Print this page
7711 SMF: Finish implementing support for degraded state


   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


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);
1182         }
1183 
1184         if (svcp->causes != NULL)
1185                 return (UU_WALK_NEXT);
1186 
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)
1190                 uu_die(emsg_nomem);
1191 
1192         if (inst_running(svcp) ||
1193             strcmp(svcp->state, SCF_STATE_STRING_UNINIT) == 0) {
1194                 /*
1195                  * If we're running, add a self-pointer in case we're
1196                  * excluding another service.
1197                  */
1198                 add_svcptr(svcp->causes, svcp);



1199                 return (UU_WALK_NEXT);
1200         }
1201 
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);
1206         }
1207 
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);
1212 
1213                 return (UU_WALK_NEXT);
1214         }
1215 
1216         if (strcmp(svcp->state, SCF_STATE_STRING_OFFLINE) != 0) {
1217                 (void) fprintf(stderr,
1218                     gettext("svc:/%s:%s has invalid state \"%s\".\n"),


1471                 ip->summary = gettext("is in an invalid state.");
1472         }
1473 }
1474 
1475 static void
1476 print_method_failure(const inst_t *ip, const char **dcp)
1477 {
1478         char buf[50];
1479         int stat = ip->start_method_waitstatus;
1480 
1481         if (stat != 0) {
1482                 if (WIFEXITED(stat)) {
1483                         if (WEXITSTATUS(stat) == SMF_EXIT_ERR_CONFIG) {
1484                                 (void) strlcpy(buf, gettext(
1485                                     "exited with $SMF_EXIT_ERR_CONFIG"),
1486                                     sizeof (buf));
1487                         } else if (WEXITSTATUS(stat) == SMF_EXIT_ERR_FATAL) {
1488                                 (void) strlcpy(buf, gettext(
1489                                     "exited with $SMF_EXIT_ERR_FATAL"),
1490                                     sizeof (buf));




1491                         } else {
1492                                 (void) snprintf(buf, sizeof (buf),
1493                                     gettext("exited with status %d"),
1494                                     WEXITSTATUS(stat));
1495                         }
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)),
1502                                             WTERMSIG(stat));
1503                                 else
1504                                         (void) snprintf(buf, sizeof (buf),
1505                                             gettext("dumped core signal %d"),
1506                                             WTERMSIG(stat));
1507                         } else {
1508                                 if (strsignal(WTERMSIG(stat)) != NULL) {
1509                                         (void) snprintf(buf, sizeof (buf),
1510                                             gettext("died on %s (%d)"),


1791                 }
1792 
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."));
1797                         dc = DC_STARTING;
1798                 } else if (strcmp(svcp->next_state, SCF_STATE_STRING_NONE) ==
1799                     0) {
1800                         print_dependency_reasons(svcp, verbose);
1801                         /* Function prints diagcodes. */
1802                         return;
1803                 } else {
1804                         (void) printf(gettext(
1805                             "Reason: Transitioning to state %s.\n"),
1806                             svcp->next_state);
1807                         dc = DC_TRANSITION;
1808                 }
1809 
1810         } else if (strcmp(svcp->state, SCF_STATE_STRING_DEGRADED) == 0) {
1811                 (void) puts(gettext("Reason: Degraded by an administrator."));


1812                 dc = DC_ADMINDEGR;















1813 
1814         } else {
1815                 (void) printf(gettext("Reason: Not in valid state (%s).\n"),
1816                     svcp->state);
1817                 dc = DC_INVALIDSTATE;
1818         }
1819 
1820 diagcode:
1821         if (g_msgbase != NULL)
1822                 (void) printf(gettext("   See: %s%s\n"), g_msgbase, dc);
1823 }
1824 
1825 static void
1826 print_manpage(int verbose)
1827 {
1828         static char *title = NULL;
1829         static char *section = NULL;
1830 
1831         if (title == NULL) {
1832                 title = safe_malloc(g_value_sz);
1833                 section = safe_malloc(g_value_sz);
1834         }
1835 
1836         if (pg_get_single_val(g_pg, SCF_PROPERTY_TM_TITLE, SCF_TYPE_ASTRING,
1837             (void *)title, g_value_sz, 0) != 0)
1838                 return;
1839 
1840         if (pg_get_single_val(g_pg, SCF_PROPERTY_TM_SECTION,
1841             SCF_TYPE_ASTRING, (void *)section, g_value_sz, 0) != 0)




   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  * Copyright 2017 RackTop Systems.
  27  */
  28 
  29 /*
  30  * Service state explanation.  For select services, display a description, the
  31  * state, and possibly why the service is in that state, what's causing it to
  32  * be in that state, and what other services it is keeping offline (impact).
  33  *
  34  * Explaining states other than offline is easy.  For maintenance and
  35  * degraded, we just use the auxiliary state.  For offline, we must determine
  36  * which dependencies are unsatisfied and recurse.  If a causal service is not
  37  * offline, then a svcptr to it is added to the offline service's causes list.
  38  * If a causal service is offline, then we recurse to determine its causes and
  39  * merge them into the causes list of the service in question (see
  40  * add_causes()).  Note that by adding a self-pointing svcptr to the causes
  41  * lists of services which are not offline or are offline for unknown reasons,
  42  * we can always merge the unsatisfied dependency's causes into the
  43  * dependent's list.
  44  *
  45  * Computing an impact list is more involved because the dependencies in the
  46  * repository are unidirectional; it requires determining the causes of all


1180                 (void) fprintf(stderr, gettext("Dependency cycle detected:\n"
1181                     "  svc:/%s:%s\n"), svcp->svcname, svcp->instname);
1182                 return ((int)canfailp != 0 ? UU_WALK_ERROR : UU_WALK_NEXT);
1183         }
1184 
1185         if (svcp->causes != NULL)
1186                 return (UU_WALK_NEXT);
1187 
1188         svcp->causes = uu_list_create(svcptrs, svcp, UU_LIST_DEBUG);
1189         svcp->baddeps = uu_list_create(deps, svcp, UU_LIST_DEBUG);
1190         if (svcp->causes == NULL || svcp->baddeps == NULL)
1191                 uu_die(emsg_nomem);
1192 
1193         if (inst_running(svcp) ||
1194             strcmp(svcp->state, SCF_STATE_STRING_UNINIT) == 0) {
1195                 /*
1196                  * If we're running, add a self-pointer in case we're
1197                  * excluding another service.
1198                  */
1199                 add_svcptr(svcp->causes, svcp);
1200                 if (strcmp(svcp->state, SCF_STATE_STRING_DEGRADED) == 0)
1201                         add_svcptr(g_causes, svcp);
1202 
1203                 return (UU_WALK_NEXT);
1204         }
1205 
1206         if (strcmp(svcp->state, SCF_STATE_STRING_MAINT) == 0) {
1207                 add_svcptr(svcp->causes, svcp);
1208                 add_svcptr(g_causes, svcp);
1209                 return (UU_WALK_NEXT);
1210         }
1211 
1212         if (strcmp(svcp->state, SCF_STATE_STRING_DISABLED) == 0) {
1213                 add_svcptr(svcp->causes, svcp);
1214                 if (svcp->enabled != 0)
1215                         add_svcptr(g_causes, svcp);
1216 
1217                 return (UU_WALK_NEXT);
1218         }
1219 
1220         if (strcmp(svcp->state, SCF_STATE_STRING_OFFLINE) != 0) {
1221                 (void) fprintf(stderr,
1222                     gettext("svc:/%s:%s has invalid state \"%s\".\n"),


1475                 ip->summary = gettext("is in an invalid state.");
1476         }
1477 }
1478 
1479 static void
1480 print_method_failure(const inst_t *ip, const char **dcp)
1481 {
1482         char buf[50];
1483         int stat = ip->start_method_waitstatus;
1484 
1485         if (stat != 0) {
1486                 if (WIFEXITED(stat)) {
1487                         if (WEXITSTATUS(stat) == SMF_EXIT_ERR_CONFIG) {
1488                                 (void) strlcpy(buf, gettext(
1489                                     "exited with $SMF_EXIT_ERR_CONFIG"),
1490                                     sizeof (buf));
1491                         } else if (WEXITSTATUS(stat) == SMF_EXIT_ERR_FATAL) {
1492                                 (void) strlcpy(buf, gettext(
1493                                     "exited with $SMF_EXIT_ERR_FATAL"),
1494                                     sizeof (buf));
1495                         } else if (WEXITSTATUS(stat) == SMF_EXIT_MON_DEGRADE) {
1496                                 (void) strlcpy(buf, gettext(
1497                                     "exited with $SMF_EXIT_MON_DEGRADE"),
1498                                     sizeof (buf));
1499                         } else {
1500                                 (void) snprintf(buf, sizeof (buf),
1501                                     gettext("exited with status %d"),
1502                                     WEXITSTATUS(stat));
1503                         }
1504                 } else if (WIFSIGNALED(stat)) {
1505                         if (WCOREDUMP(stat)) {
1506                                 if (strsignal(WTERMSIG(stat)) != NULL)
1507                                         (void) snprintf(buf, sizeof (buf),
1508                                             gettext("dumped core on %s (%d)"),
1509                                             strsignal(WTERMSIG(stat)),
1510                                             WTERMSIG(stat));
1511                                 else
1512                                         (void) snprintf(buf, sizeof (buf),
1513                                             gettext("dumped core signal %d"),
1514                                             WTERMSIG(stat));
1515                         } else {
1516                                 if (strsignal(WTERMSIG(stat)) != NULL) {
1517                                         (void) snprintf(buf, sizeof (buf),
1518                                             gettext("died on %s (%d)"),


1799                 }
1800 
1801         } else if (strcmp(svcp->state, SCF_STATE_STRING_OFFLINE) == 0) {
1802                 if (strcmp(svcp->next_state, SCF_STATE_STRING_ONLINE) == 0) {
1803                         (void) puts(gettext(
1804                             "Reason: Start method is running."));
1805                         dc = DC_STARTING;
1806                 } else if (strcmp(svcp->next_state, SCF_STATE_STRING_NONE) ==
1807                     0) {
1808                         print_dependency_reasons(svcp, verbose);
1809                         /* Function prints diagcodes. */
1810                         return;
1811                 } else {
1812                         (void) printf(gettext(
1813                             "Reason: Transitioning to state %s.\n"),
1814                             svcp->next_state);
1815                         dc = DC_TRANSITION;
1816                 }
1817 
1818         } else if (strcmp(svcp->state, SCF_STATE_STRING_DEGRADED) == 0) {
1819                 if (strcmp(svcp->aux_state, "administrative_request") == 0) {
1820                         (void) puts(gettext("Reason: Degraded by an "
1821                             "administrator."));
1822                         dc = DC_ADMINDEGR;
1823                 } else if (strcmp(svcp->aux_state, "service_request") == 0) {
1824                         if (svcp->aux_fmri) {
1825                                 (void) printf(gettext("Reason: Degraded by "
1826                                     "\"%s\"\n"), svcp->aux_fmri);
1827                                 print_aux_fmri_logs(svcp->aux_fmri);
1828                         } else {
1829                                 (void) puts(gettext("Reason: Degraded by "
1830                                     "another service."));
1831                         }
1832                 } else if (strcmp(svcp->aux_state, "method_failed") == 0) {
1833                         print_method_failure(svcp, &dc);
1834                 } else {
1835                         (void) puts(gettext("Reason: Unknown."));
1836                         dc = DC_UNKNOWN;
1837                 }
1838 
1839         } else {
1840                 (void) printf(gettext("Reason: Not in valid state (%s).\n"),
1841                     svcp->state);
1842                 dc = DC_INVALIDSTATE;
1843         }
1844 
1845 diagcode:
1846         if (g_msgbase != NULL && dc != NULL)
1847                 (void) printf(gettext("   See: %s%s\n"), g_msgbase, dc);
1848 }
1849 
1850 static void
1851 print_manpage(int verbose)
1852 {
1853         static char *title = NULL;
1854         static char *section = NULL;
1855 
1856         if (title == NULL) {
1857                 title = safe_malloc(g_value_sz);
1858                 section = safe_malloc(g_value_sz);
1859         }
1860 
1861         if (pg_get_single_val(g_pg, SCF_PROPERTY_TM_TITLE, SCF_TYPE_ASTRING,
1862             (void *)title, g_value_sz, 0) != 0)
1863                 return;
1864 
1865         if (pg_get_single_val(g_pg, SCF_PROPERTY_TM_SECTION,
1866             SCF_TYPE_ASTRING, (void *)section, g_value_sz, 0) != 0)