Copying Files Between Linux And FreeDOS
=======================================

I boot FreeDOS both on real hardware and on virtual machines. During
development i prefer to test DOS builds in a virtual machine for
convenience.  I often use qemu for this.

Up until around 2019, i was using guestmount on Fedora to copy files
back and forth between my host machine and the virtual machine.  For
me it became unstable when i copied large amounts of data or large
numbers of files.  Also, this method won't work on Slackware Linux
because libguestfs depends on supermin, which has a hard requirement
for the package manager to do dependency checking.

<https://listman.redhat.com/archives/libguestfs/2014-November/
msg00072.html>

These days i use a shell script and qemu-storage-daemon to mount the
guest filesystem and copy files.  This method is a little more
technical, but it is built-in to qemu and it has been reliable for me.

Mount Script Description
========================

$ pr -n -t mount-qemu-freedos.sh
    1   #!/bin/sh
    2   disk="/Qemu/freedos-1.3/freedos-1.3.qcow2"
    3   log="/Qemu/fuse/freedos-1.3.log"
    4   mnt="/Qemu/fuse/freedos-1.3.fuse"
    5   pid="/Qemu/fuse/freedos-1.3.pid"
    6   dir="/mnt/freedos-1.3"
    7   
    8   # truncate log
    9   cat /dev/null >"$log"
   10   
   11   # translate qcow2 to raw on the fly, and save the pid
   12   # https://www.qemu.org/2021/08/22/fuse-blkexport/
   13   qemu-storage-daemon \
   14       --blockdev node-name=prot-node,driver=file,filename="$disk" \
   15       --blockdev node-name=fmt-node,driver=qcow2,file=prot-node \
   16       --export \
   17       type=fuse,id=exp0,node-name=fmt-node,mountpoint="$mnt",writable=on \
   18       >"$log" 2>&1 &
   19   echo $! >"$pid"
   20   
   21   # wait a second, then probe the partitions
   22   sleep 1
   23   kpartx -av "$mnt" >"$log" 2>&1
   24   
   25   # find the loop device
   26   loopdev=$(grep '^add map ' <"$log" | head -1 | cut -d ' ' -f 3)
   27   loopdev="/dev/mapper/$loopdev"
   28   
   29   # mount it
   30   mount -o uid=1000,gid=1000 "$loopdev" "$dir"

The mount script is 30 lines long.

    1   #!/bin/sh

Line 1 is the standard shebang for a POSIX shell script.

    2   disk="/Qemu/freedos-1.3/freedos-1.3.qcow2"
    3   log="/Qemu/fuse/freedos-1.3.log"
    4   mnt="/Qemu/fuse/freedos-1.3.fuse"
    5   pid="/Qemu/fuse/freedos-1.3.pid"
    6   dir="/mnt/freedos-1.3"
    7   

Lines 2 through 7 set variables for the paths to the FreeDOS disk
image, the log file used by the mount script, the fuse mountpoint,
the fuse process ID, and the directory to mount the FreeDOS
filesystem to.

The "fuse mountpoint" is used by qemu-storage-daemon to translate
the FreeDOS disk image to a Linux block device.

    8   # truncate log
    9   cat /dev/null >"$log"
   10   

Lines 8 through 10 either truncates the log file to 0 bytes, or
creates it if it doesn't exist.

   11   # translate qcow2 to raw on the fly, and save the pid
   12   # https://www.qemu.org/2021/08/22/fuse-blkexport/
   13   qemu-storage-daemon \
   14       --blockdev node-name=prot-node,driver=file,filename="$disk" \
   15       --blockdev node-name=fmt-node,driver=qcow2,file=prot-node \
   16       --export \
   17       type=fuse,id=exp0,node-name=fmt-node,mountpoint="$mnt",writable=on \
   18       >"$log" 2>&1 &

Lines 11 through 18 run qemu-storage-daemon to translate the FreeDOS
disk image to a Linux block device.  All output from stderr and stdout
gets redirected to the log file.

   19   echo $! >"$pid"
   20   

Lines 19 through 20 save the qemu-storage-daemon PID to a temporary
file.  This information is useful to have when it comes time to
unmount the FreeDOS filesystem.

   21   # wait a second, then probe the partitions
   22   sleep 1

Lines 21 & 22 wait for one second to give Linux a moment.

   23   kpartx -av "$mnt" >"$log" 2>&1
   24   

Lines 23 & 24 probe the block device to inform Linux of the FreeDOS
partition table.  This creates block devices for the guest partitions
in the FreeDOS virtual machine.  All output from stderr and stdout
gets redirected to the log file.

   25   # find the loop device
   26   loopdev=$(grep '^add map ' <"$log" | head -1 | cut -d ' ' -f 3)
   27   loopdev="/dev/mapper/$loopdev"
   28   

