diff --git a/build/bootstrap/compile.com b/build/bootstrap/compile.com index 89c8adc0b..df9521d24 100755 Binary files a/build/bootstrap/compile.com and b/build/bootstrap/compile.com differ diff --git a/build/definitions.mk b/build/definitions.mk index 7a08e72a7..cfb7eafe8 100644 --- a/build/definitions.mk +++ b/build/definitions.mk @@ -169,7 +169,7 @@ DEFAULT_LDFLAGS = \ --gc-sections \ --build-id=none \ --no-dynamic-linker \ - -zmax-page-size=0x1000 + -zmax-page-size=0x1000 #--cref -Map=$@.map ZIPOBJ_FLAGS = \ -b$(IMAGE_BASE_VIRTUAL) diff --git a/dsp/tty/setraw.c b/dsp/tty/setraw.c index 72eb4a36b..6d2b8d273 100644 --- a/dsp/tty/setraw.c +++ b/dsp/tty/setraw.c @@ -31,13 +31,6 @@ int ttysetraw(struct termios *conf, int64_t flags) { conf->c_cflag &= ~(CSIZE | PARENB); conf->c_cflag |= CS8; conf->c_iflag |= IUTF8; - /* if (flags & kTtyLfToCrLf) { */ - /* /\* conf->c_oflag &= ~(OLCUC | OCRNL | ONLRET | OFILL | OFDEL); *\/ */ - /* /\* conf->c_oflag |= ONLCR | ONOCR; *\/ */ - /* conf->c_oflag |= ONLCR; */ - /* } else { */ - /* conf->c_oflag &= ~OPOST; */ - /* } */ if (!(flags & kTtySigs)) { conf->c_iflag &= ~(IGNBRK | BRKINT); conf->c_lflag &= ~(ISIG); diff --git a/examples/examples.mk b/examples/examples.mk index 3d958f8e3..0f6973377 100644 --- a/examples/examples.mk +++ b/examples/examples.mk @@ -151,14 +151,6 @@ o/$(MODE)/examples/hello.com.dbg: \ $(APE_NO_MODIFY_SELF) @$(APELINK) -o/$(MODE)/examples/printargs.com.dbg: \ - $(EXAMPLES_DEPS) \ - o/$(MODE)/examples/printargs.o \ - o/$(MODE)/examples/examples.pkg \ - $(CRT) \ - $(APE_NO_MODIFY_SELF) - @$(APELINK) - o/$(MODE)/examples/nesemu1.o: QUOTA += -M512m $(EXAMPLES_OBJS): examples/examples.mk diff --git a/examples/printargs.c b/examples/printargs.c index 11c057ce2..60ce148ed 100644 --- a/examples/printargs.c +++ b/examples/printargs.c @@ -7,30 +7,8 @@ │ • http://creativecommons.org/publicdomain/zero/1.0/ │ ╚─────────────────────────────────────────────────────────────────*/ #endif -#include "libc/bits/safemacros.internal.h" -#include "libc/calls/calls.h" #include "libc/runtime/runtime.h" int main() { - int pip[2]; - char buf[PATH_MAX]; - char *args[2] = {0}; - if (strcmp(nulltoempty(getenv("TERM")), "dumb") && isatty(0) && isatty(1) && - ((args[0] = commandv("less", buf)) || - (args[0] = commandv("more", buf)))) { - close(0); - close(2); - pipe(pip); - if (!vfork()) { - close(2); - execv(args[0], args); - _Exit(127); - } - close(0); - __printargs(""); - close(2); - wait(0); - } else { - __printargs(""); - } + __printargs(""); } diff --git a/examples/time.c b/examples/time.c index 2213ba405..b0ee8b974 100644 --- a/examples/time.c +++ b/examples/time.c @@ -67,9 +67,9 @@ int main(int argc, char *argv[]) { char *exepath; struct rusage r; long double real; - char exebuf[PATH_MAX]; + char exebuf[PATH_MAX + 1]; if (argc >= 2) { - if ((exepath = commandv(argv[1], exebuf))) { + if ((exepath = commandv(argv[1], exebuf, sizeof(exebuf)))) { real = nowl(); argv[1] = exepath; if ((ws = xvspawn(OnChild, argv + 1, &r)) != -1) { diff --git a/examples/touch.c b/examples/touch.c index 0325bfc92..58e179f44 100644 --- a/examples/touch.c +++ b/examples/touch.c @@ -20,7 +20,7 @@ int main(int argc, char *argv[]) { int i; for (i = 1; i < argc; ++i) { - if (touch(argv[i], 0644) == -1) { + if (touch(argv[i], 0666) == -1) { fprintf(stderr, "ERROR: %s: %s\n", argv[i], strerror(errno)); exit(1); } diff --git a/libc/calls/calls.h b/libc/calls/calls.h index e50c44cdc..9de7af625 100644 --- a/libc/calls/calls.h +++ b/libc/calls/calls.h @@ -75,7 +75,7 @@ bool isregularfile(const char *); bool issymlink(const char *); bool32 isatty(int) nosideeffect; bool32 ischardev(int) nosideeffect; -char *commandv(const char *, char[hasatleast PATH_MAX]); +char *commandv(const char *, char *, size_t); char *get_current_dir_name(void) dontdiscard; char *getcwd(char *, size_t); char *realpath(const char *, char *); @@ -120,13 +120,16 @@ int ftruncate(int, int64_t); int getdents(unsigned, void *, unsigned, long *); int getdomainname(char *, size_t); int gethostname(char *, size_t); +int getloadavg(double *, int); int getpgid(int); +int getpgrp(void) nosideeffect; int getpid(void); -int gettid(void); int getppid(void); int getpriority(int, unsigned); int getrlimit(int, struct rlimit *); int getrusage(int, struct rusage *); +int getsid(int) nosideeffect; +int gettid(void); int kill(int, int); int killpg(int, int); int link(const char *, const char *) dontthrow; @@ -165,11 +168,12 @@ int rmdir(const char *); int sched_getaffinity(int, uint64_t, void *); int sched_setaffinity(int, uint64_t, const void *); int sched_yield(void); +int seccomp(unsigned, unsigned, void *); int setegid(uint32_t); int seteuid(uint32_t); int setgid(int); -int setpgrp(void); int setpgid(int, int); +int setpgrp(void); int setpriority(int, unsigned, int); int setregid(uint32_t, uint32_t); int setresgid(uint32_t, uint32_t, uint32_t); @@ -206,9 +210,9 @@ long ptrace(int, ...); long telldir(DIR *); long times(struct tms *); size_t GetFileSize(const char *); -ssize_t getfiledescriptorsize(int); ssize_t copy_file_range(int, long *, int, long *, size_t, uint32_t); ssize_t copyfd(int, int64_t *, int, int64_t *, size_t, uint32_t); +ssize_t getfiledescriptorsize(int); ssize_t lseek(int, int64_t, unsigned); ssize_t pread(int, void *, size_t, int64_t); ssize_t preadv(int, struct iovec *, int, int64_t); @@ -225,14 +229,11 @@ struct dirent *readdir(DIR *); uint32_t getegid(void) nosideeffect; uint32_t geteuid(void) nosideeffect; uint32_t getgid(void) nosideeffect; -uint32_t getpgrp(void) nosideeffect; -uint32_t getsid(int) nosideeffect; uint32_t getuid(void) nosideeffect; uint32_t umask(uint32_t); void rewinddir(DIR *); void sync(void); -int getloadavg(double *, int); -int seccomp(unsigned, unsigned, void *); + int clone(int (*)(void *), void *, size_t, int, void *, int *, void *, size_t, int *); diff --git a/libc/calls/chdir-nt.c b/libc/calls/chdir-nt.c index 65c027ce5..cd5f664f9 100644 --- a/libc/calls/chdir-nt.c +++ b/libc/calls/chdir-nt.c @@ -29,7 +29,7 @@ textwindows int sys_chdir_nt(const char *path) { uint32_t n; int e, ms, err, len; - char16_t path16[PATH_MAX], var[4]; + char16_t path16[PATH_MAX + 1], var[4]; if ((len = __mkntpath(path, path16)) == -1) return -1; if (!len) return enoent(); if (len && path16[len - 1] != u'\\') { diff --git a/libc/calls/close.c b/libc/calls/close.c index c8137e0ee..13cfe7b21 100644 --- a/libc/calls/close.c +++ b/libc/calls/close.c @@ -73,7 +73,9 @@ int close(int fd) { } } } - if (!__vforked) __releasefd(fd); + if (!__vforked) { + __releasefd(fd); + } } STRACE("%s(%d) → %d% m", "close", fd, rc); return rc; diff --git a/libc/calls/commandv.c b/libc/calls/commandv.c index fad7460f3..79ad7b629 100644 --- a/libc/calls/commandv.c +++ b/libc/calls/commandv.c @@ -43,15 +43,16 @@ static bool IsComDbgPath(const char *s, size_t n) { READ64LE(s + n - 8) == READ64LE(".COM.DBG")); } -static bool AccessCommand(const char *name, char path[hasatleast PATH_MAX], +static bool AccessCommand(const char *name, char *path, size_t pathsz, size_t namelen, int *err, const char *suffix, size_t pathlen) { size_t suffixlen; suffixlen = strlen(suffix); - if (pathlen + 1 + namelen + suffixlen + 1 > PATH_MAX) return false; + if (pathlen + 1 + namelen + suffixlen + 1 > pathsz) return false; if (pathlen && (path[pathlen - 1] != '/' && path[pathlen - 1] != '\\')) { - path[pathlen] = - !IsWindows() ? '/' : memchr(path, '\\', pathlen) ? '\\' : '/'; + path[pathlen] = !IsWindows() ? '/' + : memchr(path, '\\', pathlen) ? '\\' + : '/'; pathlen++; } memcpy(path + pathlen, name, namelen); @@ -61,7 +62,7 @@ static bool AccessCommand(const char *name, char path[hasatleast PATH_MAX], return false; } -static bool SearchPath(const char *name, char path[hasatleast PATH_MAX], +static bool SearchPath(const char *name, char *path, size_t pathsz, size_t namelen, int *err, const char *suffix) { char sep; size_t i; @@ -70,11 +71,11 @@ static bool SearchPath(const char *name, char path[hasatleast PATH_MAX], sep = IsWindows() && strchr(p, ';') ? ';' : ':'; for (;;) { for (i = 0; p[i] && p[i] != sep; ++i) { - if (i < PATH_MAX) { + if (i < pathsz) { path[i] = p[i]; } } - if (AccessCommand(name, path, namelen, err, suffix, i)) { + if (AccessCommand(name, path, pathsz, namelen, err, suffix, i)) { return true; } if (p[i] == sep) { @@ -86,36 +87,36 @@ static bool SearchPath(const char *name, char path[hasatleast PATH_MAX], return false; } -static bool FindCommand(const char *name, char pathbuf[hasatleast PATH_MAX], - size_t namelen, bool priorityonly, const char *suffix, - int *err) { - if (priorityonly && - (memchr(name, '/', namelen) || memchr(name, '\\', namelen))) { - pathbuf[0] = 0; - return AccessCommand(name, pathbuf, namelen, err, suffix, 0); +static bool FindCommand(const char *name, char *pb, size_t pbsz, size_t namelen, + bool pri, const char *suffix, int *err) { + if (pri && (memchr(name, '/', namelen) || memchr(name, '\\', namelen))) { + pb[0] = 0; + return AccessCommand(name, pb, pbsz, namelen, err, suffix, 0); } - if (IsWindows() && priorityonly) { - return AccessCommand(name, pathbuf, namelen, err, suffix, - stpcpy(pathbuf, kNtSystemDirectory) - pathbuf) || - AccessCommand(name, pathbuf, namelen, err, suffix, - stpcpy(pathbuf, kNtWindowsDirectory) - pathbuf); + if (IsWindows() && pri && + pbsz > max(strlen(kNtSystemDirectory), strlen(kNtWindowsDirectory))) { + return AccessCommand(name, pb, pbsz, namelen, err, suffix, + stpcpy(pb, kNtSystemDirectory) - pb) || + AccessCommand(name, pb, pbsz, namelen, err, suffix, + stpcpy(pb, kNtWindowsDirectory) - pb); } - return (IsWindows() && AccessCommand(name, pathbuf, namelen, err, suffix, - stpcpy(pathbuf, ".") - pathbuf)) || - SearchPath(name, pathbuf, namelen, err, suffix); + return (IsWindows() && + (pbsz > 1 && AccessCommand(name, pb, pbsz, namelen, err, suffix, + stpcpy(pb, ".") - pb))) || + SearchPath(name, pb, pbsz, namelen, err, suffix); } -static bool FindVerbatim(const char *name, char pathbuf[hasatleast PATH_MAX], - size_t namelen, bool priorityonly, int *err) { - return FindCommand(name, pathbuf, namelen, priorityonly, "", err); +static bool FindVerbatim(const char *name, char *pb, size_t pbsz, + size_t namelen, bool pri, int *err) { + return FindCommand(name, pb, pbsz, namelen, pri, "", err); } -static bool FindSuffixed(const char *name, char pathbuf[hasatleast PATH_MAX], - size_t namelen, bool priorityonly, int *err) { +static bool FindSuffixed(const char *name, char *pb, size_t pbsz, + size_t namelen, bool pri, int *err) { return !IsExePath(name, namelen) && !IsComPath(name, namelen) && !IsComDbgPath(name, namelen) && - (FindCommand(name, pathbuf, namelen, priorityonly, ".com", err) || - FindCommand(name, pathbuf, namelen, priorityonly, ".exe", err)); + (FindCommand(name, pb, pbsz, namelen, pri, ".com", err) || + FindCommand(name, pb, pbsz, namelen, pri, ".exe", err)); } /** @@ -127,7 +128,7 @@ static bool FindSuffixed(const char *name, char pathbuf[hasatleast PATH_MAX], * @asyncsignalsafe * @vforksafe */ -char *commandv(const char *name, char pathbuf[hasatleast PATH_MAX]) { +char *commandv(const char *name, char *pathbuf, size_t pathbufsz) { int e, f; char *res; size_t namelen; @@ -136,25 +137,27 @@ char *commandv(const char *name, char pathbuf[hasatleast PATH_MAX]) { efault(); } else if (!(namelen = strlen(name))) { enoent(); - } else if (namelen + 1 > PATH_MAX) { + } else if (namelen + 1 > pathbufsz) { enametoolong(); } else { e = errno; f = ENOENT; - if ((IsWindows() && (FindSuffixed(name, pathbuf, namelen, true, &f) || - FindVerbatim(name, pathbuf, namelen, true, &f) || - FindSuffixed(name, pathbuf, namelen, false, &f) || - FindVerbatim(name, pathbuf, namelen, false, &f))) || - (!IsWindows() && (FindVerbatim(name, pathbuf, namelen, true, &f) || - FindSuffixed(name, pathbuf, namelen, true, &f) || - FindVerbatim(name, pathbuf, namelen, false, &f) || - FindSuffixed(name, pathbuf, namelen, false, &f)))) { + if ((IsWindows() && + (FindSuffixed(name, pathbuf, pathbufsz, namelen, true, &f) || + FindVerbatim(name, pathbuf, pathbufsz, namelen, true, &f) || + FindSuffixed(name, pathbuf, pathbufsz, namelen, false, &f) || + FindVerbatim(name, pathbuf, pathbufsz, namelen, false, &f))) || + (!IsWindows() && + (FindVerbatim(name, pathbuf, pathbufsz, namelen, true, &f) || + FindSuffixed(name, pathbuf, pathbufsz, namelen, true, &f) || + FindVerbatim(name, pathbuf, pathbufsz, namelen, false, &f) || + FindSuffixed(name, pathbuf, pathbufsz, namelen, false, &f)))) { errno = e; res = pathbuf; } else { errno = f; } } - STRACE("commandv(%#s, %p) → %#s% m", name, pathbuf, res); + STRACE("commandv(%#s, %p, %'zu) → %#s% m", name, pathbuf, pathbufsz, res); return res; } diff --git a/libc/calls/copyfile.c b/libc/calls/copyfile.c index c9e9cc93a..1e36a0f80 100644 --- a/libc/calls/copyfile.c +++ b/libc/calls/copyfile.c @@ -37,7 +37,7 @@ static textwindows int sys_copyfile_nt(const char *src, const char *dst, int flags) { int64_t fhsrc, fhdst; struct NtFileTime accessed, modified; - char16_t src16[PATH_MAX], dst16[PATH_MAX]; + char16_t src16[PATH_MAX + 1], dst16[PATH_MAX + 1]; if (__mkntpath(src, src16) == -1) return -1; if (__mkntpath(dst, dst16) == -1) return -1; if (CopyFile(src16, dst16, !!(flags & COPYFILE_NOCLOBBER))) { diff --git a/libc/calls/execlp.c b/libc/calls/execlp.c index 3444fe589..bc59b49d7 100644 --- a/libc/calls/execlp.c +++ b/libc/calls/execlp.c @@ -39,8 +39,8 @@ int execlp(const char *prog, const char *arg, ... /*, NULL*/) { char *exe; char **argv; va_list va, vb; - char pathbuf[PATH_MAX]; - if (!(exe = commandv(prog, pathbuf))) return -1; + char pathbuf[PATH_MAX + 1]; + if (!(exe = commandv(prog, pathbuf, sizeof(pathbuf)))) return -1; va_copy(vb, va); va_start(va, arg); for (i = 0; va_arg(va, const char *); ++i) donothing; diff --git a/libc/calls/execve-sysv.c b/libc/calls/execve-sysv.c index 28b842734..4c8eccfd3 100644 --- a/libc/calls/execve-sysv.c +++ b/libc/calls/execve-sysv.c @@ -33,7 +33,8 @@ int sys_execve(const char *prog, char *const argv[], char *const envp[]) { shargs = alloca((i + 2) * sizeof(char *)); memcpy(shargs + 2, argv + 1, i * sizeof(char *)); if (IsFreebsd() || IsNetbsd()) { - shargs[0] = firstnonnull(commandv("bash", alloca(PATH_MAX)), _PATH_BSHELL); + shargs[0] = firstnonnull( + commandv("bash", alloca(PATH_MAX + 1), PATH_MAX + 1), _PATH_BSHELL); } else { shargs[0] = _PATH_BSHELL; } diff --git a/libc/calls/execve.c b/libc/calls/execve.c index f7a278ecb..9df027a14 100644 --- a/libc/calls/execve.c +++ b/libc/calls/execve.c @@ -60,7 +60,7 @@ int execve(const char *prog, char *const argv[], char *const envp[]) { if (i) kprintf(", "); kprintf("%#s", envp[i]); } - kprintf("})%n"); + kprintf("})\n"); } #endif for (i = 3; i < g_fds.n; ++i) { diff --git a/libc/calls/execvpe.c b/libc/calls/execvpe.c index 8227f2eb1..ed1fd82a9 100644 --- a/libc/calls/execvpe.c +++ b/libc/calls/execvpe.c @@ -36,8 +36,8 @@ */ int execvpe(const char *prog, char *const argv[], char *const *envp) { char *exe; - char pathbuf[PATH_MAX]; + char pathbuf[PATH_MAX + 1]; if (IsAsan() && !__asan_is_valid(prog, 1)) return efault(); - if (!(exe = commandv(prog, pathbuf))) return -1; + if (!(exe = commandv(prog, pathbuf, sizeof(pathbuf)))) return -1; return execve(exe, argv, envp); } diff --git a/libc/calls/faccessat-nt.c b/libc/calls/faccessat-nt.c index c1c66d4da..f8298dcb7 100644 --- a/libc/calls/faccessat-nt.c +++ b/libc/calls/faccessat-nt.c @@ -22,7 +22,7 @@ #include "libc/sysv/errfuns.h" int sys_faccessat_nt(int dirfd, const char *path, int mode, uint32_t flags) { - char16_t path16[PATH_MAX]; + char16_t path16[PATH_MAX + 1]; if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1; return __fix_enotdir(ntaccesscheck(path16, mode), path16); } diff --git a/libc/calls/fchdir-nt.c b/libc/calls/fchdir-nt.c index ab8db742c..3c089a653 100644 --- a/libc/calls/fchdir-nt.c +++ b/libc/calls/fchdir-nt.c @@ -24,7 +24,7 @@ textwindows int sys_fchdir_nt(int dirfd) { uint32_t len; - char16_t dir[PATH_MAX]; + char16_t dir[PATH_MAX + 1]; if (!__isfdkind(dirfd, kFdFile)) return ebadf(); len = GetFinalPathNameByHandle(g_fds.p[dirfd].handle, dir, ARRAYLEN(dir), kNtFileNameNormalized | kNtVolumeNameDos); diff --git a/libc/calls/fchmodat-nt.c b/libc/calls/fchmodat-nt.c index 7b0ba5f7c..d8698aa2e 100644 --- a/libc/calls/fchmodat-nt.c +++ b/libc/calls/fchmodat-nt.c @@ -23,7 +23,7 @@ textwindows int sys_fchmodat_nt(int dirfd, const char *path, uint32_t mode, int flags) { uint32_t attr; - uint16_t path16[PATH_MAX]; + uint16_t path16[PATH_MAX + 1]; if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1; if ((attr = GetFileAttributes(path16)) != -1u) { if (mode & 0200) { diff --git a/libc/calls/fileexists.c b/libc/calls/fileexists.c index 876a1cac9..64aa86cac 100644 --- a/libc/calls/fileexists.c +++ b/libc/calls/fileexists.c @@ -48,7 +48,7 @@ bool fileexists(const char *path) { bool res; union metastat st; struct ZiposUri zipname; - uint16_t path16[PATH_MAX]; + uint16_t path16[PATH_MAX + 1]; e = errno; if (IsAsan() && !__asan_is_valid(path, 1)) { efault(); diff --git a/libc/calls/fstatat-nt.c b/libc/calls/fstatat-nt.c index 468752e70..b17d6d324 100644 --- a/libc/calls/fstatat-nt.c +++ b/libc/calls/fstatat-nt.c @@ -29,7 +29,7 @@ textwindows int sys_fstatat_nt(int dirfd, const char *path, struct stat *st, int flags) { int rc; int64_t fh; - uint16_t path16[PATH_MAX]; + uint16_t path16[PATH_MAX + 1]; if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1; if ((fh = CreateFile( path16, kNtFileReadAttributes, 0, 0, kNtOpenExisting, diff --git a/libc/calls/getcwd-nt.c b/libc/calls/getcwd-nt.c index b2236e276..0847b8653 100644 --- a/libc/calls/getcwd-nt.c +++ b/libc/calls/getcwd-nt.c @@ -28,15 +28,22 @@ textwindows char *sys_getcwd_nt(char *buf, size_t size) { uint64_t w; wint_t x, y; uint32_t n, i, j; - char16_t name16[PATH_MAX + 1]; - if ((n = GetCurrentDirectory(ARRAYLEN(name16), name16))) { - if (n <= PATH_MAX) { - tprecode16to8(buf, size, name16); - for (j = i = 0; i < n;) { - x = name16[i++] & 0xffff; + char16_t p[PATH_MAX + 1]; + if ((n = GetCurrentDirectory(ARRAYLEN(p), p))) { + if (4 + n + 1 <= size && 4 + n + 1 <= ARRAYLEN(p)) { + tprecode16to8(buf, size, p); + j = 0; + if (n >= 3 && isalpha(p[0]) && p[1] == ':' && p[2] == '\\') { + buf[j++] = '/'; + buf[j++] = '/'; + buf[j++] = '?'; + buf[j++] = '/'; + } + for (i = 0; i < n;) { + x = p[i++] & 0xffff; if (!IsUcs2(x)) { if (i < n) { - y = name16[i++] & 0xffff; + y = p[i++] & 0xffff; x = MergeUtf16(x, y); } else { x = 0xfffd; diff --git a/libc/calls/getegid.c b/libc/calls/getegid.c index a6c4709bb..929baeb10 100644 --- a/libc/calls/getegid.c +++ b/libc/calls/getegid.c @@ -19,13 +19,19 @@ #include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/dce.h" /** * Returns effective group ID of calling process. + * @return group id */ uint32_t getegid(void) { int rc; - rc = sys_getegid(); + if (!IsWindows()) { + rc = sys_getegid(); + } else { + rc = getgid(); + } STRACE("%s() → %d% m", "getegid", rc); return rc; } diff --git a/libc/calls/geteuid.c b/libc/calls/geteuid.c index f1990087c..260c4b6ed 100644 --- a/libc/calls/geteuid.c +++ b/libc/calls/geteuid.c @@ -22,10 +22,15 @@ /** * Returns effective user ID of calling process. + * @return user id */ uint32_t geteuid(void) { int rc; - rc = sys_geteuid(); + if (!IsWindows()) { + rc = sys_geteuid(); + } else { + rc = getuid(); + } STRACE("%s() → %d% m", "geteuid", rc); return rc; } diff --git a/libc/calls/getpgrp.c b/libc/calls/getpgrp.c index e6edd52f4..9a15d1c6e 100644 --- a/libc/calls/getpgrp.c +++ b/libc/calls/getpgrp.c @@ -24,7 +24,7 @@ /** * Returns process group id of calling process. */ -uint32_t getpgrp(void) { +int getpgrp(void) { int rc; if (!IsWindows()) { rc = sys_getpgrp(); diff --git a/libc/calls/getrusage-nt.c b/libc/calls/getrusage-nt.c index 341736356..35bb44e50 100644 --- a/libc/calls/getrusage-nt.c +++ b/libc/calls/getrusage-nt.c @@ -18,11 +18,14 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/calls/sig.internal.h" #include "libc/calls/struct/rusage.h" #include "libc/fmt/conv.h" +#include "libc/intrin/spinlock.h" #include "libc/nt/accounting.h" #include "libc/nt/process.h" #include "libc/nt/runtime.h" +#include "libc/nt/struct/iocounters.h" #include "libc/nt/struct/processmemorycounters.h" #include "libc/nt/thread.h" #include "libc/str/str.h" @@ -30,22 +33,32 @@ #include "libc/sysv/errfuns.h" textwindows int sys_getrusage_nt(int who, struct rusage *usage) { + int64_t me, nsignals; + struct NtIoCounters iocount; struct NtProcessMemoryCountersEx memcount; struct NtFileTime ftExit, ftUser, ftKernel, ftCreation; if (!usage) return efault(); if (who == 99) return enosys(); // @see libc/sysv/consts.sh if (!usage) return 0; + me = GetCurrentProcess(); if (!(who == RUSAGE_SELF ? GetProcessTimes : GetThreadTimes)( (who == RUSAGE_SELF ? GetCurrentProcess : GetCurrentThread)(), &ftCreation, &ftExit, &ftKernel, &ftUser) || - !GetProcessMemoryInfo(GetCurrentProcess(), &memcount, sizeof(memcount))) { + !GetProcessMemoryInfo(me, &memcount, sizeof(memcount)) || + !GetProcessIoCounters(me, &iocount)) { return __winerr(); } + _spinlock(&__sig_lock); + nsignals = __sig_count; + _spunlock(&__sig_lock); *usage = (struct rusage){ .ru_utime = WindowsDurationToTimeVal(ReadFileTime(ftUser)), .ru_stime = WindowsDurationToTimeVal(ReadFileTime(ftKernel)), .ru_maxrss = memcount.PeakWorkingSetSize / 1024, .ru_majflt = memcount.PageFaultCount, + .ru_inblock = iocount.ReadOperationCount, + .ru_oublock = iocount.WriteOperationCount, + .ru_nsignals = __sig_count, }; return 0; } diff --git a/libc/calls/getsid.c b/libc/calls/getsid.c index 4c29139f2..1d199e2b0 100644 --- a/libc/calls/getsid.c +++ b/libc/calls/getsid.c @@ -23,7 +23,7 @@ /** * Creates session and sets the process group id. */ -uint32_t getsid(int pid) { +int getsid(int pid) { int rc; rc = sys_getsid(pid); STRACE("%s(%d) → %d% m", "getsid", pid, rc); diff --git a/libc/calls/internal.h b/libc/calls/internal.h index 713383060..283b6f9fb 100644 --- a/libc/calls/internal.h +++ b/libc/calls/internal.h @@ -88,7 +88,7 @@ int __reservefd(int) hidden; void __releasefd(int) hidden; int __ensurefds(int) hidden; int64_t __getfdhandleactual(int) hidden; -void __printfds(void); +void __printfds(void) hidden; forceinline bool __isfdopen(int fd) { return 0 <= fd && fd < g_fds.n && g_fds.p[fd].kind != kFdEmpty; @@ -165,6 +165,7 @@ i32 sys_getppid(void) hidden; i32 sys_getpriority(i32, u32) hidden; i32 sys_getrlimit(i32, struct rlimit *) hidden; i32 sys_getrusage(i32, struct rusage *) hidden; +i32 sys_getsid(int) hidden; i32 sys_ioctl(i32, u64, ...) hidden; i32 sys_kill(i32, i32, i32) hidden; i32 sys_linkat(i32, const char *, i32, const char *, i32) hidden; @@ -191,8 +192,10 @@ i32 sys_setgid(i32) hidden; i32 sys_setitimer(i32, const struct itimerval *, struct itimerval *) hidden; i32 sys_setpgid(i32, i32) hidden; i32 sys_setpriority(i32, u32, i32) hidden; +i32 sys_setregid(u32, u32) hidden; i32 sys_setresgid(uint32_t, uint32_t, uint32_t) hidden; i32 sys_setresuid(uint32_t, uint32_t, uint32_t) hidden; +i32 sys_setreuid(u32, u32) hidden; i32 sys_setrlimit(i32, const struct rlimit *) hidden; i32 sys_setsid(void) hidden; i32 sys_setuid(i32) hidden; @@ -230,7 +233,6 @@ i64 sys_write(i32, const void *, u64) hidden; u32 sys_getegid(void) hidden; u32 sys_geteuid(void) hidden; u32 sys_getgid(void) hidden; -u32 sys_getsid(int) hidden; u32 sys_gettid(void) hidden; u32 sys_getuid(void) hidden; u32 sys_umask(u32) hidden; @@ -337,9 +339,10 @@ bool isregularfile_nt(const char *) hidden; bool issymlink_nt(const char *) hidden; bool32 ntsetprivilege(i64, const char16_t *, u32) hidden; char16_t *CreatePipeName(char16_t *) hidden; -int __mkntpath(const char *, char16_t[hasatleast PATH_MAX - 16]) hidden; -int __mkntpath2(const char *, char16_t[hasatleast PATH_MAX - 16], int) hidden; -int __mkntpathat(int, const char *, int, char16_t[PATH_MAX]) hidden; +int __mkntpath(const char *, char16_t[hasatleast PATH_MAX + 1]) hidden; +int __mkntpath2(const char *, char16_t[hasatleast PATH_MAX + 1], int) hidden; +int __mkntpathat(int, const char *, int, + char16_t[hasatleast PATH_MAX + 1]) hidden; int sys_clock_gettime_nt(int, struct timespec *) hidden; int ntaccesscheck(const char16_t *, u32) paramsnonnull() hidden; int sys_getsetpriority_nt(int, int, int, int (*)(int)); diff --git a/libc/calls/ioctl_tcgets-nt.c b/libc/calls/ioctl_tcgets-nt.c index c3b0110ac..ac04c84f5 100644 --- a/libc/calls/ioctl_tcgets-nt.c +++ b/libc/calls/ioctl_tcgets-nt.c @@ -19,6 +19,7 @@ #include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/calls/struct/termios.h" +#include "libc/calls/ttydefaults.h" #include "libc/nt/console.h" #include "libc/nt/enum/consolemodeflags.h" #include "libc/nt/struct/consolescreenbufferinfoex.h" @@ -35,6 +36,23 @@ textwindows int ioctl_tcgets_nt(int ignored, struct termios *tio) { outok = GetConsoleMode((out = __getfdhandleactual(1)), &outmode); if (inok | outok) { bzero(tio, sizeof(*tio)); + + tio->c_cflag |= CS8; + + tio->c_cc[VINTR] = CTRL('C'); + tio->c_cc[VQUIT] = CTRL('\\'); + tio->c_cc[VERASE] = CTRL('?'); + tio->c_cc[VKILL] = CTRL('U'); + tio->c_cc[VEOF] = CTRL('D'); + tio->c_cc[VMIN] = CTRL('A'); + tio->c_cc[VSTART] = CTRL('Q'); + tio->c_cc[VSTOP] = CTRL('S'); + tio->c_cc[VSUSP] = CTRL('Z'); + tio->c_cc[VREPRINT] = CTRL('R'); + tio->c_cc[VDISCARD] = CTRL('O'); + tio->c_cc[VWERASE] = CTRL('W'); + tio->c_cc[VLNEXT] = CTRL('V'); + if (inok) { if (inmode & kNtEnableLineInput) { tio->c_lflag |= ICANON; @@ -44,16 +62,21 @@ textwindows int ioctl_tcgets_nt(int ignored, struct termios *tio) { } if (inmode & kNtEnableProcessedInput) { tio->c_lflag |= IEXTEN | ISIG; + if (tio->c_lflag | ECHO) { + tio->c_lflag |= ECHOE; + } } } + if (outok) { if (outmode & kNtEnableProcessedOutput) { tio->c_oflag |= OPOST; } if (!(outmode & kNtDisableNewlineAutoReturn)) { - tio->c_oflag |= ONLCR; + tio->c_oflag |= OPOST | ONLCR; } } + return 0; } else { return enotty(); diff --git a/libc/calls/ioctl_tcsets-nt.c b/libc/calls/ioctl_tcsets-nt.c index a457a1d4e..9eb023cad 100644 --- a/libc/calls/ioctl_tcsets-nt.c +++ b/libc/calls/ioctl_tcsets-nt.c @@ -17,8 +17,10 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" +#include "libc/calls/strace.internal.h" #include "libc/calls/struct/metatermios.internal.h" #include "libc/calls/termios.internal.h" +#include "libc/intrin/describeflags.internal.h" #include "libc/nt/console.h" #include "libc/nt/enum/consolemodeflags.h" #include "libc/nt/enum/version.h" @@ -29,35 +31,54 @@ textwindows int ioctl_tcsets_nt(int ignored, uint64_t request, const struct termios *tio) { int64_t in, out; - bool32 inok, outok; + bool32 ok, inok, outok; uint32_t inmode, outmode; inok = GetConsoleMode((in = __getfdhandleactual(0)), &inmode); outok = GetConsoleMode((out = __getfdhandleactual(1)), &outmode); if (inok | outok) { + if (inok) { if (request == TCSETSF) { FlushConsoleInputBuffer(in); } inmode &= ~(kNtEnableLineInput | kNtEnableEchoInput | kNtEnableProcessedInput); - if (tio->c_lflag & ICANON) inmode |= kNtEnableLineInput; - if (tio->c_lflag & ECHO) inmode |= kNtEnableEchoInput; - if (tio->c_lflag & (IEXTEN | ISIG)) inmode |= kNtEnableProcessedInput; inmode |= kNtEnableWindowInput; + if (tio->c_lflag & ICANON) { + inmode |= kNtEnableLineInput; + } + if (tio->c_lflag & ECHO) { + /* + * kNtEnableEchoInput can be used only if the ENABLE_LINE_INPUT mode + * is also enabled. --Quoth MSDN + */ + inmode |= kNtEnableEchoInput | kNtEnableLineInput; + } + if (tio->c_lflag & (IEXTEN | ISIG)) { + inmode |= kNtEnableProcessedInput; + } if (NtGetVersion() >= kNtVersionWindows10) { inmode |= kNtEnableVirtualTerminalInput; } - SetConsoleMode(in, inmode); + ok = SetConsoleMode(in, inmode); + NTTRACE("SetConsoleMode(%p, %s) → %hhhd", in, + DescribeNtConsoleModeInputFlags(inmode), ok); } + if (outok) { - outmode |= kNtEnableWrapAtEolOutput; - if (tio->c_oflag & OPOST) outmode |= kNtEnableProcessedOutput; - if (!(tio->c_oflag & ONLCR)) outmode |= kNtDisableNewlineAutoReturn; + outmode &= ~(kNtDisableNewlineAutoReturn); + outmode |= kNtEnableProcessedOutput; + if (!(tio->c_oflag & ONLCR)) { + outmode |= kNtDisableNewlineAutoReturn; + } if (NtGetVersion() >= kNtVersionWindows10) { outmode |= kNtEnableVirtualTerminalProcessing; } - SetConsoleMode(out, outmode); + ok = SetConsoleMode(out, outmode); + NTTRACE("SetConsoleMode(%p, %s) → %hhhd", out, + DescribeNtConsoleModeOutputFlags(outmode), ok); } + return 0; } else { return enotty(); diff --git a/libc/calls/ioctl_tcsets.c b/libc/calls/ioctl_tcsets.c index b7f8a4155..34e2592fa 100644 --- a/libc/calls/ioctl_tcsets.c +++ b/libc/calls/ioctl_tcsets.c @@ -83,11 +83,6 @@ int ioctl_tcsets(int fd, uint64_t request, ...) { } else { rc = einval(); } - if (rc != -1) { - if (__nomultics == 0 || __nomultics == 1) { - __nomultics = !(tio->c_oflag & OPOST); - } - } STRACE("ioctl_tcsets(%d, %p, %p) → %d% m", fd, request, tio, rc); return rc; } diff --git a/libc/calls/isdirectory-nt.c b/libc/calls/isdirectory-nt.c index d0579a967..36e1dd9db 100644 --- a/libc/calls/isdirectory-nt.c +++ b/libc/calls/isdirectory-nt.c @@ -28,7 +28,7 @@ bool isdirectory_nt(const char *path) { int e; uint32_t x; - char16_t path16[PATH_MAX]; + char16_t path16[PATH_MAX + 1]; e = errno; if (__mkntpath(path, path16) == -1) return -1; if ((x = GetFileAttributes(path16)) != -1u) { diff --git a/libc/calls/isregularfile-nt.c b/libc/calls/isregularfile-nt.c index 45614ef64..91ffab2fd 100644 --- a/libc/calls/isregularfile-nt.c +++ b/libc/calls/isregularfile-nt.c @@ -28,7 +28,7 @@ bool isregularfile_nt(const char *path) { int e; uint32_t x; - char16_t path16[PATH_MAX]; + char16_t path16[PATH_MAX + 1]; e = errno; if (__mkntpath(path, path16) == -1) return -1; if ((x = GetFileAttributes(path16)) != -1u) { diff --git a/libc/calls/issymlink-nt.c b/libc/calls/issymlink-nt.c index 4c074cadb..ef9c3170a 100644 --- a/libc/calls/issymlink-nt.c +++ b/libc/calls/issymlink-nt.c @@ -28,7 +28,7 @@ bool issymlink_nt(const char *path) { int e; uint32_t x; - char16_t path16[PATH_MAX]; + char16_t path16[PATH_MAX + 1]; e = errno; if (__mkntpath(path, path16) == -1) return -1; if ((x = GetFileAttributes(path16)) != -1u) { diff --git a/libc/calls/linkat-nt.c b/libc/calls/linkat-nt.c index 072c203f6..dea46cee9 100644 --- a/libc/calls/linkat-nt.c +++ b/libc/calls/linkat-nt.c @@ -23,8 +23,8 @@ textwindows int sys_linkat_nt(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) { - char16_t newpath16[PATH_MAX]; - char16_t oldpath16[PATH_MAX]; + char16_t newpath16[PATH_MAX + 1]; + char16_t oldpath16[PATH_MAX + 1]; if (__mkntpathat(olddirfd, oldpath, 0, oldpath16) != -1 && __mkntpathat(newdirfd, newpath, 0, newpath16) != -1) { if (CreateHardLink(newpath16, oldpath16, NULL)) { diff --git a/libc/calls/mkdir.c b/libc/calls/mkdir.c index cda89a91c..d41c67814 100644 --- a/libc/calls/mkdir.c +++ b/libc/calls/mkdir.c @@ -36,7 +36,7 @@ * @param path is a UTF-8 string, preferably relative w/ forward slashes * @param mode can be, for example, 0755 * @return 0 on success or -1 w/ errno - * @error EEXIST, ENOTDIR, ENAMETOOLONG, EACCES + * @error ENAMETOOLONG if >246 characters on NT * @asyncsignalsafe * @see makedirs() */ diff --git a/libc/calls/mkdirat-nt.c b/libc/calls/mkdirat-nt.c index b167b9b5b..f15b90326 100644 --- a/libc/calls/mkdirat-nt.c +++ b/libc/calls/mkdirat-nt.c @@ -18,10 +18,13 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" #include "libc/nt/files.h" +#include "libc/str/str.h" +#include "libc/sysv/errfuns.h" textwindows int sys_mkdirat_nt(int dirfd, const char *path, uint32_t mode) { int e; - char16_t *p, path16[PATH_MAX]; + char16_t *p, path16[PATH_MAX + 1]; + /* if (strlen(path) > 248) return enametoolong(); */ if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1; if (CreateDirectory(path16, 0)) return 0; return __fix_enotdir(-1, path16); diff --git a/libc/calls/mkntpath.c b/libc/calls/mkntpath.c index 85248baad..ab5bdd6a8 100644 --- a/libc/calls/mkntpath.c +++ b/libc/calls/mkntpath.c @@ -19,6 +19,7 @@ #include "libc/calls/internal.h" #include "libc/calls/ntmagicpaths.internal.h" #include "libc/calls/strace.internal.h" +#include "libc/macros.internal.h" #include "libc/nt/systeminfo.h" #include "libc/str/oldutf16.internal.h" #include "libc/str/str.h" @@ -49,7 +50,7 @@ textwindows static const char *FixNtMagicPath(const char *path, } textwindows int __mkntpath(const char *path, - char16_t path16[hasatleast PATH_MAX - 16]) { + char16_t path16[hasatleast PATH_MAX + 1]) { return __mkntpath2(path, path16, -1); } @@ -67,14 +68,14 @@ textwindows int __mkntpath(const char *path, * @error ENAMETOOLONG */ textwindows int __mkntpath2(const char *path, - char16_t path16[hasatleast PATH_MAX - 16], + char16_t path16[hasatleast PATH_MAX + 1], int flags) { /* - * 1. Reserve +1 for NUL-terminator - * 2. Reserve +1 for UTF-16 overflow - * 3. Reserve ≥2 for SetCurrentDirectory trailing slash requirement - * 4. Reserve ≥10 for CreateNamedPipe "\\.\pipe\" prefix requirement - * 5. Reserve ≥13 for mkdir() i.e. 1+8+3+1, e.g. "\\ffffffff.xxx\0" + * 1. Need +1 for NUL-terminator + * 2. Need +1 for UTF-16 overflow + * 3. Need ≥2 for SetCurrentDirectory trailing slash requirement + * 5. Need ≥13 for mkdir() i.e. 1+8+3+1, e.g. "\\ffffffff.xxx\0" + * which is an "8.3 filename" from the DOS days */ char16_t *p; const char *q; @@ -83,7 +84,12 @@ textwindows int __mkntpath2(const char *path, path = FixNtMagicPath(path, flags); p = path16; q = path; - z = PATH_MAX - 16; + if (IsSlash(path[0]) && IsSlash(path[1]) && path[2] == '?' && + IsSlash(path[3])) { + z = MIN(32767, PATH_MAX); + } else { + z = MIN(260, PATH_MAX); + } if (IsSlash(q[0]) && q[1] == 't' && q[2] == 'm' && q[3] == 'p' && (IsSlash(q[4]) || !q[4])) { m = GetTempPath(z, p); diff --git a/libc/calls/mkntpathat.c b/libc/calls/mkntpathat.c index 0bd1e4e12..f4e6fd592 100644 --- a/libc/calls/mkntpathat.c +++ b/libc/calls/mkntpathat.c @@ -25,9 +25,9 @@ #include "libc/sysv/errfuns.h" int __mkntpathat(int dirfd, const char *path, int flags, - char16_t file[PATH_MAX]) { - char16_t dir[PATH_MAX]; + char16_t file[hasatleast PATH_MAX + 1]) { uint32_t dirlen, filelen; + char16_t dir[PATH_MAX + 1]; if ((filelen = __mkntpath2(path, file, flags)) == -1) return -1; if (!filelen) return enoent(); if (file[0] != u'\\' && dirfd != AT_FDCWD) { /* ProTip: \\?\C:\foo */ diff --git a/libc/calls/nanosleep-nt.c b/libc/calls/nanosleep-nt.c index c7b7d7125..275bf3086 100644 --- a/libc/calls/nanosleep-nt.c +++ b/libc/calls/nanosleep-nt.c @@ -20,6 +20,7 @@ #include "libc/calls/sig.internal.h" #include "libc/calls/strace.internal.h" #include "libc/errno.h" +#include "libc/limits.h" #include "libc/macros.internal.h" #include "libc/nt/errors.h" #include "libc/nt/nt/time.h" @@ -34,7 +35,7 @@ textwindows noinstrument int sys_nanosleep_nt(const struct timespec *req, int64_t ms, sec, nsec; if (__builtin_mul_overflow(req->tv_sec, 1000, &ms) || __builtin_add_overflow(ms, req->tv_nsec / 1000000, &ms)) { - ms = -1; + ms = INT64_MAX; } if (!ms && (req->tv_sec || req->tv_nsec)) { ms = 1; diff --git a/libc/calls/ntspawn.c b/libc/calls/ntspawn.c index d5f5055bb..584c42a2c 100644 --- a/libc/calls/ntspawn.c +++ b/libc/calls/ntspawn.c @@ -70,7 +70,7 @@ textwindows int ntspawn( int64_t handle; size_t blocksize; struct SpawnBlock *block; - char16_t prog16[PATH_MAX]; + char16_t prog16[PATH_MAX + 1]; rc = -1; block = NULL; if (__mkntpath(prog, prog16) == -1) return -1; diff --git a/libc/calls/open-nt.c b/libc/calls/open-nt.c index 1955a5d18..75c23d7dd 100644 --- a/libc/calls/open-nt.c +++ b/libc/calls/open-nt.c @@ -38,7 +38,7 @@ static textwindows int64_t sys_open_nt_impl(int dirfd, const char *path, uint32_t flags, int32_t mode) { - char16_t path16[PATH_MAX]; + char16_t path16[PATH_MAX + 1]; uint32_t perm, share, disp, attr; if (__mkntpathat(dirfd, path, flags, path16) == -1) return -1; if (GetNtOpenFlags(flags, mode, &perm, &share, &disp, &attr) == -1) return -1; diff --git a/libc/calls/poll.c b/libc/calls/poll.c index acada2c86..f58228e32 100644 --- a/libc/calls/poll.c +++ b/libc/calls/poll.c @@ -95,7 +95,7 @@ int poll(struct pollfd *fds, size_t nfds, int timeout_ms) { DescribePollFlags(flagbuf[0], sizeof(flagbuf[0]), fds[i].events), DescribePollFlags(flagbuf[1], sizeof(flagbuf[1]), fds[i].revents)); } - kprintf("%s}, %'zu, %'d) → %d% lm%n", i == 5 ? "..." : "", nfds, + kprintf("%s}, %'zu, %'d) → %d% lm\n", i == 5 ? "..." : "", nfds, timeout_ms, rc); } } diff --git a/libc/calls/preadv.c b/libc/calls/preadv.c index b4faa2411..94f83a1b8 100644 --- a/libc/calls/preadv.c +++ b/libc/calls/preadv.c @@ -118,7 +118,7 @@ ssize_t preadv(int fd, struct iovec *iov, int iovlen, int64_t off) { } else { kprintf(STRACE_PROLOGUE "preadv(%d, [", fd); __strace_iov(iov, iovlen, rc != -1 ? rc : 0); - kprintf("], %d, %'ld) → %'ld% m%n", iovlen, off, rc); + kprintf("], %d, %'ld) → %'ld% m\n", iovlen, off, rc); } } #endif diff --git a/libc/calls/printfds.c b/libc/calls/printfds.c index 8b5d93ffd..26ad273b2 100644 --- a/libc/calls/printfds.c +++ b/libc/calls/printfds.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" #include "libc/intrin/kprintf.h" +#include "libc/intrin/spinlock.h" static const char *__fdkind2str(int x) { switch (x) { @@ -44,6 +45,7 @@ static const char *__fdkind2str(int x) { void __printfds(void) { int i; + _spinlock(&__fds_lock); for (i = 0; i < g_fds.n; ++i) { if (!g_fds.p[i].kind) continue; kprintf("%3d %s", i, __fdkind2str(g_fds.p[i].kind)); @@ -53,6 +55,7 @@ void __printfds(void) { if (g_fds.p[i].handle) kprintf(" handle=%ld", g_fds.p[i].handle); if (g_fds.p[i].extra) kprintf(" extra=%ld", g_fds.p[i].extra); if (g_fds.p[i].worker) kprintf(" worker=%p", g_fds.p[i].worker); - kprintf("%n", g_fds.p[i].zombie); + kprintf("\n"); } + _spunlock(&__fds_lock); } diff --git a/libc/calls/program_executable_name.c b/libc/calls/program_executable_name.c index 0ef78b22f..316147b28 100644 --- a/libc/calls/program_executable_name.c +++ b/libc/calls/program_executable_name.c @@ -52,14 +52,21 @@ static textwindows bool GetNtExePath(char exe[SIZE]) { uint64_t w; wint_t x, y; uint32_t i, j; - char16_t path16[PATH_MAX + 1]; - path16[0] = 0; - rc = GetModuleFileName(0, path16, ARRAYLEN(path16)); - NTTRACE("GetModuleFileName(0, [%#hs]) → %hhhd", path16, rc); + char16_t p[PATH_MAX + 1]; + p[0] = 0; + rc = GetModuleFileName(0, p, ARRAYLEN(p)); + NTTRACE("GetModuleFileName(0, [%#hs]) → %hhhd", p, rc); if (!rc) return false; - for (i = j = 0; (x = path16[i++] & 0xffff);) { + j = 0; + if (p[0] != '\\' || p[1] != '\\' || p[2] != '?' || p[3] != '\\') { + exe[j++] = '/'; + exe[j++] = '/'; + exe[j++] = '?'; + exe[j++] = '/'; + } + for (i = 0; (x = p[i++] & 0xffff);) { if (!IsUcs2(x)) { - y = path16[i++] & 0xffff; + y = p[i++] & 0xffff; x = MergeUtf16(x, y); } if (x == '\\') x = '/'; diff --git a/libc/calls/pwritev.c b/libc/calls/pwritev.c index e6e08df84..a480338bc 100644 --- a/libc/calls/pwritev.c +++ b/libc/calls/pwritev.c @@ -123,7 +123,7 @@ ssize_t pwritev(int fd, const struct iovec *iov, int iovlen, int64_t off) { } else { kprintf(STRACE_PROLOGUE "pwritev(%d, ", fd); __strace_iov(iov, iovlen, rc != -1 ? rc : 0); - kprintf(", %d, %'ld) → %'ld% m%n", iovlen, off, rc); + kprintf(", %d, %'ld) → %'ld% m\n", iovlen, off, rc); } } #endif diff --git a/libc/calls/readlinkat-nt.c b/libc/calls/readlinkat-nt.c index bc9ac7048..e18549177 100644 --- a/libc/calls/readlinkat-nt.c +++ b/libc/calls/readlinkat-nt.c @@ -27,6 +27,7 @@ #include "libc/nt/files.h" #include "libc/nt/runtime.h" #include "libc/nt/struct/reparsedatabuffer.h" +#include "libc/str/str.h" #include "libc/str/tpenc.h" #include "libc/str/utf16.h" #include "libc/sysv/errfuns.h" @@ -39,7 +40,7 @@ textwindows ssize_t sys_readlinkat_nt(int dirfd, const char *path, char *buf, wint_t x, y; volatile char *memory; uint32_t i, j, n, mem; - char16_t path16[PATH_MAX], *p; + char16_t path16[PATH_MAX + 1], *p; struct NtReparseDataBuffer *rdb; if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1; mem = 16384; @@ -56,6 +57,12 @@ textwindows ssize_t sys_readlinkat_nt(int dirfd, const char *path, char *buf, n = rdb->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(char16_t); p = (char16_t *)((char *)rdb->SymbolicLinkReparseBuffer.PathBuffer + rdb->SymbolicLinkReparseBuffer.PrintNameOffset); + if (n >= 3 && isalpha(p[0]) && p[1] == ':' && p[2] == '\\') { + buf[j++] = '/'; + buf[j++] = '/'; + buf[j++] = '?'; + buf[j++] = '/'; + } while (i < n) { x = p[i++] & 0xffff; if (!IsUcs2(x)) { diff --git a/libc/calls/readv.c b/libc/calls/readv.c index 287641fd9..490f02c1c 100644 --- a/libc/calls/readv.c +++ b/libc/calls/readv.c @@ -72,7 +72,7 @@ ssize_t readv(int fd, const struct iovec *iov, int iovlen) { } else { kprintf(STRACE_PROLOGUE "readv(%d, [", fd); __strace_iov(iov, iovlen, rc != -1 ? rc : 0); - kprintf("], %d) → %'ld% m%n", iovlen, rc); + kprintf("], %d) → %'ld% m\n", iovlen, rc); } } #endif diff --git a/libc/calls/renameat-nt.c b/libc/calls/renameat-nt.c index 949d05d84..9b34e84f9 100644 --- a/libc/calls/renameat-nt.c +++ b/libc/calls/renameat-nt.c @@ -22,8 +22,8 @@ textwindows int sys_renameat_nt(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) { - char16_t oldpath16[PATH_MAX]; - char16_t newpath16[PATH_MAX]; + char16_t oldpath16[PATH_MAX + 1]; + char16_t newpath16[PATH_MAX + 1]; if (__mkntpathat(olddirfd, oldpath, 0, oldpath16) == -1 || __mkntpathat(newdirfd, newpath, 0, newpath16) == -1) { return -1; diff --git a/libc/calls/setegid.c b/libc/calls/setegid.c index 315ea4cbd..6a5c89087 100644 --- a/libc/calls/setegid.c +++ b/libc/calls/setegid.c @@ -22,9 +22,6 @@ /** * Sets effective group ID. */ -int setegid(unsigned egid) { - int rc; - rc = setregid(-1, egid); - STRACE("%s(%u) → %d% m", "setegid", egid, rc); - return rc; +int setegid(uint32_t egid) { + return setregid(-1, egid); } diff --git a/libc/calls/seteuid.c b/libc/calls/seteuid.c index 996ea7d98..2361627e1 100644 --- a/libc/calls/seteuid.c +++ b/libc/calls/seteuid.c @@ -22,9 +22,6 @@ /** * Sets effective user ID. */ -int seteuid(unsigned euid) { - int rc; - rc = setreuid(-1, euid); - STRACE("%s(%u) → %d% m", "seteuid", euid, rc); - return rc; +int seteuid(uint32_t euid) { + return setregid(euid, -1); } diff --git a/libc/calls/setgid.c b/libc/calls/setgid.c index 76a5d2989..93431f3a4 100644 --- a/libc/calls/setgid.c +++ b/libc/calls/setgid.c @@ -21,12 +21,16 @@ #include "libc/calls/strace.internal.h" /** - * Sets effective group id of current process. + * Sets group id of current process. * @return 0 on success or -1 w/ errno */ int setgid(int gid) { int rc; - rc = sys_setgid(gid); - STRACE("%s(%d) → %d% m", "setgid", gid); + if (IsWindows() && gid == getgid()) { + rc = 0; + } else { + rc = sys_setgid(gid); + } + STRACE("setgid(%d) → %d% m", gid, rc); return rc; } diff --git a/libc/calls/setregid.c b/libc/calls/setregid.c new file mode 100644 index 000000000..e2ee4dc94 --- /dev/null +++ b/libc/calls/setregid.c @@ -0,0 +1,35 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/calls/internal.h" +#include "libc/calls/strace.internal.h" + +/** + * Sets real and/or effective group ids. + * + * @param rgid is real group id or -1 to leave it unchanged + * @param egid is effective group id or -1 to leave it unchanged + * @return 0 on success or -1 w/ errno + */ +int setregid(uint32_t rgid, uint32_t egid) { + int rc; + rc = sys_setregid(rgid, egid); + STRACE("setregid(%d, %d) → %d% m", rgid, egid, rc); + return rc; +} diff --git a/libc/calls/setresgid.c b/libc/calls/setresgid.c index b1af4e79d..846df7a93 100644 --- a/libc/calls/setresgid.c +++ b/libc/calls/setresgid.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/calls/strace.internal.h" /** * Sets real, effective, and "saved" group ids. @@ -25,9 +26,17 @@ * @param real sets real group id or -1 to do nothing * @param effective sets effective group id or -1 to do nothing * @param saved sets saved group id or -1 to do nothing - * @see setregid(), getauxval(AT_SECURE) + * @see setresuid(), getauxval(AT_SECURE) + * @raise ENOSYS on Windows NT */ int setresgid(uint32_t real, uint32_t effective, uint32_t saved) { - if (saved == -1) return setregid(real, effective); - return sys_setresgid(real, effective, saved); + int rc; + if (saved != -1) { + rc = sys_setresgid(real, effective, saved); + } else { + // polyfill xnu and netbsd + rc = sys_setregid(real, effective); + } + STRACE("setresgid(%d, %d, %d) → %d% m", real, effective, saved, rc); + return rc; } diff --git a/libc/calls/setresuid.c b/libc/calls/setresuid.c index c4bc134de..a585dc91c 100644 --- a/libc/calls/setresuid.c +++ b/libc/calls/setresuid.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/calls/strace.internal.h" /** * Sets real, effective, and "saved" user ids. @@ -25,9 +26,17 @@ * @param real sets real user id or -1 to do nothing * @param effective sets effective user id or -1 to do nothing * @param saved sets saved user id or -1 to do nothing - * @see setreuid(), getauxval(AT_SECURE) + * @see setresgid(), getauxval(AT_SECURE) + * @raise ENOSYS on Windows NT */ int setresuid(uint32_t real, uint32_t effective, uint32_t saved) { - if (saved == -1) return setreuid(real, effective); - return sys_setresuid(real, effective, saved); + int rc; + if (saved != -1) { + rc = sys_setresuid(real, effective, saved); + } else { + // polyfill xnu and netbsd + rc = sys_setreuid(real, effective); + } + STRACE("setresuid(%d, %d, %d) → %d% m", real, effective, saved, rc); + return rc; } diff --git a/libc/calls/setreuid.c b/libc/calls/setreuid.c new file mode 100644 index 000000000..e3ff17143 --- /dev/null +++ b/libc/calls/setreuid.c @@ -0,0 +1,35 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/calls/internal.h" +#include "libc/calls/strace.internal.h" + +/** + * Sets real and/or effective user ids. + * + * @param ruid is real user id or -1 to leave it unchanged + * @param euid is effective user id or -1 to leave it unchanged + * @return 0 on success or -1 w/ errno + */ +int setreuid(uint32_t ruid, uint32_t euid) { + int rc; + rc = sys_setreuid(ruid, euid); + STRACE("setreuid(%d, %d) → %d% m", ruid, euid, rc); + return rc; +} diff --git a/libc/calls/setuid.c b/libc/calls/setuid.c index edf316f04..f46735559 100644 --- a/libc/calls/setuid.c +++ b/libc/calls/setuid.c @@ -21,12 +21,16 @@ #include "libc/calls/strace.internal.h" /** - * Sets effective group id of current process. + * Sets user id of current process. * @return 0 on success or -1 w/ errno */ int setuid(int uid) { int rc; - rc = sys_setuid(uid); - STRACE("%s(%d) → %d% m", "setuid", uid); + if (IsWindows() && uid == getuid()) { + rc = 0; + } else { + rc = sys_setuid(uid); + } + STRACE("setuid(%d) → %d% m", uid, rc); return rc; } diff --git a/libc/calls/sig.internal.h b/libc/calls/sig.internal.h index 40d3fabd9..2f58b1d6f 100644 --- a/libc/calls/sig.internal.h +++ b/libc/calls/sig.internal.h @@ -24,6 +24,7 @@ struct Signals { }; extern struct Signals __sig; // TODO(jart): Need TLS +extern long __sig_count; bool __sig_check(bool) hidden; bool __sig_handle(bool, int, int, ucontext_t *) hidden; diff --git a/libc/calls/sig2.c b/libc/calls/sig2.c index e48b5fc29..45626eff3 100644 --- a/libc/calls/sig2.c +++ b/libc/calls/sig2.c @@ -222,6 +222,7 @@ textwindows int __sig_add(int sig, int si_code) { if (1 <= sig && sig <= NSIG) { STRACE("enqueuing %G", sig); _spinlock(&__sig_lock); + ++__sig_count; if ((mem = __sig_alloc())) { mem->sig = sig; mem->si_code = si_code; diff --git a/libc/calls/sigcount.c b/libc/calls/sigcount.c new file mode 100644 index 000000000..74986db40 --- /dev/null +++ b/libc/calls/sigcount.c @@ -0,0 +1,21 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/sig.internal.h" + +long __sig_count; diff --git a/libc/calls/strace.internal.h b/libc/calls/strace.internal.h index aea83829a..17a56ca44 100644 --- a/libc/calls/strace.internal.h +++ b/libc/calls/strace.internal.h @@ -5,8 +5,8 @@ #include "libc/calls/struct/sigaction.h" #include "libc/calls/struct/stat.h" -#define _KERNTRACE 1 /* not configurable w/ flag yet */ -#define _POLLTRACE 1 /* not configurable w/ flag yet */ +#define _KERNTRACE 0 /* not configurable w/ flag yet */ +#define _POLLTRACE 0 /* not configurable w/ flag yet */ #define _DATATRACE 1 /* not configurable w/ flag yet */ #define _NTTRACE 1 /* not configurable w/ flag yet */ @@ -19,7 +19,7 @@ COSMOPOLITAN_C_START_ #define STRACE(FMT, ...) \ do { \ if (__strace > 0) { \ - __stracef(STRACE_PROLOGUE FMT "%n", ##__VA_ARGS__); \ + __stracef(STRACE_PROLOGUE FMT "\n", ##__VA_ARGS__); \ } \ } while (0) #else diff --git a/libc/calls/symlinkat-nt.c b/libc/calls/symlinkat-nt.c index 1cbcc3907..89e7bf7c1 100644 --- a/libc/calls/symlinkat-nt.c +++ b/libc/calls/symlinkat-nt.c @@ -53,8 +53,8 @@ textwindows int sys_symlinkat_nt(const char *target, int newdirfd, const char *linkpath) { int targetlen; uint32_t attrs, flags; - char16_t target16[PATH_MAX]; - char16_t linkpath16[PATH_MAX]; + char16_t target16[PATH_MAX + 1]; + char16_t linkpath16[PATH_MAX + 1]; // convert the paths if (__mkntpathat(newdirfd, linkpath, 0, linkpath16) == -1) return -1; diff --git a/libc/calls/truncate-nt.c b/libc/calls/truncate-nt.c index 29c0819b5..df64631a9 100644 --- a/libc/calls/truncate-nt.c +++ b/libc/calls/truncate-nt.c @@ -28,7 +28,7 @@ textwindows int sys_truncate_nt(const char *path, uint64_t length) { int rc; bool32 ok; int64_t fh; - uint16_t path16[PATH_MAX]; + uint16_t path16[PATH_MAX + 1]; if (__mkntpath(path, path16) == -1) return -1; if ((fh = CreateFile(path16, kNtGenericWrite, kNtFileShareRead, NULL, kNtOpenExisting, kNtFileAttributeNormal, 0)) != -1) { diff --git a/libc/calls/ttyname.c b/libc/calls/ttyname.c index 94e064feb..084c0383d 100644 --- a/libc/calls/ttyname.c +++ b/libc/calls/ttyname.c @@ -19,7 +19,7 @@ #include "libc/calls/calls.h" #include "libc/log/log.h" -static char ttyname_buf[PATH_MAX]; +static char ttyname_buf[PATH_MAX + 1]; /** * Returns name of terminal. diff --git a/libc/calls/ttyname_r.c b/libc/calls/ttyname_r.c index fcef19b89..99d67d102 100644 --- a/libc/calls/ttyname_r.c +++ b/libc/calls/ttyname_r.c @@ -63,7 +63,7 @@ static int ttyname_freebsd(int fd, char *buf, size_t size) { static int ttyname_linux(int fd, char *buf, size_t size) { struct stat st1, st2; if (!isatty(fd)) return errno; - char name[PATH_MAX]; + char name[PATH_MAX + 1]; FormatInt32(stpcpy(name, "/proc/self/fd/"), fd); ssize_t got; got = readlink(name, buf, size); diff --git a/libc/calls/unlinkat-nt.c b/libc/calls/unlinkat-nt.c index 3b8555f03..9c08462f5 100644 --- a/libc/calls/unlinkat-nt.c +++ b/libc/calls/unlinkat-nt.c @@ -39,7 +39,8 @@ * from failing for no reason at all. For example a unit test that * repeatedly opens and unlinks the same filename. */ -static textwindows int SyncDirectory(int df, char16_t path[PATH_MAX], int n) { +static textwindows int SyncDirectory(int df, char16_t path[PATH_MAX + 1], + int n) { int rc; int64_t fh; char16_t *p; @@ -128,7 +129,7 @@ static textwindows int sys_unlink_nt(const char16_t *path) { textwindows int sys_unlinkat_nt(int dirfd, const char *path, int flags) { int n, rc; - char16_t path16[PATH_MAX]; + char16_t path16[PATH_MAX + 1]; if ((n = __mkntpathat(dirfd, path, 0, path16)) == -1) { rc = -1; } else if (flags & AT_REMOVEDIR) { diff --git a/libc/calls/utimensat-nt.c b/libc/calls/utimensat-nt.c index 0a5972cde..2694bf0cd 100644 --- a/libc/calls/utimensat-nt.c +++ b/libc/calls/utimensat-nt.c @@ -35,7 +35,7 @@ textwindows int sys_utimensat_nt(int dirfd, const char *path, const struct timespec ts[2], int flags) { int i, rc; int64_t fh; - uint16_t path16[PATH_MAX]; + uint16_t path16[PATH_MAX + 1]; struct NtFileTime ft[2], *ftp[2]; if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1; if ((fh = CreateFile(path16, kNtFileWriteAttributes, kNtFileShareRead, NULL, diff --git a/libc/calls/wait4-nt.c b/libc/calls/wait4-nt.c index c411018eb..14e00a01b 100644 --- a/libc/calls/wait4-nt.c +++ b/libc/calls/wait4-nt.c @@ -95,7 +95,11 @@ static textwindows int sys_wait4_nt_impl(int pid, int *opt_out_wstatus, return 0; } } else { - i = WaitForMultipleObjects(count, handles, false, -1); + i = WaitForMultipleObjects(count, handles, false, + __SIG_POLLING_INTERVAL_MS); + if (i == kNtWaitTimeout) { + continue; + } } if (i == kNtWaitFailed) { STRACE("%s failed %u", "WaitForMultipleObjects", GetLastError()); diff --git a/libc/calls/writev.c b/libc/calls/writev.c index 296fb5353..08bc6df0c 100644 --- a/libc/calls/writev.c +++ b/libc/calls/writev.c @@ -79,7 +79,7 @@ ssize_t writev(int fd, const struct iovec *iov, int iovlen) { } else { kprintf(STRACE_PROLOGUE "writev(%d, ", fd); __strace_iov(iov, iovlen, rc != -1 ? rc : 0); - kprintf(", %d) → %'ld% m%n", iovlen, rc); + kprintf(", %d) → %'ld% m\n", iovlen, rc); } } #endif diff --git a/libc/dns/gethoststxt.c b/libc/dns/gethoststxt.c index 9a8b8a012..360114cdf 100644 --- a/libc/dns/gethoststxt.c +++ b/libc/dns/gethoststxt.c @@ -37,7 +37,7 @@ static struct HostsTxtInitialStaticMemory { } g_hoststxt_init; static textwindows dontinline char *GetNtHostsTxtPath(char *pathbuf, - uint32_t size) { + uint32_t size) { const char *const kWinHostsPath = "\\drivers\\etc\\hosts"; uint32_t len = GetSystemDirectoryA(&pathbuf[0], size); if (len && len + strlen(kWinHostsPath) + 1 < size) { @@ -57,7 +57,7 @@ static textwindows dontinline char *GetNtHostsTxtPath(char *pathbuf, const struct HostsTxt *GetHostsTxt(void) { FILE *f; const char *path; - char pathbuf[PATH_MAX]; + char pathbuf[PATH_MAX + 1]; struct HostsTxtInitialStaticMemory *init; init = &g_hoststxt_init; if (!g_hoststxt) { diff --git a/libc/dns/lookupprotobyname.c b/libc/dns/lookupprotobyname.c index 921cf371d..598f7cb3d 100644 --- a/libc/dns/lookupprotobyname.c +++ b/libc/dns/lookupprotobyname.c @@ -48,10 +48,10 @@ int LookupProtoByName(const char *protoname, char *buf, size_t bufsize, const char *filepath) { FILE *f; char *line; - char pathbuf[PATH_MAX]; const char *path; size_t linesize; int found, result; + char pathbuf[PATH_MAX + 1]; char *name, *number, *alias, *comment, *tok; if (!(path = filepath)) { path = "/etc/protocols"; diff --git a/libc/dns/lookupprotobynumber.c b/libc/dns/lookupprotobynumber.c index 6d455d4e8..935a79cfe 100644 --- a/libc/dns/lookupprotobynumber.c +++ b/libc/dns/lookupprotobynumber.c @@ -52,10 +52,10 @@ int LookupProtoByNumber(const int protonum, char *buf, size_t bufsize, const char *filepath) { FILE *f; char *line; - char pathbuf[PATH_MAX]; - const char *path; - size_t linesize; int found; + size_t linesize; + const char *path; + char pathbuf[PATH_MAX + 1]; char *name, *number, *comment, *tok; if (!(path = filepath)) { path = "/etc/protocols"; diff --git a/libc/dns/lookupservicesbyname.c b/libc/dns/lookupservicesbyname.c index ffefbf45c..bf1bb132c 100644 --- a/libc/dns/lookupservicesbyname.c +++ b/libc/dns/lookupservicesbyname.c @@ -53,10 +53,10 @@ int LookupServicesByName(const char *servname, char *servproto, const char *filepath) { FILE *f; char *line; - char pathbuf[PATH_MAX]; const char *path; size_t linesize; int found, result; + char pathbuf[PATH_MAX + 1]; char *name, *port, *proto, *alias, *comment, *tok; if (!(path = filepath)) { path = "/etc/services"; diff --git a/libc/dns/lookupservicesbyport.c b/libc/dns/lookupservicesbyport.c index 4fa9a364c..301d5d5cf 100644 --- a/libc/dns/lookupservicesbyport.c +++ b/libc/dns/lookupservicesbyport.c @@ -59,7 +59,7 @@ int LookupServicesByPort(const int servport, char *servproto, const char *filepath) { FILE *f; char *line; - char pathbuf[PATH_MAX]; + char pathbuf[PATH_MAX + 1]; const char *path; size_t linesize; int found; diff --git a/libc/fmt/abs.c b/libc/fmt/abs.c index ab4b6b6a8..1baff0057 100644 --- a/libc/fmt/abs.c +++ b/libc/fmt/abs.c @@ -18,6 +18,11 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/fmt/conv.h" -int(abs)(int x) { +/** + * Returns absolute value of 32-bit integer. + * @note `labs(LONG_MIN)` returns `LONG_MIN` unless `-ftrapv` + * @note consider ABS() to avoid narrowing + */ +int abs(int x) { return 0 < x ? x : -x; } diff --git a/libc/fmt/fmt.c b/libc/fmt/fmt.c index 488a10cfb..fec8e214f 100644 --- a/libc/fmt/fmt.c +++ b/libc/fmt/fmt.c @@ -368,9 +368,6 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) { } break; case 'n': - // nonstandard %n specifier - // used to print newlines that work in raw terminal modes - if (__nomultics) __FMT_PUT('\r'); __FMT_PUT('\n'); break; case 'F': diff --git a/libc/fmt/fmt.h b/libc/fmt/fmt.h index 3bc5b89c2..199b004a6 100644 --- a/libc/fmt/fmt.h +++ b/libc/fmt/fmt.h @@ -26,10 +26,6 @@ int sscanf(const char *, const char *, ...) scanfesque(2); int vsscanf(const char *, const char *, va_list); int vcscanf(int (*)(void *), int (*)(int, void *), void *, const char *, va_list); -int strerror_r(int, char *, size_t) dontthrow nocallback; -int strerror_wr(int, uint32_t, char *, size_t) dontthrow nocallback; -const char *strerror_short(int) nosideeffect; -const char *strerror_long(int) nosideeffect; int __fmt(void *, void *, const char *, va_list) hidden; char *itoa(int, char *, int) compatfn; char *fcvt(double, int, int *, int *); diff --git a/libc/fmt/kerrornameslong.S b/libc/fmt/kerrnodocs.S similarity index 97% rename from libc/fmt/kerrornameslong.S rename to libc/fmt/kerrnodocs.S index 127638a41..cd7e86c9e 100644 --- a/libc/fmt/kerrornameslong.S +++ b/libc/fmt/kerrnodocs.S @@ -19,8 +19,8 @@ #include "libc/macros.internal.h" .macro .e e s - .long \e - kErrorNamesLong - .long 1f - kErrorNamesLong + .long \e - kErrnoDocs + .long 1f - kErrnoDocs .rodata.str1.1 1: .asciz "\s" .previous @@ -29,7 +29,7 @@ .section .rodata .align 4 .underrun -kErrorNamesLong: +kErrnoDocs: .e EINVAL,"Invalid argument" .e ENOSYS,"Function not implemented" .e EPERM,"Operation not permitted" @@ -115,6 +115,6 @@ kErrorNamesLong: .e ENOTRECOVERABLE,"State not recoverable" .e ENONET,"Machine is not on the network" .e ERESTART,"Interrupted system call should be restarted" - .long 0 - .endobj kErrorNamesLong,globl,hidden + .long -123 + .endobj kErrnoDocs,globl,hidden .overrun diff --git a/libc/fmt/kerrornames.S b/libc/fmt/kerrnonames.S similarity index 96% rename from libc/fmt/kerrornames.S rename to libc/fmt/kerrnonames.S index 6755891c0..789339e01 100644 --- a/libc/fmt/kerrornames.S +++ b/libc/fmt/kerrnonames.S @@ -19,8 +19,8 @@ #include "libc/macros.internal.h" .macro .e e - .long \e - kErrorNames - .long 1f - kErrorNames + .long \e - kErrnoNames + .long 1f - kErrnoNames .rodata.str1.1 1: .string "\e" .previous @@ -29,7 +29,7 @@ .section .rodata .align 4 .underrun -kErrorNames: +kErrnoNames: .e EINVAL .e ENOSYS .e EPERM @@ -116,6 +116,6 @@ kErrorNames: .e ENONET .e ERESTART .e ENODATA - .long 0 - .endobj kErrorNames,globl,hidden + .long -123 + .endobj kErrnoNames,globl,hidden .overrun diff --git a/libc/fmt/kerrornames.internal.h b/libc/fmt/kerrornames.internal.h deleted file mode 100644 index b8a2636c1..000000000 --- a/libc/fmt/kerrornames.internal.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef COSMOPOLITAN_LIBC_FMT_KERRORNAMES_INTERNAL_H_ -#define COSMOPOLITAN_LIBC_FMT_KERRORNAMES_INTERNAL_H_ -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ - -struct ErrorName { - int x, s; -}; - -extern const struct ErrorName kStrSignal[]; -extern const struct ErrorName kErrorNames[]; -extern const struct ErrorName kErrorNamesLong[]; - -COSMOPOLITAN_C_END_ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_LIBC_FMT_KERRORNAMES_INTERNAL_H_ */ diff --git a/libc/fmt/labs.c b/libc/fmt/labs.c index e3a1d3916..c47c0a361 100644 --- a/libc/fmt/labs.c +++ b/libc/fmt/labs.c @@ -17,8 +17,12 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/fmt/conv.h" -#include "libc/macros.internal.h" -long(labs)(long x) { - return ABS(x); +/** + * Returns absolute value of long integer. + * @note `labs(LONG_MIN)` returns `LONG_MIN` unless `-ftrapv` + * @note consider ABS() to avoid narrowing + */ +long labs(long x) { + return 0 < x ? x : -x; } diff --git a/libc/fmt/llabs.c b/libc/fmt/llabs.c index 5ded9754c..fa1670b13 100644 --- a/libc/fmt/llabs.c +++ b/libc/fmt/llabs.c @@ -17,8 +17,12 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/fmt/conv.h" -#include "libc/macros.internal.h" -long long(llabs)(long long x) { - return ABS(x); +/** + * Returns absolute value of long long integer. + * @note `llabs(LONG_LONG_MIN)` returns `LONG_LONG_MIN` unless `-ftrapv` + * @note consider ABS() to avoid narrowing + */ +long long llabs(long long x) { + return 0 < x ? x : -x; } diff --git a/libc/fmt/magnumstrs.internal.h b/libc/fmt/magnumstrs.internal.h new file mode 100644 index 000000000..e23dfb2ad --- /dev/null +++ b/libc/fmt/magnumstrs.internal.h @@ -0,0 +1,23 @@ +#ifndef COSMOPOLITAN_LIBC_FMT_MAGNUMSTRS_H_ +#define COSMOPOLITAN_LIBC_FMT_MAGNUMSTRS_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +struct MagnumStr { + int x, s; +}; + +extern const struct MagnumStr kErrnoDocs[]; +extern const struct MagnumStr kErrnoNames[]; +extern const struct MagnumStr kIpOptnames[]; +extern const struct MagnumStr kSignalNames[]; +extern const struct MagnumStr kSockOptnames[]; +extern const struct MagnumStr kTcpOptnames[]; + +const char *DescribeSockLevel(int); +const char *DescribeSockOptname(int, int); +const char *GetMagnumStr(const struct MagnumStr *, int); + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_FMT_MAGNUMSTRS_H_ */ diff --git a/libc/fmt/strerror_long.greg.c b/libc/fmt/strerdoc.greg.c similarity index 82% rename from libc/fmt/strerror_long.greg.c rename to libc/fmt/strerdoc.greg.c index c5081970a..abd68b616 100644 --- a/libc/fmt/strerror_long.greg.c +++ b/libc/fmt/strerdoc.greg.c @@ -17,23 +17,16 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/fmt/fmt.h" -#include "libc/fmt/kerrornames.internal.h" +#include "libc/fmt/magnumstrs.internal.h" /** * Converts errno value to descriptive sentence. * @return non-null rodata string or null if not found */ -privileged const char *strerror_long(int x) { - /* kprintf() weakly depends on this function */ - int i; +const char *strerdoc(int x) { if (x) { - for (i = 0; kErrorNamesLong[i].x; ++i) { - if (x == - *(const long *)((uintptr_t)kErrorNamesLong + kErrorNamesLong[i].x)) { - return (const char *)((uintptr_t)kErrorNamesLong + - kErrorNamesLong[i].s); - } - } + return GetMagnumStr(kErrnoDocs, x); + } else { + return 0; } - return 0; } diff --git a/libc/fmt/strerror_short.greg.c b/libc/fmt/strerrno.greg.c similarity index 83% rename from libc/fmt/strerror_short.greg.c rename to libc/fmt/strerrno.greg.c index 5075af526..042ae1942 100644 --- a/libc/fmt/strerror_short.greg.c +++ b/libc/fmt/strerrno.greg.c @@ -16,22 +16,17 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/fmt/fmt.h" -#include "libc/fmt/kerrornames.internal.h" +#include "libc/fmt/magnumstrs.internal.h" +#include "libc/str/str.h" /** * Converts errno value to symbolic name. * @return non-null rodata string or null if not found */ -privileged const char *strerror_short(int x) { - /* kprintf() weakly depends on this function */ - int i; +const char *strerrno(int x) { if (x) { - for (i = 0; kErrorNames[i].x; ++i) { - if (x == *(const int *)((uintptr_t)kErrorNames + kErrorNames[i].x)) { - return (const char *)((uintptr_t)kErrorNames + kErrorNames[i].s); - } - } + return GetMagnumStr(kErrnoNames, x); + } else { + return 0; } - return 0; } diff --git a/libc/fmt/strerror.c b/libc/fmt/strerror.c index 29f9f23fe..8cfefe61b 100644 --- a/libc/fmt/strerror.c +++ b/libc/fmt/strerror.c @@ -23,9 +23,9 @@ * Converts errno value to string non-reentrantly. * @see strerror_r() */ -noasan char *strerror(int err) { +char *strerror(int err) { if (IsTiny()) { - return firstnonnull(strerror_short(err), "EUNKNOWN"); + return firstnonnull(strerrno(err), "EUNKNOWN"); } else { _Alignas(1) static char buf[512]; strerror_r(err, buf, sizeof(buf)); diff --git a/libc/fmt/strerror_r.greg.c b/libc/fmt/strerror_r.greg.c index 22365785b..bec848b21 100644 --- a/libc/fmt/strerror_r.greg.c +++ b/libc/fmt/strerror_r.greg.c @@ -25,6 +25,6 @@ * @param err is error number or zero if unknown * @return 0 on success, or error code */ -privileged int strerror_r(int err, char *buf, size_t size) { +int strerror_r(int err, char *buf, size_t size) { return strerror_wr(err, GetLastError(), buf, size); } diff --git a/libc/fmt/strerror_wr.greg.c b/libc/fmt/strerror_wr.greg.c index b4c795038..dc3d2fc77 100644 --- a/libc/fmt/strerror_wr.greg.c +++ b/libc/fmt/strerror_wr.greg.c @@ -32,13 +32,13 @@ * @param err is error number or zero if unknown * @return 0 on success, or error code */ -privileged int strerror_wr(int err, uint32_t winerr, char *buf, size_t size) { +int strerror_wr(int err, uint32_t winerr, char *buf, size_t size) { /* kprintf() weakly depends on this function */ int c, n; char16_t winmsg[256]; const char *sym, *msg; - sym = firstnonnull(strerror_short(err), "EUNKNOWN"); - msg = firstnonnull(strerror_long(err), "No error information"); + sym = firstnonnull(strerrno(err), "EUNKNOWN"); + msg = firstnonnull(strerdoc(err), "No error information"); if (IsTiny()) { if (!sym) sym = "EUNKNOWN"; for (; (c = *sym++); --size) diff --git a/libc/integral/normalize.inc b/libc/integral/normalize.inc index 489d5a7f4..335a24b9b 100644 --- a/libc/integral/normalize.inc +++ b/libc/integral/normalize.inc @@ -71,7 +71,7 @@ #define CACHELINE 0x40 /* nexgen32e */ #define CHAR_BIT 8 /* b/c von neumann */ #define ARG_MAX 0x8000 /* b/c windows */ -#define PATH_MAX 248 /* b/c win32 apis limit ~248..260 */ +#define PATH_MAX 512 /* b/c bloat */ #define NAME_MAX 63 /* b/c dns */ #define CHILD_MAX 25 /* only if malloc isn't linked */ #define OPEN_MAX 16 /* only if malloc isn't linked */ diff --git a/libc/intrin/asan.c b/libc/intrin/asan.c index aa5a86468..582a59dee 100644 --- a/libc/intrin/asan.c +++ b/libc/intrin/asan.c @@ -59,7 +59,7 @@ STATIC_YOINK("_init_asan"); #define ASAN_MORGUE_ITEMS 512 #define ASAN_MORGUE_THRESHOLD 65536 // morgue memory O(ITEMS*THRESHOLD) -#define ASAN_TRACE_ITEMS 16 // backtrace limit on malloc origin +#define ASAN_TRACE_ITEMS 16 // backtrace limit on malloc origin /** * @fileoverview Cosmopolitan Address Sanitizer Runtime. @@ -102,7 +102,7 @@ STATIC_YOINK("_init_asan"); #define REQUIRE(FUNC) \ do { \ if (!weaken(FUNC)) { \ - kprintf("error: asan needs %s%n", #FUNC); \ + kprintf("error: asan needs %s\n", #FUNC); \ __asan_die()(); \ __asan_unreachable(); \ } \ @@ -179,8 +179,7 @@ static uint64_t __asan_roundup2pow(uint64_t x) { static char *__asan_utf8cpy(char *p, unsigned c) { uint64_t z; z = tpenc(c); - do - *p++ = z; + do *p++ = z; while ((z >>= 8)); return p; } @@ -322,9 +321,9 @@ static char *__asan_hexcpy(char *p, uint64_t x, uint8_t k) { } static void __asan_exit(void) { - kprintf("your asan runtime needs%n" - "\tSTATIC_YOINK(\"__die\");%n" - "in order to show you backtraces%n"); + kprintf("your asan runtime needs\n" + "\tSTATIC_YOINK(\"__die\");\n" + "in order to show you backtraces\n"); __restorewintty(); _Exit(99); } @@ -373,6 +372,7 @@ void __asan_unpoison(long p, long n) { } static bool __asan_is_mapped(int x) { + // xxx: we can't lock because no reentrant locks yet int i; struct MemoryIntervals *m; m = weaken(_mmi); @@ -609,7 +609,7 @@ const char *__asan_describe_access_poison(signed char kind) { dontdiscard static __asan_die_f *__asan_report_invalid_pointer( const void *addr) { - kprintf("%n\e[J\e[1;31masan error\e[0m: this corruption at %p shadow %p%n", + kprintf("\n\e[J\e[1;31masan error\e[0m: this corruption at %p shadow %p\n", addr, SHADOW(addr)); return __asan_die(); } @@ -629,7 +629,6 @@ static char *__asan_format_section(char *p, const void *p1, const void *p2, if (a <= (intptr_t)addr && (intptr_t)addr <= b) { p = __stpcpy(p, " ←address"); } - if (__nomultics) *p++ = '\r'; *p++ = '\n'; } return p; @@ -638,7 +637,7 @@ static char *__asan_format_section(char *p, const void *p1, const void *p2, static void __asan_report_memory_origin_image(intptr_t a, int z) { unsigned l, m, r, n, k; struct SymbolTable *st; - kprintf("%nthe memory belongs to image symbols%n"); + kprintf("\nthe memory belongs to image symbols\n"); if (weaken(GetSymbolTable)) { if ((st = weaken(GetSymbolTable)())) { l = 0; @@ -656,7 +655,7 @@ static void __asan_report_memory_origin_image(intptr_t a, int z) { if ((st->symbols[l].x <= k && k <= st->symbols[l].y) || (st->symbols[l].x <= k + z && k + z <= st->symbols[l].y) || (k < st->symbols[l].x && st->symbols[l].y < k + z)) { - kprintf("\t%s [%#x,%#x] size %'d%n", st->name_base + st->names[l], + kprintf("\t%s [%#x,%#x] size %'d\n", st->name_base + st->names[l], st->addr_base + st->symbols[l].x, st->addr_base + st->symbols[l].y, st->symbols[l].y - st->symbols[l].x + 1); @@ -665,10 +664,10 @@ static void __asan_report_memory_origin_image(intptr_t a, int z) { } } } else { - kprintf("\tunknown please supply .com.dbg symbols or set COMDBG%n"); + kprintf("\tunknown please supply .com.dbg symbols or set COMDBG\n"); } } else { - kprintf("\tunknown please STATIC_YOINK(\"GetSymbolTable\");%n"); + kprintf("\tunknown please STATIC_YOINK(\"GetSymbolTable\");\n"); } } @@ -686,13 +685,13 @@ static noasan void OnMemory(void *x, void *y, size_t n, void *a) { static void __asan_report_memory_origin_heap(const unsigned char *a, int z) { struct ReportOriginHeap t; - kprintf("%nthe memory was allocated by%n"); + kprintf("\nthe memory was allocated by\n"); if (weaken(malloc_inspect_all)) { t.a = a; t.z = z; weaken(malloc_inspect_all)(OnMemory, &t); } else { - kprintf("\tunknown please STATIC_YOINK(\"malloc_inspect_all\");%n"); + kprintf("\tunknown please STATIC_YOINK(\"malloc_inspect_all\");\n"); } } @@ -737,7 +736,7 @@ dontdiscard static __asan_die_f *__asan_report(const void *addr, int size, struct MemoryIntervals *m; ++g_ftrace; p = __fatalbuf; - kprintf("%n\e[J\e[1;31masan error\e[0m: %s %d-byte %s at %p shadow %p%n%s%n", + kprintf("\n\e[J\e[1;31masan error\e[0m: %s %d-byte %s at %p shadow %p\n%s\n", __asan_describe_access_poison(kind), size, message, addr, SHADOW(addr), __argv[0]); if (0 < size && size < 80) { @@ -753,7 +752,6 @@ dontdiscard static __asan_die_f *__asan_report(const void *addr, int size, *p++ = ' '; } } - if (__nomultics) *p++ = '\r'; *p++ = '\n'; for (c = i = 0; i < 80; ++i) { if (!(t = __asan_check(base + i, 1).kind)) { @@ -771,7 +769,6 @@ dontdiscard static __asan_die_f *__asan_report(const void *addr, int size, } } p = __stpcpy(p, "\e[39m"); - if (__nomultics) *p++ = '\r'; *p++ = '\n'; for (i = 0; (intptr_t)(base + i) & 7; ++i) *p++ = ' '; for (; i + 8 <= 80; i += 8) { @@ -788,19 +785,18 @@ dontdiscard static __asan_die_f *__asan_report(const void *addr, int size, } } for (; i < 80; ++i) *p++ = ' '; - if (__nomultics) *p++ = '\r'; *p++ = '\n'; for (i = 0; i < 80; ++i) { p = __asan_utf8cpy(p, __asan_exists(base + i) ? kCp437[((unsigned char *)base)[i]] : L'⋅'); } - if (__nomultics) *p++ = '\r'; *p++ = '\n'; } p = __asan_format_section(p, _base, _etext, ".text", addr); p = __asan_format_section(p, _etext, _edata, ".data", addr); p = __asan_format_section(p, _end, _edata, ".bss", addr); + // xxx: we can't lock because no reentrant locks yet for (m = weaken(_mmi), i = 0; i < m->i; ++i) { x = m->p[i].x; y = m->p[i].y; @@ -809,13 +805,12 @@ dontdiscard static __asan_die_f *__asan_report(const void *addr, int size, if (x <= z && z <= y) p = __stpcpy(p, " ←address"); z = (((intptr_t)addr >> 3) + 0x7fff8000) >> 16; if (x <= z && z <= y) p = __stpcpy(p, " ←shadow"); - if (__nomultics) *p++ = '\r'; *p++ = '\n'; } *p = 0; kprintf("%s", __fatalbuf); __asan_report_memory_origin(addr, size, kind); - kprintf("%nthe crash was caused by%n"); + kprintf("\nthe crash was caused by\n"); --g_ftrace; return __asan_die(); } @@ -924,8 +919,7 @@ static void __asan_trace(struct AsanTrace *bt, const struct StackFrame *bp) { if (!__asan_checka(SHADOW(bp), sizeof(*bp) >> 3).kind) { addr = bp->addr; if (addr == weakaddr("__gc") && weakaddr("__gc")) { - do - --gi; + do --gi; while ((addr = garbage->p[gi].ret) == weakaddr("__gc")); } bt->p[i] = addr; @@ -1018,12 +1012,12 @@ int __asan_print_trace(void *p) { kprintf(" bad cookie"); return -1; } - kprintf("%n%p %,lu bytes [asan]", (char *)p, n); + kprintf("\n%p %,lu bytes [asan]", (char *)p, n); if (!__asan_is_mapped((((intptr_t)p >> 3) + 0x7fff8000) >> 16)) { kprintf(" (shadow not mapped?!)"); } for (i = 0; i < ARRAYLEN(e->bt.p) && e->bt.p[i]; ++i) { - kprintf("%n%*lx %s", 12, e->bt.p[i], + kprintf("\n%*lx %s", 12, e->bt.p[i], weaken(__get_symbol_by_addr) ? weaken(__get_symbol_by_addr)(e->bt.p[i]) : "please STATIC_YOINK(\"__get_symbol_by_addr\")"); @@ -1203,7 +1197,7 @@ void __asan_evil(uint8_t *addr, int size, const char *s1, const char *s2) { struct AsanTrace tr; __asan_rawtrace(&tr, __builtin_frame_address(0)); kprintf( - "WARNING: ASAN error during %s bad %d byte %s at %x bt %x %x %x %x %x%n", + "WARNING: ASAN error during %s bad %d byte %s at %x bt %x %x %x %x %x\n", s1, size, s2, addr, tr.p[0], tr.p[1], tr.p[2], tr.p[3], tr.p[4], tr.p[5]); } @@ -1281,6 +1275,7 @@ void __asan_install_malloc_hooks(void) { } void __asan_map_shadow(uintptr_t p, size_t n) { + // assume _mmi.lock is held void *addr; int i, a, b; size_t size; @@ -1311,7 +1306,7 @@ void __asan_map_shadow(uintptr_t p, size_t n) { m, a, a + i - 1, sm.maphandle, PROT_READ | PROT_WRITE, MAP_PRIVATE | *weaken(MAP_ANONYMOUS) | MAP_FIXED, false, false, 0, size) == -1) { - kprintf("error: could not map asan shadow memory%n"); + kprintf("error: could not map asan shadow memory\n"); __asan_die()(); __asan_unreachable(); } diff --git a/libc/intrin/assertfail.c b/libc/intrin/assertfail.c index ba38f3dc5..1be6fe260 100644 --- a/libc/intrin/assertfail.c +++ b/libc/intrin/assertfail.c @@ -35,12 +35,12 @@ relegated wontreturn void __assert_fail(const char *expr, const char *file, static bool noreentry; __strace = 0; g_ftrace = 0; - kprintf("%s:%d: assert(%s) failed%n", file, line, expr); + kprintf("%s:%d: assert(%s) failed\n", file, line, expr); if (_lockcmpxchg(&noreentry, false, true)) { if (weaken(__die)) { weaken(__die)(); } else { - kprintf("can't backtrace b/c `__die` not linked%n"); + kprintf("can't backtrace b/c `__die` not linked\n"); } rc = 23; } else { diff --git a/libc/intrin/bzero.c b/libc/intrin/bzero.c index c321dc59b..40becb89b 100644 --- a/libc/intrin/bzero.c +++ b/libc/intrin/bzero.c @@ -26,7 +26,7 @@ typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1))); typedef long long xmm_a __attribute__((__vector_size__(16), __aligned__(16))); -noasan static dontinline antiquity void bzero_sse(char *p, size_t n) { +static dontinline antiquity void bzero_sse(char *p, size_t n) { xmm_t v = {0}; if (IsAsan()) __asan_verify(p, n); if (n <= 32) { @@ -43,7 +43,7 @@ noasan static dontinline antiquity void bzero_sse(char *p, size_t n) { } } -noasan microarchitecture("avx") static void bzero_avx(char *p, size_t n) { +microarchitecture("avx") static void bzero_avx(char *p, size_t n) { xmm_t v = {0}; if (IsAsan()) __asan_verify(p, n); if (n <= 32) { diff --git a/libc/intrin/getexitcodeprocess.greg.c b/libc/intrin/getexitcodeprocess.greg.c new file mode 100644 index 000000000..9fd02ea1e --- /dev/null +++ b/libc/intrin/getexitcodeprocess.greg.c @@ -0,0 +1,36 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/internal.h" +#include "libc/calls/strace.internal.h" +#include "libc/nt/accounting.h" +#include "libc/nt/thunk/msabi.h" + +__msabi extern typeof(GetExitCodeProcess) *const __imp_GetExitCodeProcess; + +/** + * Obtains exit code for process. + * @note this wrapper takes care of ABI, STRACE(), and __winerr() + */ +textwindows int32_t GetExitCodeProcess(int64_t hProcess, uint32_t *lpExitCode) { + int32_t rc; + rc = __imp_GetExitCodeProcess(hProcess, lpExitCode); + if (!rc) __winerr(); + NTTRACE("GetExitCodeProcess(%ld, [%u]) → %u% m", hProcess, *lpExitCode, rc); + return rc; +} diff --git a/libc/intrin/getmagnumstr.greg.c b/libc/intrin/getmagnumstr.greg.c new file mode 100644 index 000000000..4be124a29 --- /dev/null +++ b/libc/intrin/getmagnumstr.greg.c @@ -0,0 +1,29 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/fmt/magnumstrs.internal.h" + +const char *GetMagnumStr(const struct MagnumStr *ms, int x) { + int i; + for (i = 0; ms[i].x != -123; ++i) { + if (x == *(const int *)((uintptr_t)ms + ms[i].x)) { + return (const char *)((uintptr_t)ms + ms[i].s); + } + } + return 0; +} diff --git a/libc/intrin/intrin.mk b/libc/intrin/intrin.mk index 77acd0597..02b18b99b 100644 --- a/libc/intrin/intrin.mk +++ b/libc/intrin/intrin.mk @@ -89,9 +89,12 @@ o/$(MODE)/libc/intrin/flushfilebuffers.greg.o \ o/$(MODE)/libc/intrin/terminateprocess.greg.o \ o/$(MODE)/libc/intrin/describemapflags.greg.o \ o/$(MODE)/libc/intrin/getfileattributes.greg.o \ +o/$(MODE)/libc/intrin/getexitcodeprocess.greg.o \ +o/$(MODE)/libc/intrin/waitforsingleobject.greg.o \ o/$(MODE)/libc/intrin/setcurrentdirectory.greg.o \ o/$(MODE)/libc/intrin/mapviewoffileexnuma.greg.o \ o/$(MODE)/libc/intrin/createfilemappingnuma.greg.o \ +o/$(MODE)/libc/intrin/waitformultipleobjects.greg.o \ o/$(MODE)/libc/intrin/generateconsolectrlevent.greg.o \ o/$(MODE)/libc/intrin/kstarttsc.o \ o/$(MODE)/libc/intrin/nomultics.o \ diff --git a/libc/intrin/kdos2errno.S b/libc/intrin/kdos2errno.S index 180d796c6..f09390e7f 100644 --- a/libc/intrin/kdos2errno.S +++ b/libc/intrin/kdos2errno.S @@ -114,7 +114,7 @@ kDos2Errno: .e kNtErrorCrc,EACCES .e kNtErrorDirNotEmpty,ENOTEMPTY .e kNtErrorDupName,EADDRINUSE - .e kNtErrorFilenameExcedRange,ENOENT + .e kNtErrorFilenameExcedRange,ENAMETOOLONG .e kNtErrorGenFailure,EACCES .e kNtErrorGracefulDisconnect,EPIPE .e kNtErrorHostDown,EHOSTUNREACH diff --git a/libc/intrin/kprintf.greg.c b/libc/intrin/kprintf.greg.c index 39d604a92..7ecf44b1b 100644 --- a/libc/intrin/kprintf.greg.c +++ b/libc/intrin/kprintf.greg.c @@ -32,6 +32,7 @@ #include "libc/intrin/nomultics.internal.h" #include "libc/intrin/spinlock.h" #include "libc/limits.h" +#include "libc/log/internal.h" #include "libc/macros.internal.h" #include "libc/nexgen32e/rdtsc.h" #include "libc/nexgen32e/uart.internal.h" @@ -174,6 +175,7 @@ privileged static inline bool kismemtrackhosed(void) { } privileged static bool kismapped(int x) { + // xxx: we can't lock because no reentrant locks yet size_t m, r, l = 0; if (!weaken(_mmi)) return true; if (kismemtrackhosed()) return false; @@ -450,8 +452,7 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt, va_list va, i = 0; m = (1 << base) - 1; if (hash && x) sign = hash; - do - z[i++ & 127] = abet[x & m]; + do z[i++ & 127] = abet[x & m]; while ((x >>= base) || (pdot && i < prec)); goto EmitNumber; @@ -556,11 +557,6 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt, va_list va, case 'n': // nonstandard %n specifier - // used to print newlines that work in raw terminal modes - if (__nomultics) { - if (p < e) *p = '\r'; - ++p; - } if (p < e) *p = '\n'; ++p; break; @@ -569,7 +565,7 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt, va_list va, // undocumented %r specifier // used for good carriage return // helps integrate loggers with repls - if (!__replmode) { + if (!__replmode || __nocolor) { break; } else { s = "\r\033[K"; @@ -845,12 +841,12 @@ privileged size_t kvsnprintf(char *b, size_t n, const char *fmt, va_list v) { */ privileged void kvprintf(const char *fmt, va_list v) { size_t n; - char b[2048]; + char b[4000]; struct Timestamps t; if (!v) return; t = kenter(); n = kformat(b, sizeof(b), fmt, v, t); - klog(b, MIN(n, sizeof(b))); + klog(b, MIN(n, sizeof(b) - 1)); kleave(t); } diff --git a/libc/intrin/memset.c b/libc/intrin/memset.c index 30d8e8f72..b13c61325 100644 --- a/libc/intrin/memset.c +++ b/libc/intrin/memset.c @@ -26,7 +26,7 @@ typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1))); typedef long long xmm_a __attribute__((__vector_size__(16), __aligned__(16))); -noasan static dontinline antiquity void *memset_sse(char *p, char c, size_t n) { +static dontinline antiquity void *memset_sse(char *p, char c, size_t n) { xmm_t v = {c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c}; if (IsAsan()) __asan_verify(p, n); if (n <= 32) { @@ -44,8 +44,7 @@ noasan static dontinline antiquity void *memset_sse(char *p, char c, size_t n) { return p; } -noasan microarchitecture("avx") static void *memset_avx(char *p, char c, - size_t n) { +microarchitecture("avx") static void *memset_avx(char *p, char c, size_t n) { char *t; xmm_t v = {c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c}; if (IsAsan()) __asan_verify(p, n); diff --git a/libc/intrin/nomultics.c b/libc/intrin/nomultics.c index 797465a4b..a02f288c1 100644 --- a/libc/intrin/nomultics.c +++ b/libc/intrin/nomultics.c @@ -17,17 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -/** - * Controls disablement of MULTICS newlines. - * - * Normally we use `\n` for newlines. If this is `true` then we'll try - * our best to use `\r\n`. This is toggled automatically on Windows or - * when `ioctl(TCSETS)` disables `OPOST`. - * - * @see kprintf() - */ -char __nomultics; - /** * Controls ANSI prefix for log emissions. * diff --git a/libc/intrin/nomultics.internal.h b/libc/intrin/nomultics.internal.h index 73298e7d2..50cf641ff 100644 --- a/libc/intrin/nomultics.internal.h +++ b/libc/intrin/nomultics.internal.h @@ -3,7 +3,6 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -extern bool __nomultics; extern bool __replmode; COSMOPOLITAN_C_END_ diff --git a/libc/intrin/onarithmeticoverflow.S b/libc/intrin/onarithmeticoverflow.S index c74d4446e..4e3d1efc2 100644 --- a/libc/intrin/onarithmeticoverflow.S +++ b/libc/intrin/onarithmeticoverflow.S @@ -25,5 +25,6 @@ __on_arithmetic_overflow: push %rbp mov %rsp,%rbp int3 - call abort +0: ud2 + jmp 0b .endfn __on_arithmetic_overflow,weak diff --git a/libc/intrin/ubsan.c b/libc/intrin/ubsan.c index 20c015296..ec357de0f 100644 --- a/libc/intrin/ubsan.c +++ b/libc/intrin/ubsan.c @@ -197,9 +197,9 @@ static wontreturn void __ubsan_unreachable(void) { } static void __ubsan_exit(void) { - kprintf("your ubsan runtime needs%n" - "\tSTATIC_YOINK(\"__die\");%n" - "in order to show you backtraces%n"); + kprintf("your ubsan runtime needs\n" + "\tSTATIC_YOINK(\"__die\");\n" + "in order to show you backtraces\n"); __restorewintty(); _Exit(99); } @@ -214,13 +214,13 @@ dontdiscard static __ubsan_die_f *__ubsan_die(void) { static void __ubsan_warning(const struct UbsanSourceLocation *loc, const char *description) { - kprintf("%s:%d: %subsan warning: %s is undefined behavior%s%n", loc->file, + kprintf("%s:%d: %subsan warning: %s is undefined behavior%s\n", loc->file, loc->line, SUBTLE, description, RESET); } dontdiscard __ubsan_die_f *__ubsan_abort(const struct UbsanSourceLocation *loc, const char *description) { - kprintf("%n%s:%d: %subsan error%s: %s%n", loc->file, loc->line, RED2, RESET, + kprintf("\n%s:%d: %subsan error%s: %s\n", loc->file, loc->line, RED2, RESET, description); return __ubsan_die(); } diff --git a/libc/intrin/waitformultipleobjects.greg.c b/libc/intrin/waitformultipleobjects.greg.c new file mode 100644 index 000000000..2b6aa0be0 --- /dev/null +++ b/libc/intrin/waitformultipleobjects.greg.c @@ -0,0 +1,39 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/internal.h" +#include "libc/calls/strace.internal.h" +#include "libc/nt/synchronization.h" +#include "libc/nt/thunk/msabi.h" + +__msabi extern typeof(WaitForMultipleObjects) *const + __imp_WaitForMultipleObjects; + +/** + * Waits for handles to change status. + * @note this wrapper takes care of ABI, STRACE(), and __winerr() + */ +uint32_t WaitForMultipleObjects(uint32_t nCount, const int64_t *lpHandles, + bool32 bWaitAll, uint32_t dwMilliseconds) { + uint32_t x; + x = __imp_WaitForMultipleObjects(nCount, lpHandles, bWaitAll, dwMilliseconds); + if (x == -1u) __winerr(); + POLLTRACE("WaitForMultipleObjects(%ld, %p, %hhhd, %'d) → %d% m", nCount, + lpHandles, bWaitAll, dwMilliseconds, x); + return x; +} diff --git a/libc/intrin/waitforsingleobject.greg.c b/libc/intrin/waitforsingleobject.greg.c new file mode 100644 index 000000000..d345ef17b --- /dev/null +++ b/libc/intrin/waitforsingleobject.greg.c @@ -0,0 +1,37 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/internal.h" +#include "libc/calls/strace.internal.h" +#include "libc/nt/synchronization.h" +#include "libc/nt/thunk/msabi.h" + +__msabi extern typeof(WaitForSingleObject) *const __imp_WaitForSingleObject; + +/** + * Waits for handle to change status. + * @note this wrapper takes care of ABI, STRACE(), and __winerr() + */ +uint32_t WaitForSingleObject(int64_t hHandle, uint32_t dwMilliseconds) { + uint32_t rc; + rc = __imp_WaitForSingleObject(hHandle, dwMilliseconds); + if (rc == -1u) __winerr(); + POLLTRACE("WaitForSingleObject(%ld, %'d) → %d% m", hHandle, dwMilliseconds, + rc); + return rc; +} diff --git a/libc/log/backtrace2.greg.c b/libc/log/backtrace2.greg.c index 642625fe1..359a7580a 100644 --- a/libc/log/backtrace2.greg.c +++ b/libc/log/backtrace2.greg.c @@ -50,7 +50,7 @@ #define kBacktraceBufSize ((kBacktraceMaxFrames - 1) * (18 + 1)) static void ShowHint(const char *s) { - kprintf("%snote: %s%s%n", SUBTLE, s, RESET); + kprintf("%snote: %s%s\n", SUBTLE, s, RESET); } static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) { @@ -63,8 +63,6 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) { char *debugbin, *p1, *p2, *p3, *addr2line; char buf[kBacktraceBufSize], *argv[kBacktraceMaxFrames]; - return -1; - if (!(debugbin = FindDebugBinary())) { return -1; } @@ -176,8 +174,8 @@ void ShowBacktrace(int fd, const struct StackFrame *bp) { __strace = st; g_ftrace = ft; #else - kprintf("ShowBacktrace() needs these flags to show C backtrace:%n" - "\t-D__FNO_OMIT_FRAME_POINTER__%n" - "\t-fno-omit-frame-pointer%n"); + kprintf("ShowBacktrace() needs these flags to show C backtrace:\n" + "\t-D__FNO_OMIT_FRAME_POINTER__\n" + "\t-fno-omit-frame-pointer\n"); #endif } diff --git a/libc/log/backtrace3.greg.c b/libc/log/backtrace3.greg.c index 24f8d15d1..e1857751e 100644 --- a/libc/log/backtrace3.greg.c +++ b/libc/log/backtrace3.greg.c @@ -56,11 +56,11 @@ noinstrument noasan int PrintBacktraceUsingSymbols(int fd, gi = garbage ? garbage->i : 0; for (i = 0, frame = bp; frame; frame = frame->next) { if (!IsValidStackFramePointer(frame)) { - kprintf("%p corrupt frame pointer%n", frame); + kprintf("%p corrupt frame pointer\n", frame); break; } if (++i == LIMIT) { - kprintf("%n"); + kprintf("\n"); break; } addr = frame->addr; @@ -84,8 +84,8 @@ noinstrument noasan int PrintBacktraceUsingSymbols(int fd, } else { addend = 0; } - kprintf("%012lx %012lx %s%+d\r%n", frame, addr, - __get_symbol_name(st, symbol), addend); + kprintf("%012lx %012lx %s%+d\n", frame, addr, __get_symbol_name(st, symbol), + addend); } return 0; } diff --git a/libc/log/checkfail.c b/libc/log/checkfail.c index 4944b53e9..d98055e7e 100644 --- a/libc/log/checkfail.c +++ b/libc/log/checkfail.c @@ -51,22 +51,22 @@ relegated void __check_fail(const char *suffix, const char *opstr, __start_fatal(file, line); __stpcpy(hostname, "unknown"); gethostname(hostname, sizeof(hostname)); - kprintf("check failed on %s pid %d%n", hostname, getpid()); - kprintf("\tCHECK_%^s(%s, %s);%n", suffix, wantstr, gotstr); - kprintf("\t\t → %p (%s)%n", want, wantstr); - kprintf("\t\t%s %p (%s)%n", opstr, got, gotstr); + kprintf("check failed on %s pid %d\n", hostname, getpid()); + kprintf("\tCHECK_%^s(%s, %s);\n", suffix, wantstr, gotstr); + kprintf("\t\t → %p (%s)\n", want, wantstr); + kprintf("\t\t%s %p (%s)\n", opstr, got, gotstr); if (!isempty(fmt)) { kprintf("\t"); va_start(va, fmt); kvprintf(fmt, va); va_end(va); - kprintf("%n"); + kprintf("\n"); } - kprintf("\t%m%n\t%s%s", SUBTLE, program_invocation_name); + kprintf("\t%m\n\t%s%s", SUBTLE, program_invocation_name); for (i = 1; i < __argc; ++i) { kprintf(" %s", __argv[i]); } - kprintf("%s%n", RESET); + kprintf("%s\n", RESET); if (!IsTiny() && e == ENOMEM) { PrintMemoryIntervals(2, &_mmi); } diff --git a/libc/log/checkfail_ndebug.c b/libc/log/checkfail_ndebug.c index ff313a715..a5a09318d 100644 --- a/libc/log/checkfail_ndebug.c +++ b/libc/log/checkfail_ndebug.c @@ -36,7 +36,7 @@ relegated void ___check_fail_ndebug(uint64_t want, uint64_t got, const char *opchar) { __restore_tty(); - kprintf("%n%serror: %s: check failed: 0x%x %s 0x%x (%s)%n", + kprintf("\n%serror: %s: check failed: 0x%x %s 0x%x (%s)\n", !__nocolor ? "\e[J" : "", program_invocation_name, want, opchar, got, strerror(errno)); __restorewintty(); diff --git a/libc/log/commandvenv.c b/libc/log/commandvenv.c index 5b1f10385..e8fd06130 100644 --- a/libc/log/commandvenv.c +++ b/libc/log/commandvenv.c @@ -47,7 +47,7 @@ */ const char *commandvenv(const char *var, const char *cmd) { const char *exepath; - static char pathbuf[PATH_MAX]; + static char pathbuf[PATH_MAX + 1]; if (*cmd == '/' || *cmd == '\\') return cmd; if ((exepath = getenv(var))) { if (isempty(exepath)) return NULL; @@ -57,5 +57,5 @@ const char *commandvenv(const char *var, const char *cmd) { return NULL; } } - return commandv(cmd, pathbuf); + return commandv(cmd, pathbuf, sizeof(pathbuf)); } diff --git a/libc/log/countexpr_report.c b/libc/log/countexpr_report.c index baba2caec..f3ffbec0b 100644 --- a/libc/log/countexpr_report.c +++ b/libc/log/countexpr_report.c @@ -55,7 +55,7 @@ static void PrintHistogram(const long *h, size_t n, long t) { for (j = 0; j < p / 100; ++j) s[j] = '#'; s[j] = 0; logos = i ? 1ul << (i - 1) : 0; - kprintf("%'12lu %'16ld %3d.%02d%% %s%n", logos, h[i], p / 100, p % 100, + kprintf("%'12lu %'16ld %3d.%02d%% %s\n", logos, h[i], p / 100, p % 100, s); } } diff --git a/libc/log/oncrash.c b/libc/log/oncrash.c index 3bdfc1fd7..b46452bd5 100644 --- a/libc/log/oncrash.c +++ b/libc/log/oncrash.c @@ -63,7 +63,7 @@ relegated static void ShowFunctionCalls(ucontext_t *ctx) { struct StackFrame *bp; struct StackFrame goodframe; if (!ctx->uc_mcontext.rip) { - kprintf("%s is NULL can't show backtrace%n", "RIP"); + kprintf("%s is NULL can't show backtrace\n", "RIP"); } else { goodframe.next = (struct StackFrame *)ctx->uc_mcontext.rbp; goodframe.addr = ctx->uc_mcontext.rip; @@ -114,7 +114,7 @@ relegated static void ShowGeneralRegisters(ucontext_t *ctx) { long double st; char *p, buf[128]; p = buf; - kprintf("%n"); + kprintf("\n"); for (i = 0, j = 0, k = 0; i < ARRAYLEN(kGregNames); ++i) { if (j > 0) *p++ = ' '; if (!(s = kGregNames[(unsigned)kGregOrder[i]])[2]) *p++ = ' '; @@ -135,7 +135,7 @@ relegated static void ShowGeneralRegisters(ucontext_t *ctx) { p = __uintcpy(p, x / 1000), *p++ = '.'; p = __uintcpy(p, x % 1000); *p = 0; - kprintf("%s%n", buf); + kprintf("%s\n", buf); p = buf; } } @@ -143,14 +143,14 @@ relegated static void ShowGeneralRegisters(ucontext_t *ctx) { p, ctx->uc_mcontext.eflags, ctx->uc_mcontext.fpregs ? ctx->uc_mcontext.fpregs->swd : 0, ctx->uc_mcontext.fpregs ? ctx->uc_mcontext.fpregs->mxcsr : 0); - kprintf("%s%n", buf); + kprintf("%s\n", buf); } relegated static void ShowSseRegisters(ucontext_t *ctx) { size_t i; char *p, buf[128]; if (ctx->uc_mcontext.fpregs) { - kprintf("%n"); + kprintf("\n"); for (i = 0; i < 8; ++i) { p = buf; if (i >= 10) { @@ -175,7 +175,7 @@ relegated static void ShowSseRegisters(ucontext_t *ctx) { p = __fixcpy(p, ctx->uc_mcontext.fpregs->xmm[i + 8].u64[1], 64); p = __fixcpy(p, ctx->uc_mcontext.fpregs->xmm[i + 8].u64[0], 64); *p = 0; - kprintf("XMM%s%n", buf); + kprintf("XMM%s\n", buf); } } } @@ -201,10 +201,10 @@ relegated void ShowCrashReport(int err, int sig, struct siginfo *si, uname(&names); p = buf; errno = err; - kprintf("%n%serror%s: Uncaught %G (%s) on %s pid %d%n" - " %s%n" - " %m%n" - " %s %s %s %s%n", + kprintf("\n%serror%s: Uncaught %G (%s) on %s pid %d\n" + " %s\n" + " %m\n" + " %s %s %s %s\n", !__nocolor ? "\e[30;101m" : "", !__nocolor ? "\e[0m" : "", sig, (ctx && (ctx->uc_mcontext.rsp >= GetStaticStackAddr(0) && ctx->uc_mcontext.rsp <= GetStaticStackAddr(0) + PAGESIZE)) @@ -213,12 +213,12 @@ relegated void ShowCrashReport(int err, int sig, struct siginfo *si, host, getpid(), program_invocation_name, names.sysname, names.version, names.nodename, names.release); if (ctx) { - kprintf("%n"); + kprintf("\n"); ShowFunctionCalls(ctx); ShowGeneralRegisters(ctx); ShowSseRegisters(ctx); } - kprintf("%n"); + kprintf("\n"); PrintMemoryIntervals(2, &_mmi); /* PrintSystemMappings(2); */ if (__argv) { @@ -228,7 +228,7 @@ relegated void ShowCrashReport(int err, int sig, struct siginfo *si, kprintf("%s ", __argv[i]); } } - kprintf("%n"); + kprintf("\n"); } relegated static void RestoreDefaultCrashSignalHandlers(void) { @@ -245,14 +245,14 @@ static wontreturn relegated noinstrument void __minicrash(int sig, struct siginfo *si, ucontext_t *ctx, const char *kind) { - kprintf("%n" - "%n" - "CRASHED %s WITH %G%n" - "%s%n" - "RIP %x%n" - "RSP %x%n" - "RBP %x%n" - "%n", + kprintf("\n" + "\n" + "CRASHED %s WITH %G\n" + "%s\n" + "RIP %x\n" + "RSP %x\n" + "RBP %x\n" + "\n", kind, sig, __argv[0], ctx ? ctx->uc_mcontext.rip : 0, ctx ? ctx->uc_mcontext.rsp : 0, ctx ? ctx->uc_mcontext.rbp : 0); __restorewintty(); diff --git a/libc/log/printgarbage.c b/libc/log/printgarbage.c index ac0afdb00..69f0bc574 100644 --- a/libc/log/printgarbage.c +++ b/libc/log/printgarbage.c @@ -30,10 +30,10 @@ void PrintGarbage(void) { size_t i; char name[19]; const char *symbol; - kprintf("%n"); - kprintf(" SHADOW STACK @ %p%n", __builtin_frame_address(0)); - kprintf("garbage ent. parent frame original ret callback arg %n"); - kprintf("------------ ------------ ------------------ ------------------ ------------------%n"); + kprintf("\n"); + kprintf(" SHADOW STACK @ %p\n", __builtin_frame_address(0)); + kprintf("garbage ent. parent frame original ret callback arg \n"); + kprintf("------------ ------------ ------------------ ------------------ ------------------\n"); if (__garbage.i) { for (i = __garbage.i; i--;) { symbol = __get_symbol_by_addr(__garbage.p[i].ret); @@ -42,7 +42,7 @@ void PrintGarbage(void) { } else { ksnprintf(name, sizeof(name), "%#014lx", __garbage.p[i].ret); } - kprintf("%12lx %12lx %18s %18s %#18lx%n", + kprintf("%12lx %12lx %18s %18s %#18lx\n", __garbage.p + i, __garbage.p[i].frame, name, @@ -50,7 +50,7 @@ void PrintGarbage(void) { __garbage.p[i].arg); } } else { - kprintf("%12s %12s %18s %18s %18s%n","empty","-","-","-","-"); + kprintf("%12s %12s %18s %18s %18s\n","empty","-","-","-","-"); } - kprintf("%n"); + kprintf("\n"); } diff --git a/libc/log/vflogf.c b/libc/log/vflogf.c index 64a83772d..ffedd9fac 100644 --- a/libc/log/vflogf.c +++ b/libc/log/vflogf.c @@ -55,7 +55,7 @@ void vflogf_onfail(FILE *f) { fseek(f, SEEK_SET, 0); f->beg = f->end = 0; clearerr(f); - (fprintf)(f, "performed emergency log truncation: %s%n", strerror(err)); + (fprintf)(f, "performed emergency log truncation: %s\n", strerror(err)); } } @@ -105,7 +105,7 @@ void(vflogf)(unsigned level, const char *file, int line, FILE *f, vflogf_onfail(f); } (vfprintf)(f, fmt, va); - fprintf(f, "%n"); + fprintf(f, "\n"); if (bufmode == _IOLBF) { f->bufmode = _IOLBF; fflush(f); @@ -114,7 +114,7 @@ void(vflogf)(unsigned level, const char *file, int line, FILE *f, __start_fatal(file, line); strcpy(buf32, "unknown"); gethostname(buf32, sizeof(buf32)); - (dprintf)(STDERR_FILENO, "fatality %s pid %d%n", buf32, getpid()); + (dprintf)(STDERR_FILENO, "fatality %s pid %d\n", buf32, getpid()); __die(); unreachable; } diff --git a/libc/mem/vasprintf.c b/libc/mem/vasprintf.c index f74ca4251..26ad2fe6c 100644 --- a/libc/mem/vasprintf.c +++ b/libc/mem/vasprintf.c @@ -22,33 +22,36 @@ /** * Formats string w/ dynamic memory allocation. - * - * @param *strp is output-only and must be free'd, even on error; since - * that's the behavior that'll make your code most portable - * @return complete bytes written (excluding NUL) or -1 w/ errno * @see xasprintf() for a better API */ int(vasprintf)(char **strp, const char *fmt, va_list va) { - char *p; - size_t size; va_list vb; + size_t size; + char *p, *p2; int wrote, rc = -1; - if ((*strp = malloc((size = 512)))) { + if ((p = malloc((size = 512)))) { va_copy(vb, va); - wrote = (vsnprintf)(*strp, size, fmt, va); + wrote = (vsnprintf)(p, size, fmt, va); if (wrote < size) { - if ((p = realloc(*strp, wrote + 1))) *strp = p; - rc = wrote; + if ((p2 = realloc(p, wrote + 1))) { + p = p2; + rc = wrote; + } } else { size = wrote + 1; - if ((p = realloc(*strp, size))) { - *strp = p; - wrote = (vsnprintf)(*strp, size, fmt, vb); + if ((p2 = realloc(p, size))) { + p = p2; + wrote = (vsnprintf)(p, size, fmt, vb); assert(wrote == size - 1); rc = wrote; } } va_end(vb); } - return rc; + if (rc != -1) { + *strp = p; + return rc; + } else { + return -1; + } } diff --git a/libc/nt/errors.h b/libc/nt/errors.h index 6a0301d39..da05e1af2 100644 --- a/libc/nt/errors.h +++ b/libc/nt/errors.h @@ -164,7 +164,7 @@ #define kNtErrorInfloopInRelocChain 202 #define kNtErrorEnvvarNotFound 203 #define kNtErrorNoSignalSent 205 -#define kNtErrorFilenameExcedRange 206 +#define kNtErrorFilenameExcedRange 206 /* ENAMETOOLONG */ #define kNtErrorRing2StackInUse 207 #define kNtErrorMetaExpansionTooLong 208 #define kNtErrorInvalidSignalNumber 209 diff --git a/libc/nt/kernel32/GetExitCodeProcess.s b/libc/nt/kernel32/GetExitCodeProcess.s index 78b43b59a..bd7cdc55f 100644 --- a/libc/nt/kernel32/GetExitCodeProcess.s +++ b/libc/nt/kernel32/GetExitCodeProcess.s @@ -2,11 +2,11 @@ .imp kernel32,__imp_GetExitCodeProcess,GetExitCodeProcess,0 .text.windows -GetExitCodeProcess: +__GetExitCodeProcess: push %rbp mov %rsp,%rbp .profilable mov __imp_GetExitCodeProcess(%rip),%rax jmp __sysv2nt - .endfn GetExitCodeProcess,globl + .endfn __GetExitCodeProcess,globl .previous diff --git a/libc/nt/kernel32/WaitForMultipleObjects.s b/libc/nt/kernel32/WaitForMultipleObjects.s index d5bd67864..ec06eccd6 100644 --- a/libc/nt/kernel32/WaitForMultipleObjects.s +++ b/libc/nt/kernel32/WaitForMultipleObjects.s @@ -2,11 +2,11 @@ .imp kernel32,__imp_WaitForMultipleObjects,WaitForMultipleObjects,0 .text.windows -WaitForMultipleObjects: +__WaitForMultipleObjects: push %rbp mov %rsp,%rbp .profilable mov __imp_WaitForMultipleObjects(%rip),%rax jmp __sysv2nt - .endfn WaitForMultipleObjects,globl + .endfn __WaitForMultipleObjects,globl .previous diff --git a/libc/nt/kernel32/WaitForSingleObject.s b/libc/nt/kernel32/WaitForSingleObject.s index 90adca673..61363d463 100644 --- a/libc/nt/kernel32/WaitForSingleObject.s +++ b/libc/nt/kernel32/WaitForSingleObject.s @@ -2,11 +2,11 @@ .imp kernel32,__imp_WaitForSingleObject,WaitForSingleObject,0 .text.windows -WaitForSingleObject: +__WaitForSingleObject: push %rbp mov %rsp,%rbp .profilable mov __imp_WaitForSingleObject(%rip),%rax jmp __sysv2nt - .endfn WaitForSingleObject,globl + .endfn __WaitForSingleObject,globl .previous diff --git a/libc/nt/master.sh b/libc/nt/master.sh index 562cb3c3b..50db7cd24 100755 --- a/libc/nt/master.sh +++ b/libc/nt/master.sh @@ -500,7 +500,6 @@ imp 'GetEnvironmentStringsA' GetEnvironmentStringsA kernel32 0 1 imp 'GetEnvironmentVariable' GetEnvironmentVariableW kernel32 0 3 imp 'GetEnvironmentVariableA' GetEnvironmentVariableA kernel32 0 3 imp 'GetErrorMode' GetErrorMode kernel32 0 -imp 'GetExitCodeProcess' GetExitCodeProcess kernel32 0 2 imp 'GetExitCodeThread' GetExitCodeThread kernel32 0 2 imp 'GetExpandedName' GetExpandedNameW kernel32 579 imp 'GetExpandedNameA' GetExpandedNameA kernel32 578 @@ -1275,9 +1274,7 @@ imp 'VirtualUnlock' VirtualUnlock kernel32 0 imp 'WTSGetActiveConsoleSessionId' WTSGetActiveConsoleSessionId kernel32 1497 imp 'WaitCommEvent' WaitCommEvent kernel32 0 imp 'WaitForDebugEvent' WaitForDebugEvent kernel32 0 -imp 'WaitForMultipleObjects' WaitForMultipleObjects kernel32 0 4 imp 'WaitForMultipleObjectsEx' WaitForMultipleObjectsEx kernel32 0 5 -imp 'WaitForSingleObject' WaitForSingleObject kernel32 0 2 imp 'WaitForSingleObjectEx' WaitForSingleObjectEx kernel32 0 3 imp 'WaitNamedPipe' WaitNamedPipeW kernel32 0 imp 'WaitNamedPipeA' WaitNamedPipeA kernel32 1509 2 @@ -1357,6 +1354,7 @@ imp '__FindNextFile' FindNextFileW kernel32 0 2 imp '__FlushFileBuffers' FlushFileBuffers kernel32 0 1 imp '__FlushViewOfFile' FlushViewOfFile kernel32 0 2 imp '__GenerateConsoleCtrlEvent' GenerateConsoleCtrlEvent kernel32 0 2 +imp '__GetExitCodeProcess' GetExitCodeProcess kernel32 0 2 imp '__GetFileAttributes' GetFileAttributesW kernel32 0 1 imp '__MapViewOfFileEx' MapViewOfFileEx kernel32 0 6 imp '__MapViewOfFileExNuma' MapViewOfFileExNuma kernel32 0 7 @@ -1372,6 +1370,8 @@ imp '__TlsGetValue' TlsGetValue kernel32 0 1 imp '__TlsSetValue' TlsSetValue kernel32 0 2 imp '__UnmapViewOfFile' UnmapViewOfFile kernel32 0 1 imp '__VirtualProtect' VirtualProtect kernel32 0 4 +imp '__WaitForMultipleObjects' WaitForMultipleObjects kernel32 0 4 +imp '__WaitForSingleObject' WaitForSingleObject kernel32 0 2 # ADVAPI32.DLL # diff --git a/libc/nt/thunk/accounting.inc b/libc/nt/thunk/accounting.inc index 860f1f14b..5c1bcbf64 100644 --- a/libc/nt/thunk/accounting.inc +++ b/libc/nt/thunk/accounting.inc @@ -6,6 +6,3 @@ extern typeof(GetThreadTimes) *const __imp_GetThreadTimes __msabi; #define GetUserName(...) __imp_GetUserNameW(__VA_ARGS__) extern typeof(GetUserName) *const __imp_GetUserNameW __msabi; - -#define GetExitCodeProcess(...) __imp_GetExitCodeProcess(__VA_ARGS__) -extern typeof(GetExitCodeProcess) *const __imp_GetExitCodeProcess __msabi; diff --git a/libc/runtime/findcombinary.c b/libc/runtime/findcombinary.c index f780ade4d..ecf7dfc5e 100644 --- a/libc/runtime/findcombinary.c +++ b/libc/runtime/findcombinary.c @@ -24,7 +24,7 @@ struct FindComBinary { bool once; const char *res; - char buf[PATH_MAX]; + char buf[PATH_MAX + 1]; }; static struct FindComBinary g_findcombinary; diff --git a/libc/runtime/internal.h b/libc/runtime/internal.h index 468d0d401..135130d48 100644 --- a/libc/runtime/internal.h +++ b/libc/runtime/internal.h @@ -30,6 +30,7 @@ int GetDosArgv(const char16_t *, char *, size_t, char **, size_t); Elf64_Ehdr *MapElfRead(const char *, struct MappedFile *) hidden; int GetDosEnviron(const char16_t *, char *, size_t, char **, size_t); bool __intercept_flag(int *, char *[], const char *); +int sys_mprotect_nt(void *, size_t, int) hidden; COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/runtime/ismemtracked.greg.c b/libc/runtime/ismemtracked.greg.c index ba0b7b2ee..becbd54aa 100644 --- a/libc/runtime/ismemtracked.greg.c +++ b/libc/runtime/ismemtracked.greg.c @@ -18,7 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/runtime/memtrack.internal.h" -bool IsMemtracked(int x, int y) { +static inline bool IsMemtrackedImpl(int x, int y) { unsigned i; i = FindMemoryInterval(&_mmi, x); if (i == _mmi.i) return false; @@ -29,3 +29,9 @@ bool IsMemtracked(int x, int y) { if (_mmi.p[i].x != _mmi.p[i - 1].y + 1) return false; } } + +bool IsMemtracked(int x, int y) { + bool res; + res = IsMemtrackedImpl(x, y); + return res; +} diff --git a/libc/runtime/memtrack.internal.h b/libc/runtime/memtrack.internal.h index b6ee29e36..ce551b24b 100644 --- a/libc/runtime/memtrack.internal.h +++ b/libc/runtime/memtrack.internal.h @@ -46,6 +46,7 @@ struct MemoryIntervals { size_t i, n; struct MemoryInterval *p; struct MemoryInterval s[OPEN_MAX]; + _Alignas(64) char lock; }; extern hidden struct MemoryIntervals _mmi; diff --git a/libc/runtime/mmap.c b/libc/runtime/mmap.c index 4e5895277..c929999a8 100644 --- a/libc/runtime/mmap.c +++ b/libc/runtime/mmap.c @@ -27,6 +27,7 @@ #include "libc/intrin/asan.internal.h" #include "libc/intrin/describeflags.internal.h" #include "libc/intrin/kprintf.h" +#include "libc/intrin/spinlock.h" #include "libc/limits.h" #include "libc/log/backtrace.internal.h" #include "libc/log/libfatal.internal.h" @@ -198,6 +199,133 @@ static textwindows dontinline noasan void *MapMemories(char *addr, size_t size, return addr; } +static noasan inline void *Mmap(void *addr, size_t size, int prot, int flags, + int fd, int64_t off) { +#if defined(SYSDEBUG) && (_KERNTRACE || _NTTRACE) + if (IsWindows()) { + STRACE("mmap(%p, %'zu, %s, %s, %d, %'ld) → ...", addr, size, + DescribeProtFlags(prot), DescribeMapFlags(flags), fd, off); + } +#endif + char *p = addr; + struct DirectMap dm; + size_t virtualused, virtualneed; + int a, b, i, f, m, n, x; + + if (UNLIKELY(!size)) { + STRACE("size=0"); + return VIP(einval()); + } + + if (UNLIKELY(!IsLegalSize(size))) { + STRACE("size isn't 48-bit"); + return VIP(einval()); + } + + if (UNLIKELY(!IsLegalPointer(p))) { + STRACE("p isn't 48-bit"); + return VIP(einval()); + } + + if (UNLIKELY(!ALIGNED(p))) { + STRACE("p isn't 64kb aligned"); + return VIP(einval()); + } + + if (UNLIKELY(fd < -1)) { + STRACE("mmap(%.12p, %'zu, fd=%d) EBADF", p, size, fd); + return VIP(ebadf()); + } + + if (UNLIKELY(!((fd != -1) ^ !!(flags & MAP_ANONYMOUS)))) { + STRACE("fd anonymous mismatch"); + return VIP(einval()); + } + + if (UNLIKELY(!(!!(flags & MAP_PRIVATE) ^ !!(flags & MAP_SHARED)))) { + STRACE("MAP_SHARED ^ MAP_PRIVATE"); + return VIP(einval()); + } + + if (UNLIKELY(off < 0)) { + STRACE("neg off"); + return VIP(einval()); + } + + if (UNLIKELY(INT64_MAX - size < off)) { + STRACE("too large"); + return VIP(einval()); + } + + if (UNLIKELY(!ALIGNED(off))) { + STRACE("p isn't 64kb aligned"); + return VIP(einval()); + } + + if ((flags & MAP_FIXED_NOREPLACE) && IsMapped(p, size)) { +#ifdef SYSDEBUG + if (OverlapsImageSpace(p, size)) { + STRACE("overlaps image"); + } else { + STRACE("overlaps existing"); + } +#endif + return VIP(efault()); + } + + if (__isfdkind(fd, kFdZip)) { + STRACE("fd is zipos handle"); + return VIP(einval()); + } + + if (__virtualmax < LONG_MAX && + (__builtin_add_overflow((virtualused = GetMemtrackSize(&_mmi)), size, + &virtualneed) || + virtualneed > __virtualmax)) { + STRACE("%'zu size + %'zu inuse exceeds virtual memory limit %'zu", size, + virtualused, __virtualmax); + return VIP(enomem()); + } + + if (fd == -1) { + size = ROUNDUP(size, FRAMESIZE); + if (IsWindows()) { + prot |= PROT_WRITE; /* kludge */ + } + } + + n = (int)(size >> 16) + !!(size & (FRAMESIZE - 1)); + assert(n > 0); + f = (flags & ~MAP_FIXED_NOREPLACE) | MAP_FIXED; + if (flags & MAP_FIXED) { + x = FRAME(p); + if (IsWindows()) { + if (UntrackMemoryIntervals(p, size)) { + OnUnrecoverableMmapError("FIXED UNTRACK FAILED"); + } + } + } else if (!NeedAutomap(p, size)) { + x = FRAME(p); + } else if (!Automap(n, &x)) { + STRACE("AUTOMAP OUT OF MEMORY D:"); + return VIP(enomem()); + } + + p = (char *)ADDR(x); + if (IsOpenbsd() && (f & MAP_GROWSDOWN)) { /* openbsd:dubstack */ + dm = sys_mmap(p, size, prot, f & ~MAP_GROWSDOWN, fd, off); + if (dm.addr == MAP_FAILED) { + return MAP_FAILED; + } + } + + if (!IsWindows()) { + return MapMemory(p, size, prot, flags, fd, off, f, x, n); + } else { + return MapMemories(p, size, prot, flags, fd, off, f, x, n); + } +} + /** * Beseeches system for page-table entries, e.g. * @@ -229,100 +357,10 @@ static textwindows dontinline noasan void *MapMemories(char *addr, size_t size, */ noasan void *mmap(void *addr, size_t size, int prot, int flags, int fd, int64_t off) { -#if defined(SYSDEBUG) && (_KERNTRACE || _NTTRACE) - if (IsWindows()) { - STRACE("mmap(%p, %'zu, %s, %s, %d, %'ld) → ...", addr, size, - DescribeProtFlags(prot), DescribeMapFlags(flags), fd, off); - } -#endif void *res; - char *p = addr; - struct DirectMap dm; - size_t virtualused, virtualneed; - int a, b, i, f, m, n, x; - if (UNLIKELY(!size)) { - STRACE("size=0"); - res = VIP(einval()); - } else if (UNLIKELY(!IsLegalSize(size))) { - STRACE("size isn't 48-bit"); - res = VIP(einval()); - } else if (UNLIKELY(!IsLegalPointer(p))) { - STRACE("p isn't 48-bit"); - res = VIP(einval()); - } else if (UNLIKELY(!ALIGNED(p))) { - STRACE("p isn't 64kb aligned"); - res = VIP(einval()); - } else if (UNLIKELY(fd < -1)) { - STRACE("mmap(%.12p, %'zu, fd=%d) EBADF", p, size, fd); - res = VIP(ebadf()); - } else if (UNLIKELY(!((fd != -1) ^ !!(flags & MAP_ANONYMOUS)))) { - STRACE("fd anonymous mismatch"); - res = VIP(einval()); - } else if (UNLIKELY(!(!!(flags & MAP_PRIVATE) ^ !!(flags & MAP_SHARED)))) { - STRACE("MAP_SHARED ^ MAP_PRIVATE"); - res = VIP(einval()); - } else if (UNLIKELY(off < 0)) { - STRACE("neg off"); - res = VIP(einval()); - } else if (UNLIKELY(INT64_MAX - size < off)) { - STRACE("too large"); - res = VIP(einval()); - } else if (UNLIKELY(!ALIGNED(off))) { - STRACE("p isn't 64kb aligned"); - res = VIP(einval()); - } else if ((flags & MAP_FIXED_NOREPLACE) && IsMapped(p, size)) { -#ifdef SYSDEBUG - if (OverlapsImageSpace(p, size)) { - STRACE("overlaps image"); - } else { - STRACE("overlaps existing"); - } -#endif - res = VIP(efault()); - } else if (__isfdkind(fd, kFdZip)) { - STRACE("fd is zipos handle"); - res = VIP(einval()); - } else if (__virtualmax < LONG_MAX && - (__builtin_add_overflow((virtualused = GetMemtrackSize(&_mmi)), - size, &virtualneed) || - virtualneed > __virtualmax)) { - STRACE("%'zu size + %'zu inuse exceeds virtual memory limit %'zu", size, - virtualused, __virtualmax); - res = VIP(enomem()); - } else { - if (fd == -1) { - size = ROUNDUP(size, FRAMESIZE); - if (IsWindows()) { - prot |= PROT_WRITE; /* kludge */ - } - } - n = (int)(size >> 16) + !!(size & (FRAMESIZE - 1)); - assert(n > 0); - f = (flags & ~MAP_FIXED_NOREPLACE) | MAP_FIXED; - if (flags & MAP_FIXED) { - x = FRAME(p); - if (IsWindows()) { - if (UntrackMemoryIntervals(p, size)) { - OnUnrecoverableMmapError("FIXED UNTRACK FAILED"); - } - } - } else if (!NeedAutomap(p, size)) { - x = FRAME(p); - } else if (!Automap(n, &x)) { - STRACE("AUTOMAP OUT OF MEMORY D:"); - return VIP(enomem()); - } - p = (char *)ADDR(x); - if (IsOpenbsd() && (f & MAP_GROWSDOWN)) { /* openbsd:dubstack */ - dm = sys_mmap(p, size, prot, f & ~MAP_GROWSDOWN, fd, off); - if (dm.addr == MAP_FAILED) res = MAP_FAILED; - } - if (!IsWindows()) { - res = MapMemory(p, size, prot, flags, fd, off, f, x, n); - } else { - res = MapMemories(p, size, prot, flags, fd, off, f, x, n); - } - } + _spinlock(&_mmi.lock); + res = Mmap(addr, size, prot, flags, fd, off); + _spunlock(&_mmi.lock); STRACE("mmap(%p, %'zu, %s, %s, %d, %'ld) → %p% m", addr, size, DescribeProtFlags(prot), DescribeMapFlags(flags), fd, off, res); return res; diff --git a/libc/runtime/mprotect-nt.greg.c b/libc/runtime/mprotect-nt.greg.c new file mode 100644 index 000000000..6c4c58673 --- /dev/null +++ b/libc/runtime/mprotect-nt.greg.c @@ -0,0 +1,63 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/intrin/spinlock.h" +#include "libc/nt/memory.h" +#include "libc/runtime/directmap.internal.h" +#include "libc/runtime/internal.h" +#include "libc/runtime/memtrack.internal.h" + +#define ADDR(x) ((char *)((int64_t)((uint64_t)(x) << 32) >> 16)) + +privileged int sys_mprotect_nt(void *addr, size_t size, int prot) { + int rc = 0; + unsigned i; + uint32_t op; + char *a, *b, *x, *y, *p; + _spinlock(&_mmi.lock); + p = addr; + i = FindMemoryInterval(&_mmi, (intptr_t)p >> 16); + if (i == _mmi.i || (!i && p + size <= ADDR(_mmi.p[0].x))) { + // memory isn't in memtrack + // let's just trust the user then + // it's probably part of the executable + if (!VirtualProtect(addr, size, __prot2nt(prot, false), &op)) { + rc = -1; + } + } else { + // memory is in memtrack, so use memtrack, to do dimensioning + // we unfortunately must do something similar to this for cow + for (; i < _mmi.i; ++i) { + x = ADDR(_mmi.p[i].x); + y = x + _mmi.p[i].size; + if ((x <= p && p < y) || (x < p + size && p + size <= y) || + (p < x && y < p + size)) { + a = MIN(MAX(p, x), y); + b = MAX(MIN(p + size, y), x); + if (!VirtualProtect(a, b - a, __prot2nt(prot, _mmi.p[i].iscow), &op)) { + rc = -1; + break; + } + } else { + break; + } + } + } + _spunlock(&_mmi.lock); + return rc; +} diff --git a/libc/runtime/mprotect.greg.c b/libc/runtime/mprotect.greg.c index 0215270ad..14b27b7db 100644 --- a/libc/runtime/mprotect.greg.c +++ b/libc/runtime/mprotect.greg.c @@ -16,26 +16,16 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/bits/asmflag.h" #include "libc/bits/likely.h" #include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/dce.h" -#include "libc/errno.h" #include "libc/intrin/describeflags.internal.h" -#include "libc/macros.internal.h" -#include "libc/nt/memory.h" -#include "libc/nt/thunk/msabi.h" -#include "libc/runtime/directmap.internal.h" -#include "libc/runtime/memtrack.internal.h" -#include "libc/sysv/consts/nr.h" +#include "libc/runtime/internal.h" +#include "libc/runtime/runtime.h" #include "libc/sysv/consts/prot.h" #include "libc/sysv/errfuns.h" -__msabi extern typeof(VirtualProtect) *const __imp_VirtualProtect; - -#define ADDR(x) ((char *)((int64_t)((uint64_t)(x) << 32) >> 16)) - /** * Modifies restrictions on virtual memory address range. * @@ -44,12 +34,8 @@ __msabi extern typeof(VirtualProtect) *const __imp_VirtualProtect; * @return 0 on success, or -1 w/ errno * @see mmap() */ -noasan noubsan privileged int mprotect(void *addr, size_t size, int prot) { - bool cf; +privileged int mprotect(void *addr, size_t size, int prot) { int64_t rc; - unsigned i; - uint32_t op; - char *a, *b, *x, *y, *p; if (SupportsWindows() && (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC | PROT_GROWSDOWN | PROT_GROWSUP))) { rc = einval(); // unix checks prot before checking size @@ -58,48 +44,9 @@ noasan noubsan privileged int mprotect(void *addr, size_t size, int prot) { } else if (UNLIKELY((intptr_t)addr & 4095)) { rc = einval(); } else if (!IsWindows()) { - asm volatile(CFLAG_ASM("clc\n\tsyscall") - : CFLAG_CONSTRAINT(cf), "=a"(rc) - : "1"(__NR_mprotect), "D"(addr), "S"(size), "d"(prot) - : "rcx", "r11", "memory", "cc"); - if (cf) { - errno = rc; - rc = -1; - } else if (rc > -4096ul) { - errno = -rc; - rc = -1; - } + rc = sys_mprotect(addr, size, prot); } else { - rc = 0; - p = addr; - i = FindMemoryInterval(&_mmi, (intptr_t)p >> 16); - if (i == _mmi.i || (!i && p + size <= ADDR(_mmi.p[0].x))) { - // memory isn't in memtrack - // let's just trust the user then - // it's probably part of the executable - if (!VirtualProtect(addr, size, __prot2nt(prot, false), &op)) { - rc = -1; - } - } else { - // memory is in memtrack, so use memtrack, to do dimensioning - // we unfortunately must do something similar to this for cow - for (; i < _mmi.i; ++i) { - x = ADDR(_mmi.p[i].x); - y = x + _mmi.p[i].size; - if ((x <= p && p < y) || (x < p + size && p + size <= y) || - (p < x && y < p + size)) { - a = MIN(MAX(p, x), y); - b = MAX(MIN(p + size, y), x); - if (!VirtualProtect(a, b - a, __prot2nt(prot, _mmi.p[i].iscow), - &op)) { - rc = -1; - break; - } - } else { - break; - } - } - } + rc = sys_mprotect_nt(addr, size, prot); } STRACE("mprotect(%p, %'zu, %s) → %d% m", addr, size, DescribeProtFlags(prot), rc); diff --git a/libc/runtime/msync-nt.c b/libc/runtime/msync-nt.c index 55fe5895f..22e680587 100644 --- a/libc/runtime/msync-nt.c +++ b/libc/runtime/msync-nt.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" +#include "libc/intrin/spinlock.h" #include "libc/macros.internal.h" #include "libc/nt/files.h" #include "libc/nt/memory.h" @@ -31,6 +32,7 @@ noasan textwindows int sys_msync_nt(char *addr, size_t size, int flags) { int i, rc = 0; char *a, *b, *x, *y; + _spinlock(&_mmi.lock); for (i = FindMemoryInterval(&_mmi, (intptr_t)addr >> 16); i < _mmi.i; ++i) { x = ADDR(_mmi.p[i].x); y = x + _mmi.p[i].size; @@ -47,30 +49,6 @@ noasan textwindows int sys_msync_nt(char *addr, size_t size, int flags) { break; } } + _spunlock(&_mmi.lock); return rc; } - -#if 0 -noasan textwindows int sys_msync_nt(char *addr, size_t size, int flags) { - char *a, *b; - int rc, x, y, l, r, i; - rc = 0; - for (i = FindMemoryInterval(&_mmi, (intptr_t)addr >> 16); i < _mmi.i; ++i) { - if ((ADDR(_mmi.p[i].x) <= addr && addr < ADDR(_mmi.p[i].y + 1)) || - (ADDR(_mmi.p[i].x) < addr + size && - addr + size <= ADDR(_mmi.p[i].y + 1)) || - (addr < ADDR(_mmi.p[i].x) && ADDR(_mmi.p[i].y + 1) < addr + size)) { - a = MIN(MAX(addr, ADDR(_mmi.p[i].x)), ADDR(_mmi.p[i].y + 1)); - b = MAX(MIN(addr + size, ADDR(_mmi.p[i].y + 1)), ADDR(_mmi.p[i].x)); - if (!FlushViewOfFile(a, b - a)) { - rc = -1; - break; - } - // TODO(jart): FlushFileBuffers too on g_fds handle if MS_SYNC? - } else { - break; - } - } - return rc; -} -#endif diff --git a/libc/runtime/munmap.c b/libc/runtime/munmap.c index 47e2a51fe..19146c221 100644 --- a/libc/runtime/munmap.c +++ b/libc/runtime/munmap.c @@ -22,6 +22,7 @@ #include "libc/dce.h" #include "libc/errno.h" #include "libc/intrin/asan.internal.h" +#include "libc/intrin/spinlock.h" #include "libc/log/libfatal.internal.h" #include "libc/macros.internal.h" #include "libc/runtime/directmap.internal.h" @@ -35,6 +36,76 @@ #define ADDR(x) ((int64_t)((uint64_t)(x) << 32) >> 16) #define FRAME(x) ((int)((intptr_t)(x) >> 16)) +static noasan int Munmap(void *v, size_t n) { + char poison, *p = v; + intptr_t a, b, x, y; + assert(!__vforked); + + if (UNLIKELY(!n)) { + STRACE("munmap(%.12p, %'zu) %s (n=0)", p, n); + return einval(); + } + + if (UNLIKELY(!IsLegalSize(n))) { + STRACE("munmap(%.12p, %'zu) EINVAL (n isn't 48-bit)", p, n); + return einval(); + } + + if (UNLIKELY(!IsLegalPointer(p))) { + STRACE("munmap(%.12p, %'zu) EINVAL (p isn't 48-bit)", p, n); + return einval(); + } + + if (UNLIKELY(!IsLegalPointer(p + (n - 1)))) { + STRACE("munmap(%.12p, %'zu) EINVAL (p+(n-1) isn't 48-bit)", p, n); + return einval(); + } + + if (UNLIKELY(!ALIGNED(p))) { + STRACE("munmap(%.12p, %'zu) EINVAL (p isn't 64kb aligned)", p, n); + return einval(); + } + + if (!IsMemtracked(FRAME(p), FRAME(p + (n - 1)))) { + STRACE("munmap(%.12p, %'zu) EFAULT (interval not tracked)", p, n); + return efault(); + } + + if (UntrackMemoryIntervals(p, n) == -1) { + return -1; + } + + if (IsWindows()) { + return 0; // UntrackMemoryIntervals does it for NT + } + + if (sys_munmap(p, n) == -1) { + return -1; // ouch + } + + if (IsAsan() && !OverlapsShadowSpace(p, n)) { + a = ((intptr_t)p >> 3) + 0x7fff8000; + b = a + (n >> 3); + if (IsMemtracked(FRAME(a), FRAME(b - 1))) { + x = ROUNDUP(a, FRAMESIZE); + y = ROUNDDOWN(b, FRAMESIZE); + if (x < y) { + // delete shadowspace if unmapping ≥512kb + __repstosb((void *)a, kAsanUnmapped, x - a); + Munmap((void *)x, y - x); + __repstosb((void *)y, kAsanUnmapped, b - y); + } else { + // otherwise just poison and assume reuse + __repstosb((void *)a, kAsanUnmapped, b - a); + } + } else { + STRACE("unshadow(%.12p, %p) EFAULT", a, b - a); + } + } + + return 0; +} + /** * Releases memory pages. * @@ -49,66 +120,11 @@ * and for files size needs to be perfect to the byte bc openbsd * @return 0 on success, or -1 w/ errno */ -noasan int munmap(void *v, size_t n) { - /* asan runtime depends on this function */ +noasan int munmap(void *p, size_t n) { int rc; - char poison, *p = v; - intptr_t a, b, x, y; - assert(!__vforked); - if (UNLIKELY(!n)) { - STRACE("munmap(%.12p, %'zu) %s (n=0)", p, n); - return einval(); - } - if (UNLIKELY(!IsLegalSize(n))) { - STRACE("munmap(%.12p, %'zu) EINVAL (n isn't 48-bit)", p, n); - return einval(); - } - if (UNLIKELY(!IsLegalPointer(p))) { - STRACE("munmap(%.12p, %'zu) EINVAL (p isn't 48-bit)", p, n); - return einval(); - } - if (UNLIKELY(!IsLegalPointer(p + (n - 1)))) { - STRACE("munmap(%.12p, %'zu) EINVAL (p+(n-1) isn't 48-bit)", p, n); - return einval(); - } - if (UNLIKELY(!ALIGNED(p))) { - STRACE("munmap(%.12p, %'zu) EINVAL (p isn't 64kb aligned)", p, n); - return einval(); - } - if (!IsMemtracked(FRAME(p), FRAME(p + (n - 1)))) { - STRACE("munmap(%.12p, %'zu) EFAULT (interval not tracked)", p, n); - return efault(); - } - if (UntrackMemoryIntervals(p, n) != -1) { - if (!IsWindows()) { - rc = sys_munmap(p, n); - if (rc != -1) { - if (IsAsan() && !OverlapsShadowSpace(p, n)) { - a = ((intptr_t)p >> 3) + 0x7fff8000; - b = a + (n >> 3); - if (IsMemtracked(FRAME(a), FRAME(b - 1))) { - x = ROUNDUP(a, FRAMESIZE); - y = ROUNDDOWN(b, FRAMESIZE); - if (x < y) { - /* delete shadowspace if unmapping ≥512kb */ - __repstosb((void *)a, kAsanUnmapped, x - a); - munmap((void *)x, y - x); - __repstosb((void *)y, kAsanUnmapped, b - y); - } else { - /* otherwise just poison and assume reuse */ - __repstosb((void *)a, kAsanUnmapped, b - a); - } - } else { - STRACE("unshadow(%.12p, %p) EFAULT", a, b - a); - } - } - } - } else { - rc = 0; /* UntrackMemoryIntervals does it for NT */ - } - } else { - rc = -1; - } + _spinlock(&_mmi.lock); + rc = Munmap(p, n); + _spunlock(&_mmi.lock); STRACE("munmap(%.12p, %'zu) → %d% m", p, n, rc); return rc; } diff --git a/libc/runtime/paginate.c b/libc/runtime/paginate.c new file mode 100644 index 000000000..51002f2f5 --- /dev/null +++ b/libc/runtime/paginate.c @@ -0,0 +1,57 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/safemacros.internal.h" +#include "libc/calls/calls.h" +#include "libc/fmt/fmt.h" +#include "libc/runtime/runtime.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/o.h" +#include "libc/x/x.h" + +/** + * Displays wall of text in terminal with pagination. + */ +void __paginate(int fd, const char *s) { + int tfd, pid; + char *args[3] = {0}; + char tmppath[PATH_MAX + 1]; + char progpath[PATH_MAX + 1]; + if (strcmp(nulltoempty(getenv("TERM")), "dumb") && isatty(0) && isatty(1) && + ((args[0] = commandv("less", progpath, sizeof(progpath))) || + (args[0] = commandv("more", progpath, sizeof(progpath))))) { + snprintf(tmppath, sizeof(tmppath), "%s%s-%s-%d.txt", kTmpPath, + program_invocation_short_name, "paginate", getpid()); + if ((tfd = open(tmppath, O_WRONLY | O_CREAT | O_TRUNC, 0644)) != -1) { + write(tfd, s, strlen(s)); + close(tfd); + args[1] = tmppath; + if ((pid = vfork()) != -1) { + if (!pid) { + execv(args[0], args); + _Exit(127); + } + waitpid(pid, 0, 0); + unlink(tmppath); + return; + } + unlink(tmppath); + } + } + write(fd, s, strlen(s)); +} diff --git a/libc/runtime/printargs.greg.c b/libc/runtime/printargs.greg.c index 10e438f7a..322de9e2f 100644 --- a/libc/runtime/printargs.greg.c +++ b/libc/runtime/printargs.greg.c @@ -44,6 +44,7 @@ #include "libc/runtime/stack.h" #include "libc/sock/internal.h" #include "libc/sock/sock.h" +#include "libc/str/str.h" #include "libc/sysv/consts/auxv.h" #include "libc/sysv/consts/f.h" #include "libc/sysv/consts/poll.h" @@ -52,12 +53,13 @@ #include "tool/decode/lib/idname.h" #include "tool/decode/lib/x86idnames.h" +STATIC_YOINK("strerror"); // for kprintf() STATIC_YOINK("strsignal"); // for kprintf() #define PRINT(FMT, ...) \ do { \ kprintf(prologue); \ - kprintf(FMT "%n", ##__VA_ARGS__); \ + kprintf(FMT "\n", ##__VA_ARGS__); \ } while (0) static const struct AuxiliaryValue { @@ -137,8 +139,8 @@ textstartup void __printargs(const char *prologue) { unsigned i, n; uintptr_t *auxp; struct utsname uts; - char path[PATH_MAX]; struct termios termios; + char path[PATH_MAX + 1]; int e, x, st, ft, flags; struct pollfd pfds[128]; struct AuxiliaryValue *auxinfo; @@ -157,7 +159,7 @@ textstartup void __printargs(const char *prologue) { kprintf(" %s", uts.release); } } - kprintf("%n"); + kprintf("\n"); } else { PRINT(" uname() failed %m"); } @@ -177,7 +179,7 @@ textstartup void __printargs(const char *prologue) { FindNameById(kX86GradeNames, getx86processormodel(kX86ProcessorModelKey)->grade)); } - kprintf("%n"); + kprintf("\n"); if ((x = KCPUIDS(16H, EAX) & 0x7fff)) { kprintf(prologue); kprintf(" %dmhz %s", x, "freq"); @@ -187,7 +189,7 @@ textstartup void __printargs(const char *prologue) { if ((x = KCPUIDS(16H, ECX) & 0x7fff)) { kprintf(" / %dmhz %s", x, "bus"); } - kprintf("%n"); + kprintf("\n"); } if (X86_HAVE(HYPERVISOR)) { unsigned eax, ebx, ecx, edx; @@ -203,8 +205,9 @@ textstartup void __printargs(const char *prologue) { PRINT(" L%d%s%s %u-way %,u byte cache w/%s " "%,u sets of %,u byte lines shared across %u threads%s", CPUID4_CACHE_LEVEL, - CPUID4_CACHE_TYPE == 1 ? " data" - : CPUID4_CACHE_TYPE == 2 ? " code" : "", + CPUID4_CACHE_TYPE == 1 ? " data" + : CPUID4_CACHE_TYPE == 2 ? " code" + : "", CPUID4_IS_FULLY_ASSOCIATIVE ? " fully-associative" : "", CPUID4_WAYS_OF_ASSOCIATIVITY, CPUID4_CACHE_SIZE_IN_BYTES, CPUID4_PHYSICAL_LINE_PARTITIONS > 1 ? " physically partitioned" : "", @@ -233,7 +236,7 @@ textstartup void __printargs(const char *prologue) { if (X86_HAVE(RDPID)) kprintf(" RDPID"); if (X86_HAVE(LA57)) kprintf(" LA57"); if (X86_HAVE(FSGSBASE)) kprintf(" FSGSBASE"); - kprintf("%n"); + kprintf("\n"); PRINT(""); PRINT("FILE DESCRIPTORS"); @@ -355,7 +358,7 @@ textstartup void __printargs(const char *prologue) { if (termios.c_iflag & IMAXBEL) kprintf(" IMAXBEL"); if (termios.c_iflag & IUTF8) kprintf(" IUTF8"); if (termios.c_iflag & IUCLC) kprintf(" IUCLC"); - kprintf("%n"); + kprintf("\n"); kprintf(prologue); kprintf(" c_oflag ="); if (termios.c_oflag & OPOST) kprintf(" OPOST"); @@ -408,15 +411,15 @@ textstartup void __printargs(const char *prologue) { } else if ((termios.c_oflag & FFDLY) == FF1) { kprintf(" FF1"); } - kprintf("%n"); + kprintf("\n"); kprintf(prologue); kprintf(" c_cflag ="); - if (termios.c_cflag & ISIG) kprintf(" ISIG"); - if (termios.c_cflag & CSTOPB) kprintf(" CSTOPB"); - if (termios.c_cflag & CREAD) kprintf(" CREAD"); if (termios.c_cflag & PARENB) kprintf(" PARENB"); if (termios.c_cflag & PARODD) kprintf(" PARODD"); + if (termios.c_cflag & CSTOPB) kprintf(" CSTOPB"); + if (termios.c_cflag & PARODD) kprintf(" PARODD"); if (termios.c_cflag & HUPCL) kprintf(" HUPCL"); + if (termios.c_cflag & CREAD) kprintf(" CREAD"); if (termios.c_cflag & CLOCAL) kprintf(" CLOCAL"); if ((termios.c_cflag & CSIZE) == CS5) { kprintf(" CS5"); @@ -427,7 +430,7 @@ textstartup void __printargs(const char *prologue) { } else if ((termios.c_cflag & CSIZE) == CS8) { kprintf(" CS8"); } - kprintf("%n"); + kprintf("\n"); kprintf(prologue); kprintf(" c_lflag ="); if (termios.c_lflag & ISIG) kprintf(" ISIG"); @@ -445,7 +448,7 @@ textstartup void __printargs(const char *prologue) { if (termios.c_lflag & FLUSHO) kprintf(" FLUSHO"); if (termios.c_lflag & PENDIN) kprintf(" PENDIN"); if (termios.c_lflag & XCASE) kprintf(" XCASE"); - kprintf("%n"); + kprintf("\n"); PRINT(" c_ispeed = %u", termios.c_ispeed); PRINT(" c_ospeed = %u", termios.c_ospeed); PRINT(" c_cc[VINTR] = CTRL-%c", CTRL(termios.c_cc[VINTR])); diff --git a/libc/runtime/printmemoryintervals.c b/libc/runtime/printmemoryintervals.c index d3b5ae1db..2fdfebce4 100644 --- a/libc/runtime/printmemoryintervals.c +++ b/libc/runtime/printmemoryintervals.c @@ -54,7 +54,7 @@ void PrintMemoryIntervals(int fd, const struct MemoryIntervals *mm) { if (mm->p[i].h != -1) { kprintf(" h=%ld", mm->p[i].h); } - kprintf("%n"); + kprintf("\n"); } - kprintf("# %ld frames mapped w/ %'ld frames gapped%n", maptally, gaptally); + kprintf("# %ld frames mapped w/ %'ld frames gapped\n", maptally, gaptally); } diff --git a/libc/runtime/runtime.h b/libc/runtime/runtime.h index 0604d98dd..2da6ea692 100644 --- a/libc/runtime/runtime.h +++ b/libc/runtime/runtime.h @@ -104,6 +104,7 @@ long GetMaxFd(void); char *GetProgramExecutableName(void); char *GetInterpreterExecutableName(char *, size_t); void __printargs(const char *); +void __paginate(int, const char *); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/runtime/runtime.mk b/libc/runtime/runtime.mk index db205c38b..1892b2408 100644 --- a/libc/runtime/runtime.mk +++ b/libc/runtime/runtime.mk @@ -69,10 +69,12 @@ o/$(MODE)/libc/runtime/ezmap.o \ o/$(MODE)/libc/runtime/getdosargv.o \ o/$(MODE)/libc/runtime/getdosenviron.o \ o/$(MODE)/libc/runtime/hook.greg.o \ +o/$(MODE)/libc/runtime/mprotect.greg.o \ +o/$(MODE)/libc/runtime/mprotect-nt.greg.o \ +o/$(MODE)/libc/runtime/ismemtracked.greg.o \ o/$(MODE)/libc/runtime/isheap.o \ o/$(MODE)/libc/runtime/memtracknt.o \ o/$(MODE)/libc/runtime/memtrack.greg.o \ -o/$(MODE)/libc/runtime/ismemtracked.greg.o \ o/$(MODE)/libc/runtime/metalprintf.greg.o \ o/$(MODE)/libc/runtime/printargs.greg.o \ o/$(MODE)/libc/runtime/mman.greg.o \ diff --git a/libc/runtime/vfork.S b/libc/runtime/vfork.S index c10080021..b09a0ff36 100644 --- a/libc/runtime/vfork.S +++ b/libc/runtime/vfork.S @@ -94,7 +94,7 @@ vfork.bsd: #ifdef SYSDEBUG .rodata.str1.1 .Llog: .ascii STRACE_PROLOGUE - .asciz "vfork()%n" + .asciz "vfork()\n" .previous #endif /* DEBUGSYS */ diff --git a/libc/runtime/winmain.greg.c b/libc/runtime/winmain.greg.c index 6208d6d69..0ad345803 100644 --- a/libc/runtime/winmain.greg.c +++ b/libc/runtime/winmain.greg.c @@ -55,6 +55,7 @@ #include "libc/runtime/memtrack.internal.h" #include "libc/runtime/runtime.h" #include "libc/sock/internal.h" +#include "libc/str/str.h" #include "libc/str/tpenc.h" #include "libc/str/utf16.h" @@ -120,6 +121,15 @@ forceinline void MakeLongDoubleLongAgain(void) { asm volatile("fldcw\t%0" : /* no outputs */ : "m"(x87cw)); } +static inline size_t StrLen16(const char16_t *s) { + size_t n; + for (n = 0;; ++n) { + if (!s[n]) { + return n; + } + } +} + __msabi static textwindows int OnEarlyWinCrash(struct NtExceptionPointers *ep) { uint32_t wrote; char buf[64], *p = buf; @@ -209,6 +219,9 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) { } } env16 = GetEnvironmentStrings(); + for (char16_t *e = env16; *e; e += StrLen16(e) + 1) { + NTTRACE("GetEnvironmentStrings() → %!#hs", e); + } NTTRACE("WinMainNew() loading environment"); GetDosEnviron(env16, wa->envblock, ARRAYLEN(wa->envblock) - 8, wa->envp, ARRAYLEN(wa->envp) - 1); @@ -257,7 +270,6 @@ __msabi textwindows int64_t WinMain(int64_t hInstance, int64_t hPrevInstance, extern uint64_t ts asm("kStartTsc"); os = WINDOWS; /* madness https://news.ycombinator.com/item?id=21019722 */ ts = rdtsc(); - __nomultics = true; __pid = GetCurrentProcessId(); __wincrashearly = AddVectoredExceptionHandler(1, (void *)OnEarlyWinCrash); cmdline = GetCommandLine(); diff --git a/libc/sock/describesocklevel.greg.c b/libc/sock/describesocklevel.greg.c new file mode 100644 index 000000000..337d6e822 --- /dev/null +++ b/libc/sock/describesocklevel.greg.c @@ -0,0 +1,33 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/fmt/itoa.h" +#include "libc/sysv/consts/sol.h" + +/** + * Describes setsockopt() level arguments. + */ +const char *DescribeSockLevel(int x) { + static char buf[12]; + if (x == SOL_IP) return "SOL_IP"; + if (x == SOL_TCP) return "SOL_TCP"; + if (x == SOL_UDP) return "SOL_UDP"; + if (x == SOL_SOCKET) return "SOL_SOCKET"; + FormatInt32(buf, x); + return buf; +} diff --git a/libc/sock/describesockoptname.greg.c b/libc/sock/describesockoptname.greg.c new file mode 100644 index 000000000..d3f1388fa --- /dev/null +++ b/libc/sock/describesockoptname.greg.c @@ -0,0 +1,45 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/fmt/itoa.h" +#include "libc/fmt/magnumstrs.internal.h" +#include "libc/sysv/consts/sol.h" + +/** + * Describes setsockopt() optname arguments. + */ +const char *DescribeSockOptname(int l, int x) { + int i; + static char buf[12], *s; + const struct MagnumStr *ms = 0; + if (x) { + if (l == SOL_SOCKET) { + ms = kSockOptnames; + } else if (l == SOL_TCP) { + ms = kTcpOptnames; + } else if (l == SOL_IP) { + ms = kIpOptnames; + } + } + if (ms && (s = GetMagnumStr(ms, x))) { + return s; + } else { + FormatInt32(buf, x); + return buf; + } +} diff --git a/libc/sock/getsockopt-nt.c b/libc/sock/getsockopt-nt.c index 49ccc4ee7..0ab21dd1f 100644 --- a/libc/sock/getsockopt-nt.c +++ b/libc/sock/getsockopt-nt.c @@ -17,20 +17,54 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" +#include "libc/bits/bits.h" #include "libc/calls/internal.h" +#include "libc/calls/struct/timeval.h" #include "libc/nt/winsock.h" #include "libc/sock/internal.h" #include "libc/sock/yoink.inc" +#include "libc/str/str.h" +#include "libc/sysv/consts/so.h" +#include "libc/sysv/consts/sol.h" #include "libc/sysv/errfuns.h" textwindows int sys_getsockopt_nt(struct Fd *fd, int level, int optname, - void *out_opt_optval, uint32_t *out_optlen) { - /* TODO(jart): Use WSAIoctl? */ + void *out_opt_optval, + uint32_t *inout_optlen) { + uint64_t ms; + uint32_t in_optlen; assert(fd->kind == kFdSocket); - if (__sys_getsockopt_nt(fd->handle, level, optname, out_opt_optval, - out_optlen) != -1) { - return 0; + + if (out_opt_optval && inout_optlen) { + in_optlen = *inout_optlen; } else { + in_optlen = 0; + } + + // TODO(jart): Use WSAIoctl? + if (__sys_getsockopt_nt(fd->handle, level, optname, out_opt_optval, + inout_optlen) == -1) { return __winsockerr(); } + + if (level == SOL_SOCKET) { + if ((optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) && + in_optlen == sizeof(struct timeval) && + *inout_optlen == sizeof(uint32_t)) { + ms = *(uint32_t *)out_opt_optval; + ((struct timeval *)out_opt_optval)->tv_sec = ms / 1000; + ((struct timeval *)out_opt_optval)->tv_usec = ms % 1000 * 1000; + *inout_optlen = sizeof(struct timeval); + } + } + + if (in_optlen == 4 && *inout_optlen == 1) { + // handle cases like this + // getsockopt(8, SOL_TCP, TCP_FASTOPEN, [u"☺"], [1]) → 0 + int32_t wut = *(signed char *)out_opt_optval; + memcpy(out_opt_optval, &wut, 4); + *inout_optlen = 4; + } + + return 0; } diff --git a/libc/sock/getsockopt.c b/libc/sock/getsockopt.c index 067c05267..d60d8d601 100644 --- a/libc/sock/getsockopt.c +++ b/libc/sock/getsockopt.c @@ -19,6 +19,8 @@ #include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/dce.h" +#include "libc/fmt/magnumstrs.internal.h" +#include "libc/intrin/asan.internal.h" #include "libc/sock/internal.h" #include "libc/sock/sock.h" #include "libc/sysv/errfuns.h" @@ -36,10 +38,15 @@ int getsockopt(int fd, int level, int optname, void *out_opt_optval, uint32_t *out_optlen) { int rc; + if (!level || !optname) { rc = enoprotoopt(); /* our sysvconsts definition */ } else if (optname == -1) { rc = 0; /* our sysvconsts definition */ + } else if (IsAsan() && (out_opt_optval && out_optlen && + (!__asan_is_valid(out_optlen, sizeof(uint32_t)) || + !__asan_is_valid(out_opt_optval, *out_optlen)))) { + rc = efault(); } else if (!IsWindows()) { rc = sys_getsockopt(fd, level, optname, out_opt_optval, out_optlen); } else if (__isfdkind(fd, kFdSocket)) { @@ -48,7 +55,18 @@ int getsockopt(int fd, int level, int optname, void *out_opt_optval, } else { rc = ebadf(); } - STRACE("getsockopt(%d, %#x, %#x, %p, %p) → %d% lm", fd, level, optname, - out_opt_optval, out_optlen, rc); + +#ifdef SYSDEBUG + if (out_opt_optval && out_optlen && rc != -1) { + STRACE("getsockopt(%d, %s, %s, [%#.*hhs], [%d]) → %d% lm", fd, + DescribeSockLevel(level), DescribeSockOptname(level, optname), + *out_optlen, out_opt_optval, *out_optlen, rc); + } else { + STRACE("getsockopt(%d, %s, %s, %p, %p) → %d% lm", fd, + DescribeSockLevel(level), DescribeSockOptname(level, optname), + out_opt_optval, out_optlen, rc); + } +#endif + return rc; } diff --git a/libc/sock/kipoptnames.S b/libc/sock/kipoptnames.S new file mode 100644 index 000000000..4d3c8dae4 --- /dev/null +++ b/libc/sock/kipoptnames.S @@ -0,0 +1,39 @@ +/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ +│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/macros.internal.h" + + .macro .e e + .long \e - kIpOptnames + .long 1f - kIpOptnames + .rodata.str1.1 +1: .string "\e" + .previous + .endm + + .section .rodata + .align 4 + .underrun +kIpOptnames: + .e IP_TOS # int + .e IP_MTU # int + .e IP_TTL # int + .e IP_HDRINCL # bool32 + .long -123 + .endobj kIpOptnames,globl,hidden + .overrun diff --git a/libc/sock/ksockoptnames.S b/libc/sock/ksockoptnames.S new file mode 100644 index 000000000..b56acbffe --- /dev/null +++ b/libc/sock/ksockoptnames.S @@ -0,0 +1,49 @@ +/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ +│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/macros.internal.h" + + .macro .e e + .long \e - kSockOptnames + .long 1f - kSockOptnames + .rodata.str1.1 +1: .string "\e" + .previous + .endm + + .section .rodata + .align 4 + .underrun +kSockOptnames: + .e SO_DEBUG # bool32 + .e SO_BROADCAST # bool32 + .e SO_REUSEADDR # bool32 + .e SO_REUSEPORT # bool32 + .e SO_KEEPALIVE # bool32 + .e SO_DONTROUTE # bool32 + .e SO_RCVTIMEO # timeval + .e SO_SNDTIMEO # timeval + .e SO_LINGER # linger + .e SO_SNDBUF # int + .e SO_RCVBUF # int + .e SO_RCVLOWAT # int + .e SO_SNDLOWAT # int + .e SO_ERROR # int + .long -123 + .endobj kSockOptnames,globl,hidden + .overrun diff --git a/libc/sock/ktcpoptnames.S b/libc/sock/ktcpoptnames.S new file mode 100644 index 000000000..f5d837ae8 --- /dev/null +++ b/libc/sock/ktcpoptnames.S @@ -0,0 +1,48 @@ +/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ +│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/macros.internal.h" + + .macro .e e + .long \e - kTcpOptnames + .long 1f - kTcpOptnames + .rodata.str1.1 +1: .string "\e" + .previous + .endm + + .section .rodata + .align 4 + .underrun +kTcpOptnames: + .e TCP_NODELAY # bool32 + .e TCP_CORK # bool32 + .e TCP_QUICKACK # bool32 + .e TCP_FASTOPEN_CONNECT # bool32 + .e TCP_DEFER_ACCEPT # bool32 + .e TCP_KEEPIDLE # int (seconds) + .e TCP_KEEPINTVL # int (seconds) + .e TCP_FASTOPEN # int + .e TCP_KEEPCNT # int + .e TCP_MAXSEG # int + .e TCP_SYNCNT # int + .e TCP_NOTSENT_LOWAT # int + .e TCP_WINDOW_CLAMP # int + .long -123 + .endobj kTcpOptnames,globl,hidden + .overrun diff --git a/libc/sock/recvmsg.c b/libc/sock/recvmsg.c index 137b6e74f..c688f808f 100644 --- a/libc/sock/recvmsg.c +++ b/libc/sock/recvmsg.c @@ -88,7 +88,7 @@ ssize_t recvmsg(int fd, struct msghdr *msg, int flags) { if (msg->msg_flags) kprintf(".flags=%#x, ", msg->msg_flags); kprintf(".iov=", fd); __strace_iov(msg->msg_iov, msg->msg_iovlen, rc != -1 ? rc : 0); - kprintf("}], %#x) → %'ld% m%n", flags, rc); + kprintf("}], %#x) → %'ld% m\n", flags, rc); } } #endif diff --git a/libc/sock/sendmsg.c b/libc/sock/sendmsg.c index d338ded3e..3c8545229 100644 --- a/libc/sock/sendmsg.c +++ b/libc/sock/sendmsg.c @@ -90,7 +90,7 @@ ssize_t sendmsg(int fd, const struct msghdr *msg, int flags) { if (msg->msg_flags) kprintf(".flags=%#x, ", msg->msg_flags); kprintf(".iov=", fd); __strace_iov(msg->msg_iov, msg->msg_iovlen, rc != -1 ? rc : 0); - kprintf("}, %#x) → %'ld% m%n", flags, rc); + kprintf("}, %#x) → %'ld% m\n", flags, rc); } } #endif diff --git a/libc/sock/setsockopt-nt.c b/libc/sock/setsockopt-nt.c index ed31ffda5..24c753517 100644 --- a/libc/sock/setsockopt-nt.c +++ b/libc/sock/setsockopt-nt.c @@ -17,9 +17,11 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/struct/timeval.h" +#include "libc/limits.h" #include "libc/macros.internal.h" #include "libc/sock/internal.h" #include "libc/sysv/consts/so.h" +#include "libc/sysv/consts/sol.h" #include "libc/sysv/errfuns.h" struct linger_nt { /* Linux+XNU+BSD ABI */ @@ -29,27 +31,34 @@ struct linger_nt { /* Linux+XNU+BSD ABI */ textwindows int sys_setsockopt_nt(struct Fd *fd, int level, int optname, const void *optval, uint32_t optlen) { + int64_t ms; struct timeval *tv; struct linger *linger; union { uint32_t millis; struct linger_nt linger; - } nt; + } u; - if (optname == SO_LINGER && optval && optlen == sizeof(struct linger)) { - linger = optval; - nt.linger.l_onoff = linger->l_onoff; - nt.linger.l_linger = MIN(0xFFFF, MAX(0, linger->l_linger)); - optval = &nt.linger; - optlen = sizeof(nt.linger); - } - - if ((optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) && optval && - optlen == sizeof(struct timeval)) { - tv = optval; - nt.millis = MIN(0xFFFFFFFF, MAX(0, tv->tv_sec * 1000 + tv->tv_usec / 1000)); - optval = &nt.millis; - optlen = sizeof(nt.millis); + if (level == SOL_SOCKET) { + if (optname == SO_LINGER && optval && optlen == sizeof(struct linger)) { + linger = optval; + u.linger.l_onoff = linger->l_onoff; + u.linger.l_linger = MIN(0xFFFF, MAX(0, linger->l_linger)); + optval = &u.linger; + optlen = sizeof(u.linger); + } else if ((optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) && optval && + optlen == sizeof(struct timeval)) { + tv = optval; + if (__builtin_mul_overflow(tv->tv_sec, 1000, &ms) || + __builtin_add_overflow(ms, tv->tv_usec / 1000, &ms) || + (ms < 0 || ms > 0xffffffff)) { + u.millis = 0xffffffff; + } else { + u.millis = ms; + } + optval = &u.millis; + optlen = sizeof(u.millis); + } } if (__sys_setsockopt_nt(fd->handle, level, optname, optval, optlen) != -1) { diff --git a/libc/sock/setsockopt.c b/libc/sock/setsockopt.c index a9e831b48..c66b078eb 100644 --- a/libc/sock/setsockopt.c +++ b/libc/sock/setsockopt.c @@ -20,6 +20,8 @@ #include "libc/calls/strace.internal.h" #include "libc/dce.h" #include "libc/errno.h" +#include "libc/fmt/magnumstrs.internal.h" +#include "libc/intrin/asan.internal.h" #include "libc/nt/winsock.h" #include "libc/sock/internal.h" #include "libc/sock/sock.h" @@ -52,12 +54,12 @@ static bool setsockopt_polyfill(int *optname) { int setsockopt(int fd, int level, int optname, const void *optval, uint32_t optlen) { int e, rc; - if (!optval) { + + if (!optname) { + rc = enosys(); /* see libc/sysv/consts.sh */ + } else if ((!optval && optlen) || + (IsAsan() && !__asan_is_valid(optval, optlen))) { rc = efault(); - } else if (!level || !optname) { - rc = enoprotoopt(); /* our sysvconsts definition */ - } else if (optname == -1) { - rc = 0; /* our sysvconsts definition */ } else if (!IsWindows()) { rc = -1; e = errno; @@ -73,7 +75,18 @@ int setsockopt(int fd, int level, int optname, const void *optval, } else { rc = ebadf(); } - STRACE("setsockopt(%d, %#x, %#x, %p, %'u) → %d% lm", fd, level, optname, - optval, optlen, rc); + +#ifdef SYSDEBUG + if (!(rc == -1 && errno == EFAULT)) { + STRACE("setsockopt(%d, %s, %s, %#.*hhs, %'u) → %d% lm", fd, + DescribeSockLevel(level), DescribeSockOptname(level, optname), + optlen, optval, optlen, rc); + } else { + STRACE("setsockopt(%d, %s, %s, %p, %'u) → %d% lm", fd, + DescribeSockLevel(level), DescribeSockOptname(level, optname), + optval, optlen, rc); + } +#endif + return rc; } diff --git a/libc/sock/sock.mk b/libc/sock/sock.mk index e8d40fa58..4ffe02852 100644 --- a/libc/sock/sock.mk +++ b/libc/sock/sock.mk @@ -9,10 +9,16 @@ LIBC_SOCK_A = o/$(MODE)/libc/sock/sock.a LIBC_SOCK_A_FILES := $(wildcard libc/sock/*) LIBC_SOCK_A_HDRS = $(filter %.h,$(LIBC_SOCK_A_FILES)) LIBC_SOCK_A_INCS = $(filter %.inc,$(LIBC_SOCK_A_FILES)) -LIBC_SOCK_A_SRCS = $(filter %.c,$(LIBC_SOCK_A_FILES)) +LIBC_SOCK_A_SRCS_C = $(filter %.c,$(LIBC_SOCK_A_FILES)) +LIBC_SOCK_A_SRCS_S = $(filter %.S,$(LIBC_SOCK_A_FILES)) + +LIBC_SOCK_A_SRCS = \ + $(LIBC_SOCK_A_SRCS_C) \ + $(LIBC_SOCK_A_SRCS_S) LIBC_SOCK_A_OBJS = \ - $(LIBC_SOCK_A_SRCS:%.c=o/$(MODE)/%.o) + $(LIBC_SOCK_A_SRCS_C:%.c=o/$(MODE)/%.o) \ + $(LIBC_SOCK_A_SRCS_S:%.S=o/$(MODE)/%.o) LIBC_SOCK_A_CHECKS = \ $(LIBC_SOCK_A).pkg \ diff --git a/libc/sock/sockdebug.c b/libc/sock/sockdebug.c index aa9351f53..ff52cf07b 100644 --- a/libc/sock/sockdebug.c +++ b/libc/sock/sockdebug.c @@ -48,6 +48,10 @@ const char *__describe_socket_type(int type) { p = stpcpy(p, "SOCK_DGRAM"); } else if (x == SOCK_RAW) { p = stpcpy(p, "SOCK_RAW"); + } else if (x == SOCK_RDM) { + p = stpcpy(p, "SOCK_RDM"); + } else if (x == SOCK_SEQPACKET) { + p = stpcpy(p, "SOCK_SEQPACKET"); } else { p = FormatInt32(p, x); } diff --git a/libc/stdio/printf.c b/libc/stdio/printf.c index 54e3a2cf3..5dcffa13a 100644 --- a/libc/stdio/printf.c +++ b/libc/stdio/printf.c @@ -32,10 +32,6 @@ * - `%m` inserts strerror(errno) into the formatted output. This is * consistent with glibc, musl, and uclibc. * - * - `%n` inserts "\n" on non-Windows and "\r\n" on Windows. This is the - * same behavior as Java. It's incompatible with glibc's behavior, - * since that's problematic according to Android's security team. - * * - `%hs` converts UTF-16/UCS-2 → UTF-8, which can be helpful on Windows. * Formatting (e.g. %-10hs) will use monospace display width rather * than string length or codepoint count. diff --git a/libc/stdio/spawn.c b/libc/stdio/spawn.c index 2ec52e244..13ae5af10 100644 --- a/libc/stdio/spawn.c +++ b/libc/stdio/spawn.c @@ -40,7 +40,7 @@ int posix_spawn(int *pid, const char *path, unsigned mode; sigset_t allsigs; struct sigaction dfl; - char *p, *q, opath[PATH_MAX]; + char *p, *q, opath[PATH_MAX + 1]; int s, fd, newfd, oflag, tempfd; if (!(*pid = vfork())) { if (attrp) { @@ -77,7 +77,7 @@ int posix_spawn(int *pid, const char *path, if (sscanf(p + 5, "%d,", &fd) != 1) _Exit(127); p = strchr(p, ',') + 1; q = strchr(p, '*'); - if (!q || q - p + 1 > PATH_MAX) _Exit(127); + if (!q || q - p > PATH_MAX) _Exit(127); strncpy(opath, p, q - p); opath[q - p] = '\0'; if (sscanf(q + 1, "%o,%o)", &oflag, &mode) != 2) _Exit(127); diff --git a/libc/stdio/spawnp.c b/libc/stdio/spawnp.c index 2191b3c99..d6b62614e 100644 --- a/libc/stdio/spawnp.c +++ b/libc/stdio/spawnp.c @@ -31,7 +31,7 @@ int posix_spawnp(int *pid, const char *path, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const argv[], char *const envp[]) { - char pathbuf[PATH_MAX]; - if (!(path = commandv(path, pathbuf))) return errno; + char pathbuf[PATH_MAX + 1]; + if (!(path = commandv(path, pathbuf, sizeof(pathbuf)))) return errno; return posix_spawn(pid, path, file_actions, attrp, argv, envp); } diff --git a/libc/stdio/tmpfile.c b/libc/stdio/tmpfile.c index 67e54721a..d4c886338 100644 --- a/libc/stdio/tmpfile.c +++ b/libc/stdio/tmpfile.c @@ -32,11 +32,11 @@ */ FILE *tmpfile(void) { int fd; - char *tmp, *sep, tpl[PATH_MAX]; + char *tmp, *sep, tpl[PATH_MAX + 1]; tmp = firstnonnull(getenv("TMPDIR"), kTmpPath); sep = !isempty(tmp) && !endswith(tmp, "/") ? "/" : ""; - if ((snprintf)(tpl, PATH_MAX, "%s%stmp.%s.XXXXXX", tmp, sep, - program_invocation_short_name) < PATH_MAX) { + if ((snprintf)(tpl, PATH_MAX + 1, "%s%stmp.%s.XXXXXX", tmp, sep, + program_invocation_short_name) <= PATH_MAX) { if ((fd = mkostemps(tpl, 0, 0)) != -1) { return fdopen(fd, "w+"); } diff --git a/libc/str/kstrsignal.S b/libc/str/ksignalnames.S similarity index 95% rename from libc/str/kstrsignal.S rename to libc/str/ksignalnames.S index 838354752..5939eb3e9 100644 --- a/libc/str/kstrsignal.S +++ b/libc/str/ksignalnames.S @@ -19,8 +19,8 @@ #include "libc/macros.internal.h" .macro .e e s - .long \e - kStrSignal - .long 1f - kStrSignal + .long \e - kSignalNames + .long 1f - kSignalNames .rodata.str1.1 1: .string "\s" .previous @@ -29,7 +29,7 @@ .section .rodata .align 4 .underrun -kStrSignal: +kSignalNames: .e SIGHUP,"HUP" .e SIGINT,"INT" .e SIGQUIT,"QUIT" @@ -65,6 +65,6 @@ kStrSignal: .e SIGRTMIN,"RTMIN" .e SIGEMT,"EMT" .e SIGPWR,"PWR" - .long 0 - .endobj kStrSignal,globl,hidden + .long -123 + .endobj kSignalNames,globl,hidden .overrun diff --git a/libc/str/qsort.c b/libc/str/qsort.c index d280a394b..d0f112e07 100644 --- a/libc/str/qsort.c +++ b/libc/str/qsort.c @@ -53,7 +53,7 @@ static inline int pntz(size_t p[2]) { return 0; } -/* smoothsort_shl() and smoothsort_shr() need n > 0 */ +// smoothsort_shl() and smoothsort_shr() need n > 0 static inline void smoothsort_shl(size_t p[2], int n) { if (n >= CHAR_BIT * sizeof(size_t)) { n -= CHAR_BIT * sizeof(size_t); @@ -163,7 +163,7 @@ static void smoothsort(struct SmoothSort *s, void *base, size_t nel, if (!size) return; head = base; high = head + size - width; - /* Precompute Leonardo numbers, scaled by element width */ + // precompute Leonardo numbers, scaled by element width for (s->lp[0] = s->lp[1] = width, i = 2; (s->lp[i] = s->lp[i - 2] + s->lp[i - 1] + width) < size; i++) { } diff --git a/libc/str/str.h b/libc/str/str.h index 3b06b430b..6ec97a339 100644 --- a/libc/str/str.h +++ b/libc/str/str.h @@ -192,7 +192,6 @@ wchar_t *wmempcpy(wchar_t *, const wchar_t *, size_t) memcpyesque; wchar_t *wmemmove(wchar_t *, const wchar_t *, size_t) memcpyesque; void *tinymemccpy(void *, const void *, int, size_t) memcpyesque; void *memmem(const void *, size_t, const void *, size_t) libcesque nosideeffect; -char *strerror(int) returnsnonnull dontthrow nocallback; long a64l(const char *); char *l64a(long); @@ -262,14 +261,12 @@ wint_t towctrans(wint_t, wctrans_t); ╚────────────────────────────────────────────────────────────────────────────│*/ char *strsignal(int) returnsnonnull libcesque; +char *strerror(int) returnsnonnull dontthrow nocallback; +const char *strerrno(int) nosideeffect libcesque; +const char *strerdoc(int) nosideeffect libcesque; +int strerror_r(int, char *, size_t) dontthrow nocallback; +int strerror_wr(int, uint32_t, char *, size_t) dontthrow nocallback; -#if defined(__GNUC__) && !defined(__STRICT_ANSI__) -/* gcc rewrites to memset otherwise :'( */ -void __bzero(void *, size_t) asm("bzero") memcpyesque; -#define bzero(DEST, SIZE) \ - ((void)((__builtin_constant_p(SIZE)) ? memset(DEST, 0, SIZE) \ - : __bzero(DEST, SIZE))) -#endif /* __GNUC__ && !__STRICT_ANSI__ */ COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_LIBC_STR_STR_H_ */ diff --git a/libc/str/strsignal.c b/libc/str/strsignal.c index 7b4283462..ea6b0868f 100644 --- a/libc/str/strsignal.c +++ b/libc/str/strsignal.c @@ -17,7 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/bits.h" -#include "libc/fmt/kerrornames.internal.h" +#include "libc/fmt/magnumstrs.internal.h" #include "libc/macros.internal.h" #include "libc/str/str.h" @@ -35,15 +35,12 @@ static char g_strsignal[12]; * @see sigaction() */ char *strsignal(int sig) { - int i; + const char *s; strcpy(g_strsignal, "SIG"); if (sig) { - for (i = 0; kStrSignal[i].x; ++i) { - if (sig == *(const int *)((uintptr_t)kStrSignal + kStrSignal[i].x)) { - strcpy(g_strsignal + 3, - (const char *)((uintptr_t)kStrSignal + kStrSignal[i].s)); - return g_strsignal; - } + if ((s = GetMagnumStr(kSignalNames, sig))) { + strcpy(g_strsignal + 3, s); + return g_strsignal; } } if (!sig) { diff --git a/libc/sysv/calls/setregid.s b/libc/sysv/calls/setregid.s deleted file mode 100644 index 7daa7a16a..000000000 --- a/libc/sysv/calls/setregid.s +++ /dev/null @@ -1,2 +0,0 @@ -.include "o/libc/sysv/macros.internal.inc" -.scall setregid,0x07f07f07f207f072,globl diff --git a/libc/sysv/calls/setreuid.s b/libc/sysv/calls/setreuid.s deleted file mode 100644 index e0b88ab32..000000000 --- a/libc/sysv/calls/setreuid.s +++ /dev/null @@ -1,2 +0,0 @@ -.include "o/libc/sysv/macros.internal.inc" -.scall setreuid,0x07e07e07e207e071,globl diff --git a/libc/sysv/calls/sys_setregid.s b/libc/sysv/calls/sys_setregid.s new file mode 100644 index 000000000..8b42b154a --- /dev/null +++ b/libc/sysv/calls/sys_setregid.s @@ -0,0 +1,2 @@ +.include "o/libc/sysv/macros.internal.inc" +.scall sys_setregid,0x07f07f07f207f072,globl,hidden diff --git a/libc/sysv/calls/sys_setreuid.s b/libc/sysv/calls/sys_setreuid.s new file mode 100644 index 000000000..a3f3fc5b3 --- /dev/null +++ b/libc/sysv/calls/sys_setreuid.s @@ -0,0 +1,2 @@ +.include "o/libc/sysv/macros.internal.inc" +.scall sys_setreuid,0x07e07e07e207e071,globl,hidden diff --git a/libc/sysv/consts.sh b/libc/sysv/consts.sh index ddace70e8..48fec094f 100755 --- a/libc/sysv/consts.sh +++ b/libc/sysv/consts.sh @@ -685,7 +685,6 @@ syscon so SO_RCVBUF 8 0x1002 0x1002 0x1002 0x1002 0x1002 # bsd co syscon so SO_RCVTIMEO 20 0x1006 0x1006 0x1006 0x100c 0x1006 # recv timeout; takes struct timeval (overrides SA_RESTART restoring EINTR behavior on recv/send/connect/accept/etc.; bsd consensus) syscon so SO_SNDTIMEO 21 0x1005 0x1005 0x1005 0x100b 0x1005 # send timeout; takes struct timeval; bsd consensus syscon so SO_RCVLOWAT 18 0x1004 0x1004 0x1004 0x1004 0x1004 # bsd consensus -syscon so SO_EXCLUSIVEADDRUSE 0 0 0 0 0 0xfffffffb # hoo boy syscon so SO_SNDLOWAT 19 0x1003 0x1003 0x1003 0x1003 0x1003 # bsd consensus syscon so SO_TYPE 3 0x1008 0x1008 0x1008 0x1008 0x1008 # bsd consensus syscon so SO_TIMESTAMP 29 0x0400 0x0400 0x0800 0x2000 0 @@ -693,6 +692,7 @@ syscon so SO_SETFIB 0 0 0x1014 0 0 0 syscon so SO_DOMAIN 39 0 0x1019 0x1024 0 0 syscon so SO_MAX_PACING_RATE 47 0 0x1018 0 0 0 syscon so SO_PEERCRED 17 0 0 0x1022 0 0 +syscon so SO_EXCLUSIVEADDRUSE 0 0 0 0 0 0xfffffffb # hoo boy syscon so LOCAL_PEERCRED 0 1 1 0 0 0 syscon so SO_PROTOCOL 38 0 0x1016 0x1025 0 0 syscon so SO_ATTACH_BPF 50 0 0 0 0 0 @@ -730,9 +730,10 @@ syscon so SO_TIMESTAMPNS 35 0 0 0 0 0 syscon so SO_WIFI_STATUS 41 0 0 0 0 0 syscon sol SOL_IP 0 0 0 0 0 0 # consensus -syscon sol SOL_SOCKET 1 0xffff 0xffff 0xffff 0xffff 0xffff # bsd+nt consensus (todo: what's up with ipproto_icmp overlap) +syscon sol SOL_SOCKET 1 0xffff 0xffff 0xffff 0xffff 0xffff # yes it's actually 0xffff; bsd+nt consensus (todo: what's up with ipproto_icmp overlap) syscon sol SOL_TCP 6 6 6 6 6 6 # consensus syscon sol SOL_UDP 17 17 17 17 17 17 # consensus +syscon sol SOL_RAW 255 0 0 0 0 0 syscon sol SOL_IPV6 41 41 41 41 41 41 syscon sol SOL_ICMPV6 58 58 58 58 58 0 syscon sol SOL_AAL 265 0 0 0 0 0 @@ -752,7 +753,6 @@ syscon sol SOL_NFC 280 0 0 0 0 0 syscon sol SOL_PACKET 263 0 0 0 0 0 syscon sol SOL_PNPIPE 275 0 0 0 0 0 syscon sol SOL_PPPOL2TP 273 0 0 0 0 0 -syscon sol SOL_RAW 255 0 0 0 0 0 syscon sol SOL_RDS 276 0 0 0 0 0 syscon sol SOL_RXRPC 272 0 0 0 0 0 syscon sol SOL_TIPC 271 0 0 0 0 0 @@ -808,13 +808,14 @@ syscon tcp TCP_REPAIR_QUEUE 20 0 0 0 0 0 # what is it syscon tcp TCP_THIN_LINEAR_TIMEOUTS 16 0 0 0 0 0 # what is it # group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary +syscon ip IP_TOS 1 3 3 3 3 8 # bsd consensus +syscon ip IP_TTL 2 4 4 4 4 7 # bsd consensus +syscon ip IP_HDRINCL 3 2 2 2 2 2 # bsd consensus syscon ip IP_DEFAULT_MULTICAST_LOOP 1 1 1 1 1 1 # consensus syscon ip IP_DEFAULT_MULTICAST_TTL 1 1 1 1 1 1 # consensus syscon ip IP_PMTUDISC_DONT 0 0 0 0 0 0 # consensus -syscon ip IP_HDRINCL 3 2 2 2 2 2 # bsd consensus syscon ip IP_MAX_MEMBERSHIPS 20 0x0fff 0x0fff 0x0fff 0x0fff 20 # bsd consensus syscon ip IP_OPTIONS 4 1 1 1 1 1 # bsd consensus -syscon ip IP_TOS 1 3 3 3 3 8 # bsd consensus syscon ip IP_RECVTTL 12 24 65 31 23 21 syscon ip IP_ADD_MEMBERSHIP 35 12 12 12 12 5 # bsd consensus syscon ip IP_DROP_MEMBERSHIP 36 13 13 13 13 6 # bsd consensus @@ -825,7 +826,6 @@ syscon ip IP_RECVOPTS 6 5 5 5 5 0 # bsd consensus syscon ip IP_RECVRETOPTS 7 6 6 6 6 0 # bsd consensus syscon ip IP_RECVDSTADDR 0 7 7 7 7 0 # bsd consensus syscon ip IP_RETOPTS 7 8 8 8 8 0 # bsd consensus -syscon ip IP_TTL 2 4 4 4 4 7 # bsd consensus syscon ip IP_ADD_SOURCE_MEMBERSHIP 39 70 70 0 0 15 syscon ip IP_BLOCK_SOURCE 38 72 72 0 0 17 syscon ip IP_DROP_SOURCE_MEMBERSHIP 40 71 71 0 0 0x10 @@ -1367,6 +1367,25 @@ syscon termios ENDRUNDISC 0 0 0 0x9 0x9 0 # boop syscon termios TIOCPTMASTER 0 0 0x2000741c 0 0 0 # boop syscon termios NETGRAPHDISC 0 0 0x6 0 0 0 # boop syscon termios H4DISC 0 0 0x7 0 0 0 # boop + +# Teletypewriter Control Modes +# +# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary +syscon termios CS5 0b0000000000000000 0b000000000000000000 0b000000000000000000 0b0000000000000000 0b0000000000000000 0b0000000000000000 # termios.c_cflag; consensus +syscon termios CS6 0b0000000000010000 0b000000000100000000 0b000000000100000000 0b0000000100000000 0b0000000100000000 0b0000000000010000 # termios.c_cflag; 6-bit characters +syscon termios CS7 0b0000000000100000 0b000000001000000000 0b000000001000000000 0b0000001000000000 0b0000001000000000 0b0000000000100000 # termios.c_cflag; 7-bit characters +syscon termios CS8 0b0000000000110000 0b000000001100000000 0b000000001100000000 0b0000001100000000 0b0000001100000000 0b0000000000110000 # termios.c_cflag; 8-bit characters +syscon termios CSIZE 0b0000000000110000 0b000000001100000000 0b000000001100000000 0b0000001100000000 0b0000001100000000 0b0000000000110000 # termios.c_cflag; mask for CS𝑥 flags +syscon termios CSTOPB 0b0000000001000000 0b000000010000000000 0b000000010000000000 0b0000010000000000 0b0000010000000000 0b0000000001000000 # termios.c_cflag; bsd consensus +syscon termios CREAD 0b0000000010000000 0b000000100000000000 0b000000100000000000 0b0000100000000000 0b0000100000000000 0b0000000010000000 # termios.c_cflag; bsd consensus +syscon termios PARENB 0b0000000100000000 0b000001000000000000 0b000001000000000000 0b0001000000000000 0b0001000000000000 0b0000000100000000 # termios.c_cflag +syscon termios PARODD 0b0000001000000000 0b000010000000000000 0b000010000000000000 0b0010000000000000 0b0010000000000000 0b0000001000000000 # termios.c_cflag +syscon termios HUPCL 0b0000010000000000 0b000100000000000000 0b000100000000000000 0b0100000000000000 0b0100000000000000 0b0000010000000000 # termios.c_cflag; bsd consensus +syscon termios CLOCAL 0b0000100000000000 0b1000000000000000 0b1000000000000000 0b1000000000000000 0b1000000000000000 0b0000100000000000 # termios.c_cflag; consensus + +# Teletypewriter Local Modes +# +# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary syscon termios ISIG 0b0000000000000001 0b0000000010000000 0b0000000010000000 0b0000000010000000 0b0000000010000000 0b0000000000000001 # termios.c_lflag|=ISIG makes Ctrl-C, Ctrl-\, etc. generate signals syscon termios ICANON 0b0000000000000010 0b0000000100000000 0b0000000100000000 0b0000000100000000 0b0000000100000000 0b0000000000000010 # termios.c_lflag&=~ICANON disables 1960's version of gnu readline (see also VMIN) syscon termios XCASE 0b0000000000000100 0 0 16777216 0 0b0000000000000100 # termios.c_lflag @@ -1383,6 +1402,10 @@ syscon termios FLUSHO 0b0001000000000000 8388608 8388608 8388608 83886 syscon termios PENDIN 0b0100000000000000 536870912 536870912 536870912 536870912 0b0100000000000000 # termios.c_lflag syscon termios IEXTEN 0b1000000000000000 0b0000010000000000 0b0000010000000000 0b0000010000000000 0b0000010000000000 0b1000000000000000 # termios.c_lflag&=~IEXTEN disables platform input processing magic syscon termios EXTPROC 65536 0b0000100000000000 0b0000100000000000 0b0000100000000000 0b0000100000000000 65536 # termios.c_lflag + +# Teletypewriter Input Modes +# +# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary syscon termios IGNBRK 0b0000000000000001 0b0000000000000001 0b0000000000000001 0b0000000000000001 0b0000000000000001 0b0000000000000001 # termios.c_iflag it's complicated, uart only? UNIXCONSENSUS syscon termios BRKINT 0b0000000000000010 0b0000000000000010 0b0000000000000010 0b0000000000000010 0b0000000000000010 0b0000000000000010 # termios.c_iflag it's complicated, uart only? UNIXCONSENSUS syscon termios IGNPAR 0b0000000000000100 0b0000000000000100 0b0000000000000100 0b0000000000000100 0b0000000000000100 0b0000000000000100 # termios.c_iflag|=IGNPAR ignores parity and framing errors; see PARMRK UNIXCONSENSUS @@ -1398,9 +1421,13 @@ syscon termios IXANY 0b0000100000000000 0b0000100000000000 0b000010000000000 syscon termios IXOFF 0b0001000000000000 0b0000010000000000 0b0000010000000000 0b0000010000000000 0b0000010000000000 0b0001000000000000 # termios.c_iflag|=IXOFF disables annoying display freeze keys syscon termios IMAXBEL 0b0010000000000000 0b0010000000000000 0b0010000000000000 0b0010000000000000 0b0010000000000000 0b0010000000000000 # termios.c_iflag|=IMAXBEL rings when queue full UNIXCONSENSUS syscon termios IUTF8 0b0100000000000000 0b0100000000000000 0 0 0 0b0100000000000000 # termios.c_iflag|=IUTF8 helps w/ rubout on UTF-8 input + +# Teletypewriter Output Modes +# +# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary syscon termios OPOST 0b0000000000000001 0b000000000000000001 0b000000000000000001 0b0000000000000001 0b0000000000000001 0b0000000000000001 # termios.c_oflag&=~OPOST disables output processing magic, e.g. MULTICS newlines syscon termios OLCUC 0b0000000000000010 0 0 0b0000000000100000 0 0b0000000000000010 # termios.c_oflag|=OLCUC maps a-z → A-Z output -syscon termios ONLCR 0b0000000000000100 0b000000000000000010 0b000000000000000010 0b0000000000000010 0b0000000000000010 0b0000000000000100 # termios.c_oflag|=ONLCR claims to map \n → \r\n output +syscon termios ONLCR 0b0000000000000100 0b000000000000000010 0b000000000000000010 0b0000000000000010 0b0000000000000010 0b0000000000000100 # termios.c_oflag|=ONLCR map \n → \r\n output (MULTICS newline) and requires OPOST syscon termios OCRNL 0b0000000000001000 0b000000000000010000 0b000000000000010000 0b0000000000010000 0b0000000000010000 0b0000000000001000 # termios.c_oflag|=OCRNL maps \r → \n output syscon termios ONOCR 0b0000000000010000 0b000000000000100000 0b000000000000100000 0b0000000001000000 0b0000000001000000 0b0000000000010000 # termios.c_oflag|=ONOCR maps \r → ∅ output iff column 0 syscon termios ONLRET 0b0000000000100000 0b000000000001000000 0b000000000001000000 0b0000000010000000 0b0000000010000000 0b0000000000100000 # termios.c_oflag|=ONLRET maps \r → ∅ output @@ -1431,11 +1458,10 @@ syscon termios VT1 0b0100000000000000 0b010000000000000000 0b0100000000000 syscon termios FFDLY 0b1000000000000000 0b000100000000000000 0b000100000000000000 0 0 0b1000000000000000 # termios.c_oflag syscon termios FF0 0b0000000000000000 0b000000000000000000 0b000000000000000000 0 0 0b0000000000000000 # termios.c_oflag syscon termios FF1 0b1000000000000000 0b000100000000000000 0b000100000000000000 0 0 0b1000000000000000 # termios.c_oflag -syscon termios CS5 0 0 0 0 0 0 # consensus -syscon termios CS6 0b0000000000010000 0b0000000100000000 0b0000000100000000 0b0000000100000000 0b0000000100000000 0b0000000000010000 # termios.c_cflag flag for 6-bit characters -syscon termios CS7 0b0000000000100000 0b0000001000000000 0b0000001000000000 0b0000001000000000 0b0000001000000000 0b0000000000100000 # termios.c_cflag flag for 7-bit characters -syscon termios CS8 0b0000000000110000 0b0000001100000000 0b0000001100000000 0b0000001100000000 0b0000001100000000 0b0000000000110000 # termios.c_cflag flag for 8-bit characters -syscon termios CSIZE 0b0000000000110000 0b0000001100000000 0b0000001100000000 0b0000001100000000 0b0000001100000000 0b0000000000110000 # mask for CS𝑥 flags + +# Teletypewriter Special Control Character Assignments +# +# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary syscon termios NCCS 20 20 20 20 20 20 # ARRAYLEN(termios.c_cc); we schlep c_line into c_cc on linux syscon termios VINTR 0+1 8 8 8 8 0 # termios.c_cc[VINTR]=𝑥 syscon termios VQUIT 1+1 9 9 9 9 1 # termios.c_cc[VQUIT]=𝑥 @@ -1454,15 +1480,13 @@ syscon termios VDISCARD 13+1 15 15 15 15 13 # termios.c_cc[VDISCA syscon termios VWERASE 14+1 4 4 4 4 14 # termios.c_cc[VWERASE]=𝑥 syscon termios VLNEXT 15+1 14 14 14 14 15 # termios.c_cc[VLNEXT]=𝑥 syscon termios VEOL2 16+1 2 2 2 2 16 # termios.c_cc[VEOL2]=𝑥 + syscon termios TIOCSERGETLSR 0x5459 0 0 0 0 0 # syscon termios TIOCSERGETMULTI 0x545a 0 0 0 0 0 # syscon termios TIOCSERSETMULTI 0x545b 0 0 0 0 0 # syscon termios TIOCSER_TEMT 1 0 0 0 0 0 # syscon termios VERIFY 47 0 0 0 0 0 -syscon termios PARENB 0x0100 0x1000 0x1000 0x1000 0x1000 0 # -syscon termios PARODD 0x0200 0x2000 0x2000 0x2000 0x2000 0 # syscon termios CIBAUD 0x100f0000 0 0 0 0 0 -syscon termios CLOCAL 0x0800 0x8000 0x8000 0x8000 0x8000 0 # syscon termios CMSPAR 0x40000000 0 0 0 0 0 syscon termios BUSY 4 0 0 0 0 0 syscon termios CANBSIZ 255 0 0 0 0 0 @@ -1488,9 +1512,6 @@ syscon termios TCOON 1 2 2 2 2 1 # see tcflow; bsd consensus syscon termios TCIOFF 2 3 3 3 3 2 # see tcflow; bsd consensus syscon termios TCION 3 4 4 4 4 3 # see tcflow; bsd consensus -syscon termios CREAD 0x80 0x0800 0x0800 0x0800 0x0800 0 # bsd consensus -syscon termios CSTOPB 0x40 0x0400 0x0400 0x0400 0x0400 0 # bsd consensus -syscon termios HUPCL 0x0400 0x4000 0x4000 0x4000 0x4000 0 # bsd consensus syscon termios CSTART 17 17 17 17 17 0 # unix consensus syscon termios CSTOP 19 19 19 19 19 0 # unix consensus diff --git a/libc/sysv/consts/CLOCAL.S b/libc/sysv/consts/CLOCAL.S index 73bdc0a62..d9bcd3c33 100644 --- a/libc/sysv/consts/CLOCAL.S +++ b/libc/sysv/consts/CLOCAL.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon termios,CLOCAL,0x0800,0x8000,0x8000,0x8000,0x8000,0 +.syscon termios,CLOCAL,0b0000100000000000,0b1000000000000000,0b1000000000000000,0b1000000000000000,0b1000000000000000,0b0000100000000000 diff --git a/libc/sysv/consts/CREAD.S b/libc/sysv/consts/CREAD.S index 1eac14cd8..e18ada92d 100644 --- a/libc/sysv/consts/CREAD.S +++ b/libc/sysv/consts/CREAD.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon termios,CREAD,0x80,0x0800,0x0800,0x0800,0x0800,0 +.syscon termios,CREAD,0b0000000010000000,0b000000100000000000,0b000000100000000000,0b0000100000000000,0b0000100000000000,0b0000000010000000 diff --git a/libc/sysv/consts/CS5.S b/libc/sysv/consts/CS5.S index 01a9b5895..ac9704d4c 100644 --- a/libc/sysv/consts/CS5.S +++ b/libc/sysv/consts/CS5.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon termios,CS5,0,0,0,0,0,0 +.syscon termios,CS5,0b0000000000000000,0b000000000000000000,0b000000000000000000,0b0000000000000000,0b0000000000000000,0b0000000000000000 diff --git a/libc/sysv/consts/CS6.S b/libc/sysv/consts/CS6.S index f5031010e..4b5329830 100644 --- a/libc/sysv/consts/CS6.S +++ b/libc/sysv/consts/CS6.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon termios,CS6,0b0000000000010000,0b0000000100000000,0b0000000100000000,0b0000000100000000,0b0000000100000000,0b0000000000010000 +.syscon termios,CS6,0b0000000000010000,0b000000000100000000,0b000000000100000000,0b0000000100000000,0b0000000100000000,0b0000000000010000 diff --git a/libc/sysv/consts/CS7.S b/libc/sysv/consts/CS7.S index d4fb534a7..923e5982c 100644 --- a/libc/sysv/consts/CS7.S +++ b/libc/sysv/consts/CS7.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon termios,CS7,0b0000000000100000,0b0000001000000000,0b0000001000000000,0b0000001000000000,0b0000001000000000,0b0000000000100000 +.syscon termios,CS7,0b0000000000100000,0b000000001000000000,0b000000001000000000,0b0000001000000000,0b0000001000000000,0b0000000000100000 diff --git a/libc/sysv/consts/CS8.S b/libc/sysv/consts/CS8.S index 08ad827a8..21784475b 100644 --- a/libc/sysv/consts/CS8.S +++ b/libc/sysv/consts/CS8.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon termios,CS8,0b0000000000110000,0b0000001100000000,0b0000001100000000,0b0000001100000000,0b0000001100000000,0b0000000000110000 +.syscon termios,CS8,0b0000000000110000,0b000000001100000000,0b000000001100000000,0b0000001100000000,0b0000001100000000,0b0000000000110000 diff --git a/libc/sysv/consts/CSIZE.S b/libc/sysv/consts/CSIZE.S index 90372e69c..59abbeb63 100644 --- a/libc/sysv/consts/CSIZE.S +++ b/libc/sysv/consts/CSIZE.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon termios,CSIZE,0b0000000000110000,0b0000001100000000,0b0000001100000000,0b0000001100000000,0b0000001100000000,0b0000000000110000 +.syscon termios,CSIZE,0b0000000000110000,0b000000001100000000,0b000000001100000000,0b0000001100000000,0b0000001100000000,0b0000000000110000 diff --git a/libc/sysv/consts/CSTOPB.S b/libc/sysv/consts/CSTOPB.S index 0e8700592..5374da0e4 100644 --- a/libc/sysv/consts/CSTOPB.S +++ b/libc/sysv/consts/CSTOPB.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon termios,CSTOPB,0x40,0x0400,0x0400,0x0400,0x0400,0 +.syscon termios,CSTOPB,0b0000000001000000,0b000000010000000000,0b000000010000000000,0b0000010000000000,0b0000010000000000,0b0000000001000000 diff --git a/libc/sysv/consts/HUPCL.S b/libc/sysv/consts/HUPCL.S index dd03f7ab0..6d27a2fb8 100644 --- a/libc/sysv/consts/HUPCL.S +++ b/libc/sysv/consts/HUPCL.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon termios,HUPCL,0x0400,0x4000,0x4000,0x4000,0x4000,0 +.syscon termios,HUPCL,0b0000010000000000,0b000100000000000000,0b000100000000000000,0b0100000000000000,0b0100000000000000,0b0000010000000000 diff --git a/libc/sysv/consts/PARENB.S b/libc/sysv/consts/PARENB.S index 2a40e7dc4..9900cf43b 100644 --- a/libc/sysv/consts/PARENB.S +++ b/libc/sysv/consts/PARENB.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon termios,PARENB,0x0100,0x1000,0x1000,0x1000,0x1000,0 +.syscon termios,PARENB,0b0000000100000000,0b000001000000000000,0b000001000000000000,0b0001000000000000,0b0001000000000000,0b0000000100000000 diff --git a/libc/sysv/consts/PARODD.S b/libc/sysv/consts/PARODD.S index 0ef8fff7a..1cfe04b15 100644 --- a/libc/sysv/consts/PARODD.S +++ b/libc/sysv/consts/PARODD.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon termios,PARODD,0x0200,0x2000,0x2000,0x2000,0x2000,0 +.syscon termios,PARODD,0b0000001000000000,0b000010000000000000,0b000010000000000000,0b0010000000000000,0b0010000000000000,0b0000001000000000 diff --git a/libc/sysv/consts/so.h b/libc/sysv/consts/so.h index e3ec79d74..3c61cf7a0 100644 --- a/libc/sysv/consts/so.h +++ b/libc/sysv/consts/so.h @@ -1,69 +1,6 @@ #ifndef COSMOPOLITAN_LIBC_SYSV_CONSTS_SO_H_ #define COSMOPOLITAN_LIBC_SYSV_CONSTS_SO_H_ #include "libc/runtime/symbolic.h" - -#define LOCAL_PEERCRED SYMBOLIC(LOCAL_PEERCRED) -#define SO_ACCEPTCONN SYMBOLIC(SO_ACCEPTCONN) -#define SO_ATTACH_BPF SYMBOLIC(SO_ATTACH_BPF) -#define SO_ATTACH_FILTER SYMBOLIC(SO_ATTACH_FILTER) -#define SO_ATTACH_REUSEPORT_CBPF SYMBOLIC(SO_ATTACH_REUSEPORT_CBPF) -#define SO_ATTACH_REUSEPORT_EBPF SYMBOLIC(SO_ATTACH_REUSEPORT_EBPF) -#define SO_BINDTODEVICE SYMBOLIC(SO_BINDTODEVICE) -#define SO_BPF_EXTENSIONS SYMBOLIC(SO_BPF_EXTENSIONS) -#define SO_BROADCAST SYMBOLIC(SO_BROADCAST) -#define SO_BSDCOMPAT SYMBOLIC(SO_BSDCOMPAT) -#define SO_BUSY_POLL SYMBOLIC(SO_BUSY_POLL) -#define SO_CNX_ADVICE SYMBOLIC(SO_CNX_ADVICE) -#define SO_DEBUG SYMBOLIC(SO_DEBUG) -#define SO_DETACH_BPF SYMBOLIC(SO_DETACH_BPF) -#define SO_DETACH_FILTER SYMBOLIC(SO_DETACH_FILTER) -#define SO_DOMAIN SYMBOLIC(SO_DOMAIN) -#define SO_DONTROUTE SYMBOLIC(SO_DONTROUTE) -#define SO_ERROR SYMBOLIC(SO_ERROR) -#define SO_EXCLUSIVEADDRUSE SYMBOLIC(SO_EXCLUSIVEADDRUSE) -#define SO_GET_FILTER SYMBOLIC(SO_GET_FILTER) -#define SO_INCOMING_CPU SYMBOLIC(SO_INCOMING_CPU) -#define SO_KEEPALIVE SYMBOLIC(SO_KEEPALIVE) -#define SO_LINGER SYMBOLIC(SO_LINGER) -#define SO_LOCK_FILTER SYMBOLIC(SO_LOCK_FILTER) -#define SO_MARK SYMBOLIC(SO_MARK) -#define SO_MAX_PACING_RATE SYMBOLIC(SO_MAX_PACING_RATE) -#define SO_NOFCS SYMBOLIC(SO_NOFCS) -#define SO_NO_CHECK SYMBOLIC(SO_NO_CHECK) -#define SO_OOBINLINE SYMBOLIC(SO_OOBINLINE) -#define SO_PASSCRED SYMBOLIC(SO_PASSCRED) -#define SO_PASSSEC SYMBOLIC(SO_PASSSEC) -#define SO_PEEK_OFF SYMBOLIC(SO_PEEK_OFF) -#define SO_PEERCRED SYMBOLIC(SO_PEERCRED) -#define SO_PEERNAME SYMBOLIC(SO_PEERNAME) -#define SO_PEERSEC SYMBOLIC(SO_PEERSEC) -#define SO_PRIORITY SYMBOLIC(SO_PRIORITY) -#define SO_PROTOCOL SYMBOLIC(SO_PROTOCOL) -#define SO_RCVBUF SYMBOLIC(SO_RCVBUF) -#define SO_RCVBUFFORCE SYMBOLIC(SO_RCVBUFFORCE) -#define SO_RCVLOWAT SYMBOLIC(SO_RCVLOWAT) -#define SO_RCVTIMEO SYMBOLIC(SO_RCVTIMEO) -#define SO_REUSEADDR SYMBOLIC(SO_REUSEADDR) -#define SO_REUSEPORT SYMBOLIC(SO_REUSEPORT) -#define SO_RXQ_OVFL SYMBOLIC(SO_RXQ_OVFL) -#define SO_SELECT_ERR_QUEUE SYMBOLIC(SO_SELECT_ERR_QUEUE) -#define SO_SETFIB SYMBOLIC(SO_SETFIB) -#define SO_SNDBUF SYMBOLIC(SO_SNDBUF) -#define SO_SNDBUFFORCE SYMBOLIC(SO_SNDBUFFORCE) -#define SO_SNDLOWAT SYMBOLIC(SO_SNDLOWAT) -#define SO_SNDTIMEO SYMBOLIC(SO_SNDTIMEO) -#define SO_TIMESTAMP SYMBOLIC(SO_TIMESTAMP) -#define SO_TIMESTAMPING SYMBOLIC(SO_TIMESTAMPING) -#define SO_TIMESTAMPNS SYMBOLIC(SO_TIMESTAMPNS) -#define SO_TYPE SYMBOLIC(SO_TYPE) -#define SO_USELOOPBACK SYMBOLIC(SO_USELOOPBACK) -#define SO_WIFI_STATUS SYMBOLIC(SO_WIFI_STATUS) - -#define SO_SECURITY_AUTHENTICATION SYMBOLIC(SO_SECURITY_AUTHENTICATION) -#define SO_SECURITY_ENCRYPTION_NETWORK SYMBOLIC(SO_SECURITY_ENCRYPTION_NETWORK) -#define SO_SECURITY_ENCRYPTION_TRANSPORT \ - SYMBOLIC(SO_SECURITY_ENCRYPTION_TRANSPORT) - #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ @@ -129,4 +66,68 @@ extern const long SO_WIFI_STATUS; COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ + +#define SO_DEBUG LITERALLY(1) + +#define LOCAL_PEERCRED SYMBOLIC(LOCAL_PEERCRED) +#define SO_ACCEPTCONN SYMBOLIC(SO_ACCEPTCONN) +#define SO_ATTACH_BPF SYMBOLIC(SO_ATTACH_BPF) +#define SO_ATTACH_FILTER SYMBOLIC(SO_ATTACH_FILTER) +#define SO_ATTACH_REUSEPORT_CBPF SYMBOLIC(SO_ATTACH_REUSEPORT_CBPF) +#define SO_ATTACH_REUSEPORT_EBPF SYMBOLIC(SO_ATTACH_REUSEPORT_EBPF) +#define SO_BINDTODEVICE SYMBOLIC(SO_BINDTODEVICE) +#define SO_BPF_EXTENSIONS SYMBOLIC(SO_BPF_EXTENSIONS) +#define SO_BROADCAST SYMBOLIC(SO_BROADCAST) +#define SO_BSDCOMPAT SYMBOLIC(SO_BSDCOMPAT) +#define SO_BUSY_POLL SYMBOLIC(SO_BUSY_POLL) +#define SO_CNX_ADVICE SYMBOLIC(SO_CNX_ADVICE) +#define SO_DETACH_BPF SYMBOLIC(SO_DETACH_BPF) +#define SO_DETACH_FILTER SYMBOLIC(SO_DETACH_FILTER) +#define SO_DOMAIN SYMBOLIC(SO_DOMAIN) +#define SO_DONTROUTE SYMBOLIC(SO_DONTROUTE) +#define SO_ERROR SYMBOLIC(SO_ERROR) +#define SO_EXCLUSIVEADDRUSE SYMBOLIC(SO_EXCLUSIVEADDRUSE) +#define SO_GET_FILTER SYMBOLIC(SO_GET_FILTER) +#define SO_INCOMING_CPU SYMBOLIC(SO_INCOMING_CPU) +#define SO_KEEPALIVE SYMBOLIC(SO_KEEPALIVE) +#define SO_LINGER SYMBOLIC(SO_LINGER) +#define SO_LOCK_FILTER SYMBOLIC(SO_LOCK_FILTER) +#define SO_MARK SYMBOLIC(SO_MARK) +#define SO_MAX_PACING_RATE SYMBOLIC(SO_MAX_PACING_RATE) +#define SO_NOFCS SYMBOLIC(SO_NOFCS) +#define SO_NO_CHECK SYMBOLIC(SO_NO_CHECK) +#define SO_OOBINLINE SYMBOLIC(SO_OOBINLINE) +#define SO_PASSCRED SYMBOLIC(SO_PASSCRED) +#define SO_PASSSEC SYMBOLIC(SO_PASSSEC) +#define SO_PEEK_OFF SYMBOLIC(SO_PEEK_OFF) +#define SO_PEERCRED SYMBOLIC(SO_PEERCRED) +#define SO_PEERNAME SYMBOLIC(SO_PEERNAME) +#define SO_PEERSEC SYMBOLIC(SO_PEERSEC) +#define SO_PRIORITY SYMBOLIC(SO_PRIORITY) +#define SO_PROTOCOL SYMBOLIC(SO_PROTOCOL) +#define SO_RCVBUF SYMBOLIC(SO_RCVBUF) +#define SO_RCVBUFFORCE SYMBOLIC(SO_RCVBUFFORCE) +#define SO_RCVLOWAT SYMBOLIC(SO_RCVLOWAT) +#define SO_RCVTIMEO SYMBOLIC(SO_RCVTIMEO) +#define SO_REUSEADDR SYMBOLIC(SO_REUSEADDR) +#define SO_REUSEPORT SYMBOLIC(SO_REUSEPORT) +#define SO_RXQ_OVFL SYMBOLIC(SO_RXQ_OVFL) +#define SO_SELECT_ERR_QUEUE SYMBOLIC(SO_SELECT_ERR_QUEUE) +#define SO_SETFIB SYMBOLIC(SO_SETFIB) +#define SO_SNDBUF SYMBOLIC(SO_SNDBUF) +#define SO_SNDBUFFORCE SYMBOLIC(SO_SNDBUFFORCE) +#define SO_SNDLOWAT SYMBOLIC(SO_SNDLOWAT) +#define SO_SNDTIMEO SYMBOLIC(SO_SNDTIMEO) +#define SO_TIMESTAMP SYMBOLIC(SO_TIMESTAMP) +#define SO_TIMESTAMPING SYMBOLIC(SO_TIMESTAMPING) +#define SO_TIMESTAMPNS SYMBOLIC(SO_TIMESTAMPNS) +#define SO_TYPE SYMBOLIC(SO_TYPE) +#define SO_USELOOPBACK SYMBOLIC(SO_USELOOPBACK) +#define SO_WIFI_STATUS SYMBOLIC(SO_WIFI_STATUS) + +#define SO_SECURITY_AUTHENTICATION SYMBOLIC(SO_SECURITY_AUTHENTICATION) +#define SO_SECURITY_ENCRYPTION_NETWORK SYMBOLIC(SO_SECURITY_ENCRYPTION_NETWORK) +#define SO_SECURITY_ENCRYPTION_TRANSPORT \ + SYMBOLIC(SO_SECURITY_ENCRYPTION_TRANSPORT) + #endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_SO_H_ */ diff --git a/libc/sysv/consts/sol.h b/libc/sysv/consts/sol.h index a24cb776b..f3a1d6f06 100644 --- a/libc/sysv/consts/sol.h +++ b/libc/sysv/consts/sol.h @@ -1,36 +1,6 @@ #ifndef COSMOPOLITAN_LIBC_SYSV_CONSTS_SOL_H_ #define COSMOPOLITAN_LIBC_SYSV_CONSTS_SOL_H_ #include "libc/runtime/symbolic.h" - -#define SOL_AAL SYMBOLIC(SOL_AAL) -#define SOL_ALG SYMBOLIC(SOL_ALG) -#define SOL_ATM SYMBOLIC(SOL_ATM) -#define SOL_BLUETOOTH SYMBOLIC(SOL_BLUETOOTH) -#define SOL_CAIF SYMBOLIC(SOL_CAIF) -#define SOL_DCCP SYMBOLIC(SOL_DCCP) -#define SOL_DECNET SYMBOLIC(SOL_DECNET) -#define SOL_ICMPV6 SYMBOLIC(SOL_ICMPV6) -#define SOL_IP SYMBOLIC(SOL_IP) -#define SOL_IPV6 SYMBOLIC(SOL_IPV6) -#define SOL_IRDA SYMBOLIC(SOL_IRDA) -#define SOL_IUCV SYMBOLIC(SOL_IUCV) -#define SOL_KCM SYMBOLIC(SOL_KCM) -#define SOL_LLC SYMBOLIC(SOL_LLC) -#define SOL_NETBEUI SYMBOLIC(SOL_NETBEUI) -#define SOL_NETLINK SYMBOLIC(SOL_NETLINK) -#define SOL_NFC SYMBOLIC(SOL_NFC) -#define SOL_PACKET SYMBOLIC(SOL_PACKET) -#define SOL_PNPIPE SYMBOLIC(SOL_PNPIPE) -#define SOL_PPPOL2TP SYMBOLIC(SOL_PPPOL2TP) -#define SOL_RAW SYMBOLIC(SOL_RAW) -#define SOL_RDS SYMBOLIC(SOL_RDS) -#define SOL_RXRPC SYMBOLIC(SOL_RXRPC) -#define SOL_SOCKET SYMBOLIC(SOL_SOCKET) -#define SOL_TCP SYMBOLIC(SOL_TCP) -#define SOL_TIPC SYMBOLIC(SOL_TIPC) -#define SOL_UDP SYMBOLIC(SOL_UDP) -#define SOL_X25 SYMBOLIC(SOL_X25) - #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ @@ -65,4 +35,35 @@ extern const long SOL_X25; COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ + +#define SOL_IP LITERALLY(0) +#define SOL_TCP LITERALLY(6) +#define SOL_UDP LITERALLY(17) + +#define SOL_AAL SYMBOLIC(SOL_AAL) +#define SOL_ALG SYMBOLIC(SOL_ALG) +#define SOL_ATM SYMBOLIC(SOL_ATM) +#define SOL_BLUETOOTH SYMBOLIC(SOL_BLUETOOTH) +#define SOL_CAIF SYMBOLIC(SOL_CAIF) +#define SOL_DCCP SYMBOLIC(SOL_DCCP) +#define SOL_DECNET SYMBOLIC(SOL_DECNET) +#define SOL_ICMPV6 SYMBOLIC(SOL_ICMPV6) +#define SOL_IPV6 SYMBOLIC(SOL_IPV6) +#define SOL_IRDA SYMBOLIC(SOL_IRDA) +#define SOL_IUCV SYMBOLIC(SOL_IUCV) +#define SOL_KCM SYMBOLIC(SOL_KCM) +#define SOL_LLC SYMBOLIC(SOL_LLC) +#define SOL_NETBEUI SYMBOLIC(SOL_NETBEUI) +#define SOL_NETLINK SYMBOLIC(SOL_NETLINK) +#define SOL_NFC SYMBOLIC(SOL_NFC) +#define SOL_PACKET SYMBOLIC(SOL_PACKET) +#define SOL_PNPIPE SYMBOLIC(SOL_PNPIPE) +#define SOL_PPPOL2TP SYMBOLIC(SOL_PPPOL2TP) +#define SOL_RAW SYMBOLIC(SOL_RAW) +#define SOL_RDS SYMBOLIC(SOL_RDS) +#define SOL_RXRPC SYMBOLIC(SOL_RXRPC) +#define SOL_SOCKET SYMBOLIC(SOL_SOCKET) +#define SOL_TIPC SYMBOLIC(SOL_TIPC) +#define SOL_X25 SYMBOLIC(SOL_X25) + #endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_SOL_H_ */ diff --git a/libc/sysv/syscalls.sh b/libc/sysv/syscalls.sh index 20d6d2da4..92e5bc1a1 100755 --- a/libc/sysv/syscalls.sh +++ b/libc/sysv/syscalls.sh @@ -154,8 +154,8 @@ scall sys_geteuid 0x019019019201906b globl hidden scall sys_getegid 0x02b02b02b202b06c globl hidden scall getgroups 0x04f04f04f204f073 globl scall setgroups 0x0500500502050074 globl -scall setreuid 0x07e07e07e207e071 globl -scall setregid 0x07f07f07f207f072 globl +scall sys_setreuid 0x07e07e07e207e071 globl hidden +scall sys_setregid 0x07f07f07f207f072 globl hidden scall sys_setuid 0x0170170172017069 globl hidden scall sys_setgid 0x0b50b50b520b506a globl hidden scall sys_setresuid 0xfff11a137ffff075 globl hidden # polyfilled for xnu diff --git a/libc/sysv/systemfive.S b/libc/sysv/systemfive.S index 9540717f0..fd37a06f4 100644 --- a/libc/sysv/systemfive.S +++ b/libc/sysv/systemfive.S @@ -553,7 +553,7 @@ syscon_windows:/* .rodata.str1.1 .Llog: .ascii STRACE_PROLOGUE .ascii "bell system five system call support" - .asciz " %'u magnums loaded on %s%n" + .asciz " %'u magnums loaded on %s\n" .previous #endif /* DEBUGSYS */ diff --git a/libc/testlib/testlib.h b/libc/testlib/testlib.h index a1e266856..1ad271559 100644 --- a/libc/testlib/testlib.h +++ b/libc/testlib/testlib.h @@ -114,11 +114,12 @@ void TearDownOnce(void); #define ASSERT_SYS(ERRNO, WANT, GOT, ...) \ do { \ - errno = 0; \ + int e = errno; \ __TEST_EQ(assert, __FILE__, __LINE__, __FUNCTION__, #WANT, #GOT, WANT, \ GOT, __VA_ARGS__); \ __TEST_EQ(assert, __FILE__, __LINE__, __FUNCTION__, #ERRNO, \ strerror(errno), ERRNO, errno, __VA_ARGS__); \ + errno = e; \ } while (0) #define ASSERT_BETWEEN(BEG, END, GOT) \ @@ -314,8 +315,8 @@ struct TestFixture { }; extern char g_fixturename[256]; -extern char g_testlib_olddir[PATH_MAX]; -extern char g_testlib_tmpdir[PATH_MAX]; +extern char g_testlib_olddir[PATH_MAX + 1]; +extern char g_testlib_tmpdir[PATH_MAX + 1]; extern bool g_testlib_shoulddebugbreak; /* set by testmain */ extern unsigned g_testlib_ran; /* set by wrappers */ extern unsigned g_testlib_failed; /* set by wrappers */ diff --git a/libc/testlib/testrunner.c b/libc/testlib/testrunner.c index d1ce3f6fb..0b076645c 100644 --- a/libc/testlib/testrunner.c +++ b/libc/testlib/testrunner.c @@ -46,9 +46,9 @@ #include "libc/x/x.h" static int x; -char g_testlib_olddir[PATH_MAX]; -char g_testlib_tmpdir[PATH_MAX]; struct sigaction wanthandlers[31]; +char g_testlib_olddir[PATH_MAX + 1]; +char g_testlib_tmpdir[PATH_MAX + 1]; void testlib_finish(void) { if (g_testlib_failed) { @@ -142,7 +142,7 @@ static void CheckForFileDescriptors(void) { for (i = 0; i < ARRAYLEN(pfds); ++i) { if (pfds[i].revents & POLLNVAL) continue; ++g_testlib_failed; - fprintf(stderr, "error: test failed to close() fd %d%n", pfds[i].fd); + fprintf(stderr, "error: test failed to close() fd %d\n", pfds[i].fd); } } #endif @@ -161,7 +161,7 @@ static void CheckForZombies(void) { break; } else { ++g_testlib_failed; - fprintf(stderr, "error: test failed to reap zombies %d%n", pid); + fprintf(stderr, "error: test failed to reap zombies %d\n", pid); } } #endif diff --git a/libc/time/localtime.c b/libc/time/localtime.c index 74bad0461..a79d0330c 100644 --- a/libc/time/localtime.c +++ b/libc/time/localtime.c @@ -399,7 +399,7 @@ tzload( 2 * sizeof *sp + 4 * TZ_MAX_TIMES]; } * up; - char fullname[PATH_MAX]; + char fullname[PATH_MAX+1]; up = calloc(1, sizeof *up); if (up == NULL) diff --git a/libc/zip.h b/libc/zip.h index 038cac34c..35477adf5 100644 --- a/libc/zip.h +++ b/libc/zip.h @@ -44,11 +44,10 @@ #define kZipCompressionNone 0 #define kZipCompressionDeflate 8 -#define kZipCdirHdrMagic 0x06054b50 /* PK♣♠ "PK\5\6" */ -#define kZipCdirHdrMinSize 22 -#define kZipCdirAlign kZipAlign -#define kZipCdirHdrLinkableSize \ - ROUNDUP(kZipCfileHdrMinSize + PATH_MAX, kZipCdirAlign) +#define kZipCdirHdrMagic 0x06054b50 /* PK♣♠ "PK\5\6" */ +#define kZipCdirHdrMinSize 22 +#define kZipCdirAlign kZipAlign +#define kZipCdirHdrLinkableSize 294 #define kZipCdir64HdrMagic 0x06064b50 /* PK♣♠ "PK\6\6" */ #define kZipCdir64HdrMinSize 56 diff --git a/net/http/decodelatin1.c b/net/http/decodelatin1.c index a52ce8b95..04ec84bd7 100644 --- a/net/http/decodelatin1.c +++ b/net/http/decodelatin1.c @@ -39,7 +39,7 @@ char *DecodeLatin1(const char *p, size_t n, size_t *z) { if (n == -1) n = p ? strlen(p) : 0; if ((q = r = malloc(n * 2 + 1))) { for (i = 0; i < n;) { - memset(vz, 0, 16); /* 3x speedup for ASCII */ + bzero(vz, 16); /* 3x speedup for ASCII */ while (i + 16 < n) { memcpy(v1, p + i, 16); pcmpgtb(v2, v1, vz); diff --git a/net/http/encodelatin1.c b/net/http/encodelatin1.c index 924188c4e..abb15c433 100644 --- a/net/http/encodelatin1.c +++ b/net/http/encodelatin1.c @@ -40,7 +40,7 @@ char *EncodeLatin1(const char *p, size_t n, size_t *z, int f) { size_t i; char t[256]; char *r, *q; - memset(t, 0, sizeof(t)); + bzero(t, sizeof(t)); if (f & kControlC0) memset(t + 0x00, 1, 0x20 - 0x00), t[0x7F] = 1; if (f & kControlC1) memset(t + 0x80, 1, 0xA0 - 0x80); t['\t'] = t['\r'] = t['\n'] = t['\v'] = !!(f & kControlWs); diff --git a/net/http/foldheader.c b/net/http/foldheader.c index f840527dc..ac930abf9 100644 --- a/net/http/foldheader.c +++ b/net/http/foldheader.c @@ -21,6 +21,9 @@ #include "libc/str/str.h" #include "net/http/http.h" +/** + * Collapses repeating headers onto a single line. + */ char *FoldHeader(struct HttpMessage *msg, char *b, int h, size_t *z) { char *p; size_t i, n, m; diff --git a/net/http/hascontrolcodes.c b/net/http/hascontrolcodes.c index c7fba8f22..dd6c4e30d 100644 --- a/net/http/hascontrolcodes.c +++ b/net/http/hascontrolcodes.c @@ -34,7 +34,7 @@ ssize_t HasControlCodes(const char *p, size_t n, int f) { char t[256]; wint_t x, a, b; size_t i, j, m, g; - memset(t, 0, sizeof(t)); + bzero(t, sizeof(t)); if (f & kControlC0) memset(t + 0x00, 1, 0x20 - 0x00), t[0x7F] = 1; if (f & kControlC1) memset(t + 0x80, 1, 0xA0 - 0x80); t['\t'] = t['\r'] = t['\n'] = t['\v'] = !!(f & kControlWs); diff --git a/net/http/parsehttpmessage.c b/net/http/parsehttpmessage.c index f9babfebb..77afdf730 100644 --- a/net/http/parsehttpmessage.c +++ b/net/http/parsehttpmessage.c @@ -36,7 +36,7 @@ */ void InitHttpMessage(struct HttpMessage *r, int type) { assert(type == kHttpRequest || type == kHttpResponse); - memset(r, 0, sizeof(*r)); + bzero(r, sizeof(*r)); r->type = type; } diff --git a/net/http/parseurl.c b/net/http/parseurl.c index cf5a8c0a6..8bdc6ac1b 100644 --- a/net/http/parseurl.c +++ b/net/http/parseurl.c @@ -257,7 +257,7 @@ static char *ParseUrlImpl(const char *s, size_t n, struct Url *h, bool latin1) { u.isform = false; u.isopaque = false; u.islatin1 = latin1; - memset(h, 0, sizeof(*h)); + bzero(h, sizeof(*h)); if ((m = malloc(latin1 ? u.n * 2 : u.n))) { u.q = u.p = m; if (ParseScheme(&u, h)) ParseAuthority(&u, h); diff --git a/net/http/underlong.c b/net/http/underlong.c index 0d924dbfb..e6e1c959b 100644 --- a/net/http/underlong.c +++ b/net/http/underlong.c @@ -46,7 +46,7 @@ char *Underlong(const char *p, size_t n, size_t *z) { if (n == -1) n = p ? strlen(p) : 0; if ((q = r = malloc(n + 1))) { for (i = 0; i < n;) { - memset(vz, 0, 16); /* 50x speedup for ASCII */ + bzero(vz, 16); /* 50x speedup for ASCII */ while (i + 16 < n) { memcpy(v1, p + i, 16); pcmpgtb(v2, v1, vz); diff --git a/test/libc/calls/commandv_test.c b/test/libc/calls/commandv_test.c index e4f6da7a7..e30ae0cda 100644 --- a/test/libc/calls/commandv_test.c +++ b/test/libc/calls/commandv_test.c @@ -35,8 +35,8 @@ uint64_t i; char *oldpath; -char tmp[PATH_MAX]; -char pathbuf[PATH_MAX]; +char tmp[PATH_MAX + 1]; +char pathbuf[PATH_MAX + 1]; char testlib_enable_tmp_setup_teardown; void SetUp(void) { @@ -54,34 +54,34 @@ void TearDown(void) { TEST(commandv, testPathSearch) { EXPECT_NE(-1, touch("bin/sh", 0755)); - EXPECT_STREQ("bin/sh", commandv("sh", pathbuf)); + EXPECT_STREQ("bin/sh", commandv("sh", pathbuf, sizeof(pathbuf))); } TEST(commandv, testPathSearch_appendsComExtension) { EXPECT_NE(-1, touch("bin/sh.com", 0755)); - EXPECT_STREQ("bin/sh.com", commandv("sh", pathbuf)); + EXPECT_STREQ("bin/sh.com", commandv("sh", pathbuf, sizeof(pathbuf))); } TEST(commandv, testSlashes_wontSearchPath_butChecksAccess) { EXPECT_NE(-1, touch("home/sh", 0755)); i = g_syscount; - EXPECT_STREQ("home/sh", commandv("home/sh", pathbuf)); + EXPECT_STREQ("home/sh", commandv("home/sh", pathbuf, sizeof(pathbuf))); if (!IsWindows()) EXPECT_EQ(i + 1, g_syscount); } TEST(commandv, testSlashes_wontSearchPath_butStillAppendsComExtension) { EXPECT_NE(-1, touch("home/sh.com", 0755)); i = g_syscount; - EXPECT_STREQ("home/sh.com", commandv("home/sh", pathbuf)); + EXPECT_STREQ("home/sh.com", commandv("home/sh", pathbuf, sizeof(pathbuf))); if (!IsWindows()) EXPECT_EQ(i + 2, g_syscount); } TEST(commandv, testSameDir_doesntHappenByDefaultUnlessItsWindows) { EXPECT_NE(-1, touch("bog", 0755)); if (IsWindows()) { - EXPECT_STREQ("./bog", commandv("bog", pathbuf)); + EXPECT_STREQ("./bog", commandv("bog", pathbuf, sizeof(pathbuf))); } else { - EXPECT_EQ(NULL, commandv("bog", pathbuf)); + EXPECT_EQ(NULL, commandv("bog", pathbuf, sizeof(pathbuf))); } } @@ -89,9 +89,9 @@ TEST(commandv, testSameDir_willHappenWithColonBlank) { CHECK_NE(-1, setenv("PATH", "bin:", true)); EXPECT_NE(-1, touch("bog", 0755)); if (IsWindows()) { - EXPECT_STREQ("./bog", commandv("bog", pathbuf)); + EXPECT_STREQ("./bog", commandv("bog", pathbuf, sizeof(pathbuf))); } else { - EXPECT_STREQ("bog", commandv("bog", pathbuf)); + EXPECT_STREQ("bog", commandv("bog", pathbuf, sizeof(pathbuf))); } } @@ -99,8 +99,8 @@ TEST(commandv, testSameDir_willHappenWithColonBlank2) { CHECK_NE(-1, setenv("PATH", ":bin", true)); EXPECT_NE(-1, touch("bog", 0755)); if (IsWindows()) { - EXPECT_STREQ("./bog", commandv("bog", pathbuf)); + EXPECT_STREQ("./bog", commandv("bog", pathbuf, sizeof(pathbuf))); } else { - EXPECT_STREQ("bog", commandv("bog", pathbuf)); + EXPECT_STREQ("bog", commandv("bog", pathbuf, sizeof(pathbuf))); } } diff --git a/test/libc/calls/execve_test.c b/test/libc/calls/execve_test.c index ce11cd967..88cbd140f 100644 --- a/test/libc/calls/execve_test.c +++ b/test/libc/calls/execve_test.c @@ -29,6 +29,13 @@ void SetUp(void) { } else { exit(7); } + } else if (getenv("_WEIRDENV")) { + for (char **e = environ; *e; ++e) { + if (!strcmp(*e, "WEIRD")) { + exit(0); + } + } + exit(7); } } @@ -47,3 +54,20 @@ TEST(execve, testWeirdAnsiC89emptyArgv) { EXPECT_TRUE(WIFEXITED(ws)); EXPECT_EQ(0, WEXITSTATUS(ws)); } + +TEST(execve, testWeirdEnvironmentVariable) { + char *prog; + int pid, ws; + if (IsWindows()) return; + if (IsOpenbsd()) return; + prog = GetProgramExecutableName(); + ASSERT_NE(-1, (pid = fork())); + if (!pid) { + execve(prog, (char *const[]){prog, 0}, + (char *const[]){"_WEIRDENV=1", "WEIRD", 0}); + _Exit(127); + } + ASSERT_NE(-1, wait(&ws)); + EXPECT_TRUE(WIFEXITED(ws)); + EXPECT_EQ(0, WEXITSTATUS(ws)); +} diff --git a/test/libc/calls/getcwd_test.c b/test/libc/calls/getcwd_test.c index e6adae3bd..111d6d03f 100644 --- a/test/libc/calls/getcwd_test.c +++ b/test/libc/calls/getcwd_test.c @@ -40,3 +40,10 @@ TEST(getcwd, testNullBuf_allocatesResult) { EXPECT_NE(-1, chdir("subdir")); EXPECT_STREQ("subdir", basename(gc(getcwd(0, 0)))); } + +TEST(getcwd, testWindows_addsFunnyPrefix) { + if (!IsWindows()) return; + char path[PATH_MAX + 1]; + ASSERT_NE(0, getcwd(path, sizeof(path))); + EXPECT_STARTSWITH("//?/", path); +} diff --git a/test/libc/calls/mkdir_test.c b/test/libc/calls/mkdir_test.c index 8da031afd..e0037d558 100644 --- a/test/libc/calls/mkdir_test.c +++ b/test/libc/calls/mkdir_test.c @@ -17,9 +17,11 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" +#include "libc/dce.h" #include "libc/errno.h" #include "libc/fmt/fmt.h" #include "libc/log/check.h" +#include "libc/mem/mem.h" #include "libc/runtime/runtime.h" #include "libc/sysv/consts/o.h" #include "libc/testlib/testlib.h" @@ -58,6 +60,15 @@ TEST(mkdir, testPathIsDirectory_EEXIST) { EXPECT_EQ(EEXIST, errno); } +TEST(mkdir, enametoolong) { + int i; + size_t n = 2048; + char *d, *s = gc(calloc(1, n)); + for (i = 0; i < n - 1; ++i) s[i] = 'x'; + s[i] = 0; + EXPECT_SYS(ENAMETOOLONG, -1, mkdir(s, 0644)); +} + TEST(makedirs, testEmptyString_EEXIST) { EXPECT_EQ(-1, mkdir("", 0755)); EXPECT_EQ(ENOENT, errno); @@ -72,3 +83,14 @@ TEST(mkdirat, testRelativePath_opensRelativeToDirFd) { EXPECT_EQ(-1, makedirs("", 0755)); EXPECT_NE(-1, close(dirfd)); } + +TEST(mkdir, longname) { + int i; + char *d, s[270] = {0}; + for (i = 0; i < sizeof(s) - 1; ++i) s[i] = 'x'; + s[i] = 0; + ASSERT_NE(NULL, (d = gc(getcwd(0, 0)))); + memcpy(s, d, strlen(d)); + s[strlen(d)] = '/'; + ASSERT_SYS(0, 0, mkdir(s, 0644)); +} diff --git a/test/libc/calls/read_test.c b/test/libc/calls/read_test.c index c2f156805..20db7ebb4 100644 --- a/test/libc/calls/read_test.c +++ b/test/libc/calls/read_test.c @@ -38,7 +38,13 @@ BENCH(read, bench) { char buf[16]; ASSERT_SYS(0, 3, open("/dev/zero", O_RDONLY)); EZBENCH2("read", donothing, read(3, buf, 5)); - EZBENCH2("readv", donothing, readv(3, &(struct iovec){buf, 5}, 1)); + EZBENCH2("pread", donothing, pread(3, buf, 5, 0)); + EZBENCH2("readv₁", donothing, readv(3, &(struct iovec){buf, 5}, 1)); + EZBENCH2("readv₂", donothing, + readv(3, (struct iovec[]){{buf, 1}, {buf + 1, 4}}, 2)); + EZBENCH2("preadv₁", donothing, preadv(3, &(struct iovec){buf, 5}, 1, 0)); + EZBENCH2("preadv₂", donothing, + preadv(3, (struct iovec[]){{buf, 1}, {buf + 1, 4}}, 2, 0)); EZBENCH2("sys_read", donothing, sys_read(3, buf, 5)); EZBENCH2("sys_readv", donothing, sys_readv(3, &(struct iovec){buf, 5}, 1)); EZBENCH2("Read", donothing, Read(3, buf, 5)); diff --git a/test/libc/calls/readlinkat_test.c b/test/libc/calls/readlinkat_test.c index add8e75aa..b178c07ee 100644 --- a/test/libc/calls/readlinkat_test.c +++ b/test/libc/calls/readlinkat_test.c @@ -83,10 +83,8 @@ TEST(readlinkat, frootloop) { ASSERT_SYS(0, 0, symlink("froot", "froot")); ASSERT_SYS(ELOOP, -1, readlink("froot/loop", buf, sizeof(buf))); if (O_NOFOLLOW) { - ASSERT_SYS(IsFreebsd() ? EMLINK - : IsNetbsd() ? EFTYPE - : ELOOP, - -1, open("froot", O_RDONLY | O_NOFOLLOW)); + ASSERT_SYS(IsFreebsd() ? EMLINK : IsNetbsd() ? EFTYPE : ELOOP, -1, + open("froot", O_RDONLY | O_NOFOLLOW)); if (0 && O_PATH) { /* need rhel5 test */ ASSERT_NE(-1, (fd = open("froot", O_RDONLY | O_NOFOLLOW | O_PATH))); ASSERT_NE(-1, close(fd)); @@ -101,3 +99,11 @@ TEST(readlinkat, statReadsNameLength) { EXPECT_TRUE(S_ISLNK(st.st_mode)); EXPECT_EQ(5, st.st_size); } + +TEST(readlinkat, realpathReturnsLongPath) { + if (!IsWindows()) return; + struct stat st; + char buf[PATH_MAX]; + ASSERT_SYS(0, 0, touch("froot", 0644)); + ASSERT_STARTSWITH("//?/", realpath("froot", buf)); +} diff --git a/test/libc/calls/seccomp_test.c b/test/libc/calls/seccomp_test.c index 7ea7d6329..6b576b9f0 100644 --- a/test/libc/calls/seccomp_test.c +++ b/test/libc/calls/seccomp_test.c @@ -22,7 +22,6 @@ #include "libc/calls/struct/iovec.h" #include "libc/calls/struct/seccomp.h" #include "libc/errno.h" -#include "libc/intrin/kprintf.h" #include "libc/runtime/runtime.h" #include "libc/sock/sock.h" #include "libc/sysv/consts/audit.h" diff --git a/test/libc/calls/sigaction_test.c b/test/libc/calls/sigaction_test.c index efbc18aab..fe4983c30 100644 --- a/test/libc/calls/sigaction_test.c +++ b/test/libc/calls/sigaction_test.c @@ -23,7 +23,6 @@ #include "libc/calls/ucontext.h" #include "libc/dce.h" #include "libc/errno.h" -#include "libc/intrin/kprintf.h" #include "libc/runtime/runtime.h" #include "libc/sysv/consts/sa.h" #include "libc/sysv/consts/sig.h" diff --git a/test/libc/calls/sigprocmask_test.c b/test/libc/calls/sigprocmask_test.c index 5ccc94071..51836565e 100644 --- a/test/libc/calls/sigprocmask_test.c +++ b/test/libc/calls/sigprocmask_test.c @@ -23,7 +23,6 @@ #include "libc/calls/struct/sigset.h" #include "libc/calls/ucontext.h" #include "libc/dce.h" -#include "libc/intrin/kprintf.h" #include "libc/sysv/consts/sa.h" #include "libc/sysv/consts/sig.h" #include "libc/testlib/testlib.h" diff --git a/test/libc/calls/sigsuspend_test.c b/test/libc/calls/sigsuspend_test.c index 7cd46385e..0772c8ef9 100644 --- a/test/libc/calls/sigsuspend_test.c +++ b/test/libc/calls/sigsuspend_test.c @@ -21,7 +21,6 @@ #include "libc/calls/struct/sigset.h" #include "libc/dce.h" #include "libc/errno.h" -#include "libc/intrin/kprintf.h" #include "libc/runtime/runtime.h" #include "libc/str/str.h" #include "libc/sysv/consts/sa.h" diff --git a/test/libc/fmt/atoi_test.c b/test/libc/fmt/atoi_test.c index a36ff54e3..1b0fc92c3 100644 --- a/test/libc/fmt/atoi_test.c +++ b/test/libc/fmt/atoi_test.c @@ -23,6 +23,13 @@ #include "libc/testlib/ezbench.h" #include "libc/testlib/testlib.h" +void __on_arithmetic_overflow(void) { + // prevent -ftrapv crashes + // + // for some reason gcc generates trap code even when we're doing it + // manually with __builtin_mul_overflow() :'( +} + TEST(atoi, test) { EXPECT_EQ(0, atoi("")); EXPECT_EQ(0, atoi("-b")); diff --git a/test/libc/intrin/kprintf_test.c b/test/libc/intrin/kprintf_test.c index cf4f9ab09..071c15f5d 100644 --- a/test/libc/intrin/kprintf_test.c +++ b/test/libc/intrin/kprintf_test.c @@ -354,6 +354,33 @@ TEST(ksnprintf, badUtf16) { } } +TEST(ksnprintf, truncation) { + char buf[16] = {0}; + rngset(buf, sizeof(buf) - 1, lemur64, -1); + ksnprintf(0, 0, "%s", "xxxxx"); + rngset(buf, sizeof(buf) - 1, lemur64, -1); + ksnprintf(buf, 1, "%s", "xxxxx"); + EXPECT_STREQ("", buf); + rngset(buf, sizeof(buf) - 1, lemur64, -1); + ksnprintf(buf, 2, "%s", "xxxxx"); + EXPECT_STREQ(".", buf); + rngset(buf, sizeof(buf) - 1, lemur64, -1); + ksnprintf(buf, 3, "%s", "xxxxx"); + EXPECT_STREQ("..", buf); + rngset(buf, sizeof(buf) - 1, lemur64, -1); + ksnprintf(buf, 4, "%s", "xxxxx"); + EXPECT_STREQ("...", buf); + rngset(buf, sizeof(buf) - 1, lemur64, -1); + ksnprintf(buf, 5, "%s", "xxxxx"); + EXPECT_STREQ("x...", buf); + rngset(buf, sizeof(buf) - 1, lemur64, -1); + ksnprintf(buf, 6, "%s", "xxxxxxxxxxx"); + EXPECT_STREQ("xx...", buf); + rngset(buf, sizeof(buf) - 1, lemur64, -1); + ksnprintf(buf, 7, "%s", "xxxxxxxxx"); + EXPECT_STREQ("xxx...", buf); +} + BENCH(printf, bench) { char b[128]; int snprintf_(char *, size_t, const char *, ...) asm("snprintf"); diff --git a/test/libc/runtime/memtrack_test.c b/test/libc/runtime/memtrack_test.c index ff84e1727..200ec8a2e 100644 --- a/test/libc/runtime/memtrack_test.c +++ b/test/libc/runtime/memtrack_test.c @@ -63,7 +63,7 @@ static void CheckMemoryIntervalsAreOk(const struct MemoryIntervals *mm) { static void RunTrackMemoryIntervalTest(const struct MemoryIntervals t[2], int x, int y, long h) { struct MemoryIntervals *mm; - mm = memcpy(malloc(sizeof(*t)), t, sizeof(*t)); + mm = memcpy(memalign(64, sizeof(*t)), t, sizeof(*t)); CheckMemoryIntervalsAreOk(mm); CHECK_NE(-1, TrackMemoryInterval(mm, x, y, h, 0, 0, 0, 0, 0, 0)); CheckMemoryIntervalsAreOk(mm); @@ -75,7 +75,7 @@ static int RunReleaseMemoryIntervalsTest(const struct MemoryIntervals t[2], int x, int y) { int rc; struct MemoryIntervals *mm; - mm = memcpy(malloc(sizeof(*t)), t, sizeof(*t)); + mm = memcpy(memalign(64, sizeof(*t)), t, sizeof(*t)); CheckMemoryIntervalsAreOk(mm); if ((rc = ReleaseMemoryIntervals(mm, x, y, NULL)) != -1) { CheckMemoryIntervalsAreOk(mm); diff --git a/test/libc/runtime/mprotect_test.c b/test/libc/runtime/mprotect_test.c index 366bb2cbc..d9f64e1a4 100644 --- a/test/libc/runtime/mprotect_test.c +++ b/test/libc/runtime/mprotect_test.c @@ -57,7 +57,7 @@ void OnSigBus(int sig, struct siginfo *si, struct ucontext *ctx) { #if 0 kprintf("SIGBUS%n"); kprintf("si->si_signo = %G%n", si->si_signo); - kprintf("si->si_errno = %s (%d)%n", strerror_short(si->si_errno), + kprintf("si->si_errno = %s (%d)%n", strerrno(si->si_errno), si->si_errno); kprintf("si->si_code = %s (%d)%n", GetSiCodeName(sig, si->si_code), si->si_code); diff --git a/third_party/argon2/blake2b.c b/third_party/argon2/blake2b.c index b004e8ef5..5aad00f29 100644 --- a/third_party/argon2/blake2b.c +++ b/third_party/argon2/blake2b.c @@ -42,7 +42,7 @@ static const uint64_t blake2b_IV[8] = { UINT64_C(0x1f83d9abfb41bd6b), UINT64_C(0x5be0cd19137e2179), }; -static const unsigned int blake2b_sigma[12][16] = { +static const unsigned char blake2b_sigma[12][16] = { {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, @@ -69,7 +69,7 @@ static inline void blake2b_set_lastblock(blake2b_state *S) { } static inline void blake2b_increment_counter(blake2b_state *S, - uint64_t inc) { + uint64_t inc) { S->t[0] += inc; S->t[1] += (S->t[0] < inc); } diff --git a/third_party/linenoise/linenoise.c b/third_party/linenoise/linenoise.c index 7952909ec..6c7a727f3 100644 --- a/third_party/linenoise/linenoise.c +++ b/third_party/linenoise/linenoise.c @@ -125,6 +125,7 @@ │ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. │ │ │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/alg/alg.h" #include "libc/assert.h" #include "libc/bits/bits.h" #include "libc/calls/calls.h" @@ -136,6 +137,7 @@ #include "libc/calls/termios.h" #include "libc/calls/ttydefaults.h" #include "libc/calls/weirdtypes.h" +#include "libc/dce.h" #include "libc/errno.h" #include "libc/fmt/conv.h" #include "libc/intrin/asan.internal.h" @@ -147,6 +149,7 @@ #include "libc/mem/mem.h" #include "libc/nexgen32e/bsr.h" #include "libc/nexgen32e/rdtsc.h" +#include "libc/nt/version.h" #include "libc/runtime/runtime.h" #include "libc/sock/sock.h" #include "libc/stdio/append.internal.h" @@ -190,15 +193,21 @@ Copyright 2010-2013 Pieter Noordhuis \""); #define DEBUG(L, ...) (void)0 #endif -#define DUFF_ROUTINE_READ(STATE) \ - case STATE: \ - linenoiseRefreshLineForce(l); \ - rc = linenoiseRead(l->ifd, seq, sizeof(seq), l, block); \ - if (rc == -1 && errno == EAGAIN) { \ - l->state = STATE; \ - return -1; \ - } \ - l->state = 0 +#define DUFF_ROUTINE_LOOP 0 +#define DUFF_ROUTINE_START 5 + +#define DUFF_ROUTINE_LABEL(STATE) \ + case STATE: \ + linenoiseRefreshLineForce(l); \ + l->state = DUFF_ROUTINE_LOOP + +#define DUFF_ROUTINE_READ(STATE) \ + DUFF_ROUTINE_LABEL(STATE); \ + rc = linenoiseRead(l->ifd, seq, sizeof(seq), l, block); \ + if (rc == -1 && errno == EAGAIN) { \ + l->state = STATE; \ + return -1; \ + } #define BLOCKING_READ() rc = linenoiseRead(l->ifd, seq, sizeof(seq), l, false) @@ -399,7 +408,9 @@ static int linenoiseIsUnsupportedTerm(void) { char *term; static char once, res; if (!once) { - if ((term = getenv("TERM"))) { + if (IsWindows() && !IsAtLeastWindows10()) { + res = 1; + } else if ((term = getenv("TERM"))) { for (i = 0; i < sizeof(kUnsupported) / sizeof(*kUnsupported); i++) { if (!strcasecmp(term, kUnsupported[i])) { res = 1; @@ -656,7 +667,7 @@ int linenoiseEnableRawMode(int fd) { raw = orig_termios; raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); - raw.c_oflag &= ~OPOST; + raw.c_oflag |= OPOST | ONLCR; raw.c_iflag |= IUTF8; raw.c_cflag |= CS8; raw.c_cc[VMIN] = 1; @@ -810,10 +821,10 @@ struct winsize linenoiseGetTerminalSize(struct winsize ws, int ifd, int ofd) { } if (((!ws.ws_col || !ws.ws_row) && linenoiseRead(ifd, 0, 0, 0, 1) != -1 && linenoiseWriteStr( - ofd, "\0337" /* save position */ - "\033[9979;9979H" /* move cursor to bottom right corner */ - "\033[6n" /* report position */ - "\0338") != -1 && /* restore position */ + ofd, "\e7" /* save position */ + "\e[9979;9979H" /* move cursor to bottom right corner */ + "\e[6n" /* report position */ + "\e8") != -1 && /* restore position */ (n = linenoiseRead(ifd, b, sizeof(b), 0, 1)) != -1 && n && b[0] == 033 && b[1] == '[' && b[n - 1] == 'R')) { p = b + 2; @@ -827,8 +838,8 @@ struct winsize linenoiseGetTerminalSize(struct winsize ws, int ifd, int ofd) { /* Clear the screen. Used to handle ctrl+l */ void linenoiseClearScreen(int fd) { - linenoiseWriteStr(fd, "\033[H" /* move cursor to top left corner */ - "\033[2J"); /* erase display */ + linenoiseWriteStr(fd, "\e[H" /* move cursor to top left corner */ + "\e[2J"); /* erase display */ } static void linenoiseBeep(void) { @@ -962,7 +973,7 @@ static char *linenoiseMakeSearchPrompt(int fail, const char *s, int n) { if (fail) abAppends(&ab, "failed "); abAppends(&ab, "reverse-i-search `\e[4m"); abAppend(&ab, s, n); - abAppends(&ab, "\033[24m"); + abAppends(&ab, "\e[24m"); abAppends(&ab, s + n); abAppendw(&ab, READ32LE("') ")); return ab.b; @@ -1007,8 +1018,8 @@ static char *linenoiseRefreshHints(struct linenoiseState *l) { if (!hintsCallback) return 0; if (!(hint = hintsCallback(l->buf, &ansi1, &ansi2))) return 0; abInit(&ab); - ansi1 = "\033[90m"; - ansi2 = "\033[39m"; + ansi1 = "\e[90m"; + ansi2 = "\e[39m"; if (ansi1) abAppends(&ab, ansi1); abAppends(&ab, hint); if (ansi2) abAppends(&ab, ansi2); @@ -1174,7 +1185,7 @@ StartOver: abInit(&ab); abAppendw(&ab, '\r'); /* start of line */ if (l->rows - l->oldpos - 1 > 0) { - abAppends(&ab, "\033["); + abAppends(&ab, "\e["); abAppendu(&ab, l->rows - l->oldpos - 1); abAppendw(&ab, 'A'); /* cursor up clamped */ } @@ -1185,7 +1196,7 @@ StartOver: if (x && x + rune.n > xn) { if (cy >= 0) ++cy; if (x < xn) { - abAppends(&ab, "\033[K"); /* clear line forward */ + abAppends(&ab, "\e[K"); /* clear line forward */ } abAppends(&ab, "\r" /* start of line */ "\n"); /* cursor down unclamped */ @@ -1200,9 +1211,9 @@ StartOver: abAppendw(&ab, '*'); } else { flipit = hasflip && (i == flip[0] || i == flip[1]); - if (flipit) abAppendw(&ab, READ32LE("\033[1m")); + if (flipit) abAppendw(&ab, READ32LE("\e[1m")); abAppendw(&ab, tpenc(rune.c)); - if (flipit) abAppendw(&ab, READ64LE("\033[22m\0\0")); + if (flipit) abAppendw(&ab, READ64LE("\e[22m\0\0")); } t = wcwidth(rune.c); t = MAX(0, t); @@ -1217,7 +1228,7 @@ StartOver: } free(hint); } - abAppendw(&ab, READ32LE("\033[J")); /* erase display forwards */ + abAppendw(&ab, READ32LE("\e[J")); /* erase display forwards */ /* * if we are at the very end of the screen with our prompt, we need to @@ -1232,12 +1243,12 @@ StartOver: * move cursor to right position */ if (cy > 0) { - abAppendw(&ab, READ32LE("\033[\0")); + abAppendw(&ab, READ32LE("\e[\0")); abAppendu(&ab, cy); abAppendw(&ab, 'A'); /* cursor up */ } if (cx > 0) { - abAppendw(&ab, READ32LE("\r\033[")); + abAppendw(&ab, READ32LE("\r\e[")); abAppendu(&ab, cx); abAppendw(&ab, 'C'); /* cursor right */ } else if (!cx) { @@ -1509,7 +1520,7 @@ static void linenoiseEditYank(struct linenoiseState *l) { static void linenoiseEditRotate(struct linenoiseState *l) { if ((l->seq[1][0] == CTRL('Y') || - (l->seq[1][0] == 033 && l->seq[1][1] == 'y'))) { + (l->seq[1][0] == '\e' && l->seq[1][1] == 'y'))) { if (l->yi < l->len && l->yj <= l->len) { memmove(l->buf + l->yi, l->buf + l->yj, l->len - l->yj + 1); l->len -= l->yj - l->yi; @@ -1780,12 +1791,12 @@ struct linenoiseState *linenoiseBegin(const char *prompt, int ifd, int ofd) { free(l); return 0; } + l->state = DUFF_ROUTINE_START; l->buf[0] = 0; l->ifd = ifd; l->ofd = ofd; l->prompt = strdup(prompt ? prompt : ""); l->ws = linenoiseGetTerminalSize(l->ws, l->ifd, l->ofd); - linenoiseHistoryAdd(""); linenoiseWriteStr(l->ofd, l->prompt); abInit(&l->ab); return l; @@ -1814,6 +1825,10 @@ void linenoiseEnd(struct linenoiseState *l) { } } +static int CompareStrings(const void *a, const void *b) { + return strcasecmp(*(const char **)a, *(const char **)b); +} + /** * Runs linenoise engine. * @@ -1844,7 +1859,7 @@ ssize_t linenoiseEdit(struct linenoiseState *l, const char *prompt, char **obuf, switch (l->state) { for (;;) { - DUFF_ROUTINE_READ(0); + DUFF_ROUTINE_READ(DUFF_ROUTINE_LOOP); HandleRead: if (!rc && l->len) { rc = 1; @@ -1933,7 +1948,7 @@ ssize_t linenoiseEdit(struct linenoiseState *l, const char *prompt, char **obuf, // handle tab and tab-tab completion if (seq[0] == '\t' && completionCallback) { - size_t i, j, k, n, m, perline, itemlen; + size_t i, j, k, n, m, itemlen; // we know that the user pressed tab once rc = 0; linenoiseFreeCompletions(&l->lc); @@ -1956,6 +1971,7 @@ ssize_t linenoiseEdit(struct linenoiseState *l, const char *prompt, char **obuf, continue; } if (l->lc.len > 1) { + qsort(l->lc.cvec, l->lc.len, sizeof(*l->lc.cvec), CompareStrings); // if there's a multiline completions, then do nothing and wait and // see if the user presses tab again. if the user does this we then // print ALL the completions, to above the editing line @@ -1965,29 +1981,42 @@ ssize_t linenoiseEdit(struct linenoiseState *l, const char *prompt, char **obuf, free(s); } for (;;) { - DUFF_ROUTINE_READ(3); + DUFF_ROUTINE_READ(2); if (rc == 1 && seq[0] == '\t') { + const char **p; struct abuf ab; + int i, x, y, xn, yn, xy; itemlen = linenoiseMaxCompletionWidth(&l->lc) + 4; - perline = MAX(1, (l->ws.ws_col - 1) / itemlen); - abInit(&ab); - abAppends(&ab, "\r\n\033[K"); - for (size_t i = 0; i < l->lc.len;) { - for (size_t j = 0; i < l->lc.len && j < perline; ++j, ++i) { - n = GetMonospaceWidth(l->lc.cvec[i], strlen(l->lc.cvec[i]), - 0); - abAppends(&ab, l->lc.cvec[i]); + xn = MAX(1, (l->ws.ws_col - 1) / itemlen); + yn = (l->lc.len + (xn - 1)) / xn; + if (!__builtin_mul_overflow(xn, yn, &xy) && + (p = calloc(xy, sizeof(char *)))) { + // arrange in column major order + for (i = x = 0; x < xn; ++x) { + for (y = 0; y < yn; ++y) { + p[y * xn + x] = i < l->lc.len ? l->lc.cvec[i++] : ""; + } + } + abInit(&ab); + abAppends(&ab, "\r\n\e[K"); + for (x = i = 0; i < xy; ++i) { + n = GetMonospaceWidth(p[i], strlen(p[i]), 0); + abAppends(&ab, p[i]); for (k = n; k < itemlen; ++k) { abAppendw(&ab, ' '); } + if (++x == xn) { + abAppendw(&ab, READ16LE("\r\n")); + x = 0; + } } - abAppendw(&ab, READ16LE("\r\n")); + ab.len -= 2; + abAppends(&ab, "\n"); + linenoiseWriteStr(l->ofd, ab.b); + linenoiseRefreshLine(l); + abFree(&ab); + free(p); } - ab.len -= 2; - abAppends(&ab, "\n"); - linenoiseWriteStr(l->ofd, ab.b); - linenoiseRefreshLine(l); - abFree(&ab); } else { goto HandleRead; } @@ -1998,7 +2027,7 @@ ssize_t linenoiseEdit(struct linenoiseState *l, const char *prompt, char **obuf, // handle (1) emacs keyboard combos // (2) otherwise sigint exit if (seq[0] == CTRL('C')) { - DUFF_ROUTINE_READ(4); + DUFF_ROUTINE_READ(3); if (rc == 1) { switch (seq[0]) { CASE(CTRL('C'), linenoiseEditInterrupt(l)); @@ -2019,7 +2048,7 @@ ssize_t linenoiseEdit(struct linenoiseState *l, const char *prompt, char **obuf, if (ispaused) { linenoiseUnpause(l->ofd); } else { - DUFF_ROUTINE_READ(5); + DUFF_ROUTINE_READ(4); if (rc > 0) { char esc[sizeof(seq) * 4]; size_t m = linenoiseEscape(esc, seq, rc); @@ -2031,6 +2060,28 @@ ssize_t linenoiseEdit(struct linenoiseState *l, const char *prompt, char **obuf, continue; } + // handle enter key + if (seq[0] == '\r') { + char *p; + l->final = 1; + free(history[--historylen]); + history[historylen] = 0; + linenoiseEditEnd(l); + linenoiseRefreshLineForce(l); + p = strdup(l->buf); + linenoiseReset(l); + if (p) { + *obuf = p; + l->state = DUFF_ROUTINE_START; + return l->len; + } else { + return -1; + } + DUFF_ROUTINE_LABEL(DUFF_ROUTINE_START); + linenoiseHistoryAdd(""); + continue; + } + // handle keystrokes that don't need read() switch (seq[0]) { CASE(CTRL('P'), linenoiseEditUp(l)); @@ -2070,22 +2121,6 @@ ssize_t linenoiseEdit(struct linenoiseState *l, const char *prompt, char **obuf, } break; - case '\r': { - l->final = 1; - free(history[--historylen]); - history[historylen] = 0; - linenoiseEditEnd(l); - linenoiseRefreshLineForce(l); - char *p = strdup(l->buf); - linenoiseReset(l); - if (p) { - *obuf = p; - return l->len; - } else { - return -1; - } - } - case '\e': // handle ansi escape if (rc < 2) break; diff --git a/third_party/lua/README.cosmo b/third_party/lua/README.cosmo index 9cdfdeee5..a418cc10c 100644 --- a/third_party/lua/README.cosmo +++ b/third_party/lua/README.cosmo @@ -30,3 +30,5 @@ LOCAL MODIFICATIONS bold text, which can be encoded elegantly as `\e[1mHELLO\e[0m`. Added luaL_traceback2() for function parameters in traceback. + + Added Python-like printf modulus operator for strings. diff --git a/third_party/lua/cosmo.h b/third_party/lua/cosmo.h index d8df45356..10a0bbc04 100644 --- a/third_party/lua/cosmo.h +++ b/third_party/lua/cosmo.h @@ -12,11 +12,12 @@ int LuaEncodeJsonData(lua_State *, char **, int, char *); int LuaEncodeLuaData(lua_State *, char **, int, char *); int LuaEncodeUrl(lua_State *); int LuaParseUrl(lua_State *); -void EscapeLuaString(char *, size_t, char **); -void LuaPushUrlParams(lua_State *, struct UrlParams *); -int LuaPushHeaders(lua_State *, struct HttpMessage *, const char *); -void LuaPushLatin1(lua_State *, const char *, size_t); int LuaPushHeader(lua_State *, struct HttpMessage *, char *, int); +int LuaPushHeaders(lua_State *, struct HttpMessage *, const char *); +void EscapeLuaString(char *, size_t, char **); +void LuaPushLatin1(lua_State *, const char *, size_t); +void LuaPushUrlParams(lua_State *, struct UrlParams *); +void LuaPrintStack(lua_State *); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/third_party/lua/lapi.c b/third_party/lua/lapi.c index ae3212cb9..3723ef79b 100644 --- a/third_party/lua/lapi.c +++ b/third_party/lua/lapi.c @@ -1,12 +1,32 @@ -/* -** $Id: lapi.c $ -** Lua API -** See Copyright Notice in lua.h -*/ - +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ #define lapi_c #define LUA_CORE - #include "third_party/lua/lapi.h" #include "third_party/lua/ldebug.h" #include "third_party/lua/ldo.h" @@ -22,8 +42,13 @@ #include "third_party/lua/lua.h" #include "third_party/lua/lundump.h" #include "third_party/lua/lvm.h" +// clang-format off + +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); -/* clang-format off */ const char lua_ident[] = "$LuaVersion: " LUA_COPYRIGHT " $" diff --git a/third_party/lua/lapi.h b/third_party/lua/lapi.h index 48c1c203d..0c5d784d7 100644 --- a/third_party/lua/lapi.h +++ b/third_party/lua/lapi.h @@ -1,9 +1,3 @@ -/* -** $Id: lapi.h $ -** Auxiliary functions from Lua API -** See Copyright Notice in lua.h -*/ - #ifndef lapi_h #define lapi_h diff --git a/third_party/lua/lauxlib.c b/third_party/lua/lauxlib.c index 03e7a6b52..16d4db7f3 100644 --- a/third_party/lua/lauxlib.c +++ b/third_party/lua/lauxlib.c @@ -1,19 +1,43 @@ -/* -** $Id: lauxlib.c $ -** Auxiliary functions for building Lua libraries -** See Copyright Notice in lua.h -*/ - +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ #define lauxlib_c #define LUA_LIB - #include "libc/calls/calls.h" #include "libc/errno.h" #include "third_party/lua/lauxlib.h" #include "third_party/lua/lprefix.h" #include "third_party/lua/lua.h" +// clang-format off -/* clang-format off */ +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); /** diff --git a/third_party/lua/lbaselib.c b/third_party/lua/lbaselib.c index 25f37e902..13d8013a9 100644 --- a/third_party/lua/lbaselib.c +++ b/third_party/lua/lbaselib.c @@ -1,19 +1,43 @@ -/* -** $Id: lbaselib.c $ -** Basic library -** See Copyright Notice in lua.h -*/ - +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ #define lbaselib_c #define LUA_LIB - #include "third_party/lua/lauxlib.h" #include "third_party/lua/lprefix.h" #include "third_party/lua/lua.h" #include "third_party/lua/lualib.h" - /* clang-format off */ +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); + static int luaB_print (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ diff --git a/third_party/lua/lcode.c b/third_party/lua/lcode.c index b448fd185..1e54b3f6a 100644 --- a/third_party/lua/lcode.c +++ b/third_party/lua/lcode.c @@ -1,12 +1,32 @@ -/* -** $Id: lcode.c $ -** Code generator for Lua -** See Copyright Notice in lua.h -*/ - +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ #define lcode_c #define LUA_CORE - #include "libc/fmt/conv.h" #include "third_party/lua/lcode.h" #include "third_party/lua/ldebug.h" @@ -22,8 +42,13 @@ #include "third_party/lua/ltable.h" #include "third_party/lua/lua.h" #include "third_party/lua/lvm.h" +// clang-format off + +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); -/* clang-format off */ /* Maximum number of registers in a Lua function (must fit in 8 bits) */ #define MAXREGS 255 diff --git a/third_party/lua/lcode.h b/third_party/lua/lcode.h index 5538136da..fe7da153a 100644 --- a/third_party/lua/lcode.h +++ b/third_party/lua/lcode.h @@ -1,9 +1,3 @@ -/* -** $Id: lcode.h $ -** Code generator for Lua -** See Copyright Notice in lua.h -*/ - #ifndef lcode_h #define lcode_h diff --git a/third_party/lua/lcorolib.c b/third_party/lua/lcorolib.c index 9c34df9ba..6cb615f10 100644 --- a/third_party/lua/lcorolib.c +++ b/third_party/lua/lcorolib.c @@ -1,18 +1,43 @@ -/* -** $Id: lcorolib.c $ -** Coroutine Library -** See Copyright Notice in lua.h -*/ - +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ #define lcorolib_c #define LUA_LIB - #include "third_party/lua/lauxlib.h" #include "third_party/lua/lprefix.h" #include "third_party/lua/lua.h" #include "third_party/lua/lualib.h" +// clang-format off + +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); -/* clang-format off */ static lua_State *getco (lua_State *L) { lua_State *co = lua_tothread(L, 1); diff --git a/third_party/lua/lctype.c b/third_party/lua/lctype.c deleted file mode 100644 index 373e56bc5..000000000 --- a/third_party/lua/lctype.c +++ /dev/null @@ -1,63 +0,0 @@ -/* -** $Id: lctype.c $ -** 'ctype' functions for Lua -** See Copyright Notice in lua.h -*/ - -#define lctype_c -#define LUA_CORE - -#include "third_party/lua/lctype.h" -#include "third_party/lua/lprefix.h" - -/* clang-format off */ - -#if !LUA_USE_CTYPE /* { */ - - - -#if defined (LUA_UCID) /* accept UniCode IDentifiers? */ -/* consider all non-ascii codepoints to be alphabetic */ -#define NONA 0x01 -#else -#define NONA 0x00 /* default */ -#endif - - -LUAI_DDEF const lu_byte luai_ctype_[UCHAR_MAX + 2] = { - 0x00, /* EOZ */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0. */ - 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, /* 2. */ - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, /* 3. */ - 0x16, 0x16, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 4. */ - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 5. */ - 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x05, - 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 6. */ - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 7. */ - 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x00, - NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* 8. */ - NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, - NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* 9. */ - NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, - NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* a. */ - NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, - NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* b. */ - NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, - 0x00, 0x00, NONA, NONA, NONA, NONA, NONA, NONA, /* c. */ - NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, - NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* d. */ - NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, - NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* e. */ - NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, - NONA, NONA, NONA, NONA, NONA, 0x00, 0x00, 0x00, /* f. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -#endif /* } */ diff --git a/third_party/lua/lctype.h b/third_party/lua/lctype.h index 472a5fb73..b4988a444 100644 --- a/third_party/lua/lctype.h +++ b/third_party/lua/lctype.h @@ -1,100 +1,54 @@ -/* -** $Id: lctype.h $ -** 'ctype' functions for Lua -** See Copyright Notice in lua.h -*/ - #ifndef lctype_h #define lctype_h - #include "third_party/lua/lua.h" -/* clang-format off */ - -/* -** WARNING: the functions defined here do not necessarily correspond -** to the similar functions in the standard C ctype.h. They are -** optimized for the specific needs of Lua. -*/ - -#if !defined(LUA_USE_CTYPE) - -#if 'A' == 65 && '0' == 48 -/* ASCII case: can use its own tables; faster and fixed */ -#define LUA_USE_CTYPE 0 -#else -/* must use standard C ctype */ -#define LUA_USE_CTYPE 1 -#endif - -#endif - - -#if !LUA_USE_CTYPE /* { */ - - -#include "third_party/lua/llimits.h" - - -#define ALPHABIT 0 -#define DIGITBIT 1 -#define PRINTBIT 2 -#define SPACEBIT 3 -#define XDIGITBIT 4 - - -#define MASK(B) (1 << (B)) - - -/* -** add 1 to char to allow index -1 (EOZ) -*/ -#define testprop(c,p) (luai_ctype_[(c)+1] & (p)) - -/* -** 'lalpha' (Lua alphabetic) and 'lalnum' (Lua alphanumeric) both include '_' -*/ -#define lislalpha(c) testprop(c, MASK(ALPHABIT)) -#define lislalnum(c) testprop(c, (MASK(ALPHABIT) | MASK(DIGITBIT))) -#define lisdigit(c) testprop(c, MASK(DIGITBIT)) -#define lisspace(c) testprop(c, MASK(SPACEBIT)) -#define lisprint(c) testprop(c, MASK(PRINTBIT)) -#define lisxdigit(c) testprop(c, MASK(XDIGITBIT)) - - /* ** In ASCII, this 'ltolower' is correct for alphabetic characters and ** for '.'. That is enough for Lua needs. ('check_exp' ensures that ** the character either is an upper-case letter or is unchanged by ** the transformation, which holds for lower-case letters and '.'.) */ -#define ltolower(c) \ - check_exp(('A' <= (c) && (c) <= 'Z') || (c) == ((c) | ('A' ^ 'a')), \ +#define ltolower(c) \ + check_exp(('A' <= (c) && (c) <= 'Z') || (c) == ((c) | ('A' ^ 'a')), \ (c) | ('A' ^ 'a')) +#define lisdigit(C) \ + ({ \ + unsigned char c_ = (C); \ + '0' <= c_&& c_ <= '9'; \ + }) -/* one entry for each character and for -1 (EOZ) */ -LUAI_DDEC(const lu_byte luai_ctype_[UCHAR_MAX + 2];) +#define lislalpha(C) \ + ({ \ + unsigned char c_ = (C); \ + ('A' <= c_ && c_ <= 'Z') || ('a' <= c_ && c_ <= 'z') || c_ == '_'; \ + }) +#define lislalnum(C) \ + ({ \ + unsigned char c_ = (C); \ + (('0' <= c_ && c_ <= '9') || ('A' <= c_ && c_ <= 'Z') || \ + ('a' <= c_ && c_ <= 'z') || c_ == '_'); \ + }) -#else /* }{ */ +#define lisspace(C) \ + ({ \ + unsigned char c_ = (C); \ + (c_ == ' ' || c_ == '\t' || c_ == '\r' || c_ == '\n' || c_ == '\f' || \ + c_ == '\v'); \ + }) -/* -** use standard C ctypes -*/ +#define lisxdigit(C) \ + ({ \ + unsigned char c_ = (C); \ + (('0' <= c_ && c_ <= '9') || ('A' <= c_ && c_ <= 'F') || \ + ('a' <= c_ && c_ <= 'f')); \ + }) - - -#define lislalpha(c) (isalpha(c) || (c) == '_') -#define lislalnum(c) (isalnum(c) || (c) == '_') -#define lisdigit(c) (isdigit(c)) -#define lisspace(c) (isspace(c)) -#define lisprint(c) (isprint(c)) -#define lisxdigit(c) (isxdigit(c)) - -#define ltolower(c) (tolower(c)) - -#endif /* } */ +#define lisprint(C) \ + ({ \ + unsigned char c_ = (C); \ + 32 <= c_&& c_ <= 126; \ + }) #endif - diff --git a/third_party/lua/ldblib.c b/third_party/lua/ldblib.c index ed9c48d31..8cdde9f90 100644 --- a/third_party/lua/ldblib.c +++ b/third_party/lua/ldblib.c @@ -1,20 +1,42 @@ -/* -** $Id: ldblib.c $ -** Interface from Lua to its debug API -** See Copyright Notice in lua.h -*/ - +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ #define ldblib_c #define LUA_LIB - -#include "third_party/lua/lprefix.h" - - - -#include "third_party/lua/lua.h" - #include "third_party/lua/lauxlib.h" +#include "third_party/lua/lprefix.h" +#include "third_party/lua/lua.h" #include "third_party/lua/lualib.h" +// clang-format off + +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); /* @@ -477,4 +499,3 @@ LUAMOD_API int luaopen_debug (lua_State *L) { luaL_newlib(L, dblib); return 1; } - diff --git a/third_party/lua/ldebug.c b/third_party/lua/ldebug.c index 1f2c0785c..7d710db75 100644 --- a/third_party/lua/ldebug.c +++ b/third_party/lua/ldebug.c @@ -1,18 +1,32 @@ -/* -** $Id: ldebug.c $ -** Debug Interface -** See Copyright Notice in lua.h -*/ - +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ #define ldebug_c #define LUA_CORE - -#include "third_party/lua/lprefix.h" - - - -#include "third_party/lua/lua.h" - #include "third_party/lua/lapi.h" #include "third_party/lua/lcode.h" #include "third_party/lua/ldebug.h" @@ -20,12 +34,19 @@ #include "third_party/lua/lfunc.h" #include "third_party/lua/lobject.h" #include "third_party/lua/lopcodes.h" +#include "third_party/lua/lprefix.h" #include "third_party/lua/lstate.h" #include "third_party/lua/lstring.h" #include "third_party/lua/ltable.h" #include "third_party/lua/ltm.h" +#include "third_party/lua/lua.h" #include "third_party/lua/lvm.h" +// clang-format off +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); #define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_VCCL) diff --git a/third_party/lua/ldebug.h b/third_party/lua/ldebug.h index e6a1a17ed..fb87123e7 100644 --- a/third_party/lua/ldebug.h +++ b/third_party/lua/ldebug.h @@ -1,9 +1,3 @@ -/* -** $Id: ldebug.h $ -** Auxiliary functions from Debug Interface module -** See Copyright Notice in lua.h -*/ - #ifndef ldebug_h #define ldebug_h diff --git a/third_party/lua/ldo.c b/third_party/lua/ldo.c index 0ebffb139..e873e6de8 100644 --- a/third_party/lua/ldo.c +++ b/third_party/lua/ldo.c @@ -1,12 +1,32 @@ -/* -** $Id: ldo.c $ -** Stack and Call structure of Lua -** See Copyright Notice in lua.h -*/ - +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ #define ldo_c #define LUA_CORE - #include "libc/runtime/gc.h" #include "third_party/lua/lapi.h" #include "third_party/lua/ldebug.h" @@ -26,8 +46,12 @@ #include "third_party/lua/lundump.h" #include "third_party/lua/lvm.h" #include "third_party/lua/lzio.h" +// clang-format off -/* clang-format off */ +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); #define errorstatus(s) ((s) > LUA_YIELD) diff --git a/third_party/lua/ldo.h b/third_party/lua/ldo.h index 209f7b60f..5a5bff6a8 100644 --- a/third_party/lua/ldo.h +++ b/third_party/lua/ldo.h @@ -1,9 +1,3 @@ -/* -** $Id: ldo.h $ -** Stack and Call structure of Lua -** See Copyright Notice in lua.h -*/ - #ifndef ldo_h #define ldo_h diff --git a/third_party/lua/ldump.c b/third_party/lua/ldump.c index 0fb11c043..05c2c1cab 100644 --- a/third_party/lua/ldump.c +++ b/third_party/lua/ldump.c @@ -1,19 +1,44 @@ -/* -** $Id: ldump.c $ -** save precompiled Lua chunks -** See Copyright Notice in lua.h -*/ - +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ #define ldump_c #define LUA_CORE - #include "third_party/lua/lobject.h" #include "third_party/lua/lprefix.h" #include "third_party/lua/lstate.h" #include "third_party/lua/lua.h" #include "third_party/lua/lundump.h" +// clang-format off + +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); -/* clang-format off */ typedef struct { lua_State *L; diff --git a/third_party/lua/lfunc.c b/third_party/lua/lfunc.c index 0b5d66d59..cedce1480 100644 --- a/third_party/lua/lfunc.c +++ b/third_party/lua/lfunc.c @@ -1,12 +1,32 @@ -/* -** $Id: lfunc.c $ -** Auxiliary functions to manipulate prototypes and closures -** See Copyright Notice in lua.h -*/ - +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ #define lfunc_c #define LUA_CORE - #include "third_party/lua/ldebug.h" #include "third_party/lua/ldo.h" #include "third_party/lua/lfunc.h" @@ -17,8 +37,13 @@ #include "third_party/lua/lstate.h" #include "third_party/lua/ltm.h" #include "third_party/lua/lua.h" +// clang-format off + +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); -/* clang-format off */ CClosure *luaF_newCclosure (lua_State *L, int nupvals) { GCObject *o = luaC_newobj(L, LUA_VCCL, sizeCclosure(nupvals)); diff --git a/third_party/lua/lfunc.h b/third_party/lua/lfunc.h index ba8839496..4f15eb98b 100644 --- a/third_party/lua/lfunc.h +++ b/third_party/lua/lfunc.h @@ -1,9 +1,3 @@ -/* -** $Id: lfunc.h $ -** Auxiliary functions to manipulate prototypes and closures -** See Copyright Notice in lua.h -*/ - #ifndef lfunc_h #define lfunc_h diff --git a/third_party/lua/lgc.c b/third_party/lua/lgc.c index da7894b72..224f15ab5 100644 --- a/third_party/lua/lgc.c +++ b/third_party/lua/lgc.c @@ -1,12 +1,32 @@ -/* -** $Id: lgc.c $ -** Garbage Collector -** See Copyright Notice in lua.h -*/ - +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ #define lgc_c #define LUA_CORE - #include "third_party/lua/ldebug.h" #include "third_party/lua/ldo.h" #include "third_party/lua/lfunc.h" @@ -19,8 +39,13 @@ #include "third_party/lua/ltable.h" #include "third_party/lua/ltm.h" #include "third_party/lua/lua.h" +// clang-format off + +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); -/* clang-format off */ /* ** Maximum number of elements to sweep in each single step. diff --git a/third_party/lua/lgc.h b/third_party/lua/lgc.h index 2e1b59ecb..efe88f329 100644 --- a/third_party/lua/lgc.h +++ b/third_party/lua/lgc.h @@ -1,9 +1,3 @@ -/* -** $Id: lgc.h $ -** Garbage Collector -** See Copyright Notice in lua.h -*/ - #ifndef lgc_h #define lgc_h diff --git a/third_party/lua/linit.c b/third_party/lua/linit.c index 3cca5c479..f64dd1327 100644 --- a/third_party/lua/linit.c +++ b/third_party/lua/linit.c @@ -1,12 +1,32 @@ -/* -** $Id: linit.c $ -** Initialization of libraries for lua.c and other clients -** See Copyright Notice in lua.h -*/ - +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ #define linit_c #define LUA_LIB - /* ** If you embed Lua in your program and need to open the standard ** libraries, call luaL_openlibs in your program. If you need a @@ -22,13 +42,17 @@ ** lua_setfield(L, -2, modname); ** lua_pop(L, 1); // remove PRELOAD table */ - #include "third_party/lua/lauxlib.h" #include "third_party/lua/lprefix.h" #include "third_party/lua/lua.h" #include "third_party/lua/lualib.h" +// clang-format off + +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); -/* clang-format off */ /* ** these libs are loaded by lua.c and are readily available to any Lua diff --git a/third_party/lua/liolib.c b/third_party/lua/liolib.c index 8974e2823..92027cb1b 100644 --- a/third_party/lua/liolib.c +++ b/third_party/lua/liolib.c @@ -1,12 +1,32 @@ -/* -** $Id: liolib.c $ -** Standard I/O (and system) library -** See Copyright Notice in lua.h -*/ - +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ #define liolib_c #define LUA_LIB - #include "libc/calls/calls.h" #include "libc/calls/weirdtypes.h" #include "libc/errno.h" @@ -16,8 +36,13 @@ #include "third_party/lua/lprefix.h" #include "third_party/lua/lua.h" #include "third_party/lua/lualib.h" +// clang-format off + +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); -/* clang-format off */ /* ** Change this macro to accept other modes for 'fopen' besides diff --git a/third_party/lua/llex.c b/third_party/lua/llex.c index 535f4cfee..337adf666 100644 --- a/third_party/lua/llex.c +++ b/third_party/lua/llex.c @@ -1,12 +1,32 @@ -/* -** $Id: llex.c $ -** Lexical Analyzer -** See Copyright Notice in lua.h -*/ - +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ #define llex_c #define LUA_CORE - #include "third_party/lua/lctype.h" #include "third_party/lua/ldebug.h" #include "third_party/lua/ldo.h" @@ -20,8 +40,12 @@ #include "third_party/lua/ltable.h" #include "third_party/lua/lua.h" #include "third_party/lua/lzio.h" +// clang-format off -/* clang-format off */ +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); #define next(ls) (ls->current = zgetc(ls->z)) diff --git a/third_party/lua/llimits.h b/third_party/lua/llimits.h index babd88ae2..941ea9219 100644 --- a/third_party/lua/llimits.h +++ b/third_party/lua/llimits.h @@ -1,9 +1,3 @@ -/* -** $Id: llimits.h $ -** Limits, basic types, and some other 'installation-dependent' definitions -** See Copyright Notice in lua.h -*/ - #ifndef llimits_h #define llimits_h diff --git a/third_party/lua/lmathlib.c b/third_party/lua/lmathlib.c index ac8d6070c..9e0ee7305 100644 --- a/third_party/lua/lmathlib.c +++ b/third_party/lua/lmathlib.c @@ -1,12 +1,32 @@ -/* -** $Id: lmathlib.c $ -** Standard mathematical library -** See Copyright Notice in lua.h -*/ - +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ #define lmathlib_c #define LUA_LIB - #include "libc/math.h" #include "libc/nt/struct/msg.h" #include "libc/time/time.h" @@ -14,8 +34,13 @@ #include "third_party/lua/lprefix.h" #include "third_party/lua/lua.h" #include "third_party/lua/lualib.h" +// clang-format off + +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); -/* clang-format off */ #undef PI #define PI (l_mathop(3.141592653589793238462643383279502884)) diff --git a/third_party/lua/lmem.c b/third_party/lua/lmem.c index 58a98fbe9..c83b25f86 100644 --- a/third_party/lua/lmem.c +++ b/third_party/lua/lmem.c @@ -1,12 +1,32 @@ -/* -** $Id: lmem.c $ -** Interface to Memory Manager -** See Copyright Notice in lua.h -*/ - +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ #define lmem_c #define LUA_CORE - #include "third_party/lua/ldebug.h" #include "third_party/lua/ldo.h" #include "third_party/lua/lgc.h" @@ -15,8 +35,13 @@ #include "third_party/lua/lprefix.h" #include "third_party/lua/lstate.h" #include "third_party/lua/lua.h" +// clang-format off + +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); -/* clang-format off */ #if defined(EMERGENCYGCTESTS) /* diff --git a/third_party/lua/lmem.h b/third_party/lua/lmem.h index 3b4b66dd2..e3b4f4d01 100644 --- a/third_party/lua/lmem.h +++ b/third_party/lua/lmem.h @@ -1,9 +1,3 @@ -/* -** $Id: lmem.h $ -** Interface to Memory Manager -** See Copyright Notice in lua.h -*/ - #ifndef lmem_h #define lmem_h diff --git a/third_party/lua/loadlib.c b/third_party/lua/loadlib.c index ae7631f9a..10b69877c 100644 --- a/third_party/lua/loadlib.c +++ b/third_party/lua/loadlib.c @@ -1,24 +1,52 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#define loadlib_c +#define LUA_LIB +#include "third_party/lua/lauxlib.h" +#include "third_party/lua/lprefix.h" +#include "third_party/lua/lua.h" +#include "third_party/lua/lualib.h" +// clang-format off + +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); + /* -** $Id: loadlib.c $ -** Dynamic library loader for Lua -** See Copyright Notice in lua.h -** ** This module contains an implementation of loadlib for Unix systems ** that have dlfcn, an implementation for Windows, and a stub for other ** systems. */ -#define loadlib_c -#define LUA_LIB - -#include "third_party/lua/lauxlib.h" -#include "third_party/lua/lprefix.h" -#include "third_party/lua/lua.h" -#include "third_party/lua/lualib.h" const char *g_lua_path_default = LUA_PATH_DEFAULT; -/* clang-format off */ /* ** LUA_IGMARK is a mark to ignore all before it when building the diff --git a/third_party/lua/lobject.c b/third_party/lua/lobject.c index ff67a677c..efadd9002 100644 --- a/third_party/lua/lobject.c +++ b/third_party/lua/lobject.c @@ -1,12 +1,32 @@ -/* -** $Id: lobject.c $ -** Some generic functions over Lua objects -** See Copyright Notice in lua.h -*/ - +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ #define lobject_c #define LUA_CORE - #include "libc/intrin/kprintf.h" #include "third_party/lua/lctype.h" #include "third_party/lua/ldebug.h" @@ -18,8 +38,12 @@ #include "third_party/lua/lstring.h" #include "third_party/lua/lua.h" #include "third_party/lua/lvm.h" +// clang-format off -/* clang-format off */ +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); static lua_Integer intarith (lua_State *L, int op, lua_Integer v1, diff --git a/third_party/lua/lobject.h b/third_party/lua/lobject.h index 0514a80fe..2f784103d 100644 --- a/third_party/lua/lobject.h +++ b/third_party/lua/lobject.h @@ -1,9 +1,3 @@ -/* -** $Id: lobject.h $ -** Type definitions for Lua objects -** See Copyright Notice in lua.h -*/ - #ifndef lobject_h #define lobject_h diff --git a/third_party/lua/lopcodes.c b/third_party/lua/lopcodes.c index f9eca6ae5..9af17c352 100644 --- a/third_party/lua/lopcodes.c +++ b/third_party/lua/lopcodes.c @@ -1,16 +1,41 @@ -/* -** $Id: lopcodes.c $ -** Opcodes for Lua virtual machine -** See Copyright Notice in lua.h -*/ - +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ #define lopcodes_c #define LUA_CORE - #include "third_party/lua/lopcodes.h" #include "third_party/lua/lprefix.h" +// clang-format off + +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); -/* clang-format off */ /* ORDER OP */ diff --git a/third_party/lua/lopcodes.h b/third_party/lua/lopcodes.h index 2c5ef28db..7ae716b85 100644 --- a/third_party/lua/lopcodes.h +++ b/third_party/lua/lopcodes.h @@ -1,9 +1,3 @@ -/* -** $Id: lopcodes.h $ -** Opcodes for Lua virtual machine -** See Copyright Notice in lua.h -*/ - #ifndef lopcodes_h #define lopcodes_h diff --git a/third_party/lua/loslib.c b/third_party/lua/loslib.c index 1373637fe..314d0308d 100644 --- a/third_party/lua/loslib.c +++ b/third_party/lua/loslib.c @@ -1,12 +1,32 @@ -/* -** $Id: loslib.c $ -** Standard Operating System library -** See Copyright Notice in lua.h -*/ - +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ #define loslib_c #define LUA_LIB - #include "libc/calls/calls.h" #include "libc/calls/weirdtypes.h" #include "libc/errno.h" @@ -20,8 +40,13 @@ #include "third_party/lua/lprefix.h" #include "third_party/lua/lua.h" #include "third_party/lua/lualib.h" +// clang-format off + +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); -/* clang-format off */ /* ** {================================================================== diff --git a/third_party/lua/lparser.c b/third_party/lua/lparser.c index 4cf90cca2..ca933328e 100644 --- a/third_party/lua/lparser.c +++ b/third_party/lua/lparser.c @@ -1,12 +1,32 @@ -/* -** $Id: lparser.c $ -** Lua Parser -** See Copyright Notice in lua.h -*/ - +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ #define lparser_c #define LUA_CORE - #include "third_party/lua/lcode.h" #include "third_party/lua/ldebug.h" #include "third_party/lua/ldo.h" @@ -21,8 +41,12 @@ #include "third_party/lua/lstring.h" #include "third_party/lua/ltable.h" #include "third_party/lua/lua.h" +// clang-format off -/* clang-format off */ +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); /* maximum number of local variables per function (must be smaller diff --git a/third_party/lua/lparser.h b/third_party/lua/lparser.h index f6244474c..96ad3bc31 100644 --- a/third_party/lua/lparser.h +++ b/third_party/lua/lparser.h @@ -1,9 +1,3 @@ -/* -** $Id: lparser.h $ -** Lua Parser -** See Copyright Notice in lua.h -*/ - #ifndef lparser_h #define lparser_h diff --git a/third_party/lua/lprefix.h b/third_party/lua/lprefix.h index 484f2ad6f..373580fe4 100644 --- a/third_party/lua/lprefix.h +++ b/third_party/lua/lprefix.h @@ -1,45 +1,36 @@ -/* -** $Id: lprefix.h $ -** Definitions for Lua code that must come before any other header file -** See Copyright Notice in lua.h -*/ - #ifndef lprefix_h #define lprefix_h - /* ** Allows POSIX/XSI stuff */ -#if !defined(LUA_USE_C89) /* { */ +#if !defined(LUA_USE_C89) /* { */ #if !defined(_XOPEN_SOURCE) -#define _XOPEN_SOURCE 600 +#define _XOPEN_SOURCE 600 #elif _XOPEN_SOURCE == 0 -#undef _XOPEN_SOURCE /* use -D_XOPEN_SOURCE=0 to undefine it */ +#undef _XOPEN_SOURCE /* use -D_XOPEN_SOURCE=0 to undefine it */ #endif /* ** Allows manipulation of large files in gcc and some other compilers */ #if !defined(LUA_32BITS) && !defined(_FILE_OFFSET_BITS) -#define _LARGEFILE_SOURCE 1 -#define _FILE_OFFSET_BITS 64 +#define _LARGEFILE_SOURCE 1 +#define _FILE_OFFSET_BITS 64 #endif -#endif /* } */ - +#endif /* } */ /* ** Windows stuff */ -#if defined(_WIN32) /* { */ +#if defined(_WIN32) /* { */ #if !defined(_CRT_SECURE_NO_WARNINGS) -#define _CRT_SECURE_NO_WARNINGS /* avoid warnings about ISO C functions */ +#define _CRT_SECURE_NO_WARNINGS /* avoid warnings about ISO C functions */ #endif -#endif /* } */ +#endif /* } */ #endif - diff --git a/third_party/lua/lrepl.c b/third_party/lua/lrepl.c index 4b446c088..0fb0d1372 100644 --- a/third_party/lua/lrepl.c +++ b/third_party/lua/lrepl.c @@ -1,9 +1,36 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ #define lua_c +#include "libc/alg/alg.h" #include "libc/calls/calls.h" #include "libc/calls/sigbits.h" #include "libc/intrin/kprintf.h" #include "libc/intrin/nomultics.internal.h" -#include "libc/intrin/spinlock.h" #include "libc/log/check.h" #include "libc/runtime/gc.h" #include "libc/runtime/runtime.h" @@ -12,13 +39,21 @@ #include "third_party/linenoise/linenoise.h" #include "third_party/lua/lauxlib.h" #include "third_party/lua/lprefix.h" +#include "third_party/lua/lrepl.h" #include "third_party/lua/lua.h" #include "third_party/lua/lualib.h" // clang-format off +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); + + bool lua_repl_blocking; bool lua_repl_isterminal; -_Alignas(64) char lualock; +linenoiseCompletionCallback *lua_repl_completions_callback; +_Alignas(64) char lua_repl_lock; struct linenoiseState *lua_repl_linenoise; static lua_State *globalL; static const char *g_progname; @@ -63,6 +98,7 @@ void lua_readline_completions(const char *p, linenoiseCompletions *c) { lua_pop(L, 1); } lua_pop(L, 1); + lua_repl_completions_callback(p, c); } char *lua_readline_hint(const char *p, const char **ansi1, const char **ansi2) { @@ -128,7 +164,7 @@ static ssize_t pushline (lua_State *L, int firstline) { if (lua_repl_isterminal) { prmt = strdup(get_prompt(L, firstline)); lua_pop(L, 1); /* remove prompt */ - _spunlock(&lualock); + LUA_REPL_UNLOCK; rc = linenoiseEdit(lua_repl_linenoise, prmt, &b, !firstline || lua_repl_blocking); free(prmt); if (rc != -1) { @@ -138,11 +174,11 @@ static ssize_t pushline (lua_State *L, int firstline) { linenoiseHistorySave(g_historypath); } } - _spinlock(&lualock); + LUA_REPL_LOCK; } else { - _spunlock(&lualock); + LUA_REPL_UNLOCK; b = linenoiseGetLine(stdin); - _spinlock(&lualock); + LUA_REPL_LOCK; rc = b ? 1 : -1; } if (rc == -1 || (!rc && !b)) { @@ -208,7 +244,7 @@ static int multiline (lua_State *L) { void lua_initrepl(lua_State *L, const char *progname) { const char *prompt; - _spinlock(&lualock); + LUA_REPL_LOCK; g_progname = progname; if ((lua_repl_isterminal = linenoiseIsTerminal())) { linenoiseSetCompletionCallback(lua_readline_completions); @@ -224,20 +260,18 @@ void lua_initrepl(lua_State *L, const char *progname) { } lua_repl_linenoise = linenoiseBegin(prompt, 0, 1); lua_pop(L, 1); /* remove prompt */ - __nomultics = 2; __replmode = true; } - _spunlock(&lualock); + LUA_REPL_UNLOCK; } void lua_freerepl(void) { - _spinlock(&lualock); - __nomultics = false; + LUA_REPL_LOCK; __replmode = false; linenoiseEnd(lua_repl_linenoise); free(g_historypath); - _spunlock(&lualock); + LUA_REPL_UNLOCK; } @@ -254,16 +288,16 @@ int lua_loadline (lua_State *L) { ssize_t rc; int status; lua_settop(L, 0); - _spinlock(&lualock); + LUA_REPL_LOCK; if ((rc = pushline(L, 1)) != 1) { - _spunlock(&lualock); + LUA_REPL_UNLOCK; return rc - 1; /* eof or error */ } if ((status = addreturn(L)) != LUA_OK) /* 'return ...' did not work? */ status = multiline(L); /* try as command, maybe with continuation lines */ lua_remove(L, 1); /* remove line from the stack */ lua_assert(lua_gettop(L) == 1); - _spunlock(&lualock); + LUA_REPL_UNLOCK; return status; } diff --git a/third_party/lua/lrepl.h b/third_party/lua/lrepl.h index f1d6ac11c..5de303a7a 100644 --- a/third_party/lua/lrepl.h +++ b/third_party/lua/lrepl.h @@ -1,14 +1,29 @@ #ifndef COSMOPOLITAN_THIRD_PARTY_LUA_LREPL_H_ #define COSMOPOLITAN_THIRD_PARTY_LUA_LREPL_H_ +#include "libc/dce.h" +#include "libc/intrin/spinlock.h" #include "third_party/linenoise/linenoise.h" #include "third_party/lua/lauxlib.h" #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -extern char lualock; +#if !defined(STATIC) && SupportsWindows() +#define LUA_REPL_LOCK _spinlock(&lua_repl_lock) +#else +#define LUA_REPL_LOCK (void)0 +#endif + +#if !defined(STATIC) && SupportsWindows() +#define LUA_REPL_UNLOCK _spunlock(&lua_repl_lock) +#else +#define LUA_REPL_UNLOCK (void)0 +#endif + +extern char lua_repl_lock; extern bool lua_repl_blocking; extern bool lua_repl_isterminal; extern struct linenoiseState *lua_repl_linenoise; +extern linenoiseCompletionCallback *lua_repl_completions_callback; void lua_freerepl(void); int lua_loadline(lua_State *); diff --git a/third_party/lua/lstate.c b/third_party/lua/lstate.c index db3871d69..100766934 100644 --- a/third_party/lua/lstate.c +++ b/third_party/lua/lstate.c @@ -1,12 +1,32 @@ -/* -** $Id: lstate.c $ -** Global State -** See Copyright Notice in lua.h -*/ - +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ #define lstate_c #define LUA_CORE - #include "libc/time/time.h" #include "third_party/lua/lapi.h" #include "third_party/lua/ldebug.h" @@ -21,8 +41,13 @@ #include "third_party/lua/ltable.h" #include "third_party/lua/ltm.h" #include "third_party/lua/lua.h" +// clang-format off + +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); -/* clang-format off */ /* ** thread state + extra space diff --git a/third_party/lua/lstate.h b/third_party/lua/lstate.h index e5d5096ef..b0b7cd17f 100644 --- a/third_party/lua/lstate.h +++ b/third_party/lua/lstate.h @@ -1,9 +1,3 @@ -/* -** $Id: lstate.h $ -** Global State -** See Copyright Notice in lua.h -*/ - #ifndef lstate_h #define lstate_h diff --git a/third_party/lua/lstring.c b/third_party/lua/lstring.c index 3ea66a5f8..d5cfcf764 100644 --- a/third_party/lua/lstring.c +++ b/third_party/lua/lstring.c @@ -1,12 +1,32 @@ -/* -** $Id: lstring.c $ -** String table (keeps all strings handled by Lua) -** See Copyright Notice in lua.h -*/ - +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ #define lstring_c #define LUA_CORE - #include "third_party/lua/ldebug.h" #include "third_party/lua/ldo.h" #include "third_party/lua/lmem.h" @@ -15,8 +35,13 @@ #include "third_party/lua/lstate.h" #include "third_party/lua/lstring.h" #include "third_party/lua/lua.h" +// clang-format off + +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); -/* clang-format off */ /* ** Maximum size for string table. diff --git a/third_party/lua/lstring.h b/third_party/lua/lstring.h index 00d632865..d9cd11ada 100644 --- a/third_party/lua/lstring.h +++ b/third_party/lua/lstring.h @@ -1,9 +1,3 @@ -/* -** $Id: lstring.h $ -** String table (keep all strings handled by Lua) -** See Copyright Notice in lua.h -*/ - #ifndef lstring_h #define lstring_h diff --git a/third_party/lua/lstrlib.c b/third_party/lua/lstrlib.c index 0b503196b..e49444ea2 100644 --- a/third_party/lua/lstrlib.c +++ b/third_party/lua/lstrlib.c @@ -1,19 +1,44 @@ -/* -** $Id: lstrlib.c $ -** Standard library for string operations and pattern-matching -** See Copyright Notice in lua.h -*/ - +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ #define lstrlib_c #define LUA_LIB - #include "libc/math.h" +#include "third_party/lua/cosmo.h" #include "third_party/lua/lauxlib.h" #include "third_party/lua/lprefix.h" #include "third_party/lua/lua.h" #include "third_party/lua/lualib.h" +// clang-format off -/* clang-format off */ +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); /* @@ -41,6 +66,8 @@ +static int str_format(lua_State *); + static int str_len (lua_State *L) { size_t l; @@ -297,7 +324,21 @@ static int arith_mul (lua_State *L) { } static int arith_mod (lua_State *L) { - return arith(L, LUA_OPMOD, "__mod"); + int i, n; + if (lua_istable(L, 2)) { // [jart] python printf operator + lua_len(L, 2); + n = lua_tointeger(L, -1); + lua_pop(L, 1); + lua_pushcfunction(L, str_format); + lua_pushvalue(L, 1); + for (i = 1; i <= n; ++i) { + lua_geti(L, 2, i); + } + lua_call(L, 1 + n, 1); + return 1; + } else { + return arith(L, LUA_OPMOD, "__mod"); + } } static int arith_pow (lua_State *L) { @@ -536,7 +577,7 @@ static const char *start_capture (MatchState *ms, const char *s, static const char *end_capture (MatchState *ms, const char *s, - const char *p) { + const char *p) { int l = capture_to_close(ms); const char *res; ms->capture[l].len = s - ms->capture[l].init; /* close capture */ diff --git a/third_party/lua/ltable.c b/third_party/lua/ltable.c index 4d021a141..a5bf84153 100644 --- a/third_party/lua/ltable.c +++ b/third_party/lua/ltable.c @@ -1,12 +1,32 @@ -/* -** $Id: ltable.c $ -** Lua tables (hash) -** See Copyright Notice in lua.h -*/ - +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ #define ltable_c #define LUA_CORE - #include "third_party/lua/ldebug.h" #include "third_party/lua/ldo.h" #include "third_party/lua/lgc.h" @@ -18,8 +38,13 @@ #include "third_party/lua/ltable.h" #include "third_party/lua/lua.h" #include "third_party/lua/lvm.h" +// clang-format off + +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); -/* clang-format off */ /* ** Implementation of tables (aka arrays, objects, or hash tables). diff --git a/third_party/lua/ltable.h b/third_party/lua/ltable.h index f5d462601..7b4014e14 100644 --- a/third_party/lua/ltable.h +++ b/third_party/lua/ltable.h @@ -1,9 +1,3 @@ -/* -** $Id: ltable.h $ -** Lua tables (hash) -** See Copyright Notice in lua.h -*/ - #ifndef ltable_h #define ltable_h diff --git a/third_party/lua/ltablib.c b/third_party/lua/ltablib.c index 553f2a7e6..9edcc3f52 100644 --- a/third_party/lua/ltablib.c +++ b/third_party/lua/ltablib.c @@ -1,20 +1,45 @@ -/* -** $Id: ltablib.c $ -** Library for Table Manipulation -** See Copyright Notice in lua.h -*/ - +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ #define ltablib_c #define LUA_LIB - #include "libc/calls/weirdtypes.h" #include "libc/time/time.h" #include "third_party/lua/lauxlib.h" #include "third_party/lua/lprefix.h" #include "third_party/lua/lua.h" #include "third_party/lua/lualib.h" +// clang-format off + +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); -/* clang-format off */ /* ** Operations that an object must define to mimic a table diff --git a/third_party/lua/ltests.c b/third_party/lua/ltests.c index 7658c8c40..6b1606902 100644 --- a/third_party/lua/ltests.c +++ b/third_party/lua/ltests.c @@ -1,12 +1,32 @@ -/* -** $Id: ltests.c $ -** Internal Module for Debugging of the Lua Implementation -** See Copyright Notice in lua.h -*/ - +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ #define ltests_c #define LUA_CORE - #include "third_party/lua/lapi.h" #include "third_party/lua/lauxlib.h" #include "third_party/lua/lcode.h" @@ -23,8 +43,13 @@ #include "third_party/lua/ltable.h" #include "third_party/lua/lua.h" #include "third_party/lua/lualib.h" +// clang-format off + +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); -/* clang-format off */ /* ** The whole module only makes sense with LUA_DEBUG on diff --git a/third_party/lua/ltests.h b/third_party/lua/ltests.h index b8fab980a..20fe75070 100644 --- a/third_party/lua/ltests.h +++ b/third_party/lua/ltests.h @@ -1,12 +1,5 @@ -/* -** $Id: ltests.h $ -** Internal Header for Debugging of the Lua Implementation -** See Copyright Notice in lua.h -*/ - #ifndef ltests_h #define ltests_h - #include "third_party/lua/lua.h" /* clang-format off */ diff --git a/third_party/lua/ltm.c b/third_party/lua/ltm.c index 75f67c5f6..25becb214 100644 --- a/third_party/lua/ltm.c +++ b/third_party/lua/ltm.c @@ -1,12 +1,32 @@ -/* -** $Id: ltm.c $ -** Tag methods -** See Copyright Notice in lua.h -*/ - +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ #define ltm_c #define LUA_CORE - #include "third_party/lua/ldebug.h" #include "third_party/lua/ldo.h" #include "third_party/lua/lgc.h" @@ -18,8 +38,13 @@ #include "third_party/lua/ltm.h" #include "third_party/lua/lua.h" #include "third_party/lua/lvm.h" +// clang-format off + +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); -/* clang-format off */ static const char udatatypename[] = "userdata"; diff --git a/third_party/lua/ltm.h b/third_party/lua/ltm.h index aa8c3785e..0bc15fddf 100644 --- a/third_party/lua/ltm.h +++ b/third_party/lua/ltm.h @@ -1,16 +1,8 @@ -/* -** $Id: ltm.h $ -** Tag methods -** See Copyright Notice in lua.h -*/ - #ifndef ltm_h #define ltm_h - #include "third_party/lua/lobject.h" #include "third_party/lua/luaconf.h" #include "third_party/lua/tms.h" - /* clang-format off */ /* diff --git a/third_party/lua/lua.main.c b/third_party/lua/lua.main.c index 876d78ec7..afbc7280b 100644 --- a/third_party/lua/lua.main.c +++ b/third_party/lua/lua.main.c @@ -1,11 +1,31 @@ -/* -** $Id: lua.c $ -** Lua stand-alone interpreter -** See Copyright Notice in lua.h -*/ - +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ #define lua_c - #include "libc/calls/calls.h" #include "libc/calls/sigbits.h" #include "libc/calls/struct/sigaction.h" @@ -28,11 +48,15 @@ #include "third_party/lua/lrepl.h" #include "third_party/lua/lua.h" #include "third_party/lua/lualib.h" +// clang-format off + +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); STATIC_STACK_SIZE(0x40000); -/* clang-format off */ - #if !defined(LUA_PROGNAME) #define LUA_PROGNAME "lua" #endif diff --git a/third_party/lua/luac.main.c b/third_party/lua/luac.main.c index 7b3c23470..83b11dcbc 100644 --- a/third_party/lua/luac.main.c +++ b/third_party/lua/luac.main.c @@ -1,12 +1,32 @@ -/* -** $Id: luac.c $ -** Lua compiler (saves bytecodes to files; also lists bytecodes) -** See Copyright Notice in lua.h -*/ - +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ #define luac_c #define LUA_CORE - #include "libc/calls/calls.h" #include "libc/calls/sigbits.h" #include "libc/calls/struct/sigaction.h" @@ -22,8 +42,13 @@ #include "third_party/lua/lua.h" #include "third_party/lua/lualib.h" #include "third_party/lua/lundump.h" +// clang-format off + +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); -/* clang-format off */ static void PrintFunction(const Proto* f, int full); #define luaU_print PrintFunction diff --git a/third_party/lua/lualib.h b/third_party/lua/lualib.h index 7fa19122d..47dfc39e3 100644 --- a/third_party/lua/lualib.h +++ b/third_party/lua/lualib.h @@ -1,12 +1,5 @@ -/* -** $Id: lualib.h $ -** Lua standard libraries -** See Copyright Notice in lua.h -*/ - #ifndef lualib_h #define lualib_h - #include "third_party/lua/lua.h" /* clang-format off */ diff --git a/third_party/lua/luaprintstack.c b/third_party/lua/luaprintstack.c new file mode 100644 index 000000000..6d286fb4b --- /dev/null +++ b/third_party/lua/luaprintstack.c @@ -0,0 +1,31 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/stdio/stdio.h" +#include "third_party/lua/cosmo.h" +#include "third_party/lua/lua.h" + +/** + * Development tool for quickly viewing the Lua stack. + */ +void LuaPrintStack(lua_State *L) { + char *s = LuaFormatStack(L); + fputs(s, stderr); + fputc('\n', stderr); + free(s); +} diff --git a/third_party/lua/lundump.h b/third_party/lua/lundump.h index ee0dbe0ab..84fa58ab3 100644 --- a/third_party/lua/lundump.h +++ b/third_party/lua/lundump.h @@ -1,12 +1,5 @@ -/* -** $Id: lundump.h $ -** load precompiled Lua chunks -** See Copyright Notice in lua.h -*/ - #ifndef lundump_h #define lundump_h - #include "third_party/lua/llimits.h" #include "third_party/lua/lobject.h" #include "third_party/lua/lzio.h" diff --git a/third_party/lua/lvm.c b/third_party/lua/lvm.c index 7780b974a..f3bf1e711 100644 --- a/third_party/lua/lvm.c +++ b/third_party/lua/lvm.c @@ -1,12 +1,32 @@ -/* -** $Id: lvm.c $ -** Lua virtual machine -** See Copyright Notice in lua.h -*/ - +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ #define lvm_c #define LUA_CORE - #include "third_party/lua/ldebug.h" #include "third_party/lua/ldo.h" #include "third_party/lua/lfunc.h" @@ -20,8 +40,13 @@ #include "third_party/lua/ltm.h" #include "third_party/lua/lua.h" #include "third_party/lua/lvm.h" +// clang-format off + +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); -/* clang-format off */ /* ** By default, use jump tables in the main interpreter loop on gcc diff --git a/third_party/lua/lvm.h b/third_party/lua/lvm.h index 8fd25ed22..9abf879ce 100644 --- a/third_party/lua/lvm.h +++ b/third_party/lua/lvm.h @@ -1,12 +1,5 @@ -/* -** $Id: lvm.h $ -** Lua virtual machine -** See Copyright Notice in lua.h -*/ - #ifndef lvm_h #define lvm_h - #include "third_party/lua/ldo.h" #include "third_party/lua/lobject.h" #include "third_party/lua/ltm.h" diff --git a/third_party/lua/lzio.c b/third_party/lua/lzio.c index 622bf60b1..4857b0957 100644 --- a/third_party/lua/lzio.c +++ b/third_party/lua/lzio.c @@ -1,20 +1,45 @@ -/* -** $Id: lzio.c $ -** Buffered streams -** See Copyright Notice in lua.h -*/ - +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Lua │ +│ Copyright © 2004-2021 Lua.org, PUC-Rio. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ #define lzio_c #define LUA_CORE - #include "third_party/lua/llimits.h" #include "third_party/lua/lmem.h" #include "third_party/lua/lprefix.h" #include "third_party/lua/lstate.h" #include "third_party/lua/lua.h" #include "third_party/lua/lzio.h" +// clang-format off + +asm(".ident\t\"\\n\\n\ +Lua 5.4.3 (MIT License)\\n\ +Copyright 1994–2021 Lua.org, PUC-Rio.\""); +asm(".include \"libc/disclaimer.inc\""); -/* clang-format off */ int luaZ_fill (ZIO *z) { size_t size; diff --git a/third_party/python/Modules/termios.c b/third_party/python/Modules/termios.c index 63814c1b1..31a9a09ba 100644 --- a/third_party/python/Modules/termios.c +++ b/third_party/python/Modules/termios.c @@ -603,7 +603,7 @@ PyInit_termios(void) if (IXANY) PyModule_AddIntConstant(m, "IXANY", IXANY); if (IXOFF) PyModule_AddIntConstant(m, "IXOFF", IXOFF); if (IMAXBEL) PyModule_AddIntConstant(m, "IMAXBEL", IMAXBEL); - if (OPOST) PyModule_AddIntConstant(m, "OPOST", OPOST); + PyModule_AddIntConstant(m, "OPOST", OPOST); if (OLCUC) PyModule_AddIntConstant(m, "OLCUC", OLCUC); if (ONLCR) PyModule_AddIntConstant(m, "ONLCR", ONLCR); if (OCRNL) PyModule_AddIntConstant(m, "OCRNL", OCRNL); diff --git a/third_party/python/pyobj.c b/third_party/python/pyobj.c index 47de11a58..0429a2485 100644 --- a/third_party/python/pyobj.c +++ b/third_party/python/pyobj.c @@ -35,6 +35,7 @@ #include "libc/sysv/consts/o.h" #include "libc/time/time.h" #include "libc/x/x.h" +#include "libc/zip.h" #include "third_party/getopt/getopt.h" #include "third_party/python/Include/abstract.h" #include "third_party/python/Include/bytesobject.h" @@ -658,16 +659,19 @@ Objectify(void) if (ispkg) { elfwriter_zip(elf, zipdir, zipdir, strlen(zipdir), pydata, 0, 040755, timestamp, timestamp, - timestamp, nocompress, image_base); + timestamp, nocompress, image_base, + kZipCdirHdrLinkableSize); } if (!binonly) { elfwriter_zip(elf, gc(xstrcat("py:", modname)), zipfile, strlen(zipfile), pydata, pysize, st.st_mode, timestamp, - timestamp, timestamp, nocompress, image_base); + timestamp, timestamp, nocompress, image_base, + kZipCdirHdrLinkableSize); } elfwriter_zip(elf, gc(xstrcat("pyc:", modname)), gc(xstrcat(zipfile, 'c')), strlen(zipfile) + 1, pycdata, pycsize, st.st_mode, timestamp, - timestamp, timestamp, nocompress, image_base); + timestamp, timestamp, nocompress, image_base, + kZipCdirHdrLinkableSize); elfwriter_align(elf, 1, 0); elfwriter_startsection(elf, ".yoink", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); diff --git a/third_party/python/repl.c b/third_party/python/repl.c index 45aae5174..addf235ca 100644 --- a/third_party/python/repl.c +++ b/third_party/python/repl.c @@ -87,7 +87,7 @@ CompleteModule(const char *s, const char *p, linenoiseCompletions *c) PyObject *m, *f, *g, *i, *v, *n; plen = strlen(p); for (it = PyImport_Inittab; it->name; ++it) { - if (startswith(it->name, p)) { + if (startswithi(it->name, p)) { AddCompletion(c, xasprintf("%s%s", s, it->name + plen)); } } @@ -98,7 +98,7 @@ CompleteModule(const char *s, const char *p, linenoiseCompletions *c) while ((v = PyIter_Next(i))) { if ((n = PyObject_GetAttrString(v, "name"))) { if (((name = PyUnicode_AsUTF8AndSize(n, &namelen)) && - namelen >= plen && !bcmp(name, p, plen))) { + namelen >= plen && !memcasecmp(name, p, plen))) { AddCompletion(c, xasprintf("%s%s", s, name + plen)); } Py_DECREF(n); @@ -125,7 +125,7 @@ CompleteDict(const char *b, const char *q, const char *p, for (i = 0; PyDict_Next(o, &i, &k, &v);) { if ((v != Py_None && PyUnicode_Check(k) && (s = PyUnicode_AsUTF8AndSize(k, &m)) && - m >= q - p && !bcmp(s, p, q - p))) { + m >= q - p && !memcasecmp(s, p, q - p))) { AddCompletion(c, xasprintf("%.*s%.*s", p - b, b, m, s)); } } @@ -142,7 +142,10 @@ CompleteDir(const char *b, const char *q, const char *p, if ((i = PyObject_GetIter(d))) { while ((k = PyIter_Next(i))) { if (((s = PyUnicode_AsUTF8AndSize(k, &m)) && - m >= q - p && !bcmp(s, p, q - p))) { + m >= q - p && !memcasecmp(s, p, q - p) && + !(q - p == 0 && m > 4 && + (s[0+0] == '_' && s[0+1] == '_' && + s[m-1] == '_' && s[m-2] == '_')))) { AddCompletion(c, xasprintf("%.*s%.*s", p - b, b, m, s)); } Py_DECREF(k); diff --git a/third_party/zip/zip.c b/third_party/zip/zip.c index 10a74456a..b7624f230 100644 --- a/third_party/zip/zip.c +++ b/third_party/zip/zip.c @@ -34,6 +34,7 @@ #include "libc/log/log.h" #include "libc/stdio/stdio.h" #include "libc/stdio/temp.h" +#include "libc/runtime/runtime.h" #include "third_party/bzip2/bzlib.h" #define MAXCOM 256 /* Maximum one-line comment size */ @@ -646,13 +647,6 @@ local void help() } } -static const char *GetPagerPath(char path[PATH_MAX]) { - const char *s; - if ((s = commandv("less", path))) return s; - if ((s = commandv("more", path))) return s; - return 0; -} - #ifdef VMSCLI void help_extended() #else @@ -660,10 +654,7 @@ local void help_extended() #endif /* Print extended help to stdout. */ { - extent i; /* counter for help array */ - - /* help array */ - const char *text = "\n\ + __paginate(1, "\n\ Extended Help for Zip\n\ \n\ See the Zip Manual for more detailed help\n\ @@ -986,27 +977,7 @@ More option highlights (see manual for additional options and details):\n\ -so show all available options on this system\n\ -X default=strip old extra fields, -X- keep old, -X strip most\n\ -ws wildcards don't span directory boundaries in paths\n\ -"; - - int pip[2]; - char *args[2] = {0}; - char pathbuf[PATH_MAX]; - if (isatty(0) && isatty(1) && (args[0] = GetPagerPath(pathbuf))) { - sigaction(SIGPIPE, &(struct sigaction){.sa_handler = SIG_IGN}, 0); - close(0); - pipe(pip); - if (!fork()) { - close(pip[1]); - execv(args[0], args); - _Exit(127); - } - close(0); - write(pip[1], text, strlen(text)); - close(pip[1]); - wait(0); - } else { - fputs(text, stdout); - } +"); exit(0); } diff --git a/tool/build/compile.c b/tool/build/compile.c index 747a57b9d..a30fde12f 100644 --- a/tool/build/compile.c +++ b/tool/build/compile.c @@ -173,7 +173,7 @@ char *shortened; char *cachedcmd; char *colorflag; char *originalcmd; -char ccpath[PATH_MAX]; +char ccpath[PATH_MAX + 1]; struct stat st; struct Strings env; @@ -811,7 +811,7 @@ int main(int argc, char *argv[]) { cmd = argv[optind]; if (!strchr(cmd, '/')) { - if (!(cmd = commandv(cmd, ccpath))) exit(127); + if (!(cmd = commandv(cmd, ccpath, sizeof(ccpath)))) exit(127); } s = basename(strdup(cmd)); diff --git a/tool/build/lib/demangle.c b/tool/build/lib/demangle.c index 5206651e3..3f702da00 100644 --- a/tool/build/lib/demangle.c +++ b/tool/build/lib/demangle.c @@ -42,9 +42,9 @@ void CloseCxxFilt(void) { void SpawnCxxFilt(void) { int pipefds[2][2]; const char *cxxfilt; - char path[PATH_MAX]; + char path[PATH_MAX + 1]; cxxfilt = firstnonnull(emptytonull(getenv("CXXFILT")), "c++filt"); - if (commandv(cxxfilt, path)) { + if (commandv(cxxfilt, path, sizeof(path))) { pipe2(pipefds[0], O_CLOEXEC); pipe2(pipefds[1], O_CLOEXEC); if (!(g_cxxfilt.pid = vfork())) { diff --git a/tool/build/lib/elfwriter.h b/tool/build/lib/elfwriter.h index 8a0d4583f..62b3277c1 100644 --- a/tool/build/lib/elfwriter.h +++ b/tool/build/lib/elfwriter.h @@ -73,7 +73,7 @@ void elfwriter_yoink(struct ElfWriter *, const char *, int); void elfwriter_setsection(struct ElfWriter *, struct ElfWriterSymRef, uint16_t); void elfwriter_zip(struct ElfWriter *, const char *, const char *, size_t, const void *, size_t, uint32_t, struct timespec, - struct timespec, struct timespec, bool, uint64_t); + struct timespec, struct timespec, bool, uint64_t, size_t); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/tool/build/lib/elfwriter_zip.c b/tool/build/lib/elfwriter_zip.c index 3501bb0d1..79e2e7971 100644 --- a/tool/build/lib/elfwriter_zip.c +++ b/tool/build/lib/elfwriter_zip.c @@ -136,7 +136,8 @@ static void EmitZipCdirHdr(unsigned char *p, const void *name, size_t namesize, void elfwriter_zip(struct ElfWriter *elf, const char *symbol, const char *name, size_t namesize, const void *data, size_t size, uint32_t mode, struct timespec mtim, struct timespec atim, - struct timespec ctim, bool nocompress, uint64_t imagebase) { + struct timespec ctim, bool nocompress, uint64_t imagebase, + size_t kZipCdirHdrLinkableSizeBootstrap) { z_stream zs; uint8_t era; uint32_t crc; @@ -159,7 +160,7 @@ void elfwriter_zip(struct ElfWriter *elf, const char *symbol, const char *name, if (S_ISREG(mode) && _istext(data, size)) { iattrs |= kZipIattrText; } - commentsize = kZipCdirHdrLinkableSize - (CFILE_HDR_SIZE + namesize); + commentsize = kZipCdirHdrLinkableSizeBootstrap - (CFILE_HDR_SIZE + namesize); dosmode = !(mode & 0200) ? kNtFileAttributeReadonly : 0; method = ShouldCompress(name, namesize, data, size, nocompress) ? kZipCompressionDeflate @@ -209,15 +210,15 @@ void elfwriter_zip(struct ElfWriter *elf, const char *symbol, const char *name, elfwriter_startsection(elf, gc(xasprintf("%s%s", ZIP_DIRECTORY_SECTION, name)), SHT_PROGBITS, SHF_ALLOC); - EmitZipCdirHdr((cfile = elfwriter_reserve(elf, kZipCdirHdrLinkableSize)), - name, namesize, crc, era, gflags, method, mtime, mdate, iattrs, - dosmode, mode, compsize, uncompsize, commentsize, mtim, atim, - ctim); + EmitZipCdirHdr( + (cfile = elfwriter_reserve(elf, kZipCdirHdrLinkableSizeBootstrap)), name, + namesize, crc, era, gflags, method, mtime, mdate, iattrs, dosmode, mode, + compsize, uncompsize, commentsize, mtim, atim, ctim); elfwriter_appendsym(elf, gc(xasprintf("%s%s", "zip+cdir:", name)), ELF64_ST_INFO(STB_LOCAL, STT_OBJECT), STV_DEFAULT, 0, - kZipCdirHdrLinkableSize); + kZipCdirHdrLinkableSizeBootstrap); elfwriter_appendrela(elf, kZipCfileOffsetOffset, lfilesym, R_X86_64_32, -imagebase); - elfwriter_commit(elf, kZipCdirHdrLinkableSize); + elfwriter_commit(elf, kZipCdirHdrLinkableSizeBootstrap); elfwriter_finishsection(elf); } diff --git a/tool/build/lib/ssemov.c b/tool/build/lib/ssemov.c index cff58591e..182e64fa3 100644 --- a/tool/build/lib/ssemov.c +++ b/tool/build/lib/ssemov.c @@ -121,11 +121,11 @@ static void MovqQqPq(struct Machine *m, uint32_t rde) { static void MovqVdqEqp(struct Machine *m, uint32_t rde) { memcpy(XmmRexrReg(m, rde), GetModrmRegisterWordPointerRead8(m, rde), 8); - memset(XmmRexrReg(m, rde) + 8, 0, 8); + bzero(XmmRexrReg(m, rde) + 8, 8); } static void MovdVdqEd(struct Machine *m, uint32_t rde) { - memset(XmmRexrReg(m, rde), 0, 16); + bzero(XmmRexrReg(m, rde), 16); memcpy(XmmRexrReg(m, rde), GetModrmRegisterWordPointerRead4(m, rde), 4); } @@ -135,7 +135,7 @@ static void MovqPqEqp(struct Machine *m, uint32_t rde) { static void MovdPqEd(struct Machine *m, uint32_t rde) { memcpy(MmReg(m, rde), GetModrmRegisterWordPointerRead4(m, rde), 4); - memset(MmReg(m, rde) + 4, 0, 4); + bzero(MmReg(m, rde) + 4, 4); } static void MovdEdVdq(struct Machine *m, uint32_t rde) { @@ -168,7 +168,7 @@ static void MovntqMqPq(struct Machine *m, uint32_t rde) { static void MovqVqWq(struct Machine *m, uint32_t rde) { memcpy(XmmRexrReg(m, rde), GetModrmRegisterXmmPointerRead8(m, rde), 8); - memset(XmmRexrReg(m, rde) + 8, 0, 8); + bzero(XmmRexrReg(m, rde) + 8, 8); } static void MovssVpsWps(struct Machine *m, uint32_t rde) { @@ -176,7 +176,7 @@ static void MovssVpsWps(struct Machine *m, uint32_t rde) { memcpy(XmmRexrReg(m, rde), XmmRexbRm(m, rde), 4); } else { memcpy(XmmRexrReg(m, rde), ComputeReserveAddressRead4(m, rde), 4); - memset(XmmRexrReg(m, rde) + 4, 0, 12); + bzero(XmmRexrReg(m, rde) + 4, 12); } } @@ -189,7 +189,7 @@ static void MovsdVpsWps(struct Machine *m, uint32_t rde) { memcpy(XmmRexrReg(m, rde), XmmRexbRm(m, rde), 8); } else { memcpy(XmmRexrReg(m, rde), ComputeReserveAddressRead8(m, rde), 8); - memset(XmmRexrReg(m, rde) + 8, 0, 8); + bzero(XmmRexrReg(m, rde) + 8, 8); } } @@ -267,7 +267,7 @@ static void MovhpdMqVq(struct Machine *m, uint32_t rde) { static void MovqWqVq(struct Machine *m, uint32_t rde) { if (IsModrmRegister(rde)) { memcpy(XmmRexbRm(m, rde), XmmRexrReg(m, rde), 8); - memset(XmmRexbRm(m, rde) + 8, 0, 8); + bzero(XmmRexbRm(m, rde) + 8, 8); } else { memcpy(ComputeReserveAddressWrite8(m, rde), XmmRexrReg(m, rde), 8); } @@ -275,7 +275,7 @@ static void MovqWqVq(struct Machine *m, uint32_t rde) { static void Movq2dqVdqNq(struct Machine *m, uint32_t rde) { memcpy(XmmRexrReg(m, rde), MmRm(m, rde), 8); - memset(XmmRexrReg(m, rde) + 8, 0, 8); + bzero(XmmRexrReg(m, rde) + 8, 8); } static void Movdq2qPqUq(struct Machine *m, uint32_t rde) { diff --git a/tool/build/runit.c b/tool/build/runit.c index b6a31568e..eef2446e2 100644 --- a/tool/build/runit.c +++ b/tool/build/runit.c @@ -113,10 +113,10 @@ char *g_prog; char *g_runitd; jmp_buf g_jmpbuf; uint16_t g_sshport; -char g_ssh[PATH_MAX]; char g_hostname[128]; uint16_t g_runitdport; volatile bool alarmed; +char g_ssh[PATH_MAX + 1]; int __sys_execve(const char *, char *const[], char *const[]) hidden; @@ -505,7 +505,8 @@ int main(int argc, char *argv[]) { } CheckExists((g_runitd = argv[1])); CheckExists((g_prog = argv[2])); - CHECK_NOTNULL(commandv(firstnonnull(getenv("SSH"), "ssh"), g_ssh)); + CHECK_NOTNULL( + commandv(firstnonnull(getenv("SSH"), "ssh"), g_ssh, sizeof(g_ssh))); if (argc == 3) { /* hosts list empty */ return 0; diff --git a/tool/build/strace.c b/tool/build/strace.c index c7a003eed..f5d59a59d 100644 --- a/tool/build/strace.c +++ b/tool/build/strace.c @@ -660,7 +660,7 @@ static void Flush(void) { static const char *GetErrnoName(int x) { const char *s; static char buf[16]; - if ((s = strerror_short(x))) return s; + if ((s = strerrno(x))) return s; FormatInt64(buf, x); return buf; } @@ -1195,6 +1195,5 @@ wontreturn void StraceMain(int argc, char *argv[]) { } int main(int argc, char *argv[]) { - __nomultics = true; StraceMain(argc, argv); } diff --git a/tool/build/zipobj.c b/tool/build/zipobj.c index cb28134e4..bdaa29025 100644 --- a/tool/build/zipobj.c +++ b/tool/build/zipobj.c @@ -34,6 +34,7 @@ #include "libc/sysv/consts/prot.h" #include "libc/time/time.h" #include "libc/x/x.h" +#include "libc/zip.h" #include "third_party/getopt/getopt.h" #include "tool/build/lib/elfwriter.h" #include "tool/build/lib/stripcomponents.h" @@ -48,6 +49,7 @@ int64_t image_base_; int strip_components_; const char *path_prefix_; struct timespec timestamp; +size_t kZipCdirHdrLinkableSizeBootstrap; wontreturn void PrintUsage(int rc, FILE *f) { fprintf(f, "%s%s%s\n", "Usage: ", program_invocation_name, @@ -60,7 +62,8 @@ void GetOpts(int *argc, char ***argv) { int opt; yoink_ = "__zip_start"; image_base_ = IMAGE_BASE_VIRTUAL; - while ((opt = getopt(*argc, *argv, "?0nhBN:C:P:o:s:y:b:")) != -1) { + kZipCdirHdrLinkableSizeBootstrap = kZipCdirHdrLinkableSize; + while ((opt = getopt(*argc, *argv, "?0nhBL:N:C:P:o:s:y:b:")) != -1) { switch (opt) { case 'o': outpath_ = optarg; @@ -91,6 +94,9 @@ void GetOpts(int *argc, char ***argv) { case '0': nocompress_ = true; break; + case 'L': + kZipCdirHdrLinkableSizeBootstrap = strtoul(optarg, NULL, 0); + break; case '?': case 'h': PrintUsage(EXIT_SUCCESS, stdout); @@ -135,7 +141,8 @@ void ProcessFile(struct ElfWriter *elf, const char *path) { } } elfwriter_zip(elf, name, name, strlen(name), map, st.st_size, st.st_mode, - timestamp, timestamp, timestamp, nocompress_, image_base_); + timestamp, timestamp, timestamp, nocompress_, image_base_, + kZipCdirHdrLinkableSizeBootstrap); if (st.st_size) CHECK_NE(-1, munmap(map, st.st_size)); close(fd); } @@ -149,7 +156,8 @@ void PullEndOfCentralDirectoryIntoLinkage(struct ElfWriter *elf) { } void CheckFilenameKosher(const char *path) { - CHECK_LE(strlen(path), PATH_MAX); + CHECK_LE(kZipCfileHdrMinSize + strlen(path), + kZipCdirHdrLinkableSizeBootstrap); CHECK(!startswith(path, "/")); CHECK(!strstr(path, "..")); } diff --git a/tool/decode/ent.c b/tool/decode/ent.c index b6bf0e39b..856989371 100644 --- a/tool/decode/ent.c +++ b/tool/decode/ent.c @@ -151,7 +151,7 @@ int main(int argc, char *argv[]) } samp = binary ? "bit" : "byte"; - memset(ccount, 0, sizeof ccount); + bzero(ccount, sizeof ccount); /* Initialise for calculations */ diff --git a/tool/decode/lib/bitabuilder.c b/tool/decode/lib/bitabuilder.c index 874d5e797..1174607c1 100644 --- a/tool/decode/lib/bitabuilder.c +++ b/tool/decode/lib/bitabuilder.c @@ -58,7 +58,7 @@ bool bitabuilder_setbit(struct BitaBuilder *bb, size_t bit) { if (i > bb->n) { n = i + (i >> 2); if ((p2 = realloc(bb->p, n))) { - memset((char *)p2 + bb->n, 0, n - bb->n); + bzero((char *)p2 + bb->n, n - bb->n); bb->n = n; bb->p = p2; } else { diff --git a/tool/decode/lib/disassemblehex.c b/tool/decode/lib/disassemblehex.c index 8d0c5def2..4a7b0a964 100644 --- a/tool/decode/lib/disassemblehex.c +++ b/tool/decode/lib/disassemblehex.c @@ -44,7 +44,7 @@ void disassemblehex(uint8_t *data, size_t size, FILE *f) { if (i == size) break; } fprintf(f, "\t.%s\t", "byte"); - memset(glyphs, 0, sizeof(glyphs)); + bzero(glyphs, sizeof(glyphs)); } /* TODO(jart): Fix Emacs */ glyphs[col] = kCp437[ch == '"' || ch == '\\' || ch == '#' ? '.' : ch]; diff --git a/tool/emacs/cosmo-stuff.el b/tool/emacs/cosmo-stuff.el index 2217aea8f..c47eb24ab 100644 --- a/tool/emacs/cosmo-stuff.el +++ b/tool/emacs/cosmo-stuff.el @@ -793,6 +793,7 @@ (message header)))) (progn + (define-key prog-mode-map (kbd "C-c C-h") 'cosmo-add-include) (define-key asm-mode-map (kbd "C-c C-h") 'cosmo-add-include) (define-key c-mode-base-map (kbd "C-c C-h") 'cosmo-add-include)) diff --git a/tool/net/demo/.init.lua b/tool/net/demo/.init.lua index acb360df4..304d0f89a 100644 --- a/tool/net/demo/.init.lua +++ b/tool/net/demo/.init.lua @@ -34,3 +34,7 @@ function OnHttpRequest() end SetHeader('Server', 'redbean!') end + +function Adder(x, y) + return x + y +end diff --git a/tool/net/demo/crashreport.lua b/tool/net/demo/crashreport.lua index 1cee29e69..3a46d1611 100644 --- a/tool/net/demo/crashreport.lua +++ b/tool/net/demo/crashreport.lua @@ -12,7 +12,7 @@ function dosomething(param1, x) SetHeader('Content-Type', 'text/plain; charset=utf-8') Write('preprae to crash... now\r\n') res = x / y - Write(string.format('42 / 0 is %d\r\n', res)) + Write('42 / 0 is %d\r\n' % {res}) end function start(param1) diff --git a/tool/net/demo/fetch.lua b/tool/net/demo/fetch.lua index 7833ab3e8..ff28742aa 100644 --- a/tool/net/demo/fetch.lua +++ b/tool/net/demo/fetch.lua @@ -2,7 +2,7 @@ local function WriteForm(url) Write('\r\n') - Write(string.format([[ + Write([[ redbean fetch demo \r\n') Write('
\r\n') -Write('
getuid()\r\n') -Write(string.format('
%d\r\n', unix.getuid())) -Write('
getgid()\r\n') -Write(string.format('
%d\r\n', unix.getgid())) -Write('
getpid()\r\n') -Write(string.format('
%d\r\n', unix.getpid())) -Write('
getppid()\r\n') -Write(string.format('
%d\r\n', unix.getppid())) -Write('
getpgrp()\r\n') -Write(string.format('
%d\r\n', unix.getpgrp())) +Write('
unix.getuid()\r\n') +Write('
%d\r\n' % {unix.getuid()}) +Write('
unix.getgid()\r\n') +Write('
%d\r\n' % {unix.getgid()}) +Write('
unix.getpid()\r\n') +Write('
%d\r\n' % {unix.getpid()}) +Write('
unix.getppid()\r\n') +Write('
%d\r\n' % {unix.getppid()}) +Write('
unix.getpgrp()\r\n') +Write('
%d\r\n' % {unix.getpgrp()}) +Write('
unix.umask()\r\n') +mask = unix.umask(027) +unix.umask(mask) +Write('
%.4o\r\n' % {mask}) -Write('
getsid(0)\r\n') +Write('
unix.getsid(0)\r\n') sid, errno = unix.getsid(0) if sid then - Write(string.format('
%d\r\n', sid)) + Write('
%d\r\n' % {sid}) else - Write(string.format('
%s\r\n', EscapeHtml(unix.strerrno(errno)))) + Write('
%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) end -Write('
gethostname()\r\n') -Write(string.format('
%s\r\n', EscapeHtml(unix.gethostname()))) -Write('
getcwd()\r\n') -Write(string.format('
%s\r\n', EscapeHtml(unix.getcwd()))) +Write('
unix.gethostname()\r\n') +Write('
%s\r\n' % {EscapeHtml(unix.gethostname())}) +Write('
unix.getcwd()\r\n') +Write('
%s\r\n' % {EscapeHtml(unix.getcwd())}) function PrintResourceLimit(name, id) soft, hard, errno = unix.getrlimit(id) - Write(string.format('
getrlimit(%s)\r\n', name)) + Write('
getrlimit(%s)\r\n' % {name}) if soft then Write('
') Write('soft ') if soft == -1 then Write('∞') else - Write(string.format('%d', soft)) + Write('%d' % {soft}) end Write('
\r\n') Write('hard ') if hard == -1 then Write('∞') else - Write(string.format('%d', hard)) + Write('%d' % {hard}) end Write('\r\n') else - Write(string.format('
%s\r\n', EscapeHtml(unix.strerrno(errno)))) + Write('
%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) end end PrintResourceLimit('RLIMIT_AS', unix.RLIMIT_AS) @@ -59,7 +64,7 @@ PrintResourceLimit('RLIMIT_FSIZE', unix.RLIMIT_FSIZE) PrintResourceLimit('RLIMIT_NPROC', unix.RLIMIT_NPROC) PrintResourceLimit('RLIMIT_NOFILE', unix.RLIMIT_NOFILE) -Write('
siocgifconf()\r\n') +Write('
unix.siocgifconf()\r\n') Write('
\r\n') ifs, errno = unix.siocgifconf() if ifs then @@ -69,12 +74,217 @@ if ifs then else cidr = 0 end - Write(string.format('%s %s/%d
\r\n', - EscapeHtml(ifs[i].name), - FormatIp(ifs[i].ip), - cidr)) + Write('%s %s/%d
\r\n' % {EscapeHtml(ifs[i].name), FormatIp(ifs[i].ip), cidr}) end else - Write(string.format('%s\r\n', EscapeHtml(unix.strerrno(errno)))) + Write('%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) end -Write('
\r\n') + +errno, enabled = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_DEBUG) +Write('
unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_DEBUG)\r\n') +if errno then + Write('
%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) +else + Write('
%s\r\n' % {enabled}) +end + +errno, enabled = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_REUSEADDR) +Write('
unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_REUSEADDR)\r\n') +if errno then + Write('
%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) +else + Write('
%s\r\n' % {enabled}) +end + +errno, enabled = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_REUSEPORT) +Write('
unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_REUSEPORT)\r\n') +if errno then + Write('
%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) +else + Write('
%s\r\n' % {enabled}) +end + +errno, enabled = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_KEEPALIVE) +Write('
unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_KEEPALIVE)\r\n') +if errno then + Write('
%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) +else + Write('
%s\r\n' % {enabled}) +end + +errno, enabled = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_NODELAY) +Write('
unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_NODELAY)\r\n') +if errno then + Write('
%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) +else + Write('
%s\r\n' % {enabled}) +end + +errno, secs, micros = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_RCVTIMEO) +Write('
unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_RCVTIMEO)\r\n') +if errno then + Write('
%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) +else + Write('
%d sec %d µs\r\n' % {secs, micros}) +end + +errno, secs, micros = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_SNDTIMEO) +Write('
unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_SNDTIMEO)\r\n') +if errno then + Write('
%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) +else + Write('
%d sec %d µs\r\n' % {secs, micros}) +end + +errno, enabled = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_DONTROUTE) +Write('
unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_DONTROUTE)\r\n') +if errno then + Write('
%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) +else + Write('
%s\r\n' % {enabled}) +end + +errno, bytes = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_SNDBUF) +Write('
unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_SNDBUF)\r\n') +if errno then + Write('
%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) +else + Write('
%d\r\n' % {bytes}) +end + +errno, bytes = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_RCVBUF) +Write('
unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_RCVBUF)\r\n') +if errno then + Write('
%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) +else + Write('
%d\r\n' % {bytes}) +end + +errno, bytes = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_FASTOPEN) +Write('
unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_FASTOPEN)\r\n') +if errno then + Write('
%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) +else + Write('
%d\r\n' % {bytes}) +end + +errno, enabled = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_BROADCAST) +Write('
unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_BROADCAST)\r\n') +if errno then + Write('
%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) +else + Write('
%s\r\n' % {enabled}) +end + +errno, enabled = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_CORK) +Write('
unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_CORK)\r\n') +if errno then + Write('
%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) +else + Write('
%s\r\n' % {enabled}) +end + +errno, enabled = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_QUICKACK) +Write('
unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_QUICKACK)\r\n') +if errno then + Write('
%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) +else + Write('
%s\r\n' % {enabled}) +end + +errno, enabled = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_DEFER_ACCEPT) +Write('
unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_DEFER_ACCEPT)\r\n') +if errno then + Write('
%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) +else + Write('
%s\r\n' % {enabled}) +end + +errno, enabled = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_FASTOPEN_CONNECT) +Write('
unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_FASTOPEN_CONNECT)\r\n') +if errno then + Write('
%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) +else + Write('
%s\r\n' % {enabled}) +end + +errno, bytes = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_SNDLOWAT) +Write('
unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_SNDLOWAT)\r\n') +if errno then + Write('
%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) +else + Write('
%d\r\n' % {bytes}) +end + +errno, bytes = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_RCVLOWAT) +Write('
unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_RCVLOWAT)\r\n') +if errno then + Write('
%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) +else + Write('
%d\r\n' % {bytes}) +end + +errno, bytes = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_KEEPCNT) +Write('
unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_KEEPCNT)\r\n') +if errno then + Write('
%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) +else + Write('
%d\r\n' % {bytes}) +end + +errno, bytes = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_MAXSEG) +Write('
unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_MAXSEG)\r\n') +if errno then + Write('
%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) +else + Write('
%d\r\n' % {bytes}) +end + +errno, bytes = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_SYNCNT) +Write('
unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_SYNCNT)\r\n') +if errno then + Write('
%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) +else + Write('
%d\r\n' % {bytes}) +end + +errno, bytes = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_NOTSENT_LOWAT) +Write('
unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_NOTSENT_LOWAT)\r\n') +if errno then + Write('
%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) +else + Write('
%d\r\n' % {bytes}) +end + +errno, bytes = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_WINDOW_CLAMP) +Write('
unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_WINDOW_CLAMP)\r\n') +if errno then + Write('
%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) +else + Write('
%d\r\n' % {bytes}) +end + +errno, bytes = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_KEEPIDLE) +Write('
unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_KEEPIDLE)\r\n') +if errno then + Write('
%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) +else + Write('
%d\r\n' % {bytes}) +end + +errno, bytes = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_KEEPINTVL) +Write('
unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_KEEPINTVL)\r\n') +if errno then + Write('
%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) +else + Write('
%d\r\n' % {bytes}) +end + +Write('
unix.environ()\r\n') +Write('
\r\n') +Write('
    \r\n') +env = unix.environ() +for i = 1,#env do + Write('
  • %s\r\n' % {EscapeHtml(env[i])}) +end +Write('
\r\n') diff --git a/tool/net/demo/unix-rawsocket.lua b/tool/net/demo/unix-rawsocket.lua index f0b3d5147..bae11971e 100644 --- a/tool/net/demo/unix-rawsocket.lua +++ b/tool/net/demo/unix-rawsocket.lua @@ -32,8 +32,9 @@ local function main() -- steal client from redbean fd = GetClientFd() - rc, errno = unix.fork() + -- this function returns twice + pid, errno = unix.fork() if errno then SetStatus(400) SetHeader('Content-Type', 'text/html; charset=utf-8') @@ -44,7 +45,7 @@ local function main() Write(EncodeBase64(LoadAsset('/redbean.png'))) Write('">\r\n') Write('redbean unix demo\r\n') - Write(string.format(' %s\r\n', unix.strerrno(errno))) + Write(' %s\r\n' % {unix.strerrno(errno)}) Write('\r\n') Write([[

@@ -57,11 +58,13 @@ local function main() return end - if rc ~= 0 then + -- the parent process gets the pid + if pid ~= 0 then unix.close(fd) return end + -- if pid is zero then we're the child -- turn into a daemon unix.umask(0) unix.setsid() @@ -119,7 +122,7 @@ local function main() else st, err = unix.stat(name) if st then - unix.write(fd, string.format(' (%d bytes)', st:size())) + unix.write(fd, ' (%d bytes)' % {st:size()}) end end unix.write(fd, '\r\n') @@ -127,7 +130,7 @@ local function main() unix.write(fd, '\r\n') else unix.write(fd, '

\r\n') - unix.write(fd, string.format('failed: %s\r\n', EscapeHtml(VisualizeControlCodes(unix:strerror(err))))) + unix.write(fd, 'failed: %s\r\n' % {EscapeHtml(VisualizeControlCodes(unix:strerror(err)))}) unix.write(fd, '

\r\n') end diff --git a/tool/net/demo/unix-subprocess.lua b/tool/net/demo/unix-subprocess.lua index 13e14980a..5e0fbe7b9 100644 --- a/tool/net/demo/unix-subprocess.lua +++ b/tool/net/demo/unix-subprocess.lua @@ -2,15 +2,20 @@ -- and pipe its output to the http user local unix = require "unix" function main() + if GetHostOs() == 'WINDOWS' then + cmd = 'dir' + else + cmd = 'ls' + end syscall = 'commandv' - ls, errno = unix.commandv("ls") + ls, errno = unix.commandv(cmd) if ls then syscall = 'pipe' reader, writer, errno = unix.pipe() if reader then - oldint = unix.sigaction(unix.SIGINT, unix.SIG_IGN) - oldquit = unix.sigaction(unix.SIGQUIT, unix.SIG_IGN) - oldmask = unix.sigprocmask(unix.SIG_BLOCK, unix.SIGCHLD) + -- oldint = unix.sigaction(unix.SIGINT, unix.SIG_IGN) + -- oldquit = unix.sigaction(unix.SIGQUIT, unix.SIG_IGN) + -- oldmask = unix.sigprocmask(unix.SIG_BLOCK, unix.SIGCHLD) syscall = 'fork' child, errno = unix.fork() if child then @@ -19,10 +24,10 @@ function main() unix.dup(writer) unix.close(writer) unix.close(reader) - unix.sigaction(unix.SIGINT, oldint) - unix.sigaction(unix.SIGQUIT, oldquit) - unix.sigprocmask(unix.SIG_SETMASK, oldmask) - unix.execve(ls, {ls, "-Shal"}) + -- unix.sigaction(unix.SIGINT, oldint) + -- unix.sigaction(unix.SIGQUIT, oldquit) + -- unix.sigprocmask(unix.SIG_SETMASK, oldmask) + unix.execve(ls, {ls, '-Shal'}) unix.exit(127) else unix.close(writer) @@ -31,21 +36,21 @@ function main() while true do data, errno = unix.read(reader) if data then - if data ~= "" then + if data ~= '' then Write(data) else break end elseif errno ~= unix.EINTR then - Log(kLogWarn, string.format('read() failed: %s', unix.strerror(errno))) + Log(kLogWarn, 'read() failed: %s' % {unix.strerror(errno)}) break end end unix.close(reader) unix.wait(-1) - unix.sigaction(unix.SIGINT, oldint) - unix.sigaction(unix.SIGQUIT, oldquit) - unix.sigprocmask(unix.SIG_SETMASK, oldmask) + -- unix.sigaction(unix.SIGINT, oldint) + -- unix.sigaction(unix.SIGQUIT, oldquit) + -- unix.sigprocmask(unix.SIG_SETMASK, oldmask) return end end @@ -53,6 +58,6 @@ function main() end SetStatus(200) SetHeader('Content-Type', 'text/plain') - Write(string.format('error %s calling %s()', unix.strerrno(errno), syscall)) + Write('error %s calling %s()' % {unix.strerrno(errno), syscall}) end main() diff --git a/tool/net/demo/unix-webserver.lua b/tool/net/demo/unix-webserver.lua index 3b399c37c..8c1bf6605 100644 --- a/tool/net/demo/unix-webserver.lua +++ b/tool/net/demo/unix-webserver.lua @@ -46,12 +46,10 @@ function main() unix.bind(server, ifs[i].ip) unix.listen(server) ip, port = unix.getsockname(server) - addr = string.format('%s:%d', FormatIp(ip), port) - url = string.format('http://%s', addr) - Log(kLogInfo, string.format('listening on %s', addr)) - unix.write(mainfd, string.format( - 'listening on %s
\r\n', - url, url)) + addr = '%s:%d' % {FormatIp(ip), port} + url = 'http://%s' % {addr} + Log(kLogInfo, 'listening on %s' % {addr}) + unix.write(mainfd, 'listening on %s
\r\n' % {url, url}) pollfds[server] = unix.POLLIN | unix.POLLHUP servers[server] = true addrs[server] = addr @@ -67,7 +65,7 @@ function main() if fd == mainfd then data, errno = unix.read(mainfd) if not data then - Log(kLogInfo, string.format('got %s from parent client', unix.strerrno(errno))) + Log(kLogInfo, 'got %s from parent client' % {unix.strerrno(errno)}) -- prevent redbean core from writing a response unix.exit(1) end @@ -80,20 +78,20 @@ function main() -- echo it back for fun unix.write(mainfd, data) elseif servers[fd] then - unix.write(mainfd, string.format('preparing to accept from %d
\r\n', fd)) + unix.write(mainfd, 'preparing to accept from %d
\r\n' % {fd}) client, clientip, clientport = unix.accept(fd) - unix.write(mainfd, string.format('preparing to accept from %d
\r\n', fd)) - addr = string.format('%s:%d', FormatIp(clientip), clientport) + unix.write(mainfd, 'preparing to accept from %d
\r\n' % {fd}) + addr = '%s:%d' % {FormatIp(clientip), clientport} addrs[client] = addr - unix.write(mainfd, string.format('got client %s
\r\n', addr)) + unix.write(mainfd, 'got client %s
\r\n' % {addr}) pollfds[client] = unix.POLLIN evs[server] = nil else - unix.write(mainfd, string.format('preparing to read from %d
\r\n', fd)) + unix.write(mainfd, 'preparing to read from %d
\r\n' % {fd}) data = unix.read(fd) - unix.write(mainfd, string.format('done reading from %d
\r\n', fd)) + unix.write(mainfd, 'done reading from %d
\r\n' % {fd}) if data and #data ~= 0 then - unix.write(mainfd, string.format('got %d bytes from %s
\r\n', #data, addrs[fd])) + unix.write(mainfd, 'got %d bytes from %s
\r\n' % {#data, addrs[fd]}) unix.write(fd, 'HTTP/1.0 200 OK\r\n' .. 'Date: '.. FormatHttpDateTime(GetDate()) ..'\r\n' .. 'Content-Type: text/html; charset=utf-8\r\n' .. diff --git a/tool/net/help.txt b/tool/net/help.txt index b48076d03..47da46e38 100644 --- a/tool/net/help.txt +++ b/tool/net/help.txt @@ -76,54 +76,56 @@ FLAGS --strace enables system call tracing --ftrace enables function call tracing + KEYBOARD - CTRL-D EXIT - CTRL-C CTRL-C EXIT - CTRL-E END - CTRL-A START - CTRL-B BACK - CTRL-F FORWARD - CTRL-L CLEAR - CTRL-H BACKSPACE - CTRL-D DELETE - CTRL-N NEXT HISTORY - CTRL-P PREVIOUS HISTORY - CTRL-R SEARCH HISTORY - CTRL-G CANCEL SEARCH - ALT-< BEGINNING OF HISTORY - ALT-> END OF HISTORY - ALT-F FORWARD WORD - ALT-B BACKWARD WORD - CTRL-K KILL LINE FORWARDS - CTRL-U KILL LINE BACKWARDS - ALT-H KILL WORD BACKWARDS - CTRL-W KILL WORD BACKWARDS - CTRL-ALT-H KILL WORD BACKWARDS - ALT-D KILL WORD FORWARDS - CTRL-Y YANK - ALT-Y ROTATE KILL RING AND YANK AGAIN - CTRL-T TRANSPOSE - ALT-T TRANSPOSE WORD - ALT-U UPPERCASE WORD - ALT-L LOWERCASE WORD - ALT-C CAPITALIZE WORD - CTRL-\ QUIT PROCESS - CTRL-S PAUSE OUTPUT - CTRL-Q UNPAUSE OUTPUT (IF PAUSED) - CTRL-Q ESCAPED INSERT - CTRL-ALT-F FORWARD EXPR - CTRL-ALT-B BACKWARD EXPR - ALT-RIGHT FORWARD EXPR - ALT-LEFT BACKWARD EXPR - ALT-SHIFT-B BARF EXPR - ALT-SHIFT-S SLURP EXPR - CTRL-SPACE SET MARK - CTRL-X CTRL-X GOTO MARK - CTRL-Z SUSPEND PROCESS - ALT-\ SQUEEZE ADJACENT WHITESPACE - PROTIP REMAP CAPS LOCK TO CTRL + CTRL-D EXIT + CTRL-C CTRL-C EXIT + CTRL-E END + CTRL-A START + CTRL-B BACK + CTRL-F FORWARD + CTRL-L CLEAR + CTRL-H BACKSPACE + CTRL-D DELETE + CTRL-N NEXT HISTORY + CTRL-P PREVIOUS HISTORY + CTRL-R SEARCH HISTORY + CTRL-G CANCEL SEARCH + ALT-< BEGINNING OF HISTORY + ALT-> END OF HISTORY + ALT-F FORWARD WORD + ALT-B BACKWARD WORD + CTRL-K KILL LINE FORWARDS + CTRL-U KILL LINE BACKWARDS + ALT-H KILL WORD BACKWARDS + CTRL-W KILL WORD BACKWARDS + CTRL-ALT-H KILL WORD BACKWARDS + ALT-D KILL WORD FORWARDS + CTRL-Y YANK + ALT-Y ROTATE KILL RING AND YANK AGAIN + CTRL-T TRANSPOSE + ALT-T TRANSPOSE WORD + ALT-U UPPERCASE WORD + ALT-L LOWERCASE WORD + ALT-C CAPITALIZE WORD + CTRL-\ QUIT PROCESS + CTRL-S PAUSE OUTPUT + CTRL-Q UNPAUSE OUTPUT (IF PAUSED) + CTRL-Q ESCAPED INSERT + CTRL-ALT-F FORWARD EXPR + CTRL-ALT-B BACKWARD EXPR + ALT-RIGHT FORWARD EXPR + ALT-LEFT BACKWARD EXPR + ALT-SHIFT-B BARF EXPR + ALT-SHIFT-S SLURP EXPR + CTRL-SPACE SET MARK + CTRL-X CTRL-X GOTO MARK + CTRL-Z SUSPEND PROCESS + ALT-\ SQUEEZE ADJACENT WHITESPACE + PROTIP REMAP CAPS LOCK TO CTRL + USAGE This executable is also a ZIP file that contains static assets. @@ -231,6 +233,24 @@ USAGE inside the binary. redbean also respects your privacy and won't phone home because your computer is its home. + +REPL + + Your redbean displays a REPL that lets you modify the state of the + main server process while your server is running. Any changes will + propagate into forked clients. + + Your REPL is displayed only when redbean is run as a non-daemon in a + UNIX terminal or the Windows 10 command prompt or powershell. Since + the REPL is a Lua REPL it's not included in a redbean-static builds. + + redbean uses the same keyboard shortcuts as GNU Readline and Emacs. + Some of its keyboard commands (listed in a previous section) were + inspired by Paredit. + + A history of your commands is saved to `~/.redbean_history`. + + SECURITY redbean uses a protocol polyglot for serving HTTP and HTTPS on @@ -246,1034 +266,1067 @@ SECURITY -VVV log ssl informational messages too -VVVV log ssl verbose details too - See https://redbean.dev for further details. + See http://redbean.dev for further details. + LUA SERVER PAGES - Any files with the extension .lua will be dynamically served by redbean. - Here's the simplest possible example: + Any files with the extension .lua will be dynamically served by redbean. + Here's the simplest possible example: - Write('Hello World') + Write('Hello World') - The Lua Server Page above should be able to perform at 700,000 responses - per second on a Core i9, without any sort of caching. If you want a Lua - handler that can do 1,000,000 responses per second, then try adding the - following global handler to your /.init.lua file: + The Lua Server Page above should be able to perform at 700,000 responses + per second on a Core i9, without any sort of caching. If you want a Lua + handler that can do 1,000,000 responses per second, then try adding the + following global handler to your /.init.lua file: - function OnHttpRequest() - Write('Hello World') - end + function OnHttpRequest() + Write('Hello World') + end - Here's an example of a more typical workflow for Lua Server Pages using - the redbean API: + Here's an example of a more typical workflow for Lua Server Pages using + the redbean API: - SetStatus(200) - SetHeader('Content-Type', 'text/plain; charset=utf-8') - Write('

Hello ') - Write(EscapeHtml(GetParam('name'))) + SetStatus(200) + SetHeader('Content-Type', 'text/plain; charset=utf-8') + Write('

Hello ') + Write(EscapeHtml(GetParam('name'))) - We didn't need the first two lines in the previous example, because - they're implied by redbean automatically if you don't set them. Responses - are also buffered until the script finishes executing. That enables - redbean to make HTTP as easy as possible. In the future, API capabilities - will be expanded to make possible things like websockets. + We didn't need the first two lines in the previous example, because + they're implied by redbean automatically if you don't set them. Responses + are also buffered until the script finishes executing. That enables + redbean to make HTTP as easy as possible. In the future, API capabilities + will be expanded to make possible things like websockets. - redbean embeds the Lua standard library. You can use packages such as io - to persist and share state across requests and connections, as well as the - StoreAsset function, and the lsqlite3 module. + redbean embeds the Lua standard library. You can use packages such as io + to persist and share state across requests and connections, as well as the + StoreAsset function, and the lsqlite3 module. - Your Lua interpreter begins its life in the main process at startup in the - .init.lua, which is likely where you'll want to perform all your expensive - one-time operations like importing modules. Then, as requests roll in, - isolated processes are cloned from the blueprint you created. + Your Lua interpreter begins its life in the main process at startup in the + .init.lua, which is likely where you'll want to perform all your expensive + one-time operations like importing modules. Then, as requests roll in, + isolated processes are cloned from the blueprint you created. + SPECIAL PATHS - / - redbean will generate a zip central directory listing for this - page, and this page only, but only if there isn't an /index.lua or - /index.html file defined. + / + redbean will generate a zip central directory listing for this + page, and this page only, but only if there isn't an /index.lua or + /index.html file defined. - /.init.lua - This script is run once in the main process at startup. This lets - you modify the state of the Lua interpreter before connection - processes are forked off. For example, it's a good idea to do - expensive one-time computations here. You can also use this file - to call the ProgramFOO() functions below. The init module load - happens after redbean's arguments and zip assets have been parsed, - but before calling functions like socket() and fork(). Note that - this path is a hidden file so that it can't be unintentionally run - by the network client. + /.init.lua + This script is run once in the main process at startup. This lets + you modify the state of the Lua interpreter before connection + processes are forked off. For example, it's a good idea to do + expensive one-time computations here. You can also use this file + to call the ProgramFOO() functions below. The init module load + happens after redbean's arguments and zip assets have been parsed, + but before calling functions like socket() and fork(). Note that + this path is a hidden file so that it can't be unintentionally run + by the network client. - /.reload.lua - This script is run from the main process when SIGHUP is received. - This only applies to redbean when running in daemon mode. Any - changes that are made to the Lua interpreter state will be - inherited by future forked connection processes. Note that this - path is a hidden file so that it can't be unintentionally run by - the network client. + /.reload.lua + This script is run from the main process when SIGHUP is received. + This only applies to redbean when running in daemon mode. Any + changes that are made to the Lua interpreter state will be + inherited by future forked connection processes. Note that this + path is a hidden file so that it can't be unintentionally run by + the network client. - /.lua/... - Your Lua modules go in this directory. The way it works is redbean - sets Lua's package.path to /zip/.lua/?.lua;/zip/.lua/?/init.lua by - default. Cosmopolitan Libc lets system calls like open read from - the ZIP structure, if the filename is prefixed with /zip/. So this - works like magic. + /.lua/... + Your Lua modules go in this directory. The way it works is redbean + sets Lua's package.path to /zip/.lua/?.lua;/zip/.lua/?/init.lua by + default. Cosmopolitan Libc lets system calls like open read from + the ZIP structure, if the filename is prefixed with /zip/. So this + works like magic. - /redbean.png - If it exists, it'll be used as the / listing page icon, embedded - as a base64 URI. + /redbean.png + If it exists, it'll be used as the / listing page icon, embedded + as a base64 URI. - /usr/share/ssl/root - This directory contains your root certificate authorities. It is - needed so the Fetch() HTTPS client API can verify that a remote - certificate was signed by a third party. You can add your own - certificate files to this directory within the ZIP executable. - If you enable HTTPS client verification then redbean will check - that HTTPS clients (a) have a certificate and (b) it was signed. + /usr/share/ssl/root + This directory contains your root certificate authorities. It is + needed so the Fetch() HTTPS client API can verify that a remote + certificate was signed by a third party. You can add your own + certificate files to this directory within the ZIP executable. + If you enable HTTPS client verification then redbean will check + that HTTPS clients (a) have a certificate and (b) it was signed. + GLOBALS - argv: array[str] - Array of command line arguments, excluding those parsed by - getopt() in the C code, which stops parsing at the first - non-hyphenated arg. In some cases you can use the magic -- - argument to delimit C from Lua arguments. + argv: array[str] + Array of command line arguments, excluding those parsed by + getopt() in the C code, which stops parsing at the first + non-hyphenated arg. In some cases you can use the magic -- + argument to delimit C from Lua arguments. + HOOKS - OnHttpRequest() - If this function is defined in the global scope by your /.init.lua - then redbean will call it at the ealiest possible moment to - hand over control for all messages (with the exception of OPTIONS - *). See functions like Route which asks redbean to do its default - thing from the handler. + OnHttpRequest() + If this function is defined in the global scope by your /.init.lua + then redbean will call it at the ealiest possible moment to + hand over control for all messages (with the exception of OPTIONS + *). See functions like Route which asks redbean to do its default + thing from the handler. - OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool - If this function is defined it'll be called from the main process - each time redbean accepts a new client connection. If it returns - true then redbean will close the connection without calling fork. + OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool + If this function is defined it'll be called from the main process + each time redbean accepts a new client connection. If it returns + true then redbean will close the connection without calling fork. - OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int) - If this function is defined it'll be called from the main process - each time redbean forks a connection handler worker process. The - ip/port of the remote client is provided, along with the ip/port - of the listening interface that accepted the connection. This may - be used to create a server activity dashboard, in which case the - data provider handler should set SetHeader('Connection','Close'). - This won't be called in uniprocess mode. + OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int) + If this function is defined it'll be called from the main process + each time redbean forks a connection handler worker process. The + ip/port of the remote client is provided, along with the ip/port + of the listening interface that accepted the connection. This may + be used to create a server activity dashboard, in which case the + data provider handler should set SetHeader('Connection','Close'). + This won't be called in uniprocess mode. - OnProcessDestroy(pid:int) - If this function is defined it'll be called from the main process - each time redbean reaps a child connection process using wait4(). - This won't be called in uniprocess mode. + OnProcessDestroy(pid:int) + If this function is defined it'll be called from the main process + each time redbean reaps a child connection process using wait4(). + This won't be called in uniprocess mode. - OnServerStart() - If this function is defined it'll be called from the main process - right before the main event loop starts. + OnServerStart() + If this function is defined it'll be called from the main process + right before the main event loop starts. - OnServerStop() - If this function is defined it'll be called from the main process - after all the connection processes have been reaped and exit() is - ready to be called. + OnServerStop() + If this function is defined it'll be called from the main process + after all the connection processes have been reaped and exit() is + ready to be called. - OnWorkerStart() - If this function is defined it'll be called from the child worker - process after it's been forked and before messages are handled. - This won't be called in uniprocess mode. + OnWorkerStart() + If this function is defined it'll be called from the child worker + process after it's been forked and before messages are handled. + This won't be called in uniprocess mode. - OnWorkerStop() - If this function is defined it'll be called from the child worker - process once _exit() is ready to be called. This won't be called - in uniprocess mode. + OnWorkerStop() + If this function is defined it'll be called from the child worker + process once _exit() is ready to be called. This won't be called + in uniprocess mode. + FUNCTIONS - Write(data:str) - Appends data to HTTP response payload buffer. This is buffered - independently of headers. - - SetStatus(code:int[,reason:str]) - Starts an HTTP response, specifying the parameters on its first - line. reason is optional since redbean can fill in the appropriate - text for well-known magic numbers, e.g. 200, 404, etc. This method - will reset the response and is therefore mutually exclusive with - ServeAsset and other Serve* functions. If this function isn't - called, then the default behavior is to send 200 OK. - - SetHeader(name:str,value:str) - Appends HTTP header to response header buffer. name is - case-insensitive and restricted to non-space ASCII. value is a - UTF-8 string that must be encodable as ISO-8859-1. Leading and - trailing whitespace is trimmed automatically. Overlong characters - are canonicalized. C0 and C1 control codes are forbidden, with the - exception of tab. This function automatically calls SetStatus(200, - "OK") if a status has not yet been set. As SetStatus and Serve* - functions reset the response, SetHeader needs to be called after - SetStatus and Serve* functions are called. The header buffer is - independent of the payload buffer. Neither is written to the wire - until the Lua Server Page has finished executing. This function - disallows the setting of certain headers such as Content-Range and - Date, which are abstracted by the transport layer. In such cases, - consider calling ServeAsset. - - SetCookie(name:str,value:str[,options:table]) - Appends Set-Cookie HTTP header to the response header buffer. - Several Set-Cookie headers can be added to the same response. - __Host- and __Secure- prefixes are supported and may set or - overwrite some of the options (for example, specifying __Host- - prefix sets the Secure option to true, sets the path to "/", and - removes the Domain option). The following options can be used (their - lowercase equivalents are supported as well): - - Expires: sets the maximum lifetime of the cookie as an HTTP-date - timestamp. Can be specified as a Date in the RFC1123 (string) - format or as a UNIX timestamp (number of seconds). - - MaxAge: sets number of seconds until the cookie expires. A zero - or negative number will expire the cookie immediately. If both - Expires and MaxAge are set, MaxAge has precedence. - - Domain: sets the host to which the cookie will be sent. - - Path: sets the path that must be present in the request URL, or - the client will not send the Cookie header. - - Secure: (bool) requests the cookie to be only send to the - server when a request is made with the https: scheme. - - HttpOnly: (bool) forbids JavaScript from accessing the cookie. - - SameSite: (Strict, Lax, or None) controls whether a cookie is - sent with cross-origin requests, providing some protection - against cross-site request forgery attacks. - - GetParam(name:str) → value:str - Returns first value associated with name. name is handled in a - case-sensitive manner. This function checks Request-URL parameters - first. Then it checks application/x-www-form-urlencoded from the - message body, if it exists, which is common for HTML forms sending - POST requests. If a parameter is supplied matching name that has - no value, e.g. foo in ?foo&bar=value, then the returned value will - be nil, whereas for ?foo=&bar=value it would be "". To - differentiate between no-equal and absent, use the HasParam - function. The returned value is decoded from ISO-8859-1 (only in - the case of Request-URL) and we assume that percent-encoded - characters were supplied by the client as UTF-8 sequences, which - are returned exactly as the client supplied them, and may - therefore may contain overlong sequences, control codes, NUL - characters, and even numbers which have been banned by the IETF. - It is the responsibility of the caller to impose further - restrictions on validity, if they're desired. - - EscapeHtml(str) → str - Escapes HTML entities: The set of entities is &><"' which become - &><"'. This function is charset agnostic and - will not canonicalize overlong encodings. It is assumed that a - UTF-8 string will be supplied. See escapehtml.c. - - LaunchBrowser([path:str]) - Launches web browser on local machine with URL to this redbean - server. This function may be called from your /.init.lua. - - CategorizeIp(ip:uint32) → str - Returns a string describing an IP address. This is currently Class - A granular. It can tell you if traffic originated from private - networks, ARIN, APNIC, DOD, etc. - - DecodeBase64(ascii:str) → binary:str - Turns ASCII into binary, in a permissive way that ignores - characters outside the base64 alphabet, such as whitespace. See - decodebase64.c. - - DecodeLatin1(iso-8859-1:str) → utf-8:str - Turns ISO-8859-1 string into UTF-8. - - EncodeBase64(binary:str) → ascii:str - Turns binary into ASCII. This can be used to create HTML data: - URIs that do things like embed a PNG file in a web page. See - encodebase64.c. - - EncodeJson(value[,options:table]) → json:str - Turns passed Lua value into a JSON string. Tables with non-zero - length (as reported by `#`) are encoded as arrays with non-array - elements ignored. Empty tables are encoded as empty arrays. All - other tables are encoded as objects with numerical keys - converted to strings (so `{[3]=1}` is encoded as `{"3":1}`). - The following options can be used: - - useoutput: (bool=false) encodes the result directly to the - output buffer and returns `nil` value. This option is - ignored if used outside of request handling code. - - numformat: (string="%.14g") sets numeric format to be used. - - maxdepth: (number=64) sets the max number of nested tables. - - EncodeLua(value[,options:table]) → json:str - Turns passed Lua value into a Lua string. The following options - can be used: - - useoutput: (bool=false) encodes the result directly to the - output buffer and returns `nil` value. This option is - ignored if used outside of request handling code. - - numformat: (string="%.14g") sets numeric format to be used. - - maxdepth: (number=64) sets the max number of nested tables. - - EncodeLatin1(utf-8:str[,flags:int]) → iso-8859-1:str - Turns UTF-8 into ISO-8859-1 string. - - EscapeFragment(str) → str - Escapes URL #fragment. The allowed characters are - -/?.~_@:!$&'()*+,;=0-9A-Za-z and everything else gets %XX encoded. - Please note that '& can still break HTML and that '() can still - break CSS URLs. This function is charset agnostic and will not - canonicalize overlong encodings. It is assumed that a UTF-8 string - will be supplied. See kescapefragment.c. - - EscapeHost(str) → str - Escapes URL host. See kescapeauthority.c - - EscapeLiteral(str) → str - Escapes JavaScript or JSON string literal content. The caller is - responsible for adding the surrounding quotation marks. This - implementation \uxxxx sequences for all non-ASCII sequences. HTML - entities are also encoded, so the output doesn't need EscapeHtml. - This function assumes UTF-8 input. Overlong encodings are - canonicalized. Invalid input sequences are assumed to be - ISO-8859-1. The output is UTF-16 since that's what JavaScript - uses. For example, some individual codepoints such as emoji - characters will encode as multiple \uxxxx sequences. Ints that are - impossible to encode as UTF-16 are substituted with the \xFFFD - replacement character. See escapejsstringliteral.c. - - EscapeParam(str) → str - Escapes URL parameter name or value. The allowed characters are - -.*_0-9A-Za-z and everything else gets %XX encoded. This function - is charset agnostic and will not canonicalize overlong encodings. - It is assumed that a UTF-8 string will be supplied. See - kescapeparam.c. - - EscapePass(str) → str - Escapes URL password. See kescapeauthority.c. - - EscapePath(str) → str - Escapes URL path. This is the same as EscapeSegment except slash - is allowed. The allowed characters are -.~_@:!$&'()*+,;=0-9A-Za-z/ - and everything else gets %XX encoded. Please note that '& can - still break HTML, so the output may need EscapeHtml too. Also note - that '() can still break CSS URLs. This function is charset - agnostic and will not canonicalize overlong encodings. It is - assumed that a UTF-8 string will be supplied. See kescapepath.c. - - EscapeSegment(str) → str - Escapes URL path segment. This is the same as EscapePath except - slash isn't allowed. The allowed characters are - -.~_@:!$&'()*+,;=0-9A-Za-z and everything else gets %XX encoded. - Please note that '& can still break HTML, so the output may need - EscapeHtml too. Also note that '() can still break CSS URLs. This - function is charset agnostic and will not canonicalize overlong - encodings. It is assumed that a UTF-8 string will be supplied. See - kescapesegment.c. - - EscapeUser(str) → str - Escapes URL username. See kescapeauthority.c. - - Fetch(url:str[,body:str|{method=value:str,body=value:str,...}]) - → status:int,{header:str=value:str,...},body:str - Sends an HTTP/HTTPS request to the specified URL. If only the URL is - provided, then a GET request is sent. If both URL and body parameters - are specified, then a POST request is sent. If any other method needs - to be specified (for example, PUT or DELETE), then passing a table as - the second value allows setting method and body values as well other - options: - - method (default = "GET"): sets the method to be used for the - request. The specified method is converted to uppercase. - - body (default = ""): sets the body value to be sent. - - followredirect (default = true): forces temporary and permanent - redirects to be followed. This behavior can be disabled by - passing `false`. - - maxredirects (default = 5): sets the number of allowed redirects - to minimize looping due to misconfigured servers. When the number - is exceeded, the result of the last redirect is returned. - When the redirect is being followed, the same method and body values - are being sent in all cases except when 303 status is returned. In - that case the method is set to GET and the body is removed before the - redirect is followed. Note that if these (method/body) values are - provided as table fields, they will be modified in place. - - FormatHttpDateTime(seconds:int) → rfc1123:str - Converts UNIX timestamp to an RFC1123 string that looks like this: - Mon, 29 Mar 2021 15:37:13 GMT. See formathttpdatetime.c. - - FormatIp(uint32) → str - Turns integer like 0x01020304 into a string like 1.2.3.4. See also - ParseIp for the inverse operation. - - GetAssetComment(path:str) → str - Returns comment text associated with asset in the ZIP central - directory. Also available as GetComment (deprecated). - - GetAssetMode(path:str) → int - Returns UNIX-style octal mode for ZIP asset (or local file if the - -D flag is used) - - GetAssetSize(path:str) → int - Returns byte size of uncompressed contents of ZIP asset (or local - file if the -D flag is used) - - GetBody() → str - Returns the request message body if present or an empty string. - Also available as GetPayload (deprecated). - - GetCookie(name:str) → str - Returns cookie value. - - GetCryptoHash(name:str,payload:str[,key:str]) → str - Returns value of the specified cryptographic hash function. If the - key is provided, then HMAC value of the same function is returned. - The name can be one of the following strings: MD5, SHA1, SHA224, - SHA256, SHA384, SHA512, and BLAKE2B256. - - GetRemoteAddr() → ip:uint32,port:uint16 - Returns client ip4 address and port, e.g. 0x01020304,31337 would - represent 1.2.3.4:31337. This is the same as GetClientAddr except - it will use the ip:port from the X-Forwarded-For header, only if - IsPrivateIp or IsLoopbackIp return true. When multiple addresses - are present in the header, the last/right-most address is used. - - GetClientAddr() → ip:uint32,port:uint16 - Returns client socket ip4 address and port, e.g. 0x01020304,31337 - would represent 1.2.3.4:31337. Please consider using GetRemoteAddr - instead, since the latter takes into consideration reverse proxy - scenarios. - - GetClientFd() → int - Returns file descriptor being used for client connection. - This is useful for scripts that want to use unix:fork(). - - IsClientUsingSsl() → bool - Returns true if client connection has begun being managed by - the MbedTLS security layer. This is an important thing to - consider if a script is taking control of GetClientFd() - - GetServerAddr() → ip:uint32,port:uint16 - Returns address to which listening server socket is bound, e.g. - 0x01020304,8080 would represent 1.2.3.4:8080. If -p 0 was supplied - as the listening port, then the port in this string will be - whatever number the operating system assigned. - - GetDate() → seconds:int - Returns date associated with request that's used to generate the - Date header, which is now, give or take a second. The returned - value is a UNIX timestamp. - - GetHeader(name:str) → value:str - Returns HTTP header. name is case-insensitive. The header value is - returned as a canonical UTF-8 string, with leading and trailing - whitespace trimmed, which was decoded from ISO-8859-1, which is - guaranteed to not have C0/C1 control sequences, with the exception - of the tab character. Leading and trailing whitespace is - automatically removed. In the event that the client suplies raw - UTF-8 in the HTTP message headers, the original UTF-8 sequence can - be losslessly restored by counter-intuitively recoding the - returned string back to Latin1. If the requested header is defined - by the RFCs as storing comma-separated values (e.g. Allow, - Accept-Encoding) and the field name occurs multiple times in the - message, then this function will fold those multiple entries into - a single string. - - GetHeaders() → {name:str=value:str,...} - Returns HTTP headers as dictionary mapping header key strings to - their UTF-8 decoded values. The ordering of headers from the - request message is not preserved. Whether or not the same key can - repeat depends on whether or not it's a standard header, and if - so, if it's one of the ones that the RFCs define as repeatable. - See khttprepeatable.c. Those headers will not be folded. Standard - headers which aren't on that list, will be overwritten with the - last-occurring one during parsing. Extended headers are always - passed through exactly as they're received. Please consider using - GetHeader API if possible since it does a better job abstracting - these issues. - - GetLogLevel() → int - Returns logger verbosity level. Likely return values are kLogDebug - > kLogVerbose > kLogInfo > kLogWarn > kLogError > kLogFatal. - - GetHost() → str - Returns host associated with request. This will be the Host - header, if it's supplied. Otherwise it's the bind address. - - GetHostOs() → str - Returns string that describes the host OS. - - GetMonospaceWidth(str|char) → int - Returns monospace display width of string. This is useful for - fixed-width formatting. For example, CJK characters typically take - up two cells. This function takes into consideration combining - characters, which are discounted, as well as control codes and - ANSI escape sequences. - - GetMethod() → str - Returns HTTP method. Normally this will be GET, HEAD, or POST in - which case redbean normalizes this value to its uppercase form. - Anything else that the RFC classifies as a "token" string is - accepted too, which might contain characters like &". - - GetParams() → {{name:str[,value:str]},...} - Returns name=value parameters from Request-URL and - application/x-www-form-urlencoded message body in the order they - were received. This may contain duplicates. The inner array will - have either one or two items, depending on whether or not the - equals sign was used. - - GetPath() → str - Returns the Request-URL path. This is guaranteed to begin with - "/". It is further guaranteed that no "//" or "/." exists in the - path. The returned value is returned as a UTF-8 string which was - decoded from ISO-8859-1. We assume that percent-encoded characters - were supplied by the client as UTF-8 sequences, which are returned - exactly as the client supplied them, and may therefore may contain - overlong sequences, control codes, NUL characters, and even - numbers which have been banned by the IETF. redbean takes those - things into consideration when performing path safety checks. It - is the responsibility of the caller to impose further restrictions - on validity, if they're desired. - - GetEffectivePath() → str - Returns path as it was resolved by the routing algorithms, which - might contain the virtual host prepended if used. - - GetScheme() → str - Returns scheme from Request-URL, if any. - - GetSslIdentity() → str - Returns certificate subject or PSK identity from the current SSL - session. `nil` is returned for regular (non-SSL) connections. - - GetStatus() → int - Returns current status (as set by an earlier SetStatus call) or - `nil` if the status hasn't been set yet. - - GetTime() → seconds:number - Returns current time as a UNIX timestamp with 0.0001s precision. - - GetUrl() → str - Returns the effective Request-URL as an ASCII string, where - illegal characters or UTF-8 is guaranteed to be percent encoded, - and has been normalized to include either the Host or - X-Forwarded-Host headers, if they exist, and possibly a scheme too - if redbean is being used as an HTTP proxy server. In the future - this API might change to return an object instead. - - GetHttpVersion() → int - Returns the request HTTP protocol version, which can be 9 for - HTTP/0.9, 10 for HTTP/1.0, or 11 for HTTP/1.1. Also available - as GetVersion (deprecated). - - GetRandomBytes([length:int]) → str - Returns string with the specified number of random bytes (1..256). - If no length is specified, then a string of length 16 is returned. - - GetRedbeanVersion() → int - Returns the Redbean version in the format 0xMMmmpp, with major (MM), - minor (mm), and patch (pp) versions encoded. The version value 1.4 - would be represented as 0x010400. - - GetZipPaths([prefix:str]) → {path:str,...} - Returns paths of all assets in the zip central directory, prefixed - by a slash. If prefix parameter is provided, then only paths that - start with the prefix (case sensitive) are returned. - - HasParam(name:str) → bool - Returns true if parameter with name was supplied in either the - Request-URL or an application/x-www-form-urlencoded message body. - - HidePath(prefix:str) - Programs redbean / listing page to not display any paths beginning - with prefix. This function should only be called from /.init.lua. - - IsPublicIp(uint32) → bool - Returns true if IP address is not a private network (10.0.0.0/8, - 172.16.0.0/12, 192.168.0.0/16) and is not localhost (127.0.0.0/8). - Note: we intentionally regard TEST-NET IPs as public. - - IsPrivateIp(uint32) → bool - Returns true if IP address is part of a private network - (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16). - - IsLoopbackClient() → bool - Returns true if the client IP address (returned by GetRemoteAddr) - is part of the localhost network (127.0.0.0/8). - - IsPrivateClient() → bool - Returns true if the client IP address (returned by GetRemoteAddr) - is part of the localhost network (127.0.0.0/8) or a private network - (10.0.0.0/8, etc.) - - IsLoopbackIp(uint32) → bool - Returns true if IP address is part of the localhost network - (127.0.0.0/8). - - IsCompressed(path:str) → bool - Returns true if ZIP artifact at path is stored on disk using - DEFLATE compression. - - IndentLines(str[,int]) → str - Adds spaces to beginnings of multiline string. If the int - parameter is not supplied then 1 space will be added. - - LoadAsset(path:str) → str - Returns contents of file as string. The asset may be sourced from - either the zip (decompressed) or the local filesystem if the -D - flag was used. If slurping large file into memory is a concern, - then consider using ServeAsset which can serve directly off disk. - - StoreAsset(path:str,data:str[,mode:int]) - Stores asset to executable's ZIP central directory. This currently - happens in an append-only fashion and is still largely in the - proof-of-concept stages. Currently only supported on Linux, XNU, - and FreeBSD. - - Log(level:int,message:str) - Emits message string to log, if level is less than or equal to - GetLogLevel. If redbean is running in interactive mode, then this - will log to the console. If redbean is running as a daemon or the - -L LOGFILE flag is passed, then this will log to the file. - Reasonable values for level are kLogDebug > kLogVerbose > kLogInfo - > kLogWarn > kLogError > kLogFatal. The logger emits timestamps in - the local timezone with microsecond precision. If log entries are - emitted more frequently than once per second, then the log entry - will display a delta timestamp, showing how much time has elapsed - since the previous log entry. This behavior is useful for quickly - measuring how long various portions of your code take to execute. - - ParseHttpDateTime(rfc1123:str) → seconds:int - Converts RFC1123 string that looks like this: Mon, 29 Mar 2021 - 15:37:13 GMT to a UNIX timestamp. See parsehttpdatetime.c. - - ParseUrl(str) → URL - Parses URL, returning object having the following fields: scheme, - user, pass, host, port, path, params, fragment. This parser is - charset agnostic. Percent encoded bytes are decoded for all - fields. Returned values might contain things like NUL characters, - spaces, control codes, and non-canonical encodings. Absent can be - discerned from empty by checking if the pointer is set. There's no - failure condition for this routine. This is a permissive parser. - This doesn't normalize path segments like `.` or `..` so use - IsAcceptablePath() to check for those. No restrictions are imposed - beyond that which is strictly necessary for parsing. All the data - that is provided will be consumed to the one of the fields. Strict - conformance is enforced on some fields more than others, like - scheme, since it's the most non-deterministically defined field of - them all. Please note this is a URL parser, not a URI parser. - Which means we support everything everything the URI spec says we - should do except for the things we won't do, like tokenizing path - segments into an array and then nesting another array beneath each - of those for storing semicolon parameters. So this parser won't - make SIP easy. What it can do is parse HTTP URLs and most URIs - like data:opaque, better in fact than most things which claim to - be URI parsers. - - EncodeUrl(URL) → str - This function is the inverse of ParseUrl. The output will always - be correctly formatted. The exception is if illegal characters are - supplied in the scheme field, since there's no way of escaping - those. Opaque parts are escaped as though they were paths, since - many URI parsers won't understand things like an unescaped - question mark in path. - - ParseIp(str) → int - Converts IPv4 address string to integer, e.g. "1.2.3.4" → - 0x01020304, or returns -1 for invalid inputs. See also FormatIp - for the inverse operation. - - ProgramAddr(str) - Configures the address on which to listen. Can be used multiple - times to set more than one address. - - ProgramBrand(str) - Changes HTTP Server header, as well as the

title on the / - listing page. The brand string needs to be a UTF-8 value that's - encodable as ISO-8859-1. If the brand is changed to something - other than redbean, then the promotional links will be removed - from the listing page too. This function should only be called - from /.init.lua. - - ProgramCache(seconds:int) - Configures Cache-Control and Expires header generation for static - asset serving. A negative value will disable the headers. Zero - means don't cache. Greater than zero asks public proxies and - browsers to cache for a given number of seconds. This should only - be called from /.init.lua. - - ProgramCertificate(pem:str) - Same as the -C flag if called from .init.lua, e.g. - ProgramCertificate(LoadAsset("/.sign.crt")) for zip loading or - ProgramCertificate(Slurp("/etc/letsencrypt.lol/fullchain.pem")) for - local file system only. - - ProgramHeader(name:str,value:str) - Appends HTTP header to the header buffer for all responses (whereas - SetHeader only appends a header to the current response buffer). - name is case-insensitive and restricted to non-space ASCII. value - is a UTF-8 string that must be encodable as ISO-8859-1. Leading and - trailing whitespace is trimmed automatically. Overlong characters - are canonicalized. C0 and C1 control codes are forbidden, with the - exception of tab. The header buffer is independent of the payload - buffer. This function disallows the setting of certain headers such - as Content-Range and Date, which are abstracted by the transport - layer. - - ProgramPort(uint16) - Hard-codes the port number on which to listen, which can be any - number in the range 1..65535, or alternatively 0 to ask the - operating system to choose a port, which may be revealed later on - by GetServerAddr or the -z flag to stdout. - - ProgramPrivateKey(pem:str) - Same as the -K flag if called from .init.lua, e.g. - ProgramPrivateKey(LoadAsset("/.sign.key")) for zip loading or - ProgramPrivateKey(Slurp("/etc/letsencrypt/fullchain.pem")) for - local file system only. - - ProgramRedirect(code:int,src:str,location:str) - Configures fallback routing for paths which would otherwise return - 404 Not Found. If code is 0 then the path is rewritten internally - as an accelerated redirect. If code is 301, 302, 307, or 308 then - a redirect response will be sent to the client. This should only - be called from /.init.lua. - - ProgramSslTicketLifetime(seconds:int) - Defaults to 86400 (24 hours). This may be set to ≤0 to disable - SSL tickets. It's a good idea to use these since it increases - handshake performance 10x and eliminates a network round trip. - - EvadeDragnetSurveillance(bool) - If this option is programmed then redbean will not transmit a - Server Name Indicator (SNI) when performing Fetch() requests. - - ProgramSslPresharedKey(key:str,identity:str) - This function can be used to enable the PSK ciphersuites - which simplify SSL and enhance its performance in controlled - environments. `key` may contain 1..32 bytes of random binary - data and identity is usually a short plaintext string. The - first time this function is called, the preshared key will - be added to both the client and the server SSL configs. If - it's called multiple times, then the remaining keys will be - added to the server, which is useful if you want to assign - separate keys to each client, each of which needs a separate - identity too. If this function is called multiple times with - the same identity string, then the latter call will overwrite - the prior. If a preshared key is supplied and no certificates - or key-signing-keys are programmed, then redbean won't bother - auto-generating any serving certificates and will instead use - only PSK ciphersuites. - - ProgramSslCiphersuite(name:str) - See https://redbean.dev/ for further details. - - IsDaemon() → bool - Returns true if -d flag was passed to redbean. - - ProgramUid(int) - Same as the -U flag if called from .init.lua for setuid() - - ProgramGid(int) - Same as the -G flag if called from .init.lua for setgid() - - ProgramDirectory(str) - Same as the -D flag if called from .init.lua for overlaying local - file system directories. This may be called multiple times. The - first directory programmed is preferred. These currently do not - show up in the index page listing. - - ProgramLogMessages(bool) - Same as the -m flag if called from .init.lua for logging message - headers only. - - ProgramLogBodies(bool) - Same as the -b flag if called from .init.lua for logging message - bodies as part of POST / PUT / etc. requests. - - ProgramLogPath(str) - Same as the -L flag if called from .init.lua for setting the log - file path on the local file system. It's created if it doesn't - exist. This is called before de-escalating the uesr / group id. - The file is opened in append only mode. If the disk runs out of - space then redbean will truncate the log file if has access to - change the log file after daemonizing. - - ProgramPidPath(str) - Same as the -P flag if called from .init.lua for setting the pid - file path on the local file system. It's useful for reloading - daemonized redbean using `kill -HUP $(cat /var/run/redbean.pid)` - or terminating redbean with `kill $(cat /var/run/redbean.pid)` - which will gracefully terminate all clients. Sending the TERM - signal twice will cause a forceful shutdown, which might make - someone with a slow internet connection who's downloading big - files unhappy. - - ProgramUniprocess([bool]) → bool - Same as the -u flag if called from .init.lua. Can be used to - configure the uniprocess mode. The current value is returned. - - Slurp(filename:str) → str - Reads file data from local file system. - - Sleep(seconds:number) - Sleeps the specified number of seconds (can be fractional). The - smallest interval is a microsecond. - - Route([host:str,[path:str]]) - Instructs redbean to follow the normal HTTP serving path. This - function is useful when writing an OnHttpRequest handler, since - that overrides the serving path entirely. So if the handler - decides it doesn't want to do anything, it can simply call this - function, to hand over control back to the redbean core. By - default, the host and path arguments are supplied from the - resolved GetUrl value. This handler always resolves, since it will - generate a 404 Not Found response if redbean couldn't find an - appropriate endpoint. - - RouteHost([host:str,[path:str]]) → bool - This is the same as Route, except it only implements the subset of - request routing needed for serving virtual-hosted assets, where - redbean tries to prefix the path with the hostname when looking up - a file. This function returns true if the request was resolved. If - it was resolved, then your OnHttpRequest request handler can still - set additional headers. - - RoutePath([path:str]) → bool - This is the same as Route, except it only implements the subset of - request routing needed for serving assets. This function returns - true if the request was resolved. If it was resolved, then your - OnHttpRequest request handler can still set additional headers. - Note that the asset needs to have "read other" permissions; - otherwise this function logs a warning and returns 403 Forbidden. - If this is undesirable, use GetAssetMode and ServeAsset to bypass - the check. - - ServeAsset(path:str) - Instructs redbean to serve static asset at path. This function - causes what would normally happen outside a dynamic handler to - happen. The asset can be sourced from either the zip or local - filesystem if -D is used. This function is mutually exclusive with - SetStatus and other Serve* functions. - - ServeError(code:int[,reason:str]) - Instructs redbean to serve a boilerplate error page. This takes - care of logging the error, setting the reason phrase, and adding a - payload. This function is mutually exclusive with SetStatus and - other Serve* functions. - - ServeRedirect(code:int,location:str) - Instructs redbean to return the specified redirect code along with - the Location header set. This function is mutually exclusive with - SetStatus and other Serve* functions. - - SetLogLevel(level:int) - Sets logger verbosity. Reasonable values for level are kLogDebug > - kLogVerbose > kLogInfo > kLogWarn > kLogError > kLogFatal. This is - reset at the end of the http request, so it can be used to disable - access log and message logging. - - VisualizeControlCodes(str) → str - Replaces C0 control codes with their UNICODE pictures - representation. This function also canonicalizes overlong - encodings. C1 control codes are replaced with a JavaScript-like - escape sequence. - - Underlong(str) → str - Canonicalizes overlong encodings. - - Crc32(initial:int,data:str) → int - Computes 32-bit CRC-32 used by zip/zlib/gzip/etc. - - Crc32c(initial:int,data:str) → int - Computes 32-bit Castagnoli Cyclic Redundancy Check. - - Md5(str) → str - Computes MD5 checksum, returning 16 bytes of binary. - - Sha1(str) → str - Computes SHA1 checksum, returning 20 bytes of binary. - - Sha224(str) → str - Computes SHA224 checksum, returning 28 bytes of binary. - - Sha256(str) → str - Computes SHA256 checksum, returning 32 bytes of binary. - - Sha384(str) → str - Computes SHA384 checksum, returning 48 bytes of binary. - - Sha512(str) → str - Computes SHA512 checksum, returning 64 bytes of binary. - - Bsf(x:int) → int - Returns position of first bit set. Passing 0 will raise an error. - Same as the Intel x86 instruction BSF. - - Bsr(x:int) → int - Returns binary logarithm of 𝑥. Passing 0 will raise an error. Same - as the Intel x86 instruction BSR. - - Popcnt(x:int) → int - Returns number of bits set in integer. - - Rdtsc() → int - Returns CPU timestamp counter. - - Lemur64() → int - Returns fastest pseudorandom non-cryptographic random number. This - linear congruential generator passes practrand and bigcrush. - - Rand64() → int - Returns nondeterministic pseudorandom non-cryptographic number. This - linear congruential generator passes practrand and bigcrush. This - generator is safe across fork(), threads, and signal handlers. - - Rdrand() → int - Returns 64-bit hardware random integer from RDRND instruction, with - automatic fallback to getrandom() if not available. - - Rdseed() → int - Returns 64-bit hardware random integer from RDSEED instruction, with - automatic fallback to RDRND and getrandom() if not available. + Write(data:str) + Appends data to HTTP response payload buffer. This is buffered + independently of headers. + + SetStatus(code:int[,reason:str]) + Starts an HTTP response, specifying the parameters on its first + line. reason is optional since redbean can fill in the appropriate + text for well-known magic numbers, e.g. 200, 404, etc. This method + will reset the response and is therefore mutually exclusive with + ServeAsset and other Serve* functions. If this function isn't + called, then the default behavior is to send 200 OK. + + SetHeader(name:str,value:str) + Appends HTTP header to response header buffer. name is + case-insensitive and restricted to non-space ASCII. value is a + UTF-8 string that must be encodable as ISO-8859-1. Leading and + trailing whitespace is trimmed automatically. Overlong characters + are canonicalized. C0 and C1 control codes are forbidden, with the + exception of tab. This function automatically calls SetStatus(200, + "OK") if a status has not yet been set. As SetStatus and Serve* + functions reset the response, SetHeader needs to be called after + SetStatus and Serve* functions are called. The header buffer is + independent of the payload buffer. Neither is written to the wire + until the Lua Server Page has finished executing. This function + disallows the setting of certain headers such as Content-Range and + Date, which are abstracted by the transport layer. In such cases, + consider calling ServeAsset. + + SetCookie(name:str,value:str[,options:table]) + Appends Set-Cookie HTTP header to the response header buffer. + Several Set-Cookie headers can be added to the same response. + __Host- and __Secure- prefixes are supported and may set or + overwrite some of the options (for example, specifying __Host- + prefix sets the Secure option to true, sets the path to "/", and + removes the Domain option). The following options can be used (their + lowercase equivalents are supported as well): + - Expires: sets the maximum lifetime of the cookie as an HTTP-date + timestamp. Can be specified as a Date in the RFC1123 (string) + format or as a UNIX timestamp (number of seconds). + - MaxAge: sets number of seconds until the cookie expires. A zero + or negative number will expire the cookie immediately. If both + Expires and MaxAge are set, MaxAge has precedence. + - Domain: sets the host to which the cookie will be sent. + - Path: sets the path that must be present in the request URL, or + the client will not send the Cookie header. + - Secure: (bool) requests the cookie to be only send to the + server when a request is made with the https: scheme. + - HttpOnly: (bool) forbids JavaScript from accessing the cookie. + - SameSite: (Strict, Lax, or None) controls whether a cookie is + sent with cross-origin requests, providing some protection + against cross-site request forgery attacks. + + GetParam(name:str) → value:str + Returns first value associated with name. name is handled in a + case-sensitive manner. This function checks Request-URL parameters + first. Then it checks application/x-www-form-urlencoded from the + message body, if it exists, which is common for HTML forms sending + POST requests. If a parameter is supplied matching name that has + no value, e.g. foo in ?foo&bar=value, then the returned value will + be nil, whereas for ?foo=&bar=value it would be "". To + differentiate between no-equal and absent, use the HasParam + function. The returned value is decoded from ISO-8859-1 (only in + the case of Request-URL) and we assume that percent-encoded + characters were supplied by the client as UTF-8 sequences, which + are returned exactly as the client supplied them, and may + therefore may contain overlong sequences, control codes, NUL + characters, and even numbers which have been banned by the IETF. + It is the responsibility of the caller to impose further + restrictions on validity, if they're desired. + + EscapeHtml(str) → str + Escapes HTML entities: The set of entities is &><"' which become + &><"'. This function is charset agnostic and + will not canonicalize overlong encodings. It is assumed that a + UTF-8 string will be supplied. See escapehtml.c. + + LaunchBrowser([path:str]) + Launches web browser on local machine with URL to this redbean + server. This function may be called from your /.init.lua. + + CategorizeIp(ip:uint32) → str + Returns a string describing an IP address. This is currently Class + A granular. It can tell you if traffic originated from private + networks, ARIN, APNIC, DOD, etc. + + DecodeBase64(ascii:str) → binary:str + Turns ASCII into binary, in a permissive way that ignores + characters outside the base64 alphabet, such as whitespace. See + decodebase64.c. + + DecodeLatin1(iso-8859-1:str) → utf-8:str + Turns ISO-8859-1 string into UTF-8. + + EncodeBase64(binary:str) → ascii:str + Turns binary into ASCII. This can be used to create HTML data: + URIs that do things like embed a PNG file in a web page. See + encodebase64.c. + + EncodeJson(value[,options:table]) → json:str + Turns passed Lua value into a JSON string. Tables with non-zero + length (as reported by `#`) are encoded as arrays with non-array + elements ignored. Empty tables are encoded as empty arrays. All + other tables are encoded as objects with numerical keys + converted to strings (so `{[3]=1}` is encoded as `{"3":1}`). + The following options can be used: + - useoutput: (bool=false) encodes the result directly to the + output buffer and returns `nil` value. This option is + ignored if used outside of request handling code. + - numformat: (string="%.14g") sets numeric format to be used. + - maxdepth: (number=64) sets the max number of nested tables. + + EncodeLua(value[,options:table]) → json:str + Turns passed Lua value into a Lua string. The following options + can be used: + - useoutput: (bool=false) encodes the result directly to the + output buffer and returns `nil` value. This option is + ignored if used outside of request handling code. + - numformat: (string="%.14g") sets numeric format to be used. + - maxdepth: (number=64) sets the max number of nested tables. + + EncodeLatin1(utf-8:str[,flags:int]) → iso-8859-1:str + Turns UTF-8 into ISO-8859-1 string. + + EscapeFragment(str) → str + Escapes URL #fragment. The allowed characters are + -/?.~_@:!$&'()*+,;=0-9A-Za-z and everything else gets %XX encoded. + Please note that '& can still break HTML and that '() can still + break CSS URLs. This function is charset agnostic and will not + canonicalize overlong encodings. It is assumed that a UTF-8 string + will be supplied. See kescapefragment.c. + + EscapeHost(str) → str + Escapes URL host. See kescapeauthority.c + + EscapeLiteral(str) → str + Escapes JavaScript or JSON string literal content. The caller is + responsible for adding the surrounding quotation marks. This + implementation \uxxxx sequences for all non-ASCII sequences. HTML + entities are also encoded, so the output doesn't need EscapeHtml. + This function assumes UTF-8 input. Overlong encodings are + canonicalized. Invalid input sequences are assumed to be + ISO-8859-1. The output is UTF-16 since that's what JavaScript + uses. For example, some individual codepoints such as emoji + characters will encode as multiple \uxxxx sequences. Ints that are + impossible to encode as UTF-16 are substituted with the \xFFFD + replacement character. See escapejsstringliteral.c. + + EscapeParam(str) → str + Escapes URL parameter name or value. The allowed characters are + -.*_0-9A-Za-z and everything else gets %XX encoded. This function + is charset agnostic and will not canonicalize overlong encodings. + It is assumed that a UTF-8 string will be supplied. See + kescapeparam.c. + + EscapePass(str) → str + Escapes URL password. See kescapeauthority.c. + + EscapePath(str) → str + Escapes URL path. This is the same as EscapeSegment except slash + is allowed. The allowed characters are -.~_@:!$&'()*+,;=0-9A-Za-z/ + and everything else gets %XX encoded. Please note that '& can + still break HTML, so the output may need EscapeHtml too. Also note + that '() can still break CSS URLs. This function is charset + agnostic and will not canonicalize overlong encodings. It is + assumed that a UTF-8 string will be supplied. See kescapepath.c. + + EscapeSegment(str) → str + Escapes URL path segment. This is the same as EscapePath except + slash isn't allowed. The allowed characters are + -.~_@:!$&'()*+,;=0-9A-Za-z and everything else gets %XX encoded. + Please note that '& can still break HTML, so the output may need + EscapeHtml too. Also note that '() can still break CSS URLs. This + function is charset agnostic and will not canonicalize overlong + encodings. It is assumed that a UTF-8 string will be supplied. See + kescapesegment.c. + + EscapeUser(str) → str + Escapes URL username. See kescapeauthority.c. + + Fetch(url:str[,body:str|{method=value:str,body=value:str,...}]) + → status:int,{header:str=value:str,...},body:str + Sends an HTTP/HTTPS request to the specified URL. If only the URL is + provided, then a GET request is sent. If both URL and body parameters + are specified, then a POST request is sent. If any other method needs + to be specified (for example, PUT or DELETE), then passing a table as + the second value allows setting method and body values as well other + options: + - method (default = "GET"): sets the method to be used for the + request. The specified method is converted to uppercase. + - body (default = ""): sets the body value to be sent. + - followredirect (default = true): forces temporary and permanent + redirects to be followed. This behavior can be disabled by + passing `false`. + - maxredirects (default = 5): sets the number of allowed redirects + to minimize looping due to misconfigured servers. When the number + is exceeded, the result of the last redirect is returned. + When the redirect is being followed, the same method and body values + are being sent in all cases except when 303 status is returned. In + that case the method is set to GET and the body is removed before the + redirect is followed. Note that if these (method/body) values are + provided as table fields, they will be modified in place. + + FormatHttpDateTime(seconds:int) → rfc1123:str + Converts UNIX timestamp to an RFC1123 string that looks like this: + Mon, 29 Mar 2021 15:37:13 GMT. See formathttpdatetime.c. + + FormatIp(uint32) → str + Turns integer like 0x01020304 into a string like 1.2.3.4. See also + ParseIp for the inverse operation. + + GetAssetComment(path:str) → str + Returns comment text associated with asset in the ZIP central + directory. Also available as GetComment (deprecated). + + GetAssetMode(path:str) → int + Returns UNIX-style octal mode for ZIP asset (or local file if the + -D flag is used) + + GetAssetSize(path:str) → int + Returns byte size of uncompressed contents of ZIP asset (or local + file if the -D flag is used) + + GetBody() → str + Returns the request message body if present or an empty string. + Also available as GetPayload (deprecated). + + GetCookie(name:str) → str + Returns cookie value. + + GetCryptoHash(name:str,payload:str[,key:str]) → str + Returns value of the specified cryptographic hash function. If the + key is provided, then HMAC value of the same function is returned. + The name can be one of the following strings: MD5, SHA1, SHA224, + SHA256, SHA384, SHA512, and BLAKE2B256. + + GetRemoteAddr() → ip:uint32,port:uint16 + Returns client ip4 address and port, e.g. 0x01020304,31337 would + represent 1.2.3.4:31337. This is the same as GetClientAddr except + it will use the ip:port from the X-Forwarded-For header, only if + IsPrivateIp or IsLoopbackIp return true. When multiple addresses + are present in the header, the last/right-most address is used. + + GetClientAddr() → ip:uint32,port:uint16 + Returns client socket ip4 address and port, e.g. 0x01020304,31337 + would represent 1.2.3.4:31337. Please consider using GetRemoteAddr + instead, since the latter takes into consideration reverse proxy + scenarios. + + GetClientFd() → int + Returns file descriptor being used for client connection. + This is useful for scripts that want to use unix:fork(). + + IsClientUsingSsl() → bool + Returns true if client connection has begun being managed by + the MbedTLS security layer. This is an important thing to + consider if a script is taking control of GetClientFd() + + GetServerAddr() → ip:uint32,port:uint16 + Returns address to which listening server socket is bound, e.g. + 0x01020304,8080 would represent 1.2.3.4:8080. If -p 0 was supplied + as the listening port, then the port in this string will be + whatever number the operating system assigned. + + GetDate() → seconds:int + Returns date associated with request that's used to generate the + Date header, which is now, give or take a second. The returned + value is a UNIX timestamp. + + GetHeader(name:str) → value:str + Returns HTTP header. name is case-insensitive. The header value is + returned as a canonical UTF-8 string, with leading and trailing + whitespace trimmed, which was decoded from ISO-8859-1, which is + guaranteed to not have C0/C1 control sequences, with the exception + of the tab character. Leading and trailing whitespace is + automatically removed. In the event that the client suplies raw + UTF-8 in the HTTP message headers, the original UTF-8 sequence can + be losslessly restored by counter-intuitively recoding the + returned string back to Latin1. If the requested header is defined + by the RFCs as storing comma-separated values (e.g. Allow, + Accept-Encoding) and the field name occurs multiple times in the + message, then this function will fold those multiple entries into + a single string. + + GetHeaders() → {name:str=value:str,...} + Returns HTTP headers as dictionary mapping header key strings to + their UTF-8 decoded values. The ordering of headers from the + request message is not preserved. Whether or not the same key can + repeat depends on whether or not it's a standard header, and if + so, if it's one of the ones that the RFCs define as repeatable. + See khttprepeatable.c. Those headers will not be folded. Standard + headers which aren't on that list, will be overwritten with the + last-occurring one during parsing. Extended headers are always + passed through exactly as they're received. Please consider using + GetHeader API if possible since it does a better job abstracting + these issues. + + GetLogLevel() → int + Returns logger verbosity level. Likely return values are kLogDebug + > kLogVerbose > kLogInfo > kLogWarn > kLogError > kLogFatal. + + GetHost() → str + Returns host associated with request. This will be the Host + header, if it's supplied. Otherwise it's the bind address. + + GetHostOs() → str + Returns string that describes the host OS. + + This can return: + + - `"LINUX"` + - `"METAL"` + - `"WINDOWS"` + - `"XNU"` + - `"NETBSD"` + - `"FREEBSD"` + - `"OPENBSD"` + + GetMonospaceWidth(str|char) → int + Returns monospace display width of string. This is useful for + fixed-width formatting. For example, CJK characters typically take + up two cells. This function takes into consideration combining + characters, which are discounted, as well as control codes and + ANSI escape sequences. + + GetMethod() → str + Returns HTTP method. Normally this will be GET, HEAD, or POST in + which case redbean normalizes this value to its uppercase form. + Anything else that the RFC classifies as a "token" string is + accepted too, which might contain characters like &". + + GetParams() → {{name:str[,value:str]},...} + Returns name=value parameters from Request-URL and + application/x-www-form-urlencoded message body in the order they + were received. This may contain duplicates. The inner array will + have either one or two items, depending on whether or not the + equals sign was used. + + GetPath() → str + Returns the Request-URL path. This is guaranteed to begin with + "/". It is further guaranteed that no "//" or "/." exists in the + path. The returned value is returned as a UTF-8 string which was + decoded from ISO-8859-1. We assume that percent-encoded characters + were supplied by the client as UTF-8 sequences, which are returned + exactly as the client supplied them, and may therefore may contain + overlong sequences, control codes, NUL characters, and even + numbers which have been banned by the IETF. redbean takes those + things into consideration when performing path safety checks. It + is the responsibility of the caller to impose further restrictions + on validity, if they're desired. + + GetEffectivePath() → str + Returns path as it was resolved by the routing algorithms, which + might contain the virtual host prepended if used. + + GetScheme() → str + Returns scheme from Request-URL, if any. + + GetSslIdentity() → str + Returns certificate subject or PSK identity from the current SSL + session. `nil` is returned for regular (non-SSL) connections. + + GetStatus() → int + Returns current status (as set by an earlier SetStatus call) or + `nil` if the status hasn't been set yet. + + GetTime() → seconds:number + Returns current time as a UNIX timestamp with 0.0001s precision. + + GetUrl() → str + Returns the effective Request-URL as an ASCII string, where + illegal characters or UTF-8 is guaranteed to be percent encoded, + and has been normalized to include either the Host or + X-Forwarded-Host headers, if they exist, and possibly a scheme too + if redbean is being used as an HTTP proxy server. In the future + this API might change to return an object instead. + + GetHttpVersion() → int + Returns the request HTTP protocol version, which can be 9 for + HTTP/0.9, 10 for HTTP/1.0, or 11 for HTTP/1.1. Also available + as GetVersion (deprecated). + + GetRandomBytes([length:int]) → str + Returns string with the specified number of random bytes (1..256). + If no length is specified, then a string of length 16 is returned. + + GetRedbeanVersion() → int + Returns the Redbean version in the format 0xMMmmpp, with major (MM), + minor (mm), and patch (pp) versions encoded. The version value 1.4 + would be represented as 0x010400. + + GetZipPaths([prefix:str]) → {path:str,...} + Returns paths of all assets in the zip central directory, prefixed + by a slash. If prefix parameter is provided, then only paths that + start with the prefix (case sensitive) are returned. + + HasParam(name:str) → bool + Returns true if parameter with name was supplied in either the + Request-URL or an application/x-www-form-urlencoded message body. + + HidePath(prefix:str) + Programs redbean / listing page to not display any paths beginning + with prefix. This function should only be called from /.init.lua. + + IsPublicIp(uint32) → bool + Returns true if IP address is not a private network (10.0.0.0/8, + 172.16.0.0/12, 192.168.0.0/16) and is not localhost (127.0.0.0/8). + Note: we intentionally regard TEST-NET IPs as public. + + IsPrivateIp(uint32) → bool + Returns true if IP address is part of a private network + (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16). + + IsLoopbackIp(uint32) → bool + Returns true if IP address is part of the localhost network + (127.0.0.0/8). + + IsCompressed(path:str) → bool + Returns true if ZIP artifact at path is stored on disk using + DEFLATE compression. + + IndentLines(str[,int]) → str + Adds spaces to beginnings of multiline string. If the int + parameter is not supplied then 1 space will be added. + + LoadAsset(path:str) → str + Returns contents of file as string. The asset may be sourced from + either the zip (decompressed) or the local filesystem if the -D + flag was used. If slurping large file into memory is a concern, + then consider using ServeAsset which can serve directly off disk. + + StoreAsset(path:str,data:str[,mode:int]) + Stores asset to executable's ZIP central directory. This currently + happens in an append-only fashion and is still largely in the + proof-of-concept stages. Currently only supported on Linux, XNU, + and FreeBSD. + + Log(level:int,message:str) + Emits message string to log, if level is less than or equal to + GetLogLevel. If redbean is running in interactive mode, then this + will log to the console. If redbean is running as a daemon or the + -L LOGFILE flag is passed, then this will log to the file. + Reasonable values for level are kLogDebug > kLogVerbose > kLogInfo + > kLogWarn > kLogError > kLogFatal. The logger emits timestamps in + the local timezone with microsecond precision. If log entries are + emitted more frequently than once per second, then the log entry + will display a delta timestamp, showing how much time has elapsed + since the previous log entry. This behavior is useful for quickly + measuring how long various portions of your code take to execute. + + ParseHttpDateTime(rfc1123:str) → seconds:int + Converts RFC1123 string that looks like this: Mon, 29 Mar 2021 + 15:37:13 GMT to a UNIX timestamp. See parsehttpdatetime.c. + + ParseUrl(str) → URL + Parses URL, returning object having the following fields: scheme, + user, pass, host, port, path, params, fragment. This parser is + charset agnostic. Percent encoded bytes are decoded for all + fields. Returned values might contain things like NUL characters, + spaces, control codes, and non-canonical encodings. Absent can be + discerned from empty by checking if the pointer is set. There's no + failure condition for this routine. This is a permissive parser. + This doesn't normalize path segments like `.` or `..` so use + IsAcceptablePath() to check for those. No restrictions are imposed + beyond that which is strictly necessary for parsing. All the data + that is provided will be consumed to the one of the fields. Strict + conformance is enforced on some fields more than others, like + scheme, since it's the most non-deterministically defined field of + them all. Please note this is a URL parser, not a URI parser. + Which means we support everything everything the URI spec says we + should do except for the things we won't do, like tokenizing path + segments into an array and then nesting another array beneath each + of those for storing semicolon parameters. So this parser won't + make SIP easy. What it can do is parse HTTP URLs and most URIs + like data:opaque, better in fact than most things which claim to + be URI parsers. + + EncodeUrl(URL) → str + This function is the inverse of ParseUrl. The output will always + be correctly formatted. The exception is if illegal characters are + supplied in the scheme field, since there's no way of escaping + those. Opaque parts are escaped as though they were paths, since + many URI parsers won't understand things like an unescaped + question mark in path. + + ParseIp(str) → int + Converts IPv4 address string to integer, e.g. "1.2.3.4" → + 0x01020304, or returns -1 for invalid inputs. See also FormatIp + for the inverse operation. + + ProgramAddr(str) + Configures the address on which to listen. Can be used multiple + times to set more than one address. + + ProgramBrand(str) + Changes HTTP Server header, as well as the

title on the / + listing page. The brand string needs to be a UTF-8 value that's + encodable as ISO-8859-1. If the brand is changed to something + other than redbean, then the promotional links will be removed + from the listing page too. This function should only be called + from /.init.lua. + + ProgramCache(seconds:int) + Configures Cache-Control and Expires header generation for static + asset serving. A negative value will disable the headers. Zero + means don't cache. Greater than zero asks public proxies and + browsers to cache for a given number of seconds. This should only + be called from /.init.lua. + + ProgramCertificate(pem:str) + Same as the -C flag if called from .init.lua, e.g. + ProgramCertificate(LoadAsset("/.sign.crt")) for zip loading or + ProgramCertificate(Slurp("/etc/letsencrypt.lol/fullchain.pem")) for + local file system only. + + ProgramHeader(name:str,value:str) + Appends HTTP header to the header buffer for all responses (whereas + SetHeader only appends a header to the current response buffer). + name is case-insensitive and restricted to non-space ASCII. value + is a UTF-8 string that must be encodable as ISO-8859-1. Leading and + trailing whitespace is trimmed automatically. Overlong characters + are canonicalized. C0 and C1 control codes are forbidden, with the + exception of tab. The header buffer is independent of the payload + buffer. This function disallows the setting of certain headers such + as Content-Range and Date, which are abstracted by the transport + layer. + + ProgramPort(uint16) + Hard-codes the port number on which to listen, which can be any + number in the range 1..65535, or alternatively 0 to ask the + operating system to choose a port, which may be revealed later on + by GetServerAddr or the -z flag to stdout. + + ProgramPrivateKey(pem:str) + Same as the -K flag if called from .init.lua, e.g. + ProgramPrivateKey(LoadAsset("/.sign.key")) for zip loading or + ProgramPrivateKey(Slurp("/etc/letsencrypt/fullchain.pem")) for + local file system only. + + ProgramRedirect(code:int,src:str,location:str) + Configures fallback routing for paths which would otherwise return + 404 Not Found. If code is 0 then the path is rewritten internally + as an accelerated redirect. If code is 301, 302, 307, or 308 then + a redirect response will be sent to the client. This should only + be called from /.init.lua. + + ProgramSslTicketLifetime(seconds:int) + Defaults to 86400 (24 hours). This may be set to ≤0 to disable + SSL tickets. It's a good idea to use these since it increases + handshake performance 10x and eliminates a network round trip. + + EvadeDragnetSurveillance(bool) + If this option is programmed then redbean will not transmit a + Server Name Indicator (SNI) when performing Fetch() requests. + + ProgramSslPresharedKey(key:str,identity:str) + This function can be used to enable the PSK ciphersuites + which simplify SSL and enhance its performance in controlled + environments. `key` may contain 1..32 bytes of random binary + data and identity is usually a short plaintext string. The + first time this function is called, the preshared key will + be added to both the client and the server SSL configs. If + it's called multiple times, then the remaining keys will be + added to the server, which is useful if you want to assign + separate keys to each client, each of which needs a separate + identity too. If this function is called multiple times with + the same identity string, then the latter call will overwrite + the prior. If a preshared key is supplied and no certificates + or key-signing-keys are programmed, then redbean won't bother + auto-generating any serving certificates and will instead use + only PSK ciphersuites. + + ProgramSslCiphersuite(name:str) + See https://redbean.dev/ for further details. + + IsDaemon() → bool + Returns true if -d flag was passed to redbean. + + ProgramUid(int) + Same as the -U flag if called from .init.lua for setuid() + + ProgramGid(int) + Same as the -G flag if called from .init.lua for setgid() + + ProgramDirectory(str) + Same as the -D flag if called from .init.lua for overlaying local + file system directories. This may be called multiple times. The + first directory programmed is preferred. These currently do not + show up in the index page listing. + + ProgramLogMessages(bool) + Same as the -m flag if called from .init.lua for logging message + headers only. + + ProgramLogBodies(bool) + Same as the -b flag if called from .init.lua for logging message + bodies as part of POST / PUT / etc. requests. + + ProgramLogPath(str) + Same as the -L flag if called from .init.lua for setting the log + file path on the local file system. It's created if it doesn't + exist. This is called before de-escalating the uesr / group id. + The file is opened in append only mode. If the disk runs out of + space then redbean will truncate the log file if has access to + change the log file after daemonizing. + + ProgramPidPath(str) + Same as the -P flag if called from .init.lua for setting the pid + file path on the local file system. It's useful for reloading + daemonized redbean using `kill -HUP $(cat /var/run/redbean.pid)` + or terminating redbean with `kill $(cat /var/run/redbean.pid)` + which will gracefully terminate all clients. Sending the TERM + signal twice will cause a forceful shutdown, which might make + someone with a slow internet connection who's downloading big + files unhappy. + + ProgramUniprocess([bool]) → bool + Same as the -u flag if called from .init.lua. Can be used to + configure the uniprocess mode. The current value is returned. + + Slurp(filename:str) → str + Reads file data from local file system. + + Sleep(seconds:number) + Sleeps the specified number of seconds (can be fractional). The + smallest interval is a microsecond. + + Route([host:str,[path:str]]) + Instructs redbean to follow the normal HTTP serving path. This + function is useful when writing an OnHttpRequest handler, since + that overrides the serving path entirely. So if the handler + decides it doesn't want to do anything, it can simply call this + function, to hand over control back to the redbean core. By + default, the host and path arguments are supplied from the + resolved GetUrl value. This handler always resolves, since it will + generate a 404 Not Found response if redbean couldn't find an + appropriate endpoint. + + RouteHost([host:str,[path:str]]) → bool + This is the same as Route, except it only implements the subset of + request routing needed for serving virtual-hosted assets, where + redbean tries to prefix the path with the hostname when looking up + a file. This function returns true if the request was resolved. If + it was resolved, then your OnHttpRequest request handler can still + set additional headers. + + RoutePath([path:str]) → bool + This is the same as Route, except it only implements the subset of + request routing needed for serving assets. This function returns + true if the request was resolved. If it was resolved, then your + OnHttpRequest request handler can still set additional headers. + Note that the asset needs to have "read other" permissions; + otherwise this function logs a warning and returns 403 Forbidden. + If this is undesirable, use GetAssetMode and ServeAsset to bypass + the check. + + ServeAsset(path:str) + Instructs redbean to serve static asset at path. This function + causes what would normally happen outside a dynamic handler to + happen. The asset can be sourced from either the zip or local + filesystem if -D is used. This function is mutually exclusive with + SetStatus and other Serve* functions. + + ServeError(code:int[,reason:str]) + Instructs redbean to serve a boilerplate error page. This takes + care of logging the error, setting the reason phrase, and adding a + payload. This function is mutually exclusive with SetStatus and + other Serve* functions. + + ServeRedirect(code:int,location:str) + Instructs redbean to return the specified redirect code along with + the Location header set. This function is mutually exclusive with + SetStatus and other Serve* functions. + + SetLogLevel(level:int) + Sets logger verbosity. Reasonable values for level are kLogDebug > + kLogVerbose > kLogInfo > kLogWarn > kLogError > kLogFatal. This is + reset at the end of the http request, so it can be used to disable + access log and message logging. + + VisualizeControlCodes(str) → str + Replaces C0 control codes with their UNICODE pictures + representation. This function also canonicalizes overlong + encodings. C1 control codes are replaced with a JavaScript-like + escape sequence. + + Underlong(str) → str + Canonicalizes overlong encodings. + + Crc32(initial:int,data:str) → int + Computes 32-bit CRC-32 used by zip/zlib/gzip/etc. + + Crc32c(initial:int,data:str) → int + Computes 32-bit Castagnoli Cyclic Redundancy Check. + + Md5(str) → str + Computes MD5 checksum, returning 16 bytes of binary. + + Sha1(str) → str + Computes SHA1 checksum, returning 20 bytes of binary. + + Sha224(str) → str + Computes SHA224 checksum, returning 28 bytes of binary. + + Sha256(str) → str + Computes SHA256 checksum, returning 32 bytes of binary. + + Sha384(str) → str + Computes SHA384 checksum, returning 48 bytes of binary. + + Sha512(str) → str + Computes SHA512 checksum, returning 64 bytes of binary. + + Bsf(x:int) → int + Returns position of first bit set. Passing 0 will raise an error. + Same as the Intel x86 instruction BSF. + + Bsr(x:int) → int + Returns binary logarithm of 𝑥. Passing 0 will raise an error. Same + as the Intel x86 instruction BSR. + + Popcnt(x:int) → int + Returns number of bits set in integer. + + Rdtsc() → int + Returns CPU timestamp counter. + + Lemur64() → int + Returns fastest pseudorandom non-cryptographic random number. This + linear congruential generator passes practrand and bigcrush. + + Rand64() → int + Returns nondeterministic pseudorandom non-cryptographic number. This + linear congruential generator passes practrand and bigcrush. This + generator is safe across fork(), threads, and signal handlers. - GetCpuCore() → int - Returns 0-indexed CPU core on which process is currently scheduled. + Rdrand() → int + Returns 64-bit hardware random integer from RDRND instruction, with + automatic fallback to getrandom() if not available. - GetCpuNode() → int - Returns 0-indexed NUMA node on which process is currently scheduled. + Rdseed() → int + Returns 64-bit hardware random integer from RDSEED instruction, with + automatic fallback to RDRND and getrandom() if not available. - Decimate(data) → int - Shrinks byte buffer in half using John Costella's magic kernel. - This downscales data 2x using an eight-tap convolution, e.g. + GetCpuCore() → int + Returns 0-indexed CPU core on which process is currently scheduled. - >: Decimate(b'\\xff\\xff\\x00\\x00\\xff\\xff\\x00\\x00\\xff\\xff\\x00\\x00') - b'\\xff\\x00\\xff\\x00\\xff\\x00' + GetCpuNode() → int + Returns 0-indexed NUMA node on which process is currently scheduled. - This is very fast if SSSE3 is available (Intel 2004+ / AMD 2011+). + Decimate(data) → int + Shrinks byte buffer in half using John Costella's magic kernel. + This downscales data 2x using an eight-tap convolution, e.g. - MeasureEntropy(data) → float - Returns Shannon entropy of array. This gives you an idea of - the density of information. Cryptographic random should be in - the ballpark of 7.9 whereas plaintext will be more like 4.5. + >: Decimate(b'\\xff\\xff\\x00\\x00\\xff\\xff\\x00\\x00\\xff\\xff\\x00\\x00') + b'\\xff\\x00\\xff\\x00\\xff\\x00' + This is very fast if SSSE3 is available (Intel 2004+ / AMD 2011+). + + MeasureEntropy(data) → float + Returns Shannon entropy of array. This gives you an idea of + the density of information. Cryptographic random should be in + the ballpark of 7.9 whereas plaintext will be more like 4.5. + + +CONSTANTS + + kLogDebug + Integer for debug logging level. See Log. + + kLogVerbose + Integer for verbose logging level, which is less than kLogDebug. + + kLogInfo + Integer for info logging level, which is less than kLogVerbose. + + kLogWarn + Integer for warn logging level, which is less than kLogVerbose. + + kLogError + Integer for error logging level, which is less than kLogWarn. + + kLogFatal + Integer for fatal logging level, which is less than kLogError. + Logging anything at this level will result in a backtrace and + process exit. + + LSQLITE3 MODULE - Please refer to the LuaSQLite3 Documentation. + Please refer to the LuaSQLite3 Documentation. - For example, you could put the following in your /.init.lua file: + For example, you could put the following in your /.init.lua file: - sqlite3 = require "lsqlite3" - db = sqlite3.open_memory() - db:exec[[ - CREATE TABLE test ( - id INTEGER PRIMARY KEY, - content TEXT - ); - INSERT INTO test (content) VALUES ('Hello World'); - INSERT INTO test (content) VALUES ('Hello Lua'); - INSERT INTO test (content) VALUES ('Hello Sqlite3'); - ]] + sqlite3 = require "lsqlite3" + db = sqlite3.open_memory() + db:exec[[ + CREATE TABLE test ( + id INTEGER PRIMARY KEY, + content TEXT + ); + INSERT INTO test (content) VALUES ('Hello World'); + INSERT INTO test (content) VALUES ('Hello Lua'); + INSERT INTO test (content) VALUES ('Hello Sqlite3'); + ]] - Then, your Lua server pages or OnHttpRequest handler may perform SQL - queries by accessing the db global. The performance is good too, at about - 400k qps. + Then, your Lua server pages or OnHttpRequest handler may perform SQL + queries by accessing the db global. The performance is good too, at about + 400k qps. - for row in db:nrows("SELECT * FROM test") do - Write(row.id.." "..row.content.."
") - end + for row in db:nrows("SELECT * FROM test") do + Write(row.id.." "..row.content.."
") + end - redbean supports a subset of what's defined in the upstream LuaSQLite3 - project. Most of the unsupported APIs relate to pointers and database - notification hooks. + redbean supports a subset of what's defined in the upstream LuaSQLite3 + project. Most of the unsupported APIs relate to pointers and database + notification hooks. - redbean also currently disables SQLite features which don't make sense for - production serving, such as ALTER, VACUUM, ANALYZE, etc. For that reason - we provide an APE build of the SQLite shell which you can use to - administrate your redbean database. See the sqlite3.com download above. + redbean also currently disables SQLite features which don't make sense for + production serving, such as ALTER, VACUUM, ANALYZE, etc. For that reason + we provide an APE build of the SQLite shell which you can use to + administrate your redbean database. See the sqlite3.com download above. + RE MODULE - This module exposes an API for POSIX regular expressions which enable you - to validate input, search for substrings, extract pieces of strings, etc. - Here's a usage example: + This module exposes an API for POSIX regular expressions which enable you + to validate input, search for substrings, extract pieces of strings, etc. + Here's a usage example: - # Example IPv4 Address Regular Expression (see also ParseIP) - p = re.compile([[^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$]]) - m,a,b,c,d = p:search(𝑠) - if m then - print("ok", tonumber(a), tonumber(b), tonumber(c), tonumber(d)) - else - print("not ok") - end + # Example IPv4 Address Regular Expression (see also ParseIP) + p = re.compile([[^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$]]) + m,a,b,c,d = p:search(𝑠) + if m then + print("ok", tonumber(a), tonumber(b), tonumber(c), tonumber(d)) + else + print("not ok") + end - re.search(regex:str,text:str[,flags:int]) → [match[,group_1,...]] - Shortcut for re.compile plus regex_t*:search. + re.search(regex:str,text:str[,flags:int]) → [match[,group_1,...]] + Shortcut for re.compile plus regex_t*:search. - re.compile(regex:str[,flags:int]) → regex_t* - Compiles regular expression, using the POSIX extended syntax. This - has an O(2^𝑛) cost, so it's a good idea to do this from your - /.init.lua file. Flags may contain re.BASIC, re.ICASE, re.NOSUB, - and/or re.NEWLINE. See also regcomp() from libc. + re.compile(regex:str[,flags:int]) → regex_t* + Compiles regular expression, using the POSIX extended syntax. This + has an O(2^𝑛) cost, so it's a good idea to do this from your + /.init.lua file. Flags may contain re.BASIC, re.ICASE, re.NOSUB, + and/or re.NEWLINE. See also regcomp() from libc. - regex_t*:search(text:str[,flags:int]) → [match[,group_1,...]] - Executes regular expression. This has an O(𝑛) cost. This returns - nothing (nil) if the pattern doesn't match anything. Otherwise it - pushes the matched substring and any parenthesis-captured values - too. Flags may contain re.NOTBOL or re.NOTEOL to indicate whether - or not text should be considered at the start and/or end of a - line. + regex_t*:search(text:str[,flags:int]) → [match[,group_1,...]] + Executes regular expression. This has an O(𝑛) cost. This returns + nothing (nil) if the pattern doesn't match anything. Otherwise it + pushes the matched substring and any parenthesis-captured values + too. Flags may contain re.NOTBOL or re.NOTEOL to indicate whether + or not text should be considered at the start and/or end of a + line. - re.BASIC - Use this flag if you prefer the default POSIX regex syntax. We use - extended regex notation by default. For example, an extended - regular expression for matching an IP address might look like - ([0-9]*)\.([0-9]*)\.([0-9]*)\.([0-9]*) whereas with basic syntax - it would look like \([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\). - This flag may only be used with re.compile and re.search. + re.BASIC + Use this flag if you prefer the default POSIX regex syntax. We use + extended regex notation by default. For example, an extended + regular expression for matching an IP address might look like + ([0-9]*)\.([0-9]*)\.([0-9]*)\.([0-9]*) whereas with basic syntax + it would look like \([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\). + This flag may only be used with re.compile and re.search. - re.ICASE - Use this flag to make your pattern case ASCII case-insensitive. - This means [a-z] will mean the same thing as [A-Za-z]. This flag - may only be used with re.compile and re.search. + re.ICASE + Use this flag to make your pattern case ASCII case-insensitive. + This means [a-z] will mean the same thing as [A-Za-z]. This flag + may only be used with re.compile and re.search. - re.NEWLINE - Use this flag to change the handling of NEWLINE (\x0a) characters. - When this flag is set, (1) a NEWLINE shall not be matched by a "." - or any form of a non-matching list, (2) a "^" shall match the - zero-length string immediately after a NEWLINE (regardless of - re.NOTBOL), and (3) a "$" shall match the zero-length string - immediately before a NEWLINE (regardless of re.NOTEOL). + re.NEWLINE + Use this flag to change the handling of NEWLINE (\x0a) characters. + When this flag is set, (1) a NEWLINE shall not be matched by a "." + or any form of a non-matching list, (2) a "^" shall match the + zero-length string immediately after a NEWLINE (regardless of + re.NOTBOL), and (3) a "$" shall match the zero-length string + immediately before a NEWLINE (regardless of re.NOTEOL). - re.NOSUB - Causes re.search to only report success and failure. This is - reported via the API by returning empty string for success. This - flag may only be used with re.compile and re.search. + re.NOSUB + Causes re.search to only report success and failure. This is + reported via the API by returning empty string for success. This + flag may only be used with re.compile and re.search. - re.NOTBOL - The first character of the string pointed to by string is not the - beginning of the line. This flag may only be used with re.search - and regex_t*:search. + re.NOTBOL + The first character of the string pointed to by string is not the + beginning of the line. This flag may only be used with re.search + and regex_t*:search. - re.NOTEOL - The last character of the string pointed to by string is not the - end of the line. This flag may only be used with re.search and - regex_t*:search. + re.NOTEOL + The last character of the string pointed to by string is not the + end of the line. This flag may only be used with re.search and + regex_t*:search. + MAXMIND MODULE - This module may be used to get city/country/asn/etc from IPs, e.g. + This module may be used to get city/country/asn/etc from IPs, e.g. - -- .init.lua - maxmind = require "maxmind" - asndb = maxmind.open('/usr/local/share/maxmind/GeoLite2-ASN.mmdb') + -- .init.lua + maxmind = require "maxmind" + asndb = maxmind.open('/usr/local/share/maxmind/GeoLite2-ASN.mmdb') - -- request handler - as = asndb:lookup(GetRemoteAddr()) - if as then - asnum = as:get("autonomous_system_number") - asorg = as:get("autonomous_system_organization") - Write(EscapeHtml(asnum)) - Write(' ') - Write(EscapeHtml(asorg)) - end + -- request handler + as = asndb:lookup(GetRemoteAddr()) + if as then + asnum = as:get("autonomous_system_number") + asorg = as:get("autonomous_system_organization") + Write(EscapeHtml(asnum)) + Write(' ') + Write(EscapeHtml(asorg)) + end - For further details, please see maxmind.lua in redbean-demo.com. + For further details, please see maxmind.lua in redbean-demo.com. + UNIX MODULE This module exposes the low-level UNIX system call interface. The way @@ -1281,23 +1334,39 @@ UNIX MODULE some kind of error obtaining the required arguments. Once Lua reads the arguments and the call is delegated to the system call interface, all further errors won't be raised, but rather returned as errnos, - which should always be checked. For example, most calls follow: + which should always be checked. For example, most syscalls follow: - rc, errno = unix.foo(...) + errno = unix.foo(...) + if errno then + Log(kLogWarn, 'foo() failed: %s' % {unix.strerror(errno)}) + end - Where the underlying call returning an rc of -1 will map to a Lua - value of nil, and if the system call doesn't return an error number - then errno will be nil and rc will be non-nil. To see which errnos are - possible for which system calls, please see the comprehensive index at - the bottom of this section. + Any POSIX API that's defined as returning 0 on success or -1 on error + is wrapped here to return nil on success and an integer on error. To + see which errnos are possible for which system calls, please see the + comprehensive index at the bottom of this section. - Your system calls are: + In cases where POSIX defines an API as returning codes on success we + wrap the APIs as follows: + + rc, errno = unix.bar(...) + if rc then + Log(kLogWarn, 'foo() succeeded: %d' % {rc}) + else + Log(kLogWarn, 'foo() failed: %s' % {unix.strerror(errno)}) + end + + If the above code succeeds, `rc` will be non-nil and `errno` will be + `nil`. If the above code fails, `rc` will be nil and `errno` will be + an integer greater than zero. + + UNIX FUNCTIONS unix.read(fd:int[, bufsiz:int, offset:int]) → data:str[, errno:int] Reads from file descriptor. - unix.write(fd:int, data[, offset]) → rc:int[, errno:int] + unix.write(fd:int, data[, offset:int]) → wrote:int[, errno:int] Writes to file descriptor. @@ -1343,7 +1412,7 @@ UNIX MODULE already. If it does exist then `nil` is returned along with `errno` set to `EEXIST`. - unix.close(fd:int) → rc:int[, errno:int] + unix.close(fd:int) → errno:int Closes file descriptor. @@ -1354,6 +1423,26 @@ UNIX MODULE will be closed. Any open connections it owns will be reset. This function never returns. + unix.environ() → {str, ...} + + Returns raw environment variables. + + This allocates and constructs the C/C++ `environ` variable as a Lua + table consisting of string keys and string values. + + This data structure preserves casing. On Windows NT, by convention, + environment variable keys are treated in a case-insensitive way. It + is the responsibility of the caller to consider this. + + This data structure preserves valueless variables. It's possible on + both UNIX and Windows to have an environment variable without an + equals, even though it's unusual. + + This data structure preserves duplicates. For example, on Windows, + there's some irregular uses of environment variables such as how the + command prompt inserts multiple environment variables with empty + string as keys, for its internal bookkeeping. + unix.fork() → childpid|0:int[, errno:int] Creates a new process mitosis style. This returns twice. The @@ -1368,14 +1457,14 @@ UNIX MODULE `prog` contains slashes then it's not path searched either and will be returned if it exists. - unix.execve(prog:str[, args:List<*>, env:Map]) → errno:int + unix.execve(prog:str[, args:List<*>[, env:List<*>]]) → errno:int Exits current process, replacing it with a new instance of the specified program. `prog` needs to be an absolute path, see commandv(). `env` defaults to to the current `environ`. Here's a basic usage example: - unix.execve("/bin/ls", {"/bin/ls", "-hal"}, {PATH="/bin"}) + unix.execve("/bin/ls", {"/bin/ls", "-hal"}, {"PATH=/bin"}) unix.exit(127) `prog` needs to be the resolved pathname of your executable. You @@ -1385,12 +1474,16 @@ UNIX MODULE should be `prog`. Values are coerced to strings. This parameter defaults to `{prog}`. - `env` is a key/value table. Keys that aren't strings are - ignored. Values are coerced to strings. This parameter defaults - to environ() in a way that avoids copying. + `env` is a string list table. Values are coerced to strings. No + ordering requirement is imposed. By convention, each string has its + key and value divided by an equals sign without spaces. If this + paremeter is not specified, it'll default to the C/C++ `environ` + variable which is inherited from the shell that launched redbean. + It's the responsibility of the user to supply a sanitized environ + when spawning untrusted processes. - execve() function is normally called after fork() returns 0. If - that isn't the case, then your redbean worker will be destroyed. + execve() is normally called after fork() returns 0. If that isn't + the case, then your redbean worker will be destroyed. This function never returns on success. @@ -1408,7 +1501,7 @@ UNIX MODULE `flags` can have `O_CLOEXEC` which means the returned file descriptors will be automatically closed upon execve(). - unix.pipe([flags]) → reader, writer, errno:int + unix.pipe([flags:int]) → reader:int, writer:int[, errno:int] Creates fifo which enables communication between processes. Returns two file descriptors: one for reading and one for @@ -1485,15 +1578,19 @@ UNIX MODULE end end - unix.getpid() → pid + unix.getpid() → pid:int Returns process id of current process. - unix.getppid() → pid + This function does not fail. + + unix.getppid() → pid:int Returns process id of parent process. - unix.kill(pid, sig) → rc:int[, errno:int] + This function does not fail. + + unix.kill(pid, sig) → errno:int Returns process id of current process. @@ -1502,41 +1599,67 @@ UNIX MODULE Triggers signal in current process. This is pretty much the same as `kill(getpid(), sig)`. - unix.access(path:str, how) → rc:int[, errno:int] + unix.access(path:str, how) → errno:int - Checks if effective user of current process has permission to - access file. `how` can be `R_OK`, `W_OK`, `X_OK`, or `F_OK` to - check for read, write, execute, and existence respectively. + Checks if effective user of current process has permission to access + file. `how` can be `R_OK`, `W_OK`, `X_OK`, or `F_OK` to check for + read, write, execute, and existence respectively. - unix.mkdir(path:str, mode) → rc:int[, errno:int] + unix.mkdir(path:str, mode) → errno:int - Makes directory. `mode` should be octal, e.g. `0755`. + Makes directory. - unix.chdir(path:str) → rc:int[, errno:int] + `path` is the path of the directory you wish to create. + + `mode` is octal permission bits, e.g. `0755`. + + Fails with `EEXIST` if `path` already exists, whether it be a + directory or a file. + + Fails with `ENOENT` if the parent directory of the directory you + want to create doesn't exist. For making `a/really/long/path/` + consider using makedirs() instead. + + Fails with `ENOTDIR` if a parent directory component existed that + wasn't a directory. + + Fails with `EACCES` if the parent directory doesn't grant write + permission to the current user. + + Fails with `ENAMETOOLONG` if the path is too long. + + unix.makedirs(path:str, mode) → errno:int + + Makes directories. + + `path` is the path of the directory you wish to create. + + `mode` is octal permission bits, e.g. `0755`. + + Unlike mkdir() this convenience wrapper will automatically create + parent parent directories as needed. + + unix.chdir(path:str) → errno:int Changes current directory to `path`. - unix.unlink(path:str) → rc:int[, errno:int] + unix.unlink(path:str) → errno:int Removes file at `path`. - unix.rmdir(path:str) → rc:int[, errno:int] + unix.rmdir(path:str) → errno:int Removes empty directory at `path`. - unix.chroot(path:str) → rc:int[, errno:int] + unix.rename(oldpath:str, newpath:str) → errno:int - Changes root directory. Raises `ENOSYS` on Windows. + Renames file or directory. - unix.rename(oldpath:str, newpath:str) → rc:int[, errno:int] - - Renames file. - - unix.link(existingpath:str, newpath:str) → rc:int[, errno:int] + unix.link(existingpath:str, newpath:str) → errno:int Creates hard link, so your underlying inode has two names. - unix.symlink(target:str, linkpath:str) → rc:int[, errno:int] + unix.symlink(target:str, linkpath:str) → errno:int Creates soft link, or a symbolic link. @@ -1545,15 +1668,15 @@ UNIX MODULE Returns absolute path of filename, with `.` and `..` components removed, and symlinks will be resolved. - unix.chown(path:str, uid, gid) → rc:int[, errno:int] + unix.chown(path:str, uid, gid) → errno:int Changes user and gorup on file. - unix.chmod(path:str, mode) → rc:int[, errno:int] + unix.chmod(path:str, mode) → errno:int Changes mode bits on file. - unix.getcwd(path:str, mode) → rc:int[, errno:int] + unix.getcwd() → path:str[, errno:int] Returns current working directory. @@ -1568,62 +1691,165 @@ UNIX MODULE POSIX advisory locks can be controlled by setting `cmd` to `F_UNLCK`, `F_RDLCK`, `F_WRLCK`, `F_SETLK`, or `F_SETLKW`. - unix.getsid(pid) → sid, errno:int + unix.getsid(pid:int) → sid:int[, errno:int] Gets session id. - unix.getpgrp() → pgid, errno:int + unix.getpgrp() → pgid:int[, errno:int] Gets process group id. - unix.setpgrp() → pgid, errno:int + unix.setpgrp() → pgid:int[, errno:int] Sets process group id. This is the same as `setpgid(0,0)`. - unix.setpgid(pid, pgid) → pgid, errno:int + unix.setpgid(pid:int, pgid:int) → pgid:int[, errno:int] Sets process group id the modern way. - unix.getpgid(pid) → pgid, errno:int + unix.getpgid(pid) → pgid:int[, errno:int] Gets process group id the modern wayp. - unix.setsid() → sid, errno:int + unix.setsid() → sid:int[, errno:int] Sets session id. This function can be used to create daemons. + Fails with `ENOSYS` on Windows NT. + unix.getuid() → uid:int - Gets user id. + Gets real user id. + + On Windows this system call is polyfilled by running GetUserNameW() + through Knuth's multiplicative hash. + + This function does not fail. unix.getgid() → gid:int - Sets group id. + Sets real group id. - unix.setuid(uid:int) → rc:int[, errno:int] + On Windows this system call is polyfilled as getuid(). + + This function does not fail. + + unix.geteuid() → uid:int + + Gets effective user id. + + For example, if your redbean is a setuid binary, then getuid() will + return the uid of the user running the program, and geteuid() shall + return zero which means root, assuming that's the file owning user. + + On Windows this system call is polyfilled as getuid(). + + This function does not fail. + + unix.getegid() → gid:int + + Gets effective group id. + + On Windows this system call is polyfilled as getuid(). + + This function does not fail. + + unix.chroot(path:str) → errno:int + + Changes root directory. + + Returns `ENOSYS` on Windows NT. + + unix.setuid(uid:int) → errno:int Sets user id. - unix.setgid(gid:int) → rc:int[, errno:int] + One use case for this function is dropping root privileges. Should + you ever choose to run redbean as root and decide not to use the + `-G` and `-U` flags, you can replicate that behavior in the Lua + processes you spawn as follows: + + errno = unix.setgid(1000) -- check your /etc/groups + if errno then + Log(kLogFatal, setgid() failed: %s' % {unix.strerror(errno)}) + end + errno = unix.setuid(1000) -- check your /etc/passwd + if errno then + Log(kLogFatal, setuid() failed: %s' % {unix.strerror(errno)}) + end + + If your goal is to relinquish privileges because redbean is a setuid + binary, then things are more straightforward: + + errno = unix.setgid(unix.getgid()) + if errno then + Log(kLogFatal, setgid() failed: %s' % {unix.strerror(errno)}) + end + errno = unix.setuid(unix.getuid()) + if errno then + Log(kLogFatal, setuid() failed: %s' % {unix.strerror(errno)}) + end + + See also the setresuid() function and be sure to refer to your local + system manual about the subtleties of changing user id in a way that + isn't restorable. + + Returns `ENOSYS` on Windows NT if `uid` isn't `getuid()`. + + unix.setgid(gid:int) → errno:int Sets group id. - unix.umask(mask) → oldmask:int + Returns `ENOSYS` on Windows NT if `gid` isn't `getgid()`. + + unix.setresuid(real:int, effective:int, saved:int) → errno:int + + Sets real, effective, and saved user ids. + + If any of the above parameters are -1, then it's a no-op. + + Returns `ENOSYS` on Windows NT. + Returns `ENOSYS` on Macintosh and NetBSD if `saved` isn't -1. + + unix.setresgid(real:int, effective:int, saved:int) → errno:int + + Sets real, effective, and saved group ids. + + If any of the above parameters are -1, then it's a no-op. + + Returns `ENOSYS` on Windows NT. + Returns `ENOSYS` on Macintosh and NetBSD if `saved` isn't -1. + + unix.umask(mask:int) → oldmask:int Sets file permission mask and returns the old one. + This is used to remove bits from the `mode` parameter of functions + like open() and mkdir(). The masks typically used are 027 and 022. + Those masks ensure that, even if a file is created with 0666 bits, + it'll be turned into 0640 or 0644 so that users other than the owner + can't modify it. + + To read the mask without changing it, try doing this: + + mask = unix.umask(027) + unix.umask(mask) + + On Windows NT this is a no-op and `mask` is returned. + + This function does not fail. + unix.syslog(priority:int, msg:str) Generates a log message, which will be distributed by syslogd. - `priority` is a bitmask containing the facility value and the - level value. If no facility value is ORed into priority, then - the default value set by openlog() is used. If set to NULL, the - program name is used. Level is one of `LOG_EMERG`, `LOG_ALERT`, - `LOG_CRIT`, `LOG_ERR`, `LOG_WARNING`, `LOG_NOTICE`, `LOG_INFO`, - `LOG_DEBUG`. + `priority` is a bitmask containing the facility value and the level + value. If no facility value is ORed into priority, then the default + value set by openlog() is used. If set to NULL, the program name is + used. Level is one of `LOG_EMERG`, `LOG_ALERT`, `LOG_CRIT`, + `LOG_ERR`, `LOG_WARNING`, `LOG_NOTICE`, `LOG_INFO`, `LOG_DEBUG`. This function currently works on Linux, Windows, and NetBSD. On WIN32 it uses the ReportEvent() facility. @@ -1640,44 +1866,77 @@ UNIX MODULE `CLOCK_REALTIME_ALARM`, and `CLOCK_BOOTTIME_ALARM`, unix.nanosleep(seconds:int[, nanos:int]) - → remseconds:int, remnanos:int, errno:int + → remseconds:int, remnanos:int[, errno:int] Sleeps with nanosecond precision. unix.sync() - unix.fsync(fd:int) → rc:int[, errno:int] - unix.fdatasync(fd:int) → rc:int[, errno:int] + unix.fsync(fd:int) → errno:int + unix.fdatasync(fd:int) → errno:int These functions are used to make programs slower by asking the operating system to flush data to the physical medium. - unix.seek(fd:int, offset:int, whence:int) → newpos:int[, errno:int] + unix.lseek(fd:int, offset:int, whence:int) → newpos:int[, errno:int] Seeks to file position. - `whence` can be one of `SEEK_SET`, `SEEK_CUR`, or `SEEK_END`. + `whence` can be one of: - unix.truncate(path:str, length) → rc:int[, errno:int] - unix.ftruncate(fd:int, length) → rc:int[, errno:int] + - `SEEK_SET`: Sets the file position to `offset` + - `SEEK_CUR`: Sets the file position to `position + offset` + - `SEEK_END`: Sets the file position to `filesize + offset` + + Returns the new position relative to the start of the file. + + unix.truncate(path:str[, length:int]) → errno:int Reduces or extends underlying physical medium of file. If file was originally larger, content >length is lost. - unix.socket([family[, type[, protocol]]]) → fd:int[, errno:int] + `length` defaults to zero. - `SOCK_CLOEXEC` may be or'd into type - `family` defaults to `AF_INET` but can be `AF_UNIX` - `type` defaults to `SOCK_STREAM` but can be `SOCK_DGRAM` - `protocol` defaults to `IPPROTO_TCP` but can be `IPPROTO_UDP` + unix.ftruncate(fd:int[, length:int]) → errno:int - unix.socketpair([family[, type[, protocol]]]) → fd1, fd2, errno:int + Reduces or extends underlying physical medium of open file. + If file was originally larger, content >length is lost. + + `length` defaults to zero. + + unix.socket([family:int[, type:int[, protocol:int]]]) → fd:int[, errno:int] + + `family` defaults to `AF_INET` and can be: + + - `AF_UNIX` + - `AF_INET` + + `type` defaults to `SOCK_STREAM` and can be: + + - `SOCK_STREAM` + - `SOCK_DGRAM` + - `SOCK_RAW` + - `SOCK_RDM` + - `SOCK_SEQPACKET` + + `protocol` defaults to `IPPROTO_TCP` and can be: + + - `IPPROTO_IP` + - `IPPROTO_ICMP` + - `IPPROTO_TCP` + - `IPPROTO_UDP` + - `IPPROTO_RAW` + + `SOCK_CLOEXEC` may be bitwise or'd into `type`. + + unix.socketpair([family:int[, type:int[, protocol:int]]]) + → fd1:int, fd2:int[, errno:int] `SOCK_CLOEXEC` may be or'd into type `family` defaults to `AF_INET` `type` defaults to `SOCK_STREAM` `protocol` defaults to `IPPROTO_TCP` - unix.bind(fd:int[, ip:uint32, port:uint16]) → rc:int[, errno:int] + unix.bind(fd:int[, ip:uint32, port:uint16]) → errno:int Binds socket. @@ -1685,14 +1944,19 @@ UNIX MODULE wanted to listen on `1.2.3.4:31337` you could do any of these unix.bind(sock, 0x01020304, 31337) + unix.bind(sock, ParseIp('1.2.3.4'), 31337) unix.bind(sock, 1 << 24 | 0 << 16 | 0 << 8 | 1, 31337) `ip` and `port` both default to zero. The meaning of bind(0, 0) is to listen on all interfaces with a kernel-assigned ephemeral port number, that can be retrieved and used as follows: - local sock = unix.socket() -- create ipv4 tcp socket - unix.bind(sock) -- all interfaces arbitrary port + local sock = unix.socket() -- create ipv4 tcp socket + errno = unix.bind(sock) -- all interfaces ephemeral port + if errno then + Log(kLogWarn, bind() failed: %s' % {unix.strerror(errno)}) + return + end ip, port = unix.getsockname(sock) print("listening on ip", FormatIp(ip), "port", port) unix.listen(sock) @@ -1710,6 +1974,55 @@ UNIX MODULE Returns list of network adapter addresses. + unix.getsockopt(fd:int, level:int, optname:int) → errno:int, ... + unix.setsockopt(fd:int, level:int, optname:int, ...) → errno:int + + Tunes networking parameters. + + `level` and `optname` may be one of the following. Please note the + type signature for getsockopt() changes depending on these values: + + - `SOL_SOCKET` + `SO_DEBUG`: bool + - `SOL_SOCKET` + `SO_BROADCAST`: bool + - `SOL_SOCKET` + `SO_REUSEADDR`: bool + - `SOL_SOCKET` + `SO_REUSEPORT`: bool + - `SOL_SOCKET` + `SO_KEEPALIVE`: bool + - `SOL_SOCKET` + `SO_DONTROUTE`: bool + - `SOL_SOCKET` + `SO_SNDBUF`: int + - `SOL_SOCKET` + `SO_RCVBUF`: int + - `SOL_SOCKET` + `SO_RCVLOWAT`: int + - `SOL_SOCKET` + `SO_SNDLOWAT`: int + - `SOL_SOCKET` + `SO_RCVTIMEO`: seconds:int[, micros:int] + - `SOL_SOCKET` + `SO_SNDTIMEO`: seconds:int[, micros:int] + - `SOL_TCP` + `TCP_NODELAY`: bool + - `SOL_TCP` + `TCP_CORK`: bool + - `SOL_TCP` + `TCP_QUICKACK`: bool + - `SOL_TCP` + `TCP_FASTOPEN_CONNECT`: bool + - `SOL_TCP` + `TCP_DEFER_ACCEPT`: bool + - `SOL_TCP` + `TCP_KEEPIDLE`: seconds:int + - `SOL_TCP` + `TCP_KEEPINTVL`: seconds:int + - `SOL_TCP` + `TCP_FASTOPEN`: int + - `SOL_TCP` + `TCP_KEEPCNT`: int + - `SOL_TCP` + `TCP_MAXSEG`: int + - `SOL_TCP` + `TCP_SYNCNT`: int + - `SOL_TCP` + `TCP_NOTSENT_LOWAT`: int + - `SOL_TCP` + `TCP_WINDOW_CLAMP`: int + - `SOL_IP` + `IP_TOS`: int + - `SOL_IP` + `IP_MTU`: int + - `SOL_IP` + `IP_TTL`: int + - `SOL_IP` + `IP_HDRINCL`: bool + + Returns `EINVAL` if settings other than the above are used. + + Returns `ENOSYS` if setting isn't supported by the host o/s. + + NOTE: The API for this function diverges from the the norm. `errno` + needs to come first in the results, because otherwise we + wouldn't know the arity of items to push before it. It's + because Cosmopolitan Libc polyfills the magic numbers above as + zero if the host operating system doesn't support them. If + there's no error, then `errno` will be set to nil. + unix.poll({fd:int=events:int, ...}[, timeoutms:int]) → {fd:int=revents:int, ...}[, errno:int] @@ -1728,7 +2041,7 @@ UNIX MODULE Returns hostname of system. - unix.listen(fd:int[, backlog]) → rc:int[, errno:int] + unix.listen(fd:int[, backlog]) → errno:int Begins listening for incoming connections on a socket. @@ -1752,27 +2065,31 @@ UNIX MODULE Retrieves the remote address of a socket. - unix.recv(fd:int[, bufsiz[, flags]]) → data, errno:int + unix.recv(fd:int[, bufsiz:int[, flags:int]]) → data:str[, errno:int] `flags` can have MSG_{WAITALL,DONTROUTE,PEEK,OOB}, etc. - unix.recvfrom(fd:int[, bufsiz[, flags]]) → data, ip, port, errno:int + unix.recvfrom(fd:int[, bufsiz:int[, flags:int]]) + → data:str, ip:uint32, port:uint16, errno:int `flags` can have MSG_{WAITALL,DONTROUTE,PEEK,OOB}, etc. - unix.send(fd:int, data[, flags]) → sent, errno:int + unix.send(fd:int, data:str[, flags:int]) → sent:int[, errno:int] This is the same as `write` except it has a `flags` argument - that's intended for sockets. `flags` can have `MSG_OOB`, - `MSG_DONTROUTE`, or `MSG_NOSIGNAL`. + that's intended for sockets. - unix.sendto(fd:int, data, ip, port[, flags]) → sent, errno:int + `flags` can have `MSG_OOB`, `MSG_DONTROUTE`, or `MSG_NOSIGNAL`. + + unix.sendto(fd:int, data:str, ip:int, port:int[, flags:int]) + → sent:int, errno:int This is useful for sending messages over UDP sockets to specific - addresses. The `flags` parameter can have `MSG_OOB`, - `MSG_DONTROUTE`, or `MSG_NOSIGNAL`. + addresses. - unix.shutdown(fd:int, how:int) → rc:int[, errno:int] + `flags` can have `MSG_OOB`, `MSG_DONTROUTE`, or `MSG_NOSIGNAL`. + + unix.shutdown(fd:int, how:int) → errno:int Partially closes socket. `how` can be `SHUT_RD`, `SHUT_WR`, or `SHUT_RDWR`. @@ -1790,7 +2107,7 @@ UNIX MODULE unix = require "unix" unix.sigaction(unix.SIGUSR1, function(sig) - print(string.format("got %s", unix.strsignal(sig))) + print('got %s' % {unix.strsignal(sig)}) end) unix.sigprocmask(unix.SIG_SETMASK, -1) unix.raise(unix.SIGUSR1) @@ -1798,10 +2115,13 @@ UNIX MODULE It's a good idea to not do too much work in a signal handler. - unix.sigsuspend([mask]) → errno + unix.sigsuspend([mask:int]) → errno:int Waits for signal to be delivered. + The signal mask is temporarily replaced with `mask` during this + system call. `mask` specifies which signals should be blocked. + unix.setitimer(which[, intsec, intmicros, valsec, valmicros]) → intsec, intns, valsec, valns, errno:int @@ -1812,7 +2132,7 @@ UNIX MODULE ticks = 0 unix.sigaction(unix.SIGALRM, function(sig) - print(string.format("tick no. %d", ticks)) + print('tick no. %d' % {ticks}) ticks = ticks + 1 end) unix.setitimer(unix.ITIMER_REAL, 0, 400000, 0, 400000) @@ -1827,18 +2147,27 @@ UNIX MODULE unix.strerrno(errno:int) → str - Turns `errno` code into its symbolic name, e.g. `"EINTR"`. + Turns `errno` code into its symbolic name, e.g. `"EINTR"`. If + `errno` isn't known, this function returns nil. + + unix.strerdoc(errno:int) → str + + Turns `errno` code into a descriptive string. If `errno` isn't + known, this function returns nil. unix.strerror(errno:int) → str - Turns `errno` code into a longer string describing the error. + Turns `errno` code into longest string describing the error. This + includes the output of both strerrno() and strerror() as well as the + error number. On Windows it includes FormatMessage() output too. If + `errno` isn't known, this function still returns a string. unix.strsignal(sig:int) → str Turns platform-specific `sig` code into its name, e.g. `strsignal(9)` always returns `"SIGKILL"`. - unix.setrlimit(resource:int, soft:int[, hard:int]) → rc:int[, errno:int] + unix.setrlimit(resource:int, soft:int[, hard:int]) → errno:int Changes resource limit. @@ -1873,24 +2202,30 @@ UNIX MODULE Returns information about resource limit. - unix.stat(x) → UnixStat*, errno:int + unix.stat(x) → UnixStat*[, errno:int] Gets information about file or directory. `x` may be a file or directory path string, or it may be a file descriptor int that was made by open(). - unix.opendir(path:str) → UnixDir*, errno:int + unix.opendir(path:str) → UnixDir*[, errno:int] Opens directory for listing its contents. - unix.opendir(fd:int) → UnixDir*, errno:int + unix.fdopendir(fd:int) → UnixDir*[, errno:int] - Opens directory for listing its contents, using a file - descriptor from `open(path, O_RDONLY|O_DIRECTORY)`. + Opens directory for listing its contents, via an fd. - UnixDir* Object + `fd` should be created by `open(path, O_RDONLY|O_DIRECTORY)`. The + returned UnixDir* ownership takes ownership of the file descriptor + and will close it automatically when garbage collected. - UnixDir:close() → rc:int[, errno:int] + UNIX DIR OBJECT + + UnixDir* objects are created by opendir() or fdopendir(). The + following methods are available: + + UnixDir:close() → errno:int may be called multiple times called by the garbage collector too @@ -1905,8 +2240,11 @@ UNIX MODULE UnixDir:fd() → fd:int[, errno:int] - EOPNOTSUPP if using /zip/ - EOPNOTSUPP if IsWindows() + Returns file descriptor of open directory object. + + Returns `EOPNOTSUPP` if using a `/zip/...` path. + + Returns `EOPNOTSUPP` if using Windows NT. UnixDir:tell() → offset:int @@ -1916,7 +2254,10 @@ UNIX MODULE Resets stream back to beginning. - UnixStat* object. + UNIX STAT OBJECT + + UnixStat* objects are created by stat() or fstat(). The following + methods are available: UnixStat:size() → bytes:int @@ -1974,313 +2315,317 @@ UNIX MODULE Block size is usually 4096 for file system files. UnixStat:dev() → int + + ID of device containing file. + UnixStat:ino() → int + + Inode number. + UnixStat:rdev() → int - Here are your error numbers: - - - `EINVAL`: Invalid argument. Raised by [pretty much everything]. - - - `ENOSYS`: System call not available on this platform. On Windows - this is raised by chroot(), setuid(), setgid(). - - - `ENOENT`: no such file or directory. Raised by access(), - alloc_hugepages(), bind(), chdir(), chmod(), chown(), chroot(), - clock_getres(), execve(), opendir(), inotify_add_watch(), kcmp(), - link(), mkdir(), mknod(), msgget(), open(), readlink(), rename(), - rmdir(), semget(), shmget(), stat(), swapon(), symlink(), - truncate(), unlink(), utime(), utimensat(). - - - `ESRCH`: No such process. Raised by getpriority(), getrlimit(), - getsid(), ioprio_set(), kill(), setpgid(), tkill(), utimensat(), - - - `EINTR`: The greatest of all errnos; crucial for building real - time reliable software. Raised by accept(), clock_nanosleep(), - close(), connect(), dup(), fcntl(), flock(), getrandom(), - nanosleep(), open(), pause(), poll(), ptrace(), read(), recv(), - select(), send(), sigsuspend(), sigwaitinfo(), truncate(), - wait(), write() - - - `EIO`: Raised by access() acct() chdir() chmod() chown() chroot() - close() copy_file_range() execve() fallocate() fsync() ioperm() - link() madvise() mbind() pciconfig_read() ptrace() read() - readlink() sendfile() statfs() symlink() sync_file_range() - truncate() unlink() write() - - - `ENXIO`: No such device or address. Raised by lseek(), open(), - prctl() - - - `E2BIG`: Argument list too long. Raised by execve(), msgop(), - sched_setattr(), semop() - - - `ENOEXEC`: exec format error. Raised by execve(), kexec_load(), - uselib() - - - `EBADF`: bad file descriptor; cf. EBADFD. Raised by accept(), - access(), bind(), chdir(), chmod(), chown(), close(), connect(), - copy_file_range(), dup(), fcntl(), flock(), fsync(), futimesat(), - opendir(), getpeername(), getsockname(), getsockopt(), - inotify_add_watch(), inotify_rm_watch(), ioctl(), kcmp(), - kexec_load(), link(), listen(), llseek(), lseek(), mkdir(), - mknod(), mmap(), open(), prctl(), read(), readahead(), - readlink(), recv(), rename(), select(), send(), shutdown(), - splice(), stat(), symlink(), sync(), sync_file_range(), - timerfd_create(), truncate(), unlink(), utimensat(), write(), - - - `ECHILD`: no child process. Raised by wait(), waitpid(), - waitid(), wait3(), wait4() - - - `EAGAIN`: resource temporarily unavailable (e.g. SO_RCVTIMEO - expired, too many processes, too much memory locked, read or - write with O_NONBLOCK needs polling, etc.). Raised by accept(), - connect(), eventfd(), fcntl(), fork(), getrandom(), mincore(), - mlock(), mmap(), mremap(), msgop(), poll(), read(), select(), - send(), setresuid(), setreuid(), setuid(), sigwaitinfo(), - splice(), tee(), timer_create(), timerfd_create(), tkill(), - write(), - - - `ENOMEM`: We require more vespene gas. Raised by access(), - bind(), chdir(), chmod(), chown(), chroot(), clone(), - copy_file_range(), create_module(), eventfd(), execve(), - fanotify_init(), fork(), getgroups(), getrlimit(), - inotify_add_watch(), inotify_init(), ioperm(), kexec_load(), - link(), mbind(), memfd_create(), mincore(), mkdir(), mknod(), - mlock(), mmap(), mprotect(), mremap(), msgget(), msgop(), - msync(), open(), poll(), readlink(), recv(), rename(), rmdir(), - select(), semget(), send(), shmget(), sigaltstack(), splice(), - stat(), subpage_prot(), swapon(), symlink(), sync_file_range(), - tee(), timer_create(), timerfd_create(), unlink(). - - - `EACCES`: Permission denied. Raised by access(), bind(), bpf(), - chdir(), chmod(), chown(), chroot(), clock_getres(), connect(), - execve(), fcntl(), getpriority(), inotify_add_watch(), link(), - mkdir(), mknod(), mmap(), mprotect(), msgctl(), msgget(), - msgop(), open(), prctl(), ptrace(), readlink(), rename(), - rmdir(), semget(), send(), setpgid(), shmget(), socket(), stat(), - symlink(), truncate(), unlink(), uselib(), utime(), utimensat(), - - - `EPERM`: Operation not permitted. Raised by accept(), chmod(), - chown(), chroot(), copy_file_range(), execve(), fallocate(), - fanotify_init(), fcntl(), futex(), get_robust_list(), - getdomainname(), getgroups(), gethostname(), getpriority(), - getrlimit(), getsid(), gettimeofday(), idle(), init_module(), - io_submit(), ioctl_console(), ioctl_ficlonerange(), - ioctl_fideduperange(), ioctl_ns(), ioctl_tty(), ioperm(), iopl(), - ioprio_set(), kcmp(), kexec_load(), keyctl(), kill(), link(), - lookup_dcookie(), madvise(), mbind(), membarrier(), - migrate_pages(), mkdir(), mknod(), mlock(), mmap(), mount(), - move_pages(), msgctl(), nice(), open(), open_by_handle_at(), - pciconfig_read(), perf_event_open(), pidfd_getfd(), - pidfd_send_signal(), pivot_root(), prctl(), process_vm_readv(), - ptrace(), quotactl(), reboot(), rename(), request_key(), rmdir(), - rt_sigqueueinfo(), sched_setaffinity(), sched_setattr(), - sched_setparam(), sched_setscheduler(), semctl(), seteuid(), - setfsgid(), setfsuid(), setgid(), setns(), setpgid(), - setresuid(), setreuid(), setsid(), setuid(), setup(), setxattr(), - shmctl(), shmget(), sigaltstack(), spu_create(), stime(), - swapon(), symlink(), syslog(), truncate(), unlink(), utime(), - utimensat(), write() - - - `ENOTBLK`: Block device required. Raised by umount(). - - - `EBUSY`: Device or resource busy. Raised by bdflush(), dup(), - fcntl(), msync(), prctl(), ptrace(), rename(), rmdir(). - - - `EEXIST`: File exists. Raised by bpf(), create_module(), - inotify_add_watch(), link(), mkdir(), mknod(), mmap(), msgget(), - open(), rename(), rmdir(), semget(), shmget(), symlink() - - - `EXDEV`: Improper link. Raised by copy_file_range(), link(), - rename() - - - `ENODEV`: No such device. Raised by arch_prctl(), eventfd(), - mmap(), open(), prctl(), timerfd_create() - - - `ENOTDIR`: Not a directory. This means that a directory component - in a supplied path *existed* but wasn't a directory. For example, - if you try to `open("foo/bar")` and `foo` is a regular file, then - `ENOTDIR` will be returned. Raised by open(), access(), chdir(), - chroot(), execve(), link(), mkdir(), mknod(), opendir(), - readlink(), rename(), rmdir(), stat(), symlink(), truncate(), - unlink(), utimensat(), bind(), chmod(), chown(), fcntl(), - futimesat(), inotify_add_watch(). - - - `EISDIR`: Is a a directory. Raised by copy_file_range(), - execve(), open(), read(), rename(), truncate(), unlink(). - - - `ENFILE`: Too many open files in system. Raised by accept(), - eventfd(), execve(), inotify_init(), memfd_create(), mmap(), - open(), pipe(), shmget(), socket(), socketpair(), swapon(), - timerfd_create(), uselib(), userfaultfd(). - - - `EMFILE`: Too many open files. Raised by accept(), dup(), - eventfd(), execve(), fanotify_init(), fcntl(), inotify_init(), - memfd_create(), open(), pipe(), socket(), socketpair(), - timerfd_create(). - - - `ENOTTY`: Inappropriate i/o control operation. Raised by ioctl(). + Device ID (if special file) + + UNIX ERRORS + + - `EINVAL`: Invalid argument. Raised by [pretty much everything]. + + - `ENOSYS`: System call not available on this platform. On Windows + this is raised by chroot(), setuid(), setgid(), getsid(), setsid(). + + - `ENOENT`: no such file or directory. Raised by access(), + alloc_hugepages(), bind(), chdir(), chmod(), chown(), chroot(), + clock_getres(), execve(), opendir(), inotify_add_watch(), kcmp(), + link(), mkdir(), mknod(), msgget(), open(), readlink(), rename(), + rmdir(), semget(), shmget(), stat(), swapon(), symlink(), + truncate(), unlink(), utime(), utimensat(). + + - `ENOTDIR`: Not a directory. This means that a directory component in + a supplied path *existed* but wasn't a directory. For example, if + you try to `open("foo/bar")` and `foo` is a regular file, then + `ENOTDIR` will be returned. Raised by open(), access(), chdir(), + chroot(), execve(), link(), mkdir(), mknod(), opendir(), readlink(), + rename(), rmdir(), stat(), symlink(), truncate(), unlink(), + utimensat(), bind(), chmod(), chown(), fcntl(), futimesat(), + inotify_add_watch(). + + - `EINTR`: The greatest of all errnos; crucial for building real time + reliable software. Raised by accept(), clock_nanosleep(), close(), + connect(), dup(), fcntl(), flock(), getrandom(), nanosleep(), + open(), pause(), poll(), ptrace(), read(), recv(), select(), send(), + sigsuspend(), sigwaitinfo(), truncate(), wait(), write() + + - `EIO`: Raised by access() acct() chdir() chmod() chown() chroot() + close() copy_file_range() execve() fallocate() fsync() ioperm() + link() madvise() mbind() pciconfig_read() ptrace() read() readlink() + sendfile() statfs() symlink() sync_file_range() truncate() unlink() + write() + + - `ENXIO`: No such device or address. Raised by lseek(), open(), + prctl() + + - `E2BIG`: Argument list too long. Raised by execve(), msgop(), + sched_setattr(), semop() + + - `ENOEXEC`: exec format error. Raised by execve(), kexec_load(), + uselib() + + - `ECHILD`: no child process. Raised by wait(), waitpid(), waitid(), + wait3(), wait4() + + - `ESRCH`: No such process. Raised by getpriority(), getrlimit(), + getsid(), ioprio_set(), kill(), setpgid(), tkill(), utimensat(), + + - `EBADF`: bad file descriptor; cf. EBADFD. Raised by accept(), + access(), bind(), chdir(), chmod(), chown(), close(), connect(), + copy_file_range(), dup(), fcntl(), flock(), fsync(), futimesat(), + opendir(), getpeername(), getsockname(), getsockopt(), + inotify_add_watch(), inotify_rm_watch(), ioctl(), kcmp(), + kexec_load(), link(), listen(), llseek(), lseek(), mkdir(), mknod(), + mmap(), open(), prctl(), read(), readahead(), readlink(), recv(), + rename(), select(), send(), shutdown(), splice(), stat(), symlink(), + sync(), sync_file_range(), timerfd_create(), truncate(), unlink(), + utimensat(), write(), + + - `EAGAIN`: resource temporarily unavailable (e.g. SO_RCVTIMEO + expired, too many processes, too much memory locked, read or write + with O_NONBLOCK needs polling, etc.). Raised by accept(), connect(), + eventfd(), fcntl(), fork(), getrandom(), mincore(), mlock(), mmap(), + mremap(), msgop(), poll(), read(), select(), send(), setresuid(), + setreuid(), setuid(), sigwaitinfo(), splice(), tee(), + timer_create(), timerfd_create(), tkill(), write(), + + - `EPIPE`: Broken pipe. Returned by write(), send(). This happens when + you try to write data to a subprocess via a pipe() but the reader + end has already closed, possibly because the process died. Normally + i/o routines only return this if `SIGPIPE` doesn't kill the process. + Unlike default UNIX programs, redbean currently ignores `SIGPIPE` by + default, so this error code is a distinct possibility when pipes or + sockets are being used. + + - `ENAMETOOLONG`: Filename too long. Cosmopolitan Libc currently + defines `PATH_MAX` as 512 characters. On UNIX, that limit should + only apply to system call wrappers like realpath(). On Windows NT + it's observed by all system calls that accept a pathname. Raised by + access(), bind(), chdir(), chmod(), chown(), chroot(), execve(), + gethostname(), inotify_add_watch(), link(), mkdir(), mknod(), + open(), readlink(), rename(), rmdir(), stat(), symlink(), + truncate(), u unlink(), utimensat() + + - `EACCES`: Permission denied. Raised by access(), bind(), bpf(), + chdir(), chmod(), chown(), chroot(), clock_getres(), connect(), + execve(), fcntl(), getpriority(), inotify_add_watch(), link(), + mkdir(), mknod(), mmap(), mprotect(), msgctl(), msgget(), msgop(), + open(), prctl(), ptrace(), readlink(), rename(), rmdir(), semget(), + send(), setpgid(), shmget(), socket(), stat(), symlink(), + truncate(), unlink(), uselib(), utime(), utimensat(), + + - `ENOMEM`: We require more vespene gas. Raised by access(), bind(), + chdir(), chmod(), chown(), chroot(), clone(), copy_file_range(), + create_module(), eventfd(), execve(), fanotify_init(), fork(), + getgroups(), getrlimit(), inotify_add_watch(), inotify_init(), + ioperm(), kexec_load(), link(), mbind(), memfd_create(), mincore(), + mkdir(), mknod(), mlock(), mmap(), mprotect(), mremap(), msgget(), + msgop(), msync(), open(), poll(), readlink(), recv(), rename(), + rmdir(), select(), semget(), send(), shmget(), sigaltstack(), + splice(), stat(), subpage_prot(), swapon(), symlink(), + sync_file_range(), tee(), timer_create(), timerfd_create(), + unlink(). + + - `EPERM`: Operation not permitted. Raised by accept(), chmod(), + chown(), chroot(), copy_file_range(), execve(), fallocate(), + fanotify_init(), fcntl(), futex(), get_robust_list(), + getdomainname(), getgroups(), gethostname(), getpriority(), + getrlimit(), getsid(), gettimeofday(), idle(), init_module(), + io_submit(), ioctl_console(), ioctl_ficlonerange(), + ioctl_fideduperange(), ioctl_ns(), ioctl_tty(), ioperm(), iopl(), + ioprio_set(), kcmp(), kexec_load(), keyctl(), kill(), link(), + lookup_dcookie(), madvise(), mbind(), membarrier(), migrate_pages(), + mkdir(), mknod(), mlock(), mmap(), mount(), move_pages(), msgctl(), + nice(), open(), open_by_handle_at(), pciconfig_read(), + perf_event_open(), pidfd_getfd(), pidfd_send_signal(), pivot_root(), + prctl(), process_vm_readv(), ptrace(), quotactl(), reboot(), + rename(), request_key(), rmdir(), rt_sigqueueinfo(), + sched_setaffinity(), sched_setattr(), sched_setparam(), + sched_setscheduler(), semctl(), seteuid(), setfsgid(), setfsuid(), + setgid(), setns(), setpgid(), setresuid(), setreuid(), setsid(), + setuid(), setup(), setxattr(), shmctl(), shmget(), sigaltstack(), + spu_create(), stime(), swapon(), symlink(), syslog(), truncate(), + unlink(), utime(), utimensat(), write() + + - `ENOTBLK`: Block device required. Raised by umount(). + + - `EBUSY`: Device or resource busy. Raised by bdflush(), dup(), + fcntl(), msync(), prctl(), ptrace(), rename(), rmdir(). + + - `EEXIST`: File exists. Raised by bpf(), create_module(), + inotify_add_watch(), link(), mkdir(), mknod(), mmap(), msgget(), + open(), rename(), rmdir(), semget(), shmget(), symlink() + + - `EXDEV`: Improper link. Raised by copy_file_range(), link(), + rename() + + - `ENODEV`: No such device. Raised by arch_prctl(), eventfd(), mmap(), + open(), prctl(), timerfd_create() - - `ETXTBSY`: Won't open executable that's executing in write mode. - Raised by access(), copy_file_range(), execve(), mmap(), open(), - truncate(). + - `EISDIR`: Is a a directory. Raised by copy_file_range(), execve(), + open(), read(), rename(), truncate(), unlink(). - - `EFBIG`: File too large. Raised by copy_file_range(), open(), - truncate(), write(). + - `ENFILE`: Too many open files in system. Raised by accept(), + eventfd(), execve(), inotify_init(), memfd_create(), mmap(), open(), + pipe(), shmget(), socket(), socketpair(), swapon(), + timerfd_create(), uselib(), userfaultfd(). - - `ENOSPC`: No space left on device. Raised by copy_file_range(), - fsync(), inotify_add_watch(), link(), mkdir(), mknod(), msgget(), - open(), rename(), semget(), shmget(), symlink(), - sync_file_range(), write(). + - `EMFILE`: Too many open files. Raised by accept(), dup(), eventfd(), + execve(), fanotify_init(), fcntl(), inotify_init(), memfd_create(), + open(), pipe(), socket(), socketpair(), timerfd_create(). - - `EDQUOT`: Disk quota exceeded. Raised by link(), mkdir(), - mknod(), open(), rename(), symlink(), write() + - `ENOTTY`: Inappropriate i/o control operation. Raised by ioctl(). - - `ESPIPE`: Invalid seek. Raised by lseek(), splice(), - sync_file_range(). + - `ETXTBSY`: Won't open executable that's executing in write mode. + Raised by access(), copy_file_range(), execve(), mmap(), open(), + truncate(). - - `EROFS`: Read-only filesystem. Raised by access(), bind(), - chmod(), chown(), link(), mkdir(), mknod(), open(), rename(), - rmdir(), symlink(), truncate(), unlink(), utime(), utimensat() + - `EFBIG`: File too large. Raised by copy_file_range(), open(), + truncate(), write(). - - `EMLINK`: Too many links; raised by link(), mkdir(), rename() + - `ENOSPC`: No space left on device. Raised by copy_file_range(), + fsync(), inotify_add_watch(), link(), mkdir(), mknod(), msgget(), + open(), rename(), semget(), shmget(), symlink(), sync_file_range(), + write(). - - `EPIPE`: Broken pipe. Raised by send(), write(). + - `EDQUOT`: Disk quota exceeded. Raised by link(), mkdir(), mknod(), + open(), rename(), symlink(), write() - - `ERANGE`: Result too large. Raised by prctl(), semop(). + - `ESPIPE`: Invalid seek. Raised by lseek(), splice(), + sync_file_range(). - - `EDEADLK`: Resource deadlock avoided. Raised by fcntl(). + - `EROFS`: Read-only filesystem. Raised by access(), bind(), chmod(), + chown(), link(), mkdir(), mknod(), open(), rename(), rmdir(), + symlink(), truncate(), unlink(), utime(), utimensat() - - `ENAMETOOLONG`: Filename too long. Raised by access(), bind(), - chdir(), chmod(), chown(), chroot(), execve(), gethostname(), - inotify_add_watch(), link(), mkdir(), mknod(), open(), - readlink(), rename(), rmdir(), stat(), symlink(), truncate(), u - unlink(), utimensat() + - `EMLINK`: Too many links; raised by link(), mkdir(), rename() - - `ENOLCK`: No locks available. Raised by fcntl(), flock(). + - `ERANGE`: Result too large. Raised by prctl(), semop(). - - `ENOTEMPTY`: Directory not empty. Raised by rmdir(). + - `EDEADLK`: Resource deadlock avoided. Raised by fcntl(). - - `ELOOP`: Too many levels of symbolic links. Raised by access(), - bind(), chdir(), chmod(), chown(), chroot(), execve(), link(), - mkdir(), mknod(), open(), readlink(), rename(), rmdir(), stat(), - symlink(), truncate(), unlink(), utimensat(). + - `ENOLCK`: No locks available. Raised by fcntl(), flock(). - - `ENOMSG`: Raised by msgop(). + - `ENOTEMPTY`: Directory not empty. Raised by rmdir(). - - `EIDRM`: Identifier removed. Raised by msgctl(), msgget(), - msgop(), shmget(). + - `ELOOP`: Too many levels of symbolic links. Raised by access(), + bind(), chdir(), chmod(), chown(), chroot(), execve(), link(), + mkdir(), mknod(), open(), readlink(), rename(), rmdir(), stat(), + symlink(), truncate(), unlink(), utimensat(). - - `ETIME`: Timer expired; timer expired. Raised by connect(). + - `ENOMSG`: Raised by msgop(). - - `EPROTO`: Raised by accept(), connect(), socket(), socketpair(). + - `EIDRM`: Identifier removed. Raised by msgctl(), msgget(), msgop(), + shmget(). - - `EOVERFLOW`: Raised by copy_file_range(), fanotify_init(), - lseek(), mmap(), open(), stat(), statfs() + - `ETIME`: Timer expired; timer expired. Raised by connect(). - - `ENOTSOCK`: Not a socket. Raised by accept(), bind(), connect(), - getpeername(), getsockname(), getsockopt(), listen(), recv(), - send(), shutdown(). + - `EPROTO`: Raised by accept(), connect(), socket(), socketpair(). - - `EDESTADDRREQ`: Destination address required. Raised by send(), - write(). + - `EOVERFLOW`: Raised by copy_file_range(), fanotify_init(), lseek(), + mmap(), open(), stat(), statfs() - - `EMSGSIZE`: Message too long. Raised by send(). + - `ENOTSOCK`: Not a socket. Raised by accept(), bind(), connect(), + getpeername(), getsockname(), getsockopt(), listen(), recv(), + send(), shutdown(). - - `EPROTOTYPE`: Protocol wrong type for socket. Raised by - connect(). + - `EDESTADDRREQ`: Destination address required. Raised by send(), + write(). - - `ENOPROTOOPT`: Protocol not available. Raised by getsockopt(), - accept(). + - `EMSGSIZE`: Message too long. Raised by send(). - - `EPROTONOSUPPORT`: Protocol not supported. Raised by socket(), - socketpair(). + - `EPROTOTYPE`: Protocol wrong type for socket. Raised by connect(). - - `ESOCKTNOSUPPORT`: Socket type not supported. + - `ENOPROTOOPT`: Protocol not available. Raised by getsockopt(), + accept(). - - `ENOTSUP`: Operation not supported. Raised by chmod(), - clock_getres(), clock_nanosleep(), timer_create() + - `EPROTONOSUPPORT`: Protocol not supported. Raised by socket(), + socketpair(). - - `EOPNOTSUPP`: Socket operation not supported. Raised by accept(), - listen(), mmap(), prctl(), readv(), send(), socketpair(), + - `ESOCKTNOSUPPORT`: Socket type not supported. - - `EPFNOSUPPORT`: protocol family not supported + - `ENOTSUP`: Operation not supported. Raised by chmod(), + clock_getres(), clock_nanosleep(), timer_create() - - `EAFNOSUPPORT`: address family not supported. Raised by - connect(), socket(), socketpair() + - `EOPNOTSUPP`: Socket operation not supported. Raised by accept(), + listen(), mmap(), prctl(), readv(), send(), socketpair(), - - `EADDRINUSE`: address already in use. Raised by bind(), - connect(), listen() + - `EPFNOSUPPORT`: protocol family not supported - - `EADDRNOTAVAIL`: address not available. Raised by bind(), - connect(). + - `EAFNOSUPPORT`: address family not supported. Raised by connect(), + socket(), socketpair() - - `ENETDOWN`: network is down; ; WSAENETDOWN. Raised by accept() + - `EADDRINUSE`: address already in use. Raised by bind(), connect(), + listen() - - `ENETUNREACH`: host is unreachable; ; WSAENETUNREACH. Raised by - accept(), connect() + - `EADDRNOTAVAIL`: address not available. Raised by bind(), connect(). - - `ENETRESET`: connection reset by network + - `ENETDOWN`: network is down; ; WSAENETDOWN. Raised by accept() - - `ECONNABORTED`: connection reset before accept. Raised by - accept() + - `ENETUNREACH`: host is unreachable; ; WSAENETUNREACH. Raised by + accept(), connect() - - `ECONNRESET`: connection reset by client. Raised by send(), + - `ENETRESET`: connection reset by network - - `ENOBUFS`: no buffer space available; raised by getpeername(), - getsockname(), send(), + - `ECONNABORTED`: connection reset before accept. Raised by accept() - - `EISCONN`: socket is connected. Raised by connect(), send(). + - `ECONNRESET`: connection reset by client. Raised by send(), - - `ENOTCONN`: socket is not connected. Raised by getpeername(), - recv(), send(), shutdown(), + - `ENOBUFS`: no buffer space available; raised by getpeername(), + getsockname(), send(), - - `ESHUTDOWN`: cannot send after transport endpoint shutdown; note - that shutdown write is an `EPIPE` + - `EISCONN`: socket is connected. Raised by connect(), send(). - - `ETOOMANYREFS`: too many references: cannot splice. Raised by - sendmsg(), + - `ENOTCONN`: socket is not connected. Raised by getpeername(), + recv(), send(), shutdown(), - - `ETIMEDOUT`: connection timed out; ; WSAETIMEDOUT; raised by - connect(), + - `ESHUTDOWN`: cannot send after transport endpoint shutdown; note + that shutdown write is an `EPIPE` - - `ECONNREFUSED`: system-imposed limit on the number of threads was - encountered.; WSAECONNREFUSED. Raised by connect(), listen(), - recv() + - `ETOOMANYREFS`: too many references: cannot splice. Raised by + sendmsg(), - - `EHOSTDOWN`: Host is down. Raised by accept() + - `ETIMEDOUT`: connection timed out; ; WSAETIMEDOUT; raised by + connect(), - - `EHOSTUNREACH`: Host is unreachable. Raised by accept() + - `ECONNREFUSED`: system-imposed limit on the number of threads was + encountered.; WSAECONNREFUSED. Raised by connect(), listen(), recv() - - `EALREADY`: Connection already in progress. Raised by connect(), - send() + - `EHOSTDOWN`: Host is down. Raised by accept() - - `ENODATA`: No message is available in xsi stream or named pipe is - being closed; no data available; barely in posix; returned by - ioctl; very close in spirit to EPIPE? + - `EHOSTUNREACH`: Host is unreachable. Raised by accept() + - `EALREADY`: Connection already in progress. Raised by connect(), + send() -CONSTANTS + - `ENODATA`: No message is available in xsi stream or named pipe is + being closed; no data available; barely in posix; returned by ioctl; + very close in spirit to EPIPE? - kLogDebug - Integer for debug logging level. See Log. + +LUA ENHANCEMENTS - kLogVerbose - Integer for verbose logging level, which is less than kLogDebug. + We've made some enhancements to the Lua language that should make it + more comfortable for C/C++ and Python developers. Some of these - kLogInfo - Integer for info logging level, which is less than kLogVerbose. + - redbean supports a printf modulus operator, like Python. For + example, you can say `"hello %s" % {"world"}` instead of + `string.format("hello %s", "world")`. - kLogWarn - Integer for warn logging level, which is less than kLogVerbose. + - redbean supports octal (base 8) integer literals. For example + `0644 == 420` is the case in redbean, whereas in upstream Lua + `0644 == 644` would be the case. - kLogError - Integer for error logging level, which is less than kLogWarn. - - kLogFatal - Integer for fatal logging level, which is less than kLogError. - Logging anything at this level will result in a backtrace and - process exit. + - redbean supports the GNU syntax for the ASCII ESC character in + string literals. For example, `"\e"` is the same as `"\x1b"`. + SEE ALSO https://justine.lol/redbean/index.html diff --git a/tool/net/lfuncs.c b/tool/net/lfuncs.c new file mode 100644 index 000000000..a58760bd5 --- /dev/null +++ b/tool/net/lfuncs.c @@ -0,0 +1,562 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "dsp/scale/cdecimate2xuint8x8.h" +#include "libc/bits/popcnt.h" +#include "libc/log/check.h" +#include "libc/log/log.h" +#include "libc/macros.internal.h" +#include "libc/mem/mem.h" +#include "libc/nexgen32e/bsf.h" +#include "libc/nexgen32e/bsr.h" +#include "libc/nexgen32e/crc32.h" +#include "libc/nexgen32e/rdtsc.h" +#include "libc/nexgen32e/rdtscp.h" +#include "libc/rand/rand.h" +#include "libc/runtime/gc.internal.h" +#include "libc/sock/sock.h" +#include "libc/sysv/consts/af.h" +#include "libc/time/time.h" +#include "libc/x/x.h" +#include "net/http/escape.h" +#include "net/http/http.h" +#include "net/http/ip.h" +#include "net/http/url.h" +#include "third_party/lua/cosmo.h" +#include "third_party/lua/lauxlib.h" +#include "third_party/lua/lua.h" +#include "third_party/mbedtls/md.h" +#include "third_party/mbedtls/md5.h" +#include "third_party/mbedtls/platform.h" +#include "third_party/mbedtls/sha1.h" +#include "third_party/mbedtls/sha256.h" +#include "third_party/mbedtls/sha512.h" +#include "tool/net/lfuncs.h" + +int LuaGetTime(lua_State *L) { + lua_pushnumber(L, nowl()); + return 1; +} + +int LuaSleep(lua_State *L) { + usleep(1e6 * luaL_checknumber(L, 1)); + return 0; +} + +int LuaRdtsc(lua_State *L) { + lua_pushinteger(L, rdtsc()); + return 1; +} + +int LuaGetCpuNode(lua_State *L) { + lua_pushinteger(L, TSC_AUX_NODE(rdpid())); + return 1; +} + +int LuaGetCpuCore(lua_State *L) { + lua_pushinteger(L, TSC_AUX_CORE(rdpid())); + return 1; +} + +int LuaGetLogLevel(lua_State *L) { + lua_pushinteger(L, __log_level); + return 1; +} + +int LuaSetLogLevel(lua_State *L) { + __log_level = luaL_checkinteger(L, 1); + return 0; +} + +static int LuaRand(lua_State *L, uint64_t impl(void)) { + lua_pushinteger(L, impl()); + return 1; +} + +int LuaLemur64(lua_State *L) { + return LuaRand(L, lemur64); +} + +int LuaRand64(lua_State *L) { + return LuaRand(L, rand64); +} + +int LuaRdrand(lua_State *L) { + return LuaRand(L, rdrand); +} + +int LuaRdseed(lua_State *L) { + return LuaRand(L, rdseed); +} + +int LuaDecimate(lua_State *L) { + size_t n, m; + const char *s; + unsigned char *p; + s = luaL_checklstring(L, 1, &n); + m = ROUNDUP(n, 16); + p = xmalloc(m); + bzero(p + n, m - n); + cDecimate2xUint8x8(m, p, (signed char[8]){-1, -3, 3, 17, 17, 3, -3, -1}); + lua_pushlstring(L, (char *)p, (n + 1) >> 1); + free(p); + return 1; +} + +int LuaMeasureEntropy(lua_State *L) { + size_t n; + const char *s; + s = luaL_checklstring(L, 1, &n); + lua_pushnumber(L, MeasureEntropy(s, n)); + return 1; +} + +int LuaGetHostOs(lua_State *L) { + const char *s = NULL; + if (IsLinux()) { + s = "LINUX"; + } else if (IsMetal()) { + s = "METAL"; + } else if (IsWindows()) { + s = "WINDOWS"; + } else if (IsXnu()) { + s = "XNU"; + } else if (IsOpenbsd()) { + s = "OPENBSD"; + } else if (IsFreebsd()) { + s = "FREEBSD"; + } else if (IsNetbsd()) { + s = "NETBSD"; + } + if (s) { + lua_pushstring(L, s); + } else { + lua_pushnil(L); + } + return 1; +} + +int LuaFormatIp(lua_State *L) { + char b[16]; + uint32_t ip; + ip = htonl(luaL_checkinteger(L, 1)); + inet_ntop(AF_INET, &ip, b, sizeof(b)); + lua_pushstring(L, b); + return 1; +} + +int LuaParseIp(lua_State *L) { + size_t n; + const char *s; + s = luaL_checklstring(L, 1, &n); + lua_pushinteger(L, ParseIp(s, n)); + return 1; +} + +static int LuaIsIp(lua_State *L, bool IsIp(uint32_t)) { + lua_pushboolean(L, IsIp(luaL_checkinteger(L, 1))); + return 1; +} + +int LuaIsPublicIp(lua_State *L) { + return LuaIsIp(L, IsPublicIp); +} + +int LuaIsPrivateIp(lua_State *L) { + return LuaIsIp(L, IsPrivateIp); +} + +int LuaIsLoopbackIp(lua_State *L) { + return LuaIsIp(L, IsLoopbackIp); +} + +int LuaCategorizeIp(lua_State *L) { + lua_pushstring(L, GetIpCategoryName(CategorizeIp(luaL_checkinteger(L, 1)))); + return 1; +} + +int LuaFormatHttpDateTime(lua_State *L) { + char buf[30]; + lua_pushstring(L, FormatUnixHttpDateTime(buf, luaL_checkinteger(L, 1))); + return 1; +} + +int LuaParseHttpDateTime(lua_State *L) { + size_t n; + const char *s; + s = luaL_checklstring(L, 1, &n); + lua_pushinteger(L, ParseHttpDateTime(s, n)); + return 1; +} + +int LuaParseParams(lua_State *L) { + void *m; + size_t size; + const char *data; + struct UrlParams h; + data = luaL_checklstring(L, 1, &size); + bzero(&h, sizeof(h)); + m = ParseParams(data, size, &h); + LuaPushUrlParams(L, &h); + free(h.p); + free(m); + return 1; +} + +int LuaParseHost(lua_State *L) { + void *m; + size_t n; + struct Url h; + const char *p; + bzero(&h, sizeof(h)); + p = luaL_checklstring(L, 1, &n); + m = ParseHost(p, n, &h); + lua_newtable(L); + LuaPushUrlView(L, &h.host); + LuaPushUrlView(L, &h.port); + free(m); + return 1; +} + +int LuaPopcnt(lua_State *L) { + lua_pushinteger(L, popcnt(luaL_checkinteger(L, 1))); + return 1; +} + +int LuaBsr(lua_State *L) { + long x; + if ((x = luaL_checkinteger(L, 1))) { + lua_pushinteger(L, bsr(x)); + return 1; + } else { + luaL_argerror(L, 1, "zero"); + unreachable; + } +} + +int LuaBsf(lua_State *L) { + long x; + if ((x = luaL_checkinteger(L, 1))) { + lua_pushinteger(L, bsf(x)); + return 1; + } else { + luaL_argerror(L, 1, "zero"); + unreachable; + } +} + +static int LuaHash(lua_State *L, uint32_t H(uint32_t, const void *, size_t)) { + long i; + size_t n; + const char *p; + i = luaL_checkinteger(L, 1); + p = luaL_checklstring(L, 2, &n); + lua_pushinteger(L, H(i, p, n)); + return 1; +} + +int LuaCrc32(lua_State *L) { + return LuaHash(L, crc32_z); +} + +int LuaCrc32c(lua_State *L) { + return LuaHash(L, crc32c); +} + +int LuaIndentLines(lua_State *L) { + void *p; + size_t n, j; + p = luaL_checklstring(L, 1, &n); + j = luaL_optinteger(L, 2, 1); + if (!(0 <= j && j <= 65535)) { + luaL_argerror(L, 2, "not in range 0..65535"); + unreachable; + } + p = IndentLines(p, n, &n, j); + lua_pushlstring(L, p, n); + free(p); + return 1; +} + +int LuaGetMonospaceWidth(lua_State *L) { + int w; + if (lua_isinteger(L, 1)) { + w = wcwidth(lua_tointeger(L, 1)); + } else if (lua_isstring(L, 1)) { + w = strwidth(luaL_checkstring(L, 1), luaL_optinteger(L, 2, 0) & 7); + } else { + luaL_argerror(L, 1, "not integer or string"); + unreachable; + } + lua_pushinteger(L, w); + return 1; +} + +int LuaSlurp(lua_State *L) { + char *p, *f; + size_t n; + f = luaL_checkstring(L, 1); + if ((p = xslurp(f, &n))) { + lua_pushlstring(L, p, n); + free(p); + return 1; + } else { + lua_pushnil(L); + lua_pushstring(L, gc(xasprintf("Can't slurp file %`'s: %m", f))); + return 2; + } +} + +static int LuaCheckControlFlags(lua_State *L, int idx) { + int f = luaL_checkinteger(L, idx); + if (f & ~(kControlWs | kControlC0 | kControlC1)) { + luaL_argerror(L, idx, "invalid control flags"); + unreachable; + } + return f; +} + +int LuaHasControlCodes(lua_State *L) { + int f; + size_t n; + const char *p; + p = luaL_checklstring(L, 1, &n); + f = LuaCheckControlFlags(L, 2); + lua_pushboolean(L, HasControlCodes(p, n, f) != -1); + return 1; +} + +int LuaEncodeLatin1(lua_State *L) { + int f; + char *p; + size_t n; + p = luaL_checklstring(L, 1, &n); + f = LuaCheckControlFlags(L, 2); + p = EncodeLatin1(p, n, &n, f); + lua_pushlstring(L, p, n); + free(p); + return 1; +} + +int LuaGetRandomBytes(lua_State *L) { + char *p; + size_t n = luaL_optinteger(L, 1, 16); + if (!(n > 0 && n <= 256)) { + luaL_argerror(L, 1, "not in range 1..256"); + unreachable; + } + p = malloc(n); + CHECK_EQ(n, getrandom(p, n, 0)); + lua_pushlstring(L, p, n); + free(p); + return 1; +} + +int LuaGetHttpReason(lua_State *L) { + lua_pushstring(L, GetHttpReason(luaL_checkinteger(L, 1))); + return 1; +} + +int LuaGetCryptoHash(lua_State *L) { + size_t hl, pl, kl; + uint8_t d[64]; + mbedtls_md_context_t ctx; + // get hash name, payload, and key + void *h = luaL_checklstring(L, 1, &hl); + void *p = luaL_checklstring(L, 2, &pl); + void *k = luaL_optlstring(L, 3, "", &kl); + const mbedtls_md_info_t *digest = mbedtls_md_info_from_string(h); + if (!digest) return luaL_argerror(L, 1, "unknown hash type"); + if (kl == 0) { + // no key provided, run generic hash function + if ((digest->f_md)(p, pl, d)) return luaL_error(L, "bad input data"); + } else if (mbedtls_md_hmac(digest, k, kl, p, pl, d)) { + return luaL_error(L, "bad input data"); + } + lua_pushlstring(L, (void *)d, digest->size); + mbedtls_platform_zeroize(d, sizeof(d)); + return 1; +} + +static dontinline int LuaIsValid(lua_State *L, bool V(const char *, size_t)) { + size_t size; + const char *data; + data = luaL_checklstring(L, 1, &size); + lua_pushboolean(L, V(data, size)); + return 1; +} + +int LuaIsValidHttpToken(lua_State *L) { + return LuaIsValid(L, IsValidHttpToken); +} + +int LuaIsAcceptablePath(lua_State *L) { + return LuaIsValid(L, IsAcceptablePath); +} + +int LuaIsReasonablePath(lua_State *L) { + return LuaIsValid(L, IsReasonablePath); +} + +int LuaIsAcceptableHost(lua_State *L) { + return LuaIsValid(L, IsAcceptableHost); +} + +int LuaIsAcceptablePort(lua_State *L) { + return LuaIsValid(L, IsAcceptablePort); +} + +static dontinline int LuaCoderImpl(lua_State *L, + char *C(const char *, size_t, size_t *)) { + void *p; + size_t n; + p = luaL_checklstring(L, 1, &n); + p = C(p, n, &n); + lua_pushlstring(L, p, n); + free(p); + return 1; +} + +static dontinline int LuaCoder(lua_State *L, + char *C(const char *, size_t, size_t *)) { + return LuaCoderImpl(L, C); +} + +int LuaUnderlong(lua_State *L) { + return LuaCoder(L, Underlong); +} + +int LuaEncodeBase64(lua_State *L) { + return LuaCoder(L, EncodeBase64); +} + +int LuaDecodeBase64(lua_State *L) { + return LuaCoder(L, DecodeBase64); +} + +int LuaDecodeLatin1(lua_State *L) { + return LuaCoder(L, DecodeLatin1); +} + +int LuaEscapeHtml(lua_State *L) { + return LuaCoder(L, EscapeHtml); +} + +int LuaEscapeParam(lua_State *L) { + return LuaCoder(L, EscapeParam); +} + +int LuaEscapePath(lua_State *L) { + return LuaCoder(L, EscapePath); +} + +int LuaEscapeHost(lua_State *L) { + return LuaCoder(L, EscapeHost); +} + +int LuaEscapeIp(lua_State *L) { + return LuaCoder(L, EscapeIp); +} + +int LuaEscapeUser(lua_State *L) { + return LuaCoder(L, EscapeUser); +} + +int LuaEscapePass(lua_State *L) { + return LuaCoder(L, EscapePass); +} + +int LuaEscapeSegment(lua_State *L) { + return LuaCoder(L, EscapeSegment); +} + +int LuaEscapeFragment(lua_State *L) { + return LuaCoder(L, EscapeFragment); +} + +int LuaEscapeLiteral(lua_State *L) { + return LuaCoder(L, EscapeJsStringLiteral); +} + +int LuaVisualizeControlCodes(lua_State *L) { + return LuaCoder(L, VisualizeControlCodes); +} + +static dontinline int LuaHasherImpl(lua_State *L, size_t k, + int H(const void *, size_t, uint8_t *)) { + void *p; + size_t n; + uint8_t d[64]; + p = luaL_checklstring(L, 1, &n); + H(p, n, d); + lua_pushlstring(L, (void *)d, k); + mbedtls_platform_zeroize(d, sizeof(d)); + return 1; +} + +static dontinline int LuaHasher(lua_State *L, size_t k, + int H(const void *, size_t, uint8_t *)) { + return LuaHasherImpl(L, k, H); +} + +int LuaMd5(lua_State *L) { + return LuaHasher(L, 16, mbedtls_md5_ret); +} + +int LuaSha1(lua_State *L) { + return LuaHasher(L, 20, mbedtls_sha1_ret); +} + +int LuaSha224(lua_State *L) { + return LuaHasher(L, 28, mbedtls_sha256_ret_224); +} + +int LuaSha256(lua_State *L) { + return LuaHasher(L, 32, mbedtls_sha256_ret_256); +} + +int LuaSha384(lua_State *L) { + return LuaHasher(L, 48, mbedtls_sha512_ret_384); +} + +int LuaSha512(lua_State *L) { + return LuaHasher(L, 64, mbedtls_sha512_ret_512); +} + +int LuaIsHeaderRepeatable(lua_State *L) { + int h; + bool r; + size_t n; + const char *s; + s = luaL_checklstring(L, 1, &n); + if ((h = GetHttpHeader(s, n)) != -1) { + r = kHttpRepeatable[h]; + } else { + r = false; + } + lua_pushboolean(L, r); + return 1; +} + +void LuaPushUrlView(lua_State *L, struct UrlView *v) { + if (v->p) { + lua_pushlstring(L, v->p, v->n); + } else { + lua_pushnil(L); + } +} diff --git a/tool/net/lfuncs.h b/tool/net/lfuncs.h new file mode 100644 index 000000000..d776272de --- /dev/null +++ b/tool/net/lfuncs.h @@ -0,0 +1,84 @@ +#ifndef COSMOPOLITAN_TOOL_NET_LFUNCS_H_ +#define COSMOPOLITAN_TOOL_NET_LFUNCS_H_ +#include "net/http/url.h" +#include "third_party/lua/lua.h" +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +int LuaMaxmind(lua_State *); +int LuaRe(lua_State *); +int LuaUnix(lua_State *); +int luaopen_argon2(lua_State *); +int luaopen_lsqlite3(lua_State *); + +int LuaBsf(lua_State *); +int LuaBsr(lua_State *); +int LuaCategorizeIp(lua_State *); +int LuaCrc32(lua_State *); +int LuaCrc32c(lua_State *); +int LuaDecimate(lua_State *); +int LuaDecodeBase64(lua_State *); +int LuaDecodeLatin1(lua_State *); +int LuaEncodeBase64(lua_State *); +int LuaEncodeLatin1(lua_State *); +int LuaEscapeFragment(lua_State *); +int LuaEscapeHost(lua_State *); +int LuaEscapeHtml(lua_State *); +int LuaEscapeIp(lua_State *); +int LuaEscapeLiteral(lua_State *); +int LuaEscapeParam(lua_State *); +int LuaEscapePass(lua_State *); +int LuaEscapePath(lua_State *); +int LuaEscapeSegment(lua_State *); +int LuaEscapeUser(lua_State *); +int LuaFormatHttpDateTime(lua_State *); +int LuaFormatIp(lua_State *); +int LuaGetCpuCore(lua_State *); +int LuaGetCpuNode(lua_State *); +int LuaGetCryptoHash(lua_State *); +int LuaGetHostOs(lua_State *); +int LuaGetHttpReason(lua_State *); +int LuaGetLogLevel(lua_State *); +int LuaGetMonospaceWidth(lua_State *); +int LuaGetRandomBytes(lua_State *); +int LuaGetTime(lua_State *); +int LuaHasControlCodes(lua_State *); +int LuaIndentLines(lua_State *); +int LuaIsAcceptableHost(lua_State *); +int LuaIsAcceptablePath(lua_State *); +int LuaIsAcceptablePort(lua_State *); +int LuaIsHeaderRepeatable(lua_State *); +int LuaIsLoopbackIp(lua_State *); +int LuaIsPrivateIp(lua_State *); +int LuaIsPublicIp(lua_State *); +int LuaIsReasonablePath(lua_State *); +int LuaIsValidHttpToken(lua_State *); +int LuaLemur64(lua_State *); +int LuaMd5(lua_State *); +int LuaMeasureEntropy(lua_State *); +int LuaParseHost(lua_State *); +int LuaParseHttpDateTime(lua_State *); +int LuaParseIp(lua_State *); +int LuaParseParams(lua_State *); +int LuaPopcnt(lua_State *); +int LuaRand64(lua_State *); +int LuaRdrand(lua_State *); +int LuaRdseed(lua_State *); +int LuaRdtsc(lua_State *); +int LuaSetLogLevel(lua_State *); +int LuaSha1(lua_State *); +int LuaSha224(lua_State *); +int LuaSha256(lua_State *); +int LuaSha384(lua_State *); +int LuaSha512(lua_State *); +int LuaSleep(lua_State *); +int LuaSlurp(lua_State *); +int LuaUnderlong(lua_State *); +int LuaVisualizeControlCodes(lua_State *); + +void LuaPushUrlView(lua_State *, struct UrlView *); +char *FormatUnixHttpDateTime(char *, int64_t); + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_TOOL_NET_LFUNCS_H_ */ diff --git a/tool/net/lunix.c b/tool/net/lunix.c index e20022b9e..677d98aa1 100644 --- a/tool/net/lunix.c +++ b/tool/net/lunix.c @@ -27,15 +27,17 @@ #include "libc/calls/struct/sigset.h" #include "libc/calls/struct/stat.h" #include "libc/calls/struct/timespec.h" +#include "libc/calls/struct/timeval.h" #include "libc/calls/ucontext.h" #include "libc/dns/dns.h" #include "libc/errno.h" #include "libc/fmt/fmt.h" -#include "libc/fmt/kerrornames.internal.h" +#include "libc/fmt/magnumstrs.internal.h" #include "libc/intrin/kprintf.h" #include "libc/log/check.h" #include "libc/log/log.h" #include "libc/macros.internal.h" +#include "libc/mem/fmt.h" #include "libc/mem/mem.h" #include "libc/runtime/runtime.h" #include "libc/sock/sock.h" @@ -47,6 +49,7 @@ #include "libc/sysv/consts/dt.h" #include "libc/sysv/consts/f.h" #include "libc/sysv/consts/fd.h" +#include "libc/sysv/consts/ip.h" #include "libc/sysv/consts/ipproto.h" #include "libc/sysv/consts/itimer.h" #include "libc/sysv/consts/log.h" @@ -61,7 +64,10 @@ #include "libc/sysv/consts/shut.h" #include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/sio.h" +#include "libc/sysv/consts/so.h" #include "libc/sysv/consts/sock.h" +#include "libc/sysv/consts/sol.h" +#include "libc/sysv/consts/tcp.h" #include "libc/sysv/consts/w.h" #include "libc/sysv/errfuns.h" #include "libc/time/time.h" @@ -110,17 +116,34 @@ static dontinline int ReturnTimespec(lua_State *L, struct timespec *ts) { } static int ReturnErrno(lua_State *L, int nils, int olderr) { - int i; + int i, newerr = errno; + if (!IsTiny() && !(0 < newerr && newerr < (!IsWindows() ? 4096 : 65536))) { + WARNF("errno should not be %d", newerr); + } for (i = 0; i < nils; ++i) { lua_pushnil(L); } - lua_pushinteger(L, errno); + lua_pushinteger(L, newerr); errno = olderr; return nils + 1; } +static int Return01(lua_State *L, int rc, int olderr) { + if (!IsTiny() && (rc != 0 && rc != -1)) { + WARNF("syscall supposed to return 0 / -1 but got %d", rc); + } + if (rc != -1) { + return 0; + } else { + return ReturnErrno(L, 0, olderr); + } +} + static int ReturnRc(lua_State *L, int64_t rc, int olderr) { if (rc != -1) { + if (!IsTiny() && olderr != errno) { + WARNF("errno unexpectedly changed %d → %d", olderr, errno); + } lua_pushinteger(L, rc); return 1; } else { @@ -128,37 +151,11 @@ static int ReturnRc(lua_State *L, int64_t rc, int olderr) { } } -static char **ConvertLuaArrayToStringList(lua_State *L, int i) { - int j, n; - char **p; - luaL_checktype(L, i, LUA_TTABLE); - lua_len(L, i); - n = lua_tointeger(L, -1); - lua_pop(L, 1); - p = xcalloc(n + 1, sizeof(*p)); - for (j = 1; j <= n; ++j) { - lua_geti(L, i, j); - p[j - 1] = strdup(lua_tostring(L, -1)); - lua_pop(L, 1); +static void CheckOptvalsize(lua_State *L, uint32_t want, uint32_t got) { + if (!IsTiny()) { + if (want == got) return; + WARNF("getsockopt optvalsize should be %d but was %d", want, got); } - return p; -} - -static char **ConvertLuaTableToEnvList(lua_State *L, int i) { - int j, n; - char **p, *s; - luaL_checktype(L, i, LUA_TTABLE); - p = xcalloc((n = 0) + 1, sizeof(char *)); - lua_pushnil(L); - for (n = 0; lua_next(L, i);) { - if (lua_type(L, -2) == LUA_TSTRING) { - p = xrealloc(p, (++n + 1) * sizeof(*p)); - p[n - 1] = xasprintf("%s=%s", lua_tostring(L, -2), lua_tostring(L, -1)); - } - lua_pop(L, 1); - } - p[n] = 0; - return p; } static void FreeStringList(char **p) { @@ -171,6 +168,30 @@ static void FreeStringList(char **p) { } } +static char **ConvertLuaArrayToStringList(lua_State *L, int i) { + int j, n; + char **p, *s; + luaL_checktype(L, i, LUA_TTABLE); + lua_len(L, i); + n = lua_tointeger(L, -1); + lua_pop(L, 1); + if ((p = calloc(n + 1, sizeof(*p)))) { + for (j = 1; j <= n; ++j) { + lua_geti(L, i, j); + s = strdup(lua_tostring(L, -1)); + lua_pop(L, 1); + if (s) { + p[j - 1] = s; + } else { + FreeStringList(p); + p = 0; + break; + } + } + } + return p; +} + //////////////////////////////////////////////////////////////////////////////// // System Calls @@ -194,6 +215,16 @@ static int LuaUnixGetgid(lua_State *L) { return ReturnInteger(L, getgid()); } +// unix.geteuid() → uid:int +static int LuaUnixGeteuid(lua_State *L) { + return ReturnInteger(L, geteuid()); +} + +// unix.getegid() → gid:int +static int LuaUnixGetegid(lua_State *L) { + return ReturnInteger(L, getegid()); +} + // unix.umask(mask:int) → oldmask:int static int LuaUnixUmask(lua_State *L) { return ReturnInteger(L, umask(luaL_checkinteger(L, 1))); @@ -204,129 +235,86 @@ static wontreturn int LuaUnixExit(lua_State *L) { _Exit(luaL_optinteger(L, 1, 0)); } -// unix.access(path:str, how:int) → rc:int[, errno:int] +// unix.access(path:str, how:int) → errno:int // how can be: R_OK, W_OK, X_OK, F_OK static int LuaUnixAccess(lua_State *L) { - const char *file; - int rc, mode, olderr; - olderr = errno; - file = luaL_checklstring(L, 1, 0); - mode = luaL_checkinteger(L, 2); - rc = access(file, mode); - return ReturnRc(L, rc, olderr); + int olderr = errno; + return Return01(L, access(luaL_checkstring(L, 1), luaL_checkinteger(L, 2)), + olderr); } -// unix.mkdir(path:str[, mode:int]) → rc:int[, errno:int] +// unix.mkdir(path:str[, mode:int]) → errno:int // mode should be octal static int LuaUnixMkdir(lua_State *L) { - const char *file; - int rc, mode, olderr; - olderr = errno; - file = luaL_checklstring(L, 1, 0); - mode = luaL_optinteger(L, 2, 0755); - rc = mkdir(file, mode); - return ReturnRc(L, rc, olderr); + int olderr = errno; + return Return01(L, mkdir(luaL_checkstring(L, 1), luaL_optinteger(L, 2, 0755)), + olderr); } -// unix.makedirs(path:str[, mode:int]) → rc:int[, errno:int] +// unix.makedirs(path:str[, mode:int]) → errno:int // mode should be octal static int LuaUnixMakedirs(lua_State *L) { - const char *file; - int rc, mode, olderr; - olderr = errno; - file = luaL_checklstring(L, 1, 0); - mode = luaL_optinteger(L, 2, 0755); - rc = makedirs(file, mode); - return ReturnRc(L, rc, olderr); + int olderr = errno; + return Return01( + L, makedirs(luaL_checkstring(L, 1), luaL_optinteger(L, 2, 0755)), olderr); } -// unix.chdir(path:str) → rc:int[, errno:int] +// unix.chdir(path:str) → errno:int static int LuaUnixChdir(lua_State *L) { - int rc, olderr; - const char *file; - olderr = errno; - file = luaL_checklstring(L, 1, 0); - rc = chdir(file); - return ReturnRc(L, rc, olderr); + int olderr = errno; + return Return01(L, chdir(luaL_checkstring(L, 1)), olderr); } -// unix.unlink(path:str) → rc:int[, errno:int] +// unix.unlink(path:str) → errno:int static int LuaUnixUnlink(lua_State *L) { - int rc, olderr; - const char *file; - olderr = errno; - file = luaL_checklstring(L, 1, 0); - rc = unlink(file); - return ReturnRc(L, rc, olderr); + int olderr = errno; + return Return01(L, unlink(luaL_checkstring(L, 1)), olderr); } -// unix.rmdir(path:str) → rc:int[, errno:int] +// unix.rmdir(path:str) → errno:int static int LuaUnixRmdir(lua_State *L) { - const char *file; - int rc, olderr; - olderr = errno; - file = luaL_checklstring(L, 1, 0); - rc = rmdir(file); - return ReturnRc(L, rc, olderr); + int olderr = errno; + return Return01(L, rmdir(luaL_checkstring(L, 1)), olderr); } -// unix.rename(oldpath:str, newpath:str) → rc:int[, errno:int] +// unix.rename(oldpath:str, newpath:str) → errno:int static int LuaUnixRename(lua_State *L) { - const char *oldpath, *newpath; - int rc, olderr; - olderr = errno; - oldpath = luaL_checklstring(L, 1, 0); - newpath = luaL_checklstring(L, 2, 0); - rc = rename(oldpath, newpath); - return ReturnRc(L, rc, olderr); + int olderr = errno; + return Return01(L, rename(luaL_checkstring(L, 1), luaL_checkstring(L, 2)), + olderr); } -// unix.link(existingpath:str, newpath:str) → rc:int[, errno:int] +// unix.link(existingpath:str, newpath:str) → errno:int static int LuaUnixLink(lua_State *L) { - const char *existingpath, *newpath; - int rc, olderr; - olderr = errno; - existingpath = luaL_checklstring(L, 1, 0); - newpath = luaL_checklstring(L, 2, 0); - rc = link(existingpath, newpath); - return ReturnRc(L, rc, olderr); + int olderr = errno; + return Return01(L, link(luaL_checkstring(L, 1), luaL_checkstring(L, 2)), + olderr); } -// unix.symlink(target:str, linkpath:str) → rc:int[, errno:int] +// unix.symlink(target:str, linkpath:str) → errno:int static int LuaUnixSymlink(lua_State *L) { - const char *target, *linkpath; - int rc, olderr; - olderr = errno; - target = luaL_checklstring(L, 1, 0); - linkpath = luaL_checklstring(L, 2, 0); - rc = symlink(target, linkpath); - return ReturnRc(L, rc, olderr); + int olderr = errno; + return Return01(L, symlink(luaL_checkstring(L, 1), luaL_checkstring(L, 2)), + olderr); } -// unix.chown(path:str, uid:int, gid:int) → rc:int[, errno:int] +// unix.chown(path:str, uid:int, gid:int) → errno:int static int LuaUnixChown(lua_State *L) { - const char *file; - int rc, uid, gid, olderr; - olderr = errno; - file = luaL_checklstring(L, 1, 0); - uid = luaL_checkinteger(L, 2); - gid = luaL_checkinteger(L, 3); - rc = chown(file, uid, gid); - return ReturnRc(L, rc, olderr); + int olderr = errno; + return Return01(L, + chown(luaL_checkstring(L, 1), luaL_checkinteger(L, 2), + luaL_checkinteger(L, 3)), + olderr); } -// unix.chmod(path:str, mode:int) → rc:int[, errno:int] +// unix.chmod(path:str, mode:int) → errno:int static int LuaUnixChmod(lua_State *L) { - const char *file; - int rc, mode, olderr; - olderr = errno; - file = luaL_checklstring(L, 1, 0); - mode = luaL_checkinteger(L, 2); - rc = chmod(file, mode); - return ReturnRc(L, rc, olderr); + int olderr = errno; + return Return01(L, chmod(luaL_checkstring(L, 1), luaL_checkinteger(L, 2)), + olderr); } -// unix.getcwd(path:str, mode:int) → rc:int[, errno:int] +// unix.getcwd() → path:str[, errno:int] static int LuaUnixGetcwd(lua_State *L) { int olderr; char *path; @@ -342,10 +330,20 @@ static int LuaUnixGetcwd(lua_State *L) { // unix.fork() → childpid|0:int[, errno:int] static int LuaUnixFork(lua_State *L) { - int rc, olderr; - olderr = errno; - rc = fork(); - return ReturnRc(L, rc, olderr); + int olderr = errno; + return ReturnRc(L, fork(), olderr); +} + +// unix.environ() → {str,...} +static int LuaUnixEnviron(lua_State *L) { + int i; + char **e; + lua_newtable(L); + for (i = 0, e = environ; *e; ++e) { + lua_pushstring(L, *e); + lua_rawseti(L, -2, ++i); + } + return 1; } // unix.execve(prog:str[, args:List<*>, env:Map]) → errno:int @@ -364,14 +362,21 @@ static int LuaUnixExecve(lua_State *L) { olderr = errno; prog = luaL_checkstring(L, 1); if (!lua_isnoneornil(L, 2)) { - argv = ConvertLuaArrayToStringList(L, 2); - freeme1 = argv; - if (!lua_isnoneornil(L, 3)) { - envp = ConvertLuaTableToEnvList(L, 3); - freeme2 = envp; + if ((argv = ConvertLuaArrayToStringList(L, 2))) { + freeme1 = argv; + if (!lua_isnoneornil(L, 3)) { + if ((envp = ConvertLuaArrayToStringList(L, 3))) { + freeme2 = envp; + } else { + FreeStringList(argv); + return ReturnErrno(L, 1, olderr); + } + } else { + envp = environ; + freeme2 = 0; + } } else { - envp = environ; - freeme2 = 0; + return ReturnErrno(L, 1, olderr); } } else { ezargs[0] = prog; @@ -389,13 +394,13 @@ static int LuaUnixExecve(lua_State *L) { // unix.commandv(prog:str) → path:str[, errno:int] static int LuaUnixCommandv(lua_State *L) { - int rc, olderr; + int olderr; const char *prog; char *pathbuf, *resolved; olderr = errno; - if ((pathbuf = malloc(PATH_MAX))) { - prog = luaL_checkstring(L, 1); - if ((resolved = commandv(prog, pathbuf))) { + prog = luaL_checkstring(L, 1); + if ((pathbuf = malloc(PATH_MAX + 1))) { + if ((resolved = commandv(prog, pathbuf, PATH_MAX + 1))) { lua_pushstring(L, resolved); free(pathbuf); return 1; @@ -411,7 +416,7 @@ static int LuaUnixCommandv(lua_State *L) { // unix.realpath(path:str) → path:str[, errno:int] static int LuaUnixRealpath(lua_State *L) { char *resolved; - int rc, olderr; + int olderr; const char *path; olderr = errno; path = luaL_checkstring(L, 1); @@ -430,25 +435,21 @@ static int LuaUnixSyslog(lua_State *L) { return 0; } -// unix.chroot(path:str) → rc:int[, errno:int] +// unix.chroot(path:str) → errno:int static int LuaUnixChroot(lua_State *L) { - int rc, olderr; - const char *path; - olderr = errno; - path = luaL_checkstring(L, 1); - rc = chroot(path); - return ReturnRc(L, rc, olderr); + int olderr = errno; + return Return01(L, chroot(luaL_checkstring(L, 1)), olderr); } -// unix.setrlimit(resource:int, soft:int[, hard:int]) → rc:int[, errno:int] +// unix.setrlimit(resource:int, soft:int[, hard:int]) → errno:int static int LuaUnixSetrlimit(lua_State *L) { - struct rlimit rlim; - int rc, olderr, resource; - olderr = errno; - resource = luaL_checkinteger(L, 1); - rlim.rlim_cur = luaL_checkinteger(L, 2); - rlim.rlim_max = luaL_optinteger(L, 3, rlim.rlim_cur); - return ReturnRc(L, setrlimit(resource, &rlim), olderr); + int olderr = errno; + int64_t soft = luaL_checkinteger(L, 2); + return Return01( + L, + setrlimit(luaL_checkinteger(L, 1), + &(struct rlimit){soft, luaL_optinteger(L, 3, soft)}), + olderr); } // unix.getrlimit(resource:int) → soft:int, hard:int[, errno:int] @@ -466,34 +467,25 @@ static int LuaUnixGetrlimit(lua_State *L) { } } -// unix.kill(pid, sig) → rc:int[, errno:int] +// unix.kill(pid:int, sig:int) → errno:int static int LuaUnixKill(lua_State *L) { - int rc, pid, sig, olderr; - olderr = errno; - pid = luaL_checkinteger(L, 1); - sig = luaL_checkinteger(L, 2); - rc = kill(pid, sig); - return ReturnRc(L, rc, olderr); + int olderr = errno; + return Return01(L, kill(luaL_checkinteger(L, 1), luaL_checkinteger(L, 2)), + olderr); } -// unix.raise(sig) → rc:int[, errno:int] +// unix.raise(sig:int) → rc:int[, errno:int] static int LuaUnixRaise(lua_State *L) { - int rc, sig, olderr; - olderr = errno; - sig = luaL_checkinteger(L, 1); - rc = raise(sig); - return ReturnRc(L, rc, olderr); + int olderr = errno; + return ReturnRc(L, raise(luaL_checkinteger(L, 1)), olderr); } -// unix.wait([pid, options]) → pid, wstatus, nil, errno +// unix.wait([pid:int, options:int]) → pid:int, wstatus:int, nil[, errno:int] static int LuaUnixWait(lua_State *L) { - int rc, pid, olderr, options, wstatus; - olderr = errno; - pid = luaL_optinteger(L, 1, -1); - options = luaL_optinteger(L, 2, 0); - rc = wait4(pid, &wstatus, options, 0); - if (rc != -1) { - lua_pushinteger(L, rc); + int pid, wstatus, olderr = errno; + if ((pid = wait4(luaL_optinteger(L, 1, -1), &wstatus, + luaL_optinteger(L, 2, 0), 0)) != -1) { + lua_pushinteger(L, pid); lua_pushinteger(L, wstatus); return 2; } else { @@ -501,20 +493,16 @@ static int LuaUnixWait(lua_State *L) { } } -// unix.fcntl(fd, cmd[, arg]) → rc:int[, errno:int] +// unix.fcntl(fd:int, cmd:int[, arg:int]) → rc:int[, errno:int] static int LuaUnixFcntl(lua_State *L) { - intptr_t arg; - int rc, fd, cmd, olderr; - olderr = errno; - fd = luaL_checkinteger(L, 1); - cmd = luaL_checkinteger(L, 2); - arg = luaL_optinteger(L, 3, 0); - rc = fcntl(fd, cmd, arg); - return ReturnRc(L, rc, olderr); + int olderr = errno; + return ReturnRc(L, + fcntl(luaL_checkinteger(L, 1), luaL_checkinteger(L, 2), + luaL_optinteger(L, 3, 0)), + olderr); } -// unix.dup(oldfd[, newfd[, flags]]) → newfd, errno -// flags can have O_CLOEXEC +// unix.dup(oldfd:int[, newfd:int[, flags:int]]) → newfd:int[, errno:int] static int LuaUnixDup(lua_State *L) { int rc, oldfd, newfd, flags, olderr; olderr = errno; @@ -529,13 +517,10 @@ static int LuaUnixDup(lua_State *L) { return ReturnRc(L, rc, olderr); } -// unix.pipe([flags]) → reader, writer, errno -// flags can have O_CLOEXEC +// unix.pipe([flags:int]) → reader:int, writer:int[, errno:int] static int LuaUnixPipe(lua_State *L) { - int flags, olderr, pipefd[2]; - olderr = errno; - flags = luaL_optinteger(L, 1, 0); - if (!pipe2(pipefd, flags)) { + int pipefd[2], olderr = errno; + if (!pipe2(pipefd, luaL_optinteger(L, 1, 0))) { lua_pushinteger(L, pipefd[0]); lua_pushinteger(L, pipefd[1]); return 2; @@ -546,78 +531,76 @@ static int LuaUnixPipe(lua_State *L) { // unix.getsid(pid) → sid:int[, errno:int] static int LuaUnixGetsid(lua_State *L) { - int rc, pid, olderr; - olderr = errno; - pid = luaL_checkinteger(L, 1); - rc = getsid(pid); - return ReturnRc(L, rc, olderr); + int olderr = errno; + return ReturnRc(L, getsid(luaL_checkinteger(L, 1)), olderr); } // unix.getpgrp() → pgid:int[, errno:int] static int LuaUnixGetpgrp(lua_State *L) { - int rc, olderr; - olderr = errno; - rc = getpgrp(); - return ReturnRc(L, rc, olderr); + int olderr = errno; + return ReturnRc(L, getpgrp(), olderr); } // unix.getpgid(pid:int) → pgid:int[, errno:int] static int LuaUnixGetpgid(lua_State *L) { - int rc, pid, olderr; - olderr = errno; - pid = luaL_checkinteger(L, 1); - rc = getpgid(pid); - return ReturnRc(L, rc, olderr); + int olderr = errno; + return ReturnRc(L, getpgid(luaL_checkinteger(L, 1)), olderr); } // unix.setpgid(pid:int, pgid:int) → pgid:int[, errno:int] static int LuaUnixSetpgid(lua_State *L) { - int rc, pid, pgid, olderr; - olderr = errno; - pid = luaL_checkinteger(L, 1); - pgid = luaL_checkinteger(L, 2); - rc = setpgid(pid, pgid); - return ReturnRc(L, rc, olderr); + int olderr = errno; + return ReturnRc(L, setpgid(luaL_checkinteger(L, 1), luaL_checkinteger(L, 2)), + olderr); } // unix.setpgrp() → pgid:int[, errno:int] static int LuaUnixSetpgrp(lua_State *L) { - int rc, pid, pgrp, olderr; - olderr = errno; - pid = luaL_checkinteger(L, 1); - pgrp = luaL_checkinteger(L, 2); - rc = setpgrp(); - return ReturnRc(L, rc, olderr); + int olderr = errno; + return ReturnRc(L, setpgrp(), olderr); } // unix.setsid() → sid:int[, errno:int] static int LuaUnixSetsid(lua_State *L) { - int rc, olderr; - olderr = errno; - rc = setsid(); - return ReturnRc(L, rc, olderr); + int olderr = errno; + return ReturnRc(L, setsid(), olderr); } -// unix.setuid(uid:int) → rc:int[, errno:int] +// unix.setuid(uid:int) → errno:int static int LuaUnixSetuid(lua_State *L) { int olderr = errno; - return ReturnRc(L, setuid(luaL_checkinteger(L, 1)), olderr); + return Return01(L, setuid(luaL_checkinteger(L, 1)), olderr); } -// unix.setgid(gid:int) → rc:int[, errno:int] +// unix.setgid(gid:int) → errno:int static int LuaUnixSetgid(lua_State *L) { int olderr = errno; - return ReturnRc(L, setgid(luaL_checkinteger(L, 1)), olderr); + return Return01(L, setgid(luaL_checkinteger(L, 1)), olderr); } -// unix.clock_gettime([clock]) → seconds, nanos, errno +// unix.setresuid(real:int, effective:int, saved:int) → errno:int +static int LuaUnixSetresuid(lua_State *L) { + int olderr = errno; + return Return01(L, + setresuid(luaL_checkinteger(L, 1), luaL_checkinteger(L, 2), + luaL_checkinteger(L, 3)), + olderr); +} + +// unix.setresgid(real:int, effective:int, saved:int) → errno:int +static int LuaUnixSetresgid(lua_State *L) { + int olderr = errno; + return Return01(L, + setresgid(luaL_checkinteger(L, 1), luaL_checkinteger(L, 2), + luaL_checkinteger(L, 3)), + olderr); +} + +// unix.clock_gettime([clock:int]) → seconds:int, nanos:int[, errno:int] static int LuaUnixGettime(lua_State *L) { struct timespec ts; - int rc, clock, olderr; - olderr = errno; - clock = luaL_optinteger(L, 1, CLOCK_REALTIME); - rc = clock_gettime(clock, &ts); - if (rc != -1) { + int rc, olderr = errno; + if (!clock_gettime(luaL_optinteger(L, 1, CLOCK_REALTIME), &ts)) { lua_pushinteger(L, ts.tv_sec); lua_pushinteger(L, ts.tv_nsec); return 2; @@ -626,15 +609,14 @@ static int LuaUnixGettime(lua_State *L) { } } -// unix.nanosleep(seconds, nanos) → remseconds, remnanos, errno +// unix.nanosleep(seconds:int, nanos:int) +// → remseconds:int, remnanos:int[, errno:int] static int LuaUnixNanosleep(lua_State *L) { - int rc, olderr; + int olderr = errno; struct timespec req, rem; - olderr = errno; req.tv_sec = luaL_checkinteger(L, 1); req.tv_nsec = luaL_optinteger(L, 2, 0); - rc = nanosleep(&req, &rem); - if (rc != -1) { + if (!nanosleep(&req, &rem)) { lua_pushinteger(L, rem.tv_sec); lua_pushinteger(L, rem.tv_nsec); return 2; @@ -649,82 +631,59 @@ static int LuaUnixSync(lua_State *L) { return 0; } -// unix.fsync(fd:int) → rc:int[, errno:int] +// unix.fsync(fd:int) → errno:int static int LuaUnixFsync(lua_State *L) { - int rc, fd, olderr; - olderr = errno; - fd = luaL_checkinteger(L, 1); - rc = fsync(fd); - return ReturnRc(L, rc, olderr); + int olderr = errno; + return Return01(L, fsync(luaL_checkinteger(L, 1)), olderr); } -// unix.fdatasync(fd:int) → rc:int[, errno:int] +// unix.fdatasync(fd:int) → errno:int static int LuaUnixFdatasync(lua_State *L) { - int rc, fd, olderr; - olderr = errno; - fd = luaL_checkinteger(L, 1); - rc = fdatasync(fd); - return ReturnRc(L, rc, olderr); + int olderr = errno; + return Return01(L, fdatasync(luaL_checkinteger(L, 1)), olderr); } -// unix.open(path, flags[, mode]) → fd, errno +// unix.open(path:str, flags:int[, mode:int]) → fd:int[, errno:int] static int LuaUnixOpen(lua_State *L) { - const char *file; - int rc, flags, mode, olderr; - olderr = errno; - file = luaL_checklstring(L, 1, 0); - flags = luaL_checkinteger(L, 2); - mode = luaL_optinteger(L, 3, 0); - rc = open(file, flags, mode); - return ReturnRc(L, rc, olderr); + int olderr = errno; + return ReturnRc(L, + open(luaL_checkstring(L, 1), luaL_checkinteger(L, 2), + luaL_optinteger(L, 3, 0)), + olderr); } -// unix.close(fd:int) → rc:int[, errno:int] +// unix.close(fd:int) → errno:int static int LuaUnixClose(lua_State *L) { - int rc, fd, olderr; - olderr = errno; - fd = luaL_checkinteger(L, 1); - rc = close(fd); - return ReturnRc(L, rc, olderr); + int olderr = errno; + return Return01(L, close(luaL_checkinteger(L, 1)), olderr); } -// unix.seek(fd, offset, whence) → newpos, errno +// unix.lseek(fd:int, offset:int[, whence:int]) → newpos:int[, errno:int] // where whence ∈ {SEEK_SET, SEEK_CUR, SEEK_END} // whence defaults to SEEK_SET -static int LuaUnixSeek(lua_State *L) { - int64_t newpos, offset; - int fd, olderr, whence; - olderr = errno; - fd = luaL_checkinteger(L, 1); - offset = luaL_checkinteger(L, 2); - whence = luaL_optinteger(L, 3, SEEK_SET); - newpos = lseek(fd, offset, whence); - return ReturnRc(L, newpos, olderr); +static int LuaUnixLseek(lua_State *L) { + int olderr = errno; + return ReturnRc(L, + lseek(luaL_checkinteger(L, 1), luaL_checkinteger(L, 2), + luaL_optinteger(L, 3, SEEK_SET)), + olderr); } -// unix.truncate(path, length) → rc:int[, errno:int] -// unix.truncate(fd, length) → rc:int[, errno:int] +// unix.truncate(path:str[, length:int]) → errno:int static int LuaUnixTruncate(lua_State *L) { - int64_t length; - const char *path; - int rc, fd, olderr, whence; - olderr = errno; - if (lua_isinteger(L, 1)) { - fd = luaL_checkinteger(L, 1); - length = luaL_checkinteger(L, 2); - rc = ftruncate(fd, length); - } else if (lua_isstring(L, 1)) { - path = luaL_checkstring(L, 1); - length = luaL_checkinteger(L, 2); - rc = truncate(path, length); - } else { - luaL_argerror(L, 1, "not integer or string"); - unreachable; - } - return ReturnRc(L, rc, olderr); + int olderr = errno; + return Return01(L, truncate(luaL_checkstring(L, 1), luaL_optinteger(L, 2, 0)), + olderr); } -// unix.read(fd:int[, bufsiz:str, offset:int]) → data:str, errno:int +// unix.ftruncate(fd:int[, length:int]) → errno:int +static int LuaUnixFtruncate(lua_State *L) { + int olderr = errno; + return Return01( + L, ftruncate(luaL_checkinteger(L, 1), luaL_optinteger(L, 2, 0)), olderr); +} + +// unix.read(fd:int[, bufsiz:str, offset:int]) → data:str[, errno:int] static int LuaUnixRead(lua_State *L) { char *buf; size_t got; @@ -774,102 +733,226 @@ static int LuaUnixWrite(lua_State *L) { return ReturnRc(L, rc, olderr); } -// unix.stat(path:str) → UnixStat*[, errno] -// unix.stat(fd:int) → UnixStat*[, errno] -static int LuaUnixStat(lua_State *L) { - const char *path; - int rc, fd, olderr; - struct UnixStat **ust, *st; - olderr = errno; - if ((st = malloc(sizeof(struct UnixStat)))) { - if (lua_isinteger(L, 1)) { - fd = luaL_checkinteger(L, 1); - rc = fstat(fd, &st->st); - } else if (lua_isstring(L, 1)) { - path = luaL_checkstring(L, 1); - rc = stat(path, &st->st); - } else { - free(st); - luaL_argerror(L, 1, "not integer or string"); - unreachable; - } - if (rc != -1) { - st->refs = 1; - ust = lua_newuserdatauv(L, sizeof(st), 1); - luaL_setmetatable(L, "UnixStat*"); - *ust = st; - return 1; - } else { - free(st); - return ReturnErrno(L, 1, olderr); - } - } else { - return ReturnErrno(L, 1, olderr); - } -} - -// unix.opendir(path:str) → UnixDir*[, errno] -// unix.opendir(fd:int) → UnixDir*[, errno] -static int LuaUnixOpendir(lua_State *L) { - DIR *rc; - int fd, olderr; - const char *path; - struct UnixDir **udir, *dir; - olderr = errno; - dir = xcalloc(1, sizeof(struct UnixDir)); - if (lua_isinteger(L, 1)) { - fd = luaL_checkinteger(L, 1); - rc = fdopendir(fd); - } else if (lua_isstring(L, 1)) { - path = luaL_checkstring(L, 1); - rc = opendir(path); - } else { - luaL_argerror(L, 1, "not integer or string"); - unreachable; - } - if (!rc) { - lua_pushnil(L); - lua_pushinteger(L, errno); - errno = olderr; - free(dir); - return 2; - } - dir->refs = 1; - dir->dir = rc; - udir = lua_newuserdatauv(L, sizeof(dir), 1); - luaL_setmetatable(L, "UnixDir*"); - *udir = dir; +static int ReturnStat(lua_State *L, struct UnixStat *ust) { + struct UnixStat **ustp; + ust->refs = 1; + ustp = lua_newuserdatauv(L, sizeof(*ustp), 1); + luaL_setmetatable(L, "UnixStat*"); + *ustp = ust; return 1; } -// unix.socket([family[, type[, protocol]]]) → fd, errno -// SOCK_CLOEXEC may be or'd into type -// family defaults to AF_INET -// type defaults to SOCK_STREAM -// protocol defaults to IPPROTO_TCP -static int LuaUnixSocket(lua_State *L) { - const char *file; - int rc, olderr, family, type, protocol; - olderr = errno; - family = luaL_optinteger(L, 1, AF_INET); - type = luaL_optinteger(L, 2, SOCK_STREAM); - protocol = luaL_optinteger(L, 3, IPPROTO_TCP); - rc = socket(family, type, protocol); - return ReturnRc(L, rc, olderr); +// unix.stat(path:str) → UnixStat*[, errno:int] +static int LuaUnixStat(lua_State *L) { + const char *path; + int olderr = errno; + struct UnixStat *ust; + path = luaL_checkstring(L, 1); + if ((ust = malloc(sizeof(*ust)))) { + if (!stat(path, &ust->st)) { + return ReturnStat(L, ust); + } + free(ust); + } + return ReturnErrno(L, 1, olderr); } -// unix.socketpair([family[, type[, protocol]]]) → fd1, fd2[, errno] -// SOCK_CLOEXEC may be or'd into type -// family defaults to AF_INET -// type defaults to SOCK_STREAM -// protocol defaults to IPPROTO_TCP -static int LuaUnixSocketpair(lua_State *L) { - int olderr, family, type, protocol, sv[2]; +// unix.fstat(fd:int) → UnixFstat*[, errno:int] +static int LuaUnixFstat(lua_State *L) { + int fd, olderr = errno; + struct UnixStat *ust; olderr = errno; - family = luaL_optinteger(L, 1, AF_INET); - type = luaL_optinteger(L, 2, SOCK_STREAM); - protocol = luaL_optinteger(L, 3, IPPROTO_TCP); - if (!socketpair(family, type, protocol, sv)) { + fd = luaL_checkinteger(L, 1); + if ((ust = malloc(sizeof(*ust)))) { + if (!fstat(fd, &ust->st)) { + return ReturnStat(L, ust); + } + free(ust); + } + return ReturnErrno(L, 1, olderr); +} + +static int ReturnDir(lua_State *L, struct UnixDir *udir) { + struct UnixDir **udirp; + udir->refs = 1; + udirp = lua_newuserdatauv(L, sizeof(*udirp), 1); + luaL_setmetatable(L, "UnixDir*"); + *udirp = udir; + return 1; +} + +// unix.opendir(path:str) → UnixDir*[, errno:int] +static int LuaUnixOpendir(lua_State *L) { + int olderr = errno; + const char *path; + struct UnixDir *udir; + path = luaL_checkstring(L, 1); + if ((udir = calloc(1, sizeof(*udir)))) { + if ((udir->dir = opendir(path))) { + return ReturnDir(L, udir); + } + free(udir); + } + return ReturnErrno(L, 1, olderr); +} + +// unix.fdopendir(fd:int) → UnixDir*[, errno:int] +static int LuaUnixFdopendir(lua_State *L) { + int fd, olderr = errno; + struct UnixDir *udir; + fd = luaL_checkinteger(L, 1); + if ((udir = calloc(1, sizeof(*udir)))) { + if ((udir->dir = fdopendir(fd))) { + return ReturnDir(L, udir); + } + free(udir); + } + return ReturnErrno(L, 1, olderr); +} + +static bool IsSockoptBool(int l, int x) { + if (l == SOL_SOCKET) { + return x == SO_DEBUG || // + x == SO_BROADCAST || // + x == SO_REUSEADDR || // + x == SO_REUSEPORT || // + x == SO_KEEPALIVE || // + x == SO_DONTROUTE; // + } else if (l = SOL_TCP) { + return x == TCP_NODELAY || // + x == TCP_CORK || // + x == TCP_QUICKACK || // + x == TCP_FASTOPEN_CONNECT || // + x == TCP_DEFER_ACCEPT; // + } else if (l = SOL_IP) { + return x == IP_HDRINCL; // + } else { + return false; + } +} + +static bool IsSockoptInt(int l, int x) { + if (l == SOL_SOCKET) { + return x == SO_SNDBUF || // + x == SO_RCVBUF || // + x == SO_RCVLOWAT || // + x == SO_SNDLOWAT; // + } else if (l = SOL_TCP) { + return x == TCP_FASTOPEN || // + x == TCP_KEEPCNT || // + x == TCP_MAXSEG || // + x == TCP_SYNCNT || // + x == TCP_NOTSENT_LOWAT || // + x == TCP_WINDOW_CLAMP || // + x == TCP_KEEPIDLE || // + x == TCP_KEEPINTVL; // + } else if (l = SOL_IP) { + return x == IP_TOS || // + x == IP_MTU || // + x == IP_TTL; // + } else { + return false; + } +} + +static bool IsSockoptTimeval(int l, int x) { + if (l == SOL_SOCKET) { + return x == SO_RCVTIMEO || // + x == SO_SNDTIMEO; // + } else { + return false; + } +} + +// unix.setsockopt(fd:int, level:int, optname:int, ...) +// → errno:int +static int LuaUnixSetsockopt(lua_State *L) { + struct timeval tv; + int rc, fd, level, optname, optval, olderr = errno; + fd = luaL_checkinteger(L, 1); + level = luaL_checkinteger(L, 2); + optname = luaL_checkinteger(L, 3); + if (IsSockoptBool(level, optname)) { + optval = lua_toboolean(L, 4); + return Return01(L, setsockopt(fd, level, optname, &optval, sizeof(optval)), + olderr); + } else if (IsSockoptInt(level, optname)) { + optval = luaL_checkinteger(L, 4); + return Return01(L, setsockopt(fd, level, optname, &optval, sizeof(optval)), + olderr); + } else if (IsSockoptTimeval(level, optname)) { + tv.tv_sec = luaL_checkinteger(L, 4); + tv.tv_usec = luaL_optinteger(L, 5, 0); + return Return01(L, setsockopt(fd, level, optname, &tv, sizeof(tv)), olderr); + } else { + lua_pushinteger(L, EINVAL); + return 1; + } +} + +// unix.getsockopt(fd:int, level:int, optname:int) +// → errno:int, ... +static int LuaUnixGetsockopt(lua_State *L) { + struct timeval tv; + uint32_t tvsize, optvalsize; + int rc, fd, level, optname, optval, olderr = errno; + fd = luaL_checkinteger(L, 1); + level = luaL_checkinteger(L, 2); + optname = luaL_checkinteger(L, 3); + if (IsSockoptBool(level, optname)) { + optvalsize = sizeof(optval); + if (getsockopt(fd, level, optname, &optval, &optvalsize) != -1) { + CheckOptvalsize(L, sizeof(optval), optvalsize); + lua_pushnil(L); + lua_pushboolean(L, optval); + return 2; + } else { + return ReturnErrno(L, 0, olderr); + } + } else if (IsSockoptInt(level, optname)) { + optvalsize = sizeof(optval); + if (getsockopt(fd, level, optname, &optval, &optvalsize) != -1) { + CheckOptvalsize(L, sizeof(optval), optvalsize); + lua_pushnil(L); + lua_pushinteger(L, optval); + return 2; + } else { + return ReturnErrno(L, 0, olderr); + } + } else if (IsSockoptTimeval(level, optname)) { + tvsize = sizeof(tv); + if (getsockopt(fd, level, optname, &tv, &tvsize) != -1) { + CheckOptvalsize(L, sizeof(tv), tvsize); + lua_pushnil(L); + lua_pushinteger(L, tv.tv_sec); + lua_pushinteger(L, tv.tv_usec); + return 3; + } else { + return ReturnErrno(L, 0, olderr); + } + } else { + lua_pushinteger(L, EINVAL); + return 1; + } +} + +// unix.socket([family:int[, type:int[, protocol:int]]]) → fd:int[, errno:int] +static int LuaUnixSocket(lua_State *L) { + int olderr = errno; + return ReturnRc( + L, + socket(luaL_optinteger(L, 1, AF_INET), luaL_optinteger(L, 2, SOCK_STREAM), + luaL_optinteger(L, 3, IPPROTO_TCP)), + olderr); +} + +// unix.socketpair([family:int[, type:int[, protocol:int]]]) +// → fd1:int, fd2:int[, errno:int] +static int LuaUnixSocketpair(lua_State *L) { + int sv[2], olderr = errno; + if (!socketpair(luaL_optinteger(L, 1, AF_INET), + luaL_optinteger(L, 2, SOCK_STREAM), + luaL_optinteger(L, 3, IPPROTO_TCP), sv)) { lua_pushinteger(L, sv[0]); lua_pushinteger(L, sv[1]); return 2; @@ -878,54 +961,41 @@ static int LuaUnixSocketpair(lua_State *L) { } } -// unix.bind(fd[, ip, port]) → rc:int[, errno:int] -// SOCK_CLOEXEC may be or'd into type -// family defaults to AF_INET -// type defaults to SOCK_STREAM -// protocol defaults to IPPROTO_TCP +// unix.bind(fd:int[, ip:uint32, port:uint16]) → errno:int static int LuaUnixBind(lua_State *L) { - uint32_t x; - int rc, olderr, fd; - struct sockaddr_in sa; - bzero(&sa, sizeof(sa)); - olderr = errno; - fd = luaL_checkinteger(L, 1); - x = luaL_optinteger(L, 2, 0); - sa.sin_family = AF_INET; - sa.sin_addr.s_addr = htonl(x); - sa.sin_port = htons(luaL_optinteger(L, 3, 0)); - rc = bind(fd, &sa, sizeof(sa)); - return ReturnRc(L, rc, olderr); + int olderr = errno; + return Return01(L, + bind(luaL_checkinteger(L, 1), + &(struct sockaddr_in){ + .sin_family = AF_INET, + .sin_addr.s_addr = htonl(luaL_optinteger(L, 2, 0)), + .sin_port = htons(luaL_optinteger(L, 3, 0)), + }, + sizeof(struct sockaddr_in)), + olderr); } -// unix.connect(fd, ip, port) → rc:int[, errno:int] -// SOCK_CLOEXEC may be or'd into type -// family defaults to AF_INET -// type defaults to SOCK_STREAM -// protocol defaults to IPPROTO_TCP +// unix.connect(fd:int, ip:uint32, port:uint16) → errno:int static int LuaUnixConnect(lua_State *L) { - int rc, olderr, fd; - struct sockaddr_in sa; - bzero(&sa, sizeof(sa)); - olderr = errno; - fd = luaL_checkinteger(L, 1); - sa.sin_addr.s_addr = htonl(luaL_checkinteger(L, 2)); - sa.sin_port = htons(luaL_checkinteger(L, 3)); - rc = connect(fd, &sa, sizeof(sa)); - return ReturnRc(L, rc, olderr); + int olderr = errno; + return Return01(L, + connect(luaL_checkinteger(L, 1), + &(struct sockaddr_in){ + .sin_addr.s_addr = htonl(luaL_checkinteger(L, 2)), + .sin_port = htons(luaL_checkinteger(L, 3)), + }, + sizeof(struct sockaddr_in)), + olderr); } -// unix.listen(fd[, backlog]) → rc:int[, errno:int] +// unix.listen(fd:int[, backlog:int]) → errno:int static int LuaUnixListen(lua_State *L) { - int rc, fd, olderr, backlog; - olderr = errno; - fd = luaL_checkinteger(L, 1); - backlog = luaL_optinteger(L, 2, 10); - rc = listen(fd, backlog); - return ReturnRc(L, rc, olderr); + int olderr = errno; + return Return01(L, listen(luaL_checkinteger(L, 1), luaL_optinteger(L, 2, 10)), + olderr); } -// unix.getsockname(fd) → ip, port, errno +// unix.getsockname(fd:int) → ip:uint32, port:uint16[, errno:int] static int LuaUnixGetsockname(lua_State *L) { int fd, olderr; uint32_t addrsize; @@ -959,7 +1029,8 @@ static int LuaUnixGetpeername(lua_State *L) { } } -// unix.siocgifconf() → {{name:str,ip:uint32,netmask:uint32}, ...}[, errno:int] +// unix.siocgifconf() → {{name:str,ip:uint32,netmask:uint32}, ...}[, +// errno:int] static int LuaUnixSiocgifconf(lua_State *L) { size_t n; char *data; @@ -1024,7 +1095,8 @@ static int LuaUnixGethostname(lua_State *L) { } } -// unix.accept(serverfd:int) → clientfd:int, ip:uint32, port:uint16[, errno:int] +// unix.accept(serverfd:int) +// → clientfd:int, ip:uint32, port:uint16[, errno:int] static int LuaUnixAccept(lua_State *L) { uint32_t addrsize; struct sockaddr_in sa; @@ -1110,7 +1182,7 @@ static int LuaUnixRecvfrom(lua_State *L) { } } -// unix.recv(fd[, bufsiz[, flags]]) → data[, errno] +// unix.recv(fd:int[, bufsiz:int[, flags:int]]) → data:str[, errno:int] static int LuaUnixRecv(lua_State *L) { char *buf; size_t got; @@ -1137,7 +1209,7 @@ static int LuaUnixRecv(lua_State *L) { } } -// unix.send(fd, data[, flags]) → sent, errno +// unix.send(fd:int, data:str[, flags:int]) → sent:int[, errno:int] static int LuaUnixSend(lua_State *L) { char *data; ssize_t rc; @@ -1152,8 +1224,8 @@ static int LuaUnixSend(lua_State *L) { return ReturnRc(L, rc, olderr); } -// unix.sendto(fd, data, ip, port[, flags]) → sent, errno -// flags MSG_OOB, MSG_DONTROUTE, MSG_NOSIGNAL, etc. +// unix.sendto(fd:int, data:str, ip:uint32, port:uint16[, flags:int]) +// → sent:int[, errno:int] static int LuaUnixSendto(lua_State *L) { char *data; ssize_t rc; @@ -1175,12 +1247,9 @@ static int LuaUnixSendto(lua_State *L) { // unix.shutdown(fd, how) → rc:int[, errno:int] // how can be SHUT_RD, SHUT_WR, or SHUT_RDWR static int LuaUnixShutdown(lua_State *L) { - int rc, fd, how, olderr; - olderr = errno; - fd = luaL_checkinteger(L, 1); - how = luaL_checkinteger(L, 2); - rc = shutdown(fd, how); - return ReturnRc(L, rc, olderr); + int olderr = errno; + return Return01(L, shutdown(luaL_checkinteger(L, 1), luaL_checkinteger(L, 2)), + olderr); } // unix.sigprocmask(how[, mask]) → oldmask[, errno] @@ -1368,7 +1437,12 @@ static int LuaUnixStrerror(lua_State *L) { // unix.strerrno(errno) → str static int LuaUnixStrerrno(lua_State *L) { - return ReturnString(L, strerror_short(luaL_checkinteger(L, 1))); + return ReturnString(L, strerrno(luaL_checkinteger(L, 1))); +} + +// unix.strerdoc(errno) → str +static int LuaUnixStrerdoc(lua_State *L) { + return ReturnString(L, strerdoc(luaL_checkinteger(L, 1))); } // unix.strsignal(sig) → str @@ -1530,7 +1604,7 @@ static int FreeUnixDir(struct UnixDir *dir) { return closedir(dir->dir); } -// UnixDir:close() → rc:int[, errno:int] +// UnixDir:close() → errno:int // may be called multiple times // called by the garbage collector too static int LuaUnixDirClose(lua_State *L) { @@ -1541,10 +1615,10 @@ static int LuaUnixDirClose(lua_State *L) { olderr = 0; rc = FreeUnixDir(*udir); *udir = 0; - return ReturnRc(L, rc, olderr); + return Return01(L, rc, olderr); } -// UnixDir:read() → name, kind, ino, off[, errno] +// UnixDir:read() → name:str, kind:int, ino:int, off:int[, errno:int] // returns nil if no more entries // kind can be DT_UNKNOWN/REG/DIR/BLK/LNK/CHR/FIFO/SOCK static int LuaUnixDirRead(lua_State *L) { @@ -1565,7 +1639,7 @@ static int LuaUnixDirRead(lua_State *L) { } } -// UnixDir:fd() → fd, errno +// UnixDir:fd() → fd:int[, errno:int] // EOPNOTSUPP if using /zip/ // EOPNOTSUPP if IsWindows() static int LuaUnixDirFd(lua_State *L) { @@ -1580,7 +1654,7 @@ static int LuaUnixDirFd(lua_State *L) { } } -// UnixDir:tell() → off +// UnixDir:tell() → off:int static int LuaUnixDirTell(lua_State *L) { long off; off = telldir(GetDirOrDie(L)); @@ -1622,10 +1696,11 @@ static void LuaUnixDirObj(lua_State *L) { static const luaL_Reg kLuaUnix[] = { {"exit", LuaUnixExit}, // exit w/o atexit - {"stat", LuaUnixStat}, // get file info + {"stat", LuaUnixStat}, // get file info from path + {"fstat", LuaUnixFstat}, // get file info from fd {"open", LuaUnixOpen}, // open file fd at lowest slot {"close", LuaUnixClose}, // close file or socket - {"seek", LuaUnixSeek}, // seek in file + {"lseek", LuaUnixLseek}, // seek in file {"read", LuaUnixRead}, // read from file or socket {"write", LuaUnixWrite}, // write to file or socket {"access", LuaUnixAccess}, // check my file authorization @@ -1636,6 +1711,7 @@ static const luaL_Reg kLuaUnix[] = { {"getcwd", LuaUnixGetcwd}, // get current directory {"fork", LuaUnixFork}, // make child process via mitosis {"execve", LuaUnixExecve}, // replace process with program + {"environ", LuaUnixEnviron}, // get environment variables {"commandv", LuaUnixCommandv}, // resolve program on $PATH {"realpath", LuaUnixRealpath}, // abspath without dots/symlinks {"syslog", LuaUnixSyslog}, // logs to system log @@ -1648,6 +1724,7 @@ static const luaL_Reg kLuaUnix[] = { {"makedirs", LuaUnixMakedirs}, // make directory and parents too {"rmdir", LuaUnixRmdir}, // remove empty directory {"opendir", LuaUnixOpendir}, // read directory entry list + {"fdopendir", LuaUnixFdopendir}, // read directory entry list {"rename", LuaUnixRename}, // rename file or directory {"link", LuaUnixLink}, // create hard link {"unlink", LuaUnixUnlink}, // remove file @@ -1656,7 +1733,7 @@ static const luaL_Reg kLuaUnix[] = { {"fsync", LuaUnixFsync}, // flush open file {"fdatasync", LuaUnixFdatasync}, // flush open file w/o metadata {"truncate", LuaUnixTruncate}, // shrink or extend file medium - {"ftruncate", LuaUnixTruncate}, // shrink or extend file medium + {"ftruncate", LuaUnixFtruncate}, // shrink or extend file medium {"umask", LuaUnixUmask}, // set default file mask {"chroot", LuaUnixChroot}, // change root directory {"setrlimit", LuaUnixSetrlimit}, // prevent cpu memory bombs @@ -1670,14 +1747,20 @@ static const luaL_Reg kLuaUnix[] = { {"setsid", LuaUnixSetsid}, // create a new session id {"getpid", LuaUnixGetpid}, // get id of this process {"getuid", LuaUnixGetuid}, // get real user id of process + {"geteuid", LuaUnixGeteuid}, // get effective user id of process {"setuid", LuaUnixSetuid}, // set real user id of process + {"setresuid", LuaUnixSetresuid}, // sets real/effective/saved uids {"getgid", LuaUnixGetgid}, // get real group id of process + {"getegid", LuaUnixGetegid}, // get effective group id of process {"setgid", LuaUnixSetgid}, // set real group id of process + {"setresgid", LuaUnixSetresgid}, // sets real/effective/saved gids {"gethostname", LuaUnixGethostname}, // get hostname of this machine {"clock_gettime", LuaUnixGettime}, // get timestamp w/ nano precision {"nanosleep", LuaUnixNanosleep}, // sleep w/ nano precision {"socket", LuaUnixSocket}, // create network communication fd {"socketpair", LuaUnixSocketpair}, // create bidirectional pipe + {"setsockopt", LuaUnixSetsockopt}, // tune socket options + {"getsockopt", LuaUnixGetsockopt}, // get socket tunings {"poll", LuaUnixPoll}, // waits for file descriptor events {"bind", LuaUnixBind}, // reserve network interface address {"listen", LuaUnixListen}, // begin listening for clients @@ -1697,6 +1780,7 @@ static const luaL_Reg kLuaUnix[] = { {"setitimer", LuaUnixSetitimer}, // set alarm clock {"strerror", LuaUnixStrerror}, // turn errno into string {"strerrno", LuaUnixStrerrno}, // turn errno into string + {"strerdoc", LuaUnixStrerdoc}, // turn errno into string {"strsignal", LuaUnixStrsignal}, // turn signal into string {"WIFEXITED", LuaUnixWifexited}, // gets exit code from wait status {"WEXITSTATUS", LuaUnixWexitstatus}, // gets exit status from wait status @@ -1705,10 +1789,17 @@ static const luaL_Reg kLuaUnix[] = { {0}, // }; -int LuaUnix(lua_State *L) { +static void LoadMagnums(lua_State *L, struct MagnumStr *ms, const char *pfx) { int i; - char sigbuf[12]; + char b[64], *p; + p = stpcpy(b, pfx); + for (i = 0; ms[i].x != -123; ++i) { + stpcpy(p, (const char *)((uintptr_t)ms + ms[i].s)); + LuaSetIntField(L, b, *(const int *)((uintptr_t)ms + ms[i].x)); + } +} +int LuaUnix(lua_State *L) { GL = L; luaL_newlib(L, kLuaUnix); LuaUnixStatObj(L); @@ -1716,19 +1807,11 @@ int LuaUnix(lua_State *L) { lua_newtable(L); lua_setglobal(L, "__signal_handlers"); - // errnos - for (i = 0; kErrorNames[i].x; ++i) { - LuaSetIntField(L, (const char *)((uintptr_t)kErrorNames + kErrorNames[i].s), - *(const int *)((uintptr_t)kErrorNames + kErrorNames[i].x)); - } - - // signals - strcpy(sigbuf, "SIG"); - for (i = 0; kStrSignal[i].x; ++i) { - strcpy(sigbuf + 3, (const char *)((uintptr_t)kStrSignal + kStrSignal[i].s)); - LuaSetIntField(L, sigbuf, - *(const int *)((uintptr_t)kStrSignal + kStrSignal[i].x)); - } + LoadMagnums(L, kErrnoNames, ""); + LoadMagnums(L, kSignalNames, "SIG"); + LoadMagnums(L, kIpOptnames, ""); + LoadMagnums(L, kTcpOptnames, ""); + LoadMagnums(L, kSockOptnames, ""); // open() flags LuaSetIntField(L, "O_RDONLY", O_RDONLY); // @@ -1816,11 +1899,17 @@ int LuaUnix(lua_State *L) { // socket() type LuaSetIntField(L, "SOCK_STREAM", SOCK_STREAM); LuaSetIntField(L, "SOCK_DGRAM", SOCK_DGRAM); + LuaSetIntField(L, "SOCK_RAW", SOCK_RAW); + LuaSetIntField(L, "SOCK_RDM", SOCK_RDM); + LuaSetIntField(L, "SOCK_SEQPACKET", SOCK_SEQPACKET); LuaSetIntField(L, "SOCK_CLOEXEC", SOCK_CLOEXEC); // socket() protocol + LuaSetIntField(L, "IPPROTO_IP", IPPROTO_IP); + LuaSetIntField(L, "IPPROTO_ICMP", IPPROTO_ICMP); LuaSetIntField(L, "IPPROTO_TCP", IPPROTO_TCP); LuaSetIntField(L, "IPPROTO_UDP", IPPROTO_UDP); + LuaSetIntField(L, "IPPROTO_RAW", IPPROTO_RAW); // shutdown() how LuaSetIntField(L, "SHUT_RD", SHUT_RD); @@ -1885,5 +1974,11 @@ int LuaUnix(lua_State *L) { LuaSetIntField(L, "LOG_INFO", LOG_INFO); LuaSetIntField(L, "LOG_DEBUG", LOG_DEBUG); + // setsockopt() level + LuaSetIntField(L, "SOL_IP", SOL_IP); + LuaSetIntField(L, "SOL_SOCKET", SOL_SOCKET); + LuaSetIntField(L, "SOL_TCP", SOL_TCP); + LuaSetIntField(L, "SOL_UDP", SOL_UDP); + return 1; } diff --git a/tool/net/net.mk b/tool/net/net.mk index edede4163..b5d763938 100644 --- a/tool/net/net.mk +++ b/tool/net/net.mk @@ -90,7 +90,8 @@ o/$(MODE)/tool/net/%.com.dbg: \ o/$(MODE)/tool/net/redbean.com.dbg: \ $(TOOL_NET_DEPS) \ - o/$(MODE)/tool/net/redbean.o \ + o/$(MODE)/tool/net/redbean.o \ + o/$(MODE)/tool/net/lfuncs.o \ o/$(MODE)/tool/net/lre.o \ o/$(MODE)/tool/net/lunix.o \ o/$(MODE)/tool/net/lmaxmind.o \ @@ -208,7 +209,8 @@ o/$(MODE)/tool/net/demo/virtualbean.html.zip.o: \ o/$(MODE)/tool/net/redbean-demo.com.dbg: \ $(TOOL_NET_DEPS) \ - o/$(MODE)/tool/net/redbean.o \ + o/$(MODE)/tool/net/redbean.o \ + o/$(MODE)/tool/net/lfuncs.o \ o/$(MODE)/tool/net/lre.o \ o/$(MODE)/tool/net/lunix.o \ o/$(MODE)/tool/net/lmaxmind.o \ @@ -326,6 +328,7 @@ o/$(MODE)/tool/net/redbean-unsecure.com: \ o/$(MODE)/tool/net/redbean-unsecure.com.dbg: \ $(TOOL_NET_DEPS) \ o/$(MODE)/tool/net/redbean-unsecure.o \ + o/$(MODE)/tool/net/lfuncs.o \ o/$(MODE)/tool/net/lre.o \ o/$(MODE)/tool/net/lunix.o \ o/$(MODE)/tool/net/lmaxmind.o \ @@ -408,6 +411,9 @@ o/$(MODE)/tool/net/redbean-original.com.dbg: \ o/$(MODE)/tool/net/redbean-original.o: tool/net/redbean.c o/$(MODE)/tool/net/redbean.o @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -DSTATIC -DUNSECURE -DREDBEAN=\"redbean-original\" $(OUTPUT_OPTION) $< +o/$(MODE)/tool/net/redbean-original.s: tool/net/redbean.c o/$(MODE)/tool/net/redbean.o + @$(COMPILE) -AOBJECTIFY.c $(COMPILE.c) -DSTATIC -DUNSECURE -DREDBEAN=\"redbean-original\" $(OUTPUT_OPTION) $< + # REDBEAN-ASSIMILATE.COM # # Same as REDBEAN.COM except without no-modify-self behavior. diff --git a/tool/net/redbean.c b/tool/net/redbean.c index ca65139e0..33bfa4ca0 100644 --- a/tool/net/redbean.c +++ b/tool/net/redbean.c @@ -57,6 +57,7 @@ #include "libc/nt/enum/fileflagandattributes.h" #include "libc/nt/runtime.h" #include "libc/nt/thread.h" +#include "libc/nt/version.h" #include "libc/rand/rand.h" #include "libc/runtime/clktck.h" #include "libc/runtime/directmap.internal.h" @@ -146,6 +147,7 @@ #include "third_party/zlib/zlib.h" #include "tool/build/lib/case.h" #include "tool/build/lib/psk.h" +#include "tool/net/lfuncs.h" #include "tool/net/luacheck.h" #include "tool/net/sandbox.h" @@ -1016,8 +1018,17 @@ static bool IsServerFd(int fd) { } static void ChangeUser(void) { - if (changegid) LOGIFNEG1(setgid(changegid)); - if (changeuid) LOGIFNEG1(setuid(changeuid)); + if (changegid) { + if (setgid(changegid)) { + FATALF("setgid() failed: %m"); + } + } + // order matters + if (changeuid) { + if (setuid(changeuid)) { + FATALF("setuid() failed: %m"); + } + } } static void Daemonize(void) { @@ -1855,6 +1866,13 @@ static bool ClientAcceptsGzip(void) { HeaderHas(&msg, inbuf.p, kHttpAcceptEncoding, "gzip", 4); } +char *FormatUnixHttpDateTime(char *s, int64_t t) { + struct tm tm; + gmtime_r(&t, &tm); + FormatHttpDateTime(s, &tm); + return s; +} + static void UpdateCurrentDate(long double now) { int64_t t; struct tm tm; @@ -1879,13 +1897,6 @@ forceinline int GetMode(struct Asset *a) { return a->file ? a->file->st.st_mode : GetZipCfileMode(zbase + a->cf); } -static char *FormatUnixHttpDateTime(char *s, int64_t t) { - struct tm tm; - gmtime_r(&t, &tm); - FormatHttpDateTime(s, &tm); - return s; -} - forceinline bool IsCompressionMethodSupported(int method) { return method == kZipCompressionNone || method == kZipCompressionDeflate; } @@ -2225,37 +2236,14 @@ static void *LoadAsset(struct Asset *a, size_t *out_size) { static wontreturn void PrintUsage(int fd, int rc) { size_t n; - int pip[2]; const char *p; struct Asset *a; - char buf[PATH_MAX]; - char *args[2] = {0}; if (!(a = GetAssetZip("/help.txt", 9)) || !(p = LoadAsset(a, &n))) { fprintf(stderr, "error: /help.txt is not a zip asset\n"); exit(1); } - if (strcmp(nulltoempty(getenv("TERM")), "dumb") && isatty(0) && isatty(1) && - ((args[0] = commandv("less", buf)) || - (args[0] = commandv("more", buf)))) { - sigaction(SIGPIPE, &(struct sigaction){.sa_handler = SIG_IGN}, 0); - close(0); - pipe(pip); - if (!fork()) { - close(pip[1]); - execv(args[0], args); - _Exit(127); - } - close(0); - WritevAll(pip[1], &(struct iovec){p, n}, 1); - close(pip[1]); - wait(0); - free(p); - exit(0); - } else { - WritevAll(fd, &(struct iovec){p, n}, 1); - free(p); - exit(rc); - } + __paginate(fd, p); + exit(rc); } static void AppendLogo(void) { @@ -2714,7 +2702,8 @@ static void LaunchBrowser(const char *path) { // assign a loopback address if no server or unknown server address if (!servers.n || !addr.s_addr) addr.s_addr = htonl(INADDR_LOOPBACK); if (*path != '/') path = gc(xasprintf("/%s", path)); - if ((prog = commandv(GetSystemUrlLauncherCommand(), gc(malloc(PATH_MAX))))) { + if ((prog = commandv(GetSystemUrlLauncherCommand(), gc(malloc(PATH_MAX + 1)), + PATH_MAX + 1))) { u = gc(xasprintf("http://%s:%d%s", inet_ntoa(addr), port, gc(EscapePath(path, -1, 0)))); DEBUGF("(srvr) opening browser with command %`'s %s", prog, u); @@ -3013,23 +3002,15 @@ static char *GetLuaResponse(void) { return luaheaderp ? luaheaderp : SetStatus(200, "OK"); } -static bool IsLoopbackClient(void) { - uint32_t ip; - uint16_t port; - GetRemoteAddr(&ip, &port); - return IsLoopbackIp(ip); -} - -static bool IsPrivateClient(void) { - uint32_t ip; - uint16_t port; - GetRemoteAddr(&ip, &port); - return IsLoopbackIp(ip) || IsPrivateIp(ip); -} - static bool ShouldServeCrashReportDetails(void) { - if (leakcrashreports) return true; - return IsPrivateClient(); + uint32_t ip; + uint16_t port; + if (leakcrashreports) { + return true; + } else { + GetRemoteAddr(&ip, &port); + return IsLoopbackIp(ip) || IsPrivateIp(ip); + } } static char *LuaOnHttpRequest(void) { @@ -3161,29 +3142,32 @@ static const char *LuaCheckHost(lua_State *L, int idx, size_t *hostlen) { static void OnlyCallFromInitLua(lua_State *L, const char *api) { if (isinitialized) { - luaL_error(L, "%s() should be called from the global scope of .init.lua", - api); + luaL_error(L, "%s() should be called %s", api, + "from the global scope of .init.lua"); unreachable; } } -static void DontCallFromInitLua(lua_State *L, const char *api) { - if (!isinitialized) { - luaL_error(L, "%s() can't be called from .init.lua", api); +static void OnlyCallFromMainProcess(lua_State *L, const char *api) { + if (__isworker) { + luaL_error(L, "%s() should be called %s", api, + "from .init.lua or the repl"); unreachable; } } static void OnlyCallDuringConnection(lua_State *L, const char *api) { if (!ishandlingconnection) { - luaL_error(L, "%s() can only be called while handling a connection", api); + luaL_error(L, "%s() can only be called ", api, + "while handling a connection"); unreachable; } } static void OnlyCallDuringRequest(lua_State *L, const char *api) { if (!ishandlingrequest) { - luaL_error(L, "%s() can only be called while handling a request", api); + luaL_error(L, "%s() can only be called %s", api, + "while handling a request"); unreachable; } } @@ -3674,7 +3658,7 @@ static void LogBody(const char *d, const char *s, size_t n) { } static int LuaFetch(lua_State *L) { -#define ssl nope /* TODO(jart): make this file less huge */ +#define ssl nope // TODO(jart): make this file less huge char *p; ssize_t rc; bool usessl; @@ -4112,55 +4096,59 @@ static int LuaGetRemoteAddr(lua_State *L) { return LuaGetAddr(L, GetRemoteAddr); } -static int LuaFormatIp(lua_State *L) { - char b[16]; - uint32_t ip; - ip = htonl(luaL_checkinteger(L, 1)); - inet_ntop(AF_INET, &ip, b, sizeof(b)); - lua_pushstring(L, b); +static int LuaLog(lua_State *L) { + int level, line; + lua_Debug ar; + const char *msg, *module; + level = luaL_checkinteger(L, 1); + if (LOGGABLE(level)) { + msg = luaL_checkstring(L, 2); + if (lua_getstack(L, 1, &ar) && lua_getinfo(L, "Sl", &ar)) { + module = ar.short_src; + line = ar.currentline; + } else { + module = gc(strndup(effectivepath.p, effectivepath.n)); + line = -1; + } + flogf(level, module, line, NULL, "%s", msg); + } + return 0; +} + +static int LuaEncodeSmth(lua_State *L, + int Encoder(lua_State *, char **, int, char *)) { + int useoutput = false; + int maxdepth = 64; + char *numformat = "%.14g"; + char *p = 0; + if (lua_istable(L, 2)) { + lua_settop(L, 2); // discard any extra arguments + lua_getfield(L, 2, "useoutput"); + // ignore useoutput outside of request handling + if (ishandlingrequest && lua_isboolean(L, -1)) + useoutput = lua_toboolean(L, -1); + lua_getfield(L, 2, "maxdepth"); + maxdepth = luaL_optinteger(L, -1, maxdepth); + lua_getfield(L, 2, "numformat"); + numformat = luaL_optstring(L, -1, numformat); + } + lua_settop(L, 1); // keep the passed argument on top + Encoder(L, useoutput ? &outbuf : &p, maxdepth, numformat); + if (useoutput) { + lua_pushnil(L); + } else { + lua_pushstring(L, p); + free(p); + } return 1; } -static int LuaParseIp(lua_State *L) { - size_t n; - const char *s; - s = luaL_checklstring(L, 1, &n); - lua_pushinteger(L, ParseIp(s, n)); - return 1; +static int LuaEncodeJson(lua_State *L) { + return LuaEncodeSmth(L, LuaEncodeJsonData); } -static int LuaIsIp(lua_State *L, bool IsIp(uint32_t)) { - lua_pushboolean(L, IsIp(luaL_checkinteger(L, 1))); - return 1; -} - -static int LuaIsPublicIp(lua_State *L) { - return LuaIsIp(L, IsPublicIp); -} - -static int LuaIsPrivateIp(lua_State *L) { - return LuaIsIp(L, IsPrivateIp); -} - -static int LuaIsLoopbackIp(lua_State *L) { - return LuaIsIp(L, IsLoopbackIp); -} - -static int LuaIsLoopbackClient(lua_State *L) { - OnlyCallDuringRequest(L, "IsLoopbackClient"); - lua_pushboolean(L, IsLoopbackClient()); - return 1; -} - -static int LuaIsPrivateClient(lua_State *L) { - OnlyCallDuringRequest(L, "IsPrivateClient"); - lua_pushboolean(L, IsPrivateClient()); - return 1; -} - -static int LuaCategorizeIp(lua_State *L) { - lua_pushstring(L, GetIpCategoryName(CategorizeIp(luaL_checkinteger(L, 1)))); - return 1; +static int LuaEncodeLua(lua_State *L) { + return LuaEncodeSmth(L, LuaEncodeLuaData); } static int LuaGetUrl(lua_State *L) { @@ -4173,14 +4161,6 @@ static int LuaGetUrl(lua_State *L) { return 1; } -static void LuaPushUrlView(lua_State *L, struct UrlView *v) { - if (v->p) { - lua_pushlstring(L, v->p, v->n); - } else { - lua_pushnil(L); - } -} - static int LuaGetScheme(lua_State *L) { OnlyCallDuringRequest(L, "GetScheme"); LuaPushUrlView(L, &url.scheme); @@ -4261,21 +4241,8 @@ static int LuaGetPort(lua_State *L) { return 1; } -static int LuaFormatHttpDateTime(lua_State *L) { - char buf[30]; - lua_pushstring(L, FormatUnixHttpDateTime(buf, luaL_checkinteger(L, 1))); - return 1; -} - -static int LuaParseHttpDateTime(lua_State *L) { - size_t n; - const char *s; - s = luaL_checklstring(L, 1, &n); - lua_pushinteger(L, ParseHttpDateTime(s, n)); - return 1; -} - static int LuaGetBody(lua_State *L) { + OnlyCallDuringRequest(L, "GetBody"); lua_pushlstring(L, inbuf.p + hdrsize, payloadlength); return 1; } @@ -4526,35 +4493,6 @@ static int LuaGetParams(lua_State *L) { return 1; } -static int LuaParseParams(lua_State *L) { - void *m; - size_t size; - const char *data; - struct UrlParams h; - data = luaL_checklstring(L, 1, &size); - bzero(&h, sizeof(h)); - m = ParseParams(data, size, &h); - LuaPushUrlParams(L, &h); - free(h.p); - free(m); - return 1; -} - -static int LuaParseHost(lua_State *L) { - void *m; - size_t n; - struct Url h; - const char *p; - bzero(&h, sizeof(h)); - p = luaL_checklstring(L, 1, &n); - m = ParseHost(p, n, &h); - lua_newtable(L); - LuaPushUrlView(L, &h.host); - LuaPushUrlView(L, &h.port); - free(m); - return 1; -} - static int LuaWrite(lua_State *L) { size_t size; const char *data; @@ -4566,350 +4504,6 @@ static int LuaWrite(lua_State *L) { return 0; } -static int LuaCheckControlFlags(lua_State *L, int idx) { - int f = luaL_checkinteger(L, idx); - if (f & ~(kControlWs | kControlC0 | kControlC1)) { - luaL_argerror(L, idx, "invalid control flags"); - unreachable; - } - return f; -} - -static int LuaHasControlCodes(lua_State *L) { - int f; - size_t n; - const char *p; - p = luaL_checklstring(L, 1, &n); - f = LuaCheckControlFlags(L, 2); - lua_pushboolean(L, HasControlCodes(p, n, f) != -1); - return 1; -} - -static int LuaIsValid(lua_State *L, bool V(const char *, size_t)) { - size_t size; - const char *data; - data = luaL_checklstring(L, 1, &size); - lua_pushboolean(L, V(data, size)); - return 1; -} - -static int LuaIsValidHttpToken(lua_State *L) { - return LuaIsValid(L, IsValidHttpToken); -} - -static int LuaIsAcceptablePath(lua_State *L) { - return LuaIsValid(L, IsAcceptablePath); -} - -static int LuaIsReasonablePath(lua_State *L) { - return LuaIsValid(L, IsReasonablePath); -} - -static int LuaIsAcceptableHost(lua_State *L) { - return LuaIsValid(L, IsAcceptableHost); -} - -static int LuaIsAcceptablePort(lua_State *L) { - return LuaIsValid(L, IsAcceptablePort); -} - -static dontinline int LuaCoderImpl(lua_State *L, - char *C(const char *, size_t, size_t *)) { - void *p; - size_t n; - p = luaL_checklstring(L, 1, &n); - p = C(p, n, &n); - lua_pushlstring(L, p, n); - free(p); - return 1; -} - -static dontinline int LuaCoder(lua_State *L, - char *C(const char *, size_t, size_t *)) { - return LuaCoderImpl(L, C); -} - -static int LuaUnderlong(lua_State *L) { - return LuaCoder(L, Underlong); -} - -static int LuaEncodeBase64(lua_State *L) { - return LuaCoder(L, EncodeBase64); -} - -static int LuaDecodeBase64(lua_State *L) { - return LuaCoder(L, DecodeBase64); -} - -static int LuaDecodeLatin1(lua_State *L) { - return LuaCoder(L, DecodeLatin1); -} - -static int LuaEscapeHtml(lua_State *L) { - return LuaCoder(L, EscapeHtml); -} - -static int LuaEscapeParam(lua_State *L) { - return LuaCoder(L, EscapeParam); -} - -static int LuaEscapePath(lua_State *L) { - return LuaCoder(L, EscapePath); -} - -static int LuaEscapeHost(lua_State *L) { - return LuaCoder(L, EscapeHost); -} - -static int LuaEscapeIp(lua_State *L) { - return LuaCoder(L, EscapeIp); -} - -static int LuaEscapeUser(lua_State *L) { - return LuaCoder(L, EscapeUser); -} - -static int LuaEscapePass(lua_State *L) { - return LuaCoder(L, EscapePass); -} - -static int LuaEscapeSegment(lua_State *L) { - return LuaCoder(L, EscapeSegment); -} - -static int LuaEscapeFragment(lua_State *L) { - return LuaCoder(L, EscapeFragment); -} - -static int LuaEscapeLiteral(lua_State *L) { - return LuaCoder(L, EscapeJsStringLiteral); -} - -static int LuaVisualizeControlCodes(lua_State *L) { - return LuaCoder(L, VisualizeControlCodes); -} - -static dontinline int LuaHasherImpl(lua_State *L, size_t k, - int H(const void *, size_t, uint8_t *)) { - void *p; - size_t n; - uint8_t d[64]; - p = luaL_checklstring(L, 1, &n); - H(p, n, d); - lua_pushlstring(L, (void *)d, k); - mbedtls_platform_zeroize(d, sizeof(d)); - return 1; -} - -static dontinline int LuaHasher(lua_State *L, size_t k, - int H(const void *, size_t, uint8_t *)) { - return LuaHasherImpl(L, k, H); -} - -static int LuaMd5(lua_State *L) { - return LuaHasher(L, 16, mbedtls_md5_ret); -} - -static int LuaSha1(lua_State *L) { - return LuaHasher(L, 20, mbedtls_sha1_ret); -} - -static int LuaSha224(lua_State *L) { - return LuaHasher(L, 28, mbedtls_sha256_ret_224); -} - -static int LuaSha256(lua_State *L) { - return LuaHasher(L, 32, mbedtls_sha256_ret_256); -} - -static int LuaSha384(lua_State *L) { - return LuaHasher(L, 48, mbedtls_sha512_ret_384); -} - -static int LuaSha512(lua_State *L) { - return LuaHasher(L, 64, mbedtls_sha512_ret_512); -} - -static dontinline int LuaGetCryptoHash(lua_State *L) { - size_t hl, pl, kl; - uint8_t d[64]; - mbedtls_md_context_t ctx; - // get hash name, payload, and key - void *h = luaL_checklstring(L, 1, &hl); - void *p = luaL_checklstring(L, 2, &pl); - void *k = luaL_optlstring(L, 3, "", &kl); - - const mbedtls_md_info_t *digest = mbedtls_md_info_from_string(h); - if (!digest) return luaL_argerror(L, 1, "unknown hash type"); - - if (kl == 0) { - // no key provided, run generic hash function - if ((digest->f_md)(p, pl, d)) return luaL_error(L, "bad input data"); - } else if (mbedtls_md_hmac(digest, k, kl, p, pl, d)) - return luaL_error(L, "bad input data"); - - lua_pushlstring(L, (void *)d, digest->size); - mbedtls_platform_zeroize(d, sizeof(d)); - return 1; -} - -static int LuaGetRandomBytes(lua_State *L) { - char *p; - size_t n = luaL_optinteger(L, 1, 16); - if (!(n > 0 && n <= 256)) { - luaL_argerror(L, 1, "not in range 1..256"); - unreachable; - } - - p = malloc(n); - CHECK_EQ(n, getrandom(p, n, 0)); - lua_pushlstring(L, p, n); - free(p); - return 1; -} - -static int LuaGetHttpReason(lua_State *L) { - lua_pushstring(L, GetHttpReason(luaL_checkinteger(L, 1))); - return 1; -} - -static int LuaEncodeSmth(lua_State *L, - int Encoder(lua_State *, char **, int, char *)) { - int useoutput = false; - int maxdepth = 64; - char *numformat = "%.14g"; - char *p = 0; - if (lua_istable(L, 2)) { - lua_settop(L, 2); // discard any extra arguments - lua_getfield(L, 2, "useoutput"); - // ignore useoutput outside of request handling - if (ishandlingrequest && lua_isboolean(L, -1)) - useoutput = lua_toboolean(L, -1); - lua_getfield(L, 2, "maxdepth"); - maxdepth = luaL_optinteger(L, -1, maxdepth); - lua_getfield(L, 2, "numformat"); - numformat = luaL_optstring(L, -1, numformat); - } - lua_settop(L, 1); // keep the passed argument on top - Encoder(L, useoutput ? &outbuf : &p, maxdepth, numformat); - if (useoutput) { - lua_pushnil(L); - } else { - lua_pushstring(L, p); - free(p); - } - return 1; -} - -static int LuaEncodeJson(lua_State *L) { - return LuaEncodeSmth(L, LuaEncodeJsonData); -} - -static int LuaEncodeLua(lua_State *L) { - return LuaEncodeSmth(L, LuaEncodeLuaData); -} - -static int LuaEncodeLatin1(lua_State *L) { - int f; - char *p; - size_t n; - p = luaL_checklstring(L, 1, &n); - f = LuaCheckControlFlags(L, 2); - p = EncodeLatin1(p, n, &n, f); - lua_pushlstring(L, p, n); - free(p); - return 1; -} - -static int LuaSlurp(lua_State *L) { - char *p, *f; - size_t n; - f = luaL_checkstring(L, 1); - if ((p = xslurp(f, &n))) { - lua_pushlstring(L, p, n); - free(p); - return 1; - } else { - lua_pushnil(L); - lua_pushstring(L, gc(xasprintf("Can't slurp file %`'s: %m", f))); - return 2; - } -} - -static int LuaIndentLines(lua_State *L) { - void *p; - size_t n, j; - p = luaL_checklstring(L, 1, &n); - j = luaL_optinteger(L, 2, 1); - if (!(0 <= j && j <= 65535)) { - luaL_argerror(L, 2, "not in range 0..65535"); - unreachable; - } - p = IndentLines(p, n, &n, j); - lua_pushlstring(L, p, n); - free(p); - return 1; -} - -static int LuaGetMonospaceWidth(lua_State *L) { - int w; - if (lua_isinteger(L, 1)) { - w = wcwidth(lua_tointeger(L, 1)); - } else if (lua_isstring(L, 1)) { - w = strwidth(luaL_checkstring(L, 1), luaL_optinteger(L, 2, 0) & 7); - } else { - luaL_argerror(L, 1, "not integer or string"); - unreachable; - } - lua_pushinteger(L, w); - return 1; -} - -static int LuaPopcnt(lua_State *L) { - lua_pushinteger(L, popcnt(luaL_checkinteger(L, 1))); - return 1; -} - -static int LuaBsr(lua_State *L) { - long x; - if ((x = luaL_checkinteger(L, 1))) { - lua_pushinteger(L, bsr(x)); - return 1; - } else { - luaL_argerror(L, 1, "zero"); - unreachable; - } -} - -static int LuaBsf(lua_State *L) { - long x; - if ((x = luaL_checkinteger(L, 1))) { - lua_pushinteger(L, bsf(x)); - return 1; - } else { - luaL_argerror(L, 1, "zero"); - unreachable; - } -} - -static int LuaHash(lua_State *L, uint32_t H(uint32_t, const void *, size_t)) { - long i; - size_t n; - const char *p; - i = luaL_checkinteger(L, 1); - p = luaL_checklstring(L, 2, &n); - lua_pushinteger(L, H(i, p, n)); - return 1; -} - -static int LuaCrc32(lua_State *L) { - return LuaHash(L, crc32_z); -} - -static int LuaCrc32c(lua_State *L) { - return LuaHash(L, crc32c); -} - static dontinline int LuaProgramInt(lua_State *L, void P(long)) { P(luaL_checkinteger(L, 1)); return 0; @@ -4921,7 +4515,7 @@ static int LuaProgramPort(lua_State *L) { } static int LuaProgramCache(lua_State *L) { - OnlyCallFromInitLua(L, "ProgramCache"); + OnlyCallFromMainProcess(L, "ProgramCache"); return LuaProgramInt(L, ProgramCache); } @@ -4940,6 +4534,18 @@ static int LuaProgramGid(lua_State *L) { return LuaProgramInt(L, ProgramGid); } +static int LuaGetClientFd(lua_State *L) { + OnlyCallDuringConnection(L, "GetClientFd"); + lua_pushinteger(L, client); + return 1; +} + +static int LuaIsClientUsingSsl(lua_State *L) { + OnlyCallDuringConnection(L, "IsClientUsingSsl"); + lua_pushboolean(L, usessl); + return 1; +} + static int LuaProgramSslTicketLifetime(lua_State *L) { OnlyCallFromInitLua(L, "ProgramSslTicketLifetime"); return LuaProgramInt(L, ProgramSslTicketLifetime); @@ -4947,9 +4553,9 @@ static int LuaProgramSslTicketLifetime(lua_State *L) { static int LuaProgramUniprocess(lua_State *L) { OnlyCallFromInitLua(L, "ProgramUniprocess"); - if (!lua_isboolean(L, 1) && !lua_isnoneornil(L, 1)) + if (!lua_isboolean(L, 1) && !lua_isnoneornil(L, 1)) { return luaL_argerror(L, 1, "invalid uniprocess mode; boolean expected"); - + } lua_pushboolean(L, uniprocess); if (lua_isboolean(L, 1)) uniprocess = lua_toboolean(L, 1); return 1; @@ -4966,7 +4572,7 @@ static int LuaProgramAddr(lua_State *L) { } static int LuaProgramBrand(lua_State *L) { - OnlyCallFromInitLua(L, "ProgramBrand"); + OnlyCallFromMainProcess(L, "ProgramBrand"); return LuaProgramString(L, ProgramBrand); } @@ -4988,7 +4594,7 @@ static int LuaProgramSslPresharedKey(lua_State *L) { struct Psk psk; size_t n1, n2, i; const char *p1, *p2; - OnlyCallFromInitLua(L, "ProgramSslPresharedKey"); + OnlyCallFromMainProcess(L, "ProgramSslPresharedKey"); p1 = luaL_checklstring(L, 1, &n1); p2 = luaL_checklstring(L, 2, &n2); if (!n1 || n1 > MBEDTLS_PSK_MAX_LEN || !n2) { @@ -5016,6 +4622,7 @@ static int LuaProgramSslPresharedKey(lua_State *L) { static int LuaProgramSslCiphersuite(lua_State *L) { mbedtls_ssl_ciphersuite_t *suite; + OnlyCallFromInitLua(L, "ProgramSslCiphersuite"); if (!(suite = GetCipherSuite(luaL_checkstring(L, 1)))) { luaL_argerror(L, 1, "unsupported or unknown ciphersuite"); unreachable; @@ -5071,11 +4678,12 @@ static int LuaProgramSslClientVerify(lua_State *L) { } static int LuaProgramSslFetchVerify(lua_State *L) { - OnlyCallFromInitLua(L, "ProgramSslFetchVerify"); + OnlyCallFromMainProcess(L, "ProgramSslFetchVerify"); return LuaProgramBool(L, &sslfetchverify); } static int LuaProgramSslInit(lua_State *L) { + OnlyCallFromInitLua(L, "SslInit"); TlsInit(); return 0; } @@ -5089,7 +4697,6 @@ static int LuaProgramLogBodies(lua_State *L) { } static int LuaEvadeDragnetSurveillance(lua_State *L) { - OnlyCallFromInitLua(L, "EvadeDragnetSurveillance"); return LuaProgramBool(L, &evadedragnetsurveillance); } @@ -5101,16 +4708,6 @@ static int LuaProgramSslCompression(lua_State *L) { return 0; } -static int LuaGetLogLevel(lua_State *L) { - lua_pushinteger(L, __log_level); - return 1; -} - -static int LuaSetLogLevel(lua_State *L) { - __log_level = luaL_checkinteger(L, 1); - return 0; -} - static int LuaHidePath(lua_State *L) { size_t pathlen; const char *path; @@ -5119,35 +4716,6 @@ static int LuaHidePath(lua_State *L) { return 0; } -static int LuaLog(lua_State *L) { - int level, line; - lua_Debug ar; - const char *msg, *module; - level = luaL_checkinteger(L, 1); - if (LOGGABLE(level)) { - msg = luaL_checkstring(L, 2); - if (lua_getstack(L, 1, &ar) && lua_getinfo(L, "Sl", &ar)) { - module = ar.short_src; - line = ar.currentline; - } else { - module = gc(strndup(effectivepath.p, effectivepath.n)); - line = -1; - } - flogf(level, module, line, NULL, "%s", msg); - } - return 0; -} - -static int LuaSleep(lua_State *L) { - usleep(1e6 * luaL_checknumber(L, 1)); - return 0; -} - -static int LuaGetTime(lua_State *L) { - lua_pushnumber(L, nowl()); - return 1; -} - static int LuaIsHiddenPath(lua_State *L) { size_t n; const char *s; @@ -5156,21 +4724,6 @@ static int LuaIsHiddenPath(lua_State *L) { return 1; } -static int LuaIsHeaderRepeatable(lua_State *L) { - int h; - bool r; - size_t n; - const char *s; - s = luaL_checklstring(L, 1, &n); - if ((h = GetHttpHeader(s, n)) != -1) { - r = kHttpRepeatable[h]; - } else { - r = false; - } - lua_pushboolean(L, r); - return 1; -} - static int LuaGetZipPaths(lua_State *L) { char *path; uint8_t *zcf; @@ -5276,31 +4829,6 @@ static int LuaGetAssetComment(lua_State *L) { return 1; } -static int LuaGetHostOs(lua_State *L) { - const char *s = NULL; - if (IsLinux()) { - s = "LINUX"; - } else if (IsMetal()) { - s = "METAL"; - } else if (IsWindows()) { - s = "WINDOWS"; - } else if (IsXnu()) { - s = "XNU"; - } else if (IsOpenbsd()) { - s = "OPENBSD"; - } else if (IsFreebsd()) { - s = "FREEBSD"; - } else if (IsNetbsd()) { - s = "NETBSD"; - } - if (s) { - lua_pushstring(L, s); - } else { - lua_pushnil(L); - } - return 1; -} - static int LuaLaunchBrowser(lua_State *L) { OnlyCallFromInitLua(L, "LaunchBrowser"); launchbrowser = strdup(luaL_optstring(L, 1, "/")); @@ -5331,75 +4859,65 @@ static bool LuaRunAsset(const char *path, bool mandatory) { return !!a; } -static int LuaRdtsc(lua_State *L) { - lua_pushinteger(L, rdtsc()); - return 1; -} - -static int LuaGetCpuNode(lua_State *L) { - lua_pushinteger(L, TSC_AUX_NODE(rdpid())); - return 1; -} - -static int LuaGetCpuCore(lua_State *L) { - lua_pushinteger(L, TSC_AUX_CORE(rdpid())); - return 1; -} - -static int LuaRand(lua_State *L, uint64_t impl(void)) { - lua_pushinteger(L, impl()); - return 1; -} - -static int LuaLemur64(lua_State *L) { - return LuaRand(L, lemur64); -} - -static int LuaRand64(lua_State *L) { - return LuaRand(L, rand64); -} - -static int LuaRdrand(lua_State *L) { - return LuaRand(L, rdrand); -} - -static int LuaRdseed(lua_State *L) { - return LuaRand(L, rdseed); -} - -static int LuaDecimate(lua_State *L) { - size_t n, m; - const char *s; - unsigned char *p; - s = luaL_checklstring(L, 1, &n); - m = ROUNDUP(n, 16); - p = xmalloc(m); - bzero(p + n, m - n); - cDecimate2xUint8x8(m, p, (signed char[8]){-1, -3, 3, 17, 17, 3, -3, -1}); - lua_pushlstring(L, (char *)p, (n + 1) >> 1); - free(p); - return 1; -} - -static int LuaMeasureEntropy(lua_State *L) { - size_t n; - const char *s; - s = luaL_checklstring(L, 1, &n); - lua_pushnumber(L, MeasureEntropy(s, n)); - return 1; -} - -static int LuaGetClientFd(lua_State *L) { - OnlyCallDuringConnection(L, "GetClientFd"); - lua_pushinteger(L, client); - return 1; -} - -static int LuaIsClientUsingSsl(lua_State *L) { - OnlyCallDuringConnection(L, "IsClientUsingSsl"); - lua_pushboolean(L, usessl); - return 1; -} +// +// list of functions that can't be run from the repl +static const char *const kDontAutoComplete[] = { + "GetBody", // + "GetClientAddr", // + "GetClientFd", // + "GetCookie", // + "GetEffectivePath", // + "GetFragment", // + "GetHeader", // + "GetHeaders", // + "GetHost", // + "GetHttpVersion", // + "GetMethod", // + "GetParam", // + "GetParams", // + "GetPass", // + "GetPath", // + "GetPort", // + "GetRemoteAddr", // + "GetScheme", // + "GetServerAddr", // + "GetSslIdentity", // + "GetStatus", // + "GetUrl", // + "GetUser", // + "HasParam", // + "IsClientUsingSsl", // + "LaunchBrowser", // + "ProgramAddr", // TODO + "ProgramBrand", // + "ProgramCertificate", // TODO + "ProgramGid", // + "ProgramLogPath", // TODO + "ProgramPidPath", // TODO + "ProgramPort", // TODO + "ProgramPrivateKey", // TODO + "ProgramSslCiphersuite", // TODO + "ProgramSslClientVerify", // TODO + "ProgramSslCompression", // + "ProgramSslTicketLifetime", // + "ProgramTimeout", // TODO + "ProgramUid", // + "ProgramUniprocess", // + "Respond", // + "Route", // + "RouteHost", // + "RoutePath", // + "ServeAsset", // + "ServeIndex", // + "ServeListing", // + "ServeRedirect", // + "ServeStatusz", // + "SetCookie", // + "SetHeader", // + "SslInit", // TODO + "Write", // +}; +// static const luaL_Reg kLuaFuncs[] = { {"Bsf", LuaBsf}, // @@ -5480,9 +4998,7 @@ static const luaL_Reg kLuaFuncs[] = { {"IsDaemon", LuaIsDaemon}, // {"IsHeaderRepeatable", LuaIsHeaderRepeatable}, // {"IsHiddenPath", LuaIsHiddenPath}, // - {"IsLoopbackClient", LuaIsLoopbackClient}, // {"IsLoopbackIp", LuaIsLoopbackIp}, // - {"IsPrivateClient", LuaIsPrivateClient}, // {"IsPrivateIp", LuaIsPrivateIp}, // {"IsPublicIp", LuaIsPublicIp}, // {"IsReasonablePath", LuaIsReasonablePath}, // @@ -5558,12 +5074,6 @@ static const luaL_Reg kLuaFuncs[] = { #endif }; -int LuaMaxmind(lua_State *); -int LuaRe(lua_State *); -int LuaUnix(lua_State *); -int luaopen_argon2(lua_State *); -int luaopen_lsqlite3(lua_State *); - static const luaL_Reg kLuaLibs[] = { {"re", LuaRe}, // {"unix", LuaUnix}, // @@ -6845,9 +6355,9 @@ static void RestoreApe(void) { struct Asset *a; extern char ape_rom_vaddr[] __attribute__((__weak__)); if (!(SUPPORT_VECTOR & (METAL | WINDOWS | XNU))) return; - if (IsWindows()) return; /* TODO */ - if (IsOpenbsd()) return; /* TODO */ - if (IsNetbsd()) return; /* TODO */ + if (IsWindows()) return; // TODO + if (IsOpenbsd()) return; // TODO + if (IsNetbsd()) return; // TODO if (endswith(zpath, ".com.dbg")) return; if ((a = GetAssetZip("/.ape", 5)) && (p = LoadAsset(a, &n))) { close(zfd); @@ -6859,6 +6369,34 @@ static void RestoreApe(void) { } } +static bool ShouldAutocomplete(const char *s) { + int c, m, l, r; + l = 0; + r = ARRAYLEN(kDontAutoComplete) - 1; + while (l <= r) { + m = (l + r) >> 1; + c = strcmp(kDontAutoComplete[m], s); + if (c < 0) { + l = m + 1; + } else if (c > 0) { + r = m - 1; + } else { + return false; + } + } + return true; +} + +static void HandleCompletions(const char *p, linenoiseCompletions *c) { + size_t i, j; + for (j = i = 0; i < c->len; ++i) { + if (ShouldAutocomplete(c->cvec[i])) { + c->cvec[j++] = c->cvec[i]; + } + } + c->len = j; +} + static int HandleReadline(void) { int status; for (;;) { @@ -6871,9 +6409,8 @@ static int HandleReadline(void) { return -1; } else if (errno == EINTR) { errno = 0; - OnInt(SIGINT); INFOF("got repl interrupt"); - return 0; + return -1; } else if (errno == EAGAIN) { errno = 0; return 0; @@ -6884,7 +6421,7 @@ static int HandleReadline(void) { } write(1, "\r\n", 2); linenoiseDisableRawMode(); - _spinlock(&lualock); + LUA_REPL_LOCK; if (status == LUA_OK) { status = lua_runchunk(GL, 0, LUA_MULTRET); } @@ -6893,7 +6430,7 @@ static int HandleReadline(void) { } else { lua_report(GL, status); } - _spunlock(&lualock); + LUA_REPL_UNLOCK; if (lua_repl_isterminal) { linenoiseEnableRawMode(0); } @@ -6911,21 +6448,24 @@ static int HandlePoll(int ms) { if (polls[pollid].fd < 0) continue; if (polls[pollid].fd) { // handle listen socket + LUA_REPL_LOCK; serverid = pollid - 1; assert(0 <= serverid && serverid < servers.n); serveraddr = &servers.p[serverid].addr; ishandlingconnection = true; - _spinlock(&lualock); rc = HandleConnection(serverid); - _spunlock(&lualock); ishandlingconnection = false; + LUA_REPL_UNLOCK; if (rc == -1) return -1; +#ifndef STATIC } else { // handle standard input rc = HandleReadline(); if (rc == -1) return rc; +#endif } } +#ifndef STATIC } else if (__replmode) { // handle refresh repl line if (!IsWindows()) { @@ -6934,6 +6474,7 @@ static int HandlePoll(int ms) { } else { linenoiseRefreshLine(lua_repl_linenoise); } +#endif } } else { if (errno == EINTR || errno == EAGAIN) { @@ -7029,16 +6570,22 @@ static void HandleShutdown(void) { // this function coroutines with linenoise static int EventLoop(int ms) { long double t; - VERBOSEF("EventLoop()"); + DEBUGF("EventLoop()"); while (!terminated) { errno = 0; if (zombied) { + LUA_REPL_LOCK; ReapZombies(); + LUA_REPL_UNLOCK; } else if (invalidated) { + LUA_REPL_LOCK; HandleReload(); + LUA_REPL_UNLOCK; invalidated = false; } else if (meltdown) { + LUA_REPL_LOCK; EnterMeltdownMode(); + LUA_REPL_UNLOCK; meltdown = false; } else if ((t = nowl()) - lastheartbeat > HEARTBEAT / 1000.) { lastheartbeat = t; @@ -7053,6 +6600,7 @@ static int EventLoop(int ms) { static void ReplEventLoop(void) { DEBUGF("ReplEventLoop()"); polls[0].fd = 0; + lua_repl_completions_callback = HandleCompletions; lua_initrepl(GL, "redbean"); if (lua_repl_isterminal) { linenoiseEnableRawMode(0); @@ -7065,8 +6613,10 @@ static void ReplEventLoop(void) { } static uint32_t WindowsReplThread(void *arg) { + int sig; DEBUGF("WindowsReplThread()"); lua_repl_blocking = true; + lua_repl_completions_callback = HandleCompletions; lua_initrepl(GL, "redbean"); if (lua_repl_isterminal) { linenoiseEnableRawMode(0); @@ -7078,9 +6628,13 @@ static uint32_t WindowsReplThread(void *arg) { } linenoiseDisableRawMode(); lua_freerepl(); - _spinlock(&lualock); + LUA_REPL_LOCK; lua_settop(GL, 0); // clear stack - _spunlock(&lualock); + LUA_REPL_UNLOCK; + if ((sig = linenoiseGetInterrupt())) { + raise(sig); + } + DEBUGF("WindowsReplThread() exiting"); return 0; } @@ -7296,7 +6850,7 @@ void RedBean(int argc, char *argv[]) { #else GetHostsTxt(); // for effect GetResolvConf(); // for effect - if (daemonize || !linenoiseIsTerminal()) { + if (daemonize || uniprocess || !linenoiseIsTerminal()) { EventLoop(HEARTBEAT); } else if (IsWindows()) { uint32_t tid; diff --git a/tool/plinko/lib/gc.c b/tool/plinko/lib/gc.c index 0b270d740..6e12485d8 100644 --- a/tool/plinko/lib/gc.c +++ b/tool/plinko/lib/gc.c @@ -50,7 +50,7 @@ struct Gc *NewGc(int A) { if (B < cHeap) cHeap = B; n = ROUNDUP(A - B, DWBITS) / DWBITS; G = Addr(BANE); - memset(G->M, 0, n * sizeof(G->M[0])); + bzero(G->M, n * sizeof(G->M[0])); G->n = n; G->A = A; G->B = B; diff --git a/tool/viz/bin2asm.c b/tool/viz/bin2asm.c index 7af7011db..4e2e19457 100644 --- a/tool/viz/bin2asm.c +++ b/tool/viz/bin2asm.c @@ -28,7 +28,7 @@ int main(int argc, char *argv[]) { while ((c = getchar()) != -1) { if (col == 0) { printf("\t.byte\t"); - memset(glyphs, 0, sizeof(glyphs)); + bzero(glyphs, sizeof(glyphs)); } ch = c & 0xff; glyphs[col] = kCp437[ch]; diff --git a/tool/viz/derasterize.c b/tool/viz/derasterize.c index 45f5115ae..ed08c6fe4 100644 --- a/tool/viz/derasterize.c +++ b/tool/viz/derasterize.c @@ -248,7 +248,7 @@ static unsigned combinecolors(unsigned char bf[1u << MC][2], const unsigned char bl[CN][YS * XS]) { uint64_t hv, ht[(1u << MC) * 2]; unsigned i, j, n, b, f, h, hi, bu, fu; - memset(ht, 0, sizeof(ht)); + bzero(ht, sizeof(ht)); for (n = b = 0; b < BN && n < (1u << MC); ++b) { bu = bl[2][b] << 020 | bl[1][b] << 010 | bl[0][b]; hi = 0; @@ -295,7 +295,7 @@ static unsigned combinecolors(unsigned char bf[1u << MC][2], const float lb[CN][YS * XS]) { \ unsigned i, k, gu; \ float p[BN], q[BN], fu, bu, r; \ - memset(q, 0, sizeof(q)); \ + bzero(q, sizeof(q)); \ for (k = 0; k < CN; ++k) { \ gu = kGlyphs[g]; \ bu = lb[k][b]; \ @@ -336,7 +336,7 @@ static float adjudicate(unsigned b, unsigned f, unsigned g, const float lb[CN][YS * XS]) { unsigned i, k, gu; float p[BN], q[BN], fu, bu, r; - memset(q, 0, sizeof(q)); + bzero(q, sizeof(q)); for (k = 0; k < CN; ++k) { gu = kGlyphs[g]; bu = lb[k][b]; @@ -487,8 +487,8 @@ static void LoadFileViaImageMagick(const char *path, unsigned yn, unsigned xn, unsigned char rgb[yn][YS][xn][XS][CN]) { const char *convert; int pid, ws, pipefds[2]; - char pathbuf[PATH_MAX], dim[32]; - if (!(convert = commandv("convert", pathbuf))) { + char pathbuf[PATH_MAX + 1], dim[32]; + if (!(convert = commandv("convert", pathbuf, sizeof(pathbuf)))) { fputs("error: `convert` command not found\n" "try: apt-get install imagemagick\n", stderr); diff --git a/tool/viz/lib/bilinearscale.c b/tool/viz/lib/bilinearscale.c index 7836787cc..edfa5b077 100644 --- a/tool/viz/lib/bilinearscale.c +++ b/tool/viz/lib/bilinearscale.c @@ -93,7 +93,7 @@ void *BilinearScale(long dcw, long dyw, long dxw, gc(xmemalign(64, ROUNDUP(dxn, 64))), gc(xmemalign(64, ROUNDUP(sxn, 64) * 2))); } else { - memset(dst[c0], 0, &dst[cn][0][0] - &dst[c0][0][0]); + bzero(dst[c0], &dst[cn][0][0] - &dst[c0][0][0]); } } return dst; diff --git a/tool/viz/lib/convolve.h b/tool/viz/lib/convolve.h index 66ca31813..892af17f3 100644 --- a/tool/viz/lib/convolve.h +++ b/tool/viz/lib/convolve.h @@ -19,12 +19,12 @@ forceinline void convolve(unsigned yn, unsigned xn, __m128 img[yn][xn], int KW, kflip[KW - i - 1][KW - j - 1] = (__v4sf){f, f, f, f}; } } - memset(&g, 0, sizeof(g)); + bzero(&g, sizeof(g)); resizegraphic(&g, yn, xn); tmp = g.b.p; for (y = 0; y < yn - KW; ++y) { for (x = 0; x < xn - KW; ++x) { - memset(&p, 0, sizeof(p)); + bzero(&p, sizeof(p)); for (i = 0; i < KW; ++i) { for (j = 0; j < KW; ++j) { p += img[y + i][x + j] * kflip[i][j] + C2; diff --git a/tool/viz/lib/unsharp.c b/tool/viz/lib/unsharp.c index 56cfbe3ae..db1932c91 100644 --- a/tool/viz/lib/unsharp.c +++ b/tool/viz/lib/unsharp.c @@ -45,7 +45,7 @@ long unsharp(long cn, long yw, long xw, unsigned char img[cn][yw][xw], long yn, for (x = 0; x < xn; ++x) { img[c][y - 3][x] = MIN(255, MAX(0, (*t)[y % 3][x])); } - memset((*t)[y % 3], 0, sizeof(short) * xn); + bzero((*t)[y % 3], sizeof(short) * xn); } if (y < yn) { for (x = 0; x < xn; ++x) { diff --git a/tool/viz/lib/ycbcr2rgb3.c b/tool/viz/lib/ycbcr2rgb3.c index 806d8824b..9d1df4c04 100644 --- a/tool/viz/lib/ycbcr2rgb3.c +++ b/tool/viz/lib/ycbcr2rgb3.c @@ -155,8 +155,8 @@ void YCbCrInit(struct YCbCr **ycbcr, bool yonly, int swing, double gamma, const double gamut[3], const double illuminant[3]) { if (!*ycbcr) *ycbcr = xcalloc(1, sizeof(struct YCbCr)); (*ycbcr)->yonly = yonly; - memset((*ycbcr)->magnums, 0, sizeof((*ycbcr)->magnums)); - memset((*ycbcr)->lighting, 0, sizeof((*ycbcr)->lighting)); + bzero((*ycbcr)->magnums, sizeof((*ycbcr)->magnums)); + bzero((*ycbcr)->lighting, sizeof((*ycbcr)->lighting)); YCbCrComputeCoefficients(swing, gamma, gamut, illuminant, (*ycbcr)->magnums, (*ycbcr)->lighting, (*ycbcr)->transfer[0]); imapxlatab((*ycbcr)->transfer[1]); diff --git a/tool/viz/life.c b/tool/viz/life.c index a648022b3..0b984ab13 100644 --- a/tool/viz/life.c +++ b/tool/viz/life.c @@ -612,7 +612,7 @@ static int LoadFile(const char *path) { } if (yn > byn || xn > bxn) goto ReadError; xchg(&board, &board2); - memset(board, 0, (byn * bxn) >> 3); + bzero(board, (byn * bxn) >> 3); yo = byn / 2 - yn / 2; xo = bxn / 2 - xn / 2; y = 0; @@ -857,7 +857,7 @@ static void Rando2(void) { static void ReadKeyboard(void) { char buf[32], *p = buf; - memset(buf, 0, sizeof(buf)); + bzero(buf, sizeof(buf)); if (readansi(0, buf, sizeof(buf)) == -1) { if (errno == EINTR) return; exit(errno); @@ -895,7 +895,7 @@ static void ReadKeyboard(void) { } break; case 'R': - memset(board, 0, (byn * bxn) >> 3); + bzero(board, (byn * bxn) >> 3); break; case CTRL('T'): OnTurbo(); @@ -1166,7 +1166,7 @@ static void OnMenuOpen(int64_t hwnd) { char buf8[PATH_MAX]; char16_t buf16[PATH_MAX]; struct NtOpenFilename ofn; - memset(&ofn, 0, sizeof(ofn)); + bzero(&ofn, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = hwnd; ofn.lpstrFile = buf16; @@ -1370,7 +1370,7 @@ static void Gui(void) { int64_t hwnd, mh; struct NtMsg msg; struct NtWndClass wc; - memset(&wc, 0, sizeof(wc)); + bzero(&wc, sizeof(wc)); wc.lpfnWndProc = NT2SYSV(WindowProc); wc.hInstance = GetModuleHandle(NULL); wc.hCursor = LoadCursor(0, kNtIdcCross); diff --git a/tool/viz/magikarp.c b/tool/viz/magikarp.c index 3cba134aa..920490d10 100644 --- a/tool/viz/magikarp.c +++ b/tool/viz/magikarp.c @@ -192,7 +192,7 @@ static void *MagikarpY(CHAR w, unsigned char p[1u << w][1u << w], char yw, long y, x, yn, xn, ym; unsigned char(*t)[(1u << w) + 2][1u << w]; t = memalign(64, ((1u << w) + 2) * (1u << w)); - memset(t, 0, ((1u << w) + 2) * (1u << w)); + bzero(t, ((1u << w) + 2) * (1u << w)); yn = 1u << yw; xn = 1u << xw; ym = yn >> 1; diff --git a/tool/viz/memzoom.c b/tool/viz/memzoom.c index 4f16e59d9..8793f8776 100644 --- a/tool/viz/memzoom.c +++ b/tool/viz/memzoom.c @@ -496,7 +496,7 @@ static void OnMouse(char *p) { static void ReadKeyboard(void) { char buf[32], *p = buf; - memset(buf, 0, sizeof(buf)); + bzero(buf, sizeof(buf)); if (readansi(0, buf, sizeof(buf)) == -1) { if (errno == EINTR) return; exit(errno); @@ -797,7 +797,7 @@ static void Zoom(long have) { n >>= 1; } if (n < tyn * txn) { - memset(canvas + n, 0, canvassize - n); + bzero(canvas + n, canvassize - n); } if (have != -1) { n = have >> zoom; @@ -817,7 +817,7 @@ static void FileZoom(void) { have = MIN(displaysize, size - offset); have = pread(fd, canvas, have, offset); have = MAX(0, have); - memset(canvas + have, 0, canvassize - have); + bzero(canvas + have, canvassize - have); Zoom(have); Render(); } diff --git a/tool/viz/printdos2errno.c b/tool/viz/printdos2errno.c index 498c89862..87f88fccf 100644 --- a/tool/viz/printdos2errno.c +++ b/tool/viz/printdos2errno.c @@ -26,11 +26,11 @@ int main(int argc, char *argv[]) { int i; for (i = 0; kDos2Errno[i].doscode; ++i) { - kprintf("dos error %10hu maps to rva %10d errno %10d which is %s%n", - kDos2Errno[i].doscode, kDos2Errno[i].systemv, - *(const int *)((intptr_t)kDos2Errno + kDos2Errno[i].systemv), - strerror_short( - *(const int *)((intptr_t)kDos2Errno + kDos2Errno[i].systemv))); + kprintf( + "dos error %10hu maps to rva %10d errno %10d which is %s%n", + kDos2Errno[i].doscode, kDos2Errno[i].systemv, + *(const int *)((intptr_t)kDos2Errno + kDos2Errno[i].systemv), + strerrno(*(const int *)((intptr_t)kDos2Errno + kDos2Errno[i].systemv))); } return 0; }