KHMEXP khm_int32 KHMAPI kmm_get_module_config(wchar_t * module, khm_int32 flags, khm_handle * result) { khm_handle csmodules; khm_handle csmodule; khm_int32 rv; if(!module || wcschr(module, L'/') || wcschr(module, L'\\')) return KHM_ERROR_INVALID_PARAM; if(KHM_FAILED(kmm_get_modules_config(flags, &csmodules))) return KHM_ERROR_UNKNOWN; rv = khc_open_space(csmodules, module, flags, &csmodule); *result = csmodule; khc_close_space(csmodules); return rv; }
KHMEXP khm_int32 KHMAPI kmm_load_default_modules(void) { khm_handle csm = NULL; khm_handle cs_mod = NULL; khm_int32 rv; wchar_t buf[KMM_MAXCCH_NAME]; khm_size s; rv = kmm_get_modules_config(0, &csm); if(KHM_FAILED(rv)) return rv; _begin_task(KHERR_CF_TRANSITIVE); _report_mr0(KHERR_NONE, MSG_LOAD_DEFAULT); _describe(); kmmint_add_to_module_queue(); while(KHM_SUCCEEDED(khc_enum_subspaces(csm, cs_mod, &cs_mod))) { s = sizeof(buf); if (KHM_FAILED(khc_get_config_space_name(cs_mod, buf, &s))) continue; /* check for schema subspace. This is not an actual module. */ if (!wcscmp(buf, L"_Schema")) continue; kmm_load_module(buf, 0, NULL); } kmmint_remove_from_module_queue(); if(csm) khc_close_space(csm); _end_task(); return rv; }
/*! \internal \brief Initialize a module \a m is not in the linked list yet. \note Should only be called from the context of the registrar thread. */ void kmmint_init_module(kmm_module_i * m) { HMODULE hm; init_module_t p_init_module; kmm_plugin_i * pi; khm_int32 rv; khm_handle csp_mod = NULL; khm_handle csp_mods = NULL; khm_size sz; khm_int32 i; /* error condition handling */ BOOL exit_module = FALSE; BOOL release_module = TRUE; BOOL record_failure = FALSE; /* failure handling */ khm_int32 max_fail_count = 0; khm_int64 fail_reset_time = 0; _begin_task(0); _report_mr1(KHERR_NONE, MSG_INIT_MODULE, _cstr(m->name)); _describe(); kmm_hold_module(kmm_handle_from_module(m)); if(KHM_FAILED(kmm_get_modules_config(0, &csp_mods))) { _report_mr0(KHERR_ERROR, MSG_IM_GET_CONFIG); _location(L"kmm_get_modules_config()"); m->state = KMM_MODULE_STATE_FAIL_UNKNOWN; goto _exit; } khc_read_int32(csp_mods, L"ModuleMaxFailureCount", &max_fail_count); khc_read_int64(csp_mods, L"ModuleFailureCountResetTime", &fail_reset_time); /* If the module is not in the pre-init state, we can't initialize it. */ if(m->state != KMM_MODULE_STATE_PREINIT) { _report_mr1(KHERR_INFO, MSG_IM_NOT_PREINIT, _int32(m->state)); goto _exit; } if(KHM_FAILED(kmm_get_module_config(m->name, 0, &csp_mod))) { _report_mr0(KHERR_ERROR, MSG_IM_NOT_REGISTERED); m->state = KMM_MODULE_STATE_FAIL_NOT_REGISTERED; goto _exit; } if(KHM_SUCCEEDED(khc_read_int32(csp_mod, L"Disabled", &i)) && i) { _report_mr0(KHERR_INFO, MSG_IM_DISABLED); m->state = KMM_MODULE_STATE_FAIL_DISABLED; goto _exit; } if(KHM_SUCCEEDED(khc_read_int32(csp_mod, L"NoUnload", &i)) && i) { m->flags |= KMM_MODULE_FLAG_NOUNLOAD; } if(KHM_SUCCEEDED(khc_read_int32(csp_mod, L"FailureCount", &i))) { khm_int64 tm; khm_int64 ct; FILETIME fct; khm_int32 last_reason = 0; /* reset the failure count if the failure count reset time period has elapsed */ tm = 0; khc_read_int64(csp_mod, L"FailureTime", &tm); GetSystemTimeAsFileTime(&fct); ct = (FtToInt(&fct) - tm) / 10000000i64; if(tm > 0 && ct > fail_reset_time) { i = 0; khc_write_int32(csp_mod, L"FailureCount", 0); khc_write_int64(csp_mod, L"FailureTime", 0); } khc_read_int32(csp_mod, L"FailureReason", &last_reason); /* did we exceed the max failure count? However, we ignore the max failure count if the reason why it didn't load the last time was because the module wasn't found. */ if(i > max_fail_count && last_reason != KMM_MODULE_STATE_FAIL_NOT_FOUND) { /* failed too many times */ _report_mr0(KHERR_INFO, MSG_IM_MAX_FAIL); m->state = KMM_MODULE_STATE_FAIL_MAX_FAILURE; goto _exit; } } if(khc_read_string(csp_mod, L"ImagePath", NULL, &sz) == KHM_ERROR_TOO_LONG) { if(m->path) PFREE(m->path); m->path = PMALLOC(sz); khc_read_string(csp_mod, L"ImagePath", m->path, &sz); } else { _report_mr0(KHERR_ERROR, MSG_IM_NOT_REGISTERED); m->state = KMM_MODULE_STATE_FAIL_NOT_REGISTERED; goto _exit; } rv = kmmint_read_module_info(m); if (KHM_FAILED(rv)) { if (rv == KHM_ERROR_INCOMPATIBLE) { _report_mr0(KHERR_ERROR, MSG_IM_INCOMPATIBLE); m->state = KMM_MODULE_STATE_FAIL_INCOMPAT; } else if (rv == KHM_ERROR_NOT_FOUND) { _report_mr1(KHERR_ERROR, MSG_IM_NOT_FOUND, _dupstr(m->path)); m->state = KMM_MODULE_STATE_FAIL_NOT_FOUND; } else { _report_mr0(KHERR_ERROR, MSG_IM_INVALID_MODULE); m->state = KMM_MODULE_STATE_FAIL_INV_MODULE; } goto _exit; } /* check again */ if(m->state != KMM_MODULE_STATE_PREINIT) { _report_mr0(KHERR_ERROR, MSG_IM_NOT_PREINIT); goto _exit; } /* from this point on, we must record any failure codes */ record_failure = TRUE; hm = LoadLibrary(m->path); if(!hm) { m->h_module = NULL; m->state = KMM_MODULE_STATE_FAIL_NOT_FOUND; _report_mr1(KHERR_ERROR, MSG_IM_NOT_FOUND, _dupstr(m->path)); goto _exit; } /* from this point on, we need to discard the module through exit_module */ ResetEvent(evt_exit); kmm_active_modules++; release_module = FALSE; exit_module = TRUE; m->flags |= KMM_MODULE_FLAG_LOADED; m->h_module = hm; /* TODO: check signatures */ p_init_module = (init_module_t) GetProcAddress(hm, EXP_INIT_MODULE); if(!p_init_module) { _report_mr1(KHERR_ERROR, MSG_IM_NO_ENTRY, _cstr(EXP_INIT_MODULE)); m->state = KMM_MODULE_STATE_FAIL_INVALID; goto _exit; } m->state = KMM_MODULE_STATE_INIT; /* call init_module() */ rv = (*p_init_module)(kmm_handle_from_module(m)); m->flags |= KMM_MODULE_FLAG_INITP; if(KHM_FAILED(rv)) { _report_mr1(KHERR_ERROR, MSG_IM_INIT_FAIL, _int32(rv)); m->state = KMM_MODULE_STATE_FAIL_LOAD; goto _exit; } if(!m->plugins) { _report_mr0(KHERR_ERROR, MSG_IM_NO_PLUGINS); m->state = KMM_MODULE_STATE_FAIL_NO_PLUGINS; record_failure = FALSE; goto _exit; } m->state = KMM_MODULE_STATE_INITPLUG; do { LPOP(&(m->plugins), &pi); if(pi) { pi->flags &= ~KMM_PLUGIN_FLAG_IN_MODLIST; kmmint_init_plugin(pi); /* release the hold obtained in kmm_provide_plugin() */ kmm_release_plugin(kmm_handle_from_plugin(pi)); } } while(pi); if(!m->plugin_count) { /* We don't want to report this case. This usually means that the plugins that were provided by the module were disabled. */ #ifdef REPORT_EMPTY_MODULES _report_mr0(KHERR_ERROR, MSG_IM_NO_PLUGINS); m->state = KMM_MODULE_STATE_FAIL_NO_PLUGINS; #endif record_failure = FALSE; goto _exit; } m->state = KMM_MODULE_STATE_RUNNING; exit_module = FALSE; record_failure = FALSE; _exit: if(csp_mod) { if(record_failure) { FILETIME fct; i = 0; khc_read_int32(csp_mod, L"FailureCount", &i); i++; khc_write_int32(csp_mod, L"FailureCount", i); if(i==1) { /* first fault */ GetSystemTimeAsFileTime(&fct); khc_write_int64(csp_mod, L"FailureTime", FtToInt(&fct)); } khc_write_int32(csp_mod, L"FailureReason", m->state); } khc_close_space(csp_mod); } if(csp_mods) khc_close_space(csp_mods); _report_mr2(KHERR_INFO, MSG_IM_MOD_STATE, _dupstr(m->name), _int32(m->state)); kmmint_remove_from_module_queue(); /* if something went wrong after init_module was called on the module code, we need to call exit_module */ if(exit_module) kmmint_exit_module(m); if(release_module) kmm_release_module(kmm_handle_from_module(m)); if (kherr_is_error()) { kherr_context * c; kherr_event * err_e = NULL; kherr_event * warn_e = NULL; kherr_event * e; c = kherr_peek_context(); err_e = kherr_get_err_event(c); for(e = kherr_get_first_event(c); e; e = kherr_get_next_event(e)) { if (e != err_e && e->severity == KHERR_WARNING) { warn_e = e; break; } } kherr_evaluate_event(err_e); if (warn_e) kherr_evaluate_event(warn_e); kherr_clear_error(); e = kherr_report(KHERR_ERROR, (wchar_t *) MSG_IMERR_TITLE, KHERR_FACILITY, NULL, err_e->long_desc, ((warn_e)? (wchar_t *)MSG_IMERR_SUGGEST: NULL), KHERR_FACILITY_ID, KHERR_SUGGEST_NONE, _cstr(m->name), ((warn_e)? _cstr(warn_e->long_desc):_vnull()), _vnull(),_vnull(), KHERR_RF_MSG_SHORT_DESC | ((warn_e)? KHERR_RF_MSG_SUGGEST: 0), KHERR_HMODULE); kherr_evaluate_event(e); kherr_release_context(c); } _end_task(); }