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