source: trunk/mondo/src/mondoarchive/mondo-cli.c @ 900

Last change on this file since 900 was 900, checked in by Bruno Cornec, 14 years ago

Huge patch to introduce low level functions that will bw used everywhere (mr_free, mr_asprintf, ...)
Nearly linking now due to that.

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