Translators

Contents

What are translators?

Translators are a massively important thing in the Hurd; they mount filesystems, handle device nodes, and can provide symlinks to filesystems which don't support them natively. But what are they, exactly? Consider your every-day average *NIX filesystem. It contains files, directories, and device nodes. These things look similar, but have very different properties. In, say, Linux if you wanted to add something new you'd need to write a device driver or a FUSE filesystem, which requires a kernel module running anyway. In the Hurd, things are a little different. If you want something new, you write a translator to handle it and, unless it requires accessing any low-level stuff, you can leave the kernel alone and run it in userspace.

Put simply, a translator sits between the user and the filesystem, and handles requests from the user in different ways. An example is the translator for /dev/null. In Linux, this is a device implemented in the kernel, in the Hurd, a user-space translator provides it. Another example is your root filesystem. The ext2fs translator receives incoming requests to read or write data, and passes those on to the kernel as requests to do things with the partition, ext2fs then returns the data to the user. Obviously, that is a translator which does require kernel-level code to work.

What about symlinks? Well, most filesystems used in *NIX provide some functionality for symlinks, but what about a filesystem with no symlink support? You could write a translator to sit in a specific file, and redirect all requests to another file. Thus, symlinks are formed.

Passive and Active Translators

There are two types of translators in the Hurd, passive and active. When you start an active translator, it starts immediately, regardless of whether you ever try to use it. In contrast, a passive translator starts running when you access it. For example, you could 'mount' a filesystem, but rather than mount it immediately, have it mount only when you try to access it.

The other main difference between active and passive translators is persistance. If an active translator dies or is killed at some point, it stays dead until you manually restart it. However, a passive translator has information about itself written to the underlying filesystem, and so can be restarted, even between boots.

Examples

Hello, world!

Of course, Hurd has a hello world translator:

settrans -cg hello /hurd/hello
cat hello

Behold, the text "Hello, world!" appears! Now, what just happened here? Well, you started the hello translator watching a file named hello, and then tried to read that file. The read request was sent to the translator, which returned the string "Hello, world!". Of course, you can achieve the same effect by having a file containing that text, but it serves as a simple example of how translators work.

Delete the translator by stopping it:

settrans -fg hello

Satisfy yourself that the file which remains is, in fact, empty, and then delete it.

Mount

In Hurd, the mount command is actually a wrapper around settrans. You may have noticed there is no umount. Do you want to know how to really 'mount' things in Hurd? This is what your mount command does:

settrans -a $path /hurd/ext2fs --writable $device

That's not just a regular mount, that's a mount which will persist between reboots. You don't even need an /etc/fstab file for permanent mounts, translators make this simple to achieve on the Hurd. But how do you unmount things? Well, it's the same way you kill any other translator:

settrans -fg $path

But for internal HDDs (the only kind you'll be dealing with, as the Hurd doesn't support USB yet), there is no need to unmount partitions before rebooting, the translator will handle that for you. And when you boot up again, if you didn't kill the translator, simply accessing the mounted partition will have the translator mount it for you.

Translators

The following translators are included in the hurd package in ArchHurd, you don't have to install them. You don't have to be root to use translators. They're all located in /hurd.

The options -fg are used to force the translator to go away.

nfs

With the nfs translator you can mount nfs shares in Hurd.

settrans -cafg /mount/point/ /hurd/nfs server:/share

You can also use mount for this task.

mount -t nfs server:/share /mount/point

ftpfs

ftpfs makes it possible to access ftp shares.

settrans -cfg ftp /hurd/ftpfs SERVER:/remote/path

hostmux

A translator for invoking host-specific translators.

This translator creates pseudo directories by accessing the node with different arguments.

Here an example with the nfs translator.

settrans -cafg nfs: /hurd/hostmux /hurd/nfs SERVER

Now you can access the shares on the server.

ls nfs:/public
ls nfs:/path/to/nothing/

You can also access different servers with this method

settrans -cafg nfs: /hurd/hostmux /hurd/nfs /
ls nfs:/SERVER/path
ls nfs:/192.168.0.1

Pretty cool, isn't it?

usermux

A translator for invoking user-specific translators.

Somewhat more complicated than hostmux and no example for real use at the moment.

unionfs

This translator allows to join different directories into one directory.

settrans -cafg union /hurd/unionfs /bin /home /lib

storeio

storeio is like losetup on linux, but with more advantages. It also supports compression with gzip and bzib2 or normal files.

It creates a block device with the given file or arguments.

settrans -ca loop0 /hurd/storeio -T file FILE
settrans -ca loop1 /hurd/storeio -T gunzip FILE.gz

ATTENTION: storeio can not size the given file. A possibility to create a file with a given size is to use dd.

dd if=/dev/null of=FILE bs=42MB

This will create an empty file with the size of 42MB. You can now work with the new block device. You can use it as temporary filesystem (ramdisk) or as portable filesystem.

ramdisk

settrans -ca ramdisk0 /hurd/storeio -T copy zero:32M
mkfs.ext2 -F -b 4096 ramdisk0
settrans -ao ramdisk0 /hurd/ext2fs.static ramdisk0

First we create a buffer with copy and getting the size with zero. (Just like dd, but without invoking a file) Then we create the filesystem on our blockdevice and mounting it with ext2fs. The argument -o (orphan) replaces the previous translator with a new one without forcing it away.

portable vfs

The following example shows how to create virtual filesystems in a file.

dd if=/dev/zero of=your.img bs=SIZE
settrans -ca loop0 /hurd/storio -T file your.img
mkfs.ext2 -F -b 4096 loop0
settrans -ca mount /hurd/ext2fs.static loop0

Fist create a file with any size and create the block device with storeio then create the filesystem and mount it.

You can also lay the translators on top of each other.

settrans -a your.img /hurd/storeio -T file your.img
settrans -ao your.img /hurd/ext2fs your.img

The file your.img is now a directory and you can use it as such.

cp your things your.img/
ls your.img/things/

To unmount the filesystem.

settrans -g your.img

ATTENTION: I noticed that if you lay one translator onto another you can only remove the one on top. I don't know if this is a feature or bug, but after that procedure you only need to use ext2fs to mount the image, which is pretty handy after all. nsmux/filter allows you to access a translator deeper inside the stack.