Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief Implementation of set/get/error plugins
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : *
8 : */
9 :
10 :
11 : #include <helper/keyhelper.hpp>
12 : #include <plugins.hpp>
13 :
14 : #include <kdbprivate.h>
15 :
16 : #include <algorithm>
17 : #include <iterator>
18 :
19 : using namespace std;
20 :
21 : namespace kdb
22 : {
23 :
24 : namespace tools
25 : {
26 :
27 36144 : Plugins::Plugins () : plugins (NR_OF_PLUGINS), nrStoragePlugins (0), nrResolverPlugins (0)
28 : {
29 18072 : placementInfo["prerollback"] = Place (RESOLVER_PLUGIN, STORAGE_PLUGIN - 1);
30 18072 : placementInfo["rollback"] = Place (STORAGE_PLUGIN, STORAGE_PLUGIN);
31 18072 : placementInfo["postrollback"] = Place (STORAGE_PLUGIN + 1, NR_OF_PLUGINS - 1);
32 :
33 18072 : placementInfo["getresolver"] = Place (RESOLVER_PLUGIN, RESOLVER_PLUGIN);
34 18072 : placementInfo["pregetstorage"] = Place (RESOLVER_PLUGIN + 1, STORAGE_PLUGIN - 1);
35 18072 : placementInfo["getstorage"] = Place (STORAGE_PLUGIN, STORAGE_PLUGIN);
36 18072 : placementInfo["postgetstorage"] = Place (STORAGE_PLUGIN + 1, NR_OF_PLUGINS - 1);
37 4518 : revPostGet = NR_OF_PLUGINS - 1;
38 :
39 18072 : placementInfo["setresolver"] = Place (RESOLVER_PLUGIN, RESOLVER_PLUGIN);
40 18072 : placementInfo["presetstorage"] = Place (RESOLVER_PLUGIN + 1, STORAGE_PLUGIN - 1);
41 18072 : placementInfo["setstorage"] = Place (STORAGE_PLUGIN, STORAGE_PLUGIN);
42 18072 : placementInfo["precommit"] = Place (STORAGE_PLUGIN + 1, COMMIT_PLUGIN - 1);
43 18072 : placementInfo["commit"] = Place (COMMIT_PLUGIN, COMMIT_PLUGIN);
44 18072 : placementInfo["postcommit"] = Place (COMMIT_PLUGIN + 1, NR_OF_PLUGINS - 1);
45 4518 : }
46 :
47 2309 : void Plugins::addInfo (Plugin & plugin)
48 : {
49 : {
50 4618 : std::string provide;
51 20781 : std::stringstream ss (plugin.lookupInfo ("provides"));
52 11360 : while (ss >> provide)
53 : {
54 3371 : alreadyProvided.push_back (provide);
55 : }
56 : /* Push back the name of the plugin itself */
57 6927 : alreadyProvided.push_back (plugin.name ());
58 : }
59 :
60 : {
61 4618 : std::string need;
62 20781 : std::stringstream ss (plugin.lookupInfo ("needs"));
63 4868 : while (ss >> need)
64 : {
65 125 : needed.push_back (need);
66 : }
67 : }
68 :
69 : {
70 4618 : std::string recommend;
71 20781 : std::stringstream ss (plugin.lookupInfo ("recommends"));
72 5078 : while (ss >> recommend)
73 : {
74 230 : recommended.push_back (recommend);
75 : }
76 : }
77 :
78 : {
79 4618 : std::string conflict;
80 20781 : std::stringstream ss (plugin.lookupInfo ("conflicts"));
81 4618 : while (ss >> conflict)
82 : {
83 0 : alreadyConflict.push_back (conflict);
84 : }
85 : }
86 2309 : }
87 :
88 30017 : void Plugins::addPlugin (Plugin & plugin, std::string which)
89 : {
90 294583 : if (!plugin.findInfo (which, "placements")) return;
91 :
92 46341 : std::string stacking = plugin.lookupInfo ("stacking");
93 :
94 6119 : if (which == "postgetstorage" && stacking == "")
95 : {
96 470 : plugins[revPostGet--] = &plugin;
97 : return;
98 : }
99 :
100 11174 : plugins[placementInfo[which].current++] = &plugin;
101 : }
102 :
103 : /**
104 : * @brief check if this plugin can be placed in the unfortunately
105 : * limited number of slots
106 : *
107 : * @param plugin the plugin to check
108 : * @param which placementInfo it is
109 : *
110 : * @retval true if it should be added
111 : * @retval false no placements (will not be added)
112 : */
113 30028 : bool Plugins::checkPlacement (Plugin & plugin, std::string which)
114 : {
115 270252 : if (!plugin.findInfo (which, "placements")) return false; // nothing to check, won't be added anyway
116 :
117 40762 : std::string stacking = plugin.lookupInfo ("stacking");
118 :
119 6120 : if (which == "postgetstorage" && stacking == "")
120 : {
121 940 : if (revPostGet >= placementInfo["postgetstorage"].current)
122 : {
123 : return true;
124 : }
125 :
126 0 : std::ostringstream os;
127 : os << "Too many plugins!\n"
128 : "The plugin "
129 0 : << plugin.name () << " can't be positioned at position " << which
130 : << " anymore.\n"
131 : "Try to reduce the number of plugins!\n"
132 : "\n"
133 0 : "Failed because of stack overflow: cant place to "
134 0 : << revPostGet << " because " << placementInfo["postgetstorage"].current << " is larger (this slot is in use)." << endl;
135 0 : throw TooManyPlugins (os.str ());
136 : }
137 :
138 5588 : if (placementInfo[which].current > placementInfo[which].max)
139 : {
140 2 : std::ostringstream os;
141 : os << "Too many plugins!\n"
142 : "The plugin "
143 2 : << plugin.name () << " can't be positioned at position " << which
144 : << " anymore.\n"
145 : "Try to reduce the number of plugins!\n"
146 : "\n"
147 : "Failed because "
148 10 : << which << " with " << placementInfo[which].current << " is larger than " << placementInfo[which].max << endl;
149 3 : throw TooManyPlugins (os.str ());
150 : }
151 :
152 : return true;
153 : }
154 :
155 80 : bool Plugins::validateProvided () const
156 : {
157 160 : return getNeededMissing ().empty ();
158 : }
159 :
160 80 : std::vector<std::string> Plugins::getNeededMissing () const
161 : {
162 80 : std::vector<std::string> ret;
163 324 : for (auto & elem : needed)
164 : {
165 8 : std::string need = elem;
166 20 : if (std::find (alreadyProvided.begin (), alreadyProvided.end (), need) == alreadyProvided.end ())
167 : {
168 2 : ret.push_back (need);
169 : }
170 : }
171 80 : return ret;
172 : }
173 :
174 0 : std::vector<std::string> Plugins::getRecommendedMissing () const
175 : {
176 0 : std::vector<std::string> ret;
177 0 : for (auto & elem : recommended)
178 : {
179 0 : std::string recommend = elem;
180 0 : if (std::find (alreadyProvided.begin (), alreadyProvided.end (), recommend) == alreadyProvided.end ())
181 : {
182 0 : ret.push_back (recommend);
183 : }
184 : }
185 0 : return ret;
186 : }
187 :
188 4064 : void Plugins::checkStorage (Plugin & plugin)
189 : {
190 40640 : if (plugin.findInfo ("storage", "provides"))
191 : {
192 1250 : ++nrStoragePlugins;
193 : }
194 :
195 4064 : if (nrStoragePlugins > 1)
196 : {
197 0 : --nrStoragePlugins;
198 0 : throw StoragePlugin ();
199 : }
200 4064 : }
201 :
202 4925 : void Plugins::checkResolver (Plugin & plugin)
203 : {
204 49250 : if (plugin.findInfo ("resolver", "provides"))
205 : {
206 2523 : ++nrResolverPlugins;
207 : }
208 :
209 :
210 4925 : if (nrResolverPlugins > 1)
211 : {
212 0 : --nrResolverPlugins;
213 0 : throw ResolverPlugin ();
214 : }
215 4925 : }
216 :
217 :
218 : /** Check ordering of plugins.
219 : */
220 2310 : void Plugins::checkOrdering (Plugin & plugin)
221 : {
222 4620 : std::string order;
223 20790 : std::stringstream ss (plugin.lookupInfo ("ordering"));
224 4890 : while (ss >> order)
225 : {
226 : /* Simple look in the already provided names.
227 : * Because both plugin names + provided names are
228 : * there.
229 : * If it is found, we have an ordering violation.
230 : */
231 675 : if (std::find (alreadyProvided.begin (), alreadyProvided.end (), order) != alreadyProvided.end ())
232 : {
233 0 : throw OrderingViolation ();
234 : }
235 : }
236 2310 : }
237 :
238 : /** Check conflicts of plugins.
239 : */
240 2310 : void Plugins::checkConflicts (Plugin & plugin)
241 : {
242 : {
243 4620 : std::string order;
244 20790 : std::stringstream ss (plugin.lookupInfo ("conflicts"));
245 4620 : while (ss >> order)
246 : {
247 : /* Simple look in the already provided names.
248 : * Because both plugin names + provided names are
249 : * there.
250 : * If one is found, we have an conflict.
251 : */
252 0 : if (std::find (alreadyProvided.begin (), alreadyProvided.end (), order) != alreadyProvided.end ())
253 : {
254 0 : throw ConflictViolation ();
255 : }
256 : }
257 : }
258 :
259 : /* Is there a conflict against the name? */
260 13860 : if (std::find (alreadyConflict.begin (), alreadyConflict.end (), plugin.name ()) != alreadyConflict.end ())
261 : {
262 0 : throw ConflictViolation ();
263 : }
264 :
265 : /* Is there a conflict against what it provides? */
266 4620 : std::string order;
267 20790 : std::stringstream ss (plugin.lookupInfo ("provides"));
268 11364 : while (ss >> order)
269 : {
270 16860 : if (std::find (alreadyConflict.begin (), alreadyConflict.end (), order) != alreadyConflict.end ())
271 : {
272 0 : throw ConflictViolation ();
273 : }
274 : }
275 2310 : }
276 :
277 :
278 2310 : void ErrorPlugins::tryPlugin (Plugin & plugin)
279 : {
280 2310 : checkOrdering (plugin);
281 2310 : checkConflicts (plugin);
282 :
283 2310 : bool willBeAdded = false;
284 9240 : willBeAdded |= checkPlacement (plugin, "prerollback");
285 9240 : willBeAdded |= checkPlacement (plugin, "rollback");
286 9240 : willBeAdded |= checkPlacement (plugin, "postrollback");
287 2310 : if (!willBeAdded) return;
288 :
289 3444 : if (!plugin.getSymbol ("error"))
290 : {
291 0 : throw MissingSymbol ("error");
292 : }
293 :
294 861 : checkResolver (plugin);
295 : }
296 :
297 :
298 2310 : void GetPlugins::tryPlugin (Plugin & plugin)
299 : {
300 2310 : bool willBeAdded = false;
301 9240 : willBeAdded |= checkPlacement (plugin, "getresolver");
302 9240 : willBeAdded |= checkPlacement (plugin, "pregetstorage");
303 9240 : willBeAdded |= checkPlacement (plugin, "getstorage");
304 9240 : willBeAdded |= checkPlacement (plugin, "postgetstorage");
305 2310 : if (!willBeAdded) return;
306 :
307 7116 : if (!plugin.getSymbol ("get"))
308 : {
309 0 : throw MissingSymbol ("get");
310 : }
311 :
312 1779 : checkStorage (plugin);
313 1779 : checkResolver (plugin);
314 : }
315 :
316 2310 : void SetPlugins::tryPlugin (Plugin & plugin)
317 : {
318 2310 : bool willBeAdded = false;
319 9240 : willBeAdded |= checkPlacement (plugin, "setresolver");
320 9240 : willBeAdded |= checkPlacement (plugin, "presetstorage");
321 9240 : willBeAdded |= checkPlacement (plugin, "setstorage");
322 9239 : willBeAdded |= checkPlacement (plugin, "precommit");
323 9236 : willBeAdded |= checkPlacement (plugin, "commit");
324 9236 : willBeAdded |= checkPlacement (plugin, "postcommit");
325 2309 : if (!willBeAdded) return;
326 :
327 9140 : if (!plugin.getSymbol ("set"))
328 : {
329 0 : throw MissingSymbol ("set");
330 : }
331 :
332 :
333 2285 : checkStorage (plugin);
334 2285 : checkResolver (plugin);
335 : }
336 :
337 :
338 2309 : void ErrorPlugins::addPlugin (Plugin & plugin)
339 : {
340 9236 : Plugins::addPlugin (plugin, "prerollback");
341 9236 : Plugins::addPlugin (plugin, "rollback");
342 9236 : Plugins::addPlugin (plugin, "postrollback");
343 :
344 2309 : Plugins::addInfo (plugin);
345 2309 : }
346 :
347 2309 : void GetPlugins::addPlugin (Plugin & plugin)
348 : {
349 9236 : Plugins::addPlugin (plugin, "getresolver");
350 9236 : Plugins::addPlugin (plugin, "pregetstorage");
351 9236 : Plugins::addPlugin (plugin, "getstorage");
352 9236 : Plugins::addPlugin (plugin, "postgetstorage");
353 2309 : }
354 :
355 2309 : void SetPlugins::addPlugin (Plugin & plugin)
356 : {
357 9236 : Plugins::addPlugin (plugin, "setresolver");
358 9236 : Plugins::addPlugin (plugin, "presetstorage");
359 9236 : Plugins::addPlugin (plugin, "setstorage");
360 9236 : Plugins::addPlugin (plugin, "precommit");
361 9236 : Plugins::addPlugin (plugin, "commit");
362 9236 : Plugins::addPlugin (plugin, "postcommit");
363 2309 : }
364 :
365 :
366 0 : void ErrorPlugins::status (std::ostream & os) const
367 : {
368 0 : std::vector<std::string> n = getNeededMissing ();
369 0 : if (!n.empty ())
370 : {
371 0 : os << "Needed plugins that are missing are: ";
372 0 : std::copy (n.begin (), n.end (), std::ostream_iterator<std::string> (os, " "));
373 : os << std::endl;
374 : }
375 0 : std::vector<std::string> r = getRecommendedMissing ();
376 0 : if (!r.empty ())
377 : {
378 0 : os << "Recommendations that are not fulfilled are: ";
379 0 : std::copy (r.begin (), r.end (), std::ostream_iterator<std::string> (os, " "));
380 : os << std::endl;
381 : }
382 0 : }
383 :
384 :
385 84 : bool ErrorPlugins::validated () const
386 : {
387 84 : return nrResolverPlugins == 1 && validateProvided ();
388 : }
389 :
390 84 : bool GetPlugins::validated () const
391 : {
392 84 : return nrStoragePlugins == 1 && nrResolverPlugins == 1;
393 : }
394 :
395 84 : bool SetPlugins::validated () const
396 : {
397 84 : return nrStoragePlugins == 1 && nrResolverPlugins == 1;
398 : }
399 :
400 :
401 : namespace
402 : {
403 1616 : void serializeConfig (std::string name, KeySet const & ks, KeySet & ret)
404 : {
405 3203 : if (!ks.size ()) return;
406 :
407 58 : Key oldParent ("user", KEY_END);
408 87 : Key newParent (name + "/config", KEY_END);
409 :
410 29 : ret.append (newParent);
411 :
412 177 : for (KeySet::iterator i = ks.begin (); i != ks.end (); ++i)
413 : {
414 225 : Key k (i->dup ());
415 225 : if (k.getNamespace () == "user") ret.append (kdb::tools::helper::rebaseKey (k, oldParent, newParent));
416 : }
417 : }
418 : } // namespace
419 :
420 :
421 599 : void ErrorPlugins::serialise (Key & baseKey, KeySet & ret)
422 : {
423 4792 : ret.append (*Key (baseKey.getName () + "/errorplugins", KEY_COMMENT, "List of plugins to use", KEY_END));
424 :
425 6589 : for (int i = 0; i < NR_OF_PLUGINS; ++i)
426 : {
427 17464 : if (plugins[i] == nullptr) continue;
428 506 : bool fr = plugins[i]->firstRef;
429 :
430 1012 : std::ostringstream pluginNumber;
431 506 : pluginNumber << i;
432 4554 : std::string name = baseKey.getName () + "/errorplugins/#" + pluginNumber.str () + plugins[i]->refname ();
433 3542 : ret.append (*Key (name, KEY_COMMENT, "A plugin", KEY_END));
434 2530 : if (fr) serializeConfig (name, plugins[i]->getConfig (), ret);
435 : }
436 599 : }
437 :
438 599 : void GetPlugins::serialise (Key & baseKey, KeySet & ret)
439 : {
440 4792 : ret.append (*Key (baseKey.getName () + "/getplugins", KEY_COMMENT, "List of plugins to use", KEY_END));
441 :
442 6589 : for (int i = 0; i < NR_OF_PLUGINS; ++i)
443 : {
444 16860 : if (plugins[i] == nullptr) continue;
445 1110 : bool fr = plugins[i]->firstRef;
446 :
447 2220 : std::ostringstream pluginNumber;
448 1110 : pluginNumber << i;
449 9990 : std::string name = baseKey.getName () + "/getplugins/#" + pluginNumber.str () + plugins[i]->refname ();
450 7770 : ret.append (*Key (name, KEY_COMMENT, "A plugin", KEY_END));
451 3518 : if (fr) serializeConfig (name, plugins[i]->getConfig (), ret);
452 : }
453 599 : }
454 :
455 :
456 599 : void SetPlugins::serialise (Key & baseKey, KeySet & ret)
457 : {
458 4792 : ret.append (*Key (baseKey.getName () + "/setplugins", KEY_COMMENT, "List of plugins to use", KEY_END));
459 :
460 6589 : for (int i = 0; i < NR_OF_PLUGINS; ++i)
461 : {
462 15871 : if (plugins[i] == nullptr) continue;
463 2099 : bool fr = plugins[i]->firstRef;
464 :
465 4198 : std::ostringstream pluginNumber;
466 2099 : pluginNumber << i;
467 18891 : std::string name = baseKey.getName () + "/setplugins/#" + pluginNumber.str () + plugins[i]->refname ();
468 14693 : ret.append (*Key (name, KEY_COMMENT, "A plugin", KEY_END));
469 4131 : if (fr) serializeConfig (name, plugins[i]->getConfig (), ret);
470 : }
471 599 : }
472 : } // namespace tools
473 : } // namespace kdb
|