| /******************************************************************************* |
| * Copyright (c) 2007, 2014 Wind River Systems, Inc. and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * and Eclipse Distribution License v1.0 which accompany this distribution. |
| * The Eclipse Public License is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * and the Eclipse Distribution License is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * You may elect to redistribute this code under either of these licenses. |
| * |
| * Contributors: |
| * Wind River Systems - initial API and implementation |
| * Nokia - Symbian support |
| *******************************************************************************/ |
| |
| /* |
| * Machine and OS dependent definitions. |
| * This module implements host OS abstraction layer that helps make |
| * agent code portable between Linux, Windows, VxWorks and potentially other OSes. |
| */ |
| |
| #include <tcf/config.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <assert.h> |
| #include <errno.h> |
| #include <signal.h> |
| #include <fcntl.h> |
| #include <ctype.h> |
| #include <tcf/framework/mdep-threads.h> |
| #include <tcf/framework/mdep-inet.h> |
| #include <tcf/framework/mdep-fs.h> |
| #include <tcf/framework/errors.h> |
| #include <tcf/framework/myalloc.h> |
| |
| pthread_attr_t pthread_create_attr; |
| int utf8_locale = 0; |
| |
| #if defined(_WIN32) || defined(__CYGWIN__) |
| |
| #ifndef SIO_UDP_CONNRESET |
| #define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12) |
| #endif |
| #ifndef SIO_UDP_NETRESET |
| #define SIO_UDP_NETRESET _WSAIOW(IOC_VENDOR,15) |
| #endif |
| #undef socket |
| int wsa_socket(int af, int type, int protocol) { |
| int res = 0; |
| |
| SetLastError(0); |
| WSASetLastError(0); |
| res = socket(af, type, protocol); |
| if (res < 0) { |
| set_win32_errno(WSAGetLastError()); |
| return -1; |
| } |
| if (type == SOCK_DGRAM && protocol == IPPROTO_UDP) { |
| DWORD dw = 0; |
| BOOL b = FALSE; |
| WSAIoctl(res, SIO_UDP_CONNRESET, &b, sizeof(b), NULL, 0, &dw, NULL, NULL); |
| WSAIoctl(res, SIO_UDP_NETRESET, &b, sizeof(b), NULL, 0, &dw, NULL, NULL); |
| } |
| return res; |
| } |
| |
| #undef connect |
| int wsa_connect(int socket, const struct sockaddr * addr, int addr_size) { |
| int res = 0; |
| SetLastError(0); |
| WSASetLastError(0); |
| res = connect(socket, addr, addr_size); |
| if (res != 0) { |
| set_win32_errno(WSAGetLastError()); |
| return -1; |
| } |
| return 0; |
| } |
| |
| #undef bind |
| int wsa_bind(int socket, const struct sockaddr * addr, int addr_size) { |
| int res = 0; |
| SetLastError(0); |
| WSASetLastError(0); |
| res = bind(socket, addr, addr_size); |
| if (res != 0) { |
| set_win32_errno(WSAGetLastError()); |
| return -1; |
| } |
| return 0; |
| } |
| |
| #undef listen |
| int wsa_listen(int socket, int size) { |
| int res = 0; |
| SetLastError(0); |
| WSASetLastError(0); |
| res = listen(socket, size); |
| if (res != 0) { |
| set_win32_errno(WSAGetLastError()); |
| return -1; |
| } |
| return 0; |
| } |
| |
| #undef recv |
| int wsa_recv(int socket, void * buf, size_t size, int flags) { |
| int res = 0; |
| SetLastError(0); |
| WSASetLastError(0); |
| res = recv(socket, (char *)buf, size, flags); |
| if (res < 0) { |
| set_win32_errno(WSAGetLastError()); |
| return -1; |
| } |
| return res; |
| } |
| |
| #undef recvfrom |
| int wsa_recvfrom(int socket, void * buf, size_t size, int flags, |
| struct sockaddr * addr, socklen_t * addr_size) { |
| int res = 0; |
| SetLastError(0); |
| WSASetLastError(0); |
| res = recvfrom(socket, (char *)buf, size, flags, addr, addr_size); |
| if (res < 0) { |
| set_win32_errno(WSAGetLastError()); |
| return -1; |
| } |
| return res; |
| } |
| |
| #undef send |
| int wsa_send(int socket, const void * buf, size_t size, int flags) { |
| int res = 0; |
| SetLastError(0); |
| WSASetLastError(0); |
| res = send(socket, (char *)buf, size, flags); |
| if (res < 0) { |
| set_win32_errno(WSAGetLastError()); |
| return -1; |
| } |
| return res; |
| } |
| |
| #undef sendto |
| int wsa_sendto(int socket, const void * buf, size_t size, int flags, |
| const struct sockaddr * dest_addr, socklen_t dest_size) { |
| int res = 0; |
| SetLastError(0); |
| WSASetLastError(0); |
| res = sendto(socket, (char *)buf, size, flags, dest_addr, dest_size); |
| if (res < 0) { |
| set_win32_errno(WSAGetLastError()); |
| return -1; |
| } |
| return res; |
| } |
| |
| #undef setsockopt |
| int wsa_setsockopt(int socket, int level, int opt, const char * value, int size) { |
| int res = 0; |
| SetLastError(0); |
| WSASetLastError(0); |
| res = setsockopt(socket, level, opt, value, size); |
| if (res != 0) { |
| set_win32_errno(WSAGetLastError()); |
| return -1; |
| } |
| return 0; |
| } |
| |
| #undef getsockname |
| int wsa_getsockname(int socket, struct sockaddr * name, int * size) { |
| int res = 0; |
| SetLastError(0); |
| WSASetLastError(0); |
| res = getsockname(socket, name, size); |
| if (res != 0) { |
| set_win32_errno(WSAGetLastError()); |
| return -1; |
| } |
| return 0; |
| } |
| |
| #undef select |
| int wsa_select(int nfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds, const struct timeval * timeout) { |
| int res = 0; |
| SetLastError(0); |
| WSASetLastError(0); |
| res = select(nfds, readfds, writefds, exceptfds, (PTIMEVAL)timeout); |
| if (res < 0) { |
| set_win32_errno(WSAGetLastError()); |
| return -1; |
| } |
| return res; |
| } |
| |
| /* inet_ntop()/inet_pton() are not available before Windows Vista */ |
| const char * inet_ntop(int af, const void * src, char * dst, socklen_t size) { |
| char * str = NULL; |
| if (af != AF_INET) { |
| #ifdef EAFNOSUPPORT |
| errno = EAFNOSUPPORT; |
| #else |
| errno = EINVAL; |
| #endif |
| return NULL; |
| } |
| str = inet_ntoa(*(struct in_addr *)src); |
| if ((socklen_t)strlen(str) >= size) { |
| errno = ENOSPC; |
| return NULL; |
| } |
| return strcpy(dst, str); |
| } |
| |
| int inet_pton(int af, const char * src, void * dst) { |
| if (af != AF_INET) { |
| #ifdef EAFNOSUPPORT |
| errno = EAFNOSUPPORT; |
| #else |
| errno = EINVAL; |
| #endif |
| return -1; |
| } |
| if (src == NULL || *src == 0) return 0; |
| if ((((struct in_addr *)dst)->s_addr = inet_addr(src)) == INADDR_NONE) return 0; |
| return 1; |
| } |
| |
| #endif /* defined(_WIN32) || defined(__CYGWIN__)*/ |
| |
| #if defined(_WIN32) && !defined(__CYGWIN__) |
| |
| static __int64 file_time_to_unix_time(const FILETIME * ft) { |
| __int64 res = (__int64)ft->dwHighDateTime << 32; |
| |
| res |= ft->dwLowDateTime; |
| res /= 10; /* from 100 nano-sec periods to usec */ |
| res -= 11644473600000000ull; /* from Win epoch to Unix epoch */ |
| return res; |
| } |
| |
| int clock_gettime(clockid_t clock_id, struct timespec * tp) { |
| FILETIME ft; |
| __int64 tim; |
| |
| assert(clock_id == CLOCK_REALTIME); |
| if (!tp) { |
| errno = EINVAL; |
| return -1; |
| } |
| GetSystemTimeAsFileTime(&ft); |
| tim = file_time_to_unix_time(&ft); |
| tp->tv_sec = (long)(tim / 1000000L); |
| tp->tv_nsec = (long)(tim % 1000000L) * 1000; |
| return 0; |
| } |
| |
| void usleep(useconds_t useconds) { |
| Sleep(useconds / 1000); |
| } |
| |
| int truncate(const char * path, int64_t size) { |
| int res = 0; |
| int f = open(path, _O_RDWR | _O_BINARY, 0); |
| if (f < 0) return -1; |
| res = ftruncate(f, size); |
| if (_close(f) < 0) return -1; |
| return res; |
| } |
| |
| int ftruncate(int fd, int64_t size) { |
| int64_t cur = 0; |
| int64_t pos = 0; |
| BOOL ret = FALSE; |
| HANDLE handle = (HANDLE)_get_osfhandle(fd); |
| |
| if (handle == INVALID_HANDLE_VALUE) { |
| errno = EBADF; |
| return -1; |
| } |
| /* save the current file pointer */ |
| cur = _lseeki64(fd, 0, SEEK_CUR); |
| if (cur >= 0) { |
| pos = _lseeki64(fd, size, SEEK_SET); |
| if (pos >= 0) { |
| ret = SetEndOfFile(handle); |
| if (!ret) set_win32_errno(GetLastError()); |
| } |
| /* restore the file pointer */ |
| cur = _lseeki64(fd, cur, SEEK_SET); |
| } |
| return cur >= 0 && pos >= 0 && ret ? 0 : -1; |
| } |
| |
| int getuid(void) { |
| /* Windows user is always a superuser :) */ |
| return 0; |
| } |
| |
| int geteuid(void) { |
| return 0; |
| } |
| |
| int getgid(void) { |
| return 0; |
| } |
| |
| int getegid(void) { |
| return 0; |
| } |
| |
| static wchar_t * str_to_wide_char(const char * str) { |
| wchar_t * res = NULL; |
| int len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); |
| if (len == 0) { |
| set_win32_errno(GetLastError()); |
| return NULL; |
| } |
| len += 16; /* utf8_opendir() needs extra space at the end of the string */ |
| res = (wchar_t *)malloc(sizeof(wchar_t) * len); |
| if (res == NULL) { |
| errno = ENOMEM; |
| return NULL; |
| } |
| len = MultiByteToWideChar(CP_UTF8, 0, str, -1, res, len); |
| if (len == 0) { |
| set_win32_errno(GetLastError()); |
| return NULL; |
| } |
| return res; |
| } |
| |
| int utf8_stat(const char * name, struct utf8_stat * buf) { |
| int error = 0; |
| struct _stati64 tmp; |
| wchar_t * path = str_to_wide_char(name); |
| if (path == NULL) return -1; |
| memset(&tmp, 0, sizeof(tmp)); |
| if (_wstati64(path, &tmp)) error = errno; |
| if (!error) { |
| buf->st_dev = tmp.st_dev; |
| buf->st_ino = tmp.st_ino; |
| buf->st_mode = tmp.st_mode; |
| buf->st_nlink = tmp.st_nlink; |
| buf->st_uid = tmp.st_uid; |
| buf->st_gid = tmp.st_gid; |
| buf->st_rdev = tmp.st_rdev; |
| buf->st_size = tmp.st_size; |
| buf->st_atime = tmp.st_atime; |
| buf->st_mtime = tmp.st_mtime; |
| buf->st_ctime = tmp.st_ctime; |
| } |
| free(path); |
| if (error) { |
| errno = error; |
| return -1; |
| } |
| return 0; |
| } |
| |
| int utf8_fstat(int fd, struct utf8_stat * buf) { |
| struct _stati64 tmp; |
| memset(&tmp, 0, sizeof(tmp)); |
| if (_fstati64(fd, &tmp)) return -1; |
| buf->st_dev = tmp.st_dev; |
| buf->st_ino = tmp.st_ino; |
| buf->st_mode = tmp.st_mode; |
| buf->st_nlink = tmp.st_nlink; |
| buf->st_uid = tmp.st_uid; |
| buf->st_gid = tmp.st_gid; |
| buf->st_rdev = tmp.st_rdev; |
| buf->st_size = tmp.st_size; |
| buf->st_atime = tmp.st_atime; |
| buf->st_mtime = tmp.st_mtime; |
| buf->st_ctime = tmp.st_ctime; |
| return 0; |
| } |
| |
| int utf8_open(const char * name, int flags, int perms) { |
| int fd = -1; |
| int error = 0; |
| wchar_t * path = str_to_wide_char(name); |
| if (path == NULL) return -1; |
| if ((fd = _wopen(path, flags, perms)) < 0) error = errno; |
| free(path); |
| if (error) { |
| errno = error; |
| return -1; |
| } |
| return fd; |
| } |
| |
| int utf8_chmod(const char * name, int mode) { |
| int error = 0; |
| wchar_t * path = str_to_wide_char(name); |
| if (path == NULL) return -1; |
| if (_wchmod(path, mode) < 0) error = errno; |
| free(path); |
| if (error) { |
| errno = error; |
| return -1; |
| } |
| return 0; |
| } |
| |
| int utf8_remove(const char * name) { |
| int error = 0; |
| wchar_t * path = str_to_wide_char(name); |
| if (path == NULL) return -1; |
| if (_wremove(path) < 0) error = errno; |
| free(path); |
| if (error) { |
| errno = error; |
| return -1; |
| } |
| return 0; |
| } |
| |
| int utf8_rmdir(const char * name) { |
| int error = 0; |
| wchar_t * path = str_to_wide_char(name); |
| if (path == NULL) return -1; |
| if (_wrmdir(path) < 0) error = errno; |
| free(path); |
| if (error) { |
| errno = error; |
| return -1; |
| } |
| return 0; |
| } |
| |
| int utf8_mkdir(const char * name, int mode) { |
| int error = 0; |
| wchar_t * path = str_to_wide_char(name); |
| if (path == NULL) return -1; |
| if (_wmkdir(path) < 0) error = errno; |
| free(path); |
| if (error) { |
| errno = error; |
| return -1; |
| } |
| return 0; |
| } |
| |
| int utf8_rename(const char * name1, const char * name2) { |
| int error = 0; |
| wchar_t * path1 = NULL; |
| wchar_t * path2 = NULL; |
| path1 = str_to_wide_char(name1); |
| if (path1 == NULL) { |
| error = errno; |
| } |
| else { |
| path2 = str_to_wide_char(name2); |
| if (path2 == NULL) error = errno; |
| } |
| if (!error && _wrename(path1, path2) < 0) error = errno; |
| free(path1); |
| free(path2); |
| if (error) { |
| errno = error; |
| return -1; |
| } |
| return 0; |
| } |
| |
| int utf8_utime(const char * name, struct utimbuf * buf) { |
| int error = 0; |
| wchar_t * path = str_to_wide_char(name); |
| if (path == NULL) return -1; |
| if (_wutime(path, buf) < 0) error = errno; |
| free(path); |
| if (error) { |
| errno = error; |
| return -1; |
| } |
| return 0; |
| } |
| |
| DIR * utf8_opendir(const char * path) { |
| DIR * d = (DIR *)malloc(sizeof(DIR)); |
| if (!d) { errno = ENOMEM; return 0; } |
| d->path = str_to_wide_char(path); |
| if (!d->path) { free(d); return NULL; } |
| wcscat(d->path, L"/*.*"); |
| d->hdl = -1; |
| return d; |
| } |
| |
| struct dirent * utf8_readdir(DIR * d) { |
| if (d->hdl < 0) { |
| int error = 0; |
| d->hdl = _wfindfirsti64(d->path, &d->blk); |
| if (d->hdl < 0) error = errno; |
| if (error) { |
| if (errno == ENOENT) errno = 0; |
| return NULL; |
| } |
| } |
| else { |
| int r = _wfindnexti64(d->hdl, &d->blk); |
| if (r < 0) { |
| if (errno == ENOENT) errno = 0; |
| return NULL; |
| } |
| } |
| if (!WideCharToMultiByte(CP_UTF8, 0, d->blk.name, -1, d->de.d_name, sizeof(d->de.d_name), NULL, NULL)) { |
| set_win32_errno(GetLastError()); |
| return 0; |
| } |
| d->de.d_size = d->blk.size; |
| d->de.d_atime = d->blk.time_access; |
| d->de.d_ctime = d->blk.time_create; |
| d->de.d_wtime = d->blk.time_write; |
| return &d->de; |
| } |
| |
| int utf8_closedir(DIR * d) { |
| int r = 0; |
| if (!d) { |
| errno = EBADF; |
| return -1; |
| } |
| if (d->hdl >= 0) r = _findclose(d->hdl); |
| free(d->path); |
| free(d); |
| return r; |
| } |
| |
| #endif /* defined(_WIN32) && !defined(__CYGWIN__) */ |
| |
| #if defined(_WIN32) && !defined(__CYGWIN__) || defined(_WRS_KERNEL) || defined(__SYMBIAN32__) |
| |
| ssize_t pread(int fd, void * buf, size_t size, off_t offset) { |
| off_t offs0; |
| ssize_t rd; |
| if ((offs0 = lseek(fd, 0, SEEK_CUR)) == (off_t)-1) return -1; |
| if (lseek(fd, offset, SEEK_SET) == (off_t)-1) return -1; |
| rd = read(fd, (void *)buf, size); |
| if (lseek(fd, offs0, SEEK_SET) == (off_t)-1) return -1; |
| return rd; |
| } |
| |
| ssize_t pwrite(int fd, const void * buf, size_t size, off_t offset) { |
| off_t offs0; |
| ssize_t wr; |
| if ((offs0 = lseek(fd, 0, SEEK_CUR)) == (off_t)-1) return -1; |
| if (lseek(fd, offset, SEEK_SET) == (off_t)-1) return -1; |
| wr = write(fd, (void *)buf, size); |
| if (lseek(fd, offs0, SEEK_SET) == (off_t)-1) return -1; |
| return wr; |
| } |
| |
| #endif /* defined(_WIN32) && !defined(__CYGWIN__) || defined(_WRS_KERNEL) || defined(__SYMBIAN32__) */ |
| |
| #ifndef big_endian_host |
| extern int big_endian_host(void) { |
| uint16_t n = 0x0201; |
| uint8_t * p = (uint8_t *)&n; |
| return *p == 0x02; |
| } |
| #endif |
| |
| void swap_bytes(void * buf, size_t size) { |
| size_t i, j, n; |
| char * p = (char *)buf; |
| n = size >> 1; |
| for (i = 0, j = size - 1; i < n; i++, j--) { |
| char x = p[i]; |
| p[i] = p[j]; |
| p[j] = x; |
| } |
| } |
| |
| #if defined(_WIN32) || defined(__CYGWIN__) |
| |
| #include <locale.h> |
| #include <shlobj.h> |
| |
| const char * get_os_name(void) { |
| static char str[256]; |
| OSVERSIONINFOEX info; |
| memset(&info, 0, sizeof(info)); |
| info.dwOSVersionInfoSize = sizeof(info); |
| GetVersionEx((OSVERSIONINFO *)&info); |
| switch (info.dwMajorVersion) { |
| case 4: |
| return "Windows NT"; |
| case 5: |
| switch (info.dwMinorVersion) { |
| case 0: return "Windows 2000"; |
| case 1: return "Windows XP"; |
| case 2: return "Windows Server 2003"; |
| } |
| break; |
| case 6: |
| switch (info.dwMinorVersion) { |
| case 0: |
| if (info.wProductType == VER_NT_WORKSTATION) return "Windows Vista"; |
| return "Windows Server 2008"; |
| case 1: |
| if (info.wProductType == VER_NT_WORKSTATION) return "Windows 7"; |
| return "Windows Server 2008 R2"; |
| case 2: |
| if (info.wProductType == VER_NT_WORKSTATION) return "Windows 8"; |
| return "Windows Server 2012"; |
| } |
| } |
| snprintf(str, sizeof(str), "Windows %d.%d", (int)info.dwMajorVersion, (int)info.dwMinorVersion); |
| return str; |
| } |
| |
| const char * get_user_home(void) { |
| WCHAR w_buf[MAX_PATH]; |
| static char a_buf[MAX_PATH]; |
| if (a_buf[0] != 0) return a_buf; |
| if (!SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, w_buf))) { |
| errno = ERR_OTHER; |
| return NULL; |
| } |
| if (!WideCharToMultiByte(CP_UTF8, 0, w_buf, -1, a_buf, sizeof(a_buf), NULL, NULL)) { |
| set_win32_errno(GetLastError()); |
| return NULL; |
| } |
| return a_buf; |
| } |
| |
| #define MAX_USER_NAME 256 |
| |
| const char * get_user_name(void) { |
| DWORD size = MAX_USER_NAME; |
| WCHAR w_buf[MAX_USER_NAME]; |
| static char a_buf[MAX_USER_NAME]; |
| if (a_buf[0] != 0) return a_buf; |
| if (!GetUserNameW(w_buf, &size)) { |
| set_win32_errno(GetLastError()); |
| return NULL; |
| } |
| if (!WideCharToMultiByte(CP_UTF8, 0, w_buf, -1, a_buf, sizeof(a_buf), NULL, NULL)) { |
| set_win32_errno(GetLastError()); |
| return NULL; |
| } |
| return a_buf; |
| } |
| |
| void ini_mdep(void) { |
| WORD wVersionRequested = MAKEWORD(1, 1); |
| WSADATA wsaData; |
| int err; |
| |
| setlocale(LC_ALL, ""); |
| SetErrorMode(SEM_FAILCRITICALERRORS); |
| err = WSAStartup(wVersionRequested, &wsaData); |
| if (err != 0) { |
| fprintf(stderr, "Couldn't access winsock.dll.\n"); |
| exit(1); |
| } |
| /* Confirm that the Windows Sockets DLL supports 1.1.*/ |
| /* Note that if the DLL supports versions greater */ |
| /* than 1.1 in addition to 1.1, it will still return */ |
| /* 1.1 in wVersion since that is the version we */ |
| /* requested. */ |
| if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { |
| fprintf(stderr, "Unacceptable version of winsock.dll.\n"); |
| WSACleanup(); |
| exit(1); |
| } |
| pthread_attr_init(&pthread_create_attr); |
| #if defined(_DEBUG) && defined(_MSC_VER) |
| _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF /* | _CRTDBG_LEAK_CHECK_DF */); |
| #endif |
| } |
| |
| #elif defined(_WRS_KERNEL) |
| |
| void usleep(useconds_t useconds) { |
| struct timespec tv; |
| tv.tv_sec = useconds / 1000000; |
| tv.tv_nsec = (useconds % 1000000) * 1000; |
| nanosleep(&tv, NULL); |
| } |
| |
| int truncate(char * path, int64_t size) { |
| int f = open(path, O_RDWR, 0); |
| if (f < 0) return -1; |
| if (ftruncate(f, size) < 0) { |
| int err = errno; |
| close(f); |
| errno = err; |
| return -1; |
| } |
| return close(f); |
| } |
| |
| int getuid(void) { |
| return 0; |
| } |
| |
| int geteuid(void) { |
| return 0; |
| } |
| |
| int getgid(void) { |
| return 0; |
| } |
| |
| int getegid(void) { |
| return 0; |
| } |
| |
| const char * get_os_name(void) { |
| #if _WRS_VXWORKS_MAJOR > 6 || _WRS_VXWORKS_MAJOR == 6 && _WRS_VXWORKS_MINOR >= 7 |
| return VXWORKS_VERSION; |
| #else |
| static char str[256]; |
| snprintf(str, sizeof(str), "VxWorks %s", kernelVersion()); |
| return str; |
| #endif |
| } |
| |
| const char * get_user_home(void) { |
| return "/"; |
| } |
| |
| const char * get_user_name(void) { |
| errno = ERR_UNSUPPORTED; |
| return NULL; |
| } |
| |
| void ini_mdep(void) { |
| pthread_attr_init(&pthread_create_attr); |
| pthread_attr_setstacksize(&pthread_create_attr, 0x8000); |
| pthread_attr_setname(&pthread_create_attr, "tTcf"); |
| pthread_attr_setopt (&pthread_create_attr, VX_FP_TASK|VX_UNBREAKABLE); |
| } |
| |
| #elif defined(__SYMBIAN32__) |
| |
| int truncate(const char * path, int64_t size) { |
| int res = 0; |
| int f = open(path, O_RDWR | O_BINARY, 0); |
| if (f < 0) return -1; |
| res = ftruncate(f, size); |
| close(f); |
| return res; |
| } |
| |
| const char * get_os_name(void) { |
| static char str[] = "SYMBIAN"; |
| return str; |
| } |
| |
| const char * get_user_home(void) { |
| static char buf[] = "C:"; |
| return buf; |
| } |
| |
| const char * get_user_name(void) { |
| errno = ERR_UNSUPPORTED; |
| return NULL; |
| } |
| |
| void ini_mdep(void) { |
| pthread_attr_init(&pthread_create_attr); |
| } |
| |
| int loc_clock_gettime(int clock_id, struct timespec * now) { |
| /* |
| * OpenC has a bug for several releases using a timezone-sensitive time in clock_realtime(). |
| * gettimeofday() is more reliable. |
| */ |
| struct timeval timenowval; |
| int ret; |
| assert(clock_id == CLOCK_REALTIME); |
| if (!now) { |
| errno = EINVAL; |
| return -1; |
| } |
| ret = gettimeofday(&timenowval, NULL); |
| if (ret < 0) |
| return ret; |
| now->tv_sec = timenowval.tv_sec; |
| now->tv_nsec = timenowval.tv_usec * 1000L; |
| return 0; |
| } |
| |
| /** |
| * Some of the dynamic IP interface scanning routines are unreliable, so |
| * include a workaround to manually set the desired interface from outside. |
| */ |
| #include <tcf/framework/ip_ifc.h> |
| |
| static ip_ifc_info* gSelectedIPInterface; |
| |
| void set_ip_ifc(ip_ifc_info* info) { |
| gSelectedIPInterface = info; |
| } |
| ip_ifc_info* get_ip_ifc(void) { |
| return gSelectedIPInterface; |
| } |
| |
| #else |
| |
| #include <pwd.h> |
| #include <locale.h> |
| #include <langinfo.h> |
| #include <sys/utsname.h> |
| #if defined(__linux__) |
| # include <asm/unistd.h> |
| #endif |
| |
| #if !defined(USE_clock_gettime) |
| # define USE_clock_gettime (!defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__APPLE__)) |
| #endif |
| |
| #if !USE_clock_gettime |
| int clock_gettime(clockid_t clock_id, struct timespec * tp) { |
| struct timeval tv; |
| |
| assert(clock_id == CLOCK_REALTIME); |
| if (!tp) { |
| errno = EINVAL; |
| return -1; |
| } |
| if (gettimeofday(&tv, NULL) < 0) { |
| return -1; |
| } |
| tp->tv_sec = tv.tv_sec; |
| tp->tv_nsec = tv.tv_usec * 1000; |
| return 0; |
| } |
| #endif |
| |
| #if defined(__UCLIBC__) |
| #include <fcntl.h> |
| |
| int posix_openpt(int flags) { |
| return (open("/dev/ptmx", flags)); |
| } |
| #endif |
| |
| const char * get_os_name(void) { |
| static char str[256]; |
| struct utsname info; |
| memset(&info, 0, sizeof(info)); |
| uname(&info); |
| assert(strlen(info.sysname) + strlen(info.release) < sizeof(str)); |
| snprintf(str, sizeof(str), "%s %s", info.sysname, info.release); |
| return str; |
| } |
| |
| const char * get_user_home(void) { |
| static char * buf = NULL; |
| if (buf == NULL) { |
| struct passwd * pwd = NULL; |
| errno = 0; |
| pwd = getpwuid(getuid()); |
| if (pwd == NULL) return NULL; |
| buf = loc_strdup(pwd->pw_dir); |
| } |
| return buf; |
| } |
| |
| const char * get_user_name(void) { |
| static const char * login = NULL; |
| if (login == NULL) { |
| login = getlogin(); |
| if (login == NULL) { |
| struct passwd * pwd = getpwuid(getuid()); |
| if (pwd == NULL) return NULL; |
| login = pwd->pw_name; |
| } |
| login = loc_strdup(login); |
| } |
| return login; |
| } |
| |
| int tkill(pid_t pid, int signal) { |
| #if defined(__linux__) |
| return syscall(__NR_tkill, pid, signal); |
| #else |
| return kill(pid, signal); |
| #endif |
| } |
| |
| void ini_mdep(void) { |
| setlocale(LC_ALL, ""); |
| #ifdef CODESET |
| utf8_locale = (strcmp(nl_langinfo(CODESET), "UTF-8") == 0); |
| #endif |
| signal(SIGPIPE, SIG_IGN); |
| pthread_attr_init(&pthread_create_attr); |
| pthread_attr_setstacksize(&pthread_create_attr, 0x8000); |
| } |
| |
| #endif |
| |
| |
| /** canonicalize_file_name ****************************************************/ |
| |
| #if defined(_WIN32) || defined(__CYGWIN__) |
| |
| char * canonicalize_file_name(const char * name) { |
| DWORD len; |
| int i = 0; |
| wchar_t buf[FILE_PATH_SIZE]; |
| wchar_t * basename = NULL; |
| wchar_t path[FILE_PATH_SIZE]; |
| char res[FILE_PATH_SIZE]; |
| |
| assert(name != NULL); |
| if (!MultiByteToWideChar(CP_UTF8, 0, name, -1, path, sizeof(path) / sizeof(wchar_t))) { |
| set_win32_errno(GetLastError()); |
| return NULL; |
| } |
| len = GetFullPathNameW(path, sizeof(buf) / sizeof(wchar_t), buf, &basename); |
| if (len == 0) { |
| errno = ENOENT; |
| return NULL; |
| } |
| if (len > FILE_PATH_SIZE - 1) { |
| errno = ENAMETOOLONG; |
| return NULL; |
| } |
| while (buf[i] != 0) { |
| if (buf[i] == '\\') buf[i] = '/'; |
| i++; |
| } |
| len = WideCharToMultiByte(CP_UTF8, 0, buf, -1, res, sizeof(res), NULL, NULL); |
| if (len == 0) { |
| set_win32_errno(GetLastError()); |
| return NULL; |
| } |
| if (len > FILE_PATH_SIZE - 1) { |
| errno = ENAMETOOLONG; |
| return NULL; |
| } |
| return strdup(res); |
| } |
| |
| #elif defined(_WRS_KERNEL) |
| |
| #include <string.h> |
| |
| char * canonicalize_file_name(const char * path) { |
| char buf[PATH_MAX]; |
| size_t i = 0; |
| size_t j = 0; |
| if (path[0] == '.' && (path[1] == '/' || path[1] == '\\' || path[1] == 0)) { |
| getcwd(buf, sizeof(buf)); |
| j = strlen(buf); |
| if (j == 1 && buf[0] == '/') j = 0; |
| i = 1; |
| } |
| else if (path[0] == '.' && path[1] == '.' && (path[2] == '/' || path[2] == '\\' || path[2] == 0)) { |
| getcwd(buf, sizeof(buf)); |
| j = strlen(buf); |
| while (j > 0 && buf[j - 1] != '/') j--; |
| if (j > 0 && buf[j - 1] == '/') j--; |
| i = 2; |
| } |
| while (path[i] && j < PATH_MAX - 1) { |
| char ch = path[i]; |
| if (ch == '\\') ch = '/'; |
| if (ch == '/') { |
| if (path[i + 1] == '/' || path[i + 1] == '\\') { |
| i++; |
| continue; |
| } |
| if (path[i + 1] == '.') { |
| if (path[i + 2] == 0) { |
| break; |
| } |
| if (path[i + 2] == '/' || path[i + 2] == '\\') { |
| i += 2; |
| continue; |
| } |
| if ((j == 0 || buf[0] == '/') && path[i + 2] == '.') { |
| if (path[i + 3] == '/' || path[i + 3] == '\\' || path[i + 3] == 0) { |
| while (j > 0 && buf[j - 1] != '/') j--; |
| if (j > 0 && buf[j - 1] == '/') j--; |
| i += 3; |
| continue; |
| } |
| } |
| } |
| } |
| buf[j++] = ch; |
| i++; |
| } |
| if (j == 0 && path[0] != 0) buf[j++] = '/'; |
| buf[j] = 0; |
| return strdup(buf); |
| } |
| |
| #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) |
| |
| char * canonicalize_file_name(const char * path) { |
| char buf[PATH_MAX]; |
| char * res = realpath(path, buf); |
| if (res == NULL) return NULL; |
| return strdup(res); |
| } |
| |
| #elif defined(__UCLIBC__) |
| |
| char * canonicalize_file_name(const char * path) { |
| return realpath(path, NULL); |
| } |
| |
| #endif |
| |
| |
| /** getaddrinfo ***************************************************************/ |
| |
| #if defined(_WRS_KERNEL) && defined(USE_VXWORKS_GETADDRINFO) |
| |
| /* TODO: VxWorks 6.6 getaddrinfo returns error when port is empty string, should return port 0 */ |
| /* TODO: VxWorks 6.6 source (as shipped at 2007 fall release) does not include ipcom header files. */ |
| extern void ipcom_freeaddrinfo(); |
| extern int ipcom_getaddrinfo(); |
| |
| static struct ai_errlist { |
| const char * str; |
| int code; |
| } ai_errlist[] = { |
| { "Success", 0 }, |
| /* |
| { "Invalid value for ai_flags", IP_EAI_BADFLAGS }, |
| { "Non-recoverable failure in name resolution", IP_EAI_FAIL }, |
| { "ai_family not supported", IP_EAI_FAMILY }, |
| { "Memory allocation failure", IP_EAI_MEMORY }, |
| { "hostname nor servname provided, or not known", IP_EAI_NONAME }, |
| { "servname not supported for ai_socktype", IP_EAI_SERVICE }, |
| { "ai_socktype not supported", IP_EAI_SOCKTYPE }, |
| { "System error returned in errno", IP_EAI_SYSTEM }, |
| */ |
| /* backward compatibility with userland code prior to 2553bis-02 */ |
| { "Address family for hostname not supported", 1 }, |
| { "No address associated with hostname", 7 }, |
| { NULL, -1 }, |
| }; |
| |
| void loc_freeaddrinfo(struct addrinfo * ai) { |
| ipcom_freeaddrinfo(ai); |
| } |
| |
| int loc_getaddrinfo(const char * nodename, const char * servname, |
| const struct addrinfo * hints, struct addrinfo ** res) { |
| return ipcom_getaddrinfo(nodename, servname, hints, res); |
| } |
| |
| const char * loc_gai_strerror(int ecode) { |
| struct ai_errlist * p; |
| static char buf[32]; |
| for (p = ai_errlist; p->str; p++) { |
| if (p->code == ecode) return p->str; |
| } |
| snprintf(buf, sizeof(buf), "Error code %d", ecode); |
| return buf; |
| } |
| |
| #elif defined(_WRS_KERNEL) |
| |
| union sockaddr_union { |
| struct sockaddr sa; |
| struct sockaddr_in sin; |
| struct sockaddr_in6 sin6; |
| }; |
| |
| extern int ipcom_getsockaddrbyaddr(); |
| |
| void loc_freeaddrinfo(struct addrinfo * ai) { |
| while (ai != NULL) { |
| struct addrinfo * next = ai->ai_next; |
| if (ai->ai_canonname != NULL) loc_free(ai->ai_canonname); |
| if (ai->ai_addr != NULL) loc_free(ai->ai_addr); |
| loc_free(ai); |
| ai = next; |
| } |
| } |
| |
| int loc_getaddrinfo(const char * nodename, const char * servname, |
| const struct addrinfo * hints, struct addrinfo ** res) { |
| int family = 0; |
| int flags = 0; |
| int socktype = 0; |
| int protocol = 0; |
| int err; |
| int port = 0; |
| char * canonname = NULL; |
| const char * host; |
| struct addrinfo * ai; |
| union sockaddr_union * sa; |
| |
| *res = NULL; |
| |
| if (hints != NULL) { |
| flags = hints->ai_flags; |
| family = hints->ai_family; |
| socktype = hints->ai_socktype; |
| protocol = hints->ai_protocol; |
| } |
| if (family == AF_UNSPEC) { |
| struct addrinfo lhints; |
| int err_v6; |
| |
| if (hints == NULL) memset(&lhints, 0, sizeof(lhints)); |
| else memcpy(&lhints, hints, sizeof(lhints)); |
| lhints.ai_family = AF_INET6; |
| err_v6 = loc_getaddrinfo(nodename, servname, &lhints, res); |
| lhints.ai_family = AF_INET; |
| while (*res != NULL) res = &(*res)->ai_next; |
| err = loc_getaddrinfo(nodename, servname, &lhints, res); |
| return err && err_v6 ? err : 0; |
| } |
| if (servname != NULL && servname[0] != 0) { |
| char * p = NULL; |
| port = (unsigned int) strtoul(servname, &p, 10); |
| if (port < 0 || port > 0xffff || *p != '\0' || p == servname) { |
| return 1; |
| } |
| } |
| if (nodename != NULL && nodename[0] != 0) { |
| host = nodename; |
| } |
| else if (flags & AI_PASSIVE) { |
| host = family == AF_INET ? "0.0.0.0" : "::"; |
| } |
| else { |
| host = family == AF_INET ? "127.0.0.1" : "::1"; |
| } |
| if (socktype == 0) { |
| socktype = SOCK_STREAM; |
| } |
| if (protocol == 0) { |
| protocol = socktype == SOCK_STREAM ? IPPROTO_TCP : IPPROTO_UDP; |
| } |
| |
| sa = loc_alloc_zero(sizeof(*sa)); |
| err = ipcom_getsockaddrbyaddr(family, host, (struct sockaddr *)sa); |
| if (err) { |
| loc_free(sa); |
| return err; |
| } |
| |
| ai = loc_alloc_zero(sizeof(*ai)); |
| switch (family) { |
| case AF_INET: |
| assert(sa->sin.sin_family == AF_INET); |
| sa->sin.sin_port = (unsigned short) htons(port); |
| ai->ai_addrlen = sizeof(struct sockaddr_in); |
| break; |
| case AF_INET6: |
| assert(sa->sin6.sin6_family == AF_INET6); |
| sa->sin6.sin6_port = (unsigned short) htons(port); |
| ai->ai_addrlen = sizeof(struct sockaddr_in6); |
| break; |
| default: |
| loc_free(sa); |
| loc_free(ai); |
| return 2; |
| } |
| |
| ai->ai_flags = 0; |
| ai->ai_family = family; |
| ai->ai_socktype = socktype; |
| ai->ai_protocol = protocol; |
| ai->ai_canonname = canonname; |
| ai->ai_addr = (struct sockaddr *)sa; |
| ai->ai_next = NULL; |
| *res = ai; |
| return 0; |
| } |
| |
| const char * loc_gai_strerror(int ecode) { |
| static char buf[32]; |
| if (ecode == 0) return "Success"; |
| snprintf(buf, sizeof(buf), "Error code %d", ecode); |
| return buf; |
| } |
| |
| #elif defined(_WIN32) || defined(__CYGWIN__) |
| |
| const char * loc_gai_strerror(int ecode) { |
| WCHAR * buf = NULL; |
| static char msg[512]; |
| if (ecode == 0) return "Success"; |
| if (!FormatMessageW( |
| FORMAT_MESSAGE_ALLOCATE_BUFFER | |
| FORMAT_MESSAGE_FROM_SYSTEM | |
| FORMAT_MESSAGE_IGNORE_INSERTS | |
| FORMAT_MESSAGE_MAX_WIDTH_MASK, |
| NULL, |
| ecode, |
| MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), |
| (LPWSTR)&buf, 0, NULL) || |
| !WideCharToMultiByte(CP_UTF8, 0, buf, -1, msg, sizeof(msg), NULL, NULL)) |
| { |
| snprintf(msg, sizeof(msg), "GAI Error Code %d", ecode); |
| } |
| if (buf != NULL) LocalFree(buf); |
| return msg; |
| } |
| |
| #elif defined(__SYMBIAN32__) |
| |
| const char * loc_gai_strerror(int ecode) { |
| static char buf[32]; |
| if (ecode == 0) return "Success"; |
| snprintf(buf, sizeof(buf), "Error code %d", ecode); |
| return buf; |
| } |
| |
| #endif |
| |
| #if defined(_WIN32) || defined(__CYGWIN__) |
| # include <tlhelp32.h> |
| # ifdef _MSC_VER |
| # pragma warning(disable:4201) /* nonstandard extension used : nameless struct/union (in winternl.h) */ |
| # include <winternl.h> |
| # else |
| # include <ntdef.h> |
| # endif |
| # ifndef STATUS_INFO_LENGTH_MISMATCH |
| # define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) |
| # endif |
| # ifndef SystemHandleInformation |
| # define SystemHandleInformation 16 |
| # endif |
| |
| /* Disable inheritance for all handles owned by process */ |
| static NTSTATUS disable_handle_inheritance(void) { |
| typedef struct _HANDLE_INFORMATION { |
| USHORT ProcessId; |
| USHORT CreatorBackTraceIndex; |
| UCHAR ObjectTypeNumber; |
| UCHAR Flags; |
| USHORT Handle; |
| PVOID Object; |
| ACCESS_MASK GrantedAccess; |
| } HANDLE_INFORMATION; |
| typedef struct _SYSTEM_HANDLE_INFORMATION { |
| ULONG Count; |
| HANDLE_INFORMATION Handles[1]; |
| } SYSTEM_HANDLE_INFORMATION; |
| typedef NTSTATUS (FAR WINAPI * QuerySystemInformationTypedef)(int, PVOID, ULONG, PULONG); |
| QuerySystemInformationTypedef QuerySystemInformationProc = (QuerySystemInformationTypedef)GetProcAddress( |
| GetModuleHandle("NTDLL.DLL"), "NtQuerySystemInformation"); |
| DWORD size; |
| NTSTATUS status; |
| SYSTEM_HANDLE_INFORMATION * hi = NULL; |
| |
| size = sizeof(SYSTEM_HANDLE_INFORMATION) + sizeof(HANDLE_INFORMATION) * 256; |
| hi = (SYSTEM_HANDLE_INFORMATION *)tmp_alloc_zero(size); |
| for (;;) { |
| status = QuerySystemInformationProc(SystemHandleInformation, hi, size, &size); |
| if (status != STATUS_INFO_LENGTH_MISMATCH) break; |
| hi = (SYSTEM_HANDLE_INFORMATION *)tmp_realloc(hi, size); |
| } |
| if (status == 0) { |
| ULONG i; |
| DWORD id = GetCurrentProcessId(); |
| for (i = 0; i < hi->Count; i++) { |
| if (hi->Handles[i].ProcessId != id) continue; |
| SetHandleInformation((HANDLE)(uintptr_t)hi->Handles[i].Handle, HANDLE_FLAG_INHERIT, 0); |
| } |
| } |
| return status; |
| } |
| |
| static char *make_cmd_from_args(char **args) { |
| int i = 0; |
| int cmd_size = 0; |
| int cmd_pos = 0; |
| char *cmd = NULL; |
| |
| # define cmd_append(ch) { \ |
| if (cmd_pos >= cmd_size) { \ |
| cmd_size += 0x1000; \ |
| cmd = (char *)loc_realloc(cmd, cmd_size); \ |
| } \ |
| cmd[cmd_pos++] = (ch); \ |
| } |
| while (args[i] != NULL) { |
| const char * p = args[i++]; |
| if (cmd_pos > 0) cmd_append(' '); |
| cmd_append('"'); |
| while (*p) { |
| if (*p == '"') cmd_append('\\'); |
| cmd_append(*p); |
| p++; |
| } |
| cmd_append('"'); |
| } |
| cmd_append(0); |
| # undef cmd_append |
| return cmd; |
| } |
| |
| static int running_as_daemon = 0; |
| |
| int is_daemon(void) { |
| return running_as_daemon; |
| } |
| |
| # if !defined(__CYGWIN__) |
| # define pipe(fds) _pipe((fds), 1024, 0) |
| # endif |
| |
| void become_daemon(char **args) { |
| int fdpairs[4]; |
| int npairs = 2; |
| char fnm[FILE_PATH_SIZE]; |
| STARTUPINFO startupInfo; |
| PROCESS_INFORMATION prs_info; |
| int i; |
| |
| assert(!running_as_daemon); |
| running_as_daemon = 1; |
| |
| if (args == NULL) |
| return; |
| |
| fflush(stdout); |
| fflush(stderr); |
| |
| /* Make sure no handles are inherited by new process */ |
| disable_handle_inheritance(); |
| |
| if (pipe(fdpairs) < 0) { |
| perror("pipe"); |
| exit(1); |
| } |
| |
| if (pipe(fdpairs + 2) < 0) { |
| perror("pipe"); |
| exit(1); |
| } |
| |
| if (GetModuleFileName(NULL, fnm, sizeof(fnm)) == 0) { |
| fprintf(stderr, "GetModuleFileName failed\n"); |
| exit(1); |
| } |
| |
| memset(&startupInfo, 0, sizeof startupInfo); |
| startupInfo.dwFlags |= STARTF_USESTDHANDLES; |
| startupInfo.hStdInput = INVALID_HANDLE_VALUE; |
| startupInfo.hStdOutput = (HANDLE)_get_osfhandle(fdpairs[1]); |
| startupInfo.hStdError = (HANDLE)_get_osfhandle(fdpairs[3]); |
| SetHandleInformation(startupInfo.hStdOutput, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); |
| SetHandleInformation(startupInfo.hStdError, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); |
| |
| if (!CreateProcess(fnm, make_cmd_from_args(args), NULL, NULL, TRUE, |
| DETACHED_PROCESS, NULL, NULL, &startupInfo, &prs_info)) { |
| fprintf(stderr, "CreateProcess failed 0x%lx\n", GetLastError()); |
| exit(1); |
| } |
| |
| for (i = 0; i < 2; i++) { |
| /* Make read side non-blocking */ |
| DWORD pipemode = PIPE_READMODE_BYTE | PIPE_NOWAIT; |
| if (!SetNamedPipeHandleState((HANDLE)_get_osfhandle(fdpairs[i*2]), &pipemode, NULL, NULL)) { |
| fprintf(stderr, "SetNamedPipeHandleState failed 0x%lx\n", GetLastError()); |
| exit(1); |
| } |
| |
| /* Close write side of pipes so we get end of file as soon as |
| * the new them or exits */ |
| close(fdpairs[i*2 + 1]); |
| fdpairs[i*2 + 1] = 1; |
| } |
| |
| while (npairs > 0) { |
| for (i = 0; i < npairs; i++) { |
| char tmpbuf[1000]; |
| DWORD size; |
| if (ReadFile((HANDLE)_get_osfhandle(fdpairs[i*2]), tmpbuf, sizeof tmpbuf, &size, NULL)) { |
| if (write(fdpairs[i*2 + 1], tmpbuf, size) < 0) |
| perror("write"); |
| } else if (GetLastError() != ERROR_NO_DATA) { |
| if (GetLastError() != ERROR_BROKEN_PIPE) { |
| fprintf(stderr, "SetNamedPipeHandleState failed 0x%lx\n", GetLastError()); |
| } |
| fdpairs[i*2] = fdpairs[(npairs - 1)*2]; |
| fdpairs[i*2 + 1] = fdpairs[(npairs - 1)*2 + 1]; |
| npairs--; |
| } |
| } |
| /* Neither select nor overlapped I/O works for anonymous pipes, so use |
| * polling for now until a better solution if found... */ |
| usleep(1000); |
| } |
| |
| exit(0); |
| } |
| |
| void close_out_and_err(void) { |
| int fd = open("nul", O_WRONLY, 0); |
| if (fd < 0) { |
| perror("open nul"); |
| exit(1); |
| } |
| |
| fflush(stdout); |
| fflush(stderr); |
| |
| dup2(fd, 1); |
| dup2(fd, 2); |
| if (fd != 1 && fd != 2) |
| close(fd); |
| } |
| |
| #elif defined(_WRS_KERNEL) || defined (__SYMBIAN32__) |
| |
| int is_daemon(void) { |
| return 0; |
| } |
| |
| void become_daemon(void) { |
| fprintf(stderr, "tcf-agent: Running in the background is not supported on %s\n", get_os_name()); |
| exit(1); |
| } |
| |
| void close_out_and_err(void) { |
| } |
| |
| #else |
| |
| static int running_as_daemon = 0; |
| |
| int is_daemon(void) { |
| return running_as_daemon; |
| } |
| |
| void become_daemon(void) { |
| int fdpairs[4]; |
| int npairs = 2; |
| |
| assert(!running_as_daemon); |
| |
| fflush(stdout); |
| fflush(stderr); |
| |
| if (pipe(fdpairs) < 0) { |
| perror("pipe"); |
| exit(1); |
| } |
| |
| if (pipe(fdpairs + 2) < 0) { |
| perror("pipe"); |
| exit(1); |
| } |
| |
| /* Fork a new process so we can close everything except the pipes */ |
| switch (fork()) { |
| default: /* Parent process */ |
| /* Close write side of pipes so we get end of file as soon as |
| * child closes them or exits */ |
| close(fdpairs[1]); |
| close(fdpairs[3]); |
| fdpairs[1] = 1; |
| fdpairs[3] = 2; |
| |
| while (npairs > 0) { |
| int i; |
| int rval; |
| int nfds = 0; |
| fd_set readfds; |
| char tmpbuf[1000]; |
| |
| FD_ZERO(&readfds); |
| for (i = 0; i < npairs; i++) { |
| int fd = fdpairs[i*2]; |
| FD_SET(fd, &readfds); |
| if (nfds < fd) |
| nfds = fd; |
| } |
| rval = select(nfds + 1, &readfds, NULL, NULL, NULL); |
| if (rval < 0) { |
| if (errno == EINTR) |
| continue; |
| perror("select"); |
| _exit(1); |
| } |
| assert(rval > 0); |
| for (i = 0; i < npairs; i++) { |
| int fd = fdpairs[i*2]; |
| if (FD_ISSET(fd, &readfds)) { |
| rval = read(fd, tmpbuf, sizeof tmpbuf); |
| if (rval > 0) { |
| if (write(fdpairs[i*2 + 1], tmpbuf, rval) < 0) |
| perror("write"); |
| } else { |
| if (rval < 0) |
| perror("read"); |
| fdpairs[i*2] = fdpairs[(npairs - 1)*2]; |
| fdpairs[i*2 + 1] = fdpairs[(npairs - 1)*2 + 1]; |
| npairs--; |
| } |
| } |
| } |
| } |
| _exit(0); |
| break; |
| |
| case 0: { /* Child process */ |
| /* Replace stdin with /dev/null */ |
| int fd = open("/dev/null", O_RDONLY); |
| if (fd < 0) { |
| perror("open /dev/null"); |
| exit(1); |
| } |
| dup2(fd, 0); |
| dup2(fdpairs[1], 1); |
| dup2(fdpairs[3], 2); |
| if (fd != 0) |
| close(fd); |
| |
| /* Close all open files except stdin, stdout and stderr */ |
| fd = sysconf(_SC_OPEN_MAX); |
| while (fd-- > 3) |
| close(fd); |
| |
| /* Fork a new process so it is owned by init */ |
| switch (fork()) { |
| default: /* Parent process */ |
| _exit(0); |
| break; |
| |
| case 0: /* Child process */ |
| /* Create new session */ |
| if (setsid() == (pid_t)-1) { |
| perror("setsid"); |
| _exit(1); |
| } |
| |
| running_as_daemon = 1; |
| return; |
| |
| case -1: /* Fork failed */ |
| perror("fork"); |
| exit(1); |
| } |
| } |
| |
| case -1: /* Fork failed */ |
| perror("fork"); |
| exit(1); |
| } |
| } |
| |
| void close_out_and_err(void) { |
| int fd = open("/dev/null", O_WRONLY); |
| if (fd < 0) { |
| perror("open /dev/null"); |
| exit(1); |
| } |
| |
| fflush(stdout); |
| fflush(stderr); |
| |
| dup2(fd, 1); |
| dup2(fd, 2); |
| if (fd != 1 && fd != 2) |
| close(fd); |
| } |
| #endif |
| |
| double str_to_double(const char * buf, char ** end) { |
| int sign_val = 0; |
| int exponent = 0; |
| int digits = 0; |
| int fraction = 0; |
| uint64_t val = 0; |
| double p10 = 10.; |
| double res; |
| int n; |
| |
| while (isspace((unsigned char)*buf)) buf++; |
| if (*buf == '-') sign_val = 1; |
| if (sign_val || *buf == '+') buf++; |
| while (*buf >= '0' && *buf <= '9') { |
| if (digits < 18) { |
| val = val * 10 + (*buf - '0'); |
| if (val != 0) digits++; |
| } |
| else { |
| fraction--; |
| } |
| buf++; |
| } |
| if (*buf == '.') { |
| buf++; |
| while (*buf >= '0' && *buf <= '9') { |
| if (digits < 18) { |
| val = val * 10 + (*buf - '0'); |
| if (val != 0) digits++; |
| fraction++; |
| } |
| buf++; |
| } |
| } |
| if (*buf == 'E' || *buf == 'e') { |
| int sign_exp = 0; |
| buf++; |
| if (*buf == '-') sign_exp = 1; |
| if (sign_exp || *buf == '+') buf++; |
| while (*buf >= '0' && *buf <= '9') { |
| exponent = exponent * 10 + (*buf - '0'); |
| buf++; |
| } |
| if (sign_exp) exponent = -exponent; |
| } |
| exponent -= fraction; |
| n = exponent; |
| res = 1.0; |
| if (n < 0) n = -n; |
| while (n) { |
| if (n & 1) res *= p10; |
| p10 *= p10; |
| n >>= 1; |
| } |
| if (exponent < 0) { |
| res = (double)val / res; |
| } |
| else { |
| res = (double)val * res; |
| } |
| if (sign_val) res = -res; |
| if (end != NULL) *end = (char *)buf; |
| return res; |
| } |
| |
| const char * double_to_str(double n) { |
| char buf[128]; |
| uint64_t fraction = 0; |
| int exponent2 = 0; |
| int exponent10 = 0; |
| int neg = 0; |
| int i; |
| |
| assert(sizeof(n) == sizeof(fraction)); |
| memcpy(&fraction, &n, sizeof(fraction)); |
| |
| neg = (fraction & ((uint64_t)1 << 63)) != 0; |
| fraction &= ((uint64_t)1 << 63) - 1; |
| |
| exponent2 = (int)(fraction >> 52); |
| fraction &= ((uint64_t)1 << 52) - 1; |
| |
| if (exponent2 == 0x7ff) { |
| if (fraction != 0) return neg ? "-NaN" : "+NaN"; |
| return neg ? "-Infinity" : "+Infinity"; |
| } |
| |
| if (exponent2 == 0) exponent2 = 1; |
| else fraction |= ((uint64_t)1 << 52); |
| |
| if (fraction == 0) return neg ? "-0." : "0"; |
| |
| exponent2 -= 1023 + 52; |
| while (exponent2 != 0) { |
| /* fraction * 2**exponent2 * 10**exponent10 == abs(n) */ |
| if (exponent2 < 0) { |
| if ((fraction & 1) == 0) { |
| fraction = fraction >> 1; |
| } |
| else if (fraction > ((uint64_t)1 << 60)) { |
| fraction = (fraction + 1) >> 1; |
| } |
| else { |
| fraction = fraction * 5; |
| exponent10--; |
| } |
| exponent2++; |
| } |
| else { |
| if (fraction < ((uint64_t)1 << 63)) { |
| fraction = fraction << 1; |
| exponent2--; |
| } |
| else { |
| fraction = (fraction + 5) / 10; |
| exponent10++; |
| } |
| } |
| } |
| |
| while (fraction > ((uint64_t)1 << 53)) { |
| fraction = (fraction + 5) / 10; |
| exponent10++; |
| } |
| |
| while (fraction % 10 == 0) { |
| fraction /= 10; |
| exponent10++; |
| } |
| |
| i = sizeof(buf); |
| buf[--i] = 0; |
| if (exponent10 != 0) { |
| int eneg = exponent10 < 0; |
| if (eneg) exponent10 = -exponent10; |
| do { |
| buf[--i] = '0' + (exponent10 % 10); |
| exponent10 /= 10; |
| } |
| while (exponent10 != 0); |
| if (eneg) buf[--i] = '-'; |
| buf[--i] = 'E'; |
| } |
| do { |
| buf[--i] = '0' + (int)(fraction % 10); |
| fraction /= 10; |
| } |
| while (fraction != 0); |
| |
| if (neg) buf[--i] = '-'; |
| return tmp_strdup(buf + i); |
| } |
| |
| #if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__APPLE__) && !defined(__VXWORKS__) |
| |
| size_t strlcpy(char * dst, const char * src, size_t size) { |
| char ch; |
| const char * src0 = src; |
| const char * dst1 = dst + size - 1; |
| |
| while ((ch = *src) != 0) { |
| if (dst < dst1) *dst++ = ch; |
| src++; |
| } |
| if (dst <= dst1) *dst = 0; |
| return src - src0; |
| } |
| |
| size_t strlcat(char * dst, const char * src, size_t size) { |
| char ch; |
| const char * dst0 = dst; |
| const char * src0 = src; |
| const char * dst1 = dst + size - 1; |
| |
| while (dst <= dst1 && *dst != 0) dst++; |
| |
| while ((ch = *src) != 0) { |
| if (dst < dst1) *dst++ = ch; |
| src++; |
| } |
| if (dst <= dst1) *dst = 0; |
| return (dst - dst0) + (src - src0); |
| } |
| |
| #endif |
| |
| #if !defined(USE_uuid_generate) |
| # define USE_uuid_generate (defined(__linux__) && !defined(__UCLIBC__) && !defined(ANDROID)) |
| #endif |
| |
| #if USE_uuid_generate |
| |
| #include <uuid/uuid.h> |
| |
| const char * create_uuid(void) { |
| uuid_t id; |
| static char buf[64]; |
| uuid_generate(id); |
| uuid_unparse(id, buf); |
| return buf; |
| } |
| |
| #else |
| |
| const char * create_uuid(void) { |
| static char buf[40]; |
| struct timespec time_now; |
| memset(&time_now, 0, sizeof(time_now)); |
| if (clock_gettime(CLOCK_REALTIME, &time_now)) check_error(errno); |
| if (buf[0] == 0) srand((unsigned int)time_now.tv_sec ^ (unsigned int)time_now.tv_nsec); |
| snprintf(buf, sizeof(buf), "%08x-%04x-4%03x-8%03x-%04x%04x%04x", |
| (int)time_now.tv_sec & 0xffffffff, (int)(time_now.tv_nsec >> 13) & 0xffff, |
| rand() & 0xfff, rand() & 0xfff, rand() & 0xffff, rand() & 0xffff, rand() & 0xffff); |
| return buf; |
| } |
| |
| #endif |