user: implement mlibc as the libc, finally.
It's finally done.. Signed-off-by: kaguya <vpshinomiya@protonmail.com>
This commit is contained in:
@@ -0,0 +1,307 @@
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <bits/ensure.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <mlibc/bitutil.hpp>
|
||||
#include <mlibc/debug.hpp>
|
||||
|
||||
const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
|
||||
const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
|
||||
|
||||
uint32_t htonl(uint32_t x) {
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
return mlibc::bit_util<uint32_t>::byteswap(x);
|
||||
#else
|
||||
return x;
|
||||
#endif
|
||||
}
|
||||
uint16_t htons(uint16_t x) {
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
return mlibc::bit_util<uint16_t>::byteswap(x);
|
||||
#else
|
||||
return x;
|
||||
#endif
|
||||
}
|
||||
uint32_t ntohl(uint32_t x) {
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
return mlibc::bit_util<uint32_t>::byteswap(x);
|
||||
#else
|
||||
return x;
|
||||
#endif
|
||||
}
|
||||
uint16_t ntohs(uint16_t x) {
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
return mlibc::bit_util<uint16_t>::byteswap(x);
|
||||
#else
|
||||
return x;
|
||||
#endif
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// IPv4 address manipulation.
|
||||
// ----------------------------------------------------------------------------
|
||||
in_addr_t inet_addr(const char *p) {
|
||||
struct in_addr a;
|
||||
if(!inet_aton(p, &a))
|
||||
return -1;
|
||||
return a.s_addr;
|
||||
}
|
||||
|
||||
in_addr_t inet_network(const char *) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
char *inet_ntoa(struct in_addr addr) {
|
||||
// string: xxx.yyy.zzz.aaa
|
||||
// 4 * 3 + 3 + 1 = 12 + 4 = 16
|
||||
thread_local static char buffer[16];
|
||||
uint32_t proper = htonl(addr.s_addr);
|
||||
snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d",
|
||||
(proper >> 24) & 0xff, ((proper >> 16) & 0xff),
|
||||
(proper >> 8) & 0xff, proper & 0xff);
|
||||
return buffer;
|
||||
}
|
||||
int inet_aton(const char *string, struct in_addr *dest) {
|
||||
int array[4];
|
||||
int i = 0;
|
||||
char *end;
|
||||
|
||||
for (; i < 4; i++) {
|
||||
array[i] = strtoul(string, &end, 0);
|
||||
if (*end && *end != '.')
|
||||
return 0;
|
||||
if (!*end)
|
||||
break;
|
||||
string = end + 1;
|
||||
}
|
||||
|
||||
switch (i) {
|
||||
case 0:
|
||||
dest->s_addr = htonl(array[0]);
|
||||
break;
|
||||
case 1:
|
||||
if (array[0] > 255 || array[1] > 0xffffff)
|
||||
return 0;
|
||||
dest->s_addr = htonl((array[0] << 24) | array[1]);
|
||||
break;
|
||||
case 2:
|
||||
if (array[0] > 255 || array[1] > 255 ||
|
||||
array[2] > 0xffff)
|
||||
return 0;
|
||||
dest->s_addr = htonl((array[0] << 24) | (array[1] << 16) |
|
||||
array[2]);
|
||||
break;
|
||||
case 3:
|
||||
if (array[0] > 255 || array[1] > 255 ||
|
||||
array[2] > 255 || array[3] > 255)
|
||||
return 0;
|
||||
dest->s_addr = htonl((array[0] << 24) | (array[1] << 16) |
|
||||
(array[2] << 8) | array[3]);
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Generic IP address manipulation.
|
||||
// ----------------------------------------------------------------------------
|
||||
const char *inet_ntop(int af, const void *__restrict src, char *__restrict dst,
|
||||
socklen_t size) {
|
||||
switch (af) {
|
||||
case AF_INET: {
|
||||
auto source = reinterpret_cast<const struct in_addr*>(src);
|
||||
uint32_t addr = ntohl(source->s_addr);
|
||||
if (snprintf(dst, size, "%d.%d.%d.%d",
|
||||
(addr >> 24) & 0xff,
|
||||
(addr >> 16) & 0xff,
|
||||
(addr >> 8) & 0xff,
|
||||
addr & 0xff) < (int)size)
|
||||
return dst;
|
||||
break;
|
||||
}
|
||||
case AF_INET6: {
|
||||
auto source = reinterpret_cast<const struct in6_addr*>(src);
|
||||
size_t cur_zeroes_off = 0;
|
||||
size_t cur_zeroes_len = 0;
|
||||
size_t max_zeroes_off = 0;
|
||||
size_t max_zeroes_len = 0;
|
||||
|
||||
/* we look for the largest block of zeroed quartet(s) */
|
||||
for(size_t i = 0; i < 8; i++) {
|
||||
auto ptr = source->s6_addr + (i * 2);
|
||||
if(!ptr[0] && !ptr[1]) {
|
||||
cur_zeroes_len++;
|
||||
if(max_zeroes_len < cur_zeroes_len) {
|
||||
max_zeroes_len = cur_zeroes_len;
|
||||
max_zeroes_off = cur_zeroes_off;
|
||||
}
|
||||
} else {
|
||||
/* advance the offset to the next quartet to check */
|
||||
cur_zeroes_len = 0;
|
||||
cur_zeroes_off = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
size_t off = 0;
|
||||
for(size_t i = 0; i < 8; i++) {
|
||||
auto ptr = source->s6_addr + (i * 2);
|
||||
|
||||
/* if we are at the beginning of the largest block of zeroed quartets, place "::" */
|
||||
if(i == max_zeroes_off && max_zeroes_len >= 2) {
|
||||
if(off < size) {
|
||||
dst[off++] = ':';
|
||||
}
|
||||
if(off < size) {
|
||||
dst[off++] = ':';
|
||||
}
|
||||
i += max_zeroes_len - 1;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* place a colon if we're not at the beginning of the string and it is not already there */
|
||||
if(off && dst[off - 1] != ':') {
|
||||
if(off < size) {
|
||||
dst[off++] = ':';
|
||||
}
|
||||
}
|
||||
|
||||
off += snprintf(dst + off, size - off, "%x", ptr[0] << 8 | ptr[1]);
|
||||
}
|
||||
|
||||
dst[off] = 0;
|
||||
|
||||
return dst;
|
||||
}
|
||||
default:
|
||||
errno = EAFNOSUPPORT;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
errno = ENOSPC;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int inet_pton(int af, const char *__restrict src, void *__restrict dst) {
|
||||
switch (af) {
|
||||
case AF_INET: {
|
||||
uint8_t array[4] = {};
|
||||
for (int i = 0; i < 4; i++) {
|
||||
char *end;
|
||||
long int value = strtol(src, &end, 10);
|
||||
if (value > 255)
|
||||
return 0;
|
||||
if (*end != '\0' && *end != '.')
|
||||
return 0;
|
||||
src = end + 1;
|
||||
array[i] = value;
|
||||
}
|
||||
auto addr = reinterpret_cast<struct in_addr*>(dst);
|
||||
uint32_t ip = (array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3];
|
||||
addr->s_addr = htonl(ip);
|
||||
break;
|
||||
}
|
||||
case AF_INET6: {
|
||||
size_t i = 0;
|
||||
uint16_t array[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
frg::optional<size_t> doubleColonOffset = frg::null_opt;
|
||||
|
||||
auto reservedRange = [&]() -> bool {
|
||||
if(i && ((doubleColonOffset && doubleColonOffset.value()) || !doubleColonOffset)) {
|
||||
return (ntohs(array[0]) >> 8) == 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
for(; i < 8; i++) {
|
||||
char *end = nullptr;
|
||||
auto value = strtol(src, &end, 16);
|
||||
|
||||
if (value > UINT16_MAX)
|
||||
return 0;
|
||||
if(end[0] != '\0' && end[0] != ':' && end[0] != '.')
|
||||
return 0;
|
||||
|
||||
if(end[0] == '.' && reservedRange() && i < 7) {
|
||||
char *ipv4end = nullptr;
|
||||
auto value0 = strtol(src, &ipv4end, 10);
|
||||
if(ipv4end[0] != '.' || value0 > UINT8_MAX || src == ipv4end)
|
||||
return 0;
|
||||
src = ipv4end + 1;
|
||||
auto value1 = strtol(src, &ipv4end, 10);
|
||||
if(ipv4end[0] != '.' || value1 > UINT8_MAX || src == ipv4end)
|
||||
return 0;
|
||||
array[i++] = htons((value0 << 8) | value1);
|
||||
src = ipv4end + 1;
|
||||
|
||||
auto value2 = strtol(src, &ipv4end, 10);
|
||||
if(ipv4end[0] != '.' || value2 > UINT8_MAX || src == ipv4end)
|
||||
return 0;
|
||||
src = ipv4end + 1;
|
||||
auto value3 = strtol(src, &ipv4end, 10);
|
||||
if(value3 > UINT8_MAX || src == ipv4end)
|
||||
return 0;
|
||||
array[i] = htons((value2 << 8) | value3);
|
||||
break;
|
||||
} else if(end[0] == ':' && end[1] == ':') {
|
||||
if(doubleColonOffset)
|
||||
return 0;
|
||||
doubleColonOffset = i + 1;
|
||||
src = end + 2;
|
||||
} else if(end[0] == ':' || end[0] == '\0') {
|
||||
src = end + 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
array[i] = htons(value);
|
||||
|
||||
if(end[0] == '\0')
|
||||
break;
|
||||
}
|
||||
|
||||
auto addr = reinterpret_cast<struct in6_addr *>(dst);
|
||||
|
||||
if(doubleColonOffset) {
|
||||
size_t suffix = i - doubleColonOffset.value() + 1;
|
||||
memset(addr->s6_addr, 0, 16);
|
||||
|
||||
for(size_t j = 0; j < doubleColonOffset.value(); j++) {
|
||||
addr->s6_addr16[j] = array[j];
|
||||
}
|
||||
|
||||
for(size_t j = 0; j < suffix; j++) {
|
||||
addr->s6_addr16[8 - suffix + j] = array[doubleColonOffset.value() + j];
|
||||
}
|
||||
} else {
|
||||
for(size_t j = 0; j < 8; j++) {
|
||||
addr->s6_addr16[j] = array[j];
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
errno = EAFNOSUPPORT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct in_addr inet_makeaddr(in_addr_t, in_addr_t) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
in_addr_t inet_netof(struct in_addr) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <frg/allocation.hpp>
|
||||
#include <mlibc/allocator.hpp>
|
||||
#include <mlibc/posix-sysdeps.hpp>
|
||||
#include <mlibc/debug.hpp>
|
||||
|
||||
// Code taken from musl
|
||||
int alphasort(const struct dirent **a, const struct dirent **b) {
|
||||
return strcoll((*a)->d_name, (*b)->d_name);
|
||||
}
|
||||
|
||||
int closedir(DIR *dir) {
|
||||
// TODO: Deallocate the dir structure.
|
||||
close(dir->__handle);
|
||||
return 0;
|
||||
}
|
||||
int dirfd(DIR *dir) {
|
||||
return dir->__handle;
|
||||
}
|
||||
DIR *fdopendir(int fd) {
|
||||
struct stat st;
|
||||
|
||||
if(fstat(fd, &st) < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
// Musl implements this, but O_PATH is only declared on the linux abi
|
||||
/*if(fcntl(fd, F_GETFL) & O_PATH) {
|
||||
errno = EBADF;
|
||||
return nullptr;
|
||||
}*/
|
||||
if(!S_ISDIR(st.st_mode)) {
|
||||
errno = ENOTDIR;
|
||||
return nullptr;
|
||||
}
|
||||
auto dir = frg::construct<__mlibc_dir_struct>(getAllocator());
|
||||
__ensure(dir);
|
||||
dir->__ent_next = 0;
|
||||
dir->__ent_limit = 0;
|
||||
int flags = fcntl(fd, F_GETFD);
|
||||
fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
|
||||
dir->__handle = fd;
|
||||
return dir;
|
||||
}
|
||||
DIR *opendir(const char *path) {
|
||||
auto dir = frg::construct<__mlibc_dir_struct>(getAllocator());
|
||||
__ensure(dir);
|
||||
dir->__ent_next = 0;
|
||||
dir->__ent_limit = 0;
|
||||
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_open_dir, nullptr);
|
||||
if(int e = mlibc::sys_open_dir(path, &dir->__handle); e) {
|
||||
errno = e;
|
||||
frg::destruct(getAllocator(), dir);
|
||||
return nullptr;
|
||||
}else{
|
||||
return dir;
|
||||
}
|
||||
}
|
||||
|
||||
struct dirent *readdir(DIR *dir) {
|
||||
__ensure(dir->__ent_next <= dir->__ent_limit);
|
||||
if(dir->__ent_next == dir->__ent_limit) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_read_entries, nullptr);
|
||||
if(int e = mlibc::sys_read_entries(dir->__handle, dir->__ent_buffer, 2048, &dir->__ent_limit); e)
|
||||
__ensure(!"mlibc::sys_read_entries() failed");
|
||||
dir->__ent_next = 0;
|
||||
if(!dir->__ent_limit)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto entp = reinterpret_cast<struct dirent *>(dir->__ent_buffer + dir->__ent_next);
|
||||
// We only copy as many bytes as we need to avoid buffer-overflows.
|
||||
memcpy(&dir->__current, entp, offsetof(struct dirent, d_name) + strlen(entp->d_name) + 1);
|
||||
dir->__ent_next += entp->d_reclen;
|
||||
return &dir->__current;
|
||||
}
|
||||
|
||||
[[gnu::alias("readdir")]] struct dirent64 *readdir64(DIR *dir);
|
||||
|
||||
int readdir_r(DIR *dir, struct dirent *entry, struct dirent **result) {
|
||||
if(!mlibc::sys_read_entries) {
|
||||
MLIBC_MISSING_SYSDEP();
|
||||
return ENOSYS;
|
||||
}
|
||||
|
||||
__ensure(dir->__ent_next <= dir->__ent_limit);
|
||||
if(dir->__ent_next == dir->__ent_limit) {
|
||||
if(int e = mlibc::sys_read_entries(dir->__handle, dir->__ent_buffer, 2048, &dir->__ent_limit); e)
|
||||
__ensure(!"mlibc::sys_read_entries() failed");
|
||||
dir->__ent_next = 0;
|
||||
if(!dir->__ent_limit) {
|
||||
*result = nullptr;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
auto entp = reinterpret_cast<struct dirent *>(dir->__ent_buffer + dir->__ent_next);
|
||||
// We only copy as many bytes as we need to avoid buffer-overflows.
|
||||
memcpy(entry, entp, offsetof(struct dirent, d_name) + strlen(entp->d_name) + 1);
|
||||
dir->__ent_next += entp->d_reclen;
|
||||
*result = entry;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rewinddir(DIR *dir) {
|
||||
lseek(dir->__handle, 0, SEEK_SET);
|
||||
dir->__ent_next = 0;
|
||||
}
|
||||
|
||||
int scandir(const char *path, struct dirent ***res, int (*select)(const struct dirent *),
|
||||
int (*compare)(const struct dirent **, const struct dirent **)) {
|
||||
DIR *dir = opendir(path);
|
||||
if (!dir)
|
||||
return -1; // errno will be set by opendir()
|
||||
|
||||
// we should save the errno
|
||||
int old_errno = errno;
|
||||
errno = 0;
|
||||
|
||||
struct dirent *dir_ent;
|
||||
struct dirent **array = nullptr, **tmp = nullptr;
|
||||
int length = 0;
|
||||
int count = 0;
|
||||
while((dir_ent = readdir(dir)) && !errno) {
|
||||
if(select && !select(dir_ent))
|
||||
continue;
|
||||
|
||||
if(count >= length) {
|
||||
length = 2*length + 1;
|
||||
tmp = static_cast<struct dirent**>(realloc(array,
|
||||
length * sizeof(struct dirent*)));
|
||||
// we need to check the call actually goes through
|
||||
// before we overwrite array so that we can
|
||||
// deallocate the already written entries should realloc()
|
||||
// have failed
|
||||
if(!tmp)
|
||||
break;
|
||||
array = tmp;
|
||||
}
|
||||
array[count] = static_cast<struct dirent*>(malloc(dir_ent->d_reclen));
|
||||
if(!array[count])
|
||||
break;
|
||||
|
||||
memcpy(array[count], dir_ent, dir_ent->d_reclen);
|
||||
count++;
|
||||
}
|
||||
|
||||
if(errno) {
|
||||
if(array)
|
||||
while(count-- > 0)
|
||||
free(array[count]);
|
||||
free(array);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// from here we can set the old errno back
|
||||
errno = old_errno;
|
||||
|
||||
if(compare)
|
||||
qsort(array, count, sizeof(struct dirent*),
|
||||
(int (*)(const void *, const void *)) compare);
|
||||
*res = array;
|
||||
return count;
|
||||
}
|
||||
void seekdir(DIR *, long) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
long telldir(DIR *) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
int versionsort(const struct dirent **a, const struct dirent **b) {
|
||||
return strverscmp((*a)->d_name, (*b)->d_name);
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include <mlibc/debug.hpp>
|
||||
|
||||
struct __dlapi_symbol {
|
||||
const char *file;
|
||||
void *base;
|
||||
const char *symbol;
|
||||
void *address;
|
||||
const void *elf_symbol;
|
||||
void *link_map;
|
||||
};
|
||||
|
||||
extern "C" const char *__dlapi_error();
|
||||
extern "C" void *__dlapi_open(const char *, int, void *);
|
||||
extern "C" void *__dlapi_resolve(void *, const char *, void *, const char *);
|
||||
extern "C" int __dlapi_reverse(const void *, __dlapi_symbol *);
|
||||
extern "C" int __dlapi_close(void *);
|
||||
extern "C" int __dlapi_find_object(void *__address, dl_find_object *__result);
|
||||
|
||||
int dlclose(void *handle) {
|
||||
return __dlapi_close(handle);
|
||||
}
|
||||
|
||||
char *dlerror(void) {
|
||||
return const_cast<char *>(__dlapi_error());
|
||||
}
|
||||
|
||||
[[gnu::noinline]]
|
||||
void *dlopen(const char *file, int flags) {
|
||||
auto ra = __builtin_extract_return_addr(__builtin_return_address(0));
|
||||
return __dlapi_open(file, flags, ra);
|
||||
}
|
||||
|
||||
[[gnu::noinline]]
|
||||
void *dlsym(void *__restrict handle, const char *__restrict string) {
|
||||
auto ra = __builtin_extract_return_addr(__builtin_return_address(0));
|
||||
return __dlapi_resolve(handle, string, ra, nullptr);
|
||||
}
|
||||
|
||||
[[gnu::noinline]]
|
||||
void *dlvsym(void *__restrict handle, const char *__restrict string, const char *__restrict version) {
|
||||
auto ra = __builtin_extract_return_addr(__builtin_return_address(0));
|
||||
return __dlapi_resolve(handle, string, ra, version);
|
||||
}
|
||||
|
||||
//gnu extensions
|
||||
|
||||
#if __MLIBC_GLIBC_OPTION
|
||||
|
||||
int dladdr(const void *ptr, Dl_info *out) {
|
||||
__dlapi_symbol info;
|
||||
if(__dlapi_reverse(ptr, &info))
|
||||
return 0;
|
||||
|
||||
out->dli_fname = info.file;
|
||||
out->dli_fbase = info.base;
|
||||
out->dli_sname = info.symbol;
|
||||
out->dli_saddr = info.address;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dladdr1(const void *ptr, Dl_info *out, void **extra, int flags) {
|
||||
__dlapi_symbol info;
|
||||
if(__dlapi_reverse(ptr, &info)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
out->dli_fname = info.file;
|
||||
out->dli_fbase = info.base;
|
||||
out->dli_sname = info.symbol;
|
||||
out->dli_saddr = info.address;
|
||||
|
||||
switch(flags) {
|
||||
case RTLD_DL_SYMENT:
|
||||
*const_cast<const void **>(extra) = info.elf_symbol;
|
||||
break;
|
||||
case RTLD_DL_LINKMAP:
|
||||
*extra = info.link_map;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dlinfo(void *__restrict, int, void *__restrict) {
|
||||
__ensure(!"dlinfo() not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
int _dl_find_object(void *address, struct dl_find_object *result) {
|
||||
return __dlapi_find_object(address, result);
|
||||
}
|
||||
|
||||
#endif // __MLIBC_GLIBC_OPTION
|
||||
@@ -0,0 +1,118 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <bits/ensure.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/posix-sysdeps.hpp>
|
||||
|
||||
int creat(const char *pathname, mode_t mode) {
|
||||
return open(pathname, O_CREAT|O_WRONLY|O_TRUNC, mode);
|
||||
}
|
||||
|
||||
int fallocate(int, int, off_t, off_t) {
|
||||
mlibc::infoLogger() << "mlibc: fallocate() is a no-op" << frg::endlog;
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fcntl(int fd, int command, ...) {
|
||||
va_list args;
|
||||
va_start(args, command);
|
||||
int result;
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fcntl, -1);
|
||||
if(int e = mlibc::sys_fcntl(fd, command, args, &result); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
va_end(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
int openat(int dirfd, const char *pathname, int flags, ...) {
|
||||
va_list args;
|
||||
va_start(args, flags);
|
||||
mode_t mode = 0;
|
||||
int fd;
|
||||
|
||||
if((flags & (O_CREAT | O_TMPFILE)))
|
||||
mode = va_arg(args, mode_t);
|
||||
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_openat, -1);
|
||||
if(int e = mlibc::sys_openat(dirfd, pathname, flags, mode, &fd); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
va_end(args);
|
||||
return fd;
|
||||
}
|
||||
|
||||
int posix_fadvise(int fd, off_t offset, off_t length, int advice) {
|
||||
if(!mlibc::sys_fadvise) {
|
||||
mlibc::infoLogger() << "mlibc: fadvise() ignored due to missing sysdep" << frg::endlog;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// posix_fadvise() returns an error instead of setting errno.
|
||||
return mlibc::sys_fadvise(fd, offset, length, advice);
|
||||
}
|
||||
|
||||
int posix_fallocate(int fd, off_t offset, off_t size) {
|
||||
// posix_fallocate() returns an error instead of setting errno.
|
||||
if(!mlibc::sys_fallocate) {
|
||||
MLIBC_MISSING_SYSDEP();
|
||||
return ENOSYS;
|
||||
}
|
||||
return mlibc::sys_fallocate(fd, offset, size);
|
||||
}
|
||||
|
||||
// This is a linux extension
|
||||
int name_to_handle_at(int dirfd, const char *pathname, struct file_handle *handle, int *mount_id, int flags) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_name_to_handle_at, -1);
|
||||
if(int e = mlibc::sys_name_to_handle_at(dirfd, pathname, handle, mount_id, flags); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int open_by_handle_at(int, struct file_handle *, int) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
ssize_t splice(int in_fd, off_t *in_off, int out_fd, off_t *out_off, size_t size, unsigned int flags) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_splice, -1);
|
||||
ssize_t ret;
|
||||
if(int e = mlibc::sys_splice(in_fd, in_off, out_fd, out_off, size, flags, &ret); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t vmsplice(int, const struct iovec *, size_t, unsigned int) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
int open(const char *pathname, int flags, ...) {
|
||||
mode_t mode = 0;
|
||||
|
||||
if ((flags & O_CREAT) || (flags & O_TMPFILE)) {
|
||||
va_list args;
|
||||
va_start(args, flags);
|
||||
mode = va_arg(args, mode_t);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
int fd;
|
||||
if(int e = mlibc::sys_open(pathname, flags, mode, &fd); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
[[gnu::alias("open")]] int open64(const char *pathname, int flags, ...);
|
||||
@@ -0,0 +1,18 @@
|
||||
|
||||
#include <ftw.h>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
|
||||
int ftw(const char *, int (*fn)(const char *, const struct stat *, int), int) {
|
||||
(void)fn;
|
||||
__ensure(!"ftw() not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
int nftw(const char *, int (*fn)(const char *, const struct stat *, int, struct FTW *),
|
||||
int, int) {
|
||||
(void)fn;
|
||||
__ensure(!"nftw() not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,386 @@
|
||||
|
||||
#include <grp.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <bits/ensure.h>
|
||||
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/posix-sysdeps.hpp>
|
||||
|
||||
namespace {
|
||||
FILE *global_file;
|
||||
|
||||
bool open_global_file() {
|
||||
if(!global_file) {
|
||||
global_file = fopen("/etc/group", "r");
|
||||
if(!global_file) {
|
||||
errno = EIO;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void close_global_file() {
|
||||
if(global_file) {
|
||||
fclose(global_file);
|
||||
global_file = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
void walk_segments(frg::string_view line, char delimiter, F fn) {
|
||||
size_t s = 0;
|
||||
while(true) {
|
||||
size_t d = line.find_first(delimiter, s);
|
||||
if(d == size_t(-1))
|
||||
break;
|
||||
auto chunk = line.sub_string(s, d - s);
|
||||
fn(chunk);
|
||||
s = d + 1;
|
||||
}
|
||||
if(line[s]) {
|
||||
auto chunk = line.sub_string(s, line.size() - s);
|
||||
|
||||
if (chunk.size() > 0) {
|
||||
// Remove trailing newline
|
||||
if (chunk[chunk.size() - 1] == '\n')
|
||||
chunk = chunk.sub_string(0, chunk.size() - 1);
|
||||
|
||||
fn(chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool extract_entry(frg::string_view line, group *entry) {
|
||||
frg::string_view segments[5];
|
||||
|
||||
// Parse the line into 3 or 4 segments (depending if the group has members or not)
|
||||
int n = 0;
|
||||
walk_segments(line, ':', [&] (frg::string_view s) {
|
||||
__ensure(n < 4);
|
||||
segments[n++] = s;
|
||||
});
|
||||
|
||||
if(n < 3) // n can be 3 when there are no members in the group
|
||||
return false;
|
||||
|
||||
// TODO: Handle strndup() and malloc() failure.
|
||||
auto name = strndup(segments[0].data(), segments[0].size());
|
||||
__ensure(name);
|
||||
|
||||
auto passwd = strndup(segments[1].data(), segments[1].size());
|
||||
|
||||
auto gid = segments[2].to_number<int>();
|
||||
if(!gid)
|
||||
return false;
|
||||
|
||||
size_t n_members = 0;
|
||||
walk_segments(segments[3], ',', [&] (frg::string_view) {
|
||||
n_members++;
|
||||
});
|
||||
|
||||
auto members = reinterpret_cast<char **>(malloc(sizeof(char *) * (n_members + 1)));
|
||||
__ensure(members);
|
||||
size_t k = 0;
|
||||
walk_segments(segments[3], ',', [&] (frg::string_view m) {
|
||||
members[k] = strndup(m.data(), m.size());
|
||||
__ensure(members[k]);
|
||||
k++;
|
||||
});
|
||||
members[k] = nullptr;
|
||||
|
||||
entry->gr_name = name;
|
||||
entry->gr_passwd = passwd;
|
||||
entry->gr_gid = *gid;
|
||||
entry->gr_mem = members;
|
||||
return true;
|
||||
}
|
||||
|
||||
void clear_entry(group *entry) {
|
||||
free(entry->gr_name);
|
||||
if(entry->gr_mem) {
|
||||
for(size_t i = 0; entry->gr_mem[i]; i++)
|
||||
free(entry->gr_mem[i]);
|
||||
free(entry->gr_mem);
|
||||
}
|
||||
entry->gr_name = nullptr;
|
||||
entry->gr_mem = nullptr;
|
||||
}
|
||||
|
||||
template<typename C>
|
||||
int walk_file(struct group *entry, C cond) {
|
||||
auto file = fopen("/etc/group", "r");
|
||||
if(!file) {
|
||||
return EIO;
|
||||
}
|
||||
|
||||
char line[512];
|
||||
while(fgets(line, 512, file)) {
|
||||
if(!extract_entry(line, entry))
|
||||
continue;
|
||||
if(cond(entry)) {
|
||||
fclose(file);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int err = ESRCH;
|
||||
if(ferror(file)) {
|
||||
err = EIO;
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
return err;
|
||||
}
|
||||
|
||||
int copy_to_buffer(struct group *grp, char *buffer, size_t size) {
|
||||
// Adjust to correct alignment so that we can put gr_mem first in buffer
|
||||
uintptr_t mask = sizeof(char *) - 1;
|
||||
size_t offset = (reinterpret_cast<uintptr_t>(buffer) % sizeof(char *) + mask) & ~mask;
|
||||
if (size < offset)
|
||||
return ERANGE;
|
||||
|
||||
buffer += offset;
|
||||
size -= offset;
|
||||
|
||||
// Calculate the amount of space we need
|
||||
size_t nmemb, required_size = 0;
|
||||
for (nmemb = 0; grp->gr_mem[nmemb] != nullptr; nmemb++) {
|
||||
// One for the string's null terminator and one for the pointer in gr_mem
|
||||
required_size += strlen(grp->gr_mem[nmemb]) + 1 + sizeof(char *);
|
||||
}
|
||||
|
||||
// One for null terminator of gr_name, plus sizeof(char *) for nullptr terminator of gr_mem
|
||||
required_size += strlen(grp->gr_name) + 1 + sizeof(char *);
|
||||
if (size < required_size)
|
||||
return ERANGE;
|
||||
|
||||
// Put the gr_mem array first in the buffer as we are guaranteed
|
||||
// that the pointer is aligned correctly
|
||||
char *string_data = buffer + (nmemb + 1) * sizeof(char *);
|
||||
|
||||
for (size_t i = 0; i < nmemb; i++) {
|
||||
reinterpret_cast<char **>(buffer)[i] = string_data;
|
||||
string_data = stpcpy(string_data, grp->gr_mem[i]) + 1;
|
||||
free(grp->gr_mem[i]);
|
||||
}
|
||||
|
||||
reinterpret_cast<char **>(buffer)[nmemb] = nullptr;
|
||||
free(grp->gr_mem);
|
||||
grp->gr_mem = reinterpret_cast<char **>(buffer);
|
||||
|
||||
char *gr_name = stpcpy(string_data, grp->gr_name) + 1;
|
||||
free(grp->gr_name);
|
||||
grp->gr_name = string_data;
|
||||
|
||||
__ensure(gr_name <= buffer + size);
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void endgrent(void) {
|
||||
close_global_file();
|
||||
}
|
||||
|
||||
struct group *getgrent(void) {
|
||||
static group entry;
|
||||
char line[512];
|
||||
|
||||
if(!open_global_file()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if(fgets(line, 512, global_file)) {
|
||||
clear_entry(&entry);
|
||||
if(!extract_entry(line, &entry)) {
|
||||
errno = EINVAL;
|
||||
return nullptr;
|
||||
}
|
||||
return &entry;
|
||||
}
|
||||
|
||||
if(ferror(global_file)) {
|
||||
errno = EIO;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
struct group *getgrgid(gid_t gid) {
|
||||
static group entry;
|
||||
|
||||
int err = walk_file(&entry, [&] (group *entry) {
|
||||
return entry->gr_gid == gid;
|
||||
});
|
||||
|
||||
if (err) {
|
||||
errno = err;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &entry;
|
||||
}
|
||||
|
||||
int getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t size, struct group **result) {
|
||||
*result = nullptr;
|
||||
int err = walk_file(grp, [&] (group *entry) {
|
||||
return entry->gr_gid == gid;
|
||||
});
|
||||
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = copy_to_buffer(grp, buffer, size);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
*result = grp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct group *getgrnam(const char *name) {
|
||||
static group entry;
|
||||
|
||||
int err = walk_file(&entry, [&] (group *entry) {
|
||||
return !strcmp(entry->gr_name, name);
|
||||
});
|
||||
|
||||
if (err) {
|
||||
errno = err;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &entry;
|
||||
}
|
||||
|
||||
int getgrnam_r(const char *name, struct group *grp, char *buffer, size_t size, struct group **result) {
|
||||
*result = nullptr;
|
||||
|
||||
int err = walk_file(grp, [&] (group *entry) {
|
||||
return !strcmp(entry->gr_name, name);
|
||||
});
|
||||
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = copy_to_buffer(grp, buffer, size);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
*result = grp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void setgrent(void) {
|
||||
if(!open_global_file()) {
|
||||
return;
|
||||
}
|
||||
rewind(global_file);
|
||||
}
|
||||
|
||||
int setgroups(size_t size, const gid_t *list) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setgroups, -1);
|
||||
if(int e = mlibc::sys_setgroups(size, list); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int initgroups(const char *, gid_t) {
|
||||
mlibc::infoLogger() << "mlibc: initgroups is a stub" << frg::endlog;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int putgrent(const struct group *g, FILE *f) {
|
||||
auto invalid = [](const char *s) {
|
||||
return s == nullptr || strchr(s, '\n') || strchr(s, ':');
|
||||
};
|
||||
|
||||
if(g == nullptr || invalid(g->gr_name) || invalid(g->gr_passwd)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(int i = 0; g->gr_mem != nullptr && g->gr_mem[i] != nullptr; ++i) {
|
||||
if (invalid(g->gr_mem[i])) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Taken from musl.
|
||||
flockfile(f);
|
||||
|
||||
int r = fprintf(f, "%s:%s:%u:", g->gr_name, g->gr_passwd, g->gr_gid);
|
||||
if(r < 0)
|
||||
goto leave;
|
||||
|
||||
for(int i = 0; g->gr_mem != nullptr && g->gr_mem[i] != nullptr; ++i) {
|
||||
r = fprintf(f, "%s%s", i ? "," : "", g->gr_mem[i]);
|
||||
if(r < 0)
|
||||
goto leave;
|
||||
}
|
||||
|
||||
r = fputc('\n', f);
|
||||
|
||||
leave:
|
||||
funlockfile(f);
|
||||
return r < 0 ? -1 : 0;
|
||||
}
|
||||
|
||||
struct group *fgetgrent(FILE *file) {
|
||||
static group entry;
|
||||
char line[512];
|
||||
|
||||
if(fgets(line, 512, file)) {
|
||||
clear_entry(&entry);
|
||||
if(!extract_entry(line, &entry)) {
|
||||
errno = EINVAL;
|
||||
return nullptr;
|
||||
}
|
||||
return &entry;
|
||||
}
|
||||
|
||||
if(ferror(file)) {
|
||||
errno = EIO;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int getgrouplist(const char *user, gid_t gid, gid_t *groups, int *ngroups) {
|
||||
int n = 1;
|
||||
int n_limit = *ngroups;
|
||||
struct group grp;
|
||||
|
||||
if(n_limit >= 1)
|
||||
*groups++ = gid;
|
||||
|
||||
int err = walk_file(&grp, [&] (group *entry) {
|
||||
size_t i = 0;
|
||||
for(; entry->gr_mem[i] && strcmp(user, entry->gr_mem[i]); i++);
|
||||
if(!entry->gr_mem[i])
|
||||
return false;
|
||||
if(++n <= n_limit)
|
||||
*groups++ = entry->gr_gid;
|
||||
return false;
|
||||
});
|
||||
|
||||
if(err != ESRCH) {
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*ngroups = n;
|
||||
|
||||
return (n > n_limit) ? -1 : n;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
#include <langinfo.h>
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/locale.hpp>
|
||||
|
||||
char *nl_langinfo(nl_item item) {
|
||||
return mlibc::nl_langinfo(item);
|
||||
}
|
||||
|
||||
char *nl_langinfo_l(nl_item, locale_t) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <libgen.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <mlibc/debug.hpp>
|
||||
|
||||
// Adopted from musl's code.
|
||||
char *basename(char *s) {
|
||||
// This empty string behavior is specified by POSIX.
|
||||
if (!s || !*s)
|
||||
return const_cast<char *>(".");
|
||||
|
||||
// Delete trailing slashes.
|
||||
// Note that we do not delete the slash at index zero.
|
||||
auto i = strlen(s) - 1;
|
||||
for(; i && s[i] == '/'; i--)
|
||||
s[i] = 0;
|
||||
|
||||
// Find the last non-trailing slash.
|
||||
for(; i && s[i - 1] != '/'; i--)
|
||||
;
|
||||
return s + i;
|
||||
}
|
||||
|
||||
char *dirname(char *s) {
|
||||
if (!s || !(*s))
|
||||
return const_cast<char *>(".");
|
||||
|
||||
auto i = strlen(s) - 1;
|
||||
|
||||
// Skip trailing slashes.
|
||||
for (; s[i] == '/'; i--)
|
||||
if(!i) // Path only consists of slashes.
|
||||
return const_cast<char *>("/");
|
||||
|
||||
// Skip the last non-slash path component.
|
||||
for (; s[i] != '/'; i--)
|
||||
if(!i) // Path only contains a single component.
|
||||
return const_cast<char *>(".");
|
||||
|
||||
// Skip slashes.
|
||||
for (; s[i] == '/'; i--)
|
||||
if(!i) // Path is entry in root directory.
|
||||
return const_cast<char *>("/");
|
||||
|
||||
s[i+1] = 0;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,548 @@
|
||||
#include <mlibc/lookup.hpp>
|
||||
#include <mlibc/resolv_conf.hpp>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/services.hpp>
|
||||
#include <bits/ensure.h>
|
||||
|
||||
#include <frg/string.hpp>
|
||||
#include <mlibc/allocator.hpp>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
namespace {
|
||||
constexpr unsigned short RETURN_NOERROR [[maybe_unused]] = 0x0;
|
||||
constexpr unsigned short RETURN_NXDOMAIN = 0x3;
|
||||
|
||||
constexpr unsigned int RECORD_A = 1;
|
||||
constexpr unsigned int RECORD_CNAME = 5;
|
||||
constexpr unsigned int RECORD_PTR = 12;
|
||||
constexpr unsigned int RECORD_AAAA = 28;
|
||||
} // namespace
|
||||
|
||||
static frg::string<MemoryAllocator> read_dns_name(char *buf, char *&it) {
|
||||
frg::string<MemoryAllocator> res{getAllocator()};
|
||||
while (true) {
|
||||
char code = *it++;
|
||||
if ((code & 0xC0) == 0xC0) {
|
||||
// pointer
|
||||
uint8_t offset = ((code & 0x3F) << 8) | *it++;
|
||||
auto offset_it = buf + offset;
|
||||
return res + read_dns_name(buf, offset_it);
|
||||
} else if (!(code & 0xC0)) {
|
||||
if (!code)
|
||||
break;
|
||||
|
||||
for (int i = 0; i < code; i++)
|
||||
res += (*it++);
|
||||
|
||||
if (*it)
|
||||
res += '.';
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int lookup_name_dns(struct lookup_result &buf, const char *name,
|
||||
frg::string<MemoryAllocator> &canon_name, int family) {
|
||||
frg::string<MemoryAllocator> request{getAllocator()};
|
||||
|
||||
int num_q = 1;
|
||||
struct dns_header header;
|
||||
header.identification = htons(123);
|
||||
header.flags = htons(0x100);
|
||||
header.no_q = htons(num_q);
|
||||
header.no_ans = htons(0);
|
||||
header.no_auths = htons(0);
|
||||
header.no_additional = htons(0);
|
||||
|
||||
request.resize(sizeof(header));
|
||||
memcpy(request.data(), &header, sizeof(header));
|
||||
|
||||
const char *end = name;
|
||||
while (*end != '\0') {
|
||||
end = strchrnul(name, '.');
|
||||
size_t length = end - name;
|
||||
frg::string_view substring{name, length};
|
||||
name += length + 1;
|
||||
request += char(length);
|
||||
request += substring;
|
||||
}
|
||||
|
||||
request += char(0);
|
||||
// set question type to fetch A or AAAA records
|
||||
uint16_t qtype = RECORD_A;
|
||||
if (family == AF_INET6)
|
||||
qtype = RECORD_AAAA;
|
||||
|
||||
request += qtype >> 8;
|
||||
request += qtype & 0xFF;
|
||||
// set CLASS to IN
|
||||
request += 0;
|
||||
request += 1;
|
||||
|
||||
mlibc::service_result serv_buf{getAllocator()};
|
||||
int serv_count = mlibc::lookup_serv_by_name(serv_buf, "domain", IPPROTO_UDP, SOCK_DGRAM, 0);
|
||||
if (serv_count < 0) {
|
||||
mlibc::infoLogger() << "mlibc: could not resolve DNS service" << frg::endlog;
|
||||
return -EAI_SERVICE;
|
||||
}
|
||||
|
||||
struct sockaddr_in sin = {};
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(serv_buf[0].port);
|
||||
|
||||
auto nameserver = get_nameserver();
|
||||
if (!inet_aton(nameserver ? nameserver->name.data() : "127.0.0.1", &sin.sin_addr)) {
|
||||
mlibc::infoLogger() << "lookup_name_dns(): inet_aton() failed!" << frg::endlog;
|
||||
return -EAI_SYSTEM;
|
||||
}
|
||||
|
||||
int fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd < 0) {
|
||||
mlibc::infoLogger() << "lookup_name_dns(): socket() failed" << frg::endlog;
|
||||
return -EAI_SYSTEM;
|
||||
}
|
||||
|
||||
size_t sent = sendto(fd, request.data(), request.size(), 0,
|
||||
(struct sockaddr*)&sin, sizeof(sin));
|
||||
if (sent != request.size()) {
|
||||
mlibc::infoLogger() << "lookup_name_dns(): sendto() failed to send everything" << frg::endlog;
|
||||
return -EAI_SYSTEM;
|
||||
}
|
||||
|
||||
char response[256];
|
||||
ssize_t rlen;
|
||||
int num_ans = 0;
|
||||
while ((rlen = recvfrom(fd, response, 256, 0, nullptr, nullptr)) >= 0) {
|
||||
if ((size_t)rlen < sizeof(struct dns_header))
|
||||
continue;
|
||||
auto response_header = reinterpret_cast<struct dns_header*>(response);
|
||||
if (response_header->identification != header.identification)
|
||||
return -EAI_FAIL;
|
||||
|
||||
if ((ntohs(response_header->flags) & 0xF) == RETURN_NXDOMAIN)
|
||||
return -EAI_NONAME;
|
||||
|
||||
auto it = response + sizeof(struct dns_header);
|
||||
for (int i = 0; i < ntohs(response_header->no_q); i++) {
|
||||
auto dns_name = read_dns_name(response, it);
|
||||
(void) dns_name;
|
||||
it += 4;
|
||||
}
|
||||
|
||||
for (int i = 0; i < ntohs(response_header->no_ans); i++) {
|
||||
struct dns_addr_buf buffer;
|
||||
auto dns_name = read_dns_name(response, it);
|
||||
|
||||
uint16_t rr_type = (it[0] << 8) | it[1];
|
||||
uint16_t rr_class = (it[2] << 8) | it[3];
|
||||
uint16_t rr_length = (it[8] << 8) | it[9];
|
||||
it += 10;
|
||||
(void)rr_class;
|
||||
|
||||
switch (rr_type) {
|
||||
case RECORD_A:
|
||||
if (family != AF_UNSPEC && family != AF_INET)
|
||||
continue;
|
||||
|
||||
memcpy(buffer.addr, it, rr_length);
|
||||
it += rr_length;
|
||||
buffer.family = AF_INET;
|
||||
buffer.name = std::move(dns_name);
|
||||
buf.buf.push(std::move(buffer));
|
||||
break;
|
||||
case RECORD_AAAA:
|
||||
if (family != AF_UNSPEC && family != AF_INET6)
|
||||
continue;
|
||||
|
||||
memcpy(buffer.addr, it, rr_length);
|
||||
it += rr_length;
|
||||
buffer.family = AF_INET6;
|
||||
buffer.name = std::move(dns_name);
|
||||
buf.buf.push(std::move(buffer));
|
||||
break;
|
||||
case RECORD_CNAME:
|
||||
canon_name = read_dns_name(response, it);
|
||||
buf.aliases.push(std::move(dns_name));
|
||||
break;
|
||||
default:
|
||||
mlibc::infoLogger() << "lookup_name_dns: unknown rr type "
|
||||
<< rr_type << frg::endlog;
|
||||
break;
|
||||
}
|
||||
}
|
||||
num_ans += ntohs(response_header->no_ans);
|
||||
|
||||
if (num_ans >= num_q)
|
||||
break;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return buf.buf.size();
|
||||
}
|
||||
|
||||
int lookup_addr_dns(frg::span<char> name, frg::array<uint8_t, 16> &addr, int family) {
|
||||
frg::string<MemoryAllocator> request{getAllocator()};
|
||||
|
||||
int num_q = 1;
|
||||
struct dns_header header;
|
||||
header.identification = htons(123);
|
||||
header.flags = htons(0x100);
|
||||
header.no_q = htons(num_q);
|
||||
header.no_ans = htons(0);
|
||||
header.no_auths = htons(0);
|
||||
header.no_additional = htons(0);
|
||||
|
||||
request.resize(sizeof(header));
|
||||
memcpy(request.data(), &header, sizeof(header));
|
||||
|
||||
char addr_str[64];
|
||||
if(!inet_ntop(family, addr.data(), addr_str, sizeof(addr_str))) {
|
||||
switch(errno) {
|
||||
case EAFNOSUPPORT:
|
||||
return -EAI_FAMILY;
|
||||
case ENOSPC:
|
||||
return -EAI_OVERFLOW;
|
||||
default:
|
||||
return -EAI_FAIL;
|
||||
}
|
||||
}
|
||||
frg::string<MemoryAllocator> req_str{getAllocator(), addr_str};
|
||||
req_str += ".in-addr.arpa";
|
||||
|
||||
frg::string_view req_view{req_str.data(), req_str.size()};
|
||||
size_t ptr = 0;
|
||||
do {
|
||||
size_t next = req_view.find_first('.', ptr);
|
||||
size_t length = next != (size_t)-1 ? next - ptr : req_view.size() - ptr;
|
||||
frg::string_view substring = req_view.sub_string(ptr, length);
|
||||
request += char(length);
|
||||
request += substring;
|
||||
ptr = next + 1;
|
||||
} while(ptr != 0);
|
||||
|
||||
request += char(0);
|
||||
// set question type to fetch PTR records
|
||||
request += 0;
|
||||
request += 12;
|
||||
// set CLASS to IN
|
||||
request += 0;
|
||||
request += 1;
|
||||
|
||||
mlibc::service_result serv_buf{getAllocator()};
|
||||
int serv_count = mlibc::lookup_serv_by_name(serv_buf, "domain", IPPROTO_UDP, SOCK_DGRAM, 0);
|
||||
if (serv_count < 0) {
|
||||
mlibc::infoLogger() << "mlibc: could not resolve DNS service" << frg::endlog;
|
||||
return -EAI_SERVICE;
|
||||
}
|
||||
|
||||
struct sockaddr_in sin = {};
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(serv_buf[0].port);
|
||||
|
||||
auto nameserver = get_nameserver();
|
||||
if (!inet_aton(nameserver ? nameserver->name.data() : "127.0.0.1", &sin.sin_addr)) {
|
||||
mlibc::infoLogger() << "lookup_name_dns(): inet_aton() failed!" << frg::endlog;
|
||||
return -EAI_SYSTEM;
|
||||
}
|
||||
|
||||
int fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd < 0) {
|
||||
mlibc::infoLogger() << "lookup_name_dns(): socket() failed" << frg::endlog;
|
||||
return -EAI_SYSTEM;
|
||||
}
|
||||
|
||||
size_t sent = sendto(fd, request.data(), request.size(), 0,
|
||||
(struct sockaddr*)&sin, sizeof(sin));
|
||||
if (sent != request.size()) {
|
||||
mlibc::infoLogger() << "lookup_name_dns(): sendto() failed to send everything" << frg::endlog;
|
||||
return -EAI_SYSTEM;
|
||||
}
|
||||
|
||||
char response[256];
|
||||
ssize_t rlen;
|
||||
int num_ans = 0;
|
||||
while ((rlen = recvfrom(fd, response, 256, 0, nullptr, nullptr)) >= 0) {
|
||||
if ((size_t)rlen < sizeof(struct dns_header))
|
||||
continue;
|
||||
auto response_header = reinterpret_cast<struct dns_header*>(response);
|
||||
if (response_header->identification != header.identification)
|
||||
return -EAI_FAIL;
|
||||
|
||||
auto it = response + sizeof(struct dns_header);
|
||||
for (int i = 0; i < ntohs(response_header->no_q); i++) {
|
||||
auto dns_name = read_dns_name(response, it);
|
||||
(void) dns_name;
|
||||
it += 4;
|
||||
}
|
||||
|
||||
for (int i = 0; i < ntohs(response_header->no_ans); i++) {
|
||||
struct dns_addr_buf buffer;
|
||||
auto dns_name = read_dns_name(response, it);
|
||||
|
||||
uint16_t rr_type = (it[0] << 8) | it[1];
|
||||
uint16_t rr_class = (it[2] << 8) | it[3];
|
||||
uint16_t rr_length = (it[8] << 8) | it[9];
|
||||
it += 10;
|
||||
(void)rr_class;
|
||||
(void)rr_length;
|
||||
|
||||
(void)dns_name;
|
||||
|
||||
switch (rr_type) {
|
||||
case RECORD_PTR: {
|
||||
auto ptr_name = read_dns_name(response, it);
|
||||
if (ptr_name.size() >= name.size())
|
||||
return -EAI_OVERFLOW;
|
||||
std::copy(ptr_name.begin(), ptr_name.end(), name.data());
|
||||
name.data()[ptr_name.size()] = '\0';
|
||||
return 1;
|
||||
}
|
||||
default:
|
||||
mlibc::infoLogger() << "lookup_addr_dns: unknown rr type "
|
||||
<< rr_type << frg::endlog;
|
||||
break;
|
||||
}
|
||||
num_ans += ntohs(response_header->no_ans);
|
||||
|
||||
if (num_ans >= num_q)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lookup_name_hosts(struct lookup_result &buf, const char *name,
|
||||
frg::string<MemoryAllocator> &canon_name, int family) {
|
||||
auto file = fopen("/etc/hosts", "r");
|
||||
if (!file) {
|
||||
switch (errno) {
|
||||
case ENOENT:
|
||||
case ENOTDIR:
|
||||
case EACCES:
|
||||
return -EAI_SERVICE;
|
||||
default:
|
||||
return -EAI_SYSTEM;
|
||||
}
|
||||
}
|
||||
|
||||
char line[128];
|
||||
int name_length = strlen(name);
|
||||
while (fgets(line, 128, file)) {
|
||||
char *pos;
|
||||
// same way to deal with comments as in services.cpp
|
||||
if ((pos = strchr(line, '#'))) {
|
||||
*pos++ = '\n';
|
||||
*pos = '\0';
|
||||
}
|
||||
|
||||
for(pos = line + 1; (pos = strstr(pos, name)) &&
|
||||
(!isspace(pos[-1]) || !isspace(pos[name_length])); pos++);
|
||||
if (!pos)
|
||||
continue;
|
||||
|
||||
for (pos = line; !isspace(*pos); pos++);
|
||||
*pos = '\0';
|
||||
|
||||
struct dns_addr_buf buffer;
|
||||
|
||||
if ((family == AF_UNSPEC || family == AF_INET) && inet_pton(AF_INET, line, buffer.addr)) {
|
||||
buffer.family = AF_INET;
|
||||
} else if((family == AF_UNSPEC || family == AF_INET6) && inet_pton(AF_INET6, line, buffer.addr)) {
|
||||
buffer.family = AF_INET6;
|
||||
} else {
|
||||
continue; // not a valid address
|
||||
}
|
||||
|
||||
pos++;
|
||||
for(; *pos && isspace(*pos); pos++);
|
||||
char *end;
|
||||
for(end = pos; *end && !isspace(*end); end++);
|
||||
|
||||
buffer.name = frg::string<MemoryAllocator>{pos,
|
||||
static_cast<size_t>(end - pos), getAllocator()};
|
||||
canon_name = buffer.name;
|
||||
|
||||
buf.buf.push(std::move(buffer));
|
||||
|
||||
pos = end;
|
||||
while (pos[1]) {
|
||||
for (; *pos && isspace(*pos); pos++);
|
||||
for (end = pos; *end && !isspace(*end); end++);
|
||||
auto name = frg::string<MemoryAllocator>{pos,
|
||||
static_cast<size_t>(end - pos), getAllocator()};
|
||||
buf.aliases.push(std::move(name));
|
||||
pos = end;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
return buf.buf.size();
|
||||
}
|
||||
|
||||
int lookup_addr_hosts(frg::span<char> name, frg::array<uint8_t, 16> &addr, int family) {
|
||||
auto file = fopen("/etc/hosts", "r");
|
||||
if (!file) {
|
||||
switch (errno) {
|
||||
case ENOENT:
|
||||
case ENOTDIR:
|
||||
case EACCES:
|
||||
return -EAI_SERVICE;
|
||||
default:
|
||||
return -EAI_SYSTEM;
|
||||
}
|
||||
}
|
||||
|
||||
// Buffer to hold ASCII version of address
|
||||
char addr_str[64];
|
||||
if(!inet_ntop(family, addr.data(), addr_str, sizeof(addr_str))) {
|
||||
switch(errno) {
|
||||
case EAFNOSUPPORT:
|
||||
return -EAI_FAMILY;
|
||||
case ENOSPC:
|
||||
return -EAI_OVERFLOW;
|
||||
default:
|
||||
return -EAI_FAIL;
|
||||
}
|
||||
}
|
||||
int addr_str_len = strlen(addr_str);
|
||||
|
||||
char line[128];
|
||||
while (fgets(line, 128, file)) {
|
||||
char *pos;
|
||||
// same way to deal with comments as in services.cpp
|
||||
if ((pos = strchr(line, '#'))) {
|
||||
*pos++ = '\n';
|
||||
*pos = '\0';
|
||||
}
|
||||
if (strncmp(line, addr_str, addr_str_len))
|
||||
continue;
|
||||
|
||||
for (pos = line + addr_str_len + 1; isspace(*pos); pos++);
|
||||
char *begin = pos;
|
||||
for (; !isspace(*pos); pos++);
|
||||
char *end = pos;
|
||||
|
||||
size_t size = end - begin;
|
||||
if (size >= name.size())
|
||||
return -EAI_OVERFLOW;
|
||||
std::copy(begin, end, name.data());
|
||||
name.data()[size] = '\0';
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lookup_name_null(struct lookup_result &buf, int flags, int family) {
|
||||
if (flags & AI_PASSIVE) {
|
||||
if (family != AF_INET6) {
|
||||
struct dns_addr_buf addr_buf;
|
||||
addr_buf.family = AF_INET;
|
||||
|
||||
in_addr_t addr = INADDR_ANY;
|
||||
memcpy(&addr_buf.addr, &addr, 4);
|
||||
|
||||
buf.buf.push_back(addr_buf);
|
||||
}
|
||||
if (family != AF_INET) {
|
||||
struct dns_addr_buf addr_buf;
|
||||
addr_buf.family = AF_INET6;
|
||||
|
||||
struct in6_addr addr = IN6ADDR_ANY_INIT;
|
||||
memcpy(&addr_buf.addr, &addr, 16);
|
||||
|
||||
buf.buf.push_back(addr_buf);
|
||||
}
|
||||
} else {
|
||||
if (family != AF_INET6) {
|
||||
struct dns_addr_buf addr_buf;
|
||||
addr_buf.family = AF_INET;
|
||||
|
||||
in_addr_t addr = INADDR_LOOPBACK;
|
||||
memcpy(&addr_buf.addr, &addr, 4);
|
||||
|
||||
buf.buf.push_back(addr_buf);
|
||||
}
|
||||
if (family != AF_INET) {
|
||||
struct dns_addr_buf addr_buf;
|
||||
addr_buf.family = AF_INET6;
|
||||
|
||||
struct in6_addr addr = IN6ADDR_LOOPBACK_INIT;
|
||||
memcpy(&addr_buf.addr, &addr, 16);
|
||||
|
||||
buf.buf.push_back(addr_buf);
|
||||
}
|
||||
}
|
||||
return buf.buf.size();
|
||||
}
|
||||
|
||||
int lookup_name_ip(struct lookup_result &buf, const char *name, int family) {
|
||||
if (family == AF_INET) {
|
||||
in_addr_t addr = 0;
|
||||
int res = inet_pton(AF_INET, name, &addr);
|
||||
|
||||
if (res <= 0)
|
||||
return -EAI_NONAME;
|
||||
|
||||
struct dns_addr_buf addr_buf;
|
||||
addr_buf.family = AF_INET;
|
||||
memcpy(&addr_buf.addr, &addr, 4);
|
||||
|
||||
buf.buf.push_back(addr_buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (family == AF_INET6) {
|
||||
struct in6_addr addr{};
|
||||
int res = inet_pton(AF_INET6, name, &addr);
|
||||
|
||||
if (res <= 0)
|
||||
return -EAI_NONAME;
|
||||
|
||||
struct dns_addr_buf addr_buf;
|
||||
addr_buf.family = AF_INET6;
|
||||
memcpy(&addr_buf.addr, &addr, 16);
|
||||
|
||||
buf.buf.push_back(addr_buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// If no family was specified we try ipv4 and then ipv6.
|
||||
in_addr_t addr4 = 0;
|
||||
int res = inet_pton(AF_INET, name, &addr4);
|
||||
|
||||
if (res > 0) {
|
||||
struct dns_addr_buf addr_buf;
|
||||
addr_buf.family = AF_INET;
|
||||
memcpy(&addr_buf.addr, &addr4, 4);
|
||||
|
||||
buf.buf.push_back(addr_buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct in6_addr addr6{};
|
||||
res = inet_pton(AF_INET6, name, &addr6);
|
||||
|
||||
if (res <= 0)
|
||||
return -EAI_NONAME;
|
||||
|
||||
struct dns_addr_buf addr_buf;
|
||||
addr_buf.family = AF_INET6;
|
||||
memcpy(&addr_buf.addr, &addr6, 16);
|
||||
|
||||
buf.buf.push_back(addr_buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
} // namespace mlibc
|
||||
@@ -0,0 +1,22 @@
|
||||
#include <mqueue.h>
|
||||
#include <bits/ensure.h>
|
||||
|
||||
int mq_getattr(mqd_t, struct mq_attr *) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
int mq_setattr(mqd_t, const struct mq_attr *__restrict__, struct mq_attr *__restrict__) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
int mq_unlink(const char *) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
mqd_t mq_open(const char *, int, ...) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
#include <errno.h>
|
||||
#include <net/if.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/posix-sysdeps.hpp>
|
||||
|
||||
void if_freenameindex(struct if_nameindex *) {
|
||||
mlibc::infoLogger() << "mlibc: if_freenameindex is a no-op" << frg::endlog;
|
||||
}
|
||||
|
||||
char *if_indextoname(unsigned int index, char *name) {
|
||||
auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_if_indextoname, NULL);
|
||||
|
||||
if(int e = sysdep(index, name); e) {
|
||||
errno = e;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
struct if_nameindex *if_nameindex(void) {
|
||||
mlibc::infoLogger() << "mlibc: if_nameindex() is a no-op" << frg::endlog;
|
||||
errno = ENOSYS;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unsigned int if_nametoindex(const char *name) {
|
||||
auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_if_nametoindex, 0);
|
||||
unsigned int ret = 0;
|
||||
|
||||
if(int e = sysdep(name, &ret); e) {
|
||||
errno = e;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,520 @@
|
||||
#include <netdb.h>
|
||||
#include <bits/ensure.h>
|
||||
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/lookup.hpp>
|
||||
#include <mlibc/allocator.hpp>
|
||||
#include <mlibc/services.hpp>
|
||||
#include <mlibc/posix-sysdeps.hpp>
|
||||
#include <frg/vector.hpp>
|
||||
#include <frg/array.hpp>
|
||||
#include <frg/span.hpp>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
__thread int __mlibc_h_errno;
|
||||
|
||||
// This function is from musl
|
||||
int *__h_errno_location(void) {
|
||||
return &__mlibc_h_errno;
|
||||
}
|
||||
|
||||
void endhostent(void) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void endnetent(void) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void endprotoent(void) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void endservent(void) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void freeaddrinfo(struct addrinfo *ptr) {
|
||||
if (ptr) {
|
||||
auto buf = (struct mlibc::ai_buf*) ptr - offsetof(struct mlibc::ai_buf, ai);
|
||||
// this string was allocated by a frg::string
|
||||
getAllocator().free(ptr->ai_canonname);
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
const char *gai_strerror(int code) {
|
||||
static thread_local char buffer[128];
|
||||
snprintf(buffer, sizeof(buffer), "Unknown error (%d)", code);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
int getaddrinfo(const char *__restrict node, const char *__restrict service,
|
||||
const struct addrinfo *__restrict hints, struct addrinfo **__restrict res) {
|
||||
if (!node && !service)
|
||||
return EAI_NONAME;
|
||||
|
||||
int socktype = 0, protocol = 0, family = AF_UNSPEC, flags = AI_V4MAPPED | AI_ADDRCONFIG;
|
||||
if (hints) {
|
||||
socktype = hints->ai_socktype;
|
||||
protocol = hints->ai_protocol;
|
||||
family = hints->ai_family;
|
||||
flags = hints->ai_flags;
|
||||
|
||||
int mask = AI_V4MAPPED | AI_ADDRCONFIG | AI_NUMERICHOST | AI_PASSIVE |
|
||||
AI_CANONNAME | AI_ALL | AI_NUMERICSERV;
|
||||
if ((flags & mask) != flags)
|
||||
return EAI_BADFLAGS;
|
||||
|
||||
if (hints->ai_flags & AI_CANONNAME && !node)
|
||||
return EAI_BADFLAGS;
|
||||
|
||||
if (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC)
|
||||
return EAI_FAMILY;
|
||||
}
|
||||
|
||||
if (flags & AI_ADDRCONFIG) {
|
||||
if (mlibc::sys_inet_configured) {
|
||||
bool ipv4 = false;
|
||||
bool ipv6 = false;
|
||||
|
||||
if (int e = mlibc::sys_inet_configured(&ipv4, &ipv6); e) {
|
||||
errno = e;
|
||||
return EAI_SYSTEM;
|
||||
}
|
||||
|
||||
if (!ipv4 && !ipv6)
|
||||
return EAI_NONAME;
|
||||
else if (ipv4 != ipv6)
|
||||
family = ipv4 ? AF_INET : AF_INET6;
|
||||
} else {
|
||||
mlibc::infoLogger() << "mlibc: sys_inet_configured() not implemented, cannot handle getaddrinfo with AI_ADDRCONFIG" << frg::endlog;
|
||||
errno = ENOSYS;
|
||||
return EAI_SYSTEM;
|
||||
}
|
||||
}
|
||||
|
||||
mlibc::service_result serv_buf{getAllocator()};
|
||||
int serv_count = mlibc::lookup_serv_by_name(serv_buf, service, protocol, socktype, flags);
|
||||
if (serv_count < 0)
|
||||
return -serv_count;
|
||||
|
||||
struct mlibc::lookup_result addr_buf;
|
||||
int addr_count = 1;
|
||||
frg::string<MemoryAllocator> canon{getAllocator()};
|
||||
if (node) {
|
||||
if ((addr_count = mlibc::lookup_name_ip(addr_buf, node, family)) <= 0) {
|
||||
if (flags & AI_NUMERICHOST)
|
||||
addr_count = -EAI_NONAME;
|
||||
else if ((addr_count = mlibc::lookup_name_hosts(addr_buf, node, canon, family)) <= 0)
|
||||
addr_count = mlibc::lookup_name_dns(addr_buf, node, canon, family);
|
||||
}
|
||||
|
||||
if (addr_count < 0)
|
||||
return -addr_count;
|
||||
if (!addr_count)
|
||||
return EAI_NONAME;
|
||||
} else {
|
||||
/* There is no node specified */
|
||||
if (flags & AI_NUMERICHOST)
|
||||
return EAI_NONAME;
|
||||
addr_count = lookup_name_null(addr_buf, flags, family);
|
||||
}
|
||||
|
||||
auto out = (struct mlibc::ai_buf *) calloc(serv_count * addr_count,
|
||||
sizeof(struct mlibc::ai_buf));
|
||||
|
||||
if (node && !canon.size() && (flags & AI_CANONNAME))
|
||||
canon = frg::string<MemoryAllocator>{node, getAllocator()};
|
||||
|
||||
for (int i = 0, k = 0; i < addr_count; i++) {
|
||||
for (int j = 0; j < serv_count; j++, k++) {
|
||||
out[i].ai.ai_family = addr_buf.buf[i].family;
|
||||
out[i].ai.ai_socktype = serv_buf[j].socktype;
|
||||
out[i].ai.ai_protocol = serv_buf[j].protocol;
|
||||
out[i].ai.ai_flags = flags;
|
||||
out[i].ai.ai_addr = (struct sockaddr *) &out[i].sa;
|
||||
|
||||
// If `node` is not null, and if requested by the AI_CANONNAME flag,
|
||||
// the `ai_canonname` field of the first returned addrinfo structure
|
||||
// shall point to a null-terminated string containing the canonical name
|
||||
// corresponding to the node argument. If the canonical name is not available,
|
||||
// then the ai_canonname field shall refer to the `node` argument or a string with
|
||||
// the same contents.
|
||||
if (node && (flags & AI_CANONNAME) && i == 0)
|
||||
out[i].ai.ai_canonname = canon.data();
|
||||
|
||||
if(i)
|
||||
out[i - 1].ai.ai_next = &out[i].ai;
|
||||
|
||||
switch (addr_buf.buf[i].family) {
|
||||
case AF_INET:
|
||||
out[i].ai.ai_addrlen = sizeof(struct sockaddr_in);
|
||||
out[i].sa.sin.sin_port = htons(serv_buf[j].port);
|
||||
out[i].sa.sin.sin_family = AF_INET;
|
||||
memcpy(&out[i].sa.sin.sin_addr, addr_buf.buf[i].addr, 4);
|
||||
break;
|
||||
case AF_INET6:
|
||||
out[i].ai.ai_addrlen = sizeof(struct sockaddr_in6);
|
||||
out[i].sa.sin6.sin6_port = htons(serv_buf[j].port);
|
||||
out[i].sa.sin6.sin6_family = AF_INET6;
|
||||
memcpy(&out[i].sa.sin6.sin6_addr, addr_buf.buf[i].addr, 16);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (addr_count)
|
||||
out[addr_count - 1].ai.ai_next = nullptr;
|
||||
|
||||
if (canon.size())
|
||||
canon.detach();
|
||||
|
||||
*res = &out[0].ai;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct hostent *gethostent(void) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
int getnameinfo(const struct sockaddr *__restrict addr, socklen_t addr_len,
|
||||
char *__restrict host, socklen_t host_len, char *__restrict serv,
|
||||
socklen_t serv_len, int flags) {
|
||||
frg::array<uint8_t, 16> addr_array;
|
||||
int family = addr->sa_family;
|
||||
|
||||
switch(family) {
|
||||
case AF_INET: {
|
||||
if (addr_len < sizeof(struct sockaddr_in))
|
||||
return EAI_FAMILY;
|
||||
auto sockaddr = reinterpret_cast<const struct sockaddr_in*>(addr);
|
||||
memcpy(addr_array.data(), reinterpret_cast<const char*>(&sockaddr->sin_addr), 4);
|
||||
break;
|
||||
}
|
||||
case AF_INET6: {
|
||||
mlibc::infoLogger() << "getnameinfo(): ipv6 is not fully supported in this function" << frg::endlog;
|
||||
if (addr_len < sizeof(struct sockaddr_in6))
|
||||
return EAI_FAMILY;
|
||||
auto sockaddr = reinterpret_cast<const struct sockaddr_in6*>(addr);
|
||||
memcpy(addr_array.data(), reinterpret_cast<const char*>(&sockaddr->sin6_addr), 16);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return EAI_FAMILY;
|
||||
}
|
||||
|
||||
if (host && host_len) {
|
||||
frg::span<char> host_span{host, host_len};
|
||||
int res = 0;
|
||||
if (!(flags & NI_NUMERICHOST))
|
||||
res = mlibc::lookup_addr_hosts(host_span, addr_array, family);
|
||||
if (!(flags & NI_NUMERICHOST) && !res)
|
||||
res = mlibc::lookup_addr_dns(host_span, addr_array, family);
|
||||
|
||||
if (!res) {
|
||||
if (flags & NI_NAMEREQD)
|
||||
return EAI_NONAME;
|
||||
if(!inet_ntop(family, addr_array.data(), host, host_len)) {
|
||||
switch(errno) {
|
||||
case EAFNOSUPPORT:
|
||||
return EAI_FAMILY;
|
||||
case ENOSPC:
|
||||
return EAI_OVERFLOW;
|
||||
default:
|
||||
return EAI_FAIL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (res < 0)
|
||||
return -res;
|
||||
}
|
||||
|
||||
if (serv && serv_len) {
|
||||
__ensure("getnameinfo(): not implemented service resolution yet!");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct netent *getnetbyaddr(uint32_t, int) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
struct netent *getnetbyname(const char *) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
struct netent *getnetent(void) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
struct hostent *gethostbyname(const char *name) {
|
||||
if (!name) {
|
||||
h_errno = HOST_NOT_FOUND;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
struct mlibc::lookup_result buf;
|
||||
frg::string<MemoryAllocator> canon{getAllocator()};
|
||||
int ret = 0;
|
||||
if ((ret = mlibc::lookup_name_hosts(buf, name, canon, AF_UNSPEC)) <= 0)
|
||||
ret = mlibc::lookup_name_dns(buf, name, canon, AF_UNSPEC);
|
||||
if (ret <= 0) {
|
||||
h_errno = HOST_NOT_FOUND;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static struct hostent h;
|
||||
if (h.h_name) {
|
||||
getAllocator().free(h.h_name);
|
||||
for (int i = 0; h.h_aliases[i] != nullptr; i++)
|
||||
getAllocator().free(h.h_aliases[i]);
|
||||
free(h.h_aliases);
|
||||
|
||||
if (h.h_addr_list) {
|
||||
for (int i = 0; h.h_addr_list[i] != nullptr; i++)
|
||||
free(h.h_addr_list[i]);
|
||||
free(h.h_addr_list);
|
||||
}
|
||||
}
|
||||
h = {};
|
||||
|
||||
if (!canon.size())
|
||||
canon = frg::string<MemoryAllocator>{name, getAllocator()};
|
||||
|
||||
h.h_name = canon.data();
|
||||
|
||||
h.h_aliases = reinterpret_cast<char**>(malloc((buf.aliases.size() + 1)
|
||||
* sizeof(char*)));
|
||||
int alias_pos = 0;
|
||||
for (auto &buf_name : buf.aliases) {
|
||||
h.h_aliases[alias_pos] = buf_name.data();
|
||||
buf_name.detach();
|
||||
alias_pos++;
|
||||
}
|
||||
h.h_aliases[alias_pos] = nullptr;
|
||||
canon.detach();
|
||||
|
||||
// just pick the first family as the one for all addresses...??
|
||||
h.h_addrtype = buf.buf[0].family;
|
||||
if (h.h_addrtype != AF_INET && h.h_addrtype != AF_INET6) {
|
||||
// this is not allowed per spec
|
||||
h_errno = NO_DATA;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// can only be AF_INET or AF_INET6
|
||||
h.h_length = h.h_addrtype == AF_INET ? 4 : 16;
|
||||
h.h_addr_list = reinterpret_cast<char**>(malloc((ret + 1) * sizeof(char*)));
|
||||
int addr_pos = 0;
|
||||
for (int i = 0; i < ret; i++) {
|
||||
if (buf.buf[i].family != h.h_addrtype)
|
||||
continue;
|
||||
h.h_addr_list[addr_pos] = reinterpret_cast<char*>(malloc(h.h_length));
|
||||
memcpy(h.h_addr_list[addr_pos], buf.buf[i].addr, h.h_length);
|
||||
addr_pos++;
|
||||
}
|
||||
h.h_addr_list[addr_pos] = nullptr;
|
||||
|
||||
return &h;
|
||||
}
|
||||
|
||||
struct hostent *gethostbyname2(const char *, int) {
|
||||
__ensure(!"gethostbyname2() not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
struct hostent *gethostbyaddr(const void *, socklen_t, int) {
|
||||
__ensure(!"gethostbyaddr() not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
int gethostbyaddr_r(const void *__restrict, socklen_t, int, struct hostent *__restrict,
|
||||
char *__restrict, size_t, struct hostent **__restrict, int *__restrict) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
int gethostbyname_r(const char *__restrict, struct hostent *__restrict, char *__restrict, size_t,
|
||||
struct hostent **__restrict, int *__restrict) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
struct protoent *getprotobyname(const char *) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
struct protoent *getprotobynumber(int) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
struct protoent *getprotoent(void) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
struct servent *getservbyname(const char *name, const char *proto) {
|
||||
int iproto = -1;
|
||||
if (proto &&(!strncmp(proto, "tcp", 3) || !strncmp(proto, "TCP", 3)))
|
||||
iproto = IPPROTO_TCP;
|
||||
else if (proto && (!strncmp(proto, "udp", 3) || !strncmp(proto, "UDP", 3)))
|
||||
iproto = IPPROTO_UDP;
|
||||
|
||||
static struct servent ret;
|
||||
if (ret.s_name) {
|
||||
free(ret.s_name);
|
||||
ret.s_name = nullptr;
|
||||
|
||||
for (char **alias = ret.s_aliases; *alias != nullptr; alias++) {
|
||||
free(*alias);
|
||||
*alias = nullptr;
|
||||
}
|
||||
|
||||
free(ret.s_proto);
|
||||
ret.s_proto = nullptr;
|
||||
}
|
||||
|
||||
mlibc::service_result serv_buf{getAllocator()};
|
||||
int count = mlibc::lookup_serv_by_name(serv_buf, name, iproto,
|
||||
0, 0);
|
||||
if (count <= 0)
|
||||
return nullptr;
|
||||
|
||||
ret.s_name = serv_buf[0].name.data();
|
||||
serv_buf[0].name.detach();
|
||||
// Sanity check.
|
||||
if (strncmp(name, serv_buf[0].name.data(), serv_buf[0].name.size()))
|
||||
return nullptr;
|
||||
|
||||
ret.s_aliases = reinterpret_cast<char**>(malloc((serv_buf[0].aliases.size() + 1) * sizeof(char*)));
|
||||
int alias_pos = 0;
|
||||
for (auto &buf_name : serv_buf[0].aliases) {
|
||||
ret.s_aliases[alias_pos] = buf_name.data();
|
||||
buf_name.detach();
|
||||
alias_pos++;
|
||||
}
|
||||
ret.s_aliases[alias_pos] = nullptr;
|
||||
|
||||
ret.s_port = htons(serv_buf[0].port);
|
||||
|
||||
auto proto_string = frg::string<MemoryAllocator>(getAllocator());
|
||||
if (!proto) {
|
||||
if (serv_buf[0].protocol == IPPROTO_TCP)
|
||||
proto_string = frg::string<MemoryAllocator>("tcp", getAllocator());
|
||||
else if (serv_buf[0].protocol == IPPROTO_UDP)
|
||||
proto_string = frg::string<MemoryAllocator>("udp", getAllocator());
|
||||
else
|
||||
return nullptr;
|
||||
} else {
|
||||
proto_string = frg::string<MemoryAllocator>(proto, getAllocator());
|
||||
}
|
||||
ret.s_proto = proto_string.data();
|
||||
proto_string.detach();
|
||||
|
||||
return &ret;
|
||||
}
|
||||
|
||||
struct servent *getservbyport(int port, const char *proto) {
|
||||
int iproto = -1;
|
||||
if (proto && (!strncmp(proto, "tcp", 3) || !strncmp(proto, "TCP", 3)))
|
||||
iproto = IPPROTO_TCP;
|
||||
else if (proto && (!strncmp(proto, "udp", 3) || !strncmp(proto, "UDP", 3)))
|
||||
iproto = IPPROTO_UDP;
|
||||
|
||||
static struct servent ret;
|
||||
if (ret.s_name) {
|
||||
free(ret.s_name);
|
||||
ret.s_name = nullptr;
|
||||
|
||||
for (char **alias = ret.s_aliases; *alias != nullptr; alias++) {
|
||||
free(*alias);
|
||||
*alias = nullptr;
|
||||
}
|
||||
|
||||
free(ret.s_proto);
|
||||
ret.s_proto = nullptr;
|
||||
}
|
||||
|
||||
mlibc::service_result serv_buf{getAllocator()};
|
||||
int count = mlibc::lookup_serv_by_port(serv_buf, iproto, ntohs(port));
|
||||
if (count <= 0)
|
||||
return nullptr;
|
||||
|
||||
ret.s_name = serv_buf[0].name.data();
|
||||
serv_buf[0].name.detach();
|
||||
|
||||
ret.s_aliases = reinterpret_cast<char**>(malloc((serv_buf[0].aliases.size() + 1) * sizeof(char*)));
|
||||
int alias_pos = 0;
|
||||
for (auto &buf_name : serv_buf[0].aliases) {
|
||||
ret.s_aliases[alias_pos] = buf_name.data();
|
||||
buf_name.detach();
|
||||
alias_pos++;
|
||||
}
|
||||
ret.s_aliases[alias_pos] = nullptr;
|
||||
|
||||
ret.s_port = port;
|
||||
|
||||
auto proto_string = frg::string<MemoryAllocator>(getAllocator());
|
||||
if (!proto) {
|
||||
if (serv_buf[0].protocol == IPPROTO_TCP)
|
||||
proto_string = frg::string<MemoryAllocator>("tcp", getAllocator());
|
||||
else if (serv_buf[0].protocol == IPPROTO_UDP)
|
||||
proto_string = frg::string<MemoryAllocator>("udp", getAllocator());
|
||||
else
|
||||
return nullptr;
|
||||
} else {
|
||||
proto_string = frg::string<MemoryAllocator>(proto, getAllocator());
|
||||
}
|
||||
ret.s_proto = proto_string.data();
|
||||
proto_string.detach();
|
||||
|
||||
return &ret;
|
||||
}
|
||||
|
||||
struct servent *getservent(void) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void sethostent(int) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void setnetent(int) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void setprotoent(int) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void setservent(int) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
const char *hstrerror(int) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/posix-sysdeps.hpp>
|
||||
|
||||
int poll(struct pollfd *fds, nfds_t count, int timeout) {
|
||||
int num_events;
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_poll, -1);
|
||||
if(int e = mlibc::sys_poll(fds, count, timeout, &num_events); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return num_events;
|
||||
}
|
||||
|
||||
#if __MLIBC_LINUX_OPTION
|
||||
|
||||
#include <mlibc/linux-sysdeps.hpp>
|
||||
|
||||
int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts, const sigset_t *sigmask) {
|
||||
if (mlibc::sys_ppoll) {
|
||||
int num_events;
|
||||
if(int e = mlibc::sys_ppoll(fds, nfds, timeout_ts, sigmask, &num_events); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return num_events;
|
||||
}
|
||||
|
||||
sigset_t origmask;
|
||||
int timeout = (timeout_ts == nullptr) ? -1 : (timeout_ts->tv_sec * 1000 + timeout_ts->tv_nsec / 1000000);
|
||||
|
||||
sigprocmask(SIG_SETMASK, sigmask, &origmask);
|
||||
int ready = poll(fds, nfds, timeout);
|
||||
sigprocmask(SIG_SETMASK, &origmask, nullptr);
|
||||
|
||||
return ready;
|
||||
}
|
||||
#endif // __MLIBC_LINUX_OPTION
|
||||
|
||||
@@ -0,0 +1,275 @@
|
||||
#include <mlibc/posix-file-io.hpp>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/posix-sysdeps.hpp>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
int mem_file::reopen(const char *, const char *) {
|
||||
mlibc::panicLogger() << "mlibc: freopen() on a mem_file stream is unimplemented!" << frg::endlog;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int mem_file::determine_type(stream_type *type) {
|
||||
*type = stream_type::file_like;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mem_file::determine_bufmode(buffer_mode *mode) {
|
||||
*mode = buffer_mode::no_buffer;
|
||||
return 0;
|
||||
}
|
||||
|
||||
memstream_mem_file::memstream_mem_file(char **ptr, size_t *sizeloc, int flags, void (*do_dispose)(abstract_file *))
|
||||
: mem_file{flags, do_dispose}, _bufloc{ptr}, _sizeloc{sizeloc} { }
|
||||
|
||||
|
||||
int memstream_mem_file::close() {
|
||||
_update_ptrs();
|
||||
_buf.detach();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int memstream_mem_file::io_read(char *buffer, size_t max_size, size_t *actual_size) {
|
||||
if ((_pos >= 0 && _pos >= _max_size) || !max_size) {
|
||||
*actual_size = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t bytes_read = std::min(size_t(_max_size - _pos), max_size);
|
||||
memcpy(buffer, _buffer().data() + _pos, bytes_read);
|
||||
_pos += bytes_read;
|
||||
*actual_size = bytes_read;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int memstream_mem_file::io_write(const char *buffer, size_t max_size, size_t *actual_size) {
|
||||
if (_pos + max_size >= _buffer_size()) {
|
||||
_buf.resize(_pos + max_size + 1, '\0');
|
||||
_update_ptrs();
|
||||
}
|
||||
|
||||
size_t bytes_write = std::min(static_cast<size_t>(_buffer_size() - _pos), max_size);
|
||||
memcpy(_buffer().data() + _pos, buffer, bytes_write);
|
||||
_pos += max_size;
|
||||
*actual_size = max_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int memstream_mem_file::io_seek(off_t offset, int whence, off_t *new_offset) {
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
_pos = offset;
|
||||
if (_pos >= 0 && size_t(_pos) >= _buffer_size()) {
|
||||
_buf.resize(_pos + 1, '\0');
|
||||
_update_ptrs();
|
||||
}
|
||||
*new_offset = _pos;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
_pos += offset;
|
||||
if (_pos >= 0 && size_t(_pos) >= _buffer_size()) {
|
||||
_buf.resize(_pos + 1, '\0');
|
||||
_update_ptrs();
|
||||
}
|
||||
*new_offset = _pos;
|
||||
break;
|
||||
case SEEK_END:
|
||||
_pos = _buffer_size() ? _buffer_size() - 1 + offset : _buffer_size() + offset;
|
||||
_buf.resize(_pos + 1, '\0');
|
||||
_update_ptrs();
|
||||
*new_offset = _pos;
|
||||
break;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void memstream_mem_file::_update_ptrs() {
|
||||
*_bufloc = _buf.data();
|
||||
*_sizeloc = _buf.size() - 1;
|
||||
}
|
||||
|
||||
fmemopen_mem_file::fmemopen_mem_file(void *in_buf, size_t size, int flags, void (*do_dispose)(abstract_file *))
|
||||
: mem_file{flags, do_dispose}, _inBuffer{in_buf}, _inBufferSize{size} {
|
||||
if(!_inBuffer) {
|
||||
_inBuffer = getAllocator().allocate(size);
|
||||
_needsDeallocation = true;
|
||||
}
|
||||
|
||||
if(_flags & O_APPEND) {
|
||||
// the initial seek-size for append is zero if buf was NULL, or the first '\0' found, or the size
|
||||
_max_size = (_needsDeallocation) ? 0 : strnlen(reinterpret_cast<char *>(_inBuffer), _inBufferSize);
|
||||
_pos = _max_size;
|
||||
} else if((_flags & O_WRONLY || _flags & O_RDWR) && _flags & O_CREAT && _flags & O_TRUNC) {
|
||||
// modes: "w", "w+"
|
||||
_max_size = 0;
|
||||
} else {
|
||||
_max_size = size;
|
||||
}
|
||||
}
|
||||
|
||||
int fmemopen_mem_file::close() {
|
||||
if(_needsDeallocation) {
|
||||
getAllocator().free(_inBuffer);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fmemopen_mem_file::io_read(char *buffer, size_t max_size, size_t *actual_size) {
|
||||
if ((_pos >= 0 && _pos >= _max_size) || !max_size) {
|
||||
*actual_size = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t bytes_read = std::min(size_t(_max_size - _pos), max_size);
|
||||
memcpy(buffer, _buffer().data() + _pos, bytes_read);
|
||||
_pos += bytes_read;
|
||||
*actual_size = bytes_read;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fmemopen_mem_file::io_write(const char *buffer, size_t max_size, size_t *actual_size) {
|
||||
off_t bytes_write = std::min(static_cast<size_t>(_buffer_size() - _pos), max_size);
|
||||
memcpy(_buffer().data() + _pos, buffer, bytes_write);
|
||||
_pos += bytes_write;
|
||||
*actual_size = bytes_write;
|
||||
|
||||
if(_pos > _max_size) {
|
||||
_max_size = _pos;
|
||||
}
|
||||
|
||||
// upon flushing, we need to put a null byte at the current position or at the end of the buffer
|
||||
size_t null = _pos;
|
||||
// a special case is if the mode is set to updating ('+'), then it always goes at the end
|
||||
if(null >= _buffer_size() || _flags & O_RDWR) {
|
||||
null = _buffer_size() - 1;
|
||||
}
|
||||
|
||||
if(_buffer_size()) {
|
||||
_buffer()[null] = '\0';
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fmemopen_mem_file::io_seek(off_t offset, int whence, off_t *new_offset) {
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
if(offset < 0 || size_t(offset) > _buffer_size()) {
|
||||
return EINVAL;
|
||||
}
|
||||
_pos = offset;
|
||||
*new_offset = _pos;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
// seeking to negative positions or positions larger than the buffer is disallowed in fmemopen(3)
|
||||
if((_pos + offset) < 0 || size_t(_pos + offset) > _buffer_size()) {
|
||||
return EINVAL;
|
||||
}
|
||||
_pos += offset;
|
||||
*new_offset = _pos;
|
||||
break;
|
||||
case SEEK_END:
|
||||
if((_max_size + offset) < 0 || size_t(_max_size + offset) > _buffer_size()) {
|
||||
return EINVAL;
|
||||
}
|
||||
_pos = _max_size + offset;
|
||||
*new_offset = _pos;
|
||||
break;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cookie_file::close() {
|
||||
if(!_funcs.close) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _funcs.close(_cookie);
|
||||
}
|
||||
|
||||
int cookie_file::reopen(const char *, const char *) {
|
||||
mlibc::panicLogger() << "mlibc: freopen() on a cookie_file stream is unimplemented!" << frg::endlog;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int cookie_file::determine_type(stream_type *type) {
|
||||
*type = stream_type::file_like;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cookie_file::determine_bufmode(buffer_mode *mode) {
|
||||
*mode = buffer_mode::no_buffer;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cookie_file::io_read(char *buffer, size_t max_size, size_t *actual_size) {
|
||||
if(!_funcs.read) {
|
||||
return EOF;
|
||||
}
|
||||
|
||||
*actual_size = _funcs.read(_cookie, buffer, max_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cookie_file::io_write(const char *buffer, size_t max_size, size_t *actual_size) {
|
||||
if(!_funcs.write) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*actual_size = _funcs.write(_cookie, buffer, max_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cookie_file::io_seek(off_t offset, int whence, off_t *new_offset) {
|
||||
if(!_funcs.seek) {
|
||||
return ENOTSUP;
|
||||
}
|
||||
|
||||
*new_offset = offset;
|
||||
|
||||
return _funcs.seek(_cookie, new_offset, whence);
|
||||
}
|
||||
|
||||
} // namespace mlibc
|
||||
|
||||
FILE *fdopen(int fd, const char *mode) {
|
||||
int flags = mlibc::fd_file::parse_modestring(mode);
|
||||
|
||||
flags &= ~O_TRUNC; // 'w' should not truncate the file
|
||||
|
||||
if (flags & O_APPEND) {
|
||||
int cur_flags = fcntl(fd, F_GETFL, 0);
|
||||
if (cur_flags < 0) {
|
||||
errno = EINVAL;
|
||||
return nullptr;
|
||||
} else if (!(cur_flags & O_APPEND)) {
|
||||
if (fcntl(fd, F_SETFL, cur_flags | O_APPEND)) {
|
||||
errno = EINVAL;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & O_CLOEXEC) {
|
||||
if (fcntl(fd, F_SETFD, FD_CLOEXEC)) {
|
||||
errno = EINVAL;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: We may need to activate line buffered mode for terminals.
|
||||
|
||||
return frg::construct<mlibc::fd_file>(getAllocator(), fd,
|
||||
mlibc::file_dispose_cb<mlibc::fd_file>);
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
#include <ctype.h>
|
||||
#include <wctype.h>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
|
||||
int isalnum_l(int c, locale_t) {
|
||||
return isalnum(c);
|
||||
}
|
||||
|
||||
int isalpha_l(int c, locale_t) {
|
||||
return isalpha(c);
|
||||
}
|
||||
|
||||
int isblank_l(int c, locale_t) {
|
||||
return isblank(c);
|
||||
}
|
||||
|
||||
int iscntrl_l(int c, locale_t) {
|
||||
return iscntrl(c);
|
||||
}
|
||||
|
||||
int isdigit_l(int c, locale_t) {
|
||||
return isdigit(c);
|
||||
}
|
||||
|
||||
int isgraph_l(int c, locale_t) {
|
||||
return isgraph(c);
|
||||
}
|
||||
|
||||
int islower_l(int c, locale_t) {
|
||||
return islower(c);
|
||||
}
|
||||
|
||||
int isprint_l(int c, locale_t) {
|
||||
return isprint(c);
|
||||
}
|
||||
|
||||
int ispunct_l(int c, locale_t) {
|
||||
return ispunct(c);
|
||||
}
|
||||
|
||||
int isspace_l(int c, locale_t) {
|
||||
return isspace(c);
|
||||
}
|
||||
|
||||
int isupper_l(int c, locale_t) {
|
||||
return isupper(c);
|
||||
}
|
||||
|
||||
int isxdigit_l(int c, locale_t) {
|
||||
return isxdigit(c);
|
||||
}
|
||||
|
||||
int isascii_l(int c, locale_t) {
|
||||
return isascii(c);
|
||||
}
|
||||
|
||||
int tolower_l(int c, locale_t) {
|
||||
return tolower(c);
|
||||
}
|
||||
|
||||
int toupper_l(int c, locale_t) {
|
||||
return toupper(c);
|
||||
}
|
||||
|
||||
int iswalnum_l(wint_t c, locale_t) {
|
||||
return iswalnum(c);
|
||||
}
|
||||
|
||||
int iswblank_l(wint_t c, locale_t) {
|
||||
return iswblank(c);
|
||||
}
|
||||
|
||||
int iswcntrl_l(wint_t c, locale_t) {
|
||||
return iswcntrl(c);
|
||||
}
|
||||
|
||||
int iswdigit_l(wint_t c, locale_t) {
|
||||
return iswdigit(c);
|
||||
}
|
||||
|
||||
int iswgraph_l(wint_t c, locale_t) {
|
||||
return iswgraph(c);
|
||||
}
|
||||
|
||||
int iswlower_l(wint_t c, locale_t) {
|
||||
return iswlower(c);
|
||||
}
|
||||
|
||||
int iswprint_l(wint_t c, locale_t) {
|
||||
return iswprint(c);
|
||||
}
|
||||
|
||||
int iswpunct_l(wint_t c, locale_t) {
|
||||
return iswpunct(c);
|
||||
}
|
||||
|
||||
int iswspace_l(wint_t c, locale_t) {
|
||||
return iswspace(c);
|
||||
}
|
||||
|
||||
int iswupper_l(wint_t c, locale_t) {
|
||||
return iswupper(c);
|
||||
}
|
||||
|
||||
int iswxdigit_l(wint_t c, locale_t) {
|
||||
return iswxdigit(c);
|
||||
}
|
||||
|
||||
int iswalpha_l(wint_t c, locale_t) {
|
||||
return iswalpha(c);
|
||||
}
|
||||
|
||||
wctype_t wctype_l(const char* p, locale_t) {
|
||||
return wctype(p);
|
||||
}
|
||||
|
||||
int iswctype_l(wint_t w, wctype_t t, locale_t) {
|
||||
return iswctype(w, t);
|
||||
}
|
||||
|
||||
wint_t towlower_l(wint_t c, locale_t) {
|
||||
return towlower(c);
|
||||
}
|
||||
|
||||
wint_t towupper_l(wint_t c, locale_t) {
|
||||
return towupper(c);
|
||||
}
|
||||
|
||||
wctrans_t wctrans_l(const char* c, locale_t) {
|
||||
return wctrans(c);
|
||||
}
|
||||
|
||||
wint_t towctrans_l(wint_t c, wctrans_t desc, locale_t) {
|
||||
return towctrans(c, desc);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
#include <bits/posix/posix_locale.h>
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/debug.hpp>
|
||||
|
||||
namespace {
|
||||
|
||||
bool newlocale_seen = false;
|
||||
bool uselocale_seen = false;
|
||||
|
||||
} // namespace
|
||||
|
||||
locale_t newlocale(int, const char *, locale_t) {
|
||||
// Due to all of the locale functions being stubs, the locale will not be used
|
||||
if(!newlocale_seen) {
|
||||
mlibc::infoLogger() << "mlibc: newlocale() is a no-op" << frg::endlog;
|
||||
newlocale_seen = true;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void freelocale(locale_t) {
|
||||
mlibc::infoLogger() << "mlibc: freelocale() is a no-op" << frg::endlog;
|
||||
return;
|
||||
}
|
||||
|
||||
locale_t uselocale(locale_t) {
|
||||
if(!uselocale_seen) {
|
||||
mlibc::infoLogger() << "mlibc: uselocale() is a no-op" << frg::endlog;
|
||||
uselocale_seen = true;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
locale_t duplocale(locale_t) {
|
||||
mlibc::infoLogger() << "mlibc: duplocale() is a no-op" << frg::endlog;
|
||||
return nullptr;
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <bits/ensure.h>
|
||||
|
||||
#include <mlibc/posix-sysdeps.hpp>
|
||||
#include <mlibc/tcb.hpp>
|
||||
|
||||
int sigsuspend(const sigset_t *sigmask) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_sigsuspend, -1);
|
||||
|
||||
// This is guaranteed to return an error (EINTR most probably)
|
||||
errno = mlibc::sys_sigsuspend(sigmask);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int pthread_sigmask(int how, const sigset_t *__restrict set, sigset_t *__restrict retrieve) {
|
||||
if(mlibc::sys_thread_sigmask) {
|
||||
if(int e = mlibc::sys_thread_sigmask(how, set, retrieve); e) {
|
||||
return e;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!mlibc::sys_sigprocmask) {
|
||||
MLIBC_MISSING_SYSDEP();
|
||||
return ENOSYS;
|
||||
}
|
||||
if(int e = mlibc::sys_sigprocmask(how, set, retrieve); e) {
|
||||
return e;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_kill(pthread_t thread, int sig) {
|
||||
auto tcb = reinterpret_cast<Tcb *>(thread);
|
||||
auto pid = getpid();
|
||||
|
||||
if(!mlibc::sys_tgkill) {
|
||||
MLIBC_MISSING_SYSDEP();
|
||||
return ENOSYS;
|
||||
}
|
||||
|
||||
if(int e = mlibc::sys_tgkill(pid, tcb->tid, sig); e) {
|
||||
return e;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sigaction(int signum, const struct sigaction *__restrict act, struct sigaction *__restrict oldact) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_sigaction, -1);
|
||||
if(int e = mlibc::sys_sigaction(signum, act, oldact); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int siginterrupt(int sig, int flag) {
|
||||
int ret;
|
||||
struct sigaction act;
|
||||
|
||||
sigaction(sig, nullptr, &act);
|
||||
if (flag)
|
||||
act.sa_flags &= ~SA_RESTART;
|
||||
else
|
||||
act.sa_flags |= SA_RESTART;
|
||||
|
||||
ret = sigaction(sig, &act, nullptr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int kill(pid_t pid, int number) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_kill, -1);
|
||||
if(int e = mlibc::sys_kill(pid, number); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int killpg(pid_t pgrp, int sig) {
|
||||
if(pgrp > 1) {
|
||||
return kill(-pgrp, sig);
|
||||
}
|
||||
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int sigtimedwait(const sigset_t *__restrict set, siginfo_t *__restrict info, const struct timespec *__restrict timeout) {
|
||||
auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_sigtimedwait, -1);
|
||||
|
||||
int signo;
|
||||
|
||||
if (int e = sysdep(set, info, timeout, &signo)) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return signo;
|
||||
}
|
||||
|
||||
int sigwaitinfo(const sigset_t *__restrict set, siginfo_t *__restrict info) {
|
||||
// NOTE: This assumes the sysdep behavior noted in mlibc/posix-sysdeps.hpp
|
||||
return sigtimedwait(set, info, nullptr);
|
||||
}
|
||||
|
||||
int sigwait(const sigset_t *__restrict set, int *__restrict sig) {
|
||||
if (int e = sigwaitinfo(set, nullptr); e < 0) {
|
||||
return e;
|
||||
} else {
|
||||
if (sig)
|
||||
*sig = e;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int sigpending(sigset_t *set) {
|
||||
auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_sigpending, -1);
|
||||
|
||||
if(int e = sysdep(set)) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sigaltstack(const stack_t *__restrict ss, stack_t *__restrict oss) {
|
||||
if (ss && ss->ss_size < MINSIGSTKSZ && !(ss->ss_flags & SS_DISABLE)) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_sigaltstack, -1);
|
||||
if (int e = mlibc::sys_sigaltstack(ss, oss); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if __MLIBC_GLIBC_OPTION
|
||||
int sigisemptyset(const sigset_t *set) {
|
||||
auto ptr = reinterpret_cast<const char *>(set);
|
||||
for(size_t i = 0; i < sizeof(sigset_t); i++) {
|
||||
if(ptr[i]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif // __MLIBC_GLIBC_OPTION
|
||||
|
||||
int sigqueue(pid_t, int, const union sigval) {
|
||||
__ensure(!"sigqueue() not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/ansi-sysdeps.hpp>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/file-io.hpp>
|
||||
#include <mlibc/posix-file-io.hpp>
|
||||
#include <mlibc/posix-sysdeps.hpp>
|
||||
|
||||
struct popen_file : mlibc::fd_file {
|
||||
popen_file(int fd, void (*do_dispose)(abstract_file *) = nullptr)
|
||||
: fd_file(fd, do_dispose) {}
|
||||
|
||||
pid_t get_popen_pid() {
|
||||
return _popen_pid;
|
||||
}
|
||||
|
||||
void set_popen_pid(pid_t new_pid) {
|
||||
_popen_pid = new_pid;
|
||||
}
|
||||
|
||||
private:
|
||||
// Underlying PID in case of popen()
|
||||
pid_t _popen_pid;
|
||||
};
|
||||
|
||||
FILE *fmemopen(void *buf, size_t size, const char *__restrict mode) {
|
||||
int flags = mlibc::fd_file::parse_modestring(mode);
|
||||
|
||||
return frg::construct<mlibc::fmemopen_mem_file>(getAllocator(), buf, size, flags,
|
||||
mlibc::file_dispose_cb<mlibc::fmemopen_mem_file>);
|
||||
}
|
||||
|
||||
int pclose(FILE *stream) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_waitpid, -1);
|
||||
|
||||
auto file = static_cast<popen_file *>(stream);
|
||||
|
||||
int status;
|
||||
pid_t pid = file->get_popen_pid();
|
||||
|
||||
fclose(file);
|
||||
|
||||
if (mlibc::sys_waitpid(pid, &status, 0, nullptr, &pid) != 0) {
|
||||
errno = ECHILD;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
FILE *popen(const char *command, const char *typestr) {
|
||||
bool is_write;
|
||||
pid_t child;
|
||||
FILE *ret = nullptr;
|
||||
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fork && mlibc::sys_dup2 && mlibc::sys_execve &&
|
||||
mlibc::sys_sigprocmask && mlibc::sys_sigaction && mlibc::sys_pipe, nullptr);
|
||||
|
||||
if (typestr == nullptr) {
|
||||
errno = EINVAL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (strstr(typestr, "w") != nullptr) {
|
||||
is_write = true;
|
||||
} else if (strstr(typestr, "r") != nullptr) {
|
||||
is_write = false;
|
||||
} else {
|
||||
errno = EINVAL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool cloexec = false;
|
||||
if (strstr(typestr, "e") != nullptr) {
|
||||
// Set FD_CLOEXEC on the new file descriptor
|
||||
cloexec = true;
|
||||
}
|
||||
|
||||
int fds[2];
|
||||
if (int e = mlibc::sys_pipe(fds, 0)) {
|
||||
errno = e;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
struct sigaction new_sa, old_int, old_quit;
|
||||
sigset_t new_mask, old_mask;
|
||||
|
||||
new_sa.sa_handler = SIG_IGN;
|
||||
new_sa.sa_flags = 0;
|
||||
sigemptyset(&new_sa.sa_mask);
|
||||
mlibc::sys_sigaction(SIGINT, &new_sa, &old_int);
|
||||
mlibc::sys_sigaction(SIGQUIT, &new_sa, &old_quit);
|
||||
|
||||
sigemptyset(&new_mask);
|
||||
sigaddset(&new_mask, SIGCHLD);
|
||||
mlibc::sys_sigprocmask(SIG_BLOCK, &new_mask, &old_mask);
|
||||
|
||||
int parent_end = is_write ? 1 : 0;
|
||||
int child_end = is_write ? 0 : 1;
|
||||
|
||||
if (int e = mlibc::sys_fork(&child)) {
|
||||
errno = e;
|
||||
mlibc::sys_close(fds[0]);
|
||||
mlibc::sys_close(fds[1]);
|
||||
} else if (!child) {
|
||||
// For the child
|
||||
mlibc::sys_sigaction(SIGINT, &old_int, nullptr);
|
||||
mlibc::sys_sigaction(SIGQUIT, &old_quit, nullptr);
|
||||
mlibc::sys_sigprocmask(SIG_SETMASK, &old_mask, nullptr);
|
||||
|
||||
mlibc::sys_close(fds[parent_end]);
|
||||
|
||||
if (mlibc::sys_dup2(fds[child_end], 0, is_write ? 0 : 1)) {
|
||||
__ensure(!"sys_dup2() failed in popen()");
|
||||
}
|
||||
mlibc::sys_close(fds[child_end]);
|
||||
|
||||
const char *args[] = {
|
||||
"sh", "-c", command, nullptr
|
||||
};
|
||||
|
||||
mlibc::sys_execve("/bin/sh", const_cast<char **>(args), environ);
|
||||
_Exit(127);
|
||||
} else {
|
||||
// For the parent
|
||||
mlibc::sys_close(fds[child_end]);
|
||||
|
||||
ret = frg::construct<popen_file>(
|
||||
getAllocator(),
|
||||
fds[parent_end],
|
||||
mlibc::file_dispose_cb<popen_file>
|
||||
);
|
||||
__ensure(ret);
|
||||
|
||||
auto file = static_cast<popen_file *>(ret);
|
||||
|
||||
file->set_popen_pid(child);
|
||||
|
||||
if (cloexec == true) {
|
||||
fcntl(file->fd(), F_SETFD, O_CLOEXEC);
|
||||
}
|
||||
}
|
||||
|
||||
mlibc::sys_sigaction(SIGINT, &old_int, nullptr);
|
||||
mlibc::sys_sigaction(SIGQUIT, &old_quit, nullptr);
|
||||
mlibc::sys_sigprocmask(SIG_SETMASK, &old_mask, nullptr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
FILE *open_memstream(char **buf, size_t *sizeloc) {
|
||||
return frg::construct<mlibc::memstream_mem_file>(getAllocator(), buf, sizeloc, O_RDWR,
|
||||
mlibc::file_dispose_cb<mlibc::memstream_mem_file>);
|
||||
}
|
||||
|
||||
int fseeko(FILE *file_base, off_t offset, int whence) {
|
||||
auto file = static_cast<mlibc::abstract_file *>(file_base);
|
||||
if(int e = file->seek(offset, whence); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
[[gnu::alias("fseeko")]] int fseeko64(FILE *file_base, off64_t offset, int whence);
|
||||
|
||||
off_t ftello(FILE *file_base) {
|
||||
auto file = static_cast<mlibc::abstract_file *>(file_base);
|
||||
off_t current_offset;
|
||||
if(int e = file->tell(¤t_offset); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return current_offset;
|
||||
}
|
||||
|
||||
[[gnu::alias("ftello")]] off64_t ftello64(FILE *file_base);
|
||||
|
||||
int dprintf(int fd, const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int result = vdprintf(fd, format, args);
|
||||
va_end(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
int vdprintf(int fd, const char *format, __builtin_va_list args) {
|
||||
mlibc::fd_file file{fd};
|
||||
int ret = vfprintf(&file, format, args);
|
||||
file.flush();
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *fgetln(FILE *, size_t *) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
char *tempnam(const char *, const char *) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
FILE *fopencookie(void *cookie, const char *__restrict mode, cookie_io_functions_t funcs) {
|
||||
int flags = mlibc::fd_file::parse_modestring(mode);
|
||||
|
||||
return frg::construct<mlibc::cookie_file>(getAllocator(), cookie, flags, funcs,
|
||||
mlibc::file_dispose_cb<mlibc::cookie_file>);
|
||||
}
|
||||
@@ -0,0 +1,569 @@
|
||||
|
||||
#include <abi-bits/fcntl.h>
|
||||
#include <bits/ensure.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <frg/small_vector.hpp>
|
||||
#include <mlibc/allocator.hpp>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/posix-sysdeps.hpp>
|
||||
#include <mlibc/rtld-config.hpp>
|
||||
|
||||
namespace {
|
||||
constexpr bool debugPathResolution = false;
|
||||
} // namespace
|
||||
|
||||
// Borrowed from musl
|
||||
static uint32_t init[] = {
|
||||
0x00000000,0x5851f42d,0xc0b18ccf,0xcbb5f646,
|
||||
0xc7033129,0x30705b04,0x20fd5db4,0x9a8b7f78,
|
||||
0x502959d8,0xab894868,0x6c0356a7,0x88cdb7ff,
|
||||
0xb477d43f,0x70a3a52b,0xa8e4baf1,0xfd8341fc,
|
||||
0x8ae16fd9,0x742d2f7a,0x0d1f0796,0x76035e09,
|
||||
0x40f7702c,0x6fa72ca5,0xaaa84157,0x58a0df74,
|
||||
0xc74a0364,0xae533cc4,0x04185faf,0x6de3b115,
|
||||
0x0cab8628,0xf043bfa4,0x398150e9,0x37521657};
|
||||
|
||||
static int n = 31;
|
||||
static int i = 3;
|
||||
static int j = 0;
|
||||
static uint32_t *x = init + 1;
|
||||
|
||||
|
||||
static uint32_t lcg31(uint32_t x) {
|
||||
return (1103515245 * x + 12345) & 0x7fffffff;
|
||||
}
|
||||
|
||||
static uint64_t lcg64(uint64_t x) {
|
||||
return 6364136223846793005ull * x + 1;
|
||||
}
|
||||
|
||||
static void *savestate(void) {
|
||||
x[-1] = (n << 16) | (i << 8) | j;
|
||||
return x - 1;
|
||||
}
|
||||
|
||||
static void loadstate(uint32_t *state) {
|
||||
x = state + 1;
|
||||
n = x[-1] >> 16;
|
||||
i = (x[-1] >> 8) & 0xff;
|
||||
j = x[-1] & 0xff;
|
||||
}
|
||||
|
||||
long random(void) {
|
||||
long k;
|
||||
|
||||
if(n == 0) {
|
||||
k = x[0] = lcg31(x[0]);
|
||||
return k;
|
||||
}
|
||||
x[i] += x[j];
|
||||
k = x[i] >> 1;
|
||||
if(++i == n)
|
||||
i = 0;
|
||||
if(++j == n)
|
||||
j = 0;
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
// erand, drand and srand are borrowed from musl
|
||||
namespace {
|
||||
|
||||
unsigned short seed_48[7] = { 0, 0, 0, 0xe66d, 0xdeec, 0x5, 0xb };
|
||||
|
||||
uint64_t eand48_step(unsigned short *xi, unsigned short *lc) {
|
||||
uint64_t x = xi[0] | (xi[1] + 0U) << 16 | (xi[2] + 0ULL) << 32;
|
||||
uint64_t a = lc[0] | (lc[1] + 0U) << 16 | (lc[2] + 0ULL) << 32;
|
||||
x = a*x + lc[3];
|
||||
xi[0] = x;
|
||||
xi[1] = x>>16;
|
||||
xi[2] = x>>32;
|
||||
return x & 0xffffffffffffull;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
double erand48(unsigned short s[3]) {
|
||||
union {
|
||||
uint64_t u;
|
||||
double f;
|
||||
} x = { 0x3ff0000000000000ULL | eand48_step(s, seed_48+3)<<4 };
|
||||
return x.f - 1.0;
|
||||
}
|
||||
|
||||
double drand48(void) {
|
||||
return erand48(seed_48);
|
||||
}
|
||||
|
||||
unsigned short *seed48(unsigned short *s) {
|
||||
static unsigned short p[3];
|
||||
memcpy(p, seed_48, sizeof p);
|
||||
memcpy(seed_48, s, sizeof p);
|
||||
return p;
|
||||
}
|
||||
|
||||
void srand48(long int seed) {
|
||||
unsigned short arr[3] = { 0x330e, (unsigned short) seed, (unsigned short) (seed>>16) };
|
||||
seed48(arr);
|
||||
}
|
||||
|
||||
long jrand48(unsigned short [3]) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
long int mrand48(void) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
// Borrowed from musl
|
||||
void srandom(unsigned int seed) {
|
||||
int k;
|
||||
uint64_t s = seed;
|
||||
|
||||
if(n == 0) {
|
||||
x[0] = s;
|
||||
return;
|
||||
}
|
||||
i = n == 31 || n == 7 ? 3 : 1;
|
||||
j = 0;
|
||||
for(k = 0; k < n; k++) {
|
||||
s = lcg64(s);
|
||||
x[k] = s >> 32;
|
||||
}
|
||||
// Make sure x contains at least one odd number
|
||||
x[0] |= 1;
|
||||
}
|
||||
|
||||
char *initstate(unsigned int seed, char *state, size_t size) {
|
||||
void *old;
|
||||
|
||||
if(size < 8)
|
||||
return nullptr;
|
||||
old = savestate();
|
||||
if(size < 32)
|
||||
n = 0;
|
||||
else if(size < 64)
|
||||
n = 7;
|
||||
else if(size < 128)
|
||||
n = 15;
|
||||
else if(size < 256)
|
||||
n = 31;
|
||||
else
|
||||
n = 63;
|
||||
x = (uint32_t *)state + 1;
|
||||
srandom(seed);
|
||||
savestate();
|
||||
return (char *)old;
|
||||
}
|
||||
|
||||
char *setstate(char *state) {
|
||||
void *old;
|
||||
|
||||
old = savestate();
|
||||
loadstate((uint32_t *)state);
|
||||
return (char *)old;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Path handling.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
int mkostemps(char *pattern, int suffixlen, int flags) {
|
||||
auto n = strlen(pattern);
|
||||
if(n < (6 + static_cast<size_t>(suffixlen))) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
flags &= ~O_WRONLY;
|
||||
|
||||
for(size_t i = 0; i < 6; i++) {
|
||||
if(pattern[n - (6 + suffixlen) + i] == 'X')
|
||||
continue;
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TODO: Do an exponential search.
|
||||
for(size_t i = 0; i < 999999; i++) {
|
||||
char sfx = pattern[n - suffixlen];
|
||||
__ensure(sprintf(pattern + (n - (6 + suffixlen)), "%06zu", i) == 6);
|
||||
pattern[n - suffixlen] = sfx;
|
||||
|
||||
int fd;
|
||||
if(int e = mlibc::sys_open(pattern, O_RDWR | O_CREAT | O_EXCL | flags, S_IRUSR | S_IWUSR, &fd); !e) {
|
||||
return fd;
|
||||
}else if(e != EEXIST) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
errno = EEXIST;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int mkostemp(char *pattern, int flags) {
|
||||
return mkostemps(pattern, 0, flags);
|
||||
}
|
||||
|
||||
int mkstemp(char *path) {
|
||||
return mkostemp(path, 0);
|
||||
}
|
||||
|
||||
int mkstemps(char *pattern, int suffixlen) {
|
||||
return mkostemps(pattern, suffixlen, 0);
|
||||
}
|
||||
|
||||
char *mkdtemp(char *pattern) {
|
||||
mlibc::infoLogger() << "mlibc mkdtemp(" << pattern << ") called" << frg::endlog;
|
||||
auto n = strlen(pattern);
|
||||
__ensure(n >= 6);
|
||||
if(n < 6) {
|
||||
errno = EINVAL;
|
||||
return nullptr;
|
||||
}
|
||||
for(size_t i = 0; i < 6; i++) {
|
||||
if(pattern[n - 6 + i] == 'X')
|
||||
continue;
|
||||
errno = EINVAL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// TODO: Do an exponential search.
|
||||
for(size_t i = 0; i < 999999; i++) {
|
||||
__ensure(sprintf(pattern + (n - 6), "%06zu", i) == 6);
|
||||
if(int e = mlibc::sys_mkdir(pattern, S_IRWXU); !e) {
|
||||
return pattern;
|
||||
}else if(e != EEXIST) {
|
||||
errno = e;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
errno = EEXIST;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char *realpath(const char *path, char *out) {
|
||||
if(debugPathResolution)
|
||||
mlibc::infoLogger() << "mlibc realpath(): Called on '" << path << "'" << frg::endlog;
|
||||
frg::string_view path_view{path};
|
||||
|
||||
// In case of the root, the string only contains the null-terminator.
|
||||
frg::small_vector<char, PATH_MAX, MemoryAllocator> resolv{getAllocator()};
|
||||
size_t ps;
|
||||
|
||||
// If the path is relative, we have to preprend the working directory.
|
||||
if(path[0] == '/') {
|
||||
resolv.push_back(0);
|
||||
ps = 1;
|
||||
}else{
|
||||
// Try to getcwd() until the buffer is large enough.
|
||||
resolv.resize(128);
|
||||
int saved_errno = errno;
|
||||
while(true) {
|
||||
// getcwd could smash errno on failure + resize (ERANGE) + success,
|
||||
// so we have to save and restore errno in that scenario.
|
||||
char *ret = getcwd(resolv.data(), resolv.size());
|
||||
if(ret != nullptr) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(errno == ERANGE) {
|
||||
errno = saved_errno;
|
||||
resolv.resize(2 * resolv.size());
|
||||
}else{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
frg::string_view cwd_view{resolv.data()};
|
||||
if(cwd_view == "/") {
|
||||
// Restore our invariant that we only store the null-terminator for the root.
|
||||
resolv.resize(1);
|
||||
resolv[0] = 0;
|
||||
}else{
|
||||
resolv.resize(cwd_view.size() + 1);
|
||||
}
|
||||
ps = 0;
|
||||
}
|
||||
|
||||
// Contains unresolved links as a relative path compared to resolv.
|
||||
frg::small_vector<char, PATH_MAX, MemoryAllocator> lnk{getAllocator()};
|
||||
size_t ls = 0;
|
||||
|
||||
auto process_segment = [&] (frg::string_view s_view) -> int {
|
||||
if(debugPathResolution)
|
||||
mlibc::infoLogger() << "mlibc realpath(): resolv is '" << resolv.data() << "'"
|
||||
<< ", segment is " << s_view.data()
|
||||
<< ", size: " << s_view.size() << frg::endlog;
|
||||
|
||||
if(!s_view.size() || s_view == ".") {
|
||||
// Keep resolv invariant.
|
||||
return 0;
|
||||
}else if(s_view == "..") {
|
||||
// Remove a single segment from resolv.
|
||||
if(resolv.size() > 1) {
|
||||
auto slash = strrchr(resolv.data(), '/');
|
||||
__ensure(slash); // We never remove the leading sla.
|
||||
resolv.resize((slash - resolv.data()) + 1);
|
||||
*slash = 0; // Replace the slash by a null-terminator.
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Append the segment to resolv.
|
||||
auto rsz = resolv.size();
|
||||
resolv[rsz - 1] = '/'; // Replace null-terminator by a slash.
|
||||
resolv.resize(rsz + s_view.size() + 1);
|
||||
memcpy(resolv.data() + rsz, s_view.data(), s_view.size());
|
||||
resolv[rsz + s_view.size()] = 0;
|
||||
|
||||
// stat() the path to (1) see if it exists and (2) see if it is a link.
|
||||
if(!mlibc::sys_stat) {
|
||||
MLIBC_MISSING_SYSDEP();
|
||||
return ENOSYS;
|
||||
}
|
||||
if(debugPathResolution)
|
||||
mlibc::infoLogger() << "mlibc realpath(): stat()ing '"
|
||||
<< resolv.data() << "'" << frg::endlog;
|
||||
struct stat st;
|
||||
if(int e = mlibc::sys_stat(mlibc::fsfd_target::path,
|
||||
-1, resolv.data(), AT_SYMLINK_NOFOLLOW, &st); e)
|
||||
return e;
|
||||
|
||||
if(S_ISLNK(st.st_mode)) {
|
||||
if(debugPathResolution) {
|
||||
mlibc::infoLogger() << "mlibc realpath(): Encountered symlink '"
|
||||
<< resolv.data() << "'" << frg::endlog;
|
||||
}
|
||||
|
||||
if(!mlibc::sys_readlink) {
|
||||
MLIBC_MISSING_SYSDEP();
|
||||
return ENOSYS;
|
||||
}
|
||||
|
||||
ssize_t sz = 0;
|
||||
char path[512];
|
||||
|
||||
if (int e = mlibc::sys_readlink(resolv.data(), path, 512, &sz); e)
|
||||
return e;
|
||||
|
||||
if(debugPathResolution) {
|
||||
mlibc::infoLogger() << "mlibc realpath(): Symlink resolves to '"
|
||||
<< frg::string_view{path, static_cast<size_t>(sz)} << "'" << frg::endlog;
|
||||
}
|
||||
|
||||
if (path[0] == '/') {
|
||||
// Absolute path, replace resolv
|
||||
|
||||
// Ignore any trailing '/' so all results will not have one to keep consistency.
|
||||
while(sz > 1 && path[sz - 1] == '/')
|
||||
sz -= 1;
|
||||
|
||||
resolv.resize(sz + 1);
|
||||
strncpy(resolv.data(), path, sz);
|
||||
resolv.data()[sz] = 0;
|
||||
|
||||
if(debugPathResolution) {
|
||||
mlibc::infoLogger() << "mlibc realpath(): Symlink is absolute, resolv: '"
|
||||
<< resolv.data() << "'" << frg::endlog;
|
||||
}
|
||||
} else {
|
||||
// Relative path, revert changes to resolv, prepend to lnk
|
||||
resolv.resize(rsz);
|
||||
resolv[rsz - 1] = 0;
|
||||
|
||||
auto lsz = lnk.size();
|
||||
lnk.resize((lsz - ls) + sz + 1);
|
||||
memmove(lnk.data() + sz, lnk.data() + ls, lsz - ls);
|
||||
memcpy(lnk.data(), path, sz);
|
||||
lnk[(lsz - ls) + sz] = 0;
|
||||
|
||||
ls = 0;
|
||||
|
||||
if(debugPathResolution) {
|
||||
mlibc::infoLogger() << "mlibc realpath(): Symlink is relative, resolv: '"
|
||||
<< resolv.data() << "' lnk: '"
|
||||
<< frg::string_view{lnk.data(), lnk.size()} << "'" << frg::endlog;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
// Each iteration of this outer loop consumes segment of the input path.
|
||||
// This design avoids copying the input path into lnk;
|
||||
// the latter could often involve additional allocations.
|
||||
while(ps < path_view.size()) {
|
||||
frg::string_view ps_view;
|
||||
if(auto slash = strchr(path + ps, '/'); slash) {
|
||||
ps_view = frg::string_view{path + ps, static_cast<size_t>(slash - (path + ps))};
|
||||
}else{
|
||||
ps_view = frg::string_view{path + ps, strlen(path) - ps};
|
||||
}
|
||||
ps += ps_view.size() + 1;
|
||||
|
||||
// Handle one segment from the input path.
|
||||
if(int e = process_segment(ps_view); e) {
|
||||
errno = e;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// This inner loop consumes segments of lnk.
|
||||
while(ls < lnk.size()) {
|
||||
frg::string_view ls_view;
|
||||
if(auto slash = strchr(lnk.data() + ls, '/'); slash) {
|
||||
ls_view = frg::string_view{lnk.data() + ls, static_cast<size_t>(slash - (lnk.data() + ls))};
|
||||
}else{
|
||||
ls_view = frg::string_view{lnk.data() + ls, strlen(lnk.data()) - ls};
|
||||
}
|
||||
ls += ls_view.size() + 1;
|
||||
|
||||
// Handle one segment from the link
|
||||
if(int e = process_segment(ls_view); e) {
|
||||
errno = e;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// All of lnk was consumed, reset it
|
||||
lnk.resize(0);
|
||||
ls = 0;
|
||||
}
|
||||
|
||||
if(resolv.size() == 1) {
|
||||
resolv.resize(0);
|
||||
resolv.push_back('/');
|
||||
resolv.push_back(0);
|
||||
}
|
||||
|
||||
if(debugPathResolution)
|
||||
mlibc::infoLogger() << "mlibc realpath(): Returns '" << resolv.data() << "'" << frg::endlog;
|
||||
|
||||
if(resolv.size() > PATH_MAX) {
|
||||
errno = ENAMETOOLONG;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if(!out)
|
||||
out = reinterpret_cast<char *>(getAllocator().allocate(resolv.size()));
|
||||
strcpy(out, resolv.data());
|
||||
return out;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Pseudoterminals
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
int ptsname_r(int fd, char *buffer, size_t length) {
|
||||
auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_ptsname, ENOSYS);
|
||||
|
||||
if(int e = sysdep(fd, buffer, length); e)
|
||||
return e;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *ptsname(int fd) {
|
||||
static char buffer[128];
|
||||
|
||||
auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_ptsname, NULL);
|
||||
|
||||
if(int e = sysdep(fd, buffer, 128); e) {
|
||||
errno = e;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
int posix_openpt(int flags) {
|
||||
int fd, e;
|
||||
|
||||
if(mlibc::sys_openpt) {
|
||||
e = mlibc::sys_openpt(flags, &fd);
|
||||
} else {
|
||||
e = mlibc::sys_open("/dev/ptmx", flags, 0, &fd);
|
||||
}
|
||||
|
||||
if (e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
} else {
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
|
||||
int unlockpt(int fd) {
|
||||
auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_unlockpt, -1);
|
||||
|
||||
if(int e = sysdep(fd); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int grantpt(int) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
double strtod_l(const char *__restrict__ nptr, char ** __restrict__ endptr, locale_t) {
|
||||
mlibc::infoLogger() << "mlibc: strtod_l ignores locale!" << frg::endlog;
|
||||
return strtod(nptr, endptr);
|
||||
}
|
||||
|
||||
long double strtold_l(const char *__restrict__, char ** __restrict__, locale_t) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
float strtof_l(const char *__restrict__ nptr, char **__restrict__ endptr, locale_t) {
|
||||
mlibc::infoLogger() << "mlibc: strtof_l ignores locales" << frg::endlog;
|
||||
return strtof(nptr, endptr);
|
||||
}
|
||||
|
||||
int strcoll_l(const char *, const char *, locale_t) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
int getsubopt(char **__restrict__, char *const *__restrict__, char **__restrict__) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
char *secure_getenv(const char *name) {
|
||||
if (mlibc::rtldConfig().secureRequired)
|
||||
return nullptr;
|
||||
else
|
||||
return getenv(name);
|
||||
}
|
||||
|
||||
void *reallocarray(void *ptr, size_t m, size_t n) {
|
||||
if(n && m > -1 / n) {
|
||||
errno = ENOMEM;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return realloc(ptr, m * n);
|
||||
}
|
||||
|
||||
char *canonicalize_file_name(const char *name) {
|
||||
return realpath(name, nullptr);
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <mlibc/debug.hpp>
|
||||
|
||||
char *strdup(const char *string) {
|
||||
auto num_bytes = strlen(string);
|
||||
|
||||
char *new_string = (char *)malloc(num_bytes + 1);
|
||||
if(!new_string) // TODO: set errno
|
||||
return nullptr;
|
||||
|
||||
memcpy(new_string, string, num_bytes);
|
||||
new_string[num_bytes] = 0;
|
||||
return new_string;
|
||||
}
|
||||
|
||||
char *strndup(const char *string, size_t max_size) {
|
||||
auto num_bytes = strnlen(string, max_size);
|
||||
char *new_string = (char *)malloc(num_bytes + 1);
|
||||
if(!new_string) // TODO: set errno
|
||||
return nullptr;
|
||||
|
||||
memcpy(new_string, string, num_bytes);
|
||||
new_string[num_bytes] = 0;
|
||||
return new_string;
|
||||
}
|
||||
|
||||
char *stpcpy(char *__restrict dest, const char *__restrict src) {
|
||||
auto n = strlen(src);
|
||||
memcpy(dest, src, n + 1);
|
||||
return dest + n;
|
||||
}
|
||||
|
||||
char *stpncpy(char *__restrict dest, const char *__restrict src, size_t n) {
|
||||
size_t nulls, copied, srcLen = strlen(src);
|
||||
if (n >= srcLen) {
|
||||
nulls = n - srcLen;
|
||||
copied = srcLen;
|
||||
} else {
|
||||
nulls = 0;
|
||||
copied = n;
|
||||
}
|
||||
|
||||
memcpy(dest, src, copied);
|
||||
memset(dest + srcLen, 0, nulls);
|
||||
return dest + n - nulls;
|
||||
}
|
||||
|
||||
size_t strnlen(const char *s, size_t n) {
|
||||
size_t len = 0;
|
||||
while(len < n && s[len])
|
||||
++len;
|
||||
return len;
|
||||
}
|
||||
|
||||
char *strsep(char **m, const char *del) {
|
||||
__ensure(m);
|
||||
|
||||
auto tok = *m;
|
||||
if(!tok)
|
||||
return nullptr;
|
||||
|
||||
// Replace the following delimiter by a null-terminator.
|
||||
// After this loop: *p is null iff we reached the end of the string.
|
||||
auto p = tok;
|
||||
while(*p && !strchr(del, *p))
|
||||
p++;
|
||||
|
||||
if(*p) {
|
||||
*p = 0;
|
||||
*m = p + 1;
|
||||
}else{
|
||||
*m = nullptr;
|
||||
}
|
||||
return tok;
|
||||
}
|
||||
|
||||
char *strsignal(int sig) {
|
||||
#define CASE_FOR(sigconst) case sigconst: s = #sigconst; break;
|
||||
const char *s;
|
||||
switch(sig) {
|
||||
CASE_FOR(SIGABRT)
|
||||
CASE_FOR(SIGFPE)
|
||||
CASE_FOR(SIGILL)
|
||||
CASE_FOR(SIGINT)
|
||||
CASE_FOR(SIGSEGV)
|
||||
CASE_FOR(SIGTERM)
|
||||
CASE_FOR(SIGPROF)
|
||||
CASE_FOR(SIGIO)
|
||||
CASE_FOR(SIGPWR)
|
||||
CASE_FOR(SIGALRM)
|
||||
CASE_FOR(SIGBUS)
|
||||
CASE_FOR(SIGCHLD)
|
||||
CASE_FOR(SIGCONT)
|
||||
CASE_FOR(SIGHUP)
|
||||
CASE_FOR(SIGKILL)
|
||||
CASE_FOR(SIGPIPE)
|
||||
CASE_FOR(SIGQUIT)
|
||||
CASE_FOR(SIGSTOP)
|
||||
CASE_FOR(SIGTSTP)
|
||||
CASE_FOR(SIGTTIN)
|
||||
CASE_FOR(SIGTTOU)
|
||||
CASE_FOR(SIGUSR1)
|
||||
CASE_FOR(SIGUSR2)
|
||||
CASE_FOR(SIGSYS)
|
||||
CASE_FOR(SIGTRAP)
|
||||
CASE_FOR(SIGURG)
|
||||
CASE_FOR(SIGVTALRM)
|
||||
CASE_FOR(SIGXCPU)
|
||||
CASE_FOR(SIGXFSZ)
|
||||
CASE_FOR(SIGWINCH)
|
||||
default:
|
||||
mlibc::infoLogger() << "mlibc: Unknown signal number " << sig << frg::endlog;
|
||||
s = "Unknown signal number";
|
||||
}
|
||||
return const_cast<char *>(s);
|
||||
}
|
||||
|
||||
char *strcasestr(const char *s, const char *pattern) {
|
||||
size_t plen = strlen(pattern);
|
||||
const char *p = s;
|
||||
while(*p) {
|
||||
// Need strncasecmp() to avoid checking past the end of a successful match.
|
||||
if(!strncasecmp(p, pattern, plen))
|
||||
return const_cast<char *>(p);
|
||||
++p;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void *memccpy(void *__restrict, const void *__restrict, int, size_t) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
// This implementation was taken from musl
|
||||
void *memrchr(const void *m, int c, size_t n) {
|
||||
const unsigned char *s = (const unsigned char *)m;
|
||||
c = (unsigned char)c;
|
||||
while(n--) {
|
||||
if(s[n] == c)
|
||||
return (void *)(s + n);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char *strerror_l(int errnum, locale_t) {
|
||||
mlibc::infoLogger() << "mlibc: strerror_l locale is ignored!" << frg::endlog;
|
||||
return strerror(errnum);
|
||||
}
|
||||
|
||||
// BSD extensions.
|
||||
// Taken from musl
|
||||
size_t strlcpy(char *d, const char *s, size_t n) {
|
||||
char *d0 = d;
|
||||
|
||||
if(!n--)
|
||||
goto finish;
|
||||
for(; n && (*d=*s); n--, s++, d++);
|
||||
*d = 0;
|
||||
finish:
|
||||
return d-d0 + strlen(s);
|
||||
}
|
||||
|
||||
size_t strlcat(char *d, const char *s, size_t n) {
|
||||
size_t l = strnlen(d, n);
|
||||
if(l == n) {
|
||||
return l + strlen(s);
|
||||
}
|
||||
return l + strlcpy(d + l, s, n - l);
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
#include <abi-bits/fcntl.h>
|
||||
#include <bits/posix/posix_time.h>
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/posix-sysdeps.hpp>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
|
||||
int timer_getoverrun(timer_t) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
int utimes(const char *filename, const struct timeval times[2]) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_utimensat, -1);
|
||||
struct timespec time[2];
|
||||
if(times == nullptr) {
|
||||
time[0].tv_sec = UTIME_NOW;
|
||||
time[0].tv_nsec = UTIME_NOW;
|
||||
time[1].tv_sec = UTIME_NOW;
|
||||
time[1].tv_nsec = UTIME_NOW;
|
||||
} else {
|
||||
time[0].tv_sec = times[0].tv_sec;
|
||||
time[0].tv_nsec = times[0].tv_usec * 1000;
|
||||
time[1].tv_sec = times[1].tv_sec;
|
||||
time[1].tv_nsec = times[1].tv_usec * 1000;
|
||||
}
|
||||
|
||||
if (int e = mlibc::sys_utimensat(AT_FDCWD, filename, time, 0); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int futimes(int, const struct timeval[2]) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
int lutimes(const char *filename, const struct timeval tv[2]) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_utimensat, -1);
|
||||
struct timespec time[2];
|
||||
if(tv == nullptr) {
|
||||
time[0].tv_sec = UTIME_NOW;
|
||||
time[0].tv_nsec = UTIME_NOW;
|
||||
time[1].tv_sec = UTIME_NOW;
|
||||
time[1].tv_nsec = UTIME_NOW;
|
||||
} else {
|
||||
time[0].tv_sec = tv[0].tv_sec;
|
||||
time[0].tv_nsec = tv[0].tv_usec * 1000;
|
||||
time[1].tv_sec = tv[1].tv_sec;
|
||||
time[1].tv_nsec = tv[1].tv_usec * 1000;
|
||||
}
|
||||
|
||||
if (int e = mlibc::sys_utimensat(AT_FDCWD, filename, time, AT_SYMLINK_NOFOLLOW); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,309 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <bits/ensure.h>
|
||||
|
||||
#include <mlibc/debug.hpp>
|
||||
|
||||
namespace {
|
||||
FILE *global_file; // Used by setpwent/getpwent/endpwent.
|
||||
|
||||
bool open_global_file() {
|
||||
if(!global_file) {
|
||||
global_file = fopen("/etc/passwd", "r");
|
||||
if(!global_file) {
|
||||
errno = EIO;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void close_global_file() {
|
||||
if(global_file) {
|
||||
fclose(global_file);
|
||||
global_file = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool extract_entry(frg::string_view line, passwd *entry) {
|
||||
frg::string_view segments[8];
|
||||
|
||||
// Parse the line into 7 or 8 segments.
|
||||
size_t s = 0;
|
||||
int n;
|
||||
for(n = 0; n < 7; n++) {
|
||||
size_t d = line.find_first(':', s);
|
||||
if(d == size_t(-1))
|
||||
break;
|
||||
segments[n] = line.sub_string(s, d - s);
|
||||
s = d + 1;
|
||||
}
|
||||
if(line.find_first(':', s) != size_t(-1))
|
||||
return false;
|
||||
segments[n] = line.sub_string(s, line.size() - s);
|
||||
n++;
|
||||
|
||||
if(n < 7)
|
||||
return false;
|
||||
|
||||
// TODO: Handle strndup() failure.
|
||||
auto name = strndup(segments[0].data(), segments[0].size());
|
||||
__ensure(name);
|
||||
|
||||
auto passwd = strndup(segments[1].data(), segments[1].size());
|
||||
__ensure(passwd);
|
||||
|
||||
auto uid = segments[2].to_number<int>();
|
||||
if(!uid)
|
||||
return false;
|
||||
auto gid = segments[3].to_number<int>();
|
||||
if(!gid)
|
||||
return false;
|
||||
|
||||
auto real_name = strndup(segments[4].data(), segments[4].size());
|
||||
__ensure(real_name);
|
||||
auto dir = strndup(segments[5].data(), segments[5].size());
|
||||
__ensure(dir);
|
||||
auto shell = strndup(segments[6].data(), segments[6].size());
|
||||
__ensure(shell);
|
||||
|
||||
// Chop the newline off the end of shell
|
||||
__ensure(strlen(shell) > 0);
|
||||
shell[strlen(shell) - 1] = '\0';
|
||||
|
||||
entry->pw_name = name;
|
||||
entry->pw_passwd = passwd;
|
||||
entry->pw_uid = *uid;
|
||||
entry->pw_gid = *gid;
|
||||
entry->pw_dir = dir;
|
||||
entry->pw_shell = shell;
|
||||
entry->pw_gecos = real_name;
|
||||
return true;
|
||||
}
|
||||
|
||||
void copy_to_buffer(passwd *pwd, char *buffer, size_t size) {
|
||||
char *pw_dir = stpcpy(buffer, pwd->pw_name) + 1;
|
||||
free(pwd->pw_name);
|
||||
pwd->pw_name = buffer;
|
||||
|
||||
char *pw_shell = stpcpy(pw_dir, pwd->pw_dir) + 1;
|
||||
free(pwd->pw_dir);
|
||||
pwd->pw_dir = pw_dir;
|
||||
|
||||
char *pw_passwd = stpcpy(pw_shell, pwd->pw_shell) + 1;
|
||||
free(pwd->pw_shell);
|
||||
pwd->pw_shell = pw_shell;
|
||||
|
||||
char *end = stpcpy(pw_passwd, pwd->pw_passwd);
|
||||
__ensure(end <= buffer + size);
|
||||
free(pwd->pw_passwd);
|
||||
pwd->pw_passwd = pw_passwd;
|
||||
}
|
||||
|
||||
void clear_entry(passwd *entry) {
|
||||
free(entry->pw_name);
|
||||
free(entry->pw_dir);
|
||||
free(entry->pw_passwd);
|
||||
free(entry->pw_shell);
|
||||
entry->pw_name = nullptr;
|
||||
entry->pw_dir = nullptr;
|
||||
entry->pw_passwd = nullptr;
|
||||
entry->pw_shell = nullptr;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
struct passwd *getpwent(void) {
|
||||
static passwd entry;
|
||||
char line[NSS_BUFLEN_PASSWD];
|
||||
|
||||
if(!open_global_file()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (fgets(line, NSS_BUFLEN_PASSWD, global_file)) {
|
||||
clear_entry(&entry);
|
||||
if(!extract_entry(line, &entry)) {
|
||||
errno = EINVAL; // I suppose this can be a valid errno?
|
||||
return nullptr;
|
||||
}
|
||||
return &entry;
|
||||
}
|
||||
|
||||
if(ferror(global_file)) {
|
||||
errno = EIO;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
struct passwd *getpwnam(const char *name) {
|
||||
static passwd entry;
|
||||
auto file = fopen("/etc/passwd", "r");
|
||||
if(!file)
|
||||
return nullptr;
|
||||
|
||||
char line[NSS_BUFLEN_PASSWD];
|
||||
while(fgets(line, NSS_BUFLEN_PASSWD, file)) {
|
||||
clear_entry(&entry);
|
||||
if(!extract_entry(line, &entry))
|
||||
continue;
|
||||
if(!strcmp(entry.pw_name, name)) {
|
||||
fclose(file);
|
||||
return &entry;
|
||||
}
|
||||
}
|
||||
|
||||
int err = errno;
|
||||
if(ferror(file)) {
|
||||
err = EIO;
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
errno = err;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int getpwnam_r(const char *name, struct passwd *pwd, char *buffer, size_t size, struct passwd **result) {
|
||||
*result = nullptr;
|
||||
auto file = fopen("/etc/passwd", "r");
|
||||
if(!file) {
|
||||
return EIO;
|
||||
}
|
||||
|
||||
char line[NSS_BUFLEN_PASSWD];
|
||||
while(fgets(line, NSS_BUFLEN_PASSWD, file)) {
|
||||
if(!extract_entry(line, pwd))
|
||||
continue;
|
||||
if(!strcmp(pwd->pw_name, name)) {
|
||||
fclose(file);
|
||||
|
||||
size_t required_size = strlen(pwd->pw_name) + strlen(pwd->pw_dir)
|
||||
+ strlen(pwd->pw_shell) + strlen(pwd->pw_passwd) + 4;
|
||||
if (size < required_size)
|
||||
return ERANGE;
|
||||
|
||||
copy_to_buffer(pwd, buffer, size);
|
||||
*result = pwd;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
if(ferror(file)) {
|
||||
ret = EIO;
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct passwd *getpwuid(uid_t uid) {
|
||||
static passwd entry;
|
||||
auto file = fopen("/etc/passwd", "r");
|
||||
if(!file)
|
||||
return nullptr;
|
||||
|
||||
char line[NSS_BUFLEN_PASSWD];
|
||||
while(fgets(line, NSS_BUFLEN_PASSWD, file)) {
|
||||
clear_entry(&entry);
|
||||
if(!extract_entry(line, &entry))
|
||||
continue;
|
||||
if(entry.pw_uid == uid) {
|
||||
fclose(file);
|
||||
return &entry;
|
||||
}
|
||||
}
|
||||
|
||||
int err = ESRCH;
|
||||
if(ferror(file)) {
|
||||
err = EIO;
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
errno = err;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, size_t size, struct passwd **result) {
|
||||
*result = nullptr;
|
||||
auto file = fopen("/etc/passwd", "r");
|
||||
if(!file) {
|
||||
return EIO;
|
||||
}
|
||||
|
||||
char line[NSS_BUFLEN_PASSWD];
|
||||
while(fgets(line, NSS_BUFLEN_PASSWD, file)) {
|
||||
if(!extract_entry(line, pwd))
|
||||
continue;
|
||||
if(pwd->pw_uid == uid) {
|
||||
fclose(file);
|
||||
|
||||
size_t required_size = strlen(pwd->pw_name) + strlen(pwd->pw_dir)
|
||||
+ strlen(pwd->pw_shell) + + strlen(pwd->pw_passwd) + 4;
|
||||
if (size < required_size)
|
||||
return ERANGE;
|
||||
|
||||
copy_to_buffer(pwd, buffer, size);
|
||||
*result = pwd;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
if(ferror(file)) {
|
||||
ret = EIO;
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void setpwent(void) {
|
||||
if(!open_global_file()) {
|
||||
return;
|
||||
}
|
||||
rewind(global_file);
|
||||
}
|
||||
|
||||
void endpwent(void) {
|
||||
close_global_file();
|
||||
}
|
||||
|
||||
int putpwent(const struct passwd *p, FILE *f) {
|
||||
auto invalid = [](const char *s) {
|
||||
return s == nullptr || strchr(s, '\n') || strchr(s, ':');
|
||||
};
|
||||
|
||||
if (p == nullptr || invalid(p->pw_name) || invalid(p->pw_passwd) || invalid(p->pw_gecos) || invalid(p->pw_dir) || invalid(p->pw_shell)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Taken from musl.
|
||||
return fprintf(f, "%s:%s:%u:%u:%s:%s:%s\n", p->pw_name, p->pw_passwd, p->pw_uid, p->pw_gid, p->pw_gecos, p->pw_dir, p->pw_shell) < 0 ? -1 : 0;
|
||||
}
|
||||
|
||||
struct passwd *fgetpwent(FILE *file) {
|
||||
static passwd entry;
|
||||
char line[NSS_BUFLEN_PASSWD];
|
||||
|
||||
|
||||
if (fgets(line, NSS_BUFLEN_PASSWD, file)) {
|
||||
clear_entry(&entry);
|
||||
if(!extract_entry(line, &entry)) {
|
||||
errno = EINVAL; // I suppose this can be a valid errno?
|
||||
return nullptr;
|
||||
}
|
||||
return &entry;
|
||||
}
|
||||
|
||||
if(ferror(file)) {
|
||||
errno = EIO;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#include <mlibc/resolv_conf.hpp>
|
||||
#include <mlibc/allocator.hpp>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
frg::optional<struct nameserver_data> get_nameserver() {
|
||||
auto file = fopen("/etc/resolv.conf", "r");
|
||||
if (!file)
|
||||
return frg::null_opt;
|
||||
|
||||
char line[128];
|
||||
struct nameserver_data ret;
|
||||
while (fgets(line, 128, file)) {
|
||||
char *pos;
|
||||
if (!strchr(line, '\n') && !feof(file)) {
|
||||
// skip truncated lines
|
||||
for (int c = getc(file); c != '\n' && c != EOF; c = getc(file));
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO(geert): resolv.conf can actually have multiple nameservers
|
||||
// but we just pick the first one for now
|
||||
if (!strncmp(line, "nameserver", 10) && isspace(line[10])) {
|
||||
char *end;
|
||||
for (pos = line + 11; isspace(*pos); pos++);
|
||||
for (end = pos; *end && !isspace(*end); end++);
|
||||
*end = '\0';
|
||||
ret.name = frg::string<MemoryAllocator>(
|
||||
pos, end - pos, getAllocator());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
if(ret.name.empty())
|
||||
return frg::null_opt;
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace mlibc
|
||||
@@ -0,0 +1,63 @@
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <sched.h>
|
||||
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/posix-sysdeps.hpp>
|
||||
|
||||
int sched_yield(void) {
|
||||
if(mlibc::sys_yield) {
|
||||
mlibc::sys_yield();
|
||||
}else{
|
||||
// Missing sched_yield() is not an error.
|
||||
MLIBC_MISSING_SYSDEP();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sched_get_priority_max(int policy) {
|
||||
int res = 0;
|
||||
|
||||
auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_get_max_priority, -1);
|
||||
if(int e = sysdep(policy, &res); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int sched_get_priority_min(int policy) {
|
||||
int res = 0;
|
||||
|
||||
auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_get_min_priority, -1);
|
||||
if(int e = sysdep(policy, &res); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int sched_setscheduler(pid_t, int, const struct sched_param *) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
int sched_getparam(pid_t pid, struct sched_param *param) {
|
||||
auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getparam, -1);
|
||||
if(int e = sysdep(pid, param); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sched_setparam(pid_t pid, const struct sched_param *param) {
|
||||
auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setparam, -1);
|
||||
if(int e = sysdep(pid, param); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <search.h>
|
||||
#include <stddef.h>
|
||||
#include <new>
|
||||
#include <mlibc/allocator.hpp>
|
||||
#include <mlibc/search.hpp>
|
||||
#include <frg/stack.hpp>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct node {
|
||||
const void *key;
|
||||
void *a[2];
|
||||
int h;
|
||||
};
|
||||
|
||||
namespace {
|
||||
int height(struct node *node) {
|
||||
return node ? node->h : 0;
|
||||
}
|
||||
|
||||
int rotate(struct node **nodep, int side) {
|
||||
struct node *node = *nodep;
|
||||
struct node *x = static_cast<struct node *>(node->a[side]);
|
||||
struct node *y = static_cast<struct node *>(x->a[!side]);
|
||||
struct node *z = static_cast<struct node *>(x->a[side]);
|
||||
|
||||
int height_node = node->h;
|
||||
int height_y = height(y);
|
||||
if (height_y > height(z)) {
|
||||
// Perform double rotation
|
||||
node->a[side] = y->a[!side];
|
||||
x->a[!side] = y->a[side];
|
||||
y->a[!side] = node;
|
||||
y->a[side] = x;
|
||||
node->h = height_y;
|
||||
x->h = height_y;
|
||||
y->h = height_y + 1;
|
||||
} else {
|
||||
// Perform single rotation
|
||||
node->a[side] = y;
|
||||
x->a[!side] = node;
|
||||
node->h = height_y + 1;
|
||||
x->h = height_y + 2;
|
||||
y = x;
|
||||
|
||||
}
|
||||
*nodep = y;
|
||||
return y->h - height_node;
|
||||
}
|
||||
|
||||
int balance_tree(struct node **nodep) {
|
||||
struct node *node = *nodep;
|
||||
int height_a = height(static_cast<struct node *>(node->a[0]));
|
||||
int height_b = height(static_cast<struct node *>(node->a[1]));
|
||||
if (height_a - height_b < 2) {
|
||||
int old = node->h;
|
||||
node->h = height_a < height_b ? height_b + 1 : height_a + 1;
|
||||
return node->h - old;
|
||||
}
|
||||
|
||||
return rotate(nodep, height_a < height_b);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void *tsearch(const void *key, void **rootp, int(*compar)(const void *, const void *)) {
|
||||
if (!rootp)
|
||||
return nullptr;
|
||||
|
||||
struct node *n = static_cast<struct node *>(*rootp);
|
||||
frg::stack<struct node **, MemoryAllocator> nodes(getAllocator());
|
||||
nodes.push(reinterpret_cast<struct node **>(rootp));
|
||||
int c = 0;
|
||||
for (;;) {
|
||||
if (!n)
|
||||
break;
|
||||
c = compar(key, n->key);
|
||||
if (!c)
|
||||
return n;
|
||||
nodes.push(reinterpret_cast<struct node **>(&n->a[c > 0]));
|
||||
n = static_cast<struct node *>(n->a[c > 0]);
|
||||
}
|
||||
|
||||
struct node *insert = static_cast<struct node*>(malloc(sizeof(struct node)));
|
||||
if (!insert)
|
||||
return nullptr;
|
||||
insert->key = key;
|
||||
insert->a[0] = insert->a[1] = nullptr;
|
||||
insert->h = 1;
|
||||
|
||||
(*nodes.top()) = insert;
|
||||
nodes.pop();
|
||||
while(nodes.size() && balance_tree(nodes.top())) nodes.pop();
|
||||
return insert;
|
||||
}
|
||||
|
||||
// This implementation is taken from musl
|
||||
void *tfind(const void *key, void *const *rootp, int (*compar)(const void *, const void *)) {
|
||||
if(!rootp)
|
||||
return nullptr;
|
||||
|
||||
struct node *n = (struct node *)*rootp;
|
||||
for(;;) {
|
||||
if(!n)
|
||||
break;
|
||||
int c = compar(key, n->key);
|
||||
if(!c)
|
||||
break;
|
||||
n = (struct node *)n->a[c > 0];
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void *tdelete(const void *, void **, int(*compar)(const void *, const void *)) {
|
||||
(void)compar;
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void twalk(const void *, void (*action)(const void *, VISIT, int)) {
|
||||
(void)action;
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void tdestroy(void *root, void (*free_node)(void *)) {
|
||||
auto *n = static_cast<node *>(root);
|
||||
frg::stack<node *, MemoryAllocator> nodes(getAllocator());
|
||||
|
||||
while(n || !nodes.empty()) {
|
||||
if(n == nullptr) {
|
||||
n = nodes.top();
|
||||
nodes.pop();
|
||||
free_node(const_cast<void *>(n->key));
|
||||
auto *next = static_cast<node *>(n->a[1]);
|
||||
free(n);
|
||||
n = next;
|
||||
} else {
|
||||
nodes.push(n);
|
||||
n = static_cast<node *>(n->a[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void *lsearch(const void *key, void *base, size_t *nelp, size_t width,
|
||||
int (*compar)(const void *, const void *)) {
|
||||
(void)key;
|
||||
(void)base;
|
||||
(void)nelp;
|
||||
(void)width;
|
||||
(void)compar;
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void *lfind(const void *key, const void *base, size_t *nelp,
|
||||
size_t width, int (*compar)(const void *, const void *)) {
|
||||
(void)key;
|
||||
(void)base;
|
||||
(void)nelp;
|
||||
(void)width;
|
||||
(void)compar;
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
namespace {
|
||||
hsearch_data globalTable {};
|
||||
} // namespace
|
||||
|
||||
int hcreate(size_t num_entries) {
|
||||
return mlibc::hcreate_r(num_entries, &globalTable);
|
||||
}
|
||||
|
||||
void hdestroy(void) {
|
||||
mlibc::hdestroy_r(&globalTable);
|
||||
}
|
||||
|
||||
ENTRY *hsearch(ENTRY item, ACTION action) {
|
||||
ENTRY *ret;
|
||||
if(mlibc::hsearch_r(item, action, &ret, &globalTable) == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
#include <semaphore.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/ansi-sysdeps.hpp>
|
||||
#include <mlibc/posix-sysdeps.hpp>
|
||||
|
||||
static constexpr unsigned int semaphoreHasWaiters = static_cast<uint32_t>(1 << 31);
|
||||
static constexpr unsigned int semaphoreCountMask = static_cast<uint32_t>(1 << 31) - 1;
|
||||
|
||||
int sem_init(sem_t *sem, int pshared, unsigned int initial_count) {
|
||||
if (pshared) {
|
||||
mlibc::infoLogger() << "mlibc: shared semaphores are unsuppored" << frg::endlog;
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (initial_count > SEM_VALUE_MAX) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
sem->__mlibc_count = initial_count;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sem_destroy(sem_t *) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sem_wait(sem_t *sem) {
|
||||
unsigned int state = 0;
|
||||
|
||||
while (1) {
|
||||
if (!(state & semaphoreCountMask)) {
|
||||
if (__atomic_compare_exchange_n(&sem->__mlibc_count, &state, semaphoreHasWaiters,
|
||||
false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE)) {
|
||||
int e = mlibc::sys_futex_wait((int *)&sem->__mlibc_count, state, nullptr);
|
||||
if (e == 0 || e == EAGAIN) {
|
||||
continue;
|
||||
} else if (e == EINTR) {
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
} else {
|
||||
mlibc::panicLogger() << "sys_futex_wait() failed with error code " << e << frg::endlog;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unsigned int desired = (state - 1);
|
||||
if (__atomic_compare_exchange_n(&sem->__mlibc_count, &state, desired, false,
|
||||
__ATOMIC_RELAXED, __ATOMIC_RELAXED))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int sem_timedwait(sem_t *sem, const struct timespec *) {
|
||||
mlibc::infoLogger() << "\e[31mmlibc: sem_timedwait is implemented as sem_wait\e[0m" << frg::endlog;
|
||||
return sem_wait(sem);
|
||||
}
|
||||
|
||||
int sem_post(sem_t *sem) {
|
||||
auto old_count = __atomic_load_n(&sem->__mlibc_count, __ATOMIC_RELAXED) & semaphoreCountMask;
|
||||
|
||||
if (old_count + 1 > SEM_VALUE_MAX) {
|
||||
errno = EOVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto state = __atomic_exchange_n(&sem->__mlibc_count, old_count + 1, __ATOMIC_RELEASE);
|
||||
|
||||
if (state & semaphoreHasWaiters)
|
||||
if (int e = mlibc::sys_futex_wake((int *)&sem->__mlibc_count); e)
|
||||
__ensure(!"sys_futex_wake() failed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sem_t *sem_open(const char *, int, ...) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
int sem_close(sem_t *) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
int sem_getvalue(sem_t *, int *) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
int sem_unlink(const char *) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
int sem_trywait(sem_t *sem) {
|
||||
while (true) {
|
||||
auto state = __atomic_load_n(&sem->__mlibc_count, __ATOMIC_ACQUIRE);
|
||||
|
||||
if ((state & semaphoreHasWaiters) || !state) {
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto desired = state - 1;
|
||||
if (__atomic_compare_exchange_n(&sem->__mlibc_count, &state, desired, false, __ATOMIC_RELEASE, __ATOMIC_RELAXED)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
#include <mlibc/services.hpp>
|
||||
#include <netdb.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <mlibc/debug.hpp>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
static int parse_rest(service_buf &buf, char *end, int proto) {
|
||||
if (!strncmp(end, "/udp", 4)) {
|
||||
if (proto == IPPROTO_TCP && proto != -1)
|
||||
return 0;
|
||||
buf.protocol = IPPROTO_UDP;
|
||||
buf.socktype = SOCK_DGRAM;
|
||||
} else if (!strncmp(end, "/tcp", 4)) {
|
||||
if (proto == IPPROTO_UDP && proto != -1)
|
||||
return 0;
|
||||
buf.protocol = IPPROTO_TCP;
|
||||
buf.socktype = SOCK_STREAM;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
//TODO(geert): also parse aliases.
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lookup_serv_file_port(service_result &buf, int proto, int port) {
|
||||
auto file = fopen(_PATH_SERVICES, "r");
|
||||
if (!file) {
|
||||
switch (errno) {
|
||||
case ENOENT:
|
||||
case ENOTDIR:
|
||||
case EACCES:
|
||||
return -EAI_SERVICE;
|
||||
default:
|
||||
return -EAI_SYSTEM;
|
||||
}
|
||||
}
|
||||
|
||||
char line_buf[129] = {0};
|
||||
char *line = line_buf + 1;
|
||||
while(fgets(line, 128, file)) {
|
||||
int name_length = 0;
|
||||
char *pos;
|
||||
// easy way to handle comments, just move the end of the line
|
||||
// to the beginning of the comment
|
||||
if ((pos = strchr(line, '#'))) {
|
||||
*pos++ = '\n';
|
||||
*pos = '\0';
|
||||
}
|
||||
|
||||
char *end = nullptr;
|
||||
for (pos = line; *pos; pos++) {
|
||||
for (; isalpha(*pos); pos++);
|
||||
int rport = strtoul(pos, &end, 10);
|
||||
if (rport != port || rport > 65535) {
|
||||
pos = end;
|
||||
continue;
|
||||
}
|
||||
|
||||
// We have found the port, time to rewind to the start
|
||||
// of the line.
|
||||
for (; pos[-1]; pos--)
|
||||
if(!isspace(pos[-1]))
|
||||
name_length++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!pos)
|
||||
continue;
|
||||
|
||||
if (!name_length)
|
||||
continue;
|
||||
|
||||
auto name = frg::string<MemoryAllocator>(pos, name_length,
|
||||
getAllocator());
|
||||
|
||||
struct service_buf sbuf = {};
|
||||
sbuf.port = port;
|
||||
sbuf.name = std::move(name);
|
||||
if (!parse_rest(sbuf, end, proto))
|
||||
continue;
|
||||
buf.push_back(std::move(sbuf));
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
return buf.size();
|
||||
}
|
||||
|
||||
static int lookup_serv_file_name(service_result &buf, const char *name,
|
||||
int proto) {
|
||||
auto file = fopen(_PATH_SERVICES, "r");
|
||||
if (!file) {
|
||||
switch (errno) {
|
||||
case ENOENT:
|
||||
case ENOTDIR:
|
||||
case EACCES:
|
||||
return -EAI_SERVICE;
|
||||
default:
|
||||
return -EAI_SYSTEM;
|
||||
}
|
||||
}
|
||||
|
||||
char line[128];
|
||||
int name_length = strlen(name);
|
||||
while(fgets(line, 128, file)) {
|
||||
char *pos;
|
||||
// easy way to handle comments, just move the end of the line
|
||||
// to the beginning of the comment
|
||||
if ((pos = strchr(line, '#'))) {
|
||||
*pos++ = '\n';
|
||||
*pos = '\0';
|
||||
}
|
||||
|
||||
for (pos = line; (pos = strstr(pos, name)); pos++) {
|
||||
// the name must start and end with a space
|
||||
if (pos > line && !isspace(pos[-1]))
|
||||
continue;
|
||||
if (pos[name_length] && !isspace(pos[name_length]))
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
if (!pos)
|
||||
continue;
|
||||
|
||||
// Skip the name at the beginning of the line.
|
||||
for(pos = line; *pos && !isspace(*pos); pos++)
|
||||
;
|
||||
|
||||
char *end = nullptr;
|
||||
int port = strtoul(pos, &end, 10);
|
||||
if (port > 65535 || end == pos)
|
||||
continue;
|
||||
|
||||
struct service_buf sbuf;
|
||||
sbuf.port = port;
|
||||
sbuf.name = frg::string<MemoryAllocator>(name, getAllocator());
|
||||
if (!parse_rest(sbuf, end, proto))
|
||||
continue;
|
||||
|
||||
buf.push_back(sbuf);
|
||||
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
return buf.size();
|
||||
}
|
||||
|
||||
|
||||
// This function returns a negative error code, since a positive
|
||||
// return code means success.
|
||||
int lookup_serv_by_name(service_result &buf, const char *name, int proto,
|
||||
int socktype, int flags) {
|
||||
switch(socktype) {
|
||||
case SOCK_STREAM:
|
||||
if (!proto)
|
||||
proto = IPPROTO_TCP;
|
||||
else if (proto != IPPROTO_TCP)
|
||||
return -EAI_SERVICE;
|
||||
break;
|
||||
case SOCK_DGRAM:
|
||||
if (!proto)
|
||||
proto = IPPROTO_UDP;
|
||||
else if (proto != IPPROTO_UDP)
|
||||
return -EAI_SERVICE;
|
||||
break;
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
if (name)
|
||||
return -EAI_SERVICE;
|
||||
buf[0].port = 0;
|
||||
buf[0].socktype = socktype;
|
||||
buf[0].protocol = proto;
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *end = nullptr;
|
||||
unsigned int port = 0;
|
||||
int count = 0;
|
||||
|
||||
if (name) {
|
||||
if (!*name)
|
||||
return -EAI_SERVICE;
|
||||
port = strtoul(name, &end, 10);
|
||||
}
|
||||
// The end pointer is a null pointer so the name was a port
|
||||
// or the name was not specified.
|
||||
if (!end || !*end) {
|
||||
if (proto != IPPROTO_UDP) {
|
||||
buf[count].port = port;
|
||||
buf[count].protocol = IPPROTO_TCP;
|
||||
buf[count].socktype = SOCK_STREAM;
|
||||
count++;
|
||||
}
|
||||
if (proto != IPPROTO_TCP) {
|
||||
buf[count].port = port;
|
||||
buf[count].protocol = IPPROTO_UDP;
|
||||
buf[count].socktype = SOCK_DGRAM;
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
if (flags & AI_NUMERICSERV)
|
||||
return -EAI_NONAME;
|
||||
|
||||
return lookup_serv_file_name(buf, name, proto);
|
||||
}
|
||||
|
||||
int lookup_serv_by_port(service_result &buf, int proto, int port) {
|
||||
return lookup_serv_file_port(buf, proto, port);
|
||||
}
|
||||
|
||||
} // namespace mlibc
|
||||
@@ -0,0 +1,376 @@
|
||||
|
||||
#include <spawn.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <sched.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/debug.hpp>
|
||||
|
||||
/*
|
||||
* Musl places this in a seperate header called fdop.h
|
||||
* This header isn't present in glibc, or on my host, so I
|
||||
* include it's contents here
|
||||
*/
|
||||
|
||||
#define FDOP_CLOSE 1
|
||||
#define FDOP_DUP2 2
|
||||
#define FDOP_OPEN 3
|
||||
#define FDOP_CHDIR 4
|
||||
#define FDOP_FCHDIR 5
|
||||
|
||||
struct fdop {
|
||||
struct fdop *next, *prev;
|
||||
int cmd, fd, srcfd, oflag;
|
||||
mode_t mode;
|
||||
char path[];
|
||||
};
|
||||
|
||||
/*
|
||||
* This posix_spawn implementation is taken from musl
|
||||
*/
|
||||
|
||||
static unsigned long handler_set[NSIG / (8 * sizeof(long))];
|
||||
|
||||
static void __get_handler_set(sigset_t *set) {
|
||||
memcpy(set, handler_set, sizeof handler_set);
|
||||
}
|
||||
|
||||
struct args {
|
||||
int p[2];
|
||||
sigset_t oldmask;
|
||||
const char *path;
|
||||
const posix_spawn_file_actions_t *fa;
|
||||
const posix_spawnattr_t *__restrict attr;
|
||||
char *const *argv, *const *envp;
|
||||
};
|
||||
|
||||
static int child(void *args_vp) {
|
||||
int i, ret;
|
||||
struct sigaction sa = {};
|
||||
struct args *args = (struct args *)args_vp;
|
||||
int p = args->p[1];
|
||||
const posix_spawn_file_actions_t *fa = args->fa;
|
||||
const posix_spawnattr_t *__restrict attr = args->attr;
|
||||
sigset_t hset;
|
||||
bool use_execvpe = false;
|
||||
|
||||
if(attr->__fn)
|
||||
use_execvpe = true;
|
||||
|
||||
close(args->p[0]);
|
||||
|
||||
/* All signal dispositions must be either SIG_DFL or SIG_IGN
|
||||
* before signals are unblocked. Otherwise a signal handler
|
||||
* from the parent might get run in the child while sharing
|
||||
* memory, with unpredictable and dangerous results. To
|
||||
* reduce overhead, sigaction has tracked for us which signals
|
||||
* potentially have a signal handler. */
|
||||
__get_handler_set(&hset);
|
||||
for(i = 1; i < NSIG; i++) {
|
||||
if((attr->__flags & POSIX_SPAWN_SETSIGDEF) && sigismember(&attr->__def, i)) {
|
||||
sa.sa_handler = SIG_DFL;
|
||||
} else if(sigismember(&hset, i)) {
|
||||
if (i - 32 < 3) {
|
||||
sa.sa_handler = SIG_IGN;
|
||||
} else {;
|
||||
sigaction(i, nullptr, &sa);
|
||||
if(sa.sa_handler == SIG_IGN)
|
||||
continue;
|
||||
sa.sa_handler = SIG_DFL;
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
sigaction(i, &sa, nullptr);
|
||||
}
|
||||
|
||||
if(attr->__flags & POSIX_SPAWN_SETSID) {
|
||||
if((ret = setsid()) < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if(attr->__flags & POSIX_SPAWN_SETPGROUP) {
|
||||
mlibc::infoLogger() << "mlibc: posix_spawn: ignoring SETPGROUP" << frg::endlog;
|
||||
//if((ret = setpgid(0, attr->__pgrp)))
|
||||
// goto fail;
|
||||
}
|
||||
|
||||
if(attr->__flags & POSIX_SPAWN_RESETIDS) {
|
||||
if((ret = setgid(getgid())) || (ret = setuid(getuid())) )
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if(fa && fa->__actions) {
|
||||
struct fdop *op;
|
||||
int fd;
|
||||
for(op = (struct fdop *)fa->__actions; op->next; op = op->next);
|
||||
for(; op; op = op->prev) {
|
||||
/* It's possible that a file operation would clobber
|
||||
* the pipe fd used for synchronizing with the
|
||||
* parent. To avoid that, we dup the pipe onto
|
||||
* an unoccupied fd. */
|
||||
if(op->fd == p) {
|
||||
ret = dup(p);
|
||||
if(ret < 0)
|
||||
goto fail;
|
||||
close(p);
|
||||
p = ret;
|
||||
}
|
||||
switch(op->cmd) {
|
||||
case FDOP_CLOSE:
|
||||
close(op->fd);
|
||||
break;
|
||||
case FDOP_DUP2:
|
||||
fd = op->srcfd;
|
||||
if(fd == p) {
|
||||
ret = -EBADF;
|
||||
goto fail;
|
||||
}
|
||||
if(fd != op->fd) {
|
||||
if((ret = dup2(fd, op->fd)) < 0)
|
||||
goto fail;
|
||||
} else {
|
||||
ret = fcntl(fd, F_GETFD);
|
||||
ret = fcntl(fd, F_SETFD, ret & ~FD_CLOEXEC);
|
||||
if(ret < 0)
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case FDOP_OPEN:
|
||||
fd = open(op->path, op->oflag, op->mode);
|
||||
if((ret = fd) < 0)
|
||||
goto fail;
|
||||
if(fd != op->fd) {
|
||||
if((ret = dup2(fd, op->fd)) < 0)
|
||||
goto fail;
|
||||
close(fd);
|
||||
}
|
||||
break;
|
||||
case FDOP_CHDIR:
|
||||
ret = chdir(op->path);
|
||||
if(ret < 0)
|
||||
goto fail;
|
||||
break;
|
||||
case FDOP_FCHDIR:
|
||||
ret = fchdir(op->fd);
|
||||
if(ret < 0)
|
||||
goto fail;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Close-on-exec flag may have been lost if we moved the pipe
|
||||
* to a different fd. */
|
||||
fcntl(p, F_SETFD, FD_CLOEXEC);
|
||||
|
||||
pthread_sigmask(SIG_SETMASK, (attr->__flags & POSIX_SPAWN_SETSIGMASK)
|
||||
? &attr->__mask : &args->oldmask, nullptr);
|
||||
|
||||
if(use_execvpe)
|
||||
execvpe(args->path, args->argv, args->envp);
|
||||
else
|
||||
execve(args->path, args->argv, args->envp);
|
||||
ret = -errno;
|
||||
|
||||
fail:
|
||||
/* Since sizeof errno < PIPE_BUF, the write is atomic. */
|
||||
ret = -ret;
|
||||
if(ret)
|
||||
while(write(p, &ret, sizeof ret) < 0);
|
||||
_exit(127);
|
||||
}
|
||||
|
||||
int posix_spawn(pid_t *__restrict res, const char *__restrict path,
|
||||
const posix_spawn_file_actions_t *file_actions,
|
||||
const posix_spawnattr_t *__restrict attrs,
|
||||
char *const argv[], char *const envp[]) {
|
||||
pid_t pid;
|
||||
int ec = 0, cs;
|
||||
struct args args;
|
||||
const posix_spawnattr_t empty_attr = {};
|
||||
sigset_t full_sigset;
|
||||
sigfillset(&full_sigset);
|
||||
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
|
||||
|
||||
args.path = path;
|
||||
args.fa = file_actions;
|
||||
args.attr = attrs ? attrs : &empty_attr;
|
||||
args.argv = argv;
|
||||
args.envp = envp;
|
||||
pthread_sigmask(SIG_BLOCK, &full_sigset, &args.oldmask);
|
||||
|
||||
/* The lock guards both against seeing a SIGABRT disposition change
|
||||
* by abort and against leaking the pipe fd to fork-without-exec. */
|
||||
//LOCK(__abort_lock);
|
||||
|
||||
if(pipe2(args.p, O_CLOEXEC)) {
|
||||
//UNLOCK(__abort_lock);
|
||||
ec = errno;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Mlibc change: We use fork + execve, as clone is not implemented.
|
||||
* This yields the same result in the end. */
|
||||
//pid = clone(child, stack + sizeof stack, CLONE_VM | CLONE_VFORK | SIGCHLD, &args);
|
||||
pid = fork();
|
||||
if(!pid) {
|
||||
child(&args);
|
||||
}
|
||||
close(args.p[1]);
|
||||
//UNLOCK(__abort_lock);
|
||||
|
||||
if(pid > 0) {
|
||||
if(read(args.p[0], &ec, sizeof ec) != sizeof ec)
|
||||
ec = 0;
|
||||
else
|
||||
waitpid(pid, nullptr, 0);
|
||||
} else {
|
||||
ec = -pid;
|
||||
}
|
||||
|
||||
close(args.p[0]);
|
||||
|
||||
if(!ec && res)
|
||||
*res = pid;
|
||||
|
||||
fail:
|
||||
pthread_sigmask(SIG_SETMASK, &args.oldmask, nullptr);
|
||||
pthread_setcancelstate(cs, nullptr);
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
int posix_spawnattr_init(posix_spawnattr_t *attr) {
|
||||
*attr = (posix_spawnattr_t){};
|
||||
return 0;
|
||||
}
|
||||
|
||||
int posix_spawnattr_destroy(posix_spawnattr_t *) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int posix_spawnattr_setflags(posix_spawnattr_t *attr, short flags) {
|
||||
const unsigned all_flags =
|
||||
POSIX_SPAWN_RESETIDS |
|
||||
POSIX_SPAWN_SETPGROUP |
|
||||
POSIX_SPAWN_SETSIGDEF |
|
||||
POSIX_SPAWN_SETSIGMASK |
|
||||
POSIX_SPAWN_SETSCHEDPARAM |
|
||||
POSIX_SPAWN_SETSCHEDULER |
|
||||
POSIX_SPAWN_USEVFORK |
|
||||
POSIX_SPAWN_SETSID;
|
||||
if(flags & ~all_flags)
|
||||
return EINVAL;
|
||||
attr->__flags = flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int posix_spawnattr_setsigdefault(posix_spawnattr_t *__restrict attr,
|
||||
const sigset_t *__restrict sigdefault) {
|
||||
attr->__def = *sigdefault;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int posix_spawnattr_setschedparam(posix_spawnattr_t *__restrict,
|
||||
const struct sched_param *__restrict) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
int posix_spawnattr_setschedpolicy(posix_spawnattr_t *, int) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
int posix_spawnattr_setsigmask(posix_spawnattr_t *__restrict attr,
|
||||
const sigset_t *__restrict sigmask) {
|
||||
attr->__mask = *sigmask;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int posix_spawnattr_setpgroup(posix_spawnattr_t *attr, pid_t pgroup) {
|
||||
attr->__pgrp = pgroup;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int posix_spawn_file_actions_init(posix_spawn_file_actions_t *file_actions) {
|
||||
file_actions->__actions = nullptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *file_actions) {
|
||||
struct fdop *op = (struct fdop *)file_actions->__actions, *next;
|
||||
while(op) {
|
||||
next = op->next;
|
||||
free(op);
|
||||
op = next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *file_actions,
|
||||
int fildes, int newfildes) {
|
||||
struct fdop *op = (struct fdop *)malloc(sizeof *op);
|
||||
if(!op)
|
||||
return ENOMEM;
|
||||
op->cmd = FDOP_DUP2;
|
||||
op->srcfd = fildes;
|
||||
op->fd = newfildes;
|
||||
if((op->next = (struct fdop *)file_actions->__actions))
|
||||
op->next->prev = op;
|
||||
op->prev = nullptr;
|
||||
file_actions->__actions = op;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *file_actions,
|
||||
int fildes) {
|
||||
struct fdop *op = (struct fdop *)malloc(sizeof *op);
|
||||
if(!op)
|
||||
return ENOMEM;
|
||||
op->cmd = FDOP_CLOSE;
|
||||
op->fd = fildes;
|
||||
if((op->next = (struct fdop *)file_actions->__actions))
|
||||
op->next->prev = op;
|
||||
op->prev = nullptr;
|
||||
file_actions->__actions = op;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int posix_spawn_file_actions_addopen(posix_spawn_file_actions_t *__restrict file_actions,
|
||||
int fildes, const char *__restrict path, int oflag, mode_t mode) {
|
||||
struct fdop *op = (struct fdop *)malloc(sizeof *op + strlen(path) + 1);
|
||||
if(!op)
|
||||
return ENOMEM;
|
||||
op->cmd = FDOP_OPEN;
|
||||
op->fd = fildes;
|
||||
op->oflag = oflag;
|
||||
op->mode = mode;
|
||||
strcpy(op->path, path);
|
||||
if((op->next = (struct fdop *)file_actions->__actions))
|
||||
op->next->prev = op;
|
||||
op->prev = nullptr;
|
||||
file_actions->__actions = op;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int posix_spawnp(pid_t *__restrict pid, const char *__restrict file,
|
||||
const posix_spawn_file_actions_t *file_actions,
|
||||
const posix_spawnattr_t *__restrict attrp,
|
||||
char *const argv[], char *const envp[]) {
|
||||
posix_spawnattr_t spawnp_attr = {};
|
||||
if(attrp)
|
||||
spawnp_attr = *attrp;
|
||||
spawnp_attr.__fn = (void *)execvpe;
|
||||
return posix_spawn(pid, file, file_actions, &spawnp_attr, argv, envp);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
|
||||
#include <strings.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/strings.hpp>
|
||||
|
||||
char *index (const char *s, int c) {
|
||||
return strchr(s, c);
|
||||
}
|
||||
|
||||
char *rindex(const char *s, int c) {
|
||||
return strrchr(s, c);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
template<typename T>
|
||||
int ffs_generic(T i) {
|
||||
//Non-portably assume a byte has 8 bits; fine in all plausible cases.
|
||||
for(size_t b = 0; b < sizeof(T) * 8;)
|
||||
if(i & (static_cast<T>(0x1) << b++))
|
||||
return b;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// On RISC-V, __builtin_ffs just calls into ffs, so we can't use it here.
|
||||
#if defined(__has_builtin) && !defined(__riscv)
|
||||
# if __has_builtin(__builtin_ffs)
|
||||
# define __mlibc_ffs __builtin_ffs
|
||||
# endif
|
||||
# if __has_builtin(__builtin_ffsl)
|
||||
# define __mlibc_ffsl __builtin_ffsl
|
||||
# endif
|
||||
# if __has_builtin(__builtin_ffsll)
|
||||
# define __mlibc_ffsll __builtin_ffsll
|
||||
# endif
|
||||
#endif
|
||||
|
||||
int ffs(int i) {
|
||||
#ifdef __mlibc_ffs
|
||||
return __mlibc_ffs(i);
|
||||
#else
|
||||
return ffs_generic<int>(i);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
Both ffsl() and ffsll() are glibc extensions
|
||||
defined in string.h. They are however implemented
|
||||
here because of similarity in logic and
|
||||
shared code.
|
||||
*/
|
||||
|
||||
int ffsl(long i) {
|
||||
#ifdef __mlibc_ffsl
|
||||
return __mlibc_ffsl(i);
|
||||
#else
|
||||
return ffs_generic<long>(i);
|
||||
#endif
|
||||
}
|
||||
|
||||
int ffsll(long long i) {
|
||||
#ifdef __mlibc_ffsll
|
||||
return __mlibc_ffsll(i);
|
||||
#else
|
||||
return ffs_generic<long long>(i);
|
||||
#endif
|
||||
}
|
||||
|
||||
int strcasecmp(const char *a, const char *b) {
|
||||
size_t i = 0;
|
||||
while(true) {
|
||||
unsigned char a_byte = tolower(a[i]);
|
||||
unsigned char b_byte = tolower(b[i]);
|
||||
if(!a_byte && !b_byte)
|
||||
return 0;
|
||||
// If only one char is null, one of the following cases applies.
|
||||
if(a_byte < b_byte)
|
||||
return -1;
|
||||
if(a_byte > b_byte)
|
||||
return 1;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
int strncasecmp(const char *a, const char *b, size_t size) {
|
||||
return mlibc::strncasecmp(a, b, size);
|
||||
}
|
||||
|
||||
// Marked as obsolete in posix 2008 but used by at least tracker
|
||||
int bcmp(const void *s1, const void *s2, size_t n) {
|
||||
return memcmp(s1, s2, n);
|
||||
}
|
||||
|
||||
void bcopy(const void *s1, void *s2, size_t n) {
|
||||
memmove(s2, s1, n);
|
||||
}
|
||||
|
||||
void bzero(void *s, size_t n) {
|
||||
memset(s, 0, n);
|
||||
}
|
||||
|
||||
void explicit_bzero(void *s, size_t len) {
|
||||
memset (s, 0, len);
|
||||
// Compiler barrier to prevent optimizing away the memset
|
||||
asm volatile ("" ::: "memory");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
|
||||
#include <sys/file.h>
|
||||
#include <mlibc/posix-sysdeps.hpp>
|
||||
#include <errno.h>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
|
||||
int flock(int fd, int opt) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_flock, -1);
|
||||
if(int e = mlibc::sys_flock(fd, opt); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
[[gnu::alias("flock")]] int flock64(int fd, int opt);
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <sys/ipc.h>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
|
||||
key_t ftok(const char *, int) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <bits/ensure.h>
|
||||
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/posix-sysdeps.hpp>
|
||||
|
||||
int mprotect(void *pointer, size_t size, int prot) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_vm_protect, -1);
|
||||
if(int e = mlibc::sys_vm_protect(pointer, size, prot); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mlock(const void *addr, size_t len) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_mlock, -1);
|
||||
if(int e = mlibc::sys_mlock(addr, len); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mlockall(int flags) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_mlockall, -1);
|
||||
if(int e = mlibc::sys_mlockall(flags); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int munlock(const void *addr, size_t len) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_munlock, -1);
|
||||
if(int e = mlibc::sys_munlock(addr, len); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int munlockall(void) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_munlockall, -1);
|
||||
if(int e = mlibc::sys_munlockall(); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int posix_madvise(void *addr, size_t length, int advice) {
|
||||
if(!mlibc::sys_posix_madvise) {
|
||||
MLIBC_MISSING_SYSDEP();
|
||||
return ENOSYS;
|
||||
}
|
||||
return mlibc::sys_posix_madvise(addr, length, advice);
|
||||
}
|
||||
|
||||
int msync(void *addr, size_t length, int flags) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_msync, -1);
|
||||
if(int e = mlibc::sys_msync(addr, length, flags); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *mmap(void *hint, size_t size, int prot, int flags, int fd, off_t offset) {
|
||||
void *window;
|
||||
if(int e = mlibc::sys_vm_map(hint, size, prot, flags, fd, offset, &window); e) {
|
||||
errno = e;
|
||||
return (void *)-1;
|
||||
}
|
||||
return window;
|
||||
}
|
||||
|
||||
[[gnu::alias("mmap")]] void *mmap64(void *hint, size_t size, int prot, int flags, int fd, off64_t offset);
|
||||
|
||||
int munmap(void *pointer, size_t size) {
|
||||
if(int e = mlibc::sys_vm_unmap(pointer, size); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The implementation of shm_open and shm_unlink is taken from musl.
|
||||
namespace {
|
||||
char *shm_mapname(const char *name, char *buf) {
|
||||
char *p;
|
||||
while(*name == '/')
|
||||
name++;
|
||||
if(*(p = strchrnul(name, '/')) || p == name ||
|
||||
(p - name <= 2 && name[0] == '.' && p[-1] == '.')) {
|
||||
errno = EINVAL;
|
||||
return nullptr;
|
||||
}
|
||||
if(p - name > NAME_MAX) {
|
||||
errno = ENAMETOOLONG;
|
||||
return nullptr;
|
||||
}
|
||||
memcpy(buf, "/dev/shm/", 9);
|
||||
memcpy(buf + 9, name, p - name + 1);
|
||||
return buf;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int shm_open(const char *name, int flags, mode_t mode) {
|
||||
int cs;
|
||||
char buf[NAME_MAX + 10];
|
||||
if(!(name = shm_mapname(name, buf)))
|
||||
return -1;
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
|
||||
int fd = open(name, flags | O_NOFOLLOW | O_CLOEXEC | O_NONBLOCK, mode);
|
||||
pthread_setcancelstate(cs, nullptr);
|
||||
return fd;
|
||||
}
|
||||
|
||||
int shm_unlink(const char *name) {
|
||||
char buf[NAME_MAX + 10];
|
||||
if(!(name = shm_mapname(name, buf)))
|
||||
return -1;
|
||||
return unlink(name);
|
||||
}
|
||||
|
||||
#if __MLIBC_LINUX_OPTION
|
||||
void *mremap(void *pointer, size_t size, size_t new_size, int flags, ...) {
|
||||
__ensure(flags == MREMAP_MAYMOVE);
|
||||
|
||||
void *window;
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_vm_remap, (void *)-1);
|
||||
if(int e = mlibc::sys_vm_remap(pointer, size, new_size, &window); e) {
|
||||
errno = e;
|
||||
return (void *)-1;
|
||||
}
|
||||
return window;
|
||||
}
|
||||
|
||||
int remap_file_pages(void *, size_t, int, size_t, int) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
int memfd_create(const char *name, unsigned int flags) {
|
||||
int ret = -1;
|
||||
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_memfd_create, -1);
|
||||
if(int e = mlibc::sys_memfd_create(name, flags, &ret)) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int madvise(void *addr, size_t length, int advice) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_madvise, -1);
|
||||
if(int e = mlibc::sys_madvise(addr, length, advice)) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mincore(void *addr, size_t length, unsigned char *vec) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_munlockall, -1);
|
||||
if(int e = mlibc::sys_mincore(addr, length, vec); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* __MLIBC_LINUX_OPTION */
|
||||
@@ -0,0 +1,23 @@
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <sys/msg.h>
|
||||
|
||||
int msgget(key_t, int) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
int msgctl(int, int, struct msqid_ds *) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
ssize_t msgrcv(int, void *, size_t, long, int) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
int msgsnd(int, const void *, size_t, int) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/posix-sysdeps.hpp>
|
||||
|
||||
int getpriority(int which, id_t who) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getpriority, -1);
|
||||
int value = 0;
|
||||
if(int e = mlibc::sys_getpriority(which, who, &value); e) {
|
||||
errno = e;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
int setpriority(int which, id_t who, int prio) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setpriority, -1);
|
||||
if(int e = mlibc::sys_setpriority(which, who, prio); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getrusage(int scope, struct rusage *usage) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getrusage, -1);
|
||||
if(int e = mlibc::sys_getrusage(scope, usage); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getrlimit(int resource, struct rlimit *limit) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getrlimit, -1);
|
||||
if(int e = mlibc::sys_getrlimit(resource, limit); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
[[gnu::alias("getrlimit")]] int getrlimit64(int resource, struct rlimit *limit);
|
||||
|
||||
int setrlimit(int resource, const struct rlimit *limit) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setrlimit, -1);
|
||||
if(int e = mlibc::sys_setrlimit(resource, limit); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
[[gnu::alias("setrlimit")]] int setrlimit64(int resource, const struct rlimit *limit);
|
||||
|
||||
int prlimit(pid_t, int, const struct rlimit *, struct rlimit *) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/select.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc-config.h>
|
||||
|
||||
#include <mlibc/posix-sysdeps.hpp>
|
||||
|
||||
void __FD_CLR(int fd, fd_set *set) {
|
||||
__ensure(fd < FD_SETSIZE);
|
||||
set->fds_bits[fd / 8] &= ~(1 << (fd % 8));
|
||||
}
|
||||
int __FD_ISSET(int fd, fd_set *set) {
|
||||
__ensure(fd < FD_SETSIZE);
|
||||
return set->fds_bits[fd / 8] & (1 << (fd % 8));
|
||||
}
|
||||
void __FD_SET(int fd, fd_set *set) {
|
||||
__ensure(fd < FD_SETSIZE);
|
||||
set->fds_bits[fd / 8] |= 1 << (fd % 8);
|
||||
}
|
||||
void __FD_ZERO(fd_set *set) {
|
||||
memset(set->fds_bits, 0, sizeof(fd_set));
|
||||
}
|
||||
|
||||
int select(int num_fds, fd_set *__restrict read_set, fd_set *__restrict write_set,
|
||||
fd_set *__restrict except_set, struct timeval *__restrict timeout) {
|
||||
int num_events = 0;
|
||||
struct timespec timeouts = {};
|
||||
struct timespec *timeout_ptr = nullptr;
|
||||
if (timeout) {
|
||||
timeouts.tv_sec = timeout->tv_sec;
|
||||
timeouts.tv_nsec = timeout->tv_usec * 1000;
|
||||
timeout_ptr = &timeouts;
|
||||
}
|
||||
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_pselect, -1);
|
||||
if(int e = mlibc::sys_pselect(num_fds, read_set, write_set, except_set,
|
||||
timeout_ptr, nullptr, &num_events); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return num_events;
|
||||
}
|
||||
|
||||
int pselect(int num_fds, fd_set *__restrict read_set, fd_set *__restrict write_set,
|
||||
fd_set *__restrict except_set, const struct timespec *timeout, const sigset_t *sigmask) {
|
||||
int num_events = 0;
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_pselect, -1);
|
||||
if(int e = mlibc::sys_pselect(num_fds, read_set, write_set, except_set,
|
||||
timeout, sigmask, &num_events); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return num_events;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <sys/sem.h>
|
||||
|
||||
#include <mlibc/posix-sysdeps.hpp>
|
||||
|
||||
int semget(key_t key, int n, int fl) {
|
||||
if(n > USHRT_MAX) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int id = 0;
|
||||
auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_semget, -1);
|
||||
if(int e = sysdep(key, n, fl, &id); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
int semop(int, struct sembuf *, size_t) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
union semun {
|
||||
int val;
|
||||
struct semid_ds *buf;
|
||||
unsigned short *array;
|
||||
};
|
||||
|
||||
int semctl(int id, int num, int cmd, ...) {
|
||||
union semun semun;
|
||||
int ret = 0;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, cmd);
|
||||
semun = va_arg(ap, union semun);
|
||||
va_end(ap);
|
||||
|
||||
auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_semctl, -1);
|
||||
if(int e = sysdep(id, num, cmd, semun.buf, &ret); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
#include <sys/shm.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/posix-sysdeps.hpp>
|
||||
|
||||
void *shmat(int shmid, const void *shmaddr, int shmflg) {
|
||||
void *ret;
|
||||
auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_shmat, ((void *)-1));
|
||||
if(int e = sysdep(&ret, shmid, shmaddr, shmflg); e) {
|
||||
errno = e;
|
||||
return ((void *)-1);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int shmctl(int shmid, int cmd, struct shmid_ds *buf) {
|
||||
int ret;
|
||||
auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_shmctl, -1);
|
||||
if(int e = sysdep(&ret, shmid, cmd, buf); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int shmdt(const void *shmaddr) {
|
||||
auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_shmdt, -1);
|
||||
if(int e = sysdep(shmaddr); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int shmget(key_t key, size_t size, int shmflg) {
|
||||
int ret;
|
||||
auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_shmget, -1);
|
||||
if(int e = sysdep(&ret, key, size, shmflg); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/posix-sysdeps.hpp>
|
||||
|
||||
int accept(int fd, struct sockaddr *__restrict addr_ptr, socklen_t *__restrict addr_length) {
|
||||
int newfd;
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_accept, -1);
|
||||
if(int e = mlibc::sys_accept(fd, &newfd, addr_ptr, addr_length, 0); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return newfd;
|
||||
}
|
||||
|
||||
int accept4(int fd, struct sockaddr *__restrict addr_ptr, socklen_t *__restrict addr_length, int flags) {
|
||||
int newfd;
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_accept, -1);
|
||||
if(int e = mlibc::sys_accept(fd, &newfd, addr_ptr, addr_length, flags); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return newfd;
|
||||
}
|
||||
|
||||
int bind(int fd, const struct sockaddr *addr_ptr, socklen_t addr_len) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_bind, -1);
|
||||
if(int e = mlibc::sys_bind(fd, addr_ptr, addr_len); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int connect(int fd, const struct sockaddr *addr_ptr, socklen_t addr_len) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_connect, -1);
|
||||
if(int e = mlibc::sys_connect(fd, addr_ptr, addr_len); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getpeername(int fd, struct sockaddr *addr_ptr, socklen_t *__restrict addr_length) {
|
||||
socklen_t actual_length;
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_peername, -1);
|
||||
if(int e = mlibc::sys_peername(fd, addr_ptr, *addr_length, &actual_length); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
*addr_length = actual_length;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getsockname(int fd, struct sockaddr *__restrict addr_ptr, socklen_t *__restrict addr_length) {
|
||||
socklen_t actual_length;
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_sockname, -1);
|
||||
if(int e = mlibc::sys_sockname(fd, addr_ptr, *addr_length, &actual_length); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
*addr_length = actual_length;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getsockopt(int fd, int layer, int number,
|
||||
void *__restrict buffer, socklen_t *__restrict size) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getsockopt, -1);
|
||||
return mlibc::sys_getsockopt(fd, layer, number, buffer, size);
|
||||
}
|
||||
|
||||
int listen(int fd, int backlog) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_listen, -1);
|
||||
if(int e = mlibc::sys_listen(fd, backlog); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t recv(int sockfd, void *__restrict buf, size_t len, int flags) {
|
||||
return recvfrom(sockfd, buf, len, flags, nullptr, nullptr);
|
||||
}
|
||||
|
||||
ssize_t recvfrom(int sockfd, void *__restrict buf, size_t len, int flags,
|
||||
struct sockaddr *__restrict src_addr, socklen_t *__restrict addrlen) {
|
||||
if(mlibc::sys_recvfrom) {
|
||||
ssize_t length;
|
||||
if(int e = mlibc::sys_recvfrom(sockfd, buf, len, flags, src_addr, addrlen, &length); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
struct iovec iov = {};
|
||||
iov.iov_base = buf;
|
||||
iov.iov_len = len;
|
||||
|
||||
struct msghdr hdr = {};
|
||||
hdr.msg_name = src_addr;
|
||||
if (addrlen) {
|
||||
hdr.msg_namelen = *addrlen;
|
||||
}
|
||||
hdr.msg_iov = &iov;
|
||||
hdr.msg_iovlen = 1;
|
||||
|
||||
int ret = recvmsg(sockfd, &hdr, flags);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if(addrlen)
|
||||
*addrlen = hdr.msg_namelen;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t recvmsg(int fd, struct msghdr *hdr, int flags) {
|
||||
ssize_t length;
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_msg_recv, -1);
|
||||
if(int e = mlibc::sys_msg_recv(fd, hdr, flags, &length); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
int recvmmsg(int, struct mmsghdr *, unsigned int, int, struct timespec *) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
ssize_t send(int fd, const void *buffer, size_t size, int flags) {
|
||||
return sendto(fd, buffer, size, flags, nullptr, 0);
|
||||
}
|
||||
|
||||
ssize_t sendto(int fd, const void *buffer, size_t size, int flags,
|
||||
const struct sockaddr *sock_addr, socklen_t addr_length) {
|
||||
if(mlibc::sys_sendto) {
|
||||
ssize_t length;
|
||||
if(int e = mlibc::sys_sendto(fd, buffer, size, flags, sock_addr, addr_length, &length); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
struct iovec iov = {};
|
||||
iov.iov_base = const_cast<void *>(buffer);
|
||||
iov.iov_len = size;
|
||||
|
||||
struct msghdr hdr = {};
|
||||
hdr.msg_name = const_cast<struct sockaddr *>(sock_addr);
|
||||
hdr.msg_namelen = addr_length;
|
||||
hdr.msg_iov = &iov;
|
||||
hdr.msg_iovlen = 1;
|
||||
|
||||
return sendmsg(fd, &hdr, flags);
|
||||
}
|
||||
|
||||
ssize_t sendmsg(int fd, const struct msghdr *hdr, int flags) {
|
||||
if(hdr->msg_iovlen > IOV_MAX)
|
||||
return EMSGSIZE;
|
||||
|
||||
ssize_t length;
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_msg_send, -1);
|
||||
if(int e = mlibc::sys_msg_send(fd, hdr, flags, &length); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
int sendmmsg(int, struct mmsghdr *, unsigned int, int) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
int setsockopt(int fd, int layer, int number,
|
||||
const void *buffer, socklen_t size) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setsockopt, -1);
|
||||
return mlibc::sys_setsockopt(fd, layer, number, buffer, size);
|
||||
}
|
||||
|
||||
int shutdown(int sockfd, int how) {
|
||||
auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_shutdown, -1);
|
||||
if(int e = sysdep(sockfd, how); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sockatmark(int) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
int socket(int family, int type, int protocol) {
|
||||
int fd;
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_socket, -1);
|
||||
if(int e = mlibc::sys_socket(family, type, protocol, &fd); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
int socketpair(int domain, int type, int protocol, int sv[2]) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_socketpair, -1);
|
||||
if(int e = mlibc::sys_socketpair(domain, type, protocol, sv); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// connectpair() is provided by the platform
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <bits/ensure.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/posix-sysdeps.hpp>
|
||||
|
||||
int chmod(const char *pathname, mode_t mode) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_chmod, -1);
|
||||
if(int e = mlibc::sys_chmod(pathname, mode); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fchmod(int fd, mode_t mode) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fchmod, -1);
|
||||
if(int e = mlibc::sys_fchmod(fd, mode); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fchmodat, -1);
|
||||
if(int e = mlibc::sys_fchmodat(dirfd, pathname, mode, flags); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fstatat(int dirfd, const char *path, struct stat *result, int flags) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_stat, -1);
|
||||
if(int e = mlibc::sys_stat(mlibc::fsfd_target::fd_path, dirfd, path, flags, result); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int futimens(int fd, const struct timespec times[2]) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_utimensat, -1);
|
||||
|
||||
if (int e = mlibc::sys_utimensat(fd, nullptr, times, 0); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mkdir(const char *path, mode_t mode) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_mkdir, -1);
|
||||
if(int e = mlibc::sys_mkdir(path, mode); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mkdirat(int dirfd, const char *path, mode_t mode) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_mkdirat, -1);
|
||||
if(int e = mlibc::sys_mkdirat(dirfd, path, mode); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mkfifo(const char *path, mode_t mode) {
|
||||
return mkfifoat(AT_FDCWD, path, mode);
|
||||
}
|
||||
|
||||
int mkfifoat(int dirfd, const char *path, mode_t mode) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_mkfifoat, -1);
|
||||
if (int e = mlibc::sys_mkfifoat(dirfd, path, mode); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mknod(const char *path, mode_t mode, dev_t dev) {
|
||||
return mknodat(AT_FDCWD, path, mode, dev);
|
||||
}
|
||||
|
||||
int mknodat(int dirfd, const char *path, mode_t mode, dev_t dev) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_mknodat, -1);
|
||||
if (int e = mlibc::sys_mknodat(dirfd, path, mode, dev); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
mode_t umask(mode_t mode) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_umask, -1);
|
||||
mode_t old;
|
||||
if (int e = mlibc::sys_umask(mode, &old); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return old;
|
||||
}
|
||||
|
||||
int utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags) {
|
||||
if(pathname == nullptr) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_utimensat, -1);
|
||||
if (int e = mlibc::sys_utimensat(dirfd, pathname, times, flags); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stat(const char *path, struct stat *result) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_stat, -1);
|
||||
if(int e = mlibc::sys_stat(mlibc::fsfd_target::path, -1, path, 0, result); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lstat(const char *path, struct stat *result) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_stat, -1);
|
||||
if(int e = mlibc::sys_stat(mlibc::fsfd_target::path,
|
||||
-1, path, AT_SYMLINK_NOFOLLOW, result); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
[[gnu::alias("lstat")]] int lstat64(const char *path, struct stat64 *result);
|
||||
|
||||
int fstat(int fd, struct stat *result) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_stat, -1);
|
||||
if(int e = mlibc::sys_stat(mlibc::fsfd_target::fd, fd, "", 0, result); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
[[gnu::alias("fstat")]] int fstat64(int fd, struct stat64 *result);
|
||||
@@ -0,0 +1,28 @@
|
||||
#include <errno.h>
|
||||
#include <sys/statvfs.h>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/posix-sysdeps.hpp>
|
||||
|
||||
int statvfs(const char *path, struct statvfs *out) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_statvfs, -1);
|
||||
if(int e = mlibc::sys_statvfs(path, out); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
[[gnu::alias("statvfs")]] int statvfs64(const char *path, struct statvfs64 *out);
|
||||
|
||||
int fstatvfs(int fd, struct statvfs *out) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fstatvfs, -1);
|
||||
if(int e = mlibc::sys_fstatvfs(fd, out); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
[[gnu::alias("fstatvfs")]] int fstatvfs64(int, struct statvfs64 *);
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/posix-sysdeps.hpp>
|
||||
|
||||
int gettimeofday(struct timeval *__restrict result, void *__restrict unused) {
|
||||
(void)unused; // Linux just ignores gettimeofday().
|
||||
|
||||
if(result) {
|
||||
long nanos;
|
||||
if(int e = mlibc::sys_clock_get(CLOCK_REALTIME, &result->tv_sec, &nanos); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
result->tv_usec = nanos / 1000;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int settimeofday(const struct timeval *tv, const struct timezone *) {
|
||||
if(!tv)
|
||||
return 0;
|
||||
// tv_usec must be in the range 0, 999999
|
||||
if(tv->tv_usec >= 1000000) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if(int e = mlibc::sys_clock_set(CLOCK_REALTIME, tv->tv_sec, tv->tv_usec * 1000); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void timeradd(const struct timeval *a, const struct timeval *b, struct timeval *res) {
|
||||
res->tv_sec = a->tv_sec + b->tv_sec;
|
||||
res->tv_usec = a->tv_usec + b->tv_usec;
|
||||
while(res->tv_usec > 999999) {
|
||||
res->tv_usec -= 1000000;
|
||||
res->tv_sec += 1;
|
||||
}
|
||||
}
|
||||
|
||||
void timersub(const struct timeval *a, const struct timeval *b, struct timeval *res) {
|
||||
res->tv_sec = a->tv_sec - b->tv_sec;
|
||||
res->tv_usec = a->tv_usec - b->tv_usec;
|
||||
while(res->tv_usec < 0) {
|
||||
res->tv_usec += 1000000;
|
||||
res->tv_sec -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
void timerclear(struct timeval *tvp) {
|
||||
tvp->tv_sec = 0;
|
||||
tvp->tv_usec = 0;
|
||||
}
|
||||
|
||||
int timerisset(struct timeval *tvp) {
|
||||
if(tvp->tv_sec != 0 || tvp->tv_usec != 0) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getitimer(int which, struct itimerval *curr_value) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getitimer, -1);
|
||||
if(int e = mlibc::sys_getitimer(which, curr_value); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setitimer, -1);
|
||||
if(int e = mlibc::sys_setitimer(which, new_value, old_value); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int timer_create(clockid_t clk, struct sigevent *__restrict evp, timer_t *__restrict res) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_timer_create, -1);
|
||||
if(int e = mlibc::sys_timer_create(clk, evp, res); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int timer_settime(timer_t t, int flags, const struct itimerspec *__restrict val, struct itimerspec *__restrict old) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_timer_settime, -1);
|
||||
if(int e = mlibc::sys_timer_settime(t, flags, val, old); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int timer_gettime(timer_t t, struct itimerspec *val) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_timer_gettime, -1);
|
||||
if(int e = mlibc::sys_timer_gettime(t, val); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int timer_delete(timer_t t) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_timer_delete, -1);
|
||||
if(int e = mlibc::sys_timer_delete(t); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/times.h>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <internal-config.h>
|
||||
#include <mlibc/posix-sysdeps.hpp>
|
||||
|
||||
clock_t times(struct tms *tms) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_times, -1);
|
||||
clock_t ret;
|
||||
if(int e = mlibc::sys_times(tms, &ret); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <frg/vector.hpp>
|
||||
#include <mlibc/allocator.hpp>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/posix-sysdeps.hpp>
|
||||
#include <bits/ensure.h>
|
||||
|
||||
ssize_t readv(int fd, const struct iovec *iovs, int iovc) {
|
||||
ssize_t read_bytes = 0;
|
||||
|
||||
auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_readv, -1);
|
||||
|
||||
if (int e = sysdep(fd, iovs, iovc, &read_bytes); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return read_bytes;
|
||||
}
|
||||
|
||||
ssize_t writev(int fd, const struct iovec *iovs, int iovc) {
|
||||
__ensure(iovc);
|
||||
|
||||
ssize_t written = 0;
|
||||
|
||||
auto sysdep = mlibc::sys_writev;
|
||||
if(sysdep) {
|
||||
int e = sysdep(fd, iovs, iovc, &written);
|
||||
if(e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
// TODO: this implementation is not safe to use in signal contexts
|
||||
mlibc::infoLogger() << "mlibc: falling back to signal-unsafe writev implementation!" << frg::endlog;
|
||||
size_t bytes = 0;
|
||||
for(int i = 0; i < iovc; i++) {
|
||||
if(SSIZE_MAX - bytes < iovs[i].iov_len) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
bytes += iovs[i].iov_len;
|
||||
}
|
||||
frg::vector<char, MemoryAllocator> buffer{getAllocator()};
|
||||
buffer.resize(bytes);
|
||||
|
||||
size_t to_copy = bytes;
|
||||
char *bp = buffer.data();
|
||||
for(int i = 0; i < iovc; i++) {
|
||||
size_t copy = frg::min(iovs[i].iov_len, to_copy);
|
||||
|
||||
bp = (char *)mempcpy((void *)bp, (void *)iovs[i].iov_base, copy);
|
||||
|
||||
to_copy -= copy;
|
||||
if(to_copy == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
written = write(fd, buffer.data(), bytes);
|
||||
return written;
|
||||
}
|
||||
|
||||
ssize_t preadv(int, const struct iovec *, int, off_t) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
ssize_t pwritev(int, const struct iovec *, int, off_t) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <internal-config.h>
|
||||
#include <mlibc/posix-sysdeps.hpp>
|
||||
|
||||
int uname(struct utsname *p) {
|
||||
if (p == nullptr) {
|
||||
errno = EFAULT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_uname, -1);
|
||||
if(int e = mlibc::sys_uname(p); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
#include <bits/ensure.h>
|
||||
|
||||
#include <mlibc/ansi-sysdeps.hpp>
|
||||
#include <mlibc/posix-sysdeps.hpp>
|
||||
#include <mlibc/debug.hpp>
|
||||
|
||||
int waitid(idtype_t idtype, id_t id, siginfo_t *info, int options) {
|
||||
auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_waitid, -1);
|
||||
if(int e = sysdep(idtype, id, info, options); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
pid_t waitpid(pid_t pid, int *status, int flags) {
|
||||
pid_t ret;
|
||||
int tmp_status = 0;
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_waitpid, -1);
|
||||
if(int e = mlibc::sys_waitpid(pid, &tmp_status, flags, nullptr, &ret); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
if(status) {
|
||||
*status = tmp_status;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
pid_t wait(int *status) {
|
||||
return waitpid(-1, status, 0);
|
||||
}
|
||||
|
||||
pid_t wait3(int *status, int options, struct rusage *rusage) {
|
||||
(void) rusage;
|
||||
mlibc::infoLogger() << "\e[31mmlibc: wait3() is not implemented correctly\e[39m"
|
||||
<< frg::endlog;
|
||||
return waitpid(-1, status, options);
|
||||
}
|
||||
|
||||
pid_t wait4(pid_t pid, int *status, int options, struct rusage *ru) {
|
||||
pid_t ret;
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_waitpid, -1);
|
||||
if(int e = mlibc::sys_waitpid(pid, status, options, ru, &ret); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
|
||||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <bits/ensure.h>
|
||||
|
||||
#include <frg/mutex.hpp>
|
||||
#include <mlibc/lock.hpp>
|
||||
#include <mlibc/debug.hpp>
|
||||
|
||||
// This syslog implementation is largely taken from musl
|
||||
|
||||
static char log_ident[32];
|
||||
static int log_options;
|
||||
static int log_facility = LOG_USER;
|
||||
static int log_fd = -1;
|
||||
static int log_opt;
|
||||
static int log_mask = 0xff;
|
||||
|
||||
static int use_mlibc_logger = 0;
|
||||
static FutexLock __syslog_lock;
|
||||
|
||||
static const struct sockaddr_un log_addr {AF_UNIX, "/dev/log"};
|
||||
|
||||
void closelog(void) {
|
||||
frg::unique_lock<FutexLock> holder { __syslog_lock };
|
||||
close(log_fd);
|
||||
log_fd = -1;
|
||||
}
|
||||
|
||||
static void __openlog() {
|
||||
log_fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
|
||||
if(log_fd >= 0) {
|
||||
int ret = connect(log_fd, (const sockaddr *)&log_addr, sizeof log_addr);
|
||||
if(ret) {
|
||||
mlibc::infoLogger() << "\e[31mmlibc: syslog: connect returned an error, falling back to infoLogger\e[39m" << frg::endlog;
|
||||
use_mlibc_logger = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void openlog(const char *ident, int options, int facility) {
|
||||
frg::unique_lock<FutexLock> holder { __syslog_lock };
|
||||
if(ident) {
|
||||
size_t n = strnlen(ident, sizeof log_ident - 1);
|
||||
memcpy(log_ident, ident, n);
|
||||
log_ident[n] = 0;
|
||||
} else {
|
||||
log_ident[0] = 0;
|
||||
}
|
||||
log_options = options;
|
||||
log_facility = facility;
|
||||
|
||||
if((options & LOG_NDELAY) && log_fd < 0)
|
||||
__openlog();
|
||||
}
|
||||
|
||||
int setlogmask(int mask) {
|
||||
int old_mask = log_mask;
|
||||
|
||||
log_mask = mask;
|
||||
|
||||
return old_mask;
|
||||
}
|
||||
|
||||
static void _vsyslog(int priority, const char *message, va_list ap) {
|
||||
auto is_lost_conn = [] (int e) {
|
||||
return e == ECONNREFUSED || e == ECONNRESET || e == ENOTCONN || e == EPIPE;
|
||||
};
|
||||
|
||||
if(!(priority & log_mask)) {
|
||||
return;
|
||||
}
|
||||
|
||||
char timebuf[16];
|
||||
time_t now;
|
||||
struct tm tm;
|
||||
char buf[1024];
|
||||
int errno_save = errno;
|
||||
int pid;
|
||||
int l, l2;
|
||||
int hlen;
|
||||
int fd;
|
||||
|
||||
if(log_fd < 0)
|
||||
__openlog();
|
||||
|
||||
if(use_mlibc_logger) {
|
||||
vsnprintf(buf, sizeof buf, message, ap);
|
||||
mlibc::infoLogger() << "mlibc: syslog: " << buf << frg::endlog;
|
||||
return;
|
||||
}
|
||||
|
||||
if(!(priority & LOG_FACMASK))
|
||||
priority |= log_facility;
|
||||
|
||||
now = time(nullptr);
|
||||
gmtime_r(&now, &tm);
|
||||
strftime(timebuf, sizeof timebuf, "%b %e %T", &tm);
|
||||
|
||||
pid = (log_opt & LOG_PID) ? getpid() : 0;
|
||||
l = snprintf(buf, sizeof buf, "<%d>%s %n%s%s%.0d%s: ",
|
||||
priority, timebuf, &hlen, log_ident, (pid ? "[" : ""), pid, (pid ? "]" : ""));
|
||||
errno = errno_save;
|
||||
l2 = vsnprintf(buf + l, sizeof buf - l, message, ap);
|
||||
if(l2 >= 0) {
|
||||
if(l2 >= (long int)(sizeof buf - l))
|
||||
l = sizeof buf - 1;
|
||||
else
|
||||
l += l2;
|
||||
if(buf[l - 1] != '\n')
|
||||
buf[l++] = '\n';
|
||||
if(send(log_fd, buf, l, 0) < 0 && (!is_lost_conn(errno)
|
||||
|| connect(log_fd, (const sockaddr *)&log_addr, sizeof log_addr) < 0
|
||||
|| send(log_fd, buf, l, 0) < 0)
|
||||
&& (log_opt & LOG_CONS)) {
|
||||
fd = open("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
|
||||
if(fd >= 0) {
|
||||
dprintf(fd, "%.*s", l - hlen, buf + hlen);
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
if(log_opt & LOG_PERROR)
|
||||
dprintf(STDERR_FILENO, "%.*s", l - hlen, buf + hlen);
|
||||
}
|
||||
}
|
||||
|
||||
void syslog(int priority, const char *format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vsyslog(priority, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void vsyslog(int priority, const char *message, va_list ap) {
|
||||
if (!(log_mask & LOG_MASK(priority & 7)) || (priority & ~0x3ff))
|
||||
return;
|
||||
|
||||
int cs;
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
|
||||
frg::unique_lock<FutexLock> lock(__syslog_lock);
|
||||
_vsyslog(priority, message, ap);
|
||||
pthread_setcancelstate(cs, nullptr);
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <termios.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/posix-sysdeps.hpp>
|
||||
|
||||
speed_t cfgetispeed(const struct termios *tios) {
|
||||
return tios->c_cflag & CBAUD;
|
||||
}
|
||||
|
||||
speed_t cfgetospeed(const struct termios *tios) {
|
||||
return tios->c_cflag & CBAUD;
|
||||
}
|
||||
|
||||
int cfsetispeed(struct termios *termios, speed_t speed) {
|
||||
return speed ? cfsetospeed(termios, speed) : 0;
|
||||
}
|
||||
|
||||
int cfsetospeed(struct termios *termios, speed_t speed) {
|
||||
if(speed & ~CBAUD) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
termios->c_cflag &= ~CBAUD;
|
||||
termios->c_cflag |= speed;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cfmakeraw(struct termios *t) {
|
||||
t->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
|
||||
t->c_oflag &= ~OPOST;
|
||||
t->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
|
||||
t->c_cflag &= ~(CSIZE | PARENB);
|
||||
t->c_cflag |= CS8;
|
||||
t->c_cc[VMIN] = 1;
|
||||
t->c_cc[VTIME] = 0;
|
||||
}
|
||||
|
||||
int tcdrain(int fd) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_tcdrain, -1);
|
||||
if(int e = mlibc::sys_tcdrain(fd); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tcflow(int fd, int action) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_tcflow, -1);
|
||||
if(int e = mlibc::sys_tcflow(fd, action); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tcflush(int fd, int queue_selector) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_tcflush, -1);
|
||||
if(int e = mlibc::sys_tcflush(fd, queue_selector); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tcgetattr(int fd, struct termios *attr) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_tcgetattr, -1);
|
||||
if(int e = mlibc::sys_tcgetattr(fd, attr); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
pid_t tcgetsid(int fd) {
|
||||
int sid;
|
||||
if(ioctl(fd, TIOCGSID, &sid) < 0) {
|
||||
return -1;
|
||||
}
|
||||
return sid;
|
||||
}
|
||||
|
||||
int tcsendbreak(int, int) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
int tcsetattr(int fd, int opts, const struct termios *attr) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_tcsetattr, -1);
|
||||
if(int e = mlibc::sys_tcsetattr(fd, opts, attr); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,510 @@
|
||||
#include <ctype.h>
|
||||
#include <langinfo.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/strings.hpp>
|
||||
|
||||
namespace {
|
||||
|
||||
int month_to_day(int month) {
|
||||
switch(month){
|
||||
case 0: return 0;
|
||||
case 1: return 31;
|
||||
case 2: return 59;
|
||||
case 3: return 90;
|
||||
case 4: return 120;
|
||||
case 5: return 151;
|
||||
case 6: return 181;
|
||||
case 7: return 212;
|
||||
case 8: return 243;
|
||||
case 9: return 273;
|
||||
case 10: return 304;
|
||||
case 11: return 334;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int is_leapyear(int year) {
|
||||
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
|
||||
}
|
||||
|
||||
int month_and_year_to_day_in_year(int month, int year){
|
||||
int day = month_to_day(month);
|
||||
if(is_leapyear(year) && month < 2)
|
||||
return day + 1;
|
||||
|
||||
return day;
|
||||
}
|
||||
|
||||
int target_determination(int month) {
|
||||
switch(month){
|
||||
case 0: return 3;
|
||||
case 1: return 14;
|
||||
case 2: return 14;
|
||||
case 3: return 4;
|
||||
case 4: return 9;
|
||||
case 5: return 6;
|
||||
case 6: return 11;
|
||||
case 7: return 8;
|
||||
case 8: return 5;
|
||||
case 9: return 10;
|
||||
case 10: return 7;
|
||||
case 11: return 12;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int doom_determination(int full_year) {
|
||||
int century = full_year / 100;
|
||||
int anchor = 2 + 5 * (century % 4) % 7;
|
||||
|
||||
int year = full_year % 100;
|
||||
|
||||
if(year % 2)
|
||||
year += 11;
|
||||
|
||||
year /= 2;
|
||||
|
||||
if(year % 2)
|
||||
year += 11;
|
||||
|
||||
return 7 - (year % 7) + anchor;
|
||||
}
|
||||
|
||||
//Determine day of week through the doomsday algorithm.
|
||||
int day_determination(int day, int month, int year) {
|
||||
int doom = doom_determination(year);
|
||||
bool leap = is_leapyear(year);
|
||||
|
||||
int target = target_determination(month);
|
||||
if(leap && month < 2)
|
||||
target++;
|
||||
|
||||
int doom_dif = (day - target) % 7;
|
||||
return (doom + doom_dif) % 7;
|
||||
}
|
||||
|
||||
struct strptime_internal_state {
|
||||
bool has_century;
|
||||
bool has_year;
|
||||
bool has_month;
|
||||
bool has_day_of_month;
|
||||
bool has_day_of_year;
|
||||
bool has_day_of_week;
|
||||
|
||||
bool full_year_given;
|
||||
|
||||
int century;
|
||||
|
||||
size_t format_index;
|
||||
size_t input_index;
|
||||
};
|
||||
|
||||
char *strptime_internal(const char *__restrict input, const char *__restrict format,
|
||||
struct tm *__restrict tm, struct strptime_internal_state *__restrict state) {
|
||||
auto matchLanginfoItem = [&] (int start, size_t num, int &dest, bool &flag) -> bool {
|
||||
for(size_t i = start; i < (start + num); i++) {
|
||||
const char *mon = nl_langinfo(i);
|
||||
size_t len = strlen(mon);
|
||||
if(mlibc::strncasecmp(&input[state->input_index], mon, len))
|
||||
continue;
|
||||
state->input_index += len;
|
||||
dest = i - start;
|
||||
flag = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
auto matchNumericRange = [&] (int start, int end, int &dest, bool *flag) -> bool {
|
||||
int product = 0, n = 0;
|
||||
sscanf(&input[state->input_index], "%d%n", &product, &n);
|
||||
if(n == 0 || 2 < n)
|
||||
return false;
|
||||
if(product < start || product > end)
|
||||
return false;
|
||||
state->input_index += n;
|
||||
dest = product;
|
||||
if(flag) *flag = true;
|
||||
return true;
|
||||
};
|
||||
|
||||
while(isspace(input[state->input_index]))
|
||||
state->input_index++;
|
||||
|
||||
if(input[state->input_index] == '\0')
|
||||
return nullptr;
|
||||
|
||||
while(format[state->format_index] != '\0'){
|
||||
if(format[state->format_index] != '%'){
|
||||
if(isspace(format[state->format_index])){
|
||||
while(isspace(input[state->input_index++]));
|
||||
state->input_index--;
|
||||
}
|
||||
else {
|
||||
if(format[state->format_index] != input[state->input_index++])
|
||||
return nullptr;
|
||||
}
|
||||
state->format_index++;
|
||||
continue;
|
||||
}
|
||||
state->format_index++;
|
||||
switch(format[state->format_index]){
|
||||
case '%':
|
||||
if(input[state->input_index++] != '%')
|
||||
return nullptr;
|
||||
break;
|
||||
case 'a':
|
||||
case 'A': {
|
||||
if (!matchLanginfoItem(DAY_1, 7, tm->tm_wday, state->has_day_of_week) && \
|
||||
!matchLanginfoItem(ABDAY_1, 7, tm->tm_wday, state->has_day_of_week))
|
||||
return nullptr;
|
||||
break;
|
||||
}
|
||||
case 'b':
|
||||
case 'B':
|
||||
case 'h': {
|
||||
if (!matchLanginfoItem(MON_1, 12, tm->tm_mon, state->has_month) && \
|
||||
!matchLanginfoItem(ABMON_1, 12, tm->tm_mon, state->has_month))
|
||||
return nullptr;
|
||||
break;
|
||||
}
|
||||
case 'c':
|
||||
__ensure(!"strptime() %c directive unimplemented.");
|
||||
__builtin_unreachable();
|
||||
break;
|
||||
case 'C': {
|
||||
int product = 0, n = 0;
|
||||
sscanf(&input[state->input_index], "%d%n", &product, &n);
|
||||
if(n == 0 || 2 < n)
|
||||
return nullptr;
|
||||
state->input_index += n;
|
||||
state->century = product;
|
||||
state->has_century = true;
|
||||
break;
|
||||
}
|
||||
case 'd': //`%d` and `%e` are equivalent
|
||||
case 'e': {
|
||||
if(!matchNumericRange(1, 31, tm->tm_mday, &state->has_day_of_month))
|
||||
return nullptr;
|
||||
break;
|
||||
}
|
||||
case 'D': { //equivalent to `%m/%d/%y`
|
||||
size_t pre_fi = state->format_index;
|
||||
state->format_index = 0;
|
||||
|
||||
char *result = strptime_internal(input, "%m/%d/%y", tm, state);
|
||||
if(result == nullptr)
|
||||
return nullptr;
|
||||
|
||||
state->format_index = pre_fi;
|
||||
break;
|
||||
}
|
||||
case 'H': {
|
||||
if(!matchNumericRange(0, 23, tm->tm_hour, nullptr))
|
||||
return nullptr;
|
||||
break;
|
||||
}
|
||||
case 'I': {
|
||||
if(!matchNumericRange(1, 12, tm->tm_hour, nullptr))
|
||||
return nullptr;
|
||||
break;
|
||||
}
|
||||
case 'j': {
|
||||
if(!matchNumericRange(1, 366, tm->tm_yday, &state->has_day_of_year))
|
||||
return nullptr;
|
||||
tm->tm_yday--;
|
||||
break;
|
||||
}
|
||||
case 'm': {
|
||||
if(!matchNumericRange(1, 12, tm->tm_mon, &state->has_month))
|
||||
return nullptr;
|
||||
tm->tm_mon--;
|
||||
break;
|
||||
}
|
||||
case 'M': {
|
||||
if(!matchNumericRange(0, 59, tm->tm_min, nullptr))
|
||||
return nullptr;
|
||||
break;
|
||||
}
|
||||
case 'n':
|
||||
case 't': {
|
||||
size_t n = 0;
|
||||
while(isspace(input[state->input_index++]))
|
||||
n++;
|
||||
if(n == 0)
|
||||
return nullptr;
|
||||
state->input_index--;
|
||||
break;
|
||||
}
|
||||
case 'p': {
|
||||
const char *meridian_str = nl_langinfo(AM_STR);
|
||||
size_t len = strlen(meridian_str);
|
||||
if (!mlibc::strncasecmp(&input[state->input_index], meridian_str, len)) {
|
||||
tm->tm_hour %= 12;
|
||||
state->input_index += len;
|
||||
break;
|
||||
}
|
||||
meridian_str = nl_langinfo(PM_STR);
|
||||
len = strlen(meridian_str);
|
||||
if (!mlibc::strncasecmp(&input[state->input_index], meridian_str, len)) {
|
||||
tm->tm_hour %= 12;
|
||||
tm->tm_hour += 12;
|
||||
state->input_index += len;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'r': { //equivalent to `%I:%M:%S %p`
|
||||
size_t pre_fi = state->format_index;
|
||||
state->format_index = 0;
|
||||
|
||||
char *result = strptime_internal(input, "%I:%M:%S %p", tm, state);
|
||||
if(result == nullptr)
|
||||
return nullptr;
|
||||
|
||||
state->format_index = pre_fi;
|
||||
break;
|
||||
}
|
||||
case 'R': { //equivalent to `%H:%M`
|
||||
size_t pre_fi = state->format_index;
|
||||
state->format_index = 0;
|
||||
|
||||
char *result = strptime_internal(input, "%H:%M", tm, state);
|
||||
if(result == nullptr)
|
||||
return nullptr;
|
||||
|
||||
state->format_index = pre_fi;
|
||||
break;
|
||||
}
|
||||
case 'S': {
|
||||
if(!matchNumericRange(0, 60, tm->tm_sec, nullptr))
|
||||
return nullptr;
|
||||
break;
|
||||
}
|
||||
case 'T': { //equivalent to `%H:%M:%S`
|
||||
size_t pre_fi = state->format_index;
|
||||
state->format_index = 0;
|
||||
|
||||
char *result = strptime_internal(input, "%H:%M:%S", tm, state);
|
||||
if(result == nullptr)
|
||||
return nullptr;
|
||||
|
||||
state->format_index = pre_fi;
|
||||
break;
|
||||
}
|
||||
case 'U':
|
||||
__ensure(!"strptime() %U directive unimplemented.");
|
||||
__builtin_unreachable();
|
||||
break;
|
||||
case 'w': {
|
||||
int product = 0, n = 0;
|
||||
sscanf(&input[state->input_index], "%d%n", &product, &n);
|
||||
if(n == 0 || 1 < n)
|
||||
return nullptr;
|
||||
state->input_index += n;
|
||||
tm->tm_wday = product;
|
||||
state->has_day_of_week = true;
|
||||
break;
|
||||
}
|
||||
case 'W':
|
||||
__ensure(!"strptime() %W directive unimplemented.");
|
||||
__builtin_unreachable();
|
||||
break;
|
||||
case 'x':
|
||||
__ensure(!"strptime() %x directive unimplemented.");
|
||||
__builtin_unreachable();
|
||||
break;
|
||||
case 'X':
|
||||
__ensure(!"strptime() %X directive unimplemented.");
|
||||
__builtin_unreachable();
|
||||
break;
|
||||
case 'y': {
|
||||
int product = 0, n = 0;
|
||||
sscanf(&input[state->input_index], "%d%n", &product, &n);
|
||||
if(n == 0 || 2 < n)
|
||||
return nullptr;
|
||||
if(product < 69)
|
||||
product += 100;
|
||||
state->input_index += n;
|
||||
tm->tm_year = product;
|
||||
state->has_year = true;
|
||||
break;
|
||||
}
|
||||
case 'Y': {
|
||||
int product = 0, n = 0;
|
||||
sscanf(&input[state->input_index], "%d%n", &product, &n);
|
||||
if(n == 0 || 4 < n)
|
||||
return nullptr;
|
||||
state->input_index += n;
|
||||
tm->tm_year = product - 1900;
|
||||
state->has_year = true;
|
||||
state->has_century = true;
|
||||
state->full_year_given = true;
|
||||
state->century = product / 100;
|
||||
break;
|
||||
}
|
||||
case 'F': { //GNU extensions
|
||||
//equivalent to `%Y-%m-%d`
|
||||
size_t pre_fi = state->format_index;
|
||||
state->format_index = 0;
|
||||
|
||||
char *result = strptime_internal(input, "%Y-%m-%d", tm, state);
|
||||
if(result == nullptr)
|
||||
return nullptr;
|
||||
|
||||
state->format_index = pre_fi;
|
||||
break;
|
||||
}
|
||||
case 'g':
|
||||
__ensure(!"strptime() %g directive unimplemented.");
|
||||
__builtin_unreachable();
|
||||
break;
|
||||
case 'G':
|
||||
__ensure(!"strptime() %G directive unimplemented.");
|
||||
__builtin_unreachable();
|
||||
break;
|
||||
case 'u': {
|
||||
if(!matchNumericRange(1, 7, tm->tm_wday, nullptr))
|
||||
return nullptr;
|
||||
tm->tm_wday--;
|
||||
break;
|
||||
}
|
||||
case 'V':
|
||||
__ensure(!"strptime() %V directive unimplemented.");
|
||||
__builtin_unreachable();
|
||||
break;
|
||||
case 'z':
|
||||
__ensure(!"strptime() %z directive unimplemented.");
|
||||
__builtin_unreachable();
|
||||
break;
|
||||
case 'Z':
|
||||
__ensure(!"strptime() %Z directive unimplemented.");
|
||||
__builtin_unreachable();
|
||||
break;
|
||||
case 's': //end of GNU extensions
|
||||
__ensure(!"strptime() %s directive unimplemented.");
|
||||
__builtin_unreachable();
|
||||
break;
|
||||
case 'E': { //locale-dependent date & time representation
|
||||
__ensure(!"strptime() %E* directives unimplemented.");
|
||||
__builtin_unreachable();
|
||||
/*
|
||||
state->format_index++;
|
||||
switch(format[state->format_index]){
|
||||
case 'c':
|
||||
break;
|
||||
case 'C':
|
||||
break;
|
||||
case 'x':
|
||||
break;
|
||||
case 'X':
|
||||
break;
|
||||
case 'y':
|
||||
break;
|
||||
case 'Y':
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
*/
|
||||
}
|
||||
case 'O': { //locale-dependent numeric symbols
|
||||
__ensure(!"strptime() %O* directives unimplemented.");
|
||||
__builtin_unreachable();
|
||||
/*
|
||||
state->format_index++;
|
||||
switch(format[state->format_index]){
|
||||
case 'd':
|
||||
case 'e':
|
||||
break;
|
||||
case 'H':
|
||||
break;
|
||||
case 'I':
|
||||
break;
|
||||
case 'm':
|
||||
break;
|
||||
case 'M':
|
||||
break;
|
||||
case 'S':
|
||||
break;
|
||||
case 'U':
|
||||
break;
|
||||
case 'w':
|
||||
break;
|
||||
case 'W':
|
||||
break;
|
||||
case 'y':
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
*/
|
||||
}
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
state->format_index++;
|
||||
}
|
||||
|
||||
return (char*)input + state->input_index;
|
||||
}
|
||||
|
||||
} //anonymous namespace
|
||||
|
||||
char *strptime(const char *__restrict s, const char *__restrict format, struct tm *__restrict tm){
|
||||
struct strptime_internal_state state = {};
|
||||
|
||||
char *result = strptime_internal(s, format, tm, &state);
|
||||
|
||||
if(result == nullptr)
|
||||
return nullptr;
|
||||
|
||||
if(state.has_century && !state.full_year_given){
|
||||
int full_year = state.century * 100;
|
||||
|
||||
if(state.has_year){
|
||||
//Compensate for default century-adjustment of `%j` operand
|
||||
if(tm->tm_year >= 100)
|
||||
full_year += tm->tm_year - 100;
|
||||
else
|
||||
full_year += tm->tm_year;
|
||||
}
|
||||
|
||||
tm->tm_year = full_year - 1900;
|
||||
|
||||
state.has_year = true;
|
||||
}
|
||||
|
||||
if(state.has_month && !state.has_day_of_year){
|
||||
int day = 0;
|
||||
if(state.has_year)
|
||||
day = month_and_year_to_day_in_year(tm->tm_mon, tm->tm_year);
|
||||
else
|
||||
day = month_to_day(tm->tm_mon);
|
||||
|
||||
tm->tm_yday = day + tm->tm_mday - 1;
|
||||
state.has_day_of_year = true;
|
||||
}
|
||||
|
||||
if(state.has_year && !state.has_day_of_week){
|
||||
if(!state.has_month && !state.has_day_of_month){
|
||||
tm->tm_wday = day_determination(0, 0, tm->tm_year + 1900);
|
||||
}
|
||||
else if(state.has_month && state.has_day_of_month){
|
||||
tm->tm_wday = day_determination(tm->tm_mday, tm->tm_mon, tm->tm_year + 1900);
|
||||
}
|
||||
state.has_day_of_week = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int clock_getcpuclockid(pid_t, clockid_t *) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#include <ucontext.h>
|
||||
#include <bits/ensure.h>
|
||||
|
||||
int getcontext(ucontext_t *) {
|
||||
__ensure(!"Not implemented!");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
int setcontext(const ucontext_t *) {
|
||||
__ensure(!"Not implemented!");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
void makecontext(ucontext_t *, void (*)(), int, ...) {
|
||||
__ensure(!"Not implemented!");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
int swapcontext(ucontext_t *, const ucontext_t *) {
|
||||
__ensure(!"Not implemented!");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,31 @@
|
||||
|
||||
#include <utime.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/posix-sysdeps.hpp>
|
||||
|
||||
int utime(const char *filename, const struct utimbuf *times) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_utimensat, -1);
|
||||
struct timespec time[2];
|
||||
if(times) {
|
||||
time[0].tv_sec = times->actime;
|
||||
time[0].tv_nsec = 0;
|
||||
time[1].tv_sec = times->modtime;
|
||||
time[1].tv_nsec = 0;
|
||||
} else {
|
||||
time[0].tv_sec = UTIME_NOW;
|
||||
time[0].tv_nsec = UTIME_NOW;
|
||||
time[1].tv_sec = UTIME_NOW;
|
||||
time[1].tv_nsec = UTIME_NOW;
|
||||
}
|
||||
|
||||
if (int e = mlibc::sys_utimensat(AT_FDCWD, filename, time, 0); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
#include <bits/ensure.h>
|
||||
#include <errno.h>
|
||||
#include <frg/mutex.hpp>
|
||||
#include <frg/spinlock.hpp>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <paths.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <utmpx.h>
|
||||
|
||||
#include <mlibc/posix-sysdeps.hpp>
|
||||
#include <mlibc/utmp.hpp>
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr const char *defaultUtmpxPath = UTMPX_FILE;
|
||||
|
||||
const char *utmpxPath = defaultUtmpxPath;
|
||||
frg::ticket_spinlock utmpxMutex;
|
||||
|
||||
frg::optional<int> utmpxFd = frg::null_opt;
|
||||
|
||||
utmpx returned;
|
||||
|
||||
} // namespace
|
||||
|
||||
void updwtmpx(const char *file, const struct utmpx *ut) {
|
||||
int fd;
|
||||
int err = mlibc::sys_open(file, O_RDWR | O_CREAT | O_CLOEXEC | O_APPEND, 0644, &fd);
|
||||
if(err) {
|
||||
mlibc::infoLogger() << "\e[31mmlibc: updwtmpx() failed to open " << file << ": "
|
||||
<< strerror(err) << "\e[39m" << frg::endlog;
|
||||
return;
|
||||
}
|
||||
|
||||
mlibc::putUtmpEntry(fd, ut);
|
||||
|
||||
mlibc::sys_close(fd);
|
||||
}
|
||||
|
||||
void endutxent(void) {
|
||||
frg::unique_lock lock{utmpxMutex};
|
||||
|
||||
if(utmpxFd) {
|
||||
mlibc::sys_close(utmpxFd.value());
|
||||
utmpxFd = frg::null_opt;
|
||||
}
|
||||
}
|
||||
|
||||
void setutxent(void) {
|
||||
frg::unique_lock lock{utmpxMutex};
|
||||
|
||||
if(!utmpxFd) {
|
||||
int fd;
|
||||
|
||||
// If we are opening the utmp file as a non-root user with a root-made
|
||||
// utmp, we need to open as a reader instead of a writer, O_RDWR will
|
||||
// fail as no write permission can be obtained with 0644.
|
||||
//
|
||||
// The operations that need writing like updates will naturally fail
|
||||
// because of the underlying sysdep failing.
|
||||
int err = mlibc::sys_open(utmpxPath, O_RDWR | O_CREAT | O_CLOEXEC, 0644, &fd);
|
||||
if(err == EACCES) {
|
||||
err = mlibc::sys_open(utmpxPath, O_RDONLY | O_CLOEXEC, 0644, &fd);
|
||||
}
|
||||
|
||||
if(err) {
|
||||
mlibc::infoLogger() << "\e[31mmlibc: setutxent() failed to open " << utmpxPath << ": "
|
||||
<< strerror(err) << "\e[39m" << frg::endlog;
|
||||
utmpxFd = frg::null_opt;
|
||||
} else {
|
||||
utmpxFd = fd;
|
||||
}
|
||||
} else {
|
||||
off_t discard;
|
||||
mlibc::sys_seek(utmpxFd.value(), 0, SEEK_SET, &discard);
|
||||
}
|
||||
}
|
||||
|
||||
struct utmpx *getutxent(void) {
|
||||
frg::unique_lock lock{utmpxMutex};
|
||||
|
||||
if(!utmpxFd)
|
||||
setutxent();
|
||||
if(!utmpxFd) {
|
||||
errno = ENOENT;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if(int e = mlibc::getUtmpEntry(*utmpxFd, &returned); e) {
|
||||
errno = e;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &returned;
|
||||
}
|
||||
|
||||
struct utmpx *pututxline(const struct utmpx *ut) {
|
||||
frg::unique_lock lock{utmpxMutex};
|
||||
|
||||
if(!utmpxFd)
|
||||
setutxent();
|
||||
if(!utmpxFd) {
|
||||
errno = ENOENT;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if(int e = mlibc::putUtmpEntry(*utmpxFd, ut); e) {
|
||||
errno = e;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return (utmpx *) ut;
|
||||
}
|
||||
|
||||
int utmpxname(const char *file) {
|
||||
frg::unique_lock lock{utmpxMutex};
|
||||
|
||||
if(strcmp(file, utmpxPath)) {
|
||||
if(!strcmp(file, defaultUtmpxPath)) {
|
||||
free((void *) utmpxPath);
|
||||
utmpxPath = defaultUtmpxPath;
|
||||
} else {
|
||||
char *name = strdup(file);
|
||||
if(!name)
|
||||
return -1;
|
||||
|
||||
if(utmpxPath != defaultUtmpxPath)
|
||||
free((void *) utmpxPath);
|
||||
|
||||
utmpxPath = name;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct utmpx *getutxid(const struct utmpx *ut) {
|
||||
frg::unique_lock lock{utmpxMutex};
|
||||
|
||||
if(!utmpxFd)
|
||||
setutxent();
|
||||
if(!utmpxFd) {
|
||||
errno = ENOENT;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if(int e = mlibc::getUtmpEntryById(*utmpxFd, ut, &returned); e) {
|
||||
errno = e;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &returned;
|
||||
}
|
||||
|
||||
struct utmpx *getutxline(const struct utmpx *ut) {
|
||||
frg::unique_lock lock{utmpxMutex};
|
||||
|
||||
if(!utmpxFd)
|
||||
setutxent();
|
||||
if(!utmpxFd) {
|
||||
errno = ENOENT;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if(int e = mlibc::getUtmpEntryByType(*utmpxFd, ut, &returned); e) {
|
||||
errno = e;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &returned;
|
||||
}
|
||||
@@ -0,0 +1,342 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* code taken from OPNSense, with modifications
|
||||
*
|
||||
* Copyright (c) 2002 Tim J. Robbins.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <wordexp.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define SHELL_PATH "/bin/sh"
|
||||
#define SHELL_NAME "sh"
|
||||
|
||||
static size_t we_read_fully(int fd, char *buffer, size_t len) {
|
||||
size_t done = 0;
|
||||
|
||||
do {
|
||||
ssize_t nread = read(fd, buffer + done, len - done);
|
||||
if(nread == -1 && errno == EINTR)
|
||||
continue;
|
||||
if(nread <= 0)
|
||||
break;
|
||||
done += nread;
|
||||
} while (done != len);
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
static int we_askshell(const char *words, wordexp_t *we, int flags) {
|
||||
int pdes[2]; /* pipe to child */
|
||||
char bbuf[9]; /* buffer for byte count */
|
||||
char wbuf[9]; /* buffer for word count */
|
||||
size_t nwords = 0; /* number of words from child */
|
||||
size_t nbytes = 0; /* number of bytes from child */
|
||||
size_t sofs = 0; /* offset into we->we_strings */
|
||||
size_t vofs = 0; /* offset into we->we_wordv */
|
||||
pid_t pid; /* PID of child */
|
||||
pid_t wpid; /* waitpid return value */
|
||||
int status; /* child exit status */
|
||||
int error; /* our return value */
|
||||
int serrno; /* errno to return */
|
||||
char *np, *p; /* handy pointers */
|
||||
char *nstrings; /* temporary for realloc() */
|
||||
char **new_wordv; /* temporary for realloc() */
|
||||
sigset_t newsigblock;
|
||||
sigset_t oldsigblock;
|
||||
const char *ifs = getenv("IFS");
|
||||
|
||||
serrno = errno;
|
||||
|
||||
if(pipe2(pdes, O_CLOEXEC) < 0)
|
||||
return WRDE_NOSPACE;
|
||||
|
||||
(void)sigemptyset(&newsigblock);
|
||||
(void)sigaddset(&newsigblock, SIGCHLD);
|
||||
(void)sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock);
|
||||
|
||||
if((pid = fork()) < 0) {
|
||||
serrno = errno;
|
||||
close(pdes[0]);
|
||||
close(pdes[1]);
|
||||
(void)sigprocmask(SIG_SETMASK, &oldsigblock, nullptr);
|
||||
errno = serrno;
|
||||
return WRDE_NOSPACE;
|
||||
} else if(pid == 0) {
|
||||
/*
|
||||
* We are the child; make /bin/sh expand `words'.
|
||||
*/
|
||||
(void)sigprocmask(SIG_SETMASK, &oldsigblock, nullptr);
|
||||
if((pdes[1] != STDOUT_FILENO ? dup2(pdes[1], STDOUT_FILENO) : fcntl(pdes[1], F_SETFD, 0)) < 0)
|
||||
_exit(1);
|
||||
|
||||
execl(SHELL_PATH, SHELL_NAME, flags & WRDE_UNDEF ? "-u" : "+u",
|
||||
"-c", "IFS=$1;eval \"$2\";eval \"set -- $3\";IFS=;a=\"$*\";"
|
||||
"printf '%08x' \"$#\" \"${#a}\";printf '%s\\0' \"$@\"", "",
|
||||
ifs != nullptr ? ifs : " \t\n",
|
||||
flags & WRDE_SHOWERR ? "" : "exec 2>/dev/null",
|
||||
words,
|
||||
(char *)nullptr);
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* We are the parent; read the output of the shell wordexp function,
|
||||
* which is a 32-bit hexadecimal word count, a 32-bit hexadecimal
|
||||
* byte count (not including terminating null bytes), followed by
|
||||
* the expanded words separated by nulls.
|
||||
*/
|
||||
close(pdes[1]);
|
||||
if(we_read_fully(pdes[0], wbuf, 8) != 8 || we_read_fully(pdes[0], bbuf, 8) != 8) {
|
||||
error = flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX;
|
||||
serrno = errno;
|
||||
goto cleanup;
|
||||
}
|
||||
wbuf[8] = bbuf[8] = '\0';
|
||||
nwords = strtol(wbuf, nullptr, 16);
|
||||
nbytes = strtol(bbuf, nullptr, 16) + nwords;
|
||||
|
||||
/*
|
||||
* Allocate or reallocate (when flags & WRDE_APPEND) the word vector
|
||||
* and string storage buffers for the expanded words we're about to
|
||||
* read from the child.
|
||||
*/
|
||||
sofs = we->we_nbytes;
|
||||
vofs = we->we_wordc;
|
||||
if((flags & (WRDE_DOOFFS|WRDE_APPEND)) == (WRDE_DOOFFS | WRDE_APPEND))
|
||||
vofs += we->we_offs;
|
||||
we->we_wordc += nwords;
|
||||
we->we_nbytes += nbytes;
|
||||
|
||||
if((new_wordv = (char **) realloc(we->we_wordv, (we->we_wordc + 1 + (flags & WRDE_DOOFFS ? we->we_offs : 0)) * sizeof(char *))) == nullptr) {
|
||||
error = WRDE_NOSPACE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
we->we_wordv = new_wordv;
|
||||
|
||||
if((nstrings = (char *) realloc(we->we_strings, we->we_nbytes)) == nullptr) {
|
||||
error = WRDE_NOSPACE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < vofs; i++) {
|
||||
if(we->we_wordv[i] != nullptr)
|
||||
we->we_wordv[i] += nstrings - we->we_strings;
|
||||
}
|
||||
we->we_strings = nstrings;
|
||||
|
||||
if(we_read_fully(pdes[0], we->we_strings + sofs, nbytes) != nbytes) {
|
||||
error = flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX;
|
||||
serrno = errno;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
error = 0;
|
||||
cleanup:
|
||||
close(pdes[0]);
|
||||
|
||||
do {
|
||||
wpid = waitpid(pid, &status, 0);
|
||||
} while(wpid < 0 && errno == EINTR);
|
||||
|
||||
(void)sigprocmask(SIG_SETMASK, &oldsigblock, nullptr);
|
||||
|
||||
if(error != 0) {
|
||||
errno = serrno;
|
||||
return error;
|
||||
}
|
||||
|
||||
if(wpid < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
|
||||
return flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX;
|
||||
|
||||
/*
|
||||
* Break the null-terminated expanded word strings out into
|
||||
* the vector.
|
||||
*/
|
||||
if(vofs == 0 && flags & WRDE_DOOFFS) {
|
||||
while (vofs < we->we_offs)
|
||||
we->we_wordv[vofs++] = nullptr;
|
||||
}
|
||||
|
||||
p = we->we_strings + sofs;
|
||||
while (nwords-- != 0) {
|
||||
we->we_wordv[vofs++] = p;
|
||||
if((np = (char *) memchr(p, '\0', nbytes)) == nullptr)
|
||||
return WRDE_NOSPACE;
|
||||
|
||||
nbytes -= np - p + 1;
|
||||
p = np + 1;
|
||||
}
|
||||
|
||||
we->we_wordv[vofs] = nullptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* we_check --
|
||||
* Check that the string contains none of the following unquoted
|
||||
* special characters: <newline> |&;<>(){}
|
||||
* or command substitutions when WRDE_NOCMD is set in flags.
|
||||
*/
|
||||
static int we_check(const char *words, int flags)
|
||||
{
|
||||
char c;
|
||||
int dquote, level, quote, squote;
|
||||
|
||||
quote = squote = dquote = 0;
|
||||
while ((c = *words++) != '\0') {
|
||||
switch (c) {
|
||||
case '\\': {
|
||||
if(squote == 0)
|
||||
quote ^= 1;
|
||||
continue;
|
||||
}
|
||||
case '\'': {
|
||||
if(quote + dquote == 0)
|
||||
squote ^= 1;
|
||||
break;
|
||||
}
|
||||
case '"': {
|
||||
if(quote + squote == 0)
|
||||
dquote ^= 1;
|
||||
break;
|
||||
}
|
||||
case '`': {
|
||||
if(quote + squote == 0 && flags & WRDE_NOCMD)
|
||||
return WRDE_CMDSUB;
|
||||
while ((c = *words++) != '\0' && c != '`')
|
||||
if(c == '\\' && (c = *words++) == '\0')
|
||||
break;
|
||||
if(c == '\0')
|
||||
return WRDE_SYNTAX;
|
||||
break;
|
||||
}
|
||||
case '|':
|
||||
case '&':
|
||||
case ';':
|
||||
case '<':
|
||||
case '>':
|
||||
case '{':
|
||||
case '}':
|
||||
case '(':
|
||||
case ')':
|
||||
case '\n': {
|
||||
if(quote + squote + dquote == 0)
|
||||
return WRDE_BADCHAR;
|
||||
break;
|
||||
}
|
||||
case '$': {
|
||||
if((c = *words++) == '\0')
|
||||
break;
|
||||
else if(quote + squote == 0 && c == '(') {
|
||||
if(flags & WRDE_NOCMD && *words != '(')
|
||||
return WRDE_CMDSUB;
|
||||
level = 1;
|
||||
while ((c = *words++) != '\0') {
|
||||
if(c == '\\') {
|
||||
if((c = *words++) == '\0')
|
||||
break;
|
||||
} else if(c == '(')
|
||||
level++;
|
||||
else if(c == ')' && --level == 0)
|
||||
break;
|
||||
}
|
||||
if(c == '\0' || level != 0)
|
||||
return WRDE_SYNTAX;
|
||||
} else if(quote + squote == 0 && c == '{') {
|
||||
level = 1;
|
||||
while ((c = *words++) != '\0') {
|
||||
if(c == '\\') {
|
||||
if((c = *words++) == '\0')
|
||||
break;
|
||||
} else if(c == '{')
|
||||
level++;
|
||||
else if(c == '}' && --level == 0)
|
||||
break;
|
||||
}
|
||||
if(c == '\0' || level != 0)
|
||||
return WRDE_SYNTAX;
|
||||
} else
|
||||
--words;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
quote = 0;
|
||||
}
|
||||
|
||||
if(quote + squote + dquote != 0)
|
||||
return WRDE_SYNTAX;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wordexp(const char * __restrict words, wordexp_t * __restrict we, int flags) {
|
||||
int error;
|
||||
|
||||
if(flags & WRDE_REUSE)
|
||||
wordfree(we);
|
||||
|
||||
if((flags & WRDE_APPEND) == 0) {
|
||||
we->we_wordc = 0;
|
||||
we->we_wordv = nullptr;
|
||||
we->we_strings = nullptr;
|
||||
we->we_nbytes = 0;
|
||||
}
|
||||
|
||||
if((error = we_check(words, flags)) != 0) {
|
||||
wordfree(we);
|
||||
return error;
|
||||
}
|
||||
|
||||
if((error = we_askshell(words, we, flags)) != 0) {
|
||||
wordfree(we);
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wordfree(wordexp_t *we) {
|
||||
if (we == nullptr)
|
||||
return;
|
||||
free(we->we_wordv);
|
||||
free(we->we_strings);
|
||||
we->we_wordv = nullptr;
|
||||
we->we_strings = nullptr;
|
||||
we->we_nbytes = 0;
|
||||
we->we_wordc = 0;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
#ifndef _ARPA_INET_H
|
||||
#define _ARPA_INET_H
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef __MLIBC_ABI_ONLY
|
||||
|
||||
uint32_t htonl(uint32_t __x);
|
||||
uint16_t htons(uint16_t __x);
|
||||
uint32_t ntohl(uint32_t __x);
|
||||
uint16_t ntohs(uint16_t __x);
|
||||
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
/* IPv4 address manipulation. */
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
|
||||
in_addr_t inet_addr(const char *__cp);
|
||||
in_addr_t inet_network(const char *__cp);
|
||||
char *inet_ntoa(struct in_addr __in);
|
||||
|
||||
/* GLIBC replacement for inet_addr(). */
|
||||
int inet_aton(const char *__cp, struct in_addr *__dest);
|
||||
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
/* Generic IP address manipulation. */
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
const char *inet_ntop(int __af, const void *__restrict __src, char *__restrict __dst,
|
||||
socklen_t __size) __attribute__((__nonnull__(3)));
|
||||
int inet_pton(int __af, const char *__restrict __src, void *__restrict __dst);
|
||||
|
||||
struct in_addr inet_makeaddr(in_addr_t __net, in_addr_t __host);
|
||||
in_addr_t inet_netof(struct in_addr __in);
|
||||
|
||||
#endif /* !__MLIBC_ABI_ONLY */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _ARPA_INET_H */
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef MLIBC_FD_SET_H
|
||||
#define MLIBC_FD_SET_H
|
||||
|
||||
#include <bits/types.h>
|
||||
|
||||
typedef struct {
|
||||
__mlibc_uint8 fds_bits[128];
|
||||
} fd_set;
|
||||
|
||||
#endif /* MLIBC_FD_SET_H */
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef _MLIBC_ID_T_H
|
||||
#define _MLIBC_ID_T_H
|
||||
|
||||
typedef unsigned int id_t;
|
||||
|
||||
#endif /* _MLIBC_ID_T_H */
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef MLIBC_IN_ADDR_H
|
||||
#define MLIBC_IN_ADDR_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef uint32_t in_addr_t;
|
||||
|
||||
#endif /* MLIBC_IN_ADDR_H */
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef MLIBC_IN_PORT_H
|
||||
#define MLIBC_IN_PORT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef uint16_t in_port_t;
|
||||
|
||||
#endif /* MLIBC_IN_PORT_H */
|
||||
@@ -0,0 +1,11 @@
|
||||
#ifndef MLIBC_IOVEC_H
|
||||
#define MLIBC_IOVEC_H
|
||||
|
||||
#include <bits/types.h>
|
||||
|
||||
struct iovec {
|
||||
void *iov_base;
|
||||
__mlibc_size iov_len;
|
||||
};
|
||||
|
||||
#endif /* MLIBC_IOVEC_H */
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef _LOCALE_T_H
|
||||
#define _LOCALE_T_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void *locale_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LOCALE_T_H */
|
||||
@@ -0,0 +1,36 @@
|
||||
#ifndef _POSIX_CTYPE_H
|
||||
#define _POSIX_CTYPE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <bits/posix/locale_t.h>
|
||||
|
||||
#ifndef __MLIBC_ABI_ONLY
|
||||
|
||||
int isalnum_l(int __c, locale_t __loc);
|
||||
int isalpha_l(int __c, locale_t __loc);
|
||||
int isblank_l(int __c, locale_t __loc);
|
||||
int iscntrl_l(int __c, locale_t __loc);
|
||||
int isdigit_l(int __c, locale_t __loc);
|
||||
int isgraph_l(int __c, locale_t __loc);
|
||||
int islower_l(int __c, locale_t __loc);
|
||||
int isprint_l(int __c, locale_t __loc);
|
||||
int ispunct_l(int __c, locale_t __loc);
|
||||
int isspace_l(int __c, locale_t __loc);
|
||||
int isupper_l(int __c, locale_t __loc);
|
||||
int isxdigit_l(int __c, locale_t __loc);
|
||||
|
||||
int isascii_l(int __c, locale_t __loc);
|
||||
|
||||
int tolower_l(int __c, locale_t __loc);
|
||||
int toupper_l(int __c, locale_t __loc);
|
||||
|
||||
#endif /* !__MLIBC_ABI_ONLY */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _POSIX_CTYPE_H */
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef MLIBC_POSIX_LOCALE_H
|
||||
#define MLIBC_POSIX_LOCALE_H
|
||||
|
||||
#include <bits/posix/locale_t.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef __MLIBC_ABI_ONLY
|
||||
|
||||
locale_t newlocale(int __category_mask, const char *__locale, locale_t __base);
|
||||
void freelocale(locale_t __locobj);
|
||||
locale_t uselocale(locale_t __locobj);
|
||||
locale_t duplocale(locale_t __locobj);
|
||||
|
||||
#endif /* !__MLIBC_ABI_ONLY */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MLIBC_POSIX_LOCALE_H */
|
||||
@@ -0,0 +1,113 @@
|
||||
|
||||
#ifndef MLIBC_POSIX_SIGNAL_H
|
||||
#define MLIBC_POSIX_SIGNAL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <bits/ansi/time_t.h>
|
||||
#include <bits/ansi/timespec.h>
|
||||
#include <bits/posix/pthread_t.h>
|
||||
#include <bits/sigset_t.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <mlibc-config.h>
|
||||
|
||||
#define FPE_INTDIV 1 /* integer divide by zero */
|
||||
#define FPE_INTOVF 2 /* integer overflow */
|
||||
#define FPE_FLTDIV 3 /* floating point divide by zero */
|
||||
#define FPE_FLTOVF 4 /* floating point overflow */
|
||||
#define FPE_FLTUND 5 /* floating point underflow */
|
||||
#define FPE_FLTRES 6 /* floating point inexact result */
|
||||
#define FPE_FLTINV 7 /* floating point invalid operation */
|
||||
#define FPE_FLTSUB 8 /* subscript out of range */
|
||||
|
||||
#define TRAP_BRKPT 1 /* process breakpoint */
|
||||
#define TRAP_TRACE 2 /* process trace trap */
|
||||
|
||||
#if defined(__x86_64__)
|
||||
/* Start Glibc stuff */
|
||||
|
||||
struct _libc_fpxreg {
|
||||
unsigned short int significand[4];
|
||||
unsigned short int exponent;
|
||||
unsigned short int __glibc_reserved1[3];
|
||||
};
|
||||
|
||||
struct _libc_xmmreg {
|
||||
uint32_t element[4];
|
||||
};
|
||||
|
||||
struct _libc_fpstate {
|
||||
uint16_t cwd;
|
||||
int16_t swd;
|
||||
uint16_t ftw;
|
||||
uint16_t fop;
|
||||
uint64_t rip;
|
||||
uint64_t dp;
|
||||
uint32_t mxcsr;
|
||||
uint32_t mxcr_mask;
|
||||
struct _libc_fpxreg _st[8];
|
||||
struct _libc_xmmreg _xmm[16];
|
||||
uint32_t __glibc_reserved1[24];
|
||||
};
|
||||
|
||||
typedef struct _libc_fpstate *fpregset_t;
|
||||
/* End Glibc stuff */
|
||||
|
||||
typedef unsigned long int greg_t;
|
||||
#endif
|
||||
|
||||
#define FPE_INTDIV 1 /* integer divide by zero */
|
||||
#define FPE_INTOVF 2 /* integer overflow */
|
||||
#define FPE_FLTDIV 3 /* floating point divide by zero */
|
||||
#define FPE_FLTOVF 4 /* floating point overflow */
|
||||
#define FPE_FLTUND 5 /* floating point underflow */
|
||||
#define FPE_FLTRES 6 /* floating point inexact result */
|
||||
#define FPE_FLTINV 7 /* floating point invalid operation */
|
||||
#define FPE_FLTSUB 8 /* subscript out of range */
|
||||
|
||||
#define TRAP_BRKPT 1 /* process breakpoint */
|
||||
#define TRAP_TRACE 2 /* process trace trap */
|
||||
|
||||
#ifndef __MLIBC_ABI_ONLY
|
||||
|
||||
/* functions to block / wait for signals */
|
||||
int sigsuspend(const sigset_t *__sigmask);
|
||||
int sigprocmask(int __how, const sigset_t *__restrict __sigmask, sigset_t *__restrict __oldmask);
|
||||
|
||||
int pthread_sigmask(int __how, const sigset_t *__restrict __sigmask, sigset_t *__restrict __oldmask);
|
||||
int pthread_kill(pthread_t __thrd, int __sig);
|
||||
|
||||
/* functions to handle signals */
|
||||
int sigaction(int __signum, const struct sigaction *__restrict __act, struct sigaction *__restrict __oldact);
|
||||
int sigpending(sigset_t *__set);
|
||||
|
||||
int siginterrupt(int __sig, int __flag);
|
||||
|
||||
int sigaltstack(const stack_t *__restrict __ss, stack_t *__restrict __oss);
|
||||
|
||||
/* functions to raise signals */
|
||||
int kill(pid_t __pid, int __number);
|
||||
int killpg(int __pgrp, int __sig);
|
||||
|
||||
int sigtimedwait(const sigset_t *__restrict __set, siginfo_t *__restrict __info, const struct timespec *__restrict __timeout);
|
||||
int sigwait(const sigset_t *__restrict __set, int *__restrict __sig);
|
||||
int sigwaitinfo(const sigset_t *__restrict __set, siginfo_t *__restrict __info);
|
||||
|
||||
/* Glibc extension */
|
||||
#if __MLIBC_GLIBC_OPTION
|
||||
int sigisemptyset(const sigset_t *__set);
|
||||
#endif /* __MLIBC_GLIBC_OPTION */
|
||||
|
||||
int sigqueue(pid_t __pid, int __sig, const union sigval __value);
|
||||
|
||||
#endif /* !__MLIBC_ABI_ONLY */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MLIBC_POSIX_SIGNAL_H */
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
|
||||
#ifndef MLIBC_POSIX_STDIO_H
|
||||
#define MLIBC_POSIX_STDIO_H
|
||||
|
||||
#include <bits/off_t.h>
|
||||
#include <bits/size_t.h>
|
||||
#include <bits/ssize_t.h>
|
||||
#include <bits/file.h>
|
||||
|
||||
/* MISSING: var_list */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define P_tmpdir "/tmp"
|
||||
|
||||
#ifndef __MLIBC_ABI_ONLY
|
||||
|
||||
int fileno(FILE *__file);
|
||||
FILE *fdopen(int __fd, const char *__mode);
|
||||
|
||||
FILE *fmemopen(void *__restrict __buf, size_t __size, const char *__restrict __mode);
|
||||
int pclose(FILE *__file);
|
||||
FILE *popen(const char *__command, const char *__type);
|
||||
FILE *open_memstream(char **__buf, size_t *__sizeloc);
|
||||
|
||||
int fseeko(FILE *__stream, off_t __offset, int __whence);
|
||||
int fseeko64(FILE *__stream, off64_t __offset, int __whence);
|
||||
off_t ftello(FILE *__stream);
|
||||
off64_t ftello64(FILE *__stream);
|
||||
|
||||
__attribute__((format(__printf__, 2, 3))) int dprintf(int __fd, const char *__format, ...);
|
||||
__attribute__((format(__printf__, 2, 0)))
|
||||
int vdprintf(int __fd, const char *__format, __builtin_va_list __args);
|
||||
|
||||
char *fgetln(FILE *__stream, size_t *__size);
|
||||
|
||||
char *tempnam(const char *__dir, const char *__pfx);
|
||||
|
||||
#endif /* !__MLIBC_ABI_ONLY */
|
||||
|
||||
#define RENAME_EXCHANGE (1 << 1)
|
||||
|
||||
/* GNU extensions */
|
||||
typedef ssize_t (cookie_read_function_t)(void *__cookie, char *__buffer, size_t __size);
|
||||
typedef ssize_t (cookie_write_function_t)(void *__cookie, const char *__buffer, size_t __size);
|
||||
typedef int (cookie_seek_function_t)(void *__cookie, off_t *, int);
|
||||
typedef int (cookie_close_function_t)(void *__cookie);
|
||||
|
||||
typedef struct _IO_cookie_io_functions_t {
|
||||
cookie_read_function_t *read;
|
||||
cookie_write_function_t *write;
|
||||
cookie_seek_function_t *seek;
|
||||
cookie_close_function_t *close;
|
||||
} cookie_io_functions_t;
|
||||
|
||||
#ifndef __MLIBC_ABI_ONLY
|
||||
|
||||
#if defined(_GNU_SOURCE)
|
||||
|
||||
FILE *fopencookie(void *__restrict __cookie, const char *__restrict __mode, cookie_io_functions_t __io_funcs);
|
||||
|
||||
#endif /* defined(_GNU_SOURCE) */
|
||||
|
||||
#endif /* !__MLIBC_ABI_ONLY */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/* MISSING: various functions and macros */
|
||||
|
||||
#endif /* MLIBC_POSIX_STDIO_H */
|
||||
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
|
||||
#ifndef MLIBC_POSIX_STDLIB_H
|
||||
#define MLIBC_POSIX_STDLIB_H
|
||||
|
||||
#include <bits/posix/locale_t.h>
|
||||
#include <bits/size_t.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef __MLIBC_ABI_ONLY
|
||||
|
||||
long random(void);
|
||||
double drand48(void);
|
||||
double erand48(unsigned short __s[3]);
|
||||
unsigned short *seed48(unsigned short __s[3]);
|
||||
void srand48(long int __seed);
|
||||
long int mrand48(void);
|
||||
long jrand48(unsigned short __s[3]);
|
||||
char *initstate(unsigned int __seed, char *__state, size_t __size);
|
||||
char *setstate(char *__state);
|
||||
void srandom(unsigned int __seed);
|
||||
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
/* Environment. */
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
|
||||
int putenv(char *__string);
|
||||
int setenv(const char *__name, const char *__value, int __overwrite);
|
||||
int unsetenv(const char *__name);
|
||||
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
/* Path handling. */
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
|
||||
int mkstemp(char *__pattern);
|
||||
int mkstemps(char *__pattern, int __suffixlen);
|
||||
int mkostemp(char *__pattern, int __flags);
|
||||
int mkostemps(char *__pattern, int __suffixlen, int __flags);
|
||||
char *mkdtemp(char *__path);
|
||||
|
||||
char *realpath(const char *__restrict __path, char *__restrict __out);
|
||||
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
/* Pseudoterminals */
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
|
||||
int posix_openpt(int __flags);
|
||||
int grantpt(int __fd);
|
||||
int unlockpt(int __fd);
|
||||
char *ptsname(int __fd);
|
||||
int ptsname_r(int __fd, char *__buf, size_t __len);
|
||||
|
||||
double strtod_l(const char *__restrict__ __nptr, char ** __restrict__ __endptr, locale_t __loc);
|
||||
long double strtold_l(const char *__restrict__ __nptr, char ** __restrict__ __endptr, locale_t __loc);
|
||||
float strtof_l(const char *__restrict __string, char **__restrict __end, locale_t __loc);
|
||||
|
||||
int getsubopt(char **__restrict__ __optionp, char *const *__restrict__ __tokens, char **__restrict__ __valuep);
|
||||
|
||||
/* GNU extension */
|
||||
char *secure_getenv(const char *__name);
|
||||
char *canonicalize_file_name(const char *__name);
|
||||
|
||||
/* BSD extension */
|
||||
void *reallocarray(void *__ptr, size_t __count, size_t __size);
|
||||
|
||||
int clearenv(void);
|
||||
|
||||
#endif /* !__MLIBC_ABI_ONLY */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MLIBC_POSIX_STDLIB_H */
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
|
||||
#ifndef MLIBC_POSIX_STRING_H
|
||||
#define MLIBC_POSIX_STRING_H
|
||||
|
||||
#include <alloca.h>
|
||||
#include <bits/posix/locale_t.h>
|
||||
#include <bits/size_t.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef __MLIBC_ABI_ONLY
|
||||
|
||||
char *strdup(const char *__string);
|
||||
char *strndup(const char *__string, size_t __max_size);
|
||||
size_t strnlen(const char *__s, size_t __max_size);
|
||||
char *strtok_r(char *__restrict __s, const char *__restrict __delim, char **__restrict __ptr);
|
||||
char *strsep(char **__stringp, const char *__delim);
|
||||
char *strsignal(int __sig);
|
||||
char *stpcpy(char *__restrict __dest, const char *__restrict __src);
|
||||
char *stpncpy(char *__restrict __dest, const char *__restrict __src, size_t __n);
|
||||
void *memccpy(void *__restrict __dest, const void *__restrict __src, int __c, size_t __n);
|
||||
|
||||
int strcoll_l(const char *__s1, const char *__s2, locale_t __locale);
|
||||
|
||||
char *strerror_l(int __errnum, locale_t __locale);
|
||||
|
||||
/* GNU extensions. */
|
||||
#if defined(_GNU_SOURCE)
|
||||
char *strcasestr(const char *__s1, const char *__s2);
|
||||
#define strdupa(x) ({ \
|
||||
const char *__str = (x); \
|
||||
size_t __len = strlen(__str) + 1; \
|
||||
char *__buf = alloca(__len); \
|
||||
(char *) memcpy(__buf, __str, __len); \
|
||||
})
|
||||
#define strndupa(x, y) ({ \
|
||||
const char *__str = (x); \
|
||||
size_t __len = strnlen(__str, (y)) + 1; \
|
||||
char *__buf = alloca(__len); \
|
||||
__buf[__len - 1] = '\0'; \
|
||||
(char *) memcpy(__buf, __str, __len - 1); \
|
||||
})
|
||||
void *memrchr(const void *__m, int __c, size_t __n);
|
||||
#endif /* defined(_GNU_SOURCE) */
|
||||
|
||||
/* BSD extensions */
|
||||
size_t strlcpy(char *__d, const char *__s, size_t __n);
|
||||
size_t strlcat(char *__d, const char *__s, size_t __n);
|
||||
|
||||
#endif /* !__MLIBC_ABI_ONLY */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MLIBC_POSIX_STRING_H */
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
#ifndef MLIBC_POSIX_TIME_H
|
||||
#define MLIBC_POSIX_TIME_H
|
||||
|
||||
#include <abi-bits/clockid_t.h>
|
||||
#include <abi-bits/sigevent.h>
|
||||
#include <bits/ansi/timespec.h>
|
||||
#include <bits/posix/timer_t.h>
|
||||
#include <bits/posix/timeval.h>
|
||||
|
||||
#define TIMER_ABSTIME 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct itimerspec {
|
||||
struct timespec it_interval;
|
||||
struct timespec it_value;
|
||||
};
|
||||
|
||||
#ifndef __MLIBC_ABI_ONLY
|
||||
|
||||
int timer_getoverrun(timer_t __timerid);
|
||||
|
||||
int utimes(const char *__filename, const struct timeval __tv[2]);
|
||||
|
||||
/* Not standardized, Linux and BSDs have it */
|
||||
int futimes(int __fd, const struct timeval __tv[2]);
|
||||
int lutimes(const char *__filename, const struct timeval __tv[2]);
|
||||
|
||||
int timer_create(clockid_t __clockid, struct sigevent *__restrict __sevp, timer_t *__restrict __timerid);
|
||||
int timer_settime(timer_t __timerid, int __flags, const struct itimerspec *__restrict __new_value,
|
||||
struct itimerspec *__restrict __old_value);
|
||||
int timer_gettime(timer_t __timerid, struct itimerspec *__curr_value);
|
||||
int timer_delete(timer_t __timerid);
|
||||
|
||||
#endif /* !__MLIBC_ABI_ONLY */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MLIBC_POSIX_TIME_H */
|
||||
@@ -0,0 +1,43 @@
|
||||
#ifndef _POSIX_WCTYPE_H
|
||||
#define _POSIX_WCTYPE_H
|
||||
|
||||
#include <bits/posix/locale_t.h>
|
||||
#include <bits/wint_t.h>
|
||||
#include <bits/wctype_t.h>
|
||||
#include <bits/wctrans_t.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef __MLIBC_ABI_ONLY
|
||||
|
||||
int iswalnum_l(wint_t __wc, locale_t __loc);
|
||||
int iswblank_l(wint_t __wc, locale_t __loc);
|
||||
int iswcntrl_l(wint_t __wc, locale_t __loc);
|
||||
int iswdigit_l(wint_t __wc, locale_t __loc);
|
||||
int iswgraph_l(wint_t __wc, locale_t __loc);
|
||||
int iswlower_l(wint_t __wc, locale_t __loc);
|
||||
int iswprint_l(wint_t __wc, locale_t __loc);
|
||||
int iswpunct_l(wint_t __wc, locale_t __loc);
|
||||
int iswspace_l(wint_t __wc, locale_t __loc);
|
||||
int iswupper_l(wint_t __wc, locale_t __loc);
|
||||
int iswxdigit_l(wint_t __wc, locale_t __loc);
|
||||
int iswalpha_l(wint_t __wc, locale_t __loc);
|
||||
|
||||
wctype_t wctype_l(const char *__string, locale_t __loc);
|
||||
int iswctype_l(wint_t __wc, wctype_t __type, locale_t __loc);
|
||||
|
||||
wint_t towlower_l(wint_t __wc, locale_t __loc);
|
||||
wint_t towupper_l(wint_t __wc, locale_t __loc);
|
||||
|
||||
wctrans_t wctrans_l(const char *__string, locale_t __loc);
|
||||
wint_t towctrans_l(wint_t __wc, wctrans_t __trans, locale_t __loc);
|
||||
|
||||
#endif /* !__MLIBC_ABI_ONLY */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _POSIX_WCTYPE_H */
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef _MLIBC_BITS_PTHREAD_T_HPP
|
||||
#define _MLIBC_BITS_PTHREAD_T_HPP
|
||||
|
||||
#include <bits/threads.h>
|
||||
|
||||
typedef struct __mlibc_thread_data *pthread_t;
|
||||
|
||||
#endif /* _MLIBC_BITS_PTHREAD_T_HPP */
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef MLIBC_STAT_H
|
||||
#define MLIBC_STAT_H
|
||||
|
||||
#include <abi-bits/stat.h>
|
||||
|
||||
/* Used by utimensat and friends */
|
||||
#define UTIME_NOW ((1l << 30) - 1l)
|
||||
#define UTIME_OMIT ((1l << 30) - 2l)
|
||||
|
||||
#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
|
||||
#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
|
||||
#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
|
||||
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
|
||||
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
|
||||
#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
|
||||
#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
|
||||
|
||||
/* POSIX compatibility macros */
|
||||
#define st_atime st_atim.tv_sec
|
||||
#define st_mtime st_mtim.tv_sec
|
||||
#define st_ctime st_ctim.tv_sec
|
||||
|
||||
#endif /* MLIBC_STAT_H */
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef _MLIBC_TIMER_T_H
|
||||
#define _MLIBC_TIMER_T_H
|
||||
|
||||
typedef void * timer_t;
|
||||
|
||||
#endif /* _MLIBC_TIMER_T_H */
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef MLIBC_TIMEVAL_H
|
||||
#define MLIBC_TIMEVAL_H
|
||||
|
||||
#include <bits/ansi/time_t.h>
|
||||
#include <abi-bits/suseconds_t.h>
|
||||
|
||||
struct timeval {
|
||||
time_t tv_sec;
|
||||
suseconds_t tv_usec;
|
||||
};
|
||||
|
||||
#endif /* MLIBC_TIMEVAL_H */
|
||||
@@ -0,0 +1,23 @@
|
||||
|
||||
#ifndef _BYTESWAP_H
|
||||
#define _BYTESWAP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define bswap_16(x) __builtin_bswap16(x)
|
||||
#define bswap_32(x) __builtin_bswap32(x)
|
||||
#define bswap_64(x) __builtin_bswap64(x)
|
||||
|
||||
/* Some programs like eudev call these functions instead */
|
||||
#define __bswap_16(x) __builtin_bswap16(x)
|
||||
#define __bswap_32(x) __builtin_bswap32(x)
|
||||
#define __bswap_64(x) __builtin_bswap64(x)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _BYTESWAP_H */
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
|
||||
#ifndef _DIRENT_H
|
||||
#define _DIRENT_H
|
||||
|
||||
#include <abi-bits/ino_t.h>
|
||||
#include <bits/off_t.h>
|
||||
#include <bits/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define DT_UNKNOWN 0
|
||||
#define DT_FIFO 1
|
||||
#define DT_CHR 2
|
||||
#define DT_DIR 4
|
||||
#define DT_BLK 6
|
||||
#define DT_REG 8
|
||||
#define DT_LNK 10
|
||||
#define DT_SOCK 12
|
||||
#define DT_WHT 14
|
||||
|
||||
#define __MLIBC_DIRENT_BODY ino_t d_ino; \
|
||||
off_t d_off; \
|
||||
unsigned short d_reclen; \
|
||||
unsigned char d_type; \
|
||||
char d_name[1024];
|
||||
|
||||
struct dirent {
|
||||
__MLIBC_DIRENT_BODY
|
||||
};
|
||||
|
||||
struct dirent64 {
|
||||
__MLIBC_DIRENT_BODY
|
||||
};
|
||||
|
||||
#define d_fileno d_ino
|
||||
|
||||
#undef __MLIBC_DIRENT_BODY
|
||||
|
||||
#define IFTODT(mode) (((mode) & 0170000) >> 12)
|
||||
|
||||
struct __mlibc_dir_struct {
|
||||
int __handle;
|
||||
__mlibc_size __ent_next;
|
||||
__mlibc_size __ent_limit;
|
||||
char __ent_buffer[2048];
|
||||
struct dirent __current;
|
||||
};
|
||||
|
||||
typedef struct __mlibc_dir_struct DIR;
|
||||
|
||||
#ifndef __MLIBC_ABI_ONLY
|
||||
|
||||
int alphasort(const struct dirent **__a, const struct dirent **__b);
|
||||
int closedir(DIR *__dirp);
|
||||
int dirfd(DIR *__dirp);
|
||||
DIR *fdopendir(int __fd);
|
||||
DIR *opendir(const char *__pathname);
|
||||
struct dirent *readdir(DIR *__dirp);
|
||||
struct dirent64 *readdir64(DIR *__dirp);
|
||||
int readdir_r(DIR *__restrict __dirp, struct dirent *__restrict __entry, struct dirent **__restrict __res);
|
||||
void rewinddir(DIR *__dirp);
|
||||
int scandir(const char *__pathname, struct dirent ***__res, int (*__select)(const struct dirent *__entry),
|
||||
int (*__compare)(const struct dirent **__a, const struct dirent **__b));
|
||||
void seekdir(DIR *__dirp, long __loc);
|
||||
long telldir(DIR *__dirp);
|
||||
int versionsort(const struct dirent **__a, const struct dirent **__b);
|
||||
|
||||
#endif /* !__MLIBC_ABI_ONLY */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _DIRENT_H */
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
|
||||
#ifndef _DLFCN_H
|
||||
#define _DLFCN_H
|
||||
|
||||
#include <mlibc-config.h>
|
||||
|
||||
#define RTLD_LOCAL 0
|
||||
#define RTLD_LAZY 1
|
||||
#define RTLD_NOW 2
|
||||
#define RTLD_NOLOAD 4
|
||||
#define RTLD_DEEPBIND 8
|
||||
#define RTLD_GLOBAL 256
|
||||
#define RTLD_NODELETE 4096
|
||||
|
||||
#define RTLD_NEXT ((void *)-1)
|
||||
#define RTLD_DEFAULT ((void *)0)
|
||||
|
||||
#define RTLD_DL_SYMENT 1
|
||||
#define RTLD_DL_LINKMAP 2
|
||||
|
||||
#define RTLD_DI_LINKMAP 2
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef __MLIBC_ABI_ONLY
|
||||
|
||||
int dlclose(void *__handle);
|
||||
char *dlerror(void);
|
||||
void *dlopen(const char *__name, int __flags);
|
||||
void *dlsym(void *__restrict __handle, const char *__restrict __name);
|
||||
void *dlvsym(void *__restrict __handle, const char *__restrict __name, const char *__restrict __version);
|
||||
|
||||
#endif /* !__MLIBC_ABI_ONLY */
|
||||
|
||||
#if defined(_GNU_SOURCE) && __MLIBC_GLIBC_OPTION
|
||||
|
||||
/*gnu extension */
|
||||
typedef struct {
|
||||
const char *dli_fname;
|
||||
void *dli_fbase;
|
||||
const char *dli_sname;
|
||||
void *dli_saddr;
|
||||
} Dl_info;
|
||||
|
||||
#if defined(__i386__)
|
||||
#define DLFO_STRUCT_HAS_EH_DBASE 1
|
||||
#define DLFO_STRUCT_HAS_EH_COUNT 0
|
||||
#define DLFO_EH_SEGMENT_TYPE PT_GNU_EH_FRAME
|
||||
#elif defined(__arm__)
|
||||
#define DLFO_STRUCT_HAS_EH_DBASE 0
|
||||
#define DLFO_STRUCT_HAS_EH_COUNT 1
|
||||
#define DLFO_EH_SEGMENT_TYPE PT_ARM_EXIDX
|
||||
#else
|
||||
#define DLFO_STRUCT_HAS_EH_DBASE 0
|
||||
#define DLFO_STRUCT_HAS_EH_COUNT 0
|
||||
#define DLFO_EH_SEGMENT_TYPE PT_GNU_EH_FRAME
|
||||
#endif
|
||||
|
||||
struct dl_find_object {
|
||||
unsigned long long dlfo_flags;
|
||||
void *dlfo_map_start;
|
||||
void *dlfo_map_end;
|
||||
struct link_map *dlfo_link_map;
|
||||
void *dlfo_eh_frame;
|
||||
#if DLFO_STRUCT_HAS_EH_DBASE
|
||||
void *dlfo_eh_dbase;
|
||||
#if __INTPTR_WIDTH__ == 32
|
||||
unsigned int __unused0;
|
||||
#endif
|
||||
#endif
|
||||
#if DLFO_STRUCT_HAS_EH_COUNT
|
||||
int dlfo_eh_count;
|
||||
unsigned int __unused1;
|
||||
#endif
|
||||
unsigned long long __dlfo_unused[7];
|
||||
};
|
||||
|
||||
#ifndef __MLIBC_ABI_ONLY
|
||||
|
||||
int dladdr(const void *__ptr, Dl_info *__out);
|
||||
int dladdr1(const void *__ptr, Dl_info *__out, void **__extra, int __flags);
|
||||
int dlinfo(void *__restrict __handle, int __request, void *__restrict __info);
|
||||
int _dl_find_object(void *__address, struct dl_find_object *__result);
|
||||
|
||||
#endif /* !__MLIBC_ABI_ONLY */
|
||||
|
||||
#endif /* defined(_GNU_SOURCE) && __MLIBC_GLIBC_OPTION */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _DLFCN_H */
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
|
||||
#ifndef _FCNTL_H
|
||||
#define _FCNTL_H
|
||||
|
||||
#include <abi-bits/fcntl.h>
|
||||
#include <abi-bits/seek-whence.h>
|
||||
#include <abi-bits/mode_t.h>
|
||||
#include <abi-bits/pid_t.h>
|
||||
#include <bits/posix/iovec.h>
|
||||
#include <bits/off_t.h>
|
||||
#include <bits/ssize_t.h>
|
||||
#include <bits/size_t.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define O_NDELAY O_NONBLOCK
|
||||
|
||||
/* WARNING: keep `flock` and `flock64` in sync or bad things will happen! */
|
||||
|
||||
struct flock {
|
||||
short l_type;
|
||||
short l_whence;
|
||||
off_t l_start;
|
||||
off_t l_len;
|
||||
pid_t l_pid;
|
||||
};
|
||||
|
||||
struct flock64 {
|
||||
short l_type;
|
||||
short l_whence;
|
||||
off_t l_start;
|
||||
off_t l_len;
|
||||
pid_t l_pid;
|
||||
};
|
||||
|
||||
#ifndef __MLIBC_ABI_ONLY
|
||||
|
||||
int creat(const char *__path, mode_t __mode);
|
||||
int fallocate(int __fd, int __mode, off_t __offset, off_t __len);
|
||||
int fcntl(int __fd, int __command, ...);
|
||||
int open(const char *__path, int __flags, ...);
|
||||
int open64(const char *__path, int __flags, ...);
|
||||
int openat(int __dirfd, const char *__path, int __flags, ...);
|
||||
int posix_fadvise(int __fd, off_t __offset, off_t __size, int __advice);
|
||||
int posix_fallocate(int __fd, off_t __offset, off_t __size);
|
||||
|
||||
#endif /* !__MLIBC_ABI_ONLY */
|
||||
|
||||
/* This is a linux extension */
|
||||
#ifdef _GNU_SOURCE
|
||||
struct file_handle {
|
||||
unsigned int handle_bytes;
|
||||
int handle_type;
|
||||
__extension__ unsigned char f_handle[0];
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef __MLIBC_ABI_ONLY
|
||||
|
||||
#ifdef _GNU_SOURCE
|
||||
int name_to_handle_at(int __dirfd, const char *__path, struct file_handle *__handle, int *__mount_id, int __flags);
|
||||
int open_by_handle_at(int __dirfd, struct file_handle *__handle, int __flags);
|
||||
#endif
|
||||
|
||||
ssize_t splice(int __fd_in, off_t *__off_in, int __fd_out, off_t *__off_out, size_t __len, unsigned int __flags);
|
||||
ssize_t vmsplice(int __fd, const struct iovec *__iov, size_t __nr_segs, unsigned int __flags);
|
||||
|
||||
#endif /* !__MLIBC_ABI_ONLY */
|
||||
|
||||
#define SPLICE_F_MOVE 1
|
||||
#define SPLICE_F_NONBLOCK 2
|
||||
#define SPLICE_F_MORE 4
|
||||
#define SPLICE_F_GIFT 8
|
||||
|
||||
#define FALLOC_FL_KEEP_SIZE 1
|
||||
#define FALLOC_FL_PUNCH_HOLE 2
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _FCNTL_H */
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
|
||||
#ifndef _FNMATCH_H
|
||||
#define _FNMATCH_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* POSIX-defined fnmatch() flags. */
|
||||
#define FNM_PATHNAME 0x1
|
||||
#define FNM_NOESCAPE 0x2
|
||||
#define FNM_PERIOD 0x4
|
||||
|
||||
/* GNU extensions for fnmatch() flags. */
|
||||
#define FNM_LEADING_DIR 0x8
|
||||
#define FNM_CASEFOLD 0x10
|
||||
#define FNM_EXTMATCH 0x20
|
||||
|
||||
/* fnmatch() return values. */
|
||||
#define FNM_NOMATCH 1
|
||||
|
||||
#ifndef __MLIBC_ABI_ONLY
|
||||
|
||||
int fnmatch(const char *__pattern, const char *__string, int __flags);
|
||||
|
||||
#endif /* !__MLIBC_ABI_ONLY */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _FNMATCH_H */
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
|
||||
#ifndef _FTW_H
|
||||
#define _FTW_H
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define FTW_F 1
|
||||
#define FTW_D 2
|
||||
#define FTW_DNR 3
|
||||
#define FTW_DP 4
|
||||
#define FTW_NS 5
|
||||
#define FTW_SL 6
|
||||
#define FTW_SLN 7
|
||||
|
||||
#define FTW_PHYS 1
|
||||
#define FTW_MOUNT 2
|
||||
#define FTW_DEPTH 4
|
||||
#define FTW_CHDIR 8
|
||||
|
||||
#define FTW_CONTINUE 0
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct FTW {
|
||||
int base;
|
||||
int level;
|
||||
};
|
||||
|
||||
#ifndef __MLIBC_ABI_ONLY
|
||||
|
||||
int ftw(const char *__dirpath, int (*__fn)(const char *__fpath, const struct stat *__sb, int __typeflag),
|
||||
int __nopenfd);
|
||||
int nftw(const char *__dirpath, int (*__fn)(const char *__fpath, const struct stat *__sb, int __typeflag,
|
||||
struct FTW *__ftwbuf), int __nopenfd, int __flags);
|
||||
|
||||
#endif /* !__MLIBC_ABI_ONLY */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _FTW_H */
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
|
||||
#ifndef _GLOB_H
|
||||
#define _GLOB_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <bits/size_t.h>
|
||||
|
||||
#define GLOB_APPEND 0x01
|
||||
#define GLOB_DOOFFS 0x02
|
||||
#define GLOB_ERR 0x04
|
||||
#define GLOB_MARK 0x08
|
||||
#define GLOB_NOCHECK 0x10
|
||||
#define GLOB_NOESCAPE 0x20
|
||||
#define GLOB_NOSORT 0x40
|
||||
#define GLOB_PERIOD 0x80
|
||||
#define GLOB_TILDE 0x100
|
||||
#define GLOB_TILDE_CHECK 0x200
|
||||
#define GLOB_BRACE 0x400
|
||||
#define GLOB_NOMAGIC 0x800
|
||||
#define GLOB_ALTDIRFUNC 0x1000
|
||||
#define GLOB_ONLYDIR 0x2000
|
||||
#define GLOB_MAGCHAR 0x4000
|
||||
|
||||
#define GLOB_ABORTED 1
|
||||
#define GLOB_NOMATCH 2
|
||||
#define GLOB_NOSPACE 3
|
||||
#define GLOB_NOSYS 4
|
||||
|
||||
struct stat;
|
||||
typedef struct glob_t {
|
||||
size_t gl_pathc;
|
||||
char **gl_pathv;
|
||||
size_t gl_offs;
|
||||
int gl_flags;
|
||||
void (*gl_closedir) (void *);
|
||||
struct dirent *(*gl_readdir) (void *);
|
||||
void *(*gl_opendir) (const char *);
|
||||
int (*gl_lstat) (const char *__restrict, struct stat *__restrict);
|
||||
int (*gl_stat) (const char *__restrict, struct stat *__restrict);
|
||||
} glob_t;
|
||||
|
||||
#ifndef __MLIBC_ABI_ONLY
|
||||
|
||||
int glob(const char *__restrict __pattern, int __flags,
|
||||
int(*__errfunc)(const char *__epath, int __errnum), struct glob_t *__restrict __pglob);
|
||||
void globfree(struct glob_t *__pglog);
|
||||
|
||||
#endif /* !__MLIBC_ABI_ONLY */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _GLOB_H */
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
#ifndef _GRP_H
|
||||
#define _GRP_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <abi-bits/gid_t.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct group {
|
||||
char *gr_name;
|
||||
char *gr_passwd;
|
||||
gid_t gr_gid;
|
||||
char **gr_mem;
|
||||
};
|
||||
|
||||
#ifndef __MLIBC_ABI_ONLY
|
||||
|
||||
void endgrent(void);
|
||||
struct group *getgrent(void);
|
||||
struct group *getgrgid(gid_t __gid);
|
||||
int getgrgid_r(gid_t __gid, struct group *__grp, char *__buf, size_t __buflen, struct group **__res);
|
||||
struct group *getgrnam(const char *__name);
|
||||
int getgrnam_r(const char *__name, struct group *__grp, char *__buf, size_t __buflen, struct group **__res);
|
||||
void setgrent(void);
|
||||
int putgrent(const struct group *__grp, FILE *__stream);
|
||||
struct group *fgetgrent(FILE *__stream);
|
||||
|
||||
int setgroups(size_t __size, const gid_t *__list);
|
||||
int initgroups(const char *__user, gid_t __group);
|
||||
|
||||
/* Non standard extension */
|
||||
int getgrouplist(const char *__user, gid_t __group, gid_t *__groups, int *__ngroups);
|
||||
|
||||
#endif /* !__MLIBC_ABI_ONLY */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _GRP_H */
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
#ifndef _LANGINFO_H
|
||||
#define _LANGINFO_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <bits/posix/locale_t.h>
|
||||
#include <bits/nl_item.h>
|
||||
|
||||
#ifndef __MLIBC_ABI_ONLY
|
||||
|
||||
char *nl_langinfo(nl_item __item);
|
||||
char *nl_langinfo_l(nl_item __item, locale_t __loc);
|
||||
|
||||
#endif /* !__MLIBC_ABI_ONLY */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LANGINFO_H */
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
|
||||
#ifndef _LIBGEN_H
|
||||
#define _LIBGEN_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(basename) && defined(_GNU_SOURCE)
|
||||
/* see: ./options/ansi/include/string.h, search for __mlibc_gnu_basename */
|
||||
# undef basename
|
||||
#endif
|
||||
|
||||
#ifndef __MLIBC_ABI_ONLY
|
||||
|
||||
char *basename(char *__path);
|
||||
#define basename basename
|
||||
char *dirname(char *__path);
|
||||
|
||||
#endif /* !__MLIBC_ABI_ONLY */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LIBGEN_H */
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
#ifndef _MLIBC_LOOKUP
|
||||
#define _MLIBC_LOOKUP
|
||||
|
||||
#include <stdint.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <frg/string.hpp>
|
||||
#include <frg/vector.hpp>
|
||||
#include <frg/span.hpp>
|
||||
#include <frg/array.hpp>
|
||||
#include <mlibc/allocator.hpp>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
struct dns_addr_buf {
|
||||
dns_addr_buf()
|
||||
: name(getAllocator()) {}
|
||||
frg::string<MemoryAllocator> name;
|
||||
int family;
|
||||
uint8_t addr[16];
|
||||
};
|
||||
|
||||
struct lookup_result {
|
||||
lookup_result()
|
||||
: buf(getAllocator()), aliases(getAllocator()) {}
|
||||
frg::vector<struct dns_addr_buf, MemoryAllocator> buf;
|
||||
frg::vector<frg::string<MemoryAllocator>, MemoryAllocator> aliases;
|
||||
};
|
||||
|
||||
struct dns_header {
|
||||
uint16_t identification;
|
||||
uint16_t flags;
|
||||
uint16_t no_q;
|
||||
uint16_t no_ans;
|
||||
uint16_t no_auths;
|
||||
uint16_t no_additional;
|
||||
};
|
||||
|
||||
struct ai_buf {
|
||||
struct addrinfo ai;
|
||||
union sa {
|
||||
struct sockaddr_in sin;
|
||||
struct sockaddr_in6 sin6;
|
||||
} sa;
|
||||
};
|
||||
|
||||
int lookup_name_dns(struct lookup_result &buf, const char *name,
|
||||
frg::string<MemoryAllocator> &canon_name, int family);
|
||||
int lookup_addr_dns(frg::span<char> name, frg::array<uint8_t, 16> &addr, int family);
|
||||
int lookup_name_hosts(struct lookup_result &buf, const char *name,
|
||||
frg::string<MemoryAllocator> &canon_name, int family);
|
||||
int lookup_addr_hosts(frg::span<char> name, frg::array<uint8_t, 16> &addr, int family);
|
||||
int lookup_name_null(struct lookup_result &buf, int flags, int family);
|
||||
int lookup_name_ip(struct lookup_result &buf, const char *name, int family);
|
||||
|
||||
} // namespace mlibc
|
||||
|
||||
#endif // _MLIBC_LOOKUP
|
||||
@@ -0,0 +1,102 @@
|
||||
#ifndef MLIBC_POSIX_FILE_IO_HPP
|
||||
#define MLIBC_POSIX_FILE_IO_HPP
|
||||
|
||||
#include <frg/span.hpp>
|
||||
#include <frg/vector.hpp>
|
||||
#include <mlibc/file-io.hpp>
|
||||
#include <mlibc/allocator.hpp>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
struct mem_file : abstract_file {
|
||||
mem_file(int flags, void (*do_dispose)(abstract_file *) = nullptr) : abstract_file{do_dispose}, _flags{flags} { };
|
||||
|
||||
int reopen(const char *path, const char *mode) override;
|
||||
protected:
|
||||
int determine_type(stream_type *type) override;
|
||||
int determine_bufmode(buffer_mode *mode) override;
|
||||
|
||||
virtual frg::span<char> _buffer() = 0;
|
||||
virtual size_t _buffer_size() const = 0;
|
||||
|
||||
off_t _pos = 0;
|
||||
int _flags = 0;
|
||||
// maintains the size of buffer contents as required by POSIX
|
||||
off_t _max_size = 0;
|
||||
};
|
||||
|
||||
struct memstream_mem_file final : public mem_file {
|
||||
memstream_mem_file(char **ptr, size_t *sizeloc, int flags, void (*do_dispose)(abstract_file *) = nullptr);
|
||||
|
||||
int close() override;
|
||||
|
||||
int io_read(char *buffer, size_t max_size, size_t *actual_size) override;
|
||||
int io_write(const char *buffer, size_t max_size, size_t *actual_size) override;
|
||||
int io_seek(off_t offset, int whence, off_t *new_offset) override;
|
||||
|
||||
frg::span<char> _buffer() override {
|
||||
return {_buf.data(), _buffer_size()};
|
||||
}
|
||||
|
||||
size_t _buffer_size() const override {
|
||||
return _buf.size();
|
||||
}
|
||||
|
||||
private:
|
||||
void _update_ptrs();
|
||||
|
||||
// Where to write back buffer and size on flush and close.
|
||||
char **_bufloc;
|
||||
size_t *_sizeloc;
|
||||
|
||||
frg::vector<char, MemoryAllocator> _buf = {getAllocator()};
|
||||
};
|
||||
|
||||
struct fmemopen_mem_file final : public mem_file {
|
||||
fmemopen_mem_file(void *in_buf, size_t size, int flags, void (*do_dispose)(abstract_file *) = nullptr);
|
||||
|
||||
int close() override;
|
||||
|
||||
int io_read(char *buffer, size_t max_size, size_t *actual_size) override;
|
||||
int io_write(const char *buffer, size_t max_size, size_t *actual_size) override;
|
||||
int io_seek(off_t offset, int whence, off_t *new_offset) override;
|
||||
|
||||
frg::span<char> _buffer() override {
|
||||
return {reinterpret_cast<char *>(_inBuffer), _buffer_size()};
|
||||
}
|
||||
|
||||
size_t _buffer_size() const override {
|
||||
return _inBufferSize;
|
||||
}
|
||||
|
||||
private:
|
||||
void *_inBuffer;
|
||||
size_t _inBufferSize;
|
||||
|
||||
bool _needsDeallocation = false;
|
||||
};
|
||||
|
||||
struct cookie_file : abstract_file {
|
||||
cookie_file(void *cookie, int flags, cookie_io_functions_t funcs, void (*do_dispose)(abstract_file *) = nullptr)
|
||||
: abstract_file{do_dispose}, _cookie{cookie}, _flags{flags}, _funcs{funcs} { }
|
||||
|
||||
int close() override;
|
||||
int reopen(const char *path, const char *mode) override;
|
||||
protected:
|
||||
int determine_type(stream_type *type) override;
|
||||
int determine_bufmode(buffer_mode *mode) override;
|
||||
|
||||
int io_read(char *buffer, size_t max_size, size_t *actual_size) override;
|
||||
int io_write(const char *buffer, size_t max_size, size_t *actual_size) override;
|
||||
int io_seek(off_t offset, int whence, off_t *new_offset) override;
|
||||
|
||||
private:
|
||||
void *_cookie;
|
||||
|
||||
[[maybe_unused]] int _flags;
|
||||
cookie_io_functions_t _funcs;
|
||||
};
|
||||
|
||||
} // namespace mlibc
|
||||
|
||||
#endif // MLIBC_POSIX_FILE_IO_HPP
|
||||
@@ -0,0 +1,263 @@
|
||||
#ifndef MLIBC_POSIX_SYSDEPS
|
||||
#define MLIBC_POSIX_SYSDEPS
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <abi-bits/seek-whence.h>
|
||||
#include <abi-bits/vm-flags.h>
|
||||
#include <bits/off_t.h>
|
||||
#include <bits/ssize_t.h>
|
||||
#include <mlibc/ansi-sysdeps.hpp>
|
||||
#include <mlibc/fsfd_target.hpp>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <abi-bits/pid_t.h>
|
||||
#include <abi-bits/socklen_t.h>
|
||||
#include <bits/posix/stat.h>
|
||||
#include <poll.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/sem.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/times.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sched.h>
|
||||
#include <termios.h>
|
||||
#include <time.h>
|
||||
#include <ucontext.h>
|
||||
|
||||
namespace [[gnu::visibility("hidden")]] mlibc {
|
||||
|
||||
void sys_libc_log(const char *message);
|
||||
[[noreturn]] void sys_libc_panic();
|
||||
|
||||
[[noreturn]] void sys_exit(int status);
|
||||
[[noreturn, gnu::weak]] void sys_thread_exit();
|
||||
|
||||
|
||||
int sys_open(const char *pathname, int flags, mode_t mode, int *fd);
|
||||
[[gnu::weak]] int sys_flock(int fd, int options);
|
||||
|
||||
[[gnu::weak]] int sys_open_dir(const char *path, int *handle);
|
||||
[[gnu::weak]] int sys_read_entries(int handle, void *buffer, size_t max_size,
|
||||
size_t *bytes_read);
|
||||
|
||||
int sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read);
|
||||
[[gnu::weak]] int sys_readv(int fd, const struct iovec *iovs, int iovc, ssize_t *bytes_read);
|
||||
|
||||
int sys_write(int fd, const void *buf, size_t count, ssize_t *bytes_written);
|
||||
[[gnu::weak]] int sys_writev(int fd, const struct iovec *iovs, int iovc, ssize_t *bytes_written);
|
||||
[[gnu::weak]] int sys_pread(int fd, void *buf, size_t n, off_t off, ssize_t *bytes_read);
|
||||
[[gnu::weak]] int sys_pwrite(int fd, const void *buf, size_t n, off_t off, ssize_t *bytes_read);
|
||||
|
||||
int sys_seek(int fd, off_t offset, int whence, off_t *new_offset);
|
||||
int sys_close(int fd);
|
||||
|
||||
[[gnu::weak]] int sys_access(const char *path, int mode);
|
||||
[[gnu::weak]] int sys_faccessat(int dirfd, const char *pathname, int mode, int flags);
|
||||
[[gnu::weak]] int sys_dup(int fd, int flags, int *newfd);
|
||||
[[gnu::weak]] int sys_dup2(int fd, int flags, int newfd);
|
||||
// In contrast to the isatty() library function, the sysdep function uses return value
|
||||
// zero (and not one) to indicate that the file is a terminal.
|
||||
[[gnu::weak]] int sys_isatty(int fd);
|
||||
[[gnu::weak]] int sys_stat(fsfd_target fsfdt, int fd, const char *path, int flags,
|
||||
struct stat *statbuf);
|
||||
[[gnu::weak]] int sys_statvfs(const char *path, struct statvfs *out);
|
||||
[[gnu::weak]] int sys_fstatvfs(int fd, struct statvfs *out);
|
||||
[[gnu::weak]] int sys_readlink(const char *path, void *buffer, size_t max_size, ssize_t *length);
|
||||
[[gnu::weak]] int sys_readlinkat(int dirfd, const char *path, void *buffer, size_t max_size, ssize_t *length);
|
||||
[[gnu::weak]] int sys_rmdir(const char *path);
|
||||
[[gnu::weak]] int sys_ftruncate(int fd, size_t size);
|
||||
[[gnu::weak]] int sys_fallocate(int fd, off_t offset, size_t size);
|
||||
[[gnu::weak]] int sys_unlinkat(int fd, const char *path, int flags);
|
||||
[[gnu::weak]] int sys_openat(int dirfd, const char *path, int flags, mode_t mode, int *fd);
|
||||
[[gnu::weak]] int sys_socket(int family, int type, int protocol, int *fd);
|
||||
[[gnu::weak]] int sys_msg_send(int fd, const struct msghdr *hdr, int flags, ssize_t *length);
|
||||
[[gnu::weak]] ssize_t sys_sendto(int fd, const void *buffer, size_t size, int flags, const struct sockaddr *sock_addr, socklen_t addr_length, ssize_t *length);
|
||||
[[gnu::weak]] int sys_msg_recv(int fd, struct msghdr *hdr, int flags, ssize_t *length);
|
||||
[[gnu::weak]] ssize_t sys_recvfrom(int fd, void *buffer, size_t size, int flags, struct sockaddr *sock_addr, socklen_t *addr_length, ssize_t *length);
|
||||
[[gnu::weak]] int sys_listen(int fd, int backlog);
|
||||
[[gnu::weak]] gid_t sys_getgid();
|
||||
[[gnu::weak]] gid_t sys_getegid();
|
||||
[[gnu::weak]] uid_t sys_getuid();
|
||||
[[gnu::weak]] uid_t sys_geteuid();
|
||||
[[gnu::weak]] pid_t sys_getpid();
|
||||
[[gnu::weak]] pid_t sys_gettid();
|
||||
[[gnu::weak]] pid_t sys_getppid();
|
||||
[[gnu::weak]] int sys_getpgid(pid_t pid, pid_t *pgid);
|
||||
[[gnu::weak]] int sys_getsid(pid_t pid, pid_t *sid);
|
||||
[[gnu::weak]] int sys_setpgid(pid_t pid, pid_t pgid);
|
||||
[[gnu::weak]] int sys_setuid(uid_t uid);
|
||||
[[gnu::weak]] int sys_seteuid(uid_t euid);
|
||||
[[gnu::weak]] int sys_setgid(gid_t gid);
|
||||
[[gnu::weak]] int sys_setegid(gid_t egid);
|
||||
[[gnu::weak]] int sys_getgroups(size_t size, gid_t *list, int *ret);
|
||||
[[gnu::weak]] void sys_yield();
|
||||
[[gnu::weak]] int sys_sleep(time_t *secs, long *nanos);
|
||||
[[gnu::weak]] int sys_fork(pid_t *child);
|
||||
[[gnu::weak]] int sys_execve(const char *path, char *const argv[], char *const envp[]);
|
||||
[[gnu::weak]] int sys_pselect(int num_fds, fd_set *read_set, fd_set *write_set,
|
||||
fd_set *except_set, const struct timespec *timeout, const sigset_t *sigmask, int *num_events);
|
||||
[[gnu::weak]] int sys_getrusage(int scope, struct rusage *usage);
|
||||
[[gnu::weak]] int sys_getrlimit(int resource, struct rlimit *limit);
|
||||
[[gnu::weak]] int sys_setrlimit(int resource, const struct rlimit *limit);
|
||||
[[gnu::weak]] int sys_getpriority(int which, id_t who, int *value);
|
||||
[[gnu::weak]] int sys_setpriority(int which, id_t who, int prio);
|
||||
[[gnu::weak]] int sys_getschedparam(void *tcb, int *policy, struct sched_param *param);
|
||||
[[gnu::weak]] int sys_setschedparam(void *tcb, int policy, const struct sched_param *param);
|
||||
[[gnu::weak]] int sys_getscheduler(pid_t pid, int *policy);
|
||||
[[gnu::weak]] int sys_getparam(pid_t pid, struct sched_param *param);
|
||||
[[gnu::weak]] int sys_setparam(pid_t pid, const struct sched_param *param);
|
||||
[[gnu::weak]] int sys_get_max_priority(int policy, int *out);
|
||||
[[gnu::weak]] int sys_get_min_priority(int policy, int *out);
|
||||
[[gnu::weak]] int sys_getcwd(char *buffer, size_t size);
|
||||
[[gnu::weak]] int sys_chdir(const char *path);
|
||||
[[gnu::weak]] int sys_fchdir(int fd);
|
||||
[[gnu::weak]] int sys_chroot(const char *path);
|
||||
[[gnu::weak]] int sys_mkdir(const char *path, mode_t mode);
|
||||
[[gnu::weak]] int sys_mkdirat(int dirfd, const char *path, mode_t mode);
|
||||
[[gnu::weak]] int sys_link(const char *old_path, const char *new_path);
|
||||
[[gnu::weak]] int sys_linkat(int olddirfd, const char *old_path, int newdirfd, const char *new_path, int flags);
|
||||
[[gnu::weak]] int sys_symlink(const char *target_path, const char *link_path);
|
||||
[[gnu::weak]] int sys_symlinkat(const char *target_path, int dirfd, const char *link_path);
|
||||
[[gnu::weak]] int sys_rename(const char *path, const char *new_path);
|
||||
[[gnu::weak]] int sys_renameat(int olddirfd, const char *old_path, int newdirfd, const char *new_path);
|
||||
[[gnu::weak]] int sys_fcntl(int fd, int request, va_list args, int *result);
|
||||
[[gnu::weak]] int sys_ttyname(int fd, char *buf, size_t size);
|
||||
[[gnu::weak]] int sys_fadvise(int fd, off_t offset, off_t length, int advice);
|
||||
[[gnu::weak]] void sys_sync();
|
||||
[[gnu::weak]] int sys_fsync(int fd);
|
||||
[[gnu::weak]] int sys_fdatasync(int fd);
|
||||
[[gnu::weak]] int sys_chmod(const char *pathname, mode_t mode);
|
||||
[[gnu::weak]] int sys_fchmod(int fd, mode_t mode);
|
||||
[[gnu::weak]] int sys_fchmodat(int fd, const char *pathname, mode_t mode, int flags);
|
||||
[[gnu::weak]] int sys_utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags);
|
||||
[[gnu::weak]] int sys_mlock(const void *addr, size_t length);
|
||||
[[gnu::weak]] int sys_munlock(const void *addr, size_t length);
|
||||
[[gnu::weak]] int sys_mlockall(int flags);
|
||||
[[gnu::weak]] int sys_mlock(const void *addr, size_t len);
|
||||
[[gnu::weak]] int sys_munlockall(void);
|
||||
[[gnu::weak]] int sys_mincore(void *addr, size_t length, unsigned char *vec);
|
||||
|
||||
// mlibc assumes that anonymous memory returned by sys_vm_map() is zeroed by the kernel / whatever is behind the sysdeps
|
||||
int sys_vm_map(void *hint, size_t size, int prot, int flags, int fd, off_t offset, void **window);
|
||||
|
||||
[[gnu::weak]] int sys_vm_remap(void *pointer, size_t size, size_t new_size, void **window);
|
||||
[[gnu::weak]] int sys_vm_protect(void *pointer, size_t size, int prot);
|
||||
|
||||
int sys_vm_unmap(void *pointer, size_t size);
|
||||
|
||||
[[gnu::weak]] int sys_setsid(pid_t *sid);
|
||||
[[gnu::weak]] int sys_tcgetattr(int fd, struct termios *attr);
|
||||
[[gnu::weak]] int sys_tcsetattr(int, int, const struct termios *attr);
|
||||
[[gnu::weak]] int sys_tcflow(int, int);
|
||||
[[gnu::weak]] int sys_tcflush(int fd, int queue);
|
||||
[[gnu::weak]] int sys_tcdrain(int);
|
||||
[[gnu::weak]] int sys_pipe(int *fds, int flags);
|
||||
[[gnu::weak]] int sys_socketpair(int domain, int type_and_flags, int proto, int *fds);
|
||||
[[gnu::weak]] int sys_poll(struct pollfd *fds, nfds_t count, int timeout, int *num_events);
|
||||
[[gnu::weak]] int sys_ioctl(int fd, unsigned long request, void *arg, int *result);
|
||||
[[gnu::weak]] int sys_getsockopt(int fd, int layer, int number,
|
||||
void *__restrict buffer, socklen_t *__restrict size);
|
||||
[[gnu::weak]] int sys_setsockopt(int fd, int layer, int number,
|
||||
const void *buffer, socklen_t size);
|
||||
[[gnu::weak]] int sys_shutdown(int sockfd, int how);
|
||||
[[gnu::weak]] int sys_sigprocmask(int how, const sigset_t *__restrict set,
|
||||
sigset_t *__restrict retrieve);
|
||||
[[gnu::weak]] int sys_thread_sigmask(int how, const sigset_t *__restrict set,
|
||||
sigset_t *__restrict retrieve);
|
||||
[[gnu::weak]] int sys_sigaction(int, const struct sigaction *__restrict,
|
||||
struct sigaction *__restrict);
|
||||
// NOTE: POSIX says that behavior of timeout = nullptr is unspecified. We treat this case
|
||||
// as an infinite timeout, making sigtimedwait(..., nullptr) equivalent to sigwaitinfo(...)
|
||||
[[gnu::weak]] int sys_sigtimedwait(const sigset_t *__restrict set, siginfo_t *__restrict info, const struct timespec *__restrict timeout, int *out_signal);
|
||||
[[gnu::weak]] int sys_kill(int, int);
|
||||
[[gnu::weak]] int sys_accept(int fd, int *newfd, struct sockaddr *addr_ptr, socklen_t *addr_length, int flags);
|
||||
[[gnu::weak]] int sys_bind(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length);
|
||||
[[gnu::weak]] int sys_connect(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length);
|
||||
[[gnu::weak]] int sys_sockname(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length,
|
||||
socklen_t *actual_length);
|
||||
[[gnu::weak]] int sys_peername(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length,
|
||||
socklen_t *actual_length);
|
||||
[[gnu::weak]] int sys_gethostname(char *buffer, size_t bufsize);
|
||||
[[gnu::weak]] int sys_sethostname(const char *buffer, size_t bufsize);
|
||||
[[gnu::weak]] int sys_mkfifoat(int dirfd, const char *path, mode_t mode);
|
||||
[[gnu::weak]] int sys_getentropy(void *buffer, size_t length);
|
||||
[[gnu::weak]] int sys_mknodat(int dirfd, const char *path, int mode, int dev);
|
||||
[[gnu::weak]] int sys_umask(mode_t mode, mode_t *old);
|
||||
|
||||
[[gnu::weak]] int sys_before_cancellable_syscall(ucontext_t *uctx);
|
||||
[[gnu::weak]] int sys_tgkill(int tgid, int tid, int sig);
|
||||
|
||||
[[gnu::weak]] int sys_fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group, int flags);
|
||||
[[gnu::weak]] int sys_sigaltstack(const stack_t *ss, stack_t *oss);
|
||||
[[gnu::weak]] int sys_sigsuspend(const sigset_t *set);
|
||||
[[gnu::weak]] int sys_sigpending(sigset_t *set);
|
||||
[[gnu::weak]] int sys_setgroups(size_t size, const gid_t *list);
|
||||
[[gnu::weak]] int sys_memfd_create(const char *name, int flags, int *fd);
|
||||
[[gnu::weak]] int sys_madvise(void *addr, size_t length, int advice);
|
||||
[[gnu::weak]] int sys_posix_madvise(void *addr, size_t length, int advice);
|
||||
[[gnu::weak]] int sys_msync(void *addr, size_t length, int flags);
|
||||
|
||||
[[gnu::weak]] int sys_getitimer(int which, struct itimerval *curr_value);
|
||||
[[gnu::weak]] int sys_setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);
|
||||
[[gnu::weak]] int sys_timer_create(clockid_t clk, struct sigevent *__restrict evp, timer_t *__restrict res);
|
||||
[[gnu::weak]] int sys_timer_settime(timer_t t, int flags, const struct itimerspec *__restrict val, struct itimerspec *__restrict old);
|
||||
[[gnu::weak]] int sys_timer_gettime(timer_t t, struct itimerspec *val);
|
||||
[[gnu::weak]] int sys_timer_delete(timer_t t);
|
||||
[[gnu::weak]] int sys_times(struct tms *tms, clock_t *out);
|
||||
[[gnu::weak]] int sys_uname(struct utsname *buf);
|
||||
[[gnu::weak]] int sys_pause();
|
||||
|
||||
[[gnu::weak]] int sys_setresuid(uid_t ruid, uid_t euid, uid_t suid);
|
||||
[[gnu::weak]] int sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid);
|
||||
[[gnu::weak]] int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
|
||||
[[gnu::weak]] int sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid);
|
||||
[[gnu::weak]] int sys_setreuid(uid_t ruid, uid_t euid);
|
||||
[[gnu::weak]] int sys_setregid(gid_t rgid, gid_t egid);
|
||||
|
||||
[[gnu::weak]] int sys_if_indextoname(unsigned int index, char *name);
|
||||
[[gnu::weak]] int sys_if_nametoindex(const char *name, unsigned int *ret);
|
||||
|
||||
[[gnu::weak]] int sys_ptsname(int fd, char *buffer, size_t length);
|
||||
[[gnu::weak]] int sys_unlockpt(int fd);
|
||||
|
||||
[[gnu::weak]] int sys_thread_setname(void *tcb, const char *name);
|
||||
[[gnu::weak]] int sys_thread_getname(void *tcb, char *name, size_t size);
|
||||
|
||||
[[gnu::weak]] int sys_sysconf(int num, long *ret);
|
||||
|
||||
[[gnu::weak]] int sys_semget(key_t key, int n, int fl, int *id);
|
||||
[[gnu::weak]] int sys_semctl(int semid, int semnum, int cmd, void *semun, int *ret);
|
||||
|
||||
[[gnu::weak]] int sys_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);
|
||||
[[gnu::weak]] int sys_getthreadaffinity(pid_t tid, size_t cpusetsize, cpu_set_t *mask);
|
||||
|
||||
[[gnu::weak]] int sys_setaffinity(pid_t pid, size_t cpusetsize, const cpu_set_t *mask);
|
||||
[[gnu::weak]] int sys_setthreadaffinity(pid_t tid, size_t cpusetsize, const cpu_set_t *mask);
|
||||
|
||||
[[gnu::weak]] int sys_waitid(idtype_t idtype, id_t id, siginfo_t *info, int options);
|
||||
|
||||
[[gnu::weak]] int sys_name_to_handle_at(int dirfd, const char *pathname, struct file_handle *handle, int *mount_id, int flags);
|
||||
[[gnu::weak]] int sys_splice(int in_fd, off_t *in_off, int out_fd, off_t *out_off, size_t size, unsigned int flags, ssize_t *out);
|
||||
|
||||
[[gnu::weak]] int sys_shmat(void **seg_start, int shmid, const void *shmaddr, int shmflg);
|
||||
[[gnu::weak]] int sys_shmctl(int *idx, int shmid, int cmd, struct shmid_ds *buf);
|
||||
[[gnu::weak]] int sys_shmdt(const void *shmaddr);
|
||||
[[gnu::weak]] int sys_shmget(int *shm_id, key_t key, size_t size, int shmflg);
|
||||
|
||||
[[gnu::weak]] int sys_inet_configured(bool *ipv4, bool *ipv6);
|
||||
|
||||
[[gnu::weak]] int sys_nice(int nice, int *new_nice);
|
||||
|
||||
[[gnu::weak]] int sys_openpt(int oflags, int *fd);
|
||||
|
||||
} //namespace mlibc
|
||||
|
||||
#endif // MLIBC_POSIX_SYSDEPS
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef _MLIBC_RESOLV_CONF
|
||||
#define _MLIBC_RESOLV_CONF
|
||||
|
||||
#include <frg/string.hpp>
|
||||
#include <frg/optional.hpp>
|
||||
#include <mlibc/allocator.hpp>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
struct nameserver_data {
|
||||
nameserver_data()
|
||||
: name(getAllocator()) {}
|
||||
frg::string<MemoryAllocator> name;
|
||||
// for in the future we can also store options here
|
||||
};
|
||||
|
||||
frg::optional<struct nameserver_data> get_nameserver();
|
||||
|
||||
} // namespace mlibc
|
||||
|
||||
#endif // _MLIBC_RESOLV_CONF
|
||||
@@ -0,0 +1,33 @@
|
||||
#ifndef _MLIBC_SERVICES
|
||||
#define _MLIBC_SERVICES
|
||||
|
||||
#include <frg/small_vector.hpp>
|
||||
#include <frg/vector.hpp>
|
||||
#include <frg/string.hpp>
|
||||
#include <mlibc/allocator.hpp>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
// Only two services for tcp and udp
|
||||
#define SERV_MAX 2
|
||||
|
||||
struct service_buf {
|
||||
service_buf()
|
||||
: name(getAllocator()), aliases(getAllocator())
|
||||
{ }
|
||||
int port, protocol, socktype;
|
||||
frg::string<MemoryAllocator> name;
|
||||
frg::vector<frg::string<MemoryAllocator>, MemoryAllocator> aliases;
|
||||
};
|
||||
|
||||
using service_result = frg::small_vector<service_buf, SERV_MAX, MemoryAllocator>;
|
||||
|
||||
int lookup_serv_by_name(service_result &buf, const char *name, int proto,
|
||||
int socktype, int flags);
|
||||
|
||||
int lookup_serv_by_port(service_result &buf, int proto, int port);
|
||||
|
||||
|
||||
} // namespace mlibc
|
||||
|
||||
#endif // _MLIBC_SERVICES
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef _MQUEUE_H
|
||||
#define _MQUEUE_H
|
||||
|
||||
#include <abi-bits/mqueue.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef int mqd_t;
|
||||
|
||||
#ifndef __MLIBC_ABI_ONLY
|
||||
|
||||
int mq_getattr(mqd_t __mqdes, struct mq_attr *__attr);
|
||||
int mq_setattr(mqd_t __mqdes, const struct mq_attr *__restrict__ __newattr, struct mq_attr *__restrict__ __oldattr);
|
||||
int mq_unlink(const char *__name);
|
||||
mqd_t mq_open(const char *__name, int __flags, ...);
|
||||
|
||||
#endif /* !__MLIBC_ABI_ONLY */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _MQUEUE_H */
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
|
||||
#ifndef _NET_IF_H
|
||||
#define _NET_IF_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <mlibc-config.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#define IF_NAMESIZE 16
|
||||
#define IFNAMSIZ IF_NAMESIZE
|
||||
#define ALTIFNAMSIZ 128
|
||||
#define IFALIASZ 256
|
||||
|
||||
struct if_nameindex {
|
||||
unsigned int if_index;
|
||||
char *if_name;
|
||||
};
|
||||
|
||||
struct ifmap {
|
||||
unsigned long mem_start;
|
||||
unsigned long mem_end;
|
||||
unsigned short base_addr;
|
||||
unsigned char irq;
|
||||
unsigned char dma;
|
||||
unsigned char port;
|
||||
};
|
||||
|
||||
struct ifreq {
|
||||
union {
|
||||
char ifrn_name[IFNAMSIZ];
|
||||
} ifr_ifrn;
|
||||
|
||||
union {
|
||||
struct sockaddr ifru_addr;
|
||||
struct sockaddr ifru_dstaddr;
|
||||
struct sockaddr ifru_broadaddr;
|
||||
struct sockaddr ifru_netmask;
|
||||
struct sockaddr ifru_hwaddr;
|
||||
short int ifru_flags;
|
||||
int ifru_ivalue;
|
||||
int ifru_mtu;
|
||||
struct ifmap ifru_map;
|
||||
char ifru_slave[IFNAMSIZ];
|
||||
char ifru_newname[IFNAMSIZ];
|
||||
char *ifru_data;
|
||||
} ifr_ifru;
|
||||
};
|
||||
|
||||
#define ifr_name ifr_ifrn.ifrn_name
|
||||
#define ifr_hwaddr ifr_ifru.ifru_hwaddr
|
||||
#define ifr_addr ifr_ifru.ifru_addr
|
||||
#define ifr_dstaddr ifr_ifru.ifru_dstaddr
|
||||
#define ifr_broadaddr ifr_ifru.ifru_broadaddr
|
||||
#define ifr_netmask ifr_ifru.ifru_netmask
|
||||
#define ifr_flags ifr_ifru.ifru_flags
|
||||
#define ifr_metric ifr_ifru.ifru_ivalue
|
||||
#define ifr_mtu ifr_ifru.ifru_mtu
|
||||
#define ifr_map ifr_ifru.ifru_map
|
||||
#define ifr_slave ifr_ifru.ifru_slave
|
||||
#define ifr_data ifr_ifru.ifru_data
|
||||
#define ifr_ifindex ifr_ifru.ifru_ivalue
|
||||
#define ifr_bandwidth ifr_ifru.ifru_ivalue
|
||||
#define ifr_qlen ifr_ifru.ifru_ivalue
|
||||
#define ifr_newname ifr_ifru.ifru_newname
|
||||
|
||||
struct ifconf {
|
||||
int ifc_len;
|
||||
union {
|
||||
char *ifcu_buf;
|
||||
struct ifreq *ifcu_req;
|
||||
} ifc_ifcu;
|
||||
};
|
||||
|
||||
#define ifc_buf ifc_ifcu.ifcu_buf
|
||||
#define ifc_req ifc_ifcu.ifcu_req
|
||||
|
||||
#ifndef __MLIBC_ABI_ONLY
|
||||
|
||||
void if_freenameindex(struct if_nameindex *__index);
|
||||
char *if_indextoname(unsigned int __index, char *__name);
|
||||
struct if_nameindex *if_nameindex(void);
|
||||
unsigned int if_nametoindex(const char *__name);
|
||||
|
||||
#endif /* !__MLIBC_ABI_ONLY */
|
||||
|
||||
#define IFHWADDRLEN 6
|
||||
|
||||
#define IFF_UP 0x1
|
||||
#define IFF_BROADCAST 0x2
|
||||
#define IFF_DEBUG 0x4
|
||||
#define IFF_LOOPBACK 0x8
|
||||
#define IFF_POINTOPOINT 0x10
|
||||
#define IFF_NOTRAILERS 0x20
|
||||
#define IFF_RUNNING 0x40
|
||||
#define IFF_NOARP 0x80
|
||||
#define IFF_PROMISC 0x100
|
||||
#define IFF_ALLMULTI 0x200
|
||||
#define IFF_MASTER 0x400
|
||||
#define IFF_SLAVE 0x800
|
||||
#define IFF_MULTICAST 0x1000
|
||||
#define IFF_PORTSEL 0x2000
|
||||
#define IFF_AUTOMEDIA 0x4000
|
||||
#define IFF_DYNAMIC 0x8000
|
||||
#define IFF_LOWER_UP 0x10000
|
||||
#define IFF_DORMANT 0x20000
|
||||
#define IFF_ECHO 0x40000
|
||||
|
||||
#if __MLIBC_LINUX_OPTION
|
||||
|
||||
#define __UAPI_DEF_IF_IFCONF 0
|
||||
#define __UAPI_DEF_IF_IFMAP 0
|
||||
#define __UAPI_DEF_IF_IFNAMSIZ 0
|
||||
#define __UAPI_DEF_IF_IFREQ 0
|
||||
#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 0
|
||||
#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 0
|
||||
|
||||
#endif /* __MLIBC_LINUX_OPTION */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _NET_IF_H */
|
||||
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
#ifndef _NET_IF_ARP_H
|
||||
#define _NET_IF_ARP_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define MAX_ADDR_LEN 7
|
||||
|
||||
#define ARPOP_REQUEST 1
|
||||
#define ARPOP_REPLY 2
|
||||
#define ARPOP_RREQUEST 3
|
||||
#define ARPOP_RREPLY 4
|
||||
#define ARPOP_InREQUEST 8
|
||||
#define ARPOP_InREPLY 9
|
||||
#define ARPOP_NAK 10
|
||||
|
||||
#define ARPHRD_NETROM 0
|
||||
#define ARPHRD_ETHER 1
|
||||
#define ARPHRD_EETHER 2
|
||||
#define ARPHRD_AX25 3
|
||||
#define ARPHRD_PRONET 4
|
||||
#define ARPHRD_CHAOS 5
|
||||
#define ARPHRD_IEEE802 6
|
||||
#define ARPHRD_ARCNET 7
|
||||
#define ARPHRD_APPLETLK 8
|
||||
#define ARPHRD_DLCI 15
|
||||
#define ARPHRD_ATM 19
|
||||
#define ARPHRD_METRICOM 23
|
||||
#define ARPHRD_IEEE1394 24
|
||||
#define ARPHRD_EUI64 27
|
||||
#define ARPHRD_INFINIBAND 32
|
||||
#define ARPHRD_SLIP 256
|
||||
#define ARPHRD_CSLIP 257
|
||||
#define ARPHRD_SLIP6 258
|
||||
#define ARPHRD_CSLIP6 259
|
||||
#define ARPHRD_RSRVD 260
|
||||
#define ARPHRD_ADAPT 264
|
||||
#define ARPHRD_ROSE 270
|
||||
#define ARPHRD_X25 271
|
||||
#define ARPHRD_HWX25 272
|
||||
#define ARPHRD_CAN 280
|
||||
#define ARPHRD_PPP 512
|
||||
#define ARPHRD_CISCO 513
|
||||
#define ARPHRD_HDLC ARPHRD_CISCO
|
||||
#define ARPHRD_LAPB 516
|
||||
#define ARPHRD_DDCMP 517
|
||||
#define ARPHRD_RAWHDLC 518
|
||||
#define ARPHRD_RAWIP 519
|
||||
|
||||
#define ARPHRD_TUNNEL 768
|
||||
#define ARPHRD_TUNNEL6 769
|
||||
#define ARPHRD_FRAD 770
|
||||
#define ARPHRD_SKIP 771
|
||||
#define ARPHRD_LOOPBACK 772
|
||||
#define ARPHRD_LOCALTLK 773
|
||||
#define ARPHRD_FDDI 774
|
||||
#define ARPHRD_BIF 775
|
||||
#define ARPHRD_SIT 776
|
||||
#define ARPHRD_IPDDP 777
|
||||
#define ARPHRD_IPGRE 778
|
||||
#define ARPHRD_PIMREG 779
|
||||
#define ARPHRD_HIPPI 780
|
||||
#define ARPHRD_ASH 781
|
||||
#define ARPHRD_ECONET 782
|
||||
#define ARPHRD_IRDA 783
|
||||
#define ARPHRD_FCPP 784
|
||||
#define ARPHRD_FCAL 785
|
||||
#define ARPHRD_FCPL 786
|
||||
#define ARPHRD_FCFABRIC 787
|
||||
#define ARPHRD_IEEE802_TR 800
|
||||
#define ARPHRD_IEEE80211 801
|
||||
#define ARPHRD_IEEE80211_PRISM 802
|
||||
#define ARPHRD_IEEE80211_RADIOTAP 803
|
||||
#define ARPHRD_IEEE802154 804
|
||||
#define ARPHRD_IEEE802154_MONITOR 805
|
||||
#define ARPHRD_PHONET 820
|
||||
#define ARPHRD_PHONET_PIPE 821
|
||||
#define ARPHRD_CAIF 822
|
||||
#define ARPHRD_IP6GRE 823
|
||||
#define ARPHRD_NETLINK 824
|
||||
#define ARPHRD_6LOWPAN 825
|
||||
#define ARPHRD_VSOCKMON 826
|
||||
|
||||
#define ARPHRD_VOID 0xFFFF
|
||||
#define ARPHRD_NONE 0xFFFE
|
||||
|
||||
struct arphdr {
|
||||
uint16_t ar_hrd;
|
||||
uint16_t ar_pro;
|
||||
uint8_t ar_hln;
|
||||
uint8_t ar_pln;
|
||||
uint16_t ar_op;
|
||||
};
|
||||
|
||||
struct arpreq {
|
||||
struct sockaddr arp_pa;
|
||||
struct sockaddr arp_ha;
|
||||
int arp_flags;
|
||||
struct sockaddr arp_netmask;
|
||||
char arp_dev[16];
|
||||
};
|
||||
|
||||
#endif /* _NET_IF_ARP_H */
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
#ifndef _NETDB_H
|
||||
#define _NETDB_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <bits/size_t.h>
|
||||
#include <bits/posix/in_port_t.h>
|
||||
#include <bits/posix/in_addr_t.h>
|
||||
#include <abi-bits/socklen_t.h>
|
||||
|
||||
#define AI_PASSIVE 0x01
|
||||
#define AI_CANONNAME 0x02
|
||||
#define AI_NUMERICHOST 0x04
|
||||
#define AI_V4MAPPED 0x08
|
||||
#define AI_ALL 0x10
|
||||
#define AI_ADDRCONFIG 0x20
|
||||
#define AI_NUMERICSERV 0x40
|
||||
|
||||
#define NI_NOFQDN 0x01
|
||||
#define NI_NUMERICHOST 0x02
|
||||
#define NI_NAMEREQD 0x04
|
||||
#define NI_NUMERICSCOPE 0x08
|
||||
#define NI_DGRAM 0x10
|
||||
|
||||
#define NI_NUMERICSERV 2
|
||||
#define NI_MAXSERV 32
|
||||
#define NI_IDN 32
|
||||
#define NI_IDN_USE_STD3_ASCII_RULES 128
|
||||
|
||||
#define NI_MAXHOST 1025
|
||||
|
||||
#define EAI_AGAIN 1
|
||||
#define EAI_BADFLAGS 2
|
||||
#define EAI_FAIL 3
|
||||
#define EAI_FAMILY 4
|
||||
#define EAI_MEMORY 5
|
||||
#define EAI_NONAME 6
|
||||
#define EAI_SERVICE 7
|
||||
#define EAI_SOCKTYPE 8
|
||||
#define EAI_SYSTEM 9
|
||||
#define EAI_OVERFLOW 10
|
||||
#define EAI_NODATA 11
|
||||
#define EAI_ADDRFAMILY 12
|
||||
|
||||
#define HOST_NOT_FOUND 1
|
||||
#define TRY_AGAIN 2
|
||||
#define NO_RECOVERY 3
|
||||
#define NO_DATA 4
|
||||
#define NO_ADDRESS NO_DATA
|
||||
|
||||
#define IPPORT_RESERVED 1024
|
||||
|
||||
#define _PATH_SERVICES "/etc/services"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef __MLIBC_ABI_ONLY
|
||||
|
||||
int *__h_errno_location(void);
|
||||
#define h_errno (*__h_errno_location())
|
||||
|
||||
#endif /* !__MLIBC_ABI_ONLY */
|
||||
|
||||
struct hostent {
|
||||
char *h_name;
|
||||
char **h_aliases;
|
||||
int h_addrtype;
|
||||
int h_length;
|
||||
char **h_addr_list;
|
||||
};
|
||||
|
||||
#define h_addr h_addr_list[0] /* Required by some programs */
|
||||
|
||||
struct netent {
|
||||
char *n_name;
|
||||
char **n_aliases;
|
||||
int n_addrtype;
|
||||
uint32_t n_net;
|
||||
};
|
||||
|
||||
struct protoent {
|
||||
char *p_name;
|
||||
char **p_aliases;
|
||||
int p_proto;
|
||||
};
|
||||
|
||||
struct servent {
|
||||
char *s_name;
|
||||
char **s_aliases;
|
||||
int s_port;
|
||||
char *s_proto;
|
||||
};
|
||||
|
||||
struct addrinfo {
|
||||
int ai_flags;
|
||||
int ai_family;
|
||||
int ai_socktype;
|
||||
int ai_protocol;
|
||||
socklen_t ai_addrlen;
|
||||
struct sockaddr *ai_addr;
|
||||
char *ai_canonname;
|
||||
struct addrinfo *ai_next;
|
||||
};
|
||||
|
||||
#ifndef __MLIBC_ABI_ONLY
|
||||
|
||||
void endhostent(void);
|
||||
void endnetent(void);
|
||||
void endprotoent(void);
|
||||
void endservent(void);
|
||||
void freeaddrinfo(struct addrinfo *__info);
|
||||
const char *gai_strerror(int __errnum);
|
||||
int getaddrinfo(const char *__restrict __node, const char *__restrict __service,
|
||||
const struct addrinfo *__restrict __hints, struct addrinfo **__restrict __res);
|
||||
struct hostent *gethostent(void);
|
||||
struct hostent *gethostbyname(const char *__name);
|
||||
struct hostent *gethostbyname2(const char *__name, int __flags);
|
||||
struct hostent *gethostbyaddr(const void *__addr, socklen_t __len, int __type);
|
||||
int gethostbyaddr_r(const void *__restrict __addr, socklen_t __len, int __type, struct hostent *__restrict __ret,
|
||||
char *__restrict __buf, size_t __buflen, struct hostent **__restrict __res, int *__restrict __h_errnump);
|
||||
int gethostbyname_r(const char *__restrict __name, struct hostent *__restrict __ret, char *__restrict __buf, size_t __buflen,
|
||||
struct hostent **__restrict __res, int *__restrict __h_errnump);
|
||||
int getnameinfo(const struct sockaddr *__restrict __addr, socklen_t __addrlen,
|
||||
char *__restrict __host, socklen_t __hostlen, char *__restrict __serv, socklen_t __servlen, int __flags);
|
||||
struct netent *getnetbyaddr(uint32_t __net, int __type);
|
||||
struct netent *getnetbyname(const char *__name);
|
||||
struct netent *getnetent(void);
|
||||
struct protoent *getprotobyname(const char *__name);
|
||||
struct protoent *getprotobynumber(int __proto);
|
||||
struct protoent *getprotoent(void);
|
||||
struct servent *getservbyname(const char *__name, const char *__proto);
|
||||
struct servent *getservbyport(int __port, const char *__proto);
|
||||
struct servent *getservent(void);
|
||||
void sethostent(int __stayopen);
|
||||
void setnetent(int __stayopen);
|
||||
void setprotoent(int __stayopen);
|
||||
void setservent(int __stayopen);
|
||||
|
||||
/* Deprecated GNU extension */
|
||||
const char *hstrerror(int __err);
|
||||
|
||||
#endif /* !__MLIBC_ABI_ONLY */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _NETDB_H */
|
||||
@@ -0,0 +1,209 @@
|
||||
#ifndef _NETINET_ICMP6_H
|
||||
#define _NETINET_ICMP6_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <abi-bits/in.h>
|
||||
#include <mlibc-config.h>
|
||||
|
||||
#if __MLIBC_GLIBC_OPTION
|
||||
#include <bits/glibc/glibc_icmp6.h>
|
||||
#endif /* __MLIBC_GLIBC_OPTION */
|
||||
|
||||
#define ICMP6_FILTER 1
|
||||
|
||||
#define ICMP6_DST_UNREACH 1
|
||||
#define ICMP6_PACKET_TOO_BIG 2
|
||||
#define ICMP6_TIME_EXCEEDED 3
|
||||
#define ICMP6_PARAM_PROB 4
|
||||
|
||||
#define ICMP6_FILTER_BLOCK 1
|
||||
#define ICMP6_FILTER_PASS 2
|
||||
#define ICMP6_FILTER_BLOCKOTHERS 3
|
||||
#define ICMP6_FILTER_PASSONLY 4
|
||||
#define ICMP6_ECHO_REQUEST 128
|
||||
#define ICMP6_ECHO_REPLY 129
|
||||
|
||||
#define MLD_LISTENER_QUERY 130
|
||||
#define MLD_LISTENER_REPORT 131
|
||||
#define MLD_LISTENER_REDUCTION 132
|
||||
|
||||
#define ICMP6_DST_UNREACH_NOROUTE 0
|
||||
#define ICMP6_DST_UNREACH_ADMIN 1
|
||||
#define ICMP6_DST_UNREACH_BEYONDSCOPE 2
|
||||
#define ICMP6_DST_UNREACH_ADDR 3
|
||||
#define ICMP6_DST_UNREACH_NOPORT 4
|
||||
|
||||
#define ICMP6_TIME_EXCEED_TRANSIT 0
|
||||
#define ICMP6_TIME_EXCEED_REASSEMBLY 1
|
||||
|
||||
#define ICMP6_PARAMPROB_HEADER 0
|
||||
#define ICMP6_PARAMPROB_NEXTHEADER 1
|
||||
#define ICMP6_PARAMPROB_OPTION 2
|
||||
|
||||
struct icmp6_filter {
|
||||
uint32_t icmp6_filt[8];
|
||||
};
|
||||
|
||||
struct icmp6_hdr {
|
||||
uint8_t icmp6_type;
|
||||
uint8_t icmp6_code;
|
||||
uint16_t icmp6_cksum;
|
||||
union {
|
||||
uint32_t icmp6_un_data32[1];
|
||||
uint16_t icmp6_un_data16[2];
|
||||
uint8_t icmp6_un_data8[4];
|
||||
} icmp6_dataun;
|
||||
};
|
||||
|
||||
#define icmp6_data32 icmp6_dataun.icmp6_un_data32
|
||||
#define icmp6_data16 icmp6_dataun.icmp6_un_data16
|
||||
#define icmp6_data8 icmp6_dataun.icmp6_un_data8
|
||||
|
||||
#define icmp6_pptr icmp6_data32[0]
|
||||
#define icmp6_mtu icmp6_data32[0]
|
||||
#define icmp6_id icmp6_data16[0]
|
||||
#define icmp6_seq icmp6_data16[1]
|
||||
#define icmp6_maxdelay icmp6_data16[0]
|
||||
|
||||
#define ICMP6_FILTER_WILLPASS(type, filterp) \
|
||||
((((filterp)->icmp6_filt[(type) >> 5]) & (1U << ((type) & 31))) == 0)
|
||||
|
||||
#define ICMP6_FILTER_WILLBLOCK(type, filterp) \
|
||||
((((filterp)->icmp6_filt[(type) >> 5]) & (1U << ((type) & 31))) != 0)
|
||||
|
||||
#define ICMP6_FILTER_SETPASS(type, filterp) \
|
||||
((((filterp)->icmp6_filt[(type) >> 5]) &= ~(1U << ((type) & 31))))
|
||||
|
||||
#define ICMP6_FILTER_SETBLOCK(type, filterp) \
|
||||
((((filterp)->icmp6_filt[(type) >> 5]) |= (1U << ((type) & 31))))
|
||||
|
||||
#define ICMP6_FILTER_SETPASSALL(filterp) \
|
||||
memset (filterp, 0, sizeof (struct icmp6_filter));
|
||||
|
||||
#define ICMP6_FILTER_SETBLOCKALL(filterp) \
|
||||
memset (filterp, 0xFF, sizeof (struct icmp6_filter));
|
||||
|
||||
#define ND_ROUTER_SOLICIT 133
|
||||
#define ND_ROUTER_ADVERT 134
|
||||
#define ND_NEIGHBOR_SOLICIT 135
|
||||
#define ND_NEIGHBOR_ADVERT 136
|
||||
#define ND_REDIRECT 137
|
||||
|
||||
struct nd_router_solicit {
|
||||
struct icmp6_hdr nd_rs_hdr;
|
||||
};
|
||||
|
||||
#define nd_rs_type nd_rs_hdr.icmp6_type
|
||||
#define nd_rs_code nd_rs_hdr.icmp6_code
|
||||
#define nd_rs_cksum nd_rs_hdr.icmp6_cksum
|
||||
#define nd_rs_reserved nd_rs_hdr.icmp6_data32[0]
|
||||
|
||||
struct nd_router_advert {
|
||||
struct icmp6_hdr nd_ra_hdr;
|
||||
uint32_t nd_ra_reachable;
|
||||
uint32_t nd_ra_retransmit;
|
||||
};
|
||||
|
||||
struct nd_opt_hdr {
|
||||
uint8_t nd_opt_type;
|
||||
uint8_t nd_opt_len;
|
||||
};
|
||||
|
||||
#define ND_OPT_SOURCE_LINKADDR 1
|
||||
#define ND_OPT_TARGET_LINKADDR 2
|
||||
#define ND_OPT_PREFIX_INFORMATION 3
|
||||
#define ND_OPT_REDIRECTED_HEADER 4
|
||||
#define ND_OPT_MTU 5
|
||||
#define ND_OPT_RTR_ADV_INTERVAL 7
|
||||
#define ND_OPT_HOME_AGENT_INFO 8
|
||||
|
||||
struct nd_opt_prefix_info {
|
||||
uint8_t nd_opt_pi_type;
|
||||
uint8_t nd_opt_pi_len;
|
||||
uint8_t nd_opt_pi_prefix_len;
|
||||
uint8_t nd_opt_pi_flags_reserved;
|
||||
uint32_t nd_opt_pi_valid_time;
|
||||
uint32_t nd_opt_pi_preferred_time;
|
||||
uint32_t nd_opt_pi_reserved2;
|
||||
struct in6_addr nd_opt_pi_prefix;
|
||||
};
|
||||
|
||||
#define ND_OPT_PI_FLAG_RADDR 0x20
|
||||
#define ND_OPT_PI_FLAG_AUTO 0x40
|
||||
#define ND_OPT_PI_FLAG_ONLINK 0x80
|
||||
|
||||
#define nd_ra_type nd_ra_hdr.icmp6_type
|
||||
#define nd_ra_code nd_ra_hdr.icmp6_code
|
||||
#define nd_ra_cksum nd_ra_hdr.icmp6_cksum
|
||||
#define nd_ra_curhoplimit nd_ra_hdr.icmp6_data8[0]
|
||||
#define nd_ra_flags_reserved nd_ra_hdr.icmp6_data8[1]
|
||||
#define nd_ra_router_lifetime nd_ra_hdr.icmp6_data16[1]
|
||||
|
||||
#define ND_RA_FLAG_HOME_AGENT 0x20
|
||||
#define ND_RA_FLAG_OTHER 0x40
|
||||
#define ND_RA_FLAG_MANAGED 0x80
|
||||
|
||||
struct nd_opt_rd_hdr {
|
||||
uint8_t nd_opt_rh_type;
|
||||
uint8_t nd_opt_rh_len;
|
||||
uint16_t nd_opt_rh_reserved1;
|
||||
uint32_t nd_opt_rh_reserved2;
|
||||
};
|
||||
|
||||
struct nd_opt_mtu {
|
||||
uint8_t nd_opt_mtu_type;
|
||||
uint8_t nd_opt_mtu_len;
|
||||
uint16_t nd_opt_mtu_reserved;
|
||||
uint32_t nd_opt_mtu_mtu;
|
||||
};
|
||||
|
||||
struct nd_neighbor_solicit {
|
||||
struct icmp6_hdr nd_ns_hdr;
|
||||
struct in6_addr nd_ns_target;
|
||||
};
|
||||
|
||||
#define nd_ns_type nd_ns_hdr.icmp6_type
|
||||
#define nd_ns_code nd_ns_hdr.icmp6_code
|
||||
#define nd_ns_cksum nd_ns_hdr.icmp6_cksum
|
||||
|
||||
struct nd_neighbor_advert {
|
||||
struct icmp6_hdr nd_na_hdr;
|
||||
struct in6_addr nd_na_target;
|
||||
};
|
||||
#define nd_na_type nd_na_hdr.icmp6_type
|
||||
#define nd_na_code nd_na_hdr.icmp6_code
|
||||
#define nd_na_cksum nd_na_hdr.icmp6_cksum
|
||||
#define nd_na_flags_reserved nd_na_hdr.icmp6_data32[0]
|
||||
|
||||
struct nd_redirect {
|
||||
struct icmp6_hdr nd_rd_hdr;
|
||||
struct in6_addr nd_rd_target;
|
||||
struct in6_addr nd_rd_dst;
|
||||
};
|
||||
|
||||
#define nd_rd_type nd_rd_hdr.icmp6_type
|
||||
#define nd_rd_code nd_rd_hdr.icmp6_code
|
||||
#define nd_rd_cksum nd_rd_hdr.icmp6_cksum
|
||||
|
||||
#define ND_NA_FLAG_OVERRIDE 0x00000020
|
||||
#define ND_NA_FLAG_SOLICITED 0x00000040
|
||||
#define ND_NA_FLAG_ROUTER 0x00000080
|
||||
|
||||
struct nd_opt_home_agent_info {
|
||||
uint8_t nd_opt_home_agent_info_type;
|
||||
uint8_t nd_opt_home_agent_info_len;
|
||||
uint16_t nd_opt_home_agent_info_reserved;
|
||||
uint16_t nd_opt_home_agent_info_preference;
|
||||
uint16_t nd_opt_home_agent_info_lifetime;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _NETINET_ICMP6_H */
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
#ifndef _NETINET_IF_ETHER_H
|
||||
#define _NETINET_IF_ETHER_H
|
||||
|
||||
#include <net/if_arp.h>
|
||||
|
||||
#define ETH_ALEN 6
|
||||
#define ETH_HLEN 14
|
||||
#define ETH_ZLEN 60
|
||||
#define ETH_FRAME_LEN 1514
|
||||
#define ETH_FCS_LEN 4
|
||||
|
||||
#define ETH_P_LOOP 0x0060
|
||||
#define ETH_P_PUP 0x0200
|
||||
#define ETH_P_PUPAT 0x0201
|
||||
#define ETH_P_IP 0x0800
|
||||
#define ETH_P_X25 0x0805
|
||||
#define ETH_P_ARP 0x0806
|
||||
#define ETH_P_BPQ 0x08FF
|
||||
#define ETH_P_IEEEPUP 0x0a00
|
||||
#define ETH_P_IEEEPUPAT 0x0a01
|
||||
#define ETH_P_BATMAN 0x4305
|
||||
#define ETH_P_DEC 0x6000
|
||||
#define ETH_P_DNA_DL 0x6001
|
||||
#define ETH_P_DNA_RC 0x6002
|
||||
#define ETH_P_DNA_RT 0x6003
|
||||
#define ETH_P_LAT 0x6004
|
||||
#define ETH_P_DIAG 0x6005
|
||||
#define ETH_P_CUST 0x6006
|
||||
#define ETH_P_SCA 0x6007
|
||||
#define ETH_P_TEB 0x6558
|
||||
#define ETH_P_RARP 0x8035
|
||||
#define ETH_P_ATALK 0x809B
|
||||
#define ETH_P_AARP 0x80F3
|
||||
#define ETH_P_8021Q 0x8100
|
||||
#define ETH_P_IPX 0x8137
|
||||
#define ETH_P_IPV6 0x86DD
|
||||
#define ETH_P_PAUSE 0x8808
|
||||
#define ETH_P_SLOW 0x8809
|
||||
#define ETH_P_WCCP 0x883E
|
||||
#define ETH_P_MPLS_UC 0x8847
|
||||
#define ETH_P_MPLS_MC 0x8848
|
||||
#define ETH_P_ATMMPOA 0x884c
|
||||
#define ETH_P_PPP_DISC 0x8863
|
||||
#define ETH_P_PPP_SES 0x8864
|
||||
#define ETH_P_LINK_CTL 0x886c
|
||||
#define ETH_P_ATMFATE 0x8884
|
||||
#define ETH_P_PAE 0x888E
|
||||
#define ETH_P_AOE 0x88A2
|
||||
#define ETH_P_8021AD 0x88A8
|
||||
#define ETH_P_802_EX1 0x88B5
|
||||
#define ETH_P_TIPC 0x88CA
|
||||
#define ETH_P_8021AH 0x88E7
|
||||
#define ETH_P_MVRP 0x88F5
|
||||
#define ETH_P_1588 0x88F7
|
||||
#define ETH_P_PRP 0x88FB
|
||||
#define ETH_P_FCOE 0x8906
|
||||
#define ETH_P_TDLS 0x890D
|
||||
#define ETH_P_FIP 0x8914
|
||||
#define ETH_P_80221 0x8917
|
||||
#define ETH_P_LOOPBACK 0x9000
|
||||
#define ETH_P_QINQ1 0x9100
|
||||
#define ETH_P_QINQ2 0x9200
|
||||
#define ETH_P_QINQ3 0x9300
|
||||
#define ETH_P_EDSA 0xDADA
|
||||
#define ETH_P_AF_IUCV 0xFBFB
|
||||
|
||||
#define ETH_P_802_3_MIN 0x0600
|
||||
|
||||
#define ETH_P_802_3 0x0001
|
||||
#define ETH_P_AX25 0x0002
|
||||
#define ETH_P_ALL 0x0003
|
||||
#define ETH_P_802_2 0x0004
|
||||
#define ETH_P_SNAP 0x0005
|
||||
#define ETH_P_DDCMP 0x0006
|
||||
#define ETH_P_WAN_PPP 0x0007
|
||||
#define ETH_P_PPP_MP 0x0008
|
||||
#define ETH_P_LOCALTALK 0x0009
|
||||
#define ETH_P_CAN 0x000C
|
||||
#define ETH_P_CANFD 0x000D
|
||||
#define ETH_P_PPPTALK 0x0010
|
||||
#define ETH_P_TR_802_2 0x0011
|
||||
#define ETH_P_MOBITEX 0x0015
|
||||
#define ETH_P_CONTROL 0x0016
|
||||
#define ETH_P_IRDA 0x0017
|
||||
#define ETH_P_ECONET 0x0018
|
||||
#define ETH_P_HDLC 0x0019
|
||||
#define ETH_P_ARCNET 0x001A
|
||||
#define ETH_P_DSA 0x001B
|
||||
#define ETH_P_TRAILER 0x001C
|
||||
#define ETH_P_PHONET 0x00F5
|
||||
#define ETH_P_IEEE802154 0x00F6
|
||||
#define ETH_P_CAIF 0x00F7
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if_arp.h>
|
||||
|
||||
struct ether_arp {
|
||||
struct arphdr ea_hdr;
|
||||
uint8_t arp_sha[ETH_ALEN];
|
||||
uint8_t arp_spa[4];
|
||||
uint8_t arp_tha[ETH_ALEN];
|
||||
uint8_t arp_tpa[4];
|
||||
};
|
||||
#define arp_hrd ea_hdr.ar_hrd
|
||||
#define arp_pro ea_hdr.ar_pro
|
||||
#define arp_hln ea_hdr.ar_hln
|
||||
#define arp_pln ea_hdr.ar_pln
|
||||
#define arp_op ea_hdr.ar_op
|
||||
|
||||
#endif /*_NETINET_IF_ETHER_H */
|
||||
@@ -0,0 +1,122 @@
|
||||
|
||||
#ifndef _NETINET_IN_H
|
||||
#define _NETINET_IN_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/socket.h> /* struct sockaddr */
|
||||
#include <abi-bits/socket.h>
|
||||
#include <abi-bits/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <mlibc-config.h>
|
||||
|
||||
#if __MLIBC_GLIBC_OPTION
|
||||
#include <endian.h>
|
||||
#endif /*__MLIBC_GLIBC_OPTION */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef __MLIBC_ABI_ONLY
|
||||
|
||||
extern const struct in6_addr in6addr_any;
|
||||
extern const struct in6_addr in6addr_loopback;
|
||||
|
||||
uint32_t htonl(uint32_t __x);
|
||||
uint16_t htons(uint16_t __x);
|
||||
uint32_t ntohl(uint32_t __x);
|
||||
uint16_t ntohs(uint16_t __x);
|
||||
|
||||
#endif /* !__MLIBC_ABI_ONLY */
|
||||
|
||||
#define IN6_IS_ADDR_UNSPECIFIED(a) ({ \
|
||||
uint32_t *_a = (uint32_t *)(((struct in6_addr *) a)->s6_addr); \
|
||||
!_a[0] && \
|
||||
!_a[1] && \
|
||||
!_a[2] && \
|
||||
!_a[3]; \
|
||||
})
|
||||
#define IN6_IS_ADDR_LOOPBACK(a) ({ \
|
||||
uint32_t *_a = (uint32_t *)(((struct in6_addr *) a)->s6_addr); \
|
||||
!_a[0] && \
|
||||
!_a[1] && \
|
||||
!_a[2] && \
|
||||
_a[3] == htonl(0x0001); \
|
||||
})
|
||||
#define IN6_IS_ADDR_MULTICAST(a) (((const uint8_t *) (a))[0] == 0xff)
|
||||
#define IN6_IS_ADDR_LINKLOCAL(a) ({ \
|
||||
uint32_t *_a = (uint32_t *)(((struct in6_addr *) a)->s6_addr); \
|
||||
(_a[0] & htonl(0xffc00000)) == htonl(0xfe800000); \
|
||||
})
|
||||
#define IN6_IS_ADDR_SITELOCAL(a) ({ \
|
||||
uint32_t *_a = (uint32_t *)(((struct in6_addr *) a)->s6_addr); \
|
||||
(_a[0] & htonl(0xffc00000)) == htonl(0xfec00000); \
|
||||
})
|
||||
#define IN6_IS_ADDR_V4MAPPED(a) ({ \
|
||||
uint32_t *_a = (uint32_t *)(((struct in6_addr *) a)->s6_addr); \
|
||||
!_a[0] && \
|
||||
!_a[1] && \
|
||||
_a[2] == htonl(0xffff); \
|
||||
})
|
||||
#define __ARE_4_BYTE_EQUAL(a, b) \
|
||||
((a)[0] == (b)[0] && (a)[1] == (b)[1] && (a)[2] == (b)[2] && \
|
||||
(a)[3] == (b)[3])
|
||||
#define IN6_ARE_ADDR_EQUAL(a, b) \
|
||||
__ARE_4_BYTE_EQUAL((const uint32_t *)(a), (const uint32_t *)(b))
|
||||
|
||||
#define IN6_IS_ADDR_V4COMPAT(a) ({ \
|
||||
uint32_t *_a = (uint32_t *)(((struct in6_addr *) a)->s6_addr); \
|
||||
uint8_t *_a8 = (uint8_t *)(((struct in6_addr *) a)->s6_addr); \
|
||||
!_a[0] && !_a[1] && !_a[2] && (_a8[15] > 1); \
|
||||
})
|
||||
#define IN6_IS_ADDR_MC_NODELOCAL(a) ({ \
|
||||
(IN6_IS_ADDR_MULTICAST(a) && \
|
||||
((((const uint8_t *)(a))[1] & 0xf) == 0x1)); \
|
||||
})
|
||||
#define IN6_IS_ADDR_MC_LINKLOCAL(a) ({ \
|
||||
(IN6_IS_ADDR_MULTICAST(a) && \
|
||||
((((const uint8_t *)(a))[1] & 0xf) == 0x2)); \
|
||||
})
|
||||
#define IN6_IS_ADDR_MC_SITELOCAL(a) ({ \
|
||||
(IN6_IS_ADDR_MULTICAST(a) && \
|
||||
((((const uint8_t *)(a))[1] & 0xf) == 0x5)); \
|
||||
})
|
||||
#define IN6_IS_ADDR_MC_ORGLOCAL(a) ({ \
|
||||
(IN6_IS_ADDR_MULTICAST(a) && \
|
||||
((((const uint8_t *)(a))[1] & 0xf) == 0x8)); \
|
||||
})
|
||||
#define IN6_IS_ADDR_MC_GLOBAL(a) ({ \
|
||||
(IN6_IS_ADDR_MULTICAST(a) && \
|
||||
((((const uint8_t *)(a))[1] & 0xf) == 0xe)); \
|
||||
})
|
||||
|
||||
#define IN_CLASSA(a) ((((in_addr_t)(a)) & 0x80000000) == 0)
|
||||
#define IN_CLASSA_NET 0xff000000
|
||||
#define IN_CLASSA_NSHIFT 24
|
||||
#define IN_CLASSA_HOST (0xffffffff & ~IN_CLASSA_NET)
|
||||
#define IN_CLASSA_MAX 128
|
||||
#define IN_CLASSB(a) ((((in_addr_t)(a)) & 0xc0000000) == 0x80000000)
|
||||
#define IN_CLASSB_NET 0xffff0000
|
||||
#define IN_CLASSB_NSHIFT 16
|
||||
#define IN_CLASSB_HOST (0xffffffff & ~IN_CLASSB_NET)
|
||||
#define IN_CLASSB_MAX 65536
|
||||
#define IN_CLASSC(a) ((((in_addr_t)(a)) & 0xe0000000) == 0xc0000000)
|
||||
#define IN_CLASSC_NET 0xffffff00
|
||||
#define IN_CLASSC_NSHIFT 8
|
||||
#define IN_CLASSC_HOST (0xffffffff & ~IN_CLASSC_NET)
|
||||
#define IN_CLASSD(a) ((((in_addr_t)(a)) & 0xf0000000) == 0xe0000000)
|
||||
#define IN_MULTICAST(a) IN_CLASSD(a)
|
||||
#define IN_EXPERIMENTAL(a) ((((in_addr_t)(a)) & 0xe0000000) == 0xe0000000)
|
||||
#define IN_BADCLASS(a) ((((in_addr_t)(a)) & 0xf0000000) == 0xf0000000)
|
||||
|
||||
#define IN_LOOPBACKNET 127
|
||||
|
||||
#define MCAST_EXCLUDE 0
|
||||
#define MCAST_INCLUDE 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _NETINET_IN_H */
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
|
||||
#ifndef _NETINET_IP_H
|
||||
#define _NETINET_IP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#define IPTOS_TOS_MASK 0x1E
|
||||
#define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK)
|
||||
#define IPTOS_LOWDELAY 0x10
|
||||
#define IPTOS_THROUGHPUT 0x08
|
||||
#define IPTOS_RELIABILITY 0x04
|
||||
#define IPTOS_LOWCOST 0x02
|
||||
#define IPTOS_MINCOST IPTOS_LOWCOST
|
||||
#define IPTOS_CLASS_CS0 0x00
|
||||
#define IPTOS_CLASS_CS4 0x80
|
||||
#define IPTOS_CLASS_CS6 0xC0
|
||||
#define IPTOS_DSCP_EF 0xB8
|
||||
|
||||
#define IPOPT_COPY 0x80
|
||||
#define IPOPT_CLASS_MASK 0x60
|
||||
#define IPOPT_NUMBER_MASK 0x1f
|
||||
|
||||
#define IPOPT_COPIED(o) ((o) & IPOPT_COPY)
|
||||
#define IPOPT_CLASS(o) ((o) & IPOPT_CLASS_MASK)
|
||||
#define IPOPT_NUMBER(o) ((o) & IPOPT_NUMBER_MASK)
|
||||
|
||||
#define IPOPT_CONTROL 0x00
|
||||
#define IPOPT_RESERVED1 0x20
|
||||
#define IPOPT_DEBMEAS 0x40
|
||||
#define IPOPT_MEASUREMENT IPOPT_DEBMEAS
|
||||
#define IPOPT_RESERVED2 0x60
|
||||
|
||||
#define IPOPT_EOL 0
|
||||
#define IPOPT_END IPOPT_EOL
|
||||
#define IPOPT_NOP 1
|
||||
#define IPOPT_NOOP IPOPT_NOP
|
||||
|
||||
#define IPOPT_RR 7
|
||||
#define IPOPT_TS 68
|
||||
#define IPOPT_TIMESTAMP IPOPT_TS
|
||||
#define IPOPT_SECURITY 130
|
||||
#define IPOPT_SEC IPOPT_SECURITY
|
||||
#define IPOPT_LSRR 131
|
||||
#define IPOPT_SATID 136
|
||||
#define IPOPT_SID IPOPT_SATID
|
||||
#define IPOPT_SSRR 137
|
||||
#define IPOPT_RA 148
|
||||
|
||||
#define IPOPT_OPTVAL 0
|
||||
#define IPOPT_OLEN 1
|
||||
#define IPOPT_OFFSET 2
|
||||
#define IPOPT_MINOFF 4
|
||||
|
||||
#define MAX_IPOPTLEN 40
|
||||
|
||||
#define IPOPT_TS_TSONLY 0
|
||||
#define IPOPT_TS_TSANDADDR 1
|
||||
#define IPOPT_TS_PRESPEC 3
|
||||
|
||||
#define IPDEFTTL 64
|
||||
|
||||
struct ip {
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
unsigned int ip_hl:4;
|
||||
unsigned int ip_v:4;
|
||||
#endif
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
unsigned int ip_v:4;
|
||||
unsigned int ip_hl:4;
|
||||
#endif
|
||||
uint8_t ip_tos;
|
||||
unsigned short ip_len;
|
||||
unsigned short ip_id;
|
||||
unsigned short ip_off;
|
||||
#define IP_RF 0x8000
|
||||
#define IP_DF 0x4000
|
||||
#define IP_MF 0x2000
|
||||
#define IP_OFFMASK 0x1fff
|
||||
uint8_t ip_ttl;
|
||||
uint8_t ip_p;
|
||||
unsigned short ip_sum;
|
||||
struct in_addr ip_src, ip_dst;
|
||||
};
|
||||
|
||||
#define IPVERSION 4
|
||||
|
||||
struct iphdr {
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
unsigned int ihl:4;
|
||||
unsigned int version:4;
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
unsigned int version:4;
|
||||
unsigned int ihl:4;
|
||||
#else
|
||||
# error "Please fix <endian.h>"
|
||||
#endif
|
||||
uint8_t tos;
|
||||
uint16_t tot_len;
|
||||
uint16_t id;
|
||||
uint16_t frag_off;
|
||||
uint8_t ttl;
|
||||
uint8_t protocol;
|
||||
uint16_t check;
|
||||
uint32_t saddr;
|
||||
uint32_t daddr;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _NETINET_IP_H */
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
#ifndef _NETINET_IP6_H
|
||||
#define _NETINET_IP6_H
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ip6_hdr {
|
||||
union {
|
||||
struct ip6_hdrctl {
|
||||
uint32_t ip6_un1_flow;
|
||||
uint16_t ip6_un1_plen;
|
||||
uint8_t ip6_un1_nxt;
|
||||
uint8_t ip6_un1_hlim;
|
||||
} ip6_un1;
|
||||
uint8_t ip6_un2_vfc;
|
||||
} ip6_ctlun;
|
||||
struct in6_addr ip6_src;
|
||||
struct in6_addr ip6_dst;
|
||||
};
|
||||
|
||||
#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _NETINET_IP6_H */
|
||||
@@ -0,0 +1,140 @@
|
||||
#ifndef _NETINET_ICMP_H
|
||||
#define _NETINET_ICMP_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
|
||||
struct icmphdr {
|
||||
uint8_t type;
|
||||
uint8_t code;
|
||||
uint16_t checksum;
|
||||
union {
|
||||
struct {
|
||||
uint16_t id;
|
||||
uint16_t sequence;
|
||||
} echo;
|
||||
uint32_t gateway;
|
||||
struct {
|
||||
uint16_t __unused;
|
||||
uint16_t mtu;
|
||||
} frag;
|
||||
uint8_t reserved[4];
|
||||
} un;
|
||||
};
|
||||
|
||||
#define ICMP_ECHOREPLY 0
|
||||
#define ICMP_DEST_UNREACH 3
|
||||
#define ICMP_SOURCE_QUENCH 4
|
||||
#define ICMP_REDIRECT 5
|
||||
#define ICMP_ECHO 8
|
||||
#define ICMP_TIME_EXCEEDED 11
|
||||
#define ICMP_PARAMETERPROB 12
|
||||
#define ICMP_TIMESTAMP 13
|
||||
#define ICMP_TIMESTAMPREPLY 14
|
||||
#define ICMP_INFO_REQUEST 15
|
||||
#define ICMP_INFO_REPLY 16
|
||||
#define ICMP_ADDRESS 17
|
||||
#define ICMP_ADDRESSREPLY 18
|
||||
|
||||
#define ICMP_NET_UNREACH 0
|
||||
#define ICMP_HOST_UNREACH 1
|
||||
#define ICMP_PROT_UNREACH 2
|
||||
#define ICMP_PORT_UNREACH 3
|
||||
#define ICMP_FRAG_NEEDED 4
|
||||
#define ICMP_SR_FAILED 5
|
||||
#define ICMP_NET_UNKNOWN 6
|
||||
#define ICMP_HOST_UNKNOWN 7
|
||||
#define ICMP_HOST_ISOLATED 8
|
||||
#define ICMP_NET_ANO 9
|
||||
#define ICMP_HOST_ANO 10
|
||||
#define ICMP_NET_UNR_TOS 11
|
||||
#define ICMP_HOST_UNR_TOS 12
|
||||
#define ICMP_PKT_FILTERED 13
|
||||
#define ICMP_PREC_VIOLATION 14
|
||||
#define ICMP_PREC_CUTOFF 15
|
||||
#define NR_ICMP_UNREACH 15
|
||||
|
||||
#define ICMP_REDIR_NET 0
|
||||
#define ICMP_REDIR_HOST 1
|
||||
#define ICMP_REDIR_NETTOS 2
|
||||
#define ICMP_REDIR_HOSTTOS 3
|
||||
|
||||
#define ICMP_EXC_TTL 0
|
||||
#define ICMP_EXC_FRAGTIME 1
|
||||
|
||||
#define ICMP_ADVLENMIN (8 + sizeof(struct ip) + 8)
|
||||
|
||||
struct icmp_ra_addr {
|
||||
uint32_t ira_addr;
|
||||
uint32_t ira_preference;
|
||||
};
|
||||
|
||||
struct icmp {
|
||||
uint8_t icmp_type;
|
||||
uint8_t icmp_code;
|
||||
uint16_t icmp_cksum;
|
||||
union {
|
||||
unsigned char ih_pptr;
|
||||
struct in_addr ih_gwaddr;
|
||||
struct ih_idseq {
|
||||
uint16_t icd_id;
|
||||
uint16_t icd_seq;
|
||||
} ih_idseq;
|
||||
uint32_t ih_void;
|
||||
|
||||
struct ih_pmtu {
|
||||
uint16_t ipm_void;
|
||||
uint16_t ipm_nextmtu;
|
||||
} ih_pmtu;
|
||||
|
||||
struct ih_rtradv {
|
||||
uint8_t irt_num_addrs;
|
||||
uint8_t irt_wpa;
|
||||
uint16_t irt_lifetime;
|
||||
} ih_rtradv;
|
||||
} icmp_hun;
|
||||
union {
|
||||
struct {
|
||||
uint32_t its_otime;
|
||||
uint32_t its_rtime;
|
||||
uint32_t its_ttime;
|
||||
} id_ts;
|
||||
struct {
|
||||
struct ip idi_ip;
|
||||
} id_ip;
|
||||
struct icmp_ra_addr id_radv;
|
||||
uint32_t id_mask;
|
||||
uint8_t id_data[1];
|
||||
} icmp_dun;
|
||||
};
|
||||
|
||||
#define icmp_pptr icmp_hun.ih_pptr
|
||||
#define icmp_gwaddr icmp_hun.ih_gwaddr
|
||||
#define icmp_id icmp_hun.ih_idseq.icd_id
|
||||
#define icmp_seq icmp_hun.ih_idseq.icd_seq
|
||||
#define icmp_void icmp_hun.ih_void
|
||||
#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void
|
||||
#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu
|
||||
#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs
|
||||
#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa
|
||||
#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime
|
||||
|
||||
#define icmp_otime icmp_dun.id_ts.its_otime
|
||||
#define icmp_rtime icmp_dun.id_ts.its_rtime
|
||||
#define icmp_ttime icmp_dun.id_ts.its_ttime
|
||||
#define icmp_ip icmp_dun.id_ip.idi_ip
|
||||
#define icmp_radv icmp_dun.id_radv
|
||||
#define icmp_mask icmp_dun.id_mask
|
||||
#define icmp_data icmp_dun.id_data
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _NETINET_ICMP_H */
|
||||
@@ -0,0 +1,95 @@
|
||||
#ifndef _NETINET_TCP_H
|
||||
#define _NETINET_TCP_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Define some macros using same ABI as Linux */
|
||||
#define TCP_NODELAY 1
|
||||
#define TCP_MAXSEG 2
|
||||
#define TCP_KEEPIDLE 4
|
||||
#define TCP_KEEPINTVL 5
|
||||
#define TCP_KEEPCNT 6
|
||||
#define TCP_DEFER_ACCEPT 9
|
||||
#define TCP_INFO 11
|
||||
#define TCP_CONGESTION 13
|
||||
#define TCP_FASTOPEN 23
|
||||
|
||||
#define TCP_ESTABLISHED 1
|
||||
#define TCP_SYN_SENT 2
|
||||
#define TCP_SYN_RECV 3
|
||||
#define TCP_FIN_WAIT1 4
|
||||
#define TCP_FIN_WAIT2 5
|
||||
#define TCP_TIME_WAIT 6
|
||||
#define TCP_CLOSE 7
|
||||
#define TCP_CLOSE_WAIT 8
|
||||
#define TCP_LAST_ACK 9
|
||||
#define TCP_LISTEN 10
|
||||
#define TCP_CLOSING 11
|
||||
#define TCP_QUICKACK 12
|
||||
|
||||
#define SOL_TCP 6
|
||||
|
||||
#define TCPI_OPT_TIMESTAMPS 1
|
||||
#define TCPI_OPT_SACK 2
|
||||
#define TCPI_OPT_WSCALE 4
|
||||
#define TCPI_OPT_ECN 8
|
||||
#define TCPI_OPT_ECN_SEEN 16
|
||||
#define TCPI_OPT_SYN_DATA 32
|
||||
|
||||
enum tcp_ca_state {
|
||||
TCP_CA_Open = 0,
|
||||
TCP_CA_Disorder = 1,
|
||||
TCP_CA_CWR = 2,
|
||||
TCP_CA_Recovery = 3,
|
||||
TCP_CA_Loss = 4
|
||||
};
|
||||
|
||||
struct tcp_info {
|
||||
uint8_t tcpi_state;
|
||||
uint8_t tcpi_ca_state;
|
||||
uint8_t tcpi_retransmits;
|
||||
uint8_t tcpi_probes;
|
||||
uint8_t tcpi_backoff;
|
||||
uint8_t tcpi_options;
|
||||
__extension__ uint8_t tcpi_snd_wscale : 4, tcpi_rcv_wscale : 4;
|
||||
|
||||
uint32_t tcpi_rto;
|
||||
uint32_t tcpi_ato;
|
||||
uint32_t tcpi_snd_mss;
|
||||
uint32_t tcpi_rcv_mss;
|
||||
|
||||
uint32_t tcpi_unacked;
|
||||
uint32_t tcpi_sacked;
|
||||
uint32_t tcpi_lost;
|
||||
uint32_t tcpi_retrans;
|
||||
uint32_t tcpi_fackets;
|
||||
|
||||
uint32_t tcpi_last_data_sent;
|
||||
uint32_t tcpi_last_ack_sent;
|
||||
uint32_t tcpi_last_data_recv;
|
||||
uint32_t tcpi_last_ack_recv;
|
||||
|
||||
uint32_t tcpi_pmtu;
|
||||
uint32_t tcpi_rcv_ssthresh;
|
||||
uint32_t tcpi_rtt;
|
||||
uint32_t tcpi_rttvar;
|
||||
uint32_t tcpi_snd_ssthresh;
|
||||
uint32_t tcpi_snd_cwnd;
|
||||
uint32_t tcpi_advmss;
|
||||
uint32_t tcpi_reordering;
|
||||
|
||||
uint32_t tcpi_rcv_rtt;
|
||||
uint32_t tcpi_rcv_space;
|
||||
|
||||
uint32_t tcpi_total_retrans;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _NETINET_TCP_H */
|
||||
@@ -0,0 +1,31 @@
|
||||
#ifndef _NETINET_UDP_H
|
||||
#define _NETINET_UDP_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
__extension__ struct udphdr {
|
||||
__extension__ union {
|
||||
struct {
|
||||
uint16_t uh_sport;
|
||||
uint16_t uh_dport;
|
||||
uint16_t uh_ulen;
|
||||
uint16_t uh_sum;
|
||||
};
|
||||
struct {
|
||||
uint16_t source;
|
||||
uint16_t dest;
|
||||
uint16_t len;
|
||||
uint16_t check;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _NETINET_UDP_H */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user