source: branches/2.2.2/mondo/src/common/libmondo-archive.c @ 1315

Last change on this file since 1315 was 1315, checked in by bruno, 12 years ago

Log files are now consistent: mondoarchive.log for mondoarchive (containing also mindi.log) and mondorestore.log for mondorestore (copied from /tmp (ram) to /var/log (disk) at the end of the restore)
One include has been created for each bianry containing only that declaration ofr the moment, but which will be extended to include all local definitions (ps_* e.g.)
Doc updated accordingly
LOGFILE in restore process is now passed in the environment and not duplicated anymore
LogIt? is not redifined either
LOGFILE should be put in environment by mondoarchive for mindi's usage but that's a step left for later.

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