rvm 1.08

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