Portable gethostname()

While gethostname() is present on almost all systems, it cannot be used directly in a portable way. The problems stem from differences in what is done when the caller does not provide a buffer large enough to contain the entire hostname. Most man pages say that the resulting hostname will be “truncated” when the buffer is too small. The definition of “truncate” varies from system to system and sometimes the system does not even behave as described in the man page.

Some systems provide a manifest constant such as MAXHOSTNAMELEN, which is meant to be used when allocating the buffer. Unfortunately, this constant is not located in a consistent place. On some systems it is in <sys/param.h>, and in others it is in <netdb.h>. Many systems don’t bother to define a constant at all. On these systems, the man page usually instructs the programmer to use some magic number such as 256.

Experiments

Experiments were done on a number of systems to see how short buffers are handled. Here is a listing of the different things that happen:

  • gethostname() returns -1 and sets errno to either 12 or 36. The buffer is not modified.
  • gethostname() returns -1 and sets errno, but also modifies the buffer.
  • gethostname() returns 0 and fills the buffer with as much of the hostname as possible, but without a terminating nul.
  • gethostname() returns 0 and fills the buffer with as much of the hostname as possible, but the last character of the buffer is set to nul.

Solution

To use gethostname() portably we must write a wrapper function which does two things:

  • Don’t assume any maximum buffer size and don’t bother to try to find a system-specific MAXHOSTNAMELEN, or equivalent.
  • After calling gethostname(), look for clues that the buffer was truncated. Try again with a bigger buffer if there is any sign of truncation.

We can use an algorithm that repeatedly calls gethostname() with ever bigger buffers until it is clear the hostname has not been truncated.

pgethostname.c is an implementation that has been tested several UNIX-like systems. It should compile without change on all modern systems.

pgethostname.man is a man page for pgethostname().