source: MondoRescue/branches/2.05/mondo/mondo/common/libmondo-files.c@ 196

Last change on this file since 196 was 196, checked in by bcornec, 18 years ago

Usage of parted2fdisk instead of fdisk everywhere.
on ia64 this is mandatory, and simplifies the infrastructure
on other archs, it doesn't change anything as parted2fdisk here is a link to fdisk

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