source: branches/stable/mondo/src/common/libmondo-archive.c @ 1770

Last change on this file since 1770 was 1770, checked in by bruno, 12 years ago
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod? silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian? keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René? Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

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