source: MondoRescue/branches/2.2.7/mondo/src/common/libmondo-cli.c@ 2007

Last change on this file since 2007 was 2007, checked in by Bruno Cornec, 16 years ago

Patch and comment from Michael Shapiro:

I wrote a function called get_dsf_mount_list() that, given a whole disk device special file (dsf), it will return a list of all of the mounted file systems residing on that disk in the
variable included_dsf_list, and a list of all of the mounted file systems that are not residing on that disk in the variable excluded_dsf_list:

static int
get_dsf_mount_list (char *dsf,

char included_dsf_list,
char
excluded_dsf_list);

The function does the following:

  • Verifies that the dsf exists and has a partition table on it.
  • Creates a linked list of all of the locally mounted file systems (i.e. the mount points that start with "/dev/") using a new structure called mounted_fs_struct. Each structure contains the name of the

device, the device's mount point, and a variable called check that will be set to 1 if the mount point resides on the disk and a 0 if the mount point does not reside on the disk.

  • Loops through each partition on the disk and:

-- If the partition is swap, it ignores it.

-- If the partition is mounted (e.g. /dev/sda1 is mounted on /boot, /dev/sda2 is mounted on /usr, etc.), it finds its entry on the linked list and sets check == 1.

-- If the partition is part of a Volume Group that has Logical Volumes mounted, it finds its entry on the linked list for each mounted Logical Volume in that Volume Group and sets check == 1. Note that if
the Volume Group contains more than one disk, it will still add the entry even if the Logical Volume's extents are not on, or only partially on, the dsf that was passed in to the function. For example,
Volume Group VolGroup00 contains the disks /dev/sda1 and /dev/sdb1, and the Logical Volumes LogVol01, which is mounted on /var and has all of its extents on /dev/sda1, and LogVol02, which is mounted as /usr
and has all of its extents on /dev/sdb1. If you pass /dev/sda into the function, both /var and /usr will be archived even though /usr is actually on/dev/sdb.

-- If the partition is part of a Volume Group that has Logical Volumes used in a mounted software raid device, it finds its entry on the linked list and sets check == 1.

-- If the partition is part of a mounted software raid device, it finds its entry on the linked list and sets check == 1.

  • At the end of the function, it walks through the linked list and, for every entry where check == 1, catenates the mount point to included_dsf_list. For every entry where check == 0, it catenates the mount

point to excluded_dsf_list.

In process_switches():

  • I added code to the section that processes the -I option and, if a whole disk device special file is passed in, it calls get_dsf_mount_list(), sets bkpinfo->include_paths == "/", and catenates the

contents of excluded_dsf_list to bkpinfo->exclude_paths. If a whole disk device special file is not passed in, it processes the -I option normally.

  • I added code to the section that processes the -E option and, if a whole disk device special file is passed in, it calls get_dsf_mount_list() and catenates the contents of included_dsf_list to

bkpinfo->exclude_paths. If a whole disk device special file is not passed in, it processes the -E option normally.

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