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
scfdie()121 scfdie()
122 {
123 die(gettext("Unexpected libscf error: %s. Exiting.\n"),
124 scf_strerror(scf_error()));
125 }
126
127 static void *
safe_malloc(size_t sz)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
usage()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 *
quote_for_shell(const char * str)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
print_value(scf_value_t * val)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
display_prop(scf_propertygroup_t * pg,scf_property_t * prop)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
display_pg(scf_propertygroup_t * pg)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
noprop_common_action()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
scf_iter_entity_pgs(scf_iter_t * iter,scf_entityp_t ent)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 *
get_snapshot(const scf_instance_t * inst,const char * snapshot)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
process_ent(scf_entityp_t ent)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
process_pg(scf_propertygroup_t * pg)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
process_prop(scf_propertygroup_t * pg,scf_property_t * prop)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
process_fmri(void * unused,scf_walkinfo_t * wip)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
add_prop(char * property)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
do_wait(void * unused,scf_walkinfo_t * wip)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
quiet_warn(const char * fmt,...)980 quiet_warn(const char *fmt, ...)
981 {
982 /* Do nothing */
983 }
984
985 /*ARGSUSED*/
986 static void
quiet_die(const char * fmt,...)987 quiet_die(const char *fmt, ...)
988 {
989 exit(UU_EXIT_FATAL);
990 }
991
992 int
main(int argc,char * argv[])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