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 #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, err; 226 227 const char * const permission_denied_emsg = 228 gettext("Permission denied.\n"); 229 230 if (types) { 231 scf_type_t ty; 232 char *buf; 233 size_t buf_sz; 234 235 if (fmris) { 236 buf_sz = max_scf_fmri_length + 1; 237 buf = safe_malloc(buf_sz); 238 239 if (scf_property_to_fmri(prop, buf, buf_sz) == -1) 240 scfdie(); 241 (void) fputs(buf, stdout); 242 243 free(buf); 244 } else { 245 buf_sz = max_scf_name_length + 1; 246 buf = safe_malloc(buf_sz); 247 248 if (scf_pg_get_name(pg, buf, buf_sz) < 0) 249 scfdie(); 250 (void) fputs(buf, stdout); 251 (void) putchar('/'); 252 253 if (scf_property_get_name(prop, buf, buf_sz) < 0) 254 scfdie(); 255 (void) fputs(buf, stdout); 256 257 free(buf); 258 } 259 260 (void) putchar(' '); 261 262 if (scf_property_type(prop, &ty) == -1) 263 scfdie(); 264 (void) fputs(scf_type_to_string(ty), stdout); 265 (void) putchar(' '); 266 } 267 268 if ((iter = scf_iter_create(hndl)) == NULL || 269 (val = scf_value_create(hndl)) == NULL) 270 scfdie(); 271 272 if (scf_iter_property_values(iter, prop) == -1) 273 scfdie(); 274 275 first = 1; 276 while ((ret = scf_iter_next_value(iter, val)) == 1) { 277 if (first) 278 first = 0; 279 else 280 (void) putchar(' '); 281 print_value(val); 282 } 283 if (ret == -1) { 284 err = scf_error(); 285 if (err == SCF_ERROR_PERMISSION_DENIED) { 286 if (uu_list_numnodes(prop_list) > 0) 287 die(permission_denied_emsg); 288 } else { 289 scfdie(); 290 } 291 } 292 293 (void) putchar('\n'); 294 295 scf_iter_destroy(iter); 296 (void) scf_value_destroy(val); 297 } 298 299 /* 300 * display_prop() all of the properties in the given property group. Force 301 * types to true so identification will be displayed. 302 */ 303 static void 304 display_pg(scf_propertygroup_t *pg) 305 { 306 scf_property_t *prop; 307 scf_iter_t *iter; 308 int ret; 309 310 types = 1; /* Always display types for whole propertygroups. */ 311 312 if ((prop = scf_property_create(hndl)) == NULL || 313 (iter = scf_iter_create(hndl)) == NULL) 314 scfdie(); 315 316 if (scf_iter_pg_properties(iter, pg) == -1) 317 scfdie(); 318 319 while ((ret = scf_iter_next_property(iter, prop)) == 1) 320 display_prop(pg, prop); 321 if (ret == -1) 322 scfdie(); 323 324 scf_iter_destroy(iter); 325 scf_property_destroy(prop); 326 } 327 328 /* 329 * Common code to execute when a nonexistant property is encountered. 330 */ 331 static void 332 noprop_common_action() 333 { 334 if (!PRINT_NOPROP_ERRORS) 335 /* We're not printing errors, so we can cut out early. */ 336 exit(UU_EXIT_FATAL); 337 338 return_code = UU_EXIT_FATAL; 339 } 340 341 /* 342 * Iterate the properties of a service or an instance when no snapshot 343 * is specified. 344 */ 345 static int 346 scf_iter_entity_pgs(scf_iter_t *iter, scf_entityp_t ent) 347 { 348 int ret = 0; 349 350 if (ent.type) { 351 /* 352 * If we are displaying properties for a service, 353 * treat it as though it were a composed, current 354 * lookup. (implicit cflag) However, if a snapshot 355 * was specified, fail. 356 */ 357 if (sflag) 358 die(gettext("Only instances have " 359 "snapshots.\n")); 360 ret = scf_iter_service_pgs(iter, ent.u.svc); 361 } else { 362 if (Cflag) 363 ret = scf_iter_instance_pgs(iter, ent.u.inst); 364 else 365 ret = scf_iter_instance_pgs_composed(iter, ent.u.inst, 366 NULL); 367 } 368 return (ret); 369 } 370 371 /* 372 * Return a snapshot for the supplied instance and snapshot name. 373 */ 374 static scf_snapshot_t * 375 get_snapshot(const scf_instance_t *inst, const char *snapshot) 376 { 377 scf_snapshot_t *snap = scf_snapshot_create(hndl); 378 379 if (snap == NULL) 380 scfdie(); 381 382 if (scf_instance_get_snapshot(inst, snapshot, snap) == -1) { 383 switch (scf_error()) { 384 case SCF_ERROR_INVALID_ARGUMENT: 385 die(gettext("Invalid snapshot name.\n")); 386 /* NOTREACHED */ 387 388 case SCF_ERROR_NOT_FOUND: 389 if (sflag == 0) { 390 scf_snapshot_destroy(snap); 391 snap = NULL; 392 } else 393 die(gettext("No such snapshot.\n")); 394 break; 395 396 default: 397 scfdie(); 398 } 399 } 400 401 return (snap); 402 } 403 404 /* 405 * Entity (service or instance): If there are -p options, 406 * display_{pg,prop}() the named property groups and/or properties. Otherwise 407 * display_pg() all property groups. 408 */ 409 static void 410 process_ent(scf_entityp_t ent) 411 { 412 scf_snapshot_t *snap = NULL; 413 scf_propertygroup_t *pg; 414 scf_property_t *prop; 415 scf_iter_t *iter; 416 svcprop_prop_node_t *spn; 417 int ret, err; 418 419 if (uu_list_numnodes(prop_list) == 0) { 420 if (quiet) 421 return; 422 423 if ((pg = scf_pg_create(hndl)) == NULL || 424 (iter = scf_iter_create(hndl)) == NULL) 425 scfdie(); 426 427 if (cflag || Cflag || ent.type != ENT_INSTANCE) { 428 if (scf_iter_entity_pgs(iter, ent) == -1) 429 scfdie(); 430 } else { 431 if (snapshot != NULL) 432 snap = get_snapshot(ent.u.inst, snapshot); 433 434 if (scf_iter_instance_pgs_composed(iter, ent.u.inst, 435 snap) == -1) 436 scfdie(); 437 if (snap) 438 scf_snapshot_destroy(snap); 439 } 440 441 while ((ret = scf_iter_next_pg(iter, pg)) == 1) 442 display_pg(pg); 443 if (ret == -1) 444 scfdie(); 445 446 /* 447 * In normal usage, i.e. against the running snapshot, 448 * we must iterate over the current non-persistent 449 * pg's. 450 */ 451 if (sflag == 0 && snap != NULL) { 452 scf_iter_reset(iter); 453 if (scf_iter_instance_pgs_composed(iter, ent.u.inst, 454 NULL) == -1) 455 scfdie(); 456 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 457 uint32_t flags; 458 459 if (scf_pg_get_flags(pg, &flags) == -1) 460 scfdie(); 461 if (flags & SCF_PG_FLAG_NONPERSISTENT) 462 display_pg(pg); 463 } 464 } 465 if (ret == -1) 466 scfdie(); 467 468 scf_iter_destroy(iter); 469 scf_pg_destroy(pg); 470 471 return; 472 } 473 474 if ((pg = scf_pg_create(hndl)) == NULL || 475 (prop = scf_property_create(hndl)) == NULL) 476 scfdie(); 477 478 if (ent.type == ENT_INSTANCE && snapshot != NULL) 479 snap = get_snapshot(ent.u.inst, snapshot); 480 481 for (spn = uu_list_first(prop_list); 482 spn != NULL; 483 spn = uu_list_next(prop_list, spn)) { 484 if (ent.type == ENT_INSTANCE) { 485 if (Cflag) 486 ret = scf_instance_get_pg(ent.u.inst, 487 spn->spn_comp1, pg); 488 else 489 ret = scf_instance_get_pg_composed(ent.u.inst, 490 snap, spn->spn_comp1, pg); 491 err = scf_error(); 492 493 /* 494 * If we didn't find it in the specified snapshot, use 495 * the current values if the pg is nonpersistent. 496 */ 497 if (ret == -1 && !Cflag &&snap != NULL && err == 498 SCF_ERROR_NOT_FOUND) { 499 ret = scf_instance_get_pg_composed( 500 ent.u.inst, NULL, spn->spn_comp1, 501 pg); 502 503 if (ret == 0) { 504 uint32_t flags; 505 506 if (scf_pg_get_flags(pg, &flags) == -1) 507 scfdie(); 508 if ((flags & SCF_PG_FLAG_NONPERSISTENT) 509 == 0) { 510 ret = -1; 511 } 512 } 513 } 514 } else { 515 /* 516 * If we are displaying properties for a service, 517 * treat it as though it were a composed, current 518 * lookup. (implicit cflag) However, if a snapshot 519 * was specified, fail. 520 */ 521 if (sflag) 522 die(gettext("Only instances have " 523 "snapshots.\n")); 524 ret = scf_entity_get_pg(ent, spn->spn_comp1, pg); 525 err = scf_error(); 526 } 527 if (ret == -1) { 528 if (err != SCF_ERROR_NOT_FOUND) 529 scfdie(); 530 531 if (PRINT_NOPROP_ERRORS) { 532 char *buf; 533 534 buf = safe_malloc(max_scf_fmri_length + 1); 535 if (scf_entity_to_fmri(ent, buf, 536 max_scf_fmri_length + 1) == -1) 537 scfdie(); 538 539 uu_warn(gettext("Couldn't find property group " 540 "`%s' for %s `%s'.\n"), spn->spn_comp1, 541 SCF_ENTITY_TYPE_NAME(ent), buf); 542 543 free(buf); 544 } 545 546 noprop_common_action(); 547 548 continue; 549 } 550 551 if (spn->spn_comp2 == NULL) { 552 if (!quiet) 553 display_pg(pg); 554 continue; 555 } 556 557 if (scf_pg_get_property(pg, spn->spn_comp2, prop) == -1) { 558 if (scf_error() != SCF_ERROR_NOT_FOUND) 559 scfdie(); 560 561 if (PRINT_NOPROP_ERRORS) { 562 char *buf; 563 564 buf = safe_malloc(max_scf_fmri_length + 1); 565 if (scf_entity_to_fmri(ent, buf, 566 max_scf_fmri_length + 1) == -1) 567 scfdie(); 568 569 /* FMRI syntax knowledge */ 570 uu_warn(gettext("Couldn't find property " 571 "`%s/%s' for %s `%s'.\n"), spn->spn_comp1, 572 spn->spn_comp2, SCF_ENTITY_TYPE_NAME(ent), 573 buf); 574 575 free(buf); 576 } 577 578 noprop_common_action(); 579 580 continue; 581 } 582 583 if (!quiet) 584 display_prop(pg, prop); 585 } 586 587 scf_property_destroy(prop); 588 scf_pg_destroy(pg); 589 if (snap) 590 scf_snapshot_destroy(snap); 591 } 592 593 /* 594 * Without -p options, just call display_pg(). Otherwise display_prop() the 595 * named properties of the property group. 596 */ 597 static void 598 process_pg(scf_propertygroup_t *pg) 599 { 600 scf_property_t *prop; 601 svcprop_prop_node_t *spn; 602 603 if (uu_list_first(prop_list) == NULL) { 604 if (quiet) 605 return; 606 607 display_pg(pg); 608 return; 609 } 610 611 prop = scf_property_create(hndl); 612 if (prop == NULL) 613 scfdie(); 614 615 for (spn = uu_list_first(prop_list); 616 spn != NULL; 617 spn = uu_list_next(prop_list, spn)) { 618 if (spn->spn_comp2 != NULL) { 619 char *buf; 620 621 buf = safe_malloc(max_scf_fmri_length + 1); 622 if (scf_pg_to_fmri(pg, buf, max_scf_fmri_length + 1) == 623 -1) 624 scfdie(); 625 626 uu_xdie(UU_EXIT_USAGE, gettext("-p argument `%s/%s' " 627 "has too many components for property " 628 "group `%s'.\n"), spn->spn_comp1, spn->spn_comp2, 629 buf); 630 631 free(buf); 632 } 633 634 if (scf_pg_get_property(pg, spn->spn_comp1, prop) == 0) { 635 if (!quiet) 636 display_prop(pg, prop); 637 continue; 638 } 639 640 if (scf_error() != SCF_ERROR_NOT_FOUND) 641 scfdie(); 642 643 if (PRINT_NOPROP_ERRORS) { 644 char *buf; 645 646 buf = safe_malloc(max_scf_fmri_length + 1); 647 if (scf_pg_to_fmri(pg, buf, max_scf_fmri_length + 1) == 648 -1) 649 scfdie(); 650 651 uu_warn(gettext("Couldn't find property `%s' in " 652 "property group `%s'.\n"), spn->spn_comp1, buf); 653 654 free(buf); 655 } 656 657 noprop_common_action(); 658 } 659 } 660 661 /* 662 * If there are -p options, show the error. Otherwise just call 663 * display_prop(). 664 */ 665 static void 666 process_prop(scf_propertygroup_t *pg, scf_property_t *prop) 667 { 668 if (uu_list_first(prop_list) != NULL) { 669 uu_warn(gettext("The -p option cannot be used with property " 670 "operands.\n")); 671 usage(); 672 } 673 674 if (quiet) 675 return; 676 677 display_prop(pg, prop); 678 } 679 680 /* Decode an operand & dispatch. */ 681 /* ARGSUSED */ 682 static int 683 process_fmri(void *unused, scf_walkinfo_t *wip) 684 { 685 scf_entityp_t ent; 686 687 /* Multiple matches imply multiple entities. */ 688 if (wip->count > 1) 689 types = fmris = 1; 690 691 if (wip->prop != NULL) { 692 process_prop(wip->pg, wip->prop); 693 } else if (wip->pg != NULL) { 694 process_pg(wip->pg); 695 } else if (wip->inst != NULL) { 696 SCF_ENTITY_SET_TO_INSTANCE(ent, wip->inst); 697 process_ent(ent); 698 } else { 699 /* scf_walk_fmri() won't let this happen */ 700 assert(wip->svc != NULL); 701 SCF_ENTITY_SET_TO_SERVICE(ent, wip->svc); 702 process_ent(ent); 703 } 704 705 return (0); 706 } 707 708 static void 709 add_prop(char *property) 710 { 711 svcprop_prop_node_t *p, *last; 712 char *slash; 713 714 const char * const invalid_component_emsg = 715 gettext("Invalid component name `%s'.\n"); 716 717 /* FMRI syntax knowledge. */ 718 slash = strchr(property, '/'); 719 if (slash != NULL) { 720 if (strchr(slash + 1, '/') != NULL) { 721 uu_warn(gettext("-p argument `%s' has too many " 722 "components.\n"), property); 723 usage(); 724 } 725 } 726 727 if (slash != NULL) 728 *slash = '\0'; 729 730 p = safe_malloc(sizeof (svcprop_prop_node_t)); 731 uu_list_node_init(p, &p->spn_list_node, prop_pool); 732 733 p->spn_comp1 = property; 734 p->spn_comp2 = (slash == NULL) ? NULL : slash + 1; 735 736 if (uu_check_name(p->spn_comp1, UU_NAME_DOMAIN) == -1) 737 uu_xdie(UU_EXIT_USAGE, invalid_component_emsg, p->spn_comp1); 738 if (p->spn_comp2 != NULL && 739 uu_check_name(p->spn_comp2, UU_NAME_DOMAIN) == -1) 740 uu_xdie(UU_EXIT_USAGE, invalid_component_emsg, p->spn_comp2); 741 742 last = uu_list_last(prop_list); 743 if (last != NULL) { 744 if ((last->spn_comp2 == NULL) ^ (p->spn_comp2 == NULL)) { 745 /* 746 * The -p options have mixed numbers of components. 747 * If they both turn out to be valid, then the 748 * single-component ones will specify property groups, 749 * so we need to turn on types to keep the output of 750 * display_prop() consistent with display_pg(). 751 */ 752 types = 1; 753 } 754 } 755 756 (void) uu_list_insert_after(prop_list, NULL, p); 757 } 758 759 760 /* 761 * Wait for a property group or property change. 762 * 763 * Extract a pg and optionally a property name from fmri & prop_list. 764 * _scf_pg_wait() for the pg, and display_pg(pg) or display_prop(pg, prop) 765 * when it returns. 766 */ 767 /* ARGSUSED */ 768 static int 769 do_wait(void *unused, scf_walkinfo_t *wip) 770 { 771 scf_property_t *prop; 772 scf_propertygroup_t *lpg, *pg; 773 const char *propname; 774 svcprop_prop_node_t *p; 775 776 const char *emsg_not_found = gettext("Not found.\n"); 777 778 if ((lpg = scf_pg_create(hndl)) == NULL || 779 (prop = scf_property_create(hndl)) == NULL) 780 scfdie(); 781 782 if (wip->prop != NULL) { 783 if (uu_list_numnodes(prop_list) > 0) 784 uu_xdie(UU_EXIT_USAGE, gettext("-p cannot be used with " 785 "property FMRIs.\n")); 786 pg = wip->pg; 787 788 assert(strrchr(wip->fmri, '/') != NULL); 789 propname = strrchr(wip->fmri, '/') + 1; 790 791 } else if (wip->pg != NULL) { 792 p = uu_list_first(prop_list); 793 794 if (p != NULL) { 795 if (p->spn_comp2 != NULL) 796 uu_xdie(UU_EXIT_USAGE, gettext("-p argument " 797 "\"%s/%s\" has too many components for " 798 "property group %s.\n"), 799 p->spn_comp1, p->spn_comp2, wip->fmri); 800 801 propname = p->spn_comp1; 802 803 if (scf_pg_get_property(wip->pg, propname, prop) != 804 SCF_SUCCESS) { 805 switch (scf_error()) { 806 case SCF_ERROR_INVALID_ARGUMENT: 807 uu_xdie(UU_EXIT_USAGE, 808 gettext("Invalid property name " 809 "\"%s\".\n"), propname); 810 811 /* NOTREACHED */ 812 813 case SCF_ERROR_NOT_FOUND: 814 die(emsg_not_found); 815 816 /* NOTREACHED */ 817 818 default: 819 scfdie(); 820 } 821 } 822 } else { 823 propname = NULL; 824 } 825 826 pg = wip->pg; 827 828 } else if (wip->inst != NULL) { 829 830 p = uu_list_first(prop_list); 831 if (p == NULL) 832 uu_xdie(UU_EXIT_USAGE, 833 gettext("Cannot wait for an instance.\n")); 834 835 if (scf_instance_get_pg(wip->inst, p->spn_comp1, lpg) != 836 SCF_SUCCESS) { 837 switch (scf_error()) { 838 case SCF_ERROR_INVALID_ARGUMENT: 839 uu_xdie(UU_EXIT_USAGE, gettext("Invalid " 840 "property group name \"%s\".\n"), 841 p->spn_comp1); 842 843 case SCF_ERROR_NOT_FOUND: 844 die(emsg_not_found); 845 846 /* NOTREACHED */ 847 848 default: 849 scfdie(); 850 } 851 } 852 853 propname = p->spn_comp2; 854 855 if (propname != NULL) { 856 if (scf_pg_get_property(lpg, propname, prop) != 857 SCF_SUCCESS) { 858 switch (scf_error()) { 859 case SCF_ERROR_INVALID_ARGUMENT: 860 uu_xdie(UU_EXIT_USAGE, 861 gettext("Invalid property name " 862 "\"%s\".\n"), propname); 863 864 case SCF_ERROR_NOT_FOUND: 865 die(emsg_not_found); 866 867 /* NOTREACHED */ 868 869 default: 870 scfdie(); 871 } 872 } 873 } 874 875 pg = lpg; 876 877 } else if (wip->svc != NULL) { 878 879 p = uu_list_first(prop_list); 880 if (p == NULL) 881 uu_xdie(UU_EXIT_USAGE, 882 gettext("Cannot wait for a service.\n")); 883 884 if (scf_service_get_pg(wip->svc, p->spn_comp1, lpg) != 885 SCF_SUCCESS) { 886 switch (scf_error()) { 887 case SCF_ERROR_INVALID_ARGUMENT: 888 uu_xdie(UU_EXIT_USAGE, gettext("Invalid " 889 "property group name \"%s\".\n"), 890 p->spn_comp1); 891 892 case SCF_ERROR_NOT_FOUND: 893 die(emsg_not_found); 894 895 default: 896 scfdie(); 897 } 898 } 899 900 propname = p->spn_comp2; 901 902 if (propname != NULL) { 903 if (scf_pg_get_property(lpg, propname, prop) != 904 SCF_SUCCESS) { 905 switch (scf_error()) { 906 case SCF_ERROR_INVALID_ARGUMENT: 907 uu_xdie(UU_EXIT_USAGE, 908 gettext("Invalid property name " 909 "\"%s\".\n"), propname); 910 911 /* NOTREACHED */ 912 913 case SCF_ERROR_NOT_FOUND: 914 die(emsg_not_found); 915 916 /* NOTREACHED */ 917 918 default: 919 scfdie(); 920 } 921 } 922 } 923 924 pg = lpg; 925 926 } else { 927 uu_xdie(UU_EXIT_USAGE, gettext("FMRI must specify an entity, " 928 "property group, or property.\n")); 929 } 930 931 for (;;) { 932 int ret; 933 934 ret = _scf_pg_wait(pg, -1); 935 if (ret != SCF_SUCCESS) 936 scfdie(); 937 938 ret = scf_pg_update(pg); 939 if (ret < 0) { 940 if (scf_error() != SCF_ERROR_DELETED) 941 scfdie(); 942 943 die(emsg_not_found); 944 } 945 if (ret == SCF_COMPLETE) 946 break; 947 } 948 949 if (propname != NULL) { 950 if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS) { 951 if (!quiet) 952 display_prop(pg, prop); 953 } else { 954 if (scf_error() != SCF_ERROR_NOT_FOUND) 955 scfdie(); 956 957 if (PRINT_NOPROP_ERRORS) 958 uu_warn(emsg_not_found); 959 960 return_code = UU_EXIT_FATAL; 961 } 962 } else { 963 if (!quiet) 964 display_pg(pg); 965 } 966 967 scf_property_destroy(prop); 968 scf_pg_destroy(lpg); 969 970 return (0); 971 } 972 973 /* 974 * These functions replace uu_warn() and uu_die() when the quiet (-q) option is 975 * used, and silently ignore any output. 976 */ 977 978 /*ARGSUSED*/ 979 static void 980 quiet_warn(const char *fmt, ...) 981 { 982 /* Do nothing */ 983 } 984 985 /*ARGSUSED*/ 986 static void 987 quiet_die(const char *fmt, ...) 988 { 989 exit(UU_EXIT_FATAL); 990 } 991 992 int 993 main(int argc, char *argv[]) 994 { 995 int c; 996 scf_walk_callback callback; 997 int flags; 998 int err; 999 1000 (void) setlocale(LC_ALL, ""); 1001 (void) textdomain(TEXT_DOMAIN); 1002 1003 return_code = UU_EXIT_OK; 1004 1005 (void) uu_setpname(argv[0]); 1006 1007 prop_pool = uu_list_pool_create("properties", 1008 sizeof (svcprop_prop_node_t), 1009 offsetof(svcprop_prop_node_t, spn_list_node), NULL, 0); 1010 if (prop_pool == NULL) 1011 uu_die("%s\n", uu_strerror(uu_error())); 1012 1013 prop_list = uu_list_create(prop_pool, NULL, 0); 1014 1015 while ((c = getopt(argc, argv, "Ccfp:qs:tvw")) != -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 '?': 1068 switch (optopt) { 1069 case 'p': 1070 usage(); 1071 1072 default: 1073 break; 1074 } 1075 1076 /* FALLTHROUGH */ 1077 1078 default: 1079 usage(); 1080 } 1081 } 1082 1083 if (optind == argc) 1084 usage(); 1085 1086 max_scf_name_length = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH); 1087 max_scf_value_length = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 1088 max_scf_fmri_length = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH); 1089 if (max_scf_name_length == -1 || max_scf_value_length == -1 || 1090 max_scf_fmri_length == -1) 1091 scfdie(); 1092 1093 hndl = scf_handle_create(SCF_VERSION); 1094 if (hndl == NULL) 1095 scfdie(); 1096 if (scf_handle_bind(hndl) == -1) 1097 die(gettext("Could not connect to configuration repository: " 1098 "%s.\n"), scf_strerror(scf_error())); 1099 1100 flags = SCF_WALK_PROPERTY | SCF_WALK_SERVICE | SCF_WALK_EXPLICIT; 1101 1102 if (wait) { 1103 if (uu_list_numnodes(prop_list) > 1) 1104 usage(); 1105 1106 if (argc - optind > 1) 1107 usage(); 1108 1109 callback = do_wait; 1110 1111 } else { 1112 callback = process_fmri; 1113 1114 flags |= SCF_WALK_MULTIPLE; 1115 } 1116 1117 if ((err = scf_walk_fmri(hndl, argc - optind, argv + optind, flags, 1118 callback, NULL, &return_code, warn)) != 0) { 1119 warn(gettext("failed to iterate over instances: %s\n"), 1120 scf_strerror(err)); 1121 return_code = UU_EXIT_FATAL; 1122 } 1123 1124 scf_handle_destroy(hndl); 1125 1126 return (return_code); 1127 } 1128