rconfig.cc

Go to the documentation of this file.
00001 #include "config.h"
00002 
00003 #include <iostream>
00004 #include <string>
00005 #include <fstream>
00006 #include <vector>
00007 #include <map>
00008 #include <algorithm>
00009 #include <cctype>
00010 
00011 #include "asserts.h"
00012 #include "error.h"
00013 #include "estring.h"
00014 #include "fs.h"
00015 #include "tstamp.h"
00016 
00017 #include "rconfig.h"
00018 
00019 //----------------------------------------------------------------------------
00020 
00021 /** Reset to a default value */
00022 void archive_path_element::clear(void)
00023 {
00024         m_type = jobname;
00025         m_literal.erase();
00026 }
00027 
00028 /** C'tor */
00029 archive_path_element::archive_path_element()
00030 {
00031         clear();
00032 }
00033 
00034 /** C'tor */
00035 archive_path_element::archive_path_element(
00036         const archive_path_element& a_class)
00037 {
00038         clear();
00039         assign(a_class);
00040 }
00041 
00042 /** C'tor */
00043 archive_path_element::archive_path_element(
00044         const archive_path_element::element_type& a_enum
00045         )
00046 {
00047         clear();
00048         assign(a_enum);
00049 }
00050 
00051 /** C'tor */
00052 archive_path_element::archive_path_element(const std::string& a_str)
00053 {
00054         clear();
00055         assign(a_str);
00056 }
00057 
00058 /** Assign the value from another archive_path_element instance */
00059 void archive_path_element::assign(const archive_path_element& a_class)
00060 {
00061         if (this == &a_class)
00062                 return;
00063 
00064         if (a_class.type() == literal)
00065                 assign(a_class.str());
00066         else
00067                 assign(a_class.type());
00068 }
00069 
00070 /** Assign any type except literal */
00071 void archive_path_element::assign(
00072         const archive_path_element::element_type& a_enum
00073         )
00074 {
00075         m_type = a_enum;
00076         if (m_type != literal) {
00077                 m_literal.erase();
00078         }
00079 }
00080 
00081 /** Assign a literal */
00082 void archive_path_element::assign(const std::string& a_str)
00083 {
00084         std::string es;
00085         std::string str;
00086         std::string::size_type idx;
00087 
00088         TRY_nomem(es = "Invalid archive-path keyword: \"");
00089         TRY_nomem(es += a_str);
00090         TRY_nomem(es += "\"");
00091 
00092         if (a_str.size() == 0) {
00093                 throw(ERROR(0,es));
00094         }
00095         if (a_str[0] == '"') {
00096                 if (a_str.size() < 3) {
00097                         throw(ERROR(0,es));
00098                 }
00099                 if (a_str[a_str.size()-1] != '"') {
00100                         throw(ERROR(0,es));
00101                 }
00102                 TRY_nomem(str = a_str.substr(1,a_str.size()-2));
00103 
00104                 idx = str.find('"');
00105                 while (idx != std::string::npos) {
00106                         if ((idx > 0) && (str[idx-1] != '\\'))
00107                                 throw(ERROR(0,es));
00108                         idx = str.find('"',idx+1);
00109                 }
00110 
00111                 idx = str.find("\\\"");
00112                 while (idx != std::string::npos) {
00113                         str.erase(idx,1);
00114                         idx = str.find("\\\"");
00115                 }
00116 
00117                 TRY_nomem(m_literal = str);
00118                 m_type = literal;
00119         }
00120         else {
00121                 str = estring(a_str).lower();
00122                 if (str == "jobname") {
00123                         assign(jobname);
00124                 }
00125                 else if (str == "groupname") {
00126                         assign(groupname);
00127                 }
00128                 else if (str == "hostname") {
00129                         assign(hostname);
00130                 }
00131                 else if (str == "pathname") {
00132                         assign(pathname);
00133                 }
00134                 else if (str == "permutation") {
00135                         assign(permutation);
00136                 }
00137                 else {
00138                         throw(ERROR(0,es));
00139                 }
00140         }
00141 }
00142 
00143 /** Retrieve the current type */
00144 const archive_path_element::element_type& 
00145         archive_path_element::type(void) const
00146 {
00147         return(m_type);
00148 }
00149 
00150 /** Retrieve the current literal value */
00151 const std::string& archive_path_element::value(void) const
00152 {
00153         return(m_literal);
00154 }
00155 
00156 /** Construct a string of the current value */
00157 const std::string archive_path_element::str(void) const
00158 {
00159         std::string::size_type idx;
00160         std::string value;
00161 
00162         if (m_type == jobname) {
00163                 TRY_nomem(value = "jobname");
00164         }
00165         else if (m_type == groupname) {
00166                 TRY_nomem(value = "groupname");
00167         }
00168         else if (m_type == hostname) {
00169                 TRY_nomem(value = "hostname");
00170         }
00171         else if (m_type == pathname) {
00172                 TRY_nomem(value = "pathname");
00173         }
00174         else if (m_type == permutation) {
00175                 TRY_nomem(value = "permutation");
00176         }
00177         else {
00178                 TRY_nomem(value = "\"");
00179                 for (idx = 0; idx != m_literal.size(); idx++) {
00180                         if (m_literal[idx] == '"') {
00181                                 TRY_nomem(value += '\\');
00182                         }
00183                         TRY_nomem(value += m_literal[idx]);
00184                 }
00185                 TRY_nomem(value += '"');
00186         }
00187 
00188         return(value);
00189 }
00190 
00191 /** Assignment */
00192 archive_path_element& 
00193         archive_path_element::operator=(const archive_path_element& a_class)
00194 {
00195         clear();
00196         assign(a_class);
00197 
00198         return(*this);
00199 }
00200 
00201 /** Assignment */
00202 archive_path_element& 
00203         archive_path_element::operator=(
00204                 const archive_path_element::element_type a_enum)
00205 {
00206         clear();
00207         assign(a_enum);
00208 
00209         return(*this);
00210 }
00211 
00212 /** Assignment */
00213 archive_path_element& 
00214         archive_path_element::operator=(const std::string& a_str)
00215 {
00216         clear();
00217         assign(a_str);
00218 
00219         return(*this);
00220 }
00221 
00222 //----------------------------------------------------------------------------
00223 
00224 /** Reset to a default value */
00225 void archive_path::reset(void)
00226 {
00227         clear();
00228         push_back("hostname/pathname");
00229 }
00230 
00231 /** C'tor */
00232 archive_path::archive_path()
00233 {
00234         reset();
00235 }
00236 
00237 /** C'tor */
00238 archive_path::archive_path(const archive_path& a_class)
00239 {
00240         push_back(a_class);
00241 }
00242 
00243 /** C'tor */
00244 archive_path::archive_path(const archive_path_element& a_class)
00245 {
00246         push_back(a_class);
00247 }
00248 
00249 /** C'tor */
00250 archive_path::archive_path(const std::string& a_str)
00251 {
00252         push_back(a_str);
00253 }
00254 
00255 /** Add elements to the path list from another archive_path instance */
00256 void archive_path::push_back(const archive_path& a_class)
00257 {
00258         const_iterator li;
00259 
00260         for (li = a_class.begin(); li != a_class.end(); li++) {
00261                 TRY_nomem(push_back(*li));
00262         }
00263 }
00264 
00265 /** Add an element to the path list from an archive_path_element instance */
00266 void archive_path::push_back(const archive_path_element& a_class)
00267 {
00268         TRY_nomem(type::push_back(a_class));
00269 }
00270 
00271 /** Parse a string into an archive-path list */
00272 void archive_path::push_back(const std::string& a_str)
00273 {
00274         std::string es;
00275         std::string keyword;
00276         std::string str;
00277         std::string::size_type idx;
00278         archive_path_element ape;
00279 
00280         if (a_str.size() == 0)
00281                 return;
00282 
00283         TRY_nomem(str = a_str);
00284         if (str[0] == '/')
00285                 str.erase(0,1);
00286         if (str[str.size()-1] == '/')
00287                 str.erase(str.size()-1,1);
00288         
00289         while (str.size() > 0) {
00290                 idx = str.find('/');
00291                 if (idx == std::string::npos) {
00292                         TRY_nomem(keyword = str);
00293                         str.erase();
00294                 }
00295                 else {
00296                         TRY_nomem(keyword = str.substr(0,idx));
00297                         str.erase(0,idx+1);
00298                 }
00299 
00300                 ape.clear();
00301                 TRY_nomem(es = "At: \"");
00302                 TRY_nomem(es += keyword);
00303                 TRY_nomem(es += "\"");
00304                 TRY(ape.assign(keyword),es);
00305                 TRY_nomem(push_back(ape));
00306         }
00307 }
00308 
00309 /** Reconstruct a string from an archive-path list */
00310 const std::string archive_path::str(void) const
00311 {
00312         std::string str;
00313         const_iterator li;
00314 
00315         for (li = begin(); li != end(); li++) {
00316                 if (li != begin()) {
00317                         TRY_nomem(str += '/');
00318                 }
00319                 TRY_nomem(str += (*li).str());
00320         }
00321 
00322         return(str);
00323 }
00324 
00325 /** Assign an archive-path list from another archive_path instance */
00326 void archive_path::assign(const archive_path& a_class)
00327 {
00328         if (this != &a_class) {
00329                 clear();
00330                 push_back(a_class);
00331         }
00332 }
00333 
00334 /** Assign an archive-path list from a single archive_path_element instance */
00335 void archive_path::assign(const archive_path_element& a_class)
00336 {
00337         clear();
00338         push_back(a_class);
00339 }
00340 
00341 /** Assign an archive-path list from a string (parse the string) */
00342 void archive_path::assign(const std::string& a_str)
00343 {
00344         clear();
00345         push_back(a_str);
00346 }
00347 
00348 /** Assignment */
00349 archive_path& archive_path::operator=(const archive_path& a_class)
00350 {
00351         assign(a_class);
00352 
00353         return(*this);
00354 }
00355 
00356 /** Assignment */
00357 archive_path& archive_path::operator=(const archive_path_element& a_class)
00358 {
00359         assign(a_class);
00360 
00361         return(*this);
00362 }
00363 
00364 /** Assignment */
00365 archive_path& archive_path::operator=(const std::string& a_str)
00366 {
00367         assign(a_str);
00368 
00369         return(*this);
00370 }
00371 
00372 //----------------------------------------------------------------------------
00373 
00374 /** Default behavior */
00375 const uint16 rsync_behavior::default_behavior;
00376 
00377 /** Clear all values and set the default to "retry" */
00378 void rsync_behavior::clear(void)
00379 {
00380         m_map.clear();
00381         m_default = retry;
00382 }
00383 
00384 /** Clear all values and set some sane default actions */
00385 void rsync_behavior::reset(void)
00386 {
00387         clear();
00388         m_default = retry;
00389         TRY_nomem(
00390                 m_map[0] = ok;
00391                 m_map[1] = fail;
00392                 m_map[2] = fail;
00393                 m_map[4] = fail;
00394                 m_map[23] = retry_without_hardlinks;
00395                 m_map[124] = fail;
00396                 m_map[125] = fail;
00397                 m_map[126] = fail;
00398                 m_map[127] = fail;
00399         );
00400 }
00401 
00402 /** C'tor */
00403 rsync_behavior::rsync_behavior()
00404 {
00405         reset();
00406 }
00407 
00408 /** C'tor */
00409 rsync_behavior::rsync_behavior(const rsync_behavior& a_class)
00410 {
00411         assign(a_class);
00412 }
00413 
00414 /** Assign an action to be taken for a specific exit code */
00415 void rsync_behavior::assign(const uint16 a_code, const value_type a_action)
00416 {
00417         if (a_code == default_behavior)
00418                 m_default = a_action;
00419         else {
00420                 TRY_nomem(m_map[a_code] = a_action);
00421         }
00422 }
00423 
00424 /** Assign actions to be taken from another rsync_behavior instance */
00425 void rsync_behavior::assign(const rsync_behavior& a_class)
00426 {
00427         if (this == &a_class)
00428                 return;
00429 
00430         clear();
00431         m_default = a_class.default_value();
00432         TRY_nomem(m_map = a_class.map_value());
00433 }
00434 
00435 /**
00436         Assign actions to be taken from a string (parse a string in the form of
00437         exit-code '=' action)
00438  */
00439 void rsync_behavior::assign(const std::string& a_str)
00440 {
00441         std::string es;
00442         std::string code_str;
00443         std::string action_str;
00444         uint16 code;
00445         rsync_behavior::behavior_type action;
00446         std::string::size_type idx;
00447 
00448         TRY_nomem(es = "Invalid rsync-behavior value: \"");
00449         TRY_nomem(es += a_str);
00450         TRY_nomem(es += "\"");
00451 
00452         TRY_nomem(action_str = a_str);
00453         idx = 0;
00454         while (isdigit(action_str[idx]) || (action_str[idx] == '*'))
00455                 ++idx;
00456         TRY_nomem(code_str = action_str.substr(0,idx));
00457         action_str.erase(0,idx);
00458         if (code_str.size() == 0)
00459                 throw(ERROR(0,es));
00460 
00461         idx = 0;
00462         while ((action_str[idx] == ' ') || (action_str[idx] == '\t'))
00463                 idx++;
00464         action_str.erase(0,idx);
00465 
00466         if (action_str[0] != '=')
00467                 throw(ERROR(0,es));
00468         action_str.erase(0,1);
00469 
00470         idx = 0;
00471         while ((action_str[idx] == ' ') || (action_str[idx] == '\t'))
00472                 idx++;
00473         action_str.erase(0,idx);
00474 
00475         if (code_str == "*")
00476                 code = rsync_behavior::default_behavior;
00477         else
00478                 code = estring(code_str);
00479         if (estring(action_str).lower() == "ok")
00480                 action = rsync_behavior::ok;
00481         else if (estring(action_str).lower() == "fail")
00482                 action = rsync_behavior::fail;
00483         else if (estring(action_str).lower() == "retry")
00484                 action = rsync_behavior::retry;
00485         else if (estring(action_str).lower() == "retry-without-hardlinks")
00486                 action = rsync_behavior::retry_without_hardlinks;
00487         else if (estring(action_str).lower() == "ok")
00488                 action = rsync_behavior::quit;
00489         else
00490                 throw(ERROR(0,es));
00491         assign(code, action);
00492 }
00493 
00494 /** Return the action to be taken for a given exit code */
00495 const rsync_behavior::value_type 
00496         rsync_behavior::operator[](const uint16 a_code) const
00497 {
00498         if (a_code == default_behavior) {
00499                 return(m_default);
00500         }
00501         if (m_map.find(a_code) != m_map.end()) {
00502                 return(m_map.find(a_code)->second);
00503         }
00504         return(m_default);
00505 }
00506 
00507 /** Return the action to be taken for a given exit code */
00508 rsync_behavior::value_type&
00509         rsync_behavior::operator[](const uint16 a_code)
00510 {
00511         if (a_code == default_behavior) {
00512                 return(m_default);
00513         }
00514         return(m_map[a_code]);
00515 }
00516 
00517 /** Assignment */
00518 rsync_behavior& rsync_behavior::operator=(const rsync_behavior& a_class)
00519 {
00520         assign(a_class);
00521 
00522         return(*this);
00523 }
00524 
00525 /** Assignment */
00526 rsync_behavior& 
00527         rsync_behavior::operator=(const rsync_behavior::behavior_type a_enum)
00528 {
00529         assign(default_behavior, a_enum);
00530 
00531         return(*this);
00532 }
00533 
00534 /** Assignment */
00535 rsync_behavior& rsync_behavior::operator=(const std::string& a_str)
00536 {
00537         assign(a_str);
00538 
00539         return(*this);
00540 }
00541 
00542 /** Return the default action */
00543 const rsync_behavior::behavior_type rsync_behavior::default_value(void) const
00544 {
00545         return(m_default);
00546 }
00547 
00548 /** Return an std::map of exit codes to actions */
00549 const rsync_behavior::map_type& rsync_behavior::map_value(void) const
00550 {
00551         return(m_map);
00552 }
00553 
00554 //----------------------------------------------------------------------------
00555 
00556 /** C'tor */
00557 job::job()
00558 {
00559         clear();
00560 }
00561 
00562 /** C'tor */
00563 job::job(const job& a_job)
00564 {
00565         clear();
00566         assign(a_job);
00567 }
00568 
00569 /** Clear values */
00570 void job::clear(void)
00571 {
00572         default_config_path.erase();
00573         default_config_line = 0;
00574         config_path.erase();
00575         config_line = 0;
00576         archive_path = "hostname/pathname";
00577         excludes.clear();
00578         includes.clear();
00579         groupname.erase();
00580         hostname.erase();
00581         jobname.erase();
00582         paths.clear();
00583         rsync_behavior.reset();
00584         rsync_connection = connection_remote;
00585         rsync_hardlink = true;
00586         rsync_multi_hardlink = false;
00587         rsync_multi_hardlink_max = 20;
00588         rsync_options.erase();
00589         rsync_remote_user.erase();
00590         rsync_remote_path.erase();
00591         rsync_remote_port = 0;
00592         rsync_remote_module.erase();
00593         rsync_retry_count = 3;
00594         rsync_retry_delay = 0;
00595         rsync_timeout = 60 * 60 * 4; // 4 hours;
00596 }
00597 
00598 /** Assign values from another job instance */
00599 void job::assign(const job& a_job)
00600 {
00601         clear();
00602 
00603         default_config_path = a_job.default_config_path;
00604         default_config_line = a_job.default_config_line;
00605         config_path = a_job.config_path;
00606         config_line = a_job.config_line;
00607         archive_path = a_job.archive_path;
00608         excludes = a_job.excludes;
00609         includes = a_job.includes;
00610         groupname = a_job.groupname;
00611         hostname = a_job.hostname;
00612         jobname = a_job.jobname;
00613         paths = a_job.paths;
00614         rsync_behavior.clear();
00615         rsync_behavior = a_job.rsync_behavior;
00616         rsync_connection = a_job.rsync_connection;
00617         rsync_hardlink = a_job.rsync_hardlink;
00618         rsync_multi_hardlink = a_job.rsync_multi_hardlink;
00619         rsync_multi_hardlink_max = a_job.rsync_multi_hardlink_max;
00620         rsync_options = a_job.rsync_options;
00621         rsync_remote_user = a_job.rsync_remote_user;
00622         rsync_remote_path = a_job.rsync_remote_path;
00623         rsync_remote_port = a_job.rsync_remote_port;
00624         rsync_remote_module = a_job.rsync_remote_module;
00625         rsync_retry_count = a_job.rsync_retry_count;
00626         rsync_retry_delay = a_job.rsync_retry_delay;
00627         rsync_timeout = a_job.rsync_timeout;
00628 }
00629 
00630 /** Assignment */
00631 job& job::operator=(const job& a_job)
00632 {
00633         assign(a_job);
00634 
00635         return(*this);
00636 }
00637 
00638 /** Generate the archive-path subdirectory for this job */
00639 const std::string job::generate_archive_path(const std::string& a_path) const
00640 {
00641         std::string es;
00642         std::string path;
00643         archive_path::const_iterator capi;
00644 
00645         for (capi = archive_path.begin(); capi != archive_path.end(); ++capi) {
00646                 if (capi->type() == archive_path_element::jobname) {
00647                         if (jobname.size() == 0) {
00648                                 TRY_nomem(es = "archive-path references jobname, ");
00649                                 TRY_nomem(es += "but jobname is empty");
00650                                 throw(ERROR(0,es));
00651                         }
00652                         if (path.size() != 0) {
00653                                 TRY_nomem(path += '/');
00654                         }
00655                         TRY_nomem(path += jobname);
00656                 }
00657                 else if (capi->type() == archive_path_element::groupname) {
00658                         if (groupname.size() == 0) {
00659                                 TRY_nomem(es = "archive-path references groupname, ");
00660                                 TRY_nomem(es += "but groupname is empty");
00661                                 throw(ERROR(0,es));
00662                         }
00663                         if (path.size() != 0) {
00664                                 TRY_nomem(path += '/');
00665                         }
00666                         TRY_nomem(path += groupname);
00667                 }
00668                 else if (capi->type() == archive_path_element::hostname) {
00669                         if (hostname.size() == 0) {
00670                                 TRY_nomem(es = "archive-path references hostname, ");
00671                                 TRY_nomem(es += "but hostname is empty");
00672                                 throw(ERROR(0,es));
00673                         }
00674                         if (path.size() != 0) {
00675                                 TRY_nomem(path += '/');
00676                         }
00677                         TRY_nomem(path += hostname);
00678                 }
00679                 else if (capi->type() == archive_path_element::pathname) {
00680                         if (a_path.size() == 0) {
00681                                 TRY_nomem(es = "archive-path references path name, ");
00682                                 TRY_nomem(es += "but path name is empty");
00683                                 throw(ERROR(0,es));
00684                         }
00685                         if (path.size() != 0) {
00686                                 TRY_nomem(path += '/');
00687                         }
00688                         TRY_nomem(path += a_path);
00689                 }
00690                 else if (capi->type() == archive_path_element::permutation) {
00691                         if (a_path.size() == 0) {
00692                                 TRY_nomem(es = "archive-path references path name, ");
00693                                 TRY_nomem(es += "but path name is empty");
00694                                 throw(ERROR(0,es));
00695                         }
00696                         if (path.size() != 0) {
00697                                 TRY_nomem(path += '/');
00698                         }
00699                         TRY_nomem(path += permute_path(a_path));
00700                 }
00701                 else if (capi->type() == archive_path_element::literal) {
00702                         if (capi->value().size() == 0) {
00703                                 TRY_nomem(es = "archive-path references literal string, ");
00704                                 TRY_nomem(es += "but literal string value is empty");
00705                                 throw(INTERNAL_ERROR(0,es));
00706                         }
00707                         if (path.size() != 0) {
00708                                 TRY_nomem(path += '/');
00709                         }
00710                         TRY_nomem(path += capi->value());
00711                 }
00712                 else
00713                         throw(INTERNAL_ERROR(0,"Unknown archive path element type"));
00714         }
00715 
00716         // If path does not end with a '/', strip off characters until it does.
00717         while ((path.size() > 0) && (path[path.size()-1] != '/'))
00718                 path.erase(path.size()-1);
00719 
00720         path = reform_path(path);
00721 
00722         return(path);
00723 }
00724 
00725 /** Generate the source path to be passed to rsync on the command line */
00726 const std::string job::generate_source_path(const std::string& a_path) const
00727 {
00728         estring path;
00729 
00730         if (rsync_connection == connection_server) {
00731                 path += "rsync://";
00732                 if (rsync_remote_user.size() != 0) {
00733                         path += rsync_remote_user;
00734                         path += "@";
00735                 }
00736                 TRY_nomem(path += hostname);
00737                 if (rsync_remote_port != 0) {
00738                         path += ":";
00739                         path += estring(rsync_remote_port);
00740                 }
00741                 if (rsync_remote_module.size() != 0) {
00742                         path += "/";
00743                         path += rsync_remote_module;
00744                         if ((a_path.size() > 0) && (a_path[0] != '/'))
00745                                 path += "/";
00746                 }
00747         }
00748         else if (rsync_connection == connection_remote) {
00749                 if (rsync_remote_user.size() != 0) {
00750                         path += rsync_remote_user;
00751                         path += "@";
00752                 }
00753                 path += hostname;
00754                 path += ":";
00755         }
00756         path += a_path;
00757 
00758         return(path);
00759 }
00760 
00761 /** Find the common pathname among all job paths (may be an empty string) */
00762 const std::string job::common_pathname(void) const
00763 {
00764         std::string common_path;
00765         paths_type::size_type pidx;
00766         std::string::size_type sidx;
00767         std::string::size_type max_sidx;
00768         bool same;
00769 
00770         TRY_nomem(common_path = "");
00771         sidx = 0;
00772         max_sidx = paths[0].size();
00773         for (pidx = 0; pidx < paths.size(); pidx++) {
00774                 if (max_sidx > paths[pidx].size()) {
00775                         max_sidx = paths[pidx].size();
00776                 }
00777         }
00778         same = true;
00779         for (sidx = 0; sidx < max_sidx; sidx++) {
00780                 for (pidx = 0; (same && (pidx < paths.size())); pidx++) {
00781                         if (pidx == 0)
00782                                 continue;
00783                         if (paths[pidx-1][sidx] != paths[pidx][sidx])
00784                                 same = false;
00785                 }
00786                 if (same)
00787                         TRY_nomem(common_path += paths[0][sidx]);
00788         }
00789         if (common_path[0] == '/')
00790                 common_path.erase(0,1);
00791         if ((common_path.size() > 0) && (common_path[common_path.size()-1] == '/'))
00792                 common_path.erase(common_path.size()-1);
00793 
00794         return(common_path);
00795 }
00796 
00797 /** Generate a unique ID string for this job */
00798 const std::string job::generate_job_id(void) const
00799 {
00800         std::string es;
00801         std::string path;
00802         archive_path::const_iterator capi;
00803 
00804         for (capi = archive_path.begin(); capi != archive_path.end(); ++capi) {
00805                 if (capi->type() == archive_path_element::jobname) {
00806                         if (jobname.size() == 0) {
00807                                 TRY_nomem(es = "archive-path references jobname, ");
00808                                 TRY_nomem(es += "but jobname is empty");
00809                                 throw(ERROR(0,es));
00810                         }
00811                         if (path.size() != 0) {
00812                                 TRY_nomem(path += '/');
00813                         }
00814                         TRY_nomem(path += jobname);
00815                 }
00816                 else if (capi->type() == archive_path_element::groupname) {
00817                         if (groupname.size() == 0) {
00818                                 TRY_nomem(es = "archive-path references groupname, ");
00819                                 TRY_nomem(es += "but groupname is empty");
00820                                 throw(ERROR(0,es));
00821                         }
00822                         if (path.size() != 0) {
00823                                 TRY_nomem(path += '/');
00824                         }
00825                         TRY_nomem(path += groupname);
00826                 }
00827                 else if (capi->type() == archive_path_element::hostname) {
00828                         if (hostname.size() == 0) {
00829                                 TRY_nomem(es = "archive-path references hostname, ");
00830                                 TRY_nomem(es += "but hostname is empty");
00831                                 throw(ERROR(0,es));
00832                         }
00833                         if (path.size() != 0) {
00834                                 TRY_nomem(path += '/');
00835                         }
00836                         TRY_nomem(path += hostname);
00837                 }
00838                 else if (capi->type() == archive_path_element::pathname) {
00839                         if (path.size() == 0) {
00840                                 TRY_nomem(path += common_pathname());
00841                         }
00842                 }
00843                 else if (capi->type() == archive_path_element::permutation) {
00844                         if (path.size() == 0) {
00845                                 TRY_nomem(path += permute_path(common_pathname()));
00846                         }
00847                 }
00848                 else if (capi->type() == archive_path_element::literal) {
00849                         if (capi->value().size() == 0) {
00850                                 TRY_nomem(es = "archive-path references literal string, ");
00851                                 TRY_nomem(es += "but literal string value is empty");
00852                                 throw(INTERNAL_ERROR(0,es));
00853                         }
00854                         if (path.size() != 0) {
00855                                 TRY_nomem(path += '/');
00856                         }
00857                         TRY_nomem(path += capi->value());
00858                 }
00859         }
00860 
00861         path = reform_path(path);
00862 
00863         if (path.size() == 0) {
00864                 TRY_nomem(path = jobname);
00865         }
00866         return(path);
00867 }
00868 
00869 /*
00870  * For some reason this doesn't work:
00871  * See following log output:
00872 
00873         2008.05.07 17:50:31 [ 18325]> [Job:0x84001b0] Command Line:
00874         2008.05.07 17:50:31 [ 18325]> [Job:0x84001b0]   Binary: /usr/bin/rsync
00875         2008.05.07 17:50:31 [ 18325]> [Job:0x84001b0]     Argv[0] = -a
00876         2008.05.07 17:50:31 [ 18325]> [Job:0x84001b0]     Argv[1] = -e
00877         2008.05.07 17:50:31 [ 18325]> [Job:0x84001b0]     Argv[2] = "/usr/bin/ssh -l root"
00878         2008.05.07 17:50:31 [ 18325]> [Job:0x84001b0]     Argv[3] = --delete
00879         2008.05.07 17:50:31 [ 18325]> [Job:0x84001b0]     Argv[4] = --delete-excluded
00880         2008.05.07 17:50:31 [ 18325]> [Job:0x84001b0]     Argv[5] = --force
00881         2008.05.07 17:50:31 [ 18325]> [Job:0x84001b0]     Argv[6] = --ignore-errors
00882         2008.05.07 17:50:31 [ 18325]> [Job:0x84001b0]     Argv[7] = --one-file-system
00883         2008.05.07 17:50:31 [ 18325]> [Job:0x84001b0]     Argv[8] = --progress
00884         2008.05.07 17:50:31 [ 18325]> [Job:0x84001b0]     Argv[9] = --exclude
00885         2008.05.07 17:50:31 [ 18325]> [Job:0x84001b0]     Argv[10] = '/tmp'
00886         2008.05.07 17:50:31 [ 18325]> [Job:0x84001b0]     Argv[11] = --exclude
00887         2008.05.07 17:50:31 [ 18325]> [Job:0x84001b0]     Argv[12] = '/var/crash'
00888         2008.05.07 17:50:31 [ 18325]> [Job:0x84001b0]     Argv[13] = --exclude
00889         2008.05.07 17:50:31 [ 18325]> [Job:0x84001b0]     Argv[14] = '/var/tmp'
00890         2008.05.07 17:50:31 [ 18325]> [Job:0x84001b0]     Argv[15] = --exclude
00891         2008.05.07 17:50:31 [ 18325]> [Job:0x84001b0]     Argv[16] = '**core'
00892         2008.05.07 17:50:31 [ 18325]> [Job:0x84001b0]     Argv[17] = --rsync-path=/usr/local/bin/rsync
00893         2008.05.07 17:50:31 [ 18325]> [Job:0x84001b0]     Argv[18] = --hard-links
00894         2008.05.07 17:50:31 [ 18325]> [Job:0x84001b0]     Argv[19] = --link-dest=../../../../2008-04-26/alces/var/spool/
00895         2008.05.07 17:50:31 [ 18325]> [Job:0x84001b0]     Argv[20] = alces:/var/spool/
00896         2008.05.07 17:50:31 [ 18325]> [Job:0x84001b0]     Argv[21] = /export/raid/0/vault/2008-05-07.incomplete/alces/var/spool/
00897         2008.05.07 17:50:38 [ 18325]> [Job:0x84001b0] [RSYNC]: rsync: Failed to exec /usr/bin/ssh -l root: No such file or directory (2)
00898         2008.05.07 17:50:38 [ 18325]> [Job:0x84001b0] [RSYNC]: rsync error: error in IPC code (code 14) at pipe.c(86) [receiver=2.6.9]
00899         2008.05.07 17:50:38 [ 18325]> [Job:0x84001b0] [RSYNC]: rsync: writefd_unbuffered failed to write 4 bytes [receiver]: Broken pipe (32)
00900         2008.05.07 17:50:38 [ 18325]> [Job:0x84001b0] [RSYNC]: rsync error: error in IPC code (code 14) at io.c(1122) [receiver=2.6.9]
00901         2008.05.07 17:50:45 [ 18325]> [Job:0x84001b0] Rsync exit code: [14] Error in IPC code
00902  */
00903 const std::vector<std::string> job::generate_rsync_options_vector(void) const
00904 {
00905         const char *ptr = rsync_options.c_str();
00906         std::vector<std::string> argv;
00907 
00908         while (*ptr != 0) {
00909                 std::string str;
00910                 // TODO: This section needs more work:
00911                 switch (*ptr) {
00912                         case '\0':
00913                                 break;
00914                         case '\'':
00915                                 ptr++;
00916                                 while ((*ptr != 0) && (*ptr != '\'')) {
00917                                         str += (*ptr);
00918                                         ptr++;
00919                                 }
00920                                 if (*ptr == '\'') {
00921                                         ptr++;
00922                                 }
00923                                 if ((*ptr == ' ') || (*ptr == '\t')) {
00924                                         ptr++;
00925                                 }
00926                                 break;
00927                         case '"':
00928                                 ptr++;
00929                                 while ((*ptr != 0) && (*ptr != '\"')) {
00930                                         str += (*ptr);
00931                                         ptr++;
00932                                 }
00933                                 if (*ptr == '\"') {
00934                                         ptr++;
00935                                 }
00936                                 if ((*ptr == ' ') || (*ptr == '\t')) {
00937                                         ptr++;
00938                                 }
00939                                 break;
00940                         default:
00941                                 while ((*ptr != 0) && (*ptr != ' ') && (*ptr != '\t')) {
00942                                         if (*ptr != '\\') {
00943                                                 str += (*ptr);
00944                                                 ptr++;
00945                                         }
00946                                         else {
00947                                                 ptr++;
00948                                                 switch (*ptr) {
00949                                                         case ' ':
00950                                                                 str += ' ';
00951                                                                 ptr++;
00952                                                                 break;
00953                                                         case 't':
00954                                                                 str += '\t';
00955                                                                 ptr++;
00956                                                                 break;
00957                                                         default:
00958                                                                 str = (*ptr);
00959                                                                 break;
00960                                                 }
00961                                         }
00962                                 }
00963                                 if ((*ptr == ' ') || (*ptr == '\t')) {
00964                                         ptr++;
00965                                 }
00966                                 break;
00967                 }
00968                 // Ensure that extra spaces between options does not result in
00969                 // "" as a command line argument.
00970                 if (str.size()) {
00971                         argv.push_back(str);
00972                 }
00973         }
00974 
00975         return(argv);
00976 }
00977 
00978 /** Perform sanity checks for the configuration settings of this job */
00979 void job::check(void)
00980 {
00981         std::string es;
00982         std::string this_path;
00983         std::string that_path;
00984         paths_type::const_iterator cpi;
00985         configuration_manager::jobs_type::const_iterator cji;
00986         paths_type::const_iterator cjapi;
00987 
00988         if (
00989                         (
00990                                 (rsync_connection == connection_remote) 
00991                                 || (rsync_connection == connection_server)
00992                         )
00993                         && (hostname.size() == 0)
00994                 )
00995         {
00996                 TRY_nomem(es = "rsync-connection-type references hostname, ");
00997                 TRY_nomem(es += "but hostname is empty");
00998                 throw(ERROR(0,es));
00999         }
01000 
01001         if ((rsync_remote_module.size() != 0) 
01002                 && (rsync_connection != connection_server)) 
01003         {
01004                 TRY_nomem(es = "rsync-remote-module specifies a module, but ");
01005                 TRY_nomem(es = "rsync-connection-type is not server");
01006                 throw(ERROR(0,es));
01007         }
01008 
01009         if (paths.size() == 0) {
01010                 throw(ERROR(0,"No paths defined for this job"));
01011         }
01012 
01013         for (cpi = paths.begin() ; cpi != paths.end(); cpi++) {
01014                 TRY_nomem(this_path = generate_archive_path(*cpi));
01015 
01016                 for (
01017                         cji = config.jobs().begin();
01018                         cji != config.jobs().end();
01019                         cji++
01020                         )
01021                 {
01022                         for (
01023                                 cjapi = cji->paths.begin();
01024                                 cjapi != cji->paths.end();
01025                                 cjapi++
01026                                 )
01027                         {
01028                                 TRY_nomem(that_path = cji->generate_archive_path(*cjapi));
01029 
01030                                 if (this_path == that_path) {
01031                                         error e(0);
01032 
01033                                         TRY_nomem(es = "Duplicate archive-path values detected");
01034                                         e.push_back(ERROR_INSTANCE(es));
01035                                         TRY_nomem(es = "Archive path: \"");
01036                                         TRY_nomem(es += this_path);
01037                                         TRY_nomem(es += "\"");
01038                                         e.push_back(ERROR_INSTANCE(es));
01039                                         TRY_nomem(es = "Previously defined at ");
01040                                         TRY_nomem(es += cji->config_path);
01041                                         TRY_nomem(es += "[");
01042                                         TRY_nomem(es += estring(cji->config_line));
01043                                         TRY_nomem(es += "]");
01044                                         e.push_back(ERROR_INSTANCE(es));
01045                                         throw(e);
01046                                 }
01047 
01048                                 if (
01049                                                 (this_path.size() < that_path.size())
01050                                                 && (this_path == that_path.substr(0,this_path.size()))
01051                                                 && (
01052                                                         (that_path[this_path.size()] == '/')
01053                                                         || (this_path.size() == 0)
01054                                                         )
01055                                         )
01056                                 {
01057                                         error e(0);
01058 
01059                                         TRY_nomem(es = "Overlapping archive-path values detected");
01060                                         e.push_back(ERROR_INSTANCE(es));
01061                                         TRY_nomem(es = "Defined archive-path: \"");
01062                                         TRY_nomem(es += this_path);
01063                                         TRY_nomem(es += "\"");
01064                                         e.push_back(ERROR_INSTANCE(es));
01065                                         TRY_nomem(es = "Is in a parent directory of another job's previously defined archive-path");
01066                                         e.push_back(ERROR_INSTANCE(es));
01067                                         TRY_nomem(es = "At ");
01068                                         TRY_nomem(es += cji->config_path);
01069                                         TRY_nomem(es += "[");
01070                                         TRY_nomem(es += estring(cji->config_line));
01071                                         TRY_nomem(es += "]");
01072                                         e.push_back(ERROR_INSTANCE(es));
01073                                         throw(e);
01074                                 }
01075 
01076                                 if (
01077                                                 (this_path.size() > that_path.size())
01078                                                 && (this_path.substr(0,that_path.size()) == that_path)
01079                                                 && (
01080                                                         (this_path[that_path.size()] == '/')
01081                                                         || (that_path.size() == 0)
01082                                                         )
01083                                         )
01084                                 {
01085                                         error e(0);
01086 
01087                                         TRY_nomem(es = "Overlapping archive-path values detected");
01088                                         e.push_back(ERROR_INSTANCE(es));
01089                                         TRY_nomem(es = "Defined archive-path: \"");
01090                                         TRY_nomem(es += this_path);
01091                                         TRY_nomem(es += "\"");
01092                                         e.push_back(ERROR_INSTANCE(es));
01093                                         TRY_nomem(es = "Is in a subdirectory of another job's previously defined archive-path");
01094                                         e.push_back(ERROR_INSTANCE(es));
01095                                         TRY_nomem(es = "At ");
01096                                         TRY_nomem(es += cji->config_path);
01097                                         TRY_nomem(es += "[");
01098                                         TRY_nomem(es += estring(cji->config_line));
01099                                         TRY_nomem(es += "]");
01100                                         e.push_back(ERROR_INSTANCE(es));
01101                                         throw(e);
01102                                 }
01103                         }
01104                 }
01105         }
01106 }
01107 
01108 //----------------------------------------------------------------------------
01109 
01110 /** Reset configuration to default settings */
01111 void configuration_manager::clear(void)
01112 {
01113         m_initialized = false;
01114         m_configs_read = 0;
01115         m_default = true;
01116         TRY_nomem(m_default_file = CONFIGFILE);
01117         m_action = action_help;
01118         m_timestamp.set();
01119         m_cfgfiles.clear();
01120         m_link_catalog_dir.erase();
01121         TRY_nomem(m_log_dir = LOGDIR);
01122         m_delete_old_log_files = false;
01123         m_delete_old_report_files = false;
01124         m_rsync_local_path.erase();
01125         if (strlen(LOCAL_RSYNC) > 0) {
01126                 TRY_nomem(m_rsync_local_path = LOCAL_RSYNC);
01127         }
01128         m_rsync_parallel = 1;
01129         m_io_poll_interval = 1;
01130         m_vaults.clear();
01131         m_vault_overflow_behavior = overflow_quit;
01132         m_vault_overflow_blocks = 10;
01133         m_vault_overflow_inodes = 10;
01134         m_vault_selection_behavior = selection_round_robin;
01135         m_vault_locking = true;
01136         m_default_job.clear();
01137         m_logging_level = logging_child;
01138         m_error_logging_level = logging_rsync;
01139         m_jobs.clear();
01140 }
01141 
01142 /** C'tor */
01143 configuration_manager::configuration_manager()
01144 {
01145         if (this != &config)
01146                 throw(
01147                         INTERNAL_ERROR(0,"Attempt to allocate multiple configuration managers")
01148                         );
01149         clear();
01150 }
01151 
01152 /** Initialize the configuration manager from rvm's command line options */
01153 void configuration_manager::init(int argc, char *argv[])
01154 {
01155         int c;
01156         estring opt;
01157         estring arg;
01158         std::string es;
01159         std::string tes;
01160         cfgfiles_type::const_iterator cfi;
01161         bool use_custom_timestamp = false;
01162         class timestamp custom_timestamp;
01163 
01164         for (c = 1; c < argc; c++) {
01165                 TRY_nomem(opt = argv[c]);
01166                 if (c+1 == argc) {
01167                         TRY_nomem(arg = "");
01168                 }
01169                 else {
01170                         TRY_nomem(arg = argv[c+1]);
01171                 }
01172 
01173                 if (opt == "--archive") {
01174                         m_action = action_archive;
01175                 }
01176                 else if (opt == "--relink") {
01177                         m_action = action_relink;
01178                 }
01179                 else if (opt == "--help") {
01180                         m_action = action_help;
01181                 }
01182                 else if (opt == "--version") {
01183                         m_action = action_version;
01184                 }
01185                 else if (opt == "--check-config") {
01186                         m_action = action_check_config;
01187                 }
01188                 else if (opt == "--no-default-config") {
01189                         m_default = false;
01190                 }
01191                 else if (opt == "--config") {
01192                         directory dir;
01193                         directory::const_iterator cdi;
01194 
01195                         TRY_nomem(es = "Error finding configuration file(s) ");
01196                         TRY_nomem(es += "matching command line argument [");
01197                         TRY_nomem(es += estring(c+1));
01198                         TRY_nomem(es += "]: \"");
01199                         TRY_nomem(es += arg);
01200                         TRY_nomem(es += "\"");
01201 
01202                         try {
01203                                 dir.path(arg);
01204                         }
01205                         catch(error e) {
01206                                 e.push_back(ERROR_INSTANCE(es));
01207                                 throw(e);
01208                         }
01209                         catch(...) {
01210                                 error e = err_unknown;
01211 
01212                                 e.push_back(ERROR_INSTANCE(es));
01213                                 throw(e);
01214                         }
01215                         if (dir.size() == 0) {
01216                                 TRY_nomem(es = "No configuration file(s) found matching ");
01217                                 TRY_nomem(es += "command line argument [");
01218                                 TRY_nomem(es += estring(c+1));
01219                                 TRY_nomem(es += "]: \"");
01220                                 TRY_nomem(es += arg);
01221                                 TRY_nomem(es += "\"");
01222 
01223                                 throw(ERROR(0,es));
01224                         }
01225                         for (cdi = dir.begin(); cdi != dir.end(); cdi++) {
01226                                 TRY_nomem(m_cfgfiles.push_back(cfgfile_element(config_file, arg)));
01227                         }
01228 
01229                         c++;
01230                 }
01231                 else if (opt == "--job") {
01232                         directory dir;
01233                         directory::const_iterator cdi;
01234 
01235                         TRY_nomem(es = "Error finding job file(s) ");
01236                         TRY_nomem(es += "matching command line argument [");
01237                         TRY_nomem(es += estring(c+1));
01238                         TRY_nomem(es += "]: \"");
01239                         TRY_nomem(es += arg);
01240                         TRY_nomem(es += "\"");
01241 
01242                         try {
01243                                 dir.path(arg);
01244                         }
01245                         catch(error e) {
01246                                 e.push_back(ERROR_INSTANCE(es));
01247                                 throw(e);
01248                         }
01249                         catch(...) {
01250                                 error e = err_unknown;
01251                                 throw(e);
01252                         }
01253                         if (dir.size() == 0) {
01254                                 TRY_nomem(es = "No job file(s) found matching ");
01255                                 TRY_nomem(es += "command line argument [");
01256                                 TRY_nomem(es += estring(c+1));
01257                                 TRY_nomem(es += "]: \"");
01258                                 TRY_nomem(es += arg);
01259                                 TRY_nomem(es += "\"");
01260 
01261                                 throw(ERROR(0,es));
01262                         }
01263                         for (cdi = dir.begin(); cdi != dir.end(); cdi++) {
01264                                 TRY_nomem(m_cfgfiles.push_back(cfgfile_element(job_file, arg)));
01265                         }
01266 
01267                         c++;
01268                 }
01269                 else if (opt == "--timestamp") {
01270                         TRY_nomem(es = "From command line argument ");
01271                         TRY_nomem(es += estring(c+1));
01272                         TRY(custom_timestamp.assign(arg),es);
01273                         use_custom_timestamp = true;
01274                         c++;
01275                         TRY_nomem(tes = es);
01276                 }
01277                 else {
01278                         TRY_nomem(es = "Unknown command line option: \"");
01279                         TRY_nomem(es += opt);
01280                         TRY_nomem(es += "\"");
01281                         throw(ERROR(0,es));
01282                 }
01283         }
01284 
01285         m_initialized = true;
01286 
01287         if ((m_action == action_help) || (m_action == action_version))
01288                 return;
01289         
01290         if (use_default())
01291                 read_config(m_default_file);
01292 
01293         for (cfi = m_cfgfiles.begin(); cfi != m_cfgfiles.end(); cfi++) {
01294                 if (cfi->first == config_file) {
01295                         read_config(cfi->second);
01296                 }
01297                 else {
01298                         read_job(cfi->second);
01299                 }
01300         }
01301 
01302         if (m_configs_read == 0) {
01303                 throw(ERROR(0,"No configuration file(s) read"));
01304         }
01305 
01306         if (use_custom_timestamp) {
01307                 TRY(m_timestamp = custom_timestamp,tes);
01308         }
01309 
01310         check();
01311 }
01312 
01313 /** Perform sanity checks on configuration settings */
01314 void configuration_manager::check(void) const
01315 {
01316         std::string es;
01317         subdirectory subdir;
01318         filestatus fstat;
01319 
01320         if (!initialized())
01321                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01322 
01323         // log-dir -- If no log-dir is set then we use a default.  What if that
01324         // default doesn't exist?
01325         if (m_log_dir.size() == 0) {
01326                 throw(ERROR(0,"log-dir not set"));
01327         }
01328         TRY_nomem(es = "Invalid log-dir value: \"");
01329         TRY_nomem(es += m_log_dir);
01330         TRY_nomem(es += "\"");
01331         TRY_instead(subdir.path(m_log_dir,"*"),es);
01332 
01333         // rsync-local-path -- If (a) rsync-local-path is not set from config, and
01334         // (b) a default was determined at compile time, then (c) does the default
01335         // exist?
01336         TRY_nomem(es = "Invalid rsync-local-path value: \"");
01337         TRY_nomem(es += m_rsync_local_path);
01338         TRY_nomem(es += "\"");
01339         TRY(fstat.path(m_rsync_local_path),es);
01340 
01341         // vault -- Are there any?
01342         if (m_vaults.size() == 0) {
01343                 throw(ERROR(0,"No vaults defined"));
01344         }
01345 
01346         // Do all jobs generate a valid job ID?
01347         // Note: This is purely cosmetic, generated job ID strings are only used in
01348         // status reports and report logs.
01349         if (jobs().size() > 0) {
01350                 jobs_type::const_iterator cji;
01351 
01352                 for (cji = jobs().begin(); cji != jobs().end(); cji++) {
01353                         if (cji->generate_job_id().size() == 0) {
01354                                 error e(0);
01355 
01356                                 TRY_nomem(es = "Empty ID generated by job at ");
01357                                 TRY_nomem(es += cji->config_path);
01358                                 TRY_nomem(es += "[");
01359                                 TRY_nomem(es += estring(cji->config_line));
01360                                 TRY_nomem(es += "]");
01361                                 e.push_back(es);
01362                                 TRY_nomem(es =
01363                                         "Use 'jobname' to assign a descriptive name to this job");
01364                                 e.push_back(es);
01365                                 throw(e);
01366                         }
01367                 }
01368         }
01369 }
01370 
01371 /** Return the initialized state of the configuration manager */
01372 const bool configuration_manager::initialized(void) const
01373 {
01374         return(m_initialized);
01375 }
01376 
01377 /** Return the action rvm is to take */
01378 const configuration_manager::action_type 
01379         configuration_manager::action(void) const
01380 {
01381         if (!initialized())
01382                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01383 
01384         return(m_action);
01385 }
01386 
01387 /** Return whether or not rvm is to try to read it's default configuration file */
01388 const bool configuration_manager::use_default(void) const
01389 {
01390         if (!initialized())
01391                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01392 
01393         return(m_default);
01394 }
01395 
01396 /** Set the default configuration filename */
01397 void configuration_manager::default_file(const std::string& a_path)
01398 {
01399         TRY_nomem(m_default_file = a_path);
01400 }
01401 
01402 /** Return the default configuration filename */
01403 const std::string& configuration_manager::default_file(void) const
01404 {
01405         if (!initialized())
01406                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01407 
01408         return(m_default_file);
01409 }
01410 
01411 /** Return the default log-dir */
01412 void configuration_manager::default_logdir(const std::string& a_path)
01413 {
01414         TRY_nomem(m_log_dir = a_path);
01415 }
01416 
01417 /** Return the timestamp of this instance of rvm */
01418 const class timestamp& configuration_manager::timestamp(void) const
01419 {
01420         if (!initialized())
01421                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01422 
01423         return(m_timestamp);
01424 }
01425 
01426 /** Return the link-catalog-dir path */
01427 const std::string& configuration_manager::link_catalog_dir(void) const
01428 {
01429         if (!initialized())
01430                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01431 
01432         return(m_link_catalog_dir);
01433 }
01434 
01435 /** Return the log-dir path */
01436 const std::string& configuration_manager::log_dir(void) const
01437 {
01438         if (!initialized())
01439                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01440 
01441         return(m_log_dir);
01442 }
01443 
01444 /** Return the value of delete-old-log-files */
01445 const bool configuration_manager::delete_old_log_files(void) const
01446 {
01447         if (!initialized())
01448                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01449 
01450         return(m_delete_old_log_files);
01451 }
01452 
01453 /** Return the value of delete-old-report-files */
01454 const bool configuration_manager::delete_old_report_files(void) const
01455 {
01456         if (!initialized())
01457                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01458 
01459         return(m_delete_old_report_files);
01460 }
01461 
01462 /** Return the rsync-local-path */
01463 const std::string& configuration_manager::rsync_local_path(void) const
01464 {
01465         if (!initialized())
01466                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01467 
01468         return(m_rsync_local_path);
01469 }
01470 
01471 /** Return the rsync-parallel */
01472 const uint16& configuration_manager::rsync_parallel(void) const
01473 {
01474         if (!initialized())
01475                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01476 
01477         return(m_rsync_parallel);
01478 }
01479 
01480 /** Return the number of seconds to sleep between polling for I/O */
01481 const uint16& configuration_manager::io_poll_interval(void) const
01482 {
01483         if (!initialized())
01484                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01485 
01486         return(m_io_poll_interval);
01487 }
01488 
01489 /** Return the timestamp-resolution */
01490 const timestamp::resolution_type configuration_manager::timestamp_resolution(void) const
01491 {
01492         if (!initialized())
01493                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01494 
01495         return(m_timestamp.resolution());
01496 }
01497 
01498 /** Return the vaults */
01499 const configuration_manager::vaults_type& configuration_manager::vaults(void) const
01500 {
01501         if (!initialized())
01502                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01503 
01504         return(m_vaults);
01505 }
01506 
01507 /** Return the vault-overflow-behavior */
01508 const configuration_manager::overflow_type& configuration_manager::vault_overflow_behavior(void) const
01509 {
01510         if (!initialized())
01511                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01512 
01513         return(m_vault_overflow_behavior);
01514 }
01515 
01516 /** Return the vault-overflow-blocks */
01517 const uint16& configuration_manager::vault_overflow_blocks(void) const
01518 {
01519         if (!initialized())
01520                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01521 
01522         return(m_vault_overflow_blocks);
01523 }
01524 
01525 /** Return the vault-overflow-inodes */
01526 const uint16& configuration_manager::vault_overflow_inodes(void) const
01527 {
01528         if (!initialized())
01529                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01530 
01531         return(m_vault_overflow_inodes);
01532 }
01533 
01534 /** Return the vault-selection-behavior */
01535 const configuration_manager::selection_type& configuration_manager::vault_selection_behavior(void) const
01536 {
01537         if (!initialized())
01538                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01539 
01540         return(m_vault_selection_behavior);
01541 }
01542 
01543 /** Return the vault-locking selection */
01544 const bool configuration_manager::vault_locking(void) const
01545 {
01546         if (!initialized())
01547                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01548 
01549         return(m_vault_locking);
01550 }
01551 
01552 /** Return the default job configuration */
01553 const job& configuration_manager::default_job(void) const
01554 {
01555         if (!initialized())
01556                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01557 
01558         return(m_default_job);
01559 }
01560 
01561 /** Return a list of jobs */
01562 const configuration_manager::jobs_type& configuration_manager::jobs(void) const
01563 {
01564         if (!initialized())
01565                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01566 
01567         return(m_jobs);
01568 }
01569 
01570 /** Return the logging-level */
01571 const configuration_manager::logging_type& configuration_manager::logging_level(void) const
01572 {
01573         if (!initialized())
01574                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01575 
01576         return(m_logging_level);
01577 }
01578 
01579 /** Return the error-logging-level */
01580 const configuration_manager::logging_type& configuration_manager::error_logging_level(void) const
01581 {
01582         if (!initialized())
01583                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01584 
01585         return(m_error_logging_level);
01586 }
01587 
01588 /** Read a configuration file */
01589 void configuration_manager::read_config(const std::string& a_path)
01590 {
01591         std::string es;
01592         std::ifstream in;
01593         uint16 line = 0;
01594 
01595         in.open(a_path.c_str());
01596         if (!in.is_open()) {
01597                 TRY_nomem(es = "Could not open configuration file: \"");
01598                 TRY_nomem(es += a_path);
01599                 TRY_nomem(es += "\"");
01600                 throw(ERROR(errno,es));
01601         }
01602 
01603         global_parser(a_path, line, in);
01604 
01605         in.close();
01606         m_configs_read++;
01607 }
01608 
01609 /** Read a job configuration file */
01610 void configuration_manager::read_job(const std::string& a_path)
01611 {
01612         std::string es;
01613         std::ifstream in;
01614         job njob;
01615         uint16 line = 0;
01616 
01617         in.open(a_path.c_str());
01618         if (!in.is_open()) {
01619                 TRY_nomem(es = "Could not open job file: \"");
01620                 TRY_nomem(es += a_path);
01621                 TRY_nomem(es += "\"");
01622                 throw(ERROR(errno,es));
01623         }
01624 
01625         njob = m_default_job;
01626 
01627         job_parser(&njob, a_path, line, in, "", false);
01628 
01629         njob.check();
01630 
01631         in.close();
01632 }
01633 
01634 //----------------------------------------------------------------------------
01635 
01636 /** Parse a keyword/value pair read from a configuration file */
01637 void parse_line(
01638         std::istream& a_in,
01639         std::string& a_keyword,
01640         std::string& a_value
01641         )
01642 {
01643         std::string es;
01644         char ch;
01645 
01646         a_keyword.erase();
01647         a_value.erase();
01648 
01649         while (true) {
01650                 a_in.get(ch);
01651                 // Skip whitespace before keyword.
01652                 while ((a_in) && ((ch == ' ') || (ch == '\t'))) {
01653                         a_in.get(ch);
01654                 }
01655                 // Read keyword
01656                 while ((a_in) && ((ch != ' ') && (ch != '\t') && (ch != '\n'))) {
01657                         TRY_nomem(a_keyword += ch);
01658                         a_in.get(ch);
01659                 }
01660                 if (!a_in)
01661                         return;
01662         
01663                 // If keyword is empty then this is a blank line, skip it.
01664                 if (a_keyword.size() == 0)
01665                         return;
01666 
01667                 // If keyword starts with a '#' then this is a comment line, skip it.
01668                 if (a_keyword[0] == '#') {
01669                         // Discard the rest of the line.
01670                         while ((a_in) && (ch != '\n')) {
01671                                 a_in.get(ch);
01672                         }
01673                         return;
01674                 }
01675 
01676                 a_keyword = estring(a_keyword).lower();
01677 
01678                 // If there is not value, return.
01679                 if (ch == '\n')
01680                         return;
01681 
01682                 // Skip whitespace between keyword and value.
01683                 a_in.get(ch);
01684                 while ((a_in) && ((ch == ' ') || (ch == '\t'))) {
01685                         a_in.get(ch);
01686                 }
01687                 if (!a_in)
01688                         return;
01689                 a_in.putback(ch);
01690                 if (!a_in)
01691                         return;
01692 
01693                 // Read value
01694                 a_in.get(ch);
01695                 while ((a_in) && (ch != '\n')) {
01696                         TRY_nomem(a_value += ch);
01697                         a_in.get(ch);
01698                 }
01699                 return;
01700         }
01701 }
01702 
01703 /** Given a path, strip off the basename -- like the dirname UNIX command */
01704 const std::string parse_dirname(const std::string& a_path)
01705 {
01706         std::string rpath;
01707 
01708         TRY_nomem(rpath = a_path);
01709 
01710         if (rpath.find_last_of('/') != std::string::npos)
01711                 rpath.erase(rpath.find_last_of('/'));
01712         
01713         if (rpath.size() == 0) {
01714                 TRY_nomem(rpath = "./");
01715                 return(rpath);
01716         }
01717 
01718         if (rpath[rpath.size()-1] != '/') {
01719                 TRY_nomem(rpath += '/');
01720         }
01721 
01722         return(rpath);
01723 }
01724 
01725 /** Given a path, strip off the directory -- like the basename UNIX commane */
01726 const std::string parse_basename(const std::string& a_path)
01727 {
01728         std::string es;
01729         std::string rpath;
01730 
01731         TRY_nomem(rpath = a_path);
01732 
01733         if (rpath.find_last_of('/') != std::string::npos)
01734                 rpath.erase(0,rpath.find_last_of('/'));
01735 
01736         return(rpath);
01737 }
01738 
01739 //----------------------------------------------------------------------------
01740 
01741 /** C'tor */
01742 global_parser::global_parser(
01743         const std::string& a_path,
01744         uint16& a_line,
01745         std::istream& a_in
01746         )
01747 {
01748         m_in = &a_in;
01749         m_path = &a_path;
01750         m_line = &a_line;
01751 
01752         parse();
01753 }
01754 
01755 /** Generate a string showing the current location within a configuration file
01756  * of the parser */
01757 const std::string global_parser::location(void)
01758 {
01759         std::string es;
01760 
01761         TRY_nomem(es = "At ");
01762         TRY_nomem(es += (*m_path));
01763         TRY_nomem(es += "[");
01764         TRY_nomem(es += estring((*m_line)));
01765         TRY_nomem(es += "]");
01766 
01767         return(es);
01768 }
01769 
01770 /** Read a configuration file, used by the "include" command */
01771 void global_parser::read_config(const std::string& a_path)
01772 {
01773         std::string es;
01774         std::ifstream in;
01775         uint16 line = 0;
01776 
01777         in.open(a_path.c_str());
01778         if (!in.is_open()) {
01779                 TRY_nomem(es = "Could not open configuraiton file: \"");
01780                 TRY_nomem(es += a_path);
01781                 TRY_nomem(es += "\"");
01782                 throw(ERROR(errno,es));
01783         }
01784 
01785         global_parser(a_path, line, in);
01786 
01787         in.close();
01788         config.m_configs_read++;
01789 }
01790 
01791 /** Read a job configuration file, used by the "include-job" command */
01792 void global_parser::read_job(const std::string& a_path, job& a_job)
01793 {
01794         std::string es;
01795         std::ifstream in;
01796         uint16 line = 0;
01797 
01798         in.open(a_path.c_str());
01799         if (!in.is_open()) {
01800                 TRY_nomem(es = "Could not open job file: \"");
01801                 TRY_nomem(es += a_path);
01802                 TRY_nomem(es += "\"");
01803                 throw(ERROR(errno,es));
01804         }
01805 
01806         job_parser(&a_job, a_path, line, in, "", false);
01807 
01808         TRY_nomem(a_job.config_path = *m_path);
01809         TRY_nomem(a_job.config_line = *m_line);
01810         a_job.check();
01811 
01812         in.close();
01813 }
01814 
01815 /** Global context parser */
01816 void global_parser::parse(void)
01817 {
01818         std::string es;
01819         std::string keyword;
01820         std::string value;
01821 
01822         while ((*m_in)) {
01823                 (*m_line)++;
01824                 
01825                 try {
01826                         parse_line((*m_in), keyword, value);
01827                 }
01828                 catch(error e) {
01829                         e.push_back(ERROR_INSTANCE(location()));
01830                         throw(e);
01831                 }
01832                 catch(...) {
01833                         error e = err_unknown;
01834 
01835                         e.push_back(ERROR_INSTANCE(location()));
01836                         throw(e);
01837                 }
01838 
01839                 if (keyword.size() == 0)
01840                         continue;
01841                 if (keyword[0] == '#')
01842                         continue;
01843 
01844                 try {
01845                         if (keyword == "<default>") {
01846                                 parse_default(value);
01847                         }
01848                         else if (keyword == "include") {
01849                                 parse_include(value);
01850                         }
01851                         else if (keyword == "include-job") {
01852                                 parse_include_job(value);
01853                         }
01854                         else if (keyword == "<job>") {
01855                                 parse_job(value);
01856                         }
01857                         else if (keyword == "link-catalog-dir") {
01858                                 parse_link_catalog_dir(value);
01859                         }
01860                         else if (keyword == "log-dir") {
01861                                 parse_log_dir(value);
01862                         }
01863                         else if (keyword == "delete-old-log-files") {
01864                                 parse_delete_old_log_files(value);
01865                         }
01866                         else if (keyword == "delete-old-report-files") {
01867                                 parse_delete_old_report_files(value);
01868                         }
01869                         else if (keyword == "logging-level") {
01870                                 parse_logging_level(value);
01871                         }
01872                         else if (keyword == "error-logging-level") {
01873                                 parse_error_logging_level(value);
01874                         }
01875                         else if (keyword == "rsync-local-path") {
01876                                 parse_rsync_local_path(value);
01877                         }
01878                         else if (keyword == "rsync-parallel") {
01879                                 parse_rsync_parallel(value);
01880                         }
01881                         else if (keyword == "io-poll-interval") {
01882                                 parse_io_poll_interval(value);
01883                         }
01884                         else if (keyword == "timestamp-resolution") {
01885                                 parse_timestamp_resolution(value);
01886                         }
01887                         else if (keyword == "vault") {
01888                                 try {
01889                                         parse_vault(value);
01890                                 }
01891                                 catch(error e) {
01892                                         std::cerr << e;
01893                                 }
01894                                 catch(...) {
01895                                         throw(err_unknown);
01896                                 }
01897                         }
01898                         else if (keyword == "vault-overflow-behavior") {
01899                                 parse_vault_overflow_behavior(value);
01900                         }
01901                         else if (keyword == "vault-overflow-blocks") {
01902                                 parse_vault_overflow_blocks(value);
01903                         }
01904                         else if (keyword == "vault-overflow-inodes") {
01905                                 parse_vault_overflow_inodes(value);
01906                         }
01907                         else if (keyword == "vault-selection-behavior") {
01908                                 parse_vault_selection_behavior(value);
01909                         }
01910                         else if (keyword == "vault-locking") {
01911                                 parse_vault_locking(value);
01912                         }
01913                         else {
01914                                 error e(0);
01915 
01916                                 TRY_nomem(es = "Unknown command in global context: \"");
01917                                 TRY_nomem(es += keyword);
01918                                 TRY_nomem(es += "\"");
01919                                 throw(ERROR(0,es));
01920                         }
01921                 }
01922                 catch(error e) {
01923                         e.push_back(ERROR_INSTANCE(location()));
01924                         throw(e);
01925                 }
01926                 catch(...) {
01927                         error e = err_unknown;
01928 
01929                         e.push_back(ERROR_INSTANCE(location()));
01930                         throw(e);
01931                 }
01932         }
01933 }
01934 
01935 /** Parse a default job context */
01936 void global_parser::parse_default(const std::string& a_value)
01937 {
01938         std::string delimiter;
01939         std::string default_config_path;
01940         uint16 default_config_line;
01941         job* jobPtr = &config.m_default_job;
01942 
01943         config.m_default_job.clear();
01944 
01945         TRY_nomem(default_config_path = *m_path);
01946         TRY_nomem(default_config_line = *m_line);
01947         TRY_nomem(delimiter = "</default>");
01948 
01949         job_parser(jobPtr, *m_path, *m_line, *m_in, delimiter, true);
01950 
01951         TRY_nomem(jobPtr->default_config_path = default_config_path);
01952         jobPtr->default_config_line = default_config_line;
01953 }
01954 
01955 /** Parse an "include" command */
01956 void global_parser::parse_include(const std::string& a_value)
01957 {
01958         std::string es;
01959         directory dir;
01960         directory::const_iterator cdi;
01961         std::string rpath;
01962         std::string ipath;
01963 
01964         if (a_value.size() == 0) {
01965                 TRY_nomem(es = "Invalid include path: \"");
01966                 TRY_nomem(es += a_value);
01967                 TRY_nomem(es += "\"");
01968                 throw(ERROR(0,es));
01969         }
01970 
01971         if (a_value[0] != '/') {
01972                 TRY_nomem(rpath = parse_dirname(*m_path));
01973         }
01974 
01975         TRY_nomem(ipath = rpath + a_value);
01976 
01977         TRY_nomem(es = "No configuration file(s) found: \"");
01978         TRY_nomem(es += a_value);
01979         TRY_nomem(es += "\"");
01980         TRY_instead(dir.path(ipath),es);
01981         if (dir.size() == 0)
01982                 throw(ERROR(0,es));
01983         
01984         for (cdi = dir.begin(); cdi != dir.end(); cdi++) {
01985                 if (dir.size() > 1) {
01986                         TRY_nomem(es = "For files found matching: \"");
01987                         TRY_nomem(es += a_value);
01988                         TRY_nomem(es += "\"");
01989                         try {
01990                                 read_config(*cdi);
01991                         }
01992                         catch(error e) {
01993                                 e.push_back(ERROR_INSTANCE(es));
01994                                 throw(e);
01995                         }
01996                         catch(...) {
01997                                 error e = err_unknown;
01998                 
01999                                 e.push_back(ERROR_INSTANCE(es));
02000                                 throw(e);
02001                         }
02002                 }
02003                 else
02004                         read_config(*cdi);
02005         }
02006 }
02007 
02008 /** Parse an "include-job" command */
02009 void global_parser::parse_include_job(const std::string& a_value)
02010 {
02011         std::string es;
02012         directory dir;
02013         directory::const_iterator cdi;
02014         std::string rpath;
02015         std::string ipath;
02016 
02017         if (a_value.size() == 0) {
02018                 TRY_nomem(es = "Invalid include-job path: \"");
02019                 TRY_nomem(es += a_value);
02020                 TRY_nomem(es += "\"");
02021                 throw(ERROR(0,es));
02022         }
02023 
02024         if (a_value[0] != '/') {
02025                 TRY_nomem(rpath = parse_dirname(*m_path));
02026         }
02027 
02028         TRY_nomem(ipath = rpath + a_value);
02029 
02030         TRY_nomem(es = "No job file(s) found: \"");
02031         TRY_nomem(es += a_value);
02032         TRY_nomem(es += "\"");
02033         TRY(dir.path(ipath),es);
02034         if (dir.size() == 0)
02035                 throw(ERROR(0,es));
02036 
02037         for (cdi = dir.begin(); cdi != dir.end(); cdi++) {
02038                 job new_job;
02039                 
02040                 new_job = config.m_default_job;
02041                 
02042                 if (dir.size() > 1) {
02043                         TRY_nomem(es = "For files found matching: \"");
02044                         TRY_nomem(es += a_value);
02045                         TRY_nomem(es += "\"");
02046                         try {
02047                                 read_job(*cdi, new_job);
02048                         }
02049                         catch(error e) {
02050                                 e.push_back(ERROR_INSTANCE(es));
02051                                 throw(e);
02052                         }
02053                         catch(...) {
02054                                 error e = err_unknown;
02055 
02056                                 e.push_back(ERROR_INSTANCE(es));
02057                                 throw(e);
02058                         }
02059                 }
02060                 else
02061                         read_job(*cdi, new_job);
02062                 TRY_nomem(config.m_jobs.push_back(new_job));
02063         }
02064 }
02065 
02066 /** Parse a job context */
02067 void global_parser::parse_job(const std::string& a_value)
02068 {
02069         std::string delimiter;
02070         std::string config_path;
02071         uint16 config_line;
02072         job new_job;
02073         
02074         TRY_nomem(config_path = *m_path);
02075         config_line = *m_line;
02076         new_job = config.m_default_job;
02077 
02078         TRY_nomem(new_job.config_path = config_path);
02079         new_job.config_line = config_line;
02080         TRY_nomem(delimiter = "</job>");
02081 
02082         job_parser(&new_job, *m_path, *m_line, *m_in, delimiter, false);
02083 
02084         new_job.check();
02085 
02086         TRY_nomem(config.m_jobs.push_back(new_job));
02087 }
02088 
02089 /** Parse a "link-catalog-dir" command */
02090 void global_parser::parse_link_catalog_dir(const std::string& a_value)
02091 {
02092         std::string es;
02093         subdirectory subdir;
02094         
02095         TRY_nomem(es = "Invalid link-catalog-dir path: \"");
02096         TRY_nomem(es += a_value);
02097         TRY_nomem(es += "\"");
02098         TRY_instead(subdir.path(a_value,"*"),es);
02099         TRY_nomem(config.m_link_catalog_dir = a_value);
02100 }
02101 
02102 /** Parse a "log-dir" command */
02103 void global_parser::parse_log_dir(const std::string& a_value)
02104 {
02105         std::string es;
02106         subdirectory subdir;
02107 
02108         TRY_nomem(es = "Invalid log-dir path: \"");
02109         TRY_nomem(es += a_value);
02110         TRY_nomem(es += "\"");
02111         TRY_instead(subdir.path(a_value,"*"),es);
02112         TRY_nomem(config.m_log_dir = a_value);
02113 }
02114 
02115 /** Parse a "delete-old-log-files" command */
02116 void global_parser::parse_delete_old_log_files(const std::string& a_value)
02117 {
02118         std::string es;
02119         estring str;
02120 
02121         TRY_nomem(es = "Invalid delete-old-log-files value: \"");
02122         TRY_nomem(es += a_value);
02123         TRY_nomem(es += "\"");
02124         TRY(str = estring(a_value).lower(),es);
02125         if (
02126                    (str == "y")
02127                 || (str == "yes")
02128                 || (str == "t")
02129                 || (str == "true")
02130                 || (str == "1")
02131                 || (str == "on")
02132                 ) {
02133                 config.m_delete_old_log_files = true;
02134         }
02135         else if (
02136                    (str == "n")
02137                 || (str == "no")
02138                 || (str == "f")
02139                 || (str == "false")
02140                 || (str == "0")
02141                 || (str == "off")
02142                 ) {
02143                 config.m_delete_old_log_files = false;
02144         }
02145         else {
02146                 throw(ERROR(0,es));
02147         }
02148 }
02149 
02150 /** Parse a "delete-old-report-files" command */
02151 void global_parser::parse_delete_old_report_files(const std::string& a_value)
02152 {
02153         std::string es;
02154         estring str;
02155 
02156         TRY_nomem(es = "Invalid delete-old-report-files value: \"");
02157         TRY_nomem(es += a_value);
02158         TRY_nomem(es += "\"");
02159         TRY(str = estring(a_value).lower(),es);
02160         if (
02161                    (str == "y")
02162                 || (str == "yes")
02163                 || (str == "t")
02164                 || (str == "true")
02165                 || (str == "1")
02166                 || (str == "on")
02167                 ) {
02168                 config.m_delete_old_report_files = true;
02169         }
02170         else if (
02171                    (str == "n")
02172                 || (str == "no")
02173                 || (str == "f")
02174                 || (str == "false")
02175                 || (str == "0")
02176                 || (str == "off")
02177                 ) {
02178                 config.m_delete_old_report_files = false;
02179         }
02180         else {
02181                 throw(ERROR(0,es));
02182         }
02183 }
02184 
02185 /** Parse a "loging-level" command */
02186 void global_parser::parse_logging_level(const std::string& a_value)
02187 {
02188         std::string es;
02189         estring str;
02190 
02191         TRY_nomem(es = "Invalid logging-level value: \"");
02192         TRY_nomem(es += a_value);
02193         TRY_nomem(es += "\"");
02194         TRY_nomem(str = estring(a_value).lower());
02195         if (str == "manager") {
02196                 config.m_logging_level = configuration_manager::logging_manager;
02197         }
02198         else if (str == "child") {
02199                 config.m_logging_level = configuration_manager::logging_child;
02200         }
02201         else if (str == "rsync") {
02202                 config.m_logging_level = configuration_manager::logging_rsync;
02203         }
02204         else {
02205                 throw(ERROR(0,es));
02206         }
02207 }
02208 
02209 /** Parse a "error-loging-level" command */
02210 void global_parser::parse_error_logging_level(const std::string& a_value)
02211 {
02212         std::string es;
02213         estring str;
02214 
02215         TRY_nomem(es = "Invalid error-logging-level value: \"");
02216         TRY_nomem(es += a_value);
02217         TRY_nomem(es += "\"");
02218         TRY_nomem(str = estring(a_value).lower());
02219         if (str == "manager") {
02220                 config.m_error_logging_level = configuration_manager::logging_manager;
02221         }
02222         else if (str == "child") {
02223                 config.m_error_logging_level = configuration_manager::logging_child;
02224         }
02225         else if (str == "rsync") {
02226                 config.m_error_logging_level = configuration_manager::logging_rsync;
02227         }
02228         else {
02229                 throw(ERROR(0,es));
02230         }
02231 }
02232 
02233 /** Parse an "rsync-local-path" command */
02234 void global_parser::parse_rsync_local_path(const std::string& a_value)
02235 {
02236         std::string es;
02237         filestatus fstat;
02238 
02239         TRY_nomem(es = "Invalid rsync-local-path value: \"");
02240         TRY_nomem(es += a_value);
02241         TRY_nomem(es += "\"");
02242         TRY_instead(fstat.path(a_value),es);
02243         TRY_nomem(config.m_rsync_local_path = a_value);
02244 }
02245 
02246 /** Parse an "rsync-parallel" command */
02247 void global_parser::parse_rsync_parallel(const std::string& a_value)
02248 {
02249         std::string es;
02250         uint16 num;
02251 
02252         TRY_nomem(es = "Invalid rsync-parallel value: \"");
02253         TRY_nomem(es += a_value);
02254         TRY_nomem(es += "\"");
02255         TRY_instead(num = estring(a_value),es);
02256         if (num == 0)
02257                 throw(ERROR(0,es));
02258         config.m_rsync_parallel = num;
02259 }
02260 
02261 /** Parse "io-poll-interval" command */
02262 void global_parser::parse_io_poll_interval(const std::string& a_value)
02263 {
02264         std::string es;
02265         uint16 num;
02266 
02267         TRY_nomem(es = "Invalid io-poll-interval value: \"");
02268         TRY_nomem(es += a_value);
02269         TRY_nomem(es += "\"");
02270         TRY_instead(num = estring(a_value),es);
02271         if (num == 0)
02272                 throw(ERROR(0,es));
02273         config.m_io_poll_interval = num;
02274 }
02275 
02276 /** Parse a "timestamp-resolution" command */
02277 void global_parser::parse_timestamp_resolution(const std::string& a_value)
02278 {
02279         std::string es;
02280         estring str;
02281 
02282         TRY_nomem(es = "Invalid timestamp-resolution: \"");
02283         TRY_nomem(es += a_value);
02284         TRY_nomem(es += "\"");
02285         TRY(str = estring(a_value).lower(),es);
02286         if (str == "year") {
02287                 config.m_timestamp.resolution(timestamp::resolution_year);
02288         }
02289         else if (str == "month") {
02290                 config.m_timestamp.resolution(timestamp::resolution_month);
02291         }
02292         else if (str == "day") {
02293                 config.m_timestamp.resolution(timestamp::resolution_day);
02294         }
02295         else if (str == "hour") {
02296                 config.m_timestamp.resolution(timestamp::resolution_hour);
02297         }
02298         else if (str == "minute") {
02299                 config.m_timestamp.resolution(timestamp::resolution_minute);
02300         }
02301         else if (str == "second") {
02302                 config.m_timestamp.resolution(timestamp::resolution_second);
02303         }
02304         else {
02305                 throw(ERROR(0,es));
02306         }
02307 }
02308 
02309 /** Parse a "vault" command */
02310 void global_parser::parse_vault(const std::string& a_value)
02311 {
02312         std::string es;
02313         directory dir;
02314         directory::const_iterator cdi;
02315         subdirectory subdir;
02316         filestatus fstat;
02317         error partial_vault_error = ERROR(0,"One or more vault paths were found to be invalid:");
02318 
02319         TRY_nomem(es = "Invalid vault path: \"");
02320         TRY_nomem(es += a_value);
02321         TRY_nomem(es += "\"");
02322 
02323         if (a_value.size() == 0)
02324                 throw(ERROR(0,es));
02325 
02326         TRY(dir.path(a_value),es);
02327 
02328         if (dir.size() == 0) {
02329                 TRY_instead(fstat.path(a_value),es);
02330         }
02331 
02332         for (cdi = dir.begin(); cdi != dir.end(); cdi++) {
02333                 if (!is_dir(*cdi)) {
02334                         TRY_nomem(es = get_error_str(ENOTDIR));
02335                         TRY_nomem(es += ": \"");
02336                         TRY_nomem(es += *cdi);
02337                         TRY_nomem(es += "\"");
02338                         partial_vault_error.push_back(es);
02339                         continue;
02340                 }
02341                 if (!readable(*cdi)) {
02342                         TRY_nomem(es = "No read access to path: \"");
02343                         TRY_nomem(es += *cdi);
02344                         TRY_nomem(es += "\"");
02345                         partial_vault_error.push_back(es);
02346                         continue;
02347                 }
02348                 if (!writable(*cdi)) {
02349                         TRY_nomem(es = "No write access to path: \"");
02350                         TRY_nomem(es += *cdi);
02351                         TRY_nomem(es += "\"");
02352                         partial_vault_error.push_back(es);
02353                         continue;
02354                 }
02355                 if (!executable(*cdi)) {
02356                         TRY_nomem(es = "No execution access to path: \"");
02357                         TRY_nomem(es += *cdi);
02358                         TRY_nomem(es += "\"");
02359                         partial_vault_error.push_back(es);
02360                         continue;
02361                 }
02362                 TRY_nomem(config.m_vaults.push_back(*cdi));
02363         }
02364 
02365         if (partial_vault_error.size() > 1) {
02366                 TRY_nomem(es = "For paths found matching: \"");
02367                 TRY_nomem(es += a_value);
02368                 TRY_nomem(es += "\"");
02369                 partial_vault_error.push_back(es);
02370                 throw(partial_vault_error);
02371         }
02372 }
02373 
02374 /** Parse a "vault-overflow-behavior" command */
02375 void global_parser::parse_vault_overflow_behavior(const std::string& a_value)
02376 {
02377         std::string es;
02378         estring str;
02379 
02380         TRY_nomem(es = "Invalid vault-overflow-behavior value: \"");
02381         TRY_nomem(es += a_value);
02382         TRY_nomem(es += "\"");
02383         TRY(str = estring(a_value).lower(),es);
02384         if (str == "quit") {
02385                 config.m_vault_overflow_behavior = configuration_manager::overflow_quit;
02386         }
02387         else if (str == "delete-oldest") {
02388                 config.m_vault_overflow_behavior = configuration_manager::overflow_delete_oldest;
02389         }
02390         else if (str == "delete-until-free") {
02391                 config.m_vault_overflow_behavior = configuration_manager::overflow_delete_until_free;
02392         }
02393         else {
02394                 throw(ERROR(0,es));
02395         }
02396 }
02397 
02398 /** Parse a "vault-overflow-blocks" command */
02399 void global_parser::parse_vault_overflow_blocks(const std::string& a_value)
02400 {
02401         std::string es;
02402         uint16 num;
02403 
02404         TRY_nomem(es = "Invalid vault-overflow-blocks value: \"");
02405         TRY_nomem(es += a_value);
02406         TRY_nomem(es += "\"");
02407         TRY(num = estring(a_value),es);
02408         if (num > 50)
02409                 throw(ERROR(0,es));
02410         config.m_vault_overflow_blocks = num;
02411 }
02412 
02413 /** Parse a "vault-overflow-inodes" command */
02414 void global_parser::parse_vault_overflow_inodes(const std::string& a_value)
02415 {
02416         std::string es;
02417         uint16 num;
02418 
02419         TRY_nomem(es = "Invalid vault-overflow-inodes value: \"");
02420         TRY_nomem(es += a_value);
02421         TRY_nomem(es += "\"");
02422         TRY(num = estring(a_value),es);
02423         if (num > 50)
02424                 throw(ERROR(0,es));
02425         config.m_vault_overflow_inodes = num;
02426 }
02427 
02428 /** Parse a "vault-selection-behavior" command */
02429 void global_parser::parse_vault_selection_behavior(const std::string& a_value)
02430 {
02431         std::string es;
02432         estring str;
02433 
02434         TRY_nomem(es = "Invalid vault-selection-behavior value: \"");
02435         TRY_nomem(es += a_value);
02436         TRY_nomem(es += "\"");
02437         TRY(str = estring(a_value).lower(),es);
02438         if (str == "max-free") {
02439                 config.m_vault_selection_behavior = configuration_manager::selection_max_free;
02440         }
02441         else if (str == "round-robin") {
02442                 config.m_vault_selection_behavior = configuration_manager::selection_round_robin;
02443         }
02444         else {
02445                 throw(ERROR(0,es));
02446         }
02447 }
02448 
02449 /** Parse a "vault-locking" command */
02450 void global_parser::parse_vault_locking(const std::string& a_value)
02451 {
02452         std::string es;
02453         estring str;
02454 
02455         TRY_nomem(es = "Invalid vault-locking value: \"");
02456         TRY_nomem(es += a_value);
02457         TRY_nomem(es += "\"");
02458         TRY(str = estring(a_value).lower(),es);
02459         if (
02460                    (str == "y")
02461                 || (str == "yes")
02462                 || (str == "t")
02463                 || (str == "true")
02464                 || (str == "1")
02465                 || (str == "on")
02466                 ) {
02467                 config.m_vault_locking = true;
02468         }
02469         else if (
02470                    (str == "n")
02471                 || (str == "no")
02472                 || (str == "f")
02473                 || (str == "false")
02474                 || (str == "0")
02475                 || (str == "off")
02476                 ) {
02477                 config.m_vault_locking = false;
02478         }
02479         else {
02480                 throw(ERROR(0,es));
02481         }
02482 }
02483 
02484 //----------------------------------------------------------------------------
02485 
02486 /** C'tor */
02487 job_parser::job_parser(
02488         job * a_job,
02489         const std::string& a_path,
02490         uint16& a_line,
02491         std::istream& a_in,
02492         const std::string& a_block_delimiter,
02493         const bool a_default_context = false
02494         )
02495 {
02496         m_job = a_job;
02497         m_in = &a_in;
02498         m_path = &a_path;
02499         m_line = &a_line;
02500         m_delimiter = &a_block_delimiter;
02501         m_default_context = a_default_context;
02502 
02503         parse();
02504 }
02505 
02506 /** Construct a string with the current location of the parser in a
02507  * configuration file */
02508 const std::string job_parser::location(void)
02509 {
02510         std::string es;
02511 
02512         TRY_nomem(es = "At ");
02513         TRY_nomem(es += (*m_path));
02514         TRY_nomem(es += "[");
02515         TRY_nomem(es += estring((*m_line)));
02516         TRY_nomem(es += "]");
02517 
02518         return(es);
02519 }
02520 
02521 /** Read a job configuration file, used by the "include" command */
02522 void job_parser::read_job(const std::string& a_path)
02523 {
02524         std::string es;
02525         std::ifstream in;
02526         uint16 line = 0;
02527 
02528         in.open(a_path.c_str());
02529         if (!in.is_open()) {
02530                 TRY_nomem(es = "Could not open job file: \"");
02531                 TRY_nomem(es += a_path);
02532                 TRY_nomem(es += "\"");
02533                 throw(ERROR(errno,es));
02534         }
02535 
02536         job_parser(m_job, a_path, line, in, "", m_default_context);
02537 
02538         in.close();
02539 }
02540 
02541 /** Job context parser */
02542 void job_parser::parse(void)
02543 {
02544         std::string es;
02545         std::string keyword;
02546         std::string value;
02547 
02548         while ((*m_in)) {
02549                 (*m_line)++;
02550                 
02551                 try {
02552                         parse_line((*m_in), keyword, value);
02553                 }
02554                 catch(error e) {
02555                         e.push_back(ERROR_INSTANCE(location()));
02556                         throw(e);
02557                 }
02558                 catch(...) {
02559                         error e = err_unknown;
02560 
02561                         e.push_back(ERROR_INSTANCE(location()));
02562                         throw(e);
02563                 }
02564 
02565                 if (!(*m_in) && (m_delimiter->size() != 0)) {
02566                         TRY_nomem(es = "Unexpected end of file, expected \"");
02567                         TRY_nomem(es += *m_delimiter);
02568                         TRY_nomem(es += "\" here");
02569                         throw(ERROR(errno,es));
02570                 }
02571 
02572                 if (keyword.size() == 0)
02573                         continue;
02574                 if (keyword[0] == '#')
02575                         continue;
02576 
02577                 try {
02578                         if (keyword == *m_delimiter) {
02579                                 return;
02580                         }
02581                         else if (keyword == "archive-path") {
02582                                 parse_archive_path(value);
02583                         }
02584                         else if (keyword == "clear") {
02585                                 parse_clear(value);
02586                         }
02587                         else if (keyword == "exclude-from") {
02588                                 parse_exclude_from(value);
02589                         }
02590                         else if (keyword == "include-from") {
02591                                 parse_include_from(value);
02592                         }
02593                         else if (keyword == "groupname") {
02594                                 parse_groupname(value);
02595                         }
02596                         else if (keyword == "hostname") {
02597                                 parse_hostname(value);
02598                         }
02599                         else if (keyword == "include") {
02600                                 parse_include(value);
02601                         }
02602                         else if ((keyword == "jobname") && (*m_delimiter == "</job>")) {
02603                                 parse_jobname(value);
02604                         }
02605                         else if (keyword == "path") {
02606                                 parse_path(value);
02607                         }
02608                         else if (keyword == "rsync-behavior") {
02609                                 parse_rsync_behavior(value);
02610                         }
02611                         else if (keyword == "rsync-connection-type") {
02612                                 parse_rsync_connection_type(value);
02613                         }
02614                         else if (keyword == "rsync-hardlink") {
02615                                 parse_rsync_hardlink(value);
02616                         }
02617                         else if (keyword == "rsync-multi-hardlink") {
02618                                 parse_rsync_multi_hardlink(value);
02619                         }
02620                         else if (keyword == "rsync-multi-hardlink-max") {
02621                                 parse_rsync_multi_hardlink_max(value);
02622                         }
02623                         else if (keyword == "rsync-options") {
02624                                 parse_rsync_options(value);
02625                         }
02626                         else if (keyword == "<rsync-options>") {
02627                                 parse_rsync_options_context(value);
02628                         }
02629                         else if (keyword == "rsync-remote-user") {
02630                                 parse_rsync_remote_user(value);
02631                         }
02632                         else if (keyword == "rsync-remote-path") {
02633                                 parse_rsync_remote_path(value);
02634                         }
02635                         else if (keyword == "rsync-remote-port") {
02636                                 parse_rsync_remote_port(value);
02637                         }
02638                         else if (keyword == "rsync-remote-module") {
02639                                 parse_rsync_remote_module(value);
02640                         }
02641                         else if (keyword == "rsync-retry-count") {
02642                                 parse_rsync_retry_count(value);
02643                         }
02644                         else if (keyword == "rsync-retry-delay") {
02645                                 parse_rsync_retry_delay(value);
02646                         }
02647                         else if (keyword == "rsync-timeout") {
02648                                 parse_rsync_timeout(value);
02649                         }
02650                         else {
02651                                 error e(0);
02652 
02653                                 TRY_nomem(es = "Unknown command in ");
02654                                 if (m_default_context) {
02655                                         TRY_nomem(es += "default");
02656                                 }
02657                                 else {
02658                                         TRY_nomem(es += "job");
02659                                 }
02660                                 TRY_nomem(es += " context: \"");
02661                                 TRY_nomem(es += keyword);
02662                                 TRY_nomem(es += "\"");
02663                                 throw(ERROR(0,es));
02664                         }
02665                 }
02666                 catch(error e) {
02667                         if ((*m_delimiter).size() == 0)
02668                                 e.push_back(ERROR_INSTANCE(location()));
02669                         throw(e);
02670                 }
02671                 catch(...) {
02672                         error e = err_unknown;
02673 
02674                         e.push_back(ERROR_INSTANCE(location()));
02675                         throw(e);
02676                 }
02677         }
02678 }
02679 
02680 /** Parse an "archive-path" command */
02681 void job_parser::parse_archive_path(const std::string& a_value)
02682 {
02683         std::string es;
02684 
02685         TRY_nomem(es = "Invalid archive-path value");
02686         TRY((*m_job).archive_path = a_value,es);
02687 }
02688 
02689 /** Parse a "clear" command */
02690 void job_parser::parse_clear(const std::string& a_value)
02691 {
02692         std::string es;
02693         estring str;
02694 
02695         TRY_nomem(es = "Invalid clear value: \"");
02696         TRY_nomem(es += a_value);
02697         TRY_nomem(es += "\"");
02698         TRY(str = estring(a_value).lower(),es);
02699         if (str == "archive-path") {
02700                 m_job->archive_path.clear();
02701         }
02702         else if (str == "exclude-from") {
02703                 m_job->excludes.clear();
02704         }
02705         else if (str == "groupname") {
02706                 m_job->groupname.erase();
02707         }
02708         else if (str == "hostname") {
02709                 m_job->hostname.erase();
02710         }
02711         else if (str == "include-from") {
02712                 m_job->includes.clear();
02713         }
02714         else if ((str == "jobname") && (*m_delimiter == "</job>")) {
02715                 m_job->jobname.erase();
02716         }
02717         else if (str == "paths") {
02718                 m_job->paths.clear();
02719         }
02720         else if (str == "rsync-behavior") {
02721                 m_job->rsync_behavior.clear();
02722         }
02723         else if (str == "rsync-options") {
02724                 m_job->rsync_options.erase();
02725         }
02726         else if (str == "rsync-remote-user") {
02727                 m_job->rsync_remote_user.erase();
02728         }
02729         else if (str == "rsync-remotr-port") {
02730                 m_job->rsync_remote_port = 0;
02731         }
02732         else if (str == "rsync-remote-module") {
02733                 m_job->rsync_remote_module.erase();
02734         }
02735         else if (str == "rsync-remote-path") {
02736                 m_job->rsync_remote_path.erase();
02737         }
02738         else {
02739                 throw(ERROR(0,es));
02740         }
02741 }
02742 
02743 /** Parse an "exclude-from" command */
02744 void job_parser::parse_exclude_from(const std::string& a_value)
02745 {
02746         std::string es;
02747         directory dir;
02748         directory::const_iterator cdi;
02749         std::string rpath;
02750         std::string ipath;
02751 
02752         if (a_value.size() == 0) {
02753                 TRY_nomem(es = "Invalid exclude-from path: \"");
02754                 TRY_nomem(es += a_value);
02755                 TRY_nomem(es += "\"");
02756                 throw(ERROR(0,es));
02757         }
02758 
02759         if (a_value[0] != '/') {
02760                 TRY_nomem(rpath = parse_dirname(*m_path));
02761         }
02762 
02763         TRY_nomem(ipath = rpath + a_value);
02764 
02765         TRY_nomem(es = "No exclude-from file(s) found: \"");
02766         TRY_nomem(es += a_value);
02767         TRY_nomem(es += "\"");
02768         TRY(dir.path(ipath),es);
02769         if (dir.size() == 0)
02770                 throw(ERROR(0,es));
02771         
02772         for (cdi = dir.begin(); cdi != dir.end(); cdi++) {
02773                 TRY_nomem((*m_job).excludes.push_back(*cdi));
02774         }
02775 }
02776 
02777 /** Parse an "include-from" command */
02778 void job_parser::parse_include_from(const std::string& a_value)
02779 {
02780         std::string es;
02781         directory dir;
02782         directory::const_iterator cdi;
02783         std::string rpath;
02784         std::string ipath;
02785 
02786         if (a_value.size() == 0) {
02787                 TRY_nomem(es = "Invalid include-from path: \"");
02788                 TRY_nomem(es += a_value);
02789                 TRY_nomem(es += "\"");
02790                 throw(ERROR(0,es));
02791         }
02792 
02793         if (a_value[0] != '/') {
02794                 TRY_nomem(rpath = parse_dirname(*m_path));
02795         }
02796 
02797         TRY_nomem(ipath = rpath + a_value);
02798 
02799         TRY_nomem(es = "No include-from file(s) found: \"");
02800         TRY_nomem(es += a_value);
02801         TRY_nomem(es += "\"");
02802         TRY(dir.path(ipath),es);
02803         if (dir.size() == 0)
02804                 throw(ERROR(0,es));
02805         
02806         for (cdi = dir.begin(); cdi != dir.end(); cdi++) {
02807                 TRY_nomem((*m_job).includes.push_back(*cdi));
02808         }
02809 }
02810 
02811 /** Parse a "groupname" command */
02812 void job_parser::parse_groupname(const std::string& a_value)
02813 {
02814         TRY_nomem((*m_job).groupname = a_value);
02815 }
02816 
02817 /** Parse a "hostname" command */
02818 void job_parser::parse_hostname(const std::string& a_value)
02819 {
02820         TRY_nomem((*m_job).hostname = a_value);
02821 }
02822 
02823 /** Parse an "include" command */
02824 void job_parser::parse_include(const std::string& a_value)
02825 {
02826         std::string es;
02827         directory dir;
02828         directory::const_iterator cdi;
02829         std::string rpath;
02830         std::string ipath;
02831 
02832         if (a_value.size() == 0) {
02833                 TRY_nomem(es = "Invalid include path: \"");
02834                 TRY_nomem(es += a_value);
02835                 TRY_nomem(es += "\"");
02836                 throw(ERROR(0,es));
02837         }
02838 
02839         if (a_value[0] != '/') {
02840                 TRY_nomem(rpath = parse_dirname(*m_path));
02841         }
02842 
02843         TRY_nomem(ipath = rpath + a_value);
02844 
02845         TRY_nomem(es = "No configuration file(s) found: \"");
02846         TRY_nomem(es += a_value);
02847         TRY_nomem(es += "\"");
02848         TRY_instead(dir.path(ipath),es);
02849         if (dir.size() == 0)
02850                 throw(ERROR(0,es));
02851         
02852         for (cdi = dir.begin(); cdi != dir.end(); cdi++) {
02853                 if (dir.size() > 1) {
02854                         TRY_nomem(es = "For files found matching: \"");
02855                         TRY_nomem(es += a_value);
02856                         TRY_nomem(es += "\"");
02857                         try {
02858                                 read_job(*cdi);
02859                         }
02860                         catch(error e) {
02861                                 e.push_back(ERROR_INSTANCE(es));
02862                                 throw(e);
02863                         }
02864                         catch(...) {
02865                                 error e = err_unknown;
02866 
02867                                 e.push_back(ERROR_INSTANCE(es));
02868                                 throw(e);
02869                         }
02870                 }
02871                 else
02872                         read_job(*cdi);
02873         }
02874 }
02875 
02876 /** Parse a "jobname" command */
02877 void job_parser::parse_jobname(const std::string& a_value)
02878 {
02879         TRY_nomem((*m_job).jobname = a_value);
02880 }
02881 
02882 /** Parse a "path" command */
02883 void job_parser::parse_path(const std::string& a_value)
02884 {
02885         TRY_nomem((*m_job).paths.push_back(a_value));
02886 }
02887 
02888 /** Parse an "rsync-behavior" command */
02889 void job_parser::parse_rsync_behavior(const std::string& a_value)
02890 {
02891         std::string es;
02892         estring str;
02893 
02894         TRY_nomem(es = "Invalid rsync-behavior value: \"");
02895         TRY_nomem(es += a_value);
02896         TRY_nomem(es += "\"");
02897         TRY(str = estring(a_value).lower(),es);
02898         if (str == "clear") {
02899                 (*m_job).rsync_behavior.clear();
02900         }
02901         else if (str == "reset") {
02902                 (*m_job).rsync_behavior.reset();
02903         }
02904         else
02905                 (*m_job).rsync_behavior.assign(a_value);
02906 }
02907 
02908 /** Parse an "rsync-connection-type" command */
02909 void job_parser::parse_rsync_connection_type(const std::string& a_value)
02910 {
02911         std::string es;
02912         estring str;
02913 
02914         TRY_nomem(es = "Invalid rsync-connection-type value: \"");
02915         TRY_nomem(es += a_value);
02916         TRY_nomem(es += "\"");
02917         TRY(str = estring(a_value).lower(),es);
02918         if (str == "local") {
02919                 (*m_job).rsync_connection = job::connection_local;
02920         }
02921         else if (str == "remote") {
02922                 (*m_job).rsync_connection = job::connection_remote;
02923         }
02924         else if (str == "server") {
02925                 (*m_job).rsync_connection = job::connection_server;
02926         }
02927         else {
02928                 throw(ERROR(0,es));
02929         }
02930 }
02931 
02932 /** Parse an "rsync-hardlink" command */
02933 void job_parser::parse_rsync_hardlink(const std::string& a_value)
02934 {
02935         std::string es;
02936         estring str;
02937 
02938         TRY_nomem(es = "Invalid rsync-hardlink value: \"");
02939         TRY_nomem(es += a_value);
02940         TRY_nomem(es += "\"");
02941         TRY(str = estring(a_value).lower(),es);
02942         if (
02943                    (str == "y")
02944                 || (str == "yes")
02945                 || (str == "t")
02946                 || (str == "true")
02947                 || (str == "1")
02948                 || (str == "on")
02949                 ) {
02950                 (*m_job).rsync_hardlink = true;
02951         }
02952         else if (
02953                    (str == "n")
02954                 || (str == "no")
02955                 || (str == "f")
02956                 || (str == "false")
02957                 || (str == "0")
02958                 || (str == "off")
02959                 ) {
02960                 (*m_job).rsync_hardlink = false;
02961         }
02962         else {
02963                 throw(ERROR(0,es));
02964         }
02965 }
02966 
02967 /** Parse an "rsync-multi-hardlink" command */
02968 void job_parser::parse_rsync_multi_hardlink(const std::string& a_value)
02969 {
02970         std::string es;
02971         estring str;
02972 
02973         TRY_nomem(es = "Invalid rsync-multi-hardlink value: \"");
02974         TRY_nomem(es += a_value);
02975         TRY_nomem(es += "\"");
02976         TRY(str = estring(a_value).lower(),es);
02977         if (
02978                    (str == "y")
02979                 || (str == "yes")
02980                 || (str == "t")
02981                 || (str == "true")
02982                 || (str == "1")
02983                 || (str == "on")
02984                 ) {
02985                 (*m_job).rsync_multi_hardlink = true;
02986                 (*m_job).rsync_hardlink = true;
02987         }
02988         else if (
02989                    (str == "n")
02990                 || (str == "no")
02991                 || (str == "f")
02992                 || (str == "false")
02993                 || (str == "0")
02994                 || (str == "off")
02995                 ) {
02996                 (*m_job).rsync_multi_hardlink = false;
02997         }
02998         else {
02999                 throw(ERROR(0,es));
03000         }
03001 }
03002 
03003 /** Parse an "rsync-multi-hardlink-max" command */
03004 void job_parser::parse_rsync_multi_hardlink_max(const std::string& a_value)
03005 {
03006         std::string es;
03007         uint16 num;
03008 
03009         TRY_nomem(es = "Invalid rsync-multi-hardlink-max value: \"");
03010         TRY_nomem(es += a_value);
03011         TRY_nomem(es += "\"");
03012         TRY_instead(num = estring(a_value),es);
03013         if (num == 0)
03014                 throw(ERROR(0,es));
03015         (*m_job).rsync_multi_hardlink_max = num;
03016 }
03017 
03018 /** Parse an "rsync-options" command */
03019 void job_parser::parse_rsync_options(const std::string& a_value)
03020 {
03021         if (*m_delimiter == "</default>") {
03022                 TRY_nomem((*m_job).rsync_options = a_value);
03023         }
03024         else {
03025                 if ((*m_job).rsync_options.size() != 0) {
03026                         TRY_nomem((*m_job).rsync_options += " ");
03027                 }
03028                 TRY_nomem((*m_job).rsync_options += a_value);
03029         }
03030 }
03031 
03032 /** Parse an rsync-options context */
03033 void job_parser::parse_rsync_options_context(const std::string& a_value)
03034 {
03035         std::string es;
03036         std::string value;
03037         std::string rsync_options;
03038         char ch;
03039 
03040         while ((*m_in)) {
03041                 (*m_line)++;
03042 
03043                 value.erase();
03044 
03045                 (*m_in).get(ch);
03046                 while ((ch == ' ') || (ch == '\t'))
03047                         (*m_in).get(ch);
03048                 while (((*m_in)) && (ch != '\n')) {
03049                         TRY_nomem(value += ch);
03050                         (*m_in).get(ch);
03051                 }
03052 
03053                 if ((!(*m_in)) && (value != "</rsync-options>")) {
03054                         TRY_nomem(es = "Unexpected end of file, expected ");
03055                         TRY_nomem(es += "\"</rsync-options>\" here");
03056                         throw(ERROR(errno,es));
03057                 }
03058 
03059                 if (value.size() == 0)
03060                         continue;
03061                 if (value[0] == '#')
03062                         continue;
03063 
03064                 if (value == "</rsync-options>") {
03065                         parse_rsync_options(rsync_options);
03066                         return;
03067                 }
03068 
03069                 if (rsync_options.size() != 0) {
03070                         TRY_nomem(rsync_options += ' ');
03071                 }
03072                 TRY_nomem(rsync_options += value);
03073         }
03074 }
03075 
03076 /** Parse a "remote-user" command */
03077 void job_parser::parse_rsync_remote_user(const std::string& a_value)
03078 {
03079         TRY_nomem((*m_job).rsync_remote_user = a_value);
03080 }
03081 
03082 /** Parse an "rsync-remote-path" command */
03083 void job_parser::parse_rsync_remote_path(const std::string& a_value)
03084 {
03085         TRY_nomem((*m_job).rsync_remote_path = a_value);
03086 }
03087 
03088 /** Parse an "rsync-remote-port" command */
03089 void job_parser::parse_rsync_remote_port(const std::string& a_value)
03090 {
03091         std::string es;
03092         estring str;
03093         uint16 num;
03094 
03095         TRY_nomem(es = "Invalid rsync-remote-port value: \"");
03096         TRY_nomem(es += a_value);
03097         TRY_nomem(es += "\"");
03098         TRY_nomem(str = a_value);
03099         TRY(num = str,es);
03100         (*m_job).rsync_remote_port = num;
03101 }
03102 
03103 /** Parse an "rsync-remote-module" command */
03104 void job_parser::parse_rsync_remote_module(const std::string& a_value)
03105 {
03106         TRY_nomem((*m_job).rsync_remote_module = a_value);
03107 }
03108 
03109 /** Parse an "rsync-retry-count" command */
03110 void job_parser::parse_rsync_retry_count(const std::string& a_value)
03111 {
03112         std::string es;
03113         estring str;
03114         uint16 num;
03115 
03116         TRY_nomem(es = "Invalid rsync-retry-count value: \"");
03117         TRY_nomem(es += a_value);
03118         TRY_nomem(es += "\"");
03119         TRY_nomem(str = a_value);
03120         TRY(num = str,es);
03121         (*m_job).rsync_retry_count = num;
03122 }
03123 
03124 /** Parse an "rsync-retry-delay" command */
03125 void job_parser::parse_rsync_retry_delay(const std::string& a_value)
03126 {
03127         std::string es;
03128         estring str;
03129         uint16 num;
03130 
03131         TRY_nomem(es = "Invalid rsync-retry-delay value: \"");
03132         TRY_nomem(es += a_value);
03133         TRY_nomem(es += "\"");
03134         TRY_nomem(str = a_value);
03135         TRY(num = str,es);
03136         (*m_job).rsync_retry_delay = num;
03137 }
03138 
03139 /** Parse an "rsync-timeout" command */
03140 void job_parser::parse_rsync_timeout(const std::string& a_value)
03141 {
03142         std::string es;
03143         estring str;
03144         uint16 num;
03145 
03146         TRY_nomem(es = "Invalid rsync-timeout value: \"");
03147         TRY_nomem(es += a_value);
03148         TRY_nomem(es += "\"");
03149         TRY_nomem(str = a_value);
03150         TRY(num = str,es);
03151         (*m_job).rsync_timeout = num;
03152 }
03153 
03154 //----------------------------------------------------------------------------
03155 
03156 /** The global configuration manager instance */
03157 configuration_manager config;

Generated on Tue Jul 1 12:09:28 2008 for rvm by  doxygen 1.5.1