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 if(!find_shared_conf(source_p
->username
, source_p
->host
, source_p
->servptr
->name
, SHARED_MODULE
))
116 sendto_one_notice(source_p
, ":*** You do not have an appropriate shared block "
117 "to load modules on this server.");
121 do_modload(source_p
, parv
[1]);
125 /* unload a module .. */
127 mo_modunload(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
129 if(!IsOperAdmin(source_p
))
131 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
132 me
.name
, source_p
->name
, "admin");
138 sendto_match_servs(source_p
, parv
[2], CAP_ENCAP
, NOCAPS
,
139 "ENCAP %s MODUNLOAD %s", parv
[2], parv
[1]);
140 if(match(parv
[2], me
.name
) == 0)
144 do_modunload(source_p
, parv
[1]);
148 me_modunload(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
150 if(!find_shared_conf(source_p
->username
, source_p
->host
, source_p
->servptr
->name
, SHARED_MODULE
))
152 sendto_one_notice(source_p
, ":*** You do not have an appropriate shared block "
153 "to load modules on this server.");
157 do_modunload(source_p
, parv
[1]);
160 /* unload and load in one! */
162 mo_modreload(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
164 if(!IsOperAdmin(source_p
))
166 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
167 me
.name
, source_p
->name
, "admin");
173 sendto_match_servs(source_p
, parv
[2], CAP_ENCAP
, NOCAPS
,
174 "ENCAP %s MODRELOAD %s", parv
[2], parv
[1]);
175 if(match(parv
[2], me
.name
) == 0)
179 do_modreload(source_p
, parv
[1]);
183 me_modreload(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
185 if(!find_shared_conf(source_p
->username
, source_p
->host
, source_p
->servptr
->name
, SHARED_MODULE
))
187 sendto_one_notice(source_p
, ":*** You do not have an appropriate shared block "
188 "to load modules on this server.");
192 do_modreload(source_p
, parv
[1]);
195 /* list modules .. */
197 mo_modlist(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
199 if(!IsOperAdmin(source_p
))
201 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
202 me
.name
, source_p
->name
, "admin");
208 sendto_match_servs(source_p
, parv
[2], CAP_ENCAP
, NOCAPS
,
209 "ENCAP %s MODLIST %s", parv
[2], parv
[1]);
210 if(match(parv
[2], me
.name
) == 0)
214 do_modlist(source_p
, parc
> 1 ? parv
[1] : 0);
218 me_modlist(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
220 if(!find_shared_conf(source_p
->username
, source_p
->host
, source_p
->servptr
->name
, SHARED_MODULE
))
222 sendto_one_notice(source_p
, ":*** You do not have an appropriate shared block "
223 "to load modules on this server.");
227 do_modlist(source_p
, parv
[1]);
230 /* unload and reload all modules */
232 mo_modrestart(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
234 if(!IsOperAdmin(source_p
))
236 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
237 me
.name
, source_p
->name
, "admin");
243 sendto_match_servs(source_p
, parv
[1], CAP_ENCAP
, NOCAPS
,
244 "ENCAP %s MODRESTART", parv
[1]);
245 if(match(parv
[1], me
.name
) == 0)
249 do_modrestart(source_p
);
253 me_modrestart(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
255 if(!find_shared_conf(source_p
->username
, source_p
->host
, source_p
->servptr
->name
, SHARED_MODULE
))
257 sendto_one_notice(source_p
, ":*** You do not have an appropriate shared block "
258 "to load modules on this server.");
262 do_modrestart(source_p
);
266 do_modload(struct Client
*source_p
, const char *module)
268 char *m_bn
= rb_basename(module);
271 if(findmodule_byname(m_bn
) != NULL
)
273 sendto_one_notice(source_p
, ":Module %s is already loaded", m_bn
);
278 mod_remember_clicaps();
280 origin
= strcmp(module, m_bn
) == 0 ? MAPI_ORIGIN_CORE
: MAPI_ORIGIN_EXTENSION
;
281 load_one_module(module, origin
, false);
283 mod_notify_clicaps();
289 do_modunload(struct Client
*source_p
, const char *module)
292 char *m_bn
= rb_basename(module);
294 if((mod
= findmodule_byname(m_bn
)) == NULL
)
296 sendto_one_notice(source_p
, ":Module %s is not loaded", m_bn
);
303 sendto_one_notice(source_p
, ":Module %s is a core module and may not be unloaded", m_bn
);
308 mod_remember_clicaps();
310 if(unload_one_module(m_bn
, true) == false)
311 sendto_one_notice(source_p
, ":Module %s is not loaded", m_bn
);
313 mod_notify_clicaps();
319 do_modreload(struct Client
*source_p
, const char *module)
321 struct modreload
*info
= rb_malloc(sizeof *info
);
322 strcpy(info
->module, module);
323 strcpy(info
->id
, source_p
->id
);
324 rb_event_addonce("modules_do_reload", modules_do_reload
, info
, 1);
328 do_modrestart(struct Client
*source_p
)
330 sendto_one_notice(source_p
, ":Reloading all modules");
333 * If a remote MODRESTART is received, m_encap.so will be reloaded,
334 * but ms_encap is in the call stack (it indirectly calls this
335 * function). Also, this function is itself in a module.
337 * This will go horribly wrong if either module is reloaded to a
340 * So, defer the restart to the event loop and return now.
342 rb_event_addonce("modules_do_restart", modules_do_restart
, NULL
, 1);
346 do_modlist(struct Client
*source_p
, const char *pattern
)
350 RB_DLINK_FOREACH(ptr
, module_list
.head
)
352 struct module *mod
= ptr
->data
;
356 case MAPI_ORIGIN_EXTENSION
:
357 origin
= "extension";
359 case MAPI_ORIGIN_CORE
:
369 if(match(pattern
, mod
->name
))
371 sendto_one(source_p
, form_str(RPL_MODLIST
),
372 me
.name
, source_p
->name
,
374 (unsigned long)(uintptr_t)mod
->address
, origin
,
375 mod
->core
? " (core)" : "", mod
->version
, mod
->description
);
380 sendto_one(source_p
, form_str(RPL_MODLIST
),
381 me
.name
, source_p
->name
, mod
->name
,
382 (unsigned long)(uintptr_t)mod
->address
, origin
,
383 mod
->core
? " (core)" : "", mod
->version
, mod
->description
);
387 sendto_one(source_p
, form_str(RPL_ENDOFMODLIST
), me
.name
, source_p
->name
);