]> jfr.im git - solanum.git/blame - modules/core/m_modules.c
Kill Travis
[solanum.git] / modules / core / m_modules.c
CommitLineData
78946542
EM
1/* modules/m_modules.c - module for module loading
2 * Copyright (c) 2016 Elizabeth Myers <elizabeth@interlinked.me>
3 *
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.
7 *
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.
19 */
20
21#include "stdinc.h"
22#include "client.h"
23#include "parse.h"
24#include "msg.h"
25#include "modules.h"
26#include "s_newconf.h"
27#include "s_conf.h"
28#include "s_serv.h"
29#include "hash.h"
30#include "ircd.h"
31#include "match.h"
32#include "numeric.h"
33#include "send.h"
34#include "packet.h"
35#include "logger.h"
36
37static const char modules_desc[] = "Provides module management commands";
38
39static void mo_modload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
40static void mo_modlist(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
41static void mo_modreload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
42static void mo_modunload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
43static void mo_modrestart(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
44
45static void me_modload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
46static void me_modlist(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
47static void me_modreload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
48static void me_modunload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
49static void me_modrestart(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
50
51static void do_modload(struct Client *, const char *);
52static void do_modunload(struct Client *, const char *);
53static void do_modreload(struct Client *, const char *);
54static void do_modlist(struct Client *, const char *);
55static void do_modrestart(struct Client *);
56
7b641013 57extern void modules_do_reload(void *); /* end of ircd/modules.c */
41390bfe
AJ
58extern void modules_do_restart(void *); /* end of ircd/modules.c */
59
78946542
EM
60struct Message modload_msgtab = {
61 "MODLOAD", 0, 0, 0, 0,
62 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modload, 2}, {mo_modload, 2}}
63};
64
65struct Message modunload_msgtab = {
66 "MODUNLOAD", 0, 0, 0, 0,
67 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modunload, 2}, {mo_modunload, 2}}
68};
69
70struct Message modreload_msgtab = {
71 "MODRELOAD", 0, 0, 0, 0,
72 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modreload, 2}, {mo_modreload, 2}}
73};
74
75struct Message modlist_msgtab = {
76 "MODLIST", 0, 0, 0, 0,
77 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modlist, 0}, {mo_modlist, 0}}
78};
79
80struct Message modrestart_msgtab = {
81 "MODRESTART", 0, 0, 0, 0,
82 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modrestart, 0}, {mo_modrestart, 0}}
83};
84
85mapi_clist_av1 modules_clist[] = { &modload_msgtab, &modunload_msgtab, &modreload_msgtab, &modlist_msgtab, &modrestart_msgtab, NULL };
86
87DECLARE_MODULE_AV2(modules, NULL, NULL, modules_clist, NULL, NULL, NULL, NULL, modules_desc);
88
89/* load a module .. */
90static void
91mo_modload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
92{
93 if(!IsOperAdmin(source_p))
94 {
95 sendto_one(source_p, form_str(ERR_NOPRIVS),
96 me.name, source_p->name, "admin");
97 return;
98 }
99
100 if(parc > 2)
101 {
102 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
103 "ENCAP %s MODLOAD %s", parv[2], parv[1]);
104 if(match(parv[2], me.name) == 0)
105 return;
106 }
107
108 do_modload(source_p, parv[1]);
109}
110
111static void
112me_modload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
113{
78946542
EM
114 do_modload(source_p, parv[1]);
115}
116
117
118/* unload a module .. */
119static void
120mo_modunload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
121{
122 if(!IsOperAdmin(source_p))
123 {
124 sendto_one(source_p, form_str(ERR_NOPRIVS),
125 me.name, source_p->name, "admin");
126 return;
127 }
128
129 if(parc > 2)
130 {
131 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
132 "ENCAP %s MODUNLOAD %s", parv[2], parv[1]);
133 if(match(parv[2], me.name) == 0)
134 return;
135 }
136
137 do_modunload(source_p, parv[1]);
138}
139
140static void
141me_modunload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
142{
78946542
EM
143 do_modunload(source_p, parv[1]);
144}
145
146/* unload and load in one! */
147static void
148mo_modreload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
149{
150 if(!IsOperAdmin(source_p))
151 {
152 sendto_one(source_p, form_str(ERR_NOPRIVS),
153 me.name, source_p->name, "admin");
154 return;
155 }
156
157 if(parc > 2)
158 {
159 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
160 "ENCAP %s MODRELOAD %s", parv[2], parv[1]);
161 if(match(parv[2], me.name) == 0)
162 return;
163 }
164
165 do_modreload(source_p, parv[1]);
166}
167
168static void
169me_modreload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
170{
78946542
EM
171 do_modreload(source_p, parv[1]);
172}
173
174/* list modules .. */
175static void
176mo_modlist(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
177{
178 if(!IsOperAdmin(source_p))
179 {
180 sendto_one(source_p, form_str(ERR_NOPRIVS),
181 me.name, source_p->name, "admin");
182 return;
183 }
184
185 if(parc > 2)
186 {
187 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
188 "ENCAP %s MODLIST %s", parv[2], parv[1]);
189 if(match(parv[2], me.name) == 0)
190 return;
191 }
192
193 do_modlist(source_p, parc > 1 ? parv[1] : 0);
194}
195
196static void
197me_modlist(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
198{
78946542
EM
199 do_modlist(source_p, parv[1]);
200}
201
202/* unload and reload all modules */
203static void
204mo_modrestart(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
205{
206 if(!IsOperAdmin(source_p))
207 {
208 sendto_one(source_p, form_str(ERR_NOPRIVS),
209 me.name, source_p->name, "admin");
210 return;
211 }
212
213 if(parc > 1)
214 {
215 sendto_match_servs(source_p, parv[1], CAP_ENCAP, NOCAPS,
216 "ENCAP %s MODRESTART", parv[1]);
217 if(match(parv[1], me.name) == 0)
218 return;
219 }
220
221 do_modrestart(source_p);
222}
223
224static void
225me_modrestart(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
226{
78946542
EM
227 do_modrestart(source_p);
228}
229
230static void
231do_modload(struct Client *source_p, const char *module)
232{
233 char *m_bn = rb_basename(module);
234 int origin;
235
2185c50a 236 if(findmodule_byname(m_bn) != NULL)
78946542
EM
237 {
238 sendto_one_notice(source_p, ":Module %s is already loaded", m_bn);
239 rb_free(m_bn);
240 return;
241 }
242
28cc8bb9
EK
243 mod_remember_clicaps();
244
78946542
EM
245 origin = strcmp(module, m_bn) == 0 ? MAPI_ORIGIN_CORE : MAPI_ORIGIN_EXTENSION;
246 load_one_module(module, origin, false);
247
28cc8bb9
EK
248 mod_notify_clicaps();
249
78946542
EM
250 rb_free(m_bn);
251}
252
253static void
254do_modunload(struct Client *source_p, const char *module)
255{
2185c50a 256 struct module *mod;
78946542
EM
257 char *m_bn = rb_basename(module);
258
2185c50a 259 if((mod = findmodule_byname(m_bn)) == NULL)
78946542
EM
260 {
261 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
262 rb_free(m_bn);
263 return;
264 }
265
2185c50a 266 if(mod->core)
78946542
EM
267 {
268 sendto_one_notice(source_p, ":Module %s is a core module and may not be unloaded", m_bn);
269 rb_free(m_bn);
270 return;
271 }
272
28cc8bb9
EK
273 mod_remember_clicaps();
274
78946542
EM
275 if(unload_one_module(m_bn, true) == false)
276 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
277
28cc8bb9
EK
278 mod_notify_clicaps();
279
78946542
EM
280 rb_free(m_bn);
281}
282
283static void
284do_modreload(struct Client *source_p, const char *module)
285{
7b641013
EK
286 struct modreload *info = rb_malloc(sizeof *info);
287 strcpy(info->module, module);
288 strcpy(info->id, source_p->id);
289 rb_event_addonce("modules_do_reload", modules_do_reload, info, 1);
78946542
EM
290}
291
292static void
293do_modrestart(struct Client *source_p)
294{
78946542
EM
295 sendto_one_notice(source_p, ":Reloading all modules");
296
41390bfe
AJ
297 /*
298 * If a remote MODRESTART is received, m_encap.so will be reloaded,
299 * but ms_encap is in the call stack (it indirectly calls this
300 * function). Also, this function is itself in a module.
301 *
302 * This will go horribly wrong if either module is reloaded to a
303 * different address.
304 *
305 * So, defer the restart to the event loop and return now.
306 */
307 rb_event_addonce("modules_do_restart", modules_do_restart, NULL, 1);
78946542
EM
308}
309
310static void
311do_modlist(struct Client *source_p, const char *pattern)
312{
2185c50a 313 rb_dlink_node *ptr;
78946542 314
2185c50a 315 RB_DLINK_FOREACH(ptr, module_list.head)
78946542 316 {
2185c50a 317 struct module *mod = ptr->data;
78946542 318 const char *origin;
2185c50a 319 switch (mod->origin)
78946542
EM
320 {
321 case MAPI_ORIGIN_EXTENSION:
322 origin = "extension";
323 break;
324 case MAPI_ORIGIN_CORE:
325 origin = "builtin";
326 break;
327 default:
328 origin = "unknown";
329 break;
330 }
331
332 if(pattern)
333 {
2185c50a 334 if(match(pattern, mod->name))
78946542
EM
335 {
336 sendto_one(source_p, form_str(RPL_MODLIST),
337 me.name, source_p->name,
2185c50a
AC
338 mod->name,
339 (unsigned long)(uintptr_t)mod->address, origin,
340 mod->core ? " (core)" : "", mod->version, mod->description);
78946542
EM
341 }
342 }
343 else
344 {
345 sendto_one(source_p, form_str(RPL_MODLIST),
2185c50a
AC
346 me.name, source_p->name, mod->name,
347 (unsigned long)(uintptr_t)mod->address, origin,
348 mod->core ? " (core)" : "", mod->version, mod->description);
78946542
EM
349 }
350 }
351
352 sendto_one(source_p, form_str(RPL_ENDOFMODLIST), me.name, source_p->name);
353}