2 * Copyright (c) 2015-16 David Lamparter, for NetDEF, Inc.
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.
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.
28 #include "lib/version.h"
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");
35 static struct frrmod_info frrmod_default_info
= {
37 .version
= FRR_VERSION
,
38 .description
= "libfrr core module",
40 union _frrmod_runtime_u frrmod_default
= {
43 .info
= &frrmod_default_info
,
44 .finished_loading
= 1,
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
56 // error need weak symbol support
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
;
63 void frrmod_init(struct frrmod_runtime
*modinfo
)
65 modinfo
->finished_loading
= true;
66 *frrmod_last
= modinfo
;
67 frrmod_last
= &modinfo
->next
;
69 execname
= modinfo
->info
->name
;
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().
78 * The (*pFerrlog)() function may copy these strings if needed, but
79 * should expect them to be freed by frrmod_load() before frrmod_load()
82 * frrmod_load() is coded such that (*pFerrlog)() will be called only
83 * in the case where frrmod_load() returns an error.
85 struct frrmod_runtime
*frrmod_load(const char *spec
, const char *dir
,
86 void (*pFerrlog
)(const void *, const char *),
87 const void *pErrlogCookie
)
90 char name
[PATH_MAX
], fullpath
[PATH_MAX
* 2], *args
;
91 struct frrmod_runtime
*rtinfo
, **rtinfop
;
92 const struct frrmod_info
*info
;
94 #define FRRMOD_LOAD_N_ERRSTR 10
95 char *aErr
[FRRMOD_LOAD_N_ERRSTR
];
96 unsigned int iErr
= 0;
98 memset(aErr
, 0, sizeof(aErr
));
100 #define ERR_RECORD(...) \
102 if (pFerrlog && (iErr < FRRMOD_LOAD_N_ERRSTR)) { \
103 aErr[iErr++] = asprintfrr(MTYPE_MODULE_LOAD_ERR, \
113 for (i = 0; i < iErr; ++i) { \
114 (*pFerrlog)(pErrlogCookie, aErr[i]); \
123 for (i = 0; i < iErr; ++i) { \
124 XFREE(MTYPE_MODULE_LOAD_ERR, aErr[i]); \
130 snprintf(name
, sizeof(name
), "%s", spec
);
131 args
= strchr(name
, ':');
135 if (!strchr(name
, '/')) {
137 snprintf(fullpath
, sizeof(fullpath
), "%s/%s_%s.so", dir
,
139 handle
= dlopen(fullpath
, RTLD_NOW
| RTLD_GLOBAL
);
141 ERR_RECORD("loader error: dlopen(%s): %s",
142 fullpath
, dlerror());
145 snprintf(fullpath
, sizeof(fullpath
), "%s/%s.so", dir
,
147 handle
= dlopen(fullpath
, RTLD_NOW
| RTLD_GLOBAL
);
149 ERR_RECORD("loader error: dlopen(%s): %s",
150 fullpath
, dlerror());
154 snprintf(fullpath
, sizeof(fullpath
), "%s", name
);
155 handle
= dlopen(fullpath
, RTLD_NOW
| RTLD_GLOBAL
);
157 ERR_RECORD("loader error: dlopen(%s): %s", fullpath
,
166 /* previous dlopen() errors are no longer relevant */
169 rtinfop
= dlsym(handle
, "frr_module");
172 ERR_RECORD("\"%s\" is not an FRR module: %s", name
, dlerror());
178 rtinfo
->load_name
= XSTRDUP(MTYPE_MODULE_LOADNAME
, name
);
179 rtinfo
->dl_handle
= handle
;
181 rtinfo
->load_args
= XSTRDUP(MTYPE_MODULE_LOADARGS
, args
);
184 if (rtinfo
->finished_loading
) {
186 ERR_RECORD("module \"%s\" already loaded", name
);
190 if (info
->init
&& info
->init()) {
192 ERR_RECORD("module \"%s\" initialisation failed", name
);
196 rtinfo
->finished_loading
= true;
198 *frrmod_last
= rtinfo
;
199 frrmod_last
= &rtinfo
->next
;
204 XFREE(MTYPE_MODULE_LOADARGS
, rtinfo
->load_args
);
205 XFREE(MTYPE_MODULE_LOADNAME
, rtinfo
->load_name
);
212 void frrmod_unload(struct frrmod_runtime
*module
)