Add x86_64-linux-gnu emulator

I wanted a tiny scriptable meltdown proof way to run userspace programs
and visualize how program execution impacts memory. It helps to explain
how things like Actually Portable Executable works. It can show you how
the GCC generated code is going about manipulating matrices and more. I
didn't feel fully comfortable with Qemu and Bochs because I'm not smart
enough to understand them. I wanted something like gVisor but with much
stronger levels of assurances. I wanted a single binary that'll run, on
all major operating systems with an embedded GPL barrier ZIP filesystem
that is tiny enough to transpile to JavaScript and run in browsers too.

https://justine.storage.googleapis.com/emulator625.mp4
This commit is contained in:
Justine Tunney 2020-08-25 04:23:25 -07:00
parent 467504308a
commit f4f4caab0e
1052 changed files with 65667 additions and 7825 deletions

View file

@ -81,20 +81,19 @@ bool isregularfile(const char *);
bool32 isatty(int) nosideeffect;
bool32 ischardev(int) nosideeffect;
char *get_current_dir_name(void) nodiscard;
char *getcwd(char *, size_t) paramsnonnull();
char *getcwd(char *, size_t);
char *realpath(const char *, char *);
char *replaceuser(const char *) nodiscard;
char *slurp(const char *, size_t *) nodiscard;
char *ttyname(int);
const char *commandv(const char *);
int access(const char *, int) nothrow paramsnonnull();
int access(const char *, int) nothrow;
int arch_prctl();
int chdir(const char *) paramsnonnull();
int chdir(const char *);
int chmod(const char *, uint32_t);
int chown(const char *, uint32_t, uint32_t) paramsnonnull();
int chown(const char *, uint32_t, uint32_t);
int close(int);
int closedir(DIR *);
int copyfile(const char *, const char *, bool);
int creat(const char *, uint32_t) nodiscard;
int dirfd(DIR *);
int dup(int) nodiscard;
@ -119,7 +118,7 @@ int fdatasync(int);
int filecmp(const char *, const char *);
int flock(int, int);
int fork(void);
int fstat(int, struct stat *) paramsnonnull();
int fstat(int, struct stat *);
int fstatat(int, const char *, struct stat *, uint32_t);
int fsync(int);
int ftruncate(int, int64_t);
@ -131,7 +130,7 @@ int kill(int, int);
int killpg(int, int);
int link(const char *, const char *) nothrow;
int linkat(int, const char *, int, const char *, uint32_t);
int lstat(const char *, struct stat *) paramsnonnull();
int lstat(const char *, struct stat *);
int madvise(void *, uint64_t, int);
int mkdir(const char *, uint32_t);
int mkdirat(int, const char *, uint32_t);
@ -141,7 +140,7 @@ int mknodat(int, const char *, int32_t, uint64_t);
int mlock(const void *, size_t);
int mlock2(const void *, size_t, int);
int mlockall(int);
int mprotect(void *, uint64_t, int) paramsnonnull() privileged;
int mprotect(void *, uint64_t, int) privileged;
int msync(void *, size_t, int);
int munlock(const void *, size_t);
int munlockall(void);
@ -150,11 +149,11 @@ int munmap_s(void *, uint64_t);
int nice(int);
int open(const char *, int, ...) nodiscard;
int openanon(char *, unsigned) nodiscard;
int openat();
int openat(int, const char *, int, ...);
int pause(void);
int personality(uint64_t);
int pipe(int[hasatleast 2]) paramsnonnull() nodiscard;
int pipe2(int[hasatleast 2], int) paramsnonnull() nodiscard;
int pipe(int[hasatleast 2]) nodiscard;
int pipe2(int[hasatleast 2], int) nodiscard;
int posix_fadvise(int, uint64_t, uint64_t, int);
int posix_fallocate(int, int64_t, int64_t);
int posix_madvise(void *, uint64_t, int);
@ -184,7 +183,7 @@ int sigaction(int, const struct sigaction *, struct sigaction *);
int sigignore(int);
int sigprocmask(int, const struct sigset *, struct sigset *);
int sigsuspend(const struct sigset *);
int stat(const char *, struct stat *) paramsnonnull();
int stat(const char *, struct stat *);
int symlink(const char *, const char *);
int symlinkat(const char *, int, const char *);
int sync_file_range(int, int64_t, int64_t, unsigned);
@ -230,7 +229,7 @@ uint32_t gettid(void) nosideeffect;
uint32_t getuid(void) nosideeffect;
uint32_t umask(int32_t);
void *getprocaddressmodule(const char *, const char *);
void *mmap(void *, uint64_t, int32_t, int32_t, int32_t, int64_t) vallocesque;
void *mmap(void *, uint64_t, int32_t, int32_t, int32_t, int64_t);
void *mremap(void *, uint64_t, uint64_t, int32_t, void *);
#define getcwd(BUF, SIZE) \

View file

