Line data Source code
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 24 : DEFINE_MTYPE_STATIC(LIB, MODULE_LOADNAME, "Module loading name");
32 24 : DEFINE_MTYPE_STATIC(LIB, MODULE_LOADARGS, "Module loading arguments");
33 24 : 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 8 : 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 8 : void frrmod_init(struct frrmod_runtime *modinfo)
64 : {
65 8 : modinfo->finished_loading = true;
66 8 : *frrmod_last = modinfo;
67 8 : frrmod_last = &modinfo->next;
68 :
69 8 : execname = modinfo->info->name;
70 8 : }
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 0 : struct frrmod_runtime *frrmod_load(const char *spec, const char *dir,
86 : void (*pFerrlog)(const void *, const char *),
87 : const void *pErrlogCookie)
88 : {
89 0 : void *handle = NULL;
90 0 : char name[PATH_MAX], fullpath[PATH_MAX * 2], *args;
91 0 : struct frrmod_runtime *rtinfo, **rtinfop;
92 0 : const struct frrmod_info *info;
93 :
94 : #define FRRMOD_LOAD_N_ERRSTR 10
95 0 : char *aErr[FRRMOD_LOAD_N_ERRSTR];
96 0 : unsigned int iErr = 0;
97 :
98 0 : 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 0 : snprintf(name, sizeof(name), "%s", spec);
131 0 : args = strchr(name, ':');
132 0 : if (args)
133 0 : *args++ = '\0';
134 :
135 0 : if (!strchr(name, '/')) {
136 0 : if (execname) {
137 0 : snprintf(fullpath, sizeof(fullpath), "%s/%s_%s.so", dir,
138 : execname, name);
139 0 : handle = dlopen(fullpath, RTLD_NOW | RTLD_GLOBAL);
140 0 : if (!handle)
141 0 : ERR_RECORD("loader error: dlopen(%s): %s",
142 : fullpath, dlerror());
143 : }
144 : if (!handle) {
145 0 : snprintf(fullpath, sizeof(fullpath), "%s/%s.so", dir,
146 : name);
147 0 : handle = dlopen(fullpath, RTLD_NOW | RTLD_GLOBAL);
148 0 : if (!handle)
149 0 : ERR_RECORD("loader error: dlopen(%s): %s",
150 : fullpath, dlerror());
151 : }
152 : }
153 : if (!handle) {
154 0 : snprintf(fullpath, sizeof(fullpath), "%s", name);
155 0 : handle = dlopen(fullpath, RTLD_NOW | RTLD_GLOBAL);
156 0 : if (!handle)
157 0 : ERR_RECORD("loader error: dlopen(%s): %s", fullpath,
158 : dlerror());
159 : }
160 0 : if (!handle) {
161 0 : ERR_REPORT;
162 0 : ERR_FREE;
163 : return NULL;
164 : }
165 :
166 : /* previous dlopen() errors are no longer relevant */
167 0 : ERR_FREE;
168 :
169 0 : rtinfop = dlsym(handle, "frr_module");
170 0 : if (!rtinfop) {
171 0 : dlclose(handle);
172 0 : ERR_RECORD("\"%s\" is not an FRR module: %s", name, dlerror());
173 0 : ERR_REPORT;
174 0 : ERR_FREE;
175 : return NULL;
176 : }
177 0 : rtinfo = *rtinfop;
178 0 : rtinfo->load_name = XSTRDUP(MTYPE_MODULE_LOADNAME, name);
179 0 : rtinfo->dl_handle = handle;
180 0 : if (args)
181 0 : rtinfo->load_args = XSTRDUP(MTYPE_MODULE_LOADARGS, args);
182 0 : info = rtinfo->info;
183 :
184 0 : if (rtinfo->finished_loading) {
185 0 : dlclose(handle);
186 0 : ERR_RECORD("module \"%s\" already loaded", name);
187 0 : goto out_fail;
188 : }
189 :
190 0 : if (info->init && info->init()) {
191 0 : dlclose(handle);
192 0 : ERR_RECORD("module \"%s\" initialisation failed", name);
193 0 : goto out_fail;
194 : }
195 :
196 0 : rtinfo->finished_loading = true;
197 :
198 0 : *frrmod_last = rtinfo;
199 0 : frrmod_last = &rtinfo->next;
200 0 : ERR_FREE;
201 : return rtinfo;
202 :
203 0 : out_fail:
204 0 : XFREE(MTYPE_MODULE_LOADARGS, rtinfo->load_args);
205 0 : XFREE(MTYPE_MODULE_LOADNAME, rtinfo->load_name);
206 0 : ERR_REPORT;
207 0 : ERR_FREE;
208 : return NULL;
209 : }
210 :
211 : #if 0
212 : void frrmod_unload(struct frrmod_runtime *module)
213 : {
214 : }
215 : #endif
|