Unix defects
This tries to list all the defects that are present in Unix, an OS from the early 70's. I consider "Unix" what current Unix clones (BSDs, illumos, Linux, …) have implemented.
None of this should be present in brand new systems except within a cleanly-separated compatibility layer (like Plan9 ape).
NULL
-Terminated lists
O(n)
while length prefix is constant-time aka O(1)
.NULL
. While with length prefix you can reuse the source as-is via an offset (or pointer) and setting a different length.NULL
being present in the middle of the list? Or NULL
being absent?
And as C doesn't have a specific type for strings (char
represents a character in the same way a "word" of memory represents some kind of word), the defects applies to all lists.
This is why most of the C API regarding strings cannot be used safely (strcpy
vs strncpy
or just memcpy
), or why so many third-party C libraries APIs are architecturally broken.
errno
Implementation-defined, had to become stored in thread-local-storage in modern systems so it's not actually a global variable… enjoy.
It's also a very poor way to handle errors, if you're wondering where the occasional "Error: Success" comes from: This is it.
And of course, it means having a pretty much static amount of possible errors.
nsswitch.conf
, resolv.conf
, …
Because those configuration files ought to be trully language-independent rather than somewhat stuck to libnss
(not Netscape/Mozilla SSL/TLS library) and libresolv
by design and prone to creating a lot of problems when used by other programs (such as not dealing correctly with the options
of resolv.conf
).
Please consider: Clean ABI; Proper servers; Virtual filesystems (could look like tcb shadow for passwd
).
See Also: The problem with nsswitch for the security angle.
By the way, while (getaddrinfo(3)
, gethostbyname(3)
, …) are part of the POSIX standard, other functions like res_query
to actually query DNS records (needed for MX
, SRV
, …) aren't standardized.
getaddrinfo(3)
Related to nsswitch.conf
.
- Enjoy most developers having to write code to handle multiple records. Hopefully an unreachable/slow host isn't fatal…
- Cannot handle Happy Eyeballs (one of the ways to support IPv6)
- Doesn't handles
SRV
records, similarly to how email is usingMX
records (not handled either but at least it's a special case).
Compare this to Plan9 dial(2)
which also has a nice NetConnInfo
structure.
gethostbyname(3)
The older brother of getaddrinfo(3)
, it doesn't handles multiple records.
Filesystem I/O
Removable storage has been a thing on computers since more or less the beginning (punched cards, tape, floppies, CDs, …).
Buggy storage devices also happen too often to be ignorable.
Networked filesystems and services exposing a filesystem (Plan9, FUSE) have also been there for a long time.
Yet somehow, even modern Unixes usually cannot handle them properly, leaving uninterruptible processes if they happen to use I/O syscalls on an errorneous target.
Even BSD sockets work better on this front (which is probably why libnfs
exists).
Filesystem Queries
Most network protocols today have the ability to ask the server to search inside some database. Meanwhile Unix filesystems don't even integrate glob
, instead this function is stuck to standard libraries. With people relying on third-party I/O-trashing central databases/indexes (again removable/network storage are a thing) from non-standard solutions like locate
that are difficult to reuse in other programs.
Meaning that applications also often roll their own solution.
Compare this to Haiku
Filesystem lack of transactions
On Unixes, thanks to the lack of grouping writes into transactions (ie. BEGIN … COMMIT
in SQL). The only way to get atomicity is to do manual Copy-on-Write: Copy to a temporary location, write there and then rename to the final destination, meaning you need to have full control over it to avoid race-conditions. And for atomicity over multiple files, a common parent directory is needed, otherwise you're in a bad state between the first rename and the last one.
It also means:
- Can't do safe operating system updates without ignoring the traditional hierarchy or separating in different filesystems (luckily ZFS subvolumes exists)
- Horribly slow, you need to copy the file(s), even with hardlinking the ones you're not writing to, it takes a very long time
/dev
isn't a virtual filesystem
- Special files present in
/dev
need to be present anywhere. But it means remote filesystems, removable storage, … can contain device files with different permissions. Don't forgetnodev
mount option on basically everything. - You must be root, or on linux have the
CAP_MKNOD
capability, to create/dev
special files. This forces things like creating an initramfs to have root. - Files present in
/dev
can be regular files, so you can accidentally end up with/dev/null
taking over memory space as various programs write into it.
Should be noted that Linux's devtmpfs
somehow fixed none of the above.
/dev
should be a virtual filesystem, say something that points to a device manager like udev or the kernel itself. Similarly to how it's done for /proc
and /sys
on Linux.
ulimit
It should have been something like cgroups/Plan9-namespaces, instead you get broken-by-default soft limits which can be overridden at any moment by applications, therefore useless. And hard-limits that can realistically only be set per-user/per-group.
Ever wanted to limit the usage of one software, like say the memory used by the browser? Well you can't with limits, and apparently cgroups have side-effects…