On Sun, Nov 4, 2018 at 9:31 AM ron minnich <rminnich@gmail.com> wrote:
On Sun, Nov 4, 2018 at 4:00 AM Chris Hanson <cmhanson@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

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 whatever.

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).