Ext4 on MacOS X

With the new Raspberry Pi 3 Model B at hand and Raspbian already running, I wanted to see if the AArch64 port of Arch Linux would run as well. As I didn't have a real computer available at that time, I tried to get the image on the microSD card on MacOS .

First, let's unmount (but not eject) the microSD card:

$ diskutil umountDisk disk2
Unmount of all volumes on disk2 was successful
Create two partitions on the device:
$ sudo fdisk -e /dev/rdisk2
fdisk: 1> erase
fdisk:*1> edit 1
Partition id ('0' to disable)  [0 - FF]: [0] (? for help) 0B
Do you wish to edit in CHS mode? [n] 
Partition offset [0 - 31116288]: [63] 
Partition size [1 - 31116225]: [31116225] 204800

fdisk:*1> edit 2
Partition id ('0' to disable)  [0 - FF]: [0] (? for help) 83
Do you wish to edit in CHS mode? [n] 
Partition offset [0 - 31116288]: [204863] 
Partition size [1 - 30911425]: [30911425] 

fdisk:*1> p
Disk: /dev/rdisk2       geometry: 1936/255/63 [31116288 sectors]
Offset: 0       Signature: 0xAA55
         Starting       Ending
 #: id  cyl  hd sec -  cyl  hd sec [     start -       size]
------------------------------------------------------------------------
 1: 0B    0   1   1 - 1023 254  63 [        63 -     204800] Win95 FAT-32
 2: 83 1023 254  63 - 1023 254  63 [    204863 -   30911425] Linux files*
 3: 00    0   0   0 -    0   0   0 [         0 -          0] unused      
 4: 00    0   0   0 -    0   0   0 [         0 -          0] unused      
fdisk:*1> write
Writing MBR at offset 0.
fdisk: 1> quit
Create a file system on each partition (we'll need e2fsprogs to create an ext4 file system):
$ sudo newfs_msdos -v boot /dev/rdisk2s1
$ sudo /opt/local/sbin/mkfs.ext4 /dev/rdisk2s2 
As MacOS is able to read FAT-32, we should be able to mount it right away:
$ diskutil mount disk2s1
Volume BOOT on disk2s1 mounted

$ df -h /Volumes/BOOT
Filesystem     Size   Used  Avail Capacity  Mounted on
/dev/disk2s1  100Mi  762Ki   99Mi     1%    /Volumes/BOOT
Mounting a ext4 file systems turned out to be more difficult and there are several solutions available.

ext2fuse

ext2fuse is said to provide ext2/ext3 support via FUSE, but it segfaults on our newly created ext4 file system:
$ sudo /opt/local/bin/ext2fuse /dev/disk2s2 /mnt/disk
/dev/disk2s2 is to be mounted at /mnt/disk
fuse-ext2fs: Filesystem has unsupported feature(s) while trying to open /dev/disk2s2
Segmentation fault: 11

$ mount | tail -1
/dev/disk2s2 on /mnt/disk (osxfuse, synchronous)

$ df -h /mnt/disk
Filesystem     Size   Used  Avail Capacity  Mounted on
/dev/disk2s2    0Bi    0Bi    0Bi   100%    /mnt/disk

$ touch /mnt/disk/foo
touch: /mnt/disk/foo: Device not configured
Maybe ext4 is just too new for ext2fuse, let's try with ext2 instead:
$ sudo /opt/local/sbin/mkfs.ext2 /dev/rdisk2s2
$ sudo /opt/local/bin/ext2fuse /dev/disk2s2 /mnt/disk
/dev/disk2s2 is to be mounted at /mnt/disk
fuse-ext2 initialized for device: /dev/disk2s2
block size is 4096
ext2fuse_dbg_msg: File not found by ext2_lookup while looking up "DCIM"
ext2fuse_dbg_msg: File not found by ext2_lookup while looking up "VSCAN"
ext2fuse_dbg_msg: File not found by ext2_lookup while looking up "DCIM"
ext2fuse_dbg_msg: File not found by ext2_lookup while looking up ".Spotlight-V100"
ext2fuse_dbg_msg: File not found by ext2_lookup while looking up ".metadata_never_index"
[...]
This command never completes but could be terminated with ^C. The same happens with an ext3 file system.

ext4fuse

ext4fuse aims for ext4 support via FUSE, let see how that goes:
$ sudo /opt/local/sbin/mkfs.ext4 /dev/rdisk2s2
$ sudo /opt/local/bin/ext4fuse /dev/disk2s2 /mnt/disk 
$ mount | tail -1
ext4fuse@osxfuse0 on /mnt/disk (osxfuse, synchronous)

$ df -h /mnt/disk
Filesystem          Size   Used  Avail Capacity  Mounted on
ext4fuse@osxfuse0    0Bi    0Bi    0Bi   100%    /mnt/disk

$ sudo touch /mnt/disk/foo
touch: /mnt/disk/foo: Function not implemented
So close! :-) But there's no write support for ext4fuse yet.

fuse-ext2

There's another option, called fuse-ext2 which appears to feature (experimental) write support. We'll need FUSE for macOS again and then build fuse-ext2 from scratch:
$ sudo port install e2fsprogs
$ git clone https://github.com/alperakcan/fuse-ext2.git fuse-ext2-git
$ cd $_
$ ./autogen.sh && LDFLAGS="-L/opt/local/lib" CFLAGS="-I/opt/local/include" \
    ./configure --prefix=/opt/fuse-ext2
$ make && sudo make install
So, let's try:
$ sudo /opt/fuse-ext2/bin/fuse-ext2 /dev/rdisk2s2 /mnt/disk -o rw+
Rats - a window pops up with:
FUSE-EXT2 could not mount /dev/disk2s2
at /mnt/disk/ because the following problem occurred:
But the error description is empty, and there's nothing in the syslog too. After some digging I decided to reboot and this time it worked:
$ sudo /opt/fuse-ext2/bin/fuse-ext2 /dev/rdisk2s2 /mnt/disk -o rw+
$ mount | tail -1
/dev/rdisk2s2 on /mnt/disk (osxfuse_ext2, local, synchronous)

$ df -h /mnt/disk/
Filesystem      Size   Used  Avail Capacity  Mounted on
/dev/rdisk2s2   15Gi  104Mi   14Gi     1%    /mnt/disk

$ sudo touch /mnt/disk/foo
$ ls -l /mnt/disk/foo
-rw-r--r--  1 root  wheel  0 Mar  5 14:29 /mnt/disk/foo
That should be enough for us to finally install the ArchLinux image on that microSD card:
$ tar -C /Volumes/BOOT/ -xzf ArchLinuxARM-rpi-3-latest.tar.gz boot
$ mv /Volumes/BOOT/{boot/*,} && rmdir /Volumes/BOOT/boot
And for the root file system:
$ sudo tar --exclude="./boot" -C /mnt/disk/ -xvzf ArchLinuxARM-rpi-3-latest.tar.gz 
x ./bin
x ./dev/: Line too long
tar: Error exit delayed from previous errors.
Apparently bsdtar has trouble when the --exclude switch is used, so let's try without and remove the superfluous /boot contents later:
$ sudo tar -C /mnt/disk/ -xzf ArchLinuxARM-rpi-3-latest.tar.gz
$ sudo rm -r /mnt/disk/boot/*
This takes quite a long while to complete, but completed eventually. Of course, all this could be avoided if would have used another operating system in the first place :-)