2 * ircd-ratbox: A slightly useful ircd.
3 * modules.c: A module loader.
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
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.
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.
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
24 * $Id: modules.c 3161 2007-01-25 07:23:01Z nenolod $
36 #include "s_newconf.h"
39 #include "ircd_defs.h"
40 #include "irc_string.h"
43 #include "sprintf_irc.h"
48 * I have moved the dl* function definitions and
49 * the two functions (load_a_module / unload_a_module) to the
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.
58 #ifndef STATIC_MODULES
60 struct module **modlist
= NULL
;
62 static const char *core_module_table
[] = {
79 #define MODS_INCREMENT 10
81 int max_mods
= MODS_INCREMENT
;
83 static dlink_list mod_paths
;
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 **);
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}}
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}}
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}}
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}}
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}}
116 extern struct Message error_msgtab
;
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
);
127 /* Add the default paths we look in to the module system --nenolod */
128 mod_add_path(MODPATH
);
129 mod_add_path(AUTOMODPATH
);
136 * side effects - returns a module path from path
138 static struct module_path
*
139 mod_find_path(const char *path
)
142 struct module_path
*mpath
;
144 DLINK_FOREACH(ptr
, mod_paths
.head
)
148 if(!strcmp(path
, mpath
->path
))
159 * side effects - adds path to list
162 mod_add_path(const char *path
)
164 struct module_path
*pathst
;
166 if(mod_find_path(path
))
169 pathst
= MyMalloc(sizeof(struct module_path
));
171 strcpy(pathst
->path
, path
);
172 dlinkAddAlloc(pathst
, &mod_paths
);
179 * side effects - clear the lists of paths
182 mod_clear_paths(void)
184 dlink_node
*ptr
, *next_ptr
;
186 DLINK_FOREACH_SAFE(ptr
, next_ptr
, mod_paths
.head
)
189 free_dlink_node(ptr
);
192 mod_paths
.head
= mod_paths
.tail
= NULL
;
193 mod_paths
.length
= 0;
203 irc_basename(const char *path
)
205 char *mod_basename
= MyMalloc(strlen(path
) + 1);
208 if(!(s
= strrchr(path
, '/')))
213 (void) strcpy(mod_basename
, s
);
225 findmodule_byname(const char *name
)
229 for (i
= 0; i
< num_mods
; i
++)
231 if(!irccmp(modlist
[i
]->name
, name
))
237 /* load_all_modules()
244 load_all_modules(int warn
)
246 DIR *system_module_dir
= NULL
;
247 struct dirent
*ldirent
= NULL
;
248 char module_fq_name
[PATH_MAX
+ 1];
253 modlist
= (struct module **) MyMalloc(sizeof(struct module) * (MODS_INCREMENT
));
255 max_mods
= MODS_INCREMENT
;
257 system_module_dir
= opendir(AUTOMODPATH
);
259 if(system_module_dir
== NULL
)
261 ilog(L_MAIN
, "Could not load modules from %s: %s", AUTOMODPATH
, strerror(errno
));
265 while ((ldirent
= readdir(system_module_dir
)) != NULL
)
267 len
= strlen(ldirent
->d_name
);
268 if((len
> 3) && !strcmp(ldirent
->d_name
+len
-3, SHARED_SUFFIX
))
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);
275 (void) closedir(system_module_dir
);
278 /* load_core_modules()
282 * side effects - core modules are loaded, if any fail, kill ircd
285 load_core_modules(int warn
)
287 char module_name
[MAXPATHLEN
];
291 for (i
= 0; core_module_table
[i
]; i
++)
293 ircsnprintf(module_name
, sizeof(module_name
), "%s/%s%s", MODPATH
,
294 core_module_table
[i
], SHARED_SUFFIX
);
296 if(load_a_module(module_name
, warn
, 1) == -1)
299 "Error loading core module %s%s: terminating ircd",
300 core_module_table
[i
], SHARED_SUFFIX
);
313 load_one_module(const char *path
, int coremodule
)
315 char modpath
[MAXPATHLEN
];
317 struct module_path
*mpath
;
321 if (server_state_foreground
== 1)
322 inotice("loading module %s ...", path
);
324 DLINK_FOREACH(pathst
, mod_paths
.head
)
326 mpath
= pathst
->data
;
328 ircsnprintf(modpath
, sizeof(modpath
), "%s/%s", mpath
->path
, path
);
329 if((strstr(modpath
, "../") == NULL
) && (strstr(modpath
, "/..") == NULL
))
331 if(stat(modpath
, &statbuf
) == 0)
333 if(S_ISREG(statbuf
.st_mode
))
335 /* Regular files only please */
337 return load_a_module(modpath
, 1, 1);
339 return load_a_module(modpath
, 1, 0);
346 sendto_realops_snomask(SNO_GENERAL
, L_ALL
, "Cannot locate module %s", path
);
351 /* load a module .. */
353 mo_modload(struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
357 if(!IsOperAdmin(source_p
))
359 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
360 me
.name
, source_p
->name
, "admin");
364 m_bn
= irc_basename(parv
[1]);
366 if(findmodule_byname(m_bn
) != -1)
368 sendto_one_notice(source_p
, ":Module %s is already loaded", m_bn
);
373 load_one_module(parv
[1], 0);
381 /* unload a module .. */
383 mo_modunload(struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
388 if(!IsOperAdmin(source_p
))
390 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
391 me
.name
, source_p
->name
, "admin");
395 m_bn
= irc_basename(parv
[1]);
397 if((modindex
= findmodule_byname(m_bn
)) == -1)
399 sendto_one_notice(source_p
, ":Module %s is not loaded", m_bn
);
404 if(modlist
[modindex
]->core
== 1)
406 sendto_one_notice(source_p
, ":Module %s is a core module and may not be unloaded", m_bn
);
411 if(unload_one_module(m_bn
, 1) == -1)
413 sendto_one_notice(source_p
, ":Module %s is not loaded", m_bn
);
420 /* unload and load in one! */
422 mo_modreload(struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
428 if(!IsOperAdmin(source_p
))
430 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
431 me
.name
, source_p
->name
, "admin");
435 m_bn
= irc_basename(parv
[1]);
437 if((modindex
= findmodule_byname(m_bn
)) == -1)
439 sendto_one_notice(source_p
, ":Module %s is not loaded", m_bn
);
444 check_core
= modlist
[modindex
]->core
;
446 if(unload_one_module(m_bn
, 1) == -1)
448 sendto_one_notice(source_p
, ":Module %s is not loaded", m_bn
);
453 if((load_one_module(parv
[1], check_core
) == -1) && check_core
)
455 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
456 "Error reloading core module: %s: terminating ircd", parv
[1]);
457 ilog(L_MAIN
, "Error loading core module %s: terminating ircd", parv
[1]);
465 /* list modules .. */
467 mo_modlist(struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
471 if(!IsOperAdmin(source_p
))
473 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
474 me
.name
, source_p
->name
, "admin");
478 for (i
= 0; i
< num_mods
; i
++)
482 if(match(parv
[1], modlist
[i
]->name
))
484 sendto_one(source_p
, form_str(RPL_MODLIST
),
485 me
.name
, source_p
->name
,
488 modlist
[i
]->version
, modlist
[i
]->core
? "(core)" : "");
493 sendto_one(source_p
, form_str(RPL_MODLIST
),
494 me
.name
, source_p
->name
, modlist
[i
]->name
,
495 modlist
[i
]->address
, modlist
[i
]->version
,
496 modlist
[i
]->core
? "(core)" : "");
500 sendto_one(source_p
, form_str(RPL_ENDOFMODLIST
), me
.name
, source_p
->name
);
504 /* unload and reload all modules */
506 mo_modrestart(struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
510 if(!IsOperAdmin(source_p
))
512 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
513 me
.name
, source_p
->name
, "admin");
517 sendto_one_notice(source_p
, ":Reloading all modules");
521 unload_one_module(modlist
[0]->name
, 0);
524 load_core_modules(0);
527 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
528 "Module Restart: %d modules unloaded, %d modules loaded",
530 ilog(L_MAIN
, "Module Restart: %d modules unloaded, %d modules loaded", modnum
, num_mods
);
537 #define RTLD_NOW RTLD_LAZY /* openbsd deficiency */
540 #ifdef CHARYBDIS_PROFILE
541 # ifndef RTLD_PROFILE
542 # warning libdl may not support profiling, sucks. :(
543 # define RTLD_PROFILE 0
547 static void increase_modlist(void);
549 #define MODS_INCREMENT 10
551 static char unknown_ver
[] = "<unknown>";
553 /* This file contains the core functions to use dynamic libraries.
558 #ifdef HAVE_MACH_O_DYLD_H
560 ** jmallett's dl*(3) shims for NSModule(3) systems.
562 #include <mach-o/dyld.h>
566 #define RTLD_LAZY 2185 /* built-in dl*(3) don't care */
569 void undefinedErrorHandler(const char *);
570 NSModule
multipleErrorHandler(NSSymbol
, NSModule
, NSModule
);
571 void linkEditErrorHandler(NSLinkEditErrors
, int, const char *, const char *);
573 void *dlopen(char *, int);
575 void *dlsym(void *, char *);
577 static int firstLoad
= TRUE
;
578 static int myDlError
;
579 static char *myErrorTable
[] = { "Loading file as object failed\n",
580 "Loading file as object succeeded\n",
581 "Not a valid shared object\n",
582 "Architecture of object invalid on this architecture\n",
583 "Invalid or corrupt image\n",
584 "Could not access object\n",
585 "NSCreateObjectFileImageFromFile failed\n",
590 undefinedErrorHandler(const char *symbolName
)
592 sendto_realops_snomask(SNO_GENERAL
, L_ALL
, "Undefined symbol: %s", symbolName
);
593 ilog(L_MAIN
, "Undefined symbol: %s", symbolName
);
598 multipleErrorHandler(NSSymbol s
, NSModule old
, NSModule
new)
601 ** This results in substantial leaking of memory... Should free one
604 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
605 "Symbol `%s' found in `%s' and `%s'",
606 NSNameOfSymbol(s
), NSNameOfModule(old
), NSNameOfModule(new));
607 ilog(L_MAIN
, "Symbol `%s' found in `%s' and `%s'",
608 NSNameOfSymbol(s
), NSNameOfModule(old
), NSNameOfModule(new));
609 /* We return which module should be considered valid, I believe */
614 linkEditErrorHandler(NSLinkEditErrors errorClass
, int errnum
,
615 const char *fileName
, const char *errorString
)
617 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
618 "Link editor error: %s for %s", errorString
, fileName
);
619 ilog(L_MAIN
, "Link editor error: %s for %s", errorString
, fileName
);
626 return myDlError
== NSObjectFileImageSuccess
? NULL
: myErrorTable
[myDlError
% 7];
630 dlopen(char *filename
, int unused
)
632 NSObjectFileImage myImage
;
638 ** If we are loading our first symbol (huzzah!) we should go ahead
639 ** and install link editor error handling!
641 NSLinkEditErrorHandlers linkEditorErrorHandlers
;
643 linkEditorErrorHandlers
.undefined
= undefinedErrorHandler
;
644 linkEditorErrorHandlers
.multiple
= multipleErrorHandler
;
645 linkEditorErrorHandlers
.linkEdit
= linkEditErrorHandler
;
646 NSInstallLinkEditErrorHandlers(&linkEditorErrorHandlers
);
649 myDlError
= NSCreateObjectFileImageFromFile(filename
, &myImage
);
650 if(myDlError
!= NSObjectFileImageSuccess
)
654 myModule
= NSLinkModule(myImage
, filename
, NSLINKMODULE_OPTION_PRIVATE
);
655 return (void *) myModule
;
659 dlclose(void *myModule
)
661 NSUnLinkModule(myModule
, FALSE
);
666 dlsym(void *myModule
, char *mySymbolName
)
670 mySymbol
= NSLookupSymbolInModule((NSModule
) myModule
, mySymbolName
);
671 return NSAddressOfSymbol(mySymbol
);
678 * HPUX dl compat functions
680 #if defined(HAVE_SHL_LOAD) && !defined(HAVE_DLOPEN)
681 #define RTLD_LAZY BIND_DEFERRED
682 #define RTLD_GLOBAL DYNAMIC_PATH
683 #define dlopen(file,mode) (void *)shl_load((file), (mode), (long) 0)
684 #define dlclose(handle) shl_unload((shl_t)(handle))
685 #define dlsym(handle,name) hpux_dlsym(handle,name)
686 #define dlerror() strerror(errno)
689 hpux_dlsym(void *handle
, char *name
)
692 if(!shl_findsym((shl_t
*) & handle
, name
, TYPE_UNDEFINED
, &sym_addr
))
699 /* unload_one_module()
701 * inputs - name of module to unload
702 * - 1 to say modules unloaded, 0 to not
703 * output - 0 if successful, -1 if error
704 * side effects - module is unloaded
707 unload_one_module(const char *name
, int warn
)
711 if((modindex
= findmodule_byname(name
)) == -1)
715 ** XXX - The type system in C does not allow direct conversion between
716 ** data and function pointers, but as it happens, most C compilers will
717 ** safely do this, however it is a theoretical overlow to cast as we
718 ** must do here. I have library functions to take care of this, but
719 ** despite being more "correct" for the C language, this is more
720 ** practical. Removing the abuse of the ability to cast ANY pointer
721 ** to and from an integer value here will break some compilers.
724 /* Left the comment in but the code isn't here any more -larne */
725 switch (modlist
[modindex
]->mapi_version
)
729 struct mapi_mheader_av1
*mheader
= modlist
[modindex
]->mapi_header
;
730 if(mheader
->mapi_command_list
)
733 for (m
= mheader
->mapi_command_list
; *m
; ++m
)
737 /* hook events are never removed, we simply lose the
738 * ability to call them --fl
740 if(mheader
->mapi_hfn_list
)
742 mapi_hfn_list_av1
*m
;
743 for (m
= mheader
->mapi_hfn_list
; m
->hapi_name
; ++m
)
744 remove_hook(m
->hapi_name
, m
->fn
);
747 if(mheader
->mapi_unregister
)
748 mheader
->mapi_unregister();
752 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
753 "Unknown/unsupported MAPI version %d when unloading %s!",
754 modlist
[modindex
]->mapi_version
, modlist
[modindex
]->name
);
755 ilog(L_MAIN
, "Unknown/unsupported MAPI version %d when unloading %s!",
756 modlist
[modindex
]->mapi_version
, modlist
[modindex
]->name
);
760 dlclose(modlist
[modindex
]->address
);
762 MyFree(modlist
[modindex
]->name
);
763 memcpy(&modlist
[modindex
], &modlist
[modindex
+ 1],
764 sizeof(struct module) * ((num_mods
- 1) - modindex
));
771 ilog(L_MAIN
, "Module %s unloaded", name
);
772 sendto_realops_snomask(SNO_GENERAL
, L_ALL
, "Module %s unloaded", name
);
782 * inputs - path name of module, int to notice, int of core
783 * output - -1 if error 0 if success
784 * side effects - loads a module if successful
787 load_a_module(const char *path
, int warn
, int core
)
796 mod_basename
= irc_basename(path
);
798 #ifdef CHARYBDIS_PROFILE
799 tmpptr
= dlopen(path
, RTLD_NOW
| RTLD_PROFILE
);
801 tmpptr
= dlopen(path
, RTLD_NOW
);
806 const char *err
= dlerror();
808 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
809 "Error loading module %s: %s", mod_basename
, err
);
810 ilog(L_MAIN
, "Error loading module %s: %s", mod_basename
, err
);
811 MyFree(mod_basename
);
817 * _mheader is actually a struct mapi_mheader_*, but mapi_version
818 * is always the first member of this structure, so we treate it
819 * as a single int in order to determine the API version.
822 mapi_version
= (int *) (uintptr_t) dlsym(tmpptr
, "_mheader");
823 if((mapi_version
== NULL
824 && (mapi_version
= (int *) (uintptr_t) dlsym(tmpptr
, "__mheader")) == NULL
)
825 || MAPI_MAGIC(*mapi_version
) != MAPI_MAGIC_HDR
)
827 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
828 "Data format error: module %s has no MAPI header.",
830 ilog(L_MAIN
, "Data format error: module %s has no MAPI header.", mod_basename
);
831 (void) dlclose(tmpptr
);
832 MyFree(mod_basename
);
836 switch (MAPI_VERSION(*mapi_version
))
840 struct mapi_mheader_av1
*mheader
= (struct mapi_mheader_av1
*) mapi_version
; /* see above */
841 if(mheader
->mapi_register
&& (mheader
->mapi_register() == -1))
843 ilog(L_MAIN
, "Module %s indicated failure during load.",
845 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
846 "Module %s indicated failure during load.",
849 MyFree(mod_basename
);
852 if(mheader
->mapi_command_list
)
855 for (m
= mheader
->mapi_command_list
; *m
; ++m
)
859 if(mheader
->mapi_hook_list
)
862 for (m
= mheader
->mapi_hook_list
; m
->hapi_name
; ++m
)
863 *m
->hapi_id
= register_hook(m
->hapi_name
);
866 if(mheader
->mapi_hfn_list
)
868 mapi_hfn_list_av1
*m
;
869 for (m
= mheader
->mapi_hfn_list
; m
->hapi_name
; ++m
)
870 add_hook(m
->hapi_name
, m
->fn
);
873 ver
= mheader
->mapi_module_version
;
878 ilog(L_MAIN
, "Module %s has unknown/unsupported MAPI version %d.",
879 mod_basename
, MAPI_VERSION(*mapi_version
));
880 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
881 "Module %s has unknown/unsupported MAPI version %d.",
882 mod_basename
, *mapi_version
);
884 MyFree(mod_basename
);
893 modlist
[num_mods
] = MyMalloc(sizeof(struct module));
894 modlist
[num_mods
]->address
= tmpptr
;
895 modlist
[num_mods
]->version
= ver
;
896 modlist
[num_mods
]->core
= core
;
897 DupString(modlist
[num_mods
]->name
, mod_basename
);
898 modlist
[num_mods
]->mapi_header
= mapi_version
;
899 modlist
[num_mods
]->mapi_version
= MAPI_VERSION(*mapi_version
);
904 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
905 "Module %s [version: %s; MAPI version: %d] loaded at 0x%lx",
906 mod_basename
, ver
, MAPI_VERSION(*mapi_version
),
907 (unsigned long) tmpptr
);
908 ilog(L_MAIN
, "Module %s [version: %s; MAPI version: %d] loaded at 0x%lx",
909 mod_basename
, ver
, MAPI_VERSION(*mapi_version
), (unsigned long) tmpptr
);
911 MyFree(mod_basename
);
920 * side effects - expand the size of modlist if necessary
923 increase_modlist(void)
925 struct module **new_modlist
= NULL
;
927 if((num_mods
+ 1) < max_mods
)
930 new_modlist
= (struct module **) MyMalloc(sizeof(struct module) *
931 (max_mods
+ MODS_INCREMENT
));
932 memcpy((void *) new_modlist
, (void *) modlist
, sizeof(struct module) * num_mods
);
935 modlist
= new_modlist
;
936 max_mods
+= MODS_INCREMENT
;
939 #else /* STATIC_MODULES */
941 /* load_all_modules()
945 * side effects - all the msgtabs are added for static modules
948 load_all_modules(int warn
)
950 load_static_modules();
953 #endif /* STATIC_MODULES */