fix possible crash on user deletion
[srvx.git] / src / modules.c
1 /* modules.c - Compiled-in module support
2  * Copyright 2002-2003 srvx Development Team
3  *
4  * This file is part of srvx.
5  *
6  * srvx is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with srvx; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
19  */
20
21 #include "log.h"
22 #include "modules.h"
23
24 enum init_state {
25     UNINIT,
26     WORKING,
27     BROKEN,
28     INITED,
29     DONE
30 };
31
32 struct cmodule {
33     const char *name;
34     int (*init_func)(void);
35     int (*finalize_func)(void);
36     const char **deps;
37     enum init_state state;
38 };
39
40 #define WITH_MODULE(x) extern int x##_init(void); extern int x##_finalize(void); extern const char *x##_module_deps[];
41 #include "modules-list.h"
42 #undef WITH_MODULE
43
44 static struct cmodule cmodules[] = {
45 #define WITH_MODULE(x) { #x, x##_init, x##_finalize, x##_module_deps, UNINIT },
46 #include "modules-list.h"
47 #undef WITH_MODULE
48     /* Placeholder at end of array */
49     { NULL, NULL, NULL, NULL, UNINIT }
50 };
51
52 static int
53 modules_bsearch(const void *a, const void *b) {
54     const char *key = a;
55     const struct cmodule *cmod = b;
56     return irccasecmp(key, cmod->name);
57 }
58
59 static int
60 modules_qsort(const void *a, const void *b) {
61     const struct cmodule *ca = a, *cb = b;
62     return irccasecmp(ca->name, cb->name);
63 }
64
65 static int
66 module_init(struct cmodule *cmod, int final) {
67     unsigned int ii;
68     struct cmodule *dep;
69
70     switch (cmod->state) {
71     case UNINIT: break;
72     case INITED: if (!final) return 1; break;
73     case DONE:   return 1;
74     case BROKEN: return 0;
75     case WORKING:
76         log_module(MAIN_LOG, LOG_ERROR, "Tried to recursively enable code module %s.", cmod->name);
77         return 0;
78     }
79     cmod->state = WORKING;
80     for (ii=0; cmod->deps[ii]; ++ii) {
81         dep = bsearch(cmod->deps[ii], cmodules, ArrayLength(cmodules)-1, sizeof(cmodules[0]), modules_bsearch);
82         if (!dep) {
83             log_module(MAIN_LOG, LOG_ERROR, "Code module %s depends on unknown module %s.", cmod->name, cmod->deps[ii]);
84             cmod->state = BROKEN;
85             return 0;
86         }
87         if (!module_init(dep, final)) {
88             log_module(MAIN_LOG, LOG_ERROR, "Failed to initialize dependency %s of code module %s.", dep->name, cmod->name);
89             cmod->state = BROKEN;
90             return 0;
91         }
92     }
93     if (final) {
94         if (!cmod->finalize_func()) {
95             log_module(MAIN_LOG, LOG_ERROR, "Failed to finalize code module %s.", cmod->name);
96             cmod->state = BROKEN;
97             return 0;
98         }
99         cmod->state = DONE;
100         return 1;
101     } else {
102         if (!cmod->init_func()) {
103             log_module(MAIN_LOG, LOG_ERROR, "Failed to initialize code module %s.", cmod->name);
104             cmod->state = BROKEN;
105             return 0;
106         }
107         cmod->state = INITED;
108         return 1;
109     }
110 }
111
112 void
113 modules_init(void) {
114     unsigned int ii;
115
116     qsort(cmodules, ArrayLength(cmodules)-1, sizeof(cmodules[0]), modules_qsort);
117     for (ii=0; cmodules[ii].name; ++ii) {
118         if (cmodules[ii].state != UNINIT) continue;
119         module_init(cmodules + ii, 0);
120         if (cmodules[ii].state != INITED) {
121             log_module(MAIN_LOG, LOG_WARNING, "Code module %s not properly initialized.", cmodules[ii].name);
122         }
123     }
124 }
125
126 void
127 modules_finalize(void) {
128     unsigned int ii;
129
130     for (ii=0; cmodules[ii].name; ++ii) {
131         if (cmodules[ii].state != INITED) continue;
132         module_init(cmodules + ii, 1);
133         if (cmodules[ii].state != DONE) {
134             log_module(MAIN_LOG, LOG_WARNING, "Code module %s not properly finalized.", cmodules[ii].name);
135         }
136     }
137 }