source: MondoRescue/branches/stable/mondo/mondo/common/libmondo-filelist.c@ 541

Last change on this file since 541 was 541, checked in by bcornec, 18 years ago

Stable is reverted to r436 (2.0.7) to put it in line with 2.0.8 and start from there over

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