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"
43 # error "Charybdis requires loadable module support."
46 struct module **modlist
= NULL
;
48 static const char *core_module_table
[] = {
66 #define MOD_WARN_DELTA (90 * 86400) /* time in seconds, 86400 seconds in a day */
68 #define MODS_INCREMENT 10
70 int max_mods
= MODS_INCREMENT
;
72 static rb_dlink_list mod_paths
;
79 ilog(L_MAIN
, "lt_dlinit failed");
83 /* Add the default paths we look in to the module system --nenolod */
84 mod_add_path(ircd_paths
[IRCD_PATH_MODULES
]);
85 mod_add_path(ircd_paths
[IRCD_PATH_AUTOLOAD_MODULES
]);
92 * side effects - returns a module path from path
95 mod_find_path(const char *path
)
100 RB_DLINK_FOREACH(ptr
, mod_paths
.head
)
104 if(!strcmp(path
, mpath
))
115 * side effects - adds path to list
118 mod_add_path(const char *path
)
122 if(mod_find_path(path
))
125 pathst
= rb_strdup(path
);
126 rb_dlinkAddAlloc(pathst
, &mod_paths
);
133 * side effects - clear the lists of paths
136 mod_clear_paths(void)
138 rb_dlink_node
*ptr
, *next_ptr
;
140 RB_DLINK_FOREACH_SAFE(ptr
, next_ptr
, mod_paths
.head
)
143 rb_free_rb_dlink_node(ptr
);
146 mod_paths
.head
= mod_paths
.tail
= NULL
;
147 mod_paths
.length
= 0;
152 * input - module to load
153 * output - index of module on success, -1 on failure
154 * side effects - none
157 findmodule_byname(const char *name
)
160 char name_ext
[PATH_MAX
+ 1];
162 rb_strlcpy(name_ext
, name
, sizeof name_ext
);
163 rb_strlcat(name_ext
, LT_MODULE_EXT
, sizeof name_ext
);
165 for (i
= 0; i
< num_mods
; i
++)
167 if(!irccmp(modlist
[i
]->name
, name
))
170 if(!irccmp(modlist
[i
]->name
, name_ext
))
177 /* load_all_modules()
184 load_all_modules(bool warn
)
186 DIR *system_module_dir
= NULL
;
187 struct dirent
*ldirent
= NULL
;
188 char module_fq_name
[PATH_MAX
+ 1];
189 size_t module_ext_len
= strlen(LT_MODULE_EXT
);
193 modlist
= (struct module **) rb_malloc(sizeof(struct module *) * (MODS_INCREMENT
));
195 max_mods
= MODS_INCREMENT
;
197 system_module_dir
= opendir(ircd_paths
[IRCD_PATH_AUTOLOAD_MODULES
]);
199 if(system_module_dir
== NULL
)
201 ilog(L_MAIN
, "Could not load modules from %s: %s", ircd_paths
[IRCD_PATH_AUTOLOAD_MODULES
], strerror(errno
));
205 while ((ldirent
= readdir(system_module_dir
)) != NULL
)
207 size_t len
= strlen(ldirent
->d_name
);
209 if(len
> module_ext_len
&&
210 rb_strncasecmp(ldirent
->d_name
+ (len
- module_ext_len
), LT_MODULE_EXT
, module_ext_len
) == 0)
212 (void) snprintf(module_fq_name
, sizeof(module_fq_name
), "%s%c%s",
213 ircd_paths
[IRCD_PATH_AUTOLOAD_MODULES
], RB_PATH_SEPARATOR
, ldirent
->d_name
);
214 (void) load_a_module(module_fq_name
, warn
, MAPI_ORIGIN_CORE
, false);
218 (void) closedir(system_module_dir
);
221 /* load_core_modules()
225 * side effects - core modules are loaded, if any fail, kill ircd
228 load_core_modules(bool warn
)
230 char module_name
[PATH_MAX
];
234 for (i
= 0; core_module_table
[i
]; i
++)
236 snprintf(module_name
, sizeof(module_name
), "%s%c%s", ircd_paths
[IRCD_PATH_MODULES
], RB_PATH_SEPARATOR
,
237 core_module_table
[i
]);
239 if(load_a_module(module_name
, warn
, MAPI_ORIGIN_CORE
, true) == false)
242 "Error loading core module %s: terminating ircd",
243 core_module_table
[i
]);
256 load_one_module(const char *path
, int origin
, bool coremodule
)
258 char modpath
[PATH_MAX
];
259 rb_dlink_node
*pathst
;
261 if (server_state_foreground
)
262 inotice("loading module %s ...", path
);
265 origin
= MAPI_ORIGIN_CORE
;
267 RB_DLINK_FOREACH(pathst
, mod_paths
.head
)
270 const char *mpath
= pathst
->data
;
272 snprintf(modpath
, sizeof(modpath
), "%s%c%s%s", mpath
, RB_PATH_SEPARATOR
, path
, LT_MODULE_EXT
);
273 if((strstr(modpath
, "../") == NULL
) && (strstr(modpath
, "/..") == NULL
))
275 if(stat(modpath
, &statbuf
) == 0 && S_ISREG(statbuf
.st_mode
))
277 /* Regular files only please */
278 return load_a_module(modpath
, true, origin
, coremodule
);
284 sendto_realops_snomask(SNO_GENERAL
, L_ALL
, "Cannot locate module %s", path
);
288 static void increase_modlist(void);
290 #define MODS_INCREMENT 10
292 static char unknown_ver
[] = "<unknown>";
293 static char unknown_description
[] = "<none>";
295 /* unload_one_module()
297 * inputs - name of module to unload
298 * - true to say modules unloaded, false to not
299 * output - true if successful, false if error
300 * side effects - module is unloaded
303 unload_one_module(const char *name
, bool warn
)
307 if((modindex
= findmodule_byname(name
)) == -1)
311 ** XXX - The type system in C does not allow direct conversion between
312 ** data and function pointers, but as it happens, most C compilers will
313 ** safely do this, however it is a theoretical overlow to cast as we
314 ** must do here. I have library functions to take care of this, but
315 ** despite being more "correct" for the C language, this is more
316 ** practical. Removing the abuse of the ability to cast ANY pointer
317 ** to and from an integer value here will break some compilers.
320 /* Left the comment in but the code isn't here any more -larne */
321 switch (modlist
[modindex
]->mapi_version
)
325 struct mapi_mheader_av1
*mheader
= modlist
[modindex
]->mapi_header
;
326 if(mheader
->mapi_command_list
)
329 for (m
= mheader
->mapi_command_list
; *m
; ++m
)
333 /* hook events are never removed, we simply lose the
334 * ability to call them --fl
336 if(mheader
->mapi_hfn_list
)
338 mapi_hfn_list_av1
*m
;
339 for (m
= mheader
->mapi_hfn_list
; m
->hapi_name
; ++m
)
340 remove_hook(m
->hapi_name
, m
->fn
);
343 if(mheader
->mapi_unregister
)
344 mheader
->mapi_unregister();
349 struct mapi_mheader_av2
*mheader
= modlist
[modindex
]->mapi_header
;
351 /* XXX duplicate code :( */
352 if(mheader
->mapi_command_list
)
355 for (m
= mheader
->mapi_command_list
; *m
; ++m
)
359 /* hook events are never removed, we simply lose the
360 * ability to call them --fl
362 if(mheader
->mapi_hfn_list
)
364 mapi_hfn_list_av1
*m
;
365 for (m
= mheader
->mapi_hfn_list
; m
->hapi_name
; ++m
)
366 remove_hook(m
->hapi_name
, m
->fn
);
369 if(mheader
->mapi_unregister
)
370 mheader
->mapi_unregister();
372 if(mheader
->mapi_cap_list
)
374 mapi_cap_list_av2
*m
;
375 for (m
= mheader
->mapi_cap_list
; m
->cap_name
; ++m
)
377 struct CapabilityIndex
*idx
;
379 switch (m
->cap_index
)
381 case MAPI_CAP_CLIENT
:
384 case MAPI_CAP_SERVER
:
388 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
389 "Unknown/unsupported CAP index found of type %d on capability %s when unloading %s",
390 m
->cap_index
, m
->cap_name
, modlist
[modindex
]->name
);
392 "Unknown/unsupported CAP index found of type %d on capability %s when unloading %s",
393 m
->cap_index
, m
->cap_name
, modlist
[modindex
]->name
);
397 if (m
->cap_id
!= NULL
)
399 capability_orphan(idx
, m
->cap_name
);
400 sendto_local_clients_with_capability(CLICAP_CAP_NOTIFY
, ":%s CAP * DEL :%s", me
.name
, m
->cap_name
);
406 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
407 "Unknown/unsupported MAPI version %d when unloading %s!",
408 modlist
[modindex
]->mapi_version
, modlist
[modindex
]->name
);
409 ilog(L_MAIN
, "Unknown/unsupported MAPI version %d when unloading %s!",
410 modlist
[modindex
]->mapi_version
, modlist
[modindex
]->name
);
414 lt_dlclose(modlist
[modindex
]->address
);
416 rb_free(modlist
[modindex
]->name
);
417 rb_free(modlist
[modindex
]);
418 memmove(&modlist
[modindex
], &modlist
[modindex
+ 1],
419 sizeof(struct module *) * ((num_mods
- 1) - modindex
));
426 ilog(L_MAIN
, "Module %s unloaded", name
);
427 sendto_realops_snomask(SNO_GENERAL
, L_ALL
, "Module %s unloaded", name
);
436 * inputs - path name of module, bool to notice, int of origin, bool if core
437 * output - false if error true if success
438 * side effects - loads a module if successful
441 load_a_module(const char *path
, bool warn
, int origin
, bool core
)
444 char *mod_displayname
, *c
;
445 const char *ver
, *description
= NULL
;
446 size_t module_ext_len
= strlen(LT_MODULE_EXT
);
450 mod_displayname
= rb_basename(path
);
452 /* Trim off the ending for the display name if we have to */
453 if((c
= rb_strcasestr(mod_displayname
, LT_MODULE_EXT
)) != NULL
)
456 tmpptr
= lt_dlopenext(path
);
460 const char *err
= lt_dlerror();
462 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
463 "Error loading module %s: %s", mod_displayname
, err
);
464 ilog(L_MAIN
, "Error loading module %s: %s", mod_displayname
, err
);
465 rb_free(mod_displayname
);
470 * _mheader is actually a struct mapi_mheader_*, but mapi_version
471 * is always the first member of this structure, so we treate it
472 * as a single int in order to determine the API version.
475 mapi_version
= (int *) (uintptr_t) lt_dlsym(tmpptr
, "_mheader");
476 if((mapi_version
== NULL
477 && (mapi_version
= (int *) (uintptr_t) lt_dlsym(tmpptr
, "__mheader")) == NULL
)
478 || MAPI_MAGIC(*mapi_version
) != MAPI_MAGIC_HDR
)
480 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
481 "Data format error: module %s has no MAPI header.",
483 ilog(L_MAIN
, "Data format error: module %s has no MAPI header.", mod_displayname
);
484 (void) lt_dlclose(tmpptr
);
485 rb_free(mod_displayname
);
489 switch (MAPI_VERSION(*mapi_version
))
493 struct mapi_mheader_av1
*mheader
= (struct mapi_mheader_av1
*)(void *)mapi_version
; /* see above */
494 if(mheader
->mapi_register
&& (mheader
->mapi_register() == -1))
496 ilog(L_MAIN
, "Module %s indicated failure during load.",
498 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
499 "Module %s indicated failure during load.",
502 rb_free(mod_displayname
);
505 if(mheader
->mapi_command_list
)
508 for (m
= mheader
->mapi_command_list
; *m
; ++m
)
512 if(mheader
->mapi_hook_list
)
515 for (m
= mheader
->mapi_hook_list
; m
->hapi_name
; ++m
)
516 *m
->hapi_id
= register_hook(m
->hapi_name
);
519 if(mheader
->mapi_hfn_list
)
521 mapi_hfn_list_av1
*m
;
522 for (m
= mheader
->mapi_hfn_list
; m
->hapi_name
; ++m
)
523 add_hook(m
->hapi_name
, m
->fn
);
526 ver
= mheader
->mapi_module_version
;
531 struct mapi_mheader_av2
*mheader
= (struct mapi_mheader_av2
*)(void *)mapi_version
; /* see above */
533 /* XXX duplicated code :( */
534 if(mheader
->mapi_register
&& (mheader
->mapi_register() == -1))
536 ilog(L_MAIN
, "Module %s indicated failure during load.",
538 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
539 "Module %s indicated failure during load.",
542 rb_free(mod_displayname
);
546 /* Basic date code checks
548 * Don't make them fatal, but do complain about differences within a certain time frame.
549 * Later on if there are major API changes we can add fatal checks.
552 if(mheader
->mapi_datecode
!= datecode
&& mheader
->mapi_datecode
> 0)
554 long int delta
= datecode
- mheader
->mapi_datecode
;
555 if (delta
> MOD_WARN_DELTA
)
558 iwarn("Module %s build date is out of sync with ircd build date by %ld days, expect problems",
559 mod_displayname
, delta
);
560 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
561 "Module %s build date is out of sync with ircd build date by %ld days, expect problems",
562 mod_displayname
, delta
);
566 if(mheader
->mapi_command_list
)
569 for (m
= mheader
->mapi_command_list
; *m
; ++m
)
573 if(mheader
->mapi_hook_list
)
576 for (m
= mheader
->mapi_hook_list
; m
->hapi_name
; ++m
)
577 *m
->hapi_id
= register_hook(m
->hapi_name
);
580 if(mheader
->mapi_hfn_list
)
582 mapi_hfn_list_av1
*m
;
583 for (m
= mheader
->mapi_hfn_list
; m
->hapi_name
; ++m
)
584 add_hook(m
->hapi_name
, m
->fn
);
587 /* New in MAPI v2 - version replacement */
588 ver
= mheader
->mapi_module_version
? mheader
->mapi_module_version
: ircd_version
;
589 description
= mheader
->mapi_module_description
;
591 if(mheader
->mapi_cap_list
)
593 mapi_cap_list_av2
*m
;
594 for (m
= mheader
->mapi_cap_list
; m
->cap_name
; ++m
)
596 struct CapabilityIndex
*idx
;
599 switch (m
->cap_index
)
601 case MAPI_CAP_CLIENT
:
604 case MAPI_CAP_SERVER
:
608 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
609 "Unknown/unsupported CAP index found of type %d on capability %s when loading %s",
610 m
->cap_index
, m
->cap_name
, mod_displayname
);
612 "Unknown/unsupported CAP index found of type %d on capability %s when loading %s",
613 m
->cap_index
, m
->cap_name
, mod_displayname
);
617 result
= capability_put(idx
, m
->cap_name
, m
->cap_ownerdata
);
618 if (m
->cap_id
!= NULL
)
620 *(m
->cap_id
) = result
;
621 sendto_local_clients_with_capability(CLICAP_CAP_NOTIFY
, ":%s CAP * ADD :%s", me
.name
, m
->cap_name
);
629 ilog(L_MAIN
, "Module %s has unknown/unsupported MAPI version %d.",
630 mod_displayname
, MAPI_VERSION(*mapi_version
));
631 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
632 "Module %s has unknown/unsupported MAPI version %d.",
633 mod_displayname
, *mapi_version
);
635 rb_free(mod_displayname
);
642 if(description
== NULL
)
643 description
= unknown_description
;
647 modlist
[num_mods
] = rb_malloc(sizeof(struct module));
648 modlist
[num_mods
]->address
= tmpptr
;
649 modlist
[num_mods
]->version
= ver
;
650 modlist
[num_mods
]->description
= description
;
651 modlist
[num_mods
]->core
= core
;
652 modlist
[num_mods
]->name
= rb_strdup(mod_displayname
);
653 modlist
[num_mods
]->mapi_header
= mapi_version
;
654 modlist
[num_mods
]->mapi_version
= MAPI_VERSION(*mapi_version
);
655 modlist
[num_mods
]->origin
= origin
;
664 case MAPI_ORIGIN_EXTENSION
:
667 case MAPI_ORIGIN_CORE
:
675 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
676 "Module %s [version: %s; MAPI version: %d; origin: %s; description: \"%s\"] loaded at %p",
677 mod_displayname
, ver
, MAPI_VERSION(*mapi_version
), o
, description
,
679 ilog(L_MAIN
, "Module %s [version: %s; MAPI version: %d; origin: %s; description: \"%s\"] loaded at %p",
680 mod_displayname
, ver
, MAPI_VERSION(*mapi_version
), o
, description
, (void *) tmpptr
);
682 rb_free(mod_displayname
);
691 * side effects - expand the size of modlist if necessary
694 increase_modlist(void)
696 struct module **new_modlist
= NULL
;
698 if((num_mods
+ 1) < max_mods
)
701 new_modlist
= (struct module **) rb_malloc(sizeof(struct module *) *
702 (max_mods
+ MODS_INCREMENT
));
703 memcpy((void *) new_modlist
, (void *) modlist
, sizeof(struct module *) * num_mods
);
706 modlist
= new_modlist
;
707 max_mods
+= MODS_INCREMENT
;