source: trunk/mondo/src/common/libmondo-archive.c @ 900

Last change on this file since 900 was 900, checked in by Bruno Cornec, 14 years ago

Huge patch to introduce low level functions that will bw used everywhere (mr_free, mr_asprintf, ...)
Nearly linking now due to that.

  • Property svn:keywords set to Id
File size: 108.2 KB
Line 
1/* $Id: libmondo-archive.c 900 2006-10-24 06:49:18Z bruno $
2
3subroutines to handle the archiving of files
4*/
5
6/**
7 * @file
8 * Functions to handle backing up data.
9 * This is the main file (at least the longest one) in libmondo.
10 */
11#include <sys/sem.h>
12#include <sys/types.h>
13#include <sys/ipc.h>
14#include <stdarg.h>
15#include <unistd.h>
16
17#include "my-stuff.h"
18#include "../common/mondostructures.h"
19#include "mr_conf.h"
20#include "mr_mem.h"
21#include "mr_err.h"
22
23#include "libmondo-string-EXT.h"
24#include "libmondo-stream-EXT.h"
25#include "libmondo-devices-EXT.h"
26#include "libmondo-tools-EXT.h"
27#include "newt-specific-EXT.h"
28#include "libmondo-fork-EXT.h"
29#include "libmondo-files-EXT.h"
30#include "libmondo-filelist-EXT.h"
31#include "libmondo-tools-EXT.h"
32#include "libmondo-verify-EXT.h"
33#include "libmondo-archive.h"
34#define DVDRWFORMAT 1
35
36
37
38/** @def DEFAULT_1722MB_DISK The default 1.722M floppy disk to write images to. */
39/** @def BACKUP_1722MB_DISK  The 1.722M floppy disk to try if the default fails. */
40
41#ifdef __FreeBSD__
42#define DEFAULT_1722MB_DISK "/dev/fd0.1722"
43#define BACKUP_1722MB_DISK "/dev/fd0.1722"
44#else
45#define DEFAULT_1722MB_DISK "/dev/fd0u1722"
46#define BACKUP_1722MB_DISK "/dev/fd0H1722"
47#ifndef _SEMUN_H
48#define _SEMUN_H
49
50    /**
51     * The semaphore union, provided only in case the user's system doesn't.
52     */
53union semun {
54    int val;
55    struct semid_ds *buf;
56    unsigned short int *array;
57    struct seminfo *__buf;
58};
59#endif
60#endif                          /* __FreeBSD__ */
61
62/*@unused@*/
63//static char cvsid[] = "$Id: libmondo-archive.c 900 2006-10-24 06:49:18Z bruno $";
64
65/* *************************** external global vars ******************/
66extern int g_current_media_number;
67extern int g_currentY;
68extern bool g_text_mode;
69extern bool g_exiting;
70extern long g_current_progress;
71extern FILE *g_tape_stream;
72extern long long g_tape_posK;
73extern char *g_mondo_home;
74extern char *g_tmpfs_mountpt;
75extern bool g_cd_recovery;
76extern char *g_serial_string;
77
78/**
79 * @addtogroup globalGroup
80 * @{
81 */
82/**
83 * The current backup media type in use.
84 */
85t_bkptype g_backup_media_type = none;
86char *g_backup_media_string = NULL;
87
88/**
89 * Incremented by each archival thread when it starts up. After that,
90 * this is the number of threads running.
91 */
92int g_current_thread_no = 0;
93
94/* @} - end of globalGroup */
95
96extern int g_noof_rows;
97
98/* Semaphore-related code */
99
100static int set_semvalue(void);
101static void del_semvalue(void);
102static int semaphore_p(void);
103static int semaphore_v(void);
104
105static int g_sem_id;
106static int g_sem_key;
107
108
109
110
111/**
112 * Initialize the semaphore.
113 * @see del_semvalue
114 * @see semaphore_p
115 * @see semaphore_v
116 * @return 1 for success, 0 for failure.
117 */
118static int set_semvalue(void)   // initializes semaphore
119{
120    union semun sem_union;
121    sem_union.val = 1;
122    if (semctl(g_sem_id, 0, SETVAL, sem_union) == -1) {
123        return (0);
124    }
125    return (1);
126}
127
128/**
129 * Frees (deletes) the semaphore. Failure is indicated by a log
130 * message.
131 * @see set_semvalue
132 */
133static void del_semvalue(void)  // deletes semaphore
134{
135    union semun sem_union;
136
137    if (semctl(g_sem_id, 0, IPC_RMID, sem_union) == -1) {
138        log_msg(3, "Failed to delete semaphore");
139    }
140}
141
142/**
143 * Acquire (increment) the semaphore (change status to P).
144 * @return 1 for success, 0 for failure.
145 * @see semaphore_v
146 */
147static int semaphore_p(void)    // changes status to 'P' (waiting)
148{
149    struct sembuf sem_b;
150
151    sem_b.sem_num = 0;
152    sem_b.sem_op = -1;          // P()
153    sem_b.sem_flg = SEM_UNDO;
154    if (semop(g_sem_id, &sem_b, 1) == -1) {
155        log_msg(3, "semaphore_p failed");
156        return (0);
157    }
158    return (1);
159}
160
161/**
162 * Free (decrement) the semaphore (change status to V).
163 * @return 1 for success, 0 for failure.
164 */
165static int semaphore_v(void)    // changes status to 'V' (free)
166{
167    struct sembuf sem_b;
168
169    sem_b.sem_num = 0;
170    sem_b.sem_op = 1;           // V()
171    sem_b.sem_flg = SEM_UNDO;
172    if (semop(g_sem_id, &sem_b, 1) == -1) {
173        log_msg(3, "semaphore_v failed");
174        return (0);
175    }
176    return (1);
177}
178
179
180//------------------------------------------------------
181
182
183/**
184 * Size in megabytes of the buffer afforded to the executable "buffer".
185 * This figure is used when we calculate how much data we have probably 'lost'
186 * when writing off the end of tape N, so that we can then figure out how much
187 * data we must recreate & write to the start of tape N+1.
188 */
189extern int g_tape_buffer_size_MB;
190
191
192
193
194int
195archive_this_fileset_with_star(struct s_bkpinfo *bkpinfo, char *filelist,
196                               char *fname, int setno)
197{
198    int retval = 0;
199    unsigned int res = 0;
200    int tries = 0;
201    char *command;
202    char *tmp;
203    char *p;
204
205    if (!does_file_exist(filelist)) {
206        mr_asprintf(&tmp,
207                 "(archive_this_fileset) - filelist %s does not exist",
208                 filelist);
209        log_to_screen(tmp);
210        mr_free(tmp);
211        return (1);
212    }
213
214    mr_asprintf(&tmp, "echo hi > %s 2> /dev/null", fname);
215    if (system(tmp)) {
216        fatal_error("Unable to write tarball to scratchdir");
217    }
218    mr_free(tmp);
219
220    mr_asprintf(&command, "star H=star list=%s -c " STAR_ACL_SZ " file=%s",
221             filelist, fname);
222    if (bkpinfo->use_lzo) {
223        fatal_error("Can't use lzop");
224    }
225    if (bkpinfo->compression_level > 0) {
226        mr_asprintf(&tmp, "%s -bz", command);
227        mr_free(command);
228        command = tmp;
229    }
230    mr_asprintf(&tmp, "%s 2>> %s", command, MONDO_LOGFILE);
231    mr_free(command);
232    command = tmp;
233    log_msg(4, "command = '%s'", command);
234
235    for (res = 99, tries = 0; tries < 3 && res != 0; tries++) {
236        log_msg(5, "command='%s'", command);
237        res = system(command);
238        tmp = last_line_of_file(MONDO_LOGFILE);
239        log_msg(1, "res=%d; tmp='%s'", res, tmp);
240        if (bkpinfo->use_star && (res == 254 || res == 65024)
241            && strstr(tmp, "star: Processed all possible files")
242            && tries > 0) {
243            log_msg(1, "Star returned nonfatal error");
244            res = 0;
245        }
246        mr_free(tmp);
247        if (res) {
248            log_OS_error(command);
249            p = strstr(command, "-acl ");
250            if (p) {
251                p[0] = p[1] = p[2] = p[3] = ' ';
252                log_msg(1, "new command = '%s'", command);
253            } else {
254                log_msg(3,
255                        "Attempt #%d failed. Pausing 3 seconds and retrying...",
256                        tries + 1);
257                sleep(3);
258            }
259        }
260    }
261    mr_free(command);
262
263    retval += res;
264    if (retval) {
265        log_msg(3, "Failed to write set %d", setno);
266    } else if (tries > 1) {
267        log_msg(3, "Succeeded in writing set %d, on try #%d", setno,
268                tries);
269    }
270
271    return (retval);
272}
273
274
275/**
276 * Call @c afio to archive the filelist @c filelist to the file @c fname.
277 *
278 * @param bkpinfo The backup information structure. Fields used:
279 * - @c compression_level
280 * - @c scratchdir (only verifies existence)
281 * - @c tmpdir (only verifies existence)
282 * - @c zip_exe
283 * - @c zip_suffix
284 * @param filelist The path to a file containing a list of files to be archived
285 * in this fileset.
286 * @param fname The output file to archive to.
287 * @param setno This fileset number.
288 * @return The number of errors encountered (0 for success).
289 * @ingroup LLarchiveGroup
290 */
291int
292archive_this_fileset(struct s_bkpinfo *bkpinfo, char *filelist,
293                     char *fname, int setno)
294{
295
296    /*@ int ************************************************************ */
297    int retval = 0;
298    int res = 0;
299    int i = 0;
300    int tries = 0;
301    static int free_ramdisk_space = 9999;
302
303    /*@ buffers ******************************************************** */
304    char *command = NULL;
305    char *zipparams = NULL;
306    char *tmp = NULL;
307    char *tmp1 = NULL;
308
309    assert(bkpinfo != NULL);
310    assert_string_is_neither_NULL_nor_zerolength(filelist);
311    assert_string_is_neither_NULL_nor_zerolength(fname);
312
313    if (bkpinfo->compression_level > 0 && bkpinfo->use_star) {
314        return (archive_this_fileset_with_star
315                (bkpinfo, filelist, fname, setno));
316    }
317
318    if (!does_file_exist(filelist)) {
319        mr_asprintf(&tmp,
320                 "(archive_this_fileset) - filelist %s does not exist",
321                 filelist);
322        log_to_screen(tmp);
323        mr_free(tmp);
324            return (1);
325    }
326    mr_asprintf(&tmp, "echo hi > %s 2> /dev/null", fname);
327    if (system(tmp)) {
328        fatal_error("Unable to write tarball to scratchdir");
329    }
330    mr_free(tmp);
331
332
333    if (bkpinfo->compression_level > 0) {
334        mr_asprintf(&tmp, "%s/do-not-compress-these", g_mondo_home);
335        //       -b %ld, TAPE_BLOCK_SIZE
336        mr_asprintf(&zipparams, "-Z -P %s -G %d -T 3k", bkpinfo->zip_exe,
337                 bkpinfo->compression_level);
338        if (does_file_exist(tmp)) {
339            mr_asprintf(&tmp1, "%s -E %s", zipparams, tmp);
340            mr_free(zipparams);
341            zipparams = tmp1;
342        } else {
343            mr_asprintf(&zipparams, " ");
344            log_msg(3, "%s not found. Cannot exclude zipfiles, etc.", tmp);
345        }
346        mr_free(tmp);
347    } else {
348        mr_asprintf(&zipparams, " ");
349    }
350
351//  make_hole_for_file(fname);
352
353    if (!does_file_exist(bkpinfo->tmpdir)) {
354        log_OS_error("tmpdir not found");
355        fatal_error("tmpdir not found");
356    }
357    if (!does_file_exist(bkpinfo->scratchdir)) {
358        log_OS_error("scratchdir not found");
359        fatal_error("scratchdir not found");
360    }
361    mr_asprintf(&command, "rm -f %s %s. %s.gz %s.%s", fname, fname, fname,
362             fname, bkpinfo->zip_suffix);
363    paranoid_system(command);
364    mr_free(command);
365
366    mr_asprintf(&command, "afio -o -b %ld -M 16m %s %s < %s 2>> %s",
367             TAPE_BLOCK_SIZE, zipparams, fname, filelist, MONDO_LOGFILE);
368    mr_free(zipparams);
369
370    mr_asprintf(&tmp, "echo hi > %s 2> /dev/null", fname);
371    if (system(tmp)) {
372        fatal_error("Unable to write tarball to scratchdir");
373    }
374    mr_free(tmp);
375
376    for (res = 99, tries = 0; tries < 3 && res != 0; tries++) {
377        log_msg(5, "command='%s'", command);
378        res = system(command);
379        if (res) {
380            log_OS_error(command);
381            log_msg(3,
382                    "Attempt #%d failed. Pausing 3 seconds and retrying...",
383                    tries + 1);
384            sleep(3);
385        }
386    }
387    mr_free(command);
388
389    retval += res;
390    if (retval) {
391        log_msg(3, "Failed to write set %d", setno);
392    } else if (tries > 1) {
393        log_msg(3, "Succeeded in writing set %d, on try #%d", setno,
394                tries);
395    }
396
397    if (g_tmpfs_mountpt != NULL) {
398        tmp = call_program_and_get_last_line_of_output
399                 ("df -m -P | grep dev/shm | grep -v none | tr -s ' ' '\t' | cut -f4");
400        i = atoi(tmp);
401        mr_free(tmp);
402
403        if (i > 0) {
404            if (free_ramdisk_space > i) {
405                free_ramdisk_space = i;
406                log_msg(2, "min(free_ramdisk_space) is now %d",
407                        free_ramdisk_space);
408                if (free_ramdisk_space < 10) {
409                    fatal_error
410                        ("Please increase PPCFG_RAMDISK_SIZE in my-stuff.h to increase size of ramdisk ");
411                }
412            }
413        }
414    }
415    return (retval);
416}
417
418
419/**
420 * Wrapper function for all the backup commands.
421 * Calls these other functions: @c prepare_filelist(),
422 * @c call_filelist_chopper(), @c copy_mondo_and_mindi_stuff_to_scratchdir(),
423 * @c call_mindi_to_supply_boot_disks(), @c do_that_initial_phase(),
424 * @c make_those_afios_phase(), @c make_those_slices_phase(), and
425 * @c do_that_final_phase(). If anything fails before @c do_that_initial_phase(),
426 * @c fatal_error is called with a suitable message.
427 * @param bkpinfo The backup information structure. Uses most fields.
428 * @return The number of non-fatal errors encountered (0 for success).
429 * @ingroup archiveGroup
430 */
431int backup_data(struct s_bkpinfo *bkpinfo)
432{
433    int retval = 0, res = 0;
434    char *tmp;
435
436    assert(bkpinfo != NULL);
437    set_g_cdrom_and_g_dvd_to_bkpinfo_value(bkpinfo);
438    if (bkpinfo->backup_media_type == dvd) {
439#ifdef DVDRWFORMAT
440        tmp = find_home_of_exe("dvd+rw-format");
441        if (!tmp) {
442            fatal_error
443                ("Cannot find dvd+rw-format. Please install it or fix your PATH.");
444        }
445        mr_free(tmp);
446#endif
447        tmp = find_home_of_exe("growisofs");
448        if (!tmp) {
449            fatal_error
450                ("Cannot find growisofs. Please install it or fix your PATH.");
451        }
452        mr_free(tmp);
453    }
454
455    if ((res = prepare_filelist(bkpinfo))) {    /* generate scratchdir/filelist.full */
456        fatal_error("Failed to generate filelist catalog");
457    }
458    if (call_filelist_chopper(bkpinfo)) {
459        fatal_error("Failed to run filelist chopper");
460    }
461
462/*
463      mr_asprintf(&tmp, "wc -l %s/archives/filelist.full > %s/archives/filelist.count",bkpinfo->scratchdir, bkpinfo->scratchdir);
464      if (run_program_and_log_output(tmp, 2))
465        { fatal_error("Failed to count filelist.full"); }
466*/
467    mr_asprintf(&tmp, "gzip -9 %s/archives/filelist.full",
468             bkpinfo->scratchdir);
469    if (run_program_and_log_output(tmp, 2)) {
470        fatal_error("Failed to gzip filelist.full");
471    }
472    mr_free(tmp);
473    mr_asprintf(&tmp, "cp -f %s/archives/*list*.gz %s", bkpinfo->scratchdir,
474             bkpinfo->tmpdir);
475    if (run_program_and_log_output(tmp, 2)) {
476        fatal_error("Failed to copy to tmpdir");
477    }
478    mr_free(tmp);
479
480    copy_mondo_and_mindi_stuff_to_scratchdir(bkpinfo);  // payload, too, if it exists
481#if __FreeBSD__ == 5
482    mr_allocstr(bkpinfo->kernel_path, "/boot/kernel/kernel");
483#elif __FreeBSD__ == 4
484    mr_allocstr(bkpinfo->kernel_path, "/kernel");
485#elif linux
486    if (figure_out_kernel_path_interactively_if_necessary
487        (bkpinfo->kernel_path)) {
488        fatal_error
489            ("Kernel not found. Please specify manually with the '-k' switch.");
490    }
491#else
492#error "I don't know about this system!"
493#endif
494    if ((res = call_mindi_to_supply_boot_disks(bkpinfo))) {
495        fatal_error("Failed to generate boot+data disks");
496    }
497    retval += do_that_initial_phase(bkpinfo);   // prepare
498    mr_asprintf(&tmp, "rm -f %s/images/*.iso", bkpinfo->scratchdir);
499    run_program_and_log_output(tmp, 1);
500    mr_free(tmp);
501    retval += make_those_slices_phase(bkpinfo); // backup BIG files
502    retval += do_that_final_phase(bkpinfo); // clean up
503    log_msg(1, "Creation of archives... complete.");
504    if (bkpinfo->verify_data) {
505        sleep(2);
506    }
507    return (retval);
508}
509
510
511/**
512 * Call Mindi to generate boot and data disks.
513 * @note This binds correctly to the new Perl version of mindi.
514 * @param bkpinfo The backup information structure. Fields used:
515 * - @c backup_media_type
516 * - @c boot_loader
517 * - @c boot_device
518 * - @c compression_level
519 * - @c differential
520 * - @c exclude_paths
521 * - @c image_devs
522 * - @c kernel_path
523 * - @c make_cd_use_lilo
524 * - @c media_device
525 * - @c media_size
526 * - @c nonbootable_backup
527 * - @c tmpdir
528 * - @c use_lzo
529 *
530 * @return The number of errors encountered (0 for success)
531 * @bug The code to automagically determine the boot drive
532 * is messy and system-dependent. In particular, it breaks
533 * for Linux RAID and LVM users.
534 * @ingroup MLarchiveGroup
535 */
536int call_mindi_to_supply_boot_disks(struct s_bkpinfo *bkpinfo)
537{
538    /*@ buffer ************************************************************ */
539    char *tmp = NULL;
540    char *command = NULL;
541    char *use_lzo_sz = NULL;
542    char *use_comp_sz = NULL;
543    char *use_star_sz = NULL;
544    char *bootldr_str = NULL;
545    char *tape_device = NULL;
546    char *last_filelist_number = NULL;
547    char *broken_bios_sz = NULL;
548    char *cd_recovery_sz = NULL;
549    char *tape_size_sz = NULL;
550    char *devs_to_exclude = NULL;
551    char *use_lilo_sz = NULL;
552    char *value = NULL;
553    char *bootdev = NULL;
554
555
556
557    /*@ char ************************************************************** */
558    char ch = '\0';
559
560    /*@ long     ********************************************************** */
561    long lines_in_filelist = 0;
562
563    /*@ int         ************************************************************* */
564    int res = 0;
565    long estimated_total_noof_slices = 0;
566
567    assert(bkpinfo != NULL);
568
569    mr_asprintf(&tmp,
570             "echo '%s' | tr -s ' ' '\n' | grep -x '/dev/.*' | tr -s '\n' ' ' | awk '{print $0\"\\n\";}'",
571             bkpinfo->exclude_paths);
572    devs_to_exclude = call_program_and_get_last_line_of_output(tmp);
573    mr_free(tmp);
574    mr_asprintf(&tmp, "devs_to_exclude = '%s'", devs_to_exclude);
575    log_msg(2, tmp);
576    mr_free(tmp);
577    mvaddstr_and_log_it(g_currentY, 0,
578                        "Calling MINDI to create boot+data disks");
579    mr_asprintf(&tmp, "%s/filelist.full", bkpinfo->tmpdir);
580    if (!does_file_exist(tmp)) {
581        mr_free(tmp);
582        mr_asprintf(&tmp, "%s/tmpfs/filelist.full", bkpinfo->tmpdir);
583        if (!does_file_exist(tmp)) {
584            fatal_error
585                ("Cannot find filelist.full, so I cannot count its lines");
586        }
587    }
588    lines_in_filelist = count_lines_in_file(tmp);
589    mr_free(tmp);
590    mr_asprintf(&tmp, "%s/LAST-FILELIST-NUMBER", bkpinfo->tmpdir);
591    last_filelist_number = last_line_of_file(tmp);
592    mr_free(tmp);
593    if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
594        mr_asprintf(&tape_size_sz, "%ld", bkpinfo->media_size[1]);
595        mr_asprintf(&tape_device, bkpinfo->media_device);
596    } else {
597        mr_asprintf(&tape_size_sz, " ");
598        mr_asprintf(&tape_device, " ");
599    }
600    if (bkpinfo->use_lzo) {
601        mr_asprintf(&use_lzo_sz, "yes");
602    } else {
603        mr_asprintf(&use_lzo_sz, "no");
604    }
605    if (bkpinfo->use_star) {
606        mr_asprintf(&use_star_sz, "yes");
607    } else {
608        mr_asprintf(&use_star_sz, "no");
609    }
610
611    if (bkpinfo->compression_level > 0) {
612        mr_asprintf(&use_comp_sz, "yes");
613    } else {
614        mr_asprintf(&use_comp_sz, "no");
615    }
616
617    mr_asprintf(&broken_bios_sz, "yes");    /* assume so */
618    if (g_cd_recovery) {
619        mr_asprintf(&cd_recovery_sz, "yes");
620    } else {
621        mr_asprintf(&cd_recovery_sz, "no");
622    }
623    /* Field shared between LILO/ELILO */
624    if (bkpinfo->make_cd_use_lilo) {
625        mr_asprintf(&use_lilo_sz, "yes");
626    } else {
627        mr_asprintf(&use_lilo_sz, "no");
628    }
629
630    if (!bkpinfo->nonbootable_backup
631        && (bkpinfo->boot_loader == '\0'
632            || bkpinfo->boot_device == NULL)) {
633
634#ifdef __FreeBSD__
635        bootdev = call_program_and_get_last_line_of_output
636                 ("mount | grep ' /boot ' | head -1 | cut -d' ' -f1 | sed 's/\\([0-9]\\).*/\\1/'");
637        if (!bootdev) {
638            bootdev = call_program_and_get_last_line_of_output
639                     ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/\\([0-9]\\).*/\\1/'");
640        }
641#else
642        bootdev = call_program_and_get_last_line_of_output
643                 ("mount | grep ' /boot ' | head -1 | cut -d' ' -f1 | sed 's/[0-9].*//'");
644        if (!bootdev) {
645            bootdev = call_program_and_get_last_line_of_output
646                     ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/[0-9].*//'");
647        }
648        if ((bootdev) && (strstr(bootdev, "/dev/cciss/"))) {
649            mr_free(bootdev);
650            bootdev = call_program_and_get_last_line_of_output
651                     ("mount | grep ' /boot ' | head -1 | cut -d' ' -f1 | cut -dp -f1");
652        }
653#endif
654        if (bootdev)
655            ch = which_boot_loader(bootdev);
656        else
657            ch = 'U';
658
659        if (bkpinfo->boot_loader != '\0') {
660            mr_asprintf(&tmp, "User specified boot loader. It is '%c'.",
661                     bkpinfo->boot_loader);
662            log_msg(2, tmp);
663            mr_free(tmp);
664        } else {
665            bkpinfo->boot_loader = ch;
666        }
667        if (bkpinfo->boot_device != NULL) {
668            mr_asprintf(&tmp, "User specified boot device. It is '%s'.",
669                     bkpinfo->boot_device);
670            log_msg(2, tmp);
671            mr_free(tmp);
672            mr_free(bootdev);
673        } else {
674            bkpinfo->boot_device = bootdev;
675        }
676    }
677
678    if (
679#ifdef __FreeBSD__
680           bkpinfo->boot_loader != 'B' && bkpinfo->boot_loader != 'D' &&
681#endif
682#ifdef __IA64__
683           bkpinfo->boot_loader != 'E' &&
684#endif
685           bkpinfo->boot_loader != 'L' && bkpinfo->boot_loader != 'G'
686           && bkpinfo->boot_loader != 'R' && !bkpinfo->nonbootable_backup)
687    {
688        fatal_error
689            ("Please specify your boot loader and device, e.g. -l GRUB -f /dev/hda.\nType 'man mondoarchive' to read the manual.");
690    }
691    if (bkpinfo->boot_loader == 'L') {
692        mr_asprintf(&bootldr_str, "LILO");
693        if (!does_file_exist("/etc/lilo.conf")) {
694            fatal_error
695                ("The de facto standard location for your boot loader's config file is /etc/lilo.conf.\nBut I cannot find it there. What is wrong with your Linux distribution?");
696        }
697    } else if (bkpinfo->boot_loader == 'G') {
698        mr_asprintf(&bootldr_str, "GRUB");
699        if (!does_file_exist("/etc/grub.conf")
700            && does_file_exist("/boot/grub/grub.conf")) {
701            run_program_and_log_output
702                ("ln -sf /boot/grub/grub.conf /etc/grub.conf", 5);
703        }
704        /* Detect Debian's grub config file */
705        else if (!does_file_exist("/etc/grub.conf")
706                 && does_file_exist("/boot/grub/menu.lst")) {
707            run_program_and_log_output
708                ("ln -s /boot/grub/menu.lst /etc/grub.conf", 5);
709        }
710        if (!does_file_exist("/etc/grub.conf")) {
711            fatal_error
712                ("The de facto standard location for your boot loader's config file is /etc/grub.conf.\nBut I cannot find it there. What is wrong with your Linux distribution?\nTry 'ln -s /boot/grub/menu.lst /etc/grub.conf'...");
713        }
714    } else if (bkpinfo->boot_loader == 'E') {
715        mr_asprintf(&bootldr_str, "ELILO");
716        /* BERLIOS: fix it for SuSE, Debian, Mandrake, ... */
717        if (!does_file_exist("/etc/elilo.conf")
718            && does_file_exist("/boot/efi/efi/redhat/elilo.conf")) {
719            run_program_and_log_output
720                ("ln -sf /boot/efi/efi/redhat/elilo.conf /etc/elilo.conf",
721                 5);
722        }
723        if (!does_file_exist("/etc/elilo.conf")) {
724            fatal_error
725                ("The de facto mondo standard location for your boot loader's config file is /etc/elilo.conf\nBut I cannot find it there. What is wrong with your Linux distribution?\nTry finding it under /boot/efi and do 'ln -s /boot/efi/..../elilo.conf /etc/elilo.conf'");
726        }
727    } else if (bkpinfo->boot_loader == 'R') {
728        mr_asprintf(&bootldr_str, "RAW");
729    }
730#ifdef __FreeBSD__
731    else if (bkpinfo->boot_loader == 'D') {
732        mr_asprintf(&bootldr_str, "DD");
733    }
734
735    else if (bkpinfo->boot_loader == 'B') {
736        mr_asprintf(&bootldr_str, "BOOT0");
737    }
738#endif
739    else {
740        mr_asprintf(&bootldr_str, "unknown");
741    }
742    mr_asprintf(&tmp, "Your boot loader is %s and it boots from %s",
743             bootldr_str, bkpinfo->boot_device);
744    log_to_screen(tmp);
745    mr_free(tmp);
746    mr_asprintf(&tmp, "%s/BOOTLOADER.DEVICE", bkpinfo->tmpdir);
747    if (write_one_liner_data_file(tmp, bkpinfo->boot_device)) {
748        log_msg(1, "%ld: Unable to write one-liner boot device", __LINE__);
749    }
750    mr_free(tmp);
751    /* BERLIOS: Use bkptype_to_string without LANG */
752    switch (bkpinfo->backup_media_type) {
753    case cdr:
754        mr_asprintf(&value, "cdr");
755        break;
756    case cdrw:
757        mr_asprintf(&value, "cdrw");
758        break;
759    case cdstream:
760        mr_asprintf(&value, "cdstream");
761        break;
762    case tape:
763        mr_asprintf(&value, "tape");
764        break;
765    case udev:
766        mr_asprintf(&value, "udev");
767        break;
768    case iso:
769        mr_asprintf(&value, "iso");
770        break;
771    case nfs:
772        mr_asprintf(&value, "nfs");
773        break;
774    case dvd:
775        mr_asprintf(&value, "dvd");
776        break;
777    default:
778        fatal_error("Unknown backup_media_type");
779    }
780    mr_asprintf(&tmp, "%s/BACKUP-MEDIA-TYPE", bkpinfo->tmpdir);
781    if (write_one_liner_data_file(tmp, value)) {
782        res++;
783        log_msg(1, "%ld: Unable to write one-liner backup-media-type",
784                __LINE__);
785    }
786    mr_free(value);
787    mr_free(tmp);
788    log_to_screen(bkpinfo->tmpdir);
789    mr_asprintf(&tmp, "%s/BOOTLOADER.NAME", bkpinfo->tmpdir);
790    if (write_one_liner_data_file(tmp, bootldr_str)) {
791        res++;
792        log_msg(1, "%ld: Unable to write one-liner bootloader.name",
793                __LINE__);
794    }
795    mr_free(bootldr_str);
796    mr_free(tmp);
797    mr_asprintf(&tmp, "%s/DIFFERENTIAL", bkpinfo->tmpdir);
798    if (bkpinfo->differential) {
799        res += write_one_liner_data_file(tmp, "1");
800    } else {
801        res += write_one_liner_data_file(tmp, "0");
802    }
803    mr_free(tmp);
804
805    estimated_total_noof_slices =
806        size_of_all_biggiefiles_K(bkpinfo) / bkpinfo->optimal_set_size + 1;
807    mr_asprintf(&command, "mkdir -p %s/images", bkpinfo->scratchdir);
808    if (system(command)) {
809        res++;
810        log_OS_error("Unable to make images directory");
811    }
812    mr_free(command);
813
814    mr_asprintf(&command, "mkdir -p %s%s", bkpinfo->scratchdir, MNT_FLOPPY);
815    if (system(command)) {
816        res++;
817        log_OS_error("Unable to make mnt floppy directory");
818    }
819    mr_free(command);
820
821    mr_asprintf(&tmp, "BTW, I'm telling Mindi your kernel is '%s'",
822             bkpinfo->kernel_path);
823    log_to_screen(tmp);
824    mr_free(tmp);
825
826    log_msg(1, "lines_in_filelist = %ld", lines_in_filelist);
827
828    // Watch it! This next line adds a parameter...
829    if (bkpinfo->nonbootable_backup) {
830        mr_asprintf(&tmp, " NONBOOTABLE");
831    } else {
832        mr_asprintf(&tmp, " ");
833    }
834
835    mr_asprintf(&command,
836/*     "mindi --custom 2=%s 3=%s/images 4=\"%s\" 5=\"%s\" \
8376=\"%s\" 7=%ld 8=\"%s\" 9=\"%s\" 10=\"%s\" \
83811=\"%s\" 12=%s 13=%ld 14=\"%s\" 15=\"%s\" 16=\"%s\" 17=\"%s\" 18=%ld 19=%d",*/
839             "mindi --custom %s %s/images '%s' '%s' \
840'%s' %ld '%s' '%s' '%s' \
841'%s' %s %ld '%s' '%s' '%s' '%s' %ld %d %s", bkpinfo->tmpdir,    // parameter #2
842             bkpinfo->scratchdir,   // parameter #3
843             bkpinfo->kernel_path,  // parameter #4
844             tape_device,       // parameter #5
845             tape_size_sz,      // parameter #6
846             lines_in_filelist, // parameter #7 (INT)
847             use_lzo_sz,        // parameter #8
848             cd_recovery_sz,    // parameter #9
849             bkpinfo->image_devs,   // parameter #10
850             broken_bios_sz,    // parameter #11
851             last_filelist_number,  // parameter #12 (STRING)
852             estimated_total_noof_slices,   // parameter #13 (INT)
853             devs_to_exclude,   // parameter #14
854             use_comp_sz,       // parameter #15
855             use_lilo_sz,       // parameter #16
856             use_star_sz,       // parameter #17
857             bkpinfo->internal_tape_block_size, // parameter #18 (LONG)
858             bkpinfo->differential, // parameter #19 (INT)
859             tmp);
860    mr_free(tmp);
861    mr_free(tape_size_sz);
862    mr_free(use_lzo_sz);
863    mr_free(tape_device);
864    mr_free(use_star_sz);
865    mr_free(use_comp_sz);
866    mr_free(broken_bios_sz);
867    mr_free(cd_recovery_sz);
868    mr_free(last_filelist_number);
869    mr_free(devs_to_exclude);
870    mr_free(use_lilo_sz);
871
872    log_msg(2, command);
873
874    //  popup_and_OK("Pausing");
875    res = run_program_and_log_to_screen(command,
876                                        "Generating boot+data disks");
877    mr_free(command);
878
879    if (bkpinfo->nonbootable_backup) {
880        res = 0;
881    }                           // hack
882    if (!res) {
883        log_to_screen("Boot+data disks were created OK");
884        mr_asprintf(&command, "mkdir -p /var/cache/mindi/");
885        log_msg(2, command);
886        run_program_and_log_output(command, FALSE);
887        mr_free(command);
888
889        mr_asprintf(&command,
890                 "cp -f %s/images/mindi.iso /var/cache/mindi/mondorescue.iso",
891                 bkpinfo->scratchdir);
892        log_msg(2, command);
893        run_program_and_log_output(command, FALSE);
894        mr_free(command);
895
896        if (bkpinfo->nonbootable_backup) {
897            mr_asprintf(&command, "cp -f %s/all.tar.gz %s/images",
898                     bkpinfo->tmpdir, bkpinfo->scratchdir);
899            if (system(command)) {
900                fatal_error("Unable to create temporary duff tarball");
901                mr_free(command);
902            }
903        }
904        mr_asprintf(&command, "cp -f %s/mindi-*oot*.img %s/images",
905                 bkpinfo->tmpdir, bkpinfo->scratchdir);
906        log_msg(2, command);
907        run_program_and_log_output(command, FALSE);
908        mr_free(command);
909
910        mr_asprintf(&tmp, "cp -f %s/images/all.tar.gz %s",
911                 bkpinfo->scratchdir, bkpinfo->tmpdir);
912        if (system(tmp)) {
913            fatal_error("Cannot find all.tar.gz in tmpdir");
914        }
915        mr_free(tmp);
916
917        if (res) {
918            mvaddstr_and_log_it(g_currentY++, 74, "Errors.");
919        } else {
920            mvaddstr_and_log_it(g_currentY++, 74, "Done.");
921        }
922    } else {
923        log_to_screen("Mindi failed to create your boot+data disks.");
924        mr_asprintf(&command, "grep 'Fatal error' /var/log/mindi.log");
925        tmp = call_program_and_get_last_line_of_output(command);
926        mr_free(command);
927        if (strlen(tmp) > 1) {
928            popup_and_OK(tmp);
929        }
930        mr_free(tmp);
931    }
932    return (res);
933}
934
935
936/**
937 * Maximum number of filesets allowed in this function.
938 */
939#define MAX_NOOF_SETS_HERE 32767
940
941/**
942 * Offset of the bkpinfo pointer (in bytes) from the
943 * buffer passed to create_afio_files_in_background.
944 */
945#define BKPINFO_LOC_OFFSET (16+MAX_NOOF_SETS_HERE/8+16)
946
947/**
948 * Main function for each @c afio thread.
949 * @param inbuf A transfer block containing:
950 * - @c p_last_set_archived: [offset 0] pointer to an @c int
951 *   containing the last set archived.
952 * - @c p_archival_threads_running: [offset 4] pointer to an @c int
953 *   containing the number of archival threads currently running.
954 * - @c p_next_set_to_archive: [offset 8] pointer to an @c int containing
955 *   the next set that should be archived.
956 * - @c p_list_of_fileset_flags: [offset 12] @c char pointer pointing to a
957 *   bit array, where each bit corresponds to a filelist (1=needs
958 *   to be archived, 0=archived).
959 * - @c bkpinfo: [offset BKPINFO_LOC_OFFSET] pointer to backup information
960 *   structure. Fields used:
961 *   - @c tmpdir
962 *   - @c zip_suffix
963 *
964 * Any of the above may be modified by the caller at any time.
965 *
966 * @bug Assumes @c int pointers are 4 bytes.
967 * @see archive_this_fileset
968 * @see make_afioballs_and_images
969 * @return NULL, always.
970 * @ingroup LLarchiveGroup
971 */
972void *create_afio_files_in_background(void *inbuf)
973{
974    long int archiving_set_no;
975    char *archiving_filelist_fname;
976    char *archiving_afioball_fname;
977    char *curr_xattr_list_fname;
978    char *curr_acl_list_fname;
979
980    struct s_bkpinfo *bkpinfo;
981    char *tmp;
982    int res = 0, retval = 0;
983    int *p_archival_threads_running;
984    int *p_last_set_archived;
985    int *p_next_set_to_archive;
986    char *p_list_of_fileset_flags;
987    int this_thread_no = g_current_thread_no++;
988
989    p_last_set_archived = (int *) inbuf;
990    p_archival_threads_running = (int *) (inbuf + 4);
991    p_next_set_to_archive = (int *) (inbuf + 8);
992    p_list_of_fileset_flags = (char *) (inbuf + 12);
993    bkpinfo = (struct s_bkpinfo *) (inbuf + BKPINFO_LOC_OFFSET);
994
995    mr_asprintf(&archiving_filelist_fname, FILELIST_FNAME_RAW_SZ,
996             bkpinfo->tmpdir, 0L);
997    archiving_set_no = 0;
998    while (does_file_exist(archiving_filelist_fname)) {
999        mr_free(archiving_filelist_fname);
1000        if (g_exiting) {
1001            fatal_error("Execution run aborted (pthread)");
1002        }
1003        if (archiving_set_no >= MAX_NOOF_SETS_HERE) {
1004            fatal_error
1005                ("Maximum number of filesets exceeded. Adjust MAX_NOOF_SETS_HERE, please.");
1006        }
1007        if (!semaphore_p()) {
1008            log_msg(3, "P sem failed (pid=%d)", (int) getpid());
1009            fatal_error("Cannot get semaphore P");
1010        }
1011        if (archiving_set_no < *p_next_set_to_archive) {
1012            archiving_set_no = *p_next_set_to_archive;
1013        }
1014        *p_next_set_to_archive = *p_next_set_to_archive + 1;
1015        if (!semaphore_v()) {
1016            fatal_error("Cannot get semaphore V");
1017        }
1018
1019        /* backup this set of files */
1020        mr_asprintf(&archiving_afioball_fname, AFIOBALL_FNAME_RAW_SZ,
1021                 bkpinfo->tmpdir, archiving_set_no, bkpinfo->zip_suffix);
1022        mr_asprintf(&archiving_filelist_fname, FILELIST_FNAME_RAW_SZ,
1023                 bkpinfo->tmpdir, archiving_set_no);
1024        if (!does_file_exist(archiving_filelist_fname)) {
1025            log_msg(3,
1026                    "%s[%d:%d] - well, I would archive %d, except that it doesn't exist. I'll stop now.",
1027                    FORTY_SPACES, getpid(), this_thread_no,
1028                    archiving_set_no);
1029            mr_free(archiving_filelist_fname);
1030            mr_free(archiving_afioball_fname);
1031            break;
1032        }
1033
1034        mr_asprintf(&tmp, AFIOBALL_FNAME_RAW_SZ, bkpinfo->tmpdir,
1035                 archiving_set_no - ARCH_BUFFER_NUM, bkpinfo->zip_suffix);
1036        if (does_file_exist(tmp)) {
1037            log_msg(4, "%s[%d:%d] - waiting for storer",
1038                    FORTY_SPACES, getpid(), this_thread_no);
1039            while (does_file_exist(tmp)) {
1040                sleep(1);
1041            }
1042            log_msg(4, "[%d] - continuing", getpid());
1043        }
1044        mr_free(tmp);
1045
1046        log_msg(4, "%s[%d:%d] - EXATing %d...", FORTY_SPACES, getpid(),
1047                this_thread_no, archiving_set_no);
1048        mr_asprintf(&curr_xattr_list_fname, XATTR_LIST_FNAME_RAW_SZ,
1049                 bkpinfo->tmpdir, archiving_set_no);
1050        mr_asprintf(&curr_acl_list_fname, ACL_LIST_FNAME_RAW_SZ,
1051                 bkpinfo->tmpdir, archiving_set_no);
1052        get_fattr_list(archiving_filelist_fname, curr_xattr_list_fname);
1053        mr_free(curr_xattr_list_fname);
1054        get_acl_list(archiving_filelist_fname, curr_acl_list_fname);
1055        mr_free(curr_acl_list_fname);
1056
1057        log_msg(4, "%s[%d:%d] - archiving %d...", FORTY_SPACES, getpid(),
1058                this_thread_no, archiving_set_no);
1059        res = archive_this_fileset(bkpinfo, archiving_filelist_fname,
1060                                   archiving_afioball_fname,
1061                                   archiving_set_no);
1062        mr_free(archiving_afioball_fname);
1063        mr_free(archiving_filelist_fname);
1064        retval += res;
1065
1066        if (res) {
1067            mr_asprintf(&tmp,
1068                     "Errors occurred while archiving set %ld. Please review logs.",
1069                     archiving_set_no);
1070            log_to_screen(tmp);
1071            mr_free(tmp);
1072        }
1073        if (!semaphore_p()) {
1074            fatal_error("Cannot get semaphore P");
1075        }
1076
1077        set_bit_N_of_array(p_list_of_fileset_flags, archiving_set_no, 5);
1078
1079        if (*p_last_set_archived < archiving_set_no) {
1080            *p_last_set_archived = archiving_set_no;
1081        }                       // finished archiving this one
1082
1083        if (!semaphore_v()) {
1084            fatal_error("Cannot get semaphore V");
1085        }
1086        log_msg(4, "%s[%d:%d] - archived %d OK", FORTY_SPACES, getpid(),
1087                this_thread_no, archiving_set_no);
1088        archiving_set_no++;
1089        mr_asprintf(&archiving_filelist_fname, FILELIST_FNAME_RAW_SZ,
1090                 bkpinfo->tmpdir, archiving_set_no);
1091    }
1092    if (!semaphore_p()) {
1093        fatal_error("Cannot get semaphore P");
1094    }
1095    (*p_archival_threads_running)--;
1096    if (!semaphore_v()) {
1097        fatal_error("Cannot get semaphore V");
1098    }
1099    log_msg(3, "%s[%d:%d] - exiting", FORTY_SPACES, getpid(),
1100            this_thread_no);
1101    mr_free(archiving_filelist_fname);
1102    pthread_exit(NULL);
1103}
1104
1105
1106/**
1107 * Finalize the backup.
1108 * For streaming backups, this writes the closing block
1109 * to the stream. For CD-based backups, this creates
1110 * the final ISO image.
1111 * @param bkpinfo The backup information structure, used only
1112 * for the @c backup_media_type.
1113 * @ingroup MLarchiveGroup
1114 */
1115int do_that_final_phase(struct s_bkpinfo *bkpinfo)
1116{
1117
1118    /*@ int ************************************** */
1119    int res = 0;
1120    int retval = 0;
1121
1122    /*@ buffers ********************************** */
1123
1124    assert(bkpinfo != NULL);
1125    mvaddstr_and_log_it(g_currentY, 0,
1126                        "Writing any remaining data to media         ");
1127
1128    log_msg(1, "Closing tape/CD ... ");
1129    if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
1130        /* write tape/cdstream */
1131        closeout_tape(bkpinfo);
1132    } else {
1133        /* write final ISO */
1134        res = write_final_iso_if_necessary(bkpinfo);
1135        retval += res;
1136        if (res) {
1137            log_msg(1, "write_final_iso_if_necessary returned an error");
1138        }
1139    }
1140    log_msg(2, "Fork is exiting ... ");
1141
1142    mvaddstr_and_log_it(g_currentY++, 74, "Done.");
1143
1144    /* final stuff */
1145    if (retval) {
1146        mvaddstr_and_log_it(g_currentY++, 74, "Errors.");
1147    } else {
1148        mvaddstr_and_log_it(g_currentY++, 74, "Done.");
1149    }
1150
1151    return (retval);
1152}
1153
1154
1155/**
1156 * Initialize the backup.
1157 * Does the following:
1158 * - Sets up the serial number.
1159 * - For streaming backups, opens the tape stream and writes the data disks
1160 *   and backup headers.
1161 * - For CD-based backups, wipes the ISOs in the target directory.
1162 *
1163 * @param bkpinfo The backup information structure. Fields used:
1164 * - @c backup_media_type
1165 * - @c cdrw_speed
1166 * - @c prefix
1167 * - @c isodir
1168 * - @c media_device
1169 * - @c scratchdir
1170 * - @c tmpdir
1171 * @return The number of errors encountered (0 for success).
1172 * @ingroup MLarchiveGroup
1173 */
1174int do_that_initial_phase(struct s_bkpinfo *bkpinfo)
1175{
1176    /*@ int *************************************** */
1177    int retval = 0;
1178
1179    /*@ buffers *********************************** */
1180    char *command, *tmpfile, *data_disks_file, *tmp;
1181
1182    assert(bkpinfo != NULL);
1183    mr_asprintf(&data_disks_file, "%s/all.tar.gz", bkpinfo->tmpdir);
1184
1185    g_serial_string = call_program_and_get_last_line_of_output("dd \
1186if=/dev/urandom bs=16 count=1 2> /dev/null | \
1187hexdump | tr -s ' ' '0' | head -n1");
1188    mr_asprintf(&tmp, "%s...word.", g_serial_string);
1189    mr_free(g_serial_string);
1190    g_serial_string = tmp;
1191    log_msg(2, "g_serial_string = '%s'", g_serial_string);
1192
1193    mr_asprintf(&tmpfile, "%s/archives/SERIAL-STRING", bkpinfo->scratchdir);
1194    if (write_one_liner_data_file(tmpfile, g_serial_string)) {
1195        log_msg(1, "%ld: Failed to write serial string", __LINE__);
1196    }
1197    mr_free(g_serial_string);
1198    mr_free(tmpfile);
1199
1200    mvaddstr_and_log_it(g_currentY, 0, "Preparing to archive your data");
1201    if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
1202        if (bkpinfo->backup_media_type == cdstream) {
1203            openout_cdstream(bkpinfo->media_device, bkpinfo->cdrw_speed);
1204        } else {
1205            openout_tape(bkpinfo->media_device, bkpinfo->internal_tape_block_size); /* sets g_tape_stream */
1206        }
1207        if (!g_tape_stream) {
1208            fatal_error("Cannot open backup (streaming) device");
1209        }
1210        log_msg(1, "Backup (stream) opened OK");
1211        write_data_disks_to_stream(data_disks_file);
1212    } else {
1213        log_msg(1, "Backing up to CD's");
1214    }
1215    mr_free(data_disks_file);
1216
1217    mr_asprintf(&command, "rm -f %s/%s/%s-[1-9]*.iso", bkpinfo->isodir,
1218             bkpinfo->nfs_remote_dir, bkpinfo->prefix);
1219    paranoid_system(command);
1220    mr_free(command);
1221    wipe_archives(bkpinfo->scratchdir);
1222    mvaddstr_and_log_it(g_currentY++, 74, "Done.");
1223    if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
1224        write_header_block_to_stream((off_t)0, "start-of-tape",
1225                                     BLK_START_OF_TAPE);
1226        write_header_block_to_stream((off_t)0, "start-of-backup",
1227                                     BLK_START_OF_BACKUP);
1228    }
1229    return (retval);
1230}
1231
1232
1233/**
1234 * Calls floppy-formatting @c cmd and tracks its progress if possible.
1235 *
1236 * @param cmd The command to run (e.g. @c fdformat @c /dev/fd0).
1237 * @param title The human-friendly description of the floppy you are writing.
1238 * This will be used as the title in the progress bar window. Example:
1239 * "Formatting disk /dev/fd0".
1240 * @see format_disk
1241 * @return The exit code of fdformat/superformat.
1242 */
1243int format_disk_SUB(char *cmd, char *title)
1244{
1245
1246    /*@ int *************************************************************** */
1247    int res = 0;
1248    int percentage = 0;
1249    int maxtracks = 0;
1250    int trackno = 0;
1251    int last_trkno = 0;
1252
1253    /*@ buffers *********************************************************** */
1254    char *command;
1255    char *tempfile;
1256
1257    /*@ pointers ********************************************************** */
1258    FILE *pin;
1259
1260    assert_string_is_neither_NULL_nor_zerolength(cmd);
1261    assert_string_is_neither_NULL_nor_zerolength(title);
1262
1263#ifdef __FreeBSD__
1264/* Ugh. FreeBSD fdformat prints out this pretty progress indicator that's
1265   impossible to parse. It looks like
1266   VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVF-------------------
1267   where V means verified, E means error, F means formatted, and - means
1268   not done yet.
1269*/
1270    return (run_program_and_log_to_screen(cmd, title));
1271#endif
1272
1273/* if Debian then do bog-standard superformat; don't be pretty */
1274    if (strstr(cmd, "superformat")) {
1275        return (run_program_and_log_to_screen(cmd, title));
1276    }
1277/* if not Debian then go ahead & use fdformat */
1278    tempfile = call_program_and_get_last_line_of_output("mktemp -q /tmp/mondo.XXXXXXXX");
1279    mr_asprintf(&command, "%s >> %s 2>> %s; rm -f %s", cmd, tempfile,
1280             tempfile, tempfile);
1281    log_msg(3, command);
1282    open_evalcall_form(title);
1283    if (!(pin = popen(command, "r"))) {
1284        log_OS_error("fmt err");
1285        return (1);
1286    }
1287    if (strstr(command, "1722")) {
1288        maxtracks = 82;
1289    } else {
1290        maxtracks = 80;
1291    }
1292    mr_free(command);
1293
1294    for (sleep(1); does_file_exist(tempfile); sleep(1)) {
1295        trackno = get_trackno_from_logfile(tempfile);
1296        if (trackno < 0 || trackno > 80) {
1297            log_msg(1, "Weird track#");
1298            continue;
1299        }
1300        percentage = trackno * 100 / maxtracks;
1301        if (trackno <= 5 && last_trkno > 40) {
1302            close_evalcall_form();
1303            open_evalcall_form("Verifying format");
1304        }
1305        last_trkno = trackno;
1306        update_evalcall_form(percentage);
1307    }
1308    close_evalcall_form();
1309    if (pclose(pin)) {
1310        res++;
1311        log_OS_error("Unable to pclose");
1312    }
1313    unlink(tempfile);
1314    mr_free(tempfile);
1315    return (res);
1316}
1317
1318
1319/**
1320 * Wrapper around @c format_disk_SUB().
1321 * This function calls @c format_disk_SUB() with a @c device of its @c device
1322 * parameter and a @c title of Formatting disk @c device. If the format
1323 * fails, the user will be given the option of retrying.
1324 *
1325 * @param device The floppy drive to write to.
1326 * @see format_disk_SUB
1327 * @return The exit code of fdformat/superformat.
1328 * @ingroup deviceGroup
1329 */
1330int format_disk(char *device)
1331{
1332
1333    /*@ int ************************************************************** */
1334    int res = 0;
1335
1336    /*@ buffer *********************************************************** */
1337    char *command;
1338    char *title;
1339
1340
1341    assert_string_is_neither_NULL_nor_zerolength(device);
1342    if (!system("which superformat > /dev/null 2> /dev/null")) {
1343        mr_asprintf(&command, "superformat %s", device);
1344    } else {
1345#ifdef __FreeBSD__
1346        mr_asprintf(&command, "fdformat -y %s", device);
1347#else
1348        mr_asprintf(&command, "fdformat %s", device);
1349#endif
1350    }
1351    mr_asprintf(&title, "Formatting disk %s", device);
1352    while ((res = format_disk_SUB(command, title))) {
1353        if (!ask_me_yes_or_no("Failed to format disk. Retry?")) {
1354            return (res);
1355        }
1356    }
1357    mr_free(title);
1358    mr_free(command);
1359    return (res);
1360}
1361
1362
1363/**
1364 * Get the <tt>N</tt>th bit of @c array.
1365 * @param array The bit-array (as a @c char pointer).
1366 * @param N The number of the bit you want.
1367 * @return TRUE (bit is set) or FALSE (bit is not set).
1368 * @see set_bit_N_of_array
1369 * @ingroup utilityGroup
1370 */
1371bool get_bit_N_of_array(char *array, int N)
1372{
1373    int element_number;
1374    int bit_number;
1375    int mask;
1376
1377    element_number = N / 8;
1378    bit_number = N % 8;
1379    mask = 1 << bit_number;
1380    if (array[element_number] & mask) {
1381        return (TRUE);
1382    } else {
1383        return (FALSE);
1384    }
1385}
1386
1387/**
1388 * @addtogroup LLarchiveGroup
1389 * @{
1390 */
1391/**
1392 * Start up threads to archive your files.
1393 *
1394 * This function starts @c ARCH_THREADS threads,
1395 * each starting execution in @c create_afio_files_in_background().
1396 * Each thread will archive individual filesets, based on the
1397 * pointers passed to it and continually updated, until all files
1398 * have been backed up. This function coordinates the threads
1399 * and copies their output to the @c scratchdir.
1400 *
1401 * @param bkpinfo The backup information structure. Fields used:
1402 * - @c backup_media_type
1403 * - @c scratchdir
1404 * - @c tmpdir
1405 * - @c zip_suffix
1406 *
1407 * @return The number of errors encountered (0 for success)
1408 */
1409int make_afioballs_and_images(struct s_bkpinfo *bkpinfo)
1410{
1411
1412    /*@ int ************************************************** */
1413    int retval = 0;
1414    long int storing_set_no = 0;
1415    int res = 0;
1416    bool done_storing = FALSE;
1417    char *result_str;
1418    char *transfer_block;
1419    void *vp;
1420    void **pvp;
1421
1422    /*@ buffers ********************************************** */
1423    char *storing_filelist_fname;
1424    char *storing_afioball_fname;
1425    char *tmp;
1426    char *media_usage_comment;
1427    pthread_t archival_thread[ARCH_THREADS];
1428    char *p_list_of_fileset_flags;
1429    int *p_archival_threads_running;
1430    int *p_last_set_archived;
1431    int *p_next_set_to_archive;
1432    int noof_threads;
1433    int i;
1434    char *curr_xattr_list_fname;
1435    char *curr_acl_list_fname;
1436    int misc_counter_that_is_not_important = 0;
1437
1438    log_msg(8, "here");
1439    assert(bkpinfo != NULL);
1440    /* BERLIOS: To be removed */
1441    malloc_string(result_str);
1442    transfer_block =
1443        malloc(sizeof(struct s_bkpinfo) + BKPINFO_LOC_OFFSET + 64);
1444    memset((void *) transfer_block, 0,
1445           sizeof(struct s_bkpinfo) + BKPINFO_LOC_OFFSET + 64);
1446    p_last_set_archived = (int *) transfer_block;
1447    p_archival_threads_running = (int *) (transfer_block + 4);
1448    p_next_set_to_archive = (int *) (transfer_block + 8);
1449    p_list_of_fileset_flags = (char *) (transfer_block + 12);
1450    memcpy((void *) (transfer_block + BKPINFO_LOC_OFFSET),
1451           (void *) bkpinfo, sizeof(struct s_bkpinfo));
1452    pvp = &vp;
1453    vp = (void *) result_str;
1454    *p_archival_threads_running = 0;
1455    *p_last_set_archived = -1;
1456    *p_next_set_to_archive = 0;
1457    log_to_screen("Archiving regular files");
1458    log_msg(5, "Go, Shorty. It's your birthday.");
1459    open_progress_form(_("Backing up filesystem"),
1460                       _("I am backing up your live filesystem now."),
1461                       _("Please wait. This may take a couple of hours."),
1462                       _("Working..."),
1463                       get_last_filelist_number(bkpinfo) + 1);
1464
1465    log_msg(5, "We're gonna party like it's your birthday.");
1466
1467    srand((unsigned int) getpid());
1468    g_sem_key = 1234 + random() % 30000;
1469    if ((g_sem_id =
1470         semget((key_t) g_sem_key, 1,
1471                IPC_CREAT | S_IREAD | S_IWRITE)) == -1) {
1472        fatal_error("MABAI - unable to semget");
1473    }
1474    if (!set_semvalue()) {
1475        fatal_error("Unable to init semaphore");
1476    }                           // initialize semaphore
1477    for (noof_threads = 0; noof_threads < ARCH_THREADS; noof_threads++) {
1478        log_msg(8, "Creating thread #%d", noof_threads);
1479        (*p_archival_threads_running)++;
1480        if ((res =
1481             pthread_create(&archival_thread[noof_threads], NULL,
1482                            create_afio_files_in_background,
1483                            (void *) transfer_block))) {
1484            fatal_error("Unable to create an archival thread");
1485        }
1486    }
1487
1488    log_msg(8, "About to enter while() loop");
1489    while (!done_storing) {
1490        if (g_exiting) {
1491            fatal_error("Execution run aborted (main loop)");
1492        }
1493        if (*p_archival_threads_running == 0
1494            && *p_last_set_archived == storing_set_no - 1) {
1495            log_msg(2,
1496                    "No archival threads are running. The last stored set was %d and I'm looking for %d. Take off your make-up; the party's over... :-)",
1497                    *p_last_set_archived, storing_set_no);
1498            done_storing = TRUE;
1499        } else
1500            if (!get_bit_N_of_array
1501                (p_list_of_fileset_flags, storing_set_no)) {
1502            misc_counter_that_is_not_important =
1503                (misc_counter_that_is_not_important + 1) % 5;
1504            /* BERLIOS: media_usage_comment was NOT initialized !!! */
1505            /* maybe  */
1506            tmp = percent_media_full_comment(bkpinfo);
1507            mr_asprintf(&media_usage_comment, "%s", tmp);
1508            mr_free(tmp);
1509            if (!misc_counter_that_is_not_important) {
1510                update_progress_form(media_usage_comment);
1511            }
1512            mr_free(media_usage_comment);
1513            sleep(1);
1514        } else {
1515            // store set N
1516            mr_asprintf(&storing_filelist_fname, FILELIST_FNAME_RAW_SZ,
1517                     bkpinfo->tmpdir, storing_set_no);
1518            mr_asprintf(&storing_afioball_fname, AFIOBALL_FNAME_RAW_SZ,
1519                     bkpinfo->tmpdir, storing_set_no, bkpinfo->zip_suffix);
1520            mr_asprintf(&curr_xattr_list_fname, XATTR_LIST_FNAME_RAW_SZ,
1521                     bkpinfo->tmpdir, storing_set_no);
1522            mr_asprintf(&curr_acl_list_fname, ACL_LIST_FNAME_RAW_SZ,
1523                     bkpinfo->tmpdir, storing_set_no);
1524
1525            log_msg(2, "Storing set %d", storing_set_no);
1526            while (!does_file_exist(storing_filelist_fname)
1527                   || !does_file_exist(storing_afioball_fname)) {
1528                log_msg(2,
1529                        "Warning - either %s or %s doesn't exist yet. I'll pause 5 secs.",
1530                        storing_filelist_fname, storing_afioball_fname);
1531                sleep(5);
1532            }
1533            tmp = percent_media_full_comment(bkpinfo);
1534            mr_asprintf(&media_usage_comment, "%s", tmp);
1535            mr_free(tmp);
1536            /* copy to CD (scratchdir) ... and an actual CD-R if necessary */
1537            if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
1538                register_in_tape_catalog(fileset, storing_set_no, -1,
1539                                         storing_afioball_fname);
1540                maintain_collection_of_recent_archives(bkpinfo->tmpdir,
1541                                                       storing_afioball_fname);
1542                iamhere("Writing EXAT files");
1543                res += write_EXAT_files_to_tape(bkpinfo,
1544                                                curr_xattr_list_fname,
1545                                                curr_acl_list_fname);
1546                // archives themselves
1547                res +=
1548                    move_files_to_stream(bkpinfo, storing_afioball_fname,
1549                                         NULL);
1550            } else {
1551                res =
1552                    move_files_to_cd(bkpinfo, storing_filelist_fname,
1553                                     curr_xattr_list_fname,
1554                                     curr_acl_list_fname,
1555                                     storing_afioball_fname, NULL);
1556            }
1557            mr_free(storing_filelist_fname);
1558            mr_free(storing_afioball_fname);
1559            mr_free(curr_xattr_list_fname);
1560            mr_free(curr_acl_list_fname);
1561            retval += res;
1562            g_current_progress++;
1563            update_progress_form(media_usage_comment);
1564            mr_free(media_usage_comment);
1565
1566            if (res) {
1567                mr_asprintf(&tmp,
1568                         "Failed to add archive %ld's files to CD dir\n",
1569                         storing_set_no);
1570                log_to_screen(tmp);
1571                mr_free(tmp);
1572                fatal_error
1573                    ("Is your hard disk full? If not, please send the author the logfile.");
1574            }
1575            storing_set_no++;
1576            //      sleep(2);
1577        }
1578    }
1579    close_progress_form();
1580
1581    log_msg(2, "Joining background threads to foreground thread");
1582    for (i = 0; i < noof_threads; i++) {
1583        pthread_join(archival_thread[i], pvp);
1584        log_msg(3, "Thread %d of %d: closed OK", i + 1, noof_threads);
1585    }
1586    del_semvalue();
1587    log_msg(2, "Done.");
1588    if (retval) {
1589        mr_asprintf(&tmp,
1590                 "Your regular files have been archived (with errors).");
1591    } else {
1592        mr_asprintf(&tmp,
1593                 "Your regular files have been archived successfully");
1594    }
1595    log_to_screen(tmp);
1596    mr_free(tmp);
1597    mr_free(transfer_block);
1598    mr_free(result_str);
1599    return (retval);
1600}
1601
1602
1603void pause_for_N_seconds(int how_long, char *msg)
1604{
1605    int i;
1606    open_evalcall_form(msg);
1607    for (i = 0; i < how_long; i++) {
1608        update_evalcall_form((int) ((100.0 / (float) (how_long) * i)));
1609        sleep(1);
1610    }
1611    close_evalcall_form();
1612}
1613
1614
1615/**
1616 * Create an ISO image in @c destfile, from files in @c bkpinfo->scratchdir.
1617 *
1618 * @param bkpinfo The backup information structure. Fields used:
1619 * - @c backup_media_type
1620 * - @c call_after_iso
1621 * - @c call_before_iso
1622 * - @c call_burn_iso
1623 * - @c call_make_iso
1624 * - @c make_cd_use_lilo
1625 * - @c manual_cd_tray
1626 * - @c nonbootable_backup
1627 * - @c scratchdir
1628 *
1629 * @param destfile Where to put the generated ISO image.
1630 * @return The number of errors encountered (0 for success)
1631 */
1632int make_iso_fs(struct s_bkpinfo *bkpinfo, char *destfile)
1633{
1634    /*@ int ********************************************** */
1635    int retval = 0;
1636    int res;
1637
1638    /*@ buffers ****************************************** */
1639    char *tmp;
1640    char *old_pwd;
1641    char *result_sz;
1642    char *message_to_screen;
1643    char *sz_blank_disk;
1644    char *tmp2;
1645    char *tmp3;
1646    bool cd_is_mountable;
1647
1648    malloc_string(old_pwd);
1649    assert(bkpinfo != NULL);
1650    assert_string_is_neither_NULL_nor_zerolength(destfile);
1651
1652    mr_asprintf(&tmp, "%s/isolinux.bin", bkpinfo->scratchdir);
1653    mr_asprintf(&tmp2, "%s/isolinux.bin", bkpinfo->tmpdir);
1654    if (does_file_exist(tmp)) {
1655        mr_asprintf(&tmp3, "cp -f %s %s", tmp, tmp2);
1656        paranoid_system(tmp3);
1657        mr_free(tmp3);
1658    }
1659    if (!does_file_exist(tmp) && does_file_exist(tmp2)) {
1660        mr_asprintf(&tmp3, "cp -f %s %s", tmp2, tmp);
1661        paranoid_system(tmp3);
1662        mr_free(tmp3);
1663    }
1664    mr_free(tmp2);
1665    mr_free(tmp);
1666
1667    if (bkpinfo->backup_media_type == iso && bkpinfo->manual_cd_tray) {
1668        popup_and_OK(_("Please insert new media and press Enter."));
1669    }
1670
1671    log_msg(2, "make_iso_fs --- scratchdir=%s --- destfile=%s",
1672            bkpinfo->scratchdir, destfile);
1673    /* BERLIOS: Do not ignore getcwd result */
1674    (void) getcwd(old_pwd, MAX_STR_LEN - 1);
1675    mr_asprintf(&tmp, "chmod 755 %s", bkpinfo->scratchdir);
1676    run_program_and_log_output(tmp, FALSE);
1677    mr_free(tmp);
1678    chdir(bkpinfo->scratchdir);
1679
1680    if (bkpinfo->call_before_iso != NULL) {
1681        mr_asprintf(&message_to_screen, "Running pre-ISO call for CD#%d",
1682                 g_current_media_number);
1683        res = eval_call_to_make_ISO(bkpinfo, bkpinfo->call_before_iso,
1684                                    destfile, g_current_media_number,
1685                                    MONDO_LOGFILE, message_to_screen);
1686        if (res) {
1687            log_to_screen("%s...failed", message_to_screen);
1688        } else {
1689            log_to_screen("%s...OK", message_to_screen);
1690        }
1691        mr_free(message_to_screen);
1692        retval += res;
1693    }
1694
1695    if (bkpinfo->call_make_iso != NULL) {
1696        log_msg(2, "bkpinfo->call_make_iso = %s", bkpinfo->call_make_iso);
1697        mr_asprintf(&tmp, "%s/archives/NOT-THE-LAST", bkpinfo->scratchdir);
1698        mr_asprintf(&message_to_screen, "Making an ISO (%s #%d)",
1699                 bkpinfo->backup_media_string,
1700                 g_current_media_number);
1701
1702        /* if g_current_media_number >= 2 then pause & ask */
1703        pause_and_ask_for_cdr(2, &cd_is_mountable);
1704        if (retval) {
1705            log_to_screen
1706                ("Serious error(s) occurred already. I shan't try to write to media.");
1707        } else {
1708            res = eval_call_to_make_ISO(bkpinfo, bkpinfo->call_make_iso,
1709                                        bkpinfo->scratchdir,
1710                                        g_current_media_number,
1711                                        MONDO_LOGFILE, message_to_screen);
1712            if (res) {
1713                log_to_screen("%s...failed to write", message_to_screen);
1714            } else {
1715                log_to_screen("%s...OK", message_to_screen);
1716                if (!run_program_and_log_output
1717                    ("tail -n10 /var/log/mondo-archive.log | grep -F ':-('",
1718                     1)) {
1719                    log_to_screen
1720                        ("Despite nonfatal errors, growisofs confirms the write was successful.");
1721                }
1722            }
1723            retval += res;
1724#ifdef DVDRWFORMAT
1725            mr_asprintf(&tmp,
1726                     "tail -n8 %s | grep 'blank=full.*dvd-compat.*DAO'",
1727                     MONDO_LOGFILE);
1728            if (g_backup_media_type == dvd
1729                && (res || !run_program_and_log_output(tmp, 1))) {
1730                log_to_screen
1731                    ("Failed to write to disk. I shall blank it and then try again.");
1732                sleep(5);
1733                sync();
1734                pause_for_N_seconds(5, "Letting DVD drive settle");
1735
1736                // dvd+rw-format --- OPTION 2
1737                if (!bkpinfo->please_dont_eject) {
1738                    log_to_screen("Ejecting media to clear drive status.");
1739                    eject_device(bkpinfo->media_device);
1740                    inject_device(bkpinfo->media_device);
1741                }
1742                pause_for_N_seconds(5, "Letting DVD drive settle");
1743                mr_asprintf(&sz_blank_disk, "dvd+rw-format %s",
1744                         bkpinfo->media_device);
1745                log_msg(3, "sz_blank_disk = '%s'", sz_blank_disk);
1746                res = run_external_binary_with_percentage_indicator_NEW
1747                    ("Blanking DVD disk", sz_blank_disk);
1748                if (res) {
1749                    log_to_screen
1750                        ("Warning - format failed. (Was it a DVD-R?) Sleeping for 5 seconds to take a breath...");
1751                    pause_for_N_seconds(5,
1752                                        "Letting DVD drive settle... and trying again.");
1753                    res = run_external_binary_with_percentage_indicator_NEW
1754                        ("Blanking DVD disk", sz_blank_disk);
1755                    if (res) {
1756                        log_to_screen("Format failed a second time.");
1757                    }
1758                } else {
1759                    log_to_screen
1760                        ("Format succeeded. Sleeping for 5 seconds to take a breath...");
1761                }
1762                mr_free(sz_blank_disk);
1763                pause_for_N_seconds(5, "Letting DVD drive settle");
1764                if (!bkpinfo->please_dont_eject) {
1765                    log_to_screen("Ejecting media to clear drive status.");
1766                    eject_device(bkpinfo->media_device);
1767                    inject_device(bkpinfo->media_device);
1768                }
1769                pause_for_N_seconds(5, "Letting DVD drive settle");
1770                res =
1771                    eval_call_to_make_ISO(bkpinfo, bkpinfo->call_make_iso,
1772                                          bkpinfo->scratchdir,
1773                                          g_current_media_number,
1774                                          MONDO_LOGFILE,
1775                                          message_to_screen);
1776                retval += res;
1777                if (!bkpinfo->please_dont_eject) {
1778                    log_to_screen("Ejecting media.");
1779                    eject_device(bkpinfo->media_device);
1780                }
1781                if (res) {
1782                    log_to_screen("Dagnabbit. It still failed.");
1783                } else {
1784                    log_to_screen
1785                        ("OK, this time I successfully backed up to DVD.");
1786                }
1787            }
1788            mr_free(tmp);
1789#endif
1790            if (g_backup_media_type == dvd && !bkpinfo->please_dont_eject) {
1791                eject_device(bkpinfo->media_device);
1792            }
1793        }
1794        mr_free(message_to_screen);
1795    } else {
1796        mr_asprintf(&message_to_screen, "Running mkisofs to make %s #%d",
1797                 bkpinfo->backup_media_string,
1798                 g_current_media_number);
1799        log_msg(1, message_to_screen);
1800        mr_asprintf(&result_sz, "Call to mkisofs to make ISO (%s #%d) ",
1801                 bkpinfo->backup_media_string,
1802                 g_current_media_number);
1803        if (bkpinfo->nonbootable_backup) {
1804            log_msg(1, "Making nonbootable backup");
1805// FIXME --- change mkisofs string to MONDO_MKISOFS_NONBOOTABLE and add ' .' at end
1806            res = eval_call_to_make_ISO(bkpinfo,
1807                                        "mkisofs -o _ISO_ -r -p MondoRescue -publisher www.mondorescue.org -A Mondo_Rescue_GPL -V _CD#_ .",
1808                                        destfile, g_current_media_number,
1809                                        MONDO_LOGFILE, message_to_screen);
1810        } else {
1811            log_msg(1, "Making bootable backup");
1812
1813#ifdef __FreeBSD__
1814            bkpinfo->make_cd_use_lilo = TRUE;
1815#endif
1816
1817
1818            log_msg(1, "make_cd_use_lilo is actually %d",
1819                    bkpinfo->make_cd_use_lilo);
1820            if (bkpinfo->make_cd_use_lilo) {
1821                log_msg(1, "make_cd_use_lilo = TRUE");
1822// FIXME --- change mkisofs string to MONDO_MKISOFS_REGULAR_SYSLINUX/LILO depending on bkpinfo->make_cd_usE_lilo
1823// and add ' .' at end
1824#ifdef __IA64__
1825                log_msg(1, "IA64 --> elilo");
1826                mr_asprintf(&tmp2,"mkisofs -no-emul-boot -b images/mindi-bootroot.%s.img -c boot.cat -o _ISO_ -J -r -p MondoRescue -publisher www.mondorescue.org -A Mondo_Rescue_GPL -V _CD#_ .", bkpinfo->mrconf->mindi_ia64_boot_size);
1827                res = eval_call_to_make_ISO(bkpinfo,
1828                                            tmp2,
1829                                            destfile,
1830                                            g_current_media_number,
1831                                            MONDO_LOGFILE,
1832                                            message_to_screen);
1833#else
1834// FIXME --- change mkisofs string to MONDO_MKISOFS_REGULAR_SYSLINUX/LILO depending on bkpinfo->make_cd_usE_lilo
1835// and add ' .' at end
1836                mr_free(tmp2);
1837                log_msg(1, "Non-ia64 --> lilo");
1838                res = eval_call_to_make_ISO(bkpinfo,
1839                                            "mkisofs -b images/mindi-bootroot.2880.img -c boot.cat -o _ISO_ -J -r -p MondoRescue -publisher www.mondorescue.org -A Mondo_Rescue_GPL -V _CD#_ .",
1840                                            destfile,
1841                                            g_current_media_number,
1842                                            MONDO_LOGFILE,
1843                                            message_to_screen);
1844#endif
1845            } else {
1846                log_msg(1, "make_cd_use_lilo = FALSE");
1847                log_msg(1, "Isolinux");
1848                res = eval_call_to_make_ISO(bkpinfo,
1849                                            "mkisofs -no-emul-boot -b isolinux.bin -boot-load-size 4 -boot-info-table -c boot.cat -o _ISO_ -J -r -p MondoRescue -publisher www.mondorescue.org -A Mondo_Rescue_GPL -V _CD#_ .",
1850                                            destfile,
1851                                            g_current_media_number,
1852                                            MONDO_LOGFILE,
1853                                            message_to_screen);
1854            }
1855        }
1856        if (res) {
1857            log_to_screen("%s...failed", result_sz);
1858        } else {
1859            log_to_screen("%s...OK", result_sz);
1860        }
1861        retval += res;
1862        mr_free(message_to_screen);
1863        mr_free(result_sz);
1864    }
1865
1866    if (bkpinfo->backup_media_type == cdr
1867        || bkpinfo->backup_media_type == cdrw) {
1868        if (is_this_device_mounted(bkpinfo->media_device)) {
1869            log_msg(2,
1870                    "Warning - %s mounted. I'm unmounting it before I burn to it.",
1871                    bkpinfo->media_device);
1872            mr_asprintf(&tmp, "umount %s", bkpinfo->media_device);
1873            run_program_and_log_output(tmp, FALSE);
1874            mr_free(tmp);
1875        }
1876    }
1877
1878    if (bkpinfo->call_burn_iso != NULL) {
1879        log_msg(2, "bkpinfo->call_burn_iso = %s", bkpinfo->call_burn_iso);
1880        mr_asprintf(&message_to_screen, "Burning %s #%d",
1881                 bkpinfo->backup_media_string,
1882                 g_current_media_number);
1883        pause_and_ask_for_cdr(2, &cd_is_mountable);
1884        res = eval_call_to_make_ISO(bkpinfo, bkpinfo->call_burn_iso,
1885                                    destfile, g_current_media_number,
1886                                    MONDO_LOGFILE, message_to_screen);
1887        if (res) {
1888            log_to_screen("%s...failed", message_to_screen);
1889        } else {
1890            log_to_screen("%s...OK", message_to_screen);
1891        }
1892        mr_free(message_to_screen);
1893        retval += res;
1894    }
1895
1896    if (bkpinfo->call_after_iso != NULL) {
1897        mr_asprintf(&message_to_screen, "Running post-ISO call (%s #%d)",
1898                 bkpinfo->backup_media_string,
1899                 g_current_media_number);
1900        res = eval_call_to_make_ISO(bkpinfo, bkpinfo->call_after_iso,
1901                                    destfile, g_current_media_number,
1902                                    MONDO_LOGFILE, message_to_screen);
1903        if (res) {
1904            log_to_screen("%s...failed", message_to_screen);
1905        } else {
1906            log_to_screen("%s...OK", message_to_screen);
1907        }
1908        mr_free(message_to_screen);
1909        retval += res;
1910    }
1911
1912    chdir(old_pwd);
1913    if (retval) {
1914        log_msg(1, "WARNING - make_iso_fs returned an error");
1915    }
1916    mr_free(old_pwd);
1917    return (retval);
1918}
1919
1920
1921bool is_dev_an_NTFS_dev(char *bigfile_fname)
1922{
1923    char *tmp;
1924    char *command;
1925    bool ret = TRUE;
1926    mr_asprintf(&command,
1927             "dd if=%s bs=512 count=1 2> /dev/null | strings | head -n1",
1928             bigfile_fname);
1929    log_msg(1, "command = '%s'", command);
1930    tmp = call_program_and_get_last_line_of_output(command);
1931    log_msg(1, "--> tmp = '%s'", tmp);
1932    mr_free(command);
1933    if (strstr(tmp, "NTFS")) {
1934        iamhere("TRUE");
1935    } else {
1936        iamhere("FALSE");
1937        ret = FALSE;
1938    }
1939    mr_free(tmp);
1940    return(ret);
1941}
1942
1943
1944/**
1945 * Back up big files by chopping them up.
1946 * This function backs up all "big" files (where "big" depends
1947 * on your backup media) in "chunks" (whose size again depends
1948 * on your media).
1949 *
1950 * @param bkpinfo The backup information structure. Fields used:
1951 * - @c backup_media_type
1952 * - @c optimal_set_size
1953 * @param biggielist_fname The path to a file containing a list of
1954 * all "big" files.
1955 * @return The number of errors encountered (0 for success)
1956 * @see slice_up_file_etc
1957 */
1958int
1959make_slices_and_images(struct s_bkpinfo *bkpinfo, char *biggielist_fname)
1960{
1961
1962    /*@ pointers ******************************************* */
1963    FILE *fin;
1964    char *p;
1965
1966    /*@ buffers ******************************************** */
1967    char *tmp;
1968    char *bigfile_fname = NULL;
1969    char *sz_devfile;
1970    char *ntfsprog_fifo = NULL;
1971    /*@ long *********************************************** */
1972    long biggie_file_number = 0;
1973    long noof_biggie_files = 0;
1974    long estimated_total_noof_slices = 0;
1975
1976    /*@ int ************************************************ */
1977    int retval = 0;
1978    int res = 0;
1979    size_t n = 0;
1980    pid_t pid;
1981    FILE *ftmp = NULL;
1982    bool delete_when_done;
1983    bool use_ntfsprog;
1984    off_t biggie_fsize;
1985
1986    assert(bkpinfo != NULL);
1987    assert_string_is_neither_NULL_nor_zerolength(biggielist_fname);
1988
1989    estimated_total_noof_slices =
1990        size_of_all_biggiefiles_K(bkpinfo) / bkpinfo->optimal_set_size + 1;
1991
1992    log_msg(1, "size of all biggiefiles = %ld",
1993            size_of_all_biggiefiles_K(bkpinfo));
1994    log_msg(1, "estimated_total_noof_slices = %ld KB / %ld KB = %ld",
1995            size_of_all_biggiefiles_K(bkpinfo), bkpinfo->optimal_set_size,
1996            estimated_total_noof_slices);
1997
1998    if (length_of_file(biggielist_fname) < 6) {
1999        log_msg(1, "No biggiefiles; fair enough...");
2000        return (0);
2001    }
2002    mr_asprintf(&tmp, "I am now backing up all large files.");
2003    log_to_screen(tmp);
2004    noof_biggie_files = count_lines_in_file(biggielist_fname);
2005    open_progress_form("Backing up big files", tmp,
2006                       "Please wait. This may take some time.", "",
2007                       estimated_total_noof_slices);
2008    mr_free(tmp);
2009
2010    if (!(fin = fopen(biggielist_fname, "r"))) {
2011        log_OS_error("Unable to openin biggielist");
2012        return (1);
2013    }
2014    for (mr_getline(&bigfile_fname, &n, fin); !feof(fin);
2015         mr_getline(&bigfile_fname, &n, fin), biggie_file_number++) {
2016        use_ntfsprog = FALSE;
2017        if (bigfile_fname[strlen(bigfile_fname) - 1] < 32) {
2018            bigfile_fname[strlen(bigfile_fname) - 1] = '\0';
2019        }
2020        biggie_fsize = length_of_file(bigfile_fname);
2021        delete_when_done = FALSE;
2022
2023        if (!does_file_exist(bigfile_fname)) {
2024            ftmp = fopen(bigfile_fname, "w");
2025            paranoid_fclose(ftmp);
2026            mr_asprintf(&tmp, "bigfile %s was deleted - creating a dummy",
2027                     bigfile_fname);
2028            delete_when_done = TRUE;
2029        } else {
2030            // Call ntfsclone (formerly partimagehack) if it's a /dev entry
2031            // (i.e. a partition to be imaged)
2032            log_msg(2, "bigfile_fname = %s", bigfile_fname);
2033            use_ntfsprog = FALSE;
2034            if (!strncmp(bigfile_fname, "/dev/", 5)
2035                && is_dev_an_NTFS_dev(bigfile_fname)) {
2036                use_ntfsprog = TRUE;
2037                log_msg(2,
2038                        "Calling ntfsclone in background because %s is an NTFS partition",
2039                        bigfile_fname);
2040                mr_asprintf(&sz_devfile, "%s/%d.%d.000",
2041                        bkpinfo->tmpdir,
2042                         (int) (random() % 32768),
2043                         (int) (random() % 32768));
2044                mkfifo(sz_devfile, 0x770);
2045                ntfsprog_fifo = sz_devfile;
2046                switch (pid = fork()) {
2047                case -1:
2048                    fatal_error("Fork failure");
2049                case 0:
2050                    log_msg(2,
2051                            "CHILD - fip - calling feed_into_ntfsprog(%s, %s)",
2052                            bigfile_fname, sz_devfile);
2053                    res = feed_into_ntfsprog(bigfile_fname, sz_devfile);
2054                    exit(res);
2055                    break;
2056                default:
2057                    log_msg(2,
2058                            "feed_into_ntfsprog() called in background --- pid=%ld",
2059                            (long int) (pid));
2060
2061                    mr_free(sz_devfile);
2062                }
2063            }
2064            // Otherwise, use good old 'dd' and 'bzip2'
2065            else {
2066                ntfsprog_fifo = NULL;
2067            }
2068
2069            // Whether partition or biggiefile, just do your thang :-)
2070            log_msg(2, "Bigfile #%ld is '%s' (%ld KB)",
2071                    biggie_file_number + 1, bigfile_fname,
2072                    (long) biggie_fsize >> 10);
2073            if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
2074                write_header_block_to_stream(biggie_fsize, bigfile_fname,
2075                                             use_ntfsprog ?
2076                                             BLK_START_A_PIHBIGGIE :
2077                                             BLK_START_A_NORMBIGGIE);
2078            }
2079            res =
2080                slice_up_file_etc(bkpinfo, bigfile_fname,
2081                                  ntfsprog_fifo, biggie_file_number,
2082                                  noof_biggie_files, use_ntfsprog);
2083            if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
2084                tmp = calc_checksum_of_file(bigfile_fname);
2085                write_header_block_to_stream((off_t)0, tmp, BLK_STOP_A_BIGGIE);
2086                mr_free(tmp);
2087            }
2088            retval += res;
2089            p = strrchr(bigfile_fname, '/');
2090            if (p) {
2091                p++;
2092            } else {
2093                p = bigfile_fname;
2094            }
2095            if (res) {
2096                mr_asprintf(&tmp, "Archiving %s ... Failed!", bigfile_fname);
2097            } else {
2098                mr_asprintf(&tmp, "Archiving %s ... OK!", bigfile_fname);
2099            }
2100
2101            if (delete_when_done) {
2102                unlink(bigfile_fname);
2103                delete_when_done = FALSE;
2104            }
2105        }
2106#ifndef _XWIN
2107        if (!g_text_mode) {
2108            newtDrawRootText(0, g_noof_rows - 2, tmp);
2109            newtRefresh();
2110        }
2111#endif
2112    }
2113    mr_free(tmp);
2114    mr_free(bigfile_fname);
2115    paranoid_fclose(fin);
2116
2117    log_msg(1, "Finished backing up bigfiles");
2118    log_msg(1, "estimated slices = %ld; actual slices = %ld",
2119            estimated_total_noof_slices, g_current_progress);
2120    close_progress_form();
2121    return (retval);
2122}
2123
2124
2125/**
2126 * Single-threaded version of @c make_afioballs_and_images().
2127 * @see make_afioballs_and_images
2128 */
2129int make_afioballs_and_images_OLD(struct s_bkpinfo *bkpinfo)
2130{
2131
2132    /*@ int ************************************************** */
2133    int retval = 0;
2134    long int curr_set_no = 0;
2135    int res = 0;
2136
2137    /*@ buffers ********************************************** */
2138    char *curr_filelist_fname;
2139    char *curr_afioball_fname;
2140    char *curr_xattr_list_fname;
2141    char *curr_acl_list_fname;
2142    char *tmp;
2143    char *media_usage_comment;
2144
2145    /* BERLIOS: Useless ?
2146       mr_asprintf(&tmp, "%s/archives/filelist.full", bkpinfo->scratchdir);
2147     */
2148
2149    log_to_screen("Archiving regular files");
2150
2151    open_progress_form(_("Backing up filesystem"),
2152                       _("I am backing up your live filesystem now."),
2153                       _("Please wait. This may take a couple of hours."),
2154                       _("Working..."),
2155                       get_last_filelist_number(bkpinfo) + 1);
2156
2157    mr_asprintf(&curr_filelist_fname, FILELIST_FNAME_RAW_SZ, bkpinfo->tmpdir,
2158             0L);
2159
2160    curr_set_no = 0;
2161    while (does_file_exist(curr_filelist_fname)) {
2162        /* backup this set of files */
2163        mr_asprintf(&curr_afioball_fname, AFIOBALL_FNAME_RAW_SZ,
2164                 bkpinfo->tmpdir, curr_set_no, bkpinfo->zip_suffix);
2165
2166        log_msg(1, "EXAT'g set %ld", curr_set_no);
2167        mr_asprintf(&curr_xattr_list_fname, XATTR_LIST_FNAME_RAW_SZ,
2168                 bkpinfo->tmpdir, curr_set_no);
2169        mr_asprintf(&curr_acl_list_fname, ACL_LIST_FNAME_RAW_SZ,
2170                 bkpinfo->tmpdir, curr_set_no);
2171        get_fattr_list(curr_filelist_fname, curr_xattr_list_fname);
2172        get_acl_list(curr_filelist_fname, curr_acl_list_fname);
2173
2174        log_msg(1, "Archiving set %ld", curr_set_no);
2175        res = archive_this_fileset(bkpinfo, curr_filelist_fname,
2176                                   curr_afioball_fname, curr_set_no);
2177        retval += res;
2178        if (res) {
2179            mr_asprintf(&tmp,
2180                     "Errors occurred while archiving set %ld. Perhaps your live filesystem changed?",
2181                     curr_set_no);
2182            log_to_screen(tmp);
2183            mr_free(tmp);
2184        }
2185
2186        tmp = percent_media_full_comment(bkpinfo);
2187        mr_asprintf(&media_usage_comment, "%s", tmp);
2188        mr_free(tmp);
2189
2190        /* copy to CD (scratchdir) ... and an actual CD-R if necessary */
2191        if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
2192            register_in_tape_catalog(fileset, curr_set_no, -1,
2193                                     curr_afioball_fname);
2194            maintain_collection_of_recent_archives(bkpinfo->tmpdir,
2195                                                   curr_afioball_fname);
2196            iamhere("Writing EXAT files");
2197            res += write_EXAT_files_to_tape(bkpinfo, curr_xattr_list_fname,
2198                                            curr_acl_list_fname);
2199            // archives themselves
2200            res = move_files_to_stream(bkpinfo, curr_afioball_fname, NULL);
2201        } else {
2202            res =
2203                move_files_to_cd(bkpinfo, curr_filelist_fname,
2204                                 curr_xattr_list_fname,
2205                                 curr_acl_list_fname, curr_afioball_fname,
2206                                 NULL);
2207        }
2208        retval += res;
2209        g_current_progress++;
2210        update_progress_form(media_usage_comment);
2211        mr_free(media_usage_comment);
2212
2213        if (res) {
2214            mr_asprintf(&tmp, "Failed to add archive %ld's files to CD dir\n",
2215                     curr_set_no);
2216            log_to_screen(tmp);
2217            mr_free(tmp);
2218            fatal_error
2219                ("Is your hard disk is full? If not, please send the author the logfile.");
2220        }
2221        mr_free(curr_filelist_fname);
2222        mr_free(curr_afioball_fname);
2223        mr_free(curr_xattr_list_fname);
2224        mr_free(curr_acl_list_fname);
2225        mr_asprintf(&curr_filelist_fname, FILELIST_FNAME_RAW_SZ,
2226                 bkpinfo->tmpdir, ++curr_set_no);
2227    }
2228    mr_free(curr_filelist_fname);
2229    close_progress_form();
2230    if (retval) {
2231        log_to_screen
2232            ("Your regular files have been archived (with errors).");
2233    } else {
2234        log_to_screen
2235            ("Your regular files have been archived successfully.");
2236    }
2237    return (retval);
2238}
2239
2240/* @} - end of LLarchiveGroup */
2241
2242
2243/**
2244 * Wrapper around @c make_afioballs_and_images().
2245 * @param bkpinfo the backup information structure. Only the
2246 * @c backup_media_type field is used within this function.
2247 * @return return code of make_afioballs_and_images
2248 * @see make_afioballs_and_images
2249 * @ingroup MLarchiveGroup
2250 */
2251int make_those_afios_phase(struct s_bkpinfo *bkpinfo)
2252{
2253    /*@ int ******************************************* */
2254    int res = 0;
2255    int retval = 0;
2256
2257    assert(bkpinfo != NULL);
2258
2259    mvaddstr_and_log_it(g_currentY, 0,
2260                        "Archiving regular files to media          ");
2261
2262    if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
2263        write_header_block_to_stream((off_t)0, "start-of-afioballs",
2264                                     BLK_START_AFIOBALLS);
2265#if __FreeBSD__ == 5
2266        log_msg(1,
2267                "Using single-threaded make_afioballs_and_images() to suit b0rken FreeBSD 5.0");
2268        res = make_afioballs_and_images_OLD(bkpinfo);
2269#else
2270        res = make_afioballs_and_images_OLD(bkpinfo);
2271#endif
2272        write_header_block_to_stream((off_t)0, "stop-afioballs",
2273                                     BLK_STOP_AFIOBALLS);
2274    } else {
2275        res = make_afioballs_and_images(bkpinfo);
2276    }
2277
2278    retval += res;
2279    if (res) {
2280        mvaddstr_and_log_it(g_currentY++, 74, "Errors.");
2281        log_msg(1, "make_afioballs_and_images returned an error");
2282    } else {
2283        mvaddstr_and_log_it(g_currentY++, 74, "Done.");
2284    }
2285    return (retval);
2286}
2287
2288/**
2289 * Wrapper around @c make_slices_and_images().
2290 * @param bkpinfo The backup information structure. Fields used:
2291 * - @c backup_media_type
2292 * - @c scratchdir
2293 * - @c tmpdir
2294 * @return The number of errors encountered (0 for success)
2295 * @ingroup MLarchiveGroup
2296 */
2297int make_those_slices_phase(struct s_bkpinfo *bkpinfo)
2298{
2299
2300    /*@ int ***************************************************** */
2301    int res = 0;
2302    int retval = 0;
2303
2304    /*@ buffers ************************************************** */
2305    char *biggielist;
2306    char *command;
2307    char *blah;
2308    char *xattr_fname;
2309    char *acl_fname;
2310
2311    assert(bkpinfo != NULL);
2312    /* slice big files */
2313    mvaddstr_and_log_it(g_currentY, 0,
2314                        "Archiving large files to media           ");
2315    mr_asprintf(&biggielist, "%s/archives/biggielist.txt",
2316             bkpinfo->scratchdir);
2317    mr_asprintf(&xattr_fname, XATTR_BIGGLST_FNAME_RAW_SZ, bkpinfo->tmpdir);
2318    mr_asprintf(&acl_fname, ACL_BIGGLST_FNAME_RAW_SZ, bkpinfo->tmpdir);
2319
2320    mr_asprintf(&command, "cp %s/biggielist.txt %s", bkpinfo->tmpdir,
2321             biggielist);
2322    paranoid_system(command);
2323    mr_free(command);
2324
2325    mr_asprintf(&blah, "biggielist = %s", biggielist);
2326    log_msg(2, blah);
2327    mr_free(blah);
2328
2329    if (!does_file_exist(biggielist)) {
2330        log_msg(1, "BTW, the biggielist does not exist");
2331    }
2332
2333    get_fattr_list(biggielist, xattr_fname);
2334    get_acl_list(biggielist, acl_fname);
2335    mr_asprintf(&command, "cp %s %s/archives/", xattr_fname,
2336             bkpinfo->scratchdir);
2337    paranoid_system(command);
2338    mr_free(command);
2339
2340    mr_asprintf(&command, "cp %s %s/archives/", acl_fname,
2341             bkpinfo->scratchdir);
2342    paranoid_system(command);
2343    mr_free(command);
2344
2345    if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
2346        res += write_EXAT_files_to_tape(bkpinfo, xattr_fname, acl_fname);
2347        mr_asprintf(&blah, "%ld", count_lines_in_file(biggielist));
2348        write_header_block_to_stream((off_t)0, blah, BLK_START_BIGGIEFILES);
2349        mr_free(blah);
2350    }
2351    mr_free(xattr_fname);
2352    mr_free(acl_fname);
2353
2354    res = make_slices_and_images(bkpinfo, biggielist);
2355    mr_free(biggielist);
2356
2357    if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
2358        write_header_block_to_stream((off_t)0, "end-of-biggiefiles",
2359                                     BLK_STOP_BIGGIEFILES);
2360    }
2361    retval += res;
2362    if (res) {
2363        log_msg(1, "make_slices_and_images returned an error");
2364        mvaddstr_and_log_it(g_currentY++, 74, "Errors.");
2365    } else {
2366        mvaddstr_and_log_it(g_currentY++, 74, "Done.");
2367    }
2368    return (retval);
2369}
2370
2371
2372/**
2373 * @addtogroup LLarchiveGroup
2374 * @{
2375 */
2376/**
2377 * Function pointer to an appropriate @c move_files_to_cd routine.
2378 * You can set this to your own function (for example, one to
2379 * transfer files over the network) or leave it as is.
2380 */
2381int (*move_files_to_cd) (struct s_bkpinfo *, char *, ...) =
2382    _move_files_to_cd;
2383
2384/**
2385 * Move some files to the ISO scratch directory.
2386 * This function moves files specified as parameters, into the directory
2387 * @c bkpinfo->scratchdir, where the files that will be stored on the next
2388 * CD are waiting.
2389 *
2390 * @param bkpinfo The backup information structure. Fields used:
2391 * - @c media_size
2392 * - @c scratchdir
2393 * @param files_to_add The files to add to the scratchdir.
2394 * @warning The list of @c files_to_add must be terminated with @c NULL.
2395 * @note If and when the space occupied by the scratchdir would exceed
2396 * the capacity of the current CD,
2397 * <tt>write_iso_and_go_on(bkpinfo, FALSE)</tt> is called and the
2398 * scratchdir is emptied.
2399 *
2400 * @return The number of errors encountered (0 for success)
2401 */
2402int _move_files_to_cd(struct s_bkpinfo *bkpinfo, char *files_to_add, ...)
2403{
2404
2405    /*@ int ************************************************************ */
2406    int retval = 0;
2407    int res = 0;
2408
2409    /*@ buffers ******************************************************** */
2410    char *tmp, *curr_file, *cf;
2411
2412    /*@ long ************************************************************ */
2413    va_list ap;
2414    long long would_occupy;
2415
2416    assert(bkpinfo != NULL);
2417    would_occupy = space_occupied_by_cd(bkpinfo->scratchdir);
2418    va_start(ap, files_to_add); // initialize the variable arguments
2419    for (cf = files_to_add; cf != NULL; cf = va_arg(ap, char *)) {
2420        if (!cf) {
2421            continue;
2422        }
2423        mr_asprintf(&curr_file, "%s", cf);
2424        if (!does_file_exist(curr_file)) {
2425            log_msg(1,
2426                    "Warning - you're trying to add a non-existent file - '%s' to the CD",
2427                    curr_file);
2428        } else {
2429            log_msg(8, "Trying to add file %s to CD", curr_file);
2430            would_occupy += length_of_file(curr_file) / 1024;
2431        }
2432        mr_free(curr_file);
2433    }
2434    va_end(ap);
2435
2436    if (bkpinfo->media_size[g_current_media_number] <= 0) {
2437        fatal_error("move_files_to_cd() - unknown media size");
2438    }
2439    if (would_occupy / 1024 > bkpinfo->media_size[g_current_media_number]) {
2440        /* FALSE because this is not the last CD we'll write */
2441        res = write_iso_and_go_on(bkpinfo, FALSE);
2442        retval += res;
2443        if (res) {
2444            log_msg(1, "WARNING - write_iso_and_go_on returned an error");
2445        }
2446    }
2447
2448    va_start(ap, files_to_add); // initialize the variable arguments
2449    for (cf = files_to_add; cf != NULL; cf = va_arg(ap, char *)) {
2450        if (!cf) {
2451            continue;
2452        }
2453        mr_asprintf(&curr_file, "%s", cf);
2454
2455        mr_asprintf(&tmp, "mv -f %s %s/archives/", curr_file,
2456                 bkpinfo->scratchdir);
2457        res = run_program_and_log_output(tmp, 5);
2458        retval += res;
2459        if (res) {
2460            log_msg(1, "(move_files_to_cd) '%s' failed", tmp);
2461        } else {
2462            log_msg(8, "Moved %s to CD OK", tmp);
2463        }
2464        mr_free(tmp);
2465        mr_free(curr_file);
2466        //      unlink (curr_file);
2467    }
2468    va_end(ap);
2469
2470    if (retval) {
2471        log_msg(1,
2472                "Warning - errors occurred while I was adding files to CD dir");
2473    }
2474    return (retval);
2475}
2476
2477/* @} - end of LLarchiveGroup */
2478
2479
2480/**
2481 * Offer to write boot and data disk images to 3.5" floppy disks.
2482 * @param bkpinfo The backup information structure. Only the
2483 * @c backup_media_type field is used in this function.
2484 * @param imagesdir The directory containing the floppy images (usually
2485 * /var/cache/mindi).
2486 *
2487 * @return The number of errors encountered (0 for success)
2488 * @see write_image_to_floppy
2489 * @see format_disk
2490 * @ingroup MLarchiveGroup
2491 */
2492int offer_to_write_floppies(struct s_bkpinfo *bkpinfo, char *imagesdir)
2493{
2494    /*@ buffer ************************************************************ */
2495    char *tmp;
2496    char *comment;
2497    char *bootdisk_dev;
2498    char *datadisk_dev;
2499    char *bootdisk_file;
2500    char *rootdisk_file;
2501
2502    /*@ int *************************************************************** */
2503    int i = 0;
2504    int res = 0;
2505
2506    /*@ bool ************************************************************** */
2507    bool format_first;
2508    bool root_disk_exists = FALSE;
2509
2510    assert(bkpinfo != NULL);
2511    assert_string_is_neither_NULL_nor_zerolength(imagesdir);
2512
2513
2514    if (!ask_me_yes_or_no
2515        ("Write boot and data disk images to 3.5\" floppy disks?")) {
2516        return (0);
2517    }
2518    if (does_device_exist(DEFAULT_1722MB_DISK)) {
2519#ifdef __FreeBSD__
2520        // tell the system that this is a 1.72m floppy
2521        system("/usr/sbin/fdcontrol -F 1722 /dev/fd0.1722");
2522#endif
2523        mr_asprintf(&bootdisk_dev, "%s", DEFAULT_1722MB_DISK);
2524    } else if (does_device_exist(BACKUP_1722MB_DISK)) {
2525        mr_asprintf(&bootdisk_dev, "/dev/fd0H1722");
2526    } else {
2527        log_msg(1, "Warning - can't find a 1.72MB floppy device *sigh*");
2528        mr_asprintf(&bootdisk_dev, DEFAULT_1722MB_DISK);
2529    }
2530    mr_asprintf(&datadisk_dev, "%s", "/dev/fd0");
2531    if (!does_device_exist(datadisk_dev)) {
2532        log_msg(1, "Warning - can't find a 1.44MB floppy device *sigh*");
2533        mr_free(datadisk_dev);
2534        mr_asprintf(&datadisk_dev, "%s", "/dev/fd0");
2535    }
2536    format_first = ask_me_yes_or_no
2537        ("Do you want me to format the disks before I write to them?");
2538
2539/* boot disk */
2540    if (ask_me_OK_or_cancel("About to write boot disk")) {
2541        log_to_screen("Writing boot floppy");
2542#ifdef __FreeBSD__
2543        mr_asprintf(&tmp, "%s/mindi-kern.1722.img", imagesdir);
2544        if (format_first) {
2545            format_disk(bootdisk_dev);
2546        }
2547        res += write_image_to_floppy(bootdisk_dev, tmp);
2548        mr_free(tmp);
2549
2550        if (ask_me_OK_or_cancel("About to write 1.44MB mfsroot disk")) {
2551            log_to_screen("Writing mfsroot floppy");
2552            if (format_first) {
2553                format_disk(datadisk_dev);
2554            }
2555            mr_asprintf(&tmp, "%s/mindi-mfsroot.1440.img", imagesdir);
2556            write_image_to_floppy(datadisk_dev, tmp);
2557            mr_free(tmp);
2558        }
2559#else
2560        mr_asprintf(&bootdisk_file, "%s/mindi-bootroot.1722.img", imagesdir);
2561        if (does_file_exist(bootdisk_file)) {
2562            if (format_first) {
2563                format_disk(bootdisk_dev);
2564            }
2565            res += write_image_to_floppy(bootdisk_dev, bootdisk_file);
2566        } else {
2567            mr_free(bootdisk_file);
2568            mr_asprintf(&bootdisk_file, "%s/mindi-boot.1440.img", imagesdir);
2569            mr_asprintf(&rootdisk_file, "%s/mindi-root.1440.img", imagesdir);
2570            root_disk_exists = TRUE;
2571            if (!does_file_exist(rootdisk_file)
2572                || !does_file_exist(bootdisk_file)) {
2573                popup_and_OK
2574                    ("Cannot write boot/root floppies. Files not found.");
2575                log_to_screen
2576                    ("Failed to find boot/root floppy images. Oh dear.");
2577                mr_free(bootdisk_file);
2578                mr_free(rootdisk_file);
2579                mr_free(bootdisk_dev);
2580                return (1);
2581            }
2582            if (format_first) {
2583                format_disk(datadisk_dev);
2584            }
2585            res += write_image_to_floppy(datadisk_dev, bootdisk_file);
2586            if (ask_me_OK_or_cancel("About to write root disk")) {
2587                log_to_screen("Writing root floppy");
2588                if (format_first) {
2589                    format_disk(datadisk_dev);
2590                }
2591                mr_asprintf(&tmp, "cat %s > %s", rootdisk_file, datadisk_dev);
2592                log_msg(1, "tmp = '%s'", tmp);
2593                res +=
2594                    run_external_binary_with_percentage_indicator_NEW
2595                    ("Writing root floppy", tmp);
2596//              res += write_image_to_floppy (datadisk_dev, rootdisk_file);
2597                mr_free(tmp);
2598            }
2599            mr_free(rootdisk_file);
2600            mr_free(bootdisk_file);
2601        }
2602#endif
2603    }
2604    mr_free(bootdisk_dev);
2605
2606    if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
2607        log_to_screen
2608            ("FYI, the data disks are stored on tape/CD for your convenience.");
2609        return (0);
2610    }
2611    for (i = 1; i < 99; i++) {
2612        mr_asprintf(&tmp, "%s/mindi-data-%d.img", imagesdir, i);
2613        log_msg(3, tmp);
2614        if (!does_file_exist(tmp)) {
2615            log_msg(3, "...not found");
2616            break;
2617        }
2618        mr_asprintf(&comment, "About to write data disk #%d", i);
2619        if (ask_me_OK_or_cancel(comment)) {
2620            mr_free(comment);
2621            mr_asprintf(&comment, "Writing data disk #%3d", i);
2622            log_to_screen(comment);
2623            mr_free(comment);
2624            if (format_first) {
2625                res += format_disk(datadisk_dev);
2626            }
2627            res += write_image_to_floppy(datadisk_dev, tmp);
2628        }
2629    }
2630    mr_free(tmp);
2631    mr_free(datadisk_dev);
2632    return (res);
2633}
2634
2635
2636/**
2637 * Wrapper around @c offer_to_write_floppies().
2638 * @param bkpinfo The backup information structure. Used only
2639 * in the call to @c offer_to_write_floppies().
2640 * @return 0 if the boot floppies were found (not necessarily written OK),
2641 * 1 otherwise.
2642 * @see offer_to_write_floppies
2643 * @ingroup MLarchiveGroup
2644 */
2645
2646int
2647offer_to_write_boot_floppies_to_physical_disks(struct s_bkpinfo *bkpinfo)
2648{
2649    int res = 0;
2650
2651    assert(bkpinfo != NULL);
2652
2653    mvaddstr_and_log_it(g_currentY, 0,
2654                        "Writing boot+data floppy images to disk");
2655
2656    if (!bkpinfo->nonbootable_backup) {
2657#ifdef __FreeBSD__
2658        if (!does_file_exist("/var/cache/mindi/mindi-kern.1722.img"))
2659#else
2660        if (!does_file_exist("/var/cache/mindi/mindi-bootroot.1722.img")
2661            && !does_file_exist("/var/cache/mindi/mindi-boot.1440.img")
2662            && !does_file_exist("/var/cache/mindi/mindi-boot.2880.img")
2663            && !does_file_exist("/var/cache/mindi/mindi-boot.5760.img"))
2664#endif
2665        {
2666            mvaddstr_and_log_it(g_currentY++, 74, "No Imgs");
2667            if (does_file_exist("/var/cache/mindi/mondorescue.iso")) {
2668                popup_and_OK
2669                    ("Boot+data floppy creation failed.\nHowever, you may burn /var/cache/mindi/mondorescue.iso to a CD\nand boot from that instead if you wish.");
2670                res++;
2671            }
2672        } else {
2673            offer_to_write_floppies(bkpinfo, "/var/cache/mindi");
2674            mvaddstr_and_log_it(g_currentY++, 74, "Done.");
2675        }
2676    } else {
2677        popup_and_OK
2678            ("Since you opted for a nonbootable backup, no boot floppies were created.");
2679    }
2680
2681    return (res);
2682}
2683
2684
2685/**
2686 * @addtogroup LLarchiveGroup
2687 * @{
2688 */
2689/**
2690 * Function pointer to an appropriate @c move_files_to_stream routine.
2691 * You can set this to your own function (for example, one to
2692 * transfer files over the network) or leave it as is.
2693 */
2694int (*move_files_to_stream) (struct s_bkpinfo *, char *, ...) =
2695    _move_files_to_stream;
2696
2697/**
2698 * Copy some files to tape.
2699 * This function copies the files specified as parameters into the tape stream.
2700 *
2701 * @param bkpinfo The backup information structure. Used only in the call to
2702 * @c write_file_to_stream_from_file().
2703 *
2704 * @param files_to_add The files to copy to the tape stream.
2705 * @warning The list of @c files_to_add must be terminated with @c NULL.
2706 * @note Files may be split across multiple tapes if necessary.
2707 *
2708 * @return The number of errors encountered (0 for success)
2709 */
2710int
2711_move_files_to_stream(struct s_bkpinfo *bkpinfo, char *files_to_add, ...)
2712{
2713
2714    /*@ int ************************************************************ */
2715    int retval = 0;
2716    int res = 0;
2717    /*@ buffers ******************************************************** */
2718
2719    /*@ char *********************************************************** */
2720    char start_chr;
2721    char stop_chr;
2722    char *curr_file, *cf;
2723    /*@ long long ****************************************************** */
2724    off_t length_of_incoming_file = (off_t)0;
2725    t_archtype type;
2726    va_list ap;
2727
2728    assert(bkpinfo != NULL);
2729    va_start(ap, files_to_add);
2730    for (cf = files_to_add; cf != NULL; cf = va_arg(ap, char *)) {
2731        if (!cf) {
2732            continue;
2733        }
2734        mr_asprintf(&curr_file, "%s", cf);
2735        if (!does_file_exist(curr_file)) {
2736            log_msg(1,
2737                    "Warning - you're trying to add a non-existent file - '%s' to the tape",
2738                    curr_file);
2739        }
2740        /* create header chars */
2741        start_chr = BLK_START_AN_AFIO_OR_SLICE;
2742        stop_chr = BLK_STOP_AN_AFIO_OR_SLICE;
2743        /* ask for new tape if necessary */
2744        length_of_incoming_file = length_of_file(curr_file);
2745        write_header_block_to_stream(length_of_incoming_file, curr_file,
2746                                     start_chr);
2747        if (strstr(curr_file, ".afio.") || strstr(curr_file, ".star.")) {
2748            type = fileset;
2749        } else if (strstr(curr_file, "slice")) {
2750            type = biggieslice;
2751        } else {
2752            type = other;
2753        }
2754        res = write_file_to_stream_from_file(bkpinfo, curr_file);
2755        retval += res;
2756        unlink(curr_file);
2757        mr_free(curr_file);
2758        /* write closing header */
2759        write_header_block_to_stream((off_t)0, "finished-writing-file", stop_chr);
2760    }
2761    va_end(ap);
2762
2763    if (retval) {
2764        log_msg(1,
2765                "Warning - errors occurred while I was adding file to tape");
2766    }
2767    return (retval);
2768}
2769
2770/* @} - end of LLarchiveGroup */
2771
2772
2773/**
2774 * @addtogroup utilityGroup
2775 * @{
2776 */
2777/**
2778 * Make sure the user has a valid CD-R(W) in the CD drive.
2779 * @param cdrw_device Set to the CD-R(W) device checked.
2780 * @param keep_looping If TRUE, keep pestering user until they insist
2781 * or insert a correct CD; if FALSE, only check once.
2782 * @return 0 (there was an OK CD in the drive) or 1 (there wasn't).
2783 */
2784char *interrogate_disk_currently_in_cdrw_drive()
2785{
2786    char *cdrecord;
2787    char *cdrw_device;
2788
2789    if ((cdrw_device = find_cdrw_device()) != NULL) {
2790        if (!system("which cdrecord > /dev/null 2> /dev/null")) {
2791            mr_asprintf(&cdrecord, "cdrecord dev=%s -atip", cdrw_device);
2792        } else if (!system("which dvdrecord > /dev/null 2> /dev/null")) {
2793            mr_asprintf(&cdrecord, "cdrecord dev=%s -atip", cdrw_device);
2794        } else {
2795            mr_asprintf(&cdrecord, " ");
2796            log_msg(2, "Found no cdrecord nor dvdrecord in path.");
2797        }
2798        if (cdrecord[0]) {
2799                retract_CD_tray_and_defeat_autorun();
2800                run_program_and_log_output(cdrecord, 5);
2801        }
2802        mr_free(cdrecord);
2803    }
2804    return(cdrw_device);
2805}
2806
2807
2808/**
2809 * Asks the user to put a CD-R(W) in the drive.
2810 * @param ask_for_one_if_more_than_this (unused)
2811 * @param pmountable If non-NULL, pointed-to value is set to TRUE if the CD is mountable, FALSE otherwise.
2812 */
2813void
2814pause_and_ask_for_cdr(int ask_for_one_if_more_than_this, bool * pmountable)
2815{
2816
2817    /*@ buffers ********************************************* */
2818    char *tmp;
2819    char *tmp1;
2820    char *szmsg;
2821    char *cdrom_dev;
2822    char *cdrw_device = NULL;
2823    char *our_serial_str;
2824    bool ok_go_ahead_burn_it;
2825    int cd_number = -1;
2826    int attempt_to_mount_returned_this = 999;
2827    char *mtpt;
2828    char *szcdno;
2829    char *szserfname;
2830    char *szunmount;
2831
2832    mr_asprintf(&szmsg, "I am about to burn %s #%d",
2833             g_backup_media_string,
2834             g_current_media_number);
2835    log_to_screen(szmsg);
2836    mr_free(szmsg);
2837    if (g_current_media_number < ask_for_one_if_more_than_this) {
2838        return;
2839    }
2840    log_to_screen("Scanning CD-ROM drive...");
2841    mr_asprintf(&mtpt, "/tmp/cd.mtpt.%ld.%ld", (long int) random(),
2842             (long int) random());
2843    make_hole_for_dir(mtpt);
2844
2845  gotos_make_me_puke:
2846    ok_go_ahead_burn_it = TRUE;
2847    cdrom_dev = find_cdrom_device(FALSE);
2848    if (cdrom_dev != NULL) {
2849/* When enabled, it made CD eject-and-retract when wrong CD inserted.. Weird
2850      log_msg(2, "paafcd: Retracting CD-ROM drive if possible" );
2851      retract_CD_tray_and_defeat_autorun();
2852*/
2853        mr_asprintf(&tmp, "umount %s", cdrom_dev);
2854        run_program_and_log_output(tmp, 1);
2855        mr_free(tmp);
2856        mr_asprintf(&szcdno, "%s/archives/THIS-CD-NUMBER", mtpt);
2857        mr_asprintf(&szserfname, "%s/archives/SERIAL-STRING", mtpt);
2858        mr_asprintf(&szunmount, "umount %s", mtpt);
2859        cd_number = -1;
2860        mr_asprintf(&tmp, "mount %s %s", cdrom_dev, mtpt);
2861        if ((attempt_to_mount_returned_this =
2862             run_program_and_log_output(tmp, 1))) {
2863            log_msg(4, "Failed to mount %s at %s", cdrom_dev, mtpt);
2864            log_to_screen("If there's a CD/DVD in the drive, it's blank.");
2865            mr_asprintf(&our_serial_str, "%s", "");
2866        } else if (!does_file_exist(szcdno)
2867                   || !does_file_exist(szserfname)) {
2868            log_to_screen
2869                ("%s has data on it but it's probably not a Mondo CD.",
2870                 g_backup_media_string);
2871            mr_asprintf(&our_serial_str, "%s", "");
2872        } else {
2873            log_to_screen("%s found in drive. It's a Mondo disk.",
2874                          g_backup_media_string);
2875            tmp1 = last_line_of_file(szcdno);
2876            cd_number = atoi(tmp1);
2877            mr_free(tmp1);
2878            mr_asprintf(&tmp1, "cat %s 2> /dev/null", szserfname);
2879            our_serial_str = call_program_and_get_last_line_of_output(tmp1);
2880            mr_free(tmp1);
2881            // FIXME - should be able to use last_line_of_file(), surely?
2882        }
2883        mr_free(szcdno);
2884        mr_free(szserfname);
2885        mr_free(tmp);
2886
2887        run_program_and_log_output(szunmount, 1);
2888        mr_free(szunmount);
2889
2890        log_msg(2, "paafcd: cd_number = %d", cd_number);
2891        log_msg(2, "our serial str = %s; g_serial_string = %s",
2892                our_serial_str, g_serial_string);
2893        if (cd_number > 0 && !strcmp(our_serial_str, g_serial_string)) {
2894            log_msg(2, "This %s is part of this backup set!",
2895                    g_backup_media_string);
2896            ok_go_ahead_burn_it = FALSE;
2897            if (cd_number == g_current_media_number - 1) {
2898                log_to_screen
2899                    ("I think you've left the previous %s in the drive.",
2900                     g_backup_media_string);
2901            } else {
2902                log_to_screen
2903                    ("Please remove this %s. It is part of the backup set you're making now.",
2904                     g_backup_media_string);
2905            }
2906        } else {
2907            log_to_screen("...but not part of _our_ backup set.");
2908        }
2909        mr_free(our_serial_str);
2910    } else {
2911        log_msg(2,
2912                "paafcd: Can't find CD-ROM drive. Perhaps it has a blank %s in it?",
2913                g_backup_media_string);
2914        if ((cdrw_device = interrogate_disk_currently_in_cdrw_drive(cdrw_device)) != NULL) {
2915            ok_go_ahead_burn_it = FALSE;
2916            log_to_screen("There isn't a writable %s in the drive.",
2917                          g_backup_media_string);
2918        }
2919        mr_free(cdrw_device);
2920    }
2921    mr_free(mtpt);
2922
2923    if (!ok_go_ahead_burn_it) {
2924        eject_device(cdrom_dev);
2925        mr_asprintf(&tmp,
2926                 "I am about to burn %s #%d of the backup set. Please insert %s and press Enter.",
2927                 g_backup_media_string,
2928                 g_current_media_number,
2929                 g_backup_media_string);
2930        popup_and_OK(tmp);
2931        mr_free(tmp);
2932        goto gotos_make_me_puke;
2933    } else {
2934        log_msg(2, "paafcd: OK, going ahead and burning it.");
2935    }
2936    mr_free(cdrom_dev);
2937
2938    log_msg(2,
2939            "paafcd: OK, I assume I have a blank/reusable %s in the drive...",
2940            g_backup_media_string);
2941
2942    log_to_screen("Proceeding w/ %s in drive.",
2943                  g_backup_media_string);
2944    if (pmountable) {
2945        if (attempt_to_mount_returned_this) {
2946            *pmountable = FALSE;
2947        } else {
2948            *pmountable = TRUE;
2949        }
2950    }
2951
2952}
2953
2954
2955/**
2956 * Set the <tt>N</tt>th bit of @c array to @c true_or_false.
2957 * @param array The bit array (as a @c char pointer).
2958 * @param N The bit number to set or reset.
2959 * @param true_or_false If TRUE then set bit @c N, if FALSE then reset bit @c N.
2960 * @see get_bit_N_of_array
2961 */
2962void set_bit_N_of_array(char *array, int N, bool true_or_false)
2963{
2964    int bit_number;
2965    int mask, orig_val, to_add;
2966    int element_number;
2967
2968    assert(array != NULL);
2969
2970    element_number = N / 8;
2971    bit_number = N % 8;
2972    to_add = (1 << bit_number);
2973    mask = 255 - to_add;
2974    orig_val = array[element_number] & mask;
2975    //  log_it("array[%d]=%02x; %02x&%02x = %02x", element_number, array[element_number], mask, orig_val);
2976    if (true_or_false) {
2977        array[element_number] = orig_val | to_add;
2978    }
2979}
2980
2981/* @} - end of utilityGroup */
2982
2983
2984/**
2985 * Chop up @c filename.
2986 * @param bkpinfo The backup information structure. Fields used:
2987 * - @c backup_media_type
2988 * - @c compression_level
2989 * - @c optimal_set_size
2990 * - @c tmpdir
2991 * - @c use_lzo
2992 * - @c zip_exe
2993 * - @c zip_suffix
2994 *
2995 * @param biggie_filename The file to chop up.
2996 * @param ntfsprog_fifo The FIFO to ntfsclone if this is an imagedev, NULL otherwise.
2997 * @param biggie_file_number The sequence number of this biggie file (starting from 0).
2998 * @param noof_biggie_files The number of biggie files there are total.
2999 * @return The number of errors encountered (0 for success)
3000 * @see make_slices_and_images
3001 * @ingroup LLarchiveGroup
3002 */
3003int
3004slice_up_file_etc(struct s_bkpinfo *bkpinfo, char *biggie_filename,
3005                  char *ntfsprog_fifo, long biggie_file_number,
3006                  long noof_biggie_files, bool use_ntfsprog)
3007{
3008
3009    /*@ buffers ************************************************** */
3010    char *tmp, *checksum_line = NULL, *command;
3011    char *tempblock;
3012    char *curr_slice_fname_uncompressed;
3013    char *curr_slice_fname_compressed;
3014    char *file_to_archive;
3015    char *file_to_openin;
3016    /*@ pointers ************************************************** */
3017    char *pB;
3018    FILE *fin, *fout;
3019
3020    /*@ bool ****************************************************** */
3021    bool finished = FALSE;
3022
3023    /*@ long ****************************************************** */
3024    size_t blksize = 0;
3025    long slice_num = 0;
3026    long i;
3027    long optimal_set_size;
3028    bool should_I_compress_slices;
3029    char *suffix;               // for compressed slices
3030
3031    /*@ long long ************************************************** */
3032    off_t totalread = (off_t)0;
3033    off_t totallength = (off_t)0;
3034    off_t length;
3035
3036    /*@ int ******************************************************** */
3037    int retval = 0;
3038    int res = 0;
3039    size_t n = 0;
3040
3041    /*@ structures ************************************************** */
3042    struct s_filename_and_lstat_info biggiestruct;
3043//  struct stat statbuf;
3044
3045    assert(bkpinfo != NULL);
3046    assert_string_is_neither_NULL_nor_zerolength(biggie_filename);
3047
3048    biggiestruct.for_backward_compatibility = '\n';
3049    biggiestruct.use_ntfsprog = use_ntfsprog;
3050    optimal_set_size = bkpinfo->optimal_set_size;
3051    if (is_this_file_compressed(biggie_filename)
3052        || bkpinfo->compression_level == 0) {
3053        mr_asprintf(&suffix, "%s", "");
3054        //      log_it("%s is indeed compressed :-)", filename);
3055        should_I_compress_slices = FALSE;
3056    } else {
3057        mr_asprintf(&suffix, "%s", bkpinfo->zip_suffix);
3058        should_I_compress_slices = TRUE;
3059    }
3060
3061    if (optimal_set_size < 999) {
3062        fatal_error("bkpinfo->optimal_set_size is insanely small");
3063    }
3064    if (ntfsprog_fifo) {
3065        file_to_openin = ntfsprog_fifo;
3066        mr_asprintf(&checksum_line, "IGNORE");
3067        log_msg(2,
3068                "Not calculating checksum for %s: it would take too long",
3069                biggie_filename);
3070        tmp = find_home_of_exe("ntfsresize");
3071        if ( !tmp) {
3072            fatal_error("ntfsresize not found");
3073        }
3074        mr_free(tmp);
3075
3076        mr_asprintf(&command, "ntfsresize --force --info %s|grep '^You might resize at '|cut -d' ' -f5", biggie_filename);
3077        log_it("command = %s", command);
3078        tmp = call_program_and_get_last_line_of_output(command);
3079        mr_free(command);
3080
3081        log_it("res of it = %s", tmp); 
3082        totallength = (off_t)atoll(tmp);
3083        mr_free(tmp);
3084    } else {
3085        file_to_openin = biggie_filename;
3086        if (strchr(biggie_filename,'\'') != NULL) {
3087            mr_asprintf(&command, "md5sum \"%s\"", biggie_filename);
3088        } else {
3089            mr_asprintf(&command, "md5sum '%s'", biggie_filename);
3090        }
3091        if (!(fin = popen(command, "r"))) {
3092            log_OS_error("Unable to popen-in command");
3093            mr_free(command);
3094            return (1);
3095        }
3096        mr_free(command);
3097        mr_getline(&checksum_line, &n, fin);
3098        pclose(fin);
3099        totallength = length_of_file (biggie_filename);
3100    }
3101    lstat(biggie_filename, &biggiestruct.properties);
3102    if (strlen(checksum_line) <= MAX_STR_LEN) {
3103        strcpy(biggiestruct.filename, biggie_filename);
3104    } else {
3105        fatal_error("biggie_filename too big");
3106    }
3107    pB = strchr(checksum_line, ' ');
3108    if (!pB) {
3109        pB = strchr(checksum_line, '\t');
3110    }
3111    if (pB) {
3112        *pB = '\0';
3113    }
3114    if (strlen(checksum_line) <= 64) {
3115        strcpy(biggiestruct.checksum, checksum_line);
3116    } else {
3117        fatal_error("checksum_line too big");
3118    }
3119    mr_free(checksum_line);
3120
3121    tmp = slice_fname(biggie_file_number, 0, bkpinfo->tmpdir, "");
3122    fout = fopen(tmp, "w");
3123    mr_free(tmp);
3124    (void) fwrite((void *) &biggiestruct, 1, sizeof(biggiestruct), fout);
3125    paranoid_fclose(fout);
3126    length = totallength / optimal_set_size / 1024;
3127    log_msg(1, "Opening in %s; slicing it and writing to CD/tape",
3128            file_to_openin);
3129    if (!(fin = fopen(file_to_openin, "r"))) {
3130        log_OS_error("Unable to openin biggie_filename");
3131        mr_asprintf(&tmp, "Cannot archive bigfile '%s': not found",
3132                 biggie_filename);
3133        log_to_screen(tmp);
3134        mr_free(tmp);
3135
3136        mr_free(suffix);
3137        return (1);
3138    }
3139    tmp = slice_fname(biggie_file_number, 0,bkpinfo->tmpdir, "");
3140    if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
3141        res = move_files_to_stream(bkpinfo,tmp,NULL);
3142    } else {
3143        res = move_files_to_cd(bkpinfo, tmp, NULL);
3144    }
3145    mr_free(tmp);
3146    i = bkpinfo->optimal_set_size / 256;
3147    for (slice_num = 1; !finished; slice_num++) {
3148        curr_slice_fname_uncompressed = slice_fname(biggie_file_number, slice_num, bkpinfo->tmpdir, "");
3149        curr_slice_fname_compressed = slice_fname(biggie_file_number, slice_num, bkpinfo->tmpdir, suffix);
3150
3151        tmp = percent_media_full_comment(bkpinfo);
3152        update_progress_form(tmp);
3153        mr_free(tmp);
3154
3155        if (!(fout = fopen(curr_slice_fname_uncompressed, "w"))) {
3156            log_OS_error(curr_slice_fname_uncompressed);
3157
3158            mr_free(curr_slice_fname_uncompressed);
3159            mr_free(curr_slice_fname_compressed);
3160            mr_free(suffix);
3161            return (1);
3162        }
3163        if (!(tempblock = (char *) malloc(256 * 1024))) {
3164            fatal_error("malloc error 256*1024");
3165        }
3166        if ((i == bkpinfo->optimal_set_size / 256)
3167            && (totalread < 1.1 * totallength)) {
3168            for (i = 0; i < bkpinfo->optimal_set_size / 256; i++) {
3169                blksize = fread(tempblock, 1, 256 * 1024, fin);
3170                if (blksize > 0) {
3171                    totalread = totalread + blksize;
3172                    (void) fwrite(tempblock, 1, blksize, fout);
3173                } else {
3174                    break;
3175                }
3176            }
3177        } else {
3178            i = 0;
3179        }
3180        mr_free(tempblock);
3181        paranoid_fclose(fout);
3182        if (i > 0)              // length_of_file (curr_slice_fname_uncompressed)
3183        {
3184            if (!does_file_exist(curr_slice_fname_uncompressed)) {
3185                log_msg(2,
3186                        "Warning - '%s' doesn't exist. How can I compress slice?",
3187                        curr_slice_fname_uncompressed);
3188            }
3189            if (should_I_compress_slices && bkpinfo->compression_level > 0) {
3190                mr_asprintf(&command, "%s -%d %s", bkpinfo->zip_exe,
3191                         bkpinfo->compression_level,
3192                         curr_slice_fname_uncompressed);
3193                log_msg(2, command);
3194                if ((res = system(command))) {
3195                    log_OS_error(command);
3196                }
3197                //              did_I_compress_slice = TRUE;
3198            } else {
3199                /* BERLIOS: Useless
3200                   mr_asprintf(&command, "mv %s %s 2>> %s",
3201                   curr_slice_fname_uncompressed,
3202                   curr_slice_fname_compressed, MONDO_LOGFILE);
3203                 */
3204                res = 0;        // don't do it :)
3205                //              did_I_compress_slice = FALSE;
3206            }
3207            retval += res;
3208            if (res) {
3209                log_msg(2, "Failed to compress the slice");
3210            }
3211            if (bkpinfo->use_lzo
3212                && strcmp(curr_slice_fname_compressed,
3213                          curr_slice_fname_uncompressed)) {
3214                unlink(curr_slice_fname_uncompressed);
3215            }
3216            if (res) {
3217                mr_asprintf(&tmp, "Problem with slice # %ld", slice_num);
3218            } else {
3219                mr_asprintf(&tmp,
3220                         "%s - Bigfile #%ld, slice #%ld compressed OK          ",
3221                         biggie_filename, biggie_file_number + 1,
3222                         slice_num);
3223            }
3224#ifndef _XWIN
3225            if (!g_text_mode) {
3226                newtDrawRootText(0, g_noof_rows - 2, tmp);
3227                newtRefresh();
3228            } else {
3229                log_msg(2, tmp);
3230            }
3231#else
3232            log_msg(2, tmp);
3233#endif
3234            mr_free(tmp);
3235            mr_asprintf(&file_to_archive, "%s", curr_slice_fname_compressed);
3236            g_current_progress++;
3237        } else {                /* if i==0 then ... */
3238
3239            finished = TRUE;
3240            mr_asprintf(&file_to_archive, "%s",
3241                     curr_slice_fname_uncompressed);
3242            if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
3243                break;
3244            }
3245        }
3246
3247        if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
3248            register_in_tape_catalog(biggieslice, biggie_file_number,
3249                                     slice_num, file_to_archive);
3250            maintain_collection_of_recent_archives(bkpinfo->tmpdir,
3251                                                   file_to_archive);
3252            res = move_files_to_stream(bkpinfo, file_to_archive, NULL);
3253        } else {
3254            res = move_files_to_cd(bkpinfo, file_to_archive, NULL);
3255        }
3256        mr_free(file_to_archive);
3257        retval += res;
3258        if (res) {
3259            mr_asprintf(&tmp,
3260                     "Failed to add slice %ld of bigfile %ld to scratchdir",
3261                     slice_num, biggie_file_number + 1);
3262            log_to_screen(tmp);
3263            mr_free(tmp);
3264            fatal_error
3265                ("Hard disk full. You should have bought a bigger one.");
3266        }
3267        mr_free(curr_slice_fname_uncompressed);
3268        mr_free(curr_slice_fname_compressed);
3269    }
3270    mr_free(suffix);
3271    paranoid_fclose(fin);
3272    if (retval) {
3273        mr_asprintf(&tmp, "Sliced bigfile #%ld...FAILED",
3274                 biggie_file_number + 1);
3275    } else {
3276        mr_asprintf(&tmp, "Sliced bigfile #%ld...OK!",
3277                 biggie_file_number + 1);
3278    }
3279    log_msg(1, tmp);
3280    mr_free(tmp);
3281    return (retval);
3282}
3283
3284
3285/**
3286 * Remove the archives in @c d.
3287 * This could possibly include any of:
3288 * - all afioballs (compressed and not)
3289 * - all filelists
3290 * - all slices
3291 * - all checksums
3292 * - a zero filler file
3293 *
3294 * @param d The directory to wipe the archives from.
3295 * @ingroup utilityGroup
3296 */
3297void wipe_archives(char *d)
3298{
3299    /*@ buffers ********************************************* */
3300    char *tmp;
3301    char *dir;
3302
3303    assert_string_is_neither_NULL_nor_zerolength(d);
3304
3305    mr_asprintf(&dir, "%s/archives", d);
3306    mr_asprintf(&tmp, "find %s -name '*.afio*' -exec rm -f '{}' \\;", dir);
3307    run_program_and_log_output(tmp, FALSE);
3308    mr_free(tmp);
3309
3310    mr_asprintf(&tmp, "find %s -name '*list.[0-9]*' -exec rm -f '{}' \\;",
3311             dir);
3312    run_program_and_log_output(tmp, FALSE);
3313    mr_free(tmp);
3314
3315    mr_asprintf(&tmp, "find %s -name 'slice*' -exec rm -f '{}' \\;", dir);
3316    run_program_and_log_output(tmp, FALSE);
3317    mr_free(tmp);
3318
3319    mr_asprintf(&tmp, "rm -f %s/cklist*", dir);
3320    run_program_and_log_output(tmp, FALSE);
3321    mr_free(tmp);
3322
3323    mr_asprintf(&tmp, "rm -f %s/zero", dir);
3324    run_program_and_log_output(tmp, FALSE);
3325    mr_free(tmp);
3326
3327    log_msg(1, "Wiped %s's archives", dir);
3328    mr_asprintf(&tmp, "ls -l %s", dir);
3329    run_program_and_log_output(tmp, FALSE);
3330    mr_free(tmp);
3331
3332    mr_free(dir);
3333}
3334
3335
3336/**
3337 * @addtogroup LLarchiveGroup
3338 * @{
3339 */
3340/**
3341 * Write the final ISO image.
3342 * @param bkpinfo The backup information structure. Used only
3343 * in the call to @c write_iso_and_go_on().
3344 * @return The number of errors encountered (0 for success)
3345 * @see write_iso_and_go_on
3346 * @see make_iso_fs
3347 * @bug The final ISO is written even if there are no files on it. In practice,
3348 * however, this occurs rarely.
3349 */
3350int write_final_iso_if_necessary(struct s_bkpinfo *bkpinfo)
3351{
3352    /*@ int ***************************************************** */
3353    int res;
3354
3355    /*@ buffers ************************************************** */
3356    char *tmp;
3357
3358    assert(bkpinfo != NULL);
3359
3360// I should really check if there are any slices or tarballs to be copied to CD-R(W)'s; the odds are approx. 1 in a million that there are no files here, so I'll just go ahead & make one more CD anyway
3361
3362    mr_asprintf(&tmp, "Writing the final ISO");
3363    log_msg(2, tmp);
3364    /* BERLIOS: center_string is now broken
3365       center_string(tmp, 80);
3366     */
3367#ifndef _XWIN
3368    if (!g_text_mode) {
3369        newtPushHelpLine(tmp);
3370    }
3371#endif
3372    mr_free(tmp);
3373    res = write_iso_and_go_on(bkpinfo, TRUE);
3374#ifndef _XWIN
3375    if (!g_text_mode) {
3376        newtPopHelpLine();
3377    }
3378#endif
3379    log_msg(2, "Returning from writing final ISO (res=%d)", res);
3380    return (res);
3381}
3382
3383
3384/**
3385 * Write an ISO image to <tt>[bkpinfo->isodir]/bkpinfo->prefix-[g_current_media_number].iso</tt>.
3386 * @param bkpinfo The backup information structure. Fields used:
3387 * - @c backup_media_type
3388 * - @c prefix
3389 * - @c isodir
3390 * - @c manual_cd_tray
3391 * - @c media_size
3392 * - @c nfs_mount
3393 * - @c nfs_remote_dir
3394 * - @c scratchdir
3395 * - @c verify_data
3396 *
3397 * @param last_cd If TRUE, this is the last CD to write; if FALSE, it's not.
3398 * @return The number of errors encountered (0 for success)
3399 * @see make_iso_fs
3400 */
3401int write_iso_and_go_on(struct s_bkpinfo *bkpinfo, bool last_cd)
3402{
3403    /*@ pointers **************************************************** */
3404    FILE *fout;
3405
3406    /*@ buffers ***************************************************** */
3407    char *tmp;
3408    char *cdno_fname;
3409    char *lastcd_fname;
3410    char *isofile;
3411
3412    /*@ bool ******************************************************** */
3413    bool that_one_was_ok;
3414    bool using_nfs;
3415    bool orig_vfy_flag_val;
3416
3417    /*@ int *********************************************************** */
3418    int res = 0;
3419
3420    assert(bkpinfo != NULL);
3421    orig_vfy_flag_val = bkpinfo->verify_data;
3422    if (bkpinfo->media_size[g_current_media_number] <= 0) {
3423        fatal_error("write_iso_and_go_on() - unknown media size");
3424    }
3425
3426    if (strlen(bkpinfo->nfs_mount) > 1) {
3427        using_nfs = TRUE;
3428    } else {
3429        using_nfs = FALSE;
3430    }
3431    log_msg(1, "OK, time to make %s #%d",
3432            bkpinfo->backup_media_string,
3433            g_current_media_number);
3434
3435    /* label the ISO with its number */
3436
3437    mr_asprintf(&cdno_fname, "%s/archives/THIS-CD-NUMBER",
3438             bkpinfo->scratchdir);
3439    fout = fopen(cdno_fname, "w");
3440    fprintf(fout, "%d", g_current_media_number);
3441    paranoid_fclose(fout);
3442    mr_free(cdno_fname);
3443
3444    mr_asprintf(&tmp, "cp -f %s/autorun %s/", g_mondo_home,
3445             bkpinfo->scratchdir);
3446    if (run_program_and_log_output(tmp, FALSE)) {
3447        log_msg(2, "Warning - unable to copy autorun to scratchdir");
3448    }
3449    mr_free(tmp);
3450
3451    /* last CD or not? Label accordingly */
3452    mr_asprintf(&lastcd_fname, "%s/archives/NOT-THE-LAST",
3453             bkpinfo->scratchdir);
3454    if (last_cd) {
3455        unlink(lastcd_fname);
3456        log_msg(2,
3457                "OK, you're telling me this is the last CD. Fair enough.");
3458    } else {
3459        fout = fopen(lastcd_fname, "w");
3460        fprintf(fout,
3461                "You're listening to 90.3 WPLN, Nashville Public Radio.\n");
3462        paranoid_fclose(fout);
3463    }
3464    mr_free(lastcd_fname);
3465
3466    if (space_occupied_by_cd(bkpinfo->scratchdir) / 1024 >
3467        bkpinfo->media_size[g_current_media_number]) {
3468        mr_asprintf(&tmp,
3469                 "Warning! CD is too big. It occupies %ld KB, which is more than the %ld KB allowed.",
3470                 (long) space_occupied_by_cd(bkpinfo->scratchdir),
3471                 (long) bkpinfo->media_size[g_current_media_number]);
3472        log_to_screen(tmp);
3473        mr_free(tmp);
3474    }
3475    mr_asprintf(&isofile, "%s/%s/%s-%d.iso", bkpinfo->isodir,
3476             bkpinfo->nfs_remote_dir, bkpinfo->prefix,
3477             g_current_media_number);
3478    for (that_one_was_ok = FALSE; !that_one_was_ok;) {
3479        res = make_iso_fs(bkpinfo, isofile);
3480        if (g_current_media_number == 1 && !res
3481            && (bkpinfo->backup_media_type == cdr
3482                || bkpinfo->backup_media_type == cdrw)) {
3483            if ((tmp = find_cdrom_device(FALSE)) == NULL)   // make sure find_cdrom_device() finds, records CD-R's loc
3484            {
3485                log_msg(3, "*Sigh* Mike, I hate your computer.");
3486                bkpinfo->manual_cd_tray = TRUE;
3487            }                   // if it can't be found then force pausing
3488            else {
3489                log_msg(3, "Great. Found Mike's CD-ROM drive.");
3490                mr_free(tmp);
3491            }
3492        }
3493        if (bkpinfo->verify_data && !res) {
3494            log_to_screen
3495                ("Please reboot from the 1st %s in Compare Mode, as a precaution.",
3496                 g_backup_media_string);
3497            chdir("/");
3498            iamhere("Before calling verify_cd_image()");
3499            res += verify_cd_image(bkpinfo);
3500            iamhere("After calling verify_cd_image()");
3501        }
3502        if (!res) {
3503            that_one_was_ok = TRUE;
3504        } else {
3505            mr_asprintf(&tmp, "Failed to burn %s #%d. Retry?",
3506                     bkpinfo->backup_media_string,
3507                     g_current_media_number);
3508            res = ask_me_yes_or_no(tmp);
3509            mr_free(tmp);
3510            if (!res) {
3511                if (ask_me_yes_or_no("Abort the backup?")) {
3512                    fatal_error("FAILED TO BACKUP");
3513                } else {
3514                    break;
3515                }
3516            } else {
3517                log_msg(2, "Retrying, at user's request...");
3518                res = 0;
3519            }
3520        }
3521    }
3522/*
3523  if (using_nfs)
3524    {
3525      mr_asprintf(&tmp,"mv -f %s %s/%s/", isofile, bkpinfo->isodir, bkpinfo->nfs_remote_dir);
3526      if (run_program_and_log_output(tmp, FALSE))
3527        { log_to_screen("Unable to move ISO to NFS dir"); }
3528    }
3529*/
3530    mr_free(isofile);
3531
3532    g_current_media_number++;
3533    if (g_current_media_number > MAX_NOOF_MEDIA) {
3534        fatal_error("Too many CD-R(W)'s. Use tape or net.");
3535    }
3536    wipe_archives(bkpinfo->scratchdir);
3537    mr_asprintf(&tmp, "rm -Rf %s/images/*gz %s/images/*data*img",
3538             bkpinfo->scratchdir, bkpinfo->scratchdir);
3539    if (system(tmp)) {
3540        log_msg(2,
3541                "Error occurred when I tried to delete the redundant IMGs and GZs");
3542    }
3543    mr_free(tmp);
3544
3545    if (last_cd) {
3546        log_msg(2, "This was your last CD.");
3547    } else {
3548        log_msg(2, "Continuing to backup your data...");
3549    }
3550
3551    bkpinfo->verify_data = orig_vfy_flag_val;
3552    return (0);
3553}
3554
3555/* @} - end of LLarchiveGroup */
3556
3557
3558/**
3559 * Verify the user's data.
3560 * @param bkpinfo The backup information structure. Fields used:
3561 * - @c backup_data
3562 * - @c backup_media_type
3563 * - @c media_device
3564 * - @c verify_data
3565 *
3566 * @return The number of errors encountered (0 for success)
3567 * @ingroup verifyGroup
3568 */
3569int verify_data(struct s_bkpinfo *bkpinfo)
3570{
3571    int res = 0, retval = 0, cdno = 0;
3572    char *tmp;
3573    long diffs = 0;
3574
3575    assert(bkpinfo != NULL);
3576    if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
3577        chdir("/");
3578        mvaddstr_and_log_it(g_currentY, 0,
3579                            "Verifying archives against live filesystem");
3580        if (bkpinfo->backup_media_type == cdstream) {
3581            mr_allocstr(bkpinfo->media_device,"/dev/cdrom");
3582        }
3583        verify_tape_backups(bkpinfo);
3584        mvaddstr_and_log_it(g_currentY++, 74, "Done.");
3585    } else if (bkpinfo->backup_data)
3586        //bkpinfo->backup_media_type == cdrw || bkpinfo->backup_media_type == cdr))
3587    {
3588        log_msg(2,
3589                "Not verifying again. Per-CD/ISO verification already carried out.");
3590        paranoid_system
3591            ("cat /tmp/changed.files.* > /tmp/changed.files 2> /dev/null");
3592    } else {
3593        g_current_media_number = cdno;
3594        if (bkpinfo->backup_media_type != iso) {
3595            bkpinfo->media_device = find_cdrom_device(FALSE);
3596        }
3597        chdir("/");
3598        for (cdno = 1; cdno < 99 && bkpinfo->verify_data; cdno++) {
3599            if (cdno != g_current_media_number) {
3600                log_msg(2,
3601                        "Warning - had to change g_current_media_number from %d to %d",
3602                        g_current_media_number, cdno);
3603                g_current_media_number = cdno;
3604            }
3605            if (bkpinfo->backup_media_type != iso) {
3606                insist_on_this_cd_number(bkpinfo, cdno);
3607            }
3608            res = verify_cd_image(bkpinfo); // sets verify_data to FALSE if it's time to stop verifying
3609            retval += res;
3610            if (res) {
3611                mr_asprintf(&tmp,
3612                         "Warnings/errors were reported while checking %s #%d",
3613                         bkpinfo->backup_media_string,
3614                         g_current_media_number);
3615                log_to_screen(tmp);
3616                mr_free(tmp);
3617
3618            }
3619        }
3620        mr_asprintf(&tmp,
3621                 "grep 'afio: ' %s | sed 's/afio: //' | grep -vx '/dev/.*' >> /tmp/changed.files",
3622                 MONDO_LOGFILE);
3623        system(tmp);
3624        mr_free(tmp);
3625
3626        mr_asprintf(&tmp,
3627                 "grep 'star: ' %s | sed 's/star: //' | grep -vx '/dev/.*' >> /tmp/changed.files",
3628                 MONDO_LOGFILE);
3629        system(tmp);
3630        mr_free(tmp);
3631
3632        run_program_and_log_output("umount " MNT_CDROM, FALSE);
3633        eject_device(bkpinfo->media_device);
3634    }
3635    diffs = count_lines_in_file("/tmp/changed.files");
3636
3637    if (diffs > 0) {
3638        if (retval == 0) {
3639            retval = (int) (-diffs);
3640        }
3641    }
3642    return (retval);
3643}
3644
3645
3646/**
3647 * @addtogroup utilityGroup
3648 * @{
3649 */
3650/**
3651 * Write an image to a real 3.5" floppy disk.
3652 * @param device The device to write to (e.g. @c /dev/fd0)
3653 * @param datafile The image to write to @p device.
3654 * @return The number of errors encountered (0 for success)
3655 * @see write_image_to_floppy
3656 */
3657int write_image_to_floppy_SUB(char *device, char *datafile)
3658{
3659    /*@ int *************************************************************** */
3660    int res = 0;
3661    int percentage = 0;
3662    int blockno = 0;
3663    int maxblocks = 0;
3664
3665    /*@ buffers************************************************************ */
3666    char *tmp;
3667    char blk[1024];
3668    char *title;
3669
3670    /*@ pointers ********************************************************** */
3671    char *p;
3672    FILE *fout, *fin;
3673
3674
3675    /* pretty stuff */
3676    if (!(p = strrchr(datafile, '/'))) {
3677        p = datafile;
3678    } else {
3679        p++;
3680    }
3681    mr_asprintf(&title, "Writing %s to floppy", p);
3682    open_evalcall_form(title);
3683    mr_free(title);
3684
3685    /* functional stuff */
3686    for (p = device + strlen(device); p != device && isdigit(*(p - 1));
3687         p--);
3688    maxblocks = atoi(p);
3689    if (!maxblocks) {
3690        maxblocks = 1440;
3691    }
3692    mr_asprintf(&tmp, "maxblocks = %d; p=%s", maxblocks, p);
3693    log_msg(2, tmp);
3694    mr_free(tmp);
3695
3696    /* copy data from image to floppy */
3697    if (!(fin = fopen(datafile, "r"))) {
3698        log_OS_error("Cannot open img");
3699        return (1);
3700    }
3701    if (!(fout = fopen(device, "w"))) {
3702        log_OS_error("Cannot open fdd");
3703        return (1);
3704    }
3705    for (blockno = 0; blockno < maxblocks; blockno++) {
3706        percentage = blockno * 100 / maxblocks;
3707        if (fread(blk, 1, 1024, fin) != 1024) {
3708            if (feof(fin)) {
3709                log_msg(1,
3710                        "img read err - img ended prematurely - non-fatal error");
3711                sleep(3);
3712                return (res);
3713            }
3714            res++;
3715            log_to_screen("img read err");
3716        }
3717        if (fwrite(blk, 1, 1024, fout) != 1024) {
3718            res++;
3719            log_to_screen("fdd write err");
3720        }
3721        if (((blockno + 1) % 128) == 0) {
3722            sync(); /* fflush doesn't work; dunno why */
3723            update_evalcall_form(percentage);
3724        }
3725    }
3726    paranoid_fclose(fin);
3727    paranoid_fclose(fout);
3728    close_evalcall_form();
3729    return (res);
3730}
3731
3732
3733/**
3734 * Wrapper around @c write_image_to_floppy_SUB().
3735 * This function, unlike @c write_image_to_floppy_SUB(),
3736 * gives the user the opportunity to retry if the write fails.
3737 * @see write_image_to_floppy_SUB
3738 */
3739int write_image_to_floppy(char *device, char *datafile)
3740{
3741    /*@ int ************************************************************** */
3742    int res = 0;
3743
3744    assert_string_is_neither_NULL_nor_zerolength(device);
3745    assert_string_is_neither_NULL_nor_zerolength(datafile);
3746
3747    while ((res = write_image_to_floppy_SUB(device, datafile))) {
3748        if (!ask_me_yes_or_no("Failed to write image to floppy. Retry?")) {
3749            return (res);
3750        }
3751    }
3752    return (res);
3753}
3754
3755/* @} - end of utilityGroup */
3756
3757void setenv_mondo_share(void) {
3758
3759setenv("MONDO_SHARE", MONDO_SHARE, 1);
3760}
3761
3762void mr_archive_init_conf(struct s_mr_conf *mr_conf) {
3763    char *command = NULL;
3764    FILE *fin = NULL;
3765    size_t n = 0;
3766    char *param = NULL;
3767
3768    mr_conf = (struct s_mr_conf *)mr_malloc(sizeof(struct s_mr_conf));
3769
3770    /* mindi conf parameters also needed in mondo */
3771    mr_asprintf(&command, "mindi -printvar IA64_BOOT_SIZE");
3772    fin = popen(command, "r");
3773    mr_getline(&param, &n, fin);
3774    pclose(fin);
3775    mr_free(command);
3776
3777    mr_conf->mindi_ia64_boot_size = atoi(param);
3778    mr_free(param);
3779
3780    /* Finds mondo conf file */
3781    mr_conf_open(MONDO_CONF_DIR"/mondo.conf");
3782
3783    /* mondo conf parameters needed */
3784    if ((mr_conf->mondo_iso_creation_cmd = mr_conf_sread("mondo_iso_creation_cmd")) == NULL) {;
3785        mr_log_exit(-1,"Unable to get mondo_iso_creation_cmd parameter from conf file\nAborting...\n");
3786    }
3787
3788    if ((mr_conf->mondo_logfile = mr_conf_sread("mondo_logfile")) == NULL) {
3789        mr_log_exit(-1,"Unable to get mondo_logfile parameter from conf file\nAborting...\n");
3790    }
3791
3792    mr_conf_close();
3793}
Note: See TracBrowser for help on using the repository browser.