Hacker News new | past | comments | ask | show | jobs | submit login
Unix and Multics (2019) (multicians.org)
135 points by aragonite 13 days ago | hide | past | favorite | 76 comments





Also relevant is the DoD security assessemt of Multics and the advantages of PL/I over C in regards to memory safety.

https://www.multicians.org/b2.html


Note the punch line at the end:

> Was it worth it?

> The marketplace seems to have answered this question: not at current prices. See [Lipner15].

Note that, unlike our discussion below, this is about the cost of implementing B2 security in an OS, not about the sale price of the OS (though the two are related).

Or perhaps I should say, the sale price of the OS is forced so high by the cost of B2 that the market isn't interested in the OS, but this would be true whether Unix was free or not.


And now we have governments stepping in to fix past decisions regarding programming culture.

I'm not sure you're still in the conversation after all this time, but if you are:

Back in the 1950s and 60s, there was the "software crisis", which was that we could not produce all the software that we felt we needed. Now we have governments, not "stepping in" exactly, but at least making recommendations. We wrote all this software, but it was imperfect in ways that cause real problems. But producing B2 software took too long and cost too much - we'd have much less software if we did it that way. (You could argue that the world would be better off; I'm assuming that it would not be.)

So I have a question (an honest question, not a "gotcha"): In your view, where should the balance be? You think C is too insecure. Fine; I won't say there's no evidence for that view. How far should we go? Java? (No buffer overflows.) Formal correctness? B2? A1?

Software that is more correct and secure is good. More software (or at least more efficiency in creating software) is also good. Where do you put the balance?


The balance should be like in any profession that affects society, there is a minimum of quality and certification, before whatever is done in a garage or home kitchen is allowed to be consumed by others.

What happened to PL/I ?

Was later adopted by IBM and Intel for their OS, although since it grew C++ levels of complexity, eventually split up in various dialects.

PL/S, PL/M, PL.8, PL/Something...

One of them, PL.8 is famously associated with being one of the first LLVM like compiler frameworks, used by IBM on their RISC research, before they pivot and created AIX for their RISC CPUs.

System languages like PL/I, BLISS, Modula-2, would have had a different adoption if UNIX wasn't basically free beer with a recipe on how to make it.


> System languages like PL/I, BLISS, Modula-2, would have had a different adoption if UNIX wasn't basically free beer with a recipe on how to make it.

You always say that. And I always call BS on it. I don't expect to persuade you, replying for the Nth time, but I have a couple of things I want you to think about.

"Not free" sometimes beats "free". People buy cars even in cities that have public transit. People paid for cable TV when over-the-air TV was free.

For this to happen, though, the not-free option has to deliver more value than the free version. With a car, I can go when I want; with public transit I have to wait. For many people, there's value in that. With cable I can watch 500 channels. There's value in that, at least for some people.

PL/I, Modula-2, and Pascal did not deliver more value than C - or at least not enough value to be worth the price of their compilers. Multics did not deliver more value than Unix - or at least, not enough more.

In fact, Multics had to reach a very high bar, because not only was Unix free, it ran on less-expensive hardware. The issue (probably) wasn't that Multics cost more than Unix; the issue was that Multics ran on hardware that cost a lot more than a PDP-11. Unix could have cost as much as Multics and still won, because the cost of the OS was not the dominant cost in the equation.

You often mention network effects - that Unix and C took over universities because they were free, and so everyone was using them, and so everyone knew how to use them, and so when they went somewhere else, they used what they knew. Go back to cable TV. Over-the-air TV had network effects - everyone was talking about the show they watched last night, and if you didn't watch it, you were left out. It was free advertising plus social pressure to be part of the "in" crowd. And yet cable still made money, and eventually grew into internet distribution, and still took away large amounts of market share from broadcast. Network effects can be overcome, if the product is actually closer to what people want.

So I think your explanation is too simplistic. It may have been a factor, but in the ahistorical world where Unix and C weren't free, I think they would have won anyway - still because of cost, but because of hardware cost.


I am full down that if UNIX wasn't free beer it would never had been adopted at scale.

Its warts are only bearable, because of being free beer.


I refer you to the last line of the article:

> Multics didn't fail: it accomplished almost all of its stated goals. Unix succeeded too, solving a different problem.

Multics wouldn't have become what Unix became even if Unix wasn't there. It was pursuing different goals. And it turned out that Unix's goals had a lot bigger market than Multics's goals.

So, Unix had warts. But those warts were bearable because it met the needs of the market it addressed, and the other OSes didn't do so, or at least didn't do so as well.


Had UNIX been sold as commercial product, most likely the winner would have been something like VAX VMS, not Multics, which was anyway an OS for DoD only.

