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

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

Replaced all occurrences of egrep with 'grep -E' and of fgrep with
'grep -F' in mondo.
egrep and fgrep are usually just script wrappers around grep these
days which means additional overhead compared to calling grep with the
relevant option. Also, it appears that egrep and fgrep have been
deprecated by POSIX some time ago.

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