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

Last change on this file since 681 was 681, checked in by andree, 13 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.