m3core/src/unix/Common/UnixC.c
/* Copyright (C) 1993, Digital Equipment Corporation */
/* All rights reserved. */
/* See the file COPYRIGHT for a full description. */
/*
On some platforms, such as 32bit Linux and 32bit Solaris,
various functions are defined to have 32bit limits by default.
unless #define _FILE_OFFSET_BITS 64, which only affects C source.
Usually they are also available with the name ending in "64" as well.
open => open64
stat => stat64
etc.
It might take a #define to expose those names to C.
(Just to help motivate why there are so many #defines.)
Therefore, saying, e.g.
<*EXTERNAL*> PROCEDURE ftruncate (fd: int; length: off_t): int;
is wrong, unless you constrain off_t to 32 bits, which is not good.
It would be correct to say:
<*EXTERNAL ftruncate64*> PROCEDURE ftruncate (fd: int; length: off_t): int;
However that is not portable.
So use these wrappers instead.
*/
#include "m3core.h"
#ifdef _WIN32
#include <windows.h>
#endif
#define M3MODULE Unix
#ifdef __cplusplus
extern "C"
{
#endif
M3_DLL_LOCAL void __cdecl
Unix__Assertions(void)
{
/* make sure things are normal */
M3_STATIC_ASSERT(CHAR_BIT == 8);
M3_STATIC_ASSERT(sizeof(short) == 2);
M3_STATIC_ASSERT(sizeof(int) == 4);
M3_STATIC_ASSERT((sizeof(long) == 4) || (sizeof(long) == 8));
M3_STATIC_ASSERT((sizeof(void*) == 4) || (sizeof(void*) == 8));
M3_STATIC_ASSERT((sizeof(size_t) == 4) || (sizeof(size_t) == 8));
M3_STATIC_ASSERT(sizeof(ptrdiff_t) == sizeof(size_t));
M3_STATIC_ASSERT(sizeof(void*) == sizeof(WORD_T));
#if !defined(_WIN64) && !defined(__vms)
M3_STATIC_ASSERT(sizeof(void*) == sizeof(long));
M3_STATIC_ASSERT(sizeof(size_t) == sizeof(long));
#endif
#if defined(_MSC_VER) || defined(__DECC)
M3_STATIC_ASSERT(sizeof(__int64) == 8);
#else
M3_STATIC_ASSERT(sizeof(long long) == 8);
#endif
#ifndef _WIN32
/* make sure all the Modula-3 types are large enough */
#define CHECK_M3_TYPE_SIZE(x) M3_STATIC_ASSERT(sizeof(m3_##x) >= sizeof(x))
#define IS_TYPE_SIGNED(x) (((x)-1) < (x)0)
CHECK_M3_TYPE_SIZE(dev_t);
CHECK_M3_TYPE_SIZE(gid_t);
CHECK_M3_TYPE_SIZE(ino_t);
CHECK_M3_TYPE_SIZE(mode_t);
CHECK_M3_TYPE_SIZE(nlink_t);
CHECK_M3_TYPE_SIZE(off_t);
CHECK_M3_TYPE_SIZE(pid_t);
CHECK_M3_TYPE_SIZE(pthread_t);
CHECK_M3_TYPE_SIZE(uid_t);
M3_STATIC_ASSERT(IS_TYPE_SIGNED(pid_t));
#endif
Usocket__Assertions();
}
M3WRAP3_(int, open, const char*, int, m3_mode_t)
M3WRAP1_(m3_mode_t, umask, m3_mode_t)
M3WRAP2_(int, chmod, const char*, m3_mode_t)
M3WRAP2_(int, creat, const char*, m3_mode_t)
M3WRAP1_(int, dup, int)
M3WRAP1(int, system, const char*)
M3WRAP1_(int, isatty, int)
M3WRAP2(int, rename, const char*, const char*)
M3WRAP1_(int, rmdir, const char*)
M3WRAP1_(int, unlink, const char*)
M3WRAP2_(int, access, const char*, int)
M3WRAP1_(int, chdir, const char*)
M3WRAP1_(int, close, int)
M3WRAP2_(int, dup2, int, int)
#ifdef __sun
M3WRAP1(m3_off_t, tell, int)
#endif
#ifndef _WIN32
M3WRAP3(int, chown, const char*, m3_uid_t, m3_gid_t)
M3WRAP3(int, fchown, int, m3_uid_t, m3_gid_t)
M3WRAP2(int, truncate, const char*, m3_off_t)
M3WRAP2(int, ftruncate, int, m3_off_t)
M3WRAP3(INTEGER, readlink, const char*, char*, INTEGER)
M3WRAP2(int, symlink, const char*, const char*)
M3WRAP1(int, fsync, int)
M3WRAP0(int, getdtablesize)
M3WRAP0(int, getpagesize)
M3WRAP1(void*, sbrk, INTEGER)
M3WRAP3(int, execve, const char*, char**, char**)
M3WRAP1(unsigned, sleep, unsigned)
M3WRAP3(m3_off_t, lseek, int, m3_off_t, int)
M3WRAP2(int, mkdir, const char*, m3_mode_t)
M3WRAP1(int, pipe, int*)
M3WRAP2(int, gethostname, char*, WORD_T)
M3WRAP2(char*, getcwd, char*, WORD_T)
#ifndef __vms
M3WRAP2(int, fchmod, int, m3_mode_t)
M3WRAP3(int, mknod, const char*, m3_mode_t, m3_dev_t)
#if 0 /* See RTProcess.Fork. */
M3_DLL_EXPORT m3_pid_t __cdecl
Unix__fork(void)
{
#ifdef __sun
/* Prior to Solaris 2.10, fork() was fork1() or forkall() depending
* on which library used. In Solaris 2.10, fork() is always fork1(),
* and a separate forkall() is available. fork1()'s declaration
* does have some #ifdef guards around it; hopefully ok.
*/
return fork1();
#else
return fork();
#endif
}
#endif
#endif /* vms */
#endif /* win32 */
M3_DLL_EXPORT void __cdecl
Unix__underscore_exit(int exit_code)
{
_exit(exit_code);
}
M3_DLL_EXPORT void __cdecl
Unix__exit(int i)
{
exit(i);
}
#ifdef _WIN32
#if 0
M3_DLL_EXPORT char* __cdecl
Unix__getcwd(char* name, WORD_T len)
{
assert(len < INT_MAX);
return _getcwd(name, (int)len);
}
M3_DLL_EXPORT int __cdecl
Unix__gethostname(char* name, WORD_T len)
{
assert(len < INT_MAX);
return gethostname(name, (int)len);
}
#endif
M3_DLL_EXPORT int __cdecl
Unix__mkdir(const char* path, m3_mode_t mode)
{
return _mkdir(path);
}
M3_DLL_EXPORT int __cdecl
Unix__pipe(int* files)
{
return _pipe(files, 0, _O_BINARY);
}
#if _MSC_VER >= 1000
M3_DLL_EXPORT m3_off_t __cdecl
Unix__lseek(int fd, m3_off_t offset, int whence)
{
return _lseeki64(fd, offset, whence);
}
M3_DLL_EXPORT m3_off_t __cdecl
Unix__tell(int fd)
{
return _telli64(fd);
}
#endif
#else
typedef struct m3_flock_t {
/* sorted by size and then name
This must match between Unix.i3 and UnixC.c. */
LONGINT len;
LONGINT start;
INTEGER pid;
INTEGER type;
INTEGER whence;
} m3_flock_t;
M3_DLL_EXPORT int __cdecl
Unix__fcntl(int fd, INTEGER request, void* m3_arg)
/* fcntl is actually fcntl(fd, request, ...).
* Wrapper is needed on some systems to handle varargs.
* See https://edoofus.blogspot.com/2008/08/interesting-bug-unbreaking-cvsupamd64.html.
*/
{
/* Errno preservation for success:
* work around a bug in the Solaris-2 'libsocket' library
* which redefines 'fcntl' in such a way as to zero out 'errno' if the
* call is successful.
* See m3-libs/m3core/src/unix/solaris-2-x/Unix.m3.
*/
int e = errno;
struct flock native_lock = { 0 };
m3_flock_t* m3_lock = { 0 };
void* native_arg = m3_arg;
int r = { 0 };
memset(&native_lock, 0, sizeof(native_lock));
if (m3_arg)
{
switch (request)
{
case F_GETLK: case F_SETLK: case F_SETLKW:
m3_lock = (m3_flock_t*)m3_arg;
native_lock.l_len = m3_lock->len;
native_lock.l_pid = m3_lock->pid;
native_lock.l_start = m3_lock->start;
native_lock.l_type = m3_lock->type;
native_lock.l_whence = m3_lock->whence;
native_arg = &native_lock;
break;
}
}
r = fcntl(fd, request, native_arg);
if (r == 0)
errno = e;
if (m3_lock)
{
m3_lock->len = native_lock.l_len;
m3_lock->pid = native_lock.l_pid;
m3_lock->start = native_lock.l_start;
m3_lock->type = native_lock.l_type;
m3_lock->whence = native_lock.l_whence;
}
return r;
}
M3_DLL_EXPORT int __cdecl
Unix__ioctl(int fd, INTEGER request, void* argp)
/* ioctl is varargs. See fcntl. */
{
/* Errno preservation for success:
* Work around a bug in the Solaris-2 'libsocket' library
* which redefines 'ioctl' in such a way as to zero out 'errno' if the
* call is successful.
* See m3-libs/m3core/src/unix/solaris-2-x/Unix.m3.
*/
int e = errno;
int r = ioctl(fd, request, argp);
if (r == 0)
errno = e;
return r;
}
#endif
#ifdef __cplusplus
} /* extern C */
#endif