Or something else, definitely not UNIX, there was plenty of other alternatives when free would not have been an option, and UNIX haters book is still quite up to date in some of the original warts.


Nitpick: Multics was used by non DoD users - e.g. Bell Canada, Ford, General Motors, and a number of Universites worldwide.

https://multicians.org/sites.html


> Had UNIX been sold as commercial product, most likely the winner would have been something like VAX VMS

In the 70s and 80s, a lot of universities used VM/CMS for research and teaching. But then they ended up all migrating to some combination of UNIX and PCs running DOS/Windows.

In the 1980s, IBM was seriously pursuing the idea of a VM/CMS-based workstation – they ended up actually releasing the IBM 7437 VM/SP Technical Workstation in 1988, and it was adopted by some customers, primarily those who used the mainframe-based CAD systems CADAM and CATIA. But it just couldn't compete with UNIX workstations in the market. In an alternative timeline where UNIX was much less successful, it might have stood more of a chance.


Had VMS been any more wide spread, there would have been a VMS haters book.

I could make a start, referring to the default editor, EDIT. In the early nineties (no idea, what version that actually was) it was possible (and there was no warning) to edit the same file in multiple sessions (using multiple terminals by not-so-well communicating team members). Only the last file saved remained on disk.


I think that’s a reasonable argument, but in practice if Unix and C weren’t free it would have meant universities using tools that were closer to free — things like the UCSD p-system would have been more widespread. Different world; possibly a better one, if I’m right, which is unknowable.

There were other free operating systems that universities could and did use like EMAS [1], UNIX beat them as well.

[1] https://en.wikipedia.org/wiki/Edinburgh_Multiple_Access_Syst...


EMAS only ran on expensive hardware, ditto MTS.

Is there a meaningful difference between C and BLISS apart from the Fortran-like syntax of BLISS?

Well, we built a compiler in bliss 36 so I can address that a bit.

Bliss isn’t like Fortran and is quite a different beast from C. It had a practical way to define structures. It defined code structures as expressions rather than statements. I feel it was a a little higher level than C. But not higher level like PL/I. There were different languages for 36 bit machines (PDP-10) 32 bit machines and I think even 16 bit machines.


Bounds checking.

PL/C was a simplified(?) version that was handy for this 1970s student.

I remember using the Cornell PL/C compiler. You could enter something like

