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"), &not_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