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                 argv.push_back(str);
00969         }
00970 
00971         return(argv);
00972 }
00973 
00974 /** Perform sanity checks for the configuration settings of this job */
00975 void job::check(void)
00976 {
00977         std::string es;
00978         std::string this_path;
00979         std::string that_path;
00980         paths_type::const_iterator cpi;
00981         configuration_manager::jobs_type::const_iterator cji;
00982         paths_type::const_iterator cjapi;
00983 
00984         if (
00985                         (
00986                                 (rsync_connection == connection_remote) 
00987                                 || (rsync_connection == connection_server)
00988                         )
00989                         && (hostname.size() == 0)
00990                 )
00991         {
00992                 TRY_nomem(es = "rsync-connection-type references hostname, ");
00993                 TRY_nomem(es += "but hostname is empty");
00994                 throw(ERROR(0,es));
00995         }
00996 
00997         if ((rsync_remote_module.size() != 0) 
00998                 && (rsync_connection != connection_server)) 
00999         {
01000                 TRY_nomem(es = "rsync-remote-module specifies a module, but ");
01001                 TRY_nomem(es = "rsync-connection-type is not server");
01002                 throw(ERROR(0,es));
01003         }
01004 
01005         if (paths.size() == 0) {
01006                 throw(ERROR(0,"No paths defined for this job"));
01007         }
01008 
01009         for (cpi = paths.begin() ; cpi != paths.end(); cpi++) {
01010                 TRY_nomem(this_path = generate_archive_path(*cpi));
01011 
01012                 for (
01013                         cji = config.jobs().begin();
01014                         cji != config.jobs().end();
01015                         cji++
01016                         )
01017                 {
01018                         for (
01019                                 cjapi = cji->paths.begin();
01020                                 cjapi != cji->paths.end();
01021                                 cjapi++
01022                                 )
01023                         {
01024                                 TRY_nomem(that_path = cji->generate_archive_path(*cjapi));
01025 
01026                                 if (this_path == that_path) {
01027                                         error e(0);
01028 
01029                                         TRY_nomem(es = "Duplicate archive-path values detected");
01030                                         e.push_back(ERROR_INSTANCE(es));
01031                                         TRY_nomem(es = "Archive path: \"");
01032                                         TRY_nomem(es += this_path);
01033                                         TRY_nomem(es += "\"");
01034                                         e.push_back(ERROR_INSTANCE(es));
01035                                         TRY_nomem(es = "Previously defined at ");
01036                                         TRY_nomem(es += cji->config_path);
01037                                         TRY_nomem(es += "[");
01038                                         TRY_nomem(es += estring(cji->config_line));
01039                                         TRY_nomem(es += "]");
01040                                         e.push_back(ERROR_INSTANCE(es));
01041                                         throw(e);
01042                                 }
01043 
01044                                 if (
01045                                                 (this_path.size() < that_path.size())
01046                                                 && (this_path == that_path.substr(0,this_path.size()))
01047                                                 && (
01048                                                         (that_path[this_path.size()] == '/')
01049                                                         || (this_path.size() == 0)
01050                                                         )
01051                                         )
01052                                 {
01053                                         error e(0);
01054 
01055                                         TRY_nomem(es = "Overlapping archive-path values detected");
01056                                         e.push_back(ERROR_INSTANCE(es));
01057                                         TRY_nomem(es = "Defined archive-path: \"");
01058                                         TRY_nomem(es += this_path);
01059                                         TRY_nomem(es += "\"");
01060                                         e.push_back(ERROR_INSTANCE(es));
01061                                         TRY_nomem(es = "Is in a parent directory of another job's previously defined archive-path");
01062                                         e.push_back(ERROR_INSTANCE(es));
01063                                         TRY_nomem(es = "At ");
01064                                         TRY_nomem(es += cji->config_path);
01065                                         TRY_nomem(es += "[");
01066                                         TRY_nomem(es += estring(cji->config_line));
01067                                         TRY_nomem(es += "]");
01068                                         e.push_back(ERROR_INSTANCE(es));
01069                                         throw(e);
01070                                 }
01071 
01072                                 if (
01073                                                 (this_path.size() > that_path.size())
01074                                                 && (this_path.substr(0,that_path.size()) == that_path)
01075                                                 && (
01076                                                         (this_path[that_path.size()] == '/')
01077                                                         || (that_path.size() == 0)
01078                                                         )
01079                                         )
01080                                 {
01081                                         error e(0);
01082 
01083                                         TRY_nomem(es = "Overlapping archive-path values detected");
01084                                         e.push_back(ERROR_INSTANCE(es));
01085                                         TRY_nomem(es = "Defined archive-path: \"");
01086                                         TRY_nomem(es += this_path);
01087                                         TRY_nomem(es += "\"");
01088                                         e.push_back(ERROR_INSTANCE(es));
01089                                         TRY_nomem(es = "Is in a subdirectory of another job's previously defined archive-path");
01090                                         e.push_back(ERROR_INSTANCE(es));
01091                                         TRY_nomem(es = "At ");
01092                                         TRY_nomem(es += cji->config_path);
01093                                         TRY_nomem(es += "[");
01094                                         TRY_nomem(es += estring(cji->config_line));
01095                                         TRY_nomem(es += "]");
01096                                         e.push_back(ERROR_INSTANCE(es));
01097                                         throw(e);
01098                                 }
01099                         }
01100                 }
01101         }
01102 }
01103 
01104 //----------------------------------------------------------------------------
01105 
01106 /** Reset configuration to default settings */
01107 void configuration_manager::clear(void)
01108 {
01109         m_initialized = false;
01110         m_configs_read = 0;
01111         m_default = true;
01112         TRY_nomem(m_default_file = CONFIGFILE);
01113         m_action = action_help;
01114         m_timestamp.set();
01115         m_cfgfiles.clear();
01116         m_link_catalog_dir.erase();
01117         TRY_nomem(m_log_dir = LOGDIR);
01118         m_delete_old_log_files = false;
01119         m_delete_old_report_files = false;
01120         m_rsync_local_path.erase();
01121         if (strlen(LOCAL_RSYNC) > 0) {
01122                 TRY_nomem(m_rsync_local_path = LOCAL_RSYNC);
01123         }
01124         m_rsync_parallel = 1;
01125         m_io_poll_interval = 1;
01126         m_vaults.clear();
01127         m_vault_overflow_behavior = overflow_quit;
01128         m_vault_overflow_blocks = 10;
01129         m_vault_overflow_inodes = 10;
01130         m_vault_selection_behavior = selection_round_robin;
01131         m_vault_locking = true;
01132         m_default_job.clear();
01133         m_logging_level = logging_child;
01134         m_error_logging_level = logging_rsync;
01135         m_jobs.clear();
01136 }
01137 
01138 /** C'tor */
01139 configuration_manager::configuration_manager()
01140 {
01141         if (this != &config)
01142                 throw(
01143                         INTERNAL_ERROR(0,"Attempt to allocate multiple configuration managers")
01144                         );
01145         clear();
01146 }
01147 
01148 /** Initialize the configuration manager from rvm's command line options */
01149 void configuration_manager::init(int argc, char *argv[])
01150 {
01151         int c;
01152         estring opt;
01153         estring arg;
01154         std::string es;
01155         std::string tes;
01156         cfgfiles_type::const_iterator cfi;
01157         bool use_custom_timestamp = false;
01158         class timestamp custom_timestamp;
01159 
01160         for (c = 1; c < argc; c++) {
01161                 TRY_nomem(opt = argv[c]);
01162                 if (c+1 == argc) {
01163                         TRY_nomem(arg = "");
01164                 }
01165                 else {
01166                         TRY_nomem(arg = argv[c+1]);
01167                 }
01168 
01169                 if (opt == "--archive") {
01170                         m_action = action_archive;
01171                 }
01172                 else if (opt == "--relink") {
01173                         m_action = action_relink;
01174                 }
01175                 else if (opt == "--help") {
01176                         m_action = action_help;
01177                 }
01178                 else if (opt == "--version") {
01179                         m_action = action_version;
01180                 }
01181                 else if (opt == "--check-config") {
01182                         m_action = action_check_config;
01183                 }
01184                 else if (opt == "--no-default-config") {
01185                         m_default = false;
01186                 }
01187                 else if (opt == "--config") {
01188                         directory dir;
01189                         directory::const_iterator cdi;
01190 
01191                         TRY_nomem(es = "Error finding configuration file(s) ");
01192                         TRY_nomem(es += "matching command line argument [");
01193                         TRY_nomem(es += estring(c+1));
01194                         TRY_nomem(es += "]: \"");
01195                         TRY_nomem(es += arg);
01196                         TRY_nomem(es += "\"");
01197 
01198                         try {
01199                                 dir.path(arg);
01200                         }
01201                         catch(error e) {
01202                                 e.push_back(ERROR_INSTANCE(es));
01203                                 throw(e);
01204                         }
01205                         catch(...) {
01206                                 error e = err_unknown;
01207 
01208                                 e.push_back(ERROR_INSTANCE(es));
01209                                 throw(e);
01210                         }
01211                         if (dir.size() == 0) {
01212                                 TRY_nomem(es = "No configuration file(s) found matching ");
01213                                 TRY_nomem(es += "command line argument [");
01214                                 TRY_nomem(es += estring(c+1));
01215                                 TRY_nomem(es += "]: \"");
01216                                 TRY_nomem(es += arg);
01217                                 TRY_nomem(es += "\"");
01218 
01219                                 throw(ERROR(0,es));
01220                         }
01221                         for (cdi = dir.begin(); cdi != dir.end(); cdi++) {
01222                                 TRY_nomem(m_cfgfiles.push_back(cfgfile_element(config_file, arg)));
01223                         }
01224 
01225                         c++;
01226                 }
01227                 else if (opt == "--job") {
01228                         directory dir;
01229                         directory::const_iterator cdi;
01230 
01231                         TRY_nomem(es = "Error finding job file(s) ");
01232                         TRY_nomem(es += "matching command line argument [");
01233                         TRY_nomem(es += estring(c+1));
01234                         TRY_nomem(es += "]: \"");
01235                         TRY_nomem(es += arg);
01236                         TRY_nomem(es += "\"");
01237 
01238                         try {
01239                                 dir.path(arg);
01240                         }
01241                         catch(error e) {
01242                                 e.push_back(ERROR_INSTANCE(es));
01243                                 throw(e);
01244                         }
01245                         catch(...) {
01246                                 error e = err_unknown;
01247                                 throw(e);
01248                         }
01249                         if (dir.size() == 0) {
01250                                 TRY_nomem(es = "No job file(s) found matching ");
01251                                 TRY_nomem(es += "command line argument [");
01252                                 TRY_nomem(es += estring(c+1));
01253                                 TRY_nomem(es += "]: \"");
01254                                 TRY_nomem(es += arg);
01255                                 TRY_nomem(es += "\"");
01256 
01257                                 throw(ERROR(0,es));
01258                         }
01259                         for (cdi = dir.begin(); cdi != dir.end(); cdi++) {
01260                                 TRY_nomem(m_cfgfiles.push_back(cfgfile_element(job_file, arg)));
01261                         }
01262 
01263                         c++;
01264                 }
01265                 else if (opt == "--timestamp") {
01266                         TRY_nomem(es = "From command line argument ");
01267                         TRY_nomem(es += estring(c+1));
01268                         TRY(custom_timestamp.assign(arg),es);
01269                         use_custom_timestamp = true;
01270                         c++;
01271                         TRY_nomem(tes = es);
01272                 }
01273                 else {
01274                         TRY_nomem(es = "Unknown command line option: \"");
01275                         TRY_nomem(es += opt);
01276                         TRY_nomem(es += "\"");
01277                         throw(ERROR(0,es));
01278                 }
01279         }
01280 
01281         m_initialized = true;
01282 
01283         if ((m_action == action_help) || (m_action == action_version))
01284                 return;
01285         
01286         if (use_default())
01287                 read_config(m_default_file);
01288 
01289         for (cfi = m_cfgfiles.begin(); cfi != m_cfgfiles.end(); cfi++) {
01290                 if (cfi->first == config_file) {
01291                         read_config(cfi->second);
01292                 }
01293                 else {
01294                         read_job(cfi->second);
01295                 }
01296         }
01297 
01298         if (m_configs_read == 0) {
01299                 throw(ERROR(0,"No configuration file(s) read"));
01300         }
01301 
01302         if (use_custom_timestamp) {
01303                 TRY(m_timestamp = custom_timestamp,tes);
01304         }
01305 
01306         check();
01307 }
01308 
01309 /** Perform sanity checks on configuration settings */
01310 void configuration_manager::check(void) const
01311 {
01312         std::string es;
01313         subdirectory subdir;
01314         filestatus fstat;
01315 
01316         if (!initialized())
01317                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01318 
01319         // log-dir -- If no log-dir is set then we use a default.  What if that
01320         // default doesn't exist?
01321         if (m_log_dir.size() == 0) {
01322                 throw(ERROR(0,"log-dir not set"));
01323         }
01324         TRY_nomem(es = "Invalid log-dir value: \"");
01325         TRY_nomem(es += m_log_dir);
01326         TRY_nomem(es += "\"");
01327         TRY_instead(subdir.path(m_log_dir,"*"),es);
01328 
01329         // rsync-local-path -- If (a) rsync-local-path is not set from config, and
01330         // (b) a default was determined at compile time, then (c) does the default
01331         // exist?
01332         TRY_nomem(es = "Invalid rsync-local-path value: \"");
01333         TRY_nomem(es += m_rsync_local_path);
01334         TRY_nomem(es += "\"");
01335         TRY(fstat.path(m_rsync_local_path),es);
01336 
01337         // vault -- Are there any?
01338         if (m_vaults.size() == 0) {
01339                 throw(ERROR(0,"No vaults defined"));
01340         }
01341 
01342         // Do all jobs generate a valid job ID?
01343         // Note: This is purely cosmetic, generated job ID strings are only used in
01344         // status reports and report logs.
01345         if (jobs().size() > 0) {
01346                 jobs_type::const_iterator cji;
01347 
01348                 for (cji = jobs().begin(); cji != jobs().end(); cji++) {
01349                         if (cji->generate_job_id().size() == 0) {
01350                                 error e(0);
01351 
01352                                 TRY_nomem(es = "Empty ID generated by job at ");
01353                                 TRY_nomem(es += cji->config_path);
01354                                 TRY_nomem(es += "[");
01355                                 TRY_nomem(es += estring(cji->config_line));
01356                                 TRY_nomem(es += "]");
01357                                 e.push_back(es);
01358                                 TRY_nomem(es =
01359                                         "Use 'jobname' to assign a descriptive name to this job");
01360                                 e.push_back(es);
01361                                 throw(e);
01362                         }
01363                 }
01364         }
01365 }
01366 
01367 /** Return the initialized state of the configuration manager */
01368 const bool configuration_manager::initialized(void) const
01369 {
01370         return(m_initialized);
01371 }
01372 
01373 /** Return the action rvm is to take */
01374 const configuration_manager::action_type 
01375         configuration_manager::action(void) const
01376 {
01377         if (!initialized())
01378                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01379 
01380         return(m_action);
01381 }
01382 
01383 /** Return whether or not rvm is to try to read it's default configuration file */
01384 const bool configuration_manager::use_default(void) const
01385 {
01386         if (!initialized())
01387                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01388 
01389         return(m_default);
01390 }
01391 
01392 /** Set the default configuration filename */
01393 void configuration_manager::default_file(const std::string& a_path)
01394 {
01395         TRY_nomem(m_default_file = a_path);
01396 }
01397 
01398 /** Return the default configuration filename */
01399 const std::string& configuration_manager::default_file(void) const
01400 {
01401         if (!initialized())
01402                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01403 
01404         return(m_default_file);
01405 }
01406 
01407 /** Return the default log-dir */
01408 void configuration_manager::default_logdir(const std::string& a_path)
01409 {
01410         TRY_nomem(m_log_dir = a_path);
01411 }
01412 
01413 /** Return the timestamp of this instance of rvm */
01414 const class timestamp& configuration_manager::timestamp(void) const
01415 {
01416         if (!initialized())
01417                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01418 
01419         return(m_timestamp);
01420 }
01421 
01422 /** Return the link-catalog-dir path */
01423 const std::string& configuration_manager::link_catalog_dir(void) const
01424 {
01425         if (!initialized())
01426                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01427 
01428         return(m_link_catalog_dir);
01429 }
01430 
01431 /** Return the log-dir path */
01432 const std::string& configuration_manager::log_dir(void) const
01433 {
01434         if (!initialized())
01435                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01436 
01437         return(m_log_dir);
01438 }
01439 
01440 /** Return the value of delete-old-log-files */
01441 const bool configuration_manager::delete_old_log_files(void) const
01442 {
01443         if (!initialized())
01444                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01445 
01446         return(m_delete_old_log_files);
01447 }
01448 
01449 /** Return the value of delete-old-report-files */
01450 const bool configuration_manager::delete_old_report_files(void) const
01451 {
01452         if (!initialized())
01453                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01454 
01455         return(m_delete_old_report_files);
01456 }
01457 
01458 /** Return the rsync-local-path */
01459 const std::string& configuration_manager::rsync_local_path(void) const
01460 {
01461         if (!initialized())
01462                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01463 
01464         return(m_rsync_local_path);
01465 }
01466 
01467 /** Return the rsync-parallel */
01468 const uint16& configuration_manager::rsync_parallel(void) const
01469 {
01470         if (!initialized())
01471                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01472 
01473         return(m_rsync_parallel);
01474 }
01475 
01476 /** Return the number of seconds to sleep between polling for I/O */
01477 const uint16& configuration_manager::io_poll_interval(void) const
01478 {
01479         if (!initialized())
01480                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01481 
01482         return(m_io_poll_interval);
01483 }
01484 
01485 /** Return the timestamp-resolution */
01486 const timestamp::resolution_type configuration_manager::timestamp_resolution(void) const
01487 {
01488         if (!initialized())
01489                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01490 
01491         return(m_timestamp.resolution());
01492 }
01493 
01494 /** Return the vaults */
01495 const configuration_manager::vaults_type& configuration_manager::vaults(void) const
01496 {
01497         if (!initialized())
01498                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01499 
01500         return(m_vaults);
01501 }
01502 
01503 /** Return the vault-overflow-behavior */
01504 const configuration_manager::overflow_type& configuration_manager::vault_overflow_behavior(void) const
01505 {
01506         if (!initialized())
01507                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01508 
01509         return(m_vault_overflow_behavior);
01510 }
01511 
01512 /** Return the vault-overflow-blocks */
01513 const uint16& configuration_manager::vault_overflow_blocks(void) const
01514 {
01515         if (!initialized())
01516                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01517 
01518         return(m_vault_overflow_blocks);
01519 }
01520 
01521 /** Return the vault-overflow-inodes */
01522 const uint16& configuration_manager::vault_overflow_inodes(void) const
01523 {
01524         if (!initialized())
01525                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01526 
01527         return(m_vault_overflow_inodes);
01528 }
01529 
01530 /** Return the vault-selection-behavior */
01531 const configuration_manager::selection_type& configuration_manager::vault_selection_behavior(void) const
01532 {
01533         if (!initialized())
01534                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01535 
01536         return(m_vault_selection_behavior);
01537 }
01538 
01539 /** Return the vault-locking selection */
01540 const bool configuration_manager::vault_locking(void) const
01541 {
01542         if (!initialized())
01543                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01544 
01545         return(m_vault_locking);
01546 }
01547 
01548 /** Return the default job configuration */
01549 const job& configuration_manager::default_job(void) const
01550 {
01551         if (!initialized())
01552                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01553 
01554         return(m_default_job);
01555 }
01556 
01557 /** Return a list of jobs */
01558 const configuration_manager::jobs_type& configuration_manager::jobs(void) const
01559 {
01560         if (!initialized())
01561                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01562 
01563         return(m_jobs);
01564 }
01565 
01566 /** Return the logging-level */
01567 const configuration_manager::logging_type& configuration_manager::logging_level(void) const
01568 {
01569         if (!initialized())
01570                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01571 
01572         return(m_logging_level);
01573 }
01574 
01575 /** Return the error-logging-level */
01576 const configuration_manager::logging_type& configuration_manager::error_logging_level(void) const
01577 {
01578         if (!initialized())
01579                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01580 
01581         return(m_error_logging_level);
01582 }
01583 
01584 /** Read a configuration file */
01585 void configuration_manager::read_config(const std::string& a_path)
01586 {
01587         std::string es;
01588         std::ifstream in;
01589         uint16 line = 0;
01590 
01591         in.open(a_path.c_str());
01592         if (!in.is_open()) {
01593                 TRY_nomem(es = "Could not open configuration file: \"");
01594                 TRY_nomem(es += a_path);
01595                 TRY_nomem(es += "\"");
01596                 throw(ERROR(errno,es));
01597         }
01598 
01599         global_parser(a_path, line, in);
01600 
01601         in.close();
01602         m_configs_read++;
01603 }
01604 
01605 /** Read a job configuration file */
01606 void configuration_manager::read_job(const std::string& a_path)
01607 {
01608         std::string es;
01609         std::ifstream in;
01610         job njob;
01611         uint16 line = 0;
01612 
01613         in.open(a_path.c_str());
01614         if (!in.is_open()) {
01615                 TRY_nomem(es = "Could not open job file: \"");
01616                 TRY_nomem(es += a_path);
01617                 TRY_nomem(es += "\"");
01618                 throw(ERROR(errno,es));
01619         }
01620 
01621         njob = m_default_job;
01622 
01623         job_parser(&njob, a_path, line, in, "", false);
01624 
01625         njob.check();
01626 
01627         in.close();
01628 }
01629 
01630 //----------------------------------------------------------------------------
01631 
01632 /** Parse a keyword/value pair read from a configuration file */
01633 void parse_line(
01634         std::istream& a_in,
01635         std::string& a_keyword,
01636         std::string& a_value
01637         )
01638 {
01639         std::string es;
01640         char ch;
01641 
01642         a_keyword.erase();
01643         a_value.erase();
01644 
01645         while (true) {
01646                 a_in.get(ch);
01647                 // Skip whitespace before keyword.
01648                 while ((a_in) && ((ch == ' ') || (ch == '\t'))) {
01649                         a_in.get(ch);
01650                 }
01651                 // Read keyword
01652                 while ((a_in) && ((ch != ' ') && (ch != '\t') && (ch != '\n'))) {
01653                         TRY_nomem(a_keyword += ch);
01654                         a_in.get(ch);
01655                 }
01656                 if (!a_in)
01657                         return;
01658         
01659                 // If keyword is empty then this is a blank line, skip it.
01660                 if (a_keyword.size() == 0)
01661                         return;
01662 
01663                 // If keyword starts with a '#' then this is a comment line, skip it.
01664                 if (a_keyword[0] == '#') {
01665                         // Discard the rest of the line.
01666                         while ((a_in) && (ch != '\n')) {
01667                                 a_in.get(ch);
01668                         }
01669                         return;
01670                 }
01671 
01672                 a_keyword = estring(a_keyword).lower();
01673 
01674                 // If there is not value, return.
01675                 if (ch == '\n')
01676                         return;
01677 
01678                 // Skip whitespace between keyword and value.
01679                 a_in.get(ch);
01680                 while ((a_in) && ((ch == ' ') || (ch == '\t'))) {
01681                         a_in.get(ch);
01682                 }
01683                 if (!a_in)
01684                         return;
01685                 a_in.putback(ch);
01686                 if (!a_in)
01687                         return;
01688 
01689                 // Read value
01690                 a_in.get(ch);
01691                 while ((a_in) && (ch != '\n')) {
01692                         TRY_nomem(a_value += ch);
01693                         a_in.get(ch);
01694                 }
01695                 return;
01696         }
01697 }
01698 
01699 /** Given a path, strip off the basename -- like the dirname UNIX command */
01700 const std::string parse_dirname(const std::string& a_path)
01701 {
01702         std::string rpath;
01703 
01704         TRY_nomem(rpath = a_path);
01705 
01706         if (rpath.find_last_of('/') != std::string::npos)
01707                 rpath.erase(rpath.find_last_of('/'));
01708         
01709         if (rpath.size() == 0) {
01710                 TRY_nomem(rpath = "./");
01711                 return(rpath);
01712         }
01713 
01714         if (rpath[rpath.size()-1] != '/') {
01715                 TRY_nomem(rpath += '/');
01716         }
01717 
01718         return(rpath);
01719 }
01720 
01721 /** Given a path, strip off the directory -- like the basename UNIX commane */
01722 const std::string parse_basename(const std::string& a_path)
01723 {
01724         std::string es;
01725         std::string rpath;
01726 
01727         TRY_nomem(rpath = a_path);
01728 
01729         if (rpath.find_last_of('/') != std::string::npos)
01730                 rpath.erase(0,rpath.find_last_of('/'));
01731 
01732         return(rpath);
01733 }
01734 
01735 //----------------------------------------------------------------------------
01736 
01737 /** C'tor */
01738 global_parser::global_parser(
01739         const std::string& a_path,
01740         uint16& a_line,
01741         std::istream& a_in
01742         )
01743 {
01744         m_in = &a_in;
01745         m_path = &a_path;
01746         m_line = &a_line;
01747 
01748         parse();
01749 }
01750 
01751 /** Generate a string showing the current location within a configuration file
01752  * of the parser */
01753 const std::string global_parser::location(void)
01754 {
01755         std::string es;
01756 
01757         TRY_nomem(es = "At ");
01758         TRY_nomem(es += (*m_path));
01759         TRY_nomem(es += "[");
01760         TRY_nomem(es += estring((*m_line)));
01761         TRY_nomem(es += "]");
01762 
01763         return(es);
01764 }
01765 
01766 /** Read a configuration file, used by the "include" command */
01767 void global_parser::read_config(const std::string& a_path)
01768 {
01769         std::string es;
01770         std::ifstream in;
01771         uint16 line = 0;
01772 
01773         in.open(a_path.c_str());
01774         if (!in.is_open()) {
01775                 TRY_nomem(es = "Could not open configuraiton file: \"");
01776                 TRY_nomem(es += a_path);
01777                 TRY_nomem(es += "\"");
01778                 throw(ERROR(errno,es));
01779         }
01780 
01781         global_parser(a_path, line, in);
01782 
01783         in.close();
01784         config.m_configs_read++;
01785 }
01786 
01787 /** Read a job configuration file, used by the "include-job" command */
01788 void global_parser::read_job(const std::string& a_path, job& a_job)
01789 {
01790         std::string es;
01791         std::ifstream in;
01792         uint16 line = 0;
01793 
01794         in.open(a_path.c_str());
01795         if (!in.is_open()) {
01796                 TRY_nomem(es = "Could not open job file: \"");
01797                 TRY_nomem(es += a_path);
01798                 TRY_nomem(es += "\"");
01799                 throw(ERROR(errno,es));
01800         }
01801 
01802         job_parser(&a_job, a_path, line, in, "", false);
01803 
01804         TRY_nomem(a_job.config_path = *m_path);
01805         TRY_nomem(a_job.config_line = *m_line);
01806         a_job.check();
01807 
01808         in.close();
01809 }
01810 
01811 /** Global context parser */
01812 void global_parser::parse(void)
01813 {
01814         std::string es;
01815         std::string keyword;
01816         std::string value;
01817 
01818         while ((*m_in)) {
01819                 (*m_line)++;
01820                 
01821                 try {
01822                         parse_line((*m_in), keyword, value);
01823                 }
01824                 catch(error e) {
01825                         e.push_back(ERROR_INSTANCE(location()));
01826                         throw(e);
01827                 }
01828                 catch(...) {
01829                         error e = err_unknown;
01830 
01831                         e.push_back(ERROR_INSTANCE(location()));
01832                         throw(e);
01833                 }
01834 
01835                 if (keyword.size() == 0)
01836                         continue;
01837                 if (keyword[0] == '#')
01838                         continue;
01839 
01840                 try {
01841                         if (keyword == "<default>") {
01842                                 parse_default(value);
01843                         }
01844                         else if (keyword == "include") {
01845                                 parse_include(value);
01846                         }
01847                         else if (keyword == "include-job") {
01848                                 parse_include_job(value);
01849                         }
01850                         else if (keyword == "<job>") {
01851                                 parse_job(value);
01852                         }
01853                         else if (keyword == "link-catalog-dir") {
01854                                 parse_link_catalog_dir(value);
01855                         }
01856                         else if (keyword == "log-dir") {
01857                                 parse_log_dir(value);
01858                         }
01859                         else if (keyword == "delete-old-log-files") {
01860                                 parse_delete_old_log_files(value);
01861                         }
01862                         else if (keyword == "delete-old-report-files") {
01863                                 parse_delete_old_report_files(value);
01864                         }
01865                         else if (keyword == "logging-level") {
01866                                 parse_logging_level(value);
01867                         }
01868                         else if (keyword == "error-logging-level") {
01869                                 parse_error_logging_level(value);
01870                         }
01871                         else if (keyword == "rsync-local-path") {
01872                                 parse_rsync_local_path(value);
01873                         }
01874                         else if (keyword == "rsync-parallel") {
01875                                 parse_rsync_parallel(value);
01876                         }
01877                         else if (keyword == "io-poll-interval") {
01878                                 parse_io_poll_interval(value);
01879                         }
01880                         else if (keyword == "timestamp-resolution") {
01881                                 parse_timestamp_resolution(value);
01882                         }
01883                         else if (keyword == "vault") {
01884                                 try {
01885                                         parse_vault(value);
01886                                 }
01887                                 catch(error e) {
01888                                         std::cerr << e;
01889                                 }
01890                                 catch(...) {
01891                                         throw(err_unknown);
01892                                 }
01893                         }
01894                         else if (keyword == "vault-overflow-behavior") {
01895                                 parse_vault_overflow_behavior(value);
01896                         }
01897                         else if (keyword == "vault-overflow-blocks") {
01898                                 parse_vault_overflow_blocks(value);
01899                         }
01900                         else if (keyword == "vault-overflow-inodes") {
01901                                 parse_vault_overflow_inodes(value);
01902                         }
01903                         else if (keyword == "vault-selection-behavior") {
01904                                 parse_vault_selection_behavior(value);
01905                         }
01906                         else if (keyword == "vault-locking") {
01907                                 parse_vault_locking(value);
01908                         }
01909                         else {
01910                                 error e(0);
01911 
01912                                 TRY_nomem(es = "Unknown command in global context: \"");
01913                                 TRY_nomem(es += keyword);
01914                                 TRY_nomem(es += "\"");
01915                                 throw(ERROR(0,es));
01916                         }
01917                 }
01918                 catch(error e) {
01919                         e.push_back(ERROR_INSTANCE(location()));
01920                         throw(e);
01921                 }
01922                 catch(...) {
01923                         error e = err_unknown;
01924 
01925                         e.push_back(ERROR_INSTANCE(location()));
01926                         throw(e);
01927                 }
01928         }
01929 }
01930 
01931 /** Parse a default job context */
01932 void global_parser::parse_default(const std::string& a_value)
01933 {
01934         std::string delimiter;
01935         std::string default_config_path;
01936         uint16 default_config_line;
01937         job* jobPtr = &config.m_default_job;
01938 
01939         config.m_default_job.clear();
01940 
01941         TRY_nomem(default_config_path = *m_path);
01942         TRY_nomem(default_config_line = *m_line);
01943         TRY_nomem(delimiter = "</default>");
01944 
01945         job_parser(jobPtr, *m_path, *m_line, *m_in, delimiter, true);
01946 
01947         TRY_nomem(jobPtr->default_config_path = default_config_path);
01948         jobPtr->default_config_line = default_config_line;
01949 }
01950 
01951 /** Parse an "include" command */
01952 void global_parser::parse_include(const std::string& a_value)
01953 {
01954         std::string es;
01955         directory dir;
01956         directory::const_iterator cdi;
01957         std::string rpath;
01958         std::string ipath;
01959 
01960         if (a_value.size() == 0) {
01961                 TRY_nomem(es = "Invalid include path: \"");
01962                 TRY_nomem(es += a_value);
01963                 TRY_nomem(es += "\"");
01964                 throw(ERROR(0,es));
01965         }
01966 
01967         if (a_value[0] != '/') {
01968                 TRY_nomem(rpath = parse_dirname(*m_path));
01969         }
01970 
01971         TRY_nomem(ipath = rpath + a_value);
01972 
01973         TRY_nomem(es = "No configuration file(s) found: \"");
01974         TRY_nomem(es += a_value);
01975         TRY_nomem(es += "\"");
01976         TRY_instead(dir.path(ipath),es);
01977         if (dir.size() == 0)
01978                 throw(ERROR(0,es));
01979         
01980         for (cdi = dir.begin(); cdi != dir.end(); cdi++) {
01981                 if (dir.size() > 1) {
01982                         TRY_nomem(es = "For files found matching: \"");
01983                         TRY_nomem(es += a_value);
01984                         TRY_nomem(es += "\"");
01985                         try {
01986                                 read_config(*cdi);
01987                         }
01988                         catch(error e) {
01989                                 e.push_back(ERROR_INSTANCE(es));
01990                                 throw(e);
01991                         }
01992                         catch(...) {
01993                                 error e = err_unknown;
01994                 
01995                                 e.push_back(ERROR_INSTANCE(es));
01996                                 throw(e);
01997                         }
01998                 }
01999                 else
02000                         read_config(*cdi);
02001         }
02002 }
02003 
02004 /** Parse an "include-job" command */
02005 void global_parser::parse_include_job(const std::string& a_value)
02006 {
02007         std::string es;
02008         directory dir;
02009         directory::const_iterator cdi;
02010         std::string rpath;
02011         std::string ipath;
02012 
02013         if (a_value.size() == 0) {
02014                 TRY_nomem(es = "Invalid include-job path: \"");
02015                 TRY_nomem(es += a_value);
02016                 TRY_nomem(es += "\"");
02017                 throw(ERROR(0,es));
02018         }
02019 
02020         if (a_value[0] != '/') {
02021                 TRY_nomem(rpath = parse_dirname(*m_path));
02022         }
02023 
02024         TRY_nomem(ipath = rpath + a_value);
02025 
02026         TRY_nomem(es = "No job file(s) found: \"");
02027         TRY_nomem(es += a_value);
02028         TRY_nomem(es += "\"");
02029         TRY(dir.path(ipath),es);
02030         if (dir.size() == 0)
02031                 throw(ERROR(0,es));
02032 
02033         for (cdi = dir.begin(); cdi != dir.end(); cdi++) {
02034                 job new_job;
02035                 
02036                 new_job = config.m_default_job;
02037                 
02038                 if (dir.size() > 1) {
02039                         TRY_nomem(es = "For files found matching: \"");
02040                         TRY_nomem(es += a_value);
02041                         TRY_nomem(es += "\"");
02042                         try {
02043                                 read_job(*cdi, new_job);
02044                         }
02045                         catch(error e) {
02046                                 e.push_back(ERROR_INSTANCE(es));
02047                                 throw(e);
02048                         }
02049                         catch(...) {
02050                                 error e = err_unknown;
02051 
02052                                 e.push_back(ERROR_INSTANCE(es));
02053                                 throw(e);
02054                         }
02055                 }
02056                 else
02057                         read_job(*cdi, new_job);
02058                 TRY_nomem(config.m_jobs.push_back(new_job));
02059         }
02060 }
02061 
02062 /** Parse a job context */
02063 void global_parser::parse_job(const std::string& a_value)
02064 {
02065         std::string delimiter;
02066         std::string config_path;
02067         uint16 config_line;
02068         job new_job;
02069         
02070         TRY_nomem(config_path = *m_path);
02071         config_line = *m_line;
02072         new_job = config.m_default_job;
02073 
02074         TRY_nomem(new_job.config_path = config_path);
02075         new_job.config_line = config_line;
02076         TRY_nomem(delimiter = "</job>");
02077 
02078         job_parser(&new_job, *m_path, *m_line, *m_in, delimiter, false);
02079 
02080         new_job.check();
02081 
02082         TRY_nomem(config.m_jobs.push_back(new_job));
02083 }
02084 
02085 /** Parse a "link-catalog-dir" command */
02086 void global_parser::parse_link_catalog_dir(const std::string& a_value)
02087 {
02088         std::string es;
02089         subdirectory subdir;
02090         
02091         TRY_nomem(es = "Invalid link-catalog-dir path: \"");
02092         TRY_nomem(es += a_value);
02093         TRY_nomem(es += "\"");
02094         TRY_instead(subdir.path(a_value,"*"),es);
02095         TRY_nomem(config.m_link_catalog_dir = a_value);
02096 }
02097 
02098 /** Parse a "log-dir" command */
02099 void global_parser::parse_log_dir(const std::string& a_value)
02100 {
02101         std::string es;
02102         subdirectory subdir;
02103 
02104         TRY_nomem(es = "Invalid log-dir path: \"");
02105         TRY_nomem(es += a_value);
02106         TRY_nomem(es += "\"");
02107         TRY_instead(subdir.path(a_value,"*"),es);
02108         TRY_nomem(config.m_log_dir = a_value);
02109 }
02110 
02111 /** Parse a "delete-old-log-files" command */
02112 void global_parser::parse_delete_old_log_files(const std::string& a_value)
02113 {
02114         std::string es;
02115         estring str;
02116 
02117         TRY_nomem(es = "Invalid delete-old-log-files value: \"");
02118         TRY_nomem(es += a_value);
02119         TRY_nomem(es += "\"");
02120         TRY(str = estring(a_value).lower(),es);
02121         if (
02122                    (str == "y")
02123                 || (str == "yes")
02124                 || (str == "t")
02125                 || (str == "true")
02126                 || (str == "1")
02127                 || (str == "on")
02128                 ) {
02129                 config.m_delete_old_log_files = true;
02130         }
02131         else if (
02132                    (str == "n")
02133                 || (str == "no")
02134                 || (str == "f")
02135                 || (str == "false")
02136                 || (str == "0")
02137                 || (str == "off")
02138                 ) {
02139                 config.m_delete_old_log_files = false;
02140         }
02141         else {
02142                 throw(ERROR(0,es));
02143         }
02144 }
02145 
02146 /** Parse a "delete-old-report-files" command */
02147 void global_parser::parse_delete_old_report_files(const std::string& a_value)
02148 {
02149         std::string es;
02150         estring str;
02151 
02152         TRY_nomem(es = "Invalid delete-old-report-files value: \"");
02153         TRY_nomem(es += a_value);
02154         TRY_nomem(es += "\"");
02155         TRY(str = estring(a_value).lower(),es);
02156         if (
02157                    (str == "y")
02158                 || (str == "yes")
02159                 || (str == "t")
02160                 || (str == "true")
02161                 || (str == "1")
02162                 || (str == "on")
02163                 ) {
02164                 config.m_delete_old_report_files = true;
02165         }
02166         else if (
02167                    (str == "n")
02168                 || (str == "no")
02169                 || (str == "f")
02170                 || (str == "false")
02171                 || (str == "0")
02172                 || (str == "off")
02173                 ) {
02174                 config.m_delete_old_report_files = false;
02175         }
02176         else {
02177                 throw(ERROR(0,es));
02178         }
02179 }
02180 
02181 /** Parse a "loging-level" command */
02182 void global_parser::parse_logging_level(const std::string& a_value)
02183 {
02184         std::string es;
02185         estring str;
02186 
02187         TRY_nomem(es = "Invalid logging-level value: \"");
02188         TRY_nomem(es += a_value);
02189         TRY_nomem(es += "\"");
02190         TRY_nomem(str = estring(a_value).lower());
02191         if (str == "manager") {
02192                 config.m_logging_level = configuration_manager::logging_manager;
02193         }
02194         else if (str == "child") {
02195                 config.m_logging_level = configuration_manager::logging_child;
02196         }
02197         else if (str == "rsync") {
02198                 config.m_logging_level = configuration_manager::logging_rsync;
02199         }
02200         else {
02201                 throw(ERROR(0,es));
02202         }
02203 }
02204 
02205 /** Parse a "error-loging-level" command */
02206 void global_parser::parse_error_logging_level(const std::string& a_value)
02207 {
02208         std::string es;
02209         estring str;
02210 
02211         TRY_nomem(es = "Invalid error-logging-level value: \"");
02212         TRY_nomem(es += a_value);
02213         TRY_nomem(es += "\"");
02214         TRY_nomem(str = estring(a_value).lower());
02215         if (str == "manager") {
02216                 config.m_error_logging_level = configuration_manager::logging_manager;
02217         }
02218         else if (str == "child") {
02219                 config.m_error_logging_level = configuration_manager::logging_child;
02220         }
02221         else if (str == "rsync") {
02222                 config.m_error_logging_level = configuration_manager::logging_rsync;
02223         }
02224         else {
02225                 throw(ERROR(0,es));
02226         }
02227 }
02228 
02229 /** Parse an "rsync-local-path" command */
02230 void global_parser::parse_rsync_local_path(const std::string& a_value)
02231 {
02232         std::string es;
02233         filestatus fstat;
02234 
02235         TRY_nomem(es = "Invalid rsync-local-path value: \"");
02236         TRY_nomem(es += a_value);
02237         TRY_nomem(es += "\"");
02238         TRY_instead(fstat.path(a_value),es);
02239         TRY_nomem(config.m_rsync_local_path = a_value);
02240 }
02241 
02242 /** Parse an "rsync-parallel" command */
02243 void global_parser::parse_rsync_parallel(const std::string& a_value)
02244 {
02245         std::string es;
02246         uint16 num;
02247 
02248         TRY_nomem(es = "Invalid rsync-parallel value: \"");
02249         TRY_nomem(es += a_value);
02250         TRY_nomem(es += "\"");
02251         TRY_instead(num = estring(a_value),es);
02252         if (num == 0)
02253                 throw(ERROR(0,es));
02254         config.m_rsync_parallel = num;
02255 }
02256 
02257 /** Parse "io-poll-interval" command */
02258 void global_parser::parse_io_poll_interval(const std::string& a_value)
02259 {
02260         std::string es;
02261         uint16 num;
02262 
02263         TRY_nomem(es = "Invalid io-poll-interval value: \"");
02264         TRY_nomem(es += a_value);
02265         TRY_nomem(es += "\"");
02266         TRY_instead(num = estring(a_value),es);
02267         if (num == 0)
02268                 throw(ERROR(0,es));
02269         config.m_io_poll_interval = num;
02270 }
02271 
02272 /** Parse a "timestamp-resolution" command */
02273 void global_parser::parse_timestamp_resolution(const std::string& a_value)
02274 {
02275         std::string es;
02276         estring str;
02277 
02278         TRY_nomem(es = "Invalid timestamp-resolution: \"");
02279         TRY_nomem(es += a_value);
02280         TRY_nomem(es += "\"");
02281         TRY(str = estring(a_value).lower(),es);
02282         if (str == "year") {
02283                 config.m_timestamp.resolution(timestamp::resolution_year);
02284         }
02285         else if (str == "month") {
02286                 config.m_timestamp.resolution(timestamp::resolution_month);
02287         }
02288         else if (str == "day") {
02289                 config.m_timestamp.resolution(timestamp::resolution_day);
02290         }
02291         else if (str == "hour") {
02292                 config.m_timestamp.resolution(timestamp::resolution_hour);
02293         }
02294         else if (str == "minute") {
02295                 config.m_timestamp.resolution(timestamp::resolution_minute);
02296         }
02297         else if (str == "second") {
02298                 config.m_timestamp.resolution(timestamp::resolution_second);
02299         }
02300         else {
02301                 throw(ERROR(0,es));
02302         }
02303 }
02304 
02305 /** Parse a "vault" command */
02306 void global_parser::parse_vault(const std::string& a_value)
02307 {
02308         std::string es;
02309         directory dir;
02310         directory::const_iterator cdi;
02311         subdirectory subdir;
02312         filestatus fstat;
02313         error partial_vault_error = ERROR(0,"One or more vault paths were found to be invalid:");
02314 
02315         TRY_nomem(es = "Invalid vault path: \"");
02316         TRY_nomem(es += a_value);
02317         TRY_nomem(es += "\"");
02318 
02319         if (a_value.size() == 0)
02320                 throw(ERROR(0,es));
02321 
02322         TRY(dir.path(a_value),es);
02323 
02324         if (dir.size() == 0) {
02325                 TRY_instead(fstat.path(a_value),es);
02326         }
02327 
02328         for (cdi = dir.begin(); cdi != dir.end(); cdi++) {
02329                 if (!is_dir(*cdi)) {
02330                         TRY_nomem(es = get_error_str(ENOTDIR));
02331                         TRY_nomem(es += ": \"");
02332                         TRY_nomem(es += *cdi);
02333                         TRY_nomem(es += "\"");
02334                         partial_vault_error.push_back(es);
02335                         continue;
02336                 }
02337                 if (!readable(*cdi)) {
02338                         TRY_nomem(es = "No read access to path: \"");
02339                         TRY_nomem(es += *cdi);
02340                         TRY_nomem(es += "\"");
02341                         partial_vault_error.push_back(es);
02342                         continue;
02343                 }
02344                 if (!writable(*cdi)) {
02345                         TRY_nomem(es = "No write access to path: \"");
02346                         TRY_nomem(es += *cdi);
02347                         TRY_nomem(es += "\"");
02348                         partial_vault_error.push_back(es);
02349                         continue;
02350                 }
02351                 if (!executable(*cdi)) {
02352                         TRY_nomem(es = "No execution access to path: \"");
02353                         TRY_nomem(es += *cdi);
02354                         TRY_nomem(es += "\"");
02355                         partial_vault_error.push_back(es);
02356                         continue;
02357                 }
02358                 TRY_nomem(config.m_vaults.push_back(*cdi));
02359         }
02360 
02361         if (partial_vault_error.size() > 1) {
02362                 TRY_nomem(es = "For paths found matching: \"");
02363                 TRY_nomem(es += a_value);
02364                 TRY_nomem(es += "\"");
02365                 partial_vault_error.push_back(es);
02366                 throw(partial_vault_error);
02367         }
02368 }
02369 
02370 /** Parse a "vault-overflow-behavior" command */
02371 void global_parser::parse_vault_overflow_behavior(const std::string& a_value)
02372 {
02373         std::string es;
02374         estring str;
02375 
02376         TRY_nomem(es = "Invalid vault-overflow-behavior value: \"");
02377         TRY_nomem(es += a_value);
02378         TRY_nomem(es += "\"");
02379         TRY(str = estring(a_value).lower(),es);
02380         if (str == "quit") {
02381                 config.m_vault_overflow_behavior = configuration_manager::overflow_quit;
02382         }
02383         else if (str == "delete-oldest") {
02384                 config.m_vault_overflow_behavior = configuration_manager::overflow_delete_oldest;
02385         }
02386         else if (str == "delete-until-free") {
02387                 config.m_vault_overflow_behavior = configuration_manager::overflow_delete_until_free;
02388         }
02389         else {
02390                 throw(ERROR(0,es));
02391         }
02392 }
02393 
02394 /** Parse a "vault-overflow-blocks" command */
02395 void global_parser::parse_vault_overflow_blocks(const std::string& a_value)
02396 {
02397         std::string es;
02398         uint16 num;
02399 
02400         TRY_nomem(es = "Invalid vault-overflow-blocks value: \"");
02401         TRY_nomem(es += a_value);
02402         TRY_nomem(es += "\"");
02403         TRY(num = estring(a_value),es);
02404         if (num > 50)
02405                 throw(ERROR(0,es));
02406         config.m_vault_overflow_blocks = num;
02407 }
02408 
02409 /** Parse a "vault-overflow-inodes" command */
02410 void global_parser::parse_vault_overflow_inodes(const std::string& a_value)
02411 {
02412         std::string es;
02413         uint16 num;
02414 
02415         TRY_nomem(es = "Invalid vault-overflow-inodes value: \"");
02416         TRY_nomem(es += a_value);
02417         TRY_nomem(es += "\"");
02418         TRY(num = estring(a_value),es);
02419         if (num > 50)
02420                 throw(ERROR(0,es));
02421         config.m_vault_overflow_inodes = num;
02422 }
02423 
02424 /** Parse a "vault-selection-behavior" command */
02425 void global_parser::parse_vault_selection_behavior(const std::string& a_value)
02426 {
02427         std::string es;
02428         estring str;
02429 
02430         TRY_nomem(es = "Invalid vault-selection-behavior value: \"");
02431         TRY_nomem(es += a_value);
02432         TRY_nomem(es += "\"");
02433         TRY(str = estring(a_value).lower(),es);
02434         if (str == "max-free") {
02435                 config.m_vault_selection_behavior = configuration_manager::selection_max_free;
02436         }
02437         else if (str == "round-robin") {
02438                 config.m_vault_selection_behavior = configuration_manager::selection_round_robin;
02439         }
02440         else {
02441                 throw(ERROR(0,es));
02442         }
02443 }
02444 
02445 /** Parse a "vault-locking" command */
02446 void global_parser::parse_vault_locking(const std::string& a_value)
02447 {
02448         std::string es;
02449         estring str;
02450 
02451         TRY_nomem(es = "Invalid vault-locking value: \"");
02452         TRY_nomem(es += a_value);
02453         TRY_nomem(es += "\"");
02454         TRY(str = estring(a_value).lower(),es);
02455         if (
02456                    (str == "y")
02457                 || (str == "yes")
02458                 || (str == "t")
02459                 || (str == "true")
02460                 || (str == "1")
02461                 || (str == "on")
02462                 ) {
02463                 config.m_vault_locking = true;
02464         }
02465         else if (
02466                    (str == "n")
02467                 || (str == "no")
02468                 || (str == "f")
02469                 || (str == "false")
02470                 || (str == "0")
02471                 || (str == "off")
02472                 ) {
02473                 config.m_vault_locking = false;
02474         }
02475         else {
02476                 throw(ERROR(0,es));
02477         }
02478 }
02479 
02480 //----------------------------------------------------------------------------
02481 
02482 /** C'tor */
02483 job_parser::job_parser(
02484         job * a_job,
02485         const std::string& a_path,
02486         uint16& a_line,
02487         std::istream& a_in,
02488         const std::string& a_block_delimiter,
02489         const bool a_default_context = false
02490         )
02491 {
02492         m_job = a_job;
02493         m_in = &a_in;
02494         m_path = &a_path;
02495         m_line = &a_line;
02496         m_delimiter = &a_block_delimiter;
02497         m_default_context = a_default_context;
02498 
02499         parse();
02500 }
02501 
02502 /** Construct a string with the current location of the parser in a
02503  * configuration file */
02504 const std::string job_parser::location(void)
02505 {
02506         std::string es;
02507 
02508         TRY_nomem(es = "At ");
02509         TRY_nomem(es += (*m_path));
02510         TRY_nomem(es += "[");
02511         TRY_nomem(es += estring((*m_line)));
02512         TRY_nomem(es += "]");
02513 
02514         return(es);
02515 }
02516 
02517 /** Read a job configuration file, used by the "include" command */
02518 void job_parser::read_job(const std::string& a_path)
02519 {
02520         std::string es;
02521         std::ifstream in;
02522         uint16 line = 0;
02523 
02524         in.open(a_path.c_str());
02525         if (!in.is_open()) {
02526                 TRY_nomem(es = "Could not open job file: \"");
02527                 TRY_nomem(es += a_path);
02528                 TRY_nomem(es += "\"");
02529                 throw(ERROR(errno,es));
02530         }
02531 
02532         job_parser(m_job, a_path, line, in, "", m_default_context);
02533 
02534         in.close();
02535 }
02536 
02537 /** Job context parser */
02538 void job_parser::parse(void)
02539 {
02540         std::string es;
02541         std::string keyword;
02542         std::string value;
02543 
02544         while ((*m_in)) {
02545                 (*m_line)++;
02546                 
02547                 try {
02548                         parse_line((*m_in), keyword, value);
02549                 }
02550                 catch(error e) {
02551                         e.push_back(ERROR_INSTANCE(location()));
02552                         throw(e);
02553                 }
02554                 catch(...) {
02555                         error e = err_unknown;
02556 
02557                         e.push_back(ERROR_INSTANCE(location()));
02558                         throw(e);
02559                 }
02560 
02561                 if (!(*m_in) && (m_delimiter->size() != 0)) {
02562                         TRY_nomem(es = "Unexpected end of file, expected \"");
02563                         TRY_nomem(es += *m_delimiter);
02564                         TRY_nomem(es += "\" here");
02565                         throw(ERROR(errno,es));
02566                 }
02567 
02568                 if (keyword.size() == 0)
02569                         continue;
02570                 if (keyword[0] == '#')
02571                         continue;
02572 
02573                 try {
02574                         if (keyword == *m_delimiter) {
02575                                 return;
02576                         }
02577                         else if (keyword == "archive-path") {
02578                                 parse_archive_path(value);
02579                         }
02580                         else if (keyword == "clear") {
02581                                 parse_clear(value);
02582                         }
02583                         else if (keyword == "exclude-from") {
02584                                 parse_exclude_from(value);
02585                         }
02586                         else if (keyword == "include-from") {
02587                                 parse_include_from(value);
02588                         }
02589                         else if (keyword == "groupname") {
02590                                 parse_groupname(value);
02591                         }
02592                         else if (keyword == "hostname") {
02593                                 parse_hostname(value);
02594                         }
02595                         else if (keyword == "include") {
02596                                 parse_include(value);
02597                         }
02598                         else if ((keyword == "jobname") && (*m_delimiter == "</job>")) {
02599                                 parse_jobname(value);
02600                         }
02601                         else if (keyword == "path") {
02602                                 parse_path(value);
02603                         }
02604                         else if (keyword == "rsync-behavior") {
02605                                 parse_rsync_behavior(value);
02606                         }
02607                         else if (keyword == "rsync-connection-type") {
02608                                 parse_rsync_connection_type(value);
02609                         }
02610                         else if (keyword == "rsync-hardlink") {
02611                                 parse_rsync_hardlink(value);
02612                         }
02613                         else if (keyword == "rsync-multi-hardlink") {
02614                                 parse_rsync_multi_hardlink(value);
02615                         }
02616                         else if (keyword == "rsync-multi-hardlink-max") {
02617                                 parse_rsync_multi_hardlink_max(value);
02618                         }
02619                         else if (keyword == "rsync-options") {
02620                                 parse_rsync_options(value);
02621                         }
02622                         else if (keyword == "<rsync-options>") {
02623                                 parse_rsync_options_context(value);
02624                         }
02625                         else if (keyword == "rsync-remote-user") {
02626                                 parse_rsync_remote_user(value);
02627                         }
02628                         else if (keyword == "rsync-remote-path") {
02629                                 parse_rsync_remote_path(value);
02630                         }
02631                         else if (keyword == "rsync-remote-port") {
02632                                 parse_rsync_remote_port(value);
02633                         }
02634                         else if (keyword == "rsync-remote-module") {
02635                                 parse_rsync_remote_module(value);
02636                         }
02637                         else if (keyword == "rsync-retry-count") {
02638                                 parse_rsync_retry_count(value);
02639                         }
02640                         else if (keyword == "rsync-retry-delay") {
02641                                 parse_rsync_retry_delay(value);
02642                         }
02643                         else if (keyword == "rsync-timeout") {
02644                                 parse_rsync_timeout(value);
02645                         }
02646                         else {
02647                                 error e(0);
02648 
02649                                 TRY_nomem(es = "Unknown command in ");
02650                                 if (m_default_context) {
02651                                         TRY_nomem(es += "default");
02652                                 }
02653                                 else {
02654                                         TRY_nomem(es += "job");
02655                                 }
02656                                 TRY_nomem(es += " context: \"");
02657                                 TRY_nomem(es += keyword);
02658                                 TRY_nomem(es += "\"");
02659                                 throw(ERROR(0,es));
02660                         }
02661                 }
02662                 catch(error e) {
02663                         if ((*m_delimiter).size() == 0)
02664                                 e.push_back(ERROR_INSTANCE(location()));
02665                         throw(e);
02666                 }
02667                 catch(...) {
02668                         error e = err_unknown;
02669 
02670                         e.push_back(ERROR_INSTANCE(location()));
02671                         throw(e);
02672                 }
02673         }
02674 }
02675 
02676 /** Parse an "archive-path" command */
02677 void job_parser::parse_archive_path(const std::string& a_value)
02678 {
02679         std::string es;
02680 
02681         TRY_nomem(es = "Invalid archive-path value");
02682         TRY((*m_job).archive_path = a_value,es);
02683 }
02684 
02685 /** Parse a "clear" command */
02686 void job_parser::parse_clear(const std::string& a_value)
02687 {
02688         std::string es;
02689         estring str;
02690 
02691         TRY_nomem(es = "Invalid clear value: \"");
02692         TRY_nomem(es += a_value);
02693         TRY_nomem(es += "\"");
02694         TRY(str = estring(a_value).lower(),es);
02695         if (str == "archive-path") {
02696                 m_job->archive_path.clear();
02697         }
02698         else if (str == "exclude-from") {
02699                 m_job->excludes.clear();
02700         }
02701         else if (str == "groupname") {
02702                 m_job->groupname.erase();
02703         }
02704         else if (str == "hostname") {
02705                 m_job->hostname.erase();
02706         }
02707         else if (str == "include-from") {
02708                 m_job->includes.clear();
02709         }
02710         else if ((str == "jobname") && (*m_delimiter == "</job>")) {
02711                 m_job->jobname.erase();
02712         }
02713         else if (str == "paths") {
02714                 m_job->paths.clear();
02715         }
02716         else if (str == "rsync-behavior") {
02717                 m_job->rsync_behavior.clear();
02718         }
02719         else if (str == "rsync-options") {
02720                 m_job->rsync_options.erase();
02721         }
02722         else if (str == "rsync-remote-user") {
02723                 m_job->rsync_remote_user.erase();
02724         }
02725         else if (str == "rsync-remotr-port") {
02726                 m_job->rsync_remote_port = 0;
02727         }
02728         else if (str == "rsync-remote-module") {
02729                 m_job->rsync_remote_module.erase();
02730         }
02731         else if (str == "rsync-remote-path") {
02732                 m_job->rsync_remote_path.erase();
02733         }
02734         else {
02735                 throw(ERROR(0,es));
02736         }
02737 }
02738 
02739 /** Parse an "exclude-from" command */
02740 void job_parser::parse_exclude_from(const std::string& a_value)
02741 {
02742         std::string es;
02743         directory dir;
02744         directory::const_iterator cdi;
02745         std::string rpath;
02746         std::string ipath;
02747 
02748         if (a_value.size() == 0) {
02749                 TRY_nomem(es = "Invalid exclude-from path: \"");
02750                 TRY_nomem(es += a_value);
02751                 TRY_nomem(es += "\"");
02752                 throw(ERROR(0,es));
02753         }
02754 
02755         if (a_value[0] != '/') {
02756                 TRY_nomem(rpath = parse_dirname(*m_path));
02757         }
02758 
02759         TRY_nomem(ipath = rpath + a_value);
02760 
02761         TRY_nomem(es = "No exclude-from file(s) found: \"");
02762         TRY_nomem(es += a_value);
02763         TRY_nomem(es += "\"");
02764         TRY(dir.path(ipath),es);
02765         if (dir.size() == 0)
02766                 throw(ERROR(0,es));
02767         
02768         for (cdi = dir.begin(); cdi != dir.end(); cdi++) {
02769                 TRY_nomem((*m_job).excludes.push_back(*cdi));
02770         }
02771 }
02772 
02773 /** Parse an "include-from" command */
02774 void job_parser::parse_include_from(const std::string& a_value)
02775 {
02776         std::string es;
02777         directory dir;
02778         directory::const_iterator cdi;
02779         std::string rpath;
02780         std::string ipath;
02781 
02782         if (a_value.size() == 0) {
02783                 TRY_nomem(es = "Invalid include-from path: \"");
02784                 TRY_nomem(es += a_value);
02785                 TRY_nomem(es += "\"");
02786                 throw(ERROR(0,es));
02787         }
02788 
02789         if (a_value[0] != '/') {
02790                 TRY_nomem(rpath = parse_dirname(*m_path));
02791         }
02792 
02793         TRY_nomem(ipath = rpath + a_value);
02794 
02795         TRY_nomem(es = "No include-from file(s) found: \"");
02796         TRY_nomem(es += a_value);
02797         TRY_nomem(es += "\"");
02798         TRY(dir.path(ipath),es);
02799         if (dir.size() == 0)
02800                 throw(ERROR(0,es));
02801         
02802         for (cdi = dir.begin(); cdi != dir.end(); cdi++) {
02803                 TRY_nomem((*m_job).includes.push_back(*cdi));
02804         }
02805 }
02806 
02807 /** Parse a "groupname" command */
02808 void job_parser::parse_groupname(const std::string& a_value)
02809 {
02810         TRY_nomem((*m_job).groupname = a_value);
02811 }
02812 
02813 /** Parse a "hostname" command */
02814 void job_parser::parse_hostname(const std::string& a_value)
02815 {
02816         TRY_nomem((*m_job).hostname = a_value);
02817 }
02818 
02819 /** Parse an "include" command */
02820 void job_parser::parse_include(const std::string& a_value)
02821 {
02822         std::string es;
02823         directory dir;
02824         directory::const_iterator cdi;
02825         std::string rpath;
02826         std::string ipath;
02827 
02828         if (a_value.size() == 0) {
02829                 TRY_nomem(es = "Invalid include path: \"");
02830                 TRY_nomem(es += a_value);
02831                 TRY_nomem(es += "\"");
02832                 throw(ERROR(0,es));
02833         }
02834 
02835         if (a_value[0] != '/') {
02836                 TRY_nomem(rpath = parse_dirname(*m_path));
02837         }
02838 
02839         TRY_nomem(ipath = rpath + a_value);
02840 
02841         TRY_nomem(es = "No configuration file(s) found: \"");
02842         TRY_nomem(es += a_value);
02843         TRY_nomem(es += "\"");
02844         TRY_instead(dir.path(ipath),es);
02845         if (dir.size() == 0)
02846                 throw(ERROR(0,es));
02847         
02848         for (cdi = dir.begin(); cdi != dir.end(); cdi++) {
02849                 if (dir.size() > 1) {
02850                         TRY_nomem(es = "For files found matching: \"");
02851                         TRY_nomem(es += a_value);
02852                         TRY_nomem(es += "\"");
02853                         try {
02854                                 read_job(*cdi);
02855                         }
02856                         catch(error e) {
02857                                 e.push_back(ERROR_INSTANCE(es));
02858                                 throw(e);
02859                         }
02860                         catch(...) {
02861                                 error e = err_unknown;
02862 
02863                                 e.push_back(ERROR_INSTANCE(es));
02864                                 throw(e);
02865                         }
02866                 }
02867                 else
02868                         read_job(*cdi);
02869         }
02870 }
02871 
02872 /** Parse a "jobname" command */
02873 void job_parser::parse_jobname(const std::string& a_value)
02874 {
02875         TRY_nomem((*m_job).jobname = a_value);
02876 }
02877 
02878 /** Parse a "path" command */
02879 void job_parser::parse_path(const std::string& a_value)
02880 {
02881         TRY_nomem((*m_job).paths.push_back(a_value));
02882 }
02883 
02884 /** Parse an "rsync-behavior" command */
02885 void job_parser::parse_rsync_behavior(const std::string& a_value)
02886 {
02887         std::string es;
02888         estring str;
02889 
02890         TRY_nomem(es = "Invalid rsync-behavior value: \"");
02891         TRY_nomem(es += a_value);
02892         TRY_nomem(es += "\"");
02893         TRY(str = estring(a_value).lower(),es);
02894         if (str == "clear") {
02895                 (*m_job).rsync_behavior.clear();
02896         }
02897         else if (str == "reset") {
02898                 (*m_job).rsync_behavior.reset();
02899         }
02900         else
02901                 (*m_job).rsync_behavior.assign(a_value);
02902 }
02903 
02904 /** Parse an "rsync-connection-type" command */
02905 void job_parser::parse_rsync_connection_type(const std::string& a_value)
02906 {
02907         std::string es;
02908         estring str;
02909 
02910         TRY_nomem(es = "Invalid rsync-connection-type value: \"");
02911         TRY_nomem(es += a_value);
02912         TRY_nomem(es += "\"");
02913         TRY(str = estring(a_value).lower(),es);
02914         if (str == "local") {
02915                 (*m_job).rsync_connection = job::connection_local;
02916         }
02917         else if (str == "remote") {
02918                 (*m_job).rsync_connection = job::connection_remote;
02919         }
02920         else if (str == "server") {
02921                 (*m_job).rsync_connection = job::connection_server;
02922         }
02923         else {
02924                 throw(ERROR(0,es));
02925         }
02926 }
02927 
02928 /** Parse an "rsync-hardlink" command */
02929 void job_parser::parse_rsync_hardlink(const std::string& a_value)
02930 {
02931         std::string es;
02932         estring str;
02933 
02934         TRY_nomem(es = "Invalid rsync-hardlink value: \"");
02935         TRY_nomem(es += a_value);
02936         TRY_nomem(es += "\"");
02937         TRY(str = estring(a_value).lower(),es);
02938         if (
02939                    (str == "y")
02940                 || (str == "yes")
02941                 || (str == "t")
02942                 || (str == "true")
02943                 || (str == "1")
02944                 || (str == "on")
02945                 ) {
02946                 (*m_job).rsync_hardlink = true;
02947         }
02948         else if (
02949                    (str == "n")
02950                 || (str == "no")
02951                 || (str == "f")
02952                 || (str == "false")
02953                 || (str == "0")
02954                 || (str == "off")
02955                 ) {
02956                 (*m_job).rsync_hardlink = false;
02957         }
02958         else {
02959                 throw(ERROR(0,es));
02960         }
02961 }
02962 
02963 /** Parse an "rsync-multi-hardlink" command */
02964 void job_parser::parse_rsync_multi_hardlink(const std::string& a_value)
02965 {
02966         std::string es;
02967         estring str;
02968 
02969         TRY_nomem(es = "Invalid rsync-multi-hardlink value: \"");
02970         TRY_nomem(es += a_value);
02971         TRY_nomem(es += "\"");
02972         TRY(str = estring(a_value).lower(),es);
02973         if (
02974                    (str == "y")
02975                 || (str == "yes")
02976                 || (str == "t")
02977                 || (str == "true")
02978                 || (str == "1")
02979                 || (str == "on")
02980                 ) {
02981                 (*m_job).rsync_multi_hardlink = true;
02982                 (*m_job).rsync_hardlink = true;
02983         }
02984         else if (
02985                    (str == "n")
02986                 || (str == "no")
02987                 || (str == "f")
02988                 || (str == "false")
02989                 || (str == "0")
02990                 || (str == "off")
02991                 ) {
02992                 (*m_job).rsync_multi_hardlink = false;
02993         }
02994         else {
02995                 throw(ERROR(0,es));
02996         }
02997 }
02998 
02999 /** Parse an "rsync-multi-hardlink-max" command */
03000 void job_parser::parse_rsync_multi_hardlink_max(const std::string& a_value)
03001 {
03002         std::string es;
03003         uint16 num;
03004 
03005         TRY_nomem(es = "Invalid rsync-multi-hardlink-max value: \"");
03006         TRY_nomem(es += a_value);
03007         TRY_nomem(es += "\"");
03008         TRY_instead(num = estring(a_value),es);
03009         if (num == 0)
03010                 throw(ERROR(0,es));
03011         (*m_job).rsync_multi_hardlink_max = num;
03012 }
03013 
03014 /** Parse an "rsync-options" command */
03015 void job_parser::parse_rsync_options(const std::string& a_value)
03016 {
03017         if (*m_delimiter == "</default>") {
03018                 TRY_nomem((*m_job).rsync_options = a_value);
03019         }
03020         else {
03021                 if ((*m_job).rsync_options.size() != 0) {
03022                         TRY_nomem((*m_job).rsync_options += " ");
03023                 }
03024                 TRY_nomem((*m_job).rsync_options += a_value);
03025         }
03026 }
03027 
03028 /** Parse an rsync-options context */
03029 void job_parser::parse_rsync_options_context(const std::string& a_value)
03030 {
03031         std::string es;
03032         std::string value;
03033         std::string rsync_options;
03034         char ch;
03035 
03036         while ((*m_in)) {
03037                 (*m_line)++;
03038 
03039                 value.erase();
03040 
03041                 (*m_in).get(ch);
03042                 while ((ch == ' ') || (ch == '\t'))
03043                         (*m_in).get(ch);
03044                 while (((*m_in)) && (ch != '\n')) {
03045                         TRY_nomem(value += ch);
03046                         (*m_in).get(ch);
03047                 }
03048 
03049                 if ((!(*m_in)) && (value != "</rsync-options>")) {
03050                         TRY_nomem(es = "Unexpected end of file, expected ");
03051                         TRY_nomem(es += "\"</rsync-options>\" here");
03052                         throw(ERROR(errno,es));
03053                 }
03054 
03055                 if (value.size() == 0)
03056                         continue;
03057                 if (value[0] == '#')
03058                         continue;
03059 
03060                 if (value == "</rsync-options>") {
03061                         parse_rsync_options(rsync_options);
03062                         return;
03063                 }
03064 
03065                 if (rsync_options.size() != 0) {
03066                         TRY_nomem(rsync_options += ' ');
03067                 }
03068                 TRY_nomem(rsync_options += value);
03069         }
03070 }
03071 
03072 /** Parse a "remote-user" command */
03073 void job_parser::parse_rsync_remote_user(const std::string& a_value)
03074 {
03075         TRY_nomem((*m_job).rsync_remote_user = a_value);
03076 }
03077 
03078 /** Parse an "rsync-remote-path" command */
03079 void job_parser::parse_rsync_remote_path(const std::string& a_value)
03080 {
03081         TRY_nomem((*m_job).rsync_remote_path = a_value);
03082 }
03083 
03084 /** Parse an "rsync-remote-port" command */
03085 void job_parser::parse_rsync_remote_port(const std::string& a_value)
03086 {
03087         std::string es;
03088         estring str;
03089         uint16 num;
03090 
03091         TRY_nomem(es = "Invalid rsync-remote-port value: \"");
03092         TRY_nomem(es += a_value);
03093         TRY_nomem(es += "\"");
03094         TRY_nomem(str = a_value);
03095         TRY(num = str,es);
03096         (*m_job).rsync_remote_port = num;
03097 }
03098 
03099 /** Parse an "rsync-remote-module" command */
03100 void job_parser::parse_rsync_remote_module(const std::string& a_value)
03101 {
03102         TRY_nomem((*m_job).rsync_remote_module = a_value);
03103 }
03104 
03105 /** Parse an "rsync-retry-count" command */
03106 void job_parser::parse_rsync_retry_count(const std::string& a_value)
03107 {
03108         std::string es;
03109         estring str;
03110         uint16 num;
03111 
03112         TRY_nomem(es = "Invalid rsync-retry-count value: \"");
03113         TRY_nomem(es += a_value);
03114         TRY_nomem(es += "\"");
03115         TRY_nomem(str = a_value);
03116         TRY(num = str,es);
03117         (*m_job).rsync_retry_count = num;
03118 }
03119 
03120 /** Parse an "rsync-retry-delay" command */
03121 void job_parser::parse_rsync_retry_delay(const std::string& a_value)
03122 {
03123         std::string es;
03124         estring str;
03125         uint16 num;
03126 
03127         TRY_nomem(es = "Invalid rsync-retry-delay value: \"");
03128         TRY_nomem(es += a_value);
03129         TRY_nomem(es += "\"");
03130         TRY_nomem(str = a_value);
03131         TRY(num = str,es);
03132         (*m_job).rsync_retry_delay = num;
03133 }
03134 
03135 /** Parse an "rsync-timeout" command */
03136 void job_parser::parse_rsync_timeout(const std::string& a_value)
03137 {
03138         std::string es;
03139         estring str;
03140         uint16 num;
03141 
03142         TRY_nomem(es = "Invalid rsync-timeout value: \"");
03143         TRY_nomem(es += a_value);
03144         TRY_nomem(es += "\"");
03145         TRY_nomem(str = a_value);
03146         TRY(num = str,es);
03147         (*m_job).rsync_timeout = num;
03148 }
03149 
03150 //----------------------------------------------------------------------------
03151 
03152 /** The global configuration manager instance */
03153 configuration_manager config;

Generated on Thu Jun 5 11:12:57 2008 for rvm by  doxygen 1.5.1