]>
Commit | Line | Data |
---|---|---|
30771d65 DL |
1 | /* |
2 | * Copyright (c) 2015-16 David Lamparter, for NetDEF, Inc. | |
3 | * | |
bbfeedb5 DL |
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. | |
30771d65 | 7 | * |
bbfeedb5 DL |
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. | |
30771d65 DL |
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 "version.h" | |
29 | ||
30 | DEFINE_MTYPE_STATIC(LIB, MODULE_LOADNAME, "Module loading name") | |
31 | DEFINE_MTYPE_STATIC(LIB, MODULE_LOADARGS, "Module loading arguments") | |
32 | ||
33 | static struct frrmod_info frrmod_default_info = { | |
34 | .name = "libfrr", | |
35 | .version = FRR_VERSION, | |
36 | .description = "libfrr core module", | |
37 | }; | |
38 | union _frrmod_runtime_u frrmod_default = { | |
996c9314 LB |
39 | .r = |
40 | { | |
41 | .info = &frrmod_default_info, | |
42 | .finished_loading = 1, | |
43 | }, | |
30771d65 DL |
44 | }; |
45 | ||
46 | // if defined(HAVE_SYS_WEAK_ALIAS_ATTRIBUTE) | |
47 | // union _frrmod_runtime_u _frrmod_this_module | |
48 | // __attribute__((weak, alias("frrmod_default"))); | |
49 | // elif defined(HAVE_SYS_WEAK_ALIAS_PRAGMA) | |
50 | #pragma weak _frrmod_this_module = frrmod_default | |
51 | // else | |
52 | // error need weak symbol support | |
53 | // endif | |
54 | ||
55 | struct frrmod_runtime *frrmod_list = &frrmod_default.r; | |
56 | static struct frrmod_runtime **frrmod_last = &frrmod_default.r.next; | |
57 | static const char *execname = NULL; | |
58 | ||
59 | void frrmod_init(struct frrmod_runtime *modinfo) | |
60 | { | |
61 | modinfo->finished_loading = 1; | |
62 | *frrmod_last = modinfo; | |
63 | frrmod_last = &modinfo->next; | |
64 | ||
65 | execname = modinfo->info->name; | |
66 | } | |
67 | ||
d62a17ae | 68 | struct frrmod_runtime *frrmod_load(const char *spec, const char *dir, char *err, |
69 | size_t err_len) | |
30771d65 DL |
70 | { |
71 | void *handle = NULL; | |
ff44f570 | 72 | char name[PATH_MAX], fullpath[PATH_MAX * 2], *args; |
30771d65 DL |
73 | struct frrmod_runtime *rtinfo, **rtinfop; |
74 | const struct frrmod_info *info; | |
75 | ||
76 | snprintf(name, sizeof(name), "%s", spec); | |
77 | args = strchr(name, ':'); | |
78 | if (args) | |
79 | *args++ = '\0'; | |
80 | ||
81 | if (!strchr(name, '/')) { | |
2e1cc436 | 82 | if (execname) { |
d62a17ae | 83 | snprintf(fullpath, sizeof(fullpath), "%s/%s_%s.so", dir, |
84 | execname, name); | |
30771d65 DL |
85 | handle = dlopen(fullpath, RTLD_NOW | RTLD_GLOBAL); |
86 | } | |
87 | if (!handle) { | |
d62a17ae | 88 | snprintf(fullpath, sizeof(fullpath), "%s/%s.so", dir, |
89 | name); | |
30771d65 DL |
90 | handle = dlopen(fullpath, RTLD_NOW | RTLD_GLOBAL); |
91 | } | |
92 | } | |
93 | if (!handle) { | |
94 | snprintf(fullpath, sizeof(fullpath), "%s", name); | |
95 | handle = dlopen(fullpath, RTLD_NOW | RTLD_GLOBAL); | |
96 | } | |
97 | if (!handle) { | |
98 | if (err) | |
99 | snprintf(err, err_len, | |
d62a17ae | 100 | "loading module \"%s\" failed: %s", name, |
101 | dlerror()); | |
30771d65 DL |
102 | return NULL; |
103 | } | |
104 | ||
105 | rtinfop = dlsym(handle, "frr_module"); | |
106 | if (!rtinfop) { | |
107 | dlclose(handle); | |
108 | if (err) | |
109 | snprintf(err, err_len, | |
d62a17ae | 110 | "\"%s\" is not an FRR module: %s", name, |
111 | dlerror()); | |
30771d65 DL |
112 | return NULL; |
113 | } | |
114 | rtinfo = *rtinfop; | |
115 | rtinfo->load_name = XSTRDUP(MTYPE_MODULE_LOADNAME, name); | |
116 | rtinfo->dl_handle = handle; | |
117 | if (args) | |
118 | rtinfo->load_args = XSTRDUP(MTYPE_MODULE_LOADARGS, args); | |
119 | info = rtinfo->info; | |
120 | ||
121 | if (rtinfo->finished_loading) { | |
122 | dlclose(handle); | |
123 | if (err) | |
d62a17ae | 124 | snprintf(err, err_len, "module \"%s\" already loaded", |
125 | name); | |
30771d65 DL |
126 | goto out_fail; |
127 | } | |
128 | ||
129 | if (info->init && info->init()) { | |
130 | dlclose(handle); | |
131 | if (err) | |
132 | snprintf(err, err_len, | |
d62a17ae | 133 | "module \"%s\" initialisation failed", name); |
30771d65 DL |
134 | goto out_fail; |
135 | } | |
136 | ||
137 | rtinfo->finished_loading = 1; | |
138 | ||
139 | *frrmod_last = rtinfo; | |
140 | frrmod_last = &rtinfo->next; | |
141 | return rtinfo; | |
142 | ||
143 | out_fail: | |
144 | if (rtinfo->load_args) | |
145 | XFREE(MTYPE_MODULE_LOADARGS, rtinfo->load_args); | |
146 | XFREE(MTYPE_MODULE_LOADNAME, rtinfo->load_name); | |
147 | return NULL; | |
148 | } | |
149 | ||
150 | #if 0 | |
151 | void frrmod_unload(struct frrmod_runtime *module) | |
152 | { | |
153 | } | |
154 | #endif |