[TUHS] Unix APIs: elegant or not?

Warner Losh imp at bsdimp.com
Mon Nov 5 03:06:36 AEST 2018

On Sun, Nov 4, 2018 at 9:31 AM ron minnich <rminnich at gmail.com> wrote:

> On Sun, Nov 4, 2018 at 4:00 AM Chris Hanson <cmhanson at eschatologist.net>
> wrote:
> > This was broken from the start though, and always really meant
> everything looks like a file *descriptor*, not a path in the filesystem.
> OK, I only got into this game in 1976, and a lot had happened in Unix by
> then,
> and maybe you saw some earlier stuff. But certainly in 1976, as
> compared to the other 4 PDP-11 operating systems I was using,
> the fact that resources had names visible to every program was very
> important  to us. On the competitor systems the naming would be built
> into individual programs,
> e.g. PIP or (non-PDP11) the MPE fcopy program, one of the few programs
> on that system where you could name, e.g., the tape drive on your
> terminal.
> Being able to use a path name for resources was a very big deal for us
> at the time. And we didn't say file descriptors, we said names.
> Hence, I rate your comment as "interesting if true" but I see no
> evidence to support it.

It depends on what you did...

Tapes were always special. You could access them via a named interface, but
it was tricky. Tapes are stateful creatures, and some programs wanted
stateful, others wanted stateless. So you got different devices to do
different behavior. Easy to oops and use the rmt0 instead of the nrmt0
device. So while it was a file, it was a file that had odd state you didn't
have disks.

Serial ports were worse. There you had no way to control the serial port
except with fancy extra programs. There was no /dev/ttyd0.9600.8N1 devnode
to open. If you wanted 9600 baud, you had to either hack the driver to do
that on open, or you had to hack your programs to know they were talking to
a special thing and needed special code to cope (raw vs cooked was another
one). so, sure, it was file based, but not entirely file based as you had
to escape to either hacky system calls (v6 and earlier) or later
generalized ioctls (v7 and later).

Every other snowflake device had it's own config program that you had to
run (or ioctls your data collection programs had to do). Setting up the
sampling rates for the A2D, or the signal strength for an IRIG generator or

So sure, you could address these devices by a file name, but you couldn't
"cp config /dev/irig" or "cat /dev/ttyd0.2400.7O2" to get data flowing on
the devices, so their addresses in the filesystem namespace were of limited
value since some files were more special than others.

I'm not sure plan-9 solved this by having a second device side-channel
either in its attempt to try a different approach to side-channel
communications than ioctl(2).

Network sockets are a logical conclusion to this state of affairs, btw. All
the plethera of new system calls for them could have been done as ioctls,
though the generic processing stuff for ioctls would have gotten in the way
of some of the socket API. It's another twist on the baud rate problem: I
need to communicate metadata about how to do things to the driver... And in
this case, a lot of the 'how to do things' is negotiated via a different
side channel (routed, ARP, etc) and so you no longer had a raw physical
network device to open, but a logical, cooked one that you interacted at
the top of the stack to and all those other details were abstracted out /
taken care of in other ways. It's unfortunate that you can't just open
"/dev/net/sri-nic.arpa" and have it do the right thing, but files kinda
want to be stateless and there's a lot of state about what you want to do
with that open command...

And while mounting allowed one to get files from a disk, it wasn't so good
at doing things dynamically (as the original system were quite static) and
required a number of ad-hoc hacks to make work right. block vs character
devices showed early on a crack in the uniformity.

So while I love the ideal, I also see how the practical side of things
forced us down the path we're down, ugly warts and all. I'd love to see
someone start with V7ish level of kernel, but add the modern things like
devfs (so one could pass 'state' strings to drivers on 'open' and have them
accept/reject them to get around some of these issues), as well as provide
all objects in a namespace that's sane and mostly enumerable. For that
you'd need new abstractions (like saying that all drivers don't interact
via cdev-nodes like today, but instead present a filesystem-like interface
so you'd open /dev/tty/d0/9600n1/hw-flow and the tty driver would get a
message for its d0 instance of 9600n1/hw-flow, though this would break
dirent(2)). In this world, you could have most of the crazy encoded into a
path for network operations as well... though I have doubts you could do it
in as a performant manner as sockets).

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://minnie.tuhs.org/pipermail/tuhs/attachments/20181104/0789bdfc/attachment.html>

More information about the TUHS mailing list