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