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

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

Fix mondoarchive CLI analysis for NETFS type of requests

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