]> jfr.im git - solanum.git/blob - modules/core/m_modules.c
cppcheck: fix various warnings/errors
[solanum.git] / modules / core / m_modules.c
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
37 static const char modules_desc[] = "Provides module management commands";
38
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 **);
44
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 **);
50
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 *);
56
57 struct Message modload_msgtab = {
58 "MODLOAD", 0, 0, 0, 0,
59 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modload, 2}, {mo_modload, 2}}
60 };
61
62 struct Message modunload_msgtab = {
63 "MODUNLOAD", 0, 0, 0, 0,
64 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modunload, 2}, {mo_modunload, 2}}
65 };
66
67 struct Message modreload_msgtab = {
68 "MODRELOAD", 0, 0, 0, 0,
69 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modreload, 2}, {mo_modreload, 2}}
70 };
71
72 struct Message modlist_msgtab = {
73 "MODLIST", 0, 0, 0, 0,
74 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modlist, 0}, {mo_modlist, 0}}
75 };
76
77 struct Message modrestart_msgtab = {
78 "MODRESTART", 0, 0, 0, 0,
79 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modrestart, 0}, {mo_modrestart, 0}}
80 };
81
82 mapi_clist_av1 modules_clist[] = { &modload_msgtab, &modunload_msgtab, &modreload_msgtab, &modlist_msgtab, &modrestart_msgtab, NULL };
83
84 DECLARE_MODULE_AV2(modules, NULL, NULL, modules_clist, NULL, NULL, NULL, NULL, modules_desc);
85
86 /* load a module .. */
87 static void
88 mo_modload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
89 {
90 if(!IsOperAdmin(source_p))
91 {
92 sendto_one(source_p, form_str(ERR_NOPRIVS),
93 me.name, source_p->name, "admin");
94 return;
95 }
96
97 if(parc > 2)
98 {
99 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
100 "ENCAP %s MODLOAD %s", parv[2], parv[1]);
101 if(match(parv[2], me.name) == 0)
102 return;
103 }
104
105 do_modload(source_p, parv[1]);
106 }
107
108 static void
109 me_modload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
110 {
111 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
112 {
113 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
114 "to load modules on this server.");
115 return;
116 }
117
118 do_modload(source_p, parv[1]);
119 }
120
121
122 /* unload a module .. */
123 static void
124 mo_modunload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
125 {
126 if(!IsOperAdmin(source_p))
127 {
128 sendto_one(source_p, form_str(ERR_NOPRIVS),
129 me.name, source_p->name, "admin");
130 return;
131 }
132
133 if(parc > 2)
134 {
135 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
136 "ENCAP %s MODUNLOAD %s", parv[2], parv[1]);
137 if(match(parv[2], me.name) == 0)
138 return;
139 }
140
141 do_modunload(source_p, parv[1]);
142 }
143
144 static void
145 me_modunload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
146 {
147 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
148 {
149 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
150 "to load modules on this server.");
151 return;
152 }
153
154 do_modunload(source_p, parv[1]);
155 }
156
157 /* unload and load in one! */
158 static void
159 mo_modreload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
160 {
161 if(!IsOperAdmin(source_p))
162 {
163 sendto_one(source_p, form_str(ERR_NOPRIVS),
164 me.name, source_p->name, "admin");
165 return;
166 }
167
168 if(parc > 2)
169 {
170 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
171 "ENCAP %s MODRELOAD %s", parv[2], parv[1]);
172 if(match(parv[2], me.name) == 0)
173 return;
174 }
175
176 do_modreload(source_p, parv[1]);
177 }
178
179 static void
180 me_modreload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
181 {
182 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
183 {
184 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
185 "to load modules on this server.");
186 return;
187 }
188
189 do_modreload(source_p, parv[1]);
190 }
191
192 /* list modules .. */
193 static void
194 mo_modlist(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
195 {
196 if(!IsOperAdmin(source_p))
197 {
198 sendto_one(source_p, form_str(ERR_NOPRIVS),
199 me.name, source_p->name, "admin");
200 return;
201 }
202
203 if(parc > 2)
204 {
205 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
206 "ENCAP %s MODLIST %s", parv[2], parv[1]);
207 if(match(parv[2], me.name) == 0)
208 return;
209 }
210
211 do_modlist(source_p, parc > 1 ? parv[1] : 0);
212 }
213
214 static void
215 me_modlist(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
216 {
217 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
218 {
219 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
220 "to load modules on this server.");
221 return;
222 }
223
224 do_modlist(source_p, parv[1]);
225 }
226
227 /* unload and reload all modules */
228 static void
229 mo_modrestart(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
230 {
231 if(!IsOperAdmin(source_p))
232 {
233 sendto_one(source_p, form_str(ERR_NOPRIVS),
234 me.name, source_p->name, "admin");
235 return;
236 }
237
238 if(parc > 1)
239 {
240 sendto_match_servs(source_p, parv[1], CAP_ENCAP, NOCAPS,
241 "ENCAP %s MODRESTART", parv[1]);
242 if(match(parv[1], me.name) == 0)
243 return;
244 }
245
246 do_modrestart(source_p);
247 }
248
249 static void
250 me_modrestart(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
251 {
252 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
253 {
254 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
255 "to load modules on this server.");
256 return;
257 }
258
259 do_modrestart(source_p);
260 }
261
262 static void
263 do_modload(struct Client *source_p, const char *module)
264 {
265 char *m_bn = rb_basename(module);
266 int origin;
267
268 if(findmodule_byname(m_bn) != NULL)
269 {
270 sendto_one_notice(source_p, ":Module %s is already loaded", m_bn);
271 rb_free(m_bn);
272 return;
273 }
274
275 origin = strcmp(module, m_bn) == 0 ? MAPI_ORIGIN_CORE : MAPI_ORIGIN_EXTENSION;
276 load_one_module(module, origin, false);
277
278 rb_free(m_bn);
279 }
280
281 static void
282 do_modunload(struct Client *source_p, const char *module)
283 {
284 struct module *mod;
285 char *m_bn = rb_basename(module);
286
287 if((mod = findmodule_byname(m_bn)) == NULL)
288 {
289 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
290 rb_free(m_bn);
291 return;
292 }
293
294 if(mod->core)
295 {
296 sendto_one_notice(source_p, ":Module %s is a core module and may not be unloaded", m_bn);
297 rb_free(m_bn);
298 return;
299 }
300
301 if(unload_one_module(m_bn, true) == false)
302 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
303
304 rb_free(m_bn);
305 }
306
307 static void
308 do_modreload(struct Client *source_p, const char *module)
309 {
310 struct module *mod;
311 int check_core;
312 char *m_bn = rb_basename(module);
313
314 if((mod = findmodule_byname(m_bn)) == NULL)
315 {
316 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
317 rb_free(m_bn);
318 return;
319 }
320
321 check_core = mod->core;
322
323 if(unload_one_module(m_bn, true) == false)
324 {
325 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
326 rb_free(m_bn);
327 return;
328 }
329
330 if((load_one_module(m_bn, mod->origin, check_core) == false) && check_core)
331 {
332 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
333 "Error reloading core module: %s: terminating ircd", m_bn);
334 ilog(L_MAIN, "Error loading core module %s: terminating ircd", m_bn);
335 exit(0);
336 }
337
338 rb_free(m_bn);
339 }
340
341 static void
342 do_modrestart(struct Client *source_p)
343 {
344 unsigned int modnum = 0;
345 rb_dlink_node *ptr, *nptr;
346
347 sendto_one_notice(source_p, ":Reloading all modules");
348
349 RB_DLINK_FOREACH_SAFE(ptr, nptr, module_list.head)
350 {
351 struct module *mod = ptr->data;
352 if(!unload_one_module(mod->name, false))
353 {
354 ilog(L_MAIN, "Module Restart: %s was not unloaded %s",
355 mod->name,
356 mod->core? "(core module)" : "");
357
358 if(!mod->core)
359 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
360 "Module Restart: %s failed to unload",
361 mod->name);
362 continue;
363 }
364
365 modnum++;
366 }
367
368 load_all_modules(false);
369 load_core_modules(false);
370 rehash(false);
371
372 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
373 "Module Restart: %u modules unloaded, %lu modules loaded",
374 modnum, rb_dlink_list_length(&module_list));
375 ilog(L_MAIN, "Module Restart: %u modules unloaded, %lu modules loaded", modnum, rb_dlink_list_length(&module_list));
376 }
377
378 static void
379 do_modlist(struct Client *source_p, const char *pattern)
380 {
381 rb_dlink_node *ptr;
382
383 RB_DLINK_FOREACH(ptr, module_list.head)
384 {
385 struct module *mod = ptr->data;
386 const char *origin;
387 switch (mod->origin)
388 {
389 case MAPI_ORIGIN_EXTENSION:
390 origin = "extension";
391 break;
392 case MAPI_ORIGIN_CORE:
393 origin = "builtin";
394 break;
395 default:
396 origin = "unknown";
397 break;
398 }
399
400 if(pattern)
401 {
402 if(match(pattern, mod->name))
403 {
404 sendto_one(source_p, form_str(RPL_MODLIST),
405 me.name, source_p->name,
406 mod->name,
407 (unsigned long)(uintptr_t)mod->address, origin,
408 mod->core ? " (core)" : "", mod->version, mod->description);
409 }
410 }
411 else
412 {
413 sendto_one(source_p, form_str(RPL_MODLIST),
414 me.name, source_p->name, mod->name,
415 (unsigned long)(uintptr_t)mod->address, origin,
416 mod->core ? " (core)" : "", mod->version, mod->description);
417 }
418 }
419
420 sendto_one(source_p, form_str(RPL_ENDOFMODLIST), me.name, source_p->name);
421 }