source: trunk/mondo/mondo/mondoarchive/mondo-cli.c @ 489

Last change on this file since 489 was 489, checked in by bcornec, 13 years ago

svn merge -r 463:482 $SVN_M/branches/stable
svn merge -r 485:488 $SVN_M/branches/stable

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