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

Last change on this file since 2225 was 2225, checked in by Bruno Cornec, 12 years ago

No need to use sudo for NFS user, just use su and avoid any passwd issue.

  • Property svn:keywords set to Id
File size: 50.5 KB
Line 
1/***************************************************************************
2$Id: libmondo-cli.c 2225 2009-06-17 02:47:09Z 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        /* test if we specified a user for the NFS dialog */
991        p = strchr(bkpinfo->nfs_mount, '@');
992        if (p != NULL) {
993            /* User found. Store the 2 values */
994            p++;
995            /* new NFS mount */
996            strcpy(tmp,p);
997            p--;
998            *p = '\0';
999            strcpy(bkpinfo->nfs_user,bkpinfo->nfs_mount);
1000            strcpy(bkpinfo->nfs_mount,tmp);
1001        }
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            log_to_screen("NFS share is not mounted. Trying to mount it for you.\n");
1009            sprintf(tmp, "mount %s", bkpinfo->nfs_mount);
1010            if (system(tmp)) {
1011                log_to_screen("Unable to mount NFS share %s. Please mount manually.\n", bkpinfo->nfs_mount);
1012                retval++;
1013            } else {
1014                sprintf(tmp, "mount | grep -E \"^%s[/]* .*\" | cut -d' ' -f3",
1015                    bkpinfo->nfs_mount);
1016                strncpy(bkpinfo->isodir,
1017                        call_program_and_get_last_line_of_output(tmp),
1018                        MAX_STR_LEN / 4);
1019                if (strlen(bkpinfo->isodir) < 3) {
1020                    retval++;
1021                    log_to_screen("NFS share %s is strangely not mounted. Please mount manually...\n", bkpinfo->nfs_mount);
1022                }
1023            }
1024        }
1025        log_msg(3, "mount = %s", bkpinfo->nfs_mount);
1026        log_msg(3, "isodir= %s", bkpinfo->isodir);
1027    }
1028
1029    if (flag_set['c']) {
1030        bkpinfo->backup_media_type = cdr;
1031    }
1032    if (flag_set['C']) {
1033        bkpinfo->backup_media_type = cdstream;
1034    }
1035    if (flag_set['i']) {
1036        bkpinfo->backup_media_type = iso;
1037    }
1038    if (flag_set['n']) {
1039        bkpinfo->backup_media_type = nfs;
1040        /* Never try to eject a NFS device */
1041        bkpinfo->please_dont_eject = TRUE;
1042    }
1043    if (flag_set['r']) {
1044        bkpinfo->backup_media_type = dvd;
1045    }
1046    if (flag_set['t']) {
1047        bkpinfo->backup_media_type = tape;
1048    }
1049    if (flag_set['u']) {
1050        bkpinfo->backup_media_type = udev;
1051    }
1052    if (flag_set['w']) {
1053        bkpinfo->backup_media_type = cdrw;
1054    }
1055    if (flag_set['U']) {
1056        bkpinfo->backup_media_type = usb;
1057        /* Never try to eject a USB device */
1058        bkpinfo->please_dont_eject = TRUE;
1059    }
1060    if (flag_set['z']) {
1061        if (find_home_of_exe("getfattr")) {
1062            mr_asprintf(&g_getfattr,"getfattr");
1063        }
1064        if (find_home_of_exe("getfacl")) {
1065            mr_asprintf(&g_getfacl,"getfacl");
1066        }
1067    }
1068
1069    /* optional, popular */
1070    if (flag_set['g']) {
1071        g_text_mode = FALSE;
1072    }
1073
1074    if (flag_set['E']) {
1075        if (bkpinfo->exclude_paths[0] == '-') {
1076            retval++;
1077            log_to_screen("Please supply a sensible value with '-E'\n");
1078        }
1079        if (bkpinfo->exclude_paths[0]) {
1080            strcat(bkpinfo->exclude_paths, " ");
1081        }
1082        mr_asprintf(&tmp1, "%s", flag_val['E']);
1083
1084        p = tmp1;
1085        q = tmp1;
1086
1087        /* Cut the flag_val['E'] in parts containing all paths to test them */
1088        while (p != NULL) {
1089            q = strchr(p, ' ');
1090            if (q != NULL) {
1091                *q = '\0';
1092                /* Fix bug 14 where ending / cause a problem later
1093                * so handled here for the moment */
1094                q--;
1095                if (*q == '/') {
1096                    *q = '\0';
1097                }
1098                q++;
1099                /* End of bug fix */
1100                if ((stat(p, &buf) != 0) && (! bkpinfo->restore_data)) {
1101                    log_msg(1, "WARNING ! %s doesn't exist", p);
1102                }
1103                p = q+1 ;
1104            } else {
1105                if ((stat(p, &buf) != 0) && (! bkpinfo->restore_data)) {
1106                    log_msg(1, "WARNING ! %s doesn't exist", p);
1107                }
1108                p = NULL;
1109            }
1110        }
1111        paranoid_free(tmp1);
1112        lastpos = 0;
1113        while ((token = mr_strtok(flag_val['E'], token_chars, &lastpos)) != NULL) {
1114            switch (get_dsf_mount_list(token, &mounted_on_dsf, &not_mounted_on_dsf)) {
1115            case 1: 
1116                log_msg(1, "WARNING ! a path doesn't exist in -E option");
1117                break;
1118            /* Everything is OK; proceed to archive data */
1119            case 0:
1120                if (strlen(mounted_on_dsf)) {
1121                    log_to_screen("Excluding the following file systems on %s:\n", token);
1122                    log_to_screen("  %s\n", mounted_on_dsf);
1123                    log_msg (5, "Adding to bkpinfo->exclude_paths due to -E option: %s", mounted_on_dsf);
1124                    strcat(bkpinfo->exclude_paths, mounted_on_dsf);
1125                    strcat(bkpinfo->exclude_paths, " ");
1126                }
1127                break;
1128            /* It's a dsf but not a whole disk dsf */
1129            case -2:
1130                log_to_screen("Could %s be a partition instead of a whole disk device special file?\nIgnored.", token);
1131                break;
1132            /* A device special file was not passed in. Process it as a path. */
1133            case -1:
1134                strcat(bkpinfo->exclude_paths, token);
1135                strcat(bkpinfo->exclude_paths, " ");
1136                break;
1137            }
1138        }
1139        log_msg(1, "exclude_paths is now '%s'", bkpinfo->exclude_paths);
1140        log_msg(4, "Finished with the -E option");
1141    }
1142
1143    if (flag_set['e']) {
1144        bkpinfo->please_dont_eject = TRUE;
1145    }
1146
1147    if ((flag_set['N']) && (! bkpinfo->restore_data))       // exclude NFS mounts & devices
1148    {
1149//      strncpy(psz, list_of_NFS_devices_and_mounts(), MAX_STR_LEN);
1150        mr_asprintf(&psz, "%s", list_of_NFS_mounts_only());
1151        if (bkpinfo->exclude_paths[0]) {
1152            strncat(bkpinfo->exclude_paths, " ", 4*MAX_STR_LEN);
1153        }
1154        strncat(bkpinfo->exclude_paths, psz, 4*MAX_STR_LEN);
1155        mr_free(psz);
1156
1157        log_msg(3, "-N means we're now excluding %s",
1158                bkpinfo->exclude_paths);
1159    }
1160
1161    if (strlen(bkpinfo->exclude_paths) >= 4*MAX_STR_LEN) {
1162        fatal_error
1163            ("Your '-E' parameter is too long. Increase MAX_STR_LEN");
1164    }
1165
1166    if (flag_set['b']) {
1167        mr_asprintf(&psz, flag_val['b']);
1168        log_msg(1, "psz = '%s'", psz);
1169        if (psz[strlen(psz) - 1] == 'k') {
1170            psz[strlen(psz) - 1] = '\0';
1171            itbs = atol(psz) * 1024L;
1172        } else {
1173            itbs = atol(psz);
1174        }
1175        mr_free(psz);
1176        log_msg(1, "'%s' --> %ld", flag_val['b'], itbs);
1177        log_msg(1, "Internal tape block size is now %ld bytes", itbs);
1178        if (itbs % 512 != 0 || itbs < 256 || itbs > 1024L * 1024) {
1179            fatal_error
1180                ("Are you nuts? Silly, your internal tape block size is. Abort, I shall.");
1181        }
1182        bkpinfo->internal_tape_block_size = itbs;
1183    }
1184
1185    if ((flag_set['D']) && (! bkpinfo->restore_data)) {
1186        bkpinfo->differential = 1;
1187//      bkpinfo->differential = atoi (flag_val['D']);
1188        if ((bkpinfo->differential < 1) || (bkpinfo->differential > 9)) {
1189            fatal_error
1190                ("The D option should be between 1 and 9 inclusive");
1191        }
1192    }
1193
1194    if (flag_set['x']) {
1195        strncpy(bkpinfo->image_devs, flag_val['x'], MAX_STR_LEN / 4);
1196        if ((run_program_and_log_output("which ntfsclone", 2)) && (! bkpinfo->restore_data)) {
1197            fatal_error("Please install ntfsprogs package/tarball.");
1198        }
1199    }
1200
1201    if (flag_set['m']) {
1202        bkpinfo->manual_cd_tray = TRUE;
1203    }
1204
1205    if ((flag_set['k']) && (! bkpinfo->restore_data)) {
1206        strncpy(bkpinfo->kernel_path, flag_val['k'], MAX_STR_LEN);
1207        if (!strcmp(bkpinfo->kernel_path, "failsafe")) {
1208            strcpy(bkpinfo->kernel_path, "FAILSAFE");
1209        }
1210        if (strcmp(bkpinfo->kernel_path, "FAILSAFE")
1211            && !does_file_exist(bkpinfo->kernel_path)) {
1212            retval++;
1213            sprintf(tmp,
1214                    "You specified kernel '%s', which does not exist\n",
1215                    bkpinfo->kernel_path);
1216            log_to_screen(tmp);
1217        }
1218    }
1219
1220    if (flag_set['p']) {
1221        strncpy(bkpinfo->prefix, flag_val['p'], MAX_STR_LEN / 4);
1222        log_msg(1,"Prefix forced to %s",bkpinfo->prefix);
1223    }
1224
1225    if (flag_set['d']) {        /* backup directory (if ISO/NFS) */
1226        if (flag_set['i']) {
1227            strncpy(bkpinfo->isodir, flag_val['d'], MAX_STR_LEN / 4);
1228            sprintf(tmp, "ls -l %s", bkpinfo->isodir);
1229            if (run_program_and_log_output(tmp, 2)) {
1230                fatal_error
1231                    ("output folder does not exist - please create it");
1232            }
1233        } else if (flag_set['n']) {
1234            strncpy(bkpinfo->nfs_remote_dir, flag_val['d'], MAX_STR_LEN);
1235        } else {                /* backup device (if tape/CD-R/CD-RW) */
1236            strncpy(bkpinfo->media_device, flag_val['d'], MAX_STR_LEN / 4);
1237        }
1238    }
1239
1240    if ((flag_set['n']) && (! bkpinfo->restore_data)) {
1241        mr_asprintf(&tmp1,"%s/%s/.dummy.txt", bkpinfo->isodir,bkpinfo->nfs_remote_dir);
1242        if (bkpinfo->nfs_user) {
1243            sprintf(tmp, "su - %s -c \"echo hi > %s\"", bkpinfo->nfs_user, tmp1);
1244        } else {
1245            sprintf(tmp, "echo hi > %s", tmp1);
1246        }
1247        if (run_program_and_log_output(tmp, 2)) {
1248            retval++;
1249            sprintf(tmp,
1250                    "Are you sure directory '%s' exists in remote dir '%s'?\nIf so, do you have rights to write to it?\n",
1251                    bkpinfo->nfs_remote_dir, bkpinfo->nfs_mount);
1252            log_to_screen(tmp);
1253        }
1254        unlink(tmp1);
1255        paranoid_free(tmp1);
1256    }
1257
1258    if (!flag_set['d']
1259        && (flag_set['c'] || flag_set['w'] || flag_set['C'])) {
1260        if (g_kernel_version >= 2.6) {
1261            if (popup_and_get_string
1262                ("Device", "Please specify the device",
1263                 bkpinfo->media_device, MAX_STR_LEN / 4)) {
1264                retval++;
1265                log_to_screen("User opted to cancel.");
1266            }
1267        } else if (find_cdrw_device(bkpinfo->media_device)) {
1268            retval++;
1269            log_to_screen
1270                ("Tried and failed to find CD-R[W] drive automatically.\n");
1271        } else {
1272            flag_set['d'] = TRUE;
1273            strncpy(flag_val['d'], bkpinfo->media_device, MAX_STR_LEN / 4);
1274        }
1275    }
1276
1277    if ((!flag_set['d'] && !flag_set['n'] && !flag_set['C']) && (! bkpinfo->restore_data)) {
1278        retval++;
1279        log_to_screen("Please specify the backup device/directory.\n");
1280        fatal_error
1281            ("You didn't use -d to specify the backup device/directory.");
1282    }
1283
1284    for (i = '0'; i <= '9'; i++) {
1285        if (flag_set[i]) {
1286            bkpinfo->compression_level = i - '0';
1287        }                       /* not '\0' but '0' */
1288    }
1289
1290    if (flag_set['S']) {
1291        sprintf(bkpinfo->scratchdir, "%s/mondo.scratch.%ld", flag_val['S'],
1292                random() % 32768);
1293    }
1294
1295    if (flag_set['T']) {
1296        setup_tmpdir(flag_val['T']);
1297        sprintf(tmp, "touch %s/.foo.dat", bkpinfo->tmpdir);
1298        if (run_program_and_log_output(tmp, 1)) {
1299            retval++;
1300            log_to_screen
1301                ("Please specify a tempdir which I can write to. :)");
1302            fatal_error("I cannot write to the tempdir you specified.");
1303        }
1304        sprintf(tmp, "ln -sf %s/.foo.dat %s/.bar.dat", bkpinfo->tmpdir, bkpinfo->tmpdir);
1305        if (run_program_and_log_output(tmp, 1)) {
1306            retval++;
1307            log_to_screen
1308                ("Please don't specify a SAMBA or VFAT or NFS tmpdir.");
1309            fatal_error("I cannot write to the tempdir you specified.");
1310        }
1311    }
1312
1313    if ((flag_set['A']) && (! bkpinfo->restore_data)) {
1314        strncpy(bkpinfo->call_after_iso, flag_val['A'], MAX_STR_LEN);
1315    }
1316
1317    if ((flag_set['B']) && (! bkpinfo->restore_data)) {
1318        strncpy(bkpinfo->call_before_iso, flag_val['B'], MAX_STR_LEN);
1319    }
1320
1321    if ((flag_set['H']) && (! bkpinfo->restore_data)) {
1322        g_cd_recovery = TRUE;
1323    }
1324
1325    if ((flag_set['l']) && (! bkpinfo->restore_data)) {
1326#ifdef __FreeBSD__
1327#  define BOOT_LOADER_CHARS "GLBMR"
1328#else
1329#  ifdef __IA64__
1330#    define BOOT_LOADER_CHARS "GER"
1331#  else
1332#    define BOOT_LOADER_CHARS "GLR"
1333#  endif
1334#endif
1335        if (!strchr
1336            (BOOT_LOADER_CHARS,
1337             (bkpinfo->boot_loader = flag_val['l'][0]))) {
1338            log_msg(1, "%c? WTF is %c? I need G, L, E or R.",
1339                    bkpinfo->boot_loader, bkpinfo->boot_loader);
1340            fatal_error
1341                ("Please specify GRUB, LILO, ELILO  or RAW with the -l switch");
1342        }
1343#undef BOOT_LOADER_CHARS
1344    }
1345
1346    if (flag_set['f']) {
1347        strncpy(bkpinfo->boot_device,
1348                resolve_softlinks_to_get_to_actual_device_file(flag_val
1349                                                               ['f']),
1350                MAX_STR_LEN / 4);
1351    }
1352
1353    if ((flag_set['P']) && (! bkpinfo->restore_data)) {
1354        strncpy(bkpinfo->postnuke_tarball, flag_val['P'], MAX_STR_LEN);
1355    }
1356
1357    if (flag_set['Q']) {
1358        i = which_boot_loader(tmp);
1359        log_msg(3, "boot loader is %c, residing at %s", i, tmp);
1360        printf("boot loader is %c, residing at %s\n", i, tmp);
1361        finish(0);
1362    }
1363
1364    if ((flag_set['L']) && (! bkpinfo->restore_data)) {
1365        bkpinfo->use_lzo = TRUE;
1366        if (run_program_and_log_output("which lzop", 2)) {
1367            retval++;
1368            log_to_screen
1369                ("Please install LZOP. You can't use '-L' until you do.\n");
1370        }
1371    }
1372
1373    if ((flag_set['G']) && (! bkpinfo->restore_data)) {
1374        bkpinfo->use_gzip = TRUE;
1375        if (run_program_and_log_output("which gzip", 2)) {
1376            retval++;
1377            log_to_screen
1378                ("Please install gzip. You can't use '-G' until you do.\n");
1379        }
1380    }
1381
1382    bkpinfo->use_obdr = FALSE;
1383    if (flag_set['o']) {
1384        if ((!flag_set['t']) && (! bkpinfo->restore_data)) {
1385            log_to_screen("OBDR support is only available for tapes. Use the -t option");
1386            fatal_error("Aborting");
1387        }
1388        bkpinfo->use_obdr = TRUE;
1389    }
1390
1391#ifndef __FreeBSD__
1392    if ((!is_this_a_valid_disk_format("vfat")) && (! bkpinfo->restore_data)) {
1393        bkpinfo->make_cd_use_lilo = TRUE;
1394        log_to_screen
1395            ("Your kernel appears not to support vfat filesystems. I am therefore");
1396        log_to_screen
1397            ("using LILO instead of SYSLINUX as the media boot loader.");
1398    }
1399    if ((run_program_and_log_output("which mkfs.vfat", 2)) && (! bkpinfo->restore_data)) {
1400        bkpinfo->make_cd_use_lilo = TRUE;
1401#ifdef __IA32__
1402        log_to_screen
1403            ("Your filesystem is missing 'mkfs.vfat', so I cannot use SYSLINUX as");
1404        log_to_screen
1405            ("your boot loader. I shall therefore use LILO instead.");
1406#endif
1407#ifdef __IA64__
1408        log_to_screen
1409            ("Your filesystem is missing 'mkfs.vfat', so I cannot prepare the EFI");
1410        log_to_screen("environment correctly. Please install it.");
1411        fatal_error("Aborting");
1412#endif
1413    }
1414#ifdef __IA64__
1415    /* We force ELILO usage on IA64 */
1416    bkpinfo->make_cd_use_lilo = TRUE;
1417#endif
1418#endif
1419
1420    if (! bkpinfo->restore_data) {
1421        i = flag_set['O'] + flag_set['V'];
1422        if (i == 0) {
1423            retval++;
1424            log_to_screen("Specify backup (-O), verify (-V) or both (-OV).\n");
1425        }
1426    }
1427
1428    if ((! bkpinfo->restore_data) && (flag_set['Z'])) {
1429            fatal_error
1430                ("The -Z switch is only valid in restore mode");
1431    }
1432
1433    if (flag_set['Z']) {
1434        if (! strcmp(flag_val['Z'], "nuke")) {
1435            bkpinfo->restore_mode = nuke;
1436        } else if (! strcmp(flag_val['Z'], "interactive")) {
1437            bkpinfo->restore_mode = interactive;
1438        } else if (! strcmp(flag_val['Z'], "compare")) {
1439            bkpinfo->restore_mode = compare;
1440        } else if (! strcmp(flag_val['Z'], "mbr")) {
1441            bkpinfo->restore_mode = mbr;
1442        } else if (! strcmp(flag_val['Z'], "iso")) {
1443            bkpinfo->restore_mode = isoonly;
1444        } else if (! strcmp(flag_val['Z'], "isonuke")) {
1445            bkpinfo->restore_mode = isonuke;
1446        } else {
1447            bkpinfo->restore_mode = interactive;
1448        }
1449    }
1450
1451/* and finally... */
1452
1453    paranoid_free(tmp);
1454    return (retval);
1455}
1456
1457
1458
1459/**
1460 * Get the switches from @p argc and @p argv using getopt() and place them in
1461 * @p flag_set and @p flag_val.
1462 * @param argc The argument count (@p argc passed to main()).
1463 * @param argv The argument vector (@p argv passed to main()).
1464 * @param flag_val An array indexed by switch letter - if a switch is set and
1465 * has an argument then set flag_val[switch] to that argument.
1466 * @param flag_set An array indexed by switch letter - if a switch is set then
1467 * set flag_set[switch] to TRUE, else set it to FALSE.
1468 * @return The number of problems with the command line (0 for success).
1469 */
1470int
1471retrieve_switches_from_command_line(int argc, char *argv[],
1472                                    char flag_val[128][MAX_STR_LEN],
1473                                    bool flag_set[128])
1474{
1475    /*@ ints ** */
1476    int opt = 0;
1477    char *tmp = NULL;
1478    int i = 0;
1479    int len;
1480
1481    /*@ bools *** */
1482    bool bad_switches = FALSE;
1483
1484    assert(flag_val != NULL);
1485    assert(flag_set != NULL);
1486
1487    for (i = 0; i < 128; i++) {
1488        flag_val[i][0] = '\0';
1489        flag_set[i] = FALSE;
1490    }
1491    while ((opt =
1492            getopt(argc, argv, MONDO_OPTIONS))
1493           != -1) {
1494        if (opt == '?') {
1495            bad_switches = TRUE;
1496            /*log_it("Invalid option: %c\n",optopt); */
1497        } else {
1498            if (flag_set[optopt]) {
1499                bad_switches = TRUE;
1500                mr_asprintf(&tmp, "Switch -%c previously defined as %s\n", opt,
1501                        flag_val[i]);
1502                log_to_screen(tmp);
1503                paranoid_free(tmp);
1504            } else {
1505                flag_set[opt] = TRUE;
1506                if (optarg) {
1507                    len = strlen(optarg);
1508                    if (optarg[0] != '/' && optarg[len - 1] == '/') {
1509                        optarg[--len] = '\0';
1510                        log_to_screen
1511                            ("Warning - param '%s' should not have trailing slash!",
1512                             optarg);
1513                    }
1514                    if (opt == 'd') {
1515                        if (strchr(flag_val[opt], '/')
1516                            && flag_val[opt][0] != '/') {
1517                            mr_asprintf(&tmp,
1518                                    "-%c flag --- must be absolute path --- '%s' isn't absolute",
1519                                    opt, flag_val[opt]);
1520                            log_to_screen(tmp);
1521                            paranoid_free(tmp);
1522                            bad_switches = TRUE;
1523                        }
1524                    }
1525                    strcpy(flag_val[opt], optarg);
1526                }
1527            }
1528        }
1529    }
1530    for (i = optind; i < argc; i++) {
1531        bad_switches = TRUE;
1532        mr_asprintf(&tmp, "Invalid arg -- %s\n", argv[i]);
1533        log_to_screen(tmp);
1534        paranoid_free(tmp);
1535    }
1536    return (bad_switches);
1537}
1538
1539
1540
1541
1542/**
1543 * Print a not-so-helpful help message and exit.
1544 */
1545void help_screen()
1546{
1547    log_msg(1, "Type 'man mondoarchive' for more information\n");
1548    exit(1);
1549}
1550
1551
1552/**
1553 * Terminate Mondo in response to a signal.
1554 * @param sig The signal number received.
1555 */
1556void terminate_daemon(int sig)
1557{
1558    char *tmp = NULL;
1559    char *tmp2 = NULL;
1560
1561    switch (sig) {
1562    case SIGINT:
1563        mr_asprintf(&tmp, "SIGINT");
1564        mr_asprintf(&tmp2, "You interrupted me :-)");
1565        break;
1566    case SIGKILL:
1567        mr_asprintf(&tmp, "SIGKILL");
1568        mr_asprintf(&tmp2,
1569               "I seriously have no clue how this signal even got to me. Something's wrong with your system.");
1570        break;
1571    case SIGTERM:
1572        mr_asprintf(&tmp, "SIGTERM");
1573        mr_asprintf(&tmp2, "Got terminate signal");
1574        break;
1575    case SIGHUP:
1576        mr_asprintf(&tmp, "SIGHUP");
1577        mr_asprintf(&tmp2, "Hangup on line");
1578        break;
1579    case SIGSEGV:
1580        mr_asprintf(&tmp, "SIGSEGV");
1581        mr_asprintf(&tmp2,
1582               "Internal programming error. Please send a backtrace as well as your log.");
1583        break;
1584    case SIGPIPE:
1585        mr_asprintf(&tmp, "SIGPIPE");
1586        mr_asprintf(&tmp2, "Pipe was broken");
1587        break;
1588    case SIGABRT:
1589        mr_asprintf(&tmp, "SIGABRT");
1590        mr_asprintf(&tmp2,
1591                "Abort - probably failed assertion. I'm sleeping for a few seconds so you can read the message.");
1592        break;
1593    default:
1594        mr_asprintf(&tmp, "(Unknown)");
1595        mr_asprintf(&tmp2, "(Unknown)");
1596    }
1597
1598    mr_strcat(tmp, " signal received from OS");
1599    log_to_screen(tmp);
1600    paranoid_free(tmp);
1601
1602    log_to_screen(tmp2);
1603    paranoid_free(tmp2);
1604    if (sig == SIGABRT) {
1605        sleep(10);
1606    }
1607    kill_buffer();
1608
1609    free_MR_global_filenames();
1610
1611    fatal_error
1612        ("MondoRescue is terminating in response to a signal from the OS");
1613    finish(254);                // just in case
1614}
1615
1616
1617
1618
1619/**
1620 * Turn signal-trapping on or off.
1621 * @param on If TRUE, turn it on; if FALSE, turn it off (we still trap it, just don't do as much).
1622 */
1623void set_signals(int on)
1624{
1625    int signals[] =
1626        { SIGTERM, SIGHUP, SIGTRAP, SIGABRT, SIGINT, SIGKILL, SIGSTOP, 0 };
1627    int i;
1628
1629    signal(SIGPIPE, sigpipe_occurred);
1630    for (i = 0; signals[i]; i++) {
1631        if (on) {
1632            signal(signals[i], terminate_daemon);
1633        } else {
1634            signal(signals[i], termination_in_progress);
1635        }
1636    }
1637}
1638
1639
1640
1641
1642/**
1643 * Exit immediately without cleaning up.
1644 * @param sig The signal we are exiting due to.
1645 */
1646void termination_in_progress(int sig)
1647{
1648    log_msg(1, "Termination in progress");
1649    usleep(1000);
1650    pthread_exit(0);
1651}
1652
1653/* @} - end of cliGroup */
Note: See TracBrowser for help on using the repository browser.