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