mirror of
https://github.com/jart/cosmopolitan.git
synced 2026-11-08 08:08:04 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c2bf341e9 | ||
|
|
6cc9e08f1b | ||
|
|
bfb85fe6d0 | ||
|
|
2cc1d5ac4c | ||
|
|
6e582d245b | ||
|
|
2395a9eced | ||
|
|
0060940d84 | ||
|
|
1ea01fc905 | ||
|
|
c7a8cd21e9 | ||
|
|
224c12f54d | ||
|
|
be29b709b7 | ||
|
|
e14ae1642e | ||
|
|
40991ec992 | ||
|
|
97bb5a3a80 | ||
|
|
bc3d84341d | ||
|
|
c937fbb222 | ||
|
|
cdf9e8c8a3 | ||
|
|
4c40c500b8 | ||
|
|
3665232d66 | ||
|
|
775944a2d0 | ||
|
|
994e1f4386 | ||
|
|
3733b43a8f | ||
|
|
134ffee519 | ||
|
|
6c90f830d9 | ||
|
|
14731d61fa | ||
|
|
418bcb39af | ||
|
|
3f49889841 | ||
|
|
1ad2f530f9 | ||
|
|
654ceaba7d | ||
|
|
6a3330d7c9 | ||
|
|
945699694e | ||
|
|
aab4ee4072 | ||
|
|
8f5678882d | ||
|
|
9fa6725067 | ||
|
|
06f9a5b627 | ||
|
|
446a1f7c5a | ||
|
|
df08b541af | ||
|
|
e0fabd1d49 | ||
|
|
9cf2bdc9a8 | ||
|
|
ed5b763a0c | ||
|
|
22b63d0b98 | ||
|
|
6f7d0cb1c3 | ||
|
|
b69f3d2488 |
No files matched your search
@@ -61,13 +61,19 @@
|
||||
|
||||
SHELL = build/bootstrap/cocmd.com
|
||||
HOSTS ?= freebsd openbsd netbsd rhel7 rhel5 win10 xnu
|
||||
MAKEFLAGS += --no-builtin-rules
|
||||
MAKEFLAGS += -j --no-builtin-rules
|
||||
|
||||
.SUFFIXES:
|
||||
.DELETE_ON_ERROR:
|
||||
.FEATURES: output-sync
|
||||
.PHONY: all o bins check test depend tags
|
||||
|
||||
ifneq ($(m),)
|
||||
ifeq ($(MODE),)
|
||||
MODE := $(m)
|
||||
endif
|
||||
endif
|
||||
|
||||
all: o
|
||||
o: o/$(MODE)
|
||||
|
||||
@@ -88,7 +94,7 @@ o/$(MODE): \
|
||||
libc/disclaimer.inc \
|
||||
rx:build/bootstrap \
|
||||
rx:o/third_party/gcc \
|
||||
/proc/self/status \
|
||||
/proc/stat \
|
||||
rw:/dev/null \
|
||||
w:o/stack.log \
|
||||
/etc/hosts \
|
||||
@@ -128,6 +134,7 @@ include libc/mem/mem.mk #─┐
|
||||
include libc/zipos/zipos.mk # ├──DYNAMIC RUNTIME
|
||||
include third_party/gdtoa/gdtoa.mk # │ You can now use stdio
|
||||
include libc/time/time.mk # │ You can finally call malloc()
|
||||
include third_party/nsync/mem/mem.mk # │
|
||||
include libc/thread/thread.mk # │
|
||||
include libc/stdio/stdio.mk # │
|
||||
include third_party/libcxx/libcxx.mk # │
|
||||
@@ -265,98 +272,102 @@ o/$(MODE)/srcs-old.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(SRCS
|
||||
o/$(MODE)/hdrs-old.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS) $(INCS),$(dir $(x))))
|
||||
$(file >$@) $(foreach x,$(HDRS) $(INCS),$(file >>$@,$(x)))
|
||||
|
||||
TAGS: .UNSANDBOXED = 1
|
||||
TAGS: private .UNSANDBOXED = 1
|
||||
TAGS: o/$(MODE)/srcs-old.txt $(SRCS)
|
||||
@$(RM) $@
|
||||
@$(TAGS) $(TAGSFLAGS) -L $< -o $@
|
||||
|
||||
HTAGS: .UNSANDBOXED = 1
|
||||
HTAGS: private .UNSANDBOXED = 1
|
||||
HTAGS: o/$(MODE)/hdrs-old.txt $(HDRS)
|
||||
@$(RM) $@
|
||||
@build/htags -L $< -o $@
|
||||
|
||||
loc: .UNSANDBOXED = 1
|
||||
loc: private .UNSANDBOXED = 1
|
||||
loc: o/$(MODE)/tool/build/summy.com
|
||||
find -name \*.h -or -name \*.c -or -name \*.S | \
|
||||
$(XARGS) wc -l | grep total | awk '{print $$1}' | $<
|
||||
|
||||
COSMOPOLITAN_OBJECTS = \
|
||||
NET_HTTP \
|
||||
LIBC_DNS \
|
||||
LIBC_SOCK \
|
||||
LIBC_NT_WS2_32 \
|
||||
LIBC_NT_IPHLPAPI \
|
||||
LIBC_NT_MSWSOCK \
|
||||
LIBC_X \
|
||||
THIRD_PARTY_GETOPT \
|
||||
LIBC_LOG \
|
||||
LIBC_TIME \
|
||||
LIBC_ZIPOS \
|
||||
THIRD_PARTY_ZLIB \
|
||||
THIRD_PARTY_MUSL \
|
||||
LIBC_STDIO \
|
||||
THIRD_PARTY_GDTOA \
|
||||
THIRD_PARTY_REGEX \
|
||||
LIBC_MEM \
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
LIBC_RUNTIME \
|
||||
THIRD_PARTY_NSYNC \
|
||||
LIBC_ELF \
|
||||
LIBC_CALLS \
|
||||
LIBC_SYSV_CALLS \
|
||||
LIBC_NT_PSAPI \
|
||||
LIBC_NT_POWRPROF \
|
||||
LIBC_NT_PDH \
|
||||
LIBC_NT_GDI32 \
|
||||
LIBC_NT_COMDLG32 \
|
||||
LIBC_NT_URL \
|
||||
LIBC_NT_USER32 \
|
||||
LIBC_NT_NTDLL \
|
||||
LIBC_NT_ADVAPI32 \
|
||||
LIBC_FMT \
|
||||
THIRD_PARTY_COMPILER_RT \
|
||||
LIBC_THREAD \
|
||||
LIBC_TINYMATH \
|
||||
THIRD_PARTY_XED \
|
||||
LIBC_STR \
|
||||
LIBC_SYSV \
|
||||
LIBC_INTRIN \
|
||||
LIBC_NT_KERNEL32 \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_VGA
|
||||
# PLEASE: MAINTAIN TOPOLOGICAL ORDER
|
||||
# FROM HIGHEST LEVEL TO LOWEST LEVEL
|
||||
COSMOPOLITAN_OBJECTS = \
|
||||
NET_HTTP \
|
||||
LIBC_DNS \
|
||||
LIBC_SOCK \
|
||||
LIBC_NT_WS2_32 \
|
||||
LIBC_NT_IPHLPAPI \
|
||||
LIBC_NT_MSWSOCK \
|
||||
LIBC_X \
|
||||
THIRD_PARTY_GETOPT \
|
||||
LIBC_LOG \
|
||||
LIBC_TIME \
|
||||
LIBC_ZIPOS \
|
||||
THIRD_PARTY_ZLIB \
|
||||
THIRD_PARTY_MUSL \
|
||||
LIBC_STDIO \
|
||||
THIRD_PARTY_GDTOA \
|
||||
THIRD_PARTY_REGEX \
|
||||
LIBC_THREAD \
|
||||
THIRD_PARTY_NSYNC_MALLOC \
|
||||
LIBC_MEM \
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
LIBC_RUNTIME \
|
||||
THIRD_PARTY_NSYNC \
|
||||
LIBC_ELF \
|
||||
LIBC_CALLS \
|
||||
LIBC_SYSV_CALLS \
|
||||
LIBC_VGA \
|
||||
LIBC_NT_PSAPI \
|
||||
LIBC_NT_POWRPROF \
|
||||
LIBC_NT_PDH \
|
||||
LIBC_NT_GDI32 \
|
||||
LIBC_NT_COMDLG32 \
|
||||
LIBC_NT_URL \
|
||||
LIBC_NT_USER32 \
|
||||
LIBC_NT_NTDLL \
|
||||
LIBC_NT_ADVAPI32 \
|
||||
LIBC_NT_SYNCHRONIZATION \
|
||||
LIBC_FMT \
|
||||
THIRD_PARTY_COMPILER_RT \
|
||||
LIBC_TINYMATH \
|
||||
THIRD_PARTY_XED \
|
||||
LIBC_STR \
|
||||
LIBC_SYSV \
|
||||
LIBC_INTRIN \
|
||||
LIBC_NT_KERNEL32 \
|
||||
LIBC_NEXGEN32E
|
||||
|
||||
COSMOPOLITAN_HEADERS = \
|
||||
APE \
|
||||
LIBC \
|
||||
LIBC_CALLS \
|
||||
LIBC_DNS \
|
||||
LIBC_ELF \
|
||||
LIBC_FMT \
|
||||
LIBC_INTRIN \
|
||||
LIBC_LOG \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_NT \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_SOCK \
|
||||
LIBC_STDIO \
|
||||
THIRD_PARTY_NSYNC \
|
||||
THIRD_PARTY_XED \
|
||||
LIBC_STR \
|
||||
LIBC_SYSV \
|
||||
LIBC_THREAD \
|
||||
LIBC_TIME \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_X \
|
||||
LIBC_ZIPOS \
|
||||
LIBC_VGA \
|
||||
NET_HTTP \
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
THIRD_PARTY_GDTOA \
|
||||
THIRD_PARTY_GETOPT \
|
||||
THIRD_PARTY_MUSL \
|
||||
THIRD_PARTY_ZLIB \
|
||||
THIRD_PARTY_ZLIB_GZ \
|
||||
COSMOPOLITAN_HEADERS = \
|
||||
APE \
|
||||
LIBC \
|
||||
LIBC_CALLS \
|
||||
LIBC_DNS \
|
||||
LIBC_ELF \
|
||||
LIBC_FMT \
|
||||
LIBC_INTRIN \
|
||||
LIBC_LOG \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_NT \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_SOCK \
|
||||
LIBC_STDIO \
|
||||
THIRD_PARTY_NSYNC \
|
||||
THIRD_PARTY_XED \
|
||||
LIBC_STR \
|
||||
LIBC_SYSV \
|
||||
LIBC_THREAD \
|
||||
LIBC_TIME \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_X \
|
||||
LIBC_ZIPOS \
|
||||
LIBC_VGA \
|
||||
NET_HTTP \
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
THIRD_PARTY_GDTOA \
|
||||
THIRD_PARTY_GETOPT \
|
||||
THIRD_PARTY_MUSL \
|
||||
THIRD_PARTY_ZLIB \
|
||||
THIRD_PARTY_ZLIB_GZ \
|
||||
THIRD_PARTY_REGEX
|
||||
|
||||
o/$(MODE)/cosmopolitan.a: \
|
||||
@@ -370,7 +381,7 @@ o/cosmopolitan.h: \
|
||||
$(file >$(TMPDIR)/$(subst /,_,$@),libc/integral/normalize.inc $(foreach x,$(COSMOPOLITAN_HEADERS),$($(x)_HDRS)))
|
||||
@$(COMPILE) -AROLLUP -T$@ o/$(MODE)/tool/build/rollup.com @$(TMPDIR)/$(subst /,_,$@) >$@
|
||||
|
||||
o/cosmopolitan.html: .UNSANDBOXED = 1
|
||||
o/cosmopolitan.html: private .UNSANDBOXED = 1
|
||||
o/cosmopolitan.html: \
|
||||
o/$(MODE)/third_party/chibicc/chibicc.com.dbg \
|
||||
$(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS))) \
|
||||
|
||||
@@ -23,11 +23,11 @@ If you're doing your development work on Linux or BSD then you need just
|
||||
five files to get started. Here's what you do on Linux:
|
||||
|
||||
```sh
|
||||
wget https://justine.lol/cosmopolitan/cosmopolitan-amalgamation-2.0.1.zip
|
||||
unzip cosmopolitan-amalgamation-2.0.1.zip
|
||||
wget https://justine.lol/cosmopolitan/cosmopolitan-amalgamation-2.1.zip
|
||||
unzip cosmopolitan-amalgamation-2.1.zip
|
||||
printf 'main() { printf("hello world\\n"); }\n' >hello.c
|
||||
gcc -g -Os -static -nostdlib -nostdinc -fno-pie -no-pie -mno-red-zone \
|
||||
-fno-omit-frame-pointer -pg -mnop-mcount -mno-tls-direct-seg-refs \
|
||||
-fno-omit-frame-pointer -pg -mnop-mcount -mno-tls-direct-seg-refs -gdwarf-4 \
|
||||
-o hello.com.dbg hello.c -fuse-ld=bfd -Wl,-T,ape.lds -Wl,--gc-sections \
|
||||
-include cosmopolitan.h crt.o ape-no-modify-self.o cosmopolitan.a
|
||||
objcopy -S -O binary hello.com.dbg hello.com
|
||||
@@ -100,7 +100,7 @@ heavyweight features like tracing to your binaries by default. In that
|
||||
case, you may want to consider using our build system:
|
||||
|
||||
```sh
|
||||
make -j8 MODE=tiny
|
||||
make m=tiny
|
||||
```
|
||||
|
||||
Which will cause programs such as `hello.com` and `life.com` to shrink
|
||||
@@ -155,7 +155,7 @@ cd cosmopolitan
|
||||
This will build the entire repository and run all the tests:
|
||||
|
||||
```sh
|
||||
build/bootstrap/make.com -j16
|
||||
build/bootstrap/make.com
|
||||
o//examples/hello.com
|
||||
find o -name \*.com | xargs ls -rShal | less
|
||||
```
|
||||
@@ -174,7 +174,7 @@ having minimal deterministic builds. For example, if you wanted to build
|
||||
only hello.com then you could do that as follows:
|
||||
|
||||
```sh
|
||||
build/bootstrap/make.com -j16 o//examples/hello.com
|
||||
build/bootstrap/make.com o//examples/hello.com
|
||||
```
|
||||
|
||||
Sometimes it's desirable to build a subset of targets, without having to
|
||||
@@ -183,7 +183,7 @@ directory name. For example, if you wanted to build only the targets and
|
||||
subtargets of the chibicc package including its tests, you would say:
|
||||
|
||||
```sh
|
||||
build/bootstrap/make.com -j16 o//third_party/chibicc
|
||||
build/bootstrap/make.com o//third_party/chibicc
|
||||
o//third_party/chibicc/chibicc.com --help
|
||||
```
|
||||
|
||||
@@ -191,18 +191,19 @@ Cosmopolitan provides a variety of build modes. For example, if you want
|
||||
really tiny binaries (as small as 12kb in size) then you'd say:
|
||||
|
||||
```sh
|
||||
build/bootstrap/make.com -j16 MODE=tiny
|
||||
build/bootstrap/make.com m=tiny
|
||||
```
|
||||
|
||||
Here's some other build modes you can try:
|
||||
|
||||
```sh
|
||||
build/bootstrap/make.com -j16 MODE=dbg # asan + ubsan + debug
|
||||
build/bootstrap/make.com -j16 MODE=asan # production memory safety
|
||||
build/bootstrap/make.com -j16 MODE=opt # -march=native optimizations
|
||||
build/bootstrap/make.com -j16 MODE=rel # traditional release binaries
|
||||
build/bootstrap/make.com -j16 MODE=optlinux # optimal linux-only performance
|
||||
build/bootstrap/make.com -j16 MODE=tinylinux # tiniest linux-only 4kb binaries
|
||||
build/bootstrap/make.com m=dbg # asan + ubsan + debug
|
||||
build/bootstrap/make.com m=asan # production memory safety
|
||||
build/bootstrap/make.com m=opt # -march=native optimizations
|
||||
build/bootstrap/make.com m=rel # traditional release binaries
|
||||
build/bootstrap/make.com m=optlinux # optimal linux-only performance
|
||||
build/bootstrap/make.com m=fastbuild # build 28% faster w/o debugging
|
||||
build/bootstrap/make.com m=tinylinux # tiniest linux-only 4kb binaries
|
||||
```
|
||||
|
||||
For further details, see [//build/config.mk](build/config.mk).
|
||||
@@ -244,11 +245,11 @@ gdb foo.com -ex 'add-symbol-file foo.com.dbg 0x401000'
|
||||
| :--- | ---: | ---: |
|
||||
| AMD | K8 Venus | 2005 |
|
||||
| Intel | Core | 2006 |
|
||||
| Windows | Vista | 2006 |
|
||||
| Linux | 2.6.18 | 2007 |
|
||||
| Windows | 8 | 2012 |
|
||||
| Mac OS X | 15.6 | 2018 |
|
||||
| FreeBSD | 13 | 2020 |
|
||||
| OpenBSD | 6.4 | 2018 |
|
||||
| FreeBSD | 13 | 2020 |
|
||||
| NetBSD | 9.2 | 2021 |
|
||||
|
||||
## Special Thanks
|
||||
|
||||
@@ -39,7 +39,6 @@
|
||||
#include "libc/elf/def.h"
|
||||
#include "libc/macho.internal.h"
|
||||
#include "libc/nexgen32e/uart.internal.h"
|
||||
#include "libc/nexgen32e/vidya.internal.h"
|
||||
#include "libc/nt/pedef.internal.h"
|
||||
#include "libc/runtime/pc.internal.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
@@ -236,8 +235,9 @@ pc: cld
|
||||
#endif
|
||||
ljmp $0,$REAL(1f)
|
||||
1: mov %cx,%ds
|
||||
mov $IMAGE_BASE_REAL-0x0500,%cx # clears bss
|
||||
mov $0x0500>>4,%ax # struct mman
|
||||
.set mm,0x0500 # struct mman
|
||||
mov $IMAGE_BASE_REAL-mm,%cx # clears bss
|
||||
mov $mm>>4,%ax
|
||||
mov %ax,%es
|
||||
xor %ax,%ax
|
||||
xor %di,%di
|
||||
@@ -329,7 +329,7 @@ dsknfo: push %bx
|
||||
movpp %es,%ds
|
||||
xor %si,%si
|
||||
mov %si,%es
|
||||
mov $0x1510,%si # mman::pc_drive_base_table
|
||||
mov $mm+"struct mman::pc_drive_base_table",%si
|
||||
xchg %si,%di
|
||||
movsw #→ headunloadtime, headloadtime
|
||||
movsw #→ shutofftime, bytespersector
|
||||
@@ -382,11 +382,11 @@ pcread: push %ax
|
||||
add $512>>4,%si
|
||||
mov %si,%es
|
||||
inc %al # ++sector
|
||||
cmp 0x151c,%al # mman::pc_drive_last_sector
|
||||
cmp mm+"struct mman::pc_drive_last_sector",%al
|
||||
jbe 2f
|
||||
mov $1,%al
|
||||
inc %dh # ++head
|
||||
cmp 0x1520,%dh # mman::pc_drive_last_head
|
||||
cmp mm+"struct mman::pc_drive_last_head",%dh
|
||||
jbe 2f
|
||||
xor %dh,%dh
|
||||
inc %cx # ++cylinder
|
||||
@@ -485,19 +485,19 @@ ape.mbrpad:
|
||||
ape_disk:
|
||||
.stub ape.diskid,quad
|
||||
.org 0x1be,0x00
|
||||
.macro .partn x
|
||||
.stub ape.part\x\().status,byte # 0=absent / 0x80=present
|
||||
.stub ape.part\x\().first.head,byte # in low 6 bits
|
||||
.stub ape.part\x\().first.cylinder,byte
|
||||
.stub ape.part\x\().first.sector,byte
|
||||
.stub ape.part\x\().filesystem,byte
|
||||
.stub ape.part\x\().last.head,byte
|
||||
.stub ape.part\x\().last.cylinder,byte
|
||||
.stub ape.part\x\().last.sector,byte
|
||||
.stub ape.part\x\().lba,long # c₀*Cₙ + h₀*Hₙ + s₀*Sₙ
|
||||
.stub ape.part\x\().sector.count,long # sectors are 512 bytes
|
||||
.macro .partn x:req sta h0 s0 c0 fs h9 s9 c9 lba0 nsec
|
||||
.stub ape.part\x\().status,byte,\sta # 0=non-boot / 0x80=active
|
||||
.stub ape.part\x\().first.head,byte,\h0
|
||||
.stub ape.part\x\().first.sector,byte,\s0 # in low 6 bits
|
||||
.stub ape.part\x\().first.cylinder,byte,\c0
|
||||
.stub ape.part\x\().filesystem,byte,\fs
|
||||
.stub ape.part\x\().last.head,byte,\h9
|
||||
.stub ape.part\x\().last.sector,byte,\s9
|
||||
.stub ape.part\x\().last.cylinder,byte,\c9
|
||||
.stub ape.part\x\().lba,long,\lba0 # c₀*Cₙ + h₀*Hₙ + s₀*Sₙ
|
||||
.stub ape.part\x\().sector.count,long,\nsec # sectors are 512 bytes
|
||||
.endm
|
||||
.partn 1
|
||||
.partn 1,0x80,0,1,0,0x7f,0xff,0xff,0xff,0,0xffffffff
|
||||
.partn 2
|
||||
.partn 3
|
||||
.partn 4
|
||||
@@ -1289,29 +1289,39 @@ lcheck: pushf # check for i8086 / i8088 / i80186
|
||||
.endfn lcheck
|
||||
|
||||
// Gets memory map from BIOS.
|
||||
e820: mov $0x0510>>4,%di # mman::e820
|
||||
mov %di,%es
|
||||
xor %edi,%edi # es:di is destination buffer
|
||||
xor %ebx,%ebx # ebx is an api state tracker
|
||||
e820: xor %ebx,%ebx # %ebx is an api state tracker
|
||||
mov %bx,%es
|
||||
mov $mm+"struct mman::e820",%di # es:di is destination buffer
|
||||
1: mov $0xE820,%eax # magic
|
||||
mov $8+8+4+4,%ecx # sizeof(struct SmapEntry)
|
||||
mov $0x534d4150,%edx # magic number
|
||||
movl $1,8+8+4/*SmapEntry::acpi3*/(%di) # prefill ACPI attributes;
|
||||
# apparently some buggy BIOSes say
|
||||
# that they return this field, yet
|
||||
# do not fill it correctly
|
||||
int $0x15 # ax,bx,cx,dx,di → ax,bx,cx
|
||||
jc 9f # cf = unsupported or abuse
|
||||
cmp %edx,%eax # more magic means success
|
||||
jne 9f
|
||||
test %cx,%cx # discard empty results
|
||||
jz 5f
|
||||
mov 8/*LODWORD(SmapEntry::size)*/(%di),%eax
|
||||
or 8+4/*HIDWORD(SmapEntry::size)*/(%di),%eax
|
||||
jz 5f
|
||||
cmp $8+8+4+1,%cx # discard if ignore flag
|
||||
jb 4f
|
||||
testb $1/*ignore*/,8+8+4/*SmapEntry::__acpi3*/(%di)
|
||||
jnz 5f
|
||||
testb $1/*don't ignore*/,8+8+4/*SmapEntry::acpi3*/(%di)
|
||||
jz 5f
|
||||
4: add $8+8+4+4,%di # keep entry
|
||||
5: test %ebx,%ebx # last entry?
|
||||
jz 8f
|
||||
cmp $0x1000,%di
|
||||
cmp $mm+"struct mman::e820_end"-(8+8+4+4),%di
|
||||
jb 1b
|
||||
8: ret
|
||||
8: xor %ax,%ax # add a blank sentinel entry
|
||||
mov $(8+8)/2,%cx
|
||||
cld
|
||||
rep stosw
|
||||
ret
|
||||
9: mov $REAL(str.e820),%di
|
||||
call rldie
|
||||
.endfn e820
|
||||
@@ -1381,9 +1391,16 @@ a20: cli
|
||||
|
||||
// Initializes long mode paging.
|
||||
pinit: push %ds
|
||||
push %es
|
||||
#define SEG 0x79000
|
||||
mov $SEG>>4,%ax
|
||||
mov %ax,%ds
|
||||
mov %ax,%es
|
||||
xor %di,%di
|
||||
xor %ax,%ax
|
||||
mov $(0x7f000-SEG)/2,%cx
|
||||
cld
|
||||
rep stosw
|
||||
movl $0x7d000+PAGE_V+PAGE_RW,0x7e000-SEG # PDPT←PML4T (+)
|
||||
movl $0x7c000+PAGE_V+PAGE_RW,0x7e800-SEG # PDPT←PML4T (-)
|
||||
movl $0x7b000+PAGE_V+PAGE_RW,0x7d000-SEG # PDT←PDPT (+)
|
||||
@@ -1392,13 +1409,14 @@ pinit: push %ds
|
||||
movl $0x79000+PAGE_V+PAGE_RW,0x7a000-SEG # PD←PDT (-)
|
||||
mov $512,%cx # PD±2MB
|
||||
mov $PAGE_V+PAGE_RW,%eax
|
||||
xor %si,%si
|
||||
0: mov %eax,(%si)
|
||||
xor %di,%di
|
||||
0: stosl
|
||||
add $0x1000,%eax
|
||||
add $8,%si
|
||||
scasl # di += 4
|
||||
loop 0b
|
||||
mov $0x7e000,%eax # PML4T←CR3
|
||||
mov %eax,%cr3
|
||||
pop %es
|
||||
pop %ds
|
||||
ret
|
||||
.endfn pinit
|
||||
@@ -1407,7 +1425,7 @@ pinit: push %ds
|
||||
//
|
||||
// @see Intel Manual V3A §4.1.2
|
||||
golong: cli
|
||||
lidt 0x1522 # mman::bad_idt
|
||||
lidt mm+"struct mman::bad_idt"
|
||||
mov %cr4,%eax
|
||||
or $CR4_PAE|CR4_PGE|CR4_OSFXSR,%eax
|
||||
mov %eax,%cr4
|
||||
@@ -1440,7 +1458,7 @@ long: xor %eax,%eax
|
||||
xor %ebx,%ebx
|
||||
xor %ebp,%ebp
|
||||
push %rbp
|
||||
mov $0x0500,%rdi # mman
|
||||
mov $mm,%rdi
|
||||
mov %cr3,%rsi
|
||||
mov $IMAGE_BASE_REAL,%edx
|
||||
call __map_phdrs
|
||||
|
||||
+4
-2
@@ -458,6 +458,7 @@ SECTIONS {
|
||||
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_line_str 0 : { *(.debug_line_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
@@ -466,6 +467,7 @@ SECTIONS {
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
.debug_pubtypes 0 : { *(.debug_pubtypes) }
|
||||
.debug_ranges 0 : { *(.debug_ranges) }
|
||||
.debug_rnglists 0 : { *(.debug_rnglists) }
|
||||
.debug_macro 0 : { *(.debug_macro) }
|
||||
.debug_addr 0 : { *(.debug_addr) }
|
||||
.gnu.attributes 0 : { KEEP(*(.gnu.attributes)) }
|
||||
@@ -714,8 +716,8 @@ ASSERT(!DEFINED(_start16) || REAL(_end) < 65536,
|
||||
ASSERT(IS2POW(ape_stack_memsz),
|
||||
"ape_stack_memsz must be a two power");
|
||||
|
||||
ASSERT(!(ape_stack_vaddr & (ape_stack_memsz - 1)),
|
||||
"ape_stack_vaddr must have ape_stack_memsz alignment; try using STATIC_STACK_ADDR(0x700000000000 - ape_stack_memsz);");
|
||||
ASSERT(ape_stack_vaddr % ape_stack_memsz == 0,
|
||||
"ape_stack_vaddr must have ape_stack_memsz alignment; try using STATIC_STACK_ADDR(0x700000040000 - ape_stack_memsz);");
|
||||
|
||||
ASSERT(ALIGNOF(.tdata) <= TLS_ALIGNMENT && ALIGNOF(.tbss) <= TLS_ALIGNMENT,
|
||||
"_Thread_local _Alignof can't exceed TLS_ALIGNMENT");
|
||||
|
||||
@@ -65,6 +65,7 @@ o/$(MODE)/ape/ape.lds: \
|
||||
libc/intrin/bits.h \
|
||||
libc/thread/tls.h \
|
||||
libc/calls/struct/timespec.h \
|
||||
libc/thread/thread.h \
|
||||
libc/dce.h \
|
||||
libc/elf/def.h \
|
||||
libc/elf/pf2prot.internal.h \
|
||||
@@ -82,6 +83,7 @@ o/$(MODE)/ape/public/ape.lds: \
|
||||
libc/intrin/bits.h \
|
||||
libc/thread/tls.h \
|
||||
libc/calls/struct/timespec.h \
|
||||
libc/thread/thread.h \
|
||||
libc/dce.h \
|
||||
libc/elf/def.h \
|
||||
libc/elf/pf2prot.internal.h \
|
||||
|
||||
+33
-33
@@ -32,23 +32,23 @@
|
||||
// @see ape/ape.lds
|
||||
// @see winimp
|
||||
.macro .imp dll:req fn:req actual:req hint
|
||||
.dll \dll
|
||||
.section .piro.data.sort.iat.2.\dll\().2.\actual,"aw",@progbits
|
||||
.dll "\dll"
|
||||
.section ".piro.data.sort.iat.2.\dll\().2.\actual","aw",@progbits
|
||||
.type \fn,@object
|
||||
.align __SIZEOF_POINTER__
|
||||
\fn: .quad RVA((\dll\().\actual))
|
||||
\fn: .quad RVA(("\dll\().\actual"))
|
||||
.size \fn,.-\fn
|
||||
.globl \fn
|
||||
.hidden \fn
|
||||
.previous
|
||||
.section .idata.ro.ilt.\dll\().2.\actual,"a",@progbits
|
||||
.Lidata.ilt.\dll\().\actual:
|
||||
.quad RVA((\dll\().\actual))
|
||||
.type .Lidata.ilt.\dll\().\actual,@object
|
||||
.size .Lidata.ilt.\dll\().\actual,.-.Lidata.ilt.\dll\().\actual
|
||||
.section ".idata.ro.ilt.\dll\().2.\actual","a",@progbits
|
||||
".Lidata.ilt.\dll\().\actual":
|
||||
.quad RVA("\dll\().\actual")
|
||||
.type ".Lidata.ilt.\dll\().\actual",@object
|
||||
.size ".Lidata.ilt.\dll\().\actual",.-".Lidata.ilt.\dll\().\actual"
|
||||
.previous
|
||||
.section .idata.ro.hnt.\dll\().2.\actual,"a",@progbits
|
||||
\dll\().\actual:
|
||||
.section ".idata.ro.hnt.\dll\().2.\actual","a",@progbits
|
||||
"\dll\().\actual":
|
||||
.ifnb \hint # hint i.e. guess function ordinal
|
||||
.short \hint
|
||||
.else
|
||||
@@ -56,55 +56,55 @@
|
||||
.endif
|
||||
.asciz "\actual"
|
||||
.align 2 # documented requirement
|
||||
.globl \dll\().\actual
|
||||
.hidden \dll\().\actual
|
||||
.type \dll\().\actual,@object
|
||||
.size \dll\().\actual,.-\dll\().\actual
|
||||
.globl "\dll\().\actual"
|
||||
.hidden "\dll\().\actual"
|
||||
.type "\dll\().\actual",@object
|
||||
.size "\dll\().\actual",.-"\dll\().\actual"
|
||||
.previous
|
||||
.endm
|
||||
|
||||
// Defines DLL import.
|
||||
// @note this is an implementation detail of .imp
|
||||
.macro .dll name:req
|
||||
.section .idata.ro.idt.2.\name,"aG",@progbits,\name,comdat
|
||||
.equ .Lidata.idt.\name,.
|
||||
.long RVA(idata.ilt.\name) # ImportLookupTable
|
||||
.section ".idata.ro.idt.2.\name","aG",@progbits,"\name",comdat
|
||||
.equ ".Lidata.idt.\name",.
|
||||
.long RVA("idata.ilt.\name") # ImportLookupTable
|
||||
.long 0 # TimeDateStamp
|
||||
.long 0 # ForwarderChain
|
||||
.long RVA(.Lidata.str.\name) # DllNameRva
|
||||
.long RVA(idata.iat.\name) # ImportAddressTable
|
||||
.type .Lidata.idt.\name,@object
|
||||
.size .Lidata.idt.\name,.-.Lidata.idt.\name
|
||||
.long RVA(".Lidata.str.\name") # DllNameRva
|
||||
.long RVA("idata.iat.\name") # ImportAddressTable
|
||||
.type ".Lidata.idt.\name",@object
|
||||
.size ".Lidata.idt.\name",.-".Lidata.idt.\name"
|
||||
.previous
|
||||
.section .idata.ro.ilt.\name\().1,"aG",@progbits,\name,comdat
|
||||
.section ".idata.ro.ilt.\name\().1","aG",@progbits,"\name",comdat
|
||||
.align __SIZEOF_POINTER__
|
||||
.type idata.ilt.\name,@object
|
||||
idata.ilt.\name:
|
||||
.type "idata.ilt.\name",@object
|
||||
"idata.ilt.\name":
|
||||
.previous/*
|
||||
...
|
||||
decentralized content
|
||||
...
|
||||
*/.section .idata.ro.ilt.\name\().3,"aG",@progbits,\name,comdat
|
||||
*/.section ".idata.ro.ilt.\name\().3","aG",@progbits,"\name",comdat
|
||||
.quad 0
|
||||
.previous
|
||||
.section .idata.ro.hnt.\name\().1,"aG",@progbits,\name,comdat
|
||||
.section ".idata.ro.hnt.\name\().1","aG",@progbits,"\name",comdat
|
||||
.align __SIZEOF_POINTER__
|
||||
.type idata.hnt.\name,@object
|
||||
.equ idata.hnt.\name,.
|
||||
.type "idata.hnt.\name",@object
|
||||
.equ "idata.hnt.\name",.
|
||||
.previous
|
||||
.section .piro.data.sort.iat.2.\name\().1,"awG",@progbits,\name,comdat
|
||||
.section ".piro.data.sort.iat.2.\name\().1","awG",@progbits,"\name",comdat
|
||||
.align __SIZEOF_POINTER__
|
||||
.type idata.iat.\name,@object
|
||||
idata.iat.\name:
|
||||
.type "idata.iat.\name",@object
|
||||
"idata.iat.\name":
|
||||
.previous/*
|
||||
...
|
||||
decentralized content
|
||||
...
|
||||
*/.section .piro.data.sort.iat.2.\name\().3,"awG",@progbits,\name,comdat
|
||||
*/.section ".piro.data.sort.iat.2.\name\().3","awG",@progbits,"\name",comdat
|
||||
.quad 0
|
||||
.previous
|
||||
.section .rodata.str1.1,"aSM",@progbits,1
|
||||
.Lidata.str.\name:
|
||||
".Lidata.str.\name":
|
||||
.asciz "\name\().dll"
|
||||
.previous
|
||||
.endm
|
||||
|
||||
+2
-2
@@ -36,8 +36,8 @@
|
||||
*/
|
||||
#define REAL(x) ((x) - (IMAGE_BASE_VIRTUAL - IMAGE_BASE_REAL))
|
||||
|
||||
#if IMAGE_BASE_VIRTUAL % 0x200000 != 0
|
||||
#error "IMAGE_BASE_VIRTUAL must be 2mb aligned"
|
||||
#if IMAGE_BASE_VIRTUAL % 0x1000 != 0
|
||||
#error "IMAGE_BASE_VIRTUAL must be 4kb aligned"
|
||||
#endif
|
||||
#if IMAGE_BASE_PHYSICAL % 0x1000 != 0
|
||||
#error "IMAGE_BASE_PHYSICAL must be 4kb aligned"
|
||||
|
||||
Binary file not shown.
+43
-1
@@ -102,7 +102,7 @@ endif
|
||||
# - Larger binaries
|
||||
#
|
||||
ifeq ($(MODE), asan)
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) -O2
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) -O2 -DSYSDEBUG
|
||||
CONFIG_COPTS += -fsanitize=address
|
||||
TARGET_ARCH ?= -msse3
|
||||
endif
|
||||
@@ -152,6 +152,10 @@ CONFIG_CCFLAGS += \
|
||||
-fomit-frame-pointer \
|
||||
-momit-leaf-frame-pointer \
|
||||
-foptimize-sibling-calls
|
||||
CONFIG_OFLAGS += \
|
||||
-g0
|
||||
CONFIG_LDFLAGS += \
|
||||
-S
|
||||
TARGET_ARCH ?= \
|
||||
-msse3
|
||||
PYFLAGS += \
|
||||
@@ -180,6 +184,10 @@ CONFIG_CPPFLAGS += \
|
||||
-DSUPPORT_VECTOR=1
|
||||
DEFAULT_COPTS += \
|
||||
-mred-zone
|
||||
CONFIG_OFLAGS += \
|
||||
-g0
|
||||
CONFIG_LDFLAGS += \
|
||||
-S
|
||||
CONFIG_CCFLAGS += \
|
||||
-Os \
|
||||
-fno-align-functions \
|
||||
@@ -212,6 +220,10 @@ CONFIG_CPPFLAGS += \
|
||||
-DSUPPORT_VECTOR=113
|
||||
DEFAULT_COPTS += \
|
||||
-mred-zone
|
||||
CONFIG_OFLAGS += \
|
||||
-g0
|
||||
CONFIG_LDFLAGS += \
|
||||
-S
|
||||
CONFIG_CCFLAGS += \
|
||||
-Os \
|
||||
-fno-align-functions \
|
||||
@@ -249,6 +261,10 @@ CONFIG_CCFLAGS += \
|
||||
-fno-align-jumps \
|
||||
-fno-align-labels \
|
||||
-fno-align-loops
|
||||
CONFIG_OFLAGS += \
|
||||
-g0
|
||||
CONFIG_LDFLAGS += \
|
||||
-S
|
||||
TARGET_ARCH ?= \
|
||||
-msse3
|
||||
endif
|
||||
@@ -278,10 +294,36 @@ CONFIG_CCFLAGS += \
|
||||
-fno-align-jumps \
|
||||
-fno-align-labels \
|
||||
-fno-align-loops
|
||||
CONFIG_OFLAGS += \
|
||||
-g0
|
||||
CONFIG_LDFLAGS += \
|
||||
-S
|
||||
TARGET_ARCH ?= \
|
||||
-msse3
|
||||
endif
|
||||
|
||||
# GCC11 Mode
|
||||
# https://justine.lol/compilers/x86_64-linux-musl__x86_64-linux-musl__g++-11.2.0.tar.xz
|
||||
ifeq ($(MODE), gcc11)
|
||||
.UNVEIL += rx:/opt/gcc11
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) $(FTRACE) -DSYSDEBUG -O2
|
||||
AS = /opt/gcc11/bin/x86_64-linux-musl-as
|
||||
CC = /opt/gcc11/bin/x86_64-linux-musl-gcc
|
||||
CXX = /opt/gcc11/bin/x86_64-linux-musl-g++
|
||||
CXXFILT = /opt/gcc11/bin/x86_64-linux-musl-c++filt
|
||||
LD = /opt/gcc11/bin/x86_64-linux-musl-ld.bfd
|
||||
NM = /opt/gcc11/bin/x86_64-linux-musl-nm
|
||||
GCC = /opt/gcc11/bin/x86_64-linux-musl-gcc
|
||||
STRIP = /opt/gcc11/bin/x86_64-linux-musl-strip
|
||||
OBJCOPY = /opt/gcc11/bin/x86_64-linux-musl-objcopy
|
||||
OBJDUMP = /opt/gcc11/bin/x86_64-linux-musl-objdump
|
||||
ADDR2LINE = /opt/gcc11/bin/x86_64-linux-musl-addr2line
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) $(FTRACE) -O2 -Wno-stringop-overread
|
||||
CONFIG_CFLAGS += -Wno-old-style-definition
|
||||
CONFIG_CPPFLAGS += -DNDEBUG -DSYSDEBUG
|
||||
TARGET_ARCH ?= -msse3
|
||||
endif
|
||||
|
||||
# LLVM Mode
|
||||
ifeq ($(MODE), llvm)
|
||||
TARGET_ARCH ?= -msse3
|
||||
|
||||
@@ -148,6 +148,7 @@ DEFAULT_CCFLAGS = \
|
||||
|
||||
DEFAULT_OFLAGS = \
|
||||
-g \
|
||||
-gdwarf-4 \
|
||||
-gdescribe-dies
|
||||
|
||||
DEFAULT_COPTS = \
|
||||
|
||||
+8
-8
@@ -163,15 +163,15 @@ o/$(MODE)%/.zip.o: %
|
||||
# and it would be too costly in terms of make latency to have every
|
||||
# header file depend on $(HDRS) and $(INCS).
|
||||
|
||||
o/%.h.ok: .UNSANDBOXED = 1
|
||||
o/%.h.ok: private .UNSANDBOXED = 1
|
||||
o/%.h.ok: %.h
|
||||
@$(COMPILE) -ACHECK.h $(COMPILE.c) -xc -g0 -o $@ $<
|
||||
|
||||
o/$(MODE)/%.h.ok: .UNSANDBOXED = 1
|
||||
o/$(MODE)/%.h.ok: private .UNSANDBOXED = 1
|
||||
o/$(MODE)/%.h.ok: %.h
|
||||
@$(COMPILE) -ACHECK.h $(COMPILE.c) -xc -g0 -o $@ $<
|
||||
|
||||
o/$(MODE)/%.hh.ok: .UNSANDBOXED = 1
|
||||
o/$(MODE)/%.hh.ok: private .UNSANDBOXED = 1
|
||||
o/$(MODE)/%.hh.ok: %.hh
|
||||
@$(COMPILE) -ACHECK.h $(COMPILE.cxx) -xc++ -g0 -o $@ $<
|
||||
|
||||
@@ -179,7 +179,7 @@ o/%.okk: .UNSANDBOXED = 1
|
||||
o/%.okk: %
|
||||
@$(COMPILE) -ACHECK.h $(COMPILE.cxx) -xc++ -g0 -o $@ $<
|
||||
|
||||
o/$(MODE)/%.okk: .UNSANDBOXED = 1
|
||||
o/$(MODE)/%.okk: private .UNSANDBOXED = 1
|
||||
o/$(MODE)/%.okk: %
|
||||
@$(COMPILE) -ACHECK.h $(COMPILE.cxx) -xc++ -g0 -o $@ $<
|
||||
|
||||
@@ -207,19 +207,19 @@ MAKE_SYMTAB_ZIP = \
|
||||
################################################################################
|
||||
# EMACS ASSEMBLY GENERATION
|
||||
|
||||
o/$(MODE)/%-gcc.asm: .UNSANDBOXED = 1
|
||||
o/$(MODE)/%-gcc.asm: private .UNSANDBOXED = 1
|
||||
o/$(MODE)/%-gcc.asm: %.c
|
||||
@$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $<
|
||||
|
||||
o/$(MODE)/%-gcc.asm: .UNSANDBOXED = 1
|
||||
o/$(MODE)/%-gcc.asm: private .UNSANDBOXED = 1
|
||||
o/$(MODE)/%-gcc.asm: %.cc
|
||||
@$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.cxx) -S -g0 $(OUTPUT_OPTION) $<
|
||||
|
||||
o/$(MODE)/%-clang.asm: .UNSANDBOXED = 1
|
||||
o/$(MODE)/%-clang.asm: private .UNSANDBOXED = 1
|
||||
o/$(MODE)/%-clang.asm: %.c
|
||||
@$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $<
|
||||
|
||||
o/$(MODE)/%-clang.asm: CC = $(CLANG)
|
||||
o/$(MODE)/%-clang.asm: .UNSANDBOXED = 1
|
||||
o/$(MODE)/%-clang.asm: private .UNSANDBOXED = 1
|
||||
o/$(MODE)/%-clang.asm: %.cc
|
||||
@$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.cxx) -S -g0 $(OUTPUT_OPTION) $<
|
||||
@@ -21,14 +21,14 @@
|
||||
#include "dsp/core/ituround.h"
|
||||
#include "dsp/core/q.h"
|
||||
#include "dsp/core/twixt8.h"
|
||||
#include "libc/intrin/bsr.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
@@ -203,8 +203,8 @@ void *Gyarados(long dyw, long dxw, int dst[dyw][dxw], long syw, long sxw,
|
||||
CHECK_LE(sxn, sxw);
|
||||
CHECK_LE(dyn, dyw);
|
||||
CHECK_LE(dxn, dxw);
|
||||
CHECK_LT(bsrl(syn) + bsrl(sxn), 32);
|
||||
CHECK_LT(bsrl(dyn) + bsrl(dxn), 32);
|
||||
CHECK_LT(_bsrl(syn) + _bsrl(sxn), 32);
|
||||
CHECK_LT(_bsrl(dyn) + _bsrl(dxn), 32);
|
||||
CHECK_LE(dyw, 0x7fff);
|
||||
CHECK_LE(dxw, 0x7fff);
|
||||
CHECK_LE(syw, 0x7fff);
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@
|
||||
* @see ttyconfig(), ttyrestore()
|
||||
*/
|
||||
int ttyconfig(int ttyfd, ttyconf_f fn, int64_t arg,
|
||||
const struct termios *opt_out_oldconf) {
|
||||
struct termios *opt_out_oldconf) {
|
||||
struct termios conf[2];
|
||||
if (tcgetattr(ttyfd, &conf[0]) != -1 &&
|
||||
fn(memcpy(&conf[1], &conf[0], sizeof(conf[0])), arg) != -1 &&
|
||||
|
||||
+4
-3
@@ -83,10 +83,11 @@ int ttyident(struct TtyIdent *ti, int ttyinfd, int ttyoutfd) {
|
||||
if (ttyident_probe(ti, ttyinfd, ttyoutfd, "\e[>c") != -1) {
|
||||
rc = 0;
|
||||
memset(&outer, 0, sizeof(outer));
|
||||
if (ti->id == 83 /* GNU Screen */ && (ti->next || weaken(malloc)) &&
|
||||
if (ti->id == 83 /* GNU Screen */ && (ti->next || _weaken(malloc)) &&
|
||||
ttyident_probe(&outer, ttyinfd, ttyoutfd, "\eP\e[>c\e\\") != -1 &&
|
||||
(ti->next = (ti->next ? ti->next
|
||||
: weaken(malloc)(sizeof(struct TtyIdent))))) {
|
||||
(ti->next =
|
||||
(ti->next ? ti->next
|
||||
: _weaken(malloc)(sizeof(struct TtyIdent))))) {
|
||||
memcpy(ti->next, &outer, sizeof(outer));
|
||||
} else {
|
||||
free_s(&ti->next);
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/tty.h"
|
||||
#include "libc/mem/arraylist2.internal.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
/* TODO(jart): DELETE */
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ int ttysendtitle(int, const char *, const struct TtyIdent *);
|
||||
int ttyident(struct TtyIdent *, int, int);
|
||||
void ttyidentclear(struct TtyIdent *);
|
||||
char *ttydescribe(char *, size_t, const struct TtyIdent *);
|
||||
int ttyconfig(int, ttyconf_f, int64_t, const struct termios *);
|
||||
int ttyconfig(int, ttyconf_f, int64_t, struct termios *);
|
||||
int ttyrestore(int, const struct termios *);
|
||||
int ttysetrawdeadline(struct termios *, int64_t);
|
||||
int ttysetrawmode(struct termios *, int64_t);
|
||||
|
||||
+2
-1
@@ -25,7 +25,7 @@
|
||||
#include "libc/calls/ucontext.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "libc/x/xsigaction.h"
|
||||
|
||||
/* TODO(jart): DELETE */
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
|
||||
int n;
|
||||
int shown[64];
|
||||
|
||||
void show(int clock) {
|
||||
int i;
|
||||
struct timespec ts;
|
||||
if (clock == 127) return;
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (shown[i] == clock) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
shown[n++] = clock;
|
||||
if (clock_getres(clock, &ts) != -1) {
|
||||
kprintf("%s %'ld ns\n", DescribeClockName(clock), _timespec_tonanos(ts));
|
||||
} else {
|
||||
kprintf("%s %s\n", DescribeClockName(clock), _strerrno(errno));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
show(CLOCK_REALTIME);
|
||||
show(CLOCK_REALTIME_FAST);
|
||||
show(CLOCK_REALTIME_PRECISE);
|
||||
show(CLOCK_MONOTONIC);
|
||||
show(CLOCK_MONOTONIC_RAW);
|
||||
show(CLOCK_MONOTONIC_FAST);
|
||||
show(CLOCK_MONOTONIC_PRECISE);
|
||||
show(CLOCK_PROCESS_CPUTIME_ID);
|
||||
show(CLOCK_THREAD_CPUTIME_ID);
|
||||
show(CLOCK_PROF);
|
||||
show(CLOCK_BOOTTIME);
|
||||
show(CLOCK_REALTIME_ALARM);
|
||||
show(CLOCK_BOOTTIME_ALARM);
|
||||
show(CLOCK_TAI);
|
||||
show(CLOCK_UPTIME);
|
||||
show(CLOCK_UPTIME_PRECISE);
|
||||
show(CLOCK_UPTIME_FAST);
|
||||
show(CLOCK_SECOND);
|
||||
}
|
||||
+1
-1
@@ -13,7 +13,7 @@
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
+5
-2
@@ -9,18 +9,21 @@
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/dirent.h"
|
||||
#include "libc/calls/struct/rusage.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/log/appendresourcereport.internal.h"
|
||||
#include "libc/log/internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/append.internal.h"
|
||||
#include "libc/stdio/append.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
@@ -151,7 +154,7 @@ int main(int argc, char *argv[]) {
|
||||
while ((line = linenoiseWithHistory(prompt, "cmd"))) {
|
||||
n = 0;
|
||||
start = line;
|
||||
if (startswith(start, "time ")) {
|
||||
if (_startswith(start, "time ")) {
|
||||
timeit = true;
|
||||
start += 5;
|
||||
} else {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
|
||||
+6
-5
@@ -7,7 +7,6 @@
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/dce.h"
|
||||
@@ -15,15 +14,16 @@
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/stdio/rand.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/goodsocket.internal.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/stdio/append.internal.h"
|
||||
#include "libc/stdio/append.h"
|
||||
#include "libc/stdio/rand.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/slice.h"
|
||||
#include "libc/str/str.h"
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "libc/sysv/consts/tcp.h"
|
||||
#include "libc/time/struct/tm.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "libc/x/xsigaction.h"
|
||||
#include "net/http/http.h"
|
||||
#include "net/http/url.h"
|
||||
#include "net/https/https.h"
|
||||
@@ -182,7 +183,7 @@ int main(int argc, char *argv[]) {
|
||||
struct Url url;
|
||||
char *host, *port;
|
||||
bool usessl = false;
|
||||
_gc(ParseUrl(urlarg, -1, &url));
|
||||
_gc(ParseUrl(urlarg, -1, &url, kUrlPlus));
|
||||
_gc(url.params.p);
|
||||
if (url.scheme.n) {
|
||||
if (url.scheme.n == 5 && !memcasecmp(url.scheme.p, "https", 5)) {
|
||||
|
||||
+2
-1
@@ -8,7 +8,8 @@
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "net/http/escape.h"
|
||||
|
||||
+2
-2
@@ -7,9 +7,9 @@
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "libc/x/xiso8601.h"
|
||||
|
||||
/**
|
||||
* @fileoverview ISO-8601 international high-precision timestamp printer.
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/zlib/zlib.h"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
/**
|
||||
|
||||
@@ -81,6 +81,7 @@ EXAMPLES_DIRECTDEPS = \
|
||||
THIRD_PARTY_MBEDTLS \
|
||||
THIRD_PARTY_MUSL \
|
||||
THIRD_PARTY_NSYNC \
|
||||
THIRD_PARTY_NSYNC_MEM \
|
||||
THIRD_PARTY_QUICKJS \
|
||||
THIRD_PARTY_STB \
|
||||
THIRD_PARTY_XED \
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/nt/nt/process.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/rand.h"
|
||||
|
||||
@@ -7,14 +7,11 @@
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/math.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
STATIC_YOINK("vga_console");
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
volatile long double x = -.5;
|
||||
volatile long double y = 1.5;
|
||||
printf("Hello World! %.19Lg\n", atan2l(x, y));
|
||||
return 0;
|
||||
char *p = _gc(malloc(64));
|
||||
strcpy(p, "this memory is free'd when main() returns");
|
||||
}
|
||||
@@ -7,20 +7,21 @@
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/rand.h"
|
||||
#include "libc/stdio/xorshift.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/stdio/xorshift.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/ex.h"
|
||||
#include "libc/sysv/consts/exit.h"
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
|
||||
+1
-2
@@ -14,8 +14,7 @@
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/itimer.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "libc/x/xsigaction.h"
|
||||
|
||||
const struct itimerval kHertz = {
|
||||
{1, 0},
|
||||
|
||||
+6
-4
@@ -9,9 +9,11 @@
|
||||
#endif
|
||||
#include "libc/dce.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "libc/x/xasprintf.h"
|
||||
#include "net/http/escape.h"
|
||||
#include "net/http/http.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
@@ -43,15 +45,15 @@ void PrintImg(const char *path) {
|
||||
size_t n;
|
||||
int opt, i, yn, xn, cn, w, h;
|
||||
void *img, *pix, *src, *mime;
|
||||
if (!(img = gc(xslurp(path, &n)))) exit(2);
|
||||
if (!(pix = gc(stbi_load_from_memory(img, n, &xn, &yn, &cn, 0)))) exit(3);
|
||||
if (!(img = _gc(xslurp(path, &n)))) exit(2);
|
||||
if (!(pix = _gc(stbi_load_from_memory(img, n, &xn, &yn, &cn, 0)))) exit(3);
|
||||
if (linktag) {
|
||||
printf("<a href=\"%s\"\n >", path);
|
||||
}
|
||||
src = path;
|
||||
if (datauri) {
|
||||
src = xasprintf("data:%s;base64,%s", FindContentType(path, -1),
|
||||
gc(EncodeBase64(img, n, &n)));
|
||||
_gc(EncodeBase64(img, n, &n)));
|
||||
}
|
||||
w = (xn + (1 << scale) / 2) >> scale;
|
||||
h = (yn + (1 << scale) / 2) >> scale;
|
||||
|
||||
@@ -1,160 +0,0 @@
|
||||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/mem/alg.h"
|
||||
#include "libc/mem/arraylist.internal.h"
|
||||
#include "libc/mem/critbit0.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/tpdecode.internal.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
STATIC_YOINK("zip_uri_support");
|
||||
|
||||
/**
|
||||
* @fileoverview Simple Interactive Spell Checker.
|
||||
*
|
||||
* This is an attempt to get spell checking to work in Emacs across
|
||||
* platforms. While the computer science behind spell checking is very
|
||||
* simple, unfortunately Emacs probes all these System Five spell progs
|
||||
* similar to how websites have been known to probe User-Agent strings.
|
||||
*
|
||||
* Here's how we believe the repl works:
|
||||
*
|
||||
* $ make -j8 o//examples/ispell.com
|
||||
* $ o//examples/ispell.com
|
||||
* @(#) Cosmopolitan Ispell Version 3.4.00 8 Feb 2015
|
||||
* word: hello
|
||||
* ok
|
||||
* word: héllo
|
||||
* how about: hills, hello, hilly, jello
|
||||
* word: lova
|
||||
* how about: diva, dona, dora, dove, elva, fora, hove, iota
|
||||
* word: hecruhecrue
|
||||
* not found
|
||||
*
|
||||
* The dictionary for this program is embedded as a text file within the
|
||||
* zip structure of the binary. It can be edited after distribution.
|
||||
*
|
||||
* It's possible to go even fancier than what this code is doing, by
|
||||
* using cmudict phonemes, bloom filters, unicode tables e.g. e vs. é,
|
||||
* and even doing ML similar to Google's online spell checker.
|
||||
*
|
||||
* TODO: Figure out why Emacs rejects this interface.
|
||||
*/
|
||||
|
||||
#define MISSING_LETTER_DISTANCE 5
|
||||
#define MAX_NEARBY_WORD_DISTANCE 6
|
||||
#define MAX_NEARBY_RESULTS 8
|
||||
|
||||
FILE *f;
|
||||
char *line;
|
||||
size_t linesize;
|
||||
const char *query;
|
||||
struct critbit0 words; /* does O(log 𝑛) fast path lookup */
|
||||
|
||||
struct NearbyWords {
|
||||
size_t i, n;
|
||||
struct WordMatch {
|
||||
long dist;
|
||||
char *word;
|
||||
} * p;
|
||||
} nearby;
|
||||
|
||||
long WordDistance(const char *a, const char *b) {
|
||||
long dist;
|
||||
int gota, gotb;
|
||||
unsigned long h, p;
|
||||
wint_t chara, charb;
|
||||
dist = p = 0;
|
||||
for (;;) {
|
||||
gota = abs(tpdecode(a, &chara)); /* parses utf-8 multibyte characters */
|
||||
gotb = abs(tpdecode(b, &charb)); /* abs() handles -1, always yields � */
|
||||
if (!chara && !charb) break;
|
||||
if (!chara || !charb) {
|
||||
dist += MISSING_LETTER_DISTANCE;
|
||||
} else if ((h = hamming(chara, charb))) {
|
||||
dist += h + p++; /* penalize multiple mismatched letters */
|
||||
}
|
||||
if (chara) a += gota;
|
||||
if (charb) b += gotb;
|
||||
}
|
||||
return dist;
|
||||
}
|
||||
|
||||
intptr_t ConsiderWord(const char *word, void *arg) {
|
||||
long dist;
|
||||
if ((dist = WordDistance(word, query)) < MAX_NEARBY_WORD_DISTANCE) {
|
||||
append(&nearby, &((struct WordMatch){dist, word}));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CompareWords(const struct WordMatch *a, const struct WordMatch *b) {
|
||||
return a->dist < b->dist;
|
||||
}
|
||||
|
||||
void FindNearbyWords(void) {
|
||||
nearby.i = 0;
|
||||
critbit0_allprefixed(&words, "", ConsiderWord, NULL);
|
||||
qsort(nearby.p, nearby.i, sizeof(struct WordMatch), (void *)CompareWords);
|
||||
}
|
||||
|
||||
void SpellChecker(void) {
|
||||
int i;
|
||||
printf("@(#) Cosmopolitan Ispell Version 3.4.00 8 Feb 2015\r\n");
|
||||
while (!feof(stdin)) {
|
||||
printf("word: ");
|
||||
fflush(stdout);
|
||||
if (getline(&line, &linesize, stdin) > 0) {
|
||||
query = strtolower(_chomp(line));
|
||||
if (critbit0_contains(&words, query)) {
|
||||
printf("ok\r\n");
|
||||
} else {
|
||||
FindNearbyWords();
|
||||
if (nearby.i) {
|
||||
printf("how about: ");
|
||||
for (i = 0; i < MIN(MAX_NEARBY_RESULTS, nearby.i); ++i) {
|
||||
if (i) printf(", ");
|
||||
fputs(nearby.p[i].word, stdout);
|
||||
}
|
||||
printf("\r\n");
|
||||
} else {
|
||||
printf("not found\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("\r\n");
|
||||
}
|
||||
CHECK_NE(-1, fclose(stdin));
|
||||
CHECK_NE(-1, fclose(stdout));
|
||||
}
|
||||
|
||||
void LoadWords(void) {
|
||||
CHECK_NOTNULL((f = fopen("/zip/usr/share/dict/words", "r")));
|
||||
while (getline(&line, &linesize, f) > 0) {
|
||||
critbit0_insert(&words, strtolower(_chomp(line)));
|
||||
}
|
||||
CHECK_NE(-1, fclose(f));
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (!NoDebug()) ShowCrashReports();
|
||||
LoadWords();
|
||||
SpellChecker();
|
||||
return 0;
|
||||
}
|
||||
+3
-3
@@ -58,14 +58,14 @@ Contact: [email protected]\"\n\
|
||||
#endif
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include "libc/mem/alg.h"
|
||||
#include "libc/mem/arraylist2.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/calls/weirdtypes.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/alg.h"
|
||||
#include "libc/mem/arraylist2.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
@@ -355,7 +355,7 @@ int getCursorPosition(int64_t ifd, int64_t ofd, int *rows, int *cols) {
|
||||
* Returns 0 on success, -1 on error. */
|
||||
int getWindowSize(int64_t ifd, int64_t ofd, int *rows, int *cols) {
|
||||
struct winsize ws;
|
||||
if (getttysize(STDOUT_FILENO, &ws) == -1 || ws.ws_col == 0) {
|
||||
if (_getttysize(1, &ws) == -1 || ws.ws_col == 0) {
|
||||
/* ioctl() failed. Try to query the terminal itself. */
|
||||
int orig_row, orig_col, retval;
|
||||
|
||||
|
||||
+3
-3
@@ -11,12 +11,12 @@
|
||||
#include "libc/calls/struct/dirent.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/dt.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "libc/x/xasprintf.h"
|
||||
|
||||
struct stat st;
|
||||
|
||||
@@ -49,7 +49,7 @@ void List(const char *path) {
|
||||
const char *vpath;
|
||||
if (strcmp(path, ".") == 0) {
|
||||
vpath = "";
|
||||
} else if (!endswith(path, "/")) {
|
||||
} else if (!_endswith(path, "/")) {
|
||||
vpath = _gc(xasprintf("%s/", path));
|
||||
} else {
|
||||
vpath = path;
|
||||
|
||||
+5
-4
@@ -7,19 +7,20 @@
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/mem/alg.h"
|
||||
#include "libc/mem/arraylist2.internal.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/dirent.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/mem/alg.h"
|
||||
#include "libc/mem/arraylist2.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/dt.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "libc/x/xiso8601.h"
|
||||
|
||||
struct stat st;
|
||||
struct Files {
|
||||
|
||||
+6
-5
@@ -10,21 +10,21 @@
|
||||
#include "dsp/tty/itoa8.h"
|
||||
#include "dsp/tty/quant.h"
|
||||
#include "dsp/tty/tty.h"
|
||||
#include "libc/mem/arraylist2.internal.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/itimerval.h"
|
||||
#include "libc/calls/struct/winsize.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/inttypes.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/mem/arraylist2.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/sock.h"
|
||||
@@ -39,7 +39,8 @@
|
||||
#include "libc/sysv/consts/poll.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "libc/x/xasprintf.h"
|
||||
#include "libc/x/xsigaction.h"
|
||||
#include "libc/zip.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
@@ -286,7 +287,7 @@ void GetTermSize(void) {
|
||||
struct winsize wsize_;
|
||||
wsize_.ws_row = 25;
|
||||
wsize_.ws_col = 80;
|
||||
getttysize(STDIN_FILENO, &wsize_);
|
||||
_getttysize(0, &wsize_);
|
||||
FreeSamplingSolution(ssy_);
|
||||
FreeSamplingSolution(ssx_);
|
||||
tyn_ = wsize_.ws_row * 2;
|
||||
|
||||
+3
-2
@@ -17,14 +17,15 @@
|
||||
#include "libc/log/gdb.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "libc/x/xasprintf.h"
|
||||
#include "tool/build/lib/panel.h"
|
||||
|
||||
/**
|
||||
@@ -76,7 +77,7 @@ void GetTtySize(void) {
|
||||
struct winsize wsize;
|
||||
wsize.ws_row = tyn;
|
||||
wsize.ws_col = txn;
|
||||
getttysize(1, &wsize);
|
||||
_getttysize(1, &wsize);
|
||||
tyn = wsize.ws_row;
|
||||
txn = wsize.ws_col;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/struct/rlimit.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
|
||||
@@ -0,0 +1,521 @@
|
||||
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright (c) 2010, 2012 David E. O'Brien │
|
||||
│ Copyright (c) 1980, 1992, 1993 │
|
||||
│ The Regents of the University of California. All rights reserved. │
|
||||
│ │
|
||||
│ Redistribution and use in source and binary forms, with or without │
|
||||
│ modification, are permitted provided that the following conditions │
|
||||
│ are met: │
|
||||
│ 1. Redistributions of source code must retain the above copyright │
|
||||
│ notice, this list of conditions and the following disclaimer. │
|
||||
│ 2. Redistributions in binary form must reproduce the above copyright │
|
||||
│ notice, this list of conditions and the following disclaimer in the │
|
||||
│ documentation and/or other materials provided with the distribution. │
|
||||
│ 3. Neither the name of the University nor the names of its contributors │
|
||||
│ may be used to endorse or promote products derived from this software │
|
||||
│ without specific prior written permission. │
|
||||
│ │
|
||||
│ THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND │
|
||||
│ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE │
|
||||
│ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE │
|
||||
│ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE │
|
||||
│ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL │
|
||||
│ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS │
|
||||
│ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) │
|
||||
│ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT │
|
||||
│ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY │
|
||||
│ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF │
|
||||
│ SUCH DAMAGE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/struct/termios.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/calls/struct/winsize.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/calls/weirdtypes.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/intrin/bswap.h"
|
||||
#include "libc/log/bsd.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/paths.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/select.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
// clang-format off
|
||||
|
||||
/**
|
||||
* @fileoverview Terminal Screencast Recorder / Player, e.g.
|
||||
*
|
||||
* make o//examples/script.com
|
||||
* o//examples/script.com -r
|
||||
* # type stuff..
|
||||
* # CTRL-D
|
||||
* o//examples/script.com -p typescript
|
||||
*
|
||||
* @note works on Linux, OpenBSD, NetBSD, FreeBSD, MacOS
|
||||
* @see https://asciinema.org/
|
||||
*/
|
||||
|
||||
asm(".ident\t\"\\n\\n\
|
||||
FreeBSD Script (BSD-3 License)\\n\
|
||||
Copyright (c) 2010, 2012 David E. O'Brien\\n\
|
||||
Copyright (c) 1980, 1992, 1993\\n\
|
||||
\tThe Regents of the University of California.\\n\
|
||||
\tAll rights reserved.\"");
|
||||
asm(".include \"libc/disclaimer.inc\"");
|
||||
|
||||
#define DEF_BUF 65536
|
||||
|
||||
struct stamp {
|
||||
uint64_t scr_len; /* amount of data */
|
||||
uint64_t scr_sec; /* time it arrived in seconds... */
|
||||
uint32_t scr_usec; /* ...and microseconds */
|
||||
uint32_t scr_direction; /* 'i', 'o', etc (also indicates endianness) */
|
||||
};
|
||||
|
||||
static FILE *fscript;
|
||||
static int master, slave;
|
||||
static int child;
|
||||
static const char *fname;
|
||||
static char *fmfname;
|
||||
static int qflg, ttyflg;
|
||||
static int usesleep, rawout, showexit;
|
||||
|
||||
static struct termios tt;
|
||||
|
||||
static void done(int) wontreturn;
|
||||
static void doshell(char **);
|
||||
static void finish(void);
|
||||
static void record(FILE *, char *, size_t, int);
|
||||
static void consume(FILE *, off_t, char *, int);
|
||||
static void playback(FILE *) wontreturn;
|
||||
static void usage(void);
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int cc;
|
||||
struct termios rtt, stt;
|
||||
struct winsize win;
|
||||
struct timeval tv, *tvp;
|
||||
time_t tvec, start;
|
||||
static char obuf[BUFSIZ];
|
||||
static char ibuf[BUFSIZ];
|
||||
fd_set rfd;
|
||||
int aflg, Fflg, kflg, pflg, ch, k, n;
|
||||
int flushtime, readstdin;
|
||||
int fm_fd, fm_log;
|
||||
|
||||
aflg = Fflg = kflg = pflg = 0;
|
||||
usesleep = 1;
|
||||
rawout = 0;
|
||||
flushtime = 30;
|
||||
fm_fd = -1; /* Shut up stupid "may be used uninitialized" GCC
|
||||
warning. (not needed w/clang) */
|
||||
showexit = 0;
|
||||
|
||||
while ((ch = getopt(argc, argv, "adeFfkpqrt:")) != -1)
|
||||
switch(ch) {
|
||||
case 'a':
|
||||
aflg = 1;
|
||||
break;
|
||||
case 'd':
|
||||
usesleep = 0;
|
||||
break;
|
||||
case 'e': /* Default behavior, accepted for linux compat */
|
||||
break;
|
||||
case 'F':
|
||||
Fflg = 1;
|
||||
break;
|
||||
case 'k':
|
||||
kflg = 1;
|
||||
break;
|
||||
case 'p':
|
||||
pflg = 1;
|
||||
break;
|
||||
case 'q':
|
||||
qflg = 1;
|
||||
break;
|
||||
case 'r':
|
||||
rawout = 1;
|
||||
break;
|
||||
case 't':
|
||||
flushtime = atoi(optarg);
|
||||
if (flushtime < 0)
|
||||
err(1, "invalid flush time %d", flushtime);
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc > 0) {
|
||||
fname = argv[0];
|
||||
argv++;
|
||||
argc--;
|
||||
} else
|
||||
fname = "typescript";
|
||||
|
||||
if ((fscript = fopen(fname, pflg ? "r" : aflg ? "a" : "w")) == NULL)
|
||||
err(1, "%s", fname);
|
||||
|
||||
if (pflg)
|
||||
playback(fscript);
|
||||
|
||||
if (tcgetattr(STDIN_FILENO, &tt) == -1 ||
|
||||
ioctl(STDIN_FILENO, TIOCGWINSZ, &win) == -1) {
|
||||
if (errno != ENOTTY) /* For debugger. */
|
||||
err(1, "tcgetattr/ioctl");
|
||||
if (openpty(&master, &slave, NULL, NULL, NULL) == -1)
|
||||
err(1, "openpty");
|
||||
} else {
|
||||
if (openpty(&master, &slave, NULL, &tt, &win) == -1)
|
||||
err(1, "openpty");
|
||||
ttyflg = 1;
|
||||
}
|
||||
|
||||
if (rawout)
|
||||
record(fscript, NULL, 0, 's');
|
||||
|
||||
if (!qflg) {
|
||||
tvec = time(NULL);
|
||||
printf("Script started, output file is %s\n", fname);
|
||||
if (!rawout) {
|
||||
fprintf(fscript, "Script started on %s",
|
||||
ctime(&tvec));
|
||||
if (argv[0]) {
|
||||
showexit = 1;
|
||||
fprintf(fscript, "Command: ");
|
||||
for (k = 0 ; argv[k] ; ++k)
|
||||
fprintf(fscript, "%s%s", k ? " " : "",
|
||||
argv[k]);
|
||||
fprintf(fscript, "\n");
|
||||
}
|
||||
}
|
||||
fflush(fscript);
|
||||
}
|
||||
if (ttyflg) {
|
||||
rtt = tt;
|
||||
cfmakeraw(&rtt);
|
||||
rtt.c_lflag &= ~ECHO;
|
||||
tcsetattr(STDIN_FILENO, TCSAFLUSH, &rtt);
|
||||
}
|
||||
|
||||
child = fork();
|
||||
if (child < 0) {
|
||||
warn("fork");
|
||||
done(1);
|
||||
}
|
||||
if (child == 0) {
|
||||
doshell(argv);
|
||||
}
|
||||
close(slave);
|
||||
|
||||
start = tvec = time(0);
|
||||
readstdin = 1;
|
||||
for (;;) {
|
||||
FD_ZERO(&rfd);
|
||||
FD_SET(master, &rfd);
|
||||
if (readstdin)
|
||||
FD_SET(STDIN_FILENO, &rfd);
|
||||
if (!readstdin && ttyflg) {
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = 0;
|
||||
tvp = &tv;
|
||||
readstdin = 1;
|
||||
} else if (flushtime > 0) {
|
||||
tv.tv_sec = flushtime - (tvec - start);
|
||||
tv.tv_usec = 0;
|
||||
tvp = &tv;
|
||||
} else {
|
||||
tvp = NULL;
|
||||
}
|
||||
n = select(master + 1, &rfd, 0, 0, tvp);
|
||||
if (n < 0 && errno != EINTR)
|
||||
break;
|
||||
if (n > 0 && FD_ISSET(STDIN_FILENO, &rfd)) {
|
||||
cc = read(STDIN_FILENO, ibuf, BUFSIZ);
|
||||
if (cc < 0)
|
||||
break;
|
||||
if (cc == 0) {
|
||||
if (tcgetattr(master, &stt) == 0 &&
|
||||
(stt.c_lflag & ICANON) != 0) {
|
||||
write(master, &stt.c_cc[VEOF], 1);
|
||||
}
|
||||
readstdin = 0;
|
||||
}
|
||||
if (cc > 0) {
|
||||
if (rawout)
|
||||
record(fscript, ibuf, cc, 'i');
|
||||
write(master, ibuf, cc);
|
||||
if (kflg && tcgetattr(master, &stt) >= 0 &&
|
||||
((stt.c_lflag & ECHO) == 0)) {
|
||||
fwrite(ibuf, 1, cc, fscript);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (n > 0 && FD_ISSET(master, &rfd)) {
|
||||
cc = read(master, obuf, sizeof (obuf));
|
||||
if (cc <= 0)
|
||||
break;
|
||||
write(STDOUT_FILENO, obuf, cc);
|
||||
if (rawout)
|
||||
record(fscript, obuf, cc, 'o');
|
||||
else
|
||||
fwrite(obuf, 1, cc, fscript);
|
||||
}
|
||||
tvec = time(0);
|
||||
if (tvec - start >= flushtime) {
|
||||
fflush(fscript);
|
||||
start = tvec;
|
||||
}
|
||||
if (Fflg)
|
||||
fflush(fscript);
|
||||
}
|
||||
finish();
|
||||
done(0);
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"usage: script [-adfkpqr] [-t time] [file [command ...]]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void
|
||||
finish(void)
|
||||
{
|
||||
int e, status;
|
||||
|
||||
if (waitpid(child, &status, 0) == child) {
|
||||
if (WIFEXITED(status))
|
||||
e = WEXITSTATUS(status);
|
||||
else if (WIFSIGNALED(status))
|
||||
e = WTERMSIG(status);
|
||||
else /* can't happen */
|
||||
e = 1;
|
||||
done(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
doshell(char **av)
|
||||
{
|
||||
const char *shell;
|
||||
|
||||
shell = getenv("SHELL");
|
||||
if (shell == NULL)
|
||||
shell = _PATH_BSHELL;
|
||||
|
||||
close(master);
|
||||
fclose(fscript);
|
||||
free(fmfname);
|
||||
login_tty(slave);
|
||||
setenv("SCRIPT", fname, 1);
|
||||
if (av[0]) {
|
||||
execvp(av[0], av);
|
||||
warn("%s", av[0]);
|
||||
} else {
|
||||
execl(shell, shell, "-i", 0);
|
||||
warn("%s", shell);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void
|
||||
done(int eno)
|
||||
{
|
||||
time_t tvec;
|
||||
|
||||
if (ttyflg)
|
||||
tcsetattr(STDIN_FILENO, TCSAFLUSH, &tt);
|
||||
tvec = time(NULL);
|
||||
if (rawout)
|
||||
record(fscript, NULL, 0, 'e');
|
||||
if (!qflg) {
|
||||
if (!rawout) {
|
||||
if (showexit)
|
||||
fprintf(fscript, "\nCommand exit status:"
|
||||
" %d", eno);
|
||||
fprintf(fscript,"\nScript done on %s",
|
||||
ctime(&tvec));
|
||||
}
|
||||
printf("\nScript done, output file is %s\n", fname);
|
||||
}
|
||||
fclose(fscript);
|
||||
close(master);
|
||||
exit(eno);
|
||||
}
|
||||
|
||||
static void
|
||||
record(FILE *fp, char *buf, size_t cc, int direction)
|
||||
{
|
||||
struct iovec iov[2];
|
||||
struct stamp stamp;
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
stamp.scr_len = cc;
|
||||
stamp.scr_sec = tv.tv_sec;
|
||||
stamp.scr_usec = tv.tv_usec;
|
||||
stamp.scr_direction = direction;
|
||||
iov[0].iov_len = sizeof(stamp);
|
||||
iov[0].iov_base = &stamp;
|
||||
iov[1].iov_len = cc;
|
||||
iov[1].iov_base = buf;
|
||||
if (writev(fileno(fp), &iov[0], 2) == -1)
|
||||
err(1, "writev");
|
||||
}
|
||||
|
||||
static void
|
||||
consume(FILE *fp, off_t len, char *buf, int reg)
|
||||
{
|
||||
size_t l;
|
||||
|
||||
if (reg) {
|
||||
if (fseeko(fp, len, SEEK_CUR) == -1)
|
||||
err(1, NULL);
|
||||
}
|
||||
else {
|
||||
while (len > 0) {
|
||||
l = MIN(DEF_BUF, len);
|
||||
if (fread(buf, sizeof(char), l, fp) != l)
|
||||
err(1, "cannot read buffer");
|
||||
len -= l;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define swapstamp(stamp) do { \
|
||||
if (stamp.scr_direction > 0xff) { \
|
||||
stamp.scr_len = bswap_64(stamp.scr_len); \
|
||||
stamp.scr_sec = bswap_64(stamp.scr_sec); \
|
||||
stamp.scr_usec = bswap_32(stamp.scr_usec); \
|
||||
stamp.scr_direction = bswap_32(stamp.scr_direction); \
|
||||
} \
|
||||
} while (0/*CONSTCOND*/)
|
||||
|
||||
static void
|
||||
termset(void)
|
||||
{
|
||||
struct termios traw;
|
||||
|
||||
if (tcgetattr(STDOUT_FILENO, &tt) == -1) {
|
||||
if (errno != ENOTTY) /* For debugger. */
|
||||
err(1, "tcgetattr");
|
||||
return;
|
||||
}
|
||||
ttyflg = 1;
|
||||
traw = tt;
|
||||
cfmakeraw(&traw);
|
||||
traw.c_lflag |= ISIG;
|
||||
tcsetattr(STDOUT_FILENO, TCSANOW, &traw);
|
||||
}
|
||||
|
||||
static void
|
||||
termreset(void)
|
||||
{
|
||||
if (ttyflg) {
|
||||
tcsetattr(STDOUT_FILENO, TCSADRAIN, &tt);
|
||||
ttyflg = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
playback(FILE *fp)
|
||||
{
|
||||
struct timespec tsi, tso;
|
||||
struct stamp stamp;
|
||||
struct stat pst;
|
||||
static char buf[DEF_BUF];
|
||||
off_t nread, save_len;
|
||||
size_t l;
|
||||
time_t tclock;
|
||||
int reg;
|
||||
|
||||
if (fstat(fileno(fp), &pst) == -1)
|
||||
err(1, "fstat failed");
|
||||
|
||||
reg = S_ISREG(pst.st_mode);
|
||||
|
||||
for (nread = 0; !reg || nread < pst.st_size; nread += save_len) {
|
||||
if (fread(&stamp, sizeof(stamp), 1, fp) != 1) {
|
||||
if (reg)
|
||||
err(1, "reading playback header");
|
||||
else
|
||||
break;
|
||||
}
|
||||
swapstamp(stamp);
|
||||
save_len = sizeof(stamp);
|
||||
|
||||
if (reg && stamp.scr_len >
|
||||
(uint64_t)(pst.st_size - save_len) - nread)
|
||||
errx(1, "invalid stamp");
|
||||
|
||||
save_len += stamp.scr_len;
|
||||
tclock = stamp.scr_sec;
|
||||
tso.tv_sec = stamp.scr_sec;
|
||||
tso.tv_nsec = stamp.scr_usec * 1000;
|
||||
|
||||
switch (stamp.scr_direction) {
|
||||
case 's':
|
||||
if (!qflg)
|
||||
printf("Script started on %s",
|
||||
ctime(&tclock));
|
||||
tsi = tso;
|
||||
consume(fp, stamp.scr_len, buf, reg);
|
||||
termset();
|
||||
atexit(termreset);
|
||||
break;
|
||||
case 'e':
|
||||
termreset();
|
||||
if (!qflg)
|
||||
printf("\nScript done on %s",
|
||||
ctime(&tclock));
|
||||
consume(fp, stamp.scr_len, buf, reg);
|
||||
break;
|
||||
case 'i':
|
||||
/* throw input away */
|
||||
consume(fp, stamp.scr_len, buf, reg);
|
||||
break;
|
||||
case 'o':
|
||||
tsi.tv_sec = tso.tv_sec - tsi.tv_sec;
|
||||
tsi.tv_nsec = tso.tv_nsec - tsi.tv_nsec;
|
||||
if (tsi.tv_nsec < 0) {
|
||||
tsi.tv_sec -= 1;
|
||||
tsi.tv_nsec += 1000000000;
|
||||
}
|
||||
if (usesleep)
|
||||
nanosleep(&tsi, NULL);
|
||||
tsi = tso;
|
||||
while (stamp.scr_len > 0) {
|
||||
l = MIN(DEF_BUF, stamp.scr_len);
|
||||
if (fread(buf, sizeof(char), l, fp) != l)
|
||||
err(1, "cannot read buffer");
|
||||
|
||||
write(STDOUT_FILENO, buf, l);
|
||||
stamp.scr_len -= l;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
errx(1, "invalid direction");
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
SCRIPT(1) Cosmopolitan General Commands Manual SCRIPT(1)
|
||||
|
||||
𝐍𝐀𝐌𝐄
|
||||
𝘀𝗰𝗿𝗶𝗽𝘁 — make typescript of terminal session
|
||||
|
||||
𝐒𝐘𝐍𝐎𝐏𝐒𝐈𝐒
|
||||
𝘀𝗰𝗿𝗶𝗽𝘁 [-𝗮𝗱𝗲𝗳𝗸𝗽𝗾𝗿] [-𝐅 p̲i̲p̲e̲] [-𝘁 t̲i̲m̲e̲] [f̲i̲l̲e̲ [c̲o̲m̲m̲a̲n̲d̲ .̲.̲.̲]]
|
||||
|
||||
𝐃𝐄𝐒𝐂𝐑𝐈𝐏𝐓𝐈𝐎𝐍
|
||||
The 𝘀𝗰𝗿𝗶𝗽𝘁 utility makes a typescript of everything printed on your termi‐
|
||||
nal. It is useful for students who need a hardcopy record of an interac‐
|
||||
tive session as proof of an assignment, as the typescript file can be
|
||||
printed out later with lpr(1).
|
||||
|
||||
If the argument f̲i̲l̲e̲ is given, 𝘀𝗰𝗿𝗶𝗽𝘁 saves all dialogue in f̲i̲l̲e̲. If no
|
||||
file name is given, the typescript is saved in the file t̲y̲p̲e̲s̲c̲r̲i̲p̲t̲.
|
||||
|
||||
If the argument c̲o̲m̲m̲a̲n̲d̲ is given, 𝘀𝗰𝗿𝗶𝗽𝘁 will run the specified command
|
||||
with an optional argument vector instead of an interactive shell.
|
||||
|
||||
The following options are available:
|
||||
|
||||
-𝗮 Append the output to f̲i̲l̲e̲ or t̲y̲p̲e̲s̲c̲r̲i̲p̲t̲, retaining the prior con‐
|
||||
tents.
|
||||
|
||||
-𝗱 When playing back a session with the -𝗽 flag, do not sleep between
|
||||
records when playing back a timestamped session.
|
||||
|
||||
-𝗲 Accepted for compatibility with u̲t̲i̲l̲-̲l̲i̲n̲u̲x̲ 𝘀𝗰𝗿𝗶𝗽𝘁. The child com‐
|
||||
mand exit status is always the exit status of 𝘀𝗰𝗿𝗶𝗽𝘁.
|
||||
|
||||
-𝐅 p̲i̲p̲e̲
|
||||
Immediately flush output after each write. This will allow a user
|
||||
to create a named pipe using mkfifo(1) and another user may watch
|
||||
the live session using a utility like cat(1).
|
||||
|
||||
-𝗸 Log keys sent to the program as well as output.
|
||||
|
||||
-𝗽 Play back a session recorded with the -𝗿 flag in real time.
|
||||
|
||||
-𝗾 Run in quiet mode, omit the start, stop and command status mes‐
|
||||
sages.
|
||||
|
||||
-𝗿 Record a session with input, output, and timestamping.
|
||||
|
||||
-𝘁 t̲i̲m̲e̲
|
||||
Specify the interval at which the script output file will be
|
||||
flushed to disk, in seconds. A value of 0 causes 𝘀𝗰𝗿𝗶𝗽𝘁 to flush
|
||||
after every character I/O event. The default interval is 30 sec‐
|
||||
onds.
|
||||
|
||||
The script ends when the forked shell (or command) exits (a c̲o̲n̲t̲r̲o̲l̲-̲D̲ to
|
||||
exit the Bourne shell (sh(1)), and e̲x̲i̲t̲, l̲o̲g̲o̲u̲t̲ or c̲o̲n̲t̲r̲o̲l̲-̲D̲ (if i̲g̲n̲o̲r̲e̲e̲o̲f̲
|
||||
is not set) for the C-shell, csh(1)).
|
||||
|
||||
Certain interactive commands, such as vi(1), create garbage in the type‐
|
||||
script file. The 𝘀𝗰𝗿𝗶𝗽𝘁 utility works best with commands that do not ma‐
|
||||
nipulate the screen. The results are meant to emulate a hardcopy terminal,
|
||||
not an addressable one.
|
||||
|
||||
𝐄𝐍𝐕𝐈𝐑𝐎𝐍𝐌𝐄𝐍𝐓
|
||||
The following environment variables are utilized by 𝘀𝗰𝗿𝗶𝗽𝘁:
|
||||
|
||||
SCRIPT
|
||||
The SCRIPT environment variable is added to the sub-shell. If
|
||||
SCRIPT already existed in the users environment, its value is over‐
|
||||
written within the sub-shell. The value of SCRIPT is the name of
|
||||
the t̲y̲p̲e̲s̲c̲r̲i̲p̲t̲ file.
|
||||
|
||||
SHELL If the variable SHELL exists, the shell forked by 𝘀𝗰𝗿𝗶𝗽𝘁 will be
|
||||
that shell. If SHELL is not set, the Bourne shell is assumed.
|
||||
(Most shells set this variable automatically).
|
||||
|
||||
𝐒𝐄𝐄 𝐀𝐋𝐒𝐎
|
||||
csh(1) (for the h̲i̲s̲t̲o̲r̲y̲ mechanism)
|
||||
|
||||
𝐇𝐈𝐒𝐓𝐎𝐑𝐘
|
||||
The 𝘀𝗰𝗿𝗶𝗽𝘁 command appeared in 3.0BSD.
|
||||
|
||||
The -𝗱, -𝗽 and -𝗿 options first appeared in NetBSD 2.0 and were ported to
|
||||
FreeBSD 9.2.
|
||||
|
||||
𝐁𝐔𝐆𝐒
|
||||
The 𝘀𝗰𝗿𝗶𝗽𝘁 utility places 𝗲𝘃𝗲𝗿𝘆𝘁𝗵𝗶𝗻𝗴 in the log file, including linefeeds
|
||||
and backspaces. This is not what the naive user expects.
|
||||
|
||||
It is not possible to specify a command without also naming the script file
|
||||
because of argument parsing compatibility issues.
|
||||
|
||||
When running in -𝗸 mode, echo cancelling is far from ideal. The slave ter‐
|
||||
minal mode is checked for ECHO mode to check when to avoid manual echo log‐
|
||||
ging. This does not work when the terminal is in a raw mode where the pro‐
|
||||
gram being run is doing manual echo.
|
||||
|
||||
If 𝘀𝗰𝗿𝗶𝗽𝘁 reads zero bytes from the terminal, it switches to a mode when it
|
||||
only attempts to read once a second until there is data to read. This pre‐
|
||||
vents 𝘀𝗰𝗿𝗶𝗽𝘁 from spinning on zero-byte reads, but might cause a 1-second
|
||||
delay in processing of user input.
|
||||
|
||||
BSD September 1, 2020 BSD
|
||||
+2
-2
@@ -14,11 +14,11 @@
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "libc/x/xiso8601.h"
|
||||
|
||||
/**
|
||||
* @fileoverview File metadata viewer.
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/stdio/append.internal.h"
|
||||
#include "libc/stdio/append.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
|
||||
+2
-1
@@ -12,10 +12,11 @@
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/ex.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "libc/x/xspawn.h"
|
||||
|
||||
/**
|
||||
* @fileoverview command for showing how long a command takes
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/append.internal.h"
|
||||
#include "libc/stdio/append.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/itimer.h"
|
||||
|
||||
+5
-5
@@ -24,7 +24,7 @@
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "libc/x/xsigaction.h"
|
||||
|
||||
#define CTRL(C) ((C) ^ 0b01000000)
|
||||
#define WRITE(FD, SLIT) write(FD, SLIT, strlen(SLIT))
|
||||
@@ -80,7 +80,7 @@ int rawmode(void) {
|
||||
}
|
||||
|
||||
void getsize(void) {
|
||||
if (getttysize(1, &wsize) != -1) {
|
||||
if (_getttysize(1, &wsize) != -1) {
|
||||
printf("termios says terminal size is %hu×%hu\r\n", wsize.ws_col,
|
||||
wsize.ws_row);
|
||||
} else {
|
||||
@@ -148,12 +148,12 @@ int main(int argc, char *argv[]) {
|
||||
if (iscntrl(code[0]) && !code[1]) {
|
||||
printf("is CTRL-%c a.k.a. ^%c\r\n", CTRL(code[0]), CTRL(code[0]));
|
||||
if (code[0] == CTRL('C') || code[0] == CTRL('D')) break;
|
||||
} else if (startswith(code, "\e[") && endswith(code, "R")) {
|
||||
} else if (_startswith(code, "\e[") && _endswith(code, "R")) {
|
||||
yn = 1, xn = 1;
|
||||
sscanf(code, "\e[%d;%dR", &yn, &xn);
|
||||
printf("inband signalling says terminal size is %d×%d\r\n", xn, yn);
|
||||
} else if (startswith(code, "\e[<") &&
|
||||
(endswith(code, "m") || endswith(code, "M"))) {
|
||||
} else if (_startswith(code, "\e[<") &&
|
||||
(_endswith(code, "m") || _endswith(code, "M"))) {
|
||||
e = 0, y = 1, x = 1;
|
||||
sscanf(code, "\e[<%d;%d;%d%c", &e, &y, &x, &c);
|
||||
printf("mouse %s at %d×%d\r\n", describemouseevent(e | (c == 'm') << 2),
|
||||
|
||||
+3
-2
@@ -110,12 +110,11 @@
|
||||
│ cosmopolitan § the unbourne shell » macros ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
#include "libc/mem/alg.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/dirent.h"
|
||||
#include "libc/calls/struct/rlimit.h"
|
||||
#include "libc/calls/struct/rusage.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/struct/tms.h"
|
||||
@@ -124,9 +123,11 @@
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/alg.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/paths.h"
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/isystem/unistd.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Bare Metal VGA TTY demo.
|
||||
*
|
||||
* This program can boot as an operating system. Try it out:
|
||||
*
|
||||
* make -j8 o//examples/vga.com
|
||||
* qemu-system-x86_64 -hda o//examples/vga.com -serial stdio
|
||||
*
|
||||
* Please note that, by default, APE binaries only use the serial port
|
||||
* for stdio. To get the VGA console as an added bonus:
|
||||
*
|
||||
* STATIC_YOINK("vga_console");
|
||||
*
|
||||
* Should be added to the top of your main() program source file.
|
||||
*/
|
||||
|
||||
STATIC_YOINK("vga_console");
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
volatile long double x = -.5;
|
||||
volatile long double y = 1.5;
|
||||
struct termios tio;
|
||||
char buf[16];
|
||||
ssize_t res;
|
||||
if (tcgetattr(0, &tio) != -1) {
|
||||
tio.c_lflag &= ~(ECHO | ICANON);
|
||||
tcsetattr(0, TCSANOW, &tio);
|
||||
}
|
||||
write(1, "\e[5n", 4);
|
||||
res = read(0, buf, 4);
|
||||
if (res != 4 || memcmp(buf, "\e[0n", 4) != 0) {
|
||||
printf("res = %d?\n", res);
|
||||
return -1;
|
||||
}
|
||||
printf("Hello World! %.19Lg\n", atan2l(x, y));
|
||||
|
||||
// read/print loop so machine doesn't reset on metal
|
||||
for (;;) {
|
||||
if ((res = readansi(0, buf, 16)) > 0) {
|
||||
printf("got %`'.*s\r\n", res, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,617 @@
|
||||
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright (c) 1980, 1993 │
|
||||
│ The Regents of the University of California. All rights reserved. │
|
||||
│ │
|
||||
│ Redistribution and use in source and binary forms, with or without │
|
||||
│ modification, are permitted provided that the following conditions │
|
||||
│ are met: │
|
||||
│ 1. Redistributions of source code must retain the above copyright │
|
||||
│ notice, this list of conditions and the following disclaimer. │
|
||||
│ 2. Redistributions in binary form must reproduce the above copyright │
|
||||
│ notice, this list of conditions and the following disclaimer in the │
|
||||
│ documentation and/or other materials provided with the distribution. │
|
||||
│ 3. Neither the name of the University nor the names of its contributors │
|
||||
│ may be used to endorse or promote products derived from this software │
|
||||
│ without specific prior written permission. │
|
||||
│ │
|
||||
│ THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND │
|
||||
│ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE │
|
||||
│ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE │
|
||||
│ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE │
|
||||
│ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL │
|
||||
│ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS │
|
||||
│ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) │
|
||||
│ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT │
|
||||
│ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY │
|
||||
│ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF │
|
||||
│ SUCH DAMAGE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/dns/dns.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/log/bsd.h"
|
||||
#include "libc/mem/fmt.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/struct/pollfd.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/af.h"
|
||||
#include "libc/sysv/consts/ex.h"
|
||||
#include "libc/sysv/consts/f.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/poll.h"
|
||||
#include "libc/sysv/consts/sock.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
// clang-format off
|
||||
|
||||
asm(".ident\t\"\\n\\n\
|
||||
FreeBSD Whois (BSD-3 License)\\n\
|
||||
Copyright (c) 1980, 1993\\n\
|
||||
\tThe Regents of the University of California.\\n\
|
||||
\tAll rights reserved.\"");
|
||||
asm(".include \"libc/disclaimer.inc\"");
|
||||
|
||||
#define ABUSEHOST "whois.abuse.net"
|
||||
#define ANICHOST "whois.arin.net"
|
||||
#define DENICHOST "whois.denic.de"
|
||||
#define DKNICHOST "whois.dk-hostmaster.dk"
|
||||
#define FNICHOST "whois.afrinic.net"
|
||||
#define GNICHOST "whois.nic.gov"
|
||||
#define IANAHOST "whois.iana.org"
|
||||
#define INICHOST "whois.internic.net"
|
||||
#define KNICHOST "whois.krnic.net"
|
||||
#define LNICHOST "whois.lacnic.net"
|
||||
#define MNICHOST "whois.ra.net"
|
||||
#define PDBHOST "whois.peeringdb.com"
|
||||
#define PNICHOST "whois.apnic.net"
|
||||
#define QNICHOST_TAIL ".whois-servers.net"
|
||||
#define RNICHOST "whois.ripe.net"
|
||||
#define VNICHOST "whois.verisign-grs.com"
|
||||
|
||||
#define DEFAULT_PORT "whois"
|
||||
|
||||
#define WHOIS_RECURSE 0x01
|
||||
#define WHOIS_QUICK 0x02
|
||||
#define WHOIS_SPAM_ME 0x04
|
||||
|
||||
#define CHOPSPAM ">>> Last update of WHOIS database:"
|
||||
|
||||
#define ishost(h) (isalnum((unsigned char)h) || h == '.' || h == '-')
|
||||
|
||||
#define SCAN(p, end, check) \
|
||||
while ((p) < (end)) \
|
||||
if (check) ++(p); \
|
||||
else break
|
||||
|
||||
static struct {
|
||||
const char *suffix, *server;
|
||||
} whoiswhere[] = {
|
||||
/* Various handles */
|
||||
{ "-ARIN", ANICHOST },
|
||||
{ "-NICAT", "at" QNICHOST_TAIL },
|
||||
{ "-NORID", "no" QNICHOST_TAIL },
|
||||
{ "-RIPE", RNICHOST },
|
||||
/* Nominet's whois server doesn't return referrals to JANET */
|
||||
{ ".ac.uk", "ac.uk" QNICHOST_TAIL },
|
||||
{ ".gov.uk", "ac.uk" QNICHOST_TAIL },
|
||||
{ "", IANAHOST }, /* default */
|
||||
{ NULL, NULL } /* safety belt */
|
||||
};
|
||||
|
||||
#define WHOIS_REFERRAL(s) { s, sizeof(s) - 1 }
|
||||
static struct {
|
||||
const char *prefix;
|
||||
size_t len;
|
||||
} whois_referral[] = {
|
||||
WHOIS_REFERRAL("whois:"), /* IANA */
|
||||
WHOIS_REFERRAL("Whois Server:"),
|
||||
WHOIS_REFERRAL("Registrar WHOIS Server:"), /* corporatedomains.com */
|
||||
WHOIS_REFERRAL("ReferralServer: whois://"), /* ARIN */
|
||||
WHOIS_REFERRAL("ReferralServer: rwhois://"), /* ARIN */
|
||||
WHOIS_REFERRAL("descr: region. Please query"), /* AfriNIC */
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
/*
|
||||
* We have a list of patterns for RIRs that assert ignorance rather than
|
||||
* providing referrals. If that happens, we guess that ARIN will be more
|
||||
* helpful. But, before following a referral to an RIR, we check if we have
|
||||
* asked that RIR already, and if so we make another guess.
|
||||
*/
|
||||
static const char *actually_arin[] = {
|
||||
"netname: ERX-NETBLOCK\n", /* APNIC */
|
||||
"netname: NON-RIPE-NCC-MANAGED-ADDRESS-BLOCK\n",
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct {
|
||||
int loop;
|
||||
const char *host;
|
||||
} try_rir[] = {
|
||||
{ 0, ANICHOST },
|
||||
{ 0, RNICHOST },
|
||||
{ 0, PNICHOST },
|
||||
{ 0, FNICHOST },
|
||||
{ 0, LNICHOST },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
reset_rir(void) {
|
||||
int i;
|
||||
|
||||
for (i = 0; try_rir[i].host != NULL; i++)
|
||||
try_rir[i].loop = 0;
|
||||
}
|
||||
|
||||
static const char *port = DEFAULT_PORT;
|
||||
|
||||
static const char *choose_server(char *);
|
||||
static struct addrinfo *gethostinfo(const char *, const char *, int);
|
||||
static void s_asprintf(char **ret, const char *format, ...);
|
||||
static void usage(void);
|
||||
static void whois(const char *, const char *, const char *, int);
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
const char *country, *host;
|
||||
int ch, flags;
|
||||
|
||||
#ifdef SOCKS
|
||||
SOCKSinit(argv[0]);
|
||||
#endif
|
||||
|
||||
country = host = NULL;
|
||||
flags = 0;
|
||||
while ((ch = getopt(argc, argv, "aAbc:fgh:iIklmp:PQrRS")) != -1) {
|
||||
switch (ch) {
|
||||
case 'a':
|
||||
host = ANICHOST;
|
||||
break;
|
||||
case 'A':
|
||||
host = PNICHOST;
|
||||
break;
|
||||
case 'b':
|
||||
host = ABUSEHOST;
|
||||
break;
|
||||
case 'c':
|
||||
country = optarg;
|
||||
break;
|
||||
case 'f':
|
||||
host = FNICHOST;
|
||||
break;
|
||||
case 'g':
|
||||
host = GNICHOST;
|
||||
break;
|
||||
case 'h':
|
||||
host = optarg;
|
||||
break;
|
||||
case 'i':
|
||||
host = INICHOST;
|
||||
break;
|
||||
case 'I':
|
||||
host = IANAHOST;
|
||||
break;
|
||||
case 'k':
|
||||
host = KNICHOST;
|
||||
break;
|
||||
case 'l':
|
||||
host = LNICHOST;
|
||||
break;
|
||||
case 'm':
|
||||
host = MNICHOST;
|
||||
break;
|
||||
case 'p':
|
||||
port = optarg;
|
||||
break;
|
||||
case 'P':
|
||||
host = PDBHOST;
|
||||
break;
|
||||
case 'Q':
|
||||
flags |= WHOIS_QUICK;
|
||||
break;
|
||||
case 'r':
|
||||
host = RNICHOST;
|
||||
break;
|
||||
case 'R':
|
||||
flags |= WHOIS_RECURSE;
|
||||
break;
|
||||
case 'S':
|
||||
flags |= WHOIS_SPAM_ME;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (!argc || (country != NULL && host != NULL))
|
||||
usage();
|
||||
|
||||
/*
|
||||
* If no host or country is specified, rely on referrals from IANA.
|
||||
*/
|
||||
if (host == NULL && country == NULL) {
|
||||
if ((host = getenv("WHOIS_SERVER")) == NULL &&
|
||||
(host = getenv("RA_SERVER")) == NULL) {
|
||||
if (!(flags & WHOIS_QUICK))
|
||||
flags |= WHOIS_RECURSE;
|
||||
}
|
||||
}
|
||||
while (argc-- > 0) {
|
||||
if (country != NULL) {
|
||||
char *qnichost;
|
||||
s_asprintf(&qnichost, "%s%s", country, QNICHOST_TAIL);
|
||||
whois(*argv, qnichost, port, flags);
|
||||
free(qnichost);
|
||||
} else
|
||||
whois(*argv, host != NULL ? host :
|
||||
choose_server(*argv), port, flags);
|
||||
reset_rir();
|
||||
argv++;
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static const char *
|
||||
choose_server(char *domain)
|
||||
{
|
||||
size_t len = strlen(domain);
|
||||
int i;
|
||||
|
||||
for (i = 0; whoiswhere[i].suffix != NULL; i++) {
|
||||
size_t suffix_len = strlen(whoiswhere[i].suffix);
|
||||
if (len > suffix_len &&
|
||||
strcasecmp(domain + len - suffix_len,
|
||||
whoiswhere[i].suffix) == 0)
|
||||
return (whoiswhere[i].server);
|
||||
}
|
||||
errx(EX_SOFTWARE, "no default whois server");
|
||||
}
|
||||
|
||||
static struct addrinfo *
|
||||
gethostinfo(const char *host, const char *hport, int exit_on_noname)
|
||||
{
|
||||
struct addrinfo hints, *res;
|
||||
int error;
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
res = NULL;
|
||||
error = getaddrinfo(host, hport, &hints, &res);
|
||||
if (error && (exit_on_noname || error != EAI_NONAME))
|
||||
err(EX_NOHOST, "%s: %s", host, gai_strerror(error));
|
||||
return (res);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper for asprintf(3) that exits on error.
|
||||
*/
|
||||
static void
|
||||
s_asprintf(char **ret, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
if (vasprintf(ret, format, ap) == -1) {
|
||||
va_end(ap);
|
||||
err(EX_OSERR, "vasprintf()");
|
||||
}
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static int
|
||||
connect_to_any_host(struct addrinfo *hostres)
|
||||
{
|
||||
struct addrinfo *res;
|
||||
nfds_t i, j;
|
||||
size_t count;
|
||||
struct pollfd *fds;
|
||||
int timeout = 180, s = -1;
|
||||
|
||||
for (res = hostres, count = 0; res; res = res->ai_next)
|
||||
count++;
|
||||
fds = calloc(count, sizeof(*fds));
|
||||
if (fds == NULL)
|
||||
err(EX_OSERR, "calloc()");
|
||||
|
||||
/*
|
||||
* Traverse the result list elements and make non-block
|
||||
* connection attempts.
|
||||
*/
|
||||
count = i = 0;
|
||||
for (res = hostres; res != NULL; res = res->ai_next) {
|
||||
s = socket(res->ai_family, res->ai_socktype | SOCK_NONBLOCK,
|
||||
res->ai_protocol);
|
||||
if (s < 0)
|
||||
continue;
|
||||
if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
|
||||
if (errno == EINPROGRESS) {
|
||||
/* Add the socket to poll list */
|
||||
fds[i].fd = s;
|
||||
fds[i].events = POLLERR | POLLHUP |
|
||||
POLLIN | POLLOUT;
|
||||
/*
|
||||
* From here until a socket connects, the
|
||||
* socket fd is owned by the fds[] poll array.
|
||||
*/
|
||||
s = -1;
|
||||
count++;
|
||||
i++;
|
||||
} else {
|
||||
close(s);
|
||||
s = -1;
|
||||
|
||||
/*
|
||||
* Poll only if we have something to poll,
|
||||
* otherwise just go ahead and try next
|
||||
* address
|
||||
*/
|
||||
if (count == 0)
|
||||
continue;
|
||||
}
|
||||
} else
|
||||
goto done;
|
||||
|
||||
/*
|
||||
* If we are at the last address, poll until a connection is
|
||||
* established or we failed all connection attempts.
|
||||
*/
|
||||
if (res->ai_next == NULL)
|
||||
timeout = INFTIM;
|
||||
|
||||
/*
|
||||
* Poll the watched descriptors for successful connections:
|
||||
* if we still have more untried resolved addresses, poll only
|
||||
* once; otherwise, poll until all descriptors have errors,
|
||||
* which will be considered as ETIMEDOUT later.
|
||||
*/
|
||||
do {
|
||||
int n;
|
||||
|
||||
n = poll(fds, i, timeout);
|
||||
if (n == 0) {
|
||||
/*
|
||||
* No event reported in time. Try with a
|
||||
* smaller timeout (but cap at 2-3ms)
|
||||
* after a new host have been added.
|
||||
*/
|
||||
if (timeout >= 3)
|
||||
timeout >>= 1;
|
||||
|
||||
break;
|
||||
} else if (n < 0) {
|
||||
/*
|
||||
* errno here can only be EINTR which we would
|
||||
* want to clean up and bail out.
|
||||
*/
|
||||
s = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for the event(s) we have seen.
|
||||
*/
|
||||
for (j = 0; j < i; j++) {
|
||||
if (fds[j].fd == -1 || fds[j].events == 0 ||
|
||||
fds[j].revents == 0)
|
||||
continue;
|
||||
if (fds[j].revents & ~(POLLIN | POLLOUT)) {
|
||||
close(fds[j].fd);
|
||||
fds[j].fd = -1;
|
||||
fds[j].events = 0;
|
||||
count--;
|
||||
continue;
|
||||
} else if (fds[j].revents & (POLLIN | POLLOUT)) {
|
||||
/* Connect succeeded. */
|
||||
s = fds[j].fd;
|
||||
fds[j].fd = -1;
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
}
|
||||
} while (timeout == INFTIM && count != 0);
|
||||
}
|
||||
|
||||
/* All attempts were failed */
|
||||
s = -1;
|
||||
if (count == 0)
|
||||
errno = ETIMEDOUT;
|
||||
|
||||
done:
|
||||
/* Close all watched fds except the succeeded one */
|
||||
for (j = 0; j < i; j++)
|
||||
if (fds[j].fd != -1)
|
||||
close(fds[j].fd);
|
||||
free(fds);
|
||||
return (s);
|
||||
}
|
||||
|
||||
static void
|
||||
whois(const char *query, const char *hostname, const char *hostport, int flags)
|
||||
{
|
||||
FILE *fp;
|
||||
struct addrinfo *hostres;
|
||||
char *buf, *host, *nhost, *nport, *p;
|
||||
int comment, s, f;
|
||||
size_t len, i;
|
||||
|
||||
hostres = gethostinfo(hostname, hostport, 1);
|
||||
s = connect_to_any_host(hostres);
|
||||
if (s == -1)
|
||||
err(EX_OSERR, "connect()");
|
||||
|
||||
/* Restore default blocking behavior. */
|
||||
if ((f = fcntl(s, F_GETFL)) == -1)
|
||||
err(EX_OSERR, "fcntl()");
|
||||
f &= ~O_NONBLOCK;
|
||||
if (fcntl(s, F_SETFL, f) == -1)
|
||||
err(EX_OSERR, "fcntl()");
|
||||
|
||||
fp = fdopen(s, "r+");
|
||||
if (fp == NULL)
|
||||
err(EX_OSERR, "fdopen()");
|
||||
|
||||
if (!(flags & WHOIS_SPAM_ME) &&
|
||||
(strcasecmp(hostname, DENICHOST) == 0 ||
|
||||
strcasecmp(hostname, "de" QNICHOST_TAIL) == 0)) {
|
||||
const char *q;
|
||||
int idn = 0;
|
||||
for (q = query; *q != '\0'; q++)
|
||||
if (!isascii(*q))
|
||||
idn = 1;
|
||||
fprintf(fp, "-T dn%s %s\r\n", idn ? "" : ",ace", query);
|
||||
} else if (!(flags & WHOIS_SPAM_ME) &&
|
||||
(strcasecmp(hostname, DKNICHOST) == 0 ||
|
||||
strcasecmp(hostname, "dk" QNICHOST_TAIL) == 0))
|
||||
fprintf(fp, "--show-handles %s\r\n", query);
|
||||
else if ((flags & WHOIS_SPAM_ME) ||
|
||||
strchr(query, ' ') != NULL)
|
||||
fprintf(fp, "%s\r\n", query);
|
||||
else if (strcasecmp(hostname, ANICHOST) == 0) {
|
||||
if (strncasecmp(query, "AS", 2) == 0 &&
|
||||
strspn(query+2, "0123456789") == strlen(query+2))
|
||||
fprintf(fp, "+ a %s\r\n", query+2);
|
||||
else
|
||||
fprintf(fp, "+ %s\r\n", query);
|
||||
} else if (strcasecmp(hostres->ai_canonname, VNICHOST) == 0)
|
||||
fprintf(fp, "domain %s\r\n", query);
|
||||
else
|
||||
fprintf(fp, "%s\r\n", query);
|
||||
fflush(fp);
|
||||
|
||||
comment = 0;
|
||||
if (!(flags & WHOIS_SPAM_ME) &&
|
||||
(strcasecmp(hostname, ANICHOST) == 0 ||
|
||||
strcasecmp(hostname, RNICHOST) == 0)) {
|
||||
comment = 2;
|
||||
}
|
||||
|
||||
nhost = NULL;
|
||||
while ((buf = fgetln(fp, &len)) != NULL) {
|
||||
/* Nominet */
|
||||
if (!(flags & WHOIS_SPAM_ME) &&
|
||||
len == 5 && strncmp(buf, "-- \r\n", 5) == 0)
|
||||
break;
|
||||
/* RIRs */
|
||||
if (comment == 1 && buf[0] == '#')
|
||||
break;
|
||||
else if (comment == 2) {
|
||||
if (strchr("#%\r\n", buf[0]) != NULL)
|
||||
continue;
|
||||
else
|
||||
comment = 1;
|
||||
}
|
||||
|
||||
printf("%.*s", (int)len, buf);
|
||||
|
||||
if ((flags & WHOIS_RECURSE) && nhost == NULL) {
|
||||
for (i = 0; whois_referral[i].prefix != NULL; i++) {
|
||||
p = buf;
|
||||
SCAN(p, buf+len, *p == ' ');
|
||||
if (strncasecmp(p, whois_referral[i].prefix,
|
||||
whois_referral[i].len) != 0)
|
||||
continue;
|
||||
p += whois_referral[i].len;
|
||||
SCAN(p, buf+len, *p == ' ');
|
||||
host = p;
|
||||
SCAN(p, buf+len, ishost(*p));
|
||||
if (p > host) {
|
||||
char *pstr;
|
||||
|
||||
s_asprintf(&nhost, "%.*s",
|
||||
(int)(p - host), host);
|
||||
|
||||
if (*p != ':') {
|
||||
s_asprintf(&nport, "%s", port);
|
||||
break;
|
||||
}
|
||||
|
||||
pstr = ++p;
|
||||
SCAN(p, buf+len, isdigit(*p));
|
||||
if (p > pstr && (p - pstr) < 6) {
|
||||
s_asprintf(&nport, "%.*s",
|
||||
(int)(p - pstr), pstr);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Invalid port; don't recurse */
|
||||
free(nhost);
|
||||
nhost = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
for (i = 0; actually_arin[i] != NULL; i++) {
|
||||
if (strncmp(buf, actually_arin[i], len) == 0) {
|
||||
s_asprintf(&nhost, "%s", ANICHOST);
|
||||
s_asprintf(&nport, "%s", port);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Verisign etc. */
|
||||
if (!(flags & WHOIS_SPAM_ME) &&
|
||||
len >= sizeof(CHOPSPAM)-1 &&
|
||||
(strncasecmp(buf, CHOPSPAM, sizeof(CHOPSPAM)-1) == 0 ||
|
||||
strncasecmp(buf, CHOPSPAM+4, sizeof(CHOPSPAM)-5) == 0)) {
|
||||
printf("\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
freeaddrinfo(hostres);
|
||||
|
||||
f = 0;
|
||||
for (i = 0; try_rir[i].host != NULL; i++) {
|
||||
/* Remember visits to RIRs */
|
||||
if (try_rir[i].loop == 0 &&
|
||||
strcasecmp(try_rir[i].host, hostname) == 0)
|
||||
try_rir[i].loop = 1;
|
||||
/* Do we need to find an alternative RIR? */
|
||||
if (try_rir[i].loop != 0 && nhost != NULL &&
|
||||
strcasecmp(try_rir[i].host, nhost) == 0) {
|
||||
free(nhost);
|
||||
nhost = NULL;
|
||||
free(nport);
|
||||
nport = NULL;
|
||||
f = 1;
|
||||
}
|
||||
}
|
||||
if (f) {
|
||||
/* Find a replacement RIR */
|
||||
for (i = 0; try_rir[i].host != NULL; i++) {
|
||||
if (try_rir[i].loop == 0) {
|
||||
s_asprintf(&nhost, "%s", try_rir[i].host);
|
||||
s_asprintf(&nport, "%s", port);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nhost != NULL) {
|
||||
/* Ignore self-referrals */
|
||||
if (strcasecmp(hostname, nhost) != 0) {
|
||||
printf("# %s\n\n", nhost);
|
||||
whois(query, nhost, nport, flags);
|
||||
}
|
||||
free(nhost);
|
||||
free(nport);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"usage: whois [-aAbfgiIklmPQrRS] [-c country-code | -h hostname] "
|
||||
"[-p port] name ...\n");
|
||||
exit(EX_USAGE);
|
||||
}
|
||||
+16
-3
@@ -7,16 +7,29 @@ extern bool __assert_disable;
|
||||
void __assert_fail(const char *, const char *, int) hidden relegated;
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define assert(EXPR) ((void)0)
|
||||
#define assert(x) ((void)0)
|
||||
#else
|
||||
#define assert(EXPR) \
|
||||
((void)((EXPR) || (__assert_fail(#EXPR, __FILE__, __LINE__), 0)))
|
||||
#define assert(x) ((void)((x) || (__assert_fail(#x, __FILE__, __LINE__), 0)))
|
||||
#endif
|
||||
|
||||
#ifndef __cplusplus
|
||||
#define static_assert _Static_assert
|
||||
#endif
|
||||
|
||||
#define _unassert(x) \
|
||||
do { \
|
||||
if (__builtin_expect(!(x), 0)) { \
|
||||
unreachable; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define _npassert(x) \
|
||||
do { \
|
||||
if (__builtin_expect(!(x), 0)) { \
|
||||
notpossible; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_ASSERT_H_ */
|
||||
+24
-40
@@ -1,22 +1,8 @@
|
||||
#ifndef COSMOPOLITAN_LIBC_ATOMIC_H_
|
||||
#define COSMOPOLITAN_LIBC_ATOMIC_H_
|
||||
#include "libc/inttypes.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
/**
|
||||
* @fileoverview C11 Atomic Types
|
||||
*
|
||||
* We supoprt C++ and old C compilers. It's recommended you use macros
|
||||
* like `_Atomic(int)` rather than `_Atomic int` or `atomic_int` since
|
||||
* we only define a portability macro for the syntax `_Atomic(T)`.
|
||||
*
|
||||
* @see libc/integral/c.inc
|
||||
* @see libc/intrin/atomic.h
|
||||
*/
|
||||
|
||||
#define atomic_bool _Atomic(_Bool)
|
||||
#define atomic_bool32 atomic_int32
|
||||
#define atomic_bool32 _Atomic(__INT32_TYPE__)
|
||||
#define atomic_char _Atomic(char)
|
||||
#define atomic_schar _Atomic(signed char)
|
||||
#define atomic_uchar _Atomic(unsigned char)
|
||||
@@ -28,29 +14,29 @@ COSMOPOLITAN_C_START_
|
||||
#define atomic_ulong _Atomic(unsigned long)
|
||||
#define atomic_llong _Atomic(long long)
|
||||
#define atomic_ullong _Atomic(unsigned long long)
|
||||
#define atomic_char16_t _Atomic(char16_t)
|
||||
#define atomic_char32_t _Atomic(char32_t)
|
||||
#define atomic_wchar_t _Atomic(wchar_t)
|
||||
#define atomic_intptr_t _Atomic(intptr_t)
|
||||
#define atomic_uintptr_t _Atomic(uintptr_t)
|
||||
#define atomic_size_t _Atomic(size_t)
|
||||
#define atomic_ptrdiff_t _Atomic(ptrdiff_t)
|
||||
#define atomic_int_fast8_t _Atomic(int_fast8_t)
|
||||
#define atomic_uint_fast8_t _Atomic(uint_fast8_t)
|
||||
#define atomic_int_fast16_t _Atomic(int_fast16_t)
|
||||
#define atomic_uint_fast16_t _Atomic(uint_fast16_t)
|
||||
#define atomic_int_fast32_t _Atomic(int_fast32_t)
|
||||
#define atomic_uint_fast32_t _Atomic(uint_fast32_t)
|
||||
#define atomic_int_fast64_t _Atomic(int_fast64_t)
|
||||
#define atomic_uint_fast64_t _Atomic(uint_fast64_t)
|
||||
#define atomic_int_least8_t _Atomic(int_least8_t)
|
||||
#define atomic_uint_least8_t _Atomic(uint_least8_t)
|
||||
#define atomic_int_least16_t _Atomic(int_least16_t)
|
||||
#define atomic_uint_least16_t _Atomic(uint_least16_t)
|
||||
#define atomic_int_least32_t _Atomic(int_least32_t)
|
||||
#define atomic_uint_least32_t _Atomic(uint_least32_t)
|
||||
#define atomic_int_least64_t _Atomic(int_least64_t)
|
||||
#define atomic_uint_least64_t _Atomic(uint_least64_t)
|
||||
#define atomic_char16_t _Atomic(__CHAR16_TYPE__)
|
||||
#define atomic_char32_t _Atomic(__CHAR32_TYPE__)
|
||||
#define atomic_wchar_t _Atomic(__WCHAR_TYPE__)
|
||||
#define atomic_intptr_t _Atomic(__INTPTR_TYPE__)
|
||||
#define atomic_uintptr_t _Atomic(__UINTPTR_TYPE__)
|
||||
#define atomic_size_t _Atomic(__SIZE_TYPE__)
|
||||
#define atomic_ptrdiff_t _Atomic(__PTRDIFF_TYPE__)
|
||||
#define atomic_int_fast8_t _Atomic(__INT_FAST8_TYPE__)
|
||||
#define atomic_uint_fast8_t _Atomic(__UINT_FAST8_TYPE__)
|
||||
#define atomic_int_fast16_t _Atomic(__INT_FAST16_TYPE__)
|
||||
#define atomic_uint_fast16_t _Atomic(__UINT_FAST16_TYPE__)
|
||||
#define atomic_int_fast32_t _Atomic(__INT_FAST32_TYPE__)
|
||||
#define atomic_uint_fast32_t _Atomic(__UINT_FAST32_TYPE__)
|
||||
#define atomic_int_fast64_t _Atomic(__INT_FAST64_TYPE__)
|
||||
#define atomic_uint_fast64_t _Atomic(__UINT_FAST64_TYPE__)
|
||||
#define atomic_int_least8_t _Atomic(__INT_LEAST8_TYPE__)
|
||||
#define atomic_uint_least8_t _Atomic(__UINT_LEAST8_TYPE__)
|
||||
#define atomic_int_least16_t _Atomic(__INT_LEAST16_TYPE__)
|
||||
#define atomic_uint_least16_t _Atomic(__UINT_LEAST16_TYPE__)
|
||||
#define atomic_int_least32_t _Atomic(__INT_LEAST32_TYPE__)
|
||||
#define atomic_uint_least32_t _Atomic(__UINT_LEAST32_TYPE__)
|
||||
#define atomic_int_least64_t _Atomic(__INT_LEAST64_TYPE__)
|
||||
#define atomic_uint_least64_t _Atomic(__UINT_LEAST64_TYPE__)
|
||||
|
||||
#ifdef __CLANG_ATOMIC_BOOL_LOCK_FREE
|
||||
#define ATOMIC_BOOL_LOCK_FREE __CLANG_ATOMIC_BOOL_LOCK_FREE
|
||||
@@ -76,6 +62,4 @@ COSMOPOLITAN_C_START_
|
||||
#define ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE
|
||||
#endif
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_ATOMIC_H_ */
|
||||
@@ -16,44 +16,78 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "third_party/xed/x86.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/calls/syscall_support-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Returns lengths of x86 ops in binary.
|
||||
*
|
||||
* The first decoded instruction is at `_ereal`. Lengths can be 1 to 15
|
||||
* bytes. Each byte in the return value is in that range, and the array
|
||||
* is NUL terminated. The returned memory is memoized, since this costs
|
||||
* some time. For example, for a 10mb Python binary, it takes 20 millis
|
||||
* so the basic idea is is you can use this output multiple times which
|
||||
* is a faster way to iterate over the binary than calling Xed.
|
||||
*
|
||||
* @return nul-terminated length array on success, or null
|
||||
*/
|
||||
privileged unsigned char *GetInstructionLengths(void) {
|
||||
static bool once;
|
||||
int i, n, err, len, rem;
|
||||
static unsigned char *res;
|
||||
struct XedDecodedInst xedd;
|
||||
unsigned char *p, *mem, *code;
|
||||
if (!once) {
|
||||
if ((mem = mmap(0, ROUNDUP(__privileged_addr - _ereal + 1, FRAMESIZE),
|
||||
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1,
|
||||
0)) != MAP_FAILED) {
|
||||
for (p = mem, code = _ereal; code < __privileged_addr; code += len) {
|
||||
rem = __privileged_addr - code;
|
||||
xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64);
|
||||
err = xed_instruction_length_decode(&xedd, code, rem);
|
||||
*p++ = len = !err ? xedd.length : 1;
|
||||
extern const unsigned FIODGNAME;
|
||||
extern const unsigned TIOCPTSNAME;
|
||||
extern const unsigned TIOCPTYGNAME;
|
||||
|
||||
struct fiodgname_arg {
|
||||
int len;
|
||||
void *buf;
|
||||
};
|
||||
|
||||
struct ptmget {
|
||||
int cfd;
|
||||
int sfd;
|
||||
char cn[1024];
|
||||
char sn[1024];
|
||||
};
|
||||
|
||||
int _ptsname(int fd, char *buf, size_t size) {
|
||||
int pty;
|
||||
size_t n;
|
||||
struct ptmget t;
|
||||
|
||||
if (_isptmaster(fd)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
t.sn[0] = '/';
|
||||
t.sn[1] = 'd';
|
||||
t.sn[2] = 'e';
|
||||
t.sn[3] = 'v';
|
||||
t.sn[4] = '/';
|
||||
t.sn[5] = 0;
|
||||
|
||||
if (IsLinux()) {
|
||||
if (sys_ioctl(fd, TIOCGPTN, &pty)) return -1;
|
||||
t.sn[5] = 'p';
|
||||
t.sn[6] = 't';
|
||||
t.sn[7] = 's';
|
||||
t.sn[8] = '/';
|
||||
FormatInt32(t.sn + 9, pty);
|
||||
} else if (IsXnu()) {
|
||||
if (sys_ioctl(fd, TIOCPTYGNAME, t.sn)) {
|
||||
return -1;
|
||||
}
|
||||
} else if (IsFreebsd()) {
|
||||
struct fiodgname_arg fgn = {sizeof(t.sn) - 5, t.sn + 5};
|
||||
if (sys_ioctl(fd, FIODGNAME, &fgn) == -1) {
|
||||
if (errno == EINVAL) {
|
||||
errno = ERANGE;
|
||||
}
|
||||
res = mem;
|
||||
return -1;
|
||||
}
|
||||
} else if (IsNetbsd()) {
|
||||
if (sys_ioctl(fd, TIOCPTSNAME, &t)) {
|
||||
return -1;
|
||||
}
|
||||
once = true;
|
||||
} else {
|
||||
return enosys();
|
||||
}
|
||||
|
||||
if ((n = strlen(t.sn)) < size) {
|
||||
memcpy(buf, t.sn, n + 1);
|
||||
return 0;
|
||||
} else {
|
||||
return erange();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -19,13 +19,9 @@
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
struct timespec _timespec_mono(void) {
|
||||
int ax, dx;
|
||||
struct timespec ts;
|
||||
ax = clock_gettime(CLOCK_MONOTONIC_FAST, &ts);
|
||||
assert(!ax);
|
||||
_npassert(!clock_gettime(CLOCK_MONOTONIC_FAST, &ts));
|
||||
return ts;
|
||||
}
|
||||
@@ -16,15 +16,12 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
struct timespec _timespec_real(void) {
|
||||
int ax, dx;
|
||||
struct timespec ts;
|
||||
ax = clock_gettime(CLOCK_REALTIME_FAST, &ts);
|
||||
if (ax) notpossible;
|
||||
_npassert(!clock_gettime(CLOCK_REALTIME_FAST, &ts));
|
||||
return ts;
|
||||
}
|
||||
@@ -27,6 +27,8 @@ int64_t _timespec_tomicros(struct timespec x) {
|
||||
if (!__builtin_mul_overflow(x.tv_sec, 1000000ul, &us) &&
|
||||
!__builtin_add_overflow(us, x.tv_nsec / 1000, &us)) {
|
||||
return us;
|
||||
} else if (x.tv_sec < 0) {
|
||||
return INT64_MIN;
|
||||
} else {
|
||||
return INT64_MAX;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@ int64_t _timespec_tomillis(struct timespec x) {
|
||||
if (!__builtin_mul_overflow(x.tv_sec, 1000ul, &ms) &&
|
||||
!__builtin_add_overflow(ms, x.tv_nsec / 1000000, &ms)) {
|
||||
return ms;
|
||||
} else if (x.tv_sec < 0) {
|
||||
return INT64_MIN;
|
||||
} else {
|
||||
return INT64_MAX;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@ int64_t _timespec_tonanos(struct timespec x) {
|
||||
if (!__builtin_mul_overflow(x.tv_sec, 1000000000ul, &ns) &&
|
||||
!__builtin_add_overflow(ns, x.tv_nsec, &ns)) {
|
||||
return ns;
|
||||
} else if (x.tv_sec < 0) {
|
||||
return INT64_MIN;
|
||||
} else {
|
||||
return INT64_MAX;
|
||||
}
|
||||
|
||||
+13
-14
@@ -68,7 +68,6 @@ int chdir(const char *);
|
||||
int chmod(const char *, uint32_t);
|
||||
int chown(const char *, uint32_t, uint32_t);
|
||||
int chroot(const char *);
|
||||
int clone(void *, void *, size_t, int, void *, int *, void *, int *);
|
||||
int close(int);
|
||||
int close_range(unsigned, unsigned, unsigned);
|
||||
int closefrom(int);
|
||||
@@ -94,16 +93,15 @@ int fchown(int, uint32_t, uint32_t);
|
||||
int fchownat(int, const char *, uint32_t, uint32_t, int);
|
||||
int fcntl(int, int, ...);
|
||||
int fdatasync(int);
|
||||
int filecmp(const char *, const char *);
|
||||
int flock(int, int);
|
||||
int fork(void);
|
||||
int fsync(int);
|
||||
int ftruncate(int, int64_t);
|
||||
int getdents(unsigned, void *, unsigned, long *);
|
||||
int getdomainname(char *, size_t);
|
||||
int getegid(void) nosideeffect;
|
||||
int geteuid(void) nosideeffect;
|
||||
int getgid(void) nosideeffect;
|
||||
uint32_t getegid(void) nosideeffect;
|
||||
uint32_t geteuid(void) nosideeffect;
|
||||
uint32_t getgid(void) nosideeffect;
|
||||
int getgroups(int size, uint32_t list[]);
|
||||
int gethostname(char *, size_t);
|
||||
int getloadavg(double *, int);
|
||||
int getpgid(int) libcesque;
|
||||
@@ -115,8 +113,8 @@ int getresgid(uint32_t *, uint32_t *, uint32_t *);
|
||||
int getresuid(uint32_t *, uint32_t *, uint32_t *);
|
||||
int getsid(int) nosideeffect libcesque;
|
||||
int gettid(void) libcesque;
|
||||
int getuid(void) libcesque;
|
||||
int iopl(int);
|
||||
uint32_t getuid(void) libcesque;
|
||||
int sys_iopl(int);
|
||||
int ioprio_get(int, int);
|
||||
int ioprio_set(int, int, int);
|
||||
int issetugid(void);
|
||||
@@ -135,11 +133,11 @@ int mkfifo(const char *, uint32_t);
|
||||
int mkfifoat(int, const char *, uint32_t);
|
||||
int mknod(const char *, uint32_t, uint64_t);
|
||||
int mknodat(int, const char *, int32_t, uint64_t);
|
||||
int mlock(const void *, size_t);
|
||||
int mlock2(const void *, size_t, int);
|
||||
int mlockall(int);
|
||||
int munlock(const void *, size_t);
|
||||
int munlockall(void);
|
||||
int sys_mlock(const void *, size_t);
|
||||
int sys_mlock2(const void *, size_t, int);
|
||||
int sys_mlockall(int);
|
||||
int sys_munlock(const void *, size_t);
|
||||
int sys_munlockall(void);
|
||||
int nice(int);
|
||||
int open(const char *, int, ...);
|
||||
int openat(int, const char *, int, ...);
|
||||
@@ -166,6 +164,7 @@ int seteuid(uint32_t);
|
||||
int setfsgid(int);
|
||||
int setfsuid(int);
|
||||
int setgid(int);
|
||||
int setgroups(size_t size, const uint32_t list[]);
|
||||
int setpgid(int, int);
|
||||
int setpgrp(void);
|
||||
int setpriority(int, unsigned, int);
|
||||
@@ -181,7 +180,7 @@ int symlink(const char *, const char *);
|
||||
int symlinkat(const char *, int, const char *);
|
||||
int sync_file_range(int, int64_t, int64_t, unsigned);
|
||||
int sys_ptrace(int, ...);
|
||||
int sysctl(const int *, unsigned, void *, size_t *, void *, size_t);
|
||||
int sys_sysctl(const int *, unsigned, void *, size_t *, void *, size_t);
|
||||
int tcsetpgrp(int, int32_t);
|
||||
int tgkill(int, int, int);
|
||||
int tkill(int, int);
|
||||
|
||||
@@ -97,6 +97,7 @@ o/$(MODE)/libc/calls/ntcontext2linux.o: private \
|
||||
|
||||
# we always want -O3 because:
|
||||
# it makes the code size smaller too
|
||||
o/$(MODE)/libc/calls/termios2host.o \
|
||||
o/$(MODE)/libc/calls/sigenter-freebsd.o \
|
||||
o/$(MODE)/libc/calls/sigenter-netbsd.o \
|
||||
o/$(MODE)/libc/calls/sigenter-openbsd.o \
|
||||
|
||||
+25
-16
@@ -26,35 +26,36 @@
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int sys_chdir_nt(const char *path) {
|
||||
textwindows int sys_chdir_nt_impl(char16_t path[hasatleast PATH_MAX],
|
||||
uint32_t len) {
|
||||
uint32_t n;
|
||||
int e, ms, err, len;
|
||||
char16_t path16[PATH_MAX], var[4];
|
||||
if ((len = __mkntpath(path, path16)) == -1) return -1;
|
||||
if (!len) return enoent();
|
||||
if (len && path16[len - 1] != u'\\') {
|
||||
int e, ms, err;
|
||||
char16_t var[4];
|
||||
|
||||
if (len && path[len - 1] != u'\\') {
|
||||
if (len + 2 > PATH_MAX) return enametoolong();
|
||||
path16[len + 0] = u'\\';
|
||||
path16[len + 1] = u'\0';
|
||||
path[len + 0] = u'\\';
|
||||
path[len + 1] = u'\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* chdir() seems flaky on windows 7
|
||||
* in a similar way to rmdir() sigh
|
||||
*/
|
||||
for (err = errno, ms = 1;; ms *= 2) {
|
||||
if (SetCurrentDirectory(path16)) {
|
||||
if (SetCurrentDirectory(path)) {
|
||||
/*
|
||||
* Now we need to set a magic environment variable.
|
||||
*/
|
||||
if ((n = GetCurrentDirectory(ARRAYLEN(path16), path16))) {
|
||||
if (n < ARRAYLEN(path16)) {
|
||||
if (!((path16[0] == '/' && path16[1] == '/') ||
|
||||
(path16[0] == '\\' && path16[1] == '\\'))) {
|
||||
if ((n = GetCurrentDirectory(PATH_MAX, path))) {
|
||||
if (n < PATH_MAX) {
|
||||
if (!((path[0] == '/' && path[1] == '/') ||
|
||||
(path[0] == '\\' && path[1] == '\\'))) {
|
||||
var[0] = '=';
|
||||
var[1] = path16[0];
|
||||
var[1] = path[0];
|
||||
var[2] = ':';
|
||||
var[3] = 0;
|
||||
if (!SetEnvironmentVariable(var, path16)) {
|
||||
if (!SetEnvironmentVariable(var, path)) {
|
||||
return __winerr();
|
||||
}
|
||||
}
|
||||
@@ -77,5 +78,13 @@ textwindows int sys_chdir_nt(const char *path) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return __fix_enotdir(-1, path16);
|
||||
return __fix_enotdir(-1, path);
|
||||
}
|
||||
|
||||
textwindows int sys_chdir_nt(const char *path) {
|
||||
int len;
|
||||
char16_t path16[PATH_MAX];
|
||||
if ((len = __mkntpath(path, path16)) == -1) return -1;
|
||||
if (!len) return enoent();
|
||||
return sys_chdir_nt_impl(path16, len);
|
||||
}
|
||||
+1
-1
@@ -16,7 +16,7 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/asan.internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/struct/timespec.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include "libc/calls/asan.internal.h"
|
||||
#include "libc/calls/clock_gettime.internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/struct/timespec.internal.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/calls/syscall_support-sysv.internal.h"
|
||||
|
||||
+4
-4
@@ -20,10 +20,10 @@
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/sock/syscall_fd.internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
@@ -59,7 +59,7 @@ int close(int fd) {
|
||||
// file descriptors the way __zipos_open() does need to retry if
|
||||
// there's indication this race condition happened.
|
||||
if (__isfdkind(fd, kFdZip)) {
|
||||
rc = weaken(__zipos_close)(fd);
|
||||
rc = _weaken(__zipos_close)(fd);
|
||||
} else {
|
||||
if (!IsWindows() && !IsMetal()) {
|
||||
rc = sys_close(fd);
|
||||
@@ -67,9 +67,9 @@ int close(int fd) {
|
||||
rc = 0;
|
||||
} else {
|
||||
if (__isfdkind(fd, kFdEpoll)) {
|
||||
rc = weaken(sys_close_epoll_nt)(fd);
|
||||
rc = _weaken(sys_close_epoll_nt)(fd);
|
||||
} else if (__isfdkind(fd, kFdSocket)) {
|
||||
rc = weaken(sys_closesocket_nt)(g_fds.p + fd);
|
||||
rc = _weaken(sys_closesocket_nt)(g_fds.p + fd);
|
||||
} else if (__isfdkind(fd, kFdFile) || //
|
||||
__isfdkind(fd, kFdConsole) || //
|
||||
__isfdkind(fd, kFdProcess)) { //
|
||||
|
||||
+15
-21
@@ -17,10 +17,10 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Closes inclusive range of file descriptors, e.g.
|
||||
@@ -32,33 +32,27 @@
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* This is supported on Linux 5.9+, FreeBSD, and OpenBSD. On FreeBSD,
|
||||
* `flags` must be zero. On OpenBSD, we call closefrom(int) so `last`
|
||||
* should be `-1` in order to get OpenBSD support, otherwise `ENOSYS`
|
||||
* will be returned. We also polyfill closefrom on FreeBSD since it's
|
||||
* available on older kernels.
|
||||
* The following flags are available:
|
||||
*
|
||||
* On Linux, the following flags are supported:
|
||||
* - `CLOSE_RANGE_UNSHARE` (Linux-only)
|
||||
* - `CLOSE_RANGE_CLOEXEC` (Linux-only)
|
||||
*
|
||||
* - CLOSE_RANGE_UNSHARE
|
||||
* - CLOSE_RANGE_CLOEXEC
|
||||
* This is only supported on Linux 5.9+ and FreeBSD 13+. Consider using
|
||||
* closefrom() which will work on OpenBSD too.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @error ENOSYS if not Linux 5.9+ / FreeBSD / OpenBSD
|
||||
* @error EBADF on OpenBSD if `first` is greater than highest fd
|
||||
* @error EINVAL if flags are bad or first is greater than last
|
||||
* @error EMFILE if a weird race condition happens on Linux
|
||||
* @error EINTR possibly on OpenBSD
|
||||
* @error ENOSYS if not Linux 5.9+ or FreeBSD 13+
|
||||
* @error ENOMEM on Linux maybe
|
||||
* @see closefrom()
|
||||
*/
|
||||
int close_range(unsigned int first, unsigned int last, unsigned int flags) {
|
||||
int rc, err;
|
||||
err = errno;
|
||||
if ((rc = sys_close_range(first, last, flags)) == -1) {
|
||||
if (errno == ENOSYS && first <= INT_MAX && last == UINT_MAX && !flags) {
|
||||
errno = err;
|
||||
rc = sys_closefrom(first);
|
||||
}
|
||||
int rc;
|
||||
if (IsLinux() || IsFreebsd()) {
|
||||
rc = sys_close_range(first, last, flags);
|
||||
} else {
|
||||
rc = enosys();
|
||||
}
|
||||
STRACE("close_range(%d, %d, %#x) → %d% m", first, last, flags, rc);
|
||||
return rc;
|
||||
|
||||
+14
-12
@@ -17,9 +17,10 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
@@ -34,26 +35,27 @@
|
||||
* }
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @error ENOSYS if not Linux 5.9+ / FreeBSD / OpenBSD
|
||||
* @error EBADF if `first` is negative
|
||||
* @error EBADF on OpenBSD if `first` is greater than highest fd
|
||||
* @error EINVAL if flags are bad or first is greater than last
|
||||
* @error EMFILE if a weird race condition happens on Linux
|
||||
* @error ENOSYS if not Linux 5.9+, FreeBSD 8+, or OpenBSD
|
||||
* @error EINTR possibly on OpenBSD
|
||||
* @error ENOMEM on Linux maybe
|
||||
* @note supported on Linux 5.9+, FreeBSD 8+, and OpenBSD
|
||||
*/
|
||||
int closefrom(int first) {
|
||||
int rc, err;
|
||||
if (first >= 0) {
|
||||
err = errno;
|
||||
if ((rc = sys_close_range(first, -1, 0)) == -1) {
|
||||
if (errno == ENOSYS) {
|
||||
errno = err;
|
||||
rc = sys_closefrom(first);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (IsNetbsd() || IsWindows() || IsMetal()) {
|
||||
rc = enosys();
|
||||
} else if (first < 0) {
|
||||
// consistent with openbsd
|
||||
// freebsd allows this but it's dangerous
|
||||
// necessary on linux due to type signature
|
||||
rc = ebadf();
|
||||
} else if (IsLinux()) {
|
||||
rc = sys_close_range(first, 0xffffffffu, 0);
|
||||
} else {
|
||||
rc = sys_closefrom(first);
|
||||
}
|
||||
STRACE("closefrom(%d) → %d% m", first, rc);
|
||||
return rc;
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
static struct CopyFileRange {
|
||||
pthread_once_t once;
|
||||
bool ok;
|
||||
} g_copy_file_range;
|
||||
|
||||
static bool HasCopyFileRange(void) {
|
||||
bool ok;
|
||||
int e, rc;
|
||||
e = errno;
|
||||
if (IsLinux()) {
|
||||
// We modernize our detection by a few years for simplicity.
|
||||
// This system call is chosen since it's listed by pledge().
|
||||
// https://www.cygwin.com/bugzilla/show_bug.cgi?id=26338
|
||||
ok = sys_close_range(-1, -2, 0) == -1 && errno == EINVAL;
|
||||
} else if (IsFreebsd()) {
|
||||
ok = sys_copy_file_range(-1, 0, -1, 0, 0, 0) == -1 && errno == EBADF;
|
||||
} else {
|
||||
ok = false;
|
||||
}
|
||||
errno = e;
|
||||
return ok;
|
||||
}
|
||||
|
||||
static void copy_file_range_init(void) {
|
||||
g_copy_file_range.ok = HasCopyFileRange();
|
||||
}
|
||||
|
||||
/**
|
||||
* Transfers data between files.
|
||||
*
|
||||
* If this system call is available (Linux c. 2018 or FreeBSD c. 2021)
|
||||
* and the file system supports it (e.g. ext4) and the source and dest
|
||||
* files are on the same file system, then this system call shall make
|
||||
* copies go about 2x faster.
|
||||
*
|
||||
* This implementation requires Linux 5.9+ even though the system call
|
||||
* was introduced in Linux 4.5. That's to ensure ENOSYS works reliably
|
||||
* due to a faulty backport, that happened in RHEL7. FreeBSD detection
|
||||
* on the other hand will work fine.
|
||||
*
|
||||
* @param infd is source file, which should be on same file system
|
||||
* @param opt_in_out_inoffset may be specified for pread() behavior
|
||||
* @param outfd should be a writable file, but not `O_APPEND`
|
||||
* @param opt_in_out_outoffset may be specified for pwrite() behavior
|
||||
* @param uptobytes is maximum number of bytes to transfer
|
||||
* @param flags is reserved for future use and must be zero
|
||||
* @return number of bytes transferred, or -1 w/ errno
|
||||
* @raise EXDEV if source and destination are on different filesystems
|
||||
* @raise EBADF if `infd` or `outfd` aren't open files or append-only
|
||||
* @raise EPERM if `fdout` refers to an immutable file on Linux
|
||||
* @raise EINVAL if ranges overlap or `flags` is non-zero
|
||||
* @raise EFBIG if `setrlimit(RLIMIT_FSIZE)` is exceeded
|
||||
* @raise EFAULT if one of the pointers memory is bad
|
||||
* @raise ERANGE if overflow happens computing ranges
|
||||
* @raise ENOSPC if file system has run out of space
|
||||
* @raise ETXTBSY if source or dest is a swap file
|
||||
* @raise EINTR if a signal was delivered instead
|
||||
* @raise EISDIR if source or dest is a directory
|
||||
* @raise ENOSYS if not Linux 5.9+ or FreeBSD 13+
|
||||
* @raise EIO if a low-level i/o error happens
|
||||
* @see sendfile() for seekable → socket
|
||||
* @see splice() for fd ↔ pipe
|
||||
*/
|
||||
ssize_t copy_file_range(int infd, int64_t *opt_in_out_inoffset, int outfd,
|
||||
int64_t *opt_in_out_outoffset, size_t uptobytes,
|
||||
uint32_t flags) {
|
||||
ssize_t rc;
|
||||
pthread_once(&g_copy_file_range.once, copy_file_range_init);
|
||||
if (!g_copy_file_range.ok) {
|
||||
rc = enosys();
|
||||
} else if (IsAsan() && ((opt_in_out_inoffset &&
|
||||
!__asan_is_valid(opt_in_out_inoffset, 8)) ||
|
||||
(opt_in_out_outoffset &&
|
||||
!__asan_is_valid(opt_in_out_outoffset, 8)))) {
|
||||
rc = efault();
|
||||
} else {
|
||||
rc = sys_copy_file_range(infd, opt_in_out_inoffset, outfd,
|
||||
opt_in_out_outoffset, uptobytes, flags);
|
||||
}
|
||||
STRACE("copy_file_range(%d, %s, %d, %s, %'zu, %#x) → %'ld% m", infd,
|
||||
DescribeInOutInt64(rc, opt_in_out_inoffset), outfd,
|
||||
DescribeInOutInt64(rc, opt_in_out_outoffset), uptobytes, flags);
|
||||
return rc;
|
||||
}
|
||||
@@ -110,8 +110,8 @@ static int sys_copyfile(const char *src, const char *dst, int flags) {
|
||||
* @param flags may have COPYFILE_PRESERVE_TIMESTAMPS, COPYFILE_NOCLOBBER
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
*/
|
||||
int copyfile(const char *src, const char *dst, int flags) {
|
||||
if (!IsWindows() || startswith(src, "/zip/") || startswith(dst, "/zip/")) {
|
||||
int _copyfile(const char *src, const char *dst, int flags) {
|
||||
if (!IsWindows() || _startswith(src, "/zip/") || _startswith(dst, "/zip/")) {
|
||||
return sys_copyfile(src, dst, flags);
|
||||
} else {
|
||||
return sys_copyfile_nt(src, dst, flags);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
int copyfile(const char *, const char *, int) paramsnonnull();
|
||||
int _copyfile(const char *, const char *, int) paramsnonnull();
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
||||
+7
-9
@@ -16,6 +16,7 @@
|
||||
│ 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/calls/internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
@@ -27,15 +28,12 @@
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Implements dup(), dup2(), dup3(), and F_DUPFD for Windows.
|
||||
*/
|
||||
// Implements dup(), dup2(), dup3(), and F_DUPFD for Windows.
|
||||
textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
|
||||
int64_t rc, proc, handle;
|
||||
|
||||
// validate the api usage
|
||||
if (oldfd < 0) return ebadf();
|
||||
if (flags & ~O_CLOEXEC) return einval();
|
||||
_unassert(oldfd >= 0);
|
||||
_unassert(newfd >= -1);
|
||||
_unassert(!(flags & ~O_CLOEXEC));
|
||||
|
||||
__fds_lock();
|
||||
|
||||
@@ -80,9 +78,9 @@ textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
|
||||
g_fds.p[newfd].mode = g_fds.p[oldfd].mode;
|
||||
g_fds.p[newfd].flags = g_fds.p[oldfd].flags & ~O_CLOEXEC;
|
||||
if (flags & O_CLOEXEC) g_fds.p[newfd].flags |= O_CLOEXEC;
|
||||
if (g_fds.p[oldfd].kind == kFdSocket && weaken(_dupsockfd)) {
|
||||
if (g_fds.p[oldfd].kind == kFdSocket && _weaken(_dupsockfd)) {
|
||||
g_fds.p[newfd].extra =
|
||||
(intptr_t)weaken(_dupsockfd)((struct SockFd *)g_fds.p[oldfd].extra);
|
||||
(intptr_t)_weaken(_dupsockfd)((struct SockFd *)g_fds.p[oldfd].extra);
|
||||
} else {
|
||||
g_fds.p[newfd].extra = g_fds.p[oldfd].extra;
|
||||
}
|
||||
|
||||
+1
-1
@@ -18,10 +18,10 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
||||
+33
-22
@@ -16,41 +16,52 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/calls/syscall_support-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
#define F_DUP2FD 10
|
||||
#define F_DUP2FD_CLOEXEC 18
|
||||
|
||||
int32_t sys_dup3(int32_t oldfd, int32_t newfd, int flags) {
|
||||
static bool once;
|
||||
static bool demodernize;
|
||||
int olderr, how, fd;
|
||||
if (!once) {
|
||||
olderr = errno;
|
||||
fd = __sys_dup3(oldfd, newfd, flags);
|
||||
if (fd == -1 && errno == ENOSYS) {
|
||||
STRACE("demodernizing %s() due to %s", "dup3", "RHEL5:CVE-2010-3301");
|
||||
demodernize = true;
|
||||
once = true;
|
||||
errno = olderr;
|
||||
} else {
|
||||
once = true;
|
||||
return fd;
|
||||
}
|
||||
} else if (!demodernize) {
|
||||
return __sys_dup3(oldfd, newfd, flags);
|
||||
static struct Dup3 {
|
||||
pthread_once_t once;
|
||||
bool demodernize;
|
||||
} g_dup3;
|
||||
|
||||
static void sys_dup3_test(void) {
|
||||
int e = errno;
|
||||
__sys_dup3(-1, -1, 0);
|
||||
if ((g_dup3.demodernize = errno == ENOSYS)) {
|
||||
STRACE("demodernizing %s() due to %s", "dup3", "ENOSYS");
|
||||
}
|
||||
if (oldfd == newfd) return einval();
|
||||
if (flags & ~O_CLOEXEC) return einval();
|
||||
errno = e;
|
||||
}
|
||||
|
||||
int32_t sys_dup3(int32_t oldfd, int32_t newfd, int flags) {
|
||||
int how;
|
||||
_unassert(oldfd >= 0);
|
||||
_unassert(newfd >= 0);
|
||||
_unassert(!(flags & ~O_CLOEXEC));
|
||||
|
||||
if (IsFreebsd()) {
|
||||
how = flags & O_CLOEXEC ? F_DUP2FD_CLOEXEC : F_DUP2FD;
|
||||
if (flags & O_CLOEXEC) {
|
||||
how = F_DUP2FD_CLOEXEC;
|
||||
} else {
|
||||
how = F_DUP2FD;
|
||||
}
|
||||
return __sys_fcntl(oldfd, how, newfd);
|
||||
}
|
||||
|
||||
pthread_once(&g_dup3.once, sys_dup3_test);
|
||||
|
||||
if (!g_dup3.demodernize) {
|
||||
return __sys_dup3(oldfd, newfd, flags);
|
||||
} else {
|
||||
return __fixupnewfd(sys_dup2(oldfd, newfd), flags);
|
||||
}
|
||||
|
||||
+7
-6
@@ -18,10 +18,11 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.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"
|
||||
|
||||
/**
|
||||
@@ -46,14 +47,14 @@
|
||||
*/
|
||||
int dup3(int oldfd, int newfd, int flags) {
|
||||
int rc;
|
||||
if (__isfdkind(oldfd, kFdZip)) {
|
||||
if (oldfd == newfd || (flags & ~O_CLOEXEC)) {
|
||||
rc = einval(); // NetBSD doesn't do this
|
||||
} else if (oldfd < 0 || newfd < 0) {
|
||||
rc = ebadf();
|
||||
} else if (__isfdkind(oldfd, kFdZip)) {
|
||||
rc = eopnotsupp();
|
||||
} else if (oldfd == newfd) {
|
||||
rc = einval();
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_dup3(oldfd, newfd, flags);
|
||||
} else if (newfd < 0) {
|
||||
rc = ebadf();
|
||||
} else {
|
||||
rc = sys_dup_nt(oldfd, newfd, flags, -1);
|
||||
}
|
||||
|
||||
@@ -20,9 +20,8 @@
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/ntspawn.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/nt/accounting.h"
|
||||
#include "libc/nt/console.h"
|
||||
|
||||
+5
-5
@@ -16,18 +16,18 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/likely.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/pledge.h"
|
||||
#include "libc/calls/pledge.internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/likely.h"
|
||||
#include "libc/intrin/promises.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
@@ -71,8 +71,8 @@ int execve(const char *prog, char *const argv[], char *const envp[]) {
|
||||
#endif
|
||||
if (!IsWindows()) {
|
||||
rc = 0;
|
||||
if (IsLinux() && __execpromises && weaken(sys_pledge_linux)) {
|
||||
rc = weaken(sys_pledge_linux)(__execpromises, __pledge_mode);
|
||||
if (IsLinux() && __execpromises && _weaken(sys_pledge_linux)) {
|
||||
rc = _weaken(sys_pledge_linux)(__execpromises, __pledge_mode);
|
||||
}
|
||||
if (!rc) {
|
||||
rc = sys_execve(prog, argv, envp);
|
||||
|
||||
@@ -16,15 +16,15 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
@@ -45,8 +45,8 @@ int faccessat(int dirfd, const char *path, int mode, uint32_t flags) {
|
||||
int e, rc;
|
||||
if (IsAsan() && !__asan_is_valid(path, 1)) {
|
||||
rc = efault();
|
||||
} else if (weaken(__zipos_notat) &&
|
||||
weaken(__zipos_notat)(dirfd, path) == -1) {
|
||||
} else if (_weaken(__zipos_notat) &&
|
||||
_weaken(__zipos_notat)(dirfd, path) == -1) {
|
||||
rc = -1; /* TODO(jart): implement me */
|
||||
} else if (!IsWindows()) {
|
||||
e = errno;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/nt/createfile.h"
|
||||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/nt/enum/filetype.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/sysv/consts/madv.h"
|
||||
@@ -33,6 +34,7 @@ textwindows int sys_fadvise_nt(int fd, uint64_t offset, uint64_t len,
|
||||
int rc, flags, mode;
|
||||
uint32_t perm, share, attr;
|
||||
|
||||
if ((int64_t)len < 0) return einval();
|
||||
if (!__isfdkind(fd, kFdFile)) return ebadf();
|
||||
h1 = g_fds.p[fd].handle;
|
||||
mode = g_fds.p[fd].mode;
|
||||
@@ -57,6 +59,10 @@ textwindows int sys_fadvise_nt(int fd, uint64_t offset, uint64_t len,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (GetFileType(h1) == kNtFileTypePipe) {
|
||||
return espipe();
|
||||
}
|
||||
|
||||
// MSDN says only these are allowed, otherwise it returns EINVAL.
|
||||
attr &= kNtFileFlagBackupSemantics | kNtFileFlagDeleteOnClose |
|
||||
kNtFileFlagNoBuffering | kNtFileFlagOpenNoRecall |
|
||||
|
||||
+30
-7
@@ -16,11 +16,17 @@
|
||||
│ 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/calls/strace.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int sys_fadvise_netbsd(int, int, int64_t, int64_t, int) asm("sys_fadvise");
|
||||
|
||||
/**
|
||||
* Drops hints to O/S about intended I/O behavior.
|
||||
@@ -28,16 +34,33 @@
|
||||
* It makes a huge difference. For example, when copying a large file,
|
||||
* it can stop the system from persisting GBs of useless memory content.
|
||||
*
|
||||
* @param len 0 means ‘til end of file
|
||||
* @param len 0 means until end of file
|
||||
* @param advice can be MADV_SEQUENTIAL, MADV_RANDOM, etc.
|
||||
* @return -1 on error
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise EBADF if `fd` isn't a valid file descriptor
|
||||
* @raise ESPIPE if `fd` refers to a pipe
|
||||
* @raise EINVAL if `advice` was invalid
|
||||
* @raise ENOSYS on XNU and OpenBSD
|
||||
*/
|
||||
int fadvise(int fd, uint64_t offset, uint64_t len, int advice) {
|
||||
int rc;
|
||||
if (!IsWindows()) {
|
||||
rc = sys_fadvise(fd, offset, len, advice); /* linux & freebsd */
|
||||
} else {
|
||||
int rc, e = errno;
|
||||
if (IsLinux()) {
|
||||
rc = sys_fadvise(fd, offset, len, advice);
|
||||
} else if (IsFreebsd() || IsNetbsd()) {
|
||||
if (IsFreebsd()) {
|
||||
rc = sys_fadvise(fd, offset, len, advice);
|
||||
} else {
|
||||
rc = sys_fadvise_netbsd(fd, offset, offset, len, advice);
|
||||
}
|
||||
_npassert(rc >= 0);
|
||||
if (rc) {
|
||||
errno = rc;
|
||||
rc = -1;
|
||||
}
|
||||
} else if (IsWindows()) {
|
||||
rc = sys_fadvise_nt(fd, offset, len, advice);
|
||||
} else {
|
||||
rc = enosys();
|
||||
}
|
||||
STRACE("fadvise(%d, %'lu, %'lu, %d) → %d% m", fd, offset, len, advice, rc);
|
||||
return rc;
|
||||
|
||||
+5
-13
@@ -23,20 +23,12 @@
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int sys_chdir_nt_impl(char16_t[hasatleast PATH_MAX], uint32_t);
|
||||
|
||||
textwindows int sys_fchdir_nt(int dirfd) {
|
||||
uint32_t len;
|
||||
char16_t dir[PATH_MAX];
|
||||
if (!__isfdkind(dirfd, kFdFile)) return ebadf();
|
||||
len = GetFinalPathNameByHandle(g_fds.p[dirfd].handle, dir, ARRAYLEN(dir),
|
||||
kNtFileNameNormalized | kNtVolumeNameDos);
|
||||
if (len + 1 + 1 > ARRAYLEN(dir)) return enametoolong();
|
||||
if (dir[len - 1] != u'\\') {
|
||||
dir[len + 0] = u'\\';
|
||||
dir[len + 1] = u'\0';
|
||||
}
|
||||
if (SetCurrentDirectory(dir)) {
|
||||
return 0;
|
||||
} else {
|
||||
return __winerr();
|
||||
}
|
||||
return sys_chdir_nt_impl(
|
||||
dir, GetFinalPathNameByHandle(g_fds.p[dirfd].handle, dir, ARRAYLEN(dir),
|
||||
kNtFileNameNormalized | kNtVolumeNameDos));
|
||||
}
|
||||
@@ -16,14 +16,14 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
|
||||
@@ -45,7 +45,8 @@ int fchmodat(int dirfd, const char *path, uint32_t mode, int flags) {
|
||||
int rc;
|
||||
if (IsAsan() && !__asan_is_valid(path, 1)) {
|
||||
rc = efault();
|
||||
} else if (weaken(__zipos_notat) && (rc = __zipos_notat(dirfd, path)) == -1) {
|
||||
} else if (_weaken(__zipos_notat) &&
|
||||
(rc = __zipos_notat(dirfd, path)) == -1) {
|
||||
rc = eopnotsupp();
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_fchmodat(dirfd, path, mode, flags);
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
|
||||
|
||||
@@ -16,13 +16,13 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
|
||||
@@ -44,7 +44,8 @@ int fchownat(int dirfd, const char *path, uint32_t uid, uint32_t gid,
|
||||
int rc;
|
||||
if (IsAsan() && !__asan_is_valid(path, 1)) {
|
||||
rc = efault();
|
||||
} else if (weaken(__zipos_notat) && (rc = __zipos_notat(dirfd, path)) == -1) {
|
||||
} else if (_weaken(__zipos_notat) &&
|
||||
(rc = __zipos_notat(dirfd, path)) == -1) {
|
||||
STRACE("zipos fchownat not supported yet");
|
||||
} else {
|
||||
rc = sys_fchownat(dirfd, path, uid, gid, flags);
|
||||
|
||||
+69
-41
@@ -24,42 +24,47 @@
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/calls/wincrash.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/cmpxchg.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/createfile.h"
|
||||
#include "libc/nt/enum/accessmask.h"
|
||||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
#include "libc/nt/enum/filelockflags.h"
|
||||
#include "libc/nt/enum/filesharemode.h"
|
||||
#include "libc/nt/enum/formatmessageflags.h"
|
||||
#include "libc/nt/errors.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/process.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/struct/byhandlefileinformation.h"
|
||||
#include "libc/nt/struct/overlapped.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/sysv/consts/f.h"
|
||||
#include "libc/sysv/consts/fd.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
bool __force_sqlite_to_work_until_we_can_fix_it;
|
||||
|
||||
static textwindows int sys_fcntl_nt_dupfd(int fd, int cmd, int start) {
|
||||
if (start < 0) return einval();
|
||||
return sys_dup_nt(fd, -1, (cmd == F_DUPFD_CLOEXEC ? O_CLOEXEC : 0), start);
|
||||
}
|
||||
|
||||
static textwindows int sys_fcntl_nt_lock(struct Fd *f, int cmd, uintptr_t arg) {
|
||||
int e;
|
||||
struct flock *l;
|
||||
uint32_t flags, err;
|
||||
struct NtOverlapped ov;
|
||||
int64_t pos, off, len, size;
|
||||
struct NtByHandleFileInformation info;
|
||||
if (!GetFileInformationByHandle(f->handle, &info)) return __winerr();
|
||||
if (!SetFilePointerEx(f->handle, 0, &pos, SEEK_CUR)) return __winerr();
|
||||
|
||||
if (!GetFileInformationByHandle(f->handle, &info)) {
|
||||
return __winerr();
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
if (!SetFilePointerEx(f->handle, 0, &pos, SEEK_CUR)) {
|
||||
return __winerr();
|
||||
}
|
||||
|
||||
l = (struct flock *)arg;
|
||||
len = l->l_len;
|
||||
off = l->l_start;
|
||||
size = (uint64_t)info.nFileSizeHigh << 32 | info.nFileSizeLow;
|
||||
|
||||
switch (l->l_whence) {
|
||||
case SEEK_SET:
|
||||
break;
|
||||
@@ -72,37 +77,60 @@ static textwindows int sys_fcntl_nt_lock(struct Fd *f, int cmd, uintptr_t arg) {
|
||||
default:
|
||||
return einval();
|
||||
}
|
||||
if (!len) len = size - off;
|
||||
if (off < 0 || len < 0) return einval();
|
||||
_offset2overlap(f->handle, off, &ov);
|
||||
if (l->l_type == F_RDLCK || l->l_type == F_WRLCK) {
|
||||
flags = 0;
|
||||
if (cmd == F_SETLK) flags |= kNtLockfileFailImmediately;
|
||||
/* TODO: How can we make SQLite locks on Windows to work? */
|
||||
/* if (l->l_type == F_WRLCK) flags |= kNtLockfileExclusiveLock; */
|
||||
if (LockFileEx(f->handle, flags, 0, len, len >> 32, &ov)) {
|
||||
return 0;
|
||||
} else {
|
||||
err = GetLastError();
|
||||
if (err == kNtErrorLockViolation) err = EAGAIN;
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
} else if (l->l_type == F_UNLCK) {
|
||||
if (UnlockFileEx(f->handle, 0, len, len >> 32, &ov)) {
|
||||
return 0;
|
||||
} else {
|
||||
err = GetLastError();
|
||||
if (err == kNtErrorNotLocked) {
|
||||
return 0;
|
||||
} else {
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
if (!len) {
|
||||
len = size - off;
|
||||
}
|
||||
|
||||
if (off < 0 || len < 0) {
|
||||
return einval();
|
||||
}
|
||||
|
||||
bool32 ok;
|
||||
struct NtOverlapped ov = {.hEvent = f->handle,
|
||||
.Pointer = (void *)(uintptr_t)off};
|
||||
|
||||
if (l->l_type == F_RDLCK || l->l_type == F_WRLCK) {
|
||||
flags = 0;
|
||||
if (cmd != F_SETLKW) {
|
||||
flags |= kNtLockfileFailImmediately;
|
||||
}
|
||||
if (l->l_type == F_WRLCK) {
|
||||
flags |= kNtLockfileExclusiveLock;
|
||||
}
|
||||
ok = LockFileEx(f->handle, flags, 0, len, len >> 32, &ov);
|
||||
if (cmd == F_GETLK) {
|
||||
if (ok) {
|
||||
l->l_type = F_UNLCK;
|
||||
if (!UnlockFileEx(f->handle, 0, len, len >> 32, &ov)) {
|
||||
notpossible;
|
||||
}
|
||||
} else {
|
||||
l->l_pid = -1;
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
if (ok || __force_sqlite_to_work_until_we_can_fix_it) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (l->l_type == F_UNLCK) {
|
||||
if (cmd == F_GETLK) return einval();
|
||||
e = errno;
|
||||
if (UnlockFileEx(f->handle, 0, len, len >> 32, &ov)) {
|
||||
return 0;
|
||||
} else if (errno == ENOLCK) {
|
||||
errno = e;
|
||||
return 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return einval();
|
||||
}
|
||||
|
||||
textwindows int sys_fcntl_nt(int fd, int cmd, uintptr_t arg) {
|
||||
|
||||
@@ -20,12 +20,14 @@
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/calls/syscall_support-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/sysv/consts/f.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int sys_fcntl(int fd, int cmd, uintptr_t arg) {
|
||||
int rc;
|
||||
int e, rc;
|
||||
bool islock;
|
||||
if ((islock = cmd == F_GETLK || //
|
||||
cmd == F_SETLK || //
|
||||
@@ -37,9 +39,13 @@ int sys_fcntl(int fd, int cmd, uintptr_t arg) {
|
||||
}
|
||||
cosmo2flock(arg);
|
||||
}
|
||||
e = errno;
|
||||
rc = __sys_fcntl(fd, cmd, arg);
|
||||
if (islock) {
|
||||
flock2cosmo(arg);
|
||||
} else if (rc == -1 && cmd == F_DUPFD_CLOEXEC && errno == EINVAL) {
|
||||
errno = e;
|
||||
rc = __fixupnewfd(__sys_fcntl(fd, F_DUPFD, arg), O_CLOEXEC);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
+5
-7
@@ -18,10 +18,10 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
@@ -37,11 +37,9 @@
|
||||
* CHECK_GE((newfd = fcntl(oldfd, F_DUPFD, 3)), 3);
|
||||
* CHECK_GE((newfd = fcntl(oldfd, F_DUPFD_CLOEXEC, 3)), 3);
|
||||
*
|
||||
* This function implements POSIX Advisory Locks, e.g.
|
||||
*
|
||||
* CHECK_NE(-1, fcntl(zfd, F_SETLKW, &(struct flock){F_WRLCK}));
|
||||
* // ...
|
||||
* CHECK_NE(-1, fcntl(zfd, F_SETLK, &(struct flock){F_UNLCK}));
|
||||
* This function implements POSIX Advisory Locks, which let independent
|
||||
* processes (and on Windows, threads too!) read/write lock byte ranges
|
||||
* of files. See `test/libc/calls/lock_test.c` for an example.
|
||||
*
|
||||
* Please be warned that locks currently do nothing on Windows since
|
||||
* figuring out how to polyfill them correctly is a work in progress.
|
||||
@@ -61,7 +59,7 @@ int fcntl(int fd, int cmd, ...) {
|
||||
va_end(va);
|
||||
if (fd >= 0) {
|
||||
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
||||
rc = weaken(__zipos_fcntl)(fd, cmd, arg);
|
||||
rc = _weaken(__zipos_fcntl)(fd, cmd, arg);
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_fcntl(fd, cmd, arg);
|
||||
} else {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
||||
@@ -16,9 +16,7 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/metastat.internal.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
@@ -26,6 +24,8 @@
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
@@ -54,9 +54,9 @@ bool fileexists(const char *path) {
|
||||
if (IsAsan() && !__asan_is_valid(path, 1)) {
|
||||
efault();
|
||||
res = false;
|
||||
} else if (weaken(__zipos_open) &&
|
||||
weaken(__zipos_parseuri)(path, &zipname) != -1) {
|
||||
if (weaken(__zipos_stat)(&zipname, &st.cosmo) != -1) {
|
||||
} else if (_weaken(__zipos_open) &&
|
||||
_weaken(__zipos_parseuri)(path, &zipname) != -1) {
|
||||
if (_weaken(__zipos_stat)(&zipname, &st.cosmo) != -1) {
|
||||
res = true;
|
||||
} else {
|
||||
res = false;
|
||||
|
||||
@@ -16,19 +16,19 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/calls/syscall_support-sysv.internal.h"
|
||||
#include "libc/sysv/consts/f.h"
|
||||
#include "libc/sysv/consts/fd.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
||||
/**
|
||||
* Applies file descriptor fixups on XNU or old Linux.
|
||||
* @see __fixupnewsockfd() for socket file descriptors
|
||||
*/
|
||||
// Applies file descriptor fixups on XNU or old Linux.
|
||||
// See __fixupnewsockfd() for socket file descriptors.
|
||||
int __fixupnewfd(int fd, int flags) {
|
||||
if (fd != -1) {
|
||||
if (flags & O_CLOEXEC) {
|
||||
__sys_fcntl(fd, F_SETFD, FD_CLOEXEC);
|
||||
_npassert(!__sys_fcntl(fd, F_SETFD, FD_CLOEXEC));
|
||||
}
|
||||
}
|
||||
return fd;
|
||||
|
||||
+34
-13
@@ -17,28 +17,49 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/nt/enum/filelockflags.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/struct/byhandlefileinformation.h"
|
||||
#include "libc/nt/struct/overlapped.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/lock.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
#define _LOCK_SH 0
|
||||
#define _LOCK_EX kNtLockfileExclusiveLock
|
||||
#define _LOCK_NB kNtLockfileFailImmediately
|
||||
#define _LOCK_UN 8
|
||||
|
||||
textwindows int sys_flock_nt(int fd, int op) {
|
||||
struct NtOverlapped ov;
|
||||
int64_t h;
|
||||
struct NtByHandleFileInformation info;
|
||||
if (!__isfdkind(fd, kFdFile)) return ebadf();
|
||||
bzero(&ov, sizeof(ov));
|
||||
if (GetFileInformationByHandle(g_fds.p[fd].handle, &info) &&
|
||||
((!(op & LOCK_UN) &&
|
||||
LockFileEx(g_fds.p[fd].handle, op, 0, info.nFileSizeLow,
|
||||
info.nFileSizeHigh, &ov)) ||
|
||||
((op & LOCK_UN) && UnlockFileEx(g_fds.p[fd].handle, 0, info.nFileSizeLow,
|
||||
info.nFileSizeHigh, &ov)))) {
|
||||
return 0;
|
||||
} else {
|
||||
h = g_fds.p[fd].handle;
|
||||
struct NtOverlapped ov = {.hEvent = h};
|
||||
|
||||
if (!GetFileInformationByHandle(h, &info)) {
|
||||
return __winerr();
|
||||
}
|
||||
|
||||
if (op & _LOCK_UN) {
|
||||
if (op & ~_LOCK_UN) {
|
||||
return einval();
|
||||
}
|
||||
if (UnlockFileEx(h, 0, info.nFileSizeLow, info.nFileSizeHigh, &ov)) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (op & ~(_LOCK_SH | _LOCK_EX | _LOCK_NB)) {
|
||||
return einval();
|
||||
}
|
||||
|
||||
if (LockFileEx(h, op, 0, info.nFileSizeLow, info.nFileSizeHigh, &ov)) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
||||
@@ -17,12 +17,13 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/intrin/bsr.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/tpenc.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/nt/enum/fileinfobyhandleclass.h"
|
||||
#include "libc/nt/enum/filetype.h"
|
||||
@@ -33,7 +34,6 @@
|
||||
#include "libc/nt/struct/filecompressioninfo.h"
|
||||
#include "libc/nt/struct/reparsedatabuffer.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/tpenc.h"
|
||||
#include "libc/str/utf16.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
@@ -61,7 +61,7 @@ static textwindows uint32_t GetSizeOfReparsePoint(int64_t fh) {
|
||||
x = 0xfffd;
|
||||
}
|
||||
}
|
||||
z += x < 0200 ? 1 : bsrl(tpenc(x)) >> 3;
|
||||
z += x < 0200 ? 1 : _bsrl(_tpenc(x)) >> 3;
|
||||
}
|
||||
} else {
|
||||
STRACE("%s failed %m", "GetSizeOfReparsePoint");
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Supports fstat(), etc. implementations.
|
||||
* Forms fstat() on System Five.
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int32_t sys_fstat(int32_t fd, struct stat *st) {
|
||||
|
||||
+2
-2
@@ -18,11 +18,11 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/stat.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
@@ -39,7 +39,7 @@
|
||||
int fstat(int fd, struct stat *st) {
|
||||
int rc;
|
||||
if (__isfdkind(fd, kFdZip)) {
|
||||
rc = weaken(__zipos_fstat)(
|
||||
rc = _weaken(__zipos_fstat)(
|
||||
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, st);
|
||||
} else if (!IsWindows() && !IsMetal()) {
|
||||
rc = sys_fstat(fd, st);
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Supports stat(), lstat(), fstatat(), etc. implementations.
|
||||
* Performs fstatat() on System Five.
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int32_t sys_fstatat(int32_t dirfd, const char *path, struct stat *st,
|
||||
|
||||
@@ -19,13 +19,13 @@
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/stat.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
@@ -59,10 +59,10 @@ int fstatat(int dirfd, const char *path, struct stat *st, int flags) {
|
||||
if (__isfdkind(dirfd, kFdZip)) {
|
||||
STRACE("zipos dirfd not supported yet");
|
||||
rc = einval();
|
||||
} else if (weaken(__zipos_stat) &&
|
||||
weaken(__zipos_parseuri)(path, &zipname) != -1) {
|
||||
} else if (_weaken(__zipos_stat) &&
|
||||
_weaken(__zipos_parseuri)(path, &zipname) != -1) {
|
||||
if (!__vforked) {
|
||||
rc = weaken(__zipos_stat)(&zipname, st);
|
||||
rc = _weaken(__zipos_stat)(&zipname, st);
|
||||
} else {
|
||||
rc = enotsup();
|
||||
}
|
||||
|
||||
Loaded 100 of 2173 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user