source: MondoRescue/branches/2.2.4/mondo/src/common/libmondo-filelist.c@ 1451

Last change on this file since 1451 was 1437, checked in by andree, 17 years ago

New define 'MINDI_CACHE' set to '/var/cache/mindi' rather than
hardcoding this in the code. Makes it easy to change the location. Also
adjusted some of the messages related to boot floppies or CDs.

(Also added missing debug level to log_debug() call.)

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