Fawkes API  Fawkes Development Version
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
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 
67  virtual void config_value_changed(const Configuration::ValueIterator *v)
68  {
69  printf("%s %-55s| %-8s| %-14s\n", v->is_default() ? "*" : " ",
70  v->path(), v->type(), v->get_as_string().c_str());
71  }
72 
73  virtual void config_comment_changed(const Configuration::ValueIterator *v)
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_float() ) {
119  printf("%s %-55s| %-8s| %-14f\n", (i->is_default() ? "*" : " "), i->path(), i->type(), i->get_float());
120  } else if ( i->is_uint() ) {
121  printf("%s %-55s| %-8s| %-14u\n", (i->is_default() ? "*" : " "), i->path(), "uint", i->get_uint());
122  } else if ( i->is_int() ) {
123  printf("%s %-55s| %-8s| %-14i\n", (i->is_default() ? "*" : " "), i->path(), i->type(), i->get_int());
124  } else if ( i->is_bool() ) {
125  printf("%s %-55s| %-8s| %-14s\n", (i->is_default() ? "*" : " "), i->path(), i->type(), (i->get_bool() ? "true" : "false"));
126  } else if ( i->is_string() ) {
127  printf("%s %-55s| %-8s| %-14s\n", (i->is_default() ? "*" : " "), i->path(), i->type(), i->get_string().c_str());
128  }
129 
130  if (show_comment) {
131  try {
132  std::string comment = i->get_comment();
133  if (comment != "") {
134  printf("C %-55s: %s\n", i->path(), comment.c_str());
135  }
136  } catch (Exception &e) {
137  // maybe there is no comment, ignore it...
138  }
139  }
140 }
141 
142 /** Print a line of output.
143  * @param i config item to print.
144  */
145 void
146 print_value(Configuration::ValueIterator *i, bool show_comment = false)
147 {
148  if ( i->is_float() ) {
149  printf("%-14f\n", i->get_float());
150  } else if ( i->is_uint() ) {
151  printf("%-14u\n", i->get_uint());
152  } else if ( i->is_int() ) {
153  printf("%-14i\n", i->get_int());
154  } else if ( i->is_bool() ) {
155  printf("%-14s\n", (i->get_bool() ? "true" : "false"));
156  } else if ( i->is_string() ) {
157  printf("%-14s\n", i->get_string().c_str());
158  }
159 }
160 
161 
162 void
163 print_usage(const char *program_name)
164 {
165  std::cout << "Usage: " << program_name << " [options] <cmd>" << std::endl
166  << "where cmd is one of the following:" << std::endl << std::endl
167  << " list" << std::endl
168  << " List all configuration items" << std::endl << std::endl
169  << " watch" << std::endl
170  << " Watch configuration changes" << std::endl << std::endl
171  << " get <path>" << std::endl
172  << " Get value for the given path" << std::endl << std::endl
173  << " set <path> <value> [type]" << std::endl
174  << " Set value for the given path to the given type and value" << std::endl
175  << " where type is one of float/uint/int/bool/string. The type" << std::endl
176  << " is only necessary if you are creating a new value" << std::endl << std::endl
177  << " set_default <path> <value> [type]" << std::endl
178  << " Set default value for the given path to the given type and value" << std::endl
179  << " where type is one of float/uint/int/bool/string. The type" << std::endl
180  << " is only necessary if you are creating a new value" << std::endl << std::endl
181  << " set_comment <path> <comment>" << std::endl
182  << " Set comment for the given path to the given value. The value at" << std::endl
183  << " the given path must already exist in the host-specific configuration." << std::endl << std::endl
184  << " set_default_comment <path> <comment>" << std::endl
185  << " Set default comment for the given path to the given value. The value at" << std::endl
186  << " the given path must already exist in the default configuration." << std::endl << std::endl
187  << " erase <path>" << std::endl
188  << " Erase value for given path from config" << std::endl
189  << " erase_default <path>" << std::endl
190  << " Erase default value for given path from config" << std::endl << std::endl
191  << "and options is none, one or more of the following:" << std::endl << std::endl
192  << " -c Show comments (only available with list and watch cmd)" << std::endl
193  << " -a Show all values, even double if default and host-specific " << std::endl
194  << " values exist (only available with list)" << std::endl
195  << " -q Quiet. Only show important output, suitable for parsing. " << std::endl
196  << " (not supported for all commands yet) " << std::endl
197  << " -r host[:port] Remote host (and optionally port) to connect to\n" << std::endl
198  << std::endl;
199 }
200 
201 /** Config tool main.
202  * @param argc argument count
203  * @param argv arguments
204  */
205 int
206 main(int argc, char **argv)
207 {
208  ArgumentParser argp(argc, argv, "+hcar:q");
209 
210  if ( argp.has_arg("h") ) {
211  print_usage(argv[0]);
212  exit(0);
213  }
214 
215  std::string host = "localhost";
216  unsigned short int port = 1910;
217  if ( argp.has_arg("r") ) {
218  argp.parse_hostport("r", host, port);
219  }
220 
221  bool quiet;
222  if ( argp.has_arg("q") ) {
223  quiet = true;
224  } else {
225  quiet = false;
226  }
227 
228  FawkesNetworkClient *c = new FawkesNetworkClient(host.c_str(), port);
229  try {
230  c->connect();
231  } catch( Exception &e ) {
232  printf("Could not connect to host: %s\n", host.c_str());
233  exit(1);
234  }
235 
236  NetworkConfiguration *netconf = new NetworkConfiguration(c);
237 
238  const std::vector< const char* > & args = argp.items();
239 
240  if ( args.size() == 0) {
241  // show usage
242  printf("Not enough args\n\n");
243  print_usage(argv[0]);
244  } else if (strcmp("get", args[0]) == 0) {
245  if (args.size() == 2) {
246  if( ! quiet ) {
247  printf("Requesting value %s\n", args[1]);
248  }
249  Configuration::ValueIterator *i = netconf->get_value(args[1]);
250  if ( i->next() ) {
251  if( quiet ) {
252  print_value(i);
253  } else {
254  print_header();
255  print_line(i);
256  }
257  } else {
258  printf("No such value found!\n");
259  }
260  delete i;
261  } else {
262  // Error!
263  printf("You must supply path argument\n");
264  }
265  } else if ((strcmp("set", args[0]) == 0) || (strcmp("set_default", args[0]) == 0)) {
266  bool set_def = (strcmp("set_default", args[0]) == 0);
267  if (args.size() >= 3) {
268  // we have at least "set path value"
269  printf("Requesting old value for %s\n", args[1]);
270  Configuration::ValueIterator *i = netconf->get_value(args[1]);
271  print_header();
272  printf("OLD:\n");
273  if ( i->next() ) {
274  print_line(i);
275  } else {
276  printf("Value does not currently exist in configuration.\n");
277  }
278 
279  std::string desired_type = "";
280  if (args.size() == 4) {
281  // we have "set path value type"
282  desired_type = args[3];
283  }
284 
285  if ( (desired_type == "") && ! i->valid()) {
286  printf("Please specify type\n");
287  delete i;
288  } else if ( (desired_type != "") && (i->valid() && (desired_type != i->type())) ) {
289  printf("The given type '%s' contradicts with type '%s' in config. "
290  "Erase before setting with new type.\n", desired_type.c_str(), i->type());
291  delete i;
292  } else {
293  if ( i->valid() ) desired_type = i->type();
294 
295  if ( desired_type == "float" ) {
296  char *endptr;
297  float f = strtod(args[2], &endptr);
298  if ( endptr[0] != 0 ) {
299  printf("ERROR: '%s' is not a float\n", args[2]);
300  } else {
301  if ( ! set_def ) {
302  netconf->set_float(args[1], f);
303  } else {
304  netconf->set_default_float(args[1], f);
305  }
306  }
307  } else if ( (desired_type == "unsigned int") || (desired_type == "uint") ) {
308  char *endptr;
309  long int li = strtol(args[2], &endptr, 10);
310  if ( (endptr[0] != 0) || (li < 0) ) {
311  printf("ERROR: '%s' is not an unsigned int\n", args[2]);
312  } else {
313  if ( ! set_def ) {
314  netconf->set_uint(args[1], li);
315  } else {
316  netconf->set_default_uint(args[1], li);
317  }
318  }
319  } else if ( desired_type == "int" ) {
320  char *endptr;
321  long int li = strtol(args[2], &endptr, 10);
322  if ( endptr[0] != 0 ) {
323  printf("ERROR: '%s' is not an int\n", args[2]);
324  } else {
325  if ( ! set_def ) {
326  netconf->set_int(args[1], li);
327  } else {
328  netconf->set_default_int(args[1], li);
329  }
330  }
331  } else if ( desired_type == "bool" ) {
332  bool valid = false;
333  bool b;
334  if ( strcasecmp("true", args[2]) == 0 ) {
335  b = true;
336  valid = true;
337  } else if ( strcasecmp("false", args[2]) == 0 ) {
338  b = false;
339  valid = true;
340  } else {
341  printf("ERROR: '%s' is not a boolean.\n", args[2]);
342  }
343  if (valid) {
344  if ( ! set_def ) {
345  netconf->set_bool(args[1], b);
346  } else {
347  netconf->set_default_bool(args[1], b);
348  }
349  }
350  } else if ( desired_type == "string" ) {
351  if ( ! set_def ) {
352  netconf->set_string(args[1], args[2]);
353  } else {
354  netconf->set_default_string(args[1], args[2]);
355  }
356  } else {
357  printf("Invalid type: %s\n", desired_type.c_str());
358  }
359 
360  delete i;
361 
362  printf("NEW:\n");
363  i = netconf->get_value(args[1]);
364  if ( i->next() ) {
365  print_line(i);
366  } else {
367  printf("ERROR: value does not exist\n");
368  }
369  delete i;
370 
371  }
372  } else {
373  printf("Usage: %s set <path> <value> [type]\n", argp.program_name());
374  }
375  } else if ((strcmp("set_comment", args[0]) == 0) ||
376  (strcmp("set_default_comment", args[0]) == 0)) {
377  bool set_def = (strcmp("set_default_comment", args[0]) == 0);
378  if (args.size() >= 3) {
379  // we have at least "set_comment path value"
380 
381  if ( ! set_def ) {
382  netconf->set_comment(args[1], args[2]);
383  } else {
384  netconf->set_default_comment(args[1], args[2]);
385  }
386 
387  } else {
388  printf("Usage: %s set_(default_)comment <path> <value>\n", argp.program_name());
389  }
390  } else if ((strcmp("erase", args[0]) == 0) || (strcmp("erase_default", args[0]) == 0)) {
391  bool erase_def = (strcmp("erase_default", args[0]) == 0);
392  if (args.size() == 2) {
393  printf("Erasing %svalue %s\n", (erase_def ? "default " : ""), args[1]);
394  bool found = false;
395  Configuration::ValueIterator *i = netconf->get_value(args[1]);
396  if ( i->next() ) {
397  print_header();
398  print_line(i);
399  found = true;
400  } else {
401  printf("No such value found!\n");
402  }
403  delete i;
404  if ( found ) {
405  if ( erase_def ) {
406  netconf->erase_default(args[1]);
407  } else {
408  netconf->erase(args[1]);
409  }
410  i = netconf->get_value(args[1]);
411  if ( i->next() ) {
412  printf("Failed to erase %s (default vs. non-default?)\n", args[1]);
413  } else {
414  printf("Successfully erased %s\n", args[1]);
415  }
416  delete i;
417  }
418  } else {
419  // Error!
420  printf("You must supply path argument\n");
421  }
422  } else if (strcmp("watch", args[0]) == 0) {
423  try {
424  netconf->set_mirror_mode(true);
425  } catch (Exception &e) {
426  e.print_trace();
427  return -1;
428  }
429  print_header();
430  netconf->lock();
431  Configuration::ValueIterator *i = netconf->iterator();
432  while ( i->next() ) {
433  print_line(i, argp.has_arg("c"));
434  }
435  delete i;
436  netconf->unlock();
437  printf("------------------------------------------------------------------------------------\n");
438  printf("Modifications since watching:\n");
439  printf("------------------------------------------------------------------------------------\n");
440  ConfigChangeWatcherTool ccwt(netconf, c);
441  ccwt.run();
442  } else if (strcmp("list", args[0]) == 0) {
443  printf("Transmitting config from host... ");
444  fflush(stdout);
445  try {
446  netconf->set_mirror_mode(true);
447  } catch (Exception &e) {
448  e.print_trace();
449  return -1;
450  }
451  netconf->lock();
452  printf("done\n");
453  print_header();
454  bool show_comments = argp.has_arg("c");
455  if (argp.has_arg("a")) {
456  printf("DEFAULT ENTRIES\n");
458  while ( i->next() ) {
459  print_line(i, show_comments);
460  }
461  delete i;
462  printf("HOST-SPECIFIC ENTRIES\n");
463  i = netconf->iterator_hostspecific();
464  while ( i->next() ) {
465  print_line(i, show_comments);
466  }
467  delete i;
468  } else {
469  Configuration::ValueIterator *i = netconf->iterator();
470  while ( i->next() ) {
471  print_line(i, show_comments);
472  }
473  delete i;
474  }
475  netconf->unlock();
476  }
477 
478  if( ! quiet ) {
479  printf("Cleaning up... ");
480  }
481  fflush(stdout);
482  delete netconf;
483  c->disconnect();
484 
485  delete c;
486  if( ! quiet ) {
487  printf("done\n");
488  }
489 
490  return 0;
491 }