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

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

getfacl and getfattr not searched everytime but only in the main of mondoarchive (in link with #63)

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