PU LIST('Hello, world!

and it would generate a raft of error messages, followed by running the program and displaying Hello, world!

PL/C's heroic error correction dates from when student programs got 2 or 3 runs per day.


We used to joke that if you fed the IBM PL/1 compiler a blank file, it would compile a default program. Probably a matrix multiply.

Yes, heroic error correction ! It was cool.

You can get a taste of the syntax from playing with REXX , which is an interpreted language that started on mainframes but has been ported almost everywhere.

In early 90th I was an OS/2 fanboy, I did a lot of automation in REXX. I'm not sure REXX syntax resembles PL/I which was then heavily used at the place I worked on "big iron". PL/I used to be more verbose, uppercased and aming SQL database work, methinks. REXX, on the other hand, was more like Perl and I felt quite comfortable with Perl when I switched OS/2 to FreeBSD. :)

And adopted as Amiga's main scripting language on its last years.

I don’t think REXX is like PL/I. And it does run on pretty much any IBM hardware and os

It is still around, although far less used than it once was. Some people use it on IBM mainframes, although COBOL was always more popular. Also saw some usage for applications on OpenVMS

IBM z/OS is mainly written in PL/X, which is a systems programming dialect of PL/I (removing features which are irrelevant to systems programming and adding stuff like inline assembly). So are various other IBM mainframe products like DB2 for z/OS. PL/X was previously known as PL/S, PL/S II, PL/AS. There was also a "PL/X-86" which was a port of PL/X to x86, targeting OS/2, it was used for mainframe service processor code.

Large parts of IBM i are written in a couple of related PL/I dialects, PL/MI and PL/MP. PL/MI is used for code that runs above the virtual machine, PL/MP for code which runs below it. When they switched from CISC to RISC, a lot of the PL/MP code was rewritten in C++, although apparently some of it survives. (Parts of IBM i are also written in Modula 2)

PL.8 is yet another systems programming PL/I dialect. It was developed as part of the compiler for the IBM 801 RISC project. It was the language many of IBM's compilers were written in (not sure if that is still true?). In the earliest versions the AIX kernel was written in a mixture of PL.8 and C, although newer versions all the PL.8 code is gone. It was also used to write firmware for mainframes (and possibly AS/400 aka IBM i too). IBM even built a PL.8 frontend for GCC, but they never officially released it outside of IBM – https://dl.acm.org/doi/10.1147/rd.483.0543

Yet another IBM PL/I dialect is PL/DS which was used for the IBM 8100 and DPPX/370, although that stuff is long dead.

Then there was also Intel / Digital Research PL/M, which was used to write CP/M. (In CP/M 2.x and later, the core of the OS was moved from PL/M to assembly to improve performance, but PL/M was still used for utilities.) I've also heard claims that PL/M was used to write some of the firmware on CISC AS/400 (more specifically, the Service Processor), although not sure how true that is.

And then the defunct Honeywell CP-6 mainframe OS had its own PL/I dialect, PL/6.

PL/I is also apparently what Stratus VOS is written in

The Space Shuttle flight software was written in HAL/S. But the HAL/S compiler, which ran under MVS (later z/OS), was written in a PL/I dialect XPL – https://github.com/virtualagc/virtualagc/tree/master/yaShutt...

Prime Computer's PRIMOS was unusually written in FORTRAN, but in later versions they started using their own PL/I dialect (PL/P) as well

Several airlines used to use a PL/I dialect called SabreTalk (aka PL/TPF), but (apparently) they've since converted all that code to C – http://teampli.net/Sabretalk_Reference_Guide.pdf


Back in the 90s, Object REXX was available on OS/2. I used it to tie a mainframe application on 3270 to SQL calls to update a database for a windows application. Once Object REXX was released on Windows, we moved it off OS/2.

REXX is not PL/I, but very easy to for a PL/I programmer to pick up.

PL/I on the mainframe can be a highly effective application language, but there's a number of features that are ferociously computationally expensive that were acceptable for low volume or one off stuff that had to be avoided by production applications.

COBOL is tedious compared to PL/I. While I had occasion to fix COBOL bugs and performance issues and even taught SQL to COBOL programmers I refused to write COBOL programs.

Then there's Multics PL/I. I did a pilot project to evaluate porting from IBM VM to Multics on Honeywell and discovered a flaky environment. I saved my employer a pile of money by killing that idea. Unfortunately the HW GCOS had to be replaced by a Multics machine which gave no end of problems. Happily that was not my problem.


I really respect Ken Thompson's ability to filter things down to the essential functionalities. I wish I could gain a fraction of that power some day.

I disrespect taking ideas from people and then talk shit about them until most people think that they're your ideas. Or just leaving out credit: https://infosec.exchange/@hovav/111301691767812533

Looks like he did update a reference to it.

https://hachyderm.io/@rsc/111307163277337129


It's very easy for moderns to forget (or just not know) how difficult it was to find information before the Internet really took off.

When Ken cited "Unknown Air Force Document", you can be sure it would have been a direct citation if he had the paper at hand. But let's be generous and assume he called an Air Force reference librarian and described the paper he was looking for, and said librarian wasn't able to find it on the basis of that description. What's the next step? There isn't one.


> Multics didn't fail: it accomplished almost all of its stated goals. Unix succeeded too, solving a different problem.

Hm.. what problems Multics had been solving then ?


The goal was a reliable secure OS (achieved) that unfortunately was not very portable.

Also: written in a high level language (uncommon at the time), uniform structures and models for things like memory and IO, and many more laid out in the original Multics papers.

If Multics had been treated as a research project rather than being a plan to invent a ton of new stuff and build a system that would be deployed in volume, everybody would be singing its praises today.


> If Multics had been treated as a research project rather than being a plan to invent a ton of new stuff and build a system that would be deployed in volume, everybody would be singing its praises today.

I wonder if Multics had to be pitched to funders as "a plan to invent a ton of new stuff and build a system that would be deployed in volume" to obtain the level of funding needed for it to prove out its precepts. As a research project, it might not have had the impact that it did upon modern OS theory, design and implementation.

Even today, there is an incredibly strong averse reaction by funding agents to the software notion of "build one to throw away".


That was back in the early 60s, funded by ARPA as part of Project MAC. The “customers” were the kinds of people who cared about the rainbow books (hint: all government), though the science was open.

ARPA (later DARPA) funded a lot of things that were built under contract, not just pure research.

Most of project MAC was pure research and a lot of it is still fundamental and influential today.


Indeed. Porting it to an architecture that wasn't 36 bits wide would be a major undertaking. From my minimal reading of the source, PL/1 (or, perhaps, the dialect of it which was used on Multics?) lacks a real equivalent to C's typedef, and as a result you have explicitly sized types like "fixed bin(35)" and "bit(18)" and the like all over the place in the source.

Beyond that, it was, as Germany described their WW1 alliance with Austria-Hungary, “chained to a corpse”. The GE 645 was essentially a IBM 7090 derivative bolted to a very advanced MMU. The successor implementations were heavily bound by (a) antediluvian architecture and (b) increasingly limited corporate resources to supercharge something increasingly farther away from the mainstream.


This short video / simulation, explains why, IMO, Unix surpassed Multics: https://www.youtube.com/watch?v=3Ea3pkTCYx4

But Multics was written in PL/I (and the Burroughs B5000 system in Algol before) so Unix doesn't have an advantage there.

> We went to lunch afterward, and I remarked to Dennis that easily half the code I was writing in Multics was error recovery code. He said, "We left all that stuff out. If there's an error, we have this routine called panic(), and when it is called, the machine crashes, and you holler down the hall, 'Hey, reboot it.'"

The New Jersey Style.


I've come to believe that the "just reboot" mindset is a rotten one that has done severe damage to computer technology and the people that work on it. It was a compromise that made sense in its place and time, but we've seen firsthand that safety, reliability, correctness, etc. are impossible to bolt on after the fact, and 50 years of commitment to that compromise has resulted in mountains of shit that will never work quite right that go on to generate more mountains of shit that will never work quite right. Decades upon decades of machines unfathomably more powerful than the PDPs UNIX was written for still kowtow to its deficiencies and mental shortcuts. I wonder if anybody who has been along for the whole ride has any regrets.

I don't think Microsoft got it from Bell Labs. "Just reboot" isn't Ritchie's invention so much as what you do when you're writing code in a too-small team and in a hurry in a crappy systems programming language. Since teams are always too small (else they are too large), and everyone is always in a hurry, the real problem is the programming language.

C's arrays-decay-to-pointers sin is the original sin here, but it's not for nothing that it's taken so long to get systems programming languages that have manual memory management and are memory-safe: that's a hard problem!


I wonder if there could be an ultra-pessimist errors-first programming language.

The main purpose of any code would be to deal with all possible errors and define them upfront. If, by miracle, your program execution does survive the minefield, you can throw a Success exception.


Errors happen when one or more of a function’s assumed dependencies are missing or invalidated. So in a PL like you’re imagining, every function would need to run an assertion prologue validating all of its static dependencies. As for dynamic dependencies, they would need to be dynamically (continually) validated, probably at multiple scopes (who watches the watchmen?). If you squint your eyes you will see that static dependency checking is in fact partially provided by type systems, the more capable the type system the broader it’s functional coverage. The complexity actually lies in those dynamic dependencies, which are external systems and components, sitting at the other end of some channel, and this includes the very hardware components the function is running on. If you follow this rabbit hole you’ll see that there’s no such things as static dependencies, just allegedly more stable dynamic ones; and that all dependencies are intertwined with each other within the continuum of the universe; and that anything that works is a miracle, built upon hopes and dreams. So we could say that the ultimate exception is a program working as intended, every time. So why even bother programming defensively? Let it crash!

You might like Erlang.

Now that's truly exceptional pessimism.

Sounds a lot like error handling in Golang :)

