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