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

Last change on this file since 681 was 681, checked in by andree, 18 years ago

Replaced all occurrences of egrep with 'grep -E' and of fgrep with
'grep -F' in mondo.
egrep and fgrep are usually just script wrappers around grep these
days which means additional overhead compared to calling grep with the
relevant option. Also, it appears that egrep and fgrep have been
deprecated by POSIX some time ago.

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