Yes, and in prod I have a recover() handler that sends me an email with stack trace. Haven't gotten one in a few years...

Somewhere a spam filter thinks stack traces look like viagra ads.

Yes, except for the "defining them upfront" part, which sounds similar in theory to checked exceptions in Java. I'm very partial to this, especially in Go, where nobody ever bothers to propagate errors properly and instead just bubbles up the same `err` object all the way to the top.

Maybe we could define a numeric identifier for each error type we have, which would let us have quite a large number of errors in an already well-known type. I guess we'd have to reserve 0 for the rare success case. In order to make sure people don't forget about it, we can even have our `main` function return an integer!


Actually you have. It is called token ring. Except it is painful to support and we all hate it. Strangely the same philosophy get you Ethernet … ether does not exist. We just do not 100% sure about delivery. And strangely in those days to think this work. And ip as well.

Rust, kind of.

People then concentrate more on avoiding errors than getting things done.

> easily half the code I was writing in Multics was error recovery code.

And it can be worse. IBM, I think it was, back in the 1970s or 80s, said that 80% of the lines of production-ready code dealt with errors - only 20% was doing the actual program functionality.


Assembly?

I've actually written most of my code like this for the last 25 years or so. Assert and panic. Surprisingly it usually ends up with stuff that never crashes in production because it spent several days blowing up in my face before it got that far.

This has been exactly my strategy when writing software for medical devices, in my case, ultrasound systems.

You have to help other developers understand how and when to use asserts, and then you have to test the developed device very well, so that it won't assert in the field.

