]> jfr.im git - solanum.git/blame - ircd/modules.c
authd: initial pass at win32 porting
[solanum.git] / ircd / modules.c
CommitLineData
212380e3
AC
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
212380e3
AC
23 */
24
25#include "stdinc.h"
212380e3 26#include "modules.h"
4016731b 27#include "logger.h"
212380e3
AC
28#include "ircd.h"
29#include "client.h"
30#include "send.h"
31#include "s_conf.h"
32#include "s_newconf.h"
33#include "numeric.h"
34#include "parse.h"
35#include "ircd_defs.h"
4562c604 36#include "match.h"
15feac53 37#include "s_serv.h"
8e9c6a75 38#include "capability.h"
212380e3 39
f272e7ab
AC
40#include <ltdl.h>
41
9abdcf1c
EM
42#ifndef LT_MODULE_EXT
43# error "Charybdis requires loadable module support."
44#endif
45
212380e3
AC
46struct module **modlist = NULL;
47
48static const char *core_module_table[] = {
431a1a27 49 "m_ban",
212380e3
AC
50 "m_die",
51 "m_error",
52 "m_join",
53 "m_kick",
54 "m_kill",
55 "m_message",
56 "m_mode",
57 "m_nick",
58 "m_part",
59 "m_quit",
60 "m_server",
212380e3
AC
61 "m_squit",
62 NULL
63};
64
81204be8
EM
65#define MOD_WARN_DELTA (90 * 86400) /* time in seconds, 86400 seconds in a day */
66
212380e3
AC
67#define MODS_INCREMENT 10
68int num_mods = 0;
69int max_mods = MODS_INCREMENT;
70
330fc5c1 71static rb_dlink_list mod_paths;
212380e3 72
3c7d6fcc
EM
73static void mo_modload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
74static void mo_modlist(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
75static void mo_modreload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
76static void mo_modunload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
77static void mo_modrestart(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
78
79static void me_modload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
80static void me_modlist(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
81static void me_modreload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
82static void me_modunload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
83static void me_modrestart(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
84
85static void do_modload(struct Client *, const char *);
86static void do_modunload(struct Client *, const char *);
87static void do_modreload(struct Client *, const char *);
88static void do_modlist(struct Client *, const char *);
89static void do_modrestart(struct Client *);
15feac53 90
212380e3 91struct Message modload_msgtab = {
7baa37a9 92 "MODLOAD", 0, 0, 0, 0,
15feac53 93 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modload, 2}, {mo_modload, 2}}
212380e3
AC
94};
95
96struct Message modunload_msgtab = {
7baa37a9 97 "MODUNLOAD", 0, 0, 0, 0,
15feac53 98 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modunload, 2}, {mo_modunload, 2}}
212380e3
AC
99};
100
101struct Message modreload_msgtab = {
7baa37a9 102 "MODRELOAD", 0, 0, 0, 0,
15feac53 103 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modreload, 2}, {mo_modreload, 2}}
212380e3
AC
104};
105
106struct Message modlist_msgtab = {
7baa37a9 107 "MODLIST", 0, 0, 0, 0,
15feac53 108 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modlist, 0}, {mo_modlist, 0}}
212380e3
AC
109};
110
111struct Message modrestart_msgtab = {
7baa37a9 112 "MODRESTART", 0, 0, 0, 0,
15feac53 113 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modrestart, 0}, {mo_modrestart, 0}}
212380e3
AC
114};
115
212380e3
AC
116void
117modules_init(void)
118{
f272e7ab
AC
119 if(lt_dlinit())
120 {
121 ilog(L_MAIN, "lt_dlinit failed");
122 exit(0);
123 }
124
212380e3
AC
125 mod_add_cmd(&modload_msgtab);
126 mod_add_cmd(&modunload_msgtab);
127 mod_add_cmd(&modreload_msgtab);
128 mod_add_cmd(&modlist_msgtab);
129 mod_add_cmd(&modrestart_msgtab);
130
131 /* Add the default paths we look in to the module system --nenolod */
132 mod_add_path(MODPATH);
133 mod_add_path(AUTOMODPATH);
134}
135
136/* mod_find_path()
137 *
138 * input - path
139 * output - none
140 * side effects - returns a module path from path
141 */
26c6ac3d 142static char *
212380e3
AC
143mod_find_path(const char *path)
144{
330fc5c1 145 rb_dlink_node *ptr;
26c6ac3d 146 char *mpath;
212380e3 147
5cefa1d6 148 RB_DLINK_FOREACH(ptr, mod_paths.head)
212380e3
AC
149 {
150 mpath = ptr->data;
151
26c6ac3d 152 if(!strcmp(path, mpath))
212380e3
AC
153 return mpath;
154 }
155
156 return NULL;
157}
158
159/* mod_add_path
160 *
161 * input - path
55abcbb2 162 * ouput -
212380e3
AC
163 * side effects - adds path to list
164 */
165void
166mod_add_path(const char *path)
167{
26c6ac3d 168 char *pathst;
212380e3
AC
169
170 if(mod_find_path(path))
171 return;
172
26c6ac3d 173 pathst = rb_strdup(path);
330fc5c1 174 rb_dlinkAddAlloc(pathst, &mod_paths);
212380e3
AC
175}
176
177/* mod_clear_paths()
178 *
179 * input -
180 * output -
181 * side effects - clear the lists of paths
182 */
183void
184mod_clear_paths(void)
185{
637c4932 186 rb_dlink_node *ptr, *next_ptr;
212380e3 187
637c4932 188 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, mod_paths.head)
212380e3 189 {
637c4932 190 rb_free(ptr->data);
30106156 191 rb_free_rb_dlink_node(ptr);
212380e3
AC
192 }
193
194 mod_paths.head = mod_paths.tail = NULL;
195 mod_paths.length = 0;
196}
197
212380e3
AC
198/* findmodule_byname
199 *
200 * input -
201 * output -
202 * side effects -
203 */
204
205int
206findmodule_byname(const char *name)
207{
208 int i;
209
210 for (i = 0; i < num_mods; i++)
211 {
212 if(!irccmp(modlist[i]->name, name))
213 return i;
214 }
215 return -1;
216}
217
218/* load_all_modules()
219 *
220 * input -
221 * output -
222 * side effects -
223 */
224void
225load_all_modules(int warn)
226{
227 DIR *system_module_dir = NULL;
228 struct dirent *ldirent = NULL;
229 char module_fq_name[PATH_MAX + 1];
1db8a313
EM
230 size_t module_ext_len = strlen(LT_MODULE_EXT);
231
212380e3
AC
232 modules_init();
233
1e170010 234 modlist = (struct module **) rb_malloc(sizeof(struct module *) * (MODS_INCREMENT));
212380e3
AC
235
236 max_mods = MODS_INCREMENT;
237
238 system_module_dir = opendir(AUTOMODPATH);
239
240 if(system_module_dir == NULL)
241 {
242 ilog(L_MAIN, "Could not load modules from %s: %s", AUTOMODPATH, strerror(errno));
243 return;
244 }
245
246 while ((ldirent = readdir(system_module_dir)) != NULL)
247 {
9abdcf1c
EM
248 struct stat s;
249 size_t len;
250
5203cba5 251 len = strlen(ldirent->d_name);
9abdcf1c 252 if(len > module_ext_len && !strcasecmp(ldirent->d_name + (len - module_ext_len), LT_MODULE_EXT))
5203cba5
VI
253 {
254 (void) snprintf(module_fq_name, sizeof(module_fq_name), "%s/%s", AUTOMODPATH, ldirent->d_name);
216d70e9 255 (void) load_a_module(module_fq_name, warn, MAPI_ORIGIN_CORE, 0);
5203cba5 256 }
212380e3
AC
257
258 }
259 (void) closedir(system_module_dir);
260}
261
262/* load_core_modules()
263 *
264 * input -
265 * output -
266 * side effects - core modules are loaded, if any fail, kill ircd
267 */
268void
269load_core_modules(int warn)
270{
d74fa5b5 271 char module_name[PATH_MAX];
212380e3
AC
272 int i;
273
274
275 for (i = 0; core_module_table[i]; i++)
276 {
9abdcf1c
EM
277 snprintf(module_name, sizeof(module_name), "%s/%s", MODPATH,
278 core_module_table[i]);
212380e3 279
216d70e9 280 if(load_a_module(module_name, warn, MAPI_ORIGIN_CORE, 1) == -1)
212380e3
AC
281 {
282 ilog(L_MAIN,
9abdcf1c
EM
283 "Error loading core module %s: terminating ircd",
284 core_module_table[i]);
212380e3
AC
285 exit(0);
286 }
287 }
288}
289
290/* load_one_module()
291 *
292 * input -
293 * output -
294 * side effects -
295 */
296int
216d70e9 297load_one_module(const char *path, int origin, int coremodule)
212380e3 298{
d74fa5b5 299 char modpath[PATH_MAX];
330fc5c1 300 rb_dlink_node *pathst;
26c6ac3d 301 const char *mpath;
212380e3
AC
302
303 struct stat statbuf;
304
503727d1 305 if (server_state_foreground)
55abcbb2 306 inotice("loading module %s ...", path);
212380e3 307
216d70e9
EM
308 if(coremodule != 0)
309 {
310 coremodule = 1;
311 origin = MAPI_ORIGIN_CORE;
312 }
313
5cefa1d6 314 RB_DLINK_FOREACH(pathst, mod_paths.head)
212380e3
AC
315 {
316 mpath = pathst->data;
317
5203cba5 318 snprintf(modpath, sizeof(modpath), "%s/%s", mpath, path);
212380e3
AC
319 if((strstr(modpath, "../") == NULL) && (strstr(modpath, "/..") == NULL))
320 {
321 if(stat(modpath, &statbuf) == 0)
322 {
323 if(S_ISREG(statbuf.st_mode))
324 {
325 /* Regular files only please */
216d70e9 326 return load_a_module(modpath, 1, origin, coremodule);
212380e3
AC
327 }
328 }
329
330 }
331 }
332
333 sendto_realops_snomask(SNO_GENERAL, L_ALL, "Cannot locate module %s", path);
334 return -1;
335}
336
337
338/* load a module .. */
3c7d6fcc 339static void
4a84a763 340mo_modload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
212380e3 341{
212380e3
AC
342 if(!IsOperAdmin(source_p))
343 {
344 sendto_one(source_p, form_str(ERR_NOPRIVS),
345 me.name, source_p->name, "admin");
3c7d6fcc 346 return;
212380e3
AC
347 }
348
15feac53
AC
349 if(parc > 2)
350 {
351 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
352 "ENCAP %s MODLOAD %s", parv[2], parv[1]);
353 if (match(parv[2], me.name) == 0)
3c7d6fcc 354 return;
15feac53
AC
355 }
356
3c7d6fcc 357 do_modload(source_p, parv[1]);
15feac53
AC
358}
359
3c7d6fcc 360static void
4a84a763 361me_modload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
15feac53
AC
362{
363 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
364 {
365 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
366 "to load modules on this server.");
3c7d6fcc 367 return;
15feac53
AC
368 }
369
3c7d6fcc 370 do_modload(source_p, parv[1]);
15feac53
AC
371}
372
3c7d6fcc
EM
373
374/* unload a module .. */
375static void
376mo_modunload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
15feac53 377{
3c7d6fcc
EM
378 if(!IsOperAdmin(source_p))
379 {
380 sendto_one(source_p, form_str(ERR_NOPRIVS),
381 me.name, source_p->name, "admin");
382 return;
383 }
212380e3 384
3c7d6fcc 385 if(parc > 2)
212380e3 386 {
3c7d6fcc
EM
387 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
388 "ENCAP %s MODUNLOAD %s", parv[2], parv[1]);
389 if (match(parv[2], me.name) == 0)
390 return;
212380e3
AC
391 }
392
3c7d6fcc
EM
393 do_modunload(source_p, parv[1]);
394}
212380e3 395
3c7d6fcc
EM
396static void
397me_modunload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
398{
399 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
400 {
401 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
402 "to load modules on this server.");
403 return;
404 }
212380e3 405
3c7d6fcc 406 do_modunload(source_p, parv[1]);
212380e3
AC
407}
408
3c7d6fcc
EM
409/* unload and load in one! */
410static void
411mo_modreload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
212380e3 412{
212380e3
AC
413 if(!IsOperAdmin(source_p))
414 {
415 sendto_one(source_p, form_str(ERR_NOPRIVS),
416 me.name, source_p->name, "admin");
3c7d6fcc 417 return;
212380e3
AC
418 }
419
15feac53
AC
420 if(parc > 2)
421 {
422 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
3c7d6fcc 423 "ENCAP %s MODRELOAD %s", parv[2], parv[1]);
15feac53 424 if (match(parv[2], me.name) == 0)
3c7d6fcc 425 return;
15feac53
AC
426 }
427
3c7d6fcc 428 do_modreload(source_p, parv[1]);
15feac53
AC
429}
430
3c7d6fcc
EM
431static void
432me_modreload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
15feac53
AC
433{
434 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
435 {
436 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
437 "to load modules on this server.");
3c7d6fcc 438 return;
15feac53
AC
439 }
440
3c7d6fcc 441 do_modreload(source_p, parv[1]);
15feac53
AC
442}
443
3c7d6fcc
EM
444/* list modules .. */
445static void
446mo_modlist(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
15feac53 447{
3c7d6fcc 448 if(!IsOperAdmin(source_p))
212380e3 449 {
3c7d6fcc
EM
450 sendto_one(source_p, form_str(ERR_NOPRIVS),
451 me.name, source_p->name, "admin");
452 return;
212380e3
AC
453 }
454
3c7d6fcc 455 if(parc > 2)
212380e3 456 {
3c7d6fcc
EM
457 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
458 "ENCAP %s MODLIST %s", parv[2], parv[1]);
459 if (match(parv[2], me.name) == 0)
460 return;
212380e3
AC
461 }
462
3c7d6fcc
EM
463 do_modlist(source_p, parc > 1 ? parv[1] : 0);
464}
465
466static void
467me_modlist(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
468{
469 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
212380e3 470 {
3c7d6fcc
EM
471 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
472 "to load modules on this server.");
473 return;
212380e3 474 }
5366977b 475
3c7d6fcc 476 do_modlist(source_p, parv[1]);
212380e3
AC
477}
478
3c7d6fcc
EM
479/* unload and reload all modules */
480static void
481mo_modrestart(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
212380e3 482{
212380e3
AC
483 if(!IsOperAdmin(source_p))
484 {
485 sendto_one(source_p, form_str(ERR_NOPRIVS),
486 me.name, source_p->name, "admin");
3c7d6fcc 487 return;
212380e3
AC
488 }
489
3c7d6fcc 490 if(parc > 1)
15feac53 491 {
3c7d6fcc
EM
492 sendto_match_servs(source_p, parv[1], CAP_ENCAP, NOCAPS,
493 "ENCAP %s MODRESTART", parv[1]);
494 if (match(parv[1], me.name) == 0)
495 return;
15feac53
AC
496 }
497
3c7d6fcc 498 do_modrestart(source_p);
15feac53
AC
499}
500
3c7d6fcc
EM
501static void
502me_modrestart(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
15feac53
AC
503{
504 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
505 {
506 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
507 "to load modules on this server.");
3c7d6fcc 508 return;
15feac53
AC
509 }
510
3c7d6fcc 511 do_modrestart(source_p);
15feac53
AC
512}
513
3c7d6fcc
EM
514static void
515do_modload(struct Client *source_p, const char *module)
516{
517 char *m_bn = rb_basename(module);
518 int origin;
519
520 if(findmodule_byname(m_bn) != -1)
521 {
522 sendto_one_notice(source_p, ":Module %s is already loaded", m_bn);
523 rb_free(m_bn);
524 return;
525 }
526
527 origin = strcmp(module, m_bn) == 0 ? MAPI_ORIGIN_CORE : MAPI_ORIGIN_EXTENSION;
528 load_one_module(module, origin, 0);
529
530 rb_free(m_bn);
531}
532
533static void
534do_modunload(struct Client *source_p, const char *module)
535{
536 int modindex;
537 char *m_bn = rb_basename(module);
538
539 if((modindex = findmodule_byname(m_bn)) == -1)
540 {
541 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
542 rb_free(m_bn);
543 return;
544 }
545
546 if(modlist[modindex]->core == 1)
547 {
548 sendto_one_notice(source_p, ":Module %s is a core module and may not be unloaded", m_bn);
549 rb_free(m_bn);
550 return;
551 }
552
553 if(unload_one_module(m_bn, 1) == -1)
554 {
555 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
556 }
557
558 rb_free(m_bn);
559}
560
561static void
15feac53
AC
562do_modreload(struct Client *source_p, const char *module)
563{
564 int modindex;
565 int check_core;
566 char *m_bn = rb_basename(module);
212380e3
AC
567
568 if((modindex = findmodule_byname(m_bn)) == -1)
569 {
5366977b 570 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
637c4932 571 rb_free(m_bn);
3c7d6fcc 572 return;
212380e3
AC
573 }
574
575 check_core = modlist[modindex]->core;
576
577 if(unload_one_module(m_bn, 1) == -1)
578 {
5366977b 579 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
637c4932 580 rb_free(m_bn);
3c7d6fcc 581 return;
212380e3
AC
582 }
583
216d70e9 584 if((load_one_module(m_bn, modlist[modindex]->origin, check_core) == -1) && check_core)
212380e3 585 {
15feac53 586 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
7d778d51
AC
587 "Error reloading core module: %s: terminating ircd", m_bn);
588 ilog(L_MAIN, "Error loading core module %s: terminating ircd", m_bn);
212380e3
AC
589 exit(0);
590 }
591
637c4932 592 rb_free(m_bn);
212380e3
AC
593}
594
3c7d6fcc
EM
595static void
596do_modrestart(struct Client *source_p)
212380e3 597{
3c7d6fcc 598 int modnum;
212380e3 599
3c7d6fcc 600 sendto_one_notice(source_p, ":Reloading all modules");
15feac53 601
3c7d6fcc
EM
602 modnum = num_mods;
603 while (num_mods)
604 unload_one_module(modlist[0]->name, 0);
15feac53 605
3c7d6fcc
EM
606 load_all_modules(0);
607 load_core_modules(0);
608 rehash(0);
15feac53 609
3c7d6fcc
EM
610 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
611 "Module Restart: %d modules unloaded, %d modules loaded",
612 modnum, num_mods);
613 ilog(L_MAIN, "Module Restart: %d modules unloaded, %d modules loaded", modnum, num_mods);
15feac53
AC
614}
615
3c7d6fcc 616static void
15feac53
AC
617do_modlist(struct Client *source_p, const char *pattern)
618{
619 int i;
620
212380e3
AC
621 for (i = 0; i < num_mods; i++)
622 {
978b7232
EM
623 const char *origin;
624 switch (modlist[i]->origin)
625 {
626 case MAPI_ORIGIN_EXTENSION:
627 origin = "extension";
628 break;
629 case MAPI_ORIGIN_CORE:
630 origin = "builtin";
631 break;
632 default:
633 origin = "unknown";
634 break;
635 }
636
15feac53 637 if(pattern)
212380e3 638 {
15feac53 639 if(match(pattern, modlist[i]->name))
212380e3
AC
640 {
641 sendto_one(source_p, form_str(RPL_MODLIST),
642 me.name, source_p->name,
643 modlist[i]->name,
978b7232
EM
644 (unsigned long)(uintptr_t)modlist[i]->address, origin,
645 modlist[i]->core ? " (core)" : "", modlist[i]->version, modlist[i]->description);
212380e3
AC
646 }
647 }
648 else
649 {
650 sendto_one(source_p, form_str(RPL_MODLIST),
651 me.name, source_p->name, modlist[i]->name,
978b7232
EM
652 (unsigned long)(uintptr_t)modlist[i]->address, origin,
653 modlist[i]->core ? " (core)" : "", modlist[i]->version, modlist[i]->description);
212380e3
AC
654 }
655 }
656
657 sendto_one(source_p, form_str(RPL_ENDOFMODLIST), me.name, source_p->name);
15feac53
AC
658}
659
212380e3
AC
660static void increase_modlist(void);
661
662#define MODS_INCREMENT 10
663
664static char unknown_ver[] = "<unknown>";
8e9c6a75 665static char unknown_description[] = "<none>";
212380e3 666
212380e3
AC
667/* unload_one_module()
668 *
669 * inputs - name of module to unload
670 * - 1 to say modules unloaded, 0 to not
671 * output - 0 if successful, -1 if error
672 * side effects - module is unloaded
673 */
674int
675unload_one_module(const char *name, int warn)
676{
677 int modindex;
678
679 if((modindex = findmodule_byname(name)) == -1)
680 return -1;
681
682 /*
683 ** XXX - The type system in C does not allow direct conversion between
684 ** data and function pointers, but as it happens, most C compilers will
55abcbb2
KB
685 ** safely do this, however it is a theoretical overlow to cast as we
686 ** must do here. I have library functions to take care of this, but
687 ** despite being more "correct" for the C language, this is more
212380e3
AC
688 ** practical. Removing the abuse of the ability to cast ANY pointer
689 ** to and from an integer value here will break some compilers.
690 ** -jmallett
691 */
692 /* Left the comment in but the code isn't here any more -larne */
693 switch (modlist[modindex]->mapi_version)
694 {
695 case 1:
696 {
697 struct mapi_mheader_av1 *mheader = modlist[modindex]->mapi_header;
698 if(mheader->mapi_command_list)
699 {
700 struct Message **m;
701 for (m = mheader->mapi_command_list; *m; ++m)
702 mod_del_cmd(*m);
703 }
704
705 /* hook events are never removed, we simply lose the
706 * ability to call them --fl
707 */
708 if(mheader->mapi_hfn_list)
709 {
710 mapi_hfn_list_av1 *m;
711 for (m = mheader->mapi_hfn_list; m->hapi_name; ++m)
712 remove_hook(m->hapi_name, m->fn);
713 }
714
715 if(mheader->mapi_unregister)
716 mheader->mapi_unregister();
717 break;
718 }
8e9c6a75
EM
719 case 2:
720 {
721 struct mapi_mheader_av2 *mheader = modlist[modindex]->mapi_header;
722
723 /* XXX duplicate code :( */
724 if(mheader->mapi_command_list)
725 {
726 struct Message **m;
727 for (m = mheader->mapi_command_list; *m; ++m)
728 mod_del_cmd(*m);
729 }
730
731 /* hook events are never removed, we simply lose the
732 * ability to call them --fl
733 */
734 if(mheader->mapi_hfn_list)
735 {
736 mapi_hfn_list_av1 *m;
737 for (m = mheader->mapi_hfn_list; m->hapi_name; ++m)
738 remove_hook(m->hapi_name, m->fn);
739 }
740
741 if(mheader->mapi_unregister)
742 mheader->mapi_unregister();
743
744 if(mheader->mapi_cap_list)
745 {
746 mapi_cap_list_av2 *m;
747 for (m = mheader->mapi_cap_list; m->cap_name; ++m)
748 {
749 struct CapabilityIndex *idx;
750
978b7232 751 switch (m->cap_index)
8e9c6a75
EM
752 {
753 case MAPI_CAP_CLIENT:
754 idx = cli_capindex;
755 break;
756 case MAPI_CAP_SERVER:
757 idx = serv_capindex;
758 break;
759 default:
760 sendto_realops_snomask(SNO_GENERAL, L_ALL,
761 "Unknown/unsupported CAP index found of type %d on capability %s when unloading %s",
762 m->cap_index, m->cap_name, modlist[modindex]->name);
763 ilog(L_MAIN,
764 "Unknown/unsupported CAP index found of type %d on capability %s when unloading %s",
765 m->cap_index, m->cap_name, modlist[modindex]->name);
766 continue;
767 }
768
769 capability_orphan(idx, m->cap_name);
770 }
771 }
772 }
212380e3
AC
773 default:
774 sendto_realops_snomask(SNO_GENERAL, L_ALL,
775 "Unknown/unsupported MAPI version %d when unloading %s!",
776 modlist[modindex]->mapi_version, modlist[modindex]->name);
777 ilog(L_MAIN, "Unknown/unsupported MAPI version %d when unloading %s!",
778 modlist[modindex]->mapi_version, modlist[modindex]->name);
779 break;
780 }
781
f272e7ab 782 lt_dlclose(modlist[modindex]->address);
212380e3 783
637c4932 784 rb_free(modlist[modindex]->name);
55d5f797 785 rb_free(modlist[modindex]);
f54e1a8f 786 memmove(&modlist[modindex], &modlist[modindex + 1],
1e170010 787 sizeof(struct module *) * ((num_mods - 1) - modindex));
212380e3
AC
788
789 if(num_mods != 0)
790 num_mods--;
791
792 if(warn == 1)
793 {
794 ilog(L_MAIN, "Module %s unloaded", name);
795 sendto_realops_snomask(SNO_GENERAL, L_ALL, "Module %s unloaded", name);
796 }
797
798 return 0;
799}
800
212380e3
AC
801/*
802 * load_a_module()
803 *
216d70e9 804 * inputs - path name of module, int to notice, int of origin, int of core
212380e3
AC
805 * output - -1 if error 0 if success
806 * side effects - loads a module if successful
807 */
808int
216d70e9 809load_a_module(const char *path, int warn, int origin, int core)
212380e3 810{
f272e7ab 811 lt_dlhandle tmpptr;
212380e3 812 char *mod_basename;
8e9c6a75 813 const char *ver, *description = NULL;
212380e3
AC
814
815 int *mapi_version;
816
b7a689d1 817 mod_basename = rb_basename(path);
212380e3 818
9abdcf1c 819 tmpptr = lt_dlopenext(path);
212380e3
AC
820
821 if(tmpptr == NULL)
822 {
f272e7ab 823 const char *err = lt_dlerror();
212380e3
AC
824
825 sendto_realops_snomask(SNO_GENERAL, L_ALL,
826 "Error loading module %s: %s", mod_basename, err);
827 ilog(L_MAIN, "Error loading module %s: %s", mod_basename, err);
637c4932 828 rb_free(mod_basename);
212380e3
AC
829 return -1;
830 }
831
212380e3
AC
832 /*
833 * _mheader is actually a struct mapi_mheader_*, but mapi_version
834 * is always the first member of this structure, so we treate it
835 * as a single int in order to determine the API version.
836 * -larne.
837 */
f272e7ab 838 mapi_version = (int *) (uintptr_t) lt_dlsym(tmpptr, "_mheader");
212380e3 839 if((mapi_version == NULL
f272e7ab 840 && (mapi_version = (int *) (uintptr_t) lt_dlsym(tmpptr, "__mheader")) == NULL)
212380e3
AC
841 || MAPI_MAGIC(*mapi_version) != MAPI_MAGIC_HDR)
842 {
843 sendto_realops_snomask(SNO_GENERAL, L_ALL,
844 "Data format error: module %s has no MAPI header.",
845 mod_basename);
846 ilog(L_MAIN, "Data format error: module %s has no MAPI header.", mod_basename);
f272e7ab 847 (void) lt_dlclose(tmpptr);
637c4932 848 rb_free(mod_basename);
212380e3
AC
849 return -1;
850 }
851
852 switch (MAPI_VERSION(*mapi_version))
853 {
854 case 1:
855 {
29c92cf9 856 struct mapi_mheader_av1 *mheader = (struct mapi_mheader_av1 *)(void *)mapi_version; /* see above */
212380e3
AC
857 if(mheader->mapi_register && (mheader->mapi_register() == -1))
858 {
859 ilog(L_MAIN, "Module %s indicated failure during load.",
860 mod_basename);
861 sendto_realops_snomask(SNO_GENERAL, L_ALL,
862 "Module %s indicated failure during load.",
863 mod_basename);
f272e7ab 864 lt_dlclose(tmpptr);
637c4932 865 rb_free(mod_basename);
212380e3
AC
866 return -1;
867 }
868 if(mheader->mapi_command_list)
869 {
870 struct Message **m;
871 for (m = mheader->mapi_command_list; *m; ++m)
872 mod_add_cmd(*m);
873 }
874
875 if(mheader->mapi_hook_list)
876 {
877 mapi_hlist_av1 *m;
878 for (m = mheader->mapi_hook_list; m->hapi_name; ++m)
879 *m->hapi_id = register_hook(m->hapi_name);
880 }
881
882 if(mheader->mapi_hfn_list)
883 {
884 mapi_hfn_list_av1 *m;
885 for (m = mheader->mapi_hfn_list; m->hapi_name; ++m)
886 add_hook(m->hapi_name, m->fn);
887 }
888
889 ver = mheader->mapi_module_version;
890 break;
891 }
8e9c6a75
EM
892 case 2:
893 {
894 struct mapi_mheader_av2 *mheader = (struct mapi_mheader_av2 *)(void *)mapi_version; /* see above */
212380e3 895
8e9c6a75
EM
896 /* XXX duplicated code :( */
897 if(mheader->mapi_register && (mheader->mapi_register() == -1))
898 {
899 ilog(L_MAIN, "Module %s indicated failure during load.",
81204be8 900 mod_basename);
8e9c6a75
EM
901 sendto_realops_snomask(SNO_GENERAL, L_ALL,
902 "Module %s indicated failure during load.",
903 mod_basename);
904 lt_dlclose(tmpptr);
905 rb_free(mod_basename);
906 return -1;
907 }
81204be8
EM
908
909 /* Basic date code checks
910 *
911 * Don't make them fatal, but do complain about differences within a certain time frame.
912 * Later on if there are major API changes we can add fatal checks.
913 * -- Elizafox
914 */
915 if(mheader->mapi_datecode != datecode && mheader->mapi_datecode > 0)
916 {
3089f59c 917 long int delta = datecode - mheader->mapi_datecode;
81204be8
EM
918 if (delta > MOD_WARN_DELTA)
919 {
920 delta /= 86400;
881acf00 921 iwarn("Module %s build date is out of sync with ircd build date by %ld days, expect problems",
81204be8
EM
922 mod_basename, delta);
923 sendto_realops_snomask(SNO_GENERAL, L_ALL,
924 "Module %s build date is out of sync with ircd build date by %ld days, expect problems",
925 mod_basename, delta);
926 }
927 }
928
8e9c6a75
EM
929 if(mheader->mapi_command_list)
930 {
931 struct Message **m;
932 for (m = mheader->mapi_command_list; *m; ++m)
933 mod_add_cmd(*m);
934 }
935
936 if(mheader->mapi_hook_list)
937 {
938 mapi_hlist_av1 *m;
939 for (m = mheader->mapi_hook_list; m->hapi_name; ++m)
940 *m->hapi_id = register_hook(m->hapi_name);
941 }
942
943 if(mheader->mapi_hfn_list)
944 {
945 mapi_hfn_list_av1 *m;
946 for (m = mheader->mapi_hfn_list; m->hapi_name; ++m)
947 add_hook(m->hapi_name, m->fn);
948 }
949
950 /* New in MAPI v2 - version replacement */
951 ver = mheader->mapi_module_version ? mheader->mapi_module_version : ircd_version;
952 description = mheader->mapi_module_description;
953
954 if(mheader->mapi_cap_list)
955 {
956 mapi_cap_list_av2 *m;
957 for (m = mheader->mapi_cap_list; m->cap_name; ++m)
958 {
959 struct CapabilityIndex *idx;
960 int result;
961
978b7232 962 switch (m->cap_index)
8e9c6a75
EM
963 {
964 case MAPI_CAP_CLIENT:
965 idx = cli_capindex;
966 break;
967 case MAPI_CAP_SERVER:
968 idx = serv_capindex;
969 break;
970 default:
971 sendto_realops_snomask(SNO_GENERAL, L_ALL,
972 "Unknown/unsupported CAP index found of type %d on capability %s when loading %s",
973 m->cap_index, m->cap_name, mod_basename);
974 ilog(L_MAIN,
975 "Unknown/unsupported CAP index found of type %d on capability %s when loading %s",
976 m->cap_index, m->cap_name, mod_basename);
977 continue;
978 }
979
980 result = capability_put(idx, m->cap_name, m->cap_ownerdata);
981 if (m->cap_id != NULL)
982 *(m->cap_id) = result;
983 }
984 }
985 }
0e5bf029
EM
986
987 break;
212380e3
AC
988 default:
989 ilog(L_MAIN, "Module %s has unknown/unsupported MAPI version %d.",
990 mod_basename, MAPI_VERSION(*mapi_version));
991 sendto_realops_snomask(SNO_GENERAL, L_ALL,
992 "Module %s has unknown/unsupported MAPI version %d.",
993 mod_basename, *mapi_version);
f272e7ab 994 lt_dlclose(tmpptr);
637c4932 995 rb_free(mod_basename);
212380e3
AC
996 return -1;
997 }
998
999 if(ver == NULL)
1000 ver = unknown_ver;
1001
8e9c6a75
EM
1002 if(description == NULL)
1003 description = unknown_description;
1004
212380e3
AC
1005 increase_modlist();
1006
eddc2ab6 1007 modlist[num_mods] = rb_malloc(sizeof(struct module));
212380e3
AC
1008 modlist[num_mods]->address = tmpptr;
1009 modlist[num_mods]->version = ver;
0eb7d9c0 1010 modlist[num_mods]->description = description;
212380e3 1011 modlist[num_mods]->core = core;
47a03750 1012 modlist[num_mods]->name = rb_strdup(mod_basename);
212380e3
AC
1013 modlist[num_mods]->mapi_header = mapi_version;
1014 modlist[num_mods]->mapi_version = MAPI_VERSION(*mapi_version);
c63aeb44 1015 modlist[num_mods]->origin = origin;
212380e3
AC
1016 num_mods++;
1017
1018 if(warn == 1)
1019 {
c63aeb44
EM
1020 const char *o;
1021
978b7232 1022 switch (origin)
c63aeb44 1023 {
c63aeb44
EM
1024 case MAPI_ORIGIN_EXTENSION:
1025 o = "extension";
1026 break;
1027 case MAPI_ORIGIN_CORE:
1028 o = "core";
1029 break;
1030 default:
1031 o = "unknown";
1032 break;
1033 }
1034
212380e3 1035 sendto_realops_snomask(SNO_GENERAL, L_ALL,
c63aeb44
EM
1036 "Module %s [version: %s; MAPI version: %d; origin: %s; description: \"%s\"] loaded at 0x%lx",
1037 mod_basename, ver, MAPI_VERSION(*mapi_version), o, description,
212380e3 1038 (unsigned long) tmpptr);
c63aeb44
EM
1039 ilog(L_MAIN, "Module %s [version: %s; MAPI version: %d; origin: %s; description: \"%s\"] loaded at 0x%lx",
1040 mod_basename, ver, MAPI_VERSION(*mapi_version), o, description, (unsigned long) tmpptr);
212380e3 1041 }
637c4932 1042 rb_free(mod_basename);
212380e3
AC
1043 return 0;
1044}
1045
1046/*
1047 * increase_modlist
1048 *
1049 * inputs - NONE
1050 * output - NONE
1051 * side effects - expand the size of modlist if necessary
1052 */
1053static void
1054increase_modlist(void)
1055{
1056 struct module **new_modlist = NULL;
1057
1058 if((num_mods + 1) < max_mods)
1059 return;
1060
1e170010 1061 new_modlist = (struct module **) rb_malloc(sizeof(struct module *) *
212380e3 1062 (max_mods + MODS_INCREMENT));
1e170010 1063 memcpy((void *) new_modlist, (void *) modlist, sizeof(struct module *) * num_mods);
212380e3 1064
637c4932 1065 rb_free(modlist);
212380e3
AC
1066 modlist = new_modlist;
1067 max_mods += MODS_INCREMENT;
1068}