Skip to content

Instantly share code, notes, and snippets.

@vidraj
Created February 1, 2025 10:29
Show Gist options
  • Select an option

  • Save vidraj/2267181fd7d1fef8cdd6f834f5f40716 to your computer and use it in GitHub Desktop.

Select an option

Save vidraj/2267181fd7d1fef8cdd6f834f5f40716 to your computer and use it in GitHub Desktop.
Headers for better C99/POSIX/GNU compatibility of HP-UX 11.11 systems

Headers for better C99/POSIX/GNU compatibility of HP-UX 11.11 systems

I used the header files below to make old HP-UX 11.11 (a.k.a. 11i v1) more compatible with modern software requiring newer POSIX standards and some GNU extensions. They can be used to bootstrap modern GCC starting with HP aCC and some ancient GCC versions.

The files in this gist are to be placed in /usr/local/include. The files sys -- stat.h and sys -- sendfile.h should be placed in /usr/local/include/sys as stat.h and sendfile.h, respectively.

I used them to compile the following software (in alphabetic order, not in the correct dependency order):

  • bash-5.2.0
  • binutils-2.40
  • coreutils-9.2
  • curl-8.1.1
  • gawk-5.2.2
  • gcc-4.0.4
  • gcc-4.9.4
  • gcc-10.4.0
  • gmp-5.0.2
  • isl-0.26
  • libiconv-1.17
  • libtool-2.4.6
  • m4-1.4.19
  • make-4.4.1
  • mpc-1.3.1
  • mpfr-4.2.0
  • ncurses-6.4
  • netcat-1.10
  • openssl-3.1.0
  • pkg-config-0.29.2
  • readline-8.2
  • tar-1.34
  • wget-1.21.4
  • xz-5.2.4

(I might've forgotten something)

The headers were evolving through the process, so their current versions below might not necessarily be valid for compiling the listed versions. I do not remember all the required steps and many of those packages required hacks and patches, which are not provided here. I vaguely recall xz giving me grief and libreadline and bash needing some moderately-complex patching.

The stdlib.h header was commented-out for some reason, so maybe it doesn't actually work or it breaks some packages. Good luck figuring that out. No warranty expressed or implied etc. ofc. :-)

#ifndef FIXED_ASSERT_H_INCLUDED
#define FIXED_ASSERT_H_INCLUDED
#ifdef __GNUC__
/* Use the header w/ fixincludes applied. */
#include_next <assert.h>
#else
#include </usr/include/assert.h>
#endif
#if __STDC_VERSION__ >= 201112L
#define static_assert _Static_assert
#endif
#endif /* FIXED_ASSERT_H_INCLUDED */
#ifndef assert
/* Include assert.h again to work around a bug in wget,
where they undef assert in config.h. */
#ifdef __GNUC__
/* Use the header w/ fixincludes applied. */
#include_next <assert.h>
#else
#include </usr/include/assert.h>
#endif
#endif
#ifndef FIXED_INTTYPES_H_INCLUDED
#define FIXED_INTTYPES_H_INCLUDED
#ifdef __GNUC__
/* Use the header w/ fixincludes applied. */
#include_next <inttypes.h>
#else
#include </usr/include/inttypes.h>
#endif
/* These defines are given in inttypes.h as empty definitions,
* which breaks binutils and potentially other programs. Define
* them properly.
*
* I can't define these in stdint.h, where they would belong
* according to POSIX, because GCC started using its own stdint.h
* somewhere between 4.2 and 4.9. Previously, I could write stdint.h
* that recursively includes inttypes.h and fixes the definition up.
*
* Now my stdint.h is not seen (shadowed by GCC's version), inttypes are
* not included from there and when they get included later, they mess
* up the already-present definition.
*/
#undef INTPTR_MAX
#define INTPTR_MAX LONG_MAX
#undef UINTPTR_MAX
#define UINTPTR_MAX ULONG_MAX
/* These should be defined here, but aren't for some reason. */
/* Hopefully I switch on the correct value here. */
#ifndef __LP64__
#define PRIdPTR PRId32
#define PRIiPTR PRIi32
#define PRIoPTR PRIo32
#define PRIxPTR PRIx32
#define PRIXPTR PRIX32
#define PRIuPTR PRIu32
#define SCNdPTR SCNd32
#define SCNiPTR SCNi32
#define SCNoPTR SCNo32
#define SCNuPTR SCNu32
#define SCNxPTR SCNx32
#else /* __LP64__ */
#define PRIdPTR PRId64
#define PRIiPTR PRIi64
#define PRIoPTR PRIo64
#define PRIxPTR PRIx64
#define PRIXPTR PRIX64
#define PRIuPTR PRIu64
#define SCNdPTR SCNd64
#define SCNiPTR SCNi64
#define SCNoPTR SCNo64
#define SCNuPTR SCNu64
#define SCNxPTR SCNx64
#endif /* __LP64__ */
#endif
#ifndef FIXED_SEMAPHORE_H_INCLUDED
#define FIXED_SEMAPHORE_H_INCLUDED
#ifdef __GNUC__
/* Use the header w/ fixincludes applied. */
#include_next <semaphore.h>
#else
#include </usr/include/semaphore.h>
#endif
#define SEM_FAILED (-1)
#endif
#ifndef FIXED_STDINT_H_INCLUDED
#define FIXED_STDINT_H_INCLUDED
/* HP-UX has the relevant defines in inttypes.h. */
/* Use the header w/ fixincludes applied. */
#include <inttypes.h>
/* INTPTR_MAX and UINTPTR_MAX defines are given in /usr/include/inttypes.h as empty definitions,
* which breaks binutils and potentially other programs. I define
* them properly in local inttypes.h to override the bad definitions ASAP.
*/
/* These ones are not given anywhere, but GNU tar needs them. */
#define PTRDIFF_MAX LONG_MAX
#define UINT_FAST8_MIN UINT_MIN
#define UINT_FAST16_MIN UINT_MIN
#define UINT_FAST32_MIN UINT_MIN
#define UINT_FAST64_MIN UINT64_MIN
#define UINT_FAST8_MAX UINT_MAX
#define UINT_FAST16_MAX UINT_MAX
#define UINT_FAST32_MAX UINT_MAX
#define UINT_FAST64_MAX UINT64_MAX
/* Should be defined here according to POSIX, needed by awk. */
#define SIZE_MAX ULONG_MAX
#endif
/* errno */
#include <errno.h>
/* strchr, strlen, strncmp, memcpy, size_t */
#include <string.h>
/* getenv, putenv, malloc */
#ifdef __GNUC__
/* Use the header w/ fixincludes applied. */
#include_next <stdlib.h>
#else
#include </usr/include/stdlib.h>
#endif
#ifndef FIXED_STDLIB_H_INCLUDED
#define FIXED_STDLIB_H_INCLUDED
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
extern char **environ;
#ifdef __cplusplus
}
#endif /* __cplusplus */
static int __env_name_is_valid(const char *env_name) {
return env_name && env_name[0] != '\0' && !strchr(env_name, '=');
}
static int __hpux_setenv(const char *env_name, const char *env_val, int overwrite) {
if (!__env_name_is_valid(env_name)) {
errno = EINVAL;
return -1;
}
if (!overwrite && getenv(env_name)) {
/* Not overwriting existing value. */
return 0;
}
/* +2 is because of the '=' and '\0'. */
size_t nlen = strlen(env_name);
size_t vlen = strlen(env_val);
size_t nvlen = nlen + vlen + 2;
/* There is a memory leak here -- nobody ever frees this string. */
char *env_name_val = (char*)malloc(nvlen);
if (!env_name_val) {
/* errno is already set by malloc. */
return -1;
}
memcpy(env_name_val, env_name, nlen);
env_name_val[nlen] = '=';
memcpy(env_name_val + nlen + 1, env_val, vlen);
env_name_val[nvlen-1] = '\0';
return putenv(env_name_val);
}
static int __hpux_unsetenv(const char *env_name) {
if (!__env_name_is_valid(env_name)) {
errno = EINVAL;
return -1;
}
/* Go through the environ list and delete the appropriate item by
reassigning the last item to its place. */
size_t nlen = strlen(env_name);
size_t i;
for (i = 0; environ[i] != NULL; i++) {
if (strncmp(env_name, environ[i], nlen) == 0 && environ[i][nlen] == '=') {
/* Move the last item to this place. */
size_t j = i + 1;
while (environ[j]) j++;
/* j is the NULL terminator, the last item is the one before that. */
j--;
if (i == j) {
/* Delete the last item. */
environ[i] = NULL;
} else {
environ[i] = environ[j];
environ[j] = NULL;
}
/* Note: memory leak here, as I don't shrink the environ array. */
break;
}
}
return 0;
}
#define setenv __hpux_setenv
#define unsetenv __hpux_unsetenv
#endif
#ifndef FIXED_SENDFILE_H_INCLUDED
#define FIXED_SENDFILE_H_INCLUDED
#include <sys/socket.h>
static ssize_t _gnulike_sendfile(int out_fd, int in_fd, off_t *offset, size_t count) {
return sendfile(out_fd, in_fd, offset, count, NULL, 0);
}
#define sendfile _gnulike_sendfile
#endif
#ifndef FIXED_STAT_H_INCLUDED
#define FIXED_STAT_H_INCLUDED
#ifdef __GNUC__
/* Use the header w/ fixincludes applied. */
#include_next <sys/stat.h>
#else
#include </usr/include/sys/stat.h>
#endif
int lchmod(const char *path, mode_t mode);
#endif
#ifndef FIXED_UNISTD_H_INCLUDED
#define FIXED_UNISTD_H_INCLUDED
#ifdef __GNUC__
/* Use the header w/ fixincludes applied. */
#include_next <unistd.h>
#else
#include </usr/include/unistd.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment