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