![]() |
Icinga-core 1.4.0
next gen monitoring
|
00001 /***************************************************************************** 00002 * 00003 * NEBMODS.C - Event Broker Module Functions 00004 * 00005 * Copyright (c) 2002-2008 Ethan Galstad (egalstad@nagios.org) 00006 * Copyright (c) 2009-2011 Nagios Core Development Team and Community Contributors 00007 * Copyright (c) 2009-2011 Icinga Development Team (http://www.icinga.org) 00008 * 00009 * License: 00010 * 00011 * This program is free software; you can redistribute it and/or modify 00012 * it under the terms of the GNU General Public License version 2 as 00013 * published by the Free Software Foundation. 00014 * 00015 * This program is distributed in the hope that it will be useful, 00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 * GNU General Public License for more details. 00019 * 00020 * You should have received a copy of the GNU General Public License 00021 * along with this program; if not, write to the Free Software 00022 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00023 * 00024 *****************************************************************************/ 00025 00026 #include "../include/config.h" 00027 #include "../include/common.h" 00028 #include "../include/nebmods.h" 00029 #include "../include/neberrors.h" 00030 #include "../include/icinga.h" 00031 00032 00033 #ifdef USE_EVENT_BROKER 00034 00035 00036 nebmodule *neb_module_list=NULL; 00037 nebcallback **neb_callback_list=NULL; 00038 00039 extern char *temp_path; 00040 00041 00042 /*#define DEBUG*/ 00043 00044 00045 /****************************************************************************/ 00046 /****************************************************************************/ 00047 /* INITIALIZATION/CLEANUP FUNCTIONS */ 00048 /****************************************************************************/ 00049 /****************************************************************************/ 00050 00051 /* initialize module routines */ 00052 int neb_init_modules(void){ 00053 #ifdef USE_LTDL 00054 int result=OK; 00055 #endif 00056 00057 /* initialize library */ 00058 #ifdef USE_LTDL 00059 result=lt_dlinit(); 00060 if(result) 00061 return ERROR; 00062 #endif 00063 00064 return OK; 00065 } 00066 00067 00068 /* deinitialize module routines */ 00069 int neb_deinit_modules(void){ 00070 #ifdef USE_LTDL 00071 int result=OK; 00072 #endif 00073 00074 /* deinitialize library */ 00075 #ifdef USE_LTDL 00076 result=lt_dlexit(); 00077 if(result) 00078 return ERROR; 00079 #endif 00080 00081 return OK; 00082 } 00083 00084 00085 00086 /* add a new module to module list */ 00087 int neb_add_module(char *filename,char *args,int should_be_loaded){ 00088 nebmodule *new_module=NULL; 00089 int x=OK; 00090 00091 if(filename==NULL) 00092 return ERROR; 00093 00094 /* allocate memory */ 00095 new_module=(nebmodule *)malloc(sizeof(nebmodule)); 00096 if(new_module==NULL) 00097 return ERROR; 00098 00099 /* initialize vars */ 00100 new_module->filename=(char *)strdup(filename); 00101 new_module->args=(args==NULL)?NULL:(char *)strdup(args); 00102 new_module->should_be_loaded=should_be_loaded; 00103 new_module->is_currently_loaded=FALSE; 00104 for(x=0;x<NEBMODULE_MODINFO_NUMITEMS;x++) 00105 new_module->info[x]=NULL; 00106 new_module->module_handle=NULL; 00107 new_module->init_func=NULL; 00108 new_module->deinit_func=NULL; 00109 #ifdef HAVE_PTHREAD_H 00110 new_module->thread_id=(pthread_t)NULL; 00111 #endif 00112 00113 /* add module to head of list */ 00114 new_module->next=neb_module_list; 00115 neb_module_list=new_module; 00116 00117 log_debug_info(DEBUGL_EVENTBROKER,0,"Added module: name='%s', args='%s', should_be_loaded='%d'\n",filename,args,should_be_loaded); 00118 00119 return OK; 00120 } 00121 00122 00123 /* free memory allocated to module list */ 00124 int neb_free_module_list(void){ 00125 nebmodule *temp_module=NULL; 00126 nebmodule *next_module=NULL; 00127 int x=OK; 00128 00129 for(temp_module=neb_module_list;temp_module;){ 00130 next_module=temp_module->next; 00131 my_free(temp_module->filename); 00132 my_free(temp_module->args); 00133 for(x=0;x<NEBMODULE_MODINFO_NUMITEMS;x++) 00134 my_free(temp_module->info[x]); 00135 my_free(temp_module); 00136 temp_module=next_module; 00137 } 00138 00139 neb_module_list=NULL; 00140 00141 return OK; 00142 } 00143 00144 00145 00146 /****************************************************************************/ 00147 /****************************************************************************/ 00148 /* LOAD/UNLOAD FUNCTIONS */ 00149 /****************************************************************************/ 00150 /****************************************************************************/ 00151 00152 00153 /* load all modules */ 00154 int neb_load_all_modules(void){ 00155 nebmodule *temp_module=NULL; 00156 int result=OK; 00157 00158 for(temp_module=neb_module_list;temp_module;temp_module=temp_module->next){ 00159 result=neb_load_module(temp_module); 00160 } 00161 00162 return OK; 00163 } 00164 00165 #ifndef PATH_MAX 00166 # define PATH_MAX 4096 00167 #endif 00168 /* load a particular module */ 00169 int neb_load_module(nebmodule *mod){ 00170 int (*initfunc)(int,char *,void *); 00171 int *module_version_ptr=NULL; 00172 int result=OK; 00173 00174 00175 if(mod==NULL || mod->filename==NULL) 00176 return ERROR; 00177 00178 /* don't reopen the module */ 00179 if(mod->is_currently_loaded==TRUE) 00180 return OK; 00181 00182 /* don't load modules unless they should be loaded */ 00183 if(mod->should_be_loaded==FALSE) 00184 return ERROR; 00185 00186 /********** 00187 Using dlopen() is great, but a real danger as-is. The problem with loaded modules is that if you overwrite the original file (e.g. using 'mv'), 00188 you do not alter the inode of the original file. Since the original file/module is memory-mapped in some fashion, Icinga will segfault the next 00189 time an event broker call is directed to one of the module's callback functions. This is extremely problematic when it comes to upgrading NEB 00190 modules while Icinga is running. A workaround is to (1) 'mv' the original/loaded module file to another name (on the same filesystem) 00191 and (2) copy the new module file to the location of the original one (using the original filename). In this scenario, dlopen() will keep referencing 00192 the original file/inode for callbacks. This is not an ideal solution. A better one is to delete the module file once it is loaded by dlopen(). 00193 This prevents other processed from unintentially overwriting the original file, which would cause Icinga to crash. However, if we delete the file 00194 before anyone else can muck with it, things should be good. 'lsof' shows that a deleted file is still referenced by the kernel and callback 00195 functions continue to work once the module has been loaded. Long story, but this took quite a while to figure out, as there isn't much 00196 of anything I could find on the subject other than some sketchy info on similar problems on HP-UX. Hopefully this will save future coders some time. 00197 So... the trick is to (1) copy the module to a temp file, (2) dlopen() the temp file, and (3) immediately delete the temp file. 00198 ************/ 00199 00200 /* 2010-01-05 MF: Patch taken from OMD into Icinga Core 00201 OMD: Do not make a copy of the module, but directly load it. This prevents problems with a tmpfs which 00202 is mounted as user. OMD users surely have no problems with modules overwritten by 'cp in runtime. Anyway, 00203 the usual way to install files is 'install', which removes and recreates the file (just as tar, rpm and 00204 many other installation-tools do). */ 00205 00206 /* load the module (use the temp copy we just made) */ 00207 #ifdef USE_LTDL 00208 mod->module_handle=lt_dlopen(mod->filename); 00209 #else 00210 mod->module_handle=(void *)dlopen(mod->filename,RTLD_NOW|RTLD_GLOBAL); 00211 #endif 00212 if(mod->module_handle==NULL){ 00213 00214 #ifdef USE_LTDL 00215 logit(NSLOG_RUNTIME_ERROR,FALSE,"Error: Could not load module '%s' -> %s\n",mod->filename,lt_dlerror()); 00216 #else 00217 logit(NSLOG_RUNTIME_ERROR,FALSE,"Error: Could not load module '%s' -> %s\n",mod->filename,dlerror()); 00218 #endif 00219 00220 return ERROR; 00221 } 00222 00223 /* find module API version */ 00224 #ifdef USE_LTDL 00225 module_version_ptr=(int *)lt_dlsym(mod->module_handle,"__neb_api_version"); 00226 #else 00227 module_version_ptr=(int *)dlsym(mod->module_handle,"__neb_api_version"); 00228 #endif 00229 00230 /* mark the module as being loaded */ 00231 mod->is_currently_loaded=TRUE; 00232 00233 /* check the module API version */ 00234 if(module_version_ptr==NULL || ((*module_version_ptr)!=CURRENT_NEB_API_VERSION)){ 00235 00236 logit(NSLOG_RUNTIME_ERROR,FALSE,"Error: Module '%s' is using an old or unspecified version of the event broker API. Module will be unloaded.\n",mod->filename); 00237 00238 neb_unload_module(mod,NEBMODULE_FORCE_UNLOAD,NEBMODULE_ERROR_API_VERSION); 00239 00240 return ERROR; 00241 } 00242 00243 /* locate the initialization function */ 00244 #ifdef USE_LTDL 00245 mod->init_func=lt_dlsym(mod->module_handle,"nebmodule_init"); 00246 #else 00247 mod->init_func=(void *)dlsym(mod->module_handle,"nebmodule_init"); 00248 #endif 00249 00250 /* if the init function could not be located, unload the module */ 00251 if(mod->init_func==NULL){ 00252 00253 logit(NSLOG_RUNTIME_ERROR,FALSE,"Error: Could not locate nebmodule_init() in module '%s'. Module will be unloaded.\n",mod->filename); 00254 00255 neb_unload_module(mod,NEBMODULE_FORCE_UNLOAD,NEBMODULE_ERROR_NO_INIT); 00256 00257 return ERROR; 00258 } 00259 00260 /* run the module's init function */ 00261 initfunc=mod->init_func; 00262 result=(*initfunc)(NEBMODULE_NORMAL_LOAD,mod->args,mod->module_handle); 00263 00264 /* if the init function returned an error, unload the module */ 00265 if(result!=OK){ 00266 00267 logit(NSLOG_RUNTIME_ERROR,FALSE,"Error: Function nebmodule_init() in module '%s' returned an error. Module will be unloaded.\n",mod->filename); 00268 00269 neb_unload_module(mod,NEBMODULE_FORCE_UNLOAD,NEBMODULE_ERROR_BAD_INIT); 00270 00271 return ERROR; 00272 } 00273 00274 logit(NSLOG_INFO_MESSAGE,FALSE,"Event broker module '%s' initialized successfully.\n",mod->filename); 00275 00276 /* locate the de-initialization function (may or may not be present) */ 00277 #ifdef USE_LTDL 00278 mod->deinit_func=lt_dlsym(mod->module_handle,"nebmodule_deinit"); 00279 #else 00280 mod->deinit_func=(void *)dlsym(mod->module_handle,"nebmodule_deinit"); 00281 #endif 00282 00283 log_debug_info(DEBUGL_EVENTBROKER,0,"Module '%s' loaded with return code of '%d'\n",mod->filename,result); 00284 if(mod->deinit_func!=NULL) 00285 log_debug_info(DEBUGL_EVENTBROKER,0,"nebmodule_deinit() found\n"); 00286 00287 return OK; 00288 } 00289 00290 00291 /* close (unload) all modules that are currently loaded */ 00292 int neb_unload_all_modules(int flags, int reason){ 00293 nebmodule *temp_module; 00294 00295 for(temp_module=neb_module_list;temp_module;temp_module=temp_module->next){ 00296 00297 /* skip modules that are not loaded */ 00298 if(temp_module->is_currently_loaded==FALSE) 00299 continue; 00300 00301 /* skip modules that do not have a valid handle */ 00302 if(temp_module->module_handle==NULL) 00303 continue; 00304 00305 /* close/unload the module */ 00306 neb_unload_module(temp_module,flags,reason); 00307 } 00308 00309 return OK; 00310 } 00311 00312 00313 00314 /* close (unload) a particular module */ 00315 int neb_unload_module(nebmodule *mod, int flags, int reason){ 00316 int (*deinitfunc)(int,int); 00317 int result=OK; 00318 00319 if(mod==NULL) 00320 return ERROR; 00321 00322 log_debug_info(DEBUGL_EVENTBROKER,0,"Attempting to unload module '%s': flags=%d, reason=%d\n",mod->filename,flags,reason); 00323 00324 /* call the de-initialization function if available (and the module was initialized) */ 00325 if(mod->deinit_func && reason!=NEBMODULE_ERROR_BAD_INIT){ 00326 00327 deinitfunc=mod->deinit_func; 00328 00329 /* module can opt to not be unloaded */ 00330 result=(*deinitfunc)(flags,reason); 00331 00332 /* if module doesn't want to be unloaded, exit with error (unless its being forced) */ 00333 if(result!=OK && !(flags & NEBMODULE_FORCE_UNLOAD)) 00334 return ERROR; 00335 } 00336 00337 /* deregister all of the module's callbacks */ 00338 neb_deregister_module_callbacks(mod); 00339 00340 /* unload the module */ 00341 #ifdef USE_LTDL 00342 result=lt_dlclose(mod->module_handle); 00343 #else 00344 result=dlclose(mod->module_handle); 00345 #endif 00346 00347 /* mark the module as being unloaded */ 00348 mod->is_currently_loaded=FALSE; 00349 00350 log_debug_info(DEBUGL_EVENTBROKER,0,"Module '%s' unloaded successfully.\n",mod->filename); 00351 00352 logit(NSLOG_INFO_MESSAGE,FALSE,"Event broker module '%s' deinitialized successfully.\n",mod->filename); 00353 00354 return OK; 00355 } 00356 00357 00358 00359 00360 /****************************************************************************/ 00361 /****************************************************************************/ 00362 /* INFO FUNCTIONS */ 00363 /****************************************************************************/ 00364 /****************************************************************************/ 00365 00366 /* sets module information */ 00367 int neb_set_module_info(void *handle, int type, char *data){ 00368 nebmodule *temp_module=NULL; 00369 00370 if(handle==NULL) 00371 return NEBERROR_NOMODULE; 00372 00373 /* check type */ 00374 if(type<0 || type>=NEBMODULE_MODINFO_NUMITEMS) 00375 return NEBERROR_MODINFOBOUNDS; 00376 00377 /* find the module */ 00378 for(temp_module=neb_module_list;temp_module!=NULL;temp_module=temp_module->next){ 00379 if((void *)temp_module->module_handle==(void *)handle) 00380 break; 00381 } 00382 if(temp_module==NULL) 00383 return NEBERROR_BADMODULEHANDLE; 00384 00385 /* free any previously allocated memory */ 00386 my_free(temp_module->info[type]); 00387 00388 /* allocate memory for the new data */ 00389 if((temp_module->info[type]=(char *)strdup(data))==NULL) 00390 return NEBERROR_NOMEM; 00391 00392 return OK; 00393 } 00394 00395 00396 00397 /****************************************************************************/ 00398 /****************************************************************************/ 00399 /* CALLBACK FUNCTIONS */ 00400 /****************************************************************************/ 00401 /****************************************************************************/ 00402 00403 /* allows a module to register a callback function */ 00404 int neb_register_callback(int callback_type, void *mod_handle, int priority, int (*callback_func)(int,void *)){ 00405 nebmodule *temp_module=NULL; 00406 nebcallback *new_callback=NULL; 00407 nebcallback *temp_callback=NULL; 00408 nebcallback *last_callback=NULL; 00409 00410 if(callback_func==NULL) 00411 return NEBERROR_NOCALLBACKFUNC; 00412 00413 if(neb_callback_list==NULL) 00414 return NEBERROR_NOCALLBACKLIST; 00415 00416 if(mod_handle==NULL) 00417 return NEBERROR_NOMODULEHANDLE; 00418 00419 /* make sure the callback type is within bounds */ 00420 if(callback_type<0 || callback_type>=NEBCALLBACK_NUMITEMS) 00421 return NEBERROR_CALLBACKBOUNDS; 00422 00423 /* make sure module handle is valid */ 00424 for(temp_module=neb_module_list;temp_module;temp_module=temp_module->next){ 00425 if((void *)temp_module->module_handle==(void *)mod_handle) 00426 break; 00427 } 00428 if(temp_module==NULL) 00429 return NEBERROR_BADMODULEHANDLE; 00430 00431 /* allocate memory */ 00432 new_callback=(nebcallback *)malloc(sizeof(nebcallback)); 00433 if(new_callback==NULL) 00434 return NEBERROR_NOMEM; 00435 00436 new_callback->priority=priority; 00437 new_callback->module_handle=(void *)mod_handle; 00438 new_callback->callback_func=(void *)callback_func; 00439 00440 /* add new function to callback list, sorted by priority (first come, first served for same priority) */ 00441 new_callback->next=NULL; 00442 if(neb_callback_list[callback_type]==NULL) 00443 neb_callback_list[callback_type]=new_callback; 00444 else{ 00445 last_callback=NULL; 00446 for(temp_callback=neb_callback_list[callback_type];temp_callback!=NULL;temp_callback=temp_callback->next){ 00447 if(temp_callback->priority>new_callback->priority) 00448 break; 00449 last_callback=temp_callback; 00450 } 00451 if(last_callback==NULL) 00452 neb_callback_list[callback_type]=new_callback; 00453 else{ 00454 if(temp_callback==NULL) 00455 last_callback->next=new_callback; 00456 else{ 00457 new_callback->next=temp_callback; 00458 last_callback->next=new_callback; 00459 } 00460 } 00461 } 00462 00463 return OK; 00464 } 00465 00466 00467 00468 /* dregisters all callback functions for a given module */ 00469 int neb_deregister_module_callbacks(nebmodule *mod){ 00470 nebcallback *temp_callback=NULL; 00471 nebcallback *next_callback=NULL; 00472 int callback_type=0; 00473 00474 if(mod==NULL) 00475 return NEBERROR_NOMODULE; 00476 00477 if(neb_callback_list==NULL) 00478 return OK; 00479 00480 for(callback_type=0;callback_type<NEBCALLBACK_NUMITEMS;callback_type++){ 00481 for(temp_callback=neb_callback_list[callback_type];temp_callback!=NULL;temp_callback=next_callback){ 00482 next_callback=temp_callback->next; 00483 if((void *)temp_callback->module_handle==(void *)mod->module_handle) 00484 neb_deregister_callback(callback_type,(int(*)(int,void*))temp_callback->callback_func); 00485 } 00486 00487 } 00488 00489 return OK; 00490 } 00491 00492 00493 /* allows a module to deregister a callback function */ 00494 int neb_deregister_callback(int callback_type, int (*callback_func)(int,void *)){ 00495 nebcallback *temp_callback=NULL; 00496 nebcallback *last_callback=NULL; 00497 nebcallback *next_callback=NULL; 00498 00499 if(callback_func==NULL) 00500 return NEBERROR_NOCALLBACKFUNC; 00501 00502 if(neb_callback_list==NULL) 00503 return NEBERROR_NOCALLBACKLIST; 00504 00505 /* make sure the callback type is within bounds */ 00506 if(callback_type<0 || callback_type>=NEBCALLBACK_NUMITEMS) 00507 return NEBERROR_CALLBACKBOUNDS; 00508 00509 /* find the callback to remove */ 00510 for(temp_callback=last_callback=neb_callback_list[callback_type];temp_callback!=NULL;temp_callback=next_callback){ 00511 next_callback=temp_callback->next; 00512 00513 /* we found it */ 00514 if(temp_callback->callback_func==(void *)callback_func) 00515 break; 00516 00517 last_callback=temp_callback; 00518 } 00519 00520 /* we couldn't find the callback */ 00521 if(temp_callback==NULL) 00522 return NEBERROR_CALLBACKNOTFOUND; 00523 00524 else{ 00525 /* only one item in the list */ 00526 if (temp_callback!=last_callback->next) 00527 neb_callback_list[callback_type]=NULL; 00528 else 00529 last_callback->next=next_callback; 00530 my_free(temp_callback); 00531 } 00532 00533 return OK; 00534 } 00535 00536 00537 00538 /* make callbacks to modules */ 00539 int neb_make_callbacks(int callback_type, void *data){ 00540 nebcallback *temp_callback=NULL, *next_callback=NULL; 00541 int (*callbackfunc)(int,void *); 00542 register int cbresult=0; 00543 int total_callbacks=0; 00544 00545 /* make sure callback list is initialized */ 00546 if(neb_callback_list==NULL) 00547 return ERROR; 00548 00549 /* make sure the callback type is within bounds */ 00550 if(callback_type<0 || callback_type>=NEBCALLBACK_NUMITEMS) 00551 return ERROR; 00552 00553 log_debug_info(DEBUGL_EVENTBROKER,1,"Making callbacks (type %d)...\n",callback_type); 00554 00555 /* make the callbacks... */ 00556 for(temp_callback=neb_callback_list[callback_type];temp_callback;temp_callback=next_callback){ 00557 /* Save temp_callback->next because if the callback function de-registers itself temp_callback's */ 00558 /* pointer isn't guaranteed to be usable anymore (neb_deregister_callback will free() it) */ 00559 next_callback=temp_callback->next; 00560 callbackfunc=temp_callback->callback_func; 00561 cbresult=callbackfunc(callback_type,data); 00562 temp_callback = next_callback; 00563 00564 total_callbacks++; 00565 log_debug_info(DEBUGL_EVENTBROKER,2,"Callback #%d (type %d) return code = %d\n",total_callbacks,callback_type,cbresult); 00566 00567 /* module wants to cancel callbacks to other modules (and potentially cancel the default Icinga handling of an event) */ 00568 if(cbresult==NEBERROR_CALLBACKCANCEL) 00569 break; 00570 00571 /* module wants to override default Icinga handling of an event */ 00572 /* not sure if we should bail out here just because one module wants to override things - what about other modules? EG 12/11/2006 */ 00573 else if(cbresult==NEBERROR_CALLBACKOVERRIDE) 00574 break; 00575 } 00576 00577 return cbresult; 00578 } 00579 00580 00581 00582 /* initialize callback list */ 00583 int neb_init_callback_list(void){ 00584 register int x=0; 00585 00586 /* allocate memory for the callback list */ 00587 neb_callback_list=(nebcallback **)malloc(NEBCALLBACK_NUMITEMS*sizeof(nebcallback *)); 00588 if(neb_callback_list==NULL) 00589 return ERROR; 00590 00591 /* initialize list pointers */ 00592 for(x=0;x<NEBCALLBACK_NUMITEMS;x++) 00593 neb_callback_list[x]=NULL; 00594 00595 return OK; 00596 } 00597 00598 00599 /* free memory allocated to callback list */ 00600 int neb_free_callback_list(void){ 00601 nebcallback *temp_callback=NULL; 00602 nebcallback *next_callback=NULL; 00603 register int x=0; 00604 00605 if(neb_callback_list==NULL) 00606 return OK; 00607 00608 for(x=0;x<NEBCALLBACK_NUMITEMS;x++){ 00609 00610 for(temp_callback=neb_callback_list[x];temp_callback!=NULL;temp_callback=next_callback){ 00611 next_callback=temp_callback->next; 00612 my_free(temp_callback); 00613 } 00614 00615 neb_callback_list[x]=NULL; 00616 } 00617 00618 my_free(neb_callback_list); 00619 00620 return OK; 00621 } 00622 00623 #endif