Compare commits

...
43 Commits
Author SHA1 Message Date
Justine Tunney 8c2bf341e9 Release Cosmopolitan 2.1 2022-09-20 05:19:30 -07:00
Justine Tunney 6cc9e08f1b Introduce cosmocc and cosmoc++ toolchain commands 2022-09-20 04:34:03 -07:00
Justine Tunney bfb85fe6d0 Remove a bunch of stuff that shouldn't be in docs 2022-09-20 02:57:46 -07:00
Justine Tunney 2cc1d5ac4c Improve redbean method=get parameter handling 2022-09-19 20:04:39 -07:00
Justine Tunney 6e582d245b Improve some timespec functions 2022-09-19 16:13:37 -07:00
Justine Tunney 2395a9eced Work around copy_file_range() GitHub Actions issue 2022-09-19 16:12:56 -07:00
Justine Tunney 0060940d84 Fix MODE=opt build 2022-09-19 15:43:52 -07:00
Justine Tunney 1ea01fc905 Fix pledge() thread killing semantics
- tkill(tid, sig) should be allowed by stdio
- tgkill(getpid(), tid, sig) should be allowed by stdio

Fixes #628
2022-09-19 15:34:11 -07:00
Justine Tunney c7a8cd21e9 Improve system call wrappers
This change improves copy_file_range(), sendfile(), splice(), openpty(),
closefrom(), close_range(), fadvise() and posix_fadvise() in addition to
writing tests that confirm things like errno and seeking behavior across
platforms. We now less aggressively polyfill behavior with some of these
functions when the platform support isn't available. Please see:

https://justine.lol/cosmopolitan/functions.html
2022-09-19 15:06:25 -07:00
Justine Tunney 224c12f54d Make zlib go faster 2022-09-18 06:30:45 -07:00
Justine Tunney be29b709b7 Fix pledge.com interop with Go DNS
Based on a pure analysis of the Go source code, it wants:

- SOL_SOCKET + SO_BROADCAST
- IPPROTO_IPV6 + IPV6_V6ONLY

