auto: clang-format the repo again

Same as before:

    fd '\.c(c|pp)?$' --print0| xargs -0 clang-format -i

This time, should only pick up the changes introduced by the
.clang-format update.
This commit is contained in:
Jōshin 2024-04-24 13:43:41 -07:00
parent d33b18d7f2
commit 21e46023ae
No known key found for this signature in database
863 changed files with 9197 additions and 4623 deletions

View file

@ -221,13 +221,15 @@ struct ApeLoader {
static unsigned long StrLen(const char *s) { static unsigned long StrLen(const char *s) {
unsigned long n = 0; unsigned long n = 0;
while (*s++) ++n; while (*s++)
++n;
return n; return n;
} }
static int StrCmp(const char *l, const char *r) { static int StrCmp(const char *l, const char *r) {
unsigned long i = 0; unsigned long i = 0;
while (l[i] == r[i] && r[i]) ++i; while (l[i] == r[i] && r[i])
++i;
return (l[i] & 255) - (r[i] & 255); return (l[i] & 255) - (r[i] & 255);
} }
@ -276,7 +278,8 @@ static char *Utoa(char p[21], unsigned long x) {
} }
static char *Itoa(char p[21], long x) { static char *Itoa(char p[21], long x) {
if (x < 0) *p++ = '-', x = -(unsigned long)x; if (x < 0)
*p++ = '-', x = -(unsigned long)x;
return Utoa(p, x); return Utoa(p, x);
} }
@ -312,7 +315,8 @@ static int GetIndirectOffset(const char *arg0) {
static void Perror(const char *thing, long rc, const char *reason) { static void Perror(const char *thing, long rc, const char *reason) {
char ibuf[21]; char ibuf[21];
ibuf[0] = 0; ibuf[0] = 0;
if (rc) Itoa(ibuf, -rc); if (rc)
Itoa(ibuf, -rc);
Print(2, "ape error: ", thing, ": ", reason, rc ? " failed w/ errno " : "", Print(2, "ape error: ", thing, ": ", reason, rc ? " failed w/ errno " : "",
ibuf, "\n", 0l); ibuf, "\n", 0l);
} }
@ -327,7 +331,8 @@ static char AccessCommand(struct PathSearcher *ps, unsigned long pathlen) {
if (pathlen + 1 + ps->namelen + 1 > sizeof(ps->path)) { if (pathlen + 1 + ps->namelen + 1 > sizeof(ps->path)) {
return 0; return 0;
} }
if (pathlen && ps->path[pathlen - 1] != '/') ps->path[pathlen++] = '/'; if (pathlen && ps->path[pathlen - 1] != '/')
ps->path[pathlen++] = '/';
memmove(ps->path + pathlen, ps->name, ps->namelen); memmove(ps->path + pathlen, ps->name, ps->namelen);
ps->path[pathlen + ps->namelen] = 0; ps->path[pathlen + ps->namelen] = 0;
return !access(ps->path, X_OK); return !access(ps->path, X_OK);
@ -377,8 +382,10 @@ static char *Commandv(struct PathSearcher *ps, const char *name,
const char *syspath) { const char *syspath) {
ps->syspath = syspath ? syspath : "/bin:/usr/local/bin:/usr/bin"; ps->syspath = syspath ? syspath : "/bin:/usr/local/bin:/usr/bin";
ps->name = name; ps->name = name;
if (!(ps->namelen = ps->indirect ? ps->indirect : StrLen(ps->name))) return 0; if (!(ps->namelen = ps->indirect ? ps->indirect : StrLen(ps->name)))
if (ps->namelen + 1 > sizeof(ps->path)) return 0; return 0;
if (ps->namelen + 1 > sizeof(ps->path))
return 0;
if (FindCommand(ps)) { if (FindCommand(ps)) {
return ps->path; return ps->path;
} else { } else {
@ -585,7 +592,8 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
a = p[i].p_vaddr & -pagesz; a = p[i].p_vaddr & -pagesz;
b = (p[i].p_vaddr + p[i].p_memsz + (pagesz - 1)) & -pagesz; b = (p[i].p_vaddr + p[i].p_memsz + (pagesz - 1)) & -pagesz;
for (j = i + 1; j < e->e_phnum; ++j) { for (j = i + 1; j < e->e_phnum; ++j) {
if (p[j].p_type != PT_LOAD) continue; if (p[j].p_type != PT_LOAD)
continue;
c = p[j].p_vaddr & -pagesz; c = p[j].p_vaddr & -pagesz;
d = (p[j].p_vaddr + p[j].p_memsz + (pagesz - 1)) & -pagesz; d = (p[j].p_vaddr + p[j].p_memsz + (pagesz - 1)) & -pagesz;
if (MAX(a, c) < MIN(b, d)) { if (MAX(a, c) < MIN(b, d)) {
@ -614,7 +622,8 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
if (e->e_type == ET_DYN) { if (e->e_type == ET_DYN) {
rc = sys_mmap(0, virtmax - virtmin, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, rc = sys_mmap(0, virtmax - virtmin, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
-1, 0); -1, 0);
if (rc < 0) Pexit(exe, rc, "pie mmap"); if (rc < 0)
Pexit(exe, rc, "pie mmap");
dynbase = rc; dynbase = rc;
if (dynbase & (pagesz - 1)) { if (dynbase & (pagesz - 1)) {
Pexit(exe, 0, "OS mmap incongruent w/ AT_PAGESZ"); Pexit(exe, 0, "OS mmap incongruent w/ AT_PAGESZ");
@ -630,14 +639,18 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
for (i = 0; i < e->e_phnum; ++i) { for (i = 0; i < e->e_phnum; ++i) {
void *addr; void *addr;
unsigned long size; unsigned long size;
if (p[i].p_type != PT_LOAD) continue; if (p[i].p_type != PT_LOAD)
continue;
/* configure mapping */ /* configure mapping */
prot = 0; prot = 0;
flags = MAP_FIXED | MAP_PRIVATE; flags = MAP_FIXED | MAP_PRIVATE;
if (p[i].p_flags & PF_R) prot |= PROT_READ; if (p[i].p_flags & PF_R)
if (p[i].p_flags & PF_W) prot |= PROT_WRITE; prot |= PROT_READ;
if (p[i].p_flags & PF_X) prot |= PROT_EXEC; if (p[i].p_flags & PF_W)
prot |= PROT_WRITE;
if (p[i].p_flags & PF_X)
prot |= PROT_EXEC;
/* load from file */ /* load from file */
if (p[i].p_filesz) { if (p[i].p_filesz) {
@ -687,24 +700,30 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
as the default strategy which is slow but it works for both */ as the default strategy which is slow but it works for both */
rc = sys_mmap(addr, size, (prot1 = PROT_READ | PROT_WRITE), rc = sys_mmap(addr, size, (prot1 = PROT_READ | PROT_WRITE),
MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0); MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
if (rc < 0) Pexit(exe, rc, "prog mmap anon"); if (rc < 0)
Pexit(exe, rc, "prog mmap anon");
rc = pread(fd, addr, p[i].p_filesz, p[i].p_offset & -pagesz); rc = pread(fd, addr, p[i].p_filesz, p[i].p_offset & -pagesz);
if (rc != p[i].p_filesz) Pexit(exe, -errno, "prog pread"); if (rc != p[i].p_filesz)
Pexit(exe, -errno, "prog pread");
#endif #endif
} else { } else {
rc = sys_mmap(addr, size, prot1, flags, fd, p[i].p_offset & -pagesz); rc = sys_mmap(addr, size, prot1, flags, fd, p[i].p_offset & -pagesz);
if (rc < 0) Pexit(exe, rc, "prog mmap"); if (rc < 0)
Pexit(exe, rc, "prog mmap");
} }
if (wipe) memset((void *)(dynbase + a), 0, wipe); if (wipe)
memset((void *)(dynbase + a), 0, wipe);
if (prot2 != prot1) { if (prot2 != prot1) {
rc = sys_mprotect(addr, size, prot2); rc = sys_mprotect(addr, size, prot2);
if (rc < 0) Pexit(exe, rc, "prog mprotect"); if (rc < 0)
Pexit(exe, rc, "prog mprotect");
} }
/* allocate extra bss */ /* allocate extra bss */
if (c > b) { if (c > b) {
flags |= MAP_ANONYMOUS; flags |= MAP_ANONYMOUS;
rc = sys_mmap((void *)(dynbase + b), c - b, prot, flags, -1, 0); rc = sys_mmap((void *)(dynbase + b), c - b, prot, flags, -1, 0);
if (rc < 0) Pexit(exe, rc, "extra bss mmap"); if (rc < 0)
Pexit(exe, rc, "extra bss mmap");
} }
} else { } else {
/* allocate pure bss */ /* allocate pure bss */
@ -712,7 +731,8 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_memsz; size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_memsz;
flags |= MAP_ANONYMOUS; flags |= MAP_ANONYMOUS;
rc = sys_mmap(addr, size, prot, flags, -1, 0); rc = sys_mmap(addr, size, prot, flags, -1, 0);
if (rc < 0) Pexit(exe, rc, "bss mmap"); if (rc < 0)
Pexit(exe, rc, "bss mmap");
} }
} }
@ -790,8 +810,10 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
/* read program headers */ /* read program headers */
rc = pread(fd, M->phdr.buf, size, ebuf->ehdr.e_phoff); rc = pread(fd, M->phdr.buf, size, ebuf->ehdr.e_phoff);
if (rc < 0) return "failed to read ELF program headers"; if (rc < 0)
if (rc != size) return "truncated read of ELF program headers"; return "failed to read ELF program headers";
if (rc != size)
return "truncated read of ELF program headers";
/* bail on recoverable program header errors */ /* bail on recoverable program header errors */
p = &M->phdr.phdr; p = &M->phdr.phdr;
@ -970,7 +992,8 @@ int main(int argc, char **argv, char **envp) {
grows down the alloc by poking the guard pages */ grows down the alloc by poking the guard pages */
n = (auxv - sp + AUXV_WORDS + 1) * sizeof(long); n = (auxv - sp + AUXV_WORDS + 1) * sizeof(long);
sp2 = (long *)__builtin_alloca(n); sp2 = (long *)__builtin_alloca(n);
if ((long)sp2 & 15) ++sp2; if ((long)sp2 & 15)
++sp2;
for (; n > 0; n -= pagesz) { for (; n > 0; n -= pagesz) {
((char *)sp2)[n - 1] = 0; ((char *)sp2)[n - 1] = 0;
} }

View file

@ -228,13 +228,15 @@ extern char _end[];
static unsigned long StrLen(const char *s) { static unsigned long StrLen(const char *s) {
unsigned long n = 0; unsigned long n = 0;
while (*s++) ++n; while (*s++)
++n;
return n; return n;
} }
static int StrCmp(const char *l, const char *r) { static int StrCmp(const char *l, const char *r) {
unsigned long i = 0; unsigned long i = 0;
while (l[i] == r[i] && r[i]) ++i; while (l[i] == r[i] && r[i])
++i;
return (l[i] & 255) - (r[i] & 255); return (l[i] & 255) - (r[i] & 255);
} }
@ -353,7 +355,8 @@ static char *Utoa(char p[20], unsigned long x) {
} }
static char *Itoa(char p[21], long x) { static char *Itoa(char p[21], long x) {
if (x < 0) *p++ = '-', x = -(unsigned long)x; if (x < 0)
*p++ = '-', x = -(unsigned long)x;
return Utoa(p, x); return Utoa(p, x);
} }
@ -362,7 +365,8 @@ __attribute__((__noinline__)) static long CallSystem(long arg1, long arg2,
long arg5, long arg6, long arg5, long arg6,
long arg7, int numba, long arg7, int numba,
char os) { char os) {
if (IsXnu()) numba |= 0x2000000; if (IsXnu())
numba |= 0x2000000;
return SystemCall(arg1, arg2, arg3, arg4, arg5, arg6, arg7, numba); return SystemCall(arg1, arg2, arg3, arg4, arg5, arg6, arg7, numba);
} }
@ -529,7 +533,8 @@ static long Printf(int os, int fd, const char *fmt, ...) {
switch ((c = *fmt++)) { switch ((c = *fmt++)) {
case 's': case 's':
for (s = __builtin_va_arg(va, const char *); s && *s; ++s) { for (s = __builtin_va_arg(va, const char *); s && *s; ++s) {
if (k < 512) b[k++] = *s; if (k < 512)
b[k++] = *s;
} }
break; break;
case 'd': case 'd':
@ -542,16 +547,19 @@ static long Printf(int os, int fd, const char *fmt, ...) {
u -= 10; u -= 10;
c = 'a' + u; c = 'a' + u;
} }
if (k < 512) b[k++] = c; if (k < 512)
b[k++] = c;
} }
break; break;
default: default:
if (k < 512) b[k++] = c; if (k < 512)
b[k++] = c;
break; break;
} }
break; break;
default: default:
if (k < 512) b[k++] = c; if (k < 512)
b[k++] = c;
break; break;
} }
} }
@ -560,7 +568,8 @@ static long Printf(int os, int fd, const char *fmt, ...) {
static void Perror(int os, const char *thing, long rc, const char *reason) { static void Perror(int os, const char *thing, long rc, const char *reason) {
char ibuf[21]; char ibuf[21];
ibuf[0] = 0; ibuf[0] = 0;
if (rc) Itoa(ibuf, -rc); if (rc)
Itoa(ibuf, -rc);
Print(os, 2, "ape error: ", thing, ": ", reason, Print(os, 2, "ape error: ", thing, ": ", reason,
rc ? " failed w/ errno " : "", ibuf, "\n", 0l); rc ? " failed w/ errno " : "", ibuf, "\n", 0l);
} }
@ -572,8 +581,10 @@ __attribute__((__noreturn__)) static void Pexit(int os, const char *c, int rc,
} }
static char AccessCommand(struct PathSearcher *ps, unsigned long pathlen) { static char AccessCommand(struct PathSearcher *ps, unsigned long pathlen) {
if (pathlen + 1 + ps->namelen + 1 > sizeof(ps->path)) return 0; if (pathlen + 1 + ps->namelen + 1 > sizeof(ps->path))
if (pathlen && ps->path[pathlen - 1] != '/') ps->path[pathlen++] = '/'; return 0;
if (pathlen && ps->path[pathlen - 1] != '/')
ps->path[pathlen++] = '/';
MemMove(ps->path + pathlen, ps->name, ps->namelen); MemMove(ps->path + pathlen, ps->name, ps->namelen);
ps->path[pathlen + ps->namelen] = 0; ps->path[pathlen + ps->namelen] = 0;
return !Access(ps->path, X_OK, ps->os); return !Access(ps->path, X_OK, ps->os);
@ -600,11 +611,14 @@ static char SearchPath(struct PathSearcher *ps) {
static char *Commandv(struct PathSearcher *ps, int os, char *name, static char *Commandv(struct PathSearcher *ps, int os, char *name,
const char *syspath) { const char *syspath) {
if (!(ps->namelen = StrLen((ps->name = name)))) return 0; if (!(ps->namelen = StrLen((ps->name = name))))
if (ps->literally || MemChr(ps->name, '/', ps->namelen)) return name; return 0;
if (ps->literally || MemChr(ps->name, '/', ps->namelen))
return name;
ps->os = os; ps->os = os;
ps->syspath = syspath ? syspath : "/bin:/usr/local/bin:/usr/bin"; ps->syspath = syspath ? syspath : "/bin:/usr/local/bin:/usr/bin";
if (ps->namelen + 1 > sizeof(ps->path)) return 0; if (ps->namelen + 1 > sizeof(ps->path))
return 0;
ps->path[0] = 0; ps->path[0] = 0;
if (SearchPath(ps)) { if (SearchPath(ps)) {
return ps->path; return ps->path;
@ -661,7 +675,8 @@ __attribute__((__noreturn__)) static void Spawn(int os, char *exe, int fd,
Pexit(os, exe, 0, "ELF segments overlap your APE loader"); Pexit(os, exe, 0, "ELF segments overlap your APE loader");
} }
for (j = i + 1; j < e->e_phnum; ++j) { for (j = i + 1; j < e->e_phnum; ++j) {
if (p[j].p_type != PT_LOAD) continue; if (p[j].p_type != PT_LOAD)
continue;
c = p[j].p_vaddr & -pagesz; c = p[j].p_vaddr & -pagesz;
d = (p[j].p_vaddr + p[j].p_memsz + (pagesz - 1)) & -pagesz; d = (p[j].p_vaddr + p[j].p_memsz + (pagesz - 1)) & -pagesz;
if (MAX(a, c) < MIN(b, d)) { if (MAX(a, c) < MIN(b, d)) {
@ -694,7 +709,8 @@ __attribute__((__noreturn__)) static void Spawn(int os, char *exe, int fd,
if (e->e_type == ET_DYN) { if (e->e_type == ET_DYN) {
rc = Mmap(0, virtmax - virtmin, PROT_NONE, rc = Mmap(0, virtmax - virtmin, PROT_NONE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0, os); MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0, os);
if (rc < 0) Pexit(os, exe, rc, "pie mmap"); if (rc < 0)
Pexit(os, exe, rc, "pie mmap");
dynbase = rc; dynbase = rc;
if (dynbase & (pagesz - 1)) { if (dynbase & (pagesz - 1)) {
Pexit(os, exe, 0, "OS mmap incongruent w/ AT_PAGESZ"); Pexit(os, exe, 0, "OS mmap incongruent w/ AT_PAGESZ");
@ -710,14 +726,18 @@ __attribute__((__noreturn__)) static void Spawn(int os, char *exe, int fd,
for (i = 0; i < e->e_phnum; ++i) { for (i = 0; i < e->e_phnum; ++i) {
void *addr; void *addr;
unsigned long size; unsigned long size;
if (p[i].p_type != PT_LOAD) continue; if (p[i].p_type != PT_LOAD)
continue;
/* configure mapping */ /* configure mapping */
prot = 0; prot = 0;
flags = MAP_FIXED | MAP_PRIVATE; flags = MAP_FIXED | MAP_PRIVATE;
if (p[i].p_flags & PF_R) prot |= PROT_READ; if (p[i].p_flags & PF_R)
if (p[i].p_flags & PF_W) prot |= PROT_WRITE; prot |= PROT_READ;
if (p[i].p_flags & PF_X) prot |= PROT_EXEC; if (p[i].p_flags & PF_W)
prot |= PROT_WRITE;
if (p[i].p_flags & PF_X)
prot |= PROT_EXEC;
if (p[i].p_filesz) { if (p[i].p_filesz) {
/* load from file */ /* load from file */
@ -744,17 +764,21 @@ __attribute__((__noreturn__)) static void Spawn(int os, char *exe, int fd,
addr = (void *)(dynbase + (p[i].p_vaddr & -pagesz)); addr = (void *)(dynbase + (p[i].p_vaddr & -pagesz));
size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_filesz; size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_filesz;
rc = Mmap(addr, size, prot1, flags, fd, p[i].p_offset & -pagesz, os); rc = Mmap(addr, size, prot1, flags, fd, p[i].p_offset & -pagesz, os);
if (rc < 0) Pexit(os, exe, rc, "prog mmap"); if (rc < 0)
if (wipe) Bzero((void *)(dynbase + a), wipe); Pexit(os, exe, rc, "prog mmap");
if (wipe)
Bzero((void *)(dynbase + a), wipe);
if (prot2 != prot1) { if (prot2 != prot1) {
rc = Mprotect(addr, size, prot2, os); rc = Mprotect(addr, size, prot2, os);
if (rc < 0) Pexit(os, exe, rc, "prog mprotect"); if (rc < 0)
Pexit(os, exe, rc, "prog mprotect");
} }
/* allocate extra bss */ /* allocate extra bss */
if (c > b) { if (c > b) {
flags |= MAP_ANONYMOUS; flags |= MAP_ANONYMOUS;
rc = Mmap((void *)(dynbase + b), c - b, prot, flags, -1, 0, os); rc = Mmap((void *)(dynbase + b), c - b, prot, flags, -1, 0, os);
if (rc < 0) Pexit(os, exe, rc, "extra bss mmap"); if (rc < 0)
Pexit(os, exe, rc, "extra bss mmap");
} }
} else { } else {
/* allocate pure bss */ /* allocate pure bss */
@ -762,7 +786,8 @@ __attribute__((__noreturn__)) static void Spawn(int os, char *exe, int fd,
size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_memsz; size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_memsz;
flags |= MAP_ANONYMOUS; flags |= MAP_ANONYMOUS;
rc = Mmap(addr, size, prot, flags, -1, 0, os); rc = Mmap(addr, size, prot, flags, -1, 0, os);
if (rc < 0) Pexit(os, exe, rc, "bss mmap"); if (rc < 0)
Pexit(os, exe, rc, "bss mmap");
} }
} }
@ -783,7 +808,8 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
struct ElfPhdr *p; struct ElfPhdr *p;
/* validate page size */ /* validate page size */
if (!pagesz) pagesz = 4096; if (!pagesz)
pagesz = 4096;
if (pagesz & (pagesz - 1)) { if (pagesz & (pagesz - 1)) {
Pexit(os, exe, 0, "AT_PAGESZ isn't two power"); Pexit(os, exe, 0, "AT_PAGESZ isn't two power");
} }
@ -818,8 +844,10 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
/* read program headers */ /* read program headers */
rc = Pread(fd, M->phdr.buf, size, e->e_phoff, os); rc = Pread(fd, M->phdr.buf, size, e->e_phoff, os);
if (rc < 0) return "failed to read ELF program headers"; if (rc < 0)
if (rc != size) return "truncated read of ELF program headers"; return "failed to read ELF program headers";
if (rc != size)
return "truncated read of ELF program headers";
/* bail on recoverable program header errors */ /* bail on recoverable program header errors */
p = &M->phdr.phdr; p = &M->phdr.phdr;
@ -949,7 +977,8 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
/* determine ape loader program name */ /* determine ape loader program name */
ape = argv[0]; ape = argv[0];
if (!ape) ape = "ape"; if (!ape)
ape = "ape";
/* detect openbsd */ /* detect openbsd */
if (SupportsOpenbsd() && !os && !auxv[0]) { if (SupportsOpenbsd() && !os && !auxv[0]) {
@ -1021,7 +1050,8 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
grows down the alloc by poking the guard pages */ grows down the alloc by poking the guard pages */
n = (endp - sp + 1) * sizeof(long); n = (endp - sp + 1) * sizeof(long);
sp2 = (long *)__builtin_alloca(n); sp2 = (long *)__builtin_alloca(n);
if ((long)sp2 & 15) ++sp2; if ((long)sp2 & 15)
++sp2;
for (; n > 0; n -= pagesz) { for (; n > 0; n -= pagesz) {
((char *)sp2)[n - 1] = 0; ((char *)sp2)[n - 1] = 0;
} }

View file

@ -197,7 +197,8 @@ static char *FormatUint32(char *p, uint32_t x) {
} }
static char *FormatInt32(char *p, int32_t x) { static char *FormatInt32(char *p, int32_t x) {
if (x < 0) *p++ = '-', x = -(uint32_t)x; if (x < 0)
*p++ = '-', x = -(uint32_t)x;
return FormatUint32(p, x); return FormatUint32(p, x);
} }
@ -205,7 +206,8 @@ static size_t StrCat(char *dst, const char *src, size_t dsize) {
size_t m, n = dsize; size_t m, n = dsize;
const char *p = dst; const char *p = dst;
const char *q = src; const char *q = src;
while (n-- != 0 && *dst != '\0') dst++; while (n-- != 0 && *dst != '\0')
dst++;
m = dst - p; m = dst - p;
n = dsize - m; n = dsize - m;
if (n-- == 0) { if (n-- == 0) {
@ -277,7 +279,8 @@ static bool IsSupportedPath(const char *path) {
for (i = 0;; ++i) { for (i = 0;; ++i) {
switch (path[i]) { switch (path[i]) {
case 0: case 0:
if (i) return true; if (i)
return true;
// fallthrough // fallthrough
case '\r': case '\r':
case '\n': case '\n':
@ -320,8 +323,10 @@ static bool ProduceDigest(const char *path, FILE *f) {
char hexdigest[65]; char hexdigest[65];
char mode[2] = {g_mode}; char mode[2] = {g_mode};
unsigned char digest[32]; unsigned char digest[32];
if (!IsSupportedPath(path)) return false; if (!IsSupportedPath(path))
if (!GetDigest(path, f, digest)) return false; return false;
if (!GetDigest(path, f, digest))
return false;
CopyHex(hexdigest, digest, 32); CopyHex(hexdigest, digest, 32);
Write(1, hexdigest, " ", mode, path, "\n", NULL); Write(1, hexdigest, " ", mode, path, "\n", NULL);
return true; return true;
@ -361,17 +366,24 @@ static bool CheckDigests(const char *path, FILE *f) {
uint8_t wantdigest[32], gotdigest[32]; uint8_t wantdigest[32], gotdigest[32];
char buf[64 + 2 + PATH_MAX + 1 + 1], *p; char buf[64 + 2 + PATH_MAX + 1 + 1], *p;
for (line = 0; fgets(buf, sizeof(buf), f); ++line) { for (line = 0; fgets(buf, sizeof(buf), f); ++line) {
if (!*Chomp(buf)) continue; if (!*Chomp(buf))
continue;
for (p = buf, i = 0; i < 32; ++i) { for (p = buf, i = 0; i < 32; ++i) {
if ((a = HexToInt(*p++ & 255)) == -1) goto InvalidLine; if ((a = HexToInt(*p++ & 255)) == -1)
if ((b = HexToInt(*p++ & 255)) == -1) goto InvalidLine; goto InvalidLine;
if ((b = HexToInt(*p++ & 255)) == -1)
goto InvalidLine;
wantdigest[i] = a << 4 | b; wantdigest[i] = a << 4 | b;
} }
if (*p++ != ' ') goto InvalidLine; if (*p++ != ' ')
if (!IsModeCharacter(*p++)) goto InvalidLine; goto InvalidLine;
if (!IsModeCharacter(*p++))
goto InvalidLine;
path2 = p; path2 = p;
if (!*path2) goto InvalidLine; if (!*path2)
if (!IsSupportedPath(path2)) continue; goto InvalidLine;
if (!IsSupportedPath(path2))
continue;
if ((f2 = fopen(path2, "rb"))) { if ((f2 = fopen(path2, "rb"))) {
if (GetDigest(path2, f2, gotdigest)) { if (GetDigest(path2, f2, gotdigest)) {
if (!memcmp(wantdigest, gotdigest, 32)) { if (!memcmp(wantdigest, gotdigest, 32)) {

View file

@ -27,7 +27,8 @@
*/ */
int alaw(int x) { int alaw(int x) {
int a, b, i; int a, b, i;
if ((a = x) < 0) a = ~a; if ((a = x) < 0)
a = ~a;
a >>= 4; a >>= 4;
if (a > 15) { if (a > 15) {
if ((i = a >> 5)) { if ((i = a >> 5)) {
@ -40,6 +41,7 @@ int alaw(int x) {
a += 16; a += 16;
} }
} }
if (x >= 0) a |= 128; if (x >= 0)
a |= 128;
return a ^ 85; return a ^ 85;
} }

View file

@ -28,13 +28,15 @@
int mulaw(int x) { int mulaw(int x) {
int b, i, a, s, l, h; int b, i, a, s, l, h;
a = x < 0 ? (~x >> 2) + 33 : (x >> 2) + 33; a = x < 0 ? (~x >> 2) + 33 : (x >> 2) + 33;
if (a > 8191) a = 8191; if (a > 8191)
a = 8191;
i = a >> 6; i = a >> 6;
s = i ? (__builtin_clz(i) ^ 31) + 2 : 1; s = i ? (__builtin_clz(i) ^ 31) + 2 : 1;
h = 8 - s; h = 8 - s;
l = (a >> s) & 15; l = (a >> s) & 15;
l = 15 - l; l = 15 - l;
b = (h << 4) | l; b = (h << 4) | l;
if (x >= 0) b |= 128; if (x >= 0)
b |= 128;
return b; return b;
} }

View file

@ -29,7 +29,8 @@ void scalevolume(size_t n, int16_t pcm[n][8], int p) {
/* TODO(jart): This isn't acceptable. */ /* TODO(jart): This isn't acceptable. */
size_t i, j; size_t i, j;
if (p > 0) { if (p > 0) {
if (p > 15) p = 15; if (p > 15)
p = 15;
for (i = 0; i < n; ++i) { for (i = 0; i < n; ++i) {
for (j = 0; j < 8; ++j) { for (j = 0; j < 8; ++j) {
pcm[i][j] = pcm[i][j] =
@ -38,7 +39,8 @@ void scalevolume(size_t n, int16_t pcm[n][8], int p) {
} }
} else if (p < 0) { } else if (p < 0) {
p = -p; p = -p;
if (p > 15) p = 15; if (p > 15)
p = 15;
for (i = 0; i < n; ++i) { for (i = 0; i < n; ++i) {
for (j = 0; j < 8; ++j) { for (j = 0; j < 8; ++j) {
pcm[i][j] = pcm[i][j] >> p; pcm[i][j] = pcm[i][j] >> p;

View file

@ -31,8 +31,10 @@ int unalaw(int x) {
i = (x ^ 85) & 127; i = (x ^ 85) & 127;
e = i >> 4; e = i >> 4;
m = i & 15; m = i & 15;
if (e > 0) m += 16; if (e > 0)
m += 16;
m = (m << 4) + 8; m = (m << 4) + 8;
if (e > 1) m = m << (e - 1); if (e > 1)
m = m << (e - 1);
return x & 128 ? m : -m; return x & 128 ? m : -m;
} }

View file

@ -46,7 +46,8 @@ forceinline void plm_video_process_macroblock(plm_video_t *self,
si = ((self->mb_row * BW) + vp) * dw + (self->mb_col * BW) + hp; si = ((self->mb_row * BW) + vp) * dw + (self->mb_col * BW) + hp;
di = (self->mb_row * dw + self->mb_col) * BW; di = (self->mb_row * dw + self->mb_col) * BW;
max_address = (dw * (self->mb_height * BW - BW + 1) - BW); max_address = (dw * (self->mb_height * BW - BW + 1) - BW);
if (si > max_address || di > max_address) return; if (si > max_address || di > max_address)
return;
d += di; d += di;
s += si; s += si;
switch (((interpolate << 2) | (odd_h << 1) | (odd_v)) & 7) { switch (((interpolate << 2) | (odd_h << 1) | (odd_v)) & 7) {

View file

@ -77,7 +77,8 @@ static struct SamplingSolution *NewSamplingSolution(long n, long s) {
static bool IsNormalized(int n, double A[n]) { static bool IsNormalized(int n, double A[n]) {
int i; int i;
double x; double x;
for (x = i = 0; i < n; ++i) x += A[i]; for (x = i = 0; i < n; ++i)
x += A[i];
return fabs(x - 1) < 1e-4; return fabs(x - 1) < 1e-4;
} }
@ -96,8 +97,10 @@ struct SamplingSolution *ComputeSamplingSolution(long dn, long sn, double dar,
short *weights, *indices; short *weights, *indices;
struct SamplingSolution *res; struct SamplingSolution *res;
long j, i, k, n, min, max, s, N[6]; long j, i, k, n, min, max, s, N[6];
if (!dar) dar = sn, dar /= dn; if (!dar)
if (!off) off = (dar - 1) / 2; dar = sn, dar /= dn;
if (!off)
off = (dar - 1) / 2;
f = dar < 1 ? 1 / dar : dar; f = dar < 1 ? 1 / dar : dar;
s = 3 * f + 4; s = 3 * f + 4;
fweights = gc(xcalloc(s + /*xxx*/ 2, sizeof(double))); fweights = gc(xcalloc(s + /*xxx*/ 2, sizeof(double)));
@ -114,8 +117,10 @@ struct SamplingSolution *ComputeSamplingSolution(long dn, long sn, double dar,
for (k = 0, j = min; j <= max; ++j) { for (k = 0, j = min; j <= max; ++j) {
fweights[k++] = ComputeWeight((j - x) / (f / par)); fweights[k++] = ComputeWeight((j - x) / (f / par));
} }
for (sum = k = 0; k < n; ++k) sum += fweights[k]; for (sum = k = 0; k < n; ++k)
for (j = 0; j < n; ++j) fweights[j] *= 1 / sum; sum += fweights[k];
for (j = 0; j < n; ++j)
fweights[j] *= 1 / sum;
DCHECK(IsNormalized(n, fweights)); DCHECK(IsNormalized(n, fweights));
for (j = 0; j < n; ++j) { for (j = 0; j < n; ++j) {
indices[i * s + j] = MIN(sn - 1, MAX(0, min + j)); indices[i * s + j] = MIN(sn - 1, MAX(0, min + j));

View file

@ -30,8 +30,10 @@
static int ttysetcursor(int fd, bool visible) { static int ttysetcursor(int fd, bool visible) {
struct NtConsoleCursorInfo ntcursor; struct NtConsoleCursorInfo ntcursor;
char code[8] = "\e[?25l"; char code[8] = "\e[?25l";
if (__nocolor) return 0; if (__nocolor)
if (visible) code[5] = 'h'; return 0;
if (visible)
code[5] = 'h';
if (IsWindows()) { if (IsWindows()) {
GetConsoleCursorInfo(GetStdHandle(kNtStdOutputHandle), &ntcursor); GetConsoleCursorInfo(GetStdHandle(kNtStdOutputHandle), &ntcursor);
ntcursor.bVisible = visible; ntcursor.bVisible = visible;

View file

@ -21,16 +21,20 @@
#include "libc/limits.h" #include "libc/limits.h"
static char *ansitoa(char *p, unsigned xt, unsigned base) { static char *ansitoa(char *p, unsigned xt, unsigned base) {
if (xt >= 8) xt -= 8, base += 60; if (xt >= 8)
xt -= 8, base += 60;
return itoa8(p, xt + base); return itoa8(p, xt + base);
} }
static char *setansibgfg(char *p, unsigned bg, unsigned fg) { static char *setansibgfg(char *p, unsigned bg, unsigned fg) {
*p++ = '\e'; *p++ = '\e';
*p++ = '['; *p++ = '[';
if (bg != -1u) p = ansitoa(p, bg, 40); if (bg != -1u)
if (bg != -1u && fg != -1u) *p++ = ';'; p = ansitoa(p, bg, 40);
if (fg != -1u) p = ansitoa(p, fg, 30); if (bg != -1u && fg != -1u)
*p++ = ';';
if (fg != -1u)
p = ansitoa(p, fg, 30);
*p++ = 'm'; *p++ = 'm';
return p; return p;
} }

View file

@ -666,7 +666,8 @@ static char *CopyBlock(char *v, const struct TtyRgb chunk[hasatleast 4],
struct Glyph *glyph) { struct Glyph *glyph) {
unsigned i; unsigned i;
CHECK_LT(pick.bg, 4); CHECK_LT(pick.bg, 4);
if (pick.fg != 0xff) CHECK_LT(pick.fg, 4); if (pick.fg != 0xff)
CHECK_LT(pick.fg, 4);
i = 0; i = 0;
if (pick.fg == 0xff) { if (pick.fg == 0xff) {
if (!ttyeq(*bg, chunk[pick.bg])) { if (!ttyeq(*bg, chunk[pick.bg])) {
@ -744,7 +745,8 @@ static dontinline char *CopyRun(char *v, size_t n,
v = CopyGlyph(v, *glyph); v = CopyGlyph(v, *glyph);
*x += 2; *x += 2;
*c += 2; *c += 2;
if (*x >= n) break; if (*x >= n)
break;
CopyChunk(chunk, *c, n); CopyChunk(chunk, *c, n);
} while (ChunkEq(chunk, lastchunk)); } while (ChunkEq(chunk, lastchunk));
*x -= 2; *x -= 2;

View file

@ -69,13 +69,16 @@ static textstartup int ttyraw_enable(void) {
} }
static textstartup void ttyraw_hidecursor(void) { static textstartup void ttyraw_hidecursor(void) {
if (!g_ttyraw.setup) return; if (!g_ttyraw.setup)
if (g_ttyraw.flags & kTtyCursor) return; return;
if (g_ttyraw.flags & kTtyCursor)
return;
ttyhidecursor(FD); ttyhidecursor(FD);
} }
static textexit int ttyraw_disable(void) { static textexit int ttyraw_disable(void) {
if (!g_ttyraw.setup) return 0; if (!g_ttyraw.setup)
return 0;
ttyshowcursor(FD); ttyshowcursor(FD);
return ttyrestore(FD, &g_ttyraw.old); return ttyrestore(FD, &g_ttyraw.old);
} }
@ -87,7 +90,8 @@ static textexit void ttyraw_onexit(void) {
static relegated void ttyraw_onsig(int sig, struct siginfo *info, static relegated void ttyraw_onsig(int sig, struct siginfo *info,
struct ucontext *ctx) { struct ucontext *ctx) {
size_t i; size_t i;
if (g_ttyraw.noreentry) _Exit(128 + sig); if (g_ttyraw.noreentry)
_Exit(128 + sig);
g_ttyraw.noreentry = true; g_ttyraw.noreentry = true;
if (g_ttyraw.flags != -1) { if (g_ttyraw.flags != -1) {
if (sig == SIGCONT) { if (sig == SIGCONT) {

View file

@ -104,8 +104,10 @@ void *Worker(void *id) {
if (client == -1) { if (client == -1) {
// accept() errors are generally ephemeral or recoverable // accept() errors are generally ephemeral or recoverable
// it'd potentially be a good idea to exponential backoff here // it'd potentially be a good idea to exponential backoff here
if (errno == ECANCELED) continue; // pthread_cancel() was called if (errno == ECANCELED)
if (errno == EMFILE) ExplainPrlimit(); continue; // pthread_cancel() was called
if (errno == EMFILE)
ExplainPrlimit();
LOG("accept() returned %m"); LOG("accept() returned %m");
SomethingHappened(); SomethingHappened();
continue; continue;
@ -346,8 +348,10 @@ int main(int argc, char *argv[]) {
if ((rc = pthread_create(th + i, &attr, Worker, (void *)(intptr_t)i))) { if ((rc = pthread_create(th + i, &attr, Worker, (void *)(intptr_t)i))) {
--a_workers; --a_workers;
kprintf("pthread_create failed: %s\n", strerror(rc)); kprintf("pthread_create failed: %s\n", strerror(rc));
if (rc == EAGAIN) ExplainPrlimit(); if (rc == EAGAIN)
if (!i) exit(1); ExplainPrlimit();
if (!i)
exit(1);
threads = i; threads = i;
break; break;
} }
@ -364,7 +368,8 @@ int main(int argc, char *argv[]) {
PrintEphemeralStatusLine(); PrintEphemeralStatusLine();
unassert(!pthread_cond_wait(&statuscond, &statuslock)); unassert(!pthread_cond_wait(&statuscond, &statuslock));
// limit status line updates to sixty frames per second // limit status line updates to sixty frames per second
do tick = timespec_add(tick, (struct timespec){0, 1e9 / 60}); do
tick = timespec_add(tick, (struct timespec){0, 1e9 / 60});
while (timespec_cmp(tick, timespec_real()) < 0); while (timespec_cmp(tick, timespec_real()) < 0);
clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &tick, 0); clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &tick, 0);
} }
@ -378,7 +383,8 @@ int main(int argc, char *argv[]) {
} }
// on windows this is the only way accept() can be canceled // on windows this is the only way accept() can be canceled
if (IsWindows()) close(server); if (IsWindows())
close(server);
// print status in terminal as the shutdown progresses // print status in terminal as the shutdown progresses
unassert(!pthread_mutex_lock(&statuslock)); unassert(!pthread_mutex_lock(&statuslock));
@ -394,7 +400,8 @@ int main(int argc, char *argv[]) {
} }
// close the server socket // close the server socket
if (!IsWindows()) close(server); if (!IsWindows())
close(server);
// clean up terminal line // clean up terminal line
LOG("thank you for choosing \e[32mgreenbean\e[0m"); LOG("thank you for choosing \e[32mgreenbean\e[0m");

View file

@ -212,10 +212,13 @@ void editorAtExit(void) {
int enableRawMode(int64_t fd) { int enableRawMode(int64_t fd) {
struct termios raw; struct termios raw;
if (E.rawmode) return 0; /* Already enabled. */ if (E.rawmode)
if (!isatty(STDIN_FILENO)) goto fatal; return 0; /* Already enabled. */
if (!isatty(STDIN_FILENO))
goto fatal;
atexit(editorAtExit); atexit(editorAtExit);
if (tcgetattr(fd, &orig_termios) == -1) goto fatal; if (tcgetattr(fd, &orig_termios) == -1)
goto fatal;
raw = orig_termios; /* modify the original mode */ raw = orig_termios; /* modify the original mode */
/* input modes: no break, no CR to NL, no parity check, no strip char, /* input modes: no break, no CR to NL, no parity check, no strip char,
@ -233,7 +236,8 @@ int enableRawMode(int64_t fd) {
raw.c_cc[VTIME] = 1; /* 100 ms timeout (unit is tens of second). */ raw.c_cc[VTIME] = 1; /* 100 ms timeout (unit is tens of second). */
/* put terminal in raw mode after flushing */ /* put terminal in raw mode after flushing */
if (tcsetattr(fd, TCSAFLUSH, &raw) < 0) goto fatal; if (tcsetattr(fd, TCSAFLUSH, &raw) < 0)
goto fatal;
E.rawmode = 1; E.rawmode = 1;
return 0; return 0;
@ -249,7 +253,8 @@ int editorReadKey(int64_t fd) {
char c, seq[3]; char c, seq[3];
do { do {
nread = read(fd, &c, 1); nread = read(fd, &c, 1);
if (nread == -1) exit(1); if (nread == -1)
exit(1);
} while (!nread); } while (!nread);
while (1) { while (1) {
@ -260,12 +265,15 @@ int editorReadKey(int64_t fd) {
return PAGE_DOWN; return PAGE_DOWN;
case '\e': /* escape sequence */ case '\e': /* escape sequence */
/* If this is just an ESC, we'll timeout here. */ /* If this is just an ESC, we'll timeout here. */
if (read(fd, seq, 1) == 0) return CTRL('['); if (read(fd, seq, 1) == 0)
return CTRL('[');
if (seq[0] == '[') { if (seq[0] == '[') {
if (read(fd, seq + 1, 1) == 0) return CTRL('['); if (read(fd, seq + 1, 1) == 0)
return CTRL('[');
if (seq[1] >= '0' && seq[1] <= '9') { if (seq[1] >= '0' && seq[1] <= '9') {
/* Extended escape, read additional byte. */ /* Extended escape, read additional byte. */
if (read(fd, seq + 2, 1) == 0) return CTRL('['); if (read(fd, seq + 2, 1) == 0)
return CTRL('[');
if (seq[2] == '~') { if (seq[2] == '~') {
switch (seq[1]) { switch (seq[1]) {
case '1': case '1':
@ -308,7 +316,8 @@ int editorReadKey(int64_t fd) {
} else if (seq[0] == 'v') { } else if (seq[0] == 'v') {
return PAGE_UP; return PAGE_UP;
} else if (seq[0] == 'O') { } else if (seq[0] == 'O') {
if (read(fd, seq + 1, 1) == 0) return CTRL('['); if (read(fd, seq + 1, 1) == 0)
return CTRL('[');
/* ESC O sequences. */ /* ESC O sequences. */
switch (seq[1]) { switch (seq[1]) {
case 'H': case 'H':
@ -332,19 +341,24 @@ int getCursorPosition(int64_t ifd, int64_t ofd, int *rows, int *cols) {
unsigned i = 0; unsigned i = 0;
/* Report cursor location */ /* Report cursor location */
if (write(ofd, "\e[6n", 4) != 4) return -1; if (write(ofd, "\e[6n", 4) != 4)
return -1;
/* Read the response: ESC [ rows ; cols R */ /* Read the response: ESC [ rows ; cols R */
while (i < sizeof(buf) - 1) { while (i < sizeof(buf) - 1) {
if (read(ifd, buf + i, 1) != 1) break; if (read(ifd, buf + i, 1) != 1)
if (buf[i] == 'R') break; break;
if (buf[i] == 'R')
break;
i++; i++;
} }
buf[i] = '\0'; buf[i] = '\0';
/* Parse it. */ /* Parse it. */
if (buf[0] != CTRL('[') || buf[1] != '[') return -1; if (buf[0] != CTRL('[') || buf[1] != '[')
if (sscanf(buf + 2, "%d;%d", rows, cols) != 2) return -1; return -1;
if (sscanf(buf + 2, "%d;%d", rows, cols) != 2)
return -1;
return 0; return 0;
} }
@ -359,12 +373,15 @@ int getWindowSize(int64_t ifd, int64_t ofd, int *rows, int *cols) {
/* Get the initial position so we can restore it later. */ /* Get the initial position so we can restore it later. */
retval = getCursorPosition(ifd, ofd, &orig_row, &orig_col); retval = getCursorPosition(ifd, ofd, &orig_row, &orig_col);
if (retval == -1) goto failed; if (retval == -1)
goto failed;
/* Go to right/bottom margin and get position. */ /* Go to right/bottom margin and get position. */
if (write(ofd, "\e[999C\e[999B", 12) != 12) goto failed; if (write(ofd, "\e[999C\e[999B", 12) != 12)
goto failed;
retval = getCursorPosition(ifd, ofd, rows, cols); retval = getCursorPosition(ifd, ofd, rows, cols);
if (retval == -1) goto failed; if (retval == -1)
goto failed;
/* Restore position. */ /* Restore position. */
char seq[32]; char seq[32];
@ -406,7 +423,8 @@ void editorUpdateSyntax(erow *row) {
row->hl = realloc(row->hl, row->rsize); row->hl = realloc(row->hl, row->rsize);
memset(row->hl, HL_NORMAL, row->rsize); memset(row->hl, HL_NORMAL, row->rsize);
if (E.syntax == NULL) return; /* No syntax, everything is HL_NORMAL. */ if (E.syntax == NULL)
return; /* No syntax, everything is HL_NORMAL. */
int i, prev_sep, in_string, in_comment; int i, prev_sep, in_string, in_comment;
char *p; char *p;
@ -475,7 +493,8 @@ void editorUpdateSyntax(erow *row) {
prev_sep = 0; prev_sep = 0;
continue; continue;
} }
if (*p == in_string) in_string = 0; if (*p == in_string)
in_string = 0;
p++; p++;
i++; i++;
continue; continue;
@ -515,7 +534,8 @@ void editorUpdateSyntax(erow *row) {
for (j = 0; keywords[j]; j++) { for (j = 0; keywords[j]; j++) {
int klen = strlen(keywords[j]); int klen = strlen(keywords[j]);
int kw2 = keywords[j][klen - 1] == '|'; int kw2 = keywords[j][klen - 1] == '|';
if (kw2) klen--; if (kw2)
klen--;
if (!memcmp(p, keywords[j], klen) && is_separator(*(p + klen))) { if (!memcmp(p, keywords[j], klen) && is_separator(*(p + klen))) {
/* Keyword */ /* Keyword */
@ -599,7 +619,8 @@ void editorUpdateRow(erow *row) {
* respecting tabs, substituting non printable characters with '?'. */ * respecting tabs, substituting non printable characters with '?'. */
free(row->render); free(row->render);
for (j = 0; j < row->size; j++) { for (j = 0; j < row->size; j++) {
if (row->chars[j] == '\t') tabs++; if (row->chars[j] == '\t')
tabs++;
} }
row->render = malloc(row->size + tabs * 8 + nonprint * 9 + 1); row->render = malloc(row->size + tabs * 8 + nonprint * 9 + 1);
@ -626,11 +647,13 @@ void editorUpdateRow(erow *row) {
/* Insert a row at the specified position, shifting the other rows on the bottom /* Insert a row at the specified position, shifting the other rows on the bottom
* if required. */ * if required. */
void editorInsertRow(int at, char *s, size_t len) { void editorInsertRow(int at, char *s, size_t len) {
if (at > E.numrows) return; if (at > E.numrows)
return;
E.row = realloc(E.row, sizeof(erow) * (E.numrows + 1)); E.row = realloc(E.row, sizeof(erow) * (E.numrows + 1));
if (at != E.numrows) { if (at != E.numrows) {
memmove(E.row + at + 1, E.row + at, sizeof(E.row[0]) * (E.numrows - at)); memmove(E.row + at + 1, E.row + at, sizeof(E.row[0]) * (E.numrows - at));
for (int j = at + 1; j <= E.numrows; j++) E.row[j].idx++; for (int j = at + 1; j <= E.numrows; j++)
E.row[j].idx++;
} }
E.row[at].size = len; E.row[at].size = len;
E.row[at].chars = malloc(len + 1); E.row[at].chars = malloc(len + 1);
@ -657,11 +680,13 @@ void editorFreeRow(erow *row) {
void editorDelRow(int at) { void editorDelRow(int at) {
erow *row; erow *row;
if (at >= E.numrows) return; if (at >= E.numrows)
return;
row = E.row + at; row = E.row + at;
editorFreeRow(row); editorFreeRow(row);
memmove(E.row + at, E.row + at + 1, sizeof(E.row[0]) * (E.numrows - at - 1)); memmove(E.row + at, E.row + at + 1, sizeof(E.row[0]) * (E.numrows - at - 1));
for (int j = at; j < E.numrows - 1; j++) E.row[j].idx++; for (int j = at; j < E.numrows - 1; j++)
E.row[j].idx++;
E.numrows--; E.numrows--;
E.dirty++; E.dirty++;
} }
@ -729,7 +754,8 @@ void editorRowAppendString(erow *row, char *s, size_t len) {
/* Delete the character at offset 'at' from the specified row. */ /* Delete the character at offset 'at' from the specified row. */
void editorRowDelChar(erow *row, int at) { void editorRowDelChar(erow *row, int at) {
if (row->size <= at) return; if (row->size <= at)
return;
memmove(row->chars + at, row->chars + at + 1, row->size - at); memmove(row->chars + at, row->chars + at + 1, row->size - at);
editorUpdateRow(row); editorUpdateRow(row);
row->size--; row->size--;
@ -745,7 +771,8 @@ void editorInsertChar(int c) {
/* If the row where the cursor is currently located does not exist in our /* If the row where the cursor is currently located does not exist in our
* logical representation of the file, add enough empty rows as needed. */ * logical representation of the file, add enough empty rows as needed. */
if (!row) { if (!row) {
while (E.numrows <= filerow) editorInsertRow(E.numrows, "", 0); while (E.numrows <= filerow)
editorInsertRow(E.numrows, "", 0);
} }
row = &E.row[filerow]; row = &E.row[filerow];
editorRowInsertChar(row, filecol, c); editorRowInsertChar(row, filecol, c);
@ -773,7 +800,8 @@ void editorInsertNewline(void) {
} }
/* If the cursor is over the current line size, we want to conceptually /* If the cursor is over the current line size, we want to conceptually
* think it's just over the last character. */ * think it's just over the last character. */
if (filecol >= row->size) filecol = row->size; if (filecol >= row->size)
filecol = row->size;
if (filecol == 0) { if (filecol == 0) {
editorInsertRow(filerow, "", 0); editorInsertRow(filerow, "", 0);
} else { } else {
@ -800,7 +828,8 @@ void editorDelChar(void) {
int filecol = E.coloff + E.cx; int filecol = E.coloff + E.cx;
erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow]; erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow];
if (!row || (filecol == 0 && filerow == 0)) return; if (!row || (filecol == 0 && filerow == 0))
return;
if (filecol == 0) { if (filecol == 0) {
/* Handle the case of column 0, we need to move the current line /* Handle the case of column 0, we need to move the current line
* on the right of the previous one. */ * on the right of the previous one. */
@ -825,7 +854,8 @@ void editorDelChar(void) {
else else
E.cx--; E.cx--;
} }
if (row) editorUpdateRow(row); if (row)
editorUpdateRow(row);
E.dirty++; E.dirty++;
} }
@ -868,12 +898,15 @@ int editorSave(void) {
int len; int len;
char *buf = editorRowsToString(&len); char *buf = editorRowsToString(&len);
int64_t fd = open(E.filename, O_RDWR | O_CREAT, 0644); int64_t fd = open(E.filename, O_RDWR | O_CREAT, 0644);
if (fd == -1) goto writeerr; if (fd == -1)
goto writeerr;
/* Use truncate + a single write(2) call in order to make saving /* Use truncate + a single write(2) call in order to make saving
* a bit safer, under the limits of what we can do in a small editor. */ * a bit safer, under the limits of what we can do in a small editor. */
if (ftruncate(fd, len) == -1) goto writeerr; if (ftruncate(fd, len) == -1)
if (write(fd, buf, len) != len) goto writeerr; goto writeerr;
if (write(fd, buf, len) != len)
goto writeerr;
close(fd); close(fd);
free(buf); free(buf);
@ -883,7 +916,8 @@ int editorSave(void) {
writeerr: writeerr:
free(buf); free(buf);
if (fd != -1) close(fd); if (fd != -1)
close(fd);
editorSetStatusMessage("Can't save! I/O error: %s", strerror(errno)); editorSetStatusMessage("Can't save! I/O error: %s", strerror(errno));
return 1; return 1;
} }
@ -924,7 +958,8 @@ void editorRefreshScreen(void) {
abAppend(&ab, "~", 1); abAppend(&ab, "~", 1);
padding--; padding--;
} }
while (padding--) abAppend(&ab, " ", 1); while (padding--)
abAppend(&ab, " ", 1);
abAppend(&ab, welcome, welcomelen); abAppend(&ab, welcome, welcomelen);
} else { } else {
abAppend(&ab, "~\e[0K\r\n", 7); abAppend(&ab, "~\e[0K\r\n", 7);
@ -939,7 +974,8 @@ void editorRefreshScreen(void) {
int current_color = -1; int current_color = -1;
#endif #endif
if (len > 0) { if (len > 0) {
if (len > E.screencols) len = E.screencols; if (len > E.screencols)
len = E.screencols;
char *c = r->render + E.coloff; char *c = r->render + E.coloff;
#if SYNTAX #if SYNTAX
unsigned char *hl = r->hl + E.coloff; unsigned char *hl = r->hl + E.coloff;
@ -990,7 +1026,8 @@ void editorRefreshScreen(void) {
E.numrows, E.dirty ? "(modified)" : ""); E.numrows, E.dirty ? "(modified)" : "");
int rlen = snprintf(rstatus, sizeof(rstatus), "%d/%d", E.rowoff + E.cy + 1, int rlen = snprintf(rstatus, sizeof(rstatus), "%d/%d", E.rowoff + E.cy + 1,
E.numrows); E.numrows);
if (len > E.screencols) len = E.screencols; if (len > E.screencols)
len = E.screencols;
abAppend(&ab, status, len); abAppend(&ab, status, len);
while (len < E.screencols) { while (len < E.screencols) {
if (E.screencols - len == rlen) { if (E.screencols - len == rlen) {
@ -1018,7 +1055,8 @@ void editorRefreshScreen(void) {
erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow]; erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow];
if (row) { if (row) {
for (j = E.coloff; j < (E.cx + E.coloff); j++) { for (j = E.coloff; j < (E.cx + E.coloff); j++) {
if (j < row->size && row->chars[j] == CTRL('I')) cx += 7 - ((cx) % 8); if (j < row->size && row->chars[j] == CTRL('I'))
cx += 7 - ((cx) % 8);
cx++; cx++;
} }
} }
@ -1069,7 +1107,8 @@ void editorFind(int64_t fd) {
int c = editorReadKey(fd); int c = editorReadKey(fd);
if (c == DEL_KEY || c == CTRL('H') || c == CTRL('?')) { if (c == DEL_KEY || c == CTRL('H') || c == CTRL('?')) {
if (qlen != 0) query[--qlen] = '\0'; if (qlen != 0)
query[--qlen] = '\0';
last_match = -1; last_match = -1;
} else if (c == CTRL('G')) { } else if (c == CTRL('G')) {
break; break;
@ -1096,7 +1135,8 @@ void editorFind(int64_t fd) {
} }
/* Search occurrence. */ /* Search occurrence. */
if (last_match == -1) find_next = 1; if (last_match == -1)
find_next = 1;
if (find_next) { if (find_next) {
char *match = NULL; char *match = NULL;
int match_offset = 0; int match_offset = 0;
@ -1190,7 +1230,8 @@ void editorMoveCursor(int key) {
break; break;
case ARROW_UP: case ARROW_UP:
if (E.cy == 0) { if (E.cy == 0) {
if (E.rowoff) E.rowoff--; if (E.rowoff)
E.rowoff--;
} else { } else {
E.cy -= 1; E.cy -= 1;
} }
@ -1299,9 +1340,11 @@ void editorProcessKeypress(int64_t fd) {
case CTRL('L'): case CTRL('L'):
times = E.screenrows / 2; times = E.screenrows / 2;
while (times--) editorMoveCursor(c == PAGE_UP ? ARROW_UP : ARROW_DOWN); while (times--)
editorMoveCursor(c == PAGE_UP ? ARROW_UP : ARROW_DOWN);
times = E.screenrows / 2; times = E.screenrows / 2;
while (times--) editorMoveCursor(c == PAGE_UP ? ARROW_DOWN : ARROW_UP); while (times--)
editorMoveCursor(c == PAGE_UP ? ARROW_DOWN : ARROW_UP);
break; break;
case PAGE_UP: case PAGE_UP:
@ -1312,14 +1355,17 @@ void editorProcessKeypress(int64_t fd) {
E.cy = E.screenrows - 1; E.cy = E.screenrows - 1;
} }
times = E.screenrows; times = E.screenrows;
while (times--) editorMoveCursor(c == PAGE_UP ? ARROW_UP : ARROW_DOWN); while (times--)
editorMoveCursor(c == PAGE_UP ? ARROW_UP : ARROW_DOWN);
times = E.screenrows / 2; times = E.screenrows / 2;
while (times--) editorMoveCursor(c == PAGE_UP ? ARROW_DOWN : ARROW_UP); while (times--)
editorMoveCursor(c == PAGE_UP ? ARROW_DOWN : ARROW_UP);
break; break;
case HOME_KEY: case HOME_KEY:
case CTRL('A'): case CTRL('A'):
while (E.cx || E.coloff) editorMoveCursor(ARROW_LEFT); while (E.cx || E.coloff)
editorMoveCursor(ARROW_LEFT);
break; break;
case END_KEY: case END_KEY:
case CTRL('E'): case CTRL('E'):

View file

@ -492,7 +492,8 @@ void TransmitVideo(void) {
ssize_t rc; ssize_t rc;
struct Frame* f; struct Frame* f;
f = &vf_[frame_]; f = &vf_[frame_];
if (!HasVideo(f)) f = FlipFrameBuffer(); if (!HasVideo(f))
f = FlipFrameBuffer();
if ((rc = Write(STDOUT_FILENO, f->w, f->p - f->w)) != -1) { if ((rc = Write(STDOUT_FILENO, f->w, f->p - f->w)) != -1) {
f->w += rc; f->w += rc;
} else if (errno == EAGAIN) { } else if (errno == EAGAIN) {
@ -504,9 +505,12 @@ void TransmitVideo(void) {
void TransmitAudio(void) { void TransmitAudio(void) {
ssize_t rc; ssize_t rc;
if (!playpid_) return; if (!playpid_)
if (!audio_.i) return; return;
if (playfd_ == -1) return; if (!audio_.i)
return;
if (playfd_ == -1)
return;
if ((rc = Write(playfd_, audio_.p, audio_.i * sizeof(short))) != -1) { if ((rc = Write(playfd_, audio_.p, audio_.i * sizeof(short))) != -1) {
rc /= sizeof(short); rc /= sizeof(short);
memmove(audio_.p, audio_.p + rc, (audio_.i - rc) * sizeof(short)); memmove(audio_.p, audio_.p + rc, (audio_.i - rc) * sizeof(short));
@ -561,9 +565,12 @@ void KeyCountdown(struct Action* a) {
void PollAndSynchronize(void) { void PollAndSynchronize(void) {
do { do {
if (ReadKeyboard() == -1) { if (ReadKeyboard() == -1) {
if (errno != EINTR) Exit(1); if (errno != EINTR)
if (exited_) Exit(0); Exit(1);
if (resized_) GetTermSize(); if (exited_)
Exit(0);
if (resized_)
GetTermSize();
} }
} while (!timeout_); } while (!timeout_);
TransmitVideo(); TransmitVideo();
@ -734,7 +741,8 @@ u8 Access(unsigned addr, u8 value, bool write) {
} }
} }
} }
if ((addr >> 13) == 3) return PRAM[addr & 0x1FFF]; if ((addr >> 13) == 3)
return PRAM[addr & 0x1FFF];
return banks[(addr / RomGranularity) % RomPages][addr % RomGranularity]; return banks[(addr / RomGranularity) % RomPages][addr % RomGranularity];
} }
@ -828,7 +836,8 @@ bool offset_toggle = false;
u8& NesMmap(int i) { u8& NesMmap(int i) {
i &= 0x3FFF; i &= 0x3FFF;
if (i >= 0x3F00) { if (i >= 0x3F00) {
if (i % 4 == 0) i &= 0x0F; if (i % 4 == 0)
i &= 0x0F;
return palette[i & 0x1F]; return palette[i & 0x1F];
} }
if (i < 0x2000) { if (i < 0x2000) {
@ -844,7 +853,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
return open_bus_decay_timer = 77777, open_bus = v; return open_bus_decay_timer = 77777, open_bus = v;
}; };
u8 res = open_bus; u8 res = open_bus;
if (write) RefreshOpenBus(v); if (write)
RefreshOpenBus(v);
switch (index) { // Which port from $200x? switch (index) { // Which port from $200x?
case 0: case 0:
if (write) { if (write) {
@ -858,7 +868,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
} }
break; break;
case 2: case 2:
if (write) break; if (write)
break;
res = reg.status | (open_bus & 0x1F); res = reg.status | (open_bus & 0x1F);
reg.InVBlank = false; // Reading $2002 clears the vblank flag. reg.InVBlank = false; // Reading $2002 clears the vblank flag.
offset_toggle = false; // Also resets the toggle for address updates. offset_toggle = false; // Also resets the toggle for address updates.
@ -867,7 +878,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
} }
break; break;
case 3: case 3:
if (write) reg.OAMaddr = v; if (write)
reg.OAMaddr = v;
break; // Index into Object Attribute Memory break; // Index into Object Attribute Memory
case 4: case 4:
if (write) { if (write) {
@ -878,7 +890,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
} }
break; break;
case 5: case 5:
if (!write) break; // Set background scrolling offset if (!write)
break; // Set background scrolling offset
if (offset_toggle) { if (offset_toggle) {
scroll.yfine = v & 7; scroll.yfine = v & 7;
scroll.ycoarse = v >> 3; scroll.ycoarse = v >> 3;
@ -888,7 +901,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
offset_toggle = !offset_toggle; offset_toggle = !offset_toggle;
break; break;
case 6: case 6:
if (!write) break; // Set video memory position for reads/writes if (!write)
break; // Set video memory position for reads/writes
if (offset_toggle) { if (offset_toggle) {
scroll.vaddrlo = v; scroll.vaddrlo = v;
vaddr.raw = (unsigned)scroll.raw; vaddr.raw = (unsigned)scroll.raw;
@ -926,17 +940,21 @@ void RenderingTick() {
case 2: // Point to attribute table case 2: // Point to attribute table
ioaddr = 0x23C0 + 0x400 * vaddr.basenta + 8 * (vaddr.ycoarse / 4) + ioaddr = 0x23C0 + 0x400 * vaddr.basenta + 8 * (vaddr.ycoarse / 4) +
(vaddr.xcoarse / 4); (vaddr.xcoarse / 4);
if (tile_decode_mode) break; // Or nametable, with sprites. if (tile_decode_mode)
case 0: // Point to nametable break; // Or nametable, with sprites.
case 0: // Point to nametable
ioaddr = 0x2000 + (vaddr.raw & 0xFFF); ioaddr = 0x2000 + (vaddr.raw & 0xFFF);
// Reset sprite data // Reset sprite data
if (x_ == 0) { if (x_ == 0) {
sprinpos = sproutpos = 0; sprinpos = sproutpos = 0;
if (reg.ShowSP) reg.OAMaddr = 0; if (reg.ShowSP)
reg.OAMaddr = 0;
} }
if (!reg.ShowBG) break; if (!reg.ShowBG)
break;
// Reset scrolling (vertical once, horizontal each scanline) // Reset scrolling (vertical once, horizontal each scanline)
if (x_ == 304 && scanline == -1) vaddr.raw = (unsigned)scroll.raw; if (x_ == 304 && scanline == -1)
vaddr.raw = (unsigned)scroll.raw;
if (x_ == 256) { if (x_ == 256) {
vaddr.xcoarse = (unsigned)scroll.xcoarse; vaddr.xcoarse = (unsigned)scroll.xcoarse;
vaddr.basenta_h = (unsigned)scroll.basenta_h; vaddr.basenta_h = (unsigned)scroll.basenta_h;
@ -949,7 +967,8 @@ void RenderingTick() {
} }
// Name table access // Name table access
pat_addr = 0x1000 * reg.BGaddr + 16 * NesMmap(ioaddr) + vaddr.yfine; pat_addr = 0x1000 * reg.BGaddr + 16 * NesMmap(ioaddr) + vaddr.yfine;
if (!tile_decode_mode) break; if (!tile_decode_mode)
break;
// Push the current tile into shift registers. // Push the current tile into shift registers.
// The bitmap pattern is 16 bits, while the attribute is 2 bits, repeated // The bitmap pattern is 16 bits, while the attribute is 2 bits, repeated
// 8 times. // 8 times.
@ -976,7 +995,8 @@ void RenderingTick() {
auto& o = OAM3[sprrenpos]; // Sprite to render on next scanline auto& o = OAM3[sprrenpos]; // Sprite to render on next scanline
memcpy(&o, &OAM2[sprrenpos], sizeof(o)); memcpy(&o, &OAM2[sprrenpos], sizeof(o));
unsigned y = (scanline)-o.y; unsigned y = (scanline)-o.y;
if (o.attr & 0x80) y ^= (reg.SPsize ? 15 : 7); if (o.attr & 0x80)
y ^= (reg.SPsize ? 15 : 7);
pat_addr = 0x1000 * (reg.SPsize ? (o.index & 0x01) : reg.SPaddr); pat_addr = 0x1000 * (reg.SPsize ? (o.index & 0x01) : reg.SPaddr);
pat_addr += 0x10 * (reg.SPsize ? (o.index & 0xFE) : (o.index & 0xFF)); pat_addr += 0x10 * (reg.SPsize ? (o.index & 0xFE) : (o.index & 0xFF));
pat_addr += (y & 7) + (y & 8) * 2; pat_addr += (y & 7) + (y & 8) * 2;
@ -1011,8 +1031,10 @@ void RenderingTick() {
break; break;
} }
++sprinpos; // next sprite ++sprinpos; // next sprite
if (sproutpos < 8) OAM2[sproutpos].y = sprtmp; if (sproutpos < 8)
if (sproutpos < 8) OAM2[sproutpos].sprindex = reg.OAMindex; OAM2[sproutpos].y = sprtmp;
if (sproutpos < 8)
OAM2[sproutpos].sprindex = reg.OAMindex;
y1 = sprtmp; y1 = sprtmp;
y2 = sprtmp + (reg.SPsize ? 16 : 8); y2 = sprtmp + (reg.SPsize ? 16 : 8);
if (!(scanline >= y1 && scanline < y2)) { if (!(scanline >= y1 && scanline < y2)) {
@ -1020,19 +1042,23 @@ void RenderingTick() {
} }
break; break;
case 1: case 1:
if (sproutpos < 8) OAM2[sproutpos].index = sprtmp; if (sproutpos < 8)
OAM2[sproutpos].index = sprtmp;
break; break;
case 2: case 2:
if (sproutpos < 8) OAM2[sproutpos].attr = sprtmp; if (sproutpos < 8)
OAM2[sproutpos].attr = sprtmp;
break; break;
case 3: case 3:
if (sproutpos < 8) OAM2[sproutpos].x_ = sprtmp; if (sproutpos < 8)
OAM2[sproutpos].x_ = sprtmp;
if (sproutpos < 8) { if (sproutpos < 8) {
++sproutpos; ++sproutpos;
} else { } else {
reg.SPoverflow = true; reg.SPoverflow = true;
} }
if (sprinpos == 2) reg.OAMaddr = 8; if (sprinpos == 2)
reg.OAMaddr = 8;
break; break;
} }
} }
@ -1060,13 +1086,17 @@ void RenderPixel() {
auto& s = OAM3[sno]; auto& s = OAM3[sno];
// Check if this sprite is horizontally in range // Check if this sprite is horizontally in range
unsigned xdiff = x_ - s.x_; unsigned xdiff = x_ - s.x_;
if (xdiff >= 8) continue; // Also matches negative values if (xdiff >= 8)
continue; // Also matches negative values
// Determine which pixel to display; skip transparent pixels // Determine which pixel to display; skip transparent pixels
if (!(s.attr & 0x40)) xdiff = 7 - xdiff; if (!(s.attr & 0x40))
xdiff = 7 - xdiff;
u8 spritepixel = (s.pattern >> (xdiff * 2)) & 3; u8 spritepixel = (s.pattern >> (xdiff * 2)) & 3;
if (!spritepixel) continue; if (!spritepixel)
continue;
// Register sprite-0 hit if applicable // Register sprite-0 hit if applicable
if (x_ < 255 && pixel && s.sprindex == 0) reg.SP0hit = true; if (x_ < 255 && pixel && s.sprindex == 0)
reg.SP0hit = true;
// Render the pixel unless behind-background placement wanted // Render the pixel unless behind-background placement wanted
if (!(s.attr & 0x20) || !pixel) { if (!(s.attr & 0x20) || !pixel) {
attr = (s.attr & 3) + 4; attr = (s.attr & 3) + 4;
@ -1095,11 +1125,13 @@ void ReadToolAssistedSpeedrunRobotKeys() {
} }
if (ctrlmask & 0x80) { if (ctrlmask & 0x80) {
joy_next_[0] = fgetc(fp); joy_next_[0] = fgetc(fp);
if (feof(fp)) joy_next_[0] = 0; if (feof(fp))
joy_next_[0] = 0;
} }
if (ctrlmask & 0x40) { if (ctrlmask & 0x40) {
joy_next_[1] = fgetc(fp); joy_next_[1] = fgetc(fp);
if (feof(fp)) joy_next_[1] = 0; if (feof(fp))
joy_next_[1] = 0;
} }
} }
} }
@ -1144,18 +1176,23 @@ void Tick() {
CPU::nmi = reg.InVBlank && reg.NMIenabled; CPU::nmi = reg.InVBlank && reg.NMIenabled;
break; break;
} }
if (VBlankState != 0) VBlankState += (VBlankState < 0 ? 1 : -1); if (VBlankState != 0)
if (open_bus_decay_timer && !--open_bus_decay_timer) open_bus = 0; VBlankState += (VBlankState < 0 ? 1 : -1);
if (open_bus_decay_timer && !--open_bus_decay_timer)
open_bus = 0;
// Graphics processing scanline? // Graphics processing scanline?
if (scanline < DYN) { if (scanline < DYN) {
/* Process graphics for this cycle */ /* Process graphics for this cycle */
if (reg.ShowBGSP) RenderingTick(); if (reg.ShowBGSP)
if (scanline >= 0 && x_ < 256) RenderPixel(); RenderingTick();
if (scanline >= 0 && x_ < 256)
RenderPixel();
} }
// Done with the cycle. Check for end of scanline. // Done with the cycle. Check for end of scanline.
if (++cycle_counter == 3) cycle_counter = 0; // For NTSC pixel shifting if (++cycle_counter == 3)
cycle_counter = 0; // For NTSC pixel shifting
if (++x_ >= scanline_end) { if (++x_ >= scanline_end) {
// Begin new scanline // Begin new scanline
FlushScanline(scanline); FlushScanline(scanline);
@ -1242,30 +1279,36 @@ struct channel {
template <unsigned c> template <unsigned c>
int Tick() { int Tick() {
channel& ch = *this; channel& ch = *this;
if (!ChannelsEnabled[c]) return c == 4 ? 64 : 8; if (!ChannelsEnabled[c])
return c == 4 ? 64 : 8;
int wl = (ch.reg.WaveLength + 1) * (c >= 2 ? 1 : 2); int wl = (ch.reg.WaveLength + 1) * (c >= 2 ? 1 : 2);
if (c == 3) wl = NoisePeriods[ch.reg.NoiseFreq]; if (c == 3)
wl = NoisePeriods[ch.reg.NoiseFreq];
int volume = ch.length_counter int volume = ch.length_counter
? ch.reg.EnvDecayDisable ? ch.reg.FixedVolume : ch.envelope ? ch.reg.EnvDecayDisable ? ch.reg.FixedVolume : ch.envelope
: 0; : 0;
// Sample may change at wavelen intervals. // Sample may change at wavelen intervals.
auto& S = ch.level; auto& S = ch.level;
if (!count(ch.wave_counter, wl)) return S; if (!count(ch.wave_counter, wl))
return S;
switch (c) { switch (c) {
default: // Square wave. With four different 8-step binary waveforms (32 default: // Square wave. With four different 8-step binary waveforms (32
// bits of data total). // bits of data total).
if (wl < 8) return S = 8; if (wl < 8)
return S = 8;
return S = (0xF33C0C04u & return S = (0xF33C0C04u &
(1u << (++ch.phase % 8 + ch.reg.DutyCycle * 8))) (1u << (++ch.phase % 8 + ch.reg.DutyCycle * 8)))
? volume ? volume
: 0; : 0;
case 2: // Triangle wave case 2: // Triangle wave
if (ch.length_counter && ch.linear_counter && wl >= 3) ++ch.phase; if (ch.length_counter && ch.linear_counter && wl >= 3)
++ch.phase;
return S = (ch.phase & 15) ^ ((ch.phase & 16) ? 15 : 0); return S = (ch.phase & 15) ^ ((ch.phase & 16) ? 15 : 0);
case 3: // Noise: Linear feedback shift register case 3: // Noise: Linear feedback shift register
if (!ch.hold) ch.hold = 1; if (!ch.hold)
ch.hold = 1;
ch.hold = ch.hold =
(ch.hold >> 1) | (ch.hold >> 1) |
(((ch.hold ^ (ch.hold >> (ch.reg.NoiseType ? 6 : 1))) & 1) << 14); (((ch.hold ^ (ch.hold >> (ch.reg.NoiseType ? 6 : 1))) & 1) << 14);
@ -1302,7 +1345,8 @@ struct channel {
} else { } else {
v -= 2; v -= 2;
} }
if (v >= 0 && v <= 0x7F) ch.linear_counter = v; if (v >= 0 && v <= 0x7F)
ch.linear_counter = v;
} }
return S = ch.linear_counter; return S = ch.linear_counter;
} }
@ -1338,7 +1382,8 @@ void Write(u8 index, u8 value) {
ch.linear_counter = ch.reg.LinearCounterInit; ch.linear_counter = ch.reg.LinearCounterInit;
ch.env_delay = ch.reg.EnvDecayRate; ch.env_delay = ch.reg.EnvDecayRate;
ch.envelope = 15; ch.envelope = 15;
if (index < 8) ch.phase = 0; if (index < 8)
ch.phase = 0;
break; break;
case 0x10: case 0x10:
ch.reg.reg3 = value; ch.reg.reg3 = value;
@ -1384,9 +1429,11 @@ u8 Read() {
for (c = 0; c < 5; ++c) { for (c = 0; c < 5; ++c) {
res |= channels[c].length_counter ? 1 << c : 0; res |= channels[c].length_counter ? 1 << c : 0;
} }
if (PeriodicIRQ) res |= 0x40; if (PeriodicIRQ)
res |= 0x40;
PeriodicIRQ = false; PeriodicIRQ = false;
if (DMC_IRQ) res |= 0x80; if (DMC_IRQ)
res |= 0x80;
DMC_IRQ = false; DMC_IRQ = false;
CPU::intr = false; CPU::intr = false;
return res; return res;
@ -1396,7 +1443,8 @@ void Tick() { // Invoked at CPU's rate.
// Divide CPU clock by 7457.5 to get a 240 Hz, which controls certain events. // Divide CPU clock by 7457.5 to get a 240 Hz, which controls certain events.
if ((hz240counter.lo += 2) >= 14915) { if ((hz240counter.lo += 2) >= 14915) {
hz240counter.lo -= 14915; hz240counter.lo -= 14915;
if (++hz240counter.hi >= 4 + FiveCycleDivider) hz240counter.hi = 0; if (++hz240counter.hi >= 4 + FiveCycleDivider)
hz240counter.hi = 0;
// 60 Hz interval: IRQ. IRQ is not invoked in five-cycle mode (48 Hz). // 60 Hz interval: IRQ. IRQ is not invoked in five-cycle mode (48 Hz).
if (!IRQdisable && !FiveCycleDivider && hz240counter.hi == 0) { if (!IRQdisable && !FiveCycleDivider && hz240counter.hi == 0) {
@ -1422,7 +1470,8 @@ void Tick() { // Invoked at CPU's rate.
if (wl >= 8 && ch.reg.SweepEnable && ch.reg.SweepShift) { if (wl >= 8 && ch.reg.SweepEnable && ch.reg.SweepShift) {
int s = wl >> ch.reg.SweepShift, d[4] = {s, s, ~s, -s}; int s = wl >> ch.reg.SweepShift, d[4] = {s, s, ~s, -s};
wl += d[ch.reg.SweepDecrease * 2 + c]; wl += d[ch.reg.SweepDecrease * 2 + c];
if (wl < 0x800) ch.reg.WaveLength = wl; if (wl < 0x800)
ch.reg.WaveLength = wl;
} }
// Linear tick (triangle wave only) // Linear tick (triangle wave only)
@ -1464,20 +1513,24 @@ namespace CPU {
void Tick() { void Tick() {
// PPU clock: 3 times the CPU rate // PPU clock: 3 times the CPU rate
for (unsigned n = 0; n < 3; ++n) PPU::Tick(); for (unsigned n = 0; n < 3; ++n)
PPU::Tick();
// APU clock: 1 times the CPU rate // APU clock: 1 times the CPU rate
for (unsigned n = 0; n < 1; ++n) APU::Tick(); for (unsigned n = 0; n < 1; ++n)
APU::Tick();
} }
template <bool write> template <bool write>
u8 MemAccess(u16 addr, u8 v) { u8 MemAccess(u16 addr, u8 v) {
// Memory writes are turned into reads while reset is being signalled // Memory writes are turned into reads while reset is being signalled
if (reset && write) return MemAccess<0>(addr); if (reset && write)
return MemAccess<0>(addr);
Tick(); Tick();
// Map the memory from CPU's viewpoint. // Map the memory from CPU's viewpoint.
/**/ if (addr < 0x2000) { /**/ if (addr < 0x2000) {
u8& r = RAM[addr & 0x7FF]; u8& r = RAM[addr & 0x7FF];
if (!write) return r; if (!write)
return r;
r = v; r = v;
} else if (addr < 0x4000) { } else if (addr < 0x4000) {
return PPU::PpuAccess(addr & 7, v, write); return PPU::PpuAccess(addr & 7, v, write);
@ -1489,17 +1542,21 @@ u8 MemAccess(u16 addr, u8 v) {
WB(0x2004, RB((v & 7) * 0x0100 + b)); WB(0x2004, RB((v & 7) * 0x0100 + b));
return 0; return 0;
case 0x15: case 0x15:
if (!write) return APU::Read(); if (!write)
return APU::Read();
APU::Write(0x15, v); APU::Write(0x15, v);
break; break;
case 0x16: case 0x16:
if (!write) return JoyRead(0); if (!write)
return JoyRead(0);
JoyStrobe(v); JoyStrobe(v);
break; break;
case 0x17: case 0x17:
if (!write) return JoyRead(1); // write:passthru if (!write)
return JoyRead(1); // write:passthru
default: default:
if (!write) break; if (!write)
break;
APU::Write(addr & 0x1F, v); APU::Write(addr & 0x1F, v);
} }
} else { } else {
@ -1527,7 +1584,8 @@ u16 wrap(u16 oldaddr, u16 newaddr) {
} }
void Misfire(u16 old, u16 addr) { void Misfire(u16 old, u16 addr) {
u16 q = wrap(old, addr); u16 q = wrap(old, addr);
if (q != addr) RB(q); if (q != addr)
RB(q);
} }
u8 Pop() { u8 Pop() {
return RB(0x100 | u8(++S)); return RB(0x100 | u8(++S));
@ -1655,7 +1713,8 @@ void Op() {
} else if (intr && !P.I) { } else if (intr && !P.I) {
op = 0x102; op = 0x102;
} }
if (!nmi_now) nmi_edge_detected = false; if (!nmi_now)
nmi_edge_detected = false;
// Define function pointers for each opcode (00..FF) and each interrupt // Define function pointers for each opcode (00..FF) and each interrupt
// (100,101,102) // (100,101,102)
@ -1757,12 +1816,15 @@ Press enter to continue without sound: ",
fgetc(fp); fgetc(fp);
fgetc(fp); fgetc(fp);
if (mappernum >= 0x40) mappernum &= 15; if (mappernum >= 0x40)
mappernum &= 15;
GamePak::mappernum = mappernum; GamePak::mappernum = mappernum;
// Read the ROM data // Read the ROM data
if (rom16count) GamePak::ROM.resize(rom16count * 0x4000); if (rom16count)
if (vrom8count) GamePak::VRAM.resize(vrom8count * 0x2000); GamePak::ROM.resize(rom16count * 0x4000);
if (vrom8count)
GamePak::VRAM.resize(vrom8count * 0x2000);
fread(&GamePak::ROM[0], rom16count, 0x4000, fp); fread(&GamePak::ROM[0], rom16count, 0x4000, fp);
fread(&GamePak::VRAM[0], vrom8count, 0x2000, fp); fread(&GamePak::VRAM[0], vrom8count, 0x2000, fp);
@ -1776,10 +1838,12 @@ Press enter to continue without sound: ",
PPU::reg.value = 0; PPU::reg.value = 0;
// Pre-initialize RAM the same way as FCEUX does, to improve TAS sync. // Pre-initialize RAM the same way as FCEUX does, to improve TAS sync.
for (unsigned a = 0; a < 0x800; ++a) CPU::RAM[a] = (a & 4) ? 0xFF : 0x00; for (unsigned a = 0; a < 0x800; ++a)
CPU::RAM[a] = (a & 4) ? 0xFF : 0x00;
// Run the CPU until the program is killed. // Run the CPU until the program is killed.
for (;;) CPU::Op(); for (;;)
CPU::Op();
} }
wontreturn void PrintUsage(int rc, FILE* f) { wontreturn void PrintUsage(int rc, FILE* f) {

View file

@ -123,14 +123,16 @@ int picolParseCommand(struct picolParser *p) {
} else if (*p->p == '[' && blevel == 0) { } else if (*p->p == '[' && blevel == 0) {
level++; level++;
} else if (*p->p == ']' && blevel == 0) { } else if (*p->p == ']' && blevel == 0) {
if (!--level) break; if (!--level)
break;
} else if (*p->p == '\\') { } else if (*p->p == '\\') {
p->p++; p->p++;
p->len--; p->len--;
} else if (*p->p == '{') { } else if (*p->p == '{') {
blevel++; blevel++;
} else if (*p->p == '}') { } else if (*p->p == '}') {
if (blevel != 0) blevel--; if (blevel != 0)
blevel--;
} }
p->p++; p->p++;
p->len--; p->len--;
@ -270,11 +272,13 @@ int picolGetToken(struct picolParser *p) {
case ' ': case ' ':
case '\t': case '\t':
case '\r': case '\r':
if (p->insidequote) return picolParseString(p); if (p->insidequote)
return picolParseString(p);
return picolParseSep(p); return picolParseSep(p);
case '\n': case '\n':
case ';': case ';':
if (p->insidequote) return picolParseString(p); if (p->insidequote)
return picolParseString(p);
return picolParseEol(p); return picolParseEol(p);
case '[': case '[':
return picolParseCommand(p); return picolParseCommand(p);
@ -310,7 +314,8 @@ void picolSetResult(struct picolInterp *i, char *s) {
struct picolVar *picolGetVar(struct picolInterp *i, char *name) { struct picolVar *picolGetVar(struct picolInterp *i, char *name) {
struct picolVar *v = i->callframe->vars; struct picolVar *v = i->callframe->vars;
while (v) { while (v) {
if (strcmp(v->name, name) == 0) return v; if (strcmp(v->name, name) == 0)
return v;
v = v->next; v = v->next;
} }
return NULL; return NULL;
@ -334,7 +339,8 @@ int picolSetVar(struct picolInterp *i, char *name, char *val) {
struct picolCmd *picolGetCommand(struct picolInterp *i, char *name) { struct picolCmd *picolGetCommand(struct picolInterp *i, char *name) {
struct picolCmd *c = i->commands; struct picolCmd *c = i->commands;
while (c) { while (c) {
if (strcmp(c->name, name) == 0) return c; if (strcmp(c->name, name) == 0)
return c;
c = c->next; c = c->next;
} }
return NULL; return NULL;
@ -372,9 +378,11 @@ int picolEval(struct picolInterp *i, char *t) {
int tlen; int tlen;
int prevtype = p.type; int prevtype = p.type;
picolGetToken(&p); picolGetToken(&p);
if (p.type == PT_EOF) break; if (p.type == PT_EOF)
break;
tlen = p.end - p.start + 1; tlen = p.end - p.start + 1;
if (tlen < 0) tlen = 0; if (tlen < 0)
tlen = 0;
t = malloc(tlen + 1); t = malloc(tlen + 1);
memcpy(t, p.start, tlen); memcpy(t, p.start, tlen);
t[tlen] = '\0'; t[tlen] = '\0';
@ -392,7 +400,8 @@ int picolEval(struct picolInterp *i, char *t) {
} else if (p.type == PT_CMD) { } else if (p.type == PT_CMD) {
retcode = picolEval(i, t); retcode = picolEval(i, t);
free(t); free(t);
if (retcode != PICOL_OK) goto err; if (retcode != PICOL_OK)
goto err;
t = strdup(i->result); t = strdup(i->result);
} else if (p.type == PT_ESC) { } else if (p.type == PT_ESC) {
/* XXX: escape handling missing! */ /* XXX: escape handling missing! */
@ -414,10 +423,12 @@ int picolEval(struct picolInterp *i, char *t) {
goto err; goto err;
} }
retcode = c->func(i, argc, argv, c->privdata); retcode = c->func(i, argc, argv, c->privdata);
if (retcode != PICOL_OK) goto err; if (retcode != PICOL_OK)
goto err;
} }
/* Prepare for the next command */ /* Prepare for the next command */
for (j = 0; j < argc; j++) free(argv[j]); for (j = 0; j < argc; j++)
free(argv[j]);
free(argv); free(argv);
argv = NULL; argv = NULL;
argc = 0; argc = 0;
@ -438,7 +449,8 @@ int picolEval(struct picolInterp *i, char *t) {
prevtype = p.type; prevtype = p.type;
} }
err: err:
for (j = 0; j < argc; j++) free(argv[j]); for (j = 0; j < argc; j++)
free(argv[j]);
free(argv); free(argv);
return retcode; return retcode;
} }
@ -454,7 +466,8 @@ int picolArityErr(struct picolInterp *i, char *name) {
int picolCommandMath(struct picolInterp *i, int argc, char **argv, void *pd) { int picolCommandMath(struct picolInterp *i, int argc, char **argv, void *pd) {
char buf[64]; char buf[64];
int a, b, c; int a, b, c;
if (argc != 3) return picolArityErr(i, argv[0]); if (argc != 3)
return picolArityErr(i, argv[0]);
a = atoi(argv[1]); a = atoi(argv[1]);
b = atoi(argv[2]); b = atoi(argv[2]);
if (argv[0][0] == '+') if (argv[0][0] == '+')
@ -485,22 +498,26 @@ int picolCommandMath(struct picolInterp *i, int argc, char **argv, void *pd) {
} }
int picolCommandSet(struct picolInterp *i, int argc, char **argv, void *pd) { int picolCommandSet(struct picolInterp *i, int argc, char **argv, void *pd) {
if (argc != 3) return picolArityErr(i, argv[0]); if (argc != 3)
return picolArityErr(i, argv[0]);
picolSetVar(i, argv[1], argv[2]); picolSetVar(i, argv[1], argv[2]);
picolSetResult(i, argv[2]); picolSetResult(i, argv[2]);
return PICOL_OK; return PICOL_OK;
} }
int picolCommandPuts(struct picolInterp *i, int argc, char **argv, void *pd) { int picolCommandPuts(struct picolInterp *i, int argc, char **argv, void *pd) {
if (argc != 2) return picolArityErr(i, argv[0]); if (argc != 2)
return picolArityErr(i, argv[0]);
printf("%s\n", argv[1]); printf("%s\n", argv[1]);
return PICOL_OK; return PICOL_OK;
} }
int picolCommandIf(struct picolInterp *i, int argc, char **argv, void *pd) { int picolCommandIf(struct picolInterp *i, int argc, char **argv, void *pd) {
int retcode; int retcode;
if (argc != 3 && argc != 5) return picolArityErr(i, argv[0]); if (argc != 3 && argc != 5)
if ((retcode = picolEval(i, argv[1])) != PICOL_OK) return retcode; return picolArityErr(i, argv[0]);
if ((retcode = picolEval(i, argv[1])) != PICOL_OK)
return retcode;
if (atoi(i->result)) if (atoi(i->result))
return picolEval(i, argv[2]); return picolEval(i, argv[2]);
else if (argc == 5) else if (argc == 5)
@ -509,10 +526,12 @@ int picolCommandIf(struct picolInterp *i, int argc, char **argv, void *pd) {
} }
int picolCommandWhile(struct picolInterp *i, int argc, char **argv, void *pd) { int picolCommandWhile(struct picolInterp *i, int argc, char **argv, void *pd) {
if (argc != 3) return picolArityErr(i, argv[0]); if (argc != 3)
return picolArityErr(i, argv[0]);
while (1) { while (1) {
int retcode = picolEval(i, argv[1]); int retcode = picolEval(i, argv[1]);
if (retcode != PICOL_OK) return retcode; if (retcode != PICOL_OK)
return retcode;
if (atoi(i->result)) { if (atoi(i->result)) {
if ((retcode = picolEval(i, argv[2])) == PICOL_CONTINUE) if ((retcode = picolEval(i, argv[2])) == PICOL_CONTINUE)
continue; continue;
@ -530,7 +549,8 @@ int picolCommandWhile(struct picolInterp *i, int argc, char **argv, void *pd) {
int picolCommandRetCodes(struct picolInterp *i, int argc, char **argv, int picolCommandRetCodes(struct picolInterp *i, int argc, char **argv,
void *pd) { void *pd) {
if (argc != 1) return picolArityErr(i, argv[0]); if (argc != 1)
return picolArityErr(i, argv[0]);
if (strcmp(argv[0], "break") == 0) if (strcmp(argv[0], "break") == 0)
return PICOL_BREAK; return PICOL_BREAK;
else if (strcmp(argv[0], "continue") == 0) else if (strcmp(argv[0], "continue") == 0)
@ -564,25 +584,31 @@ int picolCommandCallProc(struct picolInterp *i, int argc, char **argv,
tofree = p; tofree = p;
while (1) { while (1) {
char *start = p; char *start = p;
while (*p != ' ' && *p != '\0') p++; while (*p != ' ' && *p != '\0')
p++;
if (*p != '\0' && p == start) { if (*p != '\0' && p == start) {
p++; p++;
continue; continue;
} }
if (p == start) break; if (p == start)
break;
if (*p == '\0') if (*p == '\0')
done = 1; done = 1;
else else
*p = '\0'; *p = '\0';
if (++arity > argc - 1) goto arityerr; if (++arity > argc - 1)
goto arityerr;
picolSetVar(i, start, argv[arity]); picolSetVar(i, start, argv[arity]);
p++; p++;
if (done) break; if (done)
break;
} }
free(tofree); free(tofree);
if (arity != argc - 1) goto arityerr; if (arity != argc - 1)
goto arityerr;
errcode = picolEval(i, body); errcode = picolEval(i, body);
if (errcode == PICOL_RETURN) errcode = PICOL_OK; if (errcode == PICOL_RETURN)
errcode = PICOL_OK;
picolDropCallFrame(i); /* remove the called proc callframe */ picolDropCallFrame(i); /* remove the called proc callframe */
return errcode; return errcode;
arityerr: arityerr:
@ -594,14 +620,16 @@ arityerr:
int picolCommandProc(struct picolInterp *i, int argc, char **argv, void *pd) { int picolCommandProc(struct picolInterp *i, int argc, char **argv, void *pd) {
char **procdata = malloc(sizeof(char *) * 2); char **procdata = malloc(sizeof(char *) * 2);
if (argc != 4) return picolArityErr(i, argv[0]); if (argc != 4)
return picolArityErr(i, argv[0]);
procdata[0] = strdup(argv[2]); /* arguments list */ procdata[0] = strdup(argv[2]); /* arguments list */
procdata[1] = strdup(argv[3]); /* procedure body */ procdata[1] = strdup(argv[3]); /* procedure body */
return picolRegisterCommand(i, argv[1], picolCommandCallProc, procdata); return picolRegisterCommand(i, argv[1], picolCommandCallProc, procdata);
} }
int picolCommandReturn(struct picolInterp *i, int argc, char **argv, void *pd) { int picolCommandReturn(struct picolInterp *i, int argc, char **argv, void *pd) {
if (argc != 1 && argc != 2) return picolArityErr(i, argv[0]); if (argc != 1 && argc != 2)
return picolArityErr(i, argv[0]);
picolSetResult(i, (argc == 2) ? argv[1] : ""); picolSetResult(i, (argc == 2) ? argv[1] : "");
return PICOL_RETURN; return PICOL_RETURN;
} }
@ -631,9 +659,11 @@ int main(int argc, char **argv) {
int retcode; int retcode;
printf("picol> "); printf("picol> ");
fflush(stdout); fflush(stdout);
if (fgets(clibuf, 1024, stdin) == NULL) return 0; if (fgets(clibuf, 1024, stdin) == NULL)
return 0;
retcode = picolEval(&interp, clibuf); retcode = picolEval(&interp, clibuf);
if (interp.result[0] != '\0') printf("[%d] %s\n", retcode, interp.result); if (interp.result[0] != '\0')
printf("[%d] %s\n", retcode, interp.result);
} }
} else if (argc == 2) { } else if (argc == 2) {
char buf[1024 * 16]; char buf[1024 * 16];
@ -644,7 +674,8 @@ int main(int argc, char **argv) {
} }
buf[fread(buf, 1, 1024 * 16, fp)] = '\0'; buf[fread(buf, 1, 1024 * 16, fp)] = '\0';
fclose(fp); fclose(fp);
if (picolEval(&interp, buf) != PICOL_OK) printf("%s\n", interp.result); if (picolEval(&interp, buf) != PICOL_OK)
printf("%s\n", interp.result);
} }
return 0; return 0;
} }

View file

@ -23,7 +23,8 @@
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
const char *prog = argv[0]; const char *prog = argv[0];
if (!prog) prog = "rusage"; if (!prog)
prog = "rusage";
if (argc < 2) { if (argc < 2) {
tinyprint(2, prog, ": missing command\n", NULL); tinyprint(2, prog, ": missing command\n", NULL);

View file

@ -50,8 +50,10 @@ static char *Ithoa(char p[27], unsigned long x) {
} while (x); } while (x);
for (;;) { for (;;) {
*p++ = m[--i]; *p++ = m[--i];
if (!i) break; if (!i)
if (!(i % 3)) *p++ = ','; break;
if (!(i % 3))
*p++ = ',';
} }
*p = '\0'; *p = '\0';
return p; return p;

View file

@ -36,8 +36,10 @@ void Append(intptr_t i, char *s) {
int Compare(const void *a, const void *b) { int Compare(const void *a, const void *b) {
struct Thing *x = (struct Thing *)a; struct Thing *x = (struct Thing *)a;
struct Thing *y = (struct Thing *)b; struct Thing *y = (struct Thing *)b;
if (x->i < y->i) return +1; if (x->i < y->i)
if (x->i > y->i) return -1; return +1;
if (x->i > y->i)
return -1;
return 0; return 0;
} }
@ -46,19 +48,22 @@ int main(int argc, char *argv[]) {
Append((uintptr_t)__oldstack, "__oldstack"); Append((uintptr_t)__oldstack, "__oldstack");
for (int i = 0;; ++i) { for (int i = 0;; ++i) {
Append((uintptr_t)&argv[i], xasprintf("&argv[%d] = %`'s", i, argv[i])); Append((uintptr_t)&argv[i], xasprintf("&argv[%d] = %`'s", i, argv[i]));
if (!argv[i]) break; if (!argv[i])
break;
Append((uintptr_t)argv[i], xasprintf("argv[%d] = %`'s", i, argv[i])); Append((uintptr_t)argv[i], xasprintf("argv[%d] = %`'s", i, argv[i]));
} }
for (int i = 0;; ++i) { for (int i = 0;; ++i) {
Append((uintptr_t)&environ[i], Append((uintptr_t)&environ[i],
xasprintf("&environ[%d] = %`'s", i, environ[i])); xasprintf("&environ[%d] = %`'s", i, environ[i]));
if (!environ[i]) break; if (!environ[i])
break;
Append((uintptr_t)environ[i], Append((uintptr_t)environ[i],
xasprintf("environ[%d] = %`'s", i, environ[i])); xasprintf("environ[%d] = %`'s", i, environ[i]));
} }
for (int i = 0;; i += 2) { for (int i = 0;; i += 2) {
Append((uintptr_t)&__auxv[i], xasprintf("&auxv[%d] = %ld", i, __auxv[i])); Append((uintptr_t)&__auxv[i], xasprintf("&auxv[%d] = %ld", i, __auxv[i]));
if (!__auxv[i]) break; if (!__auxv[i])
break;
Append((uintptr_t)&__auxv[i + 1], Append((uintptr_t)&__auxv[i + 1],
xasprintf("&auxv[%d] = %#lx", i + 1, __auxv[i + 1])); xasprintf("&auxv[%d] = %#lx", i + 1, __auxv[i + 1]));
} }

View file

@ -198,7 +198,8 @@ int main(int argc, char *argv[]) {
dprintf(outfd, "%`'.*s (got %d) ", n, code, n); dprintf(outfd, "%`'.*s (got %d) ", n, code, n);
if (iscntrl(code[0]) && !code[1]) { if (iscntrl(code[0]) && !code[1]) {
dprintf(outfd, "is CTRL-%c a.k.a. ^%c\r\n", CTRL(code[0]), CTRL(code[0])); dprintf(outfd, "is CTRL-%c a.k.a. ^%c\r\n", CTRL(code[0]), CTRL(code[0]));
if (code[0] == CTRL('C') || code[0] == CTRL('D')) break; if (code[0] == CTRL('C') || code[0] == CTRL('D'))
break;
} else if (startswith(code, "\e[") && endswith(code, "R")) { } else if (startswith(code, "\e[") && endswith(code, "R")) {
yn = 1, xn = 1; yn = 1, xn = 1;
sscanf(code, "\e[%d;%dR", &yn, &xn); sscanf(code, "\e[%d;%dR", &yn, &xn);

View file

@ -13,7 +13,8 @@
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
struct utsname names; struct utsname names;
if (uname(&names)) return 1; if (uname(&names))
return 1;
printf("%-10s %`'s\n", "sysname", names.sysname); printf("%-10s %`'s\n", "sysname", names.sysname);
printf("%-10s %`'s\n", "release", names.release); printf("%-10s %`'s\n", "release", names.release);
printf("%-10s %`'s\n", "version", names.version); printf("%-10s %`'s\n", "version", names.version);

File diff suppressed because it is too large Load diff

View file

@ -44,8 +44,10 @@ static int display_info(const char *fpath, const struct stat *sb, int tflag,
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
int flags = 0; int flags = 0;
const char *dir; const char *dir;
if (argc > 2 && strchr(argv[2], 'd') != NULL) flags |= FTW_DEPTH; if (argc > 2 && strchr(argv[2], 'd') != NULL)
if (argc > 2 && strchr(argv[2], 'p') != NULL) flags |= FTW_PHYS; flags |= FTW_DEPTH;
if (argc > 2 && strchr(argv[2], 'p') != NULL)
flags |= FTW_PHYS;
dir = argc < 2 ? "." : argv[1]; dir = argc < 2 ? "." : argv[1];
if (nftw(dir, display_info, 20, flags) == -1) { if (nftw(dir, display_info, 20, flags) == -1) {
fprintf(stderr, "nftw() failed: %s: %s\n", strerror(errno), dir); fprintf(stderr, "nftw() failed: %s: %s\n", strerror(errno), dir);

View file

@ -96,7 +96,8 @@ int main(int argc, char *argv[]) {
appends(&msg, "\e[1m"); // bold text appends(&msg, "\e[1m"); // bold text
appendf(&msg, "Broadcast message from %s@%s", getpwuid(getuid())->pw_name, appendf(&msg, "Broadcast message from %s@%s", getpwuid(getuid())->pw_name,
GetHost()); GetHost());
if (isatty(0) && (s = ttyname(0))) appendf(&msg, " (%s)", s); if (isatty(0) && (s = ttyname(0)))
appendf(&msg, " (%s)", s);
appendf(&msg, " (%s):\r\n", GetTime()); appendf(&msg, " (%s):\r\n", GetTime());
appends(&msg, "\e[K"); appends(&msg, "\e[K");
@ -104,7 +105,8 @@ int main(int argc, char *argv[]) {
if (optind < argc) { if (optind < argc) {
// use cli arguments as message if they exist // use cli arguments as message if they exist
for (int i = 0; optind + i < argc; ++i) { for (int i = 0; optind + i < argc; ++i) {
if (i) appends(&msg, " "); if (i)
appends(&msg, " ");
for (s = argv[optind + i]; *s; ++s) { for (s = argv[optind + i]; *s; ++s) {
if (*s == '\n') { if (*s == '\n') {
appends(&msg, "\r\n\e[K"); appends(&msg, "\r\n\e[K");
@ -135,8 +137,10 @@ int main(int argc, char *argv[]) {
char pts[32]; char pts[32];
snprintf(pts, sizeof(pts), "/dev/pts/%d", i); snprintf(pts, sizeof(pts), "/dev/pts/%d", i);
if ((fd = open(pts, O_WRONLY | O_NOCTTY)) == -1) { if ((fd = open(pts, O_WRONLY | O_NOCTTY)) == -1) {
if (errno == ENOENT) continue; if (errno == ENOENT)
if (g_verbose) perror(pts); continue;
if (g_verbose)
perror(pts);
} }
write(fd, msg, appendz(msg).i); write(fd, msg, appendz(msg).i);
close(fd); close(fd);

View file

@ -59,7 +59,8 @@ int _ptsname(int fd, char *buf, size_t size) {
t.sn[5] = 0; t.sn[5] = 0;
if (IsLinux()) { if (IsLinux()) {
if (sys_ioctl(fd, TIOCGPTN, &pty)) return -1; if (sys_ioctl(fd, TIOCGPTN, &pty))
return -1;
t.sn[5] = 'p'; t.sn[5] = 'p';
t.sn[6] = 't'; t.sn[6] = 't';
t.sn[7] = 's'; t.sn[7] = 's';

View file

@ -101,7 +101,9 @@ int cfsetispeed(struct termios *t, uint32_t speed) {
* @asyncsignalsafe * @asyncsignalsafe
*/ */
int cfsetspeed(struct termios *t, uint32_t speed) { int cfsetspeed(struct termios *t, uint32_t speed) {
if (cfsetispeed(t, speed) == -1) return -1; if (cfsetispeed(t, speed) == -1)
if (cfsetospeed(t, speed) == -1) return -1; return -1;
if (cfsetospeed(t, speed) == -1)
return -1;
return 0; return 0;
} }

View file

@ -33,7 +33,8 @@ textwindows int sys_chdir_nt_impl(char16_t path[hasatleast PATH_MAX],
char16_t var[4]; char16_t var[4];
if (len && path[len - 1] != u'\\') { if (len && path[len - 1] != u'\\') {
if (len + 2 > PATH_MAX) return enametoolong(); if (len + 2 > PATH_MAX)
return enametoolong();
path[len + 0] = u'\\'; path[len + 0] = u'\\';
path[len + 1] = u'\0'; path[len + 1] = u'\0';
} }
@ -84,7 +85,9 @@ textwindows int sys_chdir_nt_impl(char16_t path[hasatleast PATH_MAX],
textwindows int sys_chdir_nt(const char *path) { textwindows int sys_chdir_nt(const char *path) {
int len; int len;
char16_t path16[PATH_MAX]; char16_t path16[PATH_MAX];
if ((len = __mkntpath(path, path16)) == -1) return -1; if ((len = __mkntpath(path, path16)) == -1)
if (!len) return enoent(); return -1;
if (!len)
return enoent();
return sys_chdir_nt_impl(path16, len); return sys_chdir_nt_impl(path16, len);
} }

View file

@ -24,11 +24,16 @@
textwindows int _check_signal(bool restartable) { textwindows int _check_signal(bool restartable) {
int status; int status;
if (_check_cancel() == -1) return -1; if (_check_cancel() == -1)
if (!_weaken(__sig_check)) return 0; return -1;
if (!(status = _weaken(__sig_check)())) return 0; if (!_weaken(__sig_check))
if (_check_cancel() == -1) return -1; return 0;
if (status == 2 && restartable) return 0; if (!(status = _weaken(__sig_check)()))
return 0;
if (_check_cancel() == -1)
return -1;
if (status == 2 && restartable)
return 0;
return eintr(); return eintr();
} }

View file

@ -61,7 +61,8 @@ static dontinline int __clk_tck_init(void) {
} else { } else {
x = __getauxval(AT_CLKTCK).value; x = __getauxval(AT_CLKTCK).value;
} }
if (x < 1) x = 100; if (x < 1)
x = 100;
clk_tck = x; clk_tck = x;
return x; return x;
} }

View file

@ -44,7 +44,8 @@ int sys_clock_gettime_mono(struct timespec *time) {
#ifdef __x86_64__ #ifdef __x86_64__
// intel architecture guarantees that a mapping exists between rdtsc & // intel architecture guarantees that a mapping exists between rdtsc &
// nanoseconds only if the cpu advertises invariant timestamps support // nanoseconds only if the cpu advertises invariant timestamps support
if (!X86_HAVE(INVTSC)) return -EINVAL; if (!X86_HAVE(INVTSC))
return -EINVAL;
#endif #endif
cosmo_once(&g_mono.once, sys_clock_gettime_mono_init); cosmo_once(&g_mono.once, sys_clock_gettime_mono_init);
cycles = rdtsc() - g_mono.base_tick; cycles = rdtsc() - g_mono.base_tick;

View file

@ -60,14 +60,17 @@ int sys_clock_gettime_xnu(int clock, struct timespec *ts) {
} }
return 0; return 0;
} else if (clock == CLOCK_MONOTONIC) { } else if (clock == CLOCK_MONOTONIC) {
if (!ts) return 0; if (!ts)
return 0;
return sys_clock_gettime_mono(ts); return sys_clock_gettime_mono(ts);
} else if (clock == CLOCK_BOOTTIME) { } else if (clock == CLOCK_BOOTTIME) {
struct timeval x; struct timeval x;
size_t n = sizeof(x); size_t n = sizeof(x);
int mib[] = {CTL_KERN, KERN_BOOTTIME}; int mib[] = {CTL_KERN, KERN_BOOTTIME};
if (sys_sysctl(mib, ARRAYLEN(mib), &x, &n, 0, 0) == -1) return -1; if (sys_sysctl(mib, ARRAYLEN(mib), &x, &n, 0, 0) == -1)
if (ts) *ts = timeval_totimespec(timeval_sub(timeval_real(), x)); return -1;
if (ts)
*ts = timeval_totimespec(timeval_sub(timeval_real(), x));
return 0; return 0;
} else { } else {
return -EINVAL; return -EINVAL;

View file

@ -57,7 +57,8 @@ int cosmo_clock_nanosleep(int clock, int flags, const struct timespec *req,
struct timespec quantum = timespec_fromnanos(1000000000 / CLK_TCK); struct timespec quantum = timespec_fromnanos(1000000000 / CLK_TCK);
clock_gettime(time_clock, &start); clock_gettime(time_clock, &start);
deadline = flags & TIMER_ABSTIME ? *req : timespec_add(start, *req); deadline = flags & TIMER_ABSTIME ? *req : timespec_add(start, *req);
if (timespec_cmp(start, deadline) >= 0) return 0; if (timespec_cmp(start, deadline) >= 0)
return 0;
remain = timespec_sub(deadline, start); remain = timespec_sub(deadline, start);
if (timespec_cmp(remain, quantum) > 0) { if (timespec_cmp(remain, quantum) > 0) {
waitfor = timespec_sub(remain, quantum); waitfor = timespec_sub(remain, quantum);

View file

@ -32,10 +32,13 @@ static textwindows int sys_clock_nanosleep_nt_impl(int clock,
uint32_t msdelay; uint32_t msdelay;
struct timespec now; struct timespec now;
for (;;) { for (;;) {
if (sys_clock_gettime_nt(clock, &now)) return -1; if (sys_clock_gettime_nt(clock, &now))
if (timespec_cmp(now, abs) >= 0) return 0; return -1;
if (timespec_cmp(now, abs) >= 0)
return 0;
msdelay = timespec_tomillis(timespec_sub(abs, now)); msdelay = timespec_tomillis(timespec_sub(abs, now));
if (_park_norestart(msdelay, waitmask)) return -1; if (_park_norestart(msdelay, waitmask))
return -1;
} }
} }
@ -48,7 +51,8 @@ textwindows int sys_clock_nanosleep_nt(int clock, int flags,
if (flags & TIMER_ABSTIME) { if (flags & TIMER_ABSTIME) {
abs = *req; abs = *req;
} else { } else {
if ((rc = sys_clock_gettime_nt(clock, &now))) goto BailOut; if ((rc = sys_clock_gettime_nt(clock, &now)))
goto BailOut;
abs = timespec_add(now, *req); abs = timespec_add(now, *req);
} }
rc = sys_clock_nanosleep_nt_impl(clock, abs, m); rc = sys_clock_nanosleep_nt_impl(clock, abs, m);

View file

@ -46,7 +46,8 @@ int sys_clock_nanosleep_xnu(int clock, int flags, const struct timespec *req,
} else { } else {
int rc; int rc;
struct timespec beg; struct timespec beg;
if (rem) sys_clock_gettime_xnu(CLOCK_REALTIME, &beg); if (rem)
sys_clock_gettime_xnu(CLOCK_REALTIME, &beg);
struct timeval rel = timespec_totimeval(*req); // rounds up struct timeval rel = timespec_totimeval(*req); // rounds up
rc = sys_select(0, 0, 0, 0, &rel); rc = sys_select(0, 0, 0, 0, &rel);
if (rc == -1 && rem && errno == EINTR) { if (rc == -1 && rem && errno == EINTR) {

View file

@ -30,7 +30,8 @@
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
textwindows int sys_close_nt(int fd, int fildes) { textwindows int sys_close_nt(int fd, int fildes) {
if (fd + 0u >= g_fds.n) return ebadf(); if (fd + 0u >= g_fds.n)
return ebadf();
struct Fd *f = g_fds.p + fd; struct Fd *f = g_fds.p + fd;
switch (f->kind) { switch (f->kind) {
case kFdZip: case kFdZip:

View file

@ -97,12 +97,14 @@ int close(int fd) {
BLOCK_SIGNALS; BLOCK_SIGNALS;
__fds_lock(); __fds_lock();
rc = close_impl(fd); rc = close_impl(fd);
if (!__vforked) __releasefd(fd); if (!__vforked)
__releasefd(fd);
__fds_unlock(); __fds_unlock();
ALLOW_SIGNALS; ALLOW_SIGNALS;
} else { } else {
rc = close_impl(fd); rc = close_impl(fd);
if (!__vforked) __releasefd(fd); if (!__vforked)
__releasefd(fd);
} }
STRACE("close(%d) → %d% m", fd, rc); STRACE("close(%d) → %d% m", fd, rc);
return rc; return rc;

View file

@ -37,10 +37,13 @@ ssize_t copyfd(int in, int out, size_t n) {
ssize_t dr, dw; ssize_t dr, dw;
for (i = 0; i < n; i += dr) { for (i = 0; i < n; i += dr) {
dr = read(in, buf, MIN(n - i, sizeof(buf))); dr = read(in, buf, MIN(n - i, sizeof(buf)));
if (dr == -1) return -1; if (dr == -1)
if (!dr) break; return -1;
if (!dr)
break;
dw = write(out, buf, dr); dw = write(out, buf, dr);
if (dw == -1) return -1; if (dw == -1)
return -1;
if (dw != dr) { if (dw != dr) {
// POSIX requires atomic IO up to PIPE_BUF // POSIX requires atomic IO up to PIPE_BUF
// The minimum permissible PIPE_BUF is 512 // The minimum permissible PIPE_BUF is 512

View file

@ -156,9 +156,12 @@ textwindows int GetNtOpenFlags(int flags, int mode, uint32_t *out_perm,
} }
// Not certain yet what benefit these flags offer. // Not certain yet what benefit these flags offer.
if (flags & _O_SEQUENTIAL) attr |= kNtFileFlagSequentialScan; if (flags & _O_SEQUENTIAL)
if (flags & _O_RANDOM) attr |= kNtFileFlagRandomAccess; attr |= kNtFileFlagSequentialScan;
if (flags & _O_DIRECT) attr |= kNtFileFlagNoBuffering; if (flags & _O_RANDOM)
attr |= kNtFileFlagRandomAccess;
if (flags & _O_DIRECT)
attr |= kNtFileFlagNoBuffering;
// TODO(jart): Should we *always* open with write permission if the // TODO(jart): Should we *always* open with write permission if the
// kernel will give it to us? We'd then deny write access // kernel will give it to us? We'd then deny write access
@ -172,9 +175,13 @@ textwindows int GetNtOpenFlags(int flags, int mode, uint32_t *out_perm,
// writing to a file across a network can occasionally return // writing to a file across a network can occasionally return
// kNtErrorAccessDenied." -Quoth MSDN // kNtErrorAccessDenied." -Quoth MSDN
if (out_perm) *out_perm = perm; if (out_perm)
if (out_share) *out_share = share; *out_perm = perm;
if (out_disp) *out_disp = disp; if (out_share)
if (out_attr) *out_attr = attr; *out_share = share;
if (out_disp)
*out_disp = disp;
if (out_attr)
*out_attr = attr;
return 0; return 0;
} }

View file

@ -42,7 +42,8 @@ textwindows char16_t *__create_pipe_name(char16_t *a) {
char16_t *p = a; char16_t *p = a;
const char *q = "\\\\?\\pipe\\cosmo\\"; const char *q = "\\\\?\\pipe\\cosmo\\";
static atomic_uint x; static atomic_uint x;
while (*q) *p++ = *q++; while (*q)
*p++ = *q++;
p = itoa16(p, __pid); p = itoa16(p, __pid);
*p++ = '-'; *p++ = '-';
p = itoa16(p, atomic_fetch_add(&x, 1)); p = itoa16(p, atomic_fetch_add(&x, 1));

View file

@ -66,12 +66,14 @@
int dup2(int oldfd, int newfd) { int dup2(int oldfd, int newfd) {
int rc; int rc;
// helps guarantee stderr log gets duplicated before user closes // helps guarantee stderr log gets duplicated before user closes
if (_weaken(kloghandle)) _weaken(kloghandle)(); if (_weaken(kloghandle))
_weaken(kloghandle)();
#ifdef __aarch64__ #ifdef __aarch64__
if (oldfd == newfd) { if (oldfd == newfd) {
// linux aarch64 defines dup3() but not dup2(), which wasn't such a // linux aarch64 defines dup3() but not dup2(), which wasn't such a
// great decision, since the two syscalls don't behave the same way // great decision, since the two syscalls don't behave the same way
if (!(rc = read(oldfd, 0, 0))) rc = oldfd; if (!(rc = read(oldfd, 0, 0)))
rc = oldfd;
} else } else
#endif #endif
if (!IsWindows()) { if (!IsWindows()) {

View file

@ -65,7 +65,8 @@
int dup3(int oldfd, int newfd, int flags) { int dup3(int oldfd, int newfd, int flags) {
int rc; int rc;
// helps guarantee stderr log gets duplicated before user closes // helps guarantee stderr log gets duplicated before user closes
if (_weaken(kloghandle)) _weaken(kloghandle)(); if (_weaken(kloghandle))
_weaken(kloghandle)();
if (oldfd == newfd || (flags & ~O_CLOEXEC)) { if (oldfd == newfd || (flags & ~O_CLOEXEC)) {
rc = einval(); // NetBSD doesn't do this rc = einval(); // NetBSD doesn't do this
} else if (oldfd < 0 || newfd < 0) { } else if (oldfd < 0 || newfd < 0) {

View file

@ -24,6 +24,7 @@
textwindows int sys_faccessat_nt(int dirfd, const char *path, int mode, textwindows int sys_faccessat_nt(int dirfd, const char *path, int mode,
uint32_t flags) { uint32_t flags) {
char16_t path16[PATH_MAX]; char16_t path16[PATH_MAX];
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1; if (__mkntpathat(dirfd, path, 0, path16) == -1)
return -1;
return __fix_enotdir(ntaccesscheck(path16, mode), path16); return __fix_enotdir(ntaccesscheck(path16, mode), path16);
} }

View file

@ -64,7 +64,8 @@ int faccessat(int dirfd, const char *path, int amode, int flags) {
rc = _weaken(__zipos_access)(&zipname, amode); rc = _weaken(__zipos_access)(&zipname, amode);
} else if (!IsWindows()) { } else if (!IsWindows()) {
e = errno; e = errno;
if (!flags) goto NoFlags; if (!flags)
goto NoFlags;
if ((rc = sys_faccessat2(dirfd, path, amode, flags)) == -1) { if ((rc = sys_faccessat2(dirfd, path, amode, flags)) == -1) {
if (errno == ENOSYS) { if (errno == ENOSYS) {
errno = e; errno = e;

View file

@ -37,8 +37,10 @@ static textwindows int sys_fadvise_nt_impl(int fd, uint64_t offset,
int rc, flags, mode; int rc, flags, mode;
uint32_t perm, share, attr; uint32_t perm, share, attr;
if ((int64_t)len < 0) return einval(); if ((int64_t)len < 0)
if (!__isfdkind(fd, kFdFile)) return ebadf(); return einval();
if (!__isfdkind(fd, kFdFile))
return ebadf();
h1 = g_fds.p[fd].handle; h1 = g_fds.p[fd].handle;
mode = g_fds.p[fd].mode; mode = g_fds.p[fd].mode;
flags = g_fds.p[fd].flags; flags = g_fds.p[fd].flags;

View file

@ -27,7 +27,8 @@ int sys_chdir_nt_impl(char16_t[hasatleast PATH_MAX], uint32_t);
textwindows int sys_fchdir_nt(int dirfd) { textwindows int sys_fchdir_nt(int dirfd) {
char16_t dir[PATH_MAX]; char16_t dir[PATH_MAX];
if (!__isfdkind(dirfd, kFdFile)) return ebadf(); if (!__isfdkind(dirfd, kFdFile))
return ebadf();
return sys_chdir_nt_impl( return sys_chdir_nt_impl(
dir, GetFinalPathNameByHandle(g_fds.p[dirfd].handle, dir, ARRAYLEN(dir), dir, GetFinalPathNameByHandle(g_fds.p[dirfd].handle, dir, ARRAYLEN(dir),
kNtFileNameNormalized | kNtVolumeNameDos)); kNtFileNameNormalized | kNtVolumeNameDos));

View file

@ -29,8 +29,10 @@
textwindows int sys_fchmod_nt(int fd, uint32_t mode) { textwindows int sys_fchmod_nt(int fd, uint32_t mode) {
// validate file descriptor // validate file descriptor
if (fd + 0u >= g_fds.n) return ebadf(); if (fd + 0u >= g_fds.n)
if (g_fds.p[fd].kind == kFdEmpty) return ebadf(); return ebadf();
if (g_fds.p[fd].kind == kFdEmpty)
return ebadf();
// get current information // get current information
struct NtFileBasicInfo fbi; struct NtFileBasicInfo fbi;

View file

@ -26,7 +26,8 @@ textwindows int sys_fchmodat_nt(int dirfd, const char *path, uint32_t mode,
int flags) { int flags) {
uint32_t attr; uint32_t attr;
uint16_t path16[PATH_MAX]; uint16_t path16[PATH_MAX];
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1; if (__mkntpathat(dirfd, path, 0, path16) == -1)
return -1;
if ((attr = GetFileAttributes(path16)) != -1u) { if ((attr = GetFileAttributes(path16)) != -1u) {
if (mode & 0222) { if (mode & 0222) {
attr &= ~kNtFileAttributeReadonly; attr &= ~kNtFileAttributeReadonly;

View file

@ -129,7 +129,8 @@ textwindows void sys_fcntl_nt_lock_cleanup(int fd) {
static textwindows int64_t GetfileSize(int64_t handle) { static textwindows int64_t GetfileSize(int64_t handle) {
struct NtByHandleFileInformation wst; struct NtByHandleFileInformation wst;
if (!GetFileInformationByHandle(handle, &wst)) return __winerr(); if (!GetFileInformationByHandle(handle, &wst))
return __winerr();
return (wst.nFileSizeHigh + 0ull) << 32 | wst.nFileSizeLow; return (wst.nFileSizeHigh + 0ull) << 32 | wst.nFileSizeLow;
} }
@ -156,7 +157,8 @@ static textwindows int sys_fcntl_nt_lock(struct Fd *f, int fd, int cmd,
break; break;
case SEEK_END: { case SEEK_END: {
int64_t size; int64_t size;
if ((size = GetfileSize(f->handle)) == -1) return -1; if ((size = GetfileSize(f->handle)) == -1)
return -1;
off = size - off; off = size - off;
break; break;
} }
@ -254,7 +256,8 @@ static textwindows int sys_fcntl_nt_lock(struct Fd *f, int fd, int cmd,
} }
if (l->l_type == F_UNLCK) { if (l->l_type == F_UNLCK) {
if (cmd == F_GETLK) return einval(); if (cmd == F_GETLK)
return einval();
// allow a big range to unlock many small ranges // allow a big range to unlock many small ranges
for (flp = &g_locks.list, fl = *flp; fl;) { for (flp = &g_locks.list, fl = *flp; fl;) {
@ -318,7 +321,8 @@ static textwindows int sys_fcntl_nt_lock(struct Fd *f, int fd, int cmd,
} }
static textwindows int sys_fcntl_nt_dupfd(int fd, int cmd, int start) { static textwindows int sys_fcntl_nt_dupfd(int fd, int cmd, int start) {
if (start < 0) return einval(); if (start < 0)
return einval();
return sys_dup_nt(fd, -1, (cmd == F_DUPFD_CLOEXEC ? _O_CLOEXEC : 0), start); return sys_dup_nt(fd, -1, (cmd == F_DUPFD_CLOEXEC ? _O_CLOEXEC : 0), start);
} }

View file

@ -27,17 +27,23 @@
textwindows int sys_fdatasync_nt(int fd, bool fake) { textwindows int sys_fdatasync_nt(int fd, bool fake) {
struct NtByHandleFileInformation wst; struct NtByHandleFileInformation wst;
if (!__isfdopen(fd)) return ebadf(); if (!__isfdopen(fd))
if (!__isfdkind(fd, kFdFile)) return einval(); return ebadf();
if (GetFileType(g_fds.p[fd].handle) != kNtFileTypeDisk) return einval(); if (!__isfdkind(fd, kFdFile))
if (!GetFileInformationByHandle(g_fds.p[fd].handle, &wst)) return __winerr(); return einval();
if (GetFileType(g_fds.p[fd].handle) != kNtFileTypeDisk)
return einval();
if (!GetFileInformationByHandle(g_fds.p[fd].handle, &wst))
return __winerr();
if (wst.dwFileAttributes & kNtFileAttributeDirectory) { if (wst.dwFileAttributes & kNtFileAttributeDirectory) {
// Flushing a directory handle is possible, but it needs // Flushing a directory handle is possible, but it needs
// kNtGenericWrite access, and MSDN doesn't document it. // kNtGenericWrite access, and MSDN doesn't document it.
return 0; return 0;
} }
if (fake) return 0; if (fake)
if (_check_signal(false) == -1) return -1; return 0;
if (_check_signal(false) == -1)
return -1;
return FlushFileBuffers(g_fds.p[fd].handle) ? 0 : __winerr(); return FlushFileBuffers(g_fds.p[fd].handle) ? 0 : __winerr();
} }

View file

@ -34,7 +34,8 @@
textwindows int sys_flock_nt(int fd, int op) { textwindows int sys_flock_nt(int fd, int op) {
int64_t h; int64_t h;
struct NtByHandleFileInformation info; struct NtByHandleFileInformation info;
if (!__isfdkind(fd, kFdFile)) return ebadf(); if (!__isfdkind(fd, kFdFile))
return ebadf();
h = g_fds.p[fd].handle; h = g_fds.p[fd].handle;
struct NtOverlapped ov = {.hEvent = h}; struct NtOverlapped ov = {.hEvent = h};

View file

@ -23,7 +23,8 @@
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
int sys_fstat_metal(int fd, struct stat *st) { int sys_fstat_metal(int fd, struct stat *st) {
if (fd < 0) return einval(); if (fd < 0)
return einval();
if (fd < g_fds.n && g_fds.p[fd].kind == kFdSerial) { if (fd < g_fds.n && g_fds.p[fd].kind == kFdSerial) {
bzero(st, sizeof(*st)); bzero(st, sizeof(*st));
st->st_dev = g_fds.p[fd].handle; st->st_dev = g_fds.p[fd].handle;

View file

@ -97,7 +97,8 @@ textwindows int sys_fstat_nt_special(int kind, struct stat *st) {
} }
textwindows int sys_fstat_nt(int fd, struct stat *st) { textwindows int sys_fstat_nt(int fd, struct stat *st) {
if (fd + 0u >= g_fds.n) return ebadf(); if (fd + 0u >= g_fds.n)
return ebadf();
switch (g_fds.p[fd].kind) { switch (g_fds.p[fd].kind) {
case kFdEmpty: case kFdEmpty:
return ebadf(); return ebadf();
@ -174,7 +175,8 @@ textwindows int sys_fstat_nt_handle(int64_t handle, const char16_t *path,
if (S_ISLNK(st.st_mode)) { if (S_ISLNK(st.st_mode)) {
if (!st.st_size) { if (!st.st_size) {
long size = GetSizeOfReparsePoint(handle); long size = GetSizeOfReparsePoint(handle);
if (size == -1) return -1; if (size == -1)
return -1;
st.st_size = size; st.st_size = size;
} }
} else { } else {

View file

@ -36,7 +36,8 @@
static int Atoi(const char *str) { static int Atoi(const char *str) {
int c; int c;
unsigned x = 0; unsigned x = 0;
if (!*str) return -1; if (!*str)
return -1;
while ((c = *str++)) { while ((c = *str++)) {
if ('0' <= c && c <= '9') { if ('0' <= c && c <= '9') {
x *= 10; x *= 10;

View file

@ -35,7 +35,8 @@
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
static inline const char *__strace_fstatat_flags(char buf[12], int flags) { static inline const char *__strace_fstatat_flags(char buf[12], int flags) {
if (flags == AT_SYMLINK_NOFOLLOW) return "AT_SYMLINK_NOFOLLOW"; if (flags == AT_SYMLINK_NOFOLLOW)
return "AT_SYMLINK_NOFOLLOW";
FormatInt32(buf, flags); FormatInt32(buf, flags);
return buf; return buf;
} }

View file

@ -54,7 +54,8 @@ textwindows int sys_fstatfs_nt(int64_t handle, struct statfs *f) {
st = NtQueryVolumeInformationFile(handle, &io, &fs, sizeof(fs), st = NtQueryVolumeInformationFile(handle, &io, &fs, sizeof(fs),
kNtFileFsFullSizeInformation); kNtFileFsFullSizeInformation);
if (!NtSuccess(st)) { if (!NtSuccess(st)) {
if (st == kNtStatusDllNotFound) return enosys(); if (st == kNtStatusDllNotFound)
return enosys();
return eio(); return eio();
} }
for (h = j = i = 0; FileSystemNameBuffer[i]; i++) { for (h = j = i = 0; FileSystemNameBuffer[i]; i++) {

View file

@ -26,6 +26,7 @@
*/ */
int ftok(const char *path, int id) { int ftok(const char *path, int id) {
struct stat st; struct stat st;
if (stat(path, &st) == -1) return -1; if (stat(path, &st) == -1)
return -1;
return (uint32_t)id << 24 | (st.st_dev & 0xff) << 16 | (st.st_ino & 0xffff); return (uint32_t)id << 24 | (st.st_dev & 0xff) << 16 | (st.st_ino & 0xffff);
} }

View file

@ -64,7 +64,8 @@ int getcpu(unsigned *out_opt_cpu, unsigned *out_opt_node) {
} }
} else { } else {
int rc = sys_getcpu(&cpu, &node, 0); int rc = sys_getcpu(&cpu, &node, 0);
if (rc == -1) return -1; if (rc == -1)
return -1;
} }
if (out_opt_cpu) { if (out_opt_cpu) {
*out_opt_cpu = cpu; *out_opt_cpu = cpu;

View file

@ -82,14 +82,17 @@ static dontinline textwindows int sys_getcwd_nt(char *buf, size_t size) {
// get current directory from the system // get current directory from the system
char16_t p16[PATH_MAX]; char16_t p16[PATH_MAX];
uint32_t n = GetCurrentDirectory(PATH_MAX, p16); uint32_t n = GetCurrentDirectory(PATH_MAX, p16);
if (!n) return eacces(); // system call failed if (!n)
if (n >= PATH_MAX) return erange(); // not enough room?!? return eacces(); // system call failed
if (n >= PATH_MAX)
return erange(); // not enough room?!?
// convert utf-16 to utf-8 // convert utf-16 to utf-8
// we can't modify `buf` until we're certain of success // we can't modify `buf` until we're certain of success
char p8[PATH_MAX], *p = p8; char p8[PATH_MAX], *p = p8;
n = tprecode16to8(p, PATH_MAX, p16).ax; n = tprecode16to8(p, PATH_MAX, p16).ax;
if (n >= PATH_MAX) return erange(); // utf-8 explosion if (n >= PATH_MAX)
return erange(); // utf-8 explosion
// turn \\?\c:\... into c:\... // turn \\?\c:\... into c:\...
if (p[0] == '\\' && // if (p[0] == '\\' && //

View file

@ -43,7 +43,8 @@ struct loadavg {
int getloadavg(double *a, int n) { int getloadavg(double *a, int n) {
// cat /proc/loadavg // cat /proc/loadavg
int i, rc; int i, rc;
if (n > 3) n = 3; if (n > 3)
n = 3;
if (!n) { if (!n) {
rc = 0; rc = 0;
} else if (n < 0) { } else if (n < 0) {

View file

@ -64,7 +64,8 @@ static ssize_t GetRandomCpu(char *p, size_t n, int f, bool impl(uint64_t *)) {
for (i = 0; i < n; i += j) { for (i = 0; i < n; i += j) {
TryAgain: TryAgain:
if (!impl(&x)) { if (!impl(&x)) {
if (f || i >= 256) break; if (f || i >= 256)
break;
goto TryAgain; goto TryAgain;
} }
for (j = 0; j < 8 && i + j < n; ++j) { for (j = 0; j < 8 && i + j < n; ++j) {

View file

@ -60,7 +60,8 @@ static bool have_getrandom;
static void GetRandomEntropy(char *p, size_t n) { static void GetRandomEntropy(char *p, size_t n) {
unassert(n <= 256); unassert(n <= 256);
if (sys_getentropy(p, n)) notpossible; if (sys_getentropy(p, n))
notpossible;
} }
static void GetRandomArnd(char *p, size_t n) { static void GetRandomArnd(char *p, size_t n) {
@ -69,8 +70,10 @@ static void GetRandomArnd(char *p, size_t n) {
cmd[0] = 1; // CTL_KERN cmd[0] = 1; // CTL_KERN
cmd[1] = IsFreebsd() ? 37 : 81; // KERN_ARND cmd[1] = IsFreebsd() ? 37 : 81; // KERN_ARND
unassert((m = n) <= 256); unassert((m = n) <= 256);
if (sys_sysctl(cmd, 2, p, &n, 0, 0) == -1) notpossible; if (sys_sysctl(cmd, 2, p, &n, 0, 0) == -1)
if (m != n) notpossible; notpossible;
if (m != n)
notpossible;
} }
static ssize_t GetRandomBsd(char *p, size_t n, void impl(char *, size_t)) { static ssize_t GetRandomBsd(char *p, size_t n, void impl(char *, size_t)) {
@ -193,7 +196,8 @@ ssize_t getrandom(void *p, size_t n, unsigned f) {
__attribute__((__constructor__(30))) static textstartup void getrandom_init( __attribute__((__constructor__(30))) static textstartup void getrandom_init(
void) { void) {
int e, rc; int e, rc;
if (IsWindows() || IsMetal()) return; if (IsWindows() || IsMetal())
return;
BLOCK_CANCELATION; BLOCK_CANCELATION;
e = errno; e = errno;
if (!(rc = sys_getrandom(0, 0, 0))) { if (!(rc = sys_getrandom(0, 0, 0))) {

View file

@ -34,15 +34,20 @@ int getresgid(uint32_t *real, uint32_t *effective, uint32_t *saved) {
int rc, gid; int rc, gid;
if (IsWindows()) { if (IsWindows()) {
gid = getgid(); gid = getgid();
if (real) *real = gid; if (real)
if (effective) *effective = gid; *real = gid;
if (saved) *saved = gid; if (effective)
*effective = gid;
if (saved)
*saved = gid;
rc = 0; rc = 0;
} else if (saved) { } else if (saved) {
rc = sys_getresgid(real, effective, saved); rc = sys_getresgid(real, effective, saved);
} else { } else {
if (real) *real = sys_getgid(); if (real)
if (effective) *effective = sys_getegid(); *real = sys_getgid();
if (effective)
*effective = sys_getegid();
rc = 0; rc = 0;
} }
STRACE("getresgid([%d], [%d], [%d]) → %d% m", real ? *real : 0, STRACE("getresgid([%d], [%d], [%d]) → %d% m", real ? *real : 0,

View file

@ -34,15 +34,20 @@ int getresuid(uint32_t *real, uint32_t *effective, uint32_t *saved) {
int rc, uid; int rc, uid;
if (IsWindows()) { if (IsWindows()) {
uid = getuid(); uid = getuid();
if (real) *real = uid; if (real)
if (effective) *effective = uid; *real = uid;
if (saved) *saved = uid; if (effective)
*effective = uid;
if (saved)
*saved = uid;
rc = 0; rc = 0;
} else if (saved) { } else if (saved) {
rc = sys_getresuid(real, effective, saved); rc = sys_getresuid(real, effective, saved);
} else { } else {
if (real) *real = sys_getuid(); if (real)
if (effective) *effective = sys_geteuid(); *real = sys_getuid();
if (effective)
*effective = sys_geteuid();
rc = 0; rc = 0;
} }
STRACE("getresuid([%d], [%d], [%d]) → %d% m", real ? *real : 0, STRACE("getresuid([%d], [%d], [%d]) → %d% m", real ? *real : 0,

View file

@ -25,7 +25,8 @@ textwindows char *GetSystemDirectoryPath(char *buf, const char *path,
uint32_t syslen = GetSystemDirectoryA(buf, size); uint32_t syslen = GetSystemDirectoryA(buf, size);
size_t pathlen = strlen(path); size_t pathlen = strlen(path);
if (syslen && syslen + pathlen + 1 < size) { if (syslen && syslen + pathlen + 1 < size) {
if (buf[syslen] == '\\') --syslen; if (buf[syslen] == '\\')
--syslen;
memcpy(buf + syslen, path, pathlen + 1); memcpy(buf + syslen, path, pathlen + 1);
return buf; return buf;
} else { } else {

View file

@ -29,7 +29,8 @@ textwindows uint32_t sys_getuid_nt(void) {
if (!(tmp = atomic_load_explicit(&uid, memory_order_acquire))) { if (!(tmp = atomic_load_explicit(&uid, memory_order_acquire))) {
GetUserName(&buf, &size); GetUserName(&buf, &size);
tmp = __fnv(buf, size >> 1) & 32767; tmp = __fnv(buf, size >> 1) & 32767;
if (!tmp) ++tmp; if (!tmp)
++tmp;
atomic_store_explicit(&uid, tmp, memory_order_release); atomic_store_explicit(&uid, tmp, memory_order_release);
} }
return tmp; return tmp;

View file

@ -244,11 +244,16 @@ static textwindows struct HostAdapterInfoNode *appendHostInfo(
* IFF_PROMISC ** NOT SUPPORTED, unknown how to retrieve it * IFF_PROMISC ** NOT SUPPORTED, unknown how to retrieve it
*/ */
flags = 0; flags = 0;
if (aa->OperStatus == kNtIfOperStatusUp) flags |= IFF_UP | IFF_RUNNING; if (aa->OperStatus == kNtIfOperStatusUp)
if (aa->IfType == kNtIfTypePpp) flags |= IFF_POINTOPOINT; flags |= IFF_UP | IFF_RUNNING;
if (!(aa->Flags & kNtIpAdapterNoMulticast)) flags |= IFF_MULTICAST; if (aa->IfType == kNtIfTypePpp)
if (aa->IfType == kNtIfTypeSoftwareLoopback) flags |= IFF_LOOPBACK; flags |= IFF_POINTOPOINT;
if (aa->FirstPrefix) flags |= IFF_BROADCAST; if (!(aa->Flags & kNtIpAdapterNoMulticast))
flags |= IFF_MULTICAST;
if (aa->IfType == kNtIfTypeSoftwareLoopback)
flags |= IFF_LOOPBACK;
if (aa->FirstPrefix)
flags |= IFF_BROADCAST;
node->flags = flags; node->flags = flags;
} else { } else {
/* Copy from previous node */ /* Copy from previous node */
@ -344,13 +349,16 @@ static textwindows int createHostInfo(
baseName[IFNAMSIZ - 2] = '\0'; baseName[IFNAMSIZ - 2] = '\0';
/* Replace any space with a '_' */ /* Replace any space with a '_' */
for (i = 0; i < IFNAMSIZ - 2; ++i) { for (i = 0; i < IFNAMSIZ - 2; ++i) {
if (baseName[i] == ' ') baseName[i] = '_'; if (baseName[i] == ' ')
if (!baseName[i]) break; baseName[i] = '_';
if (!baseName[i])
break;
} }
for (count = 0, ua = aa->FirstUnicastAddress, ap = aa->FirstPrefix; for (count = 0, ua = aa->FirstUnicastAddress, ap = aa->FirstPrefix;
(ua != NULL) && (count < MAX_UNICAST_ADDR); ++count) { (ua != NULL) && (count < MAX_UNICAST_ADDR); ++count) {
node = appendHostInfo(node, baseName, aa, &ua, &ap, count); node = appendHostInfo(node, baseName, aa, &ua, &ap, count);
if (!node) goto err; if (!node)
goto err;
if (!__hostInfo) { if (!__hostInfo) {
__hostInfo = node; __hostInfo = node;
if (_cmpxchg(&once, false, true)) { if (_cmpxchg(&once, false, true)) {
@ -444,7 +452,8 @@ static textwindows int ioctl_siocgifconf_nt(int fd, struct ifconf *ifc) {
static textwindows int ioctl_siocgifaddr_nt(int fd, struct ifreq *ifr) { static textwindows int ioctl_siocgifaddr_nt(int fd, struct ifreq *ifr) {
struct HostAdapterInfoNode *node; struct HostAdapterInfoNode *node;
node = findAdapterByName(ifr->ifr_name); node = findAdapterByName(ifr->ifr_name);
if (!node) return ebadf(); if (!node)
return ebadf();
memcpy(&ifr->ifr_addr, &node->unicast, sizeof(struct sockaddr)); memcpy(&ifr->ifr_addr, &node->unicast, sizeof(struct sockaddr));
return 0; return 0;
} }
@ -453,7 +462,8 @@ static textwindows int ioctl_siocgifaddr_nt(int fd, struct ifreq *ifr) {
static textwindows int ioctl_siocgifflags_nt(int fd, struct ifreq *ifr) { static textwindows int ioctl_siocgifflags_nt(int fd, struct ifreq *ifr) {
struct HostAdapterInfoNode *node; struct HostAdapterInfoNode *node;
node = findAdapterByName(ifr->ifr_name); node = findAdapterByName(ifr->ifr_name);
if (!node) return ebadf(); if (!node)
return ebadf();
ifr->ifr_flags = node->flags; ifr->ifr_flags = node->flags;
return 0; return 0;
} }
@ -462,7 +472,8 @@ static textwindows int ioctl_siocgifflags_nt(int fd, struct ifreq *ifr) {
static textwindows int ioctl_siocgifnetmask_nt(int fd, struct ifreq *ifr) { static textwindows int ioctl_siocgifnetmask_nt(int fd, struct ifreq *ifr) {
struct HostAdapterInfoNode *node; struct HostAdapterInfoNode *node;
node = findAdapterByName(ifr->ifr_name); node = findAdapterByName(ifr->ifr_name);
if (!node) return ebadf(); if (!node)
return ebadf();
memcpy(&ifr->ifr_netmask, &node->netmask, sizeof(struct sockaddr)); memcpy(&ifr->ifr_netmask, &node->netmask, sizeof(struct sockaddr));
return 0; return 0;
} }
@ -473,7 +484,8 @@ static textwindows int ioctl_siocgifnetmask_nt(int fd, struct ifreq *ifr) {
static textwindows int ioctl_siocgifbrdaddr_nt(int fd, struct ifreq *ifr) { static textwindows int ioctl_siocgifbrdaddr_nt(int fd, struct ifreq *ifr) {
struct HostAdapterInfoNode *node; struct HostAdapterInfoNode *node;
node = findAdapterByName(ifr->ifr_name); node = findAdapterByName(ifr->ifr_name);
if (!node) return ebadf(); if (!node)
return ebadf();
memcpy(&ifr->ifr_broadaddr, &node->broadcast, sizeof(struct sockaddr)); memcpy(&ifr->ifr_broadaddr, &node->broadcast, sizeof(struct sockaddr));
return 0; return 0;
} }
@ -513,7 +525,8 @@ static int ioctl_siocgifconf_sysv(int fd, struct ifconf *ifc) {
for (p = b, e = p + MIN(bufMax, READ32LE(ifcBsd)); p + 16 + 16 <= e; for (p = b, e = p + MIN(bufMax, READ32LE(ifcBsd)); p + 16 + 16 <= e;
p += IsBsd() ? 16 + MAX(16, p[16] & 255) : 40) { p += IsBsd() ? 16 + MAX(16, p[16] & 255) : 40) {
fam = p[IsBsd() ? 17 : 16] & 255; fam = p[IsBsd() ? 17 : 16] & 255;
if (fam != AF_INET) continue; if (fam != AF_INET)
continue;
ip = READ32BE(p + 20); ip = READ32BE(p + 20);
bzero(req, sizeof(*req)); bzero(req, sizeof(*req));
memcpy(req->ifr_name, p, 16); memcpy(req->ifr_name, p, 16);
@ -541,8 +554,10 @@ static inline void ioctl_sockaddr2linux(void *saddr) {
* requires adjustment between Linux and XNU * requires adjustment between Linux and XNU
*/ */
static int ioctl_siocgifaddr_sysv(int fd, uint64_t op, struct ifreq *ifr) { static int ioctl_siocgifaddr_sysv(int fd, uint64_t op, struct ifreq *ifr) {
if (sys_ioctl(fd, op, ifr) == -1) return -1; if (sys_ioctl(fd, op, ifr) == -1)
if (IsBsd()) ioctl_sockaddr2linux(&ifr->ifr_addr); return -1;
if (IsBsd())
ioctl_sockaddr2linux(&ifr->ifr_addr);
return 0; return 0;
} }

View file

@ -28,7 +28,8 @@
bool isdirectory_nt(const char *path) { bool isdirectory_nt(const char *path) {
uint32_t x; uint32_t x;
char16_t path16[PATH_MAX]; char16_t path16[PATH_MAX];
if (__mkntpath(path, path16) == -1) return -1; if (__mkntpath(path, path16) == -1)
return -1;
if ((x = GetFileAttributes(path16)) != -1u) { if ((x = GetFileAttributes(path16)) != -1u) {
return !!(x & kNtFileAttributeDirectory); return !!(x & kNtFileAttributeDirectory);
} else { } else {

View file

@ -30,6 +30,7 @@
*/ */
bool32 isexecutable(const char *path) { bool32 isexecutable(const char *path) {
struct stat st; struct stat st;
if (fstatat(AT_FDCWD, path, &st, 0)) return 0; if (fstatat(AT_FDCWD, path, &st, 0))
return 0;
return !S_ISDIR(st.st_mode) && !!(st.st_mode & 0111); return !S_ISDIR(st.st_mode) && !!(st.st_mode & 0111);
} }

View file

@ -33,7 +33,8 @@ static struct {
static bool __is_linux_2_6_23_impl(void) { static bool __is_linux_2_6_23_impl(void) {
int rc; int rc;
if (IsGenuineBlink()) return true; if (IsGenuineBlink())
return true;
asm volatile("syscall" asm volatile("syscall"
: "=a"(rc) : "=a"(rc)
: "0"(157), "D"(PR_GET_SECCOMP) : "0"(157), "D"(PR_GET_SECCOMP)

View file

@ -28,7 +28,8 @@
bool isregularfile_nt(const char *path) { bool isregularfile_nt(const char *path) {
uint32_t x; uint32_t x;
char16_t path16[PATH_MAX]; char16_t path16[PATH_MAX];
if (__mkntpath(path, path16) == -1) return -1; if (__mkntpath(path, path16) == -1)
return -1;
if ((x = GetFileAttributes(path16)) != -1u) { if ((x = GetFileAttributes(path16)) != -1u) {
return !(x & (kNtFileAttributeDirectory | kNtFileAttributeReparsePoint)); return !(x & (kNtFileAttributeDirectory | kNtFileAttributeReparsePoint));
} else { } else {

View file

@ -26,7 +26,8 @@
bool issymlink_nt(const char *path) { bool issymlink_nt(const char *path) {
uint32_t x; uint32_t x;
char16_t path16[PATH_MAX]; char16_t path16[PATH_MAX];
if (__mkntpath(path, path16) == -1) return -1; if (__mkntpath(path, path16) == -1)
return -1;
if ((x = GetFileAttributes(path16)) != -1u) { if ((x = GetFileAttributes(path16)) != -1u) {
return !!(x & kNtFileAttributeReparsePoint); return !!(x & kNtFileAttributeReparsePoint);
} else { } else {

View file

@ -52,31 +52,42 @@ int makedirs(const char *path, unsigned mode) {
e = errno; e = errno;
n = strlen(path); n = strlen(path);
if (n >= PATH_MAX) return enametoolong(); if (n >= PATH_MAX)
return enametoolong();
memcpy(buf, path, n + 1); memcpy(buf, path, n + 1);
i = n; i = n;
// descend // descend
while (i) { while (i) {
if (!mkdir(buf, mode)) break; if (!mkdir(buf, mode))
break;
if (errno == EEXIST) { if (errno == EEXIST) {
if (i == n) goto CheckTop; if (i == n)
goto CheckTop;
break; break;
} }
if (errno != ENOENT) return -1; if (errno != ENOENT)
while (i && buf[i - 1] == '/') buf[--i] = 0; return -1;
while (i && buf[i - 1] != '/') buf[--i] = 0; while (i && buf[i - 1] == '/')
buf[--i] = 0;
while (i && buf[i - 1] != '/')
buf[--i] = 0;
} }
// ascend // ascend
for (;;) { for (;;) {
if (mkdir(buf, mode)) { if (mkdir(buf, mode)) {
if (errno != EEXIST) return -1; if (errno != EEXIST)
if (i == n) goto CheckTop; return -1;
if (i == n)
goto CheckTop;
} }
if (i == n) break; if (i == n)
while (i < n && (c = path[i]) != '/') buf[i++] = c; break;
while (i < n && (c = path[i]) == '/') buf[i++] = c; while (i < n && (c = path[i]) != '/')
buf[i++] = c;
while (i < n && (c = path[i]) == '/')
buf[i++] = c;
} }
Finish: Finish:
@ -84,7 +95,9 @@ Finish:
return 0; return 0;
CheckTop: CheckTop:
if (stat(path, &st)) return -1; if (stat(path, &st))
if (S_ISDIR(st.st_mode)) goto Finish; return -1;
if (S_ISDIR(st.st_mode))
goto Finish;
return eexist(); return eexist();
} }

View file

@ -23,7 +23,9 @@
textwindows int sys_mkdirat_nt(int dirfd, const char *path, uint32_t mode) { textwindows int sys_mkdirat_nt(int dirfd, const char *path, uint32_t mode) {
char16_t path16[PATH_MAX]; char16_t path16[PATH_MAX];
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1; if (__mkntpathat(dirfd, path, 0, path16) == -1)
if (CreateDirectory(path16, 0)) return 0; return -1;
if (CreateDirectory(path16, 0))
return 0;
return __fix_enotdir(-1, path16); return __fix_enotdir(-1, path16);
} }

View file

@ -42,10 +42,14 @@
*/ */
int mknod(const char *path, uint32_t mode, uint64_t dev) { int mknod(const char *path, uint32_t mode, uint64_t dev) {
int e, rc; int e, rc;
if (IsAsan() && !__asan_is_valid_str(path)) return efault(); if (IsAsan() && !__asan_is_valid_str(path))
if (mode & S_IFREG) return creat(path, mode & ~S_IFREG); return efault();
if (mode & S_IFDIR) return mkdir(path, mode & ~S_IFDIR); if (mode & S_IFREG)
if (mode & S_IFIFO) return enosys(); // no named pipes! return creat(path, mode & ~S_IFREG);
if (mode & S_IFDIR)
return mkdir(path, mode & ~S_IFDIR);
if (mode & S_IFIFO)
return enosys(); // no named pipes!
if (!IsWindows()) { if (!IsWindows()) {
// TODO(jart): Whys there code out there w/ S_xxx passed via dev? // TODO(jart): Whys there code out there w/ S_xxx passed via dev?
e = errno; e = errno;

View file

@ -86,7 +86,8 @@ textwindows int mkntcmdline(char16_t cmdline[32767], char *const argv[]) {
size_t i, j, k, s; size_t i, j, k, s;
char argbuf[PATH_MAX]; char argbuf[PATH_MAX];
for (k = i = 0; argv[i]; ++i) { for (k = i = 0; argv[i]; ++i) {
if (i) APPEND(u' '); if (i)
APPEND(u' ');
if (LooksLikeCosmoDrivePath(argv[i]) && if (LooksLikeCosmoDrivePath(argv[i]) &&
strlcpy(argbuf, argv[i], PATH_MAX) < PATH_MAX) { strlcpy(argbuf, argv[i], PATH_MAX) < PATH_MAX) {
mungentpath(argbuf); mungentpath(argbuf);
@ -112,7 +113,8 @@ textwindows int mkntcmdline(char16_t cmdline[32767], char *const argv[]) {
} }
} }
} }
if (!x) break; if (!x)
break;
if (x == '\\') { if (x == '\\') {
++slashes; ++slashes;
} else if (x == '"') { } else if (x == '"') {
@ -125,7 +127,8 @@ textwindows int mkntcmdline(char16_t cmdline[32767], char *const argv[]) {
} }
slashes = 0; slashes = 0;
uint32_t w = EncodeUtf16(x); uint32_t w = EncodeUtf16(x);
do APPEND(w); do
APPEND(w);
while ((w >>= 16)); while ((w >>= 16));
} }
} }

View file

@ -44,9 +44,12 @@ static textwindows int Compare(const char *l, const char *r) {
for (;;) { for (;;) {
a = l[i] & 255; a = l[i] & 255;
b = r[i] & 255; b = r[i] & 255;
if (a == '=') a = 0; if (a == '=')
if (b == '=') b = 0; a = 0;
if (a != b || !b) break; if (b == '=')
b = 0;
if (a != b || !b)
break;
++i; ++i;
} }
return a - b; return a - b;
@ -56,13 +59,15 @@ static textwindows int InsertString(struct EnvBuilder *env, const char *str) {
int c, i, cmp; int c, i, cmp;
char *var, *path = 0; char *var, *path = 0;
if (!str) return 0; if (!str)
return 0;
// copy key=val to buf // copy key=val to buf
var = env->buf + env->bufi; var = env->buf + env->bufi;
do { do {
c = *str++; c = *str++;
if (env->bufi + 2 > 32767) return e2big(); if (env->bufi + 2 > 32767)
return e2big();
env->buf[env->bufi++] = c; env->buf[env->bufi++] = c;
if (c == '=' && str[0] == '/' && IsAlpha(str[1]) && str[2] == '/') { if (c == '=' && str[0] == '/' && IsAlpha(str[1]) && str[2] == '/') {
path = env->buf + env->bufi; path = env->buf + env->bufi;
@ -70,7 +75,8 @@ static textwindows int InsertString(struct EnvBuilder *env, const char *str) {
} while (c); } while (c);
// fixup key=/c/... → key=c:\... // fixup key=/c/... → key=c:\...
if (path) mungentpath(path); if (path)
mungentpath(path);
// append key=val to sorted list using insertion sort technique // append key=val to sorted list using insertion sort technique
for (i = env->vari;; --i) { for (i = env->vari;; --i) {
@ -143,8 +149,10 @@ textwindows int mkntenvblock(char16_t envblock[32767], char *const envp[],
#pragma GCC pop_options #pragma GCC pop_options
// load new environment into string pointer array and fix file paths // load new environment into string pointer array and fix file paths
if (InsertStrings(&env, envp) == -1) return -1; if (InsertStrings(&env, envp) == -1)
if (InsertStrings(&env, extravars) == -1) return -1; return -1;
if (InsertStrings(&env, extravars) == -1)
return -1;
if (environ) { if (environ) {
// https://jpassing.com/2009/12/28/the-hidden-danger-of-forgetting-to-specify-systemroot-in-a-custom-environment-block/ // https://jpassing.com/2009/12/28/the-hidden-danger-of-forgetting-to-specify-systemroot-in-a-custom-environment-block/
e = __getenv(environ, "SYSTEMROOT"); e = __getenv(environ, "SYSTEMROOT");

View file

@ -54,8 +54,10 @@ textwindows size_t __normntpath(char16_t *p, size_t n) {
(i + 1 < n && p[i + 1] == '.') && // (i + 1 < n && p[i + 1] == '.') && //
(i + 2 == n || IsSlash(p[i + 2]))) { (i + 2 == n || IsSlash(p[i + 2]))) {
// matched "/../" or "/..$" // matched "/../" or "/..$"
while (j && p[j - 1] == '\\') --j; while (j && p[j - 1] == '\\')
while (j && p[j - 1] != '\\') --j; --j;
while (j && p[j - 1] != '\\')
--j;
} else { } else {
p[j++] = c; p[j++] = c;
} }
@ -156,7 +158,8 @@ textwindows int __mkntpath2(const char *path,
if (!x && IsSlash(q[0]) && q[1] == 't' && q[2] == 'm' && q[3] == 'p' && if (!x && IsSlash(q[0]) && q[1] == 't' && q[2] == 'm' && q[3] == 'p' &&
(IsSlash(q[4]) || !q[4])) { (IsSlash(q[4]) || !q[4])) {
m = GetTempPath(z, p); m = GetTempPath(z, p);
if (!q[4]) return m; if (!q[4])
return m;
q += 5; q += 5;
p += m; p += m;
z -= m; z -= m;

View file

@ -33,14 +33,19 @@ static textwindows int __mkntpathath_impl(int64_t dirhand, const char *path,
size_t n; size_t n;
char16_t dir[PATH_MAX]; char16_t dir[PATH_MAX];
uint32_t dirlen, filelen; uint32_t dirlen, filelen;
if (!isutf8(path, -1)) return eilseq(); // thwart overlong nul in conversion if (!isutf8(path, -1))
if ((filelen = __mkntpath2(path, file, flags)) == -1) return -1; return eilseq(); // thwart overlong nul in conversion
if (!filelen) return enoent(); if ((filelen = __mkntpath2(path, file, flags)) == -1)
return -1;
if (!filelen)
return enoent();
if (file[0] != u'\\' && dirhand != AT_FDCWD) { // ProTip: \\?\C:\foo if (file[0] != u'\\' && dirhand != AT_FDCWD) { // ProTip: \\?\C:\foo
dirlen = GetFinalPathNameByHandle(dirhand, dir, ARRAYLEN(dir), dirlen = GetFinalPathNameByHandle(dirhand, dir, ARRAYLEN(dir),
kNtFileNameNormalized | kNtVolumeNameDos); kNtFileNameNormalized | kNtVolumeNameDos);
if (!dirlen) return __winerr(); if (!dirlen)
if (dirlen + 1 + filelen + 1 > ARRAYLEN(dir)) return enametoolong(); return __winerr();
if (dirlen + 1 + filelen + 1 > ARRAYLEN(dir))
return enametoolong();
dir[dirlen] = u'\\'; dir[dirlen] = u'\\';
memcpy(dir + dirlen + 1, file, (filelen + 1) * sizeof(char16_t)); memcpy(dir + dirlen + 1, file, (filelen + 1) * sizeof(char16_t));
memcpy(file, dir, ((n = dirlen + 1 + filelen) + 1) * sizeof(char16_t)); memcpy(file, dir, ((n = dirlen + 1 + filelen) + 1) * sizeof(char16_t));

View file

@ -84,7 +84,8 @@ int mount(const char *source, const char *target, const char *type,
if (!IsBsd()) { if (!IsBsd()) {
return sys_mount_linux(source, target, type, flags, data); return sys_mount_linux(source, target, type, flags, data);
} else { } else {
if (!strcmp(type, "iso9660")) type = "cd9660"; if (!strcmp(type, "iso9660"))
type = "cd9660";
if (!strcmp(type, "vfat")) { if (!strcmp(type, "vfat")) {
if (IsOpenbsd() || IsNetbsd()) { if (IsOpenbsd() || IsNetbsd()) {
type = "msdos"; type = "msdos";

View file

@ -47,7 +47,8 @@ void *sys_mremap(void *p, size_t n, size_t m, int f, void *q) {
: "=a"(res) : "=a"(res)
: "0"(0x019), "D"(p), "S"(n), "d"(m), "r"(r10), "r"(r8) : "0"(0x019), "D"(p), "S"(n), "d"(m), "r"(r10), "r"(r8)
: "rcx", "r11", "memory", "cc"); : "rcx", "r11", "memory", "cc");
if (res > -4096ul) errno = -res, res = -1; if (res > -4096ul)
errno = -res, res = -1;
} else if (IsNetbsd()) { } else if (IsNetbsd()) {
if (f & MREMAP_MAYMOVE) { if (f & MREMAP_MAYMOVE) {
res = 0x19B; res = 0x19B;
@ -57,7 +58,8 @@ void *sys_mremap(void *p, size_t n, size_t m, int f, void *q) {
: CFLAG_CONSTRAINT(cf), "+a"(res), "=d"(rdx) : CFLAG_CONSTRAINT(cf), "+a"(res), "=d"(rdx)
: "D"(p), "S"(n), "2"(q), "r"(r10), "r"(r8) : "D"(p), "S"(n), "2"(q), "r"(r10), "r"(r8)
: "rcx", "r9", "r11", "memory", "cc"); : "rcx", "r9", "r11", "memory", "cc");
if (cf) errno = res, res = -1; if (cf)
errno = res, res = -1;
} else { } else {
res = einval(); res = einval();
} }

View file

@ -69,7 +69,8 @@ textwindows int ntaccesscheck(const char16_t *pathname, uint32_t flags) {
int64_t hToken, hImpersonatedToken, hFile; int64_t hToken, hImpersonatedToken, hFile;
intptr_t buffer[1024 / sizeof(intptr_t)]; intptr_t buffer[1024 / sizeof(intptr_t)];
BLOCK_SIGNALS; BLOCK_SIGNALS;
if (flags & X_OK) flags |= R_OK; if (flags & X_OK)
flags |= R_OK;
granted = 0; granted = 0;
result = false; result = false;
flagmask = flags; flagmask = flags;

View file

@ -157,7 +157,8 @@ textwindows int ntspawn(
} }
} }
} }
if (sb) ntspawn_free(sb); if (sb)
ntspawn_free(sb);
ALLOW_SIGNALS; ALLOW_SIGNALS;
return rc; return rc;
} }

View file

@ -184,7 +184,8 @@ static textwindows int sys_open_nt_dup(int fd, int flags, int mode, int oldfd) {
static int Atoi(const char *str) { static int Atoi(const char *str) {
int c; int c;
unsigned x = 0; unsigned x = 0;
if (!*str) return -1; if (!*str)
return -1;
while ((c = *str++)) { while ((c = *str++)) {
if ('0' <= c && c <= '9') { if ('0' <= c && c <= '9') {
x *= 10; x *= 10;
@ -202,7 +203,8 @@ textwindows int sys_open_nt(int dirfd, const char *file, uint32_t flags,
int fd, oldfd; int fd, oldfd;
BLOCK_SIGNALS; BLOCK_SIGNALS;
__fds_lock(); __fds_lock();
if (!(flags & _O_CREAT)) mode = 0; if (!(flags & _O_CREAT))
mode = 0;
if ((rc = fd = __reservefd_unlocked(-1)) != -1) { if ((rc = fd = __reservefd_unlocked(-1)) != -1) {
if (startswith(file, "/dev/")) { if (startswith(file, "/dev/")) {
if (!strcmp(file + 5, "tty")) { if (!strcmp(file + 5, "tty")) {

View file

@ -40,20 +40,26 @@
int sys_openat_metal(int dirfd, const char *file, int flags, unsigned mode) { int sys_openat_metal(int dirfd, const char *file, int flags, unsigned mode) {
int fd; int fd;
struct MetalFile *state; struct MetalFile *state;
if (dirfd != AT_FDCWD || strcmp(file, APE_COM_NAME)) return enoent(); if (dirfd != AT_FDCWD || strcmp(file, APE_COM_NAME))
if (flags != O_RDONLY) return eacces(); return enoent();
if (!_weaken(__ape_com_base) || !_weaken(__ape_com_size)) return eopnotsupp(); if (flags != O_RDONLY)
if ((fd = __reservefd(-1)) == -1) return -1; return eacces();
if (!_weaken(__ape_com_base) || !_weaken(__ape_com_size))
return eopnotsupp();
if ((fd = __reservefd(-1)) == -1)
return -1;
if (!_weaken(calloc) || !_weaken(free)) { if (!_weaken(calloc) || !_weaken(free)) {
struct DirectMap dm; struct DirectMap dm;
dm = sys_mmap_metal(NULL, ROUNDUP(sizeof(struct MetalFile), 4096), dm = sys_mmap_metal(NULL, ROUNDUP(sizeof(struct MetalFile), 4096),
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1,
0); 0);
state = dm.addr; state = dm.addr;
if (state == (void *)-1) return -1; if (state == (void *)-1)
return -1;
} else { } else {
state = _weaken(calloc)(1, sizeof(struct MetalFile)); state = _weaken(calloc)(1, sizeof(struct MetalFile));
if (!state) return -1; if (!state)
return -1;
} }
state->base = (char *)__ape_com_base; state->base = (char *)__ape_com_base;
state->size = __ape_com_size; state->size = __ape_com_size;

View file

@ -64,12 +64,16 @@ static int openpty_impl(int *mfd, int *sfd, char *name,
} }
*mfd = m; *mfd = m;
*sfd = s; *sfd = s;
if (name) strcpy(name, t.sname); if (name)
if (tio) npassert(!tcsetattr(s, TCSAFLUSH, tio)); strcpy(name, t.sname);
if (wsz) npassert(!tcsetwinsize(s, wsz)); if (tio)
npassert(!tcsetattr(s, TCSAFLUSH, tio));
if (wsz)
npassert(!tcsetwinsize(s, wsz));
return 0; return 0;
OnError: OnError:
if (m != -1) sys_close(m); if (m != -1)
sys_close(m);
return -1; return -1;
} }

View file

@ -32,7 +32,8 @@
static textwindows int _park_thread(uint32_t msdelay, sigset_t waitmask, static textwindows int _park_thread(uint32_t msdelay, sigset_t waitmask,
bool restartable) { bool restartable) {
int sig, handler_was_called; int sig, handler_was_called;
if (_check_cancel() == -1) return -1; if (_check_cancel() == -1)
return -1;
if (_weaken(__sig_get) && (sig = _weaken(__sig_get)(waitmask))) { if (_weaken(__sig_get) && (sig = _weaken(__sig_get)(waitmask))) {
goto HandleSignal; goto HandleSignal;
} }
@ -46,7 +47,8 @@ static textwindows int _park_thread(uint32_t msdelay, sigset_t waitmask,
if (ok && _weaken(__sig_get) && (sig = _weaken(__sig_get)(waitmask))) { if (ok && _weaken(__sig_get) && (sig = _weaken(__sig_get)(waitmask))) {
HandleSignal: HandleSignal:
handler_was_called = _weaken(__sig_relay)(sig, SI_KERNEL, waitmask); handler_was_called = _weaken(__sig_relay)(sig, SI_KERNEL, waitmask);
if (_check_cancel() == -1) return -1; if (_check_cancel() == -1)
return -1;
if (!restartable || (handler_was_called & SIG_HANDLED_NO_RESTART)) { if (!restartable || (handler_was_called & SIG_HANDLED_NO_RESTART)) {
return eintr(); return eintr();
} }

View file

@ -22,7 +22,8 @@
textwindows int sys_pause_nt(void) { textwindows int sys_pause_nt(void) {
int rc; int rc;
while (!(rc = _park_norestart(-1u, 0))) donothing; while (!(rc = _park_norestart(-1u, 0)))
donothing;
return rc; return rc;
} }

View file

@ -26,6 +26,7 @@
*/ */
void perror(const char *thing) { void perror(const char *thing) {
const char *reason; const char *reason;
if (!(reason = _strerdoc(errno))) reason = "Unknown error"; if (!(reason = _strerdoc(errno)))
reason = "Unknown error";
tinyprint(2, thing ? thing : "", thing ? ": " : "", reason, "\n", NULL); tinyprint(2, thing ? thing : "", thing ? ": " : "", reason, "\n", NULL);
} }

View file

@ -25,7 +25,8 @@
int32_t sys_pipe2(int pipefd[hasatleast 2], unsigned flags) { int32_t sys_pipe2(int pipefd[hasatleast 2], unsigned flags) {
int e, rc; int e, rc;
if (!flags) goto OldSkool; if (!flags)
goto OldSkool;
e = errno; e = errno;
rc = __sys_pipe2(pipefd, flags); rc = __sys_pipe2(pipefd, flags);
if (rc == -1 && errno == ENOSYS) { if (rc == -1 && errno == ENOSYS) {

View file

@ -1023,18 +1023,21 @@ static const struct sock_filter kFilterIgnoreExitGroup[] = {
static privileged unsigned long StrLen(const char *s) { static privileged unsigned long StrLen(const char *s) {
unsigned long n = 0; unsigned long n = 0;
while (*s++) ++n; while (*s++)
++n;
return n; return n;
} }
static privileged void *MemCpy(void *d, const void *s, unsigned long n) { static privileged void *MemCpy(void *d, const void *s, unsigned long n) {
unsigned long i = 0; unsigned long i = 0;
for (; i < n; ++i) ((char *)d)[i] = ((char *)s)[i]; for (; i < n; ++i)
((char *)d)[i] = ((char *)s)[i];
return (char *)d + n; return (char *)d + n;
} }
static privileged char *FixCpy(char p[17], uint64_t x, int k) { static privileged char *FixCpy(char p[17], uint64_t x, int k) {
while (k > 0) *p++ = "0123456789abcdef"[(x >> (k -= 4)) & 15]; while (k > 0)
*p++ = "0123456789abcdef"[(x >> (k -= 4)) & 15];
*p = '\0'; *p = '\0';
return p; return p;
} }
@ -1305,7 +1308,8 @@ static privileged void MonitorSigSys(void) {
static privileged void AppendFilter(struct Filter *f, static privileged void AppendFilter(struct Filter *f,
const struct sock_filter *p, size_t n) { const struct sock_filter *p, size_t n) {
if (UNLIKELY(f->n + n > ARRAYLEN(f->p))) notpossible; if (UNLIKELY(f->n + n > ARRAYLEN(f->p)))
notpossible;
MemCpy(f->p + f->n, p, n * sizeof(*f->p)); MemCpy(f->p + f->n, p, n * sizeof(*f->p));
f->n += n; f->n += n;
} }
@ -2170,7 +2174,8 @@ static privileged void AppendPledge(struct Filter *f, //
if ((count = CountUnspecial(p, len))) { if ((count = CountUnspecial(p, len))) {
if (count < 256) { if (count < 256) {
for (j = i = 0; i < len; ++i) { for (j = i = 0; i < len; ++i) {
if (p[i] & SPECIAL) continue; if (p[i] & SPECIAL)
continue;
// jump to ALLOW rule below if accumulator equals ordinal // jump to ALLOW rule below if accumulator equals ordinal
struct sock_filter fragment[] = { struct sock_filter fragment[] = {
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, // instruction BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, // instruction
@ -2192,7 +2197,8 @@ static privileged void AppendPledge(struct Filter *f, //
// handle "special" ordinals which use hand-crafted bpf // handle "special" ordinals which use hand-crafted bpf
for (i = 0; i < len; ++i) { for (i = 0; i < len; ++i) {
if (!(p[i] & SPECIAL)) continue; if (!(p[i] & SPECIAL))
continue;
switch (p[i]) { switch (p[i]) {
case __NR_linux_mmap | EXEC: case __NR_linux_mmap | EXEC:
AllowMmapExec(f); AllowMmapExec(f);

View file

@ -249,12 +249,17 @@ int pledge(const char *promises, const char *execpromises) {
// may use pledge(0,0) to perform a support check, to determine if // may use pledge(0,0) to perform a support check, to determine if
// pledge() will be able to impose the restrictions it advertises // pledge() will be able to impose the restrictions it advertises
// within the host environment. // within the host environment.
if (execpromises) return einval(); if (execpromises)
if (IsGenuineBlink()) return enosys(); return einval();
if (IsOpenbsd()) return sys_pledge(0, 0); if (IsGenuineBlink())
if (!IsLinux()) return enosys(); return enosys();
if (IsOpenbsd())
return sys_pledge(0, 0);
if (!IsLinux())
return enosys();
rc = sys_prctl(PR_GET_SECCOMP, 0, 0, 0, 0); rc = sys_prctl(PR_GET_SECCOMP, 0, 0, 0, 0);
if (rc == 0 || rc == 2) return 0; // 2 means we're already filtered if (rc == 0 || rc == 2)
return 0; // 2 means we're already filtered
unassert(rc < 0); unassert(rc < 0);
errno = -rc; errno = -rc;
return -1; return -1;
@ -274,9 +279,11 @@ int pledge(const char *promises, const char *execpromises) {
STRACE("execpromises must be a subset of promises"); STRACE("execpromises must be a subset of promises");
rc = einval(); rc = einval();
} else { } else {
if (notsubset) iexecpromises = ipromises; if (notsubset)
iexecpromises = ipromises;
rc = sys_pledge_linux(ipromises, __pledge_mode); rc = sys_pledge_linux(ipromises, __pledge_mode);
if (rc > -4096u) errno = -rc, rc = -1; if (rc > -4096u)
errno = -rc, rc = -1;
} }
} else { } else {
e = errno; e = errno;

View file

@ -71,7 +71,8 @@ int sys_poll_metal(struct pollfd *fds, size_t nfds, unsigned timeout_ms) {
fds[i].revents = POLLNVAL; fds[i].revents = POLLNVAL;
} }
} }
if (fds[i].revents) ++rc; if (fds[i].revents)
++rc;
} }
if (rc || !blocking || unsignedsubtract(rdtsc(), start) >= timeout) { if (rc || !blocking || unsignedsubtract(rdtsc(), start) >= timeout) {
break; break;

View file

@ -81,7 +81,8 @@ static textwindows int sys_poll_nt_impl(struct pollfd *fds, uint64_t nfds,
// we might need to spawn threads and open pipes // we might need to spawn threads and open pipes
__fds_lock(); __fds_lock();
for (gotinvals = rc = sn = pn = i = 0; i < nfds; ++i) { for (gotinvals = rc = sn = pn = i = 0; i < nfds; ++i) {
if (fds[i].fd < 0) continue; if (fds[i].fd < 0)
continue;
if (__isfdopen(fds[i].fd)) { if (__isfdopen(fds[i].fd)) {
if (__isfdkind(fds[i].fd, kFdSocket)) { if (__isfdkind(fds[i].fd, kFdSocket)) {
if (sn < ARRAYLEN(sockfds)) { if (sn < ARRAYLEN(sockfds)) {

View file

@ -43,7 +43,8 @@ int posix_openpt(int flags) {
rc = sys_openat(AT_FDCWD, "/dev/ptm", flags, 0); rc = sys_openat(AT_FDCWD, "/dev/ptm", flags, 0);
} else if (IsFreebsd()) { } else if (IsFreebsd()) {
rc = sys_posix_openpt(flags); rc = sys_posix_openpt(flags);
if (rc == -1 && errno == ENOSPC) errno = EAGAIN; if (rc == -1 && errno == ENOSPC)
errno = EAGAIN;
} else { } else {
rc = enosys(); rc = enosys();
} }

View file

@ -87,9 +87,11 @@ int ppoll(struct pollfd *fds, size_t nfds, const struct timespec *timeout,
(timeout->tv_nsec + 999999) / 1000000)) { (timeout->tv_nsec + 999999) / 1000000)) {
ms = -1; ms = -1;
} }
if (sigmask) sys_sigprocmask(SIG_SETMASK, sigmask, &oldmask); if (sigmask)
sys_sigprocmask(SIG_SETMASK, sigmask, &oldmask);
rc = poll(fds, nfds, ms); rc = poll(fds, nfds, ms);
if (sigmask) sys_sigprocmask(SIG_SETMASK, &oldmask, 0); if (sigmask)
sys_sigprocmask(SIG_SETMASK, &oldmask, 0);
} }
} else { } else {
uint32_t ms; uint32_t ms;

View file

@ -84,7 +84,8 @@ static ssize_t Preadv(int fd, struct iovec *iov, int iovlen, int64_t off) {
e = errno; e = errno;
rc = sys_preadv(fd, iov, iovlen, off, off); rc = sys_preadv(fd, iov, iovlen, off, off);
if (rc != -1 || errno != ENOSYS) return rc; if (rc != -1 || errno != ENOSYS)
return rc;
errno = e; errno = e;
for (toto = i = 0; i < iovlen; ++i) { for (toto = i = 0; i < iovlen; ++i) {

View file

@ -49,13 +49,16 @@ void __printfds(struct Fd *fds, size_t fdslen) {
int i; int i;
char buf[128]; char buf[128];
for (i = 0; i < fdslen; ++i) { for (i = 0; i < fdslen; ++i) {
if (!fds[i].kind) continue; if (!fds[i].kind)
continue;
kprintf("%3d %s", i, __fdkind2str(fds[i].kind)); kprintf("%3d %s", i, __fdkind2str(fds[i].kind));
if (fds[i].flags) { if (fds[i].flags) {
kprintf(" flags=%s", (DescribeOpenFlags)(buf, fds[i].flags)); kprintf(" flags=%s", (DescribeOpenFlags)(buf, fds[i].flags));
} }
if (fds[i].mode) kprintf(" mode=%#o", fds[i].mode); if (fds[i].mode)
if (fds[i].handle) kprintf(" handle=%ld", fds[i].handle); kprintf(" mode=%#o", fds[i].mode);
if (fds[i].handle)
kprintf(" handle=%ld", fds[i].handle);
kprintf("\n"); kprintf("\n");
} }
} }

View file

@ -24,7 +24,8 @@ char *program_invocation_short_name;
__attribute__((__constructor__(10))) static textstartup void __attribute__((__constructor__(10))) static textstartup void
program_invocation_short_name_init(void) { program_invocation_short_name_init(void) {
char *p, *r; char *p, *r;
if (!__argc) return; if (!__argc)
return;
if ((p = strrchr(__argv[0], '/'))) { if ((p = strrchr(__argv[0], '/'))) {
r = p + 1; r = p + 1;
} else { } else {

View file

@ -47,9 +47,11 @@ long ptrace(int request, ...) {
rc = einval(); /* see consts.sh */ rc = einval(); /* see consts.sh */
} else { } else {
ispeek = IsLinux() && request - 1u < 3; ispeek = IsLinux() && request - 1u < 3;
if (ispeek) data = &peek; if (ispeek)
data = &peek;
rc = __sys_ptrace(request, pid, addr, data); rc = __sys_ptrace(request, pid, addr, data);
if (rc != -1 && ispeek) rc = peek; if (rc != -1 && ispeek)
rc = peek;
} }
STRACE("ptrace(%s, %d, %p, %p) → %p% m", DescribePtrace(request), pid, addr, STRACE("ptrace(%s, %d, %p, %p) → %p% m", DescribePtrace(request), pid, addr,
data, rc); data, rc);

Some files were not shown because too many files have changed in this diff Show more