The other day, I was admiring the largish pond that was placidly engulfing our parking lot, when I chanced to see someone sitting on the curb at the other end of the lot, casting their fishing line into the murky depths. At first I assumed it was someone catching trout for the newly opened fish restaurant next door. When her eyes met mine, however, I realized that it was none other than the infamous hacker, Morgan le Be.
"Hey, it's a good thing you're here," she called out to me. "Fishing always brings out my philosophical side. So, tell me—how do I know when a CD is inserted into or removed from a drive? For that matter, can I tell if a drive itself is being inserted or removed from my system?"
The answer to this question is somewhat involved, so I promised her that I'd write a newsletter article about it. And here it is.
The solution to this problem depends on a somewhat clever use of devfs to get information about the drives and removable media in your system. Unlike many previous articles on the subject, I'll assume that you're approaching devfs from the application-writing level, not as a driver writer. So here's a gentle introduction to devfs for the uninitiated.
devfs is the (not-so-) friendly name we give to the "device file system". The device file system is a virtual collection of directories and files, mounted at "/dev", that the system creates to give low-level access to various devices in your system. This includes disk drives, input devices, and peripheral cards. This low-level system allows you to communicate directly with the drivers that work with the hardware on your system -- if you know what you're doing. (Of course, as with any low-level and high-power construct, you have an immense opportunity to shoot yourself and attendant hardware in the foot if you muck around with these devices unadvisedly, so be careful!)
How do you work with these devices? If you're familiar with UNIX, you'll
recognize the paradigm instantly. Although the files in devfs are not
actual files stored on disk, you work with them as if they were actual
files, meaning that you can read and write to them using the read()
and
write()
system calls, among others. Similarly, the directories in devfs
aren't actual directories on a disk, but you can traverse them using
standard directory commands. Note that devices are identified primarily
by the directory structure (which is generally extensive and
descriptive); the files reside at the bottom of the directory structure,
usually with terse names, to provide the actual access to the device. For
a more complete introduction to devfs, read the Good Book:
DeviceDrivers_Introduction.html#DeviceDrivers_Introduction_devfs
So, to talk to a driver, you simply find the file that corresponds to the
driver you want to talk to, and invoke system functions on the file to
communicate with the driver—for example, read()
and write()
will
usually get raw data into and out of the driver. There is an additional
system call, called ioctl
, that's extremely handy when talking to
drivers—in fact, we'll be using it in just a moment. ioctl
(short for
"I/O Control", we pronounce it "eye-AWK-tul") is a generic interface that
allows you to send an opcode and a data structure to the driver to get
information into or out of the driver. For the curious,
Drivers.h
contains a big list of common ioctl
opcodes that drivers support, and
what they do.
Now that the introductory remarks are out of the way, let's look at the code. Drive Daemon is a background process that tracks all the disk drives in the system, and monitors their status. It sends out notifications when certain actions happen that affect disk drives. You can find the code at:
<ftp://ftp.be.com/pub/samples/storage_kit/DriveDaemon.zip>
There are two basic kinds of actions that DriveDaemon detects and handles:
The drive itself is added or removed (e.g., plugging in or unplugging PCMCIA drives).
The media inside the drive changes (e.g., when you insert or eject a CD).
The distinction between these two kinds of events is subtle, but it's important, because these two different kinds of actions end up being detected by DriveDaemon in totally different ways.
The first task that befalls Drive Daemon is to locate all the disk drives
in the system. Do this by examining all the directories under
/dev/disk
and finding all the files named "raw." By naming convention, files in the
/dev/disk
hierarchy called
"raw" are used to obtain raw access to a disk,
as opposed to access to specific partitions on a disk. Once we find one
of these files, we create a Drive object (which is in charge of
monitoring the status of this disk drive) and add it to a list of drives
that we're keeping track of.
To be a bit more selective about the kinds of disks we're interested in,
Drive Daemon can query the driver about what kind of disk a particular
device entry represents. This is done by using the ioctl
system call
mentioned above to issue the command B_GET_GEOMETRY
. For example, here's
how we can tell if a particular drive is a CD-ROM drive:
intfd
= ...; // this is the POSIX descriptor for the // raw disk, obtained via open() device_geometry g; if (ioctl(fd
,B_GET_GEOMETRY
, &g
, sizeof(device_geometry
)) > 0) { if (g
.device_type
==B_CD
) { // it's a CD-ROM drive } else { // it's some other kind of drive } }
See, ioctl
s are a piece of cake! But we're not done with them yet...
Next, let's figure out when the media inside a disk drive changes (this
affects floppy drives, CD-ROM drives, and other drives with removable
media). The way to do this is to have the Drive object periodically poll
the driver for its status using an ioctl
command that was custom-built
for this purpose, B_GET_MEDIA_STATUS
. For example, here's how you can
tell if a new CD has been inserted into a CD-ROM drive:
intfd
= ...; // this is the POSIX file descriptor for // the raw disk, obtained via open() status_tmediaStatus
; if (ioctl(fd
,B_GET_MEDIA_STATUS
, &mediaStatus
, sizeof(status_t)) >= 0) { switch (mediaStatus
) { caseB_DEV_MEDIA_CHANGED
: // new CD to scan break; default: // something else happened break; } }
One caveat here: the driver can only keep track of whether the media changed if the driver is kept open while the CD is removed and reinserted -- it forgets everything about its previous state when it is closed. So, for this to work, we have to open the driver when the daemon starts, and keep it open while the daemon is running, which is what Drive Daemon does. For bonus fries, this also cuts down on the performance drawback to opening and closing the driver every time we need to check on the status of the drive.
More information about removable media can be found in the following newsletter article:
Whereas checking the status of removable media is super- simple, checking to see whether a drive itself has been removed is a bit trickier. The technique hinges on the fact that, when a removable drive is unplugged from a bus, the corresponding device driver will republish its devices to indicate which devices are no longer available. Similarly, when a removable drive is plugged in, the driver must republish its devices to reflect the new additions to the system. This publish/unpublish methodology results in devfs entries being removed and added. So, you can't just keep querying your "raw" file to see whether the drive is removed, because the file might be swept out from under your feet.
"But wait," I think I hear you say. "I can check to see whether files and directories are added or deleted on my hard drive by using the Node Monitor. Couldn't I just use this in the device hierarchy as well?" Indeed, you can do just that—which is where the real power and beauty of devfs manifests itself!
Let's look at the specifics. First of all, for those of you who think the Node Monitor is a diagnostic machine used by lymphologists, a bit of orientation: the Node Monitor is a service the system provides to notify you when files or directories are added, deleted, move their location, or change their data. For a more complete description, I refer you, once again, to the Good Book:
To use it, you need to call watch_node for every directory you want to
track. To see when entries get added or removed, we need to monitor all
the directories beneath /dev/disk
.
To pick up all of these directories, we start with
/dev/disk
and recursively walk down the directory structure
from there, picking up directories as we go. Later, when we receive
notifications that items are added or removed from one of these
directories, we start or stop watching those items, respectively. It's a
bit of a brute force method, but because devfs directory hierarchies tend
to be deep but not broad, there's not too much performance penalty for
all of this watching. See the code for more details.
Having gone through all the trouble of learning this stuff, you may wonder what use you can put it to. The first, foremost, and most obvious use is for writing an automounter (i.e., what Tracker uses to mount volumes when media and disks are detected). But there are other more creative uses as well—imagine popping up a CD window when a CD is inserted in a drive, or setting up an automated system for formatting and burning Compact Flash cards when they are plugged into your machine.
My last column described the Internet Appliance space as no space at all. I tried to make the point that the term "Internet Appliance" covers a diverse and motley assemblage of devices. I recall that once upon a time, in an era far, far away, Chairman Gates shrugged off the suggestion of creating an Internet Division at Microsoft. He more or less said, in the famous 1995 Pearl Harbor speech, that the Internet was like electricity, and you didn't need an electricity division, since everything runs on it anyway. The wisdom of the Chairman notwithstanding, Microsoft announced the creation of an Internet group two or three months later. This led NeXT's Chairman Steve to remark, "Microsoft treats me the way I expected Netscape to treat me and Netscape deals with me the way I feared Microsoft would."
Back to appliances. What electrifies them is the Internet. Just as the term "electrical appliances" requires subcategories, we need to organize our thoughts a bit when looking at this new genre of devices. For the time being, I have two simple proposals. First, use the PC as an organ bank rather than a thought bank. The "sub-PC" appliance doesn't feel like a very viable idea—a PC, only smaller and cheaper. When I look at my Libretto, a very capable BeOS and Windows 98 machine, I don't really want something smaller. The Libretto already fits easily on the kitchen counter, on my lap in bed, or on the tray in a coach seat on Southwest, and inside the pocket of my L.L. Bean field coat. Add a wireless PC-Card Ethernet connection or a Ricochet modem and the size argument for a "sub-PC" disappears.
Cheaper? There are free, or quasi-free PCs—PeoplePC, for one. For the monthly subscription rate of a vanilla ISP, you get a PC, the Internet connection and "much more," such as in-home service. Why bother with less than a PC when such a deal is available?
I'm personally familiar with a related argument. I sold desktop computers, minicomputers and, now, I sell a software platform for appliances. At every turn I met the question, "why do I need this since I already have ...." The worst sales situations were the ones where the customer, or the salesperson, tried to shoehorn the contents, the application, or the larger device into the smaller one, trying to do more in less.
Most anything else could be made to work, as in making a good sale: taking the order, shipping the product, having the customer keep the product and pay the bill, getting the commission check and spending it. More for less, less for less, different for less, or even more, sometimes, but no shoehorn. VisiCalc was both more and different for less, AppleWriter was less for less—you get the idea.
My second proposal is to look at two categories of appliances; those with a hard disk and those without. It's a little simplistic, but it helps. With the diskless appliances, we have a device managed from the network. From IP telephony to information appliances, the heavy lifting is performed by the network, by one or more servers. This kind of appliance does less for less—the "more" part is simplicity.
Word documents are translated into HTML by the server, for instance; software updates, when needed, are managed remotely. As some observers noted, this sounds like a reincarnation of the NC. Well, yes and no. Yes, the NC idea was to do less for less; no, in 1995, when it was aired, the NC relied on X-Windows, which is neither simple nor less as a software platform, nor as a user experience. In that regard, we're indebted to QNX for showing what could be done on a small footprint, which led us to experiment with what we informally called BeNC a little over three years ago.
By virtue of having hard disk storage, appliances with such a feature also afford the user more control. What do I keep, what do I throw away (the "what" being mostly music or video). Think video recorders à la Tivo or Replay, or stereos with a combination of local storage and a Net connection.
At one end of the spectrum are "diskless" information appliances, at the other end are "diskfull" entertainment devices. As noted before, we're in the early stage of this emerging genre. With such a stage comes considerable confusion and the possibility of being embarrassed later by one's pronouncements. I like the confusion—to me it means opportunity. As for the occasional embarrassment, it's a small price to pay for the freedom to try thoughts out.