@ -20,12 +20,14 @@
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/sysv/errfuns.h"
/**
* Sets current directory.
* @asyncsignalsafe
*/
int chdir(const char *path) {
if (!path) return efault();
if (!IsWindows()) {
return chdir$sysv(path);
} else {

View file

@ -45,5 +45,6 @@
* @see fchmod()
*/
int chmod(const char *pathname, uint32_t mode) {
if (!pathname) return efault();
return fchmodat$sysv(AT_FDCWD, pathname, mode, 0);
}

View file

@ -20,6 +20,7 @@
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
/**
* Changes owner and/or group of pathname.
@ -34,5 +35,6 @@
* @asyncsignalsafe
*/
int chown(const char *pathname, uint32_t uid, uint32_t gid) {
if (!pathname) return efault();
return fchownat$sysv(AT_FDCWD, pathname, uid, gid, 0);
}

View file

@ -17,10 +17,9 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/sock/internal.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.h"
@ -33,7 +32,7 @@
*/
int close(int fd) {
int rc;
if (fd == -1) return 0;
if (fd == -1) return einval();
if (isfdkind(fd, kFdZip)) {
rc = weaken(__zipos_close)(
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle);

View file

@ -49,9 +49,9 @@ textwindows int fstat$nt(int64_t handle, struct stat *st) {
: (((filetype == kNtFileTypeDisk) ? S_IFBLK : 0) |
((filetype == kNtFileTypeChar) ? S_IFCHR : 0) |
((filetype == kNtFileTypePipe) ? S_IFIFO : 0))));
filetimetotimespec(&st->st_atim, wst.ftLastAccessFileTime);
filetimetotimespec(&st->st_mtim, wst.ftLastWriteFileTime);
filetimetotimespec(&st->st_ctim, wst.ftCreationFileTime);
st->st_atim = filetimetotimespec(wst.ftLastAccessFileTime);
st->st_mtim = filetimetotimespec(wst.ftLastWriteFileTime);
st->st_ctim = filetimetotimespec(wst.ftCreationFileTime);
st->st_size = (uint64_t)wst.nFileSizeHigh << 32 | wst.nFileSizeLow;
st->st_blksize = PAGESIZE;
st->st_dev = wst.dwVolumeSerialNumber;

View file

@ -23,7 +23,7 @@
* Supports fstat(), etc. implementations.
* @asyncsignalsafe
*/
int32_t fstat$sysv(int32_t fd, struct stat *st) {
textstartup int32_t fstat$sysv(int32_t fd, struct stat *st) {
int res;
if ((res = __fstat$sysv(fd, st)) != -1) {
stat2linux(st);

View file

@ -17,7 +17,7 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"

View file

@ -17,18 +17,19 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/bits/initializer.h"
#include "libc/bits/pushpop.h"
#include "libc/calls/internal.h"
#include "libc/macros.h"
#include "libc/nt/runtime.h"
#include "libc/sysv/consts/fileno.h"
STATIC_YOINK("_init_g_fds");
struct Fds g_fds;
INITIALIZER(300, _init_g_fds, {
void InitializeFileDescriptors(void) {
struct Fds *fds;
fds = VEIL("D", &g_fds);
fds = VEIL("r", &g_fds);
pushmov(&fds->f, 3ul);
pushmov(&fds->n, ARRAYLEN(fds->__init_p));
fds->p = fds->__init_p;
@ -40,4 +41,4 @@ INITIALIZER(300, _init_g_fds, {
GetStdHandle(pushpop(kNtStdOutputHandle));
fds->__init_p[STDERR_FILENO].handle =
GetStdHandle(pushpop(kNtStdErrorHandle));
})
}

29
libc/calls/g_fds_init.S Normal file
View file

@ -0,0 +1,29 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
.init.start 300,_init_g_fds
push %rdi
push %rsi
call InitializeFileDescriptors
pop %rsi
pop %rdi
.init.end 300,_init_g_fds
.source __FILE__

View file

@ -35,23 +35,28 @@
* @error ERANGE, EINVAL
*/
char *(getcwd)(char *buf, size_t size) {
buf[0] = '\0';
if (!IsWindows()) {
int olderr = errno;
if (getcwd$sysv(buf, size) != NULL) {
return buf;
} else if (IsXnu() && errno == ENOSYS) {
if (size >= 2) {
buf[0] = '.'; /* XXX: could put forth more effort */
buf[1] = '\0';
errno = olderr;
if (buf) {
buf[0] = '\0';
if (!IsWindows()) {
int olderr = errno;
if (getcwd$sysv(buf, size) != NULL) {
return buf;
} else {
erange();
} else if (IsXnu() && errno == ENOSYS) {
if (size >= 2) {
buf[0] = '.'; /* XXX: could put forth more effort */
buf[1] = '\0';
errno = olderr;
return buf;
} else {
erange();
}
}
return NULL;
} else {
return getcwd$nt(buf, size);
}
return NULL;
} else {
return getcwd$nt(buf, size);
efault();
return NULL;
}
}

View file

@ -26,10 +26,13 @@
* Returns value of environment variable, or NULL if not found.
*/
char *getenv(const char *name) {
char *empty[1] = {NULL};
char **ep = firstnonnull(environ, empty);
unsigned namelen = strlen(name);
for (int i = 0; ep[i]; ++i) {
char **ep;
size_t i, namelen;
char *empty[1] = {0};
ep = environ;
if (!ep) ep = empty;
namelen = strlen(name);
for (i = 0; ep[i]; ++i) {
if (strncmp(ep[i], name, namelen) == 0 && ep[i][namelen] == '=') {
return &ep[i][namelen + 1];
}

45
libc/calls/getrusage-nt.c Normal file
View file

@ -0,0 +1,45 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/rusage.h"
#include "libc/conv/conv.h"
#include "libc/nt/accounting.h"
#include "libc/nt/runtime.h"
#include "libc/nt/thread.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/rusage.h"
textwindows int getrusage$nt(int who, struct rusage *usage) {
struct NtFileTime CreationFileTime;
struct NtFileTime ExitFileTime;
struct NtFileTime KernelFileTime;
struct NtFileTime UserFileTime;
memset(usage, 0, sizeof(*usage));
if ((who == RUSAGE_SELF ? GetProcessTimes : GetThreadTimes)(
(who == RUSAGE_SELF ? GetCurrentProcess : GetCurrentThread)(),
&CreationFileTime, &ExitFileTime, &KernelFileTime, &UserFileTime)) {
filetimetotimeval(&usage->ru_utime, UserFileTime);
filetimetotimeval(&usage->ru_stime, KernelFileTime);
return 0;
} else {
return winerr();
}
}

View file

@ -19,35 +19,8 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/rusage.h"
#include "libc/conv/conv.h"
#include "libc/dce.h"
#include "libc/nt/accounting.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/filetime.h"
#include "libc/nt/thread.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/rusage.h"
#include "libc/sysv/errfuns.h"
static textwindows noinline int getrusage$nt(int who, struct rusage *usage) {
struct NtFileTime CreationFileTime;
struct NtFileTime ExitFileTime;
struct NtFileTime KernelFileTime;
struct NtFileTime UserFileTime;
memset(usage, 0, sizeof(*usage));
if ((who == RUSAGE_SELF ? GetProcessTimes : GetThreadTimes)(
(who == RUSAGE_SELF ? GetCurrentProcess : GetCurrentThread)(),
&CreationFileTime, &ExitFileTime, &KernelFileTime, &UserFileTime)) {
filetimetotimeval(&usage->ru_utime, UserFileTime);
filetimetotimeval(&usage->ru_stime, KernelFileTime);
return 0;
} else {
return winerr();
}
}
/**
* Returns resource usage statistics.
*

View file

@ -18,7 +18,7 @@
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/bits/weaken.h"
#include "libc/calls/internal.h"
#include "libc/mem/mem.h"
#include "libc/sysv/errfuns.h"

View file

@ -17,10 +17,11 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/dce.h"
#include "libc/calls/internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
/**
* Checks if effective user can access path in particular ways.
@ -31,6 +32,7 @@
* @asyncsignalsafe
*/
int access(const char *path, int mode) {
if (!path) return efault();
if (!IsWindows()) {
return faccessat$sysv(AT_FDCWD, path, mode, 0);
} else {

108
libc/calls/hefty/copyfile.c Normal file
View file

@ -0,0 +1,108 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/hefty/copyfile.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/stat.h"
#include "libc/dce.h"
#include "libc/nt/createfile.h"
#include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/creationdisposition.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/madv.h"
#include "libc/sysv/consts/o.h"
#include "libc/time/time.h"
static textwindows int copyfile$nt(const char *src, const char *dst,
int flags) {
int64_t fhsrc, fhdst;
struct NtFileTime accessed, modified;
char16_t src16[PATH_MAX], dst16[PATH_MAX];
if (mkntpath(src, src16) == -1) return -1;
if (mkntpath(dst, dst16) == -1) return -1;
if (CopyFile(src16, dst16, !!(flags & COPYFILE_NOCLOBBER))) {
if (flags & COPYFILE_PRESERVE_TIMESTAMPS) {
fhsrc = CreateFile(src16, kNtFileReadAttributes, kNtFileShareRead, NULL,
kNtOpenExisting, kNtFileAttributeNormal, 0);
fhdst = CreateFile(dst16, kNtFileWriteAttributes, kNtFileShareRead, NULL,
kNtOpenExisting, kNtFileAttributeNormal, 0);
if (fhsrc != -1 && fhdst != -1) {
GetFileTime(fhsrc, NULL, &accessed, &modified);
SetFileTime(fhdst, NULL, &accessed, &modified);
}
CloseHandle(fhsrc);
CloseHandle(fhdst);
}
return 0;
} else {
return winerr();
}
}
static int copyfile$sysv(const char *src, const char *dst, int flags) {
struct stat st;
size_t remaining;
ssize_t transferred;
struct timespec amtime[2];
int64_t inoffset, outoffset;
int rc, srcfd, dstfd, oflags, omode;
rc = -1;
if ((srcfd = openat$sysv(AT_FDCWD, src, O_RDONLY, 0)) != -1) {
if (fstat$sysv(srcfd, &st) != -1) {
omode = st.st_mode & 0777;
oflags = O_WRONLY | O_CREAT;
if (flags & COPYFILE_NOCLOBBER) oflags |= O_EXCL;
if ((dstfd = openat$sysv(AT_FDCWD, dst, oflags, omode)) != -1) {
remaining = st.st_size;
ftruncate(dstfd, remaining);
inoffset = 0;
outoffset = 0;
while (remaining &&
(transferred = copy_file_range(
srcfd, &inoffset, dstfd, &outoffset, remaining, 0)) != -1) {
remaining -= transferred;
}
if (!remaining) {
rc = 0;
if (flags & COPYFILE_PRESERVE_TIMESTAMPS) {
amtime[0] = st.st_atim;
amtime[1] = st.st_mtim;
utimensat$sysv(dstfd, NULL, amtime, 0);
}
}
rc |= close$sysv(dstfd);
}
}
rc |= close$sysv(srcfd);
}
return rc;
}
/**
* Copies file.
*/
int copyfile(const char *src, const char *dst, int flags) {
if (!IsWindows()) {
return copyfile$sysv(src, dst, flags);
} else {
return copyfile$nt(src, dst, flags);
}
}

View file

@ -0,0 +1,15 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_HEFTY_COPYFILE_H_
#define COSMOPOLITAN_LIBC_CALLS_HEFTY_COPYFILE_H_
#define COPYFILE_NOCLOBBER 1
#define COPYFILE_PRESERVE_OWNER 2
#define COPYFILE_PRESERVE_TIMESTAMPS 4
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
int copyfile(const char *, const char *, int) paramsnonnull();
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_HEFTY_COPYFILE_H_ */

View file

@ -0,0 +1,30 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/hefty/internal.h"
#include "libc/calls/internal.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
int faccessat$nt(int dirfd, const char *path, int mode, uint32_t flags) {
char16_t path16[PATH_MAX];
if (dirfd != AT_FDCWD || flags) return einval();
if (mkntpath(path, path16) == -1) return -1;
return ntaccesscheck(path16, mode);
}

View file

@ -18,6 +18,7 @@
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/calls/hefty/internal.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/sysv/consts/at.h"
@ -33,12 +34,10 @@
* @asyncsignalsafe
*/
int faccessat(int dirfd, const char *path, int mode, uint32_t flags) {
if (!path) return efault();
if (!IsWindows()) {
return faccessat$sysv(dirfd, path, mode, flags);
} else {
char16_t path16[PATH_MAX];
if (dirfd != AT_FDCWD || flags) return einval();
if (mkntpath(path, path16) == -1) return -1;
return ntaccesscheck(path16, mode);
return faccessat$nt(dirfd, path, mode, flags);
}
}

View file

@ -36,17 +36,18 @@ LIBC_CALLS_HEFTY_A_CHECKS = \
LIBC_CALLS_HEFTY_A_DIRECTDEPS = \
LIBC_ALG \
LIBC_CALLS \
LIBC_CONV \
LIBC_FMT \
LIBC_MEM \
LIBC_STR \
LIBC_NEXGEN32E \
LIBC_RUNTIME \
LIBC_CALLS \
LIBC_STUBS \
LIBC_NT_KERNELBASE \
LIBC_RUNTIME \
LIBC_STR \
LIBC_STUBS \
LIBC_SYSV \
LIBC_SYSV_CALLS \
LIBC_SYSV
LIBC_TIME
LIBC_CALLS_HEFTY_A_DEPS := \
$(call uniq,$(foreach x,$(LIBC_CALLS_HEFTY_A_DIRECTDEPS),$($(x))))

View file

@ -3,6 +3,7 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
int faccessat$nt(int, const char *, int, uint32_t) hidden;
int execve$nt(const char *, char *const[], char *const[]) hidden;
int spawnve$nt(unsigned, int[3], const char *, char *const[],
char *const[]) hidden;

View file

@ -35,36 +35,32 @@
* @return freshly allocated lpEnvironment or NULL w/ errno
*/
textwindows char16_t *mkntenvblock(char *const envp[]) {
size_t block_i = 0;
size_t block_n = 0;
char16_t *block_p = NULL;
size_t i, j;
if (!(envp = sortenvp(envp))) goto error;
const char16_t kNul = u'\0';
for (i = 0; envp[i]; ++i) {
unsigned consumed;
for (j = 0;; j += consumed) {
wint_t wc;
char16_t cbuf[2];
consumed = abs(tpdecode(&envp[i][j], &wc));
if (CONCAT(&block_p, &block_i, &block_n, cbuf,
abs(pututf16(cbuf, ARRAYLEN(cbuf), wc, false))) == -1) {
goto error;
wint_t wc;
size_t i, j, bi, bn;
char16_t *bp, cbuf[2];
unsigned consumed, produced;
bi = 0;
bn = 8;
bp = NULL;
if ((envp = sortenvp(envp)) && (bp = calloc(bn, sizeof(char16_t)))) {
for (i = 0; envp[i]; ++i) {
for (j = 0;; j += consumed) {
consumed = abs(tpdecode(&envp[i][j], &wc));
produced = abs(pututf16(cbuf, ARRAYLEN(cbuf), wc, false));
if (CONCAT(&bp, &bi, &bn, cbuf, produced) == -1) goto error;
if (!wc) break;
}
if (!wc) break;
}
++bi;
if (bi > ENV_MAX) {
e2big();
goto error;
}
free(envp);
return bp;
}
if (APPEND(&block_p, &block_i, &block_n, &kNul) == -1) {
goto error;
}
if (block_i > ENV_MAX) {
e2big();
goto error;
}
free(envp);
return block_p;
error:
free(envp);
free(block_p);
free(bp);
return NULL;
}

View file

@ -19,12 +19,14 @@
*/
#ifndef COSMOPOLITAN_LIBC_CALLS_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_INTERNAL_H_
#ifndef __STRICT_ANSI__
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/limits.h"
#include "libc/macros.h"
#include "libc/nt/struct/securityattributes.h"
#include "libc/nt/struct/startupinfo.h"
#include "libc/nt/struct/systeminfo.h"
#include "libc/runtime/runtime.h"
#define kSigactionMinRva 8 /* >SIG_{ERR,DFL,IGN,...} */
@ -36,6 +38,7 @@ COSMOPOLITAN_C_START_
struct NtContext;
struct NtWin32FileAttributeData;
struct ZiposHandle;
struct __darwin_siginfo;
struct __darwin_ucontext;
struct itimerval;
@ -45,7 +48,7 @@ struct sigset;
struct sysinfo;
struct timeval;
struct timezone;
struct ZiposHandle;
struct utimbuf;
struct IoctlPtmGet {
int theduxfd;
@ -62,7 +65,8 @@ struct IoctlPtmGet {
* and helps us abstract peculiarities like close() vs. closesocket().
*/
struct Fds {
size_t f, n;
size_t f; // length
size_t n; // capacity
struct Fd {
int64_t handle;
int64_t extra;
@ -132,6 +136,7 @@ i32 __dup3$sysv(i32, i32, i32) hidden;
i32 __fstat$sysv(i32, struct stat *) hidden;
i32 __fstatat$sysv(i32, const char *, struct stat *, i32) hidden;
i32 __pipe2$sysv(i32[hasatleast 2], u32) hidden;
i32 __utimensat$sysv(i32, const char *, const struct timespec *, i32) hidden;
i32 chdir$sysv(const char *) hidden;
i32 clock_gettime$sysv(i32, struct timespec *) hidden;
i32 close$sysv(i32) hidden;
@ -154,6 +159,8 @@ i32 fstat$sysv(i32, struct stat *) hidden;
i32 fstatat$sysv(i32, const char *, struct stat *, i32) hidden;
i32 fsync$sysv(i32) hidden;
i32 ftruncate$sysv(i32, i64) hidden;
i32 futimes$sysv(i32, const struct timeval *) hidden;
i32 futimesat$sysv(i32, const char *, const struct timeval *) hidden;
i32 getdents(i32, char *, u32) hidden;
i32 getppid$sysv(void) hidden;
i32 getpriority$sysv(i32, u32) hidden;
@ -164,6 +171,7 @@ i32 ioctl$sysv(i32, u64, void *) hidden;
i32 kill$sysv(i32, i32, i32) hidden;
i32 linkat$sysv(i32, const char *, i32, const char *, i32) hidden;
i32 lseek$sysv(i32, i64, i32) hidden;
i32 lutimes$sysv(const char *, const struct timeval *) hidden;
i32 madvise$sysv(void *, size_t, i32) hidden;
i32 memfd_create$sysv(const char *, u32) hidden;
i32 mkdirat$sysv(i32, const char *, u32) hidden;
@ -194,6 +202,8 @@ i32 sysinfo$sysv(struct sysinfo *) hidden;
i32 truncate$sysv(const char *, u64) hidden;
i32 uname$sysv(char *) hidden;
i32 unlinkat$sysv(i32, const char *, i32) hidden;
i32 utime$sysv(const char *, const struct utimbuf *) hidden;
i32 utimensat$sysv(i32, const char *, const struct timespec *, i32) hidden;
i32 utimes$sysv(const char *, const struct timeval *) hidden;
i32 wait4$sysv(i32, i32 *, i32, struct rusage *) hidden;
i64 copy_file_range$sysv(i32, long *, i32, long *, u64, u32) hidden;
@ -207,12 +217,12 @@ i64 sendfile$sysv(i32, i32, i64 *, u64) hidden;
i64 splice$sysv(i32, i64 *, i32, i64 *, u64, u32) hidden;
i64 vmsplice$sysv(i32, const struct iovec *, i64, u32) hidden;
i64 write$sysv(i32, const void *, u64) hidden;
int setresgid$sysv(uint32_t, uint32_t, uint32_t) hidden;
int setresuid$sysv(uint32_t, uint32_t, uint32_t) hidden;
u32 getgid$sysv(void) hidden;
u32 getpid$sysv(void) hidden;
u32 gettid$sysv(void) hidden;
u32 getuid$sysv(void) hidden;
int setresuid$sysv(uint32_t, uint32_t, uint32_t) hidden;
int setresgid$sysv(uint32_t, uint32_t, uint32_t) hidden;
void *mmap$sysv(void *, u64, u32, u32, i64, i64) hidden;
void *mremap$sysv(void *, u64, u64, i32, void *) hidden;
@ -223,13 +233,13 @@ void *mremap$sysv(void *, u64, u64, i32, void *) hidden;
int __getpid(void) hidden;
void __onfork(void) hidden;
bool32 __sigenter(i32, struct siginfo *, struct ucontext *) hidden;
i32 __mprotect(void *, u64, i32) privileged;
i32 fixupnewfd$sysv(i32, i32) hidden;
i32 tunefd$sysv(i32, i32, i32, i32) hidden;
u32 fprot2nt(i32, i32) hidden;
u32 prot2nt(i32, i32) privileged;
void __restore_rt() hidden;
void __sigenter$xnu(void *, i32, i32, void *, void *) hidden noreturn;
int utimensat$xnu(int, const char *, const struct timespec *, int) hidden;
void stat2linux(void *) hidden;
void xnutrampoline(void *, i32, i32, const struct __darwin_siginfo *,
const struct __darwin_ucontext *) hidden noreturn;
@ -271,6 +281,8 @@ int wait4$nt(int, int *, int, struct rusage *) hidden;
i64 lseek$nt(int, i64, int) hidden;
ssize_t read$nt(struct Fd *, const struct iovec *, size_t, ssize_t) hidden;
ssize_t write$nt(struct Fd *, const struct iovec *, size_t, ssize_t) hidden;
int utimensat$nt(int, const char *, const struct timespec *, int) hidden;
int getrusage$nt(int, struct rusage *) hidden;
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § syscalls » windows nt » support
@ -317,4 +329,5 @@ int __mkntpath(const char *, unsigned, char16_t[hasatleast PATH_MAX - 16])
#undef u64
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* !ANSI */
#endif /* COSMOPOLITAN_LIBC_CALLS_INTERNAL_H_ */

View file

@ -17,7 +17,7 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/bits/weaken.h"
#include "libc/calls/internal.h"
#include "libc/calls/ioctl.h"
#include "libc/nt/winsock.h"

View file

@ -32,18 +32,17 @@ textwindows int ioctl$tiocgwinsz$nt(int fd, struct winsize *ws) {
struct NtConsoleScreenBufferInfoEx sbinfo;
if (!isfdkind(fd, kFdFile)) return ebadf();
if (!GetConsoleMode(g_fds.p[fd].handle, &mode)) return enotty();
if (g_ntstartupinfo.dwFlags & kNtStartfUsecountchars) {
ws->ws_col = g_ntstartupinfo.dwXCountChars;
ws->ws_row = g_ntstartupinfo.dwYCountChars;
ws->ws_xpixel = 0;
ws->ws_ypixel = 0;
return 0;
}
memset(&sbinfo, 0, sizeof(sbinfo));
sbinfo.cbSize = sizeof(sbinfo);
if (GetConsoleScreenBufferInfoEx(g_fds.p[fd].handle, &sbinfo)) {
ws->ws_col = sbinfo.srWindow.Right;
ws->ws_row = sbinfo.srWindow.Bottom;
ws->ws_col = sbinfo.srWindow.Right - sbinfo.srWindow.Left;
ws->ws_row = sbinfo.srWindow.Bottom - sbinfo.srWindow.Top;
ws->ws_xpixel = 0;
ws->ws_ypixel = 0;
return 0;
} else if (g_ntstartupinfo.dwFlags & kNtStartfUsecountchars) {
ws->ws_col = g_ntstartupinfo.dwXCountChars;
ws->ws_row = g_ntstartupinfo.dwYCountChars;
ws->ws_xpixel = 0;
ws->ws_ypixel = 0;
return 0;

View file

@ -17,6 +17,9 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#ifdef __STRICT_ANSI__
#undef __STRICT_ANSI__
#endif
#include "libc/calls/ioctl.h"
#define EQUAL(X, Y) ((X) == (Y))

View file

@ -28,7 +28,7 @@
/**
* Returns true if file descriptor is backed by character i/o.
*/
bool32 ischardev(int fd) {
textstartup bool32 ischardev(int fd) {
int olderr;
struct stat st;
if (!IsWindows()) {

View file

@ -24,13 +24,14 @@
#include "libc/conv/conv.h"
#include "libc/dce.h"
#include "libc/log/log.h"
#include "libc/nexgen32e/vendor.h"
#include "libc/nt/struct/teb.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/o.h"
#define kBufSize 1024
#define kBufSize 1024
#define kProcStatus "/proc/self/status"
alignas(16) static const char kGdbPid[] = "TracerPid:\t";
@ -43,18 +44,20 @@ int IsDebuggerPresent(bool force) {
ssize_t got;
char buf[1024];
res = 0;
if (force || isempty(getenv("HEISENDEBUG"))) {
if (IsWindows()) {
res = NtGetPeb()->BeingDebugged;
} else if (IsLinux()) {
if ((fd = openat$sysv(AT_FDCWD, kProcStatus, O_RDONLY, 0)) != -1) {
if ((got = read$sysv(fd, buf, sizeof(buf) - sizeof(kGdbPid))) != -1) {
buf[got] = '\0';
res = atoi(firstnonnull(strstr(buf, kGdbPid), kGdbPid) +
strlen(kGdbPid));
}
close$sysv(fd);
if (!force) {
if (getenv("HEISENDEBUG")) return false;
if (IsGenuineCosmo()) return false;
}
if (IsWindows()) {
res = NtGetPeb()->BeingDebugged;
} else if (IsLinux()) {
if ((fd = openat$sysv(AT_FDCWD, kProcStatus, O_RDONLY, 0)) != -1) {
if ((got = read$sysv(fd, buf, sizeof(buf) - sizeof(kGdbPid))) != -1) {
buf[got] = '\0';
res =
atoi(firstnonnull(strstr(buf, kGdbPid), kGdbPid) + strlen(kGdbPid));
}
close$sysv(fd);
}
}
return res;

View file

@ -17,12 +17,12 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/errno.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/errno.h"
/**
* Returns true if file exists and is a directory
* Returns true if file exists and is a directory.
*/
bool isdirectory(const char *path) {
struct stat st;

View file

@ -24,33 +24,35 @@
#include "libc/nt/enum/processcreationflags.h"
#include "libc/nt/enum/threadpriority.h"
#define FFS(x) __builtin_ffs(x)
const struct NtPriorityCombo kNtPriorityCombos[] = {
{-20, ffs(kNtHighPriorityClass), kNtThreadPriorityHighest, 15},
{-18, ffs(kNtHighPriorityClass), kNtThreadPriorityTimeCritical, 15},
{-17, ffs(kNtNormalPriorityClass), kNtThreadPriorityTimeCritical, 15},
{-15, ffs(kNtIdlePriorityClass), kNtThreadPriorityTimeCritical, 15},
{-13, ffs(kNtHighPriorityClass), kNtThreadPriorityAboveNormal, 14},
{-11, ffs(kNtHighPriorityClass), kNtThreadPriorityNormal, 13},
{-9, ffs(kNtHighPriorityClass), kNtThreadPriorityBelowNormal, 12},
{-7, ffs(kNtNormalPriorityClass), kNtThreadPriorityHighest, 11},
{-5, ffs(kNtHighPriorityClass), kNtThreadPriorityLowest, 11},
{-3, ffs(kNtNormalPriorityClass), kNtThreadPriorityAboveNormal, 10},
{-1, ffs(kNtNormalPriorityClass), kNtThreadPriorityHighest, 9},
{0, ffs(kNtNormalPriorityClass), kNtThreadPriorityNormal, 9},
{1, ffs(kNtNormalPriorityClass), kNtThreadPriorityAboveNormal, 8},
{2, ffs(kNtNormalPriorityClass), kNtThreadPriorityBelowNormal, 8},
{3, ffs(kNtNormalPriorityClass), kNtThreadPriorityNormal, 7},
{4, ffs(kNtNormalPriorityClass), kNtThreadPriorityLowest, 7},
{5, ffs(kNtIdlePriorityClass), kNtThreadPriorityHighest, 6},
{6, ffs(kNtNormalPriorityClass), kNtThreadPriorityBelowNormal, 6},
{7, ffs(kNtIdlePriorityClass), kNtThreadPriorityAboveNormal, 5},
{9, ffs(kNtNormalPriorityClass), kNtThreadPriorityLowest, 5},
{11, ffs(kNtIdlePriorityClass), kNtThreadPriorityNormal, 4},
{13, ffs(kNtIdlePriorityClass), kNtThreadPriorityBelowNormal, 3},
{15, ffs(kNtIdlePriorityClass), kNtThreadPriorityLowest, 2},
{17, ffs(kNtHighPriorityClass), kNtThreadPriorityIdle, 1},
{18, ffs(kNtNormalPriorityClass), kNtThreadPriorityIdle, 1},
{19, ffs(kNtIdlePriorityClass), kNtThreadPriorityIdle, 1},
{-20, FFS(kNtHighPriorityClass), kNtThreadPriorityHighest, 15},
{-18, FFS(kNtHighPriorityClass), kNtThreadPriorityTimeCritical, 15},
{-17, FFS(kNtNormalPriorityClass), kNtThreadPriorityTimeCritical, 15},
{-15, FFS(kNtIdlePriorityClass), kNtThreadPriorityTimeCritical, 15},
{-13, FFS(kNtHighPriorityClass), kNtThreadPriorityAboveNormal, 14},
{-11, FFS(kNtHighPriorityClass), kNtThreadPriorityNormal, 13},
{-9, FFS(kNtHighPriorityClass), kNtThreadPriorityBelowNormal, 12},
{-7, FFS(kNtNormalPriorityClass), kNtThreadPriorityHighest, 11},
{-5, FFS(kNtHighPriorityClass), kNtThreadPriorityLowest, 11},
{-3, FFS(kNtNormalPriorityClass), kNtThreadPriorityAboveNormal, 10},
{-1, FFS(kNtNormalPriorityClass), kNtThreadPriorityHighest, 9},
{0, FFS(kNtNormalPriorityClass), kNtThreadPriorityNormal, 9},
{1, FFS(kNtNormalPriorityClass), kNtThreadPriorityAboveNormal, 8},
{2, FFS(kNtNormalPriorityClass), kNtThreadPriorityBelowNormal, 8},
{3, FFS(kNtNormalPriorityClass), kNtThreadPriorityNormal, 7},
{4, FFS(kNtNormalPriorityClass), kNtThreadPriorityLowest, 7},
{5, FFS(kNtIdlePriorityClass), kNtThreadPriorityHighest, 6},
{6, FFS(kNtNormalPriorityClass), kNtThreadPriorityBelowNormal, 6},
{7, FFS(kNtIdlePriorityClass), kNtThreadPriorityAboveNormal, 5},
{9, FFS(kNtNormalPriorityClass), kNtThreadPriorityLowest, 5},
{11, FFS(kNtIdlePriorityClass), kNtThreadPriorityNormal, 4},
{13, FFS(kNtIdlePriorityClass), kNtThreadPriorityBelowNormal, 3},
{15, FFS(kNtIdlePriorityClass), kNtThreadPriorityLowest, 2},
{17, FFS(kNtHighPriorityClass), kNtThreadPriorityIdle, 1},
{18, FFS(kNtNormalPriorityClass), kNtThreadPriorityIdle, 1},
{19, FFS(kNtIdlePriorityClass), kNtThreadPriorityIdle, 1},
};
const unsigned kNtPriorityCombosLen = ARRAYLEN(kNtPriorityCombos);

View file

@ -17,16 +17,14 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/sysv/consts/at.h"
/**
* Modifies restrictions on virtual memory address range.
*
* @param prot can have PROT_{NONE,READ,WRITE,EXEC,GROWSDOWN}
* @return 0 on success, or -1 w/ errno
* @see mmap()
*/
int mprotect(void *addr, uint64_t len, int prot) {
return __mprotect(addr, len, prot);
int mkdirat(int dirfd, const char *pathname, unsigned mode) {
if (dirfd == AT_FDCWD) {
return mkdir(pathname, mode);
} else {
return mkdirat$sysv(dirfd, pathname, mode);
}
}

View file

@ -39,8 +39,9 @@
* @return short count excluding NUL on success, or -1 w/ errno
* @error ENAMETOOLONG
*/
textwindows int(mkntpath)(const char *path, unsigned flags,
char16_t path16[hasatleast PATH_MAX - 16]) {
forcealignargpointer textwindows int(mkntpath)(
const char *path, unsigned flags,
char16_t path16[hasatleast PATH_MAX - 16]) {
/*
* 1. Reserve +1 for NUL-terminator
* 2. Reserve +1 for UTF-16 overflow

View file

@ -26,7 +26,14 @@
#include "libc/nt/thunk/msabi.h"
#include "libc/sysv/consts/nr.h"
privileged int __mprotect(void *addr, uint64_t len, int prot) {
/**
* Modifies restrictions on virtual memory address range.
*
* @param prot can have PROT_{NONE,READ,WRITE,EXEC,GROWSDOWN}
* @return 0 on success, or -1 w/ errno
* @see mmap()
*/
int mprotect(void *addr, uint64_t len, int prot) {
extern __msabi typeof(VirtualProtect) *const __imp_VirtualProtect;
bool cf;
int64_t rc;

View file

@ -17,7 +17,7 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"

View file

@ -19,46 +19,31 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/stat.h"
#include "libc/dce.h"
#include "libc/nt/files.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/madv.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
int copyfile(const char *frompath, const char *topath, bool dontoverwrite) {
if (IsWindows()) {
char16_t frompath16[PATH_MAX], topath16[PATH_MAX];
if (mkntpath(frompath, frompath16) == -1) return -1;
if (mkntpath(topath, topath16) == -1) return -1;
if (CopyFile(frompath16, topath16, dontoverwrite)) {
return 0;
} else {
return winerr();
}
/**
* Opens file, the modern way.
*
* @param dirfd is normally AT_FDCWD or an open relative directory thing
* @param file is a UTF-8 string, preferably relative w/ forward slashes
* @param flags should be O_RDONLY, O_WRONLY, or O_RDWR, and can be or'd
* with O_CREAT, O_TRUNC, O_APPEND, O_EXCL, O_CLOEXEC, O_TMPFILE
* @param mode is an octal user/group/other permission signifier, that's
* ignored if O_CREAT or O_TMPFILE weren't passed
* @return number needing close(), or -1 w/ errno
* @asyncsignalsafe
*/
int openat(int dirfd, const char *pathname, int flags, ...) {
va_list va;
unsigned mode;
va_start(va, flags);
mode = va_arg(va, unsigned);
va_end(va);
if (!pathname) return efault();
if (dirfd == AT_FDCWD) {
return open(pathname, flags, mode);
} else {
struct stat st;
ssize_t transferred;
int rc, fromfd, tofd;
int64_t inoffset, outoffset;
rc = -1;
if ((fromfd = openat$sysv(AT_FDCWD, frompath, O_RDONLY, 0)) != -1) {
if (fstat$sysv(fromfd, &st) != -1 &&
(tofd = openat$sysv(AT_FDCWD, topath,
O_WRONLY | O_CREAT | (dontoverwrite ? O_EXCL : 0),
st.st_mode & 0777)) != -1) {
inoffset = 0;
outoffset = 0;
while (st.st_size && (transferred = copy_file_range(
fromfd, &inoffset, tofd, &outoffset,
st.st_size, 0)) != -1) {
st.st_size -= transferred;
}
if (!st.st_size) rc = 0;
rc |= close$sysv(tofd);
}
rc |= close$sysv(fromfd);
}
return rc;
return openat$sysv(dirfd, pathname, flags, mode);
}
}

View file

@ -20,6 +20,7 @@
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/sysv/errfuns.h"
/**
* Creates file-less file descriptors for inter-process communication.
@ -30,6 +31,7 @@
* @see pipe2()
*/
int pipe(int pipefd[hasatleast 2]) {
if (!pipefd) return efault();
if (!IsWindows()) {
return pipe$sysv(pipefd);
} else {

View file

@ -20,6 +20,7 @@
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/sysv/errfuns.h"
/**
* Creates file-less file descriptors for interprocess communication.
@ -29,6 +30,7 @@
* @return 0 on success, or -1 w/ errno and pipefd isn't modified
*/
int pipe2(int pipefd[hasatleast 2], int flags) {
if (!pipefd) return efault();
if (!IsWindows()) {
return pipe2$sysv(pipefd, flags);
} else {

View file

@ -18,7 +18,7 @@
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"

View file

@ -18,7 +18,7 @@
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h"

View file

@ -17,6 +17,7 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h"

View file

@ -17,17 +17,20 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/dce.h"
#include "libc/calls/internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
/**
* Moves file the Unix way.
*
* @return 0 on success or -1 w/ errno
* @asyncsignalsafe
*/
int rename(const char *oldpathname, const char *newpathname) {
if (!oldpathname || !newpathname) return efault();
if (!IsWindows()) {
return renameat$sysv(AT_FDCWD, oldpathname, AT_FDCWD, newpathname);
} else {

32
libc/calls/renameat.c Normal file
View file

@ -0,0 +1,32 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/sysv/consts/at.h"
int renameat(int olddirfd, const char *oldpath, int newdirfd,
const char *newpath) {
unsigned mode;
if (olddirfd == AT_FDCWD && newdirfd == AT_FDCWD) {
return rename(oldpath, newpath);
} else {
return renameat$sysv(olddirfd, oldpath, newdirfd, newpath);
}
}

View file

@ -30,10 +30,14 @@
static textwindows noinline int sched_setaffinity$nt(int pid,
uint64_t bitsetsize,
const void *bitset) {
int rc;
uintptr_t mask;
int64_t handle;
typeof(SetThreadAffinityMask) *SetAffinityMask = SetThreadAffinityMask;
uintptr_t mask = 0;
mask = 0;
memcpy(&mask, bitset, min(bitsetsize, sizeof(uintptr_t)));
int64_t handle = 0;
handle = 0;
if (!pid) pid = GetCurrentThreadId();
if (0 < pid && pid <= UINT32_MAX) {
if (pid == GetCurrentProcessId()) {
pid = GetCurrentProcess();
@ -50,7 +54,7 @@ static textwindows noinline int sched_setaffinity$nt(int pid,
}
}
}
int rc = SetAffinityMask(handle ? handle : pid, mask) ? 0 : winerr();
rc = SetAffinityMask(handle ? handle : pid, mask) ? 0 : winerr();
if (handle) CloseHandle(handle);
return rc;
}
@ -58,7 +62,7 @@ static textwindows noinline int sched_setaffinity$nt(int pid,
/**
* Asks kernel to only schedule process on particular CPUs.
*
* @param pid is the process or thread id
* @param pid is the process or thread id (or 0 for caller)
* @param bitsetsize is byte length of bitset
* @param bitset can be manipulated using bt(), bts(), etc.
* @return 0 on success, or -1 w/ errno

View file

@ -20,7 +20,12 @@
#include "libc/bits/bits.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/sigaction-freebsd.h"
#include "libc/calls/struct/sigaction-linux.h"
#include "libc/calls/struct/sigaction-openbsd.h"
#include "libc/calls/struct/sigaction-xnu.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/typedef/sigaction_f.h"
#include "libc/calls/ucontext.h"
#include "libc/dce.h"
#include "libc/limits.h"
@ -32,51 +37,13 @@
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
struct siginfo;
union metasigaction {
struct sigaction cosmo;
struct sigaction$linux {
intptr_t sa_handler;
uint64_t sa_flags;
void (*sa_restorer)(void);
struct sigset$linux {
uint32_t sig[2];
} sa_mask;
} linux;
struct sigaction$freebsd {
intptr_t sa_handler;
uint32_t sa_flags;
struct sigset$freebsd {
uint32_t sig[4];
} sa_mask;
} freebsd;
struct sigaction$openbsd {
intptr_t sa_handler;
struct sigset$openbsd {
uint32_t sig[1];
} sa_mask;
int32_t sa_flags;
} openbsd;
struct sigaction$xnu_in {
intptr_t sa_handler;
void (*sa_restorer)(void *, int, int, const struct __darwin_siginfo *,
const struct __darwin_ucontext *);
struct sigset$xnu {
uint32_t sig[1];
} sa_mask;
int32_t sa_flags;
} xnu_in;
struct sigaction$xnu_out {
intptr_t sa_handler;
struct sigset$xnu sa_mask;
int32_t sa_flags;
} xnu_out;
struct sigaction$linux linux;
struct sigaction$freebsd freebsd;
struct sigaction$openbsd openbsd;
struct sigaction$xnu_in xnu_in;
struct sigaction$xnu_out xnu_out;
};
#define SWITCHEROO(S1, S2, A, B, C, D) \
@ -210,9 +177,8 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
if (rc != -1) {
if (oldact) {
oldrva = g_sighandrvas[sig];
oldact->sa_sigaction = oldrva < kSigactionMinRva
? (sigaction_f)(intptr_t)oldrva
: (sigaction_f)((uintptr_t)&_base + oldrva);
oldact->sa_sigaction = (sigaction_f)(
oldrva < kSigactionMinRva ? oldrva : (intptr_t)&_base + oldrva);
}
if (act) {
g_sighandrvas[sig] = rva;

View file

@ -17,10 +17,10 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/dce.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/sysv/errfuns.h"
/**
@ -31,6 +31,7 @@
* @asyncsignalsafe
*/
int sigsuspend(const sigset_t *mask) {
if (!mask) return efault();
if (!IsWindows()) {
return sigsuspend$sysv(mask, 8);
} else {

View file

@ -17,7 +17,7 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"

View file

@ -73,7 +73,7 @@ forceinline void stat2linux_openbsd(union metastat *ms) {
* Transcodes The Dismal Data Structure from BSDLinux ABI.
* @asyncsignalsafe
*/
void stat2linux(void *ms) {
textstartup void stat2linux(void *ms) {
if (ms) {
if (SupportsXnu() && IsXnu()) {
stat2linux_xnu((union metastat *)ms);

View file

@ -1,5 +1,6 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_METASTAT_H_
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_METASTAT_H_
#ifndef __STRICT_ANSI__
#include "libc/calls/struct/stat.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
@ -52,4 +53,5 @@ union metastat {
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* !ANSI */
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_METASTAT_H_ */

View file

@ -1,5 +1,6 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_METATERMIOS_H_
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_METATERMIOS_H_
#ifndef __STRICT_ANSI__
#include "libc/calls/struct/termios.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
@ -32,4 +33,5 @@ union metatermios {
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* !ANSI */
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_METATERMIOS_H_ */

View file

@ -0,0 +1,14 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_FREEBSD_H_
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_FREEBSD_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
struct sigaction$freebsd {
intptr_t sa_handler;
uint32_t sa_flags;
struct sigset$freebsd {
uint32_t sig[4];
} sa_mask;
};
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_FREEBSD_H_ */

View file

@ -0,0 +1,15 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_LINUX_H_
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_LINUX_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
struct sigaction$linux {
intptr_t sa_handler;
uint64_t sa_flags;
void (*sa_restorer)(void);
struct sigset$linux {
uint32_t sig[2];
} sa_mask;
};
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_LINUX_H_ */

View file

@ -0,0 +1,14 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_OPENBSD_H_
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_OPENBSD_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
struct sigaction$openbsd {
intptr_t sa_handler;
struct sigset$openbsd {
uint32_t sig[1];
} sa_mask;
int32_t sa_flags;
};
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_OPENBSD_H_ */

View file

@ -0,0 +1,28 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_XNU_H_
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_XNU_H_
#include "libc/calls/internal.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
struct __darwin_ucontext;
struct __darwin_siginfo;
struct sigset$xnu {
uint32_t sig[1];
};
struct sigaction$xnu_in {
intptr_t sa_handler;
void (*sa_restorer)(void *, int, int, const struct __darwin_siginfo *,
const struct __darwin_ucontext *);
struct sigset$xnu sa_mask;
int32_t sa_flags;
};
struct sigaction$xnu_out {
intptr_t sa_handler;
struct sigset$xnu sa_mask;
int32_t sa_flags;
};
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_XNU_H_ */

View file

@ -10,7 +10,5 @@ struct sigaltstack {
typedef struct sigaltstack stack_t;
static_assert(sizeof(stack_t) == 24);
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGALTSTACK_H_ */

View file

@ -2,7 +2,7 @@
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGSET_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
struct sigset {
struct sigset { /* cosmo abi (linux is uint64_t) */
uint32_t sig[4]; /* ignore sig[2] and sig[3] (for freebsd) */
} aligned(8);

View file

@ -1,5 +1,6 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_TERMIOS_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_TERMIOS_INTERNAL_H_
#ifndef __STRICT_ANSI__
#include "libc/bits/safemacros.h"
#include "libc/str/str.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
@ -26,4 +27,5 @@ void termios2linux(struct termios *, const union metatermios *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* !ANSI */
#endif /* COSMOPOLITAN_LIBC_CALLS_TERMIOS_INTERNAL_H_ */

View file

@ -12,10 +12,10 @@ COSMOPOLITAN_C_START_
cosmopolitan § teletypewriter control
*/
int tcgetattr(int fd, struct termios *tio);
int tcsetattr(int fd, int opt, const struct termios *tio);
int tcsetpgrp(int fd, int32_t pgrp);
int32_t tcgetpgrp(int fd);
int tcgetattr(int, struct termios *);
int tcsetattr(int, int, const struct termios *);
int tcsetpgrp(int, int32_t);
int32_t tcgetpgrp(int);
int openpty(int *, int *, char *, const struct termios *,
const struct winsize *) paramsnonnull((1, 2)) nodiscard;

View file

@ -20,6 +20,7 @@
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/sysv/errfuns.h"
/**
* Reduces or extends underlying physical medium of file.
@ -32,6 +33,7 @@
* @error ENOENT
*/
int truncate(const char *path, uint64_t length) {
if (!path) return efault();
if (!IsWindows()) {
return truncate$sysv(path, length);
} else {

View file

@ -6,29 +6,29 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define REG_R8 REG_R8
#define REG_R9 REG_R9
#define REG_R10 REG_R10
#define REG_R11 REG_R11
#define REG_R12 REG_R12
#define REG_R13 REG_R13
#define REG_R14 REG_R14
#define REG_R15 REG_R15
#define REG_RDI REG_RDI
#define REG_RSI REG_RSI
#define REG_RBP REG_RBP
#define REG_RBX REG_RBX
#define REG_RDX REG_RDX
#define REG_RAX REG_RAX
#define REG_RCX REG_RCX
#define REG_RSP REG_RSP
#define REG_RIP REG_RIP
#define REG_EFL REG_EFL
#define REG_CSGSFS REG_CSGSFS
#define REG_ERR REG_ERR
#define REG_TRAPNO REG_TRAPNO
#define REG_R8 REG_R8
#define REG_R9 REG_R9
#define REG_R10 REG_R10
#define REG_R11 REG_R11
#define REG_R12 REG_R12
#define REG_R13 REG_R13
#define REG_R14 REG_R14
#define REG_R15 REG_R15
#define REG_RDI REG_RDI
#define REG_RSI REG_RSI
#define REG_RBP REG_RBP
#define REG_RBX REG_RBX
#define REG_RDX REG_RDX
#define REG_RAX REG_RAX
#define REG_RCX REG_RCX
#define REG_RSP REG_RSP
#define REG_RIP REG_RIP
#define REG_EFL REG_EFL
#define REG_CSGSFS REG_CSGSFS
#define REG_ERR REG_ERR
#define REG_TRAPNO REG_TRAPNO
#define REG_OLDMASK REG_OLDMASK
#define REG_CR2 REG_CR2
#define REG_CR2 REG_CR2
enum GeneralRegister {
REG_R8,
@ -60,16 +60,12 @@ struct XmmRegister {
uint64_t u64[2];
};
static_assert(sizeof(struct XmmRegister) == 16);
struct FpuStackEntry {
uint16_t significand[4];
uint16_t exponent;
uint16_t padding[3];
};
static_assert(sizeof(struct FpuStackEntry) == 16);
struct FpuState {
uint16_t cwd;
uint16_t swd;

View file

@ -17,12 +17,12 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/nt/files.h"
#include "libc/str/str.h"
#include "libc/calls/internal.h"
#include "libc/sysv/errfuns.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
/**
* Deletes file.
@ -36,7 +36,7 @@
* @asyncsignalsafe
*/
int unlink(const char *name) {
if (!name) return 0;
if (!name) return efault();
if (!IsWindows()) {
return unlinkat$sysv(AT_FDCWD, name, 0);
} else {

View file

@ -19,7 +19,6 @@
*/
#include "libc/bits/bits.h"
#include "libc/calls/calls.h"
#include "libc/runtime/mappings.h"
/**
* Deletes file, the Cosmopolitan way.

30
libc/calls/unlinkat.c Normal file
View file

@ -0,0 +1,30 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/sysv/consts/at.h"
int unlinkat(int dirfd, const char *pathname, int flags) {
if (dirfd == AT_FDCWD) {
return unlink(pathname);
} else {
return unlinkat$sysv(dirfd, pathname, flags);
}
}

View file

@ -21,45 +21,46 @@
#include "libc/dce.h"
#include "libc/fmt/fmt.h"
#include "libc/limits.h"
#include "libc/macros.h"
#include "libc/nt/files.h"
#include "libc/sysv/errfuns.h"
#define DBUFSIZ 1460 /* tcp ethernet frame < -Wframe-larger-than=4096 */
struct dfile {
struct VdprintfState {
int n;
int fd;
unsigned idx;
unsigned toto;
unsigned char buf[DBUFSIZ];
unsigned char buf[1024];
};
static int vdprintf_flush(struct dfile *df) {
ssize_t wrote;
do {
wrote = write(df->fd, &df->buf[0], df->idx);
if (wrote == -1) return -1;
df->toto += (unsigned)wrote;
df->idx -= (unsigned)wrote;
if (df->toto > INT_MAX) return eoverflow();
} while (df->idx);
static int vdprintf_flush(struct VdprintfState *df, int n) {
int i, rc;
for (i = 0; i < n; i += rc) {
if ((rc = write(df->fd, df->buf + i, n - i)) == -1) {
return -1;
}
}
return 0;
}
static int vdprintfputchar(unsigned char c, struct dfile *df) {
df->buf[df->idx++] = c;
if (df->idx == DBUFSIZ && vdprintf_flush(df) == -1) return -1;
return 0;
static int vdprintfputchar(int c, struct VdprintfState *df) {
df->buf[df->n++ & (ARRAYLEN(df->buf) - 1)] = c & 0xff;
if ((df->n & (ARRAYLEN(df->buf) - 1))) {
return 0;
} else {
return vdprintf_flush(df, ARRAYLEN(df->buf));
}
}
/**
* Formats string directly to system i/o device.
*/
int(vdprintf)(int fd, const char *fmt, va_list va) {
struct dfile df;
struct VdprintfState df;
df.n = 0;
df.fd = fd;
df.idx = 0;
df.toto = 0;
if (palandprintf(vdprintfputchar, &df, fmt, va) == -1) return -1;
if (df.idx && vdprintf_flush(&df) == -1) return -1;
return df.toto;
if (palandprintf(vdprintfputchar, &df, fmt, va) != -1 ||
vdprintf_flush(&df, df.n & (ARRAYLEN(df.buf) - 1)) != -1) {
return df.n;
} else {
return -1;
}
}

View file

@ -18,7 +18,7 @@
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h"

View file

@ -17,6 +17,7 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/sock/internal.h"