/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Disk & Indicator Monitor configuration file support routines */ #include #include #include #include #include #include #include #include #include #include "disk_monitor.h" #include "util.h" #include "topo_gather.h" extern log_class_t g_verbose; const char * hotplug_state_string(hotplug_state_t state) { switch (state & ~HPS_FAULTED) { default: case HPS_UNKNOWN: return ("Unknown"); case HPS_ABSENT: return ("Absent"); case HPS_PRESENT: return ("Present"); case HPS_CONFIGURED: return ("Configured"); case HPS_UNCONFIGURED: return ("Unconfigured"); } } void conf_error_msg(conf_err_t err, char *buf, int buflen, void *arg) { switch (err) { case E_MULTIPLE_IND_LISTS_DEFINED: (void) snprintf(buf, buflen, "Multiple Indicator lists " "defined"); break; case E_MULTIPLE_INDRULE_LISTS_DEFINED: (void) snprintf(buf, buflen, "Multiple Indicator rule lists " "defined"); break; case E_INVALID_STATE_CHANGE: (void) snprintf(buf, buflen, "Invalid state change"); break; case E_IND_MULTIPLY_DEFINED: (void) snprintf(buf, buflen, "Multiple Indicator definitions (name & state) detected"); break; case E_IND_ACTION_REDUNDANT: (void) snprintf(buf, buflen, "Redundant Indicator actions " "specified"); break; case E_IND_ACTION_CONFLICT: (void) snprintf(buf, buflen, "Indicator action conflict (+/- " "same Indicator) found"); break; case E_IND_MISSING_FAULT_ON: (void) snprintf(buf, buflen, "Missing declaration of `+" INDICATOR_FAULT_IDENTIFIER "'"); break; case E_IND_MISSING_FAULT_OFF: (void) snprintf(buf, buflen, "Missing declaration of `-" INDICATOR_FAULT_IDENTIFIER "'"); break; case E_INDRULE_REFERENCES_NONEXISTENT_IND_ACTION: (void) snprintf(buf, buflen, "`%c%s': Undefined Indicator in " BAY_IND_ACTION " property", (((ind_action_t *)arg)->ind_state == INDICATOR_ON) ? '+' : '-', ((ind_action_t *)arg)->ind_name); break; case E_DUPLICATE_STATE_TRANSITION: (void) snprintf(buf, buflen, "Duplicate state transition " "(%s -> %s)", hotplug_state_string(((state_transition_t *)arg)->begin), hotplug_state_string(((state_transition_t *)arg)->end)); break; default: (void) snprintf(buf, buflen, "Unknown error"); break; } } static int string_to_integer(const char *prop, int *value) { long val; errno = 0; val = strtol(prop, NULL, 0); if (val == 0 && errno != 0) return (-1); else if (val > INT_MAX || val < INT_MIN) { errno = ERANGE; return (-1); } if (value != NULL) *value = (int)val; return (0); } const char * dm_prop_lookup(nvlist_t *props, const char *prop_name) { char *str; if (nvlist_lookup_string(props, prop_name, &str) == 0) return ((const char *)str); else return (NULL); } int dm_prop_lookup_int(nvlist_t *props, const char *prop_name, int *value) { const char *prop = dm_prop_lookup(props, prop_name); if (prop == NULL) return (-1); return (string_to_integer(prop, value)); } nvlist_t * namevalpr_to_nvlist(namevalpr_t *nvprp) { nvlist_t *nvlp = NULL; if (nvlist_alloc(&nvlp, NV_UNIQUE_NAME, 0) != 0) { return (NULL); } if (nvlist_add_string(nvlp, nvprp->name, nvprp->value) != 0) { nvlist_free(nvlp); return (NULL); } return (nvlp); } indicator_t * new_indicator(ind_state_t lstate, char *namep, char *actionp) { indicator_t *newindicator = (indicator_t *)dmalloc(sizeof (indicator_t)); newindicator->ind_state = lstate; newindicator->ind_name = namep ? dstrdup(namep) : NULL; newindicator->ind_instr_spec = actionp ? dstrdup(actionp) : NULL; newindicator->next = NULL; return (newindicator); } void link_indicator(indicator_t **first, indicator_t *to_add) { indicator_t *travptr; dm_assert(first != NULL); if (*first == NULL) *first = to_add; else { travptr = *first; while (travptr->next != NULL) { travptr = travptr->next; } travptr->next = to_add; } } void ind_free(indicator_t *indp) { indicator_t *nextp; while (indp != NULL) { nextp = indp->next; if (indp->ind_name) dstrfree(indp->ind_name); if (indp->ind_instr_spec) dstrfree(indp->ind_instr_spec); dfree(indp, sizeof (indicator_t)); indp = nextp; } } ind_action_t * new_indaction(ind_state_t state, char *namep) { ind_action_t *lap = (ind_action_t *)dmalloc(sizeof (ind_action_t)); lap->ind_state = state; lap->ind_name = namep ? dstrdup(namep) : NULL; lap->next = NULL; return (lap); } void link_indaction(ind_action_t **first, ind_action_t *to_add) { ind_action_t *travptr; dm_assert(first != NULL); if (*first == NULL) *first = to_add; else { travptr = *first; while (travptr->next != NULL) { travptr = travptr->next; } travptr->next = to_add; } } void indaction_free(ind_action_t *lap) { ind_action_t *nextp; /* Free the whole list */ while (lap != NULL) { nextp = lap->next; if (lap->ind_name) dstrfree(lap->ind_name); dfree(lap, sizeof (ind_action_t)); lap = nextp; } } indrule_t * new_indrule(state_transition_t *st, ind_action_t *actionp) { indrule_t *lrp = (indrule_t *)dmalloc(sizeof (indrule_t)); if (st != NULL) lrp->strans = *st; lrp->action_list = actionp; lrp->next = NULL; return (lrp); } void link_indrule(indrule_t **first, indrule_t *to_add) { indrule_t *travptr; dm_assert(first != NULL); if (*first == NULL) *first = to_add; else { travptr = *first; while (travptr->next != NULL) { travptr = travptr->next; } travptr->next = to_add; } } void indrule_free(indrule_t *lrp) { indrule_t *nextp; /* Free the whole list */ while (lrp != NULL) { nextp = lrp->next; if (lrp->action_list) indaction_free(lrp->action_list); dfree(lrp, sizeof (indrule_t)); lrp = nextp; } } dm_fru_t * new_dmfru(char *manu, char *modl, char *firmrev, char *serno, uint64_t capa) { dm_fru_t *frup = (dm_fru_t *)dzmalloc(sizeof (dm_fru_t)); bcopy(manu, frup->manuf, MIN(sizeof (frup->manuf), strlen(manu) + 1)); bcopy(modl, frup->model, MIN(sizeof (frup->model), strlen(modl) + 1)); bcopy(firmrev, frup->rev, MIN(sizeof (frup->rev), strlen(firmrev) + 1)); bcopy(serno, frup->serial, MIN(sizeof (frup->serial), strlen(serno) + 1)); frup->size_in_bytes = capa; return (frup); } void dmfru_free(dm_fru_t *frup) { dfree(frup, sizeof (dm_fru_t)); } diskmon_t * new_diskmon(nvlist_t *app_props, indicator_t *indp, indrule_t *indrp, nvlist_t *nvlp) { diskmon_t *dmp = (diskmon_t *)dmalloc(sizeof (diskmon_t)); if (nvlp != NULL) dmp->props = nvlp; else (void) nvlist_alloc(&dmp->props, NV_UNIQUE_NAME, 0); if (app_props) dmp->app_props = app_props; else (void) nvlist_alloc(&dmp->app_props, NV_UNIQUE_NAME, 0); dmp->ind_list = indp; dmp->indrule_list = indrp; dm_assert(pthread_mutex_init(&dmp->manager_mutex, NULL) == 0); dmp->state = HPS_UNKNOWN; dmp->initial_configuration = B_TRUE; dm_assert(pthread_mutex_init(&dmp->fault_indicator_mutex, NULL) == 0); dmp->fault_indicator_state = INDICATOR_UNKNOWN; dmp->configured_yet = B_FALSE; dmp->state_change_count = 0; dm_assert(pthread_mutex_init(&dmp->fru_mutex, NULL) == 0); dmp->frup = NULL; dmp->next = NULL; return (dmp); } void diskmon_free(diskmon_t *dmp) { diskmon_t *nextp; /* Free the whole list */ while (dmp != NULL) { nextp = dmp->next; nvlist_free(dmp->props); if (dmp->location) dstrfree(dmp->location); if (dmp->ind_list) ind_free(dmp->ind_list); if (dmp->indrule_list) indrule_free(dmp->indrule_list); nvlist_free(dmp->app_props); if (dmp->frup) dmfru_free(dmp->frup); dfree(dmp, sizeof (diskmon_t)); dmp = nextp; } } static cfgdata_t * new_cfgdata(namevalpr_t *nvp, diskmon_t *dmp) { cfgdata_t *cdp = (cfgdata_t *)dzmalloc(sizeof (cfgdata_t)); if (nvp != NULL) cdp->props = namevalpr_to_nvlist(nvp); else if (nvlist_alloc(&cdp->props, NV_UNIQUE_NAME, 0) != 0) { return (NULL); } if (dmp != NULL) cdp->disk_list = dmp; return (cdp); } static void cfgdata_add_namevalpr(cfgdata_t *cfgp, namevalpr_t *nvp) { if (cfgp->props == NULL) { (void) nvlist_alloc(&cfgp->props, NV_UNIQUE_NAME, 0); } (void) nvlist_add_string(cfgp->props, nvp->name, nvp->value); } void cfgdata_add_diskmon(cfgdata_t *cfgp, diskmon_t *dmp) { if (cfgp->disk_list == NULL) { cfgp->disk_list = dmp; } else { diskmon_t *disklist = cfgp->disk_list; while (disklist->next != NULL) disklist = disklist->next; disklist->next = dmp; } } static void cfgdata_free(cfgdata_t *cdp) { nvlist_free(cdp->props); diskmon_free(cdp->disk_list); dfree(cdp, sizeof (cfgdata_t)); } conf_err_t check_indactions(ind_action_t *indrp) { char *buf; conf_err_t rv = E_NO_ERROR; nvlist_t *nvp = NULL; int len; (void) nvlist_alloc(&nvp, NV_UNIQUE_NAME, 0); /* * Check indicator actions for conflicts */ while (indrp != NULL && rv == E_NO_ERROR) { len = strlen(indrp->ind_name) + 2; buf = dmalloc(len); (void) snprintf(buf, len, "%c%s", indrp->ind_state == INDICATOR_ON ? '+' : '-', indrp->ind_name); switch (nvlist_lookup_boolean(nvp, buf)) { case ENOENT: (void) nvlist_add_boolean(nvp, buf); break; case 0: rv = E_IND_ACTION_REDUNDANT; break; default: break; } /* Look for the opposite action. If found, that's an error */ (void) snprintf(buf, len, "%c%s", indrp->ind_state == INDICATOR_ON ? '-' : '+', indrp->ind_name); switch (nvlist_lookup_boolean(nvp, buf)) { case ENOENT: break; case 0: rv = E_IND_ACTION_CONFLICT; break; default: break; } dfree(buf, len); indrp = indrp->next; } nvlist_free(nvp); return (rv); } conf_err_t check_inds(indicator_t *indp) { char *buf; conf_err_t rv = E_NO_ERROR; nvlist_t *nvp = NULL; int len; boolean_t fault_on = B_FALSE, fault_off = B_FALSE; (void) nvlist_alloc(&nvp, NV_UNIQUE_NAME, 0); /* * Check inds for multiple definitions (same identifier or same action) */ while (indp != NULL && rv == E_NO_ERROR) { len = strlen(indp->ind_name) + 2; buf = dmalloc(len); (void) snprintf(buf, len, "%c%s", indp->ind_state == INDICATOR_ON ? '+' : '-', indp->ind_name); /* Keep track of the +/-FAULT for checking later */ if (strcasecmp(buf, "+" INDICATOR_FAULT_IDENTIFIER) == 0) fault_on = B_TRUE; else if (strcasecmp(buf, "-" INDICATOR_FAULT_IDENTIFIER) == 0) fault_off = B_TRUE; switch (nvlist_lookup_boolean(nvp, buf)) { case ENOENT: (void) nvlist_add_boolean(nvp, buf); break; case 0: rv = E_IND_MULTIPLY_DEFINED; break; default: break; } dfree(buf, len); indp = indp->next; } /* * Make sure we have a -FAULT and +FAULT */ if (!fault_on) rv = E_IND_MISSING_FAULT_ON; else if (!fault_off) rv = E_IND_MISSING_FAULT_OFF; nvlist_free(nvp); return (rv); } conf_err_t check_indrules(indrule_t *indrp, state_transition_t **offender) { char buf[32]; conf_err_t rv = E_NO_ERROR; nvlist_t *nvp = NULL; /* * Ensure that no two rules have the same state transitions. */ (void) nvlist_alloc(&nvp, NV_UNIQUE_NAME, 0); while (indrp != NULL && rv == E_NO_ERROR) { (void) snprintf(buf, sizeof (buf), "%d-%d", (int)indrp->strans.begin, (int)indrp->strans.end); switch (nvlist_lookup_boolean(nvp, buf)) { case 0: *offender = &indrp->strans; rv = E_DUPLICATE_STATE_TRANSITION; break; case ENOENT: (void) nvlist_add_boolean(nvp, buf); break; default: break; } indrp = indrp->next; } nvlist_free(nvp); return (rv); } conf_err_t check_consistent_ind_indrules(indicator_t *indp, indrule_t *indrp, ind_action_t **offender) { char *buf; conf_err_t rv = E_NO_ERROR; nvlist_t *nvp = NULL; ind_action_t *alp; int len; /* * Ensure that every indicator action referenced in each ruleset * exists in the indicator list given. */ (void) nvlist_alloc(&nvp, NV_UNIQUE_NAME, 0); while (indp != NULL) { len = strlen(indp->ind_name) + 2; buf = dmalloc(len); (void) snprintf(buf, len, "%c%s", indp->ind_state == INDICATOR_ON ? '+' : '-', indp->ind_name); (void) nvlist_add_boolean(nvp, buf); dfree(buf, len); indp = indp->next; } while (indrp != NULL && rv == E_NO_ERROR) { alp = indrp->action_list; while (alp != NULL && rv == E_NO_ERROR) { len = strlen(alp->ind_name) + 2; buf = dmalloc(len); (void) snprintf(buf, len, "%c%s", alp->ind_state == INDICATOR_ON ? '+' : '-', alp->ind_name); switch (nvlist_lookup_boolean(nvp, buf)) { case 0: /* Normal case */ break; case ENOENT: *offender = alp; rv = E_INDRULE_REFERENCES_NONEXISTENT_IND_ACTION; break; default: break; } dfree(buf, len); alp = alp->next; } indrp = indrp->next; } nvlist_free(nvp); return (rv); } conf_err_t check_state_transition(hotplug_state_t s1, hotplug_state_t s2) { /* * The following are valid transitions: * * HPS_ABSENT -> HPS_PRESENT * HPS_ABSENT -> HPS_CONFIGURED * HPS_PRESENT -> HPS_CONFIGURED * HPS_PRESENT -> HPS_ABSENT * HPS_CONFIGURED -> HPS_UNCONFIGURED * HPS_CONFIGURED -> HPS_ABSENT * HPS_UNCONFIGURED -> HPS_ABSENT * HPS_UNCONFIGURED -> HPS_CONFIGURED * */ if (s1 == HPS_ABSENT && s2 != HPS_PRESENT && s2 != HPS_CONFIGURED) return (E_INVALID_STATE_CHANGE); else if (s1 == HPS_PRESENT && (s2 != HPS_CONFIGURED && s2 != HPS_ABSENT)) return (E_INVALID_STATE_CHANGE); else if (s1 == HPS_CONFIGURED && (s2 != HPS_UNCONFIGURED && s2 != HPS_ABSENT)) return (E_INVALID_STATE_CHANGE); else if (s1 == HPS_UNCONFIGURED && (s2 != HPS_ABSENT && s2 != HPS_CONFIGURED)) return (E_INVALID_STATE_CHANGE); else return (E_NO_ERROR); } static void print_inds(indicator_t *indp, FILE *fp, char *prefix) { char plusminus; (void) fprintf(fp, "%sindicators {\n", prefix); while (indp != NULL) { plusminus = (indp->ind_state == INDICATOR_ON) ? '+' : '-'; (void) fprintf(fp, "%s\t%c%s = \"%s\"\n", prefix, plusminus, indp->ind_name, indp->ind_instr_spec); indp = indp->next; } (void) fprintf(fp, "%s}\n", prefix); } static void print_indrules(indrule_t *lrp, FILE *fp, char *prefix) { char plusminus; ind_action_t *lap; (void) fprintf(fp, "%sindicator_rules {\n", prefix); while (lrp != NULL) { (void) fprintf(fp, "%s\t%12s -> %12s\t{ ", prefix, hotplug_state_string(lrp->strans.begin), hotplug_state_string(lrp->strans.end)); lap = lrp->action_list; while (lap != NULL) { plusminus = (lap->ind_state == INDICATOR_ON) ? '+' : '-'; (void) fprintf(fp, "%c%s", plusminus, lap->ind_name); lap = lap->next; if (lap != NULL) (void) fprintf(fp, ", "); } (void) fprintf(fp, " }\n"); lrp = lrp->next; } (void) fprintf(fp, "%s}\n", prefix); } static void print_props(nvlist_t *nvlp, FILE *fp, char *prefix) { nvpair_t *nvp = nvlist_next_nvpair(nvlp, NULL); char *name, *str; while (nvp != NULL) { dm_assert(nvpair_type(nvp) == DATA_TYPE_STRING); name = nvpair_name(nvp); (void) nvlist_lookup_string(nvlp, name, &str); (void) fprintf(fp, "%s%s = \"%s\"\n", prefix, name, str); nvp = nvlist_next_nvpair(nvlp, nvp); } } static void print_ap(nvlist_t *dpp, FILE *fp, char *prefix) { int len = strlen(prefix) + 2; char *buf = dmalloc(len); (void) snprintf(buf, len, "%s\t", prefix); (void) fprintf(fp, "%sap_props {\n", prefix); print_props(dpp, fp, buf); (void) fprintf(fp, "%s}\n", prefix); dfree(buf, len); } static void print_disks(diskmon_t *dmp, FILE *fp, char *prefix) { int len = strlen(prefix) + 2; char *buf = dmalloc(len); (void) snprintf(buf, len, "%s\t", prefix); while (dmp != NULL) { (void) fprintf(fp, "%sdisk \"%s\" {\n", prefix, dmp->location); if (dmp->props) { print_props(dmp->props, fp, buf); } if (dmp->app_props) { print_ap(dmp->app_props, fp, buf); } (void) fprintf(fp, "%s\n", prefix); print_inds(dmp->ind_list, fp, buf); (void) fprintf(fp, "%s\n", prefix); print_indrules(dmp->indrule_list, fp, buf); (void) fprintf(fp, "%s}\n", prefix); if (dmp->next != NULL) (void) fprintf(fp, "%s\n", prefix); dmp = dmp->next; } dfree(buf, len); } static void print_cfgdata(cfgdata_t *cfgp, FILE *fp, char *prefix) { /* First, print the properties, then the disks */ print_props(cfgp->props, fp, prefix); (void) fprintf(fp, "%s\n", prefix); print_disks(cfgp->disk_list, fp, prefix); } int config_init(void) { if (init_configuration_from_topo() == 0) { config_data = new_cfgdata(NULL, NULL); return (0); } return (-1); } int config_get(fmd_hdl_t *hdl, const fmd_prop_t *fmd_props) { int err, i = 0; char *str = NULL; namevalpr_t nvp; uint64_t u64; boolean_t intfound = B_FALSE, strfound = B_FALSE; #define INT64_BUF_LEN 128 char buf[INT64_BUF_LEN]; u64 = fmd_prop_get_int32(hdl, GLOBAL_PROP_LOG_LEVEL); g_verbose = (int)u64; err = update_configuration_from_topo(hdl, NULL); /* Pull in the properties from the DE configuration file */ while (fmd_props[i].fmdp_name != NULL) { nvp.name = (char *)fmd_props[i].fmdp_name; switch (fmd_props[i].fmdp_type) { case FMD_TYPE_UINT32: case FMD_TYPE_INT32: intfound = B_TRUE; u64 = fmd_prop_get_int32(hdl, fmd_props[i].fmdp_name); break; case FMD_TYPE_UINT64: case FMD_TYPE_INT64: intfound = B_TRUE; u64 = fmd_prop_get_int64(hdl, fmd_props[i].fmdp_name); break; case FMD_TYPE_STRING: strfound = B_TRUE; str = fmd_prop_get_string(hdl, fmd_props[i].fmdp_name); break; } if (intfound) { (void) snprintf(buf, INT64_BUF_LEN, "0x%llx", u64); nvp.value = buf; intfound = B_FALSE; } else if (strfound) { nvp.value = str; } log_msg(MM_CONF, "Adding property `%s' with value `%s'\n", nvp.name, nvp.value); cfgdata_add_namevalpr(config_data, &nvp); if (strfound) { strfound = B_FALSE; fmd_prop_free_string(hdl, str); } i++; } if ((g_verbose & (MM_CONF|MM_OTHER)) == (MM_CONF|MM_OTHER)) print_cfgdata(config_data, stderr, ""); return (err); } void config_fini(void) { fini_configuration_from_topo(); cfgdata_free(config_data); config_data = NULL; } nvlist_t * dm_global_proplist(void) { return (config_data->props); }