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
32 #include "s_newconf.h"
35 #include "ircd_defs.h"
38 #include "capability.h"
44 # error "Solanum requires loadable module support."
47 rb_dlink_list module_list
;
48 rb_dlink_list mod_paths
;
50 static const char *core_module_table
[] = {
69 #define MOD_WARN_DELTA (90 * 86400) /* time in seconds, 86400 seconds in a day */
76 ilog(L_MAIN
, "lt_dlinit failed");
80 /* Add the default paths we look in to the module system --nenolod */
81 mod_add_path(ircd_paths
[IRCD_PATH_MODULES
]);
82 mod_add_path(ircd_paths
[IRCD_PATH_AUTOLOAD_MODULES
]);
85 static unsigned int prev_caps
;
88 mod_remember_clicaps(void)
90 prev_caps
= capability_index_mask(cli_capindex
);
94 mod_notify_clicaps(void)
96 unsigned int cur_caps
= capability_index_mask(cli_capindex
);
97 unsigned int del
= prev_caps
& ~cur_caps
;
98 unsigned int new = cur_caps
& ~prev_caps
;
101 sendto_local_clients_with_capability(CLICAP_CAP_NOTIFY
, ":%s CAP * DEL :%s",
102 me
.name
, capability_index_list(cli_capindex
, del
));
104 sendto_local_clients_with_capability(CLICAP_CAP_NOTIFY
, ":%s CAP * NEW :%s",
105 me
.name
, capability_index_list(cli_capindex
, new));
112 * side effects - returns a module path from path
115 mod_find_path(const char *path
)
120 RB_DLINK_FOREACH(ptr
, mod_paths
.head
)
124 if(!strcmp(path
, mpath
))
135 * side effects - adds path to list
138 mod_add_path(const char *path
)
142 if(mod_find_path(path
))
145 pathst
= rb_strdup(path
);
146 rb_dlinkAddAlloc(pathst
, &mod_paths
);
153 * side effects - clear the lists of paths
156 mod_clear_paths(void)
158 rb_dlink_node
*ptr
, *next_ptr
;
160 RB_DLINK_FOREACH_SAFE(ptr
, next_ptr
, mod_paths
.head
)
163 rb_free_rb_dlink_node(ptr
);
166 mod_paths
.head
= mod_paths
.tail
= NULL
;
167 mod_paths
.length
= 0;
172 * input - module to load
173 * output - index of module on success, -1 on failure
174 * side effects - none
177 findmodule_byname(const char *name
)
180 char name_ext
[PATH_MAX
+ 1];
182 rb_strlcpy(name_ext
, name
, sizeof name_ext
);
183 rb_strlcat(name_ext
, LT_MODULE_EXT
, sizeof name_ext
);
185 RB_DLINK_FOREACH(ptr
, module_list
.head
)
187 struct module *mod
= ptr
->data
;
189 if(!irccmp(mod
->name
, name
))
192 if(!irccmp(mod
->name
, name_ext
))
199 /* load_all_modules()
206 load_all_modules(bool warn
)
208 DIR *system_module_dir
= NULL
;
209 struct dirent
*ldirent
= NULL
;
210 char module_fq_name
[PATH_MAX
+ 1];
211 size_t module_ext_len
= strlen(LT_MODULE_EXT
);
213 system_module_dir
= opendir(ircd_paths
[IRCD_PATH_AUTOLOAD_MODULES
]);
215 if(system_module_dir
== NULL
)
217 ilog(L_MAIN
, "Could not load modules from %s: %s", ircd_paths
[IRCD_PATH_AUTOLOAD_MODULES
], strerror(errno
));
221 while ((ldirent
= readdir(system_module_dir
)) != NULL
)
223 size_t len
= strlen(ldirent
->d_name
);
225 if(len
> module_ext_len
&&
226 rb_strncasecmp(ldirent
->d_name
+ (len
- module_ext_len
), LT_MODULE_EXT
, module_ext_len
) == 0)
228 (void) snprintf(module_fq_name
, sizeof(module_fq_name
), "%s%c%s",
229 ircd_paths
[IRCD_PATH_AUTOLOAD_MODULES
], RB_PATH_SEPARATOR
, ldirent
->d_name
);
230 (void) load_a_module(module_fq_name
, warn
, MAPI_ORIGIN_CORE
, false);
234 (void) closedir(system_module_dir
);
237 /* load_core_modules()
241 * side effects - core modules are loaded, if any fail, kill ircd
244 load_core_modules(bool warn
)
246 char module_name
[PATH_MAX
];
250 for (i
= 0; core_module_table
[i
]; i
++)
252 snprintf(module_name
, sizeof(module_name
), "%s%c%s", ircd_paths
[IRCD_PATH_MODULES
], RB_PATH_SEPARATOR
,
253 core_module_table
[i
]);
255 if(load_a_module(module_name
, warn
, MAPI_ORIGIN_CORE
, true) == false)
258 "Error loading core module %s: terminating ircd",
259 core_module_table
[i
]);
272 load_one_module(const char *path
, int origin
, bool coremodule
)
274 char modpath
[PATH_MAX
];
275 rb_dlink_node
*pathst
;
277 if (server_state_foreground
)
278 inotice("loading module %s ...", path
);
281 origin
= MAPI_ORIGIN_CORE
;
283 RB_DLINK_FOREACH(pathst
, mod_paths
.head
)
286 const char *mpath
= pathst
->data
;
288 snprintf(modpath
, sizeof(modpath
), "%s%c%s%s", mpath
, RB_PATH_SEPARATOR
, path
, LT_MODULE_EXT
);
289 if((strstr(modpath
, "../") == NULL
) && (strstr(modpath
, "/..") == NULL
))
291 if(stat(modpath
, &statbuf
) == 0 && S_ISREG(statbuf
.st_mode
))
293 /* Regular files only please */
294 return load_a_module(modpath
, true, origin
, coremodule
);
300 sendto_realops_snomask(SNO_GENERAL
, L_NETWIDE
, "Cannot locate module %s", path
);
302 if (server_state_foreground
)
303 ierror("cannot locate module %s", path
);
308 static char unknown_ver
[] = "<unknown>";
309 static char unknown_description
[] = "<none>";
311 /* unload_one_module()
313 * inputs - name of module to unload
314 * - true to say modules unloaded, false to not
315 * output - true if successful, false if error
316 * side effects - module is unloaded
319 unload_one_module(const char *name
, bool warn
)
323 if((mod
= findmodule_byname(name
)) == NULL
)
327 ** XXX - The type system in C does not allow direct conversion between
328 ** data and function pointers, but as it happens, most C compilers will
329 ** safely do this, however it is a theoretical overlow to cast as we
330 ** must do here. I have library functions to take care of this, but
331 ** despite being more "correct" for the C language, this is more
332 ** practical. Removing the abuse of the ability to cast ANY pointer
333 ** to and from an integer value here will break some compilers.
336 /* Left the comment in but the code isn't here any more -larne */
337 switch (mod
->mapi_version
)
341 struct mapi_mheader_av1
*mheader
= mod
->mapi_header
;
342 if(mheader
->mapi_command_list
)
345 for (m
= mheader
->mapi_command_list
; *m
; ++m
)
349 /* hook events are never removed, we simply lose the
350 * ability to call them --fl
352 if(mheader
->mapi_hfn_list
)
354 mapi_hfn_list_av1
*m
;
355 for (m
= mheader
->mapi_hfn_list
; m
->hapi_name
; ++m
)
356 remove_hook(m
->hapi_name
, m
->fn
);
359 if(mheader
->mapi_unregister
)
360 mheader
->mapi_unregister();
365 struct mapi_mheader_av2
*mheader
= mod
->mapi_header
;
367 /* XXX duplicate code :( */
368 if(mheader
->mapi_command_list
)
371 for (m
= mheader
->mapi_command_list
; *m
; ++m
)
375 /* hook events are never removed, we simply lose the
376 * ability to call them --fl
378 if(mheader
->mapi_hfn_list
)
380 mapi_hfn_list_av1
*m
;
381 for (m
= mheader
->mapi_hfn_list
; m
->hapi_name
; ++m
)
382 remove_hook(m
->hapi_name
, m
->fn
);
385 if(mheader
->mapi_unregister
)
386 mheader
->mapi_unregister();
388 if(mheader
->mapi_cap_list
)
390 mapi_cap_list_av2
*m
;
391 for (m
= mheader
->mapi_cap_list
; m
->cap_name
; ++m
)
393 struct CapabilityIndex
*idx
;
395 switch (m
->cap_index
)
397 case MAPI_CAP_CLIENT
:
400 case MAPI_CAP_SERVER
:
404 sendto_realops_snomask(SNO_GENERAL
, L_NETWIDE
,
405 "Unknown/unsupported CAP index found of type %d on capability %s when unloading %s",
406 m
->cap_index
, m
->cap_name
, mod
->name
);
408 "Unknown/unsupported CAP index found of type %d on capability %s when unloading %s",
409 m
->cap_index
, m
->cap_name
, mod
->name
);
413 capability_orphan(idx
, m
->cap_name
);
419 sendto_realops_snomask(SNO_GENERAL
, L_NETWIDE
,
420 "Unknown/unsupported MAPI version %d when unloading %s!",
421 mod
->mapi_version
, mod
->name
);
422 ilog(L_MAIN
, "Unknown/unsupported MAPI version %d when unloading %s!",
423 mod
->mapi_version
, mod
->name
);
427 lt_dlclose(mod
->address
);
429 rb_dlinkDelete(&mod
->node
, &module_list
);
436 ilog(L_MAIN
, "Module %s unloaded", name
);
437 sendto_realops_snomask(SNO_GENERAL
, L_NETWIDE
, "Module %s unloaded", name
);
446 * inputs - path name of module, bool to notice, int of origin, bool if core
447 * output - false if error true if success
448 * side effects - loads a module if successful
451 load_a_module(const char *path
, bool warn
, int origin
, bool core
)
455 char *mod_displayname
, *c
;
456 const char *ver
, *description
= NULL
;
460 mod_displayname
= rb_basename(path
);
462 /* Trim off the ending for the display name if we have to */
463 if((c
= rb_strcasestr(mod_displayname
, LT_MODULE_EXT
)) != NULL
)
466 tmpptr
= lt_dlopenext(path
);
470 const char *err
= lt_dlerror();
472 sendto_realops_snomask(SNO_GENERAL
, L_NETWIDE
,
473 "Error loading module %s: %s", mod_displayname
, err
);
474 ilog(L_MAIN
, "Error loading module %s: %s", mod_displayname
, err
);
475 rb_free(mod_displayname
);
480 * _mheader is actually a struct mapi_mheader_*, but mapi_version
481 * is always the first member of this structure, so we treate it
482 * as a single int in order to determine the API version.
485 mapi_version
= (int *) (uintptr_t) lt_dlsym(tmpptr
, "_mheader");
486 if((mapi_version
== NULL
487 && (mapi_version
= (int *) (uintptr_t) lt_dlsym(tmpptr
, "__mheader")) == NULL
)
488 || MAPI_MAGIC(*mapi_version
) != MAPI_MAGIC_HDR
)
490 sendto_realops_snomask(SNO_GENERAL
, L_NETWIDE
,
491 "Data format error: module %s has no MAPI header.",
493 ilog(L_MAIN
, "Data format error: module %s has no MAPI header.", mod_displayname
);
494 (void) lt_dlclose(tmpptr
);
495 rb_free(mod_displayname
);
499 switch (MAPI_VERSION(*mapi_version
))
503 struct mapi_mheader_av1
*mheader
= (struct mapi_mheader_av1
*)(void *)mapi_version
; /* see above */
504 if(mheader
->mapi_register
&& (mheader
->mapi_register() == -1))
506 ilog(L_MAIN
, "Module %s indicated failure during load.",
508 sendto_realops_snomask(SNO_GENERAL
, L_NETWIDE
,
509 "Module %s indicated failure during load.",
512 rb_free(mod_displayname
);
515 if(mheader
->mapi_command_list
)
518 for (m
= mheader
->mapi_command_list
; *m
; ++m
)
522 if(mheader
->mapi_hook_list
)
525 for (m
= mheader
->mapi_hook_list
; m
->hapi_name
; ++m
)
526 *m
->hapi_id
= register_hook(m
->hapi_name
);
529 if(mheader
->mapi_hfn_list
)
531 mapi_hfn_list_av1
*m
;
532 for (m
= mheader
->mapi_hfn_list
; m
->hapi_name
; ++m
)
533 add_hook(m
->hapi_name
, m
->fn
);
536 ver
= mheader
->mapi_module_version
;
541 struct mapi_mheader_av2
*mheader
= (struct mapi_mheader_av2
*)(void *)mapi_version
; /* see above */
543 if(mheader
->mapi_cap_list
)
545 mapi_cap_list_av2
*m
;
546 for (m
= mheader
->mapi_cap_list
; m
->cap_name
; ++m
)
548 struct CapabilityIndex
*idx
;
551 switch (m
->cap_index
)
553 case MAPI_CAP_CLIENT
:
556 case MAPI_CAP_SERVER
:
560 sendto_realops_snomask(SNO_GENERAL
, L_NETWIDE
,
561 "Unknown/unsupported CAP index found of type %d on capability %s when loading %s",
562 m
->cap_index
, m
->cap_name
, mod_displayname
);
564 "Unknown/unsupported CAP index found of type %d on capability %s when loading %s",
565 m
->cap_index
, m
->cap_name
, mod_displayname
);
569 result
= capability_put(idx
, m
->cap_name
, m
->cap_ownerdata
);
570 if (m
->cap_id
!= NULL
)
571 *(m
->cap_id
) = result
;
575 /* XXX duplicated code :( */
576 if(mheader
->mapi_register
&& (mheader
->mapi_register() == -1))
578 ilog(L_MAIN
, "Module %s indicated failure during load.",
580 sendto_realops_snomask(SNO_GENERAL
, L_NETWIDE
,
581 "Module %s indicated failure during load.",
583 if(mheader
->mapi_cap_list
)
585 mapi_cap_list_av2
*m
;
586 for (m
= mheader
->mapi_cap_list
; m
->cap_name
; ++m
)
588 struct CapabilityIndex
*idx
;
589 switch (m
->cap_index
)
591 case MAPI_CAP_CLIENT
:
594 case MAPI_CAP_SERVER
:
600 capability_orphan(idx
, m
->cap_name
);
604 rb_free(mod_displayname
);
608 /* Basic date code checks
610 * Don't make them fatal, but do complain about differences within a certain time frame.
611 * Later on if there are major API changes we can add fatal checks.
614 if(mheader
->mapi_datecode
!= datecode
&& mheader
->mapi_datecode
> 0)
616 long int delta
= datecode
- mheader
->mapi_datecode
;
617 if (delta
> MOD_WARN_DELTA
)
620 iwarn("Module %s build date is out of sync with ircd build date by %ld days, expect problems",
621 mod_displayname
, delta
);
622 sendto_realops_snomask(SNO_GENERAL
, L_NETWIDE
,
623 "Module %s build date is out of sync with ircd build date by %ld days, expect problems",
624 mod_displayname
, delta
);
628 if(mheader
->mapi_command_list
)
631 for (m
= mheader
->mapi_command_list
; *m
; ++m
)
635 if(mheader
->mapi_hook_list
)
638 for (m
= mheader
->mapi_hook_list
; m
->hapi_name
; ++m
)
639 *m
->hapi_id
= register_hook(m
->hapi_name
);
642 if(mheader
->mapi_hfn_list
)
644 mapi_hfn_list_av1
*m
;
645 for (m
= mheader
->mapi_hfn_list
; m
->hapi_name
; ++m
)
647 int priority
= m
->priority
;
649 priority
= HOOK_NORMAL
;
650 add_hook_prio(m
->hapi_name
, m
->fn
, priority
);
654 /* New in MAPI v2 - version replacement */
655 ver
= mheader
->mapi_module_version
? mheader
->mapi_module_version
: ircd_version
;
656 description
= mheader
->mapi_module_description
;
661 ilog(L_MAIN
, "Module %s has unknown/unsupported MAPI version %d.",
662 mod_displayname
, MAPI_VERSION(*mapi_version
));
663 sendto_realops_snomask(SNO_GENERAL
, L_NETWIDE
,
664 "Module %s has unknown/unsupported MAPI version %d.",
665 mod_displayname
, *mapi_version
);
667 rb_free(mod_displayname
);
674 if(description
== NULL
)
675 description
= unknown_description
;
677 mod
= rb_malloc(sizeof(struct module));
678 mod
->address
= tmpptr
;
680 mod
->description
= description
;
682 mod
->name
= rb_strdup(mod_displayname
);
683 mod
->mapi_header
= mapi_version
;
684 mod
->mapi_version
= MAPI_VERSION(*mapi_version
);
685 mod
->origin
= origin
;
686 mod
->path
= rb_strdup(path
);
687 rb_dlinkAdd(mod
, &mod
->node
, &module_list
);
695 case MAPI_ORIGIN_EXTENSION
:
698 case MAPI_ORIGIN_CORE
:
706 sendto_realops_snomask(SNO_GENERAL
, L_NETWIDE
,
707 "Module %s [version: %s; MAPI version: %d; origin: %s; description: \"%s\"] loaded at %p",
708 mod_displayname
, ver
, MAPI_VERSION(*mapi_version
), o
, description
,
710 ilog(L_MAIN
, "Module %s [version: %s; MAPI version: %d; origin: %s; description: \"%s\"] loaded at %p",
711 mod_displayname
, ver
, MAPI_VERSION(*mapi_version
), o
, description
, (void *) tmpptr
);
713 rb_free(mod_displayname
);
718 modules_do_reload(void *info_
)
720 struct modreload
*info
= info_
;
724 char *m_bn
= rb_basename(info
->module);
726 struct Client
*source_p
= find_id(info
->id
);
728 if((mod
= findmodule_byname(m_bn
)) == NULL
)
730 if (source_p
) sendto_one_notice(source_p
, ":Module %s is not loaded", m_bn
);
736 origin
= mod
->origin
;
737 check_core
= mod
->core
;
738 path
= rb_strdup(mod
->path
);
740 mod_remember_clicaps();
742 if(unload_one_module(m_bn
, true) == false)
744 if (source_p
) sendto_one_notice(source_p
, ":Module %s is not loaded", m_bn
);
751 if((load_a_module(path
, true, origin
, check_core
) == false) && check_core
)
753 sendto_realops_snomask(SNO_GENERAL
, L_NETWIDE
,
754 "Error reloading core module: %s: terminating ircd", m_bn
);
755 ilog(L_MAIN
, "Error loading core module %s: terminating ircd", m_bn
);
759 mod_notify_clicaps();
767 modules_do_restart(void *unused
)
769 unsigned int modnum
= 0;
770 rb_dlink_node
*ptr
, *nptr
;
772 mod_remember_clicaps();
774 RB_DLINK_FOREACH_SAFE(ptr
, nptr
, module_list
.head
)
776 struct module *mod
= ptr
->data
;
777 if(!unload_one_module(mod
->name
, false))
779 ilog(L_MAIN
, "Module Restart: %s was not unloaded %s",
781 mod
->core
? "(core module)" : "");
784 sendto_realops_snomask(SNO_GENERAL
, L_NETWIDE
,
785 "Module Restart: %s failed to unload",
793 load_all_modules(false);
794 load_core_modules(false);
797 mod_notify_clicaps();
799 sendto_realops_snomask(SNO_GENERAL
, L_NETWIDE
,
800 "Module Restart: %u modules unloaded, %lu modules loaded",
801 modnum
, rb_dlink_list_length(&module_list
));
802 ilog(L_MAIN
, "Module Restart: %u modules unloaded, %lu modules loaded", modnum
, rb_dlink_list_length(&module_list
));