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