#ifndef K5_PLATFORM_H
#define K5_PLATFORM_H
#include "autoconf.h"
#include <string.h>
#include <stdarg.h>
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#ifdef _WIN32
#define CAN_COPY_VA_LIST
#endif
#if defined(macintosh) || (defined(__MACH__) && defined(__APPLE__))
#include <TargetConditionals.h>
#endif
# define JOIN__2_2(A,B) A ## _ ## _ ## B
# define JOIN__2(A,B) JOIN__2_2(A,B)
#if defined(DELAY_INITIALIZER)
# include "k5-thread.h"
typedef struct { k5_once_t once; int error, did_run; void (*fn)(void); } k5_init_t;
# ifdef USE_LINKER_INIT_OPTION
# define MAYBE_DUMMY_INIT(NAME) \
void JOIN__2(NAME, auxinit) () { }
# else
# define MAYBE_DUMMY_INIT(NAME)
# endif
# ifdef __GNUC__
# define k5_call_init_function(I) \
(__extension__ ({ \
k5_init_t *k5int_i = (I); \
int k5int_err = k5_once(&k5int_i->once, k5int_i->fn); \
(k5int_err \
? k5int_err \
: (assert(k5int_i->did_run != 0), k5int_i->error)); \
}))
# define MAYBE_DEFINE_CALLINIT_FUNCTION
# else
# define MAYBE_DEFINE_CALLINIT_FUNCTION \
static inline int k5_call_init_function(k5_init_t *i) \
{ \
int err; \
err = k5_once(&i->once, i->fn); \
if (err) \
return err; \
assert (i->did_run != 0); \
return i->error; \
}
# endif
# define MAKE_INIT_FUNCTION(NAME) \
static int NAME(void); \
MAYBE_DUMMY_INIT(NAME) \
\
static void JOIN__2(NAME, aux) (void); \
static k5_init_t JOIN__2(NAME, once) = \
{ K5_ONCE_INIT, 0, 0, JOIN__2(NAME, aux) }; \
MAYBE_DEFINE_CALLINIT_FUNCTION \
static void JOIN__2(NAME, aux) (void) \
{ \
JOIN__2(NAME, once).did_run = 1; \
JOIN__2(NAME, once).error = NAME(); \
} \
\
static int NAME(void)
# define CALL_INIT_FUNCTION(NAME) \
k5_call_init_function(& JOIN__2(NAME, once))
# define INITIALIZER_RAN(NAME) \
(JOIN__2(NAME, once).did_run && JOIN__2(NAME, once).error == 0)
# define PROGRAM_EXITING() (0)
#elif defined(__GNUC__) && !defined(_WIN32) && defined(CONSTRUCTOR_ATTR_WORKS)
# ifdef USE_LINKER_INIT_OPTION
# define MAYBE_DUMMY_INIT(NAME) \
void JOIN__2(NAME, auxinit) () { }
# else
# define MAYBE_DUMMY_INIT(NAME)
# endif
typedef struct { int error; unsigned char did_run; } k5_init_t;
# define MAKE_INIT_FUNCTION(NAME) \
MAYBE_DUMMY_INIT(NAME) \
static k5_init_t JOIN__2(NAME, ran) \
= { 0, 2 }; \
static void JOIN__2(NAME, aux)(void) \
__attribute__((constructor)); \
static int NAME(void); \
static void JOIN__2(NAME, aux)(void) \
{ \
JOIN__2(NAME, ran).error = NAME(); \
JOIN__2(NAME, ran).did_run = 3; \
} \
static int NAME(void)
# define CALL_INIT_FUNCTION(NAME) \
(JOIN__2(NAME, ran).did_run == 3 \
? JOIN__2(NAME, ran).error \
: (abort(),0))
# define INITIALIZER_RAN(NAME) (JOIN__2(NAME,ran).did_run == 3 && JOIN__2(NAME, ran).error == 0)
# define PROGRAM_EXITING() (0)
#elif defined(USE_LINKER_INIT_OPTION) || defined(_WIN32)
typedef struct { int error; unsigned char did_run; } k5_init_t;
# define MAKE_INIT_FUNCTION(NAME) \
static k5_init_t JOIN__2(NAME, ran) \
= { 0, 2 }; \
static int NAME(void); \
void JOIN__2(NAME, auxinit)() \
{ \
JOIN__2(NAME, ran).error = NAME(); \
JOIN__2(NAME, ran).did_run = 3; \
} \
static int NAME(void)
# define CALL_INIT_FUNCTION(NAME) \
(JOIN__2(NAME, ran).did_run == 3 \
? JOIN__2(NAME, ran).error \
: (abort(),0))
# define INITIALIZER_RAN(NAME) \
(JOIN__2(NAME, ran).error == 0)
# define PROGRAM_EXITING() (0)
#else
# error "Don't know how to do load-time initializers for this configuration."
# define PROGRAM_EXITING() (0)
#endif
#if defined(USE_LINKER_FINI_OPTION) || defined(_WIN32)
# ifdef __hpux
# include <dl.h>
# define MAKE_FINI_FUNCTION(NAME) \
static void NAME(void); \
void JOIN__2(NAME, auxfini)(shl_t, int); \
void JOIN__2(NAME, auxfini)(shl_t h, int l) { if (!l) NAME(); } \
static void NAME(void)
# else
# define MAKE_FINI_FUNCTION(NAME) \
void NAME(void)
# endif
#elif defined(__GNUC__) && defined(DESTRUCTOR_ATTR_WORKS)
# define MAKE_FINI_FUNCTION(NAME) \
static void NAME(void) __attribute__((destructor))
#elif !defined(SHARED)
# define MAKE_FINI_FUNCTION(NAME) \
static void NAME(void)
#else
# error "Don't know how to do unload-time finalization for this configuration."
#endif
#if defined(HAVE_STDINT_H) || defined(HAVE_INTTYPES_H)
# ifdef HAVE_STDINT_H
# include <stdint.h>
# endif
# ifdef HAVE_INTTYPES_H
# include <inttypes.h>
# endif
# define INT64_TYPE int64_t
# define UINT64_TYPE uint64_t
#elif defined(_WIN32)
# define INT64_TYPE signed __int64
# define UINT64_TYPE unsigned __int64
#else
# define INT64_TYPE signed long long
# define UINT64_TYPE unsigned long long
#endif
#ifndef SIZE_MAX
# define SIZE_MAX ((size_t)((size_t)0 - 1))
#endif
#ifndef UINT64_MAX
# define UINT64_MAX ((UINT64_TYPE)((UINT64_TYPE)0 - 1))
#endif
#if HAVE_ENDIAN_H
# include <endian.h>
#elif HAVE_MACHINE_ENDIAN_H
# include <machine/endian.h>
#endif
#if defined(BIG_ENDIAN) && defined(LITTLE_ENDIAN)
# if BYTE_ORDER == BIG_ENDIAN
# define K5_BE
# endif
# if BYTE_ORDER == LITTLE_ENDIAN
# define K5_LE
# endif
#elif defined(BIG_ENDIAN)
# define K5_BE
#elif defined(LITTLE_ENDIAN)
# define K5_LE
#elif defined(_BIG_ENDIAN) && defined(_LITTLE_ENDIAN)
# if _BYTE_ORDER == _BIG_ENDIAN
# define K5_BE
# endif
# if _BYTE_ORDER == _LITTLE_ENDIAN
# define K5_LE
# endif
#elif defined(_BIG_ENDIAN)
# define K5_BE
#elif defined(_LITTLE_ENDIAN)
# define K5_LE
#endif
#if !defined(K5_BE) && !defined(K5_LE)
# if defined(__i386__) || defined(_MIPSEL) || defined(__alpha__) || defined(__ia64__)
# define K5_LE
# endif
# if defined(__hppa__) || defined(__rs6000__) || defined(__sparc__) || defined(_MIPSEB) || defined(__m68k__) || defined(__sparc64__) || defined(__ppc__) || defined(__ppc64__)
# define K5_BE
# endif
#endif
#if defined(K5_BE) && defined(K5_LE)
# error "oops, check the byte order macros"
#endif
#ifdef __GNUC__
# define PUT(SIZE,PTR,VAL) (((struct { uint##SIZE##_t i; } __attribute__((packed)) *)(PTR))->i = (VAL))
# define GET(SIZE,PTR) (((const struct { uint##SIZE##_t i; } __attribute__((packed)) *)(PTR))->i)
# define PUTSWAPPED(SIZE,PTR,VAL) PUT(SIZE,PTR,SWAP##SIZE(VAL))
# define GETSWAPPED(SIZE,PTR) SWAP##SIZE(GET(SIZE,PTR))
#endif
#if defined(HAVE_BYTESWAP_H) && defined(HAVE_BSWAP_16)
# include <byteswap.h>
# define SWAP16 bswap_16
# define SWAP32 bswap_32
# ifdef HAVE_BSWAP_64
# define SWAP64 bswap_64
# endif
#endif
#if TARGET_OS_MAC
# include <architecture/byte_order.h>
# if 0
# define SWAP16 OSSwapInt16
# else
# define SWAP16 k5_swap16
static inline unsigned int k5_swap16 (unsigned int x) {
x &= 0xffff;
return (x >> 8) | ((x & 0xff) << 8);
}
# endif
# define SWAP32 OSSwapInt32
# define SWAP64 OSSwapInt64
#endif
static inline void
store_16_be (unsigned int val, unsigned char *p)
{
#if defined(__GNUC__) && defined(K5_BE)
PUT(16,p,val);
#elif defined(__GNUC__) && defined(K5_LE) && defined(SWAP16)
PUTSWAPPED(16,p,val);
#else
p[0] = (val >> 8) & 0xff;
p[1] = (val ) & 0xff;
#endif
}
static inline void
store_32_be (unsigned int val, unsigned char *p)
{
#if defined(__GNUC__) && defined(K5_BE)
PUT(32,p,val);
#elif defined(__GNUC__) && defined(K5_LE) && defined(SWAP32)
PUTSWAPPED(32,p,val);
#else
p[0] = (val >> 24) & 0xff;
p[1] = (val >> 16) & 0xff;
p[2] = (val >> 8) & 0xff;
p[3] = (val ) & 0xff;
#endif
}
static inline void
store_64_be (UINT64_TYPE val, unsigned char *p)
{
#if defined(__GNUC__) && defined(K5_BE)
PUT(64,p,val);
#elif defined(__GNUC__) && defined(K5_LE) && defined(SWAP64)
PUTSWAPPED(64,p,val);
#else
p[0] = (unsigned char)((val >> 56) & 0xff);
p[1] = (unsigned char)((val >> 48) & 0xff);
p[2] = (unsigned char)((val >> 40) & 0xff);
p[3] = (unsigned char)((val >> 32) & 0xff);
p[4] = (unsigned char)((val >> 24) & 0xff);
p[5] = (unsigned char)((val >> 16) & 0xff);
p[6] = (unsigned char)((val >> 8) & 0xff);
p[7] = (unsigned char)((val ) & 0xff);
#endif
}
static inline unsigned short
load_16_be (const unsigned char *p)
{
#if defined(__GNUC__) && defined(K5_BE)
return GET(16,p);
#elif defined(__GNUC__) && defined(K5_LE) && defined(SWAP16)
return GETSWAPPED(16,p);
#else
return (p[1] | (p[0] << 8));
#endif
}
static inline unsigned int
load_32_be (const unsigned char *p)
{
#if defined(__GNUC__) && defined(K5_BE)
return GET(32,p);
#elif defined(__GNUC__) && defined(K5_LE) && defined(SWAP32)
return GETSWAPPED(32,p);
#else
return (p[3] | (p[2] << 8)
| ((uint32_t) p[1] << 16)
| ((uint32_t) p[0] << 24));
#endif
}
static inline UINT64_TYPE
load_64_be (const unsigned char *p)
{
#if defined(__GNUC__) && defined(K5_BE)
return GET(64,p);
#elif defined(__GNUC__) && defined(K5_LE) && defined(SWAP64)
return GETSWAPPED(64,p);
#else
return ((UINT64_TYPE)load_32_be(p) << 32) | load_32_be(p+4);
#endif
}
static inline void
store_16_le (unsigned int val, unsigned char *p)
{
#if defined(__GNUC__) && defined(K5_LE)
PUT(16,p,val);
#elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP16)
PUTSWAPPED(16,p,val);
#else
p[1] = (val >> 8) & 0xff;
p[0] = (val ) & 0xff;
#endif
}
static inline void
store_32_le (unsigned int val, unsigned char *p)
{
#if defined(__GNUC__) && defined(K5_LE)
PUT(32,p,val);
#elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP32)
PUTSWAPPED(32,p,val);
#else
p[3] = (val >> 24) & 0xff;
p[2] = (val >> 16) & 0xff;
p[1] = (val >> 8) & 0xff;
p[0] = (val ) & 0xff;
#endif
}
static inline void
store_64_le (UINT64_TYPE val, unsigned char *p)
{
#if defined(__GNUC__) && defined(K5_LE)
PUT(64,p,val);
#elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP64)
PUTSWAPPED(64,p,val);
#else
p[7] = (unsigned char)((val >> 56) & 0xff);
p[6] = (unsigned char)((val >> 48) & 0xff);
p[5] = (unsigned char)((val >> 40) & 0xff);
p[4] = (unsigned char)((val >> 32) & 0xff);
p[3] = (unsigned char)((val >> 24) & 0xff);
p[2] = (unsigned char)((val >> 16) & 0xff);
p[1] = (unsigned char)((val >> 8) & 0xff);
p[0] = (unsigned char)((val ) & 0xff);
#endif
}
static inline unsigned short
load_16_le (const unsigned char *p)
{
#if defined(__GNUC__) && defined(K5_LE)
return GET(16,p);
#elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP16)
return GETSWAPPED(16,p);
#else
return (p[0] | (p[1] << 8));
#endif
}
static inline unsigned int
load_32_le (const unsigned char *p)
{
#if defined(__GNUC__) && defined(K5_LE)
return GET(32,p);
#elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP32)
return GETSWAPPED(32,p);
#else
return (p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24));
#endif
}
static inline UINT64_TYPE
load_64_le (const unsigned char *p)
{
#if defined(__GNUC__) && defined(K5_LE)
return GET(64,p);
#elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP64)
return GETSWAPPED(64,p);
#else
return ((UINT64_TYPE)load_32_le(p+4) << 32) | load_32_le(p);
#endif
}
static inline unsigned short
load_16_n (const unsigned char *p)
{
#ifdef _WIN32
unsigned __int16 n;
#else
uint16_t n;
#endif
memcpy(&n, p, 2);
return n;
}
static inline unsigned int
load_32_n (const unsigned char *p)
{
#ifdef _WIN32
unsigned __int32 n;
#else
uint32_t n;
#endif
memcpy(&n, p, 4);
return n;
}
static inline UINT64_TYPE
load_64_n (const unsigned char *p)
{
UINT64_TYPE n;
memcpy(&n, p, 8);
return n;
}
static inline UINT64_TYPE
k5_htonll (UINT64_TYPE val)
{
#ifdef K5_BE
return val;
#elif defined K5_LE && defined SWAP64
return SWAP64 (val);
#else
return load_64_be ((unsigned char *)&val);
#endif
}
static inline UINT64_TYPE
k5_ntohll (UINT64_TYPE val)
{
return k5_htonll (val);
}
#ifdef HAVE_GETPWNAM_R
# ifndef GETPWNAM_R_4_ARGS
# define k5_getpwnam_r(NAME, REC, BUF, BUFSIZE, OUT) \
(getpwnam_r(NAME,REC,BUF,BUFSIZE,OUT) == 0 \
? (*(OUT) == NULL ? -1 : 0) : -1)
# else
# ifdef GETPWNAM_R_RETURNS_INT
# define k5_getpwnam_r(NAME, REC, BUF, BUFSIZE, OUT) \
(getpwnam_r(NAME,REC,BUF,BUFSIZE) == 0 \
? (*(OUT) = REC, 0) \
: (*(OUT) = NULL, -1))
# else
# define k5_getpwnam_r(NAME, REC, BUF, BUFSIZE, OUT) \
(*(OUT) = getpwnam_r(NAME,REC,BUF,BUFSIZE), *(OUT) == NULL ? -1 : 0)
# endif
# endif
#else
# define k5_getpwnam_r(NAME, REC, BUF, BUFSIZE, OUT) \
(*(OUT) = getpwnam(NAME), *(OUT) == NULL ? -1 : 0)
#endif
#ifdef HAVE_GETPWUID_R
# ifndef GETPWUID_R_4_ARGS
# define k5_getpwuid_r(UID, REC, BUF, BUFSIZE, OUT) \
(getpwuid_r(UID,REC,BUF,BUFSIZE,OUT) == 0 \
? (*(OUT) == NULL ? -1 : 0) : -1)
# else
# ifdef GETPWNAM_R_RETURNS_INT
# define k5_getpwuid_r(UID, REC, BUF, BUFSIZE, OUT) \
(getpwuid_r(UID,REC,BUF,BUFSIZE) == 0 \
? (*(OUT) = REC, 0) \
: (*(OUT) = NULL, -1))
# else
# define k5_getpwuid_r(UID, REC, BUF, BUFSIZE, OUT) \
(*(OUT) = getpwuid_r(UID,REC,BUF,BUFSIZE), *(OUT) == NULL ? -1 : 0)
# endif
# endif
#else
# define k5_getpwuid_r(UID, REC, BUF, BUFSIZE, OUT) \
(*(OUT) = getpwuid(UID), *(OUT) == NULL ? -1 : 0)
#endif
#if 0
static inline int
set_cloexec_fd(int fd)
{
#if defined(F_SETFD)
# ifdef FD_CLOEXEC
if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0)
return errno;
# else
if (fcntl(fd, F_SETFD, 1) != 0)
return errno;
# endif
#endif
return 0;
}
static inline int
set_cloexec_file(FILE *f)
{
return set_cloexec_fd(fileno(f));
}
#else
#ifdef F_SETFD
# ifdef FD_CLOEXEC
# define set_cloexec_fd(FD) (fcntl((FD), F_SETFD, FD_CLOEXEC) ? errno : 0)
# else
# define set_cloexec_fd(FD) (fcntl((FD), F_SETFD, 1) ? errno : 0)
# endif
#else
# define set_cloexec_fd(FD) ((FD),0)
#endif
#define set_cloexec_file(F) set_cloexec_fd(fileno(F))
#endif
#if defined(HAS_VA_COPY) || defined(va_copy)
#elif defined(CAN_COPY_VA_LIST)
#define va_copy(dest, src) ((dest) = (src))
#else
#define va_copy(dest, src) memcmp(dest, src, sizeof(va_list))
#endif
#ifndef HAVE_STRLCPY
#define strlcpy krb5int_strlcpy
#define strlcat krb5int_strlcat
extern size_t krb5int_strlcpy(char *dst, const char *src, size_t siz);
extern size_t krb5int_strlcat(char *dst, const char *src, size_t siz);
#endif
#ifndef HAVE_VSNPRINTF
#ifdef _WIN32
static inline int
vsnprintf(char *str, size_t size, const char *format, va_list args)
{
va_list args_copy;
int length;
va_copy(args_copy, args);
length = _vscprintf(format, args_copy);
va_end(args_copy);
if (size)
_vsnprintf(str, size, format, args);
return length;
}
static inline int
snprintf(char *str, size_t size, const char *format, ...)
{
va_list args;
int n;
va_start(args, format);
n = vsnprintf(str, size, format, args);
va_end(args);
return n;
}
#else
#error We need an implementation of vsnprintf.
#endif
#endif
#if !defined(__cplusplus) && (__GNUC__ > 2)
extern int krb5int_vasprintf(char **, const char *, va_list)
__attribute__((__format__(__printf__, 2, 0)));
extern int krb5int_asprintf(char **, const char *, ...)
__attribute__((__format__(__printf__, 2, 3)));
#endif
#ifndef HAVE_VASPRINTF
#define vasprintf krb5int_vasprintf
#define asprintf krb5int_asprintf
#elif defined(NEED_VASPRINTF_PROTO)
extern int vasprintf(char **, const char *, va_list)
#if !defined(__cplusplus) && (__GNUC__ > 2)
__attribute__((__format__(__printf__, 2, 0)))
#endif
;
extern int asprintf(char **, const char *, ...)
#if !defined(__cplusplus) && (__GNUC__ > 2)
__attribute__((__format__(__printf__, 2, 3)))
#endif
;
#endif
#define SNPRINTF_OVERFLOW(result, size) \
((unsigned int)(result) >= (size_t)(size))
#ifndef HAVE_MKSTEMP
extern int krb5int_mkstemp(char *);
#define mkstemp krb5int_mkstemp
#endif
#ifndef _
#define _(X) (X)
#endif
#endif