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