Fawkes API
Fawkes Development Version
|
00001 00002 /*************************************************************************** 00003 * main.cpp - Fawkes config tool 00004 * 00005 * Created: Mon Jan 08 16:43:45 2007 00006 * Copyright 2006-2007 Tim Niemueller [www.niemueller.de] 00007 * 00008 ****************************************************************************/ 00009 00010 /* This program is free software; you can redistribute it and/or modify 00011 * it under the terms of the GNU General Public License as published by 00012 * the Free Software Foundation; either version 2 of the License, or 00013 * (at your option) any later version. 00014 * 00015 * This program is distributed in the hope that it will be useful, 00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 * GNU Library General Public License for more details. 00019 * 00020 * Read the full text in the LICENSE.GPL file in the doc directory. 00021 */ 00022 00023 #include <netcomm/fawkes/client.h> 00024 #include <config/netconf.h> 00025 #include <utils/system/argparser.h> 00026 #include <utils/system/signal.h> 00027 00028 #include <iostream> 00029 #include <cstring> 00030 #include <cstdlib> 00031 #include <cstdio> 00032 00033 using namespace fawkes; 00034 00035 /** Tool to watch and output config changes. 00036 */ 00037 class ConfigChangeWatcherTool : public ConfigurationChangeHandler, public SignalHandler 00038 { 00039 public: 00040 00041 /** Constructor. 00042 * @param config Configuration to watch 00043 * @param c network client, thread is cancelled on signal 00044 */ 00045 ConfigChangeWatcherTool(Configuration *config, FawkesNetworkClient *c) 00046 { 00047 this->c = c; 00048 this->config = config; 00049 quit = false; 00050 config->add_change_handler(this); 00051 } 00052 00053 virtual void handle_signal(int signal) 00054 { 00055 config->rem_change_handler(this); 00056 quit = true; 00057 } 00058 00059 virtual void config_tag_changed(const char *new_tag) 00060 { 00061 printf("--> New tag loaded: %s\n", new_tag); 00062 } 00063 00064 virtual void config_value_changed(const char *path, bool is_default, int value) 00065 { 00066 printf("%s %-55s| %-8s| %-14i\n", is_default ? "*" : " ", path, "int", value); 00067 } 00068 00069 virtual void config_value_changed(const char *path, bool is_default, unsigned int value) 00070 { 00071 printf("%s %-55s| %-8s| %-14u\n", is_default ? "*" : " ", path, "uint", value); 00072 } 00073 00074 virtual void config_value_changed(const char *path, bool is_default, float value) 00075 { 00076 printf("%s %-55s| %-8s| %-14f\n", is_default ? "*" : " ", path, "float", value); 00077 } 00078 00079 virtual void config_value_changed(const char *path, bool is_default, bool value) 00080 { 00081 printf("%s %-55s| %-8s| %-14s\n", is_default ? "*" : " ", path, "bool", (value ? "true" : "false")); 00082 } 00083 00084 virtual void config_value_changed(const char *path, bool is_default, const char *value) 00085 { 00086 printf("%s %-55s| %-8s| %-14s\n", is_default ? "*" : " ", path, "string", value); 00087 } 00088 00089 virtual void config_comment_changed(const char *path, bool is_default, const char *comment) 00090 { 00091 printf("%s %s: %s\n", is_default ? "C" : "c", path, comment); 00092 } 00093 00094 virtual void config_value_erased(const char *path, bool is_default) 00095 { 00096 printf("%s %-55s| %-8s| %-14s\n", is_default ? "*" : " ", path, "", "ERASED"); 00097 } 00098 00099 00100 /** Run. 00101 * This joins the network thread. 00102 */ 00103 void 00104 run() 00105 { 00106 while ( ! quit ) { 00107 c->wait(FAWKES_CID_CONFIGMANAGER); 00108 } 00109 } 00110 00111 private: 00112 FawkesNetworkClient *c; 00113 Configuration *config; 00114 bool quit; 00115 00116 }; 00117 00118 00119 /** Print header. */ 00120 void 00121 print_header() 00122 { 00123 printf("D %-55s| %-8s| %-14s\n", "Path", "Type", "Value"); 00124 printf("--------------------------------------------------------------------------------------\n"); 00125 } 00126 00127 /** Print a single value. 00128 * @param i config item to print. 00129 */ 00130 void 00131 print_value(Configuration::ValueIterator *i, bool show_comment = false) 00132 { 00133 if ( i->is_float() ) { 00134 printf("%s %-55s| %-8s| %-14f\n", (i->is_default() ? "*" : " "), i->path(), i->type(), i->get_float()); 00135 } else if ( i->is_uint() ) { 00136 printf("%s %-55s| %-8s| %-14u\n", (i->is_default() ? "*" : " "), i->path(), "uint", i->get_uint()); 00137 } else if ( i->is_int() ) { 00138 printf("%s %-55s| %-8s| %-14i\n", (i->is_default() ? "*" : " "), i->path(), i->type(), i->get_int()); 00139 } else if ( i->is_bool() ) { 00140 printf("%s %-55s| %-8s| %-14s\n", (i->is_default() ? "*" : " "), i->path(), i->type(), (i->get_bool() ? "true" : "false")); 00141 } else if ( i->is_string() ) { 00142 printf("%s %-55s| %-8s| %-14s\n", (i->is_default() ? "*" : " "), i->path(), i->type(), i->get_string().c_str()); 00143 } 00144 00145 if (show_comment) { 00146 try { 00147 std::string comment = i->get_comment(); 00148 if (comment != "") { 00149 printf("C %-55s: %s\n", i->path(), comment.c_str()); 00150 } 00151 } catch (Exception &e) { 00152 // maybe there is no comment, ignore it... 00153 } 00154 } 00155 } 00156 00157 /** Print a line of output. 00158 * @param i config item to print. 00159 */ 00160 void 00161 print_line(Configuration::ValueIterator *i, bool show_comment = false) 00162 { 00163 if ( i->is_float() ) { 00164 printf("%-14f\n", i->get_float()); 00165 } else if ( i->is_uint() ) { 00166 printf("%-14u\n", i->get_uint()); 00167 } else if ( i->is_int() ) { 00168 printf("%-14i\n", i->get_int()); 00169 } else if ( i->is_bool() ) { 00170 printf("%-14s\n", (i->get_bool() ? "true" : "false")); 00171 } else if ( i->is_string() ) { 00172 printf("%-14s\n", i->get_string().c_str()); 00173 } 00174 } 00175 00176 00177 void 00178 print_usage(const char *program_name) 00179 { 00180 std::cout << "Usage: " << program_name << " [options] <cmd>" << std::endl 00181 << "where cmd is one of the following:" << std::endl << std::endl 00182 << " list" << std::endl 00183 << " List all configuration items" << std::endl << std::endl 00184 << " watch" << std::endl 00185 << " Watch configuration changes" << std::endl << std::endl 00186 << " get <path>" << std::endl 00187 << " Get value for the given path" << std::endl << std::endl 00188 << " set <path> <value> [type]" << std::endl 00189 << " Set value for the given path to the given type and value" << std::endl 00190 << " where type is one of float/uint/int/bool/string. The type" << std::endl 00191 << " is only necessary if you are creating a new value" << std::endl << std::endl 00192 << " set_default <path> <value> [type]" << std::endl 00193 << " Set default value for the given path to the given type and value" << std::endl 00194 << " where type is one of float/uint/int/bool/string. The type" << std::endl 00195 << " is only necessary if you are creating a new value" << std::endl << std::endl 00196 << " set_comment <path> <comment>" << std::endl 00197 << " Set comment for the given path to the given value. The value at" << std::endl 00198 << " the given path must already exist in the host-specific configuration." << std::endl << std::endl 00199 << " set_default_comment <path> <comment>" << std::endl 00200 << " Set default comment for the given path to the given value. The value at" << std::endl 00201 << " the given path must already exist in the default configuration." << std::endl << std::endl 00202 << " erase <path>" << std::endl 00203 << " Erase value for given path from config" << std::endl 00204 << " erase_default <path>" << std::endl 00205 << " Erase default value for given path from config" << std::endl << std::endl 00206 << "and options is none, one or more of the following:" << std::endl << std::endl 00207 << " -c Show comments (only available with list and watch cmd)" << std::endl 00208 << " -a Show all values, even double if default and host-specific " << std::endl 00209 << " values exist (only available with list)" << std::endl 00210 << " -q Quiet. Only show important output, suitable for parsing. " << std::endl 00211 << " (not supported for all commands yet) " << std::endl 00212 << " -r host[:port] Remote host (and optionally port) to connect to\n" << std::endl 00213 << std::endl; 00214 } 00215 00216 /** Config tool main. 00217 * @param argc argument count 00218 * @param argv arguments 00219 */ 00220 int 00221 main(int argc, char **argv) 00222 { 00223 ArgumentParser argp(argc, argv, "+hcar:q"); 00224 00225 if ( argp.has_arg("h") ) { 00226 print_usage(argv[0]); 00227 exit(0); 00228 } 00229 00230 std::string host = "localhost"; 00231 unsigned short int port = 1910; 00232 if ( argp.has_arg("r") ) { 00233 argp.parse_hostport("r", host, port); 00234 } 00235 00236 bool quiet; 00237 if ( argp.has_arg("q") ) { 00238 quiet = true; 00239 } else { 00240 quiet = false; 00241 } 00242 00243 FawkesNetworkClient *c = new FawkesNetworkClient(host.c_str(), port); 00244 try { 00245 c->connect(); 00246 } catch( Exception &e ) { 00247 printf("Could not connect to host: %s\n", host.c_str()); 00248 exit(1); 00249 } 00250 00251 NetworkConfiguration *netconf = new NetworkConfiguration(c); 00252 00253 const std::vector< const char* > & args = argp.items(); 00254 00255 if ( args.size() == 0) { 00256 // show usage 00257 printf("Not enough args\n\n"); 00258 print_usage(argv[0]); 00259 } else if (strcmp("get", args[0]) == 0) { 00260 if (args.size() == 2) { 00261 if( ! quiet ) { 00262 printf("Requesting value %s\n", args[1]); 00263 } 00264 Configuration::ValueIterator *i = netconf->get_value(args[1]); 00265 if ( i->next() ) { 00266 if( quiet ) { 00267 print_line(i); 00268 } else { 00269 print_header(); 00270 print_value(i); 00271 } 00272 } else { 00273 printf("No such value found!\n"); 00274 } 00275 delete i; 00276 } else { 00277 // Error! 00278 printf("You must supply path argument\n"); 00279 } 00280 } else if ((strcmp("set", args[0]) == 0) || (strcmp("set_default", args[0]) == 0)) { 00281 bool set_def = (strcmp("set_default", args[0]) == 0); 00282 if (args.size() >= 3) { 00283 // we have at least "set path value" 00284 printf("Requesting old value for %s\n", args[1]); 00285 Configuration::ValueIterator *i = netconf->get_value(args[1]); 00286 print_header(); 00287 printf("OLD:\n"); 00288 if ( i->next() ) { 00289 print_line(i); 00290 } else { 00291 printf("Value does not currently exist in configuration.\n"); 00292 } 00293 00294 std::string desired_type = ""; 00295 if (args.size() == 4) { 00296 // we have "set path value type" 00297 desired_type = args[3]; 00298 } 00299 00300 if ( (desired_type == "") && ! i->valid()) { 00301 printf("Please specify type\n"); 00302 delete i; 00303 } else if ( (desired_type != "") && (i->valid() && (desired_type != i->type())) ) { 00304 printf("The given type '%s' contradicts with type '%s' in config. " 00305 "Erase before setting with new type.\n", desired_type.c_str(), i->type()); 00306 delete i; 00307 } else { 00308 if ( i->valid() ) desired_type = i->type(); 00309 00310 if ( desired_type == "float" ) { 00311 char *endptr; 00312 float f = strtod(args[2], &endptr); 00313 if ( endptr[0] != 0 ) { 00314 printf("ERROR: '%s' is not a float\n", args[2]); 00315 } else { 00316 if ( ! set_def ) { 00317 netconf->set_float(args[1], f); 00318 } else { 00319 netconf->set_default_float(args[1], f); 00320 } 00321 } 00322 } else if ( (desired_type == "unsigned int") || (desired_type == "uint") ) { 00323 char *endptr; 00324 long int li = strtol(args[2], &endptr, 10); 00325 if ( (endptr[0] != 0) || (li < 0) ) { 00326 printf("ERROR: '%s' is not an unsigned int\n", args[2]); 00327 } else { 00328 if ( ! set_def ) { 00329 netconf->set_uint(args[1], li); 00330 } else { 00331 netconf->set_default_uint(args[1], li); 00332 } 00333 } 00334 } else if ( desired_type == "int" ) { 00335 char *endptr; 00336 long int li = strtol(args[2], &endptr, 10); 00337 if ( endptr[0] != 0 ) { 00338 printf("ERROR: '%s' is not an int\n", args[2]); 00339 } else { 00340 if ( ! set_def ) { 00341 netconf->set_int(args[1], li); 00342 } else { 00343 netconf->set_default_int(args[1], li); 00344 } 00345 } 00346 } else if ( desired_type == "bool" ) { 00347 bool valid = false; 00348 bool b; 00349 if ( strcasecmp("true", args[2]) == 0 ) { 00350 b = true; 00351 valid = true; 00352 } else if ( strcasecmp("false", args[2]) == 0 ) { 00353 b = false; 00354 valid = true; 00355 } else { 00356 printf("ERROR: '%s' is not a boolean.\n", args[2]); 00357 } 00358 if (valid) { 00359 if ( ! set_def ) { 00360 netconf->set_bool(args[1], b); 00361 } else { 00362 netconf->set_default_bool(args[1], b); 00363 } 00364 } 00365 } else if ( desired_type == "string" ) { 00366 if ( ! set_def ) { 00367 netconf->set_string(args[1], args[2]); 00368 } else { 00369 netconf->set_default_string(args[1], args[2]); 00370 } 00371 } else { 00372 printf("Invalid type: %s\n", desired_type.c_str()); 00373 } 00374 00375 delete i; 00376 00377 printf("NEW:\n"); 00378 i = netconf->get_value(args[1]); 00379 if ( i->next() ) { 00380 print_line(i); 00381 } else { 00382 printf("ERROR: value does not exist\n"); 00383 } 00384 delete i; 00385 00386 } 00387 } else { 00388 printf("Usage: %s set <path> <value> [type]\n", argp.program_name()); 00389 } 00390 } else if ((strcmp("set_comment", args[0]) == 0) || 00391 (strcmp("set_default_comment", args[0]) == 0)) { 00392 bool set_def = (strcmp("set_default_comment", args[0]) == 0); 00393 if (args.size() >= 3) { 00394 // we have at least "set_comment path value" 00395 00396 if ( ! set_def ) { 00397 netconf->set_comment(args[1], args[2]); 00398 } else { 00399 netconf->set_default_comment(args[1], args[2]); 00400 } 00401 00402 } else { 00403 printf("Usage: %s set_(default_)comment <path> <value>\n", argp.program_name()); 00404 } 00405 } else if ((strcmp("erase", args[0]) == 0) || (strcmp("erase_default", args[0]) == 0)) { 00406 bool erase_def = (strcmp("erase_default", args[0]) == 0); 00407 if (args.size() == 2) { 00408 printf("Erasing %svalue %s\n", (erase_def ? "default " : ""), args[1]); 00409 bool found = false; 00410 Configuration::ValueIterator *i = netconf->get_value(args[1]); 00411 if ( i->next() ) { 00412 print_header(); 00413 print_line(i); 00414 found = true; 00415 } else { 00416 printf("No such value found!\n"); 00417 } 00418 delete i; 00419 if ( found ) { 00420 if ( erase_def ) { 00421 netconf->erase_default(args[1]); 00422 } else { 00423 netconf->erase(args[1]); 00424 } 00425 i = netconf->get_value(args[1]); 00426 if ( i->next() ) { 00427 printf("Failed to erase %s (default vs. non-default?)\n", args[1]); 00428 } else { 00429 printf("Successfully erased %s\n", args[1]); 00430 } 00431 delete i; 00432 } 00433 } else { 00434 // Error! 00435 printf("You must supply path argument\n"); 00436 } 00437 } else if (strcmp("watch", args[0]) == 0) { 00438 try { 00439 netconf->set_mirror_mode(true); 00440 } catch (Exception &e) { 00441 e.print_trace(); 00442 return -1; 00443 } 00444 print_header(); 00445 netconf->lock(); 00446 Configuration::ValueIterator *i = netconf->iterator(); 00447 while ( i->next() ) { 00448 print_line(i, argp.has_arg("c")); 00449 } 00450 delete i; 00451 netconf->unlock(); 00452 printf("------------------------------------------------------------------------------------\n"); 00453 printf("Modifications since watching:\n"); 00454 printf("------------------------------------------------------------------------------------\n"); 00455 ConfigChangeWatcherTool ccwt(netconf, c); 00456 ccwt.run(); 00457 } else if (strcmp("list", args[0]) == 0) { 00458 printf("Transmitting config from host... "); 00459 fflush(stdout); 00460 try { 00461 netconf->set_mirror_mode(true); 00462 } catch (Exception &e) { 00463 e.print_trace(); 00464 return -1; 00465 } 00466 netconf->lock(); 00467 printf("done\n"); 00468 print_header(); 00469 bool show_comments = argp.has_arg("c"); 00470 if (argp.has_arg("a")) { 00471 printf("DEFAULT ENTRIES\n"); 00472 Configuration::ValueIterator *i = netconf->iterator_default(); 00473 while ( i->next() ) { 00474 print_line(i, show_comments); 00475 } 00476 delete i; 00477 printf("HOST-SPECIFIC ENTRIES\n"); 00478 i = netconf->iterator_hostspecific(); 00479 while ( i->next() ) { 00480 print_line(i, show_comments); 00481 } 00482 delete i; 00483 } else { 00484 Configuration::ValueIterator *i = netconf->iterator(); 00485 while ( i->next() ) { 00486 print_line(i, show_comments); 00487 } 00488 delete i; 00489 } 00490 netconf->unlock(); 00491 } 00492 00493 if( ! quiet ) { 00494 printf("Cleaning up... "); 00495 } 00496 fflush(stdout); 00497 delete netconf; 00498 c->disconnect(); 00499 00500 delete c; 00501 if( ! quiet ) { 00502 printf("done\n"); 00503 } 00504 00505 return 0; 00506 }