When I was trying to figure out the best way to set up my removable usb drive, I ended up stumbling upon autofs as an excellent solution. After realizing the potential of it, and how configurable it is, I started setting it up to manage other mountpoints on my system. Here, I will discuss everything I set up, and how, including dynamically mounted smb, ftp, and ssh mountpoints.
What is it?
First of all, what is autofs? Basically, it is a kernel option that lets you automatically mount filesystems to your computer when you access them, and then automatically umount them when they are no longer used. For some basics, you can read the Quick autofs Tutorial or for some more specific setup information you can also check the Autofs HOWTO.
Okay, I know what it is. So what?
To illustrate some of the simple niceties of autofs, here is an example of reading the contents of a CDROM, and ejecting it, pre and post-autofs.
Before autofs:
*insert CD into CDROM mount /cdrom ls /cdrom umount /cdrom *remove CD from CDROM
With autofs:
*insert CD into CDROM ls /cdrom *remove CD from CDROM
Upon accessing the /cdrom directory, autofs automatically mounted it for me, and when I pressed the eject button (or waited for the timeout) it automatically umounted it. This is a fairly straightforward example, but it presents a lot of possibilities. For instance, you can set up SMB and NFS mounts that only mount as you access them, then umount later. Or, as in my usb drive example, mount the usb drive only when you access it, then quickly umount it when you aren't using it, so it will be safe to remove.
Okay okay, fine. How did you set it up?
First, install autofs. The autofs howto I linked to earlier goes over this, for me I just needed to make sure autofs support was in my kernel, and then I ran apt-get install autofs
in Debian, which installs all the necessary files and sets up a default /etc/auto.master file and a few default configurations, auto.net and auto.misc. Those scripts are a good starting point, and that and man 5 autofs
will clue you into some of the basic configuration you can do. First, let's set up local removable drives.
Removable drives
Okay, so first I added a line to my /etc/auto.master file. This file keeps track of where the autofs filesystems will be eventually mounted, along with pointing to the specific configuration file (or script, I'll get to that later) for it to read from, and then a column for any other options you would like to add. Here's the line I added for my removable drives:
/var/autofs/removable /etc/auto.removable --timeout=2
This line tells autofs to create a new directory under /var/autofs/removable, to then read from /etc/auto.removable to find out about any mountpoints that might exist under there, and to timeout (and therefore umount the filesystem) after 2 seconds of idling. The 2-second idling isn't as important for CDROMs as it is for usb drives, so if you want your CDROM to have a longer timeout, just create a new configuration file for it, and a new line in auto.master. You may also add extra options to be passed to the mount command in this column, options which will be applied to any mountpoint listed under this directory.
With /etc/auto.master edited, I then created a new autofs configuration file, called auto.removable, and put it in /etc. The file looks like the following:
cdrom -fstype=iso9660,ro,sync,nodev,nosuid :/dev/cdrom floppy -fstype=auto,sync,nodev,nosuid :/dev/fd0 usbdrive -fstype=vfat,uid=1002,gid=1002,umask=002 :/dev/sda1
The first column is the name of the directory mountpoint I want to use, so these lines would automount their devices when /var/autofs/removable/cdrom, /var/autofs/removable/floppy, and /var/autofs/removable/usbdrive were accessed, respectively. The second column sets up any mounting options you want to use for these individual filesystems, separated by commas. The third column is to list what device you wish to mount. IMPORTANT: if you are not listing an NFS mount, you need to prepend a colon to the beginning of the device, so /dev/cdrom becomes :/dev/cdrom.
Once you create this file, simply restart autofs with /etc/init.d/autofs restart
. Note, you only have to restart autofs when you edit /etc/auto.master. You can edit any of the other configuration files on the fly how you like, and won't have to restart autofs for the changes to take effect.
With these settings in place, I put the Fedora Core 1 cd in my cdrom, and typed ls:
greenfly@clover:~$ ls /var/autofs/removable/ greenfly@clover:~$ ls /var/autofs/removable/cdrom Fedora RPM-GPG-KEY TRANS.TBL GPL RPM-GPG-KEY-beta autorun README RPM-GPG-KEY-fedora dosutils README-Accessibility RPM-GPG-KEY-fedora-rawhide eula.txt RELEASE-NOTES RPM-GPG-KEY-fedora-test images RELEASE-NOTES.html RPM-GPG-KEY-rawhide isolinux greenfly@clover:~$ ls /var/autofs/removable/ cdrom greenfly@clover:~$ ls /var/autofs/removable/
Notice that the cdrom directory didn't exist in /var/autofs/removable until I actually tried to access it. Then it only existed until it timed out, which, with my configuration, is 2 seconds, and then it umounted. You can also check /var/log/syslog to watch autofs work:
Jan 27 10:05:41 clover automount[31302]: attempting to mount entry /var/autofs/removable/cdrom
Jan 27 10:05:41 clover automount[5729]: lookup(file): looking up cdrom
Jan 27 10:05:41 clover automount[5729]: lookup(file): cdrom -> -fstype=iso9660,ro,sync,nodev,nosuid :/dev/cdrom
Jan 27 10:05:41 clover automount[5729]: parse(sun): expanded entry: -fstype=iso9660,ro,sync,nodev,nosuid :/dev/cdrom
Jan 27 10:05:41 clover automount[5729]: parse(sun): dequote("fstype=iso9660,ro,sync,nodev,nosuid") -> fstype=iso9660,ro,sync,nodev,nosuid
Jan 27 10:05:41 clover automount[5729]: parse(sun): gathered options: fstype=iso9660,ro,sync,nodev,nosuid
Jan 27 10:05:41 clover automount[5729]: parse(sun): dequote("/dev/cdrom") -> /dev/cdrom
Jan 27 10:05:41 clover automount[5729]: parse(sun): core of entry: options=fstype=iso9660,ro,sync,nodev,nosuid, loc=/dev/cdrom
Jan 27 10:05:41 clover automount[5729]: parse(sun): mounting root /var/autofs/removable, mountpoint cdrom, what /dev/cdrom, fstype iso9660, options ro,sync,nodev,nosuid
Jan 27 10:05:41 clover automount[5729]: do_mount /dev/cdrom /var/autofs/removable/cdrom type iso9660 options ro,sync,nodev,nosuid using module generic
Jan 27 10:05:41 clover automount[5729]: mount(generic): calling mkdir_path /var/autofs/removable/cdrom
Jan 27 10:05:41 clover automount[5729]: mount(generic): calling mount -t iso9660 -s -o ro,sync,nodev,nosuid /dev/cdrom /var/autofs/removable/cdrom
Jan 27 10:05:43 clover kernel: ISO 9660 Extensions: Microsoft Joliet Level 3
Jan 27 10:05:43 clover kernel: ISO 9660 Extensions: RRIP_1991A
Jan 27 10:05:43 clover automount[5729]: mount(generic): mounted /dev/cdrom type iso9660 on /var/autofs/removable/cdrom
Jan 27 10:05:46 clover automount[5747]: running expiration on path /var/autofs/removable/cdrom
Jan 27 10:05:46 clover automount[5747]: expired /var/autofs/removable/cdrom
I have highlighted a few lines of interest. You can see autofs detect the access of /var/autofs/removable/cdrom, then watch it mount the filesystem, and then, seconds later, watch it time out and expire the mount point.
Beyond local filesystems
Autofs can manage basically any filesystem that you could normally mount by hand. This means you can use it to manage your NFS and ssh mounts. To do this, I added another line to my /etc/auto.master for smb connections:
/var/autofs/smb /etc/auto.smb --timeout=60
And then created the /etc/auto.smb file:
backup -fstype=smbfs,username=joey,password=god,uid=1000,gid=1000 ://gibson/backup html -fstype=smbfs,username=joey,password=god,uid=1000,gid=1000 ://gibson/html mp3 -fstype=smbfs,guest,uid=1000,gid=1000 ://gibson/mp3
This file sets up three mountpoints, /var/autofs/smb/backup, /var/autofs/smb/html, and /var/autofs/smb/mp3, respectively. Notice that I specify the mountpoints with a colon first, and then the normal //servername/share syntax used for smb. With this set up, I then restart autofs, and:
greenfly@clover:~$ ls /var/autofs/smb/ greenfly@clover:~$ ls /var/autofs/smb/backup 010901 rawtext 0211ay.jpg 1.40.2.zip 1.42.3.zip 2003 Web Analysis.xls ... url_200210.txt url_200210.xls url_200211.txt various_artists greenfly@clover:~$ ls /var/autofs/smb/ backup greenfly@clover:~$ ls /var/autofs/smb/
Again the mountpoint isn't created until I try to access it, then it mounts the smb share, and finally times out a minute later:
Jan 27 10:34:36 clover automount[31336]: attempting to mount entry /var/autofs/smb/backup
Jan 27 10:34:36 clover automount[8930]: lookup(file): looking up backup
Jan 27 10:34:36 clover automount[8930]: lookup(file): backup -> -fstype=smbfs,username=joey,password=god,uid=1000,gid=1000^I://gibson/backup
Jan 27 10:34:36 clover automount[8930]: parse(sun): expanded entry: -fstype=smbfs,username=joey,password=god,uid=1000,gid=1000^I://gibson/backup
Jan 27 10:34:36 clover automount[8930]: parse(sun): dequote("fstype=smbfs,username=joey,password=god,uid=1000,gid=1000") -> fstype=smbfs,username=joey,password=god,uid=1000,gid=1000
Jan 27 10:34:36 clover automount[8930]: parse(sun): gathered options: fstype=smbfs,username=joey,password=god,uid=1000,gid=1000
Jan 27 10:34:36 clover automount[8930]: parse(sun): dequote("//gibson/backup") -> //gibson/backup
Jan 27 10:34:36 clover automount[8930]: parse(sun): core of entry: options=fstype=smbfs,username=joey,password=god,uid=1000,gid=1000, loc=//gibson/backup
Jan 27 10:34:36 clover automount[8930]: parse(sun): mounting root /var/autofs/smb, mountpoint backup, what //gibson/backup, fstype smbfs, options username=joey,password=god,uid=1000,gid=1000
Jan 27 10:34:36 clover automount[8930]: do_mount //gibson/backup /var/autofs/smb/backup type smbfs options username=joey,password=god,uid=1000,gid=1000 using module generic
Jan 27 10:34:36 clover automount[8930]: mount(generic): calling mkdir_path /var/autofs/smb/backup
Jan 27 10:34:36 clover automount[8930]: mount(generic): calling mount -t smbfs -s -o username=joey,password=god,uid=1000,gid=1000 //gibson/backup /var/autofs/smb/backup
Jan 27 10:34:37 clover automount[8930]: mount(generic): mounted //gibson/backup type smbfs on /var/autofs/smb/backup
Jan 27 10:35:44 clover automount[9058]: running expiration on path /var/autofs/smb/backup
Jan 27 10:35:44 clover automount[9058]: expired /var/autofs/smb/backup
It works pretty much the same way that mounting the cdrom worked, only with different mount options.
If you just want basic autofs mounting to work with your removable devices and network shares, this is really all you need to do. Now, if you want to push the envelope...
Getting fancy
Writing your own autofs scripts
Upon reading up on the autofs options, I noticed that you can specify multiple nested mountpoints under a server. The example in the autofs[5] manpage is:
server -rw,hard,intr / -ro myserver.me.org:/ \ /usr myserver.me.org:/usr \ /home myserver.me.org:/home
The above would not only create server directory, but also nest usr and home directories (each potentially with their own options) under that mount point, simply by accessing the server directory. I used that fact, and the knowledge that you can specify scripts instead of configuration files in /etc/auto.master, to write my own dynamic script to allow me to browse smb shares dynamically. All a script you write has to do, is generate the second and third columns of a configuration file. The script will be passed the first column as an argument. I realized I could write a perl script that would receive the name of an smb server, and then scan that server for guest mountpoints, and output the proper autofs configuration. After some tweaking, I came up with this autofs script. (Note, this script uses the Filesys::SmbClient perl module, check the docs in the script itself for instructions on how to install that if you don't have it already.)
You can test out the script by running it by itself, passing the name of an smb server on your network. For instance:
greenfly@clover:~$ /etc/auto.smbbrowse gibson -fstype=smbfs,guest /mp3 //gibson/mp3 /print$ //gibson/print$
The script discovered two guest shares on that machine, mp3 and print$, and set up a multi-map entry for them. This would be exactly the same as having a text config file with the following line:
gibson -fstype=smbfs,guest /mp3 //gibson/mp3 /print$ //gibson/print$
With this script written, I simply edit my /etc/auto.master file and add an entry for smb browsing:
/var/autofs/smbbrowse /etc/auto.smbbrowse --timeout=60,-nonstrict
I put the script in /etc/ and made sure it was executable. Now, whenever I browse to /var/autofs/smbbrowse, instead of reading a config file, it will run /etc/auto.smbbrowse and take its output for the configuration. For this script to work, however, it is very important to include the -nonstrict option. This tells the script to not fail if it can't seem to mount a share (ie, it is password-protected). Otherwise, if you run it and even a single share is password protected, it will error out and not try to mount any of them. With this line added, I restart autofs, and then try it out:
greenfly@clover:~$ ls /var/autofs/smbbrowse greenfly@clover:~$ ls /var/autofs/smbbrowse/gibson mp3 greenfly@clover:~$ ls /var/autofs/smbbrowse/gibson/mp3 311 nofx Reef Madness! offspring Surf Rider operation_ivy anti-flag pennywise ... nin various_artists greenfly@clover:~$ ls /var/autofs/smbbrowse/
Note that I didn't actually have a configuration file in place for the gibson server, the script scanned the network and asked gibson what shares it had available on the fly, then the script passed any guest-mountable ones to autofs, which then decided to mount the mp3 share. In case you are curious, here's the syslog output:
Jan 27 11:08:03 clover automount[31370]: attempting to mount entry /var/autofs/smbbrowse/gibson
Jan 27 11:08:03 clover automount[12595]: lookup(program): looking up gibson
Jan 27 11:08:06 clover automount[12595]: lookup(program): gibson -> -fstype=smbfs,guest^I/mp3 //gibson/mp3 /print$ //gibson/print$
Jan 27 11:08:06 clover automount[12595]: parse(sun): expanded entry: -fstype=smbfs,guest^I/mp3 //gibson/mp3 /print //gibson/print
Jan 27 11:08:06 clover automount[12595]: parse(sun): dequote("fstype=smbfs,guest") -> fstype=smbfs,guest
Jan 27 11:08:06 clover automount[12595]: parse(sun): gathered options: nonstrict,fstype=smbfs,guest
Jan 27 11:08:06 clover automount[12595]: parse(sun): dequote("/mp3") -> /mp3
Jan 27 11:08:06 clover automount[12595]: parse(sun): dequote("//gibson/mp3") -> //gibson/mp3
Jan 27 11:08:06 clover automount[12595]: parse(sun): multimount: //gibson/mp3 on /mp3 with options nonstrict,fstype=smbfs,guest
Jan 27 11:08:06 clover automount[12595]: parse(sun): mounting root /var/autofs/smbbrowse, mountpoint gibson/mp3, what //gibson/mp3, fstype smbfs, options guest
Jan 27 11:08:06 clover automount[12595]: do_mount //gibson/mp3 /var/autofs/smbbrowse/gibson/mp3 type smbfs options guest using module generic
Jan 27 11:08:06 clover automount[12595]: mount(generic): calling mkdir_path /var/autofs/smbbrowse/gibson/mp3
Jan 27 11:08:06 clover automount[12595]: mount(generic): calling mount -t smbfs -s -o guest //gibson/mp3 /var/autofs/smbbrowse/gibson/mp3
Jan 27 11:08:06 clover automount[12595]: mount(generic): mounted //gibson/mp3 type smbfs on /var/autofs/smbbrowse/gibson/mp3
Jan 27 11:08:06 clover automount[12595]: parse(sun): dequote("/print") -> /print
Jan 27 11:08:06 clover automount[12595]: parse(sun): dequote("//gibson/print") -> //gibson/print
Jan 27 11:08:06 clover automount[12595]: parse(sun): multimount: //gibson/print on /print with options nonstrict,fstype=smbfs,guest
Jan 27 11:08:06 clover automount[12595]: parse(sun): mounting root /var/autofs/smbbrowse, mountpoint gibson/print, what //gibson/print, fstype smbfs, options guest
Jan 27 11:08:06 clover automount[12595]: do_mount //gibson/print /var/autofs/smbbrowse/gibson/print type smbfs options guest using module generic
Jan 27 11:08:06 clover automount[12595]: mount(generic): calling mkdir_path /var/autofs/smbbrowse/gibson/print
Jan 27 11:08:06 clover automount[12595]: mount(generic): calling mount -t smbfs -s -o guest //gibson/print /var/autofs/smbbrowse/gibson/print
Jan 27 11:08:06 clover automount[12595]: >> 12604: tree connect failed: ERRDOS - ERRnosuchshare (You specified an invalid share name)
Jan 27 11:08:06 clover automount[12595]: >> SMB connection failed
Jan 27 11:08:06 clover automount[12595]: mount(generic): failed to mount //gibson/print (type smbfs) on /var/autofs/smbbrowse/gibson/print
Jan 27 11:08:06 clover automount[12595]: ignoring failure of non-strict mount
Jan 27 11:09:15 clover automount[12727]: running expiration on path /var/autofs/smbbrowse/gibson
Jan 27 11:09:15 clover automount[12727]: expired /var/autofs/smbbrowse/gibson
You can notice that the logs are a bit different this time. It notices it gets a multi-map as input, and tries to mount each of the mountpoints it is given, only the mp3 mountpoint actually worked, but since we specified -nonstrict, it didn't completely error out. Now, if I want to access a guest share anywhere on my network, I simply need to browse to /var/autofs/smbbrowse/servername and see what is available.
Note that this script is only configured to scan and try to configure mountpoints as guest.
Dynamic ftp and ssh mounts with autofs and lufs
One of the things that actually inspired me to write the smb browsing script, is the similar scripting that the lufs project has included for autofs. LUFS lets you mount remote ftp and ssh servers as though they were NFS or SMB fileservers on your filesystem. With their autofs tools you can simply browse around your filesystem with stragetically-named folders and browse ftp.kernel.org, or even your own ssh or ftp servers.
The setup
Okay, so the first thing to do, is to install and setup lufs on your system. This will vary per distribution, but for me it was a matter of running
apt-get install lufs-source lufs-utils cd /usr/src/ tar xfvj lufs.tar.bz2 cd /usr/src/linux make-kpkg modules_image dpkg -i ../lufs-module*deb
This builds the lufs kernel modules I needed and installed them with the rest of the modules for my kernel. If you don't use make-kpkg to manage your modules and kernel in debian... what's wrong with you? Just kidding, if you aren't using make-kpkg, then you will need to download the lufs source from their site and build it against your kernel according to their INSTALL docs.
At this point, you will be able to use lufsmount and lufsumount to mount and umount remote ftp and ssh filesystems. Read the manpages for those repesctive commands for more information on how to run them manually.
Configuring lufs with autofs
Mounting things manually? That's not why we are using autofs! So, how do we get autofs and lufs to work together? It's actually rather easy, and just requires two extra entries in your /etc/auto.master file:
/var/autofs/ssh /usr/bin/auto.sshfs uid=1000,gid=1000,--timeout=30 /var/autofs/ftp /usr/bin/auto.ftpfs uid=1000,gid=1000,--timeout=30
Notice I added some extra options to pass along to mount, so that any remote filesystem I mount would have the UID of my current user (if you had multiple users you wanted to have access you could always create a group for them all and then just use the gid= option.) At this point I simply restart autofs and browse to /var/autofs/ftp:
greenfly@clover:~$ ls /var/autofs/ftp greenfly@clover:~$ ls /var/autofs/ftp/ftp.kernel.org/pub/linux/kernel/v2.6/ ChangeLog-2.6.0 linux-2.6.1.tar.bz2 patch-2.6.0.sign ChangeLog-2.6.1 linux-2.6.1.tar.bz2.sign patch-2.6.1.bz2 LATEST-IS-2.6.1 linux-2.6.1.tar.gz patch-2.6.1.bz2.sign README-2.6 linux-2.6.1.tar.gz.sign patch-2.6.1.gz linux-2.6.0.tar.bz2 linux-2.6.1.tar.sign patch-2.6.1.gz.sign linux-2.6.0.tar.bz2.sign patch-2.6.0.bz2 patch-2.6.1.sign linux-2.6.0.tar.gz patch-2.6.0.bz2.sign pre-releases linux-2.6.0.tar.gz.sign patch-2.6.0.gz snapshots linux-2.6.0.tar.sign patch-2.6.0.gz.sign testing greenfly@clover:~$ ls /var/autofs/ftp ftp.kernel.org greenfly@clover:~$ ls /var/autofs/ftp
Once again, notice that the directory doesn't exist until you actually access it, then autofs creates it. You can treat this like any other mounted network filesystem and copy files to your local system. With the ftp and ssh modules, you can also specify user:pass@foo.com under the /var/autofs/ftp/ directory if you don't want to log in as anonymous.
SSH mounting works basically the same was as ftp, except that everything works best if already have set up passwordless ssh logins with rsa keys for your root user. I just copied over my public root rsa key to any remote ssh server I wanted to connect to, confirmed that I could ssh to the server without requiring a password, and then I could simply browse to /var/autofs/ssh/user@server/
to connect.
One caveat, the LUFS project is still in the experimental stage, so don't be surprised if everything doesn't work exactly as stably as other network filesystems. I have noticed some caching issues when running vim on a file for minutes at a time, with file writes not always going through perfectly. For filesystem copying though, it should work fairly well.
Conclusion
So, at this point I have been using autofs for a bit, and have done a few things to make it easier to manage. For one, the /var/autofs
directory structure was getting annoying, so I created symlinks under /mnt to various autofs directories. For instance, you can run something like ln -s /var/autofs/ftp/ftp.kernel.org /mnt/ftp.kernel.org
and ftp.kernel.org
will only be mounted when you access /mnt/ftp.kernel.org/
, this works even though the directory doesn't yet exist under /var/autofs/ftp
.
You can use this to create many different symlinks for different ssh or smb accounts. I even ended up deleting my /cdrom directory, and replacing it with a symlink to /var/autofs/removable/cdrom
, and created quick access to my arslinux account by ln -s /var/autofs/ssh/greenfly@arslinux.com/home/greenfly /mnt/arslinux
. I also created quick access to the kernel and xfs ftp dirs by ln -s /var/autofs/ftp/ftp.kernel.org/pub/linux/kernel /mnt/kernel
and ln -s /var/autofs/ftp/oss.sgi.com/projects/xfs /mnt/xfs
respectively.