Modify how to make symbolic link in 'find-debuginfo.sh' script
[platform/upstream/rpm.git] / lib / rpmplugins.c
1
2 #include "system.h"
3
4 #include <rpm/rpmmacro.h>
5 #include <rpm/rpmtypes.h>
6 #include <rpm/rpmlog.h>
7 #include <rpm/rpmstring.h>
8 #include <rpm/rpmts.h>
9
10 #include "lib/rpmplugins.h"
11
12 #define STR1(x) #x
13 #define STR(x) STR1(x)
14
15 struct rpmPlugins_s {
16     void **handles;
17     ARGV_t names;
18     int count;
19     rpmts ts;
20 };
21
22 static int rpmpluginsGetPluginIndex(rpmPlugins plugins, const char *name)
23 {
24     int i;
25     for (i = 0; i < plugins->count; i++) {
26         if (rstreq(plugins->names[i], name)) {
27             return i;
28         }
29     }
30     return -1;
31 }
32
33 static int rpmpluginsHookIsSupported(void *handle, rpmPluginHook hook)
34 {
35     rpmPluginHook *supportedHooks =
36         (rpmPluginHook *) dlsym(handle, STR(PLUGIN_HOOKS));
37     return (*supportedHooks & hook);
38 }
39
40 int rpmpluginsPluginAdded(rpmPlugins plugins, const char *name)
41 {
42     return (rpmpluginsGetPluginIndex(plugins, name) >= 0);
43 }
44
45 rpmPlugins rpmpluginsNew(rpmts ts)
46 {
47     rpmPlugins plugins = xcalloc(1, sizeof(*plugins));
48     plugins->ts = ts;
49     return plugins;
50 }
51
52 rpmRC rpmpluginsAdd(rpmPlugins plugins, const char *name, const char *path,
53                     const char *opts)
54 {
55     char *error;
56
57     void *handle = dlopen(path, RTLD_LAZY);
58     if (!handle) {
59         rpmlog(RPMLOG_ERR, _("Failed to dlopen %s %s\n"), path, dlerror());
60         return RPMRC_FAIL;
61     }
62
63     /* make sure the plugin has the supported hooks flag */
64     (void) dlsym(handle, STR(PLUGIN_HOOKS));
65     if ((error = dlerror()) != NULL) {
66         rpmlog(RPMLOG_ERR, _("Failed to resolve symbol %s: %s\n"),
67                STR(PLUGIN_HOOKS), error);
68         return RPMRC_FAIL;
69     }
70
71     argvAdd(&plugins->names, name);
72     plugins->handles = xrealloc(plugins->handles, (plugins->count + 1) * sizeof(*plugins->handles));
73     plugins->handles[plugins->count] = handle;
74     plugins->count++;
75
76     return rpmpluginsCallInit(plugins, name, opts);
77 }
78
79 rpmRC rpmpluginsAddPlugin(rpmPlugins plugins, const char *type, const char *name)
80 {
81     char *path;
82     char *options;
83     rpmRC rc = RPMRC_FAIL;
84
85     path = rpmExpand("%{?__", type, "_", name, "}", NULL);
86     if (!path || rstreq(path, "")) {
87         rpmlog(RPMLOG_ERR, _("Failed to expand %%__%s_%s macro\n"),
88                type, name);
89         goto exit;
90     }
91
92     /* split the options from the path */
93 #define SKIPSPACE(s)    { while (*(s) &&  risspace(*(s))) (s)++; }
94 #define SKIPNONSPACE(s) { while (*(s) && !risspace(*(s))) (s)++; }
95     options = path;
96     SKIPNONSPACE(options);
97     if (risspace(*options)) {
98         *options = '\0';
99         options++;
100         SKIPSPACE(options);
101     }
102     if (*options == '\0') {
103         options = NULL;
104     }
105
106     rc = rpmpluginsAdd(plugins, name, path, options);
107
108   exit:
109     _free(path);
110     return rc;
111 }
112
113 rpmPlugins rpmpluginsFree(rpmPlugins plugins)
114 {
115     int i;
116     for (i = 0; i < plugins->count; i++) {
117         rpmpluginsCallCleanup(plugins, plugins->names[i]);
118         dlclose(plugins->handles[i]);
119     }
120     plugins->handles = _free(plugins->handles);
121     plugins->names = argvFree(plugins->names);
122     plugins->ts = NULL;
123     _free(plugins);
124
125     return NULL;
126 }
127
128
129 /* Common define for all rpmpluginsCall* hook functions */
130 #define RPMPLUGINS_SET_HOOK_FUNC(hook) \
131         void *handle = NULL; \
132         int index; \
133         char * error; \
134         index = rpmpluginsGetPluginIndex(plugins, name); \
135         if (index < 0) { \
136                 rpmlog(RPMLOG_ERR, _("Plugin %s not loaded\n"), name); \
137                 return RPMRC_FAIL; \
138         } \
139         handle = plugins->handles[index]; \
140         if (!handle) { \
141                 rpmlog(RPMLOG_ERR, _("Plugin %s not loaded\n"), name); \
142                 return RPMRC_FAIL; \
143         } \
144         if (!rpmpluginsHookIsSupported(handle, hook)) { \
145                 return RPMRC_OK; \
146         } \
147         *(void **)(&hookFunc) = dlsym(handle, STR(hook##_FUNC)); \
148         if ((error = dlerror()) != NULL) { \
149                 rpmlog(RPMLOG_ERR, _("Failed to resolve %s plugin symbol %s: %s\n"), name, STR(hook##_FUNC), error); \
150                 return RPMRC_FAIL; \
151         } \
152         if (rpmtsFlags(plugins->ts) & (RPMTRANS_FLAG_TEST | RPMTRANS_FLAG_JUSTDB)) { \
153                 return RPMRC_OK; \
154         } \
155         rpmlog(RPMLOG_DEBUG, "Plugin: calling hook %s in %s plugin\n", STR(hook##_FUNC), name);
156
157 rpmRC rpmpluginsCallInit(rpmPlugins plugins, const char *name, const char *opts)
158 {
159     rpmRC (*hookFunc)(rpmts, const char *, const char *);
160     RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_INIT);
161     return hookFunc(plugins->ts, name, opts);
162 }
163
164 rpmRC rpmpluginsCallCleanup(rpmPlugins plugins, const char *name)
165 {
166     rpmRC (*hookFunc)(void);
167     RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_CLEANUP);
168     return hookFunc();
169 }
170
171 rpmRC rpmpluginsCallOpenTE(rpmPlugins plugins, const char *name, rpmte te)
172 {
173     rpmRC (*hookFunc)(rpmte);
174     RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_OPENTE);
175     return hookFunc(te);
176 }
177
178 rpmRC rpmpluginsCallCollectionPostAdd(rpmPlugins plugins, const char *name)
179 {
180     rpmRC (*hookFunc)(void);
181     RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_COLL_POST_ADD);
182     return hookFunc();
183 }
184
185 rpmRC rpmpluginsCallCollectionPostAny(rpmPlugins plugins, const char *name)
186 {
187     rpmRC (*hookFunc)(void);
188     RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_COLL_POST_ANY);
189     return hookFunc();
190 }
191
192 rpmRC rpmpluginsCallCollectionPreRemove(rpmPlugins plugins, const char *name)
193 {
194     rpmRC (*hookFunc)(void);
195     RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_COLL_PRE_REMOVE);
196     return hookFunc();
197 }
198
199 rpmRC rpmpluginsCallTsmPre(rpmPlugins plugins, rpmts ts)
200 {
201     rpmRC (*hookFunc)(rpmts);
202     int i;
203     rpmRC rc = RPMRC_OK;
204     const char *name = NULL;
205
206     for (i = 0; i < plugins->count; i++) {
207         name = plugins->names[i];
208         RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_TSM_PRE);
209         if (hookFunc(ts) == RPMRC_FAIL)
210             rc = RPMRC_FAIL;
211     }
212
213     return rc;
214 }
215
216 rpmRC rpmpluginsCallTsmPost(rpmPlugins plugins, rpmts ts, int res)
217 {
218     rpmRC (*hookFunc)(rpmts, int);
219     int i;
220     rpmRC rc = RPMRC_OK;
221     const char *name = NULL;
222
223     for (i = 0; i < plugins->count; i++) {
224         name = plugins->names[i];
225         RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_TSM_POST);
226         if (hookFunc(ts, res) == RPMRC_FAIL)
227             rc = RPMRC_FAIL;
228     }
229
230     return rc;
231 }
232
233 rpmRC rpmpluginsCallPsmPre(rpmPlugins plugins, rpmte te)
234 {
235     rpmRC (*hookFunc)(rpmte);
236     int i;
237     rpmRC rc = RPMRC_OK;
238     const char *name = NULL;
239
240     for (i = 0; i < plugins->count; i++) {
241         name = plugins->names[i];
242         RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_PSM_PRE);
243         if (hookFunc(te) == RPMRC_FAIL)
244             rc = RPMRC_FAIL;
245     }
246
247     return rc;
248 }
249
250 rpmRC rpmpluginsCallPsmPost(rpmPlugins plugins, rpmte te, int res)
251 {
252     rpmRC (*hookFunc)(rpmte, int);
253     int i;
254     rpmRC rc = RPMRC_OK;
255     const char *name = NULL;
256
257     for (i = 0; i < plugins->count; i++) {
258         name = plugins->names[i];
259         RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_PSM_POST);
260         if (hookFunc(te, res) == RPMRC_FAIL)
261             rc = RPMRC_FAIL;
262     }
263
264     return rc;
265 }
266
267 rpmRC rpmpluginsCallScriptletPre(rpmPlugins plugins, const char *s_name, int type)
268 {
269     rpmRC (*hookFunc)(const char*, int);
270     int i;
271     rpmRC rc = RPMRC_OK;
272     const char *name = NULL;
273
274     for (i = 0; i < plugins->count; i++) {
275         name = plugins->names[i];
276         RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_SCRIPTLET_PRE);
277         if (hookFunc(s_name, type) == RPMRC_FAIL)
278             rc = RPMRC_FAIL;
279     }
280
281     return rc;
282 }
283
284 rpmRC rpmpluginsCallScriptletForkPost(rpmPlugins plugins, const char *path, int type)
285 {
286     rpmRC (*hookFunc)(const char*, int);
287     int i;
288     rpmRC rc = RPMRC_OK;
289     const char *name = NULL;
290
291     for (i = 0; i < plugins->count; i++) {
292         name = plugins->names[i];
293         RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_SCRIPTLET_FORK_POST);
294         if (hookFunc(path, type) == RPMRC_FAIL)
295             rc = RPMRC_FAIL;
296     }
297
298     return rc;
299 }
300
301 rpmRC rpmpluginsCallScriptletPost(rpmPlugins plugins, const char *s_name, int type, int res)
302 {
303     rpmRC (*hookFunc)(const char*, int, int);
304     int i;
305     rpmRC rc = RPMRC_OK;
306     const char *name = NULL;
307
308     for (i = 0; i < plugins->count; i++) {
309         name = plugins->names[i];
310         RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_SCRIPTLET_POST);
311         if (hookFunc(s_name, type, res) == RPMRC_FAIL)
312             rc = RPMRC_FAIL;
313     }
314
315     return rc;
316 }
317
318 rpmRC rpmpluginsCallVerify(rpmPlugins plugins, rpmKeyring keyring, rpmtd sigtd, 
319                             pgpDigParams sig, DIGEST_CTX ctx, int res)
320 {
321     rpmRC (*hookFunc)(rpmKeyring, rpmtd, pgpDigParams, DIGEST_CTX, int);
322     int i;
323     rpmRC rc = RPMRC_OK;
324     const char *name = NULL;
325
326     for (i = 0; i < plugins->count; i++) {
327         name = plugins->names[i];
328         RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_VERIFY);
329         if (hookFunc(keyring, sigtd, sig, ctx, res) == RPMRC_FAIL)
330             rc = RPMRC_FAIL;
331     }
332
333     return rc;
334 }
335
336 rpmRC rpmpluginsCallFsmInit(rpmPlugins plugins, const char* path,
337                                 mode_t mode)
338 {
339     rpmRC (*hookFunc)(const char*, mode_t);
340     int i;
341     rpmRC rc = RPMRC_OK;
342     const char *name = NULL;
343
344     for (i = 0; i < plugins->count; i++) {
345         name = plugins->names[i];
346         RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_FSM_INIT);
347         if (hookFunc(path, mode) == RPMRC_FAIL)
348             rc = RPMRC_FAIL;
349     }
350
351     return rc;
352 }
353
354 rpmRC rpmpluginsCallFsmCommit(rpmPlugins plugins, const char* path,
355                                 mode_t mode, int type)
356 {
357     rpmRC (*hookFunc)(const char*, mode_t, int);
358     int i;
359     rpmRC rc = RPMRC_OK;
360     const char *name = NULL;
361
362     for (i = 0; i < plugins->count; i++) {
363         name = plugins->names[i];
364         RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_FSM_COMMIT);
365         if (hookFunc(path, mode, type) == RPMRC_FAIL)
366             rc = RPMRC_FAIL;
367     }
368
369     return rc;
370 }
371
372 rpmRC rpmpluginsCallFileConflict(rpmPlugins plugins, rpmts ts, char* path,
373                                 Header oldHeader, rpmfi oldFi, int res)
374 {
375     rpmRC (*hookFunc)(rpmts, char*, Header, rpmfi, int);
376     int i;
377     rpmRC rc = RPMRC_OK;
378     const char *name = NULL;
379
380     for (i = 0; i < plugins->count; i++) {
381         name = plugins->names[i];
382         RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_FILE_CONFLICT);
383         if (hookFunc(ts, path, oldHeader, oldFi, res) == RPMRC_FAIL)
384             rc = RPMRC_FAIL;
385     }
386
387     return rc;
388 }