Restore stats_spy hook that was removed in commit 401f2454671ca233e35b0e6e4f3fa4c43cd...
[seven-1.x.git] / src / mod_dynamic.c
blob6f06cc63e67283adb04f9f96f980531c1d6ae7ed
1 /* {{{ irc-seven: Cows like it.
3 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center.
4 * Copyright (C) 1996-2002 Hybrid Development Team.
5 * Copyright (C) 2002-2005 ircd-ratbox development team.
6 * Copyright (C) 2006 Elfyn McBratney.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to:
21 * Free Software Foundation, Inc.
22 * 51 Franklin St - Fifth Floor
23 * Boston, MA 02110-1301
24 * USA
26 * }}} */
28 /* {{{ Includes. */
29 #include "stdinc.h"
30 #include "modules.h"
31 #include "s_log.h"
32 #include "ircd.h"
33 #include "client.h"
34 #include "send.h"
35 #include "s_conf.h"
36 #include "s_newconf.h"
37 #include "s_serv.h"
38 #include "numeric.h"
39 #include "parse.h"
40 #include "ircd_defs.h"
41 #include "irc_string.h"
42 #include "memory.h"
43 #include "tools.h"
44 #include "sprintf_irc.h"
45 /* }}} */
47 # define MODS_INCREMENT 10
49 struct module **modlist = NULL;
51 /* {{{ static const char *core_module_table[] = { ... } */
52 # define _M(s) #s
53 # define M(n) _M(m_##n)
55 static const char *core_module_table[] =
57 M(die),
58 M(error),
59 M(join),
60 M(kick),
61 M(kill),
62 M(message),
63 M(mode),
64 M(nick),
65 M(part),
66 M(quit),
67 M(server),
68 M(sjoin),
69 M(squit),
70 NULL,
72 /* }}} */
74 int num_mods = 0;
75 int max_mods = MODS_INCREMENT;
77 static dlink_list mod_paths;
79 extern struct Message error_msgtab;
81 /* {{{ Prototypes. */
82 static int mo_modload (struct Client *, struct Client *, int, const char **);
83 static int me_modload (struct Client *, struct Client *, int, const char **);
84 static int mo_modunload (struct Client *, struct Client *, int, const char **);
85 static int me_modunload (struct Client *, struct Client *, int, const char **);
86 static int mo_modreload (struct Client *, struct Client *, int, const char **);
87 static int me_modreload (struct Client *, struct Client *, int, const char **);
88 static int mo_modrestart (struct Client *, struct Client *, int, const char **);
89 static int me_modrestart (struct Client *, struct Client *, int, const char **);
90 static int mo_modlist (struct Client *, struct Client *, int, const char **);
91 static int me_modlist (struct Client *, struct Client *, int, const char **);
93 static int do_modload (struct Client *, const char *);
94 static int do_modunload (struct Client *, const char *);
95 static int do_modreload (struct Client *, const char *);
96 static int do_modrestart (struct Client *);
97 static int do_modlist (struct Client *);
98 /* }}} */
100 /* {{{ static struct Message modload_msgtab = { ... } */
101 struct Message modload_msgtab = {
102 "MODLOAD", 0, 0, 0, MFLG_SLOW,
104 mg_unreg, mg_not_oper, mg_ignore,
105 mg_ignore, {me_modload, 1}, {mo_modload, 0},
108 /* }}} */
110 /* {{{ static struct Message modunload_msgtab = { ... } */
111 struct Message modunload_msgtab =
113 "MODUNLOAD", 0, 0, 0, MFLG_SLOW,
115 mg_unreg, mg_not_oper, mg_ignore,
116 mg_ignore, {me_modunload, 1}, {mo_modunload, 0},
119 /* }}} */
121 /* {{{ static struct Message modreload_msgtab = { ... } */
122 struct Message modreload_msgtab =
124 "MODRELOAD", 0, 0, 0, MFLG_SLOW,
126 mg_unreg, mg_not_oper, mg_ignore,
127 mg_ignore, {me_modreload, 1}, {mo_modreload, 0},
130 /* }}} */
132 /* {{{ static struct Message modrestart_msgtab = { ... } */
133 struct Message modrestart_msgtab =
135 "MODRESTART", 0, 0, 0, MFLG_SLOW,
137 mg_unreg, mg_not_oper, mg_ignore,
138 mg_ignore, {me_modrestart, 0}, {mo_modrestart, 0},
141 /* }}} */
143 /* {{{ static struct Message modlist_msgtab = { ... } */
144 struct Message modlist_msgtab =
146 "MODLIST", 0, 0, 0, MFLG_SLOW,
148 mg_unreg, mg_not_oper, mg_ignore,
149 mg_ignore, {me_modlist, 0}, {mo_modlist, 0},
152 /* }}} */
154 /* {{{ void modules_init() */
155 void
156 modules_init (void)
158 mod_add_cmd(&modload_msgtab);
159 mod_add_cmd(&modunload_msgtab);
160 mod_add_cmd(&modreload_msgtab);
161 mod_add_cmd(&modlist_msgtab);
162 mod_add_cmd(&modrestart_msgtab);
164 /* Add the default paths we look in to the module system --nenolod */
165 mod_add_path(MODPATH);
166 mod_add_path(AUTOMODPATH);
168 /* }}} */
170 /* {{{ static struct module_path *mod_find_path()
172 * input - path
173 * output - none
174 * side effects - returns a module path from path
176 static struct module_path *
177 mod_find_path (const char *path)
179 dlink_node *cur = NULL;
180 struct module_path *mpath = NULL;
182 DLINK_FOREACH (cur, mod_paths.head)
184 mpath = cur->data;
185 if(!strcmp(path, mpath->path))
186 return mpath;
189 return NULL;
191 /* }}} */
193 /* {{{ void mod_add_path()
195 * input - path
196 * ouput -
197 * side effects - adds path to list
199 void
200 mod_add_path (const char *path)
202 struct module_path *pathst = NULL;
204 if(mod_find_path(path))
205 return;
207 pathst = MyMalloc(sizeof(*pathst));
208 strcpy(pathst->path, path);
209 dlinkAddAlloc(pathst, &mod_paths);
211 /* }}} */
213 /* {{{ void mod_clear_paths()
215 * input -
216 * output -
217 * side effects - clear the lists of paths
219 void
220 mod_clear_paths (void)
222 dlink_node *cur = NULL;
223 dlink_node *next = NULL;
225 DLINK_FOREACH_SAFE (cur, next, mod_paths.head)
227 MyFree(cur->data);
228 free_dlink_node(cur);
231 mod_paths.head = mod_paths.tail = NULL;
232 mod_paths.length = 0;
234 /* }}} */
236 /* {{{ char *irc_basename()
238 * input -
239 * output -
240 * side effects -
242 char *
243 irc_basename (const char *path)
245 char *mod_basename = MyMalloc(strlen(path) + 1);
246 const char *s = NULL;
248 s = strrchr(path, '/');
249 if (!s)
250 s = path;
251 else
252 ++s;
254 strcpy(mod_basename, s);
255 return mod_basename;
257 /* }}} */
259 /* {{{ int findmodule_byname()
261 * input -
262 * output -
263 * side effects -
266 findmodule_byname (const char *name)
268 int i;
270 for (i = 0; i < num_mods; ++i)
272 if(!irccmp(modlist[i]->name, name))
273 return i;
276 return -1;
278 /* }}} */
280 /* {{{ void load_all_modules()
282 * input -
283 * output -
284 * side effects -
286 void
287 load_all_modules (int warn)
289 DIR *system_module_dir = NULL;
290 struct dirent *ldirent = NULL;
291 char module_fq_name[PATH_MAX + 1];
292 int len;
294 modules_init();
296 modlist = (struct module **) MyMalloc(sizeof(struct module) * (MODS_INCREMENT));
297 max_mods = MODS_INCREMENT;
298 system_module_dir = opendir(AUTOMODPATH);
300 if(system_module_dir == NULL)
302 ilog(L_MAIN, "Could not load modules from %s: %s", AUTOMODPATH, strerror(errno));
303 return;
306 while ((ldirent = readdir(system_module_dir)) != NULL)
308 len = strlen(ldirent->d_name);
309 if((len > 3) && !strcmp(ldirent->d_name+len-3, SHARED_SUFFIX))
311 (void) ircsnprintf(module_fq_name, sizeof(module_fq_name), "%s/%s", AUTOMODPATH, ldirent->d_name);
312 (void) load_a_module(module_fq_name, warn, 0);
317 (void) closedir(system_module_dir);
319 /* }}} */
321 /* {{{ void load_core_modules()
323 * input -
324 * output -
325 * side effects - core modules are loaded, if any fail, kill ircd
327 void
328 load_core_modules (int warn)
330 int i;
331 char module_name[MAXPATHLEN];
333 for (i = 0; core_module_table[i]; ++i)
335 ircsnprintf(module_name, sizeof(module_name), "%s/%s%s", MODPATH,
336 core_module_table[i], SHARED_SUFFIX);
338 if(load_a_module(module_name, warn, 1) == -1)
340 ilog(L_MAIN,
341 "Error loading core module %s%s: terminating ircd",
342 core_module_table[i], SHARED_SUFFIX);
343 exit(0);
347 /* }}} */
349 /* {{{ int load_one_module()
351 * input -
352 * output -
353 * side effects -
356 load_one_module (const char *path, int coremodule)
358 char modpath[MAXPATHLEN];
359 dlink_node *cur = NULL;
360 struct module_path *mpath = NULL;
361 struct stat statbuf;
363 if (server_state_foreground == 1)
364 inotice("loading module %s ...", path);
366 DLINK_FOREACH (cur, mod_paths.head)
368 mpath = cur->data;
369 ircsnprintf(modpath, sizeof(modpath), "%s/%s", mpath->path, path);
371 if ((strstr(modpath, "../") == NULL) && (strstr(modpath, "/..") == NULL))
373 if (stat(modpath, &statbuf) == 0)
375 if (S_ISREG(statbuf.st_mode))
377 /* Regular files only please */
378 if (coremodule)
379 return load_a_module(modpath, 1, 1);
380 else
381 return load_a_module(modpath, 1, 0);
388 sendto_realops_snomask(SNO_GENERAL, L_ALL, "Cannot locate module %s", path);
389 return -1;
391 /* }}} */
393 /* {{{ static int mo_modload()
395 * Load a module into the IRCd.
397 * Usage:
398 * MODLOAD <module> [ON <server>]
400 * parv[0] - prefix
401 * parv[1] - module
402 * parv[2] - "ON", or nothing
403 * parv[3] - server, or nothing
405 static int
406 mo_modload (struct Client *client_p, struct Client *source_p, int parc, const char **parv)
408 if (!IsOperAdmin(source_p))
410 sendto_one(source_p, form_str(ERR_NOPRIVS),
411 me.name, source_p->name, "admin");
412 return 0;
414 else if (parc > 4)
416 sendto_one(source_p,
417 ":%s NOTICE %s :To many parameters to MODLOAD",
418 me.name, source_p->name);
419 return 0;
421 else if ((parc != 2 && parc != 4) || EmptyString(parv[1]))
423 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name,
424 source_p->name, "MODLOAD");
425 return 0;
428 /* remote? */
429 if (parc == 4)
431 if (EmptyString(parv[2]) | EmptyString(parv[3]))
433 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name,
434 source_p->name, "MODLOAD");
435 return 0;
437 else if (irccmp(parv[2], "ON") != 0)
439 sendto_one(source_p,
440 ":%s NOTICE %s :Second argument to MODLOAD "
441 "must be [ON] not [%s]",
442 me.name, source_p->name, parv[2]);
443 return 0;
446 sendto_match_servs(source_p, parv[3], CAP_ENCAP, NOCAPS,
447 "ENCAP %s MODLOAD :%s", parv[3], parv[1]);
449 if (!match(parv[3], me.name))
450 return 0;
453 return do_modload(source_p, parv[1]);
455 /* }}} */
457 /* {{{ static int me_modload()
459 * MODLOAD ENCAP message handler.
461 * Usage:
462 * MODLOAD <module>
464 * parv[0] - prefix
465 * parv[1] - module
467 static int
468 me_modload (struct Client *client_p, struct Client *source_p, int parc, const char **parv)
470 if (!IsPerson(source_p) || EmptyString(parv[1]))
471 return 0;
472 if (!find_client_shared_conf(source_p, SHARED_MODULE))
473 return 0;
475 return do_modload(source_p, parv[1]);
477 /* }}} */
479 /* {{{ static int do_modload()
481 * Perform actual loading of modules into the IRCd.
483 static int
484 do_modload (struct Client *source_p, const char *path)
486 char *base = NULL;
488 base = irc_basename(path);
489 if (findmodule_byname(base) != -1)
491 sendto_one(source_p,
492 ":%s NOTICE %s :Module %s is already loaded",
493 me.name, source_p->name, base);
495 MyFree(base);
496 return 0;
499 load_one_module(path, 0);
500 MyFree(base);
502 return 0;
504 /* }}} */
506 /* {{{ static int mo_modunload()
508 * Unload a module from the IRCd.
510 * Usage:
511 * MODUNLOAD <module>
513 * parv[0] - prefix
514 * parv[1] - module
516 static int
517 mo_modunload(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
519 if (!IsOperAdmin(source_p))
521 sendto_one(source_p, form_str(ERR_NOPRIVS),
522 me.name, source_p->name, "admin");
523 return 0;
525 else if (parc > 4)
527 sendto_one(source_p,
528 ":%s NOTICE %s :To many parameters to MODUNLOAD",
529 me.name, source_p->name);
530 return 0;
532 else if ((parc != 2 && parc != 4) || EmptyString(parv[1]))
534 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name,
535 source_p->name, "MODUNLOAD");
536 return 0;
539 /* remote? */
540 if (parc == 4)
542 if (EmptyString(parv[2]) | EmptyString(parv[3]))
544 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name,
545 source_p->name, "MODUNLOAD");
546 return 0;
548 else if (irccmp(parv[2], "ON") != 0)
550 sendto_one(source_p,
551 ":%s NOTICE %s :Second argument to MODUNLOAD "
552 "must be [ON] not [%s]",
553 me.name, source_p->name, parv[2]);
554 return 0;
557 sendto_match_servs(source_p, parv[3], CAP_ENCAP, NOCAPS,
558 "ENCAP %s MODUNLOAD :%s", parv[3], parv[1]);
560 if (!match(parv[3], me.name))
561 return 0;
564 return do_modunload(source_p, parv[1]);
566 /* }}} */
568 /* {{{ static int me_modunload()
570 * MODUNLOAD ENCAP message handler.
572 * Usage:
573 * MODUNLOAD <module>
575 * parv[0] - prefix
576 * parv[1] - module
578 static int
579 me_modunload (struct Client *client_p, struct Client *source_p, int parc, const char **parv)
581 if (!IsPerson(source_p) || EmptyString(parv[1]))
582 return 0;
583 if (!find_client_shared_conf(source_p, SHARED_MODULE))
584 return 0;
586 return do_modunload(source_p, parv[1]);
588 /* }}} */
590 /* {{{ static int do_modunload()
592 * Perform actual unloading of modules.
594 static int
595 do_modunload (struct Client *source_p, const char *path)
597 char *base = NULL;
598 int i;
600 base = irc_basename(path);
601 if ((i = findmodule_byname(base)) < 0)
603 sendto_one(source_p,
604 ":%s NOTICE %s :Module %s is not loaded",
605 me.name, source_p->name, base);
607 MyFree(base);
608 return 0;
611 if (modlist[i]->core == 1)
613 sendto_one(source_p,
614 ":%s NOTICE %s :Module %s is a core module and cannot be unloaded",
615 me.name, source_p->name, base);
617 MyFree(base);
618 return 0;
621 if (unload_one_module(base, 1) < 0)
622 sendto_one(source_p,
623 ":%s NOTICE %s :Module %s is not loaded",
624 me.name, source_p->name, base);
626 MyFree(base);
627 return 0;
629 /* }}} */
631 /* {{{ static int mo_modreload()
633 * Reload (i.e., unload and then load) a module.
635 * Usage:
636 * MODRELOAD <module> [ON <server>]
638 * parv[0] - prefix
639 * parv[1] - module
640 * parv[2] - "ON", or nothing
641 * parv[3] - server, or nothing
643 static int
644 mo_modreload (struct Client *client_p, struct Client *source_p, int parc, const char **parv)
646 if (!IsOperAdmin(source_p))
648 sendto_one(source_p, form_str(ERR_NOPRIVS),
649 me.name, source_p->name, "admin");
650 return 0;
652 else if (parc > 4)
654 sendto_one(source_p,
655 ":%s NOTICE %s :To many parameters to MODRELOAD",
656 me.name, source_p->name);
657 return 0;
659 else if ((parc != 2 && parc != 4) || EmptyString(parv[1]))
661 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name,
662 source_p->name, "MODRELOAD");
663 return 0;
666 /* remote? */
667 if (parc == 4)
669 if (EmptyString(parv[2]) | EmptyString(parv[3]))
671 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name,
672 source_p->name, "MODRELOAD");
673 return 0;
675 else if (irccmp(parv[2], "ON") != 0)
677 sendto_one(source_p,
678 ":%s NOTICE %s :Second argument to MODRELOAD "
679 "must be [ON] not [%s]",
680 me.name, source_p->name, parv[2]);
681 return 0;
684 sendto_match_servs(source_p, parv[3], CAP_ENCAP, NOCAPS,
685 "ENCAP %s MODRELOAD :%s", parv[3], parv[1]);
687 if (!match(parv[3], me.name))
688 return 0;
691 return do_modreload(source_p, parv[1]);
693 /* }}} */
695 /* {{{ static int me_modreload()
697 * MODRELOAD ENCAP message handler.
699 * Usage:
700 * MODRELOAD <module>
702 * parv[0] - prefix
703 * parv[1] - module
705 static int
706 me_modreload (struct Client *client_p, struct Client *source_p, int parc, const char **parv)
708 if (!IsPerson(source_p) || EmptyString(parv[1]))
709 return 0;
710 if (!find_client_shared_conf(source_p, SHARED_MODULE))
711 return 0;
713 return do_modreload(source_p, parv[1]);
715 /* }}} */
717 /* {{{ static int do_modreload()
719 * Perform actual reloading of modules.
721 static int
722 do_modreload (struct Client *source_p, const char *path)
724 char *base = NULL;
725 int i;
726 int is_core;
728 base = irc_basename(path);
729 if ((i = findmodule_byname(base)) < 0)
731 sendto_one(source_p,
732 ":%s NOTICE %s :Module %s is not loaded",
733 me.name, source_p->name, base);
735 MyFree(base);
736 return 0;
739 is_core = modlist[i]->core;
740 if (unload_one_module(base, 1) < 0)
742 sendto_one(source_p,
743 ":%s NOTICE %s :Module %s is not loaded",
744 me.name, source_p->name, base);
746 MyFree(base);
747 return 0;
750 if (load_one_module(path, is_core) < 0 && is_core)
752 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
753 "Error while reloading core module: %s; terminating ircd",
754 path);
756 ilog(L_MAIN,
757 "Error while reloading core module: %s; terminating ircd",
758 path);
759 exit(0);
762 MyFree(base);
763 return 0;
765 /* }}} */
767 /* {{{ static int mo_modrestart()
769 * Reload all modules.
771 * Usage:
772 * MODRESTART [ON <server>]
774 * parv[0] - prefix
775 * parv[1] - "ON", or nothing
776 * parv[2] - server, or nothing
778 static int
779 mo_modrestart (struct Client *client_p, struct Client *source_p, int parc, const char **parv)
781 if (!IsOperAdmin(source_p))
783 sendto_one(source_p, form_str(ERR_NOPRIVS),
784 me.name, source_p->name, "admin");
785 return 0;
787 else if (parc > 3)
789 sendto_one(source_p,
790 ":%s NOTICE %s :To many parameters to MODRESTART",
791 me.name, source_p->name);
792 return 0;
794 else if (parc == 2 || (parc == 3 && (EmptyString(parv[1]) || EmptyString(parv[2]))))
796 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name,
797 source_p->name, "MODRESTART");
798 return 0;
801 if (parc == 3)
803 if (irccmp(parv[1], "ON") != 0)
805 sendto_one(source_p,
806 ":%s NOTICE %s :Second argument to MODRESTART "
807 "must be [ON] not [%s]",
808 me.name, source_p->name, parv[1]);
809 return 0;
812 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
813 "ENCAP %s MODRESTART", parv[2]);
815 if (!match(parv[2], me.name))
816 return 0;
819 return do_modrestart(source_p);
821 /* }}} */
823 /* {{{ static int me_modrestart()
825 * MODRESTART ENCAP message handler.
827 * Usage:
828 * MODRESTART
830 * parv[0] - prefix
832 static int
833 me_modrestart (struct Client *client_p, struct Client *source_p, int parc, const char **parv)
835 if (!IsPerson(source_p))
836 return 0;
837 if (!find_client_shared_conf(source_p, SHARED_MODULE))
838 return 0;
840 return do_modrestart(source_p);
842 /* }}} */
844 /* {{{ static int do_modrestart()
846 * Perform actual restart of all modules.
848 static int
849 do_modrestart (struct Client *source_p)
851 int n;
853 sendto_one(source_p, ":%s NOTICE %s :Reloading all modules",
854 me.name, source_p->name);
856 n = num_mods;
857 while (num_mods)
858 unload_one_module(modlist[0]->name, 0);
860 load_all_modules(0);
861 load_core_modules(0);
862 rehash(0);
864 sendto_realops_snomask(SNO_GENERAL, L_ALL,
865 "Module Restart: %d modules unloaded, %d modules loaded",
866 n, num_mods);
867 ilog(L_MAIN, "Module Restart: %d modules unloaded, %d modules loaded",
868 n, num_mods);
870 return 0;
872 /* }}} */
874 /* {{{ static int mo_modlist()
876 * List modules currently loaded into the IRCd.
878 * Usage:
879 * MODLIST [<module>] [ON <server>]
881 * parv[0] - prefix
882 * parv[2] - "ON", or nothing
883 * parv[3] - server, or nothing
885 static int
886 mo_modlist (struct Client *client_p, struct Client *source_p, int parc, const char **parv)
888 if (!IsOperAdmin(source_p))
890 sendto_one(source_p, form_str(ERR_NOPRIVS),
891 me.name, source_p->name, "admin");
892 return 0;
894 else if (parc > 3)
896 sendto_one(source_p,
897 ":%s NOTICE %s :To many parameters to MODLIST",
898 me.name, source_p->name);
899 return 0;
901 else if (parc == 2 || (parc == 3 && (EmptyString(parv[1]) || EmptyString(parv[2]))))
903 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name,
904 source_p->name, "MODLIST");
905 return 0;
908 if (parc == 3)
910 if (irccmp(parv[1], "ON") != 0)
912 sendto_one(source_p,
913 ":%s NOTICE %s :Second argument to MODLIST "
914 "must be [ON] not [%s]",
915 me.name, source_p->name, parv[1]);
916 return 0;
919 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
920 "ENCAP %s MODLIST", parv[2]);
922 if (!match(parv[2], me.name))
923 return 0;
926 return do_modlist(source_p);
928 /* }}} */
930 /* {{{ static int me_modlist()
932 * MODLIST ENCAP message handler.
934 * Usage:
935 * MODLIST
937 * parv[0] - prefix
939 static int
940 me_modlist (struct Client *client_p, struct Client *source_p, int parc, const char **parv)
942 if (!IsPerson(source_p))
943 return 0;
944 if (!find_client_shared_conf(source_p, SHARED_MODULE))
945 return 0;
947 return do_modlist(source_p);
949 /* }}} */
951 /* {{{ static int do_modlist()
953 * Perform actual listing of loaded in modules.
955 static int
956 do_modlist (struct Client *source_p)
958 int i;
960 for (i = 0; i < num_mods; ++i)
962 sendto_one(source_p, form_str(RPL_MODLIST), me.name,
963 source_p->name, modlist[i]->name,
964 modlist[i]->address, modlist[i]->version,
965 modlist[i]->core ? "(core)" : "");
968 sendto_one(source_p, form_str(RPL_ENDOFMODLIST), me.name,
969 source_p->name);
971 return 0;
973 /* }}} */
975 # ifndef RTLD_NOW
976 # define RTLD_NOW RTLD_LAZY /* openbsd deficiency */
977 # endif
979 # ifdef SEVEN_PROFILE
980 # ifndef RTLD_PROFILE
981 # warning libdl may not support profiling, sucks. :(
982 # define RTLD_PROFILE 0
983 # endif
984 # endif
986 static void increase_modlist(void);
988 static char unknown_ver[] = "<unknown>";
990 /* {{{ int unload_one_module()
992 * inputs - name of module to unload
993 * - 1 to say modules unloaded, 0 to not
994 * output - 0 if successful, -1 if error
995 * side effects - module is unloaded
998 unload_one_module(const char *name, int warn)
1000 int modindex;
1002 if((modindex = findmodule_byname(name)) == -1)
1003 return -1;
1006 ** XXX - The type system in C does not allow direct conversion between
1007 ** data and function pointers, but as it happens, most C compilers will
1008 ** safely do this, however it is a theoretical overlow to cast as we
1009 ** must do here. I have library functions to take care of this, but
1010 ** despite being more "correct" for the C language, this is more
1011 ** practical. Removing the abuse of the ability to cast ANY pointer
1012 ** to and from an integer value here will break some compilers.
1013 ** -jmallett
1015 /* Left the comment in but the code isn't here any more -larne */
1016 switch (modlist[modindex]->mapi_version)
1018 case 1:
1020 struct mapi_mheader_av1 *mheader = modlist[modindex]->mapi_header;
1021 if(mheader->mapi_command_list)
1023 struct Message **m;
1024 for (m = mheader->mapi_command_list; *m; ++m)
1025 mod_del_cmd(*m);
1028 /* hook events are never removed, we simply lose the
1029 * ability to call them --fl
1031 if(mheader->mapi_hfn_list)
1033 mapi_hfn_list_av1 *m;
1034 for (m = mheader->mapi_hfn_list; m->hapi_name; ++m)
1035 remove_hook(m->hapi_name, m->fn);
1038 if(mheader->mapi_unregister)
1039 mheader->mapi_unregister();
1040 break;
1042 default:
1043 sendto_realops_snomask(SNO_GENERAL, L_ALL,
1044 "Unknown/unsupported MAPI version %d when unloading %s!",
1045 modlist[modindex]->mapi_version, modlist[modindex]->name);
1046 ilog(L_MAIN, "Unknown/unsupported MAPI version %d when unloading %s!",
1047 modlist[modindex]->mapi_version, modlist[modindex]->name);
1048 break;
1051 dlclose(modlist[modindex]->address);
1053 MyFree(modlist[modindex]->name);
1054 memcpy(&modlist[modindex], &modlist[modindex + 1],
1055 sizeof(struct module) * ((num_mods - 1) - modindex));
1057 if(num_mods != 0)
1058 num_mods--;
1060 if(warn == 1)
1062 ilog(L_MAIN, "Module %s unloaded", name);
1063 sendto_realops_snomask(SNO_GENERAL, L_ALL, "Module %s unloaded", name);
1066 return 0;
1068 /* }}} */
1070 /* {{{ int load_a_module()
1072 * inputs - path name of module, int to notice, int of core
1073 * output - -1 if error 0 if success
1074 * side effects - loads a module if successful
1077 load_a_module(const char *path, int warn, int core)
1079 void *tmpptr = NULL;
1081 char *mod_basename;
1082 const char *ver;
1084 int *mapi_version;
1086 mod_basename = irc_basename(path);
1088 #ifdef SEVEN_PROFILE
1089 tmpptr = dlopen(path, RTLD_NOW | RTLD_PROFILE);
1090 #else
1091 tmpptr = dlopen(path, RTLD_NOW);
1092 #endif
1094 if(tmpptr == NULL)
1096 const char *err = dlerror();
1098 sendto_realops_snomask(SNO_GENERAL, L_ALL,
1099 "Error loading module %s: %s", mod_basename, err);
1100 ilog(L_MAIN, "Error loading module %s: %s", mod_basename, err);
1101 MyFree(mod_basename);
1102 return -1;
1107 * _mheader is actually a struct mapi_mheader_*, but mapi_version
1108 * is always the first member of this structure, so we treate it
1109 * as a single int in order to determine the API version.
1110 * -larne.
1112 mapi_version = (int *) (uintptr_t) dlsym(tmpptr, "_mheader");
1113 if((mapi_version == NULL
1114 && (mapi_version = (int *) (uintptr_t) dlsym(tmpptr, "__mheader")) == NULL)
1115 || MAPI_MAGIC(*mapi_version) != MAPI_MAGIC_HDR)
1117 sendto_realops_snomask(SNO_GENERAL, L_ALL,
1118 "Data format error: module %s has no MAPI header.",
1119 mod_basename);
1120 ilog(L_MAIN, "Data format error: module %s has no MAPI header.", mod_basename);
1121 (void) dlclose(tmpptr);
1122 MyFree(mod_basename);
1123 return -1;
1126 switch (MAPI_VERSION(*mapi_version))
1128 case 1:
1130 struct mapi_mheader_av1 *mheader = (struct mapi_mheader_av1 *) mapi_version; /* see above */
1131 if(mheader->mapi_register && (mheader->mapi_register() == -1))
1133 ilog(L_MAIN, "Module %s indicated failure during load.",
1134 mod_basename);
1135 sendto_realops_snomask(SNO_GENERAL, L_ALL,
1136 "Module %s indicated failure during load.",
1137 mod_basename);
1138 dlclose(tmpptr);
1139 MyFree(mod_basename);
1140 return -1;
1142 if(mheader->mapi_command_list)
1144 struct Message **m;
1145 for (m = mheader->mapi_command_list; *m; ++m)
1146 mod_add_cmd(*m);
1149 if(mheader->mapi_hook_list)
1151 mapi_hlist_av1 *m;
1152 for (m = mheader->mapi_hook_list; m->hapi_name; ++m)
1153 *m->hapi_id = register_hook(m->hapi_name);
1156 if(mheader->mapi_hfn_list)
1158 mapi_hfn_list_av1 *m;
1159 for (m = mheader->mapi_hfn_list; m->hapi_name; ++m)
1160 add_hook(m->hapi_name, m->fn);
1163 ver = mheader->mapi_module_version;
1164 break;
1167 default:
1168 ilog(L_MAIN, "Module %s has unknown/unsupported MAPI version %d.",
1169 mod_basename, MAPI_VERSION(*mapi_version));
1170 sendto_realops_snomask(SNO_GENERAL, L_ALL,
1171 "Module %s has unknown/unsupported MAPI version %d.",
1172 mod_basename, *mapi_version);
1173 dlclose(tmpptr);
1174 MyFree(mod_basename);
1175 return -1;
1178 if(ver == NULL)
1179 ver = unknown_ver;
1181 increase_modlist();
1183 modlist[num_mods] = MyMalloc(sizeof(struct module));
1184 modlist[num_mods]->address = tmpptr;
1185 modlist[num_mods]->version = ver;
1186 modlist[num_mods]->core = core;
1187 DupString(modlist[num_mods]->name, mod_basename);
1188 modlist[num_mods]->mapi_header = mapi_version;
1189 modlist[num_mods]->mapi_version = MAPI_VERSION(*mapi_version);
1190 num_mods++;
1192 if(warn == 1)
1194 sendto_realops_snomask(SNO_GENERAL, L_ALL,
1195 "Module %s [version: %s; MAPI version: %d] loaded at 0x%lx",
1196 mod_basename, ver, MAPI_VERSION(*mapi_version),
1197 (unsigned long) tmpptr);
1198 ilog(L_MAIN, "Module %s [version: %s; MAPI version: %d] loaded at 0x%lx",
1199 mod_basename, ver, MAPI_VERSION(*mapi_version), (unsigned long) tmpptr);
1201 MyFree(mod_basename);
1202 return 0;
1204 /* }}} */
1206 /* {{{ static void increase_modlist()
1208 * inputs - NONE
1209 * output - NONE
1210 * side effects - expand the size of modlist if necessary
1212 static void
1213 increase_modlist(void)
1215 struct module **new_modlist = NULL;
1217 if((num_mods + 1) < max_mods)
1218 return;
1220 new_modlist = (struct module **) MyMalloc(sizeof(struct module) *
1221 (max_mods + MODS_INCREMENT));
1222 memcpy((void *) new_modlist, (void *) modlist, sizeof(struct module) * num_mods);
1224 MyFree(modlist);
1225 modlist = new_modlist;
1226 max_mods += MODS_INCREMENT;
1228 /* }}} */
1231 * vim: ts=8 sw=8 noet fdm=marker tw=80