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 2008 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. snap is a required scratch object. 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, scf_snapshot_t *snap) 4998 { 4999 again: 5000 if (scf_instance_get_snapshot(inst, name, snap) == 0) { 5001 if (_scf_snapshot_take_attach(inst, 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, 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_INTERNAL: 5048 case SCF_ERROR_INVALID_ARGUMENT: 5049 case SCF_ERROR_HANDLE_MISMATCH: 5050 bad_error("_scf_snapshot_take_new", 5051 scf_error()); 5052 } 5053 } 5054 } 5055 5056 return (0); 5057 } 5058 5059 /* 5060 * Import an instance. If it doesn't exist, create it. If it has 5061 * a last-import snapshot, upgrade its properties. Finish by updating its 5062 * last-import snapshot. If it doesn't have a last-import snapshot then it 5063 * could have been created for a dependent tag in another manifest. Import the 5064 * new properties. If there's a conflict, don't override, like now? 5065 * 5066 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 5067 * lcbdata->sc_err to 5068 * ECONNABORTED - repository connection broken 5069 * ENOMEM - out of memory 5070 * ENOSPC - svc.configd is out of resources 5071 * EEXIST - dependency collision in dependent service (error printed) 5072 * EPERM - couldn't create temporary instance (permission denied) 5073 * - couldn't import into temporary instance (permission denied) 5074 * - couldn't take snapshot (permission denied) 5075 * - couldn't upgrade properties (permission denied) 5076 * - couldn't import properties (permission denied) 5077 * - couldn't import dependents (permission denied) 5078 * EROFS - couldn't create temporary instance (repository read-only) 5079 * - couldn't import into temporary instance (repository read-only) 5080 * - couldn't upgrade properties (repository read-only) 5081 * - couldn't import properties (repository read-only) 5082 * - couldn't import dependents (repository read-only) 5083 * EACCES - couldn't create temporary instance (backend access denied) 5084 * - couldn't import into temporary instance (backend access denied) 5085 * - couldn't upgrade properties (backend access denied) 5086 * - couldn't import properties (backend access denied) 5087 * - couldn't import dependents (backend access denied) 5088 * EINVAL - invalid instance name (error printed) 5089 * - invalid pgroup_t's (error printed) 5090 * - invalid dependents (error printed) 5091 * EBUSY - temporary service deleted (error printed) 5092 * - temporary instance deleted (error printed) 5093 * - temporary instance changed (error printed) 5094 * - temporary instance already exists (error printed) 5095 * - instance deleted (error printed) 5096 * EBADF - instance has corrupt last-import snapshot (error printed) 5097 * - instance is corrupt (error printed) 5098 * - dependent has corrupt pg (error printed) 5099 * - dependent target has a corrupt snapshot (error printed) 5100 * -1 - unknown libscf error (error printed) 5101 */ 5102 static int 5103 lscf_instance_import(void *v, void *pvt) 5104 { 5105 entity_t *inst = v; 5106 scf_callback_t ctx; 5107 scf_callback_t *lcbdata = pvt; 5108 scf_service_t *rsvc = lcbdata->sc_parent; 5109 int r; 5110 scf_snaplevel_t *running; 5111 int flags = lcbdata->sc_flags; 5112 5113 const char * const emsg_tdel = 5114 gettext("Temporary instance svc:/%s:%s was deleted.\n"); 5115 const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s " 5116 "changed unexpectedly.\n"); 5117 const char * const emsg_del = gettext("%s changed unexpectedly " 5118 "(instance \"%s\" was deleted.)\n"); 5119 const char * const emsg_badsnap = gettext( 5120 "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n"); 5121 5122 /* 5123 * prepare last-import snapshot: 5124 * create temporary instance (service was precreated) 5125 * populate with properties from bundle 5126 * take snapshot 5127 */ 5128 if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) { 5129 switch (scf_error()) { 5130 case SCF_ERROR_CONNECTION_BROKEN: 5131 case SCF_ERROR_NO_RESOURCES: 5132 case SCF_ERROR_BACKEND_READONLY: 5133 case SCF_ERROR_BACKEND_ACCESS: 5134 return (stash_scferror(lcbdata)); 5135 5136 case SCF_ERROR_EXISTS: 5137 warn(gettext("Temporary service svc:/%s " 5138 "changed unexpectedly (instance \"%s\" added).\n"), 5139 imp_tsname, inst->sc_name); 5140 lcbdata->sc_err = EBUSY; 5141 return (UU_WALK_ERROR); 5142 5143 case SCF_ERROR_DELETED: 5144 warn(gettext("Temporary service svc:/%s " 5145 "was deleted unexpectedly.\n"), imp_tsname); 5146 lcbdata->sc_err = EBUSY; 5147 return (UU_WALK_ERROR); 5148 5149 case SCF_ERROR_INVALID_ARGUMENT: 5150 warn(gettext("Invalid instance name \"%s\".\n"), 5151 inst->sc_name); 5152 return (stash_scferror(lcbdata)); 5153 5154 case SCF_ERROR_PERMISSION_DENIED: 5155 warn(gettext("Could not create temporary instance " 5156 "\"%s\" in svc:/%s (permission denied).\n"), 5157 inst->sc_name, imp_tsname); 5158 return (stash_scferror(lcbdata)); 5159 5160 case SCF_ERROR_HANDLE_MISMATCH: 5161 case SCF_ERROR_NOT_BOUND: 5162 case SCF_ERROR_NOT_SET: 5163 default: 5164 bad_error("scf_service_add_instance", scf_error()); 5165 } 5166 } 5167 5168 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname, 5169 inst->sc_name); 5170 if (r < 0) 5171 bad_error("snprintf", errno); 5172 5173 r = lscf_import_instance_pgs(imp_tinst, imp_str, inst, 5174 lcbdata->sc_flags | SCI_NOENABLED); 5175 switch (r) { 5176 case 0: 5177 break; 5178 5179 case ECANCELED: 5180 warn(emsg_tdel, imp_tsname, inst->sc_name); 5181 lcbdata->sc_err = EBUSY; 5182 r = UU_WALK_ERROR; 5183 goto deltemp; 5184 5185 case EEXIST: 5186 warn(emsg_tchg, imp_tsname, inst->sc_name); 5187 lcbdata->sc_err = EBUSY; 5188 r = UU_WALK_ERROR; 5189 goto deltemp; 5190 5191 case ECONNABORTED: 5192 goto connaborted; 5193 5194 case ENOMEM: 5195 case ENOSPC: 5196 case EPERM: 5197 case EROFS: 5198 case EACCES: 5199 case EINVAL: 5200 case EBUSY: 5201 lcbdata->sc_err = r; 5202 r = UU_WALK_ERROR; 5203 goto deltemp; 5204 5205 default: 5206 bad_error("lscf_import_instance_pgs", r); 5207 } 5208 5209 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname, 5210 inst->sc_name); 5211 if (r < 0) 5212 bad_error("snprintf", errno); 5213 5214 ctx.sc_handle = lcbdata->sc_handle; 5215 ctx.sc_parent = imp_tinst; 5216 ctx.sc_service = 0; 5217 ctx.sc_source_fmri = inst->sc_fmri; 5218 ctx.sc_target_fmri = imp_str; 5219 if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx, 5220 UU_DEFAULT) != 0) { 5221 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 5222 bad_error("uu_list_walk", uu_error()); 5223 5224 switch (ctx.sc_err) { 5225 case ECONNABORTED: 5226 goto connaborted; 5227 5228 case ECANCELED: 5229 warn(emsg_tdel, imp_tsname, inst->sc_name); 5230 lcbdata->sc_err = EBUSY; 5231 break; 5232 5233 case EEXIST: 5234 warn(emsg_tchg, imp_tsname, inst->sc_name); 5235 lcbdata->sc_err = EBUSY; 5236 break; 5237 5238 default: 5239 lcbdata->sc_err = ctx.sc_err; 5240 } 5241 r = UU_WALK_ERROR; 5242 goto deltemp; 5243 } 5244 5245 if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name, 5246 inst->sc_name, snap_lastimport, imp_tlisnap) != 0) { 5247 switch (scf_error()) { 5248 case SCF_ERROR_CONNECTION_BROKEN: 5249 goto connaborted; 5250 5251 case SCF_ERROR_NO_RESOURCES: 5252 r = stash_scferror(lcbdata); 5253 goto deltemp; 5254 5255 case SCF_ERROR_EXISTS: 5256 warn(emsg_tchg, imp_tsname, inst->sc_name); 5257 lcbdata->sc_err = EBUSY; 5258 r = UU_WALK_ERROR; 5259 goto deltemp; 5260 5261 case SCF_ERROR_PERMISSION_DENIED: 5262 warn(gettext("Could not take \"%s\" snapshot of %s " 5263 "(permission denied).\n"), snap_lastimport, 5264 imp_str); 5265 r = stash_scferror(lcbdata); 5266 goto deltemp; 5267 5268 default: 5269 scfwarn(); 5270 lcbdata->sc_err = -1; 5271 r = UU_WALK_ERROR; 5272 goto deltemp; 5273 5274 case SCF_ERROR_HANDLE_MISMATCH: 5275 case SCF_ERROR_INVALID_ARGUMENT: 5276 case SCF_ERROR_NOT_SET: 5277 bad_error("_scf_snapshot_take_new_named", scf_error()); 5278 } 5279 } 5280 5281 if (lcbdata->sc_flags & SCI_FRESH) 5282 goto fresh; 5283 5284 if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) { 5285 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 5286 imp_lisnap) != 0) { 5287 switch (scf_error()) { 5288 case SCF_ERROR_DELETED: 5289 warn(emsg_del, inst->sc_parent->sc_fmri, 5290 inst->sc_name); 5291 lcbdata->sc_err = EBUSY; 5292 r = UU_WALK_ERROR; 5293 goto deltemp; 5294 5295 case SCF_ERROR_NOT_FOUND: 5296 flags |= SCI_FORCE; 5297 goto nosnap; 5298 5299 case SCF_ERROR_CONNECTION_BROKEN: 5300 goto connaborted; 5301 5302 case SCF_ERROR_INVALID_ARGUMENT: 5303 case SCF_ERROR_HANDLE_MISMATCH: 5304 case SCF_ERROR_NOT_BOUND: 5305 case SCF_ERROR_NOT_SET: 5306 default: 5307 bad_error("scf_instance_get_snapshot", 5308 scf_error()); 5309 } 5310 } 5311 5312 /* upgrade */ 5313 5314 /* 5315 * compare new properties with last-import properties 5316 * upgrade current properties 5317 */ 5318 /* clear sc_sceen for pgs */ 5319 if (uu_list_walk(inst->sc_pgroups, clear_int, 5320 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 5321 0) 5322 bad_error("uu_list_walk", uu_error()); 5323 5324 r = get_snaplevel(imp_lisnap, 0, imp_snpl); 5325 switch (r) { 5326 case 0: 5327 break; 5328 5329 case ECONNABORTED: 5330 goto connaborted; 5331 5332 case ECANCELED: 5333 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name); 5334 lcbdata->sc_err = EBUSY; 5335 r = UU_WALK_ERROR; 5336 goto deltemp; 5337 5338 case ENOENT: 5339 warn(emsg_badsnap, snap_lastimport, inst->sc_fmri); 5340 lcbdata->sc_err = EBADF; 5341 r = UU_WALK_ERROR; 5342 goto deltemp; 5343 5344 default: 5345 bad_error("get_snaplevel", r); 5346 } 5347 5348 if (scf_instance_get_snapshot(imp_inst, snap_running, 5349 imp_rsnap) != 0) { 5350 switch (scf_error()) { 5351 case SCF_ERROR_DELETED: 5352 warn(emsg_del, inst->sc_parent->sc_fmri, 5353 inst->sc_name); 5354 lcbdata->sc_err = EBUSY; 5355 r = UU_WALK_ERROR; 5356 goto deltemp; 5357 5358 case SCF_ERROR_NOT_FOUND: 5359 break; 5360 5361 case SCF_ERROR_CONNECTION_BROKEN: 5362 goto connaborted; 5363 5364 case SCF_ERROR_INVALID_ARGUMENT: 5365 case SCF_ERROR_HANDLE_MISMATCH: 5366 case SCF_ERROR_NOT_BOUND: 5367 case SCF_ERROR_NOT_SET: 5368 default: 5369 bad_error("scf_instance_get_snapshot", 5370 scf_error()); 5371 } 5372 5373 running = NULL; 5374 } else { 5375 r = get_snaplevel(imp_rsnap, 0, imp_rsnpl); 5376 switch (r) { 5377 case 0: 5378 running = imp_rsnpl; 5379 break; 5380 5381 case ECONNABORTED: 5382 goto connaborted; 5383 5384 case ECANCELED: 5385 warn(emsg_del, inst->sc_parent->sc_fmri, 5386 inst->sc_name); 5387 lcbdata->sc_err = EBUSY; 5388 r = UU_WALK_ERROR; 5389 goto deltemp; 5390 5391 case ENOENT: 5392 warn(emsg_badsnap, snap_running, inst->sc_fmri); 5393 lcbdata->sc_err = EBADF; 5394 r = UU_WALK_ERROR; 5395 goto deltemp; 5396 5397 default: 5398 bad_error("get_snaplevel", r); 5399 } 5400 } 5401 5402 r = upgrade_props(imp_inst, running, imp_snpl, inst); 5403 switch (r) { 5404 case 0: 5405 break; 5406 5407 case ECANCELED: 5408 case ENODEV: 5409 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name); 5410 lcbdata->sc_err = EBUSY; 5411 r = UU_WALK_ERROR; 5412 goto deltemp; 5413 5414 case ECONNABORTED: 5415 goto connaborted; 5416 5417 case ENOMEM: 5418 case ENOSPC: 5419 case EBADF: 5420 case EBUSY: 5421 case EINVAL: 5422 case EPERM: 5423 case EROFS: 5424 case EACCES: 5425 case EEXIST: 5426 lcbdata->sc_err = r; 5427 r = UU_WALK_ERROR; 5428 goto deltemp; 5429 5430 default: 5431 bad_error("upgrade_props", r); 5432 } 5433 5434 inst->sc_import_state = IMPORT_PROP_DONE; 5435 } else { 5436 switch (scf_error()) { 5437 case SCF_ERROR_CONNECTION_BROKEN: 5438 goto connaborted; 5439 5440 case SCF_ERROR_NOT_FOUND: 5441 break; 5442 5443 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 5444 case SCF_ERROR_HANDLE_MISMATCH: 5445 case SCF_ERROR_NOT_BOUND: 5446 case SCF_ERROR_NOT_SET: 5447 default: 5448 bad_error("scf_service_get_instance", scf_error()); 5449 } 5450 5451 fresh: 5452 /* create instance */ 5453 if (scf_service_add_instance(rsvc, inst->sc_name, 5454 imp_inst) != 0) { 5455 switch (scf_error()) { 5456 case SCF_ERROR_CONNECTION_BROKEN: 5457 goto connaborted; 5458 5459 case SCF_ERROR_NO_RESOURCES: 5460 case SCF_ERROR_BACKEND_READONLY: 5461 case SCF_ERROR_BACKEND_ACCESS: 5462 r = stash_scferror(lcbdata); 5463 goto deltemp; 5464 5465 case SCF_ERROR_EXISTS: 5466 warn(gettext("%s changed unexpectedly " 5467 "(instance \"%s\" added).\n"), 5468 inst->sc_parent->sc_fmri, inst->sc_name); 5469 lcbdata->sc_err = EBUSY; 5470 r = UU_WALK_ERROR; 5471 goto deltemp; 5472 5473 case SCF_ERROR_PERMISSION_DENIED: 5474 warn(gettext("Could not create \"%s\" instance " 5475 "in %s (permission denied).\n"), 5476 inst->sc_name, inst->sc_parent->sc_fmri); 5477 r = stash_scferror(lcbdata); 5478 goto deltemp; 5479 5480 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 5481 case SCF_ERROR_HANDLE_MISMATCH: 5482 case SCF_ERROR_NOT_BOUND: 5483 case SCF_ERROR_NOT_SET: 5484 default: 5485 bad_error("scf_service_add_instance", 5486 scf_error()); 5487 } 5488 } 5489 5490 nosnap: 5491 /* 5492 * Create a last-import snapshot to serve as an attachment 5493 * point for the real one from the temporary instance. Since 5494 * the contents is irrelevant, take it now, while the instance 5495 * is empty, to minimize svc.configd's work. 5496 */ 5497 if (_scf_snapshot_take_new(imp_inst, snap_lastimport, 5498 imp_lisnap) != 0) { 5499 switch (scf_error()) { 5500 case SCF_ERROR_CONNECTION_BROKEN: 5501 goto connaborted; 5502 5503 case SCF_ERROR_NO_RESOURCES: 5504 r = stash_scferror(lcbdata); 5505 goto deltemp; 5506 5507 case SCF_ERROR_EXISTS: 5508 warn(gettext("%s changed unexpectedly " 5509 "(snapshot \"%s\" added).\n"), 5510 inst->sc_fmri, snap_lastimport); 5511 lcbdata->sc_err = EBUSY; 5512 r = UU_WALK_ERROR; 5513 goto deltemp; 5514 5515 case SCF_ERROR_PERMISSION_DENIED: 5516 warn(gettext("Could not take \"%s\" snapshot " 5517 "of %s (permission denied).\n"), 5518 snap_lastimport, inst->sc_fmri); 5519 r = stash_scferror(lcbdata); 5520 goto deltemp; 5521 5522 default: 5523 scfwarn(); 5524 lcbdata->sc_err = -1; 5525 r = UU_WALK_ERROR; 5526 goto deltemp; 5527 5528 case SCF_ERROR_NOT_SET: 5529 case SCF_ERROR_INTERNAL: 5530 case SCF_ERROR_INVALID_ARGUMENT: 5531 case SCF_ERROR_HANDLE_MISMATCH: 5532 bad_error("_scf_snapshot_take_new", 5533 scf_error()); 5534 } 5535 } 5536 5537 if (li_only) 5538 goto lionly; 5539 5540 inst->sc_import_state = IMPORT_PROP_BEGUN; 5541 5542 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst, 5543 flags); 5544 switch (r) { 5545 case 0: 5546 break; 5547 5548 case ECONNABORTED: 5549 goto connaborted; 5550 5551 case ECANCELED: 5552 warn(gettext("%s changed unexpectedly " 5553 "(instance \"%s\" deleted).\n"), 5554 inst->sc_parent->sc_fmri, inst->sc_name); 5555 lcbdata->sc_err = EBUSY; 5556 r = UU_WALK_ERROR; 5557 goto deltemp; 5558 5559 case EEXIST: 5560 warn(gettext("%s changed unexpectedly " 5561 "(property group added).\n"), inst->sc_fmri); 5562 lcbdata->sc_err = EBUSY; 5563 r = UU_WALK_ERROR; 5564 goto deltemp; 5565 5566 default: 5567 lcbdata->sc_err = r; 5568 r = UU_WALK_ERROR; 5569 goto deltemp; 5570 5571 case EINVAL: /* caught above */ 5572 bad_error("lscf_import_instance_pgs", r); 5573 } 5574 5575 ctx.sc_parent = imp_inst; 5576 ctx.sc_service = 0; 5577 ctx.sc_trans = NULL; 5578 if (uu_list_walk(inst->sc_dependents, lscf_dependent_import, 5579 &ctx, UU_DEFAULT) != 0) { 5580 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 5581 bad_error("uu_list_walk", uu_error()); 5582 5583 if (ctx.sc_err == ECONNABORTED) 5584 goto connaborted; 5585 lcbdata->sc_err = ctx.sc_err; 5586 r = UU_WALK_ERROR; 5587 goto deltemp; 5588 } 5589 5590 inst->sc_import_state = IMPORT_PROP_DONE; 5591 5592 if (g_verbose) 5593 warn(gettext("Taking \"%s\" snapshot for %s.\n"), 5594 snap_initial, inst->sc_fmri); 5595 r = take_snap(imp_inst, snap_initial, imp_snap); 5596 switch (r) { 5597 case 0: 5598 break; 5599 5600 case ECONNABORTED: 5601 goto connaborted; 5602 5603 case ENOSPC: 5604 case -1: 5605 lcbdata->sc_err = r; 5606 r = UU_WALK_ERROR; 5607 goto deltemp; 5608 5609 case ECANCELED: 5610 warn(gettext("%s changed unexpectedly " 5611 "(instance %s deleted).\n"), 5612 inst->sc_parent->sc_fmri, inst->sc_name); 5613 lcbdata->sc_err = r; 5614 r = UU_WALK_ERROR; 5615 goto deltemp; 5616 5617 case EPERM: 5618 warn(emsg_snap_perm, snap_initial, inst->sc_fmri); 5619 lcbdata->sc_err = r; 5620 r = UU_WALK_ERROR; 5621 goto deltemp; 5622 5623 default: 5624 bad_error("take_snap", r); 5625 } 5626 } 5627 5628 lionly: 5629 if (lcbdata->sc_flags & SCI_NOSNAP) 5630 goto deltemp; 5631 5632 /* transfer snapshot from temporary instance */ 5633 if (g_verbose) 5634 warn(gettext("Taking \"%s\" snapshot for %s.\n"), 5635 snap_lastimport, inst->sc_fmri); 5636 if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) { 5637 switch (scf_error()) { 5638 case SCF_ERROR_CONNECTION_BROKEN: 5639 goto connaborted; 5640 5641 case SCF_ERROR_NO_RESOURCES: 5642 r = stash_scferror(lcbdata); 5643 goto deltemp; 5644 5645 case SCF_ERROR_PERMISSION_DENIED: 5646 warn(gettext("Could not take \"%s\" snapshot for %s " 5647 "(permission denied).\n"), snap_lastimport, 5648 inst->sc_fmri); 5649 r = stash_scferror(lcbdata); 5650 goto deltemp; 5651 5652 case SCF_ERROR_NOT_SET: 5653 case SCF_ERROR_HANDLE_MISMATCH: 5654 default: 5655 bad_error("_scf_snapshot_attach", scf_error()); 5656 } 5657 } 5658 5659 inst->sc_import_state = IMPORT_COMPLETE; 5660 5661 r = UU_WALK_NEXT; 5662 5663 deltemp: 5664 /* delete temporary instance */ 5665 if (scf_instance_delete(imp_tinst) != 0) { 5666 switch (scf_error()) { 5667 case SCF_ERROR_DELETED: 5668 break; 5669 5670 case SCF_ERROR_CONNECTION_BROKEN: 5671 goto connaborted; 5672 5673 case SCF_ERROR_NOT_SET: 5674 case SCF_ERROR_NOT_BOUND: 5675 default: 5676 bad_error("scf_instance_delete", scf_error()); 5677 } 5678 } 5679 5680 return (r); 5681 5682 connaborted: 5683 warn(gettext("Could not delete svc:/%s:%s " 5684 "(repository connection broken).\n"), imp_tsname, inst->sc_name); 5685 lcbdata->sc_err = ECONNABORTED; 5686 return (UU_WALK_ERROR); 5687 } 5688 5689 /* 5690 * If the service is missing, create it, import its properties, and import the 5691 * instances. Since the service is brand new, it should be empty, and if we 5692 * run into any existing entities (SCF_ERROR_EXISTS), abort. 5693 * 5694 * If the service exists, we want to upgrade its properties and import the 5695 * instances. Upgrade requires a last-import snapshot, though, which are 5696 * children of instances, so first we'll have to go through the instances 5697 * looking for a last-import snapshot. If we don't find one then we'll just 5698 * override-import the service properties (but don't delete existing 5699 * properties: another service might have declared us as a dependent). Before 5700 * we change anything, though, we want to take the previous snapshots. We 5701 * also give lscf_instance_import() a leg up on taking last-import snapshots 5702 * by importing the manifest's service properties into a temporary service. 5703 * 5704 * On success, returns UU_WALK_NEXT. On failure, returns UU_WALK_ERROR and 5705 * sets lcbdata->sc_err to 5706 * ECONNABORTED - repository connection broken 5707 * ENOMEM - out of memory 5708 * ENOSPC - svc.configd is out of resources 5709 * EPERM - couldn't create temporary service (error printed) 5710 * - couldn't import into temp service (error printed) 5711 * - couldn't create service (error printed) 5712 * - couldn't import dependent (error printed) 5713 * - couldn't take snapshot (error printed) 5714 * - couldn't create instance (error printed) 5715 * - couldn't create, modify, or delete pg (error printed) 5716 * - couldn't create, modify, or delete dependent (error printed) 5717 * - couldn't import instance (error printed) 5718 * EROFS - couldn't create temporary service (repository read-only) 5719 * - couldn't import into temporary service (repository read-only) 5720 * - couldn't create service (repository read-only) 5721 * - couldn't import dependent (repository read-only) 5722 * - couldn't create instance (repository read-only) 5723 * - couldn't create, modify, or delete pg or dependent 5724 * - couldn't import instance (repository read-only) 5725 * EACCES - couldn't create temporary service (backend access denied) 5726 * - couldn't import into temporary service (backend access denied) 5727 * - couldn't create service (backend access denied) 5728 * - couldn't import dependent (backend access denied) 5729 * - couldn't create instance (backend access denied) 5730 * - couldn't create, modify, or delete pg or dependent 5731 * - couldn't import instance (backend access denied) 5732 * EINVAL - service name is invalid (error printed) 5733 * - service name is too long (error printed) 5734 * - s has invalid pgroup (error printed) 5735 * - s has invalid dependent (error printed) 5736 * - instance name is invalid (error printed) 5737 * - instance entity_t is invalid (error printed) 5738 * EEXIST - couldn't create temporary service (already exists) (error printed) 5739 * - couldn't import dependent (dependency pg already exists) (printed) 5740 * - dependency collision in dependent service (error printed) 5741 * EBUSY - temporary service deleted (error printed) 5742 * - property group added to temporary service (error printed) 5743 * - new property group changed or was deleted (error printed) 5744 * - service was added unexpectedly (error printed) 5745 * - service was deleted unexpectedly (error printed) 5746 * - property group added to new service (error printed) 5747 * - instance added unexpectedly (error printed) 5748 * - instance deleted unexpectedly (error printed) 5749 * - dependent service deleted unexpectedly (error printed) 5750 * - pg was added, changed, or deleted (error printed) 5751 * - dependent pg changed (error printed) 5752 * - temporary instance added, changed, or deleted (error printed) 5753 * EBADF - a last-import snapshot is corrupt (error printed) 5754 * - the service is corrupt (error printed) 5755 * - a dependent is corrupt (error printed) 5756 * - an instance is corrupt (error printed) 5757 * - an instance has a corrupt last-import snapshot (error printed) 5758 * - dependent target has a corrupt snapshot (error printed) 5759 * -1 - unknown libscf error (error printed) 5760 */ 5761 static int 5762 lscf_service_import(void *v, void *pvt) 5763 { 5764 entity_t *s = v; 5765 scf_callback_t cbdata; 5766 scf_callback_t *lcbdata = pvt; 5767 scf_scope_t *scope = lcbdata->sc_parent; 5768 entity_t *inst, linst; 5769 int r; 5770 int fresh = 0; 5771 scf_snaplevel_t *running; 5772 int have_ge; 5773 5774 const char * const ts_deleted = gettext("Temporary service svc:/%s " 5775 "was deleted unexpectedly.\n"); 5776 const char * const ts_pg_added = gettext("Temporary service svc:/%s " 5777 "changed unexpectedly (property group added).\n"); 5778 const char * const s_deleted = 5779 gettext("%s was deleted unexpectedly.\n"); 5780 const char * const i_deleted = 5781 gettext("%s changed unexpectedly (instance \"%s\" deleted).\n"); 5782 const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s " 5783 "is corrupt (missing service snaplevel).\n"); 5784 5785 /* Validate the service name */ 5786 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) { 5787 switch (scf_error()) { 5788 case SCF_ERROR_CONNECTION_BROKEN: 5789 return (stash_scferror(lcbdata)); 5790 5791 case SCF_ERROR_INVALID_ARGUMENT: 5792 warn(gettext("\"%s\" is an invalid service name. " 5793 "Cannot import.\n"), s->sc_name); 5794 return (stash_scferror(lcbdata)); 5795 5796 case SCF_ERROR_NOT_FOUND: 5797 break; 5798 5799 case SCF_ERROR_HANDLE_MISMATCH: 5800 case SCF_ERROR_NOT_BOUND: 5801 case SCF_ERROR_NOT_SET: 5802 default: 5803 bad_error("scf_scope_get_service", scf_error()); 5804 } 5805 } 5806 5807 /* create temporary service */ 5808 r = snprintf(imp_tsname, max_scf_name_len + 1, "TEMP/%s", s->sc_name); 5809 if (r < 0) 5810 bad_error("snprintf", errno); 5811 if (r > max_scf_name_len) { 5812 warn(gettext( 5813 "Service name \"%s\" is too long. Cannot import.\n"), 5814 s->sc_name); 5815 lcbdata->sc_err = EINVAL; 5816 return (UU_WALK_ERROR); 5817 } 5818 5819 if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) { 5820 switch (scf_error()) { 5821 case SCF_ERROR_CONNECTION_BROKEN: 5822 case SCF_ERROR_NO_RESOURCES: 5823 case SCF_ERROR_BACKEND_READONLY: 5824 case SCF_ERROR_BACKEND_ACCESS: 5825 return (stash_scferror(lcbdata)); 5826 5827 case SCF_ERROR_EXISTS: 5828 warn(gettext( 5829 "Temporary service \"%s\" must be deleted before " 5830 "this manifest can be imported.\n"), imp_tsname); 5831 return (stash_scferror(lcbdata)); 5832 5833 case SCF_ERROR_PERMISSION_DENIED: 5834 warn(gettext("Could not create temporary service " 5835 "\"%s\" (permission denied).\n"), imp_tsname); 5836 return (stash_scferror(lcbdata)); 5837 5838 case SCF_ERROR_INVALID_ARGUMENT: 5839 case SCF_ERROR_HANDLE_MISMATCH: 5840 case SCF_ERROR_NOT_BOUND: 5841 case SCF_ERROR_NOT_SET: 5842 default: 5843 bad_error("scf_scope_add_service", scf_error()); 5844 } 5845 } 5846 5847 r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname); 5848 if (r < 0) 5849 bad_error("snprintf", errno); 5850 5851 cbdata.sc_handle = lcbdata->sc_handle; 5852 cbdata.sc_parent = imp_tsvc; 5853 cbdata.sc_service = 1; 5854 cbdata.sc_source_fmri = s->sc_fmri; 5855 cbdata.sc_target_fmri = imp_str; 5856 5857 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata, 5858 UU_DEFAULT) != 0) { 5859 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 5860 bad_error("uu_list_walk", uu_error()); 5861 5862 lcbdata->sc_err = cbdata.sc_err; 5863 switch (cbdata.sc_err) { 5864 case ECONNABORTED: 5865 goto connaborted; 5866 5867 case ECANCELED: 5868 warn(ts_deleted, imp_tsname); 5869 lcbdata->sc_err = EBUSY; 5870 return (UU_WALK_ERROR); 5871 5872 case EEXIST: 5873 warn(ts_pg_added, imp_tsname); 5874 lcbdata->sc_err = EBUSY; 5875 return (UU_WALK_ERROR); 5876 } 5877 5878 r = UU_WALK_ERROR; 5879 goto deltemp; 5880 } 5881 5882 if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata, 5883 UU_DEFAULT) != 0) { 5884 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 5885 bad_error("uu_list_walk", uu_error()); 5886 5887 lcbdata->sc_err = cbdata.sc_err; 5888 switch (cbdata.sc_err) { 5889 case ECONNABORTED: 5890 goto connaborted; 5891 5892 case ECANCELED: 5893 warn(ts_deleted, imp_tsname); 5894 lcbdata->sc_err = EBUSY; 5895 return (UU_WALK_ERROR); 5896 5897 case EEXIST: 5898 warn(ts_pg_added, imp_tsname); 5899 lcbdata->sc_err = EBUSY; 5900 return (UU_WALK_ERROR); 5901 } 5902 5903 r = UU_WALK_ERROR; 5904 goto deltemp; 5905 } 5906 5907 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) { 5908 switch (scf_error()) { 5909 case SCF_ERROR_NOT_FOUND: 5910 break; 5911 5912 case SCF_ERROR_CONNECTION_BROKEN: 5913 goto connaborted; 5914 5915 case SCF_ERROR_INVALID_ARGUMENT: 5916 case SCF_ERROR_HANDLE_MISMATCH: 5917 case SCF_ERROR_NOT_BOUND: 5918 case SCF_ERROR_NOT_SET: 5919 default: 5920 bad_error("scf_scope_get_service", scf_error()); 5921 } 5922 5923 if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) { 5924 switch (scf_error()) { 5925 case SCF_ERROR_CONNECTION_BROKEN: 5926 goto connaborted; 5927 5928 case SCF_ERROR_NO_RESOURCES: 5929 case SCF_ERROR_BACKEND_READONLY: 5930 case SCF_ERROR_BACKEND_ACCESS: 5931 r = stash_scferror(lcbdata); 5932 goto deltemp; 5933 5934 case SCF_ERROR_EXISTS: 5935 warn(gettext("Scope \"%s\" changed unexpectedly" 5936 " (service \"%s\" added).\n"), 5937 SCF_SCOPE_LOCAL, s->sc_name); 5938 lcbdata->sc_err = EBUSY; 5939 goto deltemp; 5940 5941 case SCF_ERROR_PERMISSION_DENIED: 5942 warn(gettext("Could not create service \"%s\" " 5943 "(permission denied).\n"), s->sc_name); 5944 goto deltemp; 5945 5946 case SCF_ERROR_INVALID_ARGUMENT: 5947 case SCF_ERROR_HANDLE_MISMATCH: 5948 case SCF_ERROR_NOT_BOUND: 5949 case SCF_ERROR_NOT_SET: 5950 default: 5951 bad_error("scf_scope_add_service", scf_error()); 5952 } 5953 } 5954 5955 s->sc_import_state = IMPORT_PROP_BEGUN; 5956 5957 /* import service properties */ 5958 cbdata.sc_handle = lcbdata->sc_handle; 5959 cbdata.sc_parent = imp_svc; 5960 cbdata.sc_service = 1; 5961 cbdata.sc_flags = lcbdata->sc_flags; 5962 cbdata.sc_source_fmri = s->sc_fmri; 5963 cbdata.sc_target_fmri = s->sc_fmri; 5964 5965 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, 5966 &cbdata, UU_DEFAULT) != 0) { 5967 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 5968 bad_error("uu_list_walk", uu_error()); 5969 5970 lcbdata->sc_err = cbdata.sc_err; 5971 switch (cbdata.sc_err) { 5972 case ECONNABORTED: 5973 goto connaborted; 5974 5975 case ECANCELED: 5976 warn(s_deleted, s->sc_fmri); 5977 lcbdata->sc_err = EBUSY; 5978 return (UU_WALK_ERROR); 5979 5980 case EEXIST: 5981 warn(gettext("%s changed unexpectedly " 5982 "(property group added).\n"), s->sc_fmri); 5983 lcbdata->sc_err = EBUSY; 5984 return (UU_WALK_ERROR); 5985 5986 case EINVAL: 5987 /* caught above */ 5988 bad_error("entity_pgroup_import", 5989 cbdata.sc_err); 5990 } 5991 5992 r = UU_WALK_ERROR; 5993 goto deltemp; 5994 } 5995 5996 cbdata.sc_trans = NULL; 5997 if (uu_list_walk(s->sc_dependents, lscf_dependent_import, 5998 &cbdata, UU_DEFAULT) != 0) { 5999 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6000 bad_error("uu_list_walk", uu_error()); 6001 6002 lcbdata->sc_err = cbdata.sc_err; 6003 if (cbdata.sc_err == ECONNABORTED) 6004 goto connaborted; 6005 r = UU_WALK_ERROR; 6006 goto deltemp; 6007 } 6008 6009 s->sc_import_state = IMPORT_PROP_DONE; 6010 6011 /* 6012 * This is a new service, so we can't take previous snapshots 6013 * or upgrade service properties. 6014 */ 6015 fresh = 1; 6016 goto instances; 6017 } 6018 6019 /* Clear sc_seen for the instances. */ 6020 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int, 6021 (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0) 6022 bad_error("uu_list_walk", uu_error()); 6023 6024 /* 6025 * Take previous snapshots for all instances. Even for ones not 6026 * mentioned in the bundle, since we might change their service 6027 * properties. 6028 */ 6029 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) { 6030 switch (scf_error()) { 6031 case SCF_ERROR_CONNECTION_BROKEN: 6032 goto connaborted; 6033 6034 case SCF_ERROR_DELETED: 6035 warn(s_deleted, s->sc_fmri); 6036 lcbdata->sc_err = EBUSY; 6037 r = UU_WALK_ERROR; 6038 goto deltemp; 6039 6040 case SCF_ERROR_HANDLE_MISMATCH: 6041 case SCF_ERROR_NOT_BOUND: 6042 case SCF_ERROR_NOT_SET: 6043 default: 6044 bad_error("scf_iter_service_instances", scf_error()); 6045 } 6046 } 6047 6048 for (;;) { 6049 r = scf_iter_next_instance(imp_iter, imp_inst); 6050 if (r == 0) 6051 break; 6052 if (r != 1) { 6053 switch (scf_error()) { 6054 case SCF_ERROR_DELETED: 6055 warn(s_deleted, s->sc_fmri); 6056 lcbdata->sc_err = EBUSY; 6057 r = UU_WALK_ERROR; 6058 goto deltemp; 6059 6060 case SCF_ERROR_CONNECTION_BROKEN: 6061 goto connaborted; 6062 6063 case SCF_ERROR_NOT_BOUND: 6064 case SCF_ERROR_HANDLE_MISMATCH: 6065 case SCF_ERROR_INVALID_ARGUMENT: 6066 case SCF_ERROR_NOT_SET: 6067 default: 6068 bad_error("scf_iter_next_instance", 6069 scf_error()); 6070 } 6071 } 6072 6073 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) { 6074 switch (scf_error()) { 6075 case SCF_ERROR_DELETED: 6076 continue; 6077 6078 case SCF_ERROR_CONNECTION_BROKEN: 6079 goto connaborted; 6080 6081 case SCF_ERROR_NOT_SET: 6082 case SCF_ERROR_NOT_BOUND: 6083 default: 6084 bad_error("scf_instance_get_name", scf_error()); 6085 } 6086 } 6087 6088 if (g_verbose) 6089 warn(gettext( 6090 "Taking \"%s\" snapshot for svc:/%s:%s.\n"), 6091 snap_previous, s->sc_name, imp_str); 6092 6093 r = take_snap(imp_inst, snap_previous, imp_snap); 6094 switch (r) { 6095 case 0: 6096 break; 6097 6098 case ECANCELED: 6099 continue; 6100 6101 case ECONNABORTED: 6102 goto connaborted; 6103 6104 case EPERM: 6105 warn(gettext("Could not take \"%s\" snapshot of " 6106 "svc:/%s:%s (permission denied).\n"), 6107 snap_previous, s->sc_name, imp_str); 6108 lcbdata->sc_err = r; 6109 return (UU_WALK_ERROR); 6110 6111 case ENOSPC: 6112 case -1: 6113 lcbdata->sc_err = r; 6114 r = UU_WALK_ERROR; 6115 goto deltemp; 6116 6117 default: 6118 bad_error("take_snap", r); 6119 } 6120 6121 linst.sc_name = imp_str; 6122 inst = uu_list_find(s->sc_u.sc_service.sc_service_instances, 6123 &linst, NULL, NULL); 6124 if (inst != NULL) { 6125 inst->sc_import_state = IMPORT_PREVIOUS; 6126 inst->sc_seen = 1; 6127 } 6128 } 6129 6130 /* 6131 * Create the new instances and take previous snapshots of 6132 * them. This is not necessary, but it maximizes data preservation. 6133 */ 6134 for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances); 6135 inst != NULL; 6136 inst = uu_list_next(s->sc_u.sc_service.sc_service_instances, 6137 inst)) { 6138 if (inst->sc_seen) 6139 continue; 6140 6141 if (scf_service_add_instance(imp_svc, inst->sc_name, 6142 imp_inst) != 0) { 6143 switch (scf_error()) { 6144 case SCF_ERROR_CONNECTION_BROKEN: 6145 goto connaborted; 6146 6147 case SCF_ERROR_BACKEND_READONLY: 6148 case SCF_ERROR_BACKEND_ACCESS: 6149 case SCF_ERROR_NO_RESOURCES: 6150 r = stash_scferror(lcbdata); 6151 goto deltemp; 6152 6153 case SCF_ERROR_EXISTS: 6154 warn(gettext("%s changed unexpectedly " 6155 "(instance \"%s\" added).\n"), s->sc_fmri, 6156 inst->sc_name); 6157 lcbdata->sc_err = EBUSY; 6158 r = UU_WALK_ERROR; 6159 goto deltemp; 6160 6161 case SCF_ERROR_INVALID_ARGUMENT: 6162 warn(gettext("Service \"%s\" has instance with " 6163 "invalid name \"%s\".\n"), s->sc_name, 6164 inst->sc_name); 6165 r = stash_scferror(lcbdata); 6166 goto deltemp; 6167 6168 case SCF_ERROR_PERMISSION_DENIED: 6169 warn(gettext("Could not create instance \"%s\" " 6170 "in %s (permission denied).\n"), 6171 inst->sc_name, s->sc_fmri); 6172 r = stash_scferror(lcbdata); 6173 goto deltemp; 6174 6175 case SCF_ERROR_HANDLE_MISMATCH: 6176 case SCF_ERROR_NOT_BOUND: 6177 case SCF_ERROR_NOT_SET: 6178 default: 6179 bad_error("scf_service_add_instance", 6180 scf_error()); 6181 } 6182 } 6183 6184 if (g_verbose) 6185 warn(gettext("Taking \"%s\" snapshot for " 6186 "new service %s.\n"), snap_previous, inst->sc_fmri); 6187 r = take_snap(imp_inst, snap_previous, imp_snap); 6188 switch (r) { 6189 case 0: 6190 break; 6191 6192 case ECANCELED: 6193 warn(i_deleted, s->sc_fmri, inst->sc_name); 6194 lcbdata->sc_err = EBUSY; 6195 r = UU_WALK_ERROR; 6196 goto deltemp; 6197 6198 case ECONNABORTED: 6199 goto connaborted; 6200 6201 case EPERM: 6202 warn(emsg_snap_perm, snap_previous, inst->sc_fmri); 6203 lcbdata->sc_err = r; 6204 r = UU_WALK_ERROR; 6205 goto deltemp; 6206 6207 case ENOSPC: 6208 case -1: 6209 r = UU_WALK_ERROR; 6210 goto deltemp; 6211 6212 default: 6213 bad_error("take_snap", r); 6214 } 6215 } 6216 6217 s->sc_import_state = IMPORT_PREVIOUS; 6218 6219 /* 6220 * Upgrade service properties, if we can find a last-import snapshot. 6221 * Any will do because we don't support different service properties 6222 * in different manifests, so all snaplevels of the service in all of 6223 * the last-import snapshots of the instances should be the same. 6224 */ 6225 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) { 6226 switch (scf_error()) { 6227 case SCF_ERROR_CONNECTION_BROKEN: 6228 goto connaborted; 6229 6230 case SCF_ERROR_DELETED: 6231 warn(s_deleted, s->sc_fmri); 6232 lcbdata->sc_err = EBUSY; 6233 r = UU_WALK_ERROR; 6234 goto deltemp; 6235 6236 case SCF_ERROR_HANDLE_MISMATCH: 6237 case SCF_ERROR_NOT_BOUND: 6238 case SCF_ERROR_NOT_SET: 6239 default: 6240 bad_error("scf_iter_service_instances", scf_error()); 6241 } 6242 } 6243 6244 have_ge = 0; 6245 li_only = 0; 6246 6247 for (;;) { 6248 r = scf_iter_next_instance(imp_iter, imp_inst); 6249 if (r == -1) { 6250 switch (scf_error()) { 6251 case SCF_ERROR_DELETED: 6252 warn(s_deleted, s->sc_fmri); 6253 lcbdata->sc_err = EBUSY; 6254 r = UU_WALK_ERROR; 6255 goto deltemp; 6256 6257 case SCF_ERROR_CONNECTION_BROKEN: 6258 goto connaborted; 6259 6260 case SCF_ERROR_NOT_BOUND: 6261 case SCF_ERROR_HANDLE_MISMATCH: 6262 case SCF_ERROR_INVALID_ARGUMENT: 6263 case SCF_ERROR_NOT_SET: 6264 default: 6265 bad_error("scf_iter_next_instance", 6266 scf_error()); 6267 } 6268 } 6269 6270 if (r == 0) { 6271 /* 6272 * Didn't find any last-import snapshots. Override- 6273 * import the properties. Unless one of the instances 6274 * has a general/enabled property, in which case we're 6275 * probably running a last-import-capable svccfg for 6276 * the first time, and we should only take the 6277 * last-import snapshot. 6278 */ 6279 if (have_ge) { 6280 li_only = 1; 6281 no_refresh = 1; 6282 break; 6283 } 6284 6285 s->sc_import_state = IMPORT_PROP_BEGUN; 6286 6287 cbdata.sc_handle = g_hndl; 6288 cbdata.sc_parent = imp_svc; 6289 cbdata.sc_service = 1; 6290 cbdata.sc_flags = SCI_FORCE; 6291 cbdata.sc_source_fmri = s->sc_fmri; 6292 cbdata.sc_target_fmri = s->sc_fmri; 6293 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, 6294 &cbdata, UU_DEFAULT) != 0) { 6295 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6296 bad_error("uu_list_walk", uu_error()); 6297 lcbdata->sc_err = cbdata.sc_err; 6298 switch (cbdata.sc_err) { 6299 case ECONNABORTED: 6300 goto connaborted; 6301 6302 case ECANCELED: 6303 warn(s_deleted, s->sc_fmri); 6304 lcbdata->sc_err = EBUSY; 6305 break; 6306 6307 case EINVAL: /* caught above */ 6308 case EEXIST: 6309 bad_error("entity_pgroup_import", 6310 cbdata.sc_err); 6311 } 6312 6313 r = UU_WALK_ERROR; 6314 goto deltemp; 6315 } 6316 6317 cbdata.sc_trans = NULL; 6318 if (uu_list_walk(s->sc_dependents, 6319 lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) { 6320 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6321 bad_error("uu_list_walk", uu_error()); 6322 lcbdata->sc_err = cbdata.sc_err; 6323 if (cbdata.sc_err == ECONNABORTED) 6324 goto connaborted; 6325 r = UU_WALK_ERROR; 6326 goto deltemp; 6327 } 6328 break; 6329 } 6330 6331 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 6332 imp_snap) != 0) { 6333 switch (scf_error()) { 6334 case SCF_ERROR_DELETED: 6335 continue; 6336 6337 case SCF_ERROR_NOT_FOUND: 6338 break; 6339 6340 case SCF_ERROR_CONNECTION_BROKEN: 6341 goto connaborted; 6342 6343 case SCF_ERROR_HANDLE_MISMATCH: 6344 case SCF_ERROR_NOT_BOUND: 6345 case SCF_ERROR_INVALID_ARGUMENT: 6346 case SCF_ERROR_NOT_SET: 6347 default: 6348 bad_error("scf_instance_get_snapshot", 6349 scf_error()); 6350 } 6351 6352 if (have_ge) 6353 continue; 6354 6355 /* 6356 * Check for a general/enabled property. This is how 6357 * we tell whether to import if there turn out to be 6358 * no last-import snapshots. 6359 */ 6360 if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL, 6361 imp_pg) == 0) { 6362 if (scf_pg_get_property(imp_pg, 6363 SCF_PROPERTY_ENABLED, imp_prop) == 0) { 6364 have_ge = 1; 6365 } else { 6366 switch (scf_error()) { 6367 case SCF_ERROR_DELETED: 6368 case SCF_ERROR_NOT_FOUND: 6369 continue; 6370 6371 case SCF_ERROR_INVALID_ARGUMENT: 6372 case SCF_ERROR_HANDLE_MISMATCH: 6373 case SCF_ERROR_CONNECTION_BROKEN: 6374 case SCF_ERROR_NOT_BOUND: 6375 case SCF_ERROR_NOT_SET: 6376 default: 6377 bad_error("scf_pg_get_property", 6378 scf_error()); 6379 } 6380 } 6381 } else { 6382 switch (scf_error()) { 6383 case SCF_ERROR_DELETED: 6384 case SCF_ERROR_NOT_FOUND: 6385 continue; 6386 6387 case SCF_ERROR_CONNECTION_BROKEN: 6388 goto connaborted; 6389 6390 case SCF_ERROR_NOT_BOUND: 6391 case SCF_ERROR_NOT_SET: 6392 case SCF_ERROR_INVALID_ARGUMENT: 6393 case SCF_ERROR_HANDLE_MISMATCH: 6394 default: 6395 bad_error("scf_instance_get_pg", 6396 scf_error()); 6397 } 6398 } 6399 continue; 6400 } 6401 6402 /* find service snaplevel */ 6403 r = get_snaplevel(imp_snap, 1, imp_snpl); 6404 switch (r) { 6405 case 0: 6406 break; 6407 6408 case ECONNABORTED: 6409 goto connaborted; 6410 6411 case ECANCELED: 6412 continue; 6413 6414 case ENOENT: 6415 if (scf_instance_get_name(imp_inst, imp_str, 6416 imp_str_sz) < 0) 6417 (void) strcpy(imp_str, "?"); 6418 warn(badsnap, snap_lastimport, s->sc_name, imp_str); 6419 lcbdata->sc_err = EBADF; 6420 r = UU_WALK_ERROR; 6421 goto deltemp; 6422 6423 default: 6424 bad_error("get_snaplevel", r); 6425 } 6426 6427 if (scf_instance_get_snapshot(imp_inst, snap_running, 6428 imp_rsnap) != 0) { 6429 switch (scf_error()) { 6430 case SCF_ERROR_DELETED: 6431 continue; 6432 6433 case SCF_ERROR_NOT_FOUND: 6434 break; 6435 6436 case SCF_ERROR_CONNECTION_BROKEN: 6437 goto connaborted; 6438 6439 case SCF_ERROR_INVALID_ARGUMENT: 6440 case SCF_ERROR_HANDLE_MISMATCH: 6441 case SCF_ERROR_NOT_BOUND: 6442 case SCF_ERROR_NOT_SET: 6443 default: 6444 bad_error("scf_instance_get_snapshot", 6445 scf_error()); 6446 } 6447 running = NULL; 6448 } else { 6449 r = get_snaplevel(imp_rsnap, 1, imp_rsnpl); 6450 switch (r) { 6451 case 0: 6452 running = imp_rsnpl; 6453 break; 6454 6455 case ECONNABORTED: 6456 goto connaborted; 6457 6458 case ECANCELED: 6459 continue; 6460 6461 case ENOENT: 6462 if (scf_instance_get_name(imp_inst, imp_str, 6463 imp_str_sz) < 0) 6464 (void) strcpy(imp_str, "?"); 6465 warn(badsnap, snap_running, s->sc_name, 6466 imp_str); 6467 lcbdata->sc_err = EBADF; 6468 r = UU_WALK_ERROR; 6469 goto deltemp; 6470 6471 default: 6472 bad_error("get_snaplevel", r); 6473 } 6474 } 6475 6476 if (g_verbose) { 6477 if (scf_instance_get_name(imp_inst, imp_str, 6478 imp_str_sz) < 0) 6479 (void) strcpy(imp_str, "?"); 6480 warn(gettext("Upgrading properties of %s according to " 6481 "instance \"%s\".\n"), s->sc_fmri, imp_str); 6482 } 6483 6484 /* upgrade service properties */ 6485 r = upgrade_props(imp_svc, running, imp_snpl, s); 6486 if (r == 0) 6487 break; 6488 6489 switch (r) { 6490 case ECONNABORTED: 6491 goto connaborted; 6492 6493 case ECANCELED: 6494 warn(s_deleted, s->sc_fmri); 6495 lcbdata->sc_err = EBUSY; 6496 break; 6497 6498 case ENODEV: 6499 if (scf_instance_get_name(imp_inst, imp_str, 6500 imp_str_sz) < 0) 6501 (void) strcpy(imp_str, "?"); 6502 warn(i_deleted, s->sc_fmri, imp_str); 6503 lcbdata->sc_err = EBUSY; 6504 break; 6505 6506 default: 6507 lcbdata->sc_err = r; 6508 } 6509 6510 r = UU_WALK_ERROR; 6511 goto deltemp; 6512 } 6513 6514 s->sc_import_state = IMPORT_PROP_DONE; 6515 6516 instances: 6517 /* import instances */ 6518 cbdata.sc_handle = lcbdata->sc_handle; 6519 cbdata.sc_parent = imp_svc; 6520 cbdata.sc_service = 1; 6521 cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0); 6522 cbdata.sc_general = NULL; 6523 6524 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, 6525 lscf_instance_import, &cbdata, UU_DEFAULT) != 0) { 6526 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6527 bad_error("uu_list_walk", uu_error()); 6528 6529 lcbdata->sc_err = cbdata.sc_err; 6530 if (cbdata.sc_err == ECONNABORTED) 6531 goto connaborted; 6532 r = UU_WALK_ERROR; 6533 goto deltemp; 6534 } 6535 6536 s->sc_import_state = IMPORT_COMPLETE; 6537 r = UU_WALK_NEXT; 6538 6539 deltemp: 6540 /* delete temporary service */ 6541 if (scf_service_delete(imp_tsvc) != 0) { 6542 switch (scf_error()) { 6543 case SCF_ERROR_DELETED: 6544 break; 6545 6546 case SCF_ERROR_CONNECTION_BROKEN: 6547 goto connaborted; 6548 6549 case SCF_ERROR_EXISTS: 6550 warn(gettext( 6551 "Could not delete svc:/%s (instances exist).\n"), 6552 imp_tsname); 6553 break; 6554 6555 case SCF_ERROR_NOT_SET: 6556 case SCF_ERROR_NOT_BOUND: 6557 default: 6558 bad_error("scf_service_delete", scf_error()); 6559 } 6560 } 6561 6562 return (r); 6563 6564 connaborted: 6565 warn(gettext("Could not delete svc:/%s " 6566 "(repository connection broken).\n"), imp_tsname); 6567 lcbdata->sc_err = ECONNABORTED; 6568 return (UU_WALK_ERROR); 6569 } 6570 6571 static const char * 6572 import_progress(int st) 6573 { 6574 switch (st) { 6575 case 0: 6576 return (gettext("not reached.")); 6577 6578 case IMPORT_PREVIOUS: 6579 return (gettext("previous snapshot taken.")); 6580 6581 case IMPORT_PROP_BEGUN: 6582 return (gettext("some properties imported.")); 6583 6584 case IMPORT_PROP_DONE: 6585 return (gettext("properties imported.")); 6586 6587 case IMPORT_COMPLETE: 6588 return (gettext("imported.")); 6589 6590 case IMPORT_REFRESHED: 6591 return (gettext("refresh requested.")); 6592 6593 default: 6594 #ifndef NDEBUG 6595 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n", 6596 __FILE__, __LINE__, st); 6597 #endif 6598 abort(); 6599 /* NOTREACHED */ 6600 } 6601 } 6602 6603 /* 6604 * Returns 6605 * 0 - success 6606 * - fmri wasn't found (error printed) 6607 * - entity was deleted (error printed) 6608 * - backend denied access (error printed) 6609 * ENOMEM - out of memory (error printed) 6610 * ECONNABORTED - repository connection broken (error printed) 6611 * EPERM - permission denied (error printed) 6612 * -1 - unknown libscf error (error printed) 6613 */ 6614 static int 6615 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri) 6616 { 6617 scf_error_t serr; 6618 void *ent; 6619 int issvc; 6620 int r; 6621 6622 const char *deleted = gettext("Could not refresh %s (deleted).\n"); 6623 const char *dpt_deleted = gettext("Could not refresh %s " 6624 "(dependent \"%s\" of %s) (deleted).\n"); 6625 6626 serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc); 6627 switch (serr) { 6628 case SCF_ERROR_NONE: 6629 break; 6630 6631 case SCF_ERROR_NO_MEMORY: 6632 if (name == NULL) 6633 warn(gettext("Could not refresh %s (out of memory).\n"), 6634 fmri); 6635 else 6636 warn(gettext("Could not refresh %s " 6637 "(dependent \"%s\" of %s) (out of memory).\n"), 6638 fmri, name, d_fmri); 6639 return (ENOMEM); 6640 6641 case SCF_ERROR_NOT_FOUND: 6642 if (name == NULL) 6643 warn(deleted, fmri); 6644 else 6645 warn(dpt_deleted, fmri, name, d_fmri); 6646 return (0); 6647 6648 case SCF_ERROR_INVALID_ARGUMENT: 6649 case SCF_ERROR_CONSTRAINT_VIOLATED: 6650 default: 6651 bad_error("fmri_to_entity", serr); 6652 } 6653 6654 r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str); 6655 switch (r) { 6656 case 0: 6657 break; 6658 6659 case ECONNABORTED: 6660 if (name != NULL) 6661 warn(gettext("Could not refresh %s " 6662 "(dependent \"%s\" of %s) " 6663 "(repository connection broken).\n"), fmri, name, 6664 d_fmri); 6665 return (r); 6666 6667 case ECANCELED: 6668 if (name == NULL) 6669 warn(deleted, fmri); 6670 else 6671 warn(dpt_deleted, fmri, name, d_fmri); 6672 return (0); 6673 6674 case EACCES: 6675 if (!g_verbose) 6676 return (0); 6677 if (name == NULL) 6678 warn(gettext("Could not refresh %s " 6679 "(backend access denied).\n"), fmri); 6680 else 6681 warn(gettext("Could not refresh %s " 6682 "(dependent \"%s\" of %s) " 6683 "(backend access denied).\n"), fmri, name, d_fmri); 6684 return (0); 6685 6686 case EPERM: 6687 if (name == NULL) 6688 warn(gettext("Could not refresh %s " 6689 "(permission denied).\n"), fmri); 6690 else 6691 warn(gettext("Could not refresh %s " 6692 "(dependent \"%s\" of %s) " 6693 "(permission denied).\n"), fmri, name, d_fmri); 6694 return (r); 6695 6696 case -1: 6697 scfwarn(); 6698 return (r); 6699 6700 default: 6701 bad_error("refresh_entity", r); 6702 } 6703 6704 if (issvc) 6705 scf_service_destroy(ent); 6706 else 6707 scf_instance_destroy(ent); 6708 6709 return (0); 6710 } 6711 6712 int 6713 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags) 6714 { 6715 scf_callback_t cbdata; 6716 int result = 0; 6717 entity_t *svc, *inst; 6718 uu_list_t *insts; 6719 int r; 6720 pgroup_t *old_dpt; 6721 void *cookie; 6722 int annotation_set = 0; 6723 6724 const char * const emsg_nomem = gettext("Out of memory.\n"); 6725 const char * const emsg_nores = 6726 gettext("svc.configd is out of resources.\n"); 6727 6728 lscf_prep_hndl(); 6729 6730 imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ? 6731 max_scf_name_len : max_scf_fmri_len) + 1; 6732 6733 if ((imp_scope = scf_scope_create(g_hndl)) == NULL || 6734 (imp_svc = scf_service_create(g_hndl)) == NULL || 6735 (imp_tsvc = scf_service_create(g_hndl)) == NULL || 6736 (imp_inst = scf_instance_create(g_hndl)) == NULL || 6737 (imp_tinst = scf_instance_create(g_hndl)) == NULL || 6738 (imp_snap = scf_snapshot_create(g_hndl)) == NULL || 6739 (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL || 6740 (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL || 6741 (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL || 6742 (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL || 6743 (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL || 6744 (imp_pg = scf_pg_create(g_hndl)) == NULL || 6745 (imp_pg2 = scf_pg_create(g_hndl)) == NULL || 6746 (imp_prop = scf_property_create(g_hndl)) == NULL || 6747 (imp_iter = scf_iter_create(g_hndl)) == NULL || 6748 (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL || 6749 (imp_up_iter = scf_iter_create(g_hndl)) == NULL || 6750 (imp_tx = scf_transaction_create(g_hndl)) == NULL || 6751 (imp_str = malloc(imp_str_sz)) == NULL || 6752 (imp_tsname = malloc(max_scf_name_len + 1)) == NULL || 6753 (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL || 6754 (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL || 6755 (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL || 6756 (ud_inst = scf_instance_create(g_hndl)) == NULL || 6757 (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL || 6758 (ud_pg = scf_pg_create(g_hndl)) == NULL || 6759 (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL || 6760 (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL || 6761 (ud_prop = scf_property_create(g_hndl)) == NULL || 6762 (ud_dpt_prop = scf_property_create(g_hndl)) == NULL || 6763 (ud_val = scf_value_create(g_hndl)) == NULL || 6764 (ud_iter = scf_iter_create(g_hndl)) == NULL || 6765 (ud_iter2 = scf_iter_create(g_hndl)) == NULL || 6766 (ud_tx = scf_transaction_create(g_hndl)) == NULL || 6767 (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL || 6768 (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL || 6769 (ud_name = malloc(max_scf_name_len + 1)) == NULL) { 6770 if (scf_error() == SCF_ERROR_NO_RESOURCES) 6771 warn(emsg_nores); 6772 else 6773 warn(emsg_nomem); 6774 result = -1; 6775 goto out; 6776 } 6777 6778 r = load_init(); 6779 switch (r) { 6780 case 0: 6781 break; 6782 6783 case ENOMEM: 6784 warn(emsg_nomem); 6785 result = -1; 6786 goto out; 6787 6788 default: 6789 bad_error("load_init", r); 6790 } 6791 6792 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) { 6793 switch (scf_error()) { 6794 case SCF_ERROR_CONNECTION_BROKEN: 6795 warn(gettext("Repository connection broken.\n")); 6796 repository_teardown(); 6797 result = -1; 6798 goto out; 6799 6800 case SCF_ERROR_NOT_FOUND: 6801 case SCF_ERROR_INVALID_ARGUMENT: 6802 case SCF_ERROR_NOT_BOUND: 6803 case SCF_ERROR_HANDLE_MISMATCH: 6804 default: 6805 bad_error("scf_handle_get_scope", scf_error()); 6806 } 6807 } 6808 6809 /* Set up the auditing annotation. */ 6810 if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) { 6811 annotation_set = 1; 6812 } else { 6813 switch (scf_error()) { 6814 case SCF_ERROR_CONNECTION_BROKEN: 6815 warn(gettext("Repository connection broken.\n")); 6816 repository_teardown(); 6817 result = -1; 6818 goto out; 6819 6820 case SCF_ERROR_INVALID_ARGUMENT: 6821 case SCF_ERROR_NOT_BOUND: 6822 case SCF_ERROR_NO_RESOURCES: 6823 case SCF_ERROR_INTERNAL: 6824 bad_error("_scf_set_annotation", scf_error()); 6825 /* NOTREACHED */ 6826 6827 default: 6828 /* 6829 * Do not terminate import because of inability to 6830 * generate annotation audit event. 6831 */ 6832 warn(gettext("_scf_set_annotation() unexpectedly " 6833 "failed with return code of %d\n"), scf_error()); 6834 break; 6835 } 6836 } 6837 6838 /* 6839 * Clear the sc_import_state's of all services & instances so we can 6840 * report how far we got if we fail. 6841 */ 6842 for (svc = uu_list_first(bndl->sc_bundle_services); 6843 svc != NULL; 6844 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 6845 svc->sc_import_state = 0; 6846 6847 if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances, 6848 clear_int, (void *)offsetof(entity_t, sc_import_state), 6849 UU_DEFAULT) != 0) 6850 bad_error("uu_list_walk", uu_error()); 6851 } 6852 6853 cbdata.sc_handle = g_hndl; 6854 cbdata.sc_parent = imp_scope; 6855 cbdata.sc_flags = flags; 6856 cbdata.sc_general = NULL; 6857 6858 if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import, 6859 &cbdata, UU_DEFAULT) == 0) { 6860 /* Success. Refresh everything. */ 6861 6862 if (flags & SCI_NOREFRESH || no_refresh) { 6863 result = 0; 6864 goto out; 6865 } 6866 6867 for (svc = uu_list_first(bndl->sc_bundle_services); 6868 svc != NULL; 6869 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 6870 pgroup_t *dpt; 6871 6872 insts = svc->sc_u.sc_service.sc_service_instances; 6873 6874 for (inst = uu_list_first(insts); 6875 inst != NULL; 6876 inst = uu_list_next(insts, inst)) { 6877 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL); 6878 switch (r) { 6879 case 0: 6880 break; 6881 6882 case ENOMEM: 6883 case ECONNABORTED: 6884 case EPERM: 6885 case -1: 6886 goto progress; 6887 6888 default: 6889 bad_error("imp_refresh_fmri", r); 6890 } 6891 6892 inst->sc_import_state = IMPORT_REFRESHED; 6893 6894 for (dpt = uu_list_first(inst->sc_dependents); 6895 dpt != NULL; 6896 dpt = uu_list_next(inst->sc_dependents, 6897 dpt)) 6898 if (imp_refresh_fmri( 6899 dpt->sc_pgroup_fmri, 6900 dpt->sc_pgroup_name, 6901 inst->sc_fmri) != 0) 6902 goto progress; 6903 } 6904 6905 for (dpt = uu_list_first(svc->sc_dependents); 6906 dpt != NULL; 6907 dpt = uu_list_next(svc->sc_dependents, dpt)) 6908 if (imp_refresh_fmri(dpt->sc_pgroup_fmri, 6909 dpt->sc_pgroup_name, svc->sc_fmri) != 0) 6910 goto progress; 6911 } 6912 6913 for (old_dpt = uu_list_first(imp_deleted_dpts); 6914 old_dpt != NULL; 6915 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) 6916 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri, 6917 old_dpt->sc_pgroup_name, 6918 old_dpt->sc_parent->sc_fmri) != 0) 6919 goto progress; 6920 6921 result = 0; 6922 goto out; 6923 } 6924 6925 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6926 bad_error("uu_list_walk", uu_error()); 6927 6928 printerr: 6929 /* If the error hasn't been printed yet, do so here. */ 6930 switch (cbdata.sc_err) { 6931 case ECONNABORTED: 6932 warn(gettext("Repository connection broken.\n")); 6933 break; 6934 6935 case ENOMEM: 6936 warn(emsg_nomem); 6937 break; 6938 6939 case ENOSPC: 6940 warn(emsg_nores); 6941 break; 6942 6943 case EROFS: 6944 warn(gettext("Repository is read-only.\n")); 6945 break; 6946 6947 case EACCES: 6948 warn(gettext("Repository backend denied access.\n")); 6949 break; 6950 6951 case EPERM: 6952 case EINVAL: 6953 case EEXIST: 6954 case EBUSY: 6955 case EBADF: 6956 case -1: 6957 break; 6958 6959 default: 6960 bad_error("lscf_service_import", cbdata.sc_err); 6961 } 6962 6963 progress: 6964 warn(gettext("Import of %s failed. Progress:\n"), filename); 6965 6966 for (svc = uu_list_first(bndl->sc_bundle_services); 6967 svc != NULL; 6968 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 6969 insts = svc->sc_u.sc_service.sc_service_instances; 6970 6971 warn(gettext(" Service \"%s\": %s\n"), svc->sc_name, 6972 import_progress(svc->sc_import_state)); 6973 6974 for (inst = uu_list_first(insts); 6975 inst != NULL; 6976 inst = uu_list_next(insts, inst)) 6977 warn(gettext(" Instance \"%s\": %s\n"), 6978 inst->sc_name, 6979 import_progress(inst->sc_import_state)); 6980 } 6981 6982 if (cbdata.sc_err == ECONNABORTED) 6983 repository_teardown(); 6984 6985 6986 result = -1; 6987 6988 out: 6989 if (annotation_set != 0) { 6990 /* Turn off annotation. It is no longer needed. */ 6991 (void) _scf_set_annotation(g_hndl, NULL, NULL); 6992 } 6993 load_fini(); 6994 6995 free(ud_ctarg); 6996 free(ud_oldtarg); 6997 free(ud_name); 6998 ud_ctarg = ud_oldtarg = ud_name = NULL; 6999 7000 scf_transaction_destroy(ud_tx); 7001 ud_tx = NULL; 7002 scf_iter_destroy(ud_iter); 7003 scf_iter_destroy(ud_iter2); 7004 ud_iter = ud_iter2 = NULL; 7005 scf_value_destroy(ud_val); 7006 ud_val = NULL; 7007 scf_property_destroy(ud_prop); 7008 scf_property_destroy(ud_dpt_prop); 7009 ud_prop = ud_dpt_prop = NULL; 7010 scf_pg_destroy(ud_pg); 7011 scf_pg_destroy(ud_cur_depts_pg); 7012 scf_pg_destroy(ud_run_dpts_pg); 7013 ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL; 7014 scf_snaplevel_destroy(ud_snpl); 7015 ud_snpl = NULL; 7016 scf_instance_destroy(ud_inst); 7017 ud_inst = NULL; 7018 7019 free(imp_str); 7020 free(imp_tsname); 7021 free(imp_fe1); 7022 free(imp_fe2); 7023 imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL; 7024 7025 cookie = NULL; 7026 while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) != 7027 NULL) { 7028 free((char *)old_dpt->sc_pgroup_name); 7029 free((char *)old_dpt->sc_pgroup_fmri); 7030 internal_pgroup_free(old_dpt); 7031 } 7032 uu_list_destroy(imp_deleted_dpts); 7033 7034 scf_transaction_destroy(imp_tx); 7035 imp_tx = NULL; 7036 scf_iter_destroy(imp_iter); 7037 scf_iter_destroy(imp_rpg_iter); 7038 scf_iter_destroy(imp_up_iter); 7039 imp_iter = imp_rpg_iter = imp_up_iter = NULL; 7040 scf_property_destroy(imp_prop); 7041 imp_prop = NULL; 7042 scf_pg_destroy(imp_pg); 7043 scf_pg_destroy(imp_pg2); 7044 imp_pg = imp_pg2 = NULL; 7045 scf_snaplevel_destroy(imp_snpl); 7046 scf_snaplevel_destroy(imp_rsnpl); 7047 imp_snpl = imp_rsnpl = NULL; 7048 scf_snapshot_destroy(imp_snap); 7049 scf_snapshot_destroy(imp_lisnap); 7050 scf_snapshot_destroy(imp_tlisnap); 7051 scf_snapshot_destroy(imp_rsnap); 7052 imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL; 7053 scf_instance_destroy(imp_inst); 7054 scf_instance_destroy(imp_tinst); 7055 imp_inst = imp_tinst = NULL; 7056 scf_service_destroy(imp_svc); 7057 scf_service_destroy(imp_tsvc); 7058 imp_svc = imp_tsvc = NULL; 7059 scf_scope_destroy(imp_scope); 7060 imp_scope = NULL; 7061 7062 return (result); 7063 } 7064 7065 7066 /* 7067 * Returns 7068 * 0 - success 7069 * -1 - lscf_import_instance_pgs() failed. 7070 */ 7071 int 7072 lscf_bundle_apply(bundle_t *bndl, const char *file) 7073 { 7074 entity_t *svc, *inst; 7075 scf_scope_t *rscope; 7076 scf_service_t *rsvc; 7077 scf_instance_t *rinst; 7078 int annotation_set = 0; 7079 int r; 7080 7081 lscf_prep_hndl(); 7082 7083 if ((rscope = scf_scope_create(g_hndl)) == NULL || 7084 (rsvc = scf_service_create(g_hndl)) == NULL || 7085 (rinst = scf_instance_create(g_hndl)) == NULL || 7086 (imp_pg = scf_pg_create(g_hndl)) == NULL || 7087 (imp_tx = scf_transaction_create(g_hndl)) == NULL) 7088 scfdie(); 7089 7090 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, rscope) != 0) 7091 scfdie(); 7092 7093 /* 7094 * Set the strings to be used for the security audit annotation 7095 * event. 7096 */ 7097 if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) { 7098 annotation_set = 1; 7099 } else { 7100 switch (scf_error()) { 7101 case SCF_ERROR_CONNECTION_BROKEN: 7102 warn(gettext("Repository connection broken.\n")); 7103 goto out; 7104 7105 case SCF_ERROR_INVALID_ARGUMENT: 7106 case SCF_ERROR_NOT_BOUND: 7107 case SCF_ERROR_NO_RESOURCES: 7108 case SCF_ERROR_INTERNAL: 7109 bad_error("_scf_set_annotation", scf_error()); 7110 /* NOTREACHED */ 7111 7112 default: 7113 /* 7114 * Do not abort apply operation because of 7115 * inability to create annotation audit event. 7116 */ 7117 warn(gettext("_scf_set_annotation() unexpectedly " 7118 "failed with return code of %d\n"), scf_error()); 7119 break; 7120 } 7121 } 7122 7123 for (svc = uu_list_first(bndl->sc_bundle_services); 7124 svc != NULL; 7125 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 7126 if (scf_scope_get_service(rscope, svc->sc_name, rsvc) != 0) { 7127 switch (scf_error()) { 7128 case SCF_ERROR_NOT_FOUND: 7129 if (g_verbose) 7130 warn(gettext("Ignoring nonexistent " 7131 "service %s.\n"), svc->sc_name); 7132 continue; 7133 7134 default: 7135 scfdie(); 7136 } 7137 } 7138 7139 for (inst = uu_list_first( 7140 svc->sc_u.sc_service.sc_service_instances); 7141 inst != NULL; 7142 inst = uu_list_next( 7143 svc->sc_u.sc_service.sc_service_instances, inst)) { 7144 if (scf_service_get_instance(rsvc, inst->sc_name, 7145 rinst) != 0) { 7146 switch (scf_error()) { 7147 case SCF_ERROR_NOT_FOUND: 7148 if (g_verbose) 7149 warn(gettext("Ignoring " 7150 "nonexistant instance " 7151 "%s:%s.\n"), 7152 inst->sc_parent->sc_name, 7153 inst->sc_name); 7154 continue; 7155 7156 default: 7157 scfdie(); 7158 } 7159 } 7160 7161 r = lscf_import_instance_pgs(rinst, inst->sc_fmri, inst, 7162 SCI_FORCE | SCI_KEEP); 7163 switch (r) { 7164 case 0: 7165 if (g_verbose) 7166 warn(gettext("%s updated.\n"), 7167 inst->sc_fmri); 7168 break; 7169 7170 case ECONNABORTED: 7171 warn(gettext("Could not update %s " 7172 "(repository connection broken).\n"), 7173 inst->sc_fmri); 7174 goto out; 7175 7176 case ENOMEM: 7177 warn(gettext("Could not update %s " 7178 "(out of memory).\n"), inst->sc_fmri); 7179 goto out; 7180 7181 case ENOSPC: 7182 warn(gettext("Could not update %s " 7183 "(repository server out of resources).\n"), 7184 inst->sc_fmri); 7185 goto out; 7186 7187 case ECANCELED: 7188 warn(gettext( 7189 "Could not update %s (deleted).\n"), 7190 inst->sc_fmri); 7191 break; 7192 7193 case EPERM: 7194 case EINVAL: 7195 case EBUSY: 7196 break; 7197 7198 case EROFS: 7199 warn(gettext("Could not update %s " 7200 "(repository read-only).\n"), 7201 inst->sc_fmri); 7202 goto out; 7203 7204 case EACCES: 7205 warn(gettext("Could not update %s " 7206 "(backend access denied).\n"), 7207 inst->sc_fmri); 7208 break; 7209 7210 case EEXIST: 7211 default: 7212 bad_error("lscf_import_instance_pgs", r); 7213 } 7214 } 7215 } 7216 7217 out: 7218 if (annotation_set) { 7219 /* Remove security audit annotation strings. */ 7220 (void) _scf_set_annotation(g_hndl, NULL, NULL); 7221 } 7222 7223 scf_transaction_destroy(imp_tx); 7224 imp_tx = NULL; 7225 scf_pg_destroy(imp_pg); 7226 imp_pg = NULL; 7227 7228 scf_instance_destroy(rinst); 7229 scf_service_destroy(rsvc); 7230 scf_scope_destroy(rscope); 7231 return (0); 7232 } 7233 7234 7235 /* 7236 * Export. These functions create and output an XML tree of a service 7237 * description from the repository. This is largely the inverse of 7238 * lxml_get_bundle() in svccfg_xml.c, but with some kickers: 7239 * 7240 * - We must include any properties which are not represented specifically by 7241 * a service manifest, e.g., properties created by an admin post-import. To 7242 * do so we'll iterate through all properties and deal with each 7243 * apropriately. 7244 * 7245 * - Children of services and instances must must be in the order set by the 7246 * DTD, but we iterate over the properties in undefined order. The elements 7247 * are not easily (or efficiently) sortable by name. Since there's a fixed 7248 * number of classes of them, however, we'll keep the classes separate and 7249 * assemble them in order. 7250 */ 7251 7252 /* 7253 * Convenience function to handle xmlSetProp errors (and type casting). 7254 */ 7255 static void 7256 safe_setprop(xmlNodePtr n, const char *name, const char *val) 7257 { 7258 if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL) 7259 uu_die(gettext("Could not set XML property.\n")); 7260 } 7261 7262 /* 7263 * Convenience function to set an XML attribute to the single value of an 7264 * astring property. If the value happens to be the default, don't set the 7265 * attribute. "dval" should be the default value supplied by the DTD, or 7266 * NULL for no default. 7267 */ 7268 static int 7269 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n, 7270 const char *name, const char *dval) 7271 { 7272 scf_value_t *val; 7273 ssize_t len; 7274 char *str; 7275 7276 val = scf_value_create(g_hndl); 7277 if (val == NULL) 7278 scfdie(); 7279 7280 if (prop_get_val(prop, val) != 0) { 7281 scf_value_destroy(val); 7282 return (-1); 7283 } 7284 7285 len = scf_value_get_as_string(val, NULL, 0); 7286 if (len < 0) 7287 scfdie(); 7288 7289 str = safe_malloc(len + 1); 7290 7291 if (scf_value_get_as_string(val, str, len + 1) < 0) 7292 scfdie(); 7293 7294 scf_value_destroy(val); 7295 7296 if (dval == NULL || strcmp(str, dval) != 0) 7297 safe_setprop(n, name, str); 7298 7299 free(str); 7300 7301 return (0); 7302 } 7303 7304 /* 7305 * As above, but the attribute is always set. 7306 */ 7307 static int 7308 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name) 7309 { 7310 return (set_attr_from_prop_default(prop, n, name, NULL)); 7311 } 7312 7313 /* 7314 * Dump the given document onto f, with "'s replaced by ''s. 7315 */ 7316 static int 7317 write_service_bundle(xmlDocPtr doc, FILE *f) 7318 { 7319 xmlChar *mem; 7320 int sz, i; 7321 7322 mem = NULL; 7323 xmlDocDumpFormatMemory(doc, &mem, &sz, 1); 7324 7325 if (mem == NULL) { 7326 semerr(gettext("Could not dump XML tree.\n")); 7327 return (-1); 7328 } 7329 7330 /* 7331 * Fortunately libxml produces " instead of ", so we can blindly 7332 * replace all " with '. Cursed libxml2! Why must you #ifdef out the 7333 * ' code?! 7334 */ 7335 for (i = 0; i < sz; ++i) { 7336 char c = (char)mem[i]; 7337 7338 if (c == '"') 7339 (void) fputc('\'', f); 7340 else if (c == '\'') 7341 (void) fwrite("'", sizeof ("'") - 1, 1, f); 7342 else 7343 (void) fputc(c, f); 7344 } 7345 7346 return (0); 7347 } 7348 7349 /* 7350 * Create the DOM elements in elts necessary to (generically) represent prop 7351 * (i.e., a property or propval element). If the name of the property is 7352 * known, it should be passed as name_arg. Otherwise, pass NULL. 7353 */ 7354 static void 7355 export_property(scf_property_t *prop, const char *name_arg, 7356 struct pg_elts *elts, int flags) 7357 { 7358 const char *type; 7359 scf_error_t err = 0; 7360 xmlNodePtr pnode, lnode; 7361 char *lnname; 7362 int ret; 7363 7364 /* name */ 7365 if (name_arg != NULL) { 7366 (void) strcpy(exp_str, name_arg); 7367 } else { 7368 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0) 7369 scfdie(); 7370 } 7371 7372 /* type */ 7373 type = prop_to_typestr(prop); 7374 if (type == NULL) 7375 uu_die(gettext("Can't export property %s: unknown type.\n"), 7376 exp_str); 7377 7378 /* If we're exporting values, and there's just one, export it here. */ 7379 if (!(flags & SCE_ALL_VALUES)) 7380 goto empty; 7381 7382 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) { 7383 xmlNodePtr n; 7384 7385 /* Single value, so use propval */ 7386 n = xmlNewNode(NULL, (xmlChar *)"propval"); 7387 if (n == NULL) 7388 uu_die(emsg_create_xml); 7389 7390 safe_setprop(n, name_attr, exp_str); 7391 safe_setprop(n, type_attr, type); 7392 7393 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 7394 scfdie(); 7395 safe_setprop(n, value_attr, exp_str); 7396 7397 if (elts->propvals == NULL) 7398 elts->propvals = n; 7399 else 7400 (void) xmlAddSibling(elts->propvals, n); 7401 7402 return; 7403 } 7404 7405 err = scf_error(); 7406 7407 if (err == SCF_ERROR_PERMISSION_DENIED) { 7408 semerr(emsg_permission_denied); 7409 return; 7410 } 7411 7412 if (err != SCF_ERROR_CONSTRAINT_VIOLATED && 7413 err != SCF_ERROR_NOT_FOUND && 7414 err != SCF_ERROR_PERMISSION_DENIED) 7415 scfdie(); 7416 7417 empty: 7418 /* Multiple (or no) values, so use property */ 7419 pnode = xmlNewNode(NULL, (xmlChar *)"property"); 7420 if (pnode == NULL) 7421 uu_die(emsg_create_xml); 7422 7423 safe_setprop(pnode, name_attr, exp_str); 7424 safe_setprop(pnode, type_attr, type); 7425 7426 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) { 7427 lnname = uu_msprintf("%s_list", type); 7428 if (lnname == NULL) 7429 uu_die(gettext("Could not create string")); 7430 7431 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL); 7432 if (lnode == NULL) 7433 uu_die(emsg_create_xml); 7434 7435 uu_free(lnname); 7436 7437 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS) 7438 scfdie(); 7439 7440 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 7441 1) { 7442 xmlNodePtr vn; 7443 7444 vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node", 7445 NULL); 7446 if (vn == NULL) 7447 uu_die(emsg_create_xml); 7448 7449 if (scf_value_get_as_string(exp_val, exp_str, 7450 exp_str_sz) < 0) 7451 scfdie(); 7452 safe_setprop(vn, value_attr, exp_str); 7453 } 7454 if (ret != 0) 7455 scfdie(); 7456 } 7457 7458 if (elts->properties == NULL) 7459 elts->properties = pnode; 7460 else 7461 (void) xmlAddSibling(elts->properties, pnode); 7462 } 7463 7464 /* 7465 * Add a property_group element for this property group to elts. 7466 */ 7467 static void 7468 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags) 7469 { 7470 xmlNodePtr n; 7471 struct pg_elts elts; 7472 int ret; 7473 boolean_t read_protected; 7474 7475 n = xmlNewNode(NULL, (xmlChar *)"property_group"); 7476 7477 /* name */ 7478 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 7479 scfdie(); 7480 safe_setprop(n, name_attr, exp_str); 7481 7482 /* type */ 7483 if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0) 7484 scfdie(); 7485 safe_setprop(n, type_attr, exp_str); 7486 7487 /* properties */ 7488 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 7489 scfdie(); 7490 7491 (void) memset(&elts, 0, sizeof (elts)); 7492 7493 /* 7494 * If this property group is not read protected, we always want to 7495 * output all the values. Otherwise, we only output the values if the 7496 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a). 7497 */ 7498 if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS) 7499 scfdie(); 7500 7501 if (!read_protected) 7502 flags |= SCE_ALL_VALUES; 7503 7504 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 7505 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 7506 scfdie(); 7507 7508 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 7509 xmlNodePtr m; 7510 7511 m = xmlNewNode(NULL, (xmlChar *)"stability"); 7512 if (m == NULL) 7513 uu_die(emsg_create_xml); 7514 7515 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 7516 elts.stability = m; 7517 continue; 7518 } 7519 7520 xmlFreeNode(m); 7521 } 7522 7523 export_property(exp_prop, NULL, &elts, flags); 7524 } 7525 if (ret == -1) 7526 scfdie(); 7527 7528 (void) xmlAddChild(n, elts.stability); 7529 (void) xmlAddChildList(n, elts.propvals); 7530 (void) xmlAddChildList(n, elts.properties); 7531 7532 if (eelts->property_groups == NULL) 7533 eelts->property_groups = n; 7534 else 7535 (void) xmlAddSibling(eelts->property_groups, n); 7536 } 7537 7538 /* 7539 * Create an XML node representing the dependency described by the given 7540 * property group and put it in eelts. Unless the dependency is not valid, in 7541 * which case create a generic property_group element which represents it and 7542 * put it in eelts. 7543 */ 7544 static void 7545 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts) 7546 { 7547 xmlNodePtr n; 7548 int err = 0, ret; 7549 struct pg_elts elts; 7550 7551 n = xmlNewNode(NULL, (xmlChar *)"dependency"); 7552 if (n == NULL) 7553 uu_die(emsg_create_xml); 7554 7555 /* 7556 * If the external flag is present, skip this dependency because it 7557 * should have been created by another manifest. 7558 */ 7559 if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) { 7560 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 7561 prop_get_val(exp_prop, exp_val) == 0) { 7562 uint8_t b; 7563 7564 if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS) 7565 scfdie(); 7566 7567 if (b) 7568 return; 7569 } 7570 } else if (scf_error() != SCF_ERROR_NOT_FOUND) 7571 scfdie(); 7572 7573 /* Get the required attributes. */ 7574 7575 /* name */ 7576 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 7577 scfdie(); 7578 safe_setprop(n, name_attr, exp_str); 7579 7580 /* grouping */ 7581 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 || 7582 set_attr_from_prop(exp_prop, n, "grouping") != 0) 7583 err = 1; 7584 7585 /* restart_on */ 7586 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 || 7587 set_attr_from_prop(exp_prop, n, "restart_on") != 0) 7588 err = 1; 7589 7590 /* type */ 7591 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 || 7592 set_attr_from_prop(exp_prop, n, type_attr) != 0) 7593 err = 1; 7594 7595 /* 7596 * entities: Not required, but if we create no children, it will be 7597 * created as empty on import, so fail if it's missing. 7598 */ 7599 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 && 7600 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) { 7601 scf_iter_t *eiter; 7602 int ret2; 7603 7604 eiter = scf_iter_create(g_hndl); 7605 if (eiter == NULL) 7606 scfdie(); 7607 7608 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS) 7609 scfdie(); 7610 7611 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) { 7612 xmlNodePtr ch; 7613 7614 if (scf_value_get_astring(exp_val, exp_str, 7615 exp_str_sz) < 0) 7616 scfdie(); 7617 7618 /* 7619 * service_fmri's must be first, so we can add them 7620 * here. 7621 */ 7622 ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", 7623 NULL); 7624 if (ch == NULL) 7625 uu_die(emsg_create_xml); 7626 7627 safe_setprop(ch, value_attr, exp_str); 7628 } 7629 if (ret2 == -1) 7630 scfdie(); 7631 7632 scf_iter_destroy(eiter); 7633 } else 7634 err = 1; 7635 7636 if (err) { 7637 xmlFreeNode(n); 7638 7639 export_pg(pg, eelts, 0); 7640 7641 return; 7642 } 7643 7644 /* Iterate through the properties & handle each. */ 7645 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 7646 scfdie(); 7647 7648 (void) memset(&elts, 0, sizeof (elts)); 7649 7650 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 7651 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 7652 scfdie(); 7653 7654 if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 || 7655 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 || 7656 strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 || 7657 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) { 7658 continue; 7659 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 7660 xmlNodePtr m; 7661 7662 m = xmlNewNode(NULL, (xmlChar *)"stability"); 7663 if (m == NULL) 7664 uu_die(emsg_create_xml); 7665 7666 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 7667 elts.stability = m; 7668 continue; 7669 } 7670 7671 xmlFreeNode(m); 7672 } 7673 7674 export_property(exp_prop, exp_str, &elts, 0); 7675 } 7676 if (ret == -1) 7677 scfdie(); 7678 7679 (void) xmlAddChild(n, elts.stability); 7680 (void) xmlAddChildList(n, elts.propvals); 7681 (void) xmlAddChildList(n, elts.properties); 7682 7683 if (eelts->dependencies == NULL) 7684 eelts->dependencies = n; 7685 else 7686 (void) xmlAddSibling(eelts->dependencies, n); 7687 } 7688 7689 static xmlNodePtr 7690 export_method_environment(scf_propertygroup_t *pg) 7691 { 7692 xmlNodePtr env; 7693 int ret; 7694 int children = 0; 7695 7696 if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0) 7697 return (NULL); 7698 7699 env = xmlNewNode(NULL, (xmlChar *)"method_environment"); 7700 if (env == NULL) 7701 uu_die(emsg_create_xml); 7702 7703 if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0) 7704 scfdie(); 7705 7706 if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS) 7707 scfdie(); 7708 7709 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) { 7710 xmlNodePtr ev; 7711 char *cp; 7712 7713 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 7714 scfdie(); 7715 7716 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) { 7717 warn(gettext("Invalid environment variable \"%s\".\n"), 7718 exp_str); 7719 continue; 7720 } else if (strncmp(exp_str, "SMF_", 4) == 0) { 7721 warn(gettext("Invalid environment variable \"%s\"; " 7722 "\"SMF_\" prefix is reserved.\n"), exp_str); 7723 continue; 7724 } 7725 7726 *cp = '\0'; 7727 cp++; 7728 7729 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL); 7730 if (ev == NULL) 7731 uu_die(emsg_create_xml); 7732 7733 safe_setprop(ev, name_attr, exp_str); 7734 safe_setprop(ev, value_attr, cp); 7735 children++; 7736 } 7737 7738 if (ret != 0) 7739 scfdie(); 7740 7741 if (children == 0) { 7742 xmlFreeNode(env); 7743 return (NULL); 7744 } 7745 7746 return (env); 7747 } 7748 7749 /* 7750 * As above, but for a method property group. 7751 */ 7752 static void 7753 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts) 7754 { 7755 xmlNodePtr n, env; 7756 char *str; 7757 int err = 0, nonenv, ret; 7758 uint8_t use_profile; 7759 struct pg_elts elts; 7760 xmlNodePtr ctxt; 7761 7762 n = xmlNewNode(NULL, (xmlChar *)"exec_method"); 7763 7764 /* Get the required attributes. */ 7765 7766 /* name */ 7767 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 7768 scfdie(); 7769 safe_setprop(n, name_attr, exp_str); 7770 7771 /* type */ 7772 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 || 7773 set_attr_from_prop(exp_prop, n, type_attr) != 0) 7774 err = 1; 7775 7776 /* exec */ 7777 if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 || 7778 set_attr_from_prop(exp_prop, n, "exec") != 0) 7779 err = 1; 7780 7781 /* timeout */ 7782 if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 && 7783 prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 && 7784 prop_get_val(exp_prop, exp_val) == 0) { 7785 uint64_t c; 7786 7787 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS) 7788 scfdie(); 7789 7790 str = uu_msprintf("%llu", c); 7791 if (str == NULL) 7792 uu_die(gettext("Could not create string")); 7793 7794 safe_setprop(n, "timeout_seconds", str); 7795 free(str); 7796 } else 7797 err = 1; 7798 7799 if (err) { 7800 xmlFreeNode(n); 7801 7802 export_pg(pg, eelts, 0); 7803 7804 return; 7805 } 7806 7807 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context"); 7808 if (ctxt == NULL) 7809 uu_die(emsg_create_xml); 7810 7811 /* 7812 * If we're going to have a method_context child, we need to know 7813 * before we iterate through the properties. Since method_context's 7814 * are optional, we don't want to complain about any properties 7815 * missing if none of them are there. Thus we can't use the 7816 * convenience functions. 7817 */ 7818 nonenv = 7819 scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) == 7820 SCF_SUCCESS || 7821 scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) == 7822 SCF_SUCCESS || 7823 scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) == 7824 SCF_SUCCESS || 7825 scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) == 7826 SCF_SUCCESS; 7827 7828 if (nonenv) { 7829 /* 7830 * We only want to complain about profile or credential 7831 * properties if we will use them. To determine that we must 7832 * examine USE_PROFILE. 7833 */ 7834 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 && 7835 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 7836 prop_get_val(exp_prop, exp_val) == 0) { 7837 if (scf_value_get_boolean(exp_val, &use_profile) != 7838 SCF_SUCCESS) 7839 scfdie(); 7840 } else 7841 /* 7842 * USE_PROFILE is misconfigured. Since we should have 7843 * complained just now, we don't want to complain 7844 * about any of the other properties, so don't look 7845 * for them. 7846 */ 7847 nonenv = 0; 7848 } 7849 7850 if (nonenv) { 7851 7852 if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) != 7853 0 || 7854 set_attr_from_prop_default(exp_prop, ctxt, 7855 "working_directory", ":default") != 0) 7856 err = 1; 7857 7858 if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) != 0 || 7859 set_attr_from_prop_default(exp_prop, ctxt, "project", 7860 ":default") != 0) 7861 err = 1; 7862 7863 if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) != 7864 0 || 7865 set_attr_from_prop_default(exp_prop, ctxt, 7866 "resource_pool", ":default") != 0) 7867 err = 1; 7868 7869 if (use_profile) { 7870 xmlNodePtr prof; 7871 7872 prof = xmlNewChild(ctxt, NULL, 7873 (xmlChar *)"method_profile", NULL); 7874 if (prof == NULL) 7875 uu_die(emsg_create_xml); 7876 7877 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE, exp_prop) != 7878 0 || set_attr_from_prop(exp_prop, prof, 7879 name_attr) != 0) 7880 err = 1; 7881 } else { 7882 xmlNodePtr cred; 7883 7884 cred = xmlNewChild(ctxt, NULL, 7885 (xmlChar *)"method_credential", NULL); 7886 if (cred == NULL) 7887 uu_die(emsg_create_xml); 7888 7889 if (pg_get_prop(pg, SCF_PROPERTY_USER, exp_prop) != 0 || 7890 set_attr_from_prop(exp_prop, cred, "user") != 0) 7891 err = 1; 7892 7893 if (pg_get_prop(pg, SCF_PROPERTY_GROUP, exp_prop) != 7894 0 || 7895 set_attr_from_prop_default(exp_prop, cred, 7896 "group", ":default") != 0) 7897 err = 1; 7898 7899 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS, 7900 exp_prop) != 0 || 7901 set_attr_from_prop_default(exp_prop, cred, 7902 "supp_groups", ":default") != 0) 7903 err = 1; 7904 7905 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES, 7906 exp_prop) != 0 || 7907 set_attr_from_prop_default(exp_prop, cred, 7908 "privileges", ":default") != 0) 7909 err = 1; 7910 7911 if (pg_get_prop(pg, SCF_PROPERTY_LIMIT_PRIVILEGES, 7912 exp_prop) != 0 || 7913 set_attr_from_prop_default(exp_prop, cred, 7914 "limit_privileges", ":default") != 0) 7915 err = 1; 7916 } 7917 } 7918 7919 if ((env = export_method_environment(pg)) != NULL) 7920 (void) xmlAddChild(ctxt, env); 7921 7922 if (env != NULL || err == 0) 7923 (void) xmlAddChild(n, ctxt); 7924 else 7925 xmlFreeNode(ctxt); 7926 7927 nonenv = (err == 0); 7928 7929 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 7930 scfdie(); 7931 7932 (void) memset(&elts, 0, sizeof (elts)); 7933 7934 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 7935 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 7936 scfdie(); 7937 7938 if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 || 7939 strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 || 7940 strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) { 7941 continue; 7942 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 7943 xmlNodePtr m; 7944 7945 m = xmlNewNode(NULL, (xmlChar *)"stability"); 7946 if (m == NULL) 7947 uu_die(emsg_create_xml); 7948 7949 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 7950 elts.stability = m; 7951 continue; 7952 } 7953 7954 xmlFreeNode(m); 7955 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 7956 0 || 7957 strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 || 7958 strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 || 7959 strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) { 7960 if (nonenv) 7961 continue; 7962 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 || 7963 strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 || 7964 strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 || 7965 strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 || 7966 strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) { 7967 if (nonenv && !use_profile) 7968 continue; 7969 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) { 7970 if (nonenv && use_profile) 7971 continue; 7972 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) { 7973 if (env != NULL) 7974 continue; 7975 } 7976 7977 export_property(exp_prop, exp_str, &elts, 0); 7978 } 7979 if (ret == -1) 7980 scfdie(); 7981 7982 (void) xmlAddChild(n, elts.stability); 7983 (void) xmlAddChildList(n, elts.propvals); 7984 (void) xmlAddChildList(n, elts.properties); 7985 7986 if (eelts->exec_methods == NULL) 7987 eelts->exec_methods = n; 7988 else 7989 (void) xmlAddSibling(eelts->exec_methods, n); 7990 } 7991 7992 static void 7993 export_pg_elts(struct pg_elts *elts, const char *name, const char *type, 7994 struct entity_elts *eelts) 7995 { 7996 xmlNodePtr pgnode; 7997 7998 pgnode = xmlNewNode(NULL, (xmlChar *)"property_group"); 7999 if (pgnode == NULL) 8000 uu_die(emsg_create_xml); 8001 8002 safe_setprop(pgnode, name_attr, name); 8003 safe_setprop(pgnode, type_attr, type); 8004 8005 (void) xmlAddChildList(pgnode, elts->propvals); 8006 (void) xmlAddChildList(pgnode, elts->properties); 8007 8008 if (eelts->property_groups == NULL) 8009 eelts->property_groups = pgnode; 8010 else 8011 (void) xmlAddSibling(eelts->property_groups, pgnode); 8012 } 8013 8014 /* 8015 * Process the general property group for a service. This is the one with the 8016 * goodies. 8017 */ 8018 static void 8019 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts) 8020 { 8021 struct pg_elts elts; 8022 int ret; 8023 8024 /* 8025 * In case there are properties which don't correspond to child 8026 * entities of the service entity, we'll set up a pg_elts structure to 8027 * put them in. 8028 */ 8029 (void) memset(&elts, 0, sizeof (elts)); 8030 8031 /* Walk the properties, looking for special ones. */ 8032 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8033 scfdie(); 8034 8035 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8036 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8037 scfdie(); 8038 8039 if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) { 8040 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 8041 prop_get_val(exp_prop, exp_val) == 0) { 8042 uint8_t b; 8043 8044 if (scf_value_get_boolean(exp_val, &b) != 8045 SCF_SUCCESS) 8046 scfdie(); 8047 8048 if (b) { 8049 selts->single_instance = 8050 xmlNewNode(NULL, 8051 (xmlChar *)"single_instance"); 8052 if (selts->single_instance == NULL) 8053 uu_die(emsg_create_xml); 8054 } 8055 8056 continue; 8057 } 8058 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 8059 xmlNodePtr rnode, sfnode; 8060 8061 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 8062 if (rnode == NULL) 8063 uu_die(emsg_create_xml); 8064 8065 sfnode = xmlNewChild(rnode, NULL, 8066 (xmlChar *)"service_fmri", NULL); 8067 if (sfnode == NULL) 8068 uu_die(emsg_create_xml); 8069 8070 if (set_attr_from_prop(exp_prop, sfnode, 8071 value_attr) == 0) { 8072 selts->restarter = rnode; 8073 continue; 8074 } 8075 8076 xmlFreeNode(rnode); 8077 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) == 8078 0) { 8079 xmlNodePtr s; 8080 8081 s = xmlNewNode(NULL, (xmlChar *)"stability"); 8082 if (s == NULL) 8083 uu_die(emsg_create_xml); 8084 8085 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) { 8086 selts->stability = s; 8087 continue; 8088 } 8089 8090 xmlFreeNode(s); 8091 } 8092 8093 export_property(exp_prop, exp_str, &elts, 0); 8094 } 8095 if (ret == -1) 8096 scfdie(); 8097 8098 if (elts.propvals != NULL || elts.properties != NULL) 8099 export_pg_elts(&elts, scf_pg_general, scf_group_framework, 8100 selts); 8101 } 8102 8103 static void 8104 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts) 8105 { 8106 xmlNodePtr n, prof, cred, env; 8107 uint8_t use_profile; 8108 int ret, err = 0; 8109 8110 n = xmlNewNode(NULL, (xmlChar *)"method_context"); 8111 8112 env = export_method_environment(pg); 8113 8114 /* Need to know whether we'll use a profile or not. */ 8115 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) != 0 || 8116 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) != 0 || 8117 prop_get_val(exp_prop, exp_val) != 0) { 8118 if (env != NULL) { 8119 (void) xmlAddChild(n, env); 8120 elts->method_context = n; 8121 } else { 8122 xmlFreeNode(n); 8123 export_pg(pg, elts, 0); 8124 } 8125 return; 8126 } 8127 8128 if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS) 8129 scfdie(); 8130 8131 if (use_profile) 8132 prof = xmlNewChild(n, NULL, (xmlChar *)"method_profile", NULL); 8133 else 8134 cred = 8135 xmlNewChild(n, NULL, (xmlChar *)"method_credential", NULL); 8136 8137 if (env != NULL) 8138 (void) xmlAddChild(n, env); 8139 8140 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8141 scfdie(); 8142 8143 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8144 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8145 scfdie(); 8146 8147 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) { 8148 if (set_attr_from_prop(exp_prop, n, 8149 "working_directory") != 0) 8150 err = 1; 8151 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) { 8152 if (set_attr_from_prop(exp_prop, n, "project") != 0) 8153 err = 1; 8154 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) { 8155 if (set_attr_from_prop(exp_prop, n, 8156 "resource_pool") != 0) 8157 err = 1; 8158 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) { 8159 /* EMPTY */ 8160 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) { 8161 if (use_profile || 8162 set_attr_from_prop(exp_prop, cred, "user") != 0) 8163 err = 1; 8164 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) { 8165 if (use_profile || 8166 set_attr_from_prop(exp_prop, cred, "group") != 0) 8167 err = 1; 8168 } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) { 8169 if (use_profile || set_attr_from_prop(exp_prop, cred, 8170 "supp_groups") != 0) 8171 err = 1; 8172 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) { 8173 if (use_profile || set_attr_from_prop(exp_prop, cred, 8174 "privileges") != 0) 8175 err = 1; 8176 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 8177 0) { 8178 if (use_profile || set_attr_from_prop(exp_prop, cred, 8179 "limit_privileges") != 0) 8180 err = 1; 8181 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) { 8182 if (!use_profile || set_attr_from_prop(exp_prop, 8183 prof, name_attr) != 0) 8184 err = 1; 8185 } else { 8186 /* Can't have generic properties in method_context's */ 8187 err = 1; 8188 } 8189 } 8190 if (ret == -1) 8191 scfdie(); 8192 8193 if (err && env == NULL) { 8194 xmlFreeNode(n); 8195 export_pg(pg, elts, 0); 8196 return; 8197 } 8198 8199 elts->method_context = n; 8200 } 8201 8202 /* 8203 * Given a dependency property group in the tfmri entity (target fmri), return 8204 * a dependent element which represents it. 8205 */ 8206 static xmlNodePtr 8207 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri) 8208 { 8209 uint8_t b; 8210 xmlNodePtr n, sf; 8211 int err = 0, ret; 8212 struct pg_elts pgelts; 8213 8214 /* 8215 * If external isn't set to true then exporting the service will 8216 * export this as a normal dependency, so we should stop to avoid 8217 * duplication. 8218 */ 8219 if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 || 8220 scf_property_get_value(exp_prop, exp_val) != 0 || 8221 scf_value_get_boolean(exp_val, &b) != 0 || !b) { 8222 if (g_verbose) { 8223 warn(gettext("Dependent \"%s\" cannot be exported " 8224 "properly because the \"%s\" property of the " 8225 "\"%s\" dependency of %s is not set to true.\n"), 8226 name, scf_property_external, name, tfmri); 8227 } 8228 8229 return (NULL); 8230 } 8231 8232 n = xmlNewNode(NULL, (xmlChar *)"dependent"); 8233 if (n == NULL) 8234 uu_die(emsg_create_xml); 8235 8236 safe_setprop(n, name_attr, name); 8237 8238 /* Get the required attributes */ 8239 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 || 8240 set_attr_from_prop(exp_prop, n, "restart_on") != 0) 8241 err = 1; 8242 8243 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 || 8244 set_attr_from_prop(exp_prop, n, "grouping") != 0) 8245 err = 1; 8246 8247 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 && 8248 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 && 8249 prop_get_val(exp_prop, exp_val) == 0) { 8250 /* EMPTY */ 8251 } else 8252 err = 1; 8253 8254 if (err) { 8255 xmlFreeNode(n); 8256 return (NULL); 8257 } 8258 8259 sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL); 8260 if (sf == NULL) 8261 uu_die(emsg_create_xml); 8262 8263 safe_setprop(sf, value_attr, tfmri); 8264 8265 /* 8266 * Now add elements for the other properties. 8267 */ 8268 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8269 scfdie(); 8270 8271 (void) memset(&pgelts, 0, sizeof (pgelts)); 8272 8273 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8274 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8275 scfdie(); 8276 8277 if (strcmp(exp_str, scf_property_external) == 0 || 8278 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 || 8279 strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 || 8280 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) { 8281 continue; 8282 } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) { 8283 if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 && 8284 prop_get_val(exp_prop, exp_val) == 0) { 8285 char type[sizeof ("service") + 1]; 8286 8287 if (scf_value_get_astring(exp_val, type, 8288 sizeof (type)) < 0) 8289 scfdie(); 8290 8291 if (strcmp(type, "service") == 0) 8292 continue; 8293 } 8294 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 8295 xmlNodePtr s; 8296 8297 s = xmlNewNode(NULL, (xmlChar *)"stability"); 8298 if (s == NULL) 8299 uu_die(emsg_create_xml); 8300 8301 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) { 8302 pgelts.stability = s; 8303 continue; 8304 } 8305 8306 xmlFreeNode(s); 8307 } 8308 8309 export_property(exp_prop, exp_str, &pgelts, 0); 8310 } 8311 if (ret == -1) 8312 scfdie(); 8313 8314 (void) xmlAddChild(n, pgelts.stability); 8315 (void) xmlAddChildList(n, pgelts.propvals); 8316 (void) xmlAddChildList(n, pgelts.properties); 8317 8318 return (n); 8319 } 8320 8321 static void 8322 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts) 8323 { 8324 scf_propertygroup_t *opg; 8325 scf_iter_t *iter; 8326 char *type, *fmri; 8327 int ret; 8328 struct pg_elts pgelts; 8329 xmlNodePtr n; 8330 scf_error_t serr; 8331 8332 if ((opg = scf_pg_create(g_hndl)) == NULL || 8333 (iter = scf_iter_create(g_hndl)) == NULL) 8334 scfdie(); 8335 8336 /* Can't use exp_prop_iter due to export_dependent(). */ 8337 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 8338 scfdie(); 8339 8340 type = safe_malloc(max_scf_pg_type_len + 1); 8341 8342 /* Get an extra byte so we can tell if values are too long. */ 8343 fmri = safe_malloc(max_scf_fmri_len + 2); 8344 8345 (void) memset(&pgelts, 0, sizeof (pgelts)); 8346 8347 while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) { 8348 void *entity; 8349 int isservice; 8350 scf_type_t ty; 8351 8352 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS) 8353 scfdie(); 8354 8355 if ((ty != SCF_TYPE_ASTRING && 8356 prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) || 8357 prop_get_val(exp_prop, exp_val) != 0) { 8358 export_property(exp_prop, NULL, &pgelts, 0); 8359 continue; 8360 } 8361 8362 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8363 scfdie(); 8364 8365 if (scf_value_get_astring(exp_val, fmri, 8366 max_scf_fmri_len + 2) < 0) 8367 scfdie(); 8368 8369 /* Look for a dependency group in the target fmri. */ 8370 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 8371 switch (serr) { 8372 case SCF_ERROR_NONE: 8373 break; 8374 8375 case SCF_ERROR_NO_MEMORY: 8376 uu_die(gettext("Out of memory.\n")); 8377 /* NOTREACHED */ 8378 8379 case SCF_ERROR_INVALID_ARGUMENT: 8380 if (g_verbose) { 8381 if (scf_property_to_fmri(exp_prop, fmri, 8382 max_scf_fmri_len + 2) < 0) 8383 scfdie(); 8384 8385 warn(gettext("The value of %s is not a valid " 8386 "FMRI.\n"), fmri); 8387 } 8388 8389 export_property(exp_prop, exp_str, &pgelts, 0); 8390 continue; 8391 8392 case SCF_ERROR_CONSTRAINT_VIOLATED: 8393 if (g_verbose) { 8394 if (scf_property_to_fmri(exp_prop, fmri, 8395 max_scf_fmri_len + 2) < 0) 8396 scfdie(); 8397 8398 warn(gettext("The value of %s does not specify " 8399 "a service or an instance.\n"), fmri); 8400 } 8401 8402 export_property(exp_prop, exp_str, &pgelts, 0); 8403 continue; 8404 8405 case SCF_ERROR_NOT_FOUND: 8406 if (g_verbose) { 8407 if (scf_property_to_fmri(exp_prop, fmri, 8408 max_scf_fmri_len + 2) < 0) 8409 scfdie(); 8410 8411 warn(gettext("The entity specified by %s does " 8412 "not exist.\n"), fmri); 8413 } 8414 8415 export_property(exp_prop, exp_str, &pgelts, 0); 8416 continue; 8417 8418 default: 8419 #ifndef NDEBUG 8420 (void) fprintf(stderr, "%s:%d: %s() failed with " 8421 "unexpected error %d.\n", __FILE__, __LINE__, 8422 "fmri_to_entity", serr); 8423 #endif 8424 abort(); 8425 } 8426 8427 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) { 8428 if (scf_error() != SCF_ERROR_NOT_FOUND) 8429 scfdie(); 8430 8431 warn(gettext("Entity %s is missing dependency property " 8432 "group %s.\n"), fmri, exp_str); 8433 8434 export_property(exp_prop, NULL, &pgelts, 0); 8435 continue; 8436 } 8437 8438 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0) 8439 scfdie(); 8440 8441 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) { 8442 if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0) 8443 scfdie(); 8444 8445 warn(gettext("Property group %s is not of " 8446 "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY); 8447 8448 export_property(exp_prop, NULL, &pgelts, 0); 8449 continue; 8450 } 8451 8452 n = export_dependent(opg, exp_str, fmri); 8453 if (n == NULL) 8454 export_property(exp_prop, exp_str, &pgelts, 0); 8455 else { 8456 if (eelts->dependents == NULL) 8457 eelts->dependents = n; 8458 else 8459 (void) xmlAddSibling(eelts->dependents, 8460 n); 8461 } 8462 } 8463 if (ret == -1) 8464 scfdie(); 8465 8466 free(fmri); 8467 free(type); 8468 8469 scf_iter_destroy(iter); 8470 scf_pg_destroy(opg); 8471 8472 if (pgelts.propvals != NULL || pgelts.properties != NULL) 8473 export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework, 8474 eelts); 8475 } 8476 8477 static void 8478 make_node(xmlNodePtr *nodep, const char *name) 8479 { 8480 if (*nodep == NULL) { 8481 *nodep = xmlNewNode(NULL, (xmlChar *)name); 8482 if (*nodep == NULL) 8483 uu_die(emsg_create_xml); 8484 } 8485 } 8486 8487 static xmlNodePtr 8488 export_tm_loctext(scf_propertygroup_t *pg, const char *parname) 8489 { 8490 int ret; 8491 xmlNodePtr parent = NULL; 8492 xmlNodePtr loctext = NULL; 8493 8494 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8495 scfdie(); 8496 8497 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8498 if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 || 8499 prop_get_val(exp_prop, exp_val) != 0) 8500 continue; 8501 8502 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0) 8503 scfdie(); 8504 8505 make_node(&parent, parname); 8506 loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext", 8507 (xmlChar *)exp_str); 8508 if (loctext == NULL) 8509 uu_die(emsg_create_xml); 8510 8511 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8512 scfdie(); 8513 8514 safe_setprop(loctext, "xml:lang", exp_str); 8515 } 8516 8517 if (ret == -1) 8518 scfdie(); 8519 8520 return (parent); 8521 } 8522 8523 static xmlNodePtr 8524 export_tm_manpage(scf_propertygroup_t *pg) 8525 { 8526 xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage"); 8527 if (manpage == NULL) 8528 uu_die(emsg_create_xml); 8529 8530 if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 || 8531 set_attr_from_prop(exp_prop, manpage, "title") != 0 || 8532 pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 || 8533 set_attr_from_prop(exp_prop, manpage, "section") != 0) { 8534 xmlFreeNode(manpage); 8535 return (NULL); 8536 } 8537 8538 if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0) 8539 (void) set_attr_from_prop_default(exp_prop, 8540 manpage, "manpath", ":default"); 8541 8542 return (manpage); 8543 } 8544 8545 static xmlNodePtr 8546 export_tm_doc_link(scf_propertygroup_t *pg) 8547 { 8548 xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link"); 8549 if (doc_link == NULL) 8550 uu_die(emsg_create_xml); 8551 8552 if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 || 8553 set_attr_from_prop(exp_prop, doc_link, "name") != 0 || 8554 pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 || 8555 set_attr_from_prop(exp_prop, doc_link, "uri") != 0) { 8556 xmlFreeNode(doc_link); 8557 return (NULL); 8558 } 8559 return (doc_link); 8560 } 8561 8562 /* 8563 * Process template information for a service or instances. 8564 */ 8565 static void 8566 export_template(scf_propertygroup_t *pg, struct entity_elts *elts, 8567 struct template_elts *telts) 8568 { 8569 size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX); 8570 size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX); 8571 xmlNodePtr child = NULL; 8572 8573 if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0) 8574 scfdie(); 8575 8576 if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) { 8577 telts->common_name = export_tm_loctext(pg, "common_name"); 8578 if (telts->common_name == NULL) 8579 export_pg(pg, elts, 0); 8580 return; 8581 } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) { 8582 telts->description = export_tm_loctext(pg, "description"); 8583 if (telts->description == NULL) 8584 export_pg(pg, elts, 0); 8585 return; 8586 } 8587 8588 if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) { 8589 child = export_tm_manpage(pg); 8590 } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) { 8591 child = export_tm_doc_link(pg); 8592 } 8593 8594 if (child != NULL) { 8595 make_node(&telts->documentation, "documentation"); 8596 (void) xmlAddChild(telts->documentation, child); 8597 } else { 8598 export_pg(pg, elts, 0); 8599 } 8600 } 8601 8602 /* 8603 * Process the general property group for an instance. 8604 */ 8605 static void 8606 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode, 8607 struct entity_elts *elts) 8608 { 8609 uint8_t enabled; 8610 struct pg_elts pgelts; 8611 int ret; 8612 8613 /* enabled */ 8614 if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 && 8615 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 8616 prop_get_val(exp_prop, exp_val) == 0) { 8617 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS) 8618 scfdie(); 8619 } else { 8620 enabled = 0; 8621 } 8622 8623 safe_setprop(inode, enabled_attr, enabled ? true : false); 8624 8625 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8626 scfdie(); 8627 8628 (void) memset(&pgelts, 0, sizeof (pgelts)); 8629 8630 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8631 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8632 scfdie(); 8633 8634 if (strcmp(exp_str, scf_property_enabled) == 0) { 8635 continue; 8636 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 8637 xmlNodePtr rnode, sfnode; 8638 8639 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 8640 if (rnode == NULL) 8641 uu_die(emsg_create_xml); 8642 8643 sfnode = xmlNewChild(rnode, NULL, 8644 (xmlChar *)"service_fmri", NULL); 8645 if (sfnode == NULL) 8646 uu_die(emsg_create_xml); 8647 8648 if (set_attr_from_prop(exp_prop, sfnode, 8649 value_attr) == 0) { 8650 elts->restarter = rnode; 8651 continue; 8652 } 8653 8654 xmlFreeNode(rnode); 8655 } 8656 8657 export_property(exp_prop, exp_str, &pgelts, 0); 8658 } 8659 if (ret == -1) 8660 scfdie(); 8661 8662 if (pgelts.propvals != NULL || pgelts.properties != NULL) 8663 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework, 8664 elts); 8665 } 8666 8667 /* 8668 * Put an instance element for the given instance into selts. 8669 */ 8670 static void 8671 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags) 8672 { 8673 xmlNodePtr n; 8674 boolean_t isdefault; 8675 struct entity_elts elts; 8676 struct template_elts template_elts; 8677 int ret; 8678 8679 n = xmlNewNode(NULL, (xmlChar *)"instance"); 8680 if (n == NULL) 8681 uu_die(emsg_create_xml); 8682 8683 /* name */ 8684 if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0) 8685 scfdie(); 8686 safe_setprop(n, name_attr, exp_str); 8687 isdefault = strcmp(exp_str, "default") == 0; 8688 8689 /* check existance of general pg (since general/enabled is required) */ 8690 if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) { 8691 if (scf_error() != SCF_ERROR_NOT_FOUND) 8692 scfdie(); 8693 8694 if (g_verbose) { 8695 if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0) 8696 scfdie(); 8697 8698 warn(gettext("Instance %s has no general property " 8699 "group; it will be marked disabled.\n"), exp_str); 8700 } 8701 8702 safe_setprop(n, enabled_attr, false); 8703 } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 || 8704 strcmp(exp_str, scf_group_framework) != 0) { 8705 if (g_verbose) { 8706 if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0) 8707 scfdie(); 8708 8709 warn(gettext("Property group %s is not of type " 8710 "framework; the instance will be marked " 8711 "disabled.\n"), exp_str); 8712 } 8713 8714 safe_setprop(n, enabled_attr, false); 8715 } 8716 8717 /* property groups */ 8718 if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0) 8719 scfdie(); 8720 8721 (void) memset(&elts, 0, sizeof (elts)); 8722 (void) memset(&template_elts, 0, sizeof (template_elts)); 8723 8724 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 8725 uint32_t pgflags; 8726 8727 if (scf_pg_get_flags(exp_pg, &pgflags) != 0) 8728 scfdie(); 8729 8730 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) 8731 continue; 8732 8733 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 8734 scfdie(); 8735 8736 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 8737 export_dependency(exp_pg, &elts); 8738 continue; 8739 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 8740 export_method(exp_pg, &elts); 8741 continue; 8742 } else if (strcmp(exp_str, scf_group_framework) == 0) { 8743 if (scf_pg_get_name(exp_pg, exp_str, 8744 max_scf_name_len + 1) < 0) 8745 scfdie(); 8746 8747 if (strcmp(exp_str, scf_pg_general) == 0) { 8748 export_inst_general(exp_pg, n, &elts); 8749 continue; 8750 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 8751 0) { 8752 export_method_context(exp_pg, &elts); 8753 continue; 8754 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 8755 export_dependents(exp_pg, &elts); 8756 continue; 8757 } 8758 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 8759 export_template(exp_pg, &elts, &template_elts); 8760 continue; 8761 } 8762 8763 /* Ordinary pg. */ 8764 export_pg(exp_pg, &elts, flags); 8765 } 8766 if (ret == -1) 8767 scfdie(); 8768 8769 if (template_elts.common_name != NULL) { 8770 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 8771 (void) xmlAddChild(elts.template, template_elts.common_name); 8772 (void) xmlAddChild(elts.template, template_elts.description); 8773 (void) xmlAddChild(elts.template, template_elts.documentation); 8774 } else { 8775 xmlFreeNode(template_elts.description); 8776 xmlFreeNode(template_elts.documentation); 8777 } 8778 8779 if (isdefault && elts.restarter == NULL && 8780 elts.dependencies == NULL && elts.method_context == NULL && 8781 elts.exec_methods == NULL && elts.property_groups == NULL && 8782 elts.template == NULL) { 8783 xmlChar *eval; 8784 8785 /* This is a default instance */ 8786 eval = xmlGetProp(n, (xmlChar *)enabled_attr); 8787 8788 xmlFreeNode(n); 8789 8790 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance"); 8791 if (n == NULL) 8792 uu_die(emsg_create_xml); 8793 8794 safe_setprop(n, enabled_attr, (char *)eval); 8795 xmlFree(eval); 8796 8797 selts->create_default_instance = n; 8798 } else { 8799 /* Assemble the children in order. */ 8800 (void) xmlAddChild(n, elts.restarter); 8801 (void) xmlAddChildList(n, elts.dependencies); 8802 (void) xmlAddChildList(n, elts.dependents); 8803 (void) xmlAddChild(n, elts.method_context); 8804 (void) xmlAddChildList(n, elts.exec_methods); 8805 (void) xmlAddChildList(n, elts.property_groups); 8806 (void) xmlAddChild(n, elts.template); 8807 8808 if (selts->instances == NULL) 8809 selts->instances = n; 8810 else 8811 (void) xmlAddSibling(selts->instances, n); 8812 } 8813 } 8814 8815 /* 8816 * Return a service element for the given service. 8817 */ 8818 static xmlNodePtr 8819 export_service(scf_service_t *svc, int flags) 8820 { 8821 xmlNodePtr snode; 8822 struct entity_elts elts; 8823 struct template_elts template_elts; 8824 int ret; 8825 8826 snode = xmlNewNode(NULL, (xmlChar *)"service"); 8827 if (snode == NULL) 8828 uu_die(emsg_create_xml); 8829 8830 /* Get & set name attribute */ 8831 if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0) 8832 scfdie(); 8833 safe_setprop(snode, name_attr, exp_str); 8834 8835 safe_setprop(snode, type_attr, "service"); 8836 safe_setprop(snode, "version", "0"); 8837 8838 /* Acquire child elements. */ 8839 if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS) 8840 scfdie(); 8841 8842 (void) memset(&elts, 0, sizeof (elts)); 8843 (void) memset(&template_elts, 0, sizeof (template_elts)); 8844 8845 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 8846 uint32_t pgflags; 8847 8848 if (scf_pg_get_flags(exp_pg, &pgflags) != 0) 8849 scfdie(); 8850 8851 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) 8852 continue; 8853 8854 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 8855 scfdie(); 8856 8857 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 8858 export_dependency(exp_pg, &elts); 8859 continue; 8860 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 8861 export_method(exp_pg, &elts); 8862 continue; 8863 } else if (strcmp(exp_str, scf_group_framework) == 0) { 8864 if (scf_pg_get_name(exp_pg, exp_str, 8865 max_scf_name_len + 1) < 0) 8866 scfdie(); 8867 8868 if (strcmp(exp_str, scf_pg_general) == 0) { 8869 export_svc_general(exp_pg, &elts); 8870 continue; 8871 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 8872 0) { 8873 export_method_context(exp_pg, &elts); 8874 continue; 8875 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 8876 export_dependents(exp_pg, &elts); 8877 continue; 8878 } 8879 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 8880 export_template(exp_pg, &elts, &template_elts); 8881 continue; 8882 } 8883 8884 export_pg(exp_pg, &elts, flags); 8885 } 8886 if (ret == -1) 8887 scfdie(); 8888 8889 if (template_elts.common_name != NULL) { 8890 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 8891 (void) xmlAddChild(elts.template, template_elts.common_name); 8892 (void) xmlAddChild(elts.template, template_elts.description); 8893 (void) xmlAddChild(elts.template, template_elts.documentation); 8894 } else { 8895 xmlFreeNode(template_elts.description); 8896 xmlFreeNode(template_elts.documentation); 8897 } 8898 8899 /* Iterate instances */ 8900 if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS) 8901 scfdie(); 8902 8903 while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1) 8904 export_instance(exp_inst, &elts, flags); 8905 if (ret == -1) 8906 scfdie(); 8907 8908 /* Now add all of the accumulated elements in order. */ 8909 (void) xmlAddChild(snode, elts.create_default_instance); 8910 (void) xmlAddChild(snode, elts.single_instance); 8911 (void) xmlAddChild(snode, elts.restarter); 8912 (void) xmlAddChildList(snode, elts.dependencies); 8913 (void) xmlAddChildList(snode, elts.dependents); 8914 (void) xmlAddChild(snode, elts.method_context); 8915 (void) xmlAddChildList(snode, elts.exec_methods); 8916 (void) xmlAddChildList(snode, elts.property_groups); 8917 (void) xmlAddChildList(snode, elts.instances); 8918 (void) xmlAddChild(snode, elts.stability); 8919 (void) xmlAddChild(snode, elts.template); 8920 8921 return (snode); 8922 } 8923 8924 static int 8925 export_callback(void *data, scf_walkinfo_t *wip) 8926 { 8927 FILE *f; 8928 xmlDocPtr doc; 8929 xmlNodePtr sb; 8930 int result; 8931 struct export_args *argsp = (struct export_args *)data; 8932 8933 if ((exp_inst = scf_instance_create(g_hndl)) == NULL || 8934 (exp_pg = scf_pg_create(g_hndl)) == NULL || 8935 (exp_prop = scf_property_create(g_hndl)) == NULL || 8936 (exp_val = scf_value_create(g_hndl)) == NULL || 8937 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 8938 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 8939 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 8940 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 8941 scfdie(); 8942 8943 exp_str_sz = max_scf_len + 1; 8944 exp_str = safe_malloc(exp_str_sz); 8945 8946 if (argsp->filename != NULL) { 8947 errno = 0; 8948 f = fopen(argsp->filename, "wb"); 8949 if (f == NULL) { 8950 if (errno == 0) 8951 uu_die(gettext("Could not open \"%s\": no free " 8952 "stdio streams.\n"), argsp->filename); 8953 else 8954 uu_die(gettext("Could not open \"%s\""), 8955 argsp->filename); 8956 } 8957 } else 8958 f = stdout; 8959 8960 doc = xmlNewDoc((xmlChar *)"1.0"); 8961 if (doc == NULL) 8962 uu_die(gettext("Could not create XML document.\n")); 8963 8964 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 8965 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 8966 uu_die(emsg_create_xml); 8967 8968 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 8969 if (sb == NULL) 8970 uu_die(emsg_create_xml); 8971 safe_setprop(sb, type_attr, "manifest"); 8972 safe_setprop(sb, name_attr, "export"); 8973 (void) xmlAddSibling(doc->children, sb); 8974 8975 (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags)); 8976 8977 result = write_service_bundle(doc, f); 8978 8979 free(exp_str); 8980 scf_iter_destroy(exp_val_iter); 8981 scf_iter_destroy(exp_prop_iter); 8982 scf_iter_destroy(exp_pg_iter); 8983 scf_iter_destroy(exp_inst_iter); 8984 scf_value_destroy(exp_val); 8985 scf_property_destroy(exp_prop); 8986 scf_pg_destroy(exp_pg); 8987 scf_instance_destroy(exp_inst); 8988 8989 xmlFreeDoc(doc); 8990 8991 if (f != stdout) 8992 (void) fclose(f); 8993 8994 return (result); 8995 } 8996 8997 /* 8998 * Get the service named by fmri, build an XML tree which represents it, and 8999 * dump it into filename (or stdout if filename is NULL). 9000 */ 9001 int 9002 lscf_service_export(char *fmri, const char *filename, int flags) 9003 { 9004 struct export_args args; 9005 int ret, err; 9006 9007 lscf_prep_hndl(); 9008 9009 bzero(&args, sizeof (args)); 9010 args.filename = filename; 9011 args.flags = flags; 9012 9013 err = 0; 9014 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 9015 SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback, 9016 &args, &err, semerr)) != 0) { 9017 if (ret != -1) 9018 semerr(gettext("Failed to walk instances: %s\n"), 9019 scf_strerror(ret)); 9020 return (-1); 9021 } 9022 9023 /* 9024 * Error message has already been printed. 9025 */ 9026 if (err != 0) 9027 return (-1); 9028 9029 return (0); 9030 } 9031 9032 9033 /* 9034 * Archive 9035 */ 9036 9037 static xmlNodePtr 9038 make_archive(int flags) 9039 { 9040 xmlNodePtr sb; 9041 scf_scope_t *scope; 9042 scf_service_t *svc; 9043 scf_iter_t *iter; 9044 int r; 9045 9046 if ((scope = scf_scope_create(g_hndl)) == NULL || 9047 (svc = scf_service_create(g_hndl)) == NULL || 9048 (iter = scf_iter_create(g_hndl)) == NULL || 9049 (exp_inst = scf_instance_create(g_hndl)) == NULL || 9050 (exp_pg = scf_pg_create(g_hndl)) == NULL || 9051 (exp_prop = scf_property_create(g_hndl)) == NULL || 9052 (exp_val = scf_value_create(g_hndl)) == NULL || 9053 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 9054 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 9055 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 9056 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 9057 scfdie(); 9058 9059 exp_str_sz = max_scf_len + 1; 9060 exp_str = safe_malloc(exp_str_sz); 9061 9062 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 9063 if (sb == NULL) 9064 uu_die(emsg_create_xml); 9065 safe_setprop(sb, type_attr, "archive"); 9066 safe_setprop(sb, name_attr, "none"); 9067 9068 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) 9069 scfdie(); 9070 if (scf_iter_scope_services(iter, scope) != 0) 9071 scfdie(); 9072 9073 for (;;) { 9074 r = scf_iter_next_service(iter, svc); 9075 if (r == 0) 9076 break; 9077 if (r != 1) 9078 scfdie(); 9079 9080 if (scf_service_get_name(svc, exp_str, 9081 max_scf_name_len + 1) < 0) 9082 scfdie(); 9083 9084 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0) 9085 continue; 9086 9087 xmlAddChild(sb, export_service(svc, flags)); 9088 } 9089 9090 free(exp_str); 9091 9092 scf_iter_destroy(exp_val_iter); 9093 scf_iter_destroy(exp_prop_iter); 9094 scf_iter_destroy(exp_pg_iter); 9095 scf_iter_destroy(exp_inst_iter); 9096 scf_value_destroy(exp_val); 9097 scf_property_destroy(exp_prop); 9098 scf_pg_destroy(exp_pg); 9099 scf_instance_destroy(exp_inst); 9100 scf_iter_destroy(iter); 9101 scf_service_destroy(svc); 9102 scf_scope_destroy(scope); 9103 9104 return (sb); 9105 } 9106 9107 int 9108 lscf_archive(const char *filename, int flags) 9109 { 9110 FILE *f; 9111 xmlDocPtr doc; 9112 int result; 9113 9114 lscf_prep_hndl(); 9115 9116 if (filename != NULL) { 9117 errno = 0; 9118 f = fopen(filename, "wb"); 9119 if (f == NULL) { 9120 if (errno == 0) 9121 uu_die(gettext("Could not open \"%s\": no free " 9122 "stdio streams.\n"), filename); 9123 else 9124 uu_die(gettext("Could not open \"%s\""), 9125 filename); 9126 } 9127 } else 9128 f = stdout; 9129 9130 doc = xmlNewDoc((xmlChar *)"1.0"); 9131 if (doc == NULL) 9132 uu_die(gettext("Could not create XML document.\n")); 9133 9134 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 9135 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 9136 uu_die(emsg_create_xml); 9137 9138 (void) xmlAddSibling(doc->children, make_archive(flags)); 9139 9140 result = write_service_bundle(doc, f); 9141 9142 xmlFreeDoc(doc); 9143 9144 if (f != stdout) 9145 (void) fclose(f); 9146 9147 return (result); 9148 } 9149 9150 9151 /* 9152 * "Extract" a profile. 9153 */ 9154 int 9155 lscf_profile_extract(const char *filename) 9156 { 9157 FILE *f; 9158 xmlDocPtr doc; 9159 xmlNodePtr sb, snode, inode; 9160 scf_scope_t *scope; 9161 scf_service_t *svc; 9162 scf_instance_t *inst; 9163 scf_propertygroup_t *pg; 9164 scf_property_t *prop; 9165 scf_value_t *val; 9166 scf_iter_t *siter, *iiter; 9167 int r, s; 9168 char *namebuf; 9169 uint8_t b; 9170 int result; 9171 9172 lscf_prep_hndl(); 9173 9174 if (filename != NULL) { 9175 errno = 0; 9176 f = fopen(filename, "wb"); 9177 if (f == NULL) { 9178 if (errno == 0) 9179 uu_die(gettext("Could not open \"%s\": no " 9180 "free stdio streams.\n"), filename); 9181 else 9182 uu_die(gettext("Could not open \"%s\""), 9183 filename); 9184 } 9185 } else 9186 f = stdout; 9187 9188 doc = xmlNewDoc((xmlChar *)"1.0"); 9189 if (doc == NULL) 9190 uu_die(gettext("Could not create XML document.\n")); 9191 9192 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 9193 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 9194 uu_die(emsg_create_xml); 9195 9196 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 9197 if (sb == NULL) 9198 uu_die(emsg_create_xml); 9199 safe_setprop(sb, type_attr, "profile"); 9200 safe_setprop(sb, name_attr, "extract"); 9201 (void) xmlAddSibling(doc->children, sb); 9202 9203 if ((scope = scf_scope_create(g_hndl)) == NULL || 9204 (svc = scf_service_create(g_hndl)) == NULL || 9205 (inst = scf_instance_create(g_hndl)) == NULL || 9206 (pg = scf_pg_create(g_hndl)) == NULL || 9207 (prop = scf_property_create(g_hndl)) == NULL || 9208 (val = scf_value_create(g_hndl)) == NULL || 9209 (siter = scf_iter_create(g_hndl)) == NULL || 9210 (iiter = scf_iter_create(g_hndl)) == NULL) 9211 scfdie(); 9212 9213 if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS) 9214 scfdie(); 9215 9216 if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS) 9217 scfdie(); 9218 9219 namebuf = safe_malloc(max_scf_name_len + 1); 9220 9221 while ((r = scf_iter_next_service(siter, svc)) == 1) { 9222 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS) 9223 scfdie(); 9224 9225 snode = xmlNewNode(NULL, (xmlChar *)"service"); 9226 if (snode == NULL) 9227 uu_die(emsg_create_xml); 9228 9229 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) < 9230 0) 9231 scfdie(); 9232 9233 safe_setprop(snode, name_attr, namebuf); 9234 9235 safe_setprop(snode, type_attr, "service"); 9236 safe_setprop(snode, "version", "0"); 9237 9238 while ((s = scf_iter_next_instance(iiter, inst)) == 1) { 9239 if (scf_instance_get_pg(inst, scf_pg_general, pg) != 9240 SCF_SUCCESS) { 9241 if (scf_error() != SCF_ERROR_NOT_FOUND) 9242 scfdie(); 9243 9244 if (g_verbose) { 9245 ssize_t len; 9246 char *fmri; 9247 9248 len = 9249 scf_instance_to_fmri(inst, NULL, 0); 9250 if (len < 0) 9251 scfdie(); 9252 9253 fmri = safe_malloc(len + 1); 9254 9255 if (scf_instance_to_fmri(inst, fmri, 9256 len + 1) < 0) 9257 scfdie(); 9258 9259 warn("Instance %s has no \"%s\" " 9260 "property group.\n", fmri, 9261 scf_pg_general); 9262 9263 free(fmri); 9264 } 9265 9266 continue; 9267 } 9268 9269 if (pg_get_prop(pg, scf_property_enabled, prop) != 0 || 9270 prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 || 9271 prop_get_val(prop, val) != 0) 9272 continue; 9273 9274 inode = xmlNewChild(snode, NULL, (xmlChar *)"instance", 9275 NULL); 9276 if (inode == NULL) 9277 uu_die(emsg_create_xml); 9278 9279 if (scf_instance_get_name(inst, namebuf, 9280 max_scf_name_len + 1) < 0) 9281 scfdie(); 9282 9283 safe_setprop(inode, name_attr, namebuf); 9284 9285 if (scf_value_get_boolean(val, &b) != SCF_SUCCESS) 9286 scfdie(); 9287 9288 safe_setprop(inode, enabled_attr, b ? true : false); 9289 } 9290 if (s < 0) 9291 scfdie(); 9292 9293 if (snode->children != NULL) 9294 xmlAddChild(sb, snode); 9295 else 9296 xmlFreeNode(snode); 9297 } 9298 if (r < 0) 9299 scfdie(); 9300 9301 free(namebuf); 9302 9303 result = write_service_bundle(doc, f); 9304 9305 xmlFreeDoc(doc); 9306 9307 if (f != stdout) 9308 (void) fclose(f); 9309 9310 return (result); 9311 } 9312 9313 9314 /* 9315 * Entity manipulation commands 9316 */ 9317 9318 /* 9319 * Entity selection. If no entity is selected, then the current scope is in 9320 * cur_scope, and cur_svc and cur_inst are NULL. When a service is selected, 9321 * only cur_inst is NULL, and when an instance is selected, none are NULL. 9322 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and 9323 * cur_inst will be non-NULL. 9324 */ 9325 9326 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */ 9327 static int 9328 select_inst(const char *name) 9329 { 9330 scf_instance_t *inst; 9331 scf_error_t err; 9332 9333 assert(cur_svc != NULL); 9334 9335 inst = scf_instance_create(g_hndl); 9336 if (inst == NULL) 9337 scfdie(); 9338 9339 if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) { 9340 cur_inst = inst; 9341 return (0); 9342 } 9343 9344 err = scf_error(); 9345 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 9346 scfdie(); 9347 9348 scf_instance_destroy(inst); 9349 return (1); 9350 } 9351 9352 /* Returns as above. */ 9353 static int 9354 select_svc(const char *name) 9355 { 9356 scf_service_t *svc; 9357 scf_error_t err; 9358 9359 assert(cur_scope != NULL); 9360 9361 svc = scf_service_create(g_hndl); 9362 if (svc == NULL) 9363 scfdie(); 9364 9365 if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) { 9366 cur_svc = svc; 9367 return (0); 9368 } 9369 9370 err = scf_error(); 9371 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 9372 scfdie(); 9373 9374 scf_service_destroy(svc); 9375 return (1); 9376 } 9377 9378 /* ARGSUSED */ 9379 static int 9380 select_callback(void *unused, scf_walkinfo_t *wip) 9381 { 9382 scf_instance_t *inst; 9383 scf_service_t *svc; 9384 scf_scope_t *scope; 9385 9386 if (wip->inst != NULL) { 9387 if ((scope = scf_scope_create(g_hndl)) == NULL || 9388 (svc = scf_service_create(g_hndl)) == NULL || 9389 (inst = scf_instance_create(g_hndl)) == NULL) 9390 scfdie(); 9391 9392 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 9393 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 9394 scfdie(); 9395 } else { 9396 assert(wip->svc != NULL); 9397 9398 if ((scope = scf_scope_create(g_hndl)) == NULL || 9399 (svc = scf_service_create(g_hndl)) == NULL) 9400 scfdie(); 9401 9402 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 9403 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 9404 scfdie(); 9405 9406 inst = NULL; 9407 } 9408 9409 /* Clear out the current selection */ 9410 assert(cur_scope != NULL); 9411 scf_scope_destroy(cur_scope); 9412 scf_service_destroy(cur_svc); 9413 scf_instance_destroy(cur_inst); 9414 9415 cur_scope = scope; 9416 cur_svc = svc; 9417 cur_inst = inst; 9418 9419 return (0); 9420 } 9421 9422 void 9423 lscf_select(const char *fmri) 9424 { 9425 int ret, err; 9426 9427 lscf_prep_hndl(); 9428 9429 if (cur_snap != NULL) { 9430 struct snaplevel *elt; 9431 char *buf; 9432 9433 /* Error unless name is that of the next level. */ 9434 elt = uu_list_next(cur_levels, cur_elt); 9435 if (elt == NULL) { 9436 semerr(gettext("No children.\n")); 9437 return; 9438 } 9439 9440 buf = safe_malloc(max_scf_name_len + 1); 9441 9442 if (scf_snaplevel_get_instance_name(elt->sl, buf, 9443 max_scf_name_len + 1) < 0) 9444 scfdie(); 9445 9446 if (strcmp(buf, fmri) != 0) { 9447 semerr(gettext("No such child.\n")); 9448 free(buf); 9449 return; 9450 } 9451 9452 free(buf); 9453 9454 cur_elt = elt; 9455 cur_level = elt->sl; 9456 return; 9457 } 9458 9459 /* 9460 * Special case for 'svc:', which takes the user to the scope level. 9461 */ 9462 if (strcmp(fmri, "svc:") == 0) { 9463 scf_instance_destroy(cur_inst); 9464 scf_service_destroy(cur_svc); 9465 cur_inst = NULL; 9466 cur_svc = NULL; 9467 return; 9468 } 9469 9470 /* 9471 * Special case for ':properties'. This appears as part of 'list' but 9472 * can't be selected. Give a more helpful error message in this case. 9473 */ 9474 if (strcmp(fmri, ":properties") == 0) { 9475 semerr(gettext(":properties is not an entity. Try 'listprop' " 9476 "to list properties.\n")); 9477 return; 9478 } 9479 9480 /* 9481 * First try the argument as relative to the current selection. 9482 */ 9483 if (cur_inst != NULL) { 9484 /* EMPTY */; 9485 } else if (cur_svc != NULL) { 9486 if (select_inst(fmri) != 1) 9487 return; 9488 } else { 9489 if (select_svc(fmri) != 1) 9490 return; 9491 } 9492 9493 err = 0; 9494 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 9495 select_callback, NULL, &err, semerr)) != 0) { 9496 semerr(gettext("Failed to walk instances: %s\n"), 9497 scf_strerror(ret)); 9498 } 9499 } 9500 9501 void 9502 lscf_unselect(void) 9503 { 9504 lscf_prep_hndl(); 9505 9506 if (cur_snap != NULL) { 9507 struct snaplevel *elt; 9508 9509 elt = uu_list_prev(cur_levels, cur_elt); 9510 if (elt == NULL) { 9511 semerr(gettext("No parent levels.\n")); 9512 } else { 9513 cur_elt = elt; 9514 cur_level = elt->sl; 9515 } 9516 } else if (cur_inst != NULL) { 9517 scf_instance_destroy(cur_inst); 9518 cur_inst = NULL; 9519 } else if (cur_svc != NULL) { 9520 scf_service_destroy(cur_svc); 9521 cur_svc = NULL; 9522 } else { 9523 semerr(gettext("Cannot unselect at scope level.\n")); 9524 } 9525 } 9526 9527 /* 9528 * Return the FMRI of the current selection, for the prompt. 9529 */ 9530 void 9531 lscf_get_selection_str(char *buf, size_t bufsz) 9532 { 9533 char *cp; 9534 ssize_t fmrilen, szret; 9535 boolean_t deleted = B_FALSE; 9536 9537 if (g_hndl == NULL) { 9538 (void) strlcpy(buf, "svc:", bufsz); 9539 return; 9540 } 9541 9542 if (cur_level != NULL) { 9543 assert(cur_snap != NULL); 9544 9545 /* [ snapshot ] FMRI [: instance ] */ 9546 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len 9547 + 2 + max_scf_name_len + 1 + 1); 9548 9549 buf[0] = '['; 9550 9551 szret = scf_snapshot_get_name(cur_snap, buf + 1, 9552 max_scf_name_len + 1); 9553 if (szret < 0) { 9554 if (scf_error() != SCF_ERROR_DELETED) 9555 scfdie(); 9556 9557 goto snap_deleted; 9558 } 9559 9560 (void) strcat(buf, "]svc:/"); 9561 9562 cp = strchr(buf, '\0'); 9563 9564 szret = scf_snaplevel_get_service_name(cur_level, cp, 9565 max_scf_name_len + 1); 9566 if (szret < 0) { 9567 if (scf_error() != SCF_ERROR_DELETED) 9568 scfdie(); 9569 9570 goto snap_deleted; 9571 } 9572 9573 cp = strchr(cp, '\0'); 9574 9575 if (snaplevel_is_instance(cur_level)) { 9576 *cp++ = ':'; 9577 9578 if (scf_snaplevel_get_instance_name(cur_level, cp, 9579 max_scf_name_len + 1) < 0) { 9580 if (scf_error() != SCF_ERROR_DELETED) 9581 scfdie(); 9582 9583 goto snap_deleted; 9584 } 9585 } else { 9586 *cp++ = '['; 9587 *cp++ = ':'; 9588 9589 if (scf_instance_get_name(cur_inst, cp, 9590 max_scf_name_len + 1) < 0) { 9591 if (scf_error() != SCF_ERROR_DELETED) 9592 scfdie(); 9593 9594 goto snap_deleted; 9595 } 9596 9597 (void) strcat(buf, "]"); 9598 } 9599 9600 return; 9601 9602 snap_deleted: 9603 deleted = B_TRUE; 9604 free(buf); 9605 unselect_cursnap(); 9606 } 9607 9608 assert(cur_snap == NULL); 9609 9610 if (cur_inst != NULL) { 9611 assert(cur_svc != NULL); 9612 assert(cur_scope != NULL); 9613 9614 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz); 9615 if (fmrilen >= 0) { 9616 assert(fmrilen < bufsz); 9617 if (deleted) 9618 warn(emsg_deleted); 9619 return; 9620 } 9621 9622 if (scf_error() != SCF_ERROR_DELETED) 9623 scfdie(); 9624 9625 deleted = B_TRUE; 9626 9627 scf_instance_destroy(cur_inst); 9628 cur_inst = NULL; 9629 } 9630 9631 if (cur_svc != NULL) { 9632 assert(cur_scope != NULL); 9633 9634 szret = scf_service_to_fmri(cur_svc, buf, bufsz); 9635 if (szret >= 0) { 9636 assert(szret < bufsz); 9637 if (deleted) 9638 warn(emsg_deleted); 9639 return; 9640 } 9641 9642 if (scf_error() != SCF_ERROR_DELETED) 9643 scfdie(); 9644 9645 deleted = B_TRUE; 9646 scf_service_destroy(cur_svc); 9647 cur_svc = NULL; 9648 } 9649 9650 assert(cur_scope != NULL); 9651 fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz); 9652 9653 if (fmrilen < 0) 9654 scfdie(); 9655 9656 assert(fmrilen < bufsz); 9657 if (deleted) 9658 warn(emsg_deleted); 9659 } 9660 9661 /* 9662 * Entity listing. Entities and colon namespaces (e.g., :properties and 9663 * :statistics) are listed for the current selection. 9664 */ 9665 void 9666 lscf_list(const char *pattern) 9667 { 9668 scf_iter_t *iter; 9669 char *buf; 9670 int ret; 9671 9672 lscf_prep_hndl(); 9673 9674 if (cur_level != NULL) { 9675 struct snaplevel *elt; 9676 9677 (void) fputs(COLON_NAMESPACES, stdout); 9678 9679 elt = uu_list_next(cur_levels, cur_elt); 9680 if (elt == NULL) 9681 return; 9682 9683 /* 9684 * For now, we know that the next level is an instance. But 9685 * if we ever have multiple scopes, this could be complicated. 9686 */ 9687 buf = safe_malloc(max_scf_name_len + 1); 9688 if (scf_snaplevel_get_instance_name(elt->sl, buf, 9689 max_scf_name_len + 1) >= 0) { 9690 (void) puts(buf); 9691 } else { 9692 if (scf_error() != SCF_ERROR_DELETED) 9693 scfdie(); 9694 } 9695 9696 free(buf); 9697 9698 return; 9699 } 9700 9701 if (cur_inst != NULL) { 9702 (void) fputs(COLON_NAMESPACES, stdout); 9703 return; 9704 } 9705 9706 iter = scf_iter_create(g_hndl); 9707 if (iter == NULL) 9708 scfdie(); 9709 9710 buf = safe_malloc(max_scf_name_len + 1); 9711 9712 if (cur_svc != NULL) { 9713 /* List the instances in this service. */ 9714 scf_instance_t *inst; 9715 9716 inst = scf_instance_create(g_hndl); 9717 if (inst == NULL) 9718 scfdie(); 9719 9720 if (scf_iter_service_instances(iter, cur_svc) == 0) { 9721 safe_printf(COLON_NAMESPACES); 9722 9723 for (;;) { 9724 ret = scf_iter_next_instance(iter, inst); 9725 if (ret == 0) 9726 break; 9727 if (ret != 1) { 9728 if (scf_error() != SCF_ERROR_DELETED) 9729 scfdie(); 9730 9731 break; 9732 } 9733 9734 if (scf_instance_get_name(inst, buf, 9735 max_scf_name_len + 1) >= 0) { 9736 if (pattern == NULL || 9737 fnmatch(pattern, buf, 0) == 0) 9738 (void) puts(buf); 9739 } else { 9740 if (scf_error() != SCF_ERROR_DELETED) 9741 scfdie(); 9742 } 9743 } 9744 } else { 9745 if (scf_error() != SCF_ERROR_DELETED) 9746 scfdie(); 9747 } 9748 9749 scf_instance_destroy(inst); 9750 } else { 9751 /* List the services in this scope. */ 9752 scf_service_t *svc; 9753 9754 assert(cur_scope != NULL); 9755 9756 svc = scf_service_create(g_hndl); 9757 if (svc == NULL) 9758 scfdie(); 9759 9760 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS) 9761 scfdie(); 9762 9763 for (;;) { 9764 ret = scf_iter_next_service(iter, svc); 9765 if (ret == 0) 9766 break; 9767 if (ret != 1) 9768 scfdie(); 9769 9770 if (scf_service_get_name(svc, buf, 9771 max_scf_name_len + 1) >= 0) { 9772 if (pattern == NULL || 9773 fnmatch(pattern, buf, 0) == 0) 9774 safe_printf("%s\n", buf); 9775 } else { 9776 if (scf_error() != SCF_ERROR_DELETED) 9777 scfdie(); 9778 } 9779 } 9780 9781 scf_service_destroy(svc); 9782 } 9783 9784 free(buf); 9785 scf_iter_destroy(iter); 9786 } 9787 9788 /* 9789 * Entity addition. Creates an empty entity in the current selection. 9790 */ 9791 void 9792 lscf_add(const char *name) 9793 { 9794 lscf_prep_hndl(); 9795 9796 if (cur_snap != NULL) { 9797 semerr(emsg_cant_modify_snapshots); 9798 } else if (cur_inst != NULL) { 9799 semerr(gettext("Cannot add entities to an instance.\n")); 9800 } else if (cur_svc != NULL) { 9801 9802 if (scf_service_add_instance(cur_svc, name, NULL) != 9803 SCF_SUCCESS) { 9804 switch (scf_error()) { 9805 case SCF_ERROR_INVALID_ARGUMENT: 9806 semerr(gettext("Invalid name.\n")); 9807 break; 9808 9809 case SCF_ERROR_EXISTS: 9810 semerr(gettext("Instance already exists.\n")); 9811 break; 9812 9813 case SCF_ERROR_PERMISSION_DENIED: 9814 semerr(emsg_permission_denied); 9815 break; 9816 9817 default: 9818 scfdie(); 9819 } 9820 } 9821 } else { 9822 assert(cur_scope != NULL); 9823 9824 if (scf_scope_add_service(cur_scope, name, NULL) != 9825 SCF_SUCCESS) { 9826 switch (scf_error()) { 9827 case SCF_ERROR_INVALID_ARGUMENT: 9828 semerr(gettext("Invalid name.\n")); 9829 break; 9830 9831 case SCF_ERROR_EXISTS: 9832 semerr(gettext("Service already exists.\n")); 9833 break; 9834 9835 case SCF_ERROR_PERMISSION_DENIED: 9836 semerr(emsg_permission_denied); 9837 break; 9838 9839 case SCF_ERROR_BACKEND_READONLY: 9840 semerr(emsg_read_only); 9841 break; 9842 9843 default: 9844 scfdie(); 9845 } 9846 } 9847 } 9848 } 9849 9850 /* return 1 if the entity has no persistent pgs, else return 0 */ 9851 static int 9852 entity_has_no_pgs(void *ent, int isservice) 9853 { 9854 scf_iter_t *iter = NULL; 9855 scf_propertygroup_t *pg = NULL; 9856 uint32_t flags; 9857 int err; 9858 int ret = 1; 9859 9860 if ((iter = scf_iter_create(g_hndl)) == NULL || 9861 (pg = scf_pg_create(g_hndl)) == NULL) 9862 scfdie(); 9863 9864 if (isservice) { 9865 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0) 9866 scfdie(); 9867 } else { 9868 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0) 9869 scfdie(); 9870 } 9871 9872 while ((err = scf_iter_next_pg(iter, pg)) == 1) { 9873 if (scf_pg_get_flags(pg, &flags) != 0) 9874 scfdie(); 9875 9876 /* skip nonpersistent pgs */ 9877 if (flags & SCF_PG_FLAG_NONPERSISTENT) 9878 continue; 9879 9880 ret = 0; 9881 break; 9882 } 9883 9884 if (err == -1) 9885 scfdie(); 9886 9887 scf_pg_destroy(pg); 9888 scf_iter_destroy(iter); 9889 9890 return (ret); 9891 } 9892 9893 /* return 1 if the service has no instances, else return 0 */ 9894 static int 9895 svc_has_no_insts(scf_service_t *svc) 9896 { 9897 scf_instance_t *inst; 9898 scf_iter_t *iter; 9899 int r; 9900 int ret = 1; 9901 9902 if ((inst = scf_instance_create(g_hndl)) == NULL || 9903 (iter = scf_iter_create(g_hndl)) == NULL) 9904 scfdie(); 9905 9906 if (scf_iter_service_instances(iter, svc) != 0) 9907 scfdie(); 9908 9909 r = scf_iter_next_instance(iter, inst); 9910 if (r == 1) { 9911 ret = 0; 9912 } else if (r == 0) { 9913 ret = 1; 9914 } else if (r == -1) { 9915 scfdie(); 9916 } else { 9917 bad_error("scf_iter_next_instance", r); 9918 } 9919 9920 scf_iter_destroy(iter); 9921 scf_instance_destroy(inst); 9922 9923 return (ret); 9924 } 9925 9926 /* 9927 * Entity deletion. 9928 */ 9929 9930 /* 9931 * Delete the property group <fmri>/:properties/<name>. Returns 9932 * SCF_ERROR_NONE on success (or if the entity is not found), 9933 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if 9934 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was 9935 * denied. 9936 */ 9937 static scf_error_t 9938 delete_dependency_pg(const char *fmri, const char *name) 9939 { 9940 void *entity = NULL; 9941 int isservice; 9942 scf_propertygroup_t *pg = NULL; 9943 scf_error_t result; 9944 char *pgty; 9945 scf_service_t *svc = NULL; 9946 scf_instance_t *inst = NULL; 9947 scf_iter_t *iter = NULL; 9948 char *name_buf = NULL; 9949 9950 result = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 9951 switch (result) { 9952 case SCF_ERROR_NONE: 9953 break; 9954 9955 case SCF_ERROR_NO_MEMORY: 9956 uu_die(gettext("Out of memory.\n")); 9957 /* NOTREACHED */ 9958 9959 case SCF_ERROR_INVALID_ARGUMENT: 9960 case SCF_ERROR_CONSTRAINT_VIOLATED: 9961 return (SCF_ERROR_INVALID_ARGUMENT); 9962 9963 case SCF_ERROR_NOT_FOUND: 9964 result = SCF_ERROR_NONE; 9965 goto out; 9966 9967 default: 9968 bad_error("fmri_to_entity", result); 9969 } 9970 9971 pg = scf_pg_create(g_hndl); 9972 if (pg == NULL) 9973 scfdie(); 9974 9975 if (entity_get_pg(entity, isservice, name, pg) != 0) { 9976 if (scf_error() != SCF_ERROR_NOT_FOUND) 9977 scfdie(); 9978 9979 result = SCF_ERROR_NONE; 9980 goto out; 9981 } 9982 9983 pgty = safe_malloc(max_scf_pg_type_len + 1); 9984 9985 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 9986 scfdie(); 9987 9988 if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) { 9989 result = SCF_ERROR_TYPE_MISMATCH; 9990 free(pgty); 9991 goto out; 9992 } 9993 9994 free(pgty); 9995 9996 if (scf_pg_delete(pg) != 0) { 9997 result = scf_error(); 9998 if (result != SCF_ERROR_PERMISSION_DENIED) 9999 scfdie(); 10000 goto out; 10001 } 10002 10003 /* 10004 * We have to handle the case where we've just deleted the last 10005 * property group of a "dummy" entity (instance or service). 10006 * A "dummy" entity is an entity only present to hold an 10007 * external dependency. 10008 * So, in the case we deleted the last property group then we 10009 * can also delete the entity. If the entity is an instance then 10010 * we must verify if this was the last instance for the service 10011 * and if it is, we can also delete the service if it doesn't 10012 * have any property group either. 10013 */ 10014 10015 result = SCF_ERROR_NONE; 10016 10017 if (isservice) { 10018 svc = (scf_service_t *)entity; 10019 10020 if ((inst = scf_instance_create(g_hndl)) == NULL || 10021 (iter = scf_iter_create(g_hndl)) == NULL) 10022 scfdie(); 10023 10024 name_buf = safe_malloc(max_scf_name_len + 1); 10025 } else { 10026 inst = (scf_instance_t *)entity; 10027 } 10028 10029 /* 10030 * If the entity is an instance and we've just deleted its last 10031 * property group then we should delete it. 10032 */ 10033 if (!isservice && entity_has_no_pgs(entity, isservice)) { 10034 /* find the service before deleting the inst. - needed later */ 10035 if ((svc = scf_service_create(g_hndl)) == NULL) 10036 scfdie(); 10037 10038 if (scf_instance_get_parent(inst, svc) != 0) 10039 scfdie(); 10040 10041 /* delete the instance */ 10042 if (scf_instance_delete(inst) != 0) { 10043 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10044 scfdie(); 10045 10046 result = SCF_ERROR_PERMISSION_DENIED; 10047 goto out; 10048 } 10049 /* no need to refresh the instance */ 10050 inst = NULL; 10051 } 10052 10053 /* 10054 * If the service has no more instances and pgs or we just deleted the 10055 * last instance and the service doesn't have anymore propery groups 10056 * then the service should be deleted. 10057 */ 10058 if (svc != NULL && 10059 svc_has_no_insts(svc) && 10060 entity_has_no_pgs((void *)svc, 1)) { 10061 if (scf_service_delete(svc) == 0) { 10062 if (isservice) { 10063 /* no need to refresh the service */ 10064 svc = NULL; 10065 } 10066 10067 goto out; 10068 } 10069 10070 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10071 scfdie(); 10072 10073 result = SCF_ERROR_PERMISSION_DENIED; 10074 } 10075 10076 /* if the entity has not been deleted, refresh it */ 10077 if ((isservice && svc != NULL) || (!isservice && inst != NULL)) { 10078 (void) refresh_entity(isservice, entity, fmri, inst, iter, 10079 name_buf); 10080 } 10081 10082 out: 10083 if (isservice && (inst != NULL && iter != NULL)) { 10084 free(name_buf); 10085 scf_iter_destroy(iter); 10086 scf_instance_destroy(inst); 10087 } 10088 10089 if (!isservice && svc != NULL) { 10090 scf_service_destroy(svc); 10091 } 10092 10093 scf_pg_destroy(pg); 10094 if (entity != NULL) 10095 entity_destroy(entity, isservice); 10096 10097 return (result); 10098 } 10099 10100 static int 10101 delete_dependents(scf_propertygroup_t *pg) 10102 { 10103 char *pgty, *name, *fmri; 10104 scf_property_t *prop; 10105 scf_value_t *val; 10106 scf_iter_t *iter; 10107 int r; 10108 scf_error_t err; 10109 10110 /* Verify that the pg has the correct type. */ 10111 pgty = safe_malloc(max_scf_pg_type_len + 1); 10112 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 10113 scfdie(); 10114 10115 if (strcmp(pgty, scf_group_framework) != 0) { 10116 if (g_verbose) { 10117 fmri = safe_malloc(max_scf_fmri_len + 1); 10118 if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0) 10119 scfdie(); 10120 10121 warn(gettext("Property group %s is not of expected " 10122 "type %s.\n"), fmri, scf_group_framework); 10123 10124 free(fmri); 10125 } 10126 10127 free(pgty); 10128 return (-1); 10129 } 10130 10131 free(pgty); 10132 10133 /* map delete_dependency_pg onto the properties. */ 10134 if ((prop = scf_property_create(g_hndl)) == NULL || 10135 (val = scf_value_create(g_hndl)) == NULL || 10136 (iter = scf_iter_create(g_hndl)) == NULL) 10137 scfdie(); 10138 10139 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 10140 scfdie(); 10141 10142 name = safe_malloc(max_scf_name_len + 1); 10143 fmri = safe_malloc(max_scf_fmri_len + 2); 10144 10145 while ((r = scf_iter_next_property(iter, prop)) == 1) { 10146 scf_type_t ty; 10147 10148 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0) 10149 scfdie(); 10150 10151 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 10152 scfdie(); 10153 10154 if ((ty != SCF_TYPE_ASTRING && 10155 prop_check_type(prop, SCF_TYPE_FMRI) != 0) || 10156 prop_get_val(prop, val) != 0) 10157 continue; 10158 10159 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0) 10160 scfdie(); 10161 10162 err = delete_dependency_pg(fmri, name); 10163 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) { 10164 if (scf_property_to_fmri(prop, fmri, 10165 max_scf_fmri_len + 2) < 0) 10166 scfdie(); 10167 10168 warn(gettext("Value of %s is not a valid FMRI.\n"), 10169 fmri); 10170 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) { 10171 warn(gettext("Property group \"%s\" of entity \"%s\" " 10172 "does not have dependency type.\n"), name, fmri); 10173 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) { 10174 warn(gettext("Could not delete property group \"%s\" " 10175 "of entity \"%s\" (permission denied).\n"), name, 10176 fmri); 10177 } 10178 } 10179 if (r == -1) 10180 scfdie(); 10181 10182 scf_value_destroy(val); 10183 scf_property_destroy(prop); 10184 10185 return (0); 10186 } 10187 10188 /* 10189 * Returns 1 if the instance may be running, and 0 otherwise. 10190 */ 10191 static int 10192 inst_is_running(scf_instance_t *inst) 10193 { 10194 scf_propertygroup_t *pg; 10195 scf_property_t *prop; 10196 scf_value_t *val; 10197 char buf[MAX_SCF_STATE_STRING_SZ]; 10198 int ret = 0; 10199 ssize_t szret; 10200 10201 if ((pg = scf_pg_create(g_hndl)) == NULL || 10202 (prop = scf_property_create(g_hndl)) == NULL || 10203 (val = scf_value_create(g_hndl)) == NULL) 10204 scfdie(); 10205 10206 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) { 10207 if (scf_error() != SCF_ERROR_NOT_FOUND) 10208 scfdie(); 10209 goto out; 10210 } 10211 10212 if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 || 10213 prop_check_type(prop, SCF_TYPE_ASTRING) != 0 || 10214 prop_get_val(prop, val) != 0) 10215 goto out; 10216 10217 szret = scf_value_get_astring(val, buf, sizeof (buf)); 10218 assert(szret >= 0); 10219 10220 ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 || 10221 strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0; 10222 10223 out: 10224 scf_value_destroy(val); 10225 scf_property_destroy(prop); 10226 scf_pg_destroy(pg); 10227 return (ret); 10228 } 10229 10230 static uint8_t 10231 pg_is_external_dependency(scf_propertygroup_t *pg) 10232 { 10233 char *type; 10234 scf_value_t *val; 10235 scf_property_t *prop; 10236 uint8_t b = B_FALSE; 10237 10238 type = safe_malloc(max_scf_pg_type_len + 1); 10239 10240 if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0) 10241 scfdie(); 10242 10243 if ((prop = scf_property_create(g_hndl)) == NULL || 10244 (val = scf_value_create(g_hndl)) == NULL) 10245 scfdie(); 10246 10247 if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) { 10248 if (pg_get_prop(pg, scf_property_external, prop) == 0) { 10249 if (scf_property_get_value(prop, val) != 0) 10250 scfdie(); 10251 if (scf_value_get_boolean(val, &b) != 0) 10252 scfdie(); 10253 } 10254 } 10255 10256 free(type); 10257 (void) scf_value_destroy(val); 10258 (void) scf_property_destroy(prop); 10259 10260 return (b); 10261 } 10262 10263 #define DELETE_FAILURE -1 10264 #define DELETE_SUCCESS_NOEXTDEPS 0 10265 #define DELETE_SUCCESS_EXTDEPS 1 10266 10267 /* 10268 * lscf_instance_delete() deletes an instance. Before calling 10269 * scf_instance_delete(), though, we make sure the instance isn't 10270 * running and delete dependencies in other entities which the instance 10271 * declared as "dependents". If there are dependencies which were 10272 * created for other entities, then instead of deleting the instance we 10273 * make it "empty" by deleting all other property groups and all 10274 * snapshots. 10275 * 10276 * lscf_instance_delete() verifies that there is no external dependency pgs 10277 * before suppressing the instance. If there is, then we must not remove them 10278 * now in case the instance is re-created otherwise the dependencies would be 10279 * lost. The external dependency pgs will be removed if the dependencies are 10280 * removed. 10281 * 10282 * Returns: 10283 * DELETE_FAILURE on failure 10284 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies 10285 * DELETE_SUCCESS_EXTDEPS on success - external dependencies 10286 */ 10287 static int 10288 lscf_instance_delete(scf_instance_t *inst, int force) 10289 { 10290 scf_propertygroup_t *pg; 10291 scf_snapshot_t *snap; 10292 scf_iter_t *iter; 10293 int err; 10294 int external = 0; 10295 10296 /* If we're not forcing and the instance is running, refuse. */ 10297 if (!force && inst_is_running(inst)) { 10298 char *fmri; 10299 10300 fmri = safe_malloc(max_scf_fmri_len + 1); 10301 10302 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0) 10303 scfdie(); 10304 10305 semerr(gettext("Instance %s may be running. " 10306 "Use delete -f if it is not.\n"), fmri); 10307 10308 free(fmri); 10309 return (DELETE_FAILURE); 10310 } 10311 10312 pg = scf_pg_create(g_hndl); 10313 if (pg == NULL) 10314 scfdie(); 10315 10316 if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0) 10317 (void) delete_dependents(pg); 10318 else if (scf_error() != SCF_ERROR_NOT_FOUND) 10319 scfdie(); 10320 10321 scf_pg_destroy(pg); 10322 10323 /* 10324 * If the instance has some external dependencies then we must 10325 * keep them in case the instance is reimported otherwise the 10326 * dependencies would be lost on reimport. 10327 */ 10328 if ((iter = scf_iter_create(g_hndl)) == NULL || 10329 (pg = scf_pg_create(g_hndl)) == NULL) 10330 scfdie(); 10331 10332 if (scf_iter_instance_pgs(iter, inst) < 0) 10333 scfdie(); 10334 10335 while ((err = scf_iter_next_pg(iter, pg)) == 1) { 10336 if (pg_is_external_dependency(pg)) { 10337 external = 1; 10338 continue; 10339 } 10340 10341 if (scf_pg_delete(pg) != 0) { 10342 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10343 scfdie(); 10344 else { 10345 semerr(emsg_permission_denied); 10346 10347 (void) scf_iter_destroy(iter); 10348 (void) scf_pg_destroy(pg); 10349 return (DELETE_FAILURE); 10350 } 10351 } 10352 } 10353 10354 if (err == -1) 10355 scfdie(); 10356 10357 (void) scf_iter_destroy(iter); 10358 (void) scf_pg_destroy(pg); 10359 10360 if (external) { 10361 /* 10362 * All the pgs have been deleted for the instance except 10363 * the ones holding the external dependencies. 10364 * For the job to be complete, we must also delete the 10365 * snapshots associated with the instance. 10366 */ 10367 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) == 10368 NULL) 10369 scfdie(); 10370 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL) 10371 scfdie(); 10372 10373 if (scf_iter_instance_snapshots(iter, inst) == -1) 10374 scfdie(); 10375 10376 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) { 10377 if (_scf_snapshot_delete(snap) != 0) { 10378 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10379 scfdie(); 10380 10381 semerr(emsg_permission_denied); 10382 10383 (void) scf_iter_destroy(iter); 10384 (void) scf_snapshot_destroy(snap); 10385 return (DELETE_FAILURE); 10386 } 10387 } 10388 10389 if (err == -1) 10390 scfdie(); 10391 10392 (void) scf_iter_destroy(iter); 10393 (void) scf_snapshot_destroy(snap); 10394 return (DELETE_SUCCESS_EXTDEPS); 10395 } 10396 10397 if (scf_instance_delete(inst) != 0) { 10398 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10399 scfdie(); 10400 10401 semerr(emsg_permission_denied); 10402 10403 return (DELETE_FAILURE); 10404 } 10405 10406 return (DELETE_SUCCESS_NOEXTDEPS); 10407 } 10408 10409 /* 10410 * lscf_service_delete() deletes a service. Before calling 10411 * scf_service_delete(), though, we call lscf_instance_delete() for 10412 * each of the instances and delete dependencies in other entities 10413 * which were created as "dependents" of this service. If there are 10414 * dependencies which were created for other entities, then we delete 10415 * all other property groups in the service and leave it as "empty". 10416 * 10417 * lscf_service_delete() verifies that there is no external dependency 10418 * pgs at the instance & service level before suppressing the service. 10419 * If there is, then we must not remove them now in case the service 10420 * is re-imported otherwise the dependencies would be lost. The external 10421 * dependency pgs will be removed if the dependencies are removed. 10422 * 10423 * Returns: 10424 * DELETE_FAILURE on failure 10425 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies 10426 * DELETE_SUCCESS_EXTDEPS on success - external dependencies 10427 */ 10428 static int 10429 lscf_service_delete(scf_service_t *svc, int force) 10430 { 10431 int r; 10432 scf_instance_t *inst; 10433 scf_propertygroup_t *pg; 10434 scf_iter_t *iter; 10435 int ret; 10436 int external = 0; 10437 10438 if ((inst = scf_instance_create(g_hndl)) == NULL || 10439 (pg = scf_pg_create(g_hndl)) == NULL || 10440 (iter = scf_iter_create(g_hndl)) == NULL) 10441 scfdie(); 10442 10443 if (scf_iter_service_instances(iter, svc) != 0) 10444 scfdie(); 10445 10446 for (r = scf_iter_next_instance(iter, inst); 10447 r == 1; 10448 r = scf_iter_next_instance(iter, inst)) { 10449 10450 ret = lscf_instance_delete(inst, force); 10451 if (ret == DELETE_FAILURE) { 10452 scf_iter_destroy(iter); 10453 scf_pg_destroy(pg); 10454 scf_instance_destroy(inst); 10455 return (DELETE_FAILURE); 10456 } 10457 10458 /* 10459 * Record the fact that there is some external dependencies 10460 * at the instance level. 10461 */ 10462 if (ret == DELETE_SUCCESS_EXTDEPS) 10463 external |= 1; 10464 } 10465 10466 if (r != 0) 10467 scfdie(); 10468 10469 /* Delete dependency property groups in dependent services. */ 10470 if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0) 10471 (void) delete_dependents(pg); 10472 else if (scf_error() != SCF_ERROR_NOT_FOUND) 10473 scfdie(); 10474 10475 scf_iter_destroy(iter); 10476 scf_pg_destroy(pg); 10477 scf_instance_destroy(inst); 10478 10479 /* 10480 * If the service has some external dependencies then we don't 10481 * want to remove them in case the service is re-imported. 10482 */ 10483 if ((pg = scf_pg_create(g_hndl)) == NULL || 10484 (iter = scf_iter_create(g_hndl)) == NULL) 10485 scfdie(); 10486 10487 if (scf_iter_service_pgs(iter, svc) < 0) 10488 scfdie(); 10489 10490 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 10491 if (pg_is_external_dependency(pg)) { 10492 external |= 2; 10493 continue; 10494 } 10495 10496 if (scf_pg_delete(pg) != 0) { 10497 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10498 scfdie(); 10499 else { 10500 semerr(emsg_permission_denied); 10501 10502 (void) scf_iter_destroy(iter); 10503 (void) scf_pg_destroy(pg); 10504 return (DELETE_FAILURE); 10505 } 10506 } 10507 } 10508 10509 if (r == -1) 10510 scfdie(); 10511 10512 (void) scf_iter_destroy(iter); 10513 (void) scf_pg_destroy(pg); 10514 10515 if (external != 0) 10516 return (DELETE_SUCCESS_EXTDEPS); 10517 10518 if (scf_service_delete(svc) == 0) 10519 return (DELETE_SUCCESS_NOEXTDEPS); 10520 10521 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10522 scfdie(); 10523 10524 semerr(emsg_permission_denied); 10525 return (DELETE_FAILURE); 10526 } 10527 10528 static int 10529 delete_callback(void *data, scf_walkinfo_t *wip) 10530 { 10531 int force = (int)data; 10532 10533 if (wip->inst != NULL) 10534 (void) lscf_instance_delete(wip->inst, force); 10535 else 10536 (void) lscf_service_delete(wip->svc, force); 10537 10538 return (0); 10539 } 10540 10541 void 10542 lscf_delete(const char *fmri, int force) 10543 { 10544 scf_service_t *svc; 10545 scf_instance_t *inst; 10546 int ret; 10547 10548 lscf_prep_hndl(); 10549 10550 if (cur_snap != NULL) { 10551 if (!snaplevel_is_instance(cur_level)) { 10552 char *buf; 10553 10554 buf = safe_malloc(max_scf_name_len + 1); 10555 if (scf_instance_get_name(cur_inst, buf, 10556 max_scf_name_len + 1) >= 0) { 10557 if (strcmp(buf, fmri) == 0) { 10558 semerr(emsg_cant_modify_snapshots); 10559 free(buf); 10560 return; 10561 } 10562 } else if (scf_error() != SCF_ERROR_DELETED) { 10563 scfdie(); 10564 } 10565 free(buf); 10566 } 10567 } else if (cur_inst != NULL) { 10568 /* EMPTY */; 10569 } else if (cur_svc != NULL) { 10570 inst = scf_instance_create(g_hndl); 10571 if (inst == NULL) 10572 scfdie(); 10573 10574 if (scf_service_get_instance(cur_svc, fmri, inst) == 10575 SCF_SUCCESS) { 10576 (void) lscf_instance_delete(inst, force); 10577 scf_instance_destroy(inst); 10578 return; 10579 } 10580 10581 if (scf_error() != SCF_ERROR_NOT_FOUND && 10582 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 10583 scfdie(); 10584 10585 scf_instance_destroy(inst); 10586 } else { 10587 assert(cur_scope != NULL); 10588 10589 svc = scf_service_create(g_hndl); 10590 if (svc == NULL) 10591 scfdie(); 10592 10593 if (scf_scope_get_service(cur_scope, fmri, svc) == 10594 SCF_SUCCESS) { 10595 (void) lscf_service_delete(svc, force); 10596 scf_service_destroy(svc); 10597 return; 10598 } 10599 10600 if (scf_error() != SCF_ERROR_NOT_FOUND && 10601 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 10602 scfdie(); 10603 10604 scf_service_destroy(svc); 10605 } 10606 10607 /* 10608 * Match FMRI to entity. 10609 */ 10610 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 10611 delete_callback, (void *)force, NULL, semerr)) != 0) { 10612 semerr(gettext("Failed to walk instances: %s\n"), 10613 scf_strerror(ret)); 10614 } 10615 } 10616 10617 10618 10619 /* 10620 * :properties commands. These all end with "pg" or "prop" and generally 10621 * operate on the currently selected entity. 10622 */ 10623 10624 /* 10625 * Property listing. List the property groups, properties, their types and 10626 * their values for the currently selected entity. 10627 */ 10628 static void 10629 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth) 10630 { 10631 char *buf; 10632 uint32_t flags; 10633 10634 buf = safe_malloc(max_scf_pg_type_len + 1); 10635 10636 if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0) 10637 scfdie(); 10638 10639 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 10640 scfdie(); 10641 10642 safe_printf("%-*s %s", namewidth, name, buf); 10643 10644 if (flags & SCF_PG_FLAG_NONPERSISTENT) 10645 safe_printf("\tNONPERSISTENT"); 10646 10647 safe_printf("\n"); 10648 10649 free(buf); 10650 } 10651 10652 static boolean_t 10653 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val) 10654 { 10655 if (scf_property_get_value(prop, val) == 0) { 10656 return (B_FALSE); 10657 } else { 10658 switch (scf_error()) { 10659 case SCF_ERROR_NOT_FOUND: 10660 return (B_FALSE); 10661 case SCF_ERROR_PERMISSION_DENIED: 10662 case SCF_ERROR_CONSTRAINT_VIOLATED: 10663 return (B_TRUE); 10664 default: 10665 scfdie(); 10666 /*NOTREACHED*/ 10667 } 10668 } 10669 } 10670 10671 static void 10672 list_prop_info(const scf_property_t *prop, const char *name, size_t len) 10673 { 10674 scf_iter_t *iter; 10675 scf_value_t *val; 10676 const char *type; 10677 int multiple_strings = 0; 10678 int ret; 10679 10680 if ((iter = scf_iter_create(g_hndl)) == NULL || 10681 (val = scf_value_create(g_hndl)) == NULL) 10682 scfdie(); 10683 10684 type = prop_to_typestr(prop); 10685 assert(type != NULL); 10686 10687 safe_printf("%-*s %-7s ", len, name, type); 10688 10689 if (prop_has_multiple_values(prop, val) && 10690 (scf_value_type(val) == SCF_TYPE_ASTRING || 10691 scf_value_type(val) == SCF_TYPE_USTRING)) 10692 multiple_strings = 1; 10693 10694 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS) 10695 scfdie(); 10696 10697 while ((ret = scf_iter_next_value(iter, val)) == 1) { 10698 char *buf; 10699 ssize_t vlen, szret; 10700 10701 vlen = scf_value_get_as_string(val, NULL, 0); 10702 if (vlen < 0) 10703 scfdie(); 10704 10705 buf = safe_malloc(vlen + 1); 10706 10707 szret = scf_value_get_as_string(val, buf, vlen + 1); 10708 if (szret < 0) 10709 scfdie(); 10710 assert(szret <= vlen); 10711 10712 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */ 10713 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) { 10714 safe_printf(" \""); 10715 (void) quote_and_print(buf, stdout, 0); 10716 (void) putchar('"'); 10717 if (ferror(stdout)) { 10718 (void) putchar('\n'); 10719 uu_die(gettext("Error writing to stdout.\n")); 10720 } 10721 } else { 10722 safe_printf(" %s", buf); 10723 } 10724 10725 free(buf); 10726 } 10727 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 10728 scfdie(); 10729 10730 if (putchar('\n') != '\n') 10731 uu_die(gettext("Could not output newline")); 10732 } 10733 10734 static void 10735 listprop(const char *pattern, int only_pgs) 10736 { 10737 scf_propertygroup_t *pg; 10738 scf_property_t *prop; 10739 scf_iter_t *iter, *piter; 10740 char *pgnbuf, *prnbuf, *ppnbuf; 10741 10742 void **objects; 10743 char **names; 10744 int allocd, i; 10745 10746 int ret; 10747 ssize_t pgnlen, prnlen, szret; 10748 size_t max_len = 0; 10749 10750 if (cur_svc == NULL && cur_inst == NULL) { 10751 semerr(emsg_entity_not_selected); 10752 return; 10753 } 10754 10755 if ((pg = scf_pg_create(g_hndl)) == NULL || 10756 (prop = scf_property_create(g_hndl)) == NULL || 10757 (iter = scf_iter_create(g_hndl)) == NULL || 10758 (piter = scf_iter_create(g_hndl)) == NULL) 10759 scfdie(); 10760 10761 prnbuf = safe_malloc(max_scf_name_len + 1); 10762 10763 if (cur_level != NULL) 10764 ret = scf_iter_snaplevel_pgs(iter, cur_level); 10765 else if (cur_inst != NULL) 10766 ret = scf_iter_instance_pgs(iter, cur_inst); 10767 else 10768 ret = scf_iter_service_pgs(iter, cur_svc); 10769 if (ret != 0) { 10770 if (scf_error() == SCF_ERROR_DELETED) 10771 scfdie(); 10772 return; 10773 } 10774 10775 /* 10776 * We want to only list items which match pattern, and we want the 10777 * second column to line up, so during the first pass we'll save 10778 * matching items & their names in objects and names, computing the 10779 * maximum name length as we go, and then we'll print them out. 10780 * 10781 * Note: We always keep an extra slot available so the array can be 10782 * NULL-terminated. 10783 */ 10784 i = 0; 10785 allocd = 1; 10786 objects = safe_malloc(sizeof (*objects)); 10787 names = safe_malloc(sizeof (*names)); 10788 10789 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 10790 int new_pg = 0; 10791 10792 pgnlen = scf_pg_get_name(pg, NULL, 0); 10793 if (pgnlen < 0) 10794 scfdie(); 10795 10796 pgnbuf = safe_malloc(pgnlen + 1); 10797 10798 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1); 10799 if (szret < 0) 10800 scfdie(); 10801 assert(szret <= pgnlen); 10802 10803 if (pattern == NULL || 10804 fnmatch(pattern, pgnbuf, 0) == 0) { 10805 if (i+1 >= allocd) { 10806 allocd *= 2; 10807 objects = realloc(objects, 10808 sizeof (*objects) * allocd); 10809 names = 10810 realloc(names, sizeof (*names) * allocd); 10811 if (objects == NULL || names == NULL) 10812 uu_die(gettext("Out of memory")); 10813 } 10814 objects[i] = pg; 10815 names[i] = pgnbuf; 10816 ++i; 10817 10818 if (pgnlen > max_len) 10819 max_len = pgnlen; 10820 10821 new_pg = 1; 10822 } 10823 10824 if (only_pgs) { 10825 if (new_pg) { 10826 pg = scf_pg_create(g_hndl); 10827 if (pg == NULL) 10828 scfdie(); 10829 } else 10830 free(pgnbuf); 10831 10832 continue; 10833 } 10834 10835 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 10836 scfdie(); 10837 10838 while ((ret = scf_iter_next_property(piter, prop)) == 1) { 10839 prnlen = scf_property_get_name(prop, prnbuf, 10840 max_scf_name_len + 1); 10841 if (prnlen < 0) 10842 scfdie(); 10843 10844 /* Will prepend the property group name and a slash. */ 10845 prnlen += pgnlen + 1; 10846 10847 ppnbuf = safe_malloc(prnlen + 1); 10848 10849 if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf, 10850 prnbuf) < 0) 10851 uu_die("snprintf"); 10852 10853 if (pattern == NULL || 10854 fnmatch(pattern, ppnbuf, 0) == 0) { 10855 if (i+1 >= allocd) { 10856 allocd *= 2; 10857 objects = realloc(objects, 10858 sizeof (*objects) * allocd); 10859 names = realloc(names, 10860 sizeof (*names) * allocd); 10861 if (objects == NULL || names == NULL) 10862 uu_die(gettext("Out of " 10863 "memory")); 10864 } 10865 10866 objects[i] = prop; 10867 names[i] = ppnbuf; 10868 ++i; 10869 10870 if (prnlen > max_len) 10871 max_len = prnlen; 10872 10873 prop = scf_property_create(g_hndl); 10874 } else { 10875 free(ppnbuf); 10876 } 10877 } 10878 10879 if (new_pg) { 10880 pg = scf_pg_create(g_hndl); 10881 if (pg == NULL) 10882 scfdie(); 10883 } else 10884 free(pgnbuf); 10885 } 10886 if (ret != 0) 10887 scfdie(); 10888 10889 objects[i] = NULL; 10890 10891 scf_pg_destroy(pg); 10892 scf_property_destroy(prop); 10893 10894 for (i = 0; objects[i] != NULL; ++i) { 10895 if (strchr(names[i], '/') == NULL) { 10896 /* property group */ 10897 pg = (scf_propertygroup_t *)objects[i]; 10898 list_pg_info(pg, names[i], max_len); 10899 free(names[i]); 10900 scf_pg_destroy(pg); 10901 } else { 10902 /* property */ 10903 prop = (scf_property_t *)objects[i]; 10904 list_prop_info(prop, names[i], max_len); 10905 free(names[i]); 10906 scf_property_destroy(prop); 10907 } 10908 } 10909 10910 free(names); 10911 free(objects); 10912 } 10913 10914 void 10915 lscf_listpg(const char *pattern) 10916 { 10917 lscf_prep_hndl(); 10918 10919 listprop(pattern, 1); 10920 } 10921 10922 /* 10923 * Property group and property creation, setting, and deletion. setprop (and 10924 * its alias, addprop) can either create a property group of a given type, or 10925 * it can create or set a property to a given type and list of values. 10926 */ 10927 void 10928 lscf_addpg(const char *name, const char *type, const char *flags) 10929 { 10930 scf_propertygroup_t *pg; 10931 int ret; 10932 uint32_t flgs = 0; 10933 const char *cp; 10934 10935 10936 lscf_prep_hndl(); 10937 10938 if (cur_snap != NULL) { 10939 semerr(emsg_cant_modify_snapshots); 10940 return; 10941 } 10942 10943 if (cur_inst == NULL && cur_svc == NULL) { 10944 semerr(emsg_entity_not_selected); 10945 return; 10946 } 10947 10948 if (flags != NULL) { 10949 for (cp = flags; *cp != '\0'; ++cp) { 10950 switch (*cp) { 10951 case 'P': 10952 flgs |= SCF_PG_FLAG_NONPERSISTENT; 10953 break; 10954 10955 case 'p': 10956 flgs &= ~SCF_PG_FLAG_NONPERSISTENT; 10957 break; 10958 10959 default: 10960 semerr(gettext("Invalid property group flag " 10961 "%c."), *cp); 10962 return; 10963 } 10964 } 10965 } 10966 10967 pg = scf_pg_create(g_hndl); 10968 if (pg == NULL) 10969 scfdie(); 10970 10971 if (cur_inst != NULL) 10972 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg); 10973 else 10974 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg); 10975 10976 if (ret != SCF_SUCCESS) { 10977 switch (scf_error()) { 10978 case SCF_ERROR_INVALID_ARGUMENT: 10979 semerr(gettext("Name, type, or flags are invalid.\n")); 10980 break; 10981 10982 case SCF_ERROR_EXISTS: 10983 semerr(gettext("Property group already exists.\n")); 10984 break; 10985 10986 case SCF_ERROR_PERMISSION_DENIED: 10987 semerr(emsg_permission_denied); 10988 break; 10989 10990 case SCF_ERROR_BACKEND_ACCESS: 10991 semerr(gettext("Backend refused access.\n")); 10992 break; 10993 10994 default: 10995 scfdie(); 10996 } 10997 } 10998 10999 scf_pg_destroy(pg); 11000 } 11001 11002 void 11003 lscf_delpg(char *name) 11004 { 11005 lscf_prep_hndl(); 11006 11007 if (cur_snap != NULL) { 11008 semerr(emsg_cant_modify_snapshots); 11009 return; 11010 } 11011 11012 if (cur_inst == NULL && cur_svc == NULL) { 11013 semerr(emsg_entity_not_selected); 11014 return; 11015 } 11016 11017 if (strchr(name, '/') != NULL) { 11018 semerr(emsg_invalid_pg_name, name); 11019 return; 11020 } 11021 11022 lscf_delprop(name); 11023 } 11024 11025 void 11026 lscf_listprop(const char *pattern) 11027 { 11028 lscf_prep_hndl(); 11029 11030 listprop(pattern, 0); 11031 } 11032 11033 int 11034 lscf_setprop(const char *pgname, const char *type, const char *value, 11035 const uu_list_t *values) 11036 { 11037 scf_type_t ty; 11038 scf_propertygroup_t *pg; 11039 scf_property_t *prop; 11040 int ret, result = 0; 11041 scf_transaction_t *tx; 11042 scf_transaction_entry_t *e; 11043 scf_value_t *v; 11044 uu_list_walk_t *walk; 11045 string_list_t *sp; 11046 char *propname; 11047 int req_quotes = 0; 11048 11049 lscf_prep_hndl(); 11050 11051 if ((e = scf_entry_create(g_hndl)) == NULL || 11052 (pg = scf_pg_create(g_hndl)) == NULL || 11053 (prop = scf_property_create(g_hndl)) == NULL || 11054 (tx = scf_transaction_create(g_hndl)) == NULL) 11055 scfdie(); 11056 11057 if (cur_snap != NULL) { 11058 semerr(emsg_cant_modify_snapshots); 11059 goto fail; 11060 } 11061 11062 if (cur_inst == NULL && cur_svc == NULL) { 11063 semerr(emsg_entity_not_selected); 11064 goto fail; 11065 } 11066 11067 propname = strchr(pgname, '/'); 11068 if (propname == NULL) { 11069 semerr(gettext("Property names must contain a `/'.\n")); 11070 goto fail; 11071 } 11072 11073 *propname = '\0'; 11074 ++propname; 11075 11076 if (type != NULL) { 11077 ty = string_to_type(type); 11078 if (ty == SCF_TYPE_INVALID) { 11079 semerr(gettext("Unknown type \"%s\".\n"), type); 11080 goto fail; 11081 } 11082 } 11083 11084 if (cur_inst != NULL) 11085 ret = scf_instance_get_pg(cur_inst, pgname, pg); 11086 else 11087 ret = scf_service_get_pg(cur_svc, pgname, pg); 11088 if (ret != SCF_SUCCESS) { 11089 switch (scf_error()) { 11090 case SCF_ERROR_NOT_FOUND: 11091 semerr(emsg_no_such_pg, pgname); 11092 goto fail; 11093 11094 case SCF_ERROR_INVALID_ARGUMENT: 11095 semerr(emsg_invalid_pg_name, pgname); 11096 goto fail; 11097 11098 default: 11099 scfdie(); 11100 break; 11101 } 11102 } 11103 11104 do { 11105 if (scf_pg_update(pg) == -1) 11106 scfdie(); 11107 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 11108 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11109 scfdie(); 11110 11111 semerr(emsg_permission_denied); 11112 goto fail; 11113 } 11114 11115 ret = scf_pg_get_property(pg, propname, prop); 11116 if (ret == SCF_SUCCESS) { 11117 scf_type_t current_ty; 11118 11119 if (scf_property_type(prop, ¤t_ty) != SCF_SUCCESS) 11120 scfdie(); 11121 11122 if (type == NULL) 11123 ty = current_ty; 11124 if (scf_transaction_property_change_type(tx, e, 11125 propname, ty) == -1) 11126 scfdie(); 11127 11128 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 11129 if (type == NULL) { 11130 semerr( 11131 gettext("Type required for new properties.\n")); 11132 goto fail; 11133 } 11134 if (scf_transaction_property_new(tx, e, propname, 11135 ty) == -1) 11136 scfdie(); 11137 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 11138 semerr(emsg_invalid_prop_name, propname); 11139 goto fail; 11140 } else { 11141 scfdie(); 11142 } 11143 11144 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING) 11145 req_quotes = 1; 11146 11147 if (value != NULL) { 11148 v = string_to_value(value, ty, 0); 11149 11150 if (v == NULL) 11151 goto fail; 11152 11153 ret = scf_entry_add_value(e, v); 11154 assert(ret == SCF_SUCCESS); 11155 } else { 11156 assert(values != NULL); 11157 11158 walk = uu_list_walk_start((uu_list_t *)values, 11159 UU_DEFAULT); 11160 if (walk == NULL) 11161 uu_die(gettext("Could not walk list")); 11162 11163 for (sp = uu_list_walk_next(walk); sp != NULL; 11164 sp = uu_list_walk_next(walk)) { 11165 v = string_to_value(sp->str, ty, req_quotes); 11166 11167 if (v == NULL) { 11168 scf_entry_destroy_children(e); 11169 goto fail; 11170 } 11171 11172 ret = scf_entry_add_value(e, v); 11173 assert(ret == SCF_SUCCESS); 11174 } 11175 uu_list_walk_end(walk); 11176 } 11177 result = scf_transaction_commit(tx); 11178 11179 scf_transaction_reset(tx); 11180 scf_entry_destroy_children(e); 11181 } while (result == 0); 11182 11183 if (result < 0) { 11184 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11185 scfdie(); 11186 11187 semerr(emsg_permission_denied); 11188 goto fail; 11189 } 11190 11191 scf_transaction_destroy(tx); 11192 scf_entry_destroy(e); 11193 scf_pg_destroy(pg); 11194 scf_property_destroy(prop); 11195 11196 return (0); 11197 11198 fail: 11199 scf_transaction_destroy(tx); 11200 scf_entry_destroy(e); 11201 scf_pg_destroy(pg); 11202 scf_property_destroy(prop); 11203 11204 return (-1); 11205 } 11206 11207 void 11208 lscf_delprop(char *pgn) 11209 { 11210 char *slash, *pn; 11211 scf_propertygroup_t *pg; 11212 scf_transaction_t *tx; 11213 scf_transaction_entry_t *e; 11214 int ret; 11215 11216 11217 lscf_prep_hndl(); 11218 11219 if (cur_snap != NULL) { 11220 semerr(emsg_cant_modify_snapshots); 11221 return; 11222 } 11223 11224 if (cur_inst == NULL && cur_svc == NULL) { 11225 semerr(emsg_entity_not_selected); 11226 return; 11227 } 11228 11229 pg = scf_pg_create(g_hndl); 11230 if (pg == NULL) 11231 scfdie(); 11232 11233 slash = strchr(pgn, '/'); 11234 if (slash == NULL) { 11235 pn = NULL; 11236 } else { 11237 *slash = '\0'; 11238 pn = slash + 1; 11239 } 11240 11241 if (cur_inst != NULL) 11242 ret = scf_instance_get_pg(cur_inst, pgn, pg); 11243 else 11244 ret = scf_service_get_pg(cur_svc, pgn, pg); 11245 if (ret != SCF_SUCCESS) { 11246 switch (scf_error()) { 11247 case SCF_ERROR_NOT_FOUND: 11248 semerr(emsg_no_such_pg, pgn); 11249 break; 11250 11251 case SCF_ERROR_INVALID_ARGUMENT: 11252 semerr(emsg_invalid_pg_name, pgn); 11253 break; 11254 11255 default: 11256 scfdie(); 11257 } 11258 11259 scf_pg_destroy(pg); 11260 11261 return; 11262 } 11263 11264 if (pn == NULL) { 11265 /* Try to delete the property group. */ 11266 if (scf_pg_delete(pg) != SCF_SUCCESS) { 11267 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11268 scfdie(); 11269 11270 semerr(emsg_permission_denied); 11271 } 11272 11273 scf_pg_destroy(pg); 11274 return; 11275 } 11276 11277 e = scf_entry_create(g_hndl); 11278 tx = scf_transaction_create(g_hndl); 11279 11280 do { 11281 if (scf_pg_update(pg) == -1) 11282 scfdie(); 11283 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 11284 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11285 scfdie(); 11286 11287 semerr(emsg_permission_denied); 11288 break; 11289 } 11290 11291 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) { 11292 if (scf_error() == SCF_ERROR_NOT_FOUND) { 11293 semerr(gettext("No such property %s/%s.\n"), 11294 pgn, pn); 11295 break; 11296 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 11297 semerr(emsg_invalid_prop_name, pn); 11298 break; 11299 } else { 11300 scfdie(); 11301 } 11302 } 11303 11304 ret = scf_transaction_commit(tx); 11305 11306 if (ret == 0) 11307 scf_transaction_reset(tx); 11308 } while (ret == 0); 11309 11310 if (ret < 0) { 11311 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11312 scfdie(); 11313 11314 semerr(emsg_permission_denied); 11315 } 11316 11317 scf_transaction_destroy(tx); 11318 scf_entry_destroy(e); 11319 scf_pg_destroy(pg); 11320 } 11321 11322 /* 11323 * Property editing. 11324 */ 11325 11326 static int 11327 write_edit_script(FILE *strm) 11328 { 11329 char *fmribuf; 11330 ssize_t fmrilen; 11331 11332 scf_propertygroup_t *pg; 11333 scf_property_t *prop; 11334 scf_value_t *val; 11335 scf_type_t ty; 11336 int ret, result = 0; 11337 scf_iter_t *iter, *piter, *viter; 11338 char *buf, *tybuf, *pname; 11339 const char *emsg_write_error; 11340 11341 11342 emsg_write_error = gettext("Error writing temoprary file: %s.\n"); 11343 11344 11345 /* select fmri */ 11346 if (cur_inst != NULL) { 11347 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0); 11348 if (fmrilen < 0) 11349 scfdie(); 11350 fmribuf = safe_malloc(fmrilen + 1); 11351 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0) 11352 scfdie(); 11353 } else { 11354 assert(cur_svc != NULL); 11355 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0); 11356 if (fmrilen < 0) 11357 scfdie(); 11358 fmribuf = safe_malloc(fmrilen + 1); 11359 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0) 11360 scfdie(); 11361 } 11362 11363 if (fprintf(strm, "select %s\n\n", fmribuf) < 0) { 11364 warn(emsg_write_error, strerror(errno)); 11365 free(fmribuf); 11366 return (-1); 11367 } 11368 11369 free(fmribuf); 11370 11371 11372 if ((pg = scf_pg_create(g_hndl)) == NULL || 11373 (prop = scf_property_create(g_hndl)) == NULL || 11374 (val = scf_value_create(g_hndl)) == NULL || 11375 (iter = scf_iter_create(g_hndl)) == NULL || 11376 (piter = scf_iter_create(g_hndl)) == NULL || 11377 (viter = scf_iter_create(g_hndl)) == NULL) 11378 scfdie(); 11379 11380 buf = safe_malloc(max_scf_name_len + 1); 11381 tybuf = safe_malloc(max_scf_pg_type_len + 1); 11382 pname = safe_malloc(max_scf_name_len + 1); 11383 11384 if (cur_inst != NULL) 11385 ret = scf_iter_instance_pgs(iter, cur_inst); 11386 else 11387 ret = scf_iter_service_pgs(iter, cur_svc); 11388 if (ret != SCF_SUCCESS) 11389 scfdie(); 11390 11391 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 11392 int ret2; 11393 11394 /* 11395 * # delprop pg 11396 * # addpg pg type 11397 */ 11398 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0) 11399 scfdie(); 11400 11401 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0) 11402 scfdie(); 11403 11404 if (fprintf(strm, "# Property group \"%s\"\n" 11405 "# delprop %s\n" 11406 "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) { 11407 warn(emsg_write_error, strerror(errno)); 11408 result = -1; 11409 goto out; 11410 } 11411 11412 /* # setprop pg/prop = (values) */ 11413 11414 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 11415 scfdie(); 11416 11417 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) { 11418 int first = 1; 11419 int ret3; 11420 int multiple; 11421 int is_str; 11422 scf_type_t bty; 11423 11424 if (scf_property_get_name(prop, pname, 11425 max_scf_name_len + 1) < 0) 11426 scfdie(); 11427 11428 if (scf_property_type(prop, &ty) != 0) 11429 scfdie(); 11430 11431 multiple = prop_has_multiple_values(prop, val); 11432 11433 if (fprintf(strm, "# setprop %s/%s = %s: %s", buf, 11434 pname, scf_type_to_string(ty), multiple ? "(" : "") 11435 < 0) { 11436 warn(emsg_write_error, strerror(errno)); 11437 result = -1; 11438 goto out; 11439 } 11440 11441 (void) scf_type_base_type(ty, &bty); 11442 is_str = (bty == SCF_TYPE_ASTRING); 11443 11444 if (scf_iter_property_values(viter, prop) != 11445 SCF_SUCCESS) 11446 scfdie(); 11447 11448 while ((ret3 = scf_iter_next_value(viter, val)) == 1) { 11449 char *buf; 11450 ssize_t buflen; 11451 11452 buflen = scf_value_get_as_string(val, NULL, 0); 11453 if (buflen < 0) 11454 scfdie(); 11455 11456 buf = safe_malloc(buflen + 1); 11457 11458 if (scf_value_get_as_string(val, buf, 11459 buflen + 1) < 0) 11460 scfdie(); 11461 11462 if (first) 11463 first = 0; 11464 else { 11465 if (putc(' ', strm) != ' ') { 11466 warn(emsg_write_error, 11467 strerror(errno)); 11468 result = -1; 11469 goto out; 11470 } 11471 } 11472 11473 if ((is_str && multiple) || 11474 strpbrk(buf, CHARS_TO_QUOTE) != NULL) { 11475 (void) putc('"', strm); 11476 (void) quote_and_print(buf, strm, 1); 11477 (void) putc('"', strm); 11478 11479 if (ferror(strm)) { 11480 warn(emsg_write_error, 11481 strerror(errno)); 11482 result = -1; 11483 goto out; 11484 } 11485 } else { 11486 if (fprintf(strm, "%s", buf) < 0) { 11487 warn(emsg_write_error, 11488 strerror(errno)); 11489 result = -1; 11490 goto out; 11491 } 11492 } 11493 11494 free(buf); 11495 } 11496 if (ret3 < 0 && 11497 scf_error() != SCF_ERROR_PERMISSION_DENIED) 11498 scfdie(); 11499 11500 /* Write closing paren if mult-value property */ 11501 if ((multiple && putc(')', strm) == EOF) || 11502 11503 /* Write final newline */ 11504 fputc('\n', strm) == EOF) { 11505 warn(emsg_write_error, strerror(errno)); 11506 result = -1; 11507 goto out; 11508 } 11509 } 11510 if (ret2 < 0) 11511 scfdie(); 11512 11513 if (fputc('\n', strm) == EOF) { 11514 warn(emsg_write_error, strerror(errno)); 11515 result = -1; 11516 goto out; 11517 } 11518 } 11519 if (ret < 0) 11520 scfdie(); 11521 11522 out: 11523 free(pname); 11524 free(tybuf); 11525 free(buf); 11526 scf_iter_destroy(viter); 11527 scf_iter_destroy(piter); 11528 scf_iter_destroy(iter); 11529 scf_value_destroy(val); 11530 scf_property_destroy(prop); 11531 scf_pg_destroy(pg); 11532 11533 if (result == 0) { 11534 if (fflush(strm) != 0) { 11535 warn(emsg_write_error, strerror(errno)); 11536 return (-1); 11537 } 11538 } 11539 11540 return (result); 11541 } 11542 11543 int 11544 lscf_editprop() 11545 { 11546 char *buf, *editor; 11547 size_t bufsz; 11548 int tmpfd; 11549 char tempname[] = TEMP_FILE_PATTERN; 11550 11551 lscf_prep_hndl(); 11552 11553 if (cur_snap != NULL) { 11554 semerr(emsg_cant_modify_snapshots); 11555 return (-1); 11556 } 11557 11558 if (cur_svc == NULL && cur_inst == NULL) { 11559 semerr(emsg_entity_not_selected); 11560 return (-1); 11561 } 11562 11563 tmpfd = mkstemp(tempname); 11564 if (tmpfd == -1) { 11565 semerr(gettext("Could not create temporary file.\n")); 11566 return (-1); 11567 } 11568 11569 (void) strcpy(tempfilename, tempname); 11570 11571 tempfile = fdopen(tmpfd, "r+"); 11572 if (tempfile == NULL) { 11573 warn(gettext("Could not create temporary file.\n")); 11574 if (close(tmpfd) == -1) 11575 warn(gettext("Could not close temporary file: %s.\n"), 11576 strerror(errno)); 11577 11578 remove_tempfile(); 11579 11580 return (-1); 11581 } 11582 11583 if (write_edit_script(tempfile) == -1) { 11584 remove_tempfile(); 11585 return (-1); 11586 } 11587 11588 editor = getenv("EDITOR"); 11589 if (editor == NULL) 11590 editor = "vi"; 11591 11592 bufsz = strlen(editor) + 1 + strlen(tempname) + 1; 11593 buf = safe_malloc(bufsz); 11594 11595 if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0) 11596 uu_die(gettext("Error creating editor command")); 11597 11598 if (system(buf) == -1) { 11599 semerr(gettext("Could not launch editor %s: %s\n"), editor, 11600 strerror(errno)); 11601 free(buf); 11602 remove_tempfile(); 11603 return (-1); 11604 } 11605 11606 free(buf); 11607 11608 (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE); 11609 11610 remove_tempfile(); 11611 11612 return (0); 11613 } 11614 11615 static void 11616 add_string(uu_list_t *strlist, const char *str) 11617 { 11618 string_list_t *elem; 11619 elem = safe_malloc(sizeof (*elem)); 11620 uu_list_node_init(elem, &elem->node, string_pool); 11621 elem->str = safe_strdup(str); 11622 if (uu_list_append(strlist, elem) != 0) 11623 uu_die(gettext("libuutil error: %s\n"), 11624 uu_strerror(uu_error())); 11625 } 11626 11627 /* 11628 * Get all property values that don't match the given glob pattern, 11629 * if a pattern is specified. 11630 */ 11631 static void 11632 get_prop_values(scf_property_t *prop, uu_list_t *values, 11633 const char *pattern) 11634 { 11635 scf_iter_t *iter; 11636 scf_value_t *val; 11637 int ret; 11638 11639 if ((iter = scf_iter_create(g_hndl)) == NULL || 11640 (val = scf_value_create(g_hndl)) == NULL) 11641 scfdie(); 11642 11643 if (scf_iter_property_values(iter, prop) != 0) 11644 scfdie(); 11645 11646 while ((ret = scf_iter_next_value(iter, val)) == 1) { 11647 char *buf; 11648 ssize_t vlen, szret; 11649 11650 vlen = scf_value_get_as_string(val, NULL, 0); 11651 if (vlen < 0) 11652 scfdie(); 11653 11654 buf = safe_malloc(vlen + 1); 11655 11656 szret = scf_value_get_as_string(val, buf, vlen + 1); 11657 if (szret < 0) 11658 scfdie(); 11659 assert(szret <= vlen); 11660 11661 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0) 11662 add_string(values, buf); 11663 11664 free(buf); 11665 } 11666 11667 if (ret == -1) 11668 scfdie(); 11669 11670 scf_value_destroy(val); 11671 scf_iter_destroy(iter); 11672 } 11673 11674 static int 11675 lscf_setpropvalue(const char *pgname, const char *type, 11676 const char *arg, int isadd, int isnotfoundok) 11677 { 11678 scf_type_t ty; 11679 scf_propertygroup_t *pg; 11680 scf_property_t *prop; 11681 int ret, result = 0; 11682 scf_transaction_t *tx; 11683 scf_transaction_entry_t *e; 11684 scf_value_t *v; 11685 string_list_t *sp; 11686 char *propname; 11687 uu_list_t *values; 11688 uu_list_walk_t *walk; 11689 void *cookie = NULL; 11690 char *pattern = NULL; 11691 11692 lscf_prep_hndl(); 11693 11694 if ((values = uu_list_create(string_pool, NULL, 0)) == NULL) 11695 uu_die(gettext("Could not create property list: %s\n"), 11696 uu_strerror(uu_error())); 11697 11698 if (!isadd) 11699 pattern = safe_strdup(arg); 11700 11701 if ((e = scf_entry_create(g_hndl)) == NULL || 11702 (pg = scf_pg_create(g_hndl)) == NULL || 11703 (prop = scf_property_create(g_hndl)) == NULL || 11704 (tx = scf_transaction_create(g_hndl)) == NULL) 11705 scfdie(); 11706 11707 if (cur_snap != NULL) { 11708 semerr(emsg_cant_modify_snapshots); 11709 goto fail; 11710 } 11711 11712 if (cur_inst == NULL && cur_svc == NULL) { 11713 semerr(emsg_entity_not_selected); 11714 goto fail; 11715 } 11716 11717 propname = strchr(pgname, '/'); 11718 if (propname == NULL) { 11719 semerr(gettext("Property names must contain a `/'.\n")); 11720 goto fail; 11721 } 11722 11723 *propname = '\0'; 11724 ++propname; 11725 11726 if (type != NULL) { 11727 ty = string_to_type(type); 11728 if (ty == SCF_TYPE_INVALID) { 11729 semerr(gettext("Unknown type \"%s\".\n"), type); 11730 goto fail; 11731 } 11732 } 11733 11734 if (cur_inst != NULL) 11735 ret = scf_instance_get_pg(cur_inst, pgname, pg); 11736 else 11737 ret = scf_service_get_pg(cur_svc, pgname, pg); 11738 if (ret != 0) { 11739 switch (scf_error()) { 11740 case SCF_ERROR_NOT_FOUND: 11741 if (isnotfoundok) { 11742 result = 0; 11743 } else { 11744 semerr(emsg_no_such_pg, pgname); 11745 result = -1; 11746 } 11747 goto out; 11748 11749 case SCF_ERROR_INVALID_ARGUMENT: 11750 semerr(emsg_invalid_pg_name, pgname); 11751 goto fail; 11752 11753 default: 11754 scfdie(); 11755 } 11756 } 11757 11758 do { 11759 if (scf_pg_update(pg) == -1) 11760 scfdie(); 11761 if (scf_transaction_start(tx, pg) != 0) { 11762 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11763 scfdie(); 11764 11765 semerr(emsg_permission_denied); 11766 goto fail; 11767 } 11768 11769 ret = scf_pg_get_property(pg, propname, prop); 11770 if (ret == 0) { 11771 scf_type_t ptype; 11772 char *pat = pattern; 11773 11774 if (scf_property_type(prop, &ptype) != 0) 11775 scfdie(); 11776 11777 if (isadd) { 11778 if (type != NULL && ptype != ty) { 11779 semerr(gettext("Property \"%s\" is not " 11780 "of type \"%s\".\n"), propname, 11781 type); 11782 goto fail; 11783 } 11784 11785 pat = NULL; 11786 } else { 11787 size_t len = strlen(pat); 11788 if (len > 0 && pat[len - 1] == '\"') 11789 pat[len - 1] = '\0'; 11790 if (len > 0 && pat[0] == '\"') 11791 pat++; 11792 } 11793 11794 ty = ptype; 11795 11796 get_prop_values(prop, values, pat); 11797 11798 if (isadd) 11799 add_string(values, arg); 11800 11801 if (scf_transaction_property_change(tx, e, 11802 propname, ty) == -1) 11803 scfdie(); 11804 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 11805 if (isadd) { 11806 if (type == NULL) { 11807 semerr(gettext("Type required " 11808 "for new properties.\n")); 11809 goto fail; 11810 } 11811 11812 add_string(values, arg); 11813 11814 if (scf_transaction_property_new(tx, e, 11815 propname, ty) == -1) 11816 scfdie(); 11817 } else if (isnotfoundok) { 11818 result = 0; 11819 goto out; 11820 } else { 11821 semerr(gettext("No such property %s/%s.\n"), 11822 pgname, propname); 11823 result = -1; 11824 goto out; 11825 } 11826 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 11827 semerr(emsg_invalid_prop_name, propname); 11828 goto fail; 11829 } else { 11830 scfdie(); 11831 } 11832 11833 walk = uu_list_walk_start(values, UU_DEFAULT); 11834 if (walk == NULL) 11835 uu_die(gettext("Could not walk property list.\n")); 11836 11837 for (sp = uu_list_walk_next(walk); sp != NULL; 11838 sp = uu_list_walk_next(walk)) { 11839 v = string_to_value(sp->str, ty, 0); 11840 11841 if (v == NULL) { 11842 scf_entry_destroy_children(e); 11843 goto fail; 11844 } 11845 ret = scf_entry_add_value(e, v); 11846 assert(ret == 0); 11847 } 11848 uu_list_walk_end(walk); 11849 11850 result = scf_transaction_commit(tx); 11851 11852 scf_transaction_reset(tx); 11853 scf_entry_destroy_children(e); 11854 } while (result == 0); 11855 11856 if (result < 0) { 11857 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11858 scfdie(); 11859 11860 semerr(emsg_permission_denied); 11861 goto fail; 11862 } 11863 11864 result = 0; 11865 11866 out: 11867 scf_transaction_destroy(tx); 11868 scf_entry_destroy(e); 11869 scf_pg_destroy(pg); 11870 scf_property_destroy(prop); 11871 free(pattern); 11872 11873 while ((sp = uu_list_teardown(values, &cookie)) != NULL) { 11874 free(sp->str); 11875 free(sp); 11876 } 11877 11878 uu_list_destroy(values); 11879 11880 return (result); 11881 11882 fail: 11883 result = -1; 11884 goto out; 11885 } 11886 11887 int 11888 lscf_addpropvalue(const char *pgname, const char *type, const char *value) 11889 { 11890 return (lscf_setpropvalue(pgname, type, value, 1, 0)); 11891 } 11892 11893 int 11894 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok) 11895 { 11896 return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok)); 11897 } 11898 11899 /* 11900 * Look for a standard start method, first in the instance (if any), 11901 * then the service. 11902 */ 11903 static const char * 11904 start_method_name(int *in_instance) 11905 { 11906 scf_propertygroup_t *pg; 11907 char **p; 11908 int ret; 11909 scf_instance_t *inst = cur_inst; 11910 11911 if ((pg = scf_pg_create(g_hndl)) == NULL) 11912 scfdie(); 11913 11914 again: 11915 for (p = start_method_names; *p != NULL; p++) { 11916 if (inst != NULL) 11917 ret = scf_instance_get_pg(inst, *p, pg); 11918 else 11919 ret = scf_service_get_pg(cur_svc, *p, pg); 11920 11921 if (ret == 0) { 11922 size_t bufsz = strlen(SCF_GROUP_METHOD) + 1; 11923 char *buf = safe_malloc(bufsz); 11924 11925 if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) { 11926 free(buf); 11927 continue; 11928 } 11929 if (strcmp(buf, SCF_GROUP_METHOD) != 0) { 11930 free(buf); 11931 continue; 11932 } 11933 11934 free(buf); 11935 *in_instance = (inst != NULL); 11936 scf_pg_destroy(pg); 11937 return (*p); 11938 } 11939 11940 if (scf_error() == SCF_ERROR_NOT_FOUND) 11941 continue; 11942 11943 scfdie(); 11944 } 11945 11946 if (inst != NULL) { 11947 inst = NULL; 11948 goto again; 11949 } 11950 11951 scf_pg_destroy(pg); 11952 return (NULL); 11953 } 11954 11955 static int 11956 addpg(const char *name, const char *type) 11957 { 11958 scf_propertygroup_t *pg; 11959 int ret; 11960 11961 pg = scf_pg_create(g_hndl); 11962 if (pg == NULL) 11963 scfdie(); 11964 11965 if (cur_inst != NULL) 11966 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg); 11967 else 11968 ret = scf_service_add_pg(cur_svc, name, type, 0, pg); 11969 11970 if (ret != 0) { 11971 switch (scf_error()) { 11972 case SCF_ERROR_EXISTS: 11973 ret = 0; 11974 break; 11975 11976 case SCF_ERROR_PERMISSION_DENIED: 11977 semerr(emsg_permission_denied); 11978 break; 11979 11980 default: 11981 scfdie(); 11982 } 11983 } 11984 11985 scf_pg_destroy(pg); 11986 return (ret); 11987 } 11988 11989 int 11990 lscf_setenv(uu_list_t *args, int isunset) 11991 { 11992 int ret = 0; 11993 size_t i; 11994 int argc; 11995 char **argv = NULL; 11996 string_list_t *slp; 11997 char *pattern; 11998 char *prop; 11999 int do_service = 0; 12000 int do_instance = 0; 12001 const char *method = NULL; 12002 const char *name = NULL; 12003 const char *value = NULL; 12004 scf_instance_t *saved_cur_inst = cur_inst; 12005 12006 lscf_prep_hndl(); 12007 12008 argc = uu_list_numnodes(args); 12009 if (argc < 1) 12010 goto usage; 12011 12012 argv = calloc(argc + 1, sizeof (char *)); 12013 if (argv == NULL) 12014 uu_die(gettext("Out of memory.\n")); 12015 12016 for (slp = uu_list_first(args), i = 0; 12017 slp != NULL; 12018 slp = uu_list_next(args, slp), ++i) 12019 argv[i] = slp->str; 12020 12021 argv[i] = NULL; 12022 12023 opterr = 0; 12024 optind = 0; 12025 for (;;) { 12026 ret = getopt(argc, argv, "sim:"); 12027 if (ret == -1) 12028 break; 12029 12030 switch (ret) { 12031 case 's': 12032 do_service = 1; 12033 cur_inst = NULL; 12034 break; 12035 12036 case 'i': 12037 do_instance = 1; 12038 break; 12039 12040 case 'm': 12041 method = optarg; 12042 break; 12043 12044 case '?': 12045 goto usage; 12046 12047 default: 12048 bad_error("getopt", ret); 12049 } 12050 } 12051 12052 argc -= optind; 12053 if ((do_service && do_instance) || 12054 (isunset && argc != 1) || 12055 (!isunset && argc != 2)) 12056 goto usage; 12057 12058 name = argv[optind]; 12059 if (!isunset) 12060 value = argv[optind + 1]; 12061 12062 if (cur_snap != NULL) { 12063 semerr(emsg_cant_modify_snapshots); 12064 ret = -1; 12065 goto out; 12066 } 12067 12068 if (cur_inst == NULL && cur_svc == NULL) { 12069 semerr(emsg_entity_not_selected); 12070 ret = -1; 12071 goto out; 12072 } 12073 12074 if (do_instance && cur_inst == NULL) { 12075 semerr(gettext("No instance is selected.\n")); 12076 ret = -1; 12077 goto out; 12078 } 12079 12080 if (do_service && cur_svc == NULL) { 12081 semerr(gettext("No service is selected.\n")); 12082 ret = -1; 12083 goto out; 12084 } 12085 12086 if (method == NULL) { 12087 if (do_instance || do_service) { 12088 method = "method_context"; 12089 if (!isunset) { 12090 ret = addpg("method_context", 12091 SCF_GROUP_FRAMEWORK); 12092 if (ret != 0) 12093 goto out; 12094 } 12095 } else { 12096 int in_instance; 12097 method = start_method_name(&in_instance); 12098 if (method == NULL) { 12099 semerr(gettext( 12100 "Couldn't find start method; please " 12101 "specify a method with '-m'.\n")); 12102 ret = -1; 12103 goto out; 12104 } 12105 if (!in_instance) 12106 cur_inst = NULL; 12107 } 12108 } else { 12109 scf_propertygroup_t *pg; 12110 size_t bufsz; 12111 char *buf; 12112 int ret; 12113 12114 if ((pg = scf_pg_create(g_hndl)) == NULL) 12115 scfdie(); 12116 12117 if (cur_inst != NULL) 12118 ret = scf_instance_get_pg(cur_inst, method, pg); 12119 else 12120 ret = scf_service_get_pg(cur_svc, method, pg); 12121 12122 if (ret != 0) { 12123 scf_pg_destroy(pg); 12124 switch (scf_error()) { 12125 case SCF_ERROR_NOT_FOUND: 12126 semerr(gettext("Couldn't find the method " 12127 "\"%s\".\n"), method); 12128 goto out; 12129 12130 case SCF_ERROR_INVALID_ARGUMENT: 12131 semerr(gettext("Invalid method name \"%s\".\n"), 12132 method); 12133 goto out; 12134 12135 default: 12136 scfdie(); 12137 } 12138 } 12139 12140 bufsz = strlen(SCF_GROUP_METHOD) + 1; 12141 buf = safe_malloc(bufsz); 12142 12143 if (scf_pg_get_type(pg, buf, bufsz) < 0 || 12144 strcmp(buf, SCF_GROUP_METHOD) != 0) { 12145 semerr(gettext("Property group \"%s\" is not of type " 12146 "\"method\".\n"), method); 12147 ret = -1; 12148 free(buf); 12149 scf_pg_destroy(pg); 12150 goto out; 12151 } 12152 12153 free(buf); 12154 scf_pg_destroy(pg); 12155 } 12156 12157 prop = uu_msprintf("%s/environment", method); 12158 pattern = uu_msprintf("%s=*", name); 12159 12160 if (prop == NULL || pattern == NULL) 12161 uu_die(gettext("Out of memory.\n")); 12162 12163 ret = lscf_delpropvalue(prop, pattern, !isunset); 12164 12165 if (ret == 0 && !isunset) { 12166 uu_free(pattern); 12167 uu_free(prop); 12168 prop = uu_msprintf("%s/environment", method); 12169 pattern = uu_msprintf("%s=%s", name, value); 12170 if (prop == NULL || pattern == NULL) 12171 uu_die(gettext("Out of memory.\n")); 12172 ret = lscf_addpropvalue(prop, "astring:", pattern); 12173 } 12174 uu_free(pattern); 12175 uu_free(prop); 12176 12177 out: 12178 cur_inst = saved_cur_inst; 12179 12180 free(argv); 12181 return (ret); 12182 usage: 12183 ret = -2; 12184 goto out; 12185 } 12186 12187 /* 12188 * Snapshot commands 12189 */ 12190 12191 void 12192 lscf_listsnap() 12193 { 12194 scf_snapshot_t *snap; 12195 scf_iter_t *iter; 12196 char *nb; 12197 int r; 12198 12199 lscf_prep_hndl(); 12200 12201 if (cur_inst == NULL) { 12202 semerr(gettext("Instance not selected.\n")); 12203 return; 12204 } 12205 12206 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 12207 (iter = scf_iter_create(g_hndl)) == NULL) 12208 scfdie(); 12209 12210 if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS) 12211 scfdie(); 12212 12213 nb = safe_malloc(max_scf_name_len + 1); 12214 12215 while ((r = scf_iter_next_snapshot(iter, snap)) == 1) { 12216 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0) 12217 scfdie(); 12218 12219 (void) puts(nb); 12220 } 12221 if (r < 0) 12222 scfdie(); 12223 12224 free(nb); 12225 scf_iter_destroy(iter); 12226 scf_snapshot_destroy(snap); 12227 } 12228 12229 void 12230 lscf_selectsnap(const char *name) 12231 { 12232 scf_snapshot_t *snap; 12233 scf_snaplevel_t *level; 12234 12235 lscf_prep_hndl(); 12236 12237 if (cur_inst == NULL) { 12238 semerr(gettext("Instance not selected.\n")); 12239 return; 12240 } 12241 12242 if (cur_snap != NULL) { 12243 if (name != NULL) { 12244 char *cur_snap_name; 12245 boolean_t nochange; 12246 12247 cur_snap_name = safe_malloc(max_scf_name_len + 1); 12248 12249 if (scf_snapshot_get_name(cur_snap, cur_snap_name, 12250 max_scf_name_len + 1) < 0) 12251 scfdie(); 12252 12253 nochange = strcmp(name, cur_snap_name) == 0; 12254 12255 free(cur_snap_name); 12256 12257 if (nochange) 12258 return; 12259 } 12260 12261 unselect_cursnap(); 12262 } 12263 12264 if (name == NULL) 12265 return; 12266 12267 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 12268 (level = scf_snaplevel_create(g_hndl)) == NULL) 12269 scfdie(); 12270 12271 if (scf_instance_get_snapshot(cur_inst, name, snap) != 12272 SCF_SUCCESS) { 12273 switch (scf_error()) { 12274 case SCF_ERROR_INVALID_ARGUMENT: 12275 semerr(gettext("Invalid name \"%s\".\n"), name); 12276 break; 12277 12278 case SCF_ERROR_NOT_FOUND: 12279 semerr(gettext("No such snapshot \"%s\".\n"), name); 12280 break; 12281 12282 default: 12283 scfdie(); 12284 } 12285 12286 scf_snaplevel_destroy(level); 12287 scf_snapshot_destroy(snap); 12288 return; 12289 } 12290 12291 /* Load the snaplevels into our list. */ 12292 cur_levels = uu_list_create(snaplevel_pool, NULL, 0); 12293 if (cur_levels == NULL) 12294 uu_die(gettext("Could not create list: %s\n"), 12295 uu_strerror(uu_error())); 12296 12297 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 12298 if (scf_error() != SCF_ERROR_NOT_FOUND) 12299 scfdie(); 12300 12301 semerr(gettext("Snapshot has no snaplevels.\n")); 12302 12303 scf_snaplevel_destroy(level); 12304 scf_snapshot_destroy(snap); 12305 return; 12306 } 12307 12308 cur_snap = snap; 12309 12310 for (;;) { 12311 cur_elt = safe_malloc(sizeof (*cur_elt)); 12312 uu_list_node_init(cur_elt, &cur_elt->list_node, 12313 snaplevel_pool); 12314 cur_elt->sl = level; 12315 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0) 12316 uu_die(gettext("libuutil error: %s\n"), 12317 uu_strerror(uu_error())); 12318 12319 level = scf_snaplevel_create(g_hndl); 12320 if (level == NULL) 12321 scfdie(); 12322 12323 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl, 12324 level) != SCF_SUCCESS) { 12325 if (scf_error() != SCF_ERROR_NOT_FOUND) 12326 scfdie(); 12327 12328 scf_snaplevel_destroy(level); 12329 break; 12330 } 12331 } 12332 12333 cur_elt = uu_list_last(cur_levels); 12334 cur_level = cur_elt->sl; 12335 } 12336 12337 /* 12338 * Copies the properties & values in src to dst. Assumes src won't change. 12339 * Returns -1 if permission is denied, -2 if another transaction interrupts, 12340 * and 0 on success. 12341 * 12342 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED 12343 * property, if it is copied and has type boolean. (See comment in 12344 * lscf_revert()). 12345 */ 12346 static int 12347 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst, 12348 uint8_t enabled) 12349 { 12350 scf_transaction_t *tx; 12351 scf_iter_t *iter, *viter; 12352 scf_property_t *prop; 12353 scf_value_t *v; 12354 char *nbuf; 12355 int r; 12356 12357 tx = scf_transaction_create(g_hndl); 12358 if (tx == NULL) 12359 scfdie(); 12360 12361 if (scf_transaction_start(tx, dst) != SCF_SUCCESS) { 12362 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12363 scfdie(); 12364 12365 scf_transaction_destroy(tx); 12366 12367 return (-1); 12368 } 12369 12370 if ((iter = scf_iter_create(g_hndl)) == NULL || 12371 (prop = scf_property_create(g_hndl)) == NULL || 12372 (viter = scf_iter_create(g_hndl)) == NULL) 12373 scfdie(); 12374 12375 nbuf = safe_malloc(max_scf_name_len + 1); 12376 12377 if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS) 12378 scfdie(); 12379 12380 for (;;) { 12381 scf_transaction_entry_t *e; 12382 scf_type_t ty; 12383 12384 r = scf_iter_next_property(iter, prop); 12385 if (r == -1) 12386 scfdie(); 12387 if (r == 0) 12388 break; 12389 12390 e = scf_entry_create(g_hndl); 12391 if (e == NULL) 12392 scfdie(); 12393 12394 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 12395 scfdie(); 12396 12397 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0) 12398 scfdie(); 12399 12400 if (scf_transaction_property_new(tx, e, nbuf, 12401 ty) != SCF_SUCCESS) 12402 scfdie(); 12403 12404 if ((enabled == 0 || enabled == 1) && 12405 strcmp(nbuf, scf_property_enabled) == 0 && 12406 ty == SCF_TYPE_BOOLEAN) { 12407 v = scf_value_create(g_hndl); 12408 if (v == NULL) 12409 scfdie(); 12410 12411 scf_value_set_boolean(v, enabled); 12412 12413 if (scf_entry_add_value(e, v) != 0) 12414 scfdie(); 12415 } else { 12416 if (scf_iter_property_values(viter, prop) != 0) 12417 scfdie(); 12418 12419 for (;;) { 12420 v = scf_value_create(g_hndl); 12421 if (v == NULL) 12422 scfdie(); 12423 12424 r = scf_iter_next_value(viter, v); 12425 if (r == -1) 12426 scfdie(); 12427 if (r == 0) { 12428 scf_value_destroy(v); 12429 break; 12430 } 12431 12432 if (scf_entry_add_value(e, v) != SCF_SUCCESS) 12433 scfdie(); 12434 } 12435 } 12436 } 12437 12438 free(nbuf); 12439 scf_iter_destroy(viter); 12440 scf_property_destroy(prop); 12441 scf_iter_destroy(iter); 12442 12443 r = scf_transaction_commit(tx); 12444 if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 12445 scfdie(); 12446 12447 scf_transaction_destroy_children(tx); 12448 scf_transaction_destroy(tx); 12449 12450 switch (r) { 12451 case 1: return (0); 12452 case 0: return (-2); 12453 case -1: return (-1); 12454 12455 default: 12456 abort(); 12457 } 12458 12459 /* NOTREACHED */ 12460 } 12461 12462 void 12463 lscf_revert(const char *snapname) 12464 { 12465 scf_snapshot_t *snap, *prev; 12466 scf_snaplevel_t *level, *nlevel; 12467 scf_iter_t *iter; 12468 scf_propertygroup_t *pg, *npg; 12469 scf_property_t *prop; 12470 scf_value_t *val; 12471 char *nbuf, *tbuf; 12472 uint8_t enabled; 12473 12474 lscf_prep_hndl(); 12475 12476 if (cur_inst == NULL) { 12477 semerr(gettext("Instance not selected.\n")); 12478 return; 12479 } 12480 12481 if (snapname != NULL) { 12482 snap = scf_snapshot_create(g_hndl); 12483 if (snap == NULL) 12484 scfdie(); 12485 12486 if (scf_instance_get_snapshot(cur_inst, snapname, snap) != 12487 SCF_SUCCESS) { 12488 switch (scf_error()) { 12489 case SCF_ERROR_INVALID_ARGUMENT: 12490 semerr(gettext("Invalid snapshot name " 12491 "\"%s\".\n"), snapname); 12492 break; 12493 12494 case SCF_ERROR_NOT_FOUND: 12495 semerr(gettext("No such snapshot.\n")); 12496 break; 12497 12498 default: 12499 scfdie(); 12500 } 12501 12502 scf_snapshot_destroy(snap); 12503 return; 12504 } 12505 } else { 12506 if (cur_snap != NULL) { 12507 snap = cur_snap; 12508 } else { 12509 semerr(gettext("No snapshot selected.\n")); 12510 return; 12511 } 12512 } 12513 12514 if ((prev = scf_snapshot_create(g_hndl)) == NULL || 12515 (level = scf_snaplevel_create(g_hndl)) == NULL || 12516 (iter = scf_iter_create(g_hndl)) == NULL || 12517 (pg = scf_pg_create(g_hndl)) == NULL || 12518 (npg = scf_pg_create(g_hndl)) == NULL || 12519 (prop = scf_property_create(g_hndl)) == NULL || 12520 (val = scf_value_create(g_hndl)) == NULL) 12521 scfdie(); 12522 12523 nbuf = safe_malloc(max_scf_name_len + 1); 12524 tbuf = safe_malloc(max_scf_pg_type_len + 1); 12525 12526 /* Take the "previous" snapshot before we blow away the properties. */ 12527 if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) { 12528 if (_scf_snapshot_take_attach(cur_inst, prev) != 0) 12529 scfdie(); 12530 } else { 12531 if (scf_error() != SCF_ERROR_NOT_FOUND) 12532 scfdie(); 12533 12534 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0) 12535 scfdie(); 12536 } 12537 12538 /* Save general/enabled, since we're probably going to replace it. */ 12539 enabled = 2; 12540 if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 && 12541 scf_pg_get_property(pg, scf_property_enabled, prop) == 0 && 12542 scf_property_get_value(prop, val) == 0) 12543 (void) scf_value_get_boolean(val, &enabled); 12544 12545 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 12546 if (scf_error() != SCF_ERROR_NOT_FOUND) 12547 scfdie(); 12548 12549 goto out; 12550 } 12551 12552 for (;;) { 12553 boolean_t isinst; 12554 uint32_t flags; 12555 int r; 12556 12557 /* Clear the properties from the corresponding entity. */ 12558 isinst = snaplevel_is_instance(level); 12559 12560 if (!isinst) 12561 r = scf_iter_service_pgs(iter, cur_svc); 12562 else 12563 r = scf_iter_instance_pgs(iter, cur_inst); 12564 if (r != SCF_SUCCESS) 12565 scfdie(); 12566 12567 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 12568 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 12569 scfdie(); 12570 12571 /* Skip nonpersistent pgs. */ 12572 if (flags & SCF_PG_FLAG_NONPERSISTENT) 12573 continue; 12574 12575 if (scf_pg_delete(pg) != SCF_SUCCESS) { 12576 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12577 scfdie(); 12578 12579 semerr(emsg_permission_denied); 12580 goto out; 12581 } 12582 } 12583 if (r == -1) 12584 scfdie(); 12585 12586 /* Copy the properties to the corresponding entity. */ 12587 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS) 12588 scfdie(); 12589 12590 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 12591 if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0) 12592 scfdie(); 12593 12594 if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) < 12595 0) 12596 scfdie(); 12597 12598 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 12599 scfdie(); 12600 12601 if (!isinst) 12602 r = scf_service_add_pg(cur_svc, nbuf, tbuf, 12603 flags, npg); 12604 else 12605 r = scf_instance_add_pg(cur_inst, nbuf, tbuf, 12606 flags, npg); 12607 if (r != SCF_SUCCESS) { 12608 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12609 scfdie(); 12610 12611 semerr(emsg_permission_denied); 12612 goto out; 12613 } 12614 12615 if ((enabled == 0 || enabled == 1) && 12616 strcmp(nbuf, scf_pg_general) == 0) 12617 r = pg_copy(pg, npg, enabled); 12618 else 12619 r = pg_copy(pg, npg, 2); 12620 12621 switch (r) { 12622 case 0: 12623 break; 12624 12625 case -1: 12626 semerr(emsg_permission_denied); 12627 goto out; 12628 12629 case -2: 12630 semerr(gettext( 12631 "Interrupted by another change.\n")); 12632 goto out; 12633 12634 default: 12635 abort(); 12636 } 12637 } 12638 if (r == -1) 12639 scfdie(); 12640 12641 /* Get next level. */ 12642 nlevel = scf_snaplevel_create(g_hndl); 12643 if (nlevel == NULL) 12644 scfdie(); 12645 12646 if (scf_snaplevel_get_next_snaplevel(level, nlevel) != 12647 SCF_SUCCESS) { 12648 if (scf_error() != SCF_ERROR_NOT_FOUND) 12649 scfdie(); 12650 12651 scf_snaplevel_destroy(nlevel); 12652 break; 12653 } 12654 12655 scf_snaplevel_destroy(level); 12656 level = nlevel; 12657 } 12658 12659 if (snapname == NULL) { 12660 lscf_selectsnap(NULL); 12661 snap = NULL; /* cur_snap has been destroyed */ 12662 } 12663 12664 out: 12665 free(tbuf); 12666 free(nbuf); 12667 scf_value_destroy(val); 12668 scf_property_destroy(prop); 12669 scf_pg_destroy(npg); 12670 scf_pg_destroy(pg); 12671 scf_iter_destroy(iter); 12672 scf_snaplevel_destroy(level); 12673 scf_snapshot_destroy(prev); 12674 if (snap != cur_snap) 12675 scf_snapshot_destroy(snap); 12676 } 12677 12678 void 12679 lscf_refresh(void) 12680 { 12681 ssize_t fmrilen; 12682 size_t bufsz; 12683 char *fmribuf; 12684 int r; 12685 scf_snapshot_t *snap; 12686 12687 lscf_prep_hndl(); 12688 12689 if (cur_inst == NULL) { 12690 semerr(gettext("Instance not selected.\n")); 12691 return; 12692 } 12693 12694 bufsz = max_scf_fmri_len + 1; 12695 fmribuf = safe_malloc(bufsz); 12696 fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz); 12697 if (fmrilen < 0) { 12698 free(fmribuf); 12699 if (scf_error() != SCF_ERROR_DELETED) 12700 scfdie(); 12701 scf_instance_destroy(cur_inst); 12702 cur_inst = NULL; 12703 warn(emsg_deleted); 12704 return; 12705 } 12706 assert(fmrilen < bufsz); 12707 12708 /* 12709 * If the repository is the active one, a refresh of the instance is 12710 * requested. For alternate repositories, the refresh command simply 12711 * takes a new 'running' snapshot, so the refresh method is not run. 12712 */ 12713 if (est->sc_repo_filename == NULL) { 12714 r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL); 12715 12716 switch (r) { 12717 case 0: 12718 break; 12719 12720 case ECONNABORTED: 12721 warn(gettext("Could not refresh %s " 12722 "(repository connection broken).\n"), fmribuf); 12723 break; 12724 12725 case ECANCELED: 12726 warn(emsg_deleted); 12727 break; 12728 12729 case EPERM: 12730 warn(gettext("Could not refresh %s " 12731 "(permission denied).\n"), fmribuf); 12732 break; 12733 12734 case EACCES: 12735 default: 12736 bad_error("refresh_entity", scf_error()); 12737 } 12738 12739 } else { 12740 if ((snap = scf_snapshot_create(g_hndl)) == NULL) 12741 scfdie(); 12742 r = take_snap(cur_inst, snap_running, snap); 12743 scf_snapshot_destroy(snap); 12744 12745 switch (r) { 12746 case 0: 12747 break; 12748 12749 case ECONNABORTED: 12750 warn(gettext("Could not refresh %s " 12751 "(repository connection broken).\n"), fmribuf); 12752 break; 12753 12754 case ECANCELED: 12755 warn(emsg_deleted); 12756 break; 12757 12758 case EPERM: 12759 warn(gettext("Could not refresh %s " 12760 "(permission denied).\n"), fmribuf); 12761 break; 12762 12763 case ENOSPC: 12764 warn(gettext("Could not refresh %s " 12765 "(repository server out of resources).\n"), 12766 fmribuf); 12767 break; 12768 12769 default: 12770 bad_error("take_snap", scf_error()); 12771 } 12772 } 12773 12774 free(fmribuf); 12775 } 12776 12777 #ifndef NATIVE_BUILD 12778 /* ARGSUSED */ 12779 CPL_MATCH_FN(complete_select) 12780 { 12781 const char *arg0, *arg1, *arg1end; 12782 int word_start, err = 0, r; 12783 size_t len; 12784 char *buf; 12785 12786 lscf_prep_hndl(); 12787 12788 arg0 = line + strspn(line, " \t"); 12789 assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0); 12790 12791 arg1 = arg0 + sizeof ("select") - 1; 12792 arg1 += strspn(arg1, " \t"); 12793 word_start = arg1 - line; 12794 12795 arg1end = arg1 + strcspn(arg1, " \t"); 12796 if (arg1end < line + word_end) 12797 return (0); 12798 12799 len = line + word_end - arg1; 12800 12801 buf = safe_malloc(max_scf_name_len + 1); 12802 12803 if (cur_snap != NULL) { 12804 return (0); 12805 } else if (cur_inst != NULL) { 12806 return (0); 12807 } else if (cur_svc != NULL) { 12808 scf_instance_t *inst; 12809 scf_iter_t *iter; 12810 12811 if ((inst = scf_instance_create(g_hndl)) == NULL || 12812 (iter = scf_iter_create(g_hndl)) == NULL) 12813 scfdie(); 12814 12815 if (scf_iter_service_instances(iter, cur_svc) != 0) 12816 scfdie(); 12817 12818 for (;;) { 12819 r = scf_iter_next_instance(iter, inst); 12820 if (r == 0) 12821 break; 12822 if (r != 1) 12823 scfdie(); 12824 12825 if (scf_instance_get_name(inst, buf, 12826 max_scf_name_len + 1) < 0) 12827 scfdie(); 12828 12829 if (strncmp(buf, arg1, len) == 0) { 12830 err = cpl_add_completion(cpl, line, word_start, 12831 word_end, buf + len, "", " "); 12832 if (err != 0) 12833 break; 12834 } 12835 } 12836 12837 scf_iter_destroy(iter); 12838 scf_instance_destroy(inst); 12839 12840 return (err); 12841 } else { 12842 scf_service_t *svc; 12843 scf_iter_t *iter; 12844 12845 assert(cur_scope != NULL); 12846 12847 if ((svc = scf_service_create(g_hndl)) == NULL || 12848 (iter = scf_iter_create(g_hndl)) == NULL) 12849 scfdie(); 12850 12851 if (scf_iter_scope_services(iter, cur_scope) != 0) 12852 scfdie(); 12853 12854 for (;;) { 12855 r = scf_iter_next_service(iter, svc); 12856 if (r == 0) 12857 break; 12858 if (r != 1) 12859 scfdie(); 12860 12861 if (scf_service_get_name(svc, buf, 12862 max_scf_name_len + 1) < 0) 12863 scfdie(); 12864 12865 if (strncmp(buf, arg1, len) == 0) { 12866 err = cpl_add_completion(cpl, line, word_start, 12867 word_end, buf + len, "", " "); 12868 if (err != 0) 12869 break; 12870 } 12871 } 12872 12873 scf_iter_destroy(iter); 12874 scf_service_destroy(svc); 12875 12876 return (err); 12877 } 12878 } 12879 12880 /* ARGSUSED */ 12881 CPL_MATCH_FN(complete_command) 12882 { 12883 uint32_t scope = 0; 12884 12885 if (cur_snap != NULL) 12886 scope = CS_SNAP; 12887 else if (cur_inst != NULL) 12888 scope = CS_INST; 12889 else if (cur_svc != NULL) 12890 scope = CS_SVC; 12891 else 12892 scope = CS_SCOPE; 12893 12894 return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0); 12895 } 12896 #endif /* NATIVE_BUILD */ 12897