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