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 
00128 /** Print a line of output.
00129  * @param i config item to print.
00130  */
00131 void
00132 print_line(Configuration::ValueIterator *i, bool show_comment = false)
00133 {
00134   if ( i->is_float() ) {
00135     printf("%s %-55s| %-8s| %-14f\n", (i->is_default() ? "*" : " "), i->path(), i->type(), i->get_float());
00136   } else if ( i->is_uint() ) {
00137     printf("%s %-55s| %-8s| %-14u\n", (i->is_default() ? "*" : " "), i->path(), "uint", i->get_uint());
00138   } else if ( i->is_int() ) {
00139     printf("%s %-55s| %-8s| %-14i\n", (i->is_default() ? "*" : " "), i->path(), i->type(), i->get_int());
00140   } else if ( i->is_bool() ) {
00141     printf("%s %-55s| %-8s| %-14s\n", (i->is_default() ? "*" : " "), i->path(), i->type(), (i->get_bool() ? "true" : "false"));
00142   } else if ( i->is_string() ) {
00143     printf("%s %-55s| %-8s| %-14s\n", (i->is_default() ? "*" : " "), i->path(), i->type(), i->get_string().c_str());
00144   }
00145
00146   if (show_comment) {
00147     try {
00148       std::string comment = i->get_comment();
00149       if (comment != "") {
00150         printf("C %-55s: %s\n", i->path(), comment.c_str());
00151       }
00152     } catch (Exception &e) {
00153       // maybe there is no comment, ignore it...
00154     }
00155   }
00156 }
00157
00158
00159 void
00160 print_usage(const char *program_name)
00161 {
00162   std::cout << "Usage: " << program_name << " [options] <cmd>" << std::endl
00163             << "where cmd is one of the following:" << std::endl << std::endl
00164             << "  list" << std::endl
00165             << "    List all configuration items" << std::endl << std::endl
00166             << "  watch" << std::endl
00167             << "    Watch configuration changes" << std::endl << std::endl
00168             << "  get <path>" << std::endl
00169             << "    Get value for the given path" << std::endl << std::endl
00170             << "  set <path> <value> [type]" << std::endl
00171             << "    Set value for the given path to the given type and value" << std::endl
00172             << "    where type is one of float/uint/int/bool/string. The type" << std::endl
00173             << "    is only necessary if you are creating a new value" << std::endl << std::endl
00174             << "  set_default <path> <value> [type]" << std::endl
00175             << "    Set default value for the given path to the given type and value" << std::endl
00176             << "    where type is one of float/uint/int/bool/string. The type" << std::endl
00177             << "    is only necessary if you are creating a new value" << std::endl << std::endl
00178             << "  set_comment <path> <comment>" << std::endl
00179             << "    Set comment for the given path to the given value. The value at" << std::endl
00180             << "    the given path must already exist in the host-specific configuration." << std::endl << std::endl
00181             << "  set_default_comment <path> <comment>" << std::endl
00182             << "    Set default comment for the given path to the given value. The value at" << std::endl
00183             << "    the given path must already exist in the default configuration." << std::endl << std::endl
00184             << "  erase <path>" << std::endl
00185             << "    Erase value for given path from config" << std::endl
00186             << "  erase_default <path>" << std::endl
00187             << "    Erase default value for given path from config" << std::endl << std::endl
00188             << "and options is none, one or more of the following:" << std::endl << std::endl
00189             << "  -c   Show comments (only available with list and watch cmd)" << std::endl
00190             << "  -a   Show all values, even double if default and host-specific " << std::endl
00191             << "       values exist (only available with list)" << std::endl
00192             << std::endl;
00193 }
00194 
00195 /** Config tool main.
00196  * @param argc argument count
00197  * @param argv arguments
00198  */
00199 int
00200 main(int argc, char **argv)
00201 {
00202   ArgumentParser argp(argc, argv, "+hca");
00203
00204   if ( argp.has_arg("h") ) {
00205     print_usage(argv[0]);
00206     exit(0);
00207   }
00208
00209   FawkesNetworkClient *c = new FawkesNetworkClient("localhost", 1910);
00210   c->connect();
00211
00212   NetworkConfiguration *netconf = new NetworkConfiguration(c);
00213
00214   const std::vector< const char* > & args = argp.items();
00215
00216   if ( args.size() == 0) {
00217     // show usage
00218     printf("Not enough args\n\n");
00219     print_usage(argv[0]);
00220   } else if (strcmp("get", args[0]) == 0) {
00221     if (args.size() == 2) {
00222       printf("Requesting value %s\n", args[1]);
00223       Configuration::ValueIterator *i = netconf->get_value(args[1]);
00224       if ( i->next() ) {
00225         print_header();
00226         print_line(i);
00227       } else {
00228         printf("No such value found!\n");
00229       }
00230       delete i;
00231     } else {
00232       // Error!
00233       printf("You must supply path argument\n");
00234     }
00235   } else if ((strcmp("set", args[0]) == 0) || (strcmp("set_default", args[0]) == 0)) {
00236     bool set_def = (strcmp("set_default", args[0]) == 0);
00237     if (args.size() >= 3) {
00238       // we have at least "set path value"
00239       printf("Requesting old value for %s\n", args[1]);
00240       Configuration::ValueIterator *i = netconf->get_value(args[1]);
00241       print_header();
00242       printf("OLD:\n");
00243       if ( i->next() ) {
00244         print_line(i);
00245       } else {
00246         printf("Value does not currently exist in configuration.\n");
00247       }
00248
00249       std::string desired_type = "";
00250       if (args.size() == 4) {
00251         // we have "set path value type"
00252         desired_type = args[3];
00253       }
00254
00255       if ( (desired_type == "") && ! i->valid()) {
00256         printf("Please specify type\n");
00257         delete i;
00258       } else if ( (desired_type != "") && (i->valid() && (desired_type != i->type())) ) {
00259         printf("The given type '%s' contradicts with type '%s' in config. "
00260                "Erase before setting with new type.\n", desired_type.c_str(), i->type());
00261         delete i;
00262       } else {
00263         if ( i->valid() ) desired_type = i->type();
00264
00265         if ( desired_type == "float" ) {
00266           char *endptr;
00267           float f = strtod(args[2], &endptr);
00268           if ( endptr[0] != 0 ) {
00269             printf("ERROR: '%s' is not a float\n", args[2]);
00270           } else {
00271             if ( ! set_def ) {
00272               netconf->set_float(args[1], f);
00273             } else {
00274               netconf->set_default_float(args[1], f);
00275             }
00276           }
00277         } else if ( (desired_type == "unsigned int") || (desired_type == "uint") ) {
00278           char *endptr;
00279           long int li = strtol(args[2], &endptr, 10);
00280           if ( (endptr[0] != 0) || (li < 0) ) {
00281             printf("ERROR: '%s' is not an unsigned int\n", args[2]);
00282           } else {
00283             if ( ! set_def ) {
00284               netconf->set_uint(args[1], li);
00285             } else {
00286               netconf->set_default_uint(args[1], li);
00287             }
00288           }
00289         } else if ( desired_type == "int" ) {
00290           char *endptr;
00291           long int li = strtol(args[2], &endptr, 10);
00292           if ( endptr[0] != 0 ) {
00293             printf("ERROR: '%s' is not an int\n", args[2]);
00294           } else {
00295             if ( ! set_def ) {
00296               netconf->set_int(args[1], li);
00297             } else {
00298               netconf->set_default_int(args[1], li);
00299             }
00300           }
00301         } else if ( desired_type == "bool" ) {
00302           bool valid = false;
00303           bool b;
00304           if ( strcasecmp("true", args[2]) == 0 ) {
00305             b = true;
00306             valid = true;
00307           } else if ( strcasecmp("false", args[2]) == 0 ) {
00308             b = false;
00309             valid = true;
00310           } else {
00311             printf("ERROR: '%s' is not a boolean.\n", args[2]);
00312           }
00313           if (valid) {
00314             if ( ! set_def ) {
00315               netconf->set_bool(args[1], b);
00316             } else {
00317               netconf->set_default_bool(args[1], b);
00318             }
00319           }
00320         } else if ( desired_type == "string" ) {
00321           if ( ! set_def ) {
00322             netconf->set_string(args[1], args[2]);
00323           } else {
00324             netconf->set_default_string(args[1], args[2]);
00325           }
00326         } else {
00327           printf("Invalid type: %s\n", desired_type.c_str());
00328         }
00329
00330         delete i;
00331
00332         printf("NEW:\n");
00333         i = netconf->get_value(args[1]);
00334         if ( i->next() ) {
00335           print_line(i);
00336         } else {
00337           printf("ERROR: value does not exist\n");
00338         }
00339         delete i;
00340
00341       }
00342     } else {
00343       printf("Usage: %s set <path> <value> [type]\n", argp.program_name());
00344     }
00345   } else if ((strcmp("set_comment", args[0]) == 0) ||
00346              (strcmp("set_default_comment", args[0]) == 0)) {
00347     bool set_def = (strcmp("set_default_comment", args[0]) == 0);
00348     if (args.size() >= 3) {
00349       // we have at least "set_comment path value"
00350
00351       if ( ! set_def ) {
00352         netconf->set_comment(args[1], args[2]);
00353       } else {
00354         netconf->set_default_comment(args[1], args[2]);
00355       }
00356
00357     } else {
00358       printf("Usage: %s set_(default_)comment <path> <value>\n", argp.program_name());
00359     }
00360   } else if ((strcmp("erase", args[0]) == 0) || (strcmp("erase_default", args[0]) == 0)) {
00361     bool erase_def = (strcmp("erase_default", args[0]) == 0);
00362     if (args.size() == 2) {
00363       printf("Erasing %svalue %s\n", (erase_def ? "default " : ""), args[1]);
00364       bool found = false;
00365       Configuration::ValueIterator *i = netconf->get_value(args[1]);
00366       if ( i->next() ) {
00367         print_header();
00368         print_line(i);
00369         found = true;
00370       } else {
00371         printf("No such value found!\n");
00372       }
00373       delete i;
00374       if ( found ) {
00375         if ( erase_def ) {
00376           netconf->erase_default(args[1]);
00377         } else {
00378           netconf->erase(args[1]);
00379         }
00380         i = netconf->get_value(args[1]);
00381         if ( i->next() ) {
00382           printf("Failed to erase %s (default vs. non-default?)\n", args[1]);
00383         } else {
00384           printf("Successfully erased %s\n", args[1]);
00385         }
00386         delete i;
00387       }
00388     } else {
00389       // Error!
00390       printf("You must supply path argument\n");
00391     }
00392   } else if (strcmp("watch", args[0]) == 0) {
00393     try {
00394       netconf->set_mirror_mode(true);
00395     } catch (Exception &e) {
00396       e.print_trace();
00397       return -1;
00398     }
00399     print_header();
00400     netconf->lock();
00401     Configuration::ValueIterator *i = netconf->iterator();
00402     while ( i->next() ) {
00403       print_line(i, argp.has_arg("c"));
00404     }
00405     delete i;
00406     netconf->unlock();
00407     printf("------------------------------------------------------------------------------------\n");
00408     printf("Modifications since watching:\n");
00409     printf("------------------------------------------------------------------------------------\n");
00410     ConfigChangeWatcherTool ccwt(netconf, c);
00411     ccwt.run();
00412   } else if (strcmp("list", args[0]) == 0) {
00413     printf("Transmitting config from host... ");
00414     fflush(stdout);
00415     try {
00416       netconf->set_mirror_mode(true);
00417     } catch (Exception &e) {
00418       e.print_trace();
00419       return -1;
00420     }
00421     netconf->lock();
00422     printf("done\n");
00423     print_header();
00424     bool show_comments = argp.has_arg("c");
00425     if (argp.has_arg("a")) {
00426       printf("DEFAULT ENTRIES\n");
00427       Configuration::ValueIterator *i = netconf->iterator_default();
00428       while ( i->next() ) {
00429         print_line(i, show_comments);
00430       }
00431       delete i;
00432       printf("HOST-SPECIFIC ENTRIES\n");
00433       i = netconf->iterator_hostspecific();
00434       while ( i->next() ) {
00435         print_line(i, show_comments);
00436       }
00437       delete i;
00438     } else {
00439       Configuration::ValueIterator *i = netconf->iterator();
00440       while ( i->next() ) {
00441         print_line(i, show_comments);
00442       }
00443       delete i;
00444     }
00445     netconf->unlock();
00446   }
00447
00448
00449   printf("Cleaning up... ");
00450   fflush(stdout);
00451   delete netconf;
00452   c->disconnect();
00453
00454   delete c;
00455   printf("done\n");
00456
00457   return 0;
00458 }