source: branches/2.04_berlios/mondo/mondo/common/libmondo-devices.c @ 103

Last change on this file since 103 was 103, checked in by andree, 14 years ago

Compile fix: % is modulo operator in
interactively_obtain_media_parameters_from_user().
Probably just a bracket type, reverted to what it is in 2.04 vanilla.

  • Property svn:keywords set to Id
File size: 81.2 KB
Line 
1/* libmondo-devices.c                 Subroutines for handling devices
2   $Id: libmondo-devices.c 103 2005-11-05 05:45:16Z andree $
3.
4
5
601/07/2005
7- sensibly_set_tmpdir_and_scratchdir() --- exclude smb and smbfs and (new) cifs
8
910/23
10- if root mounted at '/dev/rd/' then say FALSE, not mounted on ramdisk
11  just to please Fred Beondo :-p
12
1307/25
14- updated get_phys_size_of_drive() to support newer, larger drives
15
1607/18
17- better support of users who boot from LVM CD and nuke-restore non-LVM backups
18
1907/08
20- BLKGETSIZE64 instead of BLKGETIO..whatever (Joshua)
21- amended to use BLKGETSIZE if BLKGETSIZE64 missing (Hugo)
22- resort to HDIO_GETGEO if BLKGETSIZE and BLKGETSIZE63 fail
23
24
2506/25
26- added Mandrake 9.2 support to which_boot_loader()
27- cleaned up find_cdrom_device()
28
2906/23
30- rewrote resolve_softlinks_to_get_to_actual_device_file() in C
31
3206/17
33- don't use star automatically if SELINUX detected; let user do that
34
3505/07
36- usage of parted2fdisk instead of fdisk alone (ia32/ia64 compatibility)
37  BCO
38
3904/17
40- replaced INTERNAL_TAPE_BLK_SIZE with bkpinfo->internal_tape_block_size
41
4204/13
43- if kernel >= 2.6 then ask for /dev entry, not SCSI node
44
4504/12
46- in mount_CDROM_...whatever, don't use bkpinfo_DONTUSETHIS to see if
47  mounting a real CD device; look for /dev/ at start of $device instead
48
4904/04
50- when testing for tape drive, use INTERNAL_TAPE_BLK_SIZE, not TAPE_BLOCK_SIZE
51
5204/03
53- don't eject/retract drive if ISO
54
5502/23/2004
56- changed strstr() to strncmp() in a few places
57
5812/11/2003
59- if we can't find the DVD using dvdrecord then try it w/cdrecord
60
6111/15
62- changed a few []s to char*s
63- better support of multiple CD-ROM drives
64
6511/14
66- better find_cdrom_device(), to cope w/ multiple CD writers
67
6810/26
69- call 'mt -f %s offline' to eject tape drive in eject_device()
70
7110/25
72- ask user to confirm which NFS share to mount
73- improved which_boot_loader()
74
7510/22
76- tweaked find_cdrom_device() and find_cdrw_device()
77- created find_dvd_device()
78
7910/21
80- changed "/mnt/cdrom" to MNT_CDROM
81
8209/28
83- interactive gui no longer asks dvd's speed
84
8509/26
86- interactive gui now supports dvd
87
8809/23
89- malloc/free global strings in new subroutines - malloc_libmondo_global_strings()
90  and free_libmondo_global_strings() - which are in libmondo-tools.c
91
9209/21
93- ask for CD size when backing up interactively
94- offer to exclude NFS shares if they're present
95
9609/20
97- exclude /dev/shm from sensibly_*()
98
9909/18
100- less verbose logging when insisting on CD #n
101
10209/09
103- added resolve_softlinks_to_get_to_actual_device_file()
104
10509/05
106- rewrote inisist_on_this_cd_number() and what_number_cd_is_this()
107
10809/02
109- is_this_a_valid_disk_format() -- treat ntfs (a.k.a. type 7) as recognized format
110  just in case user's backup includes a partimagehack-imaged drive
111
11208/01 - 08/31
113- better boot-time tape detection
114- remove backup-time, erroneous, "remove floppy" msg
115- working on am_I_in_disaster_recovery_mode()
116- interactively_obtain_...() - pause & ask user to remove CD/floppy
117
11806/01 - 07/31
119- in which_boot_loader(), also search /dev/cciss for boot loader
120- fixed calls to popup_and_get_string()
121- fixed bug in get_phys_size_of_drive()
122- fixed bug in where_is_root_mounted()
123- commented out a spurious assert()
124
12505/01 - 05/31
126- superior get_phys_size_of_drive() (Joshua Oreman)
127- fixed call to inject_device() --- Andree L.
128- find_cdrom_device() now may, if asked to, mount drive if possible,
129  to test that it has a CD in it; it then unmounts
130- mount_CDROM_here() now calls retract_cd_and_defeat_autorun() as well
131- fixed support for subdir-within-NFS-mount
132- cleaned up some FreeBSD-specific stuff
133- added Joshua Oreman's FreeBSD patches
134- mount_CDROM_here() --- mkdir -p mountpt
135- add older drive support to get_phys_size_of_drive()
136
13704/01 - 04/30
138- made which_boot_loader() more friendly towards Red Hat 9
139- find_and_mount_actual_cd() retracts all CD trays
140- added lots of log_OS_error()'s and assert()'s
141- fix ISO support in interactively_restore_...()
142- made find_cdrom_device() skip dmesg if second-stage string is empty
143- in find_cdrw_device(), find cdrecord before dvdrecord
144- fixed am_i_in_disaster_recovery_mode()
145- fixed insist_on_this_cd_number()
146
14703/01 - 03/31
148- more work on find_cdrom_device()
149- find_cdrom_device() --- if nonexistent/not found then
150  make sure to return '' as dev str and 1 as res
151- cleaner find_cdrom_device(), to find DVD instead of CD-ROM
152  as last resort
153- fix insist_on_this_cd_number()
154- add user the speed of CD writer, if writing
155- if root is /dev/root then assume not a ramdisk
156
15701/07 - 02/28
158- fixed find_cdrom_device (Stan Benoit)
159- if root is at /dev/root/root then LVM (not ramdisk)
160- fix am_I_in_disaster_recovery_mode() to recognize that /dev/rd/cp*
161  entries are not ramdisks but RAID disks
162- find_cdrw_device() no longer complains to stderr if no cdrecord
163
16401/02/2003
165- sensibly_set_tmpdir_and_scratchdir() --- exclude smb and smbfs
166
16712/01/2002
168- don't ask for isodir path if in disaster recovery mode
169
17011/01 - 11/30
171- added g_restoring_live_from_cd;
172- handle_incoming_parameters() will sensibly set tmpdir and scratchdir
173- properly wipe spurious scratchdir and tmpdir
174- modified sensibly_...() to use tmp.mondo.* and mondo.scratch.*
175  instead of mondo.tmpdir.* and mondo.scratchdir.*
176- line 861,912: set media_size[0] to 1999 as well as 1 thru N
177- chmod 700, not 770, in make_fifo()
178- sensibly_set_tmpdir_and_scratchdir() will now prefix a '/' to the
179  strings if it is missing
180
18110/01 - 10/31
182- changed find_cdrom_device() to ignore DVD drives in the hd[a-d] search;
183  consequently, the subroutine will try scd0, sr0, etc. afterwards
184- commented code
185- fixed obscure bug in find_and_mount_actual_cd()
186- code which sensibly configures tmpdir,scratchdir is now sep. sub.
187- changed sort -s to sort -n <-- sensibly...()
188
18909/01 - 09/30
190- added list_of_NFS_devices_and_mounts()
191- try /dev/st0 if no tape specified at all
192- change '64k' to TAPE_BLOCK_SIZE
193- improved find_cdrom_device()
194- if cdrecord not found then find_cdrom_device() returns 1
195- if disaster recovery mode then don't ask for CD-ROM's /dev entry;
196  assume /dev/cdrom
197- if restoring data then ask for CD-ROM's /dev entry (not its SCSI node)
198- run_program_and_log_output() now takes boolean operator to specify
199  whether it will log its activities in the event of _success_
200- changed sort -n +4 to sort -s +4 (Troff)
201- ask if user's kernel is sane; if 'no' then use FAILSAFE
202- ask user to confirm the tape/CD device name
203- if restoring (not archiving) then don't try to find CD-ROM's SCSI
204  node; try to find its /dev entry instead
205- better detection of biggest partition
206
20708/01 - 08/31
208- fixed verify bug --- CD#1 was being verified again & again & ...
209- detect boot loader + device; if not detectible then _ask_
210- if run interactively, assume tape size is irrelevant & don't ask
211  for it; Mondo should handle end-of-tape gracefully now
212- worked on handling unknowng media size
213- added interactively_obtain_media_parameters_from_user()
214- when trying to mount CD-ROM, find_and_mount_actual_cd() will
215  now call find_cdrom_device() to try to find the /dev entry first
216- fixed serious bug in zero_out_a_device()
217- cleaned up some log_it() calls
218- fixed minor bug in find_cdrom_device()
219- better at distinguishing between live filesystem and ramdisk
220
22107/24/2002
222- created
223*/
224
225/**
226 * @file
227 * Functions to handle interactions with backup devices.
228 */
229
230#include "my-stuff.h"
231#include "mondostructures.h"
232#include "libmondo-files-EXT.h"
233#include "libmondo-devices.h"
234#include "lib-common-externs.h"
235#include "libmondo-string-EXT.h"
236#include "libmondo-tools-EXT.h"
237#include "libmondo-gui-EXT.h"
238#include "libmondo-fork-EXT.h"
239#include "libmondo-stream-EXT.h"
240
241#include <sys/types.h>
242#ifdef __FreeBSD__
243#define DKTYPENAMES
244#define FSTYPENAMES
245#include <sys/disklabel.h>
246#include <sys/disk.h>
247#elif linux
248#define u64 unsigned long long
249#include <linux/fs.h> /* for BLKGETSIZE64 */
250#include <linux/hdreg.h>
251#endif
252
253/*@unused@*/
254//static char cvsid[] = "$Id: libmondo-devices.c 103 2005-11-05 05:45:16Z andree $";
255
256extern int g_current_media_number;
257extern double g_kernel_version;
258
259extern bool g_ISO_restore_mode;
260extern struct s_bkpinfo *g_bkpinfo_DONTUSETHIS;
261extern char *g_erase_tmpdir_and_scratchdir;
262extern char *g_selfmounted_isodir;
263
264static char g_cdrw_drive_is_here[MAX_STR_LEN/4]="";
265static char g_cdrom_drive_is_here[MAX_STR_LEN/4]="";
266static char g_dvd_drive_is_here[MAX_STR_LEN/4]="";
267
268
269/**
270 * ????? @bug ?????
271 * @ingroup globalGroup
272 */
273bool g_restoring_live_from_cd=FALSE;
274
275extern t_bkptype g_backup_media_type; // set by main()
276
277
278
279
280void set_g_cdrom_and_g_dvd_to_bkpinfo_value(struct s_bkpinfo *bkpinfo)
281{
282  strcpy(g_cdrom_drive_is_here, bkpinfo->media_device); // just in case
283  strcpy(g_dvd_drive_is_here, bkpinfo->media_device); // just in case
284}
285
286
287
288/**
289 * Retract all CD trays and wait for autorun to complete.
290 * @ingroup deviceGroup
291 */
292void retract_CD_tray_and_defeat_autorun(void)
293{
294//  log_it("rctada: Retracting all CD trays", __LINE__);
295  if (strlen(g_cdrom_drive_is_here)>0)
296    { inject_device(g_cdrom_drive_is_here); }
297  if (strlen(g_dvd_drive_is_here)>0)
298    { inject_device(g_dvd_drive_is_here); }
299  if (strlen(g_cdrw_drive_is_here)>0)
300    { inject_device(g_cdrw_drive_is_here); }
301//  log_it("rctada: killing autorun");
302//  run_program_and_log_output("killall autorun", TRUE);
303  if (!run_program_and_log_output("ps | grep autorun | grep -v grep", 5))
304    {
305      log_it("autorun detected; sleeping for 2 seconds");
306      sleep(2);
307    }
308  log_it("rctada: Unmounting all CD drives", __LINE__);
309  run_program_and_log_output("umount /dev/cdr* /dev/dvd*", 5);
310}
311
312
313
314/**
315 * Determine whether we're booted off a ramdisk.
316 * @return @c TRUE (we are) or @c FALSE (we aren't).
317 * @ingroup utilityGroup
318 */
319bool
320am_I_in_disaster_recovery_mode (void)
321{
322  char *tmp, *comment;
323  bool is_this_a_ramdisk = FALSE;
324
325  malloc_string(tmp);
326  malloc_string(comment);
327  strcpy(tmp, where_is_root_mounted());
328  sprintf(comment, "root is mounted at %s\n", tmp);
329  log_msg(0, comment);
330  log_msg(0, "No, Schlomo, that doesn't mean %s is the root partition. It's just a debugging message. Relax. It's part of am_I_in_disaster_recovery_mode().", tmp);
331
332#ifdef __FreeBSD__
333  if (strstr(tmp, "/dev/md"))
334    {
335      is_this_a_ramdisk = TRUE;
336    }
337#else
338  if (!strncmp(tmp, "/dev/ram", 8) || (!strncmp(tmp, "/dev/rd", 7) && !strcmp(tmp, "/dev/rd/") && strncmp(tmp, "/dev/rd/cd", 10)) || strstr(tmp, "rootfs")
339    || !strcmp(tmp, "/dev/root"))
340    { is_this_a_ramdisk = TRUE; }
341  else
342    { is_this_a_ramdisk = FALSE; }
343#endif
344
345  if (is_this_a_ramdisk)
346    {
347      if (!does_file_exist("/THIS-IS-A-RAMDISK") && !does_file_exist("/tmp/mountlist.txt.sample"))
348        {
349          log_to_screen("Using /dev/root is stupid of you but I'll forgive you.");
350          is_this_a_ramdisk = FALSE;
351        }
352    }
353  if (does_file_exist("/THIS-IS-A-RAMDISK"))
354    {
355      is_this_a_ramdisk = TRUE;
356    }
357  paranoid_free(tmp);
358  paranoid_free(comment);
359  log_msg(1, "Is this a ramdisk? result = %d", is_this_a_ramdisk);
360  return(is_this_a_ramdisk);
361}
362
363
364
365
366
367/**
368 * Turn @c bkpinfo->backup_media_type into a human-readable string.
369 * @return The human readable string (e.g. @c cdr becomes <tt>"cdr"</tt>).
370 * @note The returned string points to static storage that will be overwritten with each call.
371 * @ingroup stringGroup
372 */
373static char *bkptype_to_string(t_bkptype bt)
374{
375  static char output[MAX_STR_LEN/4];
376  switch(bt)
377    {
378    case none: strcpy(output, "none");
379        break;
380    case iso:  strcpy(output, "iso");
381        break;
382    case cdr:  strcpy(output, "cdr");
383        break;
384    case cdrw: strcpy(output, "cdrw");
385        break;
386    case cdstream: strcpy(output, "cdstream");
387        break;
388    case nfs:  strcpy(output, "nfs");
389        break;
390    case tape: strcpy(output, "tape");
391        break;
392    case udev: strcpy(output, "udev");
393        break;
394    default: strcpy(output, "default");
395    }
396  return(output);
397}
398
399
400
401/**
402 * @addtogroup deviceGroup
403 * @{
404 */
405/**
406 * Eject the tray of the specified CD device.
407 * @param dev The device to eject.
408 * @return the return value of the @c eject command. (0=success, nonzero=failure)
409 */
410int eject_device(char*dev)
411{
412  char *command;
413  int res1=0, res2=0;
414
415  malloc_string(command);
416
417  if (IS_THIS_A_STREAMING_BACKUP(g_backup_media_type) && g_backup_media_type!=udev)
418    {
419      sprintf(command, "mt -f %s offline", dev);
420      res1 = run_program_and_log_output(command, 1);
421    }
422  else
423    {
424      res1 = 0;
425    }
426
427#ifdef __FreeBSD__
428  if (strstr (dev, "acd")) {
429      sprintf (command, "cdcontrol -f %s eject", dev);
430  } else {
431      sprintf (command, "camcontrol eject `echo %s | sed 's|/dev/||'`", dev);
432  }
433#else
434  sprintf(command, "eject %s", dev);
435#endif
436
437  log_msg(3, "Ejecting %s", dev);
438  res2 = run_program_and_log_output(command, 1);
439  paranoid_free(command);
440  if (res1 && res2) { return(1); }
441  else { return(0); }
442}
443
444/**
445 * Load (inject) the tray of the specified CD device.
446 * @param dev The device to load/inject.
447 * @return 0 for success, nonzero for failure.
448 */
449int inject_device(char*dev)
450{
451  char *command;
452  int i;
453
454  malloc_string(command);
455
456
457#ifdef __FreeBSD__
458  if (strstr (dev, "acd")) {
459      sprintf (command, "cdcontrol -f %s close", dev);
460  } else {
461      sprintf (command, "camcontrol load `echo %s | sed 's|/dev/||'`", dev);
462  }
463#else
464  sprintf(command, "eject -t %s", dev);
465#endif
466  i = run_program_and_log_output(command, FALSE);
467  paranoid_free(command);
468  return(i);
469}
470
471
472/**
473 * Determine whether the specified @p device (really, you can use any file)
474 * exists.
475 * @return TRUE if it exists, FALSE if it doesn't.
476 */
477bool
478does_device_exist (char *device)
479{
480
481    /*@ buffers ************************************************************/
482  char *tmp;
483
484  malloc_string(tmp);
485  assert_string_is_neither_NULL_nor_zerolength(device);
486
487  sprintf (tmp, "ls %s > /dev/null 2> /dev/null", device);
488 
489  paranoid_free(tmp);
490  if (system (tmp))
491    {
492      return (FALSE);
493    }
494  else
495    {
496      return (TRUE);
497    }
498}
499
500
501/**
502 * Determine whether a non-Microsoft partition exists on any connected hard drive.
503 * @return TRUE (there's a Linux/FreeBSD partition) or FALSE (Microsoft has taken over yet another innocent PC).
504 */
505bool
506does_nonMS_partition_exist (void)
507{
508#if __FreeBSD__
509    return !system ("for drive in /dev/ad? /dev/da?; do fdisk $drive | grep -q FreeBSD && exit 0; done; false");
510#else
511    return !system ("parted2fdisk -l 2>/dev/null | grep '^/dev/' | egrep -qv '(MS|DOS|FAT|NTFS)'");
512#endif
513}
514
515/**
516 * Determine whether the specified @p partno exists on the specified @p drive.
517 * @param drive The drive to search for the partition in.
518 * @param partno The partition number to look for.
519 * @return 0 if it exists, nonzero otherwise.
520 */
521int
522does_partition_exist (const char *drive, int partno)
523{
524    /*@ buffers *****************************************************/
525  char *program;
526  char *incoming;
527  char *searchstr;
528  char *tmp;
529
530    /*@ ints ********************************************************/
531  int res = 0;
532
533    /*@ pointers ****************************************************/
534  FILE *fin;
535
536
537    /*@ end vars ****************************************************/
538  assert_string_is_neither_NULL_nor_zerolength(drive);
539  assert(partno>=0 && partno<999);
540
541  malloc_string(program);
542  malloc_string(incoming);
543  malloc_string(searchstr);
544  malloc_string(tmp);
545
546#ifdef __FreeBSD__
547  // We assume here that this is running from mondorestore. (It is.)
548  sprintf (program, "ls %s >/dev/null 2>&1", drive, build_partition_name (tmp, drive, partno));
549  return system (program);
550#else
551  tmp[0] = '\0';
552#endif
553
554  sprintf (program, "parted2fdisk -l %s 2> /dev/null", drive);
555  fin = popen (program, "r");
556  if (!fin)
557    {
558      log_it("program=%s", program);
559      log_OS_error("Cannot popen-in program");
560      return (0);
561    }
562  (void) build_partition_name (searchstr, drive, partno);
563  strcat(searchstr, " ");
564  for (res = 0; !res && fgets (incoming, MAX_STR_LEN - 1, fin); )
565    {
566      if (strstr (incoming, searchstr))
567    {
568      res = 1;
569    }
570    }
571  if (pclose (fin)) { log_OS_error("Cannot pclose fin"); }
572  paranoid_free(program);
573  paranoid_free(incoming);
574  paranoid_free(searchstr);
575  paranoid_free(tmp);
576  return (res);
577}
578
579
580
581
582
583/**
584 * Determine whether given NULL-terminated @p str exists in the MBR of @p dev.
585 * @param dev The device to look in.
586 * @param str The string to look for.
587 * @return TRUE if it exists, FALSE if it doesn't.
588 */
589bool
590does_string_exist_in_boot_block (char *dev, char *str)
591{
592    /*@ buffers *****************************************************/
593  char *command;
594
595    /*@ end vars ****************************************************/
596  int i;
597
598  assert_string_is_neither_NULL_nor_zerolength(dev);
599  assert_string_is_neither_NULL_nor_zerolength(str);
600
601  malloc_string(command);
602  sprintf (command,
603       "dd if=%s bs=446 count=1 2> /dev/null | strings | grep \"%s\" > /dev/null 2> /dev/null",
604       dev, str);
605  i = system(command);
606  paranoid_free(command);
607  if (i)
608    {
609      return (FALSE);
610    }
611  else
612    {
613      return (TRUE);
614    }
615}
616
617/**
618 * Determine whether specified @p str exists in the first @p n sectors of
619 * @p dev.
620 * @param dev The device to look in.
621 * @param str The string to look for.
622 * @param n The number of 512-byte sectors to search.
623 */
624bool
625does_string_exist_in_first_N_blocks (char *dev, char *str, int n)
626{
627      /*@ buffers *****************************************************/
628  char *command;
629      /*@ end vars ****************************************************/ 
630  int i;
631
632  malloc_string(command);
633  sprintf (command,
634         "dd if=%s bs=512 count=%i 2> /dev/null | strings | grep \"%s\" > /dev/null 2> /dev/null",
635         dev, n, str);
636  i = system(command);
637  paranoid_free(command);
638  if (i)
639    {
640      return (FALSE);
641    }
642  else
643    {
644      return (TRUE);
645    }
646}
647
648
649
650/**
651 * Try to mount CD-ROM at @p mountpoint. If the CD-ROM is not found or has
652 * not been specified, call find_cdrom_device() to find it.
653 * @param bkpinfo The backup information structure. The only field used is @c bkpinfo->media_device.
654 * @param mountpoint Where to mount the CD-ROM.
655 * @return 0 for success, nonzero for failure.
656 * @see mount_CDROM_here
657 */
658int
659find_and_mount_actual_cd (struct s_bkpinfo *bkpinfo, char *mountpoint)
660{
661    /*@ buffers ******************************************************/
662
663    /*@ int's  *******************************************************/
664  int res;
665  char *dev;
666
667    /*@ end vars *****************************************************/
668
669  malloc_string(dev);
670  assert(bkpinfo!=NULL);
671  assert_string_is_neither_NULL_nor_zerolength(mountpoint);
672
673  if (g_backup_media_type == dvd)
674    {
675      strcpy(dev, g_dvd_drive_is_here);
676      if (!dev[0])
677        { find_dvd_device(dev,FALSE); }
678    }
679  else
680    {
681      strcpy(dev, g_cdrom_drive_is_here);
682      if (!dev[0])
683        { find_cdrom_device(dev,FALSE); }
684    }
685
686  if (bkpinfo->backup_media_type != iso)
687    { retract_CD_tray_and_defeat_autorun(); }
688
689  if (!dev[0] || (res=mount_CDROM_here (dev, mountpoint)))
690    {
691      if (!popup_and_get_string
692            ("CD-ROM device", "Please enter your CD-ROM's /dev device",
693            dev, MAX_STR_LEN/4))
694    { res = 1; }
695      else
696    { res=mount_CDROM_here (dev, mountpoint); }
697    }
698  if (res) { log_msg(1, "mount failed"); }
699  else { log_msg(1, "mount succeeded with %s", dev); }
700  paranoid_free(dev);
701  return (res);
702}
703
704
705
706
707
708/**
709 * Locate a CD-R/W writer's SCSI node.
710 * @param cdrw_device SCSI node will be placed here.
711 * @return 0 for success, nonzero for failure.
712 */
713
714
715/**
716 * Locate a CD-R/W writer's SCSI node.
717 * @param cdrw_device SCSI node will be placed here.
718 * @return 0 for success, nonzero for failure.
719 */
720int
721find_cdrw_device (char *cdrw_device)
722{
723    /*@ buffers *************************/
724  char *comment;
725  char *tmp;
726  char *cdr_exe;
727  char *command;
728
729  malloc_string(comment);
730  malloc_string(tmp);
731  malloc_string(cdr_exe);
732  malloc_string(command);
733  if (g_cdrw_drive_is_here[0])
734    {
735      strcpy(cdrw_device, g_cdrw_drive_is_here);
736      log_msg(3, "Been there, done that. Returning %s", cdrw_device);
737  paranoid_free(comment);
738  paranoid_free(tmp);
739  paranoid_free(cdr_exe);
740  paranoid_free(command);
741      return(0);
742    }
743  if (g_backup_media_type == dvd)
744    {
745      log_msg(1, "This is dumb. You're calling find_cdrw_device() but you're backing up to DVD. WTF?");
746  paranoid_free(comment);
747  paranoid_free(tmp);
748  paranoid_free(cdr_exe);
749  paranoid_free(command);
750      return(1);
751    }
752  run_program_and_log_output("insmod ide-scsi", -1);
753  if (find_home_of_exe("cdrecord"))
754    { strcpy(cdr_exe, "cdrecord"); }
755  else
756    { strcpy(cdr_exe, "dvdrecord"); }
757  tmp[0]='\0';
758  if (find_home_of_exe(cdr_exe))
759    {
760      sprintf(command, "%s -scanbus 2> /dev/null | tr -s '\t' ' ' | grep \"[0-9]*,[0-9]*,[0-9]*\" | grep -v \"[0-9]*) \\*\" | grep CD | cut -d' ' -f2 | head -n1", cdr_exe);
761      strcpy (tmp, call_program_and_get_last_line_of_output(command));
762    }
763  if (strlen (tmp) < 2)
764    {
765  paranoid_free(comment);
766  paranoid_free(tmp);
767  paranoid_free(cdr_exe);
768  paranoid_free(command);
769      return 1;
770    }
771  else
772    {
773      strcpy (cdrw_device, tmp);
774      sprintf (comment, "Found CDRW device - %s", cdrw_device);
775      log_it (comment);
776      strcpy (g_cdrw_drive_is_here, cdrw_device);
777      paranoid_free(comment);
778      paranoid_free(tmp);
779      paranoid_free(cdr_exe);
780      paranoid_free(command);
781      return (0);
782    }
783}
784
785
786
787
788/**
789 * Attempt to locate a CD-ROM device's /dev entry.
790 * Several different methods may be used to find the device, including
791 * calling @c cdrecord, searching @c dmesg, and trial-and-error.
792 * @param output Where to put the located /dev entry.
793 * @param try_to_mount Whether to mount the CD as part of the test; if mount
794 * fails then return failure.
795 * @return 0 for success, nonzero for failure.
796 */
797int
798find_cdrom_device (char *output, bool try_to_mount)
799{
800    /*@ pointers *****************************************************/
801  FILE *fin;
802  char *p;
803  char *q;
804  char *r;
805  int retval=0;
806
807    /*@ bool's *******************************************************/
808  bool found_it = FALSE;
809
810    /*@ buffers ******************************************************/
811  char *tmp;
812  char *cdr_exe;
813  char *phrase_one;
814  char *phrase_two;
815  char *command;
816  char *dvd_last_resort;
817  char *mountpoint;
818  static char the_last_place_i_found_it[MAX_STR_LEN] = "";
819
820    /*@ intialize ****************************************************/
821  malloc_string(tmp);
822  malloc_string(cdr_exe);
823  malloc_string(phrase_one);
824  malloc_string(phrase_two);
825  malloc_string(command);
826  malloc_string(dvd_last_resort);
827  malloc_string(mountpoint);
828 
829  output[0] = '\0';
830  phrase_one[0] = '\0';
831  phrase_two[0] = '\0';
832  dvd_last_resort[0] = '\0';
833
834    /*@ end vars *****************************************************/
835
836  if (g_cdrom_drive_is_here[0] && !isdigit(g_cdrom_drive_is_here[0]))
837    {
838      strcpy(output, g_cdrom_drive_is_here);
839      log_msg(3, "Been there, done that. Returning %s", output);
840      retval=0;
841      goto end_of_find_cdrom_device;
842    }
843  if (the_last_place_i_found_it[0]!='\0' && !try_to_mount)
844    {
845        strcpy(output, the_last_place_i_found_it);
846        log_msg(3, "find_cdrom_device() --- returning last found location - '%s'", output);
847        retval=0;
848    goto end_of_find_cdrom_device;
849    }
850
851  sprintf(mountpoint,"/tmp/cd.%d", (int)(random()%32767));
852  make_hole_for_dir(mountpoint);
853
854  if (find_home_of_exe("cdrecord"))
855    { strcpy(cdr_exe, "cdrecord"); }
856  else
857    { strcpy(cdr_exe, "dvdrecord"); }
858  tmp[0]='\0';
859  if (!find_home_of_exe(cdr_exe))
860    {
861      strcpy(output, "/dev/cdrom");
862      log_msg(4, "Can't find cdrecord; assuming %s", output);
863      if (!does_device_exist(output))
864        {
865          log_msg(4, "That didn't work. Sorry.");
866          retval=1;
867          goto end_of_find_cdrom_device;
868        }
869      else
870        {
871          retval=0;
872          goto end_of_find_cdrom_device;
873        }
874    }
875
876  sprintf(command, "%s -scanbus 2> /dev/null", cdr_exe);
877  fin = popen (command, "r");
878  if (!fin) { log_msg(4, "command=%s", command); log_OS_error("Cannot popen command"); return (1); }
879  for (fgets (tmp, MAX_STR_LEN, fin); !feof (fin);
880       fgets (tmp, MAX_STR_LEN, fin))
881    {
882      p = strchr (tmp, '\'');
883      if (p)
884    {
885      q = strchr (++p, '\'');
886      if (q)
887        {
888          for (r = q; *(r - 1) == ' '; r--);
889          *r = '\0';
890          strcpy (phrase_one, p);
891          p = strchr (++q, '\'');
892          if (p)
893        {
894          q = strchr (++p, '\'');
895          if (q)
896            {
897              while (*(q - 1) == ' ')
898            {
899              q--;
900            }
901              *q = '\0';
902              strcpy (phrase_two, p);
903            }
904        }
905        }
906    }
907    }
908  paranoid_pclose(fin);
909
910#ifndef __FreeBSD__
911  if (strlen(phrase_two)==0)
912    { log_msg(4, "Not running phase two. String is empty."); }
913  else
914    {
915      sprintf (command, "dmesg | grep \"%s\" 2> /dev/null", phrase_two);
916      fin = popen (command, "r");
917      if (!fin)
918        {
919          log_msg(4, "Cannot run 2nd command - non-fatal, fortunately");
920        }
921      else
922        {
923          for (fgets (tmp, MAX_STR_LEN, fin); !feof (fin); fgets (tmp, MAX_STR_LEN, fin))
924        {
925              log_msg(5, "--> '%s'", tmp);
926              if (tmp[0] != ' ' && tmp[1] != ' ')
927            {
928              p = strchr (tmp, ':');
929              if (p)
930            {
931              *p = '\0';
932              if (strstr(tmp, "DVD"))
933                {
934                  sprintf(dvd_last_resort, "/dev/%s", tmp);
935                  log_msg(4, "Ignoring '%s' because it's a DVD drive", tmp);
936                }
937              else
938                {
939                  sprintf (output, "/dev/%s", tmp);
940                  found_it = TRUE;
941                }
942            }
943                }
944            }
945          paranoid_pclose(fin);
946        }
947    }
948
949#endif
950#ifdef __FreeBSD__
951  if (!found_it)
952      { log_msg(4, "OK, approach 2"); if (!(found_it = set_dev_to_this_if_rx_OK(output, "/dev/cdrom")))
953        { if (!(found_it = set_dev_to_this_if_rx_OK(output, "/dev/cdrom1")))
954          { if (!(found_it = set_dev_to_this_if_rx_OK(output, "/dev/dvd")))
955            { if (!(found_it = set_dev_to_this_if_rx_OK(output, "/dev/acd0")))
956              { if (!(found_it = set_dev_to_this_if_rx_OK(output, "/dev/cd01")))
957                { if (!(found_it = set_dev_to_this_if_rx_OK(output, "/dev/acd1")))
958                  { if (!(found_it = set_dev_to_this_if_rx_OK(output, "/dev/cd1")))
959              { retval=1; goto end_of_find_cdrom_device; }
960          } } } } } } }
961#else
962  if (!found_it && strlen(dvd_last_resort)>0)
963    {
964      log_msg(4, "Well, I'll use the DVD - %s - as a last resort", dvd_last_resort);
965      strcpy(output, dvd_last_resort);
966      found_it = TRUE;
967    }
968  if (found_it)
969    {
970      sprintf(tmp, "grep \"%s=ide-scsi\" /proc/cmdline &> /dev/null", strrchr(output,'/')+1);
971      if (system(tmp) == 0)
972    {
973      log_msg(4, "%s is not right. It's being SCSI-emulated. Continuing.", output);
974      found_it = FALSE;
975      output[0] = '\0';
976    }
977    }
978
979  if (found_it)
980    {
981      log_msg(4, "(find_cdrom_device) --> '%s'", output);
982      if (!does_device_exist(output)) { found_it=FALSE; log_msg(4, "OK, I was wrong, I haven't found it... yet."); }
983    }
984
985  if (!found_it)
986      { log_msg(4, "OK, approach 2"); if (!(found_it = set_dev_to_this_if_rx_OK(output, "/dev/scd0")))
987        { if (!(found_it = set_dev_to_this_if_rx_OK(output, "/dev/sr0" )))
988          { if (!(found_it = set_dev_to_this_if_rx_OK(output, "/dev/cdrom")))
989            { if (!(found_it = set_dev_to_this_if_rx_OK(output, "/dev/cdrom0")))
990              { if (!(found_it = set_dev_to_this_if_rx_OK(output, "/dev/cdrom1")))
991        { if (!(found_it = set_dev_to_this_if_rx_OK(output, "/dev/sr1")))
992                  { if (!(found_it = set_dev_to_this_if_rx_OK(output, "/dev/dvd")))
993            { if (!(found_it = set_dev_to_this_if_rx_OK(output, g_cdrw_drive_is_here)))
994              { retval=1; goto end_of_find_cdrom_device; }
995            } } } } } } } }
996#endif
997
998  if (found_it && try_to_mount)
999    {
1000      if (mount_CDROM_here (output, mountpoint))
1001        {
1002          log_msg(4, "[Cardigans] I've changed my mind");
1003          found_it = FALSE;
1004        }
1005      else
1006        {
1007          sprintf(tmp, "%s/archives", mountpoint);
1008          if (!does_file_exist(tmp))
1009            {
1010              log_msg(4, "[Cardigans] I'll take it back");
1011              found_it = FALSE;
1012            }
1013          else
1014            {
1015              sprintf(command, "umount %s", output);
1016              paranoid_system(command);
1017              log_msg(4, "I'm confident the Mondo CD is in %s", output);
1018        }
1019        }
1020    }
1021  unlink(mountpoint);
1022
1023  if (found_it)
1024    {
1025      if (!does_file_exist(output)) { log_msg(3, "I still haven't found it."); return(1); }
1026      log_msg(3, "(find_cdrom_device) --> '%s'", output);
1027      strcpy(the_last_place_i_found_it, output);
1028      strcpy(g_cdrom_drive_is_here, output);
1029      retval=0;
1030      goto end_of_find_cdrom_device;
1031    }
1032
1033  sprintf(command, "%s -scanbus | grep \"[0-9],[0-9],[0-9]\" | grep \"[D|C][V|D]\" | grep -n \"\" | grep \"%s\" | cut -d':' -f2", cdr_exe, g_cdrw_drive_is_here);
1034  log_msg(1, "command=%s", command);
1035  strcpy(tmp, call_program_and_get_last_line_of_output(command));
1036  if (tmp[0])
1037    { 
1038      strcpy(output, tmp); 
1039      log_msg(4, "Finally found it at %s", output);
1040      retval=0;
1041      goto end_of_find_cdrom_device;
1042    }
1043  else
1044    {
1045      log_msg(4, "Still couldn't find it."); 
1046      retval=1;
1047      goto end_of_find_cdrom_device;
1048    }
1049end_of_find_cdrom_device:
1050  paranoid_free(tmp);
1051  paranoid_free(cdr_exe);
1052  paranoid_free(phrase_one);
1053  paranoid_free(phrase_two);
1054  paranoid_free(command);
1055  paranoid_free(dvd_last_resort);
1056  paranoid_free(mountpoint);
1057  return(retval);
1058}
1059
1060
1061
1062
1063
1064int find_dvd_device(char*output, bool try_to_mount)
1065{
1066  char *command;
1067  char *tmp;
1068  int retval=0, devno=-1;
1069
1070  malloc_string(command);
1071  malloc_string(tmp);
1072
1073    if (g_dvd_drive_is_here[0])
1074    {
1075      strcpy(output, g_dvd_drive_is_here);
1076      log_msg(3, "Been there, done that. Returning %s", output);
1077      return(0);
1078    }
1079
1080  sprintf(tmp, call_program_and_get_last_line_of_output
1081            (
1082"dvdrecord -scanbus 2> /dev/null | grep \") '\" | grep -n \"\" | grep DVD | cut -d':' -f1"
1083            )
1084        );
1085  log_msg(5, "tmp = '%s'", tmp);
1086  if (!tmp[0]) sprintf (tmp, call_program_and_get_last_line_of_output
1087                 (
1088"cdrecord -scanbus 2> /dev/null | grep \") '\" | grep -n \"\" | grep DVD | cut -d':' -f1"
1089                             )
1090                       );
1091  if (tmp[0])
1092    {
1093      devno=atoi(tmp) - 1;
1094    }
1095  if (devno>=0)
1096    {
1097      retval=0;
1098      sprintf(output, "/dev/scd%d", devno);
1099      strcpy(g_dvd_drive_is_here, output);
1100      log_msg(2, "I think DVD is at %s", output);
1101    }
1102  else
1103    {
1104      log_msg(2,"I cannot find DVD");
1105      retval=1;
1106    }
1107
1108  if (try_to_mount)
1109    {
1110      log_msg(1, "Ignoring the fact that try_to_mount==TRUE");
1111    }
1112  return(retval);
1113}
1114
1115
1116
1117
1118
1119#include <sys/ioctl.h>
1120
1121/**
1122 * Find the size of the specified @p drive, in megabytes. Uses @c ioctl calls
1123 * and @c dmesg.
1124 * @param drive The device to find the size of.
1125 * @return size in megabytes.
1126 */
1127long
1128get_phys_size_of_drive (char *drive)
1129{
1130    int fd;
1131#if linux
1132    unsigned long long s=0;
1133    int fileid, cylinders=0, cylindersleft=0;
1134    int cylindersize=0;
1135    int gotgeo = 0;
1136
1137   
1138  struct hd_geometry hdgeo;
1139#elif __FreeBSD__
1140    off_t s;
1141#endif
1142
1143    long outvalA=-1;
1144    long outvalB=-1;
1145    long outvalC=-1;
1146
1147    if ((fd = open (drive, O_RDONLY)) != -1) {
1148    if (ioctl (fd,
1149#if linux
1150    #ifdef BLKGETSIZE64
1151            BLKGETSIZE64,
1152    #else
1153            BLKGETSIZE,
1154   #endif
1155#elif __FreeBSD__
1156           DIOCGMEDIASIZE,
1157#endif
1158           &s) != -1) {
1159        close (fd);
1160                    // s>>11 works for older disks but not for newer ones
1161        outvalB =
1162#if linux
1163    #ifdef BLKGETSIZE64 
1164          s >> 20
1165    #else
1166              s >> 11
1167    #endif
1168#else
1169              s >> 20
1170#endif
1171;
1172    }
1173    }
1174
1175    if (outvalB<=0)
1176      { log_msg (1, "Error getting size of %s: %s", drive, strerror (errno)); }
1177#if linux
1178    fileid = open (drive, O_RDONLY);
1179    if (fileid) {
1180        if (ioctl (fileid, HDIO_GETGEO, &hdgeo) != -1) {
1181            if (hdgeo.cylinders && hdgeo.heads && hdgeo.sectors) {
1182                cylindersleft = cylinders = hdgeo.cylinders;
1183                cylindersize = hdgeo.heads * hdgeo.sectors / 2;
1184                outvalA = cylindersize * cylinders / 1024;
1185                log_msg (2, "Got Harddisk geometry, C:%d, H:%d, S:%d", hdgeo.cylinders, hdgeo.heads, hdgeo.sectors);
1186                gotgeo = 1;
1187            } else {
1188                log_msg (1, "Harddisk geometry wrong");
1189            }
1190        } else {
1191            log_msg (1, "Error in ioctl() getting new hard disk geometry (%s), resizing in unsafe mode", strerror(errno));
1192        }
1193        close(fileid);
1194    } else {
1195        log_msg (1, "Failed to open %s for reading: %s", drive, strerror(errno));
1196    }
1197    if (!gotgeo) {
1198        log_msg (1, "Failed to get harddisk geometry, using old mode");
1199    }
1200/* 
1201  if ((fd = open (drive, O_RDONLY)) != -1) {
1202      if (ioctl (fd, HDIO_GETGEO, &hdgeo) != -1)  {
1203      close (fd);
1204      log_msg (2, "Geometry of drive %s is C:%d, H:%d, S%d, its size is %d MB", drive, hdgeo.cylinders, hdgeo.heads, hdgeo.sectors, (hdgeo.cylinders * hdgeo.heads * hdgeo.sectors / 2 / 1024));
1205      if ( hdgeo.cylinders && hdgeo.heads && hdgeo.sectors ) {
1206          outvalB = ((long) (hdgeo.cylinders * hdgeo.heads * hdgeo.sectors / 2 / 1024));
1207      }
1208      }
1209      close (fd);
1210 */
1211#endif
1212
1213// OLDER DISKS will give ridiculously low value for outvalB (so outvalA is returned) :)
1214// NEWER DISKS will give sane value for outvalB (close to outvalA, in other words) :)
1215
1216  outvalC = (outvalA > outvalB) ? outvalA : outvalB;
1217 
1218//  log_msg (5, "drive = %s, error = %s", drive, strerror (errno));
1219//  fatal_error ("GPSOD: Unable to get size of drive");
1220  log_msg(1, "%s --> %ld or %ld --> %ld", drive, outvalA, outvalB, outvalC);
1221 
1222  return(outvalC);
1223}
1224   
1225/* The old version */
1226#if 0 
1227long
1228get_phys_size_of_drive (char *drive)
1229{
1230    /*@ pointers *****************************************************/
1231#if linux
1232  FILE *fin;
1233  char *p;
1234  char *q;
1235  char *r;
1236    /*@ buffers ******************************************************/
1237  char *tmp;
1238  char *command;
1239
1240    /*@ long *********************************************************/
1241  long outL;
1242  long tempLa;
1243  long tempLb;
1244  long tempLc;
1245
1246#endif
1247
1248  struct hd_geometry hdgeo;
1249  int fd;
1250
1251#ifdef __FreeBSD__
1252  off_t o;
1253
1254  if ((fd = open (drive, O_RDONLY)) != -1) {
1255      if (ioctl (fd, DIOCGMEDIASIZE, &o) != -1) {
1256      close (fd);
1257      return (long) (o / (off_t) (1024 * 1024));
1258      }
1259      close (fd);
1260  }
1261  log_msg (4, "drive = %s, error = %s", drive, strerror (errno));
1262  fatal_error ("GPSOD: Unable to get size of drive");
1263#else
1264
1265  malloc_string(tmp);
1266  malloc_string(command);
1267
1268  if ((fd = open (drive, O_RDONLY)) != -1) {
1269      if (ioctl (fd, HDIO_GETGEO, &hdgeo) != -1)  {
1270      close (fd);
1271      log_msg (2, "Geometry of drive %s is C:%d, H:%d, S%d, its size is %d MB", drive, hdgeo.cylinders, hdgeo.heads, hdgeo.sectors, (hdgeo.cylinders * hdgeo.heads * hdgeo.sectors / 2 / 1024));
1272      if ( hdgeo.cylinders && hdgeo.heads && hdgeo.sectors ) {
1273          return ((long) (hdgeo.cylinders * hdgeo.heads * hdgeo.sectors / 2 / 1024));
1274      }
1275      }
1276      close (fd);
1277  }
1278
1279  assert_string_is_neither_NULL_nor_zerolength(drive);
1280
1281  sprintf (command,
1282       "parted2fdisk -l %s | head -n4 | tr -s '\n' '\t' | tr -s ' ' '\t' | cut -f8,14,16",
1283       drive);
1284  strcpy (tmp, call_program_and_get_last_line_of_output (command));
1285  if (tmp[0])
1286    {
1287      p = tmp;
1288      q = strchr (p, ' ');
1289      if (q)
1290    {
1291      *(q++) = '\0';
1292      r = strchr (q, ' ');
1293      if (r)
1294        {
1295          *(r++) = '\0';
1296          tempLa = atol (p);
1297          tempLb = atol (q);
1298          tempLc = atol (r);
1299          outL = tempLa * tempLb / 1024 * tempLc / 1024;
1300          if (outL > 100)
1301        {
1302      paranoid_free(tmp);
1303      paranoid_free(command);
1304          return (outL);
1305        }
1306        }
1307    }
1308    }
1309
1310  /* try to grep for 'Drive xxxx: yyy MB' */
1311  sprintf(command, "parted2fdisk -l %s | grep MB | tr -s ' ' '\t' | cut -f3", drive);
1312  strcpy(tmp, call_program_and_get_last_line_of_output(command));
1313  if (atol(tmp) > 0)
1314    {
1315      paranoid_free(tmp);
1316      paranoid_free(command);
1317      return (atol(tmp));
1318    }
1319
1320  /* else, do it the old-fashioned way */
1321  p = strrchr (drive, (int) '/');
1322  if (p)
1323    {
1324      strcpy (tmp, p + 1);
1325    }
1326  else
1327    {
1328      paranoid_free(tmp);
1329      paranoid_free(command);
1330      return (-1);
1331    }
1332  sprintf (command, "dmesg | grep %s 2> /dev/null", tmp);
1333  if (!(fin = popen (command, "r")))
1334    { log_OS_error("Cannot popen dmesg command"); }
1335  else
1336    {
1337      fgets (tmp, MAX_STR_LEN - 1, fin);
1338      while (!feof (fin) && !strstr (tmp, "GB") && !strstr (tmp, "MB"))
1339        {
1340          fgets (tmp, MAX_STR_LEN - 1, fin);
1341        }
1342      if (pclose (fin)) { log_OS_error("Cannot pclose dmesg fin"); }
1343    }
1344  if (!(p = strstr (tmp, "GB")) && !(p = strstr (tmp, "MB")))
1345    {
1346      log_msg (3, "Cannot find %s's size: dmesg isn't helping either.",
1347           drive);
1348      paranoid_free(tmp);
1349      paranoid_free(command);
1350      return (-1);
1351    }
1352  for (; !isdigit (*(p - 1)); p--);
1353  *p = '\0';
1354  for (p--; isdigit (*(p - 1)); p--);
1355  outL = atol (p);
1356  if (outL <= 0)
1357    {
1358      paranoid_free(tmp);
1359      paranoid_free(command);
1360      return (-1);
1361    }
1362  if (strstr (tmp, "GB"))
1363    {
1364      outL = outL * 1024;
1365    }
1366      paranoid_free(tmp);
1367      paranoid_free(command);
1368  return (outL * 19 / 20);
1369#endif
1370}
1371#endif /* 0 */
1372
1373
1374
1375
1376
1377/**
1378 * Determine whether @p format is supported by the kernel. Uses /proc/filesystems
1379 * under Linux and @c lsvfs under FreeBSD.
1380 * @param format The format to test.
1381 * @return TRUE if the format is supported, FALSE if not.
1382 */
1383bool
1384is_this_a_valid_disk_format (char *format)
1385{
1386  char *good_formats;
1387    char *command;
1388    char *format_sz;
1389
1390  FILE *pin;
1391  int retval;
1392  malloc_string(good_formats);
1393  malloc_string(command);
1394  malloc_string(format_sz);
1395
1396  assert_string_is_neither_NULL_nor_zerolength(format);
1397
1398  sprintf (format_sz, "%s ", format);
1399
1400#ifdef __FreeBSD__
1401  sprintf (command,
1402           "lsvfs | tr -s '\t' ' ' | grep -v Filesys | grep -v -- -- | cut -d' ' -f1 | tr -s '\n' ' '");
1403#else
1404  sprintf (command,
1405       "cat /proc/filesystems | grep -v nodev | tr -s '\t' ' ' | cut -d' ' -f2 | tr -s '\n' ' '");
1406#endif
1407
1408  pin = popen (command, "r");
1409  if (!pin)
1410    {
1411      log_OS_error ("Unable to read good formats");
1412      retval=0;
1413    }
1414  else
1415    {
1416      strcpy (good_formats, " ");
1417      (void) fgets (good_formats + 1, MAX_STR_LEN, pin);
1418      if (pclose (pin))
1419        { log_OS_error("Cannot pclose good formats"); }
1420      strip_spaces (good_formats);
1421      strcat (good_formats, " swap lvm raid ntfs 7 "); // " ntfs 7 " -- um, cheating much? :)
1422      if (strstr (good_formats, format_sz))
1423        {
1424      retval=1;
1425        }
1426      else
1427        {
1428      retval=0;
1429        }
1430    }
1431  paranoid_free(good_formats);
1432  paranoid_free(command);
1433  paranoid_free(format_sz);
1434  return (retval);
1435}
1436
1437
1438/** @def SWAPLIST_COMMAND The command to list the swap files/partitions in use. */
1439
1440/**
1441 * Determine whether @p device_raw is currently mounted.
1442 * @param device_raw The device to check.
1443 * @return TRUE if it's mounted, FALSE if not.
1444 */
1445bool is_this_device_mounted (char *device_raw)
1446{
1447
1448    /*@ pointers *****************************************************/
1449  FILE *fin;
1450
1451    /*@ buffers ******************************************************/
1452  char *incoming;
1453  char *device_with_tab;
1454  char *device_with_space;
1455  char *tmp;
1456  int retval=0;
1457 
1458#ifdef __FreeBSD__
1459  #define SWAPLIST_COMMAND "swapinfo"
1460#else
1461  #define SWAPLIST_COMMAND "cat /proc/swaps"
1462#endif
1463
1464    /*@ end vars *****************************************************/
1465
1466  malloc_string(incoming);
1467  malloc_string(device_with_tab);
1468  malloc_string(device_with_space);
1469  malloc_string(tmp);
1470  assert(device_raw!=NULL);
1471//  assert_string_is_neither_NULL_nor_zerolength(device_raw);
1472  if (device_raw[0] != '/' && !strstr(device_raw, ":/"))
1473    {
1474      log_msg(1, "%s needs to have a '/' prefixed - I'll do it", device_raw);
1475      sprintf(tmp, "/%s", device_raw);
1476    }
1477  else
1478    {
1479      strcpy(tmp, device_raw);
1480    }
1481  log_msg(1, "Is %s mounted?", tmp);
1482  if (!strcmp(tmp, "/proc") || !strcmp(tmp, "proc"))
1483    {
1484      log_msg(1, "I don't know how the heck /proc made it into the mountlist. I'll ignore it.");
1485      return(0);
1486    }
1487  sprintf (device_with_tab, "%s\t", tmp);
1488  sprintf (device_with_space, "%s ", tmp);
1489
1490  if (!(fin = popen ("mount", "r"))) { log_OS_error("Cannot popen 'mount'"); return(FALSE); }
1491  for (fgets (incoming, MAX_STR_LEN - 1, fin); !feof (fin);
1492       fgets (incoming, MAX_STR_LEN - 1, fin))
1493    {
1494      if ( strstr (incoming, device_with_space) //> incoming
1495      || strstr (incoming, device_with_tab) ) // > incoming)
1496    {
1497      paranoid_pclose (fin);
1498      retval=1;
1499      goto end_of_func;
1500    }
1501    }
1502  paranoid_pclose(fin);
1503  sprintf (tmp, "%s | grep -w \"%s\" > /dev/null 2> /dev/null",
1504       SWAPLIST_COMMAND, device_with_space);
1505  log_msg(4, "tmp (command) = '%s'", tmp);
1506  if (!system (tmp))
1507    {
1508      retval=1;
1509      goto end_of_func;
1510    }
1511end_of_func:
1512  paranoid_free(incoming);
1513  paranoid_free(device_with_tab);
1514  paranoid_free(device_with_space);
1515  paranoid_free(tmp);
1516  return (retval);
1517}
1518
1519#ifdef __FreeBSD__
1520//                       CODE IS FREEBSD-SPECIFIC
1521/**
1522 * Create a loopback device for specified @p fname.
1523 * @param fname The file to associate with a device.
1524 * @return /dev entry for the device, or NULL if it couldn't be allocated.
1525 */
1526char *
1527make_vn (char *fname)
1528{
1529    char *device   = (char*) malloc (MAX_STR_LEN);
1530    char *mddevice = (char*) malloc (32);
1531    char command[MAX_STR_LEN];
1532    int vndev = 2;
1533    if (atoi (call_program_and_get_last_line_of_output ("/sbin/sysctl -n kern.osreldate")) <
1534        500000) {
1535        do {
1536            sprintf (mddevice, "vn%ic", vndev++);
1537            sprintf (command, "vnconfig %s %s", mddevice, fname);
1538            if (vndev > 10) {
1539                return NULL;
1540            }
1541        }
1542       while (system (command));
1543    } else {
1544        sprintf (command, "mdconfig -a -t vnode -f %s", fname);
1545        mddevice = call_program_and_get_last_line_of_output (command);
1546        if (!strstr (mddevice, "md")) {
1547            return NULL;
1548        }
1549    }
1550    sprintf (device, "/dev/%s", mddevice);
1551    return device;
1552}
1553
1554
1555
1556//                       CODE IS FREEBSD-SPECIFIC
1557/**
1558 * Deallocate specified @p dname.
1559 * This should be called when you are done with the device created by make_vn(),
1560 * so the system does not run out of @c vn devices.
1561 * @param dname The device to deallocate.
1562 * @return 0 for success, nonzero for failure.
1563 */
1564int
1565kick_vn (char *dname)
1566{
1567    char command[MAX_STR_LEN];
1568
1569    if (strncmp (dname, "/dev/", 5) == 0) {
1570        dname += 5;
1571    }
1572
1573    if (atoi (call_program_and_get_last_line_of_output ("/sbin/sysctl -n kern.osreldate")) <
1574        500000) {
1575        sprintf (command, "vnconfig -d %s", dname);
1576        return system (command);
1577    } else {
1578        sprintf (command, "mdconfig -d -u %s", dname);
1579        return system (command);
1580    }
1581    /*NOTREACHED*/
1582    return 255;
1583}
1584#endif
1585
1586
1587/**
1588 * Mount the CD-ROM at @p mountpoint.
1589 * @param device The device (or file if g_ISO_restore_mode) to mount.
1590 * @param mountpoint The place to mount it.
1591 * @return 0 for success, nonzero for failure.
1592 */
1593int
1594mount_CDROM_here (char *device, char *mountpoint)
1595{
1596    /*@ buffer *******************************************************/
1597  char *command;
1598  char *dev;
1599  char *options;
1600  int retval;
1601
1602  malloc_string(command);
1603  malloc_string(dev);
1604  malloc_string(options);
1605  assert_string_is_neither_NULL_nor_zerolength(device);
1606  assert_string_is_neither_NULL_nor_zerolength(mountpoint);
1607
1608  make_hole_for_dir(mountpoint);
1609  strcpy(options, "ro");
1610  if (isdigit(device[0]))
1611    { find_cdrom_device(device, FALSE); }
1612  else
1613    { strcpy(dev, device); }
1614  if (g_ISO_restore_mode)
1615    {
1616
1617#ifdef __FreeBSD__
1618      strcpy (dev, make_vn (device));
1619      if (!dev) {
1620          sprintf (command, "Unable to mount ISO (make_vn(%s) failed)", device);
1621          fatal_error (command);
1622        }
1623      strcpy (device, dev);
1624#else
1625      strcat(options,",loop");
1626#endif
1627
1628    }
1629  log_msg(4, "(mount_CDROM_here --- device=%s, mountpoint=%s", device, mountpoint);
1630    /*@ end vars ****************************************************/
1631
1632#ifdef __FreeBSD__
1633  sprintf (command, "mount_cd9660 -r %s %s 2>> %s",
1634           device, mountpoint, MONDO_LOGFILE);
1635
1636#else
1637  sprintf (command, "mount %s -o %s -t iso9660 %s 2>> %s",
1638           device, options, mountpoint, MONDO_LOGFILE);
1639#endif
1640
1641  log_msg (4, command);
1642  if (strncmp(device, "/dev/", 5) == 0)
1643    {
1644      retract_CD_tray_and_defeat_autorun(); 
1645    }
1646  retval = system (command);
1647  log_msg(1, "system(%s) returned %d", command, retval);
1648
1649  paranoid_free(command);
1650  paranoid_free(dev);
1651  paranoid_free(options);
1652  return(retval);
1653}
1654
1655
1656
1657
1658
1659
1660/**
1661 * Ask the user for CD number @p cd_number_i_want.
1662 * Sets g_current_media_number once the correct CD is inserted.
1663 * @param bkpinfo The backup information structure. Fields used:
1664 * - @c bkpinfo->backup_media_type
1665 * - @c bkpinfo->prefix
1666 * - @c bkpinfo->isodir
1667 * - @c bkpinfo->media_device
1668 * - @c bkpinfo->please_dont_eject_when_restoring
1669 * @param cd_number_i_want The CD number to ask for.
1670 */
1671void
1672insist_on_this_cd_number (struct s_bkpinfo* bkpinfo, int cd_number_i_want)
1673{
1674
1675    /*@ int **************************************************************/
1676  int res = 0;
1677
1678
1679    /*@ buffers **********************************************************/
1680  char *tmp;
1681  char *request;
1682
1683  assert(bkpinfo!=NULL);
1684  assert(cd_number_i_want > 0);
1685
1686//  log_msg(3, "Insisting on CD number %d", cd_number_i_want);
1687
1688  if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type))
1689    {
1690      log_msg(3, "No need to insist_on_this_cd_number when the backup type isn't CD-R(W) or NFS or ISO");
1691      return;
1692    }
1693  malloc_string(tmp);
1694  malloc_string(request);
1695  sprintf(tmp, "mkdir -p "MNT_CDROM);
1696  run_program_and_log_output(tmp, 5);
1697  if (g_ISO_restore_mode || bkpinfo->backup_media_type == iso || bkpinfo->backup_media_type == nfs)
1698    {
1699      log_msg(3, "Remounting CD");
1700      g_ISO_restore_mode = TRUE;
1701// FIXME --- I'm tempted to do something about this...
1702// Why unmount and remount again and again?
1703      if (is_this_device_mounted(MNT_CDROM)) { run_program_and_log_output("umount "MNT_CDROM, 5); }
1704      system("mkdir -p /tmp/isodir &> /dev/null");
1705      sprintf(tmp, "%s/%s/%s-%d.iso", bkpinfo->isodir, bkpinfo->nfs_remote_dir, bkpinfo->prefix, cd_number_i_want);
1706      if (!does_file_exist(tmp))
1707        {
1708      sprintf(tmp, "/tmp/isodir/%s/%s-%d.iso", bkpinfo->nfs_remote_dir, bkpinfo->prefix, cd_number_i_want);
1709      if (does_file_exist(tmp))
1710        {
1711          log_msg(1, "FIXME - hacking bkpinfo->isodir from '%s' to /tmp/isodir", bkpinfo->isodir);
1712          strcpy(bkpinfo->isodir, "/tmp/isodir");
1713        }
1714        }
1715      log_msg(3, "Mounting %s at %s", tmp, MNT_CDROM);
1716      if (mount_CDROM_here(tmp, MNT_CDROM)) { fatal_error("Mommy!"); }
1717//    g_current_media_number = cd_number_i_want;
1718//    return;
1719    }
1720  if ((res=what_number_cd_is_this (bkpinfo)) != cd_number_i_want)
1721    {
1722      log_msg(3, "Currently, we hold %d but we want %d", res, cd_number_i_want);
1723      sprintf (tmp, "Insisting on %s #%d", media_descriptor_string(bkpinfo->backup_media_type), cd_number_i_want);
1724      sprintf (request, "Please insert %s #%d and press Enter.",
1725               media_descriptor_string(bkpinfo->backup_media_type),
1726           cd_number_i_want);
1727      log_msg (3, tmp);
1728      while (what_number_cd_is_this (bkpinfo) != cd_number_i_want)
1729    {
1730      paranoid_system ("sync");
1731      if (is_this_device_mounted (MNT_CDROM))
1732        {
1733          res = run_program_and_log_output ("umount "MNT_CDROM, FALSE);
1734        }
1735      else
1736        {
1737          res = 0;
1738        }
1739      if (res)
1740        {
1741          log_to_screen ("WARNING - failed to unmount CD-ROM drive");
1742        }
1743          if (!bkpinfo->please_dont_eject)
1744            { res = eject_device(bkpinfo->media_device); }
1745          else
1746            { res = 0; }
1747      if (res)
1748        {
1749              log_to_screen ("WARNING - failed to eject CD-ROM disk");
1750        }
1751          popup_and_OK (request);
1752          if (!bkpinfo->please_dont_eject)
1753            {
1754              inject_device(bkpinfo->media_device);
1755            }
1756      paranoid_system ("sync");
1757    }
1758      log_msg (1, "Thankyou. Proceeding...");
1759      g_current_media_number = cd_number_i_want;
1760    }
1761  paranoid_free(tmp);
1762  paranoid_free(request);
1763}
1764
1765/* @} - end of deviceGroup */
1766
1767
1768
1769
1770
1771
1772/**
1773 * Ask user for details of backup/restore information.
1774 * Called when @c mondoarchive doesn't get any parameters.
1775 * @param bkpinfo The backup information structure to fill out with the user's data.
1776 * @param archiving_to_media TRUE if archiving, FALSE if restoring.
1777 * @return 0, always.
1778 * @bug No point of `int' return value.
1779 * @ingroup archiveGroup
1780 */
1781int interactively_obtain_media_parameters_from_user(struct s_bkpinfo *bkpinfo, bool archiving_to_media)
1782// archiving_to_media is TRUE if I'm being called by mondoarchive
1783// archiving_to_media is FALSE if I'm being called by mondorestore
1784{
1785  char *tmp;
1786  char *sz_size;
1787  char *command;
1788  char *comment;
1789  char *prompt;
1790  int i;
1791  FILE*fin;
1792
1793  malloc_string(tmp);
1794  malloc_string(sz_size);
1795  malloc_string(command);
1796  malloc_string(comment);
1797  malloc_string(prompt);
1798  assert(bkpinfo!=NULL);
1799  sz_size[0] = '\0';
1800  bkpinfo->nonbootable_backup = FALSE;
1801
1802// Tape, CD, NFS, ...?
1803  srandom(getpid());
1804  bkpinfo->backup_media_type = (g_restoring_live_from_cd) ? cdr : which_backup_media_type(bkpinfo->restore_data);
1805  if (bkpinfo->backup_media_type == none)
1806    { log_to_screen("User has chosen not to backup the PC"); finish(1); }
1807  if (bkpinfo->backup_media_type == tape && bkpinfo->restore_data)
1808    { popup_and_OK("Please remove CD/floppy from drive(s)"); }
1809  log_msg(3, "media type = %s", bkptype_to_string(bkpinfo->backup_media_type));
1810  if (archiving_to_media)
1811    {
1812      sensibly_set_tmpdir_and_scratchdir(bkpinfo);
1813    }
1814  bkpinfo->cdrw_speed = (bkpinfo->backup_media_type == cdstream) ? 2 : 4;
1815  bkpinfo->compression_level = (bkpinfo->backup_media_type == cdstream) ? 1:5;
1816  bkpinfo->use_lzo =  (bkpinfo->backup_media_type == cdstream) ? TRUE : FALSE;
1817
1818/*
1819  if (find_home_of_exe("star") && (!find_home_of_exe("afio") || find_home_of_exe("selinuxenabled")))
1820    {
1821      bkpinfo->use_star = FALSE;   
1822      bkpinfo->use_lzo = FALSE;
1823      log_to_screen("Using star, not afio");
1824      if (!find_home_of_exe("afio"))
1825    { log_to_screen("...because afio not found"); }
1826      if (find_home_of_exe("selinuxenabled"))
1827    { log_to_screen("...because SELINUX found"); }
1828    }
1829*/
1830
1831  mvaddstr_and_log_it(2, 0, " ");
1832
1833// Find device's /dev (or SCSI) entry
1834  switch(bkpinfo->backup_media_type)
1835    {
1836      case cdr:
1837      case cdrw:
1838      case dvd:
1839    if (archiving_to_media)
1840          {
1841            if (ask_me_yes_or_no("Is your computer a laptop, or does the CD writer incorporate BurnProof technology?"))
1842              { bkpinfo->manual_cd_tray = TRUE; }
1843            if ((bkpinfo->compression_level = which_compression_level()) == -1)
1844              { log_to_screen("User has chosen not to backup the PC"); finish(1); }
1845        sprintf(comment, "What speed is your %s (re)writer?", media_descriptor_string(bkpinfo->backup_media_type));
1846        if (bkpinfo->backup_media_type==dvd)
1847          {
1848        find_dvd_device(bkpinfo->media_device, FALSE);
1849            strcpy(tmp, "1");
1850        sprintf(sz_size, "%d", DEFAULT_DVD_DISK_SIZE); // 4.7 salesman's GB = 4.482 real GB = 4582 MB
1851        log_msg(1, "Setting to DVD defaults");
1852          }
1853        else
1854          {
1855                strcpy(bkpinfo->media_device, VANILLA_SCSI_CDROM);
1856            strcpy(tmp, "4");
1857        strcpy(sz_size, "650");
1858        log_msg(1, "Setting to CD defaults");
1859          }
1860        if (bkpinfo->backup_media_type != dvd)
1861          {
1862            if (!popup_and_get_string("Speed", comment, tmp, 4))
1863              { log_to_screen("User has chosen not to backup the PC"); finish(1); }
1864          }
1865            bkpinfo->cdrw_speed = atoi(tmp); // if DVD then this shouldn't ever be used anyway :)
1866        sprintf(comment, "How much data (in Megabytes) will each %s store?", media_descriptor_string(bkpinfo->backup_media_type));
1867        if (!popup_and_get_string("Size", comment, sz_size, 5))
1868          { log_to_screen("User has chosen not to backup the PC"); finish(1); }
1869        for(i=0; i<=MAX_NOOF_MEDIA; i++) { bkpinfo->media_size[i] = atoi(sz_size); }
1870        if (bkpinfo->media_size[0] <=0)
1871              { log_to_screen("User has chosen not to backup the PC"); finish(1); }
1872          }
1873      case cdstream:
1874    if (bkpinfo->disaster_recovery)
1875      {
1876            strcpy(bkpinfo->media_device, "/dev/cdrom");
1877        log_msg(2, "CD-ROM device assumed to be at %s", bkpinfo->media_device);
1878      }
1879    else if (bkpinfo->restore_data
1880        || bkpinfo->backup_media_type == dvd)
1881      {
1882            if (!bkpinfo->media_device[0])
1883              { strcpy(bkpinfo->media_device, "/dev/cdrom"); } // just for the heck of it :)
1884        log_msg(1, "bkpinfo->media_device = %s", bkpinfo->media_device);
1885        if (bkpinfo->backup_media_type == dvd || find_cdrom_device (bkpinfo->media_device, FALSE))
1886          {
1887        log_msg(1, "bkpinfo->media_device = %s", bkpinfo->media_device);
1888            sprintf(comment, "Please specify your %s drive's /dev entry", media_descriptor_string(bkpinfo->backup_media_type));
1889            if (!popup_and_get_string("Device?", comment, bkpinfo->media_device, MAX_STR_LEN/4))
1890              { log_to_screen("User has chosen not to backup the PC"); finish(1); }
1891          }
1892        log_msg(2, "%s device found at %s", media_descriptor_string(bkpinfo->backup_media_type), bkpinfo->media_device);
1893      }
1894    else
1895      {
1896        if (find_cdrw_device(bkpinfo->media_device)) { bkpinfo->media_device[0]='\0'; }
1897        if (bkpinfo->media_device[0])
1898          {
1899            sprintf(tmp, "I think I've found your %s burner at SCSI node %s; am I right on the money?", media_descriptor_string(bkpinfo->backup_media_type), bkpinfo->media_device);
1900            if (!ask_me_yes_or_no(tmp)) { bkpinfo->media_device[0]='\0'; }
1901          }
1902           if (!bkpinfo->media_device[0])
1903          {
1904        if (g_kernel_version < 2.6)
1905          {
1906            i=popup_and_get_string("Device node?", "What is the SCSI node of your CD (re)writer, please?", bkpinfo->media_device, MAX_STR_LEN/4);
1907          }
1908        else
1909          {
1910            i=popup_and_get_string("/dev entry?", "What is the /dev entry of your CD (re)writer, please?", bkpinfo->media_device, MAX_STR_LEN/4);
1911          }
1912        if (!i)
1913              { log_to_screen("User has chosen not to backup the PC"); finish(1); }
1914          }
1915      }
1916    if (bkpinfo->backup_media_type == cdstream)
1917      {
1918        for(i=0; i<=MAX_NOOF_MEDIA; i++) { bkpinfo->media_size[i] = 650; }
1919      }
1920    break;
1921      case udev:
1922    if (!ask_me_yes_or_no("This option is for advanced users only. Are you sure?"))
1923      { log_to_screen("User has chosen not to backup the PC"); finish(1); }
1924      case tape:
1925
1926    if (find_tape_device_and_size(bkpinfo->media_device, sz_size))
1927      {
1928        log_msg(3, "Ok, using vanilla scsi tape.");
1929        strcpy(bkpinfo->media_device, VANILLA_SCSI_TAPE);
1930        if ((fin=fopen(bkpinfo->media_device, "r")))
1931          { paranoid_fclose(fin); }
1932        else
1933          { strcpy(bkpinfo->media_device, "/dev/osst0"); }
1934      }
1935    if (bkpinfo->media_device[0])
1936      {
1937        if ((fin=fopen(bkpinfo->media_device, "r")))
1938          { paranoid_fclose(fin); }
1939        else
1940          {
1941        if (does_file_exist("/tmp/mondo-restore.cfg"))
1942          {
1943            read_cfg_var("/tmp/mondo-restore.cfg", "media-dev", bkpinfo->media_device);
1944          }
1945          }
1946        sprintf(tmp, "I think I've found your tape streamer at %s; am I right on the money?", bkpinfo->media_device);
1947      }
1948    if (bkpinfo->media_device[0])
1949      {
1950        sprintf(tmp, "I think I've found your tape streamer at %s; am I right on the money?", bkpinfo->media_device);
1951        if (!ask_me_yes_or_no(tmp)) { bkpinfo->media_device[0]='\0'; }
1952      }
1953        if (!bkpinfo->media_device[0])
1954      {
1955        if (!popup_and_get_string("Device name?", "What is the /dev entry of your tape streamer?", bkpinfo->media_device, MAX_STR_LEN/4))
1956          { log_to_screen("User has chosen not to backup the PC"); finish(1); }
1957      }
1958    sprintf(tmp, "ls -l %s", bkpinfo->media_device);
1959    if (run_program_and_log_output(tmp, FALSE))
1960          { log_to_screen("User has not specified a valid /dev entry"); finish(1); }
1961    log_msg(4, "sz_size = %s", sz_size);
1962        sz_size[0] = '\0';
1963/*
1964    if ((size_sz[0]=='\0' || atol(size_sz)==0) && archiving_to_media)
1965      {
1966        if (!popup_and_get_string("Tape size", "How much COMPRESSED data will one of your tape cartridges hold? (e.g. 4GB for 4 gigabytes)", size_sz, 16))
1967          { log_to_screen("User has chosen not to backup the PC"); finish(1); }
1968      }
1969*/
1970    if (sz_size[0]=='\0')
1971      { bkpinfo->media_size[0] = 0; }
1972        else
1973      { bkpinfo->media_size[0] = friendly_sizestr_to_sizelong (sz_size)/2 - 50; }
1974    log_msg(4, "media_size[0] = %ld", bkpinfo->media_size[0]);
1975        if (bkpinfo->media_size[0] <= 0) { bkpinfo->media_size[0] = 0; }
1976    for(i=1; i<=MAX_NOOF_MEDIA; i++) { bkpinfo->media_size[i] = bkpinfo->media_size[0]; }
1977        if (archiving_to_media)
1978          {
1979            if ((bkpinfo->compression_level = which_compression_level()) == -1)
1980              { log_to_screen("User has chosen not to backup the PC"); finish(1); }
1981          }
1982        break;
1983
1984
1985
1986      case nfs:
1987    if (!bkpinfo->nfs_mount[0]) { strcpy(bkpinfo->nfs_mount, call_program_and_get_last_line_of_output("mount | grep \":\" | cut -d' ' -f1 | head -n1")); }
1988#ifdef __FreeBSD__
1989        if (TRUE)
1990#else
1991    if (!bkpinfo->disaster_recovery )
1992#endif
1993      {
1994        if (!popup_and_get_string("NFS dir.", "Please enter path and directory where archives are stored remotely. (Mondo has taken a guess at the correct value. If it is incorrect, delete it and type the correct one.)", bkpinfo->nfs_mount, MAX_STR_LEN/4))
1995          {
1996        log_to_screen("User has chosen not to backup the PC");
1997        finish(1);
1998          }
1999            if (!bkpinfo->restore_data)
2000              {
2001                if ((bkpinfo->compression_level = which_compression_level()) == -1)
2002                  {
2003                    log_to_screen("User has chosen not to backup the PC");
2004                    finish(1);
2005                  }
2006              }
2007            // check whether already mounted - we better remove
2008            // surrounding spaces and trailing '/' for this
2009            strip_spaces (bkpinfo->nfs_mount);
2010            if (bkpinfo->nfs_mount[strlen(bkpinfo->nfs_mount) - 1] == '/')
2011               bkpinfo->nfs_mount[strlen(bkpinfo->nfs_mount) - 1] = '\0';
2012            sprintf(command, "mount | grep \"%s \" | cut -d' ' -f3",bkpinfo->nfs_mount);
2013            strcpy(bkpinfo->isodir, call_program_and_get_last_line_of_output(command));
2014      }
2015    if (bkpinfo->disaster_recovery)
2016          {
2017        system("umount /tmp/isodir 2> /dev/null");
2018        if (!popup_and_get_string("NFS share", "Which remote NFS share should I mount?", bkpinfo->nfs_mount, MAX_STR_LEN))
2019          {
2020                log_to_screen("User has chosen not to backup the PC");
2021                finish(1);
2022          }
2023          }
2024        if (!is_this_device_mounted(bkpinfo->nfs_mount))
2025          {
2026                  sprintf(bkpinfo->isodir, "/tmp/isodir.mondo.%d", (int)(random()%32768));
2027                  sprintf(command, "mkdir -p %s", bkpinfo->isodir);
2028                  run_program_and_log_output(command, 5);
2029                  sprintf(tmp, "mount %s -t nfs %s", bkpinfo->nfs_mount, bkpinfo->isodir);
2030                  run_program_and_log_output(tmp, 5);
2031                  malloc_string(g_selfmounted_isodir);
2032                  strcpy(g_selfmounted_isodir, bkpinfo->isodir);
2033          }
2034    if (!is_this_device_mounted(bkpinfo->nfs_mount))
2035      {
2036        popup_and_OK("Please mount that partition before you try to backup to or restore from it.");
2037        finish(1);
2038      }
2039        strcpy(tmp, bkpinfo->nfs_remote_dir);
2040        if (!popup_and_get_string("Directory", "Which directory within that mountpoint?", tmp, MAX_STR_LEN))
2041          {
2042            log_to_screen("User has chosen not to backup the PC");
2043             finish(1);
2044          }
2045        strcpy(bkpinfo->nfs_remote_dir, tmp);
2046        // check whether writable - we better remove surrounding spaces for this
2047        strip_spaces (bkpinfo->nfs_remote_dir);
2048        sprintf (command, "echo hi > %s/%s/.dummy.txt", bkpinfo->isodir,
2049                                  bkpinfo->nfs_remote_dir);
2050        while (run_program_and_log_output (command, FALSE)) {
2051            strcpy(tmp, bkpinfo->nfs_remote_dir);
2052            sprintf (prompt,
2053                     "Directory '%s' under mountpoint '%s' does not exist or is not writable. You can fix this or change the directory and retry or cancel the backup.",
2054                     bkpinfo->nfs_remote_dir, bkpinfo->isodir);
2055            if(!popup_and_get_string ("Directory", prompt, tmp, MAX_STR_LEN)) {
2056                log_to_screen("User has chosen not to backup the PC");
2057                finish(1);
2058            }
2059            strcpy(bkpinfo->nfs_remote_dir, tmp);
2060            // check whether writable - we better remove surrounding space s for this
2061            strip_spaces (bkpinfo->nfs_remote_dir);
2062            sprintf (command, "echo hi > %s/%s/.dummy.txt", bkpinfo->isodir,
2063                                    bkpinfo->nfs_remote_dir);
2064        }
2065
2066    for(i=0; i<=MAX_NOOF_MEDIA; i++) { bkpinfo->media_size[i] = 650; }
2067        log_msg(3, "Just set nfs_remote_dir to %s", bkpinfo->nfs_remote_dir);
2068    log_msg(3, "isodir is still %s", bkpinfo->isodir);
2069    break;
2070
2071      case iso:
2072        if (!bkpinfo->disaster_recovery)
2073          {
2074             if (!popup_and_get_string("Storage dir.", "Please enter the full path that contains your ISO images.  Example: /mnt/raid0_0", bkpinfo->isodir, MAX_STR_LEN/4))
2075          { log_to_screen("User has chosen not to backup the PC"); finish(1); }
2076             if (archiving_to_media) {
2077                 if ((bkpinfo->compression_level = which_compression_level()) == -1)
2078                     { log_to_screen("User has chosen not to backup the PC"); finish(1); }
2079                 if (!popup_and_get_string ("ISO size.", "Please enter how big you want each ISO image to be (in megabytes). This should be less than or equal to the size of the CD-R[W]'s you plan to backup to.", sz_size, 16))
2080                     { log_to_screen ("User has chosen not to backup the PC"); finish(1); }
2081                 for(i=0; i<=MAX_NOOF_MEDIA; i++) { bkpinfo->media_size[i] = atoi (sz_size); }
2082             if (!popup_and_get_string("Prefix.", "Please enter the prefix that will be prepended to your ISO filename.  Example: machine1 to obtain machine1-[1-9]*.iso files", bkpinfo->prefix, MAX_STR_LEN/4))
2083          { log_to_screen("User has chosen not to backup the PC"); finish(1); }
2084             } else {
2085                 for (i=0;i<=MAX_NOOF_MEDIA; i++) { bkpinfo->media_size[i] = 650;}
2086             }
2087          }
2088    break;
2089      default:
2090    fatal_error("I, Mojo Jojo, shall defeat those pesky Powerpuff Girls!");
2091    }
2092
2093  if (archiving_to_media)
2094    {
2095
2096#ifdef __FreeBSD__
2097    strcpy (bkpinfo->boot_device, call_program_and_get_last_line_of_output
2098        ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/\\([0-9]\\).*/\\1/'"));
2099#else
2100    strcpy (bkpinfo->boot_device, call_program_and_get_last_line_of_output
2101            ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/[0-9].*//'"));
2102#endif
2103      i = which_boot_loader(bkpinfo->boot_device);
2104      if (i=='U') // unknown
2105        {
2106
2107#ifdef __FreeBSD__
2108          if (!popup_and_get_string("Boot device", "What is your boot device? (e.g. /dev/ad0)", bkpinfo->boot_device, MAX_STR_LEN/4))
2109            { log_to_screen("User has chosen not to backup the PC"); finish(1); }
2110          i = which_boot_loader (bkpinfo->boot_device);
2111#else
2112          if (!popup_and_get_string("Boot device", "What is your boot device? (e.g. /dev/hda)", bkpinfo->boot_device, MAX_STR_LEN/4))
2113            { log_to_screen("User has chosen not to backup the PC"); finish(1); }
2114          if (does_string_exist_in_boot_block(bkpinfo->boot_device, "LILO")) { i='L'; }
2115          else if (does_string_exist_in_boot_block(bkpinfo->boot_device, "ELILO")) { i='E'; }
2116          else if (does_string_exist_in_boot_block(bkpinfo->boot_device, "GRUB")) { i='G'; }
2117          else { i = 'U'; }
2118#endif
2119          if (i == 'U')
2120            {
2121          if (ask_me_yes_or_no("Unidentified boot loader. Shall I restore it byte-for-byte at restore time and hope for the best?"))
2122        {
2123          i = 'R'; // raw
2124        }
2125          else
2126        {
2127          log_to_screen("I cannot find your boot loader. Please run mondoarchive with parameters."); finish(1);
2128        }
2129        }
2130    }
2131      bkpinfo->boot_loader = i;
2132      strcpy(bkpinfo->include_paths, "/");
2133      if (!popup_and_get_string("Backup paths", "Please enter paths which you want me to backup. The default is '/' (i.e. everything).", bkpinfo->include_paths, MAX_STR_LEN))
2134        { log_to_screen("User has chosen not to backup the PC"); finish(1); }
2135      strcpy(tmp, list_of_NFS_mounts_only());
2136      if (strlen(tmp)>2)
2137        {
2138          if (bkpinfo->exclude_paths[0]) { strcat(bkpinfo->exclude_paths, " "); }
2139          strncpy(bkpinfo->exclude_paths, tmp, MAX_STR_LEN);
2140    }
2141
2142// NTFS
2143      strcpy(tmp, call_program_and_get_last_line_of_output("parted2fdisk -l | grep -i ntfs | awk '{ print $1};' | tr -s '\\n' ' ' | awk '{ print $0};'"));
2144      if (strlen(tmp) > 2)
2145        {
2146      if (!popup_and_get_string("NTFS partitions", "Please enter/confirm the NTFS partitions you wish to backup as well.", tmp, MAX_STR_LEN/4))
2147            { log_to_screen ("User has chosen not to backup the PC"); finish(1); }
2148          strncpy (bkpinfo->image_devs, tmp, MAX_STR_LEN/4);
2149    }
2150
2151
2152      if (!popup_and_get_string("Exclude paths", "Please enter paths which you do NOT want to backup. Separate them with spaces. NB: /tmp and /proc are always excluded. :-) Just hit 'Enter' if you want to do a full system backup.", bkpinfo->exclude_paths, MAX_STR_LEN))
2153        { log_to_screen("User has chosen not to backup the PC"); finish(1); }
2154      bkpinfo->make_cd_use_lilo = FALSE;
2155      bkpinfo->backup_data = TRUE;
2156      bkpinfo->verify_data = ask_me_yes_or_no("Will you want to verify your backups after Mondo has created them?");
2157
2158#ifndef __FreeBSD__
2159      if (!ask_me_yes_or_no("Are you confident that your kernel is a sane, sensible, standard Linux kernel? Say 'no' if you are using a Gentoo <1.4 or Debian <3.0, please."))
2160#endif
2161        { strcpy(bkpinfo->kernel_path, "FAILSAFE"); }
2162
2163      if (!ask_me_yes_or_no("Are you sure you want to proceed? Hit 'no' to abort."))
2164        { log_to_screen("User has chosen not to backup the PC"); finish(1); }
2165    }
2166  else
2167    {
2168      bkpinfo->restore_data = TRUE; // probably...
2169    }
2170
2171  if (bkpinfo->backup_media_type == iso || bkpinfo->backup_media_type == nfs)
2172    {
2173      g_ISO_restore_mode = TRUE;
2174    }
2175
2176#ifdef __FreeSD__
2177// skip
2178#else
2179  if (bkpinfo->backup_media_type == nfs)
2180    {
2181      sprintf(tmp, "mount | grep \"%s\" | cut -d' ' -f3", bkpinfo->nfs_mount);
2182//      strcpy(bkpinfo->isodir, call_program_and_get_last_line_of_output(tmp));
2183      log_msg(3, "I think the NFS mount is mounted at %s", bkpinfo->isodir);
2184    }
2185  log_it("isodir = %s", bkpinfo->isodir);
2186  log_it("nfs_mount = '%s'", bkpinfo->nfs_mount);
2187#endif
2188
2189  log_it("media device = %s", bkpinfo->media_device);
2190  log_it("media size = %ld", bkpinfo->media_size[1]);
2191  log_it("media type = %s", bkptype_to_string(bkpinfo->backup_media_type));
2192  log_it("compression = %ld", bkpinfo->compression_level);
2193  log_it("include_paths = '%s'", bkpinfo->include_paths);
2194  log_it("exclude_paths = '%s'", bkpinfo->exclude_paths);
2195  log_it("scratchdir = '%s'", bkpinfo->scratchdir);
2196  log_it("tmpdir = '%s'", bkpinfo->tmpdir);
2197  log_it("boot_device = '%s' (loader=%c)", bkpinfo->boot_device, bkpinfo->boot_loader);
2198  if (bkpinfo->media_size[0] < 0) 
2199    {
2200      if (archiving_to_media)
2201        {
2202          fatal_error("Media size is less than zero.");
2203        }
2204      else
2205        {
2206      log_msg(2, "Warning - media size is less than zero.");
2207      bkpinfo->media_size[0] = 0;
2208    }
2209    }
2210  paranoid_free(tmp);
2211  paranoid_free(sz_size);
2212  paranoid_free(command);
2213  paranoid_free(comment);
2214  paranoid_free(prompt);
2215  return(0);
2216}
2217
2218
2219
2220
2221/**
2222 * @addtogroup utilityGroup
2223 * @{
2224 */
2225/**
2226 * Get a space-separated list of NFS devices and mounts.
2227 * @return The list created.
2228 * @note The return value points to static data that will be overwritten with each call.
2229 */
2230char *list_of_NFS_devices_and_mounts(void)
2231{
2232  char *exclude_these_devices;
2233  char *exclude_these_directories;
2234  static char result_sz[512];
2235
2236  malloc_string(exclude_these_devices);
2237  malloc_string(exclude_these_directories);
2238  strcpy(exclude_these_directories, call_program_and_get_last_line_of_output("mount -t coda,ncpfs,nfs,smbfs | tr -s '\t' ' ' | cut -d' ' -f3 | tr -s '\n' ' ' | awk '{print $0;}'"));
2239  strcpy(exclude_these_devices, call_program_and_get_last_line_of_output("cat /etc/fstab | tr -s '\t' ' ' | grep -E '( (coda|ncpfs|nfs|smbfs) )' | cut -d' ' -f1 | tr -s '\n' ' ' | awk '{print $0;}'"));
2240  sprintf(result_sz, "%s %s", exclude_these_directories, exclude_these_devices);
2241  paranoid_free(exclude_these_devices);
2242  paranoid_free(exclude_these_directories);
2243  return(result_sz);
2244}
2245
2246
2247
2248
2249/**
2250 * Get a space-separated list of NFS mounts.
2251 * @return The list created.
2252 * @note The return value points to static data that will be overwritten with each call.
2253 * @bug Even though we only want the mounts, the devices are still checked.
2254 */
2255char *list_of_NFS_mounts_only(void)
2256{
2257  char *exclude_these_devices;
2258  char *exclude_these_directories;
2259  static char result_sz[512];
2260
2261  malloc_string(exclude_these_devices);
2262  malloc_string(exclude_these_directories);
2263  strcpy(exclude_these_directories, call_program_and_get_last_line_of_output("mount -t coda,ncpfs,nfs,smbfs | tr -s '\t' ' ' | cut -d' ' -f3 | tr -s '\n' ' ' | awk '{print $0;}'"));
2264  strcpy(exclude_these_devices, call_program_and_get_last_line_of_output("cat /etc/fstab | tr -s '\t' ' ' | grep -E '( (coda|ncpfs|nfs|smbfs) )' | cut -d' ' -f1 | tr -s '\n' ' ' | awk '{print $0;}'"));
2265  sprintf(result_sz, "%s", exclude_these_directories);
2266  paranoid_free(exclude_these_devices);
2267  paranoid_free(exclude_these_directories);
2268  return(result_sz);
2269}
2270
2271/* @} - end of utilityGroup */
2272
2273
2274
2275
2276
2277/**
2278 * Create a randomly-named FIFO. The format is @p stub "." [random] [random] where
2279 * [random] is a random number between 1 and 32767.
2280 * @param store_name_here Where to store the new filename.
2281 * @param stub A random number will be appended to this to make the FIFO's name.
2282 * @ingroup deviceGroup
2283 */
2284void make_fifo(char*store_name_here, char*stub)
2285{
2286  char *tmp;
2287
2288  malloc_string(tmp);
2289  assert_string_is_neither_NULL_nor_zerolength(stub);
2290
2291  sprintf(store_name_here, "%s%d%d", stub, (int)(random()%32768), (int)(random()%32768));
2292  make_hole_for_file(store_name_here);
2293  mkfifo(store_name_here, S_IRWXU|S_IRWXG);
2294  sprintf(tmp, "chmod 770 %s", store_name_here);
2295  paranoid_system(tmp);
2296  paranoid_free(tmp);
2297}
2298
2299
2300
2301
2302
2303
2304/**
2305 * Set the tmpdir and scratchdir to reside on the partition with the most free space.
2306 * Automatically excludes DOS, NTFS, SMB, and NFS filesystems.
2307 * @param bkpinfo The backup information structure. @c bkpinfo->tmpdir and @c bkpinfo->scratchdir will be set.
2308 * @ingroup utilityGroup
2309 */
2310void sensibly_set_tmpdir_and_scratchdir(struct s_bkpinfo *bkpinfo)
2311{
2312  char *tmp, *command, *sz;
2313
2314  malloc_string(tmp);
2315  malloc_string(command);
2316  malloc_string(sz);
2317  assert(bkpinfo!=NULL);
2318
2319#ifdef __FreeBSD__
2320      strcpy(tmp, call_program_and_get_last_line_of_output("df -m -t nonfs,msdosfs,ntfs,smbfs,smb,cifs | tr -s '\t' ' ' | grep -v none | grep -v Filesystem | awk '{printf \"%s %s\\n\", $4, $6;}' | sort -n | tail -n1 | awk '{print $NF;}'"));
2321#else
2322      strcpy(tmp, call_program_and_get_last_line_of_output("df -m -x nfs -x vfat -x ntfs -x smbfs -x smb -x cifs | sed 's/                  /devdev/' | tr -s '\t' ' ' | grep -v none | grep -v Filesystem | grep -v /dev/shm | awk '{printf \"%s %s\\n\", $4, $6;}' | sort -n | tail -n1 | awk '{print $NF;}'"));
2323#endif
2324
2325      if (tmp[0]!='/') { strcpy(sz, tmp); strcpy(tmp, "/"); strcat(tmp, sz); }
2326      if (!tmp[0]) {
2327      fatal_error ("I couldn't figure out the tempdir!");
2328      }
2329      sprintf(bkpinfo->tmpdir, "%s/tmp.mondo.%d", tmp, (int)(random()%32768));
2330      log_it("bkpinfo->tmpdir is being set to %s", bkpinfo->tmpdir);
2331
2332      sprintf(bkpinfo->scratchdir, "%s/mondo.scratch.%d", tmp, (int)(random()%32768));
2333      log_it("bkpinfo->scratchdir is being set to %s", bkpinfo->scratchdir);
2334
2335      sprintf(g_erase_tmpdir_and_scratchdir, "rm -Rf %s %s", bkpinfo->tmpdir, bkpinfo->scratchdir);
2336     
2337      sprintf(command, "rm -Rf %s/tmp.mondo.* %s/mondo.scratch.*", tmp, tmp);
2338      paranoid_system(command);
2339  paranoid_free(tmp);
2340  paranoid_free(command);
2341  paranoid_free(sz);
2342}
2343
2344
2345
2346
2347
2348
2349/**
2350 * @addtogroup deviceGroup
2351 * @{
2352 */
2353/**
2354 * If we can read @p dev, set @p output to it.
2355 * If @p dev cannot be read, set @p output to "".
2356 * @param dev The device to check for.
2357 * @param output Set to @p dev if @p dev exists, "" otherwise.
2358 * @return TRUE if @p dev exists, FALSE if it doesn't.
2359 */
2360bool set_dev_to_this_if_rx_OK(char *output, char*dev)
2361{
2362  char *command;
2363
2364  malloc_string(command);
2365  if (!dev || dev[0]=='\0') { output[0]='\0'; return(FALSE); }
2366//  assert_string_is_neither_NULL_nor_zerolength(dev);
2367  log_msg(10, "Injecting %s", dev);
2368  inject_device(dev);
2369  if (!does_file_exist(dev)) { log_msg(10, "%s doesn't exist. Returning FALSE.", dev); return(FALSE); }
2370  sprintf(command, "dd bs=%ld count=1 if=%s of=/dev/null &> /dev/null", 512L, dev);
2371  if (!run_program_and_log_output(command, FALSE) && !run_program_and_log_output(command, FALSE))
2372    { strcpy(output, dev); log_msg(4, "Found it - %s", dev); return(TRUE); }
2373  else
2374    { output[0]='\0'; log_msg(4, "It's not %s",dev); return(FALSE); }
2375}
2376
2377
2378
2379
2380
2381/**
2382 * Find out what number CD is in the drive.
2383 * @param bkpinfo The backup information structure. The @c bkpinfo->media_device field is the only one used.
2384 * @return The current CD number, or -1 if it could not be found.
2385 * @note If the CD is not mounted, it will be mounted
2386 * (and remain mounted after this function returns).
2387 */
2388int what_number_cd_is_this(struct s_bkpinfo *bkpinfo)
2389{
2390  int cd_number=-1;
2391  char *mountdev;
2392  char *tmp;
2393
2394  malloc_string(mountdev);
2395  malloc_string(tmp);
2396  assert(bkpinfo!=NULL);
2397//  log_it("Asking what_number_cd_is_this");
2398  if (g_ISO_restore_mode)
2399    {
2400      sprintf(tmp, "mount | grep iso9660 | awk '{print $3;}'");
2401//      log_it("tmp = %s", tmp);
2402
2403      strcpy(mountdev, call_program_and_get_last_line_of_output(tmp));
2404      strcat(mountdev, "/archives/THIS-CD-NUMBER");
2405//      log_it("mountdev = %s", mountdev);
2406      cd_number = atoi(last_line_of_file(mountdev));
2407//      log_it("cd_number = %d", cd_number);
2408paranoid_free(mountdev);
2409paranoid_free(tmp);
2410      return(cd_number);
2411    }
2412
2413  strcpy(mountdev, bkpinfo->media_device);
2414  if (!mountdev[0])
2415    {
2416      log_it("(what_number_cd_is_this) Warning - media_device unknown. Finding out...");
2417      find_cdrom_device(bkpinfo->media_device, FALSE);
2418    }
2419  if (! is_this_device_mounted(MNT_CDROM))
2420    { mount_CDROM_here(mountdev, MNT_CDROM); }
2421  cd_number = atoi(last_line_of_file(MNT_CDROM"/archives/THIS-CD-NUMBER"));
2422//  log_it("cd_number..later.. = %d", cd_number);
2423paranoid_free(mountdev);
2424paranoid_free(tmp);
2425  return(cd_number);
2426}
2427
2428
2429
2430
2431
2432
2433
2434/**
2435 * Find out what device is mounted as root (/).
2436 * @return Root device.
2437 * @note The returned string points to static storage and will be overwritten with every call.
2438 * @bug A bit of a misnomer; it's actually finding out the root device.
2439 * The mountpoint (where it's mounted) will obviously be '/'.
2440 */
2441char *
2442where_is_root_mounted ()
2443{
2444    /*@ buffers *****************/
2445  static char tmp[MAX_STR_LEN];
2446
2447
2448#ifdef __FreeBSD__
2449  strcpy (tmp, call_program_and_get_last_line_of_output
2450          ("mount | grep \" on / \" | cut -d' ' -f1"));
2451#else
2452  strcpy (tmp, call_program_and_get_last_line_of_output
2453      ("mount | grep \" on / \" | cut -d' ' -f1 | sed s/[0-9]// | sed s/[0-9]//"));
2454  if (strstr(tmp, "/dev/cciss/")) {
2455      strcpy (tmp, call_program_and_get_last_line_of_output
2456              ("mount | grep \" on / \" | cut -d' ' -f1 | cut -dp -f1"));
2457  }
2458  if (strstr(tmp, "/dev/md"))
2459    {
2460      strcpy(tmp,
2461         call_program_and_get_last_line_of_output
2462         ("mount | grep \" on / \" | cut -d' ' -f1"));
2463    }
2464#endif
2465
2466  return (tmp);
2467}
2468
2469
2470/**
2471 * Find out which boot loader is in use.
2472 * @param which_device Device to look for the boot loader on.
2473 * @return 'L' for LILO, 'E'for ELILO, 'G' for GRUB, 'B' or 'D' for FreeBSD boot loaders, or 'U' for Unknown.
2474 * @note Under Linux, all drives are examined, not just @p which_device.
2475 */
2476#ifdef __FreeBSD__
2477char which_boot_loader (char *which_device)
2478{
2479  int count_lilos = 0;
2480  int count_grubs = 0;
2481  int count_boot0s = 0;
2482  int count_dangerouslydedicated = 0;
2483
2484  log_it ("looking at drive %s's MBR", which_device);
2485  if (does_string_exist_in_boot_block (which_device, "GRUB"))
2486      { count_grubs++; }
2487  if (does_string_exist_in_boot_block (which_device, "LILO"))
2488      { count_lilos++; }
2489  if (does_string_exist_in_boot_block (which_device, "Drive"))
2490      { count_boot0s++; }
2491  if (does_string_exist_in_first_N_blocks (which_device, "FreeBSD/i386", 17))
2492      { count_dangerouslydedicated++; }
2493  log_it ("%d grubs and %d lilos and %d elilos and %d boot0s and %d DD\n", count_grubs, count_lilos, count_elilos, count_boot0s, count_dangerouslydedicated);
2494
2495  if (count_grubs && !count_lilos)
2496    { return ('G'); }
2497  else if (count_lilos && !count_grubs)
2498    { return ('L'); }
2499 else if (count_grubs == 1 && count_lilos == 1)
2500    {
2501      log_it ("I'll bet you used to use LILO but switched to GRUB...");
2502      return ('G');
2503    }
2504  else if (count_boot0s == 1)
2505      { return ('B'); }
2506  else if (count_dangerouslydedicated)
2507      { return ('D'); }
2508  else
2509    {
2510      log_it ("Unknown boot loader");
2511      return ('U');
2512    }
2513}
2514
2515#else
2516
2517char which_boot_loader (char *which_device)
2518{
2519    /*@ buffer ******************************************************/
2520  char *list_drives_cmd;
2521  char *current_drive;
2522
2523    /*@ pointers ****************************************************/
2524  FILE *pdrives;
2525
2526    /*@ int *********************************************************/
2527  int count_lilos = 0;
2528  int count_grubs = 0;
2529
2530    /*@ end vars ****************************************************/
2531
2532  malloc_string(list_drives_cmd);
2533  malloc_string(current_drive);
2534
2535#ifdef __IA64__
2536  /* No choice for it */
2537  return ('E');
2538#endif
2539  assert(which_device!=NULL);
2540  //  sprintf (list_drives_cmd,
2541  //       "fdisk -l | grep /dev | grep cyl | tr ':' ' ' | cut -d' ' -f2");
2542
2543  sprintf (list_drives_cmd,
2544  // "parted2fdisk
2545       "fdisk -l 2>/dev/null | grep \"/dev/.*:\" | tr -s ':' ' ' | tr -s ' ' '\n' | grep /dev/; echo %s", where_is_root_mounted());
2546  log_it("list_drives_cmd = %s", list_drives_cmd);
2547
2548  if (!(pdrives = popen (list_drives_cmd, "r")))
2549    {
2550      log_OS_error ("Unable to open list of drives");
2551      paranoid_free(list_drives_cmd);
2552      paranoid_free(current_drive);
2553      return ('\0');
2554    }
2555  for (fgets (current_drive, MAX_STR_LEN, pdrives); !feof (pdrives);
2556       fgets (current_drive, MAX_STR_LEN, pdrives))
2557    {
2558      strip_spaces (current_drive);
2559      log_it ("looking at drive %s's MBR", current_drive);
2560      if (does_string_exist_in_boot_block (current_drive, "GRUB"))
2561    {
2562      count_grubs++;
2563      strcpy (which_device, current_drive);
2564      break;
2565    }
2566      if (does_string_exist_in_boot_block (current_drive, "LILO"))
2567    {
2568      count_lilos++;
2569      strcpy (which_device, current_drive);
2570      break;
2571    }
2572    }
2573  if (pclose (pdrives)) { log_OS_error("Cannot pclose pdrives"); }
2574  log_it ("%d grubs and %d lilos\n", count_grubs, count_lilos);
2575  paranoid_free(list_drives_cmd);
2576  paranoid_free(current_drive);
2577  if (count_grubs && !count_lilos)
2578    {
2579      return ('G');
2580    }
2581  else if (count_lilos && !count_grubs)
2582    {
2583      return ('L');
2584    }
2585  else if (count_grubs == 1 && count_lilos == 1)
2586    {
2587      log_it ("I'll bet you used to use LILO but switched to GRUB...");
2588      return ('G');
2589    }
2590  else
2591    {
2592      log_it ("Unknown boot loader");
2593      return ('U');
2594    }
2595}
2596#endif
2597
2598
2599
2600
2601/**
2602 * Write zeroes over the first 16K of @p device.
2603 * @param device The device to zero.
2604 * @return 0 for success, 1 for failure.
2605 */
2606int
2607zero_out_a_device (char *device)
2608{
2609  FILE *fout;
2610  int i;
2611
2612  assert_string_is_neither_NULL_nor_zerolength(device);
2613
2614  log_it ("Zeroing drive %s", device);
2615  if (!(fout=fopen (device, "w")))
2616    {
2617      log_OS_error ("Unable to open/write to device");
2618      return (1);
2619    }
2620  for (i = 0; i < 16384; i++)
2621    {
2622      fputc ('\0', fout);
2623    }
2624  paranoid_fclose(fout);
2625  log_it ("Device successfully zeroed.");
2626  return (0);
2627}
2628
2629/**
2630 * Return the device pointed to by @p incoming.
2631 * @param incoming The device to resolve symlinks for.
2632 * @return The path to the real device file.
2633 * @note The returned string points to static storage that will be overwritten with each call.
2634 * @bug Won't work with file v4.0; needs to be written in C.
2635 */
2636char *resolve_softlinks_to_get_to_actual_device_file(char*incoming)
2637{
2638  static char output[MAX_STR_LEN];
2639  char *command;
2640  char *curr_fname;
2641  char *scratch;
2642  char *tmp;
2643  char *p;
2644   
2645  struct stat statbuf; 
2646  command = malloc(1000);
2647  malloc_string(tmp);
2648  malloc_string(scratch);
2649  malloc_string(curr_fname);
2650  if (!does_file_exist(incoming))
2651    {
2652      log_it("resolve_softlinks_to_get_to_actual_device_file --- device not found");
2653      strcpy(output, incoming);
2654    }
2655  else
2656    {
2657      strcpy(curr_fname, incoming);
2658      lstat(curr_fname, &statbuf);
2659      while(S_ISLNK(statbuf.st_mode))
2660        {
2661      log_msg(1, "curr_fname = %s", curr_fname);
2662      sprintf(command, "file %s", curr_fname);
2663      strcpy(tmp, call_program_and_get_last_line_of_output(command));
2664      for(p=tmp + strlen(tmp); p != tmp && *p != '`' && *p != ' '; p--);
2665      p++;
2666      strcpy(scratch, p);
2667      for(p=scratch; *p != '\0' && *p != '\''; p++);
2668      *p = '\0';
2669      log_msg(0, "curr_fname %s --> '%s' --> %s", curr_fname, tmp, scratch);
2670      if (scratch[0] == '/')
2671        {
2672          strcpy(curr_fname, scratch); // copy whole thing because it's an absolute softlink
2673        }
2674      else
2675        { // copy over the basename cos it's a relative softlink
2676          p = curr_fname + strlen(curr_fname);
2677          while(p!=curr_fname && *p != '/') { p--;}
2678          if (*p == '/') { p++; }
2679          strcpy(p, scratch);
2680        }
2681          lstat(curr_fname, &statbuf);
2682    }
2683      strcpy(output, curr_fname);
2684      log_it("resolved %s to %s", incoming, output);
2685    }
2686  paranoid_free(command);
2687  paranoid_free(curr_fname);
2688  paranoid_free(tmp);
2689  return(output);
2690}
2691
2692/* @} - end of deviceGroup */
2693
2694
2695/**
2696 * Return the type of partition format (GPT or MBR)
2697 */
2698char *which_partition_format(const char *drive)
2699{
2700  static char output[4];
2701  char *tmp;
2702  char *command;
2703  char *fdisk;
2704  struct stat buf;
2705   
2706  malloc_string(tmp);
2707  malloc_string(command);
2708  malloc_string(fdisk);
2709  log_msg(0, "Looking for partition table format type");
2710// BERLIOS: Do that temporarily: we need to put back parted2fdisk everywhere
2711#ifdef __IA64__
2712  sprintf(fdisk, "/usr/local/bin/fdisk");
2713  if (stat(fdisk, &buf) != 0) {
2714#endif
2715      sprintf(fdisk, "/sbin/fdisk");
2716#ifdef __IA64__
2717  }
2718#endif
2719  log_msg(1, "Using %s",fdisk);
2720  sprintf(command, "%s -l %s | grep 'EFI GPT'", fdisk, drive);
2721  strcpy(tmp, call_program_and_get_last_line_of_output(command));
2722  if (strstr(tmp,"GPT") == NULL) {
2723      strcpy(output,"MBR");
2724  } else {
2725      strcpy(output,"GPT");
2726  }
2727  log_msg(0, "Found %s partition table format type",output);
2728  paranoid_free(command);
2729  paranoid_free(tmp);
2730  paranoid_free(fdisk);
2731  return(output);
2732}
2733
2734/* @} - end of deviceGroup */
2735
Note: See TracBrowser for help on using the repository browser.