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