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 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Copyright 2019 Joyent, Inc. 29 */ 30 31 /* 32 * svcprop - report service configuration properties 33 */ 34 35 #include <locale.h> 36 #include <libintl.h> 37 #include <libscf.h> 38 #include <libscf_priv.h> 39 #include <libuutil.h> 40 #include <stddef.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <unistd.h> 44 #include <strings.h> 45 #include <assert.h> 46 #include <zone.h> 47 48 #ifndef TEXT_DOMAIN 49 #define TEXT_DOMAIN "SUNW_OST_OSCMD" 50 #endif /* TEXT_DOMAIN */ 51 52 /* 53 * Error functions. These can change if the quiet (-q) option is used. 54 */ 55 static void (*warn)(const char *, ...) = uu_warn; 56 static __NORETURN void (*die)(const char *, ...) = uu_die; 57 58 /* 59 * Entity encapsulation. This allows me to treat services and instances 60 * similarly, and avoid duplicating process_ent(). 61 */ 62 typedef struct { 63 char type; /* !=0: service, 0: instance */ 64 union { 65 scf_service_t *svc; 66 scf_instance_t *inst; 67 } u; 68 } scf_entityp_t; 69 70 #define ENT_INSTANCE 0 71 72 #define SCF_ENTITY_SET_TO_SERVICE(ent, s) { ent.type = 1; ent.u.svc = s; } 73 74 #define SCF_ENTITY_SET_TO_INSTANCE(ent, i) \ 75 { ent.type = ENT_INSTANCE; ent.u.inst = i; } 76 77 #define scf_entity_get_pg(ent, name, pg) \ 78 (ent.type ? scf_service_get_pg(ent.u.svc, name, pg) : \ 79 scf_instance_get_pg(ent.u.inst, name, pg)) 80 81 #define scf_entity_to_fmri(ent, buf, buf_sz) \ 82 (ent.type ? scf_service_to_fmri(ent.u.svc, buf, buf_sz) : \ 83 scf_instance_to_fmri(ent.u.inst, buf, buf_sz)) 84 85 #define SCF_ENTITY_TYPE_NAME(ent) (ent.type ? "service" : "instance") 86 87 /* 88 * Data structure for -p arguments. Since they may be name or name/name, we 89 * just track the components. 90 */ 91 typedef struct svcprop_prop_node { 92 uu_list_node_t spn_list_node; 93 const char *spn_comp1; 94 const char *spn_comp2; 95 } svcprop_prop_node_t; 96 97 static uu_list_pool_t *prop_pool; 98 static uu_list_t *prop_list; 99 100 static scf_handle_t *hndl; 101 static ssize_t max_scf_name_length; 102 static ssize_t max_scf_value_length; 103 static ssize_t max_scf_fmri_length; 104 105 /* Options */ 106 static int quiet = 0; /* No output. Nothing found, exit(1) */ 107 static int types = 0; /* Display types of properties. */ 108 static int verbose = 0; /* Print not found errors to stderr. */ 109 static int fmris = 0; /* Display full FMRIs for properties. */ 110 static int wait = 0; /* Wait mode. */ 111 static char *snapshot = "running"; /* Snapshot to use. */ 112 static int Cflag = 0; /* C option supplied */ 113 static int cflag = 0; /* c option supplied */ 114 static int sflag = 0; /* s option supplied */ 115 static int return_code; /* main's return code */ 116 117 #define PRINT_NOPROP_ERRORS (!quiet || verbose) 118 119 /* 120 * For unexpected libscf errors. The ending newline is necessary to keep 121 * uu_die() from appending the errno error. 122 */ 123 static void 124 scfdie(void) 125 { 126 die(gettext("Unexpected libscf error: %s. Exiting.\n"), 127 scf_strerror(scf_error())); 128 } 129 130 static void * 131 safe_malloc(size_t sz) 132 { 133 void *p; 134 135 p = malloc(sz); 136 if (p == NULL) 137 die(gettext("Could not allocate memory")); 138 139 return (p); 140 } 141 142 static void 143 usage(void) 144 { 145 (void) fprintf(stderr, gettext("Usage: %1$s [-fqtv] " 146 "[-C | -c | -s snapshot] [-z zone] " 147 "[-p [name/]name]... \n" 148 " {FMRI | pattern}...\n" 149 " %1$s -w [-fqtv] [-z zone] [-p [name/]name] " 150 "{FMRI | pattern}\n"), uu_getpname()); 151 exit(UU_EXIT_USAGE); 152 } 153 154 /* 155 * Return an allocated copy of str, with the Bourne shell's metacharacters 156 * escaped by '\'. 157 * 158 * What about unicode? 159 */ 160 static char * 161 quote_for_shell(const char *str) 162 { 163 const char *sp; 164 char *dst, *dp; 165 size_t dst_len; 166 167 const char * const metachars = ";&()|^<>\n \t\\\"\'`"; 168 169 if (str[0] == '\0') 170 return (strdup("\"\"")); 171 172 dst_len = 0; 173 for (sp = str; *sp != '\0'; ++sp) { 174 ++dst_len; 175 176 if (strchr(metachars, *sp) != NULL) 177 ++dst_len; 178 } 179 180 if (sp - str == dst_len) 181 return (strdup(str)); 182 183 dst = safe_malloc(dst_len + 1); 184 185 for (dp = dst, sp = str; *sp != '\0'; ++dp, ++sp) { 186 if (strchr(metachars, *sp) != NULL) 187 *dp++ = '\\'; 188 189 *dp = *sp; 190 } 191 *dp = '\0'; 192 193 return (dst); 194 } 195 196 static void 197 print_value(scf_value_t *val) 198 { 199 char *buf, *qbuf; 200 ssize_t bufsz, r; 201 202 bufsz = scf_value_get_as_string(val, NULL, 0) + 1; 203 if (bufsz - 1 < 0) 204 scfdie(); 205 206 buf = safe_malloc(bufsz); 207 208 r = scf_value_get_as_string(val, buf, bufsz); 209 assert(r + 1 == bufsz); 210 211 qbuf = quote_for_shell(buf); 212 (void) fputs(qbuf, stdout); 213 214 free(qbuf); 215 free(buf); 216 } 217 218 /* 219 * Display a property's values on a line. If types is true, prepend 220 * identification (the FMRI if fmris is true, pg/prop otherwise) and the type 221 * of the property. 222 */ 223 static void 224 display_prop(scf_propertygroup_t *pg, scf_property_t *prop) 225 { 226 scf_value_t *val; 227 scf_iter_t *iter; 228 int ret, first, err; 229 230 const char * const permission_denied_emsg = 231 gettext("Permission denied.\n"); 232 233 if (types) { 234 scf_type_t ty; 235 char *buf; 236 size_t buf_sz; 237 238 if (fmris) { 239 buf_sz = max_scf_fmri_length + 1; 240 buf = safe_malloc(buf_sz); 241 242 if (scf_property_to_fmri(prop, buf, buf_sz) == -1) 243 scfdie(); 244 (void) fputs(buf, stdout); 245 246 free(buf); 247 } else { 248 buf_sz = max_scf_name_length + 1; 249 buf = safe_malloc(buf_sz); 250 251 if (scf_pg_get_name(pg, buf, buf_sz) < 0) 252 scfdie(); 253 (void) fputs(buf, stdout); 254 (void) putchar('/'); 255 256 if (scf_property_get_name(prop, buf, buf_sz) < 0) 257 scfdie(); 258 (void) fputs(buf, stdout); 259 260 free(buf); 261 } 262 263 (void) putchar(' '); 264 265 if (scf_property_type(prop, &ty) == -1) 266 scfdie(); 267 (void) fputs(scf_type_to_string(ty), stdout); 268 (void) putchar(' '); 269 } 270 271 if ((iter = scf_iter_create(hndl)) == NULL || 272 (val = scf_value_create(hndl)) == NULL) 273 scfdie(); 274 275 if (scf_iter_property_values(iter, prop) == -1) 276 scfdie(); 277 278 first = 1; 279 while ((ret = scf_iter_next_value(iter, val)) == 1) { 280 if (first) 281 first = 0; 282 else 283 (void) putchar(' '); 284 print_value(val); 285 } 286 if (ret == -1) { 287 err = scf_error(); 288 if (err == SCF_ERROR_PERMISSION_DENIED) { 289 if (uu_list_numnodes(prop_list) > 0) 290 die(permission_denied_emsg); 291 } else { 292 scfdie(); 293 } 294 } 295 296 (void) putchar('\n'); 297 298 scf_iter_destroy(iter); 299 (void) scf_value_destroy(val); 300 } 301 302 /* 303 * display_prop() all of the properties in the given property group. Force 304 * types to true so identification will be displayed. 305 */ 306 static void 307 display_pg(scf_propertygroup_t *pg) 308 { 309 scf_property_t *prop; 310 scf_iter_t *iter; 311 int ret; 312 313 types = 1; /* Always display types for whole propertygroups. */ 314 315 if ((prop = scf_property_create(hndl)) == NULL || 316 (iter = scf_iter_create(hndl)) == NULL) 317 scfdie(); 318 319 if (scf_iter_pg_properties(iter, pg) == -1) 320 scfdie(); 321 322 while ((ret = scf_iter_next_property(iter, prop)) == 1) 323 display_prop(pg, prop); 324 if (ret == -1) 325 scfdie(); 326 327 scf_iter_destroy(iter); 328 scf_property_destroy(prop); 329 } 330 331 /* 332 * Common code to execute when a nonexistant property is encountered. 333 */ 334 static void 335 noprop_common_action() 336 { 337 if (!PRINT_NOPROP_ERRORS) 338 /* We're not printing errors, so we can cut out early. */ 339 exit(UU_EXIT_FATAL); 340 341 return_code = UU_EXIT_FATAL; 342 } 343 344 /* 345 * Iterate the properties of a service or an instance when no snapshot 346 * is specified. 347 */ 348 static int 349 scf_iter_entity_pgs(scf_iter_t *iter, scf_entityp_t ent) 350 { 351 int ret = 0; 352 353 if (ent.type) { 354 /* 355 * If we are displaying properties for a service, 356 * treat it as though it were a composed, current 357 * lookup. (implicit cflag) However, if a snapshot 358 * was specified, fail. 359 */ 360 if (sflag) 361 die(gettext("Only instances have " 362 "snapshots.\n")); 363 ret = scf_iter_service_pgs(iter, ent.u.svc); 364 } else { 365 if (Cflag) 366 ret = scf_iter_instance_pgs(iter, ent.u.inst); 367 else 368 ret = scf_iter_instance_pgs_composed(iter, ent.u.inst, 369 NULL); 370 } 371 return (ret); 372 } 373 374 /* 375 * Return a snapshot for the supplied instance and snapshot name. 376 */ 377 static scf_snapshot_t * 378 get_snapshot(const scf_instance_t *inst, const char *snapshot) 379 { 380 scf_snapshot_t *snap = scf_snapshot_create(hndl); 381 382 if (snap == NULL) 383 scfdie(); 384 385 if (scf_instance_get_snapshot(inst, snapshot, snap) == -1) { 386 switch (scf_error()) { 387 case SCF_ERROR_INVALID_ARGUMENT: 388 die(gettext("Invalid snapshot name.\n")); 389 /* NOTREACHED */ 390 391 case SCF_ERROR_NOT_FOUND: 392 if (sflag == 0) { 393 scf_snapshot_destroy(snap); 394 snap = NULL; 395 } else 396 die(gettext("No such snapshot.\n")); 397 break; 398 399 default: 400 scfdie(); 401 } 402 } 403 404 return (snap); 405 } 406 407 /* 408 * Entity (service or instance): If there are -p options, 409 * display_{pg,prop}() the named property groups and/or properties. Otherwise 410 * display_pg() all property groups. 411 */ 412 static void 413 process_ent(scf_entityp_t ent) 414 { 415 scf_snapshot_t *snap = NULL; 416 scf_propertygroup_t *pg; 417 scf_property_t *prop; 418 scf_iter_t *iter; 419 svcprop_prop_node_t *spn; 420 int ret, err; 421 422 if (uu_list_numnodes(prop_list) == 0) { 423 if (quiet) 424 return; 425 426 if ((pg = scf_pg_create(hndl)) == NULL || 427 (iter = scf_iter_create(hndl)) == NULL) 428 scfdie(); 429 430 if (cflag || Cflag || ent.type != ENT_INSTANCE) { 431 if (scf_iter_entity_pgs(iter, ent) == -1) 432 scfdie(); 433 } else { 434 if (snapshot != NULL) 435 snap = get_snapshot(ent.u.inst, snapshot); 436 437 if (scf_iter_instance_pgs_composed(iter, ent.u.inst, 438 snap) == -1) 439 scfdie(); 440 if (snap) 441 scf_snapshot_destroy(snap); 442 } 443 444 while ((ret = scf_iter_next_pg(iter, pg)) == 1) 445 display_pg(pg); 446 if (ret == -1) 447 scfdie(); 448 449 /* 450 * In normal usage, i.e. against the running snapshot, 451 * we must iterate over the current non-persistent 452 * pg's. 453 */ 454 if (sflag == 0 && snap != NULL) { 455 scf_iter_reset(iter); 456 if (scf_iter_instance_pgs_composed(iter, ent.u.inst, 457 NULL) == -1) 458 scfdie(); 459 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 460 uint32_t flags; 461 462 if (scf_pg_get_flags(pg, &flags) == -1) 463 scfdie(); 464 if (flags & SCF_PG_FLAG_NONPERSISTENT) 465 display_pg(pg); 466 } 467 } 468 if (ret == -1) 469 scfdie(); 470 471 scf_iter_destroy(iter); 472 scf_pg_destroy(pg); 473 474 return; 475 } 476 477 if ((pg = scf_pg_create(hndl)) == NULL || 478 (prop = scf_property_create(hndl)) == NULL) 479 scfdie(); 480 481 if (ent.type == ENT_INSTANCE && snapshot != NULL) 482 snap = get_snapshot(ent.u.inst, snapshot); 483 484 for (spn = uu_list_first(prop_list); 485 spn != NULL; 486 spn = uu_list_next(prop_list, spn)) { 487 if (ent.type == ENT_INSTANCE) { 488 if (Cflag) 489 ret = scf_instance_get_pg(ent.u.inst, 490 spn->spn_comp1, pg); 491 else 492 ret = scf_instance_get_pg_composed(ent.u.inst, 493 snap, spn->spn_comp1, pg); 494 err = scf_error(); 495 496 /* 497 * If we didn't find it in the specified snapshot, use 498 * the current values if the pg is nonpersistent. 499 */ 500 if (ret == -1 && !Cflag &&snap != NULL && err == 501 SCF_ERROR_NOT_FOUND) { 502 ret = scf_instance_get_pg_composed( 503 ent.u.inst, NULL, spn->spn_comp1, 504 pg); 505 506 if (ret == 0) { 507 uint32_t flags; 508 509 if (scf_pg_get_flags(pg, &flags) == -1) 510 scfdie(); 511 if ((flags & SCF_PG_FLAG_NONPERSISTENT) 512 == 0) { 513 ret = -1; 514 } 515 } 516 } 517 } else { 518 /* 519 * If we are displaying properties for a service, 520 * treat it as though it were a composed, current 521 * lookup. (implicit cflag) However, if a snapshot 522 * was specified, fail. 523 */ 524 if (sflag) 525 die(gettext("Only instances have " 526 "snapshots.\n")); 527 ret = scf_entity_get_pg(ent, spn->spn_comp1, pg); 528 err = scf_error(); 529 } 530 if (ret == -1) { 531 if (err != SCF_ERROR_NOT_FOUND) 532 scfdie(); 533 534 if (PRINT_NOPROP_ERRORS) { 535 char *buf; 536 537 buf = safe_malloc(max_scf_fmri_length + 1); 538 if (scf_entity_to_fmri(ent, buf, 539 max_scf_fmri_length + 1) == -1) 540 scfdie(); 541 542 uu_warn(gettext("Couldn't find property group " 543 "`%s' for %s `%s'.\n"), spn->spn_comp1, 544 SCF_ENTITY_TYPE_NAME(ent), buf); 545 546 free(buf); 547 } 548 549 noprop_common_action(); 550 551 continue; 552 } 553 554 if (spn->spn_comp2 == NULL) { 555 if (!quiet) 556 display_pg(pg); 557 continue; 558 } 559 560 if (scf_pg_get_property(pg, spn->spn_comp2, prop) == -1) { 561 if (scf_error() != SCF_ERROR_NOT_FOUND) 562 scfdie(); 563 564 if (PRINT_NOPROP_ERRORS) { 565 char *buf; 566 567 buf = safe_malloc(max_scf_fmri_length + 1); 568 if (scf_entity_to_fmri(ent, buf, 569 max_scf_fmri_length + 1) == -1) 570 scfdie(); 571 572 /* FMRI syntax knowledge */ 573 uu_warn(gettext("Couldn't find property " 574 "`%s/%s' for %s `%s'.\n"), spn->spn_comp1, 575 spn->spn_comp2, SCF_ENTITY_TYPE_NAME(ent), 576 buf); 577 578 free(buf); 579 } 580 581 noprop_common_action(); 582 583 continue; 584 } 585 586 if (!quiet) 587 display_prop(pg, prop); 588 } 589 590 scf_property_destroy(prop); 591 scf_pg_destroy(pg); 592 if (snap) 593 scf_snapshot_destroy(snap); 594 } 595 596 /* 597 * Without -p options, just call display_pg(). Otherwise display_prop() the 598 * named properties of the property group. 599 */ 600 static void 601 process_pg(scf_propertygroup_t *pg) 602 { 603 scf_property_t *prop; 604 svcprop_prop_node_t *spn; 605 606 if (uu_list_first(prop_list) == NULL) { 607 if (quiet) 608 return; 609 610 display_pg(pg); 611 return; 612 } 613 614 prop = scf_property_create(hndl); 615 if (prop == NULL) 616 scfdie(); 617 618 for (spn = uu_list_first(prop_list); 619 spn != NULL; 620 spn = uu_list_next(prop_list, spn)) { 621 if (spn->spn_comp2 != NULL) { 622 char *buf; 623 624 buf = safe_malloc(max_scf_fmri_length + 1); 625 if (scf_pg_to_fmri(pg, buf, max_scf_fmri_length + 1) == 626 -1) 627 scfdie(); 628 629 uu_xdie(UU_EXIT_USAGE, gettext("-p argument `%s/%s' " 630 "has too many components for property " 631 "group `%s'.\n"), spn->spn_comp1, spn->spn_comp2, 632 buf); 633 } 634 635 if (scf_pg_get_property(pg, spn->spn_comp1, prop) == 0) { 636 if (!quiet) 637 display_prop(pg, prop); 638 continue; 639 } 640 641 if (scf_error() != SCF_ERROR_NOT_FOUND) 642 scfdie(); 643 644 if (PRINT_NOPROP_ERRORS) { 645 char *buf; 646 647 buf = safe_malloc(max_scf_fmri_length + 1); 648 if (scf_pg_to_fmri(pg, buf, max_scf_fmri_length + 1) == 649 -1) 650 scfdie(); 651 652 uu_warn(gettext("Couldn't find property `%s' in " 653 "property group `%s'.\n"), spn->spn_comp1, buf); 654 655 free(buf); 656 } 657 658 noprop_common_action(); 659 } 660 } 661 662 /* 663 * If there are -p options, show the error. Otherwise just call 664 * display_prop(). 665 */ 666 static void 667 process_prop(scf_propertygroup_t *pg, scf_property_t *prop) 668 { 669 if (uu_list_first(prop_list) != NULL) { 670 uu_warn(gettext("The -p option cannot be used with property " 671 "operands.\n")); 672 usage(); 673 } 674 675 if (quiet) 676 return; 677 678 display_prop(pg, prop); 679 } 680 681 /* Decode an operand & dispatch. */ 682 /* ARGSUSED */ 683 static int 684 process_fmri(void *unused, scf_walkinfo_t *wip) 685 { 686 scf_entityp_t ent; 687 688 /* Multiple matches imply multiple entities. */ 689 if (wip->count > 1) 690 types = fmris = 1; 691 692 if (wip->prop != NULL) { 693 process_prop(wip->pg, wip->prop); 694 } else if (wip->pg != NULL) { 695 process_pg(wip->pg); 696 } else if (wip->inst != NULL) { 697 SCF_ENTITY_SET_TO_INSTANCE(ent, wip->inst); 698 process_ent(ent); 699 } else { 700 /* scf_walk_fmri() won't let this happen */ 701 assert(wip->svc != NULL); 702 SCF_ENTITY_SET_TO_SERVICE(ent, wip->svc); 703 process_ent(ent); 704 } 705 706 return (0); 707 } 708 709 static void 710 add_prop(char *property) 711 { 712 svcprop_prop_node_t *p, *last; 713 char *slash; 714 715 const char * const invalid_component_emsg = 716 gettext("Invalid component name `%s'.\n"); 717 718 /* FMRI syntax knowledge. */ 719 slash = strchr(property, '/'); 720 if (slash != NULL) { 721 if (strchr(slash + 1, '/') != NULL) { 722 uu_warn(gettext("-p argument `%s' has too many " 723 "components.\n"), property); 724 usage(); 725 } 726 } 727 728 if (slash != NULL) 729 *slash = '\0'; 730 731 p = safe_malloc(sizeof (svcprop_prop_node_t)); 732 uu_list_node_init(p, &p->spn_list_node, prop_pool); 733 734 p->spn_comp1 = property; 735 p->spn_comp2 = (slash == NULL) ? NULL : slash + 1; 736 737 if (uu_check_name(p->spn_comp1, UU_NAME_DOMAIN) == -1) 738 uu_xdie(UU_EXIT_USAGE, invalid_component_emsg, p->spn_comp1); 739 if (p->spn_comp2 != NULL && 740 uu_check_name(p->spn_comp2, UU_NAME_DOMAIN) == -1) 741 uu_xdie(UU_EXIT_USAGE, invalid_component_emsg, p->spn_comp2); 742 743 last = uu_list_last(prop_list); 744 if (last != NULL) { 745 if ((last->spn_comp2 == NULL) ^ (p->spn_comp2 == NULL)) { 746 /* 747 * The -p options have mixed numbers of components. 748 * If they both turn out to be valid, then the 749 * single-component ones will specify property groups, 750 * so we need to turn on types to keep the output of 751 * display_prop() consistent with display_pg(). 752 */ 753 types = 1; 754 } 755 } 756 757 (void) uu_list_insert_after(prop_list, NULL, p); 758 } 759 760 761 /* 762 * Wait for a property group or property change. 763 * 764 * Extract a pg and optionally a property name from fmri & prop_list. 765 * _scf_pg_wait() for the pg, and display_pg(pg) or display_prop(pg, prop) 766 * when it returns. 767 */ 768 /* ARGSUSED */ 769 static int 770 do_wait(void *unused, scf_walkinfo_t *wip) 771 { 772 scf_property_t *prop; 773 scf_propertygroup_t *lpg, *pg; 774 const char *propname; 775 svcprop_prop_node_t *p; 776 777 const char *emsg_not_found = gettext("Not found.\n"); 778 779 if ((lpg = scf_pg_create(hndl)) == NULL || 780 (prop = scf_property_create(hndl)) == NULL) 781 scfdie(); 782 783 if (wip->prop != NULL) { 784 if (uu_list_numnodes(prop_list) > 0) 785 uu_xdie(UU_EXIT_USAGE, gettext("-p cannot be used with " 786 "property FMRIs.\n")); 787 pg = wip->pg; 788 789 assert(strrchr(wip->fmri, '/') != NULL); 790 propname = strrchr(wip->fmri, '/') + 1; 791 792 } else if (wip->pg != NULL) { 793 p = uu_list_first(prop_list); 794 795 if (p != NULL) { 796 if (p->spn_comp2 != NULL) 797 uu_xdie(UU_EXIT_USAGE, gettext("-p argument " 798 "\"%s/%s\" has too many components for " 799 "property group %s.\n"), 800 p->spn_comp1, p->spn_comp2, wip->fmri); 801 802 propname = p->spn_comp1; 803 804 if (scf_pg_get_property(wip->pg, propname, prop) != 805 SCF_SUCCESS) { 806 switch (scf_error()) { 807 case SCF_ERROR_INVALID_ARGUMENT: 808 uu_xdie(UU_EXIT_USAGE, 809 gettext("Invalid property name " 810 "\"%s\".\n"), propname); 811 812 /* NOTREACHED */ 813 814 case SCF_ERROR_NOT_FOUND: 815 die(emsg_not_found); 816 817 default: 818 scfdie(); 819 } 820 } 821 } else { 822 propname = NULL; 823 } 824 825 pg = wip->pg; 826 827 } else if (wip->inst != NULL) { 828 829 p = uu_list_first(prop_list); 830 if (p == NULL) 831 uu_xdie(UU_EXIT_USAGE, 832 gettext("Cannot wait for an instance.\n")); 833 834 if (scf_instance_get_pg(wip->inst, p->spn_comp1, lpg) != 835 SCF_SUCCESS) { 836 switch (scf_error()) { 837 case SCF_ERROR_INVALID_ARGUMENT: 838 uu_xdie(UU_EXIT_USAGE, gettext("Invalid " 839 "property group name \"%s\".\n"), 840 p->spn_comp1); 841 /* NOTREACHED */ 842 843 case SCF_ERROR_NOT_FOUND: 844 die(emsg_not_found); 845 846 default: 847 scfdie(); 848 } 849 } 850 851 propname = p->spn_comp2; 852 853 if (propname != NULL) { 854 if (scf_pg_get_property(lpg, propname, prop) != 855 SCF_SUCCESS) { 856 switch (scf_error()) { 857 case SCF_ERROR_INVALID_ARGUMENT: 858 uu_xdie(UU_EXIT_USAGE, 859 gettext("Invalid property name " 860 "\"%s\".\n"), propname); 861 /* NOTREACHED */ 862 863 case SCF_ERROR_NOT_FOUND: 864 die(emsg_not_found); 865 866 default: 867 scfdie(); 868 } 869 } 870 } 871 872 pg = lpg; 873 874 } else if (wip->svc != NULL) { 875 876 p = uu_list_first(prop_list); 877 if (p == NULL) 878 uu_xdie(UU_EXIT_USAGE, 879 gettext("Cannot wait for a service.\n")); 880 881 if (scf_service_get_pg(wip->svc, p->spn_comp1, lpg) != 882 SCF_SUCCESS) { 883 switch (scf_error()) { 884 case SCF_ERROR_INVALID_ARGUMENT: 885 uu_xdie(UU_EXIT_USAGE, gettext("Invalid " 886 "property group name \"%s\".\n"), 887 p->spn_comp1); 888 /* NOTREACHED */ 889 890 case SCF_ERROR_NOT_FOUND: 891 die(emsg_not_found); 892 893 default: 894 scfdie(); 895 } 896 } 897 898 propname = p->spn_comp2; 899 900 if (propname != NULL) { 901 if (scf_pg_get_property(lpg, propname, prop) != 902 SCF_SUCCESS) { 903 switch (scf_error()) { 904 case SCF_ERROR_INVALID_ARGUMENT: 905 uu_xdie(UU_EXIT_USAGE, 906 gettext("Invalid property name " 907 "\"%s\".\n"), propname); 908 909 /* NOTREACHED */ 910 911 case SCF_ERROR_NOT_FOUND: 912 die(emsg_not_found); 913 914 default: 915 scfdie(); 916 } 917 } 918 } 919 920 pg = lpg; 921 922 } else { 923 uu_xdie(UU_EXIT_USAGE, gettext("FMRI must specify an entity, " 924 "property group, or property.\n")); 925 } 926 927 for (;;) { 928 int ret; 929 930 ret = _scf_pg_wait(pg, -1); 931 if (ret != SCF_SUCCESS) 932 scfdie(); 933 934 ret = scf_pg_update(pg); 935 if (ret < 0) { 936 if (scf_error() != SCF_ERROR_DELETED) 937 scfdie(); 938 939 die(emsg_not_found); 940 } 941 if (ret == SCF_COMPLETE) 942 break; 943 } 944 945 if (propname != NULL) { 946 if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS) { 947 if (!quiet) 948 display_prop(pg, prop); 949 } else { 950 if (scf_error() != SCF_ERROR_NOT_FOUND) 951 scfdie(); 952 953 if (PRINT_NOPROP_ERRORS) 954 uu_warn(emsg_not_found); 955 956 return_code = UU_EXIT_FATAL; 957 } 958 } else { 959 if (!quiet) 960 display_pg(pg); 961 } 962 963 scf_property_destroy(prop); 964 scf_pg_destroy(lpg); 965 966 return (0); 967 } 968 969 /* 970 * These functions replace uu_warn() and uu_die() when the quiet (-q) option is 971 * used, and silently ignore any output. 972 */ 973 974 /*ARGSUSED*/ 975 static void 976 quiet_warn(const char *fmt, ...) 977 { 978 /* Do nothing */ 979 } 980 981 /*ARGSUSED*/ 982 static __NORETURN void 983 quiet_die(const char *fmt, ...) 984 { 985 exit(UU_EXIT_FATAL); 986 } 987 988 int 989 main(int argc, char *argv[]) 990 { 991 int c; 992 scf_walk_callback callback; 993 int flags; 994 int err; 995 996 (void) setlocale(LC_ALL, ""); 997 (void) textdomain(TEXT_DOMAIN); 998 999 return_code = UU_EXIT_OK; 1000 1001 (void) uu_setpname(argv[0]); 1002 1003 prop_pool = uu_list_pool_create("properties", 1004 sizeof (svcprop_prop_node_t), 1005 offsetof(svcprop_prop_node_t, spn_list_node), NULL, 0); 1006 if (prop_pool == NULL) 1007 uu_die("%s\n", uu_strerror(uu_error())); 1008 1009 prop_list = uu_list_create(prop_pool, NULL, 0); 1010 1011 hndl = scf_handle_create(SCF_VERSION); 1012 if (hndl == NULL) 1013 scfdie(); 1014 1015 while ((c = getopt(argc, argv, "Ccfp:qs:tvwz:")) != -1) { 1016 switch (c) { 1017 case 'C': 1018 if (cflag || sflag || wait) 1019 usage(); /* Not with -c, -s or -w */ 1020 Cflag++; 1021 snapshot = NULL; 1022 break; 1023 1024 case 'c': 1025 if (Cflag || sflag || wait) 1026 usage(); /* Not with -C, -s or -w */ 1027 cflag++; 1028 snapshot = NULL; 1029 break; 1030 1031 case 'f': 1032 types = 1; 1033 fmris = 1; 1034 break; 1035 1036 case 'p': 1037 add_prop(optarg); 1038 break; 1039 1040 case 'q': 1041 quiet = 1; 1042 warn = quiet_warn; 1043 die = quiet_die; 1044 break; 1045 1046 case 's': 1047 if (Cflag || cflag || wait) 1048 usage(); /* Not with -C, -c or -w */ 1049 snapshot = optarg; 1050 sflag++; 1051 break; 1052 1053 case 't': 1054 types = 1; 1055 break; 1056 1057 case 'v': 1058 verbose = 1; 1059 break; 1060 1061 case 'w': 1062 if (Cflag || cflag || sflag) 1063 usage(); /* Not with -C, -c or -s */ 1064 wait = 1; 1065 break; 1066 1067 case 'z': { 1068 scf_value_t *zone; 1069 scf_handle_t *h = hndl; 1070 1071 if (getzoneid() != GLOBAL_ZONEID) 1072 uu_die(gettext("svcprop -z may only be used " 1073 "from the global zone\n")); 1074 1075 if ((zone = scf_value_create(h)) == NULL) 1076 scfdie(); 1077 1078 if (scf_value_set_astring(zone, optarg) != SCF_SUCCESS) 1079 scfdie(); 1080 1081 if (scf_handle_decorate(h, "zone", zone) != SCF_SUCCESS) 1082 uu_die(gettext("invalid zone '%s'\n"), optarg); 1083 1084 scf_value_destroy(zone); 1085 break; 1086 } 1087 1088 case '?': 1089 switch (optopt) { 1090 case 'p': 1091 usage(); 1092 1093 default: 1094 break; 1095 } 1096 1097 /* FALLTHROUGH */ 1098 1099 default: 1100 usage(); 1101 } 1102 } 1103 1104 if (optind == argc) 1105 usage(); 1106 1107 max_scf_name_length = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH); 1108 max_scf_value_length = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 1109 max_scf_fmri_length = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH); 1110 if (max_scf_name_length == -1 || max_scf_value_length == -1 || 1111 max_scf_fmri_length == -1) 1112 scfdie(); 1113 1114 if (scf_handle_bind(hndl) == -1) 1115 die(gettext("Could not connect to configuration repository: " 1116 "%s.\n"), scf_strerror(scf_error())); 1117 1118 flags = SCF_WALK_PROPERTY | SCF_WALK_SERVICE | SCF_WALK_EXPLICIT; 1119 1120 if (wait) { 1121 if (uu_list_numnodes(prop_list) > 1) 1122 usage(); 1123 1124 if (argc - optind > 1) 1125 usage(); 1126 1127 callback = do_wait; 1128 1129 } else { 1130 callback = process_fmri; 1131 1132 flags |= SCF_WALK_MULTIPLE; 1133 } 1134 1135 if ((err = scf_walk_fmri(hndl, argc - optind, argv + optind, flags, 1136 callback, NULL, &return_code, warn)) != 0) { 1137 warn(gettext("failed to iterate over instances: %s\n"), 1138 scf_strerror(err)); 1139 return_code = UU_EXIT_FATAL; 1140 } 1141 1142 scf_handle_destroy(hndl); 1143 1144 return (return_code); 1145 } 1146