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,64 @@
|
||||
#include <err.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// va_list
|
||||
|
||||
void vwarn(const char *fmt, va_list params) {
|
||||
fprintf(stderr, "%s: ", program_invocation_short_name);
|
||||
if (fmt) {
|
||||
vfprintf(stderr, fmt, params);
|
||||
fwrite(": ", 1, 2, stderr);
|
||||
}
|
||||
perror(nullptr);
|
||||
}
|
||||
|
||||
void vwarnx(const char *fmt, va_list params) {
|
||||
fprintf(stderr, "%s: ", program_invocation_short_name);
|
||||
if (fmt) {
|
||||
vfprintf(stderr, fmt, params);
|
||||
}
|
||||
putc('\n', stderr);
|
||||
}
|
||||
|
||||
__attribute__((__noreturn__)) void verr(int status, const char *fmt, va_list params) {
|
||||
vwarn(fmt, params);
|
||||
exit(status);
|
||||
}
|
||||
|
||||
__attribute__((__noreturn__)) void verrx(int status, const char *fmt, va_list params) {
|
||||
vwarnx(fmt, params);
|
||||
exit(status);
|
||||
}
|
||||
|
||||
// variadic
|
||||
|
||||
void warn(const char *fmt, ...) {
|
||||
va_list params;
|
||||
va_start(params, fmt);
|
||||
vwarn(fmt, params);
|
||||
va_end(params);
|
||||
}
|
||||
|
||||
void warnx(const char *fmt, ...) {
|
||||
va_list params;
|
||||
va_start(params, fmt);
|
||||
vwarnx(fmt, params);
|
||||
va_end(params);
|
||||
}
|
||||
|
||||
__attribute__((__noreturn__)) void err(int status, const char *fmt, ...) {
|
||||
va_list params;
|
||||
va_start(params, fmt);
|
||||
verr(status, fmt, params);
|
||||
va_end(params);
|
||||
}
|
||||
|
||||
__attribute__((__noreturn__)) void errx(int status, const char *fmt, ...) {
|
||||
va_list params;
|
||||
va_start(params, fmt);
|
||||
verrx(status, fmt, params);
|
||||
va_end(params);
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <error.h>
|
||||
|
||||
unsigned int error_message_count = 0;
|
||||
int error_one_per_line = 0;
|
||||
void (*error_print_progname)(void) = nullptr;
|
||||
|
||||
void error(int status, int errnum, const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
error_message_count++;
|
||||
|
||||
fflush(stdout);
|
||||
if(error_print_progname) {
|
||||
error_print_progname();
|
||||
} else {
|
||||
fprintf(stderr, "%s: ", program_invocation_name);
|
||||
}
|
||||
vfprintf(stderr, format, args);
|
||||
va_end(args);
|
||||
|
||||
if(errnum) {
|
||||
fprintf(stderr, ": %s\n", strerror(errnum));
|
||||
}
|
||||
|
||||
if(status) {
|
||||
exit(status);
|
||||
}
|
||||
}
|
||||
|
||||
void error_at_line(int status, int errnum, const char *filename, unsigned int linenum, const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
static bool first_call = true;
|
||||
static unsigned int last_line = 0;
|
||||
if(!(last_line == linenum && error_one_per_line && !first_call)) {
|
||||
first_call = false;
|
||||
last_line = linenum;
|
||||
error_message_count++;
|
||||
|
||||
fflush(stdout);
|
||||
if(error_print_progname) {
|
||||
error_print_progname();
|
||||
} else {
|
||||
fprintf(stderr, "%s:", program_invocation_name);
|
||||
}
|
||||
fprintf(stderr, "%s:%u: ", filename, linenum);
|
||||
vfprintf(stderr, format, args);
|
||||
|
||||
if(errnum) {
|
||||
fprintf(stderr, ": %s\n", strerror(errnum));
|
||||
}
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
if(status) {
|
||||
exit(status);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
#include <dlfcn.h>
|
||||
#include <execinfo.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <unwind.h>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/debug.hpp>
|
||||
|
||||
namespace {
|
||||
|
||||
using UnwindBacktrace = _Unwind_Reason_Code (*)(_Unwind_Trace_Fn, void *);
|
||||
using UnwindGetIP = _Unwind_Ptr (*)(_Unwind_Context *);
|
||||
|
||||
frg::optional<void *> libgccHandle = frg::null_opt;
|
||||
|
||||
UnwindBacktrace unwindBacktrace = nullptr;
|
||||
UnwindGetIP unwindGetIP = nullptr;
|
||||
|
||||
struct UnwindState {
|
||||
void **frames;
|
||||
int count;
|
||||
int current_frame = 0;
|
||||
};
|
||||
|
||||
_Unwind_Reason_Code trace(_Unwind_Context *context, void *arg) {
|
||||
UnwindState *state = static_cast<UnwindState *>(arg);
|
||||
|
||||
if (state->current_frame >= state->count)
|
||||
return _URC_END_OF_STACK;
|
||||
|
||||
uintptr_t ip = unwindGetIP(context);
|
||||
|
||||
if (ip) {
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
ip--;
|
||||
#elif defined(__aarch64__) || defined(__loongarch64)
|
||||
ip -= 4;
|
||||
#elif defined(__riscv) || defined(__m68k__)
|
||||
ip -= 2;
|
||||
#else
|
||||
#warning "Missing support for architecture"
|
||||
ip--;
|
||||
#endif
|
||||
}
|
||||
|
||||
state->frames[state->current_frame++] = reinterpret_cast<void *>(ip);
|
||||
return _URC_NO_REASON;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int backtrace(void **buffer, int size) {
|
||||
if (size <= 0)
|
||||
return 0;
|
||||
|
||||
if (!libgccHandle) {
|
||||
libgccHandle = dlopen("libgcc_s.so.1", RTLD_LAZY | RTLD_LOCAL);
|
||||
if (!libgccHandle || libgccHandle.value() == nullptr) {
|
||||
mlibc::infoLogger() << "Failed to load libgcc_s.so.1: " << (dlerror() ? dlerror() : "") << frg::endlog;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unwindBacktrace = reinterpret_cast<UnwindBacktrace>(dlsym(libgccHandle.value(), "_Unwind_Backtrace"));
|
||||
unwindGetIP = reinterpret_cast<UnwindGetIP>(dlsym(libgccHandle.value(), "_Unwind_GetIP"));
|
||||
|
||||
if (!unwindBacktrace || !unwindGetIP) {
|
||||
mlibc::infoLogger() << "Failed to find unwind functions in libgcc_s.so.1: " << dlerror() << frg::endlog;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
UnwindState state{buffer, size};
|
||||
unwindBacktrace(trace, &state);
|
||||
return state.current_frame;
|
||||
}
|
||||
|
||||
char **backtrace_symbols(void *const *, int) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void backtrace_symbols_fd(void *const *buffer, int size, int fd) {
|
||||
if (size <= 0 || fd < 0)
|
||||
return;
|
||||
|
||||
for (int frame_num = 0; frame_num < size; frame_num++) {
|
||||
Dl_info info;
|
||||
if (dladdr(buffer[frame_num], &info) != 0) {
|
||||
if (info.dli_fname != nullptr)
|
||||
write(fd, info.dli_fname, strlen(info.dli_fname));
|
||||
|
||||
if (info.dli_sname != nullptr)
|
||||
dprintf(fd, "(%s+0x%" PRIxPTR ") ", info.dli_sname,
|
||||
reinterpret_cast<uintptr_t>(buffer[frame_num]) - reinterpret_cast<uintptr_t>(info.dli_saddr));
|
||||
else if(info.dli_saddr)
|
||||
dprintf(fd, "(+%p) ", info.dli_saddr);
|
||||
else
|
||||
dprintf(fd, "() ");
|
||||
}
|
||||
|
||||
dprintf(fd, "[%p]\n", buffer[frame_num]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#include <getopt.h>
|
||||
#include <mlibc/getopt.hpp>
|
||||
|
||||
int getopt_long(int argc, char * const argv[], const char *optstring,
|
||||
const struct option *longopts, int *longindex) {
|
||||
return getopt_common(argc, argv, optstring, longopts, longindex, mlibc::GetoptMode::Long);
|
||||
}
|
||||
|
||||
int getopt_long_only(int argc, char * const argv[], const char *optstring,
|
||||
const struct option *longopts, int *longindex) {
|
||||
return getopt_common(argc, argv, optstring, longopts, longindex, mlibc::GetoptMode::LongOnly);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
|
||||
[[gnu::noreturn]] void __assert_fail_perror(int errno, const char *file, unsigned int line,
|
||||
const char *function) {
|
||||
char *errormsg = strerror(errno);
|
||||
fprintf(stderr, "In function %s, file %s:%d: Errno '%s' failed!\n",
|
||||
function, file, line, errormsg);
|
||||
abort();
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/glibc-sysdeps.hpp>
|
||||
|
||||
int tgkill(int tgid, int tid, int sig) {
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_tgkill, -1);
|
||||
if(int e = mlibc::sys_tgkill(tgid, tid, sig); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#include <gshadow.h>
|
||||
#include <bits/ensure.h>
|
||||
|
||||
int getsgnam_r(const char *, struct sgrp *, char *, size_t, struct sgrp **) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#include <bits/glibc/glibc_malloc.h>
|
||||
#include <mlibc/allocator.hpp>
|
||||
|
||||
size_t malloc_usable_size(void *p) {
|
||||
return getAllocator().get_size(p);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#include <bits/ensure.h>
|
||||
#include <errno.h>
|
||||
#include <mlibc/glibc-sysdeps.hpp>
|
||||
#include <sys/personality.h>
|
||||
|
||||
int personality(unsigned long persona) {
|
||||
int out = 0;
|
||||
auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_personality, -1);
|
||||
|
||||
if(int e = sysdep(persona, &out); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#include <bits/ensure.h>
|
||||
#include <printf.h>
|
||||
|
||||
size_t parse_printf_format(const char * __restrict, size_t, int * __restrict) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#include <resolv.h>
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/debug.hpp>
|
||||
|
||||
int dn_expand(const unsigned char *, const unsigned char *,
|
||||
const unsigned char *, char *, int) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
int res_query(const char *, int, int, unsigned char *, int) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
int res_init() {
|
||||
mlibc::infoLogger() << "mlibc: res_init is a stub!" << frg::endlog;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int res_ninit(res_state) {
|
||||
mlibc::infoLogger() << "mlibc: res_ninit is a stub!" << frg::endlog;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void res_nclose(res_state) {
|
||||
mlibc::infoLogger() << "mlibc: res_nclose is a stub!" << frg::endlog;
|
||||
return;
|
||||
}
|
||||
|
||||
int dn_comp(const char *, unsigned char *, int, unsigned char **, unsigned char **) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
/* This is completely unused, and exists purely to satisfy broken apps. */
|
||||
|
||||
struct __res_state *__res_state() {
|
||||
static struct __res_state res;
|
||||
return &res;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#include <bits/glibc/glibc_search.h>
|
||||
#include <mlibc/search.hpp>
|
||||
|
||||
int hcreate_r(size_t num_entries, hsearch_data *htab) {
|
||||
return mlibc::hcreate_r(num_entries, htab);
|
||||
}
|
||||
|
||||
void hdestroy_r(hsearch_data *htab) {
|
||||
mlibc::hdestroy_r(htab);
|
||||
}
|
||||
|
||||
int hsearch_r(ENTRY item, ACTION action, ENTRY **ret, hsearch_data *htab) {
|
||||
return mlibc::hsearch_r(item, action, ret, htab);
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
#include <shadow.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/debug.hpp>
|
||||
|
||||
/*
|
||||
* The code in this file is largely based on or taken from musl.
|
||||
* This includes:
|
||||
* - xatol
|
||||
* - __parsespent
|
||||
* - cleanup
|
||||
* - getspnam_r
|
||||
* - getspnam
|
||||
*/
|
||||
#define NUM(n) ((n) == -1 ? 0 : -1), ((n) == -1 ? 0 : (n))
|
||||
|
||||
int putspent(const struct spwd *sp, FILE *f) {
|
||||
auto str = [] (char *s) {
|
||||
return ((s) ? (s) : "");
|
||||
};
|
||||
return fprintf(f, "%s:%s:%.*ld:%.*ld:%.*ld:%.*ld:%.*ld:%.*ld:%.*u\n",
|
||||
str(sp->sp_namp), str(sp->sp_pwdp), NUM(sp->sp_lstchg),
|
||||
NUM(sp->sp_min), NUM(sp->sp_max), NUM(sp->sp_warn),
|
||||
NUM(sp->sp_inact), NUM(sp->sp_expire), NUM((int)sp->sp_flag)) < 0 ? -1 : 0;
|
||||
}
|
||||
#undef NUM
|
||||
|
||||
static long xatol(char **s) {
|
||||
long x;
|
||||
if(**s == ':' || **s == '\n') {
|
||||
return -1;
|
||||
}
|
||||
for(x = 0; (unsigned int)**s - '0' < 10U; ++*s) {
|
||||
x = 10 * x + (**s - '0');
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
static int __parsespent(char *s, struct spwd *sp) {
|
||||
sp->sp_namp = s;
|
||||
if(!(s = strchr(s, ':'))) {
|
||||
return -1;
|
||||
}
|
||||
*s = 0;
|
||||
|
||||
sp->sp_pwdp = ++s;
|
||||
if(!(s = strchr(s, ':'))) {
|
||||
return -1;
|
||||
}
|
||||
*s = 0;
|
||||
|
||||
s++;
|
||||
sp->sp_lstchg = xatol(&s);
|
||||
if(*s != ':') {
|
||||
return -1;
|
||||
}
|
||||
|
||||
s++;
|
||||
sp->sp_min = xatol(&s);
|
||||
if(*s != ':') {
|
||||
return -1;
|
||||
}
|
||||
|
||||
s++;
|
||||
sp->sp_max = xatol(&s);
|
||||
if(*s != ':') {
|
||||
return -1;
|
||||
}
|
||||
|
||||
s++;
|
||||
sp->sp_warn = xatol(&s);
|
||||
if(*s != ':') {
|
||||
return -1;
|
||||
}
|
||||
|
||||
s++;
|
||||
sp->sp_inact = xatol(&s);
|
||||
if(*s != ':') {
|
||||
return -1;
|
||||
}
|
||||
|
||||
s++;
|
||||
sp->sp_expire = xatol(&s);
|
||||
if(*s != ':') {
|
||||
return -1;
|
||||
}
|
||||
|
||||
s++;
|
||||
sp->sp_flag = xatol(&s);
|
||||
if(*s != '\n') {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cleanup(void *p) {
|
||||
fclose((FILE *)p);
|
||||
}
|
||||
|
||||
int getspnam_r(const char *name, struct spwd *sp, char *buf, size_t size, struct spwd **res) {
|
||||
char path[20 + NAME_MAX];
|
||||
FILE *f = nullptr;
|
||||
int rv = 0;
|
||||
int fd;
|
||||
size_t k, l = strlen(name);
|
||||
int skip = 0;
|
||||
int cs;
|
||||
int orig_errno = errno;
|
||||
|
||||
*res = nullptr;
|
||||
|
||||
/* Disallow potentially-malicious user names */
|
||||
if(*name=='.' || strchr(name, '/') || !l) {
|
||||
return errno = EINVAL;
|
||||
}
|
||||
|
||||
/* Buffer size must at least be able to hold name, plus some.. */
|
||||
if(size < l + 100) {
|
||||
return errno = ERANGE;
|
||||
}
|
||||
|
||||
/* Protect against truncation */
|
||||
if(snprintf(path, sizeof path, "/etc/tcb/%s/shadow", name) >= (int)sizeof path) {
|
||||
return errno = EINVAL;
|
||||
}
|
||||
|
||||
fd = open(path, O_RDONLY|O_NOFOLLOW|O_NONBLOCK|O_CLOEXEC);
|
||||
if(fd >= 0) {
|
||||
struct stat st = {};
|
||||
errno = EINVAL;
|
||||
if(fstat(fd, &st) || !S_ISREG(st.st_mode) || !(f = fdopen(fd, "rb"))) {
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
|
||||
close(fd);
|
||||
pthread_setcancelstate(cs, nullptr);
|
||||
return errno;
|
||||
}
|
||||
} else {
|
||||
if(errno != ENOENT && errno != ENOTDIR) {
|
||||
return errno;
|
||||
}
|
||||
f = fopen("/etc/shadow", "rbe");
|
||||
if(!f) {
|
||||
if(errno != ENOENT && errno != ENOTDIR) {
|
||||
return errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_cleanup_push(cleanup, f);
|
||||
while(fgets(buf, size, f) && (k = strlen(buf)) > 0) {
|
||||
if(skip || strncmp(name, buf, l) || buf[l] != ':') {
|
||||
skip = buf[k - 1] != '\n';
|
||||
continue;
|
||||
}
|
||||
if(buf[k - 1] != '\n') {
|
||||
rv = ERANGE;
|
||||
break;
|
||||
}
|
||||
|
||||
if(__parsespent(buf, sp) < 0) {
|
||||
continue;
|
||||
}
|
||||
*res = sp;
|
||||
break;
|
||||
}
|
||||
pthread_cleanup_pop(1);
|
||||
errno = rv ? rv : orig_errno;
|
||||
return rv;
|
||||
}
|
||||
|
||||
int lckpwdf(void) {
|
||||
mlibc::infoLogger() << "mlibc: lckpwdf is unimplemented like musl" << frg::endlog;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ulckpwdf(void) {
|
||||
mlibc::infoLogger() << "mlibc: ulckpwdf is unimplemented like musl" << frg::endlog;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Musl defines LINE_LIM to 256
|
||||
#define LINE_LIM 256
|
||||
|
||||
struct spwd *getspnam(const char *name) {
|
||||
static struct spwd sp;
|
||||
static char *line;
|
||||
struct spwd *res;
|
||||
int e;
|
||||
int orig_errno = errno;
|
||||
|
||||
if(!line) {
|
||||
line = (char *)malloc(LINE_LIM);
|
||||
}
|
||||
if(!line) {
|
||||
return nullptr;
|
||||
}
|
||||
e = getspnam_r(name, &sp, line, LINE_LIM, &res);
|
||||
errno = e ? e : orig_errno;
|
||||
return res;
|
||||
}
|
||||
|
||||
struct spwd *fgetspent(FILE *f) {
|
||||
static struct spwd sp;
|
||||
static char *line;
|
||||
struct spwd *res = nullptr;
|
||||
size_t size = 0;
|
||||
int cs;
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
|
||||
if(getline(&line, &size, f) >= 0 && __parsespent(line, &sp) >= 0) {
|
||||
res = &sp;
|
||||
}
|
||||
pthread_setcancelstate(cs, nullptr);
|
||||
return res;
|
||||
}
|
||||
|
||||
void endspent(void) {
|
||||
mlibc::infoLogger() << "mlibc: endspent is a stub" << frg::endlog;
|
||||
}
|
||||
|
||||
struct spwd *sgetspent(const char *) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
|
||||
#include <mlibc/file-io.hpp>
|
||||
#include <stdio_ext.h>
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/debug.hpp>
|
||||
|
||||
size_t __fbufsize(FILE *) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
size_t __fpending(FILE *file_base) {
|
||||
__ensure(file_base->__dirty_end >= file_base->__dirty_begin);
|
||||
return file_base->__dirty_end - file_base->__dirty_begin;
|
||||
}
|
||||
|
||||
int __flbf(FILE *) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
int __freadable(FILE *) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
int __fwritable(FILE *) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
int __freading(FILE *file_base) {
|
||||
return file_base->__io_mode == 0;
|
||||
}
|
||||
|
||||
int __fwriting(FILE *file_base) {
|
||||
return file_base->__io_mode == 1;
|
||||
}
|
||||
|
||||
int __fsetlocking(FILE *file_base, int state) {
|
||||
auto file = static_cast<mlibc::abstract_file *>(file_base);
|
||||
bool oldstate = file->_lock.uselock;
|
||||
if (state != FSETLOCKING_QUERY) {
|
||||
if (state == FSETLOCKING_BYCALLER) {
|
||||
file->_lock.uselock = false;
|
||||
} else {
|
||||
file->_lock.uselock = true;
|
||||
}
|
||||
}
|
||||
if (oldstate) {
|
||||
return FSETLOCKING_INTERNAL;
|
||||
} else {
|
||||
return FSETLOCKING_BYCALLER;
|
||||
}
|
||||
}
|
||||
|
||||
void _flushlbf(void) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
// The following functions are defined by musl.
|
||||
|
||||
size_t __freadahead(FILE *file_base) {
|
||||
if(file_base->__io_mode != 0) {
|
||||
mlibc::infoLogger() << "mlibc: __freadahead() called but file is not open for reading" << frg::endlog;
|
||||
return 0;
|
||||
}
|
||||
return file_base->__valid_limit - file_base->__offset;
|
||||
}
|
||||
|
||||
const char *__freadptr(FILE *, size_t *) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void __freadptrinc(FILE *, size_t) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void __fseterr(FILE *) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
int rpmatch(const char *resp) {
|
||||
if(!resp || resp[0] == '\0')
|
||||
return -1;
|
||||
if(resp[0] == 'y' || resp[0] == 'Y')
|
||||
return 1;
|
||||
if(resp[0] == 'n' || resp[0] == 'N')
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE
|
||||
#endif
|
||||
#include <type_traits>
|
||||
#include <string.h>
|
||||
|
||||
/* This is a bit of a weird detail of the GNU implementation and C's lack of
|
||||
* overloading and strictness: GNU takes const char * and returns a char * so
|
||||
* that it autocasts to your desired constness, this function never actually
|
||||
* modifies the string.
|
||||
*/
|
||||
char *__mlibc_gnu_basename_c(const char *path) {
|
||||
char *basename_component = strrchr(path, '/');
|
||||
if (!basename_component) {
|
||||
return const_cast<char *>(path);
|
||||
}
|
||||
return basename_component + 1;
|
||||
}
|
||||
|
||||
|
||||
/* GNU exposes these overloads, and as a result, we should probably have them
|
||||
* checked, to make sure we actually match expectations.
|
||||
*/
|
||||
static_assert(
|
||||
std::is_same_v<decltype(basename((const char *)nullptr)), const char*>,
|
||||
"C++ overloads broken"
|
||||
);
|
||||
|
||||
static_assert(
|
||||
std::is_same_v<decltype(basename((char *)nullptr)), char*>,
|
||||
"C++ overloads broken"
|
||||
);
|
||||
@@ -0,0 +1,16 @@
|
||||
#include <bits/ensure.h>
|
||||
#include <errno.h>
|
||||
#include <mlibc/glibc-sysdeps.hpp>
|
||||
#include <sys/cachectl.h>
|
||||
|
||||
#ifdef __riscv
|
||||
int __riscv_flush_icache(void *start, void *end, unsigned long flags) {
|
||||
auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_riscv_flush_icache, -1);
|
||||
|
||||
if(int e = sysdep(start, end, flags); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,25 @@
|
||||
#include <errno.h>
|
||||
#include <sys/io.h>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/glibc-sysdeps.hpp>
|
||||
|
||||
int ioperm(unsigned long int from, unsigned long int num, int turn_on) {
|
||||
auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_ioperm, -1);
|
||||
|
||||
if(int e = sysdep(from, num, turn_on); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iopl(int level) {
|
||||
auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_iopl, -1);
|
||||
|
||||
if(int e = sysdep(level); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/glibc-sysdeps.hpp>
|
||||
|
||||
int ioctl(int fd, unsigned long request, ...) {
|
||||
va_list args;
|
||||
va_start(args, request);
|
||||
int result;
|
||||
MLIBC_CHECK_OR_ENOSYS(mlibc::sys_ioctl, -1);
|
||||
void *arg = va_arg(args, void *);
|
||||
if(int e = mlibc::sys_ioctl(fd, request, arg, &result); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
#include <bits/ensure.h>
|
||||
#include <sys/timex.h>
|
||||
|
||||
int adjtimex(struct timex *) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
int clock_adjtime(clockid_t, struct timex *) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
int ntp_adjtime(struct timex *) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
Reference in New Issue
Block a user