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  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  *
  25  * Copyright 2018 Joyent, Inc.
  26  */
  27 
  28 #include <stdlib.h>
  29 #include <libscf.h>
  30 #include <string.h>
  31 #include "nscd_switch.h"
  32 #include "nscd_log.h"
  33 #include "nscd_door.h"
  34 
  35 extern int      _whoami;
  36 
  37 /*
  38  * Service states monitored by nscd. Protected by
  39  * readers/writer lock nscd_smf_service_state_lock
  40  */
  41 nscd_smf_state_t *nscd_smf_service_state;
  42 static rwlock_t nscd_smf_service_state_lock = DEFAULTRWLOCK;
  43 /*
  44  * init service state table
  45  */
  46 nscd_rc_t
  47 _nscd_alloc_service_state_table()
  48 {
  49         int i;
  50 
  51         nscd_smf_service_state = calloc(NSCD_NUM_SMF_FMRI,
  52             sizeof (nscd_smf_state_t));
  53 
  54         if (nscd_smf_service_state == NULL)
  55                 return (NSCD_NO_MEMORY);
  56 
  57         for (i = 1; i < NSCD_NUM_SMF_FMRI; i++)
  58                 NSCD_SMF_SVC_STATE(i) = NSCD_SVC_STATE_UNINITED;
  59 
  60         return (NSCD_SUCCESS);
  61 }
  62 
  63 static int
  64 query_smf_state(int srci)
  65 {
  66 
  67         int     ret = NSCD_SVC_STATE_UNINITED;
  68         char    *state = NULL;
  69         char    *me = "query_smf_state";
  70 
  71         state = smf_get_state(NSCD_SMF_SVC_FMRI(srci));
  72         if (state == NULL)
  73                 return (ret);
  74 
  75         _NSCD_LOG(NSCD_LOG_SMF_MONITOR, NSCD_LOG_LEVEL_DEBUG)
  76                 (me, "%s -- %s\n", state, NSCD_SMF_SVC_FMRI(srci));
  77 
  78         (void) rw_wrlock(&nscd_smf_service_state_lock);
  79 
  80         if (nscd_smf_service_state[srci].src_name == NULL)
  81                 nscd_smf_service_state[srci].src_name =
  82                     NSCD_NSW_SRC_NAME(srci);
  83 
  84         if (strcmp(state, SCF_STATE_STRING_UNINIT) == 0)
  85                 NSCD_SMF_SVC_STATE(srci) = SCF_STATE_UNINIT;
  86         else if (strcmp(state, SCF_STATE_STRING_MAINT) == 0)
  87                 NSCD_SMF_SVC_STATE(srci) = SCF_STATE_MAINT;
  88         else if (strcmp(state, SCF_STATE_STRING_OFFLINE) == 0)
  89                 NSCD_SMF_SVC_STATE(srci) = SCF_STATE_OFFLINE;
  90         else if (strcmp(state, SCF_STATE_STRING_DISABLED) == 0)
  91                 NSCD_SMF_SVC_STATE(srci) = SCF_STATE_DISABLED;
  92         else if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0)
  93                 NSCD_SMF_SVC_STATE(srci) = SCF_STATE_ONLINE;
  94         else if (strcmp(state, SCF_STATE_STRING_DEGRADED) == 0)
  95                 NSCD_SMF_SVC_STATE(srci) = SCF_STATE_DEGRADED;
  96 
  97         ret = NSCD_SMF_SVC_STATE(srci);
  98         (void) rw_unlock(&nscd_smf_service_state_lock);
  99 
 100         free(state);
 101         return (ret);
 102 }
 103 
 104 /* ARGSUSED */
 105 static void *
 106 set_smf_state(void *arg)
 107 {
 108 
 109         int     i;
 110         int     st;
 111 
 112         (void) thr_setname(thr_self(), "set_smf_state");
 113 
 114         /*
 115          * the forker nscd needs not monitor the state
 116          * of the client services
 117          */
 118         if (_whoami == NSCD_FORKER)
 119                 thr_exit(0);
 120 
 121         /*CONSTCOND*/
 122         while (1) {
 123 
 124                 /* skip the first service which is nscd */
 125                 for (i = 1; i < NSCD_NUM_SMF_FMRI; i++) {
 126                         st = query_smf_state(i);
 127                         if (st == NSCD_SVC_STATE_UNINITED)
 128                                 break;
 129                 }
 130 
 131                 (void) sleep(NSCD_SW_CFG_G.check_smf_state_interval_g);
 132         }
 133         /* NOTREACHED */
 134         /*LINTED E_FUNC_HAS_NO_RETURN_STMT*/
 135 }
 136 
 137 nscd_rc_t
 138 _nscd_init_smf_monitor() {
 139 
 140         int     errnum;
 141         char    *me = "_nscd_init_smf_monitor";
 142 
 143         _NSCD_LOG(NSCD_LOG_SMF_MONITOR, NSCD_LOG_LEVEL_DEBUG)
 144         (me, "initializing the smf monitor\n");
 145 
 146         /*
 147          * start a thread to check the state of the client services
 148          */
 149         if (thr_create(NULL, NULL, set_smf_state,
 150                 NULL, THR_DETACHED, NULL) != 0) {
 151                 errnum = errno;
 152                 _NSCD_LOG(NSCD_LOG_SMF_MONITOR, NSCD_LOG_LEVEL_ERROR)
 153                 (me, "thr_create: %s\n", strerror(errnum));
 154                 return (NSCD_THREAD_CREATE_ERROR);
 155         }
 156 
 157         return (NSCD_SUCCESS);
 158 }
 159 
 160 int
 161 _nscd_get_smf_state(int srci, int dbi, int recheck)
 162 {
 163         int     s;
 164         char    *n;
 165 
 166         n = NSCD_NSW_SRC_NAME(srci);
 167 
 168         /* the files, compat, and dns backends are always available */
 169         if ((*n == 'f' || *n == 'c' || *n == 'd' || *n == 'a') &&
 170             (strcmp(NSCD_NSW_SRC_NAME(srci), "files") == 0 ||
 171             strcmp(NSCD_NSW_SRC_NAME(srci), "compat") == 0 ||
 172             strcmp(NSCD_NSW_SRC_NAME(srci), "ad") == 0 ||
 173             strcmp(NSCD_NSW_SRC_NAME(srci), "dns") == 0)) {
 174                 return (SCF_STATE_ONLINE);
 175         }
 176 
 177         /*
 178          * for the printer database and user backend, treat the
 179          * backend as a unsupported one, as nscd can not access
 180          * the home directory of the user
 181          */
 182         if (*n == 'u' && strcmp(NSCD_NSW_SRC_NAME(srci), "user") == 0) {
 183                 if (strcmp(NSCD_NSW_DB_NAME(dbi), NSS_DBNAM_PRINTERS) == 0)
 184                         return (NSCD_SVC_STATE_UNSUPPORTED_SRC);
 185                 else
 186                         return (SCF_STATE_ONLINE);
 187         }
 188 
 189         /*
 190          * Foreign backend is not supported by nscd unless
 191          * the backend supports the nss2 interface (global
 192          * symbol _nss_<backname name>_version is present),
 193          * tell the switch engine to return NSS_TRYLOCAL
 194          * if needed via rc NSCD_SVC_STATE_FOREIGN_SRC.
 195          */
 196         if (srci >= _nscd_cfg_num_nsw_src)
 197                 return (NSCD_SVC_STATE_FOREIGN_SRC);
 198 
 199         if (recheck == 1)
 200                 return (query_smf_state(srci));
 201 
 202         (void) rw_rdlock(&nscd_smf_service_state_lock);
 203         s = NSCD_SMF_SVC_STATE(srci);
 204         (void) rw_unlock(&nscd_smf_service_state_lock);
 205 
 206         /*
 207          * if the state has been queried at least once but is
 208          * still not online, query one more time
 209          */
 210         if (s != NSCD_SVC_STATE_UNINITED && s < SCF_STATE_ONLINE)
 211                 s = query_smf_state(srci);
 212 
 213         return (s);
 214 }