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