]>
Commit | Line | Data |
---|---|---|
30771d65 DL |
1 | /* |
2 | * Copyright (c) 2015-16 David Lamparter, for NetDEF, Inc. | |
3 | * | |
4 | * Permission is hereby granted, free of charge, to any person obtaining a | |
5 | * copy of this software and associated documentation files (the "Software"), | |
6 | * to deal in the Software without restriction, including without limitation | |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
8 | * and/or sell copies of the Software, and to permit persons to whom the | |
9 | * Software is furnished to do so, subject to the following conditions: | |
10 | * | |
11 | * The above copyright notice and this permission notice shall be included in | |
12 | * all copies or substantial portions of the Software. | |
13 | * | |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
20 | * DEALINGS IN THE SOFTWARE. | |
21 | */ | |
22 | ||
23 | #include "config.h" | |
24 | ||
25 | #include <stdlib.h> | |
26 | #include <stdio.h> | |
27 | #include <string.h> | |
28 | #include <unistd.h> | |
29 | #include <limits.h> | |
30 | #include <dlfcn.h> | |
31 | ||
32 | #include "module.h" | |
33 | #include "memory.h" | |
34 | #include "version.h" | |
35 | ||
36 | DEFINE_MTYPE_STATIC(LIB, MODULE_LOADNAME, "Module loading name") | |
37 | DEFINE_MTYPE_STATIC(LIB, MODULE_LOADARGS, "Module loading arguments") | |
38 | ||
39 | static struct frrmod_info frrmod_default_info = { | |
40 | .name = "libfrr", | |
41 | .version = FRR_VERSION, | |
42 | .description = "libfrr core module", | |
43 | }; | |
44 | union _frrmod_runtime_u frrmod_default = { | |
996c9314 LB |
45 | .r = |
46 | { | |
47 | .info = &frrmod_default_info, | |
48 | .finished_loading = 1, | |
49 | }, | |
30771d65 DL |
50 | }; |
51 | ||
52 | // if defined(HAVE_SYS_WEAK_ALIAS_ATTRIBUTE) | |
53 | // union _frrmod_runtime_u _frrmod_this_module | |
54 | // __attribute__((weak, alias("frrmod_default"))); | |
55 | // elif defined(HAVE_SYS_WEAK_ALIAS_PRAGMA) | |
56 | #pragma weak _frrmod_this_module = frrmod_default | |
57 | // else | |
58 | // error need weak symbol support | |
59 | // endif | |
60 | ||
61 | struct frrmod_runtime *frrmod_list = &frrmod_default.r; | |
62 | static struct frrmod_runtime **frrmod_last = &frrmod_default.r.next; | |
63 | static const char *execname = NULL; | |
64 | ||
65 | void frrmod_init(struct frrmod_runtime *modinfo) | |
66 | { | |
67 | modinfo->finished_loading = 1; | |
68 | *frrmod_last = modinfo; | |
69 | frrmod_last = &modinfo->next; | |
70 | ||
71 | execname = modinfo->info->name; | |
72 | } | |
73 | ||
d62a17ae | 74 | struct frrmod_runtime *frrmod_load(const char *spec, const char *dir, char *err, |
75 | size_t err_len) | |
30771d65 DL |
76 | { |
77 | void *handle = NULL; | |
78 | char name[PATH_MAX], fullpath[PATH_MAX], *args; | |
79 | struct frrmod_runtime *rtinfo, **rtinfop; | |
80 | const struct frrmod_info *info; | |
81 | ||
82 | snprintf(name, sizeof(name), "%s", spec); | |
83 | args = strchr(name, ':'); | |
84 | if (args) | |
85 | *args++ = '\0'; | |
86 | ||
87 | if (!strchr(name, '/')) { | |
88 | if (!handle && execname) { | |
d62a17ae | 89 | snprintf(fullpath, sizeof(fullpath), "%s/%s_%s.so", dir, |
90 | execname, name); | |
30771d65 DL |
91 | handle = dlopen(fullpath, RTLD_NOW | RTLD_GLOBAL); |
92 | } | |
93 | if (!handle) { | |
d62a17ae | 94 | snprintf(fullpath, sizeof(fullpath), "%s/%s.so", dir, |
95 | name); | |
30771d65 DL |
96 | handle = dlopen(fullpath, RTLD_NOW | RTLD_GLOBAL); |
97 | } | |
98 | } | |
99 | if (!handle) { | |
100 | snprintf(fullpath, sizeof(fullpath), "%s", name); | |
101 | handle = dlopen(fullpath, RTLD_NOW | RTLD_GLOBAL); | |
102 | } | |
103 | if (!handle) { | |
104 | if (err) | |
105 | snprintf(err, err_len, | |
d62a17ae | 106 | "loading module \"%s\" failed: %s", name, |
107 | dlerror()); | |
30771d65 DL |
108 | return NULL; |
109 | } | |
110 | ||
111 | rtinfop = dlsym(handle, "frr_module"); | |
112 | if (!rtinfop) { | |
113 | dlclose(handle); | |
114 | if (err) | |
115 | snprintf(err, err_len, | |
d62a17ae | 116 | "\"%s\" is not an FRR module: %s", name, |
117 | dlerror()); | |
30771d65 DL |
118 | return NULL; |
119 | } | |
120 | rtinfo = *rtinfop; | |
121 | rtinfo->load_name = XSTRDUP(MTYPE_MODULE_LOADNAME, name); | |
122 | rtinfo->dl_handle = handle; | |
123 | if (args) | |
124 | rtinfo->load_args = XSTRDUP(MTYPE_MODULE_LOADARGS, args); | |
125 | info = rtinfo->info; | |
126 | ||
127 | if (rtinfo->finished_loading) { | |
128 | dlclose(handle); | |
129 | if (err) | |
d62a17ae | 130 | snprintf(err, err_len, "module \"%s\" already loaded", |
131 | name); | |
30771d65 DL |
132 | goto out_fail; |
133 | } | |
134 | ||
135 | if (info->init && info->init()) { | |
136 | dlclose(handle); | |
137 | if (err) | |
138 | snprintf(err, err_len, | |
d62a17ae | 139 | "module \"%s\" initialisation failed", name); |
30771d65 DL |
140 | goto out_fail; |
141 | } | |
142 | ||
143 | rtinfo->finished_loading = 1; | |
144 | ||
145 | *frrmod_last = rtinfo; | |
146 | frrmod_last = &rtinfo->next; | |
147 | return rtinfo; | |
148 | ||
149 | out_fail: | |
150 | if (rtinfo->load_args) | |
151 | XFREE(MTYPE_MODULE_LOADARGS, rtinfo->load_args); | |
152 | XFREE(MTYPE_MODULE_LOADNAME, rtinfo->load_name); | |
153 | return NULL; | |
154 | } | |
155 | ||
156 | #if 0 | |
157 | void frrmod_unload(struct frrmod_runtime *module) | |
158 | { | |
159 | } | |
160 | #endif |