mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-04 02:08:30 +00:00
Make fixes and improvements
- Fix handling of precision in hex float formatting - Enhance the cocmd interpreter for system() and popen() - Manually ran the Lua unit tests, which are now passing - Let stdio i/o operations happen when file is in error state - We're now saving and restoring xmm in ftrace out of paranoia
This commit is contained in:
parent
95fbdb4f76
commit
41396ff48a
43 changed files with 495 additions and 261 deletions
|
@ -218,7 +218,9 @@ privileged void _klog(const char *b, size_t n) {
|
|||
__imp_WriteFile(h, b, n, &wrote, 0);
|
||||
__imp_SetLastError(e);
|
||||
} else if (IsMetal()) {
|
||||
if (_weaken(_klog_vga)) _weaken(_klog_vga)(b, n);
|
||||
if (_weaken(_klog_vga)) {
|
||||
_weaken(_klog_vga)(b, n);
|
||||
}
|
||||
for (i = 0; i < n; ++i) {
|
||||
for (;;) {
|
||||
dx = 0x3F8 + UART_LSR;
|
||||
|
|
|
@ -2,5 +2,5 @@
|
|||
#define _FTW_H
|
||||
#include "libc/calls/weirdtypes.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
#include "third_party/musl/ftw.h"
|
||||
#include "libc/stdio/ftw.h"
|
||||
#endif /* _FTW_H */
|
||||
|
|
|
@ -58,7 +58,7 @@ relegated wontreturn void __die(void) {
|
|||
_Exitr(77);
|
||||
} else if (owner == me) {
|
||||
kprintf("die failed while dying\n");
|
||||
_Exitr(78);
|
||||
_Exitr(79);
|
||||
} else {
|
||||
_Exit1(79);
|
||||
}
|
||||
|
|
|
@ -36,20 +36,18 @@ __nt2sysv:
|
|||
mov %rsp,%rbp
|
||||
// TODO(jart): We should probably find some way to use our own
|
||||
// stack when Windows delivers signals ;_;
|
||||
sub $0x100,%rsp
|
||||
sub $256,%rsp
|
||||
push %rbx
|
||||
push %rdi
|
||||
push %rsi
|
||||
pushf # TODO(jart): Do we need it?
|
||||
lea -0x80(%rbp),%rdi
|
||||
call _savexmm
|
||||
pushf // TODO(jart): Do we need it?
|
||||
call __xmm_save
|
||||
mov %rcx,%rdi
|
||||
mov %rdx,%rsi
|
||||
mov %r8,%rdx
|
||||
mov %r9,%rcx
|
||||
call *%rax
|
||||
lea -0x80(%rbp),%rdi
|
||||
call _loadxmm
|
||||
call __xmm_load
|
||||
popf
|
||||
pop %rsi
|
||||
pop %rdi
|
||||
|
|
|
@ -17,28 +17,48 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
.privileged
|
||||
|
||||
// Loads XMM registers from buffer.
|
||||
//
|
||||
// @param %rdi points to &(forcealign(16) uint8_t[256])[128]
|
||||
// @note modern cpus have out-of-order execution engines
|
||||
_loadxmm:
|
||||
__xmm_save:
|
||||
lea -128(%rbp),%rdi
|
||||
.leafprologue
|
||||
movaps -0x80(%rdi),%xmm0
|
||||
movaps -0x70(%rdi),%xmm1
|
||||
movaps -0x60(%rdi),%xmm2
|
||||
movaps -0x50(%rdi),%xmm3
|
||||
movaps -0x40(%rdi),%xmm4
|
||||
movaps -0x30(%rdi),%xmm5
|
||||
movaps -0x20(%rdi),%xmm6
|
||||
movaps -0x10(%rdi),%xmm7
|
||||
movaps 0x00(%rdi),%xmm8
|
||||
movaps 0x10(%rdi),%xmm9
|
||||
movaps 0x20(%rdi),%xmm10
|
||||
movaps 0x30(%rdi),%xmm11
|
||||
movaps 0x40(%rdi),%xmm12
|
||||
movaps 0x50(%rdi),%xmm13
|
||||
movaps 0x60(%rdi),%xmm14
|
||||
movaps 0x70(%rdi),%xmm15
|
||||
movdqu %xmm0,-0x80(%rdi)
|
||||
movdqu %xmm1,-0x70(%rdi)
|
||||
movdqu %xmm2,-0x60(%rdi)
|
||||
movdqu %xmm3,-0x50(%rdi)
|
||||
movdqu %xmm4,-0x40(%rdi)
|
||||
movdqu %xmm5,-0x30(%rdi)
|
||||
movdqu %xmm6,-0x20(%rdi)
|
||||
movdqu %xmm7,-0x10(%rdi)
|
||||
movdqu %xmm8,0x00(%rdi)
|
||||
movdqu %xmm9,0x10(%rdi)
|
||||
movdqu %xmm10,0x20(%rdi)
|
||||
movdqu %xmm11,0x30(%rdi)
|
||||
movdqu %xmm12,0x40(%rdi)
|
||||
movdqu %xmm13,0x50(%rdi)
|
||||
movdqu %xmm14,0x60(%rdi)
|
||||
movdqu %xmm15,0x70(%rdi)
|
||||
.leafepilogue
|
||||
.endfn _loadxmm,globl,hidden
|
||||
.endfn __xmm_save,globl,hidden
|
||||
|
||||
__xmm_load:
|
||||
lea -128(%rbp),%rdi
|
||||
.leafprologue
|
||||
movdqu -0x80(%rdi),%xmm0
|
||||
movdqu -0x70(%rdi),%xmm1
|
||||
movdqu -0x60(%rdi),%xmm2
|
||||
movdqu -0x50(%rdi),%xmm3
|
||||
movdqu -0x40(%rdi),%xmm4
|
||||
movdqu -0x30(%rdi),%xmm5
|
||||
movdqu -0x20(%rdi),%xmm6
|
||||
movdqu -0x10(%rdi),%xmm7
|
||||
movdqu 0x00(%rdi),%xmm8
|
||||
movdqu 0x10(%rdi),%xmm9
|
||||
movdqu 0x20(%rdi),%xmm10
|
||||
movdqu 0x30(%rdi),%xmm11
|
||||
movdqu 0x40(%rdi),%xmm12
|
||||
movdqu 0x50(%rdi),%xmm13
|
||||
movdqu 0x60(%rdi),%xmm14
|
||||
movdqu 0x70(%rdi),%xmm15
|
||||
.leafepilogue
|
||||
.endfn __xmm_load,globl,hidden
|
|
@ -27,15 +27,19 @@
|
|||
#include "libc/fmt/magnumstrs.internal.h"
|
||||
#include "libc/intrin/_getenv.internal.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/ok.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/consts/timer.h"
|
||||
#include "third_party/awk/cmd.h"
|
||||
#include "third_party/getopt/getopt.internal.h"
|
||||
#include "third_party/musl/glob.h"
|
||||
#include "third_party/sed/cmd.h"
|
||||
#include "third_party/tr/cmd.h"
|
||||
|
@ -61,7 +65,6 @@
|
|||
static char *p;
|
||||
static char *q;
|
||||
static char *r;
|
||||
static int envi;
|
||||
static int vari;
|
||||
static size_t n;
|
||||
static char *cmd;
|
||||
|
@ -75,6 +78,9 @@ static const char *prog;
|
|||
static char argbuf[ARG_MAX];
|
||||
static bool unsupported[256];
|
||||
|
||||
static int ShellSpawn(void);
|
||||
static int ShellExec(void);
|
||||
|
||||
static ssize_t Write(int fd, const char *s) {
|
||||
return write(fd, s, strlen(s));
|
||||
}
|
||||
|
@ -87,34 +93,19 @@ static wontreturn void UnsupportedSyntax(unsigned char c) {
|
|||
_Exit(4);
|
||||
}
|
||||
|
||||
static wontreturn void SysExit(int rc, const char *call, const char *thing) {
|
||||
int err;
|
||||
char ibuf[12];
|
||||
const char *estr;
|
||||
err = errno;
|
||||
FormatInt32(ibuf, err);
|
||||
estr = _strerdoc(err);
|
||||
if (!estr) estr = "EUNKNOWN";
|
||||
tinyprint(2, thing, ": ", call, "() failed: ", estr, " (", ibuf, ")\n", NULL);
|
||||
_Exit(rc);
|
||||
}
|
||||
|
||||
static void Open(const char *path, int fd, int flags) {
|
||||
const char *err;
|
||||
close(fd);
|
||||
if (open(path, flags, 0644) == -1) {
|
||||
SysExit(7, "open", path);
|
||||
perror(path);
|
||||
_Exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static wontreturn void Exec(void) {
|
||||
_unassert(args[0][0]);
|
||||
if (!n) {
|
||||
tinyprint(2, prog, ": error: too few args\n", NULL);
|
||||
_Exit(5);
|
||||
}
|
||||
static int SystemExec(void) {
|
||||
execvpe(args[0], args, envs);
|
||||
SysExit(127, "execve", args[0]);
|
||||
perror(args[0]);
|
||||
return (n = 0), 127;
|
||||
}
|
||||
|
||||
static int GetSignalByName(const char *s) {
|
||||
|
@ -133,6 +124,18 @@ static void PutEnv(char **p, const char *kv) {
|
|||
if (!e.s) p[e.i + 1] = 0;
|
||||
}
|
||||
|
||||
static void UnsetEnv(char **p, const char *k) {
|
||||
int i;
|
||||
struct Env e;
|
||||
if ((e = _getenv(p, k)).s) {
|
||||
p[e.i] = 0;
|
||||
for (i = e.i + 1; p[i]; ++i) {
|
||||
p[i - 1] = p[i];
|
||||
p[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Append(int c) {
|
||||
_npassert(q + 1 < argbuf + sizeof(argbuf));
|
||||
*q++ = c;
|
||||
|
@ -163,28 +166,53 @@ static wontreturn void Exit(void) {
|
|||
_Exit(n > 1 ? atoi(args[1]) : 0);
|
||||
}
|
||||
|
||||
static int Waiter(int pid) {
|
||||
int ws;
|
||||
n = 0;
|
||||
if (waitpid(pid, &ws, 0) == -1) {
|
||||
perror("wait");
|
||||
return 1;
|
||||
}
|
||||
if (WIFEXITED(ws)) {
|
||||
return WEXITSTATUS(ws);
|
||||
} else {
|
||||
return 128 + WTERMSIG(ws);
|
||||
}
|
||||
}
|
||||
|
||||
static int Wait(void) {
|
||||
char ibuf[12];
|
||||
int e, rc, ws, pid;
|
||||
int e, ws, pid;
|
||||
if (n > 1) {
|
||||
if (waitpid(atoi(args[1]), &ws, 0) == -1) {
|
||||
SysExit(22, "waitpid", prog);
|
||||
if ((pid = atoi(args[1])) <= 0) {
|
||||
tinyprint(2, "wait: bad pid\n", NULL);
|
||||
return 1;
|
||||
}
|
||||
rc = WIFEXITED(ws) ? WEXITSTATUS(ws) : 128 + WTERMSIG(ws);
|
||||
exitstatus = rc;
|
||||
return Waiter(pid);
|
||||
} else {
|
||||
for (e = errno;;) {
|
||||
for (n = 0, e = errno;;) {
|
||||
if (waitpid(-1, &ws, 0) == -1) {
|
||||
if (errno == ECHILD) {
|
||||
errno = e;
|
||||
break;
|
||||
}
|
||||
SysExit(22, "waitpid", prog);
|
||||
perror("wait");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
rc = 0;
|
||||
return 0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const char *GetOptArg(int c, int *i, int j) {
|
||||
if (args[*i][j] == c) {
|
||||
if (args[*i][j + 1]) {
|
||||
return args[*i] + j + 1;
|
||||
} else if (*i + 1 < n) {
|
||||
return args[++*i];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Echo(void) {
|
||||
|
@ -229,29 +257,60 @@ static int Read(void) {
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int NeedArgument(const char *prog) {
|
||||
tinyprint(2, prog, ": missing argument\n", NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int Cd(void) {
|
||||
const char *s;
|
||||
if ((s = n > 1 ? args[1] : _getenv(envs, "HOME").s)) {
|
||||
if (!chdir(s)) {
|
||||
return 0;
|
||||
} else {
|
||||
tinyprint(2, "chdir: ", s, ": ", _strerdoc(errno), "\n", NULL);
|
||||
perror(s);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
tinyprint(2, "chdir: missing argument\n", NULL);
|
||||
return 1;
|
||||
return NeedArgument("cd");
|
||||
}
|
||||
}
|
||||
|
||||
static int Mkdir(void) {
|
||||
int i = 1;
|
||||
int (*f)(const char *, unsigned) = mkdir;
|
||||
if (n >= 3 && !strcmp(args[1], "-p")) ++i, f = makedirs;
|
||||
int i, j;
|
||||
int mode = 0755;
|
||||
const char *arg;
|
||||
int (*mkdir_impl)(const char *, unsigned) = mkdir;
|
||||
for (i = 1; i < n; ++i) {
|
||||
if (args[i][0] == '-' && args[i][1]) {
|
||||
if (args[i][1] == '-' && !args[i][2]) {
|
||||
++i; // rm -- terminates option parsing
|
||||
break;
|
||||
}
|
||||
for (j = 1; j < args[i][j]; ++j) {
|
||||
if (args[i][j] == 'p') {
|
||||
mkdir_impl = makedirs; // mkdir -p creates parents
|
||||
continue;
|
||||
}
|
||||
if ((arg = GetOptArg('m', &i, j))) {
|
||||
mode = strtol(arg, 0, 8); // mkdir -m OCTAL sets mode
|
||||
break;
|
||||
}
|
||||
char option[2] = {args[i][j]};
|
||||
tinyprint(2, "mkdir", ": illegal option -- ", option, "\n", NULL);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == n) {
|
||||
return NeedArgument("mkdir");
|
||||
}
|
||||
for (; i < n; ++i) {
|
||||
if (f(args[i], 0755)) {
|
||||
tinyprint(2, "mkdir: ", args[i], ": ", _strerdoc(errno), "\n", NULL);
|
||||
return errno;
|
||||
if (mkdir_impl(args[i], mode)) {
|
||||
perror(args[i]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -267,7 +326,7 @@ static int Kill(void) {
|
|||
}
|
||||
for (; i < n; ++i) {
|
||||
if (kill(atoi(args[i]), sig)) {
|
||||
tinyprint(2, "kill: ", args[i], ": ", _strerdoc(errno), "\n", NULL);
|
||||
perror("kill");
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
|
@ -321,33 +380,52 @@ static int Test(void) {
|
|||
}
|
||||
|
||||
static int Rm(void) {
|
||||
int i;
|
||||
if (n > 1 && args[1][0] != '-') {
|
||||
for (i = 1; i < n; ++i) {
|
||||
if (unlink(args[i])) {
|
||||
tinyprint(2, "rm: ", args[i], ": ", _strerdoc(errno), "\n", NULL);
|
||||
int i, j;
|
||||
bool force = false;
|
||||
for (i = 1; i < n; ++i) {
|
||||
if (args[i][0] == '-' && args[i][1]) {
|
||||
if (args[i][1] == '-' && !args[i][2]) {
|
||||
++i; // rm -- terminates option parsing
|
||||
break;
|
||||
}
|
||||
for (j = 1; j < args[i][j]; ++j) {
|
||||
if (args[i][j] == 'f') {
|
||||
force = true; // rm -f forces removal
|
||||
continue;
|
||||
}
|
||||
char option[2] = {args[i][j]};
|
||||
tinyprint(2, "rm", ": illegal option -- ", option, "\n", NULL);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
return -1; // fall back to system rm command
|
||||
}
|
||||
if (i == n) {
|
||||
return NeedArgument("rm");
|
||||
}
|
||||
for (; i < n; ++i) {
|
||||
struct stat st;
|
||||
if ((!force && (lstat(args[i], &st) ||
|
||||
(!S_ISLNK(st.st_mode) && access(args[i], W_OK)))) ||
|
||||
unlink(args[i])) {
|
||||
if (force && errno == ENOENT) continue;
|
||||
perror(args[i]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Rmdir(void) {
|
||||
int i;
|
||||
if (n > 1 && args[1][0] != '-') {
|
||||
for (i = 1; i < n; ++i) {
|
||||
if (rmdir(args[i])) {
|
||||
tinyprint(2, "rmdir: ", args[i], ": ", _strerdoc(errno), "\n", NULL);
|
||||
return 1;
|
||||
}
|
||||
for (i = 1; i < n; ++i) {
|
||||
if (rmdir(args[i])) {
|
||||
perror(args[i]);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
return -1; // fall back to system rmdir command
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Touch(void) {
|
||||
|
@ -355,7 +433,7 @@ static int Touch(void) {
|
|||
if (n > 1 && args[1][0] != '-') {
|
||||
for (i = 1; i < n; ++i) {
|
||||
if (touch(args[i], 0644)) {
|
||||
tinyprint(2, "touch: ", args[i], ": ", _strerdoc(errno), "\n", NULL);
|
||||
perror(args[i]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -365,17 +443,77 @@ static int Touch(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static int Shift(int i) {
|
||||
if (i <= n) {
|
||||
memmove(args, args + i, (n - i + 1) * sizeof(*args));
|
||||
n -= i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Fake(int main(int, char **)) {
|
||||
int exitstatus, ws, pid;
|
||||
if ((pid = fork()) == -1) SysExit(21, "vfork", prog);
|
||||
int pid;
|
||||
if ((pid = fork()) == -1) {
|
||||
perror("fork");
|
||||
return 127;
|
||||
}
|
||||
if (!pid) {
|
||||
// TODO(jart): Maybe nuke stdio state somehow?
|
||||
// TODO(jart): Maybe nuke stdio too?
|
||||
if (_weaken(optind)) {
|
||||
*_weaken(optind) = 1;
|
||||
}
|
||||
environ = envs;
|
||||
exit(main(n, args));
|
||||
}
|
||||
if (waitpid(pid, &ws, 0) == -1) SysExit(22, "waitpid", prog);
|
||||
exitstatus = WIFEXITED(ws) ? WEXITSTATUS(ws) : 128 + WTERMSIG(ws);
|
||||
return n = 0, exitstatus;
|
||||
return Waiter(pid);
|
||||
}
|
||||
|
||||
static int Env(void) {
|
||||
int i, j;
|
||||
const char *arg;
|
||||
char term = '\n';
|
||||
for (i = 1; i < n; ++i) {
|
||||
if (args[i][0] == '-') {
|
||||
if (!args[i][1]) {
|
||||
envs[0] = 0; // env - clears environment
|
||||
continue;
|
||||
}
|
||||
for (j = 1; j < args[i][j]; ++j) {
|
||||
if (args[i][j] == 'i') {
|
||||
envs[0] = 0; // env -i clears environment
|
||||
continue;
|
||||
}
|
||||
if (args[i][j] == '0') {
|
||||
term = 0; // env -0 uses '\0' line separator
|
||||
continue;
|
||||
}
|
||||
if ((arg = GetOptArg('u', &i, j))) {
|
||||
UnsetEnv(envs, arg); // env -u VAR removes variable
|
||||
break;
|
||||
}
|
||||
char option[2] = {args[i][j]};
|
||||
tinyprint(2, "env", ": illegal option -- ", option, "\n", NULL);
|
||||
return 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (strchr(args[i], '=')) {
|
||||
PutEnv(envs, args[i]);
|
||||
} else {
|
||||
Shift(i);
|
||||
return ShellSpawn();
|
||||
}
|
||||
}
|
||||
for (i = 0; envs[i]; ++i) {
|
||||
Write(1, envs[i]);
|
||||
write(1, &term, 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Exec(void) {
|
||||
Shift(1);
|
||||
return ShellExec();
|
||||
}
|
||||
|
||||
static int TryBuiltin(void) {
|
||||
|
@ -384,6 +522,8 @@ static int TryBuiltin(void) {
|
|||
if (!strcmp(args[0], "cd")) return Cd();
|
||||
if (!strcmp(args[0], "rm")) return Rm();
|
||||
if (!strcmp(args[0], "[")) return Test();
|
||||
if (!strcmp(args[0], "env")) return Env();
|
||||
if (!strcmp(args[0], "exec")) return Exec();
|
||||
if (!strcmp(args[0], "wait")) return Wait();
|
||||
if (!strcmp(args[0], "echo")) return Echo();
|
||||
if (!strcmp(args[0], "read")) return Read();
|
||||
|
@ -403,43 +543,64 @@ static int TryBuiltin(void) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
static wontreturn void Launch(void) {
|
||||
static int ShellExec(void) {
|
||||
int rc;
|
||||
if ((rc = TryBuiltin()) != -1) _Exit(rc);
|
||||
Exec();
|
||||
if ((rc = TryBuiltin()) == -1) {
|
||||
rc = SystemExec();
|
||||
}
|
||||
return (n = 0), rc;
|
||||
}
|
||||
|
||||
static void Pipe(void) {
|
||||
int pid, pfds[2];
|
||||
if (pipe2(pfds, O_CLOEXEC)) SysExit(8, "pipe2", prog);
|
||||
if ((pid = fork()) == -1) SysExit(9, "vfork", prog);
|
||||
if (pipe2(pfds, O_CLOEXEC)) {
|
||||
perror("pipe");
|
||||
_Exit(127);
|
||||
}
|
||||
if ((pid = fork()) == -1) {
|
||||
perror("fork");
|
||||
_Exit(127);
|
||||
}
|
||||
if (!pid) {
|
||||
_unassert(dup2(pfds[1], 1) == 1);
|
||||
// we can't rely on cloexec because builtins
|
||||
if (pfds[0] != 1) _unassert(!close(pfds[0]));
|
||||
if (pfds[1] != 1) _unassert(!close(pfds[1]));
|
||||
Launch();
|
||||
_Exit(ShellExec());
|
||||
}
|
||||
_unassert(!dup2(pfds[0], 0));
|
||||
if (pfds[1]) _unassert(!close(pfds[1]));
|
||||
n = 0;
|
||||
}
|
||||
|
||||
static int Run(void) {
|
||||
int exitstatus, ws, pid;
|
||||
if ((exitstatus = TryBuiltin()) == -1) {
|
||||
if ((pid = vfork()) == -1) SysExit(21, "vfork", prog);
|
||||
if (!pid) Exec();
|
||||
if (waitpid(pid, &ws, 0) == -1) SysExit(22, "waitpid", prog);
|
||||
exitstatus = WIFEXITED(ws) ? WEXITSTATUS(ws) : 128 + WTERMSIG(ws);
|
||||
static int ShellSpawn(void) {
|
||||
int rc, ws, pid;
|
||||
if ((rc = TryBuiltin()) == -1) {
|
||||
switch ((pid = fork())) {
|
||||
case 0:
|
||||
_Exit(SystemExec());
|
||||
default:
|
||||
rc = Waiter(pid);
|
||||
break;
|
||||
case -1:
|
||||
perror("fork");
|
||||
rc = 127;
|
||||
break;
|
||||
}
|
||||
}
|
||||
n = 0;
|
||||
return exitstatus;
|
||||
return (n = 0), rc;
|
||||
}
|
||||
|
||||
static void Async(void) {
|
||||
if ((lastchild = fork()) == -1) SysExit(21, "vfork", prog);
|
||||
if (!lastchild) Launch();
|
||||
static void ShellSpawnAsync(void) {
|
||||
switch ((lastchild = fork())) {
|
||||
case 0:
|
||||
_Exit(ShellExec());
|
||||
default:
|
||||
break;
|
||||
case -1:
|
||||
perror("fork");
|
||||
break;
|
||||
}
|
||||
n = 0;
|
||||
}
|
||||
|
||||
|
@ -535,7 +696,7 @@ static char *Tokenize(void) {
|
|||
if (q > r) {
|
||||
return Finish();
|
||||
} else if (p[1] == '|') {
|
||||
rc = Run();
|
||||
rc = ShellSpawn();
|
||||
if (!rc) {
|
||||
_Exit(0);
|
||||
} else {
|
||||
|
@ -550,7 +711,7 @@ static char *Tokenize(void) {
|
|||
if (q > r) {
|
||||
return Finish();
|
||||
} else {
|
||||
exitstatus = Run();
|
||||
exitstatus = ShellSpawn();
|
||||
t = STATE_WHITESPACE;
|
||||
}
|
||||
} else if (*p == '>') {
|
||||
|
@ -562,7 +723,7 @@ static char *Tokenize(void) {
|
|||
if (q > r) {
|
||||
return Finish();
|
||||
} else if (p[1] == '&') {
|
||||
rc = Run();
|
||||
rc = ShellSpawn();
|
||||
if (!rc) {
|
||||
++p;
|
||||
t = STATE_WHITESPACE;
|
||||
|
@ -570,7 +731,7 @@ static char *Tokenize(void) {
|
|||
_Exit(rc);
|
||||
}
|
||||
} else {
|
||||
Async();
|
||||
ShellSpawnAsync();
|
||||
t = STATE_WHITESPACE;
|
||||
}
|
||||
} else {
|
||||
|
@ -691,7 +852,7 @@ int _cocmd(int argc, char **argv, char **envp) {
|
|||
}
|
||||
|
||||
// copy environment variables
|
||||
envi = 0;
|
||||
int envi = 0;
|
||||
if (envp) {
|
||||
for (; envp[envi]; ++envi) {
|
||||
_npassert(envi + 1 < ARRAYLEN(envs));
|
||||
|
@ -748,5 +909,5 @@ int _cocmd(int argc, char **argv, char **envp) {
|
|||
}
|
||||
}
|
||||
|
||||
Launch();
|
||||
return ShellExec();
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ ftrace_hook:
|
|||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
and $-16,%rsp
|
||||
sub $256,%rsp
|
||||
push %rax
|
||||
push %rdi
|
||||
push %rsi
|
||||
|
@ -44,7 +45,9 @@ ftrace_hook:
|
|||
push %r13
|
||||
push %r14
|
||||
push %r15
|
||||
call __xmm_save
|
||||
call ftracer
|
||||
call __xmm_load
|
||||
pop %r15
|
||||
pop %r14
|
||||
pop %r13
|
||||
|
@ -67,7 +70,7 @@ ftrace_hook:
|
|||
ldr w16,[x16,#:lo12:__ftrace]
|
||||
cmp w16,0
|
||||
ble 1f
|
||||
stp x29,x30,[sp,-256]!
|
||||
stp x29,x30,[sp,-384]!
|
||||
mov x29,sp
|
||||
|
||||
stp x0,x1,[sp,16]
|
||||
|
@ -84,6 +87,10 @@ ftrace_hook:
|
|||
stp x24,x25,[sp,208]
|
||||
stp x26,x27,[sp,224]
|
||||
str x28,[sp,240]
|
||||
stp q0,q1,[sp,256]
|
||||
stp q2,q3,[sp,288]
|
||||
stp q4,q5,[sp,320]
|
||||
stp q6,q7,[sp,352]
|
||||
|
||||
bl ftracer
|
||||
|
||||
|
@ -101,8 +108,12 @@ ftrace_hook:
|
|||
ldp x24,x25,[sp,208]
|
||||
ldp x26,x27,[sp,224]
|
||||
ldr x28,[sp,240]
|
||||
ldp q0,q1,[sp,256]
|
||||
ldp q2,q3,[sp,288]
|
||||
ldp q4,q5,[sp,320]
|
||||
ldp q6,q7,[sp,352]
|
||||
|
||||
ldp x29,x30,[sp],256
|
||||
ldp x29,x30,[sp],384
|
||||
1: ret
|
||||
|
||||
#endif /* __x86_64__ */
|
||||
|
|
|
@ -18,14 +18,13 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
#include "libc/runtime/symbols.internal.h"
|
||||
|
||||
void ftrace_hook(void);
|
||||
|
||||
_Hide int ftrace_stackdigs;
|
||||
|
||||
textstartup int ftrace_install(void) {
|
||||
if (GetSymbolTable()) {
|
||||
ftrace_stackdigs = LengthInt64Thousands(GetStackSize());
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- 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│
|
||||
/*-*- 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 │
|
||||
│ Copyright 2023 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
|
@ -16,29 +16,6 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
|
||||
// Stores XMM registers to buffer.
|
||||
//
|
||||
// @param %rdi points to &(forcealign(16) uint8_t[256])[128]
|
||||
// @note modern cpus have out-of-order execution engines
|
||||
_savexmm:
|
||||
.leafprologue
|
||||
movaps %xmm0,-0x80(%rdi)
|
||||
movaps %xmm1,-0x70(%rdi)
|
||||
movaps %xmm2,-0x60(%rdi)
|
||||
movaps %xmm3,-0x50(%rdi)
|
||||
movaps %xmm4,-0x40(%rdi)
|
||||
movaps %xmm5,-0x30(%rdi)
|
||||
movaps %xmm6,-0x20(%rdi)
|
||||
movaps %xmm7,-0x10(%rdi)
|
||||
movaps %xmm8,0x00(%rdi)
|
||||
movaps %xmm9,0x10(%rdi)
|
||||
movaps %xmm10,0x20(%rdi)
|
||||
movaps %xmm11,0x30(%rdi)
|
||||
movaps %xmm12,0x40(%rdi)
|
||||
movaps %xmm13,0x50(%rdi)
|
||||
movaps %xmm14,0x60(%rdi)
|
||||
movaps %xmm15,0x70(%rdi)
|
||||
.leafepilogue
|
||||
.endfn _savexmm,globl,hidden
|
||||
int ftrace_stackdigs;
|
|
@ -46,7 +46,6 @@
|
|||
#define DETOUR_SKEW 8
|
||||
#endif
|
||||
|
||||
extern _Hide int ftrace_stackdigs;
|
||||
static struct CosmoFtrace g_ftrace;
|
||||
|
||||
static privileged inline int GetNestingLevelImpl(struct StackFrame *frame) {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern int __pid;
|
||||
extern int ftrace_stackdigs;
|
||||
extern uint32_t __ntconsolemode[3];
|
||||
extern const char v_ntsubsystem[] __attribute__((__weak__));
|
||||
extern const uintptr_t __fini_array_end[] __attribute__((__weak__));
|
||||
|
|
|
@ -114,8 +114,6 @@ void _Exitr(int) libcesque wontreturn;
|
|||
void _Exit1(int) libcesque wontreturn;
|
||||
void _restorewintty(void);
|
||||
void __paginate(int, const char *);
|
||||
void _loadxmm(void *);
|
||||
void _savexmm(void *);
|
||||
long _missingno();
|
||||
/* memory management */
|
||||
void _weakfree(void *);
|
||||
|
|
|
@ -727,7 +727,6 @@ haveinc:
|
|||
* - `%e` double (expo formatting)
|
||||
* - `%f` double (ugly formatting)
|
||||
* - `%a` double (hex formatting)
|
||||
* - `%Lg` long double
|
||||
*
|
||||
* Size Modifiers
|
||||
*
|
||||
|
@ -738,6 +737,7 @@ haveinc:
|
|||
* - `%lx` unsigned long (64-bit hexadecimal)
|
||||
* - `%jd` intmax_t (64-bit)
|
||||
* - `%jjd` int128_t (128-bit)
|
||||
* - `%Lg` long double
|
||||
*
|
||||
* Width Modifiers
|
||||
*
|
||||
|
@ -1251,19 +1251,23 @@ _Hide int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
|||
__FMT_PUT(*s++);
|
||||
if (prec || (flags & FLAGS_HASH)) __FMT_PUT('.');
|
||||
while (--prec >= 0) {
|
||||
if ((c = *s))
|
||||
if ((c = *s)) {
|
||||
s++;
|
||||
else
|
||||
} else {
|
||||
c = '0';
|
||||
}
|
||||
__FMT_PUT(c);
|
||||
}
|
||||
__FMT_PUT(d);
|
||||
if (decpt < 0) {
|
||||
__FMT_PUT('-');
|
||||
decpt = -decpt;
|
||||
} else
|
||||
} else {
|
||||
__FMT_PUT('+');
|
||||
for (c = 2, k = 10; 10 * k <= decpt; c++, k *= 10) donothing;
|
||||
}
|
||||
for (c = 2, k = 10; 10 * k <= decpt; c++, k *= 10) {
|
||||
donothing;
|
||||
}
|
||||
for (;;) {
|
||||
i1 = decpt / k;
|
||||
__FMT_PUT(i1 + '0');
|
||||
|
@ -1271,7 +1275,9 @@ _Hide int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
|||
decpt -= i1 * k;
|
||||
decpt *= 10;
|
||||
}
|
||||
while (--width >= 0) __FMT_PUT(' ');
|
||||
while (--width >= 0) {
|
||||
__FMT_PUT(' ');
|
||||
}
|
||||
freedtoa(s0);
|
||||
break;
|
||||
|
||||
|
@ -1321,7 +1327,7 @@ _Hide int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
|||
}
|
||||
if (sign) __FMT_PUT(sign);
|
||||
__FMT_PUT('0');
|
||||
__FMT_PUT(alphabet[17]);
|
||||
__FMT_PUT(alphabet[17]); // x or X
|
||||
if ((flags & FLAGS_ZEROPAD) && width > 0 && !(flags & FLAGS_LEFT)) {
|
||||
do __FMT_PUT('0');
|
||||
while (--width > 0);
|
||||
|
@ -1329,29 +1335,31 @@ _Hide int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
|||
i1 = prec1 & 7;
|
||||
k = prec1 >> 3;
|
||||
__FMT_PUT(alphabet[(fpb.bits[k] >> 4 * i1) & 0xf]);
|
||||
if (prec1 > 0 || (flags & FLAGS_HASH)) __FMT_PUT('.');
|
||||
if (prec1 > 0) {
|
||||
prec -= prec1;
|
||||
while (prec1 > 0) {
|
||||
if (--i1 < 0) {
|
||||
if (--k < 0) break;
|
||||
i1 = 7;
|
||||
}
|
||||
__FMT_PUT(alphabet[(fpb.bits[k] >> 4 * i1) & 0xf]);
|
||||
--prec1;
|
||||
}
|
||||
if ((flags & FLAGS_HASH) && prec > 0) {
|
||||
do __FMT_PUT(0);
|
||||
while (--prec > 0);
|
||||
}
|
||||
if (prec1 > 0 || prec > 0) {
|
||||
__FMT_PUT('.');
|
||||
}
|
||||
__FMT_PUT(alphabet[16]);
|
||||
while (prec1 > 0) {
|
||||
if (--i1 < 0) {
|
||||
if (--k < 0) break;
|
||||
i1 = 7;
|
||||
}
|
||||
__FMT_PUT(alphabet[(fpb.bits[k] >> 4 * i1) & 0xf]);
|
||||
--prec1;
|
||||
--prec;
|
||||
}
|
||||
while (prec-- > 0) {
|
||||
__FMT_PUT('0');
|
||||
}
|
||||
__FMT_PUT(alphabet[16]); // p or P
|
||||
if (bex < 0) {
|
||||
__FMT_PUT('-');
|
||||
bex = -bex;
|
||||
} else
|
||||
} else {
|
||||
__FMT_PUT('+');
|
||||
for (c = 1; 10 * c <= bex; c *= 10) donothing;
|
||||
}
|
||||
for (c = 1; 10 * c <= bex; c *= 10) {
|
||||
donothing;
|
||||
}
|
||||
for (;;) {
|
||||
i1 = bex / c;
|
||||
__FMT_PUT('0' + i1);
|
||||
|
@ -1359,7 +1367,9 @@ _Hide int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
|||
bex -= i1 * c;
|
||||
bex *= 10;
|
||||
}
|
||||
while (--width >= 0) __FMT_PUT(' ');
|
||||
while (--width >= 0) {
|
||||
__FMT_PUT(' ');
|
||||
}
|
||||
break;
|
||||
|
||||
case '%':
|
||||
|
|
|
@ -43,7 +43,7 @@ size_t fread_unlocked(void *buf, size_t stride, size_t count, FILE *f) {
|
|||
ssize_t rc;
|
||||
size_t n, m;
|
||||
struct iovec iov[2];
|
||||
if (f->state) {
|
||||
if (!stride) {
|
||||
return 0;
|
||||
}
|
||||
if ((f->iomode & O_ACCMODE) == O_WRONLY) {
|
||||
|
|
53
libc/stdio/ftw.c
Normal file
53
libc/stdio/ftw.c
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╚──────────────────────────────────────────────────────────────────────────────╝
|
||||
│ │
|
||||
│ Musl Libc │
|
||||
│ Copyright © 2005-2014 Rich Felker, et al. │
|
||||
│ │
|
||||
│ Permission is hereby granted, free of charge, to any person obtaining │
|
||||
│ a copy of this software and associated documentation files (the │
|
||||
│ "Software"), to deal in the Software without restriction, including │
|
||||
│ without limitation the rights to use, copy, modify, merge, publish, │
|
||||
│ distribute, sublicense, and/or sell copies of the Software, and to │
|
||||
│ permit persons to whom the Software is furnished to do so, subject to │
|
||||
│ the following conditions: │
|
||||
│ │
|
||||
│ The above copyright notice and this permission notice shall be │
|
||||
│ included in all copies or substantial portions of the Software. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │
|
||||
│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │
|
||||
│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │
|
||||
│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │
|
||||
│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │
|
||||
│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │
|
||||
│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │
|
||||
│ │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/ftw.h"
|
||||
|
||||
asm(".ident\t\"\\n\\n\
|
||||
Musl libc (MIT License)\\n\
|
||||
Copyright 2005-2014 Rich Felker, et. al.\"");
|
||||
asm(".include \"libc/disclaimer.inc\"");
|
||||
// clang-format off
|
||||
|
||||
/**
|
||||
* Walks file tree.
|
||||
*
|
||||
* @return 0 on success, -1 on error, or non-zero `fn` result
|
||||
* @see examples/walk.c for example
|
||||
* @see nftw()
|
||||
*/
|
||||
int ftw(const char *dirpath,
|
||||
int fn(const char *fpath,
|
||||
const struct stat *st,
|
||||
int typeflag),
|
||||
int fd_limit)
|
||||
{
|
||||
/* The following cast assumes that calling a function with one
|
||||
* argument more than it needs behaves as expected. This is
|
||||
* actually undefined, but works on all real-world machines. */
|
||||
return nftw(dirpath, (int (*)())fn, fd_limit, FTW_PHYS);
|
||||
}
|
90
libc/stdio/ftw.h
Normal file
90
libc/stdio/ftw.h
Normal file
|
@ -0,0 +1,90 @@
|
|||
#ifndef COSMOPOLITAN_THIRD_PARTY_MUSL_FTW_H_
|
||||
#define COSMOPOLITAN_THIRD_PARTY_MUSL_FTW_H_
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
/**
|
||||
* Type for file.
|
||||
*/
|
||||
#define FTW_F 1
|
||||
|
||||
/**
|
||||
* Type for directory.
|
||||
*/
|
||||
#define FTW_D 2
|
||||
|
||||
/**
|
||||
* Type for directory that cannot be read.
|
||||
*/
|
||||
#define FTW_DNR 3
|
||||
|
||||
/**
|
||||
* Type for stat() failed and not a symbolic link.
|
||||
*/
|
||||
#define FTW_NS 4
|
||||
|
||||
/**
|
||||
* Type for symbolic link when `FTW_PHYS` is in flags.
|
||||
*/
|
||||
#define FTW_SL 5
|
||||
|
||||
/**
|
||||
* Directory and `FTW_DEPTH` in flags.
|
||||
*/
|
||||
#define FTW_DP 6
|
||||
|
||||
/**
|
||||
* Type for broken symbolic link when `FTW_PHYS` is not in flags.
|
||||
*/
|
||||
#define FTW_SLN 7
|
||||
|
||||
/**
|
||||
* Flag to prevent following symbolic links (recommended).
|
||||
* @see nftw() flags
|
||||
*/
|
||||
#define FTW_PHYS 1
|
||||
|
||||
/**
|
||||
* Flag to prevent crossing mount points.
|
||||
* @see nftw() flags
|
||||
*/
|
||||
#define FTW_MOUNT 2
|
||||
|
||||
/**
|
||||
* Unsupported.
|
||||
* @see nftw() flags
|
||||
*/
|
||||
#define FTW_CHDIR 4
|
||||
|
||||
/**
|
||||
* Flag for post-order traversal.
|
||||
*
|
||||
* 1. Will use `FTW_DP` instead of `FTW_D` as type.
|
||||
* 2. Directory callback happens *after* rather than before.
|
||||
*
|
||||
* @see nftw() flags
|
||||
*/
|
||||
#define FTW_DEPTH 8
|
||||
|
||||
struct FTW {
|
||||
|
||||
/**
|
||||
* Byte offset of basename component in `fpath` passed to callback.
|
||||
*/
|
||||
int base;
|
||||
|
||||
/**
|
||||
* Depth relative to `dirpath` whose level is zero.
|
||||
*/
|
||||
int level;
|
||||
};
|
||||
|
||||
int ftw(const char *, int (*)(const char *, const struct stat *, int), int);
|
||||
int nftw(const char *,
|
||||
int (*)(const char *, const struct stat *, int, struct FTW *), int,
|
||||
int);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_THIRD_PARTY_MUSL_FTW_H_ */
|
|
@ -45,7 +45,7 @@ size_t fwrite_unlocked(const void *data, size_t stride, size_t count, FILE *f) {
|
|||
size_t n, m;
|
||||
const char *p;
|
||||
struct iovec iov[2];
|
||||
if (f->state) {
|
||||
if (!stride) {
|
||||
return 0;
|
||||
}
|
||||
if ((f->iomode & O_ACCMODE) == O_RDONLY) {
|
||||
|
|
189
libc/stdio/nftw.c
Normal file
189
libc/stdio/nftw.c
Normal file
|
@ -0,0 +1,189 @@
|
|||
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╚──────────────────────────────────────────────────────────────────────────────╝
|
||||
│ │
|
||||
│ Musl Libc │
|
||||
│ Copyright © 2005-2014 Rich Felker, et al. │
|
||||
│ │
|
||||
│ Permission is hereby granted, free of charge, to any person obtaining │
|
||||
│ a copy of this software and associated documentation files (the │
|
||||
│ "Software"), to deal in the Software without restriction, including │
|
||||
│ without limitation the rights to use, copy, modify, merge, publish, │
|
||||
│ distribute, sublicense, and/or sell copies of the Software, and to │
|
||||
│ permit persons to whom the Software is furnished to do so, subject to │
|
||||
│ the following conditions: │
|
||||
│ │
|
||||
│ The above copyright notice and this permission notice shall be │
|
||||
│ included in all copies or substantial portions of the Software. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │
|
||||
│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │
|
||||
│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │
|
||||
│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │
|
||||
│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │
|
||||
│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │
|
||||
│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │
|
||||
│ │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/dirent.h"
|
||||
#include "libc/calls/weirdtypes.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/stdio/ftw.h"
|
||||
|
||||
#define PATH_MAXIMUS 4096
|
||||
|
||||
asm(".ident\t\"\\n\\n\
|
||||
Musl libc (MIT License)\\n\
|
||||
Copyright 2005-2014 Rich Felker, et. al.\"");
|
||||
asm(".include \"libc/disclaimer.inc\"");
|
||||
// clang-format off
|
||||
|
||||
struct history
|
||||
{
|
||||
struct history *chain;
|
||||
dev_t dev;
|
||||
ino_t ino;
|
||||
int level;
|
||||
int base;
|
||||
};
|
||||
|
||||
static int do_nftw(char *path,
|
||||
int fn(const char *, const struct stat *, int, struct FTW *),
|
||||
int fd_limit,
|
||||
int flags,
|
||||
struct history *h)
|
||||
{
|
||||
size_t l = strlen(path), j = l && path[l-1]=='/' ? l-1 : l;
|
||||
struct stat st;
|
||||
struct history new;
|
||||
int type;
|
||||
int r;
|
||||
int dfd=-1;
|
||||
int err=0;
|
||||
struct FTW lev;
|
||||
|
||||
if ((flags & FTW_PHYS) ? lstat(path, &st) : stat(path, &st) < 0) {
|
||||
if (!(flags & FTW_PHYS) && errno==ENOENT && !lstat(path, &st))
|
||||
type = FTW_SLN;
|
||||
else if (errno != EACCES) return -1;
|
||||
else type = FTW_NS;
|
||||
} else if (S_ISDIR(st.st_mode)) {
|
||||
if (flags & FTW_DEPTH) type = FTW_DP;
|
||||
else type = FTW_D;
|
||||
} else if (S_ISLNK(st.st_mode)) {
|
||||
if (flags & FTW_PHYS) type = FTW_SL;
|
||||
else type = FTW_SLN;
|
||||
} else {
|
||||
type = FTW_F;
|
||||
}
|
||||
|
||||
if ((flags & FTW_MOUNT) && h && st.st_dev != h->dev)
|
||||
return 0;
|
||||
|
||||
new.chain = h;
|
||||
new.dev = st.st_dev;
|
||||
new.ino = st.st_ino;
|
||||
new.level = h ? h->level+1 : 0;
|
||||
new.base = j+1;
|
||||
|
||||
lev.level = new.level;
|
||||
if (h) {
|
||||
lev.base = h->base;
|
||||
} else {
|
||||
size_t k;
|
||||
for (k=j; k && path[k]=='/'; k--);
|
||||
for (; k && path[k-1]!='/'; k--);
|
||||
lev.base = k;
|
||||
}
|
||||
|
||||
if (type == FTW_D || type == FTW_DP) {
|
||||
dfd = open(path, O_RDONLY | O_DIRECTORY);
|
||||
err = errno;
|
||||
if (dfd < 0 && err == EACCES) type = FTW_DNR;
|
||||
if (!fd_limit) close(dfd);
|
||||
}
|
||||
|
||||
if (!(flags & FTW_DEPTH) && (r=fn(path, &st, type, &lev)))
|
||||
return r;
|
||||
|
||||
for (; h; h = h->chain)
|
||||
if (h->dev == st.st_dev && h->ino == st.st_ino)
|
||||
return 0;
|
||||
|
||||
if ((type == FTW_D || type == FTW_DP) && fd_limit) {
|
||||
if (dfd < 0) {
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
DIR *d = fdopendir(dfd);
|
||||
if (d) {
|
||||
struct dirent *de;
|
||||
while ((de = readdir(d))) {
|
||||
if (de->d_name[0] == '.'
|
||||
&& (!de->d_name[1]
|
||||
|| (de->d_name[1]=='.'
|
||||
&& !de->d_name[2]))) continue;
|
||||
if (strlen(de->d_name) >= PATH_MAXIMUS-l) {
|
||||
errno = ENAMETOOLONG;
|
||||
closedir(d);
|
||||
return -1;
|
||||
}
|
||||
path[j]='/';
|
||||
strcpy(path+j+1, de->d_name);
|
||||
if ((r=do_nftw(path, fn, fd_limit-1, flags, &new))) {
|
||||
closedir(d);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
closedir(d);
|
||||
} else {
|
||||
close(dfd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
path[l] = 0;
|
||||
if ((flags & FTW_DEPTH) && (r=fn(path, &st, type, &lev)))
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks file tree.
|
||||
*
|
||||
* @return 0 on success, -1 on error, or non-zero `fn` result
|
||||
* @see examples/walk.c for example
|
||||
*/
|
||||
int nftw(const char *dirpath,
|
||||
int fn(const char *fpath,
|
||||
const struct stat *st,
|
||||
int typeflag,
|
||||
struct FTW *ftwbuf),
|
||||
int fd_limit,
|
||||
int flags)
|
||||
{
|
||||
int r, cs;
|
||||
size_t l;
|
||||
char pathbuf[PATH_MAXIMUS+1];
|
||||
|
||||
if (fd_limit <= 0) return 0;
|
||||
|
||||
l = strlen(dirpath);
|
||||
if (l > PATH_MAXIMUS) {
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
memcpy(pathbuf, dirpath, l+1);
|
||||
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
|
||||
r = do_nftw(pathbuf, fn, fd_limit, flags, NULL);
|
||||
pthread_setcancelstate(cs, 0);
|
||||
|
||||
return r;
|
||||
}
|
|
@ -203,6 +203,7 @@ typedef const int *wctrans_t;
|
|||
wctrans_t wctrans(const char *);
|
||||
wint_t towctrans(wint_t, wctrans_t);
|
||||
|
||||
int getsubopt(char **, char *const *, char **) paramsnonnull();
|
||||
char *strsignal(int) returnsnonnull libcesque;
|
||||
char *strsignal_r(int, char[hasatleast 15]) returnsnonnull libcesque;
|
||||
char *strerror(int) returnsnonnull dontthrow nocallback;
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include "libc/errno.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "third_party/musl/ftw.h"
|
||||
#include "libc/stdio/ftw.h"
|
||||
|
||||
static int rmrf_callback(const char *fpath, //
|
||||
const struct stat *st, //
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue