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

Last change on this file since 1475 was 1475, checked in by Bruno Cornec, 17 years ago

Less verbosity in the sort function (reduces log file and helps reading it)

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