source: branches/3.0/mondo/src/common/libmondo-cli.c

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