Fawkes API Fawkes Development Version
yaml.cpp
1
2/***************************************************************************
3 * yaml.cpp - Fawkes configuration stored in one or more YAML files
4 *
5 * Created: Wed Aug 01 16:46:13 2012
6 * Copyright 2006-2012 Tim Niemueller [www.niemueller.de]
7 *
8 ****************************************************************************/
9
10/* This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version. A runtime exception applies to
14 * this software (see LICENSE.GPL_WRE file mentioned below for details).
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22 */
23
24#include "yaml.h"
25
26#include "yaml_node.h"
27
28#include <core/exceptions/software.h>
29#include <core/threading/mutex.h>
30#include <core/threading/mutex_locker.h>
31#include <logging/liblogger.h>
32#include <sys/socket.h>
33#include <sys/stat.h>
34#include <utils/misc/string_split.h>
35#include <utils/system/fam_thread.h>
36#include <yaml-cpp/exceptions.h>
37
38#include <cerrno>
39#include <cstdio>
40#include <cstdlib>
41#include <cstring>
42#include <dirent.h>
43#include <fstream>
44#include <queue>
45#include <regex>
46#include <unistd.h>
47
48namespace fawkes {
49
50#define YAML_FILE_REGEX "^[a-zA-Z0-9_-]+\\.yaml$"
51
52/** @class YamlConfiguration::YamlValueIterator <config/yaml.h>
53 * Iterator for YAML config trees.
54 * This iterator is used by YamlConfiguration as a result value
55 * for queries. Its use is opaque and knowledge of
56 * Configuration::ValueIterator will suffice for interaction.
57 * @author Tim Niemueller
58 */
59
60/** Constructor.
61 * Creates an iterator representing the invalid iterator.
62 */
64{
65 current_ = nodes_.end();
66}
67
68/** Initializing constructor.
69 * @param nodes nodes to iterate over
70 */
72 std::map<std::string, std::shared_ptr<YamlConfigurationNode>> &nodes)
73: first_(true), nodes_(nodes)
74{
75 current_ = nodes_.begin();
76}
77
78bool
80{
81 if (first_) {
82 first_ = false;
83 } else {
84 ++current_;
85 }
86 return (current_ != nodes_.end());
87}
88
89bool
91{
92 return (current_ != nodes_.end());
93}
94
95const char *
97{
98 if (current_ == nodes_.end()) {
99 throw Exception("YamlValueIterator: cannot get path of invalid iterator");
100 }
101 return current_->first.c_str();
102}
103
104const char *
106{
107 if (current_ == nodes_.end()) {
108 throw Exception("YamlValueIterator: cannot get type of invalid iterator");
109 }
110 return YamlConfigurationNode::Type::to_string(current_->second->get_type());
111}
112
113bool
115{
116 if (current_ == nodes_.end()) {
117 throw Exception("YamlValueIterator: cannot check type on invalid iterator");
118 }
119 return (current_->second->is_type<float>());
120}
121
122bool
124{
125 if (current_ == nodes_.end()) {
126 throw Exception("YamlValueIterator: cannot check type on invalid iterator");
127 }
128 return (current_->second->is_type<unsigned int>());
129}
130
131bool
133{
134 if (current_ == nodes_.end()) {
135 throw Exception("YamlValueIterator: cannot check type on invalid iterator");
136 }
137 return (current_->second->is_type<int>());
138}
139
140bool
142{
143 if (current_ == nodes_.end()) {
144 throw Exception("YamlValueIterator: cannot check type on invalid iterator");
145 }
146 return (current_->second->is_type<bool>());
147}
148
149bool
151{
152 if (current_ == nodes_.end()) {
153 throw Exception("YamlValueIterator: cannot check type on invalid iterator");
154 }
155 return (current_->second->is_type<std::string>());
156}
157
158bool
160{
161 if (current_ == nodes_.end()) {
162 throw Exception("YamlValueIterator: cannot check type on invalid iterator");
163 }
164 return current_->second->get_type() == YamlConfigurationNode::Type::SEQUENCE;
165}
166
167size_t
169{
170 if (current_ == nodes_.end()) {
171 throw Exception("YamlValueIterator: cannot check type on invalid iterator");
172 }
173 if (current_->second->get_type() != YamlConfigurationNode::Type::SEQUENCE) {
174 throw Exception("YamlValueIterator: cannot get list size of non-list value");
175 }
176 return current_->second->get_list_size();
177}
178
179float
181{
182 if (current_ == nodes_.end()) {
183 throw Exception("YamlValueIterator: cannot get value of invalid iterator");
184 }
185 return current_->second->get_value<float>();
186}
187
188unsigned int
190{
191 if (current_ == nodes_.end()) {
192 throw Exception("YamlValueIterator: cannot get value of invalid iterator");
193 }
194 return current_->second->get_value<unsigned int>();
195}
196
197int
199{
200 if (current_ == nodes_.end()) {
201 throw Exception("YamlValueIterator: cannot get value of invalid iterator");
202 }
203 return current_->second->get_value<int>();
204}
205
206bool
208{
209 if (current_ == nodes_.end()) {
210 throw Exception("YamlValueIterator: cannot get value of invalid iterator");
211 }
212 return current_->second->get_value<bool>();
213}
214
215std::string
217{
218 if (current_ == nodes_.end()) {
219 throw Exception("YamlValueIterator: cannot get value of invalid iterator");
220 }
221 return current_->second->get_value<std::string>();
222}
223
224std::string
226{
227 if (current_ == nodes_.end()) {
228 throw Exception("YamlValueIterator: cannot get value of invalid iterator");
229 }
230 if (current_->second->get_type() == YamlConfigurationNode::Type::SEQUENCE) {
231 return current_->second->get_list_as_string();
232 } else {
233 return current_->second->get_value<std::string>();
234 }
235}
236
237std::vector<float>
239{
240 if (current_ == nodes_.end()) {
241 throw Exception("YamlValueIterator: cannot get value of invalid iterator");
242 }
243 return current_->second->get_list<float>();
244}
245
246std::vector<unsigned int>
248{
249 if (current_ == nodes_.end()) {
250 throw Exception("YamlValueIterator: cannot get value of invalid iterator");
251 }
252 return current_->second->get_list<unsigned int>();
253}
254
255std::vector<int>
257{
258 if (current_ == nodes_.end()) {
259 throw Exception("YamlValueIterator: cannot get value of invalid iterator");
260 }
261 return current_->second->get_list<int>();
262}
263
264std::vector<bool>
266{
267 if (current_ == nodes_.end()) {
268 throw Exception("YamlValueIterator: cannot get value of invalid iterator");
269 }
270 return current_->second->get_list<bool>();
271}
272
273std::vector<std::string>
275{
276 if (current_ == nodes_.end()) {
277 throw Exception("YamlValueIterator: cannot get value of invalid iterator");
278 }
279 return current_->second->get_list<std::string>();
280}
281
282std::string
284{
285 throw NotImplementedException("YamlConfig: comments are not available");
286}
287
288bool
290{
291 if (current_ == nodes_.end()) {
292 throw Exception("YamlValueIterator: cannot get value of invalid iterator");
293 }
294 return current_->second->is_default();
295}
296
297/** @class YamlConfiguration <config/yaml.h>
298 * Configuration store using YAML documents.
299 * @author Tim Niemueller
300 */
301
302/** Constructor. */
304{
305 fam_thread_ = NULL;
306 mutex = new Mutex();
307 write_pending_ = false;
308 write_pending_mutex_ = new Mutex();
309
310 sysconfdir_ = NULL;
311 userconfdir_ = NULL;
312}
313
314/** Constructor.
315 * @param sysconfdir system configuration directory, will be searched for
316 * default configuration file, and system will try to create host-specific
317 * database if writable
318 * @param userconfdir user configuration directory, will be searched preferably
319 * for default configuration file, and will be used to create host-specific
320 * database if sysconfdir is not writable. This directory will be created
321 * if it does not exist during load().
322 */
323YamlConfiguration::YamlConfiguration(const char *sysconfdir, const char *userconfdir)
324{
325 fam_thread_ = NULL;
326 mutex = new Mutex();
327 write_pending_ = false;
328 write_pending_mutex_ = new Mutex();
329
330 sysconfdir_ = strdup(sysconfdir);
331
332 if (userconfdir != NULL) {
333 userconfdir_ = strdup(userconfdir);
334 } else {
335 const char *homedir = getenv("HOME");
336 if (homedir == NULL) {
337 userconfdir_ = strdup(sysconfdir);
338 } else {
339 if (asprintf(&userconfdir_, "%s/%s", homedir, USERDIR) == -1) {
340 userconfdir_ = strdup(sysconfdir);
341 }
342 }
343 }
344}
345
346/** Destructor. */
348{
349 if (write_pending_) {
350 write_host_file();
351 }
352
353 if (fam_thread_) {
354 fam_thread_->cancel();
355 fam_thread_->join();
356 delete fam_thread_;
357 }
358
359 if (sysconfdir_)
360 free(sysconfdir_);
361 if (userconfdir_)
362 free(userconfdir_);
363 delete mutex;
364 delete write_pending_mutex_;
365}
366
367void
368YamlConfiguration::load(const char *file_path)
369{
370 if (file_path == NULL) {
371 file_path = "config.yaml";
372 }
373
374 std::string filename;
375 if (file_path[0] == '/') {
376 filename = file_path;
377 } else {
378 const char *try_paths[] = {userconfdir_, sysconfdir_};
379 int try_paths_len = 2;
380
381 for (int i = 0; i < try_paths_len; ++i) {
382 char *path;
383 if (asprintf(&path, "%s/%s", try_paths[i], file_path) != -1) {
384 if (access(path, R_OK) == 0) {
385 filename = path;
386 free(path);
387 break;
388 }
389 free(path);
390 }
391 }
392 if (filename == "") {
393 throw Exception("YamlConfig: cannot find configuration file %s/%s or %s/%s",
394 userconfdir_,
395 file_path,
396 sysconfdir_,
397 file_path);
398 }
399 }
400
401 config_file_ = filename;
402
403 host_file_ = "";
404 std::list<std::string> files, dirs;
405 read_yaml_config(filename, host_file_, root_, host_root_, files, dirs);
406
407#ifdef HAVE_INOTIFY
408 fam_thread_ = new FamThread();
409 RefPtr<FileAlterationMonitor> fam = fam_thread_->get_fam();
410 fam->add_filter("^[^.].*\\.yaml$");
411 std::list<std::string>::iterator f;
412 for (f = files.begin(); f != files.end(); ++f) {
413 //LibLogger::log_info("YC", "Watching %s", f->c_str());
414 fam->watch_file(f->c_str());
415 }
416 for (f = dirs.begin(); f != dirs.end(); ++f) {
417 //LibLogger::log_info("YC", "Watching DIR %s", f->c_str());
418 fam->watch_dir(f->c_str());
419 }
420 fam->add_listener(this);
421 fam_thread_->start();
422#endif
423
424 //root_->print();
425}
426
427std::shared_ptr<YamlConfigurationNode>
428YamlConfiguration::read_yaml_file(std::string filename,
429 bool ignore_missing,
430 std::queue<LoadQueueEntry> &load_queue,
431 std::string & host_file)
432{
433 if (access(filename.c_str(), R_OK) == -1) {
434 if (ignore_missing) {
435 return NULL;
436 }
437 throw Exception(errno, "YamlConfig: cannot access file %s", filename.c_str());
438 }
439
440 std::vector<YAML::Node> docs;
441 bool have_doc1 = false, have_doc2 = false;
442
443 try {
444 docs = YAML::LoadAllFromFile(filename);
445 have_doc1 = docs.size() > 0;
446 have_doc2 = docs.size() > 1;
447 } catch (YAML::ParserException &e) {
448 throw CouldNotOpenConfigException("Failed to parse %s line %i column %i: %s",
449 filename.c_str(),
450 e.mark.line,
451 e.mark.column,
452 e.msg.c_str());
453 }
454
455 std::shared_ptr<YamlConfigurationNode> sub_root;
456
457 if (!have_doc1) {
458 //throw Exception("YamlConfig: file %s contains no document", filename.c_str());
459 // empty -> ignore
460 } else if (have_doc1 && have_doc2) {
461 // we have a meta info and a config document
462 read_meta_doc(docs[0], load_queue, host_file);
463 sub_root = read_config_doc(docs[1]);
464
465 } else {
466 // only one, assume this to be the config document
467 sub_root = read_config_doc(docs[0]);
468 }
469
470 return sub_root;
471}
472
473void
474YamlConfiguration::read_yaml_config(std::string filename,
475 std::string & host_file,
476 std::shared_ptr<YamlConfigurationNode> &root,
477 std::shared_ptr<YamlConfigurationNode> &host_root,
478 std::list<std::string> & files,
479 std::list<std::string> & dirs)
480{
481 root = std::make_shared<YamlConfigurationNode>();
482
483 std::queue<LoadQueueEntry> load_queue;
484 load_queue.push(LoadQueueEntry(filename, false));
485
486 while (!load_queue.empty()) {
487 LoadQueueEntry &qe = load_queue.front();
488
489 if (qe.is_dir) {
490 dirs.push_back(qe.filename);
491 } else {
492 //LibLogger::log_debug("YamlConfiguration",
493 // "Reading YAML file '%s' (ignore missing: %s)",
494 // qe.filename.c_str(), qe.ignore_missing ? "yes" : "no");
495
496 std::shared_ptr<YamlConfigurationNode> sub_root =
497 read_yaml_file(qe.filename, qe.ignore_missing, load_queue, host_file);
498
499 if (sub_root) {
500 files.push_back(qe.filename);
501 *root += sub_root;
502 }
503 }
504
505 load_queue.pop();
506 }
507
508 if (host_file != "") {
509 //LibLogger::log_debug("YamlConfiguration",
510 // "Reading Host YAML file '%s'", host_file.c_str());
511 std::queue<LoadQueueEntry> host_load_queue;
512 host_root = read_yaml_file(host_file, true, host_load_queue, host_file);
513 if (!host_load_queue.empty()) {
514 throw CouldNotOpenConfigException("YamlConfig: includes are not allowed "
515 "in host document");
516 }
517 if (host_root) {
518 *root += host_root;
519 files.push_back(host_file);
520 } else {
521 host_root = std::make_shared<YamlConfigurationNode>();
522 }
523 } else {
524 host_root = std::make_shared<YamlConfigurationNode>();
525 }
526}
527
528void
529YamlConfiguration::fam_event(const char *filename, unsigned int mask)
530{
531 MutexLocker lock(mutex);
532 try {
533 std::string host_file = "";
534 std::list<std::string> files, dirs;
535 std::shared_ptr<YamlConfigurationNode> root, host_root;
536 read_yaml_config(config_file_, host_file, root, host_root, files, dirs);
537
538 std::list<std::string> changes = YamlConfigurationNode::diff(root_, root);
539
540 if (!changes.empty()) {
541 root_ = root;
542 host_root_ = host_root;
543 host_file_ = host_file;
544
545 std::list<std::string>::iterator c;
546 for (c = changes.begin(); c != changes.end(); ++c) {
547 notify_handlers(c->c_str());
548 }
549 }
550
551 // includes might have changed to include a new empty file
552 // so even though no value changes were seen, we might very
553 // well have new files we need to watch (or files we do no
554 // longer have to watch, so always reset and re-add.
555 RefPtr<FileAlterationMonitor> fam = fam_thread_->get_fam();
556 fam->reset();
557 std::list<std::string>::iterator f;
558 for (f = files.begin(); f != files.end(); ++f) {
559 fam->watch_file(f->c_str());
560 }
561 for (f = dirs.begin(); f != dirs.end(); ++f) {
562 fam->watch_dir(f->c_str());
563 }
564
565 } catch (Exception &e) {
566 LibLogger::log_warn("YamlConfiguration", "Failed to reload changed config, exception follows");
567 LibLogger::log_warn("YamlConfiguration", e);
568 }
569}
570
571/** Create absolute config path.
572 * If the @p path starts with / it is considered to be absolute. Otherwise
573 * it is prefixed with the config directory.
574 * @param path path
575 * @return absolute path
576 */
577static std::string
578abs_cfg_path(const std::string &path)
579{
580 if (path[0] == '/') {
581 return path;
582 } else {
583 return std::string(CONFDIR) + "/" + path;
584 }
585}
586
587/** Replace $host in string with hostname
588 * @param prelim preliminary filename (potentially with $host)
589 * @return filename with $host replaced with hostname
590 */
591static std::string
592insert_hostname(std::string prelim)
593{
594 const std::string to_replace = "$host";
595 static char * hostname = NULL;
596 if (hostname == NULL) {
597 hostname = new char[256];
598 gethostname(hostname, 256);
599 }
600 size_t repl_position = prelim.find(to_replace);
601 if (repl_position == std::string::npos) {
602 return prelim;
603 } else {
604 return prelim.replace(repl_position, to_replace.length(), std::string(hostname));
605 }
606}
607
608void
609YamlConfiguration::read_meta_doc(YAML::Node & doc,
610 std::queue<LoadQueueEntry> &load_queue,
611 std::string & host_file)
612{
613 try {
614 const YAML::Node &includes = doc["include"];
615 for (YAML::const_iterator it = includes.begin(); it != includes.end(); ++it) {
616 std::string include = insert_hostname(it->as<std::string>());
617 bool ignore_missing = false;
618 if (it->Tag() == "tag:fawkesrobotics.org,cfg/ignore-missing") {
619 ignore_missing = true;
620 }
621
622 if (it->Tag() == "tag:fawkesrobotics.org,cfg/host-specific") {
623 if (host_file != "") {
624 throw Exception("YamlConfig: Only one host-specific file can be specified");
625 }
626
627 host_file = abs_cfg_path(insert_hostname(it->Scalar()));
628 continue;
629 }
630
631 if (include.empty()) {
632 throw Exception("YamlConfig: invalid empty include");
633 }
634
635 if (include[include.size() - 1] == '/') {
636 // this should be a directory
637 std::string dirname = abs_cfg_path(include);
638 struct stat dir_stat;
639 if ((stat(dirname.c_str(), &dir_stat) != 0)) {
640 if (ignore_missing)
641 continue;
642 throw Exception(errno, "YamlConfig: Failed to stat directory %s", dirname.c_str());
643 }
644
645 if (!S_ISDIR(dir_stat.st_mode)) {
646 throw Exception("YamlConfig: %s is not a directory", dirname.c_str());
647 }
648
649 DIR *d = opendir(dirname.c_str());
650 if (!d) {
651 throw Exception(errno, "YamlConfig: failed to open directory %s", dirname.c_str());
652 }
653
654 load_queue.push(LoadQueueEntry(dirname, ignore_missing, true));
655
656 std::list<std::string> files;
657
658 std::regex yaml_regex{YAML_REGEX, std::regex_constants::extended};
659
660 struct dirent *dent;
661 while ((dent = readdir(d)) != NULL) {
662 if (regex_search(dent->d_name, yaml_regex)) {
663 std::string dn = dent->d_name;
664 files.push_back(dirname + dn);
665 }
666 }
667 closedir(d);
668
669 files.sort();
670 for (std::list<std::string>::iterator f = files.begin(); f != files.end(); ++f) {
671 load_queue.push(LoadQueueEntry(*f, ignore_missing));
672 }
673
674 } else {
675 load_queue.push(LoadQueueEntry(abs_cfg_path(include), ignore_missing));
676 }
677 }
678 } catch (YAML::KeyNotFound &e) {
679 //ignored, no includes
680 }
681}
682
683std::shared_ptr<YamlConfigurationNode>
684YamlConfiguration::read_config_doc(const YAML::Node &doc)
685{
686 return YamlConfigurationNode::create(doc);
687}
688
689void
690YamlConfiguration::write_host_file()
691{
692 if (host_file_ == "") {
693 throw Exception("YamlConfig: no host config file specified");
694 }
695 if (mutex->try_lock()) {
696 try {
697 host_root_->emit(host_file_);
698 mutex->unlock();
699 } catch (...) {
700 write_pending_mutex_->unlock();
701 mutex->unlock();
702 throw;
703 }
704 } else {
705 write_pending_mutex_->lock();
706 write_pending_ = true;
707 write_pending_mutex_->unlock();
708 }
709}
710
711void
713{
714 throw NotImplementedException("YamlConfig does not support copying of a configuration");
715}
716
717bool
719{
720 try {
721 std::shared_ptr<YamlConfigurationNode> n = root_->find(path);
722 return !n->has_children();
723 } catch (Exception &e) {
724 return false;
725 }
726}
727
728std::string
730{
731 std::shared_ptr<YamlConfigurationNode> n = root_->find(path);
732 if (n->has_children()) {
734 }
735
736 return YamlConfigurationNode::Type::to_string(n->get_type());
737}
738
739std::string
741{
742 return "";
743}
744
745/** Retrieve value casted to given type T.
746 * @param root root node of the tree to search
747 * @param path path to query
748 * @return value casted as desired
749 * @throw YAML::ScalarInvalid thrown if value does not exist or is of
750 * a different type.
751 */
752template <typename T>
753static inline T
754get_value_as(std::shared_ptr<YamlConfigurationNode> root, const char *path)
755{
756 std::shared_ptr<YamlConfigurationNode> n = root->find(path);
757 if (n->has_children()) {
759 }
760 return n->get_value<T>();
761}
762
763/** Retrieve value casted to given type T.
764 * @param root root node of the tree to search
765 * @param path path to query
766 * @return value casted as desired
767 * @throw YAML::ScalarInvalid thrown if value does not exist or is of
768 * a different type.
769 */
770template <typename T>
771static inline std::vector<T>
772get_list(std::shared_ptr<YamlConfigurationNode> root, const char *path)
773{
774 std::shared_ptr<YamlConfigurationNode> n = root->find(path);
775 if (n->has_children()) {
777 }
778 return n->get_list<T>();
779}
780
781float
783{
784 return get_value_as<float>(root_, path);
785}
786
787unsigned int
789{
790 return get_value_as<unsigned int>(root_, path);
791}
792
793int
795{
796 return get_value_as<int>(root_, path);
797}
798
799bool
801{
802 return get_value_as<bool>(root_, path);
803}
804
805std::string
807{
808 return get_value_as<std::string>(root_, path);
809}
810
811std::vector<float>
813{
814 return get_list<float>(root_, path);
815}
816
817std::vector<unsigned int>
819{
820 return get_list<unsigned int>(root_, path);
821}
822
823std::vector<int>
825{
826 return get_list<int>(root_, path);
827}
828
829std::vector<bool>
831{
832 return get_list<bool>(root_, path);
833}
834
835std::vector<std::string>
837{
838 return get_list<std::string>(root_, path);
839}
840
841/** Check if value is of given type T.
842 * @param root root node of the tree to search
843 * @param path path to query
844 * @return true if value is of desired type, false otherwise
845 */
846template <typename T>
847static inline bool
848is_type(std::shared_ptr<YamlConfigurationNode> root, const char *path)
849{
850 std::shared_ptr<YamlConfigurationNode> n = root->find(path);
851 if (n->has_children()) {
853 }
854 return n->is_type<T>();
855}
856
857bool
859{
860 return is_type<float>(root_, path);
861}
862
863bool
865{
866 std::shared_ptr<YamlConfigurationNode> n = root_->find(path);
867 if (n->has_children()) {
869 }
870
871 if (!n->is_type<unsigned int>())
872 return false;
873
874 int v = n->get_value<int>();
875 return (v >= 0);
876}
877
878bool
880{
881 return is_type<int>(root_, path);
882}
883
884bool
886{
887 return is_type<bool>(root_, path);
888}
889
890bool
892{
893 return is_type<std::string>(root_, path);
894}
895
896bool
898{
899 std::shared_ptr<YamlConfigurationNode> n = root_->find(path);
900 if (n->has_children()) {
902 }
903 return (n->get_type() == YamlConfigurationNode::Type::SEQUENCE);
904}
905
906std::string
908{
909 return "";
910}
911
912bool
914{
915 return false;
916}
917
920{
921 try {
922 std::shared_ptr<YamlConfigurationNode> n = root_->find(path);
923 if (n->has_children()) {
924 return new YamlValueIterator();
925 }
926 std::map<std::string, std::shared_ptr<YamlConfigurationNode>> nodes;
927 nodes[path] = n;
928 return new YamlValueIterator(nodes);
929 } catch (ConfigEntryNotFoundException &e) {
930 return new YamlValueIterator();
931 }
932}
933
934void
935YamlConfiguration::set_float(const char *path, float f)
936{
937 root_->set_value(path, f);
938 host_root_->set_value(path, f);
939 write_host_file();
940 notify_handlers(path, false);
941}
942
943void
944YamlConfiguration::set_uint(const char *path, unsigned int uint)
945{
946 root_->set_value(path, uint);
947 host_root_->set_value(path, uint);
948 write_host_file();
949 notify_handlers(path, false);
950}
951
952void
953YamlConfiguration::set_int(const char *path, int i)
954{
955 root_->set_value(path, i);
956 host_root_->set_value(path, i);
957 write_host_file();
958 notify_handlers(path, false);
959}
960
961void
962YamlConfiguration::set_bool(const char *path, bool b)
963{
964 root_->set_value(path, b);
965 host_root_->set_value(path, b);
966 write_host_file();
967 notify_handlers(path, false);
968}
969
970void
971YamlConfiguration::set_string(const char *path, const char *s)
972{
973 root_->set_value(path, std::string(s));
974 host_root_->set_value(path, std::string(s));
975 write_host_file();
976 notify_handlers(path, false);
977}
978
979void
980YamlConfiguration::set_string(const char *path, std::string &s)
981{
982 set_string(path, s.c_str());
983}
984
985void
986YamlConfiguration::set_floats(const char *path, std::vector<float> &f)
987{
988 root_->set_list(path, f);
989 host_root_->set_list(path, f);
990 write_host_file();
991 notify_handlers(path, false);
992}
993
994void
995YamlConfiguration::set_uints(const char *path, std::vector<unsigned int> &u)
996{
997 root_->set_list(path, u);
998 host_root_->set_list(path, u);
999 write_host_file();
1000 notify_handlers(path, false);
1001}
1002
1003void
1004YamlConfiguration::set_ints(const char *path, std::vector<int> &i)
1005{
1006 root_->set_list(path, i);
1007 host_root_->set_list(path, i);
1008 write_host_file();
1009 notify_handlers(path, false);
1010}
1011
1012void
1013YamlConfiguration::set_bools(const char *path, std::vector<bool> &b)
1014{
1015 root_->set_list(path, b);
1016 host_root_->set_list(path, b);
1017 write_host_file();
1018 notify_handlers(path, false);
1019}
1020
1021void
1022YamlConfiguration::set_strings(const char *path, std::vector<std::string> &s)
1023{
1024 root_->set_list(path, s);
1025 host_root_->set_list(path, s);
1026 write_host_file();
1027 notify_handlers(path, false);
1028}
1029
1030void
1031YamlConfiguration::set_strings(const char *path, std::vector<const char *> &s)
1032{
1033 root_->set_list(path, s);
1034 host_root_->set_list(path, s);
1035 write_host_file();
1036 notify_handlers(path, false);
1037}
1038
1039void
1040YamlConfiguration::set_comment(const char *path, const char *comment)
1041{
1042}
1043
1044void
1045YamlConfiguration::set_comment(const char *path, std::string &comment)
1046{
1047}
1048
1049void
1051{
1052 host_root_->erase(path);
1053 root_->erase(path);
1054 write_host_file();
1055}
1056
1057void
1059{
1060 throw NotImplementedException("YamlConfiguration does not support default values");
1061}
1062
1063void
1064YamlConfiguration::set_default_uint(const char *path, unsigned int uint)
1065{
1066 throw NotImplementedException("YamlConfiguration does not support default values");
1067}
1068
1069void
1071{
1072 throw NotImplementedException("YamlConfiguration does not support default values");
1073}
1074
1075void
1077{
1078 throw NotImplementedException("YamlConfiguration does not support default values");
1079}
1080
1081void
1082YamlConfiguration::set_default_string(const char *path, const char *s)
1083{
1084 throw NotImplementedException("YamlConfiguration does not support default values");
1085}
1086
1087void
1088YamlConfiguration::set_default_string(const char *path, std::string &s)
1089{
1090 set_default_string(path, s.c_str());
1091}
1092
1093void
1094YamlConfiguration::set_default_comment(const char *path, const char *comment)
1095{
1096 throw NotImplementedException("YamlConfiguration does not support default values");
1097}
1098
1099void
1100YamlConfiguration::set_default_comment(const char *path, std::string &comment)
1101{
1102 set_default_comment(path, comment.c_str());
1103}
1104
1105void
1107{
1108 throw NotImplementedException("YamlConfiguration does not support default values");
1109}
1110
1111/** Lock the config.
1112 * No further changes or queries can be executed on the configuration and will block until
1113 * the config is unlocked.
1114 */
1115void
1117{
1118 mutex->lock();
1119}
1120
1121/** Try to lock the config.
1122 * @see Configuration::lock()
1123 * @return true, if the lock has been aquired, false otherwise
1124 */
1125bool
1127{
1128 return mutex->try_lock();
1129}
1130
1131/** Unlock the config.
1132 * Modifications and queries are possible again.
1133 */
1134void
1136{
1137 write_pending_mutex_->lock();
1138 if (write_pending_) {
1139 host_root_->emit(host_file_);
1140 write_pending_ = false;
1141 }
1142 write_pending_mutex_->unlock();
1143 mutex->unlock();
1144}
1145
1146void
1148{
1149}
1150
1153{
1154 std::map<std::string, std::shared_ptr<YamlConfigurationNode>> nodes;
1155 root_->enum_leafs(nodes);
1156 return new YamlValueIterator(nodes);
1157}
1158
1161{
1162 std::string tmp_path = path;
1163 std::string::size_type tl = tmp_path.length();
1164 if ((tl > 0) && (tmp_path[tl - 1] == '/')) {
1165 tmp_path.resize(tl - 1);
1166 }
1167 try {
1168 std::shared_ptr<YamlConfigurationNode> n = root_->find(tmp_path.c_str());
1169 std::map<std::string, std::shared_ptr<YamlConfigurationNode>> nodes;
1170 n->enum_leafs(nodes, tmp_path);
1171 return new YamlValueIterator(nodes);
1172 } catch (Exception &e) {
1173 return new YamlValueIterator();
1174 }
1175}
1176
1177/** Query node for a specific path.
1178 * @param path path to retrieve node for
1179 * @return node representing requested path query result, if the path only
1180 * consists of collection and path name returns the whole document.
1181 */
1182std::shared_ptr<YamlConfigurationNode>
1183YamlConfiguration::query(const char *path) const
1184{
1185 std::queue<std::string> pel_q = str_split_to_queue(path);
1186 return root_->find(pel_q);
1187}
1188
1189} // end namespace fawkes
Thrown if a config entry could not be found.
Definition: config.h:47
Iterator interface to iterate over config values.
Definition: config.h:75
Interface for configuration handling.
Definition: config.h:68
void notify_handlers(const char *path, bool comment_changed=false)
Notify handlers for given path.
Definition: config.cpp:674
Base class for exceptions in Fawkes.
Definition: exception.h:36
FileAlterationMonitor thread wrapper.
Definition: fam_thread.h:33
RefPtr< FileAlterationMonitor > get_fam()
Get FileAlterationMonitor.
Definition: fam_thread.cpp:55
static void log_warn(const char *component, const char *format,...)
Log warning message.
Definition: liblogger.cpp:156
Mutex locking helper.
Definition: mutex_locker.h:34
Mutex mutual exclusion lock.
Definition: mutex.h:33
bool try_lock()
Tries to lock the mutex.
Definition: mutex.cpp:117
void lock()
Lock this mutex.
Definition: mutex.cpp:87
void unlock()
Unlock the mutex.
Definition: mutex.cpp:131
Called method has not been implemented.
Definition: software.h:105
RefPtr<> is a reference-counting shared smartpointer.
Definition: refptr.h:50
void reset()
Reset pointer.
Definition: refptr.h:455
void start(bool wait=true)
Call this method to start the thread.
Definition: thread.cpp:499
void join()
Join the thread.
Definition: thread.cpp:597
void cancel()
Cancel a thread.
Definition: thread.cpp:646
Iterator for YAML config trees.
Definition: yaml.h:119
virtual int get_int() const
Get int value.
Definition: yaml.cpp:198
virtual std::string get_as_string() const
Get value as string.
Definition: yaml.cpp:225
virtual bool valid() const
Check if the current element is valid.
Definition: yaml.cpp:90
virtual std::vector< float > get_floats() const
Get list of values from configuration which is of type float.
Definition: yaml.cpp:238
virtual std::vector< int > get_ints() const
Get list of values from configuration which is of type int.
Definition: yaml.cpp:256
virtual bool is_uint() const
Check if current value is a unsigned int.
Definition: yaml.cpp:123
virtual std::vector< bool > get_bools() const
Get list of values from configuration which is of type bool.
Definition: yaml.cpp:265
virtual std::vector< std::string > get_strings() const
Get list of values from configuration which is of type string.
Definition: yaml.cpp:274
virtual bool get_bool() const
Get bool value.
Definition: yaml.cpp:207
virtual bool is_int() const
Check if current value is a int.
Definition: yaml.cpp:132
virtual bool is_default() const
Check if current value was read from the default config.
Definition: yaml.cpp:289
virtual std::string get_comment() const
Get comment of value.
Definition: yaml.cpp:283
virtual const char * path() const
Path of value.
Definition: yaml.cpp:96
virtual bool is_bool() const
Check if current value is a bool.
Definition: yaml.cpp:141
virtual bool next()
Check if there is another element and advance to this if possible.
Definition: yaml.cpp:79
virtual bool is_string() const
Check if current value is a string.
Definition: yaml.cpp:150
virtual bool is_float() const
Check if current value is a float.
Definition: yaml.cpp:114
virtual std::vector< unsigned int > get_uints() const
Get list of values from configuration which is of type unsigned int.
Definition: yaml.cpp:247
virtual const char * type() const
Type of value.
Definition: yaml.cpp:105
virtual float get_float() const
Get float value.
Definition: yaml.cpp:180
virtual unsigned int get_uint() const
Get unsigned int value.
Definition: yaml.cpp:189
virtual bool is_list() const
Check if a value is a list.
Definition: yaml.cpp:159
virtual size_t get_list_size() const
Get number of elements in list value.
Definition: yaml.cpp:168
virtual std::string get_string() const
Get string value.
Definition: yaml.cpp:216
virtual void set_floats(const char *path, std::vector< float > &f)
Set new value in configuration of type float.
Definition: yaml.cpp:986
virtual void erase(const char *path)
Erase the given value from the configuration.
Definition: yaml.cpp:1050
virtual void set_strings(const char *path, std::vector< std::string > &s)
Set new value in configuration of type string.
Definition: yaml.cpp:1022
virtual std::string get_type(const char *path)
Get type of value at given path.
Definition: yaml.cpp:729
virtual std::vector< bool > get_bools(const char *path)
Get list of values from configuration which is of type bool.
Definition: yaml.cpp:830
virtual void set_string(const char *path, std::string &s)
Set new value in configuration of type string.
Definition: yaml.cpp:980
virtual bool exists(const char *path)
Check if a given value exists.
Definition: yaml.cpp:718
virtual std::string get_comment(const char *path)
Get comment of value at given path.
Definition: yaml.cpp:740
virtual void set_uint(const char *path, unsigned int uint)
Set new value in configuration of type unsigned int.
Definition: yaml.cpp:944
virtual float get_float(const char *path)
Get value from configuration which is of type float.
Definition: yaml.cpp:782
virtual unsigned int get_uint(const char *path)
Get value from configuration which is of type unsigned int.
Definition: yaml.cpp:788
virtual void set_uints(const char *path, std::vector< unsigned int > &uint)
Set new value in configuration of type unsigned int.
Definition: yaml.cpp:995
YamlConfiguration()
Constructor.
Definition: yaml.cpp:303
ValueIterator * search(const char *path)
Iterator with search results.
Definition: yaml.cpp:1160
virtual void set_ints(const char *path, std::vector< int > &i)
Set new value in configuration of type int.
Definition: yaml.cpp:1004
virtual void fam_event(const char *filename, unsigned int mask)
Event has been raised.
Definition: yaml.cpp:529
virtual void set_bools(const char *path, std::vector< bool > &b)
Set new value in configuration of type bool.
Definition: yaml.cpp:1013
virtual bool is_int(const char *path)
Check if a value is of type int.
Definition: yaml.cpp:879
virtual std::string get_string(const char *path)
Get value from configuration which is of type string.
Definition: yaml.cpp:806
virtual bool is_default(const char *path)
Check if a value was read from the default config.
Definition: yaml.cpp:913
virtual void try_dump()
Try to dump configuration.
Definition: yaml.cpp:1147
virtual void set_float(const char *path, float f)
Set new value in configuration of type float.
Definition: yaml.cpp:935
bool try_lock()
Try to lock the config.
Definition: yaml.cpp:1126
virtual bool is_uint(const char *path)
Check if a value is of type unsigned int.
Definition: yaml.cpp:864
virtual void set_default_comment(const char *path, const char *comment)
Set new default comment for existing default configuration value.
Definition: yaml.cpp:1094
virtual bool is_bool(const char *path)
Check if a value is of type bool.
Definition: yaml.cpp:885
virtual bool is_list(const char *path)
Check if a value is a list.
Definition: yaml.cpp:897
void lock()
Lock the config.
Definition: yaml.cpp:1116
virtual void set_int(const char *path, int i)
Set new value in configuration of type int.
Definition: yaml.cpp:953
virtual void set_default_int(const char *path, int i)
Set new default value in configuration of type int.
Definition: yaml.cpp:1070
virtual void set_default_string(const char *path, std::string &s)
Set new default value in configuration of type string.
Definition: yaml.cpp:1088
virtual ~YamlConfiguration()
Destructor.
Definition: yaml.cpp:347
virtual std::vector< unsigned int > get_uints(const char *path)
Get list of values from configuration which is of type unsigned int.
Definition: yaml.cpp:818
virtual int get_int(const char *path)
Get value from configuration which is of type int.
Definition: yaml.cpp:794
ValueIterator * iterator()
Iterator for all values.
Definition: yaml.cpp:1152
virtual bool get_bool(const char *path)
Get value from configuration which is of type bool.
Definition: yaml.cpp:800
virtual std::vector< std::string > get_strings(const char *path)
Get list of values from configuration which is of type string.
Definition: yaml.cpp:836
virtual std::string get_default_comment(const char *path)
Get comment of value at given path.
Definition: yaml.cpp:907
virtual void load(const char *file_path)
Load configuration.
Definition: yaml.cpp:368
virtual void set_default_uint(const char *path, unsigned int uint)
Set new default value in configuration of type unsigned int.
Definition: yaml.cpp:1064
virtual ValueIterator * get_value(const char *path)
Get value from configuration.
Definition: yaml.cpp:919
virtual void set_comment(const char *path, std::string &comment)
Set new comment for existing value.
Definition: yaml.cpp:1045
void unlock()
Unlock the config.
Definition: yaml.cpp:1135
virtual void copy(Configuration *copyconf)
Copies all values from the given configuration.
Definition: yaml.cpp:712
virtual void set_default_bool(const char *path, bool b)
Set new default value in configuration of type bool.
Definition: yaml.cpp:1076
virtual std::vector< float > get_floats(const char *path)
Get list of values from configuration which is of type float.
Definition: yaml.cpp:812
virtual bool is_float(const char *path)
Check if a value is of type float.
Definition: yaml.cpp:858
virtual bool is_string(const char *path)
Check if a value is of type string.
Definition: yaml.cpp:891
virtual void set_bool(const char *path, bool b)
Set new value in configuration of type bool.
Definition: yaml.cpp:962
virtual void set_default_float(const char *path, float f)
Set new default value in configuration of type float.
Definition: yaml.cpp:1058
virtual void erase_default(const char *path)
Erase the given default value from the configuration.
Definition: yaml.cpp:1106
virtual std::vector< int > get_ints(const char *path)
Get list of values from configuration which is of type int.
Definition: yaml.cpp:824
Fawkes library namespace.
static std::string abs_cfg_path(const std::string &path)
Create absolute config path.
Definition: yaml.cpp:578
static T get_value_as(std::shared_ptr< YamlConfigurationNode > root, const char *path)
Retrieve value casted to given type T.
Definition: memory.cpp:101
static std::vector< T > get_list(std::shared_ptr< YamlConfigurationNode > root, const char *path)
Retrieve value casted to given type T.
Definition: memory.cpp:119
static std::queue< std::string > str_split_to_queue(const std::string &s, char delim='/')
Split string by delimiter.
Definition: string_split.h:202
static std::string insert_hostname(std::string prelim)
Replace $host in string with hostname.
Definition: yaml.cpp:592
static bool is_type(std::shared_ptr< YamlConfigurationNode > root, const char *path)
Check if value is of given type T.
Definition: memory.cpp:195