Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief Source for list plugin
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : *
8 : */
9 :
10 :
11 : #ifndef HAVE_KDBCONFIG
12 : #include "kdbconfig.h"
13 : #endif
14 :
15 : #include "list.h"
16 : #include <kdbassert.h>
17 : #include <kdbease.h>
18 : #include <kdberrors.h>
19 : #include <kdbinternal.h>
20 : #include <kdbinvoke.h>
21 : #include <kdbmodule.h>
22 : #include <kdbos.h>
23 : #include <stdio.h>
24 : #include <stdlib.h>
25 : #include <string.h>
26 :
27 :
28 : typedef enum
29 : {
30 : preGetStorage = 0,
31 : procGetStorage,
32 : postGetStorage,
33 : postGetCleanup,
34 : getEnd
35 : } GetPlacements;
36 :
37 : static const char * getStrings[] = { "pregetstorage", "procgetstorage", "postgetstorage", "postgetcleanup" };
38 :
39 : typedef enum
40 : {
41 : preSetStorage = 0,
42 : preSetCleanup,
43 : preCommit,
44 : postCommit,
45 : setEnd
46 : } SetPlacements;
47 :
48 : static const char * setStrings[] = { "presetstorage", "presetcleanup", "precommit", "postcommit" };
49 :
50 : typedef enum
51 : {
52 : preRollback = 0,
53 : postRollback,
54 : errEnd
55 : } ErrPlacements;
56 :
57 : static const char * errStrings[] = { "prerollback", "postrollback" };
58 :
59 : typedef enum
60 : {
61 : GET,
62 : SET,
63 : ERR
64 : } OP;
65 :
66 : typedef struct
67 : {
68 : // keep track of placements
69 : ErrPlacements errCurrent;
70 : SetPlacements setCurrent;
71 : GetPlacements getCurrent;
72 :
73 : ErrPlacements errPlacements[2]; // prerollback and postrollback
74 : SetPlacements setPlacements[4]; // presetstorage, presetcleanup, precommit and postcommit
75 : GetPlacements getPlacements[4]; // pregetstorage, procgetstorage, postgetstorage, postgetclenaup
76 :
77 : // each keyset contains the list of plugin names for a given placement
78 : KeySet * setKS[4];
79 : KeySet * errKS[2];
80 : KeySet * getKS[4];
81 : KeySet * plugins;
82 : KeySet * modules;
83 :
84 : ElektraDeferredCallList * deferredCalls;
85 :
86 : } Placements;
87 :
88 : static char lastIndex[ELEKTRA_MAX_ARRAY_SIZE];
89 :
90 21130 : static int listParseConfiguration (Placements * placements, KeySet * config)
91 : {
92 : Key * cur;
93 21130 : Key * key = ksLookupByName (config, "/plugins", 0);
94 21130 : KeySet * cutKS = ksCut (config, key);
95 21130 : ksRewind (cutKS);
96 21130 : if (ksGetSize (cutKS) < 2)
97 : {
98 10549 : ksDel (cutKS);
99 10549 : return 0;
100 : }
101 : int rc = 0;
102 42582 : while ((cur = ksNext (cutKS)) != NULL)
103 : {
104 32001 : if (keyRel (key, cur) != 1)
105 : {
106 21354 : continue;
107 : }
108 10647 : if (keyBaseName (cur)[0] == '#')
109 : {
110 10647 : if (strcmp (lastIndex, keyBaseName (cur)) < 0)
111 : {
112 3680 : snprintf (lastIndex, ELEKTRA_MAX_ARRAY_SIZE, "%s", keyBaseName (cur));
113 : }
114 : }
115 : Key * sub;
116 10647 : Key * lookup = keyDup (cur);
117 10647 : keyAddBaseName (lookup, "placements");
118 10647 : keyAddBaseName (lookup, "set");
119 10647 : sub = ksLookup (cutKS, lookup, 0);
120 10647 : if (sub)
121 : {
122 10647 : const char * setString = keyString (sub);
123 10647 : SetPlacements setPlacement = preSetStorage;
124 63882 : while (setPlacement != setEnd)
125 : {
126 42588 : if (strstr (setString, setStrings[setPlacement]))
127 : {
128 10617 : rc = 1;
129 10617 : ksAppendKey (placements->setKS[setPlacement], keyDup (cur));
130 : }
131 42588 : ++setPlacement;
132 : }
133 : }
134 10647 : keySetBaseName (lookup, "get");
135 10647 : sub = ksLookup (cutKS, lookup, 0);
136 10647 : if (sub)
137 : {
138 10647 : const char * getString = keyString (sub);
139 10647 : GetPlacements getPlacement = preGetStorage;
140 63882 : while (getPlacement != getEnd)
141 : {
142 42588 : if (strstr (getString, getStrings[getPlacement]))
143 : {
144 10655 : rc = 1;
145 10655 : ksAppendKey (placements->getKS[getPlacement], keyDup (cur));
146 : }
147 42588 : ++getPlacement;
148 : }
149 : }
150 10647 : keySetBaseName (lookup, "error");
151 10647 : sub = ksLookup (cutKS, lookup, 0);
152 10647 : if (sub)
153 : {
154 126 : const char * errString = keyString (sub);
155 126 : ErrPlacements errPlacement = preRollback;
156 504 : while (errPlacement != errEnd)
157 : {
158 252 : if (strstr (errString, errStrings[errPlacement]))
159 : {
160 12 : rc = 1;
161 12 : ksAppendKey (placements->errKS[errPlacement], keyDup (cur));
162 : }
163 252 : ++errPlacement;
164 : }
165 : }
166 10647 : keyDel (lookup);
167 : }
168 10581 : ksDel (cutKS);
169 10581 : return rc;
170 : }
171 :
172 160 : void elektraListDeferredCall (Plugin * plugin, const char * name, KeySet * parameters)
173 : {
174 160 : Placements * placements = elektraPluginGetData (plugin);
175 160 : ELEKTRA_NOT_NULL (placements);
176 160 : elektraDeferredCallAdd (placements->deferredCalls, name, parameters);
177 :
178 : // Execute call immediately on already loaded plugins
179 160 : ksRewind (placements->plugins);
180 : Key * current;
181 400 : while ((current = ksNext (placements->plugins)) != NULL)
182 : {
183 : Plugin * slave;
184 80 : slave = *(Plugin **) keyValue (current);
185 80 : elektraDeferredCallsExecute (slave, placements->deferredCalls);
186 : }
187 160 : }
188 :
189 21130 : int elektraListOpen (Plugin * handle, Key * errorKey ELEKTRA_UNUSED)
190 : {
191 :
192 21130 : Placements * placements = (Placements *) elektraPluginGetData (handle);
193 21130 : if (!placements)
194 : {
195 21064 : placements = (Placements *) elektraMalloc (sizeof (Placements));
196 21064 : memset (placements, 0, sizeof (Placements));
197 21064 : placements->errCurrent = preRollback;
198 21064 : placements->setCurrent = preSetStorage;
199 21064 : placements->getCurrent = preGetStorage;
200 21064 : placements->getKS[0] = ksNew (0, KS_END);
201 21064 : placements->getKS[1] = ksNew (0, KS_END);
202 21064 : placements->getKS[2] = ksNew (0, KS_END);
203 21064 : placements->setKS[0] = ksNew (0, KS_END);
204 21064 : placements->setKS[1] = ksNew (0, KS_END);
205 21064 : placements->setKS[2] = ksNew (0, KS_END);
206 21064 : placements->setKS[3] = ksNew (0, KS_END);
207 21064 : placements->errKS[0] = ksNew (0, KS_END);
208 21064 : placements->errKS[1] = ksNew (0, KS_END);
209 21064 : placements->plugins = ksNew (0, KS_END);
210 21064 : placements->modules = ksNew (0, KS_END);
211 21064 : placements->deferredCalls = elektraDeferredCallCreateList ();
212 : }
213 21130 : elektraPluginSetData (handle, placements);
214 :
215 21130 : elektraModulesInit (placements->modules, NULL);
216 21130 : KeySet * config = ksDup (elektraPluginGetConfig (handle));
217 21130 : ksRewind (config);
218 21130 : Key * key = ksLookupByName (config, "/placements/set", 0);
219 21130 : if (key)
220 : {
221 10591 : const char * setString = keyString (key);
222 10591 : SetPlacements setPlacement = preSetStorage;
223 63546 : while (setPlacement != setEnd)
224 : {
225 42364 : if (strstr (setString, setStrings[setPlacement]))
226 : {
227 31769 : placements->setPlacements[setPlacement] = 1;
228 : }
229 42364 : ++setPlacement;
230 : }
231 : }
232 21130 : key = ksLookupByName (config, "/placements/get", 0);
233 21130 : if (key)
234 : {
235 10591 : const char * getString = keyString (key);
236 10591 : GetPlacements getPlacement = preGetStorage;
237 63546 : while (getPlacement != getEnd)
238 : {
239 42364 : if (strstr (getString, getStrings[getPlacement]))
240 : {
241 31731 : placements->getPlacements[getPlacement] = 1;
242 : }
243 42364 : ++getPlacement;
244 : }
245 : }
246 21130 : key = ksLookupByName (config, "/placements/error", 0);
247 21130 : if (key)
248 : {
249 10589 : const char * errString = keyString (key);
250 10589 : ErrPlacements errPlacement = preRollback;
251 42356 : while (errPlacement != errEnd)
252 : {
253 21178 : if (strstr (errString, errStrings[errPlacement]))
254 : {
255 21178 : placements->errPlacements[errPlacement] = 1;
256 : }
257 21178 : ++errPlacement;
258 : }
259 : }
260 21130 : listParseConfiguration (placements, config);
261 21130 : ksDel (config);
262 21130 : return 1; /* success */
263 : }
264 :
265 21064 : int elektraListClose (Plugin * handle, Key * errorKey)
266 : {
267 : /* free all plugin resources and shut it down */
268 21064 : Placements * placements = elektraPluginGetData (handle);
269 21064 : ksDel (placements->getKS[0]);
270 21064 : ksDel (placements->getKS[1]);
271 21064 : ksDel (placements->getKS[2]);
272 21064 : ksDel (placements->setKS[0]);
273 21064 : ksDel (placements->setKS[1]);
274 21064 : ksDel (placements->setKS[2]);
275 21064 : ksDel (placements->setKS[3]);
276 21064 : ksDel (placements->errKS[0]);
277 21064 : ksDel (placements->errKS[1]);
278 : Key * cur;
279 21064 : ksRewind (placements->plugins);
280 47630 : while ((cur = ksNext (placements->plugins)) != NULL)
281 : {
282 : Plugin * slave;
283 5502 : slave = *(Plugin **) keyValue (cur);
284 5502 : elektraPluginClose (slave, errorKey);
285 : }
286 21064 : ksDel (placements->plugins);
287 21064 : elektraModulesClose (placements->modules, NULL);
288 21064 : ksDel (placements->modules);
289 21064 : elektraDeferredCallDeleteList (placements->deferredCalls);
290 21064 : elektraFree (placements);
291 21064 : elektraPluginSetData (handle, 0);
292 21064 : return 1; /* success */
293 : }
294 :
295 23663 : static int runPlugins (KeySet * pluginKS, KeySet * modules, KeySet * plugins, KeySet * configOrig, KeySet * returned, KeySet * global,
296 : Key * parentKey, OP op, Key * (*traversalFunction) (KeySet *), ElektraDeferredCallList * deferredCalls)
297 : {
298 : Key * current;
299 :
300 23663 : Plugin * slave = NULL;
301 :
302 : // for every plugin in our list: load it, run the expected function (set/get/error) and close it again
303 23663 : KeySet * realPluginConfig = NULL;
304 55326 : while ((current = traversalFunction (pluginKS)) != NULL)
305 : {
306 8003 : const char * name = keyString (current);
307 :
308 8003 : Key * handleKey = keyDup (current);
309 8003 : keyAddName (handleKey, "handle");
310 8003 : Key * handleLookup = ksLookup (configOrig, handleKey, 0);
311 8003 : keyDel (handleKey);
312 8003 : if (handleLookup)
313 : {
314 0 : slave = *(Plugin **) keyValue (handleLookup);
315 : }
316 : else
317 : {
318 8003 : Key * searchKey = keyNew ("/", KEY_END);
319 8003 : keyAddBaseName (searchKey, name);
320 8003 : Key * lookup = ksLookup (plugins, searchKey, 0);
321 8003 : keyDel (searchKey);
322 8003 : if (lookup)
323 : {
324 2511 : slave = *(Plugin **) keyValue (lookup);
325 : }
326 : else
327 : {
328 5492 : Key * userCutPoint = keyNew ("user", 0);
329 5492 : Key * globalConfCutPoint = keyNew ("/config", 0);
330 5492 : KeySet * config = ksDup (configOrig);
331 5492 : KeySet * globalConfigAll = ksCut (config, globalConfCutPoint);
332 5492 : KeySet * userConfigAll = ksCut (config, userCutPoint);
333 5492 : KeySet * pluginConfig = ksCut (userConfigAll, current);
334 : // replace "user/plugins/#X" with "user/"
335 5492 : KeySet * pluginConfigWithConfigPrefix = elektraRenameKeys (pluginConfig, "user");
336 5492 : ksDel (pluginConfig);
337 : // append config below "/config" to all plugins
338 5492 : KeySet * globalPluginConfig = elektraRenameKeys (globalConfigAll, "user/config");
339 5492 : ksAppend (pluginConfigWithConfigPrefix, globalPluginConfig);
340 5492 : ksDel (globalPluginConfig);
341 : // remove "placements" from plugin config
342 5492 : Key * toRemove = keyNew ("user/placements", 0);
343 5492 : ksDel (ksCut (pluginConfigWithConfigPrefix, toRemove));
344 5492 : ksRewind (pluginConfigWithConfigPrefix);
345 5492 : ksDel (globalConfigAll);
346 5492 : ksDel (userConfigAll);
347 5492 : ksDel (config);
348 5492 : keyDel (userCutPoint);
349 5492 : keyDel (globalConfCutPoint);
350 5492 : keyDel (toRemove);
351 : // replace "user/config/" with "user/"
352 5492 : realPluginConfig = elektraRenameKeys (pluginConfigWithConfigPrefix, "user");
353 5492 : ksDel (pluginConfigWithConfigPrefix);
354 5492 : slave = elektraPluginOpen (name, modules, ksDup (realPluginConfig), parentKey);
355 5492 : ksDel (realPluginConfig);
356 5492 : if (!slave)
357 : {
358 0 : ksDel (configOrig);
359 0 : return -1;
360 : }
361 5492 : slave->global = global;
362 5492 : Key * slaveKey = keyNew (name, KEY_BINARY, KEY_SIZE, sizeof (Plugin *), KEY_VALUE, &slave, KEY_END);
363 5492 : keySetName (slaveKey, "/");
364 5492 : keyAddBaseName (slaveKey, name);
365 5492 : ksAppendKey (plugins, keyDup (slaveKey));
366 5492 : keyDel (slaveKey);
367 : }
368 : }
369 8003 : elektraDeferredCallsExecute (slave, deferredCalls);
370 :
371 8003 : if ((op == GET && slave->kdbGet && (slave->kdbGet (slave, returned, parentKey)) == -1) ||
372 2724 : (op == SET && slave->kdbSet && (slave->kdbSet (slave, returned, parentKey)) == -1) ||
373 0 : (op == ERR && slave->kdbError && (slave->kdbError (slave, returned, parentKey)) == -1))
374 : {
375 3 : ksDel (configOrig);
376 3 : return -1;
377 : }
378 : }
379 23660 : ksDel (configOrig);
380 23660 : return 1;
381 : }
382 :
383 16275 : int elektraListGet (Plugin * handle, KeySet * returned, Key * parentKey)
384 : {
385 16275 : if (!strcmp (keyName (parentKey), "system/elektra/modules/list"))
386 : {
387 614 : KeySet * contract =
388 614 : ksNew (30, keyNew ("system/elektra/modules/list", KEY_VALUE, "list plugin waits for your orders", KEY_END),
389 : keyNew ("system/elektra/modules/list/exports", KEY_END),
390 : keyNew ("system/elektra/modules/list/exports/open", KEY_FUNC, elektraListOpen, KEY_END),
391 : keyNew ("system/elektra/modules/list/exports/close", KEY_FUNC, elektraListClose, KEY_END),
392 : keyNew ("system/elektra/modules/list/exports/get", KEY_FUNC, elektraListGet, KEY_END),
393 : keyNew ("system/elektra/modules/list/exports/set", KEY_FUNC, elektraListSet, KEY_END),
394 : keyNew ("system/elektra/modules/list/exports/error", KEY_FUNC, elektraListError, KEY_END),
395 : keyNew ("system/elektra/modules/list/exports/addPlugin", KEY_FUNC, elektraListAddPlugin, KEY_END),
396 : keyNew ("system/elektra/modules/list/exports/editPlugin", KEY_FUNC, elektraListEditPlugin, KEY_END),
397 : keyNew ("system/elektra/modules/list/exports/deferredCall", KEY_FUNC, elektraListDeferredCall, KEY_END),
398 : keyNew ("system/elektra/modules/list/exports/mountplugin", KEY_FUNC, elektraListMountPlugin, KEY_END),
399 : keyNew ("system/elektra/modules/list/exports/unmountplugin", KEY_FUNC, elektraListUnmountPlugin, KEY_END),
400 : keyNew ("system/elektra/modules/list/exports/findplugin", KEY_FUNC, elektraListFindPlugin, KEY_END),
401 : #include ELEKTRA_README
402 : keyNew ("system/elektra/modules/list/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END);
403 614 : ksAppend (returned, contract);
404 614 : ksDel (contract);
405 :
406 614 : return 1;
407 : }
408 15661 : Placements * placements = elektraPluginGetData (handle);
409 15661 : KeySet * config = elektraPluginGetConfig (handle);
410 15661 : GetPlacements currentPlacement = placements->getCurrent;
411 15661 : KeySet * pluginKS = ksDup ((placements)->getKS[currentPlacement]);
412 15661 : ksRewind (pluginKS);
413 15661 : int ret = runPlugins (pluginKS, placements->modules, placements->plugins, ksDup (config), returned,
414 : elektraPluginGetGlobalKeySet (handle), parentKey, GET, ksNext, placements->deferredCalls);
415 15661 : placements->getCurrent = ((++currentPlacement) % getEnd);
416 36582 : while (currentPlacement < getEnd && !placements->getPlacements[currentPlacement])
417 : {
418 5260 : placements->getCurrent = ((++currentPlacement) % getEnd);
419 : }
420 15661 : ksDel (pluginKS);
421 15661 : return ret;
422 : }
423 :
424 7810 : int elektraListSet (Plugin * handle, KeySet * returned, Key * parentKey)
425 : {
426 7810 : Placements * placements = elektraPluginGetData (handle);
427 7810 : KeySet * config = elektraPluginGetConfig (handle);
428 7810 : SetPlacements currentPlacement = placements->setCurrent;
429 7810 : KeySet * pluginKS = ksDup ((placements)->setKS[currentPlacement]);
430 7810 : ksRewind (pluginKS);
431 7810 : int ret = 0;
432 7810 : ret = runPlugins (pluginKS, placements->modules, placements->plugins, ksDup (config), returned,
433 : elektraPluginGetGlobalKeySet (handle), parentKey, SET, ksPop, placements->deferredCalls);
434 7810 : placements->setCurrent = ((++currentPlacement) % setEnd);
435 18340 : while (currentPlacement < setEnd && !placements->setPlacements[currentPlacement])
436 : {
437 2720 : placements->setCurrent = ((++currentPlacement) % setEnd);
438 : }
439 7810 : elektraPluginSetData (handle, placements);
440 7810 : ksDel (pluginKS);
441 :
442 7810 : return ret;
443 : }
444 :
445 192 : int elektraListError (Plugin * handle, KeySet * returned, Key * parentKey)
446 : {
447 192 : Placements * placements = elektraPluginGetData (handle);
448 192 : KeySet * config = elektraPluginGetConfig (handle);
449 192 : ErrPlacements currentPlacement = placements->errCurrent;
450 192 : KeySet * pluginKS = ksDup ((placements)->errKS[currentPlacement]);
451 192 : ksRewind (pluginKS);
452 192 : int ret = runPlugins (pluginKS, placements->modules, placements->plugins, ksDup (config), returned,
453 : elektraPluginGetGlobalKeySet (handle), parentKey, ERR, ksPop, placements->deferredCalls);
454 192 : placements->errCurrent = ((++currentPlacement) % errEnd);
455 384 : while (currentPlacement < errEnd && !placements->errPlacements[currentPlacement])
456 : {
457 0 : placements->errCurrent = ((++currentPlacement) % errEnd);
458 : }
459 192 : ksDel (pluginKS);
460 192 : return ret;
461 : }
462 :
463 0 : int elektraListAddPlugin (Plugin * handle, KeySet * pluginConfig)
464 : {
465 0 : if (!pluginConfig)
466 : {
467 : return 0;
468 : }
469 0 : ksRewind (pluginConfig);
470 0 : ksNext (pluginConfig);
471 0 : Key * lookup = ksNext (pluginConfig);
472 0 : if (keyBaseName (lookup)[0] != '#')
473 : {
474 : return -1;
475 : }
476 : else
477 : {
478 0 : if (strcmp (lastIndex, keyBaseName (lookup)) >= 0)
479 : {
480 : return -1;
481 : }
482 : }
483 0 : Placements * placements = elektraPluginGetData (handle);
484 0 : KeySet * conf = ksDup (pluginConfig);
485 0 : ksRewind (conf);
486 0 : int rc = listParseConfiguration (placements, conf);
487 0 : ksDel (conf);
488 0 : return rc;
489 : }
490 :
491 40 : static char * getPluginPlacementList (Plugin * plugin)
492 : {
493 40 : ELEKTRA_NOT_NULL (plugin);
494 :
495 : // Get placements from plugin
496 40 : Key * pluginInfo = keyNew ("system/elektra/modules/", KEY_END);
497 40 : keyAddBaseName (pluginInfo, plugin->name);
498 40 : KeySet * ksResult = ksNew (0, KS_END);
499 40 : plugin->kdbGet (plugin, ksResult, pluginInfo);
500 :
501 40 : Key * placementsKey = keyDup (pluginInfo);
502 40 : keyAddBaseName (placementsKey, "infos");
503 40 : keyAddBaseName (placementsKey, "placements");
504 40 : Key * placements = ksLookup (ksResult, placementsKey, 0);
505 40 : if (placements == NULL)
506 : {
507 : ELEKTRA_LOG_WARNING ("could not read placements from plugin");
508 : return 0;
509 : }
510 40 : char * placementList = elektraStrDup (keyString (placements));
511 :
512 40 : keyDel (pluginInfo);
513 40 : keyDel (placementsKey);
514 40 : ksDel (ksResult);
515 :
516 40 : return placementList;
517 : }
518 :
519 40 : static char * extractGetPlacements (const char * placementList)
520 : {
521 40 : char * result = elektraMalloc (strlen (placementList) + 1);
522 40 : result[0] = '\0';
523 40 : char * resultPos = result;
524 40 : const char * last = placementList;
525 40 : const char * placement = strchr (last, ' ');
526 118 : while (placement != NULL)
527 : {
528 38 : size_t len = placement - last;
529 76 : if (strncasecmp (last, GlobalpluginPositionsStr[GETRESOLVER], len) == 0 ||
530 74 : strncasecmp (last, GlobalpluginPositionsStr[PREGETSTORAGE], len) == 0 ||
531 72 : strncasecmp (last, GlobalpluginPositionsStr[GETSTORAGE], len) == 0 ||
532 70 : strncasecmp (last, GlobalpluginPositionsStr[PROCGETSTORAGE], len) == 0 ||
533 42 : strncasecmp (last, GlobalpluginPositionsStr[POSTGETSTORAGE], len) == 0 ||
534 8 : strncasecmp (last, GlobalpluginPositionsStr[POSTGETCLEANUP], len) == 0)
535 : {
536 30 : strncpy (resultPos, last, len);
537 30 : resultPos[len] = ' ';
538 30 : resultPos += len + 1;
539 : }
540 :
541 38 : last = placement + 1;
542 38 : placement = strchr (last, ' ');
543 : }
544 :
545 80 : if (strcasecmp (last, GlobalpluginPositionsStr[GETRESOLVER]) == 0 ||
546 80 : strcasecmp (last, GlobalpluginPositionsStr[PREGETSTORAGE]) == 0 ||
547 80 : strcasecmp (last, GlobalpluginPositionsStr[GETSTORAGE]) == 0 ||
548 66 : strcasecmp (last, GlobalpluginPositionsStr[PROCGETSTORAGE]) == 0 ||
549 52 : strcasecmp (last, GlobalpluginPositionsStr[POSTGETSTORAGE]) == 0 ||
550 26 : strcasecmp (last, GlobalpluginPositionsStr[POSTGETCLEANUP]) == 0)
551 : {
552 14 : strcpy (resultPos, last);
553 14 : resultPos += strlen (last);
554 : }
555 :
556 40 : *resultPos = '\0';
557 40 : return result;
558 : }
559 :
560 40 : static char * extractSetPlacements (const char * placementList)
561 : {
562 40 : char * result = elektraMalloc (strlen (placementList) + 1);
563 40 : result[0] = '\0';
564 40 : char * resultPos = result;
565 40 : const char * last = placementList;
566 40 : const char * placement = strchr (last, ' ');
567 118 : while (placement != NULL)
568 : {
569 38 : size_t len = placement - last;
570 76 : if (strncasecmp (last, GlobalpluginPositionsStr[SETRESOLVER], len) == 0 ||
571 74 : strncasecmp (last, GlobalpluginPositionsStr[PRESETSTORAGE], len) == 0 ||
572 72 : strncasecmp (last, GlobalpluginPositionsStr[SETSTORAGE], len) == 0 ||
573 72 : strncasecmp (last, GlobalpluginPositionsStr[PRESETCLEANUP], len) == 0 ||
574 70 : strncasecmp (last, GlobalpluginPositionsStr[PRECOMMIT], len) == 0 ||
575 68 : strncasecmp (last, GlobalpluginPositionsStr[COMMIT], len) == 0 ||
576 34 : strncasecmp (last, GlobalpluginPositionsStr[POSTCOMMIT], len) == 0)
577 : {
578 6 : strncpy (resultPos, last, len);
579 6 : resultPos[len] = ' ';
580 6 : resultPos += len + 1;
581 : }
582 :
583 38 : last = placement + 1;
584 38 : placement = strchr (last, ' ');
585 : }
586 :
587 80 : if (strcasecmp (last, GlobalpluginPositionsStr[SETRESOLVER]) == 0 ||
588 64 : strcasecmp (last, GlobalpluginPositionsStr[PRESETSTORAGE]) == 0 ||
589 48 : strcasecmp (last, GlobalpluginPositionsStr[SETSTORAGE]) == 0 ||
590 48 : strcasecmp (last, GlobalpluginPositionsStr[PRESETCLEANUP]) == 0 ||
591 72 : strcasecmp (last, GlobalpluginPositionsStr[PRECOMMIT]) == 0 || strcasecmp (last, GlobalpluginPositionsStr[COMMIT]) == 0 ||
592 24 : strcasecmp (last, GlobalpluginPositionsStr[POSTCOMMIT]) == 0)
593 : {
594 24 : strcpy (resultPos, last);
595 24 : resultPos += strlen (last);
596 : }
597 :
598 40 : *resultPos = '\0';
599 40 : return result;
600 : }
601 :
602 40 : static char * extractErrorPlacements (const char * placementList)
603 : {
604 40 : char * result = elektraMalloc (strlen (placementList) + 1);
605 40 : result[0] = '\0';
606 40 : char * resultPos = result;
607 40 : const char * last = placementList;
608 40 : const char * placement = strchr (last, ' ');
609 118 : while (placement != NULL)
610 : {
611 38 : size_t len = placement - last;
612 74 : if (strncasecmp (last, GlobalpluginPositionsStr[PREROLLBACK], len) == 0 ||
613 72 : strncasecmp (last, GlobalpluginPositionsStr[ROLLBACK], len) == 0 ||
614 36 : strncasecmp (last, GlobalpluginPositionsStr[POSTROLLBACK], len) == 0)
615 : {
616 2 : strncpy (resultPos, last, len);
617 2 : resultPos[len] = ' ';
618 2 : resultPos += len + 1;
619 : }
620 :
621 38 : last = placement + 1;
622 38 : placement = strchr (last, ' ');
623 : }
624 :
625 80 : if (strcasecmp (last, GlobalpluginPositionsStr[PREROLLBACK]) == 0 || strcasecmp (last, GlobalpluginPositionsStr[ROLLBACK]) == 0 ||
626 40 : strcasecmp (last, GlobalpluginPositionsStr[POSTROLLBACK]) == 0)
627 : {
628 2 : strcpy (resultPos, last);
629 2 : resultPos += strlen (last);
630 : }
631 :
632 40 : *resultPos = '\0';
633 40 : return result;
634 : }
635 :
636 70 : static Key * findPluginInConfig (KeySet * config, const char * pluginName)
637 : {
638 70 : Key * configBase = keyNew ("user/plugins", KEY_END);
639 70 : KeySet * array = elektraArrayGet (configBase, config);
640 :
641 70 : ksRewind (array);
642 70 : Key * cur = NULL;
643 70 : while ((cur = ksNext (array)) != NULL)
644 : {
645 76 : if (strcmp (keyString (cur), pluginName) == 0)
646 : {
647 : // found plugin
648 28 : Key * result = keyDup (cur);
649 28 : keyDel (configBase);
650 28 : ksDel (array);
651 28 : return result;
652 : }
653 : }
654 :
655 42 : keyDel (configBase);
656 42 : ksDel (array);
657 42 : return NULL;
658 : }
659 :
660 66 : static void resetPlugins (Plugin * handle, Key * errorKey)
661 : {
662 66 : Placements * placements = elektraPluginGetData (handle);
663 66 : ksClear (placements->getKS[0]);
664 66 : ksClear (placements->getKS[1]);
665 66 : ksClear (placements->getKS[2]);
666 66 : ksClear (placements->setKS[0]);
667 66 : ksClear (placements->setKS[1]);
668 66 : ksClear (placements->setKS[2]);
669 66 : ksClear (placements->setKS[3]);
670 66 : ksClear (placements->errKS[0]);
671 66 : ksClear (placements->errKS[1]);
672 : Key * cur;
673 66 : ksRewind (placements->plugins);
674 152 : while ((cur = ksNext (placements->plugins)) != NULL)
675 : {
676 : Plugin * slave;
677 20 : slave = *(Plugin **) keyValue (cur);
678 20 : elektraPluginClose (slave, errorKey);
679 : }
680 66 : ksClear (placements->plugins);
681 66 : }
682 :
683 : /**
684 : * Adds a plugin in all the intended positions (given in its infos/placements key).
685 : * If the plugin is already added, effectively equivalent to calling ksDel() on pluginConfig.
686 : *
687 : * @param handle A handle of the list plugin
688 : * @param pluginName The plugin to add
689 : * @param pluginConfig The config for the plugin, if it has to be mounted; the KeySet is consumed,
690 : * don't call ksDel() on it afterwards.
691 : * @param errorKey Used for error reporting
692 : *
693 : * @retval #ELEKTRA_PLUGIN_STATUS_SUCCESS if the plugin was added
694 : * @retval #ELEKTRA_PLUGIN_STATUS_NO_UPDATE if the plugin was added already
695 : * @retval #ELEKTRA_PLUGIN_STATUS_ERROR on NULL pointers and other errors
696 : */
697 42 : int elektraListMountPlugin (Plugin * handle, const char * pluginName, KeySet * pluginConfig, Key * errorKey)
698 : {
699 42 : if (handle == NULL || pluginName == NULL || pluginConfig == NULL)
700 : {
701 : return ELEKTRA_PLUGIN_STATUS_ERROR;
702 : }
703 :
704 42 : Placements * placements = elektraPluginGetData (handle);
705 42 : KeySet * config = elektraPluginGetConfig (handle);
706 :
707 : // check if plugin already added
708 42 : Key * pluginKey = findPluginInConfig (config, pluginName);
709 42 : if (pluginKey != NULL)
710 : {
711 2 : keyDel (pluginKey);
712 2 : ksDel (pluginConfig); // consume config
713 2 : return ELEKTRA_PLUGIN_STATUS_NO_UPDATE;
714 : }
715 :
716 : // Find name for next item in plugins array
717 40 : Key * configBase = keyNew ("user/plugins", KEY_END);
718 40 : KeySet * array = elektraArrayGet (configBase, config);
719 40 : Key * pluginItem = elektraArrayGetNextKey (array);
720 :
721 40 : if (pluginItem == NULL)
722 : {
723 2 : pluginItem = keyNew ("user/plugins/#0", KEY_END);
724 : }
725 :
726 40 : keySetString (pluginItem, pluginName);
727 :
728 40 : keyDel (configBase);
729 40 : ksDel (array);
730 :
731 40 : Plugin * plugin = elektraPluginOpen (pluginName, placements->modules, pluginConfig, errorKey);
732 :
733 40 : if (plugin == NULL)
734 : {
735 0 : keyDel (pluginItem);
736 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
737 : }
738 :
739 : // Store key with plugin handle
740 40 : Key * searchKey = keyNew ("/", KEY_END);
741 40 : keyAddBaseName (searchKey, pluginName);
742 40 : keySetBinary (searchKey, &plugin, sizeof (plugin));
743 :
744 : // Find plugin placements
745 40 : char * placementList = getPluginPlacementList (plugin);
746 :
747 40 : Key * pluginPlacements = keyDup (pluginItem);
748 40 : keyAddBaseName (pluginPlacements, "placements");
749 :
750 : // Append keys to list plugin configuration
751 40 : ksAppendKey (config, pluginItem);
752 40 : ksAppendKey (config, pluginPlacements);
753 :
754 : // Add get placements
755 40 : char * getPlacementsString = extractGetPlacements (placementList);
756 40 : if (getPlacementsString != NULL)
757 : {
758 40 : Key * getPlacements = keyDup (pluginPlacements);
759 40 : keyAddBaseName (getPlacements, "get");
760 40 : keySetString (getPlacements, getPlacementsString);
761 40 : ksAppendKey (config, getPlacements);
762 : }
763 40 : elektraFree (getPlacementsString);
764 :
765 :
766 : // Add set placements
767 40 : char * setPlacementsString = extractSetPlacements (placementList);
768 40 : if (setPlacementsString != NULL)
769 : {
770 40 : Key * setPlacements = keyDup (pluginPlacements);
771 40 : keyAddBaseName (setPlacements, "set");
772 40 : keySetString (setPlacements, setPlacementsString);
773 40 : ksAppendKey (config, setPlacements);
774 : }
775 40 : elektraFree (setPlacementsString);
776 :
777 : // Add error placements
778 40 : char * errorPlacementsString = extractErrorPlacements (placementList);
779 40 : if (errorPlacementsString != NULL)
780 : {
781 40 : Key * errorPlacements = keyDup (pluginPlacements);
782 40 : keyAddBaseName (errorPlacements, "error");
783 40 : keySetString (errorPlacements, errorPlacementsString);
784 40 : ksAppendKey (config, errorPlacements);
785 : }
786 40 : elektraFree (errorPlacementsString);
787 40 : elektraFree (placementList);
788 :
789 : // reload configuration
790 40 : resetPlugins (handle, errorKey);
791 :
792 : // store new handle
793 40 : ksAppendKey (placements->plugins, searchKey);
794 40 : return elektraListOpen (handle, errorKey);
795 : }
796 :
797 : /**
798 : * Removes a plugin from all the intended positions (given in its infos/placements key).
799 : * If the plugin isn't present, nothing happens.
800 : *
801 : * @param handle A handle of the list plugin
802 : * @param pluginName The plugin to remove
803 : * @param errorKey Used for error reporting
804 : *
805 : * @retval #ELEKTRA_PLUGIN_STATUS_SUCCESS if the plugin was added
806 : * @retval #ELEKTRA_PLUGIN_STATUS_NO_UPDATE if the plugin was added already
807 : * @retval #ELEKTRA_PLUGIN_STATUS_ERROR on NULL pointers and other errors
808 : */
809 28 : int elektraListUnmountPlugin (Plugin * handle, const char * pluginName, Key * errorKey)
810 : {
811 28 : if (handle == NULL || pluginName == NULL)
812 : {
813 : return ELEKTRA_PLUGIN_STATUS_ERROR;
814 : }
815 :
816 28 : Placements * placements = elektraPluginGetData (handle);
817 28 : KeySet * config = elektraPluginGetConfig (handle);
818 :
819 : // Find plugin
820 28 : Key * pluginItem = findPluginInConfig (config, pluginName);
821 28 : if (pluginItem == NULL)
822 : {
823 : return ELEKTRA_PLUGIN_STATUS_NO_UPDATE;
824 : }
825 :
826 : // Look for plugin via handle
827 26 : Key * pluginHandle = keyDup (pluginItem);
828 26 : keyAddName (pluginHandle, "handle");
829 26 : pluginHandle = ksLookup (config, pluginHandle, KDB_O_DEL);
830 :
831 : // unload plugin if loaded via handle
832 26 : if (pluginHandle != NULL)
833 : {
834 0 : elektraPluginClose (*((Plugin **) keyValue (pluginHandle)), errorKey);
835 0 : keyDel (pluginHandle);
836 : }
837 :
838 : // Look for plugin via plugins
839 26 : Key * searchKey = keyNew ("/", KEY_END);
840 26 : keyAddBaseName (searchKey, pluginName);
841 :
842 : // pop if found
843 26 : searchKey = ksLookup (placements->plugins, searchKey, KDB_O_DEL | KDB_O_POP);
844 :
845 : // unload plugin if loaded via plugins
846 26 : if (searchKey != NULL)
847 : {
848 10 : elektraPluginClose (*((Plugin **) keyValue (searchKey)), errorKey);
849 10 : keyDel (searchKey);
850 : }
851 :
852 : // Remove plugin data from config
853 26 : ksDel (ksCut (config, pluginItem));
854 26 : keyDel (pluginItem);
855 :
856 : // reload configuration
857 26 : resetPlugins (handle, errorKey);
858 26 : return elektraListOpen (handle, errorKey);
859 : }
860 :
861 : /**
862 : * Find the handle of plugin.
863 : *
864 : * If elektraListGet(), elektraListSet() and elektraListError()
865 : * haven't been called yet, only plugins added via elektraListMountPlugin()
866 : * will be found. Other plugins aren't opened (and therefore don't have a handle)
867 : * before get/set/error is called.
868 : *
869 : * @param handle A handle of the list plugin
870 : * @param pluginName The name of the plugin to look for
871 : *
872 : * @return the handle for the given plugin, or NULL if not found
873 : * NULL is also returned if @p handle or @p pluginName are NULL
874 : */
875 36 : Plugin * elektraListFindPlugin (Plugin * handle, const char * pluginName)
876 : {
877 36 : if (handle == NULL || pluginName == NULL)
878 : {
879 : return NULL;
880 : }
881 :
882 36 : Placements * placements = elektraPluginGetData (handle);
883 36 : KeySet * config = elektraPluginGetConfig (handle);
884 :
885 36 : Key * searchKey = keyNew ("/", KEY_END);
886 36 : keyAddBaseName (searchKey, pluginName);
887 36 : Key * lookup = ksLookup (placements->plugins, searchKey, KDB_O_DEL);
888 36 : if (lookup)
889 : {
890 22 : return *(Plugin **) keyValue (lookup);
891 : }
892 :
893 :
894 : Key * current;
895 56 : for (int i = 0; i < getEnd; ++i)
896 : {
897 56 : while ((current = ksNext (placements->getKS[i])) != NULL)
898 : {
899 0 : Key * handleKey = keyDup (current);
900 0 : keyAddName (handleKey, "handle");
901 0 : Key * handleLookup = ksLookup (config, handleKey, KDB_O_DEL);
902 0 : if (handleLookup)
903 : {
904 0 : return *(Plugin **) keyValue (handleLookup);
905 : }
906 : }
907 : }
908 :
909 56 : for (int i = 0; i < setEnd; ++i)
910 : {
911 56 : while ((current = ksNext (placements->setKS[i])) != NULL)
912 : {
913 0 : Key * handleKey = keyDup (current);
914 0 : keyAddName (handleKey, "handle");
915 0 : Key * handleLookup = ksLookup (config, handleKey, KDB_O_DEL);
916 0 : if (handleLookup)
917 : {
918 0 : return *(Plugin **) keyValue (handleLookup);
919 : }
920 : }
921 : }
922 :
923 28 : for (int i = 0; i < errEnd; ++i)
924 : {
925 28 : while ((current = ksNext (placements->errKS[i])) != NULL)
926 : {
927 0 : Key * handleKey = keyDup (current);
928 0 : keyAddName (handleKey, "handle");
929 0 : Key * handleLookup = ksLookup (config, handleKey, KDB_O_DEL);
930 0 : if (handleLookup)
931 : {
932 0 : return *(Plugin **) keyValue (handleLookup);
933 : }
934 : }
935 : }
936 :
937 : return NULL;
938 : }
939 :
940 0 : int elektraListEditPlugin (Plugin * handle, KeySet * pluginConfig)
941 : {
942 0 : if (!pluginConfig)
943 : {
944 : return 0;
945 : }
946 0 : ksRewind (pluginConfig);
947 0 : ksNext (pluginConfig);
948 0 : Key * lookup = ksNext (pluginConfig);
949 0 : if (keyBaseName (lookup)[0] != '#')
950 : {
951 : return -1;
952 : }
953 : else
954 : {
955 0 : if (strcmp (lastIndex, keyBaseName (lookup)) < 0)
956 : {
957 : return -1;
958 : }
959 : }
960 0 : Placements * placements = elektraPluginGetData (handle);
961 0 : KeySet * conf = ksDup (pluginConfig);
962 0 : ksRewind (conf);
963 0 : int rc = listParseConfiguration (placements, conf);
964 0 : ksDel (conf);
965 0 : return rc;
966 : }
967 :
968 21064 : Plugin * ELEKTRA_PLUGIN_EXPORT
969 : {
970 : // clang-format off
971 21064 : return elektraPluginExport("list",
972 : ELEKTRA_PLUGIN_OPEN, &elektraListOpen,
973 : ELEKTRA_PLUGIN_CLOSE, &elektraListClose,
974 : ELEKTRA_PLUGIN_GET, &elektraListGet,
975 : ELEKTRA_PLUGIN_SET, &elektraListSet,
976 : ELEKTRA_PLUGIN_ERROR, &elektraListError,
977 : ELEKTRA_PLUGIN_END);
978 : }
|