source: MondoRescue/branches/3.0/mondo/src/common/libmondo-files.c@ 3192

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