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(const entity_t *ient, const scf_snaplevel_t *running, 3307 void *ent) 3308 { 3309 scf_propertygroup_t *ud_run_mfsts_pg = NULL; 3310 scf_property_t *ud_run_prop = NULL; 3311 scf_iter_t *ud_prop_iter; 3312 scf_value_t *fname_value; 3313 pgroup_t *mfst_pgroup; 3314 property_t *mfst_prop; 3315 property_t *old_prop; 3316 char *pname = malloc(MAXPATHLEN); 3317 char *fval; 3318 char *old_pname; 3319 char *old_fval; 3320 int mfst_seen; 3321 int r; 3322 3323 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 3324 3325 /* 3326 * This should always be the service base on the code 3327 * path, and the fact that the manifests pg is a service 3328 * level property group only. 3329 */ 3330 ud_run_mfsts_pg = scf_pg_create(g_hndl); 3331 ud_run_prop = scf_property_create(g_hndl); 3332 ud_prop_iter = scf_iter_create(g_hndl); 3333 fname_value = scf_value_create(g_hndl); 3334 3335 /* Fetch the running version of the "manifests" property group */ 3336 if (running != NULL) 3337 r = scf_snaplevel_get_pg(running, SCF_PG_MANIFESTFILES, 3338 ud_run_mfsts_pg); 3339 else 3340 r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES, 3341 ud_run_mfsts_pg); 3342 3343 if (r != 0) { 3344 switch (scf_error()) { 3345 case SCF_ERROR_NOT_FOUND: 3346 break; 3347 3348 case SCF_ERROR_DELETED: 3349 case SCF_ERROR_CONNECTION_BROKEN: 3350 return (scferror2errno(scf_error())); 3351 3352 case SCF_ERROR_NOT_SET: 3353 case SCF_ERROR_INVALID_ARGUMENT: 3354 case SCF_ERROR_HANDLE_MISMATCH: 3355 case SCF_ERROR_NOT_BOUND: 3356 default: 3357 bad_error(running ? "scf_snaplevel_get_pg" : 3358 "entity_get_pg", scf_error()); 3359 } 3360 } 3361 3362 /* Fetch the new manifests property group */ 3363 for (mfst_pgroup = uu_list_first(ient->sc_pgroups); 3364 mfst_pgroup != NULL; 3365 mfst_pgroup = uu_list_next(ient->sc_pgroups, mfst_pgroup)) { 3366 if (strcmp(mfst_pgroup->sc_pgroup_name, 3367 SCF_PG_MANIFESTFILES) == 0) 3368 break; 3369 } 3370 3371 if (scf_iter_pg_properties(ud_prop_iter, ud_run_mfsts_pg) != 3372 SCF_SUCCESS) 3373 return (-1); 3374 3375 while ((r = scf_iter_next_property(ud_prop_iter, ud_run_prop)) == 1) { 3376 mfst_seen = 0; 3377 if (scf_property_get_name(ud_run_prop, pname, MAXPATHLEN) < 0) 3378 continue; 3379 3380 for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props); 3381 mfst_prop != NULL; 3382 mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props, 3383 mfst_prop)) { 3384 if (strcmp(mfst_prop->sc_property_name, pname) == 0) { 3385 mfst_seen = 1; 3386 } 3387 } 3388 3389 /* 3390 * If the manifest is not seen then add it to the new mfst 3391 * property list to get proccessed into the repo. 3392 */ 3393 if (mfst_seen == 0) { 3394 fval = malloc(MAXPATHLEN); 3395 3396 /* 3397 * If we cannot get the value then there is no 3398 * reasont to attempt to attach the value to 3399 * the property group 3400 */ 3401 if (fval != NULL && 3402 prop_get_val(ud_run_prop, fname_value) == 0 && 3403 scf_value_get_astring(fname_value, fval, 3404 MAXPATHLEN) != -1) { 3405 /* 3406 * First check to see if the manifest is there 3407 * if not then there is no need to add it. 3408 */ 3409 if (access(fval, F_OK) == -1) { 3410 free(fval); 3411 continue; 3412 } 3413 old_pname = safe_strdup(pname); 3414 old_fval = safe_strdup(fval); 3415 old_prop = internal_property_create(old_pname, 3416 SCF_TYPE_ASTRING, 1, old_fval); 3417 3418 /* 3419 * Already checked to see if the property exists 3420 * in the group, and it does not. 3421 */ 3422 (void) internal_attach_property(mfst_pgroup, 3423 old_prop); 3424 } 3425 } 3426 } 3427 3428 return (r); 3429 } 3430 3431 /* 3432 * prop is taken to be a property in the "dependents" property group of snpl, 3433 * which is taken to be the snaplevel of a last-import snapshot corresponding 3434 * to ient. If prop is a valid dependents property, upgrade the dependent it 3435 * represents according to the repository & ient. If ud_run_dpts_pg_set is 3436 * true, then ud_run_dpts_pg is taken to be the "dependents" property group 3437 * of the entity ient represents (possibly in the running snapshot). If it 3438 * needs to be changed, an entry will be added to tx, if not NULL. 3439 * 3440 * Returns 3441 * 0 - success 3442 * ECONNABORTED - repository connection broken 3443 * ENOMEM - out of memory 3444 * ENOSPC - configd was out of resources 3445 * ECANCELED - snpl's entity was deleted 3446 * EINVAL - dependent target is invalid (error printed) 3447 * - dependent is invalid (error printed) 3448 * EBADF - snpl is corrupt (error printed) 3449 * - snpl has corrupt pg (error printed) 3450 * - dependency pg in target is corrupt (error printed) 3451 * - running snapshot in dependent is missing snaplevel (error printed) 3452 * EPERM - couldn't delete dependency pg (permission denied) (error printed) 3453 * - couldn't create dependent (permission denied) (error printed) 3454 * - couldn't modify dependent pg (permission denied) (error printed) 3455 * EROFS - couldn't delete dependency pg (repository read-only) 3456 * - couldn't create dependent (repository read-only) 3457 * EACCES - couldn't delete dependency pg (backend access denied) 3458 * - couldn't create dependent (backend access denied) 3459 * EBUSY - ud_run_dpts_pg was deleted (error printed) 3460 * - tx's pg was deleted (error printed) 3461 * - dependent pg was changed or deleted (error printed) 3462 * EEXIST - dependency pg already exists in new target (error printed) 3463 */ 3464 static int 3465 upgrade_dependent(const scf_property_t *prop, const entity_t *ient, 3466 const scf_snaplevel_t *snpl, scf_transaction_t *tx) 3467 { 3468 pgroup_t pgrp; 3469 scf_type_t ty; 3470 pgroup_t *new_dpt_pgroup; 3471 pgroup_t *old_dpt_pgroup = NULL; 3472 pgroup_t *current_pg; 3473 scf_callback_t cbdata; 3474 int tissvc; 3475 void *target_ent; 3476 scf_error_t serr; 3477 int r; 3478 scf_transaction_entry_t *ent; 3479 3480 const char * const cf_inval = gettext("Conflict upgrading %s " 3481 "(dependent \"%s\" has invalid dependents property).\n"); 3482 const char * const cf_missing = gettext("Conflict upgrading %s " 3483 "(dependent \"%s\" is missing).\n"); 3484 const char * const cf_newdpg = gettext("Conflict upgrading %s " 3485 "(dependent \"%s\" has new dependency property group).\n"); 3486 const char * const cf_newtarg = gettext("Conflict upgrading %s " 3487 "(dependent \"%s\" has new target).\n"); 3488 const char * const li_corrupt = 3489 gettext("%s: \"last-import\" snapshot is corrupt.\n"); 3490 const char * const upgrading = 3491 gettext("%s: Upgrading dependent \"%s\".\n"); 3492 const char * const r_no_lvl = gettext("%s: \"running\" snapshot is " 3493 "corrupt (missing snaplevel).\n"); 3494 3495 if (scf_property_type(prop, &ty) != 0) { 3496 switch (scf_error()) { 3497 case SCF_ERROR_DELETED: 3498 case SCF_ERROR_CONNECTION_BROKEN: 3499 return (scferror2errno(scf_error())); 3500 3501 case SCF_ERROR_NOT_BOUND: 3502 case SCF_ERROR_NOT_SET: 3503 default: 3504 bad_error("scf_property_type", scf_error()); 3505 } 3506 } 3507 3508 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 3509 warn(li_corrupt, ient->sc_fmri); 3510 return (EBADF); 3511 } 3512 3513 /* 3514 * prop represents a dependent in the old manifest. It is named after 3515 * the dependent. 3516 */ 3517 if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) { 3518 switch (scf_error()) { 3519 case SCF_ERROR_DELETED: 3520 case SCF_ERROR_CONNECTION_BROKEN: 3521 return (scferror2errno(scf_error())); 3522 3523 case SCF_ERROR_NOT_BOUND: 3524 case SCF_ERROR_NOT_SET: 3525 default: 3526 bad_error("scf_property_get_name", scf_error()); 3527 } 3528 } 3529 3530 /* See if it's in the new manifest. */ 3531 pgrp.sc_pgroup_name = ud_name; 3532 new_dpt_pgroup = 3533 uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT); 3534 3535 /* If it's not, delete it... if it hasn't been customized. */ 3536 if (new_dpt_pgroup == NULL) { 3537 pgroup_t *dpt; 3538 3539 if (!ud_run_dpts_pg_set) 3540 return (0); 3541 3542 if (scf_property_get_value(prop, ud_val) != 0) { 3543 switch (scf_error()) { 3544 case SCF_ERROR_NOT_FOUND: 3545 case SCF_ERROR_CONSTRAINT_VIOLATED: 3546 warn(li_corrupt, ient->sc_fmri); 3547 return (EBADF); 3548 3549 case SCF_ERROR_DELETED: 3550 case SCF_ERROR_CONNECTION_BROKEN: 3551 return (scferror2errno(scf_error())); 3552 3553 case SCF_ERROR_HANDLE_MISMATCH: 3554 case SCF_ERROR_NOT_BOUND: 3555 case SCF_ERROR_NOT_SET: 3556 case SCF_ERROR_PERMISSION_DENIED: 3557 default: 3558 bad_error("scf_property_get_value", 3559 scf_error()); 3560 } 3561 } 3562 3563 if (scf_value_get_as_string(ud_val, ud_oldtarg, 3564 max_scf_value_len + 1) < 0) 3565 bad_error("scf_value_get_as_string", scf_error()); 3566 3567 if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 3568 0) { 3569 switch (scf_error()) { 3570 case SCF_ERROR_NOT_FOUND: 3571 return (0); 3572 3573 case SCF_ERROR_CONNECTION_BROKEN: 3574 return (scferror2errno(scf_error())); 3575 3576 case SCF_ERROR_DELETED: 3577 warn(emsg_pg_deleted, ient->sc_fmri, 3578 "dependents"); 3579 return (EBUSY); 3580 3581 case SCF_ERROR_INVALID_ARGUMENT: 3582 case SCF_ERROR_NOT_BOUND: 3583 case SCF_ERROR_HANDLE_MISMATCH: 3584 case SCF_ERROR_NOT_SET: 3585 default: 3586 bad_error("scf_pg_get_property", scf_error()); 3587 } 3588 } 3589 if (scf_property_get_value(ud_prop, ud_val) != 0) { 3590 switch (scf_error()) { 3591 case SCF_ERROR_NOT_FOUND: 3592 case SCF_ERROR_CONSTRAINT_VIOLATED: 3593 warn(cf_inval, ient->sc_fmri, ud_name); 3594 return (0); 3595 3596 case SCF_ERROR_DELETED: 3597 case SCF_ERROR_CONNECTION_BROKEN: 3598 return (scferror2errno(scf_error())); 3599 3600 case SCF_ERROR_HANDLE_MISMATCH: 3601 case SCF_ERROR_NOT_BOUND: 3602 case SCF_ERROR_NOT_SET: 3603 case SCF_ERROR_PERMISSION_DENIED: 3604 default: 3605 bad_error("scf_property_get_value", 3606 scf_error()); 3607 } 3608 } 3609 3610 ty = scf_value_type(ud_val); 3611 assert(ty != SCF_TYPE_INVALID); 3612 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 3613 warn(cf_inval, ient->sc_fmri, ud_name); 3614 return (0); 3615 } 3616 3617 if (scf_value_get_as_string(ud_val, ud_ctarg, 3618 max_scf_value_len + 1) < 0) 3619 bad_error("scf_value_get_as_string", scf_error()); 3620 3621 r = fmri_equal(ud_ctarg, ud_oldtarg); 3622 switch (r) { 3623 case 1: 3624 break; 3625 3626 case 0: 3627 case -1: /* warn? */ 3628 warn(cf_newtarg, ient->sc_fmri, ud_name); 3629 return (0); 3630 3631 case -2: 3632 warn(li_corrupt, ient->sc_fmri); 3633 return (EBADF); 3634 3635 default: 3636 bad_error("fmri_equal", r); 3637 } 3638 3639 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) { 3640 switch (scf_error()) { 3641 case SCF_ERROR_NOT_FOUND: 3642 warn(li_corrupt, ient->sc_fmri); 3643 return (EBADF); 3644 3645 case SCF_ERROR_DELETED: 3646 case SCF_ERROR_CONNECTION_BROKEN: 3647 return (scferror2errno(scf_error())); 3648 3649 case SCF_ERROR_NOT_BOUND: 3650 case SCF_ERROR_HANDLE_MISMATCH: 3651 case SCF_ERROR_INVALID_ARGUMENT: 3652 case SCF_ERROR_NOT_SET: 3653 default: 3654 bad_error("scf_snaplevel_get_pg", scf_error()); 3655 } 3656 } 3657 3658 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 3659 snap_lastimport); 3660 switch (r) { 3661 case 0: 3662 break; 3663 3664 case ECANCELED: 3665 case ECONNABORTED: 3666 case ENOMEM: 3667 case EBADF: 3668 return (r); 3669 3670 case EACCES: 3671 default: 3672 bad_error("load_pg", r); 3673 } 3674 3675 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 3676 switch (serr) { 3677 case SCF_ERROR_NONE: 3678 break; 3679 3680 case SCF_ERROR_NO_MEMORY: 3681 internal_pgroup_free(old_dpt_pgroup); 3682 return (ENOMEM); 3683 3684 case SCF_ERROR_NOT_FOUND: 3685 internal_pgroup_free(old_dpt_pgroup); 3686 goto delprop; 3687 3688 case SCF_ERROR_CONSTRAINT_VIOLATED: /* caught above */ 3689 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 3690 default: 3691 bad_error("fmri_to_entity", serr); 3692 } 3693 3694 r = entity_get_running_pg(target_ent, tissvc, ud_name, 3695 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl); 3696 switch (r) { 3697 case 0: 3698 break; 3699 3700 case ECONNABORTED: 3701 internal_pgroup_free(old_dpt_pgroup); 3702 return (r); 3703 3704 case ECANCELED: 3705 case ENOENT: 3706 internal_pgroup_free(old_dpt_pgroup); 3707 goto delprop; 3708 3709 case EBADF: 3710 warn(r_no_lvl, ud_ctarg); 3711 internal_pgroup_free(old_dpt_pgroup); 3712 return (r); 3713 3714 case EINVAL: 3715 default: 3716 bad_error("entity_get_running_pg", r); 3717 } 3718 3719 /* load it */ 3720 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 3721 switch (r) { 3722 case 0: 3723 break; 3724 3725 case ECANCELED: 3726 internal_pgroup_free(old_dpt_pgroup); 3727 goto delprop; 3728 3729 case ECONNABORTED: 3730 case ENOMEM: 3731 case EBADF: 3732 internal_pgroup_free(old_dpt_pgroup); 3733 return (r); 3734 3735 case EACCES: 3736 default: 3737 bad_error("load_pg", r); 3738 } 3739 3740 /* compare property groups */ 3741 if (!pg_equal(old_dpt_pgroup, current_pg)) { 3742 warn(cf_newdpg, ient->sc_fmri, ud_name); 3743 internal_pgroup_free(old_dpt_pgroup); 3744 internal_pgroup_free(current_pg); 3745 return (0); 3746 } 3747 3748 internal_pgroup_free(old_dpt_pgroup); 3749 internal_pgroup_free(current_pg); 3750 3751 if (g_verbose) 3752 warn(gettext("%s: Deleting dependent \"%s\".\n"), 3753 ient->sc_fmri, ud_name); 3754 3755 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 3756 switch (scf_error()) { 3757 case SCF_ERROR_NOT_FOUND: 3758 case SCF_ERROR_DELETED: 3759 internal_pgroup_free(old_dpt_pgroup); 3760 goto delprop; 3761 3762 case SCF_ERROR_CONNECTION_BROKEN: 3763 internal_pgroup_free(old_dpt_pgroup); 3764 return (ECONNABORTED); 3765 3766 case SCF_ERROR_NOT_SET: 3767 case SCF_ERROR_INVALID_ARGUMENT: 3768 case SCF_ERROR_HANDLE_MISMATCH: 3769 case SCF_ERROR_NOT_BOUND: 3770 default: 3771 bad_error("entity_get_pg", scf_error()); 3772 } 3773 } 3774 3775 if (scf_pg_delete(ud_pg) != 0) { 3776 switch (scf_error()) { 3777 case SCF_ERROR_DELETED: 3778 break; 3779 3780 case SCF_ERROR_CONNECTION_BROKEN: 3781 case SCF_ERROR_BACKEND_READONLY: 3782 case SCF_ERROR_BACKEND_ACCESS: 3783 return (scferror2errno(scf_error())); 3784 3785 case SCF_ERROR_PERMISSION_DENIED: 3786 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri); 3787 return (scferror2errno(scf_error())); 3788 3789 case SCF_ERROR_NOT_SET: 3790 default: 3791 bad_error("scf_pg_delete", scf_error()); 3792 } 3793 } 3794 3795 /* 3796 * This service was changed, so it must be refreshed. But 3797 * since it's not mentioned in the new manifest, we have to 3798 * record its FMRI here for use later. We record the name 3799 * & the entity (via sc_parent) in case we need to print error 3800 * messages during the refresh. 3801 */ 3802 dpt = internal_pgroup_new(); 3803 if (dpt == NULL) 3804 return (ENOMEM); 3805 dpt->sc_pgroup_name = strdup(ud_name); 3806 dpt->sc_pgroup_fmri = strdup(ud_ctarg); 3807 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL) 3808 return (ENOMEM); 3809 dpt->sc_parent = (entity_t *)ient; 3810 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0) 3811 uu_die(gettext("libuutil error: %s\n"), 3812 uu_strerror(uu_error())); 3813 3814 delprop: 3815 if (tx == NULL) 3816 return (0); 3817 3818 ent = scf_entry_create(g_hndl); 3819 if (ent == NULL) 3820 return (ENOMEM); 3821 3822 if (scf_transaction_property_delete(tx, ent, ud_name) != 0) { 3823 scf_entry_destroy(ent); 3824 switch (scf_error()) { 3825 case SCF_ERROR_DELETED: 3826 warn(emsg_pg_deleted, ient->sc_fmri, 3827 "dependents"); 3828 return (EBUSY); 3829 3830 case SCF_ERROR_CONNECTION_BROKEN: 3831 return (scferror2errno(scf_error())); 3832 3833 case SCF_ERROR_NOT_FOUND: 3834 break; 3835 3836 case SCF_ERROR_HANDLE_MISMATCH: 3837 case SCF_ERROR_NOT_BOUND: 3838 case SCF_ERROR_INVALID_ARGUMENT: 3839 case SCF_ERROR_NOT_SET: 3840 default: 3841 bad_error("scf_transaction_property_delete", 3842 scf_error()); 3843 } 3844 } 3845 3846 return (0); 3847 } 3848 3849 new_dpt_pgroup->sc_pgroup_seen = 1; 3850 3851 /* 3852 * Decide whether the dependent has changed in the manifest. 3853 */ 3854 /* Compare the target. */ 3855 if (scf_property_get_value(prop, ud_val) != 0) { 3856 switch (scf_error()) { 3857 case SCF_ERROR_NOT_FOUND: 3858 case SCF_ERROR_CONSTRAINT_VIOLATED: 3859 warn(li_corrupt, ient->sc_fmri); 3860 return (EBADF); 3861 3862 case SCF_ERROR_DELETED: 3863 case SCF_ERROR_CONNECTION_BROKEN: 3864 return (scferror2errno(scf_error())); 3865 3866 case SCF_ERROR_HANDLE_MISMATCH: 3867 case SCF_ERROR_NOT_BOUND: 3868 case SCF_ERROR_NOT_SET: 3869 case SCF_ERROR_PERMISSION_DENIED: 3870 default: 3871 bad_error("scf_property_get_value", scf_error()); 3872 } 3873 } 3874 3875 if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) < 3876 0) 3877 bad_error("scf_value_get_as_string", scf_error()); 3878 3879 r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri); 3880 switch (r) { 3881 case 0: 3882 break; 3883 3884 case 1: 3885 /* Compare the dependency pgs. */ 3886 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) { 3887 switch (scf_error()) { 3888 case SCF_ERROR_NOT_FOUND: 3889 warn(li_corrupt, ient->sc_fmri); 3890 return (EBADF); 3891 3892 case SCF_ERROR_DELETED: 3893 case SCF_ERROR_CONNECTION_BROKEN: 3894 return (scferror2errno(scf_error())); 3895 3896 case SCF_ERROR_NOT_BOUND: 3897 case SCF_ERROR_HANDLE_MISMATCH: 3898 case SCF_ERROR_INVALID_ARGUMENT: 3899 case SCF_ERROR_NOT_SET: 3900 default: 3901 bad_error("scf_snaplevel_get_pg", scf_error()); 3902 } 3903 } 3904 3905 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 3906 snap_lastimport); 3907 switch (r) { 3908 case 0: 3909 break; 3910 3911 case ECANCELED: 3912 case ECONNABORTED: 3913 case ENOMEM: 3914 case EBADF: 3915 return (r); 3916 3917 case EACCES: 3918 default: 3919 bad_error("load_pg", r); 3920 } 3921 3922 if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) { 3923 /* no change, leave customizations */ 3924 internal_pgroup_free(old_dpt_pgroup); 3925 return (0); 3926 } 3927 break; 3928 3929 case -1: 3930 warn(li_corrupt, ient->sc_fmri); 3931 return (EBADF); 3932 3933 case -2: 3934 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"), 3935 ud_name, new_dpt_pgroup->sc_pgroup_fmri); 3936 return (EINVAL); 3937 3938 default: 3939 bad_error("fmri_equal", r); 3940 } 3941 3942 /* 3943 * The dependent has changed in the manifest. Upgrade the current 3944 * properties if they haven't been customized. 3945 */ 3946 3947 /* 3948 * If new_dpt_pgroup->sc_override, then act as though the property 3949 * group hasn't been customized. 3950 */ 3951 if (new_dpt_pgroup->sc_pgroup_override) 3952 goto nocust; 3953 3954 if (!ud_run_dpts_pg_set) { 3955 warn(cf_missing, ient->sc_fmri, ud_name); 3956 r = 0; 3957 goto out; 3958 } else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) { 3959 switch (scf_error()) { 3960 case SCF_ERROR_NOT_FOUND: 3961 warn(cf_missing, ient->sc_fmri, ud_name); 3962 r = 0; 3963 goto out; 3964 3965 case SCF_ERROR_CONNECTION_BROKEN: 3966 r = scferror2errno(scf_error()); 3967 goto out; 3968 3969 case SCF_ERROR_DELETED: 3970 warn(emsg_pg_deleted, ient->sc_fmri, "dependents"); 3971 r = EBUSY; 3972 goto out; 3973 3974 case SCF_ERROR_INVALID_ARGUMENT: 3975 case SCF_ERROR_NOT_BOUND: 3976 case SCF_ERROR_HANDLE_MISMATCH: 3977 case SCF_ERROR_NOT_SET: 3978 default: 3979 bad_error("scf_pg_get_property", scf_error()); 3980 } 3981 } 3982 3983 if (scf_property_get_value(ud_prop, ud_val) != 0) { 3984 switch (scf_error()) { 3985 case SCF_ERROR_NOT_FOUND: 3986 case SCF_ERROR_CONSTRAINT_VIOLATED: 3987 warn(cf_inval, ient->sc_fmri, ud_name); 3988 r = 0; 3989 goto out; 3990 3991 case SCF_ERROR_DELETED: 3992 case SCF_ERROR_CONNECTION_BROKEN: 3993 r = scferror2errno(scf_error()); 3994 goto out; 3995 3996 case SCF_ERROR_HANDLE_MISMATCH: 3997 case SCF_ERROR_NOT_BOUND: 3998 case SCF_ERROR_NOT_SET: 3999 case SCF_ERROR_PERMISSION_DENIED: 4000 default: 4001 bad_error("scf_property_get_value", scf_error()); 4002 } 4003 } 4004 4005 ty = scf_value_type(ud_val); 4006 assert(ty != SCF_TYPE_INVALID); 4007 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4008 warn(cf_inval, ient->sc_fmri, ud_name); 4009 r = 0; 4010 goto out; 4011 } 4012 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) < 4013 0) 4014 bad_error("scf_value_get_as_string", scf_error()); 4015 4016 r = fmri_equal(ud_ctarg, ud_oldtarg); 4017 if (r == -1) { 4018 warn(cf_inval, ient->sc_fmri, ud_name); 4019 r = 0; 4020 goto out; 4021 } else if (r == -2) { 4022 warn(li_corrupt, ient->sc_fmri); 4023 r = EBADF; 4024 goto out; 4025 } else if (r == 0) { 4026 /* 4027 * Target has been changed. Only abort now if it's been 4028 * changed to something other than what's in the manifest. 4029 */ 4030 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri); 4031 if (r == -1) { 4032 warn(cf_inval, ient->sc_fmri, ud_name); 4033 r = 0; 4034 goto out; 4035 } else if (r == 0) { 4036 warn(cf_newtarg, ient->sc_fmri, ud_name); 4037 r = 0; 4038 goto out; 4039 } else if (r != 1) { 4040 /* invalid sc_pgroup_fmri caught above */ 4041 bad_error("fmri_equal", r); 4042 } 4043 4044 /* 4045 * Fetch the current dependency pg. If it's what the manifest 4046 * says, then no problem. 4047 */ 4048 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4049 switch (serr) { 4050 case SCF_ERROR_NONE: 4051 break; 4052 4053 case SCF_ERROR_NOT_FOUND: 4054 warn(cf_missing, ient->sc_fmri, ud_name); 4055 r = 0; 4056 goto out; 4057 4058 case SCF_ERROR_NO_MEMORY: 4059 r = ENOMEM; 4060 goto out; 4061 4062 case SCF_ERROR_CONSTRAINT_VIOLATED: 4063 case SCF_ERROR_INVALID_ARGUMENT: 4064 default: 4065 bad_error("fmri_to_entity", serr); 4066 } 4067 4068 r = entity_get_running_pg(target_ent, tissvc, ud_name, 4069 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl); 4070 switch (r) { 4071 case 0: 4072 break; 4073 4074 case ECONNABORTED: 4075 goto out; 4076 4077 case ECANCELED: 4078 case ENOENT: 4079 warn(cf_missing, ient->sc_fmri, ud_name); 4080 r = 0; 4081 goto out; 4082 4083 case EBADF: 4084 warn(r_no_lvl, ud_ctarg); 4085 goto out; 4086 4087 case EINVAL: 4088 default: 4089 bad_error("entity_get_running_pg", r); 4090 } 4091 4092 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4093 switch (r) { 4094 case 0: 4095 break; 4096 4097 case ECANCELED: 4098 warn(cf_missing, ient->sc_fmri, ud_name); 4099 r = 0; 4100 goto out; 4101 4102 case ECONNABORTED: 4103 case ENOMEM: 4104 case EBADF: 4105 goto out; 4106 4107 case EACCES: 4108 default: 4109 bad_error("load_pg", r); 4110 } 4111 4112 if (!pg_equal(current_pg, new_dpt_pgroup)) 4113 warn(cf_newdpg, ient->sc_fmri, ud_name); 4114 internal_pgroup_free(current_pg); 4115 r = 0; 4116 goto out; 4117 } else if (r != 1) { 4118 bad_error("fmri_equal", r); 4119 } 4120 4121 nocust: 4122 /* 4123 * Target has not been customized. Check the dependency property 4124 * group. 4125 */ 4126 4127 if (old_dpt_pgroup == NULL) { 4128 if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name, 4129 ud_pg) != 0) { 4130 switch (scf_error()) { 4131 case SCF_ERROR_NOT_FOUND: 4132 warn(li_corrupt, ient->sc_fmri); 4133 return (EBADF); 4134 4135 case SCF_ERROR_DELETED: 4136 case SCF_ERROR_CONNECTION_BROKEN: 4137 return (scferror2errno(scf_error())); 4138 4139 case SCF_ERROR_NOT_BOUND: 4140 case SCF_ERROR_HANDLE_MISMATCH: 4141 case SCF_ERROR_INVALID_ARGUMENT: 4142 case SCF_ERROR_NOT_SET: 4143 default: 4144 bad_error("scf_snaplevel_get_pg", scf_error()); 4145 } 4146 } 4147 4148 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 4149 snap_lastimport); 4150 switch (r) { 4151 case 0: 4152 break; 4153 4154 case ECANCELED: 4155 case ECONNABORTED: 4156 case ENOMEM: 4157 case EBADF: 4158 return (r); 4159 4160 case EACCES: 4161 default: 4162 bad_error("load_pg", r); 4163 } 4164 } 4165 4166 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4167 switch (serr) { 4168 case SCF_ERROR_NONE: 4169 break; 4170 4171 case SCF_ERROR_NOT_FOUND: 4172 warn(cf_missing, ient->sc_fmri, ud_name); 4173 r = 0; 4174 goto out; 4175 4176 case SCF_ERROR_NO_MEMORY: 4177 r = ENOMEM; 4178 goto out; 4179 4180 case SCF_ERROR_CONSTRAINT_VIOLATED: 4181 case SCF_ERROR_INVALID_ARGUMENT: 4182 default: 4183 bad_error("fmri_to_entity", serr); 4184 } 4185 4186 r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg, 4187 ud_iter2, ud_inst, imp_snap, ud_snpl); 4188 switch (r) { 4189 case 0: 4190 break; 4191 4192 case ECONNABORTED: 4193 goto out; 4194 4195 case ECANCELED: 4196 case ENOENT: 4197 warn(cf_missing, ient->sc_fmri, ud_name); 4198 r = 0; 4199 goto out; 4200 4201 case EBADF: 4202 warn(r_no_lvl, ud_ctarg); 4203 goto out; 4204 4205 case EINVAL: 4206 default: 4207 bad_error("entity_get_running_pg", r); 4208 } 4209 4210 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4211 switch (r) { 4212 case 0: 4213 break; 4214 4215 case ECANCELED: 4216 warn(cf_missing, ient->sc_fmri, ud_name); 4217 goto out; 4218 4219 case ECONNABORTED: 4220 case ENOMEM: 4221 case EBADF: 4222 goto out; 4223 4224 case EACCES: 4225 default: 4226 bad_error("load_pg", r); 4227 } 4228 4229 if (!pg_equal(current_pg, old_dpt_pgroup)) { 4230 if (!pg_equal(current_pg, new_dpt_pgroup)) 4231 warn(cf_newdpg, ient->sc_fmri, ud_name); 4232 internal_pgroup_free(current_pg); 4233 r = 0; 4234 goto out; 4235 } 4236 4237 /* Uncustomized. Upgrade. */ 4238 4239 r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg); 4240 switch (r) { 4241 case 1: 4242 if (pg_equal(current_pg, new_dpt_pgroup)) { 4243 /* Already upgraded. */ 4244 internal_pgroup_free(current_pg); 4245 r = 0; 4246 goto out; 4247 } 4248 4249 internal_pgroup_free(current_pg); 4250 4251 /* upgrade current_pg */ 4252 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 4253 switch (scf_error()) { 4254 case SCF_ERROR_CONNECTION_BROKEN: 4255 r = scferror2errno(scf_error()); 4256 goto out; 4257 4258 case SCF_ERROR_DELETED: 4259 warn(cf_missing, ient->sc_fmri, ud_name); 4260 r = 0; 4261 goto out; 4262 4263 case SCF_ERROR_NOT_FOUND: 4264 break; 4265 4266 case SCF_ERROR_INVALID_ARGUMENT: 4267 case SCF_ERROR_NOT_BOUND: 4268 case SCF_ERROR_NOT_SET: 4269 case SCF_ERROR_HANDLE_MISMATCH: 4270 default: 4271 bad_error("entity_get_pg", scf_error()); 4272 } 4273 4274 if (tissvc) 4275 r = scf_service_add_pg(target_ent, ud_name, 4276 SCF_GROUP_DEPENDENCY, 0, ud_pg); 4277 else 4278 r = scf_instance_add_pg(target_ent, ud_name, 4279 SCF_GROUP_DEPENDENCY, 0, ud_pg); 4280 if (r != 0) { 4281 switch (scf_error()) { 4282 case SCF_ERROR_CONNECTION_BROKEN: 4283 case SCF_ERROR_NO_RESOURCES: 4284 case SCF_ERROR_BACKEND_READONLY: 4285 case SCF_ERROR_BACKEND_ACCESS: 4286 r = scferror2errno(scf_error()); 4287 goto out; 4288 4289 case SCF_ERROR_DELETED: 4290 warn(cf_missing, ient->sc_fmri, 4291 ud_name); 4292 r = 0; 4293 goto out; 4294 4295 case SCF_ERROR_PERMISSION_DENIED: 4296 warn(emsg_pg_deleted, ud_ctarg, 4297 ud_name); 4298 r = EPERM; 4299 goto out; 4300 4301 case SCF_ERROR_EXISTS: 4302 warn(emsg_pg_added, ud_ctarg, ud_name); 4303 r = EBUSY; 4304 goto out; 4305 4306 case SCF_ERROR_NOT_BOUND: 4307 case SCF_ERROR_HANDLE_MISMATCH: 4308 case SCF_ERROR_INVALID_ARGUMENT: 4309 case SCF_ERROR_NOT_SET: 4310 default: 4311 bad_error("entity_add_pg", scf_error()); 4312 } 4313 } 4314 } 4315 4316 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4317 switch (r) { 4318 case 0: 4319 break; 4320 4321 case ECANCELED: 4322 warn(cf_missing, ient->sc_fmri, ud_name); 4323 goto out; 4324 4325 case ECONNABORTED: 4326 case ENOMEM: 4327 case EBADF: 4328 goto out; 4329 4330 case EACCES: 4331 default: 4332 bad_error("load_pg", r); 4333 } 4334 4335 if (g_verbose) 4336 warn(upgrading, ient->sc_fmri, ud_name); 4337 4338 r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup, 4339 new_dpt_pgroup, 0, ient->sc_fmri); 4340 switch (r) { 4341 case 0: 4342 break; 4343 4344 case ECANCELED: 4345 warn(emsg_pg_deleted, ud_ctarg, ud_name); 4346 r = EBUSY; 4347 goto out; 4348 4349 case EPERM: 4350 warn(emsg_pg_mod_perm, ud_name, ud_ctarg); 4351 goto out; 4352 4353 case EBUSY: 4354 warn(emsg_pg_changed, ud_ctarg, ud_name); 4355 goto out; 4356 4357 case ECONNABORTED: 4358 case ENOMEM: 4359 case ENOSPC: 4360 case EROFS: 4361 case EACCES: 4362 case EINVAL: 4363 goto out; 4364 4365 default: 4366 bad_error("upgrade_pg", r); 4367 } 4368 break; 4369 4370 case 0: { 4371 scf_transaction_entry_t *ent; 4372 scf_value_t *val; 4373 4374 internal_pgroup_free(current_pg); 4375 4376 /* delete old pg */ 4377 if (g_verbose) 4378 warn(upgrading, ient->sc_fmri, ud_name); 4379 4380 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 4381 switch (scf_error()) { 4382 case SCF_ERROR_CONNECTION_BROKEN: 4383 r = scferror2errno(scf_error()); 4384 goto out; 4385 4386 case SCF_ERROR_DELETED: 4387 warn(cf_missing, ient->sc_fmri, ud_name); 4388 r = 0; 4389 goto out; 4390 4391 case SCF_ERROR_NOT_FOUND: 4392 break; 4393 4394 case SCF_ERROR_INVALID_ARGUMENT: 4395 case SCF_ERROR_NOT_BOUND: 4396 case SCF_ERROR_NOT_SET: 4397 case SCF_ERROR_HANDLE_MISMATCH: 4398 default: 4399 bad_error("entity_get_pg", scf_error()); 4400 } 4401 } else if (scf_pg_delete(ud_pg) != 0) { 4402 switch (scf_error()) { 4403 case SCF_ERROR_DELETED: 4404 break; 4405 4406 case SCF_ERROR_CONNECTION_BROKEN: 4407 case SCF_ERROR_BACKEND_READONLY: 4408 case SCF_ERROR_BACKEND_ACCESS: 4409 r = scferror2errno(scf_error()); 4410 goto out; 4411 4412 case SCF_ERROR_PERMISSION_DENIED: 4413 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri); 4414 r = scferror2errno(scf_error()); 4415 goto out; 4416 4417 case SCF_ERROR_NOT_SET: 4418 default: 4419 bad_error("scf_pg_delete", scf_error()); 4420 } 4421 } 4422 4423 /* import new one */ 4424 cbdata.sc_handle = g_hndl; 4425 cbdata.sc_trans = NULL; /* handled below */ 4426 4427 r = lscf_dependent_import(new_dpt_pgroup, &cbdata); 4428 if (r != UU_WALK_NEXT) { 4429 if (r != UU_WALK_ERROR) 4430 bad_error("lscf_dependent_import", r); 4431 4432 r = cbdata.sc_err; 4433 goto out; 4434 } 4435 4436 if (tx == NULL) 4437 break; 4438 4439 if ((ent = scf_entry_create(g_hndl)) == NULL || 4440 (val = scf_value_create(g_hndl)) == NULL) { 4441 if (scf_error() == SCF_ERROR_NO_MEMORY) 4442 return (ENOMEM); 4443 4444 bad_error("scf_entry_create", scf_error()); 4445 } 4446 4447 if (scf_transaction_property_change_type(tx, ent, ud_name, 4448 SCF_TYPE_FMRI) != 0) { 4449 switch (scf_error()) { 4450 case SCF_ERROR_CONNECTION_BROKEN: 4451 r = scferror2errno(scf_error()); 4452 goto out; 4453 4454 case SCF_ERROR_DELETED: 4455 warn(emsg_pg_deleted, ient->sc_fmri, 4456 "dependents"); 4457 r = EBUSY; 4458 goto out; 4459 4460 case SCF_ERROR_NOT_FOUND: 4461 break; 4462 4463 case SCF_ERROR_NOT_BOUND: 4464 case SCF_ERROR_HANDLE_MISMATCH: 4465 case SCF_ERROR_INVALID_ARGUMENT: 4466 case SCF_ERROR_NOT_SET: 4467 default: 4468 bad_error("scf_transaction_property_" 4469 "change_type", scf_error()); 4470 } 4471 4472 if (scf_transaction_property_new(tx, ent, ud_name, 4473 SCF_TYPE_FMRI) != 0) { 4474 switch (scf_error()) { 4475 case SCF_ERROR_CONNECTION_BROKEN: 4476 r = scferror2errno(scf_error()); 4477 goto out; 4478 4479 case SCF_ERROR_DELETED: 4480 warn(emsg_pg_deleted, ient->sc_fmri, 4481 "dependents"); 4482 r = EBUSY; 4483 goto out; 4484 4485 case SCF_ERROR_EXISTS: 4486 warn(emsg_pg_changed, ient->sc_fmri, 4487 "dependents"); 4488 r = EBUSY; 4489 goto out; 4490 4491 case SCF_ERROR_INVALID_ARGUMENT: 4492 case SCF_ERROR_HANDLE_MISMATCH: 4493 case SCF_ERROR_NOT_BOUND: 4494 case SCF_ERROR_NOT_SET: 4495 default: 4496 bad_error("scf_transaction_property_" 4497 "new", scf_error()); 4498 } 4499 } 4500 } 4501 4502 if (scf_value_set_from_string(val, SCF_TYPE_FMRI, 4503 new_dpt_pgroup->sc_pgroup_fmri) != 0) 4504 /* invalid sc_pgroup_fmri caught above */ 4505 bad_error("scf_value_set_from_string", 4506 scf_error()); 4507 4508 if (scf_entry_add_value(ent, val) != 0) 4509 bad_error("scf_entry_add_value", scf_error()); 4510 break; 4511 } 4512 4513 case -2: 4514 warn(li_corrupt, ient->sc_fmri); 4515 internal_pgroup_free(current_pg); 4516 r = EBADF; 4517 goto out; 4518 4519 case -1: 4520 default: 4521 /* invalid sc_pgroup_fmri caught above */ 4522 bad_error("fmri_equal", r); 4523 } 4524 4525 r = 0; 4526 4527 out: 4528 if (old_dpt_pgroup != NULL) 4529 internal_pgroup_free(old_dpt_pgroup); 4530 4531 return (r); 4532 } 4533 4534 /* 4535 * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we 4536 * would import it, except it seems to exist in the service anyway. Compare 4537 * the existent dependent with the one we would import, and report any 4538 * differences (if there are none, be silent). prop is the property which 4539 * represents the existent dependent (in the dependents property group) in the 4540 * entity corresponding to ient. 4541 * 4542 * Returns 4543 * 0 - success (Sort of. At least, we can continue importing.) 4544 * ECONNABORTED - repository connection broken 4545 * EBUSY - ancestor of prop was deleted (error printed) 4546 * ENOMEM - out of memory 4547 * EBADF - corrupt property group (error printed) 4548 * EINVAL - new_dpt_pgroup has invalid target (error printed) 4549 */ 4550 static int 4551 handle_dependent_conflict(const entity_t * const ient, 4552 const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup) 4553 { 4554 int r; 4555 scf_type_t ty; 4556 scf_error_t scfe; 4557 void *tptr; 4558 int tissvc; 4559 pgroup_t *pgroup; 4560 4561 if (scf_property_get_value(prop, ud_val) != 0) { 4562 switch (scf_error()) { 4563 case SCF_ERROR_CONNECTION_BROKEN: 4564 return (scferror2errno(scf_error())); 4565 4566 case SCF_ERROR_DELETED: 4567 warn(emsg_pg_deleted, ient->sc_fmri, 4568 new_dpt_pgroup->sc_pgroup_name); 4569 return (EBUSY); 4570 4571 case SCF_ERROR_CONSTRAINT_VIOLATED: 4572 case SCF_ERROR_NOT_FOUND: 4573 warn(gettext("Conflict upgrading %s (not importing " 4574 "dependent \"%s\" because it already exists.) " 4575 "Warning: The \"%s/%2$s\" property has more or " 4576 "fewer than one value)).\n"), ient->sc_fmri, 4577 new_dpt_pgroup->sc_pgroup_name, "dependents"); 4578 return (0); 4579 4580 case SCF_ERROR_HANDLE_MISMATCH: 4581 case SCF_ERROR_NOT_BOUND: 4582 case SCF_ERROR_NOT_SET: 4583 case SCF_ERROR_PERMISSION_DENIED: 4584 default: 4585 bad_error("scf_property_get_value", 4586 scf_error()); 4587 } 4588 } 4589 4590 ty = scf_value_type(ud_val); 4591 assert(ty != SCF_TYPE_INVALID); 4592 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4593 warn(gettext("Conflict upgrading %s (not importing dependent " 4594 "\"%s\" because it already exists). Warning: The " 4595 "\"%s/%s\" property has unexpected type \"%s\")).\n"), 4596 ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name, 4597 scf_type_to_string(ty), "dependents"); 4598 return (0); 4599 } 4600 4601 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) < 4602 0) 4603 bad_error("scf_value_get_as_string", scf_error()); 4604 4605 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri); 4606 switch (r) { 4607 case 0: 4608 warn(gettext("Conflict upgrading %s (not importing dependent " 4609 "\"%s\" (target \"%s\") because it already exists with " 4610 "target \"%s\").\n"), ient->sc_fmri, 4611 new_dpt_pgroup->sc_pgroup_name, 4612 new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg); 4613 return (0); 4614 4615 case 1: 4616 break; 4617 4618 case -1: 4619 warn(gettext("Conflict upgrading %s (not importing dependent " 4620 "\"%s\" because it already exists). Warning: The current " 4621 "dependent's target (%s) is invalid.\n"), ient->sc_fmri, 4622 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 4623 return (0); 4624 4625 case -2: 4626 warn(gettext("Dependent \"%s\" of %s has invalid target " 4627 "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri, 4628 new_dpt_pgroup->sc_pgroup_fmri); 4629 return (EINVAL); 4630 4631 default: 4632 bad_error("fmri_equal", r); 4633 } 4634 4635 /* compare dependency pgs in target */ 4636 scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc); 4637 switch (scfe) { 4638 case SCF_ERROR_NONE: 4639 break; 4640 4641 case SCF_ERROR_NO_MEMORY: 4642 return (ENOMEM); 4643 4644 case SCF_ERROR_NOT_FOUND: 4645 warn(emsg_dpt_dangling, ient->sc_fmri, 4646 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 4647 return (0); 4648 4649 case SCF_ERROR_CONSTRAINT_VIOLATED: 4650 case SCF_ERROR_INVALID_ARGUMENT: 4651 default: 4652 bad_error("fmri_to_entity", scfe); 4653 } 4654 4655 r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name, 4656 ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl); 4657 switch (r) { 4658 case 0: 4659 break; 4660 4661 case ECONNABORTED: 4662 return (r); 4663 4664 case ECANCELED: 4665 warn(emsg_dpt_dangling, ient->sc_fmri, 4666 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 4667 return (0); 4668 4669 case EBADF: 4670 if (tissvc) 4671 warn(gettext("%s has an instance with a \"%s\" " 4672 "snapshot which is missing a snaplevel.\n"), 4673 ud_ctarg, "running"); 4674 else 4675 warn(gettext("%s has a \"%s\" snapshot which is " 4676 "missing a snaplevel.\n"), ud_ctarg, "running"); 4677 /* FALLTHROUGH */ 4678 4679 case ENOENT: 4680 warn(emsg_dpt_no_dep, ient->sc_fmri, 4681 new_dpt_pgroup->sc_pgroup_name, ud_ctarg, 4682 new_dpt_pgroup->sc_pgroup_name); 4683 return (0); 4684 4685 case EINVAL: 4686 default: 4687 bad_error("entity_get_running_pg", r); 4688 } 4689 4690 pgroup = internal_pgroup_new(); 4691 if (pgroup == NULL) 4692 return (ENOMEM); 4693 4694 r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL); 4695 switch (r) { 4696 case 0: 4697 break; 4698 4699 case ECONNABORTED: 4700 case EBADF: 4701 case ENOMEM: 4702 internal_pgroup_free(pgroup); 4703 return (r); 4704 4705 case ECANCELED: 4706 warn(emsg_dpt_no_dep, ient->sc_fmri, 4707 new_dpt_pgroup->sc_pgroup_name, ud_ctarg, 4708 new_dpt_pgroup->sc_pgroup_name); 4709 internal_pgroup_free(pgroup); 4710 return (0); 4711 4712 case EACCES: 4713 default: 4714 bad_error("load_pg", r); 4715 } 4716 4717 /* report differences */ 4718 report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1); 4719 internal_pgroup_free(pgroup); 4720 return (0); 4721 } 4722 4723 /* 4724 * lipg is a property group in the last-import snapshot of ent, which is an 4725 * scf_service_t or an scf_instance_t (according to ient). If lipg is not in 4726 * ient's pgroups, delete it from ent if it hasn't been customized. If it is 4727 * in ents's property groups, compare and upgrade ent appropriately. 4728 * 4729 * Returns 4730 * 0 - success 4731 * ECONNABORTED - repository connection broken 4732 * ENOMEM - out of memory 4733 * ENOSPC - configd is out of resources 4734 * EINVAL - ient has invalid dependent (error printed) 4735 * - ient has invalid pgroup_t (error printed) 4736 * ECANCELED - ent has been deleted 4737 * ENODEV - entity containing lipg has been deleted 4738 * - entity containing running has been deleted 4739 * EPERM - could not delete pg (permission denied) (error printed) 4740 * - couldn't upgrade dependents (permission denied) (error printed) 4741 * - couldn't import pg (permission denied) (error printed) 4742 * - couldn't upgrade pg (permission denied) (error printed) 4743 * EROFS - could not delete pg (repository read-only) 4744 * - couldn't upgrade dependents (repository read-only) 4745 * - couldn't import pg (repository read-only) 4746 * - couldn't upgrade pg (repository read-only) 4747 * EACCES - could not delete pg (backend access denied) 4748 * - couldn't upgrade dependents (backend access denied) 4749 * - couldn't import pg (backend access denied) 4750 * - couldn't upgrade pg (backend access denied) 4751 * - couldn't read property (backend access denied) 4752 * EBUSY - property group was added (error printed) 4753 * - property group was deleted (error printed) 4754 * - property group changed (error printed) 4755 * - "dependents" pg was added, changed, or deleted (error printed) 4756 * - dependent target deleted (error printed) 4757 * - dependent pg changed (error printed) 4758 * EBADF - imp_snpl is corrupt (error printed) 4759 * - ent has bad pg (error printed) 4760 * EEXIST - dependent collision in target service (error printed) 4761 */ 4762 static int 4763 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent, 4764 const scf_snaplevel_t *running) 4765 { 4766 int r; 4767 pgroup_t *mpg, *lipg_i, *curpg_i, pgrp; 4768 scf_callback_t cbdata; 4769 4770 const char * const cf_pg_missing = 4771 gettext("Conflict upgrading %s (property group %s is missing)\n"); 4772 const char * const deleting = 4773 gettext("%s: Deleting property group \"%s\".\n"); 4774 4775 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 4776 4777 /* Skip dependent property groups. */ 4778 if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) { 4779 switch (scf_error()) { 4780 case SCF_ERROR_DELETED: 4781 return (ENODEV); 4782 4783 case SCF_ERROR_CONNECTION_BROKEN: 4784 return (ECONNABORTED); 4785 4786 case SCF_ERROR_NOT_SET: 4787 case SCF_ERROR_NOT_BOUND: 4788 default: 4789 bad_error("scf_pg_get_type", scf_error()); 4790 } 4791 } 4792 4793 if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) { 4794 if (scf_pg_get_property(lipg, "external", NULL) == 0) 4795 return (0); 4796 4797 switch (scf_error()) { 4798 case SCF_ERROR_NOT_FOUND: 4799 break; 4800 4801 case SCF_ERROR_CONNECTION_BROKEN: 4802 return (ECONNABORTED); 4803 4804 case SCF_ERROR_DELETED: 4805 return (ENODEV); 4806 4807 case SCF_ERROR_INVALID_ARGUMENT: 4808 case SCF_ERROR_NOT_BOUND: 4809 case SCF_ERROR_HANDLE_MISMATCH: 4810 case SCF_ERROR_NOT_SET: 4811 default: 4812 bad_error("scf_pg_get_property", scf_error()); 4813 } 4814 } 4815 4816 /* lookup pg in new properties */ 4817 if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) { 4818 switch (scf_error()) { 4819 case SCF_ERROR_DELETED: 4820 return (ENODEV); 4821 4822 case SCF_ERROR_CONNECTION_BROKEN: 4823 return (ECONNABORTED); 4824 4825 case SCF_ERROR_NOT_SET: 4826 case SCF_ERROR_NOT_BOUND: 4827 default: 4828 bad_error("scf_pg_get_name", scf_error()); 4829 } 4830 } 4831 4832 pgrp.sc_pgroup_name = imp_str; 4833 mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL); 4834 4835 if (mpg != NULL) 4836 mpg->sc_pgroup_seen = 1; 4837 4838 /* Special handling for dependents */ 4839 if (strcmp(imp_str, "dependents") == 0) 4840 return (upgrade_dependents(lipg, imp_snpl, ient, running, ent)); 4841 4842 if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0) 4843 if ((r = upgrade_manifestfiles(ient, running, ent)) != 0) 4844 return (r); 4845 4846 if (mpg == NULL || mpg->sc_pgroup_delete) { 4847 /* property group was deleted from manifest */ 4848 if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 4849 switch (scf_error()) { 4850 case SCF_ERROR_NOT_FOUND: 4851 return (0); 4852 4853 case SCF_ERROR_DELETED: 4854 case SCF_ERROR_CONNECTION_BROKEN: 4855 return (scferror2errno(scf_error())); 4856 4857 case SCF_ERROR_INVALID_ARGUMENT: 4858 case SCF_ERROR_HANDLE_MISMATCH: 4859 case SCF_ERROR_NOT_BOUND: 4860 case SCF_ERROR_NOT_SET: 4861 default: 4862 bad_error("entity_get_pg", scf_error()); 4863 } 4864 } 4865 4866 if (mpg != NULL && mpg->sc_pgroup_delete) { 4867 if (g_verbose) 4868 warn(deleting, ient->sc_fmri, imp_str); 4869 if (scf_pg_delete(imp_pg2) == 0) 4870 return (0); 4871 4872 switch (scf_error()) { 4873 case SCF_ERROR_DELETED: 4874 return (0); 4875 4876 case SCF_ERROR_CONNECTION_BROKEN: 4877 case SCF_ERROR_BACKEND_READONLY: 4878 case SCF_ERROR_BACKEND_ACCESS: 4879 return (scferror2errno(scf_error())); 4880 4881 case SCF_ERROR_PERMISSION_DENIED: 4882 warn(emsg_pg_del_perm, imp_str, ient->sc_fmri); 4883 return (scferror2errno(scf_error())); 4884 4885 case SCF_ERROR_NOT_SET: 4886 default: 4887 bad_error("scf_pg_delete", scf_error()); 4888 } 4889 } 4890 4891 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport); 4892 switch (r) { 4893 case 0: 4894 break; 4895 4896 case ECANCELED: 4897 return (ENODEV); 4898 4899 case ECONNABORTED: 4900 case ENOMEM: 4901 case EBADF: 4902 case EACCES: 4903 return (r); 4904 4905 default: 4906 bad_error("load_pg", r); 4907 } 4908 4909 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL); 4910 switch (r) { 4911 case 0: 4912 break; 4913 4914 case ECANCELED: 4915 case ECONNABORTED: 4916 case ENOMEM: 4917 case EBADF: 4918 case EACCES: 4919 internal_pgroup_free(lipg_i); 4920 return (r); 4921 4922 default: 4923 bad_error("load_pg", r); 4924 } 4925 4926 if (pg_equal(lipg_i, curpg_i)) { 4927 if (g_verbose) 4928 warn(deleting, ient->sc_fmri, imp_str); 4929 if (scf_pg_delete(imp_pg2) != 0) { 4930 switch (scf_error()) { 4931 case SCF_ERROR_DELETED: 4932 break; 4933 4934 case SCF_ERROR_CONNECTION_BROKEN: 4935 internal_pgroup_free(lipg_i); 4936 internal_pgroup_free(curpg_i); 4937 return (ECONNABORTED); 4938 4939 case SCF_ERROR_NOT_SET: 4940 case SCF_ERROR_NOT_BOUND: 4941 default: 4942 bad_error("scf_pg_delete", scf_error()); 4943 } 4944 } 4945 } else { 4946 report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0); 4947 } 4948 4949 internal_pgroup_free(lipg_i); 4950 internal_pgroup_free(curpg_i); 4951 4952 return (0); 4953 } 4954 4955 /* 4956 * Only dependent pgs can have override set, and we skipped those 4957 * above. 4958 */ 4959 assert(!mpg->sc_pgroup_override); 4960 4961 /* compare */ 4962 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport); 4963 switch (r) { 4964 case 0: 4965 break; 4966 4967 case ECANCELED: 4968 return (ENODEV); 4969 4970 case ECONNABORTED: 4971 case EBADF: 4972 case ENOMEM: 4973 case EACCES: 4974 return (r); 4975 4976 default: 4977 bad_error("load_pg", r); 4978 } 4979 4980 if (pg_equal(mpg, lipg_i)) { 4981 /* The manifest pg has not changed. Move on. */ 4982 r = 0; 4983 goto out; 4984 } 4985 4986 /* upgrade current properties according to lipg & mpg */ 4987 if (running != NULL) 4988 r = scf_snaplevel_get_pg(running, imp_str, imp_pg2); 4989 else 4990 r = entity_get_pg(ent, issvc, imp_str, imp_pg2); 4991 if (r != 0) { 4992 switch (scf_error()) { 4993 case SCF_ERROR_CONNECTION_BROKEN: 4994 r = scferror2errno(scf_error()); 4995 goto out; 4996 4997 case SCF_ERROR_DELETED: 4998 if (running != NULL) 4999 r = ENODEV; 5000 else 5001 r = ECANCELED; 5002 goto out; 5003 5004 case SCF_ERROR_NOT_FOUND: 5005 break; 5006 5007 case SCF_ERROR_INVALID_ARGUMENT: 5008 case SCF_ERROR_HANDLE_MISMATCH: 5009 case SCF_ERROR_NOT_BOUND: 5010 case SCF_ERROR_NOT_SET: 5011 default: 5012 bad_error("entity_get_pg", scf_error()); 5013 } 5014 5015 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5016 5017 r = 0; 5018 goto out; 5019 } 5020 5021 r = load_pg_attrs(imp_pg2, &curpg_i); 5022 switch (r) { 5023 case 0: 5024 break; 5025 5026 case ECANCELED: 5027 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5028 r = 0; 5029 goto out; 5030 5031 case ECONNABORTED: 5032 case ENOMEM: 5033 goto out; 5034 5035 default: 5036 bad_error("load_pg_attrs", r); 5037 } 5038 5039 if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) { 5040 (void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0); 5041 internal_pgroup_free(curpg_i); 5042 r = 0; 5043 goto out; 5044 } 5045 5046 internal_pgroup_free(curpg_i); 5047 5048 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL); 5049 switch (r) { 5050 case 0: 5051 break; 5052 5053 case ECANCELED: 5054 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5055 r = 0; 5056 goto out; 5057 5058 case ECONNABORTED: 5059 case EBADF: 5060 case ENOMEM: 5061 case EACCES: 5062 goto out; 5063 5064 default: 5065 bad_error("load_pg", r); 5066 } 5067 5068 if (pg_equal(lipg_i, curpg_i) && 5069 !pg_attrs_equal(lipg_i, mpg, NULL, 0)) { 5070 int do_delete = 1; 5071 5072 if (g_verbose) 5073 warn(gettext("%s: Upgrading property group \"%s\".\n"), 5074 ient->sc_fmri, mpg->sc_pgroup_name); 5075 5076 internal_pgroup_free(curpg_i); 5077 5078 if (running != NULL && 5079 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5080 switch (scf_error()) { 5081 case SCF_ERROR_DELETED: 5082 r = ECANCELED; 5083 goto out; 5084 5085 case SCF_ERROR_NOT_FOUND: 5086 do_delete = 0; 5087 break; 5088 5089 case SCF_ERROR_CONNECTION_BROKEN: 5090 r = scferror2errno(scf_error()); 5091 goto out; 5092 5093 case SCF_ERROR_HANDLE_MISMATCH: 5094 case SCF_ERROR_INVALID_ARGUMENT: 5095 case SCF_ERROR_NOT_SET: 5096 case SCF_ERROR_NOT_BOUND: 5097 default: 5098 bad_error("entity_get_pg", scf_error()); 5099 } 5100 } 5101 5102 if (do_delete && scf_pg_delete(imp_pg2) != 0) { 5103 switch (scf_error()) { 5104 case SCF_ERROR_DELETED: 5105 break; 5106 5107 case SCF_ERROR_CONNECTION_BROKEN: 5108 case SCF_ERROR_BACKEND_READONLY: 5109 case SCF_ERROR_BACKEND_ACCESS: 5110 r = scferror2errno(scf_error()); 5111 goto out; 5112 5113 case SCF_ERROR_PERMISSION_DENIED: 5114 warn(emsg_pg_del_perm, mpg->sc_pgroup_name, 5115 ient->sc_fmri); 5116 r = scferror2errno(scf_error()); 5117 goto out; 5118 5119 case SCF_ERROR_NOT_SET: 5120 case SCF_ERROR_NOT_BOUND: 5121 default: 5122 bad_error("scf_pg_delete", scf_error()); 5123 } 5124 } 5125 5126 cbdata.sc_handle = g_hndl; 5127 cbdata.sc_parent = ent; 5128 cbdata.sc_service = issvc; 5129 cbdata.sc_flags = 0; 5130 cbdata.sc_source_fmri = ient->sc_fmri; 5131 cbdata.sc_target_fmri = ient->sc_fmri; 5132 5133 r = entity_pgroup_import(mpg, &cbdata); 5134 switch (r) { 5135 case UU_WALK_NEXT: 5136 r = 0; 5137 goto out; 5138 5139 case UU_WALK_ERROR: 5140 if (cbdata.sc_err == EEXIST) { 5141 warn(emsg_pg_added, ient->sc_fmri, 5142 mpg->sc_pgroup_name); 5143 r = EBUSY; 5144 } else { 5145 r = cbdata.sc_err; 5146 } 5147 goto out; 5148 5149 default: 5150 bad_error("entity_pgroup_import", r); 5151 } 5152 } 5153 5154 if (running != NULL && 5155 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5156 switch (scf_error()) { 5157 case SCF_ERROR_CONNECTION_BROKEN: 5158 case SCF_ERROR_DELETED: 5159 r = scferror2errno(scf_error()); 5160 goto out; 5161 5162 case SCF_ERROR_NOT_FOUND: 5163 break; 5164 5165 case SCF_ERROR_HANDLE_MISMATCH: 5166 case SCF_ERROR_INVALID_ARGUMENT: 5167 case SCF_ERROR_NOT_SET: 5168 case SCF_ERROR_NOT_BOUND: 5169 default: 5170 bad_error("entity_get_pg", scf_error()); 5171 } 5172 5173 cbdata.sc_handle = g_hndl; 5174 cbdata.sc_parent = ent; 5175 cbdata.sc_service = issvc; 5176 cbdata.sc_flags = SCI_FORCE; 5177 cbdata.sc_source_fmri = ient->sc_fmri; 5178 cbdata.sc_target_fmri = ient->sc_fmri; 5179 5180 r = entity_pgroup_import(mpg, &cbdata); 5181 switch (r) { 5182 case UU_WALK_NEXT: 5183 r = 0; 5184 goto out; 5185 5186 case UU_WALK_ERROR: 5187 if (cbdata.sc_err == EEXIST) { 5188 warn(emsg_pg_added, ient->sc_fmri, 5189 mpg->sc_pgroup_name); 5190 r = EBUSY; 5191 } else { 5192 r = cbdata.sc_err; 5193 } 5194 goto out; 5195 5196 default: 5197 bad_error("entity_pgroup_import", r); 5198 } 5199 } 5200 5201 r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri); 5202 internal_pgroup_free(curpg_i); 5203 switch (r) { 5204 case 0: 5205 ient->sc_import_state = IMPORT_PROP_BEGUN; 5206 break; 5207 5208 case ECANCELED: 5209 warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name); 5210 r = EBUSY; 5211 break; 5212 5213 case EPERM: 5214 warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri); 5215 break; 5216 5217 case EBUSY: 5218 warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name); 5219 break; 5220 5221 case ECONNABORTED: 5222 case ENOMEM: 5223 case ENOSPC: 5224 case EROFS: 5225 case EACCES: 5226 case EINVAL: 5227 break; 5228 5229 default: 5230 bad_error("upgrade_pg", r); 5231 } 5232 5233 out: 5234 internal_pgroup_free(lipg_i); 5235 return (r); 5236 } 5237 5238 /* 5239 * Upgrade the properties of ent according to snpl & ient. 5240 * 5241 * Returns 5242 * 0 - success 5243 * ECONNABORTED - repository connection broken 5244 * ENOMEM - out of memory 5245 * ENOSPC - configd is out of resources 5246 * ECANCELED - ent was deleted 5247 * ENODEV - entity containing snpl was deleted 5248 * - entity containing running was deleted 5249 * EBADF - imp_snpl is corrupt (error printed) 5250 * - ent has corrupt pg (error printed) 5251 * - dependent has corrupt pg (error printed) 5252 * - dependent target has a corrupt snapshot (error printed) 5253 * EBUSY - pg was added, changed, or deleted (error printed) 5254 * - dependent target was deleted (error printed) 5255 * - dependent pg changed (error printed) 5256 * EINVAL - invalid property group name (error printed) 5257 * - invalid property name (error printed) 5258 * - invalid value (error printed) 5259 * - ient has invalid pgroup or dependent (error printed) 5260 * EPERM - could not create property group (permission denied) (error printed) 5261 * - could not modify property group (permission denied) (error printed) 5262 * - couldn't delete, upgrade, or import pg or dependent (error printed) 5263 * EROFS - could not create property group (repository read-only) 5264 * - couldn't delete, upgrade, or import pg or dependent 5265 * EACCES - could not create property group (backend access denied) 5266 * - couldn't delete, upgrade, or import pg or dependent 5267 * EEXIST - dependent collision in target service (error printed) 5268 */ 5269 static int 5270 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl, 5271 entity_t *ient) 5272 { 5273 pgroup_t *pg, *rpg; 5274 int r; 5275 uu_list_t *pgs = ient->sc_pgroups; 5276 5277 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 5278 5279 /* clear sc_sceen for pgs */ 5280 if (uu_list_walk(pgs, clear_int, 5281 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0) 5282 bad_error("uu_list_walk", uu_error()); 5283 5284 if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) { 5285 switch (scf_error()) { 5286 case SCF_ERROR_DELETED: 5287 return (ENODEV); 5288 5289 case SCF_ERROR_CONNECTION_BROKEN: 5290 return (ECONNABORTED); 5291 5292 case SCF_ERROR_NOT_SET: 5293 case SCF_ERROR_NOT_BOUND: 5294 case SCF_ERROR_HANDLE_MISMATCH: 5295 default: 5296 bad_error("scf_iter_snaplevel_pgs", scf_error()); 5297 } 5298 } 5299 5300 for (;;) { 5301 r = scf_iter_next_pg(imp_up_iter, imp_pg); 5302 if (r == 0) 5303 break; 5304 if (r == 1) { 5305 r = process_old_pg(imp_pg, ient, ent, running); 5306 switch (r) { 5307 case 0: 5308 break; 5309 5310 case ECONNABORTED: 5311 case ENOMEM: 5312 case ENOSPC: 5313 case ECANCELED: 5314 case ENODEV: 5315 case EPERM: 5316 case EROFS: 5317 case EACCES: 5318 case EBADF: 5319 case EBUSY: 5320 case EINVAL: 5321 case EEXIST: 5322 return (r); 5323 5324 default: 5325 bad_error("process_old_pg", r); 5326 } 5327 continue; 5328 } 5329 if (r != -1) 5330 bad_error("scf_iter_next_pg", r); 5331 5332 switch (scf_error()) { 5333 case SCF_ERROR_DELETED: 5334 return (ENODEV); 5335 5336 case SCF_ERROR_CONNECTION_BROKEN: 5337 return (ECONNABORTED); 5338 5339 case SCF_ERROR_HANDLE_MISMATCH: 5340 case SCF_ERROR_NOT_BOUND: 5341 case SCF_ERROR_NOT_SET: 5342 case SCF_ERROR_INVALID_ARGUMENT: 5343 default: 5344 bad_error("scf_iter_next_pg", scf_error()); 5345 } 5346 } 5347 5348 for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) { 5349 if (pg->sc_pgroup_seen) 5350 continue; 5351 5352 /* pg is new */ 5353 5354 if (strcmp(pg->sc_pgroup_name, "dependents") == 0) { 5355 r = upgrade_dependents(NULL, imp_snpl, ient, running, 5356 ent); 5357 switch (r) { 5358 case 0: 5359 break; 5360 5361 case ECONNABORTED: 5362 case ENOMEM: 5363 case ENOSPC: 5364 case ECANCELED: 5365 case ENODEV: 5366 case EBADF: 5367 case EBUSY: 5368 case EINVAL: 5369 case EPERM: 5370 case EROFS: 5371 case EACCES: 5372 case EEXIST: 5373 return (r); 5374 5375 default: 5376 bad_error("upgrade_dependents", r); 5377 } 5378 continue; 5379 } 5380 5381 if (running != NULL) 5382 r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name, 5383 imp_pg); 5384 else 5385 r = entity_get_pg(ent, issvc, pg->sc_pgroup_name, 5386 imp_pg); 5387 if (r != 0) { 5388 scf_callback_t cbdata; 5389 5390 switch (scf_error()) { 5391 case SCF_ERROR_NOT_FOUND: 5392 break; 5393 5394 case SCF_ERROR_CONNECTION_BROKEN: 5395 return (scferror2errno(scf_error())); 5396 5397 case SCF_ERROR_DELETED: 5398 if (running != NULL) 5399 return (ENODEV); 5400 else 5401 return (scferror2errno(scf_error())); 5402 5403 case SCF_ERROR_INVALID_ARGUMENT: 5404 warn(emsg_fmri_invalid_pg_name, ient->sc_fmri, 5405 pg->sc_pgroup_name); 5406 return (EINVAL); 5407 5408 case SCF_ERROR_NOT_SET: 5409 case SCF_ERROR_HANDLE_MISMATCH: 5410 case SCF_ERROR_NOT_BOUND: 5411 default: 5412 bad_error("entity_get_pg", scf_error()); 5413 } 5414 5415 /* User doesn't have pg, so import it. */ 5416 5417 cbdata.sc_handle = g_hndl; 5418 cbdata.sc_parent = ent; 5419 cbdata.sc_service = issvc; 5420 cbdata.sc_flags = SCI_FORCE; 5421 cbdata.sc_source_fmri = ient->sc_fmri; 5422 cbdata.sc_target_fmri = ient->sc_fmri; 5423 5424 r = entity_pgroup_import(pg, &cbdata); 5425 switch (r) { 5426 case UU_WALK_NEXT: 5427 ient->sc_import_state = IMPORT_PROP_BEGUN; 5428 continue; 5429 5430 case UU_WALK_ERROR: 5431 if (cbdata.sc_err == EEXIST) { 5432 warn(emsg_pg_added, ient->sc_fmri, 5433 pg->sc_pgroup_name); 5434 return (EBUSY); 5435 } 5436 return (cbdata.sc_err); 5437 5438 default: 5439 bad_error("entity_pgroup_import", r); 5440 } 5441 } 5442 5443 /* report differences between pg & current */ 5444 r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL); 5445 switch (r) { 5446 case 0: 5447 break; 5448 5449 case ECANCELED: 5450 warn(emsg_pg_deleted, ient->sc_fmri, 5451 pg->sc_pgroup_name); 5452 return (EBUSY); 5453 5454 case ECONNABORTED: 5455 case EBADF: 5456 case ENOMEM: 5457 case EACCES: 5458 return (r); 5459 5460 default: 5461 bad_error("load_pg", r); 5462 } 5463 report_pg_diffs(pg, rpg, ient->sc_fmri, 1); 5464 internal_pgroup_free(rpg); 5465 rpg = NULL; 5466 } 5467 5468 return (0); 5469 } 5470 5471 /* 5472 * Import an instance. If it doesn't exist, create it. If it has 5473 * a last-import snapshot, upgrade its properties. Finish by updating its 5474 * last-import snapshot. If it doesn't have a last-import snapshot then it 5475 * could have been created for a dependent tag in another manifest. Import the 5476 * new properties. If there's a conflict, don't override, like now? 5477 * 5478 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 5479 * lcbdata->sc_err to 5480 * ECONNABORTED - repository connection broken 5481 * ENOMEM - out of memory 5482 * ENOSPC - svc.configd is out of resources 5483 * EEXIST - dependency collision in dependent service (error printed) 5484 * EPERM - couldn't create temporary instance (permission denied) 5485 * - couldn't import into temporary instance (permission denied) 5486 * - couldn't take snapshot (permission denied) 5487 * - couldn't upgrade properties (permission denied) 5488 * - couldn't import properties (permission denied) 5489 * - couldn't import dependents (permission denied) 5490 * EROFS - couldn't create temporary instance (repository read-only) 5491 * - couldn't import into temporary instance (repository read-only) 5492 * - couldn't upgrade properties (repository read-only) 5493 * - couldn't import properties (repository read-only) 5494 * - couldn't import dependents (repository read-only) 5495 * EACCES - couldn't create temporary instance (backend access denied) 5496 * - couldn't import into temporary instance (backend access denied) 5497 * - couldn't upgrade properties (backend access denied) 5498 * - couldn't import properties (backend access denied) 5499 * - couldn't import dependents (backend access denied) 5500 * EINVAL - invalid instance name (error printed) 5501 * - invalid pgroup_t's (error printed) 5502 * - invalid dependents (error printed) 5503 * EBUSY - temporary service deleted (error printed) 5504 * - temporary instance deleted (error printed) 5505 * - temporary instance changed (error printed) 5506 * - temporary instance already exists (error printed) 5507 * - instance deleted (error printed) 5508 * EBADF - instance has corrupt last-import snapshot (error printed) 5509 * - instance is corrupt (error printed) 5510 * - dependent has corrupt pg (error printed) 5511 * - dependent target has a corrupt snapshot (error printed) 5512 * -1 - unknown libscf error (error printed) 5513 */ 5514 static int 5515 lscf_instance_import(void *v, void *pvt) 5516 { 5517 entity_t *inst = v; 5518 scf_callback_t ctx; 5519 scf_callback_t *lcbdata = pvt; 5520 scf_service_t *rsvc = lcbdata->sc_parent; 5521 int r; 5522 scf_snaplevel_t *running; 5523 int flags = lcbdata->sc_flags; 5524 5525 const char * const emsg_tdel = 5526 gettext("Temporary instance svc:/%s:%s was deleted.\n"); 5527 const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s " 5528 "changed unexpectedly.\n"); 5529 const char * const emsg_del = gettext("%s changed unexpectedly " 5530 "(instance \"%s\" was deleted.)\n"); 5531 const char * const emsg_badsnap = gettext( 5532 "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n"); 5533 5534 /* 5535 * prepare last-import snapshot: 5536 * create temporary instance (service was precreated) 5537 * populate with properties from bundle 5538 * take snapshot 5539 */ 5540 if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) { 5541 switch (scf_error()) { 5542 case SCF_ERROR_CONNECTION_BROKEN: 5543 case SCF_ERROR_NO_RESOURCES: 5544 case SCF_ERROR_BACKEND_READONLY: 5545 case SCF_ERROR_BACKEND_ACCESS: 5546 return (stash_scferror(lcbdata)); 5547 5548 case SCF_ERROR_EXISTS: 5549 warn(gettext("Temporary service svc:/%s " 5550 "changed unexpectedly (instance \"%s\" added).\n"), 5551 imp_tsname, inst->sc_name); 5552 lcbdata->sc_err = EBUSY; 5553 return (UU_WALK_ERROR); 5554 5555 case SCF_ERROR_DELETED: 5556 warn(gettext("Temporary service svc:/%s " 5557 "was deleted unexpectedly.\n"), imp_tsname); 5558 lcbdata->sc_err = EBUSY; 5559 return (UU_WALK_ERROR); 5560 5561 case SCF_ERROR_INVALID_ARGUMENT: 5562 warn(gettext("Invalid instance name \"%s\".\n"), 5563 inst->sc_name); 5564 return (stash_scferror(lcbdata)); 5565 5566 case SCF_ERROR_PERMISSION_DENIED: 5567 warn(gettext("Could not create temporary instance " 5568 "\"%s\" in svc:/%s (permission denied).\n"), 5569 inst->sc_name, imp_tsname); 5570 return (stash_scferror(lcbdata)); 5571 5572 case SCF_ERROR_HANDLE_MISMATCH: 5573 case SCF_ERROR_NOT_BOUND: 5574 case SCF_ERROR_NOT_SET: 5575 default: 5576 bad_error("scf_service_add_instance", scf_error()); 5577 } 5578 } 5579 5580 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname, 5581 inst->sc_name); 5582 if (r < 0) 5583 bad_error("snprintf", errno); 5584 5585 r = lscf_import_instance_pgs(imp_tinst, imp_str, inst, 5586 lcbdata->sc_flags | SCI_NOENABLED); 5587 switch (r) { 5588 case 0: 5589 break; 5590 5591 case ECANCELED: 5592 warn(emsg_tdel, imp_tsname, inst->sc_name); 5593 lcbdata->sc_err = EBUSY; 5594 r = UU_WALK_ERROR; 5595 goto deltemp; 5596 5597 case EEXIST: 5598 warn(emsg_tchg, imp_tsname, inst->sc_name); 5599 lcbdata->sc_err = EBUSY; 5600 r = UU_WALK_ERROR; 5601 goto deltemp; 5602 5603 case ECONNABORTED: 5604 goto connaborted; 5605 5606 case ENOMEM: 5607 case ENOSPC: 5608 case EPERM: 5609 case EROFS: 5610 case EACCES: 5611 case EINVAL: 5612 case EBUSY: 5613 lcbdata->sc_err = r; 5614 r = UU_WALK_ERROR; 5615 goto deltemp; 5616 5617 default: 5618 bad_error("lscf_import_instance_pgs", r); 5619 } 5620 5621 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname, 5622 inst->sc_name); 5623 if (r < 0) 5624 bad_error("snprintf", errno); 5625 5626 ctx.sc_handle = lcbdata->sc_handle; 5627 ctx.sc_parent = imp_tinst; 5628 ctx.sc_service = 0; 5629 ctx.sc_source_fmri = inst->sc_fmri; 5630 ctx.sc_target_fmri = imp_str; 5631 if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx, 5632 UU_DEFAULT) != 0) { 5633 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 5634 bad_error("uu_list_walk", uu_error()); 5635 5636 switch (ctx.sc_err) { 5637 case ECONNABORTED: 5638 goto connaborted; 5639 5640 case ECANCELED: 5641 warn(emsg_tdel, imp_tsname, inst->sc_name); 5642 lcbdata->sc_err = EBUSY; 5643 break; 5644 5645 case EEXIST: 5646 warn(emsg_tchg, imp_tsname, inst->sc_name); 5647 lcbdata->sc_err = EBUSY; 5648 break; 5649 5650 default: 5651 lcbdata->sc_err = ctx.sc_err; 5652 } 5653 r = UU_WALK_ERROR; 5654 goto deltemp; 5655 } 5656 5657 if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name, 5658 inst->sc_name, snap_lastimport, imp_tlisnap) != 0) { 5659 switch (scf_error()) { 5660 case SCF_ERROR_CONNECTION_BROKEN: 5661 goto connaborted; 5662 5663 case SCF_ERROR_NO_RESOURCES: 5664 r = stash_scferror(lcbdata); 5665 goto deltemp; 5666 5667 case SCF_ERROR_EXISTS: 5668 warn(emsg_tchg, imp_tsname, inst->sc_name); 5669 lcbdata->sc_err = EBUSY; 5670 r = UU_WALK_ERROR; 5671 goto deltemp; 5672 5673 case SCF_ERROR_PERMISSION_DENIED: 5674 warn(gettext("Could not take \"%s\" snapshot of %s " 5675 "(permission denied).\n"), snap_lastimport, 5676 imp_str); 5677 r = stash_scferror(lcbdata); 5678 goto deltemp; 5679 5680 default: 5681 scfwarn(); 5682 lcbdata->sc_err = -1; 5683 r = UU_WALK_ERROR; 5684 goto deltemp; 5685 5686 case SCF_ERROR_HANDLE_MISMATCH: 5687 case SCF_ERROR_INVALID_ARGUMENT: 5688 case SCF_ERROR_NOT_SET: 5689 bad_error("_scf_snapshot_take_new_named", scf_error()); 5690 } 5691 } 5692 5693 if (lcbdata->sc_flags & SCI_FRESH) 5694 goto fresh; 5695 5696 if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) { 5697 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 5698 imp_lisnap) != 0) { 5699 switch (scf_error()) { 5700 case SCF_ERROR_DELETED: 5701 warn(emsg_del, inst->sc_parent->sc_fmri, 5702 inst->sc_name); 5703 lcbdata->sc_err = EBUSY; 5704 r = UU_WALK_ERROR; 5705 goto deltemp; 5706 5707 case SCF_ERROR_NOT_FOUND: 5708 flags |= SCI_FORCE; 5709 goto nosnap; 5710 5711 case SCF_ERROR_CONNECTION_BROKEN: 5712 goto connaborted; 5713 5714 case SCF_ERROR_INVALID_ARGUMENT: 5715 case SCF_ERROR_HANDLE_MISMATCH: 5716 case SCF_ERROR_NOT_BOUND: 5717 case SCF_ERROR_NOT_SET: 5718 default: 5719 bad_error("scf_instance_get_snapshot", 5720 scf_error()); 5721 } 5722 } 5723 5724 /* upgrade */ 5725 5726 /* 5727 * compare new properties with last-import properties 5728 * upgrade current properties 5729 */ 5730 /* clear sc_sceen for pgs */ 5731 if (uu_list_walk(inst->sc_pgroups, clear_int, 5732 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 5733 0) 5734 bad_error("uu_list_walk", uu_error()); 5735 5736 r = get_snaplevel(imp_lisnap, 0, imp_snpl); 5737 switch (r) { 5738 case 0: 5739 break; 5740 5741 case ECONNABORTED: 5742 goto connaborted; 5743 5744 case ECANCELED: 5745 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name); 5746 lcbdata->sc_err = EBUSY; 5747 r = UU_WALK_ERROR; 5748 goto deltemp; 5749 5750 case ENOENT: 5751 warn(emsg_badsnap, snap_lastimport, inst->sc_fmri); 5752 lcbdata->sc_err = EBADF; 5753 r = UU_WALK_ERROR; 5754 goto deltemp; 5755 5756 default: 5757 bad_error("get_snaplevel", r); 5758 } 5759 5760 if (scf_instance_get_snapshot(imp_inst, snap_running, 5761 imp_rsnap) != 0) { 5762 switch (scf_error()) { 5763 case SCF_ERROR_DELETED: 5764 warn(emsg_del, inst->sc_parent->sc_fmri, 5765 inst->sc_name); 5766 lcbdata->sc_err = EBUSY; 5767 r = UU_WALK_ERROR; 5768 goto deltemp; 5769 5770 case SCF_ERROR_NOT_FOUND: 5771 break; 5772 5773 case SCF_ERROR_CONNECTION_BROKEN: 5774 goto connaborted; 5775 5776 case SCF_ERROR_INVALID_ARGUMENT: 5777 case SCF_ERROR_HANDLE_MISMATCH: 5778 case SCF_ERROR_NOT_BOUND: 5779 case SCF_ERROR_NOT_SET: 5780 default: 5781 bad_error("scf_instance_get_snapshot", 5782 scf_error()); 5783 } 5784 5785 running = NULL; 5786 } else { 5787 r = get_snaplevel(imp_rsnap, 0, imp_rsnpl); 5788 switch (r) { 5789 case 0: 5790 running = imp_rsnpl; 5791 break; 5792 5793 case ECONNABORTED: 5794 goto connaborted; 5795 5796 case ECANCELED: 5797 warn(emsg_del, inst->sc_parent->sc_fmri, 5798 inst->sc_name); 5799 lcbdata->sc_err = EBUSY; 5800 r = UU_WALK_ERROR; 5801 goto deltemp; 5802 5803 case ENOENT: 5804 warn(emsg_badsnap, snap_running, inst->sc_fmri); 5805 lcbdata->sc_err = EBADF; 5806 r = UU_WALK_ERROR; 5807 goto deltemp; 5808 5809 default: 5810 bad_error("get_snaplevel", r); 5811 } 5812 } 5813 5814 r = upgrade_props(imp_inst, running, imp_snpl, inst); 5815 switch (r) { 5816 case 0: 5817 break; 5818 5819 case ECANCELED: 5820 case ENODEV: 5821 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name); 5822 lcbdata->sc_err = EBUSY; 5823 r = UU_WALK_ERROR; 5824 goto deltemp; 5825 5826 case ECONNABORTED: 5827 goto connaborted; 5828 5829 case ENOMEM: 5830 case ENOSPC: 5831 case EBADF: 5832 case EBUSY: 5833 case EINVAL: 5834 case EPERM: 5835 case EROFS: 5836 case EACCES: 5837 case EEXIST: 5838 lcbdata->sc_err = r; 5839 r = UU_WALK_ERROR; 5840 goto deltemp; 5841 5842 default: 5843 bad_error("upgrade_props", r); 5844 } 5845 5846 inst->sc_import_state = IMPORT_PROP_DONE; 5847 } else { 5848 switch (scf_error()) { 5849 case SCF_ERROR_CONNECTION_BROKEN: 5850 goto connaborted; 5851 5852 case SCF_ERROR_NOT_FOUND: 5853 break; 5854 5855 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 5856 case SCF_ERROR_HANDLE_MISMATCH: 5857 case SCF_ERROR_NOT_BOUND: 5858 case SCF_ERROR_NOT_SET: 5859 default: 5860 bad_error("scf_service_get_instance", scf_error()); 5861 } 5862 5863 fresh: 5864 /* create instance */ 5865 if (scf_service_add_instance(rsvc, inst->sc_name, 5866 imp_inst) != 0) { 5867 switch (scf_error()) { 5868 case SCF_ERROR_CONNECTION_BROKEN: 5869 goto connaborted; 5870 5871 case SCF_ERROR_NO_RESOURCES: 5872 case SCF_ERROR_BACKEND_READONLY: 5873 case SCF_ERROR_BACKEND_ACCESS: 5874 r = stash_scferror(lcbdata); 5875 goto deltemp; 5876 5877 case SCF_ERROR_EXISTS: 5878 warn(gettext("%s changed unexpectedly " 5879 "(instance \"%s\" added).\n"), 5880 inst->sc_parent->sc_fmri, inst->sc_name); 5881 lcbdata->sc_err = EBUSY; 5882 r = UU_WALK_ERROR; 5883 goto deltemp; 5884 5885 case SCF_ERROR_PERMISSION_DENIED: 5886 warn(gettext("Could not create \"%s\" instance " 5887 "in %s (permission denied).\n"), 5888 inst->sc_name, inst->sc_parent->sc_fmri); 5889 r = stash_scferror(lcbdata); 5890 goto deltemp; 5891 5892 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 5893 case SCF_ERROR_HANDLE_MISMATCH: 5894 case SCF_ERROR_NOT_BOUND: 5895 case SCF_ERROR_NOT_SET: 5896 default: 5897 bad_error("scf_service_add_instance", 5898 scf_error()); 5899 } 5900 } 5901 5902 nosnap: 5903 /* 5904 * Create a last-import snapshot to serve as an attachment 5905 * point for the real one from the temporary instance. Since 5906 * the contents is irrelevant, take it now, while the instance 5907 * is empty, to minimize svc.configd's work. 5908 */ 5909 if (_scf_snapshot_take_new(imp_inst, snap_lastimport, 5910 imp_lisnap) != 0) { 5911 switch (scf_error()) { 5912 case SCF_ERROR_CONNECTION_BROKEN: 5913 goto connaborted; 5914 5915 case SCF_ERROR_NO_RESOURCES: 5916 r = stash_scferror(lcbdata); 5917 goto deltemp; 5918 5919 case SCF_ERROR_EXISTS: 5920 warn(gettext("%s changed unexpectedly " 5921 "(snapshot \"%s\" added).\n"), 5922 inst->sc_fmri, snap_lastimport); 5923 lcbdata->sc_err = EBUSY; 5924 r = UU_WALK_ERROR; 5925 goto deltemp; 5926 5927 case SCF_ERROR_PERMISSION_DENIED: 5928 warn(gettext("Could not take \"%s\" snapshot " 5929 "of %s (permission denied).\n"), 5930 snap_lastimport, inst->sc_fmri); 5931 r = stash_scferror(lcbdata); 5932 goto deltemp; 5933 5934 default: 5935 scfwarn(); 5936 lcbdata->sc_err = -1; 5937 r = UU_WALK_ERROR; 5938 goto deltemp; 5939 5940 case SCF_ERROR_NOT_SET: 5941 case SCF_ERROR_INTERNAL: 5942 case SCF_ERROR_INVALID_ARGUMENT: 5943 case SCF_ERROR_HANDLE_MISMATCH: 5944 bad_error("_scf_snapshot_take_new", 5945 scf_error()); 5946 } 5947 } 5948 5949 if (li_only) 5950 goto lionly; 5951 5952 inst->sc_import_state = IMPORT_PROP_BEGUN; 5953 5954 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst, 5955 flags); 5956 switch (r) { 5957 case 0: 5958 break; 5959 5960 case ECONNABORTED: 5961 goto connaborted; 5962 5963 case ECANCELED: 5964 warn(gettext("%s changed unexpectedly " 5965 "(instance \"%s\" deleted).\n"), 5966 inst->sc_parent->sc_fmri, inst->sc_name); 5967 lcbdata->sc_err = EBUSY; 5968 r = UU_WALK_ERROR; 5969 goto deltemp; 5970 5971 case EEXIST: 5972 warn(gettext("%s changed unexpectedly " 5973 "(property group added).\n"), inst->sc_fmri); 5974 lcbdata->sc_err = EBUSY; 5975 r = UU_WALK_ERROR; 5976 goto deltemp; 5977 5978 default: 5979 lcbdata->sc_err = r; 5980 r = UU_WALK_ERROR; 5981 goto deltemp; 5982 5983 case EINVAL: /* caught above */ 5984 bad_error("lscf_import_instance_pgs", r); 5985 } 5986 5987 ctx.sc_parent = imp_inst; 5988 ctx.sc_service = 0; 5989 ctx.sc_trans = NULL; 5990 if (uu_list_walk(inst->sc_dependents, lscf_dependent_import, 5991 &ctx, UU_DEFAULT) != 0) { 5992 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 5993 bad_error("uu_list_walk", uu_error()); 5994 5995 if (ctx.sc_err == ECONNABORTED) 5996 goto connaborted; 5997 lcbdata->sc_err = ctx.sc_err; 5998 r = UU_WALK_ERROR; 5999 goto deltemp; 6000 } 6001 6002 inst->sc_import_state = IMPORT_PROP_DONE; 6003 6004 if (g_verbose) 6005 warn(gettext("Taking \"%s\" snapshot for %s.\n"), 6006 snap_initial, inst->sc_fmri); 6007 r = take_snap(imp_inst, snap_initial, imp_snap); 6008 switch (r) { 6009 case 0: 6010 break; 6011 6012 case ECONNABORTED: 6013 goto connaborted; 6014 6015 case ENOSPC: 6016 case -1: 6017 lcbdata->sc_err = r; 6018 r = UU_WALK_ERROR; 6019 goto deltemp; 6020 6021 case ECANCELED: 6022 warn(gettext("%s changed unexpectedly " 6023 "(instance %s deleted).\n"), 6024 inst->sc_parent->sc_fmri, inst->sc_name); 6025 lcbdata->sc_err = r; 6026 r = UU_WALK_ERROR; 6027 goto deltemp; 6028 6029 case EPERM: 6030 warn(emsg_snap_perm, snap_initial, inst->sc_fmri); 6031 lcbdata->sc_err = r; 6032 r = UU_WALK_ERROR; 6033 goto deltemp; 6034 6035 default: 6036 bad_error("take_snap", r); 6037 } 6038 } 6039 6040 lionly: 6041 if (lcbdata->sc_flags & SCI_NOSNAP) 6042 goto deltemp; 6043 6044 /* transfer snapshot from temporary instance */ 6045 if (g_verbose) 6046 warn(gettext("Taking \"%s\" snapshot for %s.\n"), 6047 snap_lastimport, inst->sc_fmri); 6048 if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) { 6049 switch (scf_error()) { 6050 case SCF_ERROR_CONNECTION_BROKEN: 6051 goto connaborted; 6052 6053 case SCF_ERROR_NO_RESOURCES: 6054 r = stash_scferror(lcbdata); 6055 goto deltemp; 6056 6057 case SCF_ERROR_PERMISSION_DENIED: 6058 warn(gettext("Could not take \"%s\" snapshot for %s " 6059 "(permission denied).\n"), snap_lastimport, 6060 inst->sc_fmri); 6061 r = stash_scferror(lcbdata); 6062 goto deltemp; 6063 6064 case SCF_ERROR_NOT_SET: 6065 case SCF_ERROR_HANDLE_MISMATCH: 6066 default: 6067 bad_error("_scf_snapshot_attach", scf_error()); 6068 } 6069 } 6070 6071 inst->sc_import_state = IMPORT_COMPLETE; 6072 6073 r = UU_WALK_NEXT; 6074 6075 deltemp: 6076 /* delete temporary instance */ 6077 if (scf_instance_delete(imp_tinst) != 0) { 6078 switch (scf_error()) { 6079 case SCF_ERROR_DELETED: 6080 break; 6081 6082 case SCF_ERROR_CONNECTION_BROKEN: 6083 goto connaborted; 6084 6085 case SCF_ERROR_NOT_SET: 6086 case SCF_ERROR_NOT_BOUND: 6087 default: 6088 bad_error("scf_instance_delete", scf_error()); 6089 } 6090 } 6091 6092 return (r); 6093 6094 connaborted: 6095 warn(gettext("Could not delete svc:/%s:%s " 6096 "(repository connection broken).\n"), imp_tsname, inst->sc_name); 6097 lcbdata->sc_err = ECONNABORTED; 6098 return (UU_WALK_ERROR); 6099 } 6100 6101 /* 6102 * If the service is missing, create it, import its properties, and import the 6103 * instances. Since the service is brand new, it should be empty, and if we 6104 * run into any existing entities (SCF_ERROR_EXISTS), abort. 6105 * 6106 * If the service exists, we want to upgrade its properties and import the 6107 * instances. Upgrade requires a last-import snapshot, though, which are 6108 * children of instances, so first we'll have to go through the instances 6109 * looking for a last-import snapshot. If we don't find one then we'll just 6110 * override-import the service properties (but don't delete existing 6111 * properties: another service might have declared us as a dependent). Before 6112 * we change anything, though, we want to take the previous snapshots. We 6113 * also give lscf_instance_import() a leg up on taking last-import snapshots 6114 * by importing the manifest's service properties into a temporary service. 6115 * 6116 * On success, returns UU_WALK_NEXT. On failure, returns UU_WALK_ERROR and 6117 * sets lcbdata->sc_err to 6118 * ECONNABORTED - repository connection broken 6119 * ENOMEM - out of memory 6120 * ENOSPC - svc.configd is out of resources 6121 * EPERM - couldn't create temporary service (error printed) 6122 * - couldn't import into temp service (error printed) 6123 * - couldn't create service (error printed) 6124 * - couldn't import dependent (error printed) 6125 * - couldn't take snapshot (error printed) 6126 * - couldn't create instance (error printed) 6127 * - couldn't create, modify, or delete pg (error printed) 6128 * - couldn't create, modify, or delete dependent (error printed) 6129 * - couldn't import instance (error printed) 6130 * EROFS - couldn't create temporary service (repository read-only) 6131 * - couldn't import into temporary service (repository read-only) 6132 * - couldn't create service (repository read-only) 6133 * - couldn't import dependent (repository read-only) 6134 * - couldn't create instance (repository read-only) 6135 * - couldn't create, modify, or delete pg or dependent 6136 * - couldn't import instance (repository read-only) 6137 * EACCES - couldn't create temporary service (backend access denied) 6138 * - couldn't import into temporary service (backend access denied) 6139 * - couldn't create service (backend access denied) 6140 * - couldn't import dependent (backend access denied) 6141 * - couldn't create instance (backend access denied) 6142 * - couldn't create, modify, or delete pg or dependent 6143 * - couldn't import instance (backend access denied) 6144 * EINVAL - service name is invalid (error printed) 6145 * - service name is too long (error printed) 6146 * - s has invalid pgroup (error printed) 6147 * - s has invalid dependent (error printed) 6148 * - instance name is invalid (error printed) 6149 * - instance entity_t is invalid (error printed) 6150 * EEXIST - couldn't create temporary service (already exists) (error printed) 6151 * - couldn't import dependent (dependency pg already exists) (printed) 6152 * - dependency collision in dependent service (error printed) 6153 * EBUSY - temporary service deleted (error printed) 6154 * - property group added to temporary service (error printed) 6155 * - new property group changed or was deleted (error printed) 6156 * - service was added unexpectedly (error printed) 6157 * - service was deleted unexpectedly (error printed) 6158 * - property group added to new service (error printed) 6159 * - instance added unexpectedly (error printed) 6160 * - instance deleted unexpectedly (error printed) 6161 * - dependent service deleted unexpectedly (error printed) 6162 * - pg was added, changed, or deleted (error printed) 6163 * - dependent pg changed (error printed) 6164 * - temporary instance added, changed, or deleted (error printed) 6165 * EBADF - a last-import snapshot is corrupt (error printed) 6166 * - the service is corrupt (error printed) 6167 * - a dependent is corrupt (error printed) 6168 * - an instance is corrupt (error printed) 6169 * - an instance has a corrupt last-import snapshot (error printed) 6170 * - dependent target has a corrupt snapshot (error printed) 6171 * -1 - unknown libscf error (error printed) 6172 */ 6173 static int 6174 lscf_service_import(void *v, void *pvt) 6175 { 6176 entity_t *s = v; 6177 scf_callback_t cbdata; 6178 scf_callback_t *lcbdata = pvt; 6179 scf_scope_t *scope = lcbdata->sc_parent; 6180 entity_t *inst, linst; 6181 int r; 6182 int fresh = 0; 6183 scf_snaplevel_t *running; 6184 int have_ge; 6185 6186 const char * const ts_deleted = gettext("Temporary service svc:/%s " 6187 "was deleted unexpectedly.\n"); 6188 const char * const ts_pg_added = gettext("Temporary service svc:/%s " 6189 "changed unexpectedly (property group added).\n"); 6190 const char * const s_deleted = 6191 gettext("%s was deleted unexpectedly.\n"); 6192 const char * const i_deleted = 6193 gettext("%s changed unexpectedly (instance \"%s\" deleted).\n"); 6194 const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s " 6195 "is corrupt (missing service snaplevel).\n"); 6196 6197 /* Validate the service name */ 6198 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) { 6199 switch (scf_error()) { 6200 case SCF_ERROR_CONNECTION_BROKEN: 6201 return (stash_scferror(lcbdata)); 6202 6203 case SCF_ERROR_INVALID_ARGUMENT: 6204 warn(gettext("\"%s\" is an invalid service name. " 6205 "Cannot import.\n"), s->sc_name); 6206 return (stash_scferror(lcbdata)); 6207 6208 case SCF_ERROR_NOT_FOUND: 6209 break; 6210 6211 case SCF_ERROR_HANDLE_MISMATCH: 6212 case SCF_ERROR_NOT_BOUND: 6213 case SCF_ERROR_NOT_SET: 6214 default: 6215 bad_error("scf_scope_get_service", scf_error()); 6216 } 6217 } 6218 6219 /* create temporary service */ 6220 /* 6221 * the size of the buffer was reduced to max_scf_name_len to prevent 6222 * hitting bug 6681151. After the bug fix, the size of the buffer 6223 * should be restored to its original value (max_scf_name_len +1) 6224 */ 6225 r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name); 6226 if (r < 0) 6227 bad_error("snprintf", errno); 6228 if (r > max_scf_name_len) { 6229 warn(gettext( 6230 "Service name \"%s\" is too long. Cannot import.\n"), 6231 s->sc_name); 6232 lcbdata->sc_err = EINVAL; 6233 return (UU_WALK_ERROR); 6234 } 6235 6236 if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) { 6237 switch (scf_error()) { 6238 case SCF_ERROR_CONNECTION_BROKEN: 6239 case SCF_ERROR_NO_RESOURCES: 6240 case SCF_ERROR_BACKEND_READONLY: 6241 case SCF_ERROR_BACKEND_ACCESS: 6242 return (stash_scferror(lcbdata)); 6243 6244 case SCF_ERROR_EXISTS: 6245 warn(gettext( 6246 "Temporary service \"%s\" must be deleted before " 6247 "this manifest can be imported.\n"), imp_tsname); 6248 return (stash_scferror(lcbdata)); 6249 6250 case SCF_ERROR_PERMISSION_DENIED: 6251 warn(gettext("Could not create temporary service " 6252 "\"%s\" (permission denied).\n"), imp_tsname); 6253 return (stash_scferror(lcbdata)); 6254 6255 case SCF_ERROR_INVALID_ARGUMENT: 6256 case SCF_ERROR_HANDLE_MISMATCH: 6257 case SCF_ERROR_NOT_BOUND: 6258 case SCF_ERROR_NOT_SET: 6259 default: 6260 bad_error("scf_scope_add_service", scf_error()); 6261 } 6262 } 6263 6264 r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname); 6265 if (r < 0) 6266 bad_error("snprintf", errno); 6267 6268 cbdata.sc_handle = lcbdata->sc_handle; 6269 cbdata.sc_parent = imp_tsvc; 6270 cbdata.sc_service = 1; 6271 cbdata.sc_source_fmri = s->sc_fmri; 6272 cbdata.sc_target_fmri = imp_str; 6273 cbdata.sc_flags = 0; 6274 6275 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata, 6276 UU_DEFAULT) != 0) { 6277 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6278 bad_error("uu_list_walk", uu_error()); 6279 6280 lcbdata->sc_err = cbdata.sc_err; 6281 switch (cbdata.sc_err) { 6282 case ECONNABORTED: 6283 goto connaborted; 6284 6285 case ECANCELED: 6286 warn(ts_deleted, imp_tsname); 6287 lcbdata->sc_err = EBUSY; 6288 return (UU_WALK_ERROR); 6289 6290 case EEXIST: 6291 warn(ts_pg_added, imp_tsname); 6292 lcbdata->sc_err = EBUSY; 6293 return (UU_WALK_ERROR); 6294 } 6295 6296 r = UU_WALK_ERROR; 6297 goto deltemp; 6298 } 6299 6300 if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata, 6301 UU_DEFAULT) != 0) { 6302 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6303 bad_error("uu_list_walk", uu_error()); 6304 6305 lcbdata->sc_err = cbdata.sc_err; 6306 switch (cbdata.sc_err) { 6307 case ECONNABORTED: 6308 goto connaborted; 6309 6310 case ECANCELED: 6311 warn(ts_deleted, imp_tsname); 6312 lcbdata->sc_err = EBUSY; 6313 return (UU_WALK_ERROR); 6314 6315 case EEXIST: 6316 warn(ts_pg_added, imp_tsname); 6317 lcbdata->sc_err = EBUSY; 6318 return (UU_WALK_ERROR); 6319 } 6320 6321 r = UU_WALK_ERROR; 6322 goto deltemp; 6323 } 6324 6325 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) { 6326 switch (scf_error()) { 6327 case SCF_ERROR_NOT_FOUND: 6328 break; 6329 6330 case SCF_ERROR_CONNECTION_BROKEN: 6331 goto connaborted; 6332 6333 case SCF_ERROR_INVALID_ARGUMENT: 6334 case SCF_ERROR_HANDLE_MISMATCH: 6335 case SCF_ERROR_NOT_BOUND: 6336 case SCF_ERROR_NOT_SET: 6337 default: 6338 bad_error("scf_scope_get_service", scf_error()); 6339 } 6340 6341 if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) { 6342 switch (scf_error()) { 6343 case SCF_ERROR_CONNECTION_BROKEN: 6344 goto connaborted; 6345 6346 case SCF_ERROR_NO_RESOURCES: 6347 case SCF_ERROR_BACKEND_READONLY: 6348 case SCF_ERROR_BACKEND_ACCESS: 6349 r = stash_scferror(lcbdata); 6350 goto deltemp; 6351 6352 case SCF_ERROR_EXISTS: 6353 warn(gettext("Scope \"%s\" changed unexpectedly" 6354 " (service \"%s\" added).\n"), 6355 SCF_SCOPE_LOCAL, s->sc_name); 6356 lcbdata->sc_err = EBUSY; 6357 goto deltemp; 6358 6359 case SCF_ERROR_PERMISSION_DENIED: 6360 warn(gettext("Could not create service \"%s\" " 6361 "(permission denied).\n"), s->sc_name); 6362 goto deltemp; 6363 6364 case SCF_ERROR_INVALID_ARGUMENT: 6365 case SCF_ERROR_HANDLE_MISMATCH: 6366 case SCF_ERROR_NOT_BOUND: 6367 case SCF_ERROR_NOT_SET: 6368 default: 6369 bad_error("scf_scope_add_service", scf_error()); 6370 } 6371 } 6372 6373 s->sc_import_state = IMPORT_PROP_BEGUN; 6374 6375 /* import service properties */ 6376 cbdata.sc_handle = lcbdata->sc_handle; 6377 cbdata.sc_parent = imp_svc; 6378 cbdata.sc_service = 1; 6379 cbdata.sc_flags = lcbdata->sc_flags; 6380 cbdata.sc_source_fmri = s->sc_fmri; 6381 cbdata.sc_target_fmri = s->sc_fmri; 6382 6383 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, 6384 &cbdata, UU_DEFAULT) != 0) { 6385 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6386 bad_error("uu_list_walk", uu_error()); 6387 6388 lcbdata->sc_err = cbdata.sc_err; 6389 switch (cbdata.sc_err) { 6390 case ECONNABORTED: 6391 goto connaborted; 6392 6393 case ECANCELED: 6394 warn(s_deleted, s->sc_fmri); 6395 lcbdata->sc_err = EBUSY; 6396 return (UU_WALK_ERROR); 6397 6398 case EEXIST: 6399 warn(gettext("%s changed unexpectedly " 6400 "(property group added).\n"), s->sc_fmri); 6401 lcbdata->sc_err = EBUSY; 6402 return (UU_WALK_ERROR); 6403 6404 case EINVAL: 6405 /* caught above */ 6406 bad_error("entity_pgroup_import", 6407 cbdata.sc_err); 6408 } 6409 6410 r = UU_WALK_ERROR; 6411 goto deltemp; 6412 } 6413 6414 cbdata.sc_trans = NULL; 6415 if (uu_list_walk(s->sc_dependents, lscf_dependent_import, 6416 &cbdata, UU_DEFAULT) != 0) { 6417 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6418 bad_error("uu_list_walk", uu_error()); 6419 6420 lcbdata->sc_err = cbdata.sc_err; 6421 if (cbdata.sc_err == ECONNABORTED) 6422 goto connaborted; 6423 r = UU_WALK_ERROR; 6424 goto deltemp; 6425 } 6426 6427 s->sc_import_state = IMPORT_PROP_DONE; 6428 6429 /* 6430 * This is a new service, so we can't take previous snapshots 6431 * or upgrade service properties. 6432 */ 6433 fresh = 1; 6434 goto instances; 6435 } 6436 6437 /* Clear sc_seen for the instances. */ 6438 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int, 6439 (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0) 6440 bad_error("uu_list_walk", uu_error()); 6441 6442 /* 6443 * Take previous snapshots for all instances. Even for ones not 6444 * mentioned in the bundle, since we might change their service 6445 * properties. 6446 */ 6447 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) { 6448 switch (scf_error()) { 6449 case SCF_ERROR_CONNECTION_BROKEN: 6450 goto connaborted; 6451 6452 case SCF_ERROR_DELETED: 6453 warn(s_deleted, s->sc_fmri); 6454 lcbdata->sc_err = EBUSY; 6455 r = UU_WALK_ERROR; 6456 goto deltemp; 6457 6458 case SCF_ERROR_HANDLE_MISMATCH: 6459 case SCF_ERROR_NOT_BOUND: 6460 case SCF_ERROR_NOT_SET: 6461 default: 6462 bad_error("scf_iter_service_instances", scf_error()); 6463 } 6464 } 6465 6466 for (;;) { 6467 r = scf_iter_next_instance(imp_iter, imp_inst); 6468 if (r == 0) 6469 break; 6470 if (r != 1) { 6471 switch (scf_error()) { 6472 case SCF_ERROR_DELETED: 6473 warn(s_deleted, s->sc_fmri); 6474 lcbdata->sc_err = EBUSY; 6475 r = UU_WALK_ERROR; 6476 goto deltemp; 6477 6478 case SCF_ERROR_CONNECTION_BROKEN: 6479 goto connaborted; 6480 6481 case SCF_ERROR_NOT_BOUND: 6482 case SCF_ERROR_HANDLE_MISMATCH: 6483 case SCF_ERROR_INVALID_ARGUMENT: 6484 case SCF_ERROR_NOT_SET: 6485 default: 6486 bad_error("scf_iter_next_instance", 6487 scf_error()); 6488 } 6489 } 6490 6491 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) { 6492 switch (scf_error()) { 6493 case SCF_ERROR_DELETED: 6494 continue; 6495 6496 case SCF_ERROR_CONNECTION_BROKEN: 6497 goto connaborted; 6498 6499 case SCF_ERROR_NOT_SET: 6500 case SCF_ERROR_NOT_BOUND: 6501 default: 6502 bad_error("scf_instance_get_name", scf_error()); 6503 } 6504 } 6505 6506 if (g_verbose) 6507 warn(gettext( 6508 "Taking \"%s\" snapshot for svc:/%s:%s.\n"), 6509 snap_previous, s->sc_name, imp_str); 6510 6511 r = take_snap(imp_inst, snap_previous, imp_snap); 6512 switch (r) { 6513 case 0: 6514 break; 6515 6516 case ECANCELED: 6517 continue; 6518 6519 case ECONNABORTED: 6520 goto connaborted; 6521 6522 case EPERM: 6523 warn(gettext("Could not take \"%s\" snapshot of " 6524 "svc:/%s:%s (permission denied).\n"), 6525 snap_previous, s->sc_name, imp_str); 6526 lcbdata->sc_err = r; 6527 return (UU_WALK_ERROR); 6528 6529 case ENOSPC: 6530 case -1: 6531 lcbdata->sc_err = r; 6532 r = UU_WALK_ERROR; 6533 goto deltemp; 6534 6535 default: 6536 bad_error("take_snap", r); 6537 } 6538 6539 linst.sc_name = imp_str; 6540 inst = uu_list_find(s->sc_u.sc_service.sc_service_instances, 6541 &linst, NULL, NULL); 6542 if (inst != NULL) { 6543 inst->sc_import_state = IMPORT_PREVIOUS; 6544 inst->sc_seen = 1; 6545 } 6546 } 6547 6548 /* 6549 * Create the new instances and take previous snapshots of 6550 * them. This is not necessary, but it maximizes data preservation. 6551 */ 6552 for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances); 6553 inst != NULL; 6554 inst = uu_list_next(s->sc_u.sc_service.sc_service_instances, 6555 inst)) { 6556 if (inst->sc_seen) 6557 continue; 6558 6559 if (scf_service_add_instance(imp_svc, inst->sc_name, 6560 imp_inst) != 0) { 6561 switch (scf_error()) { 6562 case SCF_ERROR_CONNECTION_BROKEN: 6563 goto connaborted; 6564 6565 case SCF_ERROR_BACKEND_READONLY: 6566 case SCF_ERROR_BACKEND_ACCESS: 6567 case SCF_ERROR_NO_RESOURCES: 6568 r = stash_scferror(lcbdata); 6569 goto deltemp; 6570 6571 case SCF_ERROR_EXISTS: 6572 warn(gettext("%s changed unexpectedly " 6573 "(instance \"%s\" added).\n"), s->sc_fmri, 6574 inst->sc_name); 6575 lcbdata->sc_err = EBUSY; 6576 r = UU_WALK_ERROR; 6577 goto deltemp; 6578 6579 case SCF_ERROR_INVALID_ARGUMENT: 6580 warn(gettext("Service \"%s\" has instance with " 6581 "invalid name \"%s\".\n"), s->sc_name, 6582 inst->sc_name); 6583 r = stash_scferror(lcbdata); 6584 goto deltemp; 6585 6586 case SCF_ERROR_PERMISSION_DENIED: 6587 warn(gettext("Could not create instance \"%s\" " 6588 "in %s (permission denied).\n"), 6589 inst->sc_name, s->sc_fmri); 6590 r = stash_scferror(lcbdata); 6591 goto deltemp; 6592 6593 case SCF_ERROR_HANDLE_MISMATCH: 6594 case SCF_ERROR_NOT_BOUND: 6595 case SCF_ERROR_NOT_SET: 6596 default: 6597 bad_error("scf_service_add_instance", 6598 scf_error()); 6599 } 6600 } 6601 6602 if (g_verbose) 6603 warn(gettext("Taking \"%s\" snapshot for " 6604 "new service %s.\n"), snap_previous, inst->sc_fmri); 6605 r = take_snap(imp_inst, snap_previous, imp_snap); 6606 switch (r) { 6607 case 0: 6608 break; 6609 6610 case ECANCELED: 6611 warn(i_deleted, s->sc_fmri, inst->sc_name); 6612 lcbdata->sc_err = EBUSY; 6613 r = UU_WALK_ERROR; 6614 goto deltemp; 6615 6616 case ECONNABORTED: 6617 goto connaborted; 6618 6619 case EPERM: 6620 warn(emsg_snap_perm, snap_previous, inst->sc_fmri); 6621 lcbdata->sc_err = r; 6622 r = UU_WALK_ERROR; 6623 goto deltemp; 6624 6625 case ENOSPC: 6626 case -1: 6627 r = UU_WALK_ERROR; 6628 goto deltemp; 6629 6630 default: 6631 bad_error("take_snap", r); 6632 } 6633 } 6634 6635 s->sc_import_state = IMPORT_PREVIOUS; 6636 6637 /* 6638 * Upgrade service properties, if we can find a last-import snapshot. 6639 * Any will do because we don't support different service properties 6640 * in different manifests, so all snaplevels of the service in all of 6641 * the last-import snapshots of the instances should be the same. 6642 */ 6643 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) { 6644 switch (scf_error()) { 6645 case SCF_ERROR_CONNECTION_BROKEN: 6646 goto connaborted; 6647 6648 case SCF_ERROR_DELETED: 6649 warn(s_deleted, s->sc_fmri); 6650 lcbdata->sc_err = EBUSY; 6651 r = UU_WALK_ERROR; 6652 goto deltemp; 6653 6654 case SCF_ERROR_HANDLE_MISMATCH: 6655 case SCF_ERROR_NOT_BOUND: 6656 case SCF_ERROR_NOT_SET: 6657 default: 6658 bad_error("scf_iter_service_instances", scf_error()); 6659 } 6660 } 6661 6662 have_ge = 0; 6663 li_only = 0; 6664 6665 for (;;) { 6666 r = scf_iter_next_instance(imp_iter, imp_inst); 6667 if (r == -1) { 6668 switch (scf_error()) { 6669 case SCF_ERROR_DELETED: 6670 warn(s_deleted, s->sc_fmri); 6671 lcbdata->sc_err = EBUSY; 6672 r = UU_WALK_ERROR; 6673 goto deltemp; 6674 6675 case SCF_ERROR_CONNECTION_BROKEN: 6676 goto connaborted; 6677 6678 case SCF_ERROR_NOT_BOUND: 6679 case SCF_ERROR_HANDLE_MISMATCH: 6680 case SCF_ERROR_INVALID_ARGUMENT: 6681 case SCF_ERROR_NOT_SET: 6682 default: 6683 bad_error("scf_iter_next_instance", 6684 scf_error()); 6685 } 6686 } 6687 6688 if (r == 0) { 6689 /* 6690 * Didn't find any last-import snapshots. Override- 6691 * import the properties. Unless one of the instances 6692 * has a general/enabled property, in which case we're 6693 * probably running a last-import-capable svccfg for 6694 * the first time, and we should only take the 6695 * last-import snapshot. 6696 */ 6697 if (have_ge) { 6698 li_only = 1; 6699 no_refresh = 1; 6700 break; 6701 } 6702 6703 s->sc_import_state = IMPORT_PROP_BEGUN; 6704 6705 cbdata.sc_handle = g_hndl; 6706 cbdata.sc_parent = imp_svc; 6707 cbdata.sc_service = 1; 6708 cbdata.sc_flags = SCI_FORCE; 6709 cbdata.sc_source_fmri = s->sc_fmri; 6710 cbdata.sc_target_fmri = s->sc_fmri; 6711 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, 6712 &cbdata, UU_DEFAULT) != 0) { 6713 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6714 bad_error("uu_list_walk", uu_error()); 6715 lcbdata->sc_err = cbdata.sc_err; 6716 switch (cbdata.sc_err) { 6717 case ECONNABORTED: 6718 goto connaborted; 6719 6720 case ECANCELED: 6721 warn(s_deleted, s->sc_fmri); 6722 lcbdata->sc_err = EBUSY; 6723 break; 6724 6725 case EINVAL: /* caught above */ 6726 case EEXIST: 6727 bad_error("entity_pgroup_import", 6728 cbdata.sc_err); 6729 } 6730 6731 r = UU_WALK_ERROR; 6732 goto deltemp; 6733 } 6734 6735 cbdata.sc_trans = NULL; 6736 if (uu_list_walk(s->sc_dependents, 6737 lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) { 6738 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6739 bad_error("uu_list_walk", uu_error()); 6740 lcbdata->sc_err = cbdata.sc_err; 6741 if (cbdata.sc_err == ECONNABORTED) 6742 goto connaborted; 6743 r = UU_WALK_ERROR; 6744 goto deltemp; 6745 } 6746 break; 6747 } 6748 6749 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 6750 imp_snap) != 0) { 6751 switch (scf_error()) { 6752 case SCF_ERROR_DELETED: 6753 continue; 6754 6755 case SCF_ERROR_NOT_FOUND: 6756 break; 6757 6758 case SCF_ERROR_CONNECTION_BROKEN: 6759 goto connaborted; 6760 6761 case SCF_ERROR_HANDLE_MISMATCH: 6762 case SCF_ERROR_NOT_BOUND: 6763 case SCF_ERROR_INVALID_ARGUMENT: 6764 case SCF_ERROR_NOT_SET: 6765 default: 6766 bad_error("scf_instance_get_snapshot", 6767 scf_error()); 6768 } 6769 6770 if (have_ge) 6771 continue; 6772 6773 /* 6774 * Check for a general/enabled property. This is how 6775 * we tell whether to import if there turn out to be 6776 * no last-import snapshots. 6777 */ 6778 if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL, 6779 imp_pg) == 0) { 6780 if (scf_pg_get_property(imp_pg, 6781 SCF_PROPERTY_ENABLED, imp_prop) == 0) { 6782 have_ge = 1; 6783 } else { 6784 switch (scf_error()) { 6785 case SCF_ERROR_DELETED: 6786 case SCF_ERROR_NOT_FOUND: 6787 continue; 6788 6789 case SCF_ERROR_INVALID_ARGUMENT: 6790 case SCF_ERROR_HANDLE_MISMATCH: 6791 case SCF_ERROR_CONNECTION_BROKEN: 6792 case SCF_ERROR_NOT_BOUND: 6793 case SCF_ERROR_NOT_SET: 6794 default: 6795 bad_error("scf_pg_get_property", 6796 scf_error()); 6797 } 6798 } 6799 } else { 6800 switch (scf_error()) { 6801 case SCF_ERROR_DELETED: 6802 case SCF_ERROR_NOT_FOUND: 6803 continue; 6804 6805 case SCF_ERROR_CONNECTION_BROKEN: 6806 goto connaborted; 6807 6808 case SCF_ERROR_NOT_BOUND: 6809 case SCF_ERROR_NOT_SET: 6810 case SCF_ERROR_INVALID_ARGUMENT: 6811 case SCF_ERROR_HANDLE_MISMATCH: 6812 default: 6813 bad_error("scf_instance_get_pg", 6814 scf_error()); 6815 } 6816 } 6817 continue; 6818 } 6819 6820 /* find service snaplevel */ 6821 r = get_snaplevel(imp_snap, 1, imp_snpl); 6822 switch (r) { 6823 case 0: 6824 break; 6825 6826 case ECONNABORTED: 6827 goto connaborted; 6828 6829 case ECANCELED: 6830 continue; 6831 6832 case ENOENT: 6833 if (scf_instance_get_name(imp_inst, imp_str, 6834 imp_str_sz) < 0) 6835 (void) strcpy(imp_str, "?"); 6836 warn(badsnap, snap_lastimport, s->sc_name, imp_str); 6837 lcbdata->sc_err = EBADF; 6838 r = UU_WALK_ERROR; 6839 goto deltemp; 6840 6841 default: 6842 bad_error("get_snaplevel", r); 6843 } 6844 6845 if (scf_instance_get_snapshot(imp_inst, snap_running, 6846 imp_rsnap) != 0) { 6847 switch (scf_error()) { 6848 case SCF_ERROR_DELETED: 6849 continue; 6850 6851 case SCF_ERROR_NOT_FOUND: 6852 break; 6853 6854 case SCF_ERROR_CONNECTION_BROKEN: 6855 goto connaborted; 6856 6857 case SCF_ERROR_INVALID_ARGUMENT: 6858 case SCF_ERROR_HANDLE_MISMATCH: 6859 case SCF_ERROR_NOT_BOUND: 6860 case SCF_ERROR_NOT_SET: 6861 default: 6862 bad_error("scf_instance_get_snapshot", 6863 scf_error()); 6864 } 6865 running = NULL; 6866 } else { 6867 r = get_snaplevel(imp_rsnap, 1, imp_rsnpl); 6868 switch (r) { 6869 case 0: 6870 running = imp_rsnpl; 6871 break; 6872 6873 case ECONNABORTED: 6874 goto connaborted; 6875 6876 case ECANCELED: 6877 continue; 6878 6879 case ENOENT: 6880 if (scf_instance_get_name(imp_inst, imp_str, 6881 imp_str_sz) < 0) 6882 (void) strcpy(imp_str, "?"); 6883 warn(badsnap, snap_running, s->sc_name, 6884 imp_str); 6885 lcbdata->sc_err = EBADF; 6886 r = UU_WALK_ERROR; 6887 goto deltemp; 6888 6889 default: 6890 bad_error("get_snaplevel", r); 6891 } 6892 } 6893 6894 if (g_verbose) { 6895 if (scf_instance_get_name(imp_inst, imp_str, 6896 imp_str_sz) < 0) 6897 (void) strcpy(imp_str, "?"); 6898 warn(gettext("Upgrading properties of %s according to " 6899 "instance \"%s\".\n"), s->sc_fmri, imp_str); 6900 } 6901 6902 /* upgrade service properties */ 6903 r = upgrade_props(imp_svc, running, imp_snpl, s); 6904 if (r == 0) 6905 break; 6906 6907 switch (r) { 6908 case ECONNABORTED: 6909 goto connaborted; 6910 6911 case ECANCELED: 6912 warn(s_deleted, s->sc_fmri); 6913 lcbdata->sc_err = EBUSY; 6914 break; 6915 6916 case ENODEV: 6917 if (scf_instance_get_name(imp_inst, imp_str, 6918 imp_str_sz) < 0) 6919 (void) strcpy(imp_str, "?"); 6920 warn(i_deleted, s->sc_fmri, imp_str); 6921 lcbdata->sc_err = EBUSY; 6922 break; 6923 6924 default: 6925 lcbdata->sc_err = r; 6926 } 6927 6928 r = UU_WALK_ERROR; 6929 goto deltemp; 6930 } 6931 6932 s->sc_import_state = IMPORT_PROP_DONE; 6933 6934 instances: 6935 /* import instances */ 6936 cbdata.sc_handle = lcbdata->sc_handle; 6937 cbdata.sc_parent = imp_svc; 6938 cbdata.sc_service = 1; 6939 cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0); 6940 cbdata.sc_general = NULL; 6941 6942 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, 6943 lscf_instance_import, &cbdata, UU_DEFAULT) != 0) { 6944 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6945 bad_error("uu_list_walk", uu_error()); 6946 6947 lcbdata->sc_err = cbdata.sc_err; 6948 if (cbdata.sc_err == ECONNABORTED) 6949 goto connaborted; 6950 r = UU_WALK_ERROR; 6951 goto deltemp; 6952 } 6953 6954 s->sc_import_state = IMPORT_COMPLETE; 6955 r = UU_WALK_NEXT; 6956 6957 deltemp: 6958 /* delete temporary service */ 6959 if (scf_service_delete(imp_tsvc) != 0) { 6960 switch (scf_error()) { 6961 case SCF_ERROR_DELETED: 6962 break; 6963 6964 case SCF_ERROR_CONNECTION_BROKEN: 6965 goto connaborted; 6966 6967 case SCF_ERROR_EXISTS: 6968 warn(gettext( 6969 "Could not delete svc:/%s (instances exist).\n"), 6970 imp_tsname); 6971 break; 6972 6973 case SCF_ERROR_NOT_SET: 6974 case SCF_ERROR_NOT_BOUND: 6975 default: 6976 bad_error("scf_service_delete", scf_error()); 6977 } 6978 } 6979 6980 return (r); 6981 6982 connaborted: 6983 warn(gettext("Could not delete svc:/%s " 6984 "(repository connection broken).\n"), imp_tsname); 6985 lcbdata->sc_err = ECONNABORTED; 6986 return (UU_WALK_ERROR); 6987 } 6988 6989 static const char * 6990 import_progress(int st) 6991 { 6992 switch (st) { 6993 case 0: 6994 return (gettext("not reached.")); 6995 6996 case IMPORT_PREVIOUS: 6997 return (gettext("previous snapshot taken.")); 6998 6999 case IMPORT_PROP_BEGUN: 7000 return (gettext("some properties imported.")); 7001 7002 case IMPORT_PROP_DONE: 7003 return (gettext("properties imported.")); 7004 7005 case IMPORT_COMPLETE: 7006 return (gettext("imported.")); 7007 7008 case IMPORT_REFRESHED: 7009 return (gettext("refresh requested.")); 7010 7011 default: 7012 #ifndef NDEBUG 7013 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n", 7014 __FILE__, __LINE__, st); 7015 #endif 7016 abort(); 7017 /* NOTREACHED */ 7018 } 7019 } 7020 7021 /* 7022 * Returns 7023 * 0 - success 7024 * - fmri wasn't found (error printed) 7025 * - entity was deleted (error printed) 7026 * - backend denied access (error printed) 7027 * ENOMEM - out of memory (error printed) 7028 * ECONNABORTED - repository connection broken (error printed) 7029 * EPERM - permission denied (error printed) 7030 * -1 - unknown libscf error (error printed) 7031 */ 7032 static int 7033 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri) 7034 { 7035 scf_error_t serr; 7036 void *ent; 7037 int issvc; 7038 int r; 7039 7040 const char *deleted = gettext("Could not refresh %s (deleted).\n"); 7041 const char *dpt_deleted = gettext("Could not refresh %s " 7042 "(dependent \"%s\" of %s) (deleted).\n"); 7043 7044 serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc); 7045 switch (serr) { 7046 case SCF_ERROR_NONE: 7047 break; 7048 7049 case SCF_ERROR_NO_MEMORY: 7050 if (name == NULL) 7051 warn(gettext("Could not refresh %s (out of memory).\n"), 7052 fmri); 7053 else 7054 warn(gettext("Could not refresh %s " 7055 "(dependent \"%s\" of %s) (out of memory).\n"), 7056 fmri, name, d_fmri); 7057 return (ENOMEM); 7058 7059 case SCF_ERROR_NOT_FOUND: 7060 if (name == NULL) 7061 warn(deleted, fmri); 7062 else 7063 warn(dpt_deleted, fmri, name, d_fmri); 7064 return (0); 7065 7066 case SCF_ERROR_INVALID_ARGUMENT: 7067 case SCF_ERROR_CONSTRAINT_VIOLATED: 7068 default: 7069 bad_error("fmri_to_entity", serr); 7070 } 7071 7072 r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str); 7073 switch (r) { 7074 case 0: 7075 break; 7076 7077 case ECONNABORTED: 7078 if (name != NULL) 7079 warn(gettext("Could not refresh %s " 7080 "(dependent \"%s\" of %s) " 7081 "(repository connection broken).\n"), fmri, name, 7082 d_fmri); 7083 return (r); 7084 7085 case ECANCELED: 7086 if (name == NULL) 7087 warn(deleted, fmri); 7088 else 7089 warn(dpt_deleted, fmri, name, d_fmri); 7090 return (0); 7091 7092 case EACCES: 7093 if (!g_verbose) 7094 return (0); 7095 if (name == NULL) 7096 warn(gettext("Could not refresh %s " 7097 "(backend access denied).\n"), fmri); 7098 else 7099 warn(gettext("Could not refresh %s " 7100 "(dependent \"%s\" of %s) " 7101 "(backend access denied).\n"), fmri, name, d_fmri); 7102 return (0); 7103 7104 case EPERM: 7105 if (name == NULL) 7106 warn(gettext("Could not refresh %s " 7107 "(permission denied).\n"), fmri); 7108 else 7109 warn(gettext("Could not refresh %s " 7110 "(dependent \"%s\" of %s) " 7111 "(permission denied).\n"), fmri, name, d_fmri); 7112 return (r); 7113 7114 case ENOSPC: 7115 if (name == NULL) 7116 warn(gettext("Could not refresh %s " 7117 "(repository server out of resources).\n"), 7118 fmri); 7119 else 7120 warn(gettext("Could not refresh %s " 7121 "(dependent \"%s\" of %s) " 7122 "(repository server out of resources).\n"), 7123 fmri, name, d_fmri); 7124 return (r); 7125 7126 case -1: 7127 scfwarn(); 7128 return (r); 7129 7130 default: 7131 bad_error("refresh_entity", r); 7132 } 7133 7134 if (issvc) 7135 scf_service_destroy(ent); 7136 else 7137 scf_instance_destroy(ent); 7138 7139 return (0); 7140 } 7141 7142 int 7143 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags) 7144 { 7145 scf_callback_t cbdata; 7146 int result = 0; 7147 entity_t *svc, *inst; 7148 uu_list_t *insts; 7149 int r; 7150 pgroup_t *old_dpt; 7151 void *cookie; 7152 int annotation_set = 0; 7153 7154 const char * const emsg_nomem = gettext("Out of memory.\n"); 7155 const char * const emsg_nores = 7156 gettext("svc.configd is out of resources.\n"); 7157 7158 lscf_prep_hndl(); 7159 7160 imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ? 7161 max_scf_name_len : max_scf_fmri_len) + 1; 7162 7163 if ((imp_scope = scf_scope_create(g_hndl)) == NULL || 7164 (imp_svc = scf_service_create(g_hndl)) == NULL || 7165 (imp_tsvc = scf_service_create(g_hndl)) == NULL || 7166 (imp_inst = scf_instance_create(g_hndl)) == NULL || 7167 (imp_tinst = scf_instance_create(g_hndl)) == NULL || 7168 (imp_snap = scf_snapshot_create(g_hndl)) == NULL || 7169 (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL || 7170 (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL || 7171 (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL || 7172 (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL || 7173 (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL || 7174 (imp_pg = scf_pg_create(g_hndl)) == NULL || 7175 (imp_pg2 = scf_pg_create(g_hndl)) == NULL || 7176 (imp_prop = scf_property_create(g_hndl)) == NULL || 7177 (imp_iter = scf_iter_create(g_hndl)) == NULL || 7178 (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL || 7179 (imp_up_iter = scf_iter_create(g_hndl)) == NULL || 7180 (imp_tx = scf_transaction_create(g_hndl)) == NULL || 7181 (imp_str = malloc(imp_str_sz)) == NULL || 7182 (imp_tsname = malloc(max_scf_name_len + 1)) == NULL || 7183 (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL || 7184 (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL || 7185 (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL || 7186 (ud_inst = scf_instance_create(g_hndl)) == NULL || 7187 (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL || 7188 (ud_pg = scf_pg_create(g_hndl)) == NULL || 7189 (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL || 7190 (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL || 7191 (ud_prop = scf_property_create(g_hndl)) == NULL || 7192 (ud_dpt_prop = scf_property_create(g_hndl)) == NULL || 7193 (ud_val = scf_value_create(g_hndl)) == NULL || 7194 (ud_iter = scf_iter_create(g_hndl)) == NULL || 7195 (ud_iter2 = scf_iter_create(g_hndl)) == NULL || 7196 (ud_tx = scf_transaction_create(g_hndl)) == NULL || 7197 (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL || 7198 (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL || 7199 (ud_name = malloc(max_scf_name_len + 1)) == NULL) { 7200 if (scf_error() == SCF_ERROR_NO_RESOURCES) 7201 warn(emsg_nores); 7202 else 7203 warn(emsg_nomem); 7204 result = -1; 7205 goto out; 7206 } 7207 7208 r = load_init(); 7209 switch (r) { 7210 case 0: 7211 break; 7212 7213 case ENOMEM: 7214 warn(emsg_nomem); 7215 result = -1; 7216 goto out; 7217 7218 default: 7219 bad_error("load_init", r); 7220 } 7221 7222 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) { 7223 switch (scf_error()) { 7224 case SCF_ERROR_CONNECTION_BROKEN: 7225 warn(gettext("Repository connection broken.\n")); 7226 repository_teardown(); 7227 result = -1; 7228 goto out; 7229 7230 case SCF_ERROR_NOT_FOUND: 7231 case SCF_ERROR_INVALID_ARGUMENT: 7232 case SCF_ERROR_NOT_BOUND: 7233 case SCF_ERROR_HANDLE_MISMATCH: 7234 default: 7235 bad_error("scf_handle_get_scope", scf_error()); 7236 } 7237 } 7238 7239 /* Set up the auditing annotation. */ 7240 if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) { 7241 annotation_set = 1; 7242 } else { 7243 switch (scf_error()) { 7244 case SCF_ERROR_CONNECTION_BROKEN: 7245 warn(gettext("Repository connection broken.\n")); 7246 repository_teardown(); 7247 result = -1; 7248 goto out; 7249 7250 case SCF_ERROR_INVALID_ARGUMENT: 7251 case SCF_ERROR_NOT_BOUND: 7252 case SCF_ERROR_NO_RESOURCES: 7253 case SCF_ERROR_INTERNAL: 7254 bad_error("_scf_set_annotation", scf_error()); 7255 /* NOTREACHED */ 7256 7257 default: 7258 /* 7259 * Do not terminate import because of inability to 7260 * generate annotation audit event. 7261 */ 7262 warn(gettext("_scf_set_annotation() unexpectedly " 7263 "failed with return code of %d\n"), scf_error()); 7264 break; 7265 } 7266 } 7267 7268 /* 7269 * Clear the sc_import_state's of all services & instances so we can 7270 * report how far we got if we fail. 7271 */ 7272 for (svc = uu_list_first(bndl->sc_bundle_services); 7273 svc != NULL; 7274 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 7275 svc->sc_import_state = 0; 7276 7277 if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances, 7278 clear_int, (void *)offsetof(entity_t, sc_import_state), 7279 UU_DEFAULT) != 0) 7280 bad_error("uu_list_walk", uu_error()); 7281 } 7282 7283 cbdata.sc_handle = g_hndl; 7284 cbdata.sc_parent = imp_scope; 7285 cbdata.sc_flags = flags; 7286 cbdata.sc_general = NULL; 7287 7288 if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import, 7289 &cbdata, UU_DEFAULT) == 0) { 7290 /* Success. Refresh everything. */ 7291 7292 if (flags & SCI_NOREFRESH || no_refresh) { 7293 result = 0; 7294 goto out; 7295 } 7296 7297 for (svc = uu_list_first(bndl->sc_bundle_services); 7298 svc != NULL; 7299 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 7300 pgroup_t *dpt; 7301 7302 insts = svc->sc_u.sc_service.sc_service_instances; 7303 7304 for (inst = uu_list_first(insts); 7305 inst != NULL; 7306 inst = uu_list_next(insts, inst)) { 7307 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL); 7308 switch (r) { 7309 case 0: 7310 break; 7311 7312 case ENOMEM: 7313 case ECONNABORTED: 7314 case EPERM: 7315 case -1: 7316 goto progress; 7317 7318 default: 7319 bad_error("imp_refresh_fmri", r); 7320 } 7321 7322 inst->sc_import_state = IMPORT_REFRESHED; 7323 7324 for (dpt = uu_list_first(inst->sc_dependents); 7325 dpt != NULL; 7326 dpt = uu_list_next(inst->sc_dependents, 7327 dpt)) 7328 if (imp_refresh_fmri( 7329 dpt->sc_pgroup_fmri, 7330 dpt->sc_pgroup_name, 7331 inst->sc_fmri) != 0) 7332 goto progress; 7333 } 7334 7335 for (dpt = uu_list_first(svc->sc_dependents); 7336 dpt != NULL; 7337 dpt = uu_list_next(svc->sc_dependents, dpt)) 7338 if (imp_refresh_fmri(dpt->sc_pgroup_fmri, 7339 dpt->sc_pgroup_name, svc->sc_fmri) != 0) 7340 goto progress; 7341 } 7342 7343 for (old_dpt = uu_list_first(imp_deleted_dpts); 7344 old_dpt != NULL; 7345 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) 7346 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri, 7347 old_dpt->sc_pgroup_name, 7348 old_dpt->sc_parent->sc_fmri) != 0) 7349 goto progress; 7350 7351 result = 0; 7352 goto out; 7353 } 7354 7355 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7356 bad_error("uu_list_walk", uu_error()); 7357 7358 printerr: 7359 /* If the error hasn't been printed yet, do so here. */ 7360 switch (cbdata.sc_err) { 7361 case ECONNABORTED: 7362 warn(gettext("Repository connection broken.\n")); 7363 break; 7364 7365 case ENOMEM: 7366 warn(emsg_nomem); 7367 break; 7368 7369 case ENOSPC: 7370 warn(emsg_nores); 7371 break; 7372 7373 case EROFS: 7374 warn(gettext("Repository is read-only.\n")); 7375 break; 7376 7377 case EACCES: 7378 warn(gettext("Repository backend denied access.\n")); 7379 break; 7380 7381 case EPERM: 7382 case EINVAL: 7383 case EEXIST: 7384 case EBUSY: 7385 case EBADF: 7386 case -1: 7387 break; 7388 7389 default: 7390 bad_error("lscf_service_import", cbdata.sc_err); 7391 } 7392 7393 progress: 7394 warn(gettext("Import of %s failed. Progress:\n"), filename); 7395 7396 for (svc = uu_list_first(bndl->sc_bundle_services); 7397 svc != NULL; 7398 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 7399 insts = svc->sc_u.sc_service.sc_service_instances; 7400 7401 warn(gettext(" Service \"%s\": %s\n"), svc->sc_name, 7402 import_progress(svc->sc_import_state)); 7403 7404 for (inst = uu_list_first(insts); 7405 inst != NULL; 7406 inst = uu_list_next(insts, inst)) 7407 warn(gettext(" Instance \"%s\": %s\n"), 7408 inst->sc_name, 7409 import_progress(inst->sc_import_state)); 7410 } 7411 7412 if (cbdata.sc_err == ECONNABORTED) 7413 repository_teardown(); 7414 7415 7416 result = -1; 7417 7418 out: 7419 if (annotation_set != 0) { 7420 /* Turn off annotation. It is no longer needed. */ 7421 (void) _scf_set_annotation(g_hndl, NULL, NULL); 7422 } 7423 load_fini(); 7424 7425 free(ud_ctarg); 7426 free(ud_oldtarg); 7427 free(ud_name); 7428 ud_ctarg = ud_oldtarg = ud_name = NULL; 7429 7430 scf_transaction_destroy(ud_tx); 7431 ud_tx = NULL; 7432 scf_iter_destroy(ud_iter); 7433 scf_iter_destroy(ud_iter2); 7434 ud_iter = ud_iter2 = NULL; 7435 scf_value_destroy(ud_val); 7436 ud_val = NULL; 7437 scf_property_destroy(ud_prop); 7438 scf_property_destroy(ud_dpt_prop); 7439 ud_prop = ud_dpt_prop = NULL; 7440 scf_pg_destroy(ud_pg); 7441 scf_pg_destroy(ud_cur_depts_pg); 7442 scf_pg_destroy(ud_run_dpts_pg); 7443 ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL; 7444 scf_snaplevel_destroy(ud_snpl); 7445 ud_snpl = NULL; 7446 scf_instance_destroy(ud_inst); 7447 ud_inst = NULL; 7448 7449 free(imp_str); 7450 free(imp_tsname); 7451 free(imp_fe1); 7452 free(imp_fe2); 7453 imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL; 7454 7455 cookie = NULL; 7456 while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) != 7457 NULL) { 7458 free((char *)old_dpt->sc_pgroup_name); 7459 free((char *)old_dpt->sc_pgroup_fmri); 7460 internal_pgroup_free(old_dpt); 7461 } 7462 uu_list_destroy(imp_deleted_dpts); 7463 7464 scf_transaction_destroy(imp_tx); 7465 imp_tx = NULL; 7466 scf_iter_destroy(imp_iter); 7467 scf_iter_destroy(imp_rpg_iter); 7468 scf_iter_destroy(imp_up_iter); 7469 imp_iter = imp_rpg_iter = imp_up_iter = NULL; 7470 scf_property_destroy(imp_prop); 7471 imp_prop = NULL; 7472 scf_pg_destroy(imp_pg); 7473 scf_pg_destroy(imp_pg2); 7474 imp_pg = imp_pg2 = NULL; 7475 scf_snaplevel_destroy(imp_snpl); 7476 scf_snaplevel_destroy(imp_rsnpl); 7477 imp_snpl = imp_rsnpl = NULL; 7478 scf_snapshot_destroy(imp_snap); 7479 scf_snapshot_destroy(imp_lisnap); 7480 scf_snapshot_destroy(imp_tlisnap); 7481 scf_snapshot_destroy(imp_rsnap); 7482 imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL; 7483 scf_instance_destroy(imp_inst); 7484 scf_instance_destroy(imp_tinst); 7485 imp_inst = imp_tinst = NULL; 7486 scf_service_destroy(imp_svc); 7487 scf_service_destroy(imp_tsvc); 7488 imp_svc = imp_tsvc = NULL; 7489 scf_scope_destroy(imp_scope); 7490 imp_scope = NULL; 7491 7492 return (result); 7493 } 7494 7495 /* 7496 * _lscf_import_err() summarize the error handling returned by 7497 * lscf_import_{instance | service}_pgs 7498 * Return values are: 7499 * IMPORT_NEXT 7500 * IMPORT_OUT 7501 * IMPORT_BAD 7502 */ 7503 7504 #define IMPORT_BAD -1 7505 #define IMPORT_NEXT 0 7506 #define IMPORT_OUT 1 7507 7508 static int 7509 _lscf_import_err(int err, const char *fmri) 7510 { 7511 switch (err) { 7512 case 0: 7513 if (g_verbose) 7514 warn(gettext("%s updated.\n"), fmri); 7515 return (IMPORT_NEXT); 7516 7517 case ECONNABORTED: 7518 warn(gettext("Could not update %s " 7519 "(repository connection broken).\n"), fmri); 7520 return (IMPORT_OUT); 7521 7522 case ENOMEM: 7523 warn(gettext("Could not update %s (out of memory).\n"), fmri); 7524 return (IMPORT_OUT); 7525 7526 case ENOSPC: 7527 warn(gettext("Could not update %s " 7528 "(repository server out of resources).\n"), fmri); 7529 return (IMPORT_OUT); 7530 7531 case ECANCELED: 7532 warn(gettext( 7533 "Could not update %s (deleted).\n"), fmri); 7534 return (IMPORT_NEXT); 7535 7536 case EPERM: 7537 case EINVAL: 7538 case EBUSY: 7539 return (IMPORT_NEXT); 7540 7541 case EROFS: 7542 warn(gettext("Could not update %s (repository read-only).\n"), 7543 fmri); 7544 return (IMPORT_OUT); 7545 7546 case EACCES: 7547 warn(gettext("Could not update %s " 7548 "(backend access denied).\n"), fmri); 7549 return (IMPORT_NEXT); 7550 7551 case EEXIST: 7552 default: 7553 return (IMPORT_BAD); 7554 } 7555 7556 /*NOTREACHED*/ 7557 } 7558 7559 /* 7560 * Returns 7561 * 0 - success 7562 * -1 - lscf_import_instance_pgs() failed. 7563 */ 7564 int 7565 lscf_bundle_apply(bundle_t *bndl, const char *file) 7566 { 7567 entity_t *svc, *inst; 7568 scf_scope_t *rscope; 7569 scf_service_t *rsvc; 7570 scf_instance_t *rinst; 7571 scf_iter_t *iter; 7572 int annotation_set = 0; 7573 int r; 7574 7575 lscf_prep_hndl(); 7576 7577 if ((rscope = scf_scope_create(g_hndl)) == NULL || 7578 (rsvc = scf_service_create(g_hndl)) == NULL || 7579 (rinst = scf_instance_create(g_hndl)) == NULL || 7580 (iter = scf_iter_create(g_hndl)) == NULL || 7581 (imp_pg = scf_pg_create(g_hndl)) == NULL || 7582 (imp_tx = scf_transaction_create(g_hndl)) == NULL) 7583 scfdie(); 7584 7585 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, rscope) != 0) 7586 scfdie(); 7587 7588 /* 7589 * Set the strings to be used for the security audit annotation 7590 * event. 7591 */ 7592 if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) { 7593 annotation_set = 1; 7594 } else { 7595 switch (scf_error()) { 7596 case SCF_ERROR_CONNECTION_BROKEN: 7597 warn(gettext("Repository connection broken.\n")); 7598 goto out; 7599 7600 case SCF_ERROR_INVALID_ARGUMENT: 7601 case SCF_ERROR_NOT_BOUND: 7602 case SCF_ERROR_NO_RESOURCES: 7603 case SCF_ERROR_INTERNAL: 7604 bad_error("_scf_set_annotation", scf_error()); 7605 /* NOTREACHED */ 7606 7607 default: 7608 /* 7609 * Do not abort apply operation because of 7610 * inability to create annotation audit event. 7611 */ 7612 warn(gettext("_scf_set_annotation() unexpectedly " 7613 "failed with return code of %d\n"), scf_error()); 7614 break; 7615 } 7616 } 7617 7618 for (svc = uu_list_first(bndl->sc_bundle_services); 7619 svc != NULL; 7620 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 7621 int refresh = 0; 7622 7623 if (scf_scope_get_service(rscope, svc->sc_name, rsvc) != 0) { 7624 switch (scf_error()) { 7625 case SCF_ERROR_NOT_FOUND: 7626 if (g_verbose) 7627 warn(gettext("Ignoring nonexistent " 7628 "service %s.\n"), svc->sc_name); 7629 continue; 7630 7631 default: 7632 scfdie(); 7633 } 7634 } 7635 7636 /* 7637 * if we have pgs in the profile, we need to refresh ALL 7638 * instances of the service 7639 */ 7640 if (uu_list_numnodes(svc->sc_pgroups) != 0) { 7641 refresh = 1; 7642 r = lscf_import_service_pgs(rsvc, svc->sc_fmri, svc, 7643 SCI_FORCE | SCI_KEEP); 7644 switch (_lscf_import_err(r, svc->sc_fmri)) { 7645 case IMPORT_NEXT: 7646 break; 7647 7648 case IMPORT_OUT: 7649 goto out; 7650 7651 case IMPORT_BAD: 7652 default: 7653 bad_error("lscf_import_service_pgs", r); 7654 } 7655 } 7656 7657 for (inst = uu_list_first( 7658 svc->sc_u.sc_service.sc_service_instances); 7659 inst != NULL; 7660 inst = uu_list_next( 7661 svc->sc_u.sc_service.sc_service_instances, inst)) { 7662 if (scf_service_get_instance(rsvc, inst->sc_name, 7663 rinst) != 0) { 7664 switch (scf_error()) { 7665 case SCF_ERROR_NOT_FOUND: 7666 if (g_verbose) 7667 warn(gettext("Ignoring " 7668 "nonexistant instance " 7669 "%s:%s.\n"), 7670 inst->sc_parent->sc_name, 7671 inst->sc_name); 7672 continue; 7673 7674 default: 7675 scfdie(); 7676 } 7677 } 7678 7679 r = lscf_import_instance_pgs(rinst, inst->sc_fmri, inst, 7680 SCI_FORCE | SCI_KEEP); 7681 switch (_lscf_import_err(r, inst->sc_fmri)) { 7682 case IMPORT_NEXT: 7683 break; 7684 7685 case IMPORT_OUT: 7686 goto out; 7687 7688 case IMPORT_BAD: 7689 default: 7690 bad_error("lscf_import_instance_pgs", r); 7691 } 7692 7693 /* refresh only if there is no pgs in the service */ 7694 if (refresh == 0) 7695 (void) refresh_entity(0, rinst, inst->sc_fmri, 7696 NULL, NULL, NULL); 7697 } 7698 7699 if (refresh == 1) { 7700 char *name_buf = safe_malloc(max_scf_name_len + 1); 7701 7702 (void) refresh_entity(1, rsvc, svc->sc_name, rinst, 7703 iter, name_buf); 7704 free(name_buf); 7705 } 7706 } 7707 7708 out: 7709 if (annotation_set) { 7710 /* Remove security audit annotation strings. */ 7711 (void) _scf_set_annotation(g_hndl, NULL, NULL); 7712 } 7713 7714 scf_transaction_destroy(imp_tx); 7715 imp_tx = NULL; 7716 scf_pg_destroy(imp_pg); 7717 imp_pg = NULL; 7718 7719 scf_iter_destroy(iter); 7720 scf_instance_destroy(rinst); 7721 scf_service_destroy(rsvc); 7722 scf_scope_destroy(rscope); 7723 return (0); 7724 } 7725 7726 7727 /* 7728 * Export. These functions create and output an XML tree of a service 7729 * description from the repository. This is largely the inverse of 7730 * lxml_get_bundle() in svccfg_xml.c, but with some kickers: 7731 * 7732 * - We must include any properties which are not represented specifically by 7733 * a service manifest, e.g., properties created by an admin post-import. To 7734 * do so we'll iterate through all properties and deal with each 7735 * apropriately. 7736 * 7737 * - Children of services and instances must must be in the order set by the 7738 * DTD, but we iterate over the properties in undefined order. The elements 7739 * are not easily (or efficiently) sortable by name. Since there's a fixed 7740 * number of classes of them, however, we'll keep the classes separate and 7741 * assemble them in order. 7742 */ 7743 7744 /* 7745 * Convenience function to handle xmlSetProp errors (and type casting). 7746 */ 7747 static void 7748 safe_setprop(xmlNodePtr n, const char *name, const char *val) 7749 { 7750 if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL) 7751 uu_die(gettext("Could not set XML property.\n")); 7752 } 7753 7754 /* 7755 * Convenience function to set an XML attribute to the single value of an 7756 * astring property. If the value happens to be the default, don't set the 7757 * attribute. "dval" should be the default value supplied by the DTD, or 7758 * NULL for no default. 7759 */ 7760 static int 7761 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n, 7762 const char *name, const char *dval) 7763 { 7764 scf_value_t *val; 7765 ssize_t len; 7766 char *str; 7767 7768 val = scf_value_create(g_hndl); 7769 if (val == NULL) 7770 scfdie(); 7771 7772 if (prop_get_val(prop, val) != 0) { 7773 scf_value_destroy(val); 7774 return (-1); 7775 } 7776 7777 len = scf_value_get_as_string(val, NULL, 0); 7778 if (len < 0) 7779 scfdie(); 7780 7781 str = safe_malloc(len + 1); 7782 7783 if (scf_value_get_as_string(val, str, len + 1) < 0) 7784 scfdie(); 7785 7786 scf_value_destroy(val); 7787 7788 if (dval == NULL || strcmp(str, dval) != 0) 7789 safe_setprop(n, name, str); 7790 7791 free(str); 7792 7793 return (0); 7794 } 7795 7796 /* 7797 * As above, but the attribute is always set. 7798 */ 7799 static int 7800 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name) 7801 { 7802 return (set_attr_from_prop_default(prop, n, name, NULL)); 7803 } 7804 7805 /* 7806 * Dump the given document onto f, with "'s replaced by ''s. 7807 */ 7808 static int 7809 write_service_bundle(xmlDocPtr doc, FILE *f) 7810 { 7811 xmlChar *mem; 7812 int sz, i; 7813 7814 mem = NULL; 7815 xmlDocDumpFormatMemory(doc, &mem, &sz, 1); 7816 7817 if (mem == NULL) { 7818 semerr(gettext("Could not dump XML tree.\n")); 7819 return (-1); 7820 } 7821 7822 /* 7823 * Fortunately libxml produces " instead of ", so we can blindly 7824 * replace all " with '. Cursed libxml2! Why must you #ifdef out the 7825 * ' code?! 7826 */ 7827 for (i = 0; i < sz; ++i) { 7828 char c = (char)mem[i]; 7829 7830 if (c == '"') 7831 (void) fputc('\'', f); 7832 else if (c == '\'') 7833 (void) fwrite("'", sizeof ("'") - 1, 1, f); 7834 else 7835 (void) fputc(c, f); 7836 } 7837 7838 return (0); 7839 } 7840 7841 /* 7842 * Create the DOM elements in elts necessary to (generically) represent prop 7843 * (i.e., a property or propval element). If the name of the property is 7844 * known, it should be passed as name_arg. Otherwise, pass NULL. 7845 */ 7846 static void 7847 export_property(scf_property_t *prop, const char *name_arg, 7848 struct pg_elts *elts, int flags) 7849 { 7850 const char *type; 7851 scf_error_t err = 0; 7852 xmlNodePtr pnode, lnode; 7853 char *lnname; 7854 int ret; 7855 7856 /* name */ 7857 if (name_arg != NULL) { 7858 (void) strcpy(exp_str, name_arg); 7859 } else { 7860 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0) 7861 scfdie(); 7862 } 7863 7864 /* type */ 7865 type = prop_to_typestr(prop); 7866 if (type == NULL) 7867 uu_die(gettext("Can't export property %s: unknown type.\n"), 7868 exp_str); 7869 7870 /* If we're exporting values, and there's just one, export it here. */ 7871 if (!(flags & SCE_ALL_VALUES)) 7872 goto empty; 7873 7874 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) { 7875 xmlNodePtr n; 7876 7877 /* Single value, so use propval */ 7878 n = xmlNewNode(NULL, (xmlChar *)"propval"); 7879 if (n == NULL) 7880 uu_die(emsg_create_xml); 7881 7882 safe_setprop(n, name_attr, exp_str); 7883 safe_setprop(n, type_attr, type); 7884 7885 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 7886 scfdie(); 7887 safe_setprop(n, value_attr, exp_str); 7888 7889 if (elts->propvals == NULL) 7890 elts->propvals = n; 7891 else 7892 (void) xmlAddSibling(elts->propvals, n); 7893 7894 return; 7895 } 7896 7897 err = scf_error(); 7898 7899 if (err == SCF_ERROR_PERMISSION_DENIED) { 7900 semerr(emsg_permission_denied); 7901 return; 7902 } 7903 7904 if (err != SCF_ERROR_CONSTRAINT_VIOLATED && 7905 err != SCF_ERROR_NOT_FOUND && 7906 err != SCF_ERROR_PERMISSION_DENIED) 7907 scfdie(); 7908 7909 empty: 7910 /* Multiple (or no) values, so use property */ 7911 pnode = xmlNewNode(NULL, (xmlChar *)"property"); 7912 if (pnode == NULL) 7913 uu_die(emsg_create_xml); 7914 7915 safe_setprop(pnode, name_attr, exp_str); 7916 safe_setprop(pnode, type_attr, type); 7917 7918 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) { 7919 lnname = uu_msprintf("%s_list", type); 7920 if (lnname == NULL) 7921 uu_die(gettext("Could not create string")); 7922 7923 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL); 7924 if (lnode == NULL) 7925 uu_die(emsg_create_xml); 7926 7927 uu_free(lnname); 7928 7929 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS) 7930 scfdie(); 7931 7932 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 7933 1) { 7934 xmlNodePtr vn; 7935 7936 vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node", 7937 NULL); 7938 if (vn == NULL) 7939 uu_die(emsg_create_xml); 7940 7941 if (scf_value_get_as_string(exp_val, exp_str, 7942 exp_str_sz) < 0) 7943 scfdie(); 7944 safe_setprop(vn, value_attr, exp_str); 7945 } 7946 if (ret != 0) 7947 scfdie(); 7948 } 7949 7950 if (elts->properties == NULL) 7951 elts->properties = pnode; 7952 else 7953 (void) xmlAddSibling(elts->properties, pnode); 7954 } 7955 7956 /* 7957 * Add a property_group element for this property group to elts. 7958 */ 7959 static void 7960 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags) 7961 { 7962 xmlNodePtr n; 7963 struct pg_elts elts; 7964 int ret; 7965 boolean_t read_protected; 7966 7967 n = xmlNewNode(NULL, (xmlChar *)"property_group"); 7968 7969 /* name */ 7970 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 7971 scfdie(); 7972 safe_setprop(n, name_attr, exp_str); 7973 7974 /* type */ 7975 if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0) 7976 scfdie(); 7977 safe_setprop(n, type_attr, exp_str); 7978 7979 /* properties */ 7980 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 7981 scfdie(); 7982 7983 (void) memset(&elts, 0, sizeof (elts)); 7984 7985 /* 7986 * If this property group is not read protected, we always want to 7987 * output all the values. Otherwise, we only output the values if the 7988 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a). 7989 */ 7990 if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS) 7991 scfdie(); 7992 7993 if (!read_protected) 7994 flags |= SCE_ALL_VALUES; 7995 7996 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 7997 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 7998 scfdie(); 7999 8000 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 8001 xmlNodePtr m; 8002 8003 m = xmlNewNode(NULL, (xmlChar *)"stability"); 8004 if (m == NULL) 8005 uu_die(emsg_create_xml); 8006 8007 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 8008 elts.stability = m; 8009 continue; 8010 } 8011 8012 xmlFreeNode(m); 8013 } 8014 8015 export_property(exp_prop, NULL, &elts, flags); 8016 } 8017 if (ret == -1) 8018 scfdie(); 8019 8020 (void) xmlAddChild(n, elts.stability); 8021 (void) xmlAddChildList(n, elts.propvals); 8022 (void) xmlAddChildList(n, elts.properties); 8023 8024 if (eelts->property_groups == NULL) 8025 eelts->property_groups = n; 8026 else 8027 (void) xmlAddSibling(eelts->property_groups, n); 8028 } 8029 8030 /* 8031 * Create an XML node representing the dependency described by the given 8032 * property group and put it in eelts. Unless the dependency is not valid, in 8033 * which case create a generic property_group element which represents it and 8034 * put it in eelts. 8035 */ 8036 static void 8037 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts) 8038 { 8039 xmlNodePtr n; 8040 int err = 0, ret; 8041 struct pg_elts elts; 8042 8043 n = xmlNewNode(NULL, (xmlChar *)"dependency"); 8044 if (n == NULL) 8045 uu_die(emsg_create_xml); 8046 8047 /* 8048 * If the external flag is present, skip this dependency because it 8049 * should have been created by another manifest. 8050 */ 8051 if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) { 8052 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 8053 prop_get_val(exp_prop, exp_val) == 0) { 8054 uint8_t b; 8055 8056 if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS) 8057 scfdie(); 8058 8059 if (b) 8060 return; 8061 } 8062 } else if (scf_error() != SCF_ERROR_NOT_FOUND) 8063 scfdie(); 8064 8065 /* Get the required attributes. */ 8066 8067 /* name */ 8068 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 8069 scfdie(); 8070 safe_setprop(n, name_attr, exp_str); 8071 8072 /* grouping */ 8073 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 || 8074 set_attr_from_prop(exp_prop, n, "grouping") != 0) 8075 err = 1; 8076 8077 /* restart_on */ 8078 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 || 8079 set_attr_from_prop(exp_prop, n, "restart_on") != 0) 8080 err = 1; 8081 8082 /* type */ 8083 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 || 8084 set_attr_from_prop(exp_prop, n, type_attr) != 0) 8085 err = 1; 8086 8087 /* 8088 * entities: Not required, but if we create no children, it will be 8089 * created as empty on import, so fail if it's missing. 8090 */ 8091 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 && 8092 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) { 8093 scf_iter_t *eiter; 8094 int ret2; 8095 8096 eiter = scf_iter_create(g_hndl); 8097 if (eiter == NULL) 8098 scfdie(); 8099 8100 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS) 8101 scfdie(); 8102 8103 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) { 8104 xmlNodePtr ch; 8105 8106 if (scf_value_get_astring(exp_val, exp_str, 8107 exp_str_sz) < 0) 8108 scfdie(); 8109 8110 /* 8111 * service_fmri's must be first, so we can add them 8112 * here. 8113 */ 8114 ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", 8115 NULL); 8116 if (ch == NULL) 8117 uu_die(emsg_create_xml); 8118 8119 safe_setprop(ch, value_attr, exp_str); 8120 } 8121 if (ret2 == -1) 8122 scfdie(); 8123 8124 scf_iter_destroy(eiter); 8125 } else 8126 err = 1; 8127 8128 if (err) { 8129 xmlFreeNode(n); 8130 8131 export_pg(pg, eelts, 0); 8132 8133 return; 8134 } 8135 8136 /* Iterate through the properties & handle each. */ 8137 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8138 scfdie(); 8139 8140 (void) memset(&elts, 0, sizeof (elts)); 8141 8142 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8143 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8144 scfdie(); 8145 8146 if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 || 8147 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 || 8148 strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 || 8149 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) { 8150 continue; 8151 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 8152 xmlNodePtr m; 8153 8154 m = xmlNewNode(NULL, (xmlChar *)"stability"); 8155 if (m == NULL) 8156 uu_die(emsg_create_xml); 8157 8158 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 8159 elts.stability = m; 8160 continue; 8161 } 8162 8163 xmlFreeNode(m); 8164 } 8165 8166 export_property(exp_prop, exp_str, &elts, 0); 8167 } 8168 if (ret == -1) 8169 scfdie(); 8170 8171 (void) xmlAddChild(n, elts.stability); 8172 (void) xmlAddChildList(n, elts.propvals); 8173 (void) xmlAddChildList(n, elts.properties); 8174 8175 if (eelts->dependencies == NULL) 8176 eelts->dependencies = n; 8177 else 8178 (void) xmlAddSibling(eelts->dependencies, n); 8179 } 8180 8181 static xmlNodePtr 8182 export_method_environment(scf_propertygroup_t *pg) 8183 { 8184 xmlNodePtr env; 8185 int ret; 8186 int children = 0; 8187 8188 if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0) 8189 return (NULL); 8190 8191 env = xmlNewNode(NULL, (xmlChar *)"method_environment"); 8192 if (env == NULL) 8193 uu_die(emsg_create_xml); 8194 8195 if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0) 8196 scfdie(); 8197 8198 if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS) 8199 scfdie(); 8200 8201 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) { 8202 xmlNodePtr ev; 8203 char *cp; 8204 8205 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 8206 scfdie(); 8207 8208 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) { 8209 warn(gettext("Invalid environment variable \"%s\".\n"), 8210 exp_str); 8211 continue; 8212 } else if (strncmp(exp_str, "SMF_", 4) == 0) { 8213 warn(gettext("Invalid environment variable \"%s\"; " 8214 "\"SMF_\" prefix is reserved.\n"), exp_str); 8215 continue; 8216 } 8217 8218 *cp = '\0'; 8219 cp++; 8220 8221 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL); 8222 if (ev == NULL) 8223 uu_die(emsg_create_xml); 8224 8225 safe_setprop(ev, name_attr, exp_str); 8226 safe_setprop(ev, value_attr, cp); 8227 children++; 8228 } 8229 8230 if (ret != 0) 8231 scfdie(); 8232 8233 if (children == 0) { 8234 xmlFreeNode(env); 8235 return (NULL); 8236 } 8237 8238 return (env); 8239 } 8240 8241 /* 8242 * As above, but for a method property group. 8243 */ 8244 static void 8245 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts) 8246 { 8247 xmlNodePtr n, env; 8248 char *str; 8249 int err = 0, nonenv, ret; 8250 uint8_t use_profile; 8251 struct pg_elts elts; 8252 xmlNodePtr ctxt = NULL; 8253 8254 n = xmlNewNode(NULL, (xmlChar *)"exec_method"); 8255 8256 /* Get the required attributes. */ 8257 8258 /* name */ 8259 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 8260 scfdie(); 8261 safe_setprop(n, name_attr, exp_str); 8262 8263 /* type */ 8264 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 || 8265 set_attr_from_prop(exp_prop, n, type_attr) != 0) 8266 err = 1; 8267 8268 /* exec */ 8269 if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 || 8270 set_attr_from_prop(exp_prop, n, "exec") != 0) 8271 err = 1; 8272 8273 /* timeout */ 8274 if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 && 8275 prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 && 8276 prop_get_val(exp_prop, exp_val) == 0) { 8277 uint64_t c; 8278 8279 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS) 8280 scfdie(); 8281 8282 str = uu_msprintf("%llu", c); 8283 if (str == NULL) 8284 uu_die(gettext("Could not create string")); 8285 8286 safe_setprop(n, "timeout_seconds", str); 8287 free(str); 8288 } else 8289 err = 1; 8290 8291 if (err) { 8292 xmlFreeNode(n); 8293 8294 export_pg(pg, eelts, 0); 8295 8296 return; 8297 } 8298 8299 8300 /* 8301 * If we're going to have a method_context child, we need to know 8302 * before we iterate through the properties. Since method_context's 8303 * are optional, we don't want to complain about any properties 8304 * missing if none of them are there. Thus we can't use the 8305 * convenience functions. 8306 */ 8307 nonenv = 8308 scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) == 8309 SCF_SUCCESS || 8310 scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) == 8311 SCF_SUCCESS || 8312 scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) == 8313 SCF_SUCCESS || 8314 scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) == 8315 SCF_SUCCESS; 8316 8317 if (nonenv) { 8318 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context"); 8319 if (ctxt == NULL) 8320 uu_die(emsg_create_xml); 8321 8322 if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) == 8323 0 && 8324 set_attr_from_prop_default(exp_prop, ctxt, 8325 "working_directory", ":default") != 0) 8326 err = 1; 8327 8328 if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 && 8329 set_attr_from_prop_default(exp_prop, ctxt, "project", 8330 ":default") != 0) 8331 err = 1; 8332 8333 if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) == 8334 0 && 8335 set_attr_from_prop_default(exp_prop, ctxt, 8336 "resource_pool", ":default") != 0) 8337 err = 1; 8338 /* 8339 * We only want to complain about profile or credential 8340 * properties if we will use them. To determine that we must 8341 * examine USE_PROFILE. 8342 */ 8343 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 && 8344 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 8345 prop_get_val(exp_prop, exp_val) == 0) { 8346 if (scf_value_get_boolean(exp_val, &use_profile) != 8347 SCF_SUCCESS) { 8348 scfdie(); 8349 } 8350 8351 if (use_profile) { 8352 xmlNodePtr prof; 8353 8354 prof = xmlNewChild(ctxt, NULL, 8355 (xmlChar *)"method_profile", NULL); 8356 if (prof == NULL) 8357 uu_die(emsg_create_xml); 8358 8359 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE, 8360 exp_prop) != 0 || 8361 set_attr_from_prop(exp_prop, prof, 8362 name_attr) != 0) 8363 err = 1; 8364 } else { 8365 xmlNodePtr cred; 8366 8367 cred = xmlNewChild(ctxt, NULL, 8368 (xmlChar *)"method_credential", NULL); 8369 if (cred == NULL) 8370 uu_die(emsg_create_xml); 8371 8372 if (pg_get_prop(pg, SCF_PROPERTY_USER, 8373 exp_prop) != 0 || 8374 set_attr_from_prop(exp_prop, cred, 8375 "user") != 0) { 8376 err = 1; 8377 } 8378 8379 if (pg_get_prop(pg, SCF_PROPERTY_GROUP, 8380 exp_prop) == 0 && 8381 set_attr_from_prop_default(exp_prop, cred, 8382 "group", ":default") != 0) 8383 err = 1; 8384 8385 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS, 8386 exp_prop) == 0 && 8387 set_attr_from_prop_default(exp_prop, cred, 8388 "supp_groups", ":default") != 0) 8389 err = 1; 8390 8391 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES, 8392 exp_prop) == 0 && 8393 set_attr_from_prop_default(exp_prop, cred, 8394 "privileges", ":default") != 0) 8395 err = 1; 8396 8397 if (pg_get_prop(pg, 8398 SCF_PROPERTY_LIMIT_PRIVILEGES, 8399 exp_prop) == 0 && 8400 set_attr_from_prop_default(exp_prop, cred, 8401 "limit_privileges", ":default") != 0) 8402 err = 1; 8403 } 8404 } 8405 } 8406 8407 if ((env = export_method_environment(pg)) != NULL) { 8408 if (ctxt == NULL) { 8409 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context"); 8410 if (ctxt == NULL) 8411 uu_die(emsg_create_xml); 8412 } 8413 (void) xmlAddChild(ctxt, env); 8414 } 8415 8416 if (env != NULL || (nonenv && err == 0)) 8417 (void) xmlAddChild(n, ctxt); 8418 else 8419 xmlFreeNode(ctxt); 8420 8421 nonenv = (err == 0); 8422 8423 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8424 scfdie(); 8425 8426 (void) memset(&elts, 0, sizeof (elts)); 8427 8428 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8429 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8430 scfdie(); 8431 8432 if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 || 8433 strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 || 8434 strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) { 8435 continue; 8436 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 8437 xmlNodePtr m; 8438 8439 m = xmlNewNode(NULL, (xmlChar *)"stability"); 8440 if (m == NULL) 8441 uu_die(emsg_create_xml); 8442 8443 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 8444 elts.stability = m; 8445 continue; 8446 } 8447 8448 xmlFreeNode(m); 8449 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 8450 0 || 8451 strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 || 8452 strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 || 8453 strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) { 8454 if (nonenv) 8455 continue; 8456 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 || 8457 strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 || 8458 strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 || 8459 strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 || 8460 strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) { 8461 if (nonenv && !use_profile) 8462 continue; 8463 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) { 8464 if (nonenv && use_profile) 8465 continue; 8466 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) { 8467 if (env != NULL) 8468 continue; 8469 } 8470 8471 export_property(exp_prop, exp_str, &elts, 0); 8472 } 8473 if (ret == -1) 8474 scfdie(); 8475 8476 (void) xmlAddChild(n, elts.stability); 8477 (void) xmlAddChildList(n, elts.propvals); 8478 (void) xmlAddChildList(n, elts.properties); 8479 8480 if (eelts->exec_methods == NULL) 8481 eelts->exec_methods = n; 8482 else 8483 (void) xmlAddSibling(eelts->exec_methods, n); 8484 } 8485 8486 static void 8487 export_pg_elts(struct pg_elts *elts, const char *name, const char *type, 8488 struct entity_elts *eelts) 8489 { 8490 xmlNodePtr pgnode; 8491 8492 pgnode = xmlNewNode(NULL, (xmlChar *)"property_group"); 8493 if (pgnode == NULL) 8494 uu_die(emsg_create_xml); 8495 8496 safe_setprop(pgnode, name_attr, name); 8497 safe_setprop(pgnode, type_attr, type); 8498 8499 (void) xmlAddChildList(pgnode, elts->propvals); 8500 (void) xmlAddChildList(pgnode, elts->properties); 8501 8502 if (eelts->property_groups == NULL) 8503 eelts->property_groups = pgnode; 8504 else 8505 (void) xmlAddSibling(eelts->property_groups, pgnode); 8506 } 8507 8508 /* 8509 * Process the general property group for a service. This is the one with the 8510 * goodies. 8511 */ 8512 static void 8513 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts) 8514 { 8515 struct pg_elts elts; 8516 int ret; 8517 8518 /* 8519 * In case there are properties which don't correspond to child 8520 * entities of the service entity, we'll set up a pg_elts structure to 8521 * put them in. 8522 */ 8523 (void) memset(&elts, 0, sizeof (elts)); 8524 8525 /* Walk the properties, looking for special ones. */ 8526 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8527 scfdie(); 8528 8529 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8530 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8531 scfdie(); 8532 8533 if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) { 8534 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 8535 prop_get_val(exp_prop, exp_val) == 0) { 8536 uint8_t b; 8537 8538 if (scf_value_get_boolean(exp_val, &b) != 8539 SCF_SUCCESS) 8540 scfdie(); 8541 8542 if (b) { 8543 selts->single_instance = 8544 xmlNewNode(NULL, 8545 (xmlChar *)"single_instance"); 8546 if (selts->single_instance == NULL) 8547 uu_die(emsg_create_xml); 8548 } 8549 8550 continue; 8551 } 8552 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 8553 xmlNodePtr rnode, sfnode; 8554 8555 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 8556 if (rnode == NULL) 8557 uu_die(emsg_create_xml); 8558 8559 sfnode = xmlNewChild(rnode, NULL, 8560 (xmlChar *)"service_fmri", NULL); 8561 if (sfnode == NULL) 8562 uu_die(emsg_create_xml); 8563 8564 if (set_attr_from_prop(exp_prop, sfnode, 8565 value_attr) == 0) { 8566 selts->restarter = rnode; 8567 continue; 8568 } 8569 8570 xmlFreeNode(rnode); 8571 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) == 8572 0) { 8573 xmlNodePtr s; 8574 8575 s = xmlNewNode(NULL, (xmlChar *)"stability"); 8576 if (s == NULL) 8577 uu_die(emsg_create_xml); 8578 8579 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) { 8580 selts->stability = s; 8581 continue; 8582 } 8583 8584 xmlFreeNode(s); 8585 } 8586 8587 export_property(exp_prop, exp_str, &elts, 0); 8588 } 8589 if (ret == -1) 8590 scfdie(); 8591 8592 if (elts.propvals != NULL || elts.properties != NULL) 8593 export_pg_elts(&elts, scf_pg_general, scf_group_framework, 8594 selts); 8595 } 8596 8597 static void 8598 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts) 8599 { 8600 xmlNodePtr n, prof, cred, env; 8601 uint8_t use_profile; 8602 int ret, err = 0; 8603 8604 n = xmlNewNode(NULL, (xmlChar *)"method_context"); 8605 8606 env = export_method_environment(pg); 8607 8608 /* Need to know whether we'll use a profile or not. */ 8609 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 && 8610 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 8611 prop_get_val(exp_prop, exp_val) == 0) { 8612 if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS) 8613 scfdie(); 8614 8615 if (use_profile) 8616 prof = 8617 xmlNewChild(n, NULL, (xmlChar *)"method_profile", 8618 NULL); 8619 else 8620 cred = 8621 xmlNewChild(n, NULL, (xmlChar *)"method_credential", 8622 NULL); 8623 } 8624 8625 if (env != NULL) 8626 (void) xmlAddChild(n, env); 8627 8628 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8629 scfdie(); 8630 8631 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8632 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8633 scfdie(); 8634 8635 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) { 8636 if (set_attr_from_prop(exp_prop, n, 8637 "working_directory") != 0) 8638 err = 1; 8639 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) { 8640 if (set_attr_from_prop(exp_prop, n, "project") != 0) 8641 err = 1; 8642 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) { 8643 if (set_attr_from_prop(exp_prop, n, 8644 "resource_pool") != 0) 8645 err = 1; 8646 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) { 8647 /* EMPTY */ 8648 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) { 8649 if (use_profile || 8650 set_attr_from_prop(exp_prop, cred, "user") != 0) 8651 err = 1; 8652 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) { 8653 if (use_profile || 8654 set_attr_from_prop(exp_prop, cred, "group") != 0) 8655 err = 1; 8656 } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) { 8657 if (use_profile || set_attr_from_prop(exp_prop, cred, 8658 "supp_groups") != 0) 8659 err = 1; 8660 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) { 8661 if (use_profile || set_attr_from_prop(exp_prop, cred, 8662 "privileges") != 0) 8663 err = 1; 8664 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 8665 0) { 8666 if (use_profile || set_attr_from_prop(exp_prop, cred, 8667 "limit_privileges") != 0) 8668 err = 1; 8669 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) { 8670 if (!use_profile || set_attr_from_prop(exp_prop, 8671 prof, name_attr) != 0) 8672 err = 1; 8673 } else { 8674 /* Can't have generic properties in method_context's */ 8675 err = 1; 8676 } 8677 } 8678 if (ret == -1) 8679 scfdie(); 8680 8681 if (err && env == NULL) { 8682 xmlFreeNode(n); 8683 export_pg(pg, elts, 0); 8684 return; 8685 } 8686 8687 elts->method_context = n; 8688 } 8689 8690 /* 8691 * Given a dependency property group in the tfmri entity (target fmri), return 8692 * a dependent element which represents it. 8693 */ 8694 static xmlNodePtr 8695 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri) 8696 { 8697 uint8_t b; 8698 xmlNodePtr n, sf; 8699 int err = 0, ret; 8700 struct pg_elts pgelts; 8701 8702 /* 8703 * If external isn't set to true then exporting the service will 8704 * export this as a normal dependency, so we should stop to avoid 8705 * duplication. 8706 */ 8707 if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 || 8708 scf_property_get_value(exp_prop, exp_val) != 0 || 8709 scf_value_get_boolean(exp_val, &b) != 0 || !b) { 8710 if (g_verbose) { 8711 warn(gettext("Dependent \"%s\" cannot be exported " 8712 "properly because the \"%s\" property of the " 8713 "\"%s\" dependency of %s is not set to true.\n"), 8714 name, scf_property_external, name, tfmri); 8715 } 8716 8717 return (NULL); 8718 } 8719 8720 n = xmlNewNode(NULL, (xmlChar *)"dependent"); 8721 if (n == NULL) 8722 uu_die(emsg_create_xml); 8723 8724 safe_setprop(n, name_attr, name); 8725 8726 /* Get the required attributes */ 8727 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 || 8728 set_attr_from_prop(exp_prop, n, "restart_on") != 0) 8729 err = 1; 8730 8731 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 || 8732 set_attr_from_prop(exp_prop, n, "grouping") != 0) 8733 err = 1; 8734 8735 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 && 8736 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 && 8737 prop_get_val(exp_prop, exp_val) == 0) { 8738 /* EMPTY */ 8739 } else 8740 err = 1; 8741 8742 if (err) { 8743 xmlFreeNode(n); 8744 return (NULL); 8745 } 8746 8747 sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL); 8748 if (sf == NULL) 8749 uu_die(emsg_create_xml); 8750 8751 safe_setprop(sf, value_attr, tfmri); 8752 8753 /* 8754 * Now add elements for the other properties. 8755 */ 8756 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8757 scfdie(); 8758 8759 (void) memset(&pgelts, 0, sizeof (pgelts)); 8760 8761 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8762 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8763 scfdie(); 8764 8765 if (strcmp(exp_str, scf_property_external) == 0 || 8766 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 || 8767 strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 || 8768 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) { 8769 continue; 8770 } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) { 8771 if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 && 8772 prop_get_val(exp_prop, exp_val) == 0) { 8773 char type[sizeof ("service") + 1]; 8774 8775 if (scf_value_get_astring(exp_val, type, 8776 sizeof (type)) < 0) 8777 scfdie(); 8778 8779 if (strcmp(type, "service") == 0) 8780 continue; 8781 } 8782 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 8783 xmlNodePtr s; 8784 8785 s = xmlNewNode(NULL, (xmlChar *)"stability"); 8786 if (s == NULL) 8787 uu_die(emsg_create_xml); 8788 8789 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) { 8790 pgelts.stability = s; 8791 continue; 8792 } 8793 8794 xmlFreeNode(s); 8795 } 8796 8797 export_property(exp_prop, exp_str, &pgelts, 0); 8798 } 8799 if (ret == -1) 8800 scfdie(); 8801 8802 (void) xmlAddChild(n, pgelts.stability); 8803 (void) xmlAddChildList(n, pgelts.propvals); 8804 (void) xmlAddChildList(n, pgelts.properties); 8805 8806 return (n); 8807 } 8808 8809 static void 8810 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts) 8811 { 8812 scf_propertygroup_t *opg; 8813 scf_iter_t *iter; 8814 char *type, *fmri; 8815 int ret; 8816 struct pg_elts pgelts; 8817 xmlNodePtr n; 8818 scf_error_t serr; 8819 8820 if ((opg = scf_pg_create(g_hndl)) == NULL || 8821 (iter = scf_iter_create(g_hndl)) == NULL) 8822 scfdie(); 8823 8824 /* Can't use exp_prop_iter due to export_dependent(). */ 8825 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 8826 scfdie(); 8827 8828 type = safe_malloc(max_scf_pg_type_len + 1); 8829 8830 /* Get an extra byte so we can tell if values are too long. */ 8831 fmri = safe_malloc(max_scf_fmri_len + 2); 8832 8833 (void) memset(&pgelts, 0, sizeof (pgelts)); 8834 8835 while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) { 8836 void *entity; 8837 int isservice; 8838 scf_type_t ty; 8839 8840 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS) 8841 scfdie(); 8842 8843 if ((ty != SCF_TYPE_ASTRING && 8844 prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) || 8845 prop_get_val(exp_prop, exp_val) != 0) { 8846 export_property(exp_prop, NULL, &pgelts, 0); 8847 continue; 8848 } 8849 8850 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8851 scfdie(); 8852 8853 if (scf_value_get_astring(exp_val, fmri, 8854 max_scf_fmri_len + 2) < 0) 8855 scfdie(); 8856 8857 /* Look for a dependency group in the target fmri. */ 8858 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 8859 switch (serr) { 8860 case SCF_ERROR_NONE: 8861 break; 8862 8863 case SCF_ERROR_NO_MEMORY: 8864 uu_die(gettext("Out of memory.\n")); 8865 /* NOTREACHED */ 8866 8867 case SCF_ERROR_INVALID_ARGUMENT: 8868 if (g_verbose) { 8869 if (scf_property_to_fmri(exp_prop, fmri, 8870 max_scf_fmri_len + 2) < 0) 8871 scfdie(); 8872 8873 warn(gettext("The value of %s is not a valid " 8874 "FMRI.\n"), fmri); 8875 } 8876 8877 export_property(exp_prop, exp_str, &pgelts, 0); 8878 continue; 8879 8880 case SCF_ERROR_CONSTRAINT_VIOLATED: 8881 if (g_verbose) { 8882 if (scf_property_to_fmri(exp_prop, fmri, 8883 max_scf_fmri_len + 2) < 0) 8884 scfdie(); 8885 8886 warn(gettext("The value of %s does not specify " 8887 "a service or an instance.\n"), fmri); 8888 } 8889 8890 export_property(exp_prop, exp_str, &pgelts, 0); 8891 continue; 8892 8893 case SCF_ERROR_NOT_FOUND: 8894 if (g_verbose) { 8895 if (scf_property_to_fmri(exp_prop, fmri, 8896 max_scf_fmri_len + 2) < 0) 8897 scfdie(); 8898 8899 warn(gettext("The entity specified by %s does " 8900 "not exist.\n"), fmri); 8901 } 8902 8903 export_property(exp_prop, exp_str, &pgelts, 0); 8904 continue; 8905 8906 default: 8907 #ifndef NDEBUG 8908 (void) fprintf(stderr, "%s:%d: %s() failed with " 8909 "unexpected error %d.\n", __FILE__, __LINE__, 8910 "fmri_to_entity", serr); 8911 #endif 8912 abort(); 8913 } 8914 8915 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) { 8916 if (scf_error() != SCF_ERROR_NOT_FOUND) 8917 scfdie(); 8918 8919 warn(gettext("Entity %s is missing dependency property " 8920 "group %s.\n"), fmri, exp_str); 8921 8922 export_property(exp_prop, NULL, &pgelts, 0); 8923 continue; 8924 } 8925 8926 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0) 8927 scfdie(); 8928 8929 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) { 8930 if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0) 8931 scfdie(); 8932 8933 warn(gettext("Property group %s is not of " 8934 "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY); 8935 8936 export_property(exp_prop, NULL, &pgelts, 0); 8937 continue; 8938 } 8939 8940 n = export_dependent(opg, exp_str, fmri); 8941 if (n == NULL) 8942 export_property(exp_prop, exp_str, &pgelts, 0); 8943 else { 8944 if (eelts->dependents == NULL) 8945 eelts->dependents = n; 8946 else 8947 (void) xmlAddSibling(eelts->dependents, 8948 n); 8949 } 8950 } 8951 if (ret == -1) 8952 scfdie(); 8953 8954 free(fmri); 8955 free(type); 8956 8957 scf_iter_destroy(iter); 8958 scf_pg_destroy(opg); 8959 8960 if (pgelts.propvals != NULL || pgelts.properties != NULL) 8961 export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework, 8962 eelts); 8963 } 8964 8965 static void 8966 make_node(xmlNodePtr *nodep, const char *name) 8967 { 8968 if (*nodep == NULL) { 8969 *nodep = xmlNewNode(NULL, (xmlChar *)name); 8970 if (*nodep == NULL) 8971 uu_die(emsg_create_xml); 8972 } 8973 } 8974 8975 static xmlNodePtr 8976 export_tm_loctext(scf_propertygroup_t *pg, const char *parname) 8977 { 8978 int ret; 8979 xmlNodePtr parent = NULL; 8980 xmlNodePtr loctext = NULL; 8981 8982 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8983 scfdie(); 8984 8985 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8986 if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 || 8987 prop_get_val(exp_prop, exp_val) != 0) 8988 continue; 8989 8990 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0) 8991 scfdie(); 8992 8993 make_node(&parent, parname); 8994 loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext", 8995 (xmlChar *)exp_str); 8996 if (loctext == NULL) 8997 uu_die(emsg_create_xml); 8998 8999 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9000 scfdie(); 9001 9002 safe_setprop(loctext, "xml:lang", exp_str); 9003 } 9004 9005 if (ret == -1) 9006 scfdie(); 9007 9008 return (parent); 9009 } 9010 9011 static xmlNodePtr 9012 export_tm_manpage(scf_propertygroup_t *pg) 9013 { 9014 xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage"); 9015 if (manpage == NULL) 9016 uu_die(emsg_create_xml); 9017 9018 if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 || 9019 set_attr_from_prop(exp_prop, manpage, "title") != 0 || 9020 pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 || 9021 set_attr_from_prop(exp_prop, manpage, "section") != 0) { 9022 xmlFreeNode(manpage); 9023 return (NULL); 9024 } 9025 9026 if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0) 9027 (void) set_attr_from_prop_default(exp_prop, 9028 manpage, "manpath", ":default"); 9029 9030 return (manpage); 9031 } 9032 9033 static xmlNodePtr 9034 export_tm_doc_link(scf_propertygroup_t *pg) 9035 { 9036 xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link"); 9037 if (doc_link == NULL) 9038 uu_die(emsg_create_xml); 9039 9040 if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 || 9041 set_attr_from_prop(exp_prop, doc_link, "name") != 0 || 9042 pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 || 9043 set_attr_from_prop(exp_prop, doc_link, "uri") != 0) { 9044 xmlFreeNode(doc_link); 9045 return (NULL); 9046 } 9047 return (doc_link); 9048 } 9049 9050 /* 9051 * Process template information for a service or instances. 9052 */ 9053 static void 9054 export_template(scf_propertygroup_t *pg, struct entity_elts *elts, 9055 struct template_elts *telts) 9056 { 9057 size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX); 9058 size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX); 9059 xmlNodePtr child = NULL; 9060 9061 if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0) 9062 scfdie(); 9063 9064 if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) { 9065 telts->common_name = export_tm_loctext(pg, "common_name"); 9066 if (telts->common_name == NULL) 9067 export_pg(pg, elts, 0); 9068 return; 9069 } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) { 9070 telts->description = export_tm_loctext(pg, "description"); 9071 if (telts->description == NULL) 9072 export_pg(pg, elts, 0); 9073 return; 9074 } 9075 9076 if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) { 9077 child = export_tm_manpage(pg); 9078 } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) { 9079 child = export_tm_doc_link(pg); 9080 } 9081 9082 if (child != NULL) { 9083 make_node(&telts->documentation, "documentation"); 9084 (void) xmlAddChild(telts->documentation, child); 9085 } else { 9086 export_pg(pg, elts, 0); 9087 } 9088 } 9089 9090 /* 9091 * Process the general property group for an instance. 9092 */ 9093 static void 9094 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode, 9095 struct entity_elts *elts) 9096 { 9097 uint8_t enabled; 9098 struct pg_elts pgelts; 9099 int ret; 9100 9101 /* enabled */ 9102 if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 && 9103 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9104 prop_get_val(exp_prop, exp_val) == 0) { 9105 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS) 9106 scfdie(); 9107 } else { 9108 enabled = 0; 9109 } 9110 9111 safe_setprop(inode, enabled_attr, enabled ? true : false); 9112 9113 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9114 scfdie(); 9115 9116 (void) memset(&pgelts, 0, sizeof (pgelts)); 9117 9118 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9119 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9120 scfdie(); 9121 9122 if (strcmp(exp_str, scf_property_enabled) == 0) { 9123 continue; 9124 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 9125 xmlNodePtr rnode, sfnode; 9126 9127 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 9128 if (rnode == NULL) 9129 uu_die(emsg_create_xml); 9130 9131 sfnode = xmlNewChild(rnode, NULL, 9132 (xmlChar *)"service_fmri", NULL); 9133 if (sfnode == NULL) 9134 uu_die(emsg_create_xml); 9135 9136 if (set_attr_from_prop(exp_prop, sfnode, 9137 value_attr) == 0) { 9138 elts->restarter = rnode; 9139 continue; 9140 } 9141 9142 xmlFreeNode(rnode); 9143 } 9144 9145 export_property(exp_prop, exp_str, &pgelts, 0); 9146 } 9147 if (ret == -1) 9148 scfdie(); 9149 9150 if (pgelts.propvals != NULL || pgelts.properties != NULL) 9151 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework, 9152 elts); 9153 } 9154 9155 /* 9156 * Put an instance element for the given instance into selts. 9157 */ 9158 static void 9159 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags) 9160 { 9161 xmlNodePtr n; 9162 boolean_t isdefault; 9163 struct entity_elts elts; 9164 struct template_elts template_elts; 9165 int ret; 9166 9167 n = xmlNewNode(NULL, (xmlChar *)"instance"); 9168 if (n == NULL) 9169 uu_die(emsg_create_xml); 9170 9171 /* name */ 9172 if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0) 9173 scfdie(); 9174 safe_setprop(n, name_attr, exp_str); 9175 isdefault = strcmp(exp_str, "default") == 0; 9176 9177 /* check existance of general pg (since general/enabled is required) */ 9178 if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) { 9179 if (scf_error() != SCF_ERROR_NOT_FOUND) 9180 scfdie(); 9181 9182 if (g_verbose) { 9183 if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0) 9184 scfdie(); 9185 9186 warn(gettext("Instance %s has no general property " 9187 "group; it will be marked disabled.\n"), exp_str); 9188 } 9189 9190 safe_setprop(n, enabled_attr, false); 9191 } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 || 9192 strcmp(exp_str, scf_group_framework) != 0) { 9193 if (g_verbose) { 9194 if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0) 9195 scfdie(); 9196 9197 warn(gettext("Property group %s is not of type " 9198 "framework; the instance will be marked " 9199 "disabled.\n"), exp_str); 9200 } 9201 9202 safe_setprop(n, enabled_attr, false); 9203 } 9204 9205 /* property groups */ 9206 if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0) 9207 scfdie(); 9208 9209 (void) memset(&elts, 0, sizeof (elts)); 9210 (void) memset(&template_elts, 0, sizeof (template_elts)); 9211 9212 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 9213 uint32_t pgflags; 9214 9215 if (scf_pg_get_flags(exp_pg, &pgflags) != 0) 9216 scfdie(); 9217 9218 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) 9219 continue; 9220 9221 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 9222 scfdie(); 9223 9224 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 9225 export_dependency(exp_pg, &elts); 9226 continue; 9227 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 9228 export_method(exp_pg, &elts); 9229 continue; 9230 } else if (strcmp(exp_str, scf_group_framework) == 0) { 9231 if (scf_pg_get_name(exp_pg, exp_str, 9232 max_scf_name_len + 1) < 0) 9233 scfdie(); 9234 9235 if (strcmp(exp_str, scf_pg_general) == 0) { 9236 export_inst_general(exp_pg, n, &elts); 9237 continue; 9238 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 9239 0) { 9240 export_method_context(exp_pg, &elts); 9241 continue; 9242 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 9243 export_dependents(exp_pg, &elts); 9244 continue; 9245 } 9246 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 9247 export_template(exp_pg, &elts, &template_elts); 9248 continue; 9249 } 9250 9251 /* Ordinary pg. */ 9252 export_pg(exp_pg, &elts, flags); 9253 } 9254 if (ret == -1) 9255 scfdie(); 9256 9257 if (template_elts.common_name != NULL) { 9258 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 9259 (void) xmlAddChild(elts.template, template_elts.common_name); 9260 (void) xmlAddChild(elts.template, template_elts.description); 9261 (void) xmlAddChild(elts.template, template_elts.documentation); 9262 } else { 9263 xmlFreeNode(template_elts.description); 9264 xmlFreeNode(template_elts.documentation); 9265 } 9266 9267 if (isdefault && elts.restarter == NULL && 9268 elts.dependencies == NULL && elts.method_context == NULL && 9269 elts.exec_methods == NULL && elts.property_groups == NULL && 9270 elts.template == NULL) { 9271 xmlChar *eval; 9272 9273 /* This is a default instance */ 9274 eval = xmlGetProp(n, (xmlChar *)enabled_attr); 9275 9276 xmlFreeNode(n); 9277 9278 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance"); 9279 if (n == NULL) 9280 uu_die(emsg_create_xml); 9281 9282 safe_setprop(n, enabled_attr, (char *)eval); 9283 xmlFree(eval); 9284 9285 selts->create_default_instance = n; 9286 } else { 9287 /* Assemble the children in order. */ 9288 (void) xmlAddChild(n, elts.restarter); 9289 (void) xmlAddChildList(n, elts.dependencies); 9290 (void) xmlAddChildList(n, elts.dependents); 9291 (void) xmlAddChild(n, elts.method_context); 9292 (void) xmlAddChildList(n, elts.exec_methods); 9293 (void) xmlAddChildList(n, elts.property_groups); 9294 (void) xmlAddChild(n, elts.template); 9295 9296 if (selts->instances == NULL) 9297 selts->instances = n; 9298 else 9299 (void) xmlAddSibling(selts->instances, n); 9300 } 9301 } 9302 9303 /* 9304 * Return a service element for the given service. 9305 */ 9306 static xmlNodePtr 9307 export_service(scf_service_t *svc, int flags) 9308 { 9309 xmlNodePtr snode; 9310 struct entity_elts elts; 9311 struct template_elts template_elts; 9312 int ret; 9313 9314 snode = xmlNewNode(NULL, (xmlChar *)"service"); 9315 if (snode == NULL) 9316 uu_die(emsg_create_xml); 9317 9318 /* Get & set name attribute */ 9319 if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0) 9320 scfdie(); 9321 safe_setprop(snode, name_attr, exp_str); 9322 9323 safe_setprop(snode, type_attr, "service"); 9324 safe_setprop(snode, "version", "0"); 9325 9326 /* Acquire child elements. */ 9327 if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS) 9328 scfdie(); 9329 9330 (void) memset(&elts, 0, sizeof (elts)); 9331 (void) memset(&template_elts, 0, sizeof (template_elts)); 9332 9333 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 9334 uint32_t pgflags; 9335 9336 if (scf_pg_get_flags(exp_pg, &pgflags) != 0) 9337 scfdie(); 9338 9339 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) 9340 continue; 9341 9342 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 9343 scfdie(); 9344 9345 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 9346 export_dependency(exp_pg, &elts); 9347 continue; 9348 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 9349 export_method(exp_pg, &elts); 9350 continue; 9351 } else if (strcmp(exp_str, scf_group_framework) == 0) { 9352 if (scf_pg_get_name(exp_pg, exp_str, 9353 max_scf_name_len + 1) < 0) 9354 scfdie(); 9355 9356 if (strcmp(exp_str, scf_pg_general) == 0) { 9357 export_svc_general(exp_pg, &elts); 9358 continue; 9359 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 9360 0) { 9361 export_method_context(exp_pg, &elts); 9362 continue; 9363 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 9364 export_dependents(exp_pg, &elts); 9365 continue; 9366 } 9367 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 9368 export_template(exp_pg, &elts, &template_elts); 9369 continue; 9370 } 9371 9372 export_pg(exp_pg, &elts, flags); 9373 } 9374 if (ret == -1) 9375 scfdie(); 9376 9377 if (template_elts.common_name != NULL) { 9378 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 9379 (void) xmlAddChild(elts.template, template_elts.common_name); 9380 (void) xmlAddChild(elts.template, template_elts.description); 9381 (void) xmlAddChild(elts.template, template_elts.documentation); 9382 } else { 9383 xmlFreeNode(template_elts.description); 9384 xmlFreeNode(template_elts.documentation); 9385 } 9386 9387 /* Iterate instances */ 9388 if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS) 9389 scfdie(); 9390 9391 while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1) 9392 export_instance(exp_inst, &elts, flags); 9393 if (ret == -1) 9394 scfdie(); 9395 9396 /* Now add all of the accumulated elements in order. */ 9397 (void) xmlAddChild(snode, elts.create_default_instance); 9398 (void) xmlAddChild(snode, elts.single_instance); 9399 (void) xmlAddChild(snode, elts.restarter); 9400 (void) xmlAddChildList(snode, elts.dependencies); 9401 (void) xmlAddChildList(snode, elts.dependents); 9402 (void) xmlAddChild(snode, elts.method_context); 9403 (void) xmlAddChildList(snode, elts.exec_methods); 9404 (void) xmlAddChildList(snode, elts.property_groups); 9405 (void) xmlAddChildList(snode, elts.instances); 9406 (void) xmlAddChild(snode, elts.stability); 9407 (void) xmlAddChild(snode, elts.template); 9408 9409 return (snode); 9410 } 9411 9412 static int 9413 export_callback(void *data, scf_walkinfo_t *wip) 9414 { 9415 FILE *f; 9416 xmlDocPtr doc; 9417 xmlNodePtr sb; 9418 int result; 9419 struct export_args *argsp = (struct export_args *)data; 9420 9421 if ((exp_inst = scf_instance_create(g_hndl)) == NULL || 9422 (exp_pg = scf_pg_create(g_hndl)) == NULL || 9423 (exp_prop = scf_property_create(g_hndl)) == NULL || 9424 (exp_val = scf_value_create(g_hndl)) == NULL || 9425 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 9426 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 9427 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 9428 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 9429 scfdie(); 9430 9431 exp_str_sz = max_scf_len + 1; 9432 exp_str = safe_malloc(exp_str_sz); 9433 9434 if (argsp->filename != NULL) { 9435 errno = 0; 9436 f = fopen(argsp->filename, "wb"); 9437 if (f == NULL) { 9438 if (errno == 0) 9439 uu_die(gettext("Could not open \"%s\": no free " 9440 "stdio streams.\n"), argsp->filename); 9441 else 9442 uu_die(gettext("Could not open \"%s\""), 9443 argsp->filename); 9444 } 9445 } else 9446 f = stdout; 9447 9448 doc = xmlNewDoc((xmlChar *)"1.0"); 9449 if (doc == NULL) 9450 uu_die(gettext("Could not create XML document.\n")); 9451 9452 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 9453 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 9454 uu_die(emsg_create_xml); 9455 9456 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 9457 if (sb == NULL) 9458 uu_die(emsg_create_xml); 9459 safe_setprop(sb, type_attr, "manifest"); 9460 safe_setprop(sb, name_attr, "export"); 9461 (void) xmlAddSibling(doc->children, sb); 9462 9463 (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags)); 9464 9465 result = write_service_bundle(doc, f); 9466 9467 free(exp_str); 9468 scf_iter_destroy(exp_val_iter); 9469 scf_iter_destroy(exp_prop_iter); 9470 scf_iter_destroy(exp_pg_iter); 9471 scf_iter_destroy(exp_inst_iter); 9472 scf_value_destroy(exp_val); 9473 scf_property_destroy(exp_prop); 9474 scf_pg_destroy(exp_pg); 9475 scf_instance_destroy(exp_inst); 9476 9477 xmlFreeDoc(doc); 9478 9479 if (f != stdout) 9480 (void) fclose(f); 9481 9482 return (result); 9483 } 9484 9485 /* 9486 * Get the service named by fmri, build an XML tree which represents it, and 9487 * dump it into filename (or stdout if filename is NULL). 9488 */ 9489 int 9490 lscf_service_export(char *fmri, const char *filename, int flags) 9491 { 9492 struct export_args args; 9493 int ret, err; 9494 9495 lscf_prep_hndl(); 9496 9497 bzero(&args, sizeof (args)); 9498 args.filename = filename; 9499 args.flags = flags; 9500 9501 err = 0; 9502 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 9503 SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback, 9504 &args, &err, semerr)) != 0) { 9505 if (ret != -1) 9506 semerr(gettext("Failed to walk instances: %s\n"), 9507 scf_strerror(ret)); 9508 return (-1); 9509 } 9510 9511 /* 9512 * Error message has already been printed. 9513 */ 9514 if (err != 0) 9515 return (-1); 9516 9517 return (0); 9518 } 9519 9520 9521 /* 9522 * Archive 9523 */ 9524 9525 static xmlNodePtr 9526 make_archive(int flags) 9527 { 9528 xmlNodePtr sb; 9529 scf_scope_t *scope; 9530 scf_service_t *svc; 9531 scf_iter_t *iter; 9532 int r; 9533 9534 if ((scope = scf_scope_create(g_hndl)) == NULL || 9535 (svc = scf_service_create(g_hndl)) == NULL || 9536 (iter = scf_iter_create(g_hndl)) == NULL || 9537 (exp_inst = scf_instance_create(g_hndl)) == NULL || 9538 (exp_pg = scf_pg_create(g_hndl)) == NULL || 9539 (exp_prop = scf_property_create(g_hndl)) == NULL || 9540 (exp_val = scf_value_create(g_hndl)) == NULL || 9541 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 9542 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 9543 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 9544 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 9545 scfdie(); 9546 9547 exp_str_sz = max_scf_len + 1; 9548 exp_str = safe_malloc(exp_str_sz); 9549 9550 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 9551 if (sb == NULL) 9552 uu_die(emsg_create_xml); 9553 safe_setprop(sb, type_attr, "archive"); 9554 safe_setprop(sb, name_attr, "none"); 9555 9556 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) 9557 scfdie(); 9558 if (scf_iter_scope_services(iter, scope) != 0) 9559 scfdie(); 9560 9561 for (;;) { 9562 r = scf_iter_next_service(iter, svc); 9563 if (r == 0) 9564 break; 9565 if (r != 1) 9566 scfdie(); 9567 9568 if (scf_service_get_name(svc, exp_str, 9569 max_scf_name_len + 1) < 0) 9570 scfdie(); 9571 9572 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0) 9573 continue; 9574 9575 xmlAddChild(sb, export_service(svc, flags)); 9576 } 9577 9578 free(exp_str); 9579 9580 scf_iter_destroy(exp_val_iter); 9581 scf_iter_destroy(exp_prop_iter); 9582 scf_iter_destroy(exp_pg_iter); 9583 scf_iter_destroy(exp_inst_iter); 9584 scf_value_destroy(exp_val); 9585 scf_property_destroy(exp_prop); 9586 scf_pg_destroy(exp_pg); 9587 scf_instance_destroy(exp_inst); 9588 scf_iter_destroy(iter); 9589 scf_service_destroy(svc); 9590 scf_scope_destroy(scope); 9591 9592 return (sb); 9593 } 9594 9595 int 9596 lscf_archive(const char *filename, int flags) 9597 { 9598 FILE *f; 9599 xmlDocPtr doc; 9600 int result; 9601 9602 lscf_prep_hndl(); 9603 9604 if (filename != NULL) { 9605 errno = 0; 9606 f = fopen(filename, "wb"); 9607 if (f == NULL) { 9608 if (errno == 0) 9609 uu_die(gettext("Could not open \"%s\": no free " 9610 "stdio streams.\n"), filename); 9611 else 9612 uu_die(gettext("Could not open \"%s\""), 9613 filename); 9614 } 9615 } else 9616 f = stdout; 9617 9618 doc = xmlNewDoc((xmlChar *)"1.0"); 9619 if (doc == NULL) 9620 uu_die(gettext("Could not create XML document.\n")); 9621 9622 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 9623 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 9624 uu_die(emsg_create_xml); 9625 9626 (void) xmlAddSibling(doc->children, make_archive(flags)); 9627 9628 result = write_service_bundle(doc, f); 9629 9630 xmlFreeDoc(doc); 9631 9632 if (f != stdout) 9633 (void) fclose(f); 9634 9635 return (result); 9636 } 9637 9638 9639 /* 9640 * "Extract" a profile. 9641 */ 9642 int 9643 lscf_profile_extract(const char *filename) 9644 { 9645 FILE *f; 9646 xmlDocPtr doc; 9647 xmlNodePtr sb, snode, inode; 9648 scf_scope_t *scope; 9649 scf_service_t *svc; 9650 scf_instance_t *inst; 9651 scf_propertygroup_t *pg; 9652 scf_property_t *prop; 9653 scf_value_t *val; 9654 scf_iter_t *siter, *iiter; 9655 int r, s; 9656 char *namebuf; 9657 uint8_t b; 9658 int result; 9659 9660 lscf_prep_hndl(); 9661 9662 if (filename != NULL) { 9663 errno = 0; 9664 f = fopen(filename, "wb"); 9665 if (f == NULL) { 9666 if (errno == 0) 9667 uu_die(gettext("Could not open \"%s\": no " 9668 "free stdio streams.\n"), filename); 9669 else 9670 uu_die(gettext("Could not open \"%s\""), 9671 filename); 9672 } 9673 } else 9674 f = stdout; 9675 9676 doc = xmlNewDoc((xmlChar *)"1.0"); 9677 if (doc == NULL) 9678 uu_die(gettext("Could not create XML document.\n")); 9679 9680 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 9681 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 9682 uu_die(emsg_create_xml); 9683 9684 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 9685 if (sb == NULL) 9686 uu_die(emsg_create_xml); 9687 safe_setprop(sb, type_attr, "profile"); 9688 safe_setprop(sb, name_attr, "extract"); 9689 (void) xmlAddSibling(doc->children, sb); 9690 9691 if ((scope = scf_scope_create(g_hndl)) == NULL || 9692 (svc = scf_service_create(g_hndl)) == NULL || 9693 (inst = scf_instance_create(g_hndl)) == NULL || 9694 (pg = scf_pg_create(g_hndl)) == NULL || 9695 (prop = scf_property_create(g_hndl)) == NULL || 9696 (val = scf_value_create(g_hndl)) == NULL || 9697 (siter = scf_iter_create(g_hndl)) == NULL || 9698 (iiter = scf_iter_create(g_hndl)) == NULL) 9699 scfdie(); 9700 9701 if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS) 9702 scfdie(); 9703 9704 if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS) 9705 scfdie(); 9706 9707 namebuf = safe_malloc(max_scf_name_len + 1); 9708 9709 while ((r = scf_iter_next_service(siter, svc)) == 1) { 9710 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS) 9711 scfdie(); 9712 9713 snode = xmlNewNode(NULL, (xmlChar *)"service"); 9714 if (snode == NULL) 9715 uu_die(emsg_create_xml); 9716 9717 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) < 9718 0) 9719 scfdie(); 9720 9721 safe_setprop(snode, name_attr, namebuf); 9722 9723 safe_setprop(snode, type_attr, "service"); 9724 safe_setprop(snode, "version", "0"); 9725 9726 while ((s = scf_iter_next_instance(iiter, inst)) == 1) { 9727 if (scf_instance_get_pg(inst, scf_pg_general, pg) != 9728 SCF_SUCCESS) { 9729 if (scf_error() != SCF_ERROR_NOT_FOUND) 9730 scfdie(); 9731 9732 if (g_verbose) { 9733 ssize_t len; 9734 char *fmri; 9735 9736 len = 9737 scf_instance_to_fmri(inst, NULL, 0); 9738 if (len < 0) 9739 scfdie(); 9740 9741 fmri = safe_malloc(len + 1); 9742 9743 if (scf_instance_to_fmri(inst, fmri, 9744 len + 1) < 0) 9745 scfdie(); 9746 9747 warn("Instance %s has no \"%s\" " 9748 "property group.\n", fmri, 9749 scf_pg_general); 9750 9751 free(fmri); 9752 } 9753 9754 continue; 9755 } 9756 9757 if (pg_get_prop(pg, scf_property_enabled, prop) != 0 || 9758 prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 || 9759 prop_get_val(prop, val) != 0) 9760 continue; 9761 9762 inode = xmlNewChild(snode, NULL, (xmlChar *)"instance", 9763 NULL); 9764 if (inode == NULL) 9765 uu_die(emsg_create_xml); 9766 9767 if (scf_instance_get_name(inst, namebuf, 9768 max_scf_name_len + 1) < 0) 9769 scfdie(); 9770 9771 safe_setprop(inode, name_attr, namebuf); 9772 9773 if (scf_value_get_boolean(val, &b) != SCF_SUCCESS) 9774 scfdie(); 9775 9776 safe_setprop(inode, enabled_attr, b ? true : false); 9777 } 9778 if (s < 0) 9779 scfdie(); 9780 9781 if (snode->children != NULL) 9782 xmlAddChild(sb, snode); 9783 else 9784 xmlFreeNode(snode); 9785 } 9786 if (r < 0) 9787 scfdie(); 9788 9789 free(namebuf); 9790 9791 result = write_service_bundle(doc, f); 9792 9793 xmlFreeDoc(doc); 9794 9795 if (f != stdout) 9796 (void) fclose(f); 9797 9798 return (result); 9799 } 9800 9801 9802 /* 9803 * Entity manipulation commands 9804 */ 9805 9806 /* 9807 * Entity selection. If no entity is selected, then the current scope is in 9808 * cur_scope, and cur_svc and cur_inst are NULL. When a service is selected, 9809 * only cur_inst is NULL, and when an instance is selected, none are NULL. 9810 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and 9811 * cur_inst will be non-NULL. 9812 */ 9813 9814 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */ 9815 static int 9816 select_inst(const char *name) 9817 { 9818 scf_instance_t *inst; 9819 scf_error_t err; 9820 9821 assert(cur_svc != NULL); 9822 9823 inst = scf_instance_create(g_hndl); 9824 if (inst == NULL) 9825 scfdie(); 9826 9827 if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) { 9828 cur_inst = inst; 9829 return (0); 9830 } 9831 9832 err = scf_error(); 9833 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 9834 scfdie(); 9835 9836 scf_instance_destroy(inst); 9837 return (1); 9838 } 9839 9840 /* Returns as above. */ 9841 static int 9842 select_svc(const char *name) 9843 { 9844 scf_service_t *svc; 9845 scf_error_t err; 9846 9847 assert(cur_scope != NULL); 9848 9849 svc = scf_service_create(g_hndl); 9850 if (svc == NULL) 9851 scfdie(); 9852 9853 if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) { 9854 cur_svc = svc; 9855 return (0); 9856 } 9857 9858 err = scf_error(); 9859 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 9860 scfdie(); 9861 9862 scf_service_destroy(svc); 9863 return (1); 9864 } 9865 9866 /* ARGSUSED */ 9867 static int 9868 select_callback(void *unused, scf_walkinfo_t *wip) 9869 { 9870 scf_instance_t *inst; 9871 scf_service_t *svc; 9872 scf_scope_t *scope; 9873 9874 if (wip->inst != NULL) { 9875 if ((scope = scf_scope_create(g_hndl)) == NULL || 9876 (svc = scf_service_create(g_hndl)) == NULL || 9877 (inst = scf_instance_create(g_hndl)) == NULL) 9878 scfdie(); 9879 9880 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 9881 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 9882 scfdie(); 9883 } else { 9884 assert(wip->svc != NULL); 9885 9886 if ((scope = scf_scope_create(g_hndl)) == NULL || 9887 (svc = scf_service_create(g_hndl)) == NULL) 9888 scfdie(); 9889 9890 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 9891 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 9892 scfdie(); 9893 9894 inst = NULL; 9895 } 9896 9897 /* Clear out the current selection */ 9898 assert(cur_scope != NULL); 9899 scf_scope_destroy(cur_scope); 9900 scf_service_destroy(cur_svc); 9901 scf_instance_destroy(cur_inst); 9902 9903 cur_scope = scope; 9904 cur_svc = svc; 9905 cur_inst = inst; 9906 9907 return (0); 9908 } 9909 9910 static int 9911 validate_callback(void *fmri_p, scf_walkinfo_t *wip) 9912 { 9913 char **fmri = fmri_p; 9914 9915 *fmri = strdup(wip->fmri); 9916 if (*fmri == NULL) 9917 uu_die(gettext("Out of memory.\n")); 9918 9919 return (0); 9920 } 9921 9922 /* 9923 * validate [fmri] 9924 * Perform the validation of an FMRI instance. 9925 */ 9926 void 9927 lscf_validate_fmri(const char *fmri) 9928 { 9929 int ret = 0; 9930 size_t inst_sz; 9931 char *inst_fmri = NULL; 9932 scf_tmpl_errors_t *errs = NULL; 9933 char *snapbuf = NULL; 9934 9935 lscf_prep_hndl(); 9936 9937 if (fmri == NULL) { 9938 inst_sz = max_scf_fmri_len + 1; 9939 inst_fmri = safe_malloc(inst_sz); 9940 9941 if (cur_snap != NULL) { 9942 snapbuf = safe_malloc(max_scf_name_len + 1); 9943 if (scf_snapshot_get_name(cur_snap, snapbuf, 9944 max_scf_name_len + 1) < 0) 9945 scfdie(); 9946 } 9947 if (cur_inst == NULL) { 9948 semerr(gettext("No instance selected\n")); 9949 goto cleanup; 9950 } else if (scf_instance_to_fmri(cur_inst, inst_fmri, 9951 inst_sz) >= inst_sz) { 9952 /* sanity check. Should never get here */ 9953 uu_die(gettext("Unexpected error! file %s, line %d\n"), 9954 __FILE__, __LINE__); 9955 } 9956 } else { 9957 scf_error_t scf_err; 9958 int err = 0; 9959 9960 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0, 9961 validate_callback, &inst_fmri, &err, semerr)) != 0) { 9962 uu_warn("Failed to walk instances: %s\n", 9963 scf_strerror(scf_err)); 9964 goto cleanup; 9965 } 9966 if (err != 0) { 9967 /* error message displayed by scf_walk_fmri */ 9968 goto cleanup; 9969 } 9970 } 9971 9972 ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs, 9973 SCF_TMPL_VALIDATE_FLAG_CURRENT); 9974 if (ret == -1) { 9975 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) { 9976 warn(gettext("Template data for %s is invalid. " 9977 "Consider reverting to a previous snapshot or " 9978 "restoring original configuration.\n"), inst_fmri); 9979 } else { 9980 uu_warn("%s: %s\n", 9981 gettext("Error validating the instance"), 9982 scf_strerror(scf_error())); 9983 } 9984 } else if (ret == 1 && errs != NULL) { 9985 scf_tmpl_error_t *err = NULL; 9986 char *msg; 9987 size_t len = 256; /* initial error buffer size */ 9988 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ? 9989 SCF_TMPL_STRERROR_HUMAN : 0; 9990 9991 msg = safe_malloc(len); 9992 9993 while ((err = scf_tmpl_next_error(errs)) != NULL) { 9994 int ret; 9995 9996 if ((ret = scf_tmpl_strerror(err, msg, len, 9997 flag)) >= len) { 9998 len = ret + 1; 9999 msg = realloc(msg, len); 10000 if (msg == NULL) 10001 uu_die(gettext( 10002 "Out of memory.\n")); 10003 (void) scf_tmpl_strerror(err, msg, len, 10004 flag); 10005 } 10006 (void) fprintf(stderr, "%s\n", msg); 10007 } 10008 if (msg != NULL) 10009 free(msg); 10010 } 10011 if (errs != NULL) 10012 scf_tmpl_errors_destroy(errs); 10013 10014 cleanup: 10015 free(inst_fmri); 10016 free(snapbuf); 10017 } 10018 10019 static void 10020 lscf_validate_file(const char *filename) 10021 { 10022 tmpl_errors_t *errs; 10023 10024 bundle_t *b = internal_bundle_new(); 10025 if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) { 10026 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) { 10027 tmpl_errors_print(stderr, errs, ""); 10028 semerr(gettext("Validation failed.\n")); 10029 } 10030 tmpl_errors_destroy(errs); 10031 } 10032 (void) internal_bundle_free(b); 10033 } 10034 10035 /* 10036 * validate [fmri|file] 10037 */ 10038 void 10039 lscf_validate(const char *arg) 10040 { 10041 const char *str; 10042 10043 if (strncmp(arg, SCF_FMRI_FILE_PREFIX, 10044 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) { 10045 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1; 10046 lscf_validate_file(str); 10047 } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX, 10048 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) { 10049 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1; 10050 lscf_validate_fmri(str); 10051 } else if (access(arg, R_OK | F_OK) == 0) { 10052 lscf_validate_file(arg); 10053 } else { 10054 lscf_validate_fmri(arg); 10055 } 10056 } 10057 10058 void 10059 lscf_select(const char *fmri) 10060 { 10061 int ret, err; 10062 10063 lscf_prep_hndl(); 10064 10065 if (cur_snap != NULL) { 10066 struct snaplevel *elt; 10067 char *buf; 10068 10069 /* Error unless name is that of the next level. */ 10070 elt = uu_list_next(cur_levels, cur_elt); 10071 if (elt == NULL) { 10072 semerr(gettext("No children.\n")); 10073 return; 10074 } 10075 10076 buf = safe_malloc(max_scf_name_len + 1); 10077 10078 if (scf_snaplevel_get_instance_name(elt->sl, buf, 10079 max_scf_name_len + 1) < 0) 10080 scfdie(); 10081 10082 if (strcmp(buf, fmri) != 0) { 10083 semerr(gettext("No such child.\n")); 10084 free(buf); 10085 return; 10086 } 10087 10088 free(buf); 10089 10090 cur_elt = elt; 10091 cur_level = elt->sl; 10092 return; 10093 } 10094 10095 /* 10096 * Special case for 'svc:', which takes the user to the scope level. 10097 */ 10098 if (strcmp(fmri, "svc:") == 0) { 10099 scf_instance_destroy(cur_inst); 10100 scf_service_destroy(cur_svc); 10101 cur_inst = NULL; 10102 cur_svc = NULL; 10103 return; 10104 } 10105 10106 /* 10107 * Special case for ':properties'. This appears as part of 'list' but 10108 * can't be selected. Give a more helpful error message in this case. 10109 */ 10110 if (strcmp(fmri, ":properties") == 0) { 10111 semerr(gettext(":properties is not an entity. Try 'listprop' " 10112 "to list properties.\n")); 10113 return; 10114 } 10115 10116 /* 10117 * First try the argument as relative to the current selection. 10118 */ 10119 if (cur_inst != NULL) { 10120 /* EMPTY */; 10121 } else if (cur_svc != NULL) { 10122 if (select_inst(fmri) != 1) 10123 return; 10124 } else { 10125 if (select_svc(fmri) != 1) 10126 return; 10127 } 10128 10129 err = 0; 10130 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 10131 select_callback, NULL, &err, semerr)) != 0) { 10132 semerr(gettext("Failed to walk instances: %s\n"), 10133 scf_strerror(ret)); 10134 } 10135 } 10136 10137 void 10138 lscf_unselect(void) 10139 { 10140 lscf_prep_hndl(); 10141 10142 if (cur_snap != NULL) { 10143 struct snaplevel *elt; 10144 10145 elt = uu_list_prev(cur_levels, cur_elt); 10146 if (elt == NULL) { 10147 semerr(gettext("No parent levels.\n")); 10148 } else { 10149 cur_elt = elt; 10150 cur_level = elt->sl; 10151 } 10152 } else if (cur_inst != NULL) { 10153 scf_instance_destroy(cur_inst); 10154 cur_inst = NULL; 10155 } else if (cur_svc != NULL) { 10156 scf_service_destroy(cur_svc); 10157 cur_svc = NULL; 10158 } else { 10159 semerr(gettext("Cannot unselect at scope level.\n")); 10160 } 10161 } 10162 10163 /* 10164 * Return the FMRI of the current selection, for the prompt. 10165 */ 10166 void 10167 lscf_get_selection_str(char *buf, size_t bufsz) 10168 { 10169 char *cp; 10170 ssize_t fmrilen, szret; 10171 boolean_t deleted = B_FALSE; 10172 10173 if (g_hndl == NULL) { 10174 (void) strlcpy(buf, "svc:", bufsz); 10175 return; 10176 } 10177 10178 if (cur_level != NULL) { 10179 assert(cur_snap != NULL); 10180 10181 /* [ snapshot ] FMRI [: instance ] */ 10182 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len 10183 + 2 + max_scf_name_len + 1 + 1); 10184 10185 buf[0] = '['; 10186 10187 szret = scf_snapshot_get_name(cur_snap, buf + 1, 10188 max_scf_name_len + 1); 10189 if (szret < 0) { 10190 if (scf_error() != SCF_ERROR_DELETED) 10191 scfdie(); 10192 10193 goto snap_deleted; 10194 } 10195 10196 (void) strcat(buf, "]svc:/"); 10197 10198 cp = strchr(buf, '\0'); 10199 10200 szret = scf_snaplevel_get_service_name(cur_level, cp, 10201 max_scf_name_len + 1); 10202 if (szret < 0) { 10203 if (scf_error() != SCF_ERROR_DELETED) 10204 scfdie(); 10205 10206 goto snap_deleted; 10207 } 10208 10209 cp = strchr(cp, '\0'); 10210 10211 if (snaplevel_is_instance(cur_level)) { 10212 *cp++ = ':'; 10213 10214 if (scf_snaplevel_get_instance_name(cur_level, cp, 10215 max_scf_name_len + 1) < 0) { 10216 if (scf_error() != SCF_ERROR_DELETED) 10217 scfdie(); 10218 10219 goto snap_deleted; 10220 } 10221 } else { 10222 *cp++ = '['; 10223 *cp++ = ':'; 10224 10225 if (scf_instance_get_name(cur_inst, cp, 10226 max_scf_name_len + 1) < 0) { 10227 if (scf_error() != SCF_ERROR_DELETED) 10228 scfdie(); 10229 10230 goto snap_deleted; 10231 } 10232 10233 (void) strcat(buf, "]"); 10234 } 10235 10236 return; 10237 10238 snap_deleted: 10239 deleted = B_TRUE; 10240 free(buf); 10241 unselect_cursnap(); 10242 } 10243 10244 assert(cur_snap == NULL); 10245 10246 if (cur_inst != NULL) { 10247 assert(cur_svc != NULL); 10248 assert(cur_scope != NULL); 10249 10250 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz); 10251 if (fmrilen >= 0) { 10252 assert(fmrilen < bufsz); 10253 if (deleted) 10254 warn(emsg_deleted); 10255 return; 10256 } 10257 10258 if (scf_error() != SCF_ERROR_DELETED) 10259 scfdie(); 10260 10261 deleted = B_TRUE; 10262 10263 scf_instance_destroy(cur_inst); 10264 cur_inst = NULL; 10265 } 10266 10267 if (cur_svc != NULL) { 10268 assert(cur_scope != NULL); 10269 10270 szret = scf_service_to_fmri(cur_svc, buf, bufsz); 10271 if (szret >= 0) { 10272 assert(szret < bufsz); 10273 if (deleted) 10274 warn(emsg_deleted); 10275 return; 10276 } 10277 10278 if (scf_error() != SCF_ERROR_DELETED) 10279 scfdie(); 10280 10281 deleted = B_TRUE; 10282 scf_service_destroy(cur_svc); 10283 cur_svc = NULL; 10284 } 10285 10286 assert(cur_scope != NULL); 10287 fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz); 10288 10289 if (fmrilen < 0) 10290 scfdie(); 10291 10292 assert(fmrilen < bufsz); 10293 if (deleted) 10294 warn(emsg_deleted); 10295 } 10296 10297 /* 10298 * Entity listing. Entities and colon namespaces (e.g., :properties and 10299 * :statistics) are listed for the current selection. 10300 */ 10301 void 10302 lscf_list(const char *pattern) 10303 { 10304 scf_iter_t *iter; 10305 char *buf; 10306 int ret; 10307 10308 lscf_prep_hndl(); 10309 10310 if (cur_level != NULL) { 10311 struct snaplevel *elt; 10312 10313 (void) fputs(COLON_NAMESPACES, stdout); 10314 10315 elt = uu_list_next(cur_levels, cur_elt); 10316 if (elt == NULL) 10317 return; 10318 10319 /* 10320 * For now, we know that the next level is an instance. But 10321 * if we ever have multiple scopes, this could be complicated. 10322 */ 10323 buf = safe_malloc(max_scf_name_len + 1); 10324 if (scf_snaplevel_get_instance_name(elt->sl, buf, 10325 max_scf_name_len + 1) >= 0) { 10326 (void) puts(buf); 10327 } else { 10328 if (scf_error() != SCF_ERROR_DELETED) 10329 scfdie(); 10330 } 10331 10332 free(buf); 10333 10334 return; 10335 } 10336 10337 if (cur_inst != NULL) { 10338 (void) fputs(COLON_NAMESPACES, stdout); 10339 return; 10340 } 10341 10342 iter = scf_iter_create(g_hndl); 10343 if (iter == NULL) 10344 scfdie(); 10345 10346 buf = safe_malloc(max_scf_name_len + 1); 10347 10348 if (cur_svc != NULL) { 10349 /* List the instances in this service. */ 10350 scf_instance_t *inst; 10351 10352 inst = scf_instance_create(g_hndl); 10353 if (inst == NULL) 10354 scfdie(); 10355 10356 if (scf_iter_service_instances(iter, cur_svc) == 0) { 10357 safe_printf(COLON_NAMESPACES); 10358 10359 for (;;) { 10360 ret = scf_iter_next_instance(iter, inst); 10361 if (ret == 0) 10362 break; 10363 if (ret != 1) { 10364 if (scf_error() != SCF_ERROR_DELETED) 10365 scfdie(); 10366 10367 break; 10368 } 10369 10370 if (scf_instance_get_name(inst, buf, 10371 max_scf_name_len + 1) >= 0) { 10372 if (pattern == NULL || 10373 fnmatch(pattern, buf, 0) == 0) 10374 (void) puts(buf); 10375 } else { 10376 if (scf_error() != SCF_ERROR_DELETED) 10377 scfdie(); 10378 } 10379 } 10380 } else { 10381 if (scf_error() != SCF_ERROR_DELETED) 10382 scfdie(); 10383 } 10384 10385 scf_instance_destroy(inst); 10386 } else { 10387 /* List the services in this scope. */ 10388 scf_service_t *svc; 10389 10390 assert(cur_scope != NULL); 10391 10392 svc = scf_service_create(g_hndl); 10393 if (svc == NULL) 10394 scfdie(); 10395 10396 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS) 10397 scfdie(); 10398 10399 for (;;) { 10400 ret = scf_iter_next_service(iter, svc); 10401 if (ret == 0) 10402 break; 10403 if (ret != 1) 10404 scfdie(); 10405 10406 if (scf_service_get_name(svc, buf, 10407 max_scf_name_len + 1) >= 0) { 10408 if (pattern == NULL || 10409 fnmatch(pattern, buf, 0) == 0) 10410 safe_printf("%s\n", buf); 10411 } else { 10412 if (scf_error() != SCF_ERROR_DELETED) 10413 scfdie(); 10414 } 10415 } 10416 10417 scf_service_destroy(svc); 10418 } 10419 10420 free(buf); 10421 scf_iter_destroy(iter); 10422 } 10423 10424 /* 10425 * Entity addition. Creates an empty entity in the current selection. 10426 */ 10427 void 10428 lscf_add(const char *name) 10429 { 10430 lscf_prep_hndl(); 10431 10432 if (cur_snap != NULL) { 10433 semerr(emsg_cant_modify_snapshots); 10434 } else if (cur_inst != NULL) { 10435 semerr(gettext("Cannot add entities to an instance.\n")); 10436 } else if (cur_svc != NULL) { 10437 10438 if (scf_service_add_instance(cur_svc, name, NULL) != 10439 SCF_SUCCESS) { 10440 switch (scf_error()) { 10441 case SCF_ERROR_INVALID_ARGUMENT: 10442 semerr(gettext("Invalid name.\n")); 10443 break; 10444 10445 case SCF_ERROR_EXISTS: 10446 semerr(gettext("Instance already exists.\n")); 10447 break; 10448 10449 case SCF_ERROR_PERMISSION_DENIED: 10450 semerr(emsg_permission_denied); 10451 break; 10452 10453 default: 10454 scfdie(); 10455 } 10456 } 10457 } else { 10458 assert(cur_scope != NULL); 10459 10460 if (scf_scope_add_service(cur_scope, name, NULL) != 10461 SCF_SUCCESS) { 10462 switch (scf_error()) { 10463 case SCF_ERROR_INVALID_ARGUMENT: 10464 semerr(gettext("Invalid name.\n")); 10465 break; 10466 10467 case SCF_ERROR_EXISTS: 10468 semerr(gettext("Service already exists.\n")); 10469 break; 10470 10471 case SCF_ERROR_PERMISSION_DENIED: 10472 semerr(emsg_permission_denied); 10473 break; 10474 10475 case SCF_ERROR_BACKEND_READONLY: 10476 semerr(emsg_read_only); 10477 break; 10478 10479 default: 10480 scfdie(); 10481 } 10482 } 10483 } 10484 } 10485 10486 /* return 1 if the entity has no persistent pgs, else return 0 */ 10487 static int 10488 entity_has_no_pgs(void *ent, int isservice) 10489 { 10490 scf_iter_t *iter = NULL; 10491 scf_propertygroup_t *pg = NULL; 10492 uint32_t flags; 10493 int err; 10494 int ret = 1; 10495 10496 if ((iter = scf_iter_create(g_hndl)) == NULL || 10497 (pg = scf_pg_create(g_hndl)) == NULL) 10498 scfdie(); 10499 10500 if (isservice) { 10501 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0) 10502 scfdie(); 10503 } else { 10504 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0) 10505 scfdie(); 10506 } 10507 10508 while ((err = scf_iter_next_pg(iter, pg)) == 1) { 10509 if (scf_pg_get_flags(pg, &flags) != 0) 10510 scfdie(); 10511 10512 /* skip nonpersistent pgs */ 10513 if (flags & SCF_PG_FLAG_NONPERSISTENT) 10514 continue; 10515 10516 ret = 0; 10517 break; 10518 } 10519 10520 if (err == -1) 10521 scfdie(); 10522 10523 scf_pg_destroy(pg); 10524 scf_iter_destroy(iter); 10525 10526 return (ret); 10527 } 10528 10529 /* return 1 if the service has no instances, else return 0 */ 10530 static int 10531 svc_has_no_insts(scf_service_t *svc) 10532 { 10533 scf_instance_t *inst; 10534 scf_iter_t *iter; 10535 int r; 10536 int ret = 1; 10537 10538 if ((inst = scf_instance_create(g_hndl)) == NULL || 10539 (iter = scf_iter_create(g_hndl)) == NULL) 10540 scfdie(); 10541 10542 if (scf_iter_service_instances(iter, svc) != 0) 10543 scfdie(); 10544 10545 r = scf_iter_next_instance(iter, inst); 10546 if (r == 1) { 10547 ret = 0; 10548 } else if (r == 0) { 10549 ret = 1; 10550 } else if (r == -1) { 10551 scfdie(); 10552 } else { 10553 bad_error("scf_iter_next_instance", r); 10554 } 10555 10556 scf_iter_destroy(iter); 10557 scf_instance_destroy(inst); 10558 10559 return (ret); 10560 } 10561 10562 /* 10563 * Entity deletion. 10564 */ 10565 10566 /* 10567 * Delete the property group <fmri>/:properties/<name>. Returns 10568 * SCF_ERROR_NONE on success (or if the entity is not found), 10569 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if 10570 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was 10571 * denied. 10572 */ 10573 static scf_error_t 10574 delete_dependency_pg(const char *fmri, const char *name) 10575 { 10576 void *entity = NULL; 10577 int isservice; 10578 scf_propertygroup_t *pg = NULL; 10579 scf_error_t result; 10580 char *pgty; 10581 scf_service_t *svc = NULL; 10582 scf_instance_t *inst = NULL; 10583 scf_iter_t *iter = NULL; 10584 char *name_buf = NULL; 10585 10586 result = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 10587 switch (result) { 10588 case SCF_ERROR_NONE: 10589 break; 10590 10591 case SCF_ERROR_NO_MEMORY: 10592 uu_die(gettext("Out of memory.\n")); 10593 /* NOTREACHED */ 10594 10595 case SCF_ERROR_INVALID_ARGUMENT: 10596 case SCF_ERROR_CONSTRAINT_VIOLATED: 10597 return (SCF_ERROR_INVALID_ARGUMENT); 10598 10599 case SCF_ERROR_NOT_FOUND: 10600 result = SCF_ERROR_NONE; 10601 goto out; 10602 10603 default: 10604 bad_error("fmri_to_entity", result); 10605 } 10606 10607 pg = scf_pg_create(g_hndl); 10608 if (pg == NULL) 10609 scfdie(); 10610 10611 if (entity_get_pg(entity, isservice, name, pg) != 0) { 10612 if (scf_error() != SCF_ERROR_NOT_FOUND) 10613 scfdie(); 10614 10615 result = SCF_ERROR_NONE; 10616 goto out; 10617 } 10618 10619 pgty = safe_malloc(max_scf_pg_type_len + 1); 10620 10621 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 10622 scfdie(); 10623 10624 if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) { 10625 result = SCF_ERROR_TYPE_MISMATCH; 10626 free(pgty); 10627 goto out; 10628 } 10629 10630 free(pgty); 10631 10632 if (scf_pg_delete(pg) != 0) { 10633 result = scf_error(); 10634 if (result != SCF_ERROR_PERMISSION_DENIED) 10635 scfdie(); 10636 goto out; 10637 } 10638 10639 /* 10640 * We have to handle the case where we've just deleted the last 10641 * property group of a "dummy" entity (instance or service). 10642 * A "dummy" entity is an entity only present to hold an 10643 * external dependency. 10644 * So, in the case we deleted the last property group then we 10645 * can also delete the entity. If the entity is an instance then 10646 * we must verify if this was the last instance for the service 10647 * and if it is, we can also delete the service if it doesn't 10648 * have any property group either. 10649 */ 10650 10651 result = SCF_ERROR_NONE; 10652 10653 if (isservice) { 10654 svc = (scf_service_t *)entity; 10655 10656 if ((inst = scf_instance_create(g_hndl)) == NULL || 10657 (iter = scf_iter_create(g_hndl)) == NULL) 10658 scfdie(); 10659 10660 name_buf = safe_malloc(max_scf_name_len + 1); 10661 } else { 10662 inst = (scf_instance_t *)entity; 10663 } 10664 10665 /* 10666 * If the entity is an instance and we've just deleted its last 10667 * property group then we should delete it. 10668 */ 10669 if (!isservice && entity_has_no_pgs(entity, isservice)) { 10670 /* find the service before deleting the inst. - needed later */ 10671 if ((svc = scf_service_create(g_hndl)) == NULL) 10672 scfdie(); 10673 10674 if (scf_instance_get_parent(inst, svc) != 0) 10675 scfdie(); 10676 10677 /* delete the instance */ 10678 if (scf_instance_delete(inst) != 0) { 10679 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10680 scfdie(); 10681 10682 result = SCF_ERROR_PERMISSION_DENIED; 10683 goto out; 10684 } 10685 /* no need to refresh the instance */ 10686 inst = NULL; 10687 } 10688 10689 /* 10690 * If the service has no more instances and pgs or we just deleted the 10691 * last instance and the service doesn't have anymore propery groups 10692 * then the service should be deleted. 10693 */ 10694 if (svc != NULL && 10695 svc_has_no_insts(svc) && 10696 entity_has_no_pgs((void *)svc, 1)) { 10697 if (scf_service_delete(svc) == 0) { 10698 if (isservice) { 10699 /* no need to refresh the service */ 10700 svc = NULL; 10701 } 10702 10703 goto out; 10704 } 10705 10706 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10707 scfdie(); 10708 10709 result = SCF_ERROR_PERMISSION_DENIED; 10710 } 10711 10712 /* if the entity has not been deleted, refresh it */ 10713 if ((isservice && svc != NULL) || (!isservice && inst != NULL)) { 10714 (void) refresh_entity(isservice, entity, fmri, inst, iter, 10715 name_buf); 10716 } 10717 10718 out: 10719 if (isservice && (inst != NULL && iter != NULL)) { 10720 free(name_buf); 10721 scf_iter_destroy(iter); 10722 scf_instance_destroy(inst); 10723 } 10724 10725 if (!isservice && svc != NULL) { 10726 scf_service_destroy(svc); 10727 } 10728 10729 scf_pg_destroy(pg); 10730 if (entity != NULL) 10731 entity_destroy(entity, isservice); 10732 10733 return (result); 10734 } 10735 10736 static int 10737 delete_dependents(scf_propertygroup_t *pg) 10738 { 10739 char *pgty, *name, *fmri; 10740 scf_property_t *prop; 10741 scf_value_t *val; 10742 scf_iter_t *iter; 10743 int r; 10744 scf_error_t err; 10745 10746 /* Verify that the pg has the correct type. */ 10747 pgty = safe_malloc(max_scf_pg_type_len + 1); 10748 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 10749 scfdie(); 10750 10751 if (strcmp(pgty, scf_group_framework) != 0) { 10752 if (g_verbose) { 10753 fmri = safe_malloc(max_scf_fmri_len + 1); 10754 if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0) 10755 scfdie(); 10756 10757 warn(gettext("Property group %s is not of expected " 10758 "type %s.\n"), fmri, scf_group_framework); 10759 10760 free(fmri); 10761 } 10762 10763 free(pgty); 10764 return (-1); 10765 } 10766 10767 free(pgty); 10768 10769 /* map delete_dependency_pg onto the properties. */ 10770 if ((prop = scf_property_create(g_hndl)) == NULL || 10771 (val = scf_value_create(g_hndl)) == NULL || 10772 (iter = scf_iter_create(g_hndl)) == NULL) 10773 scfdie(); 10774 10775 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 10776 scfdie(); 10777 10778 name = safe_malloc(max_scf_name_len + 1); 10779 fmri = safe_malloc(max_scf_fmri_len + 2); 10780 10781 while ((r = scf_iter_next_property(iter, prop)) == 1) { 10782 scf_type_t ty; 10783 10784 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0) 10785 scfdie(); 10786 10787 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 10788 scfdie(); 10789 10790 if ((ty != SCF_TYPE_ASTRING && 10791 prop_check_type(prop, SCF_TYPE_FMRI) != 0) || 10792 prop_get_val(prop, val) != 0) 10793 continue; 10794 10795 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0) 10796 scfdie(); 10797 10798 err = delete_dependency_pg(fmri, name); 10799 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) { 10800 if (scf_property_to_fmri(prop, fmri, 10801 max_scf_fmri_len + 2) < 0) 10802 scfdie(); 10803 10804 warn(gettext("Value of %s is not a valid FMRI.\n"), 10805 fmri); 10806 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) { 10807 warn(gettext("Property group \"%s\" of entity \"%s\" " 10808 "does not have dependency type.\n"), name, fmri); 10809 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) { 10810 warn(gettext("Could not delete property group \"%s\" " 10811 "of entity \"%s\" (permission denied).\n"), name, 10812 fmri); 10813 } 10814 } 10815 if (r == -1) 10816 scfdie(); 10817 10818 scf_value_destroy(val); 10819 scf_property_destroy(prop); 10820 10821 return (0); 10822 } 10823 10824 /* 10825 * Returns 1 if the instance may be running, and 0 otherwise. 10826 */ 10827 static int 10828 inst_is_running(scf_instance_t *inst) 10829 { 10830 scf_propertygroup_t *pg; 10831 scf_property_t *prop; 10832 scf_value_t *val; 10833 char buf[MAX_SCF_STATE_STRING_SZ]; 10834 int ret = 0; 10835 ssize_t szret; 10836 10837 if ((pg = scf_pg_create(g_hndl)) == NULL || 10838 (prop = scf_property_create(g_hndl)) == NULL || 10839 (val = scf_value_create(g_hndl)) == NULL) 10840 scfdie(); 10841 10842 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) { 10843 if (scf_error() != SCF_ERROR_NOT_FOUND) 10844 scfdie(); 10845 goto out; 10846 } 10847 10848 if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 || 10849 prop_check_type(prop, SCF_TYPE_ASTRING) != 0 || 10850 prop_get_val(prop, val) != 0) 10851 goto out; 10852 10853 szret = scf_value_get_astring(val, buf, sizeof (buf)); 10854 assert(szret >= 0); 10855 10856 ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 || 10857 strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0; 10858 10859 out: 10860 scf_value_destroy(val); 10861 scf_property_destroy(prop); 10862 scf_pg_destroy(pg); 10863 return (ret); 10864 } 10865 10866 static uint8_t 10867 pg_is_external_dependency(scf_propertygroup_t *pg) 10868 { 10869 char *type; 10870 scf_value_t *val; 10871 scf_property_t *prop; 10872 uint8_t b = B_FALSE; 10873 10874 type = safe_malloc(max_scf_pg_type_len + 1); 10875 10876 if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0) 10877 scfdie(); 10878 10879 if ((prop = scf_property_create(g_hndl)) == NULL || 10880 (val = scf_value_create(g_hndl)) == NULL) 10881 scfdie(); 10882 10883 if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) { 10884 if (pg_get_prop(pg, scf_property_external, prop) == 0) { 10885 if (scf_property_get_value(prop, val) != 0) 10886 scfdie(); 10887 if (scf_value_get_boolean(val, &b) != 0) 10888 scfdie(); 10889 } 10890 } 10891 10892 free(type); 10893 (void) scf_value_destroy(val); 10894 (void) scf_property_destroy(prop); 10895 10896 return (b); 10897 } 10898 10899 #define DELETE_FAILURE -1 10900 #define DELETE_SUCCESS_NOEXTDEPS 0 10901 #define DELETE_SUCCESS_EXTDEPS 1 10902 10903 /* 10904 * lscf_instance_delete() deletes an instance. Before calling 10905 * scf_instance_delete(), though, we make sure the instance isn't 10906 * running and delete dependencies in other entities which the instance 10907 * declared as "dependents". If there are dependencies which were 10908 * created for other entities, then instead of deleting the instance we 10909 * make it "empty" by deleting all other property groups and all 10910 * snapshots. 10911 * 10912 * lscf_instance_delete() verifies that there is no external dependency pgs 10913 * before suppressing the instance. If there is, then we must not remove them 10914 * now in case the instance is re-created otherwise the dependencies would be 10915 * lost. The external dependency pgs will be removed if the dependencies are 10916 * removed. 10917 * 10918 * Returns: 10919 * DELETE_FAILURE on failure 10920 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies 10921 * DELETE_SUCCESS_EXTDEPS on success - external dependencies 10922 */ 10923 static int 10924 lscf_instance_delete(scf_instance_t *inst, int force) 10925 { 10926 scf_propertygroup_t *pg; 10927 scf_snapshot_t *snap; 10928 scf_iter_t *iter; 10929 int err; 10930 int external = 0; 10931 10932 /* If we're not forcing and the instance is running, refuse. */ 10933 if (!force && inst_is_running(inst)) { 10934 char *fmri; 10935 10936 fmri = safe_malloc(max_scf_fmri_len + 1); 10937 10938 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0) 10939 scfdie(); 10940 10941 semerr(gettext("Instance %s may be running. " 10942 "Use delete -f if it is not.\n"), fmri); 10943 10944 free(fmri); 10945 return (DELETE_FAILURE); 10946 } 10947 10948 pg = scf_pg_create(g_hndl); 10949 if (pg == NULL) 10950 scfdie(); 10951 10952 if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0) 10953 (void) delete_dependents(pg); 10954 else if (scf_error() != SCF_ERROR_NOT_FOUND) 10955 scfdie(); 10956 10957 scf_pg_destroy(pg); 10958 10959 /* 10960 * If the instance has some external dependencies then we must 10961 * keep them in case the instance is reimported otherwise the 10962 * dependencies would be lost on reimport. 10963 */ 10964 if ((iter = scf_iter_create(g_hndl)) == NULL || 10965 (pg = scf_pg_create(g_hndl)) == NULL) 10966 scfdie(); 10967 10968 if (scf_iter_instance_pgs(iter, inst) < 0) 10969 scfdie(); 10970 10971 while ((err = scf_iter_next_pg(iter, pg)) == 1) { 10972 if (pg_is_external_dependency(pg)) { 10973 external = 1; 10974 continue; 10975 } 10976 10977 if (scf_pg_delete(pg) != 0) { 10978 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10979 scfdie(); 10980 else { 10981 semerr(emsg_permission_denied); 10982 10983 (void) scf_iter_destroy(iter); 10984 (void) scf_pg_destroy(pg); 10985 return (DELETE_FAILURE); 10986 } 10987 } 10988 } 10989 10990 if (err == -1) 10991 scfdie(); 10992 10993 (void) scf_iter_destroy(iter); 10994 (void) scf_pg_destroy(pg); 10995 10996 if (external) { 10997 /* 10998 * All the pgs have been deleted for the instance except 10999 * the ones holding the external dependencies. 11000 * For the job to be complete, we must also delete the 11001 * snapshots associated with the instance. 11002 */ 11003 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) == 11004 NULL) 11005 scfdie(); 11006 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL) 11007 scfdie(); 11008 11009 if (scf_iter_instance_snapshots(iter, inst) == -1) 11010 scfdie(); 11011 11012 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) { 11013 if (_scf_snapshot_delete(snap) != 0) { 11014 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11015 scfdie(); 11016 11017 semerr(emsg_permission_denied); 11018 11019 (void) scf_iter_destroy(iter); 11020 (void) scf_snapshot_destroy(snap); 11021 return (DELETE_FAILURE); 11022 } 11023 } 11024 11025 if (err == -1) 11026 scfdie(); 11027 11028 (void) scf_iter_destroy(iter); 11029 (void) scf_snapshot_destroy(snap); 11030 return (DELETE_SUCCESS_EXTDEPS); 11031 } 11032 11033 if (scf_instance_delete(inst) != 0) { 11034 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11035 scfdie(); 11036 11037 semerr(emsg_permission_denied); 11038 11039 return (DELETE_FAILURE); 11040 } 11041 11042 return (DELETE_SUCCESS_NOEXTDEPS); 11043 } 11044 11045 /* 11046 * lscf_service_delete() deletes a service. Before calling 11047 * scf_service_delete(), though, we call lscf_instance_delete() for 11048 * each of the instances and delete dependencies in other entities 11049 * which were created as "dependents" of this service. If there are 11050 * dependencies which were created for other entities, then we delete 11051 * all other property groups in the service and leave it as "empty". 11052 * 11053 * lscf_service_delete() verifies that there is no external dependency 11054 * pgs at the instance & service level before suppressing the service. 11055 * If there is, then we must not remove them now in case the service 11056 * is re-imported otherwise the dependencies would be lost. The external 11057 * dependency pgs will be removed if the dependencies are removed. 11058 * 11059 * Returns: 11060 * DELETE_FAILURE on failure 11061 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies 11062 * DELETE_SUCCESS_EXTDEPS on success - external dependencies 11063 */ 11064 static int 11065 lscf_service_delete(scf_service_t *svc, int force) 11066 { 11067 int r; 11068 scf_instance_t *inst; 11069 scf_propertygroup_t *pg; 11070 scf_iter_t *iter; 11071 int ret; 11072 int external = 0; 11073 11074 if ((inst = scf_instance_create(g_hndl)) == NULL || 11075 (pg = scf_pg_create(g_hndl)) == NULL || 11076 (iter = scf_iter_create(g_hndl)) == NULL) 11077 scfdie(); 11078 11079 if (scf_iter_service_instances(iter, svc) != 0) 11080 scfdie(); 11081 11082 for (r = scf_iter_next_instance(iter, inst); 11083 r == 1; 11084 r = scf_iter_next_instance(iter, inst)) { 11085 11086 ret = lscf_instance_delete(inst, force); 11087 if (ret == DELETE_FAILURE) { 11088 scf_iter_destroy(iter); 11089 scf_pg_destroy(pg); 11090 scf_instance_destroy(inst); 11091 return (DELETE_FAILURE); 11092 } 11093 11094 /* 11095 * Record the fact that there is some external dependencies 11096 * at the instance level. 11097 */ 11098 if (ret == DELETE_SUCCESS_EXTDEPS) 11099 external |= 1; 11100 } 11101 11102 if (r != 0) 11103 scfdie(); 11104 11105 /* Delete dependency property groups in dependent services. */ 11106 if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0) 11107 (void) delete_dependents(pg); 11108 else if (scf_error() != SCF_ERROR_NOT_FOUND) 11109 scfdie(); 11110 11111 scf_iter_destroy(iter); 11112 scf_pg_destroy(pg); 11113 scf_instance_destroy(inst); 11114 11115 /* 11116 * If the service has some external dependencies then we don't 11117 * want to remove them in case the service is re-imported. 11118 */ 11119 if ((pg = scf_pg_create(g_hndl)) == NULL || 11120 (iter = scf_iter_create(g_hndl)) == NULL) 11121 scfdie(); 11122 11123 if (scf_iter_service_pgs(iter, svc) < 0) 11124 scfdie(); 11125 11126 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 11127 if (pg_is_external_dependency(pg)) { 11128 external |= 2; 11129 continue; 11130 } 11131 11132 if (scf_pg_delete(pg) != 0) { 11133 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11134 scfdie(); 11135 else { 11136 semerr(emsg_permission_denied); 11137 11138 (void) scf_iter_destroy(iter); 11139 (void) scf_pg_destroy(pg); 11140 return (DELETE_FAILURE); 11141 } 11142 } 11143 } 11144 11145 if (r == -1) 11146 scfdie(); 11147 11148 (void) scf_iter_destroy(iter); 11149 (void) scf_pg_destroy(pg); 11150 11151 if (external != 0) 11152 return (DELETE_SUCCESS_EXTDEPS); 11153 11154 if (scf_service_delete(svc) == 0) 11155 return (DELETE_SUCCESS_NOEXTDEPS); 11156 11157 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11158 scfdie(); 11159 11160 semerr(emsg_permission_denied); 11161 return (DELETE_FAILURE); 11162 } 11163 11164 static int 11165 delete_callback(void *data, scf_walkinfo_t *wip) 11166 { 11167 int force = (int)data; 11168 11169 if (wip->inst != NULL) 11170 (void) lscf_instance_delete(wip->inst, force); 11171 else 11172 (void) lscf_service_delete(wip->svc, force); 11173 11174 return (0); 11175 } 11176 11177 void 11178 lscf_delete(const char *fmri, int force) 11179 { 11180 scf_service_t *svc; 11181 scf_instance_t *inst; 11182 int ret; 11183 11184 lscf_prep_hndl(); 11185 11186 if (cur_snap != NULL) { 11187 if (!snaplevel_is_instance(cur_level)) { 11188 char *buf; 11189 11190 buf = safe_malloc(max_scf_name_len + 1); 11191 if (scf_instance_get_name(cur_inst, buf, 11192 max_scf_name_len + 1) >= 0) { 11193 if (strcmp(buf, fmri) == 0) { 11194 semerr(emsg_cant_modify_snapshots); 11195 free(buf); 11196 return; 11197 } 11198 } else if (scf_error() != SCF_ERROR_DELETED) { 11199 scfdie(); 11200 } 11201 free(buf); 11202 } 11203 } else if (cur_inst != NULL) { 11204 /* EMPTY */; 11205 } else if (cur_svc != NULL) { 11206 inst = scf_instance_create(g_hndl); 11207 if (inst == NULL) 11208 scfdie(); 11209 11210 if (scf_service_get_instance(cur_svc, fmri, inst) == 11211 SCF_SUCCESS) { 11212 (void) lscf_instance_delete(inst, force); 11213 scf_instance_destroy(inst); 11214 return; 11215 } 11216 11217 if (scf_error() != SCF_ERROR_NOT_FOUND && 11218 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 11219 scfdie(); 11220 11221 scf_instance_destroy(inst); 11222 } else { 11223 assert(cur_scope != NULL); 11224 11225 svc = scf_service_create(g_hndl); 11226 if (svc == NULL) 11227 scfdie(); 11228 11229 if (scf_scope_get_service(cur_scope, fmri, svc) == 11230 SCF_SUCCESS) { 11231 (void) lscf_service_delete(svc, force); 11232 scf_service_destroy(svc); 11233 return; 11234 } 11235 11236 if (scf_error() != SCF_ERROR_NOT_FOUND && 11237 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 11238 scfdie(); 11239 11240 scf_service_destroy(svc); 11241 } 11242 11243 /* 11244 * Match FMRI to entity. 11245 */ 11246 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 11247 delete_callback, (void *)force, NULL, semerr)) != 0) { 11248 semerr(gettext("Failed to walk instances: %s\n"), 11249 scf_strerror(ret)); 11250 } 11251 } 11252 11253 11254 11255 /* 11256 * :properties commands. These all end with "pg" or "prop" and generally 11257 * operate on the currently selected entity. 11258 */ 11259 11260 /* 11261 * Property listing. List the property groups, properties, their types and 11262 * their values for the currently selected entity. 11263 */ 11264 static void 11265 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth) 11266 { 11267 char *buf; 11268 uint32_t flags; 11269 11270 buf = safe_malloc(max_scf_pg_type_len + 1); 11271 11272 if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0) 11273 scfdie(); 11274 11275 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 11276 scfdie(); 11277 11278 safe_printf("%-*s %s", namewidth, name, buf); 11279 11280 if (flags & SCF_PG_FLAG_NONPERSISTENT) 11281 safe_printf("\tNONPERSISTENT"); 11282 11283 safe_printf("\n"); 11284 11285 free(buf); 11286 } 11287 11288 static boolean_t 11289 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val) 11290 { 11291 if (scf_property_get_value(prop, val) == 0) { 11292 return (B_FALSE); 11293 } else { 11294 switch (scf_error()) { 11295 case SCF_ERROR_NOT_FOUND: 11296 return (B_FALSE); 11297 case SCF_ERROR_PERMISSION_DENIED: 11298 case SCF_ERROR_CONSTRAINT_VIOLATED: 11299 return (B_TRUE); 11300 default: 11301 scfdie(); 11302 /*NOTREACHED*/ 11303 } 11304 } 11305 } 11306 11307 static void 11308 list_prop_info(const scf_property_t *prop, const char *name, size_t len) 11309 { 11310 scf_iter_t *iter; 11311 scf_value_t *val; 11312 const char *type; 11313 int multiple_strings = 0; 11314 int ret; 11315 11316 if ((iter = scf_iter_create(g_hndl)) == NULL || 11317 (val = scf_value_create(g_hndl)) == NULL) 11318 scfdie(); 11319 11320 type = prop_to_typestr(prop); 11321 assert(type != NULL); 11322 11323 safe_printf("%-*s %-7s ", len, name, type); 11324 11325 if (prop_has_multiple_values(prop, val) && 11326 (scf_value_type(val) == SCF_TYPE_ASTRING || 11327 scf_value_type(val) == SCF_TYPE_USTRING)) 11328 multiple_strings = 1; 11329 11330 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS) 11331 scfdie(); 11332 11333 while ((ret = scf_iter_next_value(iter, val)) == 1) { 11334 char *buf; 11335 ssize_t vlen, szret; 11336 11337 vlen = scf_value_get_as_string(val, NULL, 0); 11338 if (vlen < 0) 11339 scfdie(); 11340 11341 buf = safe_malloc(vlen + 1); 11342 11343 szret = scf_value_get_as_string(val, buf, vlen + 1); 11344 if (szret < 0) 11345 scfdie(); 11346 assert(szret <= vlen); 11347 11348 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */ 11349 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) { 11350 safe_printf(" \""); 11351 (void) quote_and_print(buf, stdout, 0); 11352 (void) putchar('"'); 11353 if (ferror(stdout)) { 11354 (void) putchar('\n'); 11355 uu_die(gettext("Error writing to stdout.\n")); 11356 } 11357 } else { 11358 safe_printf(" %s", buf); 11359 } 11360 11361 free(buf); 11362 } 11363 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 11364 scfdie(); 11365 11366 if (putchar('\n') != '\n') 11367 uu_die(gettext("Could not output newline")); 11368 } 11369 11370 /* 11371 * Outputs template property group info for the describe subcommand. 11372 * If 'templates' == 2, verbose output is printed in the format expected 11373 * for describe -v, which includes all templates fields. If pg is 11374 * not NULL, we're describing the template data, not an existing property 11375 * group, and formatting should be appropriate for describe -t. 11376 */ 11377 static void 11378 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates) 11379 { 11380 char *buf; 11381 uint8_t required; 11382 scf_property_t *stability_prop; 11383 scf_value_t *stability_val; 11384 11385 if (templates == 0) 11386 return; 11387 11388 if ((stability_prop = scf_property_create(g_hndl)) == NULL || 11389 (stability_val = scf_value_create(g_hndl)) == NULL) 11390 scfdie(); 11391 11392 if (templates == 2 && pg != NULL) { 11393 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY, 11394 stability_prop) == 0) { 11395 if (prop_check_type(stability_prop, 11396 SCF_TYPE_ASTRING) == 0 && 11397 prop_get_val(stability_prop, stability_val) == 0) { 11398 char *stability; 11399 11400 stability = safe_malloc(max_scf_value_len + 1); 11401 11402 if (scf_value_get_astring(stability_val, 11403 stability, max_scf_value_len + 1) == -1 && 11404 scf_error() != SCF_ERROR_NOT_FOUND) 11405 scfdie(); 11406 11407 safe_printf("%s%s: %s\n", TMPL_INDENT, 11408 gettext("stability"), stability); 11409 11410 free(stability); 11411 } 11412 } else if (scf_error() != SCF_ERROR_NOT_FOUND) 11413 scfdie(); 11414 } 11415 11416 scf_property_destroy(stability_prop); 11417 scf_value_destroy(stability_val); 11418 11419 if (pgt == NULL) 11420 return; 11421 11422 if (pg == NULL || templates == 2) { 11423 /* print type info only if scf_tmpl_pg_name succeeds */ 11424 if (scf_tmpl_pg_name(pgt, &buf) != -1) { 11425 if (pg != NULL) 11426 safe_printf("%s", TMPL_INDENT); 11427 safe_printf("%s: ", gettext("name")); 11428 safe_printf("%s\n", buf); 11429 free(buf); 11430 } 11431 11432 /* print type info only if scf_tmpl_pg_type succeeds */ 11433 if (scf_tmpl_pg_type(pgt, &buf) != -1) { 11434 if (pg != NULL) 11435 safe_printf("%s", TMPL_INDENT); 11436 safe_printf("%s: ", gettext("type")); 11437 safe_printf("%s\n", buf); 11438 free(buf); 11439 } 11440 } 11441 11442 if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0) 11443 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"), 11444 required ? "true" : "false"); 11445 11446 if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) { 11447 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"), 11448 buf); 11449 free(buf); 11450 } 11451 11452 if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) { 11453 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"), 11454 buf); 11455 free(buf); 11456 } 11457 11458 if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) { 11459 if (templates == 2) 11460 safe_printf("%s%s: %s\n", TMPL_INDENT, 11461 gettext("description"), buf); 11462 else 11463 safe_printf("%s%s\n", TMPL_INDENT, buf); 11464 free(buf); 11465 } 11466 11467 } 11468 11469 /* 11470 * With as_value set to true, indent as appropriate for the value level. 11471 * If false, indent to appropriate level for inclusion in constraint 11472 * or choice printout. 11473 */ 11474 static void 11475 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf, 11476 int as_value) 11477 { 11478 char *buf; 11479 11480 if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) { 11481 if (as_value == 0) 11482 safe_printf("%s", TMPL_CHOICE_INDENT); 11483 else 11484 safe_printf("%s", TMPL_INDENT); 11485 safe_printf("%s: %s\n", gettext("value common name"), buf); 11486 free(buf); 11487 } 11488 11489 if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) { 11490 if (as_value == 0) 11491 safe_printf("%s", TMPL_CHOICE_INDENT); 11492 else 11493 safe_printf("%s", TMPL_INDENT); 11494 safe_printf("%s: %s\n", gettext("value description"), buf); 11495 free(buf); 11496 } 11497 } 11498 11499 static void 11500 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf) 11501 { 11502 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value")); 11503 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */ 11504 safe_printf("%s\n", val_buf); 11505 11506 print_template_value_details(prt, val_buf, 1); 11507 } 11508 11509 static void 11510 print_template_constraints(scf_prop_tmpl_t *prt, int verbose) 11511 { 11512 int i, printed = 0; 11513 scf_values_t values; 11514 scf_count_ranges_t c_ranges; 11515 scf_int_ranges_t i_ranges; 11516 11517 printed = 0; 11518 i = 0; 11519 if (scf_tmpl_value_name_constraints(prt, &values) == 0) { 11520 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 11521 gettext("value constraints")); 11522 printed++; 11523 for (i = 0; i < values.value_count; ++i) { 11524 safe_printf("%s%s: %s\n", TMPL_INDENT, 11525 gettext("value name"), values.values_as_strings[i]); 11526 if (verbose == 1) 11527 print_template_value_details(prt, 11528 values.values_as_strings[i], 0); 11529 } 11530 11531 scf_values_destroy(&values); 11532 } 11533 11534 if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) { 11535 if (printed++ == 0) 11536 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 11537 gettext("value constraints")); 11538 for (i = 0; i < c_ranges.scr_num_ranges; ++i) { 11539 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT, 11540 gettext("range"), c_ranges.scr_min[i], 11541 c_ranges.scr_max[i]); 11542 } 11543 scf_count_ranges_destroy(&c_ranges); 11544 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED && 11545 scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) { 11546 if (printed++ == 0) 11547 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 11548 gettext("value constraints")); 11549 for (i = 0; i < i_ranges.sir_num_ranges; ++i) { 11550 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT, 11551 gettext("range"), i_ranges.sir_min[i], 11552 i_ranges.sir_max[i]); 11553 } 11554 scf_int_ranges_destroy(&i_ranges); 11555 } 11556 } 11557 11558 static void 11559 print_template_choices(scf_prop_tmpl_t *prt, int verbose) 11560 { 11561 int i = 0, printed = 0; 11562 scf_values_t values; 11563 scf_count_ranges_t c_ranges; 11564 scf_int_ranges_t i_ranges; 11565 11566 printed = 0; 11567 if (scf_tmpl_value_name_choices(prt, &values) == 0) { 11568 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 11569 gettext("value constraints")); 11570 printed++; 11571 for (i = 0; i < values.value_count; i++) { 11572 safe_printf("%s%s: %s\n", TMPL_INDENT, 11573 gettext("value name"), values.values_as_strings[i]); 11574 if (verbose == 1) 11575 print_template_value_details(prt, 11576 values.values_as_strings[i], 0); 11577 } 11578 11579 scf_values_destroy(&values); 11580 } 11581 11582 if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) { 11583 for (i = 0; i < c_ranges.scr_num_ranges; ++i) { 11584 if (printed++ == 0) 11585 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 11586 gettext("value choices")); 11587 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT, 11588 gettext("range"), c_ranges.scr_min[i], 11589 c_ranges.scr_max[i]); 11590 } 11591 scf_count_ranges_destroy(&c_ranges); 11592 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED && 11593 scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) { 11594 for (i = 0; i < i_ranges.sir_num_ranges; ++i) { 11595 if (printed++ == 0) 11596 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 11597 gettext("value choices")); 11598 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT, 11599 gettext("range"), i_ranges.sir_min[i], 11600 i_ranges.sir_max[i]); 11601 } 11602 scf_int_ranges_destroy(&i_ranges); 11603 } 11604 } 11605 11606 static void 11607 list_values_by_template(scf_prop_tmpl_t *prt) 11608 { 11609 print_template_constraints(prt, 1); 11610 print_template_choices(prt, 1); 11611 } 11612 11613 static void 11614 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop) 11615 { 11616 char *val_buf; 11617 scf_iter_t *iter; 11618 scf_value_t *val; 11619 int ret; 11620 11621 if ((iter = scf_iter_create(g_hndl)) == NULL || 11622 (val = scf_value_create(g_hndl)) == NULL) 11623 scfdie(); 11624 11625 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS) 11626 scfdie(); 11627 11628 val_buf = safe_malloc(max_scf_value_len + 1); 11629 11630 while ((ret = scf_iter_next_value(iter, val)) == 1) { 11631 if (scf_value_get_as_string(val, val_buf, 11632 max_scf_value_len + 1) < 0) 11633 scfdie(); 11634 11635 print_template_value(prt, val_buf); 11636 } 11637 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 11638 scfdie(); 11639 free(val_buf); 11640 11641 print_template_constraints(prt, 0); 11642 print_template_choices(prt, 0); 11643 11644 } 11645 11646 /* 11647 * Outputs property info for the describe subcommand 11648 * Verbose output if templates == 2, -v option of svccfg describe 11649 * Displays template data if prop is not NULL, -t option of svccfg describe 11650 */ 11651 static void 11652 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates) 11653 { 11654 char *buf; 11655 uint8_t u_buf; 11656 int i; 11657 uint64_t min, max; 11658 scf_values_t values; 11659 11660 if (prt == NULL || templates == 0) 11661 return; 11662 11663 if (prop == NULL) { 11664 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name")); 11665 if (scf_tmpl_prop_name(prt, &buf) > 0) { 11666 safe_printf("%s\n", buf); 11667 free(buf); 11668 } else 11669 safe_printf("(%s)\n", gettext("any")); 11670 } 11671 11672 if (prop == NULL || templates == 2) { 11673 if (prop != NULL) 11674 safe_printf("%s", TMPL_INDENT); 11675 else 11676 safe_printf("%s", TMPL_VALUE_INDENT); 11677 safe_printf("%s: ", gettext("type")); 11678 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) { 11679 safe_printf("%s\n", buf); 11680 free(buf); 11681 } else 11682 safe_printf("(%s)\n", gettext("any")); 11683 } 11684 11685 if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0) 11686 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"), 11687 u_buf ? "true" : "false"); 11688 11689 if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) { 11690 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"), 11691 buf); 11692 free(buf); 11693 } 11694 11695 if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) { 11696 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"), 11697 buf); 11698 free(buf); 11699 } 11700 11701 if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) { 11702 safe_printf("%s%s\n", TMPL_INDENT, buf); 11703 free(buf); 11704 } 11705 11706 if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0) 11707 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"), 11708 scf_tmpl_visibility_to_string(u_buf)); 11709 11710 if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) { 11711 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT, 11712 gettext("minimum number of values"), min); 11713 if (max == ULLONG_MAX) { 11714 safe_printf("%s%s: %s\n", TMPL_INDENT, 11715 gettext("maximum number of values"), 11716 gettext("unlimited")); 11717 } else { 11718 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT, 11719 gettext("maximum number of values"), max); 11720 } 11721 } 11722 11723 if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) { 11724 for (i = 0; i < values.value_count; i++) { 11725 if (i == 0) { 11726 safe_printf("%s%s:", TMPL_INDENT, 11727 gettext("internal separators")); 11728 } 11729 safe_printf(" \"%s\"", values.values_as_strings[i]); 11730 } 11731 safe_printf("\n"); 11732 } 11733 11734 if (templates != 2) 11735 return; 11736 11737 if (prop != NULL) 11738 list_values_tmpl(prt, prop); 11739 else 11740 list_values_by_template(prt); 11741 } 11742 11743 static char * 11744 read_astring(scf_propertygroup_t *pg, const char *prop_name) 11745 { 11746 char *rv; 11747 11748 rv = _scf_read_single_astring_from_pg(pg, prop_name); 11749 if (rv == NULL) { 11750 switch (scf_error()) { 11751 case SCF_ERROR_NOT_FOUND: 11752 break; 11753 default: 11754 scfdie(); 11755 } 11756 } 11757 return (rv); 11758 } 11759 11760 static void 11761 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg) 11762 { 11763 size_t doc_len; 11764 size_t man_len; 11765 char *pg_name; 11766 char *text = NULL; 11767 int rv; 11768 11769 doc_len = strlen(SCF_PG_TM_DOC_PREFIX); 11770 man_len = strlen(SCF_PG_TM_MAN_PREFIX); 11771 pg_name = safe_malloc(max_scf_name_len + 1); 11772 while ((rv = scf_iter_next_pg(iter, pg)) == 1) { 11773 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) { 11774 scfdie(); 11775 } 11776 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) { 11777 /* Display doc_link and and uri */ 11778 safe_printf("%s%s:\n", TMPL_INDENT, 11779 gettext("doc_link")); 11780 text = read_astring(pg, SCF_PROPERTY_TM_NAME); 11781 if (text != NULL) { 11782 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 11783 TMPL_INDENT, gettext("name"), text); 11784 uu_free(text); 11785 } 11786 text = read_astring(pg, SCF_PROPERTY_TM_URI); 11787 if (text != NULL) { 11788 safe_printf("%s%s: %s\n", TMPL_INDENT_2X, 11789 gettext("uri"), text); 11790 uu_free(text); 11791 } 11792 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX, 11793 man_len) == 0) { 11794 /* Display manpage title, section and path */ 11795 safe_printf("%s%s:\n", TMPL_INDENT, 11796 gettext("manpage")); 11797 text = read_astring(pg, SCF_PROPERTY_TM_TITLE); 11798 if (text != NULL) { 11799 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 11800 TMPL_INDENT, gettext("title"), text); 11801 uu_free(text); 11802 } 11803 text = read_astring(pg, SCF_PROPERTY_TM_SECTION); 11804 if (text != NULL) { 11805 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 11806 TMPL_INDENT, gettext("section"), text); 11807 uu_free(text); 11808 } 11809 text = read_astring(pg, SCF_PROPERTY_TM_MANPATH); 11810 if (text != NULL) { 11811 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 11812 TMPL_INDENT, gettext("manpath"), text); 11813 uu_free(text); 11814 } 11815 } 11816 } 11817 if (rv == -1) 11818 scfdie(); 11819 11820 done: 11821 free(pg_name); 11822 } 11823 11824 static void 11825 list_entity_tmpl(int templates) 11826 { 11827 char *common_name = NULL; 11828 char *description = NULL; 11829 char *locale = NULL; 11830 scf_iter_t *iter; 11831 scf_propertygroup_t *pg; 11832 scf_property_t *prop; 11833 int r; 11834 scf_value_t *val; 11835 11836 if ((pg = scf_pg_create(g_hndl)) == NULL || 11837 (prop = scf_property_create(g_hndl)) == NULL || 11838 (val = scf_value_create(g_hndl)) == NULL || 11839 (iter = scf_iter_create(g_hndl)) == NULL) 11840 scfdie(); 11841 11842 locale = setlocale(LC_MESSAGES, NULL); 11843 11844 if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) { 11845 common_name = safe_malloc(max_scf_value_len + 1); 11846 11847 /* Try both the current locale and the "C" locale. */ 11848 if (scf_pg_get_property(pg, locale, prop) == 0 || 11849 (scf_error() == SCF_ERROR_NOT_FOUND && 11850 scf_pg_get_property(pg, "C", prop) == 0)) { 11851 if (prop_get_val(prop, val) == 0 && 11852 scf_value_get_ustring(val, common_name, 11853 max_scf_value_len + 1) != -1) { 11854 safe_printf("%s%s: %s\n", TMPL_INDENT, 11855 gettext("common name"), common_name); 11856 } 11857 } 11858 } 11859 11860 /* 11861 * Do description, manpages, and doc links if templates == 2. 11862 */ 11863 if (templates == 2) { 11864 /* Get the description. */ 11865 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) { 11866 description = safe_malloc(max_scf_value_len + 1); 11867 11868 /* Try both the current locale and the "C" locale. */ 11869 if (scf_pg_get_property(pg, locale, prop) == 0 || 11870 (scf_error() == SCF_ERROR_NOT_FOUND && 11871 scf_pg_get_property(pg, "C", prop) == 0)) { 11872 if (prop_get_val(prop, val) == 0 && 11873 scf_value_get_ustring(val, description, 11874 max_scf_value_len + 1) != -1) { 11875 safe_printf("%s%s: %s\n", TMPL_INDENT, 11876 gettext("description"), 11877 description); 11878 } 11879 } 11880 } 11881 11882 /* Process doc_link & manpage elements. */ 11883 if (cur_level != NULL) { 11884 r = scf_iter_snaplevel_pgs_typed(iter, cur_level, 11885 SCF_GROUP_TEMPLATE); 11886 } else if (cur_inst != NULL) { 11887 r = scf_iter_instance_pgs_typed(iter, cur_inst, 11888 SCF_GROUP_TEMPLATE); 11889 } else { 11890 r = scf_iter_service_pgs_typed(iter, cur_svc, 11891 SCF_GROUP_TEMPLATE); 11892 } 11893 if (r == 0) { 11894 display_documentation(iter, pg); 11895 } 11896 } 11897 11898 free(common_name); 11899 free(description); 11900 scf_pg_destroy(pg); 11901 scf_property_destroy(prop); 11902 scf_value_destroy(val); 11903 scf_iter_destroy(iter); 11904 } 11905 11906 static void 11907 listtmpl(const char *pattern, int templates) 11908 { 11909 scf_pg_tmpl_t *pgt; 11910 scf_prop_tmpl_t *prt; 11911 char *snapbuf = NULL; 11912 char *fmribuf; 11913 char *pg_name = NULL, *prop_name = NULL; 11914 ssize_t prop_name_size; 11915 char *qual_prop_name; 11916 char *search_name; 11917 int listed = 0; 11918 11919 if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL || 11920 (prt = scf_tmpl_prop_create(g_hndl)) == NULL) 11921 scfdie(); 11922 11923 fmribuf = safe_malloc(max_scf_name_len + 1); 11924 qual_prop_name = safe_malloc(max_scf_name_len + 1); 11925 11926 if (cur_snap != NULL) { 11927 snapbuf = safe_malloc(max_scf_name_len + 1); 11928 if (scf_snapshot_get_name(cur_snap, snapbuf, 11929 max_scf_name_len + 1) < 0) 11930 scfdie(); 11931 } 11932 11933 if (cur_inst != NULL) { 11934 if (scf_instance_to_fmri(cur_inst, fmribuf, 11935 max_scf_name_len + 1) < 0) 11936 scfdie(); 11937 } else if (cur_svc != NULL) { 11938 if (scf_service_to_fmri(cur_svc, fmribuf, 11939 max_scf_name_len + 1) < 0) 11940 scfdie(); 11941 } else 11942 abort(); 11943 11944 /* If pattern is specified, we want to list only those items. */ 11945 while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, NULL) == 1) { 11946 listed = 0; 11947 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 && 11948 fnmatch(pattern, pg_name, 0) == 0)) { 11949 list_pg_tmpl(pgt, NULL, templates); 11950 listed++; 11951 } 11952 11953 scf_tmpl_prop_reset(prt); 11954 11955 while (scf_tmpl_iter_props(pgt, prt, NULL) == 0) { 11956 search_name = NULL; 11957 prop_name_size = scf_tmpl_prop_name(prt, &prop_name); 11958 if ((prop_name_size > 0) && (pg_name != NULL)) { 11959 if (snprintf(qual_prop_name, 11960 max_scf_name_len + 1, "%s/%s", 11961 pg_name, prop_name) >= 11962 max_scf_name_len + 1) { 11963 prop_name_size = -1; 11964 } else { 11965 search_name = qual_prop_name; 11966 } 11967 } 11968 if (listed > 0 || pattern == NULL || 11969 (prop_name_size > 0 && 11970 fnmatch(pattern, search_name, 11971 FNM_PATHNAME) == 0)) 11972 list_prop_tmpl(prt, NULL, templates); 11973 if (prop_name != NULL) { 11974 free(prop_name); 11975 prop_name = NULL; 11976 } 11977 } 11978 if (pg_name != NULL) { 11979 free(pg_name); 11980 pg_name = NULL; 11981 } 11982 } 11983 11984 scf_tmpl_prop_destroy(prt); 11985 scf_tmpl_pg_destroy(pgt); 11986 free(snapbuf); 11987 free(fmribuf); 11988 free(qual_prop_name); 11989 } 11990 11991 static void 11992 listprop(const char *pattern, int only_pgs, int templates) 11993 { 11994 scf_propertygroup_t *pg; 11995 scf_property_t *prop; 11996 scf_iter_t *iter, *piter; 11997 char *pgnbuf, *prnbuf, *ppnbuf; 11998 scf_pg_tmpl_t *pgt, *pgtp; 11999 scf_prop_tmpl_t *prt; 12000 12001 void **objects; 12002 char **names; 12003 void **tmpls; 12004 int allocd, i; 12005 12006 int ret; 12007 ssize_t pgnlen, prnlen, szret; 12008 size_t max_len = 0; 12009 12010 if (cur_svc == NULL && cur_inst == NULL) { 12011 semerr(emsg_entity_not_selected); 12012 return; 12013 } 12014 12015 if ((pg = scf_pg_create(g_hndl)) == NULL || 12016 (prop = scf_property_create(g_hndl)) == NULL || 12017 (iter = scf_iter_create(g_hndl)) == NULL || 12018 (piter = scf_iter_create(g_hndl)) == NULL || 12019 (prt = scf_tmpl_prop_create(g_hndl)) == NULL || 12020 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL) 12021 scfdie(); 12022 12023 prnbuf = safe_malloc(max_scf_name_len + 1); 12024 12025 if (cur_level != NULL) 12026 ret = scf_iter_snaplevel_pgs(iter, cur_level); 12027 else if (cur_inst != NULL) 12028 ret = scf_iter_instance_pgs(iter, cur_inst); 12029 else 12030 ret = scf_iter_service_pgs(iter, cur_svc); 12031 if (ret != 0) { 12032 return; 12033 } 12034 12035 /* 12036 * We want to only list items which match pattern, and we want the 12037 * second column to line up, so during the first pass we'll save 12038 * matching items, their names, and their templates in objects, 12039 * names, and tmpls, computing the maximum name length as we go, 12040 * and then we'll print them out. 12041 * 12042 * Note: We always keep an extra slot available so the array can be 12043 * NULL-terminated. 12044 */ 12045 i = 0; 12046 allocd = 1; 12047 objects = safe_malloc(sizeof (*objects)); 12048 names = safe_malloc(sizeof (*names)); 12049 tmpls = safe_malloc(sizeof (*tmpls)); 12050 12051 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 12052 int new_pg = 0; 12053 int print_props = 0; 12054 pgtp = NULL; 12055 12056 pgnlen = scf_pg_get_name(pg, NULL, 0); 12057 if (pgnlen < 0) 12058 scfdie(); 12059 12060 pgnbuf = safe_malloc(pgnlen + 1); 12061 12062 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1); 12063 if (szret < 0) 12064 scfdie(); 12065 assert(szret <= pgnlen); 12066 12067 if (scf_tmpl_get_by_pg(pg, pgt, NULL) == -1) { 12068 if (scf_error() != SCF_ERROR_NOT_FOUND) 12069 scfdie(); 12070 pgtp = NULL; 12071 } else { 12072 pgtp = pgt; 12073 } 12074 12075 if (pattern == NULL || 12076 fnmatch(pattern, pgnbuf, 0) == 0) { 12077 if (i+1 >= allocd) { 12078 allocd *= 2; 12079 objects = realloc(objects, 12080 sizeof (*objects) * allocd); 12081 names = 12082 realloc(names, sizeof (*names) * allocd); 12083 tmpls = realloc(tmpls, 12084 sizeof (*tmpls) * allocd); 12085 if (objects == NULL || names == NULL || 12086 tmpls == NULL) 12087 uu_die(gettext("Out of memory")); 12088 } 12089 objects[i] = pg; 12090 names[i] = pgnbuf; 12091 12092 if (pgtp == NULL) 12093 tmpls[i] = NULL; 12094 else 12095 tmpls[i] = pgt; 12096 12097 ++i; 12098 12099 if (pgnlen > max_len) 12100 max_len = pgnlen; 12101 12102 new_pg = 1; 12103 print_props = 1; 12104 } 12105 12106 if (only_pgs) { 12107 if (new_pg) { 12108 pg = scf_pg_create(g_hndl); 12109 if (pg == NULL) 12110 scfdie(); 12111 pgt = scf_tmpl_pg_create(g_hndl); 12112 if (pgt == NULL) 12113 scfdie(); 12114 } else 12115 free(pgnbuf); 12116 12117 continue; 12118 } 12119 12120 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 12121 scfdie(); 12122 12123 while ((ret = scf_iter_next_property(piter, prop)) == 1) { 12124 prnlen = scf_property_get_name(prop, prnbuf, 12125 max_scf_name_len + 1); 12126 if (prnlen < 0) 12127 scfdie(); 12128 12129 /* Will prepend the property group name and a slash. */ 12130 prnlen += pgnlen + 1; 12131 12132 ppnbuf = safe_malloc(prnlen + 1); 12133 12134 if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf, 12135 prnbuf) < 0) 12136 uu_die("snprintf"); 12137 12138 if (pattern == NULL || print_props == 1 || 12139 fnmatch(pattern, ppnbuf, 0) == 0) { 12140 if (i+1 >= allocd) { 12141 allocd *= 2; 12142 objects = realloc(objects, 12143 sizeof (*objects) * allocd); 12144 names = realloc(names, 12145 sizeof (*names) * allocd); 12146 tmpls = realloc(tmpls, 12147 sizeof (*tmpls) * allocd); 12148 if (objects == NULL || names == NULL || 12149 tmpls == NULL) 12150 uu_die(gettext( 12151 "Out of memory")); 12152 } 12153 12154 objects[i] = prop; 12155 names[i] = ppnbuf; 12156 12157 if (pgtp != NULL) { 12158 if (scf_tmpl_get_by_prop(pgt, prnbuf, 12159 prt, NULL) < 0) { 12160 if (scf_error() != 12161 SCF_ERROR_NOT_FOUND) 12162 scfdie(); 12163 tmpls[i] = NULL; 12164 } else { 12165 tmpls[i] = prt; 12166 } 12167 } else { 12168 tmpls[i] = NULL; 12169 } 12170 12171 ++i; 12172 12173 if (prnlen > max_len) 12174 max_len = prnlen; 12175 12176 prop = scf_property_create(g_hndl); 12177 prt = scf_tmpl_prop_create(g_hndl); 12178 } else { 12179 free(ppnbuf); 12180 } 12181 } 12182 12183 if (new_pg) { 12184 pg = scf_pg_create(g_hndl); 12185 if (pg == NULL) 12186 scfdie(); 12187 pgt = scf_tmpl_pg_create(g_hndl); 12188 if (pgt == NULL) 12189 scfdie(); 12190 } else 12191 free(pgnbuf); 12192 } 12193 if (ret != 0) 12194 scfdie(); 12195 12196 objects[i] = NULL; 12197 12198 scf_pg_destroy(pg); 12199 scf_tmpl_pg_destroy(pgt); 12200 scf_property_destroy(prop); 12201 scf_tmpl_prop_destroy(prt); 12202 12203 for (i = 0; objects[i] != NULL; ++i) { 12204 if (strchr(names[i], '/') == NULL) { 12205 /* property group */ 12206 pg = (scf_propertygroup_t *)objects[i]; 12207 pgt = (scf_pg_tmpl_t *)tmpls[i]; 12208 list_pg_info(pg, names[i], max_len); 12209 list_pg_tmpl(pgt, pg, templates); 12210 free(names[i]); 12211 scf_pg_destroy(pg); 12212 if (pgt != NULL) 12213 scf_tmpl_pg_destroy(pgt); 12214 } else { 12215 /* property */ 12216 prop = (scf_property_t *)objects[i]; 12217 prt = (scf_prop_tmpl_t *)tmpls[i]; 12218 list_prop_info(prop, names[i], max_len); 12219 list_prop_tmpl(prt, prop, templates); 12220 free(names[i]); 12221 scf_property_destroy(prop); 12222 if (prt != NULL) 12223 scf_tmpl_prop_destroy(prt); 12224 } 12225 } 12226 12227 free(names); 12228 free(objects); 12229 free(tmpls); 12230 } 12231 12232 void 12233 lscf_listpg(const char *pattern) 12234 { 12235 lscf_prep_hndl(); 12236 12237 listprop(pattern, 1, 0); 12238 } 12239 12240 /* 12241 * Property group and property creation, setting, and deletion. setprop (and 12242 * its alias, addprop) can either create a property group of a given type, or 12243 * it can create or set a property to a given type and list of values. 12244 */ 12245 void 12246 lscf_addpg(const char *name, const char *type, const char *flags) 12247 { 12248 scf_propertygroup_t *pg; 12249 int ret; 12250 uint32_t flgs = 0; 12251 const char *cp; 12252 12253 12254 lscf_prep_hndl(); 12255 12256 if (cur_snap != NULL) { 12257 semerr(emsg_cant_modify_snapshots); 12258 return; 12259 } 12260 12261 if (cur_inst == NULL && cur_svc == NULL) { 12262 semerr(emsg_entity_not_selected); 12263 return; 12264 } 12265 12266 if (flags != NULL) { 12267 for (cp = flags; *cp != '\0'; ++cp) { 12268 switch (*cp) { 12269 case 'P': 12270 flgs |= SCF_PG_FLAG_NONPERSISTENT; 12271 break; 12272 12273 case 'p': 12274 flgs &= ~SCF_PG_FLAG_NONPERSISTENT; 12275 break; 12276 12277 default: 12278 semerr(gettext("Invalid property group flag " 12279 "%c."), *cp); 12280 return; 12281 } 12282 } 12283 } 12284 12285 pg = scf_pg_create(g_hndl); 12286 if (pg == NULL) 12287 scfdie(); 12288 12289 if (cur_inst != NULL) 12290 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg); 12291 else 12292 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg); 12293 12294 if (ret != SCF_SUCCESS) { 12295 switch (scf_error()) { 12296 case SCF_ERROR_INVALID_ARGUMENT: 12297 semerr(gettext("Name, type, or flags are invalid.\n")); 12298 break; 12299 12300 case SCF_ERROR_EXISTS: 12301 semerr(gettext("Property group already exists.\n")); 12302 break; 12303 12304 case SCF_ERROR_PERMISSION_DENIED: 12305 semerr(emsg_permission_denied); 12306 break; 12307 12308 case SCF_ERROR_BACKEND_ACCESS: 12309 semerr(gettext("Backend refused access.\n")); 12310 break; 12311 12312 default: 12313 scfdie(); 12314 } 12315 } 12316 12317 scf_pg_destroy(pg); 12318 12319 private_refresh(); 12320 } 12321 12322 void 12323 lscf_delpg(char *name) 12324 { 12325 lscf_prep_hndl(); 12326 12327 if (cur_snap != NULL) { 12328 semerr(emsg_cant_modify_snapshots); 12329 return; 12330 } 12331 12332 if (cur_inst == NULL && cur_svc == NULL) { 12333 semerr(emsg_entity_not_selected); 12334 return; 12335 } 12336 12337 if (strchr(name, '/') != NULL) { 12338 semerr(emsg_invalid_pg_name, name); 12339 return; 12340 } 12341 12342 lscf_delprop(name); 12343 } 12344 12345 /* 12346 * scf_delhash() is used to remove the property group related to the 12347 * hash entry for a specific manifest in the repository. pgname will be 12348 * constructed from the location of the manifest file. If deathrow isn't 0, 12349 * manifest file doesn't need to exist (manifest string will be used as 12350 * an absolute path). 12351 */ 12352 void 12353 lscf_delhash(char *manifest, int deathrow) 12354 { 12355 char *pgname; 12356 12357 if (cur_snap != NULL || 12358 cur_inst != NULL || cur_svc != NULL) { 12359 warn(gettext("error, an entity is selected\n")); 12360 return; 12361 } 12362 12363 /* select smf/manifest */ 12364 lscf_select("smf/manifest"); 12365 /* 12366 * Translate the manifest file name to property name. In the deathrow 12367 * case, the manifest file does not need to exist. 12368 */ 12369 pgname = mhash_filename_to_propname(manifest, 12370 deathrow ? B_TRUE : B_FALSE); 12371 if (pgname == NULL) { 12372 warn(gettext("cannot resolve pathname for %s\n"), manifest); 12373 return; 12374 } 12375 /* delete the hash property name */ 12376 lscf_delpg(pgname); 12377 } 12378 12379 void 12380 lscf_listprop(const char *pattern) 12381 { 12382 lscf_prep_hndl(); 12383 12384 listprop(pattern, 0, 0); 12385 } 12386 12387 int 12388 lscf_setprop(const char *pgname, const char *type, const char *value, 12389 const uu_list_t *values) 12390 { 12391 scf_type_t ty, current_ty; 12392 scf_service_t *svc; 12393 scf_propertygroup_t *pg, *parent_pg; 12394 scf_property_t *prop, *parent_prop; 12395 scf_pg_tmpl_t *pgt; 12396 scf_prop_tmpl_t *prt; 12397 int ret, result = 0; 12398 scf_transaction_t *tx; 12399 scf_transaction_entry_t *e; 12400 scf_value_t *v; 12401 uu_list_walk_t *walk; 12402 string_list_t *sp; 12403 char *propname; 12404 int req_quotes = 0; 12405 12406 lscf_prep_hndl(); 12407 12408 if ((e = scf_entry_create(g_hndl)) == NULL || 12409 (svc = scf_service_create(g_hndl)) == NULL || 12410 (parent_pg = scf_pg_create(g_hndl)) == NULL || 12411 (pg = scf_pg_create(g_hndl)) == NULL || 12412 (parent_prop = scf_property_create(g_hndl)) == NULL || 12413 (prop = scf_property_create(g_hndl)) == NULL || 12414 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL || 12415 (prt = scf_tmpl_prop_create(g_hndl)) == NULL || 12416 (tx = scf_transaction_create(g_hndl)) == NULL) 12417 scfdie(); 12418 12419 if (cur_snap != NULL) { 12420 semerr(emsg_cant_modify_snapshots); 12421 goto fail; 12422 } 12423 12424 if (cur_inst == NULL && cur_svc == NULL) { 12425 semerr(emsg_entity_not_selected); 12426 goto fail; 12427 } 12428 12429 propname = strchr(pgname, '/'); 12430 if (propname == NULL) { 12431 semerr(gettext("Property names must contain a `/'.\n")); 12432 goto fail; 12433 } 12434 12435 *propname = '\0'; 12436 ++propname; 12437 12438 if (type != NULL) { 12439 ty = string_to_type(type); 12440 if (ty == SCF_TYPE_INVALID) { 12441 semerr(gettext("Unknown type \"%s\".\n"), type); 12442 goto fail; 12443 } 12444 } 12445 12446 if (cur_inst != NULL) 12447 ret = scf_instance_get_pg(cur_inst, pgname, pg); 12448 else 12449 ret = scf_service_get_pg(cur_svc, pgname, pg); 12450 if (ret != SCF_SUCCESS) { 12451 switch (scf_error()) { 12452 case SCF_ERROR_NOT_FOUND: 12453 semerr(emsg_no_such_pg, pgname); 12454 goto fail; 12455 12456 case SCF_ERROR_INVALID_ARGUMENT: 12457 semerr(emsg_invalid_pg_name, pgname); 12458 goto fail; 12459 12460 default: 12461 scfdie(); 12462 break; 12463 } 12464 } 12465 12466 do { 12467 if (scf_pg_update(pg) == -1) 12468 scfdie(); 12469 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 12470 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12471 scfdie(); 12472 12473 semerr(emsg_permission_denied); 12474 goto fail; 12475 } 12476 12477 ret = scf_pg_get_property(pg, propname, prop); 12478 if (ret == SCF_SUCCESS) { 12479 if (scf_property_type(prop, ¤t_ty) != SCF_SUCCESS) 12480 scfdie(); 12481 12482 if (type == NULL) 12483 ty = current_ty; 12484 if (scf_transaction_property_change_type(tx, e, 12485 propname, ty) == -1) 12486 scfdie(); 12487 12488 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 12489 /* Infer the type, if possible. */ 12490 if (type == NULL) { 12491 /* 12492 * First check if we're an instance and the 12493 * property is set on the service. 12494 */ 12495 if (cur_inst != NULL && 12496 scf_instance_get_parent(cur_inst, 12497 svc) == 0 && 12498 scf_service_get_pg(cur_svc, pgname, 12499 parent_pg) == 0 && 12500 scf_pg_get_property(parent_pg, propname, 12501 parent_prop) == 0 && 12502 scf_property_type(parent_prop, 12503 ¤t_ty) == 0) { 12504 ty = current_ty; 12505 12506 /* Then check for a type set in a template. */ 12507 } else if (scf_tmpl_get_by_pg(pg, pgt, 12508 NULL) == 0 && 12509 scf_tmpl_get_by_prop(pgt, propname, prt, 12510 NULL) == 0 && 12511 scf_tmpl_prop_type(prt, ¤t_ty) == 0) { 12512 ty = current_ty; 12513 12514 /* If type can't be inferred, fail. */ 12515 } else { 12516 semerr(gettext("Type required for new " 12517 "properties.\n")); 12518 goto fail; 12519 } 12520 } 12521 if (scf_transaction_property_new(tx, e, propname, 12522 ty) == -1) 12523 scfdie(); 12524 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 12525 semerr(emsg_invalid_prop_name, propname); 12526 goto fail; 12527 } else { 12528 scfdie(); 12529 } 12530 12531 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING) 12532 req_quotes = 1; 12533 12534 if (value != NULL) { 12535 v = string_to_value(value, ty, 0); 12536 12537 if (v == NULL) 12538 goto fail; 12539 12540 ret = scf_entry_add_value(e, v); 12541 assert(ret == SCF_SUCCESS); 12542 } else { 12543 assert(values != NULL); 12544 12545 walk = uu_list_walk_start((uu_list_t *)values, 12546 UU_DEFAULT); 12547 if (walk == NULL) 12548 uu_die(gettext("Could not walk list")); 12549 12550 for (sp = uu_list_walk_next(walk); sp != NULL; 12551 sp = uu_list_walk_next(walk)) { 12552 v = string_to_value(sp->str, ty, req_quotes); 12553 12554 if (v == NULL) { 12555 scf_entry_destroy_children(e); 12556 goto fail; 12557 } 12558 12559 ret = scf_entry_add_value(e, v); 12560 assert(ret == SCF_SUCCESS); 12561 } 12562 uu_list_walk_end(walk); 12563 } 12564 result = scf_transaction_commit(tx); 12565 12566 scf_transaction_reset(tx); 12567 scf_entry_destroy_children(e); 12568 } while (result == 0); 12569 12570 if (result < 0) { 12571 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12572 scfdie(); 12573 12574 semerr(emsg_permission_denied); 12575 goto fail; 12576 } 12577 12578 ret = 0; 12579 12580 private_refresh(); 12581 12582 goto cleanup; 12583 12584 fail: 12585 ret = -1; 12586 12587 cleanup: 12588 scf_transaction_destroy(tx); 12589 scf_entry_destroy(e); 12590 scf_service_destroy(svc); 12591 scf_pg_destroy(parent_pg); 12592 scf_pg_destroy(pg); 12593 scf_property_destroy(parent_prop); 12594 scf_property_destroy(prop); 12595 scf_tmpl_pg_destroy(pgt); 12596 scf_tmpl_prop_destroy(prt); 12597 12598 return (ret); 12599 } 12600 12601 void 12602 lscf_delprop(char *pgn) 12603 { 12604 char *slash, *pn; 12605 scf_propertygroup_t *pg; 12606 scf_transaction_t *tx; 12607 scf_transaction_entry_t *e; 12608 int ret; 12609 12610 12611 lscf_prep_hndl(); 12612 12613 if (cur_snap != NULL) { 12614 semerr(emsg_cant_modify_snapshots); 12615 return; 12616 } 12617 12618 if (cur_inst == NULL && cur_svc == NULL) { 12619 semerr(emsg_entity_not_selected); 12620 return; 12621 } 12622 12623 pg = scf_pg_create(g_hndl); 12624 if (pg == NULL) 12625 scfdie(); 12626 12627 slash = strchr(pgn, '/'); 12628 if (slash == NULL) { 12629 pn = NULL; 12630 } else { 12631 *slash = '\0'; 12632 pn = slash + 1; 12633 } 12634 12635 if (cur_inst != NULL) 12636 ret = scf_instance_get_pg(cur_inst, pgn, pg); 12637 else 12638 ret = scf_service_get_pg(cur_svc, pgn, pg); 12639 if (ret != SCF_SUCCESS) { 12640 switch (scf_error()) { 12641 case SCF_ERROR_NOT_FOUND: 12642 semerr(emsg_no_such_pg, pgn); 12643 break; 12644 12645 case SCF_ERROR_INVALID_ARGUMENT: 12646 semerr(emsg_invalid_pg_name, pgn); 12647 break; 12648 12649 default: 12650 scfdie(); 12651 } 12652 12653 scf_pg_destroy(pg); 12654 12655 return; 12656 } 12657 12658 if (pn == NULL) { 12659 /* Try to delete the property group. */ 12660 if (scf_pg_delete(pg) != SCF_SUCCESS) { 12661 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12662 scfdie(); 12663 12664 semerr(emsg_permission_denied); 12665 } else { 12666 private_refresh(); 12667 } 12668 12669 scf_pg_destroy(pg); 12670 return; 12671 } 12672 12673 e = scf_entry_create(g_hndl); 12674 tx = scf_transaction_create(g_hndl); 12675 12676 do { 12677 if (scf_pg_update(pg) == -1) 12678 scfdie(); 12679 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 12680 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12681 scfdie(); 12682 12683 semerr(emsg_permission_denied); 12684 break; 12685 } 12686 12687 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) { 12688 if (scf_error() == SCF_ERROR_NOT_FOUND) { 12689 semerr(gettext("No such property %s/%s.\n"), 12690 pgn, pn); 12691 break; 12692 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 12693 semerr(emsg_invalid_prop_name, pn); 12694 break; 12695 } else { 12696 scfdie(); 12697 } 12698 } 12699 12700 ret = scf_transaction_commit(tx); 12701 12702 if (ret == 0) 12703 scf_transaction_reset(tx); 12704 } while (ret == 0); 12705 12706 if (ret < 0) { 12707 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12708 scfdie(); 12709 12710 semerr(emsg_permission_denied); 12711 } else { 12712 private_refresh(); 12713 } 12714 12715 scf_transaction_destroy(tx); 12716 scf_entry_destroy(e); 12717 scf_pg_destroy(pg); 12718 } 12719 12720 /* 12721 * Property editing. 12722 */ 12723 12724 static int 12725 write_edit_script(FILE *strm) 12726 { 12727 char *fmribuf; 12728 ssize_t fmrilen; 12729 12730 scf_propertygroup_t *pg; 12731 scf_property_t *prop; 12732 scf_value_t *val; 12733 scf_type_t ty; 12734 int ret, result = 0; 12735 scf_iter_t *iter, *piter, *viter; 12736 char *buf, *tybuf, *pname; 12737 const char *emsg_write_error; 12738 12739 12740 emsg_write_error = gettext("Error writing temoprary file: %s.\n"); 12741 12742 12743 /* select fmri */ 12744 if (cur_inst != NULL) { 12745 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0); 12746 if (fmrilen < 0) 12747 scfdie(); 12748 fmribuf = safe_malloc(fmrilen + 1); 12749 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0) 12750 scfdie(); 12751 } else { 12752 assert(cur_svc != NULL); 12753 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0); 12754 if (fmrilen < 0) 12755 scfdie(); 12756 fmribuf = safe_malloc(fmrilen + 1); 12757 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0) 12758 scfdie(); 12759 } 12760 12761 if (fprintf(strm, "select %s\n\n", fmribuf) < 0) { 12762 warn(emsg_write_error, strerror(errno)); 12763 free(fmribuf); 12764 return (-1); 12765 } 12766 12767 free(fmribuf); 12768 12769 12770 if ((pg = scf_pg_create(g_hndl)) == NULL || 12771 (prop = scf_property_create(g_hndl)) == NULL || 12772 (val = scf_value_create(g_hndl)) == NULL || 12773 (iter = scf_iter_create(g_hndl)) == NULL || 12774 (piter = scf_iter_create(g_hndl)) == NULL || 12775 (viter = scf_iter_create(g_hndl)) == NULL) 12776 scfdie(); 12777 12778 buf = safe_malloc(max_scf_name_len + 1); 12779 tybuf = safe_malloc(max_scf_pg_type_len + 1); 12780 pname = safe_malloc(max_scf_name_len + 1); 12781 12782 if (cur_inst != NULL) 12783 ret = scf_iter_instance_pgs(iter, cur_inst); 12784 else 12785 ret = scf_iter_service_pgs(iter, cur_svc); 12786 if (ret != SCF_SUCCESS) 12787 scfdie(); 12788 12789 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 12790 int ret2; 12791 12792 /* 12793 * # delprop pg 12794 * # addpg pg type 12795 */ 12796 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0) 12797 scfdie(); 12798 12799 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0) 12800 scfdie(); 12801 12802 if (fprintf(strm, "# Property group \"%s\"\n" 12803 "# delprop %s\n" 12804 "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) { 12805 warn(emsg_write_error, strerror(errno)); 12806 result = -1; 12807 goto out; 12808 } 12809 12810 /* # setprop pg/prop = (values) */ 12811 12812 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 12813 scfdie(); 12814 12815 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) { 12816 int first = 1; 12817 int ret3; 12818 int multiple; 12819 int is_str; 12820 scf_type_t bty; 12821 12822 if (scf_property_get_name(prop, pname, 12823 max_scf_name_len + 1) < 0) 12824 scfdie(); 12825 12826 if (scf_property_type(prop, &ty) != 0) 12827 scfdie(); 12828 12829 multiple = prop_has_multiple_values(prop, val); 12830 12831 if (fprintf(strm, "# setprop %s/%s = %s: %s", buf, 12832 pname, scf_type_to_string(ty), multiple ? "(" : "") 12833 < 0) { 12834 warn(emsg_write_error, strerror(errno)); 12835 result = -1; 12836 goto out; 12837 } 12838 12839 (void) scf_type_base_type(ty, &bty); 12840 is_str = (bty == SCF_TYPE_ASTRING); 12841 12842 if (scf_iter_property_values(viter, prop) != 12843 SCF_SUCCESS) 12844 scfdie(); 12845 12846 while ((ret3 = scf_iter_next_value(viter, val)) == 1) { 12847 char *buf; 12848 ssize_t buflen; 12849 12850 buflen = scf_value_get_as_string(val, NULL, 0); 12851 if (buflen < 0) 12852 scfdie(); 12853 12854 buf = safe_malloc(buflen + 1); 12855 12856 if (scf_value_get_as_string(val, buf, 12857 buflen + 1) < 0) 12858 scfdie(); 12859 12860 if (first) 12861 first = 0; 12862 else { 12863 if (putc(' ', strm) != ' ') { 12864 warn(emsg_write_error, 12865 strerror(errno)); 12866 result = -1; 12867 goto out; 12868 } 12869 } 12870 12871 if ((is_str && multiple) || 12872 strpbrk(buf, CHARS_TO_QUOTE) != NULL) { 12873 (void) putc('"', strm); 12874 (void) quote_and_print(buf, strm, 1); 12875 (void) putc('"', strm); 12876 12877 if (ferror(strm)) { 12878 warn(emsg_write_error, 12879 strerror(errno)); 12880 result = -1; 12881 goto out; 12882 } 12883 } else { 12884 if (fprintf(strm, "%s", buf) < 0) { 12885 warn(emsg_write_error, 12886 strerror(errno)); 12887 result = -1; 12888 goto out; 12889 } 12890 } 12891 12892 free(buf); 12893 } 12894 if (ret3 < 0 && 12895 scf_error() != SCF_ERROR_PERMISSION_DENIED) 12896 scfdie(); 12897 12898 /* Write closing paren if mult-value property */ 12899 if ((multiple && putc(')', strm) == EOF) || 12900 12901 /* Write final newline */ 12902 fputc('\n', strm) == EOF) { 12903 warn(emsg_write_error, strerror(errno)); 12904 result = -1; 12905 goto out; 12906 } 12907 } 12908 if (ret2 < 0) 12909 scfdie(); 12910 12911 if (fputc('\n', strm) == EOF) { 12912 warn(emsg_write_error, strerror(errno)); 12913 result = -1; 12914 goto out; 12915 } 12916 } 12917 if (ret < 0) 12918 scfdie(); 12919 12920 out: 12921 free(pname); 12922 free(tybuf); 12923 free(buf); 12924 scf_iter_destroy(viter); 12925 scf_iter_destroy(piter); 12926 scf_iter_destroy(iter); 12927 scf_value_destroy(val); 12928 scf_property_destroy(prop); 12929 scf_pg_destroy(pg); 12930 12931 if (result == 0) { 12932 if (fflush(strm) != 0) { 12933 warn(emsg_write_error, strerror(errno)); 12934 return (-1); 12935 } 12936 } 12937 12938 return (result); 12939 } 12940 12941 int 12942 lscf_editprop() 12943 { 12944 char *buf, *editor; 12945 size_t bufsz; 12946 int tmpfd; 12947 char tempname[] = TEMP_FILE_PATTERN; 12948 12949 lscf_prep_hndl(); 12950 12951 if (cur_snap != NULL) { 12952 semerr(emsg_cant_modify_snapshots); 12953 return (-1); 12954 } 12955 12956 if (cur_svc == NULL && cur_inst == NULL) { 12957 semerr(emsg_entity_not_selected); 12958 return (-1); 12959 } 12960 12961 tmpfd = mkstemp(tempname); 12962 if (tmpfd == -1) { 12963 semerr(gettext("Could not create temporary file.\n")); 12964 return (-1); 12965 } 12966 12967 (void) strcpy(tempfilename, tempname); 12968 12969 tempfile = fdopen(tmpfd, "r+"); 12970 if (tempfile == NULL) { 12971 warn(gettext("Could not create temporary file.\n")); 12972 if (close(tmpfd) == -1) 12973 warn(gettext("Could not close temporary file: %s.\n"), 12974 strerror(errno)); 12975 12976 remove_tempfile(); 12977 12978 return (-1); 12979 } 12980 12981 if (write_edit_script(tempfile) == -1) { 12982 remove_tempfile(); 12983 return (-1); 12984 } 12985 12986 editor = getenv("EDITOR"); 12987 if (editor == NULL) 12988 editor = "vi"; 12989 12990 bufsz = strlen(editor) + 1 + strlen(tempname) + 1; 12991 buf = safe_malloc(bufsz); 12992 12993 if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0) 12994 uu_die(gettext("Error creating editor command")); 12995 12996 if (system(buf) == -1) { 12997 semerr(gettext("Could not launch editor %s: %s\n"), editor, 12998 strerror(errno)); 12999 free(buf); 13000 remove_tempfile(); 13001 return (-1); 13002 } 13003 13004 free(buf); 13005 13006 (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE); 13007 13008 remove_tempfile(); 13009 13010 return (0); 13011 } 13012 13013 static void 13014 add_string(uu_list_t *strlist, const char *str) 13015 { 13016 string_list_t *elem; 13017 elem = safe_malloc(sizeof (*elem)); 13018 uu_list_node_init(elem, &elem->node, string_pool); 13019 elem->str = safe_strdup(str); 13020 if (uu_list_append(strlist, elem) != 0) 13021 uu_die(gettext("libuutil error: %s\n"), 13022 uu_strerror(uu_error())); 13023 } 13024 13025 /* 13026 * Get all property values that don't match the given glob pattern, 13027 * if a pattern is specified. 13028 */ 13029 static void 13030 get_prop_values(scf_property_t *prop, uu_list_t *values, 13031 const char *pattern) 13032 { 13033 scf_iter_t *iter; 13034 scf_value_t *val; 13035 int ret; 13036 13037 if ((iter = scf_iter_create(g_hndl)) == NULL || 13038 (val = scf_value_create(g_hndl)) == NULL) 13039 scfdie(); 13040 13041 if (scf_iter_property_values(iter, prop) != 0) 13042 scfdie(); 13043 13044 while ((ret = scf_iter_next_value(iter, val)) == 1) { 13045 char *buf; 13046 ssize_t vlen, szret; 13047 13048 vlen = scf_value_get_as_string(val, NULL, 0); 13049 if (vlen < 0) 13050 scfdie(); 13051 13052 buf = safe_malloc(vlen + 1); 13053 13054 szret = scf_value_get_as_string(val, buf, vlen + 1); 13055 if (szret < 0) 13056 scfdie(); 13057 assert(szret <= vlen); 13058 13059 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0) 13060 add_string(values, buf); 13061 13062 free(buf); 13063 } 13064 13065 if (ret == -1) 13066 scfdie(); 13067 13068 scf_value_destroy(val); 13069 scf_iter_destroy(iter); 13070 } 13071 13072 static int 13073 lscf_setpropvalue(const char *pgname, const char *type, 13074 const char *arg, int isadd, int isnotfoundok) 13075 { 13076 scf_type_t ty; 13077 scf_propertygroup_t *pg; 13078 scf_property_t *prop; 13079 int ret, result = 0; 13080 scf_transaction_t *tx; 13081 scf_transaction_entry_t *e; 13082 scf_value_t *v; 13083 string_list_t *sp; 13084 char *propname; 13085 uu_list_t *values; 13086 uu_list_walk_t *walk; 13087 void *cookie = NULL; 13088 char *pattern = NULL; 13089 13090 lscf_prep_hndl(); 13091 13092 if ((values = uu_list_create(string_pool, NULL, 0)) == NULL) 13093 uu_die(gettext("Could not create property list: %s\n"), 13094 uu_strerror(uu_error())); 13095 13096 if (!isadd) 13097 pattern = safe_strdup(arg); 13098 13099 if ((e = scf_entry_create(g_hndl)) == NULL || 13100 (pg = scf_pg_create(g_hndl)) == NULL || 13101 (prop = scf_property_create(g_hndl)) == NULL || 13102 (tx = scf_transaction_create(g_hndl)) == NULL) 13103 scfdie(); 13104 13105 if (cur_snap != NULL) { 13106 semerr(emsg_cant_modify_snapshots); 13107 goto fail; 13108 } 13109 13110 if (cur_inst == NULL && cur_svc == NULL) { 13111 semerr(emsg_entity_not_selected); 13112 goto fail; 13113 } 13114 13115 propname = strchr(pgname, '/'); 13116 if (propname == NULL) { 13117 semerr(gettext("Property names must contain a `/'.\n")); 13118 goto fail; 13119 } 13120 13121 *propname = '\0'; 13122 ++propname; 13123 13124 if (type != NULL) { 13125 ty = string_to_type(type); 13126 if (ty == SCF_TYPE_INVALID) { 13127 semerr(gettext("Unknown type \"%s\".\n"), type); 13128 goto fail; 13129 } 13130 } 13131 13132 if (cur_inst != NULL) 13133 ret = scf_instance_get_pg(cur_inst, pgname, pg); 13134 else 13135 ret = scf_service_get_pg(cur_svc, pgname, pg); 13136 if (ret != 0) { 13137 switch (scf_error()) { 13138 case SCF_ERROR_NOT_FOUND: 13139 if (isnotfoundok) { 13140 result = 0; 13141 } else { 13142 semerr(emsg_no_such_pg, pgname); 13143 result = -1; 13144 } 13145 goto out; 13146 13147 case SCF_ERROR_INVALID_ARGUMENT: 13148 semerr(emsg_invalid_pg_name, pgname); 13149 goto fail; 13150 13151 default: 13152 scfdie(); 13153 } 13154 } 13155 13156 do { 13157 if (scf_pg_update(pg) == -1) 13158 scfdie(); 13159 if (scf_transaction_start(tx, pg) != 0) { 13160 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13161 scfdie(); 13162 13163 semerr(emsg_permission_denied); 13164 goto fail; 13165 } 13166 13167 ret = scf_pg_get_property(pg, propname, prop); 13168 if (ret == 0) { 13169 scf_type_t ptype; 13170 char *pat = pattern; 13171 13172 if (scf_property_type(prop, &ptype) != 0) 13173 scfdie(); 13174 13175 if (isadd) { 13176 if (type != NULL && ptype != ty) { 13177 semerr(gettext("Property \"%s\" is not " 13178 "of type \"%s\".\n"), propname, 13179 type); 13180 goto fail; 13181 } 13182 13183 pat = NULL; 13184 } else { 13185 size_t len = strlen(pat); 13186 if (len > 0 && pat[len - 1] == '\"') 13187 pat[len - 1] = '\0'; 13188 if (len > 0 && pat[0] == '\"') 13189 pat++; 13190 } 13191 13192 ty = ptype; 13193 13194 get_prop_values(prop, values, pat); 13195 13196 if (isadd) 13197 add_string(values, arg); 13198 13199 if (scf_transaction_property_change(tx, e, 13200 propname, ty) == -1) 13201 scfdie(); 13202 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 13203 if (isadd) { 13204 if (type == NULL) { 13205 semerr(gettext("Type required " 13206 "for new properties.\n")); 13207 goto fail; 13208 } 13209 13210 add_string(values, arg); 13211 13212 if (scf_transaction_property_new(tx, e, 13213 propname, ty) == -1) 13214 scfdie(); 13215 } else if (isnotfoundok) { 13216 result = 0; 13217 goto out; 13218 } else { 13219 semerr(gettext("No such property %s/%s.\n"), 13220 pgname, propname); 13221 result = -1; 13222 goto out; 13223 } 13224 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 13225 semerr(emsg_invalid_prop_name, propname); 13226 goto fail; 13227 } else { 13228 scfdie(); 13229 } 13230 13231 walk = uu_list_walk_start(values, UU_DEFAULT); 13232 if (walk == NULL) 13233 uu_die(gettext("Could not walk property list.\n")); 13234 13235 for (sp = uu_list_walk_next(walk); sp != NULL; 13236 sp = uu_list_walk_next(walk)) { 13237 v = string_to_value(sp->str, ty, 0); 13238 13239 if (v == NULL) { 13240 scf_entry_destroy_children(e); 13241 goto fail; 13242 } 13243 ret = scf_entry_add_value(e, v); 13244 assert(ret == 0); 13245 } 13246 uu_list_walk_end(walk); 13247 13248 result = scf_transaction_commit(tx); 13249 13250 scf_transaction_reset(tx); 13251 scf_entry_destroy_children(e); 13252 } while (result == 0); 13253 13254 if (result < 0) { 13255 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13256 scfdie(); 13257 13258 semerr(emsg_permission_denied); 13259 goto fail; 13260 } 13261 13262 result = 0; 13263 13264 private_refresh(); 13265 13266 out: 13267 scf_transaction_destroy(tx); 13268 scf_entry_destroy(e); 13269 scf_pg_destroy(pg); 13270 scf_property_destroy(prop); 13271 free(pattern); 13272 13273 while ((sp = uu_list_teardown(values, &cookie)) != NULL) { 13274 free(sp->str); 13275 free(sp); 13276 } 13277 13278 uu_list_destroy(values); 13279 13280 return (result); 13281 13282 fail: 13283 result = -1; 13284 goto out; 13285 } 13286 13287 int 13288 lscf_addpropvalue(const char *pgname, const char *type, const char *value) 13289 { 13290 return (lscf_setpropvalue(pgname, type, value, 1, 0)); 13291 } 13292 13293 int 13294 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok) 13295 { 13296 return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok)); 13297 } 13298 13299 /* 13300 * Look for a standard start method, first in the instance (if any), 13301 * then the service. 13302 */ 13303 static const char * 13304 start_method_name(int *in_instance) 13305 { 13306 scf_propertygroup_t *pg; 13307 char **p; 13308 int ret; 13309 scf_instance_t *inst = cur_inst; 13310 13311 if ((pg = scf_pg_create(g_hndl)) == NULL) 13312 scfdie(); 13313 13314 again: 13315 for (p = start_method_names; *p != NULL; p++) { 13316 if (inst != NULL) 13317 ret = scf_instance_get_pg(inst, *p, pg); 13318 else 13319 ret = scf_service_get_pg(cur_svc, *p, pg); 13320 13321 if (ret == 0) { 13322 size_t bufsz = strlen(SCF_GROUP_METHOD) + 1; 13323 char *buf = safe_malloc(bufsz); 13324 13325 if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) { 13326 free(buf); 13327 continue; 13328 } 13329 if (strcmp(buf, SCF_GROUP_METHOD) != 0) { 13330 free(buf); 13331 continue; 13332 } 13333 13334 free(buf); 13335 *in_instance = (inst != NULL); 13336 scf_pg_destroy(pg); 13337 return (*p); 13338 } 13339 13340 if (scf_error() == SCF_ERROR_NOT_FOUND) 13341 continue; 13342 13343 scfdie(); 13344 } 13345 13346 if (inst != NULL) { 13347 inst = NULL; 13348 goto again; 13349 } 13350 13351 scf_pg_destroy(pg); 13352 return (NULL); 13353 } 13354 13355 static int 13356 addpg(const char *name, const char *type) 13357 { 13358 scf_propertygroup_t *pg; 13359 int ret; 13360 13361 pg = scf_pg_create(g_hndl); 13362 if (pg == NULL) 13363 scfdie(); 13364 13365 if (cur_inst != NULL) 13366 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg); 13367 else 13368 ret = scf_service_add_pg(cur_svc, name, type, 0, pg); 13369 13370 if (ret != 0) { 13371 switch (scf_error()) { 13372 case SCF_ERROR_EXISTS: 13373 ret = 0; 13374 break; 13375 13376 case SCF_ERROR_PERMISSION_DENIED: 13377 semerr(emsg_permission_denied); 13378 break; 13379 13380 default: 13381 scfdie(); 13382 } 13383 } 13384 13385 scf_pg_destroy(pg); 13386 return (ret); 13387 } 13388 13389 int 13390 lscf_setenv(uu_list_t *args, int isunset) 13391 { 13392 int ret = 0; 13393 size_t i; 13394 int argc; 13395 char **argv = NULL; 13396 string_list_t *slp; 13397 char *pattern; 13398 char *prop; 13399 int do_service = 0; 13400 int do_instance = 0; 13401 const char *method = NULL; 13402 const char *name = NULL; 13403 const char *value = NULL; 13404 scf_instance_t *saved_cur_inst = cur_inst; 13405 13406 lscf_prep_hndl(); 13407 13408 argc = uu_list_numnodes(args); 13409 if (argc < 1) 13410 goto usage; 13411 13412 argv = calloc(argc + 1, sizeof (char *)); 13413 if (argv == NULL) 13414 uu_die(gettext("Out of memory.\n")); 13415 13416 for (slp = uu_list_first(args), i = 0; 13417 slp != NULL; 13418 slp = uu_list_next(args, slp), ++i) 13419 argv[i] = slp->str; 13420 13421 argv[i] = NULL; 13422 13423 opterr = 0; 13424 optind = 0; 13425 for (;;) { 13426 ret = getopt(argc, argv, "sim:"); 13427 if (ret == -1) 13428 break; 13429 13430 switch (ret) { 13431 case 's': 13432 do_service = 1; 13433 cur_inst = NULL; 13434 break; 13435 13436 case 'i': 13437 do_instance = 1; 13438 break; 13439 13440 case 'm': 13441 method = optarg; 13442 break; 13443 13444 case '?': 13445 goto usage; 13446 13447 default: 13448 bad_error("getopt", ret); 13449 } 13450 } 13451 13452 argc -= optind; 13453 if ((do_service && do_instance) || 13454 (isunset && argc != 1) || 13455 (!isunset && argc != 2)) 13456 goto usage; 13457 13458 name = argv[optind]; 13459 if (!isunset) 13460 value = argv[optind + 1]; 13461 13462 if (cur_snap != NULL) { 13463 semerr(emsg_cant_modify_snapshots); 13464 ret = -1; 13465 goto out; 13466 } 13467 13468 if (cur_inst == NULL && cur_svc == NULL) { 13469 semerr(emsg_entity_not_selected); 13470 ret = -1; 13471 goto out; 13472 } 13473 13474 if (do_instance && cur_inst == NULL) { 13475 semerr(gettext("No instance is selected.\n")); 13476 ret = -1; 13477 goto out; 13478 } 13479 13480 if (do_service && cur_svc == NULL) { 13481 semerr(gettext("No service is selected.\n")); 13482 ret = -1; 13483 goto out; 13484 } 13485 13486 if (method == NULL) { 13487 if (do_instance || do_service) { 13488 method = "method_context"; 13489 if (!isunset) { 13490 ret = addpg("method_context", 13491 SCF_GROUP_FRAMEWORK); 13492 if (ret != 0) 13493 goto out; 13494 } 13495 } else { 13496 int in_instance; 13497 method = start_method_name(&in_instance); 13498 if (method == NULL) { 13499 semerr(gettext( 13500 "Couldn't find start method; please " 13501 "specify a method with '-m'.\n")); 13502 ret = -1; 13503 goto out; 13504 } 13505 if (!in_instance) 13506 cur_inst = NULL; 13507 } 13508 } else { 13509 scf_propertygroup_t *pg; 13510 size_t bufsz; 13511 char *buf; 13512 int ret; 13513 13514 if ((pg = scf_pg_create(g_hndl)) == NULL) 13515 scfdie(); 13516 13517 if (cur_inst != NULL) 13518 ret = scf_instance_get_pg(cur_inst, method, pg); 13519 else 13520 ret = scf_service_get_pg(cur_svc, method, pg); 13521 13522 if (ret != 0) { 13523 scf_pg_destroy(pg); 13524 switch (scf_error()) { 13525 case SCF_ERROR_NOT_FOUND: 13526 semerr(gettext("Couldn't find the method " 13527 "\"%s\".\n"), method); 13528 goto out; 13529 13530 case SCF_ERROR_INVALID_ARGUMENT: 13531 semerr(gettext("Invalid method name \"%s\".\n"), 13532 method); 13533 goto out; 13534 13535 default: 13536 scfdie(); 13537 } 13538 } 13539 13540 bufsz = strlen(SCF_GROUP_METHOD) + 1; 13541 buf = safe_malloc(bufsz); 13542 13543 if (scf_pg_get_type(pg, buf, bufsz) < 0 || 13544 strcmp(buf, SCF_GROUP_METHOD) != 0) { 13545 semerr(gettext("Property group \"%s\" is not of type " 13546 "\"method\".\n"), method); 13547 ret = -1; 13548 free(buf); 13549 scf_pg_destroy(pg); 13550 goto out; 13551 } 13552 13553 free(buf); 13554 scf_pg_destroy(pg); 13555 } 13556 13557 prop = uu_msprintf("%s/environment", method); 13558 pattern = uu_msprintf("%s=*", name); 13559 13560 if (prop == NULL || pattern == NULL) 13561 uu_die(gettext("Out of memory.\n")); 13562 13563 ret = lscf_delpropvalue(prop, pattern, !isunset); 13564 13565 if (ret == 0 && !isunset) { 13566 uu_free(pattern); 13567 uu_free(prop); 13568 prop = uu_msprintf("%s/environment", method); 13569 pattern = uu_msprintf("%s=%s", name, value); 13570 if (prop == NULL || pattern == NULL) 13571 uu_die(gettext("Out of memory.\n")); 13572 ret = lscf_addpropvalue(prop, "astring:", pattern); 13573 } 13574 uu_free(pattern); 13575 uu_free(prop); 13576 13577 out: 13578 cur_inst = saved_cur_inst; 13579 13580 free(argv); 13581 return (ret); 13582 usage: 13583 ret = -2; 13584 goto out; 13585 } 13586 13587 /* 13588 * Snapshot commands 13589 */ 13590 13591 void 13592 lscf_listsnap() 13593 { 13594 scf_snapshot_t *snap; 13595 scf_iter_t *iter; 13596 char *nb; 13597 int r; 13598 13599 lscf_prep_hndl(); 13600 13601 if (cur_inst == NULL) { 13602 semerr(gettext("Instance not selected.\n")); 13603 return; 13604 } 13605 13606 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 13607 (iter = scf_iter_create(g_hndl)) == NULL) 13608 scfdie(); 13609 13610 if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS) 13611 scfdie(); 13612 13613 nb = safe_malloc(max_scf_name_len + 1); 13614 13615 while ((r = scf_iter_next_snapshot(iter, snap)) == 1) { 13616 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0) 13617 scfdie(); 13618 13619 (void) puts(nb); 13620 } 13621 if (r < 0) 13622 scfdie(); 13623 13624 free(nb); 13625 scf_iter_destroy(iter); 13626 scf_snapshot_destroy(snap); 13627 } 13628 13629 void 13630 lscf_selectsnap(const char *name) 13631 { 13632 scf_snapshot_t *snap; 13633 scf_snaplevel_t *level; 13634 13635 lscf_prep_hndl(); 13636 13637 if (cur_inst == NULL) { 13638 semerr(gettext("Instance not selected.\n")); 13639 return; 13640 } 13641 13642 if (cur_snap != NULL) { 13643 if (name != NULL) { 13644 char *cur_snap_name; 13645 boolean_t nochange; 13646 13647 cur_snap_name = safe_malloc(max_scf_name_len + 1); 13648 13649 if (scf_snapshot_get_name(cur_snap, cur_snap_name, 13650 max_scf_name_len + 1) < 0) 13651 scfdie(); 13652 13653 nochange = strcmp(name, cur_snap_name) == 0; 13654 13655 free(cur_snap_name); 13656 13657 if (nochange) 13658 return; 13659 } 13660 13661 unselect_cursnap(); 13662 } 13663 13664 if (name == NULL) 13665 return; 13666 13667 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 13668 (level = scf_snaplevel_create(g_hndl)) == NULL) 13669 scfdie(); 13670 13671 if (scf_instance_get_snapshot(cur_inst, name, snap) != 13672 SCF_SUCCESS) { 13673 switch (scf_error()) { 13674 case SCF_ERROR_INVALID_ARGUMENT: 13675 semerr(gettext("Invalid name \"%s\".\n"), name); 13676 break; 13677 13678 case SCF_ERROR_NOT_FOUND: 13679 semerr(gettext("No such snapshot \"%s\".\n"), name); 13680 break; 13681 13682 default: 13683 scfdie(); 13684 } 13685 13686 scf_snaplevel_destroy(level); 13687 scf_snapshot_destroy(snap); 13688 return; 13689 } 13690 13691 /* Load the snaplevels into our list. */ 13692 cur_levels = uu_list_create(snaplevel_pool, NULL, 0); 13693 if (cur_levels == NULL) 13694 uu_die(gettext("Could not create list: %s\n"), 13695 uu_strerror(uu_error())); 13696 13697 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 13698 if (scf_error() != SCF_ERROR_NOT_FOUND) 13699 scfdie(); 13700 13701 semerr(gettext("Snapshot has no snaplevels.\n")); 13702 13703 scf_snaplevel_destroy(level); 13704 scf_snapshot_destroy(snap); 13705 return; 13706 } 13707 13708 cur_snap = snap; 13709 13710 for (;;) { 13711 cur_elt = safe_malloc(sizeof (*cur_elt)); 13712 uu_list_node_init(cur_elt, &cur_elt->list_node, 13713 snaplevel_pool); 13714 cur_elt->sl = level; 13715 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0) 13716 uu_die(gettext("libuutil error: %s\n"), 13717 uu_strerror(uu_error())); 13718 13719 level = scf_snaplevel_create(g_hndl); 13720 if (level == NULL) 13721 scfdie(); 13722 13723 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl, 13724 level) != SCF_SUCCESS) { 13725 if (scf_error() != SCF_ERROR_NOT_FOUND) 13726 scfdie(); 13727 13728 scf_snaplevel_destroy(level); 13729 break; 13730 } 13731 } 13732 13733 cur_elt = uu_list_last(cur_levels); 13734 cur_level = cur_elt->sl; 13735 } 13736 13737 /* 13738 * Copies the properties & values in src to dst. Assumes src won't change. 13739 * Returns -1 if permission is denied, -2 if another transaction interrupts, 13740 * and 0 on success. 13741 * 13742 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED 13743 * property, if it is copied and has type boolean. (See comment in 13744 * lscf_revert()). 13745 */ 13746 static int 13747 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst, 13748 uint8_t enabled) 13749 { 13750 scf_transaction_t *tx; 13751 scf_iter_t *iter, *viter; 13752 scf_property_t *prop; 13753 scf_value_t *v; 13754 char *nbuf; 13755 int r; 13756 13757 tx = scf_transaction_create(g_hndl); 13758 if (tx == NULL) 13759 scfdie(); 13760 13761 if (scf_transaction_start(tx, dst) != SCF_SUCCESS) { 13762 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13763 scfdie(); 13764 13765 scf_transaction_destroy(tx); 13766 13767 return (-1); 13768 } 13769 13770 if ((iter = scf_iter_create(g_hndl)) == NULL || 13771 (prop = scf_property_create(g_hndl)) == NULL || 13772 (viter = scf_iter_create(g_hndl)) == NULL) 13773 scfdie(); 13774 13775 nbuf = safe_malloc(max_scf_name_len + 1); 13776 13777 if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS) 13778 scfdie(); 13779 13780 for (;;) { 13781 scf_transaction_entry_t *e; 13782 scf_type_t ty; 13783 13784 r = scf_iter_next_property(iter, prop); 13785 if (r == -1) 13786 scfdie(); 13787 if (r == 0) 13788 break; 13789 13790 e = scf_entry_create(g_hndl); 13791 if (e == NULL) 13792 scfdie(); 13793 13794 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 13795 scfdie(); 13796 13797 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0) 13798 scfdie(); 13799 13800 if (scf_transaction_property_new(tx, e, nbuf, 13801 ty) != SCF_SUCCESS) 13802 scfdie(); 13803 13804 if ((enabled == 0 || enabled == 1) && 13805 strcmp(nbuf, scf_property_enabled) == 0 && 13806 ty == SCF_TYPE_BOOLEAN) { 13807 v = scf_value_create(g_hndl); 13808 if (v == NULL) 13809 scfdie(); 13810 13811 scf_value_set_boolean(v, enabled); 13812 13813 if (scf_entry_add_value(e, v) != 0) 13814 scfdie(); 13815 } else { 13816 if (scf_iter_property_values(viter, prop) != 0) 13817 scfdie(); 13818 13819 for (;;) { 13820 v = scf_value_create(g_hndl); 13821 if (v == NULL) 13822 scfdie(); 13823 13824 r = scf_iter_next_value(viter, v); 13825 if (r == -1) 13826 scfdie(); 13827 if (r == 0) { 13828 scf_value_destroy(v); 13829 break; 13830 } 13831 13832 if (scf_entry_add_value(e, v) != SCF_SUCCESS) 13833 scfdie(); 13834 } 13835 } 13836 } 13837 13838 free(nbuf); 13839 scf_iter_destroy(viter); 13840 scf_property_destroy(prop); 13841 scf_iter_destroy(iter); 13842 13843 r = scf_transaction_commit(tx); 13844 if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 13845 scfdie(); 13846 13847 scf_transaction_destroy_children(tx); 13848 scf_transaction_destroy(tx); 13849 13850 switch (r) { 13851 case 1: return (0); 13852 case 0: return (-2); 13853 case -1: return (-1); 13854 13855 default: 13856 abort(); 13857 } 13858 13859 /* NOTREACHED */ 13860 } 13861 13862 void 13863 lscf_revert(const char *snapname) 13864 { 13865 scf_snapshot_t *snap, *prev; 13866 scf_snaplevel_t *level, *nlevel; 13867 scf_iter_t *iter; 13868 scf_propertygroup_t *pg, *npg; 13869 scf_property_t *prop; 13870 scf_value_t *val; 13871 char *nbuf, *tbuf; 13872 uint8_t enabled; 13873 13874 lscf_prep_hndl(); 13875 13876 if (cur_inst == NULL) { 13877 semerr(gettext("Instance not selected.\n")); 13878 return; 13879 } 13880 13881 if (snapname != NULL) { 13882 snap = scf_snapshot_create(g_hndl); 13883 if (snap == NULL) 13884 scfdie(); 13885 13886 if (scf_instance_get_snapshot(cur_inst, snapname, snap) != 13887 SCF_SUCCESS) { 13888 switch (scf_error()) { 13889 case SCF_ERROR_INVALID_ARGUMENT: 13890 semerr(gettext("Invalid snapshot name " 13891 "\"%s\".\n"), snapname); 13892 break; 13893 13894 case SCF_ERROR_NOT_FOUND: 13895 semerr(gettext("No such snapshot.\n")); 13896 break; 13897 13898 default: 13899 scfdie(); 13900 } 13901 13902 scf_snapshot_destroy(snap); 13903 return; 13904 } 13905 } else { 13906 if (cur_snap != NULL) { 13907 snap = cur_snap; 13908 } else { 13909 semerr(gettext("No snapshot selected.\n")); 13910 return; 13911 } 13912 } 13913 13914 if ((prev = scf_snapshot_create(g_hndl)) == NULL || 13915 (level = scf_snaplevel_create(g_hndl)) == NULL || 13916 (iter = scf_iter_create(g_hndl)) == NULL || 13917 (pg = scf_pg_create(g_hndl)) == NULL || 13918 (npg = scf_pg_create(g_hndl)) == NULL || 13919 (prop = scf_property_create(g_hndl)) == NULL || 13920 (val = scf_value_create(g_hndl)) == NULL) 13921 scfdie(); 13922 13923 nbuf = safe_malloc(max_scf_name_len + 1); 13924 tbuf = safe_malloc(max_scf_pg_type_len + 1); 13925 13926 /* Take the "previous" snapshot before we blow away the properties. */ 13927 if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) { 13928 if (_scf_snapshot_take_attach(cur_inst, prev) != 0) 13929 scfdie(); 13930 } else { 13931 if (scf_error() != SCF_ERROR_NOT_FOUND) 13932 scfdie(); 13933 13934 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0) 13935 scfdie(); 13936 } 13937 13938 /* Save general/enabled, since we're probably going to replace it. */ 13939 enabled = 2; 13940 if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 && 13941 scf_pg_get_property(pg, scf_property_enabled, prop) == 0 && 13942 scf_property_get_value(prop, val) == 0) 13943 (void) scf_value_get_boolean(val, &enabled); 13944 13945 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 13946 if (scf_error() != SCF_ERROR_NOT_FOUND) 13947 scfdie(); 13948 13949 goto out; 13950 } 13951 13952 for (;;) { 13953 boolean_t isinst; 13954 uint32_t flags; 13955 int r; 13956 13957 /* Clear the properties from the corresponding entity. */ 13958 isinst = snaplevel_is_instance(level); 13959 13960 if (!isinst) 13961 r = scf_iter_service_pgs(iter, cur_svc); 13962 else 13963 r = scf_iter_instance_pgs(iter, cur_inst); 13964 if (r != SCF_SUCCESS) 13965 scfdie(); 13966 13967 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 13968 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 13969 scfdie(); 13970 13971 /* Skip nonpersistent pgs. */ 13972 if (flags & SCF_PG_FLAG_NONPERSISTENT) 13973 continue; 13974 13975 if (scf_pg_delete(pg) != SCF_SUCCESS) { 13976 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13977 scfdie(); 13978 13979 semerr(emsg_permission_denied); 13980 goto out; 13981 } 13982 } 13983 if (r == -1) 13984 scfdie(); 13985 13986 /* Copy the properties to the corresponding entity. */ 13987 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS) 13988 scfdie(); 13989 13990 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 13991 if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0) 13992 scfdie(); 13993 13994 if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) < 13995 0) 13996 scfdie(); 13997 13998 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 13999 scfdie(); 14000 14001 if (!isinst) 14002 r = scf_service_add_pg(cur_svc, nbuf, tbuf, 14003 flags, npg); 14004 else 14005 r = scf_instance_add_pg(cur_inst, nbuf, tbuf, 14006 flags, npg); 14007 if (r != SCF_SUCCESS) { 14008 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14009 scfdie(); 14010 14011 semerr(emsg_permission_denied); 14012 goto out; 14013 } 14014 14015 if ((enabled == 0 || enabled == 1) && 14016 strcmp(nbuf, scf_pg_general) == 0) 14017 r = pg_copy(pg, npg, enabled); 14018 else 14019 r = pg_copy(pg, npg, 2); 14020 14021 switch (r) { 14022 case 0: 14023 break; 14024 14025 case -1: 14026 semerr(emsg_permission_denied); 14027 goto out; 14028 14029 case -2: 14030 semerr(gettext( 14031 "Interrupted by another change.\n")); 14032 goto out; 14033 14034 default: 14035 abort(); 14036 } 14037 } 14038 if (r == -1) 14039 scfdie(); 14040 14041 /* Get next level. */ 14042 nlevel = scf_snaplevel_create(g_hndl); 14043 if (nlevel == NULL) 14044 scfdie(); 14045 14046 if (scf_snaplevel_get_next_snaplevel(level, nlevel) != 14047 SCF_SUCCESS) { 14048 if (scf_error() != SCF_ERROR_NOT_FOUND) 14049 scfdie(); 14050 14051 scf_snaplevel_destroy(nlevel); 14052 break; 14053 } 14054 14055 scf_snaplevel_destroy(level); 14056 level = nlevel; 14057 } 14058 14059 if (snapname == NULL) { 14060 lscf_selectsnap(NULL); 14061 snap = NULL; /* cur_snap has been destroyed */ 14062 } 14063 14064 out: 14065 free(tbuf); 14066 free(nbuf); 14067 scf_value_destroy(val); 14068 scf_property_destroy(prop); 14069 scf_pg_destroy(npg); 14070 scf_pg_destroy(pg); 14071 scf_iter_destroy(iter); 14072 scf_snaplevel_destroy(level); 14073 scf_snapshot_destroy(prev); 14074 if (snap != cur_snap) 14075 scf_snapshot_destroy(snap); 14076 } 14077 14078 void 14079 lscf_refresh(void) 14080 { 14081 ssize_t fmrilen; 14082 size_t bufsz; 14083 char *fmribuf; 14084 int r; 14085 14086 lscf_prep_hndl(); 14087 14088 if (cur_inst == NULL) { 14089 semerr(gettext("Instance not selected.\n")); 14090 return; 14091 } 14092 14093 bufsz = max_scf_fmri_len + 1; 14094 fmribuf = safe_malloc(bufsz); 14095 fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz); 14096 if (fmrilen < 0) { 14097 free(fmribuf); 14098 if (scf_error() != SCF_ERROR_DELETED) 14099 scfdie(); 14100 scf_instance_destroy(cur_inst); 14101 cur_inst = NULL; 14102 warn(emsg_deleted); 14103 return; 14104 } 14105 assert(fmrilen < bufsz); 14106 14107 r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL); 14108 switch (r) { 14109 case 0: 14110 break; 14111 14112 case ECONNABORTED: 14113 warn(gettext("Could not refresh %s " 14114 "(repository connection broken).\n"), fmribuf); 14115 break; 14116 14117 case ECANCELED: 14118 warn(emsg_deleted); 14119 break; 14120 14121 case EPERM: 14122 warn(gettext("Could not refresh %s " 14123 "(permission denied).\n"), fmribuf); 14124 break; 14125 14126 case ENOSPC: 14127 warn(gettext("Could not refresh %s " 14128 "(repository server out of resources).\n"), 14129 fmribuf); 14130 break; 14131 14132 case EACCES: 14133 default: 14134 bad_error("refresh_entity", scf_error()); 14135 } 14136 14137 free(fmribuf); 14138 } 14139 14140 /* 14141 * describe [-v] [-t] [pg/prop] 14142 */ 14143 int 14144 lscf_describe(uu_list_t *args, int hasargs) 14145 { 14146 int ret = 0; 14147 size_t i; 14148 int argc; 14149 char **argv = NULL; 14150 string_list_t *slp; 14151 int do_verbose = 0; 14152 int do_templates = 0; 14153 char *pattern = NULL; 14154 14155 lscf_prep_hndl(); 14156 14157 if (hasargs != 0) { 14158 argc = uu_list_numnodes(args); 14159 if (argc < 1) 14160 goto usage; 14161 14162 argv = calloc(argc + 1, sizeof (char *)); 14163 if (argv == NULL) 14164 uu_die(gettext("Out of memory.\n")); 14165 14166 for (slp = uu_list_first(args), i = 0; 14167 slp != NULL; 14168 slp = uu_list_next(args, slp), ++i) 14169 argv[i] = slp->str; 14170 14171 argv[i] = NULL; 14172 14173 /* 14174 * We start optind = 0 because our list of arguments 14175 * starts at argv[0] 14176 */ 14177 optind = 0; 14178 opterr = 0; 14179 for (;;) { 14180 ret = getopt(argc, argv, "vt"); 14181 if (ret == -1) 14182 break; 14183 14184 switch (ret) { 14185 case 'v': 14186 do_verbose = 1; 14187 break; 14188 14189 case 't': 14190 do_templates = 1; 14191 break; 14192 14193 case '?': 14194 goto usage; 14195 14196 default: 14197 bad_error("getopt", ret); 14198 } 14199 } 14200 14201 pattern = argv[optind]; 14202 } 14203 14204 if (cur_inst == NULL && cur_svc == NULL) { 14205 semerr(emsg_entity_not_selected); 14206 ret = -1; 14207 goto out; 14208 } 14209 14210 /* 14211 * list_entity_tmpl(), listprop() and listtmpl() produce verbose 14212 * output if their last parameter is set to 2. Less information is 14213 * produced if the parameter is set to 1. 14214 */ 14215 if (pattern == NULL) { 14216 if (do_verbose == 1) 14217 list_entity_tmpl(2); 14218 else 14219 list_entity_tmpl(1); 14220 } 14221 14222 if (do_templates == 0) { 14223 if (do_verbose == 1) 14224 listprop(pattern, 0, 2); 14225 else 14226 listprop(pattern, 0, 1); 14227 } else { 14228 if (do_verbose == 1) 14229 listtmpl(pattern, 2); 14230 else 14231 listtmpl(pattern, 1); 14232 } 14233 14234 ret = 0; 14235 out: 14236 if (argv != NULL) 14237 free(argv); 14238 return (ret); 14239 usage: 14240 ret = -2; 14241 goto out; 14242 } 14243 14244 #ifndef NATIVE_BUILD 14245 /* ARGSUSED */ 14246 CPL_MATCH_FN(complete_select) 14247 { 14248 const char *arg0, *arg1, *arg1end; 14249 int word_start, err = 0, r; 14250 size_t len; 14251 char *buf; 14252 14253 lscf_prep_hndl(); 14254 14255 arg0 = line + strspn(line, " \t"); 14256 assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0); 14257 14258 arg1 = arg0 + sizeof ("select") - 1; 14259 arg1 += strspn(arg1, " \t"); 14260 word_start = arg1 - line; 14261 14262 arg1end = arg1 + strcspn(arg1, " \t"); 14263 if (arg1end < line + word_end) 14264 return (0); 14265 14266 len = line + word_end - arg1; 14267 14268 buf = safe_malloc(max_scf_name_len + 1); 14269 14270 if (cur_snap != NULL) { 14271 return (0); 14272 } else if (cur_inst != NULL) { 14273 return (0); 14274 } else if (cur_svc != NULL) { 14275 scf_instance_t *inst; 14276 scf_iter_t *iter; 14277 14278 if ((inst = scf_instance_create(g_hndl)) == NULL || 14279 (iter = scf_iter_create(g_hndl)) == NULL) 14280 scfdie(); 14281 14282 if (scf_iter_service_instances(iter, cur_svc) != 0) 14283 scfdie(); 14284 14285 for (;;) { 14286 r = scf_iter_next_instance(iter, inst); 14287 if (r == 0) 14288 break; 14289 if (r != 1) 14290 scfdie(); 14291 14292 if (scf_instance_get_name(inst, buf, 14293 max_scf_name_len + 1) < 0) 14294 scfdie(); 14295 14296 if (strncmp(buf, arg1, len) == 0) { 14297 err = cpl_add_completion(cpl, line, word_start, 14298 word_end, buf + len, "", " "); 14299 if (err != 0) 14300 break; 14301 } 14302 } 14303 14304 scf_iter_destroy(iter); 14305 scf_instance_destroy(inst); 14306 14307 return (err); 14308 } else { 14309 scf_service_t *svc; 14310 scf_iter_t *iter; 14311 14312 assert(cur_scope != NULL); 14313 14314 if ((svc = scf_service_create(g_hndl)) == NULL || 14315 (iter = scf_iter_create(g_hndl)) == NULL) 14316 scfdie(); 14317 14318 if (scf_iter_scope_services(iter, cur_scope) != 0) 14319 scfdie(); 14320 14321 for (;;) { 14322 r = scf_iter_next_service(iter, svc); 14323 if (r == 0) 14324 break; 14325 if (r != 1) 14326 scfdie(); 14327 14328 if (scf_service_get_name(svc, buf, 14329 max_scf_name_len + 1) < 0) 14330 scfdie(); 14331 14332 if (strncmp(buf, arg1, len) == 0) { 14333 err = cpl_add_completion(cpl, line, word_start, 14334 word_end, buf + len, "", " "); 14335 if (err != 0) 14336 break; 14337 } 14338 } 14339 14340 scf_iter_destroy(iter); 14341 scf_service_destroy(svc); 14342 14343 return (err); 14344 } 14345 } 14346 14347 /* ARGSUSED */ 14348 CPL_MATCH_FN(complete_command) 14349 { 14350 uint32_t scope = 0; 14351 14352 if (cur_snap != NULL) 14353 scope = CS_SNAP; 14354 else if (cur_inst != NULL) 14355 scope = CS_INST; 14356 else if (cur_svc != NULL) 14357 scope = CS_SVC; 14358 else 14359 scope = CS_SCOPE; 14360 14361 return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0); 14362 } 14363 #endif /* NATIVE_BUILD */ 14364