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 
48 namespace 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 
78 bool
80 {
81  if (first_) {
82  first_ = false;
83  } else {
84  ++current_;
85  }
86  return (current_ != nodes_.end());
87 }
88 
89 bool
91 {
92  return (current_ != nodes_.end());
93 }
94 
95 const 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 
104 const 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 
113 bool
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 
122 bool
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 
131 bool
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 
140 bool
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 
149 bool
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 
158 bool
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 
167 size_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 
179 float
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 
188 unsigned 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 
197 int
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 
206 bool
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 
215 std::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 
224 std::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 
237 std::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 
246 std::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 
255 std::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 
264 std::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 
273 std::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 
282 std::string
284 {
285  throw NotImplementedException("YamlConfig: comments are not available");
286 }
287 
288 bool
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  */
323 YamlConfiguration::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 
367 void
368 YamlConfiguration::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 
427 std::shared_ptr<YamlConfigurationNode>
428 YamlConfiguration::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 
473 void
474 YamlConfiguration::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 
528 void
529 YamlConfiguration::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  */
577 static std::string
578 abs_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  */
591 static std::string
592 insert_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 
608 void
609 YamlConfiguration::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 
683 std::shared_ptr<YamlConfigurationNode>
684 YamlConfiguration::read_config_doc(const YAML::Node &doc)
685 {
686  return YamlConfigurationNode::create(doc);
687 }
688 
689 void
690 YamlConfiguration::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 
711 void
712 YamlConfiguration::copy(Configuration *copyconf)
713 {
714  throw NotImplementedException("YamlConfig does not support copying of a configuration");
715 }
716 
717 bool
718 YamlConfiguration::exists(const char *path)
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 
728 std::string
729 YamlConfiguration::get_type(const char *path)
730 {
731  std::shared_ptr<YamlConfigurationNode> n = root_->find(path);
732  if (n->has_children()) {
733  throw ConfigEntryNotFoundException(path);
734  }
735 
736  return YamlConfigurationNode::Type::to_string(n->get_type());
737 }
738 
739 std::string
740 YamlConfiguration::get_comment(const char *path)
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  */
752 template <typename T>
753 static inline T
754 get_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()) {
758  throw ConfigEntryNotFoundException(path);
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  */
770 template <typename T>
771 static inline std::vector<T>
772 get_list(std::shared_ptr<YamlConfigurationNode> root, const char *path)
773 {
774  std::shared_ptr<YamlConfigurationNode> n = root->find(path);
775  if (n->has_children()) {
776  throw ConfigEntryNotFoundException(path);
777  }
778  return n->get_list<T>();
779 }
780 
781 float
782 YamlConfiguration::get_float(const char *path)
783 {
784  return get_value_as<float>(root_, path);
785 }
786 
787 unsigned int
789 {
790  return get_value_as<unsigned int>(root_, path);
791 }
792 
793 int
794 YamlConfiguration::get_int(const char *path)
795 {
796  return get_value_as<int>(root_, path);
797 }
798 
799 bool
801 {
802  return get_value_as<bool>(root_, path);
803 }
804 
805 std::string
807 {
808  return get_value_as<std::string>(root_, path);
809 }
810 
811 std::vector<float>
813 {
814  return get_list<float>(root_, path);
815 }
816 
817 std::vector<unsigned int>
819 {
820  return get_list<unsigned int>(root_, path);
821 }
822 
823 std::vector<int>
825 {
826  return get_list<int>(root_, path);
827 }
828 
829 std::vector<bool>
831 {
832  return get_list<bool>(root_, path);
833 }
834 
835 std::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  */
846 template <typename T>
847 static inline bool
848 is_type(std::shared_ptr<YamlConfigurationNode> root, const char *path)
849 {
850  std::shared_ptr<YamlConfigurationNode> n = root->find(path);
851  if (n->has_children()) {
852  throw ConfigEntryNotFoundException(path);
853  }
854  return n->is_type<T>();
855 }
856 
857 bool
858 YamlConfiguration::is_float(const char *path)
859 {
860  return is_type<float>(root_, path);
861 }
862 
863 bool
864 YamlConfiguration::is_uint(const char *path)
865 {
866  std::shared_ptr<YamlConfigurationNode> n = root_->find(path);
867  if (n->has_children()) {
868  throw ConfigEntryNotFoundException(path);
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 
878 bool
879 YamlConfiguration::is_int(const char *path)
880 {
881  return is_type<int>(root_, path);
882 }
883 
884 bool
885 YamlConfiguration::is_bool(const char *path)
886 {
887  return is_type<bool>(root_, path);
888 }
889 
890 bool
892 {
893  return is_type<std::string>(root_, path);
894 }
895 
896 bool
897 YamlConfiguration::is_list(const char *path)
898 {
899  std::shared_ptr<YamlConfigurationNode> n = root_->find(path);
900  if (n->has_children()) {
901  throw ConfigEntryNotFoundException(path);
902  }
903  return (n->get_type() == YamlConfigurationNode::Type::SEQUENCE);
904 }
905 
906 std::string
908 {
909  return "";
910 }
911 
912 bool
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 
934 void
935 YamlConfiguration::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 
943 void
944 YamlConfiguration::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 
952 void
953 YamlConfiguration::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 
961 void
962 YamlConfiguration::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 
970 void
971 YamlConfiguration::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 
979 void
980 YamlConfiguration::set_string(const char *path, std::string &s)
981 {
982  set_string(path, s.c_str());
983 }
984 
985 void
986 YamlConfiguration::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 
994 void
995 YamlConfiguration::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);
1002 
1003 void
1004 YamlConfiguration::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);
1011 
1012 void
1013 YamlConfiguration::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);
1020 
1021 void
1022 YamlConfiguration::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);
1029 
1030 void
1031 YamlConfiguration::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);
1038 
1039 void
1040 YamlConfiguration::set_comment(const char *path, const char *comment)
1041 {
1042 }
1043 
1044 void
1045 YamlConfiguration::set_comment(const char *path, std::string &comment)
1047 }
1048 
1049 void
1050 YamlConfiguration::erase(const char *path)
1052  host_root_->erase(path);
1053  root_->erase(path);
1054  write_host_file();
1055 }
1057 void
1058 YamlConfiguration::set_default_float(const char *path, float f)
1059 {
1060  throw NotImplementedException("YamlConfiguration does not support default values");
1061 }
1062 
1063 void
1064 YamlConfiguration::set_default_uint(const char *path, unsigned int uint)
1065 {
1066  throw NotImplementedException("YamlConfiguration does not support default values");
1067 }
1068 
1069 void
1070 YamlConfiguration::set_default_int(const char *path, int i)
1071 {
1072  throw NotImplementedException("YamlConfiguration does not support default values");
1073 }
1074 
1075 void
1076 YamlConfiguration::set_default_bool(const char *path, bool b)
1077 {
1078  throw NotImplementedException("YamlConfiguration does not support default values");
1079 }
1080 
1081 void
1082 YamlConfiguration::set_default_string(const char *path, const char *s)
1083 {
1084  throw NotImplementedException("YamlConfiguration does not support default values");
1085 }
1086 
1087 void
1088 YamlConfiguration::set_default_string(const char *path, std::string &s)
1089 {
1090  set_default_string(path, s.c_str());
1091 }
1092 
1093 void
1094 YamlConfiguration::set_default_comment(const char *path, const char *comment)
1095 {
1096  throw NotImplementedException("YamlConfiguration does not support default values");
1097 }
1098 
1099 void
1100 YamlConfiguration::set_default_comment(const char *path, std::string &comment)
1101 {
1102  set_default_comment(path, comment.c_str());
1103 }
1104 
1105 void
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  */
1115 void
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  */
1125 bool
1127 {
1128  return mutex->try_lock();
1129 }
1130 
1131 /** Unlock the config.
1132  * Modifications and queries are possible again.
1133  */
1134 void
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 
1146 void
1148 {
1149 }
1150 
1151 Configuration::ValueIterator *
1154  std::map<std::string, std::shared_ptr<YamlConfigurationNode>> nodes;
1155  root_->enum_leafs(nodes);
1156  return new YamlValueIterator(nodes);
1157 }
1160 YamlConfiguration::search(const char *path)
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  */
1182 std::shared_ptr<YamlConfigurationNode>
1183 YamlConfiguration::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
fawkes::Mutex::lock
void lock()
Lock this mutex.
Definition: mutex.cpp:93
fawkes::YamlConfiguration::try_dump
virtual void try_dump()
Definition: yaml.cpp:1153
fawkes::YamlConfiguration::set_floats
virtual void set_floats(const char *path, std::vector< float > &f)
Definition: yaml.cpp:992
fawkes::YamlConfiguration::is_string
virtual bool is_string(const char *path)
Definition: yaml.cpp:897
fawkes::YamlConfiguration::exists
virtual bool exists(const char *path)
Definition: yaml.cpp:724
fawkes::YamlConfiguration::set_default_string
virtual void set_default_string(const char *path, std::string &s)
Definition: yaml.cpp:1094
fawkes::YamlConfiguration::load
virtual void load(const char *file_path)
Definition: yaml.cpp:374
fawkes::YamlConfiguration::YamlValueIterator::is_int
virtual bool is_int() const
Definition: yaml.cpp:138
fawkes::YamlConfiguration::set_int
virtual void set_int(const char *path, int i)
Definition: yaml.cpp:959
fawkes::YamlConfiguration::set_uints
virtual void set_uints(const char *path, std::vector< unsigned int > &uint)
Definition: yaml.cpp:1001
fawkes::YamlConfiguration::YamlValueIterator::is_uint
virtual bool is_uint() const
Definition: yaml.cpp:129
fawkes::Mutex
Definition: mutex.h:38
fawkes::YamlConfiguration::YamlValueIterator::is_list
virtual bool is_list() const
Definition: yaml.cpp:165
fawkes::YamlConfiguration::fam_event
virtual void fam_event(const char *filename, unsigned int mask)
Definition: yaml.cpp:535
fawkes::YamlConfiguration::YamlValueIterator::is_default
virtual bool is_default() const
Definition: yaml.cpp:295
fawkes::YamlConfiguration::set_default_comment
virtual void set_default_comment(const char *path, const char *comment)
Definition: yaml.cpp:1100
fawkes::YamlConfiguration::YamlValueIterator::get_ints
virtual std::vector< int > get_ints() const
Definition: yaml.cpp:262
fawkes::YamlConfiguration::YamlValueIterator::get_uints
virtual std::vector< unsigned int > get_uints() const
Definition: yaml.cpp:253
fawkes::YamlConfiguration::YamlConfiguration
YamlConfiguration()
Constructor.
Definition: yaml.cpp:309
fawkes::YamlConfiguration::YamlValueIterator::get_floats
virtual std::vector< float > get_floats() const
Definition: yaml.cpp:244
fawkes::YamlConfiguration::YamlValueIterator
Definition: yaml.h:124
fawkes::YamlConfiguration::get_value
virtual ValueIterator * get_value(const char *path)
Definition: yaml.cpp:925
fawkes::YamlConfiguration::YamlValueIterator::get_int
virtual int get_int() const
Definition: yaml.cpp:204
fawkes::YamlConfiguration::get_ints
virtual std::vector< int > get_ints(const char *path)
Definition: yaml.cpp:830
fawkes::YamlConfiguration::set_strings
virtual void set_strings(const char *path, std::vector< std::string > &s)
Definition: yaml.cpp:1028
fawkes::YamlConfiguration::YamlValueIterator::YamlValueIterator
YamlValueIterator()
Constructor.
Definition: yaml.cpp:69
fawkes::Mutex::unlock
void unlock()
Unlock the mutex.
Definition: mutex.cpp:137
fawkes::YamlConfiguration::get_uint
virtual unsigned int get_uint(const char *path)
Definition: yaml.cpp:794
fawkes::YamlConfiguration::get_type
virtual std::string get_type(const char *path)
Definition: yaml.cpp:735
fawkes::YamlConfiguration::set_float
virtual void set_float(const char *path, float f)
Definition: yaml.cpp:941
fawkes::YamlConfiguration::YamlValueIterator::next
virtual bool next()
Definition: yaml.cpp:85
fawkes::YamlConfiguration::YamlValueIterator::get_bools
virtual std::vector< bool > get_bools() const
Definition: yaml.cpp:271
fawkes::YamlConfiguration::YamlValueIterator::get_uint
virtual unsigned int get_uint() const
Definition: yaml.cpp:195
fawkes::YamlConfiguration::set_string
virtual void set_string(const char *path, std::string &s)
Definition: yaml.cpp:986
fawkes::Configuration::ValueIterator
Definition: config.h:77
fawkes::YamlConfiguration::set_comment
virtual void set_comment(const char *path, std::string &comment)
Definition: yaml.cpp:1051
fawkes::ConfigEntryNotFoundException
Definition: config.h:52
fawkes::YamlConfiguration::YamlValueIterator::valid
virtual bool valid() const
Definition: yaml.cpp:96
fawkes::YamlConfiguration::set_bool
virtual void set_bool(const char *path, bool b)
Definition: yaml.cpp:968
fawkes::YamlConfiguration::get_strings
virtual std::vector< std::string > get_strings(const char *path)
Definition: yaml.cpp:842
fawkes::YamlConfiguration::is_float
virtual bool is_float(const char *path)
Definition: yaml.cpp:864
fawkes::YamlConfiguration::set_uint
virtual void set_uint(const char *path, unsigned int uint)
Definition: yaml.cpp:950
fawkes::YamlConfiguration::is_list
virtual bool is_list(const char *path)
Definition: yaml.cpp:903
fawkes::YamlConfiguration::get_uints
virtual std::vector< unsigned int > get_uints(const char *path)
Definition: yaml.cpp:824
fawkes::insert_hostname
static std::string insert_hostname(std::string prelim)
Replace $host in string with hostname.
Definition: yaml.cpp:598
fawkes::YamlConfiguration::unlock
void unlock()
Unlock the config.
Definition: yaml.cpp:1141
fawkes::get_list
static std::vector< T > get_list(std::shared_ptr< YamlConfigurationNode > root, const char *path)
Retrieve value casted to given type T.
Definition: memory.cpp:125
fawkes::YamlConfiguration::get_default_comment
virtual std::string get_default_comment(const char *path)
Definition: yaml.cpp:913
fawkes::YamlConfiguration::YamlValueIterator::get_list_size
virtual size_t get_list_size() const
Definition: yaml.cpp:174
fawkes::YamlConfiguration::YamlValueIterator::get_comment
virtual std::string get_comment() const
Definition: yaml.cpp:289
fawkes::YamlConfiguration::get_int
virtual int get_int(const char *path)
Definition: yaml.cpp:800
fawkes::LibLogger::log_warn
static void log_warn(const char *component, const char *format,...)
Log warning message.
Definition: liblogger.cpp:162
fawkes::YamlConfiguration::~YamlConfiguration
virtual ~YamlConfiguration()
Destructor.
Definition: yaml.cpp:353
fawkes
fawkes::YamlConfiguration::YamlValueIterator::is_string
virtual bool is_string() const
Definition: yaml.cpp:156
fawkes::YamlConfiguration::lock
void lock()
Lock the config.
Definition: yaml.cpp:1122
fawkes::YamlConfiguration::get_string
virtual std::string get_string(const char *path)
Definition: yaml.cpp:812
fawkes::YamlConfiguration::get_bools
virtual std::vector< bool > get_bools(const char *path)
Definition: yaml.cpp:836
fawkes::YamlConfiguration::is_int
virtual bool is_int(const char *path)
Definition: yaml.cpp:885
fawkes::YamlConfiguration::is_default
virtual bool is_default(const char *path)
Definition: yaml.cpp:919
fawkes::YamlConfiguration::YamlValueIterator::get_string
virtual std::string get_string() const
Definition: yaml.cpp:222
fawkes::YamlConfiguration::get_bool
virtual bool get_bool(const char *path)
Definition: yaml.cpp:806
fawkes::YamlConfiguration::set_default_float
virtual void set_default_float(const char *path, float f)
Definition: yaml.cpp:1064
fawkes::YamlConfiguration::set_default_int
virtual void set_default_int(const char *path, int i)
Definition: yaml.cpp:1076
fawkes::YamlConfiguration::get_floats
virtual std::vector< float > get_floats(const char *path)
Definition: yaml.cpp:818
fawkes::YamlConfiguration::YamlValueIterator::get_float
virtual float get_float() const
Definition: yaml.cpp:186
fawkes::Mutex::try_lock
bool try_lock()
Tries to lock the mutex.
Definition: mutex.cpp:123
fawkes::is_type
static bool is_type(std::shared_ptr< YamlConfigurationNode > root, const char *path)
Check if value is of given type T.
Definition: memory.cpp:201
fawkes::YamlConfiguration::is_uint
virtual bool is_uint(const char *path)
Definition: yaml.cpp:870
fawkes::NotImplementedException
Definition: software.h:110
fawkes::YamlConfiguration::search
ValueIterator * search(const char *path)
Definition: yaml.cpp:1166
fawkes::YamlConfiguration::YamlValueIterator::get_as_string
virtual std::string get_as_string() const
Definition: yaml.cpp:231
fawkes::Thread::start
void start(bool wait=true)
Call this method to start the thread.
Definition: thread.cpp:505
fawkes::FamThread::get_fam
RefPtr< FileAlterationMonitor > get_fam()
Get FileAlterationMonitor.
Definition: fam_thread.cpp:61
fawkes::YamlConfiguration::YamlValueIterator::get_bool
virtual bool get_bool() const
Definition: yaml.cpp:213
fawkes::get_value_as
static T get_value_as(std::shared_ptr< YamlConfigurationNode > root, const char *path)
Retrieve value casted to given type T.
Definition: memory.cpp:107
fawkes::YamlConfiguration::try_lock
bool try_lock()
Try to lock the config.
Definition: yaml.cpp:1132
fawkes::YamlConfiguration::YamlValueIterator::path
virtual const char * path() const
Definition: yaml.cpp:102
fawkes::YamlConfiguration::YamlValueIterator::type
virtual const char * type() const
Definition: yaml.cpp:111
fawkes::Thread::cancel
void cancel()
Cancel a thread.
Definition: thread.cpp:652
fawkes::abs_cfg_path
static std::string abs_cfg_path(const std::string &path)
Create absolute config path.
Definition: yaml.cpp:584
fawkes::YamlConfiguration::get_comment
virtual std::string get_comment(const char *path)
Definition: yaml.cpp:746
fawkes::YamlConfiguration::set_default_uint
virtual void set_default_uint(const char *path, unsigned int uint)
Definition: yaml.cpp:1070
fawkes::YamlConfiguration::set_ints
virtual void set_ints(const char *path, std::vector< int > &i)
Definition: yaml.cpp:1010
fawkes::Configuration::notify_handlers
void notify_handlers(const char *path, bool comment_changed=false)
Notify handlers for given path.
Definition: config.cpp:680
fawkes::YamlConfiguration::erase
virtual void erase(const char *path)
Definition: yaml.cpp:1056
fawkes::YamlConfiguration::set_bools
virtual void set_bools(const char *path, std::vector< bool > &b)
Definition: yaml.cpp:1019
fawkes::YamlConfiguration::set_default_bool
virtual void set_default_bool(const char *path, bool b)
Definition: yaml.cpp:1082
fawkes::YamlConfiguration::YamlValueIterator::is_bool
virtual bool is_bool() const
Definition: yaml.cpp:147
fawkes::YamlConfiguration::YamlValueIterator::get_strings
virtual std::vector< std::string > get_strings() const
Definition: yaml.cpp:280
fawkes::YamlConfiguration::is_bool
virtual bool is_bool(const char *path)
Definition: yaml.cpp:891
fawkes::YamlConfiguration::iterator
ValueIterator * iterator()
Definition: yaml.cpp:1158
fawkes::Thread::join
void join()
Join the thread.
Definition: thread.cpp:603
fawkes::YamlConfiguration::get_float
virtual float get_float(const char *path)
Definition: yaml.cpp:788
fawkes::YamlConfiguration::YamlValueIterator::is_float
virtual bool is_float() const
Definition: yaml.cpp:120
fawkes::YamlConfiguration::copy
virtual void copy(Configuration *copyconf)
Definition: yaml.cpp:718
fawkes::str_split_to_queue
static std::queue< std::string > str_split_to_queue(const std::string &s, char delim='/')
Split string by delimiter.
Definition: string_split.h:208
fawkes::YamlConfiguration::erase_default
virtual void erase_default(const char *path)
Definition: yaml.cpp:1112
fawkes::Exception
Definition: exception.h:41