2010-04-15
The standard format Unix error messages
As a sysadmin, I have developed strong and quite fixed opinions about how Unix programs should format their error messages for maximum useful readability by harried sysadmins. Today I feel like boiling it down to what I will grandly call the standard format Unix error message, which is the format you should use unless you have a really good reason to do otherwise.
The standard format message should be written to standard error, and looks like:
program: general problem: specific error message
A typical example would be:
mycat: cannot open 'nothing': No such file or directory
You can have multiple levels of specificness; two is just the usual
case, since it fits well with the common sort of failure (as we see in
the mycat example).
There's a number of slightly subtle aspects and rules of this form:
- error messages should be printed as a single line, even if they're
long. If you have to print multiple lines, put the program name
on the start of every line.
(If you are just reporting multiple problems at once, report each problem independently in the standard format.)
- please do not be inventive with the ordering of the parts of the error
message, where in the message you put the filename, and so on,
and especially don't use different ordering for different messages
in your program.
(I do not want to have to pay attention to your specific error messages and read them carefully; I want to skim them, and I should always be able to read an error message from left to right and get it from more general to more specific.)
- if the problem involves a file, always tell me what the filename is.
'Could not read configuration file' is less useful than 'Could not read
configuration file /etc/somefile'. (You remember where your program's
configuration file is, because you developed it. I don't.)
- similarly, please put explicit quotes around the name of the filename so
that it's clear that it's a filename and not part of your error message.
(Consider the ambiguity of 'cannot open nothing', for example.)
- I want to know exactly what went wrong, not what you think went wrong,
so if you're reporting on a failure that sets
errno(such as a failed system call), usestrerror()(or%min glibc'sprintf()), or your language's equivalent, to print the standard system error text for theerrnovalue. As a sysadmin I will be happy if you also give me theerrnonumber itself, because vendors keep changing the wording of the standard errors.(Do not give me just the
errnonumber, or I will be very grumpy. Looking things up in tables is what computers are for.)
While it's tempting to use perror() in C programs, perror() doesn't
give you enough for good messages by itself and so tempts people into
excessively minimal error messages. GNU libc has error(3), which seems
to have all of the features you could need for this and then some.
(I have probably missed some rules for good Unix error messages, and there is probably a better web page on this somewhere.)
2010-04-02
Notes on the compatibility of crypted passwords on various Unixes
For some time, lots of Unix systems have supported better password
encryption schemes than the basic old crypt(3) salted-mutant-DES
approach that's been used by Unix since V7. This is a good thing in
general, but if you have a heterogenous Unix environment with shared
passwords it creates a very important question: what password encryption
schemes are supported on all of your Unixes, and are thus safe to use?
(Encrypting passwords with an alternate scheme not supported on a
particular Unix version basically means that you can't use that Unix
version. For a long time the only safe answer here was to use the
original crypt(3) scheme, weaknesses and all; this still remains the
most future-proof answer, since it's very unlikely that there will ever
be a Unix that doesn't support them.)
In general, people have settled on a generic format for 'modular'
encrypted passwords. They generally look like '$<alg>$<salt>$<rest>',
where the <alg> is one or more characters to specify the algorithm,
the <salt> is some number of characters of per-password salt, and the
<rest> is the encryption result. This is about all that's settled;
different Unixes differ in what algorithms are supported (and how
they're designated) and how long the salt can be, and some algorithms
change the interpretation of the fields.
Based on reading manpages and Wikipedia (and not on actual experimentation), the rough state of affairs is:
- MacOS X supports only traditional
crypt(3)passwords and a special 'DES extended format' that isn't widely supported. - Linux supports MD5 and sometimes '2a' Blowfish, SHA-256, and SHA-512
and allows up to 16 characters of salt.
- FreeBSD supports MD5 and '2' Blowfish and only allows 8 characters of
salt, assuming that the manpage is not lying about that.
- NetBSD and OpenBSD support MD5 and '2a' Blowfish, with no stated salt
size limits for MD5 (their Blowfish is explicitly stated as using a
128 bit salt).
- Solaris 10 supports MD5, '2a' Blowfish, SHA-256, and SHA-512 with no
stated limit on salt size.
- AIX supports having additional algorithms, but I couldn't find documentation on what additional methods are actually supplied.
(I have skipped algorithms only supported on one Unix. There appear to be two versions of the Blowfish scheme, one known as '2' and one known as '2a'.)
Assuming that you don't care about MacOS X and perhaps AIX, MD5 appears to be your only safe bet if you trust everyone to have implemented it the same (and you can somehow avoid the salt length problem). Hopefully they have; that everyone uses the same format for modular encrypted passwords (and the same characters for various algorithms) is at least a good omen.
Sadly, my overall conclusion from this is that old-fashioned crypt(3)
passwords are still the safest choice. Enabling anything else would
require careful experimentation to make sure that everything actually
did do, say, 'MD5' encrypted passwords the same and there were not
peculiar limits that were going to be an issue.
(I'm vaguely disappointed by this, as I was hoping to find that by now
it was safe to use something better than plain old crypt(3). I guess
our systems need to stay old-fashioned for a while longer.)