source: MondoRescue/branches/2.2.9/mondo/src/common/libmondo-cli.c @ 2223

Last change on this file since 2223 was 2223, checked in by Bruno Cornec, 11 years ago

mount the NFS dir in mondoarchive, if not already mounted, but present in fstab. Also avoids issue with trailing /. Should fix #304.

  • Property svn:keywords set to Id
File size: 50.1 KB
Line 
1/***************************************************************************
2$Id: libmondo-cli.c 2223 2009-06-17 01:38:48Z 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_string.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 char g_startdir[MAX_STR_LEN];    ///< ????? @bug ?????
23extern char *MONDO_OPTIONS;
24
25/*@ file pointer **************************************************/
26extern FILE *g_tape_stream;
27
28/*@ long long *****************************************************/
29extern long long g_tape_posK;
30
31/*@ long **********************************************************/
32extern long g_noof_sets;
33
34/*@ bool******** **************************************************/
35bool g_debugging = FALSE;       ///< ????? @bug ????? @ingroup globalGroup
36bool g_running_live = FALSE;    ///< ????? @bug ????? @ingroup globalGroup
37extern bool g_cd_recovery;
38
39extern void setup_tmpdir(char *path);
40extern double g_kernel_version;
41extern int g_current_media_number;
42extern pid_t g_main_pid;
43extern char *resolve_softlinks_to_get_to_actual_device_file(char *);
44
45/* Stuff that handles the -I and -E option when a whole disk DSF is used */
46typedef struct mounted_fs_struct {
47    char device[MAX_STR_LEN];       /* The name of the device */
48    char mount_point[MAX_STR_LEN];  /* The devices mount point */
49    unsigned char check;            /* 1 == included on DSF */
50    struct mounted_fs_struct *next;
51} MOUNTED_FS_STRUCT;
52static MOUNTED_FS_STRUCT *DSF_Head = NULL;      /* Points to the first entry of mounted_fs_struct list */
53static MOUNTED_FS_STRUCT *DSF_Tail = NULL;      /* Points to the last entry of mounted_fs_struct list */
54static void add_mounted_fs_struct (MOUNTED_FS_STRUCT *DSFptr);
55static void free_mounted_fs_list (void);
56static int get_dsf_mount_list (const char *dsf, char **included_dsf_list, char **excluded_dsf_list);
57static int create_list_of_non_NFS_mounted_file_systems (void);
58static MOUNTED_FS_STRUCT *find_mount_point_in_list (char *mount_point);
59static MOUNTED_FS_STRUCT *find_device_in_list (char *device);
60
61/* Do we use extended attributes and acl ?
62 * By default no, use --acl & --attr options to force their usage */
63extern char *g_getfacl;
64extern char *g_getfattr;
65
66/* Reference to global bkpinfo */
67extern struct s_bkpinfo *bkpinfo;
68
69extern void free_MR_global_filenames(void);
70
71/**
72 * @addtogroup cliGroup
73 * @{
74 */
75/**
76 * Populate @p bkpinfo from the command-line parameters stored in @p argc and @p argv.
77 * @param argc The argument count, including the program name; @p argc passed to main().
78 * @param argv The argument vector; @p argv passed to main().
79 * @param bkpinfo The backup information structure to populate.
80 * @return The number of problems with the command line (0 for success).
81 */
82int
83handle_incoming_parameters(int argc, char *argv[])
84{
85    /*@ int *** */
86    int res = 0;
87    int retval = 0;
88    int i = 0, j;
89
90    /*@ buffers *************** */
91    char *tmp;
92    char flag_val[128][MAX_STR_LEN];
93    bool flag_set[128];
94
95    tmp = malloc(9*MAX_STR_LEN);
96    for (i = 0; i < 128; i++) {
97        flag_val[i][0] = '\0';
98        flag_set[i] = FALSE;
99    }
100    for (j = 1; j <= MAX_NOOF_MEDIA; j++) {
101        bkpinfo->media_size[j] = 650;
102    }                           /* default */
103    res =
104        retrieve_switches_from_command_line(argc, argv, flag_val,
105                                            flag_set);
106    retval += res;
107    if (!retval) {
108        res = process_switches(flag_val, flag_set);
109        retval += res;
110    }
111/*
112  if (!retval)
113    {
114*/
115    log_msg(3, "Switches:-");
116    for (i = 0; i < 128; i++) {
117        if (flag_set[i]) {
118            sprintf(tmp, "-%c %s", i, flag_val[i]);
119            log_msg(3, tmp);
120        }
121    }
122//    }
123    sprintf(tmp, "rm -Rf %s/tmp.mondo.*", bkpinfo->tmpdir);
124    paranoid_system(tmp);
125    sprintf(tmp, "rm -Rf %s/mondo.scratch.*", bkpinfo->scratchdir);
126    paranoid_system(tmp);
127    sprintf(bkpinfo->scratchdir + strlen(bkpinfo->scratchdir),
128            "/mondo.scratch.%ld", random() % 32767);
129    sprintf(tmp, "mkdir -p %s/tmpfs", bkpinfo->tmpdir);
130    paranoid_system(tmp);
131    sprintf(tmp, "mkdir -p %s", bkpinfo->scratchdir);
132    paranoid_system(tmp);
133    paranoid_free(tmp);
134    return (retval);
135}
136
137
138
139
140/**
141 * Store the sizespec(s) stored in @p value into @p bkpinfo.
142 * @param bkpinfo The backup information structure; the @c bkpinfo->media_size field will be populated.
143 * @param value The sizespec (e.g. "2g", "40m").
144 * @return 0, always.
145 * @bug Return code not needed.
146 */
147int process_the_s_switch(char *value)
148{
149    int j;
150    char tmp[MAX_STR_LEN], *p, comment[MAX_STR_LEN];
151
152    assert(bkpinfo != NULL);
153    assert(value != NULL);
154
155    bkpinfo->media_size[0] = -1;    /* dummy value */
156    for (j = 1, p = value; j < MAX_NOOF_MEDIA && strchr(p, ',');
157         j++, p = strchr(p, ',') + 1) {
158        strncpy(tmp, p, MAX_STR_LEN);
159        *(strchr(tmp, ',')) = '\0';
160        bkpinfo->media_size[j] = friendly_sizestr_to_sizelong(tmp);
161        sprintf(comment, "media_size[%d] = %ld", j,
162                bkpinfo->media_size[j]);
163        log_msg(3, comment);
164    }
165    for (; j <= MAX_NOOF_MEDIA; j++) {
166        bkpinfo->media_size[j] = friendly_sizestr_to_sizelong(p);
167    }
168//      bkpinfo->media_size[0] = bkpinfo->media_size[MAX_NOOF_MEDIA];
169    for (j = 1; j <= MAX_NOOF_MEDIA; j++) {
170        if (bkpinfo->media_size[j] <= 0) {
171            log_msg(1, "You gave media #%d an invalid size\n", j);
172            return (-1);
173        }
174    }
175    return (0);
176}
177
178/**
179 * Frees the memory for all of the structures on the linked list of
180 * all of the non-NFS mounted file systems.
181 */
182static void free_mounted_fs_list (void) {
183    MOUNTED_FS_STRUCT *DSFptr = NULL;
184    MOUNTED_FS_STRUCT *DSFnext = NULL;
185 
186    DSFptr = DSF_Head;
187    while (DSFptr != NULL) {
188        DSFnext = DSFptr->next;
189        paranoid_free(DSFptr);
190        DSFptr = DSFnext;
191    }
192    DSF_Head = NULL;
193    DSF_Tail = NULL;
194}
195
196/**
197 * Creates a singly linked list of all of the non-NFS mounted file systems.
198 * @param DSFptr A pointer  to the structure MOUNTED_FS_STRUCT used to hold
199 * the list of mounted file systems.
200 * @return None.
201 */
202static void add_mounted_fs_struct (MOUNTED_FS_STRUCT *DSFptr)
203{
204    assert (DSFptr);
205    if (DSF_Head == NULL) {
206        DSF_Head = DSFptr;
207    } else {
208        DSF_Tail->next = DSFptr;
209    }
210    DSFptr->next = NULL;
211    DSF_Tail = DSFptr;
212}
213
214/**
215 * Find the structure, in the singly linked list of all of the non-NFS
216 * mounted file systems, that contains the specified device.
217 * @param device The device to find
218 * @return NULL if it didn't find the device, a pointer to the
219 * structure if it did.
220 */
221static MOUNTED_FS_STRUCT *find_device_in_list (char *device)
222{
223    MOUNTED_FS_STRUCT *DSFptr = NULL;
224
225    DSFptr = DSF_Head;
226    while (DSFptr != NULL) {
227        if (!strcmp(DSFptr->device, device)) {
228            break;
229        }
230        DSFptr = DSFptr->next;
231    }
232    return (DSFptr);
233}
234
235/**
236 * Find the structure, in the singly linked list of all of the non-NFS
237 * mounted file systems, that contains the specified mount point.
238 * @param mount_point The mount point to find
239 * @return NULL is it didn't find the mount point, a pointer to the
240 * structure if it did.
241 */
242static MOUNTED_FS_STRUCT *find_mount_point_in_list (char *mount_point)
243{
244    MOUNTED_FS_STRUCT *DSFptr = NULL;
245
246    DSFptr = DSF_Head;
247    while (DSFptr != NULL) {
248        if (!strcmp(DSFptr->mount_point, mount_point)) {
249            break;
250        }
251        DSFptr = DSFptr->next;
252    }
253    return (DSFptr);
254}
255
256/**
257 * Creates a linked list of all of the non-NFS mounted file systems.
258 * We use a linked list because we don't know how many  mounted file
259 * there are (and there can be a lot).
260 * @return 0 on success and greated than 0 on failure.
261 */
262static int create_list_of_non_NFS_mounted_file_systems (void)
263{
264    int i = 0;
265    int mount_cnt = 0;
266    char *mounted_file_system = NULL;
267    char *command = NULL;
268    char *token = NULL;
269    char token_chars[] =" :\t\r\f\a\0";
270    MOUNTED_FS_STRUCT *DSFptr = NULL;
271
272    free_mounted_fs_list();
273    /********
274    * Find the number of mounted file system entries and their respective mount points.
275    * I can't return all of the entries as one string because it's length can be longer
276    * than MAX_STR_LEN which is used in call_program_and_get_last_line_of_output().
277    * So start looping and get the number of  mounted file systems and query them one by one.
278    ********/
279    /* Get the number of mounted file systems ((those that start with "/dev/" */
280    mr_asprintf(&command, "mount 2>/dev/null | awk '{if($1 ~ \"^/dev/\"){print $0}}'|wc -l");
281    log_msg(5, "Running: %s", command);
282    mr_asprintf(&mounted_file_system, "%s", call_program_and_get_last_line_of_output(command));
283    paranoid_free(command);
284
285    mount_cnt = atoi(mounted_file_system);
286    log_msg (5, "mount_cnt: %d", mount_cnt);
287    paranoid_free(mounted_file_system);
288
289    for (i=mount_cnt; i > 0; i--) {
290        mr_asprintf(&command, "mount 2>/dev/null | awk '{if($1 ~ \"^/dev/\"){print $1,$3}}'|head -n %d", i);
291        log_msg(5, "Running: %s", command);
292        mr_asprintf(&mounted_file_system, "%s", call_program_and_get_last_line_of_output(command));
293        paranoid_free(command);
294
295        log_msg (5, "mounted_file_system: %s", mounted_file_system);
296        if ((token = strtok(mounted_file_system, token_chars)) == NULL) {
297            log_msg (4, "Could not get the list of mounted file systems");
298            paranoid_free(mounted_file_system);
299            return (1);
300        }
301        log_msg (5, "token: %s", token);
302        while (token != NULL) {
303            log_msg (5, "token: %s", token);
304            if ((DSFptr = (MOUNTED_FS_STRUCT *) calloc(1, sizeof(MOUNTED_FS_STRUCT))) == NULL) {
305                fatal_error ("Cannot allocate memory");
306            }
307            add_mounted_fs_struct(DSFptr);
308            strcpy(DSFptr->device, token);
309            if ((token = strtok(NULL, token_chars)) == NULL) {
310                log_msg (5, "Ran out of entries on the mounted file systems list");
311                paranoid_free(mounted_file_system);
312                return (1);
313            }
314            log_msg (5, "token: %s", token);
315            strcpy(DSFptr->mount_point, token);
316            token = strtok(NULL, token_chars); 
317        }
318        paranoid_free(mounted_file_system);
319    }
320    /********
321    * DSFptr = DSF_Head;
322    * while (DSFptr != NULL) {
323    * printf ("Dev: %s  MP: %s  Check: %d\n", DSFptr->device, DSFptr->mount_point, DSFptr->check);
324    * DSFptr = DSFptr->next;
325    * }
326    ********/
327    return (0);
328}
329
330/**
331 * Given a whole disk device special file, determine which mounted file systems
332 * are on the dsf's partitions and which mounted file systems are not.
333 * @param dsf The whole disk device special file.
334 * @param included_dsf_list A char pointer used to hold the list of mount points
335 * that are on the dsf. Memory for the array will be allocated within the function.
336 * @param excluded_dsf_list A char pointer used to hold the list of mount points
337 * that are not on the dsf. Memory for the array will be allocated within the function.
338 * @return 0 on success, -1 if no device special file was passed in, -2 if a device
339 * special file was passed in but it has no partitions on it, or 1 on failure
340 */
341static int get_dsf_mount_list (const char *dsf, char **included_dsf_list, char **excluded_dsf_list) {
342    int i = 0;
343    int c = 0;
344    int lastpos = 0;
345    char VG[MAX_STR_LEN];
346    char *tmp = NULL;
347    char *command = NULL;
348    char *partition_list = NULL;
349    char partitions[64][MAX_STR_LEN];
350    char *mount_list = NULL;
351    char *token = NULL;
352    char token_chars[] =" \t\r\f\a\0";
353    MOUNTED_FS_STRUCT *DSFptr = NULL;
354
355    memset((char *)partitions, 0, sizeof(partitions));
356
357    log_msg(5, "dsf: %s", dsf);
358   
359    /********
360    * See if a device special file was passed in (i.e. it must start with /dev/
361    ********/
362    if (strncmp(dsf, "/dev/", 5)) {
363        log_msg (5, "%s does not start with /dev/ and (probably) is not a  device special file", dsf);
364        return (-1);
365    }
366    log_msg(5, "  %s looks like a device special file", dsf);
367    /* Verify that the dsf exists */ 
368    mr_asprintf(&command, "ls -al %s 2>/dev/null | wc -l", dsf);
369    log_msg(5, "  Executing: %s", command);
370    mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output(command));
371    paranoid_free(command);
372
373    log_msg(5, "  Return value: %s", tmp);
374    c = atoi(tmp);
375    paranoid_free(tmp);
376
377    if (!c) {
378        log_to_screen("Cannot find device special file %s", dsf);
379        return (1);
380    }
381    log_msg(5, "  %s device special file exists", dsf);
382   
383    /* Get a list of the mounted file systems */
384    if (create_list_of_non_NFS_mounted_file_systems()) {
385        log_to_screen ("Could not get the list of mounted file systems");
386        return (1);
387    }
388    log_msg (5, "Processing dsf: %s", dsf);
389    /********
390    * Get a list of the dsf's partitions. There could be no partitions on the disk
391    * or a dsf of a partition was passed in (e.g. /dev/sda1 instead of /dev/sda).
392    * Either way, it's an error.
393    ********/
394    mr_asprintf(&command, 
395      "parted2fdisk -l %s 2>/dev/null|grep -E \"^/dev/\"|awk '{printf(\"%%s \", $1)}END{print \"\"}'", dsf);
396    log_msg(4, "Executing: %s", command);
397    mr_asprintf(&partition_list, "%s", call_program_and_get_last_line_of_output(command));
398    paranoid_free(command);
399    log_msg(4, "Partition list for %s: %s", dsf, partition_list);
400    if (!strlen(partition_list)) {
401        /* There were no partitions on the disk */
402        log_msg(4, "Cannot find any partitions on device special file %s", dsf);
403        return (-2);
404    }
405
406    /* Fill the partition list */
407    i = 0;
408    lastpos = 0;
409    while ((token = mr_strtok(partition_list, token_chars, &lastpos)) != NULL) {
410        log_msg (5, "Found partition: %s", token);
411        strcpy(partitions[i++], token);
412    }
413    paranoid_free(partition_list);
414 
415    /********
416     * At this point, we have a list of all of the partitions on the dsf. Now try to
417     * see which partitions have a file system on them.
418     *
419     * Loop through each partition on the disk and:
420     *
421     * - If the partition is swap, it ignores it.
422     *
423     * - If the partition is mounted (e.g. /dev/sda1 is mounted on /boot), it adds an entry
424     *  to the linked list, copies to it the device name and mount point, and sets check == 1.
425     *
426     * - If the partition is part of a Volume Group that has Logical Volumes mounted, it adds
427     *  an entry to the linked list for each mounted Logical Volume in that Volume Group, copying
428     *  to it the device name and mount point, and sets check == 1. Note that if the Volume Group
429     *  contains more than one disk, it will still add the entry even if the Logical Volume's
430     *  extents are not on the dsf that was passed in to the function. For example, Volume Group
431     *  VolGroup00 contains the disks /dev/sda1 and /dev/sdb1, and the Logical Volumes LogVol01,
432     *  which is mounted on /var and has all of its extents on /dev/sda1, and LogVol02, which is
433     *  mounted as /usr and has all of its extents on /dev/sdb1. If you pass /dev/sda into the
434     *  function, both /var and /usr will be archived even though /usr is actually on/dev/sdb.
435     *
436     * - If the partition is part of a Volume Group that has Logical Volumes used in a mounted
437     *  software raid device, it adds an entry to the linked list, copies to it the software raid
438     *  device name and mount point, and sets check == 1.
439     *
440     * - If the partition is part of a mounted software raid device, it adds an entry to the linked
441     *  list, copies to it the software raid device name and mount point, and sets check == 1.
442     *
443     ********/
444    for (i=0; strlen(partitions[i]); i++) {
445        log_msg(4, "Processing partition: %s", partitions[i]);
446        /* See if it's swap. If it is, ignore it. */
447        mr_asprintf(&command,
448          "parted2fdisk -l %s 2>/dev/null | awk '{if(($1==\"%s\")&&(toupper($0) ~ \"SWAP\")){print $1;exit}}'", 
449          dsf, partitions[i]);
450        log_msg(4, "  Running: %s", command);
451        mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output(command));
452        paranoid_free(command);
453        log_msg(4, "  Return value: %s", tmp);
454        c = strlen(tmp);
455        paranoid_free(tmp);
456        if (c) {
457            log_msg(4, "It's swap. Ignoring partition %s", partitions[i]); 
458            continue;
459        } 
460        /* It's not swap. See if we can find the mount point from the mount command. */
461        mr_asprintf(&command, "mount 2>/dev/null | awk '{if((NF>0)&&($1==\"%s\")){print $3}}'", partitions[i]);
462        mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output(command));
463        paranoid_free(command);
464        if (strlen(tmp)) {
465            log_msg(4, "  %s is mounted: %s", partitions[i], tmp);
466            if ((DSFptr = find_mount_point_in_list(tmp)) == NULL) {
467                log_msg (4, "Can't find mount point %s in mounted file systems list", tmp);
468                paranoid_free(tmp);
469                return (1);
470            }
471            DSFptr->check = 1;
472            paranoid_free(tmp);
473            continue;
474        }
475        paranoid_free(tmp);
476        /* It's not swap and it's not mounted. See if it's LVM */
477        log_msg(4, "  It's not mounted. Checking to see if it's LVM...");
478        /* Get the partition ID; 8e for LVM */
479        mr_asprintf(&command, "parted2fdisk -l %s |awk '{if($1 ~ \"^%s\"){print $5}}'", dsf, partitions[i]);
480        log_msg(4, "  Running: %s", command);
481        mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output(command));
482        paranoid_free(command);
483        if (strlen(tmp)) {
484            log_msg(4, "  Partition ID: %s", tmp);
485            if (!strcasecmp(tmp, "8e")) { 
486                /* It's LVM: Find the VG it's in */
487                log_msg(4, "  It's LVM: Find the VG it's in...");
488                mr_asprintf(&command, "pvdisplay -v %s 2>/dev/null|grep \"VG Name\"|awk '{print $NF}'", partitions[i]);
489                log_msg(4, "  Running: %s", command);
490                strcpy(VG, call_program_and_get_last_line_of_output(command));
491                paranoid_free(command);
492                log_msg(4, "  Volume Group: %s", VG);
493                if (strlen(VG)) {
494                    /* Found the Volume Group. Now find all of the VG's mount points */
495                    log_msg(4, "  Found the Volume Group. Now find all of the VG's mount points");
496                    mr_asprintf(&command, 
497                      "mount 2>/dev/null|grep -E \"/dev/mapper/%s-|/dev/%s/\"|awk '{printf(\"%%s \",$3)}END{print \"\"}'", 
498                      VG, VG);
499                    log_msg(4, "  Running: %s", command);
500                    mr_asprintf(&mount_list, "%s", call_program_and_get_last_line_of_output(command));
501                    paranoid_free(command);
502                    log_msg(4, "  VG %s mount_list: %s", VG, mount_list);
503                    lastpos = 0;
504                    while ((token = mr_strtok(mount_list, token_chars, &lastpos)) != NULL) {
505                        log_msg (5, "mount point token: %s", token);
506                        if ((DSFptr = find_mount_point_in_list(token)) == NULL) {
507                            log_msg (4, "Can't find mount point %s in mounted file systems list", token);
508                            paranoid_free(tmp);
509                            return (1);
510                        }
511                        DSFptr->check = 1;
512                    }
513                    /********
514                     * Now we want to see if there are any software raid devices using
515                     * any of the Logical Volumes on the Volume Group.
516                     *******/
517                    paranoid_free(mount_list);
518                    mr_asprintf(&command, "%s",
519                        "cat /proc/mdstat|grep -iv Personal|awk '{if($0~\"^.*[ ]+:\"){printf(\"/dev/%s \", $1)}}END{print \"\"}'");
520                    log_msg (5, "Running: %s", command);
521                    mr_asprintf(&mount_list, "%s", call_program_and_get_last_line_of_output(command));
522                    paranoid_free(command);
523                    log_msg(4, "  Software raid device list: %s", mount_list);   
524                    lastpos = 0;
525                    while ((token = mr_strtok(mount_list, token_chars, &lastpos)) != NULL) {
526                        mr_asprintf(&command, "mdadm --detail %s 2>/dev/null | grep -c %s", token, VG); 
527                        log_msg (5, "Running: %s", command);
528                        paranoid_free(tmp);
529                        mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output(command));
530                        paranoid_free(command);
531                        log_msg(4, "Number of Software raid device: %s", tmp);
532                        if (atoi(tmp)) {
533                            /* This device is on our disk */
534                            if ((DSFptr = find_device_in_list(token)) == NULL) {
535                                log_msg (4, "Can't find device %s in mounted file systems list", token);
536                                paranoid_free(tmp);
537                                return (1);
538                            }
539                            DSFptr->check = 1;
540                        }
541                    }
542                    paranoid_free(mount_list);
543                } else {
544                    log_msg (4, "Error finding Volume Group for partition %s", partitions[i]);
545                    paranoid_free(tmp);
546                    return (1);
547                }
548                paranoid_free(tmp);
549                continue;
550            }
551        } else {
552            log_msg (4, "Error finding partition type for the partition %s", partitions[i]);
553        }
554        paranoid_free(tmp);
555        /********
556         * It's not swap, mounted, or LVM. See if it's used in a software raid device.
557         ********/
558        log_msg (5, "It's not swap, mounted, or LVM. See if it's used in a software raid device.");
559        mr_asprintf(&command, "mdadm --examine %s 2>/dev/null | awk '{if($1 == \"UUID\"){print $3}}'", partitions[i]);
560        log_msg(4, "  Running: %s", command);
561        mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output(command));
562        paranoid_free(command);
563        if (!strlen(tmp)) {
564            log_msg(4, "  Partition %s is not used in a non-LVM software raid device", partitions[i]);
565            paranoid_free(tmp);
566            continue;
567        }
568        log_msg (5, "  UUID: %s", tmp);
569        /* Get the Software raid device list */
570        mr_asprintf(&command, "%s",
571         "cat /proc/mdstat|grep -iv Personal|awk '{if($0~\"^.*[ ]+:\"){printf(\"/dev/%s \", $1)}}END{print \"\"}'");
572        log_msg (5, "  Running: %s", command);
573        mr_asprintf(&mount_list, "%s", call_program_and_get_last_line_of_output(command));
574        paranoid_free(command);
575        log_msg(4, "  Software raid device list: %s", mount_list);   
576        /* Loop through the software raid device list to see if we can find the partition */
577        lastpos = 0;
578        while ((token = mr_strtok(mount_list, token_chars, &lastpos)) != NULL) {
579            mr_asprintf(&command, "mdadm --detail %s 2>/dev/null | grep -c %s", token, tmp);
580            log_msg(4, "  Running: %s", command);
581            paranoid_free(tmp);
582            mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output(command));
583            paranoid_free(command);
584            if (!atoi(tmp)) {
585                log_msg (4,"  Didn't find partition %s in software raid device %s", partitions[i], token);
586            } else {
587                if ((DSFptr = find_device_in_list(token)) == NULL) {
588                    log_msg (4, "Can't find device %s in mounted file systems list", token);
589                    paranoid_free(tmp);
590                    return (1);
591                }
592                DSFptr->check = 1;
593                break;
594            }
595        }
596        paranoid_free(tmp);
597    }
598    paranoid_free(partition_list);
599    paranoid_free(mount_list);
600
601    /* Determine how much memory to allocate for included_dsf_list and excluded_dsf_list */
602    i = 0;
603    DSFptr= DSF_Head;
604    while (DSFptr != NULL) {
605        i += strlen(DSFptr->mount_point) + 1;
606        DSFptr = DSFptr->next;
607    }
608    log_msg (5, "i: %d", i);
609    if ((*included_dsf_list = (char *) calloc(i+100, sizeof(char))) == NULL) {
610        fatal_error ("Cannot allocate memory");
611    }
612    if ((*excluded_dsf_list = (char *) calloc(i+100, sizeof(char))) == NULL) {
613        fatal_error ("Cannot allocate memory");
614    }
615    DSFptr= DSF_Head;
616    while (DSFptr != NULL) {
617        if (DSFptr->check) {
618            log_msg (5, "%s is mounted on %s and is on disk %s\n", DSFptr->device, DSFptr->mount_point, dsf);
619            strcat(*included_dsf_list, DSFptr->mount_point);
620            strcat(*included_dsf_list, " ");
621        } else {
622            log_msg (4, "%s is mounted on %s and is NOT on disk %s\n", DSFptr->device, DSFptr->mount_point, dsf);
623            strcat(*excluded_dsf_list, DSFptr->mount_point);
624            strcat(*excluded_dsf_list, " ");
625        }
626        DSFptr = DSFptr->next;
627    }
628    log_msg (5, "included_dsf_list: %s", *included_dsf_list);
629    log_msg (5, "excluded_dsf_list: %s", *excluded_dsf_list);
630    return (0);
631}
632
633
634/**
635 * Process mondoarchive's command-line switches.
636 * @param bkpinfo The backup information structure to populate.
637 * @param flag_val An array of the argument passed to each switch (the letter is the index).
638 * If a switch is not set or has no argument, the field in @p flag_val doesn't matter.
639 * @param flag_set An array of <tt>bool</tt>s indexed by switch letter: TRUE if it's set,
640 * FALSE if it's not.
641 * @return The number of problems with the switches, or 0 for success.
642 * @bug Maybe include a list of all switches (inc. intentionally undocumented ones not in the manual!) here?
643 */
644int
645process_switches(char flag_val[128][MAX_STR_LEN], bool flag_set[128])
646{
647
648    /*@ ints *** */
649    int i = 0;
650    int retval = 0;
651    int percent = 0;
652    int lastpos = 0;
653
654    /*@ buffers ** */
655    char *tmp = NULL;
656    char *tmp1 = NULL;
657    char *psz = NULL;
658    char *p = NULL;
659    char *q = NULL;
660    char *token = NULL;
661    char *mounted_on_dsf = NULL;
662    char *not_mounted_on_dsf = NULL;
663    char token_chars[] =" \t\r\f\a\0";
664
665    long itbs = 0L;
666
667    struct stat buf;
668
669    malloc_string(tmp);
670
671    assert(bkpinfo != NULL);
672    assert(flag_val != NULL);
673    assert(flag_set != NULL);
674
675    bkpinfo->internal_tape_block_size = DEFAULT_INTERNAL_TAPE_BLOCK_SIZE;
676
677    /* compulsory */
678    i = flag_set['c'] + flag_set['i'] + flag_set['n'] +
679        flag_set['t'] + flag_set['u'] + flag_set['r'] +
680        flag_set['w'] + flag_set['C'] + flag_set['U'];
681    if ((i == 0) && (! bkpinfo->restore_data)) {
682        retval++;
683        log_to_screen("You must specify the media type\n");
684    }
685    if (i > 1) {
686        retval++;
687        log_to_screen("Please specify only one media type\n");
688    }
689
690    if (flag_set['K']) {
691        g_loglevel = atoi(flag_val['K']);
692            log_msg(1,"Loglevel forced to %d",g_loglevel);
693        if (g_loglevel < 3) {
694            g_loglevel = 3;
695        }
696    }
697
698    if ((flag_set['L'] && flag_set['0']) && (! bkpinfo->restore_data)) {
699        retval++;
700        log_to_screen("You cannot have 'no compression' _and_ LZOP.\n");
701    }
702    if (! bkpinfo->restore_data) {
703        bkpinfo->backup_data = flag_set['O'];
704    }
705    bkpinfo->verify_data = flag_set['V'];
706
707    if (flag_set['I'] && !bkpinfo->backup_data) {
708        log_to_screen("-I switch is ignored if just verifying");
709    }
710    if (flag_set['E'] && !bkpinfo->backup_data) {
711        log_to_screen("-E switch is ignored if just verifying");
712    }
713
714    if (!find_home_of_exe("afio")) {
715        if (find_home_of_exe("star")) {
716            flag_set['R'] = TRUE;
717            log_msg(1, "Using star instead of afio");
718        } else {
719            fatal_error
720                ("Neither afio nor star is installed. Please install at least one.");
721        }
722    }
723
724    if (flag_set['R']) {
725        bkpinfo->use_star = TRUE;
726        if (flag_set['L']) {
727            fatal_error("You may not use star and lzop at the same time.");
728        }
729        if (!find_home_of_exe("star")) {
730            fatal_error
731                ("Please install 'star' RPM or tarball if you are going to use -R. Thanks.");
732        }
733    }
734
735    if ((flag_set['W']) && (! bkpinfo->restore_data)) {
736        bkpinfo->nonbootable_backup = TRUE;
737        log_to_screen("Warning - you have opted for non-bootable backup");
738        if (flag_set['f'] || flag_set['l']) {
739            log_to_screen
740                ("You don't need to specify bootloader or bootdevice");
741        }
742    }
743
744    if (flag_set['I']) {
745        if (bkpinfo->include_paths[0] == '-') {
746            retval++;
747            log_to_screen("Please supply a sensible value with '-I'\n");
748        }
749        if (!strcmp(bkpinfo->include_paths, "/")) {
750            log_msg(2, "'/' is pleonastic.");
751            bkpinfo->include_paths[0] = '\0';
752        }
753        if (bkpinfo->include_paths[0]) {
754            strcat(bkpinfo->include_paths, " ");
755        }
756       
757        mr_asprintf(&tmp1, "%s", flag_val['I']);
758        p = tmp1;
759        q = tmp1;
760
761        /* Cut the flag_val['I'] in parts containing all paths to test them */
762        while (p != NULL) {
763            q = strchr(p, ' ');
764            if (q != NULL) {
765                *q = '\0';
766                if ((stat(p, &buf) != 0) && (! bkpinfo->restore_data)) {
767                    log_msg(1, "ERROR ! %s doesn't exist", p);
768                    fatal_error("ERROR ! You specified a directory to include which doesn't exist");
769                }
770                p = q+1 ;
771            } else {
772                if ((stat(p, &buf) != 0) && (! bkpinfo->restore_data)) {
773                    log_msg(1, "ERROR ! %s doesn't exist", p);
774                    fatal_error("ERROR ! You specified a directory to include which doesn't exist");
775                }
776                p = NULL;
777            }
778        }
779        paranoid_free(tmp1);
780        while ((token = mr_strtok(flag_val['I'], token_chars, &lastpos)) != NULL) {
781            switch (get_dsf_mount_list(token, &mounted_on_dsf, &not_mounted_on_dsf)) {
782            /* It's a dsf but not a whole disk dsf */
783            case -2:
784                log_to_screen("Could %s be a partition instead of a whole disk device special file?\n Ignored.", token);
785                break;
786            /* Fatal error; exit */
787            case 1: 
788                fatal_error("Error processing -I option");
789            /* Everything is OK; process to archive data */
790            case 0:
791                log_to_screen("Archiving only the following file systems on %s:\n", token);
792                log_to_screen("  %s\n", mounted_on_dsf);
793                strcpy(bkpinfo->include_paths, "/");
794                if (strlen(not_mounted_on_dsf)) {
795                    log_msg (5, "Adding to bkpinfo->exclude_paths due to -I option: %s", not_mounted_on_dsf);
796                    log_to_screen("Not archiving the following file systems:\n");
797                    log_to_screen("  %s\n", not_mounted_on_dsf);
798                    strcat(bkpinfo->exclude_paths, not_mounted_on_dsf);
799                    strcat(bkpinfo->exclude_paths, "");
800                }
801                break;
802            /* A device special file was not passed in. Process it as a path. */
803            case -1:
804                    strcat(bkpinfo->include_paths, token);
805                    strcat(bkpinfo->include_paths, " ");
806                break; 
807            }
808        }
809        log_msg(1, "include_paths is now '%s'", bkpinfo->include_paths);
810        if (bkpinfo->exclude_paths != NULL) {
811            log_msg(1, "exclude_paths is now '%s'", bkpinfo->exclude_paths);
812        }
813        log_msg(4, "Finished with the -I option");
814    }
815
816    if (g_kernel_version >= 2.6 && !flag_set['d']
817        && (flag_set['c'] || flag_set['w']) && (! bkpinfo->restore_data)) {
818        fatal_error
819            ("If you are using the 2.6.x kernel, please specify the CD-R(W) device.");
820    }
821
822
823    if (flag_set['J']) {
824        if (flag_set['I']) {
825            retval++;
826            log_to_screen
827                ("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. :-)");
828        }
829        bkpinfo->make_filelist = FALSE;
830        strcpy(bkpinfo->include_paths, flag_val['J']);
831    }
832
833    if ((flag_set['c'] || flag_set['w'] || flag_set['C'] || flag_set['r']) && (! bkpinfo->restore_data)) {
834        if (!flag_set['r'] && g_kernel_version <= 2.5
835            && strstr(flag_val['d'], "/dev/")) {
836            fatal_error
837                ("Please don't give a /dev entry. Give a SCSI node for the parameter of the -d flag.");
838        }
839        if (flag_set['r'] && g_kernel_version <= 2.5
840            && !strstr(flag_val['d'], "/dev/")) {
841            fatal_error
842                ("Please give a /dev entry, not a SCSI node, as the parameter of the -d flag.");
843        }
844        if (g_kernel_version >= 2.6 && !strstr(flag_val['d'], "/dev/")) {
845            log_to_screen
846                ("Linus says 2.6 has a broken ide-scsi module. Proceed at your own risk...");
847        }
848
849        if (system("which cdrecord > /dev/null 2> /dev/null")
850            && system("which dvdrecord > /dev/null 2> /dev/null")) {
851            fatal_error
852                ("Please install dvdrecord/cdrecord and try again.");
853        }
854        if (flag_set['C']) {
855            bkpinfo->cdrw_speed = atoi(flag_val['C']);
856            if (bkpinfo->cdrw_speed < 1) {
857                fatal_error
858                    ("You specified a silly speed for a CD-R[W] drive");
859            }
860            if (!flag_set['L']) {
861                log_to_screen
862                    ("You must use -L with -C. Therefore I am setting it for you.");
863                flag_set['L'] = 1;
864                flag_val['L'][0] = '\0';
865            }
866        } else {
867            log_msg(3, "flag_val['c'] = %s", flag_val['c']);
868            log_msg(3, "flag_val['w'] = %s", flag_val['w']);
869//    log_msg(3, "flag_set['r'] = %i", flag_set['r'] );
870            if (flag_set['c']) {
871                bkpinfo->cdrw_speed = atoi(flag_val['c']);
872            } else if (flag_set['w']) {
873                bkpinfo->cdrw_speed = atoi(flag_val['w']);
874            } else if (flag_set['r']) {
875                bkpinfo->cdrw_speed = 1;    /*atoi(flag_val['r']); */
876            }
877
878            if (bkpinfo->cdrw_speed < 1) {
879                fatal_error
880                    ("You specified a silly speed for a CD-R[W] drive");
881            }
882        }
883    }
884
885    if ((flag_set['t'] && !flag_set['d']) && (! bkpinfo->restore_data)) {
886        log_it("Hmm! No tape drive specified. Let's see what we can do.");
887        if (find_tape_device_and_size(flag_val['d'], tmp)) {
888            fatal_error
889                ("Tape device not specified. I couldn't find it either.");
890        }
891        flag_set['d'] = TRUE;
892        sprintf(tmp,
893                "You didn't specify a tape streamer device. I'm assuming %s",
894                flag_val['d']);
895        log_to_screen(tmp);
896        percent = 0;
897    }
898
899    if (flag_set['U'])          // USB
900    {
901        if (! flag_set['d']) {
902            fatal_error
903                ("You need to specify a device file with -d for bootable USB device usage");
904        }
905        if ((!flag_set['s']) && (! bkpinfo->restore_data)) {
906            fatal_error("You did not specify a size (-s) for your USB device. Aborting");
907        }
908    }
909
910    if (flag_set['r'])          // DVD
911    {
912        if (flag_set['m']) {
913            fatal_error
914                ("Manual CD tray (-m) not yet supported in conjunction w/ DVD drives. Drop -m.");
915        }
916        if (!flag_set['d']) {
917            if (!find_dvd_device(flag_val['d'], FALSE)) {
918                flag_set['d'] = TRUE;
919                log_to_screen("I guess DVD drive is at %s", flag_val['d']);
920            }
921        }
922        if (strchr(flag_val['d'], ',')) {
923            fatal_error
924                ("Please don't give a SCSI node. Give a _device_, preferably a /dev entry, for the parameter of the -d flag.");
925        }
926        if (! bkpinfo->restore_data) {
927            if (!find_home_of_exe("growisofs")) {
928                fatal_error
929                    ("Please install growisofs (probably part of dvd+rw-tools). If you want DVD support, you need it.");
930            }
931            if (!find_home_of_exe("dvd+rw-format")) {
932                fatal_error
933                    ("Please install dvd+rw-format (probably part of dvd+rw-tools). If you want DVD support, you need it.");
934            }
935            if (!flag_set['s']) {
936                sprintf(flag_val['s'], "%d", DEFAULT_DVD_DISK_SIZE);    // 4.7 salesman's GB = 4.482 real GB = 4582 MB
937                strcat(flag_val['s'], "m");
938                log_to_screen
939                    ("You did not specify a size (-s) for DVD. I'm guessing %s.",
940                    flag_val['s']);
941                flag_set['s'] = 1;
942            }
943        }
944/*
945      if (flag_set['Z']) {
946      bkpinfo->blank_dvd_first = TRUE;
947      }
948*/
949    }
950
951    if (flag_set['t'] || flag_set['u']) {   /* tape size */
952        if (strchr(flag_val['d'], ',')) {
953            fatal_error
954                ("Please don't give a SCSI node. Give a _device_, preferably a /dev entry, for the parameter of the -d flag.");
955        }
956        if ((flag_set['O']) && (! bkpinfo->restore_data)) {
957            if (flag_set['s']) {
958                if (flag_set['t']) {
959                    fatal_error
960                        ("For the moment, please don't specify a tape size. Mondo should handle end-of-tape gracefully anyway.");
961                }
962                if (process_the_s_switch(flag_val['s'])) {
963                    fatal_error("Bad -s switch");
964                }
965            } else if (flag_set['u'] || flag_set['t']) {
966                for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
967                    bkpinfo->media_size[i] = 0;
968                }
969            } else {
970                retval++;
971                log_to_screen("Tape size not specified.\n");
972            }
973        }
974    } else if (! bkpinfo->restore_data) {           /* CD|USB size */
975        if (flag_set['s']) {
976            if (process_the_s_switch(flag_val['s'])) {
977                fatal_error("Bad -s switch");
978            }
979        }
980        if (flag_set['w']) {
981            bkpinfo->wipe_media_first = TRUE;
982        }                       /* CD-RW */
983    }
984
985    if (flag_set['n']) {
986        strncpy(bkpinfo->nfs_mount, flag_val['n'], MAX_STR_LEN);
987        if (!flag_set['d']) {
988            strncpy(bkpinfo->nfs_remote_dir, "/", MAX_STR_LEN);
989        }
990        sprintf(tmp, "mount | grep -E \"^%s[/]* .*\" | cut -d' ' -f3",
991                bkpinfo->nfs_mount);
992        strncpy(bkpinfo->isodir,
993                call_program_and_get_last_line_of_output(tmp),
994                MAX_STR_LEN / 4);
995        if (strlen(bkpinfo->isodir) < 3) {
996            log_to_screen("NFS share is not mounted. Trying to mount it for you.\n");
997            sprintf(tmp, "mount %s", bkpinfo->nfs_mount);
998            if (system(tmp)) {
999                log_to_screen("Unable to mount NFS share %s. Please mount manually.\n", bkpinfo->nfs_mount);
1000                retval++;
1001            } else {
1002                sprintf(tmp, "mount | grep -E \"^%s[/]* .*\" | cut -d' ' -f3",
1003                    bkpinfo->nfs_mount);
1004                strncpy(bkpinfo->isodir,
1005                        call_program_and_get_last_line_of_output(tmp),
1006                        MAX_STR_LEN / 4);
1007                if (strlen(bkpinfo->isodir) < 3) {
1008                    retval++;
1009                    log_to_screen("NFS share %s is strangely not mounted. Please mount manually...\n", bkpinfo->nfs_mount);
1010                }
1011            }
1012        }
1013        log_msg(3, "mount = %s", bkpinfo->nfs_mount);
1014        log_msg(3, "isodir= %s", bkpinfo->isodir);
1015    }
1016
1017    if (flag_set['c']) {
1018        bkpinfo->backup_media_type = cdr;
1019    }
1020    if (flag_set['C']) {
1021        bkpinfo->backup_media_type = cdstream;
1022    }
1023    if (flag_set['i']) {
1024        bkpinfo->backup_media_type = iso;
1025    }
1026    if (flag_set['n']) {
1027        bkpinfo->backup_media_type = nfs;
1028        /* Never try to eject a NFS device */
1029        bkpinfo->please_dont_eject = TRUE;
1030    }
1031    if (flag_set['r']) {
1032        bkpinfo->backup_media_type = dvd;
1033    }
1034    if (flag_set['t']) {
1035        bkpinfo->backup_media_type = tape;
1036    }
1037    if (flag_set['u']) {
1038        bkpinfo->backup_media_type = udev;
1039    }
1040    if (flag_set['w']) {
1041        bkpinfo->backup_media_type = cdrw;
1042    }
1043    if (flag_set['U']) {
1044        bkpinfo->backup_media_type = usb;
1045        /* Never try to eject a USB device */
1046        bkpinfo->please_dont_eject = TRUE;
1047    }
1048    if (flag_set['z']) {
1049        if (find_home_of_exe("getfattr")) {
1050            mr_asprintf(&g_getfattr,"getfattr");
1051        }
1052        if (find_home_of_exe("getfacl")) {
1053            mr_asprintf(&g_getfacl,"getfacl");
1054        }
1055    }
1056
1057    /* optional, popular */
1058    if (flag_set['g']) {
1059        g_text_mode = FALSE;
1060    }
1061
1062    if (flag_set['E']) {
1063        if (bkpinfo->exclude_paths[0] == '-') {
1064            retval++;
1065            log_to_screen("Please supply a sensible value with '-E'\n");
1066        }
1067        if (bkpinfo->exclude_paths[0]) {
1068            strcat(bkpinfo->exclude_paths, " ");
1069        }
1070        mr_asprintf(&tmp1, "%s", flag_val['E']);
1071
1072        p = tmp1;
1073        q = tmp1;
1074
1075        /* Cut the flag_val['E'] in parts containing all paths to test them */
1076        while (p != NULL) {
1077            q = strchr(p, ' ');
1078            if (q != NULL) {
1079                *q = '\0';
1080                /* Fix bug 14 where ending / cause a problem later
1081                * so handled here for the moment */
1082                q--;
1083                if (*q == '/') {
1084                    *q = '\0';
1085                }
1086                q++;
1087                /* End of bug fix */
1088                if ((stat(p, &buf) != 0) && (! bkpinfo->restore_data)) {
1089                    log_msg(1, "WARNING ! %s doesn't exist", p);
1090                }
1091                p = q+1 ;
1092            } else {
1093                if ((stat(p, &buf) != 0) && (! bkpinfo->restore_data)) {
1094                    log_msg(1, "WARNING ! %s doesn't exist", p);
1095                }
1096                p = NULL;
1097            }
1098        }
1099        paranoid_free(tmp1);
1100        lastpos = 0;
1101        while ((token = mr_strtok(flag_val['E'], token_chars, &lastpos)) != NULL) {
1102            switch (get_dsf_mount_list(token, &mounted_on_dsf, &not_mounted_on_dsf)) {
1103            case 1: 
1104                log_msg(1, "WARNING ! a path doesn't exist in -E option");
1105                break;
1106            /* Everything is OK; proceed to archive data */
1107            case 0:
1108                if (strlen(mounted_on_dsf)) {
1109                    log_to_screen("Excluding the following file systems on %s:\n", token);
1110                    log_to_screen("  %s\n", mounted_on_dsf);
1111                    log_msg (5, "Adding to bkpinfo->exclude_paths due to -E option: %s", mounted_on_dsf);
1112                    strcat(bkpinfo->exclude_paths, mounted_on_dsf);
1113                    strcat(bkpinfo->exclude_paths, " ");
1114                }
1115                break;
1116            /* It's a dsf but not a whole disk dsf */
1117            case -2:
1118                log_to_screen("Could %s be a partition instead of a whole disk device special file?\nIgnored.", token);
1119                break;
1120            /* A device special file was not passed in. Process it as a path. */
1121            case -1:
1122                strcat(bkpinfo->exclude_paths, token);
1123                strcat(bkpinfo->exclude_paths, " ");
1124                break;
1125            }
1126        }
1127        log_msg(1, "exclude_paths is now '%s'", bkpinfo->exclude_paths);
1128        log_msg(4, "Finished with the -E option");
1129    }
1130
1131    if (flag_set['e']) {
1132        bkpinfo->please_dont_eject = TRUE;
1133    }
1134
1135    if ((flag_set['N']) && (! bkpinfo->restore_data))       // exclude NFS mounts & devices
1136    {
1137//      strncpy(psz, list_of_NFS_devices_and_mounts(), MAX_STR_LEN);
1138        asprintf(&psz, "%s", list_of_NFS_mounts_only());
1139        if (bkpinfo->exclude_paths[0]) {
1140            strncat(bkpinfo->exclude_paths, " ", 4*MAX_STR_LEN);
1141        }
1142        strncat(bkpinfo->exclude_paths, psz, 4*MAX_STR_LEN);
1143        mr_free(psz);
1144
1145        log_msg(3, "-N means we're now excluding %s",
1146                bkpinfo->exclude_paths);
1147    }
1148
1149    if (strlen(bkpinfo->exclude_paths) >= 4*MAX_STR_LEN) {
1150        fatal_error
1151            ("Your '-E' parameter is too long. Increase MAX_STR_LEN");
1152    }
1153
1154    if (flag_set['b']) {
1155        mr_asprintf(&psz, flag_val['b']);
1156        log_msg(1, "psz = '%s'", psz);
1157        if (psz[strlen(psz) - 1] == 'k') {
1158            psz[strlen(psz) - 1] = '\0';
1159            itbs = atol(psz) * 1024L;
1160        } else {
1161            itbs = atol(psz);
1162        }
1163        mr_free(psz);
1164        log_msg(1, "'%s' --> %ld", flag_val['b'], itbs);
1165        log_msg(1, "Internal tape block size is now %ld bytes", itbs);
1166        if (itbs % 512 != 0 || itbs < 256 || itbs > 1024L * 1024) {
1167            fatal_error
1168                ("Are you nuts? Silly, your internal tape block size is. Abort, I shall.");
1169        }
1170        bkpinfo->internal_tape_block_size = itbs;
1171    }
1172
1173    if ((flag_set['D']) && (! bkpinfo->restore_data)) {
1174        bkpinfo->differential = 1;
1175//      bkpinfo->differential = atoi (flag_val['D']);
1176        if ((bkpinfo->differential < 1) || (bkpinfo->differential > 9)) {
1177            fatal_error
1178                ("The D option should be between 1 and 9 inclusive");
1179        }
1180    }
1181
1182    if (flag_set['x']) {
1183        strncpy(bkpinfo->image_devs, flag_val['x'], MAX_STR_LEN / 4);
1184        if ((run_program_and_log_output("which ntfsclone", 2)) && (! bkpinfo->restore_data)) {
1185            fatal_error("Please install ntfsprogs package/tarball.");
1186        }
1187    }
1188
1189    if (flag_set['m']) {
1190        bkpinfo->manual_cd_tray = TRUE;
1191    }
1192
1193    if ((flag_set['k']) && (! bkpinfo->restore_data)) {
1194        strncpy(bkpinfo->kernel_path, flag_val['k'], MAX_STR_LEN);
1195        if (!strcmp(bkpinfo->kernel_path, "failsafe")) {
1196            strcpy(bkpinfo->kernel_path, "FAILSAFE");
1197        }
1198        if (strcmp(bkpinfo->kernel_path, "FAILSAFE")
1199            && !does_file_exist(bkpinfo->kernel_path)) {
1200            retval++;
1201            sprintf(tmp,
1202                    "You specified kernel '%s', which does not exist\n",
1203                    bkpinfo->kernel_path);
1204            log_to_screen(tmp);
1205        }
1206    }
1207
1208    if (flag_set['p']) {
1209        strncpy(bkpinfo->prefix, flag_val['p'], MAX_STR_LEN / 4);
1210        log_msg(1,"Prefix forced to %s",bkpinfo->prefix);
1211    }
1212
1213    if (flag_set['d']) {        /* backup directory (if ISO/NFS) */
1214        if (flag_set['i']) {
1215            strncpy(bkpinfo->isodir, flag_val['d'], MAX_STR_LEN / 4);
1216            sprintf(tmp, "ls -l %s", bkpinfo->isodir);
1217            if (run_program_and_log_output(tmp, 2)) {
1218                fatal_error
1219                    ("output folder does not exist - please create it");
1220            }
1221        } else if (flag_set['n']) {
1222            strncpy(bkpinfo->nfs_remote_dir, flag_val['d'], MAX_STR_LEN);
1223        } else {                /* backup device (if tape/CD-R/CD-RW) */
1224            strncpy(bkpinfo->media_device, flag_val['d'], MAX_STR_LEN / 4);
1225        }
1226    }
1227
1228    if ((flag_set['n']) && (! bkpinfo->restore_data)) {
1229        mr_asprintf(&tmp1,"%s/%s/.dummy.txt", bkpinfo->isodir,bkpinfo->nfs_remote_dir);
1230        sprintf(tmp, "echo hi > %s", tmp1);
1231        if (run_program_and_log_output(tmp, 2)) {
1232            retval++;
1233            sprintf(tmp,
1234                    "Are you sure directory '%s' exists in remote dir '%s'?\nIf so, do you have rights to write to it?\n",
1235                    bkpinfo->nfs_remote_dir, bkpinfo->nfs_mount);
1236            log_to_screen(tmp);
1237        }
1238        unlink(tmp1);
1239        paranoid_free(tmp1);
1240    }
1241
1242    if (!flag_set['d']
1243        && (flag_set['c'] || flag_set['w'] || flag_set['C'])) {
1244        if (g_kernel_version >= 2.6) {
1245            if (popup_and_get_string
1246                ("Device", "Please specify the device",
1247                 bkpinfo->media_device, MAX_STR_LEN / 4)) {
1248                retval++;
1249                log_to_screen("User opted to cancel.");
1250            }
1251        } else if (find_cdrw_device(bkpinfo->media_device)) {
1252            retval++;
1253            log_to_screen
1254                ("Tried and failed to find CD-R[W] drive automatically.\n");
1255        } else {
1256            flag_set['d'] = TRUE;
1257            strncpy(flag_val['d'], bkpinfo->media_device, MAX_STR_LEN / 4);
1258        }
1259    }
1260
1261    if ((!flag_set['d'] && !flag_set['n'] && !flag_set['C']) && (! bkpinfo->restore_data)) {
1262        retval++;
1263        log_to_screen("Please specify the backup device/directory.\n");
1264        fatal_error
1265            ("You didn't use -d to specify the backup device/directory.");
1266    }
1267
1268    for (i = '0'; i <= '9'; i++) {
1269        if (flag_set[i]) {
1270            bkpinfo->compression_level = i - '0';
1271        }                       /* not '\0' but '0' */
1272    }
1273
1274    if (flag_set['S']) {
1275        sprintf(bkpinfo->scratchdir, "%s/mondo.scratch.%ld", flag_val['S'],
1276                random() % 32768);
1277    }
1278
1279    if (flag_set['T']) {
1280        setup_tmpdir(flag_val['T']);
1281        sprintf(tmp, "touch %s/.foo.dat", bkpinfo->tmpdir);
1282        if (run_program_and_log_output(tmp, 1)) {
1283            retval++;
1284            log_to_screen
1285                ("Please specify a tempdir which I can write to. :)");
1286            fatal_error("I cannot write to the tempdir you specified.");
1287        }
1288        sprintf(tmp, "ln -sf %s/.foo.dat %s/.bar.dat", bkpinfo->tmpdir, bkpinfo->tmpdir);
1289        if (run_program_and_log_output(tmp, 1)) {
1290            retval++;
1291            log_to_screen
1292                ("Please don't specify a SAMBA or VFAT or NFS tmpdir.");
1293            fatal_error("I cannot write to the tempdir you specified.");
1294        }
1295    }
1296
1297    if ((flag_set['A']) && (! bkpinfo->restore_data)) {
1298        strncpy(bkpinfo->call_after_iso, flag_val['A'], MAX_STR_LEN);
1299    }
1300
1301    if ((flag_set['B']) && (! bkpinfo->restore_data)) {
1302        strncpy(bkpinfo->call_before_iso, flag_val['B'], MAX_STR_LEN);
1303    }
1304
1305    if ((flag_set['H']) && (! bkpinfo->restore_data)) {
1306        g_cd_recovery = TRUE;
1307    }
1308
1309    if ((flag_set['l']) && (! bkpinfo->restore_data)) {
1310#ifdef __FreeBSD__
1311#  define BOOT_LOADER_CHARS "GLBMR"
1312#else
1313#  ifdef __IA64__
1314#    define BOOT_LOADER_CHARS "GER"
1315#  else
1316#    define BOOT_LOADER_CHARS "GLR"
1317#  endif
1318#endif
1319        if (!strchr
1320            (BOOT_LOADER_CHARS,
1321             (bkpinfo->boot_loader = flag_val['l'][0]))) {
1322            log_msg(1, "%c? WTF is %c? I need G, L, E or R.",
1323                    bkpinfo->boot_loader, bkpinfo->boot_loader);
1324            fatal_error
1325                ("Please specify GRUB, LILO, ELILO  or RAW with the -l switch");
1326        }
1327#undef BOOT_LOADER_CHARS
1328    }
1329
1330    if (flag_set['f']) {
1331        strncpy(bkpinfo->boot_device,
1332                resolve_softlinks_to_get_to_actual_device_file(flag_val
1333                                                               ['f']),
1334                MAX_STR_LEN / 4);
1335    }
1336
1337    if ((flag_set['P']) && (! bkpinfo->restore_data)) {
1338        strncpy(bkpinfo->postnuke_tarball, flag_val['P'], MAX_STR_LEN);
1339    }
1340
1341    if (flag_set['Q']) {
1342        i = which_boot_loader(tmp);
1343        log_msg(3, "boot loader is %c, residing at %s", i, tmp);
1344        printf("boot loader is %c, residing at %s\n", i, tmp);
1345        finish(0);
1346    }
1347
1348    if ((flag_set['L']) && (! bkpinfo->restore_data)) {
1349        bkpinfo->use_lzo = TRUE;
1350        if (run_program_and_log_output("which lzop", 2)) {
1351            retval++;
1352            log_to_screen
1353                ("Please install LZOP. You can't use '-L' until you do.\n");
1354        }
1355    }
1356
1357    if ((flag_set['G']) && (! bkpinfo->restore_data)) {
1358        bkpinfo->use_gzip = TRUE;
1359        if (run_program_and_log_output("which gzip", 2)) {
1360            retval++;
1361            log_to_screen
1362                ("Please install gzip. You can't use '-G' until you do.\n");
1363        }
1364    }
1365
1366    bkpinfo->use_obdr = FALSE;
1367    if (flag_set['o']) {
1368        if ((!flag_set['t']) && (! bkpinfo->restore_data)) {
1369            log_to_screen("OBDR support is only available for tapes. Use the -t option");
1370            fatal_error("Aborting");
1371        }
1372        bkpinfo->use_obdr = TRUE;
1373    }
1374
1375#ifndef __FreeBSD__
1376    if ((!is_this_a_valid_disk_format("vfat")) && (! bkpinfo->restore_data)) {
1377        bkpinfo->make_cd_use_lilo = TRUE;
1378        log_to_screen
1379            ("Your kernel appears not to support vfat filesystems. I am therefore");
1380        log_to_screen
1381            ("using LILO instead of SYSLINUX as the media boot loader.");
1382    }
1383    if ((run_program_and_log_output("which mkfs.vfat", 2)) && (! bkpinfo->restore_data)) {
1384        bkpinfo->make_cd_use_lilo = TRUE;
1385#ifdef __IA32__
1386        log_to_screen
1387            ("Your filesystem is missing 'mkfs.vfat', so I cannot use SYSLINUX as");
1388        log_to_screen
1389            ("your boot loader. I shall therefore use LILO instead.");
1390#endif
1391#ifdef __IA64__
1392        log_to_screen
1393            ("Your filesystem is missing 'mkfs.vfat', so I cannot prepare the EFI");
1394        log_to_screen("environment correctly. Please install it.");
1395        fatal_error("Aborting");
1396#endif
1397    }
1398#ifdef __IA64__
1399    /* We force ELILO usage on IA64 */
1400    bkpinfo->make_cd_use_lilo = TRUE;
1401#endif
1402#endif
1403
1404    if (! bkpinfo->restore_data) {
1405        i = flag_set['O'] + flag_set['V'];
1406        if (i == 0) {
1407            retval++;
1408            log_to_screen("Specify backup (-O), verify (-V) or both (-OV).\n");
1409        }
1410    }
1411
1412    if ((! bkpinfo->restore_data) && (flag_set['Z'])) {
1413            fatal_error
1414                ("The -Z switch is only valid in restore mode");
1415    }
1416
1417    if (flag_set['Z']) {
1418        if (! strcmp(flag_val['Z'], "nuke")) {
1419            bkpinfo->restore_mode = nuke;
1420        } else if (! strcmp(flag_val['Z'], "interactive")) {
1421            bkpinfo->restore_mode = interactive;
1422        } else if (! strcmp(flag_val['Z'], "compare")) {
1423            bkpinfo->restore_mode = compare;
1424        } else if (! strcmp(flag_val['Z'], "mbr")) {
1425            bkpinfo->restore_mode = mbr;
1426        } else if (! strcmp(flag_val['Z'], "iso")) {
1427            bkpinfo->restore_mode = isoonly;
1428        } else if (! strcmp(flag_val['Z'], "isonuke")) {
1429            bkpinfo->restore_mode = isonuke;
1430        } else {
1431            bkpinfo->restore_mode = interactive;
1432        }
1433    }
1434
1435/* and finally... */
1436
1437    paranoid_free(tmp);
1438    return (retval);
1439}
1440
1441
1442
1443/**
1444 * Get the switches from @p argc and @p argv using getopt() and place them in
1445 * @p flag_set and @p flag_val.
1446 * @param argc The argument count (@p argc passed to main()).
1447 * @param argv The argument vector (@p argv passed to main()).
1448 * @param flag_val An array indexed by switch letter - if a switch is set and
1449 * has an argument then set flag_val[switch] to that argument.
1450 * @param flag_set An array indexed by switch letter - if a switch is set then
1451 * set flag_set[switch] to TRUE, else set it to FALSE.
1452 * @return The number of problems with the command line (0 for success).
1453 */
1454int
1455retrieve_switches_from_command_line(int argc, char *argv[],
1456                                    char flag_val[128][MAX_STR_LEN],
1457                                    bool flag_set[128])
1458{
1459    /*@ ints ** */
1460    int opt = 0;
1461    char *tmp = NULL;
1462    int i = 0;
1463    int len;
1464
1465    /*@ bools *** */
1466    bool bad_switches = FALSE;
1467
1468    assert(flag_val != NULL);
1469    assert(flag_set != NULL);
1470
1471    for (i = 0; i < 128; i++) {
1472        flag_val[i][0] = '\0';
1473        flag_set[i] = FALSE;
1474    }
1475    while ((opt =
1476            getopt(argc, argv, MONDO_OPTIONS))
1477           != -1) {
1478        if (opt == '?') {
1479            bad_switches = TRUE;
1480            /*log_it("Invalid option: %c\n",optopt); */
1481        } else {
1482            if (flag_set[optopt]) {
1483                bad_switches = TRUE;
1484                mr_asprintf(&tmp, "Switch -%c previously defined as %s\n", opt,
1485                        flag_val[i]);
1486                log_to_screen(tmp);
1487                paranoid_free(tmp);
1488            } else {
1489                flag_set[opt] = TRUE;
1490                if (optarg) {
1491                    len = strlen(optarg);
1492                    if (optarg[0] != '/' && optarg[len - 1] == '/') {
1493                        optarg[--len] = '\0';
1494                        log_to_screen
1495                            ("Warning - param '%s' should not have trailing slash!",
1496                             optarg);
1497                    }
1498                    if (opt == 'd') {
1499                        if (strchr(flag_val[opt], '/')
1500                            && flag_val[opt][0] != '/') {
1501                            mr_asprintf(&tmp,
1502                                    "-%c flag --- must be absolute path --- '%s' isn't absolute",
1503                                    opt, flag_val[opt]);
1504                            log_to_screen(tmp);
1505                            paranoid_free(tmp);
1506                            bad_switches = TRUE;
1507                        }
1508                    }
1509                    strcpy(flag_val[opt], optarg);
1510                }
1511            }
1512        }
1513    }
1514    for (i = optind; i < argc; i++) {
1515        bad_switches = TRUE;
1516        mr_asprintf(&tmp, "Invalid arg -- %s\n", argv[i]);
1517        log_to_screen(tmp);
1518        paranoid_free(tmp);
1519    }
1520    return (bad_switches);
1521}
1522
1523
1524
1525
1526/**
1527 * Print a not-so-helpful help message and exit.
1528 */
1529void help_screen()
1530{
1531    log_msg(1, "Type 'man mondoarchive' for more information\n");
1532    exit(1);
1533}
1534
1535
1536/**
1537 * Terminate Mondo in response to a signal.
1538 * @param sig The signal number received.
1539 */
1540void terminate_daemon(int sig)
1541{
1542    char *tmp = NULL;
1543    char *tmp2 = NULL;
1544
1545    switch (sig) {
1546    case SIGINT:
1547        mr_asprintf(&tmp, "SIGINT");
1548        mr_asprintf(&tmp2, "You interrupted me :-)");
1549        break;
1550    case SIGKILL:
1551        mr_asprintf(&tmp, "SIGKILL");
1552        mr_asprintf(&tmp2,
1553               "I seriously have no clue how this signal even got to me. Something's wrong with your system.");
1554        break;
1555    case SIGTERM:
1556        mr_asprintf(&tmp, "SIGTERM");
1557        mr_asprintf(&tmp2, "Got terminate signal");
1558        break;
1559    case SIGHUP:
1560        mr_asprintf(&tmp, "SIGHUP");
1561        mr_asprintf(&tmp2, "Hangup on line");
1562        break;
1563    case SIGSEGV:
1564        mr_asprintf(&tmp, "SIGSEGV");
1565        mr_asprintf(&tmp2,
1566               "Internal programming error. Please send a backtrace as well as your log.");
1567        break;
1568    case SIGPIPE:
1569        mr_asprintf(&tmp, "SIGPIPE");
1570        mr_asprintf(&tmp2, "Pipe was broken");
1571        break;
1572    case SIGABRT:
1573        mr_asprintf(&tmp, "SIGABRT");
1574        mr_asprintf(&tmp2,
1575                "Abort - probably failed assertion. I'm sleeping for a few seconds so you can read the message.");
1576        break;
1577    default:
1578        mr_asprintf(&tmp, "(Unknown)");
1579        mr_asprintf(&tmp2, "(Unknown)");
1580    }
1581
1582    mr_strcat(tmp, " signal received from OS");
1583    log_to_screen(tmp);
1584    paranoid_free(tmp);
1585
1586    log_to_screen(tmp2);
1587    paranoid_free(tmp2);
1588    if (sig == SIGABRT) {
1589        sleep(10);
1590    }
1591    kill_buffer();
1592
1593    free_MR_global_filenames();
1594
1595    fatal_error
1596        ("MondoRescue is terminating in response to a signal from the OS");
1597    finish(254);                // just in case
1598}
1599
1600
1601
1602
1603/**
1604 * Turn signal-trapping on or off.
1605 * @param on If TRUE, turn it on; if FALSE, turn it off (we still trap it, just don't do as much).
1606 */
1607void set_signals(int on)
1608{
1609    int signals[] =
1610        { SIGTERM, SIGHUP, SIGTRAP, SIGABRT, SIGINT, SIGKILL, SIGSTOP, 0 };
1611    int i;
1612
1613    signal(SIGPIPE, sigpipe_occurred);
1614    for (i = 0; signals[i]; i++) {
1615        if (on) {
1616            signal(signals[i], terminate_daemon);
1617        } else {
1618            signal(signals[i], termination_in_progress);
1619        }
1620    }
1621}
1622
1623
1624
1625
1626/**
1627 * Exit immediately without cleaning up.
1628 * @param sig The signal we are exiting due to.
1629 */
1630void termination_in_progress(int sig)
1631{
1632    log_msg(1, "Termination in progress");
1633    usleep(1000);
1634    pthread_exit(0);
1635}
1636
1637/* @} - end of cliGroup */
Note: See TracBrowser for help on using the repository browser.