Fawkes API  Fawkes Development Version
main.cpp
1 
2 /***************************************************************************
3  * main.cpp - Fawkes config tool
4  *
5  * Created: Mon Jan 08 16:43:45 2007
6  * Copyright 2006-2007 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.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU Library General Public License for more details.
19  *
20  * Read the full text in the LICENSE.GPL file in the doc directory.
21  */
22 
23 #include <netcomm/fawkes/client.h>
24 #include <config/netconf.h>
25 #include <config/change_handler.h>
26 #include <utils/system/argparser.h>
27 #include <utils/system/signal.h>
28 
29 #include <iostream>
30 #include <cstring>
31 #include <cstdlib>
32 #include <cstdio>
33 
34 using namespace fawkes;
35 
36 /** Tool to watch and output config changes.
37  */
40 {
41  public:
42 
43  /** Constructor.
44  * @param config Configuration to watch
45  * @param c network client, thread is cancelled on signal
46  */
49  {
50  this->c = c;
51  this->config = config;
52  quit = false;
53  config->add_change_handler(this);
54  }
55 
56  virtual void handle_signal(int signal)
57  {
58  config->rem_change_handler(this);
59  quit = true;
60  }
61 
62  virtual void config_tag_changed(const char *new_tag)
63  {
64  printf("--> New tag loaded: %s\n", new_tag);
65  }
66 
68  {
69  printf("%s %-55s| %-8s| %-14s\n", v->is_default() ? "*" : " ",
70  v->path(), v->type(), v->get_as_string().c_str());
71  }
72 
74  {
75  printf("%s %s: %s\n", v->is_default() ? "C" : "c",
76  v->path(), v->get_comment().c_str());
77  }
78 
79  virtual void config_value_erased(const char *path)
80  {
81  printf(" %-55s| %-8s| %-14s\n", path, "", "ERASED");
82  }
83 
84 
85  /** Run.
86  * This joins the network thread.
87  */
88  void
89  run()
90  {
91  while ( ! quit ) {
92  c->wait(FAWKES_CID_CONFIGMANAGER);
93  }
94  }
95 
96  private:
98  Configuration *config;
99  bool quit;
100 
101 };
102 
103 
104 /** Print header. */
105 void
106 print_header()
107 {
108  printf("D %-55s| %-8s| %-14s\n", "Path", "Type", "Value");
109  printf("--------------------------------------------------------------------------------------\n");
110 }
111 
112 /** Print a single value.
113  * @param i config item to print.
114  */
115 void
116 print_line(Configuration::ValueIterator *i, bool show_comment = false)
117 {
118  if (i->is_list()) {
119  printf("%s %-55s| %-8s| LIST (values below)\n", (i->is_default() ? "*" : " "),
120  i->path(), i->type());
121  if ( i->is_uint() ) {
122  std::vector<unsigned int> values = i->get_uints();
123  for (size_t j = 0; j < values.size(); ++j) {
124  printf(" %-67s%-14u\n", "", values[j]);
125  }
126  } else if ( i->is_int() ) {
127  std::vector<int> values = i->get_ints();
128  for (size_t j = 0; j < values.size(); ++j) {
129  printf(" %-67s%-14i\n", "", values[j]);
130  }
131  } else if ( i->is_bool() ) {
132  std::vector<bool> values = i->get_bools();
133  for (size_t j = 0; j < values.size(); ++j) {
134  printf(" %-67s%-14s\n", "", values[j] ? "true" : "false");
135  }
136  } else if ( i->is_float() ) {
137  std::vector<float> values = i->get_floats();
138  for (size_t j = 0; j < values.size(); ++j) {
139  printf(" %-67s%-14f\n", "", values[j]);
140  }
141  } else if ( i->is_string() ) {
142  std::vector<std::string> values = i->get_strings();
143  for (size_t j = 0; j < values.size(); ++j) {
144  printf(" %-67s%-14s\n", "", values[j].c_str());
145  }
146  } else {
147  printf("%s %-55s| UNKNOWN LIST TYPE\n", (i->is_default() ? "*" : " "), i->path());
148  }
149  } else {
150  if ( i->is_uint() ) {
151  printf("%s %-55s| %-8s| %-14u\n", (i->is_default() ? "*" : " "), i->path(), "uint", i->get_uint());
152  } else if ( i->is_int() ) {
153  printf("%s %-55s| %-8s| %-14i\n", (i->is_default() ? "*" : " "), i->path(), i->type(), i->get_int());
154  } else if ( i->is_bool() ) {
155  printf("%s %-55s| %-8s| %-14s\n", (i->is_default() ? "*" : " "), i->path(), i->type(), (i->get_bool() ? "true" : "false"));
156  } else if ( i->is_float() ) {
157  printf("%s %-55s| %-8s| %-14f\n", (i->is_default() ? "*" : " "), i->path(), i->type(), i->get_float());
158  } else if ( i->is_string() ) {
159  printf("%s %-55s| %-8s| %-14s\n", (i->is_default() ? "*" : " "), i->path(), i->type(), i->get_string().c_str());
160  } else {
161  printf("%s %-55s| UNKNOWN TYPE\n", (i->is_default() ? "*" : " "), i->path());
162  }
163 
164  if (show_comment) {
165  try {
166  std::string comment = i->get_comment();
167  if (comment != "") {
168  printf("C %-55s: %s\n", i->path(), comment.c_str());
169  }
170  } catch (Exception &e) {
171  // maybe there is no comment, ignore it...
172  }
173  }
174  }
175 }
176 
177 /** Print a line of output.
178  * @param i config item to print.
179  */
180 void
181 print_value(Configuration::ValueIterator *i, bool show_comment = false)
182 {
183  if ( i->is_list()) {
184  printf("%-14s\n", "LIST");
185  } else {
186  if ( i->is_uint() ) {
187  printf("%-14u\n", i->get_uint());
188  } else if ( i->is_int() ) {
189  printf("%-14i\n", i->get_int());
190  } else if ( i->is_bool() ) {
191  printf("%-14s\n", (i->get_bool() ? "true" : "false"));
192  } else if ( i->is_float() ) {
193  printf("%-14f\n", i->get_float());
194  } else if ( i->is_string() ) {
195  printf("%-14s\n", i->get_string().c_str());
196  }
197  }
198 }
199 
200 
201 void
202 print_usage(const char *program_name)
203 {
204  std::cout << "Usage: " << program_name << " [options] <cmd>" << std::endl
205  << "where cmd is one of the following:" << std::endl << std::endl
206  << " list" << std::endl
207  << " List all configuration items" << std::endl << std::endl
208  << " watch" << std::endl
209  << " Watch configuration changes" << std::endl << std::endl
210  << " get <path>" << std::endl
211  << " Get value for the given path" << std::endl << std::endl
212  << " set <path> <value> [type]" << std::endl
213  << " Set value for the given path to the given type and value" << std::endl
214  << " where type is one of float/uint/int/bool/string. The type" << std::endl
215  << " is only necessary if you are creating a new value" << std::endl << std::endl
216  << " set_default <path> <value> [type]" << std::endl
217  << " Set default value for the given path to the given type and value" << std::endl
218  << " where type is one of float/uint/int/bool/string. The type" << std::endl
219  << " is only necessary if you are creating a new value" << std::endl << std::endl
220  << " set_comment <path> <comment>" << std::endl
221  << " Set comment for the given path to the given value. The value at" << std::endl
222  << " the given path must already exist in the host-specific configuration." << std::endl << std::endl
223  << " set_default_comment <path> <comment>" << std::endl
224  << " Set default comment for the given path to the given value. The value at" << std::endl
225  << " the given path must already exist in the default configuration." << std::endl << std::endl
226  << " erase <path>" << std::endl
227  << " Erase value for given path from config" << std::endl
228  << " erase_default <path>" << std::endl
229  << " Erase default value for given path from config" << std::endl << std::endl
230  << "and options is none, one or more of the following:" << std::endl << std::endl
231  << " -c Show comments (only available with list and watch cmd)" << std::endl
232  << " -a Show all values, even double if default and host-specific " << std::endl
233  << " values exist (only available with list)" << std::endl
234  << " -q Quiet. Only show important output, suitable for parsing. " << std::endl
235  << " (not supported for all commands yet) " << std::endl
236  << " -r host[:port] Remote host (and optionally port) to connect to\n" << std::endl
237  << std::endl;
238 }
239 
240 /** Config tool main.
241  * @param argc argument count
242  * @param argv arguments
243  */
244 int
245 main(int argc, char **argv)
246 {
247  ArgumentParser argp(argc, argv, "+hcar:q");
248 
249  if ( argp.has_arg("h") ) {
250  print_usage(argv[0]);
251  exit(0);
252  }
253 
254  std::string host = "localhost";
255  unsigned short int port = 1910;
256  if ( argp.has_arg("r") ) {
257  argp.parse_hostport("r", host, port);
258  }
259 
260  bool quiet;
261  if ( argp.has_arg("q") ) {
262  quiet = true;
263  } else {
264  quiet = false;
265  }
266 
267  FawkesNetworkClient *c = new FawkesNetworkClient(host.c_str(), port);
268  try {
269  c->connect();
270  } catch( Exception &e ) {
271  printf("Could not connect to host: %s\n", host.c_str());
272  exit(1);
273  }
274 
275  NetworkConfiguration *netconf = new NetworkConfiguration(c);
276 
277  const std::vector< const char* > & args = argp.items();
278 
279  if ( args.size() == 0) {
280  // show usage
281  printf("Not enough args\n\n");
282  print_usage(argv[0]);
283  } else if (strcmp("get", args[0]) == 0) {
284  if (args.size() == 2) {
285  if( ! quiet ) {
286  printf("Requesting value %s\n", args[1]);
287  }
288  Configuration::ValueIterator *i = netconf->get_value(args[1]);
289  if ( i->next() ) {
290  if( quiet ) {
291  print_value(i);
292  } else {
293  print_header();
294  print_line(i);
295  }
296  } else {
297  printf("No such value found!\n");
298  }
299  delete i;
300  } else {
301  // Error!
302  printf("You must supply path argument\n");
303  }
304  } else if ((strcmp("set", args[0]) == 0) || (strcmp("set_default", args[0]) == 0)) {
305  bool set_def = (strcmp("set_default", args[0]) == 0);
306  if (args.size() >= 3) {
307  // we have at least "set path value"
308  printf("Requesting old value for %s\n", args[1]);
309  Configuration::ValueIterator *i = netconf->get_value(args[1]);
310  print_header();
311  printf("OLD:\n");
312  if ( i->next() ) {
313  print_line(i);
314  } else {
315  printf("Value does not currently exist in configuration.\n");
316  }
317 
318  std::string desired_type = "";
319  if (args.size() == 4) {
320  // we have "set path value type"
321  desired_type = args[3];
322  }
323 
324  if ( (desired_type == "") && ! i->valid()) {
325  printf("Please specify type\n");
326  delete i;
327  } else if ( (desired_type != "") && (i->valid() && (desired_type != i->type())) ) {
328  printf("The given type '%s' contradicts with type '%s' in config. "
329  "Erase before setting with new type.\n", desired_type.c_str(), i->type());
330  delete i;
331  } else {
332  if ( i->valid() ) desired_type = i->type();
333 
334  if ( desired_type == "float" ) {
335  char *endptr;
336  float f = strtod(args[2], &endptr);
337  if ( endptr[0] != 0 ) {
338  printf("ERROR: '%s' is not a float\n", args[2]);
339  } else {
340  if ( ! set_def ) {
341  netconf->set_float(args[1], f);
342  } else {
343  netconf->set_default_float(args[1], f);
344  }
345  }
346  } else if ( (desired_type == "unsigned int") || (desired_type == "uint") ) {
347  char *endptr;
348  long int li = strtol(args[2], &endptr, 10);
349  if ( (endptr[0] != 0) || (li < 0) ) {
350  printf("ERROR: '%s' is not an unsigned int\n", args[2]);
351  } else {
352  if ( ! set_def ) {
353  netconf->set_uint(args[1], li);
354  } else {
355  netconf->set_default_uint(args[1], li);
356  }
357  }
358  } else if ( desired_type == "int" ) {
359  char *endptr;
360  long int li = strtol(args[2], &endptr, 10);
361  if ( endptr[0] != 0 ) {
362  printf("ERROR: '%s' is not an int\n", args[2]);
363  } else {
364  if ( ! set_def ) {
365  netconf->set_int(args[1], li);
366  } else {
367  netconf->set_default_int(args[1], li);
368  }
369  }
370  } else if ( desired_type == "bool" ) {
371  bool valid = false;
372  bool b;
373  if ( strcasecmp("true", args[2]) == 0 ) {
374  b = true;
375  valid = true;
376  } else if ( strcasecmp("false", args[2]) == 0 ) {
377  b = false;
378  valid = true;
379  } else {
380  printf("ERROR: '%s' is not a boolean.\n", args[2]);
381  }
382  if (valid) {
383  if ( ! set_def ) {
384  netconf->set_bool(args[1], b);
385  } else {
386  netconf->set_default_bool(args[1], b);
387  }
388  }
389  } else if ( desired_type == "string" ) {
390  if ( ! set_def ) {
391  netconf->set_string(args[1], args[2]);
392  } else {
393  netconf->set_default_string(args[1], args[2]);
394  }
395  } else {
396  printf("Invalid type: %s\n", desired_type.c_str());
397  }
398 
399  delete i;
400 
401  printf("NEW:\n");
402  i = netconf->get_value(args[1]);
403  if ( i->next() ) {
404  print_line(i);
405  } else {
406  printf("ERROR: value does not exist\n");
407  }
408  delete i;
409 
410  }
411  } else {
412  printf("Usage: %s set <path> <value> [type]\n", argp.program_name());
413  }
414  } else if ((strcmp("set_comment", args[0]) == 0) ||
415  (strcmp("set_default_comment", args[0]) == 0)) {
416  bool set_def = (strcmp("set_default_comment", args[0]) == 0);
417  if (args.size() >= 3) {
418  // we have at least "set_comment path value"
419 
420  if ( ! set_def ) {
421  netconf->set_comment(args[1], args[2]);
422  } else {
423  netconf->set_default_comment(args[1], args[2]);
424  }
425 
426  } else {
427  printf("Usage: %s set_(default_)comment <path> <value>\n", argp.program_name());
428  }
429  } else if ((strcmp("erase", args[0]) == 0) || (strcmp("erase_default", args[0]) == 0)) {
430  bool erase_def = (strcmp("erase_default", args[0]) == 0);
431  if (args.size() == 2) {
432  printf("Erasing %svalue %s\n", (erase_def ? "default " : ""), args[1]);
433  bool found = false;
434  Configuration::ValueIterator *i = netconf->get_value(args[1]);
435  if ( i->next() ) {
436  print_header();
437  print_line(i);
438  found = true;
439  } else {
440  printf("No such value found!\n");
441  }
442  delete i;
443  if ( found ) {
444  if ( erase_def ) {
445  netconf->erase_default(args[1]);
446  } else {
447  netconf->erase(args[1]);
448  }
449  i = netconf->get_value(args[1]);
450  if ( i->next() ) {
451  printf("Failed to erase %s (default vs. non-default?)\n", args[1]);
452  } else {
453  printf("Successfully erased %s\n", args[1]);
454  }
455  delete i;
456  }
457  } else {
458  // Error!
459  printf("You must supply path argument\n");
460  }
461  } else if (strcmp("watch", args[0]) == 0) {
462  try {
463  netconf->set_mirror_mode(true);
464  } catch (Exception &e) {
465  e.print_trace();
466  return -1;
467  }
468  print_header();
469  netconf->lock();
470  Configuration::ValueIterator *i = netconf->iterator();
471  while ( i->next() ) {
472  print_line(i, argp.has_arg("c"));
473  }
474  delete i;
475  netconf->unlock();
476  printf("------------------------------------------------------------------------------------\n");
477  printf("Modifications since watching:\n");
478  printf("------------------------------------------------------------------------------------\n");
479  ConfigChangeWatcherTool ccwt(netconf, c);
480  ccwt.run();
481  } else if (strcmp("list", args[0]) == 0) {
482  printf("Transmitting config from host... ");
483  fflush(stdout);
484  try {
485  netconf->set_mirror_mode(true);
486  } catch (Exception &e) {
487  e.print_trace();
488  return -1;
489  }
490  netconf->lock();
491  printf("done\n");
492  print_header();
493  bool show_comments = argp.has_arg("c");
494  if (argp.has_arg("a")) {
495  printf("DEFAULT ENTRIES\n");
497  while ( i->next() ) {
498  print_line(i, show_comments);
499  }
500  delete i;
501  printf("HOST-SPECIFIC ENTRIES\n");
502  i = netconf->iterator_hostspecific();
503  while ( i->next() ) {
504  print_line(i, show_comments);
505  }
506  delete i;
507  } else {
508  Configuration::ValueIterator *i = netconf->iterator();
509  while ( i->next() ) {
510  print_line(i, show_comments);
511  }
512  delete i;
513  }
514  netconf->unlock();
515  }
516 
517  if( ! quiet ) {
518  printf("Cleaning up... ");
519  }
520  fflush(stdout);
521  delete netconf;
522  c->disconnect();
523 
524  delete c;
525  if( ! quiet ) {
526  printf("done\n");
527  }
528 
529  return 0;
530 }
virtual std::string get_comment() const =0
Get comment of value.
const char * program_name() const
Get name of program.
Definition: argparser.cpp:502
bool parse_hostport(const char *argn, char **host, unsigned short int *port)
Parse host:port string.
Definition: argparser.cpp:231
Simple Fawkes network client.
Definition: client.h:52
virtual std::vector< bool > get_bools() const =0
Get list of values from configuration which is of type bool.
const std::vector< const char *> & items() const
Get non-option items.
Definition: argparser.cpp:462
void run()
Run.
Definition: main.cpp:89
virtual std::vector< std::string > get_strings() const =0
Get list of values from configuration which is of type string.
virtual void set_float(const char *path, float f)
Set new value in configuration of type float.
Definition: netconf.cpp:751
virtual ValueIterator * get_value(const char *path)
Get value from configuration.
Definition: netconf.cpp:670
virtual std::vector< float > get_floats() const =0
Get list of values from configuration which is of type float.
virtual const char * type() const =0
Type of value.
virtual bool is_bool() const =0
Check if current value is a bool.
Fawkes library namespace.
virtual void handle_signal(int signal)
Signal hanlding method.
Definition: main.cpp:56
void disconnect()
Disconnect socket.
Definition: client.cpp:529
virtual void set_default_bool(const char *path, bool b)
Set new default value in configuration of type bool.
Definition: netconf.cpp:801
virtual void config_tag_changed(const char *new_tag)
Called whenever the tag has changed.
Definition: main.cpp:62
Interface for configuration change handling.
void lock()
Lock the config.
Definition: netconf.cpp:1374
void connect()
Connect to remote.
Definition: client.cpp:417
ValueIterator * iterator()
Iterator for all values.
Definition: netconf.cpp:1401
Interface for signal handling.
Definition: signal.h:35
Parse command line arguments.
Definition: argparser.h:66
virtual bool next()=0
Check if there is another element and advance to this if possible.
virtual void config_comment_changed(const Configuration::ValueIterator *v)
Called whenever a comment of a watched value has changed.
Definition: main.cpp:73
virtual std::vector< int > get_ints() const =0
Get list of values from configuration which is of type int.
virtual float get_float() const =0
Get float value.
virtual unsigned int get_uint() const =0
Get unsigned int value.
void unlock()
Unlock the config.
Definition: netconf.cpp:1388
ConfigChangeWatcherTool(Configuration *config, FawkesNetworkClient *c)
Constructor.
Definition: main.cpp:47
virtual bool is_float() const =0
Check if current value is a float.
virtual bool is_int() const =0
Check if current value is a int.
ValueIterator * iterator_default()
Iterator for all default values.
Definition: netconf.cpp:1419
virtual bool get_bool() const =0
Get bool value.
virtual void config_value_erased(const char *path)
Called whenever a value has been erased from the config.
Definition: main.cpp:79
virtual int get_int() const =0
Get int value.
virtual void set_default_uint(const char *path, unsigned int uint)
Set new default value in configuration of type unsigned int.
Definition: netconf.cpp:772
virtual std::string get_as_string() const =0
Get value as string.
virtual bool is_string() const =0
Check if current value is a string.
virtual std::vector< unsigned int > get_uints() const =0
Get list of values from configuration which is of type unsigned int.
virtual void set_comment(const char *path, std::string &comment)
Set new comment for existing value.
Definition: netconf.cpp:901
Base class for exceptions in Fawkes.
Definition: exception.h:36
virtual void config_value_changed(const Configuration::ValueIterator *v)
Called whenever a watched value has changed.
Definition: main.cpp:67
virtual void rem_change_handler(ConfigurationChangeHandler *h)
Remove a configuration change handler.
Definition: config.cpp:564
virtual bool is_uint() const =0
Check if current value is a unsigned int.
virtual bool is_list() const =0
Check if a value is a list.
virtual void erase(const char *path)
Erase the given value from the configuration.
Definition: netconf.cpp:941
virtual std::string get_string() const =0
Get string value.
ValueIterator * iterator_hostspecific()
Iterator for all host-specific values.
Definition: netconf.cpp:1437
virtual void set_default_float(const char *path, float f)
Set new default value in configuration of type float.
Definition: netconf.cpp:758
virtual void set_mirror_mode(bool mirror)
Enable or disable mirror mode.
Definition: netconf.cpp:1324
virtual void set_bool(const char *path, bool b)
Set new value in configuration of type bool.
Definition: netconf.cpp:793
virtual const char * path() const =0
Path of value.
virtual bool valid() const =0
Check if the current element is valid.
void print_trace()
Prints trace to stderr.
Definition: exception.cpp:619
virtual void set_default_int(const char *path, int i)
Set new default value in configuration of type int.
Definition: netconf.cpp:786
Iterator interface to iterate over config values.
Definition: config.h:72
virtual void set_int(const char *path, int i)
Set new value in configuration of type int.
Definition: netconf.cpp:779
virtual bool is_default() const =0
Check if current value was read from the default config.
virtual void add_change_handler(ConfigurationChangeHandler *h)
Add a configuration change handler.
Definition: config.cpp:547
bool has_arg(const char *argn)
Check if argument has been supplied.
Definition: argparser.cpp:169
virtual void set_default_comment(const char *path, std::string &comment)
Set new default comment for existing default configuration value.
Definition: netconf.cpp:907
Interface for configuration handling.
Definition: config.h:67
virtual void set_default_string(const char *path, std::string &s)
Set new default value in configuration of type string.
Definition: netconf.cpp:844
virtual void set_uint(const char *path, unsigned int uint)
Set new value in configuration of type unsigned int.
Definition: netconf.cpp:765
Tool to watch and output config changes.
Definition: main.cpp:38
Remote configuration via Fawkes net.
Definition: netconf.h:49
virtual void set_string(const char *path, std::string &s)
Set new value in configuration of type string.
Definition: netconf.cpp:837
virtual void erase_default(const char *path)
Erase the given default value from the configuration.
Definition: netconf.cpp:948