1 /* modules/m_modules.c - module for module loading
2 * Copyright (c) 2016 Elizabeth Myers <elizabeth@interlinked.me>
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice is present in all copies.
8 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
9 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
11 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
12 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
13 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
14 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
15 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
16 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
17 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
18 * POSSIBILITY OF SUCH DAMAGE.
26 #include "s_newconf.h"
37 static const char modules_desc
[] = "Provides module management commands";
39 static void mo_modload(struct MsgBuf
*, struct Client
*, struct Client
*, int, const char **);
40 static void mo_modlist(struct MsgBuf
*, struct Client
*, struct Client
*, int, const char **);
41 static void mo_modreload(struct MsgBuf
*, struct Client
*, struct Client
*, int, const char **);
42 static void mo_modunload(struct MsgBuf
*, struct Client
*, struct Client
*, int, const char **);
43 static void mo_modrestart(struct MsgBuf
*, struct Client
*, struct Client
*, int, const char **);
45 static void me_modload(struct MsgBuf
*, struct Client
*, struct Client
*, int, const char **);
46 static void me_modlist(struct MsgBuf
*, struct Client
*, struct Client
*, int, const char **);
47 static void me_modreload(struct MsgBuf
*, struct Client
*, struct Client
*, int, const char **);
48 static void me_modunload(struct MsgBuf
*, struct Client
*, struct Client
*, int, const char **);
49 static void me_modrestart(struct MsgBuf
*, struct Client
*, struct Client
*, int, const char **);
51 static void do_modload(struct Client
*, const char *);
52 static void do_modunload(struct Client
*, const char *);
53 static void do_modreload(struct Client
*, const char *);
54 static void do_modlist(struct Client
*, const char *);
55 static void do_modrestart(struct Client
*);
57 extern void modules_do_restart(void *); /* end of ircd/modules.c */
59 struct Message modload_msgtab
= {
60 "MODLOAD", 0, 0, 0, 0,
61 {mg_unreg
, mg_not_oper
, mg_ignore
, mg_ignore
, {me_modload
, 2}, {mo_modload
, 2}}
64 struct Message modunload_msgtab
= {
65 "MODUNLOAD", 0, 0, 0, 0,
66 {mg_unreg
, mg_not_oper
, mg_ignore
, mg_ignore
, {me_modunload
, 2}, {mo_modunload
, 2}}
69 struct Message modreload_msgtab
= {
70 "MODRELOAD", 0, 0, 0, 0,
71 {mg_unreg
, mg_not_oper
, mg_ignore
, mg_ignore
, {me_modreload
, 2}, {mo_modreload
, 2}}
74 struct Message modlist_msgtab
= {
75 "MODLIST", 0, 0, 0, 0,
76 {mg_unreg
, mg_not_oper
, mg_ignore
, mg_ignore
, {me_modlist
, 0}, {mo_modlist
, 0}}
79 struct Message modrestart_msgtab
= {
80 "MODRESTART", 0, 0, 0, 0,
81 {mg_unreg
, mg_not_oper
, mg_ignore
, mg_ignore
, {me_modrestart
, 0}, {mo_modrestart
, 0}}
84 mapi_clist_av1 modules_clist
[] = { &modload_msgtab
, &modunload_msgtab
, &modreload_msgtab
, &modlist_msgtab
, &modrestart_msgtab
, NULL
};
86 DECLARE_MODULE_AV2(modules
, NULL
, NULL
, modules_clist
, NULL
, NULL
, NULL
, NULL
, modules_desc
);
88 /* load a module .. */
90 mo_modload(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
92 if(!IsOperAdmin(source_p
))
94 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
95 me
.name
, source_p
->name
, "admin");
101 sendto_match_servs(source_p
, parv
[2], CAP_ENCAP
, NOCAPS
,
102 "ENCAP %s MODLOAD %s", parv
[2], parv
[1]);
103 if(match(parv
[2], me
.name
) == 0)
107 do_modload(source_p
, parv
[1]);
111 me_modload(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
113 if(!find_shared_conf(source_p
->username
, source_p
->host
, source_p
->servptr
->name
, SHARED_MODULE
))
115 sendto_one_notice(source_p
, ":*** You do not have an appropriate shared block "
116 "to load modules on this server.");
120 do_modload(source_p
, parv
[1]);
124 /* unload a module .. */
126 mo_modunload(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
128 if(!IsOperAdmin(source_p
))
130 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
131 me
.name
, source_p
->name
, "admin");
137 sendto_match_servs(source_p
, parv
[2], CAP_ENCAP
, NOCAPS
,
138 "ENCAP %s MODUNLOAD %s", parv
[2], parv
[1]);
139 if(match(parv
[2], me
.name
) == 0)
143 do_modunload(source_p
, parv
[1]);
147 me_modunload(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
149 if(!find_shared_conf(source_p
->username
, source_p
->host
, source_p
->servptr
->name
, SHARED_MODULE
))
151 sendto_one_notice(source_p
, ":*** You do not have an appropriate shared block "
152 "to load modules on this server.");
156 do_modunload(source_p
, parv
[1]);
159 /* unload and load in one! */
161 mo_modreload(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
163 if(!IsOperAdmin(source_p
))
165 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
166 me
.name
, source_p
->name
, "admin");
172 sendto_match_servs(source_p
, parv
[2], CAP_ENCAP
, NOCAPS
,
173 "ENCAP %s MODRELOAD %s", parv
[2], parv
[1]);
174 if(match(parv
[2], me
.name
) == 0)
178 do_modreload(source_p
, parv
[1]);
182 me_modreload(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
184 if(!find_shared_conf(source_p
->username
, source_p
->host
, source_p
->servptr
->name
, SHARED_MODULE
))
186 sendto_one_notice(source_p
, ":*** You do not have an appropriate shared block "
187 "to load modules on this server.");
191 do_modreload(source_p
, parv
[1]);
194 /* list modules .. */
196 mo_modlist(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
198 if(!IsOperAdmin(source_p
))
200 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
201 me
.name
, source_p
->name
, "admin");
207 sendto_match_servs(source_p
, parv
[2], CAP_ENCAP
, NOCAPS
,
208 "ENCAP %s MODLIST %s", parv
[2], parv
[1]);
209 if(match(parv
[2], me
.name
) == 0)
213 do_modlist(source_p
, parc
> 1 ? parv
[1] : 0);
217 me_modlist(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
219 if(!find_shared_conf(source_p
->username
, source_p
->host
, source_p
->servptr
->name
, SHARED_MODULE
))
221 sendto_one_notice(source_p
, ":*** You do not have an appropriate shared block "
222 "to load modules on this server.");
226 do_modlist(source_p
, parv
[1]);
229 /* unload and reload all modules */
231 mo_modrestart(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
233 if(!IsOperAdmin(source_p
))
235 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
236 me
.name
, source_p
->name
, "admin");
242 sendto_match_servs(source_p
, parv
[1], CAP_ENCAP
, NOCAPS
,
243 "ENCAP %s MODRESTART", parv
[1]);
244 if(match(parv
[1], me
.name
) == 0)
248 do_modrestart(source_p
);
252 me_modrestart(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
254 if(!find_shared_conf(source_p
->username
, source_p
->host
, source_p
->servptr
->name
, SHARED_MODULE
))
256 sendto_one_notice(source_p
, ":*** You do not have an appropriate shared block "
257 "to load modules on this server.");
261 do_modrestart(source_p
);
265 do_modload(struct Client
*source_p
, const char *module)
267 char *m_bn
= rb_basename(module);
270 if(findmodule_byname(m_bn
) != NULL
)
272 sendto_one_notice(source_p
, ":Module %s is already loaded", m_bn
);
277 mod_remember_clicaps();
279 origin
= strcmp(module, m_bn
) == 0 ? MAPI_ORIGIN_CORE
: MAPI_ORIGIN_EXTENSION
;
280 load_one_module(module, origin
, false);
282 mod_notify_clicaps();
288 do_modunload(struct Client
*source_p
, const char *module)
291 char *m_bn
= rb_basename(module);
293 if((mod
= findmodule_byname(m_bn
)) == NULL
)
295 sendto_one_notice(source_p
, ":Module %s is not loaded", m_bn
);
302 sendto_one_notice(source_p
, ":Module %s is a core module and may not be unloaded", m_bn
);
307 mod_remember_clicaps();
309 if(unload_one_module(m_bn
, true) == false)
310 sendto_one_notice(source_p
, ":Module %s is not loaded", m_bn
);
312 mod_notify_clicaps();
318 do_modreload(struct Client
*source_p
, const char *module)
322 char *m_bn
= rb_basename(module);
324 if((mod
= findmodule_byname(m_bn
)) == NULL
)
326 sendto_one_notice(source_p
, ":Module %s is not loaded", m_bn
);
331 check_core
= mod
->core
;
333 mod_remember_clicaps();
335 if(unload_one_module(m_bn
, true) == false)
337 sendto_one_notice(source_p
, ":Module %s is not loaded", m_bn
);
342 if((load_one_module(m_bn
, mod
->origin
, check_core
) == false) && check_core
)
344 sendto_realops_snomask(SNO_GENERAL
, L_NETWIDE
,
345 "Error reloading core module: %s: terminating ircd", m_bn
);
346 ilog(L_MAIN
, "Error loading core module %s: terminating ircd", m_bn
);
350 mod_notify_clicaps();
356 do_modrestart(struct Client
*source_p
)
358 sendto_one_notice(source_p
, ":Reloading all modules");
361 * If a remote MODRESTART is received, m_encap.so will be reloaded,
362 * but ms_encap is in the call stack (it indirectly calls this
363 * function). Also, this function is itself in a module.
365 * This will go horribly wrong if either module is reloaded to a
368 * So, defer the restart to the event loop and return now.
370 rb_event_addonce("modules_do_restart", modules_do_restart
, NULL
, 1);
374 do_modlist(struct Client
*source_p
, const char *pattern
)
378 RB_DLINK_FOREACH(ptr
, module_list
.head
)
380 struct module *mod
= ptr
->data
;
384 case MAPI_ORIGIN_EXTENSION
:
385 origin
= "extension";
387 case MAPI_ORIGIN_CORE
:
397 if(match(pattern
, mod
->name
))
399 sendto_one(source_p
, form_str(RPL_MODLIST
),
400 me
.name
, source_p
->name
,
402 (unsigned long)(uintptr_t)mod
->address
, origin
,
403 mod
->core
? " (core)" : "", mod
->version
, mod
->description
);
408 sendto_one(source_p
, form_str(RPL_MODLIST
),
409 me
.name
, source_p
->name
, mod
->name
,
410 (unsigned long)(uintptr_t)mod
->address
, origin
,
411 mod
->core
? " (core)" : "", mod
->version
, mod
->description
);
415 sendto_one(source_p
, form_str(RPL_ENDOFMODLIST
), me
.name
, source_p
->name
);