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 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright (c) 2015, Joyent, Inc. All rights reserved.
26 */
27
28 /*
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).
32 *
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
42 * dependent's list.
43 *
44 * Computing an impact list is more involved because the dependencies in the
45 * repository are unidirectional; it requires determining the causes of all
116 uu_panic("%s:%d: %s() failed with unknown error %d.\n", \
117 __FILE__, __LINE__, func, err);
118
119 typedef struct {
120 const char *svcname;
121 const char *instname;
122
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;
130
131 uint8_t enabled;
132 int temporary;
133 const char *restarter;
134 uu_list_t *dependencies; /* list of dependency_group's */
135
136 int active; /* In use? (cycle detection) */
137 int restarter_bad;
138 const char *summary;
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 */
143
144 uu_list_node_t node;
145 } inst_t;
146
147 typedef struct service {
148 const char *svcname;
149 uu_list_t *instances;
150 struct service *next;
151 } svc_t;
152
153 struct svcptr {
154 inst_t *svcp;
155 inst_t *next_hop;
386 max_scf_fmri_length + 1) < 0)
387 scfdie();
388
389 uu_list_node_init(d, &d->node, deps);
390 (void) uu_list_append(dg->entities, d);
391 }
392
393 uu_list_node_init(dg, &dg->node, depgroups);
394 r = uu_list_append(svcp->dependencies, dg);
395 assert(r == 0);
396 }
397
398 return (0);
399 }
400
401 static void
402 add_instance(const char *svcname, const char *instname, scf_instance_t *inst)
403 {
404 inst_t *instp;
405 svc_t *svcp;
406 int have_enabled = 0;
407 uint8_t i;
408 uint32_t h;
409 int r;
410
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)
414 break;
415 }
416
417 if (svcp == NULL) {
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)
422 uu_die(emsg_nomem);
423 svcp->next = services[h];
424 services[h] = svcp;
425 }
426
462 return;
463
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);
468 else
469 instp->aux_state = safe_strdup(AUX_STATE_INVALID);
470
471 (void) pg_get_single_val(g_pg, SCF_PROPERTY_START_METHOD_WAITSTATUS,
472 SCF_TYPE_INTEGER, &instp->start_method_waitstatus, 0, 0);
473
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);
478
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)
482 have_enabled = 1;
483 } else {
484 switch (scf_error()) {
485 case SCF_ERROR_NOT_FOUND:
486 break;
487
488 case SCF_ERROR_DELETED:
489 return;
490
491 default:
492 scfdie();
493 }
494 }
495
496 if (scf_instance_get_pg_composed(inst, NULL, SCF_PG_GENERAL, g_pg) !=
497 0) {
498 switch (scf_error()) {
499 case SCF_ERROR_DELETED:
500 case SCF_ERROR_NOT_FOUND:
501 return;
502
503 default:
504 scfdie();
505 }
506 }
507
508 if (pg_get_single_val(g_pg, SCF_PROPERTY_ENABLED, SCF_TYPE_BOOLEAN,
509 &i, 0, 0) != 0)
510 return;
511 if (!have_enabled) {
512 instp->enabled = i;
513 instp->temporary = 0;
514 } else {
515 instp->temporary = (instp->enabled != i);
516 }
517
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);
521 else
522 instp->restarter = SCF_SERVICE_STARTD;
523
524 if (strcmp(instp->state, SCF_STATE_STRING_OFFLINE) == 0 &&
525 load_dependencies(instp, inst) != 0)
526 return;
527
528 uu_list_node_init(instp, &instp->node, insts);
529 r = uu_list_append(svcp->instances, instp);
530 assert(r == 0);
531 }
532
533 static void
534 load_services(void)
535 {
536 scf_iter_t *siter, *iiter;
537 int r;
1719 goto diagcode;
1720
1721 default:
1722 bad_error("get_fmri", r);
1723 }
1724
1725 if (inst_running(rsp)) {
1726 (void) printf(gettext("Reason: Restarter %s "
1727 "has not initialized service state.\n"),
1728 svcp->restarter);
1729 dc = DC_UNINIT;
1730 } else {
1731 (void) printf(gettext(
1732 "Reason: Restarter %s is not running.\n"),
1733 svcp->restarter);
1734 dc = DC_RSTRDEAD;
1735 }
1736
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."));
1741 dc = DC_DISABLED;
1742 } else {
1743 (void) puts(gettext("Reason: "
1744 "Temporarily disabled by an administrator."));
1745 dc = DC_TEMPDISABLED;
1746 }
1747
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."));
1752 dc = DC_ADMINMAINT;
1753 } else if (strcmp(svcp->aux_state, "dependency_cycle") == 0) {
1754 (void) puts(gettext(
1755 "Reason: Completes a dependency cycle."));
1756 dc = DC_DEPCYCLE;
1757 } else if (strcmp(svcp->aux_state, "fault_threshold_reached") ==
1758 0) {
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);
|
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 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2020 Joyent, Inc.
26 */
27
28 /*
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).
32 *
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
42 * dependent's list.
43 *
44 * Computing an impact list is more involved because the dependencies in the
45 * repository are unidirectional; it requires determining the causes of all
116 uu_panic("%s:%d: %s() failed with unknown error %d.\n", \
117 __FILE__, __LINE__, func, err);
118
119 typedef struct {
120 const char *svcname;
121 const char *instname;
122
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;
130
131 uint8_t enabled;
132 int temporary;
133 const char *restarter;
134 uu_list_t *dependencies; /* list of dependency_group's */
135
136 char comment[SCF_COMMENT_MAX_LENGTH];
137
138 int active; /* In use? (cycle detection) */
139 int restarter_bad;
140 const char *summary;
141 uu_list_t *baddeps; /* list of dependency's */
142 uu_list_t *causes; /* list of svcptrs */
143 uu_list_t *impact_dependents; /* list of svcptrs */
144 uu_list_t *impact; /* list of svcptrs */
145
146 uu_list_node_t node;
147 } inst_t;
148
149 typedef struct service {
150 const char *svcname;
151 uu_list_t *instances;
152 struct service *next;
153 } svc_t;
154
155 struct svcptr {
156 inst_t *svcp;
157 inst_t *next_hop;
388 max_scf_fmri_length + 1) < 0)
389 scfdie();
390
391 uu_list_node_init(d, &d->node, deps);
392 (void) uu_list_append(dg->entities, d);
393 }
394
395 uu_list_node_init(dg, &dg->node, depgroups);
396 r = uu_list_append(svcp->dependencies, dg);
397 assert(r == 0);
398 }
399
400 return (0);
401 }
402
403 static void
404 add_instance(const char *svcname, const char *instname, scf_instance_t *inst)
405 {
406 inst_t *instp;
407 svc_t *svcp;
408 int ovr_set = 0;
409 uint8_t i;
410 uint32_t h;
411 int r;
412
413 h = hash_name(svcname) & SVC_HASH_MASK;
414 for (svcp = services[h]; svcp != NULL; svcp = svcp->next) {
415 if (strcmp(svcp->svcname, svcname) == 0)
416 break;
417 }
418
419 if (svcp == NULL) {
420 svcp = safe_malloc(sizeof (*svcp));
421 svcp->svcname = safe_strdup(svcname);
422 svcp->instances = uu_list_create(insts, svcp, UU_LIST_DEBUG);
423 if (svcp->instances == NULL)
424 uu_die(emsg_nomem);
425 svcp->next = services[h];
426 services[h] = svcp;
427 }
428
464 return;
465
466 /* restarter may not set aux_state, allow to continue in that case */
467 if (pg_get_single_val(g_pg, SCF_PROPERTY_AUX_STATE, SCF_TYPE_ASTRING,
468 g_fmri, g_fmri_sz, 0) == 0)
469 instp->aux_state = safe_strdup(g_fmri);
470 else
471 instp->aux_state = safe_strdup(AUX_STATE_INVALID);
472
473 (void) pg_get_single_val(g_pg, SCF_PROPERTY_START_METHOD_WAITSTATUS,
474 SCF_TYPE_INTEGER, &instp->start_method_waitstatus, 0, 0);
475
476 /* Get the optional auxiliary_fmri */
477 if (pg_get_single_val(g_pg, SCF_PROPERTY_AUX_FMRI, SCF_TYPE_ASTRING,
478 g_fmri, g_fmri_sz, 0) == 0)
479 instp->aux_fmri = safe_strdup(g_fmri);
480
481 if (scf_instance_get_pg(inst, SCF_PG_GENERAL_OVR, g_pg) == 0) {
482 if (pg_get_single_val(g_pg, SCF_PROPERTY_ENABLED,
483 SCF_TYPE_BOOLEAN, &instp->enabled, 0, 0) == 0)
484 ovr_set = 1;
485 (void) pg_get_single_val(g_pg, SCF_PROPERTY_COMMENT,
486 SCF_TYPE_ASTRING, instp->comment,
487 sizeof (instp->comment), EMPTY_OK);
488 } else {
489 switch (scf_error()) {
490 case SCF_ERROR_NOT_FOUND:
491 break;
492
493 case SCF_ERROR_DELETED:
494 return;
495
496 default:
497 scfdie();
498 }
499 }
500
501 if (scf_instance_get_pg_composed(inst, NULL, SCF_PG_GENERAL, g_pg) !=
502 0) {
503 switch (scf_error()) {
504 case SCF_ERROR_DELETED:
505 case SCF_ERROR_NOT_FOUND:
506 return;
507
508 default:
509 scfdie();
510 }
511 }
512
513 if (pg_get_single_val(g_pg, SCF_PROPERTY_ENABLED, SCF_TYPE_BOOLEAN,
514 &i, 0, 0) != 0)
515 return;
516
517 if (ovr_set) {
518 instp->temporary = (instp->enabled != i);
519 } else {
520 instp->enabled = i;
521 instp->temporary = 0;
522 }
523
524 if (!instp->temporary) {
525 (void) pg_get_single_val(g_pg, SCF_PROPERTY_COMMENT,
526 SCF_TYPE_ASTRING, instp->comment,
527 sizeof (instp->comment), EMPTY_OK);
528 }
529
530 if (pg_get_single_val(g_pg, SCF_PROPERTY_RESTARTER, SCF_TYPE_ASTRING,
531 g_fmri, g_fmri_sz, 0) == 0)
532 instp->restarter = safe_strdup(g_fmri);
533 else
534 instp->restarter = SCF_SERVICE_STARTD;
535
536 if (strcmp(instp->state, SCF_STATE_STRING_OFFLINE) == 0 &&
537 load_dependencies(instp, inst) != 0)
538 return;
539
540 uu_list_node_init(instp, &instp->node, insts);
541 r = uu_list_append(svcp->instances, instp);
542 assert(r == 0);
543 }
544
545 static void
546 load_services(void)
547 {
548 scf_iter_t *siter, *iiter;
549 int r;
1731 goto diagcode;
1732
1733 default:
1734 bad_error("get_fmri", r);
1735 }
1736
1737 if (inst_running(rsp)) {
1738 (void) printf(gettext("Reason: Restarter %s "
1739 "has not initialized service state.\n"),
1740 svcp->restarter);
1741 dc = DC_UNINIT;
1742 } else {
1743 (void) printf(gettext(
1744 "Reason: Restarter %s is not running.\n"),
1745 svcp->restarter);
1746 dc = DC_RSTRDEAD;
1747 }
1748
1749 } else if (strcmp(svcp->state, SCF_STATE_STRING_DISABLED) == 0) {
1750 if (!svcp->temporary) {
1751 if (svcp->comment[0] != '\0') {
1752 (void) printf(gettext("Reason: Disabled by "
1753 "an administrator: %s\n"), svcp->comment);
1754 } else {
1755 (void) printf(gettext("Reason: Disabled by "
1756 "an administrator.\n"));
1757 }
1758 dc = DC_DISABLED;
1759 } else {
1760 if (svcp->comment[0] != '\0') {
1761 (void) printf(gettext("Reason: Temporarily "
1762 "disabled by an administrator: %s\n"),
1763 svcp->comment);
1764 } else {
1765 (void) printf(gettext("Reason: Temporarily "
1766 "disabled by an administrator.\n"));
1767 }
1768 dc = DC_TEMPDISABLED;
1769 }
1770
1771 } else if (strcmp(svcp->state, SCF_STATE_STRING_MAINT) == 0) {
1772 if (strcmp(svcp->aux_state, "administrative_request") == 0) {
1773 (void) puts(gettext("Reason: "
1774 "Maintenance requested by an administrator."));
1775 dc = DC_ADMINMAINT;
1776 } else if (strcmp(svcp->aux_state, "dependency_cycle") == 0) {
1777 (void) puts(gettext(
1778 "Reason: Completes a dependency cycle."));
1779 dc = DC_DEPCYCLE;
1780 } else if (strcmp(svcp->aux_state, "fault_threshold_reached") ==
1781 0) {
1782 print_method_failure(svcp, &dc);
1783 } else if (strcmp(svcp->aux_state, "service_request") == 0) {
1784 if (svcp->aux_fmri) {
1785 (void) printf(gettext("Reason: Maintenance "
1786 "requested by \"%s\"\n"), svcp->aux_fmri);
1787 print_aux_fmri_logs(svcp->aux_fmri);
|