Yet if it does assert in the field, it's highly likely that it will get a lot of management attention.


> if it does assert in the field

That’s a key point: you don’t want debug-only asserts to be used where you need production error handling.


Here's my take. Asserts are a kind of error handling. They handle situations where the code can tell that it's off the rails. It might be off the rails due to a hardware error or a software implementation error, e.g., a 'can't happen' situation.

We didn't have debug-only asserts. Asserts were enable in the software we verified and shipped.

It took a while for developers to be able to determine when a situation called for an assert, and when it called for what might be called traditional error handling.

The strategy of shipping with asserts enabled kind of worried some folks. They were concerned that it might assert in front of a customer. I understand the concern, but in our domain, if you're doing an OB exam with the ultrasound system and you have a choice of asserting or showing a femur length measurement of -1039cm, which is better?

We didn't have many asserts in the field. We had a lab where we had about 25 - 30 ultrasound machines running embedded tests constantly. Each machine was connected to a JTAG debug board, so we could flash new code into the system and so we could set a breakpoint on the assert routine itself and save a "core dump" for subsequent debugging without having to try to reproduce the system state that led to the assert.

The whole lash-up evolved over a period of years. It worked well, so far as I know.

One mitigating factor was that our systems were class B devices. They were always supposed to be used by a medically trained professional that had the ability to take over if the system asserted, or power failed, etc.

Happy to try to answer any questions about this.


I'm sure this isn't an original idea, but I've always understood that an assert is intended for the developer, an error is intended for the user. Sometimes an assert can be by itself because you know that the invalid condition will be 'absorbed' (for want of a better word), and sometimes an assert is followed by an error because you want the developer to see more than what the error will display to the user.

I learned this approach in Code Complete, and is one of the approaches when dealing with C.

Ironically, one of the perhaps better known Multics stories involves a panic-style message from early in its boot loader.

It was in Latin. "HODIE NATUS EST RADICI FRATER".

https://multicians.org/hodie-natus-est.html


See also: this recent HN story https://news.ycombinator.com/item?id=40178652 from Cliff Biffle's blog https://cliffle.com/blog/hubris-reply-fault/ about the Hubris OS used by 0xide (https://oxide.computer/blog/hubris-and-humility).

A design principle in the OS is that if you pass anything invalid to a syscall, you don't get an error back, you get your process forcibly killed. The thing linked at the start of the paragraph above is about an extension to this principle: if you have a client/server pair running on the OS, and the server gets a request it thinks is invalid, it can forcibly kill the client.

All of which sounds kinda insane, but (as per cjk2's comment in this thread) apparently what actually happens is that in development things blow up all the time and get fixed, and once you get through that phase all those bugs are fixed and everything is very robust.

(But Hubris's use case is quite specific and so far as I know no one is claiming that it would be better if, say, Linux or Windows worked that way.)


Things don't actually blow up in development, for whatever it's worth. It's really very unusual to have a defect whereby an invalid message is sent to a task -- which was part of why REPLY_FAULT was an entirely reasonable extension of the system: it doesn't come up often, but when it does, you really want to debug it.

Ah, my apologies. I thought I remembered the Cliffle post saying that, but in fact he says it specifically about the kernel behaviour rather than about the generalization to REPLY_FAULT. I hope no one was misled.

No worries! (It would be quite reasonable to think that we hit this a lot in development; I just wanted to clarify it for anyone who came by the thread.) And it does sound pretty off the wall to anyone who might not understand the context of Hubris, but (to bring it back on topic with Unix terms), I would liken REPLY_FAULT to SIGSYS, which would be seen under similar terms (i.e., grievously incorrect application) and has the same disposition (i.e., core dump).

Eh eh, there's two New Jerseys here. There's Ritchie and friends, and then there's the people who did SVR2 and up, the ones that created that monstrosity called STREAMS, etc.

"It came from New Jersey" was a pejorative at Sun for "it's [crap code] from SVR4". I bet it's still a pejorative at Oracle for whoever still works on Solaris.


or erlang style?

Erlang's design choices naturally raise errors by default, early; Unix/C tended more to ignoring them. It's true that some faults do kill you, and that when you don't ignore errors, the next simplest handling is to panic. Back when I coded in C I usually wrapped library functions to work that way.

Erlang supports supervision patterns more, though I have little experience there.

"Let it crash" at cell boundaries is also a basic pattern in complex life. I'll bet there's plenty more for programmers to learn about robustness from biology. Doctors and medical researchers too, actually -- they seem too prone to think like "oh here's a kind of damage, guess we have the inside track on this disease now" without understanding it at a level like "here's how the body's self-repair gets overwhelmed".




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: