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.
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.
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]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright (c) 2015, Joyent, Inc. All rights reserved.
29 * Service state explanation. For select services, display a description, the
30 * state, and possibly why the service is in that state, what's causing it to
31 * be in that state, and what other services it is keeping offline (impact).
33 * Explaining states other than offline is easy. For maintenance and
34 * degraded, we just use the auxiliary state. For offline, we must determine
35 * which dependencies are unsatisfied and recurse. If a causal service is not
36 * offline, then a svcptr to it is added to the offline service's causes list.
37 * If a causal service is offline, then we recurse to determine its causes and
38 * merge them into the causes list of the service in question (see
39 * add_causes()). Note that by adding a self-pointing svcptr to the causes
40 * lists of services which are not offline or are offline for unknown reasons,
41 * we can always merge the unsatisfied dependency's causes into the
44 * Computing an impact list is more involved because the dependencies in the
45 * repository are unidirectional; it requires determining the causes of all
46 * offline services. For each unsatisfied dependency of an offline service,
47 * a svcptr to the dependent is added to the dependency's impact_dependents
48 * list (see add_causes()). determine_impact() uses the lists to build an
49 * impact list. The direct dependency is used so that a path from the
50 * affected service to the causal service can be constructed (see
51 * print_dependency_reasons()).
53 * Because we always need at least impact counts, we always run
54 * determine_causes() on all services.
56 * If no arguments are given, we must select the services which are causing
57 * other services to be offline. We do so by adding services which are not
58 * running for any reason other than another service to the g_causes list in
61 * Since all services must be examined, and their states may be consulted
62 * a lot, it is important that we only read volatile data (like states) from
63 * the repository once. add_instance() reads data for an instance from the
64 * repository into an inst_t and puts it into the "services" cache, which is
65 * organized as a hash table of svc_t's, each of which has a list of inst_t's.
78 #include <libscf_priv.h>
85 #define DC_DISABLED "SMF-8000-05"
86 #define DC_TEMPDISABLED "SMF-8000-1S"
87 #define DC_RSTRINVALID "SMF-8000-2A"
88 #define DC_RSTRABSENT "SMF-8000-3P"
89 #define DC_UNINIT "SMF-8000-4D"
90 #define DC_RSTRDEAD "SMF-8000-5H"
91 #define DC_ADMINMAINT "SMF-8000-63"
92 #define DC_SVCREQMAINT "SMF-8000-R4"
93 #define DC_REPTFAIL "SMF-8000-7Y"
94 #define DC_METHFAIL "SMF-8000-8Q"
95 #define DC_NONE "SMF-8000-9C"
96 #define DC_UNKNOWN "SMF-8000-AR"
97 #define DC_STARTING "SMF-8000-C4"
98 #define DC_ADMINDEGR "SMF-8000-DX"
99 #define DC_DEPABSENT "SMF-8000-E2"
100 #define DC_DEPRUNNING "SMF-8000-FJ"
101 #define DC_DEPOTHER "SMF-8000-GE"
102 #define DC_DEPCYCLE "SMF-8000-HP"
103 #define DC_INVALIDDEP "SMF-8000-JA"
104 #define DC_STARTFAIL "SMF-8000-KS"
105 #define DC_TOOQUICKLY "SMF-8000-L5"
106 #define DC_INVALIDSTATE "SMF-8000-N3"
107 #define DC_TRANSITION "SMF-8000-PH"
109 #define DEFAULT_MAN_PATH "/usr/share/man"
111 #define AUX_STATE_INVALID "invalid_aux_state"
113 #define uu_list_append(lst, e) uu_list_insert_before(lst, NULL, e)
115 #define bad_error(func, err) \
116 uu_panic("%s:%d: %s() failed with unknown error %d.\n", \
117 __FILE__, __LINE__, func, err);
121 const char *instname
;
123 /* restarter pg properties */
124 char state
[MAX_SCF_STATE_STRING_SZ
];
125 char next_state
[MAX_SCF_STATE_STRING_SZ
];
126 struct timeval stime
;
127 const char *aux_state
;
128 const char *aux_fmri
;
129 int64_t start_method_waitstatus
;
133 const char *restarter
;
134 uu_list_t
*dependencies
; /* list of dependency_group's */
136 int active
; /* In use? (cycle detection) */
139 uu_list_t
*baddeps
; /* list of dependency's */
140 uu_list_t
*causes
; /* list of svcptrs */
141 uu_list_t
*impact_dependents
; /* list of svcptrs */
142 uu_list_t
*impact
; /* list of svcptrs */
147 typedef struct service
{
149 uu_list_t
*instances
;
150 struct service
*next
;
159 struct dependency_group
{
160 enum { DGG_REQALL
, DGG_REQANY
, DGG_OPTALL
, DGG_EXCALL
} grouping
;
162 uu_list_t
*entities
; /* List of struct dependency's */
171 /* Hash table of service names -> svc_t's */
172 #define SVC_HASH_NBUCKETS 256
173 #define SVC_HASH_MASK (SVC_HASH_NBUCKETS - 1)
175 static svc_t
**services
;
177 static uu_list_pool_t
*insts
, *svcptrs
, *depgroups
, *deps
;
178 static uu_list_t
*g_causes
; /* list of svcptrs */
180 static scf_scope_t
*g_local_scope
;
181 static scf_service_t
*g_svc
;
182 static scf_instance_t
*g_inst
;
183 static scf_snapshot_t
*g_snap
;
184 static scf_propertygroup_t
*g_pg
;
185 static scf_property_t
*g_prop
;
186 static scf_value_t
*g_val
;
187 static scf_iter_t
*g_iter
, *g_viter
;
188 static char *g_fmri
, *g_value
;
189 static size_t g_fmri_sz
, g_value_sz
;
190 static const char *g_msgbase
= "http://illumos.org/msg/";
192 static char *emsg_nomem
;
193 static char *emsg_invalid_dep
;
195 extern scf_handle_t
*h
;
196 extern char *g_zonename
;
200 svcptr_compare(struct svcptr
*a
, struct svcptr
*b
, void *data
)
202 return (b
->svcp
- a
->svcp
);
206 hash_name(const char *name
)
211 for (p
= name
; *p
!= '\0'; ++p
) {
213 if ((g
= (h
& 0xf0000000)) != 0) {
225 emsg_nomem
= gettext("Out of memory.\n");
227 gettext("svc:/%s:%s has invalid dependency \"%s\".\n");
229 services
= calloc(SVC_HASH_NBUCKETS
, sizeof (*services
));
230 if (services
== NULL
)
233 insts
= uu_list_pool_create("insts", sizeof (inst_t
),
234 offsetof(inst_t
, node
), NULL
, UU_LIST_POOL_DEBUG
);
235 svcptrs
= uu_list_pool_create("svcptrs", sizeof (struct svcptr
),
236 offsetof(struct svcptr
, node
), (uu_compare_fn_t
*)svcptr_compare
,
238 depgroups
= uu_list_pool_create("depgroups",
239 sizeof (struct dependency_group
),
240 offsetof(struct dependency_group
, node
), NULL
, UU_LIST_POOL_DEBUG
);
241 deps
= uu_list_pool_create("deps", sizeof (struct dependency
),
242 offsetof(struct dependency
, node
), NULL
, UU_LIST_POOL_DEBUG
);
243 g_causes
= uu_list_create(svcptrs
, NULL
, UU_LIST_DEBUG
);
244 if (insts
== NULL
|| svcptrs
== NULL
|| depgroups
== NULL
||
245 deps
== NULL
|| g_causes
== NULL
)
248 if ((g_local_scope
= scf_scope_create(h
)) == NULL
||
249 (g_svc
= scf_service_create(h
)) == NULL
||
250 (g_inst
= scf_instance_create(h
)) == NULL
||
251 (g_snap
= scf_snapshot_create(h
)) == NULL
||
252 (g_pg
= scf_pg_create(h
)) == NULL
||
253 (g_prop
= scf_property_create(h
)) == NULL
||
254 (g_val
= scf_value_create(h
)) == NULL
||
255 (g_iter
= scf_iter_create(h
)) == NULL
||
256 (g_viter
= scf_iter_create(h
)) == NULL
)
259 if (scf_handle_get_scope(h
, SCF_SCOPE_LOCAL
, g_local_scope
) != 0)
262 g_fmri_sz
= max_scf_fmri_length
+ 1;
263 g_fmri
= safe_malloc(g_fmri_sz
);
265 g_value_sz
= max_scf_value_length
+ 1;
266 g_value
= safe_malloc(g_value_sz
);
270 * Repository loading routines.
276 * ECANCELED - inst was deleted
277 * EINVAL - inst is invalid
280 load_dependencies(inst_t
*svcp
, scf_instance_t
*inst
)
282 scf_snapshot_t
*snap
;
283 struct dependency_group
*dg
;
284 struct dependency
*d
;
287 assert(svcp
->dependencies
== NULL
);
288 svcp
->dependencies
= uu_list_create(depgroups
, svcp
, UU_LIST_DEBUG
);
289 if (svcp
->dependencies
== NULL
)
292 if (scf_instance_get_snapshot(inst
, "running", g_snap
) == 0) {
295 if (scf_error() != SCF_ERROR_NOT_FOUND
)
301 if (scf_iter_instance_pgs_typed_composed(g_iter
, inst
, snap
,
302 SCF_GROUP_DEPENDENCY
) != 0) {
303 if (scf_error() != SCF_ERROR_DELETED
)
309 r
= scf_iter_next_pg(g_iter
, g_pg
);
313 if (scf_error() != SCF_ERROR_DELETED
)
318 dg
= safe_malloc(sizeof (*dg
));
319 (void) memset(dg
, 0, sizeof (*dg
));
320 dg
->entities
= uu_list_create(deps
, dg
, UU_LIST_DEBUG
);
321 if (dg
->entities
== NULL
)
324 if (pg_get_single_val(g_pg
, SCF_PROPERTY_GROUPING
,
325 SCF_TYPE_ASTRING
, g_value
, g_value_sz
, 0) != 0)
328 if (strcmp(g_value
, "require_all") == 0)
329 dg
->grouping
= DGG_REQALL
;
330 else if (strcmp(g_value
, "require_any") == 0)
331 dg
->grouping
= DGG_REQANY
;
332 else if (strcmp(g_value
, "optional_all") == 0)
333 dg
->grouping
= DGG_OPTALL
;
334 else if (strcmp(g_value
, "exclude_all") == 0)
335 dg
->grouping
= DGG_EXCALL
;
337 (void) fprintf(stderr
, gettext("svc:/%s:%s has "
338 "dependency with unknown type \"%s\".\n"),
339 svcp
->svcname
, svcp
->instname
, g_value
);
343 if (pg_get_single_val(g_pg
, SCF_PROPERTY_TYPE
, SCF_TYPE_ASTRING
,
344 g_value
, g_value_sz
, 0) != 0)
346 dg
->type
= safe_strdup(g_value
);
348 if (scf_pg_get_property(g_pg
, SCF_PROPERTY_ENTITIES
, g_prop
) !=
350 switch (scf_error()) {
351 case SCF_ERROR_NOT_FOUND
:
352 (void) fprintf(stderr
, gettext("svc:/%s:%s has "
353 "dependency without an entities "
354 "property.\n"), svcp
->svcname
,
358 case SCF_ERROR_DELETED
:
366 if (scf_iter_property_values(g_viter
, g_prop
) != 0) {
367 if (scf_error() != SCF_ERROR_DELETED
)
373 r
= scf_iter_next_value(g_viter
, g_val
);
377 if (scf_error() != SCF_ERROR_DELETED
)
382 d
= safe_malloc(sizeof (*d
));
383 d
->fmri
= safe_malloc(max_scf_fmri_length
+ 1);
385 if (scf_value_get_astring(g_val
, (char *)d
->fmri
,
386 max_scf_fmri_length
+ 1) < 0)
389 uu_list_node_init(d
, &d
->node
, deps
);
390 (void) uu_list_append(dg
->entities
, d
);
393 uu_list_node_init(dg
, &dg
->node
, depgroups
);
394 r
= uu_list_append(svcp
->dependencies
, dg
);
402 add_instance(const char *svcname
, const char *instname
, scf_instance_t
*inst
)
406 int have_enabled
= 0;
411 h
= hash_name(svcname
) & SVC_HASH_MASK
;
412 for (svcp
= services
[h
]; svcp
!= NULL
; svcp
= svcp
->next
) {
413 if (strcmp(svcp
->svcname
, svcname
) == 0)
418 svcp
= safe_malloc(sizeof (*svcp
));
419 svcp
->svcname
= safe_strdup(svcname
);
420 svcp
->instances
= uu_list_create(insts
, svcp
, UU_LIST_DEBUG
);
421 if (svcp
->instances
== NULL
)
423 svcp
->next
= services
[h
];
427 instp
= safe_malloc(sizeof (*instp
));
428 (void) memset(instp
, 0, sizeof (*instp
));
429 instp
->svcname
= svcp
->svcname
;
430 instp
->instname
= safe_strdup(instname
);
431 instp
->impact_dependents
=
432 uu_list_create(svcptrs
, instp
, UU_LIST_DEBUG
);
433 if (instp
->impact_dependents
== NULL
)
436 if (scf_instance_get_pg(inst
, SCF_PG_RESTARTER
, g_pg
) != 0) {
437 switch (scf_error()) {
438 case SCF_ERROR_DELETED
:
441 case SCF_ERROR_NOT_FOUND
:
442 (void) fprintf(stderr
, gettext("svc:/%s:%s has no "
443 "\"%s\" property group; ignoring.\n"),
444 instp
->svcname
, instp
->instname
, SCF_PG_RESTARTER
);
452 if (pg_get_single_val(g_pg
, SCF_PROPERTY_STATE
, SCF_TYPE_ASTRING
,
453 (void *)instp
->state
, sizeof (instp
->state
), 0) != 0)
456 if (pg_get_single_val(g_pg
, SCF_PROPERTY_NEXT_STATE
, SCF_TYPE_ASTRING
,
457 (void *)instp
->next_state
, sizeof (instp
->next_state
), 0) != 0)
460 if (pg_get_single_val(g_pg
, SCF_PROPERTY_STATE_TIMESTAMP
,
461 SCF_TYPE_TIME
, &instp
->stime
, 0, 0) != 0)
464 /* restarter may not set aux_state, allow to continue in that case */
465 if (pg_get_single_val(g_pg
, SCF_PROPERTY_AUX_STATE
, SCF_TYPE_ASTRING
,
466 g_fmri
, g_fmri_sz
, 0) == 0)
467 instp
->aux_state
= safe_strdup(g_fmri
);
469 instp
->aux_state
= safe_strdup(AUX_STATE_INVALID
);
471 (void) pg_get_single_val(g_pg
, SCF_PROPERTY_START_METHOD_WAITSTATUS
,
472 SCF_TYPE_INTEGER
, &instp
->start_method_waitstatus
, 0, 0);
474 /* Get the optional auxiliary_fmri */
475 if (pg_get_single_val(g_pg
, SCF_PROPERTY_AUX_FMRI
, SCF_TYPE_ASTRING
,
476 g_fmri
, g_fmri_sz
, 0) == 0)
477 instp
->aux_fmri
= safe_strdup(g_fmri
);
479 if (scf_instance_get_pg(inst
, SCF_PG_GENERAL_OVR
, g_pg
) == 0) {
480 if (pg_get_single_val(g_pg
, SCF_PROPERTY_ENABLED
,
481 SCF_TYPE_BOOLEAN
, &instp
->enabled
, 0, 0) == 0)
484 switch (scf_error()) {
485 case SCF_ERROR_NOT_FOUND
:
488 case SCF_ERROR_DELETED
:
496 if (scf_instance_get_pg_composed(inst
, NULL
, SCF_PG_GENERAL
, g_pg
) !=
498 switch (scf_error()) {
499 case SCF_ERROR_DELETED
:
500 case SCF_ERROR_NOT_FOUND
:
508 if (pg_get_single_val(g_pg
, SCF_PROPERTY_ENABLED
, SCF_TYPE_BOOLEAN
,
513 instp
->temporary
= 0;
515 instp
->temporary
= (instp
->enabled
!= i
);
518 if (pg_get_single_val(g_pg
, SCF_PROPERTY_RESTARTER
, SCF_TYPE_ASTRING
,
519 g_fmri
, g_fmri_sz
, 0) == 0)
520 instp
->restarter
= safe_strdup(g_fmri
);
522 instp
->restarter
= SCF_SERVICE_STARTD
;
524 if (strcmp(instp
->state
, SCF_STATE_STRING_OFFLINE
) == 0 &&
525 load_dependencies(instp
, inst
) != 0)
528 uu_list_node_init(instp
, &instp
->node
, insts
);
529 r
= uu_list_append(svcp
->instances
, instp
);
536 scf_iter_t
*siter
, *iiter
;
538 char *svcname
, *instname
;
540 if ((siter
= scf_iter_create(h
)) == NULL
||
541 (iiter
= scf_iter_create(h
)) == NULL
)
544 svcname
= safe_malloc(max_scf_name_length
+ 1);
545 instname
= safe_malloc(max_scf_name_length
+ 1);
547 if (scf_iter_scope_services(siter
, g_local_scope
) != 0)
551 r
= scf_iter_next_service(siter
, g_svc
);
557 if (scf_service_get_name(g_svc
, svcname
,
558 max_scf_name_length
+ 1) < 0) {
559 if (scf_error() != SCF_ERROR_DELETED
)
564 if (scf_iter_service_instances(iiter
, g_svc
) != 0) {
565 if (scf_error() != SCF_ERROR_DELETED
)
571 r
= scf_iter_next_instance(iiter
, g_inst
);
575 if (scf_error() != SCF_ERROR_DELETED
)
580 if (scf_instance_get_name(g_inst
, instname
,
581 max_scf_name_length
+ 1) < 0) {
582 if (scf_error() != SCF_ERROR_DELETED
)
587 add_instance(svcname
, instname
, g_inst
);
593 scf_iter_destroy(siter
);
594 scf_iter_destroy(iiter
);
598 * Dependency analysis routines.
602 add_svcptr(uu_list_t
*lst
, inst_t
*svcp
)
608 spp
= safe_malloc(sizeof (*spp
));
610 spp
->next_hop
= NULL
;
612 if (uu_list_find(lst
, spp
, NULL
, &idx
) != NULL
) {
617 uu_list_node_init(spp
, &spp
->node
, svcptrs
);
618 r
= uu_list_append(lst
, spp
);
622 static int determine_causes(inst_t
*, void *);
625 * Determine the causes of src and add them to the causes list of dst.
626 * Returns ELOOP if src is active, and 0 otherwise.
629 add_causes(inst_t
*dst
, inst_t
*src
)
631 struct svcptr
*spp
, *copy
;
634 if (determine_causes(src
, (void *)1) != UU_WALK_NEXT
) {
635 /* Dependency cycle. */
636 (void) fprintf(stderr
, " svc:/%s:%s\n", dst
->svcname
,
641 add_svcptr(src
->impact_dependents
, dst
);
643 for (spp
= uu_list_first(src
->causes
);
645 spp
= uu_list_next(src
->causes
, spp
)) {
646 if (uu_list_find(dst
->causes
, spp
, NULL
, &idx
) != NULL
)
649 copy
= safe_malloc(sizeof (*copy
));
650 copy
->svcp
= spp
->svcp
;
651 copy
->next_hop
= src
;
652 uu_list_node_init(copy
, ©
->node
, svcptrs
);
653 uu_list_insert(dst
->causes
, copy
, idx
);
655 add_svcptr(g_causes
, spp
->svcp
);
662 inst_running(inst_t
*ip
)
664 return (strcmp(ip
->state
, SCF_STATE_STRING_ONLINE
) == 0 ||
665 strcmp(ip
->state
, SCF_STATE_STRING_DEGRADED
) == 0);
669 inst_running_or_maint(inst_t
*ip
)
671 return (inst_running(ip
) ||
672 strcmp(ip
->state
, SCF_STATE_STRING_MAINT
) == 0);
676 get_svc(const char *sn
)
681 h
= hash_name(sn
) & SVC_HASH_MASK
;
683 for (svcp
= services
[h
]; svcp
!= NULL
; svcp
= svcp
->next
) {
684 if (strcmp(svcp
->svcname
, sn
) == 0)
693 get_inst(svc_t
*svcp
, const char *in
)
697 for (instp
= uu_list_first(svcp
->instances
);
699 instp
= uu_list_next(svcp
->instances
, instp
)) {
700 if (strcmp(instp
->instname
, in
) == 0)
708 get_fmri(const char *fmri
, svc_t
**spp
, inst_t
**ipp
)
714 if (strlcpy(g_fmri
, fmri
, g_fmri_sz
) >= g_fmri_sz
)
717 if (scf_parse_svc_fmri(g_fmri
, NULL
, &sn
, &in
, NULL
, NULL
) != 0)
728 ip
= get_inst(sp
, in
);
736 *ipp
= ((in
== NULL
) ? NULL
: ip
);
742 process_reqall(inst_t
*svcp
, struct dependency_group
*dg
)
744 uu_list_walk_t
*walk
;
745 struct dependency
*d
;
750 walk
= uu_list_walk_start(dg
->entities
, UU_WALK_ROBUST
);
754 while ((d
= uu_list_walk_next(walk
)) != NULL
) {
755 r
= get_fmri(d
->fmri
, &sp
, &ip
);
759 (void) fprintf(stderr
, emsg_invalid_dep
, svcp
->svcname
,
760 svcp
->instname
, d
->fmri
);
764 uu_list_remove(dg
->entities
, d
);
765 r
= uu_list_append(svcp
->baddeps
, d
);
773 bad_error("get_fmri", r
);
777 if (inst_running(ip
))
779 r
= add_causes(svcp
, ip
);
789 for (ip
= uu_list_first(sp
->instances
);
791 ip
= uu_list_next(sp
->instances
, ip
)) {
792 if (inst_running(ip
))
797 for (ip
= uu_list_first(sp
->instances
);
799 ip
= uu_list_next(sp
->instances
, ip
)) {
800 r
= add_causes(svcp
, ip
);
803 uu_list_walk_end(walk
);
810 uu_list_walk_end(walk
);
815 process_reqany(inst_t
*svcp
, struct dependency_group
*dg
)
819 struct dependency
*d
;
821 uu_list_walk_t
*walk
;
823 for (d
= uu_list_first(dg
->entities
);
825 d
= uu_list_next(dg
->entities
, d
)) {
826 r
= get_fmri(d
->fmri
, &sp
, &ip
);
833 (void) fprintf(stderr
, emsg_invalid_dep
, svcp
->svcname
,
834 svcp
->instname
, d
->fmri
);
841 bad_error("eval_svc_dep", r
);
845 if (inst_running(ip
))
850 for (ip
= uu_list_first(sp
->instances
);
852 ip
= uu_list_next(sp
->instances
, ip
)) {
853 if (inst_running(ip
))
859 * The dependency group is not satisfied. Add all unsatisfied members
863 walk
= uu_list_walk_start(dg
->entities
, UU_WALK_ROBUST
);
867 while ((d
= uu_list_walk_next(walk
)) != NULL
) {
868 r
= get_fmri(d
->fmri
, &sp
, &ip
);
874 uu_list_remove(dg
->entities
, d
);
875 r
= uu_list_append(svcp
->baddeps
, d
);
880 /* Should have caught above. */
882 bad_error("eval_svc_dep", r
);
886 if (inst_running(ip
))
888 r
= add_causes(svcp
, ip
);
896 for (ip
= uu_list_first(sp
->instances
);
898 ip
= uu_list_next(sp
->instances
, ip
)) {
899 if (inst_running(ip
))
901 r
= add_causes(svcp
, ip
);
913 process_optall(inst_t
*svcp
, struct dependency_group
*dg
)
915 uu_list_walk_t
*walk
;
916 struct dependency
*d
;
921 walk
= uu_list_walk_start(dg
->entities
, UU_WALK_ROBUST
);
925 while ((d
= uu_list_walk_next(walk
)) != NULL
) {
926 r
= get_fmri(d
->fmri
, &sp
, &ip
);
934 (void) fprintf(stderr
, emsg_invalid_dep
, svcp
->svcname
,
935 svcp
->instname
, d
->fmri
);
942 bad_error("get_fmri", r
);
946 if ((ip
->enabled
!= 0) && !inst_running_or_maint(ip
)) {
947 r
= add_causes(svcp
, ip
);
950 uu_list_walk_end(walk
);
957 for (ip
= uu_list_first(sp
->instances
);
959 ip
= uu_list_next(sp
->instances
, ip
)) {
960 if ((ip
->enabled
!= 0) && !inst_running_or_maint(ip
)) {
961 r
= add_causes(svcp
, ip
);
964 uu_list_walk_end(walk
);
971 uu_list_walk_end(walk
);
976 process_excall(inst_t
*svcp
, struct dependency_group
*dg
)
978 struct dependency
*d
;
983 for (d
= uu_list_first(dg
->entities
);
985 d
= uu_list_next(dg
->entities
, d
)) {
986 r
= get_fmri(d
->fmri
, &sp
, &ip
);
994 (void) fprintf(stderr
, emsg_invalid_dep
, svcp
->svcname
,
995 svcp
->instname
, d
->fmri
);
1002 bad_error("eval_svc_dep", r
);
1006 if (inst_running(ip
)) {
1007 r
= add_causes(svcp
, ip
);
1016 for (ip
= uu_list_first(sp
->instances
);
1018 ip
= uu_list_next(sp
->instances
, ip
)) {
1019 if (inst_running(ip
)) {
1020 r
= add_causes(svcp
, ip
);
1033 process_svc_dg(inst_t
*svcp
, struct dependency_group
*dg
)
1035 switch (dg
->grouping
) {
1037 return (process_reqall(svcp
, dg
));
1040 return (process_reqany(svcp
, dg
));
1043 return (process_optall(svcp
, dg
));
1046 return (process_excall(svcp
, dg
));
1050 (void) fprintf(stderr
,
1051 "%s:%d: Unknown dependency grouping %d.\n", __FILE__
,
1052 __LINE__
, dg
->grouping
);
1061 * EINVAL - fmri is not a valid FMRI
1062 * 0 - the file indicated by fmri is missing
1063 * 1 - the file indicated by fmri is present
1066 eval_file_dep(const char *fmri
)
1071 if (strncmp(fmri
, "file:", sizeof ("file:") - 1) != 0)
1074 path
= fmri
+ (sizeof ("file:") - 1);
1079 if (path
[1] == '/') {
1081 if (strncmp(path
, "localhost/", sizeof ("localhost/") - 1) == 0)
1082 path
+= sizeof ("localhost") - 1;
1083 else if (path
[0] != '/')
1087 return (stat(path
, &st
) == 0 ? 1 : 0);
1091 process_file_dg(inst_t
*svcp
, struct dependency_group
*dg
)
1093 uu_list_walk_t
*walk
;
1094 struct dependency
*d
, **deps
;
1095 int r
, i
= 0, any_satisfied
= 0;
1097 if (dg
->grouping
== DGG_REQANY
) {
1098 deps
= calloc(uu_list_numnodes(dg
->entities
), sizeof (*deps
));
1103 walk
= uu_list_walk_start(dg
->entities
, UU_WALK_ROBUST
);
1107 while ((d
= uu_list_walk_next(walk
)) != NULL
) {
1108 r
= eval_file_dep(d
->fmri
);
1111 (void) fprintf(stderr
, emsg_invalid_dep
, svcp
->svcname
,
1112 svcp
->instname
, d
->fmri
);
1116 assert(r
== 0 || r
== 1);
1118 switch (dg
->grouping
) {
1122 uu_list_remove(dg
->entities
, d
);
1123 r
= uu_list_append(svcp
->baddeps
, d
);
1137 uu_list_remove(dg
->entities
, d
);
1138 r
= uu_list_append(svcp
->baddeps
, d
);
1145 (void) fprintf(stderr
, "%s:%d: Unknown grouping %d.\n",
1146 __FILE__
, __LINE__
, dg
->grouping
);
1152 uu_list_walk_end(walk
);
1154 if (dg
->grouping
!= DGG_REQANY
)
1157 if (!any_satisfied
) {
1159 uu_list_remove(dg
->entities
, deps
[i
]);
1160 r
= uu_list_append(svcp
->baddeps
, deps
[i
]);
1169 * Populate the causes list of svcp. This function should not return with
1173 determine_causes(inst_t
*svcp
, void *canfailp
)
1175 struct dependency_group
*dg
;
1179 (void) fprintf(stderr
, gettext("Dependency cycle detected:\n"
1180 " svc:/%s:%s\n"), svcp
->svcname
, svcp
->instname
);
1181 return ((int)canfailp
!= 0 ? UU_WALK_ERROR
: UU_WALK_NEXT
);
1184 if (svcp
->causes
!= NULL
)
1185 return (UU_WALK_NEXT
);
1187 svcp
->causes
= uu_list_create(svcptrs
, svcp
, UU_LIST_DEBUG
);
1188 svcp
->baddeps
= uu_list_create(deps
, svcp
, UU_LIST_DEBUG
);
1189 if (svcp
->causes
== NULL
|| svcp
->baddeps
== NULL
)
1192 if (inst_running(svcp
) ||
1193 strcmp(svcp
->state
, SCF_STATE_STRING_UNINIT
) == 0) {
1195 * If we're running, add a self-pointer in case we're
1196 * excluding another service.
1198 add_svcptr(svcp
->causes
, svcp
);
1199 return (UU_WALK_NEXT
);
1202 if (strcmp(svcp
->state
, SCF_STATE_STRING_MAINT
) == 0) {
1203 add_svcptr(svcp
->causes
, svcp
);
1204 add_svcptr(g_causes
, svcp
);
1205 return (UU_WALK_NEXT
);
1208 if (strcmp(svcp
->state
, SCF_STATE_STRING_DISABLED
) == 0) {
1209 add_svcptr(svcp
->causes
, svcp
);
1210 if (svcp
->enabled
!= 0)
1211 add_svcptr(g_causes
, svcp
);
1213 return (UU_WALK_NEXT
);
1216 if (strcmp(svcp
->state
, SCF_STATE_STRING_OFFLINE
) != 0) {
1217 (void) fprintf(stderr
,
1218 gettext("svc:/%s:%s has invalid state \"%s\".\n"),
1219 svcp
->svcname
, svcp
->instname
, svcp
->state
);
1220 add_svcptr(svcp
->causes
, svcp
);
1221 add_svcptr(g_causes
, svcp
);
1222 return (UU_WALK_NEXT
);
1225 if (strcmp(svcp
->next_state
, SCF_STATE_STRING_NONE
) != 0) {
1226 add_svcptr(svcp
->causes
, svcp
);
1227 add_svcptr(g_causes
, svcp
);
1228 return (UU_WALK_NEXT
);
1234 * Dependency analysis can add elements to our baddeps list (absent
1235 * dependency, unsatisfied file dependency), or to our cause list
1236 * (unsatisfied dependency).
1238 for (dg
= uu_list_first(svcp
->dependencies
);
1240 dg
= uu_list_next(svcp
->dependencies
, dg
)) {
1241 if (strcmp(dg
->type
, "path") == 0) {
1242 process_file_dg(svcp
, dg
);
1243 } else if (strcmp(dg
->type
, "service") == 0) {
1246 r
= process_svc_dg(svcp
, dg
);
1250 return ((int)canfailp
!= 0 ?
1251 UU_WALK_ERROR
: UU_WALK_NEXT
);
1254 (void) fprintf(stderr
, gettext("svc:/%s:%s has "
1255 "dependency group with invalid type \"%s\".\n"),
1256 svcp
->svcname
, svcp
->instname
, dg
->type
);
1260 if (uu_list_numnodes(svcp
->causes
) == 0) {
1261 if (uu_list_numnodes(svcp
->baddeps
) > 0) {
1262 add_svcptr(g_causes
, svcp
);
1263 add_svcptr(svcp
->causes
, svcp
);
1267 r
= get_fmri(svcp
->restarter
, NULL
, &restarter
);
1268 if (r
== 0 && !inst_running(restarter
)) {
1269 r
= add_causes(svcp
, restarter
);
1273 return ((int)canfailp
!= 0 ?
1274 UU_WALK_ERROR
: UU_WALK_NEXT
);
1277 svcp
->restarter_bad
= r
;
1278 add_svcptr(svcp
->causes
, svcp
);
1279 add_svcptr(g_causes
, svcp
);
1284 assert(uu_list_numnodes(svcp
->causes
) > 0);
1287 return (UU_WALK_NEXT
);
1291 determine_all_causes(void)
1296 for (i
= 0; i
< SVC_HASH_NBUCKETS
; ++i
) {
1297 for (svcp
= services
[i
]; svcp
!= NULL
; svcp
= svcp
->next
)
1298 (void) uu_list_walk(svcp
->instances
,
1299 (uu_walk_fn_t
*)determine_causes
, 0, 0);
1306 * ELOOP - dependency cycle detected
1309 determine_impact(inst_t
*ip
)
1311 struct svcptr
*idsp
, *spp
, *copy
;
1312 uu_list_index_t idx
;
1315 (void) fprintf(stderr
, gettext("Dependency cycle detected:\n"
1316 " svc:/%s:%s\n"), ip
->svcname
, ip
->instname
);
1320 if (ip
->impact
!= NULL
)
1323 ip
->impact
= uu_list_create(svcptrs
, ip
, UU_LIST_DEBUG
);
1324 if (ip
->impact
== NULL
)
1328 for (idsp
= uu_list_first(ip
->impact_dependents
);
1330 idsp
= uu_list_next(ip
->impact_dependents
, idsp
)) {
1331 if (determine_impact(idsp
->svcp
) != 0) {
1332 (void) fprintf(stderr
, " svc:/%s:%s\n",
1333 ip
->svcname
, ip
->instname
);
1337 add_svcptr(ip
->impact
, idsp
->svcp
);
1339 for (spp
= uu_list_first(idsp
->svcp
->impact
);
1341 spp
= uu_list_next(idsp
->svcp
->impact
, spp
)) {
1342 if (uu_list_find(ip
->impact
, spp
, NULL
, &idx
) != NULL
)
1345 copy
= safe_malloc(sizeof (*copy
));
1346 copy
->svcp
= spp
->svcp
;
1347 copy
->next_hop
= NULL
;
1348 uu_list_node_init(copy
, ©
->node
, svcptrs
);
1349 uu_list_insert(ip
->impact
, copy
, idx
);
1358 * Printing routines.
1364 if (scf_handle_decode_fmri(h
, SCF_SERVICE_STARTD
, NULL
, NULL
, g_inst
,
1365 NULL
, NULL
, SCF_DECODE_FMRI_EXACT
) != 0) {
1366 if (scf_error() != SCF_ERROR_NOT_FOUND
)
1372 if (scf_instance_get_pg_composed(g_inst
, NULL
, "msg", g_pg
) != 0) {
1373 switch (scf_error()) {
1374 case SCF_ERROR_NOT_FOUND
:
1375 case SCF_ERROR_DELETED
:
1383 if (scf_pg_get_property(g_pg
, "base", g_prop
) != 0) {
1384 switch (scf_error()) {
1385 case SCF_ERROR_NOT_FOUND
:
1386 case SCF_ERROR_DELETED
:
1394 if (scf_property_get_value(g_prop
, g_val
) != 0) {
1395 switch (scf_error()) {
1396 case SCF_ERROR_NOT_FOUND
:
1397 case SCF_ERROR_CONSTRAINT_VIOLATED
:
1398 case SCF_ERROR_PERMISSION_DENIED
:
1402 case SCF_ERROR_DELETED
:
1410 if (scf_value_get_astring(g_val
, g_value
, g_value_sz
) < 0) {
1411 if (scf_error() != SCF_ERROR_TYPE_MISMATCH
)
1416 g_msgbase
= safe_strdup(g_value
);
1420 determine_summary(inst_t
*ip
)
1422 if (ip
->summary
!= NULL
)
1425 if (inst_running(ip
)) {
1426 ip
->summary
= gettext("is running.");
1430 if (strcmp(ip
->state
, SCF_STATE_STRING_UNINIT
) == 0) {
1431 ip
->summary
= gettext("is uninitialized.");
1432 } else if (strcmp(ip
->state
, SCF_STATE_STRING_DISABLED
) == 0) {
1434 ip
->summary
= gettext("is disabled.");
1436 ip
->summary
= gettext("is temporarily disabled.");
1437 } else if (strcmp(ip
->state
, SCF_STATE_STRING_OFFLINE
) == 0) {
1438 if (uu_list_numnodes(ip
->baddeps
) != 0)
1439 ip
->summary
= gettext("has missing dependencies.");
1440 else if (strcmp(ip
->next_state
, SCF_STATE_STRING_ONLINE
) == 0)
1441 ip
->summary
= gettext("is starting.");
1443 ip
->summary
= gettext("is offline.");
1444 } else if (strcmp(ip
->state
, SCF_STATE_STRING_MAINT
) == 0) {
1445 if (strcmp(ip
->aux_state
, "administrative_request") == 0) {
1446 ip
->summary
= gettext("was taken down for maintenace "
1447 "by an administrator.");
1448 } else if (strcmp(ip
->aux_state
, "dependency_cycle") == 0) {
1449 ip
->summary
= gettext("completed a dependency cycle.");
1450 } else if (strcmp(ip
->aux_state
, "fault_threshold_reached") ==
1452 ip
->summary
= gettext("is not running because "
1453 "a method failed repeatedly.");
1454 } else if (strcmp(ip
->aux_state
, "invalid_dependency") == 0) {
1455 ip
->summary
= gettext("has an invalid dependency.");
1456 } else if (strcmp(ip
->aux_state
, "invalid_restarter") == 0) {
1457 ip
->summary
= gettext("has an invalid restarter.");
1458 } else if (strcmp(ip
->aux_state
, "method_failed") == 0) {
1459 ip
->summary
= gettext("is not running because "
1460 "a method failed.");
1461 } else if (strcmp(ip
->aux_state
, "none") == 0) {
1463 gettext("is not running for an unknown reason.");
1464 } else if (strcmp(ip
->aux_state
, "restarting_too_quickly") ==
1466 ip
->summary
= gettext("was restarting too quickly.");
1468 ip
->summary
= gettext("requires maintenance.");
1471 ip
->summary
= gettext("is in an invalid state.");
1476 print_method_failure(const inst_t
*ip
, const char **dcp
)
1479 int stat
= ip
->start_method_waitstatus
;
1482 if (WIFEXITED(stat
)) {
1483 if (WEXITSTATUS(stat
) == SMF_EXIT_ERR_CONFIG
) {
1484 (void) strlcpy(buf
, gettext(
1485 "exited with $SMF_EXIT_ERR_CONFIG"),
1487 } else if (WEXITSTATUS(stat
) == SMF_EXIT_ERR_FATAL
) {
1488 (void) strlcpy(buf
, gettext(
1489 "exited with $SMF_EXIT_ERR_FATAL"),
1492 (void) snprintf(buf
, sizeof (buf
),
1493 gettext("exited with status %d"),
1496 } else if (WIFSIGNALED(stat
)) {
1497 if (WCOREDUMP(stat
)) {
1498 if (strsignal(WTERMSIG(stat
)) != NULL
)
1499 (void) snprintf(buf
, sizeof (buf
),
1500 gettext("dumped core on %s (%d)"),
1501 strsignal(WTERMSIG(stat
)),
1504 (void) snprintf(buf
, sizeof (buf
),
1505 gettext("dumped core signal %d"),
1508 if (strsignal(WTERMSIG(stat
)) != NULL
) {
1509 (void) snprintf(buf
, sizeof (buf
),
1510 gettext("died on %s (%d)"),
1511 strsignal(WTERMSIG(stat
)),
1514 (void) snprintf(buf
, sizeof (buf
),
1515 gettext("died on signal %d"),
1523 if (strcmp(ip
->aux_state
, "fault_threshold_reached") != 0)
1524 (void) printf(gettext("Reason: Start method %s.\n"),
1527 (void) printf(gettext("Reason: "
1528 "Start method failed repeatedly, last %s.\n"), buf
);
1529 *dcp
= DC_STARTFAIL
;
1532 if (strcmp(ip
->aux_state
, "fault_threshold_reached") == 0)
1533 (void) puts(gettext(
1534 "Reason: Method failed repeatedly."));
1536 (void) puts(gettext("Reason: Method failed."));
1542 print_dependency_reasons(const inst_t
*svcp
, int verbose
)
1544 struct dependency
*d
;
1549 * If we couldn't determine why the service is offline, then baddeps
1550 * will be empty and causes will have a pointer to self.
1552 if (uu_list_numnodes(svcp
->baddeps
) == 0 &&
1553 uu_list_numnodes(svcp
->causes
) == 1) {
1554 spp
= uu_list_first(svcp
->causes
);
1555 if (spp
->svcp
== svcp
) {
1556 switch (svcp
->restarter_bad
) {
1558 (void) puts(gettext("Reason: Unknown."));
1563 (void) printf(gettext("Reason: "
1564 "Restarter \"%s\" is invalid.\n"),
1566 dc
= DC_RSTRINVALID
;
1570 (void) printf(gettext("Reason: "
1571 "Restarter \"%s\" does not exist.\n"),
1578 (void) fprintf(stderr
, "%s:%d: Bad "
1579 "restarter_bad value %d. Aborting.\n",
1580 __FILE__
, __LINE__
, svcp
->restarter_bad
);
1586 (void) printf(gettext(" See: %s%s\n"),
1592 for (d
= uu_list_first(svcp
->baddeps
);
1594 d
= uu_list_next(svcp
->baddeps
, d
)) {
1595 (void) printf(gettext("Reason: Dependency %s is absent.\n"),
1598 (void) printf(gettext(" See: %s%s\n"), g_msgbase
,
1602 for (spp
= uu_list_first(svcp
->causes
);
1603 spp
!= NULL
&& spp
->svcp
!= svcp
;
1604 spp
= uu_list_next(svcp
->causes
, spp
)) {
1605 determine_summary(spp
->svcp
);
1607 if (inst_running(spp
->svcp
)) {
1608 (void) printf(gettext("Reason: "
1609 "Service svc:/%s:%s is running.\n"),
1610 spp
->svcp
->svcname
, spp
->svcp
->instname
);
1613 if (snprintf(NULL
, 0,
1614 gettext("Reason: Service svc:/%s:%s %s"),
1615 spp
->svcp
->svcname
, spp
->svcp
->instname
,
1616 spp
->svcp
->summary
) <= 80) {
1617 (void) printf(gettext(
1618 "Reason: Service svc:/%s:%s %s\n"),
1619 spp
->svcp
->svcname
, spp
->svcp
->instname
,
1620 spp
->svcp
->summary
);
1622 (void) printf(gettext(
1623 "Reason: Service svc:/%s:%s\n"
1624 " %s\n"), spp
->svcp
->svcname
,
1625 spp
->svcp
->instname
, spp
->svcp
->summary
);
1631 if (g_msgbase
!= NULL
)
1632 (void) printf(gettext(" See: %s%s\n"), g_msgbase
, dc
);
1638 (void) printf(gettext(" Path: svc:/%s:%s\n"),
1639 svcp
->svcname
, svcp
->instname
);
1642 for (pp
= spp
->next_hop
; ; ) {
1645 (void) printf(gettext("%6s %*ssvc:/%s:%s\n"),
1646 "", indent
++ * 2, "", pp
->svcname
,
1649 if (pp
== spp
->svcp
)
1652 /* set pp to next_hop of cause with same svcp */
1653 tmp
= uu_list_find(pp
->causes
, spp
, NULL
, NULL
);
1661 print_logs(scf_instance_t
*inst
)
1663 if (scf_instance_get_pg(inst
, SCF_PG_RESTARTER
, g_pg
) != 0)
1666 if (pg_get_single_val(g_pg
, SCF_PROPERTY_ALT_LOGFILE
,
1667 SCF_TYPE_ASTRING
, (void *)g_value
, g_value_sz
, 0) == 0)
1668 (void) printf(gettext(" See: %s\n"), g_value
);
1670 if (pg_get_single_val(g_pg
, SCF_PROPERTY_LOGFILE
,
1671 SCF_TYPE_ASTRING
, (void *)g_value
, g_value_sz
, 0) == 0)
1672 (void) printf(gettext(" See: %s\n"), g_value
);
1676 print_aux_fmri_logs(const char *fmri
)
1678 scf_instance_t
*scf_inst
= scf_instance_create(h
);
1679 if (scf_inst
== NULL
)
1682 if (scf_handle_decode_fmri(h
, fmri
, NULL
, NULL
, scf_inst
,
1683 NULL
, NULL
, SCF_DECODE_FMRI_EXACT
) == 0)
1684 print_logs(scf_inst
);
1686 scf_instance_destroy(scf_inst
);
1690 print_reasons(const inst_t
*svcp
, int verbose
)
1693 const char *dc
= NULL
;
1695 if (strcmp(svcp
->state
, SCF_STATE_STRING_ONLINE
) == 0)
1698 if (strcmp(svcp
->state
, SCF_STATE_STRING_UNINIT
) == 0) {
1701 r
= get_fmri(svcp
->restarter
, NULL
, &rsp
);
1709 (void) printf(gettext("Reason: "
1710 "Restarter \"%s\" is invalid.\n"), svcp
->restarter
);
1711 dc
= DC_RSTRINVALID
;
1715 (void) printf(gettext("Reason: "
1716 "Restarter \"%s\" does not exist.\n"),
1722 bad_error("get_fmri", r
);
1725 if (inst_running(rsp
)) {
1726 (void) printf(gettext("Reason: Restarter %s "
1727 "has not initialized service state.\n"),
1731 (void) printf(gettext(
1732 "Reason: Restarter %s is not running.\n"),
1737 } else if (strcmp(svcp
->state
, SCF_STATE_STRING_DISABLED
) == 0) {
1738 if (!svcp
->temporary
) {
1739 (void) puts(gettext(
1740 "Reason: Disabled by an administrator."));
1743 (void) puts(gettext("Reason: "
1744 "Temporarily disabled by an administrator."));
1745 dc
= DC_TEMPDISABLED
;
1748 } else if (strcmp(svcp
->state
, SCF_STATE_STRING_MAINT
) == 0) {
1749 if (strcmp(svcp
->aux_state
, "administrative_request") == 0) {
1750 (void) puts(gettext("Reason: "
1751 "Maintenance requested by an administrator."));
1753 } else if (strcmp(svcp
->aux_state
, "dependency_cycle") == 0) {
1754 (void) puts(gettext(
1755 "Reason: Completes a dependency cycle."));
1757 } else if (strcmp(svcp
->aux_state
, "fault_threshold_reached") ==
1759 print_method_failure(svcp
, &dc
);
1760 } else if (strcmp(svcp
->aux_state
, "service_request") == 0) {
1761 if (svcp
->aux_fmri
) {
1762 (void) printf(gettext("Reason: Maintenance "
1763 "requested by \"%s\"\n"), svcp
->aux_fmri
);
1764 print_aux_fmri_logs(svcp
->aux_fmri
);
1766 (void) puts(gettext("Reason: Maintenance "
1767 "requested by another service."));
1769 dc
= DC_SVCREQMAINT
;
1770 } else if (strcmp(svcp
->aux_state
, "invalid_dependency") == 0) {
1771 (void) puts(gettext("Reason: Has invalid dependency."));
1773 } else if (strcmp(svcp
->aux_state
, "invalid_restarter") == 0) {
1774 (void) printf(gettext("Reason: Restarter \"%s\" is "
1775 "invalid.\n"), svcp
->restarter
);
1776 dc
= DC_RSTRINVALID
;
1777 } else if (strcmp(svcp
->aux_state
, "method_failed") == 0) {
1778 print_method_failure(svcp
, &dc
);
1779 } else if (strcmp(svcp
->aux_state
, "restarting_too_quickly") ==
1781 (void) puts(gettext("Reason: Restarting too quickly."));
1783 } else if (strcmp(svcp
->aux_state
, "none") == 0) {
1784 (void) printf(gettext(
1785 "Reason: Restarter %s gave no explanation.\n"),
1789 (void) puts(gettext("Reason: Unknown."));
1793 } else if (strcmp(svcp
->state
, SCF_STATE_STRING_OFFLINE
) == 0) {
1794 if (strcmp(svcp
->next_state
, SCF_STATE_STRING_ONLINE
) == 0) {
1795 (void) puts(gettext(
1796 "Reason: Start method is running."));
1798 } else if (strcmp(svcp
->next_state
, SCF_STATE_STRING_NONE
) ==
1800 print_dependency_reasons(svcp
, verbose
);
1801 /* Function prints diagcodes. */
1804 (void) printf(gettext(
1805 "Reason: Transitioning to state %s.\n"),
1810 } else if (strcmp(svcp
->state
, SCF_STATE_STRING_DEGRADED
) == 0) {
1811 (void) puts(gettext("Reason: Degraded by an administrator."));
1815 (void) printf(gettext("Reason: Not in valid state (%s).\n"),
1817 dc
= DC_INVALIDSTATE
;
1821 if (g_msgbase
!= NULL
)
1822 (void) printf(gettext(" See: %s%s\n"), g_msgbase
, dc
);
1826 print_manpage(int verbose
)
1828 static char *title
= NULL
;
1829 static char *section
= NULL
;
1831 if (title
== NULL
) {
1832 title
= safe_malloc(g_value_sz
);
1833 section
= safe_malloc(g_value_sz
);
1836 if (pg_get_single_val(g_pg
, SCF_PROPERTY_TM_TITLE
, SCF_TYPE_ASTRING
,
1837 (void *)title
, g_value_sz
, 0) != 0)
1840 if (pg_get_single_val(g_pg
, SCF_PROPERTY_TM_SECTION
,
1841 SCF_TYPE_ASTRING
, (void *)section
, g_value_sz
, 0) != 0)
1845 (void) printf(gettext(" See: %s(%s)\n"), title
, section
);
1849 if (pg_get_single_val(g_pg
, SCF_PROPERTY_TM_MANPATH
, SCF_TYPE_ASTRING
,
1850 (void *)g_value
, g_value_sz
, 0) != 0)
1853 if (strcmp(g_value
, ":default") == 0) {
1854 assert(sizeof (DEFAULT_MAN_PATH
) < g_value_sz
);
1855 (void) strcpy(g_value
, DEFAULT_MAN_PATH
);
1858 (void) printf(gettext(" See: man -M %s -s %s %s\n"), g_value
,
1865 static char *uri
= NULL
;
1868 uri
= safe_malloc(g_value_sz
);
1871 if (pg_get_single_val(g_pg
, SCF_PROPERTY_TM_URI
, SCF_TYPE_ASTRING
,
1872 (void *)uri
, g_value_sz
, 0) != 0)
1875 (void) printf(gettext(" See: %s\n"), uri
);
1882 * 1 - inst was deleted
1885 print_docs(scf_instance_t
*inst
, int verbose
)
1887 scf_snapshot_t
*snap
;
1890 if (scf_instance_get_snapshot(inst
, "running", g_snap
) != 0) {
1891 switch (scf_error()) {
1892 case SCF_ERROR_NOT_FOUND
:
1895 case SCF_ERROR_DELETED
:
1907 if (scf_iter_instance_pgs_typed_composed(g_iter
, inst
, snap
,
1908 SCF_GROUP_TEMPLATE
) != 0) {
1909 if (scf_error() != SCF_ERROR_DELETED
)
1916 r
= scf_iter_next_pg(g_iter
, g_pg
);
1920 if (scf_error() != SCF_ERROR_DELETED
)
1926 if (scf_pg_get_name(g_pg
, g_fmri
, g_fmri_sz
) < 0) {
1927 if (scf_error() != SCF_ERROR_DELETED
)
1933 if (strncmp(g_fmri
, SCF_PG_TM_MAN_PREFIX
,
1934 strlen(SCF_PG_TM_MAN_PREFIX
)) == 0) {
1935 print_manpage(verbose
);
1939 if (strncmp(g_fmri
, SCF_PG_TM_DOC_PREFIX
,
1940 strlen(SCF_PG_TM_DOC_PREFIX
)) == 0) {
1948 static int first
= 1;
1951 * Explain why the given service is in the state it's in.
1954 print_service(inst_t
*svcp
, int verbose
)
1966 (void) putchar('\n');
1968 (void) printf(gettext("svc:/%s:%s"), svcp
->svcname
, svcp
->instname
);
1970 if (scf_scope_get_service(g_local_scope
, svcp
->svcname
, g_svc
) != 0) {
1971 if (scf_error() != SCF_ERROR_NOT_FOUND
)
1974 } else if (scf_service_get_instance(g_svc
, svcp
->instname
, g_inst
) !=
1976 if (scf_error() != SCF_ERROR_NOT_FOUND
)
1982 if (inst_get_single_val(g_inst
, SCF_PG_TM_COMMON_NAME
, locale
,
1983 SCF_TYPE_USTRING
, g_value
, g_value_sz
, 0, 0, 1) == 0)
1985 else if (inst_get_single_val(g_inst
, SCF_PG_TM_COMMON_NAME
, "C",
1986 SCF_TYPE_USTRING
, g_value
, g_value_sz
, 0, 0, 1) != 0)
1987 (void) strcpy(g_value
, "?");
1989 (void) printf(gettext(" (%s)\n"), g_value
);
1991 (void) putchar('\n');
1994 if (g_zonename
!= NULL
)
1995 (void) printf(gettext(" Zone: %s\n"), g_zonename
);
1997 stime
= svcp
->stime
.tv_sec
;
1998 tmp
= localtime(&stime
);
2000 for (tbsz
= 50; ; tbsz
*= 2) {
2001 timebuf
= safe_malloc(tbsz
);
2002 if (strftime(timebuf
, tbsz
, NULL
, tmp
) != 0)
2007 (void) printf(gettext(" State: %s since %s\n"), svcp
->state
, timebuf
);
2012 print_reasons(svcp
, verbose
);
2015 deleted
= print_docs(g_inst
, verbose
);
2019 (void) determine_impact(svcp
);
2021 switch (uu_list_numnodes(svcp
->impact
)) {
2023 if (inst_running(svcp
))
2024 (void) puts(gettext("Impact: None."));
2026 (void) puts(gettext(
2027 "Impact: This service is not running."));
2032 (void) puts(gettext("Impact: 1 dependent service "
2033 "is not running. (Use -v for list.)"));
2035 (void) puts(gettext(
2036 "Impact: 1 dependent service is not running:"));
2041 (void) printf(gettext("Impact: %d dependent services "
2042 "are not running. (Use -v for list.)\n"),
2043 uu_list_numnodes(svcp
->impact
));
2045 (void) printf(gettext(
2046 "Impact: %d dependent services are not running:\n"),
2047 uu_list_numnodes(svcp
->impact
));
2051 for (spp
= uu_list_first(svcp
->impact
);
2053 spp
= uu_list_next(svcp
->impact
, spp
))
2054 (void) printf(gettext(" svc:/%s:%s\n"),
2055 spp
->svcp
->svcname
, spp
->svcp
->instname
);
2060 * Top level routine.
2064 impact_compar(const void *a
, const void *b
)
2068 n
= uu_list_numnodes((*(inst_t
**)a
)->impact
);
2069 m
= uu_list_numnodes((*(inst_t
**)b
)->impact
);
2075 print_service_cb(void *verbose
, scf_walkinfo_t
*wip
)
2080 assert(wip
->pg
== NULL
);
2082 r
= get_fmri(wip
->fmri
, NULL
, &ip
);
2083 assert(r
!= EINVAL
);
2090 print_service(ip
, (int)verbose
);
2096 explain(int verbose
, int argc
, char **argv
)
2099 * Initialize globals. If we have been called before (e.g., for a
2100 * different zone), this will clobber the previous globals -- keeping
2101 * with the proud svcs(1) tradition of not bothering to ever clean
2106 /* Walk the graph and populate services with inst_t's */
2109 /* Populate causes for services. */
2110 determine_all_causes();
2117 /* Call print_service() for each operand. */
2119 err
= scf_walk_fmri(h
, argc
, argv
, SCF_WALK_MULTIPLE
,
2120 print_service_cb
, (void *)verbose
, &exit_status
, uu_warn
);
2123 "failed to iterate over instances: %s\n"),
2125 exit_status
= UU_EXIT_FATAL
;
2132 /* Sort g_causes. */
2134 n
= uu_list_numnodes(g_causes
);
2140 ary
= calloc(n
, sizeof (*ary
));
2145 for (spp
= uu_list_first(g_causes
);
2147 spp
= uu_list_next(g_causes
, spp
)) {
2148 (void) determine_impact(spp
->svcp
);
2149 ary
[i
++] = spp
->svcp
;
2152 qsort(ary
, n
, sizeof (*ary
), impact_compar
);
2154 /* Call print_service() for each service. */
2156 for (i
= 0; i
< n
; ++i
)
2157 print_service(ary
[i
], verbose
);