]> jfr.im git - irc/rqf/shadowircd.git/blob - src/modules.c
[svn] - the new plan:
[irc/rqf/shadowircd.git] / src / modules.c
1 /*
2 * ircd-ratbox: A slightly useful ircd.
3 * modules.c: A module loader.
4 *
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * USA
23 *
24 * $Id: modules.c 1509 2006-05-28 02:35:58Z nenolod $
25 */
26
27 #include "stdinc.h"
28
29
30 #include "modules.h"
31 #include "s_log.h"
32 #include "ircd.h"
33 #include "client.h"
34 #include "send.h"
35 #include "s_conf.h"
36 #include "s_newconf.h"
37 #include "numeric.h"
38 #include "parse.h"
39 #include "ircd_defs.h"
40 #include "irc_string.h"
41 #include "memory.h"
42 #include "tools.h"
43 #include "sprintf_irc.h"
44
45
46
47 /* -TimeMr14C:
48 * I have moved the dl* function definitions and
49 * the two functions (load_a_module / unload_a_module) to the
50 * file dynlink.c
51 * And also made the necessary changes to those functions
52 * to comply with shl_load and friends.
53 * In this file, to keep consistency with the makefile,
54 * I added the ability to load *.sl files, too.
55 * 27/02/2002
56 */
57
58 #ifndef STATIC_MODULES
59
60 struct module **modlist = NULL;
61
62 static const char *core_module_table[] = {
63 "m_die",
64 "m_error",
65 "m_join",
66 "m_kick",
67 "m_kill",
68 "m_message",
69 "m_mode",
70 "m_nick",
71 "m_part",
72 "m_quit",
73 "m_server",
74 "m_sjoin",
75 "m_squit",
76 NULL
77 };
78
79 #define MODS_INCREMENT 10
80 int num_mods = 0;
81 int max_mods = MODS_INCREMENT;
82
83 static dlink_list mod_paths;
84
85 static int mo_modload(struct Client *, struct Client *, int, const char **);
86 static int mo_modlist(struct Client *, struct Client *, int, const char **);
87 static int mo_modreload(struct Client *, struct Client *, int, const char **);
88 static int mo_modunload(struct Client *, struct Client *, int, const char **);
89 static int mo_modrestart(struct Client *, struct Client *, int, const char **);
90
91 struct Message modload_msgtab = {
92 "MODLOAD", 0, 0, 0, MFLG_SLOW,
93 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_modload, 2}}
94 };
95
96 struct Message modunload_msgtab = {
97 "MODUNLOAD", 0, 0, 0, MFLG_SLOW,
98 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_modunload, 2}}
99 };
100
101 struct Message modreload_msgtab = {
102 "MODRELOAD", 0, 0, 0, MFLG_SLOW,
103 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_modreload, 2}}
104 };
105
106 struct Message modlist_msgtab = {
107 "MODLIST", 0, 0, 0, MFLG_SLOW,
108 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_modlist, 0}}
109 };
110
111 struct Message modrestart_msgtab = {
112 "MODRESTART", 0, 0, 0, MFLG_SLOW,
113 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_modrestart, 0}}
114 };
115
116 extern struct Message error_msgtab;
117
118 void
119 modules_init(void)
120 {
121 mod_add_cmd(&modload_msgtab);
122 mod_add_cmd(&modunload_msgtab);
123 mod_add_cmd(&modreload_msgtab);
124 mod_add_cmd(&modlist_msgtab);
125 mod_add_cmd(&modrestart_msgtab);
126
127 /* Add the default paths we look in to the module system --nenolod */
128 mod_add_path(MODPATH);
129 mod_add_path(AUTOMODPATH);
130 }
131
132 /* mod_find_path()
133 *
134 * input - path
135 * output - none
136 * side effects - returns a module path from path
137 */
138 static struct module_path *
139 mod_find_path(const char *path)
140 {
141 dlink_node *ptr;
142 struct module_path *mpath;
143
144 DLINK_FOREACH(ptr, mod_paths.head)
145 {
146 mpath = ptr->data;
147
148 if(!strcmp(path, mpath->path))
149 return mpath;
150 }
151
152 return NULL;
153 }
154
155 /* mod_add_path
156 *
157 * input - path
158 * ouput -
159 * side effects - adds path to list
160 */
161 void
162 mod_add_path(const char *path)
163 {
164 struct module_path *pathst;
165
166 if(mod_find_path(path))
167 return;
168
169 pathst = MyMalloc(sizeof(struct module_path));
170
171 strcpy(pathst->path, path);
172 dlinkAddAlloc(pathst, &mod_paths);
173 }
174
175 /* mod_clear_paths()
176 *
177 * input -
178 * output -
179 * side effects - clear the lists of paths
180 */
181 void
182 mod_clear_paths(void)
183 {
184 dlink_node *ptr, *next_ptr;
185
186 DLINK_FOREACH_SAFE(ptr, next_ptr, mod_paths.head)
187 {
188 MyFree(ptr->data);
189 free_dlink_node(ptr);
190 }
191
192 mod_paths.head = mod_paths.tail = NULL;
193 mod_paths.length = 0;
194 }
195
196 /* irc_basename
197 *
198 * input -
199 * output -
200 * side effects -
201 */
202 char *
203 irc_basename(const char *path)
204 {
205 char *mod_basename = MyMalloc(strlen(path) + 1);
206 const char *s;
207
208 if(!(s = strrchr(path, '/')))
209 s = path;
210 else
211 s++;
212
213 (void) strcpy(mod_basename, s);
214 return mod_basename;
215 }
216
217 /* findmodule_byname
218 *
219 * input -
220 * output -
221 * side effects -
222 */
223
224 int
225 findmodule_byname(const char *name)
226 {
227 int i;
228
229 for (i = 0; i < num_mods; i++)
230 {
231 if(!irccmp(modlist[i]->name, name))
232 return i;
233 }
234 return -1;
235 }
236
237 /* load_all_modules()
238 *
239 * input -
240 * output -
241 * side effects -
242 */
243 void
244 load_all_modules(int warn)
245 {
246 DIR *system_module_dir = NULL;
247 struct dirent *ldirent = NULL;
248 char module_fq_name[PATH_MAX + 1];
249 int len;
250
251 modules_init();
252
253 modlist = (struct module **) MyMalloc(sizeof(struct module) * (MODS_INCREMENT));
254
255 max_mods = MODS_INCREMENT;
256
257 system_module_dir = opendir(AUTOMODPATH);
258
259 if(system_module_dir == NULL)
260 {
261 ilog(L_MAIN, "Could not load modules from %s: %s", AUTOMODPATH, strerror(errno));
262 return;
263 }
264
265 while ((ldirent = readdir(system_module_dir)) != NULL)
266 {
267 len = strlen(ldirent->d_name);
268 if((len > 3) && !strcmp(ldirent->d_name+len-3, SHARED_SUFFIX))
269 {
270 (void) ircsnprintf(module_fq_name, sizeof(module_fq_name), "%s/%s", AUTOMODPATH, ldirent->d_name);
271 (void) load_a_module(module_fq_name, warn, 0);
272 }
273
274 }
275 (void) closedir(system_module_dir);
276 }
277
278 /* load_core_modules()
279 *
280 * input -
281 * output -
282 * side effects - core modules are loaded, if any fail, kill ircd
283 */
284 void
285 load_core_modules(int warn)
286 {
287 char module_name[MAXPATHLEN];
288 int i;
289
290
291 for (i = 0; core_module_table[i]; i++)
292 {
293 ircsnprintf(module_name, sizeof(module_name), "%s/%s%s", MODPATH,
294 core_module_table[i], SHARED_SUFFIX);
295
296 if(load_a_module(module_name, warn, 1) == -1)
297 {
298 ilog(L_MAIN,
299 "Error loading core module %s%s: terminating ircd",
300 core_module_table[i], SHARED_SUFFIX);
301 exit(0);
302 }
303 }
304 }
305
306 /* load_one_module()
307 *
308 * input -
309 * output -
310 * side effects -
311 */
312 int
313 load_one_module(const char *path, int coremodule)
314 {
315 char modpath[MAXPATHLEN];
316 dlink_node *pathst;
317 struct module_path *mpath;
318
319 struct stat statbuf;
320
321 if (server_state_foreground == 1)
322 inotice("loading module %s ...", path);
323
324 DLINK_FOREACH(pathst, mod_paths.head)
325 {
326 mpath = pathst->data;
327
328 ircsnprintf(modpath, sizeof(modpath), "%s/%s", mpath->path, path);
329 if((strstr(modpath, "../") == NULL) && (strstr(modpath, "/..") == NULL))
330 {
331 if(stat(modpath, &statbuf) == 0)
332 {
333 if(S_ISREG(statbuf.st_mode))
334 {
335 /* Regular files only please */
336 if(coremodule)
337 return load_a_module(modpath, 1, 1);
338 else
339 return load_a_module(modpath, 1, 0);
340 }
341 }
342
343 }
344 }
345
346 sendto_realops_snomask(SNO_GENERAL, L_ALL, "Cannot locate module %s", path);
347 return -1;
348 }
349
350
351 /* load a module .. */
352 static int
353 mo_modload(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
354 {
355 char *m_bn;
356
357 if(!IsOperAdmin(source_p))
358 {
359 sendto_one(source_p, form_str(ERR_NOPRIVS),
360 me.name, source_p->name, "admin");
361 return 0;
362 }
363
364 m_bn = irc_basename(parv[1]);
365
366 if(findmodule_byname(m_bn) != -1)
367 {
368 sendto_one(source_p,
369 ":%s NOTICE %s :Module %s is already loaded",
370 me.name, source_p->name, m_bn);
371 MyFree(m_bn);
372 return 0;
373 }
374
375 load_one_module(parv[1], 0);
376
377 MyFree(m_bn);
378
379 return 0;
380 }
381
382
383 /* unload a module .. */
384 static int
385 mo_modunload(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
386 {
387 char *m_bn;
388 int modindex;
389
390 if(!IsOperAdmin(source_p))
391 {
392 sendto_one(source_p, form_str(ERR_NOPRIVS),
393 me.name, source_p->name, "admin");
394 return 0;
395 }
396
397 m_bn = irc_basename(parv[1]);
398
399 if((modindex = findmodule_byname(m_bn)) == -1)
400 {
401 sendto_one(source_p,
402 ":%s NOTICE %s :Module %s is not loaded", me.name, source_p->name, m_bn);
403 MyFree(m_bn);
404 return 0;
405 }
406
407 if(modlist[modindex]->core == 1)
408 {
409 sendto_one(source_p,
410 ":%s NOTICE %s :Module %s is a core module and may not be unloaded",
411 me.name, source_p->name, m_bn);
412 MyFree(m_bn);
413 return 0;
414 }
415
416 if(unload_one_module(m_bn, 1) == -1)
417 {
418 sendto_one(source_p,
419 ":%s NOTICE %s :Module %s is not loaded", me.name, source_p->name, m_bn);
420 }
421 MyFree(m_bn);
422 return 0;
423 }
424
425 /* unload and load in one! */
426 static int
427 mo_modreload(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
428 {
429 char *m_bn;
430 int modindex;
431 int check_core;
432
433 if(!IsOperAdmin(source_p))
434 {
435 sendto_one(source_p, form_str(ERR_NOPRIVS),
436 me.name, source_p->name, "admin");
437 return 0;
438 }
439
440 m_bn = irc_basename(parv[1]);
441
442 if((modindex = findmodule_byname(m_bn)) == -1)
443 {
444 sendto_one(source_p,
445 ":%s NOTICE %s :Module %s is not loaded", me.name, source_p->name, m_bn);
446 MyFree(m_bn);
447 return 0;
448 }
449
450 check_core = modlist[modindex]->core;
451
452 if(unload_one_module(m_bn, 1) == -1)
453 {
454 sendto_one(source_p,
455 ":%s NOTICE %s :Module %s is not loaded", me.name, source_p->name, m_bn);
456 MyFree(m_bn);
457 return 0;
458 }
459
460 if((load_one_module(parv[1], check_core) == -1) && check_core)
461 {
462 sendto_realops_snomask(SNO_GENERAL, L_ALL,
463 "Error reloading core module: %s: terminating ircd", parv[1]);
464 ilog(L_MAIN, "Error loading core module %s: terminating ircd", parv[1]);
465 exit(0);
466 }
467
468 MyFree(m_bn);
469 return 0;
470 }
471
472 /* list modules .. */
473 static int
474 mo_modlist(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
475 {
476 int i;
477
478 if(!IsOperAdmin(source_p))
479 {
480 sendto_one(source_p, form_str(ERR_NOPRIVS),
481 me.name, source_p->name, "admin");
482 return 0;
483 }
484
485 for (i = 0; i < num_mods; i++)
486 {
487 if(parc > 1)
488 {
489 if(match(parv[1], modlist[i]->name))
490 {
491 sendto_one(source_p, form_str(RPL_MODLIST),
492 me.name, source_p->name,
493 modlist[i]->name,
494 modlist[i]->address,
495 modlist[i]->version, modlist[i]->core ? "(core)" : "");
496 }
497 }
498 else
499 {
500 sendto_one(source_p, form_str(RPL_MODLIST),
501 me.name, source_p->name, modlist[i]->name,
502 modlist[i]->address, modlist[i]->version,
503 modlist[i]->core ? "(core)" : "");
504 }
505 }
506
507 sendto_one(source_p, form_str(RPL_ENDOFMODLIST), me.name, source_p->name);
508 return 0;
509 }
510
511 /* unload and reload all modules */
512 static int
513 mo_modrestart(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
514 {
515 int modnum;
516
517 if(!IsOperAdmin(source_p))
518 {
519 sendto_one(source_p, form_str(ERR_NOPRIVS),
520 me.name, source_p->name, "admin");
521 return 0;
522 }
523
524 sendto_one(source_p, ":%s NOTICE %s :Reloading all modules", me.name, parv[0]);
525
526 modnum = num_mods;
527 while (num_mods)
528 unload_one_module(modlist[0]->name, 0);
529
530 load_all_modules(0);
531 load_core_modules(0);
532 rehash(0);
533
534 sendto_realops_snomask(SNO_GENERAL, L_ALL,
535 "Module Restart: %d modules unloaded, %d modules loaded",
536 modnum, num_mods);
537 ilog(L_MAIN, "Module Restart: %d modules unloaded, %d modules loaded", modnum, num_mods);
538 return 0;
539 }
540
541
542
543 #ifndef RTLD_NOW
544 #define RTLD_NOW RTLD_LAZY /* openbsd deficiency */
545 #endif
546
547 #ifdef CHARYBDIS_PROFILE
548 # ifndef RTLD_PROFILE
549 # warning libdl may not support profiling, sucks. :(
550 # define RTLD_PROFILE 0
551 # endif
552 #endif
553
554 static void increase_modlist(void);
555
556 #define MODS_INCREMENT 10
557
558 static char unknown_ver[] = "<unknown>";
559
560 /* This file contains the core functions to use dynamic libraries.
561 * -TimeMr14C
562 */
563
564
565 #ifdef HAVE_MACH_O_DYLD_H
566 /*
567 ** jmallett's dl*(3) shims for NSModule(3) systems.
568 */
569 #include <mach-o/dyld.h>
570
571 #ifndef HAVE_DLOPEN
572 #ifndef RTLD_LAZY
573 #define RTLD_LAZY 2185 /* built-in dl*(3) don't care */
574 #endif
575
576 void undefinedErrorHandler(const char *);
577 NSModule multipleErrorHandler(NSSymbol, NSModule, NSModule);
578 void linkEditErrorHandler(NSLinkEditErrors, int, const char *, const char *);
579 char *dlerror(void);
580 void *dlopen(char *, int);
581 int dlclose(void *);
582 void *dlsym(void *, char *);
583
584 static int firstLoad = TRUE;
585 static int myDlError;
586 static char *myErrorTable[] = { "Loading file as object failed\n",
587 "Loading file as object succeeded\n",
588 "Not a valid shared object\n",
589 "Architecture of object invalid on this architecture\n",
590 "Invalid or corrupt image\n",
591 "Could not access object\n",
592 "NSCreateObjectFileImageFromFile failed\n",
593 NULL
594 };
595
596 void
597 undefinedErrorHandler(const char *symbolName)
598 {
599 sendto_realops_snomask(SNO_GENERAL, L_ALL, "Undefined symbol: %s", symbolName);
600 ilog(L_MAIN, "Undefined symbol: %s", symbolName);
601 return;
602 }
603
604 NSModule
605 multipleErrorHandler(NSSymbol s, NSModule old, NSModule new)
606 {
607 /* XXX
608 ** This results in substantial leaking of memory... Should free one
609 ** module, maybe?
610 */
611 sendto_realops_snomask(SNO_GENERAL, L_ALL,
612 "Symbol `%s' found in `%s' and `%s'",
613 NSNameOfSymbol(s), NSNameOfModule(old), NSNameOfModule(new));
614 ilog(L_MAIN, "Symbol `%s' found in `%s' and `%s'",
615 NSNameOfSymbol(s), NSNameOfModule(old), NSNameOfModule(new));
616 /* We return which module should be considered valid, I believe */
617 return new;
618 }
619
620 void
621 linkEditErrorHandler(NSLinkEditErrors errorClass, int errnum,
622 const char *fileName, const char *errorString)
623 {
624 sendto_realops_snomask(SNO_GENERAL, L_ALL,
625 "Link editor error: %s for %s", errorString, fileName);
626 ilog(L_MAIN, "Link editor error: %s for %s", errorString, fileName);
627 return;
628 }
629
630 char *
631 dlerror(void)
632 {
633 return myDlError == NSObjectFileImageSuccess ? NULL : myErrorTable[myDlError % 7];
634 }
635
636 void *
637 dlopen(char *filename, int unused)
638 {
639 NSObjectFileImage myImage;
640 NSModule myModule;
641
642 if(firstLoad)
643 {
644 /*
645 ** If we are loading our first symbol (huzzah!) we should go ahead
646 ** and install link editor error handling!
647 */
648 NSLinkEditErrorHandlers linkEditorErrorHandlers;
649
650 linkEditorErrorHandlers.undefined = undefinedErrorHandler;
651 linkEditorErrorHandlers.multiple = multipleErrorHandler;
652 linkEditorErrorHandlers.linkEdit = linkEditErrorHandler;
653 NSInstallLinkEditErrorHandlers(&linkEditorErrorHandlers);
654 firstLoad = FALSE;
655 }
656 myDlError = NSCreateObjectFileImageFromFile(filename, &myImage);
657 if(myDlError != NSObjectFileImageSuccess)
658 {
659 return NULL;
660 }
661 myModule = NSLinkModule(myImage, filename, NSLINKMODULE_OPTION_PRIVATE);
662 return (void *) myModule;
663 }
664
665 int
666 dlclose(void *myModule)
667 {
668 NSUnLinkModule(myModule, FALSE);
669 return 0;
670 }
671
672 void *
673 dlsym(void *myModule, char *mySymbolName)
674 {
675 NSSymbol mySymbol;
676
677 mySymbol = NSLookupSymbolInModule((NSModule) myModule, mySymbolName);
678 return NSAddressOfSymbol(mySymbol);
679 }
680 #endif
681 #endif
682
683
684 /*
685 * HPUX dl compat functions
686 */
687 #if defined(HAVE_SHL_LOAD) && !defined(HAVE_DLOPEN)
688 #define RTLD_LAZY BIND_DEFERRED
689 #define RTLD_GLOBAL DYNAMIC_PATH
690 #define dlopen(file,mode) (void *)shl_load((file), (mode), (long) 0)
691 #define dlclose(handle) shl_unload((shl_t)(handle))
692 #define dlsym(handle,name) hpux_dlsym(handle,name)
693 #define dlerror() strerror(errno)
694
695 static void *
696 hpux_dlsym(void *handle, char *name)
697 {
698 void *sym_addr;
699 if(!shl_findsym((shl_t *) & handle, name, TYPE_UNDEFINED, &sym_addr))
700 return sym_addr;
701 return NULL;
702 }
703
704 #endif
705
706 /* unload_one_module()
707 *
708 * inputs - name of module to unload
709 * - 1 to say modules unloaded, 0 to not
710 * output - 0 if successful, -1 if error
711 * side effects - module is unloaded
712 */
713 int
714 unload_one_module(const char *name, int warn)
715 {
716 int modindex;
717
718 if((modindex = findmodule_byname(name)) == -1)
719 return -1;
720
721 /*
722 ** XXX - The type system in C does not allow direct conversion between
723 ** data and function pointers, but as it happens, most C compilers will
724 ** safely do this, however it is a theoretical overlow to cast as we
725 ** must do here. I have library functions to take care of this, but
726 ** despite being more "correct" for the C language, this is more
727 ** practical. Removing the abuse of the ability to cast ANY pointer
728 ** to and from an integer value here will break some compilers.
729 ** -jmallett
730 */
731 /* Left the comment in but the code isn't here any more -larne */
732 switch (modlist[modindex]->mapi_version)
733 {
734 case 1:
735 {
736 struct mapi_mheader_av1 *mheader = modlist[modindex]->mapi_header;
737 if(mheader->mapi_command_list)
738 {
739 struct Message **m;
740 for (m = mheader->mapi_command_list; *m; ++m)
741 mod_del_cmd(*m);
742 }
743
744 /* hook events are never removed, we simply lose the
745 * ability to call them --fl
746 */
747 if(mheader->mapi_hfn_list)
748 {
749 mapi_hfn_list_av1 *m;
750 for (m = mheader->mapi_hfn_list; m->hapi_name; ++m)
751 remove_hook(m->hapi_name, m->fn);
752 }
753
754 if(mheader->mapi_unregister)
755 mheader->mapi_unregister();
756 break;
757 }
758 default:
759 sendto_realops_snomask(SNO_GENERAL, L_ALL,
760 "Unknown/unsupported MAPI version %d when unloading %s!",
761 modlist[modindex]->mapi_version, modlist[modindex]->name);
762 ilog(L_MAIN, "Unknown/unsupported MAPI version %d when unloading %s!",
763 modlist[modindex]->mapi_version, modlist[modindex]->name);
764 break;
765 }
766
767 dlclose(modlist[modindex]->address);
768
769 MyFree(modlist[modindex]->name);
770 memcpy(&modlist[modindex], &modlist[modindex + 1],
771 sizeof(struct module) * ((num_mods - 1) - modindex));
772
773 if(num_mods != 0)
774 num_mods--;
775
776 if(warn == 1)
777 {
778 ilog(L_MAIN, "Module %s unloaded", name);
779 sendto_realops_snomask(SNO_GENERAL, L_ALL, "Module %s unloaded", name);
780 }
781
782 return 0;
783 }
784
785
786 /*
787 * load_a_module()
788 *
789 * inputs - path name of module, int to notice, int of core
790 * output - -1 if error 0 if success
791 * side effects - loads a module if successful
792 */
793 int
794 load_a_module(const char *path, int warn, int core)
795 {
796 void *tmpptr = NULL;
797
798 char *mod_basename;
799 const char *ver;
800
801 int *mapi_version;
802
803 mod_basename = irc_basename(path);
804
805 #ifdef CHARYBDIS_PROFILE
806 tmpptr = dlopen(path, RTLD_NOW | RTLD_PROFILE);
807 #else
808 tmpptr = dlopen(path, RTLD_NOW);
809 #endif
810
811 if(tmpptr == NULL)
812 {
813 const char *err = dlerror();
814
815 sendto_realops_snomask(SNO_GENERAL, L_ALL,
816 "Error loading module %s: %s", mod_basename, err);
817 ilog(L_MAIN, "Error loading module %s: %s", mod_basename, err);
818 MyFree(mod_basename);
819 return -1;
820 }
821
822
823 /*
824 * _mheader is actually a struct mapi_mheader_*, but mapi_version
825 * is always the first member of this structure, so we treate it
826 * as a single int in order to determine the API version.
827 * -larne.
828 */
829 mapi_version = (int *) (uintptr_t) dlsym(tmpptr, "_mheader");
830 if((mapi_version == NULL
831 && (mapi_version = (int *) (uintptr_t) dlsym(tmpptr, "__mheader")) == NULL)
832 || MAPI_MAGIC(*mapi_version) != MAPI_MAGIC_HDR)
833 {
834 sendto_realops_snomask(SNO_GENERAL, L_ALL,
835 "Data format error: module %s has no MAPI header.",
836 mod_basename);
837 ilog(L_MAIN, "Data format error: module %s has no MAPI header.", mod_basename);
838 (void) dlclose(tmpptr);
839 MyFree(mod_basename);
840 return -1;
841 }
842
843 switch (MAPI_VERSION(*mapi_version))
844 {
845 case 1:
846 {
847 struct mapi_mheader_av1 *mheader = (struct mapi_mheader_av1 *) mapi_version; /* see above */
848 if(mheader->mapi_register && (mheader->mapi_register() == -1))
849 {
850 ilog(L_MAIN, "Module %s indicated failure during load.",
851 mod_basename);
852 sendto_realops_snomask(SNO_GENERAL, L_ALL,
853 "Module %s indicated failure during load.",
854 mod_basename);
855 dlclose(tmpptr);
856 MyFree(mod_basename);
857 return -1;
858 }
859 if(mheader->mapi_command_list)
860 {
861 struct Message **m;
862 for (m = mheader->mapi_command_list; *m; ++m)
863 mod_add_cmd(*m);
864 }
865
866 if(mheader->mapi_hook_list)
867 {
868 mapi_hlist_av1 *m;
869 for (m = mheader->mapi_hook_list; m->hapi_name; ++m)
870 *m->hapi_id = register_hook(m->hapi_name);
871 }
872
873 if(mheader->mapi_hfn_list)
874 {
875 mapi_hfn_list_av1 *m;
876 for (m = mheader->mapi_hfn_list; m->hapi_name; ++m)
877 add_hook(m->hapi_name, m->fn);
878 }
879
880 ver = mheader->mapi_module_version;
881 break;
882 }
883
884 default:
885 ilog(L_MAIN, "Module %s has unknown/unsupported MAPI version %d.",
886 mod_basename, MAPI_VERSION(*mapi_version));
887 sendto_realops_snomask(SNO_GENERAL, L_ALL,
888 "Module %s has unknown/unsupported MAPI version %d.",
889 mod_basename, *mapi_version);
890 dlclose(tmpptr);
891 MyFree(mod_basename);
892 return -1;
893 }
894
895 if(ver == NULL)
896 ver = unknown_ver;
897
898 increase_modlist();
899
900 modlist[num_mods] = MyMalloc(sizeof(struct module));
901 modlist[num_mods]->address = tmpptr;
902 modlist[num_mods]->version = ver;
903 modlist[num_mods]->core = core;
904 DupString(modlist[num_mods]->name, mod_basename);
905 modlist[num_mods]->mapi_header = mapi_version;
906 modlist[num_mods]->mapi_version = MAPI_VERSION(*mapi_version);
907 num_mods++;
908
909 if(warn == 1)
910 {
911 sendto_realops_snomask(SNO_GENERAL, L_ALL,
912 "Module %s [version: %s; MAPI version: %d] loaded at 0x%lx",
913 mod_basename, ver, MAPI_VERSION(*mapi_version),
914 (unsigned long) tmpptr);
915 ilog(L_MAIN, "Module %s [version: %s; MAPI version: %d] loaded at 0x%lx",
916 mod_basename, ver, MAPI_VERSION(*mapi_version), (unsigned long) tmpptr);
917 }
918 MyFree(mod_basename);
919 return 0;
920 }
921
922 /*
923 * increase_modlist
924 *
925 * inputs - NONE
926 * output - NONE
927 * side effects - expand the size of modlist if necessary
928 */
929 static void
930 increase_modlist(void)
931 {
932 struct module **new_modlist = NULL;
933
934 if((num_mods + 1) < max_mods)
935 return;
936
937 new_modlist = (struct module **) MyMalloc(sizeof(struct module) *
938 (max_mods + MODS_INCREMENT));
939 memcpy((void *) new_modlist, (void *) modlist, sizeof(struct module) * num_mods);
940
941 MyFree(modlist);
942 modlist = new_modlist;
943 max_mods += MODS_INCREMENT;
944 }
945
946 #else /* STATIC_MODULES */
947
948 /* load_all_modules()
949 *
950 * input -
951 * output -
952 * side effects - all the msgtabs are added for static modules
953 */
954 void
955 load_all_modules(int warn)
956 {
957 load_static_modules();
958 }
959
960 #endif /* STATIC_MODULES */