rvm  1.11
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
rconfig.cc
Go to the documentation of this file.
1 #include "config.h"
2 
3 #include <iostream>
4 #include <string>
5 #include <fstream>
6 #include <vector>
7 #include <map>
8 #include <algorithm>
9 #include <cctype>
10 
11 #include "asserts.h"
12 #include "error.h"
13 #include "estring.h"
14 #include "fs.h"
15 #include "tstamp.h"
16 
17 #include "rconfig.h"
18 
19 //----------------------------------------------------------------------------
20 
21 /** Reset to a default value */
23 {
24  m_type = jobname;
25  m_literal.erase();
26 }
27 
28 /** C'tor */
30 {
31  clear();
32 }
33 
34 /** C'tor */
36  const archive_path_element& a_class)
37 {
38  clear();
39  assign(a_class);
40 }
41 
42 /** C'tor */
45  )
46 {
47  clear();
48  assign(a_enum);
49 }
50 
51 /** C'tor */
53 {
54  clear();
55  assign(a_str);
56 }
57 
58 /** Assign the value from another archive_path_element instance */
60 {
61  if (this == &a_class)
62  return;
63 
64  if (a_class.type() == literal)
65  assign(a_class.str());
66  else
67  assign(a_class.type());
68 }
69 
70 /** Assign any type except literal */
73  )
74 {
75  m_type = a_enum;
76  if (m_type != literal) {
77  m_literal.erase();
78  }
79 }
80 
81 /** Assign a literal */
82 void archive_path_element::assign(const std::string& a_str)
83 {
84  std::string es;
85  std::string str;
86  std::string::size_type idx;
87 
88  TRY_nomem(es = "Invalid archive-path keyword: \"");
89  TRY_nomem(es += a_str);
90  TRY_nomem(es += "\"");
91 
92  if (a_str.size() == 0) {
93  throw(ERROR(0,es));
94  }
95  if (a_str[0] == '"') {
96  if (a_str.size() < 3) {
97  throw(ERROR(0,es));
98  }
99  if (a_str[a_str.size()-1] != '"') {
100  throw(ERROR(0,es));
101  }
102  TRY_nomem(str = a_str.substr(1,a_str.size()-2));
103 
104  idx = str.find('"');
105  while (idx != std::string::npos) {
106  if ((idx > 0) && (str[idx-1] != '\\'))
107  throw(ERROR(0,es));
108  idx = str.find('"',idx+1);
109  }
110 
111  idx = str.find("\\\"");
112  while (idx != std::string::npos) {
113  str.erase(idx,1);
114  idx = str.find("\\\"");
115  }
116 
117  TRY_nomem(m_literal = str);
118  m_type = literal;
119  }
120  else {
121  str = estring(a_str).lower();
122  if (str == "jobname") {
123  assign(jobname);
124  }
125  else if (str == "groupname") {
126  assign(groupname);
127  }
128  else if (str == "hostname") {
129  assign(hostname);
130  }
131  else if (str == "pathname") {
132  assign(pathname);
133  }
134  else if (str == "permutation") {
136  }
137  else {
138  throw(ERROR(0,es));
139  }
140  }
141 }
142 
143 /** Retrieve the current type */
146 {
147  return(m_type);
148 }
149 
150 /** Retrieve the current literal value */
151 const std::string& archive_path_element::value(void) const
152 {
153  return(m_literal);
154 }
155 
156 /** Construct a string of the current value */
157 const std::string archive_path_element::str(void) const
158 {
159  std::string::size_type idx;
160  std::string value;
161 
162  if (m_type == jobname) {
163  TRY_nomem(value = "jobname");
164  }
165  else if (m_type == groupname) {
166  TRY_nomem(value = "groupname");
167  }
168  else if (m_type == hostname) {
169  TRY_nomem(value = "hostname");
170  }
171  else if (m_type == pathname) {
172  TRY_nomem(value = "pathname");
173  }
174  else if (m_type == permutation) {
175  TRY_nomem(value = "permutation");
176  }
177  else {
178  TRY_nomem(value = "\"");
179  for (idx = 0; idx != m_literal.size(); idx++) {
180  if (m_literal[idx] == '"') {
181  TRY_nomem(value += '\\');
182  }
183  TRY_nomem(value += m_literal[idx]);
184  }
185  TRY_nomem(value += '"');
186  }
187 
188  return(value);
189 }
190 
191 /** Assignment */
194 {
195  clear();
196  assign(a_class);
197 
198  return(*this);
199 }
200 
201 /** Assignment */
205 {
206  clear();
207  assign(a_enum);
208 
209  return(*this);
210 }
211 
212 /** Assignment */
214  archive_path_element::operator=(const std::string& a_str)
215 {
216  clear();
217  assign(a_str);
218 
219  return(*this);
220 }
221 
222 //----------------------------------------------------------------------------
223 
224 /** Reset to a default value */
226 {
227  clear();
228  push_back("hostname/pathname");
229 }
230 
231 /** C'tor */
233 {
234  reset();
235 }
236 
237 /** C'tor */
239 {
240  push_back(a_class);
241 }
242 
243 /** C'tor */
245 {
246  push_back(a_class);
247 }
248 
249 /** C'tor */
250 archive_path::archive_path(const std::string& a_str)
251 {
252  push_back(a_str);
253 }
254 
255 /** Add elements to the path list from another archive_path instance */
257 {
258  const_iterator li;
259 
260  for (li = a_class.begin(); li != a_class.end(); li++) {
261  TRY_nomem(push_back(*li));
262  }
263 }
264 
265 /** Add an element to the path list from an archive_path_element instance */
267 {
268  TRY_nomem(type::push_back(a_class));
269 }
270 
271 /** Parse a string into an archive-path list */
272 void archive_path::push_back(const std::string& a_str)
273 {
274  std::string es;
275  std::string keyword;
276  std::string str;
277  std::string::size_type idx;
279 
280  if (a_str.size() == 0)
281  return;
282 
283  TRY_nomem(str = a_str);
284  if (str[0] == '/')
285  str.erase(0,1);
286  if (str[str.size()-1] == '/')
287  str.erase(str.size()-1,1);
288 
289  while (str.size() > 0) {
290  idx = str.find('/');
291  if (idx == std::string::npos) {
292  TRY_nomem(keyword = str);
293  str.erase();
294  }
295  else {
296  TRY_nomem(keyword = str.substr(0,idx));
297  str.erase(0,idx+1);
298  }
299 
300  ape.clear();
301  TRY_nomem(es = "At: \"");
302  TRY_nomem(es += keyword);
303  TRY_nomem(es += "\"");
304  TRY(ape.assign(keyword),es);
305  TRY_nomem(push_back(ape));
306  }
307 }
308 
309 /** Reconstruct a string from an archive-path list */
310 const std::string archive_path::str(void) const
311 {
312  std::string str;
313  const_iterator li;
314 
315  for (li = begin(); li != end(); li++) {
316  if (li != begin()) {
317  TRY_nomem(str += '/');
318  }
319  TRY_nomem(str += (*li).str());
320  }
321 
322  return(str);
323 }
324 
325 /** Assign an archive-path list from another archive_path instance */
326 void archive_path::assign(const archive_path& a_class)
327 {
328  if (this != &a_class) {
329  clear();
330  push_back(a_class);
331  }
332 }
333 
334 /** Assign an archive-path list from a single archive_path_element instance */
336 {
337  clear();
338  push_back(a_class);
339 }
340 
341 /** Assign an archive-path list from a string (parse the string) */
342 void archive_path::assign(const std::string& a_str)
343 {
344  clear();
345  push_back(a_str);
346 }
347 
348 /** Assignment */
350 {
351  assign(a_class);
352 
353  return(*this);
354 }
355 
356 /** Assignment */
358 {
359  assign(a_class);
360 
361  return(*this);
362 }
363 
364 /** Assignment */
365 archive_path& archive_path::operator=(const std::string& a_str)
366 {
367  assign(a_str);
368 
369  return(*this);
370 }
371 
372 //----------------------------------------------------------------------------
373 
374 /** Default behavior */
376 
377 /** Clear all values and set the default to "retry" */
379 {
380  m_map.clear();
381  m_default = retry;
382 }
383 
384 /** Clear all values and set some sane default actions */
386 {
387  clear();
388  m_default = retry;
389  TRY_nomem(
390  m_map[0] = ok;
391  m_map[1] = fail;
392  m_map[2] = fail;
393  m_map[4] = fail;
394  m_map[23] = retry_without_hardlinks;
395  m_map[124] = fail;
396  m_map[125] = fail;
397  m_map[126] = fail;
398  m_map[127] = fail;
399  );
400 }
401 
402 /** C'tor */
404 {
405  reset();
406 }
407 
408 /** C'tor */
410 {
411  assign(a_class);
412 }
413 
414 /** Assign an action to be taken for a specific exit code */
415 void rsync_behavior::assign(const uint16 a_code, const value_type a_action)
416 {
417  if (a_code == default_behavior)
418  m_default = a_action;
419  else {
420  TRY_nomem(m_map[a_code] = a_action);
421  }
422 }
423 
424 /** Assign actions to be taken from another rsync_behavior instance */
426 {
427  if (this == &a_class)
428  return;
429 
430  clear();
431  m_default = a_class.default_value();
432  TRY_nomem(m_map = a_class.map_value());
433 }
434 
435 /**
436  Assign actions to be taken from a string (parse a string in the form of
437  exit-code '=' action)
438  */
439 void rsync_behavior::assign(const std::string& a_str)
440 {
441  std::string es;
442  std::string code_str;
443  std::string action_str;
444  uint16 code;
446  std::string::size_type idx;
447 
448  TRY_nomem(es = "Invalid rsync-behavior value: \"");
449  TRY_nomem(es += a_str);
450  TRY_nomem(es += "\"");
451 
452  TRY_nomem(action_str = a_str);
453  idx = 0;
454  while (isdigit(action_str[idx]) || (action_str[idx] == '*'))
455  ++idx;
456  TRY_nomem(code_str = action_str.substr(0,idx));
457  action_str.erase(0,idx);
458  if (code_str.size() == 0)
459  throw(ERROR(0,es));
460 
461  idx = 0;
462  while ((action_str[idx] == ' ') || (action_str[idx] == '\t'))
463  idx++;
464  action_str.erase(0,idx);
465 
466  if (action_str[0] != '=')
467  throw(ERROR(0,es));
468  action_str.erase(0,1);
469 
470  idx = 0;
471  while ((action_str[idx] == ' ') || (action_str[idx] == '\t'))
472  idx++;
473  action_str.erase(0,idx);
474 
475  if (code_str == "*")
477  else
478  code = estring(code_str);
479  if (estring(action_str).lower() == "ok")
480  action = rsync_behavior::ok;
481  else if (estring(action_str).lower() == "fail")
482  action = rsync_behavior::fail;
483  else if (estring(action_str).lower() == "retry")
484  action = rsync_behavior::retry;
485  else if (estring(action_str).lower() == "retry-without-hardlinks")
487  else if (estring(action_str).lower() == "ok")
488  action = rsync_behavior::quit;
489  else
490  throw(ERROR(0,es));
491  assign(code, action);
492 }
493 
494 /** Return the action to be taken for a given exit code */
496  rsync_behavior::operator[](const uint16 a_code) const
497 {
498  if (a_code == default_behavior) {
499  return(m_default);
500  }
501  if (m_map.find(a_code) != m_map.end()) {
502  return(m_map.find(a_code)->second);
503  }
504  return(m_default);
505 }
506 
507 /** Return the action to be taken for a given exit code */
509  rsync_behavior::operator[](const uint16 a_code)
510 {
511  if (a_code == default_behavior) {
512  return(m_default);
513  }
514  return(m_map[a_code]);
515 }
516 
517 /** Assignment */
519 {
520  assign(a_class);
521 
522  return(*this);
523 }
524 
525 /** Assignment */
528 {
529  assign(default_behavior, a_enum);
530 
531  return(*this);
532 }
533 
534 /** Assignment */
535 rsync_behavior& rsync_behavior::operator=(const std::string& a_str)
536 {
537  assign(a_str);
538 
539  return(*this);
540 }
541 
542 /** Return the default action */
544 {
545  return(m_default);
546 }
547 
548 /** Return an std::map of exit codes to actions */
550 {
551  return(m_map);
552 }
553 
554 //----------------------------------------------------------------------------
555 
556 /** C'tor */
558 {
559  clear();
560 }
561 
562 /** C'tor */
563 job::job(const job& a_job)
564 {
565  clear();
566  assign(a_job);
567 }
568 
569 /** Clear values */
570 void job::clear(void)
571 {
572  default_config_path.erase();
574  config_path.erase();
575  config_line = 0;
576  archive_path = "hostname/pathname";
577  excludes.clear();
578  includes.clear();
579  groupname.erase();
580  hostname.erase();
581  jobname.erase();
582  paths.clear();
585  rsync_hardlink = true;
586  rsync_multi_hardlink = false;
588  rsync_options.erase();
589  ssh_options.erase();
590  rsync_remote_user.erase();
591  rsync_remote_path.erase();
592  rsync_remote_port = 0;
593  rsync_remote_module.erase();
594  rsync_retry_count = 3;
595  rsync_retry_delay = 0;
596  rsync_timeout = 60 * 60 * 4; // 4 hours;
597 }
598 
599 /** Assign values from another job instance */
600 void job::assign(const job& a_job)
601 {
602  clear();
603 
606  config_path = a_job.config_path;
607  config_line = a_job.config_line;
608  archive_path = a_job.archive_path;
609  excludes = a_job.excludes;
610  includes = a_job.includes;
611  groupname = a_job.groupname;
612  hostname = a_job.hostname;
613  jobname = a_job.jobname;
614  paths = a_job.paths;
622  ssh_options = a_job.ssh_options;
630 }
631 
632 /** Assignment */
633 job& job::operator=(const job& a_job)
634 {
635  assign(a_job);
636 
637  return(*this);
638 }
639 
640 /** Generate the archive-path subdirectory for this job */
641 const std::string job::generate_archive_path(const std::string& a_path) const
642 {
643  std::string es;
644  std::string path;
645  archive_path::const_iterator capi;
646 
647  for (capi = archive_path.begin(); capi != archive_path.end(); ++capi) {
648  if (capi->type() == archive_path_element::jobname) {
649  if (jobname.size() == 0) {
650  TRY_nomem(es = "archive-path references jobname, ");
651  TRY_nomem(es += "but jobname is empty");
652  throw(ERROR(0,es));
653  }
654  if (path.size() != 0) {
655  TRY_nomem(path += '/');
656  }
657  TRY_nomem(path += jobname);
658  }
659  else if (capi->type() == archive_path_element::groupname) {
660  if (groupname.size() == 0) {
661  TRY_nomem(es = "archive-path references groupname, ");
662  TRY_nomem(es += "but groupname is empty");
663  throw(ERROR(0,es));
664  }
665  if (path.size() != 0) {
666  TRY_nomem(path += '/');
667  }
668  TRY_nomem(path += groupname);
669  }
670  else if (capi->type() == archive_path_element::hostname) {
671  if (hostname.size() == 0) {
672  TRY_nomem(es = "archive-path references hostname, ");
673  TRY_nomem(es += "but hostname is empty");
674  throw(ERROR(0,es));
675  }
676  if (path.size() != 0) {
677  TRY_nomem(path += '/');
678  }
679  TRY_nomem(path += hostname);
680  }
681  else if (capi->type() == archive_path_element::pathname) {
682  if (a_path.size() == 0) {
683  TRY_nomem(es = "archive-path references path name, ");
684  TRY_nomem(es += "but path name is empty");
685  throw(ERROR(0,es));
686  }
687  if (path.size() != 0) {
688  TRY_nomem(path += '/');
689  }
690  TRY_nomem(path += a_path);
691  }
692  else if (capi->type() == archive_path_element::permutation) {
693  if (a_path.size() == 0) {
694  TRY_nomem(es = "archive-path references path name, ");
695  TRY_nomem(es += "but path name is empty");
696  throw(ERROR(0,es));
697  }
698  if (path.size() != 0) {
699  TRY_nomem(path += '/');
700  }
701  TRY_nomem(path += permute_path(a_path));
702  }
703  else if (capi->type() == archive_path_element::literal) {
704  if (capi->value().size() == 0) {
705  TRY_nomem(es = "archive-path references literal string, ");
706  TRY_nomem(es += "but literal string value is empty");
707  throw(INTERNAL_ERROR(0,es));
708  }
709  if (path.size() != 0) {
710  TRY_nomem(path += '/');
711  }
712  TRY_nomem(path += capi->value());
713  }
714  else
715  throw(INTERNAL_ERROR(0,"Unknown archive path element type"));
716  }
717 
718  // If path does not end with a '/', strip off characters until it does.
719  while ((path.size() > 0) && (path[path.size()-1] != '/'))
720  path.erase(path.size()-1);
721 
722  path = reform_path(path);
723 
724  return(path);
725 }
726 
727 /** Generate the source path to be passed to rsync on the command line */
728 const std::string job::generate_source_path(const std::string& a_path) const
729 {
730  estring path;
731 
733  path += "rsync://";
734  if (rsync_remote_user.size() != 0) {
735  path += rsync_remote_user;
736  path += "@";
737  }
738  TRY_nomem(path += hostname);
739  if (rsync_remote_port != 0) {
740  path += ":";
741  path += estring(rsync_remote_port);
742  }
743  if (rsync_remote_module.size() != 0) {
744  path += "/";
745  path += rsync_remote_module;
746  if ((a_path.size() > 0) && (a_path[0] != '/'))
747  path += "/";
748  }
749  }
750  else if (rsync_connection == connection_remote) {
751  if (rsync_remote_user.size() != 0) {
752  path += rsync_remote_user;
753  path += "@";
754  }
755  path += hostname;
756  path += ":";
757  }
758  path += a_path;
759 
760  return(path);
761 }
762 
763 /** Find the common pathname among all job paths (may be an empty string) */
764 const std::string job::common_pathname(void) const
765 {
766  std::string common_path;
767  paths_type::size_type pidx;
768  std::string::size_type sidx;
769  std::string::size_type max_sidx;
770  bool same;
771 
772  TRY_nomem(common_path = "");
773  sidx = 0;
774  max_sidx = paths[0].size();
775  for (pidx = 0; pidx < paths.size(); pidx++) {
776  if (max_sidx > paths[pidx].size()) {
777  max_sidx = paths[pidx].size();
778  }
779  }
780  same = true;
781  for (sidx = 0; sidx < max_sidx; sidx++) {
782  for (pidx = 0; (same && (pidx < paths.size())); pidx++) {
783  if (pidx == 0)
784  continue;
785  if (paths[pidx-1][sidx] != paths[pidx][sidx])
786  same = false;
787  }
788  if (same)
789  TRY_nomem(common_path += paths[0][sidx]);
790  }
791  if (common_path[0] == '/')
792  common_path.erase(0,1);
793  if ((common_path.size() > 0) && (common_path[common_path.size()-1] == '/'))
794  common_path.erase(common_path.size()-1);
795 
796  return(common_path);
797 }
798 
799 /** Generate a unique ID string for this job */
800 const std::string job::generate_job_id(void) const
801 {
802  std::string es;
803  std::string path;
804  archive_path::const_iterator capi;
805 
806  for (capi = archive_path.begin(); capi != archive_path.end(); ++capi) {
807  if (capi->type() == archive_path_element::jobname) {
808  if (jobname.size() == 0) {
809  TRY_nomem(es = "archive-path references jobname, ");
810  TRY_nomem(es += "but jobname is empty");
811  throw(ERROR(0,es));
812  }
813  if (path.size() != 0) {
814  TRY_nomem(path += '/');
815  }
816  TRY_nomem(path += jobname);
817  }
818  else if (capi->type() == archive_path_element::groupname) {
819  if (groupname.size() == 0) {
820  TRY_nomem(es = "archive-path references groupname, ");
821  TRY_nomem(es += "but groupname is empty");
822  throw(ERROR(0,es));
823  }
824  if (path.size() != 0) {
825  TRY_nomem(path += '/');
826  }
827  TRY_nomem(path += groupname);
828  }
829  else if (capi->type() == archive_path_element::hostname) {
830  if (hostname.size() == 0) {
831  TRY_nomem(es = "archive-path references hostname, ");
832  TRY_nomem(es += "but hostname is empty");
833  throw(ERROR(0,es));
834  }
835  if (path.size() != 0) {
836  TRY_nomem(path += '/');
837  }
838  TRY_nomem(path += hostname);
839  }
840  else if (capi->type() == archive_path_element::pathname) {
841  if (path.size() == 0) {
842  TRY_nomem(path += common_pathname());
843  }
844  }
845  else if (capi->type() == archive_path_element::permutation) {
846  if (path.size() == 0) {
848  }
849  }
850  else if (capi->type() == archive_path_element::literal) {
851  if (capi->value().size() == 0) {
852  TRY_nomem(es = "archive-path references literal string, ");
853  TRY_nomem(es += "but literal string value is empty");
854  throw(INTERNAL_ERROR(0,es));
855  }
856  if (path.size() != 0) {
857  TRY_nomem(path += '/');
858  }
859  TRY_nomem(path += capi->value());
860  }
861  }
862 
863  path = reform_path(path);
864 
865  if (path.size() == 0) {
866  TRY_nomem(path = jobname);
867  }
868  return(path);
869 }
870 
871 /** Generate rsync command line options */
872 const std::vector<std::string> job::generate_rsync_options_vector(void) const
873 {
874  std::string opts = rsync_options;
875  std::vector<std::string> argv;
876  std::string str;
877 
878  while (opts.size() != 0) {
879 
880  str.clear();
881  while ((opts.size() != 0) && (opts[0] != ' ') && (opts[0] != '\t')) {
882  switch (opts[0]) {
883  case '\0':
884  break;
885  case '\'':
886  opts.erase(0,1);
887  while ((opts.size() != 0) && (opts[0] != '\'')) {
888  str += opts[0];
889  opts.erase(0,1);
890  }
891  if (opts[0] == '\'') {
892  opts.erase(0,1);
893  }
894  break;
895  case '"':
896  opts.erase(0,1);
897  while ((opts.size() != 0) && (opts[0] != '"')) {
898  if ((opts.size() >= 2) && (opts[0] == '\\') && (opts[1] == '"')) {
899  str += '"';
900  opts.erase(0,2);
901  }
902  else {
903  str += opts[0];
904  opts.erase(0,1);
905  }
906  }
907  if (opts[0] == '"') {
908  opts.erase(0,1);
909  }
910  break;
911  case '\\':
912  if ((opts.size() >= 2) && (opts[1] == ' ')) {
913  str += ' ';
914  opts.erase(0,2);
915  }
916  else if ((opts.size() >= 2) && (opts[1] == 't')) {
917  str += '\t';
918  opts.erase(0,2);
919  }
920  else {
921  str += '\\';
922  opts.erase(0,1);
923  }
924  break;
925  default:
926  str += opts[0];
927  opts.erase(0,1);
928  break;
929  }
930  }
931 
932  if (str.size()) {
933  argv.push_back(str);
934  }
935  while ((opts.size() > 0) && ((opts[0] == ' ') || (opts[0] == '\t'))) {
936  opts.erase(0,1);
937  }
938  }
939 
940  return(argv);
941 }
942 
943 /** Generate ssh command line options */
944 const std::vector<std::string> job::generate_ssh_options_vector(void) const
945 {
946  std::string opts = ssh_options;
947  std::vector<std::string> argv;
948  std::string str;
949 
950  while (opts.size() != 0) {
951 
952  str.clear();
953  while ((opts.size() != 0) && (opts[0] != ' ') && (opts[0] != '\t')) {
954  switch (opts[0]) {
955  case '\0':
956  break;
957  case '\'':
958  opts.erase(0,1);
959  while ((opts.size() != 0) && (opts[0] != '\'')) {
960  str += opts[0];
961  opts.erase(0,1);
962  }
963  if (opts[0] == '\'') {
964  opts.erase(0,1);
965  }
966  break;
967  case '"':
968  opts.erase(0,1);
969  while ((opts.size() != 0) && (opts[0] != '"')) {
970  if ((opts.size() >= 2) && (opts[0] == '\\') && (opts[1] == '"')) {
971  str += '"';
972  opts.erase(0,2);
973  }
974  else {
975  str += opts[0];
976  opts.erase(0,1);
977  }
978  }
979  if (opts[0] == '"') {
980  opts.erase(0,1);
981  }
982  break;
983  case '\\':
984  if ((opts.size() >= 2) && (opts[1] == ' ')) {
985  str += ' ';
986  opts.erase(0,2);
987  }
988  else if ((opts.size() >= 2) && (opts[1] == 't')) {
989  str += '\t';
990  opts.erase(0,2);
991  }
992  else {
993  str += '\\';
994  opts.erase(0,1);
995  }
996  break;
997  default:
998  str += opts[0];
999  opts.erase(0,1);
1000  break;
1001  }
1002  }
1003 
1004  if (str.size()) {
1005  argv.push_back(str);
1006  }
1007  while ((opts.size() > 0) && ((opts[0] == ' ') || (opts[0] == '\t'))) {
1008  opts.erase(0,1);
1009  }
1010  }
1011 
1012  return(argv);
1013 }
1014 
1015 /** Perform sanity checks for the configuration settings of this job */
1016 void job::check(void)
1017 {
1018  std::string es;
1019  std::string this_path;
1020  std::string that_path;
1021  paths_type::const_iterator cpi;
1022  configuration_manager::jobs_type::const_iterator cji;
1023  paths_type::const_iterator cjapi;
1024 
1025  if (
1026  (
1030  )
1031  && (hostname.size() == 0)
1032  )
1033  {
1034  TRY_nomem(es = "rsync-connection-type references hostname, ");
1035  TRY_nomem(es += "but hostname is empty");
1036  throw(ERROR(0,es));
1037  }
1038 
1040  /*
1041  if (config.ssh_local_path.size() == 0) {
1042  TRY_nomem(es = "rsync-connection-type references remote-rsync-local-dir, ");
1043  TRY_nomem(es += "but ssh-local-path is empty");
1044  throw(ERROR(0,es));
1045  }
1046  */
1047 
1048  if (excludes.size() != 0) {
1049  TRY_nomem(es = "rsync-connection-type is remote-rsync-local-dir, ");
1050  TRY_nomem(es += "but exclude files have been specified");
1051  throw(ERROR(0,es));
1052  }
1053 
1054  if (includes.size() != 0) {
1055  TRY_nomem(es = "rsync-connection-type is remote-rsync-local-dir, ");
1056  TRY_nomem(es += "but include files have been specified");
1057  throw(ERROR(0,es));
1058  }
1059  }
1060 
1061  if ((rsync_remote_module.size() != 0)
1063  {
1064  TRY_nomem(es = "rsync-remote-module specifies a module, but ");
1065  TRY_nomem(es = "rsync-connection-type is not server");
1066  throw(ERROR(0,es));
1067  }
1068 
1069  if (paths.size() == 0) {
1070  throw(ERROR(0,"No paths defined for this job"));
1071  }
1072 
1073  for (cpi = paths.begin() ; cpi != paths.end(); cpi++) {
1074  TRY_nomem(this_path = generate_archive_path(*cpi));
1075 
1076  for (
1077  cji = config.jobs().begin();
1078  cji != config.jobs().end();
1079  cji++
1080  )
1081  {
1082  for (
1083  cjapi = cji->paths.begin();
1084  cjapi != cji->paths.end();
1085  cjapi++
1086  )
1087  {
1088  TRY_nomem(that_path = cji->generate_archive_path(*cjapi));
1089 
1090  if (this_path == that_path) {
1091  error e(0);
1092 
1093  TRY_nomem(es = "Duplicate archive-path values detected");
1094  e.push_back(ERROR_INSTANCE(es));
1095  TRY_nomem(es = "Archive path: \"");
1096  TRY_nomem(es += this_path);
1097  TRY_nomem(es += "\"");
1098  e.push_back(ERROR_INSTANCE(es));
1099  TRY_nomem(es = "Previously defined at ");
1100  TRY_nomem(es += cji->config_path);
1101  TRY_nomem(es += "[");
1102  TRY_nomem(es += estring(cji->config_line));
1103  TRY_nomem(es += "]");
1104  e.push_back(ERROR_INSTANCE(es));
1105  throw(e);
1106  }
1107 
1108  if (
1109  (this_path.size() < that_path.size())
1110  && (this_path == that_path.substr(0,this_path.size()))
1111  && (
1112  (that_path[this_path.size()] == '/')
1113  || (this_path.size() == 0)
1114  )
1115  )
1116  {
1117  error e(0);
1118 
1119  TRY_nomem(es = "Overlapping archive-path values detected");
1120  e.push_back(ERROR_INSTANCE(es));
1121  TRY_nomem(es = "Defined archive-path: \"");
1122  TRY_nomem(es += this_path);
1123  TRY_nomem(es += "\"");
1124  e.push_back(ERROR_INSTANCE(es));
1125  TRY_nomem(es = "Is in a parent directory of another job's previously defined archive-path");
1126  e.push_back(ERROR_INSTANCE(es));
1127  TRY_nomem(es = "At ");
1128  TRY_nomem(es += cji->config_path);
1129  TRY_nomem(es += "[");
1130  TRY_nomem(es += estring(cji->config_line));
1131  TRY_nomem(es += "]");
1132  e.push_back(ERROR_INSTANCE(es));
1133  throw(e);
1134  }
1135 
1136  if (
1137  (this_path.size() > that_path.size())
1138  && (this_path.substr(0,that_path.size()) == that_path)
1139  && (
1140  (this_path[that_path.size()] == '/')
1141  || (that_path.size() == 0)
1142  )
1143  )
1144  {
1145  error e(0);
1146 
1147  TRY_nomem(es = "Overlapping archive-path values detected");
1148  e.push_back(ERROR_INSTANCE(es));
1149  TRY_nomem(es = "Defined archive-path: \"");
1150  TRY_nomem(es += this_path);
1151  TRY_nomem(es += "\"");
1152  e.push_back(ERROR_INSTANCE(es));
1153  TRY_nomem(es = "Is in a subdirectory of another job's previously defined archive-path");
1154  e.push_back(ERROR_INSTANCE(es));
1155  TRY_nomem(es = "At ");
1156  TRY_nomem(es += cji->config_path);
1157  TRY_nomem(es += "[");
1158  TRY_nomem(es += estring(cji->config_line));
1159  TRY_nomem(es += "]");
1160  e.push_back(ERROR_INSTANCE(es));
1161  throw(e);
1162  }
1163  }
1164  }
1165  }
1166 }
1167 
1168 //----------------------------------------------------------------------------
1169 
1170 /** Reset configuration to default settings */
1172 {
1173  m_initialized = false;
1174  m_configs_read = 0;
1175  m_default = true;
1178  m_timestamp.set();
1179  m_cfgfiles.clear();
1180  m_link_catalog_dir.erase();
1182  m_delete_old_log_files = false;
1183  m_delete_old_report_files = false;
1184  m_rsync_local_path.erase();
1185  m_delete_command_path.erase();
1186  if (strlen(LOCAL_RSYNC) > 0) {
1188  }
1189  m_ssh_local_path.erase();
1190  if (strlen(LOCAL_SSH) > 0) {
1192  }
1193  m_rsync_parallel = 1;
1194  m_io_poll_interval = 1;
1195  m_vaults.clear();
1200  m_vault_locking = true;
1201  m_default_job.clear();
1204  m_jobs.clear();
1205 }
1206 
1207 /** C'tor */
1209 {
1210  if (this != &config)
1211  throw(
1212  INTERNAL_ERROR(0,"Attempt to allocate multiple configuration managers")
1213  );
1214  clear();
1215 }
1216 
1217 /** Initialize the configuration manager from rvm's command line options */
1218 void configuration_manager::init(int argc, char const * argv[])
1219 {
1220  int c;
1221  estring opt;
1222  estring arg;
1223  std::string es;
1224  std::string tes;
1225  cfgfiles_type::const_iterator cfi;
1226  bool use_custom_timestamp = false;
1227  class timestamp custom_timestamp;
1228 
1229  for (c = 1; c < argc; c++) {
1230  TRY_nomem(opt = argv[c]);
1231  if (c+1 == argc) {
1232  TRY_nomem(arg = "");
1233  }
1234  else {
1235  TRY_nomem(arg = argv[c+1]);
1236  }
1237 
1238  if (opt == "--archive") {
1240  }
1241  else if (opt == "--relink") {
1243  }
1244  else if (opt == "--help") {
1246  }
1247  else if (opt == "--version") {
1249  }
1250  else if (opt == "--check-config") {
1252  }
1253  else if (opt == "--no-default-config") {
1254  m_default = false;
1255  }
1256  else if (opt == "--config") {
1257  directory dir;
1258  directory::const_iterator cdi;
1259 
1260  TRY_nomem(es = "Error finding configuration file(s) ");
1261  TRY_nomem(es += "matching command line argument [");
1262  TRY_nomem(es += estring(c+1));
1263  TRY_nomem(es += "]: \"");
1264  TRY_nomem(es += arg);
1265  TRY_nomem(es += "\"");
1266 
1267  try {
1268  dir.path(arg);
1269  }
1270  catch(error e) {
1271  e.push_back(ERROR_INSTANCE(es));
1272  throw(e);
1273  }
1274  catch(...) {
1275  error e = err_unknown;
1276 
1277  e.push_back(ERROR_INSTANCE(es));
1278  throw(e);
1279  }
1280  if (dir.size() == 0) {
1281  TRY_nomem(es = "No configuration file(s) found matching ");
1282  TRY_nomem(es += "command line argument [");
1283  TRY_nomem(es += estring(c+1));
1284  TRY_nomem(es += "]: \"");
1285  TRY_nomem(es += arg);
1286  TRY_nomem(es += "\"");
1287 
1288  throw(ERROR(0,es));
1289  }
1290  for (cdi = dir.begin(); cdi != dir.end(); cdi++) {
1291  TRY_nomem(m_cfgfiles.push_back(cfgfile_element(config_file, arg)));
1292  }
1293 
1294  c++;
1295  }
1296  else if (opt == "--job") {
1297  directory dir;
1298  directory::const_iterator cdi;
1299 
1300  TRY_nomem(es = "Error finding job file(s) ");
1301  TRY_nomem(es += "matching command line argument [");
1302  TRY_nomem(es += estring(c+1));
1303  TRY_nomem(es += "]: \"");
1304  TRY_nomem(es += arg);
1305  TRY_nomem(es += "\"");
1306 
1307  try {
1308  dir.path(arg);
1309  }
1310  catch(error e) {
1311  e.push_back(ERROR_INSTANCE(es));
1312  throw(e);
1313  }
1314  catch(...) {
1315  error e = err_unknown;
1316  throw(e);
1317  }
1318  if (dir.size() == 0) {
1319  TRY_nomem(es = "No job file(s) found matching ");
1320  TRY_nomem(es += "command line argument [");
1321  TRY_nomem(es += estring(c+1));
1322  TRY_nomem(es += "]: \"");
1323  TRY_nomem(es += arg);
1324  TRY_nomem(es += "\"");
1325 
1326  throw(ERROR(0,es));
1327  }
1328  for (cdi = dir.begin(); cdi != dir.end(); cdi++) {
1329  TRY_nomem(m_cfgfiles.push_back(cfgfile_element(job_file, arg)));
1330  }
1331 
1332  c++;
1333  }
1334  else if (opt == "--timestamp") {
1335  TRY_nomem(es = "From command line argument ");
1336  TRY_nomem(es += estring(c+1));
1337  TRY(custom_timestamp.assign(arg),es);
1338  use_custom_timestamp = true;
1339  c++;
1340  TRY_nomem(tes = es);
1341  }
1342  else {
1343  TRY_nomem(es = "Unknown command line option: \"");
1344  TRY_nomem(es += opt);
1345  TRY_nomem(es += "\"");
1346  throw(ERROR(0,es));
1347  }
1348  }
1349 
1350  m_initialized = true;
1351 
1352  if ((m_action == action_help) || (m_action == action_version))
1353  return;
1354 
1355  if (use_default())
1357 
1358  for (cfi = m_cfgfiles.begin(); cfi != m_cfgfiles.end(); cfi++) {
1359  if (cfi->first == config_file) {
1360  read_config(cfi->second);
1361  }
1362  else {
1363  read_job(cfi->second);
1364  }
1365  }
1366 
1367  if (m_configs_read == 0) {
1368  throw(ERROR(0,"No configuration file(s) read"));
1369  }
1370 
1371  if (use_custom_timestamp) {
1372  TRY(m_timestamp = custom_timestamp,tes);
1373  }
1374 
1375  check();
1376 }
1377 
1378 /** Perform sanity checks on configuration settings */
1380 {
1381  std::string es;
1382  subdirectory subdir;
1383  filestatus fstat;
1384 
1385  if (!initialized())
1386  throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
1387 
1388  // log-dir -- If no log-dir is set then we use a default. What if that
1389  // default doesn't exist?
1390  if (m_log_dir.size() == 0) {
1391  throw(ERROR(0,"log-dir not set"));
1392  }
1393  TRY_nomem(es = "Invalid log-dir value: \"");
1394  TRY_nomem(es += m_log_dir);
1395  TRY_nomem(es += "\"");
1396  TRY_instead(subdir.path(m_log_dir,"*"),es);
1397 
1398  // rsync-local-path -- If (a) rsync-local-path is not set from config, and
1399  // (b) a default was determined at compile time, then (c) does the default
1400  // exist?
1401  TRY_nomem(es = "Invalid rsync-local-path value: \"");
1403  TRY_nomem(es += "\"");
1404  TRY(fstat.path(m_rsync_local_path),es);
1405 
1406  // delete-command-path -- If delete-command-path is set, check to see if the
1407  // command exists
1408  if (m_delete_command_path.size() > 0) {
1409  TRY_nomem(es = "Invalid delete-command-path value: \"");
1411  TRY_nomem(es += "\"");
1412  TRY(fstat.path(m_delete_command_path),es);
1413  }
1414 
1415  // ssh-local-path -- If (a) ssh-local-path is not set from config, and
1416  // (b) a default was determined at compile time, then (c) does the default
1417  // exist?
1418  //
1419  // TODO: NOT SURE WE SHOULD CARE ABOUT THIS HERE. What if the end user
1420  // doesn't want or need to have ssh installed on their machine?
1421  /*
1422  TRY_nomem(es = "Invalid ssh-local-path value: \"");
1423  TRY_nomem(es += m_ssh_local_path);
1424  TRY_nomem(es += "\"");
1425  TRY(fstat.path(m_ssh_local_path),es);
1426  */
1427 
1428  // vault -- Are there any?
1429  if (m_vaults.size() == 0) {
1430  throw(ERROR(0,"No vaults defined"));
1431  }
1432 
1433  // Do all jobs generate a valid job ID?
1434  // Note: This is purely cosmetic, generated job ID strings are only used in
1435  // status reports and report logs.
1436  if (jobs().size() > 0) {
1437  jobs_type::const_iterator cji;
1438 
1439  for (cji = jobs().begin(); cji != jobs().end(); cji++) {
1440  if (cji->generate_job_id().size() == 0) {
1441  error e(0);
1442 
1443  TRY_nomem(es = "Empty ID generated by job at ");
1444  TRY_nomem(es += cji->config_path);
1445  TRY_nomem(es += "[");
1446  TRY_nomem(es += estring(cji->config_line));
1447  TRY_nomem(es += "]");
1448  e.push_back(es);
1449  TRY_nomem(es =
1450  "Use 'jobname' to assign a descriptive name to this job");
1451  e.push_back(es);
1452  throw(e);
1453  }
1454  }
1455  }
1456 }
1457 
1458 /** Return the initialized state of the configuration manager */
1460 {
1461  return(m_initialized);
1462 }
1463 
1464 /** Return the action rvm is to take */
1467 {
1468  if (!initialized())
1469  throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
1470 
1471  return(m_action);
1472 }
1473 
1474 /** Return whether or not rvm is to try to read it's default configuration file */
1476 {
1477  if (!initialized())
1478  throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
1479 
1480  return(m_default);
1481 }
1482 
1483 /** Set the default configuration filename */
1484 void configuration_manager::default_file(const std::string& a_path)
1485 {
1486  TRY_nomem(m_default_file = a_path);
1487 }
1488 
1489 /** Return the default configuration filename */
1490 const std::string& configuration_manager::default_file(void) const
1491 {
1492  if (!initialized())
1493  throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
1494 
1495  return(m_default_file);
1496 }
1497 
1498 /** Return the default log-dir */
1499 void configuration_manager::default_logdir(const std::string& a_path)
1500 {
1501  TRY_nomem(m_log_dir = a_path);
1502 }
1503 
1504 /** Return the timestamp of this instance of rvm */
1506 {
1507  if (!initialized())
1508  throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
1509 
1510  return(m_timestamp);
1511 }
1512 
1513 /** Return the link-catalog-dir path */
1514 const std::string& configuration_manager::link_catalog_dir(void) const
1515 {
1516  if (!initialized())
1517  throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
1518 
1519  return(m_link_catalog_dir);
1520 }
1521 
1522 /** Return the log-dir path */
1523 const std::string& configuration_manager::log_dir(void) const
1524 {
1525  if (!initialized())
1526  throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
1527 
1528  return(m_log_dir);
1529 }
1530 
1531 /** Return the value of delete-old-log-files */
1533 {
1534  if (!initialized())
1535  throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
1536 
1537  return(m_delete_old_log_files);
1538 }
1539 
1540 /** Return the value of delete-old-report-files */
1542 {
1543  if (!initialized())
1544  throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
1545 
1546  return(m_delete_old_report_files);
1547 }
1548 
1549 /** Return the rsync-local-path */
1550 const std::string& configuration_manager::rsync_local_path(void) const
1551 {
1552  if (!initialized())
1553  throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
1554 
1555  return(m_rsync_local_path);
1556 }
1557 
1558 /** Return the delete-command-path */
1559 const std::string& configuration_manager::delete_command_path(void) const
1560 {
1561  if (!initialized())
1562  throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
1563 
1564  return(m_delete_command_path);
1565 }
1566 
1567 /** Return the ssh-local-path */
1568 const std::string& configuration_manager::ssh_local_path(void) const
1569 {
1570  if (!initialized())
1571  throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
1572 
1573  return(m_ssh_local_path);
1574 }
1575 
1576 /** Return the rsync-parallel */
1577 const uint16& configuration_manager::rsync_parallel(void) const
1578 {
1579  if (!initialized())
1580  throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
1581 
1582  return(m_rsync_parallel);
1583 }
1584 
1585 /** Return the number of seconds to sleep between polling for I/O */
1587 {
1588  if (!initialized())
1589  throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
1590 
1591  return(m_io_poll_interval);
1592 }
1593 
1594 /** Return the timestamp-resolution */
1596 {
1597  if (!initialized())
1598  throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
1599 
1600  return(m_timestamp.resolution());
1601 }
1602 
1603 /** Return the vaults */
1605 {
1606  if (!initialized())
1607  throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
1608 
1609  return(m_vaults);
1610 }
1611 
1612 /** Return the vault-overflow-behavior */
1614 {
1615  if (!initialized())
1616  throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
1617 
1618  return(m_vault_overflow_behavior);
1619 }
1620 
1621 /** Return the vault-overflow-blocks */
1623 {
1624  if (!initialized())
1625  throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
1626 
1627  return(m_vault_overflow_blocks);
1628 }
1629 
1630 /** Return the vault-overflow-inodes */
1632 {
1633  if (!initialized())
1634  throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
1635 
1636  return(m_vault_overflow_inodes);
1637 }
1638 
1639 /** Return the vault-selection-behavior */
1641 {
1642  if (!initialized())
1643  throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
1644 
1646 }
1647 
1648 /** Return the vault-locking selection */
1650 {
1651  if (!initialized())
1652  throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
1653 
1654  return(m_vault_locking);
1655 }
1656 
1657 /** Return the default job configuration */
1659 {
1660  if (!initialized())
1661  throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
1662 
1663  return(m_default_job);
1664 }
1665 
1666 /** Return a list of jobs */
1668 {
1669  if (!initialized())
1670  throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
1671 
1672  return(m_jobs);
1673 }
1674 
1675 /** Return the logging-level */
1677 {
1678  if (!initialized())
1679  throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
1680 
1681  return(m_logging_level);
1682 }
1683 
1684 /** Return the error-logging-level */
1686 {
1687  if (!initialized())
1688  throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
1689 
1690  return(m_error_logging_level);
1691 }
1692 
1693 /** Read a configuration file */
1694 void configuration_manager::read_config(const std::string& a_path)
1695 {
1696  std::string es;
1697  std::ifstream in;
1698  uint16 line = 0;
1699 
1700  in.open(a_path.c_str());
1701  if (!in.is_open()) {
1702  TRY_nomem(es = "Could not open configuration file: \"");
1703  TRY_nomem(es += a_path);
1704  TRY_nomem(es += "\"");
1705  throw(ERROR(errno,es));
1706  }
1707 
1708  global_parser(a_path, line, in);
1709 
1710  in.close();
1711  m_configs_read++;
1712 }
1713 
1714 /** Read a job configuration file */
1715 void configuration_manager::read_job(const std::string& a_path)
1716 {
1717  std::string es;
1718  std::ifstream in;
1719  job njob;
1720  uint16 line = 0;
1721 
1722  in.open(a_path.c_str());
1723  if (!in.is_open()) {
1724  TRY_nomem(es = "Could not open job file: \"");
1725  TRY_nomem(es += a_path);
1726  TRY_nomem(es += "\"");
1727  throw(ERROR(errno,es));
1728  }
1729 
1730  njob = m_default_job;
1731 
1732  job_parser(&njob, a_path, line, in, "", false);
1733 
1734  njob.check();
1735 
1736  in.close();
1737 }
1738 
1739 //----------------------------------------------------------------------------
1740 
1741 /** Parse a keyword/value pair read from a configuration file */
1743  std::istream& a_in,
1744  std::string& a_keyword,
1745  std::string& a_value
1746  )
1747 {
1748  std::string es;
1749  char ch;
1750 
1751  a_keyword.erase();
1752  a_value.erase();
1753 
1754  while (true) {
1755  a_in.get(ch);
1756  // Skip whitespace before keyword.
1757  while ((a_in) && ((ch == ' ') || (ch == '\t'))) {
1758  a_in.get(ch);
1759  }
1760  // Read keyword
1761  while ((a_in) && ((ch != ' ') && (ch != '\t') && (ch != '\n'))) {
1762  TRY_nomem(a_keyword += ch);
1763  a_in.get(ch);
1764  }
1765  if (!a_in)
1766  return;
1767 
1768  // If keyword is empty then this is a blank line, skip it.
1769  if (a_keyword.size() == 0)
1770  return;
1771 
1772  // If keyword starts with a '#' then this is a comment line, skip it.
1773  if (a_keyword[0] == '#') {
1774  // Discard the rest of the line.
1775  while ((a_in) && (ch != '\n')) {
1776  a_in.get(ch);
1777  }
1778  return;
1779  }
1780 
1781  a_keyword = estring(a_keyword).lower();
1782 
1783  // If there is not value, return.
1784  if (ch == '\n')
1785  return;
1786 
1787  // Skip whitespace between keyword and value.
1788  a_in.get(ch);
1789  while ((a_in) && ((ch == ' ') || (ch == '\t'))) {
1790  a_in.get(ch);
1791  }
1792  if (!a_in)
1793  return;
1794  a_in.putback(ch);
1795  if (!a_in)
1796  return;
1797 
1798  // Read value
1799  a_in.get(ch);
1800  while ((a_in) && (ch != '\n')) {
1801  TRY_nomem(a_value += ch);
1802  a_in.get(ch);
1803  }
1804  return;
1805  }
1806 }
1807 
1808 /** Given a path, strip off the basename -- like the dirname UNIX command */
1809 const std::string parse_dirname(const std::string& a_path)
1810 {
1811  std::string rpath;
1812 
1813  TRY_nomem(rpath = a_path);
1814 
1815  if (rpath.find_last_of('/') != std::string::npos)
1816  rpath.erase(rpath.find_last_of('/'));
1817 
1818  if (rpath.size() == 0) {
1819  TRY_nomem(rpath = "./");
1820  return(rpath);
1821  }
1822 
1823  if (rpath[rpath.size()-1] != '/') {
1824  TRY_nomem(rpath += '/');
1825  }
1826 
1827  return(rpath);
1828 }
1829 
1830 /** Given a path, strip off the directory -- like the basename UNIX commane */
1831 const std::string parse_basename(const std::string& a_path)
1832 {
1833  std::string es;
1834  std::string rpath;
1835 
1836  TRY_nomem(rpath = a_path);
1837 
1838  if (rpath.find_last_of('/') != std::string::npos)
1839  rpath.erase(0,rpath.find_last_of('/'));
1840 
1841  return(rpath);
1842 }
1843 
1844 //----------------------------------------------------------------------------
1845 
1846 /** C'tor */
1848  const std::string& a_path,
1849  uint16& a_line,
1850  std::istream& a_in
1851  )
1852 {
1853  m_in = &a_in;
1854  m_path = &a_path;
1855  m_line = &a_line;
1856 
1857  parse();
1858 }
1859 
1860 /** Generate a string showing the current location within a configuration file
1861  * of the parser */
1862 const std::string global_parser::location(void)
1863 {
1864  std::string es;
1865 
1866  TRY_nomem(es = "At ");
1867  TRY_nomem(es += (*m_path));
1868  TRY_nomem(es += "[");
1869  TRY_nomem(es += estring((*m_line)));
1870  TRY_nomem(es += "]");
1871 
1872  return(es);
1873 }
1874 
1875 /** Read a configuration file, used by the "include" command */
1876 void global_parser::read_config(const std::string& a_path)
1877 {
1878  std::string es;
1879  std::ifstream in;
1880  uint16 line = 0;
1881 
1882  in.open(a_path.c_str());
1883  if (!in.is_open()) {
1884  TRY_nomem(es = "Could not open configuraiton file: \"");
1885  TRY_nomem(es += a_path);
1886  TRY_nomem(es += "\"");
1887  throw(ERROR(errno,es));
1888  }
1889 
1890  global_parser(a_path, line, in);
1891 
1892  in.close();
1894 }
1895 
1896 /** Read a job configuration file, used by the "include-job" command */
1897 void global_parser::read_job(const std::string& a_path, job& a_job)
1898 {
1899  std::string es;
1900  std::ifstream in;
1901  uint16 line = 0;
1902 
1903  in.open(a_path.c_str());
1904  if (!in.is_open()) {
1905  TRY_nomem(es = "Could not open job file: \"");
1906  TRY_nomem(es += a_path);
1907  TRY_nomem(es += "\"");
1908  throw(ERROR(errno,es));
1909  }
1910 
1911  job_parser(&a_job, a_path, line, in, "", false);
1912 
1913  TRY_nomem(a_job.config_path = *m_path);
1914  TRY_nomem(a_job.config_line = *m_line);
1915  a_job.check();
1916 
1917  in.close();
1918 }
1919 
1920 /** Global context parser */
1922 {
1923  std::string es;
1924  std::string keyword;
1925  std::string value;
1926 
1927  while ((*m_in)) {
1928  (*m_line)++;
1929 
1930  try {
1931  parse_line((*m_in), keyword, value);
1932  }
1933  catch(error e) {
1935  throw(e);
1936  }
1937  catch(...) {
1938  error e = err_unknown;
1939 
1941  throw(e);
1942  }
1943 
1944  if (keyword.size() == 0)
1945  continue;
1946  if (keyword[0] == '#')
1947  continue;
1948 
1949  try {
1950  if (keyword == "<default>") {
1951  parse_default(value);
1952  }
1953  else if (keyword == "include") {
1954  parse_include(value);
1955  }
1956  else if (keyword == "include-job") {
1957  parse_include_job(value);
1958  }
1959  else if (keyword == "<job>") {
1960  parse_job(value);
1961  }
1962  else if (keyword == "link-catalog-dir") {
1963  parse_link_catalog_dir(value);
1964  }
1965  else if (keyword == "log-dir") {
1966  parse_log_dir(value);
1967  }
1968  else if (keyword == "delete-old-log-files") {
1970  }
1971  else if (keyword == "delete-old-report-files") {
1973  }
1974  else if (keyword == "logging-level") {
1975  parse_logging_level(value);
1976  }
1977  else if (keyword == "error-logging-level") {
1979  }
1980  else if (keyword == "rsync-local-path") {
1981  parse_rsync_local_path(value);
1982  }
1983  else if (keyword == "delete-command-path") {
1985  }
1986  else if (keyword == "ssh-local-path") {
1987  parse_ssh_local_path(value);
1988  }
1989  else if (keyword == "rsync-parallel") {
1990  parse_rsync_parallel(value);
1991  }
1992  else if (keyword == "io-poll-interval") {
1993  parse_io_poll_interval(value);
1994  }
1995  else if (keyword == "timestamp-resolution") {
1997  }
1998  else if (keyword == "vault") {
1999  try {
2000  parse_vault(value);
2001  }
2002  catch(error e) {
2003  std::cerr << e;
2004  }
2005  catch(...) {
2006  throw(err_unknown);
2007  }
2008  }
2009  else if (keyword == "vault-overflow-behavior") {
2011  }
2012  else if (keyword == "vault-overflow-blocks") {
2014  }
2015  else if (keyword == "vault-overflow-inodes") {
2017  }
2018  else if (keyword == "vault-selection-behavior") {
2020  }
2021  else if (keyword == "vault-locking") {
2022  parse_vault_locking(value);
2023  }
2024  else {
2025  error e(0);
2026 
2027  TRY_nomem(es = "Unknown command in global context: \"");
2028  TRY_nomem(es += keyword);
2029  TRY_nomem(es += "\"");
2030  throw(ERROR(0,es));
2031  }
2032  }
2033  catch(error e) {
2035  throw(e);
2036  }
2037  catch(...) {
2038  error e = err_unknown;
2039 
2041  throw(e);
2042  }
2043  }
2044 }
2045 
2046 /** Parse a default job context */
2047 void global_parser::parse_default(const std::string& a_value)
2048 {
2049  std::string delimiter;
2050  std::string default_config_path;
2051  uint16 default_config_line;
2052  job* jobPtr = &config.m_default_job;
2053 
2055 
2056  TRY_nomem(default_config_path = *m_path);
2057  TRY_nomem(default_config_line = *m_line);
2058  TRY_nomem(delimiter = "</default>");
2059 
2060  job_parser(jobPtr, *m_path, *m_line, *m_in, delimiter, true);
2061 
2062  TRY_nomem(jobPtr->default_config_path = default_config_path);
2063  jobPtr->default_config_line = default_config_line;
2064 }
2065 
2066 /** Parse an "include" command */
2067 void global_parser::parse_include(const std::string& a_value)
2068 {
2069  std::string es;
2070  directory dir;
2071  directory::const_iterator cdi;
2072  std::string rpath;
2073  std::string ipath;
2074 
2075  if (a_value.size() == 0) {
2076  TRY_nomem(es = "Invalid include path: \"");
2077  TRY_nomem(es += a_value);
2078  TRY_nomem(es += "\"");
2079  throw(ERROR(0,es));
2080  }
2081 
2082  if (a_value[0] != '/') {
2083  TRY_nomem(rpath = parse_dirname(*m_path));
2084  }
2085 
2086  TRY_nomem(ipath = rpath + a_value);
2087 
2088  TRY_nomem(es = "No configuration file(s) found: \"");
2089  TRY_nomem(es += a_value);
2090  TRY_nomem(es += "\"");
2091  TRY_instead(dir.path(ipath),es);
2092  if (dir.size() == 0)
2093  throw(ERROR(0,es));
2094 
2095  for (cdi = dir.begin(); cdi != dir.end(); cdi++) {
2096  if (dir.size() > 1) {
2097  TRY_nomem(es = "For files found matching: \"");
2098  TRY_nomem(es += a_value);
2099  TRY_nomem(es += "\"");
2100  try {
2101  read_config(*cdi);
2102  }
2103  catch(error e) {
2104  e.push_back(ERROR_INSTANCE(es));
2105  throw(e);
2106  }
2107  catch(...) {
2108  error e = err_unknown;
2109 
2110  e.push_back(ERROR_INSTANCE(es));
2111  throw(e);
2112  }
2113  }
2114  else
2115  read_config(*cdi);
2116  }
2117 }
2118 
2119 /** Parse an "include-job" command */
2120 void global_parser::parse_include_job(const std::string& a_value)
2121 {
2122  std::string es;
2123  directory dir;
2124  directory::const_iterator cdi;
2125  std::string rpath;
2126  std::string ipath;
2127 
2128  if (a_value.size() == 0) {
2129  TRY_nomem(es = "Invalid include-job path: \"");
2130  TRY_nomem(es += a_value);
2131  TRY_nomem(es += "\"");
2132  throw(ERROR(0,es));
2133  }
2134 
2135  if (a_value[0] != '/') {
2136  TRY_nomem(rpath = parse_dirname(*m_path));
2137  }
2138 
2139  TRY_nomem(ipath = rpath + a_value);
2140 
2141  TRY_nomem(es = "No job file(s) found: \"");
2142  TRY_nomem(es += a_value);
2143  TRY_nomem(es += "\"");
2144  TRY(dir.path(ipath),es);
2145  if (dir.size() == 0)
2146  throw(ERROR(0,es));
2147 
2148  for (cdi = dir.begin(); cdi != dir.end(); cdi++) {
2149  job new_job;
2150 
2151  new_job = config.m_default_job;
2152 
2153  if (dir.size() > 1) {
2154  TRY_nomem(es = "For files found matching: \"");
2155  TRY_nomem(es += a_value);
2156  TRY_nomem(es += "\"");
2157  try {
2158  read_job(*cdi, new_job);
2159  }
2160  catch(error e) {
2161  e.push_back(ERROR_INSTANCE(es));
2162  throw(e);
2163  }
2164  catch(...) {
2165  error e = err_unknown;
2166 
2167  e.push_back(ERROR_INSTANCE(es));
2168  throw(e);
2169  }
2170  }
2171  else
2172  read_job(*cdi, new_job);
2173  TRY_nomem(config.m_jobs.push_back(new_job));
2174  }
2175 }
2176 
2177 /** Parse a job context */
2178 void global_parser::parse_job(const std::string& a_value)
2179 {
2180  std::string delimiter;
2181  std::string config_path;
2182  uint16 config_line;
2183  job new_job;
2184 
2185  TRY_nomem(config_path = *m_path);
2186  config_line = *m_line;
2187  new_job = config.m_default_job;
2188 
2189  TRY_nomem(new_job.config_path = config_path);
2190  new_job.config_line = config_line;
2191  TRY_nomem(delimiter = "</job>");
2192 
2193  job_parser(&new_job, *m_path, *m_line, *m_in, delimiter, false);
2194 
2195  new_job.check();
2196 
2197  TRY_nomem(config.m_jobs.push_back(new_job));
2198 }
2199 
2200 /** Parse a "link-catalog-dir" command */
2201 void global_parser::parse_link_catalog_dir(const std::string& a_value)
2202 {
2203  std::string es;
2204  subdirectory subdir;
2205 
2206  TRY_nomem(es = "Invalid link-catalog-dir path: \"");
2207  TRY_nomem(es += a_value);
2208  TRY_nomem(es += "\"");
2209  TRY_instead(subdir.path(a_value,"*"),es);
2210  TRY_nomem(config.m_link_catalog_dir = a_value);
2211 }
2212 
2213 /** Parse a "log-dir" command */
2214 void global_parser::parse_log_dir(const std::string& a_value)
2215 {
2216  std::string es;
2217  subdirectory subdir;
2218 
2219  TRY_nomem(es = "Invalid log-dir path: \"");
2220  TRY_nomem(es += a_value);
2221  TRY_nomem(es += "\"");
2222  TRY_instead(subdir.path(a_value,"*"),es);
2223  TRY_nomem(config.m_log_dir = a_value);
2224 }
2225 
2226 /** Parse a "delete-old-log-files" command */
2227 void global_parser::parse_delete_old_log_files(const std::string& a_value)
2228 {
2229  std::string es;
2230  estring str;
2231 
2232  TRY_nomem(es = "Invalid delete-old-log-files value: \"");
2233  TRY_nomem(es += a_value);
2234  TRY_nomem(es += "\"");
2235  TRY(str = estring(a_value).lower(),es);
2236  if (
2237  (str == "y")
2238  || (str == "yes")
2239  || (str == "t")
2240  || (str == "true")
2241  || (str == "1")
2242  || (str == "on")
2243  ) {
2245  }
2246  else if (
2247  (str == "n")
2248  || (str == "no")
2249  || (str == "f")
2250  || (str == "false")
2251  || (str == "0")
2252  || (str == "off")
2253  ) {
2255  }
2256  else {
2257  throw(ERROR(0,es));
2258  }
2259 }
2260 
2261 /** Parse a "delete-old-report-files" command */
2262 void global_parser::parse_delete_old_report_files(const std::string& a_value)
2263 {
2264  std::string es;
2265  estring str;
2266 
2267  TRY_nomem(es = "Invalid delete-old-report-files value: \"");
2268  TRY_nomem(es += a_value);
2269  TRY_nomem(es += "\"");
2270  TRY(str = estring(a_value).lower(),es);
2271  if (
2272  (str == "y")
2273  || (str == "yes")
2274  || (str == "t")
2275  || (str == "true")
2276  || (str == "1")
2277  || (str == "on")
2278  ) {
2280  }
2281  else if (
2282  (str == "n")
2283  || (str == "no")
2284  || (str == "f")
2285  || (str == "false")
2286  || (str == "0")
2287  || (str == "off")
2288  ) {
2290  }
2291  else {
2292  throw(ERROR(0,es));
2293  }
2294 }
2295 
2296 /** Parse a "loging-level" command */
2297 void global_parser::parse_logging_level(const std::string& a_value)
2298 {
2299  std::string es;
2300  estring str;
2301 
2302  TRY_nomem(es = "Invalid logging-level value: \"");
2303  TRY_nomem(es += a_value);
2304  TRY_nomem(es += "\"");
2305  TRY_nomem(str = estring(a_value).lower());
2306  if (str == "manager") {
2308  }
2309  else if (str == "child") {
2311  }
2312  else if (str == "rsync") {
2314  }
2315  else {
2316  throw(ERROR(0,es));
2317  }
2318 }
2319 
2320 /** Parse a "error-loging-level" command */
2321 void global_parser::parse_error_logging_level(const std::string& a_value)
2322 {
2323  std::string es;
2324  estring str;
2325 
2326  TRY_nomem(es = "Invalid error-logging-level value: \"");
2327  TRY_nomem(es += a_value);
2328  TRY_nomem(es += "\"");
2329  TRY_nomem(str = estring(a_value).lower());
2330  if (str == "manager") {
2332  }
2333  else if (str == "child") {
2335  }
2336  else if (str == "rsync") {
2338  }
2339  else {
2340  throw(ERROR(0,es));
2341  }
2342 }
2343 
2344 /** Parse an "rsync-local-path" command */
2345 void global_parser::parse_rsync_local_path(const std::string& a_value)
2346 {
2347  std::string es;
2348  filestatus fstat;
2349 
2350  TRY_nomem(es = "Invalid rsync-local-path value: \"");
2351  TRY_nomem(es += a_value);
2352  TRY_nomem(es += "\"");
2353  TRY_instead(fstat.path(a_value),es);
2354  TRY_nomem(config.m_rsync_local_path = a_value);
2355 }
2356 
2357 /** Parse an "delete-command-path" command */
2358 void global_parser::parse_delete_command_path(const std::string& a_value)
2359 {
2360  std::string es;
2361  filestatus fstat;
2362 
2363  TRY_nomem(es = "Invalid delete-command-path value: \"");
2364  TRY_nomem(es += a_value);
2365  TRY_nomem(es += "\"");
2366  TRY_instead(fstat.path(a_value),es);
2368 }
2369 
2370 /** Parse an "ssh-local-path" command */
2371 void global_parser::parse_ssh_local_path(const std::string& a_value)
2372 {
2373  std::string es;
2374  filestatus fstat;
2375 
2376  TRY_nomem(es = "Invalid ssh-local-path value: \"");
2377  TRY_nomem(es += a_value);
2378  TRY_nomem(es += "\"");
2379  TRY_instead(fstat.path(a_value),es);
2380  TRY_nomem(config.m_ssh_local_path = a_value);
2381 }
2382 
2383 /** Parse an "rsync-parallel" command */
2384 void global_parser::parse_rsync_parallel(const std::string& a_value)
2385 {
2386  std::string es;
2387  uint16 num;
2388 
2389  TRY_nomem(es = "Invalid rsync-parallel value: \"");
2390  TRY_nomem(es += a_value);
2391  TRY_nomem(es += "\"");
2392  TRY_instead(num = estring(a_value),es);
2393  if (num == 0)
2394  throw(ERROR(0,es));
2395  config.m_rsync_parallel = num;
2396 }
2397 
2398 /** Parse "io-poll-interval" command */
2399 void global_parser::parse_io_poll_interval(const std::string& a_value)
2400 {
2401  std::string es;
2402  uint16 num;
2403 
2404  TRY_nomem(es = "Invalid io-poll-interval value: \"");
2405  TRY_nomem(es += a_value);
2406  TRY_nomem(es += "\"");
2407  TRY_instead(num = estring(a_value),es);
2408  if (num == 0)
2409  throw(ERROR(0,es));
2410  config.m_io_poll_interval = num;
2411 }
2412 
2413 /** Parse a "timestamp-resolution" command */
2414 void global_parser::parse_timestamp_resolution(const std::string& a_value)
2415 {
2416  std::string es;
2417  estring str;
2418 
2419  TRY_nomem(es = "Invalid timestamp-resolution: \"");
2420  TRY_nomem(es += a_value);
2421  TRY_nomem(es += "\"");
2422  TRY(str = estring(a_value).lower(),es);
2423  if (str == "year") {
2425  }
2426  else if (str == "month") {
2428  }
2429  else if (str == "day") {
2431  }
2432  else if (str == "hour") {
2434  }
2435  else if (str == "minute") {
2437  }
2438  else if (str == "second") {
2440  }
2441  else {
2442  throw(ERROR(0,es));
2443  }
2444 }
2445 
2446 /** Parse a "vault" command */
2447 void global_parser::parse_vault(const std::string& a_value)
2448 {
2449  std::string es;
2450  directory dir;
2451  directory::const_iterator cdi;
2452  subdirectory subdir;
2453  filestatus fstat;
2454  error partial_vault_error = ERROR(0,"One or more vault paths were found to be invalid:");
2455 
2456  TRY_nomem(es = "Invalid vault path: \"");
2457  TRY_nomem(es += a_value);
2458  TRY_nomem(es += "\"");
2459 
2460  if (a_value.size() == 0)
2461  throw(ERROR(0,es));
2462 
2463  TRY(dir.path(a_value),es);
2464 
2465  if (dir.size() == 0) {
2466  TRY_instead(fstat.path(a_value),es);
2467  }
2468 
2469  for (cdi = dir.begin(); cdi != dir.end(); cdi++) {
2470  if (!is_dir(*cdi)) {
2471  TRY_nomem(es = get_error_str(ENOTDIR));
2472  TRY_nomem(es += ": \"");
2473  TRY_nomem(es += *cdi);
2474  TRY_nomem(es += "\"");
2475  partial_vault_error.push_back(es);
2476  continue;
2477  }
2478  if (!readable(*cdi)) {
2479  TRY_nomem(es = "No read access to path: \"");
2480  TRY_nomem(es += *cdi);
2481  TRY_nomem(es += "\"");
2482  partial_vault_error.push_back(es);
2483  continue;
2484  }
2485  if (!writable(*cdi)) {
2486  TRY_nomem(es = "No write access to path: \"");
2487  TRY_nomem(es += *cdi);
2488  TRY_nomem(es += "\"");
2489  partial_vault_error.push_back(es);
2490  continue;
2491  }
2492  if (!executable(*cdi)) {
2493  TRY_nomem(es = "No execution access to path: \"");
2494  TRY_nomem(es += *cdi);
2495  TRY_nomem(es += "\"");
2496  partial_vault_error.push_back(es);
2497  continue;
2498  }
2499  TRY_nomem(config.m_vaults.push_back(*cdi));
2500  }
2501 
2502  if (partial_vault_error.size() > 1) {
2503  TRY_nomem(es = "For paths found matching: \"");
2504  TRY_nomem(es += a_value);
2505  TRY_nomem(es += "\"");
2506  partial_vault_error.push_back(es);
2507  throw(partial_vault_error);
2508  }
2509 }
2510 
2511 /** Parse a "vault-overflow-behavior" command */
2512 void global_parser::parse_vault_overflow_behavior(const std::string& a_value)
2513 {
2514  std::string es;
2515  estring str;
2516 
2517  TRY_nomem(es = "Invalid vault-overflow-behavior value: \"");
2518  TRY_nomem(es += a_value);
2519  TRY_nomem(es += "\"");
2520  TRY(str = estring(a_value).lower(),es);
2521  if (str == "quit") {
2523  }
2524  else if (str == "delete-oldest") {
2526  }
2527  else if (str == "delete-until-free") {
2529  }
2530  else {
2531  throw(ERROR(0,es));
2532  }
2533 }
2534 
2535 /** Parse a "vault-overflow-blocks" command */
2536 void global_parser::parse_vault_overflow_blocks(const std::string& a_value)
2537 {
2538  std::string es;
2539  uint16 num;
2540 
2541  TRY_nomem(es = "Invalid vault-overflow-blocks value: \"");
2542  TRY_nomem(es += a_value);
2543  TRY_nomem(es += "\"");
2544  TRY(num = estring(a_value),es);
2545  if (num > 50)
2546  throw(ERROR(0,es));
2548 }
2549 
2550 /** Parse a "vault-overflow-inodes" command */
2551 void global_parser::parse_vault_overflow_inodes(const std::string& a_value)
2552 {
2553  std::string es;
2554  uint16 num;
2555 
2556  TRY_nomem(es = "Invalid vault-overflow-inodes value: \"");
2557  TRY_nomem(es += a_value);
2558  TRY_nomem(es += "\"");
2559  TRY(num = estring(a_value),es);
2560  if (num > 50)
2561  throw(ERROR(0,es));
2563 }
2564 
2565 /** Parse a "vault-selection-behavior" command */
2566 void global_parser::parse_vault_selection_behavior(const std::string& a_value)
2567 {
2568  std::string es;
2569  estring str;
2570 
2571  TRY_nomem(es = "Invalid vault-selection-behavior value: \"");
2572  TRY_nomem(es += a_value);
2573  TRY_nomem(es += "\"");
2574  TRY(str = estring(a_value).lower(),es);
2575  if (str == "max-free") {
2577  }
2578  else if (str == "round-robin") {
2580  }
2581  else {
2582  throw(ERROR(0,es));
2583  }
2584 }
2585 
2586 /** Parse a "vault-locking" command */
2587 void global_parser::parse_vault_locking(const std::string& a_value)
2588 {
2589  std::string es;
2590  estring str;
2591 
2592  TRY_nomem(es = "Invalid vault-locking value: \"");
2593  TRY_nomem(es += a_value);
2594  TRY_nomem(es += "\"");
2595  TRY(str = estring(a_value).lower(),es);
2596  if (
2597  (str == "y")
2598  || (str == "yes")
2599  || (str == "t")
2600  || (str == "true")
2601  || (str == "1")
2602  || (str == "on")
2603  ) {
2604  config.m_vault_locking = true;
2605  }
2606  else if (
2607  (str == "n")
2608  || (str == "no")
2609  || (str == "f")
2610  || (str == "false")
2611  || (str == "0")
2612  || (str == "off")
2613  ) {
2614  config.m_vault_locking = false;
2615  }
2616  else {
2617  throw(ERROR(0,es));
2618  }
2619 }
2620 
2621 //----------------------------------------------------------------------------
2622 
2623 /** C'tor */
2625  job * a_job,
2626  const std::string& a_path,
2627  uint16& a_line,
2628  std::istream& a_in,
2629  const std::string& a_block_delimiter,
2630  const bool a_default_context = false
2631  )
2632 {
2633  m_job = a_job;
2634  m_in = &a_in;
2635  m_path = &a_path;
2636  m_line = &a_line;
2637  m_delimiter = &a_block_delimiter;
2638  m_default_context = a_default_context;
2639 
2640  parse();
2641 }
2642 
2643 /** Construct a string with the current location of the parser in a
2644  * configuration file */
2645 const std::string job_parser::location(void)
2646 {
2647  std::string es;
2648 
2649  TRY_nomem(es = "At ");
2650  TRY_nomem(es += (*m_path));
2651  TRY_nomem(es += "[");
2652  TRY_nomem(es += estring((*m_line)));
2653  TRY_nomem(es += "]");
2654 
2655  return(es);
2656 }
2657 
2658 /** Read a job configuration file, used by the "include" command */
2659 void job_parser::read_job(const std::string& a_path)
2660 {
2661  std::string es;
2662  std::ifstream in;
2663  uint16 line = 0;
2664 
2665  in.open(a_path.c_str());
2666  if (!in.is_open()) {
2667  TRY_nomem(es = "Could not open job file: \"");
2668  TRY_nomem(es += a_path);
2669  TRY_nomem(es += "\"");
2670  throw(ERROR(errno,es));
2671  }
2672 
2673  job_parser(m_job, a_path, line, in, "", m_default_context);
2674 
2675  in.close();
2676 }
2677 
2678 /** Job context parser */
2680 {
2681  std::string es;
2682  std::string keyword;
2683  std::string value;
2684 
2685  while ((*m_in)) {
2686  (*m_line)++;
2687 
2688  try {
2689  parse_line((*m_in), keyword, value);
2690  }
2691  catch(error e) {
2693  throw(e);
2694  }
2695  catch(...) {
2696  error e = err_unknown;
2697 
2699  throw(e);
2700  }
2701 
2702  if (!(*m_in) && (m_delimiter->size() != 0)) {
2703  TRY_nomem(es = "Unexpected end of file, expected \"");
2704  TRY_nomem(es += *m_delimiter);
2705  TRY_nomem(es += "\" here");
2706  throw(ERROR(errno,es));
2707  }
2708 
2709  if (keyword.size() == 0)
2710  continue;
2711  if (keyword[0] == '#')
2712  continue;
2713 
2714  try {
2715  if (keyword == *m_delimiter) {
2716  return;
2717  }
2718  else if (keyword == "archive-path") {
2719  parse_archive_path(value);
2720  }
2721  else if (keyword == "clear") {
2722  parse_clear(value);
2723  }
2724  else if (keyword == "exclude-from") {
2725  parse_exclude_from(value);
2726  }
2727  else if (keyword == "include-from") {
2728  parse_include_from(value);
2729  }
2730  else if (keyword == "groupname") {
2731  parse_groupname(value);
2732  }
2733  else if (keyword == "hostname") {
2734  parse_hostname(value);
2735  }
2736  else if (keyword == "include") {
2737  parse_include(value);
2738  }
2739  else if ((keyword == "jobname") && (*m_delimiter == "</job>")) {
2740  parse_jobname(value);
2741  }
2742  else if (keyword == "path") {
2743  parse_path(value);
2744  }
2745  else if (keyword == "rsync-behavior") {
2746  parse_rsync_behavior(value);
2747  }
2748  else if (keyword == "rsync-connection-type") {
2750  }
2751  else if (keyword == "rsync-hardlink") {
2752  parse_rsync_hardlink(value);
2753  }
2754  else if (keyword == "rsync-multi-hardlink") {
2756  }
2757  else if (keyword == "rsync-multi-hardlink-max") {
2759  }
2760  else if (keyword == "rsync-options") {
2761  parse_rsync_options(value);
2762  }
2763  else if (keyword == "ssh-options") {
2764  parse_ssh_options(value);
2765  }
2766  else if (keyword == "<rsync-options>") {
2768  }
2769  else if (keyword == "<ssh-options>") {
2771  }
2772  else if (keyword == "rsync-remote-user") {
2773  parse_rsync_remote_user(value);
2774  }
2775  else if (keyword == "rsync-remote-path") {
2776  parse_rsync_remote_path(value);
2777  }
2778  else if (keyword == "rsync-remote-port") {
2779  parse_rsync_remote_port(value);
2780  }
2781  else if (keyword == "rsync-remote-module") {
2783  }
2784  else if (keyword == "rsync-retry-count") {
2785  parse_rsync_retry_count(value);
2786  }
2787  else if (keyword == "rsync-retry-delay") {
2788  parse_rsync_retry_delay(value);
2789  }
2790  else if (keyword == "rsync-timeout") {
2791  parse_rsync_timeout(value);
2792  }
2793  else {
2794  error e(0);
2795 
2796  TRY_nomem(es = "Unknown command in ");
2797  if (m_default_context) {
2798  TRY_nomem(es += "default");
2799  }
2800  else {
2801  TRY_nomem(es += "job");
2802  }
2803  TRY_nomem(es += " context: \"");
2804  TRY_nomem(es += keyword);
2805  TRY_nomem(es += "\"");
2806  throw(ERROR(0,es));
2807  }
2808  }
2809  catch(error e) {
2810  if ((*m_delimiter).size() == 0)
2812  throw(e);
2813  }
2814  catch(...) {
2815  error e = err_unknown;
2816 
2818  throw(e);
2819  }
2820  }
2821 }
2822 
2823 /** Parse an "archive-path" command */
2824 void job_parser::parse_archive_path(const std::string& a_value)
2825 {
2826  std::string es;
2827 
2828  TRY_nomem(es = "Invalid archive-path value");
2829  TRY((*m_job).archive_path = a_value,es);
2830 }
2831 
2832 /** Parse a "clear" command */
2833 void job_parser::parse_clear(const std::string& a_value)
2834 {
2835  std::string es;
2836  estring str;
2837 
2838  TRY_nomem(es = "Invalid clear value: \"");
2839  TRY_nomem(es += a_value);
2840  TRY_nomem(es += "\"");
2841  TRY(str = estring(a_value).lower(),es);
2842  if (str == "archive-path") {
2843  m_job->archive_path.clear();
2844  }
2845  else if (str == "exclude-from") {
2846  m_job->excludes.clear();
2847  }
2848  else if (str == "groupname") {
2849  m_job->groupname.erase();
2850  }
2851  else if (str == "hostname") {
2852  m_job->hostname.erase();
2853  }
2854  else if (str == "include-from") {
2855  m_job->includes.clear();
2856  }
2857  else if ((str == "jobname") && (*m_delimiter == "</job>")) {
2858  m_job->jobname.erase();
2859  }
2860  else if (str == "paths") {
2861  m_job->paths.clear();
2862  }
2863  else if (str == "rsync-behavior") {
2865  }
2866  else if (str == "rsync-options") {
2867  m_job->rsync_options.erase();
2868  }
2869  else if (str == "ssh-options") {
2870  m_job->ssh_options.erase();
2871  }
2872  else if (str == "rsync-remote-user") {
2873  m_job->rsync_remote_user.erase();
2874  }
2875  else if (str == "rsync-remotr-port") {
2876  m_job->rsync_remote_port = 0;
2877  }
2878  else if (str == "rsync-remote-module") {
2879  m_job->rsync_remote_module.erase();
2880  }
2881  else if (str == "rsync-remote-path") {
2882  m_job->rsync_remote_path.erase();
2883  }
2884  else {
2885  throw(ERROR(0,es));
2886  }
2887 }
2888 
2889 /** Parse an "exclude-from" command */
2890 void job_parser::parse_exclude_from(const std::string& a_value)
2891 {
2892  std::string es;
2893  directory dir;
2894  directory::const_iterator cdi;
2895  std::string rpath;
2896  std::string ipath;
2897 
2898  if (a_value.size() == 0) {
2899  TRY_nomem(es = "Invalid exclude-from path: \"");
2900  TRY_nomem(es += a_value);
2901  TRY_nomem(es += "\"");
2902  throw(ERROR(0,es));
2903  }
2904 
2905  if (a_value[0] != '/') {
2906  TRY_nomem(rpath = parse_dirname(*m_path));
2907  }
2908 
2909  TRY_nomem(ipath = rpath + a_value);
2910 
2911  TRY_nomem(es = "No exclude-from file(s) found: \"");
2912  TRY_nomem(es += a_value);
2913  TRY_nomem(es += "\"");
2914  TRY(dir.path(ipath),es);
2915  if (dir.size() == 0)
2916  throw(ERROR(0,es));
2917 
2918  for (cdi = dir.begin(); cdi != dir.end(); cdi++) {
2919  TRY_nomem((*m_job).excludes.push_back(*cdi));
2920  }
2921 }
2922 
2923 /** Parse an "include-from" command */
2924 void job_parser::parse_include_from(const std::string& a_value)
2925 {
2926  std::string es;
2927  directory dir;
2928  directory::const_iterator cdi;
2929  std::string rpath;
2930  std::string ipath;
2931 
2932  if (a_value.size() == 0) {
2933  TRY_nomem(es = "Invalid include-from path: \"");
2934  TRY_nomem(es += a_value);
2935  TRY_nomem(es += "\"");
2936  throw(ERROR(0,es));
2937  }
2938 
2939  if (a_value[0] != '/') {
2940  TRY_nomem(rpath = parse_dirname(*m_path));
2941  }
2942 
2943  TRY_nomem(ipath = rpath + a_value);
2944 
2945  TRY_nomem(es = "No include-from file(s) found: \"");
2946  TRY_nomem(es += a_value);
2947  TRY_nomem(es += "\"");
2948  TRY(dir.path(ipath),es);
2949  if (dir.size() == 0)
2950  throw(ERROR(0,es));
2951 
2952  for (cdi = dir.begin(); cdi != dir.end(); cdi++) {
2953  TRY_nomem((*m_job).includes.push_back(*cdi));
2954  }
2955 }
2956 
2957 /** Parse a "groupname" command */
2958 void job_parser::parse_groupname(const std::string& a_value)
2959 {
2960  TRY_nomem((*m_job).groupname = a_value);
2961 }
2962 
2963 /** Parse a "hostname" command */
2964 void job_parser::parse_hostname(const std::string& a_value)
2965 {
2966  TRY_nomem((*m_job).hostname = a_value);
2967 }
2968 
2969 /** Parse an "include" command */
2970 void job_parser::parse_include(const std::string& a_value)
2971 {
2972  std::string es;
2973  directory dir;
2974  directory::const_iterator cdi;
2975  std::string rpath;
2976  std::string ipath;
2977 
2978  if (a_value.size() == 0) {
2979  TRY_nomem(es = "Invalid include path: \"");
2980  TRY_nomem(es += a_value);
2981  TRY_nomem(es += "\"");
2982  throw(ERROR(0,es));
2983  }
2984 
2985  if (a_value[0] != '/') {
2986  TRY_nomem(rpath = parse_dirname(*m_path));
2987  }
2988 
2989  TRY_nomem(ipath = rpath + a_value);
2990 
2991  TRY_nomem(es = "No configuration file(s) found: \"");
2992  TRY_nomem(es += a_value);
2993  TRY_nomem(es += "\"");
2994  TRY_instead(dir.path(ipath),es);
2995  if (dir.size() == 0)
2996  throw(ERROR(0,es));
2997 
2998  for (cdi = dir.begin(); cdi != dir.end(); cdi++) {
2999  if (dir.size() > 1) {
3000  TRY_nomem(es = "For files found matching: \"");
3001  TRY_nomem(es += a_value);
3002  TRY_nomem(es += "\"");
3003  try {
3004  read_job(*cdi);
3005  }
3006  catch(error e) {
3007  e.push_back(ERROR_INSTANCE(es));
3008  throw(e);
3009  }
3010  catch(...) {
3011  error e = err_unknown;
3012 
3013  e.push_back(ERROR_INSTANCE(es));
3014  throw(e);
3015  }
3016  }
3017  else
3018  read_job(*cdi);
3019  }
3020 }
3021 
3022 /** Parse a "jobname" command */
3023 void job_parser::parse_jobname(const std::string& a_value)
3024 {
3025  TRY_nomem((*m_job).jobname = a_value);
3026 }
3027 
3028 /** Parse a "path" command */
3029 void job_parser::parse_path(const std::string& a_value)
3030 {
3031  TRY_nomem((*m_job).paths.push_back(a_value));
3032 }
3033 
3034 /** Parse an "rsync-behavior" command */
3035 void job_parser::parse_rsync_behavior(const std::string& a_value)
3036 {
3037  std::string es;
3038  estring str;
3039 
3040  TRY_nomem(es = "Invalid rsync-behavior value: \"");
3041  TRY_nomem(es += a_value);
3042  TRY_nomem(es += "\"");
3043  TRY(str = estring(a_value).lower(),es);
3044  if (str == "clear") {
3045  (*m_job).rsync_behavior.clear();
3046  }
3047  else if (str == "reset") {
3048  (*m_job).rsync_behavior.reset();
3049  }
3050  else
3051  (*m_job).rsync_behavior.assign(a_value);
3052 }
3053 
3054 /** Parse an "rsync-connection-type" command */
3055 void job_parser::parse_rsync_connection_type(const std::string& a_value)
3056 {
3057  std::string es;
3058  estring str;
3059 
3060  TRY_nomem(es = "Invalid rsync-connection-type value: \"");
3061  TRY_nomem(es += a_value);
3062  TRY_nomem(es += "\"");
3063  TRY(str = estring(a_value).lower(),es);
3064  if (str == "local") {
3065  (*m_job).rsync_connection = job::connection_local;
3066  }
3067  else if (str == "remote") {
3068  (*m_job).rsync_connection = job::connection_remote;
3069  }
3070  else if (str == "server") {
3071  (*m_job).rsync_connection = job::connection_server;
3072  }
3073  else if (str == "remote-rsync-local-dir") {
3074  (*m_job).rsync_connection = job::connection_ssh_local;
3075  }
3076  else {
3077  throw(ERROR(0,es));
3078  }
3079 }
3080 
3081 /** Parse an "rsync-hardlink" command */
3082 void job_parser::parse_rsync_hardlink(const std::string& a_value)
3083 {
3084  std::string es;
3085  estring str;
3086 
3087  TRY_nomem(es = "Invalid rsync-hardlink value: \"");
3088  TRY_nomem(es += a_value);
3089  TRY_nomem(es += "\"");
3090  TRY(str = estring(a_value).lower(),es);
3091  if (
3092  (str == "y")
3093  || (str == "yes")
3094  || (str == "t")
3095  || (str == "true")
3096  || (str == "1")
3097  || (str == "on")
3098  ) {
3099  (*m_job).rsync_hardlink = true;
3100  }
3101  else if (
3102  (str == "n")
3103  || (str == "no")
3104  || (str == "f")
3105  || (str == "false")
3106  || (str == "0")
3107  || (str == "off")
3108  ) {
3109  (*m_job).rsync_hardlink = false;
3110  }
3111  else {
3112  throw(ERROR(0,es));
3113  }
3114 }
3115 
3116 /** Parse an "rsync-multi-hardlink" command */
3117 void job_parser::parse_rsync_multi_hardlink(const std::string& a_value)
3118 {
3119  std::string es;
3120  estring str;
3121 
3122  TRY_nomem(es = "Invalid rsync-multi-hardlink value: \"");
3123  TRY_nomem(es += a_value);
3124  TRY_nomem(es += "\"");
3125  TRY(str = estring(a_value).lower(),es);
3126  if (
3127  (str == "y")
3128  || (str == "yes")
3129  || (str == "t")
3130  || (str == "true")
3131  || (str == "1")
3132  || (str == "on")
3133  ) {
3134  (*m_job).rsync_multi_hardlink = true;
3135  (*m_job).rsync_hardlink = true;
3136  }
3137  else if (
3138  (str == "n")
3139  || (str == "no")
3140  || (str == "f")
3141  || (str == "false")
3142  || (str == "0")
3143  || (str == "off")
3144  ) {
3145  (*m_job).rsync_multi_hardlink = false;
3146  }
3147  else {
3148  throw(ERROR(0,es));
3149  }
3150 }
3151 
3152 /** Parse an "rsync-multi-hardlink-max" command */
3153 void job_parser::parse_rsync_multi_hardlink_max(const std::string& a_value)
3154 {
3155  std::string es;
3156  uint16 num;
3157 
3158  TRY_nomem(es = "Invalid rsync-multi-hardlink-max value: \"");
3159  TRY_nomem(es += a_value);
3160  TRY_nomem(es += "\"");
3161  TRY_instead(num = estring(a_value),es);
3162  if (num == 0)
3163  throw(ERROR(0,es));
3164  (*m_job).rsync_multi_hardlink_max = num;
3165 }
3166 
3167 /** Parse an "rsync-options" command */
3168 void job_parser::parse_rsync_options(const std::string& a_value)
3169 {
3170  if (*m_delimiter == "</default>") {
3171  TRY_nomem((*m_job).rsync_options = a_value);
3172  }
3173  else {
3174  if ((*m_job).rsync_options.size() != 0) {
3175  TRY_nomem((*m_job).rsync_options += " ");
3176  }
3177  TRY_nomem((*m_job).rsync_options += a_value);
3178  }
3179 }
3180 
3181 /** Parse an "ssh-options" command */
3182 void job_parser::parse_ssh_options(const std::string& a_value)
3183 {
3184  if (*m_delimiter == "</default>") {
3185  TRY_nomem((*m_job).ssh_options = a_value);
3186  }
3187  else {
3188  if ((*m_job).ssh_options.size() != 0) {
3189  TRY_nomem((*m_job).ssh_options += " ");
3190  }
3191  TRY_nomem((*m_job).ssh_options += a_value);
3192  }
3193 }
3194 
3195 /** Parse an rsync-options context */
3196 void job_parser::parse_rsync_options_context(const std::string& a_value)
3197 {
3198  std::string es;
3199  std::string value;
3200  std::string rsync_options;
3201  char ch;
3202 
3203  while ((*m_in)) {
3204  (*m_line)++;
3205 
3206  value.erase();
3207 
3208  (*m_in).get(ch);
3209  while ((ch == ' ') || (ch == '\t'))
3210  (*m_in).get(ch);
3211  while (((*m_in)) && (ch != '\n')) {
3212  TRY_nomem(value += ch);
3213  (*m_in).get(ch);
3214  }
3215 
3216  if ((!(*m_in)) && (value != "</rsync-options>")) {
3217  TRY_nomem(es = "Unexpected end of file, expected ");
3218  TRY_nomem(es += "\"</rsync-options>\" here");
3219  throw(ERROR(errno,es));
3220  }
3221 
3222  if (value.size() == 0)
3223  continue;
3224  if (value[0] == '#')
3225  continue;
3226 
3227  if (value == "</rsync-options>") {
3228  parse_rsync_options(rsync_options);
3229  return;
3230  }
3231 
3232  if (rsync_options.size() != 0) {
3233  TRY_nomem(rsync_options += ' ');
3234  }
3235  TRY_nomem(rsync_options += value);
3236  }
3237 }
3238 
3239 /** Parse an ssh-options context */
3240 void job_parser::parse_ssh_options_context(const std::string& a_value)
3241 {
3242  std::string es;
3243  std::string value;
3244  std::string ssh_options;
3245  char ch;
3246 
3247  while ((*m_in)) {
3248  (*m_line)++;
3249 
3250  value.erase();
3251 
3252  (*m_in).get(ch);
3253  while ((ch == ' ') || (ch == '\t'))
3254  (*m_in).get(ch);
3255  while (((*m_in)) && (ch != '\n')) {
3256  TRY_nomem(value += ch);
3257  (*m_in).get(ch);
3258  }
3259 
3260  if ((!(*m_in)) && (value != "</ssh-options>")) {
3261  TRY_nomem(es = "Unexpected end of file, expected ");
3262  TRY_nomem(es += "\"</ssh-options>\" here");
3263  throw(ERROR(errno,es));
3264  }
3265 
3266  if (value.size() == 0)
3267  continue;
3268  if (value[0] == '#')
3269  continue;
3270 
3271  if (value == "</ssh-options>") {
3272  parse_ssh_options(ssh_options);
3273  return;
3274  }
3275 
3276  if (ssh_options.size() != 0) {
3277  TRY_nomem(ssh_options += ' ');
3278  }
3279  TRY_nomem(ssh_options += value);
3280  }
3281 }
3282 
3283 /** Parse a "remote-user" command */
3284 void job_parser::parse_rsync_remote_user(const std::string& a_value)
3285 {
3286  TRY_nomem((*m_job).rsync_remote_user = a_value);
3287 }
3288 
3289 /** Parse an "rsync-remote-path" command */
3290 void job_parser::parse_rsync_remote_path(const std::string& a_value)
3291 {
3292  TRY_nomem((*m_job).rsync_remote_path = a_value);
3293 }
3294 
3295 /** Parse an "rsync-remote-port" command */
3296 void job_parser::parse_rsync_remote_port(const std::string& a_value)
3297 {
3298  std::string es;
3299  estring str;
3300  uint16 num;
3301 
3302  TRY_nomem(es = "Invalid rsync-remote-port value: \"");
3303  TRY_nomem(es += a_value);
3304  TRY_nomem(es += "\"");
3305  TRY_nomem(str = a_value);
3306  TRY(num = str,es);
3307  (*m_job).rsync_remote_port = num;
3308 }
3309 
3310 /** Parse an "rsync-remote-module" command */
3311 void job_parser::parse_rsync_remote_module(const std::string& a_value)
3312 {
3313  TRY_nomem((*m_job).rsync_remote_module = a_value);
3314 }
3315 
3316 /** Parse an "rsync-retry-count" command */
3317 void job_parser::parse_rsync_retry_count(const std::string& a_value)
3318 {
3319  std::string es;
3320  estring str;
3321  uint16 num;
3322 
3323  TRY_nomem(es = "Invalid rsync-retry-count value: \"");
3324  TRY_nomem(es += a_value);
3325  TRY_nomem(es += "\"");
3326  TRY_nomem(str = a_value);
3327  TRY(num = str,es);
3328  (*m_job).rsync_retry_count = num;
3329 }
3330 
3331 /** Parse an "rsync-retry-delay" command */
3332 void job_parser::parse_rsync_retry_delay(const std::string& a_value)
3333 {
3334  std::string es;
3335  estring str;
3336  uint16 num;
3337 
3338  TRY_nomem(es = "Invalid rsync-retry-delay value: \"");
3339  TRY_nomem(es += a_value);
3340  TRY_nomem(es += "\"");
3341  TRY_nomem(str = a_value);
3342  TRY(num = str,es);
3343  (*m_job).rsync_retry_delay = num;
3344 }
3345 
3346 /** Parse an "rsync-timeout" command */
3347 void job_parser::parse_rsync_timeout(const std::string& a_value)
3348 {
3349  std::string es;
3350  estring str;
3351  uint16 num;
3352 
3353  TRY_nomem(es = "Invalid rsync-timeout value: \"");
3354  TRY_nomem(es += a_value);
3355  TRY_nomem(es += "\"");
3356  TRY_nomem(str = a_value);
3357  TRY(num = str,es);
3358  (*m_job).rsync_timeout = num;
3359 }
3360 
3361 //----------------------------------------------------------------------------
3362 
3363 /** The global configuration manager instance */
void init(int argc, char const *argv[])
Initialize the configuration manager from rvm's command line options.
Definition: rconfig.cc:1218
std::istream * m_in
Definition: rconfig.h:326
uint16 rsync_multi_hardlink_max
Definition: rconfig.h:178
Timestamp object.
Definition: tstamp.h:13
value_type m_default
Definition: rconfig.h:130
std::string reform_path(const std::string &a_path)
Reformat a path to remove double slashes.
Definition: fs.cc:205
includes_type includes
Definition: rconfig.h:169
rsync_connection_type rsync_connection
Definition: rconfig.h:175
void assign(const job &a_job)
Assign values from another job instance.
Definition: rconfig.cc:600
void parse_exclude_from(const std::string &a_value)
Parse an "exclude-from" command.
Definition: rconfig.cc:2890
const std::string location(void)
Generate a string showing the current location within a configuration file of the parser...
Definition: rconfig.cc:1862
void path(const std::string a_path)
Retrieve information about a pathname.
Definition: fs.cc:824
uint16 rsync_retry_delay
Definition: rconfig.h:186
void parse_rsync_retry_delay(const std::string &a_value)
Parse an "rsync-retry-delay" command.
Definition: rconfig.cc:3332
const std::string & rsync_local_path(void) const
Return the rsync-local-path.
Definition: rconfig.cc:1550
overflow_type m_vault_overflow_behavior
Definition: rconfig.h:287
const type & path(const std::string &a_path)
Retrieve a list of paths that match the wildcard path given.
Definition: fs.cc:1510
void reset(void)
Clear all values and set some sane default actions.
Definition: rconfig.cc:385
#define CONFIGFILE
Definition: config.h:11
void check(void)
Perform sanity checks for the configuration settings of this job.
Definition: rconfig.cc:1016
const std::string generate_job_id(void) const
Generate a unique ID string for this job.
Definition: rconfig.cc:800
uint16 * m_line
Definition: rconfig.h:377
job()
C'tor.
Definition: rconfig.cc:557
const uint16 & vault_overflow_blocks(void) const
Return the vault-overflow-blocks.
Definition: rconfig.cc:1622
void read_job(const std::string &a_path, job &a_job)
Read a job configuration file, used by the "include-job" command.
Definition: rconfig.cc:1897
void parse_path(const std::string &a_value)
Parse a "path" command.
Definition: rconfig.cc:3029
An extended string class.
Definition: estring.h:52
bool m_delete_old_log_files
Definition: rconfig.h:292
jobs_type m_jobs
Definition: rconfig.h:295
configuration_manager()
C'tor.
Definition: rconfig.cc:1208
std::vector< job > jobs_type
Definition: rconfig.h:233
uint16 m_io_poll_interval
Definition: rconfig.h:285
const value_type operator[](const uint16 a_code) const
Return the action to be taken for a given exit code.
Definition: rconfig.cc:496
void clear(void)
Reset to a default value.
Definition: rconfig.cc:22
void parse_clear(const std::string &a_value)
Parse a "clear" command.
Definition: rconfig.cc:2833
uint16 config_line
Definition: rconfig.h:166
std::string ssh_options
Definition: rconfig.h:180
Hold configuration data for a single job.
Definition: rconfig.h:136
void parse_hostname(const std::string &a_value)
Parse a "hostname" command.
Definition: rconfig.cc:2964
bool executable(const std::string &a_path)
Return true if the file or directory exists and is executable.
Definition: fs.cc:437
const char * get_error_str(const int a_err)
Definition: error.cc:389
void clear(void)
Clear values.
Definition: rconfig.cc:570
const value_type default_value(void) const
Return the default action.
Definition: rconfig.cc:543
std::string m_log_dir
Definition: rconfig.h:280
bool m_default_context
Definition: rconfig.h:379
void parse(void)
Job context parser.
Definition: rconfig.cc:2679
const std::string * m_path
Definition: rconfig.h:325
const std::string & value(void) const
Retrieve the current literal value.
Definition: rconfig.cc:151
std::vector< std::string > m_vaults
Definition: rconfig.h:286
const bool delete_old_log_files(void) const
Return the value of delete-old-log-files.
Definition: rconfig.cc:1532
void push_back(const error_instance &a_e)
Definition: error.cc:215
void parse_ssh_options_context(const std::string &a_value)
Parse an ssh-options context.
Definition: rconfig.cc:3240
const std::string generate_source_path(const std::string &a_path) const
Generate the source path to be passed to rsync on the command line.
Definition: rconfig.cc:728
void parse(void)
Global context parser.
Definition: rconfig.cc:1921
void parse_include(const std::string &a_value)
Parse an "include" command.
Definition: rconfig.cc:2067
excludes_type excludes
Definition: rconfig.h:168
class rsync_behavior rsync_behavior
Definition: rconfig.h:174
const uint16 & io_poll_interval(void) const
Return the number of seconds to sleep between polling for I/O.
Definition: rconfig.cc:1586
void parse_include_job(const std::string &a_value)
Parse an "include-job" command.
Definition: rconfig.cc:2120
void parse_archive_path(const std::string &a_value)
Parse an "archive-path" command.
Definition: rconfig.cc:2824
friend class global_parser
Definition: rconfig.h:299
A configuration manager support class: Used to parse a configuration file from the perspective of a j...
Definition: rconfig.h:361
uint16 rsync_remote_port
Definition: rconfig.h:184
const std::string parse_dirname(const std::string &a_path)
Given a path, strip off the basename – like the dirname UNIX command.
Definition: rconfig.cc:1809
const map_type & map_value(void) const
Return an std::map of exit codes to actions.
Definition: rconfig.cc:549
std::string m_literal
Definition: rconfig.h:56
bool writable(const std::string &a_path)
Return true if the file or directory exists and is writable.
Definition: fs.cc:427
const std::string location(void)
Construct a string with the current location of the parser in a configuration file.
Definition: rconfig.cc:2645
const class timestamp & timestamp(void) const
Return the timestamp of this instance of rvm.
Definition: rconfig.cc:1505
const std::string & log_dir(void) const
Return the log-dir path.
Definition: rconfig.cc:1523
const action_type action(void) const
Return the action rvm is to take.
Definition: rconfig.cc:1466
const uint16 & rsync_parallel(void) const
Return the rsync-parallel.
Definition: rconfig.cc:1577
void parse_delete_old_report_files(const std::string &a_value)
Parse a "delete-old-report-files" command.
Definition: rconfig.cc:2262
const bool delete_old_report_files(void) const
Return the value of delete-old-report-files.
Definition: rconfig.cc:1541
std::string rsync_remote_module
Definition: rconfig.h:183
uint16 m_vault_overflow_blocks
Definition: rconfig.h:288
void parse_rsync_remote_user(const std::string &a_value)
Parse a "remote-user" command.
Definition: rconfig.cc:3284
uint16 m_rsync_parallel
Definition: rconfig.h:284
void parse_rsync_remote_port(const std::string &a_value)
Parse an "rsync-remote-port" command.
Definition: rconfig.cc:3296
class archive_path archive_path
Definition: rconfig.h:167
void default_logdir(const std::string &a_path)
Return the default log-dir.
Definition: rconfig.cc:1499
archive_path_element()
C'tor.
Definition: rconfig.cc:29
void parse_rsync_multi_hardlink(const std::string &a_value)
Parse an "rsync-multi-hardlink" command.
Definition: rconfig.cc:3117
std::string default_config_path
Definition: rconfig.h:163
const uint16 & vault_overflow_inodes(void) const
Return the vault-overflow-inodes.
Definition: rconfig.cc:1631
void parse_vault_overflow_blocks(const std::string &a_value)
Parse a "vault-overflow-blocks" command.
Definition: rconfig.cc:2536
void parse_job(const std::string &a_value)
Parse a job context.
Definition: rconfig.cc:2178
void parse_rsync_connection_type(const std::string &a_value)
Parse an "rsync-connection-type" command.
Definition: rconfig.cc:3055
const vaults_type & vaults(void) const
Return the vaults.
Definition: rconfig.cc:1604
#define LOCAL_RSYNC
Definition: config.h:151
const selection_type & vault_selection_behavior(void) const
Return the vault-selection-behavior.
Definition: rconfig.cc:1640
cfgfiles_type m_cfgfiles
Definition: rconfig.h:278
bool readable(const std::string &a_path)
Return true if the file or directory exists and is readable.
Definition: fs.cc:417
std::pair< cfgfile_type, std::string > cfgfile_element
Definition: rconfig.h:231
const std::string common_pathname(void) const
Find the common pathname among all job paths (may be an empty string)
Definition: rconfig.cc:764
void parse_include(const std::string &a_value)
Parse an "include" command.
Definition: rconfig.cc:2970
uint16 * m_line
Definition: rconfig.h:327
void parse_rsync_options_context(const std::string &a_value)
Parse an rsync-options context.
Definition: rconfig.cc:3196
A configuration manager support class: Used to specify a single subdirectory in a path of subdirector...
Definition: rconfig.h:23
uint16 rsync_retry_count
Definition: rconfig.h:185
map_type m_map
Definition: rconfig.h:129
logging_type m_logging_level
Definition: rconfig.h:296
void parse_rsync_hardlink(const std::string &a_value)
Parse an "rsync-hardlink" command.
Definition: rconfig.cc:3082
#define err_unknown
Definition: error.h:114
void parse_delete_command_path(const std::string &a_value)
Parse an "delete-command-path" command.
Definition: rconfig.cc:2358
Retrieve a list of pathnames that match a given wildcard path.
Definition: fs.h:300
void parse_rsync_behavior(const std::string &a_value)
Parse an "rsync-behavior" command.
Definition: rconfig.cc:3035
void assign(const archive_path &a_class)
Assign an archive-path list from another archive_path instance.
Definition: rconfig.cc:326
job * m_job
Definition: rconfig.h:374
void clear(void)
Reset configuration to default settings.
Definition: rconfig.cc:1171
#define TRY_instead(code, es)
Definition: error.h:158
void parse_timestamp_resolution(const std::string &a_value)
Parse a "timestamp-resolution" command.
Definition: rconfig.cc:2414
void parse_rsync_retry_count(const std::string &a_value)
Parse an "rsync-retry-count" command.
Definition: rconfig.cc:3317
const timestamp::resolution_type timestamp_resolution(void) const
Return the timestamp-resolution.
Definition: rconfig.cc:1595
void parse_vault_overflow_behavior(const std::string &a_value)
Parse a "vault-overflow-behavior" command.
Definition: rconfig.cc:2512
void parse_rsync_multi_hardlink_max(const std::string &a_value)
Parse an "rsync-multi-hardlink-max" command.
Definition: rconfig.cc:3153
friend class job_parser
Definition: rconfig.h:300
void parse_rsync_remote_module(const std::string &a_value)
Parse an "rsync-remote-module" command.
Definition: rconfig.cc:3311
archive_path()
C'tor.
Definition: rconfig.cc:232
const std::string str(void) const
Reconstruct a string from an archive-path list.
Definition: rconfig.cc:310
void parse_delete_old_log_files(const std::string &a_value)
Parse a "delete-old-log-files" command.
Definition: rconfig.cc:2227
void parse_include_from(const std::string &a_value)
Parse an "include-from" command.
Definition: rconfig.cc:2924
std::string rsync_remote_user
Definition: rconfig.h:181
action_type m_action
Definition: rconfig.h:275
#define LOCAL_SSH
Definition: config.h:154
std::string m_default_file
Definition: rconfig.h:274
global_parser(const std::string &a_path, uint16 &a_line, std::istream &a_in)
C'tor.
Definition: rconfig.cc:1847
void assign(const timestamp &a_t)
Set the timestamp to the value of another timestamp.
Definition: tstamp.cc:79
uint16 m_vault_overflow_inodes
Definition: rconfig.h:289
#define TRY_nomem(code)
Definition: error.h:144
A configuration manager support class: Used to specify a unique subdirectory in the archive for each ...
Definition: rconfig.h:63
void parse_line(std::istream &a_in, std::string &a_keyword, std::string &a_value)
Parse a keyword/value pair read from a configuration file.
Definition: rconfig.cc:1742
uint16 rsync_timeout
Definition: rconfig.h:187
static const uint16 default_behavior
Default behavior.
Definition: rconfig.h:107
const std::string generate_archive_path(const std::string &a_path) const
Generate the archive-path subdirectory for this job.
Definition: rconfig.cc:641
void parse_rsync_timeout(const std::string &a_value)
Parse an "rsync-timeout" command.
Definition: rconfig.cc:3347
void parse_logging_level(const std::string &a_value)
Parse a "loging-level" command.
Definition: rconfig.cc:2297
class timestamp m_timestamp
Definition: rconfig.h:277
void read_config(const std::string &a_path)
Read a configuration file, used by the "include" command.
Definition: rconfig.cc:1876
void parse_rsync_remote_path(const std::string &a_value)
Parse an "rsync-remote-path" command.
Definition: rconfig.cc:3290
std::string groupname
Definition: rconfig.h:170
selection_type m_vault_selection_behavior
Definition: rconfig.h:290
An error class.
Definition: error.h:72
void parse_vault_selection_behavior(const std::string &a_value)
Parse a "vault-selection-behavior" command.
Definition: rconfig.cc:2566
bool m_delete_old_report_files
Definition: rconfig.h:293
std::string jobname
Definition: rconfig.h:172
const bool initialized(void) const
Return the initialized state of the configuration manager.
Definition: rconfig.cc:1459
bool rsync_hardlink
Definition: rconfig.h:176
void parse_link_catalog_dir(const std::string &a_value)
Parse a "link-catalog-dir" command.
Definition: rconfig.cc:2201
const type & path(const std::string a_path, const std::string a_filter="*")
Return a vector of strings of a list of files in a subdirectory.
Definition: fs.cc:1361
const std::string * m_path
Definition: rconfig.h:375
#define LOGDIR
Definition: config.h:157
std::string hostname
Definition: rconfig.h:171
void read_config(const std::string &a_path)
Read a configuration file.
Definition: rconfig.cc:1694
uint16 default_config_line
Definition: rconfig.h:164
#define TRY(code, es)
Definition: error.h:126
#define INTERNAL_ERROR(e, s)
Definition: error.h:123
std::string rsync_remote_path
Definition: rconfig.h:182
std::vector< std::string > vaults_type
Definition: rconfig.h:234
void resolution(resolution_type a_r)
Set the timestamp resolution.
Definition: tstamp.cc:302
void parse_vault_overflow_inodes(const std::string &a_value)
Parse a "vault-overflow-inodes" command.
Definition: rconfig.cc:2551
configuration_manager config
The global configuration manager instance.
Definition: rconfig.cc:3364
void set(void)
Set the timestamp to the current time and date.
Definition: tstamp.cc:58
estring & lower(void)
Convert all characters to lowercase.
Definition: estring.cc:891
const std::string & link_catalog_dir(void) const
Return the link-catalog-dir path.
Definition: rconfig.cc:1514
void read_job(const std::string &a_path)
Read a job configuration file.
Definition: rconfig.cc:1715
const bool same(std::string s1, std::string s2)
Definition: test-logger.cc:82
void parse_vault_locking(const std::string &a_value)
Parse a "vault-locking" command.
Definition: rconfig.cc:2587
void parse_vault(const std::string &a_value)
Parse a "vault" command.
Definition: rconfig.cc:2447
void parse_io_poll_interval(const std::string &a_value)
Parse "io-poll-interval" command.
Definition: rconfig.cc:2399
Retrieve information about a file or directory.
Definition: fs.h:122
void parse_rsync_options(const std::string &a_value)
Parse an "rsync-options" command.
Definition: rconfig.cc:3168
void parse_error_logging_level(const std::string &a_value)
Parse a "error-loging-level" command.
Definition: rconfig.cc:2321
const job & default_job(void) const
Return the default job configuration.
Definition: rconfig.cc:1658
std::string permute_path(const std::string &a_path)
Reformat a path to remove the begining and trailing slashes, and replace all other slashes with under...
Definition: fs.cc:224
element_type m_type
Definition: rconfig.h:55
void parse_rsync_local_path(const std::string &a_value)
Parse an "rsync-local-path" command.
Definition: rconfig.cc:2345
const bool use_default(void) const
Return whether or not rvm is to try to read it's default configuration file.
Definition: rconfig.cc:1475
void parse_groupname(const std::string &a_value)
Parse a "groupname" command.
Definition: rconfig.cc:2958
resolution_type
Definition: tstamp.h:16
A configuration manager support class: Used to map rsync exit codes to actions for rvm to take...
Definition: rconfig.h:95
void parse_jobname(const std::string &a_value)
Parse a "jobname" command.
Definition: rconfig.cc:3023
void read_job(const std::string &a_path)
Read a job configuration file, used by the "include" command.
Definition: rconfig.cc:2659
void parse_ssh_options(const std::string &a_value)
Parse an "ssh-options" command.
Definition: rconfig.cc:3182
Keep up with configuration settings for RVM and it's jobs.
Definition: rconfig.h:203
std::string config_path
Definition: rconfig.h:165
#define ERROR_INSTANCE(s)
Definition: error.h:67
const std::vector< std::string > generate_ssh_options_vector(void) const
Generate ssh command line options.
Definition: rconfig.cc:944
const jobs_type & jobs(void) const
Return a list of jobs.
Definition: rconfig.cc:1667
void parse_ssh_local_path(const std::string &a_value)
Parse an "ssh-local-path" command.
Definition: rconfig.cc:2371
void parse_default(const std::string &a_value)
Parse a default job context.
Definition: rconfig.cc:2047
std::string m_link_catalog_dir
Definition: rconfig.h:279
void clear(void)
Clear all values and set the default to "retry".
Definition: rconfig.cc:378
const std::string parse_basename(const std::string &a_path)
Given a path, strip off the directory – like the basename UNIX commane.
Definition: rconfig.cc:1831
job & operator=(const job &a_job)
Assignment.
Definition: rconfig.cc:633
const element_type & type(void) const
Retrieve the current type.
Definition: rconfig.cc:145
const std::string str(void) const
Generate a string.
Definition: tstamp.cc:387
#define ERROR(e, s)
Definition: error.h:120
const std::vector< std::string > generate_rsync_options_vector(void) const
Generate rsync command line options.
Definition: rconfig.cc:872
logging_type m_error_logging_level
Definition: rconfig.h:297
const std::string & delete_command_path(void) const
Return the delete-command-path.
Definition: rconfig.cc:1559
rsync_behavior()
C'tor.
Definition: rconfig.cc:403
const overflow_type & vault_overflow_behavior(void) const
Return the vault-overflow-behavior.
Definition: rconfig.cc:1613
rsync_behavior & operator=(const rsync_behavior &a_class)
Assignment.
Definition: rconfig.cc:518
const std::string str(void) const
Construct a string of the current value.
Definition: rconfig.cc:157
archive_path & operator=(const archive_path &a_class)
Assignment.
Definition: rconfig.cc:349
const bool vault_locking(void) const
Return the vault-locking selection.
Definition: rconfig.cc:1649
std::istream * m_in
Definition: rconfig.h:376
void assign(const archive_path_element &a_class)
Assign the value from another archive_path_element instance.
Definition: rconfig.cc:59
std::map< uint16, value_type > map_type
Definition: rconfig.h:106
void reset(void)
Reset to a default value.
Definition: rconfig.cc:225
Retrieve a list of files in a subdirectory that match a given wildcard filename.
Definition: fs.h:273
const logging_type & error_logging_level(void) const
Return the error-logging-level.
Definition: rconfig.cc:1685
job_parser(job *a_job, const std::string &a_path, uint16 &a_line, std::istream &a_in, const std::string &a_block_delimiter, const bool a_default_context)
C'tor.
Definition: rconfig.cc:2624
void parse_rsync_parallel(const std::string &a_value)
Parse an "rsync-parallel" command.
Definition: rconfig.cc:2384
const logging_type & logging_level(void) const
Return the logging-level.
Definition: rconfig.cc:1676
bool rsync_multi_hardlink
Definition: rconfig.h:177
const std::string & ssh_local_path(void) const
Return the ssh-local-path.
Definition: rconfig.cc:1568
std::string m_ssh_local_path
Definition: rconfig.h:283
void assign(const uint16 a_code, const value_type a_action)
Assign an action to be taken for a specific exit code.
Definition: rconfig.cc:415
void push_back(const archive_path &a_class)
Add elements to the path list from another archive_path instance.
Definition: rconfig.cc:256
paths_type paths
Definition: rconfig.h:173
const std::string & default_file(void) const
Return the default configuration filename.
Definition: rconfig.cc:1490
void check(void) const
Perform sanity checks on configuration settings.
Definition: rconfig.cc:1379
void parse_log_dir(const std::string &a_value)
Parse a "log-dir" command.
Definition: rconfig.cc:2214
const std::string * m_delimiter
Definition: rconfig.h:378
archive_path_element & operator=(const archive_path_element &a_class)
Assignment.
Definition: rconfig.cc:193
std::string m_delete_command_path
Definition: rconfig.h:282
std::string m_rsync_local_path
Definition: rconfig.h:281
std::string rsync_options
Definition: rconfig.h:179