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

Last change on this file since 196 was 196, checked in by bcornec, 14 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.