Compare commits

..
58 Commits
Author SHA1 Message Date
Justine Tunney 52f1db7220 Release Cosmopolitan v2.2 2022-11-07 02:29:47 -08:00
Justine Tunney c995838e5c Make improvements
- Clean up sigaction() code
- Add a port scanner example
- Introduce a ParseCidr() API
- Clean up our futex abstraction code
- Fix a harmless integer overflow in ParseIp()
- Use kernel semaphores on NetBSD to make threads much faster
2022-11-07 02:26:06 -08:00
Justine Tunney 539bddce8c Fix regression in documentation page 2022-11-06 01:16:29 -07:00
Justine Tunney 002df0f16c Fix regression in MODE=asan build 2022-11-06 01:05:13 -07:00
Justine Tunney be16bcdcd3 Fix missing Makefile dependency 2022-11-06 01:01:34 -07:00
tkchia cb9a0466f1 Work towards zipos / open(argv[0]) on metal (#667) 2022-11-06 00:29:47 -07:00
Danny Robinson 543c93f623 bestline keybindings and redbean definitions (#678)
* Add ctrl-left/right keys to bestline
* Update redbean API definitions
2022-11-06 00:28:08 -07:00
Justine Tunney 3f0bcdc3ef Improve cancellations, randomness, and time
- Exhaustively document cancellation points
- Rename SIGCANCEL to SIGTHR just like BSDs
- Further improve POSIX thread cancellations
- Ensure asynchronous cancellations work correctly
- Elevate the quality of getrandom() and getentropy()
- Make futexes cancel correctly on OpenBSD 6.x and 7.x
- Add reboot.com and shutdown.com to examples directory
- Remove underscore prefix from awesome timespec_*() APIs
- Create assertions that help verify our cancellation points
- Remove bad timespec APIs (cmp generalizes eq/ne/gt/gte/lt/lte)
2022-11-05 23:45:32 -07:00
Justine Tunney 0d7c265392 Fix backtraces on cancellation points 2022-11-04 20:22:13 -07:00
Justine Tunney 022536cab6 Make futexes cancellable by pthreads 2022-11-04 18:36:34 -07:00
Justine Tunney 2278327eba Implement support for POSIX thread cancellations
This change makes some miracle modifications to the System Five system
call support, which lets us have safe, correct, and atomic handling of
thread cancellations. It all turned out to be cheaper than anticipated
because it wasn't necessary to modify the system call veneers. We were
able to encode the cancellability of each system call into the magnums
found in libc/sysv/syscalls.sh. Since cancellations are so waq, we are
also supporting a lovely Musl Libc mask feature for raising ECANCELED.
2022-11-04 01:04:43 -07:00
Justine Tunney 37d40e087f Ignore SIGSYS on BSD by default 2022-11-03 09:32:12 -07:00
Justine Tunney 179e048bba Make some small fixes to recent changes 2022-11-03 05:45:33 -07:00
Justine Tunney c2590cf7a0 Make cosmo.ftrace() in Python easier to use 2022-11-03 01:12:25 -07:00
Justine Tunney 89d1e5b8f2 Rearrange code and make a faster sha256sum program 2022-11-02 23:19:16 -07:00
Justine Tunney 5e60e5ad10 Release redbean v2.2 2022-11-02 09:52:54 -07:00
Justine Tunney 6b06a8176d Fix some glitches in redbean
This change includes a fix to Fetch() where an out of bounds memory read
could happen, when the reverse proxied endpoint omits the content-length
header. This caused a bunch of NUL chars to appear on TurfWar's /statusz
since it wouldn't actually overrun the buffer, and if it did it would've
been caught by MODE=asan builds.
2022-11-02 09:46:34 -07:00
Justine Tunney 14d036b68d Add WSL to test fleet
All tests pass now under WSL2. They should pass under WSL1 too, but only
WSL2 is integrated into the test fleet right now. This change also fills
in some gaps in the error numbers.

Fixes #665
2022-11-02 06:49:42 -07:00
Justine Tunney fae0c0286f Workaround WSL not supporting x87 in ucontext_t 2022-11-02 03:20:39 -07:00
Justine Tunney d6ff4c754e Workaround WSL misconfiguring the x87 FPU 2022-11-02 02:17:14 -07:00
Justine Tunney f44d88707e Workaround sendfile() bug in WSL 2022-11-02 02:17:03 -07:00
Justine Tunney fc96af058b Workaround MAP_GROWSDOWN unavailability on WSL 2022-11-02 01:38:06 -07:00
Justine Tunney bd6069deb5 Remove old code from Landlock Make 2022-11-02 00:55:05 -07:00
Justine Tunney e9735a7738 Release landlock make 1.5 2022-11-01 23:52:38 -07:00
Stephen M. Cameron 0ea10c8631 Add useconds_t type to weirdtypes.h 2022-11-01 23:28:26 -07:00
Justine Tunney e522aa3a07 Make more threading improvements
- ASAN memory morgue is now lockless
- Make C11 atomics header more portable
- Rewrote pthread keys support to be lockless
- Simplify Python's unicode table unpacking code
- Make crash report write(2) closer to being atomic
- Make it possible to strace/ftrace a single thread
- ASAN now checks nul-terminated strings fast and properly
- Windows fork() now restores TLS memory of calling thread
2022-11-01 23:28:26 -07:00
Paul Kulchenko d7b88734cd Make redbean compress w/o explicit content-type (#671) 2022-11-01 23:15:20 -07:00
Gavin Hayes da8f5009fd Make Windows fcntl() and lseek() fixes (#668)
* F_SETFD should always return 0 on success
* F_SETFL is not implemented on nt
* nt lseek, error with ESPIPE when attempting on socket
2022-11-01 23:14:14 -07:00
mattx ef9776755e blackholed: allow changing iptables chain (#670)
* Make blackholed use its own chain

This makes blackholed interfere less with any existing iptables raw table configurations.

* Allow specifying iptables chain at runtime

blackholed will now insert blocks to the PREROUTING chain by default,
with a runtime switch to change it to another chain
2022-10-20 10:19:27 -07:00
Justine Tunney da336b3ea8 Make some more fixes to prod 2022-10-19 13:10:24 -07:00
Justine Tunney 69bee64a59 Make some last minute production changes 2022-10-19 10:00:29 -07:00
Justine Tunney f7ff77d865 Make fixes and improvements
- Invent iso8601us() for faster timestamps
- Improve --strace descriptions of sigset_t
- Rebuild the Landlock Make bootstrap binary
- Introduce MODE=sysv for non-Windows builds
- Permit OFD fcntl() locks under pledge(flock)
- redbean can now protect your kernel from ddos
- Have vfork() fallback to sys_fork() not fork()
- Change kmalloc() to not die when out of memory
- Improve documentation for some termios functions
- Rewrite putenv() and friends to conform to POSIX
- Fix linenoise + strace verbosity issue on Windows
- Fix regressions in our ability to show backtraces
- Change redbean SetHeader() to no-op if value is nil
- Improve fcntl() so SQLite locks work in non-WAL mode
- Remove some unnecessary work during fork() on Windows
- Create redbean-based SSL reverse proxy for IPv4 TurfWar
- Fix ape/apeinstall.sh warning when using non-bash shells
- Add ProgramTrustedIp(), and IsTrustedIp() APIs to redbean
- Support $PWD, $UID, $GID, and $EUID in command interpreter
- Introduce experimental JTqFpD APE prefix for non-Windows builds
- Invent blackhole daemon for firewalling IP addresses via UNIX named socket
- Add ProgramTokenBucket(), AcquireToken(), and CountTokens() APIs to redbean
2022-10-19 07:19:19 -07:00
Justine Tunney 648bf6555c Reimport zip into third party 2022-10-16 13:39:41 -07:00
Justine Tunney 60cb435cb4 Implement pthread_atfork()
If threads are being used, then fork() will now acquire and release and
runtime locks so that fork() may be safely used from threads. This also
makes vfork() thread safe, because pthread mutexes will do nothing when
the process is a child of vfork(). More torture tests have been written
to confirm this all works like a charm. Additionally:

- Invent hexpcpy() api
- Rename nsync_malloc_() to kmalloc()
- Complete posix named semaphore implementation
- Make pthread_create() asynchronous signal safe
- Add rm, rmdir, and touch to command interpreter builtins
- Invent sigisprecious() and modify sigset functions to use it
- Add unit tests for posix_spawn() attributes and fix its bugs

One unresolved problem is the reclaiming of *NSYNC waiter memory in the
forked child processes, within apps which have threads waiting on locks
2022-10-16 12:25:13 -07:00
Justine Tunney 64c284003d Fix MODE=opt build 2022-10-14 16:49:16 -07:00
Justine Tunney 3d2d04b25e Make cli commands yoinkable into cosmo shell
This lets our system() and popen() commands function sort of like
BusyBox and ToyBox. By default the Cosmopolitan Shell is lightweight.
But if you use STATIC_YOINK then you can pull the individual commands
you want into the linkage, and they'll be included in a single binary.
For example the demo binary embeds `tr` and `sed` and ends up ~140kb.
2022-10-14 16:37:29 -07:00
Justine Tunney 5af19b7eed Make some foss compatibility improvements 2022-10-14 13:59:34 -07:00
Justine Tunney 8111462789 Add posix semaphores support
There's still some bugs to work out on Windows and OpenBSD.
2022-10-14 09:21:02 -07:00
Justine Tunney f52f65b2e3 Make system() and popen() thread safe 2022-10-13 15:54:05 -07:00
Justine Tunney 997ce29ddc Elevate Windows production worthiness
- SQLite file locking now works on Windows
- SQLite will now use fdatasync() on non-Apple platforms
- Fix Ctrl-C handler on Windows to not crash with TLS
- Signals now work in multithreaded apps on Windows
- fcntl() will now accurately report EINVAL errors
- fcntl() now has excellent --strace logging
- Token bucket replenish now go 100x faster
- *NSYNC cancellations now work on Windows
- Support closefrom() on NetBSD
2022-10-13 13:44:41 -07:00
tkchia d38700687a [metal] Allow more fine-grained control over page permissions (#663)
- use PAGE_RSRV bit (originally only for blinkenlights),
  rather than PAGE_V bit, to indicate that a virtual address
  page has been reserved — this should allow a program to
  create & reserve inaccessible "guard pages"
- mark page table entries for non-code pages with PAGE_XD bit,
  which should be supported on (circa) post-2004 x86-64 CPUs
2022-10-12 11:07:11 -07:00
Justine Tunney 0f89140882 Further improve cocmd interpreter 2022-10-12 10:44:54 -07:00
Justine Tunney 0cee831da3 Revamp posix_spawn() implementation 2022-10-12 05:26:58 -07:00
Justine Tunney b41f91c658 Greatly expand system() shell code features
The cosmopolitan command interpreter now has 13 builtin commands,
variable support, support for ; / && / || syntax, asynchronous support,
and plenty of unit tests with bug fixes.

This change fixes a bug in posix_spawn() with null envp arg. strace
logging now uses atomic writes for scatter functions. Breaking change
renaming GetCpuCount() to _getcpucount(). TurfWar is now updated to use
the new token bucket algorithm. WIN32 affinity masks now inherit across
fork() and execve().
2022-10-11 21:30:31 -07:00
Justine Tunney e7329b7cba Implement atomic swar token bucket library 2022-10-11 21:22:04 -07:00
Justine Tunney c19ac8729d Reinvent the classic unix wall command 2022-10-11 21:22:03 -07:00
Connor 9d2f993364 Fix make sandboxing logic for .STRICT mode (#661)
Patch segfaults and handle the `.STRICT = 0` case.
2022-10-11 21:16:03 -07:00
tkchia 31dab8a75d [metal] Fix bug: do not initialize IDT & TSS if unneeded (#654)
libc/intrin/interrupts.S should not be linked in unless
an IDT (or TSS) is explicitly requested somewhere (i.e.
it should probably not be a mandatory module).
2022-10-10 20:54:46 -07:00
tkchiaandtkchia 7a06760e6f Rename LINUX to _HOSTLINUX etc. to reduce clashes (#655)
Co-authored-by: tkchia <[email protected]>
2022-10-10 20:31:25 -07:00
Connor 9209ea63a7 Integrate upstream dash changes into unbourne shell (#656) 2022-10-10 20:29:28 -07:00
Malcolm Seyd 84b9b8ed87 Fix ParseHttpMessage failing to store >2 repeatable headers (#657) 2022-10-10 20:17:17 -07:00
Justine Tunney e557058ac8 Improve cosmo's conformance to libc-test
This change addresses various open source compatibility issues, so that
we pass 313/411 of the tests in https://github.com/jart/libc-test where
earlier today we were passing about 30/411 of them, due to header toil.
Please note that Glibc only passes 341/411 so 313 today is pretty good!

- Make the conformance of libc/isystem/ headers nearly perfect
- Import more of the remaining math library routines from Musl
- Fix inconsistencies with type signatures of calls like umask
- Write tests for getpriority/setpriority which work great now
- conform to `struct sockaddr *` on remaining socket functions
- Import a bunch of uninteresting stdlib functions e.g. rand48
- Introduce readdir_r, scandir, pthread_kill, sigsetjmp, etc..

Follow the instructions in our `tool/scripts/cosmocc` toolchain to run
these tests yourself. You use `make CC=cosmocc` on the test repository
2022-10-10 17:52:41 -07:00
Justine Tunney 467a332e38 Introduce sigtimedwait() and sigwaitinfo()
This change also invents sigcountset() and strsignal_r() and improves
the quality of siginfo_t handling.
2022-10-10 07:39:44 -07:00
Justine Tunney 7ae556463a Rename rand64() to _rand64() 2022-10-10 04:12:06 -07:00
Justine Tunney c424352a0a Disable make sandobxing unless .STRICT=1
This change makes Landlock Make backwards compatible.
2022-10-10 03:49:58 -07:00
Justine Tunney d5910e2673 Fix bugs and make code tinier
- Fixed bug where stdio eof wasn't being sticky
- Fixed bug where fseeko() wasn't clearing eof state
- Removed assert() usage from libc favoring _unassert() / _npassert()
2022-10-09 23:21:34 -07:00
Justine Tunney 9b7c8db846 Perform some code maintenance
- Change IDT code so kprintf() isn't mandatory dependency
- Document current intentions around pthread_cancel()
- Make _npassert() an _unassert() in MODE=tiny
2022-10-09 13:00:46 -07:00
Justine Tunney 4a6fd3d910 Make more improvements to threading support
- fix rare thread exit race condition on openbsd
- pthread_getattr_np() now supplies detached status
- child threads may now pthread_join() the main thread
- introduce sigandset(), sigorset(), and sigisemptyset()
- introduce pthread_cleanup_push() and pthread_cleanup_pop()
2022-10-09 00:08:47 -07:00
1379 changed files with 29629 additions and 9192 deletions

No files matched your search

+17 -5
View File
@@ -60,8 +60,8 @@
# build/config.mk
SHELL = build/bootstrap/cocmd.com
HOSTS ?= freebsd openbsd netbsd rhel7 rhel5 win10 xnu
MAKEFLAGS += -j --no-builtin-rules
HOSTS ?= freebsd openbsd netbsd rhel7 rhel5 xnu win10 win10:31336
MAKEFLAGS += --no-builtin-rules
.SUFFIXES:
.DELETE_ON_ERROR:
@@ -92,6 +92,7 @@ o/$(MODE): \
.UNVEIL = \
libc/integral \
libc/disclaimer.inc \
rwc:/dev/shm \
rx:build/bootstrap \
rx:o/third_party/gcc \
/proc/stat \
@@ -121,11 +122,13 @@ include third_party/compiler_rt/compiler_rt.mk # │
include libc/str/str.mk # │
include third_party/xed/xed.mk # │
include third_party/zlib/zlib.mk # │
include third_party/double-conversion/dc.mk # │
include libc/elf/elf.mk # │
include ape/ape.mk # │
include libc/fmt/fmt.mk # │
include libc/vga/vga.mk #─┘
include libc/calls/calls.mk #─┐
include third_party/getopt/getopt.mk # │
include libc/runtime/runtime.mk # ├──SYSTEMS RUNTIME
include libc/crt/crt.mk # │ You can issue system calls
include third_party/nsync/nsync.mk # │
@@ -149,7 +152,6 @@ include dsp/mpeg/mpeg.mk # │
include dsp/dsp.mk # │
include third_party/zlib/gz/gz.mk # │
include third_party/musl/musl.mk # │
include third_party/getopt/getopt.mk # │
include libc/libc.mk #─┘
include libc/sock/sock.mk #─┐
include dsp/tty/tty.mk # ├──ONLINE RUNTIME
@@ -168,8 +170,9 @@ include test/tool/args/test.mk
include third_party/linenoise/linenoise.mk
include third_party/maxmind/maxmind.mk
include net/finger/finger.mk
include third_party/double-conversion/double-conversion.mk
include third_party/double-conversion/test/test.mk
include third_party/lua/lua.mk
include third_party/tr/tr.mk
include third_party/sed/sed.mk
include third_party/awk/awk.mk
include third_party/make/make.mk
@@ -309,7 +312,7 @@ COSMOPOLITAN_OBJECTS = \
THIRD_PARTY_GDTOA \
THIRD_PARTY_REGEX \
LIBC_THREAD \
THIRD_PARTY_NSYNC_MALLOC \
THIRD_PARTY_NSYNC_MEM \
LIBC_MEM \
THIRD_PARTY_DLMALLOC \
LIBC_RUNTIME \
@@ -402,6 +405,15 @@ $(SRCS): \
libc/integral/lp64arg.inc \
libc/integral/lp64.inc
.PHONY: toolchain
toolchain: o/cosmopolitan.h \
o/$(MODE)/ape/public/ape.lds \
o/$(MODE)/libc/crt/crt.o \
o/$(MODE)/ape/ape.o \
o/$(MODE)/ape/ape-copy-self.o \
o/$(MODE)/ape/ape-no-modify-self.o \
o/$(MODE)/cosmopolitan.a
# UNSPECIFIED PREREQUISITES TUTORIAL
#
# A build rule must exist for all files that make needs to consider in
+7 -3
View File
@@ -23,8 +23,8 @@ If you're doing your development work on Linux or BSD then you need just
five files to get started. Here's what you do on Linux:
```sh
wget https://justine.lol/cosmopolitan/cosmopolitan-amalgamation-2.1.1.zip
unzip cosmopolitan-amalgamation-2.1.1.zip
wget https://justine.lol/cosmopolitan/cosmopolitan-amalgamation-2.2.zip
unzip cosmopolitan-amalgamation-2.2.zip
printf 'main() { printf("hello world\\n"); }\n' >hello.c
gcc -g -Os -static -nostdlib -nostdinc -fno-pie -no-pie -mno-red-zone \
-fno-omit-frame-pointer -pg -mnop-mcount -mno-tls-direct-seg-refs -gdwarf-4 \
@@ -246,12 +246,16 @@ gdb foo.com -ex 'add-symbol-file foo.com.dbg 0x401000'
| AMD | K8 Venus | 2005 |
| Intel | Core | 2006 |
| Linux | 2.6.18 | 2007 |
| Windows | 8 | 2012 |
| Windows | 8 [1] | 2012 |
| Mac OS X | 15.6 | 2018 |
| OpenBSD | 6.4 | 2018 |
| FreeBSD | 13 | 2020 |
| NetBSD | 9.2 | 2021 |
[1] See our [vista branch](https://github.com/jart/cosmopolitan/tree/vista)
for a community supported version of Cosmopolitan that works on Windows
Vista and Windows 7.
## Special Thanks
Funding for this project is crowdsourced using
+26 -14
View File
@@ -35,6 +35,7 @@
#include "ape/macros.internal.h"
#include "ape/notice.inc"
#include "ape/relocations.h"
#include "libc/calls/metalfile.internal.h"
#include "libc/dce.h"
#include "libc/elf/def.h"
#include "libc/macho.internal.h"
@@ -112,7 +113,15 @@ cstr: .endobj cstr,globl,hidden # ←for gdb readability
//
// @param dl is drive number
// @noreturn
ape_mz: .asciz "MZqFpD='\n" # Mark 'Zibo' Joseph Zbikowski
ape_mz:
#if SupportsWindows() || SupportsMetal()
.asciz "MZqFpD='\n" # Mark 'Zibo' Joseph Zbikowski
#else
// Avoid virus scanner reputation damage when targeting System Five.
// WARNING: This prefix is experimental; it may be removed sometime.
// TODO(jart): Find another prefix that will work with BIOS loading.
.asciz "JTqFpD='\n" # Mark 'Zibo' Joseph Zbikowski
#endif
.short 0x1000 # MZ: lowers upper bound load / 16
.short 0xf800 # MZ: roll greed on bss
.short 0 # MZ: lower bound on stack segment
@@ -874,7 +883,7 @@ ape_macho:
.long (520f-510f)/4 # count
510: .quad 0 # rax
.quad IMAGE_BASE_VIRTUAL # rbx
.quad XNU # rcx
.quad _HOSTXNU # rcx
.quad 0 # rdx
.quad 0 # rdi
.quad 0 # rsi
@@ -1285,8 +1294,8 @@ lcheck: pushf # check for i8086 / i8088 / i80186
jl 10f
mov %edi,%eax
cpuid
mov $1<<29,%edi # need nexgen32e long mode support
and %edi,%edx
mov $1<<29|1<<20,%edi # need nexgen32e long mode support
and %edi,%edx # & nx support
cmp %edi,%edx
jne 10f
xor %ax,%ax
@@ -1415,7 +1424,7 @@ pinit: push %ds
movl $0x79000+PAGE_V+PAGE_RW,0x7b000-SEG # PD←PDT (+)
movl $0x79000+PAGE_V+PAGE_RW,0x7a000-SEG # PD←PDT (-)
mov $512,%cx # PD±2MB
mov $PAGE_V+PAGE_RW,%eax
mov $PAGE_V+PAGE_RSRV+PAGE_RW,%eax
xor %di,%di
0: stosl
add $0x1000,%eax
@@ -1438,7 +1447,7 @@ golong: cli
mov %eax,%cr4
movl $EFER,%ecx
rdmsr
or $EFER_LME|EFER_SCE,%eax
or $EFER_LME|EFER_SCE|EFER_NXE,%eax
wrmsr
lgdt REAL(_gdtrphy)
mov %cr0,%eax
@@ -1555,21 +1564,21 @@ kernel: movabs $ape_stack_vaddr,%rsp
.byte 0x0f,0x1f,0207 # nop rdi binbase
.long (IMAGE_BASE_VIRTUAL-IMAGE_BASE_REAL)/512
#endif
push $METAL # sets __hostos in crt.S
push $_HOSTMETAL # sets __hostos in crt.S
pop %rcx
push $0
pushq .Lenv0(%rip) # envp[0][0]
mov %rsp,%rbp
mov .Lenv0(%rip),%rax
mov %rax,(%rbp) # envp[0][0]
push $0 # argv[0][0]
pushq .Largv0+8(%rip) # argv[0][8]
pushq .Largv0(%rip) # argv[0][0]
mov %rsp,%rax
push $0 # auxv[1][1]
push $0 # auxv[1][0]
push %rbp # auxv[0][1]
push %rax # auxv[0][1]
push $31 # auxv[0][0] AT_EXECFN
push $0 # envp[1]
push $.Lenv0 # envp[0]
push %rbp # envp[0]
push $0 # argv[1]
push %rbp # argv[0]
push %rax # argv[0]
push $1 # argc
xor %ebp,%ebp
xor %eax,%eax
@@ -1585,6 +1594,9 @@ kernel: movabs $ape_stack_vaddr,%rsp
.rodata
.Lenv0: .asciz "METAL=1"
.Largv0:
.asciz APE_COM_NAME
.org .Largv0+16
.previous
#endif /* SupportsMetal() */
+2 -4
View File
@@ -565,12 +565,10 @@ SHSTUB2(ape_loader_dd_count,
#if SupportsMetal()
HIDDEN(v_ape_realsectors =
MIN(0x70000 - IMAGE_BASE_REAL,
ROUNDUP(RVA(_edata), 512)) / 512);
ROUNDUP(RVA(_tdata_end), 512)) / 512);
HIDDEN(v_ape_realpages = v_ape_realsectors / (4096 / 512));
HIDDEN(v_ape_highsectors =
(ROUNDUP(RVA(_edata), 512) / 512) - v_ape_realsectors);
PROVIDE_HIDDEN(_tss = 0);
PROVIDE_HIDDEN(_tss_end = 0);
(ROUNDUP(RVA(_tdata_end), 512) / 512) - v_ape_realsectors);
TSSDESCSTUB2(_tss, _tss, _tss_end ? _tss_end - _tss - 1 : 0);
#endif
+2
View File
@@ -107,6 +107,7 @@ o/$(MODE)/ape/ape-no-modify-self.o: \
libc/macho.internal.h \
libc/macros.internal.h \
libc/nexgen32e/uart.internal.h \
libc/calls/metalfile.internal.h \
libc/nexgen32e/vidya.internal.h \
libc/nt/pedef.internal.h \
libc/runtime/e820.internal.h \
@@ -133,6 +134,7 @@ o/$(MODE)/ape/ape-copy-self.o: \
libc/macho.internal.h \
libc/macros.internal.h \
libc/nexgen32e/uart.internal.h \
libc/calls/metalfile.internal.h \
libc/nexgen32e/vidya.internal.h \
libc/nt/pedef.internal.h \
libc/runtime/e820.internal.h \
+3 -1
View File
@@ -1,6 +1,6 @@
#!/bin/sh
if [ $UID -eq 0 ]; then
if [ "$(id -u)" -eq 0 ]; then
SUDO=
else
SUDO=sudo
@@ -97,6 +97,8 @@ if [ x"$(uname -s)" = xLinux ]; then
echo you may need to edit configs to persist across reboot >&2
echo '$SUDO sh -c "echo '"'"':APE:M::MZqFpD::/usr/bin/ape:'"'"' >/proc/sys/fs/binfmt_misc/register"' >&2
$SUDO sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" || exit
echo '$SUDO sh -c "echo '"'"':APE-sysv:M::JTqFpD::/usr/bin/ape:'"'"' >/proc/sys/fs/binfmt_misc/register"' >&2
$SUDO sh -c "echo ':APE-sysv:M::JTqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" || exit
echo done >&2
if [ x"$(cat /proc/sys/fs/binfmt_misc/status)" = xdisabled ]; then
+4
View File
@@ -11,6 +11,7 @@ fi
echo "APE Uninstaller intends to run"
echo
echo " $SUDO sh -c 'echo -1 >/proc/sys/fs/binfmt_misc/APE'"
echo " $SUDO sh -c 'echo -1 >/proc/sys/fs/binfmt_misc/APE-sysv'"
echo " $SUDO rm -f /usr/bin/ape ~/.ape o/tmp/.ape /tmp/.ape"
echo
echo "You may then use ape/apeinstall.sh to reinstall it"
@@ -21,4 +22,7 @@ set -ex
if [ -f /proc/sys/fs/binfmt_misc/APE ]; then
$SUDO sh -c 'echo -1 >/proc/sys/fs/binfmt_misc/APE' || exit
fi
if [ -f /proc/sys/fs/binfmt_misc/APE-sysv ]; then
$SUDO sh -c 'echo -1 >/proc/sys/fs/binfmt_misc/APE-sysv' || exit
fi
$SUDO rm -f /usr/bin/ape ~/.ape o/tmp/.ape o/tmp/ape /tmp/.ape /tmp/ape || exit
+2 -2
View File
@@ -175,7 +175,7 @@ macho: .long 0xFEEDFACE+1
510: .quad 0 # rax
.quad 0 # rbx
.quad 0 # rcx
.quad XNU # rdx
.quad _HOSTXNU # rdx
.quad 0 # rdi
.quad 0 # rsi
.quad 0 # rbp
@@ -221,7 +221,7 @@ _start:
jne 0f
cmp $+1,%edx
jne 0f
mov $XNU,%dl
mov $_HOSTXNU,%dl
xor %ecx,%ecx
0: mov %rsp,%rsi
+2 -2
View File
@@ -90,7 +90,7 @@ macho: .long 0xFEEDFACE+1
510: .quad 0 # rax
.quad 0 # rbx
.quad 0 # rcx
.quad XNU # rdx
.quad _HOSTXNU # rdx
.quad 0 # rdi
.quad 0 # rsi
.quad 0 # rbp
@@ -121,7 +121,7 @@ _start:
jne 0f
cmp $+1,%edx
jne 0f
mov $XNU,%dl
mov $_HOSTXNU,%dl
xor %ecx,%ecx
0: mov %rsp,%rsi
+8
View File
@@ -182,6 +182,14 @@
// Task State Segment Descriptor Entries.
.macro .tssdescstub name:req
.ifndef \name
.weak \name
.set \name,0
.endif
.ifndef \name\()_end
.weak \name\()_end
.set \name\()_end,0
.endif
.stub \name\()_desc_ent0,quad
.stub \name\()_desc_ent1,quad
.endm
+34
View File
@@ -0,0 +1,34 @@
#ifndef COSMOPOLITAN_APE_SECTIONS_INTERNAL_H_
#define COSMOPOLITAN_APE_SECTIONS_INTERNAL_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern unsigned char _base[];
extern unsigned char _ehead[];
extern unsigned char _etext[];
extern unsigned char _edata[];
extern unsigned char _ezip[];
extern unsigned char _end[];
extern unsigned char _ereal[];
extern unsigned char _tdata_start[];
extern unsigned char _tdata_end[];
extern unsigned char _tbss_start[];
extern unsigned char _tbss_end[];
extern unsigned char __privileged_start[];
extern unsigned char __privileged_addr[];
extern unsigned char __privileged_size[];
extern unsigned char __privileged_end[];
extern unsigned char __test_start[];
extern unsigned char __ro[];
extern unsigned char *__relo_start[];
extern unsigned char *__relo_end[];
extern uint8_t __zip_start[];
extern uint8_t __zip_end[];
extern uint8_t __data_start[];
extern uint8_t __data_end[];
extern uint8_t __bss_start[];
extern uint8_t __bss_end[];
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_APE_SECTIONS_INTERNAL_H_ */
Binary file not shown.
Binary file not shown.
+27 -6
View File
@@ -29,7 +29,7 @@ endif
#
ifeq ($(MODE),fastbuild)
CONFIG_CCFLAGS += $(BACKTRACES) $(FTRACE) -O
CONFIG_CPPFLAGS += -DSYSDEBUG
CONFIG_CPPFLAGS += -DSYSDEBUG -DDWARFLESS
CONFIG_OFLAGS += -g0
CONFIG_LDFLAGS += -S
TARGET_ARCH ?= -msse3
@@ -125,6 +125,22 @@ TARGET_ARCH ?= -msse3
OVERRIDE_CCFLAGS += -fno-pie
endif
# System Five Mode
#
# - `make MODE=sysv`
# - Optimized
# - Backtraces
# - Debuggable
# - Syscall tracing
# - Function tracing
# - No Windows bloat!
#
ifeq ($(MODE), sysv)
CONFIG_CCFLAGS += $(BACKTRACES) $(FTRACE) -O2
CONFIG_CPPFLAGS += -DSYSDEBUG -DSUPPORT_VECTOR=121
TARGET_ARCH ?= -msse3
endif
# Tiny Mode
#
# - `make MODE=tiny`
@@ -151,7 +167,8 @@ CONFIG_CCFLAGS += \
-fschedule-insns2 \
-fomit-frame-pointer \
-momit-leaf-frame-pointer \
-foptimize-sibling-calls
-foptimize-sibling-calls \
-DDWARFLESS
CONFIG_OFLAGS += \
-g0
CONFIG_LDFLAGS += \
@@ -181,7 +198,8 @@ CONFIG_CPPFLAGS += \
-DTINY \
-DNDEBUG \
-DTRUSTWORTHY \
-DSUPPORT_VECTOR=1
-DSUPPORT_VECTOR=1 \
-DDWARFLESS
DEFAULT_COPTS += \
-mred-zone
CONFIG_OFLAGS += \
@@ -217,7 +235,8 @@ CONFIG_CPPFLAGS += \
-DTINY \
-DNDEBUG \
-DTRUSTWORTHY \
-DSUPPORT_VECTOR=113
-DSUPPORT_VECTOR=113 \
-DDWARFLESS
DEFAULT_COPTS += \
-mred-zone
CONFIG_OFLAGS += \
@@ -252,7 +271,8 @@ CONFIG_CPPFLAGS += \
-DTINY \
-DNDEBUG \
-DTRUSTWORTHY \
-DSUPPORT_VECTOR=121
-DSUPPORT_VECTOR=121 \
-DDWARFLESS
DEFAULT_COPTS += \
-mred-zone
CONFIG_CCFLAGS += \
@@ -287,7 +307,8 @@ CONFIG_CPPFLAGS += \
-DTINY \
-DNDEBUG \
-DTRUSTWORTHY \
-DSUPPORT_VECTOR=251
-DSUPPORT_VECTOR=251 \
-DDWARFLESS
CONFIG_CCFLAGS += \
-Os \
-fno-align-functions \
+9 -3
View File
@@ -7,12 +7,12 @@
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
╚─────────────────────────────────────────────────────────────────*/
#endif
#include "libc/intrin/bits.h"
#include "libc/dce.h"
#include "libc/intrin/bits.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/log.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
/**
@@ -59,9 +59,15 @@
int main(int argc, char *argv[]) {
if (!IsAsan()) {
printf("this example is intended for MODE=asan or MODE=dbg\n");
kprintf("this example is intended for MODE=asan or MODE=dbg\n");
exit(1);
}
kprintf("----------------\n");
kprintf(" THIS IS A TEST \n");
kprintf("SIMULATING CRASH\n");
kprintf("----------------\n");
char *buffer;
ShowCrashReports(); /* not needed but yoinks appropriate symbols */
buffer = malloc(13);
+7 -7
View File
@@ -20,22 +20,22 @@ int main(int argc, char *argv[]) {
volatile unsigned long x;
struct timespec now, start, next, interval;
printf("hammering the cpu...\n");
next = start = _timespec_mono();
interval = _timespec_frommillis(500);
next = _timespec_add(next, interval);
next = start = timespec_mono();
interval = timespec_frommillis(500);
next = timespec_add(next, interval);
for (;;) {
for (i = 0;; ++i) {
x *= 7;
if (!(i % 256)) {
now = _timespec_mono();
if (_timespec_gte(now, next)) {
now = timespec_mono();
if (timespec_cmp(now, next) >= 0) {
break;
}
}
}
next = _timespec_add(next, interval);
next = timespec_add(next, interval);
printf("consumed %10g seconds monotonic time and %10g seconds cpu time\n",
_timespec_tonanos(_timespec_sub(now, start)) / 1000000000.,
timespec_tonanos(timespec_sub(now, start)) / 1000000000.,
(double)clock() / CLOCKS_PER_SEC);
}
}
+1 -1
View File
@@ -28,7 +28,7 @@ void show(int clock) {
}
shown[n++] = clock;
if (clock_getres(clock, &ts) != -1) {
kprintf("%s %'ld ns\n", DescribeClockName(clock), _timespec_tonanos(ts));
kprintf("%s %'ld ns\n", DescribeClockName(clock), timespec_tonanos(ts));
} else {
kprintf("%s %s\n", DescribeClockName(clock), _strerrno(errno));
}
+7
View File
@@ -7,6 +7,7 @@
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
╚─────────────────────────────────────────────────────────────────*/
#endif
#include "libc/intrin/kprintf.h"
#include "libc/log/log.h"
#include "libc/runtime/symbols.internal.h"
@@ -24,6 +25,12 @@
*/
noubsan int main(int argc, char *argv[]) {
kprintf("----------------\n");
kprintf(" THIS IS A TEST \n");
kprintf("SIMULATING CRASH\n");
kprintf("----------------\n");
volatile int64_t x;
ShowCrashReports();
return 1 / (x = 0);
+24 -1
View File
@@ -49,12 +49,12 @@ EXAMPLES_DIRECTDEPS = \
LIBC_LOG \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_NT_ADVAPI32 \
LIBC_NT_IPHLPAPI \
LIBC_NT_KERNEL32 \
LIBC_NT_NTDLL \
LIBC_NT_USER32 \
LIBC_NT_WS2_32 \
LIBC_NT_ADVAPI32 \
LIBC_RUNTIME \
LIBC_SOCK \
LIBC_STDIO \
@@ -71,8 +71,10 @@ EXAMPLES_DIRECTDEPS = \
LIBC_ZIPOS \
NET_HTTP \
NET_HTTPS \
THIRD_PARTY_AWK \
THIRD_PARTY_COMPILER_RT \
THIRD_PARTY_DLMALLOC \
THIRD_PARTY_DOUBLECONVERSION \
THIRD_PARTY_GDTOA \
THIRD_PARTY_GETOPT \
THIRD_PARTY_LIBCXX \
@@ -83,7 +85,9 @@ EXAMPLES_DIRECTDEPS = \
THIRD_PARTY_NSYNC \
THIRD_PARTY_NSYNC_MEM \
THIRD_PARTY_QUICKJS \
THIRD_PARTY_SED \
THIRD_PARTY_STB \
THIRD_PARTY_TR \
THIRD_PARTY_XED \
THIRD_PARTY_ZLIB \
TOOL_BUILD_LIB \
@@ -142,6 +146,25 @@ o/$(MODE)/examples/nesemu1.com.dbg: \
$(EXAMPLES_BOOTLOADER)
@$(APELINK)
# # force symtab.com to be a zip file, by pulling a zip asset into linkage
# # we wouldn't need to do this if we depended on functions like localtime
# o/$(MODE)/examples/symtab.com.dbg: \
# $(EXAMPLES_DEPS) \
# o/$(MODE)/examples/symtab.o \
# o/$(MODE)/examples/symtab.c.zip.o \
# o/$(MODE)/examples/examples.pkg \
# $(EXAMPLES_BOOTLOADER)
# @$(APELINK)
# modify .com so it can read the symbol table without needing the .com.dbg file
o/$(MODE)/examples/symtab.com: \
o/$(MODE)/examples/symtab.com.dbg \
o/$(MODE)/third_party/zip/zip.com \
o/$(MODE)/tool/build/symtab.com
@$(MAKE_OBJCOPY)
@$(MAKE_SYMTAB_CREATE)
@$(MAKE_SYMTAB_ZIP)
o/$(MODE)/examples/picol.o: private \
OVERRIDE_CPPFLAGS += \
-DSTACK_FRAME_UNLIMITED
+1 -8
View File
@@ -9,19 +9,12 @@
#endif
#include "libc/calls/calls.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/nt/nt/process.h"
#include "libc/mem/gc.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/rand.h"
#include "libc/stdio/stdio.h"
#include "libc/time/time.h"
#include "libc/x/x.h"
dontinline void dostuff(const char *s) {
int i, us;
srand(rand64()); /* seeds rand() w/ intel rdrnd, auxv, etc. */
srand(_rand64()); /* seeds rand() w/ intel rdrnd, auxv, etc. */
for (i = 0; i < 5; ++i) {
us = rand() % 500000;
usleep(us);
+2 -2
View File
@@ -8,8 +8,8 @@
╚─────────────────────────────────────────────────────────────────*/
#endif
#include "libc/intrin/kprintf.h"
#include "libc/runtime/sysconf.h"
#include "libc/runtime/runtime.h"
int main() {
kprintf("%d\n", GetCpuCount());
kprintf("%d\n", _getcpucount());
}
+3 -2
View File
@@ -7,6 +7,7 @@
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
╚─────────────────────────────────────────────────────────────────*/
#endif
#include "ape/sections.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/errno.h"
@@ -102,7 +103,7 @@ uint64_t rngset64(void) {
static unsigned i;
static uint64_t s;
if (!i) {
s = rand64();
s = _rand64();
i = (s + 1) & (511);
}
return MarsagliaXorshift64(&s);
@@ -215,7 +216,7 @@ const struct Function {
{"moby", moby}, //
{"mt19937", _mt19937}, //
{"python", pythonx2}, //
{"rand64", rand64}, //
{"rand64", _rand64}, //
{"rdrand", rdrand}, //
{"rdrnd", rdrand}, //
{"rdseed", rdseed}, //
+2 -3
View File
@@ -28,7 +28,6 @@
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/runtime/sysconf.h"
#include "libc/sock/sock.h"
#include "libc/sock/struct/pollfd.h"
#include "libc/sock/struct/sockaddr.h"
@@ -137,7 +136,7 @@ void *Worker(void *id) {
setsockopt(server, SOL_TCP, TCP_QUICKACK, &yes, sizeof(yes));
errno = 0;
if (bind(server, &addr, sizeof(addr)) == -1) {
if (bind(server, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
kprintf("%s() failed %m\n", "socket");
goto CloseWorker;
}
@@ -299,7 +298,7 @@ int main(int argc, char *argv[]) {
PORT);
}
threads = argc > 1 ? atoi(argv[1]) : GetCpuCount();
threads = argc > 1 ? atoi(argv[1]) : _getcpucount();
if (!(1 <= threads && threads <= 100000)) {
kprintf("error: invalid number of threads: %d\n", threads);
exit(1);
+1 -1
View File
@@ -47,7 +47,7 @@
#include "third_party/libcxx/vector"
#include "tool/viz/lib/knobs.h"
STATIC_YOINK("zip_uri_support");
STATIC_YOINK("zipos");
#define USAGE \
" [ROM] [FMV]\n\
+1
View File
@@ -7,6 +7,7 @@
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
╚─────────────────────────────────────────────────────────────────*/
#endif
#include "ape/sections.internal.h"
#include "libc/dce.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
+127
View File
@@ -0,0 +1,127 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
│ To the extent possible under law, Justine Tunney has waived │
│ all copyright and related or neighboring rights to this file, │
│ as it is written in the following disclaimers: │
│ • http://unlicense.org/ │
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
╚─────────────────────────────────────────────────────────────────*/
#endif
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/timeval.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/fmt/fmt.h"
#include "libc/mem/alloca.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/sock/struct/sockaddr.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/ipproto.h"
#include "libc/sysv/consts/so.h"
#include "libc/sysv/consts/sock.h"
#include "libc/sysv/consts/sol.h"
#include "net/http/ip.h"
/**
* @fileoverview fast local network port scanner, e.g.
*
* make -j8 o//examples/portscan.com
* o//examples/portscan.com 10.10.10.0/24 22
*/
const char *FormatIp(char buf[16], uint32_t ip) {
snprintf(buf, 16, "%hhu.%hhu.%hhu.%hhu", ip >> 24, ip >> 16, ip >> 8, ip);
return buf;
}
#define FormatIp(x) FormatIp(alloca(16), x)
int main(int argc, char *argv[]) {
int port;
struct Cidr in;
uint32_t netmask;
const char *status;
struct timeval timeout;
uint32_t network_address;
uint32_t last_host_address;
uint32_t first_host_address;
if (argc != 3) {
PrintUsage:
fprintf(stderr,
"usage: %s IP/CIDR PORT\n"
"example: %s 192.168.0.0/24 22\n",
argv[0], argv[0]);
return 1;
}
in = ParseCidr(argv[1], -1);
if (in.addr == -1) {
fprintf(stderr, "error: bad ip/cidr\n");
goto PrintUsage;
}
port = atoi(argv[2]);
if (!(1 <= port && port <= 65535)) {
fprintf(stderr, "error: bad port\n");
goto PrintUsage;
}
if (in.cidr > 30) {
fprintf(stderr, "error: maximum supported cidr is 30\n");
goto PrintUsage;
}
if (in.cidr < 22) {
fprintf(stderr, "error: minimum cidr support right now is 22\n");
goto PrintUsage;
}
netmask = -1u << (32 - in.cidr);
network_address = in.addr & netmask;
first_host_address = network_address + 1;
last_host_address = (network_address | ~netmask) - 1;
assert(last_host_address > first_host_address);
assert(last_host_address - first_host_address < 1024);
fprintf(stderr, "scanning %s through %s\n", FormatIp(first_host_address),
FormatIp(last_host_address));
timeout = timeval_frommillis(100);
for (int64_t ip = first_host_address; ip <= last_host_address; ++ip) {
if (!fork()) {
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
setsockopt(3, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
setsockopt(3, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
if (!connect(3,
(struct sockaddr *)&(struct sockaddr_in){
.sin_family = AF_INET,
.sin_addr.s_addr = htonl(ip),
.sin_port = htons(port),
},
sizeof(struct sockaddr_in))) {
status = "open";
} else if (errno == ECONNREFUSED) {
status = "closed";
} else if (errno != EINPROGRESS) {
status = _strerrno(errno);
} else {
status = 0;
}
if (status) {
printf("%-15s %s\n", FormatIp(ip), status);
}
_Exit(0);
}
}
for (;;) {
if (wait(0) == -1 && errno == ECHILD) {
break;
}
}
}
+39
View File
@@ -0,0 +1,39 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
│ To the extent possible under law, Justine Tunney has waived │
│ all copyright and related or neighboring rights to this file, │
│ as it is written in the following disclaimers: │
│ • http://unlicense.org/ │
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
╚─────────────────────────────────────────────────────────────────*/
#endif
#include "libc/calls/calls.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/reboot.h"
int main(int argc, char *argv[]) {
char line[8] = {0};
if (argc > 1 && !strcmp(argv[1], "-y")) {
line[0] = 'y';
} else {
printf("reboot your computer? yes or no [no] ");
fflush(stdout);
fgets(line, sizeof(line), stdin);
}
if (line[0] == 'y' || line[0] == 'Y') {
if (reboot(RB_AUTOBOOT)) {
printf("system is rebooting...\n");
exit(0);
} else {
perror("reboot");
exit(1);
}
} else if (line[0] == 'n' || line[0] == 'N') {
exit(0);
} else {
printf("error: unrecognized response\n");
exit(2);
}
}
+39
View File
@@ -0,0 +1,39 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
│ To the extent possible under law, Justine Tunney has waived │
│ all copyright and related or neighboring rights to this file, │
│ as it is written in the following disclaimers: │
│ • http://unlicense.org/ │
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
╚─────────────────────────────────────────────────────────────────*/
#endif
#include "libc/calls/calls.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/reboot.h"
int main(int argc, char *argv[]) {
char line[8] = {0};
if (argc > 1 && !strcmp(argv[1], "-y")) {
line[0] = 'y';
} else {
printf("shutdown your computer? yes or no [no] ");
fflush(stdout);
fgets(line, sizeof(line), stdin);
}
if (line[0] == 'y' || line[0] == 'Y') {
if (reboot(RB_POWER_OFF)) {
printf("system is shutting down...\n");
exit(0);
} else {
perror("reboot");
exit(1);
}
} else if (line[0] == 'n' || line[0] == 'N') {
exit(0);
} else {
printf("error: unrecognized response\n");
exit(2);
}
}
+42
View File
@@ -0,0 +1,42 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
│ To the extent possible under law, Justine Tunney has waived │
│ all copyright and related or neighboring rights to this file, │
│ as it is written in the following disclaimers: │
│ • http://unlicense.org/ │
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
╚─────────────────────────────────────────────────────────────────*/
#endif
#include "libc/intrin/kprintf.h"
#include "libc/log/log.h"
/**
* @fileoverview example of how to embed symbol table in .com file
*
* # build our binary
* make -j16 o//examples/symtab.com
*
* # move binary somewhere else
* # so it can't find the .com.dbg binary
* cp o//examples/symtab.com /tmp
*
* # run program
* # notice that it has a symbolic backtrace
* /tmp/symtab.com
*
* @see examples/examples.mk
*/
int main(int argc, char *argv[]) {
// this links all the debugging and zip functionality
ShowCrashReports();
kprintf("----------------\n");
kprintf(" THIS IS A TEST \n");
kprintf("SIMULATING CRASH\n");
kprintf("----------------\n");
volatile int64_t x;
return 1 / (x = 0);
}
+13 -6
View File
@@ -7,13 +7,20 @@
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
╚─────────────────────────────────────────────────────────────────*/
#endif
#include "libc/dce.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
/**
* @fileoverview Cosmopolitan Command Interpreter Demo
* Yes this works on Windows.
*/
STATIC_YOINK("_tr");
STATIC_YOINK("_sed");
int main(int argc, char *argv[]) {
if (IsWindows()) {
system("notepad");
} else {
system("ls | tr a-z A-Z");
}
system("x=world\n"
"echo hello $x |\n"
" tr a-z A-Z |\n"
" sed 's/\\(.\\)/\\1 /g'");
}
+436 -357
View File
File diff suppressed because it is too large. Load diff
+148
View File
@@ -0,0 +1,148 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
│ To the extent possible under law, Justine Tunney has waived │
│ all copyright and related or neighboring rights to this file, │
│ as it is written in the following disclaimers: │
│ • http://unlicense.org/ │
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
╚─────────────────────────────────────────────────────────────────*/
#endif
#include "libc/calls/calls.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/termios.h"
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/append.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
#include "libc/time/struct/tm.h"
#include "third_party/getopt/getopt.h"
#include "third_party/musl/passwd.h"
/**
* @fileoverview program for broadcasting message to all terminals, e.g.
*
* o//examples/wall.com hello friends
*
* Will place some bold text into the top left corners of all terminals:
*
* Broadcast message from jart@host (pts/4) (Tue Oct 11 03:52:24 2022):
* hello friends
*
* It's useful for having one terminal tab notify your other ones when
* something like a long running job completes. In the old days back
* when unix systems had multiple users, the wall command provided the
* ultimate lulz especially if it's a setuid binary with root privs.
*/
#define GETOPTS "v"
#define USAGE \
"\
Usage: wall.com [-v] [TEXTMSG] [<TEXTMSG]\n\
-v increase verbosity\n\
Examples:\n\
wall.com 'hello my friends'\n\
echo hello my friends | wall.com\n\
"
int g_verbose;
static void GetOpts(int argc, char *argv[]) {
int opt;
while ((opt = getopt(argc, argv, GETOPTS)) != -1) {
switch (opt) {
case 'v':
g_verbose++;
break;
case '?':
write(1, USAGE, sizeof(USAGE) - 1);
exit(0);
default:
write(2, USAGE, sizeof(USAGE) - 1);
exit(64);
}
}
}
char *GetHost(void) {
static char host[254];
if (gethostname(host, sizeof(host))) {
strcpy(host, "localhost");
}
return host;
}
char *GetTime(void) {
int64_t t;
struct tm tm;
struct timespec ts;
clock_gettime(0, &ts);
localtime_r(&ts.tv_sec, &tm);
return _chomp(asctime(&tm));
}
int main(int argc, char *argv[]) {
GetOpts(argc, argv);
// create broadcast banner
// we use \e[1m so the text is strong & visually distinct
// we use \e[K so it doesn't get lost in a forest of text
// we map \n → \r\n because teletype might be in raw mode
char *msg = 0;
const char *s;
appends(&msg, "\e7"); // save cursor position
appends(&msg, "\e[H"); // goto top left corne
appends(&msg, "\e[K"); // clear line forward
appends(&msg, "\e[1m"); // bold text
appendf(&msg, "Broadcast message from %s@%s", getpwuid(getuid())->pw_name,
GetHost());
if (isatty(0) && (s = ttyname(0))) appendf(&msg, " (%s)", s);
appendf(&msg, " (%s):\r\n", GetTime());
appends(&msg, "\e[K");
// append broadcast message
if (optind < argc) {
// use cli arguments as message if they exist
for (int i = 0; optind + i < argc; ++i) {
if (i) appends(&msg, " ");
for (s = argv[optind + i]; *s; ++s) {
if (*s == '\n') {
appends(&msg, "\r\n\e[K");
} else {
appendw(&msg, *s & 255);
}
}
}
} else {
// otherwise use stdin as message
ssize_t i, rc;
char buf[512];
while ((rc = read(0, buf, sizeof(buf))) > 0) {
for (i = 0; i < rc; ++i) {
if (buf[i] == '\n') {
appends(&msg, "\r\n\e[K"); // clear line forward
} else {
appendw(&msg, buf[i] & 255);
}
}
}
}
appends(&msg, "\r\n\e[K\e[0m\e8"); // restore
// try to send message to all pseudoteletypewriters
for (int i = 0;; ++i) {
int fd;
char pts[32];
snprintf(pts, sizeof(pts), "/dev/pts/%d", i);
if ((fd = open(pts, O_WRONLY | O_NOCTTY)) == -1) {
if (errno == ENOENT) break;
if (g_verbose) perror(pts);
}
write(fd, msg, appendz(msg).i);
close(fd);
}
return 0;
}
+50 -9
View File
@@ -16,19 +16,60 @@ void __assert_fail(const char *, const char *, int) hidden relegated;
#define static_assert _Static_assert
#endif
#define _unassert(x) \
do { \
if (__builtin_expect(!(x), 0)) { \
unreachable; \
} \
} while (0)
#ifdef __GNUC__
#if !defined(TINY) && !defined(MODE_DBG)
/**
* Specifies expression can't possibly be false.
*
* This macro uses the `notpossible` keyword and is intended for things
* like systems integration, where we know for a fact that something is
* never going to happen, but there's no proof. So we don't want to add
* extra bloat for filenames and line numbers, since `ShowCrashReports`
* can print a backtrace if we just embed the UD2 instruction to crash.
* That's useful for systems code, for the following reason. Invariants
* make sense with _unassert() since they usually get placed at the top
* of functions. But if you used _unassert() to test a system call does
* not fail, then check happens at the end of your function usually and
* is therefore likely to result in a failure condition where execution
* falls through into a different function, which is shocking to debug.
*
* In `MODE=tiny` these assertions are redefined as undefined behavior.
*/
#define _npassert(x) \
do { \
({ \
if (__builtin_expect(!(x), 0)) { \
notpossible; \
} \
} while (0)
(void)0; \
})
#else
#define _npassert(x) _unassert(x)
#endif
#endif
#ifdef __GNUC__
/**
* Specifies expression being false is undefined behavior.
*
* This is a good way to tell the compiler about your invariants, which
* leads to smaller faster programs. The expression is never removed by
* the preprocessor so it's recommended that it be free of side-effects
* if you intend for it to be removed. At the same time, this guarantee
* makes this assertion useful for things like system calls, since they
* won't be removed by `NDEBUG` mode.
*
* If this assertion fails, the worst possible things can happen unless
* you've built your binary in `MODE=dbg` since UBSAN is the only thing
* that's capable of debugging this macro.
*/
#define _unassert(x) \
({ \
if (__builtin_expect(!(x), 0)) { \
unreachable; \
} \
(void)0; \
})
#endif
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
+3 -2
View File
@@ -1,7 +1,7 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2021 Justine Alexandra Roberts Tunney │
│ Copyright 2022 Justine Alexandra Roberts Tunney │
│ │
│ Permission to use, copy, modify, and/or distribute this software for │
│ any purpose with or without fee is hereby granted, provided that the │
@@ -16,5 +16,6 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/sig.internal.h"
int __vforked;
struct Signals __sig;
+39 -55
View File
@@ -16,26 +16,23 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "ape/sections.internal.h"
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/siginfo.h"
#include "libc/intrin/cmpxchg.h"
#include "libc/intrin/lockcmpxchg.h"
#include "libc/calls/struct/sigset.h"
#include "libc/intrin/strace.internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
/**
* @fileoverview UNIX signals for the New Technology, Part 2.
* @threadsafe
*/
#include "libc/thread/tls.h"
/**
* Allocates piece of memory for storing pending signal.
@@ -61,6 +58,18 @@ static textwindows void __sig_free(struct Signal *mem) {
mem->used = false;
}
static inline textwindows int __sig_is_masked(int sig) {
if (__tls_enabled) {
return __get_tls()->tib_sigmask & (1ull << (sig - 1));
} else {
return __sig.sigmask & (1ull << (sig - 1));
}
}
textwindows int __sig_is_applicable(struct Signal *s) {
return s->tid <= 0 || s->tid == gettid();
}
/**
* Dequeues signal that isn't masked.
* @return signal or null if empty or none unmasked
@@ -70,7 +79,7 @@ static textwindows struct Signal *__sig_remove(void) {
if (__sig.queue) {
__sig_lock();
for (prev = 0, res = __sig.queue; res; prev = res, res = res->next) {
if (!sigismember(&__sig.mask, res->sig)) {
if (__sig_is_applicable(res) && !__sig_is_masked(res->sig)) {
if (res == __sig.queue) {
__sig.queue = res->next;
} else if (prev) {
@@ -78,8 +87,6 @@ static textwindows struct Signal *__sig_remove(void) {
}
res->next = 0;
break;
} else {
STRACE("%G is masked", res->sig);
}
}
__sig_unlock();
@@ -101,7 +108,6 @@ static bool __sig_deliver(bool restartable, int sig, int si_code,
STRACE("delivering %G", sig);
// enter the signal
__sig_lock();
rva = __sighandrvas[sig];
flags = __sighandflags[sig];
if ((~flags & SA_NODEFER) || (flags & SA_RESETHAND)) {
@@ -112,12 +118,11 @@ static bool __sig_deliver(bool restartable, int sig, int si_code,
// signal handler. in that case you must use SA_NODEFER.
__sighandrvas[sig] = (int32_t)(intptr_t)SIG_DFL;
}
__sig_unlock();
// setup the somewhat expensive information args
// only if they're requested by the user in sigaction()
if (flags & SA_SIGINFO) {
__repstosb(&info, 0, sizeof(info));
bzero(&info, sizeof(info));
info.si_signo = sig;
info.si_code = si_code;
infop = &info;
@@ -134,7 +139,9 @@ static bool __sig_deliver(bool restartable, int sig, int si_code,
// since sigaction() is @asyncsignalsafe we only restore it if the
// user didn't change it during the signal handler. we also don't
// need to do anything if this was a oneshot signal or nodefer.
_lockcmpxchg(__sighandrvas + sig, (int32_t)(intptr_t)SIG_DFL, rva);
if (__sighandrvas[sig] == (int32_t)(intptr_t)SIG_DFL) {
__sighandrvas[sig] = rva;
}
}
if (!restartable) {
@@ -150,7 +157,7 @@ static bool __sig_deliver(bool restartable, int sig, int si_code,
/**
* Returns true if signal default action is to end process.
*/
static textwindows bool __sig_isfatal(int sig) {
static textwindows bool __sig_is_fatal(int sig) {
if (sig == SIGCHLD || sig == SIGURG || sig == SIGWINCH) {
return false;
} else {
@@ -168,7 +175,7 @@ bool __sig_handle(bool restartable, int sig, int si_code, ucontext_t *ctx) {
bool delivered;
switch (__sighandrvas[sig]) {
case (intptr_t)SIG_DFL:
if (__sig_isfatal(sig)) {
if (__sig_is_fatal(sig)) {
STRACE("terminating on %G", sig);
_Exitr(128 + sig);
}
@@ -194,20 +201,18 @@ bool __sig_handle(bool restartable, int sig, int si_code, ucontext_t *ctx) {
* @threadsafe
*/
textwindows int __sig_raise(int sig, int si_code) {
int rc;
int candeliver;
__sig_lock();
candeliver = !sigismember(&__sig.mask, sig);
__sig_unlock();
switch (candeliver) {
case 1:
if (1 <= sig && sig <= 64) {
if (!__sig_is_masked(sig)) {
++__sig_count;
// TODO(jart): ucontext_t support
__sig_handle(false, sig, si_code, 0);
return 0;
case 0:
} else {
STRACE("%G is masked", sig);
return __sig_add(sig, si_code);
default:
return -1; // sigismember() validates `sig`
return __sig_add(gettid(), sig, si_code);
}
} else {
return einval();
}
}
@@ -216,18 +221,19 @@ textwindows int __sig_raise(int sig, int si_code) {
* @return 0 on success, otherwise -1 w/ errno
* @threadsafe
*/
textwindows int __sig_add(int sig, int si_code) {
textwindows int __sig_add(int tid, int sig, int si_code) {
int rc;
struct Signal *mem;
if (1 <= sig && sig <= NSIG) {
__sig_lock();
if (1 <= sig && sig <= 64) {
if (__sighandrvas[sig] == (unsigned)(intptr_t)SIG_IGN) {
STRACE("ignoring %G", sig);
rc = 0;
} else {
STRACE("enqueuing %G", sig);
__sig_lock();
++__sig_count;
if ((mem = __sig_alloc())) {
mem->tid = tid;
mem->sig = sig;
mem->si_code = si_code;
mem->next = __sig.queue;
@@ -236,8 +242,8 @@ textwindows int __sig_add(int sig, int si_code) {
} else {
rc = enomem();
}
__sig_unlock();
}
__sig_unlock();
} else {
rc = einval();
}
@@ -276,7 +282,7 @@ textwindows bool __sig_check(bool restartable) {
textwindows void __sig_check_ignore(const int sig, const unsigned rva) {
struct Signal *cur, *prev, *next;
if (rva != (unsigned)(intptr_t)SIG_IGN &&
(rva != (unsigned)(intptr_t)SIG_DFL || __sig_isfatal(sig))) {
(rva != (unsigned)(intptr_t)SIG_DFL || __sig_is_fatal(sig))) {
return;
}
if (__sig.queue) {
@@ -298,25 +304,3 @@ textwindows void __sig_check_ignore(const int sig, const unsigned rva) {
__sig_unlock();
}
}
/**
* Determines the pending signals on New Technology.
*
* @param pending is to hold the pending signals
* @threadsafe
*/
textwindows void __sig_pending(sigset_t *pending) {
struct Signal *cur;
sigemptyset(pending);
if (__sig.queue) {
__sig_lock();
for (cur = __sig.queue; cur; cur = cur->next) {
if (__sighandrvas[cur->sig] != (unsigned)(intptr_t)SIG_IGN) {
pending->__bits[(cur->sig - 1) >> 6] |= (1ull << ((cur->sig - 1) & 63));
} else {
STRACE("%G is ignored", cur->sig);
}
}
__sig_unlock();
}
}
+25 -30
View File
@@ -16,50 +16,45 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/state.internal.h"
#include "libc/macros.internal.h"
#include "libc/calls/struct/sigset.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/tls.h"
/**
* @fileoverview UNIX signals for the New Technology, Part 1.
* @threadsafe
*/
#define GetSigBit(x) (1ull << (((x)-1) & 63))
struct Signals __sig; // TODO(jart): Need TLS
#define GetSigBit(XXSIG) (1ull << (((XXSIG)-1) & 63))
/**
* Changes signal mask for main thread.
* @return 0 on success, or -1 w/ errno
*/
textwindows int __sig_mask(int how, const sigset_t *neu, sigset_t *old) {
int i;
uint64_t a, b;
uint64_t x, y, *mask;
if (how == SIG_BLOCK || how == SIG_UNBLOCK || how == SIG_SETMASK) {
__sig_lock();
if (__tls_enabled) {
mask = &__get_tls()->tib_sigmask;
} else {
mask = &__sig.sigmask;
}
if (old) {
*old = __sig.mask;
old->__bits[0] = *mask;
old->__bits[1] = 0;
}
if (neu) {
for (i = 0; i < ARRAYLEN(__sig.mask.__bits); ++i) {
if (how == SIG_BLOCK) {
__sig.mask.__bits[i] |= neu->__bits[i];
} else if (how == SIG_UNBLOCK) {
__sig.mask.__bits[i] &= ~neu->__bits[i];
} else {
__sig.mask.__bits[i] = neu->__bits[i];
}
x = *mask;
y = neu->__bits[0];
if (how == SIG_BLOCK) {
x |= y;
} else if (how == SIG_UNBLOCK) {
x &= ~y;
} else {
x = y;
}
__sig.mask.__bits[0] &= ~(GetSigBit(SIGKILL) | GetSigBit(SIGSTOP));
x &= ~(0
#define M(x) | GetSigBit(x)
#include "libc/intrin/sigisprecious.inc"
);
*mask = x;
}
__sig_unlock();
return 0;
} else {
return einval();
}
}
#undef GetSigBit
+43
View File
@@ -0,0 +1,43 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2022 Justine Alexandra Roberts Tunney │
│ │
│ Permission to use, copy, modify, and/or distribute this software for │
│ any purpose with or without fee is hereby granted, provided that the │
│ above copyright notice and this permission notice appear in all copies. │
│ │
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/sigset.h"
/**
* Determines the pending signals on New Technology.
*
* @param pending is to hold the pending signals
* @threadsafe
*/
textwindows void __sig_pending(sigset_t *pending) {
struct Signal *s;
sigemptyset(pending);
if (__sig.queue) {
__sig_lock();
for (s = __sig.queue; s; s = s->next) {
if (__sig_is_applicable(s) &&
__sighandrvas[s->sig] != (unsigned)(intptr_t)SIG_IGN) {
sigaddset(pending, s->sig);
}
}
__sig_unlock();
}
}
+1 -3
View File
@@ -32,12 +32,10 @@
* @asyncsignalsafe
*/
unsigned alarm(unsigned seconds) {
int rc;
struct itimerval it;
bzero(&it, sizeof(it));
it.it_value.tv_sec = seconds;
rc = setitimer(ITIMER_REAL, &it, &it);
assert(rc != -1);
_npassert(!setitimer(ITIMER_REAL, &it, &it));
if (!it.it_value.tv_sec && !it.it_value.tv_usec) {
return 0;
} else {
+22
View File
@@ -0,0 +1,22 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_BLOCKCANCEL_H_
#define COSMOPOLITAN_LIBC_CALLS_BLOCKCANCEL_H_
#include "libc/thread/thread.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define BLOCK_CANCELLATIONS \
do { \
int _CancelState; \
_CancelState = _pthread_block_cancellations()
#define ALLOW_CANCELLATIONS \
_pthread_allow_cancellations(_CancelState); \
} \
while (0)
int _pthread_block_cancellations(void);
void _pthread_allow_cancellations(int);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_BLOCKCANCEL_H_ */
+19
View File
@@ -0,0 +1,19 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_BLOCKSIGS_H_
#define COSMOPOLITAN_LIBC_CALLS_BLOCKSIGS_H_
#include "libc/calls/struct/sigset.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define BLOCK_SIGNALS \
do { \
sigset_t _SigMask; \
_SigMask = _sigblockall()
#define ALLOW_SIGNALS \
_sigsetmask(_SigMask); \
} \
while (0)
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_BLOCKSIGS_H_ */
+52 -51
View File
@@ -65,13 +65,13 @@ char *ttyname(int);
int access(const char *, int) dontthrow;
int arch_prctl();
int chdir(const char *);
int chmod(const char *, uint32_t);
int chown(const char *, uint32_t, uint32_t);
int chmod(const char *, unsigned);
int chown(const char *, unsigned, unsigned);
int chroot(const char *);
int close(int);
int close_range(unsigned, unsigned, unsigned);
int closefrom(int);
int creat(const char *, uint32_t);
int creat(const char *, unsigned);
int dup(int);
int dup2(int, int);
int dup3(int, int, int);
@@ -84,25 +84,22 @@ int execv(const char *, char *const[]);
int execve(const char *, char *const[], char *const[]);
int execvp(const char *, char *const[]);
int execvpe(const char *, char *const[], char *const[]);
int fexecve(int, char *const[], char *const[]);
int faccessat(int, const char *, int, uint32_t);
int faccessat(int, const char *, int, int);
int fadvise(int, uint64_t, uint64_t, int);
int fchdir(int);
int fchmod(int, uint32_t) dontthrow;
int fchmodat(int, const char *, uint32_t, int);
int fchown(int, uint32_t, uint32_t);
int fchownat(int, const char *, uint32_t, uint32_t, int);
int fchmod(int, unsigned) dontthrow;
int fchmodat(int, const char *, unsigned, int);
int fchown(int, unsigned, unsigned);
int fchownat(int, const char *, unsigned, unsigned, int);
int fcntl(int, int, ...);
int fdatasync(int);
int fexecve(int, char *const[], char *const[]);
int flock(int, int);
int fork(void);
int fsync(int);
int ftruncate(int, int64_t);
int getdomainname(char *, size_t);
uint32_t getegid(void) nosideeffect;
uint32_t geteuid(void) nosideeffect;
uint32_t getgid(void) nosideeffect;
int getgroups(int size, uint32_t list[]);
int getgroups(int, unsigned[]);
int gethostname(char *, size_t);
int getloadavg(double *, int);
int getpgid(int) libcesque;
@@ -110,35 +107,29 @@ int getpgrp(void) nosideeffect;
int getpid(void) nosideeffect libcesque;
int getppid(void);
int getpriority(int, unsigned);
int getresgid(uint32_t *, uint32_t *, uint32_t *);
int getresuid(uint32_t *, uint32_t *, uint32_t *);
int getresgid(unsigned *, unsigned *, unsigned *);
int getresuid(unsigned *, unsigned *, unsigned *);
int getsid(int) nosideeffect libcesque;
int gettid(void) libcesque;
uint32_t getuid(void) libcesque;
int sys_iopl(int);
int ioprio_get(int, int);
int ioprio_set(int, int, int);
int issetugid(void);
int kill(int, int);
int killpg(int, int);
int lchmod(const char *, uint32_t);
int lchown(const char *, uint32_t, uint32_t);
int lchmod(const char *, unsigned);
int lchown(const char *, unsigned, unsigned);
int link(const char *, const char *) dontthrow;
int linkat(int, const char *, int, const char *, int);
int madvise(void *, uint64_t, int);
int makedirs(const char *, unsigned);
int memfd_create(const char *, unsigned int);
int mincore(void *, size_t, unsigned char *);
int mkdir(const char *, uint32_t);
int mkdirat(int, const char *, uint32_t);
int mkfifo(const char *, uint32_t);
int mkfifoat(int, const char *, uint32_t);
int mknod(const char *, uint32_t, uint64_t);
int mknodat(int, const char *, int32_t, uint64_t);
int sys_mlock(const void *, size_t);
int sys_mlock2(const void *, size_t, int);
int sys_mlockall(int);
int sys_munlock(const void *, size_t);
int sys_munlockall(void);
int mkdir(const char *, unsigned);
int mkdirat(int, const char *, unsigned);
int mkfifo(const char *, unsigned);
int mkfifoat(int, const char *, unsigned);
int mknod(const char *, unsigned, uint64_t);
int mknodat(int, const char *, int, uint64_t);
int nice(int);
int open(const char *, int, ...);
int openat(int, const char *, int, ...);
@@ -148,7 +139,7 @@ int pipe(int[hasatleast 2]);
int pipe2(int[hasatleast 2], int);
int pivot_root(const char *, const char *);
int pledge(const char *, const char *);
int posix_fadvise(int, uint64_t, uint64_t, int);
int posix_fadvise(int, int64_t, int64_t, int);
int posix_madvise(void *, uint64_t, int);
int prctl(int, ...);
int raise(int);
@@ -160,36 +151,42 @@ int renameat2(long, const char *, long, const char *, int);
int rmdir(const char *);
int sched_yield(void);
int seccomp(unsigned, unsigned, void *);
int setegid(uint32_t);
int seteuid(uint32_t);
int setfsgid(int);
int setfsuid(int);
int setgid(int);
int setgroups(size_t size, const uint32_t list[]);
int setegid(unsigned);
int seteuid(unsigned);
int setfsgid(unsigned);
int setfsuid(unsigned);
int setgid(unsigned);
int setgroups(size_t, const unsigned[]);
int setpgid(int, int);
int setpgrp(void);
int setpriority(int, unsigned, int);
int setregid(uint32_t, uint32_t);
int setresgid(uint32_t, uint32_t, uint32_t);
int setresuid(uint32_t, uint32_t, uint32_t);
int setreuid(uint32_t, uint32_t);
int setregid(unsigned, unsigned);
int setresgid(unsigned, unsigned, unsigned);
int setresuid(unsigned, unsigned, unsigned);
int setreuid(unsigned, unsigned);
int setsid(void);
int setuid(int);
int setuid(unsigned);
int sigignore(int);
int siginterrupt(int, int);
int symlink(const char *, const char *);
int symlinkat(const char *, int, const char *);
int sync_file_range(int, int64_t, int64_t, unsigned);
int sys_iopl(int);
int sys_mlock(const void *, size_t);
int sys_mlock2(const void *, size_t, int);
int sys_mlockall(int);
int sys_munlock(const void *, size_t);
int sys_munlockall(void);
int sys_ptrace(int, ...);
int sys_sysctl(const int *, unsigned, void *, size_t *, void *, size_t);
int tcsetpgrp(int, int32_t);
int tcgetpgrp(int);
int tcsetpgrp(int, int);
int tgkill(int, int, int);
int tkill(int, int);
int tmpfd(void);
int touch(const char *, uint32_t);
int truncate(const char *, uint64_t);
int touch(const char *, unsigned);
int truncate(const char *, int64_t);
int ttyname_r(int, char *, size_t);
int umask(int);
int unlink(const char *);
int unlink_s(const char **);
int unlinkat(int, const char *, int);
@@ -198,21 +195,25 @@ int usleep(unsigned);
int vfork(void) returnstwice;
int wait(int *);
int waitpid(int, int *, int);
int32_t tcgetpgrp(int);
intptr_t syscall(int, ...);
long ptrace(int, ...);
ssize_t copy_file_range(int, long *, int, long *, size_t, uint32_t);
ssize_t copyfd(int, int64_t *, int, int64_t *, size_t, uint32_t);
ssize_t copy_file_range(int, long *, int, long *, size_t, unsigned);
ssize_t copyfd(int, int64_t *, int, int64_t *, size_t, unsigned);
ssize_t getfiledescriptorsize(int);
ssize_t lseek(int, int64_t, unsigned);
ssize_t lseek(int, int64_t, int);
ssize_t pread(int, void *, size_t, int64_t);
ssize_t pwrite(int, const void *, size_t, int64_t);
ssize_t read(int, void *, size_t);
ssize_t readansi(int, char *, size_t);
ssize_t readlink(const char *, char *, size_t);
ssize_t readlinkat(int, const char *, char *, size_t);
ssize_t splice(int, int64_t *, int, int64_t *, size_t, uint32_t);
ssize_t splice(int, int64_t *, int, int64_t *, size_t, unsigned);
ssize_t write(int, const void *, size_t);
unsigned getegid(void) nosideeffect;
unsigned geteuid(void) nosideeffect;
unsigned getgid(void) nosideeffect;
unsigned getuid(void) libcesque;
unsigned umask(unsigned);
void sync(void);
COSMOPOLITAN_C_END_
+16 -6
View File
@@ -65,6 +65,13 @@ $(LIBC_CALLS_A).pkg: \
$(LIBC_CALLS_A_OBJS) \
$(foreach x,$(LIBC_CALLS_A_DIRECTDEPS),$($(x)_A).pkg)
# we can't use asan because:
# siginfo_t memory is owned by kernels
o/$(MODE)/libc/calls/siginfo2cosmo.o: private \
OVERRIDE_COPTS += \
-ffreestanding \
-fno-sanitize=address
# we can't use asan because:
# ucontext_t memory is owned by xnu kernel
o/$(MODE)/libc/calls/sigenter-xnu.o: private \
@@ -172,12 +179,15 @@ o//libc/calls/statfs2cosmo.o: private \
# we always want -O2 because:
# division is expensive if not optimized
o/$(MODE)/libc/calls/clock.o \
o/$(MODE)/libc/calls/_timespec_tomillis.o \
o/$(MODE)/libc/calls/_timespec_tomicros.o \
o/$(MODE)/libc/calls/_timespec_totimeval.o \
o/$(MODE)/libc/calls/_timespec_fromnanos.o \
o/$(MODE)/libc/calls/_timespec_frommillis.o \
o/$(MODE)/libc/calls/_timespec_frommicros.o: private \
o/$(MODE)/libc/calls/timespec_tomillis.o \
o/$(MODE)/libc/calls/timespec_tomicros.o \
o/$(MODE)/libc/calls/timespec_totimeval.o \
o/$(MODE)/libc/calls/timespec_fromnanos.o \
o/$(MODE)/libc/calls/timespec_frommillis.o \
o/$(MODE)/libc/calls/timespec_frommicros.o \
o/$(MODE)/libc/calls/timeval_tomillis.o \
o/$(MODE)/libc/calls/timeval_frommillis.o \
o/$(MODE)/libc/calls/timeval_frommicros.o: private \
OVERRIDE_CFLAGS += \
-O2
@@ -18,7 +18,24 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/termios.h"
#include "libc/sysv/consts/termios.h"
#include "libc/sysv/errfuns.h"
/**
* Returns input baud rate.
* @asyncsignalsafe
*/
uint32_t cfgetispeed(const struct termios *t) {
if (CBAUD) {
return t->c_cflag & CBAUD;
} else {
return t->c_ispeed;
}
}
/**
* Returns output baud rate.
* @asyncsignalsafe
*/
uint32_t cfgetospeed(const struct termios *t) {
if (CBAUD) {
return t->c_cflag & CBAUD;
@@ -26,3 +43,46 @@ uint32_t cfgetospeed(const struct termios *t) {
return t->c_ospeed;
}
}
/**
* Sets input baud rate.
*
* @return 0 on success, or -1 w/ errno
* @asyncsignalsafe
*/
int cfsetispeed(struct termios *t, unsigned speed) {
if (speed) {
if (CBAUD) {
if (!(speed & ~CBAUD)) {
t->c_cflag &= ~CBAUD;
t->c_cflag |= speed;
} else {
return einval();
}
} else {
t->c_ispeed = speed;
}
}
return 0;
}
/**
* Sets output baud rate.
*
* @return 0 on success, or -1 w/ errno
* @asyncsignalsafe
*/
int cfsetospeed(struct termios *t, unsigned speed) {
if (CBAUD) {
if (!(speed & ~CBAUD)) {
t->c_cflag &= ~CBAUD;
t->c_cflag |= speed;
return 0;
} else {
return einval();
}
} else {
t->c_ospeed = speed;
return 0;
}
}
+1 -1
View File
@@ -36,7 +36,7 @@
int chdir(const char *path) {
int rc;
GetProgramExecutableName(); // XXX: ugly workaround
if (!path || (IsAsan() && !__asan_is_valid(path, 1))) {
if (!path || (IsAsan() && !__asan_is_valid_str(path))) {
rc = efault();
} else if (!IsWindows()) {
rc = sys_chdir(path);
+1 -1
View File
@@ -49,7 +49,7 @@
*/
int chroot(const char *path) {
int rc;
if (!path || (IsAsan() && !__asan_is_valid(path, 1))) {
if (!path || (IsAsan() && !__asan_is_valid_str(path))) {
rc = efault();
} else {
rc = sys_chroot(path);
+1 -1
View File
@@ -55,7 +55,7 @@ int64_t clock(void) {
if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) == -1) {
errno = e;
if (getrusage(RUSAGE_SELF, &ru) != -1) {
ts = _timeval_totimespec(_timeval_add(ru.ru_utime, ru.ru_stime));
ts = timeval_totimespec(timeval_add(ru.ru_utime, ru.ru_stime));
} else {
return -1;
}
+3 -3
View File
@@ -17,11 +17,11 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/struct/timespec.h"
#include "libc/thread/thread.h"
#include "libc/nexgen32e/rdtsc.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/thread.h"
static struct {
pthread_once_t once;
@@ -30,7 +30,7 @@ static struct {
} g_mono;
static void sys_clock_gettime_mono_init(void) {
g_mono.base_wall = _timespec_real();
g_mono.base_wall = timespec_real();
g_mono.base_tick = rdtsc();
}
@@ -42,7 +42,7 @@ int sys_clock_gettime_mono(struct timespec *time) {
pthread_once(&g_mono.once, sys_clock_gettime_mono_init);
cycles = rdtsc() - g_mono.base_tick;
nanos = cycles / 3;
*time = _timespec_add(g_mono.base_wall, _timespec_fromnanos(nanos));
*time = timespec_add(g_mono.base_wall, timespec_fromnanos(nanos));
return 0;
} else {
return einval();
+1 -1
View File
@@ -84,7 +84,7 @@ int clock_gettime(int clock, struct timespec *ts) {
rc = __clock_gettime(clock, ts);
}
#if SYSDEBUG
if (!(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
if (__tls_enabled && !(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
STRACE("clock_gettime(%s, [%s]) → %d% m", DescribeClockName(clock),
DescribeTimespec(rc, ts), rc);
}
+8 -8
View File
@@ -33,24 +33,24 @@ textwindows int sys_clock_nanosleep_nt(int clock, int flags,
abs = *req;
for (;;) {
if (sys_clock_gettime_nt(clock, &now)) return -1;
if (_timespec_gte(now, abs)) return 0;
if (_check_interrupts(false, g_fds.p)) return eintr();
if (timespec_cmp(now, abs) >= 0) return 0;
if (_check_interrupts(false, g_fds.p)) return -1;
SleepEx(MIN(__SIG_POLLING_INTERVAL_MS,
_timespec_tomillis(_timespec_sub(abs, now))),
timespec_tomillis(timespec_sub(abs, now))),
false);
}
} else {
if (sys_clock_gettime_nt(clock, &now)) return -1;
abs = _timespec_add(now, *req);
abs = timespec_add(now, *req);
for (;;) {
sys_clock_gettime_nt(clock, &now);
if (_timespec_gte(now, abs)) return 0;
if (timespec_cmp(now, abs) >= 0) return 0;
if (_check_interrupts(false, g_fds.p)) {
if (rem) *rem = _timespec_sub(abs, now);
return eintr();
if (rem) *rem = timespec_sub(abs, now);
return -1;
}
SleepEx(MIN(__SIG_POLLING_INTERVAL_MS,
_timespec_tomillis(_timespec_sub(abs, now))),
timespec_tomillis(timespec_sub(abs, now))),
false);
}
}
+2 -2
View File
@@ -31,8 +31,8 @@ int sys_clock_nanosleep_openbsd(int clock, int flags,
res = sys_nanosleep(req, rem);
} else {
sys_clock_gettime(clock, &now);
if (_timespec_gt(*req, now)) {
rel = _timespec_sub(*req, now);
if (timespec_cmp(*req, now) > 0) {
rel = timespec_sub(*req, now);
res = sys_nanosleep(&rel, 0);
} else {
res = 0;
+3 -3
View File
@@ -31,10 +31,10 @@ int sys_clock_nanosleep_xnu(int clock, int flags, const struct timespec *req,
struct timeval now, abs, rel;
if (clock == CLOCK_REALTIME) {
if (flags & TIMER_ABSTIME) {
abs = _timespec_totimeval(*req);
abs = timespec_totimeval(*req);
sys_gettimeofday_xnu(&now, 0, 0);
if (_timeval_gt(abs, now)) {
rel = _timeval_sub(abs, now);
if (timeval_cmp(abs, now) > 0) {
rel = timeval_sub(abs, now);
res = sys_select(0, 0, 0, 0, &rel);
} else {
res = 0;
+10 -4
View File
@@ -17,6 +17,7 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/asan.internal.h"
#include "libc/calls/cp.internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timespec.internal.h"
@@ -55,8 +56,8 @@
*
* struct timespec rel, now, abs;
* clock_gettime(CLOCK_REALTIME, &now);
* rel = _timespec_frommillis(100);
* abs = _timespec_add(now, rel);
* rel = timespec_frommillis(100);
* abs = timespec_add(now, rel);
* while (clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &abs, 0));
*
* will accurately spin on `EINTR` errors. That way you're not impeding
@@ -74,18 +75,21 @@
* if flags is `TIMER_ABSTIME` then `rem` is ignored
* @return 0 on success, or errno on error
* @raise EINTR when a signal got delivered while we were waiting
* @raise ECANCELED if thread was cancelled in masked mode
* @raise ENOTSUP if `clock` is known but we can't use it here
* @raise EFAULT if `req` or null or bad memory was passed
* @raise EINVAL if `clock` is unknown to current platform
* @raise EINVAL if `flags` has an unrecognized value
* @raise EINVAL if `req->tv_nsec ∉ [0,1000000000)`
* @raise EFAULT if bad memory was passed
* @raise ENOSYS on bare metal
* @cancellationpoint
* @returnserrno
* @norestart
*/
errno_t clock_nanosleep(int clock, int flags, const struct timespec *req,
struct timespec *rem) {
int rc, e = errno;
BEGIN_CANCELLATION_POINT;
if (!req || (IsAsan() && (!__asan_is_valid_timespec(req) ||
(rem && !__asan_is_valid_timespec(rem))))) {
@@ -112,8 +116,10 @@ errno_t clock_nanosleep(int clock, int flags, const struct timespec *req,
errno = e;
}
END_CANCELLATION_POINT;
#if SYSDEBUG
if (!(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
if (__tls_enabled && !(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
STRACE("clock_nanosleep(%s, %s, %s, [%s]) → %s", DescribeClockName(clock),
DescribeSleepFlags(flags), DescribeTimespec(0, req),
DescribeTimespec(rc, rem), DescribeErrnoResult(rc));
+8 -1
View File
@@ -18,15 +18,22 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/struct/fd.internal.h"
#include "libc/errno.h"
#include "libc/intrin/weaken.h"
#include "libc/nt/enum/filetype.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/sysv/consts/o.h"
textwindows int sys_close_nt(struct Fd *fd) {
void sys_fcntl_nt_lock_cleanup(int) hidden;
textwindows int sys_close_nt(struct Fd *fd, int fildes) {
int e;
bool ok = true;
if (_weaken(sys_fcntl_nt_lock_cleanup)) {
_weaken(sys_fcntl_nt_lock_cleanup)(fildes);
}
if (fd->kind == kFdFile && ((fd->flags & O_ACCMODE) != O_RDONLY &&
GetFileType(fd->handle) == kNtFileTypeDisk)) {
// Like Linux, closing a file on Windows doesn't guarantee it's
+2 -2
View File
@@ -16,10 +16,10 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/fd.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
@@ -81,7 +81,7 @@ int close(int fd) {
} else if (__isfdkind(fd, kFdFile) || //
__isfdkind(fd, kFdConsole) || //
__isfdkind(fd, kFdProcess)) { //
rc = sys_close_nt(g_fds.p + fd);
rc = sys_close_nt(g_fds.p + fd, fd);
} else {
rc = eio();
}
+16 -16
View File
@@ -27,35 +27,35 @@
/**
* Closes extra file descriptors, e.g.
*
* // close all non-stdio file descriptors
* if (closefrom(3) == -1) {
* for (int i = 3; i < 256; ++i) {
* if (closefrom(3))
* for (int i = 3; i < 256; ++i)
* close(i);
* }
* }
*
* @return 0 on success, or -1 w/ errno
* @error EBADF if `first` is negative
* @error EBADF on OpenBSD if `first` is greater than highest fd
* @error EINVAL if flags are bad or first is greater than last
* @error EMFILE if a weird race condition happens on Linux
* @error ENOSYS if not Linux 5.9+, FreeBSD 8+, or OpenBSD
* @error EINTR possibly on OpenBSD
* @error ENOMEM on Linux maybe
* @raise EBADF if `first` is negative
* @raise ENOSYS if not Linux 5.9+, FreeBSD 8+, OpenBSD, or NetBSD
* @raise EBADF on OpenBSD if `first` is greater than highest fd
* @raise EINVAL if flags are bad or first is greater than last
* @raise EMFILE if a weird race condition happens on Linux
* @raise ECANCELED if thread was cancelled in masked mode
* @raise EINTR possibly on OpenBSD
* @raise ENOMEM on Linux maybe
*/
int closefrom(int first) {
int rc, err;
if (IsNetbsd() || IsWindows() || IsMetal()) {
rc = enosys();
} else if (first < 0) {
if (first < 0) {
// consistent with openbsd
// freebsd allows this but it's dangerous
// necessary on linux due to type signature
rc = ebadf();
} else if (IsFreebsd() || IsOpenbsd()) {
rc = sys_closefrom(first);
} else if (IsLinux()) {
rc = sys_close_range(first, 0xffffffffu, 0);
} else if (IsNetbsd()) {
rc = __sys_fcntl(first, 10 /*F_CLOSEM*/, first);
} else {
rc = sys_closefrom(first);
rc = enosys();
}
STRACE("closefrom(%d) → %d% m", first, rc);
return rc;
+10
View File
@@ -16,7 +16,9 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/blockcancel.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/cp.internal.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/sigset.internal.h"
@@ -39,6 +41,7 @@ static bool HasCopyFileRange(void) {
bool ok;
int e, rc;
e = errno;
BLOCK_CANCELLATIONS;
if (IsLinux()) {
// We modernize our detection by a few years for simplicity.
// This system call is chosen since it's listed by pledge().
@@ -49,6 +52,7 @@ static bool HasCopyFileRange(void) {
} else {
ok = false;
}
ALLOW_CANCELLATIONS;
errno = e;
return ok;
}
@@ -81,6 +85,7 @@ static void copy_file_range_init(void) {
* @raise EBADF if `infd` or `outfd` aren't open files or append-only
* @raise EPERM if `fdout` refers to an immutable file on Linux
* @raise ENOTSUP if `infd` or `outfd` is a zip file descriptor
* @raise ECANCELED if thread was cancelled in masked mode
* @raise EINVAL if ranges overlap or `flags` is non-zero
* @raise EFBIG if `setrlimit(RLIMIT_FSIZE)` is exceeded
* @raise EFAULT if one of the pointers memory is bad
@@ -93,12 +98,15 @@ static void copy_file_range_init(void) {
* @raise EIO if a low-level i/o error happens
* @see sendfile() for seekable → socket
* @see splice() for fd ↔ pipe
* @cancellationpoint
*/
ssize_t copy_file_range(int infd, int64_t *opt_in_out_inoffset, int outfd,
int64_t *opt_in_out_outoffset, size_t uptobytes,
uint32_t flags) {
ssize_t rc;
pthread_once(&g_copy_file_range.once, copy_file_range_init);
BEGIN_CANCELLATION_POINT;
if (!g_copy_file_range.ok) {
rc = enosys();
} else if (IsAsan() && ((opt_in_out_inoffset &&
@@ -112,6 +120,8 @@ ssize_t copy_file_range(int infd, int64_t *opt_in_out_inoffset, int outfd,
rc = sys_copy_file_range(infd, opt_in_out_inoffset, outfd,
opt_in_out_outoffset, uptobytes, flags);
}
END_CANCELLATION_POINT;
STRACE("copy_file_range(%d, %s, %d, %s, %'zu, %#x) → %'ld% m", infd,
DescribeInOutInt64(rc, opt_in_out_inoffset), outfd,
DescribeInOutInt64(rc, opt_in_out_outoffset), uptobytes, flags);
+59
View File
@@ -0,0 +1,59 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2022 Justine Alexandra Roberts Tunney │
│ │
│ Permission to use, copy, modify, and/or distribute this software for │
│ any purpose with or without fee is hereby granted, provided that the │
│ above copyright notice and this permission notice appear in all copies. │
│ │
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/blockcancel.internal.h"
#include "libc/calls/cp.internal.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/thread/posixthread.internal.h"
#include "libc/thread/tls.h"
#ifdef MODE_DBG
int begin_cancellation_point(void) {
int state = 0;
struct CosmoTib *tib;
struct PosixThread *pt;
if (__enable_tls) {
tib = __get_tls();
if ((pt = (struct PosixThread *)tib->tib_pthread)) {
state = pt->flags & PT_INCANCEL;
pt->flags |= PT_INCANCEL;
}
}
return state;
}
void end_cancellation_point(int state) {
struct CosmoTib *tib;
struct PosixThread *pt;
if (__enable_tls) {
tib = __get_tls();
if ((pt = (struct PosixThread *)tib->tib_pthread)) {
pt->flags &= ~PT_INCANCEL;
pt->flags |= state;
}
}
}
void report_cancellation_point(void) {
BLOCK_CANCELLATIONS;
_bt("error: need BEGIN/END_CANCELLATION_POINT\n");
ALLOW_CANCELLATIONS;
}
#endif /* MODE_DBG */
+25
View File
@@ -0,0 +1,25 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_CP_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_CP_INTERNAL_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
int begin_cancellation_point(void);
void end_cancellation_point(int);
#ifndef MODE_DBG
#define BEGIN_CANCELLATION_POINT (void)0
#define END_CANCELLATION_POINT (void)0
#else
#define BEGIN_CANCELLATION_POINT \
do { \
int _Cp; \
_Cp = begin_cancellation_point()
#define END_CANCELLATION_POINT \
end_cancellation_point(_Cp); \
} \
while (0)
#endif
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_CP_INTERNAL_H_ */
+1
View File
@@ -31,6 +31,7 @@
* @param mode is octal bits, e.g. 0644 usually
* @return file descriptor, or -1 w/ errno
* @see openat() for further documentation
* @cancellationpoint
* @asyncsignalsafe
* @restartable
* @threadsafe
+14 -25
View File
@@ -31,13 +31,11 @@
// Implements dup(), dup2(), dup3(), and F_DUPFD for Windows.
textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
int64_t rc, proc, handle;
_unassert(oldfd >= 0);
_unassert(newfd >= -1);
_unassert(!(flags & ~O_CLOEXEC));
__fds_lock();
if (oldfd >= g_fds.n ||
if (!__isfdopen(oldfd) || newfd < -1 ||
(g_fds.p[oldfd].kind != kFdFile && g_fds.p[oldfd].kind != kFdSocket &&
g_fds.p[oldfd].kind != kFdConsole)) {
__fds_unlock();
@@ -45,27 +43,18 @@ textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
}
// allocate a new file descriptor
for (;;) {
if (newfd == -1) {
if ((newfd = __reservefd_unlocked(start)) == -1) {
__fds_unlock();
return -1;
}
break;
} else {
if (__ensurefds_unlocked(newfd) == -1) {
__fds_unlock();
return -1;
}
if (g_fds.p[newfd].kind) {
__fds_unlock();
close(newfd);
__fds_lock();
}
if (!g_fds.p[newfd].kind) {
g_fds.p[newfd].kind = kFdReserved;
break;
}
if (newfd == -1) {
if ((newfd = __reservefd_unlocked(start)) == -1) {
__fds_unlock();
return -1;
}
} else {
if (__ensurefds_unlocked(newfd) == -1) {
__fds_unlock();
return -1;
}
if (g_fds.p[newfd].kind) {
sys_close_nt(g_fds.p + newfd, newfd);
}
}
@@ -86,7 +75,7 @@ textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
}
rc = newfd;
} else {
__releasefd_unlocked(newfd);
__releasefd(newfd);
rc = __winerr();
}
+1 -1
View File
@@ -99,7 +99,7 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
startinfo.hStdError = __getfdhandleactual(2);
// spawn the process
rc = ntspawn(program, argv, envp, 0, 0, 0, 1, 0, 0, &startinfo, &procinfo);
rc = ntspawn(program, argv, envp, 0, 0, 0, true, 0, 0, &startinfo, &procinfo);
if (rc == -1) {
STRACE("panic: unrecoverable ntspawn(%#s) error: %m", program);
__imp_ExitProcess(6543);
+37 -24
View File
@@ -16,6 +16,8 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/blockcancel.internal.h"
#include "libc/calls/blocksigs.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
@@ -39,12 +41,17 @@ static bool IsApeBinary(const char *path) {
int fd;
char buf[8];
bool res = false;
// TODO(jart): Should we block signals too?
BLOCK_CANCELLATIONS;
if ((fd = sys_open(path, O_RDONLY, 0)) != -1) {
if (sys_read(fd, buf, 8) == 8 && READ64LE(buf) == READ64LE("MZqFpD='")) {
if (sys_read(fd, buf, 8) == 8 && //
(READ64LE(buf) == READ64LE("MZqFpD='") ||
READ64LE(buf) == READ64LE("JTqFpD='"))) {
res = true;
}
sys_close(fd);
}
ALLOW_CANCELLATIONS;
return res;
}
@@ -61,35 +68,41 @@ static const char *Join(const char *a, const char *b, char buf[PATH_MAX]) {
}
int sys_execve(const char *prog, char *const argv[], char *const envp[]) {
int e;
size_t i;
int e, rc;
char *buf;
char **shargs;
const char *ape;
e = errno;
__sys_execve(prog, argv, envp);
if (errno != ENOEXEC) return -1;
for (i = 0; argv[i];) ++i;
buf = alloca(PATH_MAX);
shargs = alloca((i + 4) * sizeof(char *));
if (IsApeBinary(prog) &&
(CanExecute((ape = "/usr/bin/ape")) ||
CanExecute((ape = Join(firstnonnull(getenv("TMPDIR"),
firstnonnull(getenv("HOME"), ".")),
".ape", buf))) ||
CanExecute(
(ape = Join(firstnonnull(getenv("HOME"), "."), ".ape", buf))))) {
shargs[0] = ape;
shargs[1] = "-";
shargs[2] = prog;
memcpy(shargs + 3, argv, (i + 1) * sizeof(char *));
} else if (CanExecute(prog)) {
shargs[0] = _PATH_BSHELL;
shargs[1] = prog;
memcpy(shargs + 2, argv + 1, i * sizeof(char *));
if (errno == ENOEXEC) {
for (i = 0; argv[i];) ++i;
buf = alloca(PATH_MAX);
shargs = alloca((i + 4) * sizeof(char *));
if (IsApeBinary(prog) &&
(CanExecute((ape = "/usr/bin/ape")) ||
CanExecute((ape = Join(firstnonnull(getenv("TMPDIR"),
firstnonnull(getenv("HOME"), ".")),
".ape", buf))) ||
CanExecute(
(ape = Join(firstnonnull(getenv("HOME"), "."), ".ape", buf))))) {
shargs[0] = ape;
shargs[1] = "-";
shargs[2] = prog;
memcpy(shargs + 3, argv, (i + 1) * sizeof(char *));
errno = e;
rc = __sys_execve(shargs[0], shargs, envp);
} else if (CanExecute(prog)) {
shargs[0] = _PATH_BSHELL;
shargs[1] = prog;
memcpy(shargs + 2, argv + 1, i * sizeof(char *));
errno = e;
rc = __sys_execve(shargs[0], shargs, envp);
} else {
rc = enoexec();
}
} else {
return enoexec();
rc = -1;
}
errno = e;
return __sys_execve(shargs[0], shargs, envp);
return rc;
}
+6 -18
View File
@@ -23,6 +23,7 @@
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/likely.h"
#include "libc/intrin/promises.internal.h"
@@ -53,26 +54,13 @@ int execve(const char *prog, char *const argv[], char *const envp[]) {
int rc;
size_t i;
if (!prog || !argv || !envp ||
(IsAsan() &&
(!__asan_is_valid(prog, 1) || !__asan_is_valid_strlist(argv) ||
!__asan_is_valid_strlist(envp)))) {
(IsAsan() && (!__asan_is_valid_str(prog) || //
!__asan_is_valid_strlist(argv) || //
!__asan_is_valid_strlist(envp)))) {
rc = efault();
} else {
#ifdef SYSDEBUG
if (UNLIKELY(__strace > 0)) {
kprintf(STRACE_PROLOGUE "execve(%#s, {", prog);
for (i = 0; argv[i]; ++i) {
if (i) kprintf(", ");
kprintf("%#s", argv[i]);
}
kprintf("}, {");
for (i = 0; envp[i]; ++i) {
if (i) kprintf(", ");
kprintf("%#s", envp[i]);
}
kprintf("})\n");
}
#endif
STRACE("execve(%#s, %s, %s) → ...", prog, DescribeStringList(argv),
DescribeStringList(envp));
if (!IsWindows()) {
rc = 0;
if (IsLinux() && __execpromises && _weaken(sys_pledge_linux)) {
+1 -1
View File
@@ -37,7 +37,7 @@
int execvpe(const char *prog, char *const argv[], char *const *envp) {
char *exe;
char pathbuf[PATH_MAX];
if (IsAsan() && !__asan_is_valid(prog, 1)) return efault();
if (IsAsan() && !__asan_is_valid_str(prog)) return efault();
if (!(exe = commandv(prog, pathbuf, sizeof(pathbuf)))) return -1;
return execve(exe, argv, envp);
}
+2 -2
View File
@@ -48,10 +48,10 @@
* @note on Linux `flags` is only supported on Linux 5.8+
* @asyncsignalsafe
*/
int faccessat(int dirfd, const char *path, int amode, uint32_t flags) {
int faccessat(int dirfd, const char *path, int amode, int flags) {
int e, rc;
struct ZiposUri zipname;
if (!path || (IsAsan() && !__asan_is_valid(path, 1))) {
if (!path || (IsAsan() && !__asan_is_valid_str(path))) {
rc = efault();
} else if (__isfdkind(dirfd, kFdZip)) {
rc = enotsup();
+1 -1
View File
@@ -44,7 +44,7 @@
*/
int fchmodat(int dirfd, const char *path, uint32_t mode, int flags) {
int rc;
if (IsAsan() && !__asan_is_valid(path, 1)) {
if (IsAsan() && !__asan_is_valid_str(path)) {
rc = efault();
} else if (_weaken(__zipos_notat) &&
(rc = __zipos_notat(dirfd, path)) == -1) {
+1 -1
View File
@@ -43,7 +43,7 @@
int fchownat(int dirfd, const char *path, uint32_t uid, uint32_t gid,
int flags) {
int rc;
if (IsAsan() && !__asan_is_valid(path, 1)) {
if (IsAsan() && !__asan_is_valid_str(path)) {
rc = efault();
} else if (_weaken(__zipos_notat) &&
(rc = __zipos_notat(dirfd, path)) == -1) {
+223 -47
View File
@@ -16,6 +16,7 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/fd.internal.h"
@@ -24,65 +25,131 @@
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/calls/wincrash.internal.h"
#include "libc/errno.h"
#include "libc/intrin/kmalloc.h"
#include "libc/intrin/weaken.h"
#include "libc/limits.h"
#include "libc/log/backtrace.internal.h"
#include "libc/macros.internal.h"
#include "libc/nt/enum/filelockflags.h"
#include "libc/nt/errors.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/byhandlefileinformation.h"
#include "libc/nt/struct/overlapped.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/fd.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/thread.h"
bool __force_sqlite_to_work_until_we_can_fix_it;
struct FileLock {
struct FileLock *next;
int64_t off;
int64_t len;
int fd;
bool exc;
};
static textwindows int sys_fcntl_nt_dupfd(int fd, int cmd, int start) {
if (start < 0) return einval();
return sys_dup_nt(fd, -1, (cmd == F_DUPFD_CLOEXEC ? O_CLOEXEC : 0), start);
struct FileLocks {
pthread_mutex_t mu;
struct FileLock *list;
struct FileLock *free;
};
static struct FileLocks g_locks;
static textwindows struct FileLock *NewFileLock(void) {
struct FileLock *fl;
if (g_locks.free) {
fl = g_locks.free;
g_locks.free = fl->next;
} else {
fl = kmalloc(sizeof(*fl));
}
bzero(fl, sizeof(*fl));
fl->next = g_locks.list;
g_locks.list = fl;
return fl;
}
static textwindows int sys_fcntl_nt_lock(struct Fd *f, int cmd, uintptr_t arg) {
static textwindows void FreeFileLock(struct FileLock *fl) {
fl->next = g_locks.free;
g_locks.free = fl;
}
static textwindows bool OverlapsFileLock(struct FileLock *fl, int64_t off,
int64_t len) {
uint64_t BegA, EndA, BegB, EndB;
BegA = off;
EndA = off + (len - 1);
BegB = fl->off;
EndB = fl->off + (fl->len - 1);
return MAX(BegA, BegB) < MIN(EndA, EndB);
}
static textwindows bool EncompassesFileLock(struct FileLock *fl, int64_t off,
int64_t len) {
return off <= fl->off && fl->off + fl->len <= off + len;
}
static textwindows bool EqualsFileLock(struct FileLock *fl, int64_t off,
int64_t len) {
return fl->off == off && off + len == fl->off + fl->len;
}
hidden textwindows void sys_fcntl_nt_lock_cleanup(int fd) {
struct FileLock *fl, *ft, **flp;
pthread_mutex_lock(&g_locks.mu);
for (flp = &g_locks.list, fl = *flp; fl;) {
if (fl->fd == fd) {
*flp = fl->next;
ft = fl->next;
FreeFileLock(fl);
fl = ft;
} else {
flp = &fl->next;
fl = *flp;
}
}
pthread_mutex_unlock(&g_locks.mu);
}
static textwindows int sys_fcntl_nt_lock(struct Fd *f, int fd, int cmd,
uintptr_t arg) {
int e;
struct flock *l;
uint32_t flags, err;
int64_t pos, off, len, size;
struct NtByHandleFileInformation info;
if (!GetFileInformationByHandle(f->handle, &info)) {
return __winerr();
}
pos = 0;
if (!SetFilePointerEx(f->handle, 0, &pos, SEEK_CUR)) {
return __winerr();
}
struct FileLock *fl, *ft, **flp;
int64_t pos, off, len, end, size;
l = (struct flock *)arg;
len = l->l_len;
off = l->l_start;
size = (uint64_t)info.nFileSizeHigh << 32 | info.nFileSizeLow;
switch (l->l_whence) {
case SEEK_SET:
break;
case SEEK_CUR:
off = pos + off;
pos = 0;
if (SetFilePointerEx(f->handle, 0, &pos, SEEK_CUR)) {
off = pos + off;
} else {
return __winerr();
}
break;
case SEEK_END:
off = size - off;
off = INT64_MAX - off;
break;
default:
return einval();
}
if (!len) {
len = size - off;
len = INT64_MAX - off;
}
if (off < 0 || len < 0) {
if (off < 0 || len < 0 || __builtin_add_overflow(off, len, &end)) {
return einval();
}
@@ -91,8 +158,57 @@ static textwindows int sys_fcntl_nt_lock(struct Fd *f, int cmd, uintptr_t arg) {
.Pointer = (void *)(uintptr_t)off};
if (l->l_type == F_RDLCK || l->l_type == F_WRLCK) {
if (cmd == F_SETLK || cmd == F_SETLKW) {
// make it possible to transition read locks to write locks
for (flp = &g_locks.list, fl = *flp; fl;) {
if (fl->fd == fd) {
if (EqualsFileLock(fl, off, len)) {
if (fl->exc == l->l_type == F_WRLCK) {
// we already have this lock
return 0;
} else {
// unlock our read lock and acquire write lock below
if (UnlockFileEx(f->handle, 0, len, len >> 32, &ov)) {
*flp = fl->next;
ft = fl->next;
FreeFileLock(fl);
fl = ft;
continue;
} else {
return -1;
}
}
break;
} else if (OverlapsFileLock(fl, off, len)) {
return enotsup();
}
}
flp = &fl->next;
fl = *flp;
}
}
// return better information on conflicting locks if possible
if (cmd == F_GETLK) {
for (fl = g_locks.list; fl; fl = fl->next) {
if (fl->fd == fd && //
OverlapsFileLock(fl, off, len) &&
(l->l_type == F_WRLCK || !fl->exc)) {
l->l_whence = SEEK_SET;
l->l_start = fl->off;
l->l_len = fl->len;
l->l_type == fl->exc ? F_WRLCK : F_RDLCK;
l->l_pid = getpid();
return 0;
}
}
}
flags = 0;
if (cmd != F_SETLKW) {
// TODO(jart): we should use expo backoff in wrapper function
// should not matter since sqlite doesn't need it
flags |= kNtLockfileFailImmediately;
}
if (l->l_type == F_WRLCK) {
@@ -103,72 +219,132 @@ static textwindows int sys_fcntl_nt_lock(struct Fd *f, int cmd, uintptr_t arg) {
if (ok) {
l->l_type = F_UNLCK;
if (!UnlockFileEx(f->handle, 0, len, len >> 32, &ov)) {
notpossible;
return -1;
}
} else {
l->l_pid = -1;
ok = true;
}
} else if (ok) {
fl = NewFileLock();
fl->off = off;
fl->len = len;
fl->exc = l->l_type == F_WRLCK;
fl->fd = fd;
}
if (ok || __force_sqlite_to_work_until_we_can_fix_it) {
return 0;
} else {
return -1;
}
return ok ? 0 : -1;
}
if (l->l_type == F_UNLCK) {
if (cmd == F_GETLK) return einval();
e = errno;
if (UnlockFileEx(f->handle, 0, len, len >> 32, &ov)) {
return 0;
} else if (errno == ENOLCK) {
errno = e;
return 0;
} else {
return 0;
// allow a big range to unlock many small ranges
for (flp = &g_locks.list, fl = *flp; fl;) {
if (fl->fd == fd && EncompassesFileLock(fl, off, len)) {
struct NtOverlapped ov = {.hEvent = f->handle,
.Pointer = (void *)(uintptr_t)fl->off};
if (UnlockFileEx(f->handle, 0, fl->len, fl->len >> 32, &ov)) {
*flp = fl->next;
ft = fl->next;
FreeFileLock(fl);
fl = ft;
} else {
return -1;
}
} else {
flp = &fl->next;
fl = *flp;
}
}
// win32 won't let us carve up existing locks
int overlap_count = 0;
for (fl = g_locks.list; fl; fl = fl->next) {
if (fl->fd == fd && //
OverlapsFileLock(fl, off, len)) {
++overlap_count;
}
}
// try to handle the carving cases needed by sqlite
if (overlap_count == 1) {
for (fl = g_locks.list; fl; fl = fl->next) {
if (fl->fd == fd && //
off <= fl->off && //
off + len >= fl->off && //
off + len < fl->off + fl->len) {
// cleave left side of lock
struct NtOverlapped ov = {.hEvent = f->handle,
.Pointer = (void *)(uintptr_t)fl->off};
if (!UnlockFileEx(f->handle, 0, fl->len, fl->len >> 32, &ov)) {
return -1;
}
fl->len = (fl->off + fl->len) - (off + len);
fl->off = off + len;
ov.Pointer = (void *)(uintptr_t)fl->off;
if (!LockFileEx(f->handle, kNtLockfileExclusiveLock, 0, fl->len,
fl->len >> 32, &ov)) {
return -1;
}
return 0;
}
}
}
if (overlap_count) {
return enotsup();
}
return 0;
}
return einval();
}
static textwindows int sys_fcntl_nt_dupfd(int fd, int cmd, int start) {
if (start < 0) return einval();
return sys_dup_nt(fd, -1, (cmd == F_DUPFD_CLOEXEC ? O_CLOEXEC : 0), start);
}
textwindows int sys_fcntl_nt(int fd, int cmd, uintptr_t arg) {
int rc;
uint32_t flags;
if (__isfdkind(fd, kFdFile) || __isfdkind(fd, kFdSocket)) {
if (cmd == F_GETFL) {
return g_fds.p[fd].flags &
(O_ACCMODE | O_APPEND | O_ASYNC | O_DIRECT | O_NOATIME |
O_NONBLOCK | O_RANDOM | O_SEQUENTIAL);
rc = g_fds.p[fd].flags &
(O_ACCMODE | O_APPEND | O_ASYNC | O_DIRECT | O_NOATIME | O_NONBLOCK |
O_RANDOM | O_SEQUENTIAL);
} else if (cmd == F_SETFL) {
// O_APPEND doesn't appear to be tunable at cursory glance
// O_NONBLOCK might require we start doing all i/o in threads
// O_DSYNC / O_RSYNC / O_SYNC maybe if we fsync() everything
// O_DIRECT | O_RANDOM | O_SEQUENTIAL | O_NDELAY possible but
// not worth it.
return einval();
rc = enosys();
} else if (cmd == F_GETFD) {
if (g_fds.p[fd].flags & O_CLOEXEC) {
return FD_CLOEXEC;
rc = FD_CLOEXEC;
} else {
return 0;
rc = 0;
}
} else if (cmd == F_SETFD) {
if (arg & FD_CLOEXEC) {
g_fds.p[fd].flags |= O_CLOEXEC;
return FD_CLOEXEC;
} else {
g_fds.p[fd].flags &= ~O_CLOEXEC;
return 0;
}
rc = 0;
} else if (cmd == F_SETLK || cmd == F_SETLKW || cmd == F_GETLK) {
return sys_fcntl_nt_lock(g_fds.p + fd, cmd, arg);
pthread_mutex_lock(&g_locks.mu);
rc = sys_fcntl_nt_lock(g_fds.p + fd, fd, cmd, arg);
pthread_mutex_unlock(&g_locks.mu);
} else if (cmd == F_DUPFD || cmd == F_DUPFD_CLOEXEC) {
return sys_fcntl_nt_dupfd(fd, cmd, arg);
rc = sys_fcntl_nt_dupfd(fd, cmd, arg);
} else {
return einval();
rc = einval();
}
} else {
return ebadf();
rc = ebadf();
}
return rc;
}
+3 -3
View File
@@ -26,7 +26,7 @@
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
int sys_fcntl(int fd, int cmd, uintptr_t arg) {
int sys_fcntl(int fd, int cmd, uintptr_t arg, int impl(int, int, ...)) {
int e, rc;
bool islock;
if ((islock = cmd == F_GETLK || //
@@ -40,12 +40,12 @@ int sys_fcntl(int fd, int cmd, uintptr_t arg) {
cosmo2flock(arg);
}
e = errno;
rc = __sys_fcntl(fd, cmd, arg);
rc = impl(fd, cmd, arg);
if (islock) {
flock2cosmo(arg);
} else if (rc == -1 && cmd == F_DUPFD_CLOEXEC && errno == EINVAL) {
errno = e;
rc = __fixupnewfd(__sys_fcntl(fd, F_DUPFD, arg), O_CLOEXEC);
rc = __fixupnewfd(impl(fd, F_DUPFD, arg), O_CLOEXEC);
}
return rc;
}
+107 -14
View File
@@ -17,17 +17,22 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/cp.internal.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/flock.h"
#include "libc/calls/struct/flock.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
/**
* Does things with file descriptor, via re-imagined hourglass api, e.g.
* Does things with file descriptor, e.g.
*
* CHECK_NE(-1, fcntl(fd, F_SETFD, FD_CLOEXEC));
*
@@ -37,16 +42,60 @@
* CHECK_GE((newfd = fcntl(oldfd, F_DUPFD, 3)), 3);
* CHECK_GE((newfd = fcntl(oldfd, F_DUPFD_CLOEXEC, 3)), 3);
*
* This function implements POSIX Advisory Locks, which let independent
* processes (and on Windows, threads too!) read/write lock byte ranges
* of files. See `test/libc/calls/lock_test.c` for an example.
* This function implements file record locking, which lets independent
* processes (and on Linux 3.15+, threads too!) lock arbitrary ranges
* associated with a file. See `test/libc/calls/lock_test.c` and other
* locking related tests in that folder.
*
* Please be warned that locks currently do nothing on Windows since
* figuring out how to polyfill them correctly is a work in progress.
* On Windows, the Cosmopolitan Libc polyfill for POSIX advisory locks
* only implements enough of its nuances to support SQLite's needs. Some
* possibilities, e.g. punching holes in lock, will raise `ENOTSUP`.
*
* @param cmd can be F_{GET,SET}{FD,FL}, etc.
* @param fd is the file descriptor
* @param cmd can be one of:
* - `F_GETFD` gets `FD_CLOEXEC` status of `fd
* - `F_SETFD` sets `FD_CLOEXEC` status of `arg` file descriptor
* - `F_GETFL` returns file descriptor status flags
* - `F_SETFL` sets file descriptor status flags
* - `F_DUPFD` is like dup() but `arg` is a minimum result, e.g. 3
* - `F_DUPFD_CLOEXEC` ditto but sets `O_CLOEXEC` on returned fd
* - `F_SETLK` for record locking where `arg` is `struct flock *`
* - `F_SETLKW` ditto but waits for lock (SQLite avoids this)
* - `F_GETLK` to retrieve information about a record lock
* - `F_OFD_SETLK` for better non-blocking lock (Linux 3.15+ only)
* - `F_OFD_SETLKW` for better blocking lock (Linux 3.15+ only)
* - `F_OFD_GETLK` for better lock querying (Linux 3.15+ only)
* - `F_FULLFSYNC` on MacOS for fsync() with release barrier
* - `F_BARRIERFSYNC` on MacOS for fsync() with even more barriers
* - `F_SETNOSIGPIPE` on MacOS and NetBSD to control `SIGPIPE`
* - `F_GETNOSIGPIPE` on MacOS and NetBSD to control `SIGPIPE`
* - `F_GETPATH` on MacOS and NetBSD where arg is `char[PATH_MAX]`
* - `F_MAXFD` on NetBSD to get max open file descriptor
* - `F_NOCACHE` on MacOS to toggle data caching
* - `F_GETPIPE_SZ` on Linux to get pipe size
* - `F_SETPIPE_SZ` on Linux to set pipe size
* - `F_NOTIFY` raise `SIGIO` upon `fd` events in `arg` (Linux only)
* - `DN_ACCESS` for file access
* - `DN_MODIFY` for file modifications
* - `DN_CREATE` for file creations
* - `DN_DELETE` for file deletions
* - `DN_RENAME` for file renames
* - `DN_ATTRIB` for file attribute changes
* - `DN_MULTISHOT` bitwise or for realtime signals (non-coalesced)
* @param arg can be FD_CLOEXEC, etc. depending
* @return 0 on success, or -1 w/ errno
* @raise EBADF if `fd` isn't a valid open file descriptor
* @raise EINVAL if `cmd` is unknown or unsupported by os
* @raise EINVAL if `cmd` is invalid or unsupported by os
* @raise EPERM if pledge() is in play w/o `stdio` or `flock` promise
* @raise ENOLCK if `F_SETLKW` would have exceeded `RLIMIT_LOCKS`
* @raise EPERM if `cmd` is `F_SETOWN` and we weren't authorized
* @raise ESRCH if `cmd` is `F_SETOWN` and process group not found
* @raise ENOTSUP on Windows if locking operation isn't supported yet
* @raise EDEADLK if `cmd` was `F_SETLKW` and waiting would deadlock
* @raise EMFILE if `cmd` is `F_DUPFD` or `F_DUPFD_CLOEXEC` and
* `RLIMIT_NOFILE` would be exceeded
* @cancellationpoint when `cmd` is `F_SETLKW` or `F_OFD_SETLKW`
* @asyncsignalsafe
* @restartable
*/
@@ -54,20 +103,64 @@ int fcntl(int fd, int cmd, ...) {
int rc;
va_list va;
uintptr_t arg;
va_start(va, cmd);
arg = va_arg(va, uintptr_t);
va_end(va);
if (fd >= 0) {
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
rc = _weaken(__zipos_fcntl)(fd, cmd, arg);
} else if (!IsWindows()) {
rc = sys_fcntl(fd, cmd, arg);
if (cmd >= 0) {
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
rc = _weaken(__zipos_fcntl)(fd, cmd, arg);
} else if (!IsWindows()) {
if (cmd == F_SETLKW || cmd == F_OFD_SETLKW) {
BEGIN_CANCELLATION_POINT;
rc = sys_fcntl(fd, cmd, arg, __sys_fcntl_cp);
END_CANCELLATION_POINT;
} else {
rc = sys_fcntl(fd, cmd, arg, __sys_fcntl);
}
} else {
rc = sys_fcntl_nt(fd, cmd, arg);
}
} else {
rc = sys_fcntl_nt(fd, cmd, arg);
rc = einval();
}
} else {
rc = einval();
rc = ebadf();
}
STRACE("fcntl(%d, %d, %p) → %#x% m", fd, cmd, arg, rc);
#ifdef SYSDEBUG
if (cmd == F_GETFD || //
cmd == F_GETOWN || //
cmd == F_FULLFSYNC || //
cmd == F_BARRIERFSYNC || //
cmd == F_MAXFD) {
STRACE("fcntl(%d, %s) → %d% m", fd, DescribeFcntlCmd(cmd), rc);
} else if (cmd == F_GETFL) {
STRACE("fcntl(%d, %s) → %s% m", fd, DescribeFcntlCmd(cmd),
DescribeOpenFlags(rc));
} else if (cmd == F_SETLK || //
cmd == F_SETLKW || //
cmd == F_GETLK || //
((SupportsLinux() || SupportsXnu()) && //
cmd != -1 && //
(cmd == F_OFD_SETLK || //
cmd == F_OFD_SETLKW || //
cmd == F_OFD_GETLK))) {
STRACE("fcntl(%d, %s, %s) → %d% m", fd, DescribeFcntlCmd(cmd),
DescribeFlock(cmd, (struct flock *)arg), rc);
} else if ((SupportsNetbsd() || SupportsXnu()) && cmd != -1 &&
cmd == F_GETPATH) {
STRACE("fcntl(%d, %s, [%s]) → %d% m", fd, DescribeFcntlCmd(cmd),
!rc ? (const char *)arg : "n/a", rc);
} else if (SupportsLinux() && cmd != -1 && cmd == F_NOTIFY) {
STRACE("fcntl(%d, %s, %s) → %d% m", fd, DescribeFcntlCmd(cmd),
DescribeDnotifyFlags(arg), rc);
} else {
STRACE("fcntl(%d, %s, %ld) → %#x% m", fd, DescribeFcntlCmd(cmd), arg, rc);
}
#endif
return rc;
}
+1
View File
@@ -23,5 +23,6 @@
textwindows int sys_fdatasync_nt(int fd) {
// TODO(jart): what should we do with worker pipes?
if (!__isfdkind(fd, kFdFile)) return ebadf();
if (_check_interrupts(false, 0)) return -1;
return FlushFileBuffers(g_fds.p[fd].handle) ? 0 : -1;
}
+11 -3
View File
@@ -17,10 +17,12 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/cp.internal.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/runtime/runtime.h"
/**
@@ -29,20 +31,26 @@
* @return 0 on success, or -1 w/ errno
* @see sync(), fsync(), sync_file_range()
* @see __nosync to secretly disable
* @raise ECANCELED if thread was cancelled in masked mode
* @raise EINTR if signal was delivered
* @cancellationpoint
* @asyncsignalsafe
*/
int fdatasync(int fd) {
int rc;
struct stat st;
if (__nosync != 0x5453455454534146) {
BEGIN_CANCELLATION_POINT;
if (!IsWindows()) {
rc = sys_fdatasync(fd);
} else {
rc = sys_fdatasync_nt(fd);
}
END_CANCELLATION_POINT;
STRACE("fdatasync(%d) → %d% m", fd, rc);
} else {
rc = 0;
STRACE("fdatasync(%d) → disabled% m", fd);
rc = fstat(fd, &st);
STRACE("fdatasync_fake(%d) → %d% m", fd, rc);
}
return rc;
}
+3 -17
View File
@@ -21,8 +21,7 @@
#include "libc/dce.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/likely.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
@@ -48,21 +47,8 @@ int fexecve(int fd, char *const argv[], char *const envp[]) {
(!__asan_is_valid_strlist(argv) || !__asan_is_valid_strlist(envp)))) {
rc = efault();
} else {
#ifdef SYSDEBUG
if (UNLIKELY(__strace > 0)) {
kprintf(STRACE_PROLOGUE "fexecve(%d, {", fd);
for (i = 0; argv[i]; ++i) {
if (i) kprintf(", ");
kprintf("%#s", argv[i]);
}
kprintf("}, {");
for (i = 0; envp[i]; ++i) {
if (i) kprintf(", ");
kprintf("%#s", envp[i]);
}
kprintf("})\n");
}
#endif
STRACE("fexecve(%d, %s, %s) → ...", fd, DescribeStringList(argv),
DescribeStringList(envp));
if (IsLinux()) {
char path[14 + 12];
FormatInt32(stpcpy(path, "/proc/self/fd/"), fd);
+1 -1
View File
@@ -51,7 +51,7 @@ bool fileexists(const char *path) {
struct ZiposUri zipname;
uint16_t path16[PATH_MAX];
e = errno;
if (IsAsan() && !__asan_is_valid(path, 1)) {
if (IsAsan() && !__asan_is_valid_str(path)) {
efault();
res = false;
} else if (_weaken(__zipos_open) &&
+7 -1
View File
@@ -17,10 +17,11 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/cp.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
/**
* Acquires lock on file.
@@ -30,15 +31,20 @@
* @param op can have LOCK_{SH,EX,NB,UN} for shared, exclusive,
* non-blocking, and unlocking
* @return 0 on success, or -1 w/ errno
* @cancellationpoint
* @restartable
*/
int flock(int fd, int op) {
int rc;
BEGIN_CANCELLATION_POINT;
if (!IsWindows()) {
rc = sys_flock(fd, op);
} else {
rc = sys_flock_nt(fd, op);
}
END_CANCELLATION_POINT;
STRACE("flock(%d, %d) → %d% m", fd, op, rc);
return rc;
}
+1 -1
View File
@@ -31,7 +31,7 @@ int32_t sys_fstatat(int32_t dirfd, const char *path, struct stat *st,
int rc;
void *p;
union metastat ms;
if (IsAsan() && !__asan_is_valid(path, 1)) return efault();
if (IsAsan() && !__asan_is_valid_str(path)) return efault();
if (IsLinux()) {
_Static_assert(sizeof(*st) == sizeof(ms.linux), "assumption broken");
if (IsAsan() && (st && !__asan_is_valid(st, sizeof(*st)))) return efault();
+7 -1
View File
@@ -17,22 +17,26 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/cp.internal.h"
#include "libc/calls/internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/statfs-meta.internal.h"
#include "libc/calls/struct/statfs.internal.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/runtime/stack.h"
#include "libc/sysv/errfuns.h"
/**
* Returns information about filesystem.
* @return 0 on success, or -1 w/ errno
* @cancellationpoint
*/
int fstatfs(int fd, struct statfs *sf) {
int rc;
union statfs_meta m;
BEGIN_CANCELLATION_POINT;
CheckLargeStackAllocation(&m, sizeof(m));
if (!IsWindows()) {
if ((rc = sys_fstatfs(fd, &m)) != -1) {
statfs2cosmo(sf, &m);
@@ -42,6 +46,8 @@ int fstatfs(int fd, struct statfs *sf) {
} else {
rc = ebadf();
}
END_CANCELLATION_POINT;
STRACE("fstatfs(%d, [%s]) → %d% m", fd, DescribeStatfs(rc, sf));
return rc;
}
+11 -3
View File
@@ -17,32 +17,40 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/cp.internal.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/runtime/runtime.h"
/**
* Blocks until kernel flushes buffers for fd to disk.
*
* @return 0 on success, or -1 w/ errno
* @raise ECANCELED if thread was cancelled in masked mode
* @raise EINTR if signal was delivered
* @see fdatasync(), sync_file_range()
* @see __nosync to secretly disable
* @cancellationpoint
* @asyncsignalsafe
*/
int fsync(int fd) {
int rc;
struct stat st;
if (__nosync != 0x5453455454534146) {
BEGIN_CANCELLATION_POINT;
if (!IsWindows()) {
rc = sys_fsync(fd);
} else {
rc = sys_fdatasync_nt(fd);
}
END_CANCELLATION_POINT;
STRACE("fysnc(%d) → %d% m", fd, rc);
} else {
rc = 0;
STRACE("fsync(%d) → disabled% m", fd);
rc = fstat(fd, &st);
STRACE("fsync_fake(%d) → %d% m", fd, rc);
}
return rc;
}
+7 -1
View File
@@ -17,6 +17,7 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/cp.internal.h"
#include "libc/calls/internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
@@ -49,6 +50,7 @@
* @return 0 on success, or -1 w/ errno
* @raise EINVAL if `length` is negative
* @raise EINTR if signal was delivered instead
* @raise ECANCELED if thread was cancelled in masked mode
* @raise EIO if a low-level i/o error happened
* @raise EFBIG or EINVAL if `length` is too huge
* @raise ENOTSUP if `fd` is a zip file descriptor
@@ -56,12 +58,14 @@
* @raise EINVAL if `fd` is a non-file, e.g. pipe, socket
* @raise EINVAL if `fd` wasn't opened in a writeable mode
* @raise ENOSYS on bare metal
* @see truncate()
* @cancellationpoint
* @asyncsignalsafe
* @threadsafe
*/
int ftruncate(int fd, int64_t length) {
int rc;
BEGIN_CANCELLATION_POINT;
if (fd < 0) {
rc = ebadf();
} else if (__isfdkind(fd, kFdZip)) {
@@ -78,6 +82,8 @@ int ftruncate(int fd, int64_t length) {
} else {
rc = ebadf();
}
END_CANCELLATION_POINT;
STRACE("ftruncate(%d, %'ld) → %d% m", fd, length, rc);
return rc;
}
+14 -8
View File
@@ -34,7 +34,7 @@
#define HW_NCPUONLINE_NETBSD 16
#define ALL_PROCESSOR_GROUPS 0xffff
static unsigned GetCpuCountLinux(void) {
static unsigned _getcpucount_linux(void) {
cpu_set_t s = {0};
if (sys_sched_getaffinity(0, sizeof(s), &s) != -1) {
return CPU_COUNT(&s);
@@ -43,7 +43,7 @@ static unsigned GetCpuCountLinux(void) {
}
}
static unsigned GetCpuCountBsd(void) {
static unsigned _getcpucount_bsd(void) {
size_t n;
int c, cmd[2];
n = sizeof(c);
@@ -62,12 +62,12 @@ static unsigned GetCpuCountBsd(void) {
}
}
static unsigned GetCpuCountImpl(void) {
static unsigned _getcpucount_impl(void) {
if (!IsWindows()) {
if (!IsBsd()) {
return GetCpuCountLinux();
return _getcpucount_linux();
} else {
return GetCpuCountBsd();
return _getcpucount_bsd();
}
} else {
return GetMaximumProcessorCount(ALL_PROCESSOR_GROUPS);
@@ -77,18 +77,24 @@ static unsigned GetCpuCountImpl(void) {
static int g_cpucount;
// precompute because process affinity on linux may change later
__attribute__((__constructor__)) static void init(void) {
g_cpucount = GetCpuCountImpl();
__attribute__((__constructor__)) static void _getcpucount_init(void) {
g_cpucount = _getcpucount_impl();
}
/**
* Returns number of CPUs in system.
*
* This is the same as the standard interface:
*
* sysconf(_SC_NPROCESSORS_ONLN);
*
* Except this function isn't a bloated diamond dependency.
*
* On Intel systems with HyperThreading this will return the number of
* cores multiplied by two.
*
* @return cpu count or 0 if it couldn't be determined
*/
unsigned GetCpuCount(void) {
unsigned _getcpucount(void) {
return g_cpucount;
}
+1 -1
View File
@@ -42,7 +42,7 @@ char *sys_getcwd_xnu(char *res, size_t size) {
int fd;
union metastat st[2];
char buf[XNU_MAXPATHLEN], *ret = NULL;
if ((fd = sys_openat(AT_FDCWD, ".", O_RDONLY | O_DIRECTORY, 0)) != -1) {
if ((fd = __sys_openat_nc(AT_FDCWD, ".", O_RDONLY | O_DIRECTORY, 0)) != -1) {
if (__sys_fstat(fd, &st[0]) != -1) {
if (st[0].xnu.st_dev && st[0].xnu.st_ino) {
if (__sys_fcntl(fd, XNU_F_GETPATH, (uintptr_t)buf) != -1) {
+1 -1
View File
@@ -52,7 +52,7 @@ char *getcwd(char *buf, size_t size) {
return 0;
}
} else if (_weaken(malloc)) {
assert(!__vforked);
_unassert(!__vforked);
if (!size) size = PATH_MAX;
if (!(p = _weaken(malloc)(size))) {
STRACE("getcwd(%p, %'zu) %m", buf, size);
+9 -1
View File
@@ -18,6 +18,7 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/metalfile.internal.h"
#include "libc/calls/struct/metastat.internal.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/syscall-sysv.internal.h"
@@ -60,7 +61,14 @@ ssize_t getfiledescriptorsize(int fd) {
rc = -1;
}
} else if (IsMetal()) {
rc = -1;
if (fd < 0 || fd >= g_fds.n) {
rc = ebadf();
} else if (g_fds.p[fd].kind != kFdFile) {
rc = eacces();
} else {
struct MetalFile *state = (struct MetalFile *)g_fds.p[fd].handle;
rc = state->size;
}
} else if (!IsWindows()) {
if (!__sys_fstat(fd, &st)) {
rc = METASTAT(st, st_size);
+3 -3
View File
@@ -20,10 +20,10 @@
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/dce.h"
#include "libc/fmt/conv.h"
#include "libc/thread/thread.h"
#include "libc/macros.internal.h"
#include "libc/nt/accounting.h"
#include "libc/runtime/sysconf.h"
#include "libc/runtime/runtime.h"
#include "libc/thread/thread.h"
#define FT(x) (x.dwLowDateTime | (uint64_t)x.dwHighDateTime << 32)
@@ -60,7 +60,7 @@ static textstartup void sys_getloadavg_nt_init(void) {
double a[3];
if (IsWindows()) {
load = 1;
cpus = GetCpuCount() / 2;
cpus = _getcpucount() / 2;
cpus = MAX(1, cpus);
GetSystemTimes(&idle1, &kern1, &user1);
}
+58 -19
View File
@@ -16,28 +16,67 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/kntprioritycombos.internal.h"
#include "libc/calls/calls.h"
#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/nexgen32e/ffs.h"
#include "libc/nt/enum/processaccess.h"
#include "libc/nt/enum/processcreationflags.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/nt/thread.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/prio.h"
#include "libc/sysv/errfuns.h"
textwindows int sys_getpriority_nt(int ignored) {
size_t i;
uint32_t tier, lg2tier, wut;
if ((tier = GetPriorityClass(GetCurrentProcess())) != 0 &&
(wut = GetThreadPriority(GetCurrentThread())) != -1u) {
lg2tier = ffs(tier);
for (i = 0; i < kNtPriorityCombosLen; ++i) {
if (kNtPriorityCombos[i].lg2tier == lg2tier &&
kNtPriorityCombos[i].wut == wut) {
return kNtPriorityCombos[i].nice;
}
}
abort();
} else {
return __winerr();
textwindows int sys_getpriority_nt(int which, unsigned pid) {
int rc;
uint32_t tier;
int64_t h, closeme = -1;
if (which != PRIO_PROCESS) {
return einval();
}
if (!pid || pid == getpid()) {
h = GetCurrentProcess();
} else if (__isfdkind(pid, kFdProcess)) {
h = g_fds.p[pid].handle;
} else {
h = OpenProcess(kNtProcessQueryInformation, false, pid);
if (!h) return __winerr();
closeme = h;
}
if ((tier = GetPriorityClass(h))) {
switch (tier) {
case kNtRealtimePriorityClass:
rc = -16;
break;
case kNtHighPriorityClass:
rc = -10;
break;
case kNtAboveNormalPriorityClass:
rc = -5;
break;
case kNtNormalPriorityClass:
rc = 0;
break;
case kNtBelowNormalPriorityClass:
rc = 5;
break;
case kNtIdlePriorityClass:
rc = 15;
break;
default:
notpossible;
}
} else {
rc = __winerr();
}
if (closeme != -1) {
CloseHandle(closeme);
}
return rc;
}
+40 -10
View File
@@ -17,10 +17,13 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asmflag.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/limits.h"
/**
* Returns nice value of thing.
@@ -29,20 +32,47 @@
* to clear `errno` beforehand and see if it changed, in order to truly
* determine if an error happened.
*
* @param which can be PRIO_PROCESS, PRIO_PGRP, PRIO_USER
* On Windows, there's only six priority classes. We define them as -16
* (realtime), -10 (high), -5 (above), 0 (normal), 5 (below), 15 (idle)
* which are the only values that'll roundtrip getpriority/setpriority.
*
* @param which can be one of:
* - `PRIO_PROCESS` is supported universally
* - `PRIO_PGRP` is supported on unix
* - `PRIO_USER` is supported on unix
* @param who is the pid, pgid, or uid (0 means current)
* @return value ∈ [-NZERO,NZERO) or -1 w/ errno
* @see setpriority(), nice()
* @raise EINVAL if `which` was invalid or unsupported
* @raise EPERM if access to process was denied
* @raise ESRCH if no such process existed
* @see setpriority()
*/
int getpriority(int which, unsigned who) {
privileged int getpriority(int which, unsigned who) {
int rc;
if (!IsWindows()) {
if ((rc = sys_getpriority(which, who)) != -1) {
rc = 20 - rc;
char cf;
if (IsLinux()) {
asm volatile("syscall"
: "=a"(rc)
: "0"(140), "D"(which), "S"(who)
: "rcx", "r11", "memory");
if (rc >= 0) {
rc = NZERO - rc;
} else {
errno = -rc;
rc = -1;
}
} else if (IsBsd()) {
asm volatile(CFLAG_ASM("syscall")
: CFLAG_CONSTRAINT(cf), "=a"(rc)
: "1"((IsXnu() ? 0x2000000 : 0) | 100), "D"(which), "S"(who)
: "rcx", "rdx", "r8", "r9", "r10", "r11", "memory");
if (cf) {
errno = rc;
rc = -1;
}
} else {
rc = sys_getsetpriority_nt(which, who, 0, sys_getpriority_nt);
rc = sys_getpriority_nt(which, who);
}
STRACE("getpriority(%d, %u) → %d% m", which, who, rc);
STRACE("getpriority(%s, %u) → %d% m", DescribeWhichPrio(which), who, rc);
return rc;
}
@@ -17,6 +17,7 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/metalfile.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
@@ -76,6 +77,11 @@ static inline void GetProgramExecutableNameImpl(char *p, char *e) {
return;
}
if (IsMetal()) {
if (!memccpy(p, APE_COM_NAME, 0, e - p - 1)) e[-1] = 0;
return;
}
// if argv[0] exists then turn it into an absolute path. we also try
// adding a .com suffix since the ape auto-appends it when resolving
if (__argc && (((q = __argv[0]) && !sys_faccessat(AT_FDCWD, q, F_OK, 0)) ||
+1 -4
View File
@@ -33,7 +33,7 @@
#include "libc/sysv/errfuns.h"
textwindows int sys_getrusage_nt(int who, struct rusage *usage) {
int64_t me, nsignals;
int64_t me;
struct NtIoCounters iocount;
struct NtProcessMemoryCountersEx memcount;
struct NtFileTime ftExit, ftUser, ftKernel, ftCreation;
@@ -48,9 +48,6 @@ textwindows int sys_getrusage_nt(int who, struct rusage *usage) {
!GetProcessIoCounters(me, &iocount)) {
return __winerr();
}
__sig_lock();
nsignals = __sig_count;
__sig_unlock();
*usage = (struct rusage){
.ru_utime = WindowsDurationToTimeVal(ReadFileTime(ftUser)),
.ru_stime = WindowsDurationToTimeVal(ReadFileTime(ftKernel)),
+1 -1
View File
@@ -63,7 +63,7 @@ int gettimeofday(struct timeval *tv, struct timezone *tz) {
rc = __gettimeofday(tv, tz, 0).ax;
}
#if SYSDEBUG
if (!(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
if (__tls_enabled && !(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
STRACE("gettimeofday([%s], %p) → %d% m", DescribeTimeval(rc, tv), tz, rc);
}
#endif
+2 -3
View File
@@ -18,7 +18,6 @@ hidden extern const struct Fd kEmptyFd;
int __reservefd(int) hidden;
int __reservefd_unlocked(int) hidden;
void __releasefd(int) hidden;
void __releasefd_unlocked(int) hidden;
int __ensurefds(int) hidden;
int __ensurefds_unlocked(int) hidden;
void __printfds(void) hidden;
@@ -43,8 +42,8 @@ forceinline size_t _clampio(size_t size) {
}
}
int sys_close_nt(struct Fd *) hidden;
bool _check_interrupts(bool, struct Fd *) hidden;
int sys_close_nt(struct Fd *, int) hidden;
int _check_interrupts(bool, struct Fd *) hidden;
int sys_openat_metal(int, const char *, int, unsigned);
COSMOPOLITAN_C_END_
+14 -6
View File
@@ -18,25 +18,33 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/fd.internal.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/lockcmpxchgp.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/thread.h"
#include "libc/thread/tls.h"
textwindows bool _check_interrupts(bool restartable, struct Fd *fd) {
bool res;
if (__threaded && __threaded != gettid()) return false;
textwindows int _check_interrupts(bool restartable, struct Fd *fd) {
int rc;
if (_weaken(pthread_testcancel_np) &&
(rc = _weaken(pthread_testcancel_np)())) {
errno = rc;
return -1;
}
if (_weaken(_check_sigalrm)) _weaken(_check_sigalrm)();
if (!(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
if (!__tls_enabled || !(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
if (_weaken(_check_sigchld)) _weaken(_check_sigchld)();
if (fd && _weaken(_check_sigwinch)) _weaken(_check_sigwinch)(fd);
}
res = _weaken(__sig_check) && _weaken(__sig_check)(restartable);
return res;
if (_weaken(__sig_check) && _weaken(__sig_check)(restartable)) return eintr();
return 0;
}
+1 -1
View File
@@ -253,7 +253,7 @@ static int createHostInfo(struct NtIpAdapterAddresses *firstAdapter) {
int count, i;
/* __hostInfo must be empty */
assert(__hostInfo == NULL);
_unassert(__hostInfo == NULL);
for (aa = firstAdapter; aa; aa = aa->Next) {
/* Skip all the interfaces with no address and the ones that are not AF_INET
+1 -1
View File
@@ -51,7 +51,7 @@ bool isdirectory(const char *path) {
union metastat st;
struct ZiposUri zipname;
e = errno;
if (IsAsan() && !__asan_is_valid(path, 1)) {
if (IsAsan() && !__asan_is_valid_str(path)) {
efault();
res = false;
} else if (_weaken(__zipos_open) &&
+1 -1
View File
@@ -48,7 +48,7 @@ bool isregularfile(const char *path) {
union metastat st;
struct ZiposUri zipname;
e = errno;
if (IsAsan() && !__asan_is_valid(path, 1)) {
if (IsAsan() && !__asan_is_valid_str(path)) {
efault();
res = false;
} else if (_weaken(__zipos_open) &&
+1 -1
View File
@@ -51,7 +51,7 @@ bool issymlink(const char *path) {
union metastat st;
struct ZiposUri zipname;
e = errno;
if (IsAsan() && !__asan_is_valid(path, 1)) {
if (IsAsan() && !__asan_is_valid_str(path)) {
efault();
res = false;
} else if (_weaken(__zipos_open) &&
+5 -1
View File
@@ -17,10 +17,10 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/str/str.h"
/**
@@ -38,6 +38,10 @@
* >0 can be SIGINT, SIGTERM, SIGKILL, SIGUSR1, etc.
* =0 checks both if pid exists and we can signal it
* @return 0 if something was accomplished, or -1 w/ errno
* @raise ESRCH if `pid` couldn't be found
* @raise EPERM if lacked permission to signal process
* @raise EPERM if pledge() is in play without `proc` promised
* @raise EINVAL if the provided `sig` is invalid or unsupported
* @asyncsignalsafe
*/
int kill(int pid, int sig) {
-56
View File
@@ -1,56 +0,0 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ Permission to use, copy, modify, and/or distribute this software for │
│ any purpose with or without fee is hereby granted, provided that the │
│ above copyright notice and this permission notice appear in all copies. │
│ │
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/intrin/bits.h"
#include "libc/calls/kntprioritycombos.internal.h"
#include "libc/limits.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/ffs.h"
#include "libc/nt/enum/processcreationflags.h"
#include "libc/nt/enum/threadpriority.h"
hidden const struct NtPriorityCombo kNtPriorityCombos[] = {
{-20, ffs(kNtHighPriorityClass), kNtThreadPriorityHighest, 15},
{-18, ffs(kNtHighPriorityClass), kNtThreadPriorityTimeCritical, 15},
{-17, ffs(kNtNormalPriorityClass), kNtThreadPriorityTimeCritical, 15},
{-15, ffs(kNtIdlePriorityClass), kNtThreadPriorityTimeCritical, 15},
{-13, ffs(kNtHighPriorityClass), kNtThreadPriorityAboveNormal, 14},
{-11, ffs(kNtHighPriorityClass), kNtThreadPriorityNormal, 13},
{-9, ffs(kNtHighPriorityClass), kNtThreadPriorityBelowNormal, 12},
{-7, ffs(kNtNormalPriorityClass), kNtThreadPriorityHighest, 11},
{-5, ffs(kNtHighPriorityClass), kNtThreadPriorityLowest, 11},
{-3, ffs(kNtNormalPriorityClass), kNtThreadPriorityAboveNormal, 10},
{-1, ffs(kNtNormalPriorityClass), kNtThreadPriorityHighest, 9},
{0, ffs(kNtNormalPriorityClass), kNtThreadPriorityNormal, 9},
{1, ffs(kNtNormalPriorityClass), kNtThreadPriorityAboveNormal, 8},
{2, ffs(kNtNormalPriorityClass), kNtThreadPriorityBelowNormal, 8},
{3, ffs(kNtNormalPriorityClass), kNtThreadPriorityNormal, 7},
{4, ffs(kNtNormalPriorityClass), kNtThreadPriorityLowest, 7},
{5, ffs(kNtIdlePriorityClass), kNtThreadPriorityHighest, 6},
{6, ffs(kNtNormalPriorityClass), kNtThreadPriorityBelowNormal, 6},
{7, ffs(kNtIdlePriorityClass), kNtThreadPriorityAboveNormal, 5},
{9, ffs(kNtNormalPriorityClass), kNtThreadPriorityLowest, 5},
{11, ffs(kNtIdlePriorityClass), kNtThreadPriorityNormal, 4},
{13, ffs(kNtIdlePriorityClass), kNtThreadPriorityBelowNormal, 3},
{15, ffs(kNtIdlePriorityClass), kNtThreadPriorityLowest, 2},
{17, ffs(kNtHighPriorityClass), kNtThreadPriorityIdle, 1},
{18, ffs(kNtNormalPriorityClass), kNtThreadPriorityIdle, 1},
{19, ffs(kNtIdlePriorityClass), kNtThreadPriorityIdle, 1},
};
hidden const unsigned kNtPriorityCombosLen = ARRAYLEN(kNtPriorityCombos);
-18
View File
@@ -1,18 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_KNTPRIORITYCOMBOS_H_
#define COSMOPOLITAN_LIBC_CALLS_KNTPRIORITYCOMBOS_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct NtPriorityCombo {
int8_t nice; /* sorted by this */
int8_t lg2tier;
int8_t wut;
int8_t prio;
};
hidden extern const unsigned kNtPriorityCombosLen;
hidden extern const struct NtPriorityCombo kNtPriorityCombos[];
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_KNTPRIORITYCOMBOS_H_ */
+1 -1
View File
@@ -41,7 +41,7 @@ int linkat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath,
int flags) {
int rc;
if (IsAsan() &&
(!__asan_is_valid(oldpath, 1) || !__asan_is_valid(newpath, 1))) {
(!__asan_is_valid_str(oldpath) || !__asan_is_valid_str(newpath))) {
rc = efault();
} else if (_weaken(__zipos_notat) &&
((rc = __zipos_notat(olddirfd, oldpath)) == -1 ||
+2
View File
@@ -34,6 +34,8 @@ textwindows int64_t sys_lseek_nt(int fd, int64_t offset, int whence) {
} else {
return espipe();
}
} else if (__isfdkind(fd, kFdSocket)) {
return espipe();
} else {
return ebadf();
}
Loaded 100 of 1379 files, more files were not shown because too many files have changed in this diff. Show more