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