unrealircd- supernets unrealircd source & configuration |
git clone git://git.acid.vegas/unrealircd.git |
Log | Files | Refs | Archive | README | LICENSE |
modules.c (37877B)
1 /************************************************************************ 2 * UnrealIRCd - Unreal Internet Relay Chat Daemon - src/modules.c 3 * (C) 2001 Carsten Munk (Techie/Stskeeps) <stskeeps@tspre.org> 4 * 5 * See file AUTHORS in IRC package for additional names of 6 * the programmers. 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 1, or (at your option) 11 * any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 */ 22 23 #define UNREALCORE 24 #include "unrealircd.h" 25 #ifdef _WIN32 26 #define RTLD_NOW 0 27 #elif defined(HPUX) 28 #include <dl.h> 29 #define RTLD_NOW BIND_IMMEDIATE 30 #else 31 #include <dlfcn.h> 32 #endif 33 #ifndef RTLD_NOW 34 #define RTLD_NOW RTLD_LAZY 35 #endif 36 #include "modversion.h" 37 38 Hook *Hooks[MAXHOOKTYPES]; 39 Hooktype Hooktypes[MAXCUSTOMHOOKS]; 40 Callback *Callbacks[MAXCALLBACKS]; /* Callback objects for modules, used for rehashing etc (can be multiple) */ 41 Callback *RCallbacks[MAXCALLBACKS]; /* 'Real' callback function, used for callback function calls */ 42 MODVAR Module *Modules = NULL; 43 MODVAR Versionflag *Versionflags = NULL; 44 45 Module *Module_make(ModuleHeader *header, 46 #ifdef _WIN32 47 HMODULE mod 48 #else 49 void *mod 50 #endif 51 ); 52 53 #ifdef UNDERSCORE 54 /* dlsym for OpenBSD */ 55 void *obsd_dlsym(void *handle, const char *symbol) 56 { 57 size_t buflen = strlen(symbol) + 2; 58 char *obsdsymbol = safe_alloc(buflen); 59 void *symaddr = NULL; 60 61 if (obsdsymbol) 62 { 63 ircsnprintf(obsdsymbol, buflen, "_%s", symbol); 64 symaddr = dlsym(handle, obsdsymbol); 65 safe_free(obsdsymbol); 66 } 67 68 return symaddr; 69 } 70 #endif 71 72 void deletetmp(const char *path) 73 { 74 #ifndef NOREMOVETMP 75 if (!loop.config_test) 76 remove(path); 77 #endif 78 } 79 80 void DeleteTempModules(void) 81 { 82 char tempbuf[PATH_MAX+1]; 83 #ifndef _WIN32 84 DIR *fd = opendir(TMPDIR); 85 struct dirent *dir; 86 87 if (!fd) /* Ouch.. this is NOT good!! */ 88 { 89 config_error("Unable to open temp directory %s: %s, please create one with the appropriate permissions", 90 TMPDIR, strerror(errno)); 91 if (!loop.booted) 92 exit(7); 93 return; 94 } 95 96 while ((dir = readdir(fd))) 97 { 98 char *fname = dir->d_name; 99 if (!strcmp(fname, ".") || !strcmp(fname, "..")) 100 continue; 101 if (!strstr(fname, ".so") && !strstr(fname, ".conf") && 102 (strstr(fname, "core") || strstr(fname, "unrealircd_asan."))) 103 continue; /* core dump or ASan log */ 104 ircsnprintf(tempbuf, sizeof(tempbuf), "%s/%s", TMPDIR, fname); 105 deletetmp(tempbuf); 106 } 107 closedir(fd); 108 #else 109 WIN32_FIND_DATA hData; 110 HANDLE hFile; 111 112 snprintf(tempbuf, sizeof(tempbuf), "%s/*", TMPDIR); 113 114 hFile = FindFirstFile(tempbuf, &hData); 115 if (hFile != INVALID_HANDLE_VALUE) 116 { 117 if (strcmp(hData.cFileName, ".") || strcmp(hData.cFileName, "..")) 118 { 119 ircsnprintf(tempbuf, sizeof(tempbuf), "%s/%s", TMPDIR, hData.cFileName); 120 deletetmp(tempbuf); 121 } 122 } 123 while (FindNextFile(hFile, &hData)) 124 { 125 if (!strcmp(hData.cFileName, ".") || !strcmp(hData.cFileName, "..")) 126 continue; 127 ircsnprintf(tempbuf, sizeof(tempbuf), "%s/%s", TMPDIR, hData.cFileName); 128 deletetmp(tempbuf); 129 } 130 FindClose(hFile); 131 #endif 132 } 133 134 Module *Module_Find(const char *name) 135 { 136 Module *p; 137 138 for (p = Modules; p; p = p->next) 139 { 140 if (!(p->options & MOD_OPT_PERM) && 141 (!(p->flags & MODFLAG_TESTING) || (p->flags & MODFLAG_DELAYED))) 142 continue; 143 if (!strcmp(p->header->name, name)) 144 { 145 return (p); 146 } 147 } 148 return NULL; 149 150 } 151 152 int parse_modsys_version(const char *version) 153 { 154 if (!strcmp(version, "unrealircd-6")) 155 return 0x600000; 156 return 0; 157 } 158 159 void make_compiler_string(char *buf, size_t buflen, unsigned int ver) 160 { 161 unsigned int maj, min, plevel; 162 163 if (ver == 0) 164 { 165 strlcpy(buf, "0", buflen); 166 return; 167 } 168 169 maj = ver >> 16; 170 min = (ver >> 8) & 0xff; 171 plevel = ver & 0xff; 172 173 if (plevel == 0) 174 snprintf(buf, buflen, "%d.%d", maj, min); 175 else 176 snprintf(buf, buflen, "%d.%d.%d", maj, min, plevel); 177 } 178 179 /** Transform a loadmodule path like "third/la" to 180 * something like "/home/xyz/unrealircd/modules/third/la.so 181 * (and other tricks) 182 */ 183 const char *Module_TransformPath(const char *path_) 184 { 185 static char path[1024]; 186 187 /* Prefix the module path with MODULESDIR, unless it's an absolute path 188 * (we check for "/", "\" and things like "C:" to detect absolute paths). 189 */ 190 if ((*path_ != '/') && (*path_ != '\\') && !(*path_ && (path_[1] == ':'))) 191 { 192 snprintf(path, sizeof(path), "%s/%s", MODULESDIR, path_); 193 } else { 194 strlcpy(path, path_, sizeof(path)); 195 } 196 197 /* Auto-suffix .dll / .so */ 198 if (!strstr(path, MODULE_SUFFIX)) 199 strlcat(path, MODULE_SUFFIX, sizeof(path)); 200 201 return path; 202 } 203 204 /** This function is the inverse of Module_TransformPath() */ 205 const char *Module_GetRelPath(const char *fullpath) 206 { 207 static char buf[512]; 208 char prefix[512]; 209 const char *without_prefix = fullpath; 210 char *s; 211 212 /* Strip the prefix */ 213 snprintf(prefix, sizeof(prefix), "%s/", MODULESDIR); 214 if (!strncasecmp(fullpath, prefix, strlen(prefix))) 215 without_prefix += strlen(prefix); 216 strlcpy(buf, without_prefix, sizeof(buf)); 217 218 /* Strip the suffix */ 219 s = strstr(buf, MODULE_SUFFIX); 220 if (s) 221 *s = '\0'; 222 223 return buf; 224 } 225 226 /** Validate a modules' ModuleHeader. 227 * @returns Error message is returned, or NULL if everything is OK. 228 */ 229 static const char *validate_mod_header(const char *relpath, ModuleHeader *mod_header) 230 { 231 char *p; 232 static char buf[256]; 233 234 if (!mod_header->name || !mod_header->version || !mod_header->author || !mod_header->description) 235 return "NULL values encountered in Mod_Header struct members"; 236 237 /* Validate module name */ 238 if (strcmp(mod_header->name, relpath)) 239 { 240 snprintf(buf, sizeof(buf), "Module has path '%s' but uses name '%s' in MOD_HEADER. These should be the same!", 241 relpath, mod_header->name); 242 return buf; 243 } 244 /* This too, just to be sure.. we never ever want other characters 245 * than these, since it may break the S2S SMOD command or /MODULE 246 * output etc. 247 */ 248 for (p = mod_header->name; *p; p++) 249 if (!isalnum(*p) && !strchr("._-/", *p)) 250 return "ModuleHeader.name contains illegal characters (must be: a-zA-Z0-9._-/)"; 251 252 /* Validate version, even more strict */ 253 if (!isdigit(mod_header->version[0])) 254 return "ModuleHeader.version must start with a digit"; 255 for (p = mod_header->version; *p; p++) 256 if (!isalnum(*p) && !strchr("._-", *p)) 257 return "ModuleHeader.version contains illegal characters (must be: a-zA-Z0-9._-)"; 258 259 /* Author and description are not checked, has no constraints */ 260 261 return NULL; /* SUCCESS */ 262 } 263 264 int module_already_in_testing(const char *relpath) 265 { 266 Module *m; 267 for (m = Modules; m; m = m->next) 268 { 269 if (!(m->options & MOD_OPT_PERM) && 270 (!(m->flags & MODFLAG_TESTING) || (m->flags & MODFLAG_DELAYED))) 271 continue; 272 if (!strcmp(m->relpath, relpath)) 273 return 1; 274 } 275 return 0; 276 } 277 278 /* 279 * Returns an error if insucessful .. yes NULL is OK! 280 */ 281 const char *Module_Create(const char *path_) 282 { 283 #ifdef _WIN32 284 HMODULE Mod; 285 #else /* _WIN32 */ 286 void *Mod; 287 #endif /* _WIN32 */ 288 int (*Mod_Test)(); 289 int (*Mod_Init)(); 290 int (*Mod_Load)(); 291 int (*Mod_Unload)(); 292 char *Mod_Version; 293 unsigned int *compiler_version; 294 static char errorbuf[1024]; 295 const char *path, *relpath, *tmppath; 296 ModuleHeader *mod_header = NULL; 297 int ret = 0; 298 const char *reterr; 299 Module *mod = NULL, **Mod_Handle = NULL; 300 char *expectedmodversion = our_mod_version; 301 unsigned int expectedcompilerversion = our_compiler_version; 302 long modsys_ver = 0; 303 304 path = Module_TransformPath(path_); 305 306 relpath = Module_GetRelPath(path); 307 if (module_already_in_testing(relpath)) 308 return 0; 309 310 if (!file_exists(path)) 311 { 312 snprintf(errorbuf, sizeof(errorbuf), "Cannot open module file: %s", strerror(errno)); 313 return errorbuf; 314 } 315 316 if (loop.config_test) 317 { 318 /* For './unrealircd configtest' we don't have to do any copying and shit */ 319 tmppath = path; 320 } else { 321 tmppath = unreal_mktemp(TMPDIR, unreal_getmodfilename(path)); 322 if (!tmppath) 323 return "Unable to create temporary file!"; 324 325 /* We have to copy the module, because otherwise the dynamic loader 326 * will not load the new .so if we rehash while holding the original .so 327 * We used to hardlink here instead of copy, but then OpenBSD and Linux 328 * got smart and detected that, so now we always copy. 329 */ 330 ret = unreal_copyfileex(path, tmppath, 0); 331 if (!ret) 332 { 333 snprintf(errorbuf, sizeof(errorbuf), "Failed to copy module file."); 334 return errorbuf; 335 } 336 } 337 338 if ((Mod = irc_dlopen(tmppath, RTLD_NOW))) 339 { 340 /* We have engaged the borg cube. Scan for lifesigns. */ 341 irc_dlsym(Mod, "Mod_Version", Mod_Version); 342 if (Mod_Version && strcmp(Mod_Version, expectedmodversion)) 343 { 344 snprintf(errorbuf, sizeof(errorbuf), 345 "Module was compiled for '%s', we were configured for '%s'. SOLUTION: Recompile the module(s).", 346 Mod_Version, expectedmodversion); 347 irc_dlclose(Mod); 348 deletetmp(tmppath); 349 return errorbuf; 350 } 351 if (!Mod_Version) 352 { 353 snprintf(errorbuf, sizeof(errorbuf), 354 "Module is lacking Mod_Version. Perhaps a very old one you forgot to recompile?"); 355 irc_dlclose(Mod); 356 deletetmp(tmppath); 357 return errorbuf; 358 } 359 irc_dlsym(Mod, "compiler_version", compiler_version); 360 if (compiler_version && ( ((*compiler_version) & 0xffff00) != (expectedcompilerversion & 0xffff00) ) ) 361 { 362 char theyhad[64], wehave[64]; 363 make_compiler_string(theyhad, sizeof(theyhad), *compiler_version); 364 make_compiler_string(wehave, sizeof(wehave), expectedcompilerversion); 365 snprintf(errorbuf, sizeof(errorbuf), 366 "Module was compiled with GCC %s, core was compiled with GCC %s. SOLUTION: Recompile your UnrealIRCd and all its modules by doing a 'make clean; ./Config -quick && make'.", 367 theyhad, wehave); 368 irc_dlclose(Mod); 369 deletetmp(tmppath); 370 return errorbuf; 371 } 372 irc_dlsym(Mod, "Mod_Header", mod_header); 373 if (!mod_header) 374 { 375 irc_dlclose(Mod); 376 deletetmp(tmppath); 377 return ("Unable to locate Mod_Header"); 378 } 379 if (!mod_header->modversion) 380 { 381 irc_dlclose(Mod); 382 deletetmp(tmppath); 383 return ("Lacking mod_header->modversion"); 384 } 385 if (!(modsys_ver = parse_modsys_version(mod_header->modversion))) 386 { 387 snprintf(errorbuf, 1023, "Unsupported module system version '%s'", 388 mod_header->modversion); 389 irc_dlclose(Mod); 390 deletetmp(tmppath); 391 return(errorbuf); 392 } 393 if ((reterr = validate_mod_header(relpath, mod_header))) 394 { 395 irc_dlclose(Mod); 396 deletetmp(tmppath); 397 return(reterr); 398 } 399 if (Module_Find(mod_header->name)) 400 { 401 irc_dlclose(Mod); 402 deletetmp(tmppath); 403 return (NULL); 404 } 405 mod = (Module *)Module_make(mod_header, Mod); 406 safe_strdup(mod->tmp_file, tmppath); 407 mod->mod_sys_version = modsys_ver; 408 mod->compiler_version = compiler_version ? *compiler_version : 0; 409 safe_strdup(mod->relpath, relpath); 410 411 irc_dlsym(Mod, "Mod_Init", Mod_Init); 412 if (!Mod_Init) 413 { 414 Module_free(mod); 415 return ("Unable to locate Mod_Init"); 416 } 417 irc_dlsym(Mod, "Mod_Unload", Mod_Unload); 418 if (!Mod_Unload) 419 { 420 Module_free(mod); 421 return ("Unable to locate Mod_Unload"); 422 } 423 irc_dlsym(Mod, "Mod_Load", Mod_Load); 424 if (!Mod_Load) 425 { 426 Module_free(mod); 427 return ("Unable to locate Mod_Load"); 428 } 429 irc_dlsym(Mod, "Mod_Handle", Mod_Handle); 430 if (Mod_Handle) 431 *Mod_Handle = mod; 432 irc_dlsym(Mod, "Mod_Test", Mod_Test); 433 /* add module here, so ModuleSetOptions() w/MOD_OPT_PRIORITY is available in Mod_Test() */ 434 AddListItemPrio(mod, Modules, 0); 435 if (Mod_Test) 436 { 437 if ((ret = (*Mod_Test)(&mod->modinfo)) < MOD_SUCCESS) 438 { 439 ircsnprintf(errorbuf, sizeof(errorbuf), "Mod_Test returned %i", ret); 440 /* We EXPECT the module to have cleaned up its mess */ 441 Module_free(mod); 442 return (errorbuf); 443 } 444 } 445 mod->flags = MODFLAG_TESTING; 446 return NULL; 447 } 448 else 449 { 450 /* Return the error .. */ 451 return irc_dlerror(); 452 } 453 } 454 455 void Module_DelayChildren(Module *m) 456 { 457 ModuleChild *c; 458 for (c = m->children; c; c = c->next) 459 { 460 c->child->flags |= MODFLAG_DELAYED; 461 Module_DelayChildren(c->child); 462 } 463 } 464 465 Module *Module_make(ModuleHeader *header, 466 #ifdef _WIN32 467 HMODULE mod 468 #else 469 void *mod 470 #endif 471 ) 472 { 473 Module *modp = NULL; 474 475 modp = safe_alloc(sizeof(Module)); 476 modp->header = header; 477 modp->dll = mod; 478 modp->flags = MODFLAG_NONE; 479 modp->options = 0; 480 modp->errorcode = MODERR_NOERROR; 481 modp->children = NULL; 482 modp->modinfo.size = sizeof(ModuleInfo); 483 modp->modinfo.module_load = 0; 484 modp->modinfo.handle = modp; 485 486 return (modp); 487 } 488 489 void Init_all_testing_modules(void) 490 { 491 492 Module *mi, *next; 493 int ret; 494 iFP Mod_Init; 495 for (mi = Modules; mi; mi = next) 496 { 497 next = mi->next; 498 if (!(mi->flags & MODFLAG_TESTING)) 499 continue; 500 irc_dlsym(mi->dll, "Mod_Init", Mod_Init); 501 if ((ret = (*Mod_Init)(&mi->modinfo)) < MOD_SUCCESS) { 502 config_error("Error loading %s: Mod_Init returned %i", 503 mi->header->name, ret); 504 Module_free(mi); 505 continue; 506 } 507 mi->flags = MODFLAG_INIT; 508 } 509 } 510 511 void FreeModObj(ModuleObject *obj, Module *m) 512 { 513 if (obj->type == MOBJ_EVENT) { 514 EventDel(obj->object.event); 515 } 516 else if (obj->type == MOBJ_HOOK) { 517 HookDel(obj->object.hook); 518 } 519 else if (obj->type == MOBJ_COMMAND) { 520 CommandDel(obj->object.command); 521 } 522 else if (obj->type == MOBJ_HOOKTYPE) { 523 //HooktypeDel(obj->object.hooktype, m); -- reinstate if we audited this code 524 } 525 else if (obj->type == MOBJ_VERSIONFLAG) { 526 VersionflagDel(obj->object.versionflag, m); 527 } 528 else if (obj->type == MOBJ_UMODE) { 529 UmodeDel(obj->object.umode); 530 } 531 else if (obj->type == MOBJ_CMODE) { 532 CmodeDel(obj->object.cmode); 533 } 534 else if (obj->type == MOBJ_COMMANDOVERRIDE) { 535 CommandOverrideDel(obj->object.cmdoverride); 536 } 537 else if (obj->type == MOBJ_EXTBAN) { 538 ExtbanDel(obj->object.extban); 539 } 540 else if (obj->type == MOBJ_CALLBACK) { 541 CallbackDel(obj->object.callback); 542 } 543 else if (obj->type == MOBJ_EFUNCTION) { 544 EfunctionDel(obj->object.efunction); 545 } 546 else if (obj->type == MOBJ_ISUPPORT) { 547 ISupportDel(obj->object.isupport); 548 } 549 else if (obj->type == MOBJ_MODDATA) { 550 ModDataDel(obj->object.moddata); 551 } 552 else if (obj->type == MOBJ_VALIDATOR) { 553 OperClassValidatorDel(obj->object.validator); 554 } 555 else if (obj->type == MOBJ_CLICAP) { 556 ClientCapabilityDel(obj->object.clicap); 557 } 558 else if (obj->type == MOBJ_MTAG) { 559 MessageTagHandlerDel(obj->object.mtag); 560 } 561 else if (obj->type == MOBJ_HISTORY_BACKEND) { 562 HistoryBackendDel(obj->object.history_backend); 563 } 564 else if (obj->type == MOBJ_RPC) { 565 RPCHandlerDel(obj->object.rpc); 566 } 567 else 568 { 569 unreal_log(ULOG_FATAL, "module", "FREEMODOBJ_UNKNOWN_TYPE", NULL, 570 "[BUG] FreeModObj() called for unknown object (type $type)", 571 log_data_integer("type", obj->type)); 572 abort(); 573 } 574 } 575 576 void Unload_all_loaded_modules(void) 577 { 578 Module *mi, *next; 579 ModuleChild *child, *childnext; 580 ModuleObject *objs, *objnext; 581 iFP Mod_Unload; 582 int ret; 583 584 for (mi = Modules; mi; mi = next) 585 { 586 next = mi->next; 587 if (!(mi->flags & MODFLAG_LOADED) || (mi->flags & MODFLAG_DELAYED) || (mi->options & MOD_OPT_PERM)) 588 continue; 589 irc_dlsym(mi->dll, "Mod_Unload", Mod_Unload); 590 if (Mod_Unload) 591 { 592 ret = (*Mod_Unload)(&mi->modinfo); 593 if (ret == MOD_DELAY) 594 { 595 mi->flags |= MODFLAG_DELAYED; 596 Module_DelayChildren(mi); 597 } 598 } 599 for (objs = mi->objects; objs; objs = objnext) { 600 objnext = objs->next; 601 FreeModObj(objs, mi); 602 } 603 for (child = mi->children; child; child = childnext) 604 { 605 childnext = child->next; 606 DelListItem(child,mi->children); 607 safe_free(child); 608 } 609 DelListItem(mi,Modules); 610 irc_dlclose(mi->dll); 611 deletetmp(mi->tmp_file); 612 safe_free(mi->tmp_file); 613 safe_free(mi->relpath); 614 safe_free(mi); 615 } 616 } 617 618 void Unload_all_testing_modules(void) 619 { 620 Module *mi, *next; 621 ModuleChild *child, *childnext; 622 ModuleObject *objs, *objnext; 623 624 for (mi = Modules; mi; mi = next) 625 { 626 next = mi->next; 627 if (!(mi->flags & MODFLAG_TESTING)) 628 continue; 629 for (objs = mi->objects; objs; objs = objnext) { 630 objnext = objs->next; 631 FreeModObj(objs, mi); 632 } 633 for (child = mi->children; child; child = childnext) 634 { 635 childnext = child->next; 636 DelListItem(child,mi->children); 637 safe_free(child); 638 } 639 DelListItem(mi,Modules); 640 irc_dlclose(mi->dll); 641 deletetmp(mi->tmp_file); 642 safe_free(mi->tmp_file); 643 safe_free(mi->relpath); 644 safe_free(mi); 645 } 646 } 647 648 /* 649 * Returns -1 if you cannot unload due to children still alive 650 * Returns 1 if successful 651 */ 652 int Module_free(Module *mod) 653 { 654 Module *p; 655 ModuleChild *cp, *cpnext; 656 ModuleObject *objs, *next; 657 /* Do not kill parent if children still alive */ 658 659 for (cp = mod->children; cp; cp = cp->next) 660 { 661 Module_Unload(cp->child->header->name); 662 } 663 for (objs = mod->objects; objs; objs = next) { 664 next = objs->next; 665 FreeModObj(objs, mod); 666 } 667 for (p = Modules; p; p = p->next) 668 { 669 for (cp = p->children; cp; cp = cpnext) 670 { 671 cpnext = cp->next; 672 if (cp->child == mod) 673 { 674 DelListItem(mod, p->children); 675 safe_free(cp); 676 /* We can assume there can be only one. */ 677 break; 678 } 679 } 680 } 681 DelListItem(mod, Modules); 682 irc_dlclose(mod->dll); 683 safe_free(mod->tmp_file); 684 safe_free(mod->relpath); 685 safe_free(mod); 686 return 1; 687 } 688 689 /* 690 * Module_Unload () 691 * char *name Internal module name 692 * Returns: 693 * -1 Not able to locate module, severe failure, anything 694 * 1 Module unloaded 695 * 2 Module wishes delayed unloading, has placed event 696 */ 697 int Module_Unload(const char *name) 698 { 699 Module *m; 700 int (*Mod_Unload)(); 701 int ret; 702 for (m = Modules; m; m = m->next) 703 { 704 if (!strcmp(m->header->name, name)) 705 { 706 break; 707 } 708 } 709 if (!m) 710 return -1; 711 irc_dlsym(m->dll, "Mod_Unload", Mod_Unload); 712 if (!Mod_Unload) 713 { 714 return -1; 715 } 716 ret = (*Mod_Unload)(&m->modinfo); 717 if (ret == MOD_DELAY) 718 { 719 m->flags |= MODFLAG_DELAYED; 720 Module_DelayChildren(m); 721 return 2; 722 } 723 if (ret == MOD_FAILED) 724 { 725 return -1; 726 } 727 /* No more pain detected, let's unload */ 728 DelListItem(m, Modules); 729 Module_free(m); 730 return 1; 731 } 732 733 void module_loadall(void) 734 { 735 iFP fp; 736 Module *mi, *next; 737 738 loop.config_status = CONFIG_STATUS_LOAD; 739 740 /* Run through all modules and check for module load */ 741 for (mi = Modules; mi; mi = next) 742 { 743 next = mi->next; 744 if (mi->flags & MODFLAG_LOADED) 745 continue; 746 irc_dlsym(mi->dll, "Mod_Load", fp); 747 /* Call the module_load */ 748 if ((*fp)(&mi->modinfo) != MOD_SUCCESS) 749 { 750 config_status("cannot load module %s", mi->header->name); 751 Module_free(mi); 752 } 753 else 754 mi->flags = MODFLAG_LOADED; 755 } 756 } 757 758 int Module_IsAlreadyChild(Module *parent, Module *child) 759 { 760 ModuleChild *mcp; 761 762 for (mcp = parent->children; mcp; mcp = mcp->next) 763 { 764 if (mcp->child == child) 765 return 1; 766 } 767 return 0; 768 } 769 770 void Module_AddAsChild(Module *parent, Module *child) 771 { 772 ModuleChild *childp = NULL; 773 774 childp = safe_alloc(sizeof(ModuleChild)); 775 childp->child = child; 776 AddListItem(childp, parent->children); 777 } 778 779 /* cmd_module. 780 * by Stskeeps, codemastr, Syzop. 781 * Changed it so it's now public for users too, as quite some people 782 * (and users) requested they should have the right to see what kind 783 * of weird modules are loaded on the server, especially since people 784 * like to load spy modules these days. 785 * I do not consider this sensitive information, but just in case 786 * I stripped the version string for non-admins (eg: normal users). -- Syzop 787 */ 788 CMD_FUNC(cmd_module) 789 { 790 Module *mi; 791 int i; 792 char tmp[1024], *p; 793 RealCommand *mptr; 794 int all = 0; 795 796 if ((parc > 1) && !strcmp(parv[1], "-all")) 797 all = 1; 798 799 if (MyUser(client) && !IsOper(client) && all) 800 add_fake_lag(client, 7000); /* Lag them up. Big list. */ 801 802 if ((parc > 2) && (hunt_server(client, recv_mtags, "MODULE", 2, parc, parv) != HUNTED_ISME)) 803 return; 804 805 if ((parc == 2) && (parv[1][0] != '-') && (hunt_server(client, recv_mtags, "MODULE", 1, parc, parv) != HUNTED_ISME)) 806 return; 807 808 if (all) 809 sendtxtnumeric(client, "Showing ALL loaded modules:"); 810 else 811 sendtxtnumeric(client, "Showing loaded 3rd party modules (use \"MODULE -all\" to show all modules):"); 812 813 for (mi = Modules; mi; mi = mi->next) 814 { 815 /* Skip official modules unless "MODULE -all" */ 816 if (!all && (mi->options & MOD_OPT_OFFICIAL)) 817 continue; 818 819 tmp[0] = '\0'; 820 if (mi->flags & MODFLAG_DELAYED) 821 strlcat(tmp, "[Unloading] ", sizeof(tmp)); 822 if (mi->options & MOD_OPT_PERM_RELOADABLE) 823 strlcat(tmp, "[PERM-BUT-RELOADABLE] ", sizeof(tmp)); 824 if (mi->options & MOD_OPT_PERM) 825 strlcat(tmp, "[PERM] ", sizeof(tmp)); 826 if (!(mi->options & MOD_OPT_OFFICIAL)) 827 strlcat(tmp, "[3RD] ", sizeof(tmp)); 828 if (!ValidatePermissionsForPath("server:module",client,NULL,NULL,NULL)) 829 sendtxtnumeric(client, "*** %s - %s - by %s %s", 830 mi->header->name, 831 mi->header->description, 832 mi->header->author, 833 mi->options & MOD_OPT_OFFICIAL ? "" : "[3RD]"); 834 else 835 sendtxtnumeric(client, "*** %s %s - %s - by %s %s", 836 mi->header->name, 837 mi->header->version, 838 mi->header->description, 839 mi->header->author, 840 tmp); 841 } 842 843 sendtxtnumeric(client, "End of module list"); 844 845 if (!ValidatePermissionsForPath("server:module",client,NULL,NULL,NULL)) 846 return; 847 848 tmp[0] = '\0'; 849 p = tmp; 850 for (i=0; i < MAXHOOKTYPES; i++) 851 { 852 if (!Hooks[i]) 853 continue; 854 ircsnprintf(p, sizeof(tmp) - strlen(tmp), "%d ", i); 855 p += strlen(p); 856 if (p > tmp + 380) 857 { 858 sendtxtnumeric(client, "Hooks: %s", tmp); 859 tmp[0] = '\0'; 860 p = tmp; 861 } 862 } 863 sendtxtnumeric(client, "Hooks: %s ", tmp); 864 865 tmp[0] = '\0'; 866 p = tmp; 867 for (i=0; i < 256; i++) 868 { 869 for (mptr = CommandHash[i]; mptr; mptr = mptr->next) 870 if (mptr->overriders) 871 { 872 ircsnprintf(p, sizeof(tmp)-strlen(tmp), "%s ", mptr->cmd); 873 p += strlen(p); 874 if (p > tmp+380) 875 { 876 sendtxtnumeric(client, "Override: %s", tmp); 877 tmp[0] = '\0'; 878 p = tmp; 879 } 880 } 881 } 882 sendtxtnumeric(client, "Override: %s", tmp); 883 } 884 885 Hooktype *HooktypeFind(const char *string) { 886 Hooktype *hooktype; 887 for (hooktype = Hooktypes; hooktype->string ;hooktype++) { 888 if (!strcasecmp(hooktype->string, string)) 889 return hooktype; 890 } 891 return NULL; 892 } 893 894 Versionflag *VersionflagFind(char flag) 895 { 896 Versionflag *vflag; 897 for (vflag = Versionflags; vflag; vflag = vflag->next) 898 { 899 if (vflag->flag == flag) 900 return vflag; 901 } 902 return NULL; 903 } 904 905 Versionflag *VersionflagAdd(Module *module, char flag) 906 { 907 Versionflag *vflag; 908 ModuleChild *parent; 909 if ((vflag = VersionflagFind(flag))) 910 { 911 ModuleChild *child; 912 for (child = vflag->parents; child; child = child->next) { 913 if (child->child == module) 914 break; 915 } 916 if (!child) 917 { 918 parent = safe_alloc(sizeof(ModuleChild)); 919 parent->child = module; 920 if (module) { 921 ModuleObject *vflagobj; 922 vflagobj = safe_alloc(sizeof(ModuleObject)); 923 vflagobj->type = MOBJ_VERSIONFLAG; 924 vflagobj->object.versionflag = vflag; 925 AddListItem(vflagobj, module->objects); 926 module->errorcode = MODERR_NOERROR; 927 } 928 AddListItem(parent,vflag->parents); 929 } 930 return vflag; 931 } 932 vflag = safe_alloc(sizeof(Versionflag)); 933 vflag->flag = flag; 934 parent = safe_alloc(sizeof(ModuleChild)); 935 parent->child = module; 936 if (module) 937 { 938 ModuleObject *vflagobj; 939 vflagobj = safe_alloc(sizeof(ModuleObject)); 940 vflagobj->type = MOBJ_VERSIONFLAG; 941 vflagobj->object.versionflag = vflag; 942 AddListItem(vflagobj, module->objects); 943 module->errorcode = MODERR_NOERROR; 944 } 945 flag_add(flag); 946 AddListItem(parent,vflag->parents); 947 AddListItem(vflag, Versionflags); 948 return vflag; 949 } 950 951 void VersionflagDel(Versionflag *vflag, Module *module) 952 { 953 ModuleChild *owner; 954 if (!vflag) 955 return; 956 957 for (owner = vflag->parents; owner; owner = owner->next) 958 { 959 if (owner->child == module) 960 { 961 DelListItem(owner,vflag->parents); 962 safe_free(owner); 963 break; 964 } 965 } 966 if (module) 967 { 968 ModuleObject *objs; 969 for (objs = module->objects; objs; objs = objs->next) { 970 if (objs->type == MOBJ_VERSIONFLAG && objs->object.versionflag == vflag) { 971 DelListItem(objs,module->objects); 972 safe_free(objs); 973 break; 974 } 975 } 976 } 977 if (!vflag->parents) 978 { 979 flag_del(vflag->flag); 980 DelListItem(vflag, Versionflags); 981 safe_free(vflag); 982 } 983 } 984 985 Hook *HookAddMain(Module *module, int hooktype, int priority, int (*func)(), void (*vfunc)(), char *(*stringfunc)(), const char *(*conststringfunc)()) 986 { 987 Hook *p; 988 989 p = (Hook *) safe_alloc(sizeof(Hook)); 990 if (func) 991 p->func.intfunc = func; 992 if (vfunc) 993 p->func.voidfunc = vfunc; 994 if (stringfunc) 995 p->func.stringfunc = stringfunc; 996 if (conststringfunc) 997 p->func.conststringfunc = conststringfunc; 998 p->type = hooktype; 999 p->owner = module; 1000 p->priority = priority; 1001 1002 if (module) { 1003 ModuleObject *hookobj = (ModuleObject *)safe_alloc(sizeof(ModuleObject)); 1004 hookobj->object.hook = p; 1005 hookobj->type = MOBJ_HOOK; 1006 AddListItem(hookobj, module->objects); 1007 module->errorcode = MODERR_NOERROR; 1008 } 1009 1010 AddListItemPrio(p, Hooks[hooktype], p->priority); 1011 1012 return p; 1013 } 1014 1015 Hook *HookDel(Hook *hook) 1016 { 1017 Hook *p, *q; 1018 for (p = Hooks[hook->type]; p; p = p->next) { 1019 if (p == hook) { 1020 q = p->next; 1021 DelListItem(p, Hooks[hook->type]); 1022 if (p->owner) { 1023 ModuleObject *hookobj; 1024 for (hookobj = p->owner->objects; hookobj; hookobj = hookobj->next) { 1025 if (hookobj->type == MOBJ_HOOK && hookobj->object.hook == p) { 1026 DelListItem(hookobj, hook->owner->objects); 1027 safe_free(hookobj); 1028 break; 1029 } 1030 } 1031 } 1032 safe_free(p); 1033 return q; 1034 } 1035 } 1036 return NULL; 1037 } 1038 1039 static int num_callbacks(int cbtype) 1040 { 1041 Callback *e; 1042 int cnt = 0; 1043 1044 for (e = Callbacks[cbtype]; e; e = e->next) 1045 if (!e->willberemoved) 1046 cnt++; 1047 1048 return cnt; 1049 } 1050 1051 Callback *CallbackAddMain(Module *module, int cbtype, int (*func)(), void (*vfunc)(), void *(*pvfunc)(), char *(*stringfunc)(), const char *(*conststringfunc)()) 1052 { 1053 Callback *p; 1054 1055 if (num_callbacks(cbtype) > 0) 1056 { 1057 if (module) 1058 module->errorcode = MODERR_EXISTS; 1059 return NULL; 1060 } 1061 1062 p = safe_alloc(sizeof(Callback)); 1063 if (func) 1064 p->func.intfunc = func; 1065 if (vfunc) 1066 p->func.voidfunc = vfunc; 1067 if (pvfunc) 1068 p->func.pvoidfunc = pvfunc; 1069 if (stringfunc) 1070 p->func.stringfunc = stringfunc; 1071 if (conststringfunc) 1072 p->func.conststringfunc = conststringfunc; 1073 p->type = cbtype; 1074 p->owner = module; 1075 AddListItem(p, Callbacks[cbtype]); 1076 if (module) { 1077 ModuleObject *cbobj = safe_alloc(sizeof(ModuleObject)); 1078 cbobj->object.callback = p; 1079 cbobj->type = MOBJ_CALLBACK; 1080 AddListItem(cbobj, module->objects); 1081 module->errorcode = MODERR_NOERROR; 1082 } 1083 return p; 1084 } 1085 1086 Callback *CallbackDel(Callback *cb) 1087 { 1088 Callback *p, *q; 1089 for (p = Callbacks[cb->type]; p; p = p->next) { 1090 if (p == cb) { 1091 q = p->next; 1092 DelListItem(p, Callbacks[cb->type]); 1093 if (RCallbacks[cb->type] == p) 1094 RCallbacks[cb->type] = NULL; 1095 if (p->owner) { 1096 ModuleObject *cbobj; 1097 for (cbobj = p->owner->objects; cbobj; cbobj = cbobj->next) { 1098 if ((cbobj->type == MOBJ_CALLBACK) && (cbobj->object.callback == p)) { 1099 DelListItem(cbobj, cb->owner->objects); 1100 safe_free(cbobj); 1101 break; 1102 } 1103 } 1104 } 1105 safe_free(p); 1106 return q; 1107 } 1108 } 1109 return NULL; 1110 } 1111 1112 CommandOverride *CommandOverrideAdd(Module *module, const char *name, int priority, OverrideCmdFunc function) 1113 { 1114 RealCommand *p; 1115 CommandOverride *ovr; 1116 1117 if (!(p = find_command_simple(name))) 1118 { 1119 if (module) 1120 module->errorcode = MODERR_NOTFOUND; 1121 return NULL; 1122 } 1123 for (ovr=p->overriders; ovr; ovr=ovr->next) 1124 { 1125 if ((ovr->owner == module) && (ovr->func == function)) 1126 { 1127 if (module) 1128 module->errorcode = MODERR_EXISTS; 1129 return NULL; 1130 } 1131 } 1132 ovr = safe_alloc(sizeof(CommandOverride)); 1133 ovr->func = function; 1134 ovr->owner = module; 1135 ovr->priority = priority; 1136 if (module) 1137 { 1138 ModuleObject *cmdoverobj = safe_alloc(sizeof(ModuleObject)); 1139 cmdoverobj->type = MOBJ_COMMANDOVERRIDE; 1140 cmdoverobj->object.cmdoverride = ovr; 1141 AddListItem(cmdoverobj, module->objects); 1142 module->errorcode = MODERR_NOERROR; 1143 } 1144 ovr->command = p; 1145 AddListItemPrio(ovr, p->overriders, ovr->priority); 1146 if (p->friend) 1147 { 1148 AddListItem(ovr, p->friend->overriders); 1149 } 1150 return ovr; 1151 } 1152 1153 void CommandOverrideDel(CommandOverride *cmd) 1154 { 1155 DelListItem(cmd, cmd->command->overriders); 1156 if (cmd->command->friend) 1157 { 1158 DelListItem(cmd, cmd->command->friend->overriders); 1159 } 1160 if (cmd->owner) 1161 { 1162 ModuleObject *obj; 1163 for (obj = cmd->owner->objects; obj; obj = obj->next) 1164 { 1165 if (obj->type != MOBJ_COMMANDOVERRIDE) 1166 continue; 1167 if (obj->object.cmdoverride == cmd) 1168 { 1169 DelListItem(obj, cmd->owner->objects); 1170 safe_free(obj); 1171 break; 1172 } 1173 } 1174 } 1175 safe_free(cmd); 1176 } 1177 1178 void CallCommandOverride(CommandOverride *ovr, Client *client, MessageTag *mtags, int parc, const char *parv[]) 1179 { 1180 if (ovr->next) 1181 ovr->next->func(ovr->next, client, mtags, parc, parv); 1182 else 1183 ovr->command->func(client, mtags, parc, parv); 1184 } 1185 1186 EVENT(e_unload_module_delayed) 1187 { 1188 char *name = (char *)data; 1189 int i; 1190 i = Module_Unload(name); 1191 if (i == 1) 1192 { 1193 unreal_log(ULOG_INFO, "module", "MODULE_UNLOADING_DELAYED", NULL, 1194 "Unloading module $module_name (was delayed earlier)", 1195 log_data_string("module_name", name)); 1196 } 1197 safe_free(name); 1198 extcmodes_check_for_changes(); 1199 umodes_check_for_changes(); 1200 return; 1201 } 1202 1203 void unload_all_modules(void) 1204 { 1205 Module *m; 1206 int (*Mod_Unload)(); 1207 for (m = Modules; m; m = m->next) 1208 { 1209 #ifdef DEBUGMODE 1210 unreal_log(ULOG_DEBUG, "module", "MODULE_UNLOADING", NULL, 1211 "Unloading module $module_name", 1212 log_data_string("module_name", m->header->name)); 1213 #endif 1214 irc_dlsym(m->dll, "Mod_Unload", Mod_Unload); 1215 if (Mod_Unload) 1216 (*Mod_Unload)(&m->modinfo); 1217 deletetmp(m->tmp_file); 1218 } 1219 } 1220 1221 void ModuleSetOptions(Module *module, unsigned int options, int action) 1222 { 1223 unsigned int oldopts = module->options; 1224 1225 if (options == MOD_OPT_PRIORITY) 1226 { 1227 DelListItem(module, Modules); 1228 AddListItemPrio(module, Modules, action); 1229 } else { 1230 /* Simple bit flag(s) */ 1231 if (action) 1232 module->options |= options; 1233 else 1234 module->options &= ~options; 1235 } 1236 } 1237 1238 unsigned int ModuleGetOptions(Module *module) 1239 { 1240 return module->options; 1241 } 1242 1243 unsigned int ModuleGetError(Module *module) 1244 { 1245 return module->errorcode; 1246 } 1247 1248 static const char *module_error_str[] = { 1249 "No error", 1250 "Object already exists", 1251 "No space available", 1252 "Invalid parameter(s)", 1253 "Object was not found" 1254 }; 1255 1256 const char *ModuleGetErrorStr(Module *module) 1257 { 1258 if (module->errorcode >= sizeof(module_error_str)/sizeof(module_error_str[0])) 1259 return NULL; 1260 1261 return module_error_str[module->errorcode]; 1262 } 1263 1264 /** Ensure that all required callbacks are in place and meet 1265 * all specified requirements 1266 */ 1267 int callbacks_check(void) 1268 { 1269 int i; 1270 1271 for (i=0; i < MAXCALLBACKS; i++) 1272 { 1273 if (num_callbacks(i) > 1) 1274 { 1275 config_error("ERROR: Multiple callbacks loaded for type %d. " 1276 "Make sure you only load 1 module of 1 type (eg: only 1 cloaking module)", 1277 i); 1278 return -1; 1279 } 1280 } 1281 1282 if (!Callbacks[CALLBACKTYPE_CLOAK_KEY_CHECKSUM]) 1283 { 1284 unreal_log(ULOG_ERROR, "config", "NO_CLOAKING_MODULE", NULL, 1285 "No cloaking module loaded, you must load 1 of these modulese:\n" 1286 "1) cloak_sha256 - if you are a new network starting with UnrealIRCd 6\n" 1287 "2) cloak_md5 - the old one if migrating an existing network from UnrealIRCd 3.2/4/5\n" 1288 "3) cloak_none - if you don't want to use cloaking at all\n" 1289 "See also https://www.unrealircd.org/docs/FAQ#choose-a-cloaking-module"); 1290 return -1; 1291 } 1292 return 0; 1293 } 1294 1295 void callbacks_switchover(void) 1296 { 1297 Callback *e; 1298 int i; 1299 1300 /* Now set the real callback, and tag the new one 1301 * as 'willberemoved' if needed. 1302 */ 1303 1304 for (i=0; i < MAXCALLBACKS; i++) 1305 for (e = Callbacks[i]; e; e = e->next) 1306 if (!e->willberemoved) 1307 { 1308 RCallbacks[i] = e; /* This is the new one. */ 1309 if (!(e->owner->options & MOD_OPT_PERM)) 1310 e->willberemoved = 1; 1311 break; 1312 } 1313 } 1314 1315 #ifdef _WIN32 1316 const char *our_dlerror(void) 1317 { 1318 static char errbuf[513]; 1319 DWORD err = GetLastError(); 1320 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, 1321 0, errbuf, 512, NULL); 1322 if (err == ERROR_MOD_NOT_FOUND) 1323 strlcat(errbuf, " This could be because the DLL depends on another DLL, for example if you " 1324 "are trying to load a 3rd party module which was compiled with a different compiler version.", 1325 sizeof(errbuf)); 1326 return errbuf; 1327 } 1328 #endif 1329 1330 /** Check if a module is loaded. 1331 * @param name Name of the module by relative path (eg: 'extbans/timedban') 1332 * @returns 1 if module is loaded, 0 if not. 1333 * @note The name is checked against the module name, 1334 * this can be a problem if two modules have the same name. 1335 */ 1336 int is_module_loaded(const char *name) 1337 { 1338 Module *mi; 1339 for (mi = Modules; mi; mi = mi->next) 1340 { 1341 if (mi->flags & MODFLAG_DELAYED) 1342 continue; /* unloading (delayed) */ 1343 1344 /* During config_posttest ignore modules that are loaded, 1345 * since we only care about the 'future' state. 1346 */ 1347 if ((loop.config_status < CONFIG_STATUS_LOAD) && 1348 (loop.config_status >= CONFIG_STATUS_POSTTEST) && 1349 (mi->flags == MODFLAG_LOADED)) 1350 { 1351 continue; 1352 } 1353 1354 if (!strcasecmp(mi->relpath, name)) 1355 return 1; 1356 } 1357 return 0; 1358 } 1359 1360 static const char *mod_var_name(ModuleInfo *modinfo, const char *varshortname) 1361 { 1362 static char fullname[512]; 1363 snprintf(fullname, sizeof(fullname), "%s:%s", modinfo->handle->header->name, varshortname); 1364 return fullname; 1365 } 1366 1367 int LoadPersistentPointerX(ModuleInfo *modinfo, const char *varshortname, void **var, void (*free_variable)(ModData *m)) 1368 { 1369 ModDataInfo *m; 1370 const char *fullname = mod_var_name(modinfo, varshortname); 1371 1372 m = findmoddata_byname(fullname, MODDATATYPE_LOCAL_VARIABLE); 1373 if (m) 1374 { 1375 *var = moddata_local_variable(m).ptr; 1376 return 1; 1377 } else { 1378 ModDataInfo mreq; 1379 memset(&mreq, 0, sizeof(mreq)); 1380 mreq.type = MODDATATYPE_LOCAL_VARIABLE; 1381 mreq.name = strdup(fullname); 1382 mreq.free = free_variable; 1383 m = ModDataAdd(modinfo->handle, mreq); 1384 moddata_local_variable(m).ptr = NULL; 1385 safe_free(mreq.name); 1386 return 0; 1387 } 1388 } 1389 1390 void SavePersistentPointerX(ModuleInfo *modinfo, const char *varshortname, void *var) 1391 { 1392 ModDataInfo *m; 1393 const char *fullname = mod_var_name(modinfo, varshortname); 1394 1395 m = findmoddata_byname(fullname, MODDATATYPE_LOCAL_VARIABLE); 1396 moddata_local_variable(m).ptr = var; 1397 } 1398 1399 int LoadPersistentIntX(ModuleInfo *modinfo, const char *varshortname, int *var) 1400 { 1401 ModDataInfo *m; 1402 const char *fullname = mod_var_name(modinfo, varshortname); 1403 1404 m = findmoddata_byname(fullname, MODDATATYPE_LOCAL_VARIABLE); 1405 if (m) 1406 { 1407 *var = moddata_local_variable(m).i; 1408 return 1; 1409 } else { 1410 ModDataInfo mreq; 1411 memset(&mreq, 0, sizeof(mreq)); 1412 mreq.type = MODDATATYPE_LOCAL_VARIABLE; 1413 mreq.name = strdup(fullname); 1414 mreq.free = NULL; 1415 m = ModDataAdd(modinfo->handle, mreq); 1416 moddata_local_variable(m).i = 0; 1417 safe_free(mreq.name); 1418 return 0; 1419 } 1420 } 1421 1422 void SavePersistentIntX(ModuleInfo *modinfo, const char *varshortname, int var) 1423 { 1424 ModDataInfo *m; 1425 const char *fullname = mod_var_name(modinfo, varshortname); 1426 1427 m = findmoddata_byname(fullname, MODDATATYPE_LOCAL_VARIABLE); 1428 moddata_local_variable(m).i = var; 1429 } 1430 1431 int LoadPersistentLongX(ModuleInfo *modinfo, const char *varshortname, long *var) 1432 { 1433 ModDataInfo *m; 1434 const char *fullname = mod_var_name(modinfo, varshortname); 1435 1436 m = findmoddata_byname(fullname, MODDATATYPE_LOCAL_VARIABLE); 1437 if (m) 1438 { 1439 *var = moddata_local_variable(m).l; 1440 return 1; 1441 } else { 1442 ModDataInfo mreq; 1443 memset(&mreq, 0, sizeof(mreq)); 1444 mreq.type = MODDATATYPE_LOCAL_VARIABLE; 1445 mreq.name = strdup(fullname); 1446 mreq.free = NULL; 1447 m = ModDataAdd(modinfo->handle, mreq); 1448 moddata_local_variable(m).l = 0; 1449 safe_free(mreq.name); 1450 return 0; 1451 } 1452 } 1453 1454 void SavePersistentLongX(ModuleInfo *modinfo, const char *varshortname, long var) 1455 { 1456 ModDataInfo *m; 1457 const char *fullname = mod_var_name(modinfo, varshortname); 1458 1459 m = findmoddata_byname(fullname, MODDATATYPE_LOCAL_VARIABLE); 1460 moddata_local_variable(m).l = var; 1461 } 1462 1463 int LoadPersistentLongLongX(ModuleInfo *modinfo, const char *varshortname, long long *var) 1464 { 1465 ModDataInfo *m; 1466 const char *fullname = mod_var_name(modinfo, varshortname); 1467 1468 m = findmoddata_byname(fullname, MODDATATYPE_LOCAL_VARIABLE); 1469 if (m) 1470 { 1471 *var = moddata_local_variable(m).ll; 1472 return 1; 1473 } else { 1474 ModDataInfo mreq; 1475 memset(&mreq, 0, sizeof(mreq)); 1476 mreq.type = MODDATATYPE_LOCAL_VARIABLE; 1477 mreq.name = strdup(fullname); 1478 mreq.free = NULL; 1479 m = ModDataAdd(modinfo->handle, mreq); 1480 moddata_local_variable(m).ll = 0; 1481 safe_free(mreq.name); 1482 return 0; 1483 } 1484 } 1485 1486 void SavePersistentLongLongX(ModuleInfo *modinfo, const char *varshortname, long long var) 1487 { 1488 ModDataInfo *m; 1489 const char *fullname = mod_var_name(modinfo, varshortname); 1490 1491 m = findmoddata_byname(fullname, MODDATATYPE_LOCAL_VARIABLE); 1492 moddata_local_variable(m).ll = var; 1493 } 1494 1495 extern int module_has_moddata(Module *mod); 1496 extern int module_has_extcmode_param_mode(Module *mod); 1497 1498 /** Special hack for unloading modules with moddata and parameter extcmodes */ 1499 void special_delayed_unloading(void) 1500 { 1501 Module *m, *m2; 1502 extern Module *Modules; 1503 1504 for (m = Modules; m; m = m->next) 1505 { 1506 if (!(m->flags & MODFLAG_LOADED)) 1507 continue; 1508 if ((m->options & MOD_OPT_PERM) || (m->options & MOD_OPT_PERM_RELOADABLE)) 1509 continue; 1510 if (module_has_moddata(m) || module_has_extcmode_param_mode(m)) 1511 { 1512 int found = 0; 1513 for (m2 = Modules; m2; m2 = m2->next) 1514 { 1515 if ((m != m2) && !strcmp(m->header->name, m2->header->name)) 1516 found = 1; 1517 } 1518 if (!found) 1519 { 1520 char *name = strdup(m->header->name); 1521 config_warn("Delaying module unloading of '%s' for a millisecond...", name); 1522 m->flags |= MODFLAG_DELAYED; 1523 EventAdd(NULL, "e_unload_module_delayed", e_unload_module_delayed, name, 0, 1); 1524 } 1525 } 1526 } 1527 }