Fixes #627
2022-09-18 03:56:52 -07:00
Justine Tunney e14ae1642e Fix MbedTLS Cloudflare interop in MODE=tiny 2022-09-18 03:52:09 -07:00
Justine Tunney 40991ec992 Fix getgroups / setgroups tests across platforms
See #619
2022-09-18 03:18:38 -07:00
Justine Tunney 97bb5a3a80 Fix MODE=dbg build 2022-09-18 03:16:14 -07:00
Justine Tunney bc3d84341d Fix redbean unix.nanosleep() documentation 2022-09-18 03:02:26 -07:00
tkchia c937fbb222 [metal] Export struct offsets from C code (#625)
Rather than computing them by hand.
2022-09-18 02:54:55 -07:00
tkchia cdf9e8c8a3 Bare metal VGA: fix mapping of ECMA-48 colors to VGA colors (#622)
See https://github.com/jart/cosmopolitan/pull/613#issuecomment-1247490693
2022-09-18 02:50:00 -07:00
Gavin Hayes 4c40c500b8 Add getgroups and setgroups (#619) 2022-09-18 02:48:53 -07:00
Justine Tunney 3665232d66 Release redbean 2.0.19 2022-09-17 02:18:19 -07:00
Justine Tunney 775944a2d0 Fix important bugs in redbean
This change upgrades to the latest Chromium Zlib, fixes bugs in redbean,
and introduces better support for reverse proxies like Cloudflare. This
change improves the security of redbean and it's recommended that users
upgrade to the release that'll follow. This change also updates the docs
to clarify how to use the security tools redbean provides e.g. pledge(),
unveil(), and the MODE=asan builds which improve memory safety.
2022-09-17 02:18:06 -07:00
Justine Tunney 994e1f4386 Improve pthread_join()
Since we're now on Windows 8, we can have clone() work as advertised on
Windows, where it sends a futex wake to the child tid. It's also likely
we no longer need to work around thread flakes on OpenBSD, in _wait0().
2022-09-16 14:02:06 -07:00
tkchia 3733b43a8f Bare metal: fix corner case in __normalize_e820( ) (#624)
See https://github.com/jart/cosmopolitan/pull/609#issuecomment-1247083243
2022-09-15 21:09:29 -07:00
Justine Tunney 134ffee519 Change support vector to Windows 8+
Doing this makes binaries tinier, since we don't need to have all the
extra code for supporting a 32-bit address space. It also benefits us
because we're able to use WIN32 futexes, which makes locking simpler.

b69f3d2488 is what officially ended our
Windows 7 support. This change is merely a formalization. You can use
old versions of Cosmo now and forevermore if you need Windows 7 since
our repository is hermetic and vendors all its dependencies.

Won't fix #617
2022-09-15 03:55:05 -07:00
Connor 6c90f830d9 Retain DWARF 5 sections for line numbers (#618)
Fixes #594
2022-09-14 23:03:49 -07:00
Gavin Hayes 14731d61fa fix MODE=dbg python build (#620) 2022-09-14 22:53:44 -07:00
Paul Kulchenko 418bcb39af Allow optional double quotes in dd parameters on macOS (#621) 2022-09-14 22:53:20 -07:00
Justine Tunney 3f49889841 Make important improvements
- Fix preadv() and pwritev() for old distros
- Introduce _npassert() and _unassert() macros
- Prove that file locks work properly on Windows
- Support fcntl(F_DUPFD_CLOEXEC) on more systems
2022-09-14 22:39:08 -07:00
Justine Tunney 1ad2f530f9 Add script.com and whois.com courtesy of FreeBSD 2022-09-13 20:26:13 -07:00
Justine Tunney 654ceaba7d Clean up threading code some more 2022-09-13 20:17:34 -07:00
tkchia 6a3330d7c9 VGA tty initialization should not run outside of bare metal mode (#614) 2022-09-13 15:27:19 -07:00
tkchia 945699694e Bare metal VGA: clarify code comments (#616) 2022-09-13 15:26:33 -07:00
Justine Tunney aab4ee4072 Add sys_ prefix to unwrapped system calls
This change also implements getlogin() and getlogin_r().
2022-09-13 11:20:35 -07:00
Justine Tunney 8f5678882d Make dos errno multimapping linkage tinier
640 bytes for old kDos2Errno table
182 bytes for new kDos2Errno under hello2.com (MODE=fastbuild)
122 bytes for new kDos2Errno under hello2.com (MODE=tiny)
2022-09-13 06:25:50 -07:00
Justine Tunney 9fa6725067 Fix bug with sendfile() on XNU 2022-09-13 04:32:29 -07:00
Justine Tunney 06f9a5b627 Get repository to build with GCC 11
See #594
2022-09-13 04:14:55 -07:00
Justine Tunney 446a1f7c5a Fix the build 2022-09-13 02:28:07 -07:00
tkchiaandtkchia df08b541af Bare metal VGA: implement "status report" escape codes (#613)
* Bare metal VGA: implement "status report" escape codes
* Minor fix to pseudoteletypewriter code

Co-authored-by: tkchia <[email protected]>
2022-09-13 02:14:10 -07:00
tkchiaandtkchia e0fabd1d49 [WIP] Get bare metal working outside of an emulator (#609)
You can now run bare metal on bare metal!

* Fix handling of int 0x15 eax = 0xe820 memory map
* Fix some issues in initial page table creation
* hello4.com now works outside emulators
* Ensure area for identity page tables are zeroed first
* Simplify logic for creating page table entries, this partly
  reverts 577c0f6226
* Add degenerate MBR partition entry, to ease testing

Co-authored-by: tkchia <[email protected]>
2022-09-13 02:01:49 -07:00
Justine Tunney 9cf2bdc9a8 Rebuild compile.com
This updates the bootstrap binary for the build compile command wrapper,
which was recently updated by #602.
2022-09-13 01:50:20 -07:00
Connor ed5b763a0c Refine V=0 command logging (#602)
This fixes off-by-one bugs, as well as missing carriage returns
caused by command truncation. When the terminal's width is 0 or
unknown, line feeds are used instead. Otherwise, the command is
padded with spaces to clear the line when the terminal is dumb.
2022-09-13 01:48:28 -07:00
Justine Tunney 22b63d0b98 Add *NSYNC to libc/isystem 2022-09-13 01:47:12 -07:00
Justine Tunney 6f7d0cb1c3 Pay off more technical debt
This makes breaking changes to add underscores to many non-standard
function names provided by the c library. MODE=tiny is now tinier and
we now use smaller locks that are better for tiny apps in this mode.
Some headers have been renamed to be in the same folder as the build
package, so it'll be easier to know which build dependency is needed.
Certain old misguided interfaces have been removed. Intel intrinsics
headers are now listed in libc/isystem (but not in the amalgamation)
to help further improve open source compatibility. Header complexity
has also been reduced. Lastly, more shell scripts are now available.
2022-09-12 23:36:56 -07:00
Justine Tunney b69f3d2488 Optimize memory layout 2022-09-12 04:26:52 -07:00
2173 changed files with 20021 additions and 16114 deletions

No files matched your search

+93 -82
View File
@@ -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))) \
+17 -16
View File
@@ -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
+49 -31
View File
@@ -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
View File
@@ -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");
+2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+1
View File
@@ -148,6 +148,7 @@ DEFAULT_CCFLAGS = \
DEFAULT_OFLAGS = \
-g \
-gdwarf-4 \
-gdescribe-dies
DEFAULT_COPTS = \
+8 -8
View File
@@ -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) $<
+4 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 */
+56
View File
@@ -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
View File
@@ -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
View File
@@ -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 {
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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.
+1 -1
View File
@@ -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"
+1 -1
View File
@@ -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"
/**
+1
View File
@@ -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
View File
@@ -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"
+5 -8
View File
@@ -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");
}
+3 -2
View File
@@ -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"
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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;
-160
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
+1
View File
@@ -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
View File
@@ -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"
+521
View File
@@ -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);
}
+100
View File
@@ -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
View File
@@ -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.
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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"
+60
View File
@@ -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);
}
}
}
+617
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
+1 -5
View File
@@ -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;
}
+2 -5
View File
@@ -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;
}
+2
View File
@@ -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;
}
+2
View File
@@ -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;
}
+2
View File
@@ -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
View File
@@ -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);
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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"
/**
+1 -1
View File
@@ -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"
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+1 -1
View File
@@ -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"
+115
View File
@@ -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;
}
+2 -2
View File
@@ -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);
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
}
+1 -2
View File
@@ -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
View File
@@ -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);
+4 -4
View File
@@ -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;
+6
View File
@@ -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
View File
@@ -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
View File
@@ -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));
}
+4 -3
View File
@@ -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
View File
@@ -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"
+4 -3
View File
@@ -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
View File
@@ -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) {
+7 -1
View File
@@ -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
View File
@@ -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 {
+1 -1
View File
@@ -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"
+5 -5
View File
@@ -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;
+5 -5
View File
@@ -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
View File
@@ -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
View File
@@ -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"
+4 -4
View File
@@ -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");
+1 -1
View File
@@ -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
View File
@@ -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);
+1 -1
View File
@@ -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,
+4 -4
View File
@@ -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