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