]> jfr.im git - solanum.git/blob - ircd/modules.c
More bool conversions [ci skip]
[solanum.git] / ircd / modules.c
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
23 */
24
25 #include "stdinc.h"
26 #include "modules.h"
27 #include "logger.h"
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"
36 #include "match.h"
37 #include "s_serv.h"
38 #include "capability.h"
39
40 #include <ltdl.h>
41
42 struct module **modlist = NULL;
43
44 static const char *core_module_table[] = {
45 "m_ban",
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",
57 "m_squit",
58 NULL
59 };
60
61 #define MOD_WARN_DELTA (90 * 86400) /* time in seconds, 86400 seconds in a day */
62
63 #define MODS_INCREMENT 10
64 int num_mods = 0;
65 int max_mods = MODS_INCREMENT;
66
67 static rb_dlink_list mod_paths;
68
69 static void mo_modload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
70 static void mo_modlist(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
71 static void mo_modreload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
72 static void mo_modunload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
73 static void mo_modrestart(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
74
75 static void me_modload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
76 static void me_modlist(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
77 static void me_modreload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
78 static void me_modunload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
79 static void me_modrestart(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
80
81 static void do_modload(struct Client *, const char *);
82 static void do_modunload(struct Client *, const char *);
83 static void do_modreload(struct Client *, const char *);
84 static void do_modlist(struct Client *, const char *);
85 static void do_modrestart(struct Client *);
86
87 struct Message modload_msgtab = {
88 "MODLOAD", 0, 0, 0, 0,
89 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modload, 2}, {mo_modload, 2}}
90 };
91
92 struct Message modunload_msgtab = {
93 "MODUNLOAD", 0, 0, 0, 0,
94 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modunload, 2}, {mo_modunload, 2}}
95 };
96
97 struct Message modreload_msgtab = {
98 "MODRELOAD", 0, 0, 0, 0,
99 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modreload, 2}, {mo_modreload, 2}}
100 };
101
102 struct Message modlist_msgtab = {
103 "MODLIST", 0, 0, 0, 0,
104 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modlist, 0}, {mo_modlist, 0}}
105 };
106
107 struct Message modrestart_msgtab = {
108 "MODRESTART", 0, 0, 0, 0,
109 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modrestart, 0}, {mo_modrestart, 0}}
110 };
111
112 void
113 modules_init(void)
114 {
115 if(lt_dlinit())
116 {
117 ilog(L_MAIN, "lt_dlinit failed");
118 exit(0);
119 }
120
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 */
138 static char *
139 mod_find_path(const char *path)
140 {
141 rb_dlink_node *ptr;
142 char *mpath;
143
144 RB_DLINK_FOREACH(ptr, mod_paths.head)
145 {
146 mpath = ptr->data;
147
148 if(!strcmp(path, mpath))
149 return mpath;
150 }
151
152 return NULL;
153 }
154
155 /* mod_add_path
156 *
157 * input - path
158 * ouput -
159 * side effects - adds path to list
160 */
161 void
162 mod_add_path(const char *path)
163 {
164 char *pathst;
165
166 if(mod_find_path(path))
167 return;
168
169 pathst = rb_strdup(path);
170 rb_dlinkAddAlloc(pathst, &mod_paths);
171 }
172
173 /* mod_clear_paths()
174 *
175 * input -
176 * output -
177 * side effects - clear the lists of paths
178 */
179 void
180 mod_clear_paths(void)
181 {
182 rb_dlink_node *ptr, *next_ptr;
183
184 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, mod_paths.head)
185 {
186 rb_free(ptr->data);
187 rb_free_rb_dlink_node(ptr);
188 }
189
190 mod_paths.head = mod_paths.tail = NULL;
191 mod_paths.length = 0;
192 }
193
194 /* findmodule_byname
195 *
196 * input -
197 * output -
198 * side effects -
199 */
200
201 int
202 findmodule_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 */
220 void
221 load_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
230 modlist = (struct module **) rb_malloc(sizeof(struct module *) * (MODS_INCREMENT));
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 {
244 len = strlen(ldirent->d_name);
245 if((len > 3) && !strcmp(ldirent->d_name+len-3, ".la"))
246 {
247 (void) snprintf(module_fq_name, sizeof(module_fq_name), "%s/%s", AUTOMODPATH, ldirent->d_name);
248 (void) load_a_module(module_fq_name, warn, MAPI_ORIGIN_CORE, 0);
249 }
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 */
261 void
262 load_core_modules(int warn)
263 {
264 char module_name[PATH_MAX];
265 int i;
266
267
268 for (i = 0; core_module_table[i]; i++)
269 {
270 snprintf(module_name, sizeof(module_name), "%s/%s%s", MODPATH,
271 core_module_table[i], ".la");
272
273 if(load_a_module(module_name, warn, MAPI_ORIGIN_CORE, 1) == -1)
274 {
275 ilog(L_MAIN,
276 "Error loading core module %s%s: terminating ircd",
277 core_module_table[i], ".la");
278 exit(0);
279 }
280 }
281 }
282
283 /* load_one_module()
284 *
285 * input -
286 * output -
287 * side effects -
288 */
289 int
290 load_one_module(const char *path, int origin, int coremodule)
291 {
292 char modpath[PATH_MAX];
293 rb_dlink_node *pathst;
294 const char *mpath;
295
296 struct stat statbuf;
297
298 if (server_state_foreground == 1)
299 inotice("loading module %s ...", path);
300
301 if(coremodule != 0)
302 {
303 coremodule = 1;
304 origin = MAPI_ORIGIN_CORE;
305 }
306
307 RB_DLINK_FOREACH(pathst, mod_paths.head)
308 {
309 mpath = pathst->data;
310
311 snprintf(modpath, sizeof(modpath), "%s/%s", mpath, path);
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 */
319 return load_a_module(modpath, 1, origin, coremodule);
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 .. */
332 static void
333 mo_modload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
334 {
335 if(!IsOperAdmin(source_p))
336 {
337 sendto_one(source_p, form_str(ERR_NOPRIVS),
338 me.name, source_p->name, "admin");
339 return;
340 }
341
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)
347 return;
348 }
349
350 do_modload(source_p, parv[1]);
351 }
352
353 static void
354 me_modload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
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.");
360 return;
361 }
362
363 do_modload(source_p, parv[1]);
364 }
365
366
367 /* unload a module .. */
368 static void
369 mo_modunload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
370 {
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 }
377
378 if(parc > 2)
379 {
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;
384 }
385
386 do_modunload(source_p, parv[1]);
387 }
388
389 static void
390 me_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 }
398
399 do_modunload(source_p, parv[1]);
400 }
401
402 /* unload and load in one! */
403 static void
404 mo_modreload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
405 {
406 if(!IsOperAdmin(source_p))
407 {
408 sendto_one(source_p, form_str(ERR_NOPRIVS),
409 me.name, source_p->name, "admin");
410 return;
411 }
412
413 if(parc > 2)
414 {
415 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
416 "ENCAP %s MODRELOAD %s", parv[2], parv[1]);
417 if (match(parv[2], me.name) == 0)
418 return;
419 }
420
421 do_modreload(source_p, parv[1]);
422 }
423
424 static void
425 me_modreload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
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.");
431 return;
432 }
433
434 do_modreload(source_p, parv[1]);
435 }
436
437 /* list modules .. */
438 static void
439 mo_modlist(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
440 {
441 if(!IsOperAdmin(source_p))
442 {
443 sendto_one(source_p, form_str(ERR_NOPRIVS),
444 me.name, source_p->name, "admin");
445 return;
446 }
447
448 if(parc > 2)
449 {
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;
454 }
455
456 do_modlist(source_p, parc > 1 ? parv[1] : 0);
457 }
458
459 static void
460 me_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))
463 {
464 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
465 "to load modules on this server.");
466 return;
467 }
468
469 do_modlist(source_p, parv[1]);
470 }
471
472 /* unload and reload all modules */
473 static void
474 mo_modrestart(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
475 {
476 if(!IsOperAdmin(source_p))
477 {
478 sendto_one(source_p, form_str(ERR_NOPRIVS),
479 me.name, source_p->name, "admin");
480 return;
481 }
482
483 if(parc > 1)
484 {
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;
489 }
490
491 do_modrestart(source_p);
492 }
493
494 static void
495 me_modrestart(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
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.");
501 return;
502 }
503
504 do_modrestart(source_p);
505 }
506
507 static void
508 do_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
526 static void
527 do_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
554 static void
555 do_modreload(struct Client *source_p, const char *module)
556 {
557 int modindex;
558 int check_core;
559 char *m_bn = rb_basename(module);
560
561 if((modindex = findmodule_byname(m_bn)) == -1)
562 {
563 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
564 rb_free(m_bn);
565 return;
566 }
567
568 check_core = modlist[modindex]->core;
569
570 if(unload_one_module(m_bn, 1) == -1)
571 {
572 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
573 rb_free(m_bn);
574 return;
575 }
576
577 if((load_one_module(m_bn, modlist[modindex]->origin, check_core) == -1) && check_core)
578 {
579 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
580 "Error reloading core module: %s: terminating ircd", m_bn);
581 ilog(L_MAIN, "Error loading core module %s: terminating ircd", m_bn);
582 exit(0);
583 }
584
585 rb_free(m_bn);
586 }
587
588 static void
589 do_modrestart(struct Client *source_p)
590 {
591 int modnum;
592
593 sendto_one_notice(source_p, ":Reloading all modules");
594
595 modnum = num_mods;
596 while (num_mods)
597 unload_one_module(modlist[0]->name, 0);
598
599 load_all_modules(0);
600 load_core_modules(0);
601 rehash(0);
602
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);
607 }
608
609 static void
610 do_modlist(struct Client *source_p, const char *pattern)
611 {
612 int i;
613
614 for (i = 0; i < num_mods; i++)
615 {
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
630 if(pattern)
631 {
632 if(match(pattern, modlist[i]->name))
633 {
634 sendto_one(source_p, form_str(RPL_MODLIST),
635 me.name, source_p->name,
636 modlist[i]->name,
637 (unsigned long)(uintptr_t)modlist[i]->address, origin,
638 modlist[i]->core ? " (core)" : "", modlist[i]->version, modlist[i]->description);
639 }
640 }
641 else
642 {
643 sendto_one(source_p, form_str(RPL_MODLIST),
644 me.name, source_p->name, modlist[i]->name,
645 (unsigned long)(uintptr_t)modlist[i]->address, origin,
646 modlist[i]->core ? " (core)" : "", modlist[i]->version, modlist[i]->description);
647 }
648 }
649
650 sendto_one(source_p, form_str(RPL_ENDOFMODLIST), me.name, source_p->name);
651 }
652
653 static void increase_modlist(void);
654
655 #define MODS_INCREMENT 10
656
657 static char unknown_ver[] = "<unknown>";
658 static char unknown_description[] = "<none>";
659
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 */
667 int
668 unload_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
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
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 }
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
744 switch (m->cap_index)
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 }
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
775 lt_dlclose(modlist[modindex]->address);
776
777 rb_free(modlist[modindex]->name);
778 rb_free(modlist[modindex]);
779 memmove(&modlist[modindex], &modlist[modindex + 1],
780 sizeof(struct module *) * ((num_mods - 1) - modindex));
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
794 /*
795 * load_a_module()
796 *
797 * inputs - path name of module, int to notice, int of origin, int of core
798 * output - -1 if error 0 if success
799 * side effects - loads a module if successful
800 */
801 int
802 load_a_module(const char *path, int warn, int origin, int core)
803 {
804 lt_dlhandle tmpptr;
805 char *mod_basename;
806 const char *ver, *description = NULL;
807
808 int *mapi_version;
809
810 mod_basename = rb_basename(path);
811
812 tmpptr = lt_dlopen(path);
813
814 if(tmpptr == NULL)
815 {
816 const char *err = lt_dlerror();
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);
821 rb_free(mod_basename);
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 */
832 mapi_version = (int *) (uintptr_t) lt_dlsym(tmpptr, "_mheader");
833 if((mapi_version == NULL
834 && (mapi_version = (int *) (uintptr_t) lt_dlsym(tmpptr, "__mheader")) == NULL)
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);
841 (void) lt_dlclose(tmpptr);
842 rb_free(mod_basename);
843 return -1;
844 }
845
846 switch (MAPI_VERSION(*mapi_version))
847 {
848 case 1:
849 {
850 struct mapi_mheader_av1 *mheader = (struct mapi_mheader_av1 *)(void *)mapi_version; /* see above */
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);
858 lt_dlclose(tmpptr);
859 rb_free(mod_basename);
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 }
886 case 2:
887 {
888 struct mapi_mheader_av2 *mheader = (struct mapi_mheader_av2 *)(void *)mapi_version; /* see above */
889
890 /* XXX duplicated code :( */
891 if(mheader->mapi_register && (mheader->mapi_register() == -1))
892 {
893 ilog(L_MAIN, "Module %s indicated failure during load.",
894 mod_basename);
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 }
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 {
911 long int delta = datecode - mheader->mapi_datecode;
912 if (delta > MOD_WARN_DELTA)
913 {
914 delta /= 86400;
915 iwarn("Module %s build date is out of sync with ircd build date by %ld days, expect problems",
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
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
956 switch (m->cap_index)
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 }
980
981 break;
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);
988 lt_dlclose(tmpptr);
989 rb_free(mod_basename);
990 return -1;
991 }
992
993 if(ver == NULL)
994 ver = unknown_ver;
995
996 if(description == NULL)
997 description = unknown_description;
998
999 increase_modlist();
1000
1001 modlist[num_mods] = rb_malloc(sizeof(struct module));
1002 modlist[num_mods]->address = tmpptr;
1003 modlist[num_mods]->version = ver;
1004 modlist[num_mods]->description = description;
1005 modlist[num_mods]->core = core;
1006 modlist[num_mods]->name = rb_strdup(mod_basename);
1007 modlist[num_mods]->mapi_header = mapi_version;
1008 modlist[num_mods]->mapi_version = MAPI_VERSION(*mapi_version);
1009 modlist[num_mods]->origin = origin;
1010 num_mods++;
1011
1012 if(warn == 1)
1013 {
1014 const char *o;
1015
1016 switch (origin)
1017 {
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
1029 sendto_realops_snomask(SNO_GENERAL, L_ALL,
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,
1032 (unsigned long) tmpptr);
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);
1035 }
1036 rb_free(mod_basename);
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 */
1047 static void
1048 increase_modlist(void)
1049 {
1050 struct module **new_modlist = NULL;
1051
1052 if((num_mods + 1) < max_mods)
1053 return;
1054
1055 new_modlist = (struct module **) rb_malloc(sizeof(struct module *) *
1056 (max_mods + MODS_INCREMENT));
1057 memcpy((void *) new_modlist, (void *) modlist, sizeof(struct module *) * num_mods);
1058
1059 rb_free(modlist);
1060 modlist = new_modlist;
1061 max_mods += MODS_INCREMENT;
1062 }