Back to index

nordugrid-arc-nox  1.1.0~rc6
UserConfig.cpp
Go to the documentation of this file.
00001 // -*- indent-tabs-mode: nil -*-
00002 
00003 #ifdef HAVE_CONFIG_H
00004 #include <config.h>
00005 #endif
00006 
00007 #include <fstream>
00008 #include <glibmm.h>
00009 #ifdef HAVE_GIOMM
00010 #include <giomm/file.h>
00011 #include <giomm/error.h>
00012 #else
00013 #include <sys/stat.h>
00014 #endif
00015 
00016 #include <arc/ArcLocation.h>
00017 #include <arc/IniConfig.h>
00018 #include <arc/Logger.h>
00019 #include <arc/StringConv.h>
00020 #include <arc/URL.h>
00021 #include <arc/User.h>
00022 #include <arc/UserConfig.h>
00023 #include <arc/Utils.h>
00024 
00025 #define HANDLESTRATT(ATT, SETTER) \
00026   if (common[ATT]) {\
00027     SETTER((std::string)common[ATT]);\
00028     common[ATT].Destroy();\
00029     if (common[ATT]) {\
00030       logger.msg(WARNING, "Multiple %s attributes in configuration file (%s)", ATT, conffile); \
00031       while (common[ATT]) common[ATT].Destroy();\
00032     }\
00033   }
00034 
00035 
00036 namespace Arc {
00037 
00038   std::string tostring(const ServiceType st) {
00039     switch (st) {
00040     case COMPUTING:
00041       return istring("computing");
00042     case INDEX:
00043       return istring("index");
00044     }
00045   }
00046 
00047   Logger UserConfig::logger(Logger::getRootLogger(), "UserConfig");
00048 
00049   const std::string UserConfig::DEFAULT_BROKER = "Random";
00050 
00051   const std::string UserConfig::ARCUSERDIRECTORY = Glib::build_filename(User().Home(), ".arc");
00052 
00053 #ifdef WIN32
00054   const std::string UserConfig::SYSCONFIG =  ArcLocation::Get() + "\\etc\\arc\\client.conf";
00055   const std::string UserConfig::EXAMPLECONFIG = ArcLocation::Get() + "\\share\\arc\\examples\\client.conf.example";
00056 #else
00057   const std::string UserConfig::SYSCONFIG = Glib::build_filename(PKGSYSCONFDIR, "client.conf");
00058   const std::string UserConfig::EXAMPLECONFIG = Glib::build_filename(PKGDATADIR G_DIR_SEPARATOR_S "examples", "client.conf.example");
00059 #endif
00060 
00061   const std::string UserConfig::DEFAULTCONFIG = Glib::build_filename(ARCUSERDIRECTORY, "client.conf");
00062 
00063   UserConfig::UserConfig(initializeCredentialsType initializeCredentials) {
00064     if (initializeCredentials != initializeCredentialsType::SkipCredentials) {
00065       InitializeCredentials();
00066       if ((!CredentialsFound()) && (initializeCredentials == initializeCredentialsType::RequireCredentials))
00067         return;
00068     }
00069 
00070     ok = true;
00071 
00072     setDefaults();
00073   }
00074 
00075   UserConfig::UserConfig(const std::string& conffile,
00076                          initializeCredentialsType initializeCredentials,
00077                          bool loadSysConfig)
00078     : ok(false) {
00079     if (loadSysConfig) {
00080       if (!Glib::file_test(SYSCONFIG, Glib::FILE_TEST_IS_REGULAR))
00081         logger.msg(INFO, "System configuration file (%s) does not exist.", SYSCONFIG);
00082       else if (!LoadConfigurationFile(SYSCONFIG, true))
00083         logger.msg(INFO, "System configuration file (%s) contains errors.", SYSCONFIG);
00084     }
00085 
00086     if (conffile.empty()) {
00087       if (CreateDefaultConfigurationFile()) {
00088         if (!LoadConfigurationFile(DEFAULTCONFIG, false)) {
00089           logger.msg(WARNING, "User configuration file (%s) contains errors.", DEFAULTCONFIG);
00090           return;
00091         }
00092       }
00093       else
00094         logger.msg(INFO, "No configuration file could be loaded.");
00095     }
00096     else if (!Glib::file_test(conffile, Glib::FILE_TEST_IS_REGULAR)) {
00097       logger.msg(WARNING, "User configuration file (%s) does not exist or cannot be loaded.", conffile);
00098       return;
00099     }
00100     else if (!LoadConfigurationFile(conffile)) {
00101       logger.msg(WARNING, "User configuration file (%s) contains errors.", conffile);
00102       return;
00103     }
00104 
00105     if (initializeCredentials != initializeCredentialsType::SkipCredentials) {
00106       InitializeCredentials();
00107       if ((!CredentialsFound()) && (initializeCredentials == initializeCredentialsType::RequireCredentials))
00108         return;
00109     }
00110 
00111     ok = true;
00112 
00113     setDefaults();
00114   }
00115 
00116   UserConfig::UserConfig(const std::string& conffile, const std::string& jfile,
00117                          initializeCredentialsType initializeCredentials, bool loadSysConfig)
00118     : ok(false) {
00119     // If job list file have been specified, try to initialize it, and
00120     // if it fails then this object is non-valid (ok = false).
00121     if (!jfile.empty() && !JobListFile(jfile))
00122       return;
00123 
00124     if (loadSysConfig) {
00125       if (!Glib::file_test(SYSCONFIG, Glib::FILE_TEST_IS_REGULAR))
00126         logger.msg(INFO, "System configuration file (%s) does not exist.", SYSCONFIG);
00127       else if (!LoadConfigurationFile(SYSCONFIG, true))
00128         logger.msg(INFO, "System configuration file (%s) contains errors.", SYSCONFIG);
00129     }
00130 
00131     if (conffile.empty()) {
00132       if (CreateDefaultConfigurationFile()) {
00133         if (!LoadConfigurationFile(DEFAULTCONFIG, !jfile.empty())) {
00134           logger.msg(WARNING, "User configuration file (%s) contains errors.", DEFAULTCONFIG);
00135           return;
00136         }
00137       }
00138       else
00139         logger.msg(INFO, "No configuration file could be loaded.");
00140     }
00141     else if (!Glib::file_test(conffile, Glib::FILE_TEST_IS_REGULAR)) {
00142       logger.msg(WARNING, "User configuration file (%s) does not exist or cannot be loaded.", conffile);
00143       return;
00144     }
00145     else if (!LoadConfigurationFile(conffile)) {
00146       logger.msg(WARNING, "User configuration file (%s) contains errors.", conffile);
00147       return;
00148     }
00149 
00150     // If no job list file have been initialized use the default. If the
00151     // job list file cannot be initialized this object is non-valid.
00152     if (joblistfile.empty() && !JobListFile(Glib::build_filename(ARCUSERDIRECTORY, "jobs.xml")))
00153       return;
00154 
00155     if (initializeCredentials != initializeCredentialsType::SkipCredentials) {
00156       InitializeCredentials();
00157       if ((!CredentialsFound()) && (initializeCredentials == initializeCredentialsType::RequireCredentials))
00158         return;
00159     }
00160 
00161     ok = true;
00162 
00163     setDefaults();
00164   }
00165 
00166   UserConfig::UserConfig(const long int& ptraddr) { *this = *((UserConfig*)ptraddr); }
00167 
00168   void UserConfig::ApplyToConfig(BaseConfig& ccfg) const {
00169     if (!proxyPath.empty())
00170       ccfg.AddProxy(proxyPath);
00171     else {
00172       ccfg.AddCertificate(certificatePath);
00173       ccfg.AddPrivateKey(keyPath);
00174     }
00175 
00176     ccfg.AddCADir(caCertificatesDirectory);
00177 
00178     if(!overlayfile.empty())
00179       ccfg.GetOverlay(overlayfile);
00180   }
00181 
00182   bool UserConfig::Timeout(int newTimeout) {
00183     if (timeout > 0) {
00184       timeout = newTimeout;
00185       return true;
00186     }
00187 
00188     return false;
00189   }
00190 
00191   bool UserConfig::Verbosity(const std::string& newVerbosity) {
00192     LogLevel ll;
00193     if (istring_to_level(newVerbosity, ll)) {
00194       verbosity = newVerbosity;
00195       return true;
00196     }
00197     else {
00198       logger.msg(WARNING, "Unable to parse the specified verbosity (%s) to one of the allowed levels", newVerbosity);
00199       return false;
00200     }
00201   }
00202 
00203   bool UserConfig::JobListFile(const std::string& path) {
00204     // Check if joblistfile exist.
00205     if (!Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
00206       // The joblistfile does not exist. Create a empty version, and if
00207       // this fails report an error and exit.
00208       const std::string joblistdir = Glib::path_get_dirname(path);
00209 
00210       // Check if the parent directory exist.
00211       if (!Glib::file_test(joblistdir, Glib::FILE_TEST_EXISTS)) {
00212         // Create directory.
00213         if (!makeDir(joblistdir)) {
00214           logger.msg(ERROR, "Unable to create %s directory", joblistdir);
00215           return false;
00216         }
00217       }
00218       else if (!Glib::file_test(joblistdir, Glib::FILE_TEST_IS_DIR)) {
00219         logger.msg(ERROR, "%s is not a directory, it is needed for the client to function correctly", joblistdir);
00220         return false;
00221       }
00222 
00223       NS ns;
00224       Config(ns).SaveToFile(path);
00225       logger.msg(INFO, "Created empty ARC job list file: %s", path);
00226     }
00227     else if (!Glib::file_test(path, Glib::FILE_TEST_IS_REGULAR)) {
00228       logger.msg(ERROR, "ARC job list file is not a regular file: %s", path);
00229       return false;
00230     }
00231 
00232     joblistfile = path;
00233     return true;
00234   }
00235 
00236   bool UserConfig::Broker(const std::string& nameandarguments) {
00237     const std::size_t pos = nameandarguments.find(":");
00238     if (pos != std::string::npos) // Arguments given in 'nameandarguments'
00239       broker = std::make_pair<std::string, std::string>(nameandarguments.substr(0, pos),
00240                                                         nameandarguments.substr(pos+1));
00241     else
00242       broker = std::make_pair<std::string, std::string>(nameandarguments, "");
00243 
00244     return true;
00245   }
00246 
00247   void UserConfig::InitializeCredentials() {
00248     const User user;
00249     // Look for credentials.
00250     if (!GetEnv("X509_USER_PROXY").empty()) {
00251       if (!Glib::file_test(proxyPath = GetEnv("X509_USER_PROXY"), Glib::FILE_TEST_IS_REGULAR)) {
00252         logger.msg(ERROR, "Can not access proxy file: %s", proxyPath);
00253         proxyPath.clear();
00254       }
00255     }
00256     else if (!GetEnv("X509_USER_CERT").empty() &&
00257              !GetEnv("X509_USER_KEY").empty()) {
00258       if (!Glib::file_test(certificatePath = GetEnv("X509_USER_CERT"), Glib::FILE_TEST_IS_REGULAR)) {
00259         logger.msg(ERROR, "Can not access certificate file: %s", certificatePath);
00260         certificatePath.clear();
00261       }
00262       if (!Glib::file_test(keyPath = GetEnv("X509_USER_KEY"), Glib::FILE_TEST_IS_REGULAR)) {
00263         logger.msg(ERROR, "Can not access key file: %s", keyPath);
00264         keyPath.clear();
00265       }
00266     }
00267     else if (!proxyPath.empty()) {
00268       if (!Glib::file_test(proxyPath, Glib::FILE_TEST_IS_REGULAR)) {
00269         logger.msg(ERROR, "Can not access proxy file: %s", proxyPath);
00270         proxyPath.clear();
00271       }
00272     }
00273     else if (!certificatePath.empty() && !keyPath.empty()) {
00274       if (!Glib::file_test(certificatePath.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
00275         logger.msg(ERROR, "Can not access certificate file: %s", certificatePath);
00276         certificatePath.clear();
00277       }
00278       if (!Glib::file_test(keyPath.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
00279         logger.msg(ERROR, "Can not access key file: %s", keyPath);
00280         keyPath.clear();
00281       }
00282     }
00283     else if (!Glib::file_test(proxyPath = Glib::build_filename(Glib::get_tmp_dir(), std::string("x509up_u") + tostring(user.get_uid())), Glib::FILE_TEST_IS_REGULAR)) {
00284       logger.msg(WARNING, "Default proxy file does not exist: %s "
00285                           "trying default certificate and key", proxyPath);
00286       if (user.get_uid() == 0) {
00287         certificatePath = Glib::build_filename(G_DIR_SEPARATOR_S + std::string("etc"), std::string("grid-security") + G_DIR_SEPARATOR_S + std::string("hostcert.pem"));
00288         keyPath = Glib::build_filename(G_DIR_SEPARATOR_S + std::string("etc"), std::string("grid-security") + G_DIR_SEPARATOR_S + std::string("hostkey.pem"));
00289       }
00290       else {
00291         certificatePath = Glib::build_filename(user.Home(), std::string(".globus") + G_DIR_SEPARATOR_S +  std::string("usercert.pem"));
00292         keyPath = Glib::build_filename(user.Home(), std::string(".globus") + G_DIR_SEPARATOR_S + std::string("userkey.pem"));
00293       }
00294 #ifdef WIN32
00295         certificatePath = Glib::build_filename(std::string(g_get_home_dir()), std::string(".globus") + G_DIR_SEPARATOR_S +  std::string("usercert.pem"));
00296         keyPath = Glib::build_filename(std::string(g_get_home_dir()), std::string(".globus") + G_DIR_SEPARATOR_S + std::string("userkey.pem"));
00297 #endif
00298 
00299       if (!Glib::file_test(certificatePath, Glib::FILE_TEST_IS_REGULAR)) {
00300         logger.msg(ERROR, "Can not access certificate file: %s", certificatePath);
00301         certificatePath.clear();
00302       }
00303       if (!Glib::file_test(keyPath, Glib::FILE_TEST_IS_REGULAR)) {
00304         logger.msg(ERROR, "Can not access key file: %s", keyPath);
00305         keyPath.clear();
00306       }
00307     }
00308 
00309     if (!GetEnv("X509_CERT_DIR").empty()) {
00310       if (!Glib::file_test(caCertificatesDirectory = GetEnv("X509_CERT_DIR"), Glib::FILE_TEST_IS_DIR)) {
00311         logger.msg(ERROR, "Can not access CA certificate directory: %s", caCertificatesDirectory);
00312         caCertificatesDirectory.clear();
00313       }
00314     }
00315     else if (!caCertificatesDirectory.empty()) {
00316       if (!Glib::file_test(caCertificatesDirectory, Glib::FILE_TEST_IS_DIR)) {
00317         logger.msg(ERROR, "Can not access CA certificate directory: %s", caCertificatesDirectory);
00318         caCertificatesDirectory.clear();
00319       }
00320     }
00321     else if ((user.get_uid() == 0 || !Glib::file_test(caCertificatesDirectory = user.Home() + G_DIR_SEPARATOR_S + ".globus" + G_DIR_SEPARATOR_S + "certificates", Glib::FILE_TEST_IS_DIR)) &&
00322              !Glib::file_test(caCertificatesDirectory = std::string(Glib::get_home_dir()) + G_DIR_SEPARATOR_S + ".globus" + G_DIR_SEPARATOR_S + "certificates", Glib::FILE_TEST_IS_DIR) &&
00323              !Glib::file_test(caCertificatesDirectory = ArcLocation::Get() + G_DIR_SEPARATOR_S + "etc" + G_DIR_SEPARATOR_S + "certificates", Glib::FILE_TEST_IS_DIR) &&
00324              !Glib::file_test(caCertificatesDirectory = ArcLocation::Get() + G_DIR_SEPARATOR_S + "etc" + G_DIR_SEPARATOR_S + "grid-security" + G_DIR_SEPARATOR_S + "certificates", Glib::FILE_TEST_IS_DIR) &&
00325              !Glib::file_test(caCertificatesDirectory = ArcLocation::Get() + G_DIR_SEPARATOR_S + "share" + G_DIR_SEPARATOR_S + "certificates", Glib::FILE_TEST_IS_DIR)) {
00326       caCertificatesDirectory = Glib::build_filename(G_DIR_SEPARATOR_S + std::string("etc"), std::string("grid-security") + G_DIR_SEPARATOR_S + std::string("certificates"));
00327       if (!Glib::file_test(caCertificatesDirectory.c_str(), Glib::FILE_TEST_IS_DIR)) {
00328         logger.msg(ERROR, "Can not locate CA certificate directory.");
00329         caCertificatesDirectory.clear();
00330       }
00331     }
00332 
00333     if (!proxyPath.empty())
00334       logger.msg(INFO, "Using proxy file: %s", proxyPath);
00335     else if (!certificatePath.empty() && !keyPath.empty()) {
00336       logger.msg(INFO, "Using certificate file: %s", certificatePath);
00337       logger.msg(INFO, "Using key file: %s", keyPath);
00338     }
00339 
00340     if (!caCertificatesDirectory.empty())
00341       logger.msg(INFO, "Using CA certificate directory: %s", caCertificatesDirectory);
00342   }
00343 
00344   bool UserConfig::LoadConfigurationFile(const std::string& conffile, bool ignoreJobListFile) {
00345     if (!conffile.empty()) {
00346       IniConfig ini(conffile);
00347       if (ini) {
00348         logger.msg(INFO, "Loading configuration (%s)", conffile);
00349 
00350         if (ini["alias"]) {
00351           XMLNode aliasXML = ini["alias"];
00352           if (aliasMap) { // Merge aliases. Overwrite existing aliases
00353             while (aliasXML.Child()) {
00354               if (aliasMap[aliasXML.Child().Name()]) {
00355                 aliasMap[aliasXML.Child().Name()].Replace(aliasXML.Child());
00356                 logger.msg(INFO, "Overwriting already defined alias \"%s\"",  aliasXML.Child().Name());
00357               }
00358               else
00359                 aliasMap.NewChild(aliasXML.Child());
00360 
00361               aliasXML.Child().Destroy();
00362             }
00363           }
00364           else
00365             aliasXML.New(aliasMap);
00366           aliasXML.Destroy();
00367         }
00368 
00369         if (ini["common"]) {
00370           XMLNode common = ini["common"];
00371           HANDLESTRATT("verbosity", Verbosity)
00372           HANDLESTRATT("joblist", JobListFile)
00373           if (common["timeout"]) {
00374             if (!stringto(common["timeout"], timeout))
00375               logger.msg(WARNING, "The value of the timeout attribute in the configuration file (%s) was only partially parsed", conffile);
00376             common["timeout"].Destroy();
00377             if (common["timeout"]) {
00378               logger.msg(WARNING, "Multiple %s attributes in configuration file (%s)", "timeout", conffile);
00379               while (common["timeout"]) common["timeout"].Destroy();
00380             }
00381           }
00382           if (common["brokername"]) {
00383             broker = std::make_pair<std::string, std::string>(ini["common"]["brokername"],
00384                                                               ini["common"]["brokerarguments"] ? ini["common"]["brokerarguments"] : "");
00385             common["brokername"].Destroy();
00386             if (common["brokername"]) {
00387               logger.msg(WARNING, "Multiple %s attributes in configuration file (%s)", "brokername", conffile);
00388               while (common["brokername"]) common["brokername"].Destroy();
00389             }
00390             if (common["brokerarguments"]) {
00391               common["brokerarguments"].Destroy();
00392               if (common["brokerarguments"]) {
00393                 logger.msg(WARNING, "Multiple %s attributes in configuration file (%s)", "brokerarguments", conffile);
00394                 while (common["brokerarguments"]) common["brokerarguments"].Destroy();
00395               }
00396             }
00397           }
00398           // This block must be executed after the 'brokername' block.
00399           if (common["brokerarguments"]) {
00400             logger.msg(WARNING, "The brokerarguments attribute can only be used in conjunction with the brokername attribute");
00401             while (common["brokerarguments"]) common["brokerarguments"].Destroy();
00402           }
00403           if (common["bartender"]) {
00404             std::list<std::string> bartendersStr;
00405             tokenize(common["bartender"], bartendersStr, " \t");
00406             for (std::list<std::string>::const_iterator it = bartendersStr.begin();
00407                  it != bartendersStr.end(); it++) {
00408               URL bartenderURL(*it);
00409               if (!bartenderURL)
00410                 logger.msg(WARNING, "Could not convert the bartender attribute value (%s) to an URL instance in configuration file (%s)", *it, conffile);
00411               else
00412                 bartenders.push_back(bartenderURL);
00413             }
00414             common["bartender"].Destroy();
00415             if (common["bartender"]) {
00416               logger.msg(WARNING, "Multiple %s attributes in configuration file (%s)", "bartender", conffile);
00417               while (common["bartender"]) common["bartender"].Destroy();
00418             }
00419           }
00420           HANDLESTRATT("vomsserverpath", VOMSServerPath)
00421           HANDLESTRATT("username", UserName)
00422           HANDLESTRATT("password", Password)
00423           HANDLESTRATT("proxypath", ProxyPath)
00424           HANDLESTRATT("certificatepath", CertificatePath)
00425           HANDLESTRATT("keypath", KeyPath)
00426           HANDLESTRATT("keypassword", KeyPassword)
00427           if (common["keysize"]) {
00428             if (!stringto(ini["common"]["keysize"], keySize))
00429               logger.msg(WARNING, "The value of the keysize attribute in the configuration file (%s) was only partially parsed", conffile);
00430             common["keysize"].Destroy();
00431             if (common["keysize"]) {
00432               logger.msg(WARNING, "Multiple %s attributes in configuration file (%s)", "keysize", conffile);
00433               while (common["keysize"]) common["keysize"].Destroy();
00434             }
00435           }
00436           HANDLESTRATT("cacertificatepath", CACertificatePath)
00437           HANDLESTRATT("cacertificatesdirectory", CACertificatesDirectory)
00438           if (common["certificatelifetime"]) {
00439             certificateLifeTime = Period((std::string)common["certificatelifetime"]);
00440             common["certificatelifetime"].Destroy();
00441             if (common["certificatelifetime"]) {
00442               logger.msg(WARNING, "Multiple %s attributes in configuration file (%s)", "certificatelifetime", conffile);
00443               while (common["certificatelifetime"]) common["certificatelifetime"].Destroy();
00444             }
00445           }
00446           if (common["slcs"]) {
00447             slcs = URL((std::string)common["slcs"]);
00448             if (!slcs) {
00449               logger.msg(WARNING, "Could not convert the slcs attribute value (%s) to an URL instance in configuration file (%s)", (std::string)common["slcs"], conffile);
00450               slcs = URL();
00451             }
00452             common["slcs"].Destroy();
00453             if (common["slcs"]) {
00454               logger.msg(WARNING, "Multiple %s attributes in configuration file (%s)", "slcs", conffile);
00455               while (common["slcs"]) common["slcs"].Destroy();
00456             }
00457           }
00458           HANDLESTRATT("storedirectory", StoreDirectory)
00459           HANDLESTRATT("idpname", IdPName)
00460           if (common["defaultservices"]) {
00461             if (!selectedServices.first.empty() || !selectedServices.second.empty())
00462               ClearSelectedServices();
00463             std::list<std::string> defaultServicesStr;
00464             tokenize(common["defaultservices"], defaultServicesStr, " \t");
00465             for (std::list<std::string>::const_iterator it = defaultServicesStr.begin();
00466                  it != defaultServicesStr.end(); it++) {
00467               // Aliases cannot contain '.' or ':'.
00468 
00469               if (it->find_first_of(":.") == std::string::npos) { // Alias
00470                 if (!aliasMap[*it]) {
00471                   logger.msg(ERROR, "Could not resolve alias \"%s\" it is not defined.", *it);
00472                   return false;
00473                 }
00474 
00475                 std::list<std::string> resolvedAliases(1, *it);
00476                 if (!ResolveAlias(selectedServices, resolvedAliases))
00477                   return false;
00478               }
00479               else {
00480                 const std::size_t pos1 = it->find(":");
00481                 const std::size_t pos2 = it->find(":", pos1+1);
00482                 if (pos2 == std::string::npos) {
00483                   logger.msg(WARNING, "The defaultservices attribute value contains a wrongly formated element (%s) in configuration file (%s)", *it, conffile);
00484                   continue;
00485                 }
00486                 const std::string serviceType = it->substr(0, pos1);
00487                 if (serviceType != "computing" && serviceType != "index") {
00488                   logger.msg(WARNING, "The defaultservices attribute value contains a unknown servicetype %s at %s in configuration file (%s)", serviceType, *it, conffile);
00489                   continue;
00490                 }
00491                 const URL url(it->substr(pos2+1));
00492                 if (!url) {
00493                   logger.msg(WARNING, "The defaultservices attribute value contains a wrongly formated URL (%s) in configuration file (%s)", it->substr(pos2+1), conffile);
00494                   continue;
00495                 }
00496                 const std::string flavour = it->substr(pos1+1,pos2-pos1-1);
00497                 logger.msg(VERBOSE, "Adding selected service %s:%s:%s", serviceType, flavour, url.str());
00498                 if (serviceType == "computing")
00499                   selectedServices.first[flavour].push_back(url);
00500                 else
00501                   selectedServices.second[flavour].push_back(url);
00502               }
00503             }
00504             common["defaultservices"].Destroy();
00505             if (common["defaultservices"]) {
00506               logger.msg(WARNING, "Multiple %s attributes in configuration file (%s)", "defaultservices", conffile);
00507               while (common["defaultservices"]) common["defaultservices"].Destroy();
00508             }
00509           }
00510           if (common["rejectservices"]) {
00511             std::list<std::string> rejectServicesStr;
00512             tokenize(common["rejectservices"], rejectServicesStr, " \t");
00513             for (std::list<std::string>::const_iterator it = rejectServicesStr.begin();
00514                  it != rejectServicesStr.end(); it++) {
00515               // Aliases cannot contain '.' or ':'.
00516               if (it->find_first_of(":.") == std::string::npos) { // Alias
00517                 if (!aliasMap[*it]) {
00518                   logger.msg(ERROR, "Could not resolve alias \"%s\" it is not defined.", *it);
00519                   return false;
00520                 }
00521 
00522                 std::list<std::string> resolvedAliases(1, *it);
00523                 if (!ResolveAlias(selectedServices, resolvedAliases))
00524                   return false;
00525               }
00526               else {
00527                 const std::size_t pos1 = it->find(":");
00528                 const std::size_t pos2 = it->find(":", pos1+1);
00529                 if (pos2 == std::string::npos) {
00530                   logger.msg(WARNING, "The rejectservices attribute value contains a wrongly formated element (%s) in configuration file (%s)", *it, conffile);
00531                   continue;
00532                 }
00533                 const std::string serviceType = it->substr(0, pos1);
00534                 if (serviceType != "computing" && serviceType != "index") {
00535                   logger.msg(WARNING, "The rejectservices attribute value contains a unknown servicetype %s at %s in configuration file (%s)", serviceType, *it, conffile);
00536                   continue;
00537                 }
00538                 const URL url(it->substr(pos2+1));
00539                 if (!url) {
00540                   logger.msg(WARNING, "The rejectservices attribute value contains a wrongly formated URL (%s) in configuration file (%s)", it->substr(pos2+1), conffile);
00541                   continue;
00542                 }
00543                 const std::string flavour = it->substr(pos1+1,pos2-pos1-1);
00544                 logger.msg(VERBOSE, "Adding rejected service %s:%s:%s", serviceType, flavour, url.str());
00545                 if (serviceType == "computing")
00546                   rejectedServices.first[flavour].push_back(url);
00547                 else
00548                   rejectedServices.second[flavour].push_back(url);
00549               }
00550             }
00551             common["rejectservices"].Destroy();
00552             if (common["rejectservices"]) {
00553               logger.msg(WARNING, "Multiple %s attributes in configuration file (%s)", "rejectservices", conffile);
00554               while (common["rejectservices"]) common["rejectservices"].Destroy();
00555             }
00556           }
00557           HANDLESTRATT("overlayfile", OverlayFile)
00558           if(!overlayfile.empty())
00559             if (!Glib::file_test(overlayfile, Glib::FILE_TEST_IS_REGULAR))
00560               logger.msg(WARNING, "Specified overlay file (%s) does not exist.", overlayfile);
00561           while (common.Child()) {
00562             logger.msg(WARNING, "Unknown attribute %s in common section, ignoring it", common.Child().Name());
00563             common.Child().Destroy();
00564           }
00565 
00566           common.Destroy();
00567         }
00568 
00569         while (ini.Child()) {
00570           logger.msg(INFO, "Unknown section %s, ignoring it", ini.Child().Name());
00571           ini.Child().Destroy();
00572         }
00573 
00574         logger.msg(INFO, "Configuration (%s) loaded", conffile);
00575       }
00576       else
00577         logger.msg(WARNING, "Could not load configuration (%s)", conffile);
00578     }
00579 
00580     return true;
00581   }
00582 
00583   bool UserConfig::SaveToFile(const std::string& filename) const {
00584     std::ofstream file(filename.c_str(), std::ios::out);
00585     if (!file)
00586       return false;
00587 
00588     file << "[ common ]" << std::endl;
00589     if (!verbosity.empty())
00590       file << "verbosity = " << verbosity << std::endl;
00591     if (!joblistfile.empty())
00592       file << "joblist = " << joblistfile << std::endl;
00593     if (timeout > 0)
00594       file << "timeout = " << timeout << std::endl;
00595     if (!broker.first.empty()) {
00596       file << "brokername = " << broker.first << std::endl;
00597       if (!broker.second.empty())
00598         file << "brokerarguments = " << broker.second << std::endl;
00599     }
00600     if (!bartenders.empty()) {
00601       file << "bartender =";
00602       for (std::vector<URL>::const_iterator it = bartenders.begin();
00603            it != bartenders.end(); it++) {
00604         file << " " << it->fullstr();
00605       }
00606       file << std::endl;
00607     }
00608     if (!vomsServerPath.empty())
00609       file << "vomsserverpath = " << vomsServerPath << std::endl;
00610     if (!username.empty())
00611       file << "username = " << username << std::endl;
00612     if (!password.empty())
00613       file << "password = " << password << std::endl;
00614     if (!proxyPath.empty())
00615       file << "proxypath = " << proxyPath << std::endl;
00616     if (!certificatePath.empty())
00617       file << "certificatepath = " << certificatePath << std::endl;
00618     if (!keyPath.empty())
00619       file << "keypath = " << keyPath << std::endl;
00620     if (!keyPassword.empty())
00621       file << "keypassword = " << keyPassword << std::endl;
00622     if (keySize > 0)
00623       file << "keysize = " << keySize << std::endl;
00624     if (!caCertificatePath.empty())
00625       file << "cacertificatepath = " << caCertificatePath << std::endl;
00626     if (!caCertificatesDirectory.empty())
00627       file << "cacertificatesdirectory = " << caCertificatesDirectory << std::endl;
00628     if (certificateLifeTime > 0)
00629       file << "certificatelifetime = " << certificateLifeTime << std::endl;
00630     if (slcs)
00631       file << "slcs = " << slcs.fullstr() << std::endl;
00632     if (!storeDirectory.empty())
00633       file << "storedirectory = " << storeDirectory << std::endl;
00634     if (!idPName.empty())
00635       file << "idpname = " << idPName << std::endl;
00636     if (!selectedServices.first.empty() || !selectedServices.second.empty()) {
00637       file << "defaultservices =";
00638       for (URLListMap::const_iterator it = selectedServices.first.begin();
00639            it != selectedServices.first.end(); it++) {
00640         for (std::list<URL>::const_iterator iitt = it->second.begin();
00641              iitt != it->second.end(); iitt++) {
00642           file << " computing:" << it->first << ":" << iitt->fullstr();
00643         }
00644       }
00645       for (URLListMap::const_iterator it = selectedServices.second.begin();
00646            it != selectedServices.second.end(); it++) {
00647         for (std::list<URL>::const_iterator iitt = it->second.begin();
00648              iitt != it->second.end(); iitt++) {
00649           file << " index:" << it->first << ":" << iitt->fullstr();
00650         }
00651       }
00652       file << std::endl;
00653     }
00654     if (!rejectedServices.first.empty() || !rejectedServices.second.empty()) {
00655       file << "rejectedservices =";
00656       for (URLListMap::const_iterator it = rejectedServices.first.begin();
00657            it != rejectedServices.first.end(); it++) {
00658         for (std::list<URL>::const_iterator iitt = it->second.begin();
00659              iitt != it->second.end(); iitt++) {
00660           file << " computing:" << it->first << ":" << iitt->fullstr();
00661         }
00662       }
00663       for (URLListMap::const_iterator it = rejectedServices.second.begin();
00664            it != rejectedServices.second.end(); it++) {
00665         for (std::list<URL>::const_iterator iitt = it->second.begin();
00666              iitt != it->second.end(); iitt++) {
00667           file << " index:" << it->first << ":" << iitt->fullstr();
00668         }
00669       }
00670       file << std::endl;
00671     }
00672     if (!overlayfile.empty())
00673       file << "overlayfile = " << overlayfile << std::endl;
00674 
00675     if (aliasMap.Size() > 0) {
00676       int i = 0;
00677       file << std::endl << "[ alias ]" << std::endl;
00678       while (XMLNode n = const_cast<XMLNode&>(aliasMap).Child(i++)) {
00679         file << n.Name() << " = " << (std::string)n << std::endl;
00680       }
00681     }
00682 
00683     logger.msg(INFO, "UserConfiguration saved to file (%s)", filename);
00684 
00685     return true;
00686   }
00687 
00688   bool UserConfig::CreateDefaultConfigurationFile() const {
00689     // If the default configuration file does not exist, copy an example file.
00690     if (!Glib::file_test(DEFAULTCONFIG, Glib::FILE_TEST_EXISTS)) {
00691 
00692       // Check if the parent directory exist.
00693       if (!Glib::file_test(ARCUSERDIRECTORY, Glib::FILE_TEST_EXISTS)) {
00694         // Create directory.
00695         if (!makeDir(ARCUSERDIRECTORY)) {
00696           logger.msg(WARNING, "Unable to create %s directory.", ARCUSERDIRECTORY);
00697           return false;
00698         }
00699       }
00700 
00701       if (Glib::file_test(ARCUSERDIRECTORY, Glib::FILE_TEST_IS_DIR)) {
00702         if (Glib::file_test(EXAMPLECONFIG, Glib::FILE_TEST_IS_REGULAR)) {
00703           // Destination: Get basename, remove example prefix and add .arc directory.
00704           if (copyFile(EXAMPLECONFIG, DEFAULTCONFIG))
00705             logger.msg(INFO, "Configuration example file created (%s)", DEFAULTCONFIG);
00706           else
00707             logger.msg(WARNING, "Unable to copy example configuration from existing configuration (%s)", EXAMPLECONFIG);
00708             return false;
00709         }
00710         else {
00711           logger.msg(WARNING, "Cannot copy example configuration (%s), it is not a regular file", EXAMPLECONFIG);
00712           return false;
00713         }
00714       }
00715       else {
00716         logger.msg(WARNING, "Example configuration (%s) not created.", DEFAULTCONFIG);
00717         return false;
00718       }
00719     }
00720     else if (!Glib::file_test(DEFAULTCONFIG, Glib::FILE_TEST_IS_REGULAR)) {
00721       logger.msg(WARNING, "The default configuration file (%s) is not a regular file.", DEFAULTCONFIG);
00722       return false;
00723     }
00724 
00725     return true;
00726   }
00727 
00728   bool UserConfig::AddServices(const std::list<std::string>& services, ServiceType st) {
00729     const std::string serviceType = tostring(st);
00730     for (std::list<std::string>::const_iterator it = services.begin();
00731          it != services.end(); it++) {
00732       URLListMap& servicesRef = ((*it)[0] != '-' ? (st == COMPUTING ? selectedServices.first : selectedServices.second)
00733                                                  : (st == COMPUTING ? rejectedServices.first : rejectedServices.second));
00734 
00735       const std::string service = ((*it)[0] != '-' ? *it : it->substr(1));
00736 
00737       // Alias cannot contain '.', ':', ' ' or '\t' and a URL must contain atleast one of ':' or '.'.
00738       if (service.find_first_of(":. \t") == std::string::npos) { // Alias.
00739         if (!aliasMap[service]) {
00740           logger.msg(ERROR, "Could not resolve alias \"%s\" it is not defined.", service);
00741           return false;
00742         }
00743 
00744         std::list<std::string> resolvedAliases(1, service);
00745         if (!ResolveAlias(servicesRef, st, resolvedAliases))
00746           return false;
00747       }
00748       else { // URL
00749         const std::size_t pos = service.find(":");
00750         if (pos == std::string::npos) {
00751           logger.msg(WARNING, "Cannot parse the specified %s service (%s)", serviceType, service);
00752           continue;
00753         }
00754 
00755         const URL url(service.substr(pos+1));
00756         if (!url || url.Protocol() == "file") {
00757           logger.msg(WARNING, "The specified %s service (%s) is not a valid URL", serviceType, service.substr(pos+1));
00758           continue;
00759         }
00760         const std::string flavour = service.substr(0, pos);
00761         logger.msg(VERBOSE, "Adding %s service %s:%s ", (*it)[0] != '-' ? "selected" : "rejected", flavour, url.str());
00762         servicesRef[flavour].push_back(url);
00763       }
00764     }
00765 
00766     return true;
00767   }
00768 
00769   bool UserConfig::AddServices(const std::list<std::string>& selected,
00770                                const std::list<std::string>& rejected,
00771                                ServiceType st) {
00772     bool isSelectedNotRejected = true;
00773     const std::string serviceType = tostring(st);
00774     for (std::list<std::string>::const_iterator it = selected.begin();
00775          it != selected.end(); it++) {
00776       if (it == selected.end()) {
00777         if (selected.empty())
00778           break;
00779         it = selected.begin();
00780         isSelectedNotRejected = false;
00781       }
00782 
00783       URLListMap& servicesRef = (isSelectedNotRejected ? (st == COMPUTING ? selectedServices.first : selectedServices.second)
00784                                                        : (st == COMPUTING ? rejectedServices.first : rejectedServices.second));
00785       const std::string& service = *it;
00786 
00787       // Alias cannot contain '.', ':', ' ' or '\t' and a URL must contain atleast one of ':' or '.'.
00788       if (service.find_first_of(":. \t") == std::string::npos) { // Alias.
00789         if (!aliasMap[service]) {
00790           logger.msg(ERROR, "Could not resolve alias \"%s\" it is not defined.", service);
00791           return false;
00792         }
00793 
00794         std::list<std::string> resolvedAliases(1, service);
00795         if (!ResolveAlias(servicesRef, st, resolvedAliases))
00796           return false;
00797       }
00798       else { // URL
00799         const std::size_t pos = service.find(":");
00800         if (pos == std::string::npos) {
00801           logger.msg(WARNING, "Cannot parse the specified %s service (%s)", serviceType, service);
00802           continue;
00803         }
00804 
00805         const URL url(service.substr(pos+1));
00806         if (!url || url.Protocol() == "file") {
00807           logger.msg(WARNING, "The specified %s service (%s) is not a valid URL", serviceType, service.substr(pos+1));
00808           continue;
00809         }
00810         const std::string flavour = service.substr(0, pos);
00811         logger.msg(VERBOSE, "Adding %s service %s:%s ", isSelectedNotRejected ? "selected" : "rejected", flavour, url.str());
00812         servicesRef[flavour].push_back(url);
00813       }
00814     }
00815 
00816     return true;
00817   }
00818 
00819   const URLListMap& UserConfig::GetSelectedServices(ServiceType st) const {
00820     return st == COMPUTING ? selectedServices.first : selectedServices.second;
00821   }
00822 
00823   const URLListMap& UserConfig::GetRejectedServices(ServiceType st) const {
00824     return st == COMPUTING ? rejectedServices.first : rejectedServices.second;
00825   }
00826 
00827   void UserConfig::ClearSelectedServices(ServiceType st) {
00828     if (st == COMPUTING)
00829       selectedServices.first.clear();
00830     else
00831       selectedServices.second.clear();
00832   }
00833 
00834   void UserConfig::ClearSelectedServices() {
00835     selectedServices.first.clear();
00836     selectedServices.second.clear();
00837   }
00838 
00839   void UserConfig::ClearRejectedServices(ServiceType st) {
00840     if (st == COMPUTING)
00841       rejectedServices.first.clear();
00842     else
00843       rejectedServices.second.clear();
00844   }
00845 
00846   void UserConfig::ClearRejectedServices() {
00847     rejectedServices.first.clear();
00848     rejectedServices.second.clear();
00849   }
00850 
00851   bool UserConfig::ResolveAlias(URLListMap& services, ServiceType st,
00852                                 std::list<std::string>& resolvedAliases) {
00853     std::list<std::string> valueList;
00854     tokenize(aliasMap[resolvedAliases.back()], valueList, " \t");
00855 
00856     for (std::list<std::string>::const_iterator it = valueList.begin();
00857          it != valueList.end(); it++) {
00858       const std::size_t pos1 = it->find(":");
00859       const std::size_t pos2 = it->find(":", pos1+1);
00860 
00861       if (pos1 == std::string::npos) { // Alias.
00862         const std::string& referedAlias = *it;
00863         if (std::find(resolvedAliases.begin(), resolvedAliases.end(), referedAlias) != resolvedAliases.end()) { // Loop detected.
00864           std::string loopstr = "";
00865           for (std::list<std::string>::const_iterator itloop = resolvedAliases.begin();
00866                itloop != resolvedAliases.end(); itloop++)
00867             loopstr += *itloop + " -> ";
00868           loopstr += referedAlias;
00869           logger.msg(ERROR, "Cannot resolve alias \"%s\". Loop detected: %s", resolvedAliases.front(), loopstr);
00870           return false;
00871         }
00872 
00873         if (!aliasMap[referedAlias]) {
00874           logger.msg(ERROR, "Cannot resolve alias %s, it is not defined", referedAlias);
00875           return false;
00876         }
00877 
00878         resolvedAliases.push_back(referedAlias);
00879         if (!ResolveAlias(services, st, resolvedAliases))
00880           return false;
00881 
00882         resolvedAliases.pop_back();
00883       }
00884       else if (pos2 != std::string::npos) { // serviceType:flavour:URL
00885         const std::string serviceType = it->substr(0, pos1);
00886         if (serviceType != "computing" && serviceType != "index") {
00887           logger.msg(WARNING, "Alias name (%s) contains a unknown servicetype %s at %s", resolvedAliases.front(), serviceType, *it);
00888           continue;
00889         }
00890         else if ((st == COMPUTING && serviceType != "computing") ||
00891                  (st == INDEX && serviceType != "index"))
00892           continue;
00893 
00894         const URL url(it->substr(pos2+1));
00895         if (!url) {
00896           logger.msg(WARNING, "Alias name (%s) contains a wrongly formated URL (%s)", resolvedAliases.front(), it->substr(pos2+1));
00897           continue;
00898         }
00899         const std::string flavour = it->substr(pos1+1, pos2-pos1-1);
00900         logger.msg(VERBOSE, "Adding service %s:%s:%s from resolved alias %s", serviceType, flavour, url.str(), resolvedAliases.back());
00901         services[flavour].push_back(url);
00902       }
00903       else {
00904         logger.msg(WARNING, "Alias (%s) contains a wrongly formated element (%s)", resolvedAliases.front(), *it);
00905       }
00906     }
00907 
00908     return true;
00909   }
00910 
00911   bool UserConfig::ResolveAlias(std::pair<URLListMap, URLListMap>& services,
00912                                 std::list<std::string>& resolvedAliases) {
00913     std::list<std::string> valueList;
00914     tokenize(aliasMap[resolvedAliases.back()], valueList, " \t");
00915 
00916     for (std::list<std::string>::const_iterator it = valueList.begin();
00917          it != valueList.end(); it++) {
00918       const std::size_t pos1 = it->find(":");
00919       const std::size_t pos2 = it->find(":", pos1+1);
00920 
00921       if (pos1 == std::string::npos) { // Alias.
00922         const std::string& referedAlias = *it;
00923         if (std::find(resolvedAliases.begin(), resolvedAliases.end(), referedAlias) != resolvedAliases.end()) { // Loop detected.
00924           std::string loopstr = "";
00925           for (std::list<std::string>::const_iterator itloop = resolvedAliases.begin();
00926                itloop != resolvedAliases.end(); itloop++)
00927             loopstr += *itloop + " -> ";
00928           loopstr += referedAlias;
00929           logger.msg(ERROR, "Cannot resolve alias \"%s\". Loop detected: %s", resolvedAliases.front(), loopstr);
00930           return false;
00931         }
00932 
00933         if (!aliasMap[referedAlias]) {
00934           logger.msg(ERROR, "Cannot resolve alias %s, it is not defined", referedAlias);
00935           return false;
00936         }
00937 
00938         resolvedAliases.push_back(referedAlias);
00939         if (!ResolveAlias(services, resolvedAliases))
00940           return false;
00941 
00942         resolvedAliases.pop_back();
00943       }
00944       else if (pos2 != std::string::npos) { // serviceType:flavour:URL
00945         const std::string serviceType = it->substr(0, pos1);
00946         if (serviceType != "computing" && serviceType != "index") {
00947           logger.msg(WARNING, "Alias name (%s) contains a unknown servicetype %s at %s", resolvedAliases.front(), serviceType, *it);
00948           continue;
00949         }
00950         const URL url(it->substr(pos2+1));
00951         if (!url) {
00952           logger.msg(WARNING, "Alias name (%s) contains a wrongly formated URL (%s)", resolvedAliases.front(), it->substr(pos2+1));
00953           continue;
00954         }
00955         const std::string flavour = it->substr(pos1+1, pos2-pos1-1);
00956         logger.msg(VERBOSE, "Adding service %s:%s:%s from resolved alias %s", serviceType, flavour, url.str(), resolvedAliases.back());
00957         if (serviceType == "computing")
00958           services.first[flavour].push_back(url);
00959         else
00960           services.second[flavour].push_back(url);
00961       }
00962       else {
00963         logger.msg(WARNING, "Alias (%s) contains a wrongly formated element (%s)", resolvedAliases.front(), *it);
00964       }
00965     }
00966 
00967     return true;
00968   }
00969 
00970   void UserConfig::setDefaults() {
00971     timeout = DEFAULT_TIMEOUT;
00972     broker.first = DEFAULT_BROKER;
00973     broker.second = "";
00974   }
00975 
00976   bool UserConfig::makeDir(const std::string& path) {
00977     bool dirCreated = false;
00978 #ifdef HAVE_GIOMM
00979     try {
00980       dirCreated = Gio::File::create_for_path(path)->make_directory();
00981     } catch (Glib::Error e) {
00982       logger.msg(WARNING, "%s", (std::string)e.what());
00983     }
00984 #else
00985     dirCreated = (mkdir(path.c_str(), 0755) == 0);
00986 #endif
00987 
00988     if (dirCreated)
00989       logger.msg(INFO, "%s directory created", path);
00990 
00991     return dirCreated;
00992   }
00993 
00994   bool UserConfig::copyFile(const std::string& source, const std::string& destination) {
00995 #ifdef HAVE_GIOMM
00996     try {
00997       return Gio::File::create_for_path(source)->copy(Gio::File::create_for_path(destination), Gio::FILE_COPY_NONE);
00998     } catch (Gio::Error e) {
00999       logger.msg(WARNING, "%s", (std::string)e.what());
01000       return false;
01001     }
01002 #else
01003     std::ifstream ifsSource(source.c_str(), std::ios::in | std::ios::binary);
01004     if (!ifsSource)
01005       return false;
01006 
01007     std::ofstream ofsDestination(destination.c_str(), std::ios::out | std::ios::binary);
01008     if (!ofsDestination)
01009       return false;
01010 
01011     int bytesRead = -1;
01012     char buff[1024];
01013     while (bytesRead != 0) {
01014       ifsSource.read((char*)buff, 1024);
01015       bytesRead = ifsSource.gcount();
01016       ofsDestination.write((char*)buff, bytesRead);
01017     }
01018 
01019     return true;
01020 #endif
01021   }
01022 
01023 } // namespace Arc