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