Lines 25 through 28 use grep to find the first partition probed by
kpartx.

   28   
   29   # mount it
   30   mount -o uid=1000,gid=1000 "$loopdev" "$dir"

Lines 28 through 30 mount the FreeDOS filesystem, giving full
permission to user 1000 and group 1000.  This allows you to copy
files between the FreeDOS filesystem and an unprivileged Linux
account.

Mount Script Example
====================

I make sure the FreeDOS virtual machine is shut down.

Prior to running this script for the first time, i created the
following directories:

# mkdir -p /mnt/freedos-1.3
# mkdir -p /Qemu/fuse

I run this script as root.

# ./mount-qemu-freedos.sh

Now that the FreeDOS filesystem is mounted, simply copy files back
and forth between $HOME and /mnt/freedos-1.3/

$ ls -l /mnt/freedos-1.3/*.{COM,SYS}
-rwxr-xr-x 1 ben ben 85480 Jul 10  2021 /mnt/freedos-1.3/COMMAND.COM*
-rwxr-xr-x 1 ben ben 46256 Feb 20  2022 /mnt/freedos-1.3/KERNEL.SYS*

Mount Script Limitations
========================

* This script does not check whether the filesystem is locked by a
  running virtual machine.
* This script does not check whether the filesystem has already been
  mounted.
* The "sleep 1" command is not elegant, but it helps avoid a race
  condition and it works on my computer. ;)
* This script assumes that you wish to copy files between the Linux
  host and the FIRST partition of the FreeDOS guest.
* This script assumes that your user and group id are 1000.  To find
  out your actual user and group id, run the id command:

  $ id
  uid=1000(ben) gid=1000(ben) groups=...

Notes:

* Watch out for errors about a Read-only filesystem while removing a
  file or copying a file to the FreeDOS filesystem.  This usually
  means that Linux mounted the filesystem read-only because the FAT
  filesystem was marked "unclean" and it needs to be repaired.  If in
  doubt, reboot and then check the FreeDOS filesystem.

Unmount Script Description
==========================

$ pr -n -t unmount-qemu-freedos.sh
    1   #!/bin/sh
    2   mnt="/Qemu/fuse/freedos-1.3.fuse"
    3   pid="/Qemu/fuse/freedos-1.3.pid"
    4   dir="/mnt/freedos-1.3"
    5   
    6   # unmount the filesystem
    7   umount "$dir"
    8   
    9   # unmap the partition and delete the loop device
   10   kpartx -d "$mnt"
   11   
   12   # kill qemu-storage-daemon
   13   kill $(<$pid)

The unmount script is 13 lines long.

    1   #!/bin/sh

Line 1 is the standard shebang for a POSIX shell script.

    2   mnt="/mnt/fuse/freedos-1.3.fuse"
    3   pid="/mnt/fuse/freedos-1.3.pid"
    4   dir="/mnt/freedos-1.3"
    5   

Lines 2 through 5 set variables for the paths to the fuse mountpoint,
the fuse process ID, and the directory where the FreeDOS filesystem
is mounted.

    6   # unmount the filesystem
    7   umount "$dir"
    8   

Lines 6 through 8 unmount the FreeDOS filesystem.

    9   # unmap the partition and delete the loop device
   10   kpartx -d "$mnt"
   11   

Lines 9 through 11 unmap the FreeDOS partition and delete the loop
device that was created by qemu-storage-daemon.

   12   # kill qemu-storage-daemon
   13   kill $(<$pid)

Lines 12 & 13 quit the qemu-storage-daemon process, which is no
longer needed.

Unmount Script Example
======================

Always unmount the FreeDOS filesystem before you use it again in
your virtual machine.  To do otherwise is to risk filesystem
corruption.

I run this script as root.

# ./unmount-qemu-freedos.sh

Alternatives
============

* Qemu has a VVFAT feature to translate your host filesystem to a
  virtual FAT device, similar to what DOSBox and DOSBox-X do.  I
  have experienced data corruption writing to VVFAT from FreeDOS.
  It's safest to use in a read-only fashion, copying files from the
  Linux host.

  Example qemu argument:
  -drive file=fat:rw:$HOME/dos,format=raw,media=disk

  <https://en.wikibooks.org/wiki/QEMU/Devices/Storage
  #Virtual_FAT_filesystem_(VVFAT)>

* The VirtualBox equivalent to qemu-storage-daemon is a utility named vdfuse.

  <http://download.opensuse.org/repositories/Virtualization:/
  VirtualBox_backports/openSUSE_Factory/src/vdfuse-8.2a-6.14.src.rpm>

  <https://forums.virtualbox.org/viewtopic.php?f=7&t=17574>

* mTCP FTP over virtual ethernet device

* Kermit & FOSSIL over virtual serial port


_______________________________________________
Freedos-user mailing list
Freedos-user@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/freedos-user

Reply via email to