source: branches/2.2.9/mondo/src/common/libmondo-files.c @ 2242

Last change on this file since 2242 was 2242, checked in by bruno, 10 years ago

r3145@localhost: bruno | 2009-06-29 17:18:58 +0200

  • Remove 2 memory leaks and change the behavoir for function media_descriptor_string which now allocates the string it returns (which needs to be free by the caller)
  • Property svn:keywords set to Id
File size: 36.5 KB
Line 
1/* file manipulation
2   $Id: libmondo-files.c 2242 2009-06-29 17:19:18Z bruno $
3*/
4
5/**
6 * @file
7 * Functions to manipulate files.
8 */
9
10
11#include "my-stuff.h"
12#include "mr_mem.h"
13#include "mondostructures.h"
14#include "libmondo-files.h"
15
16#include "lib-common-externs.h"
17
18#include "libmondo-tools-EXT.h"
19#include "libmondo-gui-EXT.h"
20#include "libmondo-devices-EXT.h"
21#include "libmondo-fork-EXT.h"
22#include "libmondo-string-EXT.h"
23
24/*@unused@*/
25//static char cvsid[] = "$Id: libmondo-files.c 2242 2009-06-29 17:19:18Z bruno $";
26
27extern char err_log_lines[NOOF_ERR_LINES][MAX_STR_LEN];
28
29extern int g_currentY;
30extern char *g_mondo_home;
31
32/* Reference to global bkpinfo */
33extern struct s_bkpinfo *bkpinfo;
34
35/**
36 * @addtogroup fileGroup
37 * @{
38 */
39/**
40 * Get an md5 checksum of the specified file.
41 * @param filename The file to checksum.
42 * @return The 32-character ASCII representation of the 128-bit checksum.
43 * @note The returned string points to static storage that will be overwritten with each call.
44 */
45char *calc_checksum_of_file(char *filename)
46{
47    /*@ buffers ***************************************************** */
48    static char output[MAX_STR_LEN];
49    char command[MAX_STR_LEN * 2];
50    char tmp[MAX_STR_LEN];
51
52    /*@ pointers **************************************************** */
53    char *p;
54    FILE *fin;
55
56    /*@ initialize pointers ***************************************** */
57
58    p = output;
59
60    /*@************************************************************** */
61
62    assert_string_is_neither_NULL_nor_zerolength(filename);
63    if (does_file_exist(filename)) {
64        sprintf(command, "md5sum \"%s\"", filename);
65        fin = popen(command, "r");
66        if (fin) {
67            (void) fgets(output, MAX_STR_LEN, fin);
68            p = strchr(output, ' ');
69            paranoid_pclose(fin);
70        }
71    } else {
72        sprintf(tmp, "File '%s' not found; cannot calc checksum",
73                filename);
74        log_it(tmp);
75    }
76    if (p) {
77        *p = '\0';
78    }
79    return (output);
80}
81
82
83/**
84 * Get a not-quite-unique representation of some of the file's @c stat properties.
85 * The returned string has the form <tt>size-mtime-ctime</tt>.
86 * @param curr_fname The file to generate the "checksum" for.
87 * @return The "checksum".
88 * @note The returned string points to static storage that will be overwritten with each call.
89 */
90char *calc_file_ugly_minichecksum(char *curr_fname)
91{
92
93    /*@ buffers ***************************************************** */
94    static char curr_cksum[1000];
95
96    /*@ pointers **************************************************** */
97
98    /*@ structures ************************************************** */
99    struct stat buf;
100
101    /*@ initialize data *************************************************** */
102    curr_cksum[0] = '\0';
103
104    /*@************************************************************** */
105
106    assert_string_is_neither_NULL_nor_zerolength(curr_fname);
107    if (lstat(curr_fname, &buf)) {
108        return (curr_cksum);    // empty
109    }
110
111    sprintf(curr_cksum, "%ld-%ld-%ld", (long) (buf.st_size),
112            (long) (buf.st_mtime), (long) (buf.st_ctime));
113    return (curr_cksum);
114}
115
116
117
118/**
119 * Get the number of lines in @p filename.
120 * @param filename The file to count lines in.
121 * @return The number of lines in @p filename.
122 * @bug This function uses the shell and "wc -l"; it should probably be rewritten in C.
123 */
124long count_lines_in_file(char *filename)
125{
126
127    /*@ buffers ***************************************************** */
128    char command[MAX_STR_LEN * 2];
129    char incoming[MAX_STR_LEN];
130    char tmp[MAX_STR_LEN];
131
132    /*@ long ******************************************************** */
133    long noof_lines = -1L;
134
135    /*@ pointers **************************************************** */
136    FILE *fin;
137
138    /*@ initialize [0] to null ******************************************** */
139    incoming[0] = '\0';
140
141    assert_string_is_neither_NULL_nor_zerolength(filename);
142    if (!does_file_exist(filename)) {
143        sprintf(tmp,
144                "%s does not exist, so I cannot found the number of lines in it",
145                filename);
146        log_it(tmp);
147        return (0);
148    }
149    sprintf(command, "cat %s | wc -l", filename);
150    if (!does_file_exist(filename)) {
151        return (-1);
152    }
153    fin = popen(command, "r");
154    if (fin) {
155        if (feof(fin)) {
156            noof_lines = 0;
157        } else {
158            (void) fgets(incoming, MAX_STR_LEN - 1, fin);
159            while (strlen(incoming) > 0
160                   && incoming[strlen(incoming) - 1] < 32) {
161                incoming[strlen(incoming) - 1] = '\0';
162            }
163            noof_lines = atol(incoming);
164        }
165        paranoid_pclose(fin);
166    }
167    return (noof_lines);
168}
169
170
171/**
172 * Check for existence of given @p filename.
173 * @param filename The file to check for.
174 * @return TRUE if it exists, FALSE otherwise.
175 */
176bool does_file_exist(char *filename)
177{
178
179    /*@ structures ************************************************** */
180    struct stat buf;
181
182    /*@************************************************************** */
183
184    assert(filename != NULL);
185    //  assert_string_is_neither_NULL_nor_zerolength(filename);
186    if (lstat(filename, &buf)) {
187        log_msg(20, "%s does not exist", filename);
188        return (FALSE);
189    } else {
190        log_msg(20, "%s exists", filename);
191        return (TRUE);
192    }
193}
194
195
196
197
198
199
200/**
201 * Modify @p inout (a file containing a list of files) to only contain files
202 * that exist.
203 * @param inout The filelist to operate on.
204 * @note The original file is renamed beforehand, so it will not be accessible
205 * while the modification is in progress.
206 */
207void exclude_nonexistent_files(char *inout)
208{
209    char infname[MAX_STR_LEN];
210    char outfname[MAX_STR_LEN];
211    char tmp[MAX_STR_LEN];
212    char incoming[MAX_STR_LEN];
213
214    /*@ int ********************************************************* */
215    int i;
216
217    /*@ pointers **************************************************** */
218    FILE *fin, *fout;
219
220
221    /*@ end vars *********************************************************** */
222
223    assert_string_is_neither_NULL_nor_zerolength(inout);
224    sprintf(infname, "%s.in", inout);
225    sprintf(outfname, "%s", inout);
226    sprintf(tmp, "cp -f %s %s", inout, infname);
227    run_program_and_log_output(tmp, FALSE);
228    if (!(fin = fopen(infname, "r"))) {
229        log_OS_error("Unable to openin infname");
230        return;
231    }
232    if (!(fout = fopen(outfname, "w"))) {
233        log_OS_error("Unable to openout outfname");
234        return;
235    }
236    for (fgets(incoming, MAX_STR_LEN, fin); !feof(fin);
237         fgets(incoming, MAX_STR_LEN, fin)) {
238        i = strlen(incoming) - 1;
239        if (i >= 0 && incoming[i] < 32) {
240            incoming[i] = '\0';
241        }
242        if (does_file_exist(incoming)) {
243            fprintf(fout, "%s\n", incoming);
244        } else {
245            sprintf(tmp, "Excluding '%s'-nonexistent\n", incoming);
246            log_it(tmp);
247        }
248    }
249    paranoid_fclose(fout);
250    paranoid_fclose(fin);
251    unlink(infname);
252}
253
254
255
256
257
258
259
260
261
262/**
263 * Attempt to find the user's kernel by calling Mindi.
264 * If Mindi can't find the kernel, ask user. If @p kernel is not empty,
265 * don't do anything.
266 * @param kernel Where to put the found kernel.
267 * @return 0 for success, 1 for failure.
268 */
269int figure_out_kernel_path_interactively_if_necessary(char *kernel)
270{
271    char tmp[MAX_STR_LEN];
272    char *command;
273
274    if (!kernel[0]) {
275        strcpy(kernel,
276               call_program_and_get_last_line_of_output
277               ("mindi --findkernel 2> /dev/null"));
278    }
279    // If we didn't get anything back, check whether mindi raised a fatal error
280    if (!kernel[0]) {
281        malloc_string(command);
282        strcpy(command, "grep 'Fatal error' /var/log/mindi.log");
283        strcpy(tmp, call_program_and_get_last_line_of_output(command));
284        if (strlen(tmp) > 1) {
285            popup_and_OK(tmp);
286            fatal_error("Mindi gave a fatal error. Please check '/var/log/mindi.log'.");
287        }
288        paranoid_free(command);
289    }
290    log_it("Calling Mindi with kernel path of '%s'", kernel);
291    while (!kernel[0]) {
292        if (!ask_me_yes_or_no
293            ("Kernel not found or invalid. Choose another?")) {
294            return (1);
295        }
296        if (!popup_and_get_string
297            ("Kernel path",
298             "What is the full path and filename of your kernel, please?",
299             kernel, MAX_STR_LEN / 4)) {
300            fatal_error
301                ("Kernel not found. Please specify with the '-k' flag.");
302        }
303        sprintf(tmp, "User says kernel is at %s", kernel);
304        log_it(tmp);
305    }
306    return (0);
307}
308
309
310
311
312
313
314/**
315 * Find location of specified executable in user's PATH.
316 * @param fname The basename of the executable to search for (e.g. @c afio).
317 * @return The full path to the executable, or "" if it does not exist, or NULL if @c file could not be found.
318 * @note The returned string points to static storage that will be overwritten with each call.
319 * @bug The checks with @c file and @c dirname seem pointless. If @c incoming is "", then you're calling
320 * <tt>dirname 2\>/dev/null</tt> or <tt>file 2\>/dev/null | cut -d':' -f1 2\>/dev/null</tt>, which basically amounts
321 * to nothing.
322 */
323char *find_home_of_exe(char *fname)
324{
325    /*@ buffers ********************* */
326    static char output[MAX_STR_LEN];
327    char *incoming;
328    char *command;
329
330    malloc_string(incoming);
331    malloc_string(command);
332    incoming[0] = '\0';
333    /*@******************************* */
334
335    assert_string_is_neither_NULL_nor_zerolength(fname);
336    sprintf(command, "which %s 2> /dev/null", fname);
337    strcpy(incoming, call_program_and_get_last_line_of_output(command));
338    if (incoming[0] == '\0') {
339        if (system("which file > /dev/null 2> /dev/null")) {
340            paranoid_free(incoming);
341            paranoid_free(command);
342            output[0] = '\0';
343            return (NULL);      // forget it :)
344        }
345        sprintf(command,
346                "file %s 2> /dev/null | cut -d':' -f1 2> /dev/null",
347                incoming);
348        strcpy(incoming,
349               call_program_and_get_last_line_of_output(command));
350    }
351    if (incoming[0] == '\0')    // yes, it is == '\0' twice, not once :)
352    {
353        sprintf(command, "dirname %s 2> /dev/null", incoming);
354        strcpy(incoming,
355               call_program_and_get_last_line_of_output(command));
356    }
357    strcpy(output, incoming);
358    if (output[0] != '\0' && does_file_exist(output)) {
359        log_msg(4, "find_home_of_exe () --- Found %s at %s", fname,
360                incoming);
361    } else {
362        output[0] = '\0';
363        log_msg(4, "find_home_of_exe() --- Could not find %s", fname);
364    }
365    paranoid_free(incoming);
366    paranoid_free(command);
367    if (!output[0]) {
368        return (NULL);
369    } else {
370        return (output);
371    }
372}
373
374
375
376
377
378
379
380
381/**
382 * Get the last sequence of digits surrounded by non-digits in the first 32k of
383 * a file.
384 * @param logfile The file to look in.
385 * @return The number found, or 0 if none.
386 */
387int get_trackno_from_logfile(char *logfile)
388{
389
390    /*@ pointers ********************************************************* */
391    FILE *fin;
392
393    /*@ int ************************************************************** */
394    int trackno = 0;
395    size_t len = 0;
396
397    /*@ buffer ************************************************************ */
398    char datablock[32701];
399
400    assert_string_is_neither_NULL_nor_zerolength(logfile);
401    if (!(fin = fopen(logfile, "r"))) {
402        log_OS_error("Unable to open logfile");
403        fatal_error("Unable to open logfile to read trackno");
404    }
405    len = fread(datablock, 1, 32700, fin);
406    paranoid_fclose(fin);
407    if (len <= 0) {
408        return (0);
409    }
410    for (; len > 0 && !isdigit(datablock[len - 1]); len--);
411    datablock[len--] = '\0';
412    for (; len > 0 && isdigit(datablock[len - 1]); len--);
413    trackno = atoi(datablock + len);
414    /*
415       sprintf(tmp,"datablock=%s; trackno=%d",datablock+len, trackno);
416       log_it(tmp);
417     */
418    return (trackno);
419}
420
421
422
423
424
425
426
427/**
428 * Get a percentage from the last line of @p filename. We look for the string
429 * "% done" on the last line and, if we find it, grab the number before the last % sign.
430 * @param filename The file to get the percentage from.
431 * @return The percentage found, or 0 for error.
432 */
433int grab_percentage_from_last_line_of_file(char *filename)
434{
435
436    /*@ buffers ***************************************************** */
437    char tmp[MAX_STR_LEN];
438    char lastline[MAX_STR_LEN];
439    char command[MAX_STR_LEN];
440    /*@ pointers **************************************************** */
441    char *p;
442
443    /*@ int's ******************************************************* */
444    int i;
445
446    for (i = NOOF_ERR_LINES - 1;
447         i >= 0 && !strstr(err_log_lines[i], "% Done")
448         && !strstr(err_log_lines[i], "% done"); i--);
449    if (i < 0) {
450        sprintf(command,
451                "tail -n3 %s | grep -Fi \"%c\" | tail -n1 | awk '{print $0;}'",
452                filename, '%');
453        strcpy(lastline,
454               call_program_and_get_last_line_of_output(command));
455        if (!lastline[0]) {
456            return (0);
457        }
458    } else {
459        strcpy(lastline, err_log_lines[i]);
460    }
461
462    p = strrchr(lastline, '%');
463    if (p) {
464        *p = '\0';
465    }
466//  log_msg(2, "lastline='%s', ", p, lastline);
467    if (!p) {
468        return (0);
469    }
470    *p = '\0';
471    for (p--; *p != ' ' && p != lastline; p--);
472    if (p != lastline) {
473        p++;
474    }
475    i = atoi(p);
476
477    sprintf(tmp, "'%s' --> %d", p, i);
478//     log_to_screen(tmp);
479
480    return (i);
481}
482
483
484
485
486
487/**
488 * Return the last line of @p filename.
489 * @param filename The file to get the last line of.
490 * @return The last line of the file.
491 * @note The returned string points to static storage that will be overwritten with each call.
492 */
493char *last_line_of_file(char *filename)
494{
495    /*@ buffers ***************************************************** */
496    static char output[MAX_STR_LEN];
497    static char command[MAX_STR_LEN * 2];
498    static char tmp[MAX_STR_LEN];
499
500    /*@ pointers **************************************************** */
501    FILE *fin;
502
503    /*@ end vars **************************************************** */
504
505    if (!does_file_exist(filename)) {
506        sprintf(tmp, "Tring to get last line of nonexistent file (%s)",
507                filename);
508        log_it(tmp);
509        output[0] = '\0';
510        return (output);
511    }
512    sprintf(command, "tail -n1 %s", filename);
513    fin = popen(command, "r");
514    (void) fgets(output, MAX_STR_LEN, fin);
515    paranoid_pclose(fin);
516    while (strlen(output) > 0 && output[strlen(output) - 1] < 32) {
517        output[strlen(output) - 1] = '\0';
518    }
519    return (output);
520}
521
522/**
523 * Get the length of @p filename in bytes.
524 * @param filename The file to get the length of.
525 * @return The length of the file, or -1 for error.
526 */
527off_t length_of_file(char *filename)
528{
529    /*@ pointers *************************************************** */
530    FILE *fin;
531
532    /*@ long long ************************************************* */
533    off_t length;
534
535    fin = fopen(filename, "r");
536    if (!fin) {
537        log_it("filename=%s", filename);
538        log_OS_error("Unable to openin filename");
539        return (-1);
540    }
541    fseeko(fin, 0, SEEK_END);
542    length = ftello(fin);
543    paranoid_fclose(fin);
544    return (length);
545}
546
547
548
549/**
550 * ?????
551 * @bug I don't know what this function does. However, it seems orphaned, so it should probably be removed.
552 */
553int
554make_checksum_list_file(char *filelist, char *cksumlist, char *comppath)
555{
556    /*@ pointers **************************************************** */
557    FILE *fin;
558    FILE *fout;
559
560    /*@ int   ******************************************************* */
561    int percentage;
562    int i;
563    int counter = 0;
564
565    /*@ buffer ****************************************************** */
566    char stub_fname[1000];
567    char curr_fname[1000];
568    char curr_cksum[1000];
569    char tmp[1000];
570
571    /*@ long [long] ************************************************* */
572    off_t filelist_length;
573    off_t curr_pos;
574    long start_time;
575    long current_time;
576    long time_taken;
577    long time_remaining;
578
579    /*@ end vars *************************************************** */
580
581    start_time = get_time();
582    filelist_length = length_of_file(filelist);
583    sprintf(tmp, "filelist = %s; cksumlist = %s", filelist, cksumlist);
584    log_it(tmp);
585    fin = fopen(filelist, "r");
586    if (fin == NULL) {
587        log_OS_error("Unable to fopen-in filelist");
588        log_to_screen("Can't open filelist");
589        return (1);
590    }
591    fout = fopen(cksumlist, "w");
592    if (fout == NULL) {
593        log_OS_error("Unable to openout cksumlist");
594        paranoid_fclose(fin);
595        log_to_screen("Can't open checksum list");
596        return (1);
597    }
598    for (fgets(stub_fname, 999, fin); !feof(fin);
599         fgets(stub_fname, 999, fin)) {
600        if (stub_fname[(i = strlen(stub_fname) - 1)] < 32) {
601            stub_fname[i] = '\0';
602        }
603        sprintf(tmp, "%s%s", comppath, stub_fname);
604        strcpy(curr_fname, tmp + 1);
605        strcpy(curr_cksum, calc_file_ugly_minichecksum(curr_fname));
606        fprintf(fout, "%s\t%s\n", curr_fname, curr_cksum);
607        if (counter++ > 12) {
608            current_time = get_time();
609            counter = 0;
610            curr_fname[37] = '\0';
611            curr_pos = ftello(fin) / 1024;
612            percentage = (int) (curr_pos * 100 / filelist_length);
613            time_taken = current_time - start_time;
614            if (percentage == 0) {
615                /*              printf("%0d%% done      \r",percentage); */
616            } else {
617                time_remaining =
618                    time_taken * 100 / (long) (percentage) - time_taken;
619                sprintf(tmp,
620                        "%02d%% done   %02d:%02d taken   %02d:%02d remaining  %-37s\r",
621                        percentage, (int) (time_taken / 60),
622                        (int) (time_taken % 60),
623                        (int) (time_remaining / 60),
624                        (int) (time_remaining % 60), curr_fname);
625                log_to_screen(tmp);
626            }
627            sync();
628        }
629    }
630    paranoid_fclose(fout);
631    paranoid_fclose(fin);
632    log_it("Done.");
633    return (0);
634}
635
636
637/**
638 * Create the directory @p outdir_fname and all parent directories. Equivalent to <tt>mkdir -p</tt>.
639 * @param outdir_fname The directory to create.
640 * @return The return value of @c mkdir.
641 */
642int make_hole_for_dir(char *outdir_fname)
643{
644    char tmp[MAX_STR_LEN * 2];
645    int res = 0;
646
647    assert_string_is_neither_NULL_nor_zerolength(outdir_fname);
648    sprintf(tmp, "mkdir -p %s", outdir_fname);
649    res = system(tmp);
650    return (res);
651}
652
653
654/**
655 * Create the parent directories of @p outfile_fname.
656 * @param outfile_fname The file to make a "hole" for.
657 * @return 0, always.
658 * @bug Return value unnecessary.
659 */
660int make_hole_for_file(char *outfile_fname)
661{
662    /*@ buffer ****************************************************** */
663    char command[MAX_STR_LEN * 2];
664
665    /*@ int  ******************************************************** */
666    int res = 0;
667
668    /*@ end vars *************************************************** */
669
670    assert_string_is_neither_NULL_nor_zerolength(outfile_fname);
671    assert(!strstr(outfile_fname, MNT_CDROM));
672    assert(!strstr(outfile_fname, "/dev/cdrom"));
673    sprintf(command, "mkdir -p \"%s\" 2> /dev/null", outfile_fname);
674    res += system(command);
675    sprintf(command, "rmdir \"%s\" 2> /dev/null", outfile_fname);
676    res += system(command);
677    sprintf(command, "rm -f \"%s\" 2> /dev/null", outfile_fname);
678    res += system(command);
679    unlink(outfile_fname);
680    return (0);
681}
682
683
684
685
686/**
687 * Get the number of lines in @p filelist_fname that contain the string @p wildcard.
688 * @param filelist_fname The file to search through.
689 * @param wildcard The string to search for. This is @e not a shell glob or a regular expression.
690 * @return The number of lines matched.
691 */
692long noof_lines_that_match_wildcard(char *filelist_fname, char *wildcard)
693{
694    /*@ long ******************************************************* */
695    long matches = 0;
696
697    /*@ pointers *************************************************** */
698    FILE *fin;
699
700    /*@ buffers **************************************************** */
701    char incoming[MAX_STR_LEN];
702
703    /*@ end vars *************************************************** */
704
705
706    fin = fopen(filelist_fname, "r");
707
708    if (!fin) {
709        log_OS_error("Unable to openin filelist_fname");
710        return (0);
711    }
712    (void) fgets(incoming, MAX_STR_LEN - 1, fin);
713    while (!feof(fin)) {
714        if (strstr(incoming, wildcard)) {
715            matches++;
716        }
717        (void) fgets(incoming, MAX_STR_LEN - 1, fin);
718    }
719    paranoid_fclose(fin);
720    return (matches);
721}
722
723
724
725/**
726 * Determine the size (in KB) of @p dev in the mountlist in <tt>tmpdir</tt>/mountlist.txt.
727 * @param tmpdir The tempdir where the mountlist is stored.
728 * @param dev The device to search for.
729 * @return The size of the partition in KB.
730 */
731long size_of_partition_in_mountlist_K(char *tmpdir, char *dev)
732{
733    char command[MAX_STR_LEN];
734    char mountlist[MAX_STR_LEN];
735    char sz_res[MAX_STR_LEN];
736    long file_len_K;
737
738    sprintf(mountlist, "%s/mountlist.txt", tmpdir);
739    sprintf(command,
740            "grep \"%s \" %s/mountlist.txt | head -n1 | awk '{print $4}'",
741            dev, tmpdir);
742    log_it(command);
743    strcpy(sz_res, call_program_and_get_last_line_of_output(command));
744    file_len_K = atol(sz_res);
745    log_msg(4, "%s --> %s --> %ld", command, sz_res, file_len_K);
746    return (file_len_K);
747}
748
749/**
750 * Calculate the total size (in KB) of all the biggiefiles in this backup.
751 * @param bkpinfo The backup information structure. Only the @c bkpinfo->tmpdir field is used.
752 * @return The total size of all biggiefiles in KB.
753 */
754long size_of_all_biggiefiles_K()
755{
756    /*@ buffers ***************************************************** */
757    char *fname;
758    char *biggielist;
759    char *comment;
760    char *tmp;
761    char *command;
762
763    /*@ long ******************************************************** */
764    long scratchL = 0;
765    long file_len_K;
766
767    /*@ pointers *************************************************** */
768    FILE *fin = NULL;
769
770    /*@ end vars *************************************************** */
771
772    malloc_string(fname);
773    malloc_string(biggielist);
774    malloc_string(comment);
775    malloc_string(tmp);
776    malloc_string(command);
777    log_it("Calculating size of all biggiefiles (in total)");
778    sprintf(biggielist, "%s/biggielist.txt", bkpinfo->tmpdir);
779    log_it("biggielist = %s", biggielist);
780    if (!(fin = fopen(biggielist, "r"))) {
781        log_OS_error
782            ("Cannot open biggielist. OK, so estimate is based on filesets only.");
783    } else {
784        log_msg(4, "Reading it...");
785        for (fgets(fname, MAX_STR_LEN, fin); !feof(fin);
786             fgets(fname, MAX_STR_LEN, fin)) {
787            if (fname[strlen(fname) - 1] <= 32) {
788                fname[strlen(fname) - 1] = '\0';
789            }
790            if (0 == strncmp(fname, "/dev/", 5)) {
791                if (is_dev_an_NTFS_dev(fname)) {
792                    if ( !find_home_of_exe("ntfsresize")) {
793                        fatal_error("ntfsresize not found");
794                    }
795                    sprintf(command, "ntfsresize --force --info %s|grep '^You might resize at '|cut -d' ' -f5", fname);
796                    log_it("command = %s", command);
797                    strcpy (tmp, call_program_and_get_last_line_of_output(command));
798                    log_it("res of it = %s", tmp);
799                    file_len_K = atoll(tmp) / 1024L;
800                } else {
801                    file_len_K = get_phys_size_of_drive(fname) * 1024L;
802                }
803            } else {
804                /* BERLIOS: more than long here ??? */
805                file_len_K = (long) (length_of_file(fname) / 1024);
806            }
807            if (file_len_K > 0) {
808                scratchL += file_len_K;
809                log_msg(4, "%s --> %ld K", fname, file_len_K);
810            }
811            sprintf(comment,
812                    "After adding %s, scratchL+%ld now equals %ld", fname,
813                    file_len_K, scratchL);
814            log_msg(4, comment);
815            if (feof(fin)) {
816                break;
817            }
818        }
819    }
820    log_it("Closing...");
821    paranoid_fclose(fin);
822    log_it("Finished calculating total size of all biggiefiles");
823    paranoid_free(fname);
824    paranoid_free(biggielist);
825    paranoid_free(comment);
826    paranoid_free(tmp);
827    paranoid_free(command);
828    return (scratchL);
829}
830
831/**
832 * Determine the amount of space (in KB) occupied by a mounted CD.
833 * This can also be used to find the space used for other directories.
834 * @param mountpt The mountpoint/directory to check.
835 * @return The amount of space occupied in KB.
836 */
837long long space_occupied_by_cd(char *mountpt)
838{
839    /*@ buffer ****************************************************** */
840    char tmp[MAX_STR_LEN];
841    char command[MAX_STR_LEN * 2];
842    long long llres;
843    /*@ pointers **************************************************** */
844    char *p;
845    FILE *fin;
846
847    /*@ end vars *************************************************** */
848
849    sprintf(command, "du -sk %s", mountpt);
850    errno = 0;
851    fin = popen(command, "r");
852    if (errno) {
853      log_it("popen() FAILED: command=%s, mountpt=%s, fin=%d, errno=%d, strerror=%s", command, mountpt, fin, errno, strerror(errno));
854      llres = 0;
855    } else {
856      (void) fgets(tmp, MAX_STR_LEN, fin);
857      paranoid_pclose(fin);
858      p = strchr(tmp, '\t');
859      if (p) {
860        *p = '\0';
861      }
862      for (p = tmp, llres = 0; *p != '\0'; p++) {
863        llres *= 10;
864        llres += (int) (*p - '0');
865      }
866    }
867
868    return (llres);
869}
870
871
872/**
873 * Update a CRC checksum to include another character.
874 * @param crc The original CRC checksum.
875 * @param c The character to add.
876 * @return The new CRC checksum.
877 * @ingroup utilityGroup
878 */
879unsigned int updcrc(unsigned int crc, unsigned int c)
880{
881    unsigned int tmp;
882    tmp = (crc >> 8) ^ c;
883    crc = (crc << 8) ^ crctttab[tmp & 255];
884    return crc;
885}
886
887/**
888 * Update a reverse CRC checksum to include another character.
889 * @param crc The original CRC checksum.
890 * @param c The character to add.
891 * @return The new CRC checksum.
892 * @ingroup utilityGroup
893 */
894unsigned int updcrcr(unsigned int crc, unsigned int c)
895{
896    unsigned int tmp;
897    tmp = crc ^ c;
898    crc = (crc >> 8) ^ crc16tab[tmp & 0xff];
899    return crc;
900}
901
902
903
904
905/**
906 * Check for an executable on the user's system; write a message to the
907 * screen and the log if we can't find it.
908 * @param fname The executable basename to look for.
909 * @return 0 if it's found, nonzero if not.
910 */
911int whine_if_not_found(char *fname)
912{
913    /*@ buffers *** */
914    char command[MAX_STR_LEN * 2];
915    char errorstr[MAX_STR_LEN];
916
917
918    sprintf(command, "which %s > /dev/null 2> /dev/null", fname);
919    sprintf(errorstr,
920            "Please install '%s'. I cannot find it on your system.",
921            fname);
922    if (system(command)) {
923        log_to_screen(errorstr);
924        log_to_screen
925            ("There may be hyperlink at http://www.mondorescue.com which");
926        log_to_screen("will take you to the relevant (missing) package.");
927        return (1);
928    } else {
929        return (0);
930    }
931}
932
933
934
935
936
937
938/**
939 * Create a data file at @p fname containing @p contents.
940 * The data actually can be multiple lines, despite the name.
941 * @param fname The file to create.
942 * @param contents The data to put in it.
943 * @return 0 for success, 1 for failure.
944 */
945int write_one_liner_data_file(char *fname, char *contents)
946{
947    /*@ pointers *************************************************** */
948    FILE *fout;
949    int res = 0;
950
951    /*@ end vars *************************************************** */
952
953    assert_string_is_neither_NULL_nor_zerolength(fname);
954    if (!contents) {
955        log_it("%d: Warning - writing NULL to %s", __LINE__, fname);
956    }
957    if (!(fout = fopen(fname, "w"))) {
958        log_it("fname=%s");
959        log_OS_error("Unable to openout fname");
960        return (1);
961    }
962    fprintf(fout, "%s\n", contents);
963    paranoid_fclose(fout);
964    return (res);
965}
966
967
968
969/**
970 * Read @p fname into @p contents.
971 * @param fname The file to read.
972 * @param contents Where to put its contents.
973 * @return 0 for success, nonzero for failure.
974 */
975int read_one_liner_data_file(char *fname, char *contents)
976{
977    /*@ pointers *************************************************** */
978    FILE *fin;
979    int res = 0;
980    int i;
981
982    /*@ end vars *************************************************** */
983
984    assert_string_is_neither_NULL_nor_zerolength(fname);
985    if (!contents) {
986        log_it("%d: Warning - reading NULL from %s", __LINE__, fname);
987    }
988    if (!(fin = fopen(fname, "r"))) {
989        log_it("fname=%s", fname);
990        log_OS_error("Unable to openin fname");
991        return (1);
992    }
993    fscanf(fin, "%s\n", contents);
994    i = strlen(contents);
995    if (i > 0 && contents[i - 1] < 32) {
996        contents[i - 1] = '\0';
997    }
998    paranoid_fclose(fin);
999    return (res);
1000}
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010/**
1011 * Copy the files that Mondo/Mindi need to run to the scratchdir or tempdir.
1012 * Currently this includes: copy Mondo's home directory to scratchdir, untar "mondo_home/payload.tgz"
1013 * if it exists, copy LAST-FILELIST-NUMBER to scratchdir, copy mondorestore
1014 * and post-nuke.tgz (if it exists) to tmpdir, and run "hostname > scratchdir/HOSTNAME".
1015 * @param bkpinfo The backup information structure. Fields used:
1016 * - @c bkpinfo->postnuke_tarball
1017 * - @c bkpinfo->scratchdir
1018 * - @c bkpinfo->tmpdir
1019 */
1020void copy_mondo_and_mindi_stuff_to_scratchdir()
1021{
1022    /*@ Char buffers ** */
1023    char command[MAX_STR_LEN * 2];
1024    char tmp[MAX_STR_LEN];
1025    char old_pwd[MAX_STR_LEN];
1026
1027    mvaddstr_and_log_it(g_currentY, 0,
1028                        "Copying Mondo's core files to the scratch directory");
1029
1030    log_msg(4, "g_mondo_home='%s'", g_mondo_home);
1031    if (strlen(g_mondo_home) < 2) {
1032        find_and_store_mondoarchives_home(g_mondo_home);
1033    }
1034    sprintf(command, CP_BIN " --parents -pRdf %s %s", g_mondo_home,
1035            bkpinfo->scratchdir);
1036
1037    log_msg(4, "command = %s", command);
1038    if (run_program_and_log_output(command, 1)) {
1039        fatal_error("Failed to copy Mondo's stuff to scratchdir");
1040    }
1041
1042    sprintf(tmp, "%s/payload.tgz", g_mondo_home);
1043    if (does_file_exist(tmp)) {
1044        log_it("Untarring payload %s to scratchdir %s", tmp,
1045               bkpinfo->scratchdir);
1046        (void) getcwd(old_pwd, MAX_STR_LEN - 1);
1047        chdir(bkpinfo->scratchdir);
1048        sprintf(command, "tar -zxvf %s", tmp);
1049        if (run_program_and_log_output(command, FALSE)) {
1050            fatal_error("Failed to untar payload");
1051        }
1052        chdir(old_pwd);
1053    }
1054
1055    sprintf(command, "cp -f %s/LAST-FILELIST-NUMBER %s", bkpinfo->tmpdir,
1056            bkpinfo->scratchdir);
1057
1058    if (run_program_and_log_output(command, FALSE)) {
1059        fatal_error("Failed to copy LAST-FILELIST-NUMBER to scratchdir");
1060    }
1061
1062    strcpy(tmp,
1063           call_program_and_get_last_line_of_output("which mondorestore"));
1064    if (!tmp[0]) {
1065        fatal_error
1066            ("'which mondorestore' returned null. Where's your mondorestore? `which` can't find it. That's odd. Did you install mondorestore?");
1067    }
1068    sprintf(command, "cp -f %s %s", tmp, bkpinfo->tmpdir);
1069    if (run_program_and_log_output(command, FALSE)) {
1070        fatal_error("Failed to copy mondorestore to tmpdir");
1071    }
1072
1073    sprintf(command, "hostname > %s/HOSTNAME", bkpinfo->scratchdir);
1074    paranoid_system(command);
1075
1076    if (bkpinfo->postnuke_tarball[0]) {
1077        sprintf(command, "cp -f %s %s/post-nuke.tgz",
1078                bkpinfo->postnuke_tarball, bkpinfo->tmpdir);
1079        if (run_program_and_log_output(command, FALSE)) {
1080            fatal_error("Unable to copy post-nuke tarball to tmpdir");
1081        }
1082    }
1083
1084
1085    mvaddstr_and_log_it(g_currentY++, 74, "Done.");
1086}
1087
1088
1089
1090
1091
1092/**
1093 * Store the client's NFS configuration in files to be restored at restore-time.
1094 * Assumes that @c bkpinfo->media_type = nfs, but does not check for this.
1095 * @param bkpinfo The backup information structure. Fields used:
1096 * - @c nfs_mount
1097 * - @c nfs_remote_dir
1098 * - @c tmpdir
1099 */
1100void store_nfs_config()
1101{
1102
1103    /*@ buffers ******** */
1104    char nfs_dev[MAX_STR_LEN];
1105    char mac_addr[MAX_STR_LEN];
1106    char nfs_mount[MAX_STR_LEN];
1107    char nfs_client_ipaddr[MAX_STR_LEN];
1108    char nfs_client_netmask[MAX_STR_LEN];
1109    char nfs_client_broadcast[MAX_STR_LEN];
1110    char nfs_client_defgw[MAX_STR_LEN];
1111    char nfs_server_ipaddr[MAX_STR_LEN];
1112    char tmp[MAX_STR_LEN];
1113    char command[MAX_STR_LEN * 2];
1114
1115    /*@ pointers ***** */
1116    char *p;
1117
1118    log_it("Storing NFS configuration");
1119    strcpy(tmp, bkpinfo->nfs_mount);
1120    p = strchr(tmp, ':');
1121    if (!p) {
1122        fatal_error
1123            ("NFS mount doesn't have a colon in it, e.g. 192.168.1.4:/home/nfs");
1124    }
1125    *(p++) = '\0';
1126    strcpy(nfs_server_ipaddr, tmp);
1127    strcpy(nfs_mount, p);
1128
1129    /* BERLIOS : there is a bug #67 here as it only considers the first NIC */
1130    sprintf(command,
1131            "ifconfig | tr '\n' '#' | sed s/##// | tr '#' ' ' | tr '' '\n' | head -n1 | cut -d' ' -f1");
1132    strcpy(nfs_dev, call_program_and_get_last_line_of_output(command));
1133    sprintf(command,
1134            "ifconfig | tr '\n' '#' | sed s/##// | tr '#' ' ' | tr '' '\\n' | head -n1 | tr -s '\t' ' ' | cut -d' ' -f7 | cut -d':' -f2");
1135    strcpy(nfs_client_ipaddr,
1136           call_program_and_get_last_line_of_output(command));
1137    sprintf(command,
1138            "ifconfig | tr '\n' '#' | sed s/##// | tr '#' ' ' | tr '' '\\n' | head -n1 | tr -s '\t' ' ' | cut -d' ' -f9 | cut -d':' -f2");
1139    strcpy(nfs_client_netmask,
1140           call_program_and_get_last_line_of_output(command));
1141    sprintf(command,
1142            "ifconfig | tr '\n' '#' | sed s/##// | tr '#' ' ' | tr '' '\\n' | head -n1 | tr -s '\t' ' ' | cut -d' ' -f8 | cut -d':' -f2");
1143    strcpy(nfs_client_broadcast,
1144           call_program_and_get_last_line_of_output(command));
1145    sprintf(command,
1146            "route -n | grep '^0.0.0.0' | awk '{print $2}'");
1147    strcpy(nfs_client_defgw,
1148           call_program_and_get_last_line_of_output(command));
1149    sprintf(tmp,
1150            "nfs_client_ipaddr=%s; nfs_server_ipaddr=%s; nfs_mount=%s",
1151            nfs_client_ipaddr, nfs_server_ipaddr, nfs_mount);
1152    if (strlen(nfs_dev) < 2) {
1153        fatal_error
1154            ("Unable to find ethN (eth0, eth1, ...) adapter via NFS mount you specified.");
1155    }
1156    /********
1157    * If the NFS device that found above is a bonded device,
1158    * we need to replace it with an ethN device or the
1159    * networking will not start during an NFS restore.
1160    *
1161    * If the NFS device in nfs_dev begins with the word "bond", or alb or aft
1162    * look for the corresponding slave ethN device and copy it to nfs_dev.
1163    * Using the common MAC address
1164    ********/
1165    if (!strncmp(nfs_dev, "bond", 4) || !strncmp(nfs_dev, "alb", 3) || !strncmp(nfs_dev, "aft", 3)) {
1166        log_to_screen("Found bonding device %s; looking for corresponding ethN slave device\n", nfs_dev);
1167        sprintf(command,
1168                "ifconfig %s | awk '{print $5}' | head -n1", nfs_dev);
1169        strcpy(mac_addr, call_program_and_get_last_line_of_output(command));
1170        sprintf(command,
1171                "ifconfig | grep -E '%s' | grep -v '%s' | head -n1 | cut -d' ' -f1", mac_addr,nfs_dev);
1172        strcpy(nfs_dev, call_program_and_get_last_line_of_output(command));
1173        log_to_screen("Replacing it with %s\n", nfs_dev);
1174    }
1175
1176    sprintf(tmp, "%s/NFS-DEV", bkpinfo->tmpdir);
1177    write_one_liner_data_file(tmp, nfs_dev);
1178
1179    sprintf(tmp, "%s/NFS-CLIENT-IPADDR", bkpinfo->tmpdir);
1180    write_one_liner_data_file(tmp, nfs_client_ipaddr);
1181    sprintf(tmp, "%s/NFS-CLIENT-NETMASK", bkpinfo->tmpdir);
1182    write_one_liner_data_file(tmp, nfs_client_netmask);
1183    sprintf(tmp, "%s/NFS-CLIENT-BROADCAST", bkpinfo->tmpdir);
1184    write_one_liner_data_file(tmp, nfs_client_broadcast);
1185    sprintf(tmp, "%s/NFS-CLIENT-DEFGW", bkpinfo->tmpdir);
1186    write_one_liner_data_file(tmp, nfs_client_defgw);
1187    sprintf(tmp, "%s/NFS-SERVER-IPADDR", bkpinfo->tmpdir);
1188    write_one_liner_data_file(tmp, nfs_server_ipaddr);
1189    sprintf(tmp, "%s/NFS-SERVER-MOUNT", bkpinfo->tmpdir);
1190    write_one_liner_data_file(tmp, bkpinfo->nfs_mount);
1191    sprintf(tmp, "%s/NFS-SERVER-PATH", bkpinfo->tmpdir);
1192    write_one_liner_data_file(tmp, bkpinfo->nfs_remote_dir);
1193    sprintf(tmp, "%s/ISO-PREFIX", bkpinfo->tmpdir);
1194    write_one_liner_data_file(tmp, bkpinfo->prefix);
1195    log_it("Finished storing NFS configuration");
1196}
1197
1198
1199
1200
1201
1202
1203/**
1204 * Determine the approximate number of media that the backup will take up,
1205 * and tell the user. The uncompressed size is estimated as size_of_all_biggiefiles_K()
1206 * plus (noof_sets x bkpinfo->optimal_set_size). The compression factor is estimated as
1207 * 2/3 for LZO and 1/2 for bzip2. The data is not saved anywhere. If there are any
1208 * "imagedevs", the estimate is not shown as it will be wildly inaccurate.
1209 * If there are more than 50 media estimated, the estimate will not be shown.
1210 * @param bkpinfo The backup information structure. Fields used:
1211 * - @c bkpinfo->backup_media_type
1212 * - @c bkpinfo->image_devs
1213 * - @c bkpinfo->media_size
1214 * - @c bkpinfo->optimal_set_size
1215 * - @c bkpinfo->use_lzo
1216 * @param noof_sets The number of filesets created.
1217 * @ingroup archiveGroup
1218 */
1219void
1220estimate_noof_media_required(long noof_sets)
1221{
1222    /*@ buffers *************** */
1223    char tmp[MAX_STR_LEN];
1224    char *mds = NULL;
1225
1226    /*@ long long ************* */
1227    long long scratchLL;
1228
1229    if (bkpinfo->media_size[1] <= 0) {
1230        log_to_screen("Number of media required: UNKNOWN");
1231        return;
1232    }
1233
1234    log_it("Estimating number of media required...");
1235    scratchLL =
1236        (long long) (noof_sets) * (long long) (bkpinfo->optimal_set_size)
1237        + (long long) (size_of_all_biggiefiles_K());
1238    scratchLL = (scratchLL / 1024) / bkpinfo->media_size[1];
1239    scratchLL++;
1240    if (bkpinfo->use_lzo) {
1241        scratchLL = (scratchLL * 2) / 3;
1242    } else if (bkpinfo->use_gzip) {
1243        scratchLL = (scratchLL * 2) / 3;
1244    } else {
1245        scratchLL = scratchLL / 2;
1246    }
1247    if (!scratchLL) {
1248        scratchLL++;
1249    }
1250    if (scratchLL <= 1) {
1251        mds = media_descriptor_string(bkpinfo->backup_media_type);
1252        sprintf(tmp,
1253                "Your backup will probably occupy a single %s. Maybe two.", mds);
1254        mr_free(mds);
1255    } else if (scratchLL > 4) {
1256        sprintf(tmp,
1257                "Your backup will occupy one meeeeellion media! (maybe %s)",
1258                number_to_text((int) (scratchLL + 1)));
1259    } else {
1260        sprintf(tmp, "Your backup will occupy approximately %s media.",
1261                number_to_text((int) (scratchLL + 1)));
1262    }
1263    if (!bkpinfo->image_devs[0] && (scratchLL < 50)) {
1264        log_to_screen(tmp);
1265    }
1266}
1267
1268
1269/**
1270 * Get the last suffix of @p instr.
1271 * If @p instr was "httpd.log.gz", we would return "gz".
1272 * @param instr The filename to get the suffix of.
1273 * @return The suffix (without a dot), or "" if none.
1274 * @note The returned string points to static storage that will be overwritten with each call.
1275 */
1276char *sz_last_suffix(char *instr)
1277{
1278    static char outstr[MAX_STR_LEN];
1279    char *p;
1280
1281    p = strrchr(instr, '.');
1282    if (!p) {
1283        outstr[0] = '\0';
1284    } else {
1285        strcpy(outstr, p);
1286    }
1287    return (outstr);
1288}
1289
1290
1291/**
1292 * Determine whether a file is compressed. This is done
1293 * by reading through the "do-not-compress-these" file distributed with Mondo.
1294 * @param filename The file to check.
1295 * @return TRUE if it's compressed, FALSE if not.
1296 */
1297bool is_this_file_compressed(char *filename)
1298{
1299    char do_not_compress_these[MAX_STR_LEN];
1300    char tmp[MAX_STR_LEN];
1301    char *p;
1302    char *q = NULL;
1303
1304    q = strrchr(filename, '.');
1305    if (q == NULL) {
1306        return (FALSE);
1307    }
1308
1309    sprintf(tmp, "%s/do-not-compress-these", g_mondo_home);
1310    if (!does_file_exist(tmp)) {
1311        return (FALSE);
1312    }
1313    /* BERLIOS: This is just plain WRONG !! */
1314    strcpy(do_not_compress_these,last_line_of_file(tmp));
1315
1316    for (p = do_not_compress_these; p != NULL; p++) {
1317        strcpy(tmp, p);
1318        if (strchr(tmp, ' ')) {
1319            *(strchr(tmp, ' ')) = '\0';
1320        }
1321        if (!strcmp(q, tmp)) {
1322            return (TRUE);
1323        }
1324        if (!(p = strchr(p, ' '))) {
1325            break;
1326        }
1327    }
1328    return (FALSE);
1329}
1330
1331
1332
1333int mode_of_file(char *fname)
1334{
1335    struct stat buf;
1336
1337    if (lstat(fname, &buf)) {
1338        return (-1);
1339    }                           // error
1340    else {
1341        return (buf.st_mode);
1342    }
1343}
1344
1345
1346
1347
1348/**
1349 * Create a small script that mounts /boot, calls @c grub-install, and syncs the disks.
1350 * @param outfile Where to put the script.
1351 * @return 0 for success, 1 for failure.
1352 */
1353int make_grub_install_scriptlet(char *outfile)
1354{
1355    FILE *fout;
1356    char *tmp;
1357    int retval = 0;
1358
1359    malloc_string(tmp);
1360    if ((fout = fopen(outfile, "w"))) {
1361        fprintf(fout,
1362                "#!/bin/sh\n\nmount /boot > /dev/null 2> /dev/null\ngrub-install $@\nres=$?\nsync;sync;sync\nexit $res\n");
1363        paranoid_fclose(fout);
1364        log_msg(2, "Created %s", outfile);
1365        sprintf(tmp, "chmod +x %s", outfile);
1366        paranoid_system(tmp);
1367        retval = 0;
1368    } else {
1369        retval = 1;
1370    }
1371    paranoid_free(tmp);
1372    return (retval);
1373}
1374
1375/* @} - end fileGroup */
Note: See TracBrowser for help on using the repository browser.