Ignore:
Timestamp:
Mar 9, 2024, 3:10:04 AM (4 months ago)
Author:
Bruno Cornec
Message:

Fix all remaining compiler errors

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/3.3/mondo/src/common/libmondo-devices.c

    r3878 r3879  
    8080
    8181/**
    82  * Retract all CD trays and wait for autorun to complete.
    83  * @ingroup deviceGroup
    84  */
    85 void retract_CD_tray_and_defeat_autorun(void)
    86 {
    87 //  log_it("rctada: Retracting optical tray", __LINE__);
    88     if (!bkpinfo->please_dont_eject) {
    89         if (bkpinfo->media_device != NULL) {
    90             inject_device(bkpinfo->media_device);
    91     }
    92     if (!run_program_and_log_output("ps | grep autorun | grep -v grep", 5)) {
    93         log_it("autorun detected; sleeping for 2 seconds");
    94         sleep(2);
    95     }
    96 }
    97 
    98 
    99 
    100 /**
    101  * Find out what device is mounted as root (/).
    102  * @return Root device.
    103  * @note The returned string points to storage that needs to be freed by
    104  * caller
    105  * @bug A bit of a misnomer; it's actually finding out the root device.
    106  * The mountpoint (where it's mounted) will obviously be '/'.
    107  */
    108 char *where_is_root_mounted(void) {
    109 
    110 /*@ buffers **************** */
    111 char *tmp = NULL;
    112 
    113 #ifdef __FreeBSD__
    114     tmp = call_program_and_get_last_line_of_output("mount | grep \" on / \" | cut -d' ' -f1");
    115 #else
    116     tmp = call_program_and_get_last_line_of_output("mount | grep \" on / \" | cut -d' ' -f1 | sed s/[0-9]// | sed s/[0-9]//");
    117     if (strstr(tmp, "/dev/cciss/")) {
    118         mr_free(tmp);
    119         tmp = call_program_and_get_last_line_of_output("mount | grep \" on / \" | cut -d' ' -f1 | cut -dp -f1");
    120     }
    121     if (strstr(tmp, "/dev/md")) {
    122         mr_free(tmp);
    123         tmp = call_program_and_get_last_line_of_output("mount | grep \" on / \" | cut -d' ' -f1");
    124     }
    125 #endif
    126 
    127 return (tmp);
    128 }
    129 
    130 
    131 
    132 /**
    133  * Determine whether we're booted off a ramdisk.
    134  * @return @c TRUE (we are) or @c FALSE (we aren't).
    135  * @ingroup utilityGroup
    136  */
    137 bool am_I_in_disaster_recovery_mode(void)
    138 {
    139     char *tmp = NULL;
    140     bool is_this_a_ramdisk = FALSE;
    141 
    142     tmp = where_is_root_mounted();
    143     log_msg(0, "root is mounted at %s", tmp);
    144     log_msg(0, "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);
    145 
    146 #ifdef __FreeBSD__
    147     if (strstr(tmp, "/dev/md")) {
    148         is_this_a_ramdisk = TRUE;
    149     }
    150 #else
    151     if (!strncmp(tmp, "/dev/ram", 8)
    152         || (!strncmp(tmp, "/dev/rd", 7) && !strcmp(tmp, "/dev/rd/")
    153             && strncmp(tmp, "/dev/rd/cd", 10)) || strstr(tmp, "rootfs")
    154         || !strcmp(tmp, "/dev/root")) {
    155         is_this_a_ramdisk = TRUE;
    156     } else {
    157         is_this_a_ramdisk = FALSE;
    158     }
    159 #endif
    160     mr_free(tmp);
    161 
    162     if (is_this_a_ramdisk) {
    163         if (!does_file_exist("/THIS-IS-A-RAMDISK")) {
    164             log_to_screen("Using /dev/root is stupid of you but I'll forgive you.");
    165             is_this_a_ramdisk = FALSE;
    166         }
    167     }
    168     if (does_file_exist("/THIS-IS-A-RAMDISK")) {
    169         is_this_a_ramdisk = TRUE;
    170     }
    171 
    172     log_msg(1, "Is this a ramdisk? result = %s", (is_this_a_ramdisk) ? "TRUE" : "FALSE");
    173     return (is_this_a_ramdisk);
    174 }
    175 
    176 
    177 
    178 
    179 
    180 /**
    181  * Turn @c bkpinfo->backup_media_type into a human-readable string.
    182  * @return The human readable string (e.g. @c cdr becomes <tt>"cdr"</tt>).
    183  * @note The returned string points to static storage that will be overwritten with each call.
    184  * @ingroup stringGroup
    185  */
    186 static char *bkptype_to_string(t_bkptype bt)
    187 {
    188     static char output[MAX_STR_LEN / 4];
    189     switch (bt) {
    190     case none:
    191         strcpy(output, "none");
    192         break;
    193     case iso:
    194         strcpy(output, "iso");
    195         break;
    196     case cdr:
    197         strcpy(output, "cdr");
    198         break;
    199     case cdstream:
    200         strcpy(output, "cdstream");
    201         break;
    202     case netfs:
    203         strcpy(output, "netfs");
    204         break;
    205     case tape:
    206         strcpy(output, "tape");
    207         break;
    208     case udev:
    209         strcpy(output, "udev");
    210         break;
    211     case usb:
    212         strcpy(output, "usb");
    213         break;
    214     default:
    215         strcpy(output, "default");
    216     }
    217     return (output);
    218 }
    219 
    220 
    221 
    222 /**
    223  * @addtogroup deviceGroup
    224  * @{
    225  */
    226 /**
    227  * Eject the tray of the specified CD device.
    228  * @param dev The device to eject.
    229  * @return the return value of the @c eject command. (0=success, nonzero=failure)
    230  */
    231 int eject_device(char *dev)
    232 {
    233     char *command = NULL;
    234     int res1 = 0, res2 = 0;
    235 
    236     if (dev == NULL) {
    237         return (1);
    238     }
    239 
    240     if (IS_THIS_A_STREAMING_BACKUP(g_backup_media_type)
    241         && g_backup_media_type != udev) {
    242         mr_asprintf(command, "mt -f %s offline", dev);
    243         res1 = run_program_and_log_output(command, 1);
    244         mr_free(command);
    245     } else {
    246         res1 = 0;
    247     }
    248 
    249 #ifdef __FreeBSD__
    250     if (strstr(dev, "acd")) {
    251         mr_asprintf(command, "cdcontrol -f %s eject", dev);
    252     } else {
    253         mr_asprintf(command, "camcontrol eject `echo %s | sed 's|/dev/||'`", dev);
    254     }
    255 #else
    256     mr_asprintf(command, "eject %s", dev);
    257 #endif
    258 
    259     log_msg(3, "Ejecting %s", dev);
    260     res2 = run_program_and_log_output(command, 1);
    261     mr_free(command);
    262     if (res1 && res2) {
    263         return (1);
    264     } else {
    265         return (0);
    266     }
    267 }
    268 
    269 /**
    270  * Load (inject) the tray of the specified CD device.
    271  * @param dev The device to load/inject.
    272  * @return 0 for success, nonzero for failure.
    273  */
    274 int inject_device(char *dev)
    275 {
    276     char *command = NULL;
    277     int i;
    278 
    279     if (dev == NULL) {
    280         return (1);
    281     }
    282 
    283 #ifdef __FreeBSD__
    284     if (strstr(dev, "acd")) {
    285         mr_asprintf(command, "cdcontrol -f %s close", dev);
    286     } else {
    287         mr_asprintf(command, "camcontrol load `echo %s | sed 's|/dev/||'`", dev);
    288     }
    289 #else
    290     mr_asprintf(command, "eject -t %s", dev);
    291 #endif
    292     i = run_program_and_log_output(command, FALSE);
    293     mr_free(command);
    294     return (i);
    295 }
    296 
    297 
    298 /**
    299  * Determine whether the specified @p device (really, you can use any file)
    300  * exists.
    301  * @return TRUE if it exists, FALSE if it doesn't.
    302  */
    303 bool does_device_exist(char *device)
    304 {
    305 
    306     /*@ buffers *********************************************************** */
    307     char *tmp = NULL;
    308     bool ret;
    309 
    310     assert_string_is_neither_NULL_nor_zerolength(device);
    311 
    312     mr_asprintf(tmp, "ls %s > /dev/null 2> /dev/null", device);
    313 
    314     if (system(tmp)) {
    315         ret = FALSE;
    316     } else {
    317         ret = TRUE;
    318     }
    319     mr_free(tmp);
    320     return (ret);
    321 }
    322 
    323 
    324 /**
    325  * Determine whether a non-Microsoft partition exists on any connected hard drive.
    326  * @return TRUE (there's a Linux/FreeBSD partition) or FALSE (Microsoft has taken over yet another innocent machine).
    327  */
    328 bool does_nonMS_partition_exist(void)
    329 {
    330 #if __FreeBSD__
    331     return
    332         !system("for drive in /dev/ad? /dev/da?; do fdisk $drive | grep -q FreeBSD && exit 0; done; false");
    333 #else
    334     return
    335         !system("mr-parted2fdisk -l 2>/dev/null | grep '^/dev/' | grep -Eqv '(MS|DOS|EFI|FAT|NTFS)'");
    336 #endif
    337 }
    338 
    339 /**
    340  * Determine whether the specified @p partno exists on the specified @p drive.
    341  * @param drive The drive to search for the partition in.
    342  * @param partno The partition number to look for.
    343  * @return 0 if it exists, nonzero otherwise.
    344  */
    345 int does_partition_exist(const char *drive, int partno)
    346 {
    347     /*@ buffers **************************************************** */
    348     char *program = NULL;
    349     char *incoming = NULL;
    350     char *searchstr = NULL;
    351 
    352     /*@ ints ******************************************************* */
    353     int res = 0;
    354 
    355     /*@ pointers *************************************************** */
    356     FILE *fin;
    357 
    358     /*@ end vars *************************************************** */
    359     assert_string_is_neither_NULL_nor_zerolength(drive);
    360     assert(partno >= 0 && partno < 999);
    361 
    362 #ifdef __FreeBSD__
    363     // We assume here that this is running from mondorestore. (It is.)
    364     tmp = build_partition_name(drive, partno);
    365     mr_asprintf(program, "ls %s %s >/dev/null 2>&1", drive, tmp);
    366     mr_free(tmp);
    367     res = system(program);
    368     mr_free(program);
    369     return(res);
    370 #endif
    371 
    372     mr_asprintf(program, "mr-parted2fdisk -l %s 2> /dev/null", drive);
    373     fin = popen(program, "r");
    374     if (!fin) {
    375         log_it("program=%s", program);
    376         log_OS_error("Cannot popen-in program");
    377         mr_free(program);
    378         return (0);
    379     }
    380     mr_free(program);
    381 
    382     searchstr = build_partition_name(drive, partno);
    383     mr_strcat(searchstr, " ");
    384     for (res = 0, mr_getline(incoming, fin); !res && !feof(fin) ; mr_getline(incoming, fin)) {
    385         if (strstr(incoming, searchstr)) {
    386             res = 1;
    387         }
    388         mr_free(incoming);
    389     }
    390     mr_free(searchstr);
    391     mr_free(incoming);
    392 
    393     if (pclose(fin)) {
    394         log_OS_error("Cannot pclose fin");
    395     }
    396     return (res);
    397 }
    398 
    399 
    400 
    401 
    402 
    403 /**
    404  * Determine whether given NULL-terminated @p str exists in the begining of @p dev.
    405  * @param dev The device to look in.
    406  * @param str The string to look for.
    407  * @return TRUE if it exists, FALSE if it doesn't.
    408  */
    409 bool does_string_exist_in_boot_block(char *dev, char *str)
    410 {
    411     /*@ buffers **************************************************** */
    412     char *command = NULL;
    413 
    414     /*@ end vars *************************************************** */
    415     int i;
    416 
    417     assert_string_is_neither_NULL_nor_zerolength(dev);
    418     assert_string_is_neither_NULL_nor_zerolength(str);
    419 
    420     /* For UEFI detection, this should be extended to count=1000 ! */
    421     if (bkpinfo->boot_type == UEFI) {
    422         mr_asprintf(command, "dd if=%s bs=446 count=1000 2> /dev/null | strings | grep \"%s\" > /dev/null 2> /dev/null", dev, str);
    423     } else {
    424         mr_asprintf(command, "dd if=%s bs=446 count=1 2> /dev/null | strings | grep \"%s\" > /dev/null 2> /dev/null", dev, str);
    425     }
    426     i = system(command);
    427     mr_free(command);
    428     if (i) {
    429         return (FALSE);
    430     } else {
    431         return (TRUE);
    432     }
    433 }
    434 
    435 /**
    436  * Determine whether specified @p str exists in the first @p n sectors of
    437  * @p dev.
    438  * @param dev The device to look in.
    439  * @param str The string to look for.
    440  * @param n The number of 512-byte sectors to search.
    441  */
    442 bool does_string_exist_in_first_N_blocks(char *dev, char *str, int n)
    443 {
    444     /*@ buffers **************************************************** */
    445     char *command = NULL;
    446     /*@ end vars *************************************************** */
    447     int i;
    448 
    449     mr_asprintf(command, "dd if=%s bs=512 count=%i 2> /dev/null | strings | grep \"%s\" > /dev/null 2> /dev/null", dev, n, str);
    450     i = system(command);
    451     mr_free(command);
    452     if (i) {
    453         return (FALSE);
    454     } else {
    455         return (TRUE);
    456     }
    457 }
    458 
    459 
    460 /*
    461  * This function tries to find an optical media device
    462  * and return it's device file to the caller that needs to free it
    463  */
    464 char *find_optical_device(void) {
    465     char *dev = NULL;
    466     char *tmp1 = NULL;
    467     char *command = NULL;
    468 
    469     log_to_screen("I am looking for your optical burner. Please wait.");
    470 
    471     if (bkpinfo->media_device != NULL) {
    472         log_msg(3, "Been there, done that. Returning %s", bkpinfo->media_device);
    473         return (bkpinfo->media_device);
    474     }
    475 
    476     mr_asprintf(tmp1, "cdrecord -inq 2> /dev/null | grep -E '^Detected '  | cut -d':' -f2");
    477     dev = call_program_and_get_last_line_of_output(tmp1);
    478     mr_free(tmp1);
    479 
    480     if ((dev != NULL) && does_file_exist(dev)) {
    481         log_msg(2, "find_optical_device found %s automatically", dev);
    482     } else {
    483         mr_free(dev);
    484         tmp1 = find_home_of_exe("lsscsi");
    485         if (tmp1 != NULL) {
    486             mr_asprintf(command, "%s | grep ' cd' | awk '{print $NF}' | head -1", tmp1);
    487             dev = call_program_and_get_last_line_of_output(command);
    488             mr_free(command);
    489         }
    490         mr_free(tmp1);
    491 
    492         if ((dev == NULL) || !does_file_exist(dev)) {
    493             /* trying something else then */
    494             mr_asprintf(dev, "%s", VANILLA_SCSI_CDROM);
    495             if (!does_file_exist(dev)) {
    496                 mr_asprintf(dev, "%s", ALT_CDROM);
    497                 if (!does_file_exist(dev)) {
    498                     mr_asprintf(dev, "%s", "/dev/cdrom");
    499                     if (!does_file_exist(dev)) {
    500                         mr_asprintf(dev, "%s", "/dev/dvd");
    501                         if (!does_file_exist(dev)) {
    502                             log_it("Unable to find a tape device on this system");
    503                         }
    504                     }
    505                 }
    506             }
    507         }
    508         if (dev != NULL) {
    509             log_it("find_optical_device found %s manually", dev);
    510         }
    511     }
    512 
    513     if ((dev != NULL) && does_file_exist(dev)) {
    514         log_it("find_optical_device returns %s", dev);
    515     } else {
    516         mr_free(dev);
    517         log_it("find_optical_device found no optical burner on your system returning NULL");
    518     }
    519     return(dev);
    520 }
    521 /**
    522 * Mount the CD-ROM or USB device at /mnt/cdrom.
    523 * @param bkpinfo The backup information structure. Fields used:
    524 * - @c bkpinfo->backup_media_type
    525 * - @c bkpinfo->disaster_recovery
    526 * - @c bkpinfo->isodir
    527 * - @c bkpinfo->media_device
    528 * @return TRUE for success, FALSE for failure.
    529 */
    530 bool mount_media(const char *mountpoint) {
    531 
    532     char *mount_cmd = NULL;
    533     char *mountdir = NULL;
    534     char *tmp = NULL;
    535     int i = 0, res = 0;
    536 #ifdef __FreeBSD__
    537     char mdd[32];
    538     char *mddev = mdd;
    539     char *dev;
    540 #endif
    541 
    542     if (bkpinfo->backup_media_type == tape || bkpinfo->backup_media_type == udev) {
    543         log_msg(8, "Tape/udev. Therefore, no need to mount a media.");
    544         return(TRUE);
    545     }
    546 
    547     assert_string_is_neither_NULL_nor_zerolength(mountpoint);
    548 
    549     mr_asprintf(tmp, "mount | grep -F %s", mountpoint);
    550     if (!run_program_and_log_output(tmp, FALSE)) {
    551         log_msg(2, "mount_media() - media already mounted. Fair enough.");
    552         mr_free(tmp);
    553         return (TRUE);
    554     }
    555     mr_free(tmp);
    556 
    557     make_hole_for_dir(mountpoint);
    558 
    559     if (bkpinfo->backup_media_type == netfs) {
    560         log_msg(2, "Mounting for Network thingy");
    561         log_msg(2, "isodir = %s", bkpinfo->isodir);
    562         if (((bkpinfo->isodir == NULL) || !strcmp(bkpinfo->isodir, "/")) && am_I_in_disaster_recovery_mode()) {
    563             mr_asprintf(bkpinfo->isodir, "%s", "/tmp/isodir");
    564             log_msg(1, "isodir is being set to %s", bkpinfo->isodir);
    565         }
    566 #ifdef __FreeBSD__
    567         if (bkpinfo->netfs_remote_dir != NULL) {
    568             // NETFS
    569             mr_asprintf(mount_cmd, "/mnt/isodir/%s/%s/%s-%d.iso", bkpinfo->isodir, bkpinfo->netfs_remote_dir, bkpinfo->prefix, g_current_media_number);
    570         } else {
    571             // ISO
    572             mr_asprintf(mount_cmd, "/mnt/isodir/%s/%s-%d.iso", bkpinfo->isodir, bkpinfo->prefix, g_current_media_number);
    573         }
    574         mddev = make_vn(mount_cmd);
    575         mr_free(mount_cmd);
    576 
    577         mr_asprintf(mount_cmd, "mount_cd9660 -r %s %s", mddev, mountpoint);
    578 #else
    579         if (bkpinfo->netfs_remote_dir != NULL) {
    580             // NETFS
    581             mr_asprintf(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, mountpoint);
    582         } else {
    583             // ISO
    584             mr_asprintf(mount_cmd, "mount %s/%s-%d.iso -t iso9660 -o loop,ro %s", bkpinfo->isodir, bkpinfo->prefix, g_current_media_number, mountpoint);
    585         }
    586 #endif
    587 
    588     } else if (bkpinfo->backup_media_type == iso) {
    589         if (bkpinfo->subdir) {
    590             mr_asprintf(mountdir, "%s/%s", bkpinfo->isodir, bkpinfo->subdir);
    591         } else {
    592             mr_asprintf(mountdir, "%s", bkpinfo->isodir);
    593         }
    594 #ifdef __FreeBSD__
    595         mr_asprintf(mount_cmd, "%s/%s-%d.iso", mountdir, bkpinfo->prefix, g_current_media_number);
    596         mddev = make_vn(mount_cmd);
    597         mr_free(mount_cmd);
    598 
    599         mr_asprintf(mount_cmd, "mount_cd9660 -r %s %s", mddev, mountpoint);
    600 #else
    601         mr_asprintf(mount_cmd, "mount %s/%s-%d.iso -t iso9660 -o loop,ro %s", mountdir, bkpinfo->prefix, g_current_media_number, mountpoint);
    602 #endif
    603         mr_free(mountdir);
    604     } else if (bkpinfo->backup_media_type == usb) {
    605         mr_asprintf(mount_cmd, "mount -t vfat %s %s", bkpinfo->media_device, mountpoint);
    606     } else {    //  optical
    607         if (bkpinfo->disaster_recovery
    608             && does_file_exist("/tmp/CDROM-LIVES-HERE")) {
    609             mr_asprintf(bkpinfo->media_device, "%s", last_line_of_file("/tmp/CDROM-LIVES-HERE"));
    610         } else {
    611             if (bkpinfo->media_device == NULL) {
    612                 bkpinfo->media_device = find_optical_device();
    613             }
    614         }
    615 
    616 #ifdef __FreeBSD__
    617         if (g_ISO_restore_mode) {
    618             mr_asprintf(dev, "%s", make_vn(bkpinfo->media_device));
    619             if (!dev) {
    620                 mr_asprintf(command, "Unable to mount ISO (make_vn(%s) failed)", bkpinfo->media_device);
    621                 fatal_error(command);
    622             }
    623             mr_free(bkpinfo->media_device);
    624             bkpinfo->media_device = dev
    625         }
    626 
    627         mr_asprintf(mount_cmd, "mount_cd9660 -r %s %s 2>> %s", bkpinfo->media_device, mountpoint, MONDO_LOGFILE);
    628 #else
    629         mr_asprintf(mount_cmd, "mount %s -o loop,ro -t iso9660 %s 2>> %s", bkpinfo->media_device, mountpoint, MONDO_LOGFILE);
    630 #endif
    631         log_msg(2, "(mount_media) --- command = %s", mount_cmd);
    632         // usefull ??
    633         if (strncmp(bkpinfo->media_device, "/dev/", 5) == 0) {
    634             retract_CD_tray_and_defeat_autorun();
    635         }
    636     }
    637 
    638     for (i = 0; i < 2; i++) {
    639         res = run_program_and_log_output(mount_cmd, FALSE);
    640         if (!res) {
    641             break;
    642         } else {
    643             log_msg(2, "Failed to mount device.");
    644             sleep(5);
    645             sync();
    646         }
    647     }
    648     mr_free(mount_cmd);
    649 
    650     if (res) {
    651         log_msg(2, "Failed, despite %d attempts", i);
    652         return(FALSE);
    653     } else {
    654         log_msg(2, "Mounted media drive OK");
    655         return(TRUE);
    656     }
    657 }
    658 /**************************************************************************
    659 *END_MOUNT_MEDIA                                                         *
    660 **************************************************************************/
    661 
    662 
    663 
    664 
    665 /**
    666  * Try to mount CD/DVD at @p mountpoint. If the CD/DVD is not found or has
    667  * not been specified, call find_optical_device() to find it.
    668  * @param mountpoint Where to mount the CD-ROM.
    669  * @return TRUE for success, FALSE for failure.
    670  * @see mount_media
    671  */
    672 bool find_and_mount_actual_cd(char *mountpoint) {
    673 
    674     /*@ buffers ***************************************************** */
    675 
    676     /*@ int's  ****************************************************** */
    677     bool res;
    678 
    679     /*@ end vars **************************************************** */
    680 
    681     assert(bkpinfo != NULL);
    682     assert_string_is_neither_NULL_nor_zerolength(mountpoint);
    683 
    684     if (bkpinfo->media_device == NULL) {
    685         bkpinfo->media_device = find_optical_device();
    686     }
    687 
    688     if (bkpinfo->backup_media_type != iso) {
    689         retract_CD_tray_and_defeat_autorun();
    690     }
    691 
    692     if ((bkpinfo->media_device == NULL) || (res = mount_media(mountpoint))) {
    693         mr_free(bkpinfo->media_device);
    694         if ((bkpinfo->media_device = mr_popup_and_get_string("CD-ROM device", "Please enter your CD-ROM's /dev device", "/dev/cdrom")) == NULL) {
    695             res = TRUE;
    696         } else {
    697             res = mount_media(mountpoint);
    698         }
    699     }
    700     if (res) {
    701         log_msg(1, "mount failed");
    702     } else {
    703         log_msg(1, "mount succeeded with %s", bkpinfo->media_device);
    704     }
    705     return (res);
    706 }
    707 /*
    708  * This function tries to find a USB media device
    709  * and return it's device file to the caller that needs to free it
    710  */
    711 char *find_usb_device(void)
    712 {
    713     char *dev = NULL;
    714     char *tmp1 = NULL;
    715     char *command = NULL;
    716 
    717     log_to_screen("I am looking for your USB key. Please wait.");
    718 
    719     if (bkpinfo->media_device != NULL) {
    720         log_msg(3, "Been there, done that. Returning %s", bkpinfo->media_device);
    721         return (bkpinfo->media_device);
    722     }
    723 
    724     tmp1 = find_home_of_exe("lsscsi");
    725     if (tmp1 != NULL) {
    726         mr_asprintf(command, "%s | grep ' disk' | grep USB | awk '{print $NF}' | head -1", tmp1);
    727         dev = call_program_and_get_last_line_of_output(command);
    728         mr_free(command);
    729     }
    730     mr_free(tmp1);
    731 
    732     if ((dev == NULL) || !does_file_exist(dev)) {
    733         tmp1 = find_home_of_exe("lsblk");
    734         if (tmp1 != NULL) {
    735             mr_asprintf(command, "%s --noheadings --raw --output rm,tran,type,path --sort path | awk '/^1 usb disk/ {d=$4} END {print d}'", tmp1);
    736             dev = call_program_and_get_last_line_of_output(command);
    737             mr_free(command);
    738         }
    739         mr_free(tmp1);
    740         log_it("Unable to find a tape device on this system");
    741     }
    742     if (dev != NULL) {
    743         log_it("find_usb_device found %s manually", dev);
    744     }
    745 
    746     if ((dev != NULL) && does_file_exist(dev)) {
    747         log_it("find_usb_device returns %s", dev);
    748     } else {
    749         mr_free(dev);
    750         log_it("find_usb_device found no USB key on your system returning NULL");
    751     }
    752     return(dev);
    753 }
    754 
    755 
    756 
    757 /* Generic fund to find a media
    758  * Return a dynamically allocted string that caller needs to free
    759  * @media_type is the type of media to look for
    760  */
    761 
    762 char *find_device(t_bkptype media_type) {
    763 
    764     if (media_type == usb) {
    765         return(find_usb_device());
    766     } else if (media_type == tape) {
    767         return(find_tape_device());
    768     } else if ((media_type == dvd) || (media_type == cdr)) {
    769         return(find_optical_device());
    770     } else {
    771         return(NULL);
    772     }
    773 }
    774 
    775 
    776 
    777 
    778 #include <sys/ioctl.h>
    779 
    780 /**
    781  * Find the size of the specified @p drive, in megabytes. Uses @c ioctl calls
    782  * and @c dmesg.
    783  * @param drive The device to find the size of.
    784  * @return size in megabytes.
    785  */
    786 long get_phys_size_of_drive(char *drive)
    787 {
    788     int fd;
    789 #if linux
    790     unsigned long long s = 0;
    791     int fileid, cylinders = 0;
    792     int cylindersize = 0;
    793     int gotgeo = 0;
    794 
    795 
    796     struct hd_geometry hdgeo;
    797 #elif __FreeBSD__
    798     off_t s;
    799 #endif
    800 
    801     long outvalA = -1;
    802     long outvalB = -1;
    803     long outvalC = -1;
    804 
    805     if ((fd = open(drive, O_RDONLY)) != -1) {
    806         if (ioctl(fd,
    807 #if linux
    808 #ifdef BLKGETSIZE64
    809                   BLKGETSIZE64,
    810 #else
    811                   BLKGETSIZE,
    812 #endif
    813 #elif __FreeBSD__
    814                   DIOCGMEDIASIZE,
    815 #endif
    816                   &s) != -1) {
    817             close(fd);
    818             // s>>11 works for older disks but not for newer ones
    819             outvalB =
    820 #if linux
    821 #ifdef BLKGETSIZE64
    822                 s >> 20
    823 #else
    824                 s >> 11
    825 #endif
    826 #else
    827                 s >> 20
    828 #endif
    829                 ;
    830         }
    831     }
    832 
    833     if (outvalB <= 0) {
    834         log_msg(1, "Error getting size of %s: %s", drive, strerror(errno));
    835 #if linux
    836         fileid = open(drive, O_RDONLY);
    837         if (fileid != -1) {
    838             if (ioctl(fileid, HDIO_GETGEO, &hdgeo) != -1) {
    839                 if (hdgeo.cylinders && hdgeo.heads && hdgeo.sectors) {
    840                     cylindersize = hdgeo.heads * hdgeo.sectors / 2;
    841                     outvalA = cylindersize * cylinders / 1024;
    842                     log_msg(2, "Got Harddisk geometry, C:%d, H:%d, S:%d",
    843                             hdgeo.cylinders, hdgeo.heads, hdgeo.sectors);
    844                     gotgeo = 1;
    845                 } else {
    846                     log_msg(1, "Harddisk geometry wrong");
    847                 }
    848             } else {
    849                 log_msg(1,
    850                         "Error in ioctl() getting new hard disk geometry (%s), resizing in unsafe mode",
    851                         strerror(errno));
    852             }
    853             close(fileid);
    854         } else {
    855             log_msg(1, "Failed to open %s for reading: %s", drive,
    856                     strerror(errno));
    857         }
    858         if (!gotgeo) {
    859             log_msg(1, "Failed to get harddisk geometry, using old mode");
    860         }
    861 #endif
    862     }
    863 // OLDER DISKS will give ridiculously low value for outvalB (so outvalA is returned) :)
    864 // NEWER DISKS will give sane value for outvalB (close to outvalA, in other words) :)
    865 
    866     outvalC = (outvalA > outvalB) ? outvalA : outvalB;
    867 
    868 //  log_msg (5, "drive = %s, error = %s", drive, strerror (errno));
    869 //  fatal_error ("GPSOD: Unable to get size of drive");
    870     log_msg(1, "%s --> %ld or %ld --> %ld", drive, outvalA, outvalB,
    871             outvalC);
    872 
    873     return (outvalC);
    874 }
    875 
    876 /**
    877  * Determine whether @p format is supported by the kernel. Uses /proc/filesystems
    878  * under Linux and @c lsvfs under FreeBSD.
    879  * @param format The format to test.
    880  * @return TRUE if the format is supported, FALSE if not.
    881  */
    882 bool is_this_a_valid_disk_format(char *format)
    883 {
    884     char *good_formats = NULL;
    885     char *command = NULL;
    886     char *format_sz = NULL;
    887     char *p = NULL;
    888 
    889     FILE *pin;
    890     int retval;
    891 
    892     assert_string_is_neither_NULL_nor_zerolength(format);
    893 
    894     mr_asprintf(format_sz, "%s ", format);
    895 
    896 #ifdef __FreeBSD__
    897     mr_asprintf(command, "lsvfs | tr -s '\t' ' ' | grep -v Filesys | grep -v -- -- | cut -d' ' -f1 | tr -s '\n' ' '");
    898 #else
    899     mr_asprintf(command, "grep -v nodev /proc/filesystems | tr -s '\t' ' ' | cut -d' ' -f2 | tr -s '\n' ' '");
    900 #endif
    901 
    902     pin = popen(command, "r");
    903     mr_free(command);
    904 
    905     if (!pin) {
    906         log_OS_error("Unable to read good formats");
    907         retval = 0;
    908     } else {
    909         mr_getline(p, pin);
    910         good_formats = mr_strip_spaces(p);
    911         mr_free(p);
    912         (void)pclose(pin);
    913         mr_strcat(good_formats, " swap lvm raid ntfs-3g ntfs 7 ");  // " ntfs 7 " -- um, cheating much? :)
    914         if (strstr(good_formats, format_sz)) {
    915             retval = 1;
    916         } else {
    917             retval = 0;
    918         }
    919     }
    920     mr_free(good_formats);
    921     mr_free(format_sz);
    922 
    923     return (retval);
    924 }
    925 
    926 
    927 /** @def SWAPLIST_COMMAND The command to list the swap files/partitions in use. */
    928 
    929 /**
    930  * Determine whether @p device_raw is currently mounted.
    931  * @param device_raw The device to check.
    932  * @return TRUE if it's mounted, FALSE if not.
    933  */
    934 bool is_this_device_mounted(char *device_raw)
    935 {
    936 
    937     char *tmp = NULL;
    938     bool retval = FALSE;
    939 
    940     mr_asprintf(tmp, "mr-device-mounted %s > /dev/null", device_raw);
    941     if (system(tmp) == 0) {
    942         retval = TRUE;
    943     }
    944     mr_free(tmp);
    945     return(retval);
    946 }
    947 
    948 /* previous C version replaced by a call to a perl script, fixing issues with symlinks between devices - RHEL7 e.g.
    949     FILE *fin;
    950 
    951     char *incoming = NULL;
    952     char *device_with_tab = NULL;
    953     char *device_with_space = NULL;
    954     char *tmp = NULL;
    955     bool retval = FALSE;
    956 
    957 #ifdef __FreeBSD__
    958 #define SWAPLIST_COMMAND "swapinfo"
    959 #else
    960 #define SWAPLIST_COMMAND "cat /proc/swaps"
    961 #endif
    962 
    963 
    964     if (device_raw == NULL) {
    965         return(FALSE);
    966     }
    967 
    968     if (device_raw[0] != '/' && !strstr(device_raw, ":/")) {
    969         log_msg(1, "%s needs to have a '/' prefixed - I'll do it", device_raw);
    970         mr_asprintf(tmp, "/%s", device_raw);
    971     } else {
    972         mr_asprintf(tmp, "%s", device_raw);
    973     }
    974     log_msg(1, "Is %s mounted?", tmp);
    975     if (!strcmp(tmp, "/proc") || !strcmp(tmp, "proc")) {
    976         log_msg(1, "I don't know how the heck /proc made it into the mountlist. I'll ignore it.");
    977         mr_free(tmp);
    978         return(FALSE);
    979     }
    980     mr_asprintf(device_with_tab, "%s\t", tmp);
    981     mr_asprintf(device_with_space, "%s ", tmp);
    982     mr_free(tmp);
    983 
    984     if (!(fin = popen("mount", "r"))) {
    985         log_OS_error("Cannot popen 'mount'");
    986         return(FALSE);
    987     }
    988 
    989     for (mr_getline(incoming, fin); !feof(fin); mr_getline(incoming, fin)) {
    990         if (strstr(incoming, device_with_space) || strstr(incoming, device_with_tab)) {
    991             paranoid_pclose(fin);
    992             mr_free(incoming);
    993             return(TRUE);
    994         }
    995         mr_free(incoming);
    996     }
    997     mr_free(incoming);
    998     mr_free(device_with_tab);
    999     paranoid_pclose(fin);
    1000 
    1001     mr_asprintf(tmp, "%s | grep -E \"^%s\" > /dev/null 2> /dev/null", SWAPLIST_COMMAND, device_with_space);
    1002     mr_free(device_with_space);
    1003     log_msg(4, "tmp (command) = '%s'", tmp);
    1004     if (!system(tmp)) {
    1005         retval = TRUE;
    1006     }
    1007     mr_free(tmp);
    1008     return(retval);
    1009 }
    1010 */
    1011 
    1012 #ifdef __FreeBSD__
    1013 //                       CODE IS FREEBSD-SPECIFIC
    1014 /**
    1015  * Create a loopback device for specified @p fname.
    1016  * @param fname The file to associate with a device.
    1017  * @return /dev entry for the device, or NULL if it couldn't be allocated.
    1018  */
    1019 char *make_vn(char *fname)
    1020 {
    1021     char *device = (char *) malloc(MAX_STR_LEN);
    1022     char *mddevice = NULL;
    1023     char *command = NULL;
    1024     char *tmp = NULL;
    1025     int vndev = 2;
    1026 
    1027     tmp = call_program_and_get_last_line_of_output("/sbin/sysctl -n kern.osreldate");
    1028     if (atoi(tmp) < 500000) {
    1029         do {
    1030             mr_asprintf(mddevice, "vn%ic", vndev++);
    1031             mr_free(command);
    1032             mr_asprintf(command, "vnconfig %s %s", mddevice, fname);
    1033             if (vndev > 10) {
    1034                 mr_free(tmp);
    1035                 mr_free(mddevice);
    1036                 mr_free(command);
    1037                 return NULL;
    1038             }
    1039         }
    1040         while (system(command));
    1041     } else {
    1042         mr_asprintf(command, "mdconfig -a -t vnode -f %s", fname);
    1043         mddevice = call_program_and_get_last_line_of_output(command);
    1044         if (!strstr(mddevice, "md")) {
    1045             mr_free(tmp);
    1046             mr_free(command);
    1047             mr_free(mddevice);
    1048             return NULL;
    1049         }
    1050     }
    1051     mr_free(tmp);
    1052     mr_free(command);
    1053     sprintf(device, "/dev/%s", mddevice);
    1054     mr_free(mddevice);
    1055     return device;
    1056 }
    1057 
    1058 
    1059 
    1060 //                       CODE IS FREEBSD-SPECIFIC
    1061 /**
    1062  * Deallocate specified @p dname.
    1063  * This should be called when you are done with the device created by make_vn(),
    1064  * so the system does not run out of @c vn devices.
    1065  * @param dname The device to deallocate.
    1066  * @return 0 for success, nonzero for failure.
    1067  */
    1068 int kick_vn(char *dname)
    1069 {
    1070     char *command = NULL;
    1071     char *tmp = NULL;
    1072     int res = 0;
    1073 
    1074     if (strncmp(dname, "/dev/", 5) == 0) {
    1075         dname += 5;
    1076     }
    1077 
    1078     tmp = call_program_and_get_last_line_of_output("/sbin/sysctl -n kern.osreldate");
    1079     if (atoi(tmp) < 500000) {
    1080         mr_asprintf(command, "vnconfig -d %s", dname);
    1081     } else {
    1082         mr_asprintf(command, "mdconfig -d -u %s", dname);
    1083     }
    1084     mr_free(tmp);
    1085     res = system(command);
    1086     mr_free(command);
    1087     return(res);
    1088 }
    1089 #endif
    1090 
    1091 
    1092 /**
    1093  * Mount the CD-ROM at @p mountpoint.
    1094  * @param device The device (or file if g_ISO_restore_mode) to mount.
    1095  * @param mountpoint The place to mount it.
    1096  * @return 0 for success, nonzero for failure.
    1097  */
    1098 int mount_USB_here(char *device, char *mountpoint)
    1099 {
    1100     /*@ buffer ****************************************************** */
    1101     char *command = NULL;
    1102     int retval;
    1103 
    1104     assert_string_is_neither_NULL_nor_zerolength(device);
    1105     assert_string_is_neither_NULL_nor_zerolength(mountpoint);
    1106 
    1107     make_hole_for_dir(mountpoint);
    1108     if (isdigit(device[0])) {
    1109         return(1);
    1110     }
    1111     log_msg(4, "(mount_USB_here --- device=%s, mountpoint=%s", device, mountpoint);
    1112 
    1113 #ifdef __FreeBSD__
    1114     mr_asprintf(command, "mount_vfat %s %s 2>> %s", device, mountpoint, MONDO_LOGFILE);
    1115 
    1116 #else
    1117     mr_asprintf(command, "mount %s -t vfat %s 2>> %s", device, mountpoint, MONDO_LOGFILE);
    1118 #endif
    1119 
    1120     log_msg(4, command);
    1121     retval = system(command);
    1122     log_msg(1, "system(%s) returned %d", command, retval);
    1123     mr_free(command);
    1124 
    1125     return (retval);
    1126 }
    1127 
    1128 /**
    1129  * Find out what number CD is in the drive.
    1130  * @param bkpinfo The backup information structure. The @c bkpinfo->media_device field is the only one used.
    1131  * @return The current CD number, or -1 if it could not be found.
    1132  * @note If the CD is not mounted, it will be mounted
    1133  * (and remain mounted after this function returns).
    1134  */
    1135 int what_number_cd_is_this(void) {
    1136 
    1137     int cd_number = -1;
    1138     char *mountdev = NULL;
    1139     char *tmp = NULL;
    1140 
    1141     assert(bkpinfo != NULL);
    1142 //  log_it("Asking what_number_cd_is_this");
    1143     if ((g_ISO_restore_mode) || (g_restoring_live_from_cd)) {
    1144         tmp = call_program_and_get_last_line_of_output("mount | grep iso9660 | awk '{print $3;}'");
    1145         mr_asprintf(mountdev, "%s%s", tmp, "/archives/THIS-CD-NUMBER");
    1146         mr_free(tmp);
    1147         cd_number = atoi(last_line_of_file(mountdev));
    1148         mr_free(mountdev);
    1149         return (cd_number);
    1150     }
    1151 
    1152     if ((bkpinfo->media_device == NULL) || !does_file_exist(bkpinfo->media_device)) {
    1153         log_it("ERROR: bkpinfo->media_device shoulnd't be unaccessible here\n");
    1154         /* trying again ! */
    1155         bkpinfo->media_device = find_optical_device();
    1156     }
    1157     if ((bkpinfo->media_device == NULL) || !does_file_exist(bkpinfo->media_device)) {
    1158         fatal_error("ERROR: bkpinfo->media_device shoulnd't really be unaccessible here\n");
    1159     }
    1160     if (!is_this_device_mounted(MNT_CDROM)) {
    1161         mount_media(MNT_CDROM);
    1162     }
    1163 
    1164     cd_number = atoi(last_line_of_file(MNT_CDROM "/archives/THIS-CD-NUMBER"));
    1165     return(cd_number);
    1166 }
    1167 
    1168 
    1169 
    1170 
    1171 /**
    1172  * Ask the user for CD number @p cd_number_i_want.
    1173  * Sets g_current_media_number once the correct CD is inserted.
    1174  * @param bkpinfo The backup information structure. Fields used:
    1175  * - @c bkpinfo->backup_media_type
    1176  * - @c bkpinfo->prefix
    1177  * - @c bkpinfo->isodir
    1178  * - @c bkpinfo->media_device
    1179  * - @c bkpinfo->please_dont_eject_when_restoring
    1180  * @param cd_number_i_want The CD number to ask for.
    1181  */
    1182 void
    1183 insist_on_this_cd_number(int cd_number_i_want)
    1184 {
    1185 
    1186     /*@ int ************************************************************* */
    1187     int res = 0;
    1188 
    1189 
    1190     /*@ buffers ********************************************************* */
    1191     char *tmp = NULL;
    1192     char *mds = NULL;
    1193     char *request = NULL;
    1194 
    1195     assert(bkpinfo != NULL);
    1196     assert(cd_number_i_want > 0);
    1197 
    1198 //  log_msg(3, "Insisting on CD number %d", cd_number_i_want);
    1199 
    1200     if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
    1201         log_msg(3,
    1202                 "No need to insist_on_this_cd_number when the backup type isn't CD-R(W) or NFS or ISO");
    1203         return;
    1204     }
    1205     if (!does_file_exist(MNT_CDROM)) {
    1206         mr_asprintf(tmp, "mkdir -p " MNT_CDROM);
    1207         run_program_and_log_output(tmp, 5);
    1208         mr_free(tmp);
    1209     }
    1210 
    1211     if (g_ISO_restore_mode || bkpinfo->backup_media_type == iso || bkpinfo->backup_media_type == netfs) {
    1212         g_ISO_restore_mode = TRUE;
    1213     }
    1214     if ((res = what_number_cd_is_this()) != cd_number_i_want) {
    1215         log_msg(3, "Currently, we hold %d but we want %d", res, cd_number_i_want);
    1216 
    1217         /* Now we need to umount the current media to have the next mounted after */
    1218         run_program_and_log_output("umount -d " MNT_CDROM, FALSE);
    1219         log_msg(3, "Mounting next media %d",cd_number_i_want);
    1220         g_current_media_number = cd_number_i_want;
    1221         mount_media(MNT_CDROM);
    1222 
    1223         mds = media_descriptor_string(bkpinfo->backup_media_type);
    1224         log_msg(3, "Insisting on %s #%d", mds, cd_number_i_want);
    1225         mr_asprintf(request, "Please insert %s #%d and press Enter.", mds, cd_number_i_want);
    1226         mr_free(mds);
    1227 
    1228         while (what_number_cd_is_this() != cd_number_i_want) {
    1229             sync();
    1230             if (is_this_device_mounted(MNT_CDROM)) {
    1231                 res =
    1232                     run_program_and_log_output("umount -d " MNT_CDROM, FALSE);
    1233             } else {
    1234                 res = 0;
    1235             }
    1236             if (res) {
    1237                 log_to_screen("WARNING - failed to unmount CD-ROM drive");
    1238             }
    1239             if (!bkpinfo->please_dont_eject) {
    1240                 res = eject_device(bkpinfo->media_device);
    1241             } else {
    1242                 res = 0;
    1243             }
    1244             if (res) {
    1245                 log_to_screen("WARNING - failed to eject CD-ROM disk");
    1246             }
    1247             popup_and_OK(request);
    1248             if (!bkpinfo->please_dont_eject) {
    1249                 inject_device(bkpinfo->media_device);
    1250             }
    1251             sync();
    1252         }
    1253         mr_free(request);
    1254 
    1255         log_msg(1, "Thankyou. Proceeding...");
    1256         g_current_media_number = cd_number_i_want;
    1257     }
    1258 }
    1259 
    1260 /* @} - end of deviceGroup */
    1261 
    1262 
    1263 
    1264 /**
    1265  * Creates a singly linked list of all of the non-NETFS mounted file systems.
    1266  * @param DSFptr A pointer  to the structure MOUNTED_FS_STRUCT used to hold
    1267  * the list of mounted file systems.
    1268  * @return None.
    1269  */
    1270 static void add_mounted_fs_struct (MOUNTED_FS_STRUCT *DSFptr)
    1271 {
    1272     assert (DSFptr);
    1273     if (DSF_Head == NULL) {
    1274         DSF_Head = DSFptr;
    1275     } else {
    1276         DSF_Tail->next = DSFptr;
    1277     }
    1278     DSFptr->next = NULL;
    1279     DSF_Tail = DSFptr;
    1280 }
    1281 
    1282 /**
    1283  * Find the structure, in the singly linked list of all of the non-NETFS
    1284  * mounted file systems, that contains the specified device.
    1285  * @param device The device to find
    1286  * @return NULL if it didn't find the device, a pointer to the
    1287  * structure if it did.
    1288  */
    1289 static MOUNTED_FS_STRUCT *find_device_in_list (char *device)
    1290 {
    1291     MOUNTED_FS_STRUCT *DSFptr = NULL;
    1292 
    1293     DSFptr = DSF_Head;
    1294     while (DSFptr != NULL) {
    1295         if (!strcmp(DSFptr->device, device)) {
    1296             break;
    1297         }
    1298         DSFptr = DSFptr->next;
    1299     }
    1300     return (DSFptr);
    1301 }
    1302 
    1303 /**
    1304  * Find the structure, in the singly linked list of all of the non-NETFS
    1305  * mounted file systems, that contains the specified mount point.
    1306  * @param mount_point The mount point to find
    1307  * @return NULL is it didn't find the mount point, a pointer to the
    1308  * structure if it did.
    1309  */
    1310 static MOUNTED_FS_STRUCT *find_mount_point_in_list (char *mount_point)
    1311 {
    1312     MOUNTED_FS_STRUCT *DSFptr = NULL;
    1313 
    1314     DSFptr = DSF_Head;
    1315     while (DSFptr != NULL) {
    1316         if (!strcmp(DSFptr->mount_point, mount_point)) {
    1317             break;
    1318         }
    1319         DSFptr = DSFptr->next;
    1320     }
    1321     return (DSFptr);
    1322 }
    1323 
    1324 /**
    132582 * Frees the memory for all of the structures on the linked list of
    132683 * all of the non-NETFS mounted file systems.
     
    133996    DSF_Tail = NULL;
    134097}
     98
     99
     100/**
     101 * Creates a singly linked list of all of the non-NETFS mounted file systems.
     102 * @param DSFptr A pointer  to the structure MOUNTED_FS_STRUCT used to hold
     103 * the list of mounted file systems.
     104 * @return None.
     105 */
     106static void add_mounted_fs_struct (MOUNTED_FS_STRUCT *DSFptr)
     107{
     108    assert (DSFptr);
     109    if (DSF_Head == NULL) {
     110        DSF_Head = DSFptr;
     111    } else {
     112        DSF_Tail->next = DSFptr;
     113    }
     114    DSFptr->next = NULL;
     115    DSF_Tail = DSFptr;
     116}
     117
    1341118
    1342119
     
    1415192}
    1416193
     194/**
     195 * Find the structure, in the singly linked list of all of the non-NETFS
     196 * mounted file systems, that contains the specified mount point.
     197 * @param mount_point The mount point to find
     198 * @return NULL is it didn't find the mount point, a pointer to the
     199 * structure if it did.
     200 */
     201static MOUNTED_FS_STRUCT *find_mount_point_in_list (char *mount_point)
     202{
     203    MOUNTED_FS_STRUCT *DSFptr = NULL;
     204
     205    DSFptr = DSF_Head;
     206    while (DSFptr != NULL) {
     207        if (!strcmp(DSFptr->mount_point, mount_point)) {
     208            break;
     209        }
     210        DSFptr = DSFptr->next;
     211    }
     212    return (DSFptr);
     213}
     214
     215
     216/**
     217 * Find the structure, in the singly linked list of all of the non-NETFS
     218 * mounted file systems, that contains the specified device.
     219 * @param device The device to find
     220 * @return NULL if it didn't find the device, a pointer to the
     221 * structure if it did.
     222 */
     223static MOUNTED_FS_STRUCT *find_device_in_list(char *device) {
     224    MOUNTED_FS_STRUCT *DSFptr = NULL;
     225
     226    DSFptr = DSF_Head;
     227    while (DSFptr != NULL) {
     228        if (!strcmp(DSFptr->device, device)) {
     229            break;
     230        }
     231        DSFptr = DSFptr->next;
     232    }
     233    return (DSFptr);
     234}
    1417235
    1418236
     
    1749567
    1750568
     569/**
     570 * Load (inject) the tray of the specified CD device.
     571 * @param dev The device to load/inject.
     572 * @return 0 for success, nonzero for failure.
     573 */
     574int inject_device(char *dev)
     575{
     576    char *command = NULL;
     577    int i;
     578
     579    if (dev == NULL) {
     580        return (1);
     581    }
     582
     583#ifdef __FreeBSD__
     584    if (strstr(dev, "acd")) {
     585        mr_asprintf(command, "cdcontrol -f %s close", dev);
     586    } else {
     587        mr_asprintf(command, "camcontrol load `echo %s | sed 's|/dev/||'`", dev);
     588    }
     589#else
     590    mr_asprintf(command, "eject -t %s", dev);
     591#endif
     592    i = run_program_and_log_output(command, FALSE);
     593    mr_free(command);
     594    return (i);
     595}
     596
     597
     598/**
     599 * Retract all CD trays and wait for autorun to complete.
     600 * @ingroup deviceGroup
     601 */
     602void retract_CD_tray_and_defeat_autorun(void)
     603{
     604//  log_it("rctada: Retracting optical tray", __LINE__);
     605    if (!bkpinfo->please_dont_eject) {
     606        if (bkpinfo->media_device != NULL) {
     607            inject_device(bkpinfo->media_device);
     608        }
     609    }
     610    if (!run_program_and_log_output("ps | grep autorun | grep -v grep", 5)) {
     611        log_it("autorun detected; sleeping for 2 seconds");
     612        sleep(2);
     613    }
     614}
     615
     616
     617
     618/**
     619 * Find out what device is mounted as root (/).
     620 * @return Root device.
     621 * @note The returned string points to storage that needs to be freed by
     622 * caller
     623 * @bug A bit of a misnomer; it's actually finding out the root device.
     624 * The mountpoint (where it's mounted) will obviously be '/'.
     625 */
     626char *where_is_root_mounted(void) {
     627
     628/*@ buffers **************** */
     629char *tmp = NULL;
     630
     631#ifdef __FreeBSD__
     632    tmp = call_program_and_get_last_line_of_output("mount | grep \" on / \" | cut -d' ' -f1");
     633#else
     634    tmp = call_program_and_get_last_line_of_output("mount | grep \" on / \" | cut -d' ' -f1 | sed s/[0-9]// | sed s/[0-9]//");
     635    if (strstr(tmp, "/dev/cciss/")) {
     636        mr_free(tmp);
     637        tmp = call_program_and_get_last_line_of_output("mount | grep \" on / \" | cut -d' ' -f1 | cut -dp -f1");
     638    }
     639    if (strstr(tmp, "/dev/md")) {
     640        mr_free(tmp);
     641        tmp = call_program_and_get_last_line_of_output("mount | grep \" on / \" | cut -d' ' -f1");
     642    }
     643#endif
     644
     645return (tmp);
     646}
     647
     648
     649
     650/**
     651 * Determine whether we're booted off a ramdisk.
     652 * @return @c TRUE (we are) or @c FALSE (we aren't).
     653 * @ingroup utilityGroup
     654 */
     655bool am_I_in_disaster_recovery_mode(void)
     656{
     657    char *tmp = NULL;
     658    bool is_this_a_ramdisk = FALSE;
     659
     660    tmp = where_is_root_mounted();
     661    log_msg(0, "root is mounted at %s", tmp);
     662    log_msg(0, "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);
     663
     664#ifdef __FreeBSD__
     665    if (strstr(tmp, "/dev/md")) {
     666        is_this_a_ramdisk = TRUE;
     667    }
     668#else
     669    if (!strncmp(tmp, "/dev/ram", 8)
     670        || (!strncmp(tmp, "/dev/rd", 7) && !strcmp(tmp, "/dev/rd/")
     671            && strncmp(tmp, "/dev/rd/cd", 10)) || strstr(tmp, "rootfs")
     672        || !strcmp(tmp, "/dev/root")) {
     673        is_this_a_ramdisk = TRUE;
     674    } else {
     675        is_this_a_ramdisk = FALSE;
     676    }
     677#endif
     678    mr_free(tmp);
     679
     680    if (is_this_a_ramdisk) {
     681        if (!does_file_exist("/THIS-IS-A-RAMDISK")) {
     682            log_to_screen("Using /dev/root is stupid of you but I'll forgive you.");
     683            is_this_a_ramdisk = FALSE;
     684        }
     685    }
     686    if (does_file_exist("/THIS-IS-A-RAMDISK")) {
     687        is_this_a_ramdisk = TRUE;
     688    }
     689
     690    log_msg(1, "Is this a ramdisk? result = %s", (is_this_a_ramdisk) ? "TRUE" : "FALSE");
     691    return (is_this_a_ramdisk);
     692}
     693
     694
     695
     696
     697
     698/**
     699 * Turn @c bkpinfo->backup_media_type into a human-readable string.
     700 * @return The human readable string (e.g. @c cdr becomes <tt>"cdr"</tt>).
     701 * @note The returned string points to static storage that will be overwritten with each call.
     702 * @ingroup stringGroup
     703 */
     704static char *bkptype_to_string(t_bkptype bt)
     705{
     706    char *output = NULL;
     707    switch (bt) {
     708    case none:
     709        mr_asprintf(output, "%s", "none");
     710        break;
     711    case iso:
     712        mr_asprintf(output, "%s", "iso");
     713        break;
     714    case cdr:
     715        mr_asprintf(output, "%s", "cdr");
     716        break;
     717    case cdstream:
     718        mr_asprintf(output, "%s", "cdstream");
     719        break;
     720    case netfs:
     721        mr_asprintf(output, "%s", "netfs");
     722        break;
     723    case tape:
     724        mr_asprintf(output, "%s", "tape");
     725        break;
     726    case udev:
     727        mr_asprintf(output, "%s", "udev");
     728        break;
     729    case usb:
     730        mr_asprintf(output, "%s", "usb");
     731        break;
     732    default:
     733        mr_asprintf(output, "%s", "default");
     734    }
     735    return (output);
     736}
     737
     738
     739
     740/**
     741 * @addtogroup deviceGroup
     742 * @{
     743 */
     744/**
     745 * Eject the tray of the specified CD device.
     746 * @param dev The device to eject.
     747 * @return the return value of the @c eject command. (0=success, nonzero=failure)
     748 */
     749int eject_device(char *dev)
     750{
     751    char *command = NULL;
     752    int res1 = 0, res2 = 0;
     753
     754    if (dev == NULL) {
     755        return (1);
     756    }
     757
     758    if (IS_THIS_A_STREAMING_BACKUP(g_backup_media_type)
     759        && g_backup_media_type != udev) {
     760        mr_asprintf(command, "mt -f %s offline", dev);
     761        res1 = run_program_and_log_output(command, 1);
     762        mr_free(command);
     763    } else {
     764        res1 = 0;
     765    }
     766
     767#ifdef __FreeBSD__
     768    if (strstr(dev, "acd")) {
     769        mr_asprintf(command, "cdcontrol -f %s eject", dev);
     770    } else {
     771        mr_asprintf(command, "camcontrol eject `echo %s | sed 's|/dev/||'`", dev);
     772    }
     773#else
     774    mr_asprintf(command, "eject %s", dev);
     775#endif
     776
     777    log_msg(3, "Ejecting %s", dev);
     778    res2 = run_program_and_log_output(command, 1);
     779    mr_free(command);
     780    if (res1 && res2) {
     781        return (1);
     782    } else {
     783        return (0);
     784    }
     785}
     786
     787/**
     788 * Determine whether a non-Microsoft partition exists on any connected hard drive.
     789 * @return TRUE (there's a Linux/FreeBSD partition) or FALSE (Microsoft has taken over yet another innocent machine).
     790 */
     791bool does_nonMS_partition_exist(void)
     792{
     793#if __FreeBSD__
     794    return
     795        !system("for drive in /dev/ad? /dev/da?; do fdisk $drive | grep -q FreeBSD && exit 0; done; false");
     796#else
     797    return
     798        !system("mr-parted2fdisk -l 2>/dev/null | grep '^/dev/' | grep -Eqv '(MS|DOS|EFI|FAT|NTFS)'");
     799#endif
     800}
     801
     802/**
     803 * Determine whether the specified @p partno exists on the specified @p drive.
     804 * @param drive The drive to search for the partition in.
     805 * @param partno The partition number to look for.
     806 * @return 0 if it exists, nonzero otherwise.
     807 */
     808int does_partition_exist(const char *drive, int partno)
     809{
     810    /*@ buffers **************************************************** */
     811    char *program = NULL;
     812    char *incoming = NULL;
     813    char *searchstr = NULL;
     814
     815    /*@ ints ******************************************************* */
     816    int res = 0;
     817
     818    /*@ pointers *************************************************** */
     819    FILE *fin;
     820
     821    /*@ end vars *************************************************** */
     822    assert_string_is_neither_NULL_nor_zerolength(drive);
     823    assert(partno >= 0 && partno < 999);
     824
     825#ifdef __FreeBSD__
     826    // We assume here that this is running from mondorestore. (It is.)
     827    tmp = build_partition_name(drive, partno);
     828    mr_asprintf(program, "ls %s %s >/dev/null 2>&1", drive, tmp);
     829    mr_free(tmp);
     830    res = system(program);
     831    mr_free(program);
     832    return(res);
     833#endif
     834
     835    mr_asprintf(program, "mr-parted2fdisk -l %s 2> /dev/null", drive);
     836    fin = popen(program, "r");
     837    if (!fin) {
     838        log_it("program=%s", program);
     839        log_OS_error("Cannot popen-in program");
     840        mr_free(program);
     841        return (0);
     842    }
     843    mr_free(program);
     844
     845    searchstr = build_partition_name(drive, partno);
     846    mr_strcat(searchstr, " ");
     847    for (res = 0, mr_getline(incoming, fin); !res && !feof(fin) ; mr_getline(incoming, fin)) {
     848        if (strstr(incoming, searchstr)) {
     849            res = 1;
     850        }
     851        mr_free(incoming);
     852    }
     853    mr_free(searchstr);
     854    mr_free(incoming);
     855
     856    if (pclose(fin)) {
     857        log_OS_error("Cannot pclose fin");
     858    }
     859    return (res);
     860}
     861
     862
     863
     864
     865
     866/**
     867 * Determine whether given NULL-terminated @p str exists in the begining of @p dev.
     868 * @param dev The device to look in.
     869 * @param str The string to look for.
     870 * @return TRUE if it exists, FALSE if it doesn't.
     871 */
     872bool does_string_exist_in_boot_block(char *dev, char *str)
     873{
     874    /*@ buffers **************************************************** */
     875    char *command = NULL;
     876
     877    /*@ end vars *************************************************** */
     878    int i;
     879
     880    assert_string_is_neither_NULL_nor_zerolength(dev);
     881    assert_string_is_neither_NULL_nor_zerolength(str);
     882
     883    /* For UEFI detection, this should be extended to count=1000 ! */
     884    if (bkpinfo->boot_type == UEFI) {
     885        mr_asprintf(command, "dd if=%s bs=446 count=1000 2> /dev/null | strings | grep \"%s\" > /dev/null 2> /dev/null", dev, str);
     886    } else {
     887        mr_asprintf(command, "dd if=%s bs=446 count=1 2> /dev/null | strings | grep \"%s\" > /dev/null 2> /dev/null", dev, str);
     888    }
     889    i = system(command);
     890    mr_free(command);
     891    if (i) {
     892        return (FALSE);
     893    } else {
     894        return (TRUE);
     895    }
     896}
     897
     898/**
     899 * Determine whether specified @p str exists in the first @p n sectors of
     900 * @p dev.
     901 * @param dev The device to look in.
     902 * @param str The string to look for.
     903 * @param n The number of 512-byte sectors to search.
     904 */
     905bool does_string_exist_in_first_N_blocks(char *dev, char *str, int n)
     906{
     907    /*@ buffers **************************************************** */
     908    char *command = NULL;
     909    /*@ end vars *************************************************** */
     910    int i;
     911
     912    mr_asprintf(command, "dd if=%s bs=512 count=%i 2> /dev/null | strings | grep \"%s\" > /dev/null 2> /dev/null", dev, n, str);
     913    i = system(command);
     914    mr_free(command);
     915    if (i) {
     916        return (FALSE);
     917    } else {
     918        return (TRUE);
     919    }
     920}
     921
     922
     923/*
     924 * This function tries to find an optical media device
     925 * and return it's device file to the caller that needs to free it
     926 */
     927char *find_optical_device(void) {
     928    char *dev = NULL;
     929    char *tmp1 = NULL;
     930    char *command = NULL;
     931
     932    log_to_screen("I am looking for your optical burner. Please wait.");
     933
     934    if (bkpinfo->media_device != NULL) {
     935        log_msg(3, "Been there, done that. Returning %s", bkpinfo->media_device);
     936        return (bkpinfo->media_device);
     937    }
     938
     939    mr_asprintf(tmp1, "cdrecord -inq 2> /dev/null | grep -E '^Detected '  | cut -d':' -f2");
     940    dev = call_program_and_get_last_line_of_output(tmp1);
     941    mr_free(tmp1);
     942
     943    if ((dev != NULL) && does_file_exist(dev)) {
     944        log_msg(2, "find_optical_device found %s automatically", dev);
     945    } else {
     946        mr_free(dev);
     947        tmp1 = find_home_of_exe("lsscsi");
     948        if (tmp1 != NULL) {
     949            mr_asprintf(command, "%s | grep ' cd' | awk '{print $NF}' | head -1", tmp1);
     950            dev = call_program_and_get_last_line_of_output(command);
     951            mr_free(command);
     952        }
     953        mr_free(tmp1);
     954
     955        if ((dev == NULL) || !does_file_exist(dev)) {
     956            /* trying something else then */
     957            mr_asprintf(dev, "%s", VANILLA_SCSI_CDROM);
     958            if (!does_file_exist(dev)) {
     959                mr_asprintf(dev, "%s", ALT_CDROM);
     960                if (!does_file_exist(dev)) {
     961                    mr_asprintf(dev, "%s", "/dev/cdrom");
     962                    if (!does_file_exist(dev)) {
     963                        mr_asprintf(dev, "%s", "/dev/dvd");
     964                        if (!does_file_exist(dev)) {
     965                            log_it("Unable to find a tape device on this system");
     966                        }
     967                    }
     968                }
     969            }
     970        }
     971        if (dev != NULL) {
     972            log_it("find_optical_device found %s manually", dev);
     973        }
     974    }
     975
     976    if ((dev != NULL) && does_file_exist(dev)) {
     977        log_it("find_optical_device returns %s", dev);
     978    } else {
     979        mr_free(dev);
     980        log_it("find_optical_device found no optical burner on your system returning NULL");
     981    }
     982    return(dev);
     983}
     984/**
     985* Mount the CD-ROM or USB device at /mnt/cdrom.
     986* @param bkpinfo The backup information structure. Fields used:
     987* - @c bkpinfo->backup_media_type
     988* - @c bkpinfo->disaster_recovery
     989* - @c bkpinfo->isodir
     990* - @c bkpinfo->media_device
     991* @return TRUE for success, FALSE for failure.
     992*/
     993bool mount_media(const char *mountpoint) {
     994
     995    char *mount_cmd = NULL;
     996    char *mountdir = NULL;
     997    char *tmp = NULL;
     998    int i = 0, res = 0;
     999#ifdef __FreeBSD__
     1000    char mdd[32];
     1001    char *mddev = mdd;
     1002    char *dev;
     1003#endif
     1004
     1005    if (bkpinfo->backup_media_type == tape || bkpinfo->backup_media_type == udev) {
     1006        log_msg(8, "Tape/udev. Therefore, no need to mount a media.");
     1007        return(TRUE);
     1008    }
     1009
     1010    assert_string_is_neither_NULL_nor_zerolength(mountpoint);
     1011
     1012    mr_asprintf(tmp, "mount | grep -F %s", mountpoint);
     1013    if (!run_program_and_log_output(tmp, FALSE)) {
     1014        log_msg(2, "mount_media() - media already mounted. Fair enough.");
     1015        mr_free(tmp);
     1016        return (TRUE);
     1017    }
     1018    mr_free(tmp);
     1019
     1020    make_hole_for_dir(mountpoint);
     1021
     1022    if (bkpinfo->backup_media_type == netfs) {
     1023        log_msg(2, "Mounting for Network thingy");
     1024        log_msg(2, "isodir = %s", bkpinfo->isodir);
     1025        if (((bkpinfo->isodir == NULL) || !strcmp(bkpinfo->isodir, "/")) && am_I_in_disaster_recovery_mode()) {
     1026            mr_asprintf(bkpinfo->isodir, "%s", "/tmp/isodir");
     1027            log_msg(1, "isodir is being set to %s", bkpinfo->isodir);
     1028        }
     1029#ifdef __FreeBSD__
     1030        if (bkpinfo->netfs_remote_dir != NULL) {
     1031            // NETFS
     1032            mr_asprintf(mount_cmd, "/mnt/isodir/%s/%s/%s-%d.iso", bkpinfo->isodir, bkpinfo->netfs_remote_dir, bkpinfo->prefix, g_current_media_number);
     1033        } else {
     1034            // ISO
     1035            mr_asprintf(mount_cmd, "/mnt/isodir/%s/%s-%d.iso", bkpinfo->isodir, bkpinfo->prefix, g_current_media_number);
     1036        }
     1037        mddev = make_vn(mount_cmd);
     1038        mr_free(mount_cmd);
     1039
     1040        mr_asprintf(mount_cmd, "mount_cd9660 -r %s %s", mddev, mountpoint);
     1041#else
     1042        if (bkpinfo->netfs_remote_dir != NULL) {
     1043            // NETFS
     1044            mr_asprintf(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, mountpoint);
     1045        } else {
     1046            // ISO
     1047            mr_asprintf(mount_cmd, "mount %s/%s-%d.iso -t iso9660 -o loop,ro %s", bkpinfo->isodir, bkpinfo->prefix, g_current_media_number, mountpoint);
     1048        }
     1049#endif
     1050
     1051    } else if (bkpinfo->backup_media_type == iso) {
     1052        if (bkpinfo->subdir) {
     1053            mr_asprintf(mountdir, "%s/%s", bkpinfo->isodir, bkpinfo->subdir);
     1054        } else {
     1055            mr_asprintf(mountdir, "%s", bkpinfo->isodir);
     1056        }
     1057#ifdef __FreeBSD__
     1058        mr_asprintf(mount_cmd, "%s/%s-%d.iso", mountdir, bkpinfo->prefix, g_current_media_number);
     1059        mddev = make_vn(mount_cmd);
     1060        mr_free(mount_cmd);
     1061
     1062        mr_asprintf(mount_cmd, "mount_cd9660 -r %s %s", mddev, mountpoint);
     1063#else
     1064        mr_asprintf(mount_cmd, "mount %s/%s-%d.iso -t iso9660 -o loop,ro %s", mountdir, bkpinfo->prefix, g_current_media_number, mountpoint);
     1065#endif
     1066        mr_free(mountdir);
     1067    } else if (bkpinfo->backup_media_type == usb) {
     1068        mr_asprintf(mount_cmd, "mount -t vfat %s %s", bkpinfo->media_device, mountpoint);
     1069    } else {    //  optical
     1070        if (bkpinfo->disaster_recovery
     1071            && does_file_exist("/tmp/CDROM-LIVES-HERE")) {
     1072            mr_asprintf(bkpinfo->media_device, "%s", last_line_of_file("/tmp/CDROM-LIVES-HERE"));
     1073        } else {
     1074            if (bkpinfo->media_device == NULL) {
     1075                bkpinfo->media_device = find_optical_device();
     1076            }
     1077        }
     1078
     1079#ifdef __FreeBSD__
     1080        if (g_ISO_restore_mode) {
     1081            mr_asprintf(dev, "%s", make_vn(bkpinfo->media_device));
     1082            if (!dev) {
     1083                mr_asprintf(command, "Unable to mount ISO (make_vn(%s) failed)", bkpinfo->media_device);
     1084                fatal_error(command);
     1085            }
     1086            mr_free(bkpinfo->media_device);
     1087            bkpinfo->media_device = dev
     1088        }
     1089
     1090        mr_asprintf(mount_cmd, "mount_cd9660 -r %s %s 2>> %s", bkpinfo->media_device, mountpoint, MONDO_LOGFILE);
     1091#else
     1092        mr_asprintf(mount_cmd, "mount %s -o loop,ro -t iso9660 %s 2>> %s", bkpinfo->media_device, mountpoint, MONDO_LOGFILE);
     1093#endif
     1094        log_msg(2, "(mount_media) --- command = %s", mount_cmd);
     1095        // usefull ??
     1096        if (strncmp(bkpinfo->media_device, "/dev/", 5) == 0) {
     1097            retract_CD_tray_and_defeat_autorun();
     1098        }
     1099    }
     1100
     1101    for (i = 0; i < 2; i++) {
     1102        res = run_program_and_log_output(mount_cmd, FALSE);
     1103        if (!res) {
     1104            break;
     1105        } else {
     1106            log_msg(2, "Failed to mount device.");
     1107            sleep(5);
     1108            sync();
     1109        }
     1110    }
     1111    mr_free(mount_cmd);
     1112
     1113    if (res) {
     1114        log_msg(2, "Failed, despite %d attempts", i);
     1115        return(FALSE);
     1116    } else {
     1117        log_msg(2, "Mounted media drive OK");
     1118        return(TRUE);
     1119    }
     1120}
     1121/**************************************************************************
     1122*END_MOUNT_MEDIA                                                         *
     1123**************************************************************************/
     1124
     1125
     1126
     1127
     1128/**
     1129 * Try to mount CD/DVD at @p mountpoint. If the CD/DVD is not found or has
     1130 * not been specified, call find_optical_device() to find it.
     1131 * @param mountpoint Where to mount the CD-ROM.
     1132 * @return TRUE for success, FALSE for failure.
     1133 * @see mount_media
     1134 */
     1135bool find_and_mount_actual_cd(char *mountpoint) {
     1136
     1137    /*@ buffers ***************************************************** */
     1138
     1139    /*@ int's  ****************************************************** */
     1140    bool res;
     1141
     1142    /*@ end vars **************************************************** */
     1143
     1144    assert(bkpinfo != NULL);
     1145    assert_string_is_neither_NULL_nor_zerolength(mountpoint);
     1146
     1147    if (bkpinfo->media_device == NULL) {
     1148        bkpinfo->media_device = find_optical_device();
     1149    }
     1150
     1151    if (bkpinfo->backup_media_type != iso) {
     1152        retract_CD_tray_and_defeat_autorun();
     1153    }
     1154
     1155    if ((bkpinfo->media_device == NULL) || (res = mount_media(mountpoint))) {
     1156        mr_free(bkpinfo->media_device);
     1157        if ((bkpinfo->media_device = mr_popup_and_get_string("CD-ROM device", "Please enter your CD-ROM's /dev device", "/dev/cdrom")) == NULL) {
     1158            res = TRUE;
     1159        } else {
     1160            res = mount_media(mountpoint);
     1161        }
     1162    }
     1163    if (res) {
     1164        log_msg(1, "mount failed");
     1165    } else {
     1166        log_msg(1, "mount succeeded with %s", bkpinfo->media_device);
     1167    }
     1168    return (res);
     1169}
     1170/*
     1171 * This function tries to find a USB media device
     1172 * and return it's device file to the caller that needs to free it
     1173 */
     1174char *find_usb_device(void)
     1175{
     1176    char *dev = NULL;
     1177    char *tmp1 = NULL;
     1178    char *command = NULL;
     1179
     1180    log_to_screen("I am looking for your USB key. Please wait.");
     1181
     1182    if (bkpinfo->media_device != NULL) {
     1183        log_msg(3, "Been there, done that. Returning %s", bkpinfo->media_device);
     1184        return (bkpinfo->media_device);
     1185    }
     1186
     1187    tmp1 = find_home_of_exe("lsscsi");
     1188    if (tmp1 != NULL) {
     1189        mr_asprintf(command, "%s | grep ' disk' | grep USB | awk '{print $NF}' | head -1", tmp1);
     1190        dev = call_program_and_get_last_line_of_output(command);
     1191        mr_free(command);
     1192    }
     1193    mr_free(tmp1);
     1194
     1195    if ((dev == NULL) || !does_file_exist(dev)) {
     1196        tmp1 = find_home_of_exe("lsblk");
     1197        if (tmp1 != NULL) {
     1198            mr_asprintf(command, "%s --noheadings --raw --output rm,tran,type,path --sort path | awk '/^1 usb disk/ {d=$4} END {print d}'", tmp1);
     1199            dev = call_program_and_get_last_line_of_output(command);
     1200            mr_free(command);
     1201        }
     1202        mr_free(tmp1);
     1203        log_it("Unable to find a tape device on this system");
     1204    }
     1205    if (dev != NULL) {
     1206        log_it("find_usb_device found %s manually", dev);
     1207    }
     1208
     1209    if ((dev != NULL) && does_file_exist(dev)) {
     1210        log_it("find_usb_device returns %s", dev);
     1211    } else {
     1212        mr_free(dev);
     1213        log_it("find_usb_device found no USB key on your system returning NULL");
     1214    }
     1215    return(dev);
     1216}
     1217
     1218
     1219
     1220/* Generic fund to find a media
     1221 * Return a dynamically allocted string that caller needs to free
     1222 * @media_type is the type of media to look for
     1223 */
     1224
     1225char *find_device(t_bkptype media_type) {
     1226
     1227    if (media_type == usb) {
     1228        return(find_usb_device());
     1229    } else if (media_type == tape) {
     1230        return(find_tape_device());
     1231    } else if ((media_type == dvd) || (media_type == cdr)) {
     1232        return(find_optical_device());
     1233    } else {
     1234        return(NULL);
     1235    }
     1236}
     1237
     1238
     1239
     1240
     1241#include <sys/ioctl.h>
     1242
     1243/**
     1244 * Find the size of the specified @p drive, in megabytes. Uses @c ioctl calls
     1245 * and @c dmesg.
     1246 * @param drive The device to find the size of.
     1247 * @return size in megabytes.
     1248 */
     1249long get_phys_size_of_drive(char *drive)
     1250{
     1251    int fd;
     1252#if linux
     1253    unsigned long long s = 0;
     1254    int fileid, cylinders = 0;
     1255    int cylindersize = 0;
     1256    int gotgeo = 0;
     1257
     1258
     1259    struct hd_geometry hdgeo;
     1260#elif __FreeBSD__
     1261    off_t s;
     1262#endif
     1263
     1264    long outvalA = -1;
     1265    long outvalB = -1;
     1266    long outvalC = -1;
     1267
     1268    if ((fd = open(drive, O_RDONLY)) != -1) {
     1269        if (ioctl(fd,
     1270#if linux
     1271#ifdef BLKGETSIZE64
     1272                  BLKGETSIZE64,
     1273#else
     1274                  BLKGETSIZE,
     1275#endif
     1276#elif __FreeBSD__
     1277                  DIOCGMEDIASIZE,
     1278#endif
     1279                  &s) != -1) {
     1280            close(fd);
     1281            // s>>11 works for older disks but not for newer ones
     1282            outvalB =
     1283#if linux
     1284#ifdef BLKGETSIZE64
     1285                s >> 20
     1286#else
     1287                s >> 11
     1288#endif
     1289#else
     1290                s >> 20
     1291#endif
     1292                ;
     1293        }
     1294    }
     1295
     1296    if (outvalB <= 0) {
     1297        log_msg(1, "Error getting size of %s: %s", drive, strerror(errno));
     1298#if linux
     1299        fileid = open(drive, O_RDONLY);
     1300        if (fileid != -1) {
     1301            if (ioctl(fileid, HDIO_GETGEO, &hdgeo) != -1) {
     1302                if (hdgeo.cylinders && hdgeo.heads && hdgeo.sectors) {
     1303                    cylindersize = hdgeo.heads * hdgeo.sectors / 2;
     1304                    outvalA = cylindersize * cylinders / 1024;
     1305                    log_msg(2, "Got Harddisk geometry, C:%d, H:%d, S:%d",
     1306                            hdgeo.cylinders, hdgeo.heads, hdgeo.sectors);
     1307                    gotgeo = 1;
     1308                } else {
     1309                    log_msg(1, "Harddisk geometry wrong");
     1310                }
     1311            } else {
     1312                log_msg(1,
     1313                        "Error in ioctl() getting new hard disk geometry (%s), resizing in unsafe mode",
     1314                        strerror(errno));
     1315            }
     1316            close(fileid);
     1317        } else {
     1318            log_msg(1, "Failed to open %s for reading: %s", drive,
     1319                    strerror(errno));
     1320        }
     1321        if (!gotgeo) {
     1322            log_msg(1, "Failed to get harddisk geometry, using old mode");
     1323        }
     1324#endif
     1325    }
     1326// OLDER DISKS will give ridiculously low value for outvalB (so outvalA is returned) :)
     1327// NEWER DISKS will give sane value for outvalB (close to outvalA, in other words) :)
     1328
     1329    outvalC = (outvalA > outvalB) ? outvalA : outvalB;
     1330
     1331//  log_msg (5, "drive = %s, error = %s", drive, strerror (errno));
     1332//  fatal_error ("GPSOD: Unable to get size of drive");
     1333    log_msg(1, "%s --> %ld or %ld --> %ld", drive, outvalA, outvalB,
     1334            outvalC);
     1335
     1336    return (outvalC);
     1337}
     1338
     1339/**
     1340 * Determine whether @p format is supported by the kernel. Uses /proc/filesystems
     1341 * under Linux and @c lsvfs under FreeBSD.
     1342 * @param format The format to test.
     1343 * @return TRUE if the format is supported, FALSE if not.
     1344 */
     1345bool is_this_a_valid_disk_format(char *format)
     1346{
     1347    char *good_formats = NULL;
     1348    char *command = NULL;
     1349    char *format_sz = NULL;
     1350    char *p = NULL;
     1351
     1352    FILE *pin;
     1353    int retval;
     1354
     1355    assert_string_is_neither_NULL_nor_zerolength(format);
     1356
     1357    mr_asprintf(format_sz, "%s ", format);
     1358
     1359#ifdef __FreeBSD__
     1360    mr_asprintf(command, "lsvfs | tr -s '\t' ' ' | grep -v Filesys | grep -v -- -- | cut -d' ' -f1 | tr -s '\n' ' '");
     1361#else
     1362    mr_asprintf(command, "grep -v nodev /proc/filesystems | tr -s '\t' ' ' | cut -d' ' -f2 | tr -s '\n' ' '");
     1363#endif
     1364
     1365    pin = popen(command, "r");
     1366    mr_free(command);
     1367
     1368    if (!pin) {
     1369        log_OS_error("Unable to read good formats");
     1370        retval = 0;
     1371    } else {
     1372        mr_getline(p, pin);
     1373        good_formats = mr_strip_spaces(p);
     1374        mr_free(p);
     1375        (void)pclose(pin);
     1376        mr_strcat(good_formats, " swap lvm raid ntfs-3g ntfs 7 ");  // " ntfs 7 " -- um, cheating much? :)
     1377        if (strstr(good_formats, format_sz)) {
     1378            retval = 1;
     1379        } else {
     1380            retval = 0;
     1381        }
     1382    }
     1383    mr_free(good_formats);
     1384    mr_free(format_sz);
     1385
     1386    return (retval);
     1387}
     1388
     1389
     1390/** @def SWAPLIST_COMMAND The command to list the swap files/partitions in use. */
     1391
     1392/**
     1393 * Determine whether @p device_raw is currently mounted.
     1394 * @param device_raw The device to check.
     1395 * @return TRUE if it's mounted, FALSE if not.
     1396 */
     1397bool is_this_device_mounted(char *device_raw)
     1398{
     1399
     1400    char *tmp = NULL;
     1401    bool retval = FALSE;
     1402
     1403    mr_asprintf(tmp, "mr-device-mounted %s > /dev/null", device_raw);
     1404    if (system(tmp) == 0) {
     1405        retval = TRUE;
     1406    }
     1407    mr_free(tmp);
     1408    return(retval);
     1409}
     1410
     1411#ifdef __FreeBSD__
     1412//                       CODE IS FREEBSD-SPECIFIC
     1413/**
     1414 * Create a loopback device for specified @p fname.
     1415 * @param fname The file to associate with a device.
     1416 * @return /dev entry for the device, or NULL if it couldn't be allocated.
     1417 */
     1418char *make_vn(char *fname)
     1419{
     1420    char *device = (char *) malloc(MAX_STR_LEN);
     1421    char *mddevice = NULL;
     1422    char *command = NULL;
     1423    char *tmp = NULL;
     1424    int vndev = 2;
     1425
     1426    tmp = call_program_and_get_last_line_of_output("/sbin/sysctl -n kern.osreldate");
     1427    if (atoi(tmp) < 500000) {
     1428        do {
     1429            mr_asprintf(mddevice, "vn%ic", vndev++);
     1430            mr_free(command);
     1431            mr_asprintf(command, "vnconfig %s %s", mddevice, fname);
     1432            if (vndev > 10) {
     1433                mr_free(tmp);
     1434                mr_free(mddevice);
     1435                mr_free(command);
     1436                return NULL;
     1437            }
     1438        }
     1439        while (system(command));
     1440    } else {
     1441        mr_asprintf(command, "mdconfig -a -t vnode -f %s", fname);
     1442        mddevice = call_program_and_get_last_line_of_output(command);
     1443        if (!strstr(mddevice, "md")) {
     1444            mr_free(tmp);
     1445            mr_free(command);
     1446            mr_free(mddevice);
     1447            return NULL;
     1448        }
     1449    }
     1450    mr_free(tmp);
     1451    mr_free(command);
     1452    sprintf(device, "/dev/%s", mddevice);
     1453    mr_free(mddevice);
     1454    return device;
     1455}
     1456
     1457
     1458
     1459//                       CODE IS FREEBSD-SPECIFIC
     1460/**
     1461 * Deallocate specified @p dname.
     1462 * This should be called when you are done with the device created by make_vn(),
     1463 * so the system does not run out of @c vn devices.
     1464 * @param dname The device to deallocate.
     1465 * @return 0 for success, nonzero for failure.
     1466 */
     1467int kick_vn(char *dname)
     1468{
     1469    char *command = NULL;
     1470    char *tmp = NULL;
     1471    int res = 0;
     1472
     1473    if (strncmp(dname, "/dev/", 5) == 0) {
     1474        dname += 5;
     1475    }
     1476
     1477    tmp = call_program_and_get_last_line_of_output("/sbin/sysctl -n kern.osreldate");
     1478    if (atoi(tmp) < 500000) {
     1479        mr_asprintf(command, "vnconfig -d %s", dname);
     1480    } else {
     1481        mr_asprintf(command, "mdconfig -d -u %s", dname);
     1482    }
     1483    mr_free(tmp);
     1484    res = system(command);
     1485    mr_free(command);
     1486    return(res);
     1487}
     1488#endif
     1489
     1490
     1491/**
     1492 * Mount the CD-ROM at @p mountpoint.
     1493 * @param device The device (or file if g_ISO_restore_mode) to mount.
     1494 * @param mountpoint The place to mount it.
     1495 * @return 0 for success, nonzero for failure.
     1496 */
     1497int mount_USB_here(char *device, char *mountpoint)
     1498{
     1499    /*@ buffer ****************************************************** */
     1500    char *command = NULL;
     1501    int retval;
     1502
     1503    assert_string_is_neither_NULL_nor_zerolength(device);
     1504    assert_string_is_neither_NULL_nor_zerolength(mountpoint);
     1505
     1506    make_hole_for_dir(mountpoint);
     1507    if (isdigit(device[0])) {
     1508        return(1);
     1509    }
     1510    log_msg(4, "(mount_USB_here --- device=%s, mountpoint=%s", device, mountpoint);
     1511
     1512#ifdef __FreeBSD__
     1513    mr_asprintf(command, "mount_vfat %s %s 2>> %s", device, mountpoint, MONDO_LOGFILE);
     1514
     1515#else
     1516    mr_asprintf(command, "mount %s -t vfat %s 2>> %s", device, mountpoint, MONDO_LOGFILE);
     1517#endif
     1518
     1519    log_msg(4, command);
     1520    retval = system(command);
     1521    log_msg(1, "system(%s) returned %d", command, retval);
     1522    mr_free(command);
     1523
     1524    return (retval);
     1525}
     1526
     1527/**
     1528 * Find out what number CD is in the drive.
     1529 * @param bkpinfo The backup information structure. The @c bkpinfo->media_device field is the only one used.
     1530 * @return The current CD number, or -1 if it could not be found.
     1531 * @note If the CD is not mounted, it will be mounted
     1532 * (and remain mounted after this function returns).
     1533 */
     1534int what_number_cd_is_this(void) {
     1535
     1536    int cd_number = -1;
     1537    char *mountdev = NULL;
     1538    char *tmp = NULL;
     1539
     1540    assert(bkpinfo != NULL);
     1541//  log_it("Asking what_number_cd_is_this");
     1542    if ((g_ISO_restore_mode) || (g_restoring_live_from_cd)) {
     1543        tmp = call_program_and_get_last_line_of_output("mount | grep iso9660 | awk '{print $3;}'");
     1544        mr_asprintf(mountdev, "%s%s", tmp, "/archives/THIS-CD-NUMBER");
     1545        mr_free(tmp);
     1546        cd_number = atoi(last_line_of_file(mountdev));
     1547        mr_free(mountdev);
     1548        return (cd_number);
     1549    }
     1550
     1551    if ((bkpinfo->media_device == NULL) || !does_file_exist(bkpinfo->media_device)) {
     1552        log_it("ERROR: bkpinfo->media_device shoulnd't be unaccessible here\n");
     1553        /* trying again ! */
     1554        bkpinfo->media_device = find_optical_device();
     1555    }
     1556    if ((bkpinfo->media_device == NULL) || !does_file_exist(bkpinfo->media_device)) {
     1557        fatal_error("ERROR: bkpinfo->media_device shoulnd't really be unaccessible here\n");
     1558    }
     1559    if (!is_this_device_mounted(MNT_CDROM)) {
     1560        mount_media(MNT_CDROM);
     1561    }
     1562
     1563    cd_number = atoi(last_line_of_file(MNT_CDROM "/archives/THIS-CD-NUMBER"));
     1564    return(cd_number);
     1565}
     1566
     1567
     1568
     1569
     1570/**
     1571 * Ask the user for CD number @p cd_number_i_want.
     1572 * Sets g_current_media_number once the correct CD is inserted.
     1573 * @param bkpinfo The backup information structure. Fields used:
     1574 * - @c bkpinfo->backup_media_type
     1575 * - @c bkpinfo->prefix
     1576 * - @c bkpinfo->isodir
     1577 * - @c bkpinfo->media_device
     1578 * - @c bkpinfo->please_dont_eject_when_restoring
     1579 * @param cd_number_i_want The CD number to ask for.
     1580 */
     1581void
     1582insist_on_this_cd_number(int cd_number_i_want)
     1583{
     1584
     1585    /*@ int ************************************************************* */
     1586    int res = 0;
     1587
     1588
     1589    /*@ buffers ********************************************************* */
     1590    char *tmp = NULL;
     1591    char *mds = NULL;
     1592    char *request = NULL;
     1593
     1594    assert(bkpinfo != NULL);
     1595    assert(cd_number_i_want > 0);
     1596
     1597//  log_msg(3, "Insisting on CD number %d", cd_number_i_want);
     1598
     1599    if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
     1600        log_msg(3,
     1601                "No need to insist_on_this_cd_number when the backup type isn't CD-R(W) or NFS or ISO");
     1602        return;
     1603    }
     1604    if (!does_file_exist(MNT_CDROM)) {
     1605        mr_asprintf(tmp, "mkdir -p " MNT_CDROM);
     1606        run_program_and_log_output(tmp, 5);
     1607        mr_free(tmp);
     1608    }
     1609
     1610    if (g_ISO_restore_mode || bkpinfo->backup_media_type == iso || bkpinfo->backup_media_type == netfs) {
     1611        g_ISO_restore_mode = TRUE;
     1612    }
     1613    if ((res = what_number_cd_is_this()) != cd_number_i_want) {
     1614        log_msg(3, "Currently, we hold %d but we want %d", res, cd_number_i_want);
     1615
     1616        /* Now we need to umount the current media to have the next mounted after */
     1617        run_program_and_log_output("umount -d " MNT_CDROM, FALSE);
     1618        log_msg(3, "Mounting next media %d",cd_number_i_want);
     1619        g_current_media_number = cd_number_i_want;
     1620        mount_media(MNT_CDROM);
     1621
     1622        mds = media_descriptor_string(bkpinfo->backup_media_type);
     1623        log_msg(3, "Insisting on %s #%d", mds, cd_number_i_want);
     1624        mr_asprintf(request, "Please insert %s #%d and press Enter.", mds, cd_number_i_want);
     1625        mr_free(mds);
     1626
     1627        while (what_number_cd_is_this() != cd_number_i_want) {
     1628            sync();
     1629            if (is_this_device_mounted(MNT_CDROM)) {
     1630                res =
     1631                    run_program_and_log_output("umount -d " MNT_CDROM, FALSE);
     1632            } else {
     1633                res = 0;
     1634            }
     1635            if (res) {
     1636                log_to_screen("WARNING - failed to unmount CD-ROM drive");
     1637            }
     1638            if (!bkpinfo->please_dont_eject) {
     1639                res = eject_device(bkpinfo->media_device);
     1640            } else {
     1641                res = 0;
     1642            }
     1643            if (res) {
     1644                log_to_screen("WARNING - failed to eject CD-ROM disk");
     1645            }
     1646            popup_and_OK(request);
     1647            if (!bkpinfo->please_dont_eject) {
     1648                inject_device(bkpinfo->media_device);
     1649            }
     1650            sync();
     1651        }
     1652        mr_free(request);
     1653
     1654        log_msg(1, "Thankyou. Proceeding...");
     1655        g_current_media_number = cd_number_i_want;
     1656    }
     1657}
     1658
     1659
    17511660/* Update the bkpinfo structure for exclude & include paths
    17521661 * in order to handle correctly paths corresponding to devices */
     
    21082017    // Tape, CD, NETFS, ...?
    21092018    srandom(getpid());
    2110     bkpinfo->backup_media_type =
    2111         (g_restoring_live_from_cd) ? cdr :
    2112         which_backup_media_type(bkpinfo->restore_data);
     2019    bkpinfo->backup_media_type = (g_restoring_live_from_cd) ? cdr : which_backup_media_type(bkpinfo->restore_data);
    21132020    if (bkpinfo->backup_media_type == none) {
    21142021        log_to_screen("User has chosen not to backup the machine");
    21152022        finish(1);
    21162023    }
    2117     log_msg(3, "media type = %s", bkptype_to_string(bkpinfo->backup_media_type));
     2024    tmp = bkptype_to_string(bkpinfo->backup_media_type);
     2025    log_msg(3, "media type = %s", tmp);
     2026    mr_free(tmp);
    21182027
    21192028    /* Why asking to remove the media with tape ?
     
    27552664    log_it("media device = %s", bkpinfo->media_device);
    27562665    log_it("media size = %ld", bkpinfo->media_size);
    2757     log_it("media type = %s", bkptype_to_string(bkpinfo->backup_media_type));
     2666    tmp = bkptype_to_string(bkpinfo->backup_media_type);
     2667    log_it("media type = %s", tmp);
     2668    mr_free(tmp);
    27582669    if (bkpinfo->prefix != NULL) {
    27592670        log_it("prefix = %s", bkpinfo->prefix);
Note: See TracChangeset for help on using the changeset viewer.