This is a compilation of common porting problems and their solutions.

Additionally to this page, also see the section General Porting Issues of http://www.debian.org/ports/hurd/hurd-devel-debian, as well as further Debian-specific porting information.

There is a separate page about System API Limitations.

You may ask on the bug-hurd mailing list for details or questions about fixing bugs.

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. Usually it is thus simpler to just use dynamic allocation. Sometimes the amount is actually known. Else, a geometrically growing loop can be used: for instance, see Alioth patch or Pulseaudio patch. Note that in some cases there are GNU extensions that just work fine: when the __GLIBC__ macro is defined, getcwd() calls can be just replaced by get_current_dir_name() calls.

ARG_MAX

Same rationale as PATH_MAX. There is no limit on the number of arguments.

IOV_MAX

Same rationale as PATH_MAX. There is no limit on the number of iovec items.

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 which returns the hostname as a dynamic buffer. For example:

Buggy code:

char localhost[MAXHOSTNAMELEN];
...
gethostname(localhost, sizeof(localhost));

Fixed code:

#include "xgethostname.h"
...
char *localhost;
...
localhost = xgethostname();
if (! localhost)
  {
    perror ("xgethostname");
    return ERROR;
  }
...
/* use LOCALHOST.  */
free (localhost);

NOFILE

Replace with getrlimit(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:

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)

C++, error_t and E*

On the Hurd, error_t is an enumeration of the E* constants. However, C++ does not like E* integer macros being directly assigned to that enumeration. In short, replace

    error_t err = EINTR;

by

    error_t err = error_t(EINTR);

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)

Also, change calls to ioctl(fd, TCGETS, ...) and ioctl(fd, TCSETS, ...) with tcgetattr(fd, ...) and tcsetattr(fd, ...).

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)

missing _IOT

This comes from ioctls. Fixing this is easy if the structure members can be expressed by using the _IOT() macro, else it's simply impossible... See bits/termios.h for an instance:

#define _IOT_termios /* Hurd ioctl type field. */ \ _IOT (_IOTS (tcflag_t), 4, _IOTS (cc_t), NCCS, _IOTS (speed_t), 2)

The rationale behind is that on the Hurd ioctl numbers actually encode how the data should be transferred via RPC: here struct termios holds 4 members of type tcflag_ts, then NCCS members of type cc_tsi and finaly 2 members of type speed_ts, so the RPC mecanism will know how to transfer them.

As you can see, this limits the number of contiguous kinds of members to 3, and in addition to that (see the bitfield described in ioctls.h), the third kind of member is limited to 3 members. This is a design limitation, there is no way to overcome it at the moment.

Note: if a field member is a pointer, then the ioctl can't be expressed this way, and that makes sense, since the server you're talking to doesn't have direct access to your memory. Ways other than ioctls must then be found.

SA_SIGINFO

Not implemented, packages may be fixed for working around this: use void sighandler(int num) prototype and sa_handler field.

SOL_IP

Not implemented yet.

HZ

Linuxish and doesn't even make sense since the value may vary according to the running kernel. Should use sysconf(_SC_CLK_TCK) or CLK_TCK instead.

SIOCDEVPRIVATE

Oh, we should probably provide it.

MAP_NORESERVE

Not POSIX, but we could implement it.

O_DIRECT

Long story to implement.

PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP

We could easily provide it;

PTHREAD_STACK_MIN

We should actually provide it.

linux/types.h or asm/types.h

These are not POSIX, sys/types.h and stdint.h should be used instead.

iopl

Not supported. Try to replace with ioperm(0, 65536, 1) (conditionned with __GNU__ as that will not work in Linux).

semget, sem_open

Not implemented, will always fail. Use sem_init() instead if possible.

net/if_arp.h, net/ethernet.h, etc.

Not implemented, not POSIX. Try to disable the feature in the package.

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.