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

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

Modify getfattr call to have all extended attributes, including non user ones. (patch from Kevin Ritzenthaler Kevin.Ritzenthaler_at_hp.com) and fix #357

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