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