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