diff --git a/.gitattributes b/.gitattributes index 77bb8d060..fa3e12742 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,4 @@ # -*- conf -*- *.gz binary /build/bootstrap/*.com binary -/build/bootstrap/*.com binary /usr/share/zoneinfo/* binary diff --git a/Makefile b/Makefile index 66c2dbb77..4bea2a572 100644 --- a/Makefile +++ b/Makefile @@ -73,9 +73,38 @@ MODE := $(m) endif endif +UNAME_M = $(shell uname -m) +UNAME_S = $(shell uname -s) + +# apple still distributes a 17 year old version of gnu make +ifeq ($(MAKE_VERSION), 3.81) +$(error please use build/bootstrap/make.com) +endif + +# provide instructions to non-linux users on unbundling gcc +ifeq ($(TOOLCHAIN),) # if TOOLCHAIN isn't defined +ifeq ("$(wildcard o/third_party/gcc/bin/x86_64-linux-cosmo-*)","") # if our gcc isn't unbundled +ifneq ($(UNAME_M)-$(UNAME_S), x86_64-Linux) # if this is not amd64 linux +$(error you need to download https://justine.lol/cosmocc-0.0.12.zip and unzip it inside the cosmo directory) +endif +endif +endif + +# the default build modes is empty string +# on x86_64 hosts, MODE= is the same as MODE=x86_64 +# on aarch64 hosts, MODE= is changed to MODE=aarch64 +ifeq ($(MODE),) +ifeq ($(UNAME_M),arm64) +MODE := aarch64 +endif +ifeq ($(UNAME_M),aarch64) +MODE := aarch64 +endif +endif + +# primary build rules all: o o: o/$(MODE) - o/$(MODE): \ o/$(MODE)/ape \ o/$(MODE)/dsp \ @@ -86,18 +115,23 @@ o/$(MODE): \ o/$(MODE)/examples \ o/$(MODE)/third_party +# check if we're using o//third_party/make/make.com +# we added sandboxing to guarantee cosmo's makefile is hermetic +# it also shaves away 200ms of startup latency with native $(uniq) ifneq ($(LANDLOCKMAKE_VERSION),) +ifeq ($(UNAME_S),Linux) ifeq ($(wildcard /usr/bin/ape),) $(warning please run ape/apeinstall.sh if you intend to use landlock make) $(shell sleep .5) endif +endif ifeq ($(USE_SYSTEM_TOOLCHAIN),) .STRICT = 1 endif endif -.PLEDGE = stdio rpath wpath cpath fattr proc -.UNVEIL = \ +.PLEDGE += stdio rpath wpath cpath fattr proc +.UNVEIL += \ libc/integral \ libc/stdbool.h \ libc/disclaimer.inc \ diff --git a/bin/aarch64-unknown-cosmo-addr2line b/bin/aarch64-unknown-cosmo-addr2line index d85555b40..0db247007 100755 --- a/bin/aarch64-unknown-cosmo-addr2line +++ b/bin/aarch64-unknown-cosmo-addr2line @@ -1,9 +1,15 @@ #!/bin/sh - MODE=${MODE:-${m:-aarch64}} COSMO=${COSMO:-/opt/cosmo} COSMOS=${COSMOS:-/opt/cosmos/aarch64} -TOOL="$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-addr2line" + +if [ -x "$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-gcc" ]; then + BRAND=musl +else + BRAND=cosmo +fi + +TOOL="$COSMO/o/third_party/gcc/bin/aarch64-linux-$BRAND-addr2line" if [ ! -x "$TOOL" ]; then echo "$0: you need to run: aarch64-unknown-cosmo-cc --update" >&2 diff --git a/bin/aarch64-unknown-cosmo-ar b/bin/aarch64-unknown-cosmo-ar index 79a86a39e..cf683311d 100755 --- a/bin/aarch64-unknown-cosmo-ar +++ b/bin/aarch64-unknown-cosmo-ar @@ -1,5 +1,4 @@ #!/bin/sh - PROG=${0##*/} MODE=${MODE:-${m:-aarch64}} COSMO=${COSMO:-/opt/cosmo} @@ -9,8 +8,14 @@ fatal_error() { exit 1 } -if [ ! -x "$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-ar" ]; then +if [ -x "$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-gcc" ]; then + BRAND=musl +else + BRAND=cosmo +fi + +if [ ! -x "$COSMO/o/third_party/gcc/bin/aarch64-linux-$BRAND-ar" ]; then fatal_error "you need to run: aarch64-unknown-cosmo-cc --update" fi -exec "$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-ar" "$@" +exec "$COSMO/o/third_party/gcc/bin/aarch64-linux-$BRAND-ar" "$@" diff --git a/bin/aarch64-unknown-cosmo-as b/bin/aarch64-unknown-cosmo-as index ecc114d9b..8ce97fd5f 100755 --- a/bin/aarch64-unknown-cosmo-as +++ b/bin/aarch64-unknown-cosmo-as @@ -1,9 +1,15 @@ #!/bin/sh - MODE=${MODE:-${m:-aarch64}} COSMO=${COSMO:-/opt/cosmo} COSMOS=${COSMOS:-/opt/cosmos/aarch64} -TOOL="$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-as" + +if [ -x "$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-gcc" ]; then + BRAND=musl +else + BRAND=cosmo +fi + +TOOL="$COSMO/o/third_party/gcc/bin/aarch64-linux-$BRAND-as" if [ ! -x "$TOOL" ]; then echo "$0: you need to run: aarch64-unknown-cosmo-cc --update" >&2 diff --git a/bin/aarch64-unknown-cosmo-nm b/bin/aarch64-unknown-cosmo-nm index bd25f1b79..fb51833e1 100755 --- a/bin/aarch64-unknown-cosmo-nm +++ b/bin/aarch64-unknown-cosmo-nm @@ -1,9 +1,15 @@ #!/bin/sh - MODE=${MODE:-${m:-aarch64}} COSMO=${COSMO:-/opt/cosmo} COSMOS=${COSMOS:-/opt/cosmos/aarch64} -TOOL="$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-nm" + +if [ -x "$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-gcc" ]; then + BRAND=musl +else + BRAND=cosmo +fi + +TOOL="$COSMO/o/third_party/gcc/bin/aarch64-linux-$BRAND-nm" if [ ! -x "$TOOL" ]; then echo "$0: you need to run: aarch64-unknown-cosmo-cc --update" >&2 diff --git a/bin/aarch64-unknown-cosmo-objcopy b/bin/aarch64-unknown-cosmo-objcopy index f561cd9af..f9de8f3f6 100755 --- a/bin/aarch64-unknown-cosmo-objcopy +++ b/bin/aarch64-unknown-cosmo-objcopy @@ -1,9 +1,15 @@ #!/bin/sh - MODE=${MODE:-${m:-aarch64}} COSMO=${COSMO:-/opt/cosmo} COSMOS=${COSMOS:-/opt/cosmos/aarch64} -TOOL="$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-objcopy" + +if [ -x "$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-gcc" ]; then + BRAND=musl +else + BRAND=cosmo +fi + +TOOL="$COSMO/o/third_party/gcc/bin/aarch64-linux-$BRAND-objcopy" if [ ! -x "$TOOL" ]; then echo "$0: you need to run: aarch64-unknown-cosmo-cc --update" >&2 diff --git a/bin/aarch64-unknown-cosmo-objdump b/bin/aarch64-unknown-cosmo-objdump index 274bc8c4d..1429f137f 100755 --- a/bin/aarch64-unknown-cosmo-objdump +++ b/bin/aarch64-unknown-cosmo-objdump @@ -1,9 +1,15 @@ #!/bin/sh - MODE=${MODE:-${m:-aarch64}} COSMO=${COSMO:-/opt/cosmo} COSMOS=${COSMOS:-/opt/cosmos/aarch64} -TOOL="$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-objdump" + +if [ -x "$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-gcc" ]; then + BRAND=musl +else + BRAND=cosmo +fi + +TOOL="$COSMO/o/third_party/gcc/bin/aarch64-linux-$BRAND-objdump" if [ ! -x "$TOOL" ]; then echo "$0: you need to run: aarch64-unknown-cosmo-cc --update" >&2 diff --git a/bin/aarch64-unknown-cosmo-strip b/bin/aarch64-unknown-cosmo-strip index 4c1c8e7e5..a2cfd3377 100755 --- a/bin/aarch64-unknown-cosmo-strip +++ b/bin/aarch64-unknown-cosmo-strip @@ -1,9 +1,15 @@ #!/bin/sh - MODE=${MODE:-${m:-aarch64}} COSMO=${COSMO:-/opt/cosmo} COSMOS=${COSMOS:-/opt/cosmos/aarch64} -TOOL="$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-strip" + +if [ -x "$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-gcc" ]; then + BRAND=musl +else + BRAND=cosmo +fi + +TOOL="$COSMO/o/third_party/gcc/bin/aarch64-linux-$BRAND-strip" if [ ! -x "$TOOL" ]; then echo "$0: you need to run: aarch64-unknown-cosmo-cc --update" >&2 diff --git a/bin/apecopy b/bin/apecopy index 98d6eb549..8f2d80f0f 100755 --- a/bin/apecopy +++ b/bin/apecopy @@ -1,5 +1,4 @@ #!/bin/sh - PROG=${0##*/} COSMO=${COSMO:-/opt/cosmo} @@ -67,8 +66,14 @@ if [ ! -d "$COSMO" ]; then fatal_error "you need to clone cosmopolitan to your $COSMO directory" fi +if [ -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc" ]; then + BRAND=musl +else + BRAND=cosmo +fi + if [ ! -f "$COSMO/o//tool/build/zipcopy.com" ] || - [ ! -f "$COSMO/o/third_party/gcc/bin/$ARCH-linux-musl-objcopy" ]; then + [ ! -f "$COSMO/o/third_party/gcc/bin/$ARCH-linux-$BRAND-objcopy" ]; then if [ $CROSS -eq 0 ]; then fatal_error "you need to run: cosmocc --update" else @@ -88,7 +93,7 @@ elif [ x"$INPUT" = x"$OUTPUT" ]; then fatal_error "$INPUT: input and output file can't be the same" fi -"$COSMO/o/third_party/gcc/bin/$ARCH-linux-musl-objcopy" \ +"$COSMO/o/third_party/gcc/bin/$ARCH-linux-$BRAND-objcopy" \ $OBJCOPYFLAGS \ "$INPUT" \ "$OUTPUT" || exit diff --git a/bin/cosmoaddr2line b/bin/cosmoaddr2line index 07d8bc886..85b8d85bf 100755 --- a/bin/cosmoaddr2line +++ b/bin/cosmoaddr2line @@ -1,15 +1,31 @@ #!/bin/sh +COSMO=${COSMO:-/opt/cosmo} + set -- -apifCe "$@" if [ -n "$ADDR2LINE" ]; then exec "$ADDR2LINE" "$@" fi -COSMO=${COSMO:-/opt/cosmo} +find_addr2line() { + if [ -x o/third_party/gcc/bin/$1-linux-cosmo-addr2line ]; then + ADDR2LINE=o/third_party/gcc/bin/$1-linux-cosmo-addr2line + elif [ -x o/third_party/gcc/bin/$1-linux-musl-addr2line ]; then + ADDR2LINE=o/third_party/gcc/bin/$1-linux-musl-addr2line + elif [ -x "$COSMO/o/third_party/gcc/bin/$1-linux-cosmo-addr2line" ]; then + ADDR2LINE="$COSMO/o/third_party/gcc/bin/$1-linux-cosmo-addr2line" + elif [ -x "$COSMO/o/third_party/gcc/bin/$1-linux-musl-addr2line" ]; then + ADDR2LINE="$COSMO/o/third_party/gcc/bin/$1-linux-musl-addr2line" + else + echo "error: toolchain not found (try running 'cosmocc --update' or 'make' in the cosmo monorepo)" >&2 + exit 1 + fi +} + for ARCH in x86_64 aarch64; do - o/third_party/gcc/bin/$ARCH-linux-musl-addr2line "$@" 2>/dev/null && exit - "$COSMO/o/third_party/gcc/bin/$ARCH-linux-musl-addr2line" "$@" 2>/dev/null && exit + find_addr2line $ARCH + "$ADDR2LINE" "$@" 2>/dev/null && exit done -echo please set the ADDR2LINE environment variable >&2 +echo "error: addr2line failed" >&2 exit 1 diff --git a/bin/cosmocc b/bin/cosmocc index eecc99756..5604cdf69 100755 --- a/bin/cosmocc +++ b/bin/cosmocc @@ -138,13 +138,19 @@ else COSMOS=${COSMOS:-/opt/cosmos/$ARCH} fi -CC="$COSMO/o/third_party/gcc/bin/$ARCH-linux-musl-gcc" +if [ -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc" ]; then + BRAND=musl +else + BRAND=cosmo +fi + +CC="$COSMO/o/third_party/gcc/bin/$ARCH-linux-$BRAND-gcc" CRT="$COSMO/o/$MODE/libc/crt/crt.o" LDLIBS="$COSMO/o/$MODE/cosmopolitan.a" CPPFLAGS="$CPPFLAGS -isystem $COSMOS/include -isystem $COSMO/libc/isystem" LDFLAGS="$LDFLAGS -L$COSMOS/lib" if [ x"$PROG" != x"${PROG%++}" ]; then - CC="$COSMO/o/third_party/gcc/bin/$ARCH-linux-musl-g++" + CC="$COSMO/o/third_party/gcc/bin/$ARCH-linux-$BRAND-g++" CFLAGS="$CFLAGS -fno-rtti -fno-exceptions -fuse-cxa-atexit" LDLIBS="$COSMO/o/$MODE/third_party/libcxx/libcxx.a $LDLIBS" fi @@ -360,7 +366,7 @@ if [ -n "$OUTPUT" ] && [ -f "$OUTPUT" ]; then # -> foo.com (ape) # -> foo.com.dbg (elf) mv -f "$OUTPUT" "$OUTPUT.dbg" || exit - "$COSMO/o/third_party/gcc/bin/$ARCH-linux-musl-objcopy" \ + "$COSMO/o/third_party/gcc/bin/$ARCH-linux-$BRAND-objcopy" \ $OBJCOPYFLAGS \ "$OUTPUT.dbg" \ "$OUTPUT" || exit @@ -368,7 +374,7 @@ if [ -n "$OUTPUT" ] && [ -f "$OUTPUT" ]; then "$OUTPUT.dbg" \ "$OUTPUT" || exit elif [ $SFLAG -eq 1 ]; then - "$COSMO/o/third_party/gcc/bin/$ARCH-linux-musl-strip" \ + "$COSMO/o/third_party/gcc/bin/$ARCH-linux-$BRAND-strip" \ "$OUTPUT" || exit fi fi diff --git a/bin/fatcosmoar b/bin/fatcosmoar index f08d9a399..6d4f9698a 100755 --- a/bin/fatcosmoar +++ b/bin/fatcosmoar @@ -1,5 +1,4 @@ #!/bin/sh - PROG=${0##*/} MODE=${MODE:-$m} COSMO=${COSMO:-/opt/cosmo} @@ -9,12 +8,18 @@ fatal_error() { exit 1 } -if [ ! -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-ar" ]; then +if [ -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc" ]; then + BRAND=musl +else + BRAND=cosmo +fi + +if [ ! -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-$BRAND-ar" ]; then fatal_error "you need to run: fatcosmocc --update" fi -AR_X86_64="$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-ar" -AR_AARCH64="$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-ar" +AR_X86_64="$COSMO/o/third_party/gcc/bin/x86_64-linux-$BRAND-ar" +AR_AARCH64="$COSMO/o/third_party/gcc/bin/aarch64-linux-$BRAND-ar" if [ "$1" = "--version" ]; then # note: only the underlying gnu compiler binaries are gpl # our shell script is released with the isc license diff --git a/bin/fatcosmocc b/bin/fatcosmocc index e229b2609..ca7e9a9bf 100755 --- a/bin/fatcosmocc +++ b/bin/fatcosmocc @@ -182,6 +182,12 @@ if [ ! -f "$COSMOS/lib/libc.a" ] || exit 1 fi +if [ -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc" ]; then + BRAND=musl +else + BRAND=cosmo +fi + FIXUPOBJ="$COSMO/o//tool/build/fixupobj.com" TEMP_FILES= SAVE_TEMPS=0 @@ -371,11 +377,11 @@ if [ x"$OPT" != x"-Os" ] && [ x"$MODE" != x"tiny" ]; then CFLAGS="$CFLAGS -fno-optimize-sibling-calls -mno-omit-leaf-frame-pointer" fi -CC_X86_64="$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc" -CC_AARCH64="$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-gcc" +CC_X86_64="$COSMO/o/third_party/gcc/bin/x86_64-linux-$BRAND-gcc" +CC_AARCH64="$COSMO/o/third_party/gcc/bin/aarch64-linux-$BRAND-gcc" if [ x"$PROG" != x"${PROG%++}" ]; then - CC_X86_64="$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-g++" - CC_AARCH64="$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-g++" + CC_X86_64="$COSMO/o/third_party/gcc/bin/x86_64-linux-$BRAND-g++" + CC_AARCH64="$COSMO/o/third_party/gcc/bin/aarch64-linux-$BRAND-g++" CFLAGS="$CFLAGS -fno-rtti -fno-exceptions -fuse-cxa-atexit" fi diff --git a/bin/x86_64-unknown-cosmo-addr2line b/bin/x86_64-unknown-cosmo-addr2line index 59bbad431..0b2b06950 100755 --- a/bin/x86_64-unknown-cosmo-addr2line +++ b/bin/x86_64-unknown-cosmo-addr2line @@ -1,9 +1,15 @@ #!/bin/sh - MODE=${MODE:-$m} COSMO=${COSMO:-/opt/cosmo} COSMOS=${COSMOS:-/opt/cosmos} -TOOL="$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-addr2line" + +if [ -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc" ]; then + BRAND=musl +else + BRAND=cosmo +fi + +TOOL="$COSMO/o/third_party/gcc/bin/x86_64-linux-$BRAND-addr2line" if [ ! -x "$TOOL" ]; then echo "$0: you need to run: x86_64-unknown-cosmo-cc --update" >&2 diff --git a/bin/x86_64-unknown-cosmo-ar b/bin/x86_64-unknown-cosmo-ar index dee1394bb..118b519aa 100755 --- a/bin/x86_64-unknown-cosmo-ar +++ b/bin/x86_64-unknown-cosmo-ar @@ -9,8 +9,14 @@ fatal_error() { exit 1 } -if [ ! -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-ar" ]; then +if [ -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc" ]; then + BRAND=musl +else + BRAND=cosmo +fi + +if [ ! -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-$BRAND-ar" ]; then fatal_error "you need to run: x86_64-unknown-cosmo-cc --update" fi -exec "$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-ar" "$@" +exec "$COSMO/o/third_party/gcc/bin/x86_64-linux-$BRAND-ar" "$@" diff --git a/bin/x86_64-unknown-cosmo-as b/bin/x86_64-unknown-cosmo-as index cacf0d6e9..470a711b2 100755 --- a/bin/x86_64-unknown-cosmo-as +++ b/bin/x86_64-unknown-cosmo-as @@ -1,9 +1,15 @@ #!/bin/sh - MODE=${MODE:-$m} COSMO=${COSMO:-/opt/cosmo} COSMOS=${COSMOS:-/opt/cosmos} -TOOL="$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-as" + +if [ -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc" ]; then + BRAND=musl +else + BRAND=cosmo +fi + +TOOL="$COSMO/o/third_party/gcc/bin/x86_64-linux-$BRAND-as" if [ ! -x "$TOOL" ]; then echo "$0: you need to run: x86_64-unknown-cosmo-cc --update" >&2 diff --git a/bin/x86_64-unknown-cosmo-nm b/bin/x86_64-unknown-cosmo-nm index 679370e60..b425f4a36 100755 --- a/bin/x86_64-unknown-cosmo-nm +++ b/bin/x86_64-unknown-cosmo-nm @@ -1,9 +1,15 @@ #!/bin/sh - MODE=${MODE:-$m} COSMO=${COSMO:-/opt/cosmo} COSMOS=${COSMOS:-/opt/cosmos} -TOOL="$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-nm" + +if [ -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc" ]; then + BRAND=musl +else + BRAND=cosmo +fi + +TOOL="$COSMO/o/third_party/gcc/bin/x86_64-linux-$BRAND-nm" if [ ! -x "$TOOL" ]; then echo "$0: you need to run: x86_64-unknown-cosmo-cc --update" >&2 diff --git a/bin/x86_64-unknown-cosmo-objcopy b/bin/x86_64-unknown-cosmo-objcopy index 9ec84bee4..90b764510 100755 --- a/bin/x86_64-unknown-cosmo-objcopy +++ b/bin/x86_64-unknown-cosmo-objcopy @@ -1,9 +1,15 @@ #!/bin/sh - MODE=${MODE:-$m} COSMO=${COSMO:-/opt/cosmo} COSMOS=${COSMOS:-/opt/cosmos} -TOOL="$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-objcopy" + +if [ -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc" ]; then + BRAND=musl +else + BRAND=cosmo +fi + +TOOL="$COSMO/o/third_party/gcc/bin/x86_64-linux-$BRAND-objcopy" if [ ! -x "$TOOL" ]; then echo "$0: you need to run: x86_64-unknown-cosmo-cc --update" >&2 diff --git a/bin/x86_64-unknown-cosmo-objdump b/bin/x86_64-unknown-cosmo-objdump index da25e9926..4c27d4881 100755 --- a/bin/x86_64-unknown-cosmo-objdump +++ b/bin/x86_64-unknown-cosmo-objdump @@ -1,9 +1,15 @@ #!/bin/sh - MODE=${MODE:-$m} COSMO=${COSMO:-/opt/cosmo} COSMOS=${COSMOS:-/opt/cosmos} -TOOL="$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-objdump" + +if [ -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc" ]; then + BRAND=musl +else + BRAND=cosmo +fi + +TOOL="$COSMO/o/third_party/gcc/bin/x86_64-linux-$BRAND-objdump" if [ ! -x "$TOOL" ]; then echo "$0: you need to run: x86_64-unknown-cosmo-cc --update" >&2 diff --git a/bin/x86_64-unknown-cosmo-strip b/bin/x86_64-unknown-cosmo-strip index e9dd34ec6..34647e5d9 100755 --- a/bin/x86_64-unknown-cosmo-strip +++ b/bin/x86_64-unknown-cosmo-strip @@ -1,9 +1,15 @@ #!/bin/sh - MODE=${MODE:-$m} COSMO=${COSMO:-/opt/cosmo} COSMOS=${COSMOS:-/opt/cosmos} -TOOL="$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-strip" + +if [ -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc" ]; then + BRAND=musl +else + BRAND=cosmo +fi + +TOOL="$COSMO/o/third_party/gcc/bin/x86_64-linux-$BRAND-strip" if [ ! -x "$TOOL" ]; then echo "$0: you need to run: x86_64-unknown-cosmo-cc --update" >&2 diff --git a/build/bootstrap/ar.com b/build/bootstrap/ar.com index f5bfc395b..c7ba5aadf 100755 Binary files a/build/bootstrap/ar.com and b/build/bootstrap/ar.com differ diff --git a/build/bootstrap/cocmd.com b/build/bootstrap/cocmd.com index d61b3d12b..021a5543b 100755 Binary files a/build/bootstrap/cocmd.com and b/build/bootstrap/cocmd.com differ diff --git a/build/bootstrap/compile.com b/build/bootstrap/compile.com index d1eaa1a3b..023ebe3f9 100755 Binary files a/build/bootstrap/compile.com and b/build/bootstrap/compile.com differ diff --git a/build/bootstrap/cp.com b/build/bootstrap/cp.com index dc2c6f8d9..78848be2e 100755 Binary files a/build/bootstrap/cp.com and b/build/bootstrap/cp.com differ diff --git a/build/bootstrap/fixupobj.com b/build/bootstrap/fixupobj.com index fdf9f2719..5162a2bad 100755 Binary files a/build/bootstrap/fixupobj.com and b/build/bootstrap/fixupobj.com differ diff --git a/build/bootstrap/gzip.com b/build/bootstrap/gzip.com index 667d7369b..56bd4e409 100755 Binary files a/build/bootstrap/gzip.com and b/build/bootstrap/gzip.com differ diff --git a/build/bootstrap/make.com b/build/bootstrap/make.com index c9c8beb6c..347ca03d5 100755 Binary files a/build/bootstrap/make.com and b/build/bootstrap/make.com differ diff --git a/build/bootstrap/mkdeps.com b/build/bootstrap/mkdeps.com index 7fc162ae7..c406e1271 100755 Binary files a/build/bootstrap/mkdeps.com and b/build/bootstrap/mkdeps.com differ diff --git a/build/bootstrap/mkdir.com b/build/bootstrap/mkdir.com index f972be18c..5268fa76d 100755 Binary files a/build/bootstrap/mkdir.com and b/build/bootstrap/mkdir.com differ diff --git a/build/bootstrap/objbincopy.com b/build/bootstrap/objbincopy.com index 7b995000f..584783679 100755 Binary files a/build/bootstrap/objbincopy.com and b/build/bootstrap/objbincopy.com differ diff --git a/build/bootstrap/package.com b/build/bootstrap/package.com index b2cb8f00a..6fe200ea7 100755 Binary files a/build/bootstrap/package.com and b/build/bootstrap/package.com differ diff --git a/build/bootstrap/pwd.com b/build/bootstrap/pwd.com index e0dd91a20..6e43ae548 100755 Binary files a/build/bootstrap/pwd.com and b/build/bootstrap/pwd.com differ diff --git a/build/bootstrap/rm.com b/build/bootstrap/rm.com index 7d4b51a4a..2bf9c048f 100755 Binary files a/build/bootstrap/rm.com and b/build/bootstrap/rm.com differ diff --git a/build/bootstrap/touch.com b/build/bootstrap/touch.com index 724bc2ae7..70ea97a1c 100755 Binary files a/build/bootstrap/touch.com and b/build/bootstrap/touch.com differ diff --git a/build/bootstrap/unbundle.com b/build/bootstrap/unbundle.com index 0cb05dc6e..4147431cc 100755 Binary files a/build/bootstrap/unbundle.com and b/build/bootstrap/unbundle.com differ diff --git a/build/bootstrap/zipcopy.com b/build/bootstrap/zipcopy.com index a448c6cf8..e4c199230 100755 Binary files a/build/bootstrap/zipcopy.com and b/build/bootstrap/zipcopy.com differ diff --git a/build/bootstrap/zipobj.com b/build/bootstrap/zipobj.com index 9b2bbd30f..7efcc73db 100755 Binary files a/build/bootstrap/zipobj.com and b/build/bootstrap/zipobj.com differ diff --git a/build/config.mk b/build/config.mk index f36b6bb87..7d73d10f9 100644 --- a/build/config.mk +++ b/build/config.mk @@ -16,6 +16,12 @@ CONFIG_CCFLAGS += -O2 $(BACKTRACES) CONFIG_CPPFLAGS += -DSYSDEBUG TARGET_ARCH ?= -msse3 endif +ifeq ($(MODE), x86_64) +ENABLE_FTRACE = 1 +CONFIG_OFLAGS ?= -g +CONFIG_CCFLAGS += -O2 $(BACKTRACES) +CONFIG_CPPFLAGS += -DSYSDEBUG +endif ifeq ($(MODE), aarch64) ENABLE_FTRACE = 1 CONFIG_OFLAGS ?= -g @@ -39,8 +45,8 @@ CONFIG_CPPFLAGS += -DSYSDEBUG endif ifeq ($(MODE), aarch64-zero) CONFIG_OFLAGS ?= -g -OVERRIDE_CFLAGS += -O0 -OVERRIDE_CXXFLAGS += -O0 +OVERRIDE_CFLAGS += -O0 -fdce +OVERRIDE_CXXFLAGS += -O0 -fdce CONFIG_CPPFLAGS += -DSYSDEBUG endif @@ -166,7 +172,7 @@ ifeq ($(MODE), aarch64-dbg) ENABLE_FTRACE = 1 CONFIG_OFLAGS ?= -g CONFIG_CPPFLAGS += -DMODE_DBG -D__SANITIZE_UNDEFINED__ -CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG -O0 -fno-inline +CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG -O0 -fno-inline -fdce CONFIG_COPTS += -fsanitize=undefined QUOTA ?= -C64 -L300 endif diff --git a/build/definitions.mk b/build/definitions.mk index f4b5341d7..751cbb5e6 100644 --- a/build/definitions.mk +++ b/build/definitions.mk @@ -94,17 +94,24 @@ endif ifeq ($(PREFIX),) ifeq ($(USE_SYSTEM_TOOLCHAIN),) -ifneq ("$(wildcard o/third_party/gcc/bin/x86_64-pc-linux-gnu-*)","") -PREFIX = o/third_party/gcc/bin/x86_64-pc-linux-gnu- +ifeq ($(ARCH),x86_64) +ifneq ("$(wildcard o/third_party/gcc/bin/x86_64-linux-cosmo-*)","") +PREFIX = o/third_party/gcc/bin/x86_64-linux-cosmo- else IGNORE := $(shell build/bootstrap/unbundle.com) PREFIX = o/third_party/gcc/bin/x86_64-linux-musl- endif -ifeq ($(ARCH), aarch64) +endif # ($(ARCH),x86_64)) +ifeq ($(ARCH),aarch64) +ifneq ("$(wildcard o/third_party/gcc/bin/aarch64-linux-cosmo-*)","") +PREFIX = o/third_party/gcc/bin/aarch64-linux-cosmo- +else +IGNORE := $(shell build/bootstrap/unbundle.com) PREFIX = o/third_party/gcc/bin/aarch64-linux-musl- endif -endif -endif +endif # ($(ARCH),aarch64) +endif # ($(USE_SYSTEM_TOOLCHAIN),) +endif # ($(PREFIX),) AS = $(PREFIX)as CC = $(PREFIX)gcc @@ -116,7 +123,7 @@ GCC = $(PREFIX)gcc STRIP = $(PREFIX)strip OBJCOPY = $(PREFIX)objcopy OBJDUMP = $(PREFIX)objdump -ifneq ($(wildcard $(PWD)/$(PREFIX)addr2line), ) +ifneq ($(wildcard $(PWD)/$(PREFIX)addr2line),) ADDR2LINE = $(PWD)/$(PREFIX)addr2line else ADDR2LINE = $(PREFIX)addr2line diff --git a/build/objdump b/build/objdump index 2e032aa04..103269f7b 100755 --- a/build/objdump +++ b/build/objdump @@ -1,6 +1,29 @@ #!/bin/sh -if printf '%s\n' "$*" | grep aarch64 >/dev/null 2>&1; then - exec o/third_party/gcc/bin/aarch64-linux-musl-objdump "$@" -else - exec o/third_party/gcc/bin/x86_64-linux-musl-objdump "$@" +COSMO=${COSMO:-/opt/cosmo} + +if [ -n "$OBJDUMP" ]; then + exec "$OBJDUMP" "$@" +fi + +find_objdump() { + if [ -x o/third_party/gcc/bin/$1-linux-cosmo-objdump ]; then + OBJDUMP=o/third_party/gcc/bin/$1-linux-cosmo-objdump + elif [ -x o/third_party/gcc/bin/$1-linux-musl-objdump ]; then + OBJDUMP=o/third_party/gcc/bin/$1-linux-musl-objdump + elif [ -x "$COSMO/o/third_party/gcc/bin/$1-linux-cosmo-objdump" ]; then + OBJDUMP="$COSMO/o/third_party/gcc/bin/$1-linux-cosmo-objdump" + elif [ -x "$COSMO/o/third_party/gcc/bin/$1-linux-musl-objdump" ]; then + OBJDUMP="$COSMO/o/third_party/gcc/bin/$1-linux-musl-objdump" + else + echo "error: toolchain not found (try running 'cosmocc --update' or 'make' in the cosmo monorepo)" >&2 + exit 1 + fi +} + +if printf '%s\n' "$*" | grep aarch64 >/dev/null 2>&1; then + find_objdump aarch64 + exec "$OBJDUMP" "$@" +else + find_objdump x86_64 + exec "$OBJDUMP" "$@" fi diff --git a/libc/calls/assertfail.c b/libc/calls/assertfail.c index 539998086..24782417f 100644 --- a/libc/calls/assertfail.c +++ b/libc/calls/assertfail.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" #include "libc/calls/calls.h" +#include "libc/calls/struct/sigset.internal.h" #include "libc/errno.h" #include "libc/fmt/itoa.h" #include "libc/intrin/describebacktrace.internal.h" @@ -28,9 +29,11 @@ */ void __assert_fail(const char *expr, const char *file, int line) { char ibuf[12]; + sigset_t m = __sig_block(); FormatInt32(ibuf, line); tinyprint(2, file, ":", ibuf, ": assert(", expr, ") failed (", program_invocation_short_name, " ", DescribeBacktrace(__builtin_frame_address(0)), ")\n", NULL); + __sig_unblock(m); abort(); } diff --git a/libc/calls/blockcancel.internal.h b/libc/calls/blockcancel.internal.h index b4d9848b8..5ca6ed3a5 100644 --- a/libc/calls/blockcancel.internal.h +++ b/libc/calls/blockcancel.internal.h @@ -1,6 +1,5 @@ #ifndef COSMOPOLITAN_LIBC_CALLS_BLOCKCANCEL_H_ #define COSMOPOLITAN_LIBC_CALLS_BLOCKCANCEL_H_ -#include "libc/thread/thread.h" #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ diff --git a/libc/calls/createfileflags.c b/libc/calls/createfileflags.c index 7d9e43f78..641564c20 100644 --- a/libc/calls/createfileflags.c +++ b/libc/calls/createfileflags.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" #include "libc/calls/calls.h" +#include "libc/calls/createfileflags.internal.h" #include "libc/nt/createfile.h" #include "libc/nt/enum/accessmask.h" #include "libc/nt/enum/creationdisposition.h" @@ -26,23 +27,6 @@ #include "libc/sysv/consts/o.h" #include "libc/sysv/errfuns.h" -// code size optimization -// -#define _O_APPEND 0x00000400 // kNtFileAppendData -#define _O_CREAT 0x00000040 // kNtOpenAlways -#define _O_EXCL 0x00000080 // kNtCreateNew -#define _O_TRUNC 0x00000200 // kNtCreateAlways -#define _O_DIRECTORY 0x00010000 // kNtFileFlagBackupSemantics -#define _O_UNLINK 0x04000100 // kNtFileAttributeTemporary|DeleteOnClose -#define _O_DIRECT 0x00004000 // kNtFileFlagNoBuffering -#define _O_NONBLOCK 0x00000800 // kNtFileFlagWriteThrough (not sent to win32) -#define _O_RANDOM 0x80000000 // kNtFileFlagRandomAccess -#define _O_SEQUENTIAL 0x40000000 // kNtFileFlagSequentialScan -#define _O_COMPRESSED 0x20000000 // kNtFileAttributeCompressed -#define _O_INDEXED 0x10000000 // !kNtFileAttributeNotContentIndexed -#define _O_CLOEXEC 0x00080000 -// - textwindows int GetNtOpenFlags(int flags, int mode, uint32_t *out_perm, uint32_t *out_share, uint32_t *out_disp, uint32_t *out_attr) { diff --git a/libc/calls/createfileflags.internal.h b/libc/calls/createfileflags.internal.h new file mode 100644 index 000000000..249c43e58 --- /dev/null +++ b/libc/calls/createfileflags.internal.h @@ -0,0 +1,22 @@ +#ifndef COSMOPOLITAN_LIBC_CALLS_CREATEFILEFLAGS_INTERNAL_H_ +#define COSMOPOLITAN_LIBC_CALLS_CREATEFILEFLAGS_INTERNAL_H_ + +// code size optimization +// +#define _O_APPEND 0x00000400 // kNtFileAppendData +#define _O_CREAT 0x00000040 // kNtOpenAlways +#define _O_EXCL 0x00000080 // kNtCreateNew +#define _O_TRUNC 0x00000200 // kNtCreateAlways +#define _O_DIRECTORY 0x00010000 // kNtFileFlagBackupSemantics +#define _O_UNLINK 0x04000100 // kNtFileAttributeTemporary|DeleteOnClose +#define _O_DIRECT 0x00004000 // kNtFileFlagNoBuffering +#define _O_NONBLOCK 0x00000800 // kNtFileFlagWriteThrough (not sent to win32) +#define _O_RANDOM 0x80000000 // kNtFileFlagRandomAccess +#define _O_SEQUENTIAL 0x40000000 // kNtFileFlagSequentialScan +#define _O_COMPRESSED 0x20000000 // kNtFileAttributeCompressed +#define _O_INDEXED 0x10000000 // !kNtFileAttributeNotContentIndexed +#define _O_NOFOLLOW 0x00020000 // kNtFileFlagOpenReparsePoint +#define _O_CLOEXEC 0x00080000 +// + +#endif /* COSMOPOLITAN_LIBC_CALLS_CREATEFILEFLAGS_INTERNAL_H_ */ diff --git a/libc/calls/dup-nt.c b/libc/calls/dup-nt.c index f106e6fb3..f093326f3 100644 --- a/libc/calls/dup-nt.c +++ b/libc/calls/dup-nt.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" #include "libc/calls/calls.h" +#include "libc/calls/createfileflags.internal.h" #include "libc/calls/internal.h" #include "libc/calls/state.internal.h" #include "libc/calls/struct/sigset.internal.h" @@ -65,10 +66,10 @@ static textwindows int sys_dup_nt_impl(int oldfd, int newfd, int flags, kNtDuplicateSameAccess)) { g_fds.p[newfd] = g_fds.p[oldfd]; g_fds.p[newfd].handle = handle; - if (flags & O_CLOEXEC) { - g_fds.p[newfd].flags |= O_CLOEXEC; + if (flags & _O_CLOEXEC) { + g_fds.p[newfd].flags |= _O_CLOEXEC; } else { - g_fds.p[newfd].flags &= ~O_CLOEXEC; + g_fds.p[newfd].flags &= ~_O_CLOEXEC; } rc = newfd; } else { diff --git a/libc/calls/fadvise-nt.c b/libc/calls/fadvise-nt.c index 86dec5dde..c0a31468e 100644 --- a/libc/calls/fadvise-nt.c +++ b/libc/calls/fadvise-nt.c @@ -16,6 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/createfileflags.internal.h" #include "libc/calls/internal.h" #include "libc/calls/sig.internal.h" #include "libc/calls/state.internal.h" @@ -41,17 +42,17 @@ static textwindows int sys_fadvise_nt_impl(int fd, uint64_t offset, h1 = g_fds.p[fd].handle; mode = g_fds.p[fd].mode; flags = g_fds.p[fd].flags; - flags &= ~(O_SEQUENTIAL | O_RANDOM); + flags &= ~(_O_SEQUENTIAL | _O_RANDOM); switch (advice) { case MADV_NORMAL: break; case MADV_RANDOM: - flags |= O_RANDOM; + flags |= _O_RANDOM; break; case MADV_WILLNEED: case MADV_SEQUENTIAL: - flags |= O_SEQUENTIAL; + flags |= _O_SEQUENTIAL; break; default: return einval(); diff --git a/libc/calls/fchmod-nt.c b/libc/calls/fchmod-nt.c new file mode 100644 index 000000000..99b66d8de --- /dev/null +++ b/libc/calls/fchmod-nt.c @@ -0,0 +1,57 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2023 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ 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/struct/fd.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" +#include "libc/nt/enum/fileflagandattributes.h" +#include "libc/nt/enum/fileinfobyhandleclass.h" +#include "libc/nt/files.h" +#include "libc/nt/struct/filebasicinfo.h" +#include "libc/sysv/errfuns.h" + +textwindows int sys_fchmod_nt(int fd, uint32_t mode) { + + // validate file descriptor + if (fd + 0u >= g_fds.n) return ebadf(); + if (g_fds.p[fd].kind == kFdEmpty) return ebadf(); + + // get current information + struct NtFileBasicInfo fbi; + if (!GetFileInformationByHandleEx(g_fds.p[fd].handle, kNtFileBasicInfo, &fbi, + sizeof(fbi))) { + return __winerr(); + } + + // change attributes + if (mode & 0222) { + fbi.FileAttributes &= ~kNtFileAttributeReadonly; + } else { + fbi.FileAttributes |= kNtFileAttributeReadonly; + } + + // set new attributes + if (!SetFileInformationByHandle(g_fds.p[fd].handle, kNtFileBasicInfo, &fbi, + sizeof(fbi))) { + return __winerr(); + } + + // all good + return 0; +} diff --git a/libc/calls/fchmod.c b/libc/calls/fchmod.c index 092a8e57c..8be3e8f3a 100644 --- a/libc/calls/fchmod.c +++ b/libc/calls/fchmod.c @@ -17,18 +17,32 @@ │ 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" +#include "libc/intrin/strace.internal.h" #include "libc/sysv/errfuns.h" /** * Changes file permissions via open()'d file descriptor. * * @param mode contains octal flags (base 8) + * @raise EROFS if `fd` is a `/zip/...` file * @asyncsignalsafe * @see chmod() */ int fchmod(int fd, uint32_t mode) { - // TODO(jart): Windows - return sys_fchmod(fd, mode); + int rc; + if (__isfdkind(fd, kFdZip)) { + rc = erofs(); + } else if (IsLinux() || IsXnu() || IsFreebsd() || IsOpenbsd() || IsNetbsd()) { + rc = sys_fchmod(fd, mode); + } else if (IsWindows()) { + rc = sys_fchmod_nt(fd, mode); + } else { + rc = enosys(); + } + STRACE("fchmod(%d, %#o) → %d% m", fd, mode, rc); + return rc; } diff --git a/libc/calls/fcntl-nt.c b/libc/calls/fcntl-nt.c index 51e44d640..e2a3fd508 100644 --- a/libc/calls/fcntl-nt.c +++ b/libc/calls/fcntl-nt.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" #include "libc/calls/calls.h" +#include "libc/calls/createfileflags.internal.h" #include "libc/calls/internal.h" #include "libc/calls/struct/fd.internal.h" #include "libc/calls/struct/flock.h" @@ -318,7 +319,7 @@ static textwindows int sys_fcntl_nt_lock(struct Fd *f, int fd, int cmd, 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); + 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) { @@ -329,21 +330,21 @@ textwindows int sys_fcntl_nt(int fd, int cmd, uintptr_t arg) { __isfdkind(fd, kFdConsole) || // __isfdkind(fd, kFdDevNull)) { if (cmd == F_GETFL) { - rc = g_fds.p[fd].flags & (O_ACCMODE | O_APPEND | O_DIRECT | O_NONBLOCK | - O_RANDOM | O_SEQUENTIAL); + rc = g_fds.p[fd].flags & (O_ACCMODE | _O_APPEND | _O_DIRECT | + _O_NONBLOCK | _O_RANDOM | _O_SEQUENTIAL); } else if (cmd == F_SETFL) { rc = sys_fcntl_nt_setfl(fd, arg); } else if (cmd == F_GETFD) { - if (g_fds.p[fd].flags & O_CLOEXEC) { + if (g_fds.p[fd].flags & _O_CLOEXEC) { rc = FD_CLOEXEC; } else { rc = 0; } } else if (cmd == F_SETFD) { if (arg & FD_CLOEXEC) { - g_fds.p[fd].flags |= O_CLOEXEC; + g_fds.p[fd].flags |= _O_CLOEXEC; } else { - g_fds.p[fd].flags &= ~O_CLOEXEC; + g_fds.p[fd].flags &= ~_O_CLOEXEC; } rc = 0; } else if (cmd == F_SETLK || cmd == F_SETLKW || cmd == F_GETLK) { diff --git a/libc/calls/fdatasync-nt.c b/libc/calls/fdatasync-nt.c index 6c83d398e..4646b7b63 100644 --- a/libc/calls/fdatasync-nt.c +++ b/libc/calls/fdatasync-nt.c @@ -36,9 +36,8 @@ textwindows int sys_fdatasync_nt(int fd, bool fake) { // kNtGenericWrite access, and MSDN doesn't document it. return 0; } - if (_check_cancel() == -1) return -1; - if (_check_signal(false) == -1) return -1; if (fake) return 0; + if (_check_signal(false) == -1) return -1; return FlushFileBuffers(g_fds.p[fd].handle) ? 0 : __winerr(); } diff --git a/libc/calls/fstat-nt.c b/libc/calls/fstat-nt.c index b71f17ac1..69f0e5cb4 100644 --- a/libc/calls/fstat-nt.c +++ b/libc/calls/fstat-nt.c @@ -107,11 +107,12 @@ textwindows int sys_fstat_nt(int fd, struct stat *st) { case kFdSocket: return sys_fstat_nt_socket(g_fds.p[fd].kind, st); default: - return sys_fstat_nt_handle(g_fds.p[fd].handle, st); + return sys_fstat_nt_handle(g_fds.p[fd].handle, 0, st); } } -textwindows int sys_fstat_nt_handle(int64_t handle, struct stat *out_st) { +textwindows int sys_fstat_nt_handle(int64_t handle, const char16_t *path, + struct stat *out_st) { struct stat st = {0}; // Always set st_blksize to avoid divide by zero issues. @@ -143,7 +144,7 @@ textwindows int sys_fstat_nt_handle(int64_t handle, struct stat *out_st) { } st.st_mode = 0444 & ~umask; if ((wst.dwFileAttributes & kNtFileAttributeDirectory) || - IsWindowsExecutable(handle)) { + IsWindowsExecutable(handle, path)) { st.st_mode |= 0111 & ~umask; } st.st_flags = wst.dwFileAttributes; diff --git a/libc/calls/fstatat-nt.c b/libc/calls/fstatat-nt.c index 720110ae7..9ff276c49 100644 --- a/libc/calls/fstatat-nt.c +++ b/libc/calls/fstatat-nt.c @@ -74,10 +74,11 @@ TryAgain: ((flags & AT_SYMLINK_NOFOLLOW) ? kNtFileFlagOpenReparsePoint : 0), 0)) != -1) { - rc = st ? sys_fstat_nt_handle(fh, st) : 0; + rc = st ? sys_fstat_nt_handle(fh, path16, st) : 0; CloseHandle(fh); } else if (dwDesiredAccess == kNtFileGenericRead && - GetLastError() == kNtErrorSharingViolation) { + (GetLastError() == kNtErrorAccessDenied || + GetLastError() == kNtErrorSharingViolation)) { dwDesiredAccess = kNtFileReadAttributes; errno = e; goto TryAgain; diff --git a/libc/calls/getrandom-metal.c b/libc/calls/getrandom-metal.c new file mode 100644 index 000000000..74be74be5 --- /dev/null +++ b/libc/calls/getrandom-metal.c @@ -0,0 +1,94 @@ +/*-*- 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 2023 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/intrin/asmflag.h" +#include "libc/nexgen32e/x86feature.h" +#include "libc/sysv/consts/grnd.h" +#include "libc/sysv/errfuns.h" +#ifdef __x86_64__ + +static bool GetRandomRdseed(uint64_t *out) { + int i; + char cf; + uint64_t x; + for (i = 0; i < 10; ++i) { + asm volatile(CFLAG_ASM("rdseed\t%1") + : CFLAG_CONSTRAINT(cf), "=r"(x) + : /* no inputs */ + : "cc"); + if (cf) { + *out = x; + return true; + } + asm volatile("pause"); + } + return false; +} + +static bool GetRandomRdrand(uint64_t *out) { + int i; + char cf; + uint64_t x; + for (i = 0; i < 10; ++i) { + asm volatile(CFLAG_ASM("rdrand\t%1") + : CFLAG_CONSTRAINT(cf), "=r"(x) + : /* no inputs */ + : "cc"); + if (cf) { + *out = x; + return true; + } + asm volatile("pause"); + } + return false; +} + +static ssize_t GetRandomCpu(char *p, size_t n, int f, bool impl(uint64_t *)) { + uint64_t x; + size_t i, j; + for (i = 0; i < n; i += j) { + TryAgain: + if (!impl(&x)) { + if (f || i >= 256) break; + goto TryAgain; + } + for (j = 0; j < 8 && i + j < n; ++j) { + p[i + j] = x; + x >>= 8; + } + } + return n; +} + +ssize_t sys_getrandom_metal(char *p, size_t n, int f) { + if (f & GRND_RANDOM) { + if (X86_HAVE(RDSEED)) { + return GetRandomCpu(p, n, f, GetRandomRdseed); + } else { + return enosys(); + } + } else { + if (X86_HAVE(RDRND)) { + return GetRandomCpu(p, n, f, GetRandomRdrand); + } else { + return enosys(); + } + } +} + +#endif /* __x86_64__ */ diff --git a/libc/calls/getrandom.c b/libc/calls/getrandom.c index b862ca2fa..3ced34951 100644 --- a/libc/calls/getrandom.c +++ b/libc/calls/getrandom.c @@ -55,78 +55,10 @@ __static_yoink("rdrand_init"); int sys_getentropy(void *, size_t) asm("sys_getrandom"); +ssize_t sys_getrandom_metal(char *, size_t, int); static bool have_getrandom; -static bool GetRandomRdseed(uint64_t *out) { - int i; - char cf; - uint64_t x; - for (i = 0; i < 10; ++i) { - asm volatile(CFLAG_ASM("rdseed\t%1") - : CFLAG_CONSTRAINT(cf), "=r"(x) - : /* no inputs */ - : "cc"); - if (cf) { - *out = x; - return true; - } - asm volatile("pause"); - } - return false; -} - -static bool GetRandomRdrand(uint64_t *out) { - int i; - char cf; - uint64_t x; - for (i = 0; i < 10; ++i) { - asm volatile(CFLAG_ASM("rdrand\t%1") - : CFLAG_CONSTRAINT(cf), "=r"(x) - : /* no inputs */ - : "cc"); - if (cf) { - *out = x; - return true; - } - asm volatile("pause"); - } - return false; -} - -static ssize_t GetRandomCpu(char *p, size_t n, int f, bool impl(uint64_t *)) { - uint64_t x; - size_t i, j; - for (i = 0; i < n; i += j) { - TryAgain: - if (!impl(&x)) { - if (f || i >= 256) break; - goto TryAgain; - } - for (j = 0; j < 8 && i + j < n; ++j) { - p[i + j] = x; - x >>= 8; - } - } - return n; -} - -static ssize_t GetRandomMetal(char *p, size_t n, int f) { - if (f & GRND_RANDOM) { - if (X86_HAVE(RDSEED)) { - return GetRandomCpu(p, n, f, GetRandomRdseed); - } else { - return enosys(); - } - } else { - if (X86_HAVE(RDRND)) { - return GetRandomCpu(p, n, f, GetRandomRdrand); - } else { - return enosys(); - } - } -} - static void GetRandomEntropy(char *p, size_t n) { unassert(n <= 256); if (sys_getentropy(p, n)) notpossible; @@ -181,8 +113,10 @@ ssize_t __getrandom(void *p, size_t n, unsigned f) { } } else if (IsFreebsd() || IsNetbsd()) { rc = GetRandomBsd(p, n, GetRandomArnd); +#ifdef __x86_64__ } else if (IsMetal()) { - rc = GetRandomMetal(p, n, f); + rc = sys_getrandom_metal(p, n, f); +#endif } else { BEGIN_CANCELATION_POINT; rc = GetDevUrandom(p, n); diff --git a/libc/calls/internal.h b/libc/calls/internal.h index 94258beb1..f2fa4d731 100644 --- a/libc/calls/internal.h +++ b/libc/calls/internal.h @@ -24,11 +24,11 @@ int __ensurefds(int); uint32_t sys_getuid_nt(void); int __ensurefds_unlocked(int); void __printfds(struct Fd *, size_t); -int IsWindowsExecutable(int64_t); int CountConsoleInputBytes(void); int FlushConsoleInputBytes(void); int64_t GetConsoleInputHandle(void); int64_t GetConsoleOutputHandle(void); +int IsWindowsExecutable(int64_t, const char16_t *); void InterceptTerminalCommands(const char *, size_t); forceinline int64_t __getfdhandleactual(int fd) { diff --git a/libc/calls/interrupts-nt.c b/libc/calls/interrupts-nt.c index 3af045bff..eb4d27e96 100644 --- a/libc/calls/interrupts-nt.c +++ b/libc/calls/interrupts-nt.c @@ -36,8 +36,10 @@ textwindows int _check_cancel(void) { textwindows int _check_signal(bool restartable) { int status; + if (_check_cancel() == -1) return -1; if (!_weaken(__sig_check)) return 0; if (!(status = _weaken(__sig_check)())) return 0; + if (_check_cancel() == -1) return -1; if (status == 2 && restartable) return 0; return eintr(); } diff --git a/libc/calls/ioctl.c b/libc/calls/ioctl.c index aca879bdb..819416fec 100644 --- a/libc/calls/ioctl.c +++ b/libc/calls/ioctl.c @@ -115,6 +115,7 @@ static int ioctl_fionread(int fd, uint32_t *arg) { *arg = avail; return 0; } else if (GetLastError() == kNtErrorBrokenPipe) { + *arg = 0; // win32 can give epipe on reader end return 0; } else { return __winerr(); diff --git a/libc/calls/ntaccesscheck.c b/libc/calls/ntaccesscheck.c index e407a9545..895d4a357 100644 --- a/libc/calls/ntaccesscheck.c +++ b/libc/calls/ntaccesscheck.c @@ -108,7 +108,7 @@ textwindows int ntaccesscheck(const char16_t *pathname, uint32_t flags) { 0)) != -1) { unassert(GetFileInformationByHandle(hFile, &wst)); if ((wst.dwFileAttributes & kNtFileAttributeDirectory) || - IsWindowsExecutable(hFile)) { + IsWindowsExecutable(hFile, pathname)) { rc = 0; } else { rc = eacces(); diff --git a/libc/calls/open-nt.c b/libc/calls/open-nt.c index 570ff6d59..c9420f1a8 100644 --- a/libc/calls/open-nt.c +++ b/libc/calls/open-nt.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" +#include "libc/calls/createfileflags.internal.h" #include "libc/calls/internal.h" #include "libc/calls/state.internal.h" #include "libc/calls/struct/sigset.internal.h" @@ -56,31 +57,31 @@ static textwindows int64_t sys_open_nt_impl(int dirfd, const char *path, // implement no follow flag // you can't open symlinks; use readlink // this flag only applies to the final path component - // if O_NOFOLLOW_ANY is passed (-1 on NT) it'll be rejected later + // if _O_NOFOLLOW_ANY is passed (-1 on NT) it'll be rejected later uint32_t fattr = GetFileAttributes(path16); - if (flags & O_NOFOLLOW) { + if (flags & _O_NOFOLLOW) { if (fattr != -1u && (fattr & kNtFileAttributeReparsePoint)) { return eloop(); } - flags &= ~O_NOFOLLOW; // don't actually pass this to win32 + flags &= ~_O_NOFOLLOW; // don't actually pass this to win32 } // handle some obvious cases while we have the attributes // we should ideally resolve symlinks ourself before doing this if (fattr != -1u) { if (fattr & kNtFileAttributeDirectory) { - if ((flags & O_ACCMODE) != O_RDONLY || (flags & O_CREAT)) { + if ((flags & O_ACCMODE) != O_RDONLY || (flags & _O_CREAT)) { // tried to open directory for writing. note that our - // undocumented O_TMPFILE support on windows requires that a + // undocumented _O_TMPFILE support on windows requires that a // filename be passed, rather than a directory like linux. return eisdir(); } // on posix, the o_directory flag is an advisory safeguard that // isn't required. on windows, it's mandatory for opening a dir - flags |= O_DIRECTORY; + flags |= _O_DIRECTORY; } else if (!(fattr & kNtFileAttributeReparsePoint)) { // we know for certain file isn't a directory - if (flags & O_DIRECTORY) { + if (flags & _O_DIRECTORY) { return enotdir(); } } @@ -186,7 +187,7 @@ textwindows int sys_open_nt(int dirfd, const char *file, uint32_t flags, ssize_t rc; BLOCK_SIGNALS; __fds_lock(); - if (!(flags & O_CREAT)) mode = 0; + if (!(flags & _O_CREAT)) mode = 0; if ((rc = fd = __reservefd_unlocked(-1)) != -1) { if (startswith(file, "/dev/")) { if (!strcmp(file + 5, "tty")) { diff --git a/libc/calls/park.c b/libc/calls/park.c index 119e29854..ee6ac3cf0 100644 --- a/libc/calls/park.c +++ b/libc/calls/park.c @@ -20,6 +20,7 @@ #include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/calls/struct/sigset.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/errno.h" #include "libc/intrin/atomic.h" #include "libc/nt/enum/wait.h" @@ -45,11 +46,13 @@ static textwindows int _park_thread(uint32_t msdelay, sigset_t waitmask, pthread_cleanup_push((void *)CloseHandle, (void *)sem); atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_SEM, memory_order_release); om = __sig_beginwait(waitmask); - if ((rc = _check_cancel()) != -1 && (rc = _check_signal(restartable)) != -1) { - unassert((wi = WaitForSingleObject(sem, msdelay)) != -1u); - if (restartable && !(pt->pt_flags & PT_RESTARTABLE)) rc = eintr(); - rc |= _check_signal(restartable); - if (rc == -1 && errno == EINTR) _check_cancel(); + if ((rc = _check_signal(restartable)) != -1) { + if ((wi = WaitForSingleObject(sem, msdelay)) != -1u) { + if (restartable && !(pt->pt_flags & PT_RESTARTABLE)) rc = eintr(); + rc |= _check_signal(restartable); + } else { + rc = __winerr(); + } } __sig_finishwait(om); atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_CPU, memory_order_release); diff --git a/libc/calls/read-nt.c b/libc/calls/read-nt.c index 7ce32aaf0..72334878f 100644 --- a/libc/calls/read-nt.c +++ b/libc/calls/read-nt.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" #include "libc/atomic.h" +#include "libc/calls/createfileflags.internal.h" #include "libc/calls/internal.h" #include "libc/calls/sig.internal.h" #include "libc/calls/state.internal.h" @@ -729,7 +730,7 @@ static textwindows int WaitForConsole(struct Fd *f, sigset_t waitmask) { ms = __ttyconf.vtime * 100; } } - if (f->flags & O_NONBLOCK) { + if (f->flags & _O_NONBLOCK) { return eagain(); // standard unix non-blocking } pt = _pthread_self(); @@ -738,12 +739,14 @@ static textwindows int WaitForConsole(struct Fd *f, sigset_t waitmask) { pthread_cleanup_push((void *)CloseHandle, (void *)sem); atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_SEM, memory_order_release); m = __sig_beginwait(waitmask); - if ((rc = _check_cancel()) != -1 && (rc = _check_signal(true)) != -1) { + if ((rc = _check_signal(true)) != -1) { int64_t hands[2] = {sem, __keystroke.cin}; - unassert(WaitForMultipleObjects(2, hands, 0, ms) != -1u); - if (~pt->pt_flags & PT_RESTARTABLE) rc = eintr(); - rc |= _check_signal(true); - if (rc == -1 && errno == EINTR) _check_cancel(); + if (WaitForMultipleObjects(2, hands, 0, ms) != -1u) { + if (!(pt->pt_flags & PT_RESTARTABLE)) rc = eintr(); + rc |= _check_signal(true); + } else { + rc = __winerr(); + } } __sig_finishwait(m); atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_CPU, memory_order_release); diff --git a/libc/calls/readwrite-nt.c b/libc/calls/readwrite-nt.c index 06ba2b37b..040765899 100644 --- a/libc/calls/readwrite-nt.c +++ b/libc/calls/readwrite-nt.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" +#include "libc/calls/createfileflags.internal.h" #include "libc/calls/internal.h" #include "libc/calls/sig.internal.h" #include "libc/calls/struct/fd.internal.h" @@ -140,15 +141,16 @@ sys_readwrite_nt(int fd, void *data, size_t size, ssize_t offset, pt->pt_flags |= PT_RESTARTABLE; atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_IO, memory_order_release); m = __sig_beginwait(waitmask); - if (f->flags & O_NONBLOCK) { + if (f->flags & _O_NONBLOCK) { CancelIoEx(handle, &overlap); eagained = true; - } else if (_check_cancel()) { - CancelIoEx(handle, &overlap); - canceled = true; } else if (_check_signal(true)) { CancelIoEx(handle, &overlap); - eintered = true; + if (errno == ECANCELED) { + canceled = true; + } else { + eintered = true; + } } else { WaitForSingleObject(overlap.hEvent, -1u); } @@ -197,7 +199,7 @@ sys_readwrite_nt(int fd, void *data, size_t size, ssize_t offset, // it's also fine to do nothing here; punt to next cancelation point if (GetLastError() == kNtErrorOperationAborted) { if (_check_cancel() == -1) return ecanceled(); - if (!eintered && _check_signal(false)) return eintr(); + if (!eintered && _check_signal(false)) return -1; } // if we chose to process a pending signal earlier then we preserve diff --git a/libc/calls/setfl.c b/libc/calls/setfl.c index e1fb8841a..56bbf00ed 100644 --- a/libc/calls/setfl.c +++ b/libc/calls/setfl.c @@ -16,6 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/createfileflags.internal.h" #include "libc/calls/internal.h" #include "libc/calls/struct/fd.internal.h" #include "libc/calls/syscall_support-nt.internal.h" @@ -36,8 +37,9 @@ textwindows int sys_fcntl_nt_setfl(int fd, unsigned flags) { // - O_DIRECT works but haven't tested // // the other bits are ignored. - unsigned allowed = O_APPEND | O_SEQUENTIAL | O_RANDOM | O_DIRECT | O_NONBLOCK; - unsigned needreo = O_APPEND | O_SEQUENTIAL | O_RANDOM | O_DIRECT; + unsigned allowed = + _O_APPEND | _O_SEQUENTIAL | _O_RANDOM | _O_DIRECT | _O_NONBLOCK; + unsigned needreo = _O_APPEND | _O_SEQUENTIAL | _O_RANDOM | _O_DIRECT; unsigned newflag = (g_fds.p[fd].flags & ~allowed) | (flags & allowed); if (g_fds.p[fd].kind == kFdFile && diff --git a/libc/calls/sig.c b/libc/calls/sig.c index 1a6b8d996..bbb5b8f65 100644 --- a/libc/calls/sig.c +++ b/libc/calls/sig.c @@ -33,9 +33,7 @@ #include "libc/fmt/itoa.h" #include "libc/intrin/atomic.h" #include "libc/intrin/bsf.h" -#include "libc/intrin/bsr.h" #include "libc/intrin/describebacktrace.internal.h" -#include "libc/intrin/kprintf.h" #include "libc/intrin/popcnt.h" #include "libc/intrin/strace.internal.h" #include "libc/intrin/weaken.h" @@ -105,7 +103,7 @@ static textwindows int __sig_getter(struct CosmoTib *tib, atomic_ulong *sigs) { pending = atomic_load_explicit(sigs, memory_order_acquire); masked = atomic_load_explicit(&tib->tib_sigmask, memory_order_acquire); if ((deliverable = pending & ~masked)) { - sig = _bsf(deliverable) + 1; + sig = _bsfl(deliverable) + 1; bit = 1ull << (sig - 1); if (atomic_fetch_and_explicit(sigs, ~bit, memory_order_acq_rel) & bit) { return sig; @@ -263,7 +261,7 @@ textwindows void __sig_cancel(struct PosixThread *pt, int sig, unsigned flags) { WakeByAddressSingle(blocker); } -// the user's signal handler callback is composed with this trampoline +// the user's signal handler callback is wrapped with this trampoline static textwindows wontreturn void __sig_tramp(struct SignalFrame *sf) { int sig = sf->si.si_signo; struct CosmoTib *tib = __get_tls(); diff --git a/libc/calls/struct/stat.internal.h b/libc/calls/struct/stat.internal.h index 4e4fdcbfa..2d5f51dfb 100644 --- a/libc/calls/struct/stat.internal.h +++ b/libc/calls/struct/stat.internal.h @@ -9,7 +9,7 @@ int sys_fstat(int, struct stat *); int sys_fstatat(int, const char *, struct stat *, int); int sys_fstat_nt(int, struct stat *); int sys_fstat_nt_special(int, struct stat *); -int sys_fstat_nt_handle(int64_t, struct stat *); +int sys_fstat_nt_handle(int64_t, const char16_t *, struct stat *); int sys_fstatat_nt(int, const char *, struct stat *, int); int sys_lstat_nt(const char *, struct stat *); int sys_fstat_metal(int, struct stat *); diff --git a/libc/calls/struct/utsname.h b/libc/calls/struct/utsname.h index f98f07b3d..07c055f09 100644 --- a/libc/calls/struct/utsname.h +++ b/libc/calls/struct/utsname.h @@ -1,7 +1,7 @@ #ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_UTSNAME_H_ #define COSMOPOLITAN_LIBC_CALLS_STRUCT_UTSNAME_H_ -#define SYS_NMLN 321 +#define SYS_NMLN 150 #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ diff --git a/libc/calls/syscall-nt.internal.h b/libc/calls/syscall-nt.internal.h index 887c42099..4e5a8994c 100644 --- a/libc/calls/syscall-nt.internal.h +++ b/libc/calls/syscall-nt.internal.h @@ -12,6 +12,7 @@ int sys_execve_nt(const char *, char *const[], char *const[]); int sys_faccessat_nt(int, const char *, int, uint32_t); int sys_fadvise_nt(int, uint64_t, uint64_t, int); int sys_fchdir_nt(int); +int sys_fchmod_nt(int, uint32_t); int sys_fchmodat_nt(int, const char *, uint32_t, int); int sys_fcntl_nt(int, int, uintptr_t); int sys_fdatasync_nt(int, bool); diff --git a/libc/calls/ttyname_r.c b/libc/calls/ttyname_r.c index a5617a259..be049136c 100644 --- a/libc/calls/ttyname_r.c +++ b/libc/calls/ttyname_r.c @@ -91,7 +91,12 @@ errno_t ttyname_r(int fd, char *buf, size_t size) { } else if (IsWindows()) { res = sys_ttyname_nt(fd, buf, size); } else { - res = ENOSYS; + // TODO(jart): Use that fstat(dev/ino) + readdir(/dev/) trick. + if (strlcpy(buf, "/dev/tty", size) < size) { + res = 0; + } else { + res = ERANGE; + } } errno = e; STRACE("ttyname_r(%d, %#.*hhs) → %s", fd, (int)size, buf, diff --git a/libc/calls/winexec.c b/libc/calls/winexec.c index af14e2b9f..c8c96cb7d 100644 --- a/libc/calls/winexec.c +++ b/libc/calls/winexec.c @@ -18,14 +18,57 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" #include "libc/calls/struct/sigset.internal.h" +#include "libc/intrin/bits.h" #include "libc/nt/errors.h" #include "libc/nt/events.h" #include "libc/nt/files.h" #include "libc/nt/runtime.h" #include "libc/nt/struct/overlapped.h" +#include "libc/str/str.h" +#include "libc/str/tab.internal.h" +#include "third_party/linenoise/linenoise.h" + +#define EXT(s) READ32LE(s "\0\0") + +static bool IsGraph(wint_t c) { + return 0x21 <= c && c <= 0x7E; +} + +static uint32_t GetFileExtension(const char16_t *s) { + uint32_t w; + size_t i, n; + n = s ? strlen16(s) : 0; + for (i = w = 0; n--;) { + wint_t c = s[n]; + if (!IsGraph(c)) return 0; + if (c == '.') break; + if (++i > 4) return 0; + w <<= 8; + w |= kToLower[c]; + } + return w; +} // checks if file should be considered an executable on windows -textwindows int IsWindowsExecutable(int64_t handle) { +textwindows int IsWindowsExecutable(int64_t handle, const char16_t *path) { + + // fast path known file extensions + // shaves away 100ms of gnu make latency in cosmo monorepo + uint32_t ext; + if (!IsTiny() && (ext = GetFileExtension(path))) { + if (ext == EXT("c") || // c code + ext == EXT("cc") || // c++ code + ext == EXT("h") || // c/c++ header + ext == EXT("s") || // assembly code + ext == EXT("o")) { // object file + return false; + } + if (ext == EXT("com") || // mz executable + ext == EXT("exe") || // mz executable + ext == EXT("sh")) { // bourne shells + return true; + } + } // read first two bytes of file // access() and stat() aren't cancelation points diff --git a/libc/integral/c.inc b/libc/integral/c.inc index c4da8a4c5..99bdc1d2d 100644 --- a/libc/integral/c.inc +++ b/libc/integral/c.inc @@ -146,7 +146,6 @@ typedef struct { } axdx_t; #endif - #ifndef __chibicc__ #define va_list __builtin_va_list #define va_arg(ap, type) __builtin_va_arg(ap, type) @@ -620,12 +619,6 @@ void abort(void) wontreturn; do { \ } while (0) -#if defined(__GNUC__) && !defined(__STRICT_ANSI__) -#define _Vector_size(k) __attribute__((__vector_size__(k))) -#else -#define _Vector_size(k) [k] -#endif - #ifndef __STRICT_ANSI__ #define textstartup _Section(".text.startup") #define textexit _Section(".text.exit") diff --git a/libc/intrin/createfile.c b/libc/intrin/createfile.c index 7a0db6195..183477e45 100644 --- a/libc/intrin/createfile.c +++ b/libc/intrin/createfile.c @@ -48,10 +48,25 @@ CreateFile(const char16_t *lpFileName, // int64_t opt_hTemplateFile) { int64_t hHandle; uint32_t micros = 1; + char buf_accessflags[512]; + (void)buf_accessflags; + char buf_shareflags[64]; + (void)buf_shareflags; + char buf_secattr[32]; + (void)buf_secattr; + char buf_flagattr[256]; + (void)buf_flagattr; TryAgain: hHandle = __imp_CreateFileW(lpFileName, dwDesiredAccess, dwShareMode, opt_lpSecurity, dwCreationDisposition, dwFlagsAndAttributes, opt_hTemplateFile); + NTTRACE("CreateFile(%#hs, %s, %s, %s, %s, %s, %ld) → {%ld, %d}", lpFileName, + (DescribeNtFileAccessFlags)(buf_accessflags, dwDesiredAccess), + (DescribeNtFileShareFlags)(buf_shareflags, dwShareMode), + (DescribeNtSecurityAttributes)(buf_secattr, opt_lpSecurity), + DescribeNtCreationDisposition(dwCreationDisposition), + (DescribeNtFileFlagAttr)(buf_flagattr, dwFlagsAndAttributes), + opt_hTemplateFile, hHandle, __imp_GetLastError()); if (hHandle == -1) { switch (__imp_GetLastError()) { case kNtErrorPipeBusy: @@ -77,12 +92,5 @@ TryAgain: } __winerr(); } - NTTRACE("CreateFile(%#hs, %s, %s, %s, %s, %s, %ld) → %ld% m", lpFileName, - DescribeNtFileAccessFlags(dwDesiredAccess), - DescribeNtFileShareFlags(dwShareMode), - DescribeNtSecurityAttributes(opt_lpSecurity), - DescribeNtCreationDisposition(dwCreationDisposition), - DescribeNtFileFlagAttr(dwFlagsAndAttributes), opt_hTemplateFile, - hHandle); return hHandle; } diff --git a/libc/intrin/createthread.c b/libc/intrin/createthread.c index d79cfe989..aa660e9b9 100644 --- a/libc/intrin/createthread.c +++ b/libc/intrin/createthread.c @@ -19,10 +19,12 @@ #include "libc/calls/syscall_support-nt.internal.h" #include "libc/intrin/describeflags.internal.h" #include "libc/intrin/strace.internal.h" +#include "libc/nt/runtime.h" #include "libc/nt/struct/securityattributes.h" #include "libc/nt/thread.h" __msabi extern typeof(CreateThread) *const __imp_CreateThread; +__msabi extern typeof(GetLastError) *const __imp_GetLastError; /** * Opens file on the New Technology. @@ -41,9 +43,10 @@ CreateThread(const struct NtSecurityAttributes *lpThreadAttributes, int64_t hHandle; hHandle = __imp_CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, opt_lpThreadId); - NTTRACE("CreateThread(%s, %'zu, %t, %p, %s, %p) → %ld% m", + NTTRACE("CreateThread(%s, %'zu, %t, %p, %s, %p) → {%ld, %d}", DescribeNtSecurityAttributes(lpThreadAttributes), dwStackSize, lpStartAddress, lpParameter, - DescribeThreadCreateFlags(dwCreationFlags), opt_lpThreadId, hHandle); + DescribeThreadCreateFlags(dwCreationFlags), opt_lpThreadId, hHandle, + __imp_GetLastError()); return hHandle; } diff --git a/libc/intrin/flushfilebuffers.c b/libc/intrin/flushfilebuffers.c index e96ef39bd..21f437909 100644 --- a/libc/intrin/flushfilebuffers.c +++ b/libc/intrin/flushfilebuffers.c @@ -19,8 +19,10 @@ #include "libc/calls/syscall_support-nt.internal.h" #include "libc/intrin/strace.internal.h" #include "libc/nt/files.h" +#include "libc/nt/runtime.h" __msabi extern typeof(FlushFileBuffers) *const __imp_FlushFileBuffers; +__msabi extern typeof(GetLastError) *const __imp_GetLastError; /** * Flushes buffers of specified file to disk. @@ -36,6 +38,7 @@ __msabi extern typeof(FlushFileBuffers) *const __imp_FlushFileBuffers; textwindows bool32 FlushFileBuffers(int64_t hFile) { bool32 ok; ok = __imp_FlushFileBuffers(hFile); - NTTRACE("FlushFileBuffers(%ld) → %hhhd% m", hFile, ok); + NTTRACE("FlushFileBuffers(%ld) → {%hhhd, %d}", hFile, ok, + __imp_GetLastError()); return ok; } diff --git a/libc/intrin/isdebuggerpresent.c b/libc/intrin/isdebuggerpresent.c index c514d7dfa..7ee193002 100644 --- a/libc/intrin/isdebuggerpresent.c +++ b/libc/intrin/isdebuggerpresent.c @@ -33,7 +33,11 @@ #define kPid "TracerPid:\t" static textwindows bool IsBeingDebugged(void) { +#ifdef __x86_64__ return !!NtGetPeb()->BeingDebugged; +#else + return false; +#endif } /** diff --git a/libc/intrin/macros.h b/libc/intrin/macros.h index 44e9e668e..050b203ba 100644 --- a/libc/intrin/macros.h +++ b/libc/intrin/macros.h @@ -9,7 +9,8 @@ #if defined(__x86_64__) && !defined(__STRICT_ANSI__) -typedef char __intrin_xmm_t _Vector_size(16) forcealign(16) mayalias; +typedef char __intrin_xmm_t + __attribute__((__vector_size__(16), __aligned__(16), __may_alias__)); #define INTRIN_SSEVEX_X_X_X_(PURE, ISA, OP, FLAGS, A, B, C) \ do { \ diff --git a/libc/intrin/reopenfile.c b/libc/intrin/reopenfile.c index 759e06274..c62fd2caa 100644 --- a/libc/intrin/reopenfile.c +++ b/libc/intrin/reopenfile.c @@ -20,9 +20,11 @@ #include "libc/intrin/describeflags.internal.h" #include "libc/intrin/strace.internal.h" #include "libc/nt/files.h" +#include "libc/nt/runtime.h" #include "libc/nt/thunk/msabi.h" __msabi extern typeof(ReOpenFile) *const __imp_ReOpenFile; +__msabi extern typeof(GetLastError) *const __imp_GetLastError; /** * Reopens file on the New Technology. @@ -34,9 +36,10 @@ int64_t ReOpenFile(int64_t hOriginalFile, uint32_t dwDesiredAccess, int64_t hHandle; hHandle = __imp_ReOpenFile(hOriginalFile, dwDesiredAccess, dwShareMode, dwFlagsAndAttributes); - NTTRACE("ReOpenFile(%ld, %s, %s, %s) → %ld% m", hOriginalFile, + NTTRACE("ReOpenFile(%ld, %s, %s, %s) → {%ld, %d}", hOriginalFile, DescribeNtFileAccessFlags(dwDesiredAccess), DescribeNtFileShareFlags(dwShareMode), - DescribeNtFileFlagAttr(dwFlagsAndAttributes), hHandle); + DescribeNtFileFlagAttr(dwFlagsAndAttributes), hHandle, + __imp_GetLastError()); return hHandle; } diff --git a/libc/intrin/terminateprocess.c b/libc/intrin/terminateprocess.c index 752523fd0..2f0e3b1e1 100644 --- a/libc/intrin/terminateprocess.c +++ b/libc/intrin/terminateprocess.c @@ -23,6 +23,7 @@ #include "libc/nt/thunk/msabi.h" __msabi extern typeof(TerminateProcess) *const __imp_TerminateProcess; +__msabi extern typeof(GetLastError) *const __imp_GetLastError; /** * Terminates the specified process and all of its threads. @@ -30,6 +31,7 @@ __msabi extern typeof(TerminateProcess) *const __imp_TerminateProcess; textwindows bool32 TerminateProcess(int64_t hProcess, uint32_t uWaitStatus) { bool32 ok; ok = __imp_TerminateProcess(hProcess, uWaitStatus); - NTTRACE("TerminateProcess(%ld, %u) → %hhhd% m", hProcess, uWaitStatus, ok); + NTTRACE("TerminateProcess(%ld, %u) → {%hhhd, %d}", hProcess, uWaitStatus, ok, + __imp_GetLastError()); return ok; } diff --git a/libc/intrin/waitformultipleobjects.c b/libc/intrin/waitformultipleobjects.c index 8382d794d..ef97e8c2e 100644 --- a/libc/intrin/waitformultipleobjects.c +++ b/libc/intrin/waitformultipleobjects.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/syscall_support-nt.internal.h" #include "libc/intrin/strace.internal.h" +#include "libc/nt/runtime.h" #include "libc/nt/synchronization.h" #include "libc/nt/thunk/msabi.h" @@ -26,14 +27,15 @@ __msabi extern typeof(WaitForMultipleObjects) /** * Waits for handles to change status. - * @note this wrapper takes care of ABI, STRACE(), and __winerr() + * + * @return -1u on error w/ GetLastError() + * @raise kNtErrorInvalidParameter if `bWaitAll` and `lpHandles` has dupes */ uint32_t WaitForMultipleObjects(uint32_t nCount, const int64_t *lpHandles, bool32 bWaitAll, uint32_t dwMilliseconds) { uint32_t x; x = __imp_WaitForMultipleObjects(nCount, lpHandles, bWaitAll, dwMilliseconds); - if (x == -1u) __winerr(); - POLLTRACE("WaitForMultipleObjects(%ld, %p, %hhhd, %'d) → %d% m", nCount, - lpHandles, bWaitAll, dwMilliseconds, x); + POLLTRACE("WaitForMultipleObjects(%ld, %p, %hhhd, %'d) → %d %d", nCount, + lpHandles, bWaitAll, dwMilliseconds, x, GetLastError()); return x; } diff --git a/libc/intrin/waitforsingleobject.c b/libc/intrin/waitforsingleobject.c index 96ccc9681..e0d4d9975 100644 --- a/libc/intrin/waitforsingleobject.c +++ b/libc/intrin/waitforsingleobject.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/syscall_support-nt.internal.h" #include "libc/intrin/strace.internal.h" +#include "libc/nt/runtime.h" #include "libc/nt/synchronization.h" #include "libc/nt/thunk/msabi.h" @@ -30,7 +31,7 @@ __msabi extern typeof(WaitForSingleObject) *const __imp_WaitForSingleObject; uint32_t WaitForSingleObject(int64_t hHandle, uint32_t dwMilliseconds) { uint32_t rc; rc = __imp_WaitForSingleObject(hHandle, dwMilliseconds); - POLLTRACE("WaitForSingleObject(%ld, %'d) → %d% m", hHandle, dwMilliseconds, - rc); + POLLTRACE("WaitForSingleObject(%ld, %'d) → %d %d", hHandle, dwMilliseconds, + rc, GetLastError()); return rc; } diff --git a/libc/log/oncrash_arm64.c b/libc/log/oncrash_arm64.c index 7e448af5c..82b2101fe 100644 --- a/libc/log/oncrash_arm64.c +++ b/libc/log/oncrash_arm64.c @@ -366,7 +366,7 @@ static relegated void __oncrash_impl(int sig, struct siginfo *si, free(mem); } b->p[b->n - 1] = '\n'; - sys_write(2, b->p, MIN(b->i, b->n)); + klog(b->p, MIN(b->i, b->n)); } relegated void __oncrash(int sig, struct siginfo *si, void *arg) { diff --git a/libc/proc/posix_spawn.c b/libc/proc/posix_spawn.c index 959f7585f..bd9466dae 100644 --- a/libc/proc/posix_spawn.c +++ b/libc/proc/posix_spawn.c @@ -37,6 +37,7 @@ #include "libc/fmt/magnumstrs.internal.h" #include "libc/intrin/asan.internal.h" #include "libc/intrin/atomic.h" +#include "libc/intrin/bsf.h" #include "libc/intrin/describeflags.internal.h" #include "libc/intrin/dll.h" #include "libc/intrin/strace.internal.h" @@ -151,10 +152,11 @@ static textwindows bool spawnfds_exists(struct SpawnFds *fds, int fildes) { return fildes + 0u < fds->n && fds->p[fildes].kind; } -static textwindows void spawnfds_close(struct SpawnFds *fds, int fildes) { +static textwindows errno_t spawnfds_close(struct SpawnFds *fds, int fildes) { if (spawnfds_exists(fds, fildes)) { fds->p[fildes] = (struct Fd){0}; } + return 0; } static textwindows errno_t spawnfds_dup2(struct SpawnFds *fds, int fildes, @@ -181,8 +183,8 @@ static textwindows errno_t spawnfds_dup2(struct SpawnFds *fds, int fildes, } static textwindows errno_t spawnfds_open(struct SpawnFds *fds, int64_t dirhand, - int fildes, const char *path, - int oflag, int mode) { + const char *path, int oflag, int mode, + int fildes) { int64_t h; errno_t err; char16_t path16[PATH_MAX]; @@ -283,42 +285,47 @@ static textwindows errno_t posix_spawn_nt_impl( // apply user file actions if (file_actions) { for (struct _posix_faction *a = *file_actions; a && !err; a = a->next) { + char errno_buf[30]; + char oflags_buf[128]; + char openmode_buf[15]; + (void)errno_buf; + (void)oflags_buf; + (void)openmode_buf; switch (a->action) { case _POSIX_SPAWN_CLOSE: - spawnfds_close(&fds, a->fildes); + err = spawnfds_close(&fds, a->fildes); + STRACE("spawnfds_close(%d) → %s", a->fildes, + (DescribeErrno)(errno_buf, err)); break; case _POSIX_SPAWN_DUP2: err = spawnfds_dup2(&fds, a->fildes, a->newfildes); - if (err) { - STRACE("spawnfds_dup2(%d, %d) failed", a->fildes, a->newfildes); - goto ReturnErr; - } + STRACE("spawnfds_dup2(%d, %d) → %s", a->fildes, a->newfildes, + (DescribeErrno)(errno_buf, err)); break; case _POSIX_SPAWN_OPEN: - err = spawnfds_open(&fds, dirhand, a->fildes, a->path, a->oflag, - a->mode); - if (err) { - STRACE("spawnfds_open(%d, %#s) failed", a->fildes, a->path); - goto ReturnErr; - } + err = spawnfds_open(&fds, dirhand, a->path, a->oflag, a->mode, + a->fildes); + STRACE("spawnfds_open(%#s, %s, %s, %d) → %s", a->path, + (DescribeOpenFlags)(oflags_buf, a->oflag), + (DescribeOpenMode)(openmode_buf, a->oflag, a->mode), a->fildes, + (DescribeErrno)(errno_buf, err)); break; case _POSIX_SPAWN_CHDIR: err = spawnfds_chdir(&fds, dirhand, a->path, &dirhand); - if (err) { - STRACE("spawnfds_chdir(%#s) failed", a->path); - goto ReturnErr; - } + STRACE("spawnfds_chdir(%#s) → %s", a->path, + (DescribeErrno)(errno_buf, err)); break; case _POSIX_SPAWN_FCHDIR: err = spawnfds_fchdir(&fds, a->fildes, &dirhand); - if (err) { - STRACE("spawnfds_fchdir(%d) failed", a->fildes); - goto ReturnErr; - } + STRACE("spawnfds_fchdir(%d) → %s", a->fildes, + (DescribeErrno)(errno_buf, err)); break; default: __builtin_unreachable(); } + if (err) { + goto ReturnErr; + } } } @@ -572,9 +579,13 @@ errno_t posix_spawn(int *pid, const char *path, } } if (flags & POSIX_SPAWN_SETRLIMIT) { - for (int rez = 0; rez <= ARRAYLEN((*attrp)->rlim); ++rez) { - if ((*attrp)->rlimset & (1u << rez)) { - if (setrlimit(rez, (*attrp)->rlim + rez)) { + int rlimset = (*attrp)->rlimset; + while (rlimset) { + int resource = _bsf(rlimset); + rlimset &= ~(1u << resource); + if (setrlimit(resource, (*attrp)->rlim + resource)) { + // MacOS ARM64 RLIMIT_STACK always returns EINVAL + if (!IsXnuSilicon()) { goto ChildFailed; } } diff --git a/libc/proc/posix_spawn.internal.h b/libc/proc/posix_spawn.internal.h index 855774be1..6dce26533 100644 --- a/libc/proc/posix_spawn.internal.h +++ b/libc/proc/posix_spawn.internal.h @@ -19,8 +19,8 @@ struct _posix_spawna { bool schedparam_isset; bool schedpolicy_isset; int pgroup; - int rlimset; int schedpolicy; + int rlimset; struct sched_param schedparam; sigset_t sigmask; sigset_t sigdefault; diff --git a/libc/proc/posix_spawn_file_actions_addclose.c b/libc/proc/posix_spawn_file_actions_addclose.c index 3bf4a7ee1..635ae64e0 100644 --- a/libc/proc/posix_spawn_file_actions_addclose.c +++ b/libc/proc/posix_spawn_file_actions_addclose.c @@ -32,7 +32,6 @@ int posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *file_actions, int fildes) { if (fildes < 0) return EBADF; - if (IsWindows() && fildes > 2) return 0; return __posix_spawn_add_file_action(file_actions, (struct _posix_faction){ .action = _POSIX_SPAWN_CLOSE, diff --git a/libc/proc/posix_spawn_file_actions_adddup2.c b/libc/proc/posix_spawn_file_actions_adddup2.c index 449a86b2c..7768d9bb3 100644 --- a/libc/proc/posix_spawn_file_actions_adddup2.c +++ b/libc/proc/posix_spawn_file_actions_adddup2.c @@ -26,14 +26,12 @@ * * @param file_actions was initialized by posix_spawn_file_actions_init() * @return 0 on success, or errno on error - * @raise ENOMEM if we require more vespene gas * @raise EBADF if 'fildes' or `newfildes` is negative - * @raise ENOTSUP if `newfildes` isn't 0, 1, or 2 on Windows + * @raise ENOMEM if insufficient memory was available */ int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *file_actions, int fildes, int newfildes) { if (fildes < 0 || newfildes < 0) return EBADF; - if (IsWindows() && newfildes > 2) return ENOTSUP; return __posix_spawn_add_file_action(file_actions, (struct _posix_faction){ .action = _POSIX_SPAWN_DUP2, diff --git a/libc/proc/posix_spawnattr_getrlimit.c b/libc/proc/posix_spawnattr_getrlimit.c index 2109bf89c..bb3e59981 100644 --- a/libc/proc/posix_spawnattr_getrlimit.c +++ b/libc/proc/posix_spawnattr_getrlimit.c @@ -21,6 +21,8 @@ #include "libc/macros.internal.h" #include "libc/proc/posix_spawn.h" #include "libc/proc/posix_spawn.internal.h" +#include "libc/stdio/sysparam.h" +#include "libc/sysv/consts/rlim.h" /** * Gets resource limit for spawned process. @@ -31,7 +33,7 @@ */ int posix_spawnattr_getrlimit(const posix_spawnattr_t *attr, int resource, struct rlimit *rlim) { - if ((0 <= resource && resource < ARRAYLEN((*attr)->rlim))) { + if (0 <= resource && resource < MIN(RLIM_NLIMITS, ARRAYLEN((*attr)->rlim))) { if (((*attr)->rlimset & (1u << resource))) { *rlim = (*attr)->rlim[resource]; return 0; diff --git a/libc/proc/posix_spawnattr_setflags.c b/libc/proc/posix_spawnattr_setflags.c index 12c00e325..9521bb9b2 100644 --- a/libc/proc/posix_spawnattr_setflags.c +++ b/libc/proc/posix_spawnattr_setflags.c @@ -37,9 +37,10 @@ */ int posix_spawnattr_setflags(posix_spawnattr_t *attr, short flags) { if (flags & - ~(POSIX_SPAWN_RESETIDS | POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_SETSIGDEF | - POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSCHEDPARAM | - POSIX_SPAWN_SETSCHEDULER | POSIX_SPAWN_SETSID)) { + ~(POSIX_SPAWN_USEVFORK | POSIX_SPAWN_RESETIDS | POSIX_SPAWN_SETPGROUP | + POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK | + POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER | + POSIX_SPAWN_SETSID | POSIX_SPAWN_SETRLIMIT)) { return EINVAL; } (*attr)->flags = flags; diff --git a/libc/proc/posix_spawnattr_setrlimit.c b/libc/proc/posix_spawnattr_setrlimit.c index 10dabee61..90be67c43 100644 --- a/libc/proc/posix_spawnattr_setrlimit.c +++ b/libc/proc/posix_spawnattr_setrlimit.c @@ -21,6 +21,7 @@ #include "libc/macros.internal.h" #include "libc/proc/posix_spawn.h" #include "libc/proc/posix_spawn.internal.h" +#include "libc/sysv/consts/rlim.h" /** * Sets resource limit on spawned process. @@ -32,7 +33,7 @@ */ int posix_spawnattr_setrlimit(posix_spawnattr_t *attr, int resource, const struct rlimit *rlim) { - if (0 <= resource && resource < ARRAYLEN((*attr)->rlim)) { + if (0 <= resource && resource < MIN(RLIM_NLIMITS, ARRAYLEN((*attr)->rlim))) { (*attr)->flags |= POSIX_SPAWN_SETRLIMIT; (*attr)->rlimset |= 1u << resource; (*attr)->rlim[resource] = *rlim; diff --git a/libc/proc/proc.c b/libc/proc/proc.c index 38f8870cf..4c3cbef1e 100644 --- a/libc/proc/proc.c +++ b/libc/proc/proc.c @@ -103,12 +103,8 @@ static textwindows dontinstrument uint32_t __proc_worker(void *arg) { __proc_unlock(); // wait for win32 to report any status change - millis = n == 64 ? __SIG_PROC_INTERVAL_MS : -1u; - i = WaitForMultipleObjects(n, handles, false, millis); - if (i == -1u) { - STRACE("PROC WORKER DYING: WAIT FAILED: %s", strerror(errno)); - break; - } + millis = n == 64 ? 20 : -1u; + unassert((i = WaitForMultipleObjects(n, handles, false, millis)) != -1u); i &= ~kNtWaitAbandoned; if (!i || i == kNtWaitTimeout) continue; GetExitCodeProcess(handles[i], &status); diff --git a/libc/runtime/ftrace-hook.S b/libc/runtime/ftrace-hook.S index 84dbca1ac..2537944fc 100644 --- a/libc/runtime/ftrace-hook.S +++ b/libc/runtime/ftrace-hook.S @@ -68,14 +68,15 @@ ftrace_hook: #elif defined(__aarch64__) - adrp x16,__ftrace - ldr w16,[x16,#:lo12:__ftrace] - cmp w16,0 - ble 1f stp x29,x30,[sp,-384]! mov x29,sp - stp x0,x1,[sp,16] + + adrp x0,__ftrace + ldr w0,[x0,#:lo12:__ftrace] + cmp w0,0 + ble 1f + stp x2,x3,[sp,32] stp x4,x5,[sp,48] stp x6,x7,[sp,64] @@ -83,12 +84,12 @@ ftrace_hook: stp x10,x11,[sp,96] stp x12,x13,[sp,112] stp x14,x15,[sp,128] - str x19,[sp,160] + stp x16,x19,[sp,160] stp x20,x21,[sp,176] stp x22,x23,[sp,192] stp x24,x25,[sp,208] stp x26,x27,[sp,224] - str x28,[sp,240] + stp x17,x28,[sp,240] stp q0,q1,[sp,256] stp q2,q3,[sp,288] stp q4,q5,[sp,320] @@ -96,27 +97,27 @@ ftrace_hook: bl ftracer - ldp x0,x1,[sp,16] - ldp x2,x3,[sp,32] - ldp x4,x5,[sp,48] - ldp x6,x7,[sp,64] - ldp x8,x9,[sp,80] - ldp x10,x11,[sp,96] - ldp x12,x13,[sp,112] - ldp x14,x15,[sp,128] - ldr x19,[sp,160] - ldp x20,x21,[sp,176] - ldp x22,x23,[sp,192] - ldp x24,x25,[sp,208] - ldp x26,x27,[sp,224] - ldr x28,[sp,240] - ldp q0,q1,[sp,256] - ldp q2,q3,[sp,288] - ldp q4,q5,[sp,320] ldp q6,q7,[sp,352] + ldp q4,q5,[sp,320] + ldp q2,q3,[sp,288] + ldp q0,q1,[sp,256] + ldp x17,x28,[sp,240] + ldp x26,x27,[sp,224] + ldp x24,x25,[sp,208] + ldp x22,x23,[sp,192] + ldp x20,x21,[sp,176] + ldp x16,x19,[sp,160] + ldp x14,x15,[sp,128] + ldp x12,x13,[sp,112] + ldp x10,x11,[sp,96] + ldp x8,x9,[sp,80] + ldp x6,x7,[sp,64] + ldp x4,x5,[sp,48] + ldp x2,x3,[sp,32] +1: ldp x0,x1,[sp,16] ldp x29,x30,[sp],384 -1: ret + ret #endif /* __x86_64__ */ .endfn ftrace_hook,globl,hidden diff --git a/libc/sock/winsockblock.c b/libc/sock/winsockblock.c index 9a0f18661..77849065e 100644 --- a/libc/sock/winsockblock.c +++ b/libc/sock/winsockblock.c @@ -90,12 +90,13 @@ __winsock_block(int64_t handle, uint32_t flags, bool nonblock, if (nonblock) { CancelWinsockBlock(handle, &overlap); eagained = true; - } else if (_check_cancel()) { - CancelWinsockBlock(handle, &overlap); - canceled = true; } else if (_check_signal(true)) { CancelWinsockBlock(handle, &overlap); - eintered = true; + if (errno == ECANCELED) { + canceled = true; + } else { + eintered = true; + } } else { status = WSAWaitForMultipleEvents(1, &overlap.hEvent, 0, srwtimeout ? srwtimeout : -1u, 0); @@ -142,7 +143,7 @@ __winsock_block(int64_t handle, uint32_t flags, bool nonblock, } if (GetLastError() == kNtErrorOperationAborted) { if (_check_cancel() == -1) return ecanceled(); - if (!eintered && _check_signal(false)) return eintr(); + if (!eintered && _check_signal(false)) return -1; } if (eintered) { return eintr(); diff --git a/libc/sysv/sysv.c b/libc/sysv/sysv.c index dc30c8a31..2fdcade5c 100644 --- a/libc/sysv/sysv.c +++ b/libc/sysv/sysv.c @@ -57,7 +57,7 @@ dontinline long systemfive_cancellable(void) { return systemfive_cancel(); } #if IsModeDbg() - if (!(pth->flags & PT_INCANCEL)) { + if (!(pth->pt_flags & PT_INCANCEL)) { if (_weaken(report_cancelation_point)) { _weaken(report_cancelation_point)(); } diff --git a/test/libc/calls/fchmod_test.c b/test/libc/calls/fchmod_test.c new file mode 100644 index 000000000..3f95204fc --- /dev/null +++ b/test/libc/calls/fchmod_test.c @@ -0,0 +1,41 @@ +/*-*- 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 2023 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/calls/struct/stat.h" +#include "libc/testlib/testlib.h" + +void SetUpOnce(void) { + testlib_enable_tmp_setup_teardown(); +} + +uint32_t GetMode(int fd) { + struct stat st; + ASSERT_SYS(0, 0, fstat(fd, &st)); + return st.st_mode & 0777; +} + +TEST(fchmod, canChangeReadOnlyBit) { + ASSERT_SYS(0, 3, creat("foo", 0600)); + ASSERT_EQ(0600, GetMode(3)); + ASSERT_SYS(0, 0, fchmod(3, 0400)); + ASSERT_EQ(0400, GetMode(3)); + ASSERT_SYS(0, 0, fchmod(3, 0600)); + ASSERT_EQ(0600, GetMode(3)); + ASSERT_SYS(0, 0, close(3)); +} diff --git a/test/libc/calls/open_test.c b/test/libc/calls/open_test.c index fe77d895b..7eced981e 100644 --- a/test/libc/calls/open_test.c +++ b/test/libc/calls/open_test.c @@ -495,3 +495,16 @@ TEST(open, mereOpen_doesntTouch) { EXPECT_EQ(0, timespec_cmp(st.st_mtim, birth)); EXPECT_EQ(0, timespec_cmp(st.st_atim, birth)); } + +TEST(open, canTruncateExistingFile) { + struct stat st; + ASSERT_SYS(0, 0, xbarf("foo", "hello", -1)); + ASSERT_SYS(0, 0, stat("foo", &st)); + ASSERT_EQ(5, st.st_size); + ASSERT_SYS(0, 3, open("foo", O_RDWR | O_TRUNC)); + ASSERT_SYS(0, 0, fstat(3, &st)); + ASSERT_EQ(0, st.st_size); + ASSERT_SYS(0, 0, close(3)); + ASSERT_SYS(0, 0, stat("foo", &st)); + ASSERT_EQ(0, st.st_size); +} diff --git a/test/libc/thread/makecontext_test.c b/test/libc/thread/makecontext_test.c index 3137e794f..81f641baf 100644 --- a/test/libc/thread/makecontext_test.c +++ b/test/libc/thread/makecontext_test.c @@ -21,6 +21,11 @@ #include "libc/dce.h" #include "libc/limits.h" #include "libc/mem/gc.internal.h" +#include "libc/nt/createfile.h" +#include "libc/nt/enum/accessmask.h" +#include "libc/nt/enum/creationdisposition.h" +#include "libc/nt/enum/fileflagandattributes.h" +#include "libc/nt/enum/filesharemode.h" #include "libc/runtime/runtime.h" #include "libc/runtime/stack.h" #include "libc/runtime/symbols.internal.h" @@ -89,9 +94,14 @@ TEST(makecontext, crash) { TEST(makecontext, backtrace) { if (IsTiny()) return; // doesn't print full crash report SPAWN(fork); - ASSERT_SYS(0, 0, close(2)); - ASSERT_SYS(0, 2, creat("log", 0644)); - __klog_handle = 2; + if (IsWindows()) { + __klog_handle = + CreateFile(u"log", kNtFileAppendData, + kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete, 0, + kNtOpenAlways, kNtFileAttributeNormal, 0); + } else { + __klog_handle = creat("log", 0644); + } getcontext(&uc); uc.uc_link = 0; uc.uc_stack.ss_sp = NewCosmoStack(); diff --git a/test/libc/thread/test.mk b/test/libc/thread/test.mk index 9c0a662b7..4391bc2cd 100644 --- a/test/libc/thread/test.mk +++ b/test/libc/thread/test.mk @@ -29,6 +29,7 @@ TEST_LIBC_THREAD_DIRECTDEPS = \ LIBC_LOG \ LIBC_MEM \ LIBC_NEXGEN32E \ + LIBC_NT_KERNEL32 \ LIBC_PROC \ LIBC_RUNTIME \ LIBC_SOCK \ diff --git a/third_party/make/config.h b/third_party/make/config.h index 5411073dc..a94336401 100644 --- a/third_party/make/config.h +++ b/third_party/make/config.h @@ -286,12 +286,6 @@ /* Define to 1 if you have the `pipe' function. */ #define HAVE_PIPE 1 -/* Define to 1 if you have the `posix_spawn' function. */ -#define HAVE_POSIX_SPAWN 1 - -/* Define to 1 if you have the `posix_spawnattr_setsigmask' function. */ -#define HAVE_POSIX_SPAWNATTR_SETSIGMASK 1 - /* Define to 1 if you have the `pselect' function. */ #define HAVE_PSELECT 1 diff --git a/third_party/make/dirname.h b/third_party/make/dirname.h index dc238bdce..07d6bee16 100644 --- a/third_party/make/dirname.h +++ b/third_party/make/dirname.h @@ -20,7 +20,7 @@ #ifndef DIRNAME_H_ # define DIRNAME_H_ 1 -#include "third_party/make/dosname.h" +#include "third_party/make/filename.h" # ifndef DIRECTORY_SEPARATOR # define DIRECTORY_SEPARATOR '/' diff --git a/third_party/make/dosname.h b/third_party/make/dosname.h deleted file mode 100644 index add963f70..000000000 --- a/third_party/make/dosname.h +++ /dev/null @@ -1,53 +0,0 @@ -/* clang-format off */ -/* File names on MS-DOS/Windows systems. - - Copyright (C) 2000-2001, 2004-2006, 2009-2020 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - - From Paul Eggert and Jim Meyering. */ - -#ifndef _DOSNAME_H -#define _DOSNAME_H - -#if (defined _WIN32 || defined __CYGWIN__ \ - || defined __EMX__ || defined __MSDOS__ || defined __DJGPP__) - /* This internal macro assumes ASCII, but all hosts that support drive - letters use ASCII. */ -# define _IS_DRIVE_LETTER(C) (((unsigned int) (C) | ('a' - 'A')) - 'a' \ - <= 'z' - 'a') -# define FILE_SYSTEM_PREFIX_LEN(Filename) \ - (_IS_DRIVE_LETTER ((Filename)[0]) && (Filename)[1] == ':' ? 2 : 0) -# ifndef __CYGWIN__ -# define FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE 1 -# endif -# define ISSLASH(C) ((C) == '/' || (C) == '\\') -#else -# define FILE_SYSTEM_PREFIX_LEN(Filename) 0 -# define ISSLASH(C) ((C) == '/') -#endif - -#ifndef FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE -# define FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE 0 -#endif - -#if FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE -# define IS_ABSOLUTE_FILE_NAME(F) ISSLASH ((F)[FILE_SYSTEM_PREFIX_LEN (F)]) -# else -# define IS_ABSOLUTE_FILE_NAME(F) \ - (ISSLASH ((F)[0]) || FILE_SYSTEM_PREFIX_LEN (F) != 0) -#endif -#define IS_RELATIVE_FILE_NAME(F) (! IS_ABSOLUTE_FILE_NAME (F)) - -#endif /* DOSNAME_H_ */ diff --git a/third_party/make/filename.h b/third_party/make/filename.h index 09f69601a..beb24dd13 100644 --- a/third_party/make/filename.h +++ b/third_party/make/filename.h @@ -29,23 +29,13 @@ extern "C" { it may be concatenated to a directory pathname. IS_PATH_WITH_DIR(P) tests whether P contains a directory specification. */ -#if defined _WIN32 || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__ - /* Native Windows, Cygwin, OS/2, DOS */ -# define ISSLASH(C) ((C) == '/' || (C) == '\\') -# define HAS_DEVICE(P) \ - ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \ - && (P)[1] == ':') -# define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P)) -# define IS_PATH_WITH_DIR(P) \ - (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P)) -# define FILE_SYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0) -#else - /* Unix */ # define ISSLASH(C) ((C) == '/') -# define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0]) -# define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL) -# define FILE_SYSTEM_PREFIX_LEN(P) 0 -#endif +# define HAS_DEVICE(Filename) ((void) (Filename), 0) +# define FILE_SYSTEM_PREFIX_LEN(Filename) ((void) (Filename), 0) +# define FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE 0 +# define IS_ABSOLUTE_FILE_NAME(Filename) ISSLASH ((Filename)[0]) +# define IS_RELATIVE_FILE_NAME(Filename) (! ISSLASH ((Filename)[0])) +# define IS_FILE_NAME_WITH_DIR(Filename) (strchr ((Filename), '/') != NULL) #ifdef __cplusplus diff --git a/third_party/make/findprog-in.c b/third_party/make/findprog-in.c index 50758700c..826b766f3 100644 --- a/third_party/make/findprog-in.c +++ b/third_party/make/findprog-in.c @@ -20,6 +20,9 @@ #include "libc/errno.h" #include "libc/str/str.h" #include "libc/mem/mem.h" +#include "third_party/make/filename.h" +#include "libc/calls/struct/stat.h" +#include "libc/sysv/consts/s.h" #include "third_party/make/config.h" /* Specification. */ @@ -58,8 +61,8 @@ static const char * const suffixes[] = /* Note: The cmd.exe program does a different lookup: It searches according to the PATHEXT environment variable. See . - Also, it executes files ending .bat and .cmd directly without letting the - kernel interpret the program file. */ + Also, it executes files ending in .bat and .cmd directly without letting + the kernel interpret the program file. */ #elif defined __CYGWIN__ "", ".exe", ".com" #elif defined __EMX__ @@ -73,7 +76,7 @@ static const char * const suffixes[] = const char * find_in_given_path (const char *progname, const char *path, - bool optimize_for_exec) + const char *directory, bool optimize_for_exec) { { bool has_slash = false; @@ -101,6 +104,12 @@ find_in_given_path (const char *progname, const char *path, with such a suffix is actually executable. */ int failure_errno; size_t i; + + const char *directory_as_prefix = + (directory != NULL && IS_RELATIVE_FILE_NAME (progname) + ? directory + : ""); + #if defined _WIN32 && !defined __CYGWIN__ /* Native Windows */ const char *progbasename; @@ -112,6 +121,8 @@ find_in_given_path (const char *progname, const char *path, if (ISSLASH (*p)) progbasename = p + 1; } + + bool progbasename_has_dot = (strchr (progbasename, '.') != NULL); #endif /* Try all platform-dependent suffixes. */ @@ -123,12 +134,16 @@ find_in_given_path (const char *progname, const char *path, #if defined _WIN32 && !defined __CYGWIN__ /* Native Windows */ /* File names without a '.' are not considered executable, and for file names with a '.' no additional suffix is tried. */ - if ((*suffix != '\0') != (strchr (progbasename, '.') != NULL)) + if ((*suffix != '\0') != progbasename_has_dot) #endif { - /* Concatenate progname and suffix. */ + /* Concatenate directory_as_prefix, progname, suffix. */ char *progpathname = - xconcatenated_filename ("", progname, suffix); + concatenated_filename (directory_as_prefix, progname, + suffix); + + if (progpathname == NULL) + return NULL; /* errno is set here */ /* On systems which have the eaccess() system call, let's use it. On other systems, let's hope that this program @@ -136,14 +151,26 @@ find_in_given_path (const char *progname, const char *path, call access() despite its design flaw. */ if (eaccess (progpathname, X_OK) == 0) { - /* Found! */ - if (strcmp (progpathname, progname) == 0) + /* Check that the progpathname does not point to a + directory. */ + struct stat statbuf; + + if (stat (progpathname, &statbuf) >= 0) { - free (progpathname); - return progname; + if (! S_ISDIR (statbuf.st_mode)) + { + /* Found! */ + if (strcmp (progpathname, progname) == 0) + { + free (progpathname); + return progname; + } + else + return progpathname; + } + + errno = EACCES; } - else - return progpathname; } if (errno != ENOENT) @@ -152,6 +179,36 @@ find_in_given_path (const char *progname, const char *path, free (progpathname); } } + #if defined _WIN32 && !defined __CYGWIN__ /* Native Windows */ + if (failure_errno == ENOENT && !progbasename_has_dot) + { + /* In the loop above, we skipped suffix = "". Do this loop + round now, merely to provide a better errno than ENOENT. */ + + char *progpathname = + concatenated_filename (directory_as_prefix, progname, ""); + + if (progpathname == NULL) + return NULL; /* errno is set here */ + + if (eaccess (progpathname, X_OK) == 0) + { + struct stat statbuf; + + if (stat (progpathname, &statbuf) >= 0) + { + if (! S_ISDIR (statbuf.st_mode)) + errno = ENOEXEC; + else + errno = EACCES; + } + } + + failure_errno = errno; + + free (progpathname); + } + #endif errno = failure_errno; return NULL; @@ -165,17 +222,26 @@ find_in_given_path (const char *progname, const char *path, path = ""; { - int failure_errno; /* Make a copy, to prepare for destructive modifications. */ - char *path_copy = xstrdup (path); + char *path_copy = strdup (path); + if (path_copy == NULL) + return NULL; /* errno is set here */ + + int failure_errno; char *path_rest; char *cp; + #if defined _WIN32 && !defined __CYGWIN__ /* Native Windows */ + bool progname_has_dot = (strchr (progname, '.') != NULL); + #endif + failure_errno = ENOENT; for (path_rest = path_copy; ; path_rest = cp + 1) { const char *dir; bool last; + char *dir_as_prefix_to_free; + const char *dir_as_prefix; size_t i; /* Extract next directory in PATH. */ @@ -189,6 +255,25 @@ find_in_given_path (const char *progname, const char *path, if (dir == cp) dir = "."; + /* Concatenate directory and dir. */ + if (directory != NULL && IS_RELATIVE_FILE_NAME (dir)) + { + dir_as_prefix_to_free = + concatenated_filename (directory, dir, NULL); + if (dir_as_prefix_to_free == NULL) + { + /* errno is set here. */ + failure_errno = errno; + goto failed; + } + dir_as_prefix = dir_as_prefix_to_free; + } + else + { + dir_as_prefix_to_free = NULL; + dir_as_prefix = dir; + } + /* Try all platform-dependent suffixes. */ for (i = 0; i < sizeof (suffixes) / sizeof (suffixes[0]); i++) { @@ -197,12 +282,20 @@ find_in_given_path (const char *progname, const char *path, #if defined _WIN32 && !defined __CYGWIN__ /* Native Windows */ /* File names without a '.' are not considered executable, and for file names with a '.' no additional suffix is tried. */ - if ((*suffix != '\0') != (strchr (progname, '.') != NULL)) + if ((*suffix != '\0') != progname_has_dot) #endif { - /* Concatenate dir, progname, and suffix. */ + /* Concatenate dir_as_prefix, progname, and suffix. */ char *progpathname = - xconcatenated_filename (dir, progname, suffix); + concatenated_filename (dir_as_prefix, progname, suffix); + + if (progpathname == NULL) + { + /* errno is set here. */ + failure_errno = errno; + free (dir_as_prefix_to_free); + goto failed; + } /* On systems which have the eaccess() system call, let's use it. On other systems, let's hope that this program @@ -210,25 +303,45 @@ find_in_given_path (const char *progname, const char *path, call access() despite its design flaw. */ if (eaccess (progpathname, X_OK) == 0) { - /* Found! */ - if (strcmp (progpathname, progname) == 0) + /* Check that the progpathname does not point to a + directory. */ + struct stat statbuf; + + if (stat (progpathname, &statbuf) >= 0) { - free (progpathname); + if (! S_ISDIR (statbuf.st_mode)) + { + /* Found! */ + if (strcmp (progpathname, progname) == 0) + { + free (progpathname); - /* Add the "./" prefix for real, that - xconcatenated_filename() optimized away. This - avoids a second PATH search when the caller uses - execl/execv/execlp/execvp. */ - progpathname = - XNMALLOC (2 + strlen (progname) + 1, char); - progpathname[0] = '.'; - progpathname[1] = NATIVE_SLASH; - memcpy (progpathname + 2, progname, - strlen (progname) + 1); + /* Add the "./" prefix for real, that + concatenated_filename() optimized away. + This avoids a second PATH search when the + caller uses execl/execv/execlp/execvp. */ + progpathname = + (char *) malloc (2 + strlen (progname) + 1); + if (progpathname == NULL) + { + /* errno is set here. */ + failure_errno = errno; + free (dir_as_prefix_to_free); + goto failed; + } + progpathname[0] = '.'; + progpathname[1] = NATIVE_SLASH; + memcpy (progpathname + 2, progname, + strlen (progname) + 1); + } + + free (dir_as_prefix_to_free); + free (path_copy); + return progpathname; + } + + errno = EACCES; } - - free (path_copy); - return progpathname; } if (errno != ENOENT) @@ -237,11 +350,49 @@ find_in_given_path (const char *progname, const char *path, free (progpathname); } } + #if defined _WIN32 && !defined __CYGWIN__ /* Native Windows */ + if (failure_errno == ENOENT && !progname_has_dot) + { + /* In the loop above, we skipped suffix = "". Do this loop + round now, merely to provide a better errno than ENOENT. */ + + char *progpathname = + concatenated_filename (dir_as_prefix, progname, ""); + + if (progpathname == NULL) + { + /* errno is set here. */ + failure_errno = errno; + free (dir_as_prefix_to_free); + goto failed; + } + + if (eaccess (progpathname, X_OK) == 0) + { + struct stat statbuf; + + if (stat (progpathname, &statbuf) >= 0) + { + if (! S_ISDIR (statbuf.st_mode)) + errno = ENOEXEC; + else + errno = EACCES; + } + } + + failure_errno = errno; + + free (progpathname); + } + #endif + + free (dir_as_prefix_to_free); if (last) break; } + failed: /* Not found in PATH. */ free (path_copy); diff --git a/third_party/make/findprog.h b/third_party/make/findprog.h index 6d2d5b373..c6f9c8742 100644 --- a/third_party/make/findprog.h +++ b/third_party/make/findprog.h @@ -41,6 +41,10 @@ extern const char *find_in_path (const char *progname); directory. A null PATH is equivalent to an empty PATH, that is, to the singleton list that contains only the current directory. + If DIRECTORY is not NULL, all relative filenames (i.e. PROGNAME when it + contains a slash, and the PATH elements) are considered relative to + DIRECTORY instead of relative to the current directory of this process. + Determines the pathname that would be called by execlp/execvp of PROGNAME. - If successful, it returns a pathname containing a slash (either absolute or relative to the current directory). The returned string can be used @@ -52,6 +56,7 @@ extern const char *find_in_path (const char *progname); - EACCES: means that the program's file cannot be accessed (due to some issue with one of the ancestor directories) or lacks the execute permissions. + - ENOMEM: means out of memory. If OPTIMIZE_FOR_EXEC is true, the function saves some work, under the assumption that the resulting pathname will not be accessed directly, only through execl/execv or execlp/execvp. @@ -60,6 +65,7 @@ extern const char *find_in_path (const char *progname); - On POSIX systems excluding Cygwin: a '/', - On Windows, OS/2, DOS platforms: a '/' or '\'. */ extern const char *find_in_given_path (const char *progname, const char *path, + const char *directory, bool optimize_for_exec); diff --git a/third_party/make/job.c b/third_party/make/job.c index 5003fb91f..198648209 100644 --- a/third_party/make/job.c +++ b/third_party/make/job.c @@ -47,6 +47,7 @@ this program. If not, see . */ #include "libc/macros.internal.h" #include "libc/math.h" #include "libc/nexgen32e/kcpuids.h" +#include "libc/proc/posix_spawn.h" #include "libc/runtime/runtime.h" #include "libc/sock/sock.h" #include "libc/str/str.h" @@ -63,10 +64,14 @@ this program. If not, see . */ #include "libc/x/x.h" #include "third_party/make/commands.h" #include "third_party/make/dep.h" +#include "third_party/make/findprog.h" #include "third_party/make/os.h" #include "third_party/make/variable.h" // clang-format off +#define USE_POSIX_SPAWN (!IsLinux() && !IsOpenbsd()) +#define HAVE_POSIX_SPAWNATTR_SETSIGMASK + #ifdef WINDOWS32 const char *default_shell = "sh.exe"; int no_default_sh_exe = 1; @@ -1891,6 +1896,153 @@ child_execute_job (struct childbase *child, fderr = child->output.err; } + if (USE_POSIX_SPAWN) { + char *cmd; + posix_spawnattr_t attr; + posix_spawn_file_actions_t fa; + short flags = 0; + + if ((r = posix_spawnattr_init (&attr)) != 0) + goto done; + + if ((r = posix_spawn_file_actions_init (&fa)) != 0) + { + posix_spawnattr_destroy (&attr); + goto done; + } + + // [jart] use setrlimit on posix_spawn + // TODO(jart): support landlock make rlimit variables + if (stack_limit.rlim_cur && RLIMIT_STACK < RLIM_NLIMITS) + { + posix_spawnattr_setrlimit (&attr, RLIMIT_STACK, &stack_limit); + flags |= POSIX_SPAWN_SETRLIMIT; + } + + /* Unblock all signals. */ +#ifdef HAVE_POSIX_SPAWNATTR_SETSIGMASK + { + sigset_t mask; + sigemptyset (&mask); + r = posix_spawnattr_setsigmask (&attr, &mask); + if (r != 0) + goto cleanup; + flags |= POSIX_SPAWN_SETSIGMASK; + } +#endif /* have posix_spawnattr_setsigmask() */ + + /* USEVFORK can give significant speedup on systems where it's available. */ +#ifdef POSIX_SPAWN_USEVFORK + flags |= POSIX_SPAWN_USEVFORK; +#endif + + /* For any redirected FD, dup2() it to the standard FD. + They are all marked close-on-exec already. */ + if (fdin >= 0 && fdin != FD_STDIN) + if ((r = posix_spawn_file_actions_adddup2 (&fa, fdin, FD_STDIN)) != 0) + goto cleanup; + if (fdout != FD_STDOUT) + if ((r = posix_spawn_file_actions_adddup2 (&fa, fdout, FD_STDOUT)) != 0) + goto cleanup; + if (fderr != FD_STDERR) + if ((r = posix_spawn_file_actions_adddup2 (&fa, fderr, FD_STDERR)) != 0) + goto cleanup; + + /* We can't use the POSIX_SPAWN_RESETIDS flag: when make is invoked under + restrictive environments like unshare it will fail with EINVAL. */ + + /* Apply the spawn flags. */ + if ((r = posix_spawnattr_setflags (&attr, flags)) != 0) + goto cleanup; + + /* Look up the program on the child's PATH, if needed. */ + { + const char *p = NULL; + char **pp; + + for (pp = child->environment; *pp != NULL; ++pp) + if ((*pp)[0] == 'P' && (*pp)[1] == 'A' && (*pp)[2] == 'T' + && (*pp)[3] == 'H' &&(*pp)[4] == '=') + { + p = (*pp) + 5; + break; + } + + /* execvp() will use a default PATH if none is set; emulate that. */ + if (p == NULL) + { + size_t l = confstr (_CS_PATH, NULL, 0); + if (l) + { + char *dp = alloca (l); + confstr (_CS_PATH, dp, l); + p = dp; + } + } + + cmd = (char *)find_in_given_path (argv[0], p, NULL, 0); + } + + if (!cmd) + { + r = errno; + goto cleanup; + } + + /* Start the program. */ + while ((r = posix_spawn (&pid, cmd, &fa, &attr, argv, + child->environment)) == EINTR) + ; + + /* posix_spawn() doesn't provide sh fallback like exec() does; implement + it here. POSIX doesn't specify the path to sh so use the default. */ + + if (r == ENOEXEC) + { + char **nargv; + char **pp; + size_t l = 0; + + for (pp = argv; *pp != NULL; ++pp) + ++l; + + nargv = xmalloc (sizeof (char *) * (l + 3)); + nargv[0] = (char *)default_shell; + nargv[1] = cmd; + memcpy (&nargv[2], &argv[1], sizeof (char *) * l); + + while ((r = posix_spawn (&pid, nargv[0], &fa, &attr, nargv, + child->environment)) == EINTR) + ; + + free (nargv); + } + + if (r == 0) + { + /* Spawn succeeded but may fail later: remember the command. */ + free (child->cmd_name); + if (cmd != argv[0]) + child->cmd_name = cmd; + else + child->cmd_name = xstrdup(cmd); + } + + cleanup: + posix_spawn_file_actions_destroy (&fa); + posix_spawnattr_destroy (&attr); + + done: + if (r != 0) + pid = -1; + + if (pid < 0) + OSS (error, NILF, "%s: %s", argv[0], strerror (r)); + + return pid; + + } // USE_POSIX_SPAWN + pid = fork(); if (pid != 0) return pid; @@ -2446,17 +2598,23 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, shell = default_shell; /* [jart] remove code that forces slow path if not using /bin/sh */ + /* else if (strcmp (shell, default_shell)) */ + /* goto slow; */ if (ifs) for (cap = ifs; *cap != '\0'; ++cap) - if (*cap != ' ' && *cap != '\t' && *cap != '\n') + if (*cap != ' ' && *cap != '\t' && *cap != '\n') { + // kprintf("slow because whitespace\n"); goto slow; + } if (shellflags) if (shellflags[0] != '-' || ((shellflags[1] != 'c' || shellflags[2] != '\0') - && (shellflags[1] != 'e' || shellflags[2] != 'c' || shellflags[3] != '\0'))) + && (shellflags[1] != 'e' || shellflags[2] != 'c' || shellflags[3] != '\0'))) { + // kprintf("slow because shell flags\n"); goto slow; + } i = strlen (line) + 1; @@ -2515,18 +2673,21 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, If we see any of those, punt. But on MSDOS, if we use COMMAND.COM, double and single quotes have the same effect. */ - else if (instring == '"' && strchr ("\\$`", *p) != 0 && unixy_shell) + else if (instring == '"' && strchr ("\\$`", *p) != 0 && unixy_shell) { + // kprintf("slow because backslash\n"); goto slow; - else + } else *ap++ = *p; } - else if (strchr (sh_chars, *p) != 0) + else if (strchr (sh_chars, *p) != 0) { /* Not inside a string, but it's a special char. */ + // kprintf("slow because %#c found in %#s\n", *p, line); goto slow; - else if (one_shell && *p == '\n') + } else if (one_shell && *p == '\n') { /* In .ONESHELL mode \n is a separator like ; or && */ + // kprintf("slow because oneshell thing\n"); goto slow; - else + } else /* Not a special char. */ switch (*p) { @@ -2535,8 +2696,10 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, first word with no equals sign in it. This is not the case with sh -k, but we never get here when using nonstandard shell flags. */ - if (! seen_nonequals && unixy_shell) + if (! seen_nonequals && unixy_shell) { + // kprintf("slow because nonequals\n"); goto slow; + } word_has_equals = 1; *ap++ = '='; break; @@ -2590,10 +2753,12 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, /* Update SEEN_NONEQUALS, which tells us if every word heretofore has contained an '='. */ seen_nonequals |= ! word_has_equals; - if (word_has_equals && ! seen_nonequals) + if (word_has_equals && ! seen_nonequals) { /* An '=' in a word before the first word without one is magical. */ + // kprintf("slow because word equals\n"); goto slow; + } word_has_equals = 0; /* Prepare for the next word. */ /* If this argument is the command name, @@ -2604,8 +2769,10 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, int j; for (j = 0; sh_cmds[j] != 0; ++j) { - if (streq (sh_cmds[j], new_argv[0])) + if (streq (sh_cmds[j], new_argv[0])) { + // kprintf("slow because builtin shell commands\n"); goto slow; + } } } @@ -2621,9 +2788,11 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, } end_of_line: - if (instring) + if (instring) { /* Let the shell deal with an unterminated quote. */ + // kprintf("slow because unterminated quote\n"); goto slow; + } /* Terminate the last argument and the argument list. */ @@ -2636,8 +2805,10 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, { int j; for (j = 0; sh_cmds[j] != 0; ++j) - if (streq (sh_cmds[j], new_argv[0])) + if (streq (sh_cmds[j], new_argv[0])) { + // kprintf("slow because sh_cmds\n"); goto slow; + } } if (new_argv[0] == 0) diff --git a/third_party/make/main.c b/third_party/make/main.c index 2bcd304e8..64697f8c0 100644 --- a/third_party/make/main.c +++ b/third_party/make/main.c @@ -971,7 +971,7 @@ reset_jobserver (void) int main (int argc, char **argv, char **envp) { - ShowCrashReports(); + // ShowCrashReports(); static char *stdin_nm = 0; int makefile_status = MAKE_SUCCESS; @@ -982,7 +982,7 @@ main (int argc, char **argv, char **envp) int argv_slots; // [jart] workaround to prevent make -j fork bomb - default_load_average = __get_cpu_count(); + default_load_average = __get_cpu_count() * 1.5; max_load_average = default_load_average; /* Useful for attaching debuggers, etc. */ @@ -1042,10 +1042,6 @@ main (int argc, char **argv, char **envp) #undef FATAL_SIG -#ifndef NDEBUG - ShowCrashReports(); -#endif - /* Do not ignore the child-death signal. This must be done before any children could possibly be created; otherwise, the wait functions won't work on systems with the SVR4 ECHILD brain diff --git a/third_party/make/make.mk b/third_party/make/make.mk index 760a17dde..2bbb13933 100644 --- a/third_party/make/make.mk +++ b/third_party/make/make.mk @@ -29,7 +29,6 @@ THIRD_PARTY_MAKE_HDRS = \ third_party/make/job.h \ third_party/make/unistd.h \ third_party/make/getprogname.h \ - third_party/make/dosname.h \ third_party/make/config.h \ third_party/make/concat-filename.h \ third_party/make/findprog.h \ diff --git a/third_party/mbedtls/aesni.c b/third_party/mbedtls/aesni.c index 9695477a1..cc1d6a36b 100644 --- a/third_party/mbedtls/aesni.c +++ b/third_party/mbedtls/aesni.c @@ -130,8 +130,8 @@ int mbedtls_aesni_crypt_ecb( mbedtls_aes_context *ctx, */ void mbedtls_aesni_gcm_mult( unsigned char a[16], const uint64_t b[2] ) { - uint64_t aa _Vector_size(16) forcealign(16); - uint64_t bb _Vector_size(16) forcealign(16); + uint64_t aa __attribute__((__vector_size__(16), __aligned__(16))); + uint64_t bb __attribute__((__vector_size__(16), __aligned__(16))); /* The inputs are in big-endian order, so byte-reverse them */ aa[0] = READ64BE(a+8); diff --git a/third_party/nsync/futex.c b/third_party/nsync/futex.c index 7d6513418..f34de99c4 100644 --- a/third_party/nsync/futex.c +++ b/third_party/nsync/futex.c @@ -169,11 +169,9 @@ static int nsync_futex_wait_win32_ (atomic_int *w, int expect, char pshare, return 0; } if (pt) atomic_store_explicit (&pt->pt_blocker, w, memory_order_release); - if (_check_cancel () == -1) return -1; if (_check_signal (false) == -1) return -1; ok = WaitOnAddress (w, &expect, sizeof(int), timespec_tomillis (wait)); - if (_check_signal (false) == -1) { _check_cancel (); return -1; } - if (_check_cancel () == -1) return -1; + if (_check_signal (false) == -1) return -1; if (ok) { return 0; } else { diff --git a/tool/build/build.mk b/tool/build/build.mk index 7d1b0d74b..46a801555 100644 --- a/tool/build/build.mk +++ b/tool/build/build.mk @@ -108,6 +108,7 @@ o/$(MODE)/tool/build/dso/sandbox.so: \ -s \ -shared \ -nostdlib \ + -fuse-ld=bfd \ -Wl,--gc-sections \ o/$(MODE)/tool/build/dso/sandbox.o \ o/$(MODE)/libc/calls/pledge-linux.o \ diff --git a/tool/emacs/cosmo-stuff.el b/tool/emacs/cosmo-stuff.el index 42648c5c7..278d3b67b 100644 --- a/tool/emacs/cosmo-stuff.el +++ b/tool/emacs/cosmo-stuff.el @@ -25,8 +25,23 @@ (require 'ld-script) (require 'make-mode) -(setq cosmo-dbg-mode "dbg") -(setq cosmo-default-mode "") +(setq cosmo-arch + (let ((arch (string-trim-right + (shell-command-to-string + "uname -m")))) + (cond ((string= arch "amd64") "x86_64") + ((string= arch "arm64") "aarch64") + (t arch)))) + +(setq cosmo-default-mode + (cond ((string= cosmo-arch "aarch64") "aarch64") + (t ""))) + +;; TODO(jart): How do we get GCC to do only dead code elimination? +(setq cosmo-dbg-mode + (cond ((string= cosmo-arch "aarch64") "aarch64") + (t "dbg"))) + (setq c-doc-comment-style 'javadown) (add-to-list 'auto-mode-alist '("\\.x$" . c-mode)) ;; -aux-info @@ -161,14 +176,23 @@ (cosmo-startswith "test/" pkg)))) (defun cosmo--make-mode (arg &optional default) - (cond ((eq arg 1) "tiny") + (cond ((eq arg 1) + (cond ((string= cosmo-arch "aarch64") "aarch64-tiny") + (t "tiny"))) ((eq arg 2) "opt") ((eq arg 3) "rel") - ((eq arg 4) cosmo-dbg-mode) - ((eq arg 5) "") + ((eq arg 4) + cosmo-dbg-mode) + ((eq arg 5) + (cond ((string= cosmo-arch "aarch64") "aarch64") + (t cosmo-default-mode))) ((eq arg 6) "llvm") - ((eq arg 7) "aarch64") - ((eq arg 8) "aarch64-tiny") + ((eq arg 7) + (cond ((string= cosmo-arch "aarch64") "x86_64") + (t "aarch64"))) + ((eq arg 8) + (cond ((string= cosmo-arch "aarch64") "tiny") + (t "aarch64-tiny"))) (default default) ((cosmo-intest) cosmo-dbg-mode) (t cosmo-default-mode)))