ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/modules.c
Revision: 1404
Committed: Thu May 10 20:41:45 2012 UTC (14 years, 4 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-8/src/modules.c
File size: 14626 byte(s)
Error occurred while calculating annotation data.
Log Message:
- minor cleanups to the module code

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 * modules.c: A module loader.
4 *
5 * Copyright (C) 2002 by the past and present ircd coders, and others.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 * USA
21 *
22 * $Id$
23 */
24
25 #include "ltdl.h"
26
27 #include "stdinc.h"
28 #include "list.h"
29 #include "modules.h"
30 #include "log.h"
31 #include "ircd.h"
32 #include "client.h"
33 #include "send.h"
34 #include "conf.h"
35 #include "numeric.h"
36 #include "parse.h"
37 #include "ircd_defs.h"
38 #include "irc_string.h"
39 #include "memory.h"
40
41
42 static dlink_list modules_list = { NULL, NULL, 0 };
43
44 static const char *unknown_ver = "<unknown>";
45
46 static const char *core_module_table[] =
47 {
48 "m_die.la",
49 "m_error.la",
50 "m_join.la",
51 "m_kick.la",
52 "m_kill.la",
53 "m_message.la",
54 "m_mode.la",
55 "m_nick.la",
56 "m_part.la",
57 "m_quit.la",
58 "m_server.la",
59 "m_sjoin.la",
60 "m_squit.la",
61 NULL
62 };
63
64 static dlink_list mod_paths = { NULL, NULL, 0 };
65 static dlink_list conf_modules = { NULL, NULL, 0 };
66
67 static void mo_modload(struct Client *, struct Client *, int, char *[]);
68 static void mo_modlist(struct Client *, struct Client *, int, char *[]);
69 static void mo_modreload(struct Client *, struct Client *, int, char *[]);
70 static void mo_modunload(struct Client *, struct Client *, int, char *[]);
71 static void mo_modrestart(struct Client *, struct Client *, int, char *[]);
72
73 struct Message modload_msgtab = {
74 "MODLOAD", 0, 0, 2, 0, MFLG_SLOW, 0,
75 {m_unregistered, m_not_oper, m_ignore, m_ignore, mo_modload, m_ignore}
76 };
77
78 struct Message modunload_msgtab = {
79 "MODUNLOAD", 0, 0, 2, 0, MFLG_SLOW, 0,
80 {m_unregistered, m_not_oper, m_ignore, m_ignore, mo_modunload, m_ignore}
81 };
82
83 struct Message modreload_msgtab = {
84 "MODRELOAD", 0, 0, 2, 0, MFLG_SLOW, 0,
85 {m_unregistered, m_not_oper, m_ignore, m_ignore, mo_modreload, m_ignore}
86 };
87
88 struct Message modlist_msgtab = {
89 "MODLIST", 0, 0, 0, 0, MFLG_SLOW, 0,
90 {m_unregistered, m_not_oper, m_ignore, m_ignore, mo_modlist, m_ignore}
91 };
92
93 struct Message modrestart_msgtab = {
94 "MODRESTART", 0, 0, 0, 0, MFLG_SLOW, 0,
95 {m_unregistered, m_not_oper, m_ignore, m_ignore, mo_modrestart, m_ignore}
96 };
97
98
99 int
100 modules_valid_suffix(const char *name)
101 {
102 return ((name = strrchr(name, '.'))) && !strcmp(name, ".la");
103 }
104
105 /* unload_one_module()
106 *
107 * inputs - name of module to unload
108 * - 1 to say modules unloaded, 0 to not
109 * output - 0 if successful, -1 if error
110 * side effects - module is unloaded
111 */
112 int
113 unload_one_module(const char *name, int warn)
114 {
115 struct module *modp = NULL;
116
117 if ((modp = findmodule_byname(name)) == NULL)
118 return -1;
119
120 if (modp->modexit)
121 modp->modexit();
122
123 assert(dlink_list_length(&modules_list) > 0);
124 dlinkDelete(&modp->node, &modules_list);
125 MyFree(modp->name);
126
127 lt_dlclose(modp->handle);
128
129 if (warn == 1)
130 {
131 ilog(LOG_TYPE_IRCD, "Module %s unloaded", name);
132 sendto_realops_flags(UMODE_ALL, L_ALL, "Module %s unloaded", name);
133 }
134
135 return 0;
136 }
137
138 /* load_a_module()
139 *
140 * inputs - path name of module, int to notice, int of core
141 * output - -1 if error 0 if success
142 * side effects - loads a module if successful
143 */
144 int
145 load_a_module(const char *path, int warn)
146 {
147 lt_dlhandle tmpptr = NULL;
148 const char *mod_basename = NULL;
149 struct module *modp = NULL;
150
151 if (findmodule_byname((mod_basename = libio_basename(path))))
152 return 1;
153
154 if (!(tmpptr = lt_dlopen(path))) {
155 const char *err = ((err = lt_dlerror())) ? err : "<unknown>";
156
157 sendto_realops_flags(UMODE_ALL, L_ALL, "Error loading module %s: %s",
158 mod_basename, err);
159 ilog(LOG_TYPE_IRCD, "Error loading module %s: %s", mod_basename, err);
160 return -1;
161 }
162
163 if ((modp = lt_dlsym(tmpptr, "module_entry")) == NULL)
164 {
165 sendto_realops_flags(UMODE_ALL, L_ALL, "Module %s has no module_entry export",
166 mod_basename);
167 ilog(LOG_TYPE_IRCD, "Module %s has no module_entry export", mod_basename);
168 lt_dlclose(tmpptr);
169 return -1;
170 }
171
172 modp->handle = tmpptr;
173
174 if (EmptyString(modp->version))
175 modp->version = unknown_ver;
176
177 DupString(modp->name, mod_basename);
178 dlinkAdd(modp, &modp->node, &modules_list);
179
180 if (modp->modinit)
181 modp->modinit();
182
183 if (warn == 1)
184 {
185 sendto_realops_flags(UMODE_ALL, L_ALL,
186 "Module %s [version: %s handle: %p] loaded.",
187 modp->name, modp->version, tmpptr);
188 ilog(LOG_TYPE_IRCD, "Module %s [version: %s handle: %p] loaded.",
189 modp->name, modp->version, tmpptr);
190 }
191
192 return 0;
193 }
194
195 /*
196 * modules_init
197 *
198 * input - NONE
199 * output - NONE
200 * side effects - The basic module manipulation modules are loaded
201 */
202 void
203 modules_init(void)
204 {
205 if (lt_dlinit())
206 {
207 ilog(LOG_TYPE_IRCD, "Couldn't initialize the libltdl run time dynamic"
208 " link library. Exiting.");
209 exit(0);
210 }
211
212 mod_add_cmd(&modload_msgtab);
213 mod_add_cmd(&modunload_msgtab);
214 mod_add_cmd(&modreload_msgtab);
215 mod_add_cmd(&modlist_msgtab);
216 mod_add_cmd(&modrestart_msgtab);
217 }
218
219 /* mod_find_path()
220 *
221 * input - path
222 * output - none
223 * side effects - returns a module path from path
224 */
225 static struct module_path *
226 mod_find_path(const char *path)
227 {
228 dlink_node *ptr;
229
230 DLINK_FOREACH(ptr, mod_paths.head)
231 {
232 struct module_path *mpath = ptr->data;
233
234 if (!strcmp(path, mpath->path))
235 return mpath;
236 }
237
238 return NULL;
239 }
240
241 /* mod_add_path()
242 *
243 * input - path
244 * output - NONE
245 * side effects - adds path to list
246 */
247 void
248 mod_add_path(const char *path)
249 {
250 struct module_path *pathst;
251
252 if (mod_find_path(path))
253 return;
254
255 pathst = MyMalloc(sizeof(struct module_path));
256
257 strlcpy(pathst->path, path, sizeof(pathst->path));
258 dlinkAdd(pathst, &pathst->node, &mod_paths);
259 }
260
261 /* add_conf_module
262 *
263 * input - module name
264 * output - NONE
265 * side effects - adds module to conf_mod
266 */
267 void
268 add_conf_module(const char *name)
269 {
270 struct module_path *pathst;
271
272 pathst = MyMalloc(sizeof(struct module_path));
273
274 strlcpy(pathst->path, name, sizeof(pathst->path));
275 dlinkAdd(pathst, &pathst->node, &conf_modules);
276 }
277
278 /* mod_clear_paths()
279 *
280 * input - NONE
281 * output - NONE
282 * side effects - clear the lists of paths and conf modules
283 */
284 void
285 mod_clear_paths(void)
286 {
287 dlink_node *ptr = NULL, *next_ptr = NULL;
288
289 DLINK_FOREACH_SAFE(ptr, next_ptr, mod_paths.head)
290 {
291 dlinkDelete(ptr, &mod_paths);
292 MyFree(ptr->data);
293 }
294
295 DLINK_FOREACH_SAFE(ptr, next_ptr, conf_modules.head)
296 {
297 dlinkDelete(ptr, &conf_modules);
298 MyFree(ptr->data);
299 }
300 }
301
302 /* findmodule_byname
303 *
304 * input - name of module
305 * output - NULL if not found or pointer to module
306 * side effects - NONE
307 */
308 struct module *
309 findmodule_byname(const char *name)
310 {
311 dlink_node *ptr = NULL;
312
313 DLINK_FOREACH(ptr, modules_list.head)
314 {
315 struct module *modp = ptr->data;
316
317 if (strcmp(modp->name, name) == 0)
318 return modp;
319 }
320
321 return NULL;
322 }
323
324 /* load_all_modules()
325 *
326 * input - int flag warn
327 * output - NONE
328 * side effects - load all modules found in autoload directory
329 */
330 void
331 load_all_modules(int warn)
332 {
333 DIR *system_module_dir = NULL;
334 struct dirent *ldirent = NULL;
335 char module_fq_name[PATH_MAX + 1];
336
337 if ((system_module_dir = opendir(AUTOMODPATH)) == NULL)
338 {
339 ilog(LOG_TYPE_IRCD, "Could not load modules from %s: %s",
340 AUTOMODPATH, strerror(errno));
341 return;
342 }
343
344 while ((ldirent = readdir(system_module_dir)) != NULL)
345 {
346 if (modules_valid_suffix(ldirent->d_name))
347 {
348 snprintf(module_fq_name, sizeof(module_fq_name), "%s/%s",
349 AUTOMODPATH, ldirent->d_name);
350 load_a_module(module_fq_name, warn);
351 }
352 }
353
354 closedir(system_module_dir);
355 }
356
357 /* load_conf_modules()
358 *
359 * input - NONE
360 * output - NONE
361 * side effects - load modules given in ircd.conf
362 */
363 void
364 load_conf_modules(void)
365 {
366 dlink_node *ptr = NULL;
367
368 DLINK_FOREACH(ptr, conf_modules.head)
369 {
370 struct module_path *mpath = ptr->data;
371
372 if (findmodule_byname(mpath->path) == NULL)
373 load_one_module(mpath->path);
374 }
375 }
376
377 /* load_core_modules()
378 *
379 * input - int flag warn
380 * output - NONE
381 * side effects - core modules are loaded, if any fail, kill ircd
382 */
383 void
384 load_core_modules(int warn)
385 {
386 char module_name[PATH_MAX + 1];
387 int i = 0;
388
389 for (; core_module_table[i]; ++i)
390 {
391 snprintf(module_name, sizeof(module_name), "%s%s",
392 MODPATH, core_module_table[i]);
393
394 if (load_a_module(module_name, warn) == -1)
395 {
396 ilog(LOG_TYPE_IRCD, "Error loading core module %s: terminating ircd",
397 core_module_table[i]);
398 exit(EXIT_FAILURE);
399 }
400 }
401 }
402
403 /* load_one_module()
404 *
405 * input - pointer to path
406 * - flagged as core module or not
407 * output - -1 if error
408 * side effects - module is loaded if found.
409 */
410 int
411 load_one_module(const char *path)
412 {
413 dlink_node *ptr = NULL;
414 char modpath[PATH_MAX + 1];
415 struct stat statbuf;
416
417 DLINK_FOREACH(ptr, mod_paths.head)
418 {
419 const struct module_path *mpath = ptr->data;
420
421 snprintf(modpath, sizeof(modpath), "%s/%s", mpath->path, path);
422
423 if (!modules_valid_suffix(path))
424 continue;
425
426 if (strstr(modpath, "../") == NULL &&
427 strstr(modpath, "/..") == NULL)
428 if (!stat(modpath, &statbuf))
429 if (S_ISREG(statbuf.st_mode)) /* Regular files only please */
430 return load_a_module(modpath, 1);
431 }
432
433 sendto_realops_flags(UMODE_ALL, L_ALL,
434 "Cannot locate module %s", path);
435 ilog(LOG_TYPE_IRCD, "Cannot locate module %s", path);
436 return -1;
437 }
438
439 /* load a module .. */
440 static void
441 mo_modload(struct Client *client_p, struct Client *source_p,
442 int parc, char *parv[])
443 {
444 const char *m_bn = NULL;
445
446 if (!HasOFlag(source_p, OPER_FLAG_MODULE))
447 {
448 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
449 me.name, source_p->name);
450 return;
451 }
452
453 m_bn = libio_basename(parv[1]);
454
455 if (findmodule_byname(m_bn) != NULL)
456 {
457 sendto_one(source_p, ":%s NOTICE %s :Module %s is already loaded",
458 me.name, source_p->name, m_bn);
459 return;
460 }
461
462 load_one_module(parv[1]);
463 }
464
465 /* unload a module .. */
466 static void
467 mo_modunload(struct Client *client_p, struct Client *source_p,
468 int parc, char *parv[])
469 {
470 const char *m_bn = NULL;
471 struct module *modp = NULL;
472
473 if (!HasOFlag(source_p, OPER_FLAG_MODULE))
474 {
475 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
476 me.name, source_p->name);
477 return;
478 }
479
480 m_bn = libio_basename(parv[1]);
481
482 if ((modp = findmodule_byname(m_bn)) == NULL)
483 {
484 sendto_one(source_p, ":%s NOTICE %s :Module %s is not loaded",
485 me.name, source_p->name, m_bn);
486 return;
487 }
488
489 if (modp->flags & MODULE_FLAG_CORE)
490 {
491 sendto_one(source_p,
492 ":%s NOTICE %s :Module %s is a core module and may not be unloaded",
493 me.name, source_p->name, m_bn);
494 return;
495 }
496
497 if (unload_one_module(m_bn, 1) == -1)
498 {
499 sendto_one(source_p, ":%s NOTICE %s :Module %s is not loaded",
500 me.name, source_p->name, m_bn);
501 }
502 }
503
504 /* unload and load in one! */
505 static void
506 mo_modreload(struct Client *client_p, struct Client *source_p,
507 int parc, char *parv[])
508 {
509 const char *m_bn = NULL;
510 struct module *modp = NULL;
511 int check_core;
512
513 if (!HasOFlag(source_p, OPER_FLAG_MODULE))
514 {
515 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
516 me.name, source_p->name);
517 return;
518 }
519
520 m_bn = libio_basename(parv[1]);
521
522 if ((modp = findmodule_byname(m_bn)) == NULL)
523 {
524 sendto_one(source_p, ":%s NOTICE %s :Module %s is not loaded",
525 me.name, source_p->name, m_bn);
526 return;
527 }
528
529 check_core = (modp->flags & MODULE_FLAG_CORE) != 0;
530
531 if (unload_one_module(m_bn, 1) == -1)
532 {
533 sendto_one(source_p, ":%s NOTICE %s :Module %s is not loaded",
534 me.name, source_p->name, m_bn);
535 return;
536 }
537
538 if ((load_one_module(parv[1]) == -1) && check_core)
539 {
540 sendto_realops_flags(UMODE_ALL, L_ALL, "Error reloading core "
541 "module: %s: terminating ircd", parv[1]);
542 ilog(LOG_TYPE_IRCD, "Error loading core module %s: terminating ircd", parv[1]);
543 exit(0);
544 }
545 }
546
547 /* list modules .. */
548 static void
549 mo_modlist(struct Client *client_p, struct Client *source_p,
550 int parc, char *parv[])
551 {
552 const dlink_node *ptr = NULL;
553
554 if (!HasOFlag(source_p, OPER_FLAG_MODULE))
555 {
556 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
557 me.name, source_p->name);
558 return;
559 }
560
561 DLINK_FOREACH(ptr, modules_list.head)
562 {
563 const struct module *modp = ptr->data;
564
565 if (parc > 1 && !match(parv[1], modp->name))
566 continue;
567
568 sendto_one(source_p, form_str(RPL_MODLIST), me.name, source_p->name,
569 modp->name, modp->handle,
570 modp->version, (modp->flags & MODULE_FLAG_CORE) ?"(core)":"");
571 }
572
573 sendto_one(source_p, form_str(RPL_ENDOFMODLIST),
574 me.name, source_p->name);
575 }
576
577 /* unload and reload all modules */
578 static void
579 mo_modrestart(struct Client *client_p, struct Client *source_p,
580 int parc, char *parv[])
581 {
582 unsigned int modnum = 0;
583 dlink_node *ptr = NULL, *ptr_next = NULL;
584
585 if (!HasOFlag(source_p, OPER_FLAG_MODULE))
586 {
587 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
588 me.name, source_p->name);
589 return;
590 }
591
592 sendto_one(source_p, ":%s NOTICE %s :Reloading all modules",
593 me.name, source_p->name);
594
595 modnum = dlink_list_length(&modules_list);
596
597 DLINK_FOREACH_SAFE(ptr, ptr_next, modules_list.head)
598 {
599 struct module *modp = ptr->data;
600 unload_one_module(modp->name, 0);
601 }
602
603 load_all_modules(0);
604 load_conf_modules();
605 load_core_modules(0);
606
607 sendto_realops_flags(UMODE_ALL, L_ALL,
608 "Module Restart: %u modules unloaded, %u modules loaded",
609 modnum, dlink_list_length(&modules_list));
610 ilog(LOG_TYPE_IRCD, "Module Restart: %u modules unloaded, %u modules loaded",
611 modnum, dlink_list_length(&modules_list));
612 }

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision