## Table of Contents
%TOC%
## Overview
This is a recompilation of common porting problems and their solutions. Information is gathered from the following sources:
* [Debian GNU/Hurd port guidelines](http://www.debian.org/ports/hurd/hurd-devel-debian/)
* [James Morrison's GNU/Hurd pages](http://hurd.dyndns.org/)
as well as other misc. sources.
First of all, see [[BtsFiling]] if you need instructions on manipulating [Debian](http://www.debian.org/) source packages and submitting patches to their [Bug Tracking System](http://bugs.debian.org/).
## Missing pthreads
You can try out Neal Walfield's implementation of libpthreads. It will serve as our pthreads library until "the one pthreads that will rule them all" in GLibC has native support on the Hurd. Quote is from the mailing lists by Roland McGrath.
The pthread library is available from [the Hurd CVS on Savannah](http://savannah.gnu.org/projects/hurd/).
## Undefined `bits/confname.h` macros (`PIPE_BUF`, ...)
If macro `XXX` is undefined, but macro `_SC_XXX` or `_PC_XXX` is defined in `bits/confname.h`, you probably need to use `sysconf`, `pathconf` or `fpathconf` to obtain it dynamicaly.
The following macros have been found in this offending situation (add more if you find them): `PIPE_BUF`
An example with `sysconf`: (when you find a `sysconf` offending macro, put a better example)
#ifndef XXX
#define XXX sysconf(_SC_XXX)
#endif
/* offending code using XXX follows */
An example with `fpathconf`:
#ifdef PIPE_BUF
read(fd, buff, PIPE_BUF - 1);
#else
read(fd, buff, fpathconf(fd, _PC_PIPE_BUF) - 1);
#endif
/* note we can't #define PIPE_BUF, because it depends
on the "fd" variable */
## Bad File Descriptor
If you get Bad File Descriptor error when trying to read from a file (or accessing it at all), check the `open()` invocation. The second argument is the access method. If it is a hard coded number instead of a symbol defined in the standard header files, the code is screwed and should be fixed to either use `O_RDONLY`, `O_WRONLY` or `O_RDWR`. This bug was observed in the `fortunes` and `mtools` packages for example.
## `PATH_MAX` / `MAX_PATH` / `MAXPATHLEN`
Every unconditionalized use of `PATH_MAX`, `MAX_PATH` or `MAXPATHLEN` is a POSIX incompatibility. If there is no upper limit on the length of a path (as its the case for GNU), this symbol is not defined in any header file. Instead, you need to either use a different implementation that does not rely on the length of a string or use `sysconf()` to query the length at runtime. If `sysconf()` returns -1, you have to use `realloc()` to allocate the needed memory dynamically.
## `MAXHOSTNAMELEN`
Same as `PATH_MAX`. When you find a `gethostname()` function, which acts on a static buffer, you can replace it with Neal's [xgethostname function](http://ftp.walfield.org/pub/people/neal/xgethostname/) which returns the hostname as a dynamic buffer. For example:
Buggy code:
char localhost[MAXHOSTNAMELEN];
...
gethostname(localhost, sizeof(localhost));
Fixed code:
#ifndef MAXHOSTNAMELEN
#include "xgethostname.h"
#endif
...
#ifdef MAXHOSTNAMELEN
char localhost[MAXHOSTNAMELEN];
#else
char *localhost;
#endif
...
#ifdef MAXHOSTNAMELEN
gethostname(localhost, sizeof(localhost));
#else
localhost = xgethostname();
#endif
## `NOFILE`
Replace with `RLIMIT_NOFILE`
## GNU specific `#define`
If you need to include specific code for GNU/Hurd using `#if` ... `#endif`, then you can use the `__GNU__` symbol to do so. But think (at least) thrice! before doing so. In most situations, this is completely unnecessary and will create more problems than it may solve. Better ask on the mailing list how to do it right if you can't think of a better solution.
## `sys_errlist[]` vs. `strerror()`
If a program has only support for `sys_errlist[]` you will have to do some work to make it compile on GNU, which has dropped support for it and does only provide `strerror()`. Steinar Hamre writes about `strerror()`:
`strerror()` should be used because:
* It is the modern, POSIX way.
* It is localized.
* It handles invalid signals/numbers out of range. (better errorhandling and not a buffer-overflow-candidate/security risk)
`strerror()` should always be used if it is available. Unfortunaly there are still some old non-POSIX systems that do not have `strerror()`, only `sys_errlist[]`.
Today, only supporting `strerror()` is far better than only supporting `sys_errlist[]`. The best (from a portability viewpoint), however is supporting both. For configure.in, you will need:
AC_CHECK_FUNCS(strerror)
To `config.h.in`, you need to add:
#undef HAVE_STRERROR
Then something like:
#ifndef HAVE_STRERROR
static char *
private_strerror (errnum)
int errnum;
{
extern char *sys_errlist[];
extern int sys_nerr;
if (errnum > 0 && errnum <= sys_nerr)
return sys_errlist[errnum];
return "Unknown system error";
}
#define strerror private_strerror
#endif /* HAVE_STRERROR */
You can for example look in the latest coreutils (the above is a simplified version of what I found there.) Patches should of course be sent to upstream maintainers, this is very useful even for systems with a working `sys_errlist[]`.
Of course, if you don't care about broken systems (like MS-DOG) not supporting `strerror()` you can just replace `sys_errlist[]` directly (upstream might not accept your patch, but debian should have no problem)
## Filenames ending in a slash \`/'
Those are evil if they don't exist and you want to name a directory this way. For example, `mkdir foobar/` will not work on GNU. This is POSIX compatible. POSIX says that the path of a directory may have slashes appended to it. But the directory does not exist yet, so the path does not refer to a directory, and hence trailing slashes are not guaranteed to work. Just drop the slashes, and you're fine.
## Missing `termio.h`
Change it to use `termios.h` (check for it properly with autoconf `HAVE_TERMIOS_H` or the `__GLIBC__` macro)
## `AC_HEADER_TERMIO`
The autoconf check for `AC_HEADER_TERMIO` tryes to check for termios, but it's only really checking for termio in `termios.h`. It is better to use `AC_CHECK_HEADERS(termio.h termios.h)`
## broken libc6 dependency
Some packages use an erroneous dependency on `libc6-dev`. This is incorrect because `libc6` is specific to GNU/Linux. The corresponding package for GNU is `libc0.3-dev` but other OSes will have different ones. You can locate the problem in the `debian/control` file of the source tree. Typical solutions include detecting the OS using `dpkg-architecture` and hardcoding the soname, or better, use a logical OR. eg: `libc6-dev | libc0.3-dev | libc-dev`. The `libc-dev` is a virtual package that works for any soname but you have to put it only as the last option.
## Third argument in `ioctl` (`TIOCFLUSH`, etc)
Broken arguments for `ioctl`'s which might work on other systems will cause segfault on GNU, because they are passed to and from a Hurd server RPC.
For example, `TIOCFLUSH` wants an `(int *)`, but will run on GNU/Linux if you pass it a 0. The solution in this case is to declare and assign an `int`, eg:
int out = 0;
and pass its address to `ioctl`:
ioctl (fd, TIOCFLUSH, &out);
See [a simple fix for TIOCFLUSH in telnet](http://mail.gnu.org/archive/html/bug-inetutils/2001-08/msg00015.html).
## Uncompliant use of `sockaddr_un`
The following declaration:
sockaddr_un sun = { AF_UNIX, "/path/to/socket" };
won't work on GNU/Hurd. The Glibc API requires that the second parameter of a `sockaddr_un` struct is array of chars, but NOT pointer to array of chars. So we have to copy them directly into the `sun_path` address. Glibc wants string of chars there that doesn't need to end in NUL character _and_ correct size of `sockaddr_un` passed to socket functions. When calling socket functions one should always use `SUN_LEN (su)` for the sockaddr length argument.
When you use _literal string_ as value for `sun_path` and you are absolutely sure its length is less than 100, _and only then_, use the following code:
struct sockaddr_un sun;
sun.sun_family = AF_LOCAL;
strcpy (sun.sun_path, "/path/to/socket");
/* ... bind (sock, (struct sockaddr *)&sun, SUN_LEN (&sun)) ... */
When one of the conditions for using the above code is not satisfied, you should use the following code. It expects glibc environment. You can check this by the presence of the `__GLIBC__` macro definition.
struct sockaddr_un *sun =
alloca (offsetof (struct sockaddr_un, sun_path) + strlen (filename) + 1);
sun->sun_family = AF_LOCAL;
strcpy (sun->sun_path, filename);
/* ... bind (sock, (struct sockaddr *)sun, SUN_LEN (sun)) ... */
NOTE: the current API is subject to change, see the notes in Glibc's docs ("info libc" and search for `sockaddr_un`) and [Debian bug #187391](http://bugs.debian.org/187391).
----
## ChangeLog
-- [[Main/RobertMillan]] - 22 Jul 2002
Formatting and minor grammatical fixes.
-- [[Main/JoachimNilsson]] - 09 Sep 2002
Added more examples and misc semantical fixes.
-- [[Main/RobertMillan]] - 05 Oct 2002
Added `xgethostname` example.
-- [[Main/RobertMillan]] - 15 Nov 2002
Added broken libc6 dependency
-- [[Main/RobertMillan]] - 21 Nov 2002
Text formatting.
-- Ognyan Kulev - 12 Mar 2003
Added `ioctl` entry.
-- [[Main/RobertMillan]] - 19 Mar 2003
Added `sockaddr_un` entry.
-- [[Main/RobertMillan]] - 05 Apr 2003
-- [[Main/OgnyanKulev]] - 19 Apr 2003