blob: 6fc0aa1042d273b2fc29d49ac3d4ae99a9340e3d [file] [log] [blame]
James Kuszmaul82f6c042021-01-17 11:30:16 -08001/**
2 * @file mod.c Loadable modules
3 *
4 * Copyright (C) 2010 Creytiv.com
5 */
6#include <sys/types.h>
7#include <string.h>
8#include <re_types.h>
9#include <re_fmt.h>
10#include <re_mem.h>
11#include <re_mbuf.h>
12#include <re_list.h>
13#include <re_mod.h>
14#include "mod_internal.h"
15
16
17#define DEBUG_MODULE "mod"
18#define DEBUG_LEVEL 5
19#include <re_dbg.h>
20
21
22/** Defines a loadable module */
23struct mod {
24 struct le le; /**< Linked list element */
25 void *h; /**< Module handler */
26 const struct mod_export *me; /**< Module exports */
27};
28
29
30static struct list modl; /* struct mod */
31
32
33/**
34 * Initialise module loading
35 */
36void mod_init(void)
37{
38 list_init(&modl);
39}
40
41
42/**
43 * Unload all modules
44 */
45void mod_close(void)
46{
47 list_flush(&modl);
48}
49
50
51static void mod_destructor(void *data)
52{
53 struct mod *m = data;
54 const struct mod_export *me = m->me;
55 int err;
56
57 if (me && me->close && (err = me->close())) {
58 DEBUG_NOTICE("close: error (%m)\n", err);
59 }
60
61 list_unlink(&m->le);
62
63 _mod_close(m->h);
64}
65
66
67/**
68 * Find a module by name in the list of loaded modules
69 *
70 * @param name Name of module to find
71 *
72 * @return Module if found, NULL if not found
73 */
74struct mod *mod_find(const char *name)
75{
76 struct le *le;
77 struct pl x;
78
79 if (!name)
80 return NULL;
81
82 if (re_regex(name, strlen(name), "[/]*[^./]+" MOD_EXT, NULL, &x))
83 return NULL;
84
85 for (le = modl.head; le; le = le->next) {
86 struct mod *m = le->data;
87
88 if (0 == pl_strcasecmp(&x, m->me->name))
89 return m;
90 }
91
92 return NULL;
93}
94
95
96/**
97 * Load and initialise a loadable module by name
98 *
99 * @param mp Pointer to allocated module object
100 * @param name Name of loadable module
101 *
102 * @return 0 if success, otherwise errorcode
103 */
104int mod_load(struct mod **mp, const char *name)
105{
106 struct mod *m;
107 int err = 0;
108
109 if (!mp || !name)
110 return EINVAL;
111
112 /* check if already loaded */
113 m = mod_find(name);
114 if (m) {
115 DEBUG_NOTICE("module already loaded: %s\n", name);
116 return EALREADY;
117 }
118
119 m = mem_zalloc(sizeof(*m), mod_destructor);
120 if (!m)
121 return ENOMEM;
122
123 list_append(&modl, &m->le, m);
124
125 m->h = _mod_open(name);
126 if (!m->h) {
127 err = ENOENT;
128 goto out;
129 }
130
131 m->me = _mod_sym(m->h, "exports");
132 if (!m->me) {
133 err = ELIBBAD;
134 goto out;
135 }
136
137 if (m->me->init && (err = m->me->init()))
138 goto out;
139
140 out:
141 if (err)
142 mem_deref(m);
143 else
144 *mp = m;
145
146 return err;
147}
148
149
150/**
151 * Add and initialise an external module with exports
152 *
153 * @param mp Pointer to allocated module object
154 * @param me Module exports
155 *
156 * @return 0 if success, otherwise errorcode
157 */
158int mod_add(struct mod **mp, const struct mod_export *me)
159{
160 struct mod *m;
161 int err = 0;
162
163 if (!mp || !me)
164 return EINVAL;
165
166 /* check if already loaded */
167 m = mod_find(me->name);
168 if (m) {
169 DEBUG_NOTICE("module already loaded: %s\n", me->name);
170 return EALREADY;
171 }
172
173 m = mem_zalloc(sizeof(*m), mod_destructor);
174 if (!m)
175 return ENOMEM;
176
177 list_append(&modl, &m->le, m);
178
179 m->me = me;
180
181 if (m->me->init)
182 err = m->me->init();
183
184 if (err)
185 mem_deref(m);
186 else
187 *mp = m;
188
189 return err;
190}
191
192
193/**
194 * Get module export from a loadable module
195 *
196 * @param m Loadable module
197 *
198 * @return Module export
199 */
200const struct mod_export *mod_export(const struct mod *m)
201{
202 return m ? m->me : NULL;
203}
204
205
206/**
207 * Get the list of loaded modules
208 *
209 * @return Module list
210 */
211struct list *mod_list(void)
212{
213 return &modl;
214}
215
216
217/**
218 * Debug loadable modules
219 *
220 * @param pf Print handler for debug output
221 * @param unused Unused parameter
222 *
223 * @return 0 if success, otherwise errorcode
224 */
225int mod_debug(struct re_printf *pf, void *unused)
226{
227 struct le *le;
228 int err;
229
230 (void)unused;
231
232 err = re_hprintf(pf, "\n--- Modules (%u) ---\n", list_count(&modl));
233
234 for (le = modl.head; le && !err; le = le->next) {
235 const struct mod *m = le->data;
236 const struct mod_export *me = m->me;
237
238 err = re_hprintf(pf, " %16s type=%-12s ref=%u\n",
239 me->name, me->type, mem_nrefs(m));
240 }
241
242 err |= re_hprintf(pf, "\n");
243
244 return err;
245}