source: branches/stable/mondo/mondo/mondoarchive/mondo-cli.c @ 681

Last change on this file since 681 was 681, checked in by andree, 13 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: 31.3 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 681 2006-06-25 02:41:57Z 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 681 2006-06-25 02:41:57Z 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 *tmp1;
359    char *psz;
360    char *p;
361    char *q;
362
363    long itbs;
364
365    struct stat buf;
366
367    malloc_string(tmp);
368    malloc_string(psz);
369
370    assert(bkpinfo != NULL);
371    assert(flag_val != NULL);
372    assert(flag_set != NULL);
373
374    bkpinfo->internal_tape_block_size = DEFAULT_INTERNAL_TAPE_BLOCK_SIZE;
375
376/* compulsory */
377    i = flag_set['c'] + flag_set['i'] + flag_set['n'] +
378        flag_set['t'] + flag_set['u'] + flag_set['r'] +
379        flag_set['w'] + flag_set['C'];
380    if (i == 0) {
381        retval++;
382        log_to_screen("You must specify the media type\n");
383    }
384    if (i > 1) {
385        retval++;
386        log_to_screen("Please specify only one media type\n");
387    }
388    if (flag_set['K']) {
389        g_loglevel = atoi(flag_val['K']);
390        if (g_loglevel < 3) {
391            g_loglevel = 3;
392        }
393    }
394    if (flag_set['L'] && flag_set['0']) {
395        retval++;
396        log_to_screen("You cannot have 'no compression' _and_ LZOP.\n");
397    }
398    bkpinfo->backup_data = flag_set['O'];
399    bkpinfo->verify_data = flag_set['V'];
400    if (flag_set['I'] && !bkpinfo->backup_data) {
401        log_to_screen("-I switch is ignored if just verifying");
402    }
403    if (flag_set['E'] && !bkpinfo->backup_data) {
404        log_to_screen("-E switch is ignored if just verifying");
405    }
406
407    if (!find_home_of_exe("afio")) {
408        if (find_home_of_exe("star")) {
409            flag_set['R'] = TRUE;
410            log_msg(1, "Using star instead of afio");
411        } else {
412            fatal_error
413                ("Neither afio nor star is installed. Please install at least one.");
414        }
415    }
416
417    if (flag_set['R']) {
418        bkpinfo->use_star = TRUE;
419        if (flag_set['L']) {
420            fatal_error("You may not use star and lzop at the same time.");
421        }
422        if (!find_home_of_exe("star")) {
423            fatal_error
424                ("Please install 'star' RPM or tarball if you are going to use -R. Thanks.");
425        }
426    }
427    if (flag_set['W']) {
428        bkpinfo->nonbootable_backup = TRUE;
429        log_to_screen("Warning - you have opted for non-bootable backup");
430        if (flag_set['f'] || flag_set['l']) {
431            log_to_screen
432                ("You don't need to specify bootloader or bootdevice");
433        }
434    }
435    if (flag_set['t'] && flag_set['H']) {
436        fatal_error
437            ("Sorry, you may not nuke w/o warning from tape. Drop -H, please.");
438    }
439    if (flag_set['I']) {
440        if (!strcmp(bkpinfo->include_paths, "/")) {
441            log_msg(2, "'/' is pleonastic.");
442            bkpinfo->include_paths[0] = '\0';
443        }
444        if (bkpinfo->include_paths[0]) {
445            strcat(bkpinfo->include_paths, " ");
446        }
447        asprintf(&tmp1, flag_val['I']);
448        p = tmp1;
449        q = tmp1;
450
451        /* Cut the flag_val['I'] in parts containing all paths to test them */
452        while (p != NULL) {
453            q = strchr(p, ' ');
454            if (q != NULL) {
455                *q = '\0';
456                if (stat(p, &buf) != 0) {
457                    log_msg(1, "ERROR ! %s doesn't exist", p);
458                    fatal_error("ERROR ! You specified a directory to include which doesn't exist");
459                }
460                p = q+1 ;
461            } else {
462                if (stat(p, &buf) != 0) {
463                    log_msg(1, "ERROR ! %s doesn't exist", p);
464                    fatal_error("ERROR ! You specified a directory to include which doesn't exist");
465                }
466                p = NULL;
467            }
468        }
469        paranoid_free(tmp1);
470
471        strncpy(bkpinfo->include_paths + strlen(bkpinfo->include_paths),
472                flag_val['I'],
473                4*MAX_STR_LEN - strlen(bkpinfo->include_paths));
474        log_msg(1, "include_paths is now '%s'", bkpinfo->include_paths);
475        if (bkpinfo->include_paths[0] == '-') {
476            retval++;
477            log_to_screen("Please supply a sensible value with '-I'\n");
478        }
479    }
480
481    if (g_kernel_version >= 2.6 && !flag_set['d']
482        && (flag_set['c'] || flag_set['w'])) {
483        fatal_error
484            ("If you are using the 2.6.x kernel, please specify the CD-R(W) device.");
485    }
486
487
488    if (flag_set['J']) {
489        if (flag_set['I']) {
490            retval++;
491            log_to_screen
492                ("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. :-)");
493        }
494        bkpinfo->make_filelist = FALSE;
495        strcpy(bkpinfo->include_paths, flag_val['J']);
496    }
497    if (flag_set['c'] || flag_set['w'] || flag_set['C'] || flag_set['r']) {
498        if (!flag_set['r'] && g_kernel_version <= 2.5
499            && strstr(flag_val['d'], "/dev/")) {
500            fatal_error
501                ("Please don't give a /dev entry. Give a SCSI node for the parameter of the -d flag.");
502        }
503        if (flag_set['r'] && g_kernel_version <= 2.5
504            && !strstr(flag_val['d'], "/dev/")) {
505            fatal_error
506                ("Please give a /dev entry, not a SCSI node, as the parameter of the -d flag.");
507        }
508        if (g_kernel_version >= 2.6 && !strstr(flag_val['d'], "/dev/")) {
509            log_to_screen
510                ("Linus says 2.6 has a broken ide-scsi module. Proceed at your own risk...");
511        }
512
513        if (system("which cdrecord > /dev/null 2> /dev/null")
514            && system("which dvdrecord > /dev/null 2> /dev/null")) {
515            fatal_error
516                ("Please install dvdrecord/cdrecord and try again.");
517        }
518        if (flag_set['C']) {
519            bkpinfo->cdrw_speed = atoi(flag_val['C']);
520            if (bkpinfo->cdrw_speed < 1) {
521                fatal_error
522                    ("You specified a silly speed for a CD-R[W] drive");
523            }
524            if (!flag_set['L']) {
525                log_to_screen
526                    ("You must use -L with -C. Therefore I am setting it for you.");
527                flag_set['L'] = 1;
528                flag_val['L'][0] = '\0';
529            }
530        } else {
531            log_msg(3, "flag_val['c'] = %s", flag_val['c']);
532            log_msg(3, "flag_val['w'] = %s", flag_val['w']);
533//    log_msg(3, "flag_set['r'] = %i", flag_set['r'] );
534            if (flag_set['c']) {
535                bkpinfo->cdrw_speed = atoi(flag_val['c']);
536            } else if (flag_set['w']) {
537                bkpinfo->cdrw_speed = atoi(flag_val['w']);
538            } else if (flag_set['r']) {
539                bkpinfo->cdrw_speed = 1;    /*atoi(flag_val['r']); */
540            }
541
542            if (bkpinfo->cdrw_speed < 1) {
543                fatal_error
544                    ("You specified a silly speed for a CD-R[W] drive");
545            }
546        }
547    }
548    if (flag_set['t'] && !flag_set['d']) {
549        log_it("Hmm! No tape drive specified. Let's see what we can do.");
550        if (find_tape_device_and_size(flag_val['d'], tmp)) {
551            fatal_error
552                ("Tape device not specified. I couldn't find it either.");
553        }
554        flag_set['d'] = TRUE;
555        sprintf(tmp,
556                "You didn't specify a tape streamer device. I'm assuming %s",
557                flag_val['d']);
558        log_to_screen(tmp);
559        percent = 0;
560    }
561
562    if (flag_set['r'])          // DVD
563    {
564        if (flag_set['m']) {
565            fatal_error
566                ("Manual CD tray (-m) not yet supported in conjunction w/ DVD drives. Drop -m.");
567        }
568        if (!flag_set['d']) {
569            if (!find_dvd_device(flag_val['d'], FALSE)) {
570                flag_set['d'] = TRUE;
571                log_to_screen("I guess DVD drive is at %s", flag_val['d']);
572            }
573        }
574        if (!find_home_of_exe("growisofs")) {
575            fatal_error
576                ("Please install growisofs (probably part of dvd+rw-tools). If you want DVD support, you need it.");
577        }
578        if (!find_home_of_exe("dvd+rw-format")) {
579            fatal_error
580                ("Please install dvd+rw-format (probably part of dvd+rw-tools). If you want DVD support, you need it.");
581        }
582        if (strchr(flag_val['d'], ',')) {
583            fatal_error
584                ("Please don't give a SCSI node. Give a _device_, preferably a /dev entry, for the parameter of the -d flag.");
585        }
586        if (!flag_set['s']) {
587            sprintf(flag_val['s'], "%d", DEFAULT_DVD_DISK_SIZE);    // 4.7 salesman's GB = 4.482 real GB = 4582 MB
588            strcat(flag_val['s'], "m");
589            log_to_screen
590                ("You did not specify a size (-s) for DVD. I'm guessing %s.",
591                 flag_val['s']);
592            flag_set['s'] = 1;
593        }
594/*
595      if (flag_set['Z']) {
596      bkpinfo->blank_dvd_first = TRUE;
597      }
598*/
599    }
600
601    if (flag_set['t'] || flag_set['u']) {   /* tape size */
602        if (strchr(flag_val['d'], ',')) {
603            fatal_error
604                ("Please don't give a SCSI node. Give a _device_, preferably a /dev entry, for the parameter of the -d flag.");
605        }
606        if (flag_set['O']) {
607            if (flag_set['s']) {
608                if (flag_set['t']) {
609                    fatal_error
610                        ("For the moment, please don't specify a tape size. Mondo should handle end-of-tape gracefully anyway.");
611                }
612                if (process_the_s_switch(bkpinfo, flag_val['s'])) {
613                    fatal_error("Bad -s switch");
614                }
615            } else if (flag_set['u'] || flag_set['t']) {
616                for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
617                    bkpinfo->media_size[i] = 0;
618                }
619            } else {
620                retval++;
621                log_to_screen("Tape size not specified.\n");
622            }
623        }
624    } else {                    /* CD size */
625        if (flag_set['s']) {
626            if (process_the_s_switch(bkpinfo, flag_val['s'])) {
627                fatal_error("Bad -s switch");
628            }
629        }
630        if (flag_set['w']) {
631            bkpinfo->wipe_media_first = TRUE;
632        }                       /* CD-RW */
633    }
634    if (flag_set['n']) {
635        strncpy(bkpinfo->nfs_mount, flag_val['n'], MAX_STR_LEN);
636        if (!flag_set['d']) {
637            strncpy(bkpinfo->nfs_remote_dir, "/", MAX_STR_LEN);
638        }
639        sprintf(tmp, "mount | grep -x \"%s .*\" | cut -d' ' -f3",
640                bkpinfo->nfs_mount);
641        strncpy(bkpinfo->isodir,
642                call_program_and_get_last_line_of_output(tmp),
643                MAX_STR_LEN / 4);
644        if (strlen(bkpinfo->isodir) < 3) {
645            retval++;
646            log_to_screen("NFS share is not mounted. Please mount it.\n");
647        }
648        log_msg(3, "mount = %s", bkpinfo->nfs_mount);
649        log_msg(3, "isodir= %s", bkpinfo->isodir);
650    }
651    if (flag_set['c']) {
652        bkpinfo->backup_media_type = cdr;
653    }
654    if (flag_set['C']) {
655        bkpinfo->backup_media_type = cdstream;
656    }
657    if (flag_set['i']) {
658        bkpinfo->backup_media_type = iso;
659    }
660    if (flag_set['n']) {
661        bkpinfo->backup_media_type = nfs;
662    }
663    if (flag_set['r']) {
664        bkpinfo->backup_media_type = dvd;
665    }
666    if (flag_set['t']) {
667        bkpinfo->backup_media_type = tape;
668    }
669    if (flag_set['u']) {
670        bkpinfo->backup_media_type = udev;
671    }
672    if (flag_set['w']) {
673        bkpinfo->backup_media_type = cdrw;
674    }
675
676/* optional, popular */
677    if (flag_set['g']) {
678        g_text_mode = FALSE;
679    }
680    if (flag_set['E']) {
681        if (bkpinfo->exclude_paths[0]) {
682            strcat(bkpinfo->exclude_paths, " ");
683        }
684        asprintf(&tmp1, flag_val['E']);
685        p = tmp1;
686        q = tmp1;
687
688        /* Cut the flag_val['E'] in parts containing all paths to test them */
689        while (p != NULL) {
690            q = strchr(p, ' ');
691            if (q != NULL) {
692                *q = '\0';
693                if (stat(p, &buf) != 0) {
694                    log_msg(1, "WARNING ! %s doesn't exist", p);
695                }
696                p = q+1 ;
697            } else {
698                if (stat(p, &buf) != 0) {
699                    log_msg(1, "WARNING ! %s doesn't exist", p);
700                }
701                p = NULL;
702            }
703        }
704        paranoid_free(tmp1);
705
706        strncpy(bkpinfo->exclude_paths + strlen(bkpinfo->exclude_paths),
707                flag_val['E'],
708                4*MAX_STR_LEN - strlen(bkpinfo->exclude_paths));
709    }
710    if (flag_set['e']) {
711        bkpinfo->please_dont_eject = TRUE;
712    }
713    if (flag_set['N'])          // exclude NFS mounts & devices
714    {
715//      strncpy(psz, list_of_NFS_devices_and_mounts(), MAX_STR_LEN);
716        strncpy(psz, list_of_NFS_mounts_only(), MAX_STR_LEN);
717        if (bkpinfo->exclude_paths[0]) {
718            strncat(bkpinfo->exclude_paths, " ", MAX_STR_LEN);
719        }
720        strncat(bkpinfo->exclude_paths, psz, MAX_STR_LEN);
721        log_msg(3, "-N means we're now excluding %s",
722                bkpinfo->exclude_paths);
723    }
724    if (strlen(bkpinfo->exclude_paths) >= MAX_STR_LEN) {
725        fatal_error
726            ("Your '-E' parameter is too long. Please use '-J'. (See manual.)");
727    }
728    if (flag_set['b']) {
729        strcpy(psz, flag_val['b']);
730        log_msg(1, "psz = '%s'", psz);
731        if (psz[strlen(psz) - 1] == 'k') {
732            psz[strlen(psz) - 1] = '\0';
733            itbs = atol(psz) * 1024L;
734        } else {
735            itbs = atol(psz);
736        }
737        log_msg(1, "'%s' --> %ld", flag_val['b'], itbs);
738        log_msg(1, "Internal tape block size is now %ld bytes", itbs);
739        if (itbs % 512 != 0 || itbs < 256 || itbs > 1024L * 1024) {
740            fatal_error
741                ("Are you nuts? Silly, your internal tape block size is. Abort, I shall.");
742        }
743        bkpinfo->internal_tape_block_size = itbs;
744    }
745    if (flag_set['D']) {
746        bkpinfo->differential = 1;
747//      bkpinfo->differential = atoi (flag_val['D']);
748        if ((bkpinfo->differential < 1) || (bkpinfo->differential > 9)) {
749            fatal_error
750                ("The D option should be between 1 and 9 inclusive");
751        }
752    }
753    if (flag_set['x']) {
754        strncpy(bkpinfo->image_devs, flag_val['x'], MAX_STR_LEN / 4);
755        if (run_program_and_log_output("which ntfsclone", 2)) {
756            fatal_error("Please install ntfsprogs package/tarball.");
757        }
758    }
759    if (flag_set['m']) {
760        bkpinfo->manual_cd_tray = TRUE;
761    }
762    if (flag_set['k']) {
763        strncpy(bkpinfo->kernel_path, flag_val['k'], MAX_STR_LEN);
764        if (!strcmp(bkpinfo->kernel_path, "failsafe")) {
765            strcpy(bkpinfo->kernel_path, "FAILSAFE");
766        }
767        if (strcmp(bkpinfo->kernel_path, "FAILSAFE")
768            && !does_file_exist(bkpinfo->kernel_path)) {
769            retval++;
770            sprintf(tmp,
771                    "You specified kernel '%s', which does not exist\n",
772                    bkpinfo->kernel_path);
773            log_to_screen(tmp);
774        }
775    }
776    if (flag_set['p']) {
777        strncpy(bkpinfo->prefix, flag_val['p'], MAX_STR_LEN / 4);
778    }
779
780
781    if (flag_set['d']) {        /* backup directory (if ISO/NFS) */
782        if (flag_set['i']) {
783            strncpy(bkpinfo->isodir, flag_val['d'], MAX_STR_LEN / 4);
784            sprintf(tmp, "ls -l %s", bkpinfo->isodir);
785            if (run_program_and_log_output(tmp, FALSE)) {
786                fatal_error
787                    ("output folder does not exist - please create it");
788            }
789        } else if (flag_set['n']) {
790            strncpy(bkpinfo->nfs_remote_dir, flag_val['d'], MAX_STR_LEN);
791        } else {                /* backup device (if tape/CD-R/CD-RW) */
792
793            strncpy(bkpinfo->media_device, flag_val['d'], MAX_STR_LEN / 4);
794        }
795    }
796
797    if (flag_set['n']) {
798        sprintf(tmp, "echo hi > %s/%s/.dummy.txt", bkpinfo->isodir,
799                bkpinfo->nfs_remote_dir);
800        if (run_program_and_log_output(tmp, FALSE)) {
801            retval++;
802            sprintf(tmp,
803                    "Are you sure directory '%s' exists in remote dir '%s'?\nIf so, do you have rights to write to it?\n",
804                    bkpinfo->nfs_remote_dir, bkpinfo->nfs_mount);
805            log_to_screen(tmp);
806        }
807    }
808
809    if (!flag_set['d']
810        && (flag_set['c'] || flag_set['w'] || flag_set['C'])) {
811        if (g_kernel_version >= 2.6) {
812            if (popup_and_get_string
813                ("Device", "Please specify the device",
814                 bkpinfo->media_device, MAX_STR_LEN / 4)) {
815                retval++;
816                log_to_screen("User opted to cancel.");
817            }
818        } else if (find_cdrw_device(bkpinfo->media_device)) {
819            retval++;
820            log_to_screen
821                ("Tried and failed to find CD-R[W] drive automatically.\n");
822        } else {
823            flag_set['d'] = TRUE;
824            strncpy(flag_val['d'], bkpinfo->media_device, MAX_STR_LEN / 4);
825        }
826    }
827
828    if (!flag_set['d'] && !flag_set['n'] && !flag_set['C']) {
829        retval++;
830        log_to_screen("Please specify the backup device/directory.\n");
831        fatal_error
832            ("You didn't use -d to specify the backup device/directory.");
833    }
834/* optional, obscure */
835    for (i = '0'; i <= '9'; i++) {
836        if (flag_set[i]) {
837            bkpinfo->compression_level = i - '0';
838        }                       /* not '\0' but '0' */
839    }
840    if (flag_set['S']) {
841        sprintf(bkpinfo->scratchdir, "%s/mondo.scratch.%ld", flag_val['S'],
842                random() % 32768);
843    }
844    if (flag_set['T']) {
845        sprintf(bkpinfo->tmpdir, "%s/tmp.mondo.%ld", flag_val['T'],
846                random() % 32768);
847        sprintf(tmp, "touch %s/.foo.dat", flag_val['T']);
848        if (run_program_and_log_output(tmp, 1)) {
849            retval++;
850            log_to_screen
851                ("Please specify a tempdir which I can write to. :)");
852            fatal_error("I cannot write to the tempdir you specified.");
853        }
854        sprintf(tmp, "ln -sf %s/.foo.dat %s/.bar.dat", flag_val['T'],
855                flag_val['T']);
856        if (run_program_and_log_output(tmp, 1)) {
857            retval++;
858            log_to_screen
859                ("Please don't specify a SAMBA or VFAT or NFS tmpdir.");
860            fatal_error("I cannot write to the tempdir you specified.");
861        }
862    }
863    if (flag_set['A']) {
864        strncpy(bkpinfo->call_after_iso, flag_val['A'], MAX_STR_LEN);
865    }
866    if (flag_set['B']) {
867        strncpy(bkpinfo->call_before_iso, flag_val['B'], MAX_STR_LEN);
868    }
869    if (flag_set['F']) {
870        g_skip_floppies = TRUE;
871    }
872    if (flag_set['H']) {
873        g_cd_recovery = TRUE;
874    }
875    if (flag_set['l']) {
876#ifdef __FreeBSD__
877#  define BOOT_LOADER_CHARS "GLBMR"
878#else
879#  ifdef __IA64__
880#    define BOOT_LOADER_CHARS "GER"
881#  else
882#    define BOOT_LOADER_CHARS "GLR"
883#  endif
884#endif
885        if (!strchr
886            (BOOT_LOADER_CHARS,
887             (bkpinfo->boot_loader = flag_val['l'][0]))) {
888            log_msg(1, "%c? WTF is %c? I need G, L, E or R.",
889                    bkpinfo->boot_loader, bkpinfo->boot_loader);
890            fatal_error
891                ("Please specify GRUB, LILO, ELILO  or RAW with the -l switch");
892        }
893#undef BOOT_LOADER_CHARS
894    }
895    if (flag_set['f']) {
896        strncpy(bkpinfo->boot_device,
897                resolve_softlinks_to_get_to_actual_device_file(flag_val
898                                                               ['f']),
899                MAX_STR_LEN / 4);
900    }
901    if (flag_set['P']) {
902        strncpy(bkpinfo->postnuke_tarball, flag_val['P'], MAX_STR_LEN);
903    }
904    if (flag_set['Q']) {
905        i = which_boot_loader(tmp);
906        log_msg(3, "boot loader is %c, residing at %s", i, tmp);
907        printf("boot loader is %c, residing at %s\n", i, tmp);
908        finish(0);
909    }
910    if (flag_set['L']) {
911        bkpinfo->use_lzo = TRUE;
912        if (run_program_and_log_output("which lzop", FALSE)) {
913            retval++;
914            log_to_screen
915                ("Please install LZOP. You can't use '-L' until you do.\n");
916        }
917    }
918
919    if (!flag_set['o']
920        &&
921        !run_program_and_log_output
922        ("grep -Ei suse /etc/issue.net | grep -E '9.0' | grep 64", TRUE)) {
923        bkpinfo->make_cd_use_lilo = TRUE;
924        log_to_screen
925            ("Forcing you to use LILO. SuSE 9.0 (64-bit) has a broken mkfs.vfat binary.");
926    }
927    if (flag_set['o']) {
928        bkpinfo->make_cd_use_lilo = TRUE;
929    }
930#ifndef __FreeBSD__
931    else {
932        if (!is_this_a_valid_disk_format("vfat")) {
933            bkpinfo->make_cd_use_lilo = TRUE;
934            log_to_screen
935                ("Your kernel appears not to support vfat filesystems. I am therefore");
936            log_to_screen
937                ("using LILO instead of SYSLINUX as the CD/floppy's boot loader.");
938        }
939        if (run_program_and_log_output("which mkfs.vfat", FALSE)) {
940            bkpinfo->make_cd_use_lilo = TRUE;
941#ifdef __IA32__
942            log_to_screen
943                ("Your filesystem is missing 'mkfs.vfat', so I cannot use SYSLINUX as");
944            log_to_screen
945                ("your boot loader. I shall therefore use LILO instead.");
946#endif
947#ifdef __IA64__
948            log_to_screen
949                ("Your filesystem is missing 'mkfs.vfat', so I cannot prepare the EFI");
950            log_to_screen("environment correctly. Please install it.");
951            fatal_error("Aborting");
952#endif
953        }
954#ifdef __IA64__
955        /* We force ELILO usage on IA64 */
956        bkpinfo->make_cd_use_lilo = TRUE;
957#endif
958    }
959#endif
960
961    if (bkpinfo->make_cd_use_lilo && !does_file_exist("/boot/boot.b")) {
962        paranoid_system("touch /boot/boot.b");
963    }
964
965    i = flag_set['O'] + flag_set['V'];
966    if (i == 0) {
967        retval++;
968        log_to_screen("Specify backup (-O), verify (-V) or both (-OV).\n");
969    }
970
971/* and finally... */
972
973    paranoid_free(tmp);
974    paranoid_free(psz);
975    return (retval);
976}
977
978
979
980/**
981 * Get the switches from @p argc and @p argv using getopt() and place them in
982 * @p flag_set and @p flag_val.
983 * @param argc The argument count (@p argc passed to main()).
984 * @param argv The argument vector (@p argv passed to main()).
985 * @param flag_val An array indexed by switch letter - if a switch is set and
986 * has an argument then set flag_val[switch] to that argument.
987 * @param flag_set An array indexed by switch letter - if a switch is set then
988 * set flag_set[switch] to TRUE, else set it to FALSE.
989 * @return The number of problems with the command line (0 for success).
990 */
991int
992retrieve_switches_from_command_line(int argc, char *argv[],
993                                    char flag_val[128][MAX_STR_LEN],
994                                    bool flag_set[128])
995{
996    /*@ ints ** */
997    int opt = 0;
998    char tmp[MAX_STR_LEN];
999    int i = 0;
1000    int len;
1001
1002    /*@ bools *** */
1003    bool bad_switches = FALSE;
1004
1005    assert(flag_val != NULL);
1006    assert(flag_set != NULL);
1007
1008    for (i = 0; i < 128; i++) {
1009        flag_val[i][0] = '\0';
1010        flag_set[i] = FALSE;
1011    }
1012    while ((opt =
1013            getopt(argc, argv,
1014                   "0123456789A:B:C:DE:FHI:J:K:LNOP:QRS:T:VWb:c:d:ef:gik:l:mn:op:rs:tuw:x:"))
1015           != -1) {
1016        if (opt == '?') {
1017            bad_switches = TRUE;
1018            /*log_it("Invalid option: %c\n",optopt); */
1019        } else {
1020            if (flag_set[optopt]) {
1021                bad_switches = TRUE;
1022                sprintf(tmp, "Switch -%c previously defined as %s\n", opt,
1023                        flag_val[i]);
1024                log_to_screen(tmp);
1025            } else {
1026                flag_set[opt] = TRUE;
1027                if (optarg) {
1028                    len = strlen(optarg);
1029                    if (optarg[0] != '/' && optarg[len - 1] == '/') {
1030                        optarg[--len] = '\0';
1031                        log_to_screen
1032                            ("Warning - param '%s' should not have trailing slash!",
1033                             optarg);
1034                    }
1035                    if (opt == 'd') {
1036                        if (strchr(flag_val[opt], '/')
1037                            && flag_val[opt][0] != '/') {
1038                            sprintf(tmp,
1039                                    "-%c flag --- must be absolute path --- '%s' isn't absolute",
1040                                    opt, flag_val[opt]);
1041                            log_to_screen(tmp);
1042                            bad_switches = TRUE;
1043                        }
1044                    }
1045                    strcpy(flag_val[opt], optarg);
1046                }
1047            }
1048        }
1049    }
1050    for (i = optind; i < argc; i++) {
1051        bad_switches = TRUE;
1052        sprintf(tmp, "Invalid arg -- %s\n", argv[i]);
1053        log_to_screen(tmp);
1054    }
1055    return (bad_switches);
1056}
1057
1058
1059
1060
1061/**
1062 * Print a not-so-helpful help message and exit.
1063 */
1064void help_screen()
1065{
1066    log_msg(1, "Type 'man mondo-archive' for more information\n");
1067    exit(1);
1068}
1069
1070
1071/**
1072 * Terminate Mondo in response to a signal.
1073 * @param sig The signal number received.
1074 */
1075void terminate_daemon(int sig)
1076{
1077    char tmp[64];
1078    char tmp2[MAX_STR_LEN];
1079    //  char command[512];
1080    //  pid_t pid;
1081
1082    switch (sig) {
1083    case SIGINT:
1084        sprintf(tmp, "SIGINT");
1085        strcpy(tmp2, "You interrupted me :-)");
1086        break;
1087    case SIGKILL:
1088        sprintf(tmp, "SIGKILL");
1089        strcpy(tmp2,
1090               "I seriously have no clue how this signal even got to me. Something's wrong with your system.");
1091        break;
1092    case SIGTERM:
1093        sprintf(tmp, "SIGTERM");
1094        strcpy(tmp2, "Got terminate signal");
1095        break;
1096    case SIGHUP:
1097        sprintf(tmp, "SIGHUP");
1098        strcpy(tmp2, "Hangup on line");
1099        break;
1100    case SIGSEGV:
1101        sprintf(tmp, "SIGSEGV");
1102        strcpy(tmp2,
1103               "Internal programming error. Please send a backtrace as well as your log.");
1104        break;
1105    case SIGPIPE:
1106        sprintf(tmp, "SIGPIPE");
1107        strcpy(tmp2, "Pipe was broken");
1108        break;
1109    case SIGABRT:
1110        sprintf(tmp, "SIGABRT");
1111        sprintf(tmp2,
1112                "Abort - probably failed assertion. I'm sleeping for a few seconds so you can read the message.");
1113        break;
1114    default:
1115        sprintf(tmp, "(Unknown)");
1116    }
1117
1118    strcat(tmp, " signal received from OS");
1119    log_to_screen(tmp);
1120    log_to_screen(tmp2);
1121    if (sig == SIGABRT) {
1122        sleep(10);
1123    }
1124    kill_buffer();
1125    fatal_error
1126        ("Mondoarchive is terminating in response to a signal from the OS");
1127    finish(254);                // just in case
1128}
1129
1130
1131
1132
1133/**
1134 * Turn signal-trapping on or off.
1135 * @param on If TRUE, turn it on; if FALSE, turn it off (we still trap it, just don't do as much).
1136 */
1137void set_signals(int on)
1138{
1139    int signals[] =
1140        { SIGTERM, SIGHUP, SIGTRAP, SIGABRT, SIGINT, SIGKILL, SIGSTOP, 0 };
1141    int i;
1142
1143    signal(SIGPIPE, sigpipe_occurred);
1144    for (i = 0; signals[i]; i++) {
1145        if (on) {
1146            signal(signals[i], terminate_daemon);
1147        } else {
1148            signal(signals[i], termination_in_progress);
1149        }
1150    }
1151}
1152
1153
1154
1155
1156/**
1157 * Exit immediately without cleaning up.
1158 * @param sig The signal we are exiting due to.
1159 */
1160void termination_in_progress(int sig)
1161{
1162    log_msg(1, "Termination in progress");
1163    usleep(1000);
1164    pthread_exit(0);
1165}
1166
1167/* @} - end of cliGroup */
Note: See TracBrowser for help on using the repository browser.