]> git.proxmox.com Git - mirror_frr.git/blob - lib/module.c
Merge pull request #13278 from FRRouting/mergify/bp/stable/8.5/pr-13269
[mirror_frr.git] / lib / module.c
1 /*
2 * Copyright (c) 2015-16 David Lamparter, for NetDEF, Inc.
3 *
4 * Permission to use, copy, modify, and 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 appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include "config.h"
18
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <limits.h>
24 #include <dlfcn.h>
25
26 #include "module.h"
27 #include "memory.h"
28 #include "lib/version.h"
29 #include "printfrr.h"
30
31 DEFINE_MTYPE_STATIC(LIB, MODULE_LOADNAME, "Module loading name");
32 DEFINE_MTYPE_STATIC(LIB, MODULE_LOADARGS, "Module loading arguments");
33 DEFINE_MTYPE_STATIC(LIB, MODULE_LOAD_ERR, "Module loading error");
34
35 static struct frrmod_info frrmod_default_info = {
36 .name = "libfrr",
37 .version = FRR_VERSION,
38 .description = "libfrr core module",
39 };
40 union _frrmod_runtime_u frrmod_default = {
41 .r =
42 {
43 .info = &frrmod_default_info,
44 .finished_loading = 1,
45 },
46 };
47
48 XREF_SETUP();
49
50 // if defined(HAVE_SYS_WEAK_ALIAS_ATTRIBUTE)
51 // union _frrmod_runtime_u _frrmod_this_module
52 // __attribute__((weak, alias("frrmod_default")));
53 // elif defined(HAVE_SYS_WEAK_ALIAS_PRAGMA)
54 #pragma weak _frrmod_this_module = frrmod_default
55 // else
56 // error need weak symbol support
57 // endif
58
59 struct frrmod_runtime *frrmod_list = &frrmod_default.r;
60 static struct frrmod_runtime **frrmod_last = &frrmod_default.r.next;
61 static const char *execname = NULL;
62
63 void frrmod_init(struct frrmod_runtime *modinfo)
64 {
65 modinfo->finished_loading = true;
66 *frrmod_last = modinfo;
67 frrmod_last = &modinfo->next;
68
69 execname = modinfo->info->name;
70 }
71
72 /*
73 * If caller wants error strings, it should define non-NULL pFerrlog
74 * which will be called with 0-terminated error messages. These
75 * messages will NOT contain newlines, and the (*pFerrlog)() function
76 * could be called multiple times for a single call to frrmod_load().
77 *
78 * The (*pFerrlog)() function may copy these strings if needed, but
79 * should expect them to be freed by frrmod_load() before frrmod_load()
80 * returns.
81 *
82 * frrmod_load() is coded such that (*pFerrlog)() will be called only
83 * in the case where frrmod_load() returns an error.
84 */
85 struct frrmod_runtime *frrmod_load(const char *spec, const char *dir,
86 void (*pFerrlog)(const void *, const char *),
87 const void *pErrlogCookie)
88 {
89 void *handle = NULL;
90 char name[PATH_MAX], fullpath[PATH_MAX * 2], *args;
91 struct frrmod_runtime *rtinfo, **rtinfop;
92 const struct frrmod_info *info;
93
94 #define FRRMOD_LOAD_N_ERRSTR 10
95 char *aErr[FRRMOD_LOAD_N_ERRSTR];
96 unsigned int iErr = 0;
97
98 memset(aErr, 0, sizeof(aErr));
99
100 #define ERR_RECORD(...) \
101 do { \
102 if (pFerrlog && (iErr < FRRMOD_LOAD_N_ERRSTR)) { \
103 aErr[iErr++] = asprintfrr(MTYPE_MODULE_LOAD_ERR, \
104 __VA_ARGS__); \
105 } \
106 } while (0)
107
108 #define ERR_REPORT \
109 do { \
110 if (pFerrlog) { \
111 unsigned int i; \
112 \
113 for (i = 0; i < iErr; ++i) { \
114 (*pFerrlog)(pErrlogCookie, aErr[i]); \
115 } \
116 } \
117 } while (0)
118
119 #define ERR_FREE \
120 do { \
121 unsigned int i; \
122 \
123 for (i = 0; i < iErr; ++i) { \
124 XFREE(MTYPE_MODULE_LOAD_ERR, aErr[i]); \
125 aErr[i] = 0; \
126 } \
127 iErr = 0; \
128 } while (0)
129
130 snprintf(name, sizeof(name), "%s", spec);
131 args = strchr(name, ':');
132 if (args)
133 *args++ = '\0';
134
135 if (!strchr(name, '/')) {
136 if (execname) {
137 snprintf(fullpath, sizeof(fullpath), "%s/%s_%s.so", dir,
138 execname, name);
139 handle = dlopen(fullpath, RTLD_NOW | RTLD_GLOBAL);
140 if (!handle)
141 ERR_RECORD("loader error: dlopen(%s): %s",
142 fullpath, dlerror());
143 }
144 if (!handle) {
145 snprintf(fullpath, sizeof(fullpath), "%s/%s.so", dir,
146 name);
147 handle = dlopen(fullpath, RTLD_NOW | RTLD_GLOBAL);
148 if (!handle)
149 ERR_RECORD("loader error: dlopen(%s): %s",
150 fullpath, dlerror());
151 }
152 }
153 if (!handle) {
154 snprintf(fullpath, sizeof(fullpath), "%s", name);
155 handle = dlopen(fullpath, RTLD_NOW | RTLD_GLOBAL);
156 if (!handle)
157 ERR_RECORD("loader error: dlopen(%s): %s", fullpath,
158 dlerror());
159 }
160 if (!handle) {
161 ERR_REPORT;
162 ERR_FREE;
163 return NULL;
164 }
165
166 /* previous dlopen() errors are no longer relevant */
167 ERR_FREE;
168
169 rtinfop = dlsym(handle, "frr_module");
170 if (!rtinfop) {
171 dlclose(handle);
172 ERR_RECORD("\"%s\" is not an FRR module: %s", name, dlerror());
173 ERR_REPORT;
174 ERR_FREE;
175 return NULL;
176 }
177 rtinfo = *rtinfop;
178 rtinfo->load_name = XSTRDUP(MTYPE_MODULE_LOADNAME, name);
179 rtinfo->dl_handle = handle;
180 if (args)
181 rtinfo->load_args = XSTRDUP(MTYPE_MODULE_LOADARGS, args);
182 info = rtinfo->info;
183
184 if (rtinfo->finished_loading) {
185 dlclose(handle);
186 ERR_RECORD("module \"%s\" already loaded", name);
187 goto out_fail;
188 }
189
190 if (info->init && info->init()) {
191 dlclose(handle);
192 ERR_RECORD("module \"%s\" initialisation failed", name);
193 goto out_fail;
194 }
195
196 rtinfo->finished_loading = true;
197
198 *frrmod_last = rtinfo;
199 frrmod_last = &rtinfo->next;
200 ERR_FREE;
201 return rtinfo;
202
203 out_fail:
204 XFREE(MTYPE_MODULE_LOADARGS, rtinfo->load_args);
205 XFREE(MTYPE_MODULE_LOADNAME, rtinfo->load_name);
206 ERR_REPORT;
207 ERR_FREE;
208 return NULL;
209 }
210
211 #if 0
212 void frrmod_unload(struct frrmod_runtime *module)
213 {
214 }
215 #endif