source: MondoRescue/branches/2.2.9/mondo/src/common/libmondo-filelist.c@ 2157

Last change on this file since 2157 was 2133, checked in by Bruno Cornec, 15 years ago

Exclude in the file list all FS of type proc and sysf (newer kernel crash when accessing kcore in /proc, even in a bind mounted proc - Cf: https://qa.mandriva.com/show_bug.cgi?id=46523 - Should solve #306

  • Property svn:keywords set to Id
File size: 51.2 KB
Line 
1/*
2 $Id: libmondo-filelist.c 2133 2009-01-25 10:55:28Z bruno $
3*/
4
5/**
6 * @file
7 * Functions which create, chop, and edit the filelist.
8 */
9
10#include "my-stuff.h"
11#include "mondostructures.h"
12#include "lib-common-externs.h"
13#include "libmondo-filelist.h"
14#include "libmondo-string-EXT.h"
15#include "libmondo-files-EXT.h"
16#include "libmondo-fork-EXT.h"
17#include "libmondo-gui-EXT.h"
18#include "libmondo-tools-EXT.h"
19#include "mr_string.h"
20
21#include <time.h>
22#include <stdio.h>
23#include <sys/types.h>
24#include <sys/stat.h>
25#include <dirent.h>
26#include <errno.h>
27#include <stdio.h>
28
29
30/**
31 * The maximum depth of directories to put in the skeleton filelist.
32 * This is a balance between performance and a good progress indicator.
33 */
34#define MAX_SKEL_DEPTH 3
35
36
37extern ssize_t getline(char **lineptr, size_t * n, FILE * stream);
38extern char *MONDO_LOGFILE;
39
40/* Reference to global bkpinfo */
41extern struct s_bkpinfo *bkpinfo;
42
43
44int mondo_makefilelist(char *logfile, char *tmpdir, char *scratchdir,
45 char *include_paths, char *excp, int differential,
46 char *userdef_filelist);
47
48
49/*@unused@*/
50//static char cvsid[] = "$Id: libmondo-filelist.c 2133 2009-01-25 10:55:28Z bruno $";
51
52/**
53 * Number of lines in the filelist last loaded.
54 * @warning This implies that two filesets cannot be loaded at once.
55 * @ingroup globalGroup
56 */
57long g_original_noof_lines_in_filelist = 0;
58
59/**
60 * Number of filesets in the current backup.
61 * @ingroup globalGroup
62 */
63long g_noof_sets = 0;
64
65extern bool g_text_mode;
66extern newtComponent g_progressForm;
67extern int g_currentY;
68extern int g_noof_rows;
69
70extern char *g_getfacl;
71extern char *g_getfattr;
72
73
74
75/**
76 * @addtogroup filelistGroup
77 * @{
78 */
79/**
80 * Call chop_filelist() to chop the filelist into sets.
81 * @param bkpinfo The backup information structure. Fields used:
82 * - @c bkpinfo->image_devs
83 * - @c bkpinfo->optimal_set_size
84 * - @c bkpinfo->scratchdir
85 * - @c bkpinfo->tmpdir
86 * @see chop_filelist
87 */
88int call_filelist_chopper()
89{
90 /*@ buffers *********************** */
91 char *dev;
92 char *filelist;
93 char *tempfile;
94 char *cksumlist;
95 char *tmp;
96 long noof_sets;
97
98 /*@ pointers ********************** */
99 char *ptr;
100 FILE *fout;
101
102 /*@ int *************************** */
103 int i, retval = 0;
104
105 malloc_string(dev);
106 malloc_string(filelist);
107 malloc_string(tempfile);
108 malloc_string(cksumlist);
109 malloc_string(tmp);
110 mvaddstr_and_log_it(g_currentY, 0, "Dividing filelist into sets");
111
112 log_to_screen("Dividing filelist into sets. Please wait.");
113 i = 0;
114 sprintf(filelist, "%s/archives/filelist.full", bkpinfo->scratchdir);
115 sprintf(cksumlist, "%s/cklist.full", bkpinfo->tmpdir);
116 if (!does_file_exist(filelist)) {
117 log_it("filelist %s not found", filelist);
118 fatal_error("call_filelist_chopper() -- filelist not found!");
119 }
120
121 noof_sets =
122 chop_filelist(filelist, bkpinfo->tmpdir,
123 bkpinfo->optimal_set_size);
124 estimate_noof_media_required(noof_sets); // for cosmetic purposes
125
126 sprintf(tempfile, "%s/biggielist.txt", bkpinfo->tmpdir);
127 if (!(fout = fopen(tempfile, "a"))) {
128 log_OS_error("Cannot append to biggielist");
129 retval++;
130 goto end_of_func;
131 }
132 log_it(bkpinfo->image_devs);
133
134 ptr = bkpinfo->image_devs;
135
136 while (ptr && *ptr) {
137 strcpy(dev, ptr);
138 log_it("Examining imagedev %s", dev);
139 for (i = 0; i < (int) strlen(dev) && dev[i] != ' '; i++);
140 dev[i] = '\0';
141 if (!strlen(dev)) {
142 continue;
143 }
144 fprintf(fout, "%s\n", dev);
145 log_it("Adding '%s' to biggielist", dev);
146 if ((ptr = strchr(ptr, ' '))) {
147 ptr++;
148 }
149 }
150 paranoid_fclose(fout);
151 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
152
153 end_of_func:
154 paranoid_free(filelist);
155 paranoid_free(tempfile);
156 paranoid_free(cksumlist);
157 paranoid_free(dev);
158 paranoid_free(tmp);
159 return (retval);
160}
161
162
163
164int sort_file(char *orig_fname)
165{
166 char *tmp_fname;
167 char *command;
168 int retval = 0;
169
170 log_msg(5, "Sorting file %s", orig_fname);
171 malloc_string(tmp_fname);
172 malloc_string(command);
173 sprintf(tmp_fname, "%s/sortfile", bkpinfo->tmpdir);
174
175 if (!does_file_exist(orig_fname)) {
176 log_msg(2, "file %s empty", orig_fname);
177 return (0);
178 } // no sense in trying to sort an empty file
179
180 sprintf(command, "sort %s > %s 2>> %s", orig_fname, tmp_fname,
181 MONDO_LOGFILE);
182 retval = system(command);
183 if (retval) {
184 log_msg(2, "Failed to sort %s - oh dear", orig_fname);
185 } else {
186 log_msg(5, "Sorted %s --> %s OK. Copying it back to %s now",
187 orig_fname, tmp_fname, orig_fname);
188 sprintf(command, "mv -f %s %s", tmp_fname, orig_fname);
189 retval += run_program_and_log_output(command, 5);
190 if (retval) {
191 log_msg(2, "Failed to copy %s back to %s - oh dear", tmp_fname,
192 orig_fname);
193 } else {
194 log_msg(5, "%s was sorted OK.", orig_fname);
195 }
196 }
197 paranoid_free(tmp_fname);
198 paranoid_free(command);
199 log_msg(5, "Finished sorting file %s", orig_fname);
200 return (retval);
201}
202
203
204
205/**
206 * Chop the filelist into sets.
207 * Each fileset is a list of files whose total (uncompressed) size is usually
208 * about X KB. Files bigger than 8X KB are placed in a "biggielist"; they will
209 * be sliced and compressed separately from the regular files.
210 *
211 * @param filelist The big filelist (filelist.full) to chop up.
212 * @param outdir The directory to place the files (filelist.N where N is
213 * an integer, biggielist.txt, and LAST-FILELIST-NUMBER) created
214 * @param maxsetsizeK Optimal size of a fileset (X above).
215 * @return number of errors encountered (0 for success).
216 */
217int chop_filelist(char *filelist, char *outdir, long maxsetsizeK)
218{
219/*@ long ****************************************/
220 long lino = 0;
221 long max_sane_size_for_a_file;
222 long curr_set_size;
223 long noof_lines;
224 long siz;
225
226 /*@ int **************************************** */
227 int i;
228 long curr_set_no;
229
230 /*@ buffers ************************************* */
231 char *outfname;
232 char *biggie_fname;
233 char *incoming;
234 char *tmp;
235 char *acl_fname;
236 char *xattr_fname;
237
238 /*@ pointers *********************************** */
239 FILE *fin;
240 FILE *fout;
241 FILE *fbig;
242
243 /*@ structures ********************************* */
244 struct stat buf;
245 int err = 0;
246
247 malloc_string(outfname);
248 malloc_string(biggie_fname);
249 incoming = malloc(MAX_STR_LEN * 2);
250 malloc_string(tmp);
251 malloc_string(acl_fname);
252 malloc_string(xattr_fname);
253
254 assert_string_is_neither_NULL_nor_zerolength(filelist);
255 assert_string_is_neither_NULL_nor_zerolength(outdir);
256 assert(maxsetsizeK > 0);
257
258 max_sane_size_for_a_file = 64L * 1024L;
259// max_sane_size_for_a_file = maxsetsizeK*2;
260// if (max_sane_size_for_a_file > 32*1024)
261// { max_sane_size_for_a_file = 32*1024; }
262
263 log_it("filelist=%s;", filelist);
264 open_evalcall_form("Dividing filelist into sets");
265 noof_lines = count_lines_in_file(filelist);
266 if (!(fin = fopen(filelist, "r"))) {
267 log_OS_error("Cannot openin filelist");
268 return (0);
269 }
270 curr_set_no = 0;
271 curr_set_size = 0;
272 sprintf(outfname, "%s/filelist.%ld", outdir, curr_set_no);
273 sprintf(biggie_fname, "%s/biggielist.txt", outdir);
274 log_it("outfname=%s; biggie_fname=%s", outfname, biggie_fname);
275 if (!(fbig = fopen(biggie_fname, "w"))) {
276 log_OS_error("Cannot openout biggie_fname");
277 err++;
278 goto end_of_func;
279 }
280 if (!(fout = fopen(outfname, "w"))) {
281 log_OS_error("Cannot openout outfname");
282 err++;
283 goto end_of_func;
284 }
285 (void) fgets(incoming, MAX_STR_LEN * 2 - 1, fin);
286 while (!feof(fin)) {
287 lino++;
288 i = strlen(incoming) - 1;
289 if (i < 0) {
290 i = 0;
291 }
292 if (i > MAX_STR_LEN - 1) {
293 incoming[MAX_STR_LEN - 30] = '\0';
294 log_msg(1, "Warning - truncating file %s's name", incoming);
295 err++;
296 }
297 if (incoming[i] < 32) {
298 incoming[i] = '\0';
299 }
300 if (!strncmp(incoming, "/dev/", 5)) {
301 siz = 1;
302 } else if (lstat(incoming, &buf) != 0) {
303 siz = 0;
304 } else {
305 siz = (long) (buf.st_size >> 10);
306 }
307 if (siz > max_sane_size_for_a_file)
308// && strcmp(incoming+strlen(incoming)-4, ".bz2") && strcmp(incoming+strlen(incoming)-4, ".tbz"))
309 {
310 fprintf(fbig, "%s\n", incoming);
311 } else {
312 curr_set_size += siz;
313 fprintf(fout, "%s\n", incoming);
314 if (curr_set_size > maxsetsizeK) {
315 paranoid_fclose(fout);
316 sort_file(outfname);
317 curr_set_no++;
318 curr_set_size = 0;
319 sprintf(outfname, "%s/filelist.%ld", outdir, curr_set_no);
320 if (!(fout = fopen(outfname, "w"))) {
321 log_OS_error("Unable to openout outfname");
322 err++;
323 goto end_of_func;
324 }
325 sprintf(tmp, "Fileset #%ld chopped ", curr_set_no - 1);
326 update_evalcall_form((int) (lino * 100 / noof_lines));
327 /* if (!g_text_mode) {newtDrawRootText(0,22,tmp);newtRefresh();} else {log_it(tmp);} */
328 }
329 }
330 (void) fgets(incoming, MAX_STR_LEN * 2 - 1, fin);
331 }
332 paranoid_fclose(fin);
333 paranoid_fclose(fout);
334 paranoid_fclose(fbig);
335
336 if (length_of_file(outfname) <= 2) {
337 unlink(outfname);
338 g_noof_sets--;
339 }
340 g_noof_sets = curr_set_no;
341 sort_file(outfname);
342 sort_file(biggie_fname);
343 sprintf(outfname, "%s/LAST-FILELIST-NUMBER", outdir);
344 sprintf(tmp, "%ld", curr_set_no);
345 if (write_one_liner_data_file(outfname, tmp)) {
346 log_OS_error
347 ("Unable to echo write one-liner to LAST-FILELIST-NUMBER");
348 err = 1;
349 }
350 if (curr_set_no == 0) {
351 sprintf(tmp, "Only one fileset. Fine.");
352 } else {
353 sprintf(tmp, "Filelist divided into %ld sets", curr_set_no + 1);
354 }
355 log_msg(1, tmp);
356 close_evalcall_form();
357 /* This is to work around an obscure bug in Newt; open a form, close it,
358 carry on... I don't know why it works but it works. If you don't do this
359 then update_progress_form() won't show the "time taken / time remaining"
360 line. The bug only crops up AFTER the call to chop_filelist(). Weird. */
361#ifndef _XWIN
362 if (!g_text_mode) {
363 open_progress_form("", "", "", "", 100);
364 newtPopHelpLine();
365 newtFormDestroy(g_progressForm);
366 newtPopWindow();
367 }
368#endif
369 end_of_func:
370 paranoid_free(outfname);
371 paranoid_free(biggie_fname);
372 paranoid_free(incoming);
373 paranoid_free(tmp);
374 paranoid_free(acl_fname);
375 paranoid_free(xattr_fname);
376 return (err ? 0 : curr_set_no + 1);
377}
378
379
380
381
382
383/**
384 * Free all the memory used by a filelist structure.
385 * Since this may take a long time for large filelists, a progress bar will be displayed.
386 * @param filelist The filelist to free.
387 */
388void free_filelist(struct s_node *filelist)
389{
390 /*@ int's ******************************************************* */
391 static int depth = 0;
392 int percentage;
393
394 /*@ long's ****************************************************** */
395 static long i = 0;
396
397 /*@ end vars **************************************************** */
398
399 assert(filelist != NULL);
400 if (depth == 0) {
401 open_evalcall_form("Freeing memory");
402 log_to_screen("Freeing memory formerly occupied by filelist");
403 }
404 depth++;
405
406 if (filelist->ch == '\0') {
407 if (!(i++ % 1111)) {
408 percentage =
409 (int) (i * 100 / g_original_noof_lines_in_filelist);
410 update_evalcall_form(percentage);
411
412 }
413 }
414
415 if (filelist->right) {
416 free_filelist(filelist->right);
417 filelist->right = NULL;
418 }
419 if (filelist->down) {
420/* if (!(i++ %39999)) { update_evalcall_form(0); } */
421 free_filelist(filelist->down);
422 filelist->down = NULL;
423 }
424 filelist->ch = '\0';
425 paranoid_free(filelist);
426 depth--;
427 if (depth == 0) {
428 close_evalcall_form();
429 log_it("Finished freeing memory");
430 }
431}
432
433
434int call_exe_and_pipe_output_to_fd(char *syscall, FILE * pout)
435{
436 FILE *pattr;
437 char *tmp;
438 pattr = popen(syscall, "r");
439 if (!pattr) {
440 log_msg(1, "Failed to open fattr() %s", syscall);
441 return (1);
442 }
443 if (feof(pattr)) {
444 log_msg(1, "Failed to call fattr() %s", syscall);
445 paranoid_pclose(pattr);
446 return (2);
447 }
448 malloc_string(tmp);
449 for (fgets(tmp, MAX_STR_LEN, pattr); !feof(pattr);
450 fgets(tmp, MAX_STR_LEN, pattr)) {
451 fputs(tmp, pout);
452 }
453 paranoid_pclose(pattr);
454 paranoid_free(tmp);
455 return (0);
456}
457
458
459
460int gen_aux_list(char *filelist, char *syscall_sprintf,
461 char *auxlist_fname)
462{
463 FILE *fin;
464 FILE *pout;
465 char *pout_command;
466 char *syscall;
467 char *file_to_analyze;
468 char *strtmp = NULL;
469 char *tmp = NULL;
470 int i;
471
472 if (!(fin = fopen(filelist, "r"))) {
473 log_msg(1, "Cannot openin filelist %s", filelist);
474 return (1);
475 }
476 malloc_string(pout_command);
477 sprintf(pout_command, "gzip -c1 > %s", auxlist_fname);
478 if (!(pout = popen(pout_command, "w"))) {
479 log_msg(1, "Cannot openout auxlist_fname %s", auxlist_fname);
480 fclose(fin);
481 paranoid_free(pout_command);
482 return (4);
483 }
484 malloc_string(file_to_analyze);
485 for (fgets(file_to_analyze, MAX_STR_LEN, fin); !feof(fin);
486 fgets(file_to_analyze, MAX_STR_LEN, fin)) {
487 i = strlen(file_to_analyze);
488 if (i > 0 && file_to_analyze[i - 1] < 32) {
489 file_to_analyze[i - 1] = '\0';
490 }
491 log_msg(8, "Analyzing %s", file_to_analyze);
492 tmp = mr_stresc(file_to_analyze, "`$\\\"", '\\');
493 asprintf(&strtmp, syscall_sprintf, tmp);
494 paranoid_free(tmp);
495 asprintf(&syscall, "%s 2>> /dev/null", strtmp); // " MONDO_LOGFILE);
496 paranoid_free(strtmp);
497 call_exe_and_pipe_output_to_fd(syscall, pout);
498 paranoid_free(syscall);
499 }
500 paranoid_fclose(fin);
501 paranoid_pclose(pout);
502 paranoid_free(file_to_analyze);
503 paranoid_free(pout_command);
504 return (0);
505}
506
507
508int get_acl_list(char *filelist, char *facl_fname)
509{
510 char *command;
511 int retval = 0;
512
513 if (g_getfacl != NULL) {
514 malloc_string(command);
515 sprintf(command, "touch %s", facl_fname);
516 run_program_and_log_output(command, 8);
517// sort_file(filelist); // FIXME - filelist chopper sorts, so this isn't necessary
518 sprintf(command,
519 "getfacl --all-effective -P %s 2>> %s | gzip -c1 > %s 2>> %s",
520 filelist, MONDO_LOGFILE, facl_fname, MONDO_LOGFILE);
521 iamhere(command);
522 retval = system(command);
523 paranoid_free(command);
524 }
525 return (retval);
526}
527
528
529int get_fattr_list(char *filelist, char *fattr_fname)
530{
531 char *command;
532 int retval = 0;
533
534 if (g_getfattr != NULL) {
535 malloc_string(command);
536 sprintf(command, "touch %s", fattr_fname);
537 run_program_and_log_output(command, 8);
538 paranoid_free(command);
539// sort_file(filelist); // FIXME - filelist chopper sorts, so this isn't necessary
540 retval =
541 gen_aux_list(filelist, "getfattr --en=hex -P -d \"%s\"",
542 fattr_fname);
543 }
544 return (retval);
545}
546
547
548int set_EXAT_list(char *orig_msklist, char *original_exat_fname,
549 char *executable)
550{
551 const int my_depth = 8;
552 char *command, *syscall_pin, *syscall_pout, *incoming;
553 char *current_subset_file, *current_master_file, *masklist;
554 int retval = 0;
555 int i;
556 char *p, *q;
557 FILE *pin, *pout, *faclin;
558
559 malloc_string(command);
560 log_msg(1, "set_EXAT_list(%s, %s, %s)", orig_msklist,
561 original_exat_fname, executable);
562 if (!orig_msklist || !orig_msklist[0]
563 || !does_file_exist(orig_msklist)) {
564 log_msg(1,
565 "No masklist provided. I shall therefore set ALL attributes.");
566 sprintf(command, "gzip -dc %s | %s --restore - 2>> %s",
567 original_exat_fname, executable, MONDO_LOGFILE);
568 log_msg(1, "command = %s", command);
569 retval = system(command);
570 paranoid_free(command);
571 log_msg(1, "Returning w/ retval=%d", retval);
572 return (retval);
573 }
574 if (length_of_file(original_exat_fname) <= 0) {
575 log_msg(1,
576 "original_exat_fname %s is empty or missing, so no need to set EXAT list",
577 original_exat_fname);
578 paranoid_free(command);
579 return (0);
580 }
581 malloc_string(incoming);
582 malloc_string(masklist);
583 malloc_string(current_subset_file);
584 malloc_string(current_master_file);
585 malloc_string(syscall_pin);
586 malloc_string(syscall_pout);
587 sprintf(masklist, "%s/masklist", bkpinfo->tmpdir);
588 sprintf(command, "cp -f %s %s", orig_msklist, masklist);
589 run_program_and_log_output(command, 1);
590 sort_file(masklist);
591 current_subset_file[0] = current_master_file[0] = '\0';
592 sprintf(syscall_pin, "gzip -dc %s", original_exat_fname);
593 sprintf(syscall_pout, "%s --restore - 2>> %s", executable,
594 MONDO_LOGFILE);
595
596 log_msg(1, "syscall_pin = %s", syscall_pin);
597 log_msg(1, "syscall_pout = %s", syscall_pout);
598 pout = popen(syscall_pout, "w");
599 if (!pout) {
600 iamhere("Unable to openout to syscall_pout");
601 return (1);
602 }
603 pin = popen(syscall_pin, "r");
604 if (!pin) {
605 pclose(pout);
606 iamhere("Unable to openin from syscall");
607 return (1);
608 }
609 faclin = fopen(masklist, "r");
610 if (!faclin) {
611 pclose(pin);
612 pclose(pout);
613 iamhere("Unable to openin masklist");
614 return (1);
615 }
616// printf("Hi there. Starting the loop\n");
617
618 fgets(current_subset_file, MAX_STR_LEN, faclin);
619 fgets(incoming, MAX_STR_LEN, pin);
620 while (!feof(pin) && !feof(faclin)) {
621// printf("incoming = %s", incoming);
622
623 strcpy(current_master_file, incoming + 8);
624
625 p = current_subset_file;
626 if (*p == '/') {
627 p++;
628 }
629 i = strlen(p);
630 if (i > 0 && p[i - 1] < 32) {
631 p[i - 1] = '\0';
632 }
633
634
635 q = current_master_file;
636 if (*q == '/') {
637 q++;
638 }
639 i = strlen(q);
640 if (i > 0 && q[i - 1] < 32) {
641 q[i - 1] = '\0';
642 }
643
644 i = strcmp(p, q);
645 log_msg(my_depth, "'%s' v '%s' --> %d\n", p, q, i);
646
647// printf("%s v %s --> %d\n", p, q, i);
648
649 if (i < 0) { // read another subset file in.
650 log_msg(my_depth, "Reading next subset line in\n\n");
651 fgets(current_subset_file, MAX_STR_LEN, faclin);
652 continue;
653 }
654
655 if (!i) {
656 fputs(incoming, pout);
657 }
658 fgets(incoming, MAX_STR_LEN, pin);
659 if (!i) {
660 log_msg(my_depth, "Copying master %s", q);
661 }
662// if (!i) { printf("Match --- %s\n", q); }
663
664 while (!feof(pin) && strncmp(incoming, "# file: ", 8)) {
665 if (!i) {
666
667// printf("%s", incoming);
668
669 fputs(incoming, pout);
670 }
671 fgets(incoming, MAX_STR_LEN, pin);
672 }
673 if (!i) {
674 fgets(current_subset_file, MAX_STR_LEN, faclin);
675 }
676 }
677 while (!feof(pin)) {
678 fgets(incoming, MAX_STR_LEN, pin);
679 }
680 fclose(faclin);
681 pclose(pin);
682 pclose(pout);
683
684// printf("OK, loop is done\n");
685
686 unlink(masklist);
687 paranoid_free(current_subset_file);
688 paranoid_free(current_master_file);
689 paranoid_free(syscall_pout);
690 paranoid_free(syscall_pin);
691 paranoid_free(masklist);
692 paranoid_free(incoming);
693 paranoid_free(command);
694 return (retval);
695}
696
697
698int set_fattr_list(char *masklist, char *fattr_fname)
699{
700 if (find_home_of_exe("setfattr")) {
701 return (set_EXAT_list(masklist, fattr_fname, "setfattr"));
702 } else {
703 log_msg(1, "ERROR: set_EXAT_list: setfattr doesn't exist");
704 return(0);
705 }
706}
707
708
709
710int set_acl_list(char *masklist, char *acl_fname)
711{
712 if (find_home_of_exe("setfacl")) {
713 return (set_EXAT_list(masklist, acl_fname, "setfacl"));
714 } else {
715 log_msg(1, "ERROR: set_EXAT_list: setfacl doesn't exist");
716 return(0);
717 }
718}
719
720
721/**
722 * Get the number of the last fileset in the backup.
723 * @param bkpinfo The backup information structure. Only the @c bkpinfo->tmpdir field is used.
724 * @return The last filelist number.
725 * @note This function should only be called at restore-time.
726 */
727int get_last_filelist_number()
728{
729 /*@ buffers ***************************************************** */
730 char val_sz[MAX_STR_LEN];
731 char cfg_fname[MAX_STR_LEN];
732/* char tmp[MAX_STR_LEN]; remove stan benoit apr 2002 */
733
734 /*@ long ******************************************************** */
735 int val_i;
736
737 /*@ end vars **************************************************** */
738
739 assert(bkpinfo != NULL);
740
741 strcpy(val_sz,"");
742 sprintf(cfg_fname, "%s/mondo-restore.cfg", bkpinfo->tmpdir);
743 read_cfg_var(cfg_fname, "last-filelist-number", val_sz);
744 val_i = atoi(val_sz);
745 if (val_i <= 0) {
746 val_i = 500;
747 }
748 return (val_i);
749}
750
751
752/**
753 * Add a string at @p startnode.
754 * @param startnode The node to start at when searching for where to add the string.
755 * @param string_to_add The string to add.
756 * @return 0 for success, 1 for failure.
757 * @bug I don't understand this function. Would someone care to explain it?
758 */
759int add_string_at_node(struct s_node *startnode, char *string_to_add)
760{
761
762
763 /*@ int ******************************************************** */
764 int noof_chars;
765 int i;
766 int res;
767
768 /*@ sturctures ************************************************* */
769 struct s_node *node, *newnode;
770
771 /*@ char ****************************************************** */
772 char char_to_add;
773
774 /*@ bools ****************************************************** */
775
776 const bool sosodef = FALSE;
777
778 static int depth = 0;
779 static char original_string[MAX_STR_LEN];
780
781 assert(startnode != NULL);
782 assert(string_to_add != NULL);
783
784 if (!depth) {
785 strcpy(original_string, string_to_add);
786 }
787
788 noof_chars = strlen(string_to_add) + 1; /* we include the '\0' */
789
790/* walk across tree if necessary */
791 node = startnode;
792 char_to_add = string_to_add[0];
793 if (node->right != NULL && node->ch < char_to_add) {
794 log_msg(7, "depth=%d --- going RIGHT ... %c-->%c", depth,
795 char_to_add, node->ch, (node->right)->ch);
796 return (add_string_at_node(node->right, string_to_add));
797 }
798
799/* walk down tree if appropriate */
800 if (node->down != NULL && node->ch == char_to_add) {
801 log_msg(7, "depth=%d char=%c --- going DOWN", depth, char_to_add);
802 depth++;
803 res = add_string_at_node(node->down, string_to_add + 1);
804 depth--;
805 return (res);
806 }
807
808 if (char_to_add == '\0' && node->ch == '\0') {
809 log_msg(6, "%s already in tree", original_string);
810 return (1);
811 }
812
813/* add here */
814 if (!(newnode = (struct s_node *) malloc(sizeof(struct s_node)))) {
815 log_to_screen("failed to malloc");
816 depth--;
817 return (1);
818 }
819 if (char_to_add < node->ch) // add to the left of node
820 {
821 log_msg(7, "depth=%d char=%c --- adding (left)", depth,
822 char_to_add);
823 memcpy((void *) newnode, (void *) node, sizeof(struct s_node));
824 node->right = newnode;
825 } else if (char_to_add > node->ch) // add to the right of node
826 {
827 log_msg(7, "depth=%d char=%c --- adding (right)", depth,
828 char_to_add);
829 newnode->right = node->right; // newnode is to the RIGHT of node
830 node->right = newnode;
831 node = newnode;
832 }
833 // from now on, we're working on 'node'
834 node->down = NULL;
835 node->ch = char_to_add;
836 node->expanded = node->selected = FALSE;
837 if (char_to_add == '\0') {
838 log_msg(6, "Added %s OK", original_string);
839 return (0);
840 }
841// add the rest
842 log_msg(6, "Adding remaining chars ('%s')", string_to_add + 1);
843 for (i = 1; i < noof_chars; i++) {
844 if (!
845 (node->down =
846 (struct s_node *) malloc(sizeof(struct s_node)))) {
847 log_to_screen("%s - failed to malloc", string_to_add);
848 return (1);
849 }
850 node = node->down;
851 char_to_add = string_to_add[i];
852 log_msg(6, "Adding '%c'", char_to_add);
853 node->ch = char_to_add;
854 node->right = node->down = NULL;
855 node->expanded = node->selected = FALSE;
856 if (!node->ch) {
857 node->selected = sosodef;
858 }
859 }
860 log_msg(6, "Finally - added %s OK", original_string);
861 return (0);
862}
863
864
865
866
867/**
868 * Load a filelist into a <tt>struct s_node</tt>.
869 * When you are done with the filelist, call free_filelist().
870 * @param filelist_fname The file to load the filelist from.
871 * @return A filelist tree structure.
872 */
873struct s_node *load_filelist(char *filelist_fname)
874{
875
876 /*@ structures ************************************************* */
877 struct s_node *filelist;
878
879 /*@ pointers *************************************************** */
880 FILE *pin;
881
882 /*@ buffers **************************************************** */
883 char command_to_open_fname[MAX_STR_LEN];
884 char fname[MAX_STR_LEN];
885 char tmp[MAX_STR_LEN];
886 int pos_in_fname;
887 /*@ int ******************************************************** */
888 int percentage;
889
890 /*@ long ******************************************************* */
891 long lines_in_filelist;
892 long lino = 0;
893 /*@ end vars *************************************************** */
894
895 assert_string_is_neither_NULL_nor_zerolength(filelist_fname);
896
897 if (!does_file_exist(filelist_fname)) {
898 fatal_error("filelist does not exist -- cannot load it");
899 }
900 log_to_screen("Loading filelist");
901 sprintf(command_to_open_fname, "gzip -dc %s", filelist_fname);
902 sprintf(tmp, "zcat %s | wc -l", filelist_fname);
903 log_msg(6, "tmp = %s", tmp);
904 lines_in_filelist =
905 atol(call_program_and_get_last_line_of_output(tmp));
906 if (lines_in_filelist < 3) {
907 log_to_screen("Warning - surprisingly short filelist.");
908 }
909 g_original_noof_lines_in_filelist = lines_in_filelist;
910 if (!(filelist = (struct s_node *) malloc(sizeof(struct s_node)))) {
911 return (NULL);
912 }
913 filelist->ch = '/';
914 filelist->right = NULL;
915 filelist->down = malloc(sizeof(struct s_node));
916 filelist->expanded = filelist->selected = FALSE;
917 (filelist->down)->ch = '\0';
918 (filelist->down)->right = (filelist->down)->down = FALSE;
919 (filelist->down)->expanded = (filelist->down)->selected = FALSE;
920 if (!(pin = popen(command_to_open_fname, "r"))) {
921 log_OS_error("Unable to openin filelist_fname");
922 return (NULL);
923 }
924 open_evalcall_form("Loading filelist from disk");
925 for (fgets(fname, MAX_STR_LEN, pin); !feof(pin);
926 fgets(fname, MAX_STR_LEN, pin)) {
927 if ((fname[strlen(fname) - 1] == 13
928 || fname[strlen(fname) - 1] == 10) && strlen(fname) > 0) {
929 fname[strlen(fname) - 1] = '\0';
930 }
931// strip_spaces (fname);
932 if (!strlen(fname)) {
933 continue;
934 }
935 for (pos_in_fname = 0; fname[pos_in_fname] != '\0'; pos_in_fname++) {
936 if (fname[pos_in_fname] != '/') {
937 continue;
938 }
939 strcpy(tmp, fname);
940 tmp[pos_in_fname] = '\0';
941 if (strlen(tmp)) {
942 add_string_at_node(filelist, tmp);
943 }
944 }
945 add_string_at_node(filelist, fname);
946 if (!(++lino % 1111)) {
947 percentage = (int) (lino * 100 / lines_in_filelist);
948 update_evalcall_form(percentage);
949 }
950 }
951 paranoid_pclose(pin);
952 close_evalcall_form();
953 log_it("Finished loading filelist");
954 return (filelist);
955}
956
957
958/**
959 * Log a list of files in @p node.
960 * @param node The toplevel node to use.
961 */
962void show_filelist(struct s_node *node)
963{
964 static int depth = 0;
965 static char current_string[200];
966
967 if (depth == 0) {
968 log_msg(0, "----------------show filelist--------------");
969 }
970 current_string[depth] = node->ch;
971
972 log_msg(3, "depth=%d", depth);
973 if (node->down) {
974 log_msg(3, "moving down");
975 depth++;
976 show_filelist(node->down);
977 depth--;
978 }
979
980 if (!node->ch) {
981 log_msg(0, "%s\n", current_string);
982 }
983
984 if (node->right) {
985 log_msg(3, "moving right");
986 show_filelist(node->right);
987 }
988 if (depth == 0) {
989 log_msg(0, "----------------show filelist--------------");
990 }
991 return;
992}
993
994
995
996
997/**
998 * Reset the filelist to the state it was when it was loaded. This does not
999 * touch the file on disk.
1000 * @param filelist The filelist tree structure.
1001 */
1002void reload_filelist(struct s_node *filelist)
1003{
1004 assert(filelist != NULL);
1005 toggle_node_selection(filelist, FALSE);
1006 toggle_path_expandability(filelist, "/", FALSE);
1007 toggle_all_root_dirs_on(filelist);
1008}
1009
1010
1011
1012/**
1013 * Save a filelist tree structure to disk.
1014 * @param filelist The filelist tree structure to save.
1015 * @param outfname Where to save it.
1016 */
1017void save_filelist(struct s_node *filelist, char *outfname)
1018{
1019 /*@ int ********************************************************* */
1020 static int percentage;
1021 static int depth = 0;
1022
1023 /*@ buffers ***************************************************** */
1024 static char str[MAX_STR_LEN];
1025
1026 /*@ structures ************************************************** */
1027 struct s_node *node;
1028
1029 /*@ pointers **************************************************** */
1030 static FILE *fout = NULL;
1031
1032 /*@ long ******************************************************** */
1033 static long lines_in_filelist = 0;
1034 static long lino = 0;
1035
1036 /*@ end vars *************************************************** */
1037
1038 assert(filelist != NULL);
1039 assert(outfname != NULL); // will be zerolength if save_filelist() is called by itself
1040 if (depth == 0) {
1041 log_to_screen("Saving filelist");
1042 if (!(fout = fopen(outfname, "w"))) {
1043 fatal_error("Cannot openout/save filelist");
1044 }
1045 lines_in_filelist = g_original_noof_lines_in_filelist; /* set by load_filelist() */
1046 open_evalcall_form("Saving selection to disk");
1047 }
1048 for (node = filelist; node != NULL; node = node->right) {
1049 str[depth] = node->ch;
1050 log_msg(5, "depth=%d ch=%c", depth, node->ch);
1051 if (!node->ch) {
1052// if (node->selected)
1053// {
1054 fprintf(fout, "%s\n", str);
1055// }
1056 if (!(++lino % 1111)) {
1057 percentage = (int) (lino * 100 / lines_in_filelist);
1058 update_evalcall_form(percentage);
1059 }
1060 }
1061 if (node->down) {
1062 depth++;
1063 save_filelist(node->down, "");
1064 depth--;
1065 }
1066 }
1067 if (depth == 0) {
1068 paranoid_fclose(fout);
1069 close_evalcall_form();
1070 log_it("Finished saving filelist");
1071 }
1072}
1073
1074
1075
1076/**
1077 * Toggle all root dirs on.
1078 * @param filelist The filelist tree structure to operate on.
1079 * @bug I don't understand this function. Would someone care to explain it?
1080 */
1081void toggle_all_root_dirs_on(struct s_node *filelist)
1082{
1083 /*@ structures ************************************************** */
1084 struct s_node *node;
1085
1086 /*@ int ********************************************************* */
1087 static int depth = 0;
1088 static int root_dirs_expanded;
1089
1090 /*@ buffers ***************************************************** */
1091 static char filename[MAX_STR_LEN];
1092
1093 /*@ end vars *************************************************** */
1094
1095 assert(filelist != NULL);
1096 if (depth == 0) {
1097 log_it("Toggling all root dirs ON");
1098 root_dirs_expanded = 0;
1099 }
1100 for (node = filelist; node != NULL; node = node->right) {
1101 filename[depth] = node->ch;
1102 if (node->ch == '\0' && strlen(filename) > 1
1103 && (!strchr(filename + 1, '/'))) {
1104 node->selected = FALSE;
1105 node->expanded = TRUE;
1106// log_it (filename);
1107 root_dirs_expanded++;
1108 }
1109 if (node->down) {
1110 depth++;
1111 toggle_all_root_dirs_on(node->down);
1112 depth--;
1113 }
1114 }
1115 if (depth == 0) {
1116 log_it("Finished toggling all root dirs ON");
1117 }
1118}
1119
1120
1121/**
1122 * Toggle the expandability of a path.
1123 * @param filelist The filelist tree to operate on.
1124 * @param pathname The path to toggle expandability of.
1125 * @param on_or_off Whether to toggle it on or off.
1126 * @bug I don't understand this function. Would someone care to explain it?
1127 */
1128void
1129toggle_path_expandability(struct s_node *filelist, char *pathname,
1130 bool on_or_off)
1131{
1132
1133 /*@ int ******************************************************** */
1134 static int depth = 0;
1135 static int total_expanded;
1136 static int root_depth;
1137 int j;
1138 /*@ structures ************************************************* */
1139 struct s_node *node;
1140
1141 /*@ buffers **************************************************** */
1142 static char current_filename[MAX_STR_LEN];
1143
1144/* char tmp[MAX_STR_LEN+2]; */
1145
1146 /*@ end vars *************************************************** */
1147
1148 assert(filelist != NULL);
1149 assert_string_is_neither_NULL_nor_zerolength(pathname);
1150 if (depth == 0) {
1151 total_expanded = 0;
1152// log_it ("Toggling path's expandability");
1153 for (root_depth = (int) strlen(pathname);
1154 root_depth > 0 && pathname[root_depth - 1] != '/';
1155 root_depth--);
1156 if (root_depth < 2) {
1157 root_depth = (int) strlen(pathname);
1158 }
1159 }
1160 for (node = filelist; node != NULL; node = node->right) {
1161 current_filename[depth] = node->ch;
1162 if (node->down) {
1163 depth++;
1164 toggle_path_expandability(node->down, pathname, on_or_off);
1165 depth--;
1166 }
1167 if (node->ch == '\0') {
1168 if (!strncmp(pathname, current_filename, strlen(pathname))) {
1169 for (j = root_depth;
1170 current_filename[j] != '/'
1171 && current_filename[j] != '\0'; j++);
1172 if (current_filename[j] != '\0') {
1173 for (j++;
1174 current_filename[j] != '/'
1175 && current_filename[j] != '\0'; j++);
1176 }
1177 if (current_filename[j] == '\0') {
1178 node->expanded =
1179 (!strcmp(pathname, current_filename) ? TRUE :
1180 on_or_off);
1181 }
1182 }
1183 }
1184 if (node->expanded) {
1185 if (total_expanded < ARBITRARY_MAXIMUM - 32
1186 || !strrchr(current_filename + strlen(pathname), '/')) {
1187 total_expanded++;
1188 } else {
1189 node->expanded = FALSE;
1190 }
1191 }
1192 }
1193 if (depth == 0) {
1194// log_it ("Finished toggling expandability");
1195 }
1196}
1197
1198/**
1199 * Toggle whether a path is selected.
1200 * @param filelist The filelist tree to operate on.
1201 * @param pathname The path to toggle selection of.
1202 * @param on_or_off Whether to toggle it on or off.
1203 * @bug I don't understand this function. Would someone care to explain it?
1204 */
1205void
1206toggle_path_selection(struct s_node *filelist, char *pathname,
1207 bool on_or_off)
1208{
1209 /*@ int ********************************************************* */
1210 static int depth = 0;
1211 int j;
1212
1213 /*@ structures ************************************************** */
1214 struct s_node *node;
1215
1216 /*@ buffers ***************************************************** */
1217 static char current_filename[MAX_STR_LEN];
1218 char tmp[MAX_STR_LEN + 2];
1219
1220 /*@ end vars *************************************************** */
1221 assert(filelist != NULL);
1222 assert_string_is_neither_NULL_nor_zerolength(pathname);
1223 if (depth == 0) {
1224 log_it("Toggling path's selection");
1225 }
1226 for (node = filelist; node != NULL; node = node->right) {
1227 current_filename[depth] = node->ch;
1228 if (node->down) {
1229 depth++;
1230 toggle_path_selection(node->down, pathname, on_or_off);
1231 depth--;
1232 }
1233 if (node->ch == '\0') {
1234 if (!strncmp(pathname, current_filename, strlen(pathname))) {
1235 for (j = 0;
1236 pathname[j] != '\0'
1237 && pathname[j] == current_filename[j]; j++);
1238 if (current_filename[j] == '/'
1239 || current_filename[j] == '\0') {
1240 node->selected = on_or_off;
1241 sprintf(tmp, "%s is now %s\n", current_filename,
1242 (on_or_off ? "ON" : "OFF"));
1243 }
1244 }
1245 }
1246 }
1247 if (depth == 0) {
1248 log_it("Finished toggling selection");
1249 }
1250}
1251
1252
1253/**
1254 * Toggle node selection of a filelist tree.
1255 * @param filelist The filelist tree to operate on.
1256 * @param on_or_off Whether to toggle selection on or off.
1257 * @bug I don't understand this function. Would someone care to explain it?
1258 */
1259void toggle_node_selection(struct s_node *filelist, bool on_or_off)
1260{
1261 /*@ structure ************************************************** */
1262 struct s_node *node;
1263
1264 /*@ end vars *************************************************** */
1265 assert(filelist != NULL);
1266 for (node = filelist; node != NULL; node = node->right) {
1267 if (node->ch == '/') {
1268 continue;
1269 } /* don't go deep */
1270 if (node->ch == '\0') {
1271 node->selected = on_or_off;
1272 }
1273 if (node->down) {
1274 toggle_node_selection(node->down, on_or_off);
1275 }
1276 }
1277}
1278
1279
1280
1281
1282
1283
1284
1285/**
1286 * The pathname to the skeleton filelist, used to give better progress reporting for mondo_makefilelist().
1287 */
1288char *g_skeleton_filelist = NULL;
1289
1290/**
1291 * Number of entries in the skeleton filelist.
1292 */
1293long g_skeleton_entries = 0;
1294
1295/**
1296 * Wrapper around mondo_makefilelist().
1297 * @param bkpinfo The backup information structure. Fields used:
1298 * - @c bkpinfo->differential
1299 * - @c bkpinfo->exclude_paths
1300 * - @c bkpinfo->include_paths
1301 * - @c bkpinfo->make_filelist
1302 * - @c bkpinfo->scratchdir
1303 * - @c bkpinfo->tmpdir
1304 * @return 0 for success, nonzero for failure.
1305 * @see mondo_makefilelist
1306 */
1307int prepare_filelist()
1308{
1309
1310 /*@ int **************************************************** */
1311 int res = 0;
1312
1313 assert(bkpinfo != NULL);
1314 log_it("tmpdir=%s; scratchdir=%s", bkpinfo->tmpdir,
1315 bkpinfo->scratchdir);
1316 if (bkpinfo->make_filelist) {
1317 mvaddstr_and_log_it(g_currentY, 0,
1318 "Making catalog of files to be backed up");
1319 } else {
1320 mvaddstr_and_log_it(g_currentY, 0,
1321 "Using supplied catalog of files to be backed up");
1322 }
1323
1324 if (bkpinfo->make_filelist) {
1325 res =
1326 mondo_makefilelist(MONDO_LOGFILE, bkpinfo->tmpdir,
1327 bkpinfo->scratchdir, bkpinfo->include_paths,
1328 bkpinfo->exclude_paths,
1329 bkpinfo->differential, NULL);
1330 } else {
1331 res =
1332 mondo_makefilelist(MONDO_LOGFILE, bkpinfo->tmpdir,
1333 bkpinfo->scratchdir, NULL,
1334 bkpinfo->exclude_paths,
1335 bkpinfo->differential,
1336 bkpinfo->include_paths);
1337 }
1338
1339 if (res) {
1340 log_OS_error("Call to mondo_makefilelist failed");
1341 mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
1342 } else {
1343 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
1344 }
1345 return (res);
1346}
1347
1348
1349/**
1350 * Recursively list all files in @p dir newer than @p time_of_last_full_backup to @p fout.
1351 * @param dir The directory to list to @p fout.
1352 * @param sth The directories to skip (exclude).
1353 * @param fout The file to write everything to.
1354 * @param time_of_last_full_backup Only backup files newer than this (0 to disable).
1355 * @return 0, always.
1356 * @bug Return value should be @c void.
1357 */
1358int open_and_list_dir(char *dir, char *sth, FILE * fout,
1359 time_t time_of_last_full_backup)
1360{
1361 const char delims[] = " ";
1362
1363 DIR *dip;
1364 struct dirent *dit;
1365 struct stat statbuf;
1366 char *new;
1367 char *tmp;
1368 static int percentage = 0;
1369 char *skip_these;
1370 char *new_with_spaces;
1371 char *strtmp;
1372 char *token;
1373 char *find_excludes;
1374 static char *name_of_evalcall_form;
1375 int i;
1376 int lastpos = 0;
1377 static int depth = 0;
1378 char *p;
1379 static int counter = 0;
1380 static int uberctr = 0;
1381 static char *find_skeleton_marker;
1382 static long skeleton_lino = 0;
1383 static time_t last_time = 0;
1384 time_t this_time;
1385
1386 p = strrchr(dir, '/');
1387 if (p) {
1388 if (!strcmp(p, "/.") || !strcmp(p, "/..")) {
1389 return (0);
1390 }
1391 }
1392
1393 if (!depth) {
1394 malloc_string(name_of_evalcall_form);
1395 malloc_string(find_skeleton_marker);
1396 asprintf(&find_excludes, " ");
1397 while((token = mr_strtok (sth, delims, &lastpos))) {
1398 asprintf(&strtmp,"%s", find_excludes);
1399 paranoid_free(find_excludes);
1400 asprintf(&find_excludes,"%s -path %s -prune -o", strtmp, token);
1401 paranoid_free(strtmp);
1402 paranoid_free(token);
1403 }
1404#if linux
1405 // 2.6 has /sys as a proc-type thing -- must be excluded
1406 asprintf(&strtmp,
1407 "find %s -maxdepth %d -fstype mvfs -prune -o -path /dev/shm -prune -o -fstype proc -prune -o -fstype sysfs -prune -o %s -type d -print > %s 2> /dev/null",
1408 dir, MAX_SKEL_DEPTH, find_excludes, g_skeleton_filelist);
1409#else
1410 // On BSD, for example, /sys is the kernel sources -- don't exclude
1411 asprintf(&strtmp,
1412 "find %s -maxdepth %d -fstype mvfs -prune -o -path /proc -prune -o %s -type d -print > %s 2> /dev/null",
1413 dir, MAX_SKEL_DEPTH, find_excludes, g_skeleton_filelist);
1414#endif
1415 paranoid_free(find_excludes);
1416 log_msg(5, "find command = %s", strtmp);
1417 system(strtmp);
1418 paranoid_free(strtmp);
1419 asprintf(&tmp, "wc -l %s | awk '{print $1;}'", g_skeleton_filelist);
1420 g_skeleton_entries =
1421 1 + atol(call_program_and_get_last_line_of_output(tmp));
1422 paranoid_free(tmp);
1423 sprintf(name_of_evalcall_form, "Making catalog of %s", dir);
1424 open_evalcall_form(name_of_evalcall_form);
1425 find_skeleton_marker[0] = '\0';
1426 skeleton_lino = 1;
1427 log_msg(5, "entries = %ld", g_skeleton_entries);
1428 percentage = 0;
1429 } else if (depth <= MAX_SKEL_DEPTH) // update evalcall form if appropriate
1430 {
1431 sprintf(find_skeleton_marker,
1432 "grep -Fv \"%s\" %s > %s.new 2> /dev/null", dir,
1433 g_skeleton_filelist, g_skeleton_filelist);
1434// log_msg(0, "fsm = %s", find_skeleton_marker);
1435 if (!system(find_skeleton_marker)) {
1436 percentage = (int) (skeleton_lino * 100 / g_skeleton_entries);
1437 skeleton_lino++;
1438// log_msg(5, "Found %s", dir);
1439// log_msg(2, "Incrementing skeleton_lino; now %ld/%ld (%d%%)", skeleton_lino, g_skeleton_entries, percentage);
1440 sprintf(find_skeleton_marker, "mv -f %s.new %s",
1441 g_skeleton_filelist, g_skeleton_filelist);
1442// log_msg(6, "fsm = %s", find_skeleton_marker);
1443 run_program_and_log_output(find_skeleton_marker, 8);
1444 time(&this_time);
1445 if (this_time != last_time) {
1446 last_time = this_time;
1447#ifndef _XWIN
1448 if (!g_text_mode) {
1449 asprintf(&tmp, "Reading %-68s", dir);
1450 newtDrawRootText(0, g_noof_rows - 3, tmp);
1451 paranoid_free(tmp);
1452 }
1453#endif
1454 update_evalcall_form(percentage);
1455 }
1456 }
1457 }
1458
1459 depth++;
1460
1461// log_msg(0, "Cataloguing %s", dir);
1462 if (sth[0] == ' ') {
1463 asprintf(&skip_these, "%s", sth);
1464 } else {
1465 asprintf(&skip_these, " %s ", sth);
1466 }
1467 asprintf(&new_with_spaces, " %s ", dir);
1468 if ((dip = opendir(dir)) == NULL) {
1469 asprintf(&tmp,"opendir %s", dir);
1470 log_OS_error(tmp);
1471 paranoid_free(tmp);
1472 } else if (strstr(skip_these, new_with_spaces)) {
1473 fprintf(fout, "%s\n", dir); // if excluded dir then print dir ONLY
1474 } else {
1475 fprintf(fout, "%s\n", dir);
1476 while ((dit = readdir(dip)) != NULL) {
1477 i++;
1478 if (strcmp(dir, "/")) {
1479 asprintf(&new,"%s/%s",dir,dit->d_name);
1480 } else {
1481 asprintf(&new,"%s%s",dir,dit->d_name);
1482 }
1483 paranoid_free(new_with_spaces);
1484 asprintf(&new_with_spaces, " %s ", new);
1485 if (strstr(skip_these, new_with_spaces)) {
1486 fprintf(fout, "%s\n", new);
1487 paranoid_free(new_with_spaces);
1488 } else {
1489 paranoid_free(new_with_spaces);
1490 if (!lstat(new, &statbuf)) {
1491 if (!S_ISLNK(statbuf.st_mode)
1492 && S_ISDIR(statbuf.st_mode)) {
1493 open_and_list_dir(new, skip_these, fout,
1494 time_of_last_full_backup);
1495 } else {
1496 if (time_of_last_full_backup == 0
1497 || time_of_last_full_backup <
1498 statbuf.st_ctime) {
1499 fprintf(fout, "%s\n", new);
1500 if ((counter++) > 128) {
1501 counter = 0;
1502 uberctr++;
1503 asprintf(&tmp, " %c ",
1504 special_dot_char(uberctr));
1505#ifndef _XWIN
1506 if (!g_text_mode) {
1507 newtDrawRootText(77, g_noof_rows - 3,
1508 tmp);
1509 newtRefresh();
1510 }
1511#endif
1512 paranoid_free(tmp);
1513 }
1514 }
1515 }
1516 }
1517 }
1518 paranoid_free(new);
1519 }
1520 }
1521 paranoid_free(new_with_spaces);
1522 paranoid_free(skip_these);
1523
1524 if (dip) {
1525 if (closedir(dip) == -1) {
1526 log_OS_error("closedir");
1527 }
1528 }
1529 depth--;
1530 if (!depth) {
1531 close_evalcall_form();
1532 paranoid_free(name_of_evalcall_form);
1533 paranoid_free(find_skeleton_marker);
1534 unlink(g_skeleton_filelist);
1535 log_msg(5, "g_skeleton_entries = %ld", g_skeleton_entries);
1536 }
1537 return (0);
1538}
1539
1540
1541
1542/**
1543 * Get the next entry in the space-separated list in @p incoming.
1544 * So if @p incoming was '"one and two" three four', we would
1545 * return "one and two".
1546 * @param incoming The list to get the next entry from.
1547 * @return The first item in the list (respecting double quotes).
1548 * @note The returned string points to static data that will be overwritten with each call.
1549 */
1550char *next_entry(char *incoming)
1551{
1552 char *sz_res;
1553 char *p;
1554 bool in_quotes = FALSE;
1555
1556 asprintf(&sz_res, "%s", incoming);
1557 p = sz_res;
1558 while ((*p != ' ' || in_quotes) && *p != '\0') {
1559 if (*p == '\"') {
1560 in_quotes = !in_quotes;
1561 }
1562 p++;
1563 }
1564 *p = '\0';
1565 return (sz_res);
1566}
1567
1568
1569
1570/**
1571 * Create the filelist for the backup. It will be stored in [scratchdir]/archives/filelist.full.
1572 * @param logfile Unused.
1573 * @param tmpdir The tmpdir of the backup.
1574 * @param scratchdir The scratchdir of the backup.
1575 * @param include_paths The paths to back up, or NULL if you're using a user-defined filelist.
1576 * @param excp The paths to NOT back up.
1577 * @param differential The differential level (currently only 0 and 1 are supported).
1578 * @param userdef_filelist The user-defined filelist, or NULL if you're using @p include_paths.
1579 * @return 0, always.
1580 * @bug @p logfile is unused.
1581 * @bug Return value is meaningless.
1582 */
1583int mondo_makefilelist(char *logfile, char *tmpdir, char *scratchdir,
1584 char *include_paths, char *excp, int differential,
1585 char *userdef_filelist)
1586{
1587 char *p, *q;
1588 char *sz_datefile;
1589 char *sz_filelist, *exclude_paths, *tmp;
1590 int i;
1591 FILE *fout;
1592 char *command;
1593 time_t time_of_last_full_backup = 0;
1594 struct stat statbuf;
1595 char *tmp1 = NULL;
1596 char *tmp2 = NULL;
1597
1598 malloc_string(command);
1599 malloc_string(tmp);
1600 malloc_string(g_skeleton_filelist);
1601 if (!(exclude_paths = malloc(8*MAX_STR_LEN))) {
1602 fatal_error("Cannot malloc exclude_paths");
1603 }
1604 asprintf(&sz_datefile,MONDO_CACHE"/difflevel.%d" , 0);
1605 if (!include_paths && !userdef_filelist) {
1606 fatal_error
1607 ("Please supply either include_paths or userdef_filelist");
1608 }
1609// make hole for filelist
1610 sprintf(command, "mkdir -p %s/archives", scratchdir);
1611 paranoid_system(command);
1612 asprintf(&sz_filelist, "%s/tmpfs/filelist.full", tmpdir);
1613 make_hole_for_file(sz_filelist);
1614
1615 if (differential == 0) {
1616 // restore last good datefile if it exists
1617 sprintf(command, "cp -f %s.aborted %s", sz_datefile, sz_datefile);
1618 run_program_and_log_output(command, 3);
1619 // backup last known good datefile just in case :)
1620 if (does_file_exist(sz_datefile)) {
1621 sprintf(command, "mv -f %s %s.aborted", sz_datefile,
1622 sz_datefile);
1623 paranoid_system(command);
1624 }
1625 make_hole_for_file(sz_datefile);
1626 write_one_liner_data_file(sz_datefile,
1627 call_program_and_get_last_line_of_output
1628 ("date +%s"));
1629 } else if (lstat(sz_datefile, &statbuf)) {
1630 log_msg(2,
1631 "Warning - unable to find date of previous backup. Full backup instead.");
1632 differential = 0;
1633 time_of_last_full_backup = 0;
1634 } else {
1635 time_of_last_full_backup = statbuf.st_mtime;
1636 log_msg(2, "Differential backup. Yay.");
1637 }
1638 paranoid_free(sz_datefile);
1639
1640// use user-specified filelist (if specified)
1641 if (userdef_filelist) {
1642 log_msg(1,
1643 "Using the user-specified filelist - %s - instead of calculating one",
1644 userdef_filelist);
1645 sprintf(command, "cp -f %s %s", userdef_filelist, sz_filelist);
1646 if (run_program_and_log_output(command, 3)) {
1647 fatal_error("Failed to copy user-specified filelist");
1648 }
1649 } else {
1650 log_msg(2, "include_paths = '%s'", include_paths);
1651 log_msg(1, "Calculating filelist");
1652 asprintf(&tmp2, call_program_and_get_last_line_of_output("mount | grep -Ew 'ntfs|ntfs-3g|fat|vfat|dos' | awk '{print $3}'"));
1653 if (strlen(tmp2) < 1) {
1654 asprintf(&tmp1," ");
1655 } else {
1656 log_msg(2, "Found windows FS: %s",tmp2);
1657 asprintf(&tmp1, "find %s -name '/win386.swp' -o -name '/hiberfil.sys' -o -name '/pagefile.sys' 2> /dev/null\n",tmp2);
1658 paranoid_free(tmp2);
1659 asprintf(&tmp2, call_program_and_get_last_line_of_output(tmp1));
1660 log_msg(2, "Found windows files: %s",tmp2);
1661 }
1662 paranoid_free(tmp1);
1663
1664 snprintf(exclude_paths, (size_t)8*MAX_STR_LEN," %s %s %s %s %s . .. \
1665" MNT_CDROM " " MNT_FLOPPY " /media /tmp \
1666/proc /sys " MINDI_CACHE, MONDO_CACHE, excp, tmp2, (tmpdir[0] == '/' && tmpdir[1] == '/') ? (tmpdir + 1) : tmpdir, (scratchdir[0] == '/' && scratchdir[1] == '/') ? (scratchdir + 1) : scratchdir);
1667 paranoid_free(tmp2);
1668
1669 log_msg(2, "Excluding paths = '%s'", exclude_paths);
1670 log_msg(2,
1671 "Generating skeleton filelist so that we can track our progress");
1672 sprintf(g_skeleton_filelist, "%s/tmpfs/skeleton.txt", tmpdir);
1673 make_hole_for_file(g_skeleton_filelist);
1674 log_msg(4, "g_skeleton_entries = %ld", g_skeleton_entries);
1675 log_msg(2, "Opening out filelist to %s", sz_filelist);
1676 if (!(fout = fopen(sz_filelist, "w"))) {
1677 fatal_error("Cannot openout to sz_filelist");
1678 }
1679 i = 0;
1680 if (strlen(include_paths) == 0) {
1681 log_msg(1, "Including only '/' in %s", sz_filelist);
1682 open_and_list_dir("/", exclude_paths, fout,
1683 time_of_last_full_backup);
1684 } else {
1685 p = include_paths;
1686 while (*p) {
1687 q = next_entry(p);
1688 log_msg(1, "Including %s in filelist %s", q, sz_filelist);
1689 open_and_list_dir(q, exclude_paths, fout,
1690 time_of_last_full_backup);
1691 p += strlen(q);
1692 paranoid_free(q);
1693 while (*p == ' ') {
1694 p++;
1695 }
1696 }
1697 }
1698 paranoid_fclose(fout);
1699 }
1700 log_msg(2, "Copying new filelist to scratchdir");
1701 sprintf(command, "mkdir -p %s/archives", scratchdir);
1702 paranoid_system(command);
1703 sprintf(command, "cp -f %s %s/archives/", sz_filelist, scratchdir);
1704 paranoid_system(command);
1705 sprintf(command, "mv -f %s %s", sz_filelist, tmpdir);
1706 paranoid_system(command);
1707 paranoid_free(sz_filelist);
1708 log_msg(2, "Freeing variables");
1709 paranoid_free(command);
1710 paranoid_free(exclude_paths);
1711 paranoid_free(tmp);
1712 paranoid_free(g_skeleton_filelist);
1713 log_msg(2, "Exiting");
1714 return (0);
1715}
1716
1717
1718
1719
1720/**
1721 * Locate the string @p string_to_find in the tree rooted at @p startnode.
1722 * @param startnode The node containing the root of the directory tree.
1723 * @param string_to_find The string to look for at @p startnode.
1724 * @return The node containing the last element of @p string_to_find, or NULL if
1725 * it was not found.
1726 */
1727struct s_node *find_string_at_node(struct s_node *startnode,
1728 char *string_to_find)
1729{
1730 /*@ int ******************************************************** */
1731 int noof_chars;
1732 static int depth = 0;
1733 static char original_string[MAX_STR_LEN];
1734
1735 /*@ sturctures ************************************************* */
1736 struct s_node *node;
1737
1738 /*@ char ****************************************************** */
1739 char char_to_find;
1740
1741 /*@ bools ****************************************************** */
1742
1743 if (!depth) {
1744 strcpy(original_string, string_to_find);
1745 }
1746
1747 assert(startnode != NULL);
1748 assert(string_to_find != NULL);
1749
1750 noof_chars = strlen(string_to_find) + 1; /* we include the '\0' */
1751
1752 log_msg(7, "starting --- str=%s", string_to_find);
1753
1754/* walk across tree if necessary */
1755 node = startnode;
1756 char_to_find = string_to_find[0];
1757 if (node->right != NULL && node->ch < char_to_find) {
1758 log_msg(7, "depth=%d --- going RIGHT ... %c-->%c", depth,
1759 char_to_find, node->ch, (node->right)->ch);
1760 return (find_string_at_node(node->right, string_to_find));
1761 }
1762
1763/* walk down tree if appropriate */
1764 if (node->down != NULL && node->ch == char_to_find) {
1765 log_msg(7, "depth=%d char=%c --- going DOWN", depth, char_to_find);
1766 depth++;
1767 node = find_string_at_node(node->down, string_to_find + 1);
1768 depth--;
1769 return (node);
1770 }
1771
1772 if (char_to_find == '\0' && node->ch == '\0') {
1773 log_msg(7, "%s is in tree", original_string);
1774 return (node);
1775 } else {
1776 log_msg(7, "%s is NOT in tree", original_string);
1777 return (NULL);
1778 }
1779}
1780
1781
1782
1783/**
1784 * Write all entries in @p needles_list_fname which are also in
1785 * @p filelist to @p matches_list_fname.
1786 * @param needles_list_fname A file containing strings to look for, 1 per line.
1787 * @param filelist The node for the root of the directory structure to search in.
1788 * @param matches_list_fname The filename where we should put the matches.
1789 * @return The number of matches found.
1790 */
1791long save_filelist_entries_in_common(char *needles_list_fname,
1792 struct s_node *filelist,
1793 char *matches_list_fname,
1794 bool use_star)
1795{
1796 int retval = 0;
1797 struct s_node *found_node;
1798 FILE *fin;
1799 FILE *fout;
1800 char *fname;
1801 char *tmp;
1802 size_t len = 0; // Scrub's patch doesn't work without that
1803
1804// log_msg(1, "use_star = %s", (use_star)?"TRUE":"FALSE");
1805 malloc_string(fname);
1806 malloc_string(tmp);
1807 log_msg(5, "starting");
1808 log_msg(5, "needles_list_fname = %s", needles_list_fname);
1809 log_msg(5, "matches_list_fname = %s", matches_list_fname);
1810 if (!(fin = fopen(needles_list_fname, "r"))) {
1811 fatal_error("Cannot openin needles_list_fname");
1812 }
1813 if (!(fout = fopen(matches_list_fname, "w"))) {
1814 fatal_error("Cannot openout matches_list_fname");
1815 }
1816 while (!feof(fin)) {
1817// fscanf(fin, "%s\n", fname);
1818 len = MAX_STR_LEN - 1;
1819 getline(&fname, &len, fin); // patch by Scrub
1820 if (!use_star) {
1821 if (fname[0] == '/') {
1822 strcpy(tmp, fname);
1823 } else {
1824 tmp[0] = '/';
1825 strcpy(tmp + 1, fname);
1826 }
1827 strcpy(fname, tmp);
1828 }
1829 while (strlen(fname) > 0 && fname[strlen(fname) - 1] < 32) {
1830 fname[strlen(fname) - 1] = '\0';
1831 }
1832
1833/*
1834 if (strlen(fname)>3 && fname[strlen(fname)-1]=='/') { fname[strlen(fname)-1] = '\0'; }
1835 if (strlen(fname)==0) { continue; }
1836 sprintf(temporary_string, "echo \"Looking for '%s'\" >> /tmp/looking.txt", fname);
1837 system(temporary_string);
1838*/
1839
1840 log_msg(5, "Looking for '%s'", fname);
1841 found_node = find_string_at_node(filelist, fname);
1842 if (found_node) {
1843 if (found_node->selected) {
1844// if (use_star)
1845 if (fname[0] == '/') {
1846 strcpy(tmp, fname + 1);
1847 strcpy(fname, tmp);
1848 }
1849 log_msg(5, "Found '%s'", fname);
1850 turn_wildcard_chars_into_literal_chars(tmp, fname);
1851 fprintf(fout, "%s\n", tmp);
1852 retval++;
1853 }
1854 }
1855 }
1856 paranoid_fclose(fout);
1857 paranoid_fclose(fin);
1858 paranoid_free(fname);
1859 paranoid_free(tmp);
1860 return (retval);
1861}
1862
1863
1864
1865
1866
1867
1868/**
1869 * Add all files listed in @p list_of_files_fname to the directory structure rooted at
1870 * @p filelist.
1871 * @param filelist The top node of the directory structure to add the files to.
1872 * @param list_of_files_fname The file containing the files to add, 1 per line.
1873 * @param flag_em If TRUE, then flag the added files for restoration.
1874 * @return 0 for success, nonzero for failure.
1875 */
1876int add_list_of_files_to_filelist(struct s_node *filelist,
1877 char *list_of_files_fname, bool flag_em)
1878{
1879 FILE *fin;
1880 char *tmp;
1881 struct s_node *nod;
1882
1883 malloc_string(tmp);
1884 log_msg(3, "Adding %s to filelist", list_of_files_fname);
1885 if (!(fin = fopen(list_of_files_fname, "r"))) {
1886 iamhere(list_of_files_fname);
1887 return (1);
1888 }
1889 for (fgets(tmp, MAX_STR_LEN, fin); !feof(fin);
1890 fgets(tmp, MAX_STR_LEN, fin)) {
1891 if (!tmp[0]) {
1892 continue;
1893 }
1894 if ((tmp[strlen(tmp) - 1] == 13 || tmp[strlen(tmp) - 1] == 10)
1895 && strlen(tmp) > 0) {
1896 tmp[strlen(tmp) - 1] = '\0';
1897 }
1898 log_msg(2, "tmp = '%s'", tmp);
1899 if (!tmp[0]) {
1900 continue;
1901 }
1902 if ((nod = find_string_at_node(filelist, tmp))) {
1903 log_msg(5, "Found '%s' in filelist already. Cool.", tmp);
1904 } else {
1905 add_string_at_node(filelist, tmp);
1906 nod = find_string_at_node(filelist, tmp);
1907 }
1908
1909 if (nod && flag_em) {
1910 toggle_path_selection(filelist, tmp, TRUE);
1911 log_msg(5, "Flagged '%s'", tmp);
1912 }
1913 }
1914 paranoid_fclose(fin);
1915 paranoid_free(tmp);
1916 return (0);
1917}
1918
1919/* @} - end of filelistGroup */
Note: See TracBrowser for help on using the repository browser.