source: branches/2.06/mondo/mondo/mondoarchive/mondo-cli.c @ 296

Last change on this file since 296 was 296, checked in by andree, 15 years ago

Replaced partimagehack with ntfsclone from ntfsprogs package. Replaced
all occurrences of strings 'partimagehack' and 'partimage' with 'ntfsprog'.

  • Property svn:keywords set to Id
File size: 30.5 KB
Line 
1/***************************************************************************
2mondo-cli.c
3-------------------
4begin                : Fri Apr 19 16:40:35 EDT 2002
5copyright        : (C) 2002 Mondo  Hugo Rabson
6email                : Hugo Rabson <hugorabson@msn.com>
7edited by            : by Stan Benoit 4/2002
8email                : troff@nakedsoul.org
9cvsid                : $Id: mondo-cli.c 296 2006-01-11 09:10:31Z andree $
10 ***************************************************************************/
11
12/***************************************************************************
13 *                                                                         *
14 *   This program is free software; you can redistribute it and/or modify  *
15 *   it under the terms of the GNU General Public License as published by  *
16 *   the Free Software Foundation; either version 2 of the License, or     *
17 *   (at your option) any later version.                                   *
18 *                                                                         *
19 ***************************************************************************/
20
21/***************************************************************************
22UPDATE LOG
23
24
2508/04
26- if user specifies a dumb -T value, abort
27
2807/22
29- handle -Q sensibly (don't abort if only -Q supplied)
30
3107/17
32- better checking of NFS dir's validity
33
3406/19
35- added AUX_VER
36
3704/17
38- added '-b' support
3904/03
40- added star support
41
4202/06
43- fixed "Please give /dev entry" error msg
44
4501/20/2004
46- added 2.6.x-kernel "device = /dev/...." support to param reader
47- better handling of SCSI and /dev entries
48- touch /boot/boot.b if necessary
49
5009/26/2003
51- typo in command-line handling of 'r'
52
5309/25
54- added DVD write support
55
5609/24
57- if tape backup (-t) but user doesn't specify tape drive then
58  make an educated guess using find_tape_device_and_size()
59
6009/18
61- insist on partimagehack being present if -x found
62
6309/16
64- added support for multiple -I's and -E's in call to mondoarchive
65- the '-D' flag doesn't take a value now
66
6707/14
68- fatal error if -E too short
69
7005/14
71- if 'n' and user doesn't have rights to write to output dir
72  then error out
73
7405/05
75- added Joshua Oreman's FreeBSD patches
76
7705/04
78- added Herman Kuster's multi-level bkp patch
79
8005/02
81- write errors to screen, not just to log
82
8304/25
84- added lots of assert()'s and log_OS_error()'s
85
8604/21
87- line 570 --- resolve boot device if softlink
88
8904/08
90- changed a bunch of fprintf(stderr,...)'s to log_it()'s
91- fixed final / removal in retrieve_switches_from_command_line()
92
9304/04
94- added -e
95
9603/15
97- reject relative paths if -d flag (Alessandro Polverini)
98
9901/02/2003
100- added -J flag (to let user specify incoming filelist)
101
10212/13/2002
103- various strcpy() calls replaced with strncpy() calls
104
10512/10
106- added g_loglevel
107
10811/25
109- line 614 --- if commmand-line param ends in '/' then drop that '/'
110
11111/19
112- rewrote finish() to kill processes more softly
113- if user calls with '-l RAW' then
114
11509/01 - 09/30
116- added -N to let user exclude all NFS-related mounts and devices
117- run_program_and_log_output() now takes boolean operator to specify
118  whether it will log its activities in the event of _success_
119
12008/01 - 08/31
121- if no device specified when backing up to tape streamer then assume /dev/st0
122- abort if tape user specifies tape size (just for testing porpoises)
123- tape users no longer need to specify tape size
124- added some comments
125- added bkpinfo->backup_media_type
126- renamed from mondo-archive.c to mondo-cli.c
127
12807/01 - 07/31
129- better check for mkfs.vfat
130- more sanity-checking for -d flag
131- if isodir does not exist then abort
132- removed "the rest are..." comment from log
133- do not permit '-H' and '-t' in the same command line
134- if not '-o' then insist on vfat-friendly kernel
135
13606/01 - 06/30
137- added signal-trapping
138- added '-W' (won't make bootable CD or floppies) flag
139- added missing 'j++' to -s switch's code
140- expanded -s switch
141- added -u switch
142- if dvdrecord exists and cdrecord doesn't then use
143  dvdrecord instead of cdrecord
144
14504/01 - 04/30
146- if CD-ROM is supermounted then unmount, run, and remount
147- replace MONDO_VERSION #define with VERSION from ../config.h
148- if CD-ROM is mounted at start then abort
149- improved homedir-locating code
150- improved "backup will occupy N CD's" calculation a bit
151- added -m (manual CD tray) flag
152
153
154*******************************************************************/
155
156/**
157 * @file
158 * Functions for handling command-line arguments passed to mondoarchive.
159 */
160
161/** @def BOOT_LOADER_CHARS The characters allowed for boot loader on this platform. */
162
163#include <pthread.h>
164#include "../common/my-stuff.h"
165#include "../common/mondostructures.h"
166#include "mondo-cli-EXT.h"
167#include "../common/libmondo.h"
168
169//static char cvsid[] = "$Id: mondo-cli.c 296 2006-01-11 09:10:31Z andree $";
170
171extern int g_loglevel;
172extern bool g_text_mode;
173extern bool g_skip_floppies;    ///< Whether to skip the creation of boot disks
174extern char g_startdir[MAX_STR_LEN];    ///< ????? @bug ?????
175extern char g_erase_tmpdir_and_scratchdir[MAX_STR_LEN];
176extern char g_tmpfs_mountpt[MAX_STR_LEN];
177extern bool g_sigpipe;
178
179/*@ file pointer **************************************************/
180extern FILE *g_tape_stream;
181
182/*@ long long *****************************************************/
183extern long long g_tape_posK;
184
185/*@ long **********************************************************/
186extern long g_noof_sets;
187
188/*@ bool******** **************************************************/
189bool g_debugging = FALSE;       ///< ????? @bug ????? @ingroup globalGroup
190bool g_running_live = FALSE;    ///< ????? @bug ????? @ingroup globalGroup
191extern bool g_cd_recovery;
192
193/**
194 * Whether we're restoring from ISOs. Obviously not, since this is the
195 * backup program.
196 * @note You @b MUST declare this variable somewhere in your program if
197 * you use libmondo. Otherwise the link will fail.
198 * @ingroup globalGroup
199 */
200bool g_ISO_restore_mode = FALSE;
201
202
203extern double g_kernel_version;
204
205extern int g_current_media_number;
206
207
208
209extern pid_t g_main_pid;
210
211
212
213
214extern char *resolve_softlinks_to_get_to_actual_device_file(char *);
215
216
217
218/**
219 * @addtogroup cliGroup
220 * @{
221 */
222/**
223 * Populate @p bkpinfo from the command-line parameters stored in @p argc and @p argv.
224 * @param argc The argument count, including the program name; @p argc passed to main().
225 * @param argv The argument vector; @p argv passed to main().
226 * @param bkpinfo The backup information structure to populate.
227 * @return The number of problems with the command line (0 for success).
228 */
229int
230handle_incoming_parameters(int argc, char *argv[],
231                           struct s_bkpinfo *bkpinfo)
232{
233    /*@ int *** */
234    int res = 0;
235    int retval = 0;
236    int i = 0, j;
237
238    /*@ buffers *************** */
239    char *tmp;
240    char flag_val[128][MAX_STR_LEN];
241    bool flag_set[128];
242
243    malloc_string(tmp);
244    sensibly_set_tmpdir_and_scratchdir(bkpinfo);
245    for (i = 0; i < 128; i++) {
246        flag_val[i][0] = '\0';
247        flag_set[i] = FALSE;
248    }
249    //  strcpy (bkpinfo->tmpdir, "/root/images/mondo");
250    //  strcpy (bkpinfo->scratchdir, "/home");
251    for (j = 1; j <= MAX_NOOF_MEDIA; j++) {
252        bkpinfo->media_size[j] = 650;
253    }                           /* default */
254    res =
255        retrieve_switches_from_command_line(argc, argv, flag_val,
256                                            flag_set);
257    retval += res;
258    if (!retval) {
259        res = process_switches(bkpinfo, flag_val, flag_set);
260        retval += res;
261    }
262/*
263  if (!retval)
264    {
265*/
266    log_msg(3, "Switches:-");
267    for (i = 0; i < 128; i++) {
268        if (flag_set[i]) {
269            sprintf(tmp, "-%c %s", i, flag_val[i]);
270            log_msg(3, tmp);
271        }
272    }
273//    }
274    sprintf(tmp, "rm -Rf %s/tmp.mondo.*", bkpinfo->tmpdir);
275    paranoid_system(tmp);
276    sprintf(tmp, "rm -Rf %s/mondo.scratch.*", bkpinfo->scratchdir);
277    paranoid_system(tmp);
278    sprintf(bkpinfo->tmpdir + strlen(bkpinfo->tmpdir), "/tmp.mondo.%ld",
279            random() % 32767);
280    sprintf(bkpinfo->scratchdir + strlen(bkpinfo->scratchdir),
281            "/mondo.scratch.%ld", random() % 32767);
282    sprintf(tmp, "mkdir -p %s/tmpfs", bkpinfo->tmpdir);
283    paranoid_system(tmp);
284    sprintf(tmp, "mkdir -p %s", bkpinfo->scratchdir);
285    paranoid_system(tmp);
286    if (bkpinfo->nfs_mount[0] != '\0') {
287        store_nfs_config(bkpinfo);
288    }
289    paranoid_free(tmp);
290    return (retval);
291}
292
293
294
295
296/**
297 * Store the sizespec(s) stored in @p value into @p bkpinfo.
298 * @param bkpinfo The backup information structure; the @c bkpinfo->media_size field will be populated.
299 * @param value The sizespec (e.g. "2g", "40m").
300 * @return 0, always.
301 * @bug Return code not needed.
302 */
303int process_the_s_switch(struct s_bkpinfo *bkpinfo, char *value)
304{
305    int j;
306    char tmp[MAX_STR_LEN], *p, comment[MAX_STR_LEN];
307
308    assert(bkpinfo != NULL);
309    assert(value != NULL);
310
311    bkpinfo->media_size[0] = -1;    /* dummy value */
312    for (j = 1, p = value; j < MAX_NOOF_MEDIA && strchr(p, ',');
313         j++, p = strchr(p, ',') + 1) {
314        strncpy(tmp, p, MAX_STR_LEN);
315        *(strchr(tmp, ',')) = '\0';
316        bkpinfo->media_size[j] = friendly_sizestr_to_sizelong(tmp);
317        sprintf(comment, "media_size[%d] = %ld", j,
318                bkpinfo->media_size[j]);
319        log_msg(3, comment);
320    }
321    for (; j <= MAX_NOOF_MEDIA; j++) {
322        bkpinfo->media_size[j] = friendly_sizestr_to_sizelong(p);
323    }
324//      bkpinfo->media_size[0] = bkpinfo->media_size[MAX_NOOF_MEDIA];
325    for (j = 1; j <= MAX_NOOF_MEDIA; j++) {
326        if (bkpinfo->media_size[j] <= 0) {
327            log_msg(1, "You gave media #%d an invalid size\n", j);
328            return (-1);
329        }
330    }
331    return (0);
332}
333
334
335
336/**
337 * Process mondoarchive's command-line switches.
338 * @param bkpinfo The backup information structure to populate.
339 * @param flag_val An array of the argument passed to each switch (the letter is the index).
340 * If a switch is not set or has no argument, the field in @p flag_val doesn't matter.
341 * @param flag_set An array of <tt>bool</tt>s indexed by switch letter: TRUE if it's set,
342 * FALSE if it's not.
343 * @return The number of problems with the switches, or 0 for success.
344 * @bug Maybe include a list of all switches (inc. intentionally undocumented ones not in the manual!) here?
345 */
346int
347process_switches(struct s_bkpinfo *bkpinfo,
348                 char flag_val[128][MAX_STR_LEN], bool flag_set[128])
349{
350
351    /*@ ints *** */
352    int i = 0;
353    int retval = 0;
354    int percent = 0;
355
356    /*@ buffers ** */
357    char *tmp;
358    char *psz;
359
360    long itbs;
361
362    struct stat buf;
363
364    malloc_string(tmp);
365    malloc_string(psz);
366
367    assert(bkpinfo != NULL);
368    assert(flag_val != NULL);
369    assert(flag_set != NULL);
370
371    bkpinfo->internal_tape_block_size = DEFAULT_INTERNAL_TAPE_BLOCK_SIZE;
372
373/* compulsory */
374    i = flag_set['c'] + flag_set['i'] + flag_set['n'] +
375        flag_set['t'] + flag_set['u'] + flag_set['r'] +
376        flag_set['w'] + flag_set['C'];
377    if (i == 0) {
378        retval++;
379        log_to_screen("You must specify the media type\n");
380    }
381    if (i > 1) {
382        retval++;
383        log_to_screen("Please specify only one media type\n");
384    }
385    if (flag_set['K']) {
386        g_loglevel = atoi(flag_val['K']);
387        if (g_loglevel < 3) {
388            g_loglevel = 3;
389        }
390    }
391    if (flag_set['L'] && flag_set['0']) {
392        retval++;
393        log_to_screen("You cannot have 'no compression' _and_ LZOP.\n");
394    }
395    bkpinfo->backup_data = flag_set['O'];
396    bkpinfo->verify_data = flag_set['V'];
397    if (flag_set['I'] && !bkpinfo->backup_data) {
398        log_to_screen("-I switch is ignored if just verifying");
399    }
400    if (flag_set['E'] && !bkpinfo->backup_data) {
401        log_to_screen("-E switch is ignored if just verifying");
402    }
403
404    if (!find_home_of_exe("afio")) {
405        if (find_home_of_exe("star")) {
406            flag_set['R'] = TRUE;
407            log_msg(1, "Using star instead of afio");
408        } else {
409            fatal_error
410                ("Neither afio nor star is installed. Please install at least one.");
411        }
412    }
413
414    if (flag_set['R']) {
415        bkpinfo->use_star = TRUE;
416        if (flag_set['L']) {
417            fatal_error("You may not use star and lzop at the same time.");
418        }
419        if (!find_home_of_exe("star")) {
420            fatal_error
421                ("Please install 'star' RPM or tarball if you are going to use -R. Thanks.");
422        }
423    }
424    if (flag_set['W']) {
425        bkpinfo->nonbootable_backup = TRUE;
426        log_to_screen("Warning - you have opted for non-bootable backup");
427        if (flag_set['f'] || flag_set['l']) {
428            log_to_screen
429                ("You don't need to specify bootloader or bootdevice");
430        }
431    }
432    if (flag_set['t'] && flag_set['H']) {
433        fatal_error
434            ("Sorry, you may not nuke w/o warning from tape. Drop -H, please.");
435    }
436    if (flag_set['I']) {
437        if (!strcmp(bkpinfo->include_paths, "/")) {
438            log_msg(2, "'/' is pleonastic.");
439            bkpinfo->include_paths[0] = '\0';
440        }
441        if (bkpinfo->include_paths[0]) {
442            strcat(bkpinfo->include_paths, " ");
443        }
444        if (stat(flag_val['I'], &buf) != 0) {
445            log_msg("ERROR ! %s doesn't exist", flag_val['I']);
446            fatal_error("ERROR ! You specified a directory to include which doesn't exist");
447        }
448        strncpy(bkpinfo->include_paths + strlen(bkpinfo->include_paths),
449                flag_val['I'],
450                MAX_STR_LEN - strlen(bkpinfo->include_paths));
451        log_msg(1, "include_paths is now '%s'", bkpinfo->include_paths);
452        if (bkpinfo->include_paths[0] == '-') {
453            retval++;
454            log_to_screen("Please supply a sensible value with '-I'\n");
455        }
456    }
457
458    if (g_kernel_version >= 2.6 && !flag_set['d']
459        && (flag_set['c'] || flag_set['w'])) {
460        fatal_error
461            ("If you are using the 2.6.x kernel, please specify the CD-R(W) device.");
462    }
463
464
465    if (flag_set['J']) {
466        if (flag_set['I']) {
467            retval++;
468            log_to_screen
469                ("Please do not use -J in combination with -I. If you want to make a list of files to backup, that's fine, use -J <filename> but please don't muddy the waters by combining -J with -I. Thanks. :-)");
470        }
471        bkpinfo->make_filelist = FALSE;
472        strcpy(bkpinfo->include_paths, flag_val['J']);
473    }
474    if (flag_set['c'] || flag_set['w'] || flag_set['C'] || flag_set['r']) {
475        if (!flag_set['r'] && g_kernel_version <= 2.5
476            && strstr(flag_val['d'], "/dev/")) {
477            fatal_error
478                ("Please don't give a /dev entry. Give a SCSI node for the parameter of the -d flag.");
479        }
480        if (flag_set['r'] && g_kernel_version <= 2.5
481            && !strstr(flag_val['d'], "/dev/")) {
482            fatal_error
483                ("Please give a /dev entry, not a SCSI node, as the parameter of the -d flag.");
484        }
485        if (g_kernel_version >= 2.6 && !strstr(flag_val['d'], "/dev/")) {
486            log_to_screen
487                ("Linus says 2.6 has a broken ide-scsi module. Proceed at your own risk...");
488        }
489
490        if (system("which cdrecord > /dev/null 2> /dev/null")
491            && system("which dvdrecord > /dev/null 2> /dev/null")) {
492            fatal_error
493                ("Please install dvdrecord/cdrecord and try again.");
494        }
495        if (flag_set['C']) {
496            bkpinfo->cdrw_speed = atoi(flag_val['C']);
497            if (bkpinfo->cdrw_speed < 1) {
498                fatal_error
499                    ("You specified a silly speed for a CD-R[W] drive");
500            }
501            if (!flag_set['L']) {
502                log_to_screen
503                    ("You must use -L with -C. Therefore I am setting it for you.");
504                flag_set['L'] = 1;
505                flag_val['L'][0] = '\0';
506            }
507        } else {
508            log_msg(3, "flag_val['c'] = %s", flag_val['c']);
509            log_msg(3, "flag_val['w'] = %s", flag_val['w']);
510//    log_msg(3, "flag_set['r'] = %i", flag_set['r'] );
511            if (flag_set['c']) {
512                bkpinfo->cdrw_speed = atoi(flag_val['c']);
513            } else if (flag_set['w']) {
514                bkpinfo->cdrw_speed = atoi(flag_val['w']);
515            } else if (flag_set['r']) {
516                bkpinfo->cdrw_speed = 1;    /*atoi(flag_val['r']); */
517            }
518
519            if (bkpinfo->cdrw_speed < 1) {
520                fatal_error
521                    ("You specified a silly speed for a CD-R[W] drive");
522            }
523        }
524    }
525    if (flag_set['t'] && !flag_set['d']) {
526        log_it("Hmm! No tape drive specified. Let's see what we can do.");
527        if (find_tape_device_and_size(flag_val['d'], tmp)) {
528            fatal_error
529                ("Tape device not specified. I couldn't find it either.");
530        }
531        flag_set['d'] = TRUE;
532        sprintf(tmp,
533                "You didn't specify a tape streamer device. I'm assuming %s",
534                flag_val['d']);
535        log_to_screen(tmp);
536        percent = 0;
537    }
538
539    if (flag_set['r'])          // DVD
540    {
541        if (flag_set['m']) {
542            fatal_error
543                ("Manual CD tray (-m) not yet supported in conjunction w/ DVD drives. Drop -m.");
544        }
545        if (!flag_set['d']) {
546            if (!find_dvd_device(flag_val['d'], FALSE)) {
547                flag_set['d'] = TRUE;
548                log_to_screen("I guess DVD drive is at %s", flag_val['d']);
549            }
550        }
551        if (!find_home_of_exe("growisofs")) {
552            fatal_error
553                ("Please install growisofs (probably part of dvd+rw-tools). If you want DVD support, you need it.");
554        }
555        if (!find_home_of_exe("dvd+rw-format")) {
556            fatal_error
557                ("Please install dvd+rw-format (probably part of dvd+rw-tools). If you want DVD support, you need it.");
558        }
559        if (strchr(flag_val['d'], ',')) {
560            fatal_error
561                ("Please don't give a SCSI node. Give a _device_, preferably a /dev entry, for the parameter of the -d flag.");
562        }
563        if (!flag_set['s']) {
564            sprintf(flag_val['s'], "%d", DEFAULT_DVD_DISK_SIZE);    // 4.7 salesman's GB = 4.482 real GB = 4582 MB
565            strcat(flag_val['s'], "m");
566            log_to_screen
567                ("You did not specify a size (-s) for DVD. I'm guessing %s.",
568                 flag_val['s']);
569            flag_set['s'] = 1;
570        }
571/*
572      if (flag_set['Z']) {
573      bkpinfo->blank_dvd_first = TRUE;
574      }
575*/
576    }
577
578    if (flag_set['t'] || flag_set['u']) {   /* tape size */
579        if (strchr(flag_val['d'], ',')) {
580            fatal_error
581                ("Please don't give a SCSI node. Give a _device_, preferably a /dev entry, for the parameter of the -d flag.");
582        }
583        if (flag_set['O']) {
584            if (flag_set['s']) {
585                if (flag_set['t']) {
586                    fatal_error
587                        ("For the moment, please don't specify a tape size. Mondo should handle end-of-tape gracefully anyway.");
588                }
589                if (process_the_s_switch(bkpinfo, flag_val['s'])) {
590                    fatal_error("Bad -s switch");
591                }
592            } else if (flag_set['u'] || flag_set['t']) {
593                for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
594                    bkpinfo->media_size[i] = 0;
595                }
596            } else {
597                retval++;
598                log_to_screen("Tape size not specified.\n");
599            }
600        }
601    } else {                    /* CD size */
602        if (flag_set['s']) {
603            if (process_the_s_switch(bkpinfo, flag_val['s'])) {
604                fatal_error("Bad -s switch");
605            }
606        }
607        if (flag_set['w']) {
608            bkpinfo->wipe_media_first = TRUE;
609        }                       /* CD-RW */
610    }
611    if (flag_set['n']) {
612        strncpy(bkpinfo->nfs_mount, flag_val['n'], MAX_STR_LEN);
613        if (!flag_set['d']) {
614            strncpy(bkpinfo->nfs_remote_dir, "/", MAX_STR_LEN);
615        }
616        sprintf(tmp, "mount | grep -x \"%s .*\" | cut -d' ' -f3",
617                bkpinfo->nfs_mount);
618        strncpy(bkpinfo->isodir,
619                call_program_and_get_last_line_of_output(tmp),
620                MAX_STR_LEN / 4);
621        if (strlen(bkpinfo->isodir) < 3) {
622            retval++;
623            log_to_screen("NFS share is not mounted. Please mount it.\n");
624        }
625        log_msg(3, "mount = %s", bkpinfo->nfs_mount);
626        log_msg(3, "isodir= %s", bkpinfo->isodir);
627    }
628    if (flag_set['c']) {
629        bkpinfo->backup_media_type = cdr;
630    }
631    if (flag_set['C']) {
632        bkpinfo->backup_media_type = cdstream;
633    }
634    if (flag_set['i']) {
635        bkpinfo->backup_media_type = iso;
636    }
637    if (flag_set['n']) {
638        bkpinfo->backup_media_type = nfs;
639    }
640    if (flag_set['r']) {
641        bkpinfo->backup_media_type = dvd;
642    }
643    if (flag_set['t']) {
644        bkpinfo->backup_media_type = tape;
645    }
646    if (flag_set['u']) {
647        bkpinfo->backup_media_type = udev;
648    }
649    if (flag_set['w']) {
650        bkpinfo->backup_media_type = cdrw;
651    }
652
653/* optional, popular */
654    if (flag_set['g']) {
655        g_text_mode = FALSE;
656    }
657    if (flag_set['E']) {
658        if (bkpinfo->exclude_paths[0]) {
659            strcat(bkpinfo->exclude_paths, " ");
660        }
661        if (stat(flag_val['E'], &buf) != 0) {
662            log_msg(1, "WARNING ! %s doesn't exist", flag_val['E']);
663        }
664        strncpy(bkpinfo->exclude_paths + strlen(bkpinfo->exclude_paths),
665                flag_val['E'],
666                MAX_STR_LEN - strlen(bkpinfo->exclude_paths));
667    }
668    if (flag_set['e']) {
669        bkpinfo->please_dont_eject = TRUE;
670    }
671    if (flag_set['N'])          // exclude NFS mounts & devices
672    {
673//      strncpy(psz, list_of_NFS_devices_and_mounts(), MAX_STR_LEN);
674        strncpy(psz, list_of_NFS_mounts_only(), MAX_STR_LEN);
675        if (bkpinfo->exclude_paths[0]) {
676            strncat(bkpinfo->exclude_paths, " ", MAX_STR_LEN);
677        }
678        strncat(bkpinfo->exclude_paths, psz, MAX_STR_LEN);
679        log_msg(3, "-N means we're now excluding %s",
680                bkpinfo->exclude_paths);
681    }
682    if (strlen(bkpinfo->exclude_paths) >= MAX_STR_LEN) {
683        fatal_error
684            ("Your '-E' parameter is too long. Please use '-J'. (See manual.)");
685    }
686    if (flag_set['b']) {
687        strcpy(psz, flag_val['b']);
688        log_msg(1, "psz = '%s'", psz);
689        if (psz[strlen(psz) - 1] == 'k') {
690            psz[strlen(psz) - 1] = '\0';
691            itbs = atol(psz) * 1024L;
692        } else {
693            itbs = atol(psz);
694        }
695        log_msg(1, "'%s' --> %ld", flag_val['b'], itbs);
696        log_msg(1, "Internal tape block size is now %ld bytes", itbs);
697        if (itbs % 512 != 0 || itbs < 256 || itbs > 1024L * 1024) {
698            fatal_error
699                ("Are you nuts? Silly, your internal tape block size is. Abort, I shall.");
700        }
701        bkpinfo->internal_tape_block_size = itbs;
702    }
703    if (flag_set['D']) {
704        bkpinfo->differential = 1;
705//      bkpinfo->differential = atoi (flag_val['D']);
706        if ((bkpinfo->differential < 1) || (bkpinfo->differential > 9)) {
707            fatal_error
708                ("The D option should be between 1 and 9 inclusive");
709        }
710    }
711    if (flag_set['x']) {
712        strncpy(bkpinfo->image_devs, flag_val['x'], MAX_STR_LEN / 4);
713        if (run_program_and_log_output("which ntfsclone", 2)) {
714            fatal_error("Please install ntfsprogs package/tarball.");
715        }
716    }
717    if (flag_set['m']) {
718        bkpinfo->manual_cd_tray = TRUE;
719    }
720    if (flag_set['k']) {
721        strncpy(bkpinfo->kernel_path, flag_val['k'], MAX_STR_LEN);
722        if (!strcmp(bkpinfo->kernel_path, "failsafe")) {
723            strcpy(bkpinfo->kernel_path, "FAILSAFE");
724        }
725        if (strcmp(bkpinfo->kernel_path, "FAILSAFE")
726            && !does_file_exist(bkpinfo->kernel_path)) {
727            retval++;
728            sprintf(tmp,
729                    "You specified kernel '%s', which does not exist\n",
730                    bkpinfo->kernel_path);
731            log_to_screen(tmp);
732        }
733    }
734    if (flag_set['p']) {
735        strncpy(bkpinfo->prefix, flag_val['p'], MAX_STR_LEN / 4);
736    }
737
738
739    if (flag_set['d']) {        /* backup directory (if ISO/NFS) */
740        if (flag_set['i']) {
741            strncpy(bkpinfo->isodir, flag_val['d'], MAX_STR_LEN / 4);
742            sprintf(tmp, "ls -l %s", bkpinfo->isodir);
743            if (run_program_and_log_output(tmp, FALSE)) {
744                fatal_error
745                    ("output folder does not exist - please create it");
746            }
747        } else if (flag_set['n']) {
748            strncpy(bkpinfo->nfs_remote_dir, flag_val['d'], MAX_STR_LEN);
749        } else {                /* backup device (if tape/CD-R/CD-RW) */
750
751            strncpy(bkpinfo->media_device, flag_val['d'], MAX_STR_LEN / 4);
752        }
753    }
754
755    if (flag_set['n']) {
756        sprintf(tmp, "echo hi > %s/%s/.dummy.txt", bkpinfo->isodir,
757                bkpinfo->nfs_remote_dir);
758        if (run_program_and_log_output(tmp, FALSE)) {
759            retval++;
760            sprintf(tmp,
761                    "Are you sure directory '%s' exists in remote dir '%s'?\nIf so, do you have rights to write to it?\n",
762                    bkpinfo->nfs_remote_dir, bkpinfo->nfs_mount);
763            log_to_screen(tmp);
764        }
765    }
766
767    if (!flag_set['d']
768        && (flag_set['c'] || flag_set['w'] || flag_set['C'])) {
769        if (g_kernel_version >= 2.6) {
770            if (popup_and_get_string
771                ("Device", "Please specify the device",
772                 bkpinfo->media_device, MAX_STR_LEN / 4)) {
773                retval++;
774                log_to_screen("User opted to cancel.");
775            }
776        } else if (find_cdrw_device(bkpinfo->media_device)) {
777            retval++;
778            log_to_screen
779                ("Tried and failed to find CD-R[W] drive automatically.\n");
780        } else {
781            flag_set['d'] = TRUE;
782            strncpy(flag_val['d'], bkpinfo->media_device, MAX_STR_LEN / 4);
783        }
784    }
785
786    if (!flag_set['d'] && !flag_set['n'] && !flag_set['C']) {
787        retval++;
788        log_to_screen("Please specify the backup device/directory.\n");
789        fatal_error
790            ("You didn't use -d to specify the backup device/directory.");
791    }
792/* optional, obscure */
793    for (i = '0'; i <= '9'; i++) {
794        if (flag_set[i]) {
795            bkpinfo->compression_level = i - '0';
796        }                       /* not '\0' but '0' */
797    }
798    if (flag_set['S']) {
799        sprintf(bkpinfo->scratchdir, "%s/mondo.scratch.%ld", flag_val['S'],
800                random() % 32768);
801    }
802    if (flag_set['T']) {
803        sprintf(bkpinfo->tmpdir, "%s/tmp.mondo.%ld", flag_val['T'],
804                random() % 32768);
805        sprintf(tmp, "touch %s/.foo.dat", flag_val['T']);
806        if (run_program_and_log_output(tmp, 1)) {
807            retval++;
808            log_to_screen
809                ("Please specify a tempdir which I can write to. :)");
810            fatal_error("I cannot write to the tempdir you specified.");
811        }
812        sprintf(tmp, "ln -sf %s/.foo.dat %s/.bar.dat", flag_val['T'],
813                flag_val['T']);
814        if (run_program_and_log_output(tmp, 1)) {
815            retval++;
816            log_to_screen
817                ("Please don't specify a SAMBA or VFAT or NFS tmpdir.");
818            fatal_error("I cannot write to the tempdir you specified.");
819        }
820    }
821    if (flag_set['A']) {
822        strncpy(bkpinfo->call_after_iso, flag_val['A'], MAX_STR_LEN);
823    }
824    if (flag_set['B']) {
825        strncpy(bkpinfo->call_before_iso, flag_val['B'], MAX_STR_LEN);
826    }
827    if (flag_set['F']) {
828        g_skip_floppies = TRUE;
829    }
830    if (flag_set['H']) {
831        g_cd_recovery = TRUE;
832    }
833    if (flag_set['l']) {
834#ifdef __FreeBSD__
835#  define BOOT_LOADER_CHARS "GLBMR"
836#else
837#  ifdef __IA64__
838#    define BOOT_LOADER_CHARS "GER"
839#  else
840#    define BOOT_LOADER_CHARS "GLR"
841#  endif
842#endif
843        if (!strchr
844            (BOOT_LOADER_CHARS,
845             (bkpinfo->boot_loader = flag_val['l'][0]))) {
846            log_msg(1, "%c? WTF is %c? I need G, L, E or R.",
847                    bkpinfo->boot_loader, bkpinfo->boot_loader);
848            fatal_error
849                ("Please specify GRUB, LILO, ELILO  or RAW with the -l switch");
850        }
851#undef BOOT_LOADER_CHARS
852    }
853    if (flag_set['f']) {
854        strncpy(bkpinfo->boot_device,
855                resolve_softlinks_to_get_to_actual_device_file(flag_val
856                                                               ['f']),
857                MAX_STR_LEN / 4);
858    }
859    if (flag_set['P']) {
860        strncpy(bkpinfo->postnuke_tarball, flag_val['P'], MAX_STR_LEN);
861    }
862    if (flag_set['Q']) {
863        i = which_boot_loader(tmp);
864        log_msg(3, "boot loader is %c, residing at %s", i, tmp);
865        printf("boot loader is %c, residing at %s\n", i, tmp);
866        finish(0);
867    }
868    if (flag_set['L']) {
869        bkpinfo->use_lzo = TRUE;
870        if (run_program_and_log_output("which lzop", FALSE)) {
871            retval++;
872            log_to_screen
873                ("Please install LZOP. You can't use '-L' until you do.\n");
874        }
875    }
876
877    if (!flag_set['o']
878        &&
879        !run_program_and_log_output
880        ("grep -i suse /etc/issue.net | grep 64", TRUE)) {
881        bkpinfo->make_cd_use_lilo = TRUE;
882        log_to_screen
883            ("Forcing you to use LILO. SuSE 9.0 (64-bit) has a broken mkfs.vfat binary.");
884    }
885    if (flag_set['o']) {
886        bkpinfo->make_cd_use_lilo = TRUE;
887    }
888#ifndef __FreeBSD__
889    else {
890        if (!is_this_a_valid_disk_format("vfat")) {
891            bkpinfo->make_cd_use_lilo = TRUE;
892            log_to_screen
893                ("Your kernel appears not to support vfat filesystems. I am therefore");
894            log_to_screen
895                ("using LILO instead of SYSLINUX as the CD/floppy's boot loader.");
896        }
897        if (run_program_and_log_output("which mkfs.vfat", FALSE)) {
898            bkpinfo->make_cd_use_lilo = TRUE;
899#ifdef __IA32__
900            log_to_screen
901                ("Your filesystem is missing 'mkfs.vfat', so I cannot use SYSLINUX as");
902            log_to_screen
903                ("your boot loader. I shall therefore use LILO instead.");
904#endif
905#ifdef __IA64__
906            log_to_screen
907                ("Your filesystem is missing 'mkfs.vfat', so I cannot prepare the EFI");
908            log_to_screen("environment correctly. Please install it.");
909            fatal_error("Aborting");
910#endif
911        }
912#ifdef __IA64__
913        /* We force ELILO usage on IA64 */
914        bkpinfo->make_cd_use_lilo = TRUE;
915#endif
916    }
917#endif
918
919    if (bkpinfo->make_cd_use_lilo && !does_file_exist("/boot/boot.b")) {
920        paranoid_system("touch /boot/boot.b");
921    }
922
923    i = flag_set['O'] + flag_set['V'];
924    if (i == 0) {
925        retval++;
926        log_to_screen("Specify backup (-O), verify (-V) or both (-OV).\n");
927    }
928
929/* and finally... */
930
931    paranoid_free(tmp);
932    paranoid_free(psz);
933    return (retval);
934}
935
936
937
938/**
939 * Get the switches from @p argc and @p argv using getopt() and place them in
940 * @p flag_set and @p flag_val.
941 * @param argc The argument count (@p argc passed to main()).
942 * @param argv The argument vector (@p argv passed to main()).
943 * @param flag_val An array indexed by switch letter - if a switch is set and
944 * has an argument then set flag_val[switch] to that argument.
945 * @param flag_set An array indexed by switch letter - if a switch is set then
946 * set flag_set[switch] to TRUE, else set it to FALSE.
947 * @return The number of problems with the command line (0 for success).
948 */
949int
950retrieve_switches_from_command_line(int argc, char *argv[],
951                                    char flag_val[128][MAX_STR_LEN],
952                                    bool flag_set[128])
953{
954    /*@ ints ** */
955    int opt = 0;
956    char tmp[MAX_STR_LEN];
957    int i = 0;
958    int len;
959
960    /*@ bools *** */
961    bool bad_switches = FALSE;
962
963    assert(flag_val != NULL);
964    assert(flag_set != NULL);
965
966    for (i = 0; i < 128; i++) {
967        flag_val[i][0] = '\0';
968        flag_set[i] = FALSE;
969    }
970    while ((opt =
971            getopt(argc, argv,
972                   "0123456789A:B:C:DE:FHI:J:K:LNOP:QRS:T:VWb:c:d:ef:gik:l:mn:op:rs:tuw:x:"))
973           != -1) {
974        if (opt == '?') {
975            bad_switches = TRUE;
976            /*log_it("Invalid option: %c\n",optopt); */
977        } else {
978            if (flag_set[optopt]) {
979                bad_switches = TRUE;
980                sprintf(tmp, "Switch -%c previously defined as %s\n", opt,
981                        flag_val[i]);
982                log_to_screen(tmp);
983            } else {
984                flag_set[opt] = TRUE;
985                if (optarg) {
986                    len = strlen(optarg);
987                    if (optarg[0] != '/' && optarg[len - 1] == '/') {
988                        optarg[--len] = '\0';
989                        log_to_screen
990                            ("Warning - param '%s' should not have trailing slash!",
991                             optarg);
992                    }
993                    if (opt == 'd') {
994                        if (strchr(flag_val[opt], '/')
995                            && flag_val[opt][0] != '/') {
996                            sprintf(tmp,
997                                    "-%c flag --- must be absolute path --- '%s' isn't absolute",
998                                    opt, flag_val[opt]);
999                            log_to_screen(tmp);
1000                            bad_switches = TRUE;
1001                        }
1002                    }
1003                    strcpy(flag_val[opt], optarg);
1004                }
1005            }
1006        }
1007    }
1008    for (i = optind; i < argc; i++) {
1009        bad_switches = TRUE;
1010        sprintf(tmp, "Invalid arg -- %s\n", argv[i]);
1011        log_to_screen(tmp);
1012    }
1013    return (bad_switches);
1014}
1015
1016
1017
1018
1019/**
1020 * Print a not-so-helpful help message and exit.
1021 */
1022void help_screen()
1023{
1024    log_msg(1, "Type 'man mondo-archive' for more information\n");
1025    exit(1);
1026}
1027
1028
1029/**
1030 * Terminate Mondo in response to a signal.
1031 * @param sig The signal number received.
1032 */
1033void terminate_daemon(int sig)
1034{
1035    char tmp[64];
1036    char tmp2[MAX_STR_LEN];
1037    //  char command[512];
1038    //  pid_t pid;
1039
1040    switch (sig) {
1041    case SIGINT:
1042        sprintf(tmp, "SIGINT");
1043        strcpy(tmp2, "You interrupted me :-)");
1044        break;
1045    case SIGKILL:
1046        sprintf(tmp, "SIGKILL");
1047        strcpy(tmp2,
1048               "I seriously have no clue how this signal even got to me. Something's wrong with your system.");
1049        break;
1050    case SIGTERM:
1051        sprintf(tmp, "SIGTERM");
1052        strcpy(tmp2, "Got terminate signal");
1053        break;
1054    case SIGHUP:
1055        sprintf(tmp, "SIGHUP");
1056        strcpy(tmp2, "Hangup on line");
1057        break;
1058    case SIGSEGV:
1059        sprintf(tmp, "SIGSEGV");
1060        strcpy(tmp2,
1061               "Internal programming error. Please send a backtrace as well as your log.");
1062        break;
1063    case SIGPIPE:
1064        sprintf(tmp, "SIGPIPE");
1065        strcpy(tmp2, "Pipe was broken");
1066        break;
1067    case SIGABRT:
1068        sprintf(tmp, "SIGABRT");
1069        sprintf(tmp2,
1070                "Abort - probably failed assertion. I'm sleeping for a few seconds so you can read the message.");
1071        break;
1072    default:
1073        sprintf(tmp, "(Unknown)");
1074    }
1075
1076    strcat(tmp, " signal received from OS");
1077    log_to_screen(tmp);
1078    log_to_screen(tmp2);
1079    if (sig == SIGABRT) {
1080        sleep(10);
1081    }
1082    kill_buffer();
1083    fatal_error
1084        ("Mondoarchive is terminating in response to a signal from the OS");
1085    finish(254);                // just in case
1086}
1087
1088
1089
1090
1091/**
1092 * Turn signal-trapping on or off.
1093 * @param on If TRUE, turn it on; if FALSE, turn it off (we still trap it, just don't do as much).
1094 */
1095void set_signals(int on)
1096{
1097    int signals[] =
1098        { SIGTERM, SIGHUP, SIGTRAP, SIGABRT, SIGINT, SIGKILL, SIGSTOP, 0 };
1099    int i;
1100
1101    signal(SIGPIPE, sigpipe_occurred);
1102    for (i = 0; signals[i]; i++) {
1103        if (on) {
1104            signal(signals[i], terminate_daemon);
1105        } else {
1106            signal(signals[i], termination_in_progress);
1107        }
1108    }
1109}
1110
1111
1112
1113
1114/**
1115 * Exit immediately without cleaning up.
1116 * @param sig The signal we are exiting due to.
1117 */
1118void termination_in_progress(int sig)
1119{
1120    log_msg(1, "Termination in progress");
1121    usleep(1000);
1122    pthread_exit(0);
1123}
1124
1125/* @} - end of cliGroup */
Note: See TracBrowser for help on using the repository browser.