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