/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "config.h"
#undef HAVE_CONFIG_H
/* Linux needs the _XOPEN_SOURCE define, but others don't. It needs to be
defined before unistd.h, so we need the above config.h include hack.. */
#ifdef PREAD_WRAPPERS
# define _XOPEN_SOURCE 500 /* Linux */
#endif
#define IN_COMPAT_C
#include "lib.h"
#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
#include <syslog.h>
#include <time.h>
#include <sys/time.h>
#ifndef INADDR_NONE
# define INADDR_NONE INADDR_BROADCAST
#endif
#if !defined (HAVE_STRCASECMP) && !defined (HAVE_STRICMP)
int i_my_strcasecmp(const char *s1, const char *s2)
{
while (*s1 != '\0' && i_toupper(*s1) == i_toupper(*s2)) {
s1++; s2++;
}
return i_toupper(*s1) - i_toupper(*s2);
}
int i_my_strncasecmp(const char *s1, const char *s2, size_t max_chars)
{
while (max_chars > 1 && *s1 != '\0' &&
i_toupper(*s1) == i_toupper(*s2)) {
s1++; s2++; max_chars--;
}
return i_toupper(*s1) - i_toupper(*s2);
}
#endif
#ifndef HAVE_INET_ATON
int i_my_inet_aton(const char *cp, struct in_addr *inp)
{
in_addr_t addr;
addr = inet_addr(cp);
if (addr == INADDR_NONE)
return 0;
inp->s_addr = addr;
return 1;
}
#endif
#ifndef HAVE_VSYSLOG
void i_my_vsyslog(int priority, const char *format, va_list args)
{
T_BEGIN {
syslog(priority, "%s", t_strdup_vprintf(format, args));
} T_END;
}
#endif
#ifndef HAVE_GETPAGESIZE
int i_my_getpagesize(void)
{
#ifdef _SC_PAGESIZE
return sysconf(_SC_PAGESIZE);
#else
# ifdef __GNUC__
# warning Guessing page size to be 4096
# endif
return 4096;
#endif
}
#endif
#ifndef HAVE_WRITEV
ssize_t i_my_writev(int fd, const struct iovec *iov, int iov_len)
{
size_t written;
ssize_t ret;
int i;
written = 0;
for (i = 0; i < iov_len; i++, iov++) {
ret = write(fd, iov->iov_base, iov->iov_len);
if (ret < 0)
return -1;
written += ret;
if ((size_t)ret != iov->iov_len)
break;
}
if (written > SSIZE_T_MAX) {
errno = ERANGE;
return -1;
}
return (ssize_t)written;
}
#endif
#if !defined(HAVE_PREAD) || defined(PREAD_BROKEN)
ssize_t i_my_pread(int fd, void *buf, size_t count, off_t offset)
{
ssize_t ret;
off_t old_offset;
old_offset = lseek(fd, 0, SEEK_CUR);
if (old_offset == -1)
return -1;
if (lseek(fd, offset, SEEK_SET) < 0)
return -1;
ret = read(fd, buf, count);
if (ret < 0)
return -1;
if (lseek(fd, old_offset, SEEK_SET) < 0)
return -1;
return ret;
}
ssize_t i_my_pwrite(int fd, const void *buf, size_t count, off_t offset)
{
ssize_t ret;
off_t old_offset;
old_offset = lseek(fd, 0, SEEK_CUR);
if (old_offset == -1)
return -1;
if (lseek(fd, offset, SEEK_SET) < 0)
return -1;
ret = write(fd, buf, count);
if (ret < 0)
return -1;
if (lseek(fd, old_offset, SEEK_SET) < 0)
return -1;
return ret;
}
#elif defined(PREAD_WRAPPERS)
ssize_t i_my_pread(int fd, void *buf, size_t count, off_t offset)
{
ssize_t ret;
ret = pread(fd, buf, count, offset);
return ret;
}
ssize_t i_my_pwrite(int fd, const void *buf, size_t count, off_t offset)
{
return pwrite(fd, buf, count, offset);
}
#endif
#ifndef HAVE_SETEUID
int i_my_seteuid(uid_t euid)
{
#ifdef HAVE_SETREUID
/* HP-UX at least doesn't have seteuid() but has setreuid() */
return setreuid(-1, euid);
#else
# error Missing seteuid functionality
#endif
}
#endif
#ifndef HAVE_SETEGID
int i_my_setegid(gid_t egid)
{
#ifdef HAVE_SETRESGID
/* HP-UX at least doesn't have setegid() but has setresgid() */
return setresgid(-1, egid, -1);
#else
# error Missing setegid functionality
#endif
}
#endif
#ifndef HAVE_LIBGEN_H
char *i_my_basename(char *path)
{
char *p;
/* note that this isn't POSIX-compliant basename() replacement.
too much trouble without any gain. */
p = strrchr(path, '/');
return p == NULL ? path : p + 1;
}
#endif
#ifdef HAVE_OLD_VSNPRINTF
#undef vsnprintf
int i_my_vsnprintf(char *str, size_t size, const char *format, va_list ap)
{
size_t tmp_size;
char *tmp;
int ret;
/* On overflow HP-UX returns -1, IRIX and Tru64 return size-1. */
ret = vsnprintf(str, size, format, ap);
if (ret >= 0 && (size_t)ret+1 != size)
return ret;
/* see if data stack has enough available space for it */
tmp_size = t_get_bytes_available();
if (tmp_size > size) {
tmp = t_buffer_get(tmp_size);
ret = vsnprintf(tmp, tmp_size, format, ap);
if (ret >= 0 && (size_t)ret+1 != tmp_size) {
if (size > 0) {
memcpy(str, tmp, size-1);
str[size-1] = '\0';
}
return ret;
}
} else {
tmp_size = size;
}
/* try to allocate enough memory to get it to fit. */
do {
tmp_size = nearest_power(tmp_size+1);
tmp = i_malloc(tmp_size);
ret = vsnprintf(tmp, tmp_size, format, ap);
if (ret >= 0 && (size_t)ret+1 != tmp_size) {
if (size > 0) {
memcpy(str, tmp, size-1);
str[size-1] = '\0';
}
i_free(tmp);
return ret;
}
i_free(tmp);
} while (tmp_size < 1024*1024);
i_panic("my_vsnprintf(): Output string too big");
}
#endif
#ifndef HAVE_CLOCK_GETTIME
int i_my_clock_gettime(int clk_id, struct timespec *tp)
{
struct timeval tv;
i_assert(clk_id == CLOCK_REALTIME);
/* fallback to using microseconds */
if (gettimeofday(&tv, NULL) < 0)
return -1;
tp->tv_sec = tv.tv_sec;
tp->tv_nsec = tv.tv_usec * 1000;
return 0;
}
#endif