home *** CD-ROM | disk | FTP | other *** search
- Newsgroups: comp.sys.next.programmer
- Path: sparky!uunet!gumby!destroyer!ncar!unmvax!ctm
- From: ctm@ardi.com (Clifford T. Matthews)
- Subject: Re: _IO, _IOR, _IOW and _IOWR functions
- Message-ID: <1992Aug19.220946.13633@unmvax.cs.unm.edu>
- Keywords: pedantic, long
- Sender: ctm@unmvax.cs.unm.edu (Clifford T. Matthews)
- Organization: ARDI
- Date: Wed, 19 Aug 92 22:09:46 GMT
- Lines: 125
-
- Dear curious/bored folks,
-
- The "routines" that the subject line alludes to are actually macros that
- are used to create "magic cookies" for the ioctl system call. By magic
- cookie, I mean a unique integer identifier. Here's a brief top-of-my-head
- history of ioctls and such:
-
- In general, UNIX allows you to do three different things with devices:
- read, write, and "everything else". Reading and writing need no further
- explanation; "everything else" (done with the "ioctl" system call) varies
- from device to device, but includes things like setting the input and output
- speed for terminals, setting the density for tapes as well as werid stuff
- like raw scsi commands (you need root to do these, which is good).
-
- In general, UNIX has little abbreviations for the devices that it supports.
- The NeXT has support for things like "sd" (SCSI drive), "od" (optical drive),
- "zs" (zilog serial communications controler (terminal port)) and so on. When
- you need to do low-level accesses to these things you wind up writing code
- that looks like:
-
- int filedescriptor;
- char buf[1024];
-
- filedescriptor = open("/dev/rsd0h", O_RDONLY);
- nread = read(filedescriptor, buf, sizeofbuff);
- ...
- err = close(filedescriptor);
- ...
-
- In the above example "/dev/rsd0h" identifies that you want to open up
- the first logical SCSI drive (drive 0). The "h" means the special
- partition that allows you to get to normally inaccessible portions of
- the disk and the "r" preceeding the "sd" means you want "raw" access,
- i.e. you'll be bypassing the normal UNIX block buffering cache.
-
- You can read about raw SCSI access in the "sd" man page. If you do, you
- will see that you can do other things with disks, like eject them.
- To do so, you use the DKIOCEJECT ioctl argument, as in:
-
- err = ioctl(filedescriptor, DKIOCEJECT, (char *) 0);
-
- In the above example the third argument to the ioctl is zero, cast as a
- pointer to char. We do that because DKIOCEJECT doesn't need any extra
- information to do it's job. The file descriptor that is passed in is
- sufficient to identify which disk to eject. However, some ioctls need
- extra information, or return extra information, or both. We're now
- ready to look at _IO, _IOR, _IOW and _IOWR.
-
- It turns out that if you "grep DKIOCEJECT /usr/include/nextdev/*.h",
- you'll see that DKIOEJECT is a #define that looks like this:
-
- #define DKIOCEJECT _IO('d', 21) /* eject disk */
-
- _IO is just a macro that generates a unique number that the implementors
- of ioctl for disks can look at. The 'd' is a single character that serves
- to identify what kind of device the ioctl is relevant to 'd' in this case
- stands for disk. As long as people are consistent and there's no collision,
- it doesn't matter what the letter is. The second argument, 21, is just
- a unique number that keeps DKIOCEJECT separate from the other 'd' ioctls.
- If you "grep _IO /usr/include/nextdev/disk.h", you'll get this for output:
-
- #define DKIOCGLABEL _IO('d', 0) /* read label */
- #define DKIOCSLABEL _IO('d', 1) /* write label */
- #define DKIOCGBITMAP _IO('d', 2) /* read bitmap */
- #define DKIOCSBITMAP _IO('d', 3) /* write bitmap */
- #define DKIOCREQ _IOWR('d', 4, struct disk_req) /* cmd request */
- #define DKIOCINFO _IOR('d', 5, struct drive_info) /* get drive info */
- #define DKIOCZSTATS _IO('d',7) /* zero statistics */
- #define DKIOCGSTATS _IO('d', 8) /* get statistics */
- #define DKIOCRESET _IO('d', 9) /* reset disk */
- #define DKIOCGFLAGS _IOR('d', 11, int) /* get driver flags */
- #define DKIOCSFLAGS _IOW('d', 12, int) /* set driver flags */
- #define DKIOCSDCWIRE _IOW('d', 14, struct sdc_wire) /* sdc wire memory */
- #define DKIOCSDCLOCK _IO('d', 15) /* sdc lock */
- #define DKIOCSDCUNLOCK _IO('d', 16) /* sdc unlock */
- #define DKIOCGFREEVOL _IOR('d', 17, int) /* get free volume # */
- #define DKIOCGBBT _IO('d', 18) /* read bad blk tbl */
- #define DKIOCSBBT _IO('d', 19) /* write bad blk tbl */
- #define DKIOCMNOTIFY _IOW('d', 20, int) /* message on insert */
- #define DKIOCEJECT _IO('d', 21) /* eject disk */
- #define DKIOCPANELPRT _IOW('d', 22, int) /* register Panel
- #define DKIOCSFORMAT _IOW('d', 23, int) /* set 'Formatted' flag
- #define DKIOCGFORMAT _IOR('d', 23, int) /* get 'Formatted' flag
-
- See, someone just arbitrarily assigned numbers for the various special things
- that you may want to do to disks. Not all of the #defines are _IO, there's
- also _IOR, _IOW and _IOWR. Those used when the ioctl needs to read information
- from the device, write information to the device or both, respectively.
- With those three variants of _IO, a little more is being done then creating
- a unique number; the nunmber of bytes that need to be copied between
- "user space" (i.e. your program) and "kernel space" (i.e. the UNIX operating
- system) is also rolled into the "magic cookie". Specifically those three
- variants use sizeof(arg3) to determine how many bytes are going to need to
- be transferred. So in reality, the magic cookie consists of four things:
-
- The type of device we're operating with/on
- A unique number identifying the type of operation we're doing
- a pair of direction flags no direction, read, write, both
- and
- the number of bytes that will be moved.
-
- So now the question is what can you do with _IO and friends? Basically Nothing.
- There is no point to rolling your own "magic cookies", because the device
- drivers only know about the ioctls that are available through their (slightly)
- less cryptic names (i.e. "DKIOCEJECT" vs. "_IO('d', 21)"). However, there
- are rare times when you may want to know what kind of "ioctl"s an application
- is using. In that case, you can find the #defines for "_IO" and friends and
- figure out what the various magic cookies for the various ioctl calls, and
- then use gdb on the mystery program and take a look at the args on the stack
- when ioctl is called.
-
- As always, if a routine requires super-user privs to function, you should be
- very wary of using it; when you're doing low-level accesses to disks and
- what not, you can really do a lot of damage in a short time.
-
- BTW, I enjoy learning about things via the net, but I really like to see
- references rather than information; I try to do unto others ..., but in
- this case I'm not really sure what a relevant reference would be, perhaps
- a book about programming the kernel, or the design/history of UNIX. The
- trouble is, I was hacking UNIX kernels before those books were published,
- so I'm not adequately familar with the books to tell you whether or not
- they go into such little details.
-
- --Cliff[ord T. Matthews]
- ctm@ardi.com
-