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_reload(void *); /* end of ircd/modules.c */
58 extern void modules_do_restart(void *); /* end of ircd/modules.c */
60 struct 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}}
65 struct 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}}
70 struct 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}}
75 struct 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}}
80 struct 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}}
85 mapi_clist_av1 modules_clist
[] = { &modload_msgtab
, &modunload_msgtab
, &modreload_msgtab
, &modlist_msgtab
, &modrestart_msgtab
, NULL
};
87 DECLARE_MODULE_AV2(modules
, NULL
, NULL
, modules_clist
, NULL
, NULL
, NULL
, NULL
, modules_desc
);
89 /* load a module .. */
91 mo_modload(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
93 if(!IsOperAdmin(source_p
))
95 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
96 me
.name
, source_p
->name
, "admin");
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)
108 do_modload(source_p
, parv
[1]);
112 me_modload(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
114 do_modload(source_p
, parv
[1]);
118 /* unload a module .. */
120 mo_modunload(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
122 if(!IsOperAdmin(source_p
))
124 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
125 me
.name
, source_p
->name
, "admin");
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)
137 do_modunload(source_p
, parv
[1]);
141 me_modunload(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
143 do_modunload(source_p
, parv
[1]);
146 /* unload and load in one! */
148 mo_modreload(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
150 if(!IsOperAdmin(source_p
))
152 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
153 me
.name
, source_p
->name
, "admin");
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)
165 do_modreload(source_p
, parv
[1]);
169 me_modreload(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
171 do_modreload(source_p
, parv
[1]);
174 /* list modules .. */
176 mo_modlist(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
178 if(!IsOperAdmin(source_p
))
180 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
181 me
.name
, source_p
->name
, "admin");
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)
193 do_modlist(source_p
, parc
> 1 ? parv
[1] : 0);
197 me_modlist(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
199 do_modlist(source_p
, parv
[1]);
202 /* unload and reload all modules */
204 mo_modrestart(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
206 if(!IsOperAdmin(source_p
))
208 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
209 me
.name
, source_p
->name
, "admin");
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)
221 do_modrestart(source_p
);
225 me_modrestart(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
227 do_modrestart(source_p
);
231 do_modload(struct Client
*source_p
, const char *module)
233 char *m_bn
= rb_basename(module);
236 if(findmodule_byname(m_bn
) != NULL
)
238 sendto_one_notice(source_p
, ":Module %s is already loaded", m_bn
);
243 mod_remember_clicaps();
245 origin
= strcmp(module, m_bn
) == 0 ? MAPI_ORIGIN_CORE
: MAPI_ORIGIN_EXTENSION
;
246 load_one_module(module, origin
, false);
248 mod_notify_clicaps();
254 do_modunload(struct Client
*source_p
, const char *module)
257 char *m_bn
= rb_basename(module);
259 if((mod
= findmodule_byname(m_bn
)) == NULL
)
261 sendto_one_notice(source_p
, ":Module %s is not loaded", m_bn
);
268 sendto_one_notice(source_p
, ":Module %s is a core module and may not be unloaded", m_bn
);
273 mod_remember_clicaps();
275 if(unload_one_module(m_bn
, true) == false)
276 sendto_one_notice(source_p
, ":Module %s is not loaded", m_bn
);
278 mod_notify_clicaps();
284 do_modreload(struct Client
*source_p
, const char *module)
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);
293 do_modrestart(struct Client
*source_p
)
295 sendto_one_notice(source_p
, ":Reloading all modules");
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.
302 * This will go horribly wrong if either module is reloaded to a
305 * So, defer the restart to the event loop and return now.
307 rb_event_addonce("modules_do_restart", modules_do_restart
, NULL
, 1);
311 do_modlist(struct Client
*source_p
, const char *pattern
)
315 RB_DLINK_FOREACH(ptr
, module_list
.head
)
317 struct module *mod
= ptr
->data
;
321 case MAPI_ORIGIN_EXTENSION
:
322 origin
= "extension";
324 case MAPI_ORIGIN_CORE
:
334 if(match(pattern
, mod
->name
))
336 sendto_one(source_p
, form_str(RPL_MODLIST
),
337 me
.name
, source_p
->name
,
339 (unsigned long)(uintptr_t)mod
->address
, origin
,
340 mod
->core
? " (core)" : "", mod
->version
, mod
->description
);
345 sendto_one(source_p
, form_str(RPL_MODLIST
),
346 me
.name
, source_p
->name
, mod
->name
,
347 (unsigned long)(uintptr_t)mod
->address
, origin
,
348 mod
->core
? " (core)" : "", mod
->version
, mod
->description
);
352 sendto_one(source_p
, form_str(RPL_ENDOFMODLIST
), me
.name
, source_p
->name
);