blob: 6b6d55ac9b0868c3106377e4e2eceb4d720b9a0d [file] [log] [blame]
Ole Troandf87f802020-11-18 19:17:48 +01001/*
2 * Copyright (c) 2020 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <dlfcn.h>
17#include <dirent.h>
18#include <sys/types.h>
19#include <sys/stat.h>
20#include <unistd.h>
21#include <vlib/vlib.h>
22#include "vat2.h"
23
24typedef struct
25{
26 u8 *name;
27 u8 *filename;
28 struct stat file_info;
29 void *handle;
30} plugin_info_t;
31
32/* loaded plugin info */
33plugin_info_t *plugin_info;
34
35static int
36load_one_plugin (plugin_info_t * pi)
37{
38 void *handle, *register_handle;
39 clib_error_t *(*fp) (void);
40 clib_error_t *error;
41
42 handle = dlopen ((char *) pi->name, RTLD_LAZY);
43
44 /*
45 * Note: this can happen if the plugin has an undefined symbol reference,
46 * so print a warning. Otherwise, the poor slob won't know what happened.
47 * Ask me how I know that...
48 */
49 if (handle == 0)
50 {
51 clib_warning ("%s", dlerror ());
52 return -1;
53 }
54
55 pi->handle = handle;
56
57 register_handle = dlsym (pi->handle, "vat2_register_plugin");
58 if (register_handle == 0)
59 {
60 clib_warning ("%s: symbol vat2_register_plugin not found", pi->name);
61 dlclose (handle);
62 return -1;
63 }
64
65 fp = register_handle;
66
67 error = (*fp) ();
68
69 if (error)
70 {
71 clib_error_report (error);
72 dlclose (handle);
73 return -1;
74 }
75
76 return 0;
77}
78
79static u8 **
80split_plugin_path (char *plugin_path)
81{
82 int i;
83 u8 **rv = 0;
84 u8 *path = (u8 *) plugin_path;
85 u8 *this = 0;
86
87 for (i = 0; i < vec_len (plugin_path); i++)
88 {
89 if (path[i] != ':')
90 {
91 vec_add1 (this, path[i]);
92 continue;
93 }
94 vec_add1 (this, 0);
95 vec_add1 (rv, this);
96 this = 0;
97 }
98 if (this)
99 {
100 vec_add1 (this, 0);
101 vec_add1 (rv, this);
102 }
103 return rv;
104}
105
106int
107vat2_load_plugins (char *path, char *filter, int *loaded)
108{
109 DIR *dp;
110 struct dirent *entry;
111 struct stat statb;
112 uword *p;
113 plugin_info_t *pi;
114 u8 **plugin_path;
115 int i;
116 int res = 0;
117 uword *plugin_by_name_hash = hash_create_string (0, sizeof (uword));
118
119 *loaded = 0;
120 plugin_path = split_plugin_path (path);
121
122 for (i = 0; i < vec_len (plugin_path); i++)
123 {
124 DBG ("Opening path: %s\n", plugin_path[i]);
125 dp = opendir ((char *) plugin_path[i]);
126
127 if (dp == 0)
128 continue;
129
130 while ((entry = readdir (dp)))
131 {
132 u8 *plugin_name;
133
134 if (filter)
135 {
136 int j;
137 for (j = 0; j < vec_len (filter); j++)
138 if (entry->d_name[j] != filter[j])
139 goto next;
140 }
141
142 plugin_name = format (0, "%s/%s%c", plugin_path[i],
143 entry->d_name, 0);
144
145 /* unreadable */
146 if (stat ((char *) plugin_name, &statb) < 0)
147 {
148 ignore:
149 vec_free (plugin_name);
150 continue;
151 }
152
153 /* a dir or other things which aren't plugins */
154 if (!S_ISREG (statb.st_mode))
155 goto ignore;
156
157 p = hash_get_mem (plugin_by_name_hash, plugin_name);
158 if (p == 0)
159 {
160 vec_add2 (plugin_info, pi, 1);
161 pi->name = plugin_name;
162 pi->file_info = statb;
163
164 if (load_one_plugin (pi))
165 {
166 res = -1;
167 vec_free (plugin_name);
168 _vec_len (plugin_info) = vec_len (plugin_info) - 1;
169 continue;
170 }
171 clib_memset (pi, 0, sizeof (*pi));
172 hash_set_mem (plugin_by_name_hash, plugin_name,
173 pi - plugin_info);
174 *loaded = *loaded + 1;
175 }
176 next:
177 ;
178 }
179 closedir (dp);
180 vec_free (plugin_path[i]);
181 }
182 vec_free (plugin_path);
183 return res;
184}
185
186#define QUOTE_(x) #x
187#define QUOTE(x) QUOTE_(x)
188
189/*
190 * fd.io coding-style-patch-verification: ON
191 *
192 * Local Variables:
193 * eval: (c-set-style "gnu")
194 * End:
195 */