In the previous installment (Part 4), we took a close look at what devfs is and how it solves nearly all device management problems. Now, it's time to get devfs up and running on your system. In this article, we'll get your system devfs-ready, and in the next, we will do the actual conversion to devfs. It's perfectly fine to follow the steps in this article even before the next and final devfs article is published, because after we finish all these steps, your system will continue to operate as normal -- it will simply be ready for the upcoming devfs transition. So there's no need to hold off until the next article before following these steps.
Note: Because we'll be making fairly major changes to portions of a Linux system, there's the real potential of messing up your system. So, if you're inexperienced with making "under the hood" modifications to your Linux system, you'll definitely want to do this on a non-critical Linux box, at least for your first time.
To get devfs up and running, you'll need to be using some version of Linux 2.4 (2.4.6 or 2.4.8 would be a good choice) and glibc 2.1.3 or greater. It's also recommended that you use Xfree86 4.0 or greater; if you aren't, I recommend that you upgrade to Xfree86 4.1 first.
In our next article, we'll be making changes to boot-critical portions of your
Linux system. Since it's definitely possible that you could mess up your boot
process by accident if something goes wrong, I'm going to start off this
article by first showing you how to get your system up and running with an
emergency bash shell. You can use this emergency boot process if you do happen to find that your system doesn't
boot due to some problem with your init scripts or /sbin/init itself.
The easiest way to do an emergency boot is to pass an init=/bin/bash
option to the kernel at boot-time using either GRUB or LILO. With GRUB, you
should be able to pass this option interactively as needed, by hitting e
to edit your current menu entry in real-time. With LILO, make sure that you've
figured out how to pass kernel boot options before continuing, and create a new
"emergency" LILO boot option if necessary.
So, the basic "rescue" process is as follows. First, pass init=/bin/bash
to the kernel as a kernel boot option. When the kernel boots, it will then start
/bin/bash instead of the normal /sbin/init as the first process.
You'll be greeted with a root bash prompt without even having been prompted
to log in:
# |
However, even though you are greeted with a root bash prompt, only
your root filesystem is mounted, and even it is only mounted read-only. Here's
how to get your system up and running from this point forward. If your
filesystems weren't unmounted cleanly, you should fsck them
first. First, do an fsck -a on your root filesystem, and then an fsck
-R -A -a should take care of all of your other filesystems:
# fsck -a /dev/hda1 # fsck -R -A -a |
Now that your filesystems are consistent (or if your filesystems were unmounted cleanly when you rebooted and you skipped the previous step), you can simply remount the root filesystem as read-write and mount /proc as follows:
# mount / -o remount,rw # mount /proc |
Then, mount any important filesystem trees that you may have on other partitions. For example, if you have /usr on another partition, you'll also need to type:
# mount /usr |
It may also be a good idea to activate your swap if you plan to do anything more than fire up an editor. If you use emacs, you may need it :)
# swapon -a |
Now, you should be able to run your favorite editor and edit whatever files need to be edited in order to fix the boot problem that you are having. Once complete, simply remount the partitions as read-only in the order that you mounted them. For example, if you have a separate /usr partition, you'd get all your filesystems in a consistent state (ready for reboot) by typing:
# mount /usr -o remount,ro # mount / -o remount,ro |
Now, you can safely reboot. The boot problem is hopefully now resolved and your normal LILO or GRUB options will get the system up and running:
# /sbin/reboot -nfi |
Now that you know what to do in case of an emergency, we're ready to
get your system ready for devfs. In the next article, we're going to be making some relatively
complex changes to your Linux system. Why is this necessary? Because we're
not just enabling devfs functionality in the kernel, which is actually quite
easy. We're also going to set up devfsd (the device management daemon)
in a special mode so that it backs up and restores any changes to device
permissions and ownership. We need to do a lot of little tricks to get this
new system working perfectly. But once it is, I think you'll be very
pleased with the result.
The first step to enabling devfs on your system is easy: you'll need to enable
devfs support in the kernel. For this, you'll need a 2.4 series kernel. Using
make menuconfig or make xconfig, head over to the Code
maturity level options section and make sure that the Prompt for
development and/or incomplete code/drivers option is enabled. Then,
head over to the File systems kernel configuration section and look for
the /dev file system support (EXPERIMENTAL) option. Enable it. You'll
see a couple of additional options appear below the option you just enabled.
The first one controls whether devfs will be mounted to /dev
automatically when the kernel boots. Don't enable this option; we will
manually mount /dev using a special script. The second option,
Debug devfs, should also be disabled.
While you have the File systems kernel configuration section on screen,
disable support for the /dev/pts file system for Unix98 PTYs if you
happen to have it enabled. Devfs provides similar functionality, so you won't
need the devpts filesystem anymore. Go ahead and save your kernel
configuration; we'll compile and install a new kernel in a bit. Finally,
before moving on to the next step, check to see if you have a /dev/pts
entry in your /etc/fstab; if you do, comment it out so that it
doesn't get mounted at boot-time anymore.
Miscellaneous configuration quirks
Next, load the /etc/securetty file into an editor. This file is
used by login and allows you to specify the ttys that the root user
is allowed to use to login. Normally, it contains the devices tty1
through tty12, one per line. In order to get this file ready for devfs,
you should add the appropriate devfs-style names for these ttys, keeping the
older tty? names in case you decide to boot with devfs disabled. Add
the following lines to the bottom of /etc/securetty.
vc/1 vc/2 vc/3 vc/4 vc/5 vc/6 vc/7 vc/8 vc/9 vc/10 vc/11 vc/12 |
The next step is to get devfsd, the devfs helper daemon, installed on the
system. Devfsd will take care of creating "old-style" compatibility device
nodes, performing automated actions when a driver is registered/unregistered,
take care of backing up changes to device permissions and ownership to a
directory on the root filesystem, and more. Right now, we'll just get devfsd
installed; next article, we'll get it up and running, along with devfs. To install
devfsd, first download the most recent version of the devfsd tarball (see Resources later in this article), currently version 1.3.16.
Then perform the following steps:
# tar xzvf devfsd-1.3.16.tar.gz # cd devfsd # make |
Now, devfsd should be compiled and ready to install. If your man pages are
stored in /usr/man, type make install; if you are using an
FHS-compliant system and your man pages are in /usr/share/man,
type make mandir=/usr/share/man install. Devfsd will now be installed
but not runnning, which is exactly how we want it at this point.
Now, go ahead and compile and install your recently configured kernel. This kernel should be a drop-in replacement for your current kernel; it should boot normally, and although it has devfs support built in, you should notice no difference from the one you're running now. Once the new kernel is installed, reboot your system to make sure that everything is working fine up to this point.
Devfs configuration approaches
Your system is now ready for the devfs conversion, which I will cover in detail in the next article. Now would be a good time to get familiar with the approach we are using. As you will see, devfs-enabling a distribution can be very tricky, especially if you want to use all the nice devfs features like persistent permissions and ownership.
The problems with kernel automounting
There are actually a number of ways to devfs-enable a system. One is to have
the kernel automatically mount devfs to /dev at boot; we won't be
using this option, but it is available. At first glance, this approach
would seem to make a lot of sense because it would ensure that all devfs-style
devices are available to all processes, even the first process,
/sbin/init. However, there's a problem with this approach. While devfs
provides all the "new-style" devices, the old-style device nodes are created by
the devfsd daemon. devfsd isn't started by the kernel, so even
if we have the kernel mount devfs at boot, we are still only left with a
partial set of device nodes by the time /sbin/init starts up. This means
that tweaks to your system initializations scripts will be required in order to
get devfsd up and running at just the right time. Not only is this tricky
(since it requires that you have an expert understanding of your own system's
startup scripts), but this approach has other problems as well.
The main problem with the kernel mounting approach is that devfsd works
best when it has access to the contents of your original old-style on-disk
/dev directory. Typically, we allow access to the original
old-style devices by bind-mounting /dev to another location
(typically /dev-state) before devfs itself is mounted to /dev.
This ensures that the contents of your old /dev are still
accessible at /dev-state even after devfs is mounted, which allows
devfsd to use this directory for persistent device storage. It's
important to understand that without the bind mount, the old contents of
/dev would be inaccessible, since mounting devfs at
/dev would effectively cover them up. And this is the problem
with having the kernel mount devfs. If the kernel mounts the devfs
filesystem at /dev before any process is able to start, then we
have no opportunity to perform the bind mount, and the original contents of
/dev are completely hidden. Icky, isn't it? (To learn more about bind mounts, see Part 3 of this series.)
Ideally, it would be great if we could have a full
set of device nodes (new-style and compatibility devices) as soon as
/sbin/init is started and also have the opportunity to bind mount
/dev to another location before devfs is even mounted; but how is
this possible?
Well, one way would be to add a kernel patch to perform the bind mount from
/dev to /dev-state. However, while this is
definitely possible and actually quite easy to perform, it would be
inconvenient to manually patch every new Linux kernel you install. Therefore,
probably the best way to solve the devfs "chicken and egg" problem is to use an
init wrapper. For our particular application, the init wrapper will be
a bash script that takes the place of /sbin/init -- our real init
has been renamed as /sbin/init.system. In short, this is what the init
wrapper will do:
#!/bin/bash mkdir -f /dev-state mount --bind /dev /dev-state mount -t devfs none /dev devfsd /dev exec /sbin/init.system |
As you can see, the first thing the wrapper does is ensure that
/dev-state exists. Then, the /dev tree is bind
mounted to /dev-state, so that the contents of /dev
are available via the /dev-state directory. Then, our devfs
filesystem is mounted on top of /dev and we start devfsd so
that our compatibility devices are automatically registered with devfs.
Finally, we exec the original/sbin/init, which has now
been renamed to /sbin/init.system. The exec command causes
init.system to replace the running bash process. This means that our
bash script terminates and init.system inherits process ID 1, the
coveted process ID of the init process. When /sbin/init.system
starts up, the system boots as normal except that devfs is now fully
operational; by using an init wrapper, we avoided having to patch the kernel,
tweak our startup scripts, or deal with having only a semi-operational devfs
system.
In my next article, I'll guide you through the process of getting the full
version of the init wrapper up and running and show you how to take advantage
of devfsd's many powerful features. Stay tuned!
- Read Daniel's other articles in this series, where he describes:
- the benefits of journalling and ReiserFS (Part 1)
- setting up a ReiserFS system (Part 2)
- using the tmpfs virtual memory filesystem and bind mounts (Part 3)
- the benefits of devfs, the device management filesystem (Part 4)
- completing the conversion to devfs using an init wrapper (Part 6)
- Download the most recent version of the devfsd tarball, currently version 1.3.16.
- O'Reilly's Linux
Device Drivers, 2nd Edition is an excellent book and a great
resource for learning more about device registration, and
Linux device driver programming in general.
- Be sure to read the Linux Devfs
FAQ by Richard Gooch, the creator of Linux devfs. It's complete, verbose, and up-to-date. What more could you ask
for? You may also want to visit Richard Gooch's main page;
it contains devfs as well as other neat things.
- Subscribe to the devfs mailing list by sending an e-mail to
majordomo@oss.sgi.com with the word
subscribe in the body of the message. View the devfs list archives.
- Find out more about GRUB at the GNU GRUB project page.
Even better, check out Daniel's developerWorks tutorial on installing and using GRUB.
- Are you a LILO user? It's OK; we still love you. Grab the most recent version of LILO.
- Linux Weekly News is a great resource
for keeping up with the latest kernel developments.
- Browse more Linux resources on developerWorks.
- Browse more Open source resources on developerWorks.
Residing in Albuquerque, New Mexico, Daniel Robbins is the President/CEO of Gentoo Technologies, Inc., the creator of Gentoo Linux, an advanced Linux for the PC, and the Portage system, a next-generation ports system for Linux. He has also served as a contributing author for the Macmillan books Caldera OpenLinux Unleashed, SuSE Linux Unleashed, and Samba Unleashed. Daniel has been involved with computers in some fashion since the second grade, when he was first exposed to the Logo programming language as well as a potentially dangerous dose of Pac Man. This probably explains why he has since served as a Lead Graphic Artist at SONY Electronic Publishing/Psygnosis. Daniel enjoys spending time with his wife, Mary, and his daughter, Hadassah. You can contact Daniel at drobbins@gentoo.org.