root/branches/stable/mondo/src/mondoarchive/mondo-cli.c

Revision 910, 31.5 kB (checked in by bruno, 4 years ago)

replaces grep -x by grep -E during restore as busybox doesn't provide -x either

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