/* libmondo-devices.c Subroutines for handling devices $Id: libmondo-devices.c 3013 2012-05-30 07:16:16Z bruno $ */ /** * @file * Functions to handle interactions with backup devices. */ #include "my-stuff.h" #include "mr_mem.h" #include "mr_str.h" #include "mondostructures.h" #include "libmondo-files-EXT.h" #include "libmondo-devices.h" #include "lib-common-externs.h" #include "libmondo-string-EXT.h" #include "libmondo-tools-EXT.h" #include "libmondo-gui-EXT.h" #include "libmondo-fork-EXT.h" #include "libmondo-stream-EXT.h" #include #ifdef __FreeBSD__ #define DKTYPENAMES #define FSTYPENAMES #include #include #elif linux #define u64 unsigned long long #include /* for BLKGETSIZE64 */ #include #endif /*@unused@*/ //static char cvsid[] = "$Id: libmondo-devices.c 3013 2012-05-30 07:16:16Z bruno $"; // extern char *which_compression_type(); /* Do we use extended attributes and acl ? */ extern char *g_getfacl; extern char *g_getfattr; extern int g_current_media_number; extern double g_kernel_version; extern bool g_ISO_restore_mode; extern char *g_selfmounted_isodir; extern char *MONDO_LOGFILE; extern void setup_tmpdir(char *path); static char g_cdrw_drive_is_here[MAX_STR_LEN / 4] = ""; static char g_cdrom_drive_is_here[MAX_STR_LEN / 4] = ""; static char g_dvd_drive_is_here[MAX_STR_LEN / 4] = ""; /** * ????? @bug ????? * @ingroup globalGroup */ bool g_restoring_live_from_cd = FALSE; bool g_restoring_live_from_netfs = FALSE; extern t_bkptype g_backup_media_type; // set by main() /* Reference to global bkpinfo */ extern struct s_bkpinfo *bkpinfo; /* Stuff that handles the -I and -E option when a whole disk DSF is used */ typedef struct mounted_fs_struct { char device[MAX_STR_LEN]; /* The name of the device */ char mount_point[MAX_STR_LEN]; /* The devices mount point */ unsigned char check; /* 1 == included on DSF */ struct mounted_fs_struct *next; } MOUNTED_FS_STRUCT; static MOUNTED_FS_STRUCT *DSF_Head = NULL; /* Points to the first entry of mounted_fs_struct list */ static MOUNTED_FS_STRUCT *DSF_Tail = NULL; /* Points to the last entry of mounted_fs_struct list */ void set_g_cdrom_and_g_dvd_to_bkpinfo_value() { strcpy(g_cdrom_drive_is_here, bkpinfo->media_device); // just in case strcpy(g_dvd_drive_is_here, bkpinfo->media_device); // just in case } /** * Retract all CD trays and wait for autorun to complete. * @ingroup deviceGroup */ void retract_CD_tray_and_defeat_autorun(void) { // log_it("rctada: Retracting all CD trays", __LINE__); if (!bkpinfo->please_dont_eject) { if (strlen(g_cdrom_drive_is_here) > 0) { inject_device(g_cdrom_drive_is_here); } if (strlen(g_dvd_drive_is_here) > 0) { inject_device(g_dvd_drive_is_here); } if (strlen(g_cdrw_drive_is_here) > 0) { inject_device(g_cdrw_drive_is_here); } } // log_it("rctada: killing autorun"); // run_program_and_log_output("killall autorun", TRUE); if (!run_program_and_log_output("ps | grep autorun | grep -v grep", 5)) { log_it("autorun detected; sleeping for 2 seconds"); sleep(2); } log_it("rctada: Unmounting all CD drives", __LINE__); run_program_and_log_output("umount /dev/cdr* /dev/dvd*", 5); } /** * Determine whether we're booted off a ramdisk. * @return @c TRUE (we are) or @c FALSE (we aren't). * @ingroup utilityGroup */ bool am_I_in_disaster_recovery_mode(void) { char *tmp = NULL; char *comment; bool is_this_a_ramdisk = FALSE; malloc_string(comment); mr_asprintf(&tmp, "%s", where_is_root_mounted()); sprintf(comment, "root is mounted at %s\n", tmp); log_msg(0, comment); 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); #ifdef __FreeBSD__ if (strstr(tmp, "/dev/md")) { is_this_a_ramdisk = TRUE; } #else if (!strncmp(tmp, "/dev/ram", 8) || (!strncmp(tmp, "/dev/rd", 7) && !strcmp(tmp, "/dev/rd/") && strncmp(tmp, "/dev/rd/cd", 10)) || strstr(tmp, "rootfs") || !strcmp(tmp, "/dev/root")) { is_this_a_ramdisk = TRUE; } else { is_this_a_ramdisk = FALSE; } #endif mr_free(tmp); if (is_this_a_ramdisk) { if (!does_file_exist("/THIS-IS-A-RAMDISK")) { log_to_screen ("Using /dev/root is stupid of you but I'll forgive you."); is_this_a_ramdisk = FALSE; } } if (does_file_exist("/THIS-IS-A-RAMDISK")) { is_this_a_ramdisk = TRUE; } paranoid_free(comment); log_msg(1, "Is this a ramdisk? result = %d", is_this_a_ramdisk); return (is_this_a_ramdisk); } /** * Turn @c bkpinfo->backup_media_type into a human-readable string. * @return The human readable string (e.g. @c cdr becomes "cdr"). * @note The returned string points to static storage that will be overwritten with each call. * @ingroup stringGroup */ static char *bkptype_to_string(t_bkptype bt) { static char output[MAX_STR_LEN / 4]; switch (bt) { case none: strcpy(output, "none"); break; case iso: strcpy(output, "iso"); break; case cdr: strcpy(output, "cdr"); break; case cdrw: strcpy(output, "cdrw"); break; case cdstream: strcpy(output, "cdstream"); break; case netfs: strcpy(output, "netfs"); break; case tape: strcpy(output, "tape"); break; case udev: strcpy(output, "udev"); break; case usb: strcpy(output, "usb"); break; default: strcpy(output, "default"); } return (output); } /** * @addtogroup deviceGroup * @{ */ /** * Eject the tray of the specified CD device. * @param dev The device to eject. * @return the return value of the @c eject command. (0=success, nonzero=failure) */ int eject_device(char *dev) { char *command; int res1 = 0, res2 = 0; malloc_string(command); if (IS_THIS_A_STREAMING_BACKUP(g_backup_media_type) && g_backup_media_type != udev) { sprintf(command, "mt -f %s offline", dev); res1 = run_program_and_log_output(command, 1); } else { res1 = 0; } #ifdef __FreeBSD__ if (strstr(dev, "acd")) { sprintf(command, "cdcontrol -f %s eject", dev); } else { sprintf(command, "camcontrol eject `echo %s | sed 's|/dev/||'`", dev); } #else sprintf(command, "eject %s", dev); #endif log_msg(3, "Ejecting %s", dev); res2 = run_program_and_log_output(command, 1); paranoid_free(command); if (res1 && res2) { return (1); } else { return (0); } } /** * Load (inject) the tray of the specified CD device. * @param dev The device to load/inject. * @return 0 for success, nonzero for failure. */ int inject_device(char *dev) { char *command; int i; malloc_string(command); #ifdef __FreeBSD__ if (strstr(dev, "acd")) { sprintf(command, "cdcontrol -f %s close", dev); } else { sprintf(command, "camcontrol load `echo %s | sed 's|/dev/||'`", dev); } #else sprintf(command, "eject -t %s", dev); #endif i = run_program_and_log_output(command, FALSE); paranoid_free(command); return (i); } /** * Determine whether the specified @p device (really, you can use any file) * exists. * @return TRUE if it exists, FALSE if it doesn't. */ bool does_device_exist(char *device) { /*@ buffers *********************************************************** */ char *tmp; bool ret; malloc_string(tmp); assert_string_is_neither_NULL_nor_zerolength(device); sprintf(tmp, "ls %s > /dev/null 2> /dev/null", device); if (system(tmp)) { ret = FALSE; } else { ret = TRUE; } paranoid_free(tmp); return (ret); } /** * Determine whether a non-Microsoft partition exists on any connected hard drive. * @return TRUE (there's a Linux/FreeBSD partition) or FALSE (Microsoft has taken over yet another innocent PC). */ bool does_nonMS_partition_exist(void) { #if __FreeBSD__ return !system ("for drive in /dev/ad? /dev/da?; do fdisk $drive | grep -q FreeBSD && exit 0; done; false"); #else return !system ("parted2fdisk -l 2>/dev/null | grep '^/dev/' | grep -Eqv '(MS|DOS|FAT|NTFS)'"); #endif } /** * Determine whether the specified @p partno exists on the specified @p drive. * @param drive The drive to search for the partition in. * @param partno The partition number to look for. * @return 0 if it exists, nonzero otherwise. */ int does_partition_exist(const char *drive, int partno) { /*@ buffers **************************************************** */ char *program; char *incoming; char *searchstr = NULL; char *tmp; /*@ ints ******************************************************* */ int res = 0; /*@ pointers *************************************************** */ FILE *fin; /*@ end vars *************************************************** */ assert_string_is_neither_NULL_nor_zerolength(drive); assert(partno >= 0 && partno < 999); malloc_string(program); malloc_string(incoming); malloc_string(searchstr); malloc_string(tmp); #ifdef __FreeBSD__ // We assume here that this is running from mondorestore. (It is.) sprintf(program, "ls %s %s >/dev/null 2>&1", drive, build_partition_name(tmp, drive, partno)); return system(program); #else tmp[0] = '\0'; #endif sprintf(program, "parted2fdisk -l %s 2> /dev/null", drive); fin = popen(program, "r"); if (!fin) { log_it("program=%s", program); log_OS_error("Cannot popen-in program"); return (0); } (void) build_partition_name(searchstr, drive, partno); strcat(searchstr, " "); for (res = 0; !res && fgets(incoming, MAX_STR_LEN - 1, fin);) { if (strstr(incoming, searchstr)) { res = 1; } } if (pclose(fin)) { log_OS_error("Cannot pclose fin"); } paranoid_free(program); paranoid_free(incoming); paranoid_free(searchstr); paranoid_free(tmp); return (res); } /** * Determine whether given NULL-terminated @p str exists in the MBR of @p dev. * @param dev The device to look in. * @param str The string to look for. * @return TRUE if it exists, FALSE if it doesn't. */ bool does_string_exist_in_boot_block(char *dev, char *str) { /*@ buffers **************************************************** */ char *command; /*@ end vars *************************************************** */ int i; assert_string_is_neither_NULL_nor_zerolength(dev); assert_string_is_neither_NULL_nor_zerolength(str); malloc_string(command); sprintf(command, "dd if=%s bs=446 count=1 2> /dev/null | strings | grep \"%s\" > /dev/null 2> /dev/null", dev, str); i = system(command); paranoid_free(command); if (i) { return (FALSE); } else { return (TRUE); } } /** * Determine whether specified @p str exists in the first @p n sectors of * @p dev. * @param dev The device to look in. * @param str The string to look for. * @param n The number of 512-byte sectors to search. */ bool does_string_exist_in_first_N_blocks(char *dev, char *str, int n) { /*@ buffers **************************************************** */ char *command; /*@ end vars *************************************************** */ int i; malloc_string(command); sprintf(command, "dd if=%s bs=512 count=%i 2> /dev/null | strings | grep \"%s\" > /dev/null 2> /dev/null", dev, n, str); i = system(command); paranoid_free(command); if (i) { return (FALSE); } else { return (TRUE); } } /** * Try to mount CD-ROM at @p mountpoint. If the CD-ROM is not found or has * not been specified, call find_cdrom_device() to find it. * @param bkpinfo The backup information structure. The only field used is @c bkpinfo->media_device. * @param mountpoint Where to mount the CD-ROM. * @return 0 for success, nonzero for failure. * @see mount_CDROM_here */ int find_and_mount_actual_cd(char *mountpoint) { /*@ buffers ***************************************************** */ /*@ int's ****************************************************** */ int res; char *dev; /*@ end vars **************************************************** */ malloc_string(dev); assert(bkpinfo != NULL); assert_string_is_neither_NULL_nor_zerolength(mountpoint); if (g_backup_media_type == dvd) { strcpy(dev, g_dvd_drive_is_here); if (!dev[0]) { find_dvd_device(dev, FALSE); } } else { strcpy(dev, g_cdrom_drive_is_here); if (!dev[0]) { find_cdrom_device(dev, FALSE); } } if (bkpinfo->backup_media_type != iso) { retract_CD_tray_and_defeat_autorun(); } if (!dev[0] || (res = mount_CDROM_here(dev, mountpoint))) { if (!popup_and_get_string ("CD-ROM device", "Please enter your CD-ROM's /dev device", dev, MAX_STR_LEN / 4)) { res = 1; } else { res = mount_CDROM_here(dev, mountpoint); } } if (res) { log_msg(1, "mount failed"); } else { log_msg(1, "mount succeeded with %s", dev); } paranoid_free(dev); return (res); } /** * Locate a CD-R/W writer's SCSI node. * @param cdrw_device SCSI node will be placed here. * @return 0 for success, nonzero for failure. */ int find_cdrw_device(char *cdrw_device) { /*@ buffers ************************ */ char *comment; char *tmp = NULL; char *cdr_exe = NULL; char *command; malloc_string(comment); malloc_string(command); if (g_cdrw_drive_is_here[0]) { strcpy(cdrw_device, g_cdrw_drive_is_here); log_msg(3, "Been there, done that. Returning %s", cdrw_device); paranoid_free(comment); paranoid_free(command); return (0); } if (g_backup_media_type == dvd) { log_msg(1, "This is dumb. You're calling find_cdrw_device() but you're backing up to DVD. WTF?"); paranoid_free(comment); paranoid_free(command); return (1); } run_program_and_log_output("insmod ide-scsi", -1); if (find_home_of_exe("cdrecord")) { mr_asprintf(&cdr_exe, "cdrecord"); } else { mr_asprintf(&cdr_exe, "dvdrecord"); } if (find_home_of_exe(cdr_exe)) { sprintf(command, "%s -scanbus 2> /dev/null | tr -s '\t' ' ' | grep \"[0-9]*,[0-9]*,[0-9]*\" | grep -v \"[0-9]*) \\*\" | grep -E '[D|C][V|D]' | cut -d' ' -f2 | head -n1", cdr_exe); mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output(command)); } if ((tmp == NULL) || (strlen(tmp) < 2)) { paranoid_free(comment); mr_free(tmp); mr_free(cdr_exe); paranoid_free(command); return 1; } else { strcpy(cdrw_device, tmp); sprintf(comment, "Found CDRW device - %s", cdrw_device); log_it(comment); strcpy(g_cdrw_drive_is_here, cdrw_device); paranoid_free(comment); mr_free(tmp); mr_free(cdr_exe); paranoid_free(command); return (0); } } /** * Attempt to locate a CD-ROM device's /dev entry. * Several different methods may be used to find the device, including * calling @c cdrecord, searching @c dmesg, and trial-and-error. * @param output Where to put the located /dev entry. * @param try_to_mount Whether to mount the CD as part of the test; if mount * fails then return failure. * @return 0 for success, nonzero for failure. */ int find_cdrom_device(char *output, bool try_to_mount) { /*@ pointers **************************************************** */ FILE *fin; char *p; char *q; char *r; int retval = 0; /*@ bool's ****************************************************** */ bool found_it = FALSE; /*@ buffers ***************************************************** */ char *tmp; char *tmp1 = NULL; char *cdr_exe = NULL; char *phrase_one; char *phrase_two; char *command; char *dvd_last_resort; char *mountpoint; static char the_last_place_i_found_it[MAX_STR_LEN] = ""; /*@ intialize *************************************************** */ malloc_string(tmp); malloc_string(phrase_one); malloc_string(phrase_two); malloc_string(command); malloc_string(dvd_last_resort); malloc_string(mountpoint); output[0] = '\0'; phrase_one[0] = '\0'; phrase_two[0] = '\0'; dvd_last_resort[0] = '\0'; /*@ end vars **************************************************** */ if (g_cdrom_drive_is_here[0] && !isdigit(g_cdrom_drive_is_here[0])) { strcpy(output, g_cdrom_drive_is_here); log_msg(3, "Been there, done that. Returning %s", output); retval = 0; goto end_of_find_cdrom_device; } if (the_last_place_i_found_it[0] != '\0' && !try_to_mount) { strcpy(output, the_last_place_i_found_it); log_msg(3, "find_cdrom_device() --- returning last found location - '%s'", output); retval = 0; goto end_of_find_cdrom_device; } sprintf(mountpoint, "%s/cd.mnt", bkpinfo->tmpdir); make_hole_for_dir(mountpoint); if (find_home_of_exe("cdrecord")) { mr_asprintf(&cdr_exe, "cdrecord"); } else { mr_asprintf(&cdr_exe, "dvdrecord"); } tmp[0] = '\0'; if (!find_home_of_exe(cdr_exe)) { strcpy(output, "/dev/cdrom"); log_msg(4, "Can't find cdrecord; assuming %s", output); if (!does_device_exist(output)) { log_msg(4, "That didn't work. Sorry."); retval = 1; goto end_of_find_cdrom_device; } else { retval = 0; goto end_of_find_cdrom_device; } } sprintf(command, "%s -scanbus 2> /dev/null", cdr_exe); fin = popen(command, "r"); if (!fin) { log_msg(4, "command=%s", command); log_OS_error("Cannot popen command"); mr_free(cdr_exe); return (1); } for ((void)fgets(tmp, MAX_STR_LEN, fin); !feof(fin); (void)fgets(tmp, MAX_STR_LEN, fin)) { p = strchr(tmp, '\''); if (p) { q = strchr(++p, '\''); if (q) { for (r = q; *(r - 1) == ' '; r--); *r = '\0'; strcpy(phrase_one, p); p = strchr(++q, '\''); if (p) { q = strchr(++p, '\''); if (q) { while (*(q - 1) == ' ') { q--; } *q = '\0'; strcpy(phrase_two, p); } } } } } paranoid_pclose(fin); #ifndef __FreeBSD__ if (strlen(phrase_two) == 0) { log_msg(4, "Not running phase two. String is empty."); } else { sprintf(command, "dmesg | grep \"%s\" 2> /dev/null", phrase_two); fin = popen(command, "r"); if (!fin) { log_msg(4, "Cannot run 2nd command - non-fatal, fortunately"); } else { for ((void)fgets(tmp, MAX_STR_LEN, fin); !feof(fin); (void)fgets(tmp, MAX_STR_LEN, fin)) { log_msg(5, "--> '%s'", tmp); if (tmp[0] != ' ' && tmp[1] != ' ') { p = strchr(tmp, ':'); if (p) { *p = '\0'; if (strstr(tmp, "DVD")) { sprintf(dvd_last_resort, "/dev/%s", tmp); log_msg(4, "Ignoring '%s' because it's a DVD drive", tmp); } else { sprintf(output, "/dev/%s", tmp); found_it = TRUE; } } } } paranoid_pclose(fin); } } #endif #ifdef __FreeBSD__ if (!found_it) { log_msg(4, "OK, approach 2"); if (!(found_it = set_dev_to_this_if_rx_OK(output, "/dev/cdrom"))) { if (! (found_it = set_dev_to_this_if_rx_OK(output, "/dev/cdrom1"))) { if (! (found_it = set_dev_to_this_if_rx_OK(output, "/dev/dvd"))) { if (! (found_it = set_dev_to_this_if_rx_OK(output, "/dev/acd0"))) { if (! (found_it = set_dev_to_this_if_rx_OK(output, "/dev/cd01"))) { if (! (found_it = set_dev_to_this_if_rx_OK(output, "/dev/acd1"))) { if (! (found_it = set_dev_to_this_if_rx_OK(output, "/dev/cd1"))) { retval = 1; goto end_of_find_cdrom_device; } } } } } } } } #else if (!found_it && strlen(dvd_last_resort) > 0) { log_msg(4, "Well, I'll use the DVD - %s - as a last resort", dvd_last_resort); strcpy(output, dvd_last_resort); found_it = TRUE; } if (found_it) { sprintf(tmp, "grep \"%s=ide-scsi\" /proc/cmdline &> /dev/null", strrchr(output, '/') + 1); if (system(tmp) == 0) { log_msg(4, "%s is not right. It's being SCSI-emulated. Continuing.", output); found_it = FALSE; output[0] = '\0'; } } if (found_it) { log_msg(4, "(find_cdrom_device) --> '%s'", output); if (!does_device_exist(output)) { found_it = FALSE; log_msg(4, "OK, I was wrong, I haven't found it... yet."); } } if (!found_it) { log_msg(4, "OK, approach 2"); if (!(found_it = set_dev_to_this_if_rx_OK(output, "/dev/scd0"))) { if (!(found_it = set_dev_to_this_if_rx_OK(output, "/dev/sr0"))) { if (! (found_it = set_dev_to_this_if_rx_OK(output, "/dev/cdrom"))) { if (! (found_it = set_dev_to_this_if_rx_OK(output, "/dev/cdrom0"))) { if (! (found_it = set_dev_to_this_if_rx_OK(output, "/dev/cdrom1"))) { if (! (found_it = set_dev_to_this_if_rx_OK(output, "/dev/sr1"))) { if (! (found_it = set_dev_to_this_if_rx_OK(output, "/dev/dvd"))) { if (! (found_it = set_dev_to_this_if_rx_OK(output, g_cdrw_drive_is_here))) { retval = 1; goto end_of_find_cdrom_device; } } } } } } } } } #endif if (found_it && try_to_mount) { if (mount_CDROM_here(output, mountpoint)) { log_msg(4, "[Cardigans] I've changed my mind"); found_it = FALSE; } else { sprintf(tmp, "%s/archives", mountpoint); if (!does_file_exist(tmp)) { log_msg(4, "[Cardigans] I'll take it back"); found_it = FALSE; } else { sprintf(command, "umount %s", output); paranoid_system(command); log_msg(4, "I'm confident the Mondo CD is in %s", output); } } } unlink(mountpoint); if (found_it) { if (!does_file_exist(output)) { log_msg(3, "I still haven't found it."); return (1); } log_msg(3, "(find_cdrom_device) --> '%s'", output); strcpy(the_last_place_i_found_it, output); strcpy(g_cdrom_drive_is_here, output); retval = 0; goto end_of_find_cdrom_device; } sprintf(command, "%s -scanbus | grep \"[0-9],[0-9],[0-9]\" | grep -E \"[D|C][V|D]\" | grep -n \"\" | grep \"%s\" | cut -d':' -f2", cdr_exe, g_cdrw_drive_is_here); log_msg(1, "command=%s", command); mr_asprintf(&tmp1, "%s", call_program_and_get_last_line_of_output(command)); if (strlen(tmp1) > 0) { strcpy(output, tmp1); log_msg(4, "Finally found it at %s", output); retval = 0; } else { log_msg(4, "Still couldn't find it."); retval = 1; } mr_free(tmp1); end_of_find_cdrom_device: paranoid_free(tmp); mr_free(cdr_exe); paranoid_free(phrase_one); paranoid_free(phrase_two); paranoid_free(command); paranoid_free(dvd_last_resort); paranoid_free(mountpoint); return (retval); } int find_dvd_device(char *output, bool try_to_mount) { char *command; char *tmp; int retval = 0, devno = -1; malloc_string(command); malloc_string(tmp); if (g_dvd_drive_is_here[0]) { strcpy(output, g_dvd_drive_is_here); log_msg(3, "Been there, done that. Returning %s", output); return (0); } sprintf(tmp, "%s", call_program_and_get_last_line_of_output ("dvdrecord -scanbus 2> /dev/null | grep \)\ \' | grep -n '' | grep -E '[D|C][V|D]' | cut -d':' -f1") ); log_msg(5, "tmp = '%s'", tmp); if (!tmp[0]) sprintf(tmp, "%s", call_program_and_get_last_line_of_output ("cdrecord -scanbus 2> /dev/null | grep \)\ \' | grep -n '' | grep -E '[D|C][V|D]' | cut -d':' -f1") ); if (tmp[0]) { devno = atoi(tmp) - 1; } if (devno >= 0) { retval = 0; sprintf(output, "/dev/scd%d", devno); strcpy(g_dvd_drive_is_here, output); log_msg(2, "I think DVD is at %s", output); } else { log_msg(2, "I cannot find DVD"); retval = 1; } if (try_to_mount) { log_msg(1, "Ignoring the fact that try_to_mount==TRUE"); } return (retval); } #include /** * Find the size of the specified @p drive, in megabytes. Uses @c ioctl calls * and @c dmesg. * @param drive The device to find the size of. * @return size in megabytes. */ long get_phys_size_of_drive(char *drive) { int fd; #if linux unsigned long long s = 0; int fileid, cylinders = 0, cylindersleft = 0; int cylindersize = 0; int gotgeo = 0; struct hd_geometry hdgeo; #elif __FreeBSD__ off_t s; #endif long outvalA = -1; long outvalB = -1; long outvalC = -1; if ((fd = open(drive, O_RDONLY)) != -1) { if (ioctl(fd, #if linux #ifdef BLKGETSIZE64 BLKGETSIZE64, #else BLKGETSIZE, #endif #elif __FreeBSD__ DIOCGMEDIASIZE, #endif &s) != -1) { close(fd); // s>>11 works for older disks but not for newer ones outvalB = #if linux #ifdef BLKGETSIZE64 s >> 20 #else s >> 11 #endif #else s >> 20 #endif ; } } if (outvalB <= 0) { log_msg(1, "Error getting size of %s: %s", drive, strerror(errno)); #if linux fileid = open(drive, O_RDONLY); if (fileid != -1) { if (ioctl(fileid, HDIO_GETGEO, &hdgeo) != -1) { if (hdgeo.cylinders && hdgeo.heads && hdgeo.sectors) { cylindersleft = cylinders = hdgeo.cylinders; cylindersize = hdgeo.heads * hdgeo.sectors / 2; outvalA = cylindersize * cylinders / 1024; log_msg(2, "Got Harddisk geometry, C:%d, H:%d, S:%d", hdgeo.cylinders, hdgeo.heads, hdgeo.sectors); gotgeo = 1; } else { log_msg(1, "Harddisk geometry wrong"); } } else { log_msg(1, "Error in ioctl() getting new hard disk geometry (%s), resizing in unsafe mode", strerror(errno)); } close(fileid); } else { log_msg(1, "Failed to open %s for reading: %s", drive, strerror(errno)); } if (!gotgeo) { log_msg(1, "Failed to get harddisk geometry, using old mode"); } #endif } // OLDER DISKS will give ridiculously low value for outvalB (so outvalA is returned) :) // NEWER DISKS will give sane value for outvalB (close to outvalA, in other words) :) outvalC = (outvalA > outvalB) ? outvalA : outvalB; // log_msg (5, "drive = %s, error = %s", drive, strerror (errno)); // fatal_error ("GPSOD: Unable to get size of drive"); log_msg(1, "%s --> %ld or %ld --> %ld", drive, outvalA, outvalB, outvalC); return (outvalC); } /** * Determine whether @p format is supported by the kernel. Uses /proc/filesystems * under Linux and @c lsvfs under FreeBSD. * @param format The format to test. * @return TRUE if the format is supported, FALSE if not. */ bool is_this_a_valid_disk_format(char *format) { char *good_formats = NULL; char *command; char *format_sz; FILE *pin; int retval; malloc_string(good_formats); malloc_string(command); malloc_string(format_sz); assert_string_is_neither_NULL_nor_zerolength(format); sprintf(format_sz, "%s ", format); #ifdef __FreeBSD__ sprintf(command, "lsvfs | tr -s '\t' ' ' | grep -v Filesys | grep -v -- -- | cut -d' ' -f1 | tr -s '\n' ' '"); #else sprintf(command, "grep -v nodev /proc/filesystems | tr -s '\t' ' ' | cut -d' ' -f2 | tr -s '\n' ' '"); #endif pin = popen(command, "r"); if (!pin) { log_OS_error("Unable to read good formats"); retval = 0; } else { strcpy(good_formats, " "); (void) fgets(good_formats + 1, MAX_STR_LEN - 1, pin); if (pclose(pin)) { log_OS_error("Cannot pclose good formats"); } strip_spaces(good_formats); strcat(good_formats, " swap lvm raid ntfs-3g ntfs 7 "); // " ntfs 7 " -- um, cheating much? :) if (strstr(good_formats, format_sz)) { retval = 1; } else { retval = 0; } } paranoid_free(good_formats); paranoid_free(command); paranoid_free(format_sz); return (retval); } /** @def SWAPLIST_COMMAND The command to list the swap files/partitions in use. */ /** * Determine whether @p device_raw is currently mounted. * @param device_raw The device to check. * @return TRUE if it's mounted, FALSE if not. */ bool is_this_device_mounted(char *device_raw) { /*@ pointers **************************************************** */ FILE *fin; /*@ buffers ***************************************************** */ char *incoming; char *device_with_tab = NULL; char *device_with_space = NULL; char *tmp = NULL; bool retval = FALSE; #ifdef __FreeBSD__ #define SWAPLIST_COMMAND "swapinfo" #else #define SWAPLIST_COMMAND "cat /proc/swaps" #endif /*@ end vars **************************************************** */ malloc_string(incoming); assert(device_raw != NULL); // assert_string_is_neither_NULL_nor_zerolength(device_raw); if (device_raw[0] != '/' && !strstr(device_raw, ":/")) { log_msg(1, "%s needs to have a '/' prefixed - I'll do it", device_raw); mr_asprintf(&tmp, "/%s", device_raw); } else { mr_asprintf(&tmp, "%s", device_raw); } log_msg(1, "Is %s mounted?", tmp); if (!strcmp(tmp, "/proc") || !strcmp(tmp, "proc")) { log_msg(1, "I don't know how the heck /proc made it into the mountlist. I'll ignore it."); mr_free(tmp); return(FALSE); } mr_asprintf(&device_with_tab, "%s\t", tmp); mr_asprintf(&device_with_space, "%s ", tmp); mr_free(tmp); if (!(fin = popen("mount", "r"))) { log_OS_error("Cannot popen 'mount'"); return(FALSE); } for ((void)fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin); (void)fgets(incoming, MAX_STR_LEN - 1, fin)) { if (strstr(incoming, device_with_space) //> incoming || strstr(incoming, device_with_tab)) // > incoming) { paranoid_pclose(fin); paranoid_free(incoming); return(TRUE); } } mr_free(device_with_tab); paranoid_pclose(fin); mr_asprintf(&tmp, "%s | grep -E \"^%s\" > /dev/null 2> /dev/null", SWAPLIST_COMMAND, device_with_space); mr_free(device_with_space); log_msg(4, "tmp (command) = '%s'", tmp); if (!system(tmp)) { retval = TRUE; } mr_free(tmp); paranoid_free(incoming); return(retval); } #ifdef __FreeBSD__ // CODE IS FREEBSD-SPECIFIC /** * Create a loopback device for specified @p fname. * @param fname The file to associate with a device. * @return /dev entry for the device, or NULL if it couldn't be allocated. */ char *make_vn(char *fname) { char *device = (char *) malloc(MAX_STR_LEN); char *mddevice = (char *) malloc(32); char command[MAX_STR_LEN]; int vndev = 2; if (atoi (call_program_and_get_last_line_of_output ("/sbin/sysctl -n kern.osreldate")) < 500000) { do { sprintf(mddevice, "vn%ic", vndev++); sprintf(command, "vnconfig %s %s", mddevice, fname); if (vndev > 10) { return NULL; } } while (system(command)); } else { sprintf(command, "mdconfig -a -t vnode -f %s", fname); mddevice = call_program_and_get_last_line_of_output(command); if (!strstr(mddevice, "md")) { return NULL; } } sprintf(device, "/dev/%s", mddevice); return device; } // CODE IS FREEBSD-SPECIFIC /** * Deallocate specified @p dname. * This should be called when you are done with the device created by make_vn(), * so the system does not run out of @c vn devices. * @param dname The device to deallocate. * @return 0 for success, nonzero for failure. */ int kick_vn(char *dname) { char command[MAX_STR_LEN]; if (strncmp(dname, "/dev/", 5) == 0) { dname += 5; } if (atoi (call_program_and_get_last_line_of_output ("/sbin/sysctl -n kern.osreldate")) < 500000) { sprintf(command, "vnconfig -d %s", dname); return system(command); } else { sprintf(command, "mdconfig -d -u %s", dname); return system(command); } /*NOTREACHED*/ return 255; } #endif /** * Mount the CD-ROM at @p mountpoint. * @param device The device (or file if g_ISO_restore_mode) to mount. * @param mountpoint The place to mount it. * @return 0 for success, nonzero for failure. */ int mount_USB_here(char *device, char *mountpoint) { /*@ buffer ****************************************************** */ char *command; int retval; malloc_string(command); assert_string_is_neither_NULL_nor_zerolength(device); assert_string_is_neither_NULL_nor_zerolength(mountpoint); make_hole_for_dir(mountpoint); if (isdigit(device[0])) { return(1); } log_msg(4, "(mount_USB_here --- device=%s, mountpoint=%s", device, mountpoint); #ifdef __FreeBSD__ sprintf(command, "mount_vfat %s %s 2>> %s", device, mountpoint, MONDO_LOGFILE); #else sprintf(command, "mount %s -t vfat %s 2>> %s", device, mountpoint, MONDO_LOGFILE); #endif log_msg(4, command); retval = system(command); log_msg(1, "system(%s) returned %d", command, retval); paranoid_free(command); return (retval); } /** * Mount the CD-ROM at @p mountpoint. * @param device The device (or file if g_ISO_restore_mode) to mount. * @param mountpoint The place to mount it. * @return 0 for success, nonzero for failure. */ int mount_CDROM_here(char *device, char *mountpoint) { /*@ buffer ****************************************************** */ char *command = NULL; int retval; #ifdef __FreeBSD__ char *dev = NULL; #else char *options = NULL; #endif assert_string_is_neither_NULL_nor_zerolength(device); assert_string_is_neither_NULL_nor_zerolength(mountpoint); make_hole_for_dir(mountpoint); if (isdigit(device[0])) { find_cdrom_device(device, FALSE); } #ifndef __FreeBSD__ mr_asprintf(&options, "ro"); #endif if (g_ISO_restore_mode) { #ifdef __FreeBSD__ mr_asprintf(&dev, "%s", make_vn(device)); if (!dev) { mr_asprintf(&command, "Unable to mount ISO (make_vn(%s) failed)", device); fatal_error(command); } strcpy(device, dev); paranoid_free(dev); #else mr_strcat(options, ",loop"); #endif } log_msg(4, "(mount_CDROM_here --- device=%s, mountpoint=%s", device, mountpoint); /*@ end vars *************************************************** */ #ifdef __FreeBSD__ mr_asprintf(&command, "mount_cd9660 -r %s %s 2>> %s", device, mountpoint, MONDO_LOGFILE); #else mr_asprintf(&command, "mount %s -o %s -t iso9660 %s 2>> %s", device, options, mountpoint, MONDO_LOGFILE); paranoid_free(options); #endif log_msg(4, command); if (strncmp(device, "/dev/", 5) == 0) { retract_CD_tray_and_defeat_autorun(); } retval = system(command); log_msg(1, "system(%s) returned %d", command, retval); paranoid_free(command); return (retval); } /** * Mount the CD-ROM or USB device at /mnt/cdrom. * @param bkpinfo The backup information structure. Fields used: * - @c bkpinfo->backup_media_type * - @c bkpinfo->disaster_recovery * - @c bkpinfo->isodir * - @c bkpinfo->media_device * @return 0 for success, nonzero for failure. */ int mount_media() { char *mount_cmd; char *mountdir = NULL; int i, res; #ifdef __FreeBSD__ char mdd[32]; char *mddev = mdd; #endif malloc_string(mount_cmd); assert(bkpinfo != NULL); if (bkpinfo->backup_media_type == tape || bkpinfo->backup_media_type == udev) { log_msg(8, "Tape/udev. Therefore, no need to mount a media."); paranoid_free(mount_cmd); return 0; } if (!run_program_and_log_output("mount | grep -F " MNT_CDROM, FALSE)) { log_msg(2, "mount_media() - media already mounted. Fair enough."); paranoid_free(mount_cmd); return (0); } if (bkpinfo->backup_media_type == netfs) { log_msg(2, "Mounting for Network thingy"); log_msg(2, "isodir = %s", bkpinfo->isodir); if ((!bkpinfo->isodir[0] || !strcmp(bkpinfo->isodir, "/")) && am_I_in_disaster_recovery_mode()) { strcpy(bkpinfo->isodir, "/tmp/isodir"); log_msg(1, "isodir is being set to %s", bkpinfo->isodir); } #ifdef __FreeBSD__ sprintf(mount_cmd, "/mnt/isodir/%s/%s/%s-%d.iso", bkpinfo->isodir, bkpinfo->netfs_remote_dir, bkpinfo->prefix, g_current_media_number); mddev = make_vn(mount_cmd); sprintf(mount_cmd, "mount_cd9660 -r %s " MNT_CDROM, mddev); #else sprintf(mount_cmd, "mount %s/%s/%s-%d.iso -t iso9660 -o loop,ro %s", bkpinfo->isodir, bkpinfo->netfs_remote_dir, bkpinfo->prefix, g_current_media_number, MNT_CDROM); #endif } else if (bkpinfo->backup_media_type == iso) { if (bkpinfo->subdir) { mr_asprintf(&mountdir, "%s/%s", bkpinfo->isodir, bkpinfo->subdir); } else { mr_asprintf(&mountdir, "%s", bkpinfo->isodir); } #ifdef __FreeBSD__ sprintf(mount_cmd, "%s/%s-%d.iso", mountdir, bkpinfo->prefix, g_current_media_number); mddev = make_vn(mount_cmd); sprintf(mount_cmd, "mount_cd9660 -r %s %s", mddev, MNT_CDROM); #else sprintf(mount_cmd, "mount %s/%s-%d.iso -t iso9660 -o loop,ro %s", mountdir, bkpinfo->prefix, g_current_media_number, MNT_CDROM); #endif mr_free(mountdir); } else if (bkpinfo->backup_media_type == usb) { sprintf(mount_cmd, "mount -t vfat %s %s", bkpinfo->media_device, MNT_CDROM); } else if (strstr(bkpinfo->media_device, "/dev/")) { #ifdef __FreeBSD__ sprintf(mount_cmd, "mount_cd9660 -r %s %s", bkpinfo->media_device, MNT_CDROM); #else sprintf(mount_cmd, "mount %s -t iso9660 -o ro %s", bkpinfo->media_device, MNT_CDROM); #endif } else { if (bkpinfo->disaster_recovery && does_file_exist("/tmp/CDROM-LIVES-HERE")) { strcpy(bkpinfo->media_device, last_line_of_file("/tmp/CDROM-LIVES-HERE")); } else { find_cdrom_device(bkpinfo->media_device, TRUE); } #ifdef __FreeBSD__ sprintf(mount_cmd, "mount_cd9660 -r %s %s", bkpinfo->media_device, MNT_CDROM); #else sprintf(mount_cmd, "mount %s -t iso9660 -o ro %s", bkpinfo->media_device, MNT_CDROM); #endif } log_msg(2, "(mount_media) --- command = %s", mount_cmd); for (i = 0; i < 2; i++) { res = run_program_and_log_output(mount_cmd, FALSE); if (!res) { break; } else { log_msg(2, "Failed to mount device."); sleep(5); run_program_and_log_output("sync", FALSE); } } if (res) { log_msg(2, "Failed, despite %d attempts", i); } else { log_msg(2, "Mounted media drive OK"); } paranoid_free(mount_cmd); return (res); } /************************************************************************** *END_MOUNT_CDROM * **************************************************************************/ /** * Ask the user for CD number @p cd_number_i_want. * Sets g_current_media_number once the correct CD is inserted. * @param bkpinfo The backup information structure. Fields used: * - @c bkpinfo->backup_media_type * - @c bkpinfo->prefix * - @c bkpinfo->isodir * - @c bkpinfo->media_device * - @c bkpinfo->please_dont_eject_when_restoring * @param cd_number_i_want The CD number to ask for. */ void insist_on_this_cd_number(int cd_number_i_want) { /*@ int ************************************************************* */ int res = 0; /*@ buffers ********************************************************* */ char *tmp; char *mds = NULL; char *request; assert(bkpinfo != NULL); assert(cd_number_i_want > 0); // log_msg(3, "Insisting on CD number %d", cd_number_i_want); if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) { log_msg(3, "No need to insist_on_this_cd_number when the backup type isn't CD-R(W) or NFS or ISO"); return; } if (g_ISO_restore_mode || bkpinfo->backup_media_type == iso || bkpinfo->backup_media_type == netfs) { g_ISO_restore_mode = TRUE; } malloc_string(tmp); malloc_string(request); sprintf(tmp, "mkdir -p " MNT_CDROM); run_program_and_log_output(tmp, 5); if ((res = what_number_cd_is_this()) != cd_number_i_want) { log_msg(3, "Currently, we hold %d but we want %d", res, cd_number_i_want); /* Now we need to umount the current media to have the next mounted after */ run_program_and_log_output("umount -d " MNT_CDROM, FALSE); log_msg(3, "Mounting next media %d",cd_number_i_want); g_current_media_number = cd_number_i_want; mount_media(); mds = media_descriptor_string(bkpinfo->backup_media_type); sprintf(tmp, "Insisting on %s #%d", mds, cd_number_i_want); sprintf(request, "Please insert %s #%d and press Enter.", mds, cd_number_i_want); mr_free(mds); log_msg(3, tmp); while (what_number_cd_is_this() != cd_number_i_want) { paranoid_system("sync"); if (is_this_device_mounted(MNT_CDROM)) { res = run_program_and_log_output("umount -d " MNT_CDROM, FALSE); } else { res = 0; } if (res) { log_to_screen("WARNING - failed to unmount CD-ROM drive"); } if (!bkpinfo->please_dont_eject) { res = eject_device(bkpinfo->media_device); } else { res = 0; } if (res) { log_to_screen("WARNING - failed to eject CD-ROM disk"); } popup_and_OK(request); if (!bkpinfo->please_dont_eject) { inject_device(bkpinfo->media_device); } paranoid_system("sync"); } log_msg(1, "Thankyou. Proceeding..."); g_current_media_number = cd_number_i_want; } paranoid_free(tmp); paranoid_free(request); } /* @} - end of deviceGroup */ /** * Creates a singly linked list of all of the non-NETFS mounted file systems. * @param DSFptr A pointer to the structure MOUNTED_FS_STRUCT used to hold * the list of mounted file systems. * @return None. */ static void add_mounted_fs_struct (MOUNTED_FS_STRUCT *DSFptr) { assert (DSFptr); if (DSF_Head == NULL) { DSF_Head = DSFptr; } else { DSF_Tail->next = DSFptr; } DSFptr->next = NULL; DSF_Tail = DSFptr; } /** * Find the structure, in the singly linked list of all of the non-NETFS * mounted file systems, that contains the specified device. * @param device The device to find * @return NULL if it didn't find the device, a pointer to the * structure if it did. */ static MOUNTED_FS_STRUCT *find_device_in_list (char *device) { MOUNTED_FS_STRUCT *DSFptr = NULL; DSFptr = DSF_Head; while (DSFptr != NULL) { if (!strcmp(DSFptr->device, device)) { break; } DSFptr = DSFptr->next; } return (DSFptr); } /** * Find the structure, in the singly linked list of all of the non-NETFS * mounted file systems, that contains the specified mount point. * @param mount_point The mount point to find * @return NULL is it didn't find the mount point, a pointer to the * structure if it did. */ static MOUNTED_FS_STRUCT *find_mount_point_in_list (char *mount_point) { MOUNTED_FS_STRUCT *DSFptr = NULL; DSFptr = DSF_Head; while (DSFptr != NULL) { if (!strcmp(DSFptr->mount_point, mount_point)) { break; } DSFptr = DSFptr->next; } return (DSFptr); } /** * Frees the memory for all of the structures on the linked list of * all of the non-NETFS mounted file systems. */ static void free_mounted_fs_list (void) { MOUNTED_FS_STRUCT *DSFptr = NULL; MOUNTED_FS_STRUCT *DSFnext = NULL; DSFptr = DSF_Head; while (DSFptr != NULL) { DSFnext = DSFptr->next; paranoid_free(DSFptr); DSFptr = DSFnext; } DSF_Head = NULL; DSF_Tail = NULL; } /** * Creates a linked list of all of the non-NETFS mounted file systems. * We use a linked list because we don't know how many mounted file * there are (and there can be a lot). * @return 0 on success and greated than 0 on failure. */ static int create_list_of_non_NETFS_mounted_file_systems (void) { int i = 0; int mount_cnt = 0; int lastpos = 0; char *mounted_file_system = NULL; char *command = NULL; char *token = NULL; char token_chars[] =" :\t\r\f\a\0"; MOUNTED_FS_STRUCT *DSFptr = NULL; free_mounted_fs_list(); /******** * Find the number of mounted file system entries and their respective mount points. * I can't return all of the entries as one string because it's length can be longer * than MAX_STR_LEN which is used in call_program_and_get_last_line_of_output(). * So start looping and get the number of mounted file systems and query them one by one. ********/ /* Get the number of mounted file systems ((those that start with "/dev/" */ mr_asprintf(&command, "mount 2>/dev/null | awk '{if($1 ~ \"^/dev/\"){print $0}}'|wc -l"); log_msg(5, "Running: %s", command); mr_asprintf(&mounted_file_system, "%s", call_program_and_get_last_line_of_output(command)); paranoid_free(command); mount_cnt = atoi(mounted_file_system); log_msg (5, "mount_cnt: %d", mount_cnt); paranoid_free(mounted_file_system); for (i=mount_cnt; i > 0; i--) { mr_asprintf(&command, "mount 2>/dev/null | awk '{if($1 ~ \"^/dev/\"){print $1,$3}}'|head -n %d", i); log_msg(5, "Running: %s", command); mr_asprintf(&mounted_file_system, "%s", call_program_and_get_last_line_of_output(command)); paranoid_free(command); log_msg (5, "mounted_file_system: %s", mounted_file_system); if ((token = mr_strtok(mounted_file_system, token_chars, &lastpos)) == NULL) { log_msg (4, "Could not get the list of mounted file systems"); paranoid_free(mounted_file_system); mr_free(token); return (1); } if (token) { log_msg (5, "token: %s", token); } while (token != NULL) { log_msg (5, "token: %s", token); if ((DSFptr = (MOUNTED_FS_STRUCT *) calloc(1, sizeof(MOUNTED_FS_STRUCT))) == NULL) { fatal_error ("Cannot allocate memory"); } add_mounted_fs_struct(DSFptr); strcpy(DSFptr->device, token); mr_free(token); if ((token = mr_strtok(mounted_file_system, token_chars, &lastpos)) == NULL) { log_msg (5, "Ran out of entries on the mounted file systems list"); mr_free(mounted_file_system); mr_free(token); return (1); } log_msg (5, "token: %s", token); strcpy(DSFptr->mount_point, token); mr_free(token); token = mr_strtok(mounted_file_system, token_chars, &lastpos); } mr_free(mounted_file_system); } /******** * DSFptr = DSF_Head; * while (DSFptr != NULL) { * printf ("Dev: %s MP: %s Check: %d\n", DSFptr->device, DSFptr->mount_point, DSFptr->check); * DSFptr = DSFptr->next; * } ********/ return (0); } /** * Given a whole disk device special file, determine which mounted file systems * are on the dsf's partitions and which mounted file systems are not. * @param dsf The whole disk device special file. * @param included_dsf_list A char pointer used to hold the list of mount points * that are on the dsf. Memory for the array will be allocated within the function. * @param excluded_dsf_list A char pointer used to hold the list of mount points * that are not on the dsf. Memory for the array will be allocated within the function. * @return 0 on success, -1 if no device special file was passed in, -2 if a device * special file was passed in but it has no partitions on it, or 1 on failure */ static int get_dsf_mount_list (const char *dsf, char **included_dsf_list, char **excluded_dsf_list) { int i = 0; int c = 0; int lastpos = 0; char VG[MAX_STR_LEN]; char *tmp = NULL; char *command = NULL; char *partition_list = NULL; char partitions[64][MAX_STR_LEN]; char *mount_list = NULL; char *token = NULL; char *ndsf = NULL; char token_chars[] =" \t\r\f\a\0"; MOUNTED_FS_STRUCT *DSFptr = NULL; memset((char *)partitions, 0, sizeof(partitions)); log_msg(5, "dsf: %s", dsf); /******** * See if a device special file was passed in (i.e. it must start with /dev/ ********/ if (strncmp(dsf, "/dev/", 5)) { log_msg (4, "%s does not start with /dev/ and (probably) is not a device special file", dsf); return (-1); } log_msg(4, " %s looks like a device special file", dsf); /* Verify that the dsf exists */ mr_asprintf(&command, "ls -al %s 2>/dev/null | wc -l", dsf); log_msg(5, " Executing: %s", command); mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output(command)); paranoid_free(command); log_msg(5, " Return value: %s", tmp); c = atoi(tmp); paranoid_free(tmp); if (!c) { log_to_screen("Cannot find device special file %s", dsf); return (1); } log_msg(4, " %s device special file exists", dsf); /* Get a list of the mounted file systems */ if (create_list_of_non_NETFS_mounted_file_systems()) { log_to_screen ("Could not get the list of mounted file systems"); return (1); } log_msg (5, "Processing dsf: %s", dsf); /******** * Get a list of the dsf's partitions. There could be no partitions on the disk * or a dsf of a partition was passed in (e.g. /dev/sda1 instead of /dev/sda). * Either way, it's an error. ********/ mr_asprintf(&command, "parted2fdisk -l %s 2>/dev/null|grep -E \"^/dev/\"|awk '{printf(\"%%s \", $1)}END{print \"\"}'", dsf); log_msg(5, "Executing: %s", command); mr_asprintf(&partition_list, "%s", call_program_and_get_last_line_of_output(command)); paranoid_free(command); log_msg(4, "Partition list for %s: %s", dsf, partition_list); if (!strlen(partition_list)) { /* There were no partitions on the disk */ log_msg(4, "No partitions on device special file %s", dsf); log_msg(4, "I guess it's a partition itself"); strcpy(partitions[0], dsf); ndsf = truncate_to_drive_name(dsf); } else { /* Fill the partition list */ i = 0; lastpos = 0; while ((token = mr_strtok(partition_list, token_chars, &lastpos)) != NULL) { log_msg (4, "Found partition: %s", token); strcpy(partitions[i++], token); mr_free(token); } mr_asprintf(&ndsf, "%s", dsf); } mr_free(partition_list); /* In any case we want to exclude the dsf itself from all MondRescue activities * at restore time (LVM, fdisk, ...) so we want it in our exclude_dev list */ if ((DSFptr = (MOUNTED_FS_STRUCT *) calloc(1, sizeof(MOUNTED_FS_STRUCT))) == NULL) { fatal_error ("Cannot allocate memory"); } add_mounted_fs_struct(DSFptr); strcpy(DSFptr->device, dsf); DSFptr->check = 1; /* For the rest ndsf is the new dsf to deal with */ /******** * At this point, we have a list of all of the partitions on the dsf. Now try to * see which partitions have a file system on them. * * Loop through each partition on the disk and: * * - If the partition is swap, it ignores it. * * - If the partition is mounted (e.g. /dev/sda1 is mounted on /boot), it adds an entry * to the linked list, copies to it the device name and mount point, and sets check == 1. * * - If the partition is part of a Volume Group that has Logical Volumes mounted, it adds * an entry to the linked list for each mounted Logical Volume in that Volume Group, copying * to it the device name and mount point, and sets check == 1. Note that if the Volume Group * contains more than one disk, it will still add the entry even if the Logical Volume's * extents are not on the dsf that was passed in to the function. For example, Volume Group * VolGroup00 contains the disks /dev/sda1 and /dev/sdb1, and the Logical Volumes LogVol01, * which is mounted on /var and has all of its extents on /dev/sda1, and LogVol02, which is * mounted as /usr and has all of its extents on /dev/sdb1. If you pass /dev/sda into the * function, both /var and /usr will be archived even though /usr is actually on/dev/sdb. * * - If the partition is part of a Volume Group that has Logical Volumes used in a mounted * software raid device, it adds an entry to the linked list, copies to it the software raid * device name and mount point, and sets check == 1. * * - If the partition is part of a mounted software raid device, it adds an entry to the linked * list, copies to it the software raid device name and mount point, and sets check == 1. * ********/ for (i=0; strlen(partitions[i]); i++) { log_msg(4, "Processing partition: %s", partitions[i]); /* See if it's swap. If it is, ignore it. */ mr_asprintf(&command, "parted2fdisk -l %s 2>/dev/null | awk '{if(($1==\"%s\")&&(toupper($0) ~ \"SWAP\")){print $1;exit}}'", ndsf, partitions[i]); log_msg(5, " Running: %s", command); mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output(command)); paranoid_free(command); log_msg(5, " Return value: %s", tmp); c = strlen(tmp); paranoid_free(tmp); if (c) { log_msg(4, "It's swap. Ignoring partition %s", partitions[i]); continue; } /* It's not swap. See if we can find the mount point from the mount command. */ mr_asprintf(&command, "mount 2>/dev/null | awk '{if((NF>0)&&($1==\"%s\")){print $3}}'", partitions[i]); mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output(command)); paranoid_free(command); if (strlen(tmp)) { log_msg(4, " %s is mounted: %s", partitions[i], tmp); if ((DSFptr = find_mount_point_in_list(tmp)) == NULL) { log_msg (4, "Can't find mount point %s in mounted file systems list", tmp); paranoid_free(tmp); return (1); } DSFptr->check = 1; paranoid_free(tmp); continue; } paranoid_free(tmp); /* It's not swap and it's not mounted. See if it's LVM */ log_msg(4, " It's not mounted. Checking to see if it's LVM..."); /* Check for LVM */ mr_asprintf(&command, "pvdisplay -c %s | grep '%s:' 2> /dev/null", partitions[i], partitions[i]); log_msg(5, " Running: %s", command); mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output(command)); paranoid_free(command); if (strlen(tmp)) { log_msg(4, "Found an LVM partition at %s. Find the VG it's in...", partitions[i]); /* It's LVM: Find the VG it's in */ mr_asprintf(&command, "pvdisplay -v %s 2>/dev/null|grep \"VG Name\"|awk '{print $NF}'", partitions[i]); log_msg(5, " Running: %s", command); strcpy(VG, call_program_and_get_last_line_of_output(command)); paranoid_free(command); log_msg(4, " Volume Group: %s", VG); if (strlen(VG)) { /* Found the Volume Group. Now find all of the VG's mount points */ log_msg(4, " Found the Volume Group. Now find all of the VG's mount points"); mr_asprintf(&command, "mount 2>/dev/null|grep -E \"/dev/mapper/%s-|/dev/%s/\"|awk '{printf(\"%%s \",$3)}END{print \"\"}'", VG, VG); log_msg(5, " Running: %s", command); mr_asprintf(&mount_list, "%s", call_program_and_get_last_line_of_output(command)); paranoid_free(command); log_msg(4, " VG %s mount_list: %s", VG, mount_list); lastpos = 0; while ((token = mr_strtok(mount_list, token_chars, &lastpos)) != NULL) { log_msg (5, "mount point token: %s", token); if ((DSFptr = find_mount_point_in_list(token)) == NULL) { log_msg (4, "Can't find mount point %s in mounted file systems list", token); paranoid_free(tmp); mr_free(token); return (1); } DSFptr->check = 1; mr_free(token); } /******** * Now we want to see if there are any software raid devices using * any of the Logical Volumes on the Volume Group. *******/ paranoid_free(mount_list); mr_asprintf(&command, "%s", "cat /proc/mdstat|grep -iv Personal|awk '{if($0~\"^.*[ ]+:\"){printf(\"/dev/%s \", $1)}}END{print \"\"}'"); log_msg (5, "Running: %s", command); mr_asprintf(&mount_list, "%s", call_program_and_get_last_line_of_output(command)); paranoid_free(command); log_msg(4, " Software raid device list: %s", mount_list); lastpos = 0; while ((token = mr_strtok(mount_list, token_chars, &lastpos)) != NULL) { mr_asprintf(&command, "mdadm --detail %s 2>/dev/null | grep -c %s", token, VG); log_msg (5, "Running: %s", command); paranoid_free(tmp); mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output(command)); paranoid_free(command); log_msg(4, "Number of Software raid device: %s", tmp); if (atoi(tmp)) { /* This device is on our disk */ if ((DSFptr = find_device_in_list(token)) == NULL) { log_msg (4, "Can't find device %s in mounted file systems list", token); paranoid_free(tmp); mr_free(token); return (1); } DSFptr->check = 1; } } mr_free(token); paranoid_free(mount_list); } else { log_msg (4, "Error finding Volume Group for partition %s", partitions[i]); paranoid_free(tmp); return (1); } paranoid_free(tmp); continue; } else { log_msg (4, "Error finding partition type for the partition %s", partitions[i]); } paranoid_free(tmp); /******** * It's not swap, mounted, or LVM. See if it's used in a software raid device. ********/ log_msg (5, "It's not swap, mounted, or LVM. See if it's used in a software raid device."); mr_asprintf(&command, "mdadm --examine %s 2>/dev/null | awk '{if($1 == \"UUID\"){print $3}}'", partitions[i]); log_msg(4, " Running: %s", command); mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output(command)); paranoid_free(command); if (!strlen(tmp)) { log_msg(4, " Partition %s is not used in a non-LVM software raid device", partitions[i]); paranoid_free(tmp); continue; } log_msg (5, " UUID: %s", tmp); /* Get the Software raid device list */ mr_asprintf(&command, "%s", "cat /proc/mdstat|grep -iv Personal|awk '{if($0~\"^.*[ ]+:\"){printf(\"/dev/%s \", $1)}}END{print \"\"}'"); log_msg (5, " Running: %s", command); mr_asprintf(&mount_list, "%s", call_program_and_get_last_line_of_output(command)); paranoid_free(command); log_msg(4, " Software raid device list: %s", mount_list); /* Loop through the software raid device list to see if we can find the partition */ lastpos = 0; while ((token = mr_strtok(mount_list, token_chars, &lastpos)) != NULL) { mr_asprintf(&command, "mdadm --detail %s 2>/dev/null | grep -c %s", token, tmp); log_msg(4, " Running: %s", command); paranoid_free(tmp); mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output(command)); paranoid_free(command); if (!atoi(tmp)) { log_msg (4," Didn't find partition %s in software raid device %s", partitions[i], token); } else { if ((DSFptr = find_device_in_list(token)) == NULL) { log_msg (4, "Can't find device %s in mounted file systems list", token); paranoid_free(tmp); mr_free(token); return (1); } DSFptr->check = 1; break; } mr_free(token); } paranoid_free(tmp); paranoid_free(mount_list); } /* Determine how much memory to allocate for included_dsf_list and excluded_dsf_list */ i = 0; DSFptr= DSF_Head; while (DSFptr != NULL) { i += strlen(DSFptr->mount_point) + 1; DSFptr = DSFptr->next; } log_msg (5, "i: %d", i); if ((*included_dsf_list = (char *) calloc(i+100, sizeof(char))) == NULL) { fatal_error ("Cannot allocate memory"); } if ((*excluded_dsf_list = (char *) calloc(i+100, sizeof(char))) == NULL) { fatal_error ("Cannot allocate memory"); } DSFptr= DSF_Head; while (DSFptr != NULL) { if (DSFptr->check) { log_msg (4, "%s is mounted on %s and is on disk %s", DSFptr->device, DSFptr->mount_point, ndsf); strcat(*included_dsf_list, DSFptr->mount_point); strcat(*included_dsf_list, "|"); } else { log_msg (4, "%s is mounted on %s and is NOT on disk %s", DSFptr->device, DSFptr->mount_point, ndsf); strcat(*excluded_dsf_list, DSFptr->mount_point); strcat(*excluded_dsf_list, "|"); } DSFptr = DSFptr->next; } mr_free(ndsf); log_msg (5, "included_dsf_list: %s", *included_dsf_list); log_msg (5, "excluded_dsf_list: %s", *excluded_dsf_list); return (0); } /* Update the bkpinfo structure for exclude & include paths * in order to handle correctly paths corresponding to devices */ void mr_make_devlist_from_pathlist(char *pathlist, char mode) { char *token = NULL; int lastpos = 0; char *mounted_on_dsf = NULL; char *not_mounted_on_dsf = NULL; char token_chars[] ="|\t\r\f\a\0\n"; char *tmp = NULL; char *tmp1 = NULL; char *tmp2 = NULL; if (pathlist == NULL) { return; } while ((token = mr_strtok(pathlist, token_chars, &lastpos)) != NULL) { switch (get_dsf_mount_list(token, &mounted_on_dsf, ¬_mounted_on_dsf)) { case 1: if (mode == 'E') { log_msg(1, "WARNING ! %s doesn't exist in -E option", token); } else { log_msg(1, "ERROR ! %s doesn't exist in -I option", token); fatal_error("Error processing -I option"); } break; /* Everything is OK; proceed to archive data */ case 0: if (mode == 'E') { if (strlen(mounted_on_dsf)) { log_to_screen("Excluding the following file systems on %s:", token); log_to_screen("==> %s", mounted_on_dsf); log_msg (5, "Adding to bkpinfo->exclude_paths due to -E option: %s", mounted_on_dsf); if (bkpinfo->exclude_paths) { mr_strcat(bkpinfo->exclude_paths,"|%s",mounted_on_dsf); } else { mr_asprintf(&(bkpinfo->exclude_paths),"%s",mounted_on_dsf); } if (bkpinfo->exclude_devs) { mr_strcat(bkpinfo->exclude_devs,"|%s",token); } else { mr_asprintf(&(bkpinfo->exclude_devs),"%s",token); } } } else { log_to_screen("Archiving only the following file systems on %s:", token); log_to_screen("==> %s", mounted_on_dsf); strcpy(bkpinfo->include_paths, "/"); if (strlen(not_mounted_on_dsf)) { log_msg (5, "Adding to bkpinfo->exclude_paths due to -I option: %s", not_mounted_on_dsf); log_to_screen("Not archiving the following file systems:"); log_to_screen("==> %s", not_mounted_on_dsf); if (bkpinfo->exclude_paths) { mr_strcat(bkpinfo->exclude_paths, "|%s",not_mounted_on_dsf); } else { mr_asprintf(&(bkpinfo->exclude_paths),"%s",not_mounted_on_dsf); } } } break; /* It's a dsf but not a whole disk dsf */ case -2: log_to_screen("Could %s be a partition instead of a whole disk device special file?\nIgnored.", token); break; /* A device special file was not passed in. Process it as a path. */ case -1: /* Adds a | to ensure correct detection even at both ends */ mr_asprintf(&tmp1,"|%s",token); mr_asprintf(&tmp2,"|%s|",token); if (mode == 'E') { /* Add the token if not already in the list */ mr_asprintf(&tmp,"|%s|",bkpinfo->exclude_paths); if (strstr(tmp,tmp2) == NULL) { if (bkpinfo->exclude_paths) { mr_strcat(bkpinfo->exclude_paths,tmp1); mr_free(tmp1); } else { bkpinfo->exclude_paths = tmp1; } } } else { /* Add the token if not already in the list */ mr_asprintf(&tmp,"|%s|",bkpinfo->include_paths); if (strstr(tmp,tmp2) == NULL) { strcat(bkpinfo->include_paths,tmp1); } mr_free(tmp1); } mr_free(tmp); mr_free(tmp2); break; } mr_free(token); if (bkpinfo->include_paths != NULL) { log_msg(1, "include_paths is now '%s'", bkpinfo->include_paths); } if (bkpinfo->exclude_paths != NULL) { log_msg(1, "exclude_paths is now '%s'", bkpinfo->exclude_paths); } if (bkpinfo->exclude_devs != NULL) { log_msg(1, "exclude_devs is now '%s'", bkpinfo->exclude_devs); } } } /** * Ask user for details of backup/restore information. * Called when @c mondoarchive doesn't get any parameters. * @param bkpinfo The backup information structure to fill out with the user's data. * @param archiving_to_media TRUE if archiving, FALSE if restoring. * @return 0, always. * @bug No point of `int' return value. * @ingroup archiveGroup */ int interactively_obtain_media_parameters_from_user(bool archiving_to_media) // archiving_to_media is TRUE if I'm being called by mondoarchive // archiving_to_media is FALSE if I'm being called by mondorestore { char *tmp = NULL; char *tmp1 = NULL; char *mds = NULL; char *q = NULL; char p[8*MAX_STR_LEN]; char *sz_size; char *command; char *compression_type = NULL; char *comment; char *prompt; int i; FILE *fin; malloc_string(sz_size); malloc_string(command); malloc_string(comment); malloc_string(prompt); malloc_string(tmp1); assert(bkpinfo != NULL); sz_size[0] = '\0'; bkpinfo->nonbootable_backup = FALSE; // Tape, CD, NETFS, ...? srandom(getpid()); bkpinfo->backup_media_type = (g_restoring_live_from_cd) ? cdr : which_backup_media_type(bkpinfo->restore_data); if (bkpinfo->backup_media_type == none) { log_to_screen("User has chosen not to backup the PC"); finish(1); } /* Why asking to remove the media with tape ? if (bkpinfo->backup_media_type == tape && bkpinfo->restore_data) { popup_and_OK("Please remove media from drive(s)"); } */ log_msg(3, "media type = %s", bkptype_to_string(bkpinfo->backup_media_type)); if (archiving_to_media) { sensibly_set_tmpdir_and_scratchdir(); } bkpinfo->cdrw_speed = (bkpinfo->backup_media_type == cdstream) ? 2 : 4; bkpinfo->compression_level = (bkpinfo->backup_media_type == cdstream) ? 1 : 5; bkpinfo->use_lzo = (bkpinfo->backup_media_type == cdstream) ? TRUE : FALSE; mvaddstr_and_log_it(2, 0, " "); // Find device's /dev (or SCSI) entry switch (bkpinfo->backup_media_type) { case cdr: case cdrw: case dvd: case usb: /* Never try to eject a USB device */ if (bkpinfo->backup_media_type == usb) { bkpinfo->please_dont_eject = TRUE; } if (archiving_to_media) { if ((bkpinfo->backup_media_type != dvd) && (bkpinfo->backup_media_type != usb)) { if (ask_me_yes_or_no ("Is your computer a laptop, or does the CD writer incorporate BurnProof technology?")) { bkpinfo->manual_cd_tray = TRUE; } } if ((compression_type = which_compression_type()) == NULL) { log_to_screen("User has chosen not to backup the PC"); finish(1); } if ((bkpinfo->compression_level = which_compression_level()) == -1) { log_to_screen("User has chosen not to backup the PC"); finish(1); } mds = media_descriptor_string(bkpinfo->backup_media_type); sprintf(comment, "What speed is your %s (re)writer?", mds); if (bkpinfo->backup_media_type == dvd) { find_dvd_device(bkpinfo->media_device, FALSE); strcpy(tmp1, "1"); sprintf(sz_size, "%d", DEFAULT_DVD_DISK_SIZE); // 4.7 salesman's GB = 4.482 real GB = 4482 MB log_msg(1, "Setting to DVD defaults"); } else { strcpy(bkpinfo->media_device, VANILLA_SCSI_CDROM); strcpy(tmp1, "4"); strcpy(sz_size, "650"); log_msg(1, "Setting to CD defaults"); } if ((bkpinfo->backup_media_type != dvd) && (bkpinfo->backup_media_type != usb)) { if (!popup_and_get_string("Speed", comment, tmp1, 4)) { log_to_screen("User has chosen not to backup the PC"); finish(1); } } bkpinfo->cdrw_speed = atoi(tmp1); // if DVD then this shouldn't ever be used anyway :) sprintf(comment, "How much data (in Megabytes) will each %s store?", mds); mr_free(mds); if (!popup_and_get_string("Size", comment, sz_size, 5)) { log_to_screen("User has chosen not to backup the PC"); finish(1); } for (i = 0; i <= MAX_NOOF_MEDIA; i++) { bkpinfo->media_size[i] = atoi(sz_size); } if (bkpinfo->media_size[0] <= 0) { log_to_screen("User has chosen not to backup the PC"); finish(1); } } /* No break because we continue even for usb */ case cdstream: mds = media_descriptor_string(bkpinfo->backup_media_type); if ((bkpinfo->disaster_recovery) && (bkpinfo->backup_media_type != usb)) { strcpy(bkpinfo->media_device, "/dev/cdrom"); log_msg(2, "CD-ROM device assumed to be at %s", bkpinfo->media_device); } else if ((bkpinfo->restore_data && (bkpinfo->backup_media_type != usb)) || bkpinfo->backup_media_type == dvd) { if (!bkpinfo->media_device[0]) { strcpy(bkpinfo->media_device, "/dev/cdrom"); } // just for the heck of it :) log_msg(1, "bkpinfo->media_device = %s", bkpinfo->media_device); if (bkpinfo->backup_media_type == dvd || find_cdrom_device(bkpinfo->media_device, FALSE)) { log_msg(1, "bkpinfo->media_device = %s", bkpinfo->media_device); sprintf(comment, "Please specify your %s drive's /dev entry", mds); if (!popup_and_get_string ("Device?", comment, bkpinfo->media_device, MAX_STR_LEN / 4)) { log_to_screen("User has chosen not to backup the PC"); finish(1); } } log_msg(2, "%s device found at %s", mds, bkpinfo->media_device); } else { if ((find_cdrw_device(bkpinfo->media_device)) && (bkpinfo->backup_media_type != usb)) { bkpinfo->media_device[0] = '\0'; } if (bkpinfo->media_device[0]) { if (bkpinfo->backup_media_type == usb) { mr_asprintf(&tmp, "I think your %s media corresponds to %s. Is this correct?", mds, bkpinfo->media_device); } else { mr_asprintf(&tmp, "I think I've found your %s burner at SCSI node %s. Is this correct? (Say no if you have an IDE burner and you are running a 2.6 kernel. You will then be prompted for further details.)", mds, bkpinfo->media_device); } if (!ask_me_yes_or_no(tmp)) { bkpinfo->media_device[0] = '\0'; } mr_free(tmp); } if (!bkpinfo->media_device[0]) { if (bkpinfo->backup_media_type == usb) { i = popup_and_get_string("/dev entry?", "What is the /dev entry of your USB Disk/Key, please?", bkpinfo->media_device, MAX_STR_LEN / 4); } else { if (g_kernel_version < 2.6) { 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); } else { 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); } } if (!i) { log_to_screen("User has chosen not to backup the PC"); finish(1); } } } mr_free(mds); if (bkpinfo->backup_media_type == cdstream) { for (i = 0; i <= MAX_NOOF_MEDIA; i++) { bkpinfo->media_size[i] = 650; } } break; case udev: if (!ask_me_yes_or_no ("This option is for advanced users only. Are you sure?")) { log_to_screen("User has chosen not to backup the PC"); finish(1); } case tape: if ((!bkpinfo->restore_mode) && (find_tape_device_and_size(bkpinfo->media_device, sz_size))) { log_msg(3, "Ok, using vanilla scsi tape."); strcpy(bkpinfo->media_device, VANILLA_SCSI_TAPE); if ((fin = fopen(bkpinfo->media_device, "r"))) { paranoid_fclose(fin); } else { strcpy(bkpinfo->media_device, "/dev/osst0"); } } if (bkpinfo->media_device[0]) { if ((fin = fopen(bkpinfo->media_device, "r"))) { paranoid_fclose(fin); } else { if (does_file_exist("/tmp/mondo-restore.cfg")) { read_cfg_var("/tmp/mondo-restore.cfg", "media-dev", bkpinfo->media_device); } } } if (bkpinfo->media_device[0]) { mr_asprintf(&tmp, "I think I've found your tape streamer at %s; am I right on the money?", bkpinfo->media_device); if (!ask_me_yes_or_no(tmp)) { bkpinfo->media_device[0] = '\0'; } mr_free(tmp); } if (!bkpinfo->media_device[0]) { if (!popup_and_get_string ("Device name?", "What is the /dev entry of your tape streamer?", bkpinfo->media_device, MAX_STR_LEN / 4)) { log_to_screen("User has chosen not to backup the PC"); finish(1); } } mr_asprintf(&tmp, "ls -l %s", bkpinfo->media_device); if (run_program_and_log_output(tmp, FALSE)) { log_to_screen("User has not specified a valid /dev entry"); finish(1); } mr_free(tmp); log_msg(4, "sz_size = %s", sz_size); sz_size[0] = '\0'; if (sz_size[0] == '\0') { bkpinfo->media_size[0] = 0; } else { bkpinfo->media_size[0] = friendly_sizestr_to_sizelong(sz_size) / 2 - 50; } log_msg(4, "media_size[0] = %ld", bkpinfo->media_size[0]); if (bkpinfo->media_size[0] <= 0) { bkpinfo->media_size[0] = 0; } for (i = 1; i <= MAX_NOOF_MEDIA; i++) { bkpinfo->media_size[i] = bkpinfo->media_size[0]; } bkpinfo->use_obdr = ask_me_yes_or_no ("Do you want to activate OBDR support for your tapes ?"); if (bkpinfo->use_obdr) { log_msg(4, "obdr mode = TRUE"); } else { log_msg(4, "obdr mode = FALSE"); } if (archiving_to_media) { if ((compression_type = which_compression_type()) == NULL) { log_to_screen("User has chosen not to backup the PC"); finish(1); } if ((bkpinfo->compression_level = which_compression_level()) == -1) { log_to_screen("User has chosen not to backup the PC"); finish(1); } } break; case netfs: /* Never try to eject a NETFS device */ bkpinfo->please_dont_eject = TRUE; /* Initiate bkpinfo netfs_mount path from running environment if not already done */ if (!bkpinfo->netfs_mount[0]) { strcpy(bkpinfo->netfs_mount, call_program_and_get_last_line_of_output ("mount | grep \":\" | cut -d' ' -f1 | head -n1")); } #ifdef __FreeBSD__ if (TRUE) #else if (!bkpinfo->disaster_recovery) #endif { if (!popup_and_get_string ("Network shared 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->netfs_mount, MAX_STR_LEN / 4)) { log_to_screen("User has chosen not to backup the PC"); finish(1); } if (!bkpinfo->restore_data) { if ((compression_type = which_compression_type()) == NULL) { log_to_screen("User has chosen not to backup the PC"); finish(1); } if ((bkpinfo->compression_level = which_compression_level()) == -1) { log_to_screen("User has chosen not to backup the PC"); finish(1); } } // check whether already mounted - we better remove // surrounding spaces and trailing '/' for this strip_spaces(bkpinfo->netfs_mount); if (bkpinfo->netfs_mount[strlen(bkpinfo->netfs_mount) - 1] == '/') bkpinfo->netfs_mount[strlen(bkpinfo->netfs_mount) - 1] = '\0'; q = strchr(bkpinfo->netfs_mount, '@'); if (q != NULL) { /* User found. Store the 2 values */ q++; /* new netfs mount */ strcpy(tmp1,q); } else { strcpy(tmp1,bkpinfo->netfs_mount); } sprintf(command, "mount | grep \"%s \" | cut -d' ' -f3", tmp1); strcpy(bkpinfo->isodir, call_program_and_get_last_line_of_output(command)); if (!bkpinfo->restore_data) { sprintf(sz_size, "%d", DEFAULT_DVD_DISK_SIZE); // 4.7 salesman's GB = 4.482 real GB = 4482 MB sprintf(comment, "How much data (in Megabytes) will each media store?"); if (!popup_and_get_string("Size", comment, sz_size, 5)) { log_to_screen("User has chosen not to backup the PC"); finish(1); } } else { strcpy(sz_size, "0"); } for (i = 0; i <= MAX_NOOF_MEDIA; i++) { bkpinfo->media_size[i] = atoi(sz_size); } if (bkpinfo->media_size[0] < 0) { log_to_screen("User has chosen not to backup the PC"); finish(1); } } /* Force NFS to be the protocol by default */ if (bkpinfo->netfs_proto == NULL) { mr_asprintf(&(bkpinfo->netfs_proto), "nfs"); } if (bkpinfo->disaster_recovery) { sprintf(command ,"umount %s/isodir 2> /dev/null", bkpinfo->tmpdir); (void)system(command); } strcpy(tmp1, bkpinfo->netfs_proto); if (!popup_and_get_string ("Network protocol", "Which protocol should I use (nfs/sshfs) ?", tmp1, MAX_STR_LEN)) { log_to_screen("User has chosen not to backup the PC"); finish(1); } mr_free(bkpinfo->netfs_proto); mr_asprintf(&(bkpinfo->netfs_proto), "%s", tmp1); if (!popup_and_get_string ("Network share", "Which remote share should I mount?", bkpinfo->netfs_mount, MAX_STR_LEN)) { log_to_screen("User has chosen not to backup the PC"); finish(1); } if (bkpinfo->netfs_user) { strcpy(tmp1, bkpinfo->netfs_user); } else { strcpy(tmp1, ""); } if (!popup_and_get_string ("Network user", "Which user should I use if any ?", tmp1, MAX_STR_LEN)) { log_to_screen("User has chosen not to backup the PC"); finish(1); } mr_free(bkpinfo->netfs_user); if (strcmp(tmp1, "") != 0) { mr_asprintf(&(bkpinfo->netfs_user), "%s", tmp1); } /* Initiate bkpinfo isodir path from running environment if mount already done */ if (is_this_device_mounted(bkpinfo->netfs_mount)) { strcpy(bkpinfo->isodir, call_program_and_get_last_line_of_output ("mount | grep \":\" | cut -d' ' -f3 | head -n1")); } else { sprintf(bkpinfo->isodir, "%s/netfsdir", bkpinfo->tmpdir); sprintf(command, "mkdir -p %s", bkpinfo->isodir); run_program_and_log_output(command, 5); if (bkpinfo->restore_data) { if (strstr(bkpinfo->netfs_proto, "sshfs")) { mr_asprintf(&tmp, "sshfs -o ro"); } else { mr_asprintf(&tmp, "mount -t %s -o nolock,ro", bkpinfo->netfs_proto); } } else { if (strstr(bkpinfo->netfs_proto, "sshfs")) { mr_asprintf(&tmp, "sshfs"); } else { mr_asprintf(&tmp, "mount -t %s -o nolock", bkpinfo->netfs_proto); } } mr_strcat(tmp, " "); if (bkpinfo->netfs_user) { mr_strcat(tmp, "%s@", bkpinfo->netfs_user); } mr_strcat(tmp, "%s %s", bkpinfo->netfs_mount, bkpinfo->isodir); run_program_and_log_output(tmp, 3); mr_free(tmp); malloc_string(g_selfmounted_isodir); strcpy(g_selfmounted_isodir, bkpinfo->isodir); } if (!is_this_device_mounted(bkpinfo->netfs_mount)) { popup_and_OK ("Please mount that partition before you try to backup to or restore from it."); finish(1); } strcpy(tmp1, bkpinfo->netfs_remote_dir); if (!popup_and_get_string ("Directory", "Which directory within that mountpoint?", tmp1, MAX_STR_LEN)) { log_to_screen("User has chosen not to backup the PC"); finish(1); } strcpy(bkpinfo->netfs_remote_dir, tmp1); // check whether writable - we better remove surrounding spaces for this strip_spaces(bkpinfo->netfs_remote_dir); 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)) { log_to_screen("User has chosen not to backup the PC"); finish(1); } log_msg(3, "prefix set to %s", bkpinfo->prefix); log_msg(3, "Just set netfs_remote_dir to %s", bkpinfo->netfs_remote_dir); log_msg(3, "isodir is still %s", bkpinfo->isodir); break; case iso: if (!bkpinfo->disaster_recovery) { if (!popup_and_get_string ("Storage dir.", "Please enter the full path name to the directory for your ISO images. Example: /mnt/raid0_0", bkpinfo->isodir, MAX_STR_LEN / 4)) { log_to_screen("User has chosen not to backup the PC"); finish(1); } if (archiving_to_media) { if ((compression_type = which_compression_type()) == NULL) { log_to_screen("User has chosen not to backup the PC"); finish(1); } if ((bkpinfo->compression_level = which_compression_level()) == -1) { log_to_screen("User has chosen not to backup the PC"); finish(1); } sprintf(sz_size, "%d", DEFAULT_DVD_DISK_SIZE); // 4.7 salesman's GB = 4.482 real GB = 4482 MB 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 (700) or DVD's (4480) you plan to backup to.", sz_size, 16)) { log_to_screen("User has chosen not to backup the PC"); finish(1); } for (i = 0; i <= MAX_NOOF_MEDIA; i++) { bkpinfo->media_size[i] = atoi(sz_size); } } else { for (i = 0; i <= MAX_NOOF_MEDIA; i++) { bkpinfo->media_size[i] = 650; } } } 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)) { log_to_screen("User has chosen not to backup the PC"); finish(1); } log_msg(3, "prefix set to %s", bkpinfo->prefix); break; default: fatal_error ("I, Mojo Jojo, shall defeat those pesky Powerpuff Girls!"); } if (archiving_to_media) { #ifdef __FreeBSD__ strcpy(bkpinfo->boot_device, call_program_and_get_last_line_of_output ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/\\([0-9]\\).*/\\1/'")); #else strcpy(bkpinfo->boot_device, call_program_and_get_last_line_of_output ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/[0-9].*//'")); #endif i = which_boot_loader(bkpinfo->boot_device); if (i == 'U') // unknown { #ifdef __FreeBSD__ if (!popup_and_get_string ("Boot device", "What is your boot device? (e.g. /dev/ad0)", bkpinfo->boot_device, MAX_STR_LEN / 4)) { log_to_screen("User has chosen not to backup the PC"); finish(1); } i = which_boot_loader(bkpinfo->boot_device); #else if (!popup_and_get_string ("Boot device", "What is your boot device? (e.g. /dev/hda)", bkpinfo->boot_device, MAX_STR_LEN / 4)) { log_to_screen("User has chosen not to backup the PC"); finish(1); } if (does_string_exist_in_boot_block (bkpinfo->boot_device, "LILO")) { i = 'L'; } else if (does_string_exist_in_boot_block (bkpinfo->boot_device, "ELILO")) { i = 'E'; } else if (does_string_exist_in_boot_block (bkpinfo->boot_device, "GRUB")) { i = 'G'; } else { i = 'U'; } #endif if (i == 'U') { if (ask_me_yes_or_no ("Unidentified boot loader. Shall I restore it byte-for-byte at restore time and hope for the best?")) { i = 'R'; // raw } else { log_to_screen ("I cannot find your boot loader. Please run mondoarchive with parameters."); finish(1); } } } bkpinfo->boot_loader = i; strcpy(bkpinfo->include_paths, "/"); if (!popup_and_get_string ("Backup paths", "Please enter paths (separated by '|') which you want me to backup. The default is '/' (i.e. everything).", bkpinfo->include_paths, MAX_STR_LEN)) { log_to_screen("User has chosen not to backup the PC"); finish(1); } tmp = list_of_NETFS_mounts_only(); if (strlen(tmp) > 2) { mr_strcat(bkpinfo->exclude_paths, "|%s",tmp); } mr_free(tmp); // NTFS strcpy(tmp1, call_program_and_get_last_line_of_output("parted2fdisk -l | grep -i ntfs | awk '{ print $1};' | tr -s '\\n' ' ' | awk '{ print $0};'")); if (strlen(tmp1) > 2) { if (!popup_and_get_string ("NTFS partitions", "Please enter/confirm the NTFS partitions you wish to backup as well.", tmp1, MAX_STR_LEN / 4)) { log_to_screen("User has chosen not to backup the PC"); finish(1); } strncpy(bkpinfo->image_devs, tmp1, MAX_STR_LEN / 4); } if (bkpinfo->exclude_paths != NULL ) { strncpy(p,bkpinfo->exclude_paths,(8*MAX_STR_LEN)-1); } else { p[0] = '\0'; } popup_and_get_string("Exclude paths", "Please enter paths which you do NOT want to backup. Separate them with '|'. NB: /tmp and /proc are always excluded. :-) Just hit 'Enter' if you want to do a full system backup.", p, (8*MAX_STR_LEN)-1); if (p == NULL) { log_to_screen("User has chosen not to backup the PC"); finish(1); } mr_free(bkpinfo->exclude_paths); mr_asprintf(&tmp, "%s", p); bkpinfo->exclude_paths = tmp; if (!popup_and_get_string ("Temporary directory", "Please enter your temporary directory.", bkpinfo->tmpdir, (4*MAX_STR_LEN)-1)) { log_to_screen("User has chosen not to backup the PC"); finish(1); } if (!popup_and_get_string ("Scratch directory", "Please enter your scratch directory.", bkpinfo->scratchdir, (4*MAX_STR_LEN)-1)) { log_to_screen("User has chosen not to backup the PC"); finish(1); } if (ask_me_yes_or_no("Do you want to backup extended attributes?")) { if (find_home_of_exe("getfattr")) { mr_asprintf(&g_getfattr,"getfattr"); } if (find_home_of_exe("getfacl")) { mr_asprintf(&g_getfacl,"getfacl"); } } // Interactive mode: #ifdef __IA64__ bkpinfo->make_cd_use_lilo = TRUE; #else bkpinfo->make_cd_use_lilo = FALSE; #endif bkpinfo->backup_data = TRUE; if (strcmp(compression_type,"lzo") == 0) { strcpy(bkpinfo->zip_exe, "lzop"); strcpy(bkpinfo->zip_suffix, "lzo"); } else if (strcmp(compression_type,"gzip") == 0) { strcpy(bkpinfo->zip_exe, "gzip"); strcpy(bkpinfo->zip_suffix, "gz"); //} else if (strcmp(compression_type,"lzma") == 0) { //strcpy(bkpinfo->zip_exe, "xy"); //strcpy(bkpinfo->zip_suffix, "xy"); } else if (strcmp(compression_type,"bzip2") == 0) { strcpy(bkpinfo->zip_exe, "bzip2"); strcpy(bkpinfo->zip_suffix, "bz2"); } else { bkpinfo->zip_exe[0] = bkpinfo->zip_suffix[0] = '\0'; } bkpinfo->verify_data = ask_me_yes_or_no ("Will you want to verify your backups after Mondo has created them?"); #ifndef __FreeBSD__ 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.")) #endif { strcpy(bkpinfo->kernel_path, "FAILSAFE"); } if (!ask_me_yes_or_no ("Are you sure you want to proceed? Hit 'no' to abort.")) { log_to_screen("User has chosen not to backup the PC"); finish(1); } } else { bkpinfo->restore_data = TRUE; // probably... } mr_free(compression_type); if (bkpinfo->backup_media_type == iso || bkpinfo->backup_media_type == netfs) { g_ISO_restore_mode = TRUE; } #ifdef __FreeSD__ // skip #else if (bkpinfo->backup_media_type == netfs) { log_msg(3, "I think the Remote mount is mounted at %s", bkpinfo->isodir); } log_it("isodir = %s", bkpinfo->isodir); log_it("netfs_mount = '%s'", bkpinfo->netfs_mount); if (bkpinfo->netfs_proto) { log_it("netfs_proto = '%s'", bkpinfo->netfs_proto); } if (bkpinfo->netfs_user) { log_it("netfs_user = '%s'", bkpinfo->netfs_user); } #endif log_it("media device = %s", bkpinfo->media_device); log_it("media size = %ld", bkpinfo->media_size[1]); log_it("media type = %s", bkptype_to_string(bkpinfo->backup_media_type)); log_it("prefix = %s", bkpinfo->prefix); log_it("compression = %ld", bkpinfo->compression_level); log_it("exclude_path = %s", bkpinfo->exclude_paths); log_it("include_path = %s", bkpinfo->include_paths); /* Handle devices passed in bkpinfo and print result */ /* the mr_make_devlist_from_pathlist function appends * to the *_paths variables so copy before */ mr_make_devlist_from_pathlist(bkpinfo->exclude_paths, 'E'); mr_make_devlist_from_pathlist(bkpinfo->include_paths, 'I'); log_it("scratchdir = '%s'", bkpinfo->scratchdir); log_it("tmpdir = '%s'", bkpinfo->tmpdir); log_it("image_devs = '%s'", bkpinfo->image_devs); log_it("boot_device = '%s' (loader=%c)", bkpinfo->boot_device, bkpinfo->boot_loader); if (bkpinfo->media_size[0] < 0) { if (archiving_to_media) { fatal_error("Media size is less than zero."); } else { log_msg(2, "Warning - media size is less than zero."); bkpinfo->media_size[0] = 0; } } paranoid_free(sz_size); paranoid_free(tmp1); paranoid_free(command); paranoid_free(comment); paranoid_free(prompt); return (0); } /** * Get a |-separated list of NETFS mounts. * @return The list created. * @note The return value points to allocated string that needs to be freed * @bug Even though we only want the mounts, the devices are still checked. */ char *list_of_NETFS_mounts_only(void) { char *exclude_these_directories = NULL; mr_asprintf(&exclude_these_directories,"%s", call_program_and_get_last_line_of_output("mount -t coda,ncpfs,fuse.sshfs,nfs,nfs4,vmhgfs,smbfs,cifs,afs,gfs,ocfs,ocfs2,mvfs,nsspool,nssvol | tr -s '\t' ' ' | cut -d' ' -f3 | tr -s '\n' '|' | awk '{print $0;}'")); log_msg(9,"list_of_NETFS_mounts_only returns %s\n",exclude_these_directories); return(exclude_these_directories); } /* @} - end of utilityGroup */ /** * Create a randomly-named FIFO. The format is @p stub "." [random] [random] where * [random] is a random number between 1 and 32767. * @param store_name_here Where to store the new filename. * @param stub A random number will be appended to this to make the FIFO's name. * @ingroup deviceGroup */ void make_fifo(char *store_name_here, char *stub) { char *tmp; malloc_string(tmp); assert_string_is_neither_NULL_nor_zerolength(stub); sprintf(store_name_here, "%s%d%d", stub, (int) (random() % 32768), (int) (random() % 32768)); make_hole_for_file(store_name_here); mkfifo(store_name_here, S_IRWXU | S_IRWXG); sprintf(tmp, "chmod 770 %s", store_name_here); paranoid_system(tmp); paranoid_free(tmp); } /** * Set the tmpdir and scratchdir to reside on the partition with the most free space. * Automatically excludes DOS, NTFS, SMB, and NFS filesystems. * @param bkpinfo The backup information structure. @c bkpinfo->tmpdir and @c bkpinfo->scratchdir will be set. * @ingroup utilityGroup */ void sensibly_set_tmpdir_and_scratchdir() { char *tmp = NULL; char *tmp1 = NULL; char *command = NULL; char *sz = NULL; assert(bkpinfo != NULL); #ifdef __FreeBSD__ mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output("LANGUAGE=C df -m -P -t nonfs,msdosfs,ntfs,ntfs-3g,vmhgfs,smbfs,smb,cifs,afs,gfs,ocfs,ocfs2,mvfs,nsspool,nssvol | grep -vE \"none|Filesystem\" | awk '{printf \"%s %s\\n\", $4, $6;}' | sort -nr | awk '{print $NF;}' | while read x ; do test -w $x && echo $x && break ; done")); #else mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output("LANGUAGE=C df -m -P -x nfs -x nfs4 -x fuse.sshfs -x fuse -x vfat -x ntfs -x ntfs-3g -x vmhgfs -x smbfs -x smb -x cifs -x afs -x gfs -x ocfs -x ocfs2 -x mvfs -x nsspool -x nssvol -x iso9660 | grep -vE \"none|Filesystem|/dev/shm\" | awk '{printf \"%s %s\\n\", $4, $6;}' | sort -nr | awk '{print $NF;}' | while read x ; do test -w $x && echo $x && break ; done")); #endif if (tmp[0] != '/') { mr_asprintf(&sz, "%s", tmp); paranoid_free(tmp); mr_asprintf(&tmp, "/%s", sz); mr_free(sz); } if (!tmp[0]) { fatal_error("I couldn't figure out the tempdir!"); } setup_tmpdir(tmp); log_it("bkpinfo->tmpdir is being set to %s", bkpinfo->tmpdir); /* Before changing remove old ones if any */ if (bkpinfo->scratchdir) { chdir("/tmp"); mr_asprintf(&tmp1, "rm -Rf %s", bkpinfo->scratchdir); paranoid_system(tmp1); mr_free(tmp1); } sprintf(bkpinfo->scratchdir, "%s/mondo.scratch.%d", tmp, (int) (random() % 32768)); log_it("bkpinfo->scratchdir is being set to %s", bkpinfo->scratchdir); mr_asprintf(&command, "rm -Rf %s/tmp.mondo.* %s/mondo.scratch.*", tmp, tmp); paranoid_free(tmp); paranoid_system(command); mr_free(command); } /** * @addtogroup deviceGroup * @{ */ /** * If we can read @p dev, set @p output to it. * If @p dev cannot be read, set @p output to "". * @param dev The device to check for. * @param output Set to @p dev if @p dev exists, "" otherwise. * @return TRUE if @p dev exists, FALSE if it doesn't. */ bool set_dev_to_this_if_rx_OK(char *output, char *dev) { char *command; malloc_string(command); if (!dev || dev[0] == '\0') { output[0] = '\0'; return (FALSE); } // assert_string_is_neither_NULL_nor_zerolength(dev); if (!bkpinfo->please_dont_eject) { log_msg(10, "Injecting %s", dev); inject_device(dev); } if (!does_file_exist(dev)) { log_msg(10, "%s doesn't exist. Returning FALSE.", dev); return (FALSE); } sprintf(command, "dd bs=%ld count=1 if=%s of=/dev/null &> /dev/null", 512L, dev); if (!run_program_and_log_output(command, FALSE) && !run_program_and_log_output(command, FALSE)) { strcpy(output, dev); log_msg(4, "Found it - %s", dev); return (TRUE); } else { output[0] = '\0'; log_msg(4, "It's not %s", dev); return (FALSE); } } /** * Find out what number CD is in the drive. * @param bkpinfo The backup information structure. The @c bkpinfo->media_device field is the only one used. * @return The current CD number, or -1 if it could not be found. * @note If the CD is not mounted, it will be mounted * (and remain mounted after this function returns). */ int what_number_cd_is_this() { int cd_number = -1; char *mountdev = NULL; char *tmp = NULL; assert(bkpinfo != NULL); // log_it("Asking what_number_cd_is_this"); if (g_ISO_restore_mode) { mr_asprintf(&tmp, "mount | grep iso9660 | awk '{print $3;}'"); mr_asprintf(&mountdev, "%s%s", call_program_and_get_last_line_of_output(tmp), "/archives/THIS-CD-NUMBER"); cd_number = atoi(last_line_of_file(mountdev)); paranoid_free(mountdev); paranoid_free(tmp); return (cd_number); } mr_asprintf(&mountdev, "%s", bkpinfo->media_device); if (!mountdev[0]) { log_it ("(what_number_cd_is_this) Warning - media_device unknown. Finding out..."); find_cdrom_device(bkpinfo->media_device, FALSE); } if (!is_this_device_mounted(MNT_CDROM)) { if (bkpinfo->backup_media_type == usb) { mount_USB_here(mountdev, MNT_CDROM); } else { mount_CDROM_here(mountdev, MNT_CDROM); } } paranoid_free(mountdev); cd_number = atoi(last_line_of_file(MNT_CDROM "/archives/THIS-CD-NUMBER")); return (cd_number); } /** * Find out what device is mounted as root (/). * @return Root device. * @note The returned string points to static storage and will be overwritten with every call. * @bug A bit of a misnomer; it's actually finding out the root device. * The mountpoint (where it's mounted) will obviously be '/'. */ char *where_is_root_mounted() { /*@ buffers **************** */ static char tmp[MAX_STR_LEN]; #ifdef __FreeBSD__ strcpy(tmp, call_program_and_get_last_line_of_output ("mount | grep \" on / \" | cut -d' ' -f1")); #else strcpy(tmp, call_program_and_get_last_line_of_output ("mount | grep \" on / \" | cut -d' ' -f1 | sed s/[0-9]// | sed s/[0-9]//")); if (strstr(tmp, "/dev/cciss/")) { strcpy(tmp, call_program_and_get_last_line_of_output ("mount | grep \" on / \" | cut -d' ' -f1 | cut -dp -f1")); } if (strstr(tmp, "/dev/md")) { strcpy(tmp, call_program_and_get_last_line_of_output ("mount | grep \" on / \" | cut -d' ' -f1")); } #endif return (tmp); } /** * Find out which boot loader is in use. * @param which_device Device to look for the boot loader on. * @return 'L' for LILO, 'E'for ELILO, 'G' for GRUB, 'B' or 'D' for FreeBSD boot loaders, or 'U' for Unknown. * @note Under Linux, all drives are examined, not just @p which_device. */ #ifdef __FreeBSD__ char which_boot_loader(char *which_device) { int count_lilos = 0; int count_grubs = 0; int count_boot0s = 0; int count_dangerouslydedicated = 0; log_it("looking at drive %s's MBR", which_device); if (does_string_exist_in_boot_block(which_device, "GRUB")) { count_grubs++; } if (does_string_exist_in_boot_block(which_device, "LILO")) { count_lilos++; } if (does_string_exist_in_boot_block(which_device, "Drive")) { count_boot0s++; } if (does_string_exist_in_first_N_blocks (which_device, "FreeBSD/i386", 17)) { count_dangerouslydedicated++; } 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); if (count_grubs && !count_lilos) { return ('G'); } else if (count_lilos && !count_grubs) { return ('L'); } else if (count_grubs == 1 && count_lilos == 1) { log_it("I'll bet you used to use LILO but switched to GRUB..."); return ('G'); } else if (count_boot0s == 1) { return ('B'); } else if (count_dangerouslydedicated) { return ('D'); } else { log_it("Unknown boot loader"); return ('U'); } } #else char which_boot_loader(char *which_device) { /*@ buffer ***************************************************** */ char *list_drives_cmd = NULL; char *current_drive; /*@ pointers *************************************************** */ FILE *pdrives; /*@ int ******************************************************** */ int count_lilos = 0; int count_grubs = 0; /*@ end vars *************************************************** */ malloc_string(current_drive); #ifdef __IA64__ /* No choice for it */ return ('E'); #endif assert(which_device != NULL); mr_asprintf(&list_drives_cmd, "parted2fdisk -l 2>/dev/null | grep \"/dev/.*:\" | tr -s ':' ' ' | tr -s ' ' '\n' | grep /dev/; echo %s", where_is_root_mounted()); log_it("list_drives_cmd = %s", list_drives_cmd); if (!(pdrives = popen(list_drives_cmd, "r"))) { log_OS_error("Unable to open list of drives"); mr_free(list_drives_cmd); paranoid_free(current_drive); return ('\0'); } mr_free(list_drives_cmd); for ((void)fgets(current_drive, MAX_STR_LEN, pdrives); !feof(pdrives); (void)fgets(current_drive, MAX_STR_LEN, pdrives)) { strip_spaces(current_drive); log_it("looking at drive %s's MBR", current_drive); if (does_string_exist_in_boot_block(current_drive, "GRUB")) { count_grubs++; strcpy(which_device, current_drive); break; } if (does_string_exist_in_boot_block(current_drive, "LILO")) { count_lilos++; strcpy(which_device, current_drive); break; } } if (pclose(pdrives)) { log_OS_error("Cannot pclose pdrives"); } log_it("%d grubs and %d lilos\n", count_grubs, count_lilos); if (count_grubs && !count_lilos) { paranoid_free(current_drive); return ('G'); } else if (count_lilos && !count_grubs) { paranoid_free(current_drive); return ('L'); } else if (count_grubs == 1 && count_lilos == 1) { log_it("I'll bet you used to use LILO but switched to GRUB..."); paranoid_free(current_drive); return ('G'); } else { // We need to look on each partition then mr_asprintf(&list_drives_cmd, "parted2fdisk -l 2>/dev/null | grep -E \"^/dev/\" | tr -s ':' ' ' | tr -s ' ' '\n' | grep /dev/"); log_it("list_drives_cmd = %s", list_drives_cmd); if (!(pdrives = popen(list_drives_cmd, "r"))) { log_OS_error("Unable to open list of drives"); mr_free(list_drives_cmd); paranoid_free(current_drive); return ('\0'); } mr_free(list_drives_cmd); for ((void)fgets(current_drive, MAX_STR_LEN, pdrives); !feof(pdrives); (void)fgets(current_drive, MAX_STR_LEN, pdrives)) { strip_spaces(current_drive); log_it("looking at partition %s's BR", current_drive); if (does_string_exist_in_boot_block(current_drive, "GRUB")) { count_grubs++; strcpy(which_device, current_drive); break; } if (does_string_exist_in_boot_block(current_drive, "LILO")) { count_lilos++; strcpy(which_device, current_drive); break; } } if (pclose(pdrives)) { log_OS_error("Cannot pclose pdrives"); } log_it("%d grubs and %d lilos\n", count_grubs, count_lilos); paranoid_free(current_drive); if (count_grubs && !count_lilos) { return ('G'); } else if (count_lilos && !count_grubs) { return ('L'); } else if (count_grubs == 1 && count_lilos == 1) { log_it("I'll bet you used to use LILO but switched to GRUB..."); return ('G'); } else { log_it("Unknown boot loader"); return ('U'); } } } #endif /** * Write zeroes over the first 16K of @p device. * @param device The device to zero. * @return 0 for success, 1 for failure. */ int zero_out_a_device(char *device) { FILE *fout; int i; assert_string_is_neither_NULL_nor_zerolength(device); log_it("Zeroing drive %s", device); if (!(fout = fopen(device, "w"))) { log_OS_error("Unable to open/write to device"); return (1); } for (i = 0; i < 16384; i++) { fputc('\0', fout); } paranoid_fclose(fout); log_it("Device successfully zeroed."); return (0); } /** * Return the device pointed to by @p incoming. * @param incoming The device to resolve symlinks for. * @return The path to the real device file. * @note The returned string points to static storage that will be overwritten with each call. * @bug Won't work with file v4.0; needs to be written in C. */ char *resolve_softlinks_to_get_to_actual_device_file(char *incoming) { static char output[MAX_STR_LEN]; char *command; char *curr_fname; char *scratch = NULL; char *tmp = NULL; char *p; struct stat statbuf; command = malloc(1000); malloc_string(curr_fname); if (!does_file_exist(incoming)) { log_it ("resolve_softlinks_to_get_to_actual_device_file --- device not found"); strcpy(output, incoming); } else { strcpy(curr_fname, incoming); lstat(curr_fname, &statbuf); while (S_ISLNK(statbuf.st_mode)) { log_msg(1, "curr_fname = %s", curr_fname); sprintf(command, "file %s", curr_fname); mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output(command)); for (p = tmp + strlen(tmp); p != tmp && *p != '`' && *p != ' '; p--); p++; mr_asprintf(&scratch, "%s", p); for (p = scratch; *p != '\0' && *p != '\''; p++); *p = '\0'; log_msg(0, "curr_fname %s --> '%s' --> %s", curr_fname, tmp, scratch); mr_free(tmp); if (scratch[0] == '/') { strcpy(curr_fname, scratch); // copy whole thing because it's an absolute softlink } else { // copy over the basename cos it's a relative softlink p = curr_fname + strlen(curr_fname); while (p != curr_fname && *p != '/') { p--; } if (*p == '/') { p++; } strcpy(p, scratch); } mr_free(scratch); lstat(curr_fname, &statbuf); } strcpy(output, curr_fname); log_it("resolved %s to %s", incoming, output); } paranoid_free(command); paranoid_free(curr_fname); return (output); } /* @} - end of deviceGroup */ /** * Return the type of partition format (GPT or MBR) */ char *which_partition_format(const char *drive) { static char output[4]; char *tmp = NULL; char *command; char *fdisk; #ifdef __IA64__ struct stat buf; #endif malloc_string(command); malloc_string(fdisk); sprintf(fdisk, "/sbin/parted2fdisk"); sprintf(command, "%s -l %s | grep 'EFI GPT'", fdisk, drive); mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output(command)); if (strstr(tmp, "GPT") == NULL) { strcpy(output, "MBR"); } else { strcpy(output, "GPT"); } mr_free(tmp); log_msg(0, "Found %s partition table format type", output); paranoid_free(command); paranoid_free(fdisk); return (output); } /* @} - end of deviceGroup */