1 /*
2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 University of Maryland at College Park
4 * Copyright (c) 2007-2013 Zmanda, Inc. All Rights Reserved.
5 * All Rights Reserved.
6 *
7 * Permission to use, copy, modify, distribute, and sell this software and its
8 * documentation for any purpose is hereby granted without fee, provided that
9 * the above copyright notice appear in all copies and that both that
10 * copyright notice and this permission notice appear in supporting
11 * documentation, and that the name of U.M. not be used in advertising or
12 * publicity pertaining to distribution of the software without specific,
13 * written prior permission. U.M. makes no representations about the
14 * suitability of this software for any purpose. It is provided "as is"
15 * without express or implied warranty.
16 *
17 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
19 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
21 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 *
24 * Authors: the Amanda Development Team. Its members are listed in a
25 * file named AUTHORS, in the root directory of this distribution.
26 */
27 /*
28 * $Id: amgtar.c 8888 2007-10-02 13:40:42Z martineau $
29 *
30 * send estimated backup sizes using dump
31 */
32
33 /* PROPERTY:
34 *
35 * GNUTAR-PATH (default GNUTAR)
36 * GNUTAR-LISTDIR (default CNF_GNUTAR_LIST_DIR)
37 * DIRECTORY (no default, if set, the backup will be from that directory
38 * instead of from the --device)
39 * ONE-FILE-SYSTEM (default YES)
40 * SPARSE (default YES)
41 * ATIME-PRESERVE (default YES)
42 * CHECK-DEVICE (default YES)
43 * NO-UNQUOTE (default NO)
44 * ACLS (default NO)
45 * SELINUX (default NO)
46 * XATTRS (default NO)
47 * INCLUDE-FILE
48 * INCLUDE-LIST
49 * INCLUDE-LIST-GLOB
50 * INCLUDE-OPTIONAL
51 * EXCLUDE-FILE
52 * EXCLUDE-LIST
53 * EXCLUDE-LIST-GLOB
54 * EXCLUDE-OPTIONAL
55 * NORMAL
56 * IGNORE
57 * STRANGE
58 * EXIT-HANDLING (1=GOOD 2=BAD)
59 * TAR-BLOCKSIZE (default does not add --blocking-factor option,
60 * using tar's default)
61 * VERBOSE
62 */
63
64 #include "amanda.h"
65 #include "match.h"
66 #include "pipespawn.h"
67 #include "amfeatures.h"
68 #include "clock.h"
69 #include "util.h"
70 #include "getfsent.h"
71 #include "client_util.h"
72 #include "conffile.h"
73 #include "getopt.h"
74 #include "security-file.h"
75
76 int debug_application = 1;
77 #define application_debug(i, ...) do { \
78 if ((i) <= debug_application) { \
79 dbprintf(__VA_ARGS__); \
80 } \
81 } while (0)
82
83 static amregex_t init_re_table[] = {
84 /* tar prints the size in bytes */
85 AM_SIZE_RE("^ *Total bytes written: [0-9][0-9]*", 1, 1),
86 AM_NORMAL_RE("^could not open conf file"),
87 AM_NORMAL_RE("^Elapsed time:"),
88 AM_NORMAL_RE("^Throughput"),
89 AM_IGNORE_RE(": Directory is new$"),
90 AM_IGNORE_RE(": Directory has been renamed"),
91
92 /* GNU tar 1.27 */
93 AM_NORMAL_RE(": directory is on a different filesystem; not dumped"),
94
95 /* GNU tar 1.13.17 will print this warning when (not) backing up a
96 Unix named socket. */
97 AM_NORMAL_RE(": socket ignored$"),
98
99 /* GNUTAR produces a few error messages when files are modified or
100 removed while it is running. They may cause data to be lost, but
101 then they may not. We shouldn't consider them NORMAL until
102 further investigation. */
103 AM_NORMAL_RE(": File .* shrunk by [0-9][0-9]* bytes, padding with zeros"),
104 AM_NORMAL_RE(": Cannot add file .*: No such file or directory$"),
105 AM_NORMAL_RE(": Error exit delayed from previous errors"),
106
107 /* catch-all: DMP_STRANGE is returned for all other lines */
108 AM_STRANGE_RE(NULL)
109 };
110 static amregex_t *re_table;
111
112 /* local functions */
113 int main(int argc, char **argv);
114
115 typedef struct application_argument_s {
116 char *config;
117 char *host;
118 int message;
119 int collection;
120 int calcsize;
121 char *tar_blocksize;
122 GSList *level;
123 GSList *command_options;
124 char *include_list_glob;
125 char *exclude_list_glob;
126 dle_t dle;
127 int argc;
128 char **argv;
129 int verbose;
130 int ignore_zeros;
131 } application_argument_t;
132
133 enum { CMD_ESTIMATE, CMD_BACKUP };
134
135 static void amgtar_support(application_argument_t *argument);
136 static void amgtar_selfcheck(application_argument_t *argument);
137 static void amgtar_estimate(application_argument_t *argument);
138 static void amgtar_backup(application_argument_t *argument);
139 static void amgtar_restore(application_argument_t *argument);
140 static void amgtar_validate(application_argument_t *argument);
141 static void amgtar_build_exinclude(dle_t *dle, int verbose,
142 int *nb_exclude, char **file_exclude,
143 int *nb_include, char **file_include);
144 static char *amgtar_get_incrname(application_argument_t *argument, int level,
145 FILE *mesgstream, int command);
146 static void check_no_check_device(void);
147 static GPtrArray *amgtar_build_argv(char *gnutar_realpath,
148 application_argument_t *argument,
149 char *incrname, char **file_exclude,
150 char **file_include, int command);
151 static char *gnutar_path;
152 static char *gnutar_listdir;
153 static char *gnutar_directory;
154 static int gnutar_onefilesystem;
155 static int gnutar_atimepreserve;
156 static int gnutar_acls;
157 static int gnutar_selinux;
158 static int gnutar_xattrs;
159 static int gnutar_checkdevice;
160 static int gnutar_no_unquote;
161 static int gnutar_sparse;
162 static int gnutar_sparse_set = 0;
163 static GSList *normal_message = NULL;
164 static GSList *ignore_message = NULL;
165 static GSList *strange_message = NULL;
166 static char *exit_handling;
167 static int exit_value[256];
168
169 static struct option long_options[] = {
170 {"config" , 1, NULL, 1},
171 {"host" , 1, NULL, 2},
172 {"disk" , 1, NULL, 3},
173 {"device" , 1, NULL, 4},
174 {"level" , 1, NULL, 5},
175 {"index" , 1, NULL, 6},
176 {"message" , 1, NULL, 7},
177 {"collection" , 0, NULL, 8},
178 {"record" , 0, NULL, 9},
179 {"gnutar-path" , 1, NULL, 10},
180 {"gnutar-listdir" , 1, NULL, 11},
181 {"one-file-system" , 1, NULL, 12},
182 {"sparse" , 1, NULL, 13},
183 {"atime-preserve" , 1, NULL, 14},
184 {"check-device" , 1, NULL, 15},
185 {"include-file" , 1, NULL, 16},
186 {"include-list" , 1, NULL, 17},
187 {"include-optional", 1, NULL, 18},
188 {"exclude-file" , 1, NULL, 19},
189 {"exclude-list" , 1, NULL, 20},
190 {"exclude-optional", 1, NULL, 21},
191 {"directory" , 1, NULL, 22},
192 {"normal" , 1, NULL, 23},
193 {"ignore" , 1, NULL, 24},
194 {"strange" , 1, NULL, 25},
195 {"exit-handling" , 1, NULL, 26},
196 {"calcsize" , 0, NULL, 27},
197 {"tar-blocksize" , 1, NULL, 28},
198 {"no-unquote" , 1, NULL, 29},
199 {"acls" , 1, NULL, 30},
200 {"selinux" , 1, NULL, 31},
201 {"xattrs" , 1, NULL, 32},
202 {"command-options" , 1, NULL, 33},
203 {"include-list-glob", 1, NULL, 34},
204 {"exclude-list-glob", 1, NULL, 35},
205 {"verbose" , 1, NULL, 36},
206 {"ignore-zeros" , 1, NULL, 37},
207 {NULL, 0, NULL, 0}
208 };
209
210 static char *
escape_tar_glob(char * str,int * in_argv)211 escape_tar_glob(
212 char *str,
213 int *in_argv)
214 {
215 char *result = malloc(4*strlen(str)+1);
216 char *r = result;
217 char *s;
218
219 *in_argv = 0;
220 for (s = str; *s != '\0'; s++) {
221 if (*s == '\\') {
222 char c = *(s+1);
223 if (c == '\\') {
224 *r++ = '\\';
225 *r++ = '\\';
226 *r++ = '\\';
227 s++;
228 } else if (c == '?') {
229 *r++ = 127;
230 s++;
231 continue;
232 } else if (c == 'a') {
233 *r++ = 7;
234 s++;
235 continue;
236 } else if (c == 'b') {
237 *r++ = 8;
238 s++;
239 continue;
240 } else if (c == 'f') {
241 *r++ = 12;
242 s++;
243 continue;
244 } else if (c == 'n') {
245 *r++ = 10;
246 s++;
247 *in_argv = 1;
248 continue;
249 } else if (c == 'r') {
250 *r++ = 13;
251 s++;
252 *in_argv = 1;
253 continue;
254 } else if (c == 't') {
255 *r++ = 9;
256 s++;
257 continue;
258 } else if (c == 'v') {
259 *r++ = 11;
260 s++;
261 continue;
262 } else if (c >= '0' && c <= '9') {
263 char d = c-'0';
264 s++;
265 c = *(s+1);
266 if (c >= '0' && c <= '9') {
267 d = (d*8)+(c-'0');
268 s++;
269 c = *(s+1);
270 if (c >= '0' && c <= '9') {
271 d = (d*8)+(c-'0');
272 s++;
273 }
274 }
275 *r++ = d;
276 continue;
277 } else {
278 *r++ = '\\';
279 }
280 } else if (*s == '?') {
281 *r++ = '\\';
282 *r++ = '\\';
283 } else if (*s == '*' || *s == '[') {
284 *r++ = '\\';
285 }
286 *r++ = *s;
287 }
288 *r = '\0';
289
290 return result;
291 }
292
293
294 int
main(int argc,char ** argv)295 main(
296 int argc,
297 char ** argv)
298 {
299 int c;
300 char *command;
301 application_argument_t argument;
302 int i;
303
304 #ifdef GNUTAR
305 gnutar_path = GNUTAR;
306 #else
307 gnutar_path = NULL;
308 #endif
309 gnutar_listdir = NULL;
310 gnutar_directory = NULL;
311 gnutar_onefilesystem = 1;
312 gnutar_atimepreserve = 1;
313 gnutar_acls = 0;
314 gnutar_selinux = 0;
315 gnutar_xattrs = 0;
316 gnutar_checkdevice = 1;
317 gnutar_sparse = 1;
318 gnutar_no_unquote = 0;
319 exit_handling = NULL;
320
321 /* initialize */
322
323 /*
324 * Configure program for internationalization:
325 * 1) Only set the message locale for now.
326 * 2) Set textdomain for all amanda related programs to "amanda"
327 * We don't want to be forced to support dozens of message catalogs.
328 */
329 setlocale(LC_MESSAGES, "C");
330 textdomain("amanda");
331
332 if (argc < 2) {
333 printf("ERROR no command given to amgtar\n");
334 error(_("No command given to amgtar"));
335 }
336
337 /* drop root privileges */
338 if (!set_root_privs(0)) {
339 if (strcmp(argv[1], "selfcheck") == 0) {
340 printf("ERROR amgtar must be run setuid root\n");
341 }
342 error(_("amgtar must be run setuid root"));
343 }
344
345 safe_fd(3, 2);
346
347 set_pname("amgtar");
348
349 /* Don't die when child closes pipe */
350 signal(SIGPIPE, SIG_IGN);
351
352 #if defined(USE_DBMALLOC)
353 malloc_size_1 = malloc_inuse(&malloc_hist_1);
354 #endif
355
356 add_amanda_log_handler(amanda_log_stderr);
357 add_amanda_log_handler(amanda_log_syslog);
358 dbopen(DBG_SUBDIR_CLIENT);
359 startclock();
360 dbprintf(_("version %s\n"), VERSION);
361
362 config_init(CONFIG_INIT_CLIENT, NULL);
363
364 //check_running_as(RUNNING_AS_DUMPUSER_PREFERRED);
365 //root for amrecover
366 //RUNNING_AS_CLIENT_LOGIN from selfcheck, sendsize, sendbackup
367
368 /* parse argument */
369 command = argv[1];
370
371 argument.config = NULL;
372 argument.host = NULL;
373 argument.message = 0;
374 argument.collection = 0;
375 argument.calcsize = 0;
376 argument.tar_blocksize = NULL;
377 argument.level = NULL;
378 argument.command_options = NULL;
379 argument.include_list_glob = NULL;
380 argument.exclude_list_glob = NULL;
381 argument.verbose = 0;
382 argument.ignore_zeros = 1;
383 init_dle(&argument.dle);
384 argument.dle.record = 0;
385
386 while (1) {
387 int option_index = 0;
388 c = getopt_long (argc, argv, "", long_options, &option_index);
389 if (c == -1) {
390 break;
391 }
392 switch (c) {
393 case 1: argument.config = stralloc(optarg);
394 break;
395 case 2: argument.host = stralloc(optarg);
396 break;
397 case 3: argument.dle.disk = stralloc(optarg);
398 break;
399 case 4: argument.dle.device = stralloc(optarg);
400 break;
401 case 5: argument.level = g_slist_append(argument.level,
402 GINT_TO_POINTER(atoi(optarg)));
403 break;
404 case 6: argument.dle.create_index = 1;
405 break;
406 case 7: argument.message = 1;
407 break;
408 case 8: argument.collection = 1;
409 break;
410 case 9: argument.dle.record = 1;
411 break;
412 case 10: gnutar_path = stralloc(optarg);
413 break;
414 case 11: gnutar_listdir = stralloc(optarg);
415 break;
416 case 12: if (optarg && strcasecmp(optarg, "NO") == 0)
417 gnutar_onefilesystem = 0;
418 else if (optarg && strcasecmp(optarg, "YES") == 0)
419 gnutar_onefilesystem = 1;
420 else if (strcasecmp(command, "selfcheck") == 0)
421 printf(_("ERROR [%s: bad ONE-FILE-SYSTEM property value (%s)]\n"), get_pname(), optarg);
422 break;
423 case 13: gnutar_sparse_set = 1;
424 if (optarg && strcasecmp(optarg, "NO") == 0)
425 gnutar_sparse = 0;
426 else if (optarg && strcasecmp(optarg, "YES") == 0)
427 gnutar_sparse = 1;
428 else if (strcasecmp(command, "selfcheck") == 0)
429 printf(_("ERROR [%s: bad SPARSE property value (%s)]\n"), get_pname(), optarg);
430 break;
431 case 14: if (optarg && strcasecmp(optarg, "NO") == 0)
432 gnutar_atimepreserve = 0;
433 else if (optarg && strcasecmp(optarg, "YES") == 0)
434 gnutar_atimepreserve = 1;
435 else if (strcasecmp(command, "selfcheck") == 0)
436 printf(_("ERROR [%s: bad ATIME-PRESERVE property value (%s)]\n"), get_pname(), optarg);
437 break;
438 case 15: if (optarg && strcasecmp(optarg, "NO") == 0)
439 gnutar_checkdevice = 0;
440 else if (optarg && strcasecmp(optarg, "YES") == 0)
441 gnutar_checkdevice = 1;
442 else if (strcasecmp(command, "selfcheck") == 0)
443 printf(_("ERROR [%s: bad CHECK-DEVICE property value (%s)]\n"), get_pname(), optarg);
444 break;
445 case 16: if (optarg)
446 argument.dle.include_file =
447 append_sl(argument.dle.include_file, optarg);
448 break;
449 case 17: if (optarg)
450 argument.dle.include_list =
451 append_sl(argument.dle.include_list, optarg);
452 break;
453 case 18: argument.dle.include_optional = 1;
454 break;
455 case 19: if (optarg)
456 argument.dle.exclude_file =
457 append_sl(argument.dle.exclude_file, optarg);
458 break;
459 case 20: if (optarg)
460 argument.dle.exclude_list =
461 append_sl(argument.dle.exclude_list, optarg);
462 break;
463 case 21: argument.dle.exclude_optional = 1;
464 break;
465 case 22: gnutar_directory = stralloc(optarg);
466 break;
467 case 23: if (optarg)
468 normal_message =
469 g_slist_append(normal_message, optarg);
470 break;
471 case 24: if (optarg)
472 ignore_message =
473 g_slist_append(ignore_message, optarg);
474 break;
475 case 25: if (optarg)
476 strange_message =
477 g_slist_append(strange_message, optarg);
478 break;
479 case 26: if (optarg)
480 exit_handling = stralloc(optarg);
481 break;
482 case 27: argument.calcsize = 1;
483 break;
484 case 28: argument.tar_blocksize = stralloc(optarg);
485 break;
486 case 29: if (optarg && strcasecmp(optarg, "NO") == 0)
487 gnutar_no_unquote = 0;
488 else if (optarg && strcasecmp(optarg, "YES") == 0)
489 gnutar_no_unquote = 1;
490 else if (strcasecmp(command, "selfcheck") == 0)
491 printf(_("ERROR [%s: bad No_UNQUOTE property value (%s)]\n"), get_pname(), optarg);
492 break;
493 case 30: if (optarg && strcasecmp(optarg, "YES") == 0)
494 gnutar_acls = 1;
495 break;
496 case 31: if (optarg && strcasecmp(optarg, "YES") == 0)
497 gnutar_selinux = 1;
498 break;
499 case 32: if (optarg && strcasecmp(optarg, "YES") == 0)
500 gnutar_xattrs = 1;
501 break;
502 case 33: argument.command_options =
503 g_slist_append(argument.command_options,
504 stralloc(optarg));
505 break;
506 case 34: if (optarg)
507 argument.include_list_glob = stralloc(optarg);
508 break;
509 case 35: if (optarg)
510 argument.exclude_list_glob = stralloc(optarg);
511 break;
512 case 36: if (optarg && strcasecmp(optarg, "YES") == 0)
513 argument.verbose = 1;
514 break;
515 case 37: if (strcasecmp(optarg, "YES") != 0)
516 argument.ignore_zeros = 0;
517 break;
518 case ':':
519 case '?':
520 break;
521 }
522 }
523
524 if (!argument.dle.disk && argument.dle.device)
525 argument.dle.disk = stralloc(argument.dle.device);
526 if (!argument.dle.device && argument.dle.disk)
527 argument.dle.device = stralloc(argument.dle.disk);
528
529 argument.argc = argc - optind;
530 argument.argv = argv + optind;
531
532 if (argument.config) {
533 config_init(CONFIG_INIT_CLIENT | CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_OVERLAY,
534 argument.config);
535 dbrename(get_config_name(), DBG_SUBDIR_CLIENT);
536 }
537
538 if (config_errors(NULL) >= CFGERR_ERRORS) {
539 g_critical(_("errors processing config file"));
540 }
541
542 if (!gnutar_listdir) {
543 gnutar_listdir = g_strdup(getconf_str(CNF_GNUTAR_LIST_DIR));
544 }
545
546 re_table = build_re_table(init_re_table, normal_message, ignore_message,
547 strange_message);
548
549 for(i=0;i<256;i++)
550 exit_value[i] = 1; /* BAD */
551 exit_value[0] = 0; /* GOOD */
552 exit_value[1] = 0; /* GOOD */
553 if (exit_handling) {
554 char *s = exit_handling;
555 while (s) {
556 char *r = strchr(s, '=');
557 if (r) {
558 int j = atoi(s);
559 if (j >= 0 && j < 256) {
560 r++;
561 if (strncasecmp(r, "GOOD", 4) == 0) {
562 exit_value[j] = 0;
563 }
564 }
565 }
566 s = strchr(s+1, ' ');
567 }
568 }
569
570 if (strlen(gnutar_listdir) == 0)
571 gnutar_listdir = NULL;
572
573 if (gnutar_path) {
574 dbprintf("GNUTAR-PATH %s\n", gnutar_path);
575 } else {
576 dbprintf("GNUTAR-PATH is not set\n");
577 }
578 if (gnutar_listdir) {
579 dbprintf("GNUTAR-LISTDIR %s\n", gnutar_listdir);
580 } else {
581 dbprintf("GNUTAR-LISTDIR is not set\n");
582 }
583 if (gnutar_directory) {
584 dbprintf("DIRECTORY %s\n", gnutar_directory);
585 }
586 dbprintf("ONE-FILE-SYSTEM %s\n", gnutar_onefilesystem? "yes":"no");
587 dbprintf("SPARSE %s\n", gnutar_sparse? "yes":"no");
588 dbprintf("NO-UNQUOTE %s\n", gnutar_no_unquote? "yes":"no");
589 dbprintf("ATIME-PRESERVE %s\n", gnutar_atimepreserve? "yes":"no");
590 dbprintf("ACLS %s\n", gnutar_acls? "yes":"no");
591 dbprintf("SELINUX %s\n", gnutar_selinux? "yes":"no");
592 dbprintf("XATTRS %s\n", gnutar_xattrs? "yes":"no");
593 dbprintf("CHECK-DEVICE %s\n", gnutar_checkdevice? "yes":"no");
594 {
595 amregex_t *rp;
596 for (rp = re_table; rp->regex != NULL; rp++) {
597 switch (rp->typ) {
598 case DMP_NORMAL : dbprintf("NORMAL %s\n", rp->regex); break;
599 case DMP_IGNORE : dbprintf("IGNORE %s\n", rp->regex); break;
600 case DMP_STRANGE: dbprintf("STRANGE %s\n", rp->regex); break;
601 case DMP_SIZE : dbprintf("SIZE %s\n", rp->regex); break;
602 case DMP_ERROR : dbprintf("ERROR %s\n", rp->regex); break;
603 }
604 }
605 }
606
607 if (strcmp(command, "support") == 0) {
608 amgtar_support(&argument);
609 } else if (strcmp(command, "selfcheck") == 0) {
610 amgtar_selfcheck(&argument);
611 } else if (strcmp(command, "estimate") == 0) {
612 amgtar_estimate(&argument);
613 } else if (strcmp(command, "backup") == 0) {
614 amgtar_backup(&argument);
615 } else if (strcmp(command, "restore") == 0) {
616 amgtar_restore(&argument);
617 } else if (strcmp(command, "validate") == 0) {
618 amgtar_validate(&argument);
619 } else {
620 dbprintf("Unknown command `%s'.\n", command);
621 fprintf(stderr, "Unknown command `%s'.\n", command);
622 exit (1);
623 }
624
625 dbclose();
626
627 return 0;
628 }
629
validate_command_options(application_argument_t * argument)630 static char *validate_command_options(
631 application_argument_t *argument)
632 {
633 GSList *copt;
634
635 for (copt = argument->command_options; copt != NULL; copt = copt->next) {
636 char *opt = (char *)copt->data;
637
638 if (g_str_has_prefix(opt, "--rsh-command") ||
639 g_str_has_prefix(opt,"--to-command") ||
640 g_str_has_prefix(opt,"--info-script") ||
641 g_str_has_prefix(opt,"--new-volume-script") ||
642 g_str_has_prefix(opt,"--rmt-command") ||
643 g_str_has_prefix(opt,"--use-compress-program")) {
644 return opt;
645 }
646 }
647
648 return NULL;
649 }
650
651 static void
amgtar_support(application_argument_t * argument)652 amgtar_support(
653 application_argument_t *argument)
654 {
655 (void)argument;
656 fprintf(stdout, "CONFIG YES\n");
657 fprintf(stdout, "HOST YES\n");
658 fprintf(stdout, "DISK YES\n");
659 fprintf(stdout, "MAX-LEVEL 399\n");
660 fprintf(stdout, "INDEX-LINE YES\n");
661 fprintf(stdout, "INDEX-XML NO\n");
662 fprintf(stdout, "MESSAGE-LINE YES\n");
663 fprintf(stdout, "MESSAGE-XML NO\n");
664 fprintf(stdout, "RECORD YES\n");
665 fprintf(stdout, "INCLUDE-FILE YES\n");
666 fprintf(stdout, "INCLUDE-LIST YES\n");
667 fprintf(stdout, "INCLUDE-LIST-GLOB YES\n");
668 fprintf(stdout, "INCLUDE-OPTIONAL YES\n");
669 fprintf(stdout, "EXCLUDE-FILE YES\n");
670 fprintf(stdout, "EXCLUDE-LIST YES\n");
671 fprintf(stdout, "EXCLUDE-LIST-GLOB YES\n");
672 fprintf(stdout, "EXCLUDE-OPTIONAL YES\n");
673 fprintf(stdout, "COLLECTION NO\n");
674 fprintf(stdout, "MULTI-ESTIMATE YES\n");
675 fprintf(stdout, "CALCSIZE YES\n");
676 fprintf(stdout, "CLIENT-ESTIMATE YES\n");
677 }
678
679 static void
amgtar_selfcheck(application_argument_t * argument)680 amgtar_selfcheck(
681 application_argument_t *argument)
682 {
683 char *option;
684
685 if (argument->dle.disk) {
686 char *qdisk = quote_string(argument->dle.disk);
687 fprintf(stdout, "OK disk %s\n", qdisk);
688 amfree(qdisk);
689 }
690
691 printf("OK amgtar version %s\n", VERSION);
692 amgtar_build_exinclude(&argument->dle, 1, NULL, NULL, NULL, NULL);
693
694 printf("OK amgtar\n");
695
696
697 if ((option = validate_command_options(argument))) {
698 fprintf(stdout, "ERROR [Invalid '%s' COMMAND-OPTIONS\n", option);
699 }
700
701 if (gnutar_path) {
702 char *gnutar_realpath = NULL;
703 if (check_file(gnutar_path, X_OK) &&
704 check_exec_for_suid("GNUTAR_PATH", gnutar_path, stdout, &gnutar_realpath)) {
705 char *gtar_version;
706 GPtrArray *argv_ptr = g_ptr_array_new();
707
708 g_ptr_array_add(argv_ptr, gnutar_realpath);
709 g_ptr_array_add(argv_ptr, "--version");
710 g_ptr_array_add(argv_ptr, NULL);
711
712 gtar_version = get_first_line(argv_ptr);
713 if (gtar_version) {
714 char *gv;
715 for (gv = gtar_version; *gv && !g_ascii_isdigit(*gv); gv++);
716 printf("OK amgtar gtar-version %s\n", gv);
717 } else {
718 printf(_("ERROR [Can't get %s version]\n"), gnutar_realpath);
719 }
720
721 g_ptr_array_free(argv_ptr, TRUE);
722 amfree(gtar_version);
723 }
724 amfree(gnutar_realpath);
725 } else {
726 printf(_("ERROR [GNUTAR program not available]\n"));
727 }
728 if (gnutar_listdir && strlen(gnutar_listdir) == 0)
729 gnutar_listdir = NULL;
730 if (gnutar_listdir) {
731 check_dir(gnutar_listdir, R_OK|W_OK);
732 } else {
733 printf(_("ERROR [No GNUTAR-LISTDIR]\n"));
734 }
735
736 set_root_privs(1);
737 if (gnutar_directory) {
738 check_dir(gnutar_directory, R_OK);
739 } else if (argument->dle.device) {
740 check_dir(argument->dle.device, R_OK);
741 }
742 if (argument->calcsize) {
743 char *calcsize = vstralloc(amlibexecdir, "/", "calcsize", NULL);
744 check_file(calcsize, X_OK);
745 check_suid(calcsize);
746 amfree(calcsize);
747 }
748 set_root_privs(0);
749 }
750
751 static void
amgtar_estimate(application_argument_t * argument)752 amgtar_estimate(
753 application_argument_t *argument)
754 {
755 char *incrname = NULL;
756 GPtrArray *argv_ptr;
757 int nullfd = -1;
758 int pipefd = -1;
759 FILE *dumpout = NULL;
760 off_t size = -1;
761 char line[32768];
762 char *errmsg = NULL;
763 char *qerrmsg = NULL;
764 char *qdisk;
765 amwait_t wait_status;
766 int tarpid;
767 amregex_t *rp;
768 times_t start_time;
769 int level;
770 GSList *levels;
771 char *file_exclude;
772 char *file_include;
773 char *option;
774 char *gnutar_realpath = NULL;
775
776 if (!argument->level) {
777 fprintf(stderr, "ERROR No level argument\n");
778 error(_("No level argument"));
779 }
780 if (!argument->dle.disk) {
781 fprintf(stderr, "ERROR No disk argument\n");
782 error(_("No disk argument"));
783 }
784 if (!argument->dle.device) {
785 fprintf(stderr, "ERROR No device argument\n");
786 error(_("No device argument"));
787 }
788
789 qdisk = quote_string(argument->dle.disk);
790
791 if ((option = validate_command_options(argument))) {
792 fprintf(stderr, "ERROR Invalid '%s' COMMAND-OPTIONS\n", option);
793 error("Invalid '%s' COMMAND-OPTIONS", option);
794 }
795
796 if (argument->calcsize) {
797 char *dirname;
798 int nb_exclude;
799 int nb_include;
800
801 if (gnutar_directory) {
802 dirname = gnutar_directory;
803 } else {
804 dirname = argument->dle.device;
805 }
806
807 amgtar_build_exinclude(&argument->dle, 1,
808 &nb_exclude, &file_exclude,
809 &nb_include, &file_include);
810
811 run_calcsize(argument->config, "GNUTAR", argument->dle.disk, dirname,
812 argument->level, file_exclude, file_include);
813
814 if (argument->verbose == 0) {
815 if (file_exclude)
816 unlink(file_exclude);
817 if (file_include)
818 unlink(file_include);
819 }
820 return;
821 }
822
823 if (!gnutar_path) {
824 errmsg = vstrallocf(_("GNUTAR-PATH not defined"));
825 goto common_error;
826 }
827
828 if (!check_exec_for_suid("GNUTAR_PATH", gnutar_path, stderr, &gnutar_realpath)) {
829 errmsg = g_strdup_printf("'%s' binary is not secure", gnutar_path);
830 goto common_error;
831 }
832
833 if (!gnutar_listdir) {
834 errmsg = vstrallocf(_("GNUTAR-LISTDIR not defined"));
835 goto common_error;
836 }
837
838 for (levels = argument->level; levels != NULL; levels = levels->next) {
839 level = GPOINTER_TO_INT(levels->data);
840 incrname = amgtar_get_incrname(argument, level, stdout, CMD_ESTIMATE);
841 argv_ptr = amgtar_build_argv(gnutar_realpath,
842 argument, incrname, &file_exclude,
843 &file_include, CMD_ESTIMATE);
844
845 start_time = curclock();
846
847 if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
848 errmsg = vstrallocf(_("Cannot access /dev/null : %s"),
849 strerror(errno));
850 goto common_exit;
851 }
852
853 tarpid = pipespawnv(gnutar_realpath, STDERR_PIPE, 1,
854 &nullfd, &nullfd, &pipefd,
855 (char **)argv_ptr->pdata);
856
857 dumpout = fdopen(pipefd,"r");
858 if (!dumpout) {
859 error(_("Can't fdopen: %s"), strerror(errno));
860 /*NOTREACHED*/
861 }
862
863 size = (off_t)-1;
864 while (size < 0 && (fgets(line, sizeof(line), dumpout) != NULL)) {
865 if (line[strlen(line)-1] == '\n') /* remove trailling \n */
866 line[strlen(line)-1] = '\0';
867 if (line[0] == '\0')
868 continue;
869 dbprintf("%s\n", line);
870 /* check for size match */
871 /*@ignore@*/
872 for(rp = re_table; rp->regex != NULL; rp++) {
873 if(match(rp->regex, line)) {
874 if (rp->typ == DMP_SIZE) {
875 size = ((the_num(line, rp->field)*rp->scale+1023.0)/1024.0);
876 if(size < 0.0)
877 size = 1.0; /* found on NeXT -- sigh */
878 }
879 break;
880 }
881 }
882 /*@end@*/
883 }
884
885 while (fgets(line, sizeof(line), dumpout) != NULL) {
886 dbprintf("%s", line);
887 }
888
889 dbprintf(".....\n");
890 dbprintf(_("estimate time for %s level %d: %s\n"),
891 qdisk,
892 level,
893 walltime_str(timessub(curclock(), start_time)));
894 if(size == (off_t)-1) {
895 errmsg = vstrallocf(_("no size line match in %s output"), gnutar_realpath);
896 dbprintf(_("%s for %s\n"), errmsg, qdisk);
897 dbprintf(".....\n");
898 } else if(size == (off_t)0 && argument->level == 0) {
899 dbprintf(_("possible %s problem -- is \"%s\" really empty?\n"),
900 gnutar_realpath, argument->dle.disk);
901 dbprintf(".....\n");
902 }
903 dbprintf(_("estimate size for %s level %d: %lld KB\n"),
904 qdisk,
905 level,
906 (long long)size);
907
908 kill(-tarpid, SIGTERM);
909
910 dbprintf(_("waiting for %s \"%s\" child\n"), gnutar_realpath, qdisk);
911 waitpid(tarpid, &wait_status, 0);
912 if (WIFSIGNALED(wait_status)) {
913 errmsg = vstrallocf(_("%s terminated with signal %d: see %s"),
914 gnutar_realpath, WTERMSIG(wait_status), dbfn());
915 } else if (WIFEXITED(wait_status)) {
916 if (exit_value[WEXITSTATUS(wait_status)] == 1) {
917 errmsg = vstrallocf(_("%s exited with status %d: see %s"),
918 gnutar_realpath, WEXITSTATUS(wait_status), dbfn());
919 } else {
920 /* Normal exit */
921 }
922 } else {
923 errmsg = vstrallocf(_("%s got bad exit: see %s"),
924 gnutar_realpath, dbfn());
925 }
926 dbprintf(_("after %s %s wait\n"), gnutar_realpath, qdisk);
927
928 common_exit:
929 if (errmsg) {
930 dbprintf("%s", errmsg);
931 fprintf(stdout, "ERROR %s\n", errmsg);
932 }
933
934 if (incrname) {
935 unlink(incrname);
936 }
937
938 if (argument->verbose == 0) {
939 if (file_exclude)
940 unlink(file_exclude);
941 if (file_include)
942 unlink(file_include);
943 }
944
945 g_ptr_array_free_full(argv_ptr);
946
947 aclose(nullfd);
948 afclose(dumpout);
949
950 fprintf(stdout, "%d %lld 1\n", level, (long long)size);
951 }
952 amfree(qdisk);
953 amfree(gnutar_realpath);
954 return;
955
956 common_error:
957 qerrmsg = quote_string(errmsg);
958 amfree(qdisk);
959 dbprintf("%s", errmsg);
960 fprintf(stdout, "ERROR %s\n", qerrmsg);
961 amfree(errmsg);
962 amfree(qerrmsg);
963 amfree(gnutar_realpath);
964 return;
965 }
966
967 static void
amgtar_backup(application_argument_t * argument)968 amgtar_backup(
969 application_argument_t *argument)
970 {
971 int dumpin;
972 char *qdisk;
973 char *incrname;
974 char line[32768];
975 amregex_t *rp;
976 off_t dump_size = -1;
977 char *type;
978 char startchr;
979 int dataf = 1;
980 int mesgf = 3;
981 int indexf = 4;
982 int outf;
983 FILE *mesgstream;
984 FILE *indexstream = NULL;
985 FILE *outstream;
986 char *errmsg = NULL;
987 amwait_t wait_status;
988 GPtrArray *argv_ptr;
989 int tarpid;
990 char *file_exclude;
991 char *file_include;
992 char *option;
993 char *gnutar_realpath = NULL;
994
995 mesgstream = fdopen(mesgf, "w");
996 if (!mesgstream) {
997 error(_("error mesgstream(%d): %s\n"), mesgf, strerror(errno));
998 }
999
1000 if (!gnutar_path) {
1001 fprintf(mesgstream, "? GNUTAR-PATH not defined\n");
1002 error(_("GNUTAR-PATH not defined"));
1003 }
1004 if (!gnutar_listdir) {
1005 fprintf(mesgstream, "? GNUTAR-LISTDIR not defined\n");
1006 error(_("GNUTAR-LISTDIR not defined"));
1007 }
1008
1009 if (!argument->level) {
1010 fprintf(mesgstream, "? No level argument\n");
1011 error(_("No level argument"));
1012 }
1013 if (!argument->dle.disk) {
1014 fprintf(mesgstream, "? No disk argument\n");
1015 error(_("No disk argument"));
1016 }
1017 if (!argument->dle.device) {
1018 fprintf(mesgstream, "? No device argument\n");
1019 error(_("No device argument"));
1020 }
1021
1022 if (!check_exec_for_suid("GNUTAR_PATH", gnutar_path, NULL, &gnutar_realpath)) {
1023 fprintf(mesgstream, "? '%s' binary is not secure\n", gnutar_path);
1024 error("'%s' binary is not secure", gnutar_path);
1025 }
1026
1027 if ((option = validate_command_options(argument))) {
1028 fprintf(mesgstream, "? Invalid '%s' COMMAND-OPTIONS\n", option);
1029 error("Invalid '%s' COMMAND-OPTIONS", option);
1030 }
1031
1032 qdisk = quote_string(argument->dle.disk);
1033
1034 incrname = amgtar_get_incrname(argument,
1035 GPOINTER_TO_INT(argument->level->data),
1036 mesgstream, CMD_BACKUP);
1037 argv_ptr = amgtar_build_argv(gnutar_realpath,
1038 argument, incrname, &file_exclude,
1039 &file_include, CMD_BACKUP);
1040
1041 tarpid = pipespawnv(gnutar_realpath, STDIN_PIPE|STDERR_PIPE, 1,
1042 &dumpin, &dataf, &outf, (char **)argv_ptr->pdata);
1043 /* close the write ends of the pipes */
1044
1045 aclose(dumpin);
1046 aclose(dataf);
1047 if (argument->dle.create_index) {
1048 indexstream = fdopen(indexf, "w");
1049 if (!indexstream) {
1050 error(_("error indexstream(%d): %s\n"), indexf, strerror(errno));
1051 }
1052 }
1053 outstream = fdopen(outf, "r");
1054 if (!outstream) {
1055 error(_("error outstream(%d): %s\n"), outf, strerror(errno));
1056 }
1057
1058 while (fgets(line, sizeof(line), outstream) != NULL) {
1059 if (line[strlen(line)-1] == '\n') /* remove trailling \n */
1060 line[strlen(line)-1] = '\0';
1061 if (*line == '.' && *(line+1) == '/') { /* filename */
1062 if (argument->dle.create_index) {
1063 fprintf(indexstream, "%s\n", &line[1]); /* remove . */
1064 }
1065 } else { /* message */
1066 for(rp = re_table; rp->regex != NULL; rp++) {
1067 if(match(rp->regex, line)) {
1068 break;
1069 }
1070 }
1071 if(rp->typ == DMP_SIZE) {
1072 dump_size = (off_t)((the_num(line, rp->field)* rp->scale+1023.0)/1024.0);
1073 }
1074 switch(rp->typ) {
1075 case DMP_NORMAL:
1076 type = "normal";
1077 startchr = '|';
1078 break;
1079 case DMP_IGNORE:
1080 continue;
1081 case DMP_STRANGE:
1082 type = "strange";
1083 startchr = '?';
1084 break;
1085 case DMP_SIZE:
1086 type = "size";
1087 startchr = '|';
1088 break;
1089 case DMP_ERROR:
1090 type = "error";
1091 startchr = '?';
1092 break;
1093 default:
1094 type = "unknown";
1095 startchr = '!';
1096 break;
1097 }
1098 dbprintf("%3d: %7s(%c): %s\n", rp->srcline, type, startchr, line);
1099 fprintf(mesgstream,"%c %s\n", startchr, line);
1100 }
1101 }
1102
1103 waitpid(tarpid, &wait_status, 0);
1104 if (WIFSIGNALED(wait_status)) {
1105 errmsg = vstrallocf(_("%s terminated with signal %d: see %s"),
1106 gnutar_realpath, WTERMSIG(wait_status), dbfn());
1107 } else if (WIFEXITED(wait_status)) {
1108 if (exit_value[WEXITSTATUS(wait_status)] == 1) {
1109 errmsg = vstrallocf(_("%s exited with status %d: see %s"),
1110 gnutar_realpath, WEXITSTATUS(wait_status), dbfn());
1111 } else {
1112 /* Normal exit */
1113 }
1114 } else {
1115 errmsg = vstrallocf(_("%s got bad exit: see %s"),
1116 gnutar_realpath, dbfn());
1117 }
1118 dbprintf(_("after %s %s wait\n"), gnutar_realpath, qdisk);
1119 dbprintf(_("amgtar: %s: pid %ld\n"), gnutar_realpath, (long)tarpid);
1120 if (errmsg) {
1121 dbprintf("%s", errmsg);
1122 g_fprintf(mesgstream, "sendbackup: error [%s]\n", errmsg);
1123 }
1124
1125 if (!errmsg && incrname && strlen(incrname) > 4) {
1126 if (argument->dle.record) {
1127 char *nodotnew;
1128 nodotnew = stralloc(incrname);
1129 nodotnew[strlen(nodotnew)-4] = '\0';
1130 if (rename(incrname, nodotnew)) {
1131 dbprintf(_("%s: warning [renaming %s to %s: %s]\n"),
1132 get_pname(), incrname, nodotnew, strerror(errno));
1133 g_fprintf(mesgstream, _("? warning [renaming %s to %s: %s]\n"),
1134 incrname, nodotnew, strerror(errno));
1135 }
1136 amfree(nodotnew);
1137 } else {
1138 if (unlink(incrname) == -1) {
1139 dbprintf(_("%s: warning [unlink %s: %s]\n"),
1140 get_pname(), incrname, strerror(errno));
1141 g_fprintf(mesgstream, _("? warning [unlink %s: %s]\n"),
1142 incrname, strerror(errno));
1143 }
1144 }
1145 }
1146
1147 dbprintf("sendbackup: size %lld\n", (long long)dump_size);
1148 fprintf(mesgstream, "sendbackup: size %lld\n", (long long)dump_size);
1149 dbprintf("sendbackup: end\n");
1150 fprintf(mesgstream, "sendbackup: end\n");
1151
1152 if (argument->dle.create_index)
1153 fclose(indexstream);
1154
1155 fclose(mesgstream);
1156
1157 if (argument->verbose == 0) {
1158 if (file_exclude)
1159 unlink(file_exclude);
1160 if (file_include)
1161 unlink(file_include);
1162 }
1163
1164 amfree(incrname);
1165 amfree(qdisk);
1166 amfree(gnutar_realpath);
1167 g_ptr_array_free_full(argv_ptr);
1168 }
1169
1170 static void
amgtar_restore(application_argument_t * argument)1171 amgtar_restore(
1172 application_argument_t *argument)
1173 {
1174 GPtrArray *argv_ptr = g_ptr_array_new();
1175 char **env;
1176 int j;
1177 char *e;
1178 char *include_filename = NULL;
1179 char *exclude_filename = NULL;
1180 char *gnutar_realpath = NULL;
1181
1182 if (!gnutar_path) {
1183 error(_("GNUTAR-PATH not defined"));
1184 }
1185
1186 if (!check_exec_for_suid("GNUTAR_PATH", gnutar_path, NULL, &gnutar_realpath)) {
1187 error("'%s' binary is not secure", gnutar_path);
1188 }
1189
1190 if (!security_allow_to_restore(NULL)) {
1191 error("The user is not allowed to restore files");
1192 }
1193
1194 g_ptr_array_add(argv_ptr, stralloc(gnutar_realpath));
1195 g_ptr_array_add(argv_ptr, stralloc("--numeric-owner"));
1196 if (gnutar_no_unquote)
1197 g_ptr_array_add(argv_ptr, stralloc("--no-unquote"));
1198 if (gnutar_acls)
1199 g_ptr_array_add(argv_ptr, stralloc("--acls"));
1200 if (gnutar_selinux)
1201 g_ptr_array_add(argv_ptr, stralloc("--selinux"));
1202 if (gnutar_xattrs)
1203 g_ptr_array_add(argv_ptr, stralloc("--xattrs"));
1204 /* ignore trailing zero blocks on input (this was the default until tar-1.21) */
1205 if (argument->ignore_zeros) {
1206 g_ptr_array_add(argv_ptr, stralloc("--ignore-zeros"));
1207 }
1208 if (argument->tar_blocksize) {
1209 g_ptr_array_add(argv_ptr, stralloc("--blocking-factor"));
1210 g_ptr_array_add(argv_ptr, stralloc(argument->tar_blocksize));
1211 }
1212 g_ptr_array_add(argv_ptr, stralloc("-xpGvf"));
1213 g_ptr_array_add(argv_ptr, stralloc("-"));
1214 if (gnutar_directory) {
1215 struct stat stat_buf;
1216 if(stat(gnutar_directory, &stat_buf) != 0) {
1217 fprintf(stderr,"can not stat directory %s: %s\n", gnutar_directory, strerror(errno));
1218 exit(1);
1219 }
1220 if (!S_ISDIR(stat_buf.st_mode)) {
1221 fprintf(stderr,"%s is not a directory\n", gnutar_directory);
1222 exit(1);
1223 }
1224 if (access(gnutar_directory, W_OK) != 0) {
1225 fprintf(stderr, "Can't write to %s: %s\n", gnutar_directory, strerror(errno));
1226 exit(1);
1227 }
1228 g_ptr_array_add(argv_ptr, stralloc("--directory"));
1229 g_ptr_array_add(argv_ptr, stralloc(gnutar_directory));
1230 }
1231
1232 g_ptr_array_add(argv_ptr, stralloc("--wildcards"));
1233 if (argument->dle.exclude_list &&
1234 argument->dle.exclude_list->nb_element == 1) {
1235 FILE *exclude;
1236 char *sdisk;
1237 int in_argv;
1238 int entry_in_exclude = 0;
1239 char line[2*PATH_MAX];
1240 FILE *exclude_list;
1241
1242 if (argument->dle.disk) {
1243 sdisk = sanitise_filename(argument->dle.disk);
1244 } else {
1245 sdisk = g_strdup_printf("no_dle-%d", (int)getpid());
1246 }
1247 exclude_filename= vstralloc(AMANDA_TMPDIR, "/", "exclude-", sdisk, NULL);
1248 exclude_list = fopen(argument->dle.exclude_list->first->name, "r");
1249
1250 exclude = fopen(exclude_filename, "w");
1251 while (fgets(line, 2*PATH_MAX, exclude_list)) {
1252 char *escaped;
1253 line[strlen(line)-1] = '\0'; /* remove '\n' */
1254 escaped = escape_tar_glob(line, &in_argv);
1255 if (in_argv) {
1256 g_ptr_array_add(argv_ptr, "--exclude");
1257 g_ptr_array_add(argv_ptr, escaped);
1258 } else {
1259 fprintf(exclude,"%s\n", escaped);
1260 entry_in_exclude++;
1261 amfree(escaped);
1262 }
1263 }
1264 fclose(exclude);
1265 g_ptr_array_add(argv_ptr, stralloc("--exclude-from"));
1266 g_ptr_array_add(argv_ptr, exclude_filename);
1267 }
1268
1269 if (argument->exclude_list_glob) {
1270 g_ptr_array_add(argv_ptr, stralloc("--exclude-from"));
1271 g_ptr_array_add(argv_ptr, stralloc(argument->exclude_list_glob));
1272 }
1273
1274 {
1275 GPtrArray *argv_include = g_ptr_array_new();
1276 FILE *include;
1277 char *sdisk;
1278 int in_argv;
1279 guint i;
1280 int entry_in_include = 0;
1281
1282 if (argument->dle.disk) {
1283 sdisk = sanitise_filename(argument->dle.disk);
1284 } else {
1285 sdisk = g_strdup_printf("no_dle-%d", (int)getpid());
1286 }
1287 include_filename = vstralloc(AMANDA_TMPDIR, "/", "include-", sdisk, NULL);
1288 include = fopen(include_filename, "w");
1289 if (argument->dle.include_list &&
1290 argument->dle.include_list->nb_element == 1) {
1291 char line[2*PATH_MAX];
1292 FILE *include_list = fopen(argument->dle.include_list->first->name, "r");
1293 while (fgets(line, 2*PATH_MAX, include_list)) {
1294 char *escaped;
1295 line[strlen(line)-1] = '\0'; /* remove '\n' */
1296 escaped = escape_tar_glob(line, &in_argv);
1297 if (in_argv) {
1298 g_ptr_array_add(argv_include, escaped);
1299 } else {
1300 fprintf(include,"%s\n", escaped);
1301 entry_in_include++;
1302 amfree(escaped);
1303 }
1304 }
1305 }
1306
1307 for (j=1; j< argument->argc; j++) {
1308 char *escaped = escape_tar_glob(argument->argv[j], &in_argv);
1309 if (in_argv) {
1310 g_ptr_array_add(argv_include, escaped);
1311 } else {
1312 fprintf(include,"%s\n", escaped);
1313 entry_in_include++;
1314 amfree(escaped);
1315 }
1316 }
1317 fclose(include);
1318
1319 if (entry_in_include) {
1320 g_ptr_array_add(argv_ptr, stralloc("--files-from"));
1321 g_ptr_array_add(argv_ptr, include_filename);
1322 }
1323
1324 if (argument->include_list_glob) {
1325 g_ptr_array_add(argv_ptr, stralloc("--files-from"));
1326 g_ptr_array_add(argv_ptr, stralloc(argument->include_list_glob));
1327 }
1328
1329 for (i = 0; i < argv_include->len; i++) {
1330 g_ptr_array_add(argv_ptr, (char *)g_ptr_array_index(argv_include,i));
1331 }
1332 }
1333 g_ptr_array_add(argv_ptr, NULL);
1334
1335 debug_executing(argv_ptr);
1336
1337 env = safe_env();
1338 become_root();
1339 execve(gnutar_realpath, (char **)argv_ptr->pdata, env);
1340 e = strerror(errno);
1341 error(_("error [exec %s: %s]"), gnutar_realpath, e);
1342 }
1343
1344 static void
amgtar_validate(application_argument_t * argument G_GNUC_UNUSED)1345 amgtar_validate(
1346 application_argument_t *argument G_GNUC_UNUSED)
1347 {
1348 char *cmd;
1349 GPtrArray *argv_ptr = g_ptr_array_new();
1350 char **env;
1351 char *e;
1352 char buf[32768];
1353
1354 if (!gnutar_path) {
1355 dbprintf("GNUTAR-PATH not set; Piping to /dev/null\n");
1356 fprintf(stderr,"GNUTAR-PATH not set; Piping to /dev/null\n");
1357 goto pipe_to_null;
1358 }
1359
1360 cmd = stralloc(gnutar_path);
1361 g_ptr_array_add(argv_ptr, stralloc(gnutar_path));
1362 /* ignore trailing zero blocks on input (this was the default until tar-1.21) */
1363 g_ptr_array_add(argv_ptr, stralloc("--ignore-zeros"));
1364 g_ptr_array_add(argv_ptr, stralloc("-tf"));
1365 g_ptr_array_add(argv_ptr, stralloc("-"));
1366 g_ptr_array_add(argv_ptr, NULL);
1367
1368 debug_executing(argv_ptr);
1369 env = safe_env();
1370 execve(cmd, (char **)argv_ptr->pdata, env);
1371 e = strerror(errno);
1372 dbprintf("failed to execute %s: %s; Piping to /dev/null\n", cmd, e);
1373 fprintf(stderr,"failed to execute %s: %s; Piping to /dev/null\n", cmd, e);
1374 pipe_to_null:
1375 while (read(0, buf, 32768) > 0) {
1376 }
1377 }
1378
1379 static void
amgtar_build_exinclude(dle_t * dle,int verbose,int * nb_exclude,char ** file_exclude,int * nb_include,char ** file_include)1380 amgtar_build_exinclude(
1381 dle_t *dle,
1382 int verbose,
1383 int *nb_exclude,
1384 char **file_exclude,
1385 int *nb_include,
1386 char **file_include)
1387 {
1388 int n_exclude = 0;
1389 int n_include = 0;
1390 char *exclude = NULL;
1391 char *include = NULL;
1392
1393 if (dle->exclude_file) n_exclude += dle->exclude_file->nb_element;
1394 if (dle->exclude_list) n_exclude += dle->exclude_list->nb_element;
1395 if (dle->include_file) n_include += dle->include_file->nb_element;
1396 if (dle->include_list) n_include += dle->include_list->nb_element;
1397
1398 if (n_exclude > 0) exclude = build_exclude(dle, verbose);
1399 if (n_include > 0) include = build_include(dle, verbose);
1400
1401 if (nb_exclude)
1402 *nb_exclude = n_exclude;
1403 if (file_exclude)
1404 *file_exclude = exclude;
1405 else
1406 amfree(exclude);
1407
1408 if (nb_include)
1409 *nb_include = n_include;
1410 if (file_include)
1411 *file_include = include;
1412 else
1413 amfree(include);
1414 }
1415
1416 static char *
amgtar_get_incrname(application_argument_t * argument,int level,FILE * mesgstream,int command)1417 amgtar_get_incrname(
1418 application_argument_t *argument,
1419 int level,
1420 FILE *mesgstream,
1421 int command)
1422 {
1423 char *basename = NULL;
1424 char *incrname = NULL;
1425 int infd, outfd;
1426 ssize_t nb;
1427 char *inputname = NULL;
1428 char *errmsg = NULL;
1429 char *buf;
1430
1431 if (gnutar_listdir) {
1432 char number[NUM_STR_SIZE];
1433 int baselevel;
1434 char *sdisk = sanitise_filename(argument->dle.disk);
1435
1436 basename = vstralloc(gnutar_listdir,
1437 "/",
1438 argument->host,
1439 sdisk,
1440 NULL);
1441 amfree(sdisk);
1442
1443 snprintf(number, SIZEOF(number), "%d", level);
1444 incrname = vstralloc(basename, "_", number, ".new", NULL);
1445 unlink(incrname);
1446
1447 /*
1448 * Open the listed incremental file from the previous level. Search
1449 * backward until one is found. If none are found (which will also
1450 * be true for a level 0), arrange to read from /dev/null.
1451 */
1452 baselevel = level;
1453 infd = -1;
1454 while (infd == -1) {
1455 if (--baselevel >= 0) {
1456 snprintf(number, SIZEOF(number), "%d", baselevel);
1457 inputname = newvstralloc(inputname,
1458 basename, "_", number, NULL);
1459 } else {
1460 inputname = newstralloc(inputname, "/dev/null");
1461 }
1462 if ((infd = open(inputname, O_RDONLY)) == -1) {
1463
1464 errmsg = vstrallocf(_("amgtar: error opening %s: %s"),
1465 inputname, strerror(errno));
1466 dbprintf("%s\n", errmsg);
1467 if (baselevel < 0) {
1468 if (command == CMD_ESTIMATE) {
1469 fprintf(mesgstream, "ERROR %s\n", errmsg);
1470 } else {
1471 fprintf(mesgstream, "? %s\n", errmsg);
1472 }
1473 exit(1);
1474 }
1475 amfree(errmsg);
1476 }
1477 }
1478
1479 /*
1480 * Copy the previous listed incremental file to the new one.
1481 */
1482 if ((outfd = open(incrname, O_WRONLY|O_CREAT, 0600)) == -1) {
1483 errmsg = vstrallocf(_("error opening %s: %s"),
1484 incrname, strerror(errno));
1485 dbprintf("%s\n", errmsg);
1486 if (command == CMD_ESTIMATE) {
1487 fprintf(mesgstream, "ERROR %s\n", errmsg);
1488 } else {
1489 fprintf(mesgstream, "? %s\n", errmsg);
1490 }
1491 exit(1);
1492 }
1493
1494 while ((nb = read(infd, &buf, SIZEOF(buf))) > 0) {
1495 if (full_write(outfd, &buf, (size_t)nb) < (size_t)nb) {
1496 errmsg = vstrallocf(_("writing to %s: %s"),
1497 incrname, strerror(errno));
1498 dbprintf("%s\n", errmsg);
1499 if (command == CMD_ESTIMATE) {
1500 fprintf(mesgstream, "ERROR %s\n", errmsg);
1501 } else {
1502 fprintf(mesgstream, "? %s\n", errmsg);
1503 }
1504 exit(1);
1505 }
1506 }
1507
1508 if (nb < 0) {
1509 errmsg = vstrallocf(_("reading from %s: %s"),
1510 inputname, strerror(errno));
1511 dbprintf("%s\n", errmsg);
1512 if (command == CMD_ESTIMATE) {
1513 fprintf(mesgstream, "ERROR %s\n", errmsg);
1514 } else {
1515 fprintf(mesgstream, "? %s\n", errmsg);
1516 }
1517 exit(1);
1518 }
1519
1520 if (close(infd) != 0) {
1521 errmsg = vstrallocf(_("closing %s: %s"),
1522 inputname, strerror(errno));
1523 dbprintf("%s\n", errmsg);
1524 if (command == CMD_ESTIMATE) {
1525 fprintf(mesgstream, "ERROR %s\n", errmsg);
1526 } else {
1527 fprintf(mesgstream, "? %s\n", errmsg);
1528 }
1529 exit(1);
1530 }
1531 if (close(outfd) != 0) {
1532 errmsg = vstrallocf(_("closing %s: %s"),
1533 incrname, strerror(errno));
1534 dbprintf("%s\n", errmsg);
1535 dbprintf("%s\n", errmsg);
1536 if (command == CMD_ESTIMATE) {
1537 fprintf(mesgstream, "ERROR %s\n", errmsg);
1538 } else {
1539 fprintf(mesgstream, "? %s\n", errmsg);
1540 }
1541 exit(1);
1542 }
1543
1544 amfree(inputname);
1545 amfree(basename);
1546 }
1547 return incrname;
1548 }
1549
1550 static void
check_no_check_device(void)1551 check_no_check_device(void)
1552 {
1553 if (gnutar_checkdevice == 0) {
1554 GPtrArray *argv_ptr = g_ptr_array_new();
1555 int dumpin;
1556 int dataf;
1557 int outf;
1558 int size;
1559 char buf[32768];
1560
1561 g_ptr_array_add(argv_ptr, gnutar_path);
1562 g_ptr_array_add(argv_ptr, "-x");
1563 g_ptr_array_add(argv_ptr, "--no-check-device");
1564 g_ptr_array_add(argv_ptr, "-f");
1565 g_ptr_array_add(argv_ptr, "-");
1566 g_ptr_array_add(argv_ptr, NULL);
1567
1568 pipespawnv(gnutar_path, STDIN_PIPE|STDOUT_PIPE|STDERR_PIPE, 0,
1569 &dumpin, &dataf, &outf, (char **)argv_ptr->pdata);
1570 aclose(dumpin);
1571 aclose(dataf);
1572 size = read(outf, buf, 32767);
1573 if (size > 0) {
1574 buf[size] = '\0';
1575 if (strstr(buf, "--no-check-device")) {
1576 g_debug("disabling --no-check-device since '%s' doesn't support it", gnutar_path);
1577 gnutar_checkdevice = 1;
1578 }
1579 }
1580 aclose(outf);
1581 g_ptr_array_free(argv_ptr, TRUE);
1582 }
1583 }
1584
amgtar_build_argv(char * gnutar_realpath,application_argument_t * argument,char * incrname,char ** file_exclude,char ** file_include,int command)1585 GPtrArray *amgtar_build_argv(
1586 char *gnutar_realpath,
1587 application_argument_t *argument,
1588 char *incrname,
1589 char **file_exclude,
1590 char **file_include,
1591 int command)
1592 {
1593 int nb_exclude;
1594 int nb_include;
1595 char *dirname;
1596 char tmppath[PATH_MAX];
1597 GPtrArray *argv_ptr = g_ptr_array_new();
1598 GSList *copt;
1599
1600 check_no_check_device();
1601 amgtar_build_exinclude(&argument->dle, 1,
1602 &nb_exclude, file_exclude,
1603 &nb_include, file_include);
1604
1605 if (gnutar_directory) {
1606 dirname = gnutar_directory;
1607 } else {
1608 dirname = argument->dle.device;
1609 }
1610
1611 g_ptr_array_add(argv_ptr, stralloc(gnutar_realpath));
1612
1613 g_ptr_array_add(argv_ptr, stralloc("--create"));
1614 if (command == CMD_BACKUP && argument->dle.create_index)
1615 g_ptr_array_add(argv_ptr, stralloc("--verbose"));
1616 g_ptr_array_add(argv_ptr, stralloc("--file"));
1617 if (command == CMD_ESTIMATE) {
1618 g_ptr_array_add(argv_ptr, stralloc("/dev/null"));
1619 } else {
1620 g_ptr_array_add(argv_ptr, stralloc("-"));
1621 }
1622 if (gnutar_no_unquote)
1623 g_ptr_array_add(argv_ptr, stralloc("--no-unquote"));
1624 g_ptr_array_add(argv_ptr, stralloc("--directory"));
1625 canonicalize_pathname(dirname, tmppath);
1626 g_ptr_array_add(argv_ptr, stralloc(tmppath));
1627 if (gnutar_onefilesystem)
1628 g_ptr_array_add(argv_ptr, stralloc("--one-file-system"));
1629 if (gnutar_atimepreserve)
1630 g_ptr_array_add(argv_ptr, stralloc("--atime-preserve=system"));
1631 if (!gnutar_checkdevice)
1632 g_ptr_array_add(argv_ptr, stralloc("--no-check-device"));
1633 if (gnutar_acls)
1634 g_ptr_array_add(argv_ptr, stralloc("--acls"));
1635 if (gnutar_selinux)
1636 g_ptr_array_add(argv_ptr, stralloc("--selinux"));
1637 if (gnutar_xattrs)
1638 g_ptr_array_add(argv_ptr, stralloc("--xattrs"));
1639 g_ptr_array_add(argv_ptr, stralloc("--listed-incremental"));
1640 g_ptr_array_add(argv_ptr, stralloc(incrname));
1641 if (gnutar_sparse) {
1642 if (!gnutar_sparse_set) {
1643 char *gtar_version;
1644 char *minor_version;
1645 char *sminor_version;
1646 char *gv;
1647 int major;
1648 int minor;
1649 GPtrArray *version_ptr = g_ptr_array_new();
1650
1651 g_ptr_array_add(version_ptr, gnutar_path);
1652 g_ptr_array_add(version_ptr, "--version");
1653 g_ptr_array_add(version_ptr, NULL);
1654 gtar_version = get_first_line(version_ptr);
1655 if (gtar_version) {
1656 for (gv = gtar_version; *gv && !g_ascii_isdigit(*gv); gv++);
1657 minor_version = index(gtar_version, '.');
1658 if (minor_version) {
1659 *minor_version++ = '\0';
1660 sminor_version = index(minor_version, '.');
1661 if (sminor_version) {
1662 *sminor_version = '\0';
1663 }
1664 major = atoi(gv);
1665 minor = atoi(minor_version);
1666 if (major < 1 ||
1667 (major == 1 && minor < 28)) {
1668 gnutar_sparse = 0;
1669 }
1670 }
1671 }
1672 g_ptr_array_free(version_ptr, TRUE);
1673 amfree(gtar_version);
1674 }
1675 if (gnutar_sparse) {
1676 g_ptr_array_add(argv_ptr, g_strdup("--sparse"));
1677 }
1678 }
1679 if (argument->tar_blocksize) {
1680 g_ptr_array_add(argv_ptr, stralloc("--blocking-factor"));
1681 g_ptr_array_add(argv_ptr, stralloc(argument->tar_blocksize));
1682 }
1683 g_ptr_array_add(argv_ptr, stralloc("--ignore-failed-read"));
1684 g_ptr_array_add(argv_ptr, stralloc("--totals"));
1685
1686 for (copt = argument->command_options; copt != NULL; copt = copt->next) {
1687 g_ptr_array_add(argv_ptr, stralloc((char *)copt->data));
1688 }
1689
1690 if (*file_exclude) {
1691 g_ptr_array_add(argv_ptr, stralloc("--exclude-from"));
1692 g_ptr_array_add(argv_ptr, stralloc(*file_exclude));
1693 }
1694
1695 if (*file_include) {
1696 g_ptr_array_add(argv_ptr, stralloc("--files-from"));
1697 g_ptr_array_add(argv_ptr, stralloc(*file_include));
1698 }
1699 else {
1700 g_ptr_array_add(argv_ptr, stralloc("."));
1701 }
1702 g_ptr_array_add(argv_ptr, NULL);
1703
1704 return(argv_ptr);
1705 }
1706
1707