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
00022 void archive_path_element::clear(void)
00023 {
00024 m_type = jobname;
00025 m_literal.erase();
00026 }
00027
00028
00029 archive_path_element::archive_path_element()
00030 {
00031 clear();
00032 }
00033
00034
00035 archive_path_element::archive_path_element(
00036 const archive_path_element& a_class)
00037 {
00038 clear();
00039 assign(a_class);
00040 }
00041
00042
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
00052 archive_path_element::archive_path_element(const std::string& a_str)
00053 {
00054 clear();
00055 assign(a_str);
00056 }
00057
00058
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
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
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
00144 const archive_path_element::element_type&
00145 archive_path_element::type(void) const
00146 {
00147 return(m_type);
00148 }
00149
00150
00151 const std::string& archive_path_element::value(void) const
00152 {
00153 return(m_literal);
00154 }
00155
00156
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
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
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
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
00225 void archive_path::reset(void)
00226 {
00227 clear();
00228 push_back("hostname/pathname");
00229 }
00230
00231
00232 archive_path::archive_path()
00233 {
00234 reset();
00235 }
00236
00237
00238 archive_path::archive_path(const archive_path& a_class)
00239 {
00240 push_back(a_class);
00241 }
00242
00243
00244 archive_path::archive_path(const archive_path_element& a_class)
00245 {
00246 push_back(a_class);
00247 }
00248
00249
00250 archive_path::archive_path(const std::string& a_str)
00251 {
00252 push_back(a_str);
00253 }
00254
00255
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
00266 void archive_path::push_back(const archive_path_element& a_class)
00267 {
00268 TRY_nomem(type::push_back(a_class));
00269 }
00270
00271
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
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
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
00335 void archive_path::assign(const archive_path_element& a_class)
00336 {
00337 clear();
00338 push_back(a_class);
00339 }
00340
00341
00342 void archive_path::assign(const std::string& a_str)
00343 {
00344 clear();
00345 push_back(a_str);
00346 }
00347
00348
00349 archive_path& archive_path::operator=(const archive_path& a_class)
00350 {
00351 assign(a_class);
00352
00353 return(*this);
00354 }
00355
00356
00357 archive_path& archive_path::operator=(const archive_path_element& a_class)
00358 {
00359 assign(a_class);
00360
00361 return(*this);
00362 }
00363
00364
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
00375 const uint16 rsync_behavior::default_behavior;
00376
00377
00378 void rsync_behavior::clear(void)
00379 {
00380 m_map.clear();
00381 m_default = retry;
00382 }
00383
00384
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
00403 rsync_behavior::rsync_behavior()
00404 {
00405 reset();
00406 }
00407
00408
00409 rsync_behavior::rsync_behavior(const rsync_behavior& a_class)
00410 {
00411 assign(a_class);
00412 }
00413
00414
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
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
00437
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
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
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
00518 rsync_behavior& rsync_behavior::operator=(const rsync_behavior& a_class)
00519 {
00520 assign(a_class);
00521
00522 return(*this);
00523 }
00524
00525
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
00535 rsync_behavior& rsync_behavior::operator=(const std::string& a_str)
00536 {
00537 assign(a_str);
00538
00539 return(*this);
00540 }
00541
00542
00543 const rsync_behavior::behavior_type rsync_behavior::default_value(void) const
00544 {
00545 return(m_default);
00546 }
00547
00548
00549 const rsync_behavior::map_type& rsync_behavior::map_value(void) const
00550 {
00551 return(m_map);
00552 }
00553
00554
00555
00556
00557 job::job()
00558 {
00559 clear();
00560 }
00561
00562
00563 job::job(const job& a_job)
00564 {
00565 clear();
00566 assign(a_job);
00567 }
00568
00569
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_options.erase();
00587 rsync_remote_user.erase();
00588 rsync_remote_path.erase();
00589 rsync_remote_port = 0;
00590 rsync_remote_module.erase();
00591 rsync_retry_count = 3;
00592 rsync_timeout = 60 * 60 * 4;
00593 }
00594
00595
00596 void job::assign(const job& a_job)
00597 {
00598 clear();
00599
00600 default_config_path = a_job.default_config_path;
00601 default_config_line = a_job.default_config_line;
00602 config_path = a_job.config_path;
00603 config_line = a_job.config_line;
00604 archive_path = a_job.archive_path;
00605 excludes = a_job.excludes;
00606 includes = a_job.includes;
00607 groupname = a_job.groupname;
00608 hostname = a_job.hostname;
00609 jobname = a_job.jobname;
00610 paths = a_job.paths;
00611 rsync_behavior.clear();
00612 rsync_behavior = a_job.rsync_behavior;
00613 rsync_connection = a_job.rsync_connection;
00614 rsync_hardlink = a_job.rsync_hardlink;
00615 rsync_options = a_job.rsync_options;
00616 rsync_remote_user = a_job.rsync_remote_user;
00617 rsync_remote_path = a_job.rsync_remote_path;
00618 rsync_remote_port = a_job.rsync_remote_port;
00619 rsync_remote_module = a_job.rsync_remote_module;
00620 rsync_retry_count = a_job.rsync_retry_count;
00621 rsync_timeout = a_job.rsync_timeout;
00622 }
00623
00624
00625 job& job::operator=(const job& a_job)
00626 {
00627 assign(a_job);
00628
00629 return(*this);
00630 }
00631
00632
00633 const std::string job::generate_archive_path(const std::string& a_path) const
00634 {
00635 std::string es;
00636 std::string path;
00637 archive_path::const_iterator capi;
00638
00639 for (capi = archive_path.begin(); capi != archive_path.end(); ++capi) {
00640 if (capi->type() == archive_path_element::jobname) {
00641 if (jobname.size() == 0) {
00642 TRY_nomem(es = "archive-path references jobname, ");
00643 TRY_nomem(es += "but jobname is empty");
00644 throw(ERROR(0,es));
00645 }
00646 if (path.size() != 0) {
00647 TRY_nomem(path += '/');
00648 }
00649 TRY_nomem(path += jobname);
00650 }
00651 else if (capi->type() == archive_path_element::groupname) {
00652 if (groupname.size() == 0) {
00653 TRY_nomem(es = "archive-path references groupname, ");
00654 TRY_nomem(es += "but groupname is empty");
00655 throw(ERROR(0,es));
00656 }
00657 if (path.size() != 0) {
00658 TRY_nomem(path += '/');
00659 }
00660 TRY_nomem(path += groupname);
00661 }
00662 else if (capi->type() == archive_path_element::hostname) {
00663 if (hostname.size() == 0) {
00664 TRY_nomem(es = "archive-path references hostname, ");
00665 TRY_nomem(es += "but hostname is empty");
00666 throw(ERROR(0,es));
00667 }
00668 if (path.size() != 0) {
00669 TRY_nomem(path += '/');
00670 }
00671 TRY_nomem(path += hostname);
00672 }
00673 else if (capi->type() == archive_path_element::pathname) {
00674 if (a_path.size() == 0) {
00675 TRY_nomem(es = "archive-path references path name, ");
00676 TRY_nomem(es += "but path name is empty");
00677 throw(ERROR(0,es));
00678 }
00679 if (path.size() != 0) {
00680 TRY_nomem(path += '/');
00681 }
00682 TRY_nomem(path += a_path);
00683 }
00684 else if (capi->type() == archive_path_element::permutation) {
00685 if (a_path.size() == 0) {
00686 TRY_nomem(es = "archive-path references path name, ");
00687 TRY_nomem(es += "but path name is empty");
00688 throw(ERROR(0,es));
00689 }
00690 if (path.size() != 0) {
00691 TRY_nomem(path += '/');
00692 }
00693 TRY_nomem(path += permute_path(a_path));
00694 }
00695 else if (capi->type() == archive_path_element::literal) {
00696 if (capi->value().size() == 0) {
00697 TRY_nomem(es = "archive-path references literal string, ");
00698 TRY_nomem(es += "but literal string value is empty");
00699 throw(INTERNAL_ERROR(0,es));
00700 }
00701 if (path.size() != 0) {
00702 TRY_nomem(path += '/');
00703 }
00704 TRY_nomem(path += capi->value());
00705 }
00706 else
00707 throw(INTERNAL_ERROR(0,"Unknown archive path element type"));
00708 }
00709
00710
00711 while ((path.size() > 0) && (path[path.size()-1] != '/'))
00712 path.erase(path.size()-1);
00713
00714 path = reform_path(path);
00715
00716 return(path);
00717 }
00718
00719
00720 const std::string job::generate_source_path(const std::string& a_path) const
00721 {
00722 estring path;
00723
00724 if (rsync_connection == connection_server) {
00725 path += "rsync://";
00726 if (rsync_remote_user.size() != 0) {
00727 path += rsync_remote_user;
00728 path += "@";
00729 }
00730 TRY_nomem(path += hostname);
00731 if (rsync_remote_port != 0) {
00732 path += ":";
00733 path += estring(rsync_remote_port);
00734 }
00735 if (rsync_remote_module.size() != 0) {
00736 path += "/";
00737 path += rsync_remote_module;
00738 if ((a_path.size() > 0) && (a_path[0] != '/'))
00739 path += "/";
00740 }
00741 }
00742 else if (rsync_connection == connection_remote) {
00743 if (rsync_remote_user.size() != 0) {
00744 path += rsync_remote_user;
00745 path += "@";
00746 }
00747 path += hostname;
00748 path += ":";
00749 }
00750 path += a_path;
00751
00752 return(path);
00753 }
00754
00755
00756 const std::string job::common_pathname(void) const
00757 {
00758 std::string common_path;
00759 paths_type::size_type pidx;
00760 std::string::size_type sidx;
00761 std::string::size_type max_sidx;
00762 bool same;
00763
00764 TRY_nomem(common_path = "");
00765 sidx = 0;
00766 max_sidx = paths[0].size();
00767 for (pidx = 0; pidx < paths.size(); pidx++) {
00768 if (max_sidx > paths[pidx].size()) {
00769 max_sidx = paths[pidx].size();
00770 }
00771 }
00772 same = true;
00773 for (sidx = 0; sidx < max_sidx; sidx++) {
00774 for (pidx = 0; (same && (pidx < paths.size())); pidx++) {
00775 if (pidx == 0)
00776 continue;
00777 if (paths[pidx-1][sidx] != paths[pidx][sidx])
00778 same = false;
00779 }
00780 if (same)
00781 TRY_nomem(common_path += paths[0][sidx]);
00782 }
00783 if (common_path[0] == '/')
00784 common_path.erase(0,1);
00785 if ((common_path.size() > 0) && (common_path[common_path.size()-1] == '/'))
00786 common_path.erase(common_path.size()-1);
00787
00788 return(common_path);
00789 }
00790
00791
00792 const std::string job::generate_job_id(void) const
00793 {
00794 std::string es;
00795 std::string path;
00796 archive_path::const_iterator capi;
00797
00798 for (capi = archive_path.begin(); capi != archive_path.end(); ++capi) {
00799 if (capi->type() == archive_path_element::jobname) {
00800 if (jobname.size() == 0) {
00801 TRY_nomem(es = "archive-path references jobname, ");
00802 TRY_nomem(es += "but jobname is empty");
00803 throw(ERROR(0,es));
00804 }
00805 if (path.size() != 0) {
00806 TRY_nomem(path += '/');
00807 }
00808 TRY_nomem(path += jobname);
00809 }
00810 else if (capi->type() == archive_path_element::groupname) {
00811 if (groupname.size() == 0) {
00812 TRY_nomem(es = "archive-path references groupname, ");
00813 TRY_nomem(es += "but groupname is empty");
00814 throw(ERROR(0,es));
00815 }
00816 if (path.size() != 0) {
00817 TRY_nomem(path += '/');
00818 }
00819 TRY_nomem(path += groupname);
00820 }
00821 else if (capi->type() == archive_path_element::hostname) {
00822 if (hostname.size() == 0) {
00823 TRY_nomem(es = "archive-path references hostname, ");
00824 TRY_nomem(es += "but hostname is empty");
00825 throw(ERROR(0,es));
00826 }
00827 if (path.size() != 0) {
00828 TRY_nomem(path += '/');
00829 }
00830 TRY_nomem(path += hostname);
00831 }
00832 else if (capi->type() == archive_path_element::pathname) {
00833 if (path.size() == 0) {
00834 TRY_nomem(path += common_pathname());
00835 }
00836 }
00837 else if (capi->type() == archive_path_element::permutation) {
00838 if (path.size() == 0) {
00839 TRY_nomem(path += permute_path(common_pathname()));
00840 }
00841 }
00842 else if (capi->type() == archive_path_element::literal) {
00843 if (capi->value().size() == 0) {
00844 TRY_nomem(es = "archive-path references literal string, ");
00845 TRY_nomem(es += "but literal string value is empty");
00846 throw(INTERNAL_ERROR(0,es));
00847 }
00848 if (path.size() != 0) {
00849 TRY_nomem(path += '/');
00850 }
00851 TRY_nomem(path += capi->value());
00852 }
00853 }
00854
00855 path = reform_path(path);
00856
00857 if (path.size() == 0) {
00858 TRY_nomem(path = jobname);
00859 }
00860 return(path);
00861 }
00862
00863
00864 void job::check(void)
00865 {
00866 std::string es;
00867 std::string this_path;
00868 std::string that_path;
00869 paths_type::const_iterator cpi;
00870 configuration_manager::jobs_type::const_iterator cji;
00871 paths_type::const_iterator cjapi;
00872
00873 if (
00874 (
00875 (rsync_connection == connection_remote)
00876 || (rsync_connection == connection_server)
00877 )
00878 && (hostname.size() == 0)
00879 )
00880 {
00881 TRY_nomem(es = "rsync-connection-type references hostname, ");
00882 TRY_nomem(es += "but hostname is empty");
00883 throw(ERROR(0,es));
00884 }
00885
00886 if ((rsync_remote_module.size() != 0)
00887 && (rsync_connection != connection_server))
00888 {
00889 TRY_nomem(es = "rsync-remote-module specifies a module, but ");
00890 TRY_nomem(es = "rsync-connection-type is not server");
00891 throw(ERROR(0,es));
00892 }
00893
00894 if (paths.size() == 0) {
00895 throw(ERROR(0,"No paths defined for this job"));
00896 }
00897
00898 for (cpi = paths.begin() ; cpi != paths.end(); cpi++) {
00899 TRY_nomem(this_path = generate_archive_path(*cpi));
00900
00901 for (
00902 cji = config.jobs().begin();
00903 cji != config.jobs().end();
00904 cji++
00905 )
00906 {
00907 for (
00908 cjapi = cji->paths.begin();
00909 cjapi != cji->paths.end();
00910 cjapi++
00911 )
00912 {
00913 TRY_nomem(that_path = cji->generate_archive_path(*cjapi));
00914
00915 if (this_path == that_path) {
00916 error e(0);
00917
00918 TRY_nomem(es = "Duplicate archive-path values detected");
00919 e.push_back(ERROR_INSTANCE(es));
00920 TRY_nomem(es = "Archive path: \"");
00921 TRY_nomem(es += this_path);
00922 TRY_nomem(es += "\"");
00923 e.push_back(ERROR_INSTANCE(es));
00924 TRY_nomem(es = "Previously defined at ");
00925 TRY_nomem(es += cji->config_path);
00926 TRY_nomem(es += "[");
00927 TRY_nomem(es += estring(cji->config_line));
00928 TRY_nomem(es += "]");
00929 e.push_back(ERROR_INSTANCE(es));
00930 throw(e);
00931 }
00932
00933 if (
00934 (this_path.size() < that_path.size())
00935 && (this_path == that_path.substr(0,this_path.size()))
00936 && (
00937 (that_path[this_path.size()] == '/')
00938 || (this_path.size() == 0)
00939 )
00940 )
00941 {
00942 error e(0);
00943
00944 TRY_nomem(es = "Overlapping archive-path values detected");
00945 e.push_back(ERROR_INSTANCE(es));
00946 TRY_nomem(es = "Defined archive-path: \"");
00947 TRY_nomem(es += this_path);
00948 TRY_nomem(es += "\"");
00949 e.push_back(ERROR_INSTANCE(es));
00950 TRY_nomem(es = "Is in a parent directory of another job's previously defined archive-path");
00951 e.push_back(ERROR_INSTANCE(es));
00952 TRY_nomem(es = "At ");
00953 TRY_nomem(es += cji->config_path);
00954 TRY_nomem(es += "[");
00955 TRY_nomem(es += estring(cji->config_line));
00956 TRY_nomem(es += "]");
00957 e.push_back(ERROR_INSTANCE(es));
00958 throw(e);
00959 }
00960
00961 if (
00962 (this_path.size() > that_path.size())
00963 && (this_path.substr(0,that_path.size()) == that_path)
00964 && (
00965 (this_path[that_path.size()] == '/')
00966 || (that_path.size() == 0)
00967 )
00968 )
00969 {
00970 error e(0);
00971
00972 TRY_nomem(es = "Overlapping archive-path values detected");
00973 e.push_back(ERROR_INSTANCE(es));
00974 TRY_nomem(es = "Defined archive-path: \"");
00975 TRY_nomem(es += this_path);
00976 TRY_nomem(es += "\"");
00977 e.push_back(ERROR_INSTANCE(es));
00978 TRY_nomem(es = "Is in a subdirectory of another job's previously defined archive-path");
00979 e.push_back(ERROR_INSTANCE(es));
00980 TRY_nomem(es = "At ");
00981 TRY_nomem(es += cji->config_path);
00982 TRY_nomem(es += "[");
00983 TRY_nomem(es += estring(cji->config_line));
00984 TRY_nomem(es += "]");
00985 e.push_back(ERROR_INSTANCE(es));
00986 throw(e);
00987 }
00988 }
00989 }
00990 }
00991 }
00992
00993
00994
00995
00996 void configuration_manager::clear(void)
00997 {
00998 m_initialized = false;
00999 m_configs_read = 0;
01000 m_default = true;
01001 TRY_nomem(m_default_file = CONFIGFILE);
01002 m_action = action_help;
01003 m_timestamp.set();
01004 m_cfgfiles.clear();
01005 m_link_catalog_dir.erase();
01006 TRY_nomem(m_log_dir = LOGDIR);
01007 m_rsync_local_path.erase();
01008 if (strlen(LOCAL_RSYNC) > 0) {
01009 TRY_nomem(m_rsync_local_path = LOCAL_RSYNC);
01010 }
01011 m_rsync_parallel = 1;
01012 m_io_poll_interval = 1;
01013 m_vaults.clear();
01014 m_vault_overflow_behavior = overflow_quit;
01015 m_vault_overflow_blocks = 10;
01016 m_vault_overflow_inodes = 10;
01017 m_vault_selection_behavior = selection_round_robin;
01018 m_vault_locking = true;
01019 m_default_job.clear();
01020 m_logging_level = logging_child;
01021 m_error_logging_level = logging_rsync;
01022 m_jobs.clear();
01023 }
01024
01025
01026 configuration_manager::configuration_manager()
01027 {
01028 if (this != &config)
01029 throw(
01030 INTERNAL_ERROR(0,"Attempt to allocate multiple configuration managers")
01031 );
01032 clear();
01033 }
01034
01035
01036 void configuration_manager::init(int argc, char *argv[])
01037 {
01038 int c;
01039 estring opt;
01040 estring arg;
01041 std::string es;
01042 std::string tes;
01043 cfgfiles_type::const_iterator cfi;
01044 bool use_custom_timestamp = false;
01045 class timestamp custom_timestamp;
01046
01047 for (c = 1; c < argc; c++) {
01048 TRY_nomem(opt = argv[c]);
01049 if (c+1 == argc) {
01050 TRY_nomem(arg = "");
01051 }
01052 else {
01053 TRY_nomem(arg = argv[c+1]);
01054 }
01055
01056 if (opt == "--archive") {
01057 m_action = action_archive;
01058 }
01059 else if (opt == "--relink") {
01060 m_action = action_relink;
01061 }
01062 else if (opt == "--help") {
01063 m_action = action_help;
01064 }
01065 else if (opt == "--version") {
01066 m_action = action_version;
01067 }
01068 else if (opt == "--check-config") {
01069 m_action = action_check_config;
01070 }
01071 else if (opt == "--no-default-config") {
01072 m_default = false;
01073 }
01074 else if (opt == "--config") {
01075 directory dir;
01076 directory::const_iterator cdi;
01077
01078 TRY_nomem(es = "Error finding configuration file(s) ");
01079 TRY_nomem(es += "matching command line argument [");
01080 TRY_nomem(es += estring(c+1));
01081 TRY_nomem(es += "]: \"");
01082 TRY_nomem(es += arg);
01083 TRY_nomem(es += "\"");
01084
01085 try {
01086 dir.path(arg);
01087 }
01088 catch(error e) {
01089 e.push_back(ERROR_INSTANCE(es));
01090 throw(e);
01091 }
01092 catch(...) {
01093 error e = err_unknown;
01094
01095 e.push_back(ERROR_INSTANCE(es));
01096 throw(e);
01097 }
01098 if (dir.size() == 0) {
01099 TRY_nomem(es = "No configuration file(s) found matching ");
01100 TRY_nomem(es += "command line argument [");
01101 TRY_nomem(es += estring(c+1));
01102 TRY_nomem(es += "]: \"");
01103 TRY_nomem(es += arg);
01104 TRY_nomem(es += "\"");
01105
01106 throw(ERROR(0,es));
01107 }
01108 for (cdi = dir.begin(); cdi != dir.end(); cdi++) {
01109 TRY_nomem(m_cfgfiles.push_back(cfgfile_element(config_file, arg)));
01110 }
01111
01112 c++;
01113 }
01114 else if (opt == "--job") {
01115 directory dir;
01116 directory::const_iterator cdi;
01117
01118 TRY_nomem(es = "Error finding job file(s) ");
01119 TRY_nomem(es += "matching command line argument [");
01120 TRY_nomem(es += estring(c+1));
01121 TRY_nomem(es += "]: \"");
01122 TRY_nomem(es += arg);
01123 TRY_nomem(es += "\"");
01124
01125 try {
01126 dir.path(arg);
01127 }
01128 catch(error e) {
01129 e.push_back(ERROR_INSTANCE(es));
01130 throw(e);
01131 }
01132 catch(...) {
01133 error e = err_unknown;
01134 throw(e);
01135 }
01136 if (dir.size() == 0) {
01137 TRY_nomem(es = "No job file(s) found matching ");
01138 TRY_nomem(es += "command line argument [");
01139 TRY_nomem(es += estring(c+1));
01140 TRY_nomem(es += "]: \"");
01141 TRY_nomem(es += arg);
01142 TRY_nomem(es += "\"");
01143
01144 throw(ERROR(0,es));
01145 }
01146 for (cdi = dir.begin(); cdi != dir.end(); cdi++) {
01147 TRY_nomem(m_cfgfiles.push_back(cfgfile_element(job_file, arg)));
01148 }
01149
01150 c++;
01151 }
01152 else if (opt == "--timestamp") {
01153 TRY_nomem(es = "From command line argument ");
01154 TRY_nomem(es += estring(c+1));
01155 TRY(custom_timestamp.assign(arg),es);
01156 use_custom_timestamp = true;
01157 c++;
01158 TRY_nomem(tes = es);
01159 }
01160 else {
01161 TRY_nomem(es = "Unknown command line option: \"");
01162 TRY_nomem(es += opt);
01163 TRY_nomem(es += "\"");
01164 throw(ERROR(0,es));
01165 }
01166 }
01167
01168 m_initialized = true;
01169
01170 if ((m_action == action_help) || (m_action == action_version))
01171 return;
01172
01173 if (use_default())
01174 read_config(m_default_file);
01175
01176 for (cfi = m_cfgfiles.begin(); cfi != m_cfgfiles.end(); cfi++) {
01177 if (cfi->first == config_file) {
01178 read_config(cfi->second);
01179 }
01180 else {
01181 read_job(cfi->second);
01182 }
01183 }
01184
01185 if (m_configs_read == 0) {
01186 throw(ERROR(0,"No configuration file(s) read"));
01187 }
01188
01189 if (use_custom_timestamp) {
01190 TRY(m_timestamp = custom_timestamp,tes);
01191 }
01192
01193 check();
01194 }
01195
01196
01197 void configuration_manager::check(void) const
01198 {
01199 std::string es;
01200 subdirectory subdir;
01201 filestatus fstat;
01202
01203 if (!initialized())
01204 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01205
01206
01207
01208 if (m_log_dir.size() == 0) {
01209 throw(ERROR(0,"log-dir not set"));
01210 }
01211 TRY_nomem(es = "Invalid log-dir value: \"");
01212 TRY_nomem(es += m_log_dir);
01213 TRY_nomem(es += "\"");
01214 TRY_instead(subdir.path(m_log_dir,"*"),es);
01215
01216
01217
01218
01219 TRY_nomem(es = "Invalid rsync-local-path value: \"");
01220 TRY_nomem(es += m_rsync_local_path);
01221 TRY_nomem(es += "\"");
01222 TRY(fstat.path(m_rsync_local_path),es);
01223
01224
01225 if (m_vaults.size() == 0) {
01226 throw(ERROR(0,"No vaults defined"));
01227 }
01228
01229
01230
01231
01232 if (jobs().size() > 0) {
01233 jobs_type::const_iterator cji;
01234
01235 for (cji = jobs().begin(); cji != jobs().end(); cji++) {
01236 if (cji->generate_job_id().size() == 0) {
01237 error e(0);
01238
01239 TRY_nomem(es = "Empty ID generated by job at ");
01240 TRY_nomem(es += cji->config_path);
01241 TRY_nomem(es += "[");
01242 TRY_nomem(es += estring(cji->config_line));
01243 TRY_nomem(es += "]");
01244 e.push_back(es);
01245 TRY_nomem(es =
01246 "Use 'jobname' to assign a descriptive name to this job");
01247 e.push_back(es);
01248 throw(e);
01249 }
01250 }
01251 }
01252 }
01253
01254
01255 const bool configuration_manager::initialized(void) const
01256 {
01257 return(m_initialized);
01258 }
01259
01260
01261 const configuration_manager::action_type
01262 configuration_manager::action(void) const
01263 {
01264 if (!initialized())
01265 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01266
01267 return(m_action);
01268 }
01269
01270
01271 const bool configuration_manager::use_default(void) const
01272 {
01273 if (!initialized())
01274 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01275
01276 return(m_default);
01277 }
01278
01279
01280 void configuration_manager::default_file(const std::string& a_path)
01281 {
01282 TRY_nomem(m_default_file = a_path);
01283 }
01284
01285
01286 const std::string& configuration_manager::default_file(void) const
01287 {
01288 if (!initialized())
01289 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01290
01291 return(m_default_file);
01292 }
01293
01294
01295 void configuration_manager::default_logdir(const std::string& a_path)
01296 {
01297 TRY_nomem(m_log_dir = a_path);
01298 }
01299
01300
01301 const class timestamp& configuration_manager::timestamp(void) const
01302 {
01303 if (!initialized())
01304 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01305
01306 return(m_timestamp);
01307 }
01308
01309
01310 const std::string& configuration_manager::link_catalog_dir(void) const
01311 {
01312 if (!initialized())
01313 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01314
01315 return(m_link_catalog_dir);
01316 }
01317
01318
01319 const std::string& configuration_manager::log_dir(void) const
01320 {
01321 if (!initialized())
01322 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01323
01324 return(m_log_dir);
01325 }
01326
01327
01328 const std::string& configuration_manager::rsync_local_path(void) const
01329 {
01330 if (!initialized())
01331 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01332
01333 return(m_rsync_local_path);
01334 }
01335
01336
01337 const uint16& configuration_manager::rsync_parallel(void) const
01338 {
01339 if (!initialized())
01340 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01341
01342 return(m_rsync_parallel);
01343 }
01344
01345
01346 const uint16& configuration_manager::io_poll_interval(void) const
01347 {
01348 if (!initialized())
01349 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01350
01351 return(m_io_poll_interval);
01352 }
01353
01354
01355 const timestamp::resolution_type configuration_manager::timestamp_resolution(void) const
01356 {
01357 if (!initialized())
01358 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01359
01360 return(m_timestamp.resolution());
01361 }
01362
01363
01364 const configuration_manager::vaults_type& configuration_manager::vaults(void) const
01365 {
01366 if (!initialized())
01367 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01368
01369 return(m_vaults);
01370 }
01371
01372
01373 const configuration_manager::overflow_type& configuration_manager::vault_overflow_behavior(void) const
01374 {
01375 if (!initialized())
01376 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01377
01378 return(m_vault_overflow_behavior);
01379 }
01380
01381
01382 const uint16& configuration_manager::vault_overflow_blocks(void) const
01383 {
01384 if (!initialized())
01385 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01386
01387 return(m_vault_overflow_blocks);
01388 }
01389
01390
01391 const uint16& configuration_manager::vault_overflow_inodes(void) const
01392 {
01393 if (!initialized())
01394 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01395
01396 return(m_vault_overflow_inodes);
01397 }
01398
01399
01400 const configuration_manager::selection_type& configuration_manager::vault_selection_behavior(void) const
01401 {
01402 if (!initialized())
01403 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01404
01405 return(m_vault_selection_behavior);
01406 }
01407
01408
01409 const bool configuration_manager::vault_locking(void) const
01410 {
01411 if (!initialized())
01412 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01413
01414 return(m_vault_locking);
01415 }
01416
01417
01418 const job& configuration_manager::default_job(void) const
01419 {
01420 if (!initialized())
01421 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01422
01423 return(m_default_job);
01424 }
01425
01426
01427 const configuration_manager::jobs_type& configuration_manager::jobs(void) const
01428 {
01429 if (!initialized())
01430 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01431
01432 return(m_jobs);
01433 }
01434
01435
01436 const configuration_manager::logging_type& configuration_manager::logging_level(void) const
01437 {
01438 if (!initialized())
01439 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01440
01441 return(m_logging_level);
01442 }
01443
01444
01445 const configuration_manager::logging_type& configuration_manager::error_logging_level(void) const
01446 {
01447 if (!initialized())
01448 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
01449
01450 return(m_error_logging_level);
01451 }
01452
01453
01454 void configuration_manager::read_config(const std::string& a_path)
01455 {
01456 std::string es;
01457 std::ifstream in;
01458 uint16 line = 0;
01459
01460 in.open(a_path.c_str());
01461 if (!in.is_open()) {
01462 TRY_nomem(es = "Could not open configuration file: \"");
01463 TRY_nomem(es += a_path);
01464 TRY_nomem(es += "\"");
01465 throw(ERROR(errno,es));
01466 }
01467
01468 global_parser(a_path, line, in);
01469
01470 in.close();
01471 m_configs_read++;
01472 }
01473
01474
01475 void configuration_manager::read_job(const std::string& a_path)
01476 {
01477 std::string es;
01478 std::ifstream in;
01479 job njob;
01480 uint16 line = 0;
01481
01482 in.open(a_path.c_str());
01483 if (!in.is_open()) {
01484 TRY_nomem(es = "Could not open job file: \"");
01485 TRY_nomem(es += a_path);
01486 TRY_nomem(es += "\"");
01487 throw(ERROR(errno,es));
01488 }
01489
01490 njob = m_default_job;
01491
01492 job_parser(&njob, a_path, line, in, "", false);
01493
01494 njob.check();
01495
01496 in.close();
01497 }
01498
01499
01500
01501
01502 void parse_line(
01503 std::istream& a_in,
01504 std::string& a_keyword,
01505 std::string& a_value
01506 )
01507 {
01508 std::string es;
01509 char ch;
01510
01511 a_keyword.erase();
01512 a_value.erase();
01513
01514 while (true) {
01515 a_in.get(ch);
01516
01517 while ((a_in) && ((ch == ' ') || (ch == '\t'))) {
01518 a_in.get(ch);
01519 }
01520
01521 while ((a_in) && ((ch != ' ') && (ch != '\t') && (ch != '\n'))) {
01522 TRY_nomem(a_keyword += ch);
01523 a_in.get(ch);
01524 }
01525 if (!a_in)
01526 return;
01527
01528
01529 if (a_keyword.size() == 0)
01530 return;
01531
01532
01533 if (a_keyword[0] == '#') {
01534
01535 while ((a_in) && (ch != '\n')) {
01536 a_in.get(ch);
01537 }
01538 return;
01539 }
01540
01541 a_keyword = estring(a_keyword).lower();
01542
01543
01544 if (ch == '\n')
01545 return;
01546
01547
01548 a_in.get(ch);
01549 while ((a_in) && ((ch == ' ') || (ch == '\t'))) {
01550 a_in.get(ch);
01551 }
01552 if (!a_in)
01553 return;
01554 a_in.putback(ch);
01555 if (!a_in)
01556 return;
01557
01558
01559 a_in.get(ch);
01560 while ((a_in) && (ch != '\n')) {
01561 TRY_nomem(a_value += ch);
01562 a_in.get(ch);
01563 }
01564 return;
01565 }
01566 }
01567
01568
01569 const std::string parse_dirname(const std::string& a_path)
01570 {
01571 std::string rpath;
01572
01573 TRY_nomem(rpath = a_path);
01574
01575 if (rpath.find_last_of('/') != std::string::npos)
01576 rpath.erase(rpath.find_last_of('/'));
01577
01578 if (rpath.size() == 0) {
01579 TRY_nomem(rpath = "./");
01580 return(rpath);
01581 }
01582
01583 if (rpath[rpath.size()-1] != '/') {
01584 TRY_nomem(rpath += '/');
01585 }
01586
01587 return(rpath);
01588 }
01589
01590
01591 const std::string parse_basename(const std::string& a_path)
01592 {
01593 std::string es;
01594 std::string rpath;
01595
01596 TRY_nomem(rpath = a_path);
01597
01598 if (rpath.find_last_of('/') != std::string::npos)
01599 rpath.erase(0,rpath.find_last_of('/'));
01600
01601 return(rpath);
01602 }
01603
01604
01605
01606
01607 global_parser::global_parser(
01608 const std::string& a_path,
01609 uint16& a_line,
01610 std::istream& a_in
01611 )
01612 {
01613 m_in = &a_in;
01614 m_path = &a_path;
01615 m_line = &a_line;
01616
01617 parse();
01618 }
01619
01620
01621
01622 const std::string global_parser::location(void)
01623 {
01624 std::string es;
01625
01626 TRY_nomem(es = "At ");
01627 TRY_nomem(es += (*m_path));
01628 TRY_nomem(es += "[");
01629 TRY_nomem(es += estring((*m_line)));
01630 TRY_nomem(es += "]");
01631
01632 return(es);
01633 }
01634
01635
01636 void global_parser::read_config(const std::string& a_path)
01637 {
01638 std::string es;
01639 std::ifstream in;
01640 uint16 line = 0;
01641
01642 in.open(a_path.c_str());
01643 if (!in.is_open()) {
01644 TRY_nomem(es = "Could not open configuraiton file: \"");
01645 TRY_nomem(es += a_path);
01646 TRY_nomem(es += "\"");
01647 throw(ERROR(errno,es));
01648 }
01649
01650 global_parser(a_path, line, in);
01651
01652 in.close();
01653 config.m_configs_read++;
01654 }
01655
01656
01657 void global_parser::read_job(const std::string& a_path, job& a_job)
01658 {
01659 std::string es;
01660 std::ifstream in;
01661 uint16 line = 0;
01662
01663 in.open(a_path.c_str());
01664 if (!in.is_open()) {
01665 TRY_nomem(es = "Could not open job file: \"");
01666 TRY_nomem(es += a_path);
01667 TRY_nomem(es += "\"");
01668 throw(ERROR(errno,es));
01669 }
01670
01671 job_parser(&a_job, a_path, line, in, "", false);
01672
01673 TRY_nomem(a_job.config_path = *m_path);
01674 TRY_nomem(a_job.config_line = *m_line);
01675 a_job.check();
01676
01677 in.close();
01678 }
01679
01680
01681 void global_parser::parse(void)
01682 {
01683 std::string es;
01684 std::string keyword;
01685 std::string value;
01686
01687 while ((*m_in)) {
01688 (*m_line)++;
01689
01690 try {
01691 parse_line((*m_in), keyword, value);
01692 }
01693 catch(error e) {
01694 e.push_back(ERROR_INSTANCE(location()));
01695 throw(e);
01696 }
01697 catch(...) {
01698 error e = err_unknown;
01699
01700 e.push_back(ERROR_INSTANCE(location()));
01701 throw(e);
01702 }
01703
01704 if (keyword.size() == 0)
01705 continue;
01706 if (keyword[0] == '#')
01707 continue;
01708
01709 try {
01710 if (keyword == "<default>") {
01711 parse_default(value);
01712 }
01713 else if (keyword == "include") {
01714 parse_include(value);
01715 }
01716 else if (keyword == "include-job") {
01717 parse_include_job(value);
01718 }
01719 else if (keyword == "<job>") {
01720 parse_job(value);
01721 }
01722 else if (keyword == "link-catalog-dir") {
01723 parse_link_catalog_dir(value);
01724 }
01725 else if (keyword == "log-dir") {
01726 parse_log_dir(value);
01727 }
01728 else if (keyword == "logging-level") {
01729 parse_logging_level(value);
01730 }
01731 else if (keyword == "error-logging-level") {
01732 parse_error_logging_level(value);
01733 }
01734 else if (keyword == "rsync-local-path") {
01735 parse_rsync_local_path(value);
01736 }
01737 else if (keyword == "rsync-parallel") {
01738 parse_rsync_parallel(value);
01739 }
01740 else if (keyword == "io-poll-interval") {
01741 parse_io_poll_interval(value);
01742 }
01743 else if (keyword == "timestamp-resolution") {
01744 parse_timestamp_resolution(value);
01745 }
01746 else if (keyword == "vault") {
01747 try {
01748 parse_vault(value);
01749 }
01750 catch(error e) {
01751 std::cerr << e;
01752 }
01753 catch(...) {
01754 throw(err_unknown);
01755 }
01756 }
01757 else if (keyword == "vault-overflow-behavior") {
01758 parse_vault_overflow_behavior(value);
01759 }
01760 else if (keyword == "vault-overflow-blocks") {
01761 parse_vault_overflow_blocks(value);
01762 }
01763 else if (keyword == "vault-overflow-inodes") {
01764 parse_vault_overflow_inodes(value);
01765 }
01766 else if (keyword == "vault-selection-behavior") {
01767 parse_vault_selection_behavior(value);
01768 }
01769 else if (keyword == "vault-locking") {
01770 parse_vault_locking(value);
01771 }
01772 else {
01773 error e(0);
01774
01775 TRY_nomem(es = "Unknown command in global context: \"");
01776 TRY_nomem(es += keyword);
01777 TRY_nomem(es += "\"");
01778 throw(ERROR(0,es));
01779 }
01780 }
01781 catch(error e) {
01782 e.push_back(ERROR_INSTANCE(location()));
01783 throw(e);
01784 }
01785 catch(...) {
01786 error e = err_unknown;
01787
01788 e.push_back(ERROR_INSTANCE(location()));
01789 throw(e);
01790 }
01791 }
01792 }
01793
01794
01795 void global_parser::parse_default(const std::string& a_value)
01796 {
01797 std::string delimiter;
01798 std::string default_config_path;
01799 uint16 default_config_line;
01800 job* jobPtr = &config.m_default_job;
01801
01802 config.m_default_job.clear();
01803
01804 TRY_nomem(default_config_path = *m_path);
01805 TRY_nomem(default_config_line = *m_line);
01806 TRY_nomem(delimiter = "</default>");
01807
01808 job_parser(jobPtr, *m_path, *m_line, *m_in, delimiter, true);
01809
01810 TRY_nomem(jobPtr->default_config_path = default_config_path);
01811 jobPtr->default_config_line = default_config_line;
01812 }
01813
01814
01815 void global_parser::parse_include(const std::string& a_value)
01816 {
01817 std::string es;
01818 directory dir;
01819 directory::const_iterator cdi;
01820 std::string rpath;
01821 std::string ipath;
01822
01823 if (a_value.size() == 0) {
01824 TRY_nomem(es = "Invalid include path: \"");
01825 TRY_nomem(es += a_value);
01826 TRY_nomem(es += "\"");
01827 throw(ERROR(0,es));
01828 }
01829
01830 if (a_value[0] != '/') {
01831 TRY_nomem(rpath = parse_dirname(*m_path));
01832 }
01833
01834 TRY_nomem(ipath = rpath + a_value);
01835
01836 TRY_nomem(es = "No configuration file(s) found: \"");
01837 TRY_nomem(es += a_value);
01838 TRY_nomem(es += "\"");
01839 TRY_instead(dir.path(ipath),es);
01840 if (dir.size() == 0)
01841 throw(ERROR(0,es));
01842
01843 for (cdi = dir.begin(); cdi != dir.end(); cdi++) {
01844 if (dir.size() > 1) {
01845 TRY_nomem(es = "For files found matching: \"");
01846 TRY_nomem(es += a_value);
01847 TRY_nomem(es += "\"");
01848 try {
01849 read_config(*cdi);
01850 }
01851 catch(error e) {
01852 e.push_back(ERROR_INSTANCE(es));
01853 throw(e);
01854 }
01855 catch(...) {
01856 error e = err_unknown;
01857
01858 e.push_back(ERROR_INSTANCE(es));
01859 throw(e);
01860 }
01861 }
01862 else
01863 read_config(*cdi);
01864 }
01865 }
01866
01867
01868 void global_parser::parse_include_job(const std::string& a_value)
01869 {
01870 std::string es;
01871 directory dir;
01872 directory::const_iterator cdi;
01873 std::string rpath;
01874 std::string ipath;
01875
01876 if (a_value.size() == 0) {
01877 TRY_nomem(es = "Invalid include-job path: \"");
01878 TRY_nomem(es += a_value);
01879 TRY_nomem(es += "\"");
01880 throw(ERROR(0,es));
01881 }
01882
01883 if (a_value[0] != '/') {
01884 TRY_nomem(rpath = parse_dirname(*m_path));
01885 }
01886
01887 TRY_nomem(ipath = rpath + a_value);
01888
01889 TRY_nomem(es = "No job file(s) found: \"");
01890 TRY_nomem(es += a_value);
01891 TRY_nomem(es += "\"");
01892 TRY(dir.path(ipath),es);
01893 if (dir.size() == 0)
01894 throw(ERROR(0,es));
01895
01896 for (cdi = dir.begin(); cdi != dir.end(); cdi++) {
01897 job new_job;
01898
01899 new_job = config.m_default_job;
01900
01901 if (dir.size() > 1) {
01902 TRY_nomem(es = "For files found matching: \"");
01903 TRY_nomem(es += a_value);
01904 TRY_nomem(es += "\"");
01905 try {
01906 read_job(*cdi, new_job);
01907 }
01908 catch(error e) {
01909 e.push_back(ERROR_INSTANCE(es));
01910 throw(e);
01911 }
01912 catch(...) {
01913 error e = err_unknown;
01914
01915 e.push_back(ERROR_INSTANCE(es));
01916 throw(e);
01917 }
01918 }
01919 else
01920 read_job(*cdi, new_job);
01921 TRY_nomem(config.m_jobs.push_back(new_job));
01922 }
01923 }
01924
01925
01926 void global_parser::parse_job(const std::string& a_value)
01927 {
01928 std::string delimiter;
01929 std::string config_path;
01930 uint16 config_line;
01931 job new_job;
01932
01933 TRY_nomem(config_path = *m_path);
01934 config_line = *m_line;
01935 new_job = config.m_default_job;
01936
01937 TRY_nomem(new_job.config_path = config_path);
01938 new_job.config_line = config_line;
01939 TRY_nomem(delimiter = "</job>");
01940
01941 job_parser(&new_job, *m_path, *m_line, *m_in, delimiter, false);
01942
01943 new_job.check();
01944
01945 TRY_nomem(config.m_jobs.push_back(new_job));
01946 }
01947
01948
01949 void global_parser::parse_link_catalog_dir(const std::string& a_value)
01950 {
01951 std::string es;
01952 subdirectory subdir;
01953
01954 TRY_nomem(es = "Invalid link-catalog-dir path: \"");
01955 TRY_nomem(es += a_value);
01956 TRY_nomem(es += "\"");
01957 TRY_instead(subdir.path(a_value,"*"),es);
01958 TRY_nomem(config.m_link_catalog_dir = a_value);
01959 }
01960
01961
01962 void global_parser::parse_log_dir(const std::string& a_value)
01963 {
01964 std::string es;
01965 subdirectory subdir;
01966
01967 TRY_nomem(es = "Invalid log-dir path: \"");
01968 TRY_nomem(es += a_value);
01969 TRY_nomem(es += "\"");
01970 TRY_instead(subdir.path(a_value,"*"),es);
01971 TRY_nomem(config.m_log_dir = a_value);
01972 }
01973
01974
01975 void global_parser::parse_logging_level(const std::string& a_value)
01976 {
01977 std::string es;
01978 estring str;
01979
01980 TRY_nomem(es = "Invalid logging-level value: \"");
01981 TRY_nomem(es += a_value);
01982 TRY_nomem(es += "\"");
01983 TRY_nomem(str = estring(a_value).lower());
01984 if (str == "manager") {
01985 config.m_logging_level = configuration_manager::logging_manager;
01986 }
01987 else if (str == "child") {
01988 config.m_logging_level = configuration_manager::logging_child;
01989 }
01990 else if (str == "rsync") {
01991 config.m_logging_level = configuration_manager::logging_rsync;
01992 }
01993 else {
01994 throw(ERROR(0,es));
01995 }
01996 }
01997
01998
01999 void global_parser::parse_error_logging_level(const std::string& a_value)
02000 {
02001 std::string es;
02002 estring str;
02003
02004 TRY_nomem(es = "Invalid error-logging-level value: \"");
02005 TRY_nomem(es += a_value);
02006 TRY_nomem(es += "\"");
02007 TRY_nomem(str = estring(a_value).lower());
02008 if (str == "manager") {
02009 config.m_error_logging_level = configuration_manager::logging_manager;
02010 }
02011 else if (str == "child") {
02012 config.m_error_logging_level = configuration_manager::logging_child;
02013 }
02014 else if (str == "rsync") {
02015 config.m_error_logging_level = configuration_manager::logging_rsync;
02016 }
02017 else {
02018 throw(ERROR(0,es));
02019 }
02020 }
02021
02022
02023 void global_parser::parse_rsync_local_path(const std::string& a_value)
02024 {
02025 std::string es;
02026 filestatus fstat;
02027
02028 TRY_nomem(es = "Invalid rsync-local-path value: \"");
02029 TRY_nomem(es += a_value);
02030 TRY_nomem(es += "\"");
02031 TRY_instead(fstat.path(a_value),es);
02032 TRY_nomem(config.m_rsync_local_path = a_value);
02033 }
02034
02035
02036 void global_parser::parse_rsync_parallel(const std::string& a_value)
02037 {
02038 std::string es;
02039 uint16 num;
02040
02041 TRY_nomem(es = "Invalid rsync-parallel value: \"");
02042 TRY_nomem(es += a_value);
02043 TRY_nomem(es += "\"");
02044 TRY_instead(num = estring(a_value),es);
02045 if (num == 0)
02046 throw(ERROR(0,es));
02047 config.m_rsync_parallel = num;
02048 }
02049
02050
02051 void global_parser::parse_io_poll_interval(const std::string& a_value)
02052 {
02053 std::string es;
02054 uint16 num;
02055
02056 TRY_nomem(es = "Invalid io-poll-interval value: \"");
02057 TRY_nomem(es += a_value);
02058 TRY_nomem(es += "\"");
02059 TRY_instead(num = estring(a_value),es);
02060 if (num == 0)
02061 throw(ERROR(0,es));
02062 config.m_io_poll_interval = num;
02063 }
02064
02065
02066 void global_parser::parse_timestamp_resolution(const std::string& a_value)
02067 {
02068 std::string es;
02069 estring str;
02070
02071 TRY_nomem(es = "Invalid timestamp-resolution: \"");
02072 TRY_nomem(es += a_value);
02073 TRY_nomem(es += "\"");
02074 TRY(str = estring(a_value).lower(),es);
02075 if (str == "year") {
02076 config.m_timestamp.resolution(timestamp::resolution_year);
02077 }
02078 else if (str == "month") {
02079 config.m_timestamp.resolution(timestamp::resolution_month);
02080 }
02081 else if (str == "day") {
02082 config.m_timestamp.resolution(timestamp::resolution_day);
02083 }
02084 else if (str == "hour") {
02085 config.m_timestamp.resolution(timestamp::resolution_hour);
02086 }
02087 else if (str == "minute") {
02088 config.m_timestamp.resolution(timestamp::resolution_minute);
02089 }
02090 else if (str == "second") {
02091 config.m_timestamp.resolution(timestamp::resolution_second);
02092 }
02093 else {
02094 throw(ERROR(0,es));
02095 }
02096 }
02097
02098
02099 void global_parser::parse_vault(const std::string& a_value)
02100 {
02101 std::string es;
02102 directory dir;
02103 directory::const_iterator cdi;
02104 subdirectory subdir;
02105 filestatus fstat;
02106 error partial_vault_error = ERROR(0,"One or more vault paths were found to be invalid:");
02107
02108 TRY_nomem(es = "Invalid vault path: \"");
02109 TRY_nomem(es += a_value);
02110 TRY_nomem(es += "\"");
02111
02112 if (a_value.size() == 0)
02113 throw(ERROR(0,es));
02114
02115 TRY(dir.path(a_value),es);
02116
02117 if (dir.size() == 0) {
02118 TRY_instead(fstat.path(a_value),es);
02119 }
02120
02121 for (cdi = dir.begin(); cdi != dir.end(); cdi++) {
02122 if (!is_dir(*cdi)) {
02123 TRY_nomem(es = get_error_str(ENOTDIR));
02124 TRY_nomem(es += ": \"");
02125 TRY_nomem(es += *cdi);
02126 TRY_nomem(es += "\"");
02127 partial_vault_error.push_back(es);
02128 continue;
02129 }
02130 if (!readable(*cdi)) {
02131 TRY_nomem(es = "No read access to path: \"");
02132 TRY_nomem(es += *cdi);
02133 TRY_nomem(es += "\"");
02134 partial_vault_error.push_back(es);
02135 continue;
02136 }
02137 if (!writable(*cdi)) {
02138 TRY_nomem(es = "No write access to path: \"");
02139 TRY_nomem(es += *cdi);
02140 TRY_nomem(es += "\"");
02141 partial_vault_error.push_back(es);
02142 continue;
02143 }
02144 if (!executable(*cdi)) {
02145 TRY_nomem(es = "No execution access to path: \"");
02146 TRY_nomem(es += *cdi);
02147 TRY_nomem(es += "\"");
02148 partial_vault_error.push_back(es);
02149 continue;
02150 }
02151 TRY_nomem(config.m_vaults.push_back(*cdi));
02152 }
02153
02154 if (partial_vault_error.size() > 1) {
02155 TRY_nomem(es = "For paths found matching: \"");
02156 TRY_nomem(es += a_value);
02157 TRY_nomem(es += "\"");
02158 partial_vault_error.push_back(es);
02159 throw(partial_vault_error);
02160 }
02161 }
02162
02163
02164 void global_parser::parse_vault_overflow_behavior(const std::string& a_value)
02165 {
02166 std::string es;
02167 estring str;
02168
02169 TRY_nomem(es = "Invalid vault-overflow-behavior value: \"");
02170 TRY_nomem(es += a_value);
02171 TRY_nomem(es += "\"");
02172 TRY(str = estring(a_value).lower(),es);
02173 if (str == "quit") {
02174 config.m_vault_overflow_behavior = configuration_manager::overflow_quit;
02175 }
02176 else if (str == "delete-oldest") {
02177 config.m_vault_overflow_behavior = configuration_manager::overflow_delete_oldest;
02178 }
02179 else if (str == "delete-until-free") {
02180 config.m_vault_overflow_behavior = configuration_manager::overflow_delete_until_free;
02181 }
02182 else {
02183 throw(ERROR(0,es));
02184 }
02185 }
02186
02187
02188 void global_parser::parse_vault_overflow_blocks(const std::string& a_value)
02189 {
02190 std::string es;
02191 uint16 num;
02192
02193 TRY_nomem(es = "Invalid vault-overflow-blocks value: \"");
02194 TRY_nomem(es += a_value);
02195 TRY_nomem(es += "\"");
02196 TRY(num = estring(a_value),es);
02197 if (num > 50)
02198 throw(ERROR(0,es));
02199 config.m_vault_overflow_blocks = num;
02200 }
02201
02202
02203 void global_parser::parse_vault_overflow_inodes(const std::string& a_value)
02204 {
02205 std::string es;
02206 uint16 num;
02207
02208 TRY_nomem(es = "Invalid vault-overflow-inodes value: \"");
02209 TRY_nomem(es += a_value);
02210 TRY_nomem(es += "\"");
02211 TRY(num = estring(a_value),es);
02212 if (num > 50)
02213 throw(ERROR(0,es));
02214 config.m_vault_overflow_inodes = num;
02215 }
02216
02217
02218 void global_parser::parse_vault_selection_behavior(const std::string& a_value)
02219 {
02220 std::string es;
02221 estring str;
02222
02223 TRY_nomem(es = "Invalid vault-selection-behavior value: \"");
02224 TRY_nomem(es += a_value);
02225 TRY_nomem(es += "\"");
02226 TRY(str = estring(a_value).lower(),es);
02227 if (str == "max-free") {
02228 config.m_vault_selection_behavior = configuration_manager::selection_max_free;
02229 }
02230 else if (str == "round-robin") {
02231 config.m_vault_selection_behavior = configuration_manager::selection_round_robin;
02232 }
02233 else {
02234 throw(ERROR(0,es));
02235 }
02236 }
02237
02238
02239 void global_parser::parse_vault_locking(const std::string& a_value)
02240 {
02241 std::string es;
02242 estring str;
02243
02244 TRY_nomem(es = "Invalid vault-locking value: \"");
02245 TRY_nomem(es += a_value);
02246 TRY_nomem(es += "\"");
02247 TRY(str = estring(a_value).lower(),es);
02248 if (
02249 (str == "y")
02250 || (str == "yes")
02251 || (str == "t")
02252 || (str == "true")
02253 || (str == "1")
02254 || (str == "on")
02255 ) {
02256 config.m_vault_locking = true;
02257 }
02258 else if (
02259 (str == "n")
02260 || (str == "no")
02261 || (str == "f")
02262 || (str == "false")
02263 || (str == "0")
02264 || (str == "off")
02265 ) {
02266 config.m_vault_locking = false;
02267 }
02268 else {
02269 throw(ERROR(0,es));
02270 }
02271 }
02272
02273
02274
02275
02276 job_parser::job_parser(
02277 job * a_job,
02278 const std::string& a_path,
02279 uint16& a_line,
02280 std::istream& a_in,
02281 const std::string& a_block_delimiter,
02282 const bool a_default_context = false
02283 )
02284 {
02285 m_job = a_job;
02286 m_in = &a_in;
02287 m_path = &a_path;
02288 m_line = &a_line;
02289 m_delimiter = &a_block_delimiter;
02290 m_default_context = a_default_context;
02291
02292 parse();
02293 }
02294
02295
02296
02297 const std::string job_parser::location(void)
02298 {
02299 std::string es;
02300
02301 TRY_nomem(es = "At ");
02302 TRY_nomem(es += (*m_path));
02303 TRY_nomem(es += "[");
02304 TRY_nomem(es += estring((*m_line)));
02305 TRY_nomem(es += "]");
02306
02307 return(es);
02308 }
02309
02310
02311 void job_parser::read_job(const std::string& a_path)
02312 {
02313 std::string es;
02314 std::ifstream in;
02315 uint16 line = 0;
02316
02317 in.open(a_path.c_str());
02318 if (!in.is_open()) {
02319 TRY_nomem(es = "Could not open job file: \"");
02320 TRY_nomem(es += a_path);
02321 TRY_nomem(es += "\"");
02322 throw(ERROR(errno,es));
02323 }
02324
02325 job_parser(m_job, a_path, line, in, "", m_default_context);
02326
02327 in.close();
02328 }
02329
02330
02331 void job_parser::parse(void)
02332 {
02333 std::string es;
02334 std::string keyword;
02335 std::string value;
02336
02337 while ((*m_in)) {
02338 (*m_line)++;
02339
02340 try {
02341 parse_line((*m_in), keyword, value);
02342 }
02343 catch(error e) {
02344 e.push_back(ERROR_INSTANCE(location()));
02345 throw(e);
02346 }
02347 catch(...) {
02348 error e = err_unknown;
02349
02350 e.push_back(ERROR_INSTANCE(location()));
02351 throw(e);
02352 }
02353
02354 if (!(*m_in) && (m_delimiter->size() != 0)) {
02355 TRY_nomem(es = "Unexpected end of file, expected \"");
02356 TRY_nomem(es += *m_delimiter);
02357 TRY_nomem(es += "\" here");
02358 throw(ERROR(errno,es));
02359 }
02360
02361 if (keyword.size() == 0)
02362 continue;
02363 if (keyword[0] == '#')
02364 continue;
02365
02366 try {
02367 if (keyword == *m_delimiter) {
02368 return;
02369 }
02370 else if (keyword == "archive-path") {
02371 parse_archive_path(value);
02372 }
02373 else if (keyword == "clear") {
02374 parse_clear(value);
02375 }
02376 else if (keyword == "exclude-from") {
02377 parse_exclude_from(value);
02378 }
02379 else if (keyword == "include-from") {
02380 parse_include_from(value);
02381 }
02382 else if (keyword == "groupname") {
02383 parse_groupname(value);
02384 }
02385 else if (keyword == "hostname") {
02386 parse_hostname(value);
02387 }
02388 else if (keyword == "include") {
02389 parse_include(value);
02390 }
02391 else if ((keyword == "jobname") && (*m_delimiter == "</job>")) {
02392 parse_jobname(value);
02393 }
02394 else if (keyword == "path") {
02395 parse_path(value);
02396 }
02397 else if (keyword == "rsync-behavior") {
02398 parse_rsync_behavior(value);
02399 }
02400 else if (keyword == "rsync-connection-type") {
02401 parse_rsync_connection_type(value);
02402 }
02403 else if (keyword == "rsync-hardlink") {
02404 parse_rsync_hardlink(value);
02405 }
02406 else if (keyword == "rsync-options") {
02407 parse_rsync_options(value);
02408 }
02409 else if (keyword == "<rsync-options>") {
02410 parse_rsync_options_context(value);
02411 }
02412 else if (keyword == "rsync-remote-user") {
02413 parse_rsync_remote_user(value);
02414 }
02415 else if (keyword == "rsync-remote-path") {
02416 parse_rsync_remote_path(value);
02417 }
02418 else if (keyword == "rsync-remote-port") {
02419 parse_rsync_remote_port(value);
02420 }
02421 else if (keyword == "rsync-remote-module") {
02422 parse_rsync_remote_module(value);
02423 }
02424 else if (keyword == "rsync-retry-count") {
02425 parse_rsync_retry_count(value);
02426 }
02427 else if (keyword == "rsync-timeout") {
02428 parse_rsync_timeout(value);
02429 }
02430 else {
02431 error e(0);
02432
02433 TRY_nomem(es = "Unknown command in ");
02434 if (m_default_context) {
02435 TRY_nomem(es += "default");
02436 }
02437 else {
02438 TRY_nomem(es += "job");
02439 }
02440 TRY_nomem(es += " context: \"");
02441 TRY_nomem(es += keyword);
02442 TRY_nomem(es += "\"");
02443 throw(ERROR(0,es));
02444 }
02445 }
02446 catch(error e) {
02447 if ((*m_delimiter).size() == 0)
02448 e.push_back(ERROR_INSTANCE(location()));
02449 throw(e);
02450 }
02451 catch(...) {
02452 error e = err_unknown;
02453
02454 e.push_back(ERROR_INSTANCE(location()));
02455 throw(e);
02456 }
02457 }
02458 }
02459
02460
02461 void job_parser::parse_archive_path(const std::string& a_value)
02462 {
02463 std::string es;
02464
02465 TRY_nomem(es = "Invalid archive-path value");
02466 TRY((*m_job).archive_path = a_value,es);
02467 }
02468
02469
02470 void job_parser::parse_clear(const std::string& a_value)
02471 {
02472 std::string es;
02473 estring str;
02474
02475 TRY_nomem(es = "Invalid clear value: \"");
02476 TRY_nomem(es += a_value);
02477 TRY_nomem(es += "\"");
02478 TRY(str = estring(a_value).lower(),es);
02479 if (str == "archive-path") {
02480 m_job->archive_path.clear();
02481 }
02482 else if (str == "exclude-from") {
02483 m_job->excludes.clear();
02484 }
02485 else if (str == "groupname") {
02486 m_job->groupname.erase();
02487 }
02488 else if (str == "hostname") {
02489 m_job->hostname.erase();
02490 }
02491 else if (str == "include-from") {
02492 m_job->includes.clear();
02493 }
02494 else if ((str == "jobname") && (*m_delimiter == "</job>")) {
02495 m_job->jobname.erase();
02496 }
02497 else if (str == "paths") {
02498 m_job->paths.clear();
02499 }
02500 else if (str == "rsync-behavior") {
02501 m_job->rsync_behavior.clear();
02502 }
02503 else if (str == "rsync-options") {
02504 m_job->rsync_options.erase();
02505 }
02506 else if (str == "rsync-remote-user") {
02507 m_job->rsync_remote_user.erase();
02508 }
02509 else if (str == "rsync-remotr-port") {
02510 m_job->rsync_remote_port = 0;
02511 }
02512 else if (str == "rsync-remote-module") {
02513 m_job->rsync_remote_module.erase();
02514 }
02515 else if (str == "rsync-remote-path") {
02516 m_job->rsync_remote_path.erase();
02517 }
02518 else {
02519 throw(ERROR(0,es));
02520 }
02521 }
02522
02523
02524 void job_parser::parse_exclude_from(const std::string& a_value)
02525 {
02526 std::string es;
02527 directory dir;
02528 directory::const_iterator cdi;
02529 std::string rpath;
02530 std::string ipath;
02531
02532 if (a_value.size() == 0) {
02533 TRY_nomem(es = "Invalid exclude-from path: \"");
02534 TRY_nomem(es += a_value);
02535 TRY_nomem(es += "\"");
02536 throw(ERROR(0,es));
02537 }
02538
02539 if (a_value[0] != '/') {
02540 TRY_nomem(rpath = parse_dirname(*m_path));
02541 }
02542
02543 TRY_nomem(ipath = rpath + a_value);
02544
02545 TRY_nomem(es = "No exclude-from file(s) found: \"");
02546 TRY_nomem(es += a_value);
02547 TRY_nomem(es += "\"");
02548 TRY(dir.path(ipath),es);
02549 if (dir.size() == 0)
02550 throw(ERROR(0,es));
02551
02552 for (cdi = dir.begin(); cdi != dir.end(); cdi++) {
02553 TRY_nomem((*m_job).excludes.push_back(*cdi));
02554 }
02555 }
02556
02557
02558 void job_parser::parse_include_from(const std::string& a_value)
02559 {
02560 std::string es;
02561 directory dir;
02562 directory::const_iterator cdi;
02563 std::string rpath;
02564 std::string ipath;
02565
02566 if (a_value.size() == 0) {
02567 TRY_nomem(es = "Invalid include-from path: \"");
02568 TRY_nomem(es += a_value);
02569 TRY_nomem(es += "\"");
02570 throw(ERROR(0,es));
02571 }
02572
02573 if (a_value[0] != '/') {
02574 TRY_nomem(rpath = parse_dirname(*m_path));
02575 }
02576
02577 TRY_nomem(ipath = rpath + a_value);
02578
02579 TRY_nomem(es = "No include-from file(s) found: \"");
02580 TRY_nomem(es += a_value);
02581 TRY_nomem(es += "\"");
02582 TRY(dir.path(ipath),es);
02583 if (dir.size() == 0)
02584 throw(ERROR(0,es));
02585
02586 for (cdi = dir.begin(); cdi != dir.end(); cdi++) {
02587 TRY_nomem((*m_job).includes.push_back(*cdi));
02588 }
02589 }
02590
02591
02592 void job_parser::parse_groupname(const std::string& a_value)
02593 {
02594 TRY_nomem((*m_job).groupname = a_value);
02595 }
02596
02597
02598 void job_parser::parse_hostname(const std::string& a_value)
02599 {
02600 TRY_nomem((*m_job).hostname = a_value);
02601 }
02602
02603
02604 void job_parser::parse_include(const std::string& a_value)
02605 {
02606 std::string es;
02607 directory dir;
02608 directory::const_iterator cdi;
02609 std::string rpath;
02610 std::string ipath;
02611
02612 if (a_value.size() == 0) {
02613 TRY_nomem(es = "Invalid include path: \"");
02614 TRY_nomem(es += a_value);
02615 TRY_nomem(es += "\"");
02616 throw(ERROR(0,es));
02617 }
02618
02619 if (a_value[0] != '/') {
02620 TRY_nomem(rpath = parse_dirname(*m_path));
02621 }
02622
02623 TRY_nomem(ipath = rpath + a_value);
02624
02625 TRY_nomem(es = "No configuration file(s) found: \"");
02626 TRY_nomem(es += a_value);
02627 TRY_nomem(es += "\"");
02628 TRY_instead(dir.path(ipath),es);
02629 if (dir.size() == 0)
02630 throw(ERROR(0,es));
02631
02632 for (cdi = dir.begin(); cdi != dir.end(); cdi++) {
02633 if (dir.size() > 1) {
02634 TRY_nomem(es = "For files found matching: \"");
02635 TRY_nomem(es += a_value);
02636 TRY_nomem(es += "\"");
02637 try {
02638 read_job(*cdi);
02639 }
02640 catch(error e) {
02641 e.push_back(ERROR_INSTANCE(es));
02642 throw(e);
02643 }
02644 catch(...) {
02645 error e = err_unknown;
02646
02647 e.push_back(ERROR_INSTANCE(es));
02648 throw(e);
02649 }
02650 }
02651 else
02652 read_job(*cdi);
02653 }
02654 }
02655
02656
02657 void job_parser::parse_jobname(const std::string& a_value)
02658 {
02659 TRY_nomem((*m_job).jobname = a_value);
02660 }
02661
02662
02663 void job_parser::parse_path(const std::string& a_value)
02664 {
02665 TRY_nomem((*m_job).paths.push_back(a_value));
02666 }
02667
02668
02669 void job_parser::parse_rsync_behavior(const std::string& a_value)
02670 {
02671 std::string es;
02672 estring str;
02673
02674 TRY_nomem(es = "Invalid rsync-behavior value: \"");
02675 TRY_nomem(es += a_value);
02676 TRY_nomem(es += "\"");
02677 TRY(str = estring(a_value).lower(),es);
02678 if (str == "clear") {
02679 (*m_job).rsync_behavior.clear();
02680 }
02681 else if (str == "reset") {
02682 (*m_job).rsync_behavior.reset();
02683 }
02684 else
02685 (*m_job).rsync_behavior.assign(a_value);
02686 }
02687
02688
02689 void job_parser::parse_rsync_connection_type(const std::string& a_value)
02690 {
02691 std::string es;
02692 estring str;
02693
02694 TRY_nomem(es = "Invalid rsync-connection-type value: \"");
02695 TRY_nomem(es += a_value);
02696 TRY_nomem(es += "\"");
02697 TRY(str = estring(a_value).lower(),es);
02698 if (str == "local") {
02699 (*m_job).rsync_connection = job::connection_local;
02700 }
02701 else if (str == "remote") {
02702 (*m_job).rsync_connection = job::connection_remote;
02703 }
02704 else if (str == "server") {
02705 (*m_job).rsync_connection = job::connection_server;
02706 }
02707 else {
02708 throw(ERROR(0,es));
02709 }
02710 }
02711
02712
02713 void job_parser::parse_rsync_hardlink(const std::string& a_value)
02714 {
02715 std::string es;
02716 estring str;
02717
02718 TRY_nomem(es = "Invalid rsync-hardlink value: \"");
02719 TRY_nomem(es += a_value);
02720 TRY_nomem(es += "\"");
02721 TRY(str = estring(a_value).lower(),es);
02722 if (
02723 (str == "y")
02724 || (str == "yes")
02725 || (str == "t")
02726 || (str == "true")
02727 || (str == "1")
02728 || (str == "on")
02729 ) {
02730 (*m_job).rsync_hardlink = true;
02731 }
02732 else if (
02733 (str == "n")
02734 || (str == "no")
02735 || (str == "f")
02736 || (str == "false")
02737 || (str == "0")
02738 || (str == "off")
02739 ) {
02740 (*m_job).rsync_hardlink = false;
02741 }
02742 else {
02743 throw(ERROR(0,es));
02744 }
02745 }
02746
02747
02748 void job_parser::parse_rsync_options(const std::string& a_value)
02749 {
02750 if (*m_delimiter == "</default>") {
02751 TRY_nomem((*m_job).rsync_options = a_value);
02752 }
02753 else {
02754 if ((*m_job).rsync_options.size() != 0) {
02755 TRY_nomem((*m_job).rsync_options += " ");
02756 }
02757 TRY_nomem((*m_job).rsync_options += a_value);
02758 }
02759 }
02760
02761
02762 void job_parser::parse_rsync_options_context(const std::string& a_value)
02763 {
02764 std::string es;
02765 std::string value;
02766 std::string rsync_options;
02767 char ch;
02768
02769 while ((*m_in)) {
02770 (*m_line)++;
02771
02772 value.erase();
02773
02774 (*m_in).get(ch);
02775 while ((ch == ' ') || (ch == '\t'))
02776 (*m_in).get(ch);
02777 while (((*m_in)) && (ch != '\n')) {
02778 TRY_nomem(value += ch);
02779 (*m_in).get(ch);
02780 }
02781
02782 if ((!(*m_in)) && (value != "</rsync-options>")) {
02783 TRY_nomem(es = "Unexpected end of file, expected ");
02784 TRY_nomem(es += "\"</rsync-options>\" here");
02785 throw(ERROR(errno,es));
02786 }
02787
02788 if (value.size() == 0)
02789 continue;
02790 if (value[0] == '#')
02791 continue;
02792
02793 if (value == "</rsync-options>") {
02794 parse_rsync_options(rsync_options);
02795 return;
02796 }
02797
02798 if (rsync_options.size() != 0) {
02799 TRY_nomem(rsync_options += ' ');
02800 }
02801 TRY_nomem(rsync_options += value);
02802 }
02803 }
02804
02805
02806 void job_parser::parse_rsync_remote_user(const std::string& a_value)
02807 {
02808 TRY_nomem((*m_job).rsync_remote_user = a_value);
02809 }
02810
02811
02812 void job_parser::parse_rsync_remote_path(const std::string& a_value)
02813 {
02814 TRY_nomem((*m_job).rsync_remote_path = a_value);
02815 }
02816
02817
02818 void job_parser::parse_rsync_remote_port(const std::string& a_value)
02819 {
02820 std::string es;
02821 estring str;
02822 uint16 num;
02823
02824 TRY_nomem(es = "Invalid rsync-remote-port value: \"");
02825 TRY_nomem(es += a_value);
02826 TRY_nomem(es += "\"");
02827 TRY_nomem(str = a_value);
02828 TRY(num = str,es);
02829 (*m_job).rsync_remote_port = num;
02830 }
02831
02832
02833 void job_parser::parse_rsync_remote_module(const std::string& a_value)
02834 {
02835 TRY_nomem((*m_job).rsync_remote_module = a_value);
02836 }
02837
02838
02839 void job_parser::parse_rsync_retry_count(const std::string& a_value)
02840 {
02841 std::string es;
02842 estring str;
02843 uint16 num;
02844
02845 TRY_nomem(es = "Invalid rsync-retry-count value: \"");
02846 TRY_nomem(es += a_value);
02847 TRY_nomem(es += "\"");
02848 TRY_nomem(str = a_value);
02849 TRY(num = str,es);
02850 (*m_job).rsync_retry_count = num;
02851 }
02852
02853
02854 void job_parser::parse_rsync_timeout(const std::string& a_value)
02855 {
02856 std::string es;
02857 estring str;
02858 uint16 num;
02859
02860 TRY_nomem(es = "Invalid rsync-timeout value: \"");
02861 TRY_nomem(es += a_value);
02862 TRY_nomem(es += "\"");
02863 TRY_nomem(str = a_value);
02864 TRY(num = str,es);
02865 (*m_job).rsync_timeout = num;
02866 }
02867
02868
02869
02870
02871 configuration_manager config;