mirror of
https://github.com/jart/cosmopolitan.git
synced 2026-11-08 01:58:20 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
52f1db7220 | ||
|
|
c995838e5c | ||
|
|
539bddce8c | ||
|
|
002df0f16c | ||
|
|
be16bcdcd3 | ||
|
|
cb9a0466f1 | ||
|
|
543c93f623 | ||
|
|
3f0bcdc3ef | ||
|
|
0d7c265392 | ||
|
|
022536cab6 | ||
|
|
2278327eba | ||
|
|
37d40e087f | ||
|
|
179e048bba | ||
|
|
c2590cf7a0 | ||
|
|
89d1e5b8f2 | ||
|
|
5e60e5ad10 | ||
|
|
6b06a8176d | ||
|
|
14d036b68d | ||
|
|
fae0c0286f | ||
|
|
d6ff4c754e | ||
|
|
f44d88707e | ||
|
|
fc96af058b | ||
|
|
bd6069deb5 | ||
|
|
e9735a7738 | ||
|
|
0ea10c8631 | ||
|
|
e522aa3a07 | ||
|
|
d7b88734cd | ||
|
|
da8f5009fd | ||
|
|
ef9776755e | ||
|
|
da336b3ea8 | ||
|
|
69bee64a59 | ||
|
|
f7ff77d865 | ||
|
|
648bf6555c | ||
|
|
60cb435cb4 | ||
|
|
64c284003d | ||
|
|
3d2d04b25e | ||
|
|
5af19b7eed | ||
|
|
8111462789 | ||
|
|
f52f65b2e3 | ||
|
|
997ce29ddc | ||
|
|
d38700687a | ||
|
|
0f89140882 | ||
|
|
0cee831da3 | ||
|
|
b41f91c658 | ||
|
|
e7329b7cba | ||
|
|
c19ac8729d | ||
|
|
9d2f993364 | ||
|
|
31dab8a75d | ||
|
|
7a06760e6f | ||
|
|
9209ea63a7 | ||
|
|
84b9b8ed87 | ||
|
|
e557058ac8 | ||
|
|
467a332e38 | ||
|
|
7ae556463a | ||
|
|
c424352a0a | ||
|
|
d5910e2673 | ||
|
|
9b7c8db846 | ||
|
|
4a6fd3d910 | ||
|
|
38df0a4186 | ||
|
|
1c0adb556d | ||
|
|
8aca94f951 | ||
|
|
38e3ab57a6 | ||
|
|
672ccda37c | ||
|
|
9849b4c7ba | ||
|
|
3421b9a580 | ||
|
|
29d695f4c9 | ||
|
|
7d6835c0dd | ||
|
|
05197afca2 | ||
|
|
bc353f454b | ||
|
|
7bc24888fe | ||
|
|
59ac141e49 | ||
|
|
60b68d7152 | ||
|
|
a5b483f2d4 | ||
|
|
d3efa47f81 | ||
|
|
7822917fc2 | ||
|
|
81ee11a16e | ||
|
|
f155205eb0 | ||
|
|
e46ef487a8 | ||
|
|
afc07b9339 | ||
|
|
edb8fef06c | ||
|
|
b75a4654cf | ||
|
|
fe3216e961 | ||
|
|
174d288e66 | ||
|
|
9f9b240f3d | ||
|
|
726f04e8aa | ||
|
|
556697cbd8 | ||
|
|
3ee3736a01 | ||
|
|
01bd7d1008 | ||
|
|
32321ab1e9 | ||
|
|
3b4fcd8575 | ||
|
|
6ba3b448f3 | ||
|
|
91e167caaf | ||
|
|
ccbae7799e | ||
|
|
af24c19db3 | ||
|
|
950a1b310b | ||
|
|
daca5499b9 | ||
|
|
2526a9b8c7 | ||
|
|
7549a5755e | ||
|
|
795d295590 | ||
|
|
3f3cb0650b | ||
|
|
acd8900071 | ||
|
|
6c60793f3a | ||
|
|
ad97775370 | ||
|
|
0b5f84dd20 | ||
|
|
27b5deefb1 | ||
|
|
ecb2ef7c39 | ||
|
|
304cf8869c | ||
|
|
3e0ddf70e9 | ||
|
|
5005f2e446 | ||
|
|
bc8532688b | ||
|
|
09811e739f | ||
|
|
24988f2351 | ||
|
|
b46f763ee7 | ||
|
|
87708c5d6e |
No files matched your search
@@ -21,8 +21,11 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: support ape bins
|
||||
run: sudo sh -c "echo ':APE:M::MZqFpD::/bin/sh:' >/proc/sys/fs/binfmt_misc/register"
|
||||
- name: support ape bins 1
|
||||
run: sudo cp build/bootstrap/ape.elf /usr/bin/ape
|
||||
|
||||
- name: support ape bins 2
|
||||
run: sudo sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register"
|
||||
|
||||
- name: make matrix
|
||||
run: V=0 make -j2 MODE=${{ matrix.mode }}
|
||||
@@ -60,8 +60,8 @@
|
||||
# build/config.mk
|
||||
|
||||
SHELL = build/bootstrap/cocmd.com
|
||||
HOSTS ?= freebsd openbsd netbsd rhel7 rhel5 win10 xnu
|
||||
MAKEFLAGS += -j --no-builtin-rules
|
||||
HOSTS ?= freebsd openbsd netbsd rhel7 rhel5 xnu win10 win10:31336
|
||||
MAKEFLAGS += --no-builtin-rules
|
||||
|
||||
.SUFFIXES:
|
||||
.DELETE_ON_ERROR:
|
||||
@@ -92,6 +92,7 @@ o/$(MODE): \
|
||||
.UNVEIL = \
|
||||
libc/integral \
|
||||
libc/disclaimer.inc \
|
||||
rwc:/dev/shm \
|
||||
rx:build/bootstrap \
|
||||
rx:o/third_party/gcc \
|
||||
/proc/stat \
|
||||
@@ -121,11 +122,13 @@ include third_party/compiler_rt/compiler_rt.mk # │
|
||||
include libc/str/str.mk # │
|
||||
include third_party/xed/xed.mk # │
|
||||
include third_party/zlib/zlib.mk # │
|
||||
include third_party/double-conversion/dc.mk # │
|
||||
include libc/elf/elf.mk # │
|
||||
include ape/ape.mk # │
|
||||
include libc/fmt/fmt.mk # │
|
||||
include libc/vga/vga.mk #─┘
|
||||
include libc/calls/calls.mk #─┐
|
||||
include third_party/getopt/getopt.mk # │
|
||||
include libc/runtime/runtime.mk # ├──SYSTEMS RUNTIME
|
||||
include libc/crt/crt.mk # │ You can issue system calls
|
||||
include third_party/nsync/nsync.mk # │
|
||||
@@ -149,7 +152,6 @@ include dsp/mpeg/mpeg.mk # │
|
||||
include dsp/dsp.mk # │
|
||||
include third_party/zlib/gz/gz.mk # │
|
||||
include third_party/musl/musl.mk # │
|
||||
include third_party/getopt/getopt.mk # │
|
||||
include libc/libc.mk #─┘
|
||||
include libc/sock/sock.mk #─┐
|
||||
include dsp/tty/tty.mk # ├──ONLINE RUNTIME
|
||||
@@ -160,6 +162,7 @@ include net/https/https.mk # │
|
||||
include third_party/regex/regex.mk #─┘
|
||||
include third_party/tidy/tidy.mk
|
||||
include third_party/third_party.mk
|
||||
include third_party/nsync/testing/testing.mk
|
||||
include libc/testlib/testlib.mk
|
||||
include tool/viz/lib/vizlib.mk
|
||||
include tool/args/args.mk
|
||||
@@ -167,8 +170,9 @@ include test/tool/args/test.mk
|
||||
include third_party/linenoise/linenoise.mk
|
||||
include third_party/maxmind/maxmind.mk
|
||||
include net/finger/finger.mk
|
||||
include third_party/double-conversion/double-conversion.mk
|
||||
include third_party/double-conversion/test/test.mk
|
||||
include third_party/lua/lua.mk
|
||||
include third_party/tr/tr.mk
|
||||
include third_party/sed/sed.mk
|
||||
include third_party/awk/awk.mk
|
||||
include third_party/make/make.mk
|
||||
@@ -202,6 +206,7 @@ include tool/hash/hash.mk
|
||||
include tool/net/net.mk
|
||||
include tool/viz/viz.mk
|
||||
include tool/tool.mk
|
||||
include net/turfwar/turfwar.mk
|
||||
include test/libc/tinymath/test.mk
|
||||
include test/libc/intrin/test.mk
|
||||
include test/libc/mem/test.mk
|
||||
@@ -307,7 +312,7 @@ COSMOPOLITAN_OBJECTS = \
|
||||
THIRD_PARTY_GDTOA \
|
||||
THIRD_PARTY_REGEX \
|
||||
LIBC_THREAD \
|
||||
THIRD_PARTY_NSYNC_MALLOC \
|
||||
THIRD_PARTY_NSYNC_MEM \
|
||||
LIBC_MEM \
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
LIBC_RUNTIME \
|
||||
@@ -400,6 +405,15 @@ $(SRCS): \
|
||||
libc/integral/lp64arg.inc \
|
||||
libc/integral/lp64.inc
|
||||
|
||||
.PHONY: toolchain
|
||||
toolchain: o/cosmopolitan.h \
|
||||
o/$(MODE)/ape/public/ape.lds \
|
||||
o/$(MODE)/libc/crt/crt.o \
|
||||
o/$(MODE)/ape/ape.o \
|
||||
o/$(MODE)/ape/ape-copy-self.o \
|
||||
o/$(MODE)/ape/ape-no-modify-self.o \
|
||||
o/$(MODE)/cosmopolitan.a
|
||||
|
||||
# UNSPECIFIED PREREQUISITES TUTORIAL
|
||||
#
|
||||
# A build rule must exist for all files that make needs to consider in
|
||||
|
||||
@@ -23,8 +23,8 @@ 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.1.zip
|
||||
unzip cosmopolitan-amalgamation-2.1.zip
|
||||
wget https://justine.lol/cosmopolitan/cosmopolitan-amalgamation-2.2.zip
|
||||
unzip cosmopolitan-amalgamation-2.2.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 -gdwarf-4 \
|
||||
@@ -246,20 +246,26 @@ gdb foo.com -ex 'add-symbol-file foo.com.dbg 0x401000'
|
||||
| AMD | K8 Venus | 2005 |
|
||||
| Intel | Core | 2006 |
|
||||
| Linux | 2.6.18 | 2007 |
|
||||
| Windows | 8 | 2012 |
|
||||
| Windows | 8 [1] | 2012 |
|
||||
| Mac OS X | 15.6 | 2018 |
|
||||
| OpenBSD | 6.4 | 2018 |
|
||||
| FreeBSD | 13 | 2020 |
|
||||
| NetBSD | 9.2 | 2021 |
|
||||
|
||||
[1] See our [vista branch](https://github.com/jart/cosmopolitan/tree/vista)
|
||||
for a community supported version of Cosmopolitan that works on Windows
|
||||
Vista and Windows 7.
|
||||
|
||||
## Special Thanks
|
||||
|
||||
Funding for this project is crowdsourced using
|
||||
[GitHub Sponsors](https://github.com/sponsors/jart) and
|
||||
[Patreon](https://www.patreon.com/jart). Your support is what makes this
|
||||
project possible. Thank you! We'd also like to give special thanks to
|
||||
the following individuals:
|
||||
the following groups and individuals:
|
||||
|
||||
- [Joe Drumgoole](https://github.com/jdrumgoole)
|
||||
- [Rob Figueiredo](https://github.com/robfig)
|
||||
- [Wasmer](https://wasmer.io/)
|
||||
|
||||
For publicly sponsoring our work at the highest tier.
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "ape/macros.internal.h"
|
||||
#include "ape/notice.inc"
|
||||
#include "ape/relocations.h"
|
||||
#include "libc/calls/metalfile.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/elf/def.h"
|
||||
#include "libc/macho.internal.h"
|
||||
@@ -112,7 +113,15 @@ cstr: .endobj cstr,globl,hidden # ←for gdb readability
|
||||
//
|
||||
// @param dl is drive number
|
||||
// @noreturn
|
||||
ape_mz: .asciz "MZqFpD='\n" # Mark 'Zibo' Joseph Zbikowski
|
||||
ape_mz:
|
||||
#if SupportsWindows() || SupportsMetal()
|
||||
.asciz "MZqFpD='\n" # Mark 'Zibo' Joseph Zbikowski
|
||||
#else
|
||||
// Avoid virus scanner reputation damage when targeting System Five.
|
||||
// WARNING: This prefix is experimental; it may be removed sometime.
|
||||
// TODO(jart): Find another prefix that will work with BIOS loading.
|
||||
.asciz "JTqFpD='\n" # Mark 'Zibo' Joseph Zbikowski
|
||||
#endif
|
||||
.short 0x1000 # MZ: lowers upper bound load / 16
|
||||
.short 0xf800 # MZ: roll greed on bss
|
||||
.short 0 # MZ: lower bound on stack segment
|
||||
@@ -125,6 +134,7 @@ ape_mz: .asciz "MZqFpD='\n" # Mark 'Zibo' Joseph Zbikowski
|
||||
.org 0x24 # MZ: bytes reserved for you
|
||||
.ascii "JT" # MZ: OEM identifier
|
||||
.short 0 # MZ: OEM information
|
||||
.ascii "' <<'@'\n"
|
||||
.org 0x40-4 # MZ: bytes reserved for you
|
||||
#if SupportsWindows() || SupportsMetal()
|
||||
.long RVA(ape_pe) # PE: the new technology
|
||||
@@ -250,7 +260,6 @@ pc: cld
|
||||
xor %cx,%cx # current cylinder
|
||||
xor %dh,%dh # current head
|
||||
mov $v_ape_realsectors,%di # total sectors
|
||||
sub $v_ape_realslacksectors,%di
|
||||
3: call pcread
|
||||
dec %di
|
||||
jnz 3b
|
||||
@@ -549,7 +558,7 @@ ape_disk:
|
||||
the bourne executable & linkable format */
|
||||
|
||||
#if SupportsWindows() || SupportsMetal() || SupportsXnu()
|
||||
apesh: .ascii "'\n#'\"\n" # sixth edition shebang
|
||||
apesh: .ascii "\n@\n#'\"\n" # sixth edition shebang
|
||||
// Until all operating systems can be updated to support APE,
|
||||
// we have a beautiful, yet imperfect workaround, which is to
|
||||
// modify the binary to follow the local system's convention.
|
||||
@@ -874,7 +883,7 @@ ape_macho:
|
||||
.long (520f-510f)/4 # count
|
||||
510: .quad 0 # rax
|
||||
.quad IMAGE_BASE_VIRTUAL # rbx
|
||||
.quad XNU # rcx
|
||||
.quad _HOSTXNU # rcx
|
||||
.quad 0 # rdx
|
||||
.quad 0 # rdi
|
||||
.quad 0 # rsi
|
||||
@@ -1137,12 +1146,17 @@ sconf: .short 1843200/*hz*/ / 16/*wut*/ / 9600/*baud*/
|
||||
.endobj sconf,global,hidden
|
||||
|
||||
// Global Descriptor Table
|
||||
//
|
||||
// @note address portion only concern legacy modes
|
||||
.align 8
|
||||
gdt: .short 2f-1f # table byte length
|
||||
.long REAL(1f),0 # table address
|
||||
.zero 2
|
||||
_gdtrphy:
|
||||
.short 2f-1f-1 # table byte length
|
||||
.long REAL(1f) # table address (physical space)
|
||||
.endobj _gdtrphy,global,hidden
|
||||
_gdtr:
|
||||
.short 2f-1f-1 # table byte length
|
||||
.quad 1f # table address (final virtual space)
|
||||
.endobj _gdtr,global,hidden
|
||||
.align 8
|
||||
_gdt:
|
||||
1:
|
||||
// ┌G:granularity (1 → limit *= 0x1000)
|
||||
// │┌D/B:default operation size (0 = 16|64bit, 1 = 32-bit)
|
||||
@@ -1172,7 +1186,9 @@ gdt: .short 2f-1f # table byte length
|
||||
.quad 0b0000000011001111100100100000000000000000000000001111111111111111 #32
|
||||
.quad 0b0000000010101111100110110000000000000000000000001111111111111111 #40
|
||||
.quad 0b0000000010101111100100110000000000000000000000001111111111111111 #48
|
||||
2: .endobj gdt,global,hidden
|
||||
.tssdescstub _tss #56,64
|
||||
2:
|
||||
.endobj _gdt,global,hidden
|
||||
|
||||
/*─────────────────────────────────────────────────────────────────────────────╗
|
||||
│ αcτµαlly pδrταblε εxεcµταblε § real mode │
|
||||
@@ -1278,8 +1294,8 @@ lcheck: pushf # check for i8086 / i8088 / i80186
|
||||
jl 10f
|
||||
mov %edi,%eax
|
||||
cpuid
|
||||
mov $1<<29,%edi # need nexgen32e long mode support
|
||||
and %edi,%edx
|
||||
mov $1<<29|1<<20,%edi # need nexgen32e long mode support
|
||||
and %edi,%edx # & nx support
|
||||
cmp %edi,%edx
|
||||
jne 10f
|
||||
xor %ax,%ax
|
||||
@@ -1408,7 +1424,7 @@ pinit: push %ds
|
||||
movl $0x79000+PAGE_V+PAGE_RW,0x7b000-SEG # PD←PDT (+)
|
||||
movl $0x79000+PAGE_V+PAGE_RW,0x7a000-SEG # PD←PDT (-)
|
||||
mov $512,%cx # PD±2MB
|
||||
mov $PAGE_V+PAGE_RW,%eax
|
||||
mov $PAGE_V+PAGE_RSRV+PAGE_RW,%eax
|
||||
xor %di,%di
|
||||
0: stosl
|
||||
add $0x1000,%eax
|
||||
@@ -1431,9 +1447,9 @@ golong: cli
|
||||
mov %eax,%cr4
|
||||
movl $EFER,%ecx
|
||||
rdmsr
|
||||
or $EFER_LME|EFER_SCE,%eax
|
||||
or $EFER_LME|EFER_SCE|EFER_NXE,%eax
|
||||
wrmsr
|
||||
lgdt REAL(gdt)
|
||||
lgdt REAL(_gdtrphy)
|
||||
mov %cr0,%eax
|
||||
or $CR0_PE|CR0_PG|CR0_MP,%eax
|
||||
and $~CR0_EM,%eax
|
||||
@@ -1451,6 +1467,8 @@ long: xor %eax,%eax
|
||||
mov %eax,%fs
|
||||
mov %eax,%gs
|
||||
mov $0x80000,%esp
|
||||
mov $GDT_LONG_TSS,%al
|
||||
ltr %ax
|
||||
xor %r12d,%r12d
|
||||
xor %r13d,%r13d
|
||||
xor %r14d,%r14d
|
||||
@@ -1464,6 +1482,8 @@ long: xor %eax,%eax
|
||||
call __map_phdrs
|
||||
push $0x037f
|
||||
fldcw (%rsp)
|
||||
lgdt _gdtr # reload GDTR for
|
||||
# virtual memory space
|
||||
movabs $kernel,%rax
|
||||
jmp *%rax
|
||||
.endfn long
|
||||
@@ -1544,21 +1564,21 @@ kernel: movabs $ape_stack_vaddr,%rsp
|
||||
.byte 0x0f,0x1f,0207 # nop rdi binbase
|
||||
.long (IMAGE_BASE_VIRTUAL-IMAGE_BASE_REAL)/512
|
||||
#endif
|
||||
push $METAL # sets __hostos in crt.S
|
||||
push $_HOSTMETAL # sets __hostos in crt.S
|
||||
pop %rcx
|
||||
push $0
|
||||
pushq .Lenv0(%rip) # envp[0][0]
|
||||
mov %rsp,%rbp
|
||||
mov .Lenv0(%rip),%rax
|
||||
mov %rax,(%rbp) # envp[0][0]
|
||||
push $0 # argv[0][0]
|
||||
pushq .Largv0+8(%rip) # argv[0][8]
|
||||
pushq .Largv0(%rip) # argv[0][0]
|
||||
mov %rsp,%rax
|
||||
push $0 # auxv[1][1]
|
||||
push $0 # auxv[1][0]
|
||||
push %rbp # auxv[0][1]
|
||||
push %rax # auxv[0][1]
|
||||
push $31 # auxv[0][0] AT_EXECFN
|
||||
push $0 # envp[1]
|
||||
push $.Lenv0 # envp[0]
|
||||
push %rbp # envp[0]
|
||||
push $0 # argv[1]
|
||||
push %rbp # argv[0]
|
||||
push %rax # argv[0]
|
||||
push $1 # argc
|
||||
xor %ebp,%ebp
|
||||
xor %eax,%eax
|
||||
@@ -1574,6 +1594,9 @@ kernel: movabs $ape_stack_vaddr,%rsp
|
||||
|
||||
.rodata
|
||||
.Lenv0: .asciz "METAL=1"
|
||||
.Largv0:
|
||||
.asciz APE_COM_NAME
|
||||
.org .Largv0+16
|
||||
.previous
|
||||
|
||||
#endif /* SupportsMetal() */
|
||||
@@ -1586,7 +1609,6 @@ kernel: movabs $ape_stack_vaddr,%rsp
|
||||
.ldsvar _end
|
||||
.ldsvar _etext
|
||||
.ldsvar v_ape_realsectors
|
||||
.ldsvar v_ape_realslacksectors
|
||||
.ldsvar v_ape_highsectors
|
||||
.ldsvar ape_idata_ro
|
||||
.ldsvar ape_pad_rodata
|
||||
|
||||
+4
-6
@@ -427,7 +427,7 @@ SECTIONS {
|
||||
|
||||
KEEP(*(.bssepilogue))
|
||||
/*END: NT FORK COPYING */
|
||||
. = ALIGN(FRAMESIZE); /* for brk()/sbrk() allocation */
|
||||
. = ALIGN(PAGESIZE);
|
||||
HIDDEN(_end = .);
|
||||
PROVIDE_HIDDEN(end = .);
|
||||
} :Bss
|
||||
@@ -565,13 +565,11 @@ SHSTUB2(ape_loader_dd_count,
|
||||
#if SupportsMetal()
|
||||
HIDDEN(v_ape_realsectors =
|
||||
MIN(0x70000 - IMAGE_BASE_REAL,
|
||||
ROUNDUP(RVA(_edata), 4096)) / 512);
|
||||
HIDDEN(v_ape_realslacksectors =
|
||||
v_ape_realsectors - MIN(0x70000 - IMAGE_BASE_REAL,
|
||||
ROUNDUP(RVA(_edata), 512)) / 512);
|
||||
ROUNDUP(RVA(_tdata_end), 512)) / 512);
|
||||
HIDDEN(v_ape_realpages = v_ape_realsectors / (4096 / 512));
|
||||
HIDDEN(v_ape_highsectors =
|
||||
(ROUNDUP(RVA(_edata), 512) / 512) - v_ape_realsectors);
|
||||
(ROUNDUP(RVA(_tdata_end), 512) / 512) - v_ape_realsectors);
|
||||
TSSDESCSTUB2(_tss, _tss, _tss_end ? _tss_end - _tss - 1 : 0);
|
||||
#endif
|
||||
|
||||
/* ZIP End of Central Directory header */
|
||||
|
||||
@@ -107,6 +107,7 @@ o/$(MODE)/ape/ape-no-modify-self.o: \
|
||||
libc/macho.internal.h \
|
||||
libc/macros.internal.h \
|
||||
libc/nexgen32e/uart.internal.h \
|
||||
libc/calls/metalfile.internal.h \
|
||||
libc/nexgen32e/vidya.internal.h \
|
||||
libc/nt/pedef.internal.h \
|
||||
libc/runtime/e820.internal.h \
|
||||
@@ -133,6 +134,7 @@ o/$(MODE)/ape/ape-copy-self.o: \
|
||||
libc/macho.internal.h \
|
||||
libc/macros.internal.h \
|
||||
libc/nexgen32e/uart.internal.h \
|
||||
libc/calls/metalfile.internal.h \
|
||||
libc/nexgen32e/vidya.internal.h \
|
||||
libc/nt/pedef.internal.h \
|
||||
libc/runtime/e820.internal.h \
|
||||
|
||||
+3
-1
@@ -1,6 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ $UID -eq 0 ]; then
|
||||
if [ "$(id -u)" -eq 0 ]; then
|
||||
SUDO=
|
||||
else
|
||||
SUDO=sudo
|
||||
@@ -97,6 +97,8 @@ if [ x"$(uname -s)" = xLinux ]; then
|
||||
echo you may need to edit configs to persist across reboot >&2
|
||||
echo '$SUDO sh -c "echo '"'"':APE:M::MZqFpD::/usr/bin/ape:'"'"' >/proc/sys/fs/binfmt_misc/register"' >&2
|
||||
$SUDO sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" || exit
|
||||
echo '$SUDO sh -c "echo '"'"':APE-sysv:M::JTqFpD::/usr/bin/ape:'"'"' >/proc/sys/fs/binfmt_misc/register"' >&2
|
||||
$SUDO sh -c "echo ':APE-sysv:M::JTqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" || exit
|
||||
echo done >&2
|
||||
|
||||
if [ x"$(cat /proc/sys/fs/binfmt_misc/status)" = xdisabled ]; then
|
||||
|
||||
@@ -11,6 +11,7 @@ fi
|
||||
echo "APE Uninstaller intends to run"
|
||||
echo
|
||||
echo " $SUDO sh -c 'echo -1 >/proc/sys/fs/binfmt_misc/APE'"
|
||||
echo " $SUDO sh -c 'echo -1 >/proc/sys/fs/binfmt_misc/APE-sysv'"
|
||||
echo " $SUDO rm -f /usr/bin/ape ~/.ape o/tmp/.ape /tmp/.ape"
|
||||
echo
|
||||
echo "You may then use ape/apeinstall.sh to reinstall it"
|
||||
@@ -21,4 +22,7 @@ set -ex
|
||||
if [ -f /proc/sys/fs/binfmt_misc/APE ]; then
|
||||
$SUDO sh -c 'echo -1 >/proc/sys/fs/binfmt_misc/APE' || exit
|
||||
fi
|
||||
if [ -f /proc/sys/fs/binfmt_misc/APE-sysv ]; then
|
||||
$SUDO sh -c 'echo -1 >/proc/sys/fs/binfmt_misc/APE-sysv' || exit
|
||||
fi
|
||||
$SUDO rm -f /usr/bin/ape ~/.ape o/tmp/.ape o/tmp/ape /tmp/.ape /tmp/ape || exit
|
||||
+2
-2
@@ -175,7 +175,7 @@ macho: .long 0xFEEDFACE+1
|
||||
510: .quad 0 # rax
|
||||
.quad 0 # rbx
|
||||
.quad 0 # rcx
|
||||
.quad XNU # rdx
|
||||
.quad _HOSTXNU # rdx
|
||||
.quad 0 # rdi
|
||||
.quad 0 # rsi
|
||||
.quad 0 # rbp
|
||||
@@ -221,7 +221,7 @@ _start:
|
||||
jne 0f
|
||||
cmp $+1,%edx
|
||||
jne 0f
|
||||
mov $XNU,%dl
|
||||
mov $_HOSTXNU,%dl
|
||||
xor %ecx,%ecx
|
||||
|
||||
0: mov %rsp,%rsi
|
||||
|
||||
+2
-2
@@ -90,7 +90,7 @@ macho: .long 0xFEEDFACE+1
|
||||
510: .quad 0 # rax
|
||||
.quad 0 # rbx
|
||||
.quad 0 # rcx
|
||||
.quad XNU # rdx
|
||||
.quad _HOSTXNU # rdx
|
||||
.quad 0 # rdi
|
||||
.quad 0 # rsi
|
||||
.quad 0 # rbp
|
||||
@@ -121,7 +121,7 @@ _start:
|
||||
jne 0f
|
||||
cmp $+1,%edx
|
||||
jne 0f
|
||||
mov $XNU,%dl
|
||||
mov $_HOSTXNU,%dl
|
||||
xor %ecx,%ecx
|
||||
|
||||
0: mov %rsp,%rsi
|
||||
|
||||
@@ -180,6 +180,20 @@
|
||||
.stub \name\()_bcs\n,long
|
||||
.endm
|
||||
|
||||
// Task State Segment Descriptor Entries.
|
||||
.macro .tssdescstub name:req
|
||||
.ifndef \name
|
||||
.weak \name
|
||||
.set \name,0
|
||||
.endif
|
||||
.ifndef \name\()_end
|
||||
.weak \name\()_end
|
||||
.set \name\()_end,0
|
||||
.endif
|
||||
.stub \name\()_desc_ent0,quad
|
||||
.stub \name\()_desc_ent1,quad
|
||||
.endm
|
||||
|
||||
/* clang-format on */
|
||||
#elif defined(__LINKER__)
|
||||
|
||||
@@ -257,5 +271,22 @@
|
||||
(X) % 10 * 0x1000000 \
|
||||
: 0xffffffffffffffff)
|
||||
|
||||
/**
|
||||
* Laying out the GDT entries for a TSS for bare metal operation.
|
||||
*/
|
||||
#define TSSDESCSTUB2(SYM, BASE, LIM) \
|
||||
HIDDEN(SYM##_desc_ent0 = TSSDESC_ENT0(BASE, LIM)); \
|
||||
HIDDEN(SYM##_desc_ent1 = TSSDESC_ENT1(BASE)); \
|
||||
ASSERT((LIM) >= 0 && (LIM) <= 0xffff, "bare metal TSS is suspiciously fat")
|
||||
#define TSSDESC_ENT0(BASE, LIM) \
|
||||
(((LIM) << 0 & 0x000000000000ffff) | \
|
||||
((BASE) << 16 & 0x000000ffffff0000) | \
|
||||
0x89 << 40 | \
|
||||
((LIM) >> 16 << 48 & 0x000f000000000000) | \
|
||||
0x2 << 52 | \
|
||||
((BASE) >> 24 << 56 & 0xff00000000000000))
|
||||
#define TSSDESC_ENT1(BASE) \
|
||||
((BASE) >> 32 << 0 & 0x00000000ffffffff)
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
#endif /* APE_MACROS_H_ */
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef COSMOPOLITAN_APE_SECTIONS_INTERNAL_H_
|
||||
#define COSMOPOLITAN_APE_SECTIONS_INTERNAL_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern unsigned char _base[];
|
||||
extern unsigned char _ehead[];
|
||||
extern unsigned char _etext[];
|
||||
extern unsigned char _edata[];
|
||||
extern unsigned char _ezip[];
|
||||
extern unsigned char _end[];
|
||||
extern unsigned char _ereal[];
|
||||
extern unsigned char _tdata_start[];
|
||||
extern unsigned char _tdata_end[];
|
||||
extern unsigned char _tbss_start[];
|
||||
extern unsigned char _tbss_end[];
|
||||
extern unsigned char __privileged_start[];
|
||||
extern unsigned char __privileged_addr[];
|
||||
extern unsigned char __privileged_size[];
|
||||
extern unsigned char __privileged_end[];
|
||||
extern unsigned char __test_start[];
|
||||
extern unsigned char __ro[];
|
||||
extern unsigned char *__relo_start[];
|
||||
extern unsigned char *__relo_end[];
|
||||
extern uint8_t __zip_start[];
|
||||
extern uint8_t __zip_end[];
|
||||
extern uint8_t __data_start[];
|
||||
extern uint8_t __data_end[];
|
||||
extern uint8_t __bss_start[];
|
||||
extern uint8_t __bss_end[];
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_APE_SECTIONS_INTERNAL_H_ */
|
||||
Binary file not shown.
Binary file not shown.
+27
-6
@@ -29,7 +29,7 @@ endif
|
||||
#
|
||||
ifeq ($(MODE),fastbuild)
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) $(FTRACE) -O
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG -DDWARFLESS
|
||||
CONFIG_OFLAGS += -g0
|
||||
CONFIG_LDFLAGS += -S
|
||||
TARGET_ARCH ?= -msse3
|
||||
@@ -125,6 +125,22 @@ TARGET_ARCH ?= -msse3
|
||||
OVERRIDE_CCFLAGS += -fno-pie
|
||||
endif
|
||||
|
||||
# System Five Mode
|
||||
#
|
||||
# - `make MODE=sysv`
|
||||
# - Optimized
|
||||
# - Backtraces
|
||||
# - Debuggable
|
||||
# - Syscall tracing
|
||||
# - Function tracing
|
||||
# - No Windows bloat!
|
||||
#
|
||||
ifeq ($(MODE), sysv)
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) $(FTRACE) -O2
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG -DSUPPORT_VECTOR=121
|
||||
TARGET_ARCH ?= -msse3
|
||||
endif
|
||||
|
||||
# Tiny Mode
|
||||
#
|
||||
# - `make MODE=tiny`
|
||||
@@ -151,7 +167,8 @@ CONFIG_CCFLAGS += \
|
||||
-fschedule-insns2 \
|
||||
-fomit-frame-pointer \
|
||||
-momit-leaf-frame-pointer \
|
||||
-foptimize-sibling-calls
|
||||
-foptimize-sibling-calls \
|
||||
-DDWARFLESS
|
||||
CONFIG_OFLAGS += \
|
||||
-g0
|
||||
CONFIG_LDFLAGS += \
|
||||
@@ -181,7 +198,8 @@ CONFIG_CPPFLAGS += \
|
||||
-DTINY \
|
||||
-DNDEBUG \
|
||||
-DTRUSTWORTHY \
|
||||
-DSUPPORT_VECTOR=1
|
||||
-DSUPPORT_VECTOR=1 \
|
||||
-DDWARFLESS
|
||||
DEFAULT_COPTS += \
|
||||
-mred-zone
|
||||
CONFIG_OFLAGS += \
|
||||
@@ -217,7 +235,8 @@ CONFIG_CPPFLAGS += \
|
||||
-DTINY \
|
||||
-DNDEBUG \
|
||||
-DTRUSTWORTHY \
|
||||
-DSUPPORT_VECTOR=113
|
||||
-DSUPPORT_VECTOR=113 \
|
||||
-DDWARFLESS
|
||||
DEFAULT_COPTS += \
|
||||
-mred-zone
|
||||
CONFIG_OFLAGS += \
|
||||
@@ -252,7 +271,8 @@ CONFIG_CPPFLAGS += \
|
||||
-DTINY \
|
||||
-DNDEBUG \
|
||||
-DTRUSTWORTHY \
|
||||
-DSUPPORT_VECTOR=121
|
||||
-DSUPPORT_VECTOR=121 \
|
||||
-DDWARFLESS
|
||||
DEFAULT_COPTS += \
|
||||
-mred-zone
|
||||
CONFIG_CCFLAGS += \
|
||||
@@ -287,7 +307,8 @@ CONFIG_CPPFLAGS += \
|
||||
-DTINY \
|
||||
-DNDEBUG \
|
||||
-DTRUSTWORTHY \
|
||||
-DSUPPORT_VECTOR=251
|
||||
-DSUPPORT_VECTOR=251 \
|
||||
-DDWARFLESS
|
||||
CONFIG_CCFLAGS += \
|
||||
-Os \
|
||||
-fno-align-functions \
|
||||
|
||||
+15
-23
@@ -73,33 +73,25 @@ IMAGE_BASE_VIRTUAL ?= 0x400000
|
||||
IGNORE := $(shell $(ECHO) -2 ♥cosmo)
|
||||
IGNORE := $(shell $(MKDIR) o/tmp)
|
||||
|
||||
ifneq ("$(wildcard o/third_party/gcc/bin/x86_64-pc-linux-gnu-as.exe)","")
|
||||
AS = o/third_party/gcc/bin/x86_64-pc-linux-gnu-as.exe
|
||||
CC = o/third_party/gcc/bin/x86_64-pc-linux-gnu-gcc.exe
|
||||
CXX = o/third_party/gcc/bin/x86_64-pc-linux-gnu-g++.exe
|
||||
CXXFILT = o/third_party/gcc/bin/x86_64-pc-linux-gnu-c++filt.exe
|
||||
LD = o/third_party/gcc/bin/x86_64-pc-linux-gnu-ld.bfd.exe
|
||||
NM = o/third_party/gcc/bin/x86_64-pc-linux-gnu-nm.exe
|
||||
GCC = o/third_party/gcc/bin/x86_64-pc-linux-gnu-gcc.exe
|
||||
STRIP = o/third_party/gcc/bin/x86_64-pc-linux-gnu-strip.exe
|
||||
OBJCOPY = o/third_party/gcc/bin/x86_64-pc-linux-gnu-objcopy.exe
|
||||
OBJDUMP = o/third_party/gcc/bin/x86_64-pc-linux-gnu-objdump.exe
|
||||
ADDR2LINE = $(PWD)/o/third_party/gcc/bin/x86_64-pc-linux-gnu-addr2line.exe
|
||||
ifneq ("$(wildcard o/third_party/gcc/bin/x86_64-pc-linux-gnu-*)","")
|
||||
PREFIX = o/third_party/gcc/bin/x86_64-pc-linux-gnu-
|
||||
else
|
||||
IGNORE := $(shell build/bootstrap/unbundle.com)
|
||||
AS = o/third_party/gcc/bin/x86_64-linux-musl-as
|
||||
CC = o/third_party/gcc/bin/x86_64-linux-musl-gcc
|
||||
CXX = o/third_party/gcc/bin/x86_64-linux-musl-g++
|
||||
CXXFILT = o/third_party/gcc/bin/x86_64-linux-musl-c++filt
|
||||
LD = o/third_party/gcc/bin/x86_64-linux-musl-ld.bfd
|
||||
NM = o/third_party/gcc/bin/x86_64-linux-musl-nm
|
||||
GCC = o/third_party/gcc/bin/x86_64-linux-musl-gcc
|
||||
STRIP = o/third_party/gcc/bin/x86_64-linux-musl-strip
|
||||
OBJCOPY = o/third_party/gcc/bin/x86_64-linux-musl-objcopy
|
||||
OBJDUMP = o/third_party/gcc/bin/x86_64-linux-musl-objdump
|
||||
ADDR2LINE = $(PWD)/o/third_party/gcc/bin/x86_64-linux-musl-addr2line
|
||||
PREFIX = o/third_party/gcc/bin/x86_64-linux-musl-
|
||||
endif
|
||||
|
||||
AS = $(PREFIX)as
|
||||
CC = $(PREFIX)gcc
|
||||
CXX = $(PREFIX)g++
|
||||
CXXFILT = $(PREFIX)c++filt
|
||||
LD = $(PREFIX)ld.bfd
|
||||
NM = $(PREFIX)nm
|
||||
GCC = $(PREFIX)gcc
|
||||
STRIP = $(PREFIX)strip
|
||||
OBJCOPY = $(PREFIX)objcopy
|
||||
OBJDUMP = $(PREFIX)objdump
|
||||
ADDR2LINE = $(PWD)/$(PREFIX)addr2line
|
||||
|
||||
export ADDR2LINE
|
||||
export LC_ALL
|
||||
export MKDIR
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/kprintf.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"
|
||||
|
||||
/**
|
||||
@@ -59,9 +59,15 @@
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (!IsAsan()) {
|
||||
printf("this example is intended for MODE=asan or MODE=dbg\n");
|
||||
kprintf("this example is intended for MODE=asan or MODE=dbg\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
kprintf("----------------\n");
|
||||
kprintf(" THIS IS A TEST \n");
|
||||
kprintf("SIMULATING CRASH\n");
|
||||
kprintf("----------------\n");
|
||||
|
||||
char *buffer;
|
||||
ShowCrashReports(); /* not needed but yoinks appropriate symbols */
|
||||
buffer = malloc(13);
|
||||
|
||||
+7
-7
@@ -20,22 +20,22 @@ int main(int argc, char *argv[]) {
|
||||
volatile unsigned long x;
|
||||
struct timespec now, start, next, interval;
|
||||
printf("hammering the cpu...\n");
|
||||
next = start = _timespec_mono();
|
||||
interval = _timespec_frommillis(500);
|
||||
next = _timespec_add(next, interval);
|
||||
next = start = timespec_mono();
|
||||
interval = timespec_frommillis(500);
|
||||
next = timespec_add(next, interval);
|
||||
for (;;) {
|
||||
for (i = 0;; ++i) {
|
||||
x *= 7;
|
||||
if (!(i % 256)) {
|
||||
now = _timespec_mono();
|
||||
if (_timespec_gte(now, next)) {
|
||||
now = timespec_mono();
|
||||
if (timespec_cmp(now, next) >= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
next = _timespec_add(next, interval);
|
||||
next = timespec_add(next, interval);
|
||||
printf("consumed %10g seconds monotonic time and %10g seconds cpu time\n",
|
||||
_timespec_tonanos(_timespec_sub(now, start)) / 1000000000.,
|
||||
timespec_tonanos(timespec_sub(now, start)) / 1000000000.,
|
||||
(double)clock() / CLOCKS_PER_SEC);
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ void show(int clock) {
|
||||
}
|
||||
shown[n++] = clock;
|
||||
if (clock_getres(clock, &ts) != -1) {
|
||||
kprintf("%s %'ld ns\n", DescribeClockName(clock), _timespec_tonanos(ts));
|
||||
kprintf("%s %'ld ns\n", DescribeClockName(clock), timespec_tonanos(ts));
|
||||
} else {
|
||||
kprintf("%s %s\n", DescribeClockName(clock), _strerrno(errno));
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/symbols.internal.h"
|
||||
|
||||
@@ -24,6 +25,12 @@
|
||||
*/
|
||||
|
||||
noubsan int main(int argc, char *argv[]) {
|
||||
|
||||
kprintf("----------------\n");
|
||||
kprintf(" THIS IS A TEST \n");
|
||||
kprintf("SIMULATING CRASH\n");
|
||||
kprintf("----------------\n");
|
||||
|
||||
volatile int64_t x;
|
||||
ShowCrashReports();
|
||||
return 1 / (x = 0);
|
||||
|
||||
+24
-1
@@ -49,12 +49,12 @@ EXAMPLES_DIRECTDEPS = \
|
||||
LIBC_LOG \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_NT_ADVAPI32 \
|
||||
LIBC_NT_IPHLPAPI \
|
||||
LIBC_NT_KERNEL32 \
|
||||
LIBC_NT_NTDLL \
|
||||
LIBC_NT_USER32 \
|
||||
LIBC_NT_WS2_32 \
|
||||
LIBC_NT_ADVAPI32 \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_SOCK \
|
||||
LIBC_STDIO \
|
||||
@@ -71,8 +71,10 @@ EXAMPLES_DIRECTDEPS = \
|
||||
LIBC_ZIPOS \
|
||||
NET_HTTP \
|
||||
NET_HTTPS \
|
||||
THIRD_PARTY_AWK \
|
||||
THIRD_PARTY_COMPILER_RT \
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
THIRD_PARTY_DOUBLECONVERSION \
|
||||
THIRD_PARTY_GDTOA \
|
||||
THIRD_PARTY_GETOPT \
|
||||
THIRD_PARTY_LIBCXX \
|
||||
@@ -83,7 +85,9 @@ EXAMPLES_DIRECTDEPS = \
|
||||
THIRD_PARTY_NSYNC \
|
||||
THIRD_PARTY_NSYNC_MEM \
|
||||
THIRD_PARTY_QUICKJS \
|
||||
THIRD_PARTY_SED \
|
||||
THIRD_PARTY_STB \
|
||||
THIRD_PARTY_TR \
|
||||
THIRD_PARTY_XED \
|
||||
THIRD_PARTY_ZLIB \
|
||||
TOOL_BUILD_LIB \
|
||||
@@ -142,6 +146,25 @@ o/$(MODE)/examples/nesemu1.com.dbg: \
|
||||
$(EXAMPLES_BOOTLOADER)
|
||||
@$(APELINK)
|
||||
|
||||
# # force symtab.com to be a zip file, by pulling a zip asset into linkage
|
||||
# # we wouldn't need to do this if we depended on functions like localtime
|
||||
# o/$(MODE)/examples/symtab.com.dbg: \
|
||||
# $(EXAMPLES_DEPS) \
|
||||
# o/$(MODE)/examples/symtab.o \
|
||||
# o/$(MODE)/examples/symtab.c.zip.o \
|
||||
# o/$(MODE)/examples/examples.pkg \
|
||||
# $(EXAMPLES_BOOTLOADER)
|
||||
# @$(APELINK)
|
||||
|
||||
# modify .com so it can read the symbol table without needing the .com.dbg file
|
||||
o/$(MODE)/examples/symtab.com: \
|
||||
o/$(MODE)/examples/symtab.com.dbg \
|
||||
o/$(MODE)/third_party/zip/zip.com \
|
||||
o/$(MODE)/tool/build/symtab.com
|
||||
@$(MAKE_OBJCOPY)
|
||||
@$(MAKE_SYMTAB_CREATE)
|
||||
@$(MAKE_SYMTAB_ZIP)
|
||||
|
||||
o/$(MODE)/examples/picol.o: private \
|
||||
OVERRIDE_CPPFLAGS += \
|
||||
-DSTACK_FRAME_UNLIMITED
|
||||
|
||||
+1
-8
@@ -9,19 +9,12 @@
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/nt/nt/process.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/rand.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
dontinline void dostuff(const char *s) {
|
||||
int i, us;
|
||||
srand(rand64()); /* seeds rand() w/ intel rdrnd, auxv, etc. */
|
||||
srand(_rand64()); /* seeds rand() w/ intel rdrnd, auxv, etc. */
|
||||
for (i = 0; i < 5; ++i) {
|
||||
us = rand() % 500000;
|
||||
usleep(us);
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/runtime/sysconf.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
int main() {
|
||||
kprintf("%d\n", GetCpuCount());
|
||||
kprintf("%d\n", _getcpucount());
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "ape/sections.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/errno.h"
|
||||
@@ -102,7 +103,7 @@ uint64_t rngset64(void) {
|
||||
static unsigned i;
|
||||
static uint64_t s;
|
||||
if (!i) {
|
||||
s = rand64();
|
||||
s = _rand64();
|
||||
i = (s + 1) & (511);
|
||||
}
|
||||
return MarsagliaXorshift64(&s);
|
||||
@@ -215,7 +216,7 @@ const struct Function {
|
||||
{"moby", moby}, //
|
||||
{"mt19937", _mt19937}, //
|
||||
{"python", pythonx2}, //
|
||||
{"rand64", rand64}, //
|
||||
{"rand64", _rand64}, //
|
||||
{"rdrand", rdrand}, //
|
||||
{"rdrnd", rdrand}, //
|
||||
{"rdseed", rdseed}, //
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
#include "libc/runtime/sysconf.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/sock/struct/pollfd.h"
|
||||
#include "libc/sock/struct/sockaddr.h"
|
||||
@@ -137,7 +136,7 @@ void *Worker(void *id) {
|
||||
setsockopt(server, SOL_TCP, TCP_QUICKACK, &yes, sizeof(yes));
|
||||
errno = 0;
|
||||
|
||||
if (bind(server, &addr, sizeof(addr)) == -1) {
|
||||
if (bind(server, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
|
||||
kprintf("%s() failed %m\n", "socket");
|
||||
goto CloseWorker;
|
||||
}
|
||||
@@ -167,7 +166,7 @@ void *Worker(void *id) {
|
||||
|
||||
// wait for client connection
|
||||
clientaddrsize = sizeof(clientaddr);
|
||||
client = accept(server, &clientaddr, &clientaddrsize);
|
||||
client = accept(server, (struct sockaddr *)&clientaddr, &clientaddrsize);
|
||||
|
||||
// accept() can raise a very diverse number of errors but none of
|
||||
// them are really true showstoppers that would necessitate us to
|
||||
@@ -299,7 +298,7 @@ int main(int argc, char *argv[]) {
|
||||
PORT);
|
||||
}
|
||||
|
||||
threads = argc > 1 ? atoi(argv[1]) : GetCpuCount();
|
||||
threads = argc > 1 ? atoi(argv[1]) : _getcpucount();
|
||||
if (!(1 <= threads && threads <= 100000)) {
|
||||
kprintf("error: invalid number of threads: %d\n", threads);
|
||||
exit(1);
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@
|
||||
#include "third_party/libcxx/vector"
|
||||
#include "tool/viz/lib/knobs.h"
|
||||
|
||||
STATIC_YOINK("zip_uri_support");
|
||||
STATIC_YOINK("zipos");
|
||||
|
||||
#define USAGE \
|
||||
" [ROM] [FMV]\n\
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "ape/sections.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
#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/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/sock/struct/sockaddr.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/af.h"
|
||||
#include "libc/sysv/consts/ipproto.h"
|
||||
#include "libc/sysv/consts/so.h"
|
||||
#include "libc/sysv/consts/sock.h"
|
||||
#include "libc/sysv/consts/sol.h"
|
||||
#include "net/http/ip.h"
|
||||
|
||||
/**
|
||||
* @fileoverview fast local network port scanner, e.g.
|
||||
*
|
||||
* make -j8 o//examples/portscan.com
|
||||
* o//examples/portscan.com 10.10.10.0/24 22
|
||||
*/
|
||||
|
||||
const char *FormatIp(char buf[16], uint32_t ip) {
|
||||
snprintf(buf, 16, "%hhu.%hhu.%hhu.%hhu", ip >> 24, ip >> 16, ip >> 8, ip);
|
||||
return buf;
|
||||
}
|
||||
|
||||
#define FormatIp(x) FormatIp(alloca(16), x)
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int port;
|
||||
struct Cidr in;
|
||||
uint32_t netmask;
|
||||
const char *status;
|
||||
struct timeval timeout;
|
||||
uint32_t network_address;
|
||||
uint32_t last_host_address;
|
||||
uint32_t first_host_address;
|
||||
|
||||
if (argc != 3) {
|
||||
PrintUsage:
|
||||
fprintf(stderr,
|
||||
"usage: %s IP/CIDR PORT\n"
|
||||
"example: %s 192.168.0.0/24 22\n",
|
||||
argv[0], argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
in = ParseCidr(argv[1], -1);
|
||||
if (in.addr == -1) {
|
||||
fprintf(stderr, "error: bad ip/cidr\n");
|
||||
goto PrintUsage;
|
||||
}
|
||||
|
||||
port = atoi(argv[2]);
|
||||
if (!(1 <= port && port <= 65535)) {
|
||||
fprintf(stderr, "error: bad port\n");
|
||||
goto PrintUsage;
|
||||
}
|
||||
|
||||
if (in.cidr > 30) {
|
||||
fprintf(stderr, "error: maximum supported cidr is 30\n");
|
||||
goto PrintUsage;
|
||||
}
|
||||
|
||||
if (in.cidr < 22) {
|
||||
fprintf(stderr, "error: minimum cidr support right now is 22\n");
|
||||
goto PrintUsage;
|
||||
}
|
||||
|
||||
netmask = -1u << (32 - in.cidr);
|
||||
network_address = in.addr & netmask;
|
||||
first_host_address = network_address + 1;
|
||||
last_host_address = (network_address | ~netmask) - 1;
|
||||
|
||||
assert(last_host_address > first_host_address);
|
||||
assert(last_host_address - first_host_address < 1024);
|
||||
|
||||
fprintf(stderr, "scanning %s through %s\n", FormatIp(first_host_address),
|
||||
FormatIp(last_host_address));
|
||||
|
||||
timeout = timeval_frommillis(100);
|
||||
for (int64_t ip = first_host_address; ip <= last_host_address; ++ip) {
|
||||
if (!fork()) {
|
||||
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
setsockopt(3, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
|
||||
setsockopt(3, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
|
||||
if (!connect(3,
|
||||
(struct sockaddr *)&(struct sockaddr_in){
|
||||
.sin_family = AF_INET,
|
||||
.sin_addr.s_addr = htonl(ip),
|
||||
.sin_port = htons(port),
|
||||
},
|
||||
sizeof(struct sockaddr_in))) {
|
||||
status = "open";
|
||||
} else if (errno == ECONNREFUSED) {
|
||||
status = "closed";
|
||||
} else if (errno != EINPROGRESS) {
|
||||
status = _strerrno(errno);
|
||||
} else {
|
||||
status = 0;
|
||||
}
|
||||
if (status) {
|
||||
printf("%-15s %s\n", FormatIp(ip), status);
|
||||
}
|
||||
_Exit(0);
|
||||
}
|
||||
}
|
||||
for (;;) {
|
||||
if (wait(0) == -1 && errno == ECHILD) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#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/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/reboot.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
char line[8] = {0};
|
||||
if (argc > 1 && !strcmp(argv[1], "-y")) {
|
||||
line[0] = 'y';
|
||||
} else {
|
||||
printf("reboot your computer? yes or no [no] ");
|
||||
fflush(stdout);
|
||||
fgets(line, sizeof(line), stdin);
|
||||
}
|
||||
if (line[0] == 'y' || line[0] == 'Y') {
|
||||
if (reboot(RB_AUTOBOOT)) {
|
||||
printf("system is rebooting...\n");
|
||||
exit(0);
|
||||
} else {
|
||||
perror("reboot");
|
||||
exit(1);
|
||||
}
|
||||
} else if (line[0] == 'n' || line[0] == 'N') {
|
||||
exit(0);
|
||||
} else {
|
||||
printf("error: unrecognized response\n");
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#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/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/reboot.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
char line[8] = {0};
|
||||
if (argc > 1 && !strcmp(argv[1], "-y")) {
|
||||
line[0] = 'y';
|
||||
} else {
|
||||
printf("shutdown your computer? yes or no [no] ");
|
||||
fflush(stdout);
|
||||
fgets(line, sizeof(line), stdin);
|
||||
}
|
||||
if (line[0] == 'y' || line[0] == 'Y') {
|
||||
if (reboot(RB_POWER_OFF)) {
|
||||
printf("system is shutting down...\n");
|
||||
exit(0);
|
||||
} else {
|
||||
perror("reboot");
|
||||
exit(1);
|
||||
}
|
||||
} else if (line[0] == 'n' || line[0] == 'N') {
|
||||
exit(0);
|
||||
} else {
|
||||
printf("error: unrecognized response\n");
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#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/intrin/kprintf.h"
|
||||
#include "libc/log/log.h"
|
||||
|
||||
/**
|
||||
* @fileoverview example of how to embed symbol table in .com file
|
||||
*
|
||||
* # build our binary
|
||||
* make -j16 o//examples/symtab.com
|
||||
*
|
||||
* # move binary somewhere else
|
||||
* # so it can't find the .com.dbg binary
|
||||
* cp o//examples/symtab.com /tmp
|
||||
*
|
||||
* # run program
|
||||
* # notice that it has a symbolic backtrace
|
||||
* /tmp/symtab.com
|
||||
*
|
||||
* @see examples/examples.mk
|
||||
*/
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
// this links all the debugging and zip functionality
|
||||
ShowCrashReports();
|
||||
|
||||
kprintf("----------------\n");
|
||||
kprintf(" THIS IS A TEST \n");
|
||||
kprintf("SIMULATING CRASH\n");
|
||||
kprintf("----------------\n");
|
||||
|
||||
volatile int64_t x;
|
||||
return 1 / (x = 0);
|
||||
}
|
||||
+13
-6
@@ -7,13 +7,20 @@
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/dce.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Cosmopolitan Command Interpreter Demo
|
||||
* Yes this works on Windows.
|
||||
*/
|
||||
|
||||
STATIC_YOINK("_tr");
|
||||
STATIC_YOINK("_sed");
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (IsWindows()) {
|
||||
system("notepad");
|
||||
} else {
|
||||
system("ls | tr a-z A-Z");
|
||||
}
|
||||
system("x=world\n"
|
||||
"echo hello $x |\n"
|
||||
" tr a-z A-Z |\n"
|
||||
" sed 's/\\(.\\)/\\1 /g'");
|
||||
}
|
||||
+436
-357
File diff suppressed because it is too large.
Load diff
+2
-2
@@ -49,12 +49,12 @@ int main(int argc, char *argv[]) {
|
||||
printf("res = %d?\n", res);
|
||||
return -1;
|
||||
}
|
||||
printf("Hello World! %.19Lg\n", atan2l(x, y));
|
||||
printf("\e[92;44mHello World!\e[0m %.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);
|
||||
printf("got \e[97m%`'.*s\e[0m\r\n", res, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#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 Demo of program crash reporting with Bare Metal VGA TTY.
|
||||
*
|
||||
* make -j8 o//examples/vga2.com
|
||||
* qemu-system-x86_64 -hda o//examples/vga2.com -serial stdio
|
||||
*/
|
||||
|
||||
STATIC_YOINK("vga_console");
|
||||
STATIC_YOINK("_idt");
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
volatile int x = 1;
|
||||
volatile int y = 2;
|
||||
printf("\e[92;44mHello World!\e[0m %d\n", 1 / (x + y - 3));
|
||||
for (;;);
|
||||
}
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
#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/struct/timespec.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/append.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/time/struct/tm.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
#include "third_party/musl/passwd.h"
|
||||
|
||||
/**
|
||||
* @fileoverview program for broadcasting message to all terminals, e.g.
|
||||
*
|
||||
* o//examples/wall.com hello friends
|
||||
*
|
||||
* Will place some bold text into the top left corners of all terminals:
|
||||
*
|
||||
* Broadcast message from jart@host (pts/4) (Tue Oct 11 03:52:24 2022):
|
||||
* hello friends
|
||||
*
|
||||
* It's useful for having one terminal tab notify your other ones when
|
||||
* something like a long running job completes. In the old days back
|
||||
* when unix systems had multiple users, the wall command provided the
|
||||
* ultimate lulz especially if it's a setuid binary with root privs.
|
||||
*/
|
||||
|
||||
#define GETOPTS "v"
|
||||
#define USAGE \
|
||||
"\
|
||||
Usage: wall.com [-v] [TEXTMSG] [<TEXTMSG]\n\
|
||||
-v increase verbosity\n\
|
||||
Examples:\n\
|
||||
wall.com 'hello my friends'\n\
|
||||
echo hello my friends | wall.com\n\
|
||||
"
|
||||
|
||||
int g_verbose;
|
||||
|
||||
static void GetOpts(int argc, char *argv[]) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, GETOPTS)) != -1) {
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
g_verbose++;
|
||||
break;
|
||||
case '?':
|
||||
write(1, USAGE, sizeof(USAGE) - 1);
|
||||
exit(0);
|
||||
default:
|
||||
write(2, USAGE, sizeof(USAGE) - 1);
|
||||
exit(64);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *GetHost(void) {
|
||||
static char host[254];
|
||||
if (gethostname(host, sizeof(host))) {
|
||||
strcpy(host, "localhost");
|
||||
}
|
||||
return host;
|
||||
}
|
||||
|
||||
char *GetTime(void) {
|
||||
int64_t t;
|
||||
struct tm tm;
|
||||
struct timespec ts;
|
||||
clock_gettime(0, &ts);
|
||||
localtime_r(&ts.tv_sec, &tm);
|
||||
return _chomp(asctime(&tm));
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
GetOpts(argc, argv);
|
||||
|
||||
// create broadcast banner
|
||||
// we use \e[1m so the text is strong & visually distinct
|
||||
// we use \e[K so it doesn't get lost in a forest of text
|
||||
// we map \n → \r\n because teletype might be in raw mode
|
||||
char *msg = 0;
|
||||
const char *s;
|
||||
appends(&msg, "\e7"); // save cursor position
|
||||
appends(&msg, "\e[H"); // goto top left corne
|
||||
appends(&msg, "\e[K"); // clear line forward
|
||||
appends(&msg, "\e[1m"); // bold text
|
||||
appendf(&msg, "Broadcast message from %s@%s", getpwuid(getuid())->pw_name,
|
||||
GetHost());
|
||||
if (isatty(0) && (s = ttyname(0))) appendf(&msg, " (%s)", s);
|
||||
appendf(&msg, " (%s):\r\n", GetTime());
|
||||
appends(&msg, "\e[K");
|
||||
|
||||
// append broadcast message
|
||||
if (optind < argc) {
|
||||
// use cli arguments as message if they exist
|
||||
for (int i = 0; optind + i < argc; ++i) {
|
||||
if (i) appends(&msg, " ");
|
||||
for (s = argv[optind + i]; *s; ++s) {
|
||||
if (*s == '\n') {
|
||||
appends(&msg, "\r\n\e[K");
|
||||
} else {
|
||||
appendw(&msg, *s & 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// otherwise use stdin as message
|
||||
ssize_t i, rc;
|
||||
char buf[512];
|
||||
while ((rc = read(0, buf, sizeof(buf))) > 0) {
|
||||
for (i = 0; i < rc; ++i) {
|
||||
if (buf[i] == '\n') {
|
||||
appends(&msg, "\r\n\e[K"); // clear line forward
|
||||
} else {
|
||||
appendw(&msg, buf[i] & 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
appends(&msg, "\r\n\e[K\e[0m\e8"); // restore
|
||||
|
||||
// try to send message to all pseudoteletypewriters
|
||||
for (int i = 0;; ++i) {
|
||||
int fd;
|
||||
char pts[32];
|
||||
snprintf(pts, sizeof(pts), "/dev/pts/%d", i);
|
||||
if ((fd = open(pts, O_WRONLY | O_NOCTTY)) == -1) {
|
||||
if (errno == ENOENT) break;
|
||||
if (g_verbose) perror(pts);
|
||||
}
|
||||
write(fd, msg, appendz(msg).i);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
+50
-9
@@ -16,19 +16,60 @@ void __assert_fail(const char *, const char *, int) hidden relegated;
|
||||
#define static_assert _Static_assert
|
||||
#endif
|
||||
|
||||
#define _unassert(x) \
|
||||
do { \
|
||||
if (__builtin_expect(!(x), 0)) { \
|
||||
unreachable; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#ifdef __GNUC__
|
||||
#if !defined(TINY) && !defined(MODE_DBG)
|
||||
/**
|
||||
* Specifies expression can't possibly be false.
|
||||
*
|
||||
* This macro uses the `notpossible` keyword and is intended for things
|
||||
* like systems integration, where we know for a fact that something is
|
||||
* never going to happen, but there's no proof. So we don't want to add
|
||||
* extra bloat for filenames and line numbers, since `ShowCrashReports`
|
||||
* can print a backtrace if we just embed the UD2 instruction to crash.
|
||||
* That's useful for systems code, for the following reason. Invariants
|
||||
* make sense with _unassert() since they usually get placed at the top
|
||||
* of functions. But if you used _unassert() to test a system call does
|
||||
* not fail, then check happens at the end of your function usually and
|
||||
* is therefore likely to result in a failure condition where execution
|
||||
* falls through into a different function, which is shocking to debug.
|
||||
*
|
||||
* In `MODE=tiny` these assertions are redefined as undefined behavior.
|
||||
*/
|
||||
#define _npassert(x) \
|
||||
do { \
|
||||
({ \
|
||||
if (__builtin_expect(!(x), 0)) { \
|
||||
notpossible; \
|
||||
} \
|
||||
} while (0)
|
||||
(void)0; \
|
||||
})
|
||||
#else
|
||||
#define _npassert(x) _unassert(x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
/**
|
||||
* Specifies expression being false is undefined behavior.
|
||||
*
|
||||
* This is a good way to tell the compiler about your invariants, which
|
||||
* leads to smaller faster programs. The expression is never removed by
|
||||
* the preprocessor so it's recommended that it be free of side-effects
|
||||
* if you intend for it to be removed. At the same time, this guarantee
|
||||
* makes this assertion useful for things like system calls, since they
|
||||
* won't be removed by `NDEBUG` mode.
|
||||
*
|
||||
* If this assertion fails, the worst possible things can happen unless
|
||||
* you've built your binary in `MODE=dbg` since UBSAN is the only thing
|
||||
* that's capable of debugging this macro.
|
||||
*/
|
||||
#define _unassert(x) \
|
||||
({ \
|
||||
if (__builtin_expect(!(x), 0)) { \
|
||||
unreachable; \
|
||||
} \
|
||||
(void)0; \
|
||||
})
|
||||
#endif
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
||||
@@ -16,5 +16,6 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/sig.internal.h"
|
||||
|
||||
bool __time_critical;
|
||||
struct Signals __sig;
|
||||
@@ -16,26 +16,23 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "ape/sections.internal.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/siginfo.h"
|
||||
#include "libc/intrin/cmpxchg.h"
|
||||
#include "libc/intrin/lockcmpxchg.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/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/errfuns.h"
|
||||
|
||||
/**
|
||||
* @fileoverview UNIX signals for the New Technology, Part 2.
|
||||
* @threadsafe
|
||||
*/
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
/**
|
||||
* Allocates piece of memory for storing pending signal.
|
||||
@@ -61,6 +58,18 @@ static textwindows void __sig_free(struct Signal *mem) {
|
||||
mem->used = false;
|
||||
}
|
||||
|
||||
static inline textwindows int __sig_is_masked(int sig) {
|
||||
if (__tls_enabled) {
|
||||
return __get_tls()->tib_sigmask & (1ull << (sig - 1));
|
||||
} else {
|
||||
return __sig.sigmask & (1ull << (sig - 1));
|
||||
}
|
||||
}
|
||||
|
||||
textwindows int __sig_is_applicable(struct Signal *s) {
|
||||
return s->tid <= 0 || s->tid == gettid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dequeues signal that isn't masked.
|
||||
* @return signal or null if empty or none unmasked
|
||||
@@ -70,7 +79,7 @@ static textwindows struct Signal *__sig_remove(void) {
|
||||
if (__sig.queue) {
|
||||
__sig_lock();
|
||||
for (prev = 0, res = __sig.queue; res; prev = res, res = res->next) {
|
||||
if (!sigismember(&__sig.mask, res->sig)) {
|
||||
if (__sig_is_applicable(res) && !__sig_is_masked(res->sig)) {
|
||||
if (res == __sig.queue) {
|
||||
__sig.queue = res->next;
|
||||
} else if (prev) {
|
||||
@@ -78,8 +87,6 @@ static textwindows struct Signal *__sig_remove(void) {
|
||||
}
|
||||
res->next = 0;
|
||||
break;
|
||||
} else {
|
||||
STRACE("%G is masked", res->sig);
|
||||
}
|
||||
}
|
||||
__sig_unlock();
|
||||
@@ -101,7 +108,6 @@ static bool __sig_deliver(bool restartable, int sig, int si_code,
|
||||
STRACE("delivering %G", sig);
|
||||
|
||||
// enter the signal
|
||||
__sig_lock();
|
||||
rva = __sighandrvas[sig];
|
||||
flags = __sighandflags[sig];
|
||||
if ((~flags & SA_NODEFER) || (flags & SA_RESETHAND)) {
|
||||
@@ -112,12 +118,11 @@ static bool __sig_deliver(bool restartable, int sig, int si_code,
|
||||
// signal handler. in that case you must use SA_NODEFER.
|
||||
__sighandrvas[sig] = (int32_t)(intptr_t)SIG_DFL;
|
||||
}
|
||||
__sig_unlock();
|
||||
|
||||
// setup the somewhat expensive information args
|
||||
// only if they're requested by the user in sigaction()
|
||||
if (flags & SA_SIGINFO) {
|
||||
__repstosb(&info, 0, sizeof(info));
|
||||
bzero(&info, sizeof(info));
|
||||
info.si_signo = sig;
|
||||
info.si_code = si_code;
|
||||
infop = &info;
|
||||
@@ -134,7 +139,9 @@ static bool __sig_deliver(bool restartable, int sig, int si_code,
|
||||
// since sigaction() is @asyncsignalsafe we only restore it if the
|
||||
// user didn't change it during the signal handler. we also don't
|
||||
// need to do anything if this was a oneshot signal or nodefer.
|
||||
_lockcmpxchg(__sighandrvas + sig, (int32_t)(intptr_t)SIG_DFL, rva);
|
||||
if (__sighandrvas[sig] == (int32_t)(intptr_t)SIG_DFL) {
|
||||
__sighandrvas[sig] = rva;
|
||||
}
|
||||
}
|
||||
|
||||
if (!restartable) {
|
||||
@@ -150,7 +157,7 @@ static bool __sig_deliver(bool restartable, int sig, int si_code,
|
||||
/**
|
||||
* Returns true if signal default action is to end process.
|
||||
*/
|
||||
static textwindows bool __sig_isfatal(int sig) {
|
||||
static textwindows bool __sig_is_fatal(int sig) {
|
||||
if (sig == SIGCHLD || sig == SIGURG || sig == SIGWINCH) {
|
||||
return false;
|
||||
} else {
|
||||
@@ -168,7 +175,7 @@ bool __sig_handle(bool restartable, int sig, int si_code, ucontext_t *ctx) {
|
||||
bool delivered;
|
||||
switch (__sighandrvas[sig]) {
|
||||
case (intptr_t)SIG_DFL:
|
||||
if (__sig_isfatal(sig)) {
|
||||
if (__sig_is_fatal(sig)) {
|
||||
STRACE("terminating on %G", sig);
|
||||
_Exitr(128 + sig);
|
||||
}
|
||||
@@ -194,20 +201,18 @@ bool __sig_handle(bool restartable, int sig, int si_code, ucontext_t *ctx) {
|
||||
* @threadsafe
|
||||
*/
|
||||
textwindows int __sig_raise(int sig, int si_code) {
|
||||
int rc;
|
||||
int candeliver;
|
||||
__sig_lock();
|
||||
candeliver = !sigismember(&__sig.mask, sig);
|
||||
__sig_unlock();
|
||||
switch (candeliver) {
|
||||
case 1:
|
||||
if (1 <= sig && sig <= 64) {
|
||||
if (!__sig_is_masked(sig)) {
|
||||
++__sig_count;
|
||||
// TODO(jart): ucontext_t support
|
||||
__sig_handle(false, sig, si_code, 0);
|
||||
return 0;
|
||||
case 0:
|
||||
} else {
|
||||
STRACE("%G is masked", sig);
|
||||
return __sig_add(sig, si_code);
|
||||
default:
|
||||
return -1; // sigismember() validates `sig`
|
||||
return __sig_add(gettid(), sig, si_code);
|
||||
}
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,18 +221,19 @@ textwindows int __sig_raise(int sig, int si_code) {
|
||||
* @return 0 on success, otherwise -1 w/ errno
|
||||
* @threadsafe
|
||||
*/
|
||||
textwindows int __sig_add(int sig, int si_code) {
|
||||
textwindows int __sig_add(int tid, int sig, int si_code) {
|
||||
int rc;
|
||||
struct Signal *mem;
|
||||
if (1 <= sig && sig <= NSIG) {
|
||||
__sig_lock();
|
||||
if (1 <= sig && sig <= 64) {
|
||||
if (__sighandrvas[sig] == (unsigned)(intptr_t)SIG_IGN) {
|
||||
STRACE("ignoring %G", sig);
|
||||
rc = 0;
|
||||
} else {
|
||||
STRACE("enqueuing %G", sig);
|
||||
__sig_lock();
|
||||
++__sig_count;
|
||||
if ((mem = __sig_alloc())) {
|
||||
mem->tid = tid;
|
||||
mem->sig = sig;
|
||||
mem->si_code = si_code;
|
||||
mem->next = __sig.queue;
|
||||
@@ -236,8 +242,8 @@ textwindows int __sig_add(int sig, int si_code) {
|
||||
} else {
|
||||
rc = enomem();
|
||||
}
|
||||
__sig_unlock();
|
||||
}
|
||||
__sig_unlock();
|
||||
} else {
|
||||
rc = einval();
|
||||
}
|
||||
@@ -276,7 +282,7 @@ textwindows bool __sig_check(bool restartable) {
|
||||
textwindows void __sig_check_ignore(const int sig, const unsigned rva) {
|
||||
struct Signal *cur, *prev, *next;
|
||||
if (rva != (unsigned)(intptr_t)SIG_IGN &&
|
||||
(rva != (unsigned)(intptr_t)SIG_DFL || __sig_isfatal(sig))) {
|
||||
(rva != (unsigned)(intptr_t)SIG_DFL || __sig_is_fatal(sig))) {
|
||||
return;
|
||||
}
|
||||
if (__sig.queue) {
|
||||
@@ -298,25 +304,3 @@ textwindows void __sig_check_ignore(const int sig, const unsigned rva) {
|
||||
__sig_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the pending signals on New Technology.
|
||||
*
|
||||
* @param pending is to hold the pending signals
|
||||
* @threadsafe
|
||||
*/
|
||||
textwindows void __sig_pending(sigset_t *pending) {
|
||||
struct Signal *cur;
|
||||
sigemptyset(pending);
|
||||
if (__sig.queue) {
|
||||
__sig_lock();
|
||||
for (cur = __sig.queue; cur; cur = cur->next) {
|
||||
if (__sighandrvas[cur->sig] != (unsigned)(intptr_t)SIG_IGN) {
|
||||
pending->__bits[(cur->sig - 1) >> 6] |= (1ull << ((cur->sig - 1) & 63));
|
||||
} else {
|
||||
STRACE("%G is ignored", cur->sig);
|
||||
}
|
||||
}
|
||||
__sig_unlock();
|
||||
}
|
||||
}
|
||||
@@ -16,50 +16,45 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
/**
|
||||
* @fileoverview UNIX signals for the New Technology, Part 1.
|
||||
* @threadsafe
|
||||
*/
|
||||
#define GetSigBit(x) (1ull << (((x)-1) & 63))
|
||||
|
||||
struct Signals __sig; // TODO(jart): Need TLS
|
||||
|
||||
#define GetSigBit(XXSIG) (1ull << (((XXSIG)-1) & 63))
|
||||
|
||||
/**
|
||||
* Changes signal mask for main thread.
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
*/
|
||||
textwindows int __sig_mask(int how, const sigset_t *neu, sigset_t *old) {
|
||||
int i;
|
||||
uint64_t a, b;
|
||||
uint64_t x, y, *mask;
|
||||
if (how == SIG_BLOCK || how == SIG_UNBLOCK || how == SIG_SETMASK) {
|
||||
__sig_lock();
|
||||
if (__tls_enabled) {
|
||||
mask = &__get_tls()->tib_sigmask;
|
||||
} else {
|
||||
mask = &__sig.sigmask;
|
||||
}
|
||||
if (old) {
|
||||
*old = __sig.mask;
|
||||
old->__bits[0] = *mask;
|
||||
old->__bits[1] = 0;
|
||||
}
|
||||
if (neu) {
|
||||
for (i = 0; i < ARRAYLEN(__sig.mask.__bits); ++i) {
|
||||
if (how == SIG_BLOCK) {
|
||||
__sig.mask.__bits[i] |= neu->__bits[i];
|
||||
} else if (how == SIG_UNBLOCK) {
|
||||
__sig.mask.__bits[i] &= ~neu->__bits[i];
|
||||
} else {
|
||||
__sig.mask.__bits[i] = neu->__bits[i];
|
||||
}
|
||||
x = *mask;
|
||||
y = neu->__bits[0];
|
||||
if (how == SIG_BLOCK) {
|
||||
x |= y;
|
||||
} else if (how == SIG_UNBLOCK) {
|
||||
x &= ~y;
|
||||
} else {
|
||||
x = y;
|
||||
}
|
||||
__sig.mask.__bits[0] &= ~(GetSigBit(SIGKILL) | GetSigBit(SIGSTOP));
|
||||
x &= ~(0
|
||||
#define M(x) | GetSigBit(x)
|
||||
#include "libc/intrin/sigisprecious.inc"
|
||||
);
|
||||
*mask = x;
|
||||
}
|
||||
__sig_unlock();
|
||||
return 0;
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
}
|
||||
|
||||
#undef GetSigBit
|
||||
@@ -0,0 +1,43 @@
|
||||
/*-*- 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/sig.internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
|
||||
/**
|
||||
* Determines the pending signals on New Technology.
|
||||
*
|
||||
* @param pending is to hold the pending signals
|
||||
* @threadsafe
|
||||
*/
|
||||
textwindows void __sig_pending(sigset_t *pending) {
|
||||
struct Signal *s;
|
||||
sigemptyset(pending);
|
||||
if (__sig.queue) {
|
||||
__sig_lock();
|
||||
for (s = __sig.queue; s; s = s->next) {
|
||||
if (__sig_is_applicable(s) &&
|
||||
__sighandrvas[s->sig] != (unsigned)(intptr_t)SIG_IGN) {
|
||||
sigaddset(pending, s->sig);
|
||||
}
|
||||
}
|
||||
__sig_unlock();
|
||||
}
|
||||
}
|
||||
+6
-1
@@ -22,9 +22,14 @@
|
||||
/**
|
||||
* Checks if effective user can access path in particular ways.
|
||||
*
|
||||
* This is equivalent to saying:
|
||||
*
|
||||
* faccessat(AT_FDCWD, path, mode, 0);
|
||||
*
|
||||
* @param path is a filename or directory
|
||||
* @param mode can be R_OK, W_OK, X_OK, F_OK
|
||||
* @return 0 if ok, or -1 and sets errno
|
||||
* @return 0 if ok, or -1 w/ errno
|
||||
* @see faccessat() for further documentation
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int access(const char *path, int mode) {
|
||||
|
||||
+1
-3
@@ -32,12 +32,10 @@
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
unsigned alarm(unsigned seconds) {
|
||||
int rc;
|
||||
struct itimerval it;
|
||||
bzero(&it, sizeof(it));
|
||||
it.it_value.tv_sec = seconds;
|
||||
rc = setitimer(ITIMER_REAL, &it, &it);
|
||||
assert(rc != -1);
|
||||
_npassert(!setitimer(ITIMER_REAL, &it, &it));
|
||||
if (!it.it_value.tv_sec && !it.it_value.tv_usec) {
|
||||
return 0;
|
||||
} else {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#ifndef COSMOPOLITAN_LIBC_CALLS_ASAN_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_ASAN_INTERNAL_H_
|
||||
#include "libc/intrin/asmflag.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/intrin/asmflag.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
@@ -14,6 +15,10 @@ forceinline bool __asan_is_valid_timespec(const struct timespec *ts) {
|
||||
return zf;
|
||||
}
|
||||
|
||||
forceinline bool __asan_is_valid_timeval(const struct timeval *tv) {
|
||||
return __asan_is_valid_timespec((const struct timespec *)tv);
|
||||
}
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_ASAN_INTERNAL_H_ */
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef COSMOPOLITAN_LIBC_CALLS_BLOCKCANCEL_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_BLOCKCANCEL_H_
|
||||
#include "libc/thread/thread.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define BLOCK_CANCELLATIONS \
|
||||
do { \
|
||||
int _CancelState; \
|
||||
_CancelState = _pthread_block_cancellations()
|
||||
|
||||
#define ALLOW_CANCELLATIONS \
|
||||
_pthread_allow_cancellations(_CancelState); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
int _pthread_block_cancellations(void);
|
||||
void _pthread_allow_cancellations(int);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_BLOCKCANCEL_H_ */
|
||||
@@ -0,0 +1,19 @@
|
||||
#ifndef COSMOPOLITAN_LIBC_CALLS_BLOCKSIGS_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_BLOCKSIGS_H_
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define BLOCK_SIGNALS \
|
||||
do { \
|
||||
sigset_t _SigMask; \
|
||||
_SigMask = _sigblockall()
|
||||
|
||||
#define ALLOW_SIGNALS \
|
||||
_sigsetmask(_SigMask); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_BLOCKSIGS_H_ */
|
||||
+52
-50
@@ -65,13 +65,13 @@ char *ttyname(int);
|
||||
int access(const char *, int) dontthrow;
|
||||
int arch_prctl();
|
||||
int chdir(const char *);
|
||||
int chmod(const char *, uint32_t);
|
||||
int chown(const char *, uint32_t, uint32_t);
|
||||
int chmod(const char *, unsigned);
|
||||
int chown(const char *, unsigned, unsigned);
|
||||
int chroot(const char *);
|
||||
int close(int);
|
||||
int close_range(unsigned, unsigned, unsigned);
|
||||
int closefrom(int);
|
||||
int creat(const char *, uint32_t);
|
||||
int creat(const char *, unsigned);
|
||||
int dup(int);
|
||||
int dup2(int, int);
|
||||
int dup3(int, int, int);
|
||||
@@ -84,24 +84,22 @@ int execv(const char *, char *const[]);
|
||||
int execve(const char *, char *const[], char *const[]);
|
||||
int execvp(const char *, char *const[]);
|
||||
int execvpe(const char *, char *const[], char *const[]);
|
||||
int faccessat(int, const char *, int, uint32_t);
|
||||
int faccessat(int, const char *, int, int);
|
||||
int fadvise(int, uint64_t, uint64_t, int);
|
||||
int fchdir(int);
|
||||
int fchmod(int, uint32_t) dontthrow;
|
||||
int fchmodat(int, const char *, uint32_t, int);
|
||||
int fchown(int, uint32_t, uint32_t);
|
||||
int fchownat(int, const char *, uint32_t, uint32_t, int);
|
||||
int fchmod(int, unsigned) dontthrow;
|
||||
int fchmodat(int, const char *, unsigned, int);
|
||||
int fchown(int, unsigned, unsigned);
|
||||
int fchownat(int, const char *, unsigned, unsigned, int);
|
||||
int fcntl(int, int, ...);
|
||||
int fdatasync(int);
|
||||
int fexecve(int, char *const[], char *const[]);
|
||||
int flock(int, int);
|
||||
int fork(void);
|
||||
int fsync(int);
|
||||
int ftruncate(int, int64_t);
|
||||
int getdomainname(char *, size_t);
|
||||
uint32_t getegid(void) nosideeffect;
|
||||
uint32_t geteuid(void) nosideeffect;
|
||||
uint32_t getgid(void) nosideeffect;
|
||||
int getgroups(int size, uint32_t list[]);
|
||||
int getgroups(int, unsigned[]);
|
||||
int gethostname(char *, size_t);
|
||||
int getloadavg(double *, int);
|
||||
int getpgid(int) libcesque;
|
||||
@@ -109,35 +107,29 @@ int getpgrp(void) nosideeffect;
|
||||
int getpid(void) nosideeffect libcesque;
|
||||
int getppid(void);
|
||||
int getpriority(int, unsigned);
|
||||
int getresgid(uint32_t *, uint32_t *, uint32_t *);
|
||||
int getresuid(uint32_t *, uint32_t *, uint32_t *);
|
||||
int getresgid(unsigned *, unsigned *, unsigned *);
|
||||
int getresuid(unsigned *, unsigned *, unsigned *);
|
||||
int getsid(int) nosideeffect libcesque;
|
||||
int gettid(void) libcesque;
|
||||
uint32_t getuid(void) libcesque;
|
||||
int sys_iopl(int);
|
||||
int ioprio_get(int, int);
|
||||
int ioprio_set(int, int, int);
|
||||
int issetugid(void);
|
||||
int kill(int, int);
|
||||
int killpg(int, int);
|
||||
int lchmod(const char *, uint32_t);
|
||||
int lchown(const char *, uint32_t, uint32_t);
|
||||
int lchmod(const char *, unsigned);
|
||||
int lchown(const char *, unsigned, unsigned);
|
||||
int link(const char *, const char *) dontthrow;
|
||||
int linkat(int, const char *, int, const char *, int);
|
||||
int madvise(void *, uint64_t, int);
|
||||
int makedirs(const char *, unsigned);
|
||||
int memfd_create(const char *, unsigned int);
|
||||
int mincore(void *, size_t, unsigned char *);
|
||||
int mkdir(const char *, uint32_t);
|
||||
int mkdirat(int, const char *, uint32_t);
|
||||
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 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 mkdir(const char *, unsigned);
|
||||
int mkdirat(int, const char *, unsigned);
|
||||
int mkfifo(const char *, unsigned);
|
||||
int mkfifoat(int, const char *, unsigned);
|
||||
int mknod(const char *, unsigned, uint64_t);
|
||||
int mknodat(int, const char *, int, uint64_t);
|
||||
int nice(int);
|
||||
int open(const char *, int, ...);
|
||||
int openat(int, const char *, int, ...);
|
||||
@@ -147,7 +139,7 @@ int pipe(int[hasatleast 2]);
|
||||
int pipe2(int[hasatleast 2], int);
|
||||
int pivot_root(const char *, const char *);
|
||||
int pledge(const char *, const char *);
|
||||
int posix_fadvise(int, uint64_t, uint64_t, int);
|
||||
int posix_fadvise(int, int64_t, int64_t, int);
|
||||
int posix_madvise(void *, uint64_t, int);
|
||||
int prctl(int, ...);
|
||||
int raise(int);
|
||||
@@ -159,36 +151,42 @@ int renameat2(long, const char *, long, const char *, int);
|
||||
int rmdir(const char *);
|
||||
int sched_yield(void);
|
||||
int seccomp(unsigned, unsigned, void *);
|
||||
int setegid(uint32_t);
|
||||
int seteuid(uint32_t);
|
||||
int setfsgid(int);
|
||||
int setfsuid(int);
|
||||
int setgid(int);
|
||||
int setgroups(size_t size, const uint32_t list[]);
|
||||
int setegid(unsigned);
|
||||
int seteuid(unsigned);
|
||||
int setfsgid(unsigned);
|
||||
int setfsuid(unsigned);
|
||||
int setgid(unsigned);
|
||||
int setgroups(size_t, const unsigned[]);
|
||||
int setpgid(int, int);
|
||||
int setpgrp(void);
|
||||
int setpriority(int, unsigned, int);
|
||||
int setregid(uint32_t, uint32_t);
|
||||
int setresgid(uint32_t, uint32_t, uint32_t);
|
||||
int setresuid(uint32_t, uint32_t, uint32_t);
|
||||
int setreuid(uint32_t, uint32_t);
|
||||
int setregid(unsigned, unsigned);
|
||||
int setresgid(unsigned, unsigned, unsigned);
|
||||
int setresuid(unsigned, unsigned, unsigned);
|
||||
int setreuid(unsigned, unsigned);
|
||||
int setsid(void);
|
||||
int setuid(int);
|
||||
int setuid(unsigned);
|
||||
int sigignore(int);
|
||||
int siginterrupt(int, int);
|
||||
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_iopl(int);
|
||||
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 sys_ptrace(int, ...);
|
||||
int sys_sysctl(const int *, unsigned, void *, size_t *, void *, size_t);
|
||||
int tcsetpgrp(int, int32_t);
|
||||
int tcgetpgrp(int);
|
||||
int tcsetpgrp(int, int);
|
||||
int tgkill(int, int, int);
|
||||
int tkill(int, int);
|
||||
int tmpfd(void);
|
||||
int touch(const char *, uint32_t);
|
||||
int truncate(const char *, uint64_t);
|
||||
int touch(const char *, unsigned);
|
||||
int truncate(const char *, int64_t);
|
||||
int ttyname_r(int, char *, size_t);
|
||||
int umask(int);
|
||||
int unlink(const char *);
|
||||
int unlink_s(const char **);
|
||||
int unlinkat(int, const char *, int);
|
||||
@@ -197,21 +195,25 @@ int usleep(unsigned);
|
||||
int vfork(void) returnstwice;
|
||||
int wait(int *);
|
||||
int waitpid(int, int *, int);
|
||||
int32_t tcgetpgrp(int);
|
||||
intptr_t syscall(int, ...);
|
||||
long ptrace(int, ...);
|
||||
ssize_t copy_file_range(int, long *, int, long *, size_t, uint32_t);
|
||||
ssize_t copyfd(int, int64_t *, int, int64_t *, size_t, uint32_t);
|
||||
ssize_t copy_file_range(int, long *, int, long *, size_t, unsigned);
|
||||
ssize_t copyfd(int, int64_t *, int, int64_t *, size_t, unsigned);
|
||||
ssize_t getfiledescriptorsize(int);
|
||||
ssize_t lseek(int, int64_t, unsigned);
|
||||
ssize_t lseek(int, int64_t, int);
|
||||
ssize_t pread(int, void *, size_t, int64_t);
|
||||
ssize_t pwrite(int, const void *, size_t, int64_t);
|
||||
ssize_t read(int, void *, size_t);
|
||||
ssize_t readansi(int, char *, size_t);
|
||||
ssize_t readlink(const char *, char *, size_t);
|
||||
ssize_t readlinkat(int, const char *, char *, size_t);
|
||||
ssize_t splice(int, int64_t *, int, int64_t *, size_t, uint32_t);
|
||||
ssize_t splice(int, int64_t *, int, int64_t *, size_t, unsigned);
|
||||
ssize_t write(int, const void *, size_t);
|
||||
unsigned getegid(void) nosideeffect;
|
||||
unsigned geteuid(void) nosideeffect;
|
||||
unsigned getgid(void) nosideeffect;
|
||||
unsigned getuid(void) libcesque;
|
||||
unsigned umask(unsigned);
|
||||
void sync(void);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
||||
+16
-6
@@ -65,6 +65,13 @@ $(LIBC_CALLS_A).pkg: \
|
||||
$(LIBC_CALLS_A_OBJS) \
|
||||
$(foreach x,$(LIBC_CALLS_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
# we can't use asan because:
|
||||
# siginfo_t memory is owned by kernels
|
||||
o/$(MODE)/libc/calls/siginfo2cosmo.o: private \
|
||||
OVERRIDE_COPTS += \
|
||||
-ffreestanding \
|
||||
-fno-sanitize=address
|
||||
|
||||
# we can't use asan because:
|
||||
# ucontext_t memory is owned by xnu kernel
|
||||
o/$(MODE)/libc/calls/sigenter-xnu.o: private \
|
||||
@@ -172,12 +179,15 @@ o//libc/calls/statfs2cosmo.o: private \
|
||||
# we always want -O2 because:
|
||||
# division is expensive if not optimized
|
||||
o/$(MODE)/libc/calls/clock.o \
|
||||
o/$(MODE)/libc/calls/_timespec_tomillis.o \
|
||||
o/$(MODE)/libc/calls/_timespec_tomicros.o \
|
||||
o/$(MODE)/libc/calls/_timespec_totimeval.o \
|
||||
o/$(MODE)/libc/calls/_timespec_fromnanos.o \
|
||||
o/$(MODE)/libc/calls/_timespec_frommillis.o \
|
||||
o/$(MODE)/libc/calls/_timespec_frommicros.o: private \
|
||||
o/$(MODE)/libc/calls/timespec_tomillis.o \
|
||||
o/$(MODE)/libc/calls/timespec_tomicros.o \
|
||||
o/$(MODE)/libc/calls/timespec_totimeval.o \
|
||||
o/$(MODE)/libc/calls/timespec_fromnanos.o \
|
||||
o/$(MODE)/libc/calls/timespec_frommillis.o \
|
||||
o/$(MODE)/libc/calls/timespec_frommicros.o \
|
||||
o/$(MODE)/libc/calls/timeval_tomillis.o \
|
||||
o/$(MODE)/libc/calls/timeval_frommillis.o \
|
||||
o/$(MODE)/libc/calls/timeval_frommicros.o: private \
|
||||
OVERRIDE_CFLAGS += \
|
||||
-O2
|
||||
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
|
||||
uint32_t cfgetispeed(const struct termios *t) {
|
||||
if (CBAUD) {
|
||||
return t->c_cflag & CBAUD;
|
||||
} else {
|
||||
return t->c_ispeed;
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
|
||||
uint32_t cfgetospeed(const struct termios *t) {
|
||||
if (CBAUD) {
|
||||
return t->c_cflag & CBAUD;
|
||||
} else {
|
||||
return t->c_ospeed;
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int cfsetispeed(struct termios *t, int speed) {
|
||||
if (speed) {
|
||||
if (CBAUD) {
|
||||
if (speed & ~CBAUD) return einval();
|
||||
t->c_cflag &= ~CBAUD;
|
||||
t->c_cflag |= speed;
|
||||
} else {
|
||||
t->c_ispeed = speed;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -20,7 +20,59 @@
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int cfsetospeed(struct termios *t, int speed) {
|
||||
/**
|
||||
* Returns input baud rate.
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
uint32_t cfgetispeed(const struct termios *t) {
|
||||
if (CBAUD) {
|
||||
return t->c_cflag & CBAUD;
|
||||
} else {
|
||||
return t->c_ispeed;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns output baud rate.
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
uint32_t cfgetospeed(const struct termios *t) {
|
||||
if (CBAUD) {
|
||||
return t->c_cflag & CBAUD;
|
||||
} else {
|
||||
return t->c_ospeed;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets input baud rate.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int cfsetispeed(struct termios *t, unsigned speed) {
|
||||
if (speed) {
|
||||
if (CBAUD) {
|
||||
if (!(speed & ~CBAUD)) {
|
||||
t->c_cflag &= ~CBAUD;
|
||||
t->c_cflag |= speed;
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
} else {
|
||||
t->c_ispeed = speed;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets output baud rate.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int cfsetospeed(struct termios *t, unsigned speed) {
|
||||
if (CBAUD) {
|
||||
if (!(speed & ~CBAUD)) {
|
||||
t->c_cflag &= ~CBAUD;
|
||||
+4
-2
@@ -16,11 +16,12 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/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/strace.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
@@ -34,7 +35,8 @@
|
||||
*/
|
||||
int chdir(const char *path) {
|
||||
int rc;
|
||||
if (!path || (IsAsan() && !__asan_is_valid(path, 1))) {
|
||||
GetProgramExecutableName(); // XXX: ugly workaround
|
||||
if (!path || (IsAsan() && !__asan_is_valid_str(path))) {
|
||||
rc = efault();
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_chdir(path);
|
||||
|
||||
+28
-2
@@ -17,17 +17,43 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Changes root directory.
|
||||
*
|
||||
* Please consider using unveil() instead of chroot(). If you use this
|
||||
* system call then consider using both chdir() and closefrom() before
|
||||
* calling this function. Otherwise there's a small risk that fchdir()
|
||||
* could be used to escape the chroot() environment. Cosmopolitan Libc
|
||||
* focuses on static binaries which make chroot() infinitely easier to
|
||||
* use since you don't need to construct an entire userspace each time
|
||||
* however unveil() is still better to use on modern Linux and OpenBSD
|
||||
* because it doesn't require root privileges.
|
||||
*
|
||||
* @param path shall become the new root directory
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise EACCES if we don't have permission to search a component of `path`
|
||||
* @raise ENOTDIR if a directory component in `path` exists as non-directory
|
||||
* @raise ENAMETOOLONG if symlink-resolved `path` length exceeds `PATH_MAX`
|
||||
* @raise ENAMETOOLONG if component in `path` exists longer than `NAME_MAX`
|
||||
* @raise EPERM if not root or pledge() is in play
|
||||
* @raise EIO if a low-level i/o error occurred
|
||||
* @raise EFAULT if `path` is bad memory
|
||||
* @raise ENOENT if `path` doesn't exist
|
||||
* @raise ENOSYS on Windows
|
||||
*/
|
||||
int chroot(const char *path) {
|
||||
int rc;
|
||||
rc = sys_chroot(path);
|
||||
if (!path || (IsAsan() && !__asan_is_valid_str(path))) {
|
||||
rc = efault();
|
||||
} else {
|
||||
rc = sys_chroot(path);
|
||||
}
|
||||
STRACE("chroot(%s) → %d% m", path, rc);
|
||||
return rc;
|
||||
}
|
||||
+1
-1
@@ -55,7 +55,7 @@ int64_t clock(void) {
|
||||
if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) == -1) {
|
||||
errno = e;
|
||||
if (getrusage(RUSAGE_SELF, &ru) != -1) {
|
||||
ts = _timeval_totimespec(_timeval_add(ru.ru_utime, ru.ru_stime));
|
||||
ts = timeval_totimespec(timeval_add(ru.ru_utime, ru.ru_stime));
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/asan.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"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/time/time.h"
|
||||
@@ -49,6 +49,12 @@ static int sys_clock_getres_xnu(int clock, struct timespec *ts) {
|
||||
|
||||
/**
|
||||
* Returns granularity of clock.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @error EPERM if pledge() is in play without stdio promise
|
||||
* @error EINVAL if `clock` isn't supported on this system
|
||||
* @error EFAULT if `ts` points to bad memory
|
||||
* @threadsafe
|
||||
*/
|
||||
int clock_getres(int clock, struct timespec *ts) {
|
||||
int rc;
|
||||
|
||||
@@ -17,11 +17,11 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/nexgen32e/rdtsc.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
static struct {
|
||||
pthread_once_t once;
|
||||
@@ -30,7 +30,7 @@ static struct {
|
||||
} g_mono;
|
||||
|
||||
static void sys_clock_gettime_mono_init(void) {
|
||||
g_mono.base_wall = _timespec_real();
|
||||
g_mono.base_wall = timespec_real();
|
||||
g_mono.base_tick = rdtsc();
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ int sys_clock_gettime_mono(struct timespec *time) {
|
||||
pthread_once(&g_mono.once, sys_clock_gettime_mono_init);
|
||||
cycles = rdtsc() - g_mono.base_tick;
|
||||
nanos = cycles / 3;
|
||||
*time = _timespec_add(g_mono.base_wall, _timespec_fromnanos(nanos));
|
||||
*time = timespec_add(g_mono.base_wall, timespec_fromnanos(nanos));
|
||||
return 0;
|
||||
} else {
|
||||
return einval();
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include "libc/calls/asan.internal.h"
|
||||
#include "libc/calls/clock_gettime.internal.h"
|
||||
#include "libc/calls/state.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"
|
||||
@@ -30,9 +29,11 @@
|
||||
#include "libc/intrin/asmflag.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
/**
|
||||
* Returns nanosecond time.
|
||||
@@ -48,12 +49,30 @@
|
||||
* __clock_gettime l: 35𝑐 11𝑛𝑠
|
||||
* sys_clock_gettime l: 220𝑐 71𝑛𝑠
|
||||
*
|
||||
* @param clock can be CLOCK_REALTIME, CLOCK_MONOTONIC, etc.
|
||||
* @param clock can be one of:
|
||||
* - `CLOCK_REALTIME`: universally supported
|
||||
* - `CLOCK_REALTIME_FAST`: ditto but faster on freebsd
|
||||
* - `CLOCK_MONOTONIC`: universally supported
|
||||
* - `CLOCK_MONOTONIC_FAST`: ditto but faster on freebsd
|
||||
* - `CLOCK_MONOTONIC_RAW`: nearly universally supported
|
||||
* - `CLOCK_PROCESS_CPUTIME_ID`: linux and bsd
|
||||
* - `CLOCK_THREAD_CPUTIME_ID`: linux and bsd
|
||||
* - `CLOCK_REALTIME_COARSE`: : linux and openbsd
|
||||
* - `CLOCK_MONOTONIC_COARSE`: linux
|
||||
* - `CLOCK_PROF`: linux and netbsd
|
||||
* - `CLOCK_BOOTTIME`: linux and openbsd
|
||||
* - `CLOCK_REALTIME_ALARM`: linux-only
|
||||
* - `CLOCK_BOOTTIME_ALARM`: linux-only
|
||||
* - `CLOCK_TAI`: linux-only
|
||||
* @param ts is where the result is stored
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @error EINVAL if clock isn't supported on this system
|
||||
* @error EPERM if pledge() is in play without stdio promise
|
||||
* @error EINVAL if `clock` isn't supported on this system
|
||||
* @error EFAULT if `ts` points to bad memory
|
||||
* @see strftime(), gettimeofday()
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
int clock_gettime(int clock, struct timespec *ts) {
|
||||
int rc;
|
||||
@@ -65,7 +84,7 @@ int clock_gettime(int clock, struct timespec *ts) {
|
||||
rc = __clock_gettime(clock, ts);
|
||||
}
|
||||
#if SYSDEBUG
|
||||
if (!__time_critical) {
|
||||
if (__tls_enabled && !(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
|
||||
STRACE("clock_gettime(%s, [%s]) → %d% m", DescribeClockName(clock),
|
||||
DescribeTimespec(rc, ts), rc);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/calls/struct/timespec.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/sysv/consts/timer.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int sys_clock_nanosleep_nt(int clock, int flags,
|
||||
const struct timespec *req,
|
||||
struct timespec *rem) {
|
||||
struct timespec now, abs;
|
||||
if (flags & TIMER_ABSTIME) {
|
||||
abs = *req;
|
||||
for (;;) {
|
||||
if (sys_clock_gettime_nt(clock, &now)) return -1;
|
||||
if (timespec_cmp(now, abs) >= 0) return 0;
|
||||
if (_check_interrupts(false, g_fds.p)) return -1;
|
||||
SleepEx(MIN(__SIG_POLLING_INTERVAL_MS,
|
||||
timespec_tomillis(timespec_sub(abs, now))),
|
||||
false);
|
||||
}
|
||||
} else {
|
||||
if (sys_clock_gettime_nt(clock, &now)) return -1;
|
||||
abs = timespec_add(now, *req);
|
||||
for (;;) {
|
||||
sys_clock_gettime_nt(clock, &now);
|
||||
if (timespec_cmp(now, abs) >= 0) return 0;
|
||||
if (_check_interrupts(false, g_fds.p)) {
|
||||
if (rem) *rem = timespec_sub(abs, now);
|
||||
return -1;
|
||||
}
|
||||
SleepEx(MIN(__SIG_POLLING_INTERVAL_MS,
|
||||
timespec_tomillis(timespec_sub(abs, now))),
|
||||
false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/calls/struct/timespec.internal.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int sys_clock_nanosleep_openbsd(int clock, int flags,
|
||||
const struct timespec *req,
|
||||
struct timespec *rem) {
|
||||
int res;
|
||||
struct timespec now, rel;
|
||||
if (clock == CLOCK_REALTIME) {
|
||||
if (!flags) {
|
||||
res = sys_nanosleep(req, rem);
|
||||
} else {
|
||||
sys_clock_gettime(clock, &now);
|
||||
if (timespec_cmp(*req, now) > 0) {
|
||||
rel = timespec_sub(*req, now);
|
||||
res = sys_nanosleep(&rel, 0);
|
||||
} else {
|
||||
res = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
res = enotsup();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ Copyright 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 │
|
||||
@@ -16,21 +16,34 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/calls/struct/timespec.internal.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/calls/struct/timeval.internal.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/sysv/consts/timer.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int sys_utimes_nt(const char *path, const struct timeval tv[2]) {
|
||||
struct timespec ts[2];
|
||||
if (tv) {
|
||||
ts[0].tv_sec = tv[0].tv_sec;
|
||||
ts[0].tv_nsec = tv[0].tv_usec * 1000;
|
||||
ts[1].tv_sec = tv[1].tv_sec;
|
||||
ts[1].tv_nsec = tv[1].tv_usec * 1000;
|
||||
return sys_utimensat_nt(AT_FDCWD, path, ts, 0);
|
||||
int sys_clock_nanosleep_xnu(int clock, int flags, const struct timespec *req,
|
||||
struct timespec *rem) {
|
||||
int res;
|
||||
struct timeval now, abs, rel;
|
||||
if (clock == CLOCK_REALTIME) {
|
||||
if (flags & TIMER_ABSTIME) {
|
||||
abs = timespec_totimeval(*req);
|
||||
sys_gettimeofday_xnu(&now, 0, 0);
|
||||
if (timeval_cmp(abs, now) > 0) {
|
||||
rel = timeval_sub(abs, now);
|
||||
res = sys_select(0, 0, 0, 0, &rel);
|
||||
} else {
|
||||
res = 0;
|
||||
}
|
||||
} else {
|
||||
res = sys_nanosleep_xnu(req, rem);
|
||||
}
|
||||
} else {
|
||||
return sys_utimensat_nt(AT_FDCWD, path, NULL, 0);
|
||||
res = enotsup();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
/*-*- 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/asan.internal.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/calls/struct/timespec.internal.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/calls/struct/timeval.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/sysv/consts/timer.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
/**
|
||||
* Sleeps for particular amount of time.
|
||||
*
|
||||
* Here's how you could sleep for one second:
|
||||
*
|
||||
* clock_nanosleep(0, 0, &(struct timespec){1}, 0);
|
||||
*
|
||||
* Your sleep will be interrupted automatically if you do something like
|
||||
* press ctrl-c during the wait. That's an `EINTR` error and it lets you
|
||||
* immediately react to status changes. This is always the case, even if
|
||||
* you're using `SA_RESTART` since this is a `@norestart` system call.
|
||||
*
|
||||
* void OnCtrlC(int sig) {} // EINTR only happens after delivery
|
||||
* signal(SIGINT, OnCtrlC); // do delivery rather than kill proc
|
||||
* printf("save me from sleeping forever by pressing ctrl-c\n");
|
||||
* clock_nanosleep(0, 0, &(struct timespec){INT_MAX}, 0);
|
||||
* printf("you're my hero\n");
|
||||
*
|
||||
* If you want to perform an uninterruptible sleep without having to use
|
||||
* sigprocmask() to block all signals then this function provides a good
|
||||
* solution to that problem. For example:
|
||||
*
|
||||
* struct timespec rel, now, abs;
|
||||
* clock_gettime(CLOCK_REALTIME, &now);
|
||||
* rel = timespec_frommillis(100);
|
||||
* abs = timespec_add(now, rel);
|
||||
* while (clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &abs, 0));
|
||||
*
|
||||
* will accurately spin on `EINTR` errors. That way you're not impeding
|
||||
* signal delivery and you're not losing precision on your wait timeout.
|
||||
* This function has first-class support on Linux, FreeBSD, and NetBSD;
|
||||
* on OpenBSD it's good; on XNU it's bad; and on Windows it's ugly.
|
||||
*
|
||||
* @param clock should be `CLOCK_REALTIME` and you may consult the docs
|
||||
* of your preferred platforms to see what other clocks might work
|
||||
* @param flags can be 0 for relative and `TIMER_ABSTIME` for absolute
|
||||
* @param req can be a relative or absolute time, depending on `flags`
|
||||
* @param rem shall be updated with the remainder of unslept time when
|
||||
* (1) it's non-null; (2) `flags` is 0; and (3) -1 w/ `EINTR` is
|
||||
* returned; if this function returns 0 then `rem` is undefined;
|
||||
* if flags is `TIMER_ABSTIME` then `rem` is ignored
|
||||
* @return 0 on success, or errno on error
|
||||
* @raise EINTR when a signal got delivered while we were waiting
|
||||
* @raise ECANCELED if thread was cancelled in masked mode
|
||||
* @raise ENOTSUP if `clock` is known but we can't use it here
|
||||
* @raise EFAULT if `req` or null or bad memory was passed
|
||||
* @raise EINVAL if `clock` is unknown to current platform
|
||||
* @raise EINVAL if `flags` has an unrecognized value
|
||||
* @raise EINVAL if `req->tv_nsec ∉ [0,1000000000)`
|
||||
* @raise ENOSYS on bare metal
|
||||
* @cancellationpoint
|
||||
* @returnserrno
|
||||
* @norestart
|
||||
*/
|
||||
errno_t clock_nanosleep(int clock, int flags, const struct timespec *req,
|
||||
struct timespec *rem) {
|
||||
int rc, e = errno;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (!req || (IsAsan() && (!__asan_is_valid_timespec(req) ||
|
||||
(rem && !__asan_is_valid_timespec(rem))))) {
|
||||
rc = efault();
|
||||
} else if (clock == 127 || //
|
||||
(flags & ~TIMER_ABSTIME) || //
|
||||
req->tv_sec < 0 || //
|
||||
!(0 <= req->tv_nsec && req->tv_nsec <= 999999999)) {
|
||||
rc = einval();
|
||||
} else if (IsLinux() || IsFreebsd() || IsNetbsd()) {
|
||||
rc = sys_clock_nanosleep(clock, flags, req, rem);
|
||||
} else if (IsXnu()) {
|
||||
rc = sys_clock_nanosleep_xnu(clock, flags, req, rem);
|
||||
} else if (IsOpenbsd()) {
|
||||
rc = sys_clock_nanosleep_openbsd(clock, flags, req, rem);
|
||||
} else if (IsMetal()) {
|
||||
rc = enosys();
|
||||
} else {
|
||||
rc = sys_clock_nanosleep_nt(clock, flags, req, rem);
|
||||
}
|
||||
|
||||
if (rc == -1) {
|
||||
rc = errno;
|
||||
errno = e;
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
|
||||
#if SYSDEBUG
|
||||
if (__tls_enabled && !(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
|
||||
STRACE("clock_nanosleep(%s, %s, %s, [%s]) → %s", DescribeClockName(clock),
|
||||
DescribeSleepFlags(flags), DescribeTimespec(0, req),
|
||||
DescribeTimespec(rc, rem), DescribeErrnoResult(rc));
|
||||
}
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -18,15 +18,22 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/nt/enum/filetype.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
||||
textwindows int sys_close_nt(struct Fd *fd) {
|
||||
void sys_fcntl_nt_lock_cleanup(int) hidden;
|
||||
|
||||
textwindows int sys_close_nt(struct Fd *fd, int fildes) {
|
||||
int e;
|
||||
bool ok = true;
|
||||
|
||||
if (_weaken(sys_fcntl_nt_lock_cleanup)) {
|
||||
_weaken(sys_fcntl_nt_lock_cleanup)(fildes);
|
||||
}
|
||||
|
||||
if (fd->kind == kFdFile && ((fd->flags & O_ACCMODE) != O_RDONLY &&
|
||||
GetFileType(fd->handle) == kNtFileTypeDisk)) {
|
||||
// Like Linux, closing a file on Windows doesn't guarantee it's
|
||||
|
||||
+19
-11
@@ -16,10 +16,10 @@
|
||||
│ 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"
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
@@ -32,17 +32,25 @@
|
||||
/**
|
||||
* Closes file descriptor.
|
||||
*
|
||||
* This function may be used for file descriptors returned by functions
|
||||
* like open, socket, accept, epoll_create, and landlock_create_ruleset.
|
||||
* This function releases resources returned by functions such as:
|
||||
*
|
||||
* This function should never be called twice for the same file
|
||||
* descriptor, regardless of whether or not an error happened. However
|
||||
* that doesn't mean the error should be ignored.
|
||||
* - openat()
|
||||
* - socket()
|
||||
* - accept()
|
||||
* - epoll_create()
|
||||
* - landlock_create_ruleset()
|
||||
*
|
||||
* This function should never be reattempted if an error is returned;
|
||||
* however, that doesn't mean the error should be ignored. This goes
|
||||
* against the conventional wisdom of looping on `EINTR`.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @error EINTR means a signal was received while closing in which case
|
||||
* close() does not need to be called again, since the fd will close
|
||||
* in the background
|
||||
* @raise EINTR if signal was delivered; do *not* retry
|
||||
* @raise EBADF if `fd` is negative or not open; however, an exception
|
||||
* is made by Cosmopolitan Libc for `close(-1)` which returns zero
|
||||
* and does nothing, in order to assist with code that may wish to
|
||||
* close the same resource multiple times without dirtying `errno`
|
||||
* @raise EIO if a low-level i/o error occurred
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
@@ -51,7 +59,7 @@ int close(int fd) {
|
||||
if (fd == -1) {
|
||||
rc = 0;
|
||||
} else if (fd < 0) {
|
||||
rc = einval();
|
||||
rc = ebadf();
|
||||
} else {
|
||||
// for performance reasons we want to avoid holding __fds_lock()
|
||||
// while sys_close() is happening. this leaves the kernel / libc
|
||||
@@ -73,7 +81,7 @@ int close(int fd) {
|
||||
} else if (__isfdkind(fd, kFdFile) || //
|
||||
__isfdkind(fd, kFdConsole) || //
|
||||
__isfdkind(fd, kFdProcess)) { //
|
||||
rc = sys_close_nt(g_fds.p + fd);
|
||||
rc = sys_close_nt(g_fds.p + fd, fd);
|
||||
} else {
|
||||
rc = eio();
|
||||
}
|
||||
|
||||
+16
-16
@@ -27,35 +27,35 @@
|
||||
/**
|
||||
* Closes extra file descriptors, e.g.
|
||||
*
|
||||
* // close all non-stdio file descriptors
|
||||
* if (closefrom(3) == -1) {
|
||||
* for (int i = 3; i < 256; ++i) {
|
||||
* if (closefrom(3))
|
||||
* for (int i = 3; i < 256; ++i)
|
||||
* close(i);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @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
|
||||
* @raise EBADF if `first` is negative
|
||||
* @raise ENOSYS if not Linux 5.9+, FreeBSD 8+, OpenBSD, or NetBSD
|
||||
* @raise EBADF on OpenBSD if `first` is greater than highest fd
|
||||
* @raise EINVAL if flags are bad or first is greater than last
|
||||
* @raise EMFILE if a weird race condition happens on Linux
|
||||
* @raise ECANCELED if thread was cancelled in masked mode
|
||||
* @raise EINTR possibly on OpenBSD
|
||||
* @raise ENOMEM on Linux maybe
|
||||
*/
|
||||
int closefrom(int first) {
|
||||
int rc, err;
|
||||
if (IsNetbsd() || IsWindows() || IsMetal()) {
|
||||
rc = enosys();
|
||||
} else if (first < 0) {
|
||||
if (first < 0) {
|
||||
// consistent with openbsd
|
||||
// freebsd allows this but it's dangerous
|
||||
// necessary on linux due to type signature
|
||||
rc = ebadf();
|
||||
} else if (IsFreebsd() || IsOpenbsd()) {
|
||||
rc = sys_closefrom(first);
|
||||
} else if (IsLinux()) {
|
||||
rc = sys_close_range(first, 0xffffffffu, 0);
|
||||
} else if (IsNetbsd()) {
|
||||
rc = __sys_fcntl(first, 10 /*F_CLOSEM*/, first);
|
||||
} else {
|
||||
rc = sys_closefrom(first);
|
||||
rc = enosys();
|
||||
}
|
||||
STRACE("closefrom(%d) → %d% m", first, rc);
|
||||
return rc;
|
||||
|
||||
@@ -16,7 +16,10 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/blockcancel.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
@@ -38,6 +41,7 @@ static bool HasCopyFileRange(void) {
|
||||
bool ok;
|
||||
int e, rc;
|
||||
e = errno;
|
||||
BLOCK_CANCELLATIONS;
|
||||
if (IsLinux()) {
|
||||
// We modernize our detection by a few years for simplicity.
|
||||
// This system call is chosen since it's listed by pledge().
|
||||
@@ -48,6 +52,7 @@ static bool HasCopyFileRange(void) {
|
||||
} else {
|
||||
ok = false;
|
||||
}
|
||||
ALLOW_CANCELLATIONS;
|
||||
errno = e;
|
||||
return ok;
|
||||
}
|
||||
@@ -79,6 +84,8 @@ static void copy_file_range_init(void) {
|
||||
* @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 ENOTSUP if `infd` or `outfd` is a zip file descriptor
|
||||
* @raise ECANCELED if thread was cancelled in masked mode
|
||||
* @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
|
||||
@@ -91,12 +98,15 @@ static void copy_file_range_init(void) {
|
||||
* @raise EIO if a low-level i/o error happens
|
||||
* @see sendfile() for seekable → socket
|
||||
* @see splice() for fd ↔ pipe
|
||||
* @cancellationpoint
|
||||
*/
|
||||
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);
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (!g_copy_file_range.ok) {
|
||||
rc = enosys();
|
||||
} else if (IsAsan() && ((opt_in_out_inoffset &&
|
||||
@@ -104,10 +114,14 @@ ssize_t copy_file_range(int infd, int64_t *opt_in_out_inoffset, int outfd,
|
||||
(opt_in_out_outoffset &&
|
||||
!__asan_is_valid(opt_in_out_outoffset, 8)))) {
|
||||
rc = efault();
|
||||
} else if (__isfdkind(infd, kFdZip) || __isfdkind(outfd, kFdZip)) {
|
||||
rc = enotsup();
|
||||
} else {
|
||||
rc = sys_copy_file_range(infd, opt_in_out_inoffset, outfd,
|
||||
opt_in_out_outoffset, uptobytes, flags);
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
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);
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*-*- 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/blockcancel.internal.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/thread/posixthread.internal.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#ifdef MODE_DBG
|
||||
|
||||
int begin_cancellation_point(void) {
|
||||
int state = 0;
|
||||
struct CosmoTib *tib;
|
||||
struct PosixThread *pt;
|
||||
if (__enable_tls) {
|
||||
tib = __get_tls();
|
||||
if ((pt = (struct PosixThread *)tib->tib_pthread)) {
|
||||
state = pt->flags & PT_INCANCEL;
|
||||
pt->flags |= PT_INCANCEL;
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
void end_cancellation_point(int state) {
|
||||
struct CosmoTib *tib;
|
||||
struct PosixThread *pt;
|
||||
if (__enable_tls) {
|
||||
tib = __get_tls();
|
||||
if ((pt = (struct PosixThread *)tib->tib_pthread)) {
|
||||
pt->flags &= ~PT_INCANCEL;
|
||||
pt->flags |= state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void report_cancellation_point(void) {
|
||||
BLOCK_CANCELLATIONS;
|
||||
_bt("error: need BEGIN/END_CANCELLATION_POINT\n");
|
||||
ALLOW_CANCELLATIONS;
|
||||
}
|
||||
|
||||
#endif /* MODE_DBG */
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef COSMOPOLITAN_LIBC_CALLS_CP_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_CP_INTERNAL_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
int begin_cancellation_point(void);
|
||||
void end_cancellation_point(int);
|
||||
|
||||
#ifndef MODE_DBG
|
||||
#define BEGIN_CANCELLATION_POINT (void)0
|
||||
#define END_CANCELLATION_POINT (void)0
|
||||
#else
|
||||
#define BEGIN_CANCELLATION_POINT \
|
||||
do { \
|
||||
int _Cp; \
|
||||
_Cp = begin_cancellation_point()
|
||||
#define END_CANCELLATION_POINT \
|
||||
end_cancellation_point(_Cp); \
|
||||
} \
|
||||
while (0)
|
||||
#endif
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_CP_INTERNAL_H_ */
|
||||
+12
-10
@@ -21,20 +21,22 @@
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
||||
/**
|
||||
* Creates new file, returning open()'d file descriptor.
|
||||
* Creates file.
|
||||
*
|
||||
* This function is shorthand for:
|
||||
* This is equivalent to saying:
|
||||
*
|
||||
* open(file, O_CREAT | O_WRONLY | O_TRUNC, mode)
|
||||
* int fd = openat(AT_FDCWD, file, O_CREAT | O_WRONLY | O_TRUNC, mode);
|
||||
*
|
||||
* @param file is a UTF-8 string, which is truncated if it exists
|
||||
* @param mode is an octal user/group/other permission, e.g. 0755
|
||||
* @return a number registered with the system to track the open file,
|
||||
* which must be stored using a 64-bit type in order to support both
|
||||
* System V and Windows, and must be closed later on using close()
|
||||
* @see open(), touch()
|
||||
* @param file specifies filesystem path to create
|
||||
* @param mode is octal bits, e.g. 0644 usually
|
||||
* @return file descriptor, or -1 w/ errno
|
||||
* @see openat() for further documentation
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
* @threadsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
dontdiscard int creat(const char *file, uint32_t mode) {
|
||||
int creat(const char *file, uint32_t mode) {
|
||||
return openat(AT_FDCWD, file, O_CREAT | O_WRONLY | O_TRUNC, mode);
|
||||
}
|
||||
+14
-25
@@ -31,13 +31,11 @@
|
||||
// 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;
|
||||
_unassert(oldfd >= 0);
|
||||
_unassert(newfd >= -1);
|
||||
_unassert(!(flags & ~O_CLOEXEC));
|
||||
|
||||
__fds_lock();
|
||||
|
||||
if (oldfd >= g_fds.n ||
|
||||
if (!__isfdopen(oldfd) || newfd < -1 ||
|
||||
(g_fds.p[oldfd].kind != kFdFile && g_fds.p[oldfd].kind != kFdSocket &&
|
||||
g_fds.p[oldfd].kind != kFdConsole)) {
|
||||
__fds_unlock();
|
||||
@@ -45,27 +43,18 @@ textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
|
||||
}
|
||||
|
||||
// allocate a new file descriptor
|
||||
for (;;) {
|
||||
if (newfd == -1) {
|
||||
if ((newfd = __reservefd_unlocked(start)) == -1) {
|
||||
__fds_unlock();
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
if (__ensurefds_unlocked(newfd) == -1) {
|
||||
__fds_unlock();
|
||||
return -1;
|
||||
}
|
||||
if (g_fds.p[newfd].kind) {
|
||||
__fds_unlock();
|
||||
close(newfd);
|
||||
__fds_lock();
|
||||
}
|
||||
if (!g_fds.p[newfd].kind) {
|
||||
g_fds.p[newfd].kind = kFdReserved;
|
||||
break;
|
||||
}
|
||||
if (newfd == -1) {
|
||||
if ((newfd = __reservefd_unlocked(start)) == -1) {
|
||||
__fds_unlock();
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (__ensurefds_unlocked(newfd) == -1) {
|
||||
__fds_unlock();
|
||||
return -1;
|
||||
}
|
||||
if (g_fds.p[newfd].kind) {
|
||||
sys_close_nt(g_fds.p + newfd, newfd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +75,7 @@ textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
|
||||
}
|
||||
rc = newfd;
|
||||
} else {
|
||||
__releasefd_unlocked(newfd);
|
||||
__releasefd(newfd);
|
||||
rc = __winerr();
|
||||
}
|
||||
|
||||
|
||||
+4
-3
@@ -32,15 +32,16 @@
|
||||
*
|
||||
* @param fd remains open afterwards
|
||||
* @return some arbitrary new number for fd
|
||||
* @raise EOPNOTSUPP if zipos file
|
||||
* @raise EBADF if fd isn't open
|
||||
* @raise EPERM if pledge() is in play without stdio
|
||||
* @raise ENOTSUP if `fd` is a zip file descriptor
|
||||
* @raise EBADF if `fd` is negative or not open
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
int dup(int fd) {
|
||||
int rc;
|
||||
if (__isfdkind(fd, kFdZip)) {
|
||||
rc = eopnotsupp();
|
||||
rc = enotsup();
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_dup(fd);
|
||||
} else {
|
||||
|
||||
+7
-4
@@ -18,10 +18,10 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/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"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
@@ -38,16 +38,19 @@
|
||||
* @param newfd if already assigned, is silently closed beforehand;
|
||||
* unless it's equal to oldfd, in which case dup2() is a no-op
|
||||
* @return new file descriptor, or -1 w/ errno
|
||||
* @raise EBADF is oldfd isn't open
|
||||
* @raise EBADF is newfd negative or too big
|
||||
* @raise EPERM if pledge() is in play without stdio
|
||||
* @raise EMFILE if `RLIMIT_NOFILE` has been reached
|
||||
* @raise ENOTSUP if `oldfd` is on zip file system
|
||||
* @raise EINTR if a signal handler was called
|
||||
* @raise EBADF is `newfd` negative or too big
|
||||
* @raise EBADF is `oldfd` isn't open
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
int dup2(int oldfd, int newfd) {
|
||||
int rc;
|
||||
if (__isfdkind(oldfd, kFdZip)) {
|
||||
rc = eopnotsupp();
|
||||
rc = enotsup();
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_dup2(oldfd, newfd);
|
||||
} else if (newfd < 0) {
|
||||
|
||||
+7
-5
@@ -38,11 +38,13 @@
|
||||
* @param flags may have O_CLOEXEC which is needed to preserve the
|
||||
* close-on-execve() state after file descriptor duplication
|
||||
* @return newfd on success, or -1 w/ errno
|
||||
* @raise EINVAL if flags has unsupported bits
|
||||
* @raise EINVAL if newfd equals oldfd
|
||||
* @raise EBADF is oldfd isn't open
|
||||
* @raise EBADF is newfd negative or too big
|
||||
* @raise ENOTSUP if `oldfd` is a zip file descriptor
|
||||
* @raise EPERM if pledge() is in play without stdio
|
||||
* @raise EINVAL if `flags` has unsupported bits
|
||||
* @raise EINTR if a signal handler was called
|
||||
* @raise EBADF is `newfd` negative or too big
|
||||
* @raise EINVAL if `newfd` equals oldfd
|
||||
* @raise EBADF is `oldfd` isn't open
|
||||
* @see dup(), dup2()
|
||||
*/
|
||||
int dup3(int oldfd, int newfd, int flags) {
|
||||
@@ -52,7 +54,7 @@ int dup3(int oldfd, int newfd, int flags) {
|
||||
} else if (oldfd < 0 || newfd < 0) {
|
||||
rc = ebadf();
|
||||
} else if (__isfdkind(oldfd, kFdZip)) {
|
||||
rc = eopnotsupp();
|
||||
rc = enotsup();
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_dup3(oldfd, newfd, flags);
|
||||
} else {
|
||||
|
||||
@@ -99,7 +99,7 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
|
||||
startinfo.hStdError = __getfdhandleactual(2);
|
||||
|
||||
// spawn the process
|
||||
rc = ntspawn(program, argv, envp, 0, 0, 0, 1, 0, 0, &startinfo, &procinfo);
|
||||
rc = ntspawn(program, argv, envp, 0, 0, 0, true, 0, 0, &startinfo, &procinfo);
|
||||
if (rc == -1) {
|
||||
STRACE("panic: unrecoverable ntspawn(%#s) error: %m", program);
|
||||
__imp_ExitProcess(6543);
|
||||
|
||||
+37
-24
@@ -16,6 +16,8 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/blockcancel.internal.h"
|
||||
#include "libc/calls/blocksigs.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
@@ -39,12 +41,17 @@ static bool IsApeBinary(const char *path) {
|
||||
int fd;
|
||||
char buf[8];
|
||||
bool res = false;
|
||||
// TODO(jart): Should we block signals too?
|
||||
BLOCK_CANCELLATIONS;
|
||||
if ((fd = sys_open(path, O_RDONLY, 0)) != -1) {
|
||||
if (sys_read(fd, buf, 8) == 8 && READ64LE(buf) == READ64LE("MZqFpD='")) {
|
||||
if (sys_read(fd, buf, 8) == 8 && //
|
||||
(READ64LE(buf) == READ64LE("MZqFpD='") ||
|
||||
READ64LE(buf) == READ64LE("JTqFpD='"))) {
|
||||
res = true;
|
||||
}
|
||||
sys_close(fd);
|
||||
}
|
||||
ALLOW_CANCELLATIONS;
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -61,35 +68,41 @@ static const char *Join(const char *a, const char *b, char buf[PATH_MAX]) {
|
||||
}
|
||||
|
||||
int sys_execve(const char *prog, char *const argv[], char *const envp[]) {
|
||||
int e;
|
||||
size_t i;
|
||||
int e, rc;
|
||||
char *buf;
|
||||
char **shargs;
|
||||
const char *ape;
|
||||
e = errno;
|
||||
__sys_execve(prog, argv, envp);
|
||||
if (errno != ENOEXEC) return -1;
|
||||
for (i = 0; argv[i];) ++i;
|
||||
buf = alloca(PATH_MAX);
|
||||
shargs = alloca((i + 4) * sizeof(char *));
|
||||
if (IsApeBinary(prog) &&
|
||||
(CanExecute((ape = "/usr/bin/ape")) ||
|
||||
CanExecute((ape = Join(firstnonnull(getenv("TMPDIR"),
|
||||
firstnonnull(getenv("HOME"), ".")),
|
||||
".ape", buf))) ||
|
||||
CanExecute(
|
||||
(ape = Join(firstnonnull(getenv("HOME"), "."), ".ape", buf))))) {
|
||||
shargs[0] = ape;
|
||||
shargs[1] = "-";
|
||||
shargs[2] = prog;
|
||||
memcpy(shargs + 3, argv, (i + 1) * sizeof(char *));
|
||||
} else if (CanExecute(prog)) {
|
||||
shargs[0] = _PATH_BSHELL;
|
||||
shargs[1] = prog;
|
||||
memcpy(shargs + 2, argv + 1, i * sizeof(char *));
|
||||
if (errno == ENOEXEC) {
|
||||
for (i = 0; argv[i];) ++i;
|
||||
buf = alloca(PATH_MAX);
|
||||
shargs = alloca((i + 4) * sizeof(char *));
|
||||
if (IsApeBinary(prog) &&
|
||||
(CanExecute((ape = "/usr/bin/ape")) ||
|
||||
CanExecute((ape = Join(firstnonnull(getenv("TMPDIR"),
|
||||
firstnonnull(getenv("HOME"), ".")),
|
||||
".ape", buf))) ||
|
||||
CanExecute(
|
||||
(ape = Join(firstnonnull(getenv("HOME"), "."), ".ape", buf))))) {
|
||||
shargs[0] = ape;
|
||||
shargs[1] = "-";
|
||||
shargs[2] = prog;
|
||||
memcpy(shargs + 3, argv, (i + 1) * sizeof(char *));
|
||||
errno = e;
|
||||
rc = __sys_execve(shargs[0], shargs, envp);
|
||||
} else if (CanExecute(prog)) {
|
||||
shargs[0] = _PATH_BSHELL;
|
||||
shargs[1] = prog;
|
||||
memcpy(shargs + 2, argv + 1, i * sizeof(char *));
|
||||
errno = e;
|
||||
rc = __sys_execve(shargs[0], shargs, envp);
|
||||
} else {
|
||||
rc = enoexec();
|
||||
}
|
||||
} else {
|
||||
return enoexec();
|
||||
rc = -1;
|
||||
}
|
||||
errno = e;
|
||||
return __sys_execve(shargs[0], shargs, envp);
|
||||
return rc;
|
||||
}
|
||||
+10
-18
@@ -23,6 +23,7 @@
|
||||
#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/kprintf.h"
|
||||
#include "libc/intrin/likely.h"
|
||||
#include "libc/intrin/promises.internal.h"
|
||||
@@ -35,6 +36,10 @@
|
||||
/**
|
||||
* Replaces current process with program.
|
||||
*
|
||||
* On Windows, `argv` and `envp` can't contain binary strings. They need
|
||||
* to be valid UTF-8 in order to round-trip the WIN32 API, without being
|
||||
* corrupted.
|
||||
*
|
||||
* @param program will not be PATH searched, see commandv()
|
||||
* @param argv[0] is the name of the program to run
|
||||
* @param argv[1,n-2] optionally specify program arguments
|
||||
@@ -49,26 +54,13 @@ int execve(const char *prog, char *const argv[], char *const envp[]) {
|
||||
int rc;
|
||||
size_t i;
|
||||
if (!prog || !argv || !envp ||
|
||||
(IsAsan() &&
|
||||
(!__asan_is_valid(prog, 1) || !__asan_is_valid_strlist(argv) ||
|
||||
!__asan_is_valid_strlist(envp)))) {
|
||||
(IsAsan() && (!__asan_is_valid_str(prog) || //
|
||||
!__asan_is_valid_strlist(argv) || //
|
||||
!__asan_is_valid_strlist(envp)))) {
|
||||
rc = efault();
|
||||
} else {
|
||||
#ifdef SYSDEBUG
|
||||
if (UNLIKELY(__strace > 0)) {
|
||||
kprintf(STRACE_PROLOGUE "execve(%#s, {", prog);
|
||||
for (i = 0; argv[i]; ++i) {
|
||||
if (i) kprintf(", ");
|
||||
kprintf("%#s", argv[i]);
|
||||
}
|
||||
kprintf("}, {");
|
||||
for (i = 0; envp[i]; ++i) {
|
||||
if (i) kprintf(", ");
|
||||
kprintf("%#s", envp[i]);
|
||||
}
|
||||
kprintf("})\n");
|
||||
}
|
||||
#endif
|
||||
STRACE("execve(%#s, %s, %s) → ...", prog, DescribeStringList(argv),
|
||||
DescribeStringList(envp));
|
||||
if (!IsWindows()) {
|
||||
rc = 0;
|
||||
if (IsLinux() && __execpromises && _weaken(sys_pledge_linux)) {
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
int execvpe(const char *prog, char *const argv[], char *const *envp) {
|
||||
char *exe;
|
||||
char pathbuf[PATH_MAX];
|
||||
if (IsAsan() && !__asan_is_valid(prog, 1)) return efault();
|
||||
if (IsAsan() && !__asan_is_valid_str(prog)) return efault();
|
||||
if (!(exe = commandv(prog, pathbuf, sizeof(pathbuf)))) return -1;
|
||||
return execve(exe, argv, envp);
|
||||
}
|
||||
+22
-12
@@ -17,6 +17,7 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
@@ -35,33 +36,42 @@
|
||||
* @param dirfd is normally AT_FDCWD but if it's an open directory and
|
||||
* file is a relative path, then file is opened relative to dirfd
|
||||
* @param path is a filename or directory
|
||||
* @param mode can be R_OK, W_OK, X_OK, F_OK
|
||||
* @param flags can have AT_EACCESS, AT_SYMLINK_NOFOLLOW
|
||||
* @note on Linux flags is only supported on Linux 5.8+
|
||||
* @param amode can be `R_OK`, `W_OK`, `X_OK`, or `F_OK`
|
||||
* @param flags can have `AT_EACCESS` and/or `AT_SYMLINK_NOFOLLOW`
|
||||
* @return 0 if ok, or -1 and sets errno
|
||||
* @raise EINVAL if `mode` has bad value
|
||||
* @raise EPERM if pledge() is in play without rpath promise
|
||||
* @raise EACCES if access for requested `mode` would be denied
|
||||
* @raise ENOTDIR if a directory component in `path` exists as non-directory
|
||||
* @raise ENOENT if component of `path` doesn't exist or `path` is empty
|
||||
* @raise ENOTSUP if `path` is a zip file and `dirfd` isn't `AT_FDCWD`
|
||||
* @note on Linux `flags` is only supported on Linux 5.8+
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int faccessat(int dirfd, const char *path, int mode, uint32_t flags) {
|
||||
int faccessat(int dirfd, const char *path, int amode, int flags) {
|
||||
int e, rc;
|
||||
if (IsAsan() && !__asan_is_valid(path, 1)) {
|
||||
struct ZiposUri zipname;
|
||||
if (!path || (IsAsan() && !__asan_is_valid_str(path))) {
|
||||
rc = efault();
|
||||
} else if (_weaken(__zipos_notat) &&
|
||||
_weaken(__zipos_notat)(dirfd, path) == -1) {
|
||||
rc = -1; /* TODO(jart): implement me */
|
||||
} else if (__isfdkind(dirfd, kFdZip)) {
|
||||
rc = enotsup();
|
||||
} else if (_weaken(__zipos_open) &&
|
||||
_weaken(__zipos_parseuri)(path, &zipname) != -1) {
|
||||
rc = _weaken(__zipos_access)(&zipname, amode);
|
||||
} else if (!IsWindows()) {
|
||||
e = errno;
|
||||
if (!flags) goto NoFlags;
|
||||
if ((rc = sys_faccessat2(dirfd, path, mode, flags)) == -1) {
|
||||
if ((rc = sys_faccessat2(dirfd, path, amode, flags)) == -1) {
|
||||
if (errno == ENOSYS) {
|
||||
errno = e;
|
||||
NoFlags:
|
||||
rc = sys_faccessat(dirfd, path, mode, flags);
|
||||
rc = sys_faccessat(dirfd, path, amode, flags);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rc = sys_faccessat_nt(dirfd, path, mode, flags);
|
||||
rc = sys_faccessat_nt(dirfd, path, amode, flags);
|
||||
}
|
||||
STRACE("faccessat(%s, %#s, %#o, %#x) → %d% m", DescribeDirfd(dirfd), path,
|
||||
mode, flags, rc);
|
||||
amode, flags, rc);
|
||||
return rc;
|
||||
}
|
||||
@@ -37,17 +37,18 @@
|
||||
* @param path must exist
|
||||
* @param mode contains octal flags (base 8)
|
||||
* @param flags can have `AT_SYMLINK_NOFOLLOW`
|
||||
* @raise ENOTSUP if `dirfd` or `path` use zip file system
|
||||
* @errors ENOENT, ENOTDIR, ENOSYS
|
||||
* @asyncsignalsafe
|
||||
* @see fchmod()
|
||||
*/
|
||||
int fchmodat(int dirfd, const char *path, uint32_t mode, int flags) {
|
||||
int rc;
|
||||
if (IsAsan() && !__asan_is_valid(path, 1)) {
|
||||
if (IsAsan() && !__asan_is_valid_str(path)) {
|
||||
rc = efault();
|
||||
} else if (_weaken(__zipos_notat) &&
|
||||
(rc = __zipos_notat(dirfd, path)) == -1) {
|
||||
rc = eopnotsupp();
|
||||
rc = enotsup();
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_fchmodat(dirfd, path, mode, flags);
|
||||
} else {
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
* @param gid is group id, or -1 to not change
|
||||
* @param flags can have AT_SYMLINK_NOFOLLOW, etc.
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise ENOTSUP if `dirfd` or `path` use zip file system
|
||||
* @see chown(), lchown() for shorthand notation
|
||||
* @see /etc/passwd for user ids
|
||||
* @see /etc/group for group ids
|
||||
@@ -42,11 +43,11 @@
|
||||
int fchownat(int dirfd, const char *path, uint32_t uid, uint32_t gid,
|
||||
int flags) {
|
||||
int rc;
|
||||
if (IsAsan() && !__asan_is_valid(path, 1)) {
|
||||
if (IsAsan() && !__asan_is_valid_str(path)) {
|
||||
rc = efault();
|
||||
} else if (_weaken(__zipos_notat) &&
|
||||
(rc = __zipos_notat(dirfd, path)) == -1) {
|
||||
STRACE("zipos fchownat not supported yet");
|
||||
rc = enotsup();
|
||||
} else {
|
||||
rc = sys_fchownat(dirfd, path, uid, gid, flags);
|
||||
}
|
||||
|
||||
+223
-47
@@ -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/struct/fd.internal.h"
|
||||
@@ -24,65 +25,131 @@
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/calls/wincrash.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/kmalloc.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/enum/filelockflags.h"
|
||||
#include "libc/nt/errors.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/f.h"
|
||||
#include "libc/sysv/consts/fd.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
bool __force_sqlite_to_work_until_we_can_fix_it;
|
||||
struct FileLock {
|
||||
struct FileLock *next;
|
||||
int64_t off;
|
||||
int64_t len;
|
||||
int fd;
|
||||
bool exc;
|
||||
};
|
||||
|
||||
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);
|
||||
struct FileLocks {
|
||||
pthread_mutex_t mu;
|
||||
struct FileLock *list;
|
||||
struct FileLock *free;
|
||||
};
|
||||
|
||||
static struct FileLocks g_locks;
|
||||
|
||||
static textwindows struct FileLock *NewFileLock(void) {
|
||||
struct FileLock *fl;
|
||||
if (g_locks.free) {
|
||||
fl = g_locks.free;
|
||||
g_locks.free = fl->next;
|
||||
} else {
|
||||
fl = kmalloc(sizeof(*fl));
|
||||
}
|
||||
bzero(fl, sizeof(*fl));
|
||||
fl->next = g_locks.list;
|
||||
g_locks.list = fl;
|
||||
return fl;
|
||||
}
|
||||
|
||||
static textwindows int sys_fcntl_nt_lock(struct Fd *f, int cmd, uintptr_t arg) {
|
||||
static textwindows void FreeFileLock(struct FileLock *fl) {
|
||||
fl->next = g_locks.free;
|
||||
g_locks.free = fl;
|
||||
}
|
||||
|
||||
static textwindows bool OverlapsFileLock(struct FileLock *fl, int64_t off,
|
||||
int64_t len) {
|
||||
uint64_t BegA, EndA, BegB, EndB;
|
||||
BegA = off;
|
||||
EndA = off + (len - 1);
|
||||
BegB = fl->off;
|
||||
EndB = fl->off + (fl->len - 1);
|
||||
return MAX(BegA, BegB) < MIN(EndA, EndB);
|
||||
}
|
||||
|
||||
static textwindows bool EncompassesFileLock(struct FileLock *fl, int64_t off,
|
||||
int64_t len) {
|
||||
return off <= fl->off && fl->off + fl->len <= off + len;
|
||||
}
|
||||
|
||||
static textwindows bool EqualsFileLock(struct FileLock *fl, int64_t off,
|
||||
int64_t len) {
|
||||
return fl->off == off && off + len == fl->off + fl->len;
|
||||
}
|
||||
|
||||
hidden textwindows void sys_fcntl_nt_lock_cleanup(int fd) {
|
||||
struct FileLock *fl, *ft, **flp;
|
||||
pthread_mutex_lock(&g_locks.mu);
|
||||
for (flp = &g_locks.list, fl = *flp; fl;) {
|
||||
if (fl->fd == fd) {
|
||||
*flp = fl->next;
|
||||
ft = fl->next;
|
||||
FreeFileLock(fl);
|
||||
fl = ft;
|
||||
} else {
|
||||
flp = &fl->next;
|
||||
fl = *flp;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&g_locks.mu);
|
||||
}
|
||||
|
||||
static textwindows int sys_fcntl_nt_lock(struct Fd *f, int fd, int cmd,
|
||||
uintptr_t arg) {
|
||||
int e;
|
||||
struct flock *l;
|
||||
uint32_t flags, err;
|
||||
int64_t pos, off, len, size;
|
||||
struct NtByHandleFileInformation info;
|
||||
|
||||
if (!GetFileInformationByHandle(f->handle, &info)) {
|
||||
return __winerr();
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
if (!SetFilePointerEx(f->handle, 0, &pos, SEEK_CUR)) {
|
||||
return __winerr();
|
||||
}
|
||||
struct FileLock *fl, *ft, **flp;
|
||||
int64_t pos, off, len, end, size;
|
||||
|
||||
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;
|
||||
case SEEK_CUR:
|
||||
off = pos + off;
|
||||
pos = 0;
|
||||
if (SetFilePointerEx(f->handle, 0, &pos, SEEK_CUR)) {
|
||||
off = pos + off;
|
||||
} else {
|
||||
return __winerr();
|
||||
}
|
||||
break;
|
||||
case SEEK_END:
|
||||
off = size - off;
|
||||
off = INT64_MAX - off;
|
||||
break;
|
||||
default:
|
||||
return einval();
|
||||
}
|
||||
|
||||
if (!len) {
|
||||
len = size - off;
|
||||
len = INT64_MAX - off;
|
||||
}
|
||||
|
||||
if (off < 0 || len < 0) {
|
||||
if (off < 0 || len < 0 || __builtin_add_overflow(off, len, &end)) {
|
||||
return einval();
|
||||
}
|
||||
|
||||
@@ -91,8 +158,57 @@ static textwindows int sys_fcntl_nt_lock(struct Fd *f, int cmd, uintptr_t arg) {
|
||||
.Pointer = (void *)(uintptr_t)off};
|
||||
|
||||
if (l->l_type == F_RDLCK || l->l_type == F_WRLCK) {
|
||||
|
||||
if (cmd == F_SETLK || cmd == F_SETLKW) {
|
||||
// make it possible to transition read locks to write locks
|
||||
for (flp = &g_locks.list, fl = *flp; fl;) {
|
||||
if (fl->fd == fd) {
|
||||
if (EqualsFileLock(fl, off, len)) {
|
||||
if (fl->exc == l->l_type == F_WRLCK) {
|
||||
// we already have this lock
|
||||
return 0;
|
||||
} else {
|
||||
// unlock our read lock and acquire write lock below
|
||||
if (UnlockFileEx(f->handle, 0, len, len >> 32, &ov)) {
|
||||
*flp = fl->next;
|
||||
ft = fl->next;
|
||||
FreeFileLock(fl);
|
||||
fl = ft;
|
||||
continue;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
} else if (OverlapsFileLock(fl, off, len)) {
|
||||
return enotsup();
|
||||
}
|
||||
}
|
||||
flp = &fl->next;
|
||||
fl = *flp;
|
||||
}
|
||||
}
|
||||
|
||||
// return better information on conflicting locks if possible
|
||||
if (cmd == F_GETLK) {
|
||||
for (fl = g_locks.list; fl; fl = fl->next) {
|
||||
if (fl->fd == fd && //
|
||||
OverlapsFileLock(fl, off, len) &&
|
||||
(l->l_type == F_WRLCK || !fl->exc)) {
|
||||
l->l_whence = SEEK_SET;
|
||||
l->l_start = fl->off;
|
||||
l->l_len = fl->len;
|
||||
l->l_type == fl->exc ? F_WRLCK : F_RDLCK;
|
||||
l->l_pid = getpid();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flags = 0;
|
||||
if (cmd != F_SETLKW) {
|
||||
// TODO(jart): we should use expo backoff in wrapper function
|
||||
// should not matter since sqlite doesn't need it
|
||||
flags |= kNtLockfileFailImmediately;
|
||||
}
|
||||
if (l->l_type == F_WRLCK) {
|
||||
@@ -103,72 +219,132 @@ static textwindows int sys_fcntl_nt_lock(struct Fd *f, int cmd, uintptr_t arg) {
|
||||
if (ok) {
|
||||
l->l_type = F_UNLCK;
|
||||
if (!UnlockFileEx(f->handle, 0, len, len >> 32, &ov)) {
|
||||
notpossible;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
l->l_pid = -1;
|
||||
ok = true;
|
||||
}
|
||||
} else if (ok) {
|
||||
fl = NewFileLock();
|
||||
fl->off = off;
|
||||
fl->len = len;
|
||||
fl->exc = l->l_type == F_WRLCK;
|
||||
fl->fd = fd;
|
||||
}
|
||||
if (ok || __force_sqlite_to_work_until_we_can_fix_it) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
return ok ? 0 : -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;
|
||||
|
||||
// allow a big range to unlock many small ranges
|
||||
for (flp = &g_locks.list, fl = *flp; fl;) {
|
||||
if (fl->fd == fd && EncompassesFileLock(fl, off, len)) {
|
||||
struct NtOverlapped ov = {.hEvent = f->handle,
|
||||
.Pointer = (void *)(uintptr_t)fl->off};
|
||||
if (UnlockFileEx(f->handle, 0, fl->len, fl->len >> 32, &ov)) {
|
||||
*flp = fl->next;
|
||||
ft = fl->next;
|
||||
FreeFileLock(fl);
|
||||
fl = ft;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
flp = &fl->next;
|
||||
fl = *flp;
|
||||
}
|
||||
}
|
||||
|
||||
// win32 won't let us carve up existing locks
|
||||
int overlap_count = 0;
|
||||
for (fl = g_locks.list; fl; fl = fl->next) {
|
||||
if (fl->fd == fd && //
|
||||
OverlapsFileLock(fl, off, len)) {
|
||||
++overlap_count;
|
||||
}
|
||||
}
|
||||
|
||||
// try to handle the carving cases needed by sqlite
|
||||
if (overlap_count == 1) {
|
||||
for (fl = g_locks.list; fl; fl = fl->next) {
|
||||
if (fl->fd == fd && //
|
||||
off <= fl->off && //
|
||||
off + len >= fl->off && //
|
||||
off + len < fl->off + fl->len) {
|
||||
// cleave left side of lock
|
||||
struct NtOverlapped ov = {.hEvent = f->handle,
|
||||
.Pointer = (void *)(uintptr_t)fl->off};
|
||||
if (!UnlockFileEx(f->handle, 0, fl->len, fl->len >> 32, &ov)) {
|
||||
return -1;
|
||||
}
|
||||
fl->len = (fl->off + fl->len) - (off + len);
|
||||
fl->off = off + len;
|
||||
ov.Pointer = (void *)(uintptr_t)fl->off;
|
||||
if (!LockFileEx(f->handle, kNtLockfileExclusiveLock, 0, fl->len,
|
||||
fl->len >> 32, &ov)) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (overlap_count) {
|
||||
return enotsup();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return einval();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
textwindows int sys_fcntl_nt(int fd, int cmd, uintptr_t arg) {
|
||||
int rc;
|
||||
uint32_t flags;
|
||||
if (__isfdkind(fd, kFdFile) || __isfdkind(fd, kFdSocket)) {
|
||||
if (cmd == F_GETFL) {
|
||||
return g_fds.p[fd].flags &
|
||||
(O_ACCMODE | O_APPEND | O_ASYNC | O_DIRECT | O_NOATIME |
|
||||
O_NONBLOCK | O_RANDOM | O_SEQUENTIAL);
|
||||
rc = g_fds.p[fd].flags &
|
||||
(O_ACCMODE | O_APPEND | O_ASYNC | O_DIRECT | O_NOATIME | O_NONBLOCK |
|
||||
O_RANDOM | O_SEQUENTIAL);
|
||||
} else if (cmd == F_SETFL) {
|
||||
// O_APPEND doesn't appear to be tunable at cursory glance
|
||||
// O_NONBLOCK might require we start doing all i/o in threads
|
||||
// O_DSYNC / O_RSYNC / O_SYNC maybe if we fsync() everything
|
||||
// O_DIRECT | O_RANDOM | O_SEQUENTIAL | O_NDELAY possible but
|
||||
// not worth it.
|
||||
return einval();
|
||||
rc = enosys();
|
||||
} else if (cmd == F_GETFD) {
|
||||
if (g_fds.p[fd].flags & O_CLOEXEC) {
|
||||
return FD_CLOEXEC;
|
||||
rc = FD_CLOEXEC;
|
||||
} else {
|
||||
return 0;
|
||||
rc = 0;
|
||||
}
|
||||
} else if (cmd == F_SETFD) {
|
||||
if (arg & FD_CLOEXEC) {
|
||||
g_fds.p[fd].flags |= O_CLOEXEC;
|
||||
return FD_CLOEXEC;
|
||||
} else {
|
||||
g_fds.p[fd].flags &= ~O_CLOEXEC;
|
||||
return 0;
|
||||
}
|
||||
rc = 0;
|
||||
} else if (cmd == F_SETLK || cmd == F_SETLKW || cmd == F_GETLK) {
|
||||
return sys_fcntl_nt_lock(g_fds.p + fd, cmd, arg);
|
||||
pthread_mutex_lock(&g_locks.mu);
|
||||
rc = sys_fcntl_nt_lock(g_fds.p + fd, fd, cmd, arg);
|
||||
pthread_mutex_unlock(&g_locks.mu);
|
||||
} else if (cmd == F_DUPFD || cmd == F_DUPFD_CLOEXEC) {
|
||||
return sys_fcntl_nt_dupfd(fd, cmd, arg);
|
||||
rc = sys_fcntl_nt_dupfd(fd, cmd, arg);
|
||||
} else {
|
||||
return einval();
|
||||
rc = einval();
|
||||
}
|
||||
} else {
|
||||
return ebadf();
|
||||
rc = ebadf();
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int sys_fcntl(int fd, int cmd, uintptr_t arg) {
|
||||
int sys_fcntl(int fd, int cmd, uintptr_t arg, int impl(int, int, ...)) {
|
||||
int e, rc;
|
||||
bool islock;
|
||||
if ((islock = cmd == F_GETLK || //
|
||||
@@ -40,12 +40,12 @@ int sys_fcntl(int fd, int cmd, uintptr_t arg) {
|
||||
cosmo2flock(arg);
|
||||
}
|
||||
e = errno;
|
||||
rc = __sys_fcntl(fd, cmd, arg);
|
||||
rc = impl(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);
|
||||
rc = __fixupnewfd(impl(fd, F_DUPFD, arg), O_CLOEXEC);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
+107
-14
@@ -17,17 +17,22 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/flock.h"
|
||||
#include "libc/calls/struct/flock.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/sysv/consts/f.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
|
||||
/**
|
||||
* Does things with file descriptor, via re-imagined hourglass api, e.g.
|
||||
* Does things with file descriptor, e.g.
|
||||
*
|
||||
* CHECK_NE(-1, fcntl(fd, F_SETFD, FD_CLOEXEC));
|
||||
*
|
||||
@@ -37,16 +42,60 @@
|
||||
* 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, 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.
|
||||
* This function implements file record locking, which lets independent
|
||||
* processes (and on Linux 3.15+, threads too!) lock arbitrary ranges
|
||||
* associated with a file. See `test/libc/calls/lock_test.c` and other
|
||||
* locking related tests in that folder.
|
||||
*
|
||||
* Please be warned that locks currently do nothing on Windows since
|
||||
* figuring out how to polyfill them correctly is a work in progress.
|
||||
* On Windows, the Cosmopolitan Libc polyfill for POSIX advisory locks
|
||||
* only implements enough of its nuances to support SQLite's needs. Some
|
||||
* possibilities, e.g. punching holes in lock, will raise `ENOTSUP`.
|
||||
*
|
||||
* @param cmd can be F_{GET,SET}{FD,FL}, etc.
|
||||
* @param fd is the file descriptor
|
||||
* @param cmd can be one of:
|
||||
* - `F_GETFD` gets `FD_CLOEXEC` status of `fd
|
||||
* - `F_SETFD` sets `FD_CLOEXEC` status of `arg` file descriptor
|
||||
* - `F_GETFL` returns file descriptor status flags
|
||||
* - `F_SETFL` sets file descriptor status flags
|
||||
* - `F_DUPFD` is like dup() but `arg` is a minimum result, e.g. 3
|
||||
* - `F_DUPFD_CLOEXEC` ditto but sets `O_CLOEXEC` on returned fd
|
||||
* - `F_SETLK` for record locking where `arg` is `struct flock *`
|
||||
* - `F_SETLKW` ditto but waits for lock (SQLite avoids this)
|
||||
* - `F_GETLK` to retrieve information about a record lock
|
||||
* - `F_OFD_SETLK` for better non-blocking lock (Linux 3.15+ only)
|
||||
* - `F_OFD_SETLKW` for better blocking lock (Linux 3.15+ only)
|
||||
* - `F_OFD_GETLK` for better lock querying (Linux 3.15+ only)
|
||||
* - `F_FULLFSYNC` on MacOS for fsync() with release barrier
|
||||
* - `F_BARRIERFSYNC` on MacOS for fsync() with even more barriers
|
||||
* - `F_SETNOSIGPIPE` on MacOS and NetBSD to control `SIGPIPE`
|
||||
* - `F_GETNOSIGPIPE` on MacOS and NetBSD to control `SIGPIPE`
|
||||
* - `F_GETPATH` on MacOS and NetBSD where arg is `char[PATH_MAX]`
|
||||
* - `F_MAXFD` on NetBSD to get max open file descriptor
|
||||
* - `F_NOCACHE` on MacOS to toggle data caching
|
||||
* - `F_GETPIPE_SZ` on Linux to get pipe size
|
||||
* - `F_SETPIPE_SZ` on Linux to set pipe size
|
||||
* - `F_NOTIFY` raise `SIGIO` upon `fd` events in `arg` (Linux only)
|
||||
* - `DN_ACCESS` for file access
|
||||
* - `DN_MODIFY` for file modifications
|
||||
* - `DN_CREATE` for file creations
|
||||
* - `DN_DELETE` for file deletions
|
||||
* - `DN_RENAME` for file renames
|
||||
* - `DN_ATTRIB` for file attribute changes
|
||||
* - `DN_MULTISHOT` bitwise or for realtime signals (non-coalesced)
|
||||
* @param arg can be FD_CLOEXEC, etc. depending
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise EBADF if `fd` isn't a valid open file descriptor
|
||||
* @raise EINVAL if `cmd` is unknown or unsupported by os
|
||||
* @raise EINVAL if `cmd` is invalid or unsupported by os
|
||||
* @raise EPERM if pledge() is in play w/o `stdio` or `flock` promise
|
||||
* @raise ENOLCK if `F_SETLKW` would have exceeded `RLIMIT_LOCKS`
|
||||
* @raise EPERM if `cmd` is `F_SETOWN` and we weren't authorized
|
||||
* @raise ESRCH if `cmd` is `F_SETOWN` and process group not found
|
||||
* @raise ENOTSUP on Windows if locking operation isn't supported yet
|
||||
* @raise EDEADLK if `cmd` was `F_SETLKW` and waiting would deadlock
|
||||
* @raise EMFILE if `cmd` is `F_DUPFD` or `F_DUPFD_CLOEXEC` and
|
||||
* `RLIMIT_NOFILE` would be exceeded
|
||||
* @cancellationpoint when `cmd` is `F_SETLKW` or `F_OFD_SETLKW`
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
*/
|
||||
@@ -54,20 +103,64 @@ int fcntl(int fd, int cmd, ...) {
|
||||
int rc;
|
||||
va_list va;
|
||||
uintptr_t arg;
|
||||
|
||||
va_start(va, cmd);
|
||||
arg = va_arg(va, uintptr_t);
|
||||
va_end(va);
|
||||
|
||||
if (fd >= 0) {
|
||||
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
||||
rc = _weaken(__zipos_fcntl)(fd, cmd, arg);
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_fcntl(fd, cmd, arg);
|
||||
if (cmd >= 0) {
|
||||
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
||||
rc = _weaken(__zipos_fcntl)(fd, cmd, arg);
|
||||
} else if (!IsWindows()) {
|
||||
if (cmd == F_SETLKW || cmd == F_OFD_SETLKW) {
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
rc = sys_fcntl(fd, cmd, arg, __sys_fcntl_cp);
|
||||
END_CANCELLATION_POINT;
|
||||
} else {
|
||||
rc = sys_fcntl(fd, cmd, arg, __sys_fcntl);
|
||||
}
|
||||
} else {
|
||||
rc = sys_fcntl_nt(fd, cmd, arg);
|
||||
}
|
||||
} else {
|
||||
rc = sys_fcntl_nt(fd, cmd, arg);
|
||||
rc = einval();
|
||||
}
|
||||
} else {
|
||||
rc = einval();
|
||||
rc = ebadf();
|
||||
}
|
||||
STRACE("fcntl(%d, %d, %p) → %#x% m", fd, cmd, arg, rc);
|
||||
|
||||
#ifdef SYSDEBUG
|
||||
if (cmd == F_GETFD || //
|
||||
cmd == F_GETOWN || //
|
||||
cmd == F_FULLFSYNC || //
|
||||
cmd == F_BARRIERFSYNC || //
|
||||
cmd == F_MAXFD) {
|
||||
STRACE("fcntl(%d, %s) → %d% m", fd, DescribeFcntlCmd(cmd), rc);
|
||||
} else if (cmd == F_GETFL) {
|
||||
STRACE("fcntl(%d, %s) → %s% m", fd, DescribeFcntlCmd(cmd),
|
||||
DescribeOpenFlags(rc));
|
||||
} else if (cmd == F_SETLK || //
|
||||
cmd == F_SETLKW || //
|
||||
cmd == F_GETLK || //
|
||||
((SupportsLinux() || SupportsXnu()) && //
|
||||
cmd != -1 && //
|
||||
(cmd == F_OFD_SETLK || //
|
||||
cmd == F_OFD_SETLKW || //
|
||||
cmd == F_OFD_GETLK))) {
|
||||
STRACE("fcntl(%d, %s, %s) → %d% m", fd, DescribeFcntlCmd(cmd),
|
||||
DescribeFlock(cmd, (struct flock *)arg), rc);
|
||||
} else if ((SupportsNetbsd() || SupportsXnu()) && cmd != -1 &&
|
||||
cmd == F_GETPATH) {
|
||||
STRACE("fcntl(%d, %s, [%s]) → %d% m", fd, DescribeFcntlCmd(cmd),
|
||||
!rc ? (const char *)arg : "n/a", rc);
|
||||
} else if (SupportsLinux() && cmd != -1 && cmd == F_NOTIFY) {
|
||||
STRACE("fcntl(%d, %s, %s) → %d% m", fd, DescribeFcntlCmd(cmd),
|
||||
DescribeDnotifyFlags(arg), rc);
|
||||
} else {
|
||||
STRACE("fcntl(%d, %s, %ld) → %#x% m", fd, DescribeFcntlCmd(cmd), arg, rc);
|
||||
}
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -23,5 +23,6 @@
|
||||
textwindows int sys_fdatasync_nt(int fd) {
|
||||
// TODO(jart): what should we do with worker pipes?
|
||||
if (!__isfdkind(fd, kFdFile)) return ebadf();
|
||||
if (_check_interrupts(false, 0)) return -1;
|
||||
return FlushFileBuffers(g_fds.p[fd].handle) ? 0 : -1;
|
||||
}
|
||||
+11
-3
@@ -17,10 +17,12 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/struct/stat.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/runtime/runtime.h"
|
||||
|
||||
/**
|
||||
@@ -29,20 +31,26 @@
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @see sync(), fsync(), sync_file_range()
|
||||
* @see __nosync to secretly disable
|
||||
* @raise ECANCELED if thread was cancelled in masked mode
|
||||
* @raise EINTR if signal was delivered
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int fdatasync(int fd) {
|
||||
int rc;
|
||||
struct stat st;
|
||||
if (__nosync != 0x5453455454534146) {
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
if (!IsWindows()) {
|
||||
rc = sys_fdatasync(fd);
|
||||
} else {
|
||||
rc = sys_fdatasync_nt(fd);
|
||||
}
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("fdatasync(%d) → %d% m", fd, rc);
|
||||
} else {
|
||||
rc = 0;
|
||||
STRACE("fdatasync(%d) → disabled% m", fd);
|
||||
rc = fstat(fd, &st);
|
||||
STRACE("fdatasync_fake(%d) → %d% m", fd, rc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*-*- 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/syscall-sysv.internal.h"
|
||||
#include "libc/dce.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/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int sys_fexecve(int, char *const[], char *const[]);
|
||||
|
||||
/**
|
||||
* Executes binary executable at file descriptor.
|
||||
*
|
||||
* This is only supported on Linux and FreeBSD. APE binaries currently
|
||||
* aren't supported.
|
||||
*
|
||||
* @param fd is opened executable and current file position is ignored
|
||||
* @return doesn't return on success, otherwise -1 w/ errno
|
||||
* @raise ENOEXEC if file at `fd` isn't an assimilated ELF executable
|
||||
* @raise ENOSYS on Windows, XNU, OpenBSD, NetBSD, and Metal
|
||||
*/
|
||||
int fexecve(int fd, char *const argv[], char *const envp[]) {
|
||||
int rc;
|
||||
size_t i;
|
||||
if (!argv || !envp ||
|
||||
(IsAsan() &&
|
||||
(!__asan_is_valid_strlist(argv) || !__asan_is_valid_strlist(envp)))) {
|
||||
rc = efault();
|
||||
} else {
|
||||
STRACE("fexecve(%d, %s, %s) → ...", fd, DescribeStringList(argv),
|
||||
DescribeStringList(envp));
|
||||
if (IsLinux()) {
|
||||
char path[14 + 12];
|
||||
FormatInt32(stpcpy(path, "/proc/self/fd/"), fd);
|
||||
rc = __sys_execve(path, argv, envp);
|
||||
} else if (IsFreebsd()) {
|
||||
rc = sys_fexecve(fd, argv, envp);
|
||||
} else {
|
||||
rc = enosys();
|
||||
}
|
||||
}
|
||||
STRACE("fexecve(%d) failed %d% m", fd, rc);
|
||||
return rc;
|
||||
}
|
||||
@@ -51,7 +51,7 @@ bool fileexists(const char *path) {
|
||||
struct ZiposUri zipname;
|
||||
uint16_t path16[PATH_MAX];
|
||||
e = errno;
|
||||
if (IsAsan() && !__asan_is_valid(path, 1)) {
|
||||
if (IsAsan() && !__asan_is_valid_str(path)) {
|
||||
efault();
|
||||
res = false;
|
||||
} else if (_weaken(__zipos_open) &&
|
||||
|
||||
+7
-1
@@ -17,10 +17,11 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/cp.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"
|
||||
|
||||
/**
|
||||
* Acquires lock on file.
|
||||
@@ -30,15 +31,20 @@
|
||||
* @param op can have LOCK_{SH,EX,NB,UN} for shared, exclusive,
|
||||
* non-blocking, and unlocking
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
* @restartable
|
||||
*/
|
||||
int flock(int fd, int op) {
|
||||
int rc;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (!IsWindows()) {
|
||||
rc = sys_flock(fd, op);
|
||||
} else {
|
||||
rc = sys_flock_nt(fd, op);
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("flock(%d, %d) → %d% m", fd, op, rc);
|
||||
return rc;
|
||||
}
|
||||
@@ -31,7 +31,7 @@ int32_t sys_fstatat(int32_t dirfd, const char *path, struct stat *st,
|
||||
int rc;
|
||||
void *p;
|
||||
union metastat ms;
|
||||
if (IsAsan() && !__asan_is_valid(path, 1)) return efault();
|
||||
if (IsAsan() && !__asan_is_valid_str(path)) return efault();
|
||||
if (IsLinux()) {
|
||||
_Static_assert(sizeof(*st) == sizeof(ms.linux), "assumption broken");
|
||||
if (IsAsan() && (st && !__asan_is_valid(st, sizeof(*st)))) return efault();
|
||||
|
||||
@@ -17,22 +17,26 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/struct/statfs-meta.internal.h"
|
||||
#include "libc/calls/struct/statfs.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Returns information about filesystem.
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
*/
|
||||
int fstatfs(int fd, struct statfs *sf) {
|
||||
int rc;
|
||||
union statfs_meta m;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
CheckLargeStackAllocation(&m, sizeof(m));
|
||||
|
||||
if (!IsWindows()) {
|
||||
if ((rc = sys_fstatfs(fd, &m)) != -1) {
|
||||
statfs2cosmo(sf, &m);
|
||||
@@ -42,6 +46,8 @@ int fstatfs(int fd, struct statfs *sf) {
|
||||
} else {
|
||||
rc = ebadf();
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("fstatfs(%d, [%s]) → %d% m", fd, DescribeStatfs(rc, sf));
|
||||
return rc;
|
||||
}
|
||||
+11
-3
@@ -17,32 +17,40 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/struct/stat.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/runtime/runtime.h"
|
||||
|
||||
/**
|
||||
* Blocks until kernel flushes buffers for fd to disk.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise ECANCELED if thread was cancelled in masked mode
|
||||
* @raise EINTR if signal was delivered
|
||||
* @see fdatasync(), sync_file_range()
|
||||
* @see __nosync to secretly disable
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int fsync(int fd) {
|
||||
int rc;
|
||||
struct stat st;
|
||||
if (__nosync != 0x5453455454534146) {
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
if (!IsWindows()) {
|
||||
rc = sys_fsync(fd);
|
||||
} else {
|
||||
rc = sys_fdatasync_nt(fd);
|
||||
}
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("fysnc(%d) → %d% m", fd, rc);
|
||||
} else {
|
||||
rc = 0;
|
||||
STRACE("fsync(%d) → disabled% m", fd);
|
||||
rc = fstat(fd, &st);
|
||||
STRACE("fsync_fake(%d) → %d% m", fd, rc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -16,9 +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/syscall_support-nt.internal.h"
|
||||
#include "libc/nt/enum/filemovemethod.h"
|
||||
#include "libc/nt/errors.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int sys_ftruncate_nt(int64_t handle, uint64_t length) {
|
||||
@@ -28,7 +31,13 @@ textwindows int sys_ftruncate_nt(int64_t handle, uint64_t length) {
|
||||
if ((ok = SetFilePointerEx(handle, 0, &tell, kNtFileCurrent))) {
|
||||
ok = SetFilePointerEx(handle, length, NULL, kNtFileBegin) &&
|
||||
SetEndOfFile(handle);
|
||||
SetFilePointerEx(handle, tell, NULL, kNtFileBegin);
|
||||
_npassert(SetFilePointerEx(handle, tell, NULL, kNtFileBegin));
|
||||
}
|
||||
if (ok) {
|
||||
return 0;
|
||||
} else if (GetLastError() == kNtErrorAccessDenied) {
|
||||
return einval(); // ftruncate() doesn't raise EACCES
|
||||
} else {
|
||||
return __winerr();
|
||||
}
|
||||
return ok ? 0 : __winerr();
|
||||
}
|
||||
+48
-8
@@ -17,33 +17,73 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/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"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Changes size of file.
|
||||
* Changes size of open file.
|
||||
*
|
||||
* If the file size is increased, the extended area shall appear as if
|
||||
* it were zero-filled. If your file size is decreased, the extra data
|
||||
* shall be lost.
|
||||
*
|
||||
* This function never changes the file position. This is true even if
|
||||
* ftruncate() causes the position to become beyond the end of file in
|
||||
* which case, the rules described in the lseek() documentation apply.
|
||||
*
|
||||
* Some operating systems implement an optimization, where `length` is
|
||||
* treated as a logical size and the requested physical space won't be
|
||||
* allocated until non-zero values get written into it. Our tests show
|
||||
* this happens on Linux (usually with 4096 byte granularity), FreeBSD
|
||||
* (which favors 512-byte granularity), and MacOS (prefers 4096 bytes)
|
||||
* however Windows, OpenBSD, and NetBSD always reserve physical space.
|
||||
* This may be inspected using fstat() and consulting stat::st_blocks.
|
||||
*
|
||||
* @param fd must be open for writing
|
||||
* @param length may be greater than current current file size, in which
|
||||
* case System V guarantees it'll be zero'd but Windows NT doesn't;
|
||||
* since the prior extends logically and the latter physically
|
||||
* @param length may be greater than current current file size
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise EINVAL if `length` is negative
|
||||
* @raise EINTR if signal was delivered instead
|
||||
* @raise ECANCELED if thread was cancelled in masked mode
|
||||
* @raise EIO if a low-level i/o error happened
|
||||
* @raise EFBIG or EINVAL if `length` is too huge
|
||||
* @raise ENOTSUP if `fd` is a zip file descriptor
|
||||
* @raise EBADF if `fd` isn't an open file descriptor
|
||||
* @raise EINVAL if `fd` is a non-file, e.g. pipe, socket
|
||||
* @raise EINVAL if `fd` wasn't opened in a writeable mode
|
||||
* @raise ENOSYS on bare metal
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
*/
|
||||
int ftruncate(int fd, int64_t length) {
|
||||
int rc;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (fd < 0) {
|
||||
rc = einval();
|
||||
rc = ebadf();
|
||||
} else if (__isfdkind(fd, kFdZip)) {
|
||||
rc = enotsup();
|
||||
} else if (IsMetal()) {
|
||||
rc = enosys();
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_ftruncate(fd, length, length);
|
||||
} else {
|
||||
if (fd >= g_fds.n) rc = ebadf();
|
||||
if (IsNetbsd() && rc == -1 && errno == ENOSPC) {
|
||||
errno = EFBIG; // POSIX doesn't specify ENOSPC for ftruncate()
|
||||
}
|
||||
} else if (__isfdopen(fd)) {
|
||||
rc = sys_ftruncate_nt(g_fds.p[fd].handle, length);
|
||||
} else {
|
||||
rc = ebadf();
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("ftruncate(%d, %'ld) → %d% m", fd, length, rc);
|
||||
return rc;
|
||||
}
|
||||
+25
-5
@@ -16,16 +16,36 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/calls/struct/timespec.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Sets atime/mtime on file descriptor.
|
||||
* Changes access/modified time on open file, the modern way.
|
||||
*
|
||||
* This function is the same as `utimensat(fd, 0, ts, 0)`.
|
||||
* XNU only has microsecond (1e-6) accuracy. Windows only has
|
||||
* hectonanosecond (1e-7) accuracy. RHEL5 (Linux c. 2007) doesn't
|
||||
* support this system call.
|
||||
*
|
||||
* @param ts is atime/mtime, or null for current time
|
||||
* @raise ENOSYS on RHEL5
|
||||
* @param fd is file descriptor of file whose timestamps will change
|
||||
* @param ts is {access, modified} timestamps, or null for current time
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise ENOTSUP if `fd` is on the zip filesystem
|
||||
* @raise EINVAL if `flags` had an unrecognized value
|
||||
* @raise EPERM if pledge() is in play without `fattr` promise
|
||||
* @raise EINVAL if `ts` specifies a nanosecond value that's out of range
|
||||
* @raise EBADF if `fd` isn't an open file descriptor
|
||||
* @raise EFAULT if `ts` memory was invalid
|
||||
* @raise ENOSYS on RHEL5 or bare metal
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
*/
|
||||
int futimens(int fd, const struct timespec ts[2]) {
|
||||
return utimensat(fd, 0, ts, 0);
|
||||
int rc;
|
||||
rc = __utimens(fd, 0, ts, 0);
|
||||
STRACE("futimens(%d, {%s, %s}) → %d% m", fd, DescribeTimespec(0, ts),
|
||||
DescribeTimespec(0, ts ? ts + 1 : 0), rc);
|
||||
return rc;
|
||||
}
|
||||
@@ -16,62 +16,45 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/asan.internal.h"
|
||||
#include "libc/calls/struct/itimerval.internal.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/calls/struct/timespec.internal.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
forceinline int Identity(int c) {
|
||||
return c;
|
||||
}
|
||||
|
||||
forceinline int ToUpper(int c) {
|
||||
return 'a' <= c && c <= 'z' ? c - ('a' - 'A') : c;
|
||||
}
|
||||
|
||||
forceinline char *GetEnv(const char *s, int xlat(int)) {
|
||||
char **p;
|
||||
size_t i, j;
|
||||
if ((p = environ)) {
|
||||
for (i = 0; p[i]; ++i) {
|
||||
for (j = 0;; ++j) {
|
||||
if (!s[j]) {
|
||||
if (p[i][j] == '=') {
|
||||
return p[i] + j + 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (xlat(s[j]) != xlat(p[i][j])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Returns value of environment variable, or NULL if not found.
|
||||
* Sets atime/mtime on file descriptor.
|
||||
*
|
||||
* Environment variables can store empty string on Unix but not Windows.
|
||||
*
|
||||
* @note should not be used after __cxa_finalize() is called
|
||||
* @param ts is atime/mtime, or null for current time
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise ENOTSUP if `fd` is on zip filesystem
|
||||
* @raise EBADF if `fd` isn't an open file descriptor
|
||||
* @raise EPERM if pledge() is in play without `fattr` promise
|
||||
* @raise EINVAL if `tv` specifies a microsecond value that's out of range
|
||||
* @raise ENOSYS on RHEL5 or bare metal
|
||||
* @see futimens() for modern version
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
*/
|
||||
char *getenv(const char *s) {
|
||||
char *r;
|
||||
if (!s) return 0;
|
||||
if (!IsWindows()) {
|
||||
r = GetEnv(s, Identity);
|
||||
int futimes(int fd, const struct timeval tv[2]) {
|
||||
int rc;
|
||||
struct timespec ts[2];
|
||||
|
||||
if (tv) {
|
||||
ts[0].tv_sec = tv[0].tv_sec;
|
||||
ts[0].tv_nsec = tv[0].tv_usec * 1000;
|
||||
ts[1].tv_sec = tv[1].tv_sec;
|
||||
ts[1].tv_nsec = tv[1].tv_usec * 1000;
|
||||
rc = __utimens(fd, 0, ts, 0);
|
||||
} else {
|
||||
r = GetEnv(s, ToUpper);
|
||||
rc = __utimens(fd, 0, 0, 0);
|
||||
}
|
||||
#if SYSDEBUG
|
||||
if (!(s[0] == 'T' && s[1] == 'Z' && !s[2])) {
|
||||
// TODO(jart): memoize TZ or something
|
||||
STRACE("getenv(%#s) → %#s", s, r);
|
||||
}
|
||||
#endif
|
||||
return r;
|
||||
|
||||
STRACE("futimes(%d, {%s, %s}) → %d% m", fd, DescribeTimeval(0, tv),
|
||||
DescribeTimeval(0, tv ? tv + 1 : 0), rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -19,7 +19,5 @@
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
// TODO(jart): These should be _Thread_local but doing that currently
|
||||
// causes a regression with runitd.com on Windows.
|
||||
unsigned __sighandrvas[NSIG];
|
||||
unsigned __sighandflags[NSIG];
|
||||
@@ -34,7 +34,7 @@
|
||||
#define HW_NCPUONLINE_NETBSD 16
|
||||
#define ALL_PROCESSOR_GROUPS 0xffff
|
||||
|
||||
static unsigned GetCpuCountLinux(void) {
|
||||
static unsigned _getcpucount_linux(void) {
|
||||
cpu_set_t s = {0};
|
||||
if (sys_sched_getaffinity(0, sizeof(s), &s) != -1) {
|
||||
return CPU_COUNT(&s);
|
||||
@@ -43,7 +43,7 @@ static unsigned GetCpuCountLinux(void) {
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned GetCpuCountBsd(void) {
|
||||
static unsigned _getcpucount_bsd(void) {
|
||||
size_t n;
|
||||
int c, cmd[2];
|
||||
n = sizeof(c);
|
||||
@@ -62,12 +62,12 @@ static unsigned GetCpuCountBsd(void) {
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned GetCpuCountImpl(void) {
|
||||
static unsigned _getcpucount_impl(void) {
|
||||
if (!IsWindows()) {
|
||||
if (!IsBsd()) {
|
||||
return GetCpuCountLinux();
|
||||
return _getcpucount_linux();
|
||||
} else {
|
||||
return GetCpuCountBsd();
|
||||
return _getcpucount_bsd();
|
||||
}
|
||||
} else {
|
||||
return GetMaximumProcessorCount(ALL_PROCESSOR_GROUPS);
|
||||
@@ -77,18 +77,24 @@ static unsigned GetCpuCountImpl(void) {
|
||||
static int g_cpucount;
|
||||
|
||||
// precompute because process affinity on linux may change later
|
||||
__attribute__((__constructor__)) static void init(void) {
|
||||
g_cpucount = GetCpuCountImpl();
|
||||
__attribute__((__constructor__)) static void _getcpucount_init(void) {
|
||||
g_cpucount = _getcpucount_impl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of CPUs in system.
|
||||
*
|
||||
* This is the same as the standard interface:
|
||||
*
|
||||
* sysconf(_SC_NPROCESSORS_ONLN);
|
||||
*
|
||||
* Except this function isn't a bloated diamond dependency.
|
||||
*
|
||||
* On Intel systems with HyperThreading this will return the number of
|
||||
* cores multiplied by two.
|
||||
*
|
||||
* @return cpu count or 0 if it couldn't be determined
|
||||
*/
|
||||
unsigned GetCpuCount(void) {
|
||||
unsigned _getcpucount(void) {
|
||||
return g_cpucount;
|
||||
}
|
||||
@@ -42,7 +42,7 @@ char *sys_getcwd_xnu(char *res, size_t size) {
|
||||
int fd;
|
||||
union metastat st[2];
|
||||
char buf[XNU_MAXPATHLEN], *ret = NULL;
|
||||
if ((fd = sys_openat(AT_FDCWD, ".", O_RDONLY | O_DIRECTORY, 0)) != -1) {
|
||||
if ((fd = __sys_openat_nc(AT_FDCWD, ".", O_RDONLY | O_DIRECTORY, 0)) != -1) {
|
||||
if (__sys_fstat(fd, &st[0]) != -1) {
|
||||
if (st[0].xnu.st_dev && st[0].xnu.st_ino) {
|
||||
if (__sys_fcntl(fd, XNU_F_GETPATH, (uintptr_t)buf) != -1) {
|
||||
|
||||
@@ -52,7 +52,7 @@ char *getcwd(char *buf, size_t size) {
|
||||
return 0;
|
||||
}
|
||||
} else if (_weaken(malloc)) {
|
||||
assert(!__vforked);
|
||||
_unassert(!__vforked);
|
||||
if (!size) size = PATH_MAX;
|
||||
if (!(p = _weaken(malloc)(size))) {
|
||||
STRACE("getcwd(%p, %'zu) %m", buf, size);
|
||||
|
||||
@@ -16,13 +16,14 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
void __releasefd_unlocked(int fd) {
|
||||
if (0 <= fd && fd < g_fds.n) {
|
||||
bzero(g_fds.p + fd, sizeof(*g_fds.p));
|
||||
g_fds.f = MIN(fd, g_fds.f);
|
||||
}
|
||||
/**
|
||||
* Gets file descriptor table size.
|
||||
*
|
||||
* @return current limit on the number of open files per process
|
||||
*/
|
||||
int getdtablesize(void) {
|
||||
return g_fds.n;
|
||||
}
|
||||
Loaded 100 of 1553 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user