diff --git a/ape/ape.mk b/ape/ape.mk index 8e8b2d1d0..40739d700 100644 --- a/ape/ape.mk +++ b/ape/ape.mk @@ -197,25 +197,25 @@ o/$(MODE)/ape/loader-xnu-clang.asm: ape/loader.c o/$(MODE)/ape/ape.elf: o/$(MODE)/ape/ape.elf.dbg o/$(MODE)/ape/ape.macho: o/$(MODE)/ape/ape.macho.dbg -o/$(MODE)/ape/ape.elf.dbg: private \ - LDFLAGS += \ - -z common-page-size=0x10 \ - -z max-page-size=0x10 +APE_LOADER_LDFLAGS = \ + -static \ + -no-pie \ + -nostdlib \ + --no-dynamic-linker \ + -zcommon-page-size=0x1000 \ + -zmax-page-size=0x1000 + o/$(MODE)/ape/ape.elf.dbg: \ o/$(MODE)/ape/loader.o \ o/$(MODE)/ape/loader-elf.o \ ape/loader.lds - @$(ELFLINK) + @$(COMPILE) -ALINK.elf $(LINK) -T ape/loader.lds $(APE_LOADER_LDFLAGS) -o $@ o/$(MODE)/ape/loader-elf.o o/$(MODE)/ape/loader.o -o/$(MODE)/ape/ape.macho.dbg: private \ - LDFLAGS += \ - -z common-page-size=0x10 \ - -z max-page-size=0x10 o/$(MODE)/ape/ape.macho.dbg: \ o/$(MODE)/ape/loader-xnu.o \ o/$(MODE)/ape/loader-macho.o \ ape/loader.lds - @$(ELFLINK) + @$(COMPILE) -ALINK.elf $(LINK) -T ape/loader.lds $(APE_LOADER_LDFLAGS) -o $@ o/$(MODE)/ape/loader-macho.o o/$(MODE)/ape/loader-xnu.o .PHONY: o/$(MODE)/ape o/$(MODE)/ape: $(APE_CHECKS) \ diff --git a/ape/apeinstall.sh b/ape/apeinstall.sh index 334ed2778..7744420aa 100755 --- a/ape/apeinstall.sh +++ b/ape/apeinstall.sh @@ -12,13 +12,8 @@ echo "Author: Justine Tunney " >&2 ################################################################################ # INSTALL APE LOADER SYSTEMWIDE -if [ -f o/depend ]; then - # mkdeps.com build was successfully run so assume we can build - echo >&2 - echo "recompiling ape loader" >&2 - echo "running: make -j8 o//ape" >&2 - make -j8 o//ape || exit - echo "done" >&2 +if [ -f o/depend ] && make -j8 o//ape; then + echo "successfully recompiled ape loader" >&2 elif [ -d build/bootstrap ]; then # if make isn't being used then it's unlikely the user changed the sources # in that case the prebuilt binaries should be completely up-to-date diff --git a/ape/loader.c b/ape/loader.c index 103775969..5de00f11f 100644 --- a/ape/loader.c +++ b/ape/loader.c @@ -77,12 +77,18 @@ * @note this can probably be used as a binfmt_misc interpreter */ +#define PAGE_SIZE 4096 +#define NULL_PAGE 2097152 + #define LINUX 1 #define XNU 8 #define OPENBSD 16 #define FREEBSD 32 #define NETBSD 64 +#define MIN(X, Y) ((Y) > (X) ? (X) : (Y)) +#define MAX(X, Y) ((Y) < (X) ? (X) : (Y)) + #define SupportsLinux() (SUPPORT_VECTOR & LINUX) #define SupportsXnu() (SUPPORT_VECTOR & XNU) #define SupportsFreebsd() (SUPPORT_VECTOR & FREEBSD) @@ -103,29 +109,29 @@ #define MAP_PRIVATE 2 #define MAP_FIXED 16 #define MAP_ANONYMOUS (IsLinux() ? 32 : 4096) -#define AT_EXECFN_LINUX 31 -#define AT_EXECFN_NETBSD 2014 #define ELFCLASS32 1 #define ELFDATA2LSB 1 #define EM_NEXGEN32E 62 #define ET_EXEC 2 #define PT_LOAD 1 #define PT_DYNAMIC 2 +#define PT_INTERP 3 #define EI_CLASS 4 #define EI_DATA 5 #define PF_X 1 #define PF_W 2 #define PF_R 4 +#define AT_PHDR 3 +#define AT_PHENT 4 +#define AT_PHNUM 5 +#define AT_EXECFN_LINUX 31 +#define AT_EXECFN_NETBSD 2014 #define X_OK 1 #define XCR0_SSE 2 #define XCR0_AVX 4 #define PR_SET_MM 35 #define PR_SET_MM_EXE_FILE 13 -#define Min(X, Y) ((Y) > (X) ? (X) : (Y)) -#define Roundup(X, K) (((X) + (K)-1) & -(K)) -#define Rounddown(X, K) ((X) & -(K)) - #define Read32(S) \ ((unsigned)(255 & (S)[3]) << 030 | (unsigned)(255 & (S)[2]) << 020 | \ (unsigned)(255 & (S)[1]) << 010 | (unsigned)(255 & (S)[0]) << 000) @@ -190,16 +196,14 @@ struct ApeLoader { union ElfEhdrBuf ehdr; union ElfPhdrBuf phdr; struct PathSearcher ps; + char path[1024]; }; -long SystemCall(long arg1, // - long arg2, // - long arg3, // - long arg4, // - long arg5, // - long arg6, // - long arg7, // - long magi); +long SystemCall(long arg1, long arg2, long arg3, long arg4, long arg5, + long arg6, long arg7, long magi); + +extern char __executable_start[]; +extern char _end[]; static int ToLower(int c) { return 'A' <= c && c <= 'Z' ? c + ('a' - 'A') : c; @@ -300,7 +304,7 @@ static long Pread(int fd, void *data, unsigned long size, long off, int os) { } else if (IsFreebsd()) { magi = 0x1db; } else if (IsOpenbsd()) { - magi = 0x0a9; // OpenBSD v7.3+ + magi = 0x0a9; /* OpenBSD v7.3+ */ } else if (IsNetbsd()) { magi = 0x0ad; } else { @@ -337,6 +341,11 @@ static int Open(const char *path, int flags, int mode, int os) { (IsLinux() ? 2 : 5) | (IsXnu() ? 0x2000000 : 0)); } +static int Mprotect(void *addr, unsigned long size, int prot, int os) { + return SystemCall((long)addr, size, prot, 0, 0, 0, 0, + (IsLinux() ? 10 : 74) | (IsXnu() ? 0x2000000 : 0)); +} + static long Mmap(void *addr, unsigned long size, int prot, int flags, int fd, long off, int os) { long magi; @@ -347,7 +356,7 @@ static long Mmap(void *addr, unsigned long size, int prot, int flags, int fd, } else if (IsFreebsd()) { magi = 477; } else if (IsOpenbsd()) { - magi = 49; // OpenBSD v7.3+ + magi = 49; /* OpenBSD v7.3+ */ } else if (IsNetbsd()) { magi = 197; } else { @@ -480,15 +489,26 @@ __attribute__((__noreturn__)) static void Spawn(int os, const char *exe, int fd, long *sp, struct ElfEhdr *e, struct ElfPhdr *p) { long rc; - int prot, flags; + int prot; + int flags; + int found_code; + int found_entry; long code, codesize; - unsigned long a, b, i; + unsigned long a, b, c, d, i, j; + /* load elf */ code = 0; codesize = 0; - for (i = e->e_phnum; i--;) { + found_code = 0; + found_entry = 0; + for (i = 0; i < e->e_phnum; ++i) { + + /* validate program header */ + if (p[i].p_type == PT_INTERP) { + Pexit(os, exe, 0, "ELF has PT_INTERP which is unsupported"); + } if (p[i].p_type == PT_DYNAMIC) { - Pexit(os, exe, 0, "not a static executable"); + Pexit(os, exe, 0, "ELF has PT_DYNAMIC which is unsupported"); } if (p[i].p_type != PT_LOAD) { continue; @@ -496,12 +516,39 @@ __attribute__((__noreturn__)) static void Spawn(int os, const char *exe, int fd, if (!p[i].p_memsz) { continue; } - if (p[i].p_vaddr & 4095) { - Pexit(os, exe, 0, "APE phdr addr must be 4096-aligned"); + if (p[i].p_filesz > p[i].p_memsz) { + Pexit(os, exe, 0, "ELF phdr filesz exceeds memsz"); } - if (p[i].p_offset & 4095) { - Pexit(os, exe, 0, "APE phdr offset must be 4096-aligned"); + if ((p[i].p_vaddr & (PAGE_SIZE - 1)) != (p[i].p_offset & (PAGE_SIZE - 1))) { + Pexit(os, exe, 0, "ELF phdr virt/off skew mismatch w.r.t. pagesize"); } + if (p[i].p_vaddr + p[i].p_memsz < p[i].p_vaddr || + p[i].p_vaddr + p[i].p_memsz + (PAGE_SIZE - 1) < p[i].p_vaddr) { + Pexit(os, exe, 0, "ELF phdr vaddr+memsz overflow"); + } + if (p[i].p_vaddr + p[i].p_filesz < p[i].p_vaddr || + p[i].p_vaddr + p[i].p_filesz + (PAGE_SIZE - 1) < p[i].p_vaddr) { + Pexit(os, exe, 0, "ELF phdr vaddr+files overflow"); + } + a = p[i].p_vaddr & -PAGE_SIZE; + b = (p[i].p_vaddr + p[i].p_memsz + (PAGE_SIZE - 1)) & -PAGE_SIZE; + if (MAX(a, 0) < MIN(b, NULL_PAGE)) { + Pexit(os, exe, 0, "ELF overlaps NULL page"); + } + if (MAX(a, (unsigned long)__executable_start) < + MIN(b, (unsigned long)_end)) { + Pexit(os, exe, 0, "ELF overlaps your APE loader"); + } + for (j = i + 1; j < e->e_phnum; ++j) { + if (p[j].p_type != PT_LOAD) continue; + c = p[j].p_vaddr & -PAGE_SIZE; + d = (p[j].p_vaddr + p[j].p_memsz + (PAGE_SIZE - 1)) & -PAGE_SIZE; + if (MAX(a, c) < MIN(b, d)) { + Pexit(os, exe, 0, "ELF overlaps its own vaspace"); + } + } + + /* configure mapping */ prot = 0; flags = MAP_FIXED | MAP_PRIVATE; if (p[i].p_flags & PF_R) { @@ -512,47 +559,76 @@ __attribute__((__noreturn__)) static void Spawn(int os, const char *exe, int fd, } if (p[i].p_flags & PF_X) { prot |= PROT_EXEC; - code = p[i].p_vaddr; - codesize = p[i].p_filesz; + if (!found_code) { + code = p[i].p_vaddr; + codesize = p[i].p_filesz; + } + if (p[i].p_vaddr <= e->e_entry && + e->e_entry < p[i].p_vaddr + p[i].p_memsz) { + found_entry = 1; + } } + + /* load from file */ if (p[i].p_filesz) { - if ((rc = Mmap((void *)p[i].p_vaddr, p[i].p_filesz, prot, flags, fd, - p[i].p_offset, os)) < 0) { - Pexit(os, exe, rc, "image mmap"); + void *addr; + unsigned long size; + int dirty, prot1, prot2; + dirty = 0; + prot1 = prot; + prot2 = prot; + a = p[i].p_vaddr + p[i].p_filesz; + b = (a + (PAGE_SIZE - 1)) & -PAGE_SIZE; + c = p[i].p_vaddr + p[i].p_memsz; + if (b > c) b = c; + if (c > b) { + dirty = 1; + if (~prot1 & PROT_WRITE) { + prot1 = PROT_READ | PROT_WRITE; + } } - if ((a = Min(-p[i].p_filesz & 4095, p[i].p_memsz - p[i].p_filesz))) { - MemSet((void *)(p[i].p_vaddr + p[i].p_filesz), 0, a); + addr = (void *)(p[i].p_vaddr & -PAGE_SIZE); + size = (p[i].p_vaddr & (PAGE_SIZE - 1)) + p[i].p_filesz; + rc = Mmap(addr, size, prot1, flags, fd, p[i].p_offset & -PAGE_SIZE, os); + if (rc < 0) Pexit(os, exe, rc, "prog mmap"); + if (dirty) MemSet((void *)a, 0, b - a); + if (prot2 != prot1) { + rc = Mprotect(addr, size, prot2, os); + if (rc < 0) Pexit(os, exe, rc, "prog mprotect"); } } - if ((b = Roundup(p[i].p_memsz, 4096)) > - (a = Roundup(p[i].p_filesz, 4096))) { - if ((rc = Mmap((void *)p[i].p_vaddr + a, b - a, prot, - flags | MAP_ANONYMOUS, -1, 0, os)) < 0) { - Pexit(os, exe, rc, "bss mmap"); - } + + /* allocate extra bss */ + a = p[i].p_vaddr + p[i].p_filesz; + a = (a + (PAGE_SIZE - 1)) & -PAGE_SIZE; + b = p[i].p_vaddr + p[i].p_memsz; + if (b > a) { + rc = Mmap((void *)a, b - a, prot, flags | MAP_ANONYMOUS, 0, 0, os); + if (rc < 0) Pexit(os, exe, rc, "bss mmap"); } } - if (!code) { - Pexit(os, exe, 0, "ELF needs PT_LOAD phdr w/ PF_X"); - } + /* finish up */ + if (!found_entry) { + Pexit(os, exe, 0, "ELF entrypoint not found in PT_LOAD with PF_X"); + } Close(fd, os); Msyscall(code, codesize, os); - // we clear all the general registers we can to have some wiggle room - // to extend the behavior of this loader in the future. we don't need - // to clear the xmm registers since the ape loader should be compiled - // with the -mgeneral-regs-only flag. + /* we clear all the general registers we can to have some wiggle room + to extend the behavior of this loader in the future. we don't need + to clear the xmm registers since the ape loader should be compiled + with the -mgeneral-regs-only flag. */ asm volatile("xor\t%%eax,%%eax\n\t" "xor\t%%r8d,%%r8d\n\t" "xor\t%%r9d,%%r9d\n\t" "xor\t%%r10d,%%r10d\n\t" "xor\t%%r11d,%%r11d\n\t" - "xor\t%%ebx,%%ebx\n\t" // netbsd doesnt't clear this - "xor\t%%r12d,%%r12d\n\t" // netbsd doesnt't clear this - "xor\t%%r13d,%%r13d\n\t" // netbsd doesnt't clear this - "xor\t%%r14d,%%r14d\n\t" // netbsd doesnt't clear this - "xor\t%%r15d,%%r15d\n\t" // netbsd doesnt't clear this + "xor\t%%ebx,%%ebx\n\t" /* netbsd doesnt't clear this */ + "xor\t%%r12d,%%r12d\n\t" /* netbsd doesnt't clear this */ + "xor\t%%r13d,%%r13d\n\t" /* netbsd doesnt't clear this */ + "xor\t%%r14d,%%r14d\n\t" /* netbsd doesnt't clear this */ + "xor\t%%r15d,%%r15d\n\t" /* netbsd doesnt't clear this */ "mov\t%%rdx,%%rsp\n\t" "xor\t%%edx,%%edx\n\t" "push\t%%rsi\n\t" @@ -566,16 +642,30 @@ __attribute__((__noreturn__)) static void Spawn(int os, const char *exe, int fd, } static void TryElf(struct ApeLoader *M, const char *exe, int fd, long *sp, - int os) { - unsigned size; - if (Read32(M->ehdr.buf) == Read32("\177ELF") && // - M->ehdr.ehdr.e_type == ET_EXEC && // - M->ehdr.ehdr.e_machine == EM_NEXGEN32E && // - M->ehdr.ehdr.e_ident[EI_CLASS] != ELFCLASS32 && // - M->ehdr.ehdr.e_phentsize >= sizeof(M->phdr.phdr) && // - (size = (unsigned)M->ehdr.ehdr.e_phnum * M->ehdr.ehdr.e_phentsize) <= - sizeof(M->phdr.buf) && + long *auxv, int os) { + unsigned size = M->ehdr.ehdr.e_phnum; + if (Read32(M->ehdr.buf) == Read32("\177ELF") && + M->ehdr.ehdr.e_type == ET_EXEC && + M->ehdr.ehdr.e_machine == EM_NEXGEN32E && + M->ehdr.ehdr.e_ident[EI_CLASS] != ELFCLASS32 && + M->ehdr.ehdr.e_phentsize >= sizeof(M->phdr.phdr) && + (size *= M->ehdr.ehdr.e_phentsize) <= sizeof(M->phdr.buf) && Pread(fd, M->phdr.buf, size, M->ehdr.ehdr.e_phoff, os) == size) { + for (; *auxv; auxv += 2) { + switch (*auxv) { + case AT_PHDR: + auxv[1] = (unsigned long)&M->phdr; + break; + case AT_PHENT: + auxv[1] = M->ehdr.ehdr.e_phentsize; + break; + case AT_PHNUM: + auxv[1] = M->ehdr.ehdr.e_phnum; + break; + default: + break; + } + } Spawn(os, exe, fd, sp, &M->ehdr.ehdr, &M->phdr.phdr); } } @@ -588,7 +678,7 @@ __attribute__((__noreturn__)) void ApeLoader(long di, long *sp, char dl) { long *auxv, *ap, *ew; char *p, *exe, *prog, **argv, **envp; - // detect freebsd + /* detect freebsd */ if (SupportsXnu() && dl == XNU) { os = XNU; } else if (SupportsFreebsd() && di) { @@ -598,7 +688,7 @@ __attribute__((__noreturn__)) void ApeLoader(long di, long *sp, char dl) { os = 0; } - // extract arguments + /* extract arguments */ argc = *sp; argv = (char **)(sp + 1); envp = (char **)(sp + 1 + argc + 1); @@ -609,12 +699,12 @@ __attribute__((__noreturn__)) void ApeLoader(long di, long *sp, char dl) { } } - // detect openbsd + /* detect openbsd */ if (SupportsOpenbsd() && !os && !auxv[0]) { os = OPENBSD; } - // detect netbsd and find end of words + /* detect netbsd and find end of words */ for (ap = auxv; ap[0]; ap += 2) { if (SupportsNetbsd() && !os && ap[0] == AT_EXECFN_NETBSD) { os = NETBSD; @@ -622,23 +712,23 @@ __attribute__((__noreturn__)) void ApeLoader(long di, long *sp, char dl) { } ew = ap + 1; - // allocate loader memory + /* allocate loader memory */ n = sizeof(*M) / sizeof(long); MemMove(sp - n, sp, (char *)ew - (char *)sp); sp -= n, argv -= n, envp -= n, auxv -= n; M = (struct ApeLoader *)(ew - n); - // default operating system + /* default operating system */ if (!os) { os = LINUX; } - // we can load via shell, shebang, or binfmt_misc + /* we can load via shell, shebang, or binfmt_misc */ if (argc >= 3 && !StrCmp(argv[1], "-")) { - // if the first argument is a hyphen then we give the user the - // power to change argv[0] or omit it entirely. most operating - // systems don't permit the omission of argv[0] but we do, b/c - // it's specified by ANSI X3.159-1988. + /* if the first argument is a hyphen then we give the user the + power to change argv[0] or omit it entirely. most operating + systems don't permit the omission of argv[0] but we do, b/c + it's specified by ANSI X3.159-1988. */ prog = (char *)sp[3]; argc = sp[3] = sp[0] - 3; argv = (char **)((sp += 3) + 1); @@ -646,7 +736,7 @@ __attribute__((__noreturn__)) void ApeLoader(long di, long *sp, char dl) { Print(os, 2, "usage: ape PROG [ARGV1,ARGV2,...]\n" " ape - PROG [ARGV0,ARGV1,...]\n" - "αcτµαlly pδrταblε εxεcµταblε loader v1.1\n" + "αcτµαlly pδrταblε εxεcµταblε loader v1.2\n" "copyright 2022 justine alexandra roberts tunney\n" "https://justine.lol/ape.html\n", 0l); @@ -657,7 +747,7 @@ __attribute__((__noreturn__)) void ApeLoader(long di, long *sp, char dl) { argv = (char **)((sp += 1) + 1); } - // resolve path of executable and read its first page + /* resolve path of executable and read its first page */ if (!(exe = Commandv(&M->ps, os, prog, GetEnv(envp, "PATH")))) { Pexit(os, prog, 0, "not found (maybe chmod +x)"); } else if ((fd = Open(exe, O_RDONLY, 0, os)) < 0) { @@ -668,17 +758,17 @@ __attribute__((__noreturn__)) void ApeLoader(long di, long *sp, char dl) { Pexit(os, exe, 0, "too small"); } - // change argv[0] to resolved path if it's ambiguous + /* change argv[0] to resolved path if it's ambiguous */ if (argc > 0 && *prog != '/' && *exe == '/' && !StrCmp(prog, argv[0])) { argv[0] = exe; } - // ape intended behavior - // 1. if file is a native executable, try to run it natively - // 2. if ape, will scan shell script for elf printf statements - // 3. shell script may have multiple lines producing elf headers - // 4. all elf printf lines must exist in the first 4096 bytes of file - // 5. elf program headers may appear anywhere in the binary + /* ape intended behavior + 1. if file is a native executable, try to run it natively + 2. if ape, will scan shell script for elf printf statements + 3. shell script may have multiple lines producing elf headers + 4. all elf printf lines must exist in the first 4096 bytes of file + 5. elf program headers may appear anywhere in the binary */ if ((IsXnu() && Read32(M->ehdr.buf) == 0xFEEDFACE + 1) || (!IsXnu() && Read32(M->ehdr.buf) == Read32("\177ELF"))) { Close(fd, os); @@ -708,10 +798,10 @@ __attribute__((__noreturn__)) void ApeLoader(long di, long *sp, char dl) { M->ehdr.buf[i++] = c; } if (i >= sizeof(M->ehdr.ehdr)) { - TryElf(M, exe, fd, sp, os); + TryElf(M, exe, fd, sp, auxv, os); } } } - TryElf(M, exe, fd, sp, os); + TryElf(M, exe, fd, sp, auxv, os); Pexit(os, exe, 0, "Not an acceptable APE/ELF executable for x86-64"); } diff --git a/ape/loader.lds b/ape/loader.lds index 326bbfeb3..7507beec2 100644 --- a/ape/loader.lds +++ b/ape/loader.lds @@ -19,7 +19,8 @@ ENTRY(_start) SECTIONS { - . = 0x200000; + . = 0x7fff0000; + __executable_start = .; .rodata : { KEEP(*(.head)) *(.rodata .rodata.*) @@ -29,6 +30,7 @@ SECTIONS { text = .; *(.text) } + _end = .; /DISCARD/ : { *(.*) } diff --git a/build/bootstrap/ape.elf b/build/bootstrap/ape.elf index 3218e7f76..34bde40e6 100755 Binary files a/build/bootstrap/ape.elf and b/build/bootstrap/ape.elf differ diff --git a/build/bootstrap/ape.macho b/build/bootstrap/ape.macho index e29b98751..41d4aa21d 100755 Binary files a/build/bootstrap/ape.macho and b/build/bootstrap/ape.macho differ diff --git a/examples/panels.c b/examples/panels.c index 8ae42a697..8630e86a8 100644 --- a/examples/panels.c +++ b/examples/panels.c @@ -8,7 +8,6 @@ ╚─────────────────────────────────────────────────────────────────*/ #endif #include "libc/calls/calls.h" -#include "libc/calls/ioctl.h" #include "libc/calls/struct/sigaction.h" #include "libc/calls/struct/termios.h" #include "libc/calls/struct/winsize.h" diff --git a/examples/script.c b/examples/script.c index e6940d25a..c8d1d8b85 100644 --- a/examples/script.c +++ b/examples/script.c @@ -30,7 +30,6 @@ │ SUCH DAMAGE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/ioctl.h" #include "libc/calls/struct/iovec.h" #include "libc/calls/struct/stat.h" #include "libc/calls/struct/termios.h" diff --git a/examples/ttyinfo.c b/examples/ttyinfo.c index fd8b73a17..2d488148e 100644 --- a/examples/ttyinfo.c +++ b/examples/ttyinfo.c @@ -9,7 +9,6 @@ #endif #include "dsp/tty/tty.h" #include "libc/calls/calls.h" -#include "libc/calls/ioctl.h" #include "libc/calls/struct/sigaction.h" #include "libc/calls/termios.h" #include "libc/errno.h" diff --git a/libc/calls/calls.h b/libc/calls/calls.h index 4b8a1a92f..6483f340d 100644 --- a/libc/calls/calls.h +++ b/libc/calls/calls.h @@ -114,6 +114,7 @@ int getpriority(int, unsigned); int getresgid(unsigned *, unsigned *, unsigned *); int getresuid(unsigned *, unsigned *, unsigned *); int getsid(int) nosideeffect libcesque; +int ioctl(int, unsigned long, ...); int ioprio_get(int, int); int ioprio_set(int, int, int); int issetugid(void); diff --git a/libc/calls/calls.mk b/libc/calls/calls.mk index aa55d3b34..7762dd908 100644 --- a/libc/calls/calls.mk +++ b/libc/calls/calls.mk @@ -136,8 +136,6 @@ o/$(MODE)/libc/calls/mkntenvblock.o: private \ # we must segregate codegen because: # file contains multiple independently linkable apis -o/$(MODE)/libc/calls/ioctl-siocgifconf.o \ -o/$(MODE)/libc/calls/ioctl-siocgifconf-nt.o: private \ COPTS += \ -ffunction-sections \ -fdata-sections @@ -146,14 +144,7 @@ o/$(MODE)/libc/calls/ioctl-siocgifconf-nt.o: private \ # va_arg codegen is very bloated in default mode o//libc/calls/open.o \ o//libc/calls/openat.o \ -o//libc/calls/prctl.o \ -o//libc/calls/ioctl.o \ -o//libc/calls/ioctl_default.o \ -o//libc/calls/ioctl_fioclex-nt.o \ -o//libc/calls/ioctl_fioclex.o \ -o//libc/calls/ioctl_siocgifconf-nt.o \ -o//libc/calls/ioctl_siocgifconf.o \ -o//libc/calls/fcntl.o: private \ +o//libc/calls/prctl.o: \ CFLAGS += \ -Os diff --git a/libc/calls/ioctl.c b/libc/calls/ioctl.c index 82dcb029d..5e7a32beb 100644 --- a/libc/calls/ioctl.c +++ b/libc/calls/ioctl.c @@ -16,27 +16,686 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#ifdef __STRICT_ANSI__ -#undef __STRICT_ANSI__ -#endif -#include "libc/calls/ioctl.h" +#include "libc/assert.h" +#include "libc/calls/internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/termios.h" +#include "libc/dce.h" +#include "libc/errno.h" +#include "libc/intrin/bits.h" +#include "libc/intrin/cmpxchg.h" +#include "libc/intrin/strace.internal.h" +#include "libc/intrin/weaken.h" +#include "libc/macros.internal.h" +#include "libc/mem/alloca.h" +#include "libc/mem/mem.h" +#include "libc/nt/errors.h" +#include "libc/nt/iphlpapi.h" +#include "libc/nt/runtime.h" +#include "libc/nt/struct/ipadapteraddresses.h" +#include "libc/nt/winsock.h" +#include "libc/runtime/runtime.h" +#include "libc/sock/internal.h" +#include "libc/sock/struct/ifconf.h" +#include "libc/sock/struct/ifreq.h" +#include "libc/sock/struct/sockaddr.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/af.h" +#include "libc/sysv/consts/fio.h" +#include "libc/sysv/consts/iff.h" +#include "libc/sysv/consts/o.h" +#include "libc/sysv/consts/sio.h" #include "libc/sysv/consts/termios.h" +#include "libc/sysv/errfuns.h" -#define EQUAL(X, Y) ((X) == (Y)) +/* Maximum number of unicast addresses handled for each interface */ +#define MAX_UNICAST_ADDR 32 +#define MAX_NAME_CLASH ((int)('z' - 'a')) /* Allow a..z */ + +static struct HostAdapterInfoNode { + struct HostAdapterInfoNode *next; + char name[IFNAMSIZ]; /* Obtained from FriendlyName */ + struct sockaddr unicast; + struct sockaddr netmask; + struct sockaddr broadcast; + short flags; +} * __hostInfo; + +static int ioctl_default(int fd, unsigned long request, ...) { + int rc; + void *arg; + va_list va; + int64_t handle; + va_start(va, request); + arg = va_arg(va, void *); + va_end(va); + if (!IsWindows()) { + return sys_ioctl(fd, request, arg); + } else if (__isfdopen(fd)) { + if (g_fds.p[fd].kind == kFdSocket) { + handle = __getfdhandleactual(fd); + if ((rc = _weaken(__sys_ioctlsocket_nt)(handle, request, arg)) != -1) { + return rc; + } else { + return _weaken(__winsockerr)(); + } + } else { + return eopnotsupp(); + } + } else { + return ebadf(); + } +} + +/* Frees all the nodes of the _hostInfo */ +static textwindows void freeHostInfo(void) { + struct HostAdapterInfoNode *next, *node = __hostInfo; + if (_weaken(free)) { + while (node) { + next = node->next; + _weaken(free)(node); + node = next; + } + } + __hostInfo = NULL; +} + +/* Given a short adapter name, look into __hostInfo to see if there is + * an adapter with the same name. Returns the pointer to the HostAdapterInfoNode + * if found, or NULL if not found + */ +static textwindows struct HostAdapterInfoNode *findAdapterByName( + const char *name) { + struct HostAdapterInfoNode *node = __hostInfo; + while (node) { + if (!strncmp(name, node->name, IFNAMSIZ)) { + return node; + } + node = node->next; + } + return NULL; +} + +/* Creates a new HostAdapterInfoNode object, initializes it from + * the given adapter, unicast address and address prefixes + * and insert it in the __hostInfo. + * Increments the pointers to the unicast addresses and + * the address prefixes + * Returns NULL if an error occurred or the newly created + * HostAdapterInfoNode object (last in the list) + */ +static textwindows struct HostAdapterInfoNode *appendHostInfo( + struct HostAdapterInfoNode *parentInfoNode, + const char *baseName, /* Max length = IFNAMSIZ-1 */ + const struct NtIpAdapterAddresses + *aa, /* Top level adapter object being processed */ + struct NtIpAdapterUnicastAddress * + *ptrUA, /* Ptr to ptr to unicast address list node */ + struct NtIpAdapterPrefix * + *ptrAP, /* Ptr to ptr to Adapter prefix list node */ + int count) { /* count is used to create a unique name in case of alias */ + + struct HostAdapterInfoNode *temp; + struct HostAdapterInfoNode *node; + uint32_t ip, netmask, broadcast; + struct sockaddr_in *a; + int attemptNum; + + if (!_weaken(calloc) || !(node = _weaken(calloc)(1, sizeof(*node)))) { + errno = ENOMEM; + return NULL; + } + + memcpy(node->name, baseName, IFNAMSIZ); + + /* Are there more than a single unicast address ? */ + if (count > 0 || ((*ptrUA)->Next != NULL)) { + /* Yes, compose it using : */ + size_t nameLen = strlen(node->name); + if (nameLen + 2 > IFNAMSIZ - 2) { + /* Appending the ":x" will exceed the size, need to chop the end */ + nameLen -= 2; + } + node->name[nameLen - 2] = ':'; + node->name[nameLen - 1] = '0' + count; + node->name[nameLen] = '\0'; + } + + /* Is there a name clash with other interfaces? */ + for (attemptNum = 0; attemptNum < MAX_NAME_CLASH; ++attemptNum) { + temp = findAdapterByName(node->name); + if (!temp) { + break; + } else { + /* Yes, this name has been already used, append an extra + * character to resolve conflict. Note since the max length + * of the string now is IFNAMSIZ-2, we have just enough space for this. + * E.g. 'Ethernet_1' -> 'Ethernet_1a' + */ + size_t pos = strlen(node->name); + node->name[pos] = 'a' + attemptNum; + node->name[pos + 1] = '\0'; + /* Try again */ + } + } + + if (attemptNum == MAX_NAME_CLASH) { + /* Cannot resolve the conflict */ + if (_weaken(free)) { + _weaken(free)(node); + } + errno = EEXIST; + return NULL; + } + + /* Finally we got a unique short and friendly name */ + node->unicast = *((*ptrUA)->Address.lpSockaddr); + if (*ptrUA == aa->FirstUnicastAddress) { + short flags; + /* This is the first unicast address of this interface + * calculate the flags for this adapter. Flags to consider: + * IFF_UP + * IFF_BROADCAST ** TODO: We need to validate + * IFF_LOOPBACK + * IFF_POINTOPOINT + * IFF_MULTICAST + * IFF_RUNNING ** Same as IFF_UP for now + * IFF_PROMISC ** NOT SUPPORTED, unknown how to retrieve it + */ + flags = 0; + if (aa->OperStatus == kNtIfOperStatusUp) flags |= IFF_UP | IFF_RUNNING; + if (aa->IfType == kNtIfTypePpp) flags |= IFF_POINTOPOINT; + if (!(aa->Flags & kNtIpAdapterNoMulticast)) flags |= IFF_MULTICAST; + if (aa->IfType == kNtIfTypeSoftwareLoopback) flags |= IFF_LOOPBACK; + if (aa->FirstPrefix) flags |= IFF_BROADCAST; + node->flags = flags; + } else { + /* Copy from previous node */ + node->flags = parentInfoNode->flags; + } + + ip = ntohl( + ((struct sockaddr_in *)(*ptrUA)->Address.lpSockaddr)->sin_addr.s_addr); + netmask = (uint32_t)-1 << (32 - (*ptrUA)->OnLinkPrefixLength); + broadcast = (ip & netmask) | (~netmask & -1); + + a = (struct sockaddr_in *)&node->netmask; + a->sin_family = AF_INET; + a->sin_addr.s_addr = htonl(netmask); + + a = (struct sockaddr_in *)&node->broadcast; + a->sin_family = AF_INET; + a->sin_addr.s_addr = htonl(broadcast); + + /* Process the prefix and extract the netmask and broadcast */ + /* According to the doc: + * + * On Windows Vista and later, the linked IP_ADAPTER_PREFIX + * structures pointed to by the FirstPrefix member include three + * IP adapter prefixes for each IP address assigned to the + * adapter. These include the host IP address prefix, the subnet + * IP address prefix, and the subnet broadcast IP address prefix. + * In addition, for each adapter there is a multicast address + * prefix and a broadcast address prefix. + * -Source: MSDN on IP_ADAPTER_ADDRESSES_LH + * + * For example, interface "Ethernet", with 2 unicast addresses: + * + * - 192.168.1.84 + * - 192.168.5.99 + * + * The Prefix list has 8 elements: + * + * #1: 192.168.1.0/24 <- Network, use the PrefixLength for netmask + * #2: 192.168.1.84/32 <- Host IP + * #3: 192.168.1.255/32 <- Subnet broadcast + * + * #4: 192.168.5.0/24 <- Network + * #5: 192.168.5.99/32 <- Host IP + * #6: 192.168.5.255/32 <- Subnet broadcast + * + * #7: 224.0.0.0/4 <- Multicast + * #8: 255.255.255.255/32 <- Broadcast + */ + + if (ptrAP && *ptrAP) { + *ptrAP = (*ptrAP)->Next; /* skip net ip */ + if (*ptrAP) { + *ptrAP = (*ptrAP)->Next; /* skip host ip */ + if (*ptrAP) { + node->broadcast = *((*ptrAP)->Address.lpSockaddr); + } + } + } + + *ptrUA = (*ptrUA)->Next; + + /* Append this node to the last node (if any) */ + if (parentInfoNode) { + parentInfoNode->next = node; + } + + /* Success */ + return node; +} + +/* Returns -1 in case of failure */ +static textwindows int createHostInfo( + struct NtIpAdapterAddresses *firstAdapter) { + static bool once; + struct NtIpAdapterAddresses *aa; + struct NtIpAdapterUnicastAddress *ua; + struct NtIpAdapterPrefix *ap; + struct HostAdapterInfoNode *node = NULL; + char baseName[IFNAMSIZ]; + char name[IFNAMSIZ]; + int count, i; + /* __hostInfo must be empty */ + _unassert(__hostInfo == NULL); + for (aa = firstAdapter; aa; aa = aa->Next) { + /* Skip all the interfaces with no address and the ones that are not AF_INET + */ + if (!aa->FirstUnicastAddress || + aa->FirstUnicastAddress->Address.lpSockaddr->sa_family != AF_INET) { + continue; + } + /* Use max IFNAMSIZ-1 chars, leave the last char for eventual conflicts */ + tprecode16to8(baseName, IFNAMSIZ - 1, aa->FriendlyName); + baseName[IFNAMSIZ - 2] = '\0'; + /* Replace any space with a '_' */ + for (i = 0; i < IFNAMSIZ - 2; ++i) { + if (baseName[i] == ' ') baseName[i] = '_'; + if (!baseName[i]) break; + } + for (count = 0, ua = aa->FirstUnicastAddress, ap = aa->FirstPrefix; + (ua != NULL) && (count < MAX_UNICAST_ADDR); ++count) { + node = appendHostInfo(node, baseName, aa, &ua, &ap, count); + if (!node) goto err; + if (!__hostInfo) { + __hostInfo = node; + if (_cmpxchg(&once, false, true)) { + atexit(freeHostInfo); + } + } + } + /* Note: do we need to process the remaining adapter prefix? + * ap - points to broadcast addr + * ap->Next - points to interface multicast addr + * Ignoring them for now + */ + } + return 0; +err: + freeHostInfo(); + return -1; +} + +static textwindows int readAdapterAddresses(void) { + uint32_t size, rc; + struct NtIpAdapterAddresses *aa = NULL; + /* + * Calculate the required data size + * Note: alternatively you can use AF_UNSPEC to also return IPv6 interfaces + */ + rc = GetAdaptersAddresses(AF_INET, + kNtGaaFlagSkipAnycast | kNtGaaFlagSkipMulticast | + kNtGaaFlagSkipDnsServer | + kNtGaaFlagIncludePrefix, + NULL, /* Reserved */ + NULL, /* Ptr */ + &size); + if (rc != kNtErrorBufferOverflow) { + ebadf(); + goto err; + } + if (!_weaken(malloc) || + !(aa = (struct NtIpAdapterAddresses *)_weaken(malloc)(size))) { + enomem(); + goto err; + } + /* Re-run GetAdaptersAddresses this time with a valid buffer */ + rc = GetAdaptersAddresses(AF_INET, + kNtGaaFlagSkipAnycast | kNtGaaFlagSkipMulticast | + kNtGaaFlagSkipDnsServer | + kNtGaaFlagIncludePrefix, + // kNtGaaFlagIncludePrefix, + NULL, aa, &size); + if (rc != kNtErrorSuccess) { + errno = GetLastError(); + goto err; + } + if (createHostInfo(aa) == -1) { + goto err; + } + if (_weaken(free)) { + _weaken(free)(aa); + } + return 0; +err: + if (_weaken(free)) { + _weaken(free)(aa); + } + freeHostInfo(); + return -1; +} + +static textwindows int ioctl_siocgifconf_nt(int fd, struct ifconf *ifc) { + struct ifreq *ptr; + struct NtIpAdapterAddresses *aa; + struct HostAdapterInfoNode *node; + if (__hostInfo) { + freeHostInfo(); + } + if (readAdapterAddresses() == -1) { + return -1; + } + for (ptr = ifc->ifc_req, node = __hostInfo; + (((char *)(ptr + 1) - ifc->ifc_buf) < ifc->ifc_len) && node; + ptr++, node = node->next) { + memcpy(ptr->ifr_name, node->name, IFNAMSIZ); + memcpy(&ptr->ifr_addr, &node->unicast, sizeof(struct sockaddr)); + } + ifc->ifc_len = (char *)ptr - ifc->ifc_buf; + return 0; +} /** - * Controls settings on device. + * Returns unicast addresses. + */ +static textwindows int ioctl_siocgifaddr_nt(int fd, struct ifreq *ifr) { + struct HostAdapterInfoNode *node; + node = findAdapterByName(ifr->ifr_name); + if (!node) return ebadf(); + memcpy(&ifr->ifr_addr, &node->unicast, sizeof(struct sockaddr)); + return 0; +} + +/* Performs the SIOCGIFFLAGS operation */ +static textwindows int ioctl_siocgifflags_nt(int fd, struct ifreq *ifr) { + struct HostAdapterInfoNode *node; + node = findAdapterByName(ifr->ifr_name); + if (!node) return ebadf(); + ifr->ifr_flags = node->flags; + return 0; +} + +/* Performs the SIOCGIFNETMASK operation */ +static textwindows int ioctl_siocgifnetmask_nt(int fd, struct ifreq *ifr) { + struct HostAdapterInfoNode *node; + node = findAdapterByName(ifr->ifr_name); + if (!node) return ebadf(); + memcpy(&ifr->ifr_netmask, &node->netmask, sizeof(struct sockaddr)); + return 0; +} + +/** + * Returns broadcast address. + */ +static textwindows int ioctl_siocgifbrdaddr_nt(int fd, struct ifreq *ifr) { + struct HostAdapterInfoNode *node; + node = findAdapterByName(ifr->ifr_name); + if (!node) return ebadf(); + memcpy(&ifr->ifr_broadaddr, &node->broadcast, sizeof(struct sockaddr)); + return 0; +} + +static int ioctl_siocgifconf_sysv(int fd, struct ifconf *ifc) { + /* + * We're 100% compatible with Linux. + * BSD ABIs mainly differ by having sockaddr::sa_len + * XNU uses a 32-bit length in a struct that's packed! + */ + int i, rc, fam; + char *b, *p, *e; + char ifcBsd[16]; + struct ifreq *req; + uint32_t bufLen, ip; + size_t numReq, bufMax; + if (IsLinux()) { + return sys_ioctl(fd, SIOCGIFCONF, ifc); + } + bufMax = 15000; /* conservative guesstimate */ + b = alloca(bufMax); + memcpy(ifcBsd, &bufMax, 8); /* ifc_len */ + memcpy(ifcBsd + (IsXnu() ? 4 : 8), &b, 8); /* ifc_buf */ + if ((rc = sys_ioctl(fd, SIOCGIFCONF, &ifcBsd)) != -1) { + /* + * On XNU the size of the struct ifreq is different than Linux. + * On Linux is fixed (40 bytes), but on XNU the struct sockaddr + * has variable length, making the whole struct ifreq a variable + * sized record. + */ + memcpy(&bufLen, b, 4); + req = ifc->ifc_req; + for (p = b, e = p + MIN(bufMax, READ32LE(ifcBsd)); p + 16 + 16 <= e; + p += IsBsd() ? 16 + MAX(16, p[16] & 255) : 40) { + fam = p[IsBsd() ? 17 : 16] & 255; + if (fam != AF_INET) continue; + ip = READ32BE(p + 20); + bzero(req, sizeof(*req)); + memcpy(req->ifr_name, p, 16); + memcpy(&req->ifr_addr, p + 16, 16); + req->ifr_addr.sa_family = fam; + ((struct sockaddr_in *)&req->ifr_addr)->sin_addr.s_addr = htonl(ip); + ++req; + } + ifc->ifc_len = (char *)req - ifc->ifc_buf; /* Adjust len */ + } + return rc; +} + +static inline void ioctl_sockaddr2linux(void *saddr) { + char *p; + if (saddr) { + p = saddr; + p[0] = p[1]; + p[1] = 0; + } +} + +/* + * Used for all the ioctl that returns sockaddr structure that + * requires adjustment between Linux and XNU + */ +static int ioctl_siocgifaddr_sysv(int fd, uint64_t op, struct ifreq *ifr) { + if (sys_ioctl(fd, op, ifr) == -1) return -1; + if (IsBsd()) ioctl_sockaddr2linux(&ifr->ifr_addr); + return 0; +} + +static int ioctl_siocgifconf(int fd, void *arg) { + if (!IsWindows()) { + return ioctl_siocgifconf_sysv(fd, arg); + } else { + return ioctl_siocgifconf_nt(fd, arg); + } +} + +static int ioctl_siocgifaddr(int fd, void *arg) { + if (!IsWindows()) { + return ioctl_siocgifaddr_sysv(fd, SIOCGIFADDR, arg); + } else { + return ioctl_siocgifaddr_nt(fd, arg); + } +} + +static int ioctl_siocgifnetmask(int fd, void *arg) { + if (!IsWindows()) { + return ioctl_siocgifaddr_sysv(fd, SIOCGIFNETMASK, arg); + } else { + return ioctl_siocgifnetmask_nt(fd, arg); + } +} + +static int ioctl_siocgifbrdaddr(int fd, void *arg) { + if (!IsWindows()) { + return ioctl_siocgifaddr_sysv(fd, SIOCGIFBRDADDR, arg); + } else { + return ioctl_siocgifbrdaddr_nt(fd, arg); + } +} + +static int ioctl_siocgifdstaddr(int fd, void *arg) { + if (!IsWindows()) { + return ioctl_siocgifaddr_sysv(fd, SIOCGIFDSTADDR, arg); + } else { + return enotsup(); + /* Not supported - Unknown how to find out how to retrieve the destination + * address of a PPP from the interface list returned by the + * GetAdaptersAddresses function + * + return ioctl_siocgifdstaddr_nt(fd, arg); + */ + } +} + +static int ioctl_siocgifflags(int fd, void *arg) { + if (!IsWindows()) { + /* Both XNU and Linux are for once compatible here... */ + return ioctl_default(fd, SIOCGIFFLAGS, arg); + } else { + return ioctl_siocgifflags_nt(fd, arg); + } +} + +/** + * Sets "close on exec" on file descriptor the fast way. + * + * @see ioctl(fd, FIOCLEX, 0) dispatches here + */ +static int ioctl_fioclex(int fd, int req) { + int rc; + if (fd >= 0) { + if (IsWindows() || (fd < g_fds.n && g_fds.p[fd].kind == kFdZip)) { + if (__isfdopen(fd)) { + if (req == FIOCLEX) { + g_fds.p[fd].flags |= O_CLOEXEC; + } else { + g_fds.p[fd].flags &= ~O_CLOEXEC; + } + rc = 0; + } else { + rc = ebadf(); + } + } else { + rc = sys_ioctl(fd, req); + } + } else { + rc = einval(); + } + return rc; +} + +/** + * Performs special i/o operation on file descriptor. + * + * @param request can be any of: + * + * - `FIONREAD` takes an `int *` and returns how many bytes of input + * are available on a terminal or socket, waiting to be read. On + * Windows this currently won't work for console file descriptors. + * + * - `TIOCGWINSZ` populates `struct winsize *` with the dimensions + * of your teletypewriter. It's an alias for tcgetwinsize(). + * + * - `TIOCSWINSZ` with the dimensions of your teletypewriter to + * `struct winsize *`. It's an alias for tcsetwinsize(). + * + * - `TIOCOUTQ` takes an `int *` and returns the number of bytes in + * the terminal's output buffer. Only available on UNIX. + * + * - `TIOCSTI` takes a `const char *` and may be used to fake input + * to a tty. This API isn't available on OpenBSD. Only available + * on UNIX. + * + * - `TIOCNOTTY` takes an `int tty_fd` arg and makes it the + * controlling terminal of the calling process, which should have + * called setsid() beforehand. + * + * - `TIOCNOTTY` to give up the controlling terminal. Only available + * on UNIX. + * + * - `TIOCNXCL` to give up exclusive mode on terminal. Only + * available on UNIX. + * + * - `FIOCLEX` sets the `O_CLOEXEC` state (no arg) noting that this + * polyfill may be removed in the future, and code should migrate + * to the equivalent fcntl() api. + * + * - `FIONBIO` sets the `O_NONBLOCK` state (arg is `int *enabled`) + * which is supported on Windows for sockets. + * + * - `FIONCLEX` clears the `O_CLOEXEC` state (no arg) noting that + * this polyfill may be removed in the future, and code should + * migrate to the equivalent fcntl() api. + * + * - `SIOCGIFCONF` takes an struct ifconf object of a given size, + * whose arg is `struct ifconf *`. It implements the Linux style + * and modifies the following: + * - ifc_len: set it to the number of valid ifreq structures + * representingthe interfaces + * - ifc_ifcu.ifcu_req: sets the name of the interface for each + * interface + * The ifc_len is an input/output parameter: set it to the total + * size of the ifcu_buf (ifcu_req) buffer on input. + * + * - `SIOCGIFNETMASK` populates a `struct ifconf *` record with the + * network interface mask. This data structure should be obtained + * by calling `SIOCGIFCONF`. + * + * - `SIOCGIFBRDADDR` populates a `struct ifconf *` record with the + * network broadcast addr. This data structure should be obtained + * by calling `SIOCGIFCONF`. + * + * - `TCGETS` isn't polyfilled; use tcgetattr() + * - `TCSETS` isn't polyfilled; use tcsetattr() + * - `TCSETSW` isn't polyfilled; use tcsetattr() + * - `TCSETSF` isn't polyfilled; use tcsetattr() + * - `TCXONC` isn't polyfilled; use tcflow() + * - `TCSBRK` isn't polyfilled; use tcdrain() + * - `TCFLSH` isn't polyfilled; use tcflush() + * - `TIOCGPTN` isn't polyfilled; use ptsname() + * - `TIOCGSID` isn't polyfilled; use tcgetsid() + * - `TCSBRK` isn't polyfilled; use tcsendbreak() + * - `TCSBRK` isn't polyfilled; use tcsendbreak() + * - `TIOCSPGRP` isn't polyfilled; use tcsetpgrp() + * - `TIOCSPTLCK` isn't polyfilled; use unlockpt() + * * @restartable * @vforksafe */ -int(ioctl)(int fd, uint64_t request, ...) { +int ioctl(int fd, unsigned long request, ...) { + int rc; void *arg; va_list va; va_start(va, request); arg = va_arg(va, void *); va_end(va); - if (request == TIOCGWINSZ) return tcgetwinsize(fd, arg); - if (request == TIOCSWINSZ) return tcsetwinsize(fd, arg); - return __IOCTL_DISPATCH(EQUAL, -1, fd, request, arg); + if (request == FIONBIO) { + rc = ioctl_default(fd, request, arg); + } else if (request == FIOCLEX) { + rc = ioctl_fioclex(fd, request); + } else if (request == FIONCLEX) { + rc = ioctl_fioclex(fd, request); + } else if (request == TIOCGWINSZ) { + rc = tcgetwinsize(fd, arg); + } else if (request == TIOCSWINSZ) { + rc = tcsetwinsize(fd, arg); + } else if (request == SIOCGIFCONF) { + rc = ioctl_siocgifconf(fd, arg); + } else if (request == SIOCGIFADDR) { + rc = ioctl_siocgifaddr(fd, arg); + } else if (request == SIOCGIFNETMASK) { + rc = ioctl_siocgifnetmask(fd, arg); + } else if (request == SIOCGIFBRDADDR) { + rc = ioctl_siocgifbrdaddr(fd, arg); + } else if (request == SIOCGIFDSTADDR) { + rc = ioctl_siocgifdstaddr(fd, arg); + } else if (request == SIOCGIFFLAGS) { + rc = ioctl_siocgifflags(fd, arg); + } else { + rc = ioctl_default(fd, request, arg); + } + STRACE("ioctl(%d, %#lx, %p) → %d% m", fd, request, arg, rc); + return rc; } diff --git a/libc/calls/ioctl.h b/libc/calls/ioctl.h deleted file mode 100644 index af78342ef..000000000 --- a/libc/calls/ioctl.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef COSMOPOLITAN_LIBC_CALLS_IOCTL_H_ -#define COSMOPOLITAN_LIBC_CALLS_IOCTL_H_ -#include "libc/calls/termios.h" -#include "libc/sysv/consts/fio.h" -#include "libc/sysv/consts/sio.h" -#include "libc/sysv/consts/termios.h" -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ - -/*───────────────────────────────────────────────────────────────────────────│─╗ -│ cosmopolitan § system calls » ioctl ─╬─│┼ -╚────────────────────────────────────────────────────────────────────────────│*/ - -int ioctl(int, uint64_t, ...); - -#if defined(__GNUC__) && !defined(__STRICT_ANSI__) && defined(COSMO) -/*───────────────────────────────────────────────────────────────────────────│─╗ -│ cosmopolitan § system calls » ioctl » undiamonding ─╬─│┼ -╚────────────────────────────────────────────────────────────────────────────│*/ - -#define ioctl(FD, REQUEST, ...) \ - __IOCTL_DISPATCH(__EQUIVALENT, ioctl_default(FD, REQUEST, ##__VA_ARGS__), \ - FD, REQUEST, ##__VA_ARGS__) - -#define __EQUIVALENT(X, Y) (__builtin_constant_p((X) == (Y)) && ((X) == (Y))) - -#define __IOCTL_DISPATCH(CMP, DEFAULT, FD, REQUEST, ...) \ - ({ \ - int ReZ; \ - if (CMP(REQUEST, SIOCGIFCONF)) { \ - ReZ = ioctl_siocgifconf(FD, ##__VA_ARGS__); \ - } else if (CMP(REQUEST, SIOCGIFADDR)) { \ - ReZ = ioctl_siocgifaddr(FD, ##__VA_ARGS__); \ - } else if (CMP(REQUEST, SIOCGIFNETMASK)) { \ - ReZ = ioctl_siocgifnetmask(FD, ##__VA_ARGS__); \ - } else if (CMP(REQUEST, SIOCGIFBRDADDR)) { \ - ReZ = ioctl_siocgifbrdaddr(FD, ##__VA_ARGS__); \ - } else if (CMP(REQUEST, SIOCGIFDSTADDR)) { \ - ReZ = ioctl_siocgifdstaddr(FD, ##__VA_ARGS__); \ - } else if (CMP(REQUEST, SIOCGIFFLAGS)) { \ - ReZ = ioctl_siocgifflags(FD, ##__VA_ARGS__); \ - } else if (CMP(REQUEST, FIONBIO)) { \ - ReZ = ioctl_default(FD, REQUEST, ##__VA_ARGS__); \ - } else if (CMP(REQUEST, FIOCLEX)) { \ - ReZ = ioctl_fioclex(FD, REQUEST); \ - } else if (CMP(REQUEST, FIONCLEX)) { \ - ReZ = ioctl_fioclex(FD, REQUEST); \ - } else { \ - ReZ = DEFAULT; \ - } \ - ReZ; \ - }) - -int ioctl_default(int, uint64_t, ...); -int ioctl_fioclex(int, int); -int ioctl_siocgifaddr(int, ...); -int ioctl_siocgifbrdaddr(int, ...); -int ioctl_siocgifconf(int, ...); -int ioctl_siocgifdstaddr(int, ...); -int ioctl_siocgifflags(int, ...); -int ioctl_siocgifnetmask(int, ...); - -#endif /* GNUC && !ANSI */ -COSMOPOLITAN_C_END_ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_LIBC_CALLS_IOCTL_H_ */ diff --git a/libc/calls/ioctl_default.c b/libc/calls/ioctl_default.c deleted file mode 100644 index 2df9a3f85..000000000 --- a/libc/calls/ioctl_default.c +++ /dev/null @@ -1,52 +0,0 @@ -/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ -│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ -╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2020 Justine Alexandra Roberts Tunney │ -│ │ -│ 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/ioctl.h" -#include "libc/calls/syscall-sysv.internal.h" -#include "libc/dce.h" -#include "libc/intrin/weaken.h" -#include "libc/nt/winsock.h" -#include "libc/sock/internal.h" -#include "libc/sysv/errfuns.h" - -int ioctl_default(int fd, uint64_t request, ...) { - int rc; - void *arg; - va_list va; - int64_t handle; - va_start(va, request); - arg = va_arg(va, void *); - va_end(va); - if (!IsWindows()) { - return sys_ioctl(fd, request, arg); - } else if (__isfdopen(fd)) { - if (g_fds.p[fd].kind == kFdSocket) { - handle = __getfdhandleactual(fd); - if ((rc = _weaken(__sys_ioctlsocket_nt)(handle, request, arg)) != -1) { - return rc; - } else { - return _weaken(__winsockerr)(); - } - } else { - return eopnotsupp(); - } - } else { - return ebadf(); - } -} diff --git a/libc/calls/ioctl_fioclex.c b/libc/calls/ioctl_fioclex.c deleted file mode 100644 index 825285d76..000000000 --- a/libc/calls/ioctl_fioclex.c +++ /dev/null @@ -1,54 +0,0 @@ -/*-*- 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 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/calls/internal.h" -#include "libc/calls/ioctl.h" -#include "libc/calls/syscall-sysv.internal.h" -#include "libc/dce.h" -#include "libc/intrin/strace.internal.h" -#include "libc/sysv/consts/o.h" -#include "libc/sysv/errfuns.h" - -/** - * Sets "close on exec" on file descriptor the fast way. - * - * @see ioctl(fd, FIOCLEX, 0) dispatches here - */ -int ioctl_fioclex(int fd, int req) { - int rc; - if (fd >= 0) { - if (IsWindows() || (fd < g_fds.n && g_fds.p[fd].kind == kFdZip)) { - if (__isfdopen(fd)) { - if (req == FIOCLEX) { - g_fds.p[fd].flags |= O_CLOEXEC; - } else { - g_fds.p[fd].flags &= ~O_CLOEXEC; - } - rc = 0; - } else { - rc = ebadf(); - } - } else { - rc = sys_ioctl(fd, req); - } - } else { - rc = einval(); - } - STRACE("%s(%d, %d) → %d% m", "ioctl_fioclex", fd, req, rc); - return rc; -} diff --git a/libc/calls/ioctl_siocgifconf-nt.c b/libc/calls/ioctl_siocgifconf-nt.c deleted file mode 100644 index 6762d018b..000000000 --- a/libc/calls/ioctl_siocgifconf-nt.c +++ /dev/null @@ -1,414 +0,0 @@ -/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ -│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ -╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2020 Justine Alexandra Roberts Tunney │ -│ │ -│ 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/assert.h" -#include "libc/calls/calls.h" -#include "libc/errno.h" -#include "libc/intrin/cmpxchg.h" -#include "libc/intrin/weaken.h" -#include "libc/mem/mem.h" -#include "libc/nt/errors.h" -#include "libc/nt/iphlpapi.h" -#include "libc/nt/runtime.h" -#include "libc/nt/struct/ipadapteraddresses.h" -#include "libc/nt/winsock.h" -#include "libc/runtime/runtime.h" -#include "libc/sock/internal.h" -#include "libc/sock/sock.h" -#include "libc/sock/struct/ifconf.h" -#include "libc/str/str.h" -#include "libc/sysv/consts/af.h" -#include "libc/sysv/consts/iff.h" -#include "libc/sysv/consts/o.h" -#include "libc/sysv/errfuns.h" - -/* Maximum number of unicast addresses handled for each interface */ -#define MAX_UNICAST_ADDR 32 -#define MAX_NAME_CLASH ((int)('z' - 'a')) /* Allow a..z */ - -struct HostAdapterInfoNode { - struct HostAdapterInfoNode *next; - char name[IFNAMSIZ]; /* Obtained from FriendlyName */ - struct sockaddr unicast; - struct sockaddr netmask; - struct sockaddr broadcast; - short flags; -} * __hostInfo; - -/* Frees all the nodes of the _hostInfo */ -static void freeHostInfo(void) { - struct HostAdapterInfoNode *next, *node = __hostInfo; - if (_weaken(free)) { - while (node) { - next = node->next; - _weaken(free)(node); - node = next; - } - } - __hostInfo = NULL; -} - -/* Given a short adapter name, look into __hostInfo to see if there is - * an adapter with the same name. Returns the pointer to the HostAdapterInfoNode - * if found, or NULL if not found - */ -static struct HostAdapterInfoNode *findAdapterByName(const char *name) { - struct HostAdapterInfoNode *node = __hostInfo; - while (node) { - if (!strncmp(name, node->name, IFNAMSIZ)) { - return node; - } - node = node->next; - } - return NULL; -} - -/* Creates a new HostAdapterInfoNode object, initializes it from - * the given adapter, unicast address and address prefixes - * and insert it in the __hostInfo. - * Increments the pointers to the unicast addresses and - * the address prefixes - * Returns NULL if an error occurred or the newly created - * HostAdapterInfoNode object (last in the list) - */ -struct HostAdapterInfoNode *appendHostInfo( - struct HostAdapterInfoNode *parentInfoNode, - const char *baseName, /* Max length = IFNAMSIZ-1 */ - const struct NtIpAdapterAddresses - *aa, /* Top level adapter object being processed */ - struct NtIpAdapterUnicastAddress * - *ptrUA, /* Ptr to ptr to unicast address list node */ - struct NtIpAdapterPrefix * - *ptrAP, /* Ptr to ptr to Adapter prefix list node */ - int count) { /* count is used to create a unique name in case of alias */ - - struct HostAdapterInfoNode *temp; - struct HostAdapterInfoNode *node; - uint32_t ip, netmask, broadcast; - struct sockaddr_in *a; - int attemptNum; - - if (!_weaken(calloc) || !(node = _weaken(calloc)(1, sizeof(*node)))) { - errno = ENOMEM; - return NULL; - } - - memcpy(node->name, baseName, IFNAMSIZ); - - /* Are there more than a single unicast address ? */ - if (count > 0 || ((*ptrUA)->Next != NULL)) { - /* Yes, compose it using : */ - size_t nameLen = strlen(node->name); - if (nameLen + 2 > IFNAMSIZ - 2) { - /* Appending the ":x" will exceed the size, need to chop the end */ - nameLen -= 2; - } - node->name[nameLen - 2] = ':'; - node->name[nameLen - 1] = '0' + count; - node->name[nameLen] = '\0'; - } - - /* Is there a name clash with other interfaces? */ - for (attemptNum = 0; attemptNum < MAX_NAME_CLASH; ++attemptNum) { - temp = findAdapterByName(node->name); - if (!temp) { - break; - } else { - /* Yes, this name has been already used, append an extra - * character to resolve conflict. Note since the max length - * of the string now is IFNAMSIZ-2, we have just enough space for this. - * E.g. 'Ethernet_1' -> 'Ethernet_1a' - */ - size_t pos = strlen(node->name); - node->name[pos] = 'a' + attemptNum; - node->name[pos + 1] = '\0'; - /* Try again */ - } - } - - if (attemptNum == MAX_NAME_CLASH) { - /* Cannot resolve the conflict */ - if (_weaken(free)) { - _weaken(free)(node); - } - errno = EEXIST; - return NULL; - } - - /* Finally we got a unique short and friendly name */ - node->unicast = *((*ptrUA)->Address.lpSockaddr); - if (*ptrUA == aa->FirstUnicastAddress) { - short flags; - /* This is the first unicast address of this interface - * calculate the flags for this adapter. Flags to consider: - * IFF_UP - * IFF_BROADCAST ** TODO: We need to validate - * IFF_LOOPBACK - * IFF_POINTOPOINT - * IFF_MULTICAST - * IFF_RUNNING ** Same as IFF_UP for now - * IFF_PROMISC ** NOT SUPPORTED, unknown how to retrieve it - */ - flags = 0; - if (aa->OperStatus == kNtIfOperStatusUp) flags |= IFF_UP | IFF_RUNNING; - if (aa->IfType == kNtIfTypePpp) flags |= IFF_POINTOPOINT; - if (!(aa->Flags & kNtIpAdapterNoMulticast)) flags |= IFF_MULTICAST; - if (aa->IfType == kNtIfTypeSoftwareLoopback) flags |= IFF_LOOPBACK; - if (aa->FirstPrefix) flags |= IFF_BROADCAST; - node->flags = flags; - } else { - /* Copy from previous node */ - node->flags = parentInfoNode->flags; - } - - ip = ntohl( - ((struct sockaddr_in *)(*ptrUA)->Address.lpSockaddr)->sin_addr.s_addr); - netmask = (uint32_t)-1 << (32 - (*ptrUA)->OnLinkPrefixLength); - broadcast = (ip & netmask) | (~netmask & -1); - - a = (struct sockaddr_in *)&node->netmask; - a->sin_family = AF_INET; - a->sin_addr.s_addr = htonl(netmask); - - a = (struct sockaddr_in *)&node->broadcast; - a->sin_family = AF_INET; - a->sin_addr.s_addr = htonl(broadcast); - - /* Process the prefix and extract the netmask and broadcast */ - /* According to the doc: - * - * On Windows Vista and later, the linked IP_ADAPTER_PREFIX - * structures pointed to by the FirstPrefix member include three - * IP adapter prefixes for each IP address assigned to the - * adapter. These include the host IP address prefix, the subnet - * IP address prefix, and the subnet broadcast IP address prefix. - * In addition, for each adapter there is a multicast address - * prefix and a broadcast address prefix. - * -Source: MSDN on IP_ADAPTER_ADDRESSES_LH - * - * For example, interface "Ethernet", with 2 unicast addresses: - * - * - 192.168.1.84 - * - 192.168.5.99 - * - * The Prefix list has 8 elements: - * - * #1: 192.168.1.0/24 <- Network, use the PrefixLength for netmask - * #2: 192.168.1.84/32 <- Host IP - * #3: 192.168.1.255/32 <- Subnet broadcast - * - * #4: 192.168.5.0/24 <- Network - * #5: 192.168.5.99/32 <- Host IP - * #6: 192.168.5.255/32 <- Subnet broadcast - * - * #7: 224.0.0.0/4 <- Multicast - * #8: 255.255.255.255/32 <- Broadcast - */ - - if (ptrAP && *ptrAP) { - *ptrAP = (*ptrAP)->Next; /* skip net ip */ - if (*ptrAP) { - *ptrAP = (*ptrAP)->Next; /* skip host ip */ - if (*ptrAP) { - node->broadcast = *((*ptrAP)->Address.lpSockaddr); - } - } - } - - *ptrUA = (*ptrUA)->Next; - - /* Append this node to the last node (if any) */ - if (parentInfoNode) { - parentInfoNode->next = node; - } - - /* Success */ - return node; -} - -/* Returns -1 in case of failure */ -static int createHostInfo(struct NtIpAdapterAddresses *firstAdapter) { - static bool once; - struct NtIpAdapterAddresses *aa; - struct NtIpAdapterUnicastAddress *ua; - struct NtIpAdapterPrefix *ap; - struct HostAdapterInfoNode *node = NULL; - char baseName[IFNAMSIZ]; - char name[IFNAMSIZ]; - int count, i; - - /* __hostInfo must be empty */ - _unassert(__hostInfo == NULL); - - for (aa = firstAdapter; aa; aa = aa->Next) { - /* Skip all the interfaces with no address and the ones that are not AF_INET - */ - if (!aa->FirstUnicastAddress || - aa->FirstUnicastAddress->Address.lpSockaddr->sa_family != AF_INET) { - continue; - } - - /* Use max IFNAMSIZ-1 chars, leave the last char for eventual conflicts */ - tprecode16to8(baseName, IFNAMSIZ - 1, aa->FriendlyName); - baseName[IFNAMSIZ - 2] = '\0'; - /* Replace any space with a '_' */ - for (i = 0; i < IFNAMSIZ - 2; ++i) { - if (baseName[i] == ' ') baseName[i] = '_'; - if (!baseName[i]) break; - } - for (count = 0, ua = aa->FirstUnicastAddress, ap = aa->FirstPrefix; - (ua != NULL) && (count < MAX_UNICAST_ADDR); ++count) { - node = appendHostInfo(node, baseName, aa, &ua, &ap, count); - if (!node) goto err; - if (!__hostInfo) { - __hostInfo = node; - if (_cmpxchg(&once, false, true)) { - atexit(freeHostInfo); - } - } - } - - /* Note: do we need to process the remaining adapter prefix? - * ap - points to broadcast addr - * ap->Next - points to interface multicast addr - * Ignoring them for now - */ - } - return 0; - -err: - freeHostInfo(); - return -1; -} - -static int readAdapterAddresses(void) { - uint32_t size, rc; - struct NtIpAdapterAddresses *aa = NULL; - - /* Calculate the required data size - * Note: alternatively you can use AF_UNSPEC to also return IPv6 interfaces - */ - rc = GetAdaptersAddresses(AF_INET, - kNtGaaFlagSkipAnycast | kNtGaaFlagSkipMulticast | - kNtGaaFlagSkipDnsServer | - kNtGaaFlagIncludePrefix, - NULL, /* Reserved */ - NULL, /* Ptr */ - &size); - if (rc != kNtErrorBufferOverflow) { - ebadf(); - goto err; - } - - if (!_weaken(malloc) || - !(aa = (struct NtIpAdapterAddresses *)_weaken(malloc)(size))) { - enomem(); - goto err; - } - - /* Re-run GetAdaptersAddresses this time with a valid buffer */ - rc = GetAdaptersAddresses(AF_INET, - kNtGaaFlagSkipAnycast | kNtGaaFlagSkipMulticast | - kNtGaaFlagSkipDnsServer | - kNtGaaFlagIncludePrefix, - // kNtGaaFlagIncludePrefix, - NULL, aa, &size); - if (rc != kNtErrorSuccess) { - errno = GetLastError(); - goto err; - } - if (createHostInfo(aa) == -1) { - goto err; - } - - if (_weaken(free)) { - _weaken(free)(aa); - } - return 0; - -err: - if (_weaken(free)) { - _weaken(free)(aa); - } - freeHostInfo(); - return -1; -} - -textwindows int ioctl_siocgifconf_nt(int fd, struct ifconf *ifc) { - struct NtIpAdapterAddresses *aa; - struct HostAdapterInfoNode *node; - struct ifreq *ptr; - - if (__hostInfo) { - freeHostInfo(); - } - - if (readAdapterAddresses() == -1) { - return -1; - } - - for (ptr = ifc->ifc_req, node = __hostInfo; - (((char *)(ptr + 1) - ifc->ifc_buf) < ifc->ifc_len) && node; - ptr++, node = node->next) { - memcpy(ptr->ifr_name, node->name, IFNAMSIZ); - memcpy(&ptr->ifr_addr, &node->unicast, sizeof(struct sockaddr)); - } - ifc->ifc_len = (char *)ptr - ifc->ifc_buf; - - return 0; -} - -/** - * Returns unicast addresses. - */ -int ioctl_siocgifaddr_nt(int fd, struct ifreq *ifr) { - struct HostAdapterInfoNode *node; - node = findAdapterByName(ifr->ifr_name); - if (!node) return ebadf(); - memcpy(&ifr->ifr_addr, &node->unicast, sizeof(struct sockaddr)); - return 0; -} - -/* Performs the SIOCGIFFLAGS operation */ -int ioctl_siocgifflags_nt(int fd, struct ifreq *ifr) { - struct HostAdapterInfoNode *node; - node = findAdapterByName(ifr->ifr_name); - if (!node) return ebadf(); - ifr->ifr_flags = node->flags; - return 0; -} - -/* Performs the SIOCGIFNETMASK operation */ -int ioctl_siocgifnetmask_nt(int fd, struct ifreq *ifr) { - struct HostAdapterInfoNode *node; - node = findAdapterByName(ifr->ifr_name); - if (!node) return ebadf(); - memcpy(&ifr->ifr_netmask, &node->netmask, sizeof(struct sockaddr)); - return 0; -} - -/** - * Returns broadcast address. - */ -int ioctl_siocgifbrdaddr_nt(int fd, struct ifreq *ifr) { - struct HostAdapterInfoNode *node; - node = findAdapterByName(ifr->ifr_name); - if (!node) return ebadf(); - memcpy(&ifr->ifr_broadaddr, &node->broadcast, sizeof(struct sockaddr)); - return 0; -} diff --git a/libc/calls/ioctl_siocgifconf.c b/libc/calls/ioctl_siocgifconf.c deleted file mode 100644 index cfa89e6a3..000000000 --- a/libc/calls/ioctl_siocgifconf.c +++ /dev/null @@ -1,206 +0,0 @@ -/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ -│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ -╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2020 Justine Alexandra Roberts Tunney │ -│ │ -│ 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/assert.h" -#include "libc/calls/ioctl.h" -#include "libc/calls/syscall-sysv.internal.h" -#include "libc/dce.h" -#include "libc/intrin/bits.h" -#include "libc/intrin/strace.internal.h" -#include "libc/intrin/weaken.h" -#include "libc/macros.internal.h" -#include "libc/mem/mem.h" -#include "libc/sock/internal.h" -#include "libc/sock/sock.h" -#include "libc/sock/struct/ifconf.h" -#include "libc/sock/struct/ifreq.h" -#include "libc/str/str.h" -#include "libc/sysv/consts/af.h" -#include "libc/sysv/consts/sio.h" -#include "libc/sysv/errfuns.h" - -/* SIOCGIFCONF: - * Takes an struct ifconf object of a given size - * Modifies the following: - * - ifc_len: set it to the number of valid ifreq structures representing - * the interfaces - * - ifc_ifcu.ifcu_req: sets the name of the interface for each interface - * The ifc_len is an input/output parameter: set it to the total size of - * the ifcu_buf (ifcu_req) buffer on input. - */ -int ioctl_siocgifconf_nt(int, struct ifconf *) _Hide; -int ioctl_siocgifaddr_nt(int, struct ifreq *) _Hide; -int ioctl_siocgifflags_nt(int, struct ifreq *) _Hide; -int ioctl_siocgifnetmask_nt(int, struct ifreq *) _Hide; -int ioctl_siocgifbrdaddr_nt(int, struct ifreq *) _Hide; - -static int ioctl_siocgifconf_sysv(int fd, struct ifconf *ifc) { - /* - * We're 100% compatible with Linux. - * BSD ABIs mainly differ by having sockaddr::sa_len - * XNU uses a 32-bit length in a struct that's packed! - */ - int i, rc, fam; - char *b, *p, *e; - char ifcBsd[16]; - struct ifreq *req; - uint32_t bufLen, ip; - size_t numReq, bufMax; - if (IsLinux()) return sys_ioctl(fd, SIOCGIFCONF, ifc); - if (!_weaken(malloc)) return enomem(); - bufMax = 15000; /* conservative guesstimate */ - if (!(b = _weaken(malloc)(bufMax))) return enomem(); - memcpy(ifcBsd, &bufMax, 8); /* ifc_len */ - memcpy(ifcBsd + (IsXnu() ? 4 : 8), &b, 8); /* ifc_buf */ - if ((rc = sys_ioctl(fd, SIOCGIFCONF, &ifcBsd)) != -1) { - /* - * On XNU the size of the struct ifreq is different than Linux. - * On Linux is fixed (40 bytes), but on XNU the struct sockaddr - * has variable length, making the whole struct ifreq a variable - * sized record. - */ - memcpy(&bufLen, b, 4); - req = ifc->ifc_req; - for (p = b, e = p + MIN(bufMax, READ32LE(ifcBsd)); p + 16 + 16 <= e; - p += IsBsd() ? 16 + MAX(16, p[16] & 255) : 40) { - fam = p[IsBsd() ? 17 : 16] & 255; - if (fam != AF_INET) continue; - ip = READ32BE(p + 20); - bzero(req, sizeof(*req)); - memcpy(req->ifr_name, p, 16); - memcpy(&req->ifr_addr, p + 16, 16); - req->ifr_addr.sa_family = fam; - ((struct sockaddr_in *)&req->ifr_addr)->sin_addr.s_addr = htonl(ip); - ++req; - } - ifc->ifc_len = (char *)req - ifc->ifc_buf; /* Adjust len */ - } - if (_weaken(free)) _weaken(free)(b); - return rc; -} - -forceinline void Sockaddr2linux(void *saddr) { - char *p; - if (saddr) { - p = saddr; - p[0] = p[1]; - p[1] = 0; - } -} - -/* Used for all the ioctl that returns sockaddr structure that - * requires adjustment between Linux and XNU - */ -static int ioctl_siocgifaddr_sysv(int fd, uint64_t op, struct ifreq *ifr) { - if (sys_ioctl(fd, op, ifr) == -1) return -1; - if (IsBsd()) Sockaddr2linux(&ifr->ifr_addr); - return 0; -} - -/** - * Returns information about network interfaces. - * - * @see ioctl(fd, SIOCGIFCONF, tio) dispatches here - */ -int ioctl_siocgifconf(int fd, ...) { - int rc; - va_list va; - struct ifconf *ifc; - va_start(va, fd); - ifc = va_arg(va, struct ifconf *); - va_end(va); - if (!IsWindows()) { - rc = ioctl_siocgifconf_sysv(fd, ifc); - } else { - rc = ioctl_siocgifconf_nt(fd, ifc); - } - STRACE("%s(%d) → %d% m", "ioctl_siocgifconf", fd, rc); - return rc; -} - -int ioctl_siocgifaddr(int fd, ...) { - va_list va; - struct ifreq *ifr; - va_start(va, fd); - ifr = va_arg(va, struct ifreq *); - va_end(va); - if (!IsWindows()) { - return ioctl_siocgifaddr_sysv(fd, SIOCGIFADDR, ifr); - } else { - return ioctl_siocgifaddr_nt(fd, ifr); - } -} - -int ioctl_siocgifnetmask(int fd, ...) { - va_list va; - struct ifreq *ifr; - va_start(va, fd); - ifr = va_arg(va, struct ifreq *); - va_end(va); - if (!IsWindows()) { - return ioctl_siocgifaddr_sysv(fd, SIOCGIFNETMASK, ifr); - } else { - return ioctl_siocgifnetmask_nt(fd, ifr); - } -} - -int ioctl_siocgifbrdaddr(int fd, ...) { - va_list va; - struct ifreq *ifr; - va_start(va, fd); - ifr = va_arg(va, struct ifreq *); - va_end(va); - if (!IsWindows()) { - return ioctl_siocgifaddr_sysv(fd, SIOCGIFBRDADDR, ifr); - } else { - return ioctl_siocgifbrdaddr_nt(fd, ifr); - } -} - -int ioctl_siocgifdstaddr(int fd, ...) { - va_list va; - struct ifreq *ifr; - va_start(va, fd); - ifr = va_arg(va, struct ifreq *); - va_end(va); - if (!IsWindows()) { - return ioctl_siocgifaddr_sysv(fd, SIOCGIFDSTADDR, ifr); - } else { - return enotsup(); - /* Not supported - Unknown how to find out how to retrieve the destination - * address of a PPP from the interface list returned by the - * GetAdaptersAddresses function - * - return ioctl_siocgifdstaddr_nt(fd, ifc); - */ - } -} - -int ioctl_siocgifflags(int fd, ...) { - va_list va; - struct ifreq *ifr; - va_start(va, fd); - ifr = va_arg(va, struct ifreq *); - va_end(va); - if (!IsWindows()) { - /* Both XNU and Linux are for once compatible here... */ - return ioctl_default(fd, SIOCGIFFLAGS, ifr); - } else { - return ioctl_siocgifflags_nt(fd, ifr); - } -} diff --git a/libc/calls/openpty.c b/libc/calls/openpty.c index 3ea8300c8..18981d827 100644 --- a/libc/calls/openpty.c +++ b/libc/calls/openpty.c @@ -19,7 +19,6 @@ #include "libc/assert.h" #include "libc/calls/blockcancel.internal.h" #include "libc/calls/calls.h" -#include "libc/calls/ioctl.h" #include "libc/calls/struct/metatermios.internal.h" #include "libc/calls/struct/termios.h" #include "libc/calls/struct/winsize.h" diff --git a/libc/calls/tcgetwinsize.c b/libc/calls/tcgetwinsize.c index efa1b067f..347738f4e 100644 --- a/libc/calls/tcgetwinsize.c +++ b/libc/calls/tcgetwinsize.c @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" -#include "libc/calls/ioctl.h" #include "libc/calls/struct/winsize.h" #include "libc/calls/struct/winsize.internal.h" #include "libc/calls/syscall-sysv.internal.h" diff --git a/libc/calls/tcsetattr.c b/libc/calls/tcsetattr.c index 7040a5e77..f0f48275d 100644 --- a/libc/calls/tcsetattr.c +++ b/libc/calls/tcsetattr.c @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" -#include "libc/calls/ioctl.h" #include "libc/calls/struct/metatermios.internal.h" #include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/termios.h" diff --git a/libc/isystem/sys/ioctl.h b/libc/isystem/sys/ioctl.h index 644c4f99f..1ae5208a5 100644 --- a/libc/isystem/sys/ioctl.h +++ b/libc/isystem/sys/ioctl.h @@ -1,7 +1,6 @@ #ifndef LIBC_ISYSTEM_SYS_IOCTL_H_ #define LIBC_ISYSTEM_SYS_IOCTL_H_ #include "libc/calls/calls.h" -#include "libc/calls/ioctl.h" #include "libc/calls/struct/winsize.h" #include "libc/sysv/consts/fd.h" #include "libc/sysv/consts/fio.h" diff --git a/libc/runtime/login_tty.c b/libc/runtime/login_tty.c index b0b74ed06..48580f1f0 100644 --- a/libc/runtime/login_tty.c +++ b/libc/runtime/login_tty.c @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/ioctl.h" #include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/intrin/strace.internal.h" diff --git a/libc/sysv/consts.sh b/libc/sysv/consts.sh index 42ba16d25..9475952db 100755 --- a/libc/sysv/consts.sh +++ b/libc/sysv/consts.sh @@ -351,6 +351,7 @@ syscon fcntl2 F_GETFD 1 1 1 1 1 1 1 1 # unix consensus & fak syscon fcntl2 F_SETFD 2 2 2 2 2 2 2 2 # unix consensus & faked nt syscon fcntl2 F_GETFL 3 3 3 3 3 3 3 3 # unix consensus & faked nt syscon fcntl2 F_SETFL 4 4 4 4 4 4 4 4 # unix consensus & faked nt +syscon fcntl F_DUPFD_CLOEXEC 0x0406 0x0406 67 67 17 10 12 0x0406 # Linux 2.6.24+; faked nt syscon fcntl2 F_SETOWN 8 8 6 6 6 6 6 -1 # bsd consensus syscon fcntl2 F_GETOWN 9 9 5 5 5 5 5 -1 # bsd consensus syscon fcntl2 F_SETOWN_EX 15 15 -1 -1 -1 -1 -1 -1 # TODO(jart): polyfill @@ -362,7 +363,6 @@ syscon fcntl3 F_SETNOSIGPIPE -1 -1 73 73 -1 -1 14 -1 # syscon fcntl3 F_GETNOSIGPIPE -1 -1 74 74 -1 -1 13 -1 # syscon fcntl3 F_GETPATH -1 -1 50 50 -1 -1 15 -1 # geth path associated with fd into buffer with PATH_MAX (1024) bytes syscon fcntl3 FD_CLOEXEC 1 1 1 1 1 1 1 1 # unix consensus & faked nt -syscon fcntl F_DUPFD_CLOEXEC 0x0406 0x0406 67 67 17 10 12 0x0406 # Linux 2.6.24+; faked nt syscon fcntl F_MAXFD -1 -1 -1 -1 -1 -1 11 -1 # syscon fcntl F_NOTIFY 0x0402 0x0402 -1 -1 -1 -1 -1 -1 syscon fcntl F_SETPIPE_SZ 0x0407 0x0407 -1 -1 -1 -1 -1 -1 @@ -399,14 +399,6 @@ syscon fcntl F_GETOWN_EX 0x10 0x10 -1 -1 -1 -1 -1 -1 syscon fcntl F_SETLEASE 0x0400 0x0400 -1 106 -1 -1 -1 -1 syscon fcntl F_GETLEASE 0x0401 0x0401 -1 107 -1 -1 -1 -1 -syscon ioctl FIONBIO 0x5421 0x5421 0x8004667e 0x8004667e 0x8004667e 0x8004667e 0x8004667e 0x8004667e # BSD-The New Technology consensus; FIONBIO is traditional O_NONBLOCK; see F_SETFL for re-imagined api -syscon ioctl FIOASYNC 0x5452 0x5452 0x8004667d 0x8004667d 0x8004667d 0x8004667d 0x8004667d 0x8004667d # BSD-The New Technology consensus -syscon ioctl FIONREAD 0x541b 0x541b 0x4004667f 0x4004667f 0x4004667f 0x4004667f 0x4004667f 0x4004667f # BSD-The New Technology consensus; bytes waiting in FD's input buffer -syscon ioctl FIOCLEX 0x5451 0x5451 0x20006601 0x20006601 0x20006601 0x20006601 0x20006601 0x5451 # sets "close on exec" on file descriptor the fast way; faked nt -syscon ioctl FIONCLEX 0x5450 0x5450 0x20006602 0x20006602 0x20006602 0x20006602 0x20006602 0x5450 # clears "close on exec" on file descriptor the fast way; faked nt -#syscon ioctl FIONWRITE 0x0 0x0 0x0 0x0 0x40046677 0x0 0x0 -1 # [FreeBSD Generalization] bytes queued in FD's output buffer (same as TIOCOUTQ for TTY FDs; see also SO_SNDBUF) -#syscon ioctl FIONSPACE 0x0 0x0 0x0 0x0 0x40046676 0x0 0x0 -1 # [FreeBSD Generalization] capacity of FD's output buffer, e.g. equivalent to TIOCGSERIAL w/ UART - # openat(), fstatat(), linkat(), etc. magnums # # group name GNU/Systemd GNU/Systemd (Aarch64) XNU's Not UNIX! MacOS (Arm64) FreeBSD OpenBSD NetBSD The New Technology Commentary @@ -944,68 +936,76 @@ syscon ptrace PTRACE_EVENT_STOP 128 128 -1 -1 -1 -1 -1 -1 # group name GNU/Systemd GNU/Systemd (Aarch64) XNU's Not UNIX! MacOS (Arm64) FreeBSD OpenBSD NetBSD The New Technology Commentary syscon clone CLONE_VM 0x00000100 0x00000100 0x00000100 0x00000100 0x00000100 0x00000100 0x00000100 0x00000100 # intentionally symbolic so we can tell if clone() is being used to create threads -# socket ioctl() +# ioctl() requests # # group name GNU/Systemd GNU/Systemd (Aarch64) XNU's Not UNIX! MacOS (Arm64) FreeBSD OpenBSD NetBSD The New Technology Commentary -syscon sio SIOCATMARK 0x8905 0x8905 0x40047307 0x40047307 0x40047307 0x40047307 0x40047307 0x40047307 # use sockatmark(); determines if oob is available; bsd consensus -syscon sio SIOCADDMULTI 0x8931 0x8931 0x80206931 0x80206931 0x80206931 0x80206931 0x80206931 0 # bsd consensus -syscon sio SIOCDELMULTI 0x8932 0x8932 0x80206932 0x80206932 0x80206932 0x80206932 0x80206932 0 # bsd consensus -syscon sio SIOCDIFADDR 0x8936 0x8936 0x80206919 0x80206919 0x80206919 0x80206919 0x80206919 0 # bsd consensus -syscon sio SIOCGIFADDR 0x8915 0x8915 0xc0206921 0xc0206921 0xc0206921 0xc0206921 0xc0206921 0 # bsd consensus -syscon sio SIOCGIFBRDADDR 0x8919 0x8919 0xc0206923 0xc0206923 0xc0206923 0xc0206923 0xc0206923 0 # bsd consensus -syscon sio SIOCGIFDSTADDR 0x8917 0x8917 0xc0206922 0xc0206922 0xc0206922 0xc0206922 0xc0206922 0 # bsd consensus -syscon sio SIOCGIFFLAGS 0x8913 0x8913 0xc0206911 0xc0206911 0xc0206911 0xc0206911 0xc0206911 0 # bsd consensus -syscon sio SIOCGIFMETRIC 0x891d 0x891d 0xc0206917 0xc0206917 0xc0206917 0xc0206917 0xc0206917 0 # bsd consensus -syscon sio SIOCGIFNETMASK 0x891b 0x891b 0xc0206925 0xc0206925 0xc0206925 0xc0206925 0xc0206925 0 # bsd consensus -syscon sio SIOCGPGRP 0x8904 0x8904 0x40047309 0x40047309 0x40047309 0x40047309 0x40047309 0 # bsd consensus -syscon sio SIOCSIFADDR 0x8916 0x8916 0x8020690c 0x8020690c 0x8020690c 0x8020690c 0x8020690c 0 # bsd consensus -syscon sio SIOCSIFBRDADDR 0x891a 0x891a 0x80206913 0x80206913 0x80206913 0x80206913 0x80206913 0 # bsd consensus -syscon sio SIOCSIFDSTADDR 0x8918 0x8918 0x8020690e 0x8020690e 0x8020690e 0x8020690e 0x8020690e 0 # bsd consensus -syscon sio SIOCSIFFLAGS 0x8914 0x8914 0x80206910 0x80206910 0x80206910 0x80206910 0x80206910 0 # bsd consensus -syscon sio SIOCSIFMETRIC 0x891e 0x891e 0x80206918 0x80206918 0x80206918 0x80206918 0x80206918 0 # bsd consensus -syscon sio SIOCSIFNETMASK 0x891c 0x891c 0x80206916 0x80206916 0x80206916 0x80206916 0x80206916 0 # bsd consensus -syscon sio SIOCSPGRP 0x8902 0x8902 0x80047308 0x80047308 0x80047308 0x80047308 0x80047308 0 # bsd consensus -syscon sio SIOCGIFCONF 0x8912 0x8912 0xc00c6924 0xc00c6924 0xc0106924 0xc0106924 0xc0106924 0 -syscon sio SIOCGIFMTU 0x8921 0x8921 0xc0206933 0xc0206933 0xc0206933 0xc020697e 0xc020697e 0 -syscon sio SIOCSIFMTU 0x8922 0x8922 0x80206934 0x80206934 0x80206934 0x8020697f 0x8020697f 0 -syscon sio SIOCGIFINDEX 0x8933 0x8933 0 0 0xc0206920 0 0 0 -syscon sio SIOCSIFNAME 0x8923 0x8923 0 0 0x80206928 0 0 0 -syscon sio SIOCADDDLCI 0x8980 0x8980 0 0 0 0 0 0 -syscon sio SIOCADDRT 0x890b 0x890b 0 0 0 0 0 0 -syscon sio SIOCDARP 0x8953 0x8953 0 0 0 0 0 0 -syscon sio SIOCDELDLCI 0x8981 0x8981 0 0 0 0 0 0 -syscon sio SIOCDELRT 0x890c 0x890c 0 0 0 0 0 0 -syscon sio SIOCDEVPRIVATE 0x89f0 0x89f0 0 0 0 0 0 0 -syscon sio SIOCDRARP 0x8960 0x8960 0 0 0 0 0 0 -syscon sio SIOCGARP 0x8954 0x8954 0 0 0 0 0 0 -syscon sio SIOCGIFBR 0x8940 0x8940 0 0 0 0 0 0 -syscon sio SIOCGIFCOUNT 0x8938 0x8938 0 0 0 0 0 0 -syscon sio SIOCGIFENCAP 0x8925 0x8925 0 0 0 0 0 0 -syscon sio SIOCGIFHWADDR 0x8927 0x8927 0 0 0 0 0 0 -syscon sio SIOCGIFMAP 0x8970 0x8970 0 0 0 0 0 0 -syscon sio SIOCGIFMEM 0x891f 0x891f 0 0 0 0 0 0 -syscon sio SIOCGIFNAME 0x8910 0x8910 0 0 0 0 0 0 -syscon sio SIOCGIFPFLAGS 0x8935 0x8935 0 0 0 0 0 0 -syscon sio SIOCGIFSLAVE 0x8929 0x8929 0 0 0 0 0 0 -syscon sio SIOCGIFTXQLEN 0x8942 0x8942 0 0 0 0 0 0 -syscon sio SIOCGRARP 0x8961 0x8961 0 0 0 0 0 0 -syscon sio SIOCGSTAMP 0x8906 0x8906 0 0 0 0 0 0 -syscon sio SIOCGSTAMPNS 0x8907 0x8907 0 0 0 0 0 0 -syscon sio SIOCPROTOPRIVATE 0x89e0 0x89e0 0 0 0 0 0 0 -syscon sio SIOCRTMSG 0x890d 0x890d 0 0 0 0 0 0 -syscon sio SIOCSARP 0x8955 0x8955 0 0 0 0 0 0 -syscon sio SIOCSIFBR 0x8941 0x8941 0 0 0 0 0 0 -syscon sio SIOCSIFENCAP 0x8926 0x8926 0 0 0 0 0 0 -syscon sio SIOCSIFHWADDR 0x8924 0x8924 0 0 0 0 0 0 -syscon sio SIOCSIFHWBROADCAST 0x8937 0x8937 0 0 0 0 0 0 -syscon sio SIOCSIFLINK 0x8911 0x8911 0 0 0 0 0 0 -syscon sio SIOCSIFMAP 0x8971 0x8971 0 0 0 0 0 0 -syscon sio SIOCSIFMEM 0x8920 0x8920 0 0 0 0 0 0 -syscon sio SIOCSIFPFLAGS 0x8934 0x8934 0 0 0 0 0 0 -syscon sio SIOCSIFSLAVE 0x8930 0x8930 0 0 0 0 0 0 -syscon sio SIOCSIFTXQLEN 0x8943 0x8943 0 0 0 0 0 0 -syscon sio SIOCSRARP 0x8962 0x8962 0 0 0 0 0 0 -syscon sio SIOGIFINDEX 0x8933 0x8933 0 0 0 0 0 0 +syscon ioctl FIONBIO 0x5421 0x5421 0x8004667e 0x8004667e 0x8004667e 0x8004667e 0x8004667e 0x8004667e # BSD-The New Technology consensus; FIONBIO is traditional O_NONBLOCK; see F_SETFL for re-imagined api +syscon ioctl FIOASYNC 0x5452 0x5452 0x8004667d 0x8004667d 0x8004667d 0x8004667d 0x8004667d 0x8004667d # BSD-The New Technology consensus +syscon ioctl FIONREAD 0x541b 0x541b 0x4004667f 0x4004667f 0x4004667f 0x4004667f 0x4004667f 0x4004667f # BSD-The New Technology consensus; bytes waiting in FD's input buffer +syscon ioctl FIOCLEX 0x5451 0x5451 0x20006601 0x20006601 0x20006601 0x20006601 0x20006601 0x5451 # sets "close on exec" on file descriptor the fast way; faked nt +syscon ioctl FIONCLEX 0x5450 0x5450 0x20006602 0x20006602 0x20006602 0x20006602 0x20006602 0x5450 # clears "close on exec" on file descriptor the fast way; faked nt +#syscon ioctl FIONWRITE 0x0 0x0 0x0 0x0 0x40046677 0x0 0x0 -1 # [FreeBSD Generalization] bytes queued in FD's output buffer (same as TIOCOUTQ for TTY FDs; see also SO_SNDBUF) +#syscon ioctl FIONSPACE 0x0 0x0 0x0 0x0 0x40046676 0x0 0x0 -1 # [FreeBSD Generalization] capacity of FD's output buffer, e.g. equivalent to TIOCGSERIAL w/ UART +syscon ioctl SIOCGIFCONF 0x8912 0x8912 0xc00c6924 0xc00c6924 0xc0106924 0xc0106924 0xc0106924 0 +syscon ioctl SIOCATMARK 0x8905 0x8905 0x40047307 0x40047307 0x40047307 0x40047307 0x40047307 0x40047307 # use sockatmark(); determines if oob is available; bsd consensus +syscon ioctl SIOCADDMULTI 0x8931 0x8931 0x80206931 0x80206931 0x80206931 0x80206931 0x80206931 0 # bsd consensus +syscon ioctl SIOCDELMULTI 0x8932 0x8932 0x80206932 0x80206932 0x80206932 0x80206932 0x80206932 0 # bsd consensus +syscon ioctl SIOCDIFADDR 0x8936 0x8936 0x80206919 0x80206919 0x80206919 0x80206919 0x80206919 0 # bsd consensus +syscon ioctl SIOCGIFADDR 0x8915 0x8915 0xc0206921 0xc0206921 0xc0206921 0xc0206921 0xc0206921 0 # bsd consensus +syscon ioctl SIOCGIFBRDADDR 0x8919 0x8919 0xc0206923 0xc0206923 0xc0206923 0xc0206923 0xc0206923 0 # bsd consensus +syscon ioctl SIOCGIFDSTADDR 0x8917 0x8917 0xc0206922 0xc0206922 0xc0206922 0xc0206922 0xc0206922 0 # bsd consensus +syscon ioctl SIOCGIFFLAGS 0x8913 0x8913 0xc0206911 0xc0206911 0xc0206911 0xc0206911 0xc0206911 0 # bsd consensus +syscon ioctl SIOCGIFMETRIC 0x891d 0x891d 0xc0206917 0xc0206917 0xc0206917 0xc0206917 0xc0206917 0 # bsd consensus +syscon ioctl SIOCGIFNETMASK 0x891b 0x891b 0xc0206925 0xc0206925 0xc0206925 0xc0206925 0xc0206925 0 # bsd consensus +syscon ioctl SIOCGPGRP 0x8904 0x8904 0x40047309 0x40047309 0x40047309 0x40047309 0x40047309 0 # bsd consensus +syscon ioctl SIOCSIFADDR 0x8916 0x8916 0x8020690c 0x8020690c 0x8020690c 0x8020690c 0x8020690c 0 # bsd consensus +syscon ioctl SIOCSIFBRDADDR 0x891a 0x891a 0x80206913 0x80206913 0x80206913 0x80206913 0x80206913 0 # bsd consensus +syscon ioctl SIOCSIFDSTADDR 0x8918 0x8918 0x8020690e 0x8020690e 0x8020690e 0x8020690e 0x8020690e 0 # bsd consensus +syscon ioctl SIOCSIFFLAGS 0x8914 0x8914 0x80206910 0x80206910 0x80206910 0x80206910 0x80206910 0 # bsd consensus +syscon ioctl SIOCSIFMETRIC 0x891e 0x891e 0x80206918 0x80206918 0x80206918 0x80206918 0x80206918 0 # bsd consensus +syscon ioctl SIOCSIFNETMASK 0x891c 0x891c 0x80206916 0x80206916 0x80206916 0x80206916 0x80206916 0 # bsd consensus +syscon ioctl SIOCSPGRP 0x8902 0x8902 0x80047308 0x80047308 0x80047308 0x80047308 0x80047308 0 # bsd consensus +syscon ioctl SIOCGIFMTU 0x8921 0x8921 0xc0206933 0xc0206933 0xc0206933 0xc020697e 0xc020697e 0 +syscon ioctl SIOCSIFMTU 0x8922 0x8922 0x80206934 0x80206934 0x80206934 0x8020697f 0x8020697f 0 + +syscon ioctl SIOCGIFINDEX 0x8933 0x8933 0 0 0xc0206920 0 0 0 +syscon ioctl SIOCSIFNAME 0x8923 0x8923 0 0 0x80206928 0 0 0 +syscon ioctl SIOCADDDLCI 0x8980 0x8980 0 0 0 0 0 0 +syscon ioctl SIOCADDRT 0x890b 0x890b 0 0 0 0 0 0 +syscon ioctl SIOCDARP 0x8953 0x8953 0 0 0 0 0 0 +syscon ioctl SIOCDELDLCI 0x8981 0x8981 0 0 0 0 0 0 +syscon ioctl SIOCDELRT 0x890c 0x890c 0 0 0 0 0 0 +syscon ioctl SIOCDEVPRIVATE 0x89f0 0x89f0 0 0 0 0 0 0 +syscon ioctl SIOCDRARP 0x8960 0x8960 0 0 0 0 0 0 +syscon ioctl SIOCGARP 0x8954 0x8954 0 0 0 0 0 0 +syscon ioctl SIOCGIFBR 0x8940 0x8940 0 0 0 0 0 0 +syscon ioctl SIOCGIFCOUNT 0x8938 0x8938 0 0 0 0 0 0 +syscon ioctl SIOCGIFENCAP 0x8925 0x8925 0 0 0 0 0 0 +syscon ioctl SIOCGIFHWADDR 0x8927 0x8927 0 0 0 0 0 0 +syscon ioctl SIOCGIFMAP 0x8970 0x8970 0 0 0 0 0 0 +syscon ioctl SIOCGIFMEM 0x891f 0x891f 0 0 0 0 0 0 +syscon ioctl SIOCGIFNAME 0x8910 0x8910 0 0 0 0 0 0 +syscon ioctl SIOCGIFPFLAGS 0x8935 0x8935 0 0 0 0 0 0 +syscon ioctl SIOCGIFSLAVE 0x8929 0x8929 0 0 0 0 0 0 +syscon ioctl SIOCGIFTXQLEN 0x8942 0x8942 0 0 0 0 0 0 +syscon ioctl SIOCGRARP 0x8961 0x8961 0 0 0 0 0 0 +syscon ioctl SIOCGSTAMP 0x8906 0x8906 0 0 0 0 0 0 +syscon ioctl SIOCGSTAMPNS 0x8907 0x8907 0 0 0 0 0 0 +syscon ioctl SIOCPROTOPRIVATE 0x89e0 0x89e0 0 0 0 0 0 0 +syscon ioctl SIOCRTMSG 0x890d 0x890d 0 0 0 0 0 0 +syscon ioctl SIOCSARP 0x8955 0x8955 0 0 0 0 0 0 +syscon ioctl SIOCSIFBR 0x8941 0x8941 0 0 0 0 0 0 +syscon ioctl SIOCSIFENCAP 0x8926 0x8926 0 0 0 0 0 0 +syscon ioctl SIOCSIFHWADDR 0x8924 0x8924 0 0 0 0 0 0 +syscon ioctl SIOCSIFHWBROADCAST 0x8937 0x8937 0 0 0 0 0 0 +syscon ioctl SIOCSIFLINK 0x8911 0x8911 0 0 0 0 0 0 +syscon ioctl SIOCSIFMAP 0x8971 0x8971 0 0 0 0 0 0 +syscon ioctl SIOCSIFMEM 0x8920 0x8920 0 0 0 0 0 0 +syscon ioctl SIOCSIFPFLAGS 0x8934 0x8934 0 0 0 0 0 0 +syscon ioctl SIOCSIFSLAVE 0x8930 0x8930 0 0 0 0 0 0 +syscon ioctl SIOCSIFTXQLEN 0x8943 0x8943 0 0 0 0 0 0 +syscon ioctl SIOCSRARP 0x8962 0x8962 0 0 0 0 0 0 +syscon ioctl SIOGIFINDEX 0x8933 0x8933 0 0 0 0 0 0 # socket() address families # diff --git a/libc/sysv/consts/f.h b/libc/sysv/consts/f.h index eb333e41e..7a466096b 100644 --- a/libc/sysv/consts/f.h +++ b/libc/sysv/consts/f.h @@ -3,6 +3,11 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ +/* + * full set of fcntl() commands + * many are only provided by a single platform + * will be equal to -1 when not available on host + */ extern const int F_BARRIERFSYNC; extern const int F_DUPFD; extern const int F_DUPFD_CLOEXEC; @@ -42,34 +47,28 @@ extern const int F_WRLCK; COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#define F_DUPFD 0 -#define F_GETFD 1 -#define F_SETFD 2 -#define F_GETFL 3 -#define F_SETFL 4 - +/* + * portable fcntl() commands + */ +#define F_DUPFD 0 +#define F_GETFD 1 +#define F_SETFD 2 +#define F_GETFL 3 +#define F_SETFL 4 #define F_DUPFD_CLOEXEC F_DUPFD_CLOEXEC -#define F_GETLEASE F_GETLEASE -#define F_GETLK F_GETLK -#define F_GETLK64 F_GETLK64 -#define F_GETOWN F_GETOWN -#define F_GETPATH F_GETPATH -#define F_GETPIPE_SZ F_GETPIPE_SZ -#define F_GETSIG F_GETSIG -#define F_MAXFD F_MAXFD -#define F_NOCACHE F_NOCACHE -#define F_NOTIFY F_NOTIFY -#define F_RDLCK F_RDLCK -#define F_SETLEASE F_SETLEASE -#define F_SETLK F_SETLK -#define F_SETLK64 F_SETLK64 -#define F_SETLKW F_SETLKW -#define F_SETLKW64 F_SETLKW64 -#define F_SETOWN F_SETOWN -#define F_SETPIPE_SZ F_SETPIPE_SZ -#define F_SETSIG F_SETSIG -#define F_UNLCK F_UNLCK -#define F_WRLCK F_WRLCK +/* + * posix advisory locks + * polyfilled poorly on windows + */ +#define F_SETLK F_SETLK +#define F_SETLK64 F_SETLK64 +#define F_SETLKW F_SETLKW +#define F_SETLKW64 F_SETLKW64 +#define F_GETLK F_GETLK +#define F_GETLK64 F_GETLK64 +#define F_RDLCK F_RDLCK +#define F_UNLCK F_UNLCK +#define F_WRLCK F_WRLCK #endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_F_H_ */ diff --git a/libc/sysv/consts/sio.h b/libc/sysv/consts/sio.h index bda4adb62..e5c10b84a 100644 --- a/libc/sysv/consts/sio.h +++ b/libc/sysv/consts/sio.h @@ -3,126 +3,88 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -extern const uint64_t SIOCADDDLCI; -extern const uint64_t SIOCADDMULTI; -extern const uint64_t SIOCADDRT; -extern const uint64_t SIOCATMARK; -extern const uint64_t SIOCDARP; -extern const uint64_t SIOCDELDLCI; -extern const uint64_t SIOCDELMULTI; -extern const uint64_t SIOCDELRT; -extern const uint64_t SIOCDEVPRIVATE; -extern const uint64_t SIOCDIFADDR; -extern const uint64_t SIOCDRARP; -extern const uint64_t SIOCGARP; -extern const uint64_t SIOCGIFADDR; -extern const uint64_t SIOCGIFBR; -extern const uint64_t SIOCGIFBRDADDR; -extern const uint64_t SIOCGIFCONF; -extern const uint64_t SIOCGIFCOUNT; -extern const uint64_t SIOCGIFDSTADDR; -extern const uint64_t SIOCGIFENCAP; -extern const uint64_t SIOCGIFFLAGS; -extern const uint64_t SIOCGIFHWADDR; -extern const uint64_t SIOCGIFINDEX; -extern const uint64_t SIOCGIFMAP; -extern const uint64_t SIOCGIFMEM; -extern const uint64_t SIOCGIFMETRIC; -extern const uint64_t SIOCGIFMTU; -extern const uint64_t SIOCGIFNAME; -extern const uint64_t SIOCGIFNETMASK; -extern const uint64_t SIOCGIFPFLAGS; -extern const uint64_t SIOCGIFSLAVE; -extern const uint64_t SIOCGIFTXQLEN; -extern const uint64_t SIOCGPGRP; -extern const uint64_t SIOCGRARP; -extern const uint64_t SIOCGSTAMP; -extern const uint64_t SIOCGSTAMPNS; -extern const uint64_t SIOCPROTOPRIVATE; -extern const uint64_t SIOCRTMSG; -extern const uint64_t SIOCSARP; -extern const uint64_t SIOCSIFADDR; -extern const uint64_t SIOCSIFBR; -extern const uint64_t SIOCSIFBRDADDR; -extern const uint64_t SIOCSIFDSTADDR; -extern const uint64_t SIOCSIFENCAP; -extern const uint64_t SIOCSIFFLAGS; -extern const uint64_t SIOCSIFHWADDR; -extern const uint64_t SIOCSIFHWBROADCAST; -extern const uint64_t SIOCSIFLINK; -extern const uint64_t SIOCSIFMAP; -extern const uint64_t SIOCSIFMEM; -extern const uint64_t SIOCSIFMETRIC; -extern const uint64_t SIOCSIFMTU; -extern const uint64_t SIOCSIFNAME; -extern const uint64_t SIOCSIFNETMASK; -extern const uint64_t SIOCSIFPFLAGS; -extern const uint64_t SIOCSIFSLAVE; -extern const uint64_t SIOCSIFTXQLEN; -extern const uint64_t SIOCSPGRP; -extern const uint64_t SIOCSRARP; -extern const uint64_t SIOGIFINDEX; +extern const unsigned long SIOCADDDLCI; +extern const unsigned long SIOCADDMULTI; +extern const unsigned long SIOCADDRT; +extern const unsigned long SIOCATMARK; /* use sockatmark() */ +extern const unsigned long SIOCDARP; +extern const unsigned long SIOCDELDLCI; +extern const unsigned long SIOCDELMULTI; +extern const unsigned long SIOCDELRT; +extern const unsigned long SIOCDEVPRIVATE; +extern const unsigned long SIOCDIFADDR; +extern const unsigned long SIOCDRARP; +extern const unsigned long SIOCGARP; +extern const unsigned long SIOCGIFADDR; +extern const unsigned long SIOCGIFBR; +extern const unsigned long SIOCGIFBRDADDR; +extern const unsigned long SIOCGIFCONF; +extern const unsigned long SIOCGIFCOUNT; +extern const unsigned long SIOCGIFDSTADDR; +extern const unsigned long SIOCGIFENCAP; +extern const unsigned long SIOCGIFFLAGS; +extern const unsigned long SIOCGIFHWADDR; +extern const unsigned long SIOCGIFINDEX; +extern const unsigned long SIOCGIFMAP; +extern const unsigned long SIOCGIFMEM; +extern const unsigned long SIOCGIFMETRIC; +extern const unsigned long SIOCGIFMTU; +extern const unsigned long SIOCGIFNAME; +extern const unsigned long SIOCGIFNETMASK; +extern const unsigned long SIOCGIFPFLAGS; +extern const unsigned long SIOCGIFSLAVE; +extern const unsigned long SIOCGIFTXQLEN; +extern const unsigned long SIOCGPGRP; +extern const unsigned long SIOCGRARP; +extern const unsigned long SIOCGSTAMP; +extern const unsigned long SIOCGSTAMPNS; +extern const unsigned long SIOCPROTOPRIVATE; +extern const unsigned long SIOCRTMSG; +extern const unsigned long SIOCSARP; +extern const unsigned long SIOCSIFADDR; +extern const unsigned long SIOCSIFBR; +extern const unsigned long SIOCSIFBRDADDR; +extern const unsigned long SIOCSIFDSTADDR; +extern const unsigned long SIOCSIFENCAP; +extern const unsigned long SIOCSIFFLAGS; +extern const unsigned long SIOCSIFHWADDR; +extern const unsigned long SIOCSIFHWBROADCAST; +extern const unsigned long SIOCSIFLINK; +extern const unsigned long SIOCSIFMAP; +extern const unsigned long SIOCSIFMEM; +extern const unsigned long SIOCSIFMETRIC; +extern const unsigned long SIOCSIFMTU; +extern const unsigned long SIOCSIFNAME; +extern const unsigned long SIOCSIFNETMASK; +extern const unsigned long SIOCSIFPFLAGS; +extern const unsigned long SIOCSIFSLAVE; +extern const unsigned long SIOCSIFTXQLEN; +extern const unsigned long SIOCSPGRP; +extern const unsigned long SIOCSRARP; +extern const unsigned long SIOGIFINDEX; -#define SIOCADDDLCI SIOCADDDLCI -#define SIOCADDMULTI SIOCADDMULTI -#define SIOCADDRT SIOCADDRT -#define SIOCATMARK SIOCATMARK -#define SIOCDARP SIOCDARP -#define SIOCDELDLCI SIOCDELDLCI -#define SIOCDELMULTI SIOCDELMULTI -#define SIOCDELRT SIOCDELRT -#define SIOCDEVPRIVATE SIOCDEVPRIVATE -#define SIOCDIFADDR SIOCDIFADDR -#define SIOCDRARP SIOCDRARP -#define SIOCGARP SIOCGARP -#define SIOCGIFADDR SIOCGIFADDR -#define SIOCGIFBR SIOCGIFBR -#define SIOCGIFBRDADDR SIOCGIFBRDADDR -#define SIOCGIFCONF SIOCGIFCONF -#define SIOCGIFCOUNT SIOCGIFCOUNT -#define SIOCGIFDSTADDR SIOCGIFDSTADDR -#define SIOCGIFENCAP SIOCGIFENCAP -#define SIOCGIFFLAGS SIOCGIFFLAGS -#define SIOCGIFHWADDR SIOCGIFHWADDR -#define SIOCGIFINDEX SIOCGIFINDEX -#define SIOCGIFMAP SIOCGIFMAP -#define SIOCGIFMEM SIOCGIFMEM -#define SIOCGIFMETRIC SIOCGIFMETRIC -#define SIOCGIFMTU SIOCGIFMTU -#define SIOCGIFNAME SIOCGIFNAME -#define SIOCGIFNETMASK SIOCGIFNETMASK -#define SIOCGIFPFLAGS SIOCGIFPFLAGS -#define SIOCGIFSLAVE SIOCGIFSLAVE -#define SIOCGIFTXQLEN SIOCGIFTXQLEN -#define SIOCGPGRP SIOCGPGRP -#define SIOCGRARP SIOCGRARP -#define SIOCGSTAMP SIOCGSTAMP -#define SIOCGSTAMPNS SIOCGSTAMPNS -#define SIOCPROTOPRIVATE SIOCPROTOPRIVATE -#define SIOCRTMSG SIOCRTMSG -#define SIOCSARP SIOCSARP -#define SIOCSIFADDR SIOCSIFADDR -#define SIOCSIFBR SIOCSIFBR -#define SIOCSIFBRDADDR SIOCSIFBRDADDR -#define SIOCSIFDSTADDR SIOCSIFDSTADDR -#define SIOCSIFENCAP SIOCSIFENCAP -#define SIOCSIFFLAGS SIOCSIFFLAGS -#define SIOCSIFHWADDR SIOCSIFHWADDR -#define SIOCSIFHWBROADCAST SIOCSIFHWBROADCAST -#define SIOCSIFLINK SIOCSIFLINK -#define SIOCSIFMAP SIOCSIFMAP -#define SIOCSIFMEM SIOCSIFMEM -#define SIOCSIFMETRIC SIOCSIFMETRIC -#define SIOCSIFMTU SIOCSIFMTU -#define SIOCSIFNAME SIOCSIFNAME -#define SIOCSIFNETMASK SIOCSIFNETMASK -#define SIOCSIFPFLAGS SIOCSIFPFLAGS -#define SIOCSIFSLAVE SIOCSIFSLAVE -#define SIOCSIFTXQLEN SIOCSIFTXQLEN -#define SIOCSPGRP SIOCSPGRP -#define SIOCSRARP SIOCSRARP -#define SIOGIFINDEX SIOGIFINDEX +#define SIOCGIFCONF SIOCGIFCONF +#define SIOCGIFADDR SIOCGIFADDR +#define SIOCSIFADDR SIOCSIFADDR +#define SIOCDIFADDR SIOCDIFADDR +#define SIOCGIFBRDADDR SIOCGIFBRDADDR +#define SIOCGIFNETMASK SIOCGIFNETMASK +#define SIOCGIFFLAGS SIOCGIFFLAGS +#define SIOCSIFFLAGS SIOCSIFFLAGS +#define SIOCGIFMETRIC SIOCGIFMETRIC +#define SIOCSIFMETRIC SIOCSIFMETRIC +#define SIOCSIFBRDADDR SIOCSIFBRDADDR +#define SIOCSIFNETMASK SIOCSIFNETMASK +#define SIOCGIFDSTADDR SIOCGIFDSTADDR +#define SIOCSIFDSTADDR SIOCSIFDSTADDR +#define SIOCGIFMTU SIOCGIFMTU +#define SIOCSIFMTU SIOCSIFMTU +#define SIOCGPGRP SIOCGPGRP +#define SIOCSPGRP SIOCSPGRP + +#define SIOCADDMULTI SIOCADDMULTI +#define SIOCDELMULTI SIOCDELMULTI COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/sysv/consts/termios.h b/libc/sysv/consts/termios.h index cb7ad7a10..d6e677db4 100644 --- a/libc/sysv/consts/termios.h +++ b/libc/sysv/consts/termios.h @@ -155,73 +155,74 @@ extern const uint32_t CRTSCTS; #define FF1 FF1 #define FF2 FF2 -#define CLOCAL CLOCAL -#define CREAD CREAD -#define CS5 CS5 -#define CS6 CS6 -#define CS7 CS7 -#define CS8 CS8 -#define CSIZE CSIZE -#define CSTOPB CSTOPB -#define ECHO 8 -#define ECHOCTL ECHOCTL -#define ECHOE ECHOE -#define ECHOK ECHOK -#define ECHOKE ECHOKE -#define ECHONL ECHONL -#define ECHOPRT ECHOPRT -#define EXTPROC EXTPROC -#define FLUSHO FLUSHO -#define HUPCL HUPCL -#define ICANON ICANON -#define IEXTEN IEXTEN -#define ISIG ISIG -#define IUCLC IUCLC -#define IUTF8 IUTF8 -#define IXOFF IXOFF -#define IXON IXON -#define NOFLSH NOFLSH -#define OCRNL OCRNL -#define OFDEL OFDEL -#define OFILL OFILL -#define OLCUC OLCUC -#define ONLCR ONLCR -#define ONLRET ONLRET -#define ONOCR ONOCR -#define PARENB PARENB -#define PARODD PARODD -#define PENDIN PENDIN -#define TIOCCONS TIOCCONS -#define TIOCGETD TIOCGETD -#define TIOCGWINSZ TIOCGWINSZ -#define TIOCNOTTY TIOCNOTTY -#define TIOCNXCL TIOCNXCL -#define TIOCOUTQ TIOCOUTQ -#define TIOCSCTTY TIOCSCTTY -#define TIOCSETD TIOCSETD -#define TIOCSIG TIOCSIG -#define TIOCSPGRP TIOCSPGRP -#define TIOCSTI TIOCSTI -#define TIOCSWINSZ TIOCSWINSZ -#define TOSTOP TOSTOP -#define VDISCARD VDISCARD -#define VEOF VEOF -#define VEOL VEOL -#define VEOL2 VEOL2 -#define VERASE VERASE -#define VINTR VINTR -#define VKILL VKILL -#define VLNEXT VLNEXT -#define VMIN VMIN -#define VQUIT VQUIT -#define VREPRINT VREPRINT -#define VSTART VSTART -#define VSTOP VSTOP -#define VSUSP VSUSP -#define VSWTC VSWTC -#define VTIME VTIME -#define VWERASE VWERASE -#define XCASE XCASE +#define CLOCAL CLOCAL +#define CREAD CREAD +#define CS5 CS5 +#define CS6 CS6 +#define CS7 CS7 +#define CS8 CS8 +#define CSIZE CSIZE +#define CSTOPB CSTOPB +#define ECHO 8 +#define ECHOCTL ECHOCTL +#define ECHOE ECHOE +#define ECHOK ECHOK +#define ECHOKE ECHOKE +#define ECHONL ECHONL +#define ECHOPRT ECHOPRT +#define EXTPROC EXTPROC +#define FLUSHO FLUSHO +#define HUPCL HUPCL +#define ICANON ICANON +#define IEXTEN IEXTEN +#define ISIG ISIG +#define IUCLC IUCLC +#define IUTF8 IUTF8 +#define IXOFF IXOFF +#define IXON IXON +#define NOFLSH NOFLSH +#define OCRNL OCRNL +#define OFDEL OFDEL +#define OFILL OFILL +#define OLCUC OLCUC +#define ONLCR ONLCR +#define ONLRET ONLRET +#define ONOCR ONOCR +#define PARENB PARENB +#define PARODD PARODD +#define PENDIN PENDIN +#define TOSTOP TOSTOP +#define VDISCARD VDISCARD +#define VEOF VEOF +#define VEOL VEOL +#define VEOL2 VEOL2 +#define VERASE VERASE +#define VINTR VINTR +#define VKILL VKILL +#define VLNEXT VLNEXT +#define VMIN VMIN +#define VQUIT VQUIT +#define VREPRINT VREPRINT +#define VSTART VSTART +#define VSTOP VSTOP +#define VSUSP VSUSP +#define VSWTC VSWTC +#define VTIME VTIME +#define VWERASE VWERASE +#define XCASE XCASE + +/* terminal ioctls */ +#define TIOCGWINSZ TIOCGWINSZ /* get tty dimensions */ +#define TIOCSWINSZ TIOCSWINSZ /* set tty dimensions */ +#define TIOCCONS TIOCCONS /* redirect terminal */ +#define TIOCGETD TIOCGETD /* get line discipline */ +#define TIOCSETD TIOCSETD /* set line discipline */ +#define TIOCNOTTY TIOCNOTTY /* give up terminal */ +#define TIOCNXCL TIOCNXCL /* disable exclusive mode */ +#define TIOCOUTQ TIOCOUTQ /* bytes in output buffer */ +#define TIOCSCTTY TIOCSCTTY /* make controlling terminal */ +#define TIOCSIG TIOCSIG /* generate pty signal */ +#define TIOCSTI TIOCSTI /* insert fake tty input */ /* tcsetattr() */ #define TCSANOW 0 diff --git a/test/libc/calls/ioctl_siocgifconf_test.c b/test/libc/calls/ioctl_test.c similarity index 96% rename from test/libc/calls/ioctl_siocgifconf_test.c rename to test/libc/calls/ioctl_test.c index 54c1372cd..feef5501d 100644 --- a/test/libc/calls/ioctl_siocgifconf_test.c +++ b/test/libc/calls/ioctl_test.c @@ -1,7 +1,7 @@ /*-*- 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 2021 Justine Alexandra Roberts Tunney │ +│ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ @@ -16,14 +16,13 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/intrin/bits.h" #include "libc/calls/calls.h" #include "libc/calls/internal.h" -#include "libc/calls/ioctl.h" +#include "libc/intrin/bits.h" #include "libc/log/check.h" #include "libc/log/log.h" -#include "libc/mem/mem.h" #include "libc/mem/gc.internal.h" +#include "libc/mem/mem.h" #include "libc/sock/sock.h" #include "libc/sock/struct/ifconf.h" #include "libc/sock/struct/ifreq.h" @@ -34,7 +33,7 @@ #include "libc/sysv/consts/sock.h" #include "libc/testlib/testlib.h" -TEST(ioctl_siocgifconf, test) { +TEST(siocgifconf, test) { size_t n; char *data; int socketfd; diff --git a/test/libc/calls/pledge_test.c b/test/libc/calls/pledge_test.c index 499c8273f..317fa8b06 100644 --- a/test/libc/calls/pledge_test.c +++ b/test/libc/calls/pledge_test.c @@ -18,7 +18,6 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/internal.h" -#include "libc/calls/ioctl.h" #include "libc/calls/pledge.internal.h" #include "libc/calls/struct/bpf.internal.h" #include "libc/calls/struct/filter.internal.h" diff --git a/test/libc/calls/test.mk b/test/libc/calls/test.mk index 17329d6e8..cf4d6bab3 100644 --- a/test/libc/calls/test.mk +++ b/test/libc/calls/test.mk @@ -149,7 +149,7 @@ o/$(MODE)/test/libc/calls/zipread.com.zip.o: private \ -B # TODO(jart): Have pledge() support SIOCGIFCONF -o/$(MODE)/test/libc/calls/ioctl_siocgifconf_test.com.runs: \ +o/$(MODE)/test/libc/calls/ioctl_test.com.runs: \ private .PLEDGE = o/$(MODE)/test/libc/calls/poll_test.com.runs: \ diff --git a/third_party/finger/display.c b/third_party/finger/display.c index d9e93f93c..f1f48c18e 100644 --- a/third_party/finger/display.c +++ b/third_party/finger/display.c @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ -#include "libc/calls/ioctl.h" +#include "libc/calls/calls.h" #include "libc/calls/struct/termios.h" #include "libc/calls/struct/winsize.h" #include "libc/calls/termios.h" diff --git a/third_party/linenoise/linenoise.c b/third_party/linenoise/linenoise.c index 472608d5d..4f7c23f7c 100644 --- a/third_party/linenoise/linenoise.c +++ b/third_party/linenoise/linenoise.c @@ -129,7 +129,6 @@ #include "third_party/linenoise/linenoise.h" #include "libc/assert.h" #include "libc/calls/calls.h" -#include "libc/calls/ioctl.h" #include "libc/calls/sig.internal.h" #include "libc/calls/struct/sigaction.h" #include "libc/calls/struct/stat.h" diff --git a/third_party/lua/lunix.c b/third_party/lua/lunix.c index e11f5f5ba..79867a7f9 100644 --- a/third_party/lua/lunix.c +++ b/third_party/lua/lunix.c @@ -21,7 +21,6 @@ #include "libc/atomic.h" #include "libc/calls/calls.h" #include "libc/calls/cp.internal.h" -#include "libc/calls/ioctl.h" #include "libc/calls/makedev.h" #include "libc/calls/pledge.h" #include "libc/calls/struct/bpf.internal.h" @@ -100,6 +99,7 @@ #include "libc/sysv/consts/sol.h" #include "libc/sysv/consts/st.h" #include "libc/sysv/consts/tcp.h" +#include "libc/sysv/consts/termios.h" #include "libc/sysv/consts/utime.h" #include "libc/sysv/consts/w.h" #include "libc/sysv/errfuns.h" diff --git a/third_party/python/Modules/fcntlmodule.c b/third_party/python/Modules/fcntlmodule.c index 0a56c35cd..a83c7cf2d 100644 --- a/third_party/python/Modules/fcntlmodule.c +++ b/third_party/python/Modules/fcntlmodule.c @@ -6,7 +6,6 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #define PY_SSIZE_T_CLEAN #include "libc/calls/calls.h" -#include "libc/calls/ioctl.h" #include "libc/calls/struct/flock.h" #include "libc/errno.h" #include "libc/sysv/consts/f.h" diff --git a/third_party/python/Modules/posixmodule.c b/third_party/python/Modules/posixmodule.c index 27259da36..e6b4a237c 100644 --- a/third_party/python/Modules/posixmodule.c +++ b/third_party/python/Modules/posixmodule.c @@ -9,7 +9,6 @@ #include "libc/assert.h" #include "libc/calls/calls.h" #include "libc/calls/internal.h" -#include "libc/calls/ioctl.h" #include "libc/calls/makedev.h" #include "libc/calls/struct/dirent.h" #include "libc/calls/struct/iovec.h" diff --git a/third_party/python/Modules/socketmodule.c b/third_party/python/Modules/socketmodule.c index 5876d96fc..7bfeac1f4 100644 --- a/third_party/python/Modules/socketmodule.c +++ b/third_party/python/Modules/socketmodule.c @@ -6,7 +6,6 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "third_party/python/Modules/socketmodule.h" #include "libc/calls/calls.h" -#include "libc/calls/ioctl.h" #include "libc/calls/weirdtypes.h" #include "libc/dce.h" #include "libc/dns/dns.h" diff --git a/third_party/python/Python/fileutils.c b/third_party/python/Python/fileutils.c index ae11d2482..04d3e8824 100644 --- a/third_party/python/Python/fileutils.c +++ b/third_party/python/Python/fileutils.c @@ -4,21 +4,20 @@ │ Python 3 │ │ https://docs.python.org/3/license.html │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "third_party/python/Include/fileutils.h" #include "libc/calls/calls.h" -#include "libc/calls/ioctl.h" #include "libc/dce.h" #include "libc/errno.h" #include "libc/nt/runtime.h" +#include "libc/str/locale.h" #include "libc/str/str.h" +#include "libc/str/unicode.h" #include "libc/sysv/consts/f.h" #include "libc/sysv/consts/fd.h" #include "libc/sysv/consts/fio.h" #include "libc/sysv/consts/o.h" -#include "libc/str/locale.h" -#include "libc/str/unicode.h" #include "third_party/python/Include/bytesobject.h" #include "third_party/python/Include/ceval.h" -#include "third_party/python/Include/fileutils.h" #include "third_party/python/Include/object.h" #include "third_party/python/Include/osdefs.h" #include "third_party/python/Include/pyerrors.h" diff --git a/third_party/quickjs/quickjs-libc.c b/third_party/quickjs/quickjs-libc.c index ecfa0245d..5bed2256a 100644 --- a/third_party/quickjs/quickjs-libc.c +++ b/third_party/quickjs/quickjs-libc.c @@ -26,7 +26,6 @@ #include "libc/assert.h" #include "libc/calls/calls.h" #include "libc/calls/internal.h" -#include "libc/calls/ioctl.h" #include "libc/calls/struct/dirent.h" #include "libc/calls/struct/sigaction.h" #include "libc/calls/struct/stat.h" diff --git a/third_party/sed/process.c b/third_party/sed/process.c index e5d2dac9e..1d9caf1cb 100644 --- a/third_party/sed/process.c +++ b/third_party/sed/process.c @@ -32,7 +32,6 @@ * SUCH DAMAGE. */ #include "libc/calls/calls.h" -#include "libc/calls/ioctl.h" #include "libc/calls/struct/winsize.h" #include "libc/errno.h" #include "libc/fmt/conv.h" diff --git a/third_party/sqlite3/os_unix.c b/third_party/sqlite3/os_unix.c index a02d4974f..1bf5b0067 100644 --- a/third_party/sqlite3/os_unix.c +++ b/third_party/sqlite3/os_unix.c @@ -117,7 +117,6 @@ #endif #if SQLITE_ENABLE_LOCKING_STYLE -#include "libc/calls/ioctl.h" #include "libc/calls/struct/winsize.h" #include "libc/sysv/consts/fd.h" #include "libc/sysv/consts/fio.h" diff --git a/third_party/unzip/ttyio.c b/third_party/unzip/ttyio.c index 3ed030c0f..bb72edcb3 100644 --- a/third_party/unzip/ttyio.c +++ b/third_party/unzip/ttyio.c @@ -33,7 +33,6 @@ #include "libc/calls/termios.h" #include "third_party/unzip/crypt.h" #include "libc/sysv/consts/termios.h" -#include "libc/calls/ioctl.h" #include "libc/calls/struct/winsize.h" #include "libc/calls/termios.h" #include "third_party/unzip/globals.h" diff --git a/third_party/zip/ttyio.c b/third_party/zip/ttyio.c index d2a7263dc..dca8e0e58 100644 --- a/third_party/zip/ttyio.c +++ b/third_party/zip/ttyio.c @@ -110,7 +110,6 @@ #if (defined(UNZIP) && !defined(FUNZIP) && defined(UNIX) && defined(MORE)) #include "libc/calls/calls.h" -#include "libc/calls/ioctl.h" #include "libc/calls/struct/winsize.h" #include "libc/sysv/consts/fd.h" #include "libc/sysv/consts/fio.h" @@ -160,7 +159,6 @@ # ifndef CMS_MVS # if (!defined(MINIX) && !defined(GOT_IOCTL_H)) #include "libc/calls/calls.h" -#include "libc/calls/ioctl.h" #include "libc/calls/struct/winsize.h" #include "libc/sysv/consts/fd.h" #include "libc/sysv/consts/fio.h" diff --git a/tool/build/compile.c b/tool/build/compile.c index a032bb073..205ca3e28 100644 --- a/tool/build/compile.c +++ b/tool/build/compile.c @@ -18,7 +18,6 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/copyfile.h" -#include "libc/calls/ioctl.h" #include "libc/calls/struct/itimerval.h" #include "libc/calls/struct/rlimit.h" #include "libc/calls/struct/rusage.h" diff --git a/tool/build/mkdeps.c b/tool/build/mkdeps.c index 7a0bd8091..50928f8d3 100644 --- a/tool/build/mkdeps.c +++ b/tool/build/mkdeps.c @@ -13,8 +13,8 @@ │ 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 OUTPATH OF OR IN CONNECTION WITH THE USE OR │ │ -PERFORMANCE OF THIS SOFTWARE. │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/errno.h" @@ -57,9 +57,48 @@ PERFORMANCE OF THIS SOFTWARE. │ "copyright 2023 justine tunney\n" \ "https://github.com/jart/cosmopolitan\n" -#define kIncludePrefix "include \"" +#define MANUAL \ + " -r o// -o OUTPUT INPUT...\n" \ + "\n" \ + "DESCRIPTION\n" \ + "\n" \ + " Generates makefile defining header dependencies.\n" \ + "\n" \ + " Includes look like this:\n" \ + "\n" \ + " - #include \"root/of/repository/foo.h\"\n" \ + " - .include \"root/of/repository/foo.inc\"\n" \ + "\n" \ + " They do NOT look like this:\n" \ + "\n" \ + " - #include \n" \ + " - #include \"foo.h\"\n" \ + " - # include \"foo.h\"\n" \ + " - #include \"foo.h\"\n" \ + "\n" \ + " Your generated make code looks like this:\n" \ + "\n" \ + " o//package/foo.o: \\\n" \ + " package/foo.c \\\n" \ + " package/foo.h \\\n" \ + " package/bar.h\n" \ + " o//package/bar.o: \\\n" \ + " package/bar.c \\\n" \ + " package/bar.h\n" \ + "\n" \ + "FLAGS\n" \ + "\n" \ + " -h show usage\n" \ + " -o OUTPUT set output path\n" \ + " -r ROOT set build output prefix, e.g. o//\n" \ + "\n" \ + "ARGUMENTS\n" \ + "\n" \ + " OUTPUT shall be makefile code\n" \ + " INPUT should be source or @args.txt\n" \ + "\n" -const char kSourceExts[][5] = {".s", ".S", ".c", ".cc", ".cpp"}; +#define kIncludePrefix "include \"" struct Source { unsigned hash; @@ -87,6 +126,8 @@ struct Edges { struct Edge *p; }; +static const char kSourceExts[][5] = {".s", ".S", ".c", ".cc", ".cpp"}; + static char *names; static unsigned counter; static const char *prog; @@ -295,24 +336,7 @@ static void LoadRelationships(int argc, char *argv[]) { } static wontreturn void ShowUsage(int rc, int fd) { - tinyprint(fd, VERSION, - "\n" - "USAGE\n" - "\n", - " ", prog, " -r o// -o OUTPUT INPUT...\n", - "\n" - "FLAGS\n" - "\n" - " -h show usage\n" - " -o OUTPUT set output path\n" - " -r ROOT set build output prefix, e.g. o//\n" - "\n" - "ARGUMENTS\n" - "\n" - " OUTPUT shall be makefile code\n" - " INPUT should be source or @args.txt\n" - "\n", - NULL); + tinyprint(fd, VERSION, "\nUSAGE\n\n ", prog, MANUAL, NULL); exit(rc); } diff --git a/tool/build/unbuffer.c b/tool/build/unbuffer.c index a9a55361c..6686b6b30 100644 --- a/tool/build/unbuffer.c +++ b/tool/build/unbuffer.c @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/ioctl.h" #include "libc/calls/struct/sigaction.h" #include "libc/calls/struct/termios.h" #include "libc/calls/struct/winsize.h" diff --git a/tool/net/redbean.c b/tool/net/redbean.c index 945b15eee..989699de2 100644 --- a/tool/net/redbean.c +++ b/tool/net/redbean.c @@ -20,7 +20,6 @@ #include "libc/assert.h" #include "libc/atomic.h" #include "libc/calls/calls.h" -#include "libc/calls/ioctl.h" #include "libc/calls/pledge.h" #include "libc/calls/struct/dirent.h" #include "libc/calls/struct/flock.h" diff --git a/tool/viz/basicidea.c b/tool/viz/basicidea.c index b85c127f6..c983db860 100644 --- a/tool/viz/basicidea.c +++ b/tool/viz/basicidea.c @@ -18,7 +18,6 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "dsp/scale/scale.h" #include "libc/calls/calls.h" -#include "libc/calls/ioctl.h" #include "libc/calls/struct/stat.h" #include "libc/calls/struct/winsize.h" #include "libc/calls/termios.h" diff --git a/tool/viz/derasterize.c b/tool/viz/derasterize.c index 762bfdd1f..60a36d6a9 100644 --- a/tool/viz/derasterize.c +++ b/tool/viz/derasterize.c @@ -19,7 +19,6 @@ #include "dsp/tty/itoa8.h" #include "libc/assert.h" #include "libc/calls/calls.h" -#include "libc/calls/ioctl.h" #include "libc/calls/struct/stat.h" #include "libc/calls/termios.h" #include "libc/fmt/conv.h" diff --git a/tool/viz/fontspace.c b/tool/viz/fontspace.c index bf7bfa618..42086072d 100644 --- a/tool/viz/fontspace.c +++ b/tool/viz/fontspace.c @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "dsp/scale/cdecimate2xuint8x8.h" -#include "libc/calls/ioctl.h" #include "libc/calls/struct/winsize.h" #include "libc/calls/termios.h" #include "libc/fmt/conv.h" diff --git a/tool/viz/life.c b/tool/viz/life.c index 93d9f2c91..617baee45 100644 --- a/tool/viz/life.c +++ b/tool/viz/life.c @@ -18,7 +18,6 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "dsp/scale/scale.h" #include "libc/calls/calls.h" -#include "libc/calls/ioctl.h" #include "libc/calls/struct/sigaction.h" #include "libc/calls/struct/termios.h" #include "libc/calls/struct/winsize.h" diff --git a/tool/viz/memzoom.c b/tool/viz/memzoom.c index 8210595ce..879745cec 100644 --- a/tool/viz/memzoom.c +++ b/tool/viz/memzoom.c @@ -18,7 +18,6 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "dsp/scale/cdecimate2xuint8x8.h" #include "libc/calls/calls.h" -#include "libc/calls/ioctl.h" #include "libc/calls/struct/sigaction.h" #include "libc/calls/struct/siginfo.h" #include "libc/calls/struct/stat.h" diff --git a/tool/viz/printansi.c b/tool/viz/printansi.c index 8855cd272..59e91f706 100644 --- a/tool/viz/printansi.c +++ b/tool/viz/printansi.c @@ -23,7 +23,6 @@ #include "dsp/tty/tty.h" #include "libc/assert.h" #include "libc/calls/calls.h" -#include "libc/calls/ioctl.h" #include "libc/calls/struct/stat.h" #include "libc/calls/struct/winsize.h" #include "libc/calls/termios.h" diff --git a/tool/viz/printimage.c b/tool/viz/printimage.c index f2e70494b..c57deb6ca 100644 --- a/tool/viz/printimage.c +++ b/tool/viz/printimage.c @@ -22,7 +22,6 @@ #include "dsp/tty/quant.h" #include "dsp/tty/tty.h" #include "libc/calls/calls.h" -#include "libc/calls/ioctl.h" #include "libc/calls/struct/stat.h" #include "libc/calls/struct/winsize.h" #include "libc/calls/termios.h" diff --git a/tool/viz/printvideo.c b/tool/viz/printvideo.c index 0af0cd4e2..a1ffeac12 100644 --- a/tool/viz/printvideo.c +++ b/tool/viz/printvideo.c @@ -26,7 +26,6 @@ #include "libc/assert.h" #include "libc/calls/calls.h" #include "libc/calls/internal.h" -#include "libc/calls/ioctl.h" #include "libc/calls/struct/framebufferfixedscreeninfo.h" #include "libc/calls/struct/framebuffervirtualscreeninfo.h" #include "libc/calls/struct/iovec.h"