Using an external USB 3.5-inch floppy disk drive in Linux

Back in 2004 I needed to get some files off my old 3.5″ floppy disks, so I bought an external USB floppy disk drive to use with a laptop running Windows XP. The label on the drive gives the manufacturer and model as ‘SmartDisk: FDUSB-TM2, Mitsumi Model #: D353FUE’.

Anyway, today I wanted to throw out some 720KB DD (Double Density) and 1440KB HD (High Density) 3.5″ floppy disks but first needed to check their contents and wipe them. So I dug out the SmartDisk USB drive to see if it would work with the current Gentoo Linux installation on my newest laptop. I was pleased to discover that it does, and below are some notes on how to use it in case anyone else needs to use one of these devices.

Once plugged in to a USB port on my laptop, the lsusb command shows the device has been recognised:

Bus 001 Device 013: ID 03ee:6901 Mitsumi SmartDisk FDD

Note that the Linux floppy driver is not needed for USB floppy disk drives:

root # grep -i CONFIG_BLK_DEV_FD /usr/src/linux/.config
# CONFIG_BLK_DEV_FD is not set

A Linux utility named ufiformat is used to low-level format floppy disks in USB floppy disk drives. A Gentoo Linux ebuild for Version 0.9.9 of ufiformat is listed below, and it can be used in a local overlay under the category sys-fs:

# Copyright 1999-2014 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: $

EAPI=5

DESCRIPTION="USB Floppy Disk formatting tool"
HOMEPAGE="http://www.geocities.jp/tedi_world/format_usbfdd_e.html"
SRC_URI="http://www.geocities.jp/tedi_world/${P}.tar.gz"

LICENSE="GPL-2"
SLOT="0"
KEYWORDS="~amd64 ~x86"
IUSE=""

RDEPEND="sys-fs/e2fsprogs"
DEPEND=${RDEPEND}

UPDATE (2 November 2019): As of March 31, 2019, Yahoo! Geocities service has been discontinued, so the ufiformat repository has been moved to GitHub. I have updated the link in the paragraph above accordingly. Therefore, in the ebuild the HOMEPAGE and SRC_URI variables need to be changed – see the update at the end of this blog post.

The ufiformat utility is straightforward to use:

root # ufiformat --help
Usage: ufiformat [OPTION]... [DEVICE]
Format a floppy disk in a USB floppy disk DEVICE.

  -f, --format [SIZE]  specify format capacity SIZE in KB
                       without -f option, the format of the current media will be used
  -V, --verify         verify the medium after formatting
  -F, --force          do not perform any safety checks
  -i, --inquire        show device information, instead of performing format
                       without DEVICE argument, list USB floppy disk devices
  -v, --verbose        show detailed output
  -q, --quiet          suppress minor output
  -h, --help           show this message

To find the device name, use the blkid command before plugging in the USB cable and again after plugging in the USB cable. The extra device listed the second time will be the floppy disk drive. For example, in my case the new line at the end of the blkid output indicated the drive was /dev/sdd:

/dev/sdd: SEC_TYPE="msdos" UUID="BBBA-37AF" TYPE="vfat"

The fdisk command will confirm that the device is the floppy drive:

root # fdisk -l /dev/sdd
Disk /dev/sdd: 720 KiB, 737280 bytes, 1440 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x00000000

Note that /dev/sdd will not be listed in the output of blkid if there is no disk in the floppy drive, although the ls command will list /dev/sdd while the drive is connected to the computer.

Notice that there are no devices /dev/fd0, /dev/fd1, /dev/fd2 and /dev/fd3, etc. This does not matter.

root # ls /dev
audio1           dri      i2c-10   kmem          mapper              nvidiactl  sda1       sequencer2  tty0   tty2   tty30  tty41  tty52  tty63    usbmon3     vcs2    vcsa12
autofs           dsp1     i2c-11   kmsg          mcelog              nvram      sda2       sg0         tty1   tty20  tty31  tty42  tty53  tty7     usbmon4     vcs3    vcsa2
block            fb0      i2c-2    log           mem                 pktcdvd    sda3       sg1         tty10  tty21  tty32  tty43  tty54  tty8     v4l         vcs4    vcsa3
bsg              fd       i2c-3    loop-control  memory_bandwidth    port       sda5       sg2         tty11  tty22  tty33  tty44  tty55  tty9     vboxdrv     vcs5    vcsa4
bus              full     i2c-4    loop0         mixer               ptmx       sda6       sg3         tty12  tty23  tty34  tty45  tty56  ttyS0    vboxdrvu    vcs6    vcsa5
char             fuse     i2c-5    loop1         mixer1              pts        sda7       shm         tty13  tty24  tty35  tty46  tty57  ttyS1    vboxnetctl  vcs7    vcsa6
console          hidraw0  i2c-6    loop2         mqueue              random     sdb        snapshot    tty14  tty25  tty36  tty47  tty58  ttyS2    vboxusb     vcs8    vcsa7
core             hidraw1  i2c-7    loop3         network_latency     rfkill     sdb1       snd         tty15  tty26  tty37  tty48  tty59  ttyS3    vcs         vcs9    vcsa8
cpu              hidraw2  i2c-8    loop4         network_throughput  root       sdc        stderr      tty16  tty27  tty38  tty49  tty6   urandom  vcs1        vcsa    vcsa9
cpu_dma_latency  hpet     i2c-9    loop5         null                rtc        sdc1       stdin       tty17  tty28  tty39  tty5   tty60  usbmon0  vcs10       vcsa1   vga_arbiter
cuse             i2c-0    initctl  loop6         nvidia-modeset      rtc0       sdd        stdout      tty18  tty29  tty4   tty50  tty61  usbmon1  vcs11       vcsa10  video0
disk             i2c-1    input    loop7         nvidia0             sda        sequencer  tty         tty19  tty3   tty40  tty51  tty62  usbmon2  vcs12       vcsa11  zero
root # ls -la /dev/fd
lrwxrwxrwx 1 root root 13 Jan 17 02:13 /dev/fd -> /proc/self/fd
root # ls -la /proc/self/fd
total 0
dr-x------ 2 root root  0 Jan 17 04:26 .
dr-xr-xr-x 8 root root  0 Jan 17 04:26 ..
lrwx------ 1 root root 64 Jan 17 04:26 0 -> /dev/pts/1
lrwx------ 1 root root 64 Jan 17 04:26 1 -> /dev/pts/1
lrwx------ 1 root root 64 Jan 17 04:26 2 -> /dev/pts/1
lr-x------ 1 root root 64 Jan 17 04:26 3 -> /proc/17669/fd

To format an HD floppy disk with the FAT file system, I did the following:

root # ufiformat -f 1440 /dev/sdd
geometry: track=80, head=2, sector=18, block=512
done                                   
root # /usr/sbin/mkfs.vfat /dev/sdd
mkfs.fat 4.0 (2016-05-06)
attribute "partition" not found
root # ufiformat -i /dev/sdd
vendor:  MITSUMI
product: USB FDD
write protect: off
media type: 2HD
status      block size   kb
formatted    2880  512 1440
formattable  2880  512 1440
formattable  1232 1024 1232
formattable  2400  512 1200

To format a DD floppy disk with the FAT file system, I did the following:

root # ufiformat -f 720 /dev/sdd
geometry: track=80, head=2, sector=9, block=512
done                                   
root # /usr/sbin/mkfs.vfat /dev/sdd
mkfs.fat 4.0 (2016-05-06)
attribute "partition" not found
root # ufiformat -i /dev/sdd
vendor:  MITSUMI
product: USB FDD
write protect: off
media type: 2DD
status      block size   kb
formatted    1440  512  720
formattable  1440  512  720

I use the KDE Desktop Environment. The Device Notifier widget in the System Tray shows the drive and — once a formatted floppy disk is in the drive — it is possible to use the Device Notifier to mount, open and unmount the floppy disk. However, it is also possible to use the command line:

root # mkdir /mnt/floppy
root # mount /dev/sdd /mnt/floppy
root # ls /mnt/floppy
root # cp /test.txt /mnt/floppy/
root # ls /mnt/floppy
test.txt
root # umount /dev/sdd

Earlier in this post I showed examples of formatting floppy disks using the FAT file system, but it is of course possible to format them using other file systems, such as:

root # mkfs.ext2 /dev/sdd
mke2fs 1.43.3 (04-Sep-2016)
/dev/sdd contains a vfat file system
Proceed anyway? (y,n) y
Creating filesystem with 720 1k blocks and 96 inodes

Allocating group tables: done                            
Writing inode tables: done                            
Writing superblocks and filesystem accounting information: done

Anyway, I was able to check the contents of the floppies and wipe them before disposing of them. It’s good to know that some old technologies can still be used when needs be. I won’t be throwing out the old floppy disk drive just yet.

UPDATE (2 November 2019): As of March 31, 2019, Yahoo! Geocities service has been discontinued, so the ufiformat repository has been moved to GitHub. Therefore, in the ebuild the HOMEPAGE and SRC_URI variables need to be changed from:

HOMEPAGE="http://www.geocities.jp/tedi_world/format_usbfdd_e.html"
SRC_URI="http://www.geocities.jp/tedi_world/${P}.tar.gz"

to:

HOMEPAGE="https://github.com/tedigh/ufiformat/"
SRC_URI="https://github.com/tedigh/ufiformat/archive/v0.9.9.zip"

or:

HOMEPAGE="https://github.com/tedigh/ufiformat/"
SRC_URI="https://github.com/tedigh/ufiformat/archive/v{$PV}.zip"

A method of ‘masking’ an OpenRC service (NetworkManager, in this case)

A Gentoo Linux user with an installation using OpenRC recently asked in the Gentoo Forums how to either a) disable NetworkManager so that it would not interfere with his netifrc configuration to give his installation a static IP address, or b) configure NetworkManager to use a static IP address (see the thread NetworkManager and static IP [SOLVED! THANKYOU]). In the end he solved the problem by uninstalling NetworkManager, the cleanest solution in his case given that his desktop machine is always in the same location and he does not need the features NetworkManager provides.

Now, although I use NetworkManager instead of netifrc, what intrigued me is that disabling the NetworkManager service using the standard command below does not stop the NetworkManager init script from running at boot-up:

root # rc-update delete NetworkManager default

Despite using the above command, following a reboot the NetworkManager service is still started and becomes active, and the NetworkManager daemon is running. Web browsers and other applications requiring network access still work. In order to stop the service running immediately so that his netifrc static IP address configuration could work, the aforementioned Gentoo user had to stop the NetworkManager service as follows:

root # /etc/init.d/NetworkManager stop

(The command ‘rc-service NetworkManager stop‘ does the same thing.)

The behaviour is the same on my laptop running Gentoo with OpenRC 0.22.4 and NetworkManager installed by networkmanager-1.4.0-r1 ebuild (with the upstream patch and necessary edit to the init script mentioned in Gentoo Bug Report No. 595806 – net-misc/networkmanager-1.4.0-r1[consolekit]: doesn’t automatically activate connections marked with "Automatically connect to this network when it’s available").

So two questions arose: What launches the NetworkManager init script when it has not been added to a runlevel? What needs to be done to stop this from happening? My curiosity was piqued.

As it happens, a somewhat similar situation exists when using systemd rather than OpenRC, as explained in Arch Linux Forums thread [SOLVED] NetworkManager auto restart even though I stop it. and Red Hat Bugzilla Report No. 815243 – Even though NetworkManager was manually stopped, it gets restarted automatically via D-Bus, although those were primarily concerned with how to prevent NetworkManager being restarted during the same session, i.e. without having rebooted.

The following systemd commands are needed to stop immediately the NetworkManager service and keep it from being restarted subsequently during the current session and after rebooting:

root # systemctl mask NetworkManager
root # systemctl stop NetworkManager
root # systemctl disable NetworkManager

Unfortunately there is no equivalent mask command for an OpenRC service. The equivalent OpenRC commands for the second and third commands above are:

root # rc-service NetworkManager stop
root # rc-update delete NetworkManager default

However, as I pointed out earlier, for some reason the latter command does not stop OpenRC running the NetworkManager init script at boot.

I wondered how I could ‘mask’ the NetworkManager service in OpenRC. I asked myself what the systemd mask command actually does. Well, it simply creates a symlink from /etc/systemd/system/NetworkManager.service to /dev/null so that there is no longer a real unit file for systemd to use, and therefore systemd can no longer launch the service. So why not do something similar in OpenRC. I hit upon the idea of telling the NetworkManager init script it needs a non-existent service in order to start, thus preventing OpenRC from starting the NetworkManager service:

root # echo 'rc_need="non-existent_service"' >> /etc/conf.d/NetworkManager # (Or just edit the file manually.)

That is all there is to it. When booting, OpenRC now displays the messages shown below:

* ERROR: NetworkManager needs service(s) non-existent_service
* ERROR: cannot start netmount as NetworkManager would not start
* ERROR: cannot start samba as NetworkManager would not start

As shown below, now the service is not started, so the NetworkManager daemon is never launched:

root # rc-status
Runlevel: default
 dbus                                                  [  started  ]
 syslog-ng                                             [  started  ]
 consolekit                                            [  started  ]
 netmount                                              [  stopped  ]
 cupsd                                                 [  started  ]
 samba                                                 [  stopped  ]
 cronie                                                [  started  ]
 clamd                                                 [  started  ]
 bluetooth                                             [  started  ]
 xdm                                                   [  started  ]
 cups-browsed                                          [  started  ]
 sshd                                                  [  started  ]
 local                                                 [  started  ]
Dynamic Runlevel: hotplugged
Dynamic Runlevel: needed/wanted
 modules-load                                          [  started  ]
 xdm-setup                                             [  started  ]
 avahi-daemon                                          [  started  ]
Dynamic Runlevel: manual
root # ps -ef | grep -v grep | grep -i network
root #

As expected, given that the netmount service and samba service depend on the NetworkManager service starting, neither of those services were able to start either.

Furthermore, because I masked the service, if I attempt to start it manually:

root # rc-service NetworkManager restart
 * ERROR: NetworkManager needs service(s) non-existent_service

To unmask the service in OpenRC, all that is needed is:

root # sed -i '/rc_need="non-existent_service"/d' /etc/conf.d/NetworkManager # (Or just edit the file manually.)

Note that, instead of “non-existent_service” I could have written “fubar”, “null” or any other string that is not the name of an actual service. But “non-existent_service” is more meaningful and less likely to confuse me when viewing system messages and contents of the service configuration file.

In summary…

Why does OpenRC run the NetworkManager service init script when it is not in any runlevel?

I have no idea!

I wondered if the D-Bus service does it. The Arch Wiki article on NetworkManager claims this is the case (see the section titled Disable NetworkManager). However, my attempts at preventing D-Bus doing anything to NetworkManager did not stop the NetworkManager init script from being run at boot. I deleted /etc/dbus-1/system.d/org.freedesktop.NetworkManager.conf and /etc/dbus-1/system.d/nm-dispatcher.conf but that did not help. Neither did creating an appropriate /etc/dbus-1/system.d/org.freedesktop.NetworkManager.conf or /etc/dbus-1/system-local.conf. There is no /usr/share/dbus-1/system-services/org.freedesktop.NetworkManager.service file in my Gentoo installation using OpenRC, but creating one did not help either. So, if you know what runs the OpenRC NetworkManager init script when it is not in any runlevel, please post a comment.

Anyway, I now know how to prevent it happening, so I have satisfied my curiosity. Below I list the commands I actually used in a Gentoo Linux installation (amd64, OpenRC) and a Sabayon Linux installation (~amd64, systemd) to check the functionality.

OpenRC

The following two (optionally three) commands are needed to stop immediately the NetworkManager service and prevent it being restarted subsequently during this session and after rebooting:

root # rc-service NetworkManager stop
root # echo 'rc_need="non-existent_service"' >> /etc/conf.d/NetworkManager
root # rc-update del NetworkManager default # (Optional.)

The following two (optionally three) commands are needed to unmask the NetworkManager service and start it immediately, and make it start automatically after rebooting:

root # sed -i '/rc_need="non-existent_service"/d' /etc/conf.d/NetworkManager
root # rc-service NetworkManager restart
root # rc-update add NetworkManager default # Only needed if I earlier deleted the service from the default runlevel.

systemd

The following three commands are needed to stop immediately the NetworkManager service and prevent it being restarted subsequently during this session and after rebooting:

root # systemctl mask NetworkManager
root # systemctl stop NetworkManager
root # systemctl disable NetworkManager

The following three systemd commands are needed to unmask the NetworkManager service and start it immediately, and also make it start automatically after rebooting:

root # systemctl unmask NetworkManager
root # systemctl enable NetworkManager
root # systemctl start NetworkManager