main.cpp

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 }

Generated on Tue Feb 22 13:32:17 2011 for Fawkes API by  doxygen 1.4.7