1 //*********************************************************************/
2 // dar - disk archive - a backup/restoration program
3 // Copyright (C) 2002-2052 Denis Corbin
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 //
19 // to contact the author : http://dar.linux.free.fr/email.html
20 /*********************************************************************/
21
22 #include "../my_config.h"
23
24 extern "C"
25 {
26 #if HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29 #if HAVE_SYS_TYPES_H
30 #include <sys/types.h>
31 #endif
32 #if HAVE_SYS_STAT_H
33 #include <sys/stat.h>
34 #endif
35 #if HAVE_FCNTL_H
36 #include <fcntl.h>
37 #endif
38 #include "getopt_decision.h"
39
40 #if HAVE_STRING_H
41 #include <string.h>
42 #endif
43
44 #if HAVE_STRINGS_H
45 #include <strings.h>
46 #endif
47
48 #if STDC_HEADERS
49 # include <string.h>
50 #else
51 # if !HAVE_STRCHR
52 # define strchr index
53 # define strrchr rindex
54 # endif
55 char *strchr (), *strrchr ();
56 # if !HAVE_MEMCPY
57 # define memcpy(d, s, n) bcopy ((s), (d), (n))
58 # define memmove(d, s, n) bcopy ((s), (d), (n))
59 # endif
60 #endif
61
62 #if HAVE_ERRNO_H
63 #include <errno.h>
64 #endif
65 } // end extern "C"
66
67 #include <string>
68 #include <algorithm>
69 #include <vector>
70 #include <deque>
71 #include <iostream>
72 #include <new>
73
74 #include "deci.hpp"
75 #include "command_line.hpp"
76 #include "user_interaction.hpp"
77 #include "tools.hpp"
78 #include "line_tools.hpp"
79 #include "dar.hpp"
80 #include "dar_suite.hpp"
81 #include "integers.hpp"
82 #include "no_comment.hpp"
83 #include "config_file.hpp"
84 #include "shell_interaction.hpp"
85 #include "dar.hpp"
86 #include "libdar.hpp"
87 #include "cygwin_adapt.hpp"
88 #include "mask_list.hpp"
89 #include "crit_action_cmd_line.hpp"
90 #include "criterium.hpp"
91 #include "fichier_local.hpp"
92
93 #define OPT_STRING "c:A:x:d:t:l:v::z::y::nw::p::k::R:s:S:X:I:P:bhLWDru:U:VC:i:o:OT::E:F:K:J:Y:Z:B:fm:NH::a::eQGMg:#:*:,[:]:+:@:$:~:%:q/:^:_:01:2:.:3:9:<:>:=:4:5::7:"
94
95 #define ONLY_ONCE "Only one -%c is allowed, ignoring this extra option"
96 #define MISSING_ARG "Missing argument to -%c option"
97 #define INVALID_ARG "Invalid argument given to -%c option"
98 #define INVALID_SIZE "Invalid size given with option -%c"
99
100 #define DEFAULT_CRYPTO_SIZE 10240
101
102
103 using namespace std;
104 using namespace libdar;
105 struct pre_mask
106 {
107 bool included; // whether it is a include or exclude entry
108 string mask; // the string (either a mask or a filename)
109 bool case_sensit; // whether comparison is case sensitive
110 bool file_listing; // whether the corresponding string is a filename containing a list of file to match to
111 bool glob_exp; // whether this is a glob (not regex) expression
112 };
113
114 struct mask_opt
115 {
116 bool case_sensit;
117 bool file_listing;
118 const path & prefix;
119 bool glob_exp;
120
mask_optmask_opt121 mask_opt(const path & ref) : prefix(ref) {};
122
read_frommask_opt123 void read_from(struct pre_mask m) { case_sensit = m.case_sensit; file_listing = m.file_listing; glob_exp = m.glob_exp; };
124 };
125
126 static const U_I min_compr_size_default = 100;
127 // the default value for --mincompr
128
129 static const U_I sparse_file_min_size_default = 15;
130 // the default value for --sparse-file-min-size
131
132 static const char * AUXILIARY_TARGET = "auxiliary";
133 static const char * REFERENCE_TARGET = "reference";
134
135 // return a newly allocated memory (to be deleted by the caller)
136 static void show_license(shell_interaction & dialog);
137 static void show_warranty(shell_interaction & dialog);
138 static void show_version(shell_interaction & dialog, const char *command_name);
139 static void usage(shell_interaction & dialog, const char *command_name);
140 static void split_compression_algo(const char *arg, compression & algo, U_I & level);
141 static fsa_scope string_to_fsa(const string & arg);
142
143 #if HAVE_GETOPT_LONG
144 const struct option *get_long_opt();
145 #endif
146
147 struct recursive_param
148 {
149 // input parameters
150 shell_interaction *dialog;
151 const char *home;
152 const vector<string> dar_dcf_path;
153 const vector<string> dar_duc_path;
154 // output parameters
155 vector<string> inclusions;
156 deque<pre_mask> name_include_exclude;
157 deque<pre_mask> path_include_exclude;
158 deque<pre_mask> ea_include_exclude;
159 deque<pre_mask> compr_include_exclude;
160 deque<pre_mask> backup_hook_include_exclude;
161 bool readconfig;
162 bool glob_mode;
163 vector<string> non_options; // list of user targets
164 bool ordered_filters;
165 bool case_sensit;
166 bool fixed_date_mode;
167 bool sparse_file_reactivation;
168 U_I suffix_base;
169 bool ea_erase;
170 bool only_more_recent;
171 bool detruire;
172 bool no_inter;
173 vector<string> read_targets; // list of not found uset targets so far
174 bool duc_and;
175
recursive_paramrecursive_param176 recursive_param(shell_interaction & x_dialog,
177 const char *x_home,
178 const vector<string> & x_dar_dcf_path,
179 const vector<string> & x_dar_duc_path): dar_dcf_path(x_dar_dcf_path), dar_duc_path(x_dar_duc_path)
180 {
181 dialog = new (nothrow) shell_interaction(x_dialog);
182 if(dialog == nullptr)
183 throw Ememory("recursive_param::recursive_param");
184 home = x_home;
185
186 //
187 readconfig = true;
188 glob_mode = true; // defaults to glob expressions
189 ordered_filters = false;
190 case_sensit = true;
191 fixed_date_mode = false;
192 sparse_file_reactivation = false;
193 suffix_base = TOOLS_BIN_SUFFIX;
194 ea_erase = false;
195 only_more_recent = false;
196 detruire = true;
197 no_inter = false;
198 duc_and = false;
199 };
200
recursive_paramrecursive_param201 recursive_param(const recursive_param & ref): dar_dcf_path(ref.dar_dcf_path), dar_duc_path(ref.dar_duc_path)
202 {
203 throw SRC_BUG;
204 }
205
~recursive_paramrecursive_param206 ~recursive_param()
207 {
208 if(dialog != nullptr)
209 delete dialog;
210 }
211 };
212
213 static bool get_args_recursive(recursive_param & rec,
214 line_param & p,
215 S_I argc,
216 char * const argv[]);
217
218
219 static void make_args_from_file(user_interaction & dialog,
220 operation op,
221 const vector<string> & targets,
222 const string & filename,
223 S_I & argc,
224 char **&argv,
225 vector<string> & read_targets, // read targets are removed from this argument
226 bool info_details);
227 static void destroy(S_I argc, char **argv);
228 static void skip_getopt(S_I argc, char *const argv[], S_I next_to_read);
229 static bool update_with_config_files(recursive_param & rec, line_param & p);
230
231 static mask *make_include_exclude_name(const string & x, mask_opt opt);
232 static mask *make_exclude_path_ordered(const string & x, mask_opt opt);
233 static mask *make_exclude_path_unordered(const string & x, mask_opt opt);
234 static mask *make_include_path(const string & x, mask_opt opt);
235 static mask *make_ordered_mask(deque<pre_mask> & listing, mask *(*make_include_mask) (const string & x, mask_opt opt), mask *(*make_exclude_mask)(const string & x, mask_opt opt), const path & prefix);
236 static mask *make_unordered_mask(deque<pre_mask> & listing, mask *(*make_include_mask) (const string & x, mask_opt opt), mask *(*make_exclude_mask)(const string & x, mask_opt opt), const path & prefix);
237 static void add_non_options(S_I argc, char * const argv[], vector<string> & non_options);
238
239 // #define DEBOGGAGE
240 #ifdef DEBOGGAGE
241 static void show_args(S_I argc, char *argv[]);
242 #endif
243
get_args(shell_interaction & dialog,const char * home,const vector<string> & dar_dcf_path,const vector<string> & dar_duc_path,S_I argc,char * const argv[],line_param & p)244 bool get_args(shell_interaction & dialog,
245 const char *home,
246 const vector<string> & dar_dcf_path,
247 const vector<string> & dar_duc_path,
248 S_I argc,
249 char *const argv[],
250 line_param & p)
251 {
252 string cmd = path(argv[0]).basename();
253 recursive_param rec = recursive_param(dialog, home, dar_dcf_path, dar_duc_path);
254
255 // initializing parameters to their default values
256 p.op = noop;
257 p.file_size = 0;
258 p.first_file_size = 0;
259 p.filename = "";
260 p.allow_over = true;
261 p.warn_over = true;
262 p.info_details = false;
263 p.display_treated = false;
264 p.display_treated_only_dir = false;
265 p.display_skipped = false;
266 p.display_finished = false;
267 p.algo = none;
268 p.compression_level = 9;
269 p.pause = 0;
270 p.beep = false;
271 p.empty_dir = false;
272 p.input_pipe = "";
273 p.output_pipe = "";
274 p.what_to_check = cat_inode::cf_all;
275 p.execute = "";
276 p.execute_ref = "";
277 p.pass.clear();
278 p.signatories.clear();
279 p.blind_signatures = false;
280 p.pass_ref.clear();
281 p.flat = false;
282 p.min_compr_size = min_compr_size_default;
283 p.nodump = false;
284 p.exclude_by_ea = false;
285 p.ea_name_for_exclusion = "";
286 p.hourshift = 0;
287 p.warn_remove_no_match = true;
288 p.filter_unsaved = false;
289 p.empty = false;
290 p.alter_atime = true;
291 p.same_fs = false;
292 p.snapshot = false;
293 p.cache_directory_tagging = false;
294 p.crypto_size = DEFAULT_CRYPTO_SIZE;
295 p.crypto_size_ref = DEFAULT_CRYPTO_SIZE;
296 p.list_mode = archive_options_listing::normal;
297 p.aux_pass.clear();
298 p.aux_execute = "";
299 p.aux_crypto_size = DEFAULT_CRYPTO_SIZE;
300 p.keep_compressed = false;
301 p.fixed_date = 0;
302 p.quiet = false;
303 p.slice_perm = "";
304 p.slice_user = "";
305 p.slice_group = "";
306 p.repeat_count = 3; // 3 retry by default
307 p.repeat_byte = 1; // 1 wasted byte allowed by default
308 p.decremental = false;
309 #if FURTIVE_READ_MODE_AVAILABLE
310 p.furtive_read_mode = true;
311 #else
312 p.furtive_read_mode = false;
313 #endif
314 p.lax = false;
315 p.use_sequential_marks = true;
316 p.sequential_read = false;
317 p.sparse_file_min_size = sparse_file_min_size_default;
318 p.dirty = dirtyb_warn;
319 p.security_check = true;
320 p.user_comment = "";
321 p.hash = hash_none;
322 p.num_digits = 0;
323 p.ref_num_digits = 0;
324 p.aux_num_digits = 0;
325 p.only_deleted = false;
326 p.not_deleted = false;
327 p.backup_hook_mask = nullptr;
328 p.backup_hook_execute = "";
329 p.list_ea = false;
330 p.ignore_unknown_inode = false;
331 p.no_compare_symlink_date = true;
332 p.scope = all_fsa_families();
333 p.multi_threaded = true;
334 p.sizes_in_bytes = false;
335 p.header_only = false;
336 p.zeroing_neg_dates = false;
337
338 try
339 {
340 opterr = 0;
341
342 if(!get_args_recursive(rec, p, argc, argv))
343 return false;
344
345 // checking and updating options with configuration file if any
346 if(rec.readconfig)
347 if(! update_with_config_files(rec, p))
348 return false;
349
350 // this cannot be done sooner, because "info_details" would always be equal to false
351 // as command-line would not have been yet parsed.
352
353 if(p.info_details)
354 {
355 if(!rec.non_options.empty())
356 {
357 vector<string>::iterator it = rec.non_options.begin();
358 bool init_message_done = false;
359
360 while(it != rec.non_options.end())
361 {
362 if(*it != AUXILIARY_TARGET && *it != REFERENCE_TARGET) // theses two targets are stored as "user targets" but are reserved targets not user's
363 {
364 if(!init_message_done)
365 {
366 dialog.warning(gettext("User target found on command line or included file(s):"));
367 init_message_done = true;
368 }
369 dialog.printf("\t%S", &(*it)); // yes, strange syntax, where "&(*it)" is not equal to "it" ... :-)
370 }
371 ++it;
372 }
373
374 if(!init_message_done)
375 dialog.warning(gettext("No user target found on command line"));
376 }
377 }
378
379 // some sanity checks
380
381 vector<string> unseen = tools_substract_from_vector(rec.non_options, rec.read_targets);
382 vector<string> special_targets;
383 special_targets.push_back(AUXILIARY_TARGET);
384 special_targets.push_back(REFERENCE_TARGET);
385 unseen = tools_substract_from_vector(unseen, special_targets);
386 if(!unseen.empty())
387 {
388 string not_seen;
389
390 for(vector<string>::iterator it = unseen.begin(); it != unseen.end(); ++it)
391 not_seen += *it + " ";
392
393 throw Erange("get_args", tools_printf(gettext("Given user target(s) could not be found: %S"), ¬_seen));
394 }
395
396 if(p.filename == "" || p.sauv_root == nullptr || p.op == noop)
397 throw Erange("get_args", tools_printf(gettext("Missing -c -x -d -t -l -C -+ option, see `%S -h' for help"), &cmd));
398 if(p.filename == "-" && !p.file_size.is_zero())
399 throw Erange("get_args", gettext("Slicing (-s option), is not compatible with archive on standard output (\"-\" as filename)"));
400 if(p.filename != "-" && (p.op != create && p.op != isolate && p.op != merging))
401 if(p.sauv_root == nullptr)
402 throw SRC_BUG;
403 if(p.filename != "-")
404 tools_check_basename(dialog, *p.sauv_root, p.filename, EXTENSION);
405 if((p.op == merging || p.op == create) && p.aux_filename != nullptr)
406 {
407 if(p.aux_root == nullptr)
408 throw SRC_BUG;
409 else
410 tools_check_basename(dialog, *p.aux_root, *p.aux_filename, EXTENSION);
411 }
412
413 if(p.fs_root == nullptr)
414 {
415 p.fs_root = new (nothrow) path(".");
416 if(p.fs_root == nullptr)
417 throw Ememory("get_args");
418 }
419 if(rec.fixed_date_mode && p.op != create)
420 throw Erange("get_args", gettext("-af option is only available with -c"));
421 if(p.ref_filename != nullptr && p.op == listing)
422 dialog.warning(gettext("-A option is not available with -l"));
423 if(p.op == isolate && p.ref_filename == nullptr)
424 throw Erange("get_args", gettext("with -C option, -A option is mandatory"));
425 if(p.op == merging && p.ref_filename == nullptr)
426 throw Erange("get_args", gettext("with -+ option, -A option is mandatory"));
427 if(p.op != extract && !p.warn_remove_no_match)
428 dialog.warning(gettext("-wa is only useful with -x option"));
429 if(p.filename == "-" && p.ref_filename != nullptr && *p.ref_filename == "-"
430 && p.output_pipe == "" && !p.sequential_read)
431 throw Erange("get_args", gettext("-o is mandatory when using \"-A -\" with \"-c -\" \"-C -\" or \"-+ -\""));
432 if(p.ref_filename != nullptr && *p.ref_filename != "-")
433 {
434 if(p.ref_root == nullptr)
435 throw SRC_BUG;
436 else
437 tools_check_basename(dialog, *p.ref_root, *p.ref_filename, EXTENSION);
438 }
439
440 if(p.algo != none && p.op != create && p.op != isolate && p.op != merging)
441 dialog.warning(gettext("-z option needs only to be used with -c -C or -+ options"));
442 if(!p.first_file_size.is_zero() && p.file_size.is_zero())
443 throw Erange("get_args", gettext("-S option requires the use of -s"));
444 if(p.what_to_check != cat_inode::cf_all && (p.op == isolate || (p.op == create && p.ref_root == nullptr) || p.op == test || p.op == listing || p.op == merging))
445 dialog.warning(gettext("ignoring -O option, as it is useless in this situation"));
446 if(p.what_to_check == cat_inode::cf_all
447 && p.op == extract
448 && capability_CHOWN(dialog, p.info_details)
449 && getuid() != 0) // uid == 0 for root
450 {
451 p.what_to_check = cat_inode::cf_ignore_owner;
452 string msg = tools_printf(gettext("File ownership will not be restored as %s has not the CHOWN capability nor is running as root. to avoid this message use -O option"), cmd.c_str());
453 dialog.pause(msg);
454 }
455 if(p.furtive_read_mode
456 && capability_FOWNER(dialog, p.info_details) != libdar::capa_set
457 && getuid() != 0)
458 {
459 if(p.op == create || p.op == diff)
460 dialog.printf(gettext("Furtive read mode has been disabled as %s has not the FOWNER capability nor is running as root"), cmd.c_str());
461 p.furtive_read_mode = false;
462 }
463
464 if(p.execute_ref != "" && p.ref_filename == nullptr)
465 dialog.warning(gettext("-F is only useful with -A option, for the archive of reference"));
466 if(p.pass_ref != "" && p.ref_filename == nullptr)
467 {
468 dialog.warning(gettext("-J is only useful with -A option, for the archive of reference"));
469 }
470 if(p.flat && p.op != extract)
471 dialog.warning(gettext("-f in only available with -x option, ignoring"));
472 if(p.min_compr_size != min_compr_size_default && p.op != create && p.op != merging)
473 dialog.warning(gettext("-m is only useful with -c"));
474 if(!p.hourshift.is_zero())
475 {
476 if(p.op == create)
477 {
478 if(p.ref_filename == nullptr)
479 dialog.warning(gettext("-H is only useful with -A option when making a backup"));
480 }
481 else
482 if(p.op == extract)
483 {
484 if(!rec.only_more_recent)
485 dialog.warning(gettext("-H is only useful with -r option when extracting"));
486 }
487 else
488 if(p.op != diff)
489 dialog.warning(gettext("-H is only useful with -c, -d or -x"));
490 }
491
492 if(p.filter_unsaved && p.op != listing)
493 dialog.warning(gettext("-as is only available with -l, ignoring -as option"));
494 if(p.empty && p.op != create && p.op != extract && p.op != merging && p.op != test)
495 dialog.warning(gettext("-e is only useful with -x, -c or -+ options"));
496 if(!p.alter_atime && p.op != create && p.op != diff)
497 dialog.warning(gettext("-ac is only useful with -c or -d"));
498 if(p.same_fs && p.op != create)
499 dialog.warning(gettext("-M is only useful with -c"));
500 if(p.snapshot && p.op != create)
501 dialog.warning(gettext("The snapshot backup (-A +) is only available with -c option, ignoring"));
502 if(p.cache_directory_tagging && p.op != create)
503 dialog.warning(gettext("The Cache Directory Tagging Standard is only useful while performing a backup, ignoring it here"));
504
505 if((p.aux_root != nullptr || p.aux_filename != nullptr) && p.op != merging && p.op != create)
506 throw Erange("get_args", gettext("-@ is only available with -+ and -c options"));
507 if(p.aux_pass != "" && p.op != merging && p.op != create)
508 throw Erange("get_args", gettext("-$ is only available with -+ option and -c options"));
509 if(p.aux_execute != "" && p.op != merging && p.op != create)
510 throw Erange("get_args", gettext("-~ is only available with -+ and -c options"));
511 if(p.aux_crypto_size != DEFAULT_CRYPTO_SIZE && p.op != merging && p.op != create)
512 throw Erange("get_args", tools_printf(gettext("-%% is only available with -+ option")));
513
514 if(p.aux_pass != "" && p.aux_filename == nullptr)
515 dialog.warning(gettext("-$ is only useful with -@ option, for the auxiliary archive of reference"));
516 if(p.aux_crypto_size != DEFAULT_CRYPTO_SIZE && p.aux_filename == nullptr)
517 dialog.printf(gettext("-%% is only useful with -@ option, for the auxiliary archive of reference"));
518 if(p.aux_execute != "" && p.aux_filename == nullptr)
519 dialog.warning(gettext("-~ is only useful with -@ option, for the auxiliary archive of reference"));
520 if(p.keep_compressed && p.op != merging)
521 {
522 dialog.warning(gettext("-ak is only available while merging (operation -+), ignoring -ak"));
523 p.keep_compressed = false;
524 }
525
526 if(p.algo != none && p.op == merging && p.keep_compressed)
527 dialog.warning(gettext("Compression option (-z option) is useless and ignored when using -ak option"));
528
529 // sparse files handling
530
531 if(p.sparse_file_min_size != sparse_file_min_size_default)
532 {
533 if(p.op != merging && p.op != create)
534 dialog.warning(gettext("--sparse-file-min-size only available while saving or merging archives, ignoring"));
535 else
536 if(p.op == merging && !rec.sparse_file_reactivation)
537 dialog.warning(gettext("To use --sparse-file-min-size while merging archive, you need to use -ah option too, please check man page for details"));
538 }
539 if(p.op == merging && !rec.sparse_file_reactivation)
540 p.sparse_file_min_size = 0; // disabled by default for archive merging
541
542 if((p.not_deleted || p.only_deleted) && p.op != extract)
543 dialog.warning(gettext("-k option is only useful with -x option"));
544
545 if(p.not_deleted && p.only_deleted)
546 throw Erange("get_args", gettext("-konly and -kignore cannot be used at the same time"));
547
548 if(rec.no_inter && !p.pause.is_zero())
549 throw Erange("get_args", gettext("-p and -Q options are mutually exclusives"));
550
551 if(p.display_finished && p.op != create)
552 dialog.warning(gettext("-vf is only useful with -c option"));
553
554 //////////////////////
555 // generating masks
556 // for filenames
557 //
558 string cwd = tools_getcwd();
559
560 if(rec.ordered_filters)
561 p.selection = make_ordered_mask(rec.name_include_exclude,
562 &make_include_exclude_name,
563 &make_include_exclude_name,
564 tools_relative2absolute_path(*p.fs_root, cwd));
565 else // unordered filters
566 p.selection = make_unordered_mask(rec.name_include_exclude,
567 &make_include_exclude_name,
568 &make_include_exclude_name,
569 tools_relative2absolute_path(*p.fs_root, cwd));
570
571
572 /////////////////////////
573 // generating masks for
574 // directory tree
575 //
576
577 if(rec.ordered_filters)
578 p.subtree = make_ordered_mask(rec.path_include_exclude,
579 &make_include_path,
580 &make_exclude_path_ordered,
581 p.op != test && p.op != merging && p.op != listing ? tools_relative2absolute_path(*p.fs_root, cwd) : "<ROOT>");
582 else // unordered filters
583 p.subtree = make_unordered_mask(rec.path_include_exclude,
584 &make_include_path,
585 &make_exclude_path_unordered,
586 p.op != test && p.op != merging && p.op != listing ? tools_relative2absolute_path(*p.fs_root, cwd) : "<ROOT>");
587
588
589 ////////////////////////////////
590 // generating mask for
591 // compression selected files
592 //
593 if(p.algo == none)
594 {
595 if(!rec.compr_include_exclude.empty())
596 dialog.warning(gettext("-Y and -Z are only useful with compression (-z option), ignoring any -Y and -Z option"));
597 if(p.min_compr_size != min_compr_size_default)
598 dialog.warning(gettext("-m is only useful with compression (-z option), ignoring -m"));
599 }
600
601 if(p.algo != none)
602 if(rec.ordered_filters)
603 p.compress_mask = make_ordered_mask(rec.compr_include_exclude,
604 &make_include_exclude_name,
605 &make_include_exclude_name,
606 tools_relative2absolute_path(*p.fs_root, cwd));
607 else
608 p.compress_mask = make_unordered_mask(rec.compr_include_exclude,
609 &make_include_exclude_name,
610 &make_include_exclude_name,
611 tools_relative2absolute_path(*p.fs_root, cwd));
612 else
613 {
614 p.compress_mask = new (nothrow) bool_mask(true);
615 if(p.compress_mask == nullptr)
616 throw Ememory("get_args");
617 }
618
619 ////////////////////////////////
620 // generating mask for EA
621 //
622 //
623
624 if(rec.ordered_filters)
625 p.ea_mask = make_ordered_mask(rec.ea_include_exclude,
626 &make_include_exclude_name,
627 &make_include_exclude_name,
628 tools_relative2absolute_path(*p.fs_root, cwd));
629 else // unordered filters
630 p.ea_mask = make_unordered_mask(rec.ea_include_exclude,
631 &make_include_exclude_name,
632 &make_include_exclude_name,
633 tools_relative2absolute_path(*p.fs_root, cwd));
634
635
636 ////////////////////////////////
637 // generating mask for backup hook
638 //
639 //
640
641 if(rec.backup_hook_include_exclude.size() == 0)
642 {
643 p.backup_hook_mask = nullptr;
644 if(p.backup_hook_execute != "")
645 {
646 p.backup_hook_execute = "";
647 if(p.op != create)
648 dialog.warning(gettext("-= option is valid only while saving files, thus in conjunction with -c option, ignoring"));
649 else
650 dialog.warning(gettext("-= option will be ignored as it is useless if you do not specify to which files or directories this backup hook is to be applied, thanks to -< and -> options. See man page for more details."));
651 }
652 }
653 else
654 if(p.op != create)
655 {
656 dialog.warning(gettext("backup hook feature (-<, -> or -= options) is only available when saving files, ignoring"));
657 p.backup_hook_mask = nullptr;
658 p.backup_hook_execute = "";
659 }
660 else
661 if(rec.ordered_filters)
662 p.backup_hook_mask = make_ordered_mask(rec.backup_hook_include_exclude,
663 &make_exclude_path_unordered, // no mistake here about *exclude*, nor *unordered*
664 &make_exclude_path_unordered, // no mistake here about *exclude*, nor *unordered*
665 tools_relative2absolute_path(*p.fs_root, cwd));
666 else
667 p.backup_hook_mask = make_unordered_mask(rec.backup_hook_include_exclude,
668 &make_exclude_path_unordered,// no mistake here about *exclude*
669 &make_exclude_path_unordered,
670 tools_relative2absolute_path(*p.fs_root, cwd));
671
672
673 ////////////////////////////////
674 // overwriting policy
675 //
676
677 switch(p.op)
678 {
679 case merging:
680 if(p.overwrite == nullptr)
681 {
682 p.overwrite = new (nothrow) crit_constant_action(data_preserve, EA_merge_preserve);
683 if(p.overwrite == nullptr)
684 throw Ememory("get_args");
685 }
686 break;
687 case extract:
688 if(p.overwrite == nullptr)
689 {
690 line_tools_4_4_build_compatible_overwriting_policy(p.allow_over,
691 rec.detruire,
692 rec.only_more_recent,
693 p.hourshift,
694 rec.ea_erase,
695 p.overwrite);
696 if(p.overwrite == nullptr)
697 throw Ememory("get_args");
698 }
699 break;
700 default:
701 if(p.overwrite != nullptr)
702 {
703 delete p.overwrite;
704 p.overwrite = nullptr;
705 dialog.warning(gettext("-/ option is only useful with -+ option, ignoring"));
706 }
707 }
708
709 ////////////////////////////////
710 // user comment
711 //
712 //
713
714 if(p.user_comment != "")
715 if(p.op != create && p.op != merging && p.op != isolate)
716 dialog.warning(gettext("-. option is only useful when merging, creating or isolating an archive, ignoring"));
717 else
718 {
719 p.user_comment = line_tools_expand_user_comment(p.user_comment, argc, argv);
720 if(p.info_details)
721 dialog.printf(gettext("The following user comment will be placed in clear text in the archive: %S"), &p.user_comment);
722 }
723 else
724 p.user_comment = "N/A";
725
726 ////////////////////////////////
727 // security check
728 //
729 //
730
731 if(!p.alter_atime)
732 p.security_check = false;
733 }
734 catch(Erange & e)
735 {
736 dialog.warning(string(gettext("Parse error: ")) + e.get_message());
737 return false;
738 }
739 return true;
740 }
741
get_short_opt()742 const char *get_short_opt() { return OPT_STRING; }
743
744
745
get_args_recursive(recursive_param & rec,line_param & p,S_I argc,char * const argv[])746 static bool get_args_recursive(recursive_param & rec,
747 line_param & p,
748 S_I argc,
749 char * const argv[])
750 {
751 S_I lu;
752 S_I rec_c;
753 char **rec_v = nullptr;
754 pre_mask tmp_pre_mask;
755 U_I tmp;
756 string tmp_string, tmp_string2;
757
758 // fetching first the targets (non optional argument of command line)
759 add_non_options(argc, argv, rec.non_options);
760
761 #if HAVE_GETOPT_LONG
762 while((lu = getopt_long(argc, argv, OPT_STRING, get_long_opt(), nullptr)) != EOF)
763 #else
764 while((lu = getopt(argc, argv, OPT_STRING)) != EOF)
765 #endif
766 {
767 switch(lu)
768 {
769 case 'c':
770 case 'x':
771 case 'd':
772 case 't':
773 case 'l':
774 case 'C':
775 case '+':
776 if(optarg == nullptr)
777 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
778 if(p.filename != "" || p.sauv_root != nullptr)
779 throw Erange("get_args", gettext(" Only one option of -c -d -t -l -C -x or -+ is allowed"));
780 if(string(optarg) != string(""))
781 tools_split_path_basename(optarg, p.sauv_root, p.filename);
782 else
783 throw Erange("get_args", tools_printf(gettext(INVALID_ARG), char(lu)));
784 switch(lu)
785 {
786 case 'c':
787 p.op = create;
788 break;
789 case 'x':
790 p.op = extract;
791 break;
792 case 'd':
793 p.op = diff;
794 break;
795 case 't':
796 p.op = test;
797 break;
798 case 'l':
799 p.op = listing;
800 break;
801 case 'C':
802 p.op = isolate;
803 break;
804 case '+':
805 p.op = merging;
806 break;
807 default:
808 throw SRC_BUG;
809 }
810 break;
811 case 'A':
812 if(p.ref_filename != nullptr || p.ref_root != nullptr || p.snapshot || !p.fixed_date.is_zero())
813 throw Erange("get_args", gettext("Only one -A option is allowed"));
814 if(optarg == nullptr)
815 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
816 if(strcmp("", optarg) == 0)
817 throw Erange("get_args", tools_printf(gettext(INVALID_ARG), char(lu)));
818 if(rec.fixed_date_mode)
819 {
820 try
821 {
822 try
823 {
824 // trying to read a simple integer
825 // note that the namespace specification is necessary
826 // due to similar existing name in std namespace under
827 // certain OS (FreeBSD 10.0)
828 libdar::deci tmp = string(optarg);
829 p.fixed_date = tmp.computer();
830 }
831 catch(Edeci & e)
832 {
833 // fallback to human readable string
834
835 p.fixed_date = tools_convert_date(optarg);
836 }
837 }
838 catch(Egeneric & e)
839 {
840 throw Erange("get_args", string(gettext("Error while parsing -A argument as a date: ")+ e.get_message()));
841 }
842 }
843 else
844 if(strcmp("+", optarg) == 0)
845 p.snapshot = true;
846 else
847 {
848 p.ref_filename = new (nothrow) string();
849 if(p.ref_filename == nullptr)
850 throw Ememory("get_args");
851 try
852 {
853 tools_split_path_basename(optarg, p.ref_root, *p.ref_filename);
854 rec.non_options.push_back("reference");
855 }
856 catch(...)
857 {
858 delete p.ref_filename;
859 p.ref_filename = nullptr;
860 throw;
861 }
862 }
863 break;
864 case 'v':
865 if(optarg == nullptr)
866 {
867 p.info_details = true;
868 p.display_treated = true;
869 p.display_treated_only_dir = false;
870 }
871 else
872 if(strcasecmp("skipped", optarg) == 0 || strcasecmp("s", optarg) == 0)
873 p.display_skipped = true;
874 else if(strcasecmp("treated", optarg) == 0 || strcasecmp("t", optarg) == 0)
875 {
876 p.display_treated = true;
877 p.display_treated_only_dir = false;
878 }
879 else if(strcasecmp("messages", optarg) == 0 || strcasecmp("m", optarg) == 0)
880 p.info_details = true;
881 else if(strcasecmp("dir", optarg) == 0 || strcasecmp("d", optarg) == 0)
882 {
883 p.display_treated = true;
884 p.display_treated_only_dir = true;
885 }
886 else if(strcasecmp("finished", optarg) == 0 || strcasecmp("f", optarg) == 0)
887 p.display_finished = true;
888 else if(strcasecmp("all", optarg) == 0 || strcasecmp("a", optarg) == 0)
889 {
890 p.info_details = true;
891 p.display_skipped = true;
892 p.display_treated = true;
893 p.display_treated_only_dir = false;
894 }
895 else
896 throw Erange("command_line.cpp:get_args_recursive", tools_printf(gettext(INVALID_ARG), char(lu)));
897 break;
898 case 'z':
899 if(optarg != nullptr)
900 split_compression_algo(optarg, p.algo, p.compression_level);
901 else
902 if(p.algo == none)
903 p.algo = gzip;
904 else
905 throw Erange("get_args", gettext("Choose only one compression algorithm"));
906 break;
907 case 'n':
908 p.allow_over = false;
909 if(!p.warn_over)
910 {
911 rec.dialog->warning(gettext("-w option is useless with -n"));
912 p.warn_over = false;
913 }
914 break;
915 case 'w':
916 p.warn_over = false;
917 if(optarg != nullptr)
918 {
919 if(strcmp(optarg, "a") == 0 || strcmp(optarg, "all") == 0)
920 p.warn_remove_no_match = false;
921 else
922 if(strcmp(optarg, "d") != 0 && strcmp(optarg, "default") != 0)
923 throw Erange("get_args", string(gettext("Unknown argument given to -w: ")) + optarg);
924 // else this is the default -w
925 }
926 break;
927 case 'p':
928 if(optarg != nullptr)
929 {
930 // note that the namespace specification is necessary
931 // due to similar existing name in std namespace under
932 // certain OS (FreeBSD 10.0)
933 libdar::deci conv = string(optarg);
934 p.pause = conv.computer();
935 }
936 else
937 p.pause = 1;
938 break;
939 case 'k':
940 if(optarg == nullptr) // -k without argument
941 {
942 if(p.only_deleted)
943 throw Erange("command_line.cpp:get_args_recursive", string(gettext("\"-k\" (or \"-kignore\") and \"-konly\" are not compatible")));
944 p.not_deleted = true;
945 }
946 else
947 if(strcasecmp(optarg, "ignore") == 0)
948 {
949 if(p.only_deleted)
950 throw Erange("command_line.cpp:get_args_recursive", string(gettext("\"-k\" (or \"-kignore\") and \"-konly\" are not compatible")));
951 p.not_deleted = true;
952 }
953 else
954 if(strcasecmp(optarg, "only") == 0)
955 {
956 if(p.not_deleted)
957 throw Erange("command_line.cpp:get_args_recursive", string(gettext("\"-k\" (or \"-kignore\") and \"-konly\" are not compatible")));
958 p.only_deleted = true;
959 }
960 else
961 throw Erange("command_line.cpp:get_args_recursive", tools_printf(gettext("Unknown argument given to -k : %s"), optarg));
962 break;
963 case 'R':
964 if(p.fs_root != nullptr)
965 throw Erange("get_args", gettext("Only one -R option is allowed"));
966 if(optarg == nullptr)
967 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
968 else
969 {
970 try
971 {
972 // first, trying to read the path as if it was a UNIX path
973 // this is necessary to take care of dot (.) and double dot (..)
974 // part inside the path and eventually reduce them to be able
975 // to apply filters on it in a consistent manner
976 p.fs_root = new (nothrow) path(optarg, false);
977 }
978 catch(Erange & e)
979 {
980 // well, it is not a UNIX path, using undisclosed object creation mode
981 // for example argument may contain // or \\ this tolerance has been
982 // added at release 2.4.0, but has drawback when using Unix path beginning
983 // with a dot ./restore (bug reported by Jim Avera against release 2.5.6)
984 p.fs_root = new (nothrow) path(optarg, true);
985 }
986 }
987 if(p.fs_root == nullptr)
988 throw Ememory("get_args");
989 break;
990 case 's':
991 if(!p.file_size.is_zero())
992 throw Erange("get_args", gettext("Only one -s option is allowed"));
993 if(optarg == nullptr)
994 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
995 else
996 {
997 try
998 {
999 p.file_size = tools_get_extended_size(optarg, rec.suffix_base);
1000 if(p.first_file_size.is_zero())
1001 p.first_file_size = p.file_size;
1002 }
1003 catch(Edeci &e)
1004 {
1005 rec.dialog->warning(tools_printf(gettext(INVALID_SIZE), char(lu)));
1006 return false;
1007 }
1008 }
1009 break;
1010 case 'S':
1011 if(optarg == nullptr)
1012 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
1013 if(p.first_file_size.is_zero())
1014 p.first_file_size = tools_get_extended_size(optarg, rec.suffix_base);
1015 else
1016 if(p.file_size.is_zero())
1017 throw Erange("get_args", gettext("Only one -S option is allowed"));
1018 else
1019 if(p.file_size == p.first_file_size)
1020 {
1021 try
1022 {
1023 p.first_file_size = tools_get_extended_size(optarg, rec.suffix_base);
1024 if(p.first_file_size == p.file_size)
1025 rec.dialog->warning(gettext("Giving to -S option the same value as the one given to -s option is useless"));
1026 }
1027 catch(Egeneric &e)
1028 {
1029 rec.dialog->warning(tools_printf(gettext(INVALID_SIZE), char(lu)));
1030 return false;
1031 }
1032
1033 }
1034 else
1035 throw Erange("get_args", gettext("Only one -S option is allowed"));
1036 break;
1037 case 'X':
1038 if(optarg == nullptr)
1039 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
1040 tmp_pre_mask.file_listing = false;
1041 tmp_pre_mask.case_sensit = rec.case_sensit;
1042 tmp_pre_mask.included = false;
1043 tmp_pre_mask.mask = string(optarg);
1044 tmp_pre_mask.glob_exp = rec.glob_mode;
1045 rec.name_include_exclude.push_back(tmp_pre_mask);
1046 break;
1047 case 'I':
1048 if(optarg == nullptr)
1049 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
1050 tmp_pre_mask.file_listing = false;
1051 tmp_pre_mask.case_sensit = rec.case_sensit;
1052 tmp_pre_mask.included = true;
1053 tmp_pre_mask.mask = string(optarg);
1054 tmp_pre_mask.glob_exp = rec.glob_mode;
1055 rec.name_include_exclude.push_back(tmp_pre_mask);
1056 break;
1057 case 'P':
1058 case ']':
1059 if(optarg == nullptr)
1060 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
1061 tmp_pre_mask.file_listing = lu == ']';
1062 tmp_pre_mask.case_sensit = rec.case_sensit;
1063 tmp_pre_mask.included = false;
1064 tmp_pre_mask.mask = string(optarg);
1065 tmp_pre_mask.glob_exp = rec.glob_mode;
1066 rec.path_include_exclude.push_back(tmp_pre_mask);
1067 break;
1068 case 'g':
1069 case '[':
1070 if(optarg == nullptr)
1071 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
1072 tmp_pre_mask.file_listing = lu == '[';
1073 tmp_pre_mask.case_sensit = rec.case_sensit;
1074 tmp_pre_mask.included = true;
1075 tmp_pre_mask.mask = string(optarg);
1076 tmp_pre_mask.glob_exp = rec.glob_mode;
1077 rec.path_include_exclude.push_back(tmp_pre_mask);
1078 break;
1079 case 'b':
1080 p.beep = true;
1081 break;
1082 case 'h':
1083 usage(*rec.dialog, argv[0]);
1084 p.op = version_or_help;
1085 return false;
1086 case 'L':
1087 show_license(*rec.dialog);
1088 return false;
1089 case 'W':
1090 show_warranty(*rec.dialog);
1091 return false;
1092 case 'D':
1093 if(p.empty_dir)
1094 rec.dialog->warning(tools_printf(gettext(ONLY_ONCE), char(lu)));
1095 else
1096 p.empty_dir = true;
1097 break;
1098 case 'r':
1099 if(!p.allow_over)
1100 rec.dialog->warning(gettext("-r is useless with -n"));
1101 if(rec.only_more_recent)
1102 rec.dialog->warning(tools_printf(gettext(ONLY_ONCE), char(lu)));
1103 else
1104 rec.only_more_recent = true;
1105 break;
1106 case 'u':
1107 case 'U':
1108 if(optarg == nullptr)
1109 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
1110 tmp_pre_mask.file_listing = false;
1111 tmp_pre_mask.case_sensit = rec.case_sensit;
1112 tmp_pre_mask.included = lu == 'U';
1113 tmp_pre_mask.mask = string(optarg);
1114 tmp_pre_mask.glob_exp = rec.glob_mode;
1115 rec.ea_include_exclude.push_back(tmp_pre_mask);
1116 break;
1117 case 'V':
1118 show_version(*rec.dialog, argv[0]);
1119 p.op = version_or_help;
1120 return false;
1121 case 'i':
1122 if(optarg == nullptr)
1123 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
1124 if(p.input_pipe == "")
1125 p.input_pipe = optarg;
1126 else
1127 rec.dialog->warning(tools_printf(gettext(ONLY_ONCE), char(lu)));
1128 break;
1129 case 'o':
1130 if(optarg == nullptr)
1131 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
1132 if(p.output_pipe == "")
1133 p.output_pipe = optarg;
1134 else
1135 rec.dialog->warning(tools_printf(gettext(ONLY_ONCE), char(lu)));
1136 break;
1137 case 'O':
1138 if(p.what_to_check != cat_inode::cf_all)
1139 rec.dialog->warning(tools_printf(gettext(ONLY_ONCE), char(lu)));
1140 else
1141 if(optarg == nullptr)
1142 p.what_to_check = cat_inode::cf_ignore_owner;
1143 else
1144 if(strcasecmp(optarg, "ignore-owner") == 0)
1145 p.what_to_check = cat_inode::cf_ignore_owner;
1146 else
1147 if(strcasecmp(optarg, "mtime") == 0)
1148 p.what_to_check = cat_inode::cf_mtime;
1149 else
1150 if(strcasecmp(optarg, "inode-type") == 0)
1151 p.what_to_check = cat_inode::cf_inode_type;
1152 else
1153 throw Erange("get_args", tools_printf(gettext(INVALID_ARG), char(lu)));
1154
1155 break;
1156 case 'T':
1157 if(optarg == nullptr)
1158 p.list_mode = archive_options_listing::tree;
1159 else if(strcasecmp("normal", optarg) == 0)
1160 p.list_mode = archive_options_listing::normal;
1161 else if(strcasecmp("tree", optarg) == 0)
1162 p.list_mode = archive_options_listing::tree;
1163 else if(strcasecmp("xml", optarg) == 0)
1164 p.list_mode = archive_options_listing::xml;
1165 else if(strcasecmp("slicing", optarg) == 0 || strcasecmp("slice", optarg) == 0)
1166 p.list_mode = archive_options_listing::slicing;
1167 else
1168 throw Erange("command_line.cpp:get_args_recursive", tools_printf(gettext(INVALID_ARG), char(lu)));
1169 break;
1170 case 'E':
1171 if(optarg == nullptr)
1172 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
1173 line_tools_split_at_first_space(optarg, tmp_string, tmp_string2);
1174 tmp_string = line_tools_get_full_path_from_PATH(rec.dar_duc_path, tmp_string.c_str()) + " " + tmp_string2;
1175 if(p.execute == "")
1176 p.execute = tmp_string;
1177 else
1178 {
1179 if(rec.duc_and)
1180 p.execute += string(" && ");
1181 else
1182 p.execute += string(" ; ");
1183 p.execute += tmp_string;
1184 }
1185 break;
1186 case 'F':
1187 if(optarg == nullptr)
1188 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
1189 line_tools_split_at_first_space(optarg, tmp_string, tmp_string2);
1190 tmp_string = line_tools_get_full_path_from_PATH(rec.dar_duc_path, tmp_string.c_str()) + " " + tmp_string2;
1191 if(p.execute_ref == "")
1192 p.execute_ref = tmp_string;
1193 else
1194 {
1195 if(rec.duc_and)
1196 p.execute_ref += string(" && ");
1197 else
1198 p.execute_ref += string(" ; ");
1199 p.execute_ref += tmp_string;
1200 }
1201 break;
1202 case 'J':
1203 if(optarg == nullptr)
1204 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
1205 if(p.pass_ref == "")
1206 p.pass_ref = secu_string(optarg, strlen(optarg));
1207 else
1208 rec.dialog->warning(tools_printf(gettext(ONLY_ONCE), char(lu)));
1209 break;
1210 case 'K':
1211 if(optarg == nullptr)
1212 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
1213 if(p.pass == "")
1214 p.pass = secu_string(optarg, strlen(optarg));
1215 else
1216 rec.dialog->warning(tools_printf(gettext(ONLY_ONCE), char(lu)));
1217 break;
1218 case 'Y':
1219 if(optarg == nullptr)
1220 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
1221 tmp_pre_mask.file_listing = false;
1222 tmp_pre_mask.case_sensit = rec.case_sensit;
1223 tmp_pre_mask.included = true;
1224 tmp_pre_mask.mask = string(optarg);
1225 tmp_pre_mask.glob_exp = rec.glob_mode;
1226 rec.compr_include_exclude.push_back(tmp_pre_mask);
1227 break;
1228 case 'Z':
1229 if(optarg == nullptr)
1230 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
1231 tmp_pre_mask.file_listing = false;
1232 tmp_pre_mask.case_sensit = rec.case_sensit;
1233 tmp_pre_mask.included = false;
1234 tmp_pre_mask.mask = string(optarg);
1235 tmp_pre_mask.glob_exp = rec.glob_mode;
1236 rec.compr_include_exclude.push_back(tmp_pre_mask);
1237 break;
1238 case 'B':
1239 if(optarg == nullptr)
1240 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
1241 tmp_string = line_tools_get_full_path_from_PATH(rec.dar_dcf_path, optarg);
1242 if(find(rec.inclusions.begin(), rec.inclusions.end(), tmp_string) != rec.inclusions.end())
1243 throw Erange("get_args", tools_printf(gettext("File inclusion loop detected. The file %s includes itself directly or through other files (-B option)"), optarg));
1244 else
1245 {
1246 bool ret;
1247 try
1248 {
1249 make_args_from_file(*rec.dialog,
1250 p.op,
1251 rec.non_options,
1252 tmp_string,
1253 rec_c,
1254 rec_v,
1255 rec.read_targets,
1256 p.info_details);
1257 }
1258 catch(Esystem & e)
1259 {
1260 Erange modif = Erange("get_args", tools_printf(gettext("Error reading included file (%s): "), optarg) + e.get_message());
1261 throw modif;
1262 }
1263 catch(Erange & e)
1264 {
1265 Erange modif = Erange("get_args", tools_printf(gettext("Error in included file (%s): "), optarg) + e.get_message());
1266 throw modif;
1267 }
1268 #if DEBOGGAGE
1269 show_args(rec_c, rec_v);
1270 #endif
1271 S_I optind_mem = line_tools_reset_getopt(); // save the external variable to use recursivity (see getopt)
1272 // reset getopt module
1273
1274 try
1275 {
1276 rec.inclusions.push_back(tmp_string);
1277 try
1278 {
1279 ret = get_args_recursive(rec, p, rec_c, rec_v);
1280 }
1281 catch(Erange & e)
1282 {
1283 Erange more = Erange(e.get_source(), tools_printf(gettext("In included file %S: "), &tmp_string) + e.get_message());
1284 rec.inclusions.pop_back();
1285 throw more;
1286 }
1287 catch(...)
1288 {
1289 rec.inclusions.pop_back();
1290 throw;
1291 }
1292 rec.inclusions.pop_back();
1293 }
1294 catch(...)
1295 {
1296 destroy(rec_c, rec_v);
1297 rec_v = nullptr;
1298 rec_c = 0;
1299 skip_getopt(argc, argv, optind_mem);
1300 throw;
1301 }
1302 destroy(rec_c, rec_v);
1303 rec_v = nullptr;
1304 rec_c = 0;
1305 skip_getopt(argc, argv, optind_mem); // restores getopt after recursion
1306
1307 if(!ret)
1308 return false;
1309 }
1310 break;
1311 case 'f':
1312 if(p.flat)
1313 rec.dialog->warning(tools_printf(gettext(ONLY_ONCE), char(lu)));
1314 else
1315 p.flat = true;
1316 break;
1317 case 'm':
1318 if(p.min_compr_size != min_compr_size_default)
1319 rec.dialog->warning(tools_printf(gettext(ONLY_ONCE), char(lu)));
1320 else
1321 {
1322 if(optarg == nullptr)
1323 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
1324 p.min_compr_size = tools_get_extended_size(optarg, rec.suffix_base);
1325 if(p.min_compr_size == min_compr_size_default)
1326 rec.dialog->warning(tools_printf(gettext("%d is the default value for -m, no need to specify it on command line, ignoring"), min_compr_size_default));
1327 break;
1328 }
1329 case 'N':
1330 if(!rec.readconfig)
1331 rec.dialog->warning(tools_printf(gettext(ONLY_ONCE), char(lu)));
1332 else
1333 rec.readconfig = false;
1334 break;
1335 case ' ':
1336 #ifdef LIBDAR_NODUMP_FEATURE
1337 if(p.nodump)
1338 rec.dialog->warning(tools_printf(gettext(ONLY_ONCE), char(lu)));
1339 else
1340 p.nodump = true;
1341 break;
1342 #else
1343 throw Ecompilation(gettext("--nodump feature has not been activated at compilation time, it is thus not available"));
1344 #endif
1345 case 'H':
1346 if(optarg == nullptr)
1347 p.hourshift = 1;
1348 else
1349 {
1350 try
1351 {
1352 // note that the namespace specification is necessary
1353 // due to similar existing name in std namespace under
1354 // certain OS (FreeBSD 10.0)
1355 p.hourshift = libdar::deci(string(optarg)).computer();
1356 }
1357 catch(Edeci & e)
1358 {
1359 throw Erange("command_line.cpp:get_args_recursive", gettext("Argument given to -H is not a positive integer number"));
1360 }
1361 }
1362 break;
1363 case 'a':
1364 if(optarg == nullptr)
1365 throw Erange("command_line.cpp:get_args_recursive", gettext("-a option requires an argument"));
1366 if(strcasecmp("SI-unit", optarg) == 0 || strcasecmp("SI", optarg) == 0 || strcasecmp("SI-units", optarg) == 0)
1367 rec.suffix_base = TOOLS_SI_SUFFIX;
1368 else if(strcasecmp("binary-unit", optarg) == 0 || strcasecmp("binary", optarg) == 0 || strcasecmp("binary-units", optarg) == 0)
1369 rec.suffix_base = TOOLS_BIN_SUFFIX;
1370 else if(strcasecmp("atime", optarg) == 0 || strcasecmp("a", optarg) == 0)
1371 {
1372 p.alter_atime = true;
1373 p.furtive_read_mode = false;
1374 }
1375 else if(strcasecmp("ctime", optarg) == 0 || strcasecmp("c", optarg) == 0)
1376 {
1377 p.alter_atime = false;
1378 p.furtive_read_mode = false;
1379 }
1380 else if(strcasecmp("m", optarg) == 0 || strcasecmp("mask", optarg) == 0)
1381 {
1382 if(rec.ordered_filters)
1383 rec.dialog->warning(tools_printf(gettext(ONLY_ONCE), char(lu)));
1384 else
1385 rec.ordered_filters = true;
1386 }
1387 else if(strcasecmp("n", optarg) == 0 || strcasecmp("no-case", optarg) == 0 || strcasecmp("no_case", optarg) == 0)
1388 rec.case_sensit = false;
1389 else if(strcasecmp("case", optarg) == 0)
1390 rec.case_sensit = true;
1391 else if(strcasecmp("s", optarg) == 0 || strcasecmp("saved", optarg) == 0)
1392 {
1393 if(p.filter_unsaved)
1394 rec.dialog->warning(tools_printf(gettext(ONLY_ONCE), char(lu)));
1395 else
1396 p.filter_unsaved = true;
1397 }
1398 else if(strcasecmp("e", optarg) == 0 || strcasecmp("erase_ea", optarg) == 0)
1399 {
1400 if(rec.ea_erase)
1401 rec.dialog->warning(tools_printf(gettext(ONLY_ONCE), char(lu)));
1402 else
1403 rec.ea_erase = true;
1404 }
1405 else if(strcasecmp("g", optarg) == 0 || strcasecmp("glob", optarg) == 0)
1406 rec.glob_mode = true;
1407 else if(strcasecmp("r", optarg) == 0 || strcasecmp("regex", optarg) == 0)
1408 rec.glob_mode = false;
1409 else if(strcasecmp("k", optarg) == 0 || strcasecmp("keep-compressed", optarg) == 0)
1410 {
1411 if(p.keep_compressed)
1412 rec.dialog->warning(gettext("-ak option need not be specified more than once, ignoring extra -ak options"));
1413 p.keep_compressed = true;
1414 }
1415 else if(strcasecmp("f", optarg) == 0 || strcasecmp("fixed-date", optarg) == 0)
1416 {
1417 if(p.ref_filename != nullptr || p.ref_root != nullptr || p.snapshot)
1418 throw Erange("get_args", gettext("-af must be present before -A option not after!"));
1419 if(rec.fixed_date_mode)
1420 rec.dialog->warning(gettext("-af option need not be specified more than once, ignoring extra -af options"));
1421 rec.fixed_date_mode = true;
1422 }
1423 else if(strcasecmp("d", optarg) == 0 || strcasecmp("decremental", optarg) == 0)
1424 p.decremental = true;
1425 else if(strcasecmp("l", optarg) == 0 || strcasecmp("lax", optarg) == 0)
1426 p.lax = true;
1427 else if(strcasecmp("t", optarg) == 0 || strcasecmp("tape-marks", optarg) == 0)
1428 p.use_sequential_marks = false;
1429 else if(strcasecmp("h", optarg) == 0 || strcasecmp("holes-recheck", optarg) == 0)
1430 rec.sparse_file_reactivation = true;
1431 else if(strcasecmp("secu", optarg) == 0)
1432 p.security_check = false;
1433 else if(strcasecmp("list-ea", optarg) == 0)
1434 p.list_ea = true;
1435 else if(strcasecmp("i", optarg) == 0 || strcasecmp("ignore-unknown-inode-type", optarg) == 0)
1436 p.ignore_unknown_inode = true;
1437 else if(strcasecmp("do-not-compare-symlink-mtime", optarg) == 0)
1438 p.no_compare_symlink_date = false;
1439 else if(strcasecmp("test-self-reported-bug", optarg) == 0)
1440 throw SRC_BUG; // testing the way a internal error is reported
1441 else if(strcasecmp("b", optarg) == 0 || strcasecmp("blind-to-signatures", optarg) == 0)
1442 p.blind_signatures = true;
1443 else if(strcasecmp("duc", optarg) == 0)
1444 rec.duc_and = true;
1445 else if(strcasecmp("y", optarg) == 0 || strcasecmp("byte", optarg) == 0 || strcasecmp("bytes", optarg) == 0)
1446 p.sizes_in_bytes = true;
1447 else if(strcasecmp("header", optarg) == 0)
1448 p.header_only = true;
1449 else if(strcasecmp("z", optarg) == 0 || strcasecmp("zeroing-negative-dates", optarg) == 0)
1450 p.zeroing_neg_dates = true;
1451 else
1452 throw Erange("command_line.cpp:get_args_recursive", tools_printf(gettext("Unknown argument given to -a : %s"), optarg));
1453 break;
1454 case 'e':
1455 if(p.empty)
1456 rec.dialog->warning(tools_printf(gettext(ONLY_ONCE), char(lu)));
1457 else
1458 p.empty = true;
1459 break;
1460 case 'Q':
1461 rec.no_inter = true;
1462 break;
1463 case 'G':
1464 if(optarg != nullptr)
1465 throw Erange("command_line.cpp:get_arg_recursive", tools_printf(gettext(INVALID_ARG), char(lu)));
1466 if(compile_time::libthreadar() && !rec.no_inter)
1467 rec.dialog->pause(gettext("Warning: -G option is an experimental and unsupported feature, read man page about -G option for more information"));
1468 p.multi_threaded = false;
1469 break;
1470 case 'M':
1471 if(p.same_fs)
1472 rec.dialog->warning(tools_printf(gettext(ONLY_ONCE), char(lu)));
1473 else
1474 p.same_fs = true;
1475 break;
1476 case '#':
1477 if(! tools_my_atoi(optarg, tmp))
1478 throw Erange("get_args", tools_printf(gettext(INVALID_ARG), char(lu)));
1479 else
1480 p.crypto_size = (U_32)tmp;
1481 break;
1482 case '*':
1483 if(! tools_my_atoi(optarg, tmp))
1484 throw Erange("get_args", tools_printf(gettext(INVALID_ARG), char(lu)));
1485 else
1486 p.crypto_size_ref = (U_32)tmp;
1487 break;
1488 case ',':
1489 if(p.cache_directory_tagging)
1490 rec.dialog->warning(tools_printf(gettext(ONLY_ONCE), char(lu)));
1491 else
1492 p.cache_directory_tagging = true;
1493 break;
1494 case '@':
1495 if(p.aux_filename != nullptr || p.aux_root != nullptr)
1496 throw Erange("get_args", gettext("Only one -@ option is allowed"));
1497 if(optarg == nullptr)
1498 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
1499 if(strcmp("", optarg) == 0)
1500 throw Erange("get_args", tools_printf(gettext(INVALID_ARG), char(lu)));
1501 else
1502 {
1503 p.aux_filename = new (nothrow) string();
1504 if(p.aux_filename == nullptr)
1505 throw Ememory("get_args");
1506 try
1507 {
1508 tools_split_path_basename(optarg, p.aux_root, *p.aux_filename);
1509 rec.non_options.push_back("auxiliary");
1510 }
1511 catch(...)
1512 {
1513 delete p.aux_filename;
1514 p.aux_filename = nullptr;
1515 throw;
1516 }
1517 }
1518 break;
1519 case '~':
1520 if(optarg == nullptr)
1521 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
1522 line_tools_split_at_first_space(optarg, tmp_string, tmp_string2);
1523 tmp_string = line_tools_get_full_path_from_PATH(rec.dar_duc_path, tmp_string.c_str()) + " " + tmp_string2;
1524 if(p.aux_execute == "")
1525 p.aux_execute = tmp_string;
1526 else
1527 {
1528 if(rec.duc_and)
1529 p.aux_execute += string(" && ");
1530 else
1531 p.aux_execute += string(" ; ");
1532 p.aux_execute += tmp_string;
1533 }
1534 break;
1535 case '$':
1536 if(optarg == nullptr)
1537 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
1538 if(p.aux_pass == "")
1539 p.aux_pass = secu_string(optarg, strlen(optarg));
1540 else
1541 rec.dialog->warning(tools_printf(gettext(ONLY_ONCE), char(lu)));
1542 break;
1543 case '%':
1544 if(! tools_my_atoi(optarg, tmp))
1545 throw Erange("get_args", tools_printf(gettext(INVALID_ARG), char(lu)));
1546 else
1547 p.aux_crypto_size = (U_32)tmp;
1548 break;
1549 case '/':
1550 if(optarg == nullptr)
1551 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
1552 if(p.overwrite == nullptr)
1553 {
1554 try
1555 {
1556 p.overwrite = crit_action_create_from_string(*rec.dialog, crit_action_canonize_string(optarg), p.hourshift);
1557 }
1558 catch(Erange & e)
1559 {
1560 throw Erange(e.get_source(), string(gettext("Syntax error in overwriting policy: ") + e.get_message()));
1561 }
1562 }
1563 else
1564 rec.dialog->warning(tools_printf(gettext(ONLY_ONCE), char(lu)));
1565 break;
1566 case '^':
1567 if(optarg == nullptr)
1568 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
1569 line_tools_slice_ownership(string(optarg), p.slice_perm, p.slice_user, p.slice_group);
1570 break;
1571 case '_':
1572 if(optarg == nullptr)
1573 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
1574 line_tools_repeat_param(string(optarg), p.repeat_count, p.repeat_byte);
1575 break;
1576 case '0':
1577 if(optarg == nullptr)
1578 p.sequential_read = true;
1579 else
1580 throw Erange("get_args", tools_printf(gettext(INVALID_ARG), char(lu)));
1581 break;
1582 case '1':
1583 if(p.sparse_file_min_size != sparse_file_min_size_default)
1584 rec.dialog->warning(tools_printf(gettext(ONLY_ONCE), char(lu)));
1585 else
1586 {
1587 if(optarg == nullptr)
1588 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
1589 try
1590 {
1591 p.sparse_file_min_size = tools_get_extended_size(optarg, rec.suffix_base);
1592 if(p.sparse_file_min_size == sparse_file_min_size_default)
1593 rec.dialog->warning(tools_printf(gettext("%d is the default value for --sparse-file-min-size, no need to specify it on command line, ignoring"), sparse_file_min_size_default));
1594 }
1595 catch(Edeci & e)
1596 {
1597 throw Erange("get_args", tools_printf(gettext(INVALID_ARG), char(lu)));
1598 }
1599 }
1600 break;
1601 case '2':
1602 if(p.dirty != dirtyb_warn)
1603 rec.dialog->warning(tools_printf(gettext(ONLY_ONCE), char(lu)));
1604 else
1605 {
1606 if(optarg == nullptr)
1607 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
1608 if(strcasecmp("ignore", optarg) == 0)
1609 p.dirty = dirtyb_ignore;
1610 else
1611 if(strcasecmp("no-warn", optarg) == 0)
1612 p.dirty = dirtyb_ok;
1613 else
1614 throw Erange("command_line.cpp:get_args_recursive", tools_printf(gettext("Unknown argument given to -2 : %s"), optarg));
1615 }
1616 break;
1617 case '"':
1618 if(optarg == nullptr)
1619 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
1620 else
1621 {
1622 tlv_list tmp;
1623 argc_argv arg;
1624 bool ret;
1625
1626 tools_read_from_pipe(*rec.dialog, tools_str2int(optarg), tmp);
1627 line_tools_tlv_list2argv(*rec.dialog, tmp, arg);
1628
1629 S_I optind_mem = line_tools_reset_getopt(); // save the external variable to use recursivity (see getopt)
1630 // reset getopt module
1631
1632 ret = get_args_recursive(rec, p, arg.argc(), arg.argv());
1633 skip_getopt(argc, argv, optind_mem); // restores getopt after recursion
1634
1635 if(!ret)
1636 return false;
1637 }
1638 break;
1639 case 'q':
1640 p.quiet = true;
1641 break;
1642 case '.':
1643 if(optarg == nullptr)
1644 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
1645 if(p.user_comment != "")
1646 p.user_comment += " ";
1647 p.user_comment += optarg;
1648 break;
1649 case '3':
1650 if(optarg == nullptr)
1651 throw Erange("get_args", tools_printf(gettext("Missing argument to --hash"), char(lu)));
1652 if(strcasecmp(optarg, "md5") == 0)
1653 p.hash = hash_md5;
1654 else
1655 if(strcasecmp(optarg, "sha1") == 0)
1656 p.hash = hash_sha1;
1657 else
1658 if(strcasecmp(optarg, "sha512") == 0)
1659 p.hash = hash_sha512;
1660 else
1661 throw Erange("get_args", string(gettext("Unknown parameter given to --hash option: ")) + optarg);
1662 break;
1663 case '9':
1664 if(optarg == nullptr)
1665 throw Erange("get_args", tools_printf(gettext("Missing argument to --min-digits"), char(lu)));
1666 else
1667 {
1668 try
1669 {
1670 line_tools_get_min_digits(optarg, p.num_digits, p.ref_num_digits, p.aux_num_digits);
1671 }
1672 catch(Erange & e)
1673 {
1674 throw Erange("get_args", string(gettext("Error while parsing --min-digits option: ")) + e.get_message());
1675 }
1676 }
1677 break;
1678 case '=':
1679 if(optarg == nullptr)
1680 throw Erange("get_args", tools_printf(gettext("Missing argument to --backup-hook-execute"), char(lu)));
1681 line_tools_split_at_first_space(optarg, tmp_string, tmp_string2);
1682 tmp_string = line_tools_get_full_path_from_PATH(rec.dar_duc_path, tmp_string.c_str()) + " " + tmp_string2;
1683 if(p.backup_hook_execute == "")
1684 p.backup_hook_execute = tmp_string;
1685 else
1686 p.backup_hook_execute += string(" ; ") + tmp_string;
1687 break;
1688 case '>':
1689 if(optarg == nullptr)
1690 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
1691 tmp_pre_mask.file_listing = false;
1692 tmp_pre_mask.case_sensit = rec.case_sensit;
1693 tmp_pre_mask.included = false;
1694 tmp_pre_mask.mask = string(optarg);
1695 tmp_pre_mask.glob_exp = rec.glob_mode;
1696 rec.backup_hook_include_exclude.push_back(tmp_pre_mask);
1697 break;
1698 case '<':
1699 if(optarg == nullptr)
1700 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
1701 tmp_pre_mask.file_listing = false;
1702 tmp_pre_mask.case_sensit = rec.case_sensit;
1703 tmp_pre_mask.included = true;
1704 tmp_pre_mask.mask = string(optarg);
1705 tmp_pre_mask.glob_exp = rec.glob_mode;
1706 rec.backup_hook_include_exclude.push_back(tmp_pre_mask);
1707 break;
1708 case '4':
1709 if(optarg == nullptr)
1710 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
1711 p.scope = string_to_fsa(optarg);
1712 if(p.info_details)
1713 {
1714 string list;
1715 set<fsa_family>::iterator it = p.scope.begin();
1716 while(it != p.scope.end())
1717 {
1718 list += " ";
1719 list += fsa_family_to_string(*it);
1720 ++it;
1721 }
1722 rec.dialog->warning(string("FSA family in scope:") + list);
1723 }
1724 break;
1725 case '5':
1726 p.exclude_by_ea = true;
1727 if(optarg != nullptr)
1728 p.ea_name_for_exclusion = optarg;
1729 else
1730 p.ea_name_for_exclusion = "";
1731 break;
1732 case '7':
1733 if(optarg != nullptr)
1734 {
1735 if(strlen(optarg) != 0)
1736 p.signatories = line_tools_split(optarg, ',');
1737 else
1738 throw Erange("get_args", tools_printf(gettext(INVALID_ARG), char(lu)));
1739 }
1740 else
1741 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(lu)));
1742 break;
1743 case ':':
1744 throw Erange("get_args", tools_printf(gettext(MISSING_ARG), char(optopt)));
1745 case '?':
1746 throw Erange("get_args", tools_printf(gettext("Unknown option -%c"),char(optopt)));
1747 default:
1748 throw Erange("get_args", tools_printf(gettext("Unknown option -%c"),char(lu)));
1749 }
1750 }
1751
1752 return true;
1753 }
1754
usage(shell_interaction & dialog,const char * command_name)1755 static void usage(shell_interaction & dialog, const char *command_name)
1756 {
1757 string name;
1758 tools_extract_basename(command_name, name);
1759 dialog.change_non_interactive_output(&cout);
1760
1761 dialog.printf(gettext("usage: %s [ -c | -x | -d | -t | -l | -C | -+ ] [<path>/]<basename> [options...]\n"), name.c_str());
1762 dialog.printf(" %s -h\n", name.c_str());
1763 dialog.printf(" %s -V\n", name.c_str());
1764 dialog.printf(gettext("\n"));
1765 dialog.printf(gettext("Commands are:\n"));
1766 dialog.printf(gettext(" -c creates an archive\n"));
1767 dialog.printf(gettext(" -x extracts files from the archive\n"));
1768 dialog.printf(gettext(" -d compares the archive with the existing filesystem\n"));
1769 dialog.printf(gettext(" -t tests the archive integrity\n"));
1770 dialog.printf(gettext(" -l lists the contents of the archive\n"));
1771 dialog.printf(gettext(" -C isolates the catalogue from an archive\n"));
1772 dialog.printf(gettext(" -+ merge two archives / create a sub archive\n"));
1773 dialog.printf(gettext("\n"));
1774 dialog.printf(gettext(" -h displays this help information\n"));
1775 dialog.printf(gettext(" -V displays version information\n"));
1776 dialog.printf(gettext("\n"));
1777 dialog.printf(gettext("Common options:\n"));
1778 dialog.printf(gettext(" -v\t\t verbose output\n"));
1779 dialog.printf(gettext(" -q\t\t suppress final statistics report\n"));
1780 dialog.printf(gettext(" -vs\t\t display skipped files\n"));
1781 dialog.printf(gettext(" -R <path>\t filesystem root directory (current dir by default)\n"));
1782 dialog.printf(gettext(" -X <mask>\t files to exclude from the operation (none by default)\n"));
1783 dialog.printf(gettext(" -I <mask>\t files to include in the operation (all by default)\n"));
1784 dialog.printf(gettext(" -P <path>\t subdirectory to exclude from the operation\n"));
1785 dialog.printf(gettext(" -g <path>\t subdirectory to include in the operation\n"));
1786 dialog.printf(gettext(" -[ <filename> filename contains a list of files to include\n"));
1787 dialog.printf(gettext(" -] <path>\t filename contains a list of files to exclude\n"));
1788 dialog.printf(gettext(" -n\t\t don't overwrite files\n"));
1789 dialog.printf(gettext(" -w\t\t don't warn before overwriting files\n"));
1790 dialog.printf(gettext(" -wa\t\t don't warn before overwriting and removing files\n"));
1791 dialog.printf(gettext(" -b\t\t ring the terminal bell when user action is required\n"));
1792 dialog.printf(gettext(" -O[ignore-owner | mtime | inode-type] do not consider user and group\n"));
1793 dialog.printf(gettext("\t\t ownership\n"));
1794 dialog.printf(gettext(" -H [N]\t ignore shift in dates of an exact number of hours\n"));
1795 dialog.printf(gettext(" -E <string>\t command to execute between slices\n"));
1796 dialog.printf(gettext(" -F <string>\t same as -E but for the archive of reference\n"));
1797 dialog.printf(gettext(" -u <mask>\t mask to ignore certain EA\n"));
1798 dialog.printf(gettext(" -U <mask>\t mask to allow certain EA\n"));
1799 dialog.printf(gettext(" -K <string>\t use <string> as key to encrypt/decrypt\n"));
1800 dialog.printf(gettext(" -J <string>\t same as -K but it does concern the archive of reference\n"));
1801 dialog.printf(gettext(" -# <integer> encryption block size\n"));
1802 dialog.printf(gettext(" -* <integer> same as -# but for archive of reference\n"));
1803 dialog.printf(gettext(" -B <filename> read options from given file\n"));
1804 dialog.printf(gettext(" -N\t\t do not read ~/.darrc nor /etc/darrc configuration file\n"));
1805 dialog.printf(gettext(" -e\t\t dry run, fake execution, nothing is produced\n"));
1806 dialog.printf(gettext(" -Q\t\t suppress the initial warning when not launched from a tty\n"));
1807 dialog.printf(gettext(" -aa\t\t do not try to preserve atime of file open for reading.\n"));
1808 dialog.printf(gettext(" -ac\t\t do not try to preserve ctime (default behavior).\n"));
1809 dialog.printf(gettext(" -am\t\t set ordered mode for all filters\n"));
1810 dialog.printf(gettext(" -an\t\t the masks that follow are now case insensitive\n"));
1811 dialog.printf(gettext(" -acase\t the masks that follow are now case sensitive\n"));
1812 dialog.printf(gettext(" -ar\t\t set the following masks to be regex expressions\n"));
1813 dialog.printf(gettext(" -ag\t\t set the following masks to be glob expressions\n"));
1814 dialog.printf(gettext("\n"));
1815 dialog.printf(gettext("Saving / Isolation / merging options (to use with -c, -C or -+):\n"));
1816 dialog.printf(gettext(" -A [path/]<basename> archive to take as reference\n"));
1817 dialog.printf(gettext(" -@ [path/]<basename> auxiliary archive of reference for merging\n"));
1818 dialog.printf(gettext(" -$ <string>\t encryption key for auxiliary archive\n"));
1819 dialog.printf(gettext(" -~ <string>\t command between slices of the auxiliary archive\n"));
1820 dialog.printf(gettext(" -z [[algo:]level]\t compress data in archive. -z = -z9 = -zgzip:9\n"));
1821 dialog.printf(gettext(" Available algo: gzip,bzip2,lzo,xz. Exemples: -zlzo -zxz:5 -z1 -z\n"));
1822 dialog.printf(gettext(" -s <integer> split the archive in several files of size <integer>\n"));
1823 dialog.printf(gettext(" -S <integer> first file size (if different from following ones)\n"));
1824 dialog.printf(gettext(" -aSI \t slice size suffixes k, M, T, G, etc. are power of 10\n"));
1825 dialog.printf(gettext(" -abinary\t slice size suffixes k, M, T, G, etc. are power of 2\n"));
1826 dialog.printf(gettext(" -p\t\t pauses before writing to a new file\n"));
1827 dialog.printf(gettext(" -D\t\t excluded directories are stored as empty directories\n"));
1828 dialog.printf(gettext(" -Z <mask>\t do not compress the matching filenames\n"));
1829 dialog.printf(gettext(" -Y <mask>\t do only compress the matching filenames\n"));
1830 dialog.printf(gettext(" -m <number>\t do not compress file smaller than <number>\n"));
1831 dialog.printf(gettext(" --nodump\t do not backup, files having the nodump 'd' flag set\n"));
1832 dialog.printf(gettext(" -@ [path/]<basename> Do on-fly catalogue isolation of the resulting archive\n"));
1833 dialog.printf(gettext(" -M\t\t stay in the same filesystem while scanning directories\n"));
1834 dialog.printf(gettext(" -,\t\t ignore directories that follow the Directory Tagging\n"));
1835 dialog.printf(gettext("\t\t Standard\n"));
1836 dialog.printf(gettext(" -/ <string>\t which way dar can overwrite files at archive merging or\n"));
1837 dialog.printf(gettext("\t\t extraction time\n"));
1838 dialog.printf(gettext(" -^ <string>\t permission[:user[:group]] of created slices\n"));
1839 dialog.printf(gettext("\n"));
1840 dialog.printf(gettext("Restoring options (to use with -x) :\n"));
1841 dialog.printf(gettext(" -k\t\t do not remove files destroyed since the reference backup\n"));
1842 dialog.printf(gettext(" -r\t\t do not restore file older than those on filesystem\n"));
1843 dialog.printf(gettext(" -f\t\t do not restore directory structure\n"));
1844 dialog.printf(gettext("\n"));
1845 dialog.printf(gettext("Reading options (to use with -x, -d, -t, -l, -A)\n"));
1846 dialog.printf(gettext(" -i <named pipe> pipe to use instead of std input to read data from dar_slave\n"));
1847 dialog.printf(gettext(" -o <named pipe> pipe to use instead of std output to orders dar_slave\n"));
1848 dialog.printf(gettext("\n"));
1849 dialog.printf(gettext("Listing options (to use with -l):\n"));
1850 dialog.printf(gettext(" -T\t\t tree output format\n"));
1851 dialog.printf(gettext(" -as\t\t only list files saved in the archive\n"));
1852 dialog.printf(gettext("\n\n"));
1853 dialog.printf(gettext("Type \"man dar\" for more details and for all other available options.\n"));
1854 }
1855
show_warranty(shell_interaction & dialog)1856 static void show_warranty(shell_interaction & dialog)
1857 {
1858 dialog.change_non_interactive_output(&cout);
1859 dialog.printf(" NO WARRANTY\n");
1860 dialog.printf("\n");
1861 dialog.printf(" 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n");
1862 dialog.printf("FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n");
1863 dialog.printf("OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n");
1864 dialog.printf("PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n");
1865 dialog.printf("OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n");
1866 dialog.printf("MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n");
1867 dialog.printf("TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n");
1868 dialog.printf("PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n");
1869 dialog.printf("REPAIR OR CORRECTION.\n");
1870 dialog.printf("\n");
1871 dialog.printf(" 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n");
1872 dialog.printf("WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n");
1873 dialog.printf("REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n");
1874 dialog.printf("INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n");
1875 dialog.printf("OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n");
1876 dialog.printf("TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n");
1877 dialog.printf("YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n");
1878 dialog.printf("PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n");
1879 dialog.printf("POSSIBILITY OF SUCH DAMAGES.\n");
1880 dialog.printf("\n");
1881 }
1882
show_license(shell_interaction & dialog)1883 static void show_license(shell_interaction & dialog)
1884 {
1885 dialog.change_non_interactive_output(&cout);
1886 dialog.printf(" GNU GENERAL PUBLIC LICENSE\n");
1887 dialog.printf(" Version 2, June 1991\n");
1888 dialog.printf("\n");
1889 dialog.printf(" Copyright (C) 1989, 1991 Free Software Foundation, Inc.\n");
1890 dialog.printf(" 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n");
1891 dialog.printf(" Everyone is permitted to copy and distribute verbatim copies\n");
1892 dialog.printf(" of this license document, but changing it is not allowed.\n");
1893 dialog.printf("\n");
1894 dialog.printf(" Preamble\n");
1895 dialog.printf("\n");
1896 dialog.printf(" The licenses for most software are designed to take away your\n");
1897 dialog.printf("freedom to share and change it. By contrast, the GNU General Public\n");
1898 dialog.printf("License is intended to guarantee your freedom to share and change free\n");
1899 dialog.printf("software--to make sure the software is free for all its users. This\n");
1900 dialog.printf("General Public License applies to most of the Free Software\n");
1901 dialog.printf("Foundation's software and to any other program whose authors commit to\n");
1902 dialog.printf("using it. (Some other Free Software Foundation software is covered by\n");
1903 dialog.printf("the GNU Library General Public License instead.) You can apply it to\n");
1904 dialog.printf("your programs, too.\n");
1905 dialog.printf("\n");
1906 dialog.printf(" When we speak of free software, we are referring to freedom, not\n");
1907 dialog.printf("price. Our General Public Licenses are designed to make sure that you\n");
1908 dialog.printf("have the freedom to distribute copies of free software (and charge for\n");
1909 dialog.printf("this service if you wish), that you receive source code or can get it\n");
1910 dialog.printf("if you want it, that you can change the software or use pieces of it\n");
1911 dialog.printf("in new free programs; and that you know you can do these things.\n");
1912 dialog.printf("\n");
1913 dialog.printf(" To protect your rights, we need to make restrictions that forbid\n");
1914 dialog.printf("anyone to deny you these rights or to ask you to surrender the rights.\n");
1915 dialog.printf("These restrictions translate to certain responsibilities for you if you\n");
1916 dialog.printf("distribute copies of the software, or if you modify it.\n");
1917 dialog.printf("\n");
1918 dialog.printf(" For example, if you distribute copies of such a program, whether\n");
1919 dialog.printf("gratis or for a fee, you must give the recipients all the rights that\n");
1920 dialog.printf("you have. You must make sure that they, too, receive or can get the\n");
1921 dialog.printf("source code. And you must show them these terms so they know their\n");
1922 dialog.printf("rights.\n");
1923 dialog.printf("\n");
1924 dialog.printf(" We protect your rights with two steps: (1) copyright the software, and\n");
1925 dialog.printf("(2) offer you this license which gives you legal permission to copy,\n");
1926 dialog.printf("distribute and/or modify the software.\n");
1927 dialog.printf("\n");
1928 dialog.printf(" Also, for each author's protection and ours, we want to make certain\n");
1929 dialog.printf("that everyone understands that there is no warranty for this free\n");
1930 dialog.printf("software. If the software is modified by someone else and passed on, we\n");
1931 dialog.printf("want its recipients to know that what they have is not the original, so\n");
1932 dialog.printf("that any problems introduced by others will not reflect on the original\n");
1933 dialog.printf("authors' reputations.\n");
1934 dialog.printf("\n");
1935 dialog.printf(" Finally, any free program is threatened constantly by software\n");
1936 dialog.printf("patents. We wish to avoid the danger that redistributors of a free\n");
1937 dialog.printf("program will individually obtain patent licenses, in effect making the\n");
1938 dialog.printf("program proprietary. To prevent this, we have made it clear that any\n");
1939 dialog.printf("patent must be licensed for everyone's free use or not licensed at all.\n");
1940 dialog.printf("\n");
1941 dialog.printf(" The precise terms and conditions for copying, distribution and\n");
1942 dialog.printf("modification follow.\n");
1943 dialog.printf("\n");
1944 dialog.printf(" GNU GENERAL PUBLIC LICENSE\n");
1945 dialog.printf(" TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n");
1946 dialog.printf("\n");
1947 dialog.printf(" 0. This License applies to any program or other work which contains\n");
1948 dialog.printf("a notice placed by the copyright holder saying it may be distributed\n");
1949 dialog.printf("under the terms of this General Public License. The \"Program\", below,\n");
1950 dialog.printf("refers to any such program or work, and a \"work based on the Program\"\n");
1951 dialog.printf("means either the Program or any derivative work under copyright law:\n");
1952 dialog.printf("that is to say, a work containing the Program or a portion of it,\n");
1953 dialog.printf("either verbatim or with modifications and/or translated into another\n");
1954 dialog.printf("language. (Hereinafter, translation is included without limitation in\n");
1955 dialog.printf("the term \"modification\".) Each licensee is addressed as \"you\".\n");
1956 dialog.printf("\n");
1957 dialog.printf("Activities other than copying, distribution and modification are not\n");
1958 dialog.printf("covered by this License; they are outside its scope. The act of\n");
1959 dialog.printf("running the Program is not restricted, and the output from the Program\n");
1960 dialog.printf("is covered only if its contents constitute a work based on the\n");
1961 dialog.printf("Program (independent of having been made by running the Program).\n");
1962 dialog.printf("Whether that is true depends on what the Program does.\n");
1963 dialog.printf("\n");
1964 dialog.printf(" 1. You may copy and distribute verbatim copies of the Program's\n");
1965 dialog.printf("source code as you receive it, in any medium, provided that you\n");
1966 dialog.printf("conspicuously and appropriately publish on each copy an appropriate\n");
1967 dialog.printf("copyright notice and disclaimer of warranty; keep intact all the\n");
1968 dialog.printf("notices that refer to this License and to the absence of any warranty;\n");
1969 dialog.printf("and give any other recipients of the Program a copy of this License\n");
1970 dialog.printf("along with the Program.\n");
1971 dialog.printf("\n");
1972 dialog.printf("You may charge a fee for the physical act of transferring a copy, and\n");
1973 dialog.printf("you may at your option offer warranty protection in exchange for a fee.\n");
1974 dialog.printf("\n");
1975 dialog.printf(" 2. You may modify your copy or copies of the Program or any portion\n");
1976 dialog.printf("of it, thus forming a work based on the Program, and copy and\n");
1977 dialog.printf("distribute such modifications or work under the terms of Section 1\n");
1978 dialog.printf("above, provided that you also meet all of these conditions:\n");
1979 dialog.printf("\n");
1980 dialog.printf(" a) You must cause the modified files to carry prominent notices\n");
1981 dialog.printf(" stating that you changed the files and the date of any change.\n");
1982 dialog.printf("\n");
1983 dialog.printf(" b) You must cause any work that you distribute or publish, that in\n");
1984 dialog.printf(" whole or in part contains or is derived from the Program or any\n");
1985 dialog.printf(" part thereof, to be licensed as a whole at no charge to all third\n");
1986 dialog.printf(" parties under the terms of this License.\n");
1987 dialog.printf("\n");
1988 dialog.printf(" c) If the modified program normally reads commands interactively\n");
1989 dialog.printf(" when run, you must cause it, when started running for such\n");
1990 dialog.printf(" interactive use in the most ordinary way, to print or display an\n");
1991 dialog.printf(" announcement including an appropriate copyright notice and a\n");
1992 dialog.printf(" notice that there is no warranty (or else, saying that you provide\n");
1993 dialog.printf(" a warranty) and that users may redistribute the program under\n");
1994 dialog.printf(" these conditions, and telling the user how to view a copy of this\n");
1995 dialog.printf(" License. (Exception: if the Program itself is interactive but\n");
1996 dialog.printf(" does not normally print such an announcement, your work based on\n");
1997 dialog.printf(" the Program is not required to print an announcement.)\n");
1998 dialog.printf("\n");
1999 dialog.printf("These requirements apply to the modified work as a whole. If\n");
2000 dialog.printf("identifiable sections of that work are not derived from the Program,\n");
2001 dialog.printf("and can be reasonably considered independent and separate works in\n");
2002 dialog.printf("themselves, then this License, and its terms, do not apply to those\n");
2003 dialog.printf("sections when you distribute them as separate works. But when you\n");
2004 dialog.printf("distribute the same sections as part of a whole which is a work based\n");
2005 dialog.printf("on the Program, the distribution of the whole must be on the terms of\n");
2006 dialog.printf("this License, whose permissions for other licensees extend to the\n");
2007 dialog.printf("entire whole, and thus to each and every part regardless of who wrote it.\n");
2008 dialog.printf("\n");
2009 dialog.printf("Thus, it is not the intent of this section to claim rights or contest\n");
2010 dialog.printf("your rights to work written entirely by you; rather, the intent is to\n");
2011 dialog.printf("exercise the right to control the distribution of derivative or\n");
2012 dialog.printf("collective works based on the Program.\n");
2013 dialog.printf("\n");
2014 dialog.printf("In addition, mere aggregation of another work not based on the Program\n");
2015 dialog.printf("with the Program (or with a work based on the Program) on a volume of\n");
2016 dialog.printf("a storage or distribution medium does not bring the other work under\n");
2017 dialog.printf("the scope of this License.\n");
2018 dialog.printf("\n");
2019 dialog.printf(" 3. You may copy and distribute the Program (or a work based on it,\n");
2020 dialog.printf("under Section 2) in object code or executable form under the terms of\n");
2021 dialog.printf("Sections 1 and 2 above provided that you also do one of the following:\n");
2022 dialog.printf("\n");
2023 dialog.printf(" a) Accompany it with the complete corresponding machine-readable\n");
2024 dialog.printf(" source code, which must be distributed under the terms of Sections\n");
2025 dialog.printf(" 1 and 2 above on a medium customarily used for software interchange; or,\n");
2026 dialog.printf("\n");
2027 dialog.printf(" b) Accompany it with a written offer, valid for at least three\n");
2028 dialog.printf(" years, to give any third party, for a charge no more than your\n");
2029 dialog.printf(" cost of physically performing source distribution, a complete\n");
2030 dialog.printf(" machine-readable copy of the corresponding source code, to be\n");
2031 dialog.printf(" distributed under the terms of Sections 1 and 2 above on a medium\n");
2032 dialog.printf(" customarily used for software interchange; or,\n");
2033 dialog.printf("\n");
2034 dialog.printf(" c) Accompany it with the information you received as to the offer\n");
2035 dialog.printf(" to distribute corresponding source code. (This alternative is\n");
2036 dialog.printf(" allowed only for noncommercial distribution and only if you\n");
2037 dialog.printf(" received the program in object code or executable form with such\n");
2038 dialog.printf(" an offer, in accord with Subsection b above.)\n");
2039 dialog.printf("\n");
2040 dialog.printf("The source code for a work means the preferred form of the work for\n");
2041 dialog.printf("making modifications to it. For an executable work, complete source\n");
2042 dialog.printf("code means all the source code for all modules it contains, plus any\n");
2043 dialog.printf("associated interface definition files, plus the scripts used to\n");
2044 dialog.printf("control compilation and installation of the executable. However, as a\n");
2045 dialog.printf("special exception, the source code distributed need not include\n");
2046 dialog.printf("anything that is normally distributed (in either source or binary\n");
2047 dialog.printf("form) with the major components (compiler, kernel, and so on) of the\n");
2048 dialog.printf("operating system on which the executable runs, unless that component\n");
2049 dialog.printf("itself accompanies the executable.\n");
2050 dialog.printf("\n");
2051 dialog.printf("If distribution of executable or object code is made by offering\n");
2052 dialog.printf("access to copy from a designated place, then offering equivalent\n");
2053 dialog.printf("access to copy the source code from the same place counts as\n");
2054 dialog.printf("distribution of the source code, even though third parties are not\n");
2055 dialog.printf("compelled to copy the source along with the object code.\n");
2056 dialog.printf("\n");
2057 dialog.printf(" 4. You may not copy, modify, sublicense, or distribute the Program\n");
2058 dialog.printf("except as expressly provided under this License. Any attempt\n");
2059 dialog.printf("otherwise to copy, modify, sublicense or distribute the Program is\n");
2060 dialog.printf("void, and will automatically terminate your rights under this License.\n");
2061 dialog.printf("However, parties who have received copies, or rights, from you under\n");
2062 dialog.printf("this License will not have their licenses terminated so long as such\n");
2063 dialog.printf("parties remain in full compliance.\n");
2064 dialog.printf("\n");
2065 dialog.printf(" 5. You are not required to accept this License, since you have not\n");
2066 dialog.printf("signed it. However, nothing else grants you permission to modify or\n");
2067 dialog.printf("distribute the Program or its derivative works. These actions are\n");
2068 dialog.printf("prohibited by law if you do not accept this License. Therefore, by\n");
2069 dialog.printf("modifying or distributing the Program (or any work based on the\n");
2070 dialog.printf("Program), you indicate your acceptance of this License to do so, and\n");
2071 dialog.printf("all its terms and conditions for copying, distributing or modifying\n");
2072 dialog.printf("the Program or works based on it.\n");
2073 dialog.printf("\n");
2074 dialog.printf(" 6. Each time you redistribute the Program (or any work based on the\n");
2075 dialog.printf("Program), the recipient automatically receives a license from the\n");
2076 dialog.printf("original licensor to copy, distribute or modify the Program subject to\n");
2077 dialog.printf("these terms and conditions. You may not impose any further\n");
2078 dialog.printf("restrictions on the recipients' exercise of the rights granted herein.\n");
2079 dialog.printf("You are not responsible for enforcing compliance by third parties to\n");
2080 dialog.printf("this License.\n");
2081 dialog.printf("\n");
2082 dialog.printf(" 7. If, as a consequence of a court judgment or allegation of patent\n");
2083 dialog.printf("infringement or for any other reason (not limited to patent issues),\n");
2084 dialog.printf("conditions are imposed on you (whether by court order, agreement or\n");
2085 dialog.printf("otherwise) that contradict the conditions of this License, they do not\n");
2086 dialog.printf("excuse you from the conditions of this License. If you cannot\n");
2087 dialog.printf("distribute so as to satisfy simultaneously your obligations under this\n");
2088 dialog.printf("License and any other pertinent obligations, then as a consequence you\n");
2089 dialog.printf("may not distribute the Program at all. For example, if a patent\n");
2090 dialog.printf("license would not permit royalty-free redistribution of the Program by\n");
2091 dialog.printf("all those who receive copies directly or indirectly through you, then\n");
2092 dialog.printf("the only way you could satisfy both it and this License would be to\n");
2093 dialog.printf("refrain entirely from distribution of the Program.\n");
2094 dialog.printf("\n");
2095 dialog.printf("If any portion of this section is held invalid or unenforceable under\n");
2096 dialog.printf("any particular circumstance, the balance of the section is intended to\n");
2097 dialog.printf("apply and the section as a whole is intended to apply in other\n");
2098 dialog.printf("circumstances.\n");
2099 dialog.printf("\n");
2100 dialog.printf("It is not the purpose of this section to induce you to infringe any\n");
2101 dialog.printf("patents or other property right claims or to contest validity of any\n");
2102 dialog.printf("such claims; this section has the sole purpose of protecting the\n");
2103 dialog.printf("integrity of the free software distribution system, which is\n");
2104 dialog.printf("implemented by public license practices. Many people have made\n");
2105 dialog.printf("generous contributions to the wide range of software distributed\n");
2106 dialog.printf("through that system in reliance on consistent application of that\n");
2107 dialog.printf("system; it is up to the author/donor to decide if he or she is willing\n");
2108 dialog.printf("to distribute software through any other system and a licensee cannot\n");
2109 dialog.printf("impose that choice.\n");
2110 dialog.printf("\n");
2111 dialog.printf("This section is intended to make thoroughly clear what is believed to\n");
2112 dialog.printf("be a consequence of the rest of this License.\n");
2113 dialog.printf("\n");
2114 dialog.printf(" 8. If the distribution and/or use of the Program is restricted in\n");
2115 dialog.printf("certain countries either by patents or by copyrighted interfaces, the\n");
2116 dialog.printf("original copyright holder who places the Program under this License\n");
2117 dialog.printf("may add an explicit geographical distribution limitation excluding\n");
2118 dialog.printf("those countries, so that distribution is permitted only in or among\n");
2119 dialog.printf("countries not thus excluded. In such case, this License incorporates\n");
2120 dialog.printf("the limitation as if written in the body of this License.\n");
2121 dialog.printf("\n");
2122 dialog.printf(" 9. The Free Software Foundation may publish revised and/or new versions\n");
2123 dialog.printf("of the General Public License from time to time. Such new versions will\n");
2124 dialog.printf("be similar in spirit to the present version, but may differ in detail to\n");
2125 dialog.printf("address new problems or concerns.\n");
2126 dialog.printf("\n");
2127 dialog.printf("Each version is given a distinguishing version number. If the Program\n");
2128 dialog.printf("specifies a version number of this License which applies to it and \"any\n");
2129 dialog.printf("later version\", you have the option of following the terms and conditions\n");
2130 dialog.printf("either of that version or of any later version published by the Free\n");
2131 dialog.printf("Software Foundation. If the Program does not specify a version number of\n");
2132 dialog.printf("this License, you may choose any version ever published by the Free Software\n");
2133 dialog.printf("Foundation.\n");
2134 dialog.printf("\n");
2135 dialog.printf(" 10. If you wish to incorporate parts of the Program into other free\n");
2136 dialog.printf("programs whose distribution conditions are different, write to the author\n");
2137 dialog.printf("to ask for permission. For software which is copyrighted by the Free\n");
2138 dialog.printf("Software Foundation, write to the Free Software Foundation; we sometimes\n");
2139 dialog.printf("make exceptions for this. Our decision will be guided by the two goals\n");
2140 dialog.printf("of preserving the free status of all derivatives of our free software and\n");
2141 dialog.printf("of promoting the sharing and reuse of software generally.\n");
2142 dialog.printf("\n");
2143 show_warranty(dialog);
2144 dialog.printf(" END OF TERMS AND CONDITIONS\n");
2145 dialog.printf("\n");
2146 dialog.printf(" How to Apply These Terms to Your New Programs\n");
2147 dialog.printf("\n");
2148 dialog.printf(" If you develop a new program, and you want it to be of the greatest\n");
2149 dialog.printf("possible use to the public, the best way to achieve this is to make it\n");
2150 dialog.printf("free software which everyone can redistribute and change under these terms.\n");
2151 dialog.printf("\n");
2152 dialog.printf(" To do so, attach the following notices to the program. It is safest\n");
2153 dialog.printf("to attach them to the start of each source file to most effectively\n");
2154 dialog.printf("convey the exclusion of warranty; and each file should have at least\n");
2155 dialog.printf("the \"copyright\" line and a pointer to where the full notice is found.\n");
2156 dialog.printf("\n");
2157 dialog.printf(" <one line to give the program's name and a brief idea of what it does.>\n");
2158 dialog.printf(" Copyright (C) <year> <name of author>\n");
2159 dialog.printf("\n");
2160 dialog.printf(" This program is free software; you can redistribute it and/or modify\n");
2161 dialog.printf(" it under the terms of the GNU General Public License as published by\n");
2162 dialog.printf(" the Free Software Foundation; either version 2 of the License, or\n");
2163 dialog.printf(" (at your option) any later version.\n");
2164 dialog.printf("\n");
2165 dialog.printf(" This program is distributed in the hope that it will be useful,\n");
2166 dialog.printf(" but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
2167 dialog.printf(" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n");
2168 dialog.printf(" GNU General Public License for more details.\n");
2169 dialog.printf("\n");
2170 dialog.printf(" You should have received a copy of the GNU General Public License\n");
2171 dialog.printf(" along with this program; if not, write to the Free Software\n");
2172 dialog.printf(" Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n");
2173 dialog.printf("\n");
2174 dialog.printf("\n");
2175 dialog.printf("Also add information on how to contact you by electronic and paper mail.\n");
2176 dialog.printf("\n");
2177 dialog.printf("If the program is interactive, make it output a short notice like this\n");
2178 dialog.printf("when it starts in an interactive mode:\n");
2179 dialog.printf("\n");
2180 dialog.printf(" Gnomovision version 69, Copyright (C) year name of author\n");
2181 dialog.printf(" Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n");
2182 dialog.printf(" This is free software, and you are welcome to redistribute it\n");
2183 dialog.printf(" under certain conditions; type `show c' for details.\n");
2184 dialog.printf("\n");
2185 dialog.printf("The hypothetical commands `show w' and `show c' should show the appropriate\n");
2186 dialog.printf("parts of the General Public License. Of course, the commands you use may\n");
2187 dialog.printf("be called something other than `show w' and `show c'; they could even be\n");
2188 dialog.printf("mouse-clicks or menu items--whatever suits your program.\n");
2189 dialog.printf("\n");
2190 dialog.printf("You should also get your employer (if you work as a programmer) or your\n");
2191 dialog.printf("school, if any, to sign a \"copyright disclaimer\" for the program, if\n");
2192 dialog.printf("necessary. Here is a sample; alter the names:\n");
2193 dialog.printf("\n");
2194 dialog.printf(" Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n");
2195 dialog.printf(" `Gnomovision' (which makes passes at compilers) written by James Hacker.\n");
2196 dialog.printf("\n");
2197 dialog.printf(" <signature of Ty Coon>, 1 April 1989\n");
2198 dialog.printf(" Ty Coon, President of Vice\n");
2199 dialog.printf("\n");
2200 dialog.printf("This General Public License does not permit incorporating your program into\n");
2201 dialog.printf("proprietary programs. If your program is a subroutine library, you may\n");
2202 dialog.printf("consider it more useful to permit linking proprietary applications with the\n");
2203 dialog.printf("library. If this is what you want to do, use the GNU Library General\n");
2204 dialog.printf("Public License instead of this License.\n");
2205 dialog.printf("\n");
2206 }
2207
show_version(shell_interaction & dialog,const char * command_name)2208 static void show_version(shell_interaction & dialog, const char *command_name)
2209 {
2210 string name;
2211 tools_extract_basename(command_name, name);
2212 U_I maj, med, min;
2213
2214 get_version(maj, med, min);
2215 dialog.change_non_interactive_output(&cout);
2216 dialog.warning(tools_printf("\n %s version %s, Copyright (C) 2002-2052 Denis Corbin\n", name.c_str(), ::dar_version())
2217 + " " + dar_suite_command_line_features()
2218 + "\n"
2219 + (maj > 2 ? tools_printf(gettext(" Using libdar %u.%u.%u built with compilation time options:"), maj, med, min)
2220 : tools_printf(gettext(" Using libdar %u.%u built with compilation time options:"), maj, min)));
2221 tools_display_features(dialog);
2222 dialog.printf("\n");
2223 dialog.warning(tools_printf(gettext(" compiled the %s with %s version %s\n"), __DATE__, CC_NAT, __VERSION__)
2224 + tools_printf(gettext(" %s is part of the Disk ARchive suite (Release %s)\n"), name.c_str(), PACKAGE_VERSION)
2225 + tools_printf(gettext(" %s comes with ABSOLUTELY NO WARRANTY; for details\n type `%s -W'."), name.c_str(), name.c_str())
2226 + tools_printf(gettext(" This is free software, and you are welcome\n to redistribute it under certain conditions;"))
2227 + tools_printf(gettext(" type `%s -L | more'\n for details.\n\n"), name.c_str()));
2228 }
2229
2230 #if HAVE_GETOPT_LONG
get_long_opt()2231 const struct option *get_long_opt()
2232 {
2233 static const struct option ret[] = {
2234 {"beep", no_argument, nullptr, 'b' },
2235 {"create", required_argument, nullptr, 'c'},
2236 {"diff", required_argument, nullptr, 'd'},
2237 {"help", no_argument, nullptr, 'h'},
2238 {"input", required_argument, nullptr, 'i'},
2239 {"deleted", optional_argument, nullptr, 'k'},
2240 {"no-delete", no_argument, nullptr, 'k'}, // backward compatiblity
2241 {"list", required_argument, nullptr, 'l'},
2242 {"no-overwrite", no_argument, nullptr, 'n'},
2243 {"output", required_argument, nullptr, 'o'},
2244 {"pause", optional_argument, nullptr, 'p'},
2245 {"recent", no_argument, nullptr, 'r'},
2246 {"slice", required_argument, nullptr, 's'},
2247 {"test", required_argument, nullptr, 't'},
2248 {"exclude-ea", required_argument, nullptr, 'u'},
2249 {"verbose", optional_argument, nullptr, 'v'},
2250 {"no-warn", optional_argument, nullptr, 'w'},
2251 {"extract", required_argument, nullptr, 'x'},
2252 {"gzip", optional_argument, nullptr, 'z'}, // backward compatibility
2253 {"compression", required_argument, nullptr, 'z'},
2254 {"ref", required_argument, nullptr, 'A'},
2255 {"isolate", required_argument, nullptr, 'C'},
2256 {"empty-dir", no_argument, nullptr, 'D'},
2257 {"include", required_argument, nullptr, 'I'},
2258 {"prune", required_argument, nullptr, 'P'},
2259 {"fs-root", required_argument, nullptr, 'R'},
2260 {"first-slice", required_argument, nullptr, 'S'},
2261 {"include-ea", required_argument, nullptr, 'U'},
2262 {"version", no_argument, nullptr, 'V'},
2263 {"exclude", required_argument, nullptr, 'X'},
2264 {"ignore-owner", no_argument, nullptr, 'O'},
2265 {"comparison-field", optional_argument, nullptr, 'O'},
2266 {"tree-format", no_argument, nullptr, 'T'},
2267 {"list-format", required_argument, nullptr, 'T'},
2268 {"execute", required_argument, nullptr, 'E'},
2269 {"execute-ref",required_argument, nullptr, 'F'},
2270 {"ref-execute",required_argument, nullptr, 'F'},
2271 {"key", required_argument, nullptr, 'K'},
2272 {"key-ref", required_argument, nullptr, 'J'},
2273 {"ref-key", required_argument, nullptr, 'J'},
2274 {"include-compression", required_argument, nullptr, 'Y'},
2275 {"exclude-compression", required_argument, nullptr, 'Z'},
2276 {"batch", required_argument, nullptr, 'B'},
2277 {"flat", no_argument, nullptr, 'f'},
2278 {"mincompr", required_argument, nullptr, 'm'},
2279 {"noconf", no_argument, nullptr, 'N'},
2280 {"nodump", no_argument, nullptr, ' '},
2281 {"hour", optional_argument, nullptr, 'H'},
2282 {"alter", optional_argument, nullptr, 'a'},
2283 {"empty", no_argument, nullptr, 'e'},
2284 {"dry-run", no_argument, nullptr, 'e'},
2285 {"on-fly-isolate", required_argument, nullptr, '@'},
2286 {"no-mount-points", no_argument, nullptr, 'M'},
2287 {"go-into", required_argument, nullptr, 'g'},
2288 {"crypto-block", required_argument, nullptr, '#'},
2289 {"ref-crypto-block", required_argument, nullptr, '*'},
2290 {"crypto-block-ref", required_argument, nullptr, '*'},
2291 {"cache-directory-tagging", no_argument, nullptr, ','},
2292 {"include-from-file", required_argument, nullptr, '['},
2293 {"exclude-from-file", required_argument, nullptr, ']'},
2294 {"merge", required_argument, nullptr, '+'},
2295 {"aux", required_argument, nullptr, '@'},
2296 {"aux-ref", required_argument, nullptr, '@'},
2297 {"aux-key", required_argument, nullptr, '$'},
2298 {"aux-execute", required_argument, nullptr, '~'},
2299 {"aux-crypto-block", required_argument, nullptr, '%'},
2300 {"quiet", no_argument, nullptr, 'q'},
2301 {"overwriting-policy", required_argument, nullptr, '/' },
2302 {"slice-mode", required_argument, nullptr, '^' },
2303 {"retry-on-change", required_argument, nullptr, '_' },
2304 {"pipe-fd", required_argument, nullptr, '"' },
2305 {"sequential-read", no_argument, nullptr, '0'},
2306 {"sparse-file-min-size", required_argument, nullptr, '1'},
2307 {"dirty-behavior", required_argument, nullptr, '2'},
2308 {"user-comment", required_argument, nullptr, '.'},
2309 {"hash", required_argument, nullptr, '3'},
2310 {"min-digits", required_argument, nullptr, '9'},
2311 {"backup-hook-include", required_argument, nullptr, '<'},
2312 {"backup-hook-exclude", required_argument, nullptr, '>'},
2313 {"backup-hook-execute", required_argument, nullptr, '='},
2314 {"fsa-scope", required_argument, nullptr, '4'},
2315 {"exclude-by-ea", optional_argument, nullptr, '5'},
2316 {"sign", required_argument, nullptr, '7'},
2317 {"single-thread", no_argument, nullptr, 'G'},
2318 { nullptr, 0, nullptr, 0 }
2319 };
2320
2321 return ret;
2322 }
2323 #endif
2324
make_args_from_file(user_interaction & dialog,operation op,const vector<string> & targets,const string & filename,S_I & argc,char ** & argv,vector<string> & read_targets,bool info_details)2325 static void make_args_from_file(user_interaction & dialog,
2326 operation op,
2327 const vector<string> & targets,
2328 const string & filename,
2329 S_I & argc,
2330 char **&argv,
2331 vector<string> & read_targets,
2332 bool info_details)
2333 {
2334 vector <string> cibles;
2335 vector <string> locally_unread_targets;
2336 argv = nullptr;
2337 argc = 0;
2338
2339 fichier_local conf = fichier_local(filename, false); // the object conf will close fd
2340
2341 ////////
2342 // removing the comments from file
2343 //
2344 no_comment sousconf = no_comment(conf);
2345
2346 ////////
2347 // defining the conditional syntax targets
2348 // that will be considered in the file
2349 cibles = targets;
2350 cibles.push_back("all");
2351 switch(op)
2352 {
2353 case noop:
2354 cibles.push_back("default");
2355 break;
2356 case create:
2357 cibles.push_back("create");
2358 break;
2359 case extract:
2360 cibles.push_back("extract");
2361 break;
2362 case diff:
2363 cibles.push_back("diff");
2364 break;
2365 case test:
2366 cibles.push_back("test");
2367 break;
2368 case listing:
2369 cibles.push_back("listing");
2370 cibles.push_back("list");
2371 break;
2372 case merging:
2373 cibles.push_back("merge");
2374 break;
2375 case isolate:
2376 cibles.push_back("isolate");
2377 break;
2378 default:
2379 throw SRC_BUG;
2380 }
2381
2382
2383 //////
2384 // hide the targets we don't want to see
2385 //
2386 config_file surconf = config_file(cibles, sousconf);
2387
2388 //////
2389 // now we have surconf -> sousconf -> conf -> fd
2390 // which makes the job to remove comments
2391 // and hide unwanted conditional statements on the fly
2392 // surconf can be used as a normal file.
2393 //
2394
2395 const char *command = "dar";
2396 char *pseudo_command = nullptr;
2397
2398 try
2399 {
2400 vector <string> mots;
2401
2402
2403 // now parsing the file and cutting words
2404 // taking care of quotes
2405 //
2406 mots = tools_split_in_words(surconf);
2407
2408
2409 // now converting the mots of type vector<string> to argc/argv arguments
2410 //
2411 argc = mots.size()+1;
2412 if(argc < 0)
2413 throw SRC_BUG; // integer overflow occurred
2414 argv = new (nothrow) char *[argc];
2415 if(argv == nullptr)
2416 throw Ememory("make_args_from_file");
2417 for(S_I i = 0; i < argc; ++i)
2418 argv[i] = nullptr;
2419
2420 // adding a fake "dar" word as first argument (= argv[0])
2421 //
2422 char *pseudo_command = new (nothrow) char[strlen(command)+1];
2423 if(pseudo_command == nullptr)
2424 throw Ememory("make_args_from_file");
2425 strncpy(pseudo_command, command, strlen(command));
2426 pseudo_command[strlen(command)] = '\0';
2427 argv[0] = pseudo_command;
2428 pseudo_command = nullptr;
2429
2430 if(info_details)
2431 dialog.printf(gettext("Arguments read from %S :"), &filename);
2432 for(U_I i = 0; i < mots.size(); ++i)
2433 {
2434 argv[i+1] = tools_str2charptr(mots[i]); // mots[i] goes to argv[i+1] !
2435 if(info_details)
2436 dialog.printf(" \"%s\"", argv[i+1]);
2437 }
2438 if(info_details)
2439 dialog.printf("\n");
2440 }
2441 catch(...)
2442 {
2443 if(argv != nullptr)
2444 {
2445 for(S_I i = 0; i < argc; ++i)
2446 if(argv[i] != nullptr)
2447 delete[] argv[i];
2448 delete[] argv;
2449 argv = nullptr;
2450 }
2451 argc = 0;
2452 if(pseudo_command != nullptr)
2453 {
2454 delete[] pseudo_command;
2455 pseudo_command = nullptr;
2456 }
2457 throw;
2458 }
2459
2460 tools_merge_to_vector(read_targets, surconf.get_read_targets());
2461 }
2462
2463
destroy(S_I argc,char ** argv)2464 static void destroy(S_I argc, char **argv)
2465 {
2466 S_I i = 0;
2467 for(i = 0; i < argc; ++i)
2468 delete [] argv[i];
2469 delete [] argv;
2470 }
2471
skip_getopt(S_I argc,char * const argv[],S_I next_to_read)2472 static void skip_getopt(S_I argc, char * const argv[], S_I next_to_read)
2473 {
2474 (void)line_tools_reset_getopt();
2475 #if HAVE_GETOPT_LONG
2476 while(getopt_long(argc, argv, OPT_STRING, get_long_opt(), nullptr) != EOF && optind < next_to_read)
2477 ;
2478 #else
2479 while(getopt(argc, argv, OPT_STRING) != EOF && optind < next_to_read)
2480 ;
2481 #endif
2482 }
2483
2484 #ifdef DEBOGGAGE
show_args(S_I argc,char * argv[])2485 static void show_args(S_I argc, char *argv[])
2486 {
2487 S_I i;
2488 for(i = 0; i < argc; ++i)
2489 dialog.printf("[%s]\n", argv[i]);
2490 }
2491 #endif
2492
2493
update_with_config_files(recursive_param & rec,line_param & p)2494 static bool update_with_config_files(recursive_param & rec, line_param & p)
2495 {
2496 string buffer;
2497 enum { syntax, ok, unknown } retour = unknown;
2498 S_I rec_c = 0;
2499 char **rec_v = nullptr;
2500
2501 (void)line_tools_reset_getopt();
2502
2503 // trying to open $HOME/.darrc
2504
2505 buffer = string(rec.home) + "/.darrc";
2506
2507 try
2508 {
2509 make_args_from_file(*rec.dialog,
2510 p.op,
2511 rec.non_options,
2512 buffer,
2513 rec_c,
2514 rec_v,
2515 rec.read_targets,
2516 p.info_details);
2517
2518 try
2519 {
2520 try
2521 {
2522 if(! get_args_recursive(rec, p, rec_c, rec_v))
2523 retour = syntax;
2524 else
2525 retour = ok;
2526 }
2527 catch(Erange & e)
2528 {
2529 Erange more = Erange(e.get_source(), tools_printf(gettext("In included file %S: "), &buffer) + e.get_message());
2530 throw more;
2531 }
2532 }
2533 catch(...)
2534 {
2535 if(rec_v != nullptr)
2536 {
2537 destroy(rec_c, rec_v);
2538 rec_v = nullptr;
2539 rec_c = 0;
2540 }
2541 throw;
2542 }
2543 if(rec_v != nullptr)
2544 {
2545 destroy(rec_c, rec_v);
2546 rec_v = nullptr;
2547 rec_c = 0;
2548 }
2549 }
2550 catch(Esystem & e)
2551 {
2552 switch(e.get_code())
2553 {
2554 case Esystem::io_absent:
2555 // failed openning the file,
2556 // nothing to do,
2557 // we will try the other config file
2558 // below
2559 break;
2560 case Esystem::io_exist:
2561 throw SRC_BUG;
2562 default:
2563 throw SRC_BUG;
2564 }
2565 }
2566 catch(Erange & e)
2567 {
2568 if(e.get_source() != "make_args_from_file")
2569 throw;
2570 }
2571
2572 rec_c = 0;
2573 rec_v = nullptr;
2574
2575 if(retour == unknown)
2576 {
2577 // trying to open DAR_SYS_DIR/darrc
2578
2579 buffer = string(DAR_SYS_DIR) + "/darrc";
2580
2581 try
2582 {
2583
2584 make_args_from_file(*rec.dialog,
2585 p.op,
2586 rec.non_options,
2587 buffer,
2588 rec_c,
2589 rec_v,
2590 rec.read_targets,
2591 p.info_details);
2592
2593 try
2594 {
2595 (void)line_tools_reset_getopt(); // reset getopt call
2596
2597 try
2598 {
2599 if(! get_args_recursive(rec, p, rec_c, rec_v))
2600 retour = syntax;
2601 else
2602 retour = ok;
2603 }
2604 catch(Erange & e)
2605 {
2606 Erange more = Erange(e.get_source(), tools_printf(gettext("In included file %S: "), &buffer) + e.get_message());
2607 throw more;
2608 }
2609 }
2610 catch(...)
2611 {
2612 if(rec_v != nullptr)
2613 {
2614 destroy(rec_c, rec_v);
2615 rec_v = nullptr;
2616 rec_c = 0;
2617 }
2618 throw;
2619 }
2620
2621 if(rec_v != nullptr)
2622 {
2623 destroy(rec_c, rec_v);
2624 rec_v = nullptr;
2625 rec_c = 0;
2626 }
2627 }
2628 catch(Esystem & e)
2629 {
2630 switch(e.get_code())
2631 {
2632 case Esystem::io_absent:
2633 // failed openning the file,
2634 // nothing to do,
2635 break;
2636 case Esystem::io_exist:
2637 throw SRC_BUG;
2638 default:
2639 throw SRC_BUG;
2640 }
2641 }
2642 catch(Erange & e)
2643 {
2644 if(e.get_source() != "make_args_from_file")
2645 throw;
2646 }
2647 }
2648
2649 return retour != syntax;
2650 }
2651
2652
make_include_exclude_name(const string & x,mask_opt opt)2653 static mask *make_include_exclude_name(const string & x, mask_opt opt)
2654 {
2655 mask *ret = nullptr;
2656
2657 if(opt.glob_exp)
2658 ret = new (nothrow) simple_mask(x, opt.case_sensit);
2659 else
2660 ret = new (nothrow) regular_mask(x, opt.case_sensit);
2661
2662 if(ret == nullptr)
2663 throw Ememory("make_include_exclude_name");
2664 else
2665 return ret;
2666 }
2667
make_exclude_path_ordered(const string & x,mask_opt opt)2668 static mask *make_exclude_path_ordered(const string & x, mask_opt opt)
2669 {
2670 mask *ret = nullptr;
2671 if(opt.file_listing)
2672 {
2673 ret = new (nothrow) mask_list(x, opt.case_sensit, opt.prefix, false);
2674 if(ret == nullptr)
2675 throw Ememory("make_exclude_path");
2676 }
2677 else // not file listing mask
2678 {
2679 if(opt.glob_exp)
2680 {
2681 ou_mask *val = new (nothrow) ou_mask();
2682
2683 if(val == nullptr)
2684 throw Ememory("make_exclude_path");
2685
2686 val->add_mask(simple_mask((opt.prefix + x).display(), opt.case_sensit));
2687 val->add_mask(simple_mask((opt.prefix + x).display() + "/*", opt.case_sensit));
2688 ret = val;
2689 }
2690 else // regex
2691 {
2692 ret = new (nothrow) regular_mask(tools_build_regex_for_exclude_mask(opt.prefix.display(), x), opt.case_sensit);
2693
2694 if(ret == nullptr)
2695 throw Ememory("make_exclude_path");
2696 }
2697 }
2698
2699 return ret;
2700 }
2701
2702
make_exclude_path_unordered(const string & x,mask_opt opt)2703 static mask *make_exclude_path_unordered(const string & x, mask_opt opt)
2704 {
2705 mask *ret = nullptr;
2706
2707 if(opt.file_listing)
2708 ret = new (nothrow) mask_list(x, opt.case_sensit, opt.prefix, false);
2709 else
2710 if(opt.glob_exp)
2711 ret = new (nothrow) simple_mask((opt.prefix + x).display(), opt.case_sensit);
2712 else
2713 ret = new (nothrow) regular_mask(tools_build_regex_for_exclude_mask(opt.prefix.display(), x), opt.case_sensit);
2714 if(ret == nullptr)
2715 throw Ememory("make_exclude_path");
2716
2717 return ret;
2718 }
2719
make_include_path(const string & x,mask_opt opt)2720 static mask *make_include_path(const string & x, mask_opt opt)
2721 {
2722 mask *ret = nullptr;
2723
2724 if(opt.file_listing)
2725 ret = new (nothrow) mask_list(x, opt.case_sensit, opt.prefix, true);
2726 else
2727 ret = new (nothrow) simple_path_mask(opt.prefix +x, opt.case_sensit);
2728 if(ret == nullptr)
2729 throw Ememory("make_include_path");
2730
2731 return ret;
2732 }
2733
make_ordered_mask(deque<pre_mask> & listing,mask * (* make_include_mask)(const string & x,mask_opt opt),mask * (* make_exclude_mask)(const string & x,mask_opt opt),const path & prefix)2734 static mask *make_ordered_mask(deque<pre_mask> & listing, mask *(*make_include_mask) (const string & x, mask_opt opt), mask *(*make_exclude_mask)(const string & x, mask_opt opt), const path & prefix)
2735 {
2736 mask *ret_mask = nullptr;
2737 ou_mask *tmp_ou_mask = nullptr;
2738 et_mask *tmp_et_mask = nullptr;
2739 mask *tmp_mask = nullptr;
2740 mask_opt opt = prefix;
2741
2742 try
2743 {
2744 while(!listing.empty())
2745 {
2746 opt.read_from(listing.front());
2747 if(listing.front().included)
2748 if(ret_mask == nullptr) // first mask
2749 {
2750 ret_mask = (*make_include_mask)(listing.front().mask, opt);
2751 if(ret_mask == nullptr)
2752 throw Ememory("make_ordered_mask");
2753 }
2754 else // ret_mask != nullptr (need to chain to existing masks)
2755 {
2756 if(tmp_ou_mask != nullptr)
2757 {
2758 tmp_mask = (*make_include_mask)(listing.front().mask, opt);
2759 tmp_ou_mask->add_mask(*tmp_mask);
2760 delete tmp_mask;
2761 tmp_mask = nullptr;
2762 }
2763 else // need to create ou_mask
2764 {
2765 tmp_mask = (*make_include_mask)(listing.front().mask, opt);
2766 tmp_ou_mask = new (nothrow) ou_mask();
2767 if(tmp_ou_mask == nullptr)
2768 throw Ememory("make_ordered_mask");
2769 tmp_ou_mask->add_mask(*ret_mask);
2770 tmp_ou_mask->add_mask(*tmp_mask);
2771 delete tmp_mask;
2772 tmp_mask = nullptr;
2773 delete ret_mask;
2774 ret_mask = tmp_ou_mask;
2775 tmp_et_mask = nullptr;
2776 }
2777 }
2778 else // exclude mask
2779 if(ret_mask == nullptr)
2780 {
2781 tmp_mask = (*make_exclude_mask)(listing.front().mask, opt);
2782 ret_mask = new (nothrow) not_mask(*tmp_mask);
2783 if(ret_mask == nullptr)
2784 throw Ememory("make_ordered_mask");
2785 delete tmp_mask;
2786 tmp_mask = nullptr;
2787 }
2788 else // ret_mask != nullptr
2789 {
2790 if(tmp_et_mask != nullptr)
2791 {
2792 tmp_mask = (*make_exclude_mask)(listing.front().mask, opt);
2793 tmp_et_mask->add_mask(not_mask(*tmp_mask));
2794 delete tmp_mask;
2795 tmp_mask = nullptr;
2796 }
2797 else // need to create et_mask
2798 {
2799 tmp_mask = (*make_exclude_mask)(listing.front().mask, opt);
2800 tmp_et_mask = new (nothrow) et_mask();
2801 if(tmp_et_mask == nullptr)
2802 throw Ememory("make_ordered_mask");
2803 tmp_et_mask->add_mask(*ret_mask);
2804 tmp_et_mask->add_mask(not_mask(*tmp_mask));
2805 delete tmp_mask;
2806 tmp_mask = nullptr;
2807 delete ret_mask;
2808 ret_mask = tmp_et_mask;
2809 tmp_ou_mask = nullptr;
2810 }
2811 }
2812 listing.pop_front();
2813 }
2814
2815 if(ret_mask == nullptr)
2816 {
2817 ret_mask = new (nothrow) bool_mask(true);
2818 if(ret_mask == nullptr)
2819 throw Ememory("get_args");
2820 }
2821 }
2822 catch(...)
2823 {
2824 if(ret_mask != nullptr)
2825 {
2826 delete tmp_mask;
2827 tmp_mask = nullptr;
2828 }
2829 if(tmp_ou_mask != nullptr && tmp_ou_mask != ret_mask)
2830 {
2831 delete tmp_ou_mask;
2832 tmp_ou_mask = nullptr;
2833 }
2834 if(tmp_et_mask != nullptr && tmp_et_mask != ret_mask)
2835 {
2836 delete tmp_et_mask;
2837 tmp_et_mask = nullptr;
2838 }
2839 if(tmp_mask != nullptr)
2840 {
2841 delete tmp_mask;
2842 tmp_mask = nullptr;
2843 }
2844 throw;
2845 }
2846
2847 return ret_mask;
2848 }
2849
make_unordered_mask(deque<pre_mask> & listing,mask * (* make_include_mask)(const string & x,mask_opt opt),mask * (* make_exclude_mask)(const string & x,mask_opt opt),const path & prefix)2850 static mask *make_unordered_mask(deque<pre_mask> & listing, mask *(*make_include_mask) (const string & x, mask_opt opt), mask *(*make_exclude_mask)(const string & x, mask_opt opt), const path & prefix)
2851 {
2852 et_mask *ret_mask = new (nothrow) et_mask();
2853 ou_mask tmp_include, tmp_exclude;
2854 mask *tmp_mask = nullptr;
2855 mask_opt opt = prefix;
2856
2857 if(ret_mask == nullptr)
2858 throw Ememory("make_unordered_mask");
2859
2860 try
2861 {
2862 while(!listing.empty())
2863 {
2864 opt.read_from(listing.front());
2865 if(listing.front().included)
2866 {
2867 tmp_mask = (*make_include_mask)(listing.front().mask, opt);
2868 tmp_include.add_mask(*tmp_mask);
2869 delete tmp_mask;
2870 tmp_mask = nullptr;
2871 }
2872 else // excluded mask
2873 {
2874 tmp_mask = (*make_exclude_mask)(listing.front().mask, opt);
2875 tmp_exclude.add_mask(*tmp_mask);
2876 delete tmp_mask;
2877 tmp_mask = nullptr;
2878 }
2879 listing.pop_front();
2880 }
2881
2882 if(tmp_include.size() > 0)
2883 ret_mask->add_mask(tmp_include);
2884 else
2885 ret_mask->add_mask(bool_mask(true));
2886 if(tmp_exclude.size() > 0)
2887 ret_mask->add_mask(not_mask(tmp_exclude));
2888 }
2889 catch(...)
2890 {
2891 delete ret_mask;
2892 ret_mask = nullptr;
2893 throw;
2894 }
2895
2896 return ret_mask;
2897 }
2898
split_compression_algo(const char * arg,compression & algo,U_I & level)2899 static void split_compression_algo(const char *arg, compression & algo, U_I & level)
2900 {
2901 if(arg == nullptr)
2902 throw SRC_BUG;
2903 else
2904 {
2905 string working = arg;
2906 string::iterator it = working.begin();
2907
2908 while(it != working.end() && *it != ':')
2909 it++;
2910
2911 if(it == working.end()) // no ':' found in string
2912 {
2913 if(!tools_my_atoi(working.c_str(), level))
2914 {
2915 // argument to -z is not an integer, testing whether this is an algorithm
2916
2917 try
2918 {
2919 algo = string2compression(working.c_str());
2920 level = 9; // argument is a compression algo, level is 9 by default
2921 }
2922 catch(Erange & e)
2923 {
2924 throw Erange("split_compression_algo", tools_printf(gettext("%s does not name a compression \"[algorithm][:][level]\" , like for examples \"gzip\", \"lzo\", \"bzip2\", \"lzo:3\", \"gzip:2\", \"8\" or \"1\". Please review the man page about -z option"), working.c_str()));
2925 }
2926 }
2927 else // argument is a compression level, algorithm is gzip by default
2928 algo = gzip;
2929 }
2930 else // a ':' has been found and "it" points to it
2931 {
2932 string first_part = string(working.begin(), it);
2933 string second_part = string(it+1, working.end());
2934
2935 if(first_part != "")
2936 algo = string2compression(first_part);
2937 else
2938 algo = gzip; // default algorithm
2939
2940 if(second_part != "")
2941 {
2942 if(!tools_my_atoi(second_part.c_str(), level) || level > 9 || level < 1)
2943 throw Erange("split_compression_algo", gettext("Compression level must be between 1 and 9, included"));
2944 }
2945 else
2946 level = 9; // default compression level
2947 }
2948 }
2949 }
2950
string_to_fsa(const string & arg)2951 static fsa_scope string_to_fsa(const string & arg)
2952 {
2953 fsa_scope ret;
2954 vector<string> fams = line_tools_split(arg, ',');
2955
2956 ret.clear();
2957 if(arg != "none")
2958 {
2959 for(vector<string>::iterator it = fams.begin();
2960 it != fams.end();
2961 ++it)
2962 {
2963 if(*it == "extX"
2964 || *it == "ext"
2965 || *it == "extx")
2966 ret.insert(fsaf_linux_extX);
2967 else if(*it == "HFS+"
2968 || *it == "hfs+")
2969 ret.insert(fsaf_hfs_plus);
2970 else
2971 throw Erange("string_to_fsa", string(gettext("unknown FSA family: ")) + (*it));
2972 }
2973 }
2974
2975 return ret;
2976 }
2977
add_non_options(S_I argc,char * const argv[],vector<string> & non_options)2978 static void add_non_options(S_I argc, char * const argv[], vector<string> & non_options)
2979 {
2980 (void)line_tools_reset_getopt();
2981
2982 #if HAVE_GETOPT_LONG
2983 while(getopt_long(argc, argv, OPT_STRING, get_long_opt(), nullptr) != EOF)
2984 ;
2985 #else
2986 while(getopt(argc, argv, OPT_STRING) != EOF)
2987 ;
2988 #endif
2989
2990 for(S_I i = optind ; i < argc ; ++i)
2991 if(strcmp(argv[i],"create") == 0
2992 || strcmp(argv[i], "extract") == 0
2993 || strcmp(argv[i], "listing") == 0
2994 || strcmp(argv[i], "list") == 0
2995 || strcmp(argv[i], "test") == 0
2996 || strcmp(argv[i], "diff") == 0
2997 || strcmp(argv[i], "isolate") == 0
2998 || strcmp(argv[i], "merge") == 0
2999 || strcmp(argv[i], "reference") == 0
3000 || strcmp(argv[i], "auxiliary") == 0
3001 || strcmp(argv[i], "all") == 0
3002 || strcmp(argv[i], "default") == 0)
3003 throw Erange("add_non_options", tools_printf(gettext("User target named \"%s\" is not allowed (reserved word for conditional syntax)"), argv[i]));
3004 else
3005 non_options.push_back(argv[i]);
3006
3007 (void)line_tools_reset_getopt();
3008 }
3009