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