HsUnix.c 2.83 KB
Newer Older
1
2
3
4
5
6
7
8
9
/* -----------------------------------------------------------------------------
 *
 * (c) The University of Glasgow 2002
 *
 * Definitions for package `unix' which are visible in Haskell land.
 *
 * ---------------------------------------------------------------------------*/

#include "HsUnix.h"
10

11
#ifdef HAVE_RTLDNEXT
12
void *__hsunix_rtldNext (void) {return RTLD_NEXT;}
13
14
15
#endif

#ifdef HAVE_RTLDDEFAULT
16
void *__hsunix_rtldDefault (void) {return RTLD_DEFAULT;}
17
18
#endif

19
#if HAVE_PTSNAME && (__GLASGOW_HASKELL__ < 800)
20
21
22
// On Linux (and others), <stdlib.h> needs to be included while
// `_XOPEN_SOURCE` is already defined. However, GHCs before GHC 8.0
// didn't do that yet for CApiFFI, so we need this workaround here.
23

24
25
26
char *__hsunix_ptsname(int fd)   { return ptsname(fd);  }
int   __hsunix_grantpt(int fd)   { return grantpt(fd);  }
int   __hsunix_unlockpt(int fd)  { return unlockpt(fd); }
27
28
29
30
31
#endif

// push a SVR4 STREAMS module; do nothing if STREAMS not available
int __hsunix_push_module(int fd, const char *module)
{
32
#if defined(I_PUSH) && !defined(HAVE_DEV_PTC)
33
34
35
36
37
38
    return ioctl(fd, I_PUSH, module);
#else
    return 0;
#endif
}

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/*
 * GNU glibc 2.23 and later deprecate `readdir_r` in favour of plain old
 * `readdir` which in some upcoming POSIX standard is going to required to be
 * re-entrant.
 * Eventually we want to drop `readder_r` all together, but want to be
 * compatible with older unixen which may not have a re-entrant `readdir`.
 * Solution is to make systems with *known* re-entrant `readir` use that and use
 * `readdir_r` whereever we have it and don't *know* that `readdir` is
 * re-entrant.
 */

#if defined (__GLIBC__) && (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 23)
#define USE_READDIR_R 0
#else
#define USE_READDIR_R 1
#endif

56
57
58
59
60
61
/*
 * read an entry from the directory stream; opt for the
 * re-entrant friendly way of doing this, if available.
 */
int __hscore_readdir( DIR *dirPtr, struct dirent **pDirEnt )
{
62
#if HAVE_READDIR_R && USE_READDIR_R
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
  struct dirent* p;
  int res;
  static unsigned int nm_max = (unsigned int)-1;

  if (pDirEnt == NULL) {
    return -1;
  }
  if (nm_max == (unsigned int)-1) {
#ifdef NAME_MAX
    nm_max = NAME_MAX + 1;
#else
    nm_max = pathconf(".", _PC_NAME_MAX);
    if (nm_max == -1) { nm_max = 255; }
    nm_max++;
#endif
  }
  p = (struct dirent*)malloc(sizeof(struct dirent) + nm_max);
  if (p == NULL) return -1;
  res = readdir_r(dirPtr, p, pDirEnt);
  if (res != 0) {
      *pDirEnt = NULL;
      free(p);
  }
  else if (*pDirEnt == NULL) {
    // end of stream
    free(p);
  }
  return res;
#else

  if (pDirEnt == NULL) {
    return -1;
  }

  *pDirEnt = readdir(dirPtr);
  if (*pDirEnt == NULL) {
    return -1;
  } else {
    return 0;
  }
#endif
}

char *__hscore_d_name( struct dirent* d )
{
  return (d->d_name);
}

void __hscore_free_dirent(struct dirent *dEnt)
{
113
#if HAVE_READDIR_R && USE_READDIR_R
114
115
116
  free(dEnt);
#endif
}