🙃The world is full of pain, but we can fix it with love!

Libc/POSIX Function "Extensions"


| 272 words

Recently, I’ve been working on porting some libraries to GNU/Hurd. Many (old) libraries use *_MAX constants on POSIX system interfaces to calculate buffer sizes. However, the GNU/Hurd maintainers urge against the blind use of them and refuse to define them in system headers. When old APIs are gone, compatibility problems come. To make my life easier, I’ll put some reusable code snippets here to help fix *_MAX bugs.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>

static inline char *xreadlink(const char *restrict path) {
  char *buffer;
  size_t allocated = 128;
  ssize_t len;

  while (1) {
    buffer = (char *)malloc(allocated);
    if (!buffer) {
      return NULL;
    }
    len = readlink(path, buffer, allocated);
    if (len < (ssize_t)allocated) {
      return buffer;
    }
    free(buffer);
    if (len >= (ssize_t)allocated) {
      allocated *= 2;
      continue;
    }
    return NULL;
  }
}

static inline char *xgethostname() {
  long max_host_name;
  char *buffer;

  max_host_name = sysconf(_SC_HOST_NAME_MAX);
  buffer = malloc(max_host_name + 1);

  if (gethostname(buffer, max_host_name + 1)) {
    free(buffer);
    return NULL;
  }

  buffer[max_host_name] = '\0';
  return buffer;
}

static inline char *xgetcwd() {
  char *buffer;
  size_t allocated = 128;

  while (1) {
    buffer = (char *)malloc(allocated);
    if (!buffer) {
      return NULL;
    }
    getcwd(buffer, allocated);
    if (buffer)
      return buffer;
    free(buffer);
    if (errno == ERANGE) {
      allocated *= 2;
      continue;
    }
    return NULL;
  }
}