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

Last change on this file since 68 was 68, checked in by andree, 14 years ago

At the end of function run_program_and_log_to_screen, paranoid_pclose is
used to close the process stream. This means - as we don't evaluate the
exit code of the called program - that mondoarchive will happily
continue even if mondo has failed. Only later will it give an error when
it tries to burn an image that miondi has actually failed to create.

The change to libmondo-fork.c.diff addresses this by using pclose
directly (rather than the paranoid_pclose macro) and by then evaluating
the status information and extracting the exit code of the called
program.

The change to libmondo-archive.c makes it so that at the end of function
call_mindi_to_supply_boot_disks popup_and_OK is called in case of an
error rather than log_to_screen. This ensures that the main error is not
drowned in a sea of other messages.

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