Compare commits

...
85 Commits
Author SHA1 Message Date
Justin Tunney aefad27c09 Add bootstrap binary for elf2pe
It's now easier to cross compile a 2.5 kb hello world program for win32,
on arm64 xnu, that'll run on the very latest Windows, e.g.

cosmo-make -j12 m=x86_64 o/x86_64/tool/hello/hello-pe.ape
2026-10-20 18:25:16 -04:00
Gavin Hayes b0cebefd8e Fix GetProgramExecutableName() on NetBSD (#1529)
The sysctl parameters for querying KERN_PROC_PATHNAME are different from
FreeBSD. The tests now check the GPEN path using stat instead of strcmp.
2026-10-20 00:04:57 -04:00
Gavin Hayes 34fa4edae8 Update Fexecve to try execveat first on Linux (#1528)
Using execveat makes it possible for non-APE fexecve to work when procfs
is not mounted (LSMs may require procfs to be mounted so there is a path
for the file). Additionally, we now do not retry if errno is not ENOSYS,
ENOEXEC, or ELIBBAD as the retry funcs will still fail for other errors.
2026-10-13 17:41:14 -04:00
Gavin Hayes c7c9916eb8 Fix (f)execve tests under landlock make (#1527) 2026-10-13 06:39:25 -04:00
Justin Tunney 88848afdff Fix bugs in ctl 2026-10-12 18:28:01 -04:00
Justin Tunney e0c68ba56b Import some bug fixes from Musl Libc
Credit goes to Liam Wachter, Rich Felker, Szabolcs Nagy, and Yao Zi.
2026-10-12 17:57:21 -04:00
Justin Tunney bc6f307aa5 Update MaxMind library 2026-10-12 04:07:37 -04:00
Justin Tunney 7bc687dbc4 Fix warning with my Emacs config 2026-10-12 00:32:29 -04:00
Justin Tunney 1bc2a45f4a Make process initialization go faster 2026-10-11 19:42:53 -04:00
Justin Tunney 6ad44a10c2 Remove dated and incomplete romanize example 2026-10-11 04:24:30 -04:00
Justin Tunney 9607bee4b2 Make Plinko more hackable 2026-10-11 02:22:34 -04:00
Justin Tunney 2143d61dfa Improve POSIX conformance of freopen() 2026-10-10 22:20:30 -04:00
Gavin Hayes fdea2482dd Rewrite fexecve for better zipos & APE handling (#888)
This is essentially a rewrite of the entire `fexecve` implementation. We
no longer attempt to attempt to assimilate APEs in mem -- if the syscall
fails we fallback to sys_execve(/dev/fd/X so the APE loader can be used.
When a zipos file descriptor is passed, the new memfd is now only leaked
if the file has zipos (is a ZIP file) or is an APE, otherwise FD_CLOEXEC
is set on it (so non-zip ELFs do not leak). Previously FD_CLOEXEC on APE
binaries was not set when copying to a `memfd`, due to the security risk
of still leaking a fd, we no longer do so. FD_CLOEXEC does not work with
the APE loader (we may be able to later add support using AT_EXECFD). On
Linux, non-zip ELF files with only execute permissions may be opened and
run with _OPATH. The new version is vforksafe+asyncsignalsafe. To ensure
even on failure, the `memfd` will be cleaned up, pthread_cleanup_push is
used. zipos fexecve fails with `ENOTSUP` when `__vforked` so it does not
leak a `memfd` into the parent process if there is pthread cancellation.

The tests were revamped to more completely cover the various branches of
ELF or APE, zip file or not, `FD_CLOEXEC`, `O_PATH`, zipos fd or not, or
vforked. Additionally, there are checks for fd leaks. Feature testing is
done on Linux for the tests that rely on kernels newer than 2.6.18 so in
theory they should still pass on old Linux. For now, the zipos (f)execve
tests are only enabled on Linux as they have not been tested on FreeBSD.
The test files pass on Linux, Qemu user aarch64/x86_64, and Windows Ten.
2026-10-07 01:54:35 -04:00
Gavin Hayes c7d64e1b8b fix(execve-sysv): on shell fallback always terminate argv even when argc == 0 (#1525) 2026-10-06 10:31:45 -04:00
Gavin Hayes 977d10172c fix: include __program_executable_name in stack mapping even if argc == 0 (#1519) 2026-10-06 10:13:31 -04:00
Gavin Hayes 3293fad0a9 cleanup remnants of kErrnoNames (#1507)
https://github.com/jart/cosmopolitan/commit/5ddb5c2adad79407fb800fce47f389611f90a511
removed kErrnoNames , but left it in the header.
2026-07-19 21:14:06 -05:00
Justine Tunney 036845632f Fix bug with complex math
This change fixes a bug impacting complex math, where division of double
and float values (as in __divdc3, __divsc3) produced (inf, nan) whenever
the divisor's largest component was below one in magnitude, such as this
1. / (.5 + 0i) yielded (inf, nan) instead of the (2, 0) that is correct.
The same flaw sadly applied to any divisor with max(|real|, |imag|) < 1.

The bug was hidden by how -fcx-limited-range (part of -ffast-math) makes
the compiler inline naive division instead of calling __divdc3. Numerous
tests have been added so that this will not regress again in the future.

The bug was almost certainly caused by a misguided attempt to address an
undefined behavior sanitizer (UBSAN) warning (m=dbg) w/ signed shifting.
2026-05-31 09:58:10 -07:00
Justine Tunney 4a47191f51 Make qsort not depend on malloc 2026-05-21 19:15:02 -07:00
Justine Tunney a831042eca Clean up some code 2026-05-20 15:49:13 -07:00
Justine Tunney b4b5af498f Support C11 threads API
The C11 standard threads API is a subset of the POSIX threads API. It is
cool, because for example C11 mutexes can be a lighter weight wrapper of
nsync that only needs 24 bytes per `mtx_t` as opposed to pthread_mutex_t
requiring 64 bytes per mutex. To test that it all works, dozens of tests
have been added to the test/c11/ and test/posix/ folders.
2026-05-20 14:32:32 -07:00
Justine Tunney 18e3a2e7ce Improve invalid lock timestamp checking 2026-05-20 13:30:20 -07:00
Justine Tunney bc37215177 Fix EINTR bug in pthread_cond_timedwait
In cases where NSYNC isn't being used, the backup code path wasn't right
when it came to spinning on interrupt and checking the futex. This error
was caught thanks to a new suite of posix and c11 tests coming soon.
2026-05-20 13:09:44 -07:00
Justine Tunney 7e35bc854f Fix past timestamp lock bug on Windows and XNU 2026-05-20 12:41:23 -07:00
Justine Tunney 6eb8da23d4 Fix NetBSD lock signal bug 2026-05-20 12:25:04 -07:00
Justine Tunney 0b80275299 Introduce pthread_mutex_clocklock() 2026-05-20 10:25:15 -07:00
Justine Tunney ee883eabb3 Introduce nsync_mu_timedlock 2026-05-20 05:59:11 -07:00
Justine Tunney 7666e63ef9 Fix issue with RLIMIT_NOFILE on Windows 2026-05-20 02:04:35 -07:00
Justine Tunney 60734c784a Improve smoothsort
This change imports upstream changes from Musl Libc that protect us from
unknown security bugs. I've also made some changes of my own, to make it
go faster sorting small two power widths.
2026-05-18 14:15:59 -07:00
Justine Tunney deb866efd5 Remove openmp_test 2026-05-18 11:38:13 -07:00
Justine Tunney ad16ba5460 Add llround, llroundf, and llroundl 2026-05-18 07:39:14 -07:00
Justine Tunney db041429ed Increase turfwar queue size 2026-05-18 07:38:37 -07:00
Gautham eedf7d2db6 Add some headers and stubs (#1474)
- signal.h should show ucontext
- dlopen-related
- SIGIOT (is just SIGABRT)
~~itimerspec~~
~~sigevent~~
~~timer_create~~
2026-03-05 16:18:22 -08:00
Gautham 9ba2b50805 Set PF_INET = 2 on Windows (#1441) 2026-01-18 23:40:41 -08:00
Tobias Fleischer 7ecf16e306 Remove conflicting defines in windowsesque.h (#1467) 2026-01-18 23:39:21 -08:00
James Hulce db617bfd58 Update lsqlite3 documentation link comments (#1428) 2026-01-18 17:18:45 -08:00
BONNAURE Olivier 9b1285b915 Update onError in definition.lua (#1442) 2026-01-18 17:10:12 -08:00
Justine Tunney b444b3a6e0 Fix regressions in strcasechr, wcschr, strchr16
This change fixes a regression introduced by string library improvements
in 5ddb5c2ada that could cause wcschr(s,0)
to return NULL rather than a pointer to the end of the string.
2025-12-02 00:35:55 -08:00
Justine Tunney b0fdf97054 Syntax highlight .inc files 2025-11-18 18:30:50 -08:00
Justine Tunney 2f786453ee Fix VSCode 2025-11-18 17:24:36 -08:00
Justine Tunney 694ef1aa8b Remove optlinux from github actions
The cosmocc -moptlinux mode assumes you have an Intel / AMD CPU with AVX
however the GA instances we've been getting are faulting on AVX opcodes.
2025-11-18 14:12:55 -08:00
Justine Tunney bc0fc702fe Remove more miniaudio.h ifdefs 2025-11-18 12:39:18 -08:00
Justine Tunney bea62f3631 Upgrade miniaudio to v0.11.23 2025-11-18 11:52:53 -08:00
Gautham dee25272f1 Use --std=gnu17 for cosmocc (#1452)
Third party libraries in superconfigure have compiler checks, that error
out for C23, so the preference would be to use C17 for a while until all
those libraries are updated.
2025-11-17 11:17:02 -08:00
Justine Tunney 5ddb5c2ada Make improvements
- Open flags (e.g. O_CREAT) are now constants
- Error numbers (e.g. EINVAL) are now constants
- Signal numbers (e.g. SIGINT) are now constants
- fcntl() file locks now work properly on Windows
- Significantly improve Windows path handling code
- Implement true vfork() on Windows and make fork() faster
- Implement scanf %[charset] support and improve conformance
- Introduce $COSMOSDRIVE so you can use Windows 11 dev drives
- Fix stdio seek/tell bug and make stdio locks faster and safer
- Change TLS ABI to use tlscc wrapper that inserts function calls
- Make malloc() faster on all platforms using new cosmo_shard() api
- Make malloc() fast like tcmalloc on Linux using restartable sequences
- Improve fsync() and fdatasync() polyfills so they abstract robustness
- Fix CLOCK_BOOTTIME and CLOCK_MONOTONIC on XNU so it reflects uptime
- Fix bugs in Windows overlapped code that could possibly cause crash
- Fix bugs in Windows signal code that could possibly cause crash
- Make symlinks with multiple components work right on Windows
- Add FreeBSD ELF note to remove SIGBUS issue and other quirks
- Support symlinks on Windows under non-administrator accounts
- Make kisdangerous() scalable by adding radix trie to mmap()
- Make large realloc() operations zero-cost on all platforms
- Fix bugs in readdir() on Windows where d_reclen wasn't set
- Make all system call wrappers memory safe (raises EFAULT)
- Fix bugs in poll() and select() on Windows with 64+ fds
- Fix bug in madvise() on Windows that could cause crash
- Support WUNTRACED, SIGSTOP, and SIGCONT on Windows
- Increase x86 image base from 0x400000 to 0x4200000
- Introduce -msysv and -mtinylinux flags to cosmocc
- Fix issues with siglongjmp() on XNU and NetBSD
- Make pthread_barrier_wait() work correctly
- Make clock_gettime() faster on FreeBSD ARM
- Support file mode bits better on Windows
- Improve performance of string libraries
- Raise EILSEQ when creating evil paths
- Fix std::terminate to not use malloc
- Modernize more c11 and c23 features
- Make pthread_once() exception safe
- Support RLIMIT_CPU on Windows
- Introduce HACL* cryptography
- Introduce cosmopolitan make
- Introduce fasterzip program
- Introduce open_memstream()
- Introduce dedupe program
- Introduce arc4random()
- Introduce f2fs support
2025-11-16 21:15:26 -08:00
Alexar f1dc5cff44 Make redbean probe for port on bind failure (#1451)
When redbean is starting up, if you don't explicitly specify a port then
it'll choose the default one, which is 8080. If that port is in use then
redbean will increment the port number up to 20 times before it gives up
2025-11-15 08:28:34 -08:00
Hugues Morisset f1e83d5240 Add IPv6 support to getifaddrs() on Linux (#1415) 2025-05-21 01:20:22 -07:00
Steven Dee (Jōshin) 2fe8338f92 Better mtimes for github workflow build cache (#1421)
Saves and restores mtimes to a file, also covering the `o/` directory to
hopefully preserve make dependency information better.
2025-05-20 22:17:55 -07:00
ShalokShalom 4ca513cba2 Add C++ to README (#1407) 2025-04-25 15:47:50 -07:00
Steven Dee (Jōshin) 455910e8f2 Make more shared_ptr fixes (#1401)
* Make refcount reads explicitly atomic
* Consistently put `const` in the same place
* Write the general `operator=` on `weak_ptr`
2025-04-21 05:36:50 -07:00
Steven Dee (Jōshin) 9c68bc19b5 Cache .cosmocc and o for github workflows (#1400)
Uses GitHub’s actions/cache@v4 to store the cosmocc distribution and the
output directory between runs of the build workflow, with the version of
cosmocc as the cache key.

Upgrades to actions/checkout@v4.
2025-04-17 15:55:27 -07:00
Steven Dee (Jōshin) 66d1050af6 Correctly implement weak_ptr assignment/copy/moves (#1399) 2025-04-17 14:01:20 -07:00
Justine Tunney fbc4fcbb71 Get GDB working
You can now say `gdb hello.com.dbg` and it'll work perfectly.
2025-03-30 15:25:55 -07:00
Steven Dee (Jōshin) afc986f741 Fix shared_ptr<T>::owner_before (#1390)
`!(a < b)` is not the same as `b < a`.

I think I originally wrote it this way to avoid making weak_ptr a friend
of shared_ptr, but weak_ptr already is a friend.
2025-03-25 01:49:34 -04:00
Derek 5eb7cd6643 Add support for getcpu() system call to pledge() (#1387)
This fixes redbean Lua tests which were failing with SIGSYS on Linux.
2025-03-21 16:08:25 -07:00
Brett Jia a8ed4fdd09 Add NetBSD evbarm and fix segfault (#1384)
This change fixes a segmentation fault when comparing loaders that don't
have a target kernel set. Additionally, adds evbarm, which is the output
of uname -m on NetBSD on aarch64.
2025-03-12 17:37:46 -07:00
Brett Jia 7b69652854 Add -k OSNAME flag to apelink (#1383)
Let's say you pass the `-M blink-mips.elf` flag to apelink, so that your
ape binary will bundle a compressed build of blink, and the shell script
will extract that binary and launch your program under it, if running on
a MIPS system. However, for any given microprocessor architecture, we'll
need a separate loader for each operating system. The issue is ELF OSABI
isn't very useful. As an example, SerenityOS and Linux both have SYSV in
the OSABI field. So to tell their binaries apart we'd have to delve into
various other conventions, like special sections and PT_NOTE structures.

To make things simple this change introduces the `-k OS` flag to apelink
which generate shell script content that ensures `OS` matches `uname -s`
before attempting to execute a loader. For example, you could say:

    apelink -k Linux -M blink-linux-arm.elf -M blink-linux-mips.elf \
            -k Darwin -M blink-darwin-ppc.elf \
            ...

To introduce support for old 32-bit architectures on multiple OSes, when
building your cosmo binary.
2025-03-12 13:26:51 -07:00
Leal G. b235492e71 Add usertrust certificate (#1382)
Bundle USERTrust CA certificates to /usr/share/ssl/root for TLS verifies
2025-03-11 17:59:34 -07:00
Brett Jia fc81fd8d16 Support additional architectures in apelink (#1381)
This updates apelink to support machine architectures not in the source
program input list by adding additional loaders, extracting the correct
one that matches the host uname machine. With this change, blink can be
supplied as the additional loader to run the program in x86_64 VMs. The
change has been verified against blink 1.0, powerpc64le and mips64el in
Docker using QEMU.
2025-03-06 10:26:31 -08:00
Gautham 38930de8e0 Make tool for replacing ELF strings (#1344) 2025-02-08 21:17:42 -08:00
Brett Jia 0e557d041d Check downloaded gcc/clang checksums (#1367)
Check sha256 checksums of the downloaded gcc and clang toolchains. It'll
allow us to extend trust to external toolchains if building from source.
2025-02-08 17:46:09 -08:00
Brett Jia 1d676b36e6 Make cosmoranlib executable (#1366)
Fixes #1325
2025-02-08 17:38:00 -08:00
Brett Jia 10a92cee94 Support building cosmocc on MacOS (#1365)
This updates the cosmocc toolchain packaging script to work on MacOS. It
has been tested on GitHub Actions macos-13 (x86_64) and macos-14 (arm64)
runners, and is verified to still work on Ubuntu (GitHub Actions runners
ubuntu-24.04 and ubuntu-24.04-arm). It'll help bring cosmocc to MacPorts
by running the packaging script. We favor `gmake` rather than the `make`
command because it distinguishes GNU Make from BSD Make, and Xcode Make.
Additionally, APE loader from the bootstrapper toolchain is used instead
of a system APE, which may not be available.
2025-02-08 12:45:45 -08:00
A2va 42a9ed0131 Adds some NT functions (#1358) 2025-02-08 08:08:08 -08:00
Björn Buckwalter 12cb0669fb Clarify unix.mapshared versus file locks (#1355) 2025-02-08 00:48:38 -08:00
rufeooo 7f6a7d6fff Fix sigaction example code (#1363) 2025-02-07 11:42:47 -08:00
Steven Dee (Jōshin) 9f6bf6ea71 tool/zsh/mkofs: doas 2025-01-13 16:48:55 -08:00
Steven Dee (Jōshin) 102edf4ea2 tool/zsh/mmake: style 2025-01-05 20:53:53 -08:00
Steven Dee (Jōshin) 21968acf99 Standard make path (#1353)
Modifies download-cosmocc.sh to maintain a .cosmocc/current symlink that
always points to the most recently downloaded version of cosmocc. We can
use this to point at a canonical make for a bootstrapped repository. For
first-time builds, we suggest: https://cosmo.zip/pub/cosmos/bin/make and
have updated the docs in a few places to mention this.

Fixes the other part of #1346.
2025-01-05 20:47:34 -08:00
Justine Tunney 98861b23fc Make some style fixes to prng code 2025-01-05 20:18:05 -08:00
Steven Dee (Jōshin) dab6d7a345 Resolve multiple definition of __sig (fixes #1346) (#1352) 2025-01-05 19:54:49 -08:00
Justine Tunney 90119c422c Fix 404 url
Closes #1347
2025-01-05 17:04:37 -08:00
Justine Tunney 5907304049 Release Cosmopolitan v4.0.2 2025-01-05 14:05:49 -08:00
Justine Tunney 035b0e2a62 Attempt to fix MODE=dbg Windows execve() flake 2025-01-05 14:05:49 -08:00
Justine Tunney 7b67b20dae Fix Windows MODE=tiny breakage 2025-01-05 14:05:49 -08:00
Himanshu Pal f0b0f926bf Enable sqlite3 serialization in redbean (#1349)
This fixes a failing demo page, that requires us to enable serialization
in the lsqlite3 library that's used by the redbean server.
2025-01-05 13:59:10 -08:00
Justine Tunney 29eb7e67bb Fix fork() regression on Windows
Recent optimizations to fork() introduced a regression, that could cause
the subprocess to fail unexpectedly, when TlsAlloc() returns a different
index. This is because we were burning the indexes into the displacement
of x86 opcodes. So when fork() happened and the executable memory copied
it would use the old index. Right now the way this is being solved is to
not copy the executable on fork() and then re-apply code changes. If you
need to be able to preserve self-modified code on fork, reach out and we
can implement a better solution for you. This gets us unblocked quickly.
2025-01-05 09:25:23 -08:00
Justine Tunney f71f61cd40 Add some temporary logging statements 2025-01-04 23:37:32 -08:00
Justine Tunney 53c6edfd18 Make correction to last change 2025-01-04 21:38:47 -08:00
Justine Tunney 42a3bb729a Make execve() linger when it can't spoof parent
It's now possible to use execve() when the parent process isn't built by
cosmo. In such cases, the current process will kill all threads and then
linger around, waiting for the newly created process to die, and then we
propagate its exit code to the parent. This should help bazel and others

Allocating private anonymous memory is now 5x faster on Windows. This is
thanks to VirtualAlloc() which is faster than the file mapping APIs. The
fork() function also now goes 30% faster, since we are able to avoid the
VirtualProtect() calls on mappings in most cases now.

Fixes #1253
2025-01-04 21:13:37 -08:00
Justine Tunney c97a858470 Remove missing definitions 2025-01-04 00:20:45 -08:00
Justine Tunney 4acd12a514 Release Cosmopolitan v4.0.1 2025-01-03 19:51:34 -08:00
Justine Tunney b734eec836 Test restricting tests to single cpu 2025-01-03 19:51:09 -08:00
Justine Tunney fe01642a20 Add missing lock to fork() on Windows 2025-01-03 19:01:58 -08:00
Justine Tunney e939659b70 Fix ordering of pthread_create(pthread_t *thread)
This change fixes a bug where signal_latency_async_test would flake less
than 1/1000 of the time. What was happening was pthread_kill(sender_thr)
would return EFAULT. This was because pthread_create() was not returning
the thread object pointer until after clone() had been called. So it was
actually possible for the main thread to stall after calling clone() and
during that time the receiver would launch and receive a signal from the
sender thread, and then fail when it tried to send a pong. I thought I'd
use a barrier at first, in the test, to synchronize thread creation, but
I firmly believe that pthread_create() was to blame and now that's fixed
2025-01-03 17:34:29 -08:00
Justine Tunney ed6d133a27 Use tgkill() on Linux and FreeBSD
This eliminates the chance of rare bugs when thread IDs are recycled.
2025-01-03 17:27:13 -08:00
2897 changed files with 224249 additions and 133833 deletions

No files matched your search

+41 -3
View File
@@ -1,5 +1,8 @@
name: build
env:
COSMOCC_VERSION: 3.9.2
on:
push:
branches:
@@ -17,15 +20,50 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
mode: ["", tiny, rel, tinylinux, optlinux]
mode: ["", tiny, rel, tinylinux]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
# Full checkout needed for git-restore-mtime-bare.
fetch-depth: 0
# TODO(jart): fork this action.
- uses: chetan/git-restore-mtime-action@v2
- uses: actions/cache/restore@v4
id: cache
with:
path: |
.cosmocc
o
key: ${{ env.COSMOCC_VERSION }}-${{ matrix.mode }}-${{ github.sha }}
restore-keys: |
${{ env.COSMOCC_VERSION }}-${{ matrix.mode }}-
${{ env.COSMOCC_VERSION }}-
- name: Restore mtimes
if: steps.cache.outputs.cache-hit == 'true'
run: |
while read mtime file; do
[ -f "$file" ] && touch -d "@$mtime" "$file"
done < o/.mtimes
- name: support ape bins 1
run: sudo cp build/bootstrap/ape.elf /usr/bin/ape
run: sudo cp -a build/bootstrap/ape.elf /usr/bin/ape
- name: support ape bins 2
run: sudo sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register"
- name: make matrix
run: V=0 make -j2 MODE=${{ matrix.mode }}
- name: Save mtimes
run: |
find o -type f -exec stat -c "%Y %n" {} \; > o/.mtimes
- uses: actions/cache/save@v4
with:
path: |
.cosmocc
o
key: ${{ env.COSMOCC_VERSION }}-${{ matrix.mode }}-${{ github.sha }}
+1
View File
@@ -1,6 +1,7 @@
# -*- conf -*-
/o
/core
/cosmocc
/.cosmocc
+29
View File
@@ -0,0 +1,29 @@
{
"configurations": [
{
"name": "Cosmopolitan",
"includePath": [
"${workspaceFolder}",
"${workspaceFolder}/libc/isystem"
],
"defines": [
"_COSMO_SOURCE",
"MODE=\"aarch64\""
],
"compilerPath": "${workspaceFolder}/.cosmocc/3.9.2/bin/aarch64-linux-cosmo-gcc",
"cStandard": "c17",
"cppStandard": "c++17",
"intelliSenseMode": "gcc-arm64",
"compilerArgs": [
"-nostdinc",
"-iquote",
"${workspaceFolder}",
"-isystem",
"${workspaceFolder}/libc/isystem",
"-include",
"libc/integral/normalize.inc"
]
}
],
"version": 4
}
+2 -12
View File
@@ -1,15 +1,4 @@
{
"C_Cpp.default.compilerPath": ".cosmocc/3.9.2/bin/aarch64-linux-cosmo-c++",
"C_Cpp.default.compilerArgs": [
"-nostdinc",
"-nostdlib",
"-iquote.",
"-isystemlibc/isystem",
"-isystemthird_party/libcxx",
"-includelibc/integral/normalize.inc",
"-D_COSMO_SOURCE",
"-D__aarch64__"
],
"[c]": {
"editor.tabSize": 2,
"editor.insertSpaces": true
@@ -31,6 +20,7 @@
"editor.insertSpaces": true
},
"files.associations": {
"log.h": "c"
"log.h": "c",
"*.inc": "c"
}
}
+57 -40
View File
@@ -77,7 +77,8 @@ COMMA := ,
PWD := $(shell pwd)
# detect wsl2 running cosmopolitan binaries on the host by checking whether:
# - user ran build/bootstrap/make, in which case make's working directory is in wsl
# - user ran .cosmocc/current/bin/make, in which case make's working directory
# is in wsl
# - user ran make, in which case cocmd's working directory is in wsl
ifneq ($(findstring //wsl.localhost/,$(CURDIR) $(PWD)),)
$(warning wsl2 interop is enabled)
@@ -89,7 +90,7 @@ UNAME_S := $(shell uname -s)
# apple still distributes a 17 year old version of gnu make
ifeq ($(MAKE_VERSION), 3.81)
$(error please use build/bootstrap/make)
$(error please use https://cosmo.zip/pub/cosmos/bin/make)
endif
LC_ALL = C
@@ -109,11 +110,12 @@ ECHO = $(BOOTSTRAP)/echo.ape
CHMOD = $(BOOTSTRAP)/chmod.ape
TOUCH = $(BOOTSTRAP)/touch.ape
PKG = $(BOOTSTRAP)/package.ape
MKDEPS = $(BOOTSTRAP)/mkdeps
MKDEPS = build/bootstrap/mkdeps
ZIPOBJ = $(BOOTSTRAP)/zipobj
ZIPCOPY = $(BOOTSTRAP)/zipcopy
ELF2PE = build/bootstrap/elf2pe
PECHECK = $(BOOTSTRAP)/pecheck
FIXUPOBJ = $(BOOTSTRAP)/fixupobj
FIXUPOBJ = build/bootstrap/fixupobj
OBJBINCOPY = $(BOOTSTRAP)/objbincopy
MKDIR = $(BOOTSTRAP)/mkdir.ape -p
COMPILE = $(BOOTSTRAP)/compile.ape -V9 -M2048m -P8192 $(QUOTA)
@@ -135,7 +137,7 @@ ARCH = aarch64
HOSTS ?= pi pi5 studio freebsdarm
else
ARCH = x86_64
HOSTS ?= freebsd rhel7 xnu openbsd netbsd win10 luna
HOSTS ?= freebsd xnu win10 luna netbsd
endif
ZIPOBJ_FLAGS += -a$(ARCH)
@@ -154,9 +156,13 @@ DOWNLOAD := $(shell build/download-cosmocc.sh $(COSMOCC) 3.9.2 f4ff13af65fcd309f
IGNORE := $(shell $(MKDIR) $(TMPDIR))
ifeq ($(ARCH), x86_64)
TLSCC = build/bootstrap/tlscc
endif
AS = $(TOOLCHAIN)as
CC = $(TOOLCHAIN)gcc
CXX = $(TOOLCHAIN)g++
CC = $(TLSCC) $(TOOLCHAIN)gcc
CXX = $(TLSCC) $(TOOLCHAIN)g++
CXXFILT = $(TOOLCHAIN)c++filt
LD = $(TOOLCHAIN)ld.bfd
NM = $(TOOLCHAIN)nm
@@ -189,39 +195,42 @@ o/$(MODE): \
o/$(MODE)/: o/$(MODE)
o/$(MODE)/.: o/$(MODE)
# check if we're using o//third_party/make/make
# we added sandboxing to guarantee cosmo's makefile is hermetic
# it also shaves away 200ms of startup latency with native $(uniq)
ifneq ($(LANDLOCKMAKE_VERSION),)
ifeq ($(UNAME_S),Linux)
ifeq ($(wildcard /usr/bin/ape),)
$(warning please run ape/apeinstall.sh if you intend to use landlock make)
$(shell sleep .5)
endif
endif
ifneq ($(TOOLCHAIN),)
.STRICT = 1
endif
endif
.PLEDGE += stdio rpath wpath cpath fattr proc
.UNVEIL += \
libc/integral \
libc/stdbool.h \
rwc:/dev/shm \
# If you're using Cosmopolitan Make as your `make` command (you can
# build it by saying `make o//third_party/make/make`) then these
# variables will activate its pledge() and unveil() sandboxing
# functionality when running on Linux. When cross-compiling, it's
# important that your qemu binaries be statically compiled. See
# third_party/qemu/ for our prebuilt qemu-aarch64 binary. Yes
# binfmt_misc has to be configured to use it on foreign bins.
.SANDBOXED = 1
.PLEDGE := stdio rpath wpath cpath fattr proc
.UNVEIL := \
rwcx:o \
rwcx:/tmp \
rwcx:$(TMPDIR) \
rx:/usr/bin/ape \
rx:.cosmocc \
rx:build/bootstrap \
r:build/portcosmo.h \
libc/integral \
rwc:/dev/shm \
/proc/stat \
rw:/dev/null \
rw:/dev/full \
w:o/stack.log \
/etc/hosts \
/etc/ape.trust \
/etc/ape.revoke \
/etc/ssh/ssh_host_ed25519_key.pub \
~/.runit.psk \
~/.ssh/authorized_keys \
~/.ssh/id_ed25519.pub \
~/.ape.trust \
~/.ape.revoke \
/proc/self/status \
rx:/usr/bin/qemu-aarch64 \
rx:o/third_party/qemu/qemu-aarch64 \
/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
rx:/usr/bin/qemu-x86_64 \
rx:/usr/libexec/qemu-binfmt/aarch64-binfmt-P
endif
PKGS =
@@ -256,8 +265,10 @@ include third_party/gdtoa/BUILD.mk # ├──DYNAMIC RUNTIME
include third_party/nsync/mem/BUILD.mk # │ You can now use stdio
include libc/proc/BUILD.mk # │ You can now use threads
include libc/dlopen/BUILD.mk # │ You can now use processes
include libc/thread/BUILD.mk # │ You can finally call malloc()
include third_party/libunwind/BUILD.mk # | You can finally call malloc()
include libc/thread/BUILD.mk # │
include third_party/zlib/BUILD.mk # │
include third_party/haclstar/BUILD.mk # │
include libc/stdio/BUILD.mk # │
include tool/hello/BUILD.mk # │
include third_party/tz/BUILD.mk # │
@@ -283,15 +294,15 @@ include dsp/scale/BUILD.mk # │
include dsp/mpeg/BUILD.mk # │
include dsp/tty/BUILD.mk # │
include dsp/audio/BUILD.mk # │
include dsp/prog/BUILD.mk # │
include dsp/BUILD.mk # │
include third_party/stb/BUILD.mk # │
include third_party/mbedtls/BUILD.mk # │
include third_party/ncurses/BUILD.mk # │
include third_party/readline/BUILD.mk # │
include third_party/libunwind/BUILD.mk # |
include third_party/libcxxabi/BUILD.mk # |
include third_party/miniaudio/BUILD.mk # |
include third_party/double-conversion/BUILD.mk # │
include dsp/prog/BUILD.mk # │
include ctl/BUILD.mk # │
include third_party/libcxx/BUILD.mk # │
include third_party/openmp/BUILD.mk # │
@@ -304,7 +315,9 @@ include third_party/nsync/testing/BUILD.mk
include libc/testlib/BUILD.mk
include tool/viz/lib/BUILD.mk
include tool/args/BUILD.mk
include tool/chat/BUILD.mk
include test/math/BUILD.mk
include test/c11/BUILD.mk
include test/posix/BUILD.mk
include test/ctl/BUILD.mk
include test/libcxx/BUILD.mk
@@ -313,6 +326,8 @@ include third_party/linenoise/BUILD.mk
include third_party/maxmind/BUILD.mk
include net/finger/BUILD.mk
include third_party/double-conversion/test/BUILD.mk
include third_party/dash/BUILD.mk
include third_party/netcat/BUILD.mk
include third_party/lua/BUILD.mk
include third_party/tree/BUILD.mk
include third_party/zstd/BUILD.mk
@@ -344,7 +359,6 @@ include tool/decode/lib/BUILD.mk
include tool/decode/BUILD.mk
include tool/lambda/lib/BUILD.mk
include tool/lambda/BUILD.mk
include tool/plinko/lib/BUILD.mk
include tool/plinko/BUILD.mk
include test/tool/plinko/BUILD.mk
include tool/net/BUILD.mk
@@ -413,24 +427,24 @@ o/$(MODE)/hdrs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS) $(
o/$(MODE)/incs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(INCS) $(INCS),$(dir $(x)))) $(INCS) $(INCS)
$(file >$@,$(INCS))
o/$(MODE)/depend: o/$(MODE)/.x o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt o/$(MODE)/incs.txt $(SRCS) $(HDRS) $(INCS)
$(COMPILE) -AMKDEPS -L320 $(MKDEPS) -o $@ -s -r o/$(MODE)/ @o/$(MODE)/srcs.txt @o/$(MODE)/hdrs.txt @o/$(MODE)/incs.txt
$(COMPILE) -AMKDEPS -L320 $(MKDEPS) -o $@ -s -r o/$(MODE)/ -S c++:third_party/libcxx/ -S libc/isystem/ @o/$(MODE)/srcs.txt @o/$(MODE)/hdrs.txt @o/$(MODE)/incs.txt
o/$(MODE)/srcs-old.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(SRCS),$(dir $(x))))
$(file >$@) $(foreach x,$(SRCS),$(file >>$@,$(x)))
o/$(MODE)/hdrs-old.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS) $(INCS),$(dir $(x))))
$(file >$@) $(foreach x,$(HDRS) $(INCS),$(file >>$@,$(x)))
TAGS: private .UNSANDBOXED = 1
TAGS: private .SANDBOXED = 0
TAGS: o/$(MODE)/srcs-old.txt $(SRCS) #o/$(MODE)/third_party/ctags/ctags
@$(RM) $@
@o/$(MODE)/third_party/ctags/ctags $(TAGSFLAGS) -L $< -o $@
HTAGS: private .UNSANDBOXED = 1
HTAGS: private .SANDBOXED = 0
HTAGS: o/$(MODE)/hdrs-old.txt $(filter-out third_party/libcxx/%,$(HDRS)) #o/$(MODE)/third_party/ctags/ctags
@$(RM) $@
@build/htags o/$(MODE)/third_party/ctags/ctags -L $< -o $@
loc: private .UNSANDBOXED = 1
loc: private .SANDBOXED = 0
loc: o/$(MODE)/tool/build/summy
find -name \*.h -or -name \*.hpp -or -name \*.c -or -name \*.cc -or -name \*.cpp -or -name \*.S -or -name \*.mk | \
$(XARGS) wc -l | grep total | awk '{print $$1}' | $<
@@ -461,6 +475,7 @@ COSMOPOLITAN = \
LIBC_NT_SHELL32 \
LIBC_NT_SYNCHRONIZATION \
LIBC_NT_USER32 \
LIBC_NT_WINMM \
LIBC_NT_WS2_32 \
LIBC_PROC \
LIBC_RUNTIME \
@@ -554,7 +569,7 @@ COSMOPOLITAN_H_ROOT_HDRS = \
libc/integral/normalize.inc \
$(foreach x,$(COSMOPOLITAN_H_PKGS),$($(x)_HDRS))
o/cosmopolitan.html: private .UNSANDBOXED = 1
o/cosmopolitan.html: private .SANDBOXED = 0
o/cosmopolitan.html: \
o/$(MODE)/third_party/chibicc/chibicc.dbg \
$(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS))) \
@@ -577,6 +592,7 @@ ifeq ($(ARCH), x86_64)
TOOLCHAIN_ARTIFACTS = \
o/$(MODE)/ape/ape.lds \
o/$(MODE)/libc/crt/crt.o \
o/$(MODE)/libc/crt/crtfastmath.o \
o/$(MODE)/ape/ape.elf \
o/$(MODE)/ape/ape.o \
o/$(MODE)/ape/ape-copy-self.o \
@@ -595,6 +611,7 @@ TOOLCHAIN_ARTIFACTS = \
o/$(MODE)/ape/ape.elf \
o/$(MODE)/ape/aarch64.lds \
o/$(MODE)/libc/crt/crt.o \
o/$(MODE)/libc/crt/crtfastmath.o \
o/$(MODE)/cosmopolitan.a \
o/$(MODE)/third_party/libcxx/libcxx.a \
o/$(MODE)/tool/build/march-native \
@@ -610,7 +627,7 @@ clean_toolchain:
$(RM) $(TOOLCHAIN_ARTIFACTS)
aarch64: private .INTERNET = true
aarch64: private .UNSANDBOXED = true
aarch64: private .SANDBOXED = 0
aarch64:
$(MAKE) m=aarch64
+16 -9
View File
@@ -3,7 +3,7 @@
[![build](https://github.com/jart/cosmopolitan/actions/workflows/build.yml/badge.svg)](https://github.com/jart/cosmopolitan/actions/workflows/build.yml)
# Cosmopolitan
[Cosmopolitan Libc](https://justine.lol/cosmopolitan/index.html) makes C
[Cosmopolitan Libc](https://justine.lol/cosmopolitan/index.html) makes C/C++
a build-once run-anywhere language, like Java, except it doesn't need an
interpreter or virtual machine. Instead, it reconfigures stock GCC and
Clang to output a POSIX-approved polyglot format that runs natively on
@@ -87,15 +87,22 @@ ape/apeinstall.sh
```
You can now build the mono repo with any modern version of GNU Make. To
make life easier, we've included one in the cosmocc toolchain, which is
guaranteed to be compatible and furthermore includes our extensions for
doing build system sandboxing.
bootstrap your build, you can install Cosmopolitan Make from this site:
https://cosmo.zip/pub/cosmos/bin/make
E.g.:
```sh
build/bootstrap/make -j8
curl -LO https://cosmo.zip/pub/cosmos/bin/make
./make -j8
o//examples/hello
```
After you've built the repo once, you can also use the make from your
cosmocc at `.cosmocc/current/bin/make`. You might even prefer to alias
make to `$COSMO/.cosmocc/current/bin/make`.
Since the Cosmopolitan repository is very large, you might only want to
build one particular thing. Here's an example of a target that can be
compiled relatively quickly, which is a simple POSIX test that only
@@ -103,7 +110,7 @@ depends on core LIBC packages.
```sh
rm -rf o//libc o//test
build/bootstrap/make o//test/posix/signal_test
.cosmocc/current/bin/make o//test/posix/signal_test
o//test/posix/signal_test
```
@@ -112,21 +119,21 @@ list out each individual one. For example if you wanted to build and run
all the unit tests in the `TEST_POSIX` package, you could say:
```sh
build/bootstrap/make o//test/posix
.cosmocc/current/bin/make o//test/posix
```
Cosmopolitan provides a variety of build modes. For example, if you want
really tiny binaries (as small as 12kb in size) then you'd say:
```sh
build/bootstrap/make m=tiny
.cosmocc/current/bin/make m=tiny
```
You can furthermore cut out the bloat of other operating systems, and
have Cosmopolitan become much more similar to Musl Libc.
```sh
build/bootstrap/make m=tinylinux
.cosmocc/current/bin/make m=tinylinux
```
For further details, see [//build/config.mk](build/config.mk).
+2
View File
@@ -49,6 +49,8 @@ o/$(MODE)/ape/aarch64.lds: \
libc/thread/tls.h \
libc/calls/struct/timespec.h \
libc/macros.h \
libc/sysv/consts/prot.h \
libc/dce.h \
libc/str/str.h
APE_LOADER_LDFLAGS = \
+16 -2
View File
@@ -4,6 +4,8 @@
#include "libc/sysv/consts/prot.h"
#include "libc/thread/tls.h"
#define CACHELINE 64
ENTRY(_start)
OUTPUT_ARCH(aarch64)
OUTPUT_FORMAT("elf64-littleaarch64",
@@ -73,13 +75,16 @@ SECTIONS {
KEEP(*(SORT_NONE(.fini)))
} =0x1f2003d5
. += CONSTANT(MAXPAGESIZE);
. = ALIGN(CONSTANT(MAXPAGESIZE));
__privileged_start = .;
.privileged : {
__privileged_start = ABSOLUTE(.) & -CONSTANT(MAXPAGESIZE);
*(.privileged*)
} =0x1f2003d6
. = ALIGN(CONSTANT(MAXPAGESIZE));
_rodata = .;
.rodata : {
KEEP(*(.rodata.pytab.0));
KEEP(*(.rodata.pytab.1));
@@ -200,6 +205,9 @@ SECTIONS {
.data : {
__data_start = .;
KEEP(*(SORT_BY_NAME(.piro.data.sort.*)))
. = ALIGN(CACHELINE);
*(.data.rarechange)
. = ALIGN(CACHELINE);
*(.data .data.* .gnu.linkonce.d.*)
KEEP(*(SORT_BY_NAME(.sort.data.*)))
SORT(CONSTRUCTORS)
@@ -214,6 +222,9 @@ SECTIONS {
.bss : {
*(.dynbss)
. = ALIGN(CACHELINE);
*(.bss.rarechange)
. = ALIGN(CACHELINE);
*(.bss .bss.* .gnu.linkonce.b.*)
KEEP(*(SORT_BY_NAME(.piro.bss.sort.*)))
*(COMMON)
@@ -259,6 +270,9 @@ SECTIONS {
.debug_ranges 0 : { *(.debug_ranges) }
.debug_macro 0 : { *(.debug_macro) }
.debug_addr 0 : { *(.debug_addr) }
.debug_names 0 : { *(.debug_names) }
.debug_loclists 0 : { *(.debug_loclists) }
.debug_str_offsets 0 : { *(.debug_str_offsets) }
.ARM.attributes 0 : { KEEP(*(.ARM.attributes)) KEEP(*(.gnu.attributes)) }
.note.gnu.arm.ident 0 : { KEEP(*(.note.gnu.arm.ident)) }
+43 -2
View File
@@ -789,6 +789,33 @@ ape.ident:
.type ape.ident,@object
.previous
#if SupportsFreebsd()
//
// This PT_NOTE enables the following kernel behaviors:
//
// - P_OSREL_SIGSEGV ensures SIGEGV signals aren't misdelivered as
// as SIGBUS with invalid siginfo fields.
//
// - P_OSREL_SHUTDOWN_ENOTCONN is probably a good thing
//
// - P_OSREL_SIGWAIT prevents sigwait() from raising EINTR
//
// - P_OSREL_MAP_FSTRICT (basically MAP_SHARED_VALIDATE?)
//
.section .note.freebsd.ident,"a",@progbits
.balign 4
freebsd.ident:
.long 2f-1f
.long 4f-3f
.long 1 // NT_FREEBSD_ABI_TAG
1: .asciz "FreeBSD"
2: .balign 4
3: .long 1300000 // v13.0+ c. 2020
4: .size freebsd.ident,.-freebsd.ident
.type freebsd.ident,@object
.previous
#endif /* SupportsFreebsd() */
#if SupportsOpenbsd()
.section .note.openbsd.ident,"a",@progbits
.balign 4
@@ -1086,6 +1113,19 @@ ape_pe: .ascin "PE",4
.long PERDAT // Flags
.previous
.section .pe.sections,"a",@progbits
.ascin ".idata",8 // Section Name
.long ape_idt_memsz // Virtual Size or Physical Address
.long ape_idt_rva // Relative Virtual Address
.long ape_idt_filesz // Physical Size
.long ape_idt_offset // Physical Offset
.long 0 // Relocation Table Offset
.long 0 // Line Number Table Offset
.short 0 // Relocation Count
.short 0 // Line Number Count
.long PEIMPS // Flags
.previous
.section .pe.sections,"a",@progbits
.ascin ".data",8 // Section Name
.long ape_ram_memsz // Virtual Size or Physical Address
@@ -1711,6 +1751,7 @@ kernel: movabs $ape_stack_vaddr,%rsp
mov $0x79000,%esi
mov $0x7f000,%edx
call __reclaim_boot_pages
movl $1,__pib(%rip)
push $_HOSTMETAL // sets __hostos in crt.S
pop %rcx
pushq .Lenv0(%rip) // envp[0][0]
@@ -1828,7 +1869,7 @@ __bss_end:
.section .notice,"aR",@progbits
.asciz "\n\n\
Cosmopolitan\n\
Copyright 2024 Justine Alexandra Roberts Tunney\n\
Copyright 2025 Justine Alexandra Roberts Tunney\n\
\n\
Permission to use, copy, modify, and/or distribute this software for\n\
any purpose with or without fee is hereby granted, provided that the\n\
@@ -1844,4 +1885,4 @@ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\n\
PERFORMANCE OF THIS SOFTWARE."
.end


+55 -26
View File
@@ -186,6 +186,8 @@
/* uncomment if .com.dbg won't execute on your kernel (will break .com file) */
/* #define APE_FIX_COM_DBG */
#define CACHELINE 64
#ifdef __x86__
#define CODE_GRANULE 1
#else
@@ -199,7 +201,7 @@
#endif
#ifndef IMAGE_BASE_VIRTUAL
#define IMAGE_BASE_VIRTUAL 0x400000
#define IMAGE_BASE_VIRTUAL 0x4200000
#endif
#if IMAGE_BASE_VIRTUAL > 0xffffffff
@@ -237,11 +239,10 @@ SECTIONS {
KEEP(*(.elf.phdrs))
ape_phdrs_end = .;
/* OpenBSD */
/* ELF PT_NOTE data structures */
. = ALIGN(. != 0 ? __SIZEOF_POINTER__ : 0);
ape_note = .;
KEEP(*(.note.openbsd.ident))
KEEP(*(.note.netbsd.ident))
KEEP(*(.note.*))
ape_note_end = .;
/* Portable Executable */
@@ -321,6 +322,7 @@ SECTIONS {
/*BEGIN: Read Only Data */
.rodata ALIGN(CONSTANT(COMMONPAGESIZE)) : {
_rodata = .;
KEEP(*(.rodata.pytab.0));
KEEP(*(.rodata.pytab.1));
KEEP(*(.rodata.pytab.2));
@@ -342,12 +344,6 @@ SECTIONS {
/*BEGIN: read-only data that's only needed for initialization */
#if SupportsWindows()
/* Windows DLL Import Directory */
KEEP(*(.idata.ro));
KEEP(*(SORT_BY_NAME(.idata.ro.*)))
#endif
/* Encoded Data Structures w/ Linear Initialization Order */
KEEP(*(.initroprologue))
KEEP(*(SORT_BY_NAME(.initro.*)))
@@ -386,13 +382,34 @@ SECTIONS {
_tbss_end = .;
} :Tls
.idata : {
#if SupportsWindows()
KEEP(*(.dllstr));
KEEP(*(.idata.ro));
KEEP(*(SORT_BY_NAME(.idata.ro.*)));
KEEP(*(SORT_BY_NAME(.piro.data.sort.iat.*)));
KEEP(*(.data.nt.*));
#endif
. = ALIGN(. != 0 ? CONSTANT(COMMONPAGESIZE) : 0);
} :Ram
.eh_frame : {
__eh_frame_start = .;
KEEP(*(.eh_frame))
*(.eh_frame.*)
__eh_frame_end = .;
} :Ram
.data . : {
/*BEGIN: Read/Write Data */
#if SupportsWindows()
KEEP(*(SORT_BY_NAME(.piro.data.sort.iat.*)))
#endif
/*BEGIN: NT FORK COPYING */
KEEP(*(.dataprologue))
/* Precious Runtime Constants */
. = ALIGN(CACHELINE);
*(.data.rarechange)
. = ALIGN(CACHELINE);
*(.data .data.*)
*(.gnu_extab)
*(.gcc_except_table .gcc_except_table.*)
@@ -426,11 +443,6 @@ SECTIONS {
KEEP(*(.dtors))
__fini_array_end = .;
__eh_frame_start = .;
KEEP(*(.eh_frame))
*(.eh_frame.*)
__eh_frame_end = .;
/*BEGIN: Post-Initialization Read-Only */
. = ALIGN(. != 0 ? __SIZEOF_POINTER__ : 0);
KEEP(*(SORT_BY_NAME(.piro.relo.sort.*)))
@@ -439,7 +451,6 @@ SECTIONS {
KEEP(*(.piro.pad.data))
*(.igot.plt)
KEEP(*(.dataepilogue))
. = ALIGN(. != 0 ? CONSTANT(COMMONPAGESIZE) : 0);
/*END: NT FORK COPYING */
_edata = .;
@@ -463,6 +474,11 @@ SECTIONS {
. += . > 0 ? CODE_GRANULE : 0;
/*END: Post-Initialization Read-Only */
/* Precious Runtime Constants */
. = ALIGN(CACHELINE);
*(.bss.rarechange)
. = ALIGN(CACHELINE);
/* Statically Allocated Empty Space */
*(SORT_BY_ALIGNMENT(.bss))
*(SORT_BY_ALIGNMENT(.bss.*))
@@ -519,6 +535,9 @@ SECTIONS {
.debug_rnglists 0 : { *(.debug_rnglists) }
.debug_macro 0 : { *(.debug_macro) }
.debug_addr 0 : { *(.debug_addr) }
.debug_names 0 : { *(.debug_names) }
.debug_loclists 0 : { *(.debug_loclists) }
.debug_str_offsets 0 : { *(.debug_str_offsets) }
.gnu.attributes 0 : { KEEP(*(.gnu.attributes)) }
.GCC.command.line 0 : { *(.GCC.command.line) }
@@ -545,7 +564,7 @@ SECTIONS {
}
}
ape_pe_filealignment = 512;
ape_pe_filealignment = 4096;
ape_pe_sectionalignment = 4096;
ape_pe_sizeofheaders = SIZEOF(.head);
ape_pe_sizeofimage = ROUNDUP(_end - __executable_start, ape_pe_sectionalignment);
@@ -582,11 +601,19 @@ ape_rom_memsz = ape_rom_filesz;
ape_rom_align = CONSTANT(COMMONPAGESIZE);
ape_rom_rva = RVA(ape_rom_vaddr);
ape_ram_vaddr = ADDR(.data);
ape_idt_vaddr = ADDR(.idata);
ape_idt_offset = ape_idt_vaddr - __executable_start;
ape_idt_paddr = LOADADDR(.idata);
ape_idt_filesz = ADDR(.eh_frame) - ADDR(.idata);
ape_idt_memsz = ape_idt_filesz;
ape_idt_align = CONSTANT(COMMONPAGESIZE);
ape_idt_rva = RVA(ape_idt_vaddr);
ape_ram_vaddr = ADDR(.eh_frame);
ape_ram_offset = ape_ram_vaddr - __executable_start;
ape_ram_paddr = LOADADDR(.data);
ape_ram_filesz = ADDR(.bss) - ADDR(.data);
ape_ram_memsz = _end - ADDR(.data);
ape_ram_paddr = LOADADDR(.eh_frame);
ape_ram_filesz = ADDR(.bss) - ADDR(.eh_frame);
ape_ram_memsz = _end - ADDR(.eh_frame);
ape_ram_align = CONSTANT(COMMONPAGESIZE);
ape_ram_rva = RVA(ape_ram_vaddr);
@@ -596,7 +623,7 @@ ape_stack_offset = 0;
ape_stack_vaddr = DEFINED(ape_stack_vaddr) ? ape_stack_vaddr : 0x700000000000;
ape_stack_paddr = ape_ram_paddr + ape_ram_filesz;
ape_stack_filesz = 0;
ape_stack_memsz = DEFINED(ape_stack_memsz) ? ape_stack_memsz : 8 * 1024 * 1024;
ape_stack_memsz = DEFINED(ape_stack_memsz) ? ape_stack_memsz : 8 * 1024 * 1024; /* for gnu make */
ape_note_offset = ape_cod_offset + (ape_note - ape_cod_vaddr);
ape_note_filesz = ape_note_end - ape_note;
@@ -710,8 +737,10 @@ CHURN(ape_pe_sections);
CHURN(ape_pe_sections_end);
CHURN(ape_pe_shnum);
CHURN(ape_phdrs_end);
CHURN(WinMain);
#endif /* SupportsWindows() */
#if SupportsWindows()
CHURN(WinMain);
#endif
#endif /* SupportsXnu() */
#if SupportsWindows() || SupportsMetal()
+2 -2
View File
@@ -10,8 +10,8 @@ if [ ! -f ape/loader.c ]; then
cd "$COSMO" || exit
fi
if [ -x build/bootstrap/make ]; then
MAKE=build/bootstrap/make
if [ -x .cosmocc/current/bin/make ]; then
MAKE=.cosmocc/current/bin/make
else
MAKE=make
fi
+1 -1
View File
@@ -107,7 +107,7 @@
*/.section ".piro.data.sort.iat.2.\name\().3","awG",@progbits,"\name",comdat
.quad 0
.previous
.section .rodata.str1.1,"aSM",@progbits,1
.section .dllstr,"aSM",@progbits,1
".Lidata.str.\name":
.asciz "\name\().dll"
.previous
+1 -1
View File
@@ -14,7 +14,7 @@
#define IMAGE_BASE_REAL 0x2000
#ifndef IMAGE_BASE_VIRTUAL
#define IMAGE_BASE_VIRTUAL 0x400000
#define IMAGE_BASE_VIRTUAL 0x4200000
#endif
#ifndef IMAGE_BASE_PHYSICAL
+4
View File
@@ -6,6 +6,7 @@ extern const char __notices[] __attribute__((__weak__));
extern unsigned char __executable_start[] __attribute__((__weak__));
extern unsigned char __privileged_start[] __attribute__((__weak__));
extern unsigned char _ehead[] __attribute__((__weak__));
extern unsigned char _rodata[] __attribute__((__weak__));
extern unsigned char _etext[] __attribute__((__weak__));
extern unsigned char _edata[] __attribute__((__weak__));
extern unsigned char _ezip[] __attribute__((__weak__));
@@ -28,5 +29,8 @@ extern unsigned long __got_start[] __attribute__((__weak__));
extern unsigned long __got_end[] __attribute__((__weak__));
extern unsigned char ape_phdrs[] __attribute__((__weak__));
#define __rarechange _Section(".bss.rarechange")
#define __data_rarechange _Section(".data.rarechange")
COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_APE_SECTIONS_INTERNAL_H_ */
+48 -72
View File
@@ -361,13 +361,13 @@ Here's the TLS memory layout on x86_64:
```
__get_tls()
│
%fs OpenBSD/NetBSD
%fs Linux/FreeBSD/NetBSD/OpenBSD
_Thread_local │
┌───┬──────────┬──────────┼───┐
│pad│ .tdata │ .tbss │tib│
└───┴──────────┴──────────┼───┘
│
Linux/FreeBSD/Windows/Mac %gs
Windows/Mac %gs
```
Quite possibly the greatest challenge in Actually Portable Executable
@@ -401,80 +401,56 @@ arises in the fact that our Linux-flavored GCC and Clang toolchains
(which are used to produce cross-OS binaries) are also only capable of
producing TLS instructions that use the %fs convention.
To solve these challenges, the `cosmocc` compiler will rewrite binary
objects after they've been compiled by GCC, so that the `%gs` register
is used, rather than `%fs`. Morphing x86-64 binaries after they've been
compiled is normally difficult, due to the complexity of the machine
instruction language. However GCC provides `-mno-tls-direct-seg-refs`
which greatly reduces the complexity of this task. This flag forgoes
some optimizations to make the generated code simpler. Rather than doing
clever arithmetic with `%fs` prefixes, the compiler will always generate
the thread information block address load as a separate instruction.
To solve these challenges, the `cosmocc` compiler rewrites GCC generated
assembly so that the `%fs` referencing instructions created by GCC when
using the `-mno-tls-direct-seg-refs` flag are replaced by calls to the
following functions:
```c
// Change AMD code to use %gs:0x30 instead of %fs:0
// We assume -mno-tls-direct-seg-refs has been used
static void ChangeTlsFsToGs(unsigned char *p, size_t n) {
unsigned char *e = p + n - 9;
while (p <= e) {
// we're checking for the following expression:
// 0144 == p[0] && // %fs
// 0110 == (p[1] & 0373) && // rex.w (and ignore rex.r)
// (0213 == p[2] || // mov reg/mem → reg (word-sized)
// 0003 == p[2]) && // add reg/mem → reg (word-sized)
// 0004 == (p[3] & 0307) && // mod/rm (4,reg,0) means sib → reg
// 0045 == p[4] && // sib (5,4,0) → (rbp,rsp,0) → disp32
// 0000 == p[5] && // displacement (von Neumann endian)
// 0000 == p[6] && // displacement
// 0000 == p[7] && // displacement
// 0000 == p[8] // displacement
uint64_t w = READ64LE(p) & READ64LE("\377\373\377\307\377\377\377\377");
if ((w == READ64LE("\144\110\213\004\045\000\000\000") ||
w == READ64LE("\144\110\003\004\045\000\000\000")) &&
!p[8]) {
p[0] = 0145; // change %fs to %gs
p[5] = 0x30; // change 0 to 0x30
p += 9;
} else {
++p;
}
}
}
```
- `__get_tls_rax`
- `__get_tls_rbx`
- `__get_tls_rcx`
- `__get_tls_rdx`
- `__get_tls_rdi`
- `__get_tls_rsi`
- `__get_tls_rbp`
- `__get_tls_r8`
- `__get_tls_r9`
- `__get_tls_r10`
- `__get_tls_r11`
- `__get_tls_r12`
- `__get_tls_r13`
- `__get_tls_r14`
- `__get_tls_r15`
- `__add_tls_rax`
- `__add_tls_rbx`
- `__add_tls_rcx`
- `__add_tls_rdx`
- `__add_tls_rdi`
- `__add_tls_rsi`
- `__add_tls_rbp`
- `__add_tls_r8`
- `__add_tls_r9`
- `__add_tls_r10`
- `__add_tls_r11`
- `__add_tls_r12`
- `__add_tls_r13`
- `__add_tls_r14`
- `__add_tls_r15`
By favoring `%gs` we've now ensured friction-free compatibility for the
APE runtime on MacOS, Linux, and FreeBSD which are all able to conform
easily to this convention. However additional work needs to be done at
runtime when an APE program is started on Windows, OpenBSD, and NetBSD.
On these platforms, all executable pages must be faulted and morphed to
fixup the TLS instructions.
The `cosmocc` script internally uses a tool named `tlscc` which wraps a
gcc or clang compilation so it generates intermediate assembly code that
it can modify to call the above functions. In the process, it also adds
the `-mno-tls-direct-seg-refs` and `-mno-red-zone` flags to the compile
command to ensure the compiler only generates TLS assembly instructions
that are understood by the tool.
On OpenBSD and NetBSD, this is as simple as undoing the example
operation above. Earlier at compile-time we turned `%fs` into `%gs`.
Now, at runtime, `%gs` must be turned back into `%fs`. Since the
executable is morphing itself, this is easier said than done.
The above functions do not clobber any registers. The function name
specifies the register to which the result is stored or added. The only
above function that can be called by C code is `__get_tls_rax`.
OpenBSD for example enforces a `W^X` invariant. Code that's executing
can't modify itself at the same time. The way Cosmopolitan solves this
is by defining a special part of the binary called `.text.privileged`.
This section is aligned to page boundaries. A GNU ld linker script is
used to ensure that code which morphs code is placed into this section,
through the use of a header-defined cosmo-specific keyword `privileged`.
Additionally, the `fixupobj` program is used by the Cosmo build system
to ensure that compiled objects don't contain privileged functions that
call non-privileged functions. Needless to say, `mprotect()` needs to be
a privileged function, so that it can be used to disable the execute bit
on all other parts of the executable except for the privileged section,
thereby making it writable. Once this has been done, code can change.
On Windows the displacement bytes of the TLS instruction are changed to
use the `%gs:0x1480+i*8` ABI where `i` is a number assigned by the WIN32
`TlsAlloc()` API. This avoids the need to call `TlsGetValue()` which is
implemented this exact same way under the hood. Even though 0x1480 isn't
explicitly documented by MSDN, this ABI is believed to be stable because
MSVC generates binaries that use this offset directly. The only caveat
is that `TlsAlloc()` must be called as early in the runtime init as
possible, to ensure an index less than 64 is returned.
When Windows and MacOS aren't in the support vector, then the above
assembly rewriting pass can be avoided entirely, and the binary can
simply use the TLS opcodes that GCC and Clang generate for Linux.
### Thread Information Block (TIB)
+10
View File
@@ -61,6 +61,16 @@ netbsd.ident:
4: .size netbsd.ident,.-netbsd.ident
.type netbsd.ident,@object
.balign 4
freebsd.ident:
.long 2f-1f
.long 4f-3f
.long 1 // NT_FREEBSD_ABI_TAG
1: .asciz "FreeBSD"
2: .balign 4
3: .long 1300000 // v13.0+ c. 2020
4: .size freebsd.ident,.-freebsd.ident
.type freebsd.ident,@object
.balign 4
ape.ident:
.long 2f-1f
.long 4f-3f
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+1
View File
@@ -5,6 +5,7 @@
-Wa,-msse2avx
-Werror=maybe-uninitialized
-Wno-literal-suffix
-Wno-prio-ctor-dtor
-Wno-unused-but-set-variable
-Wunsafe-loop-optimizations
-fbranch-target-load-optimize
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+56 -25
View File
@@ -96,24 +96,22 @@ endif
# - Turns off support for other operating systems
#
ifeq ($(MODE), optlinux)
TLSCC =
CONFIG_OFLAGS ?= -g -ggdb
CONFIG_CPPFLAGS += -DNDEBUG -DSYSDEBUG -DSUPPORT_VECTOR=1
CONFIG_CCFLAGS += -O3 -fmerge-all-constants
CONFIG_COPTS += -mred-zone
CONFIG_TARGET_ARCH ?= -march=native
CONFIG_TARGET_ARCH ?= -mavx
endif
ifeq ($(MODE), x86_64-optlinux)
CONFIG_OFLAGS ?= -g -ggdb
TLSCC =
CONFIG_CPPFLAGS += -DNDEBUG -DSYSDEBUG -DSUPPORT_VECTOR=1
CONFIG_CCFLAGS += -O3 -fmerge-all-constants
CONFIG_COPTS += -mred-zone
CONFIG_TARGET_ARCH ?= -march=native
CONFIG_TARGET_ARCH ?= -mavx
endif
ifeq ($(MODE), aarch64-optlinux)
CONFIG_OFLAGS ?= -g -ggdb
CONFIG_CPPFLAGS += -DNDEBUG -DSYSDEBUG -DSUPPORT_VECTOR=1
CONFIG_CCFLAGS += -O3 -fmerge-all-constants
CONFIG_COPTS += -mred-zone
endif
# Release Mode
@@ -153,7 +151,7 @@ OVERRIDE_CFLAGS += -O0
OVERRIDE_CXXFLAGS += -O0
CONFIG_CPPFLAGS += -DMODE_DBG -D__SANITIZE_UNDEFINED__ -Wno-unused-variable -Wno-unused-but-set-variable
CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG
CONFIG_COPTS += -fsanitize=undefined
CONFIG_COPTS += -fsanitize=undefined -fno-data-sections
OVERRIDE_CCFLAGS += -fno-pie
QUOTA ?= -C64 -L300
endif
@@ -164,7 +162,7 @@ OVERRIDE_CFLAGS += -O0
OVERRIDE_CXXFLAGS += -O0
CONFIG_CPPFLAGS += -DMODE_DBG -D__SANITIZE_UNDEFINED__ -Wno-unused-variable -Wno-unused-but-set-variable
CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG
CONFIG_COPTS += -fsanitize=undefined
CONFIG_COPTS += -fsanitize=undefined -fno-data-sections
OVERRIDE_CCFLAGS += -fno-pie
QUOTA ?= -C64 -L300
endif
@@ -175,7 +173,7 @@ OVERRIDE_CFLAGS += -O0 -fdce
OVERRIDE_CXXFLAGS += -O0 -fdce
CONFIG_CPPFLAGS += -DMODE_DBG -D__SANITIZE_UNDEFINED__ -Wno-unused-variable -Wno-unused-but-set-variable
CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG
CONFIG_COPTS += -fsanitize=undefined
CONFIG_COPTS += -fsanitize=undefined -fno-data-sections
QUOTA ?= -C64 -L300
endif
@@ -191,7 +189,16 @@ endif
#
ifeq ($(MODE), sysv)
ENABLE_FTRACE = 1
CONFIG_OFLAGS ?= -g -ggdb
CONFIG_CCFLAGS += $(BACKTRACES) -O2
CONFIG_CPPFLAGS += -DSYSDEBUG -DSUPPORT_VECTOR=121
endif
ifeq ($(MODE), x86_64-sysv)
ENABLE_FTRACE = 1
CONFIG_CCFLAGS += $(BACKTRACES) -O2
CONFIG_CPPFLAGS += -DSYSDEBUG -DSUPPORT_VECTOR=121
endif
ifeq ($(MODE), aarch64-sysv)
ENABLE_FTRACE = 1
CONFIG_CCFLAGS += $(BACKTRACES) -O2
CONFIG_CPPFLAGS += -DSYSDEBUG -DSUPPORT_VECTOR=121
endif
@@ -211,8 +218,7 @@ endif
ifeq ($(MODE), tiny)
CONFIG_CPPFLAGS += \
-DTINY \
-DNDEBUG \
-DTRUSTWORTHY
-DNDEBUG
CONFIG_CCFLAGS += \
-Os \
-fno-align-functions \
@@ -230,8 +236,7 @@ endif
ifeq ($(MODE), x86_64-tiny)
CONFIG_CPPFLAGS += \
-DTINY \
-DNDEBUG \
-DTRUSTWORTHY
-DNDEBUG
CONFIG_CCFLAGS += \
-Os \
-fno-align-functions \
@@ -250,8 +255,7 @@ ifeq ($(MODE), aarch64-tiny)
# TODO(jart): -mcmodel=tiny
CONFIG_CPPFLAGS += \
-DTINY \
-DNDEBUG \
-DTRUSTWORTHY
-DNDEBUG
CONFIG_CCFLAGS += \
-Os \
-fno-align-functions \
@@ -281,10 +285,37 @@ endif
# - YOLO
#
ifeq ($(MODE), tinylinux)
TLSCC =
CONFIG_CPPFLAGS += \
-DTINY \
-DNDEBUG \
-DSUPPORT_VECTOR=1 \
-DDWARFLESS
CONFIG_CCFLAGS += \
-Os \
-fno-align-functions \
-fno-align-jumps \
-fno-align-labels \
-fno-align-loops
endif
ifeq ($(MODE), x86_64-tinylinux)
TLSCC =
CONFIG_CPPFLAGS += \
-DTINY \
-DNDEBUG \
-DSUPPORT_VECTOR=1 \
-DDWARFLESS
CONFIG_CCFLAGS += \
-Os \
-fno-align-functions \
-fno-align-jumps \
-fno-align-labels \
-fno-align-loops
endif
ifeq ($(MODE), aarch64-tinylinux)
CONFIG_CPPFLAGS += \
-DTINY \
-DNDEBUG \
-DTRUSTWORTHY \
-DSUPPORT_VECTOR=1 \
-DDWARFLESS
CONFIG_CCFLAGS += \
@@ -310,10 +341,10 @@ endif
# - YOLO
#
ifeq ($(MODE), tinylinuxbsd)
TLSCC =
CONFIG_CPPFLAGS += \
-DTINY \
-DNDEBUG \
-DTRUSTWORTHY \
-DSUPPORT_VECTOR=113 \
-DDWARFLESS
CONFIG_CCFLAGS += \
@@ -341,7 +372,6 @@ ifeq ($(MODE), tinysysv)
CONFIG_CPPFLAGS += \
-DTINY \
-DNDEBUG \
-DTRUSTWORTHY \
-DSUPPORT_VECTOR=121 \
-DDWARFLESS
CONFIG_CCFLAGS += \
@@ -369,7 +399,6 @@ ifeq ($(MODE), tinynowin)
CONFIG_CPPFLAGS += \
-DTINY \
-DNDEBUG \
-DTRUSTWORTHY \
-DSUPPORT_VECTOR=251 \
-DDWARFLESS
CONFIG_CCFLAGS += \
@@ -410,7 +439,7 @@ endif
# The rest of the monorepo may not work with llvm.
#
ifeq ($(MODE), llvm)
.STRICT = 0
.SANDBOXED = 0
CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG -O2
AS = clang
CC = clang
@@ -450,9 +479,9 @@ endif
# like objconv to convert them to COFF or MachO. Then use ANSI mode to
# rollup one header file that'll enable linkage with minimal issues.
ifeq ($(MODE), ansi)
CONFIG_CFLAGS += -std=c11
CONFIG_CFLAGS += -std=c23
#CONFIG_CPPFLAGS += -ansi
CONFIG_CXXFLAGS += -std=c++11
CONFIG_CXXFLAGS += -std=c++23
endif
ifneq ($(ENABLE_FTRACE),)
@@ -490,7 +519,7 @@ endif
ifeq ($(ARCH), aarch64)
# this flag causes gcc to generate functions like this
#
# nop nop nop nop nop nop
# nop nop nop nop nop nop nop nop
# func:
# nop
# ...
@@ -507,7 +536,9 @@ ifeq ($(ARCH), aarch64)
# b -5
# ...
#
CONFIG_CCFLAGS += -fpatchable-function-entry=7,6
# we only need -fpatchable-function-entry=7,6 but we round up to 32
# bytes so we don't break function alignment.
CONFIG_CCFLAGS += -fpatchable-function-entry=9,8
endif
endif
+2 -4
View File
@@ -53,11 +53,7 @@
# OVERRIDE_FOO set ~/.cosmo.mk and target-specific (use rarely)
#
ifeq ($(LANDLOCKMAKE_VERSION),)
TMPSAFE = $(join $(TMPDIR)/,$(subst /,_,$@)).tmp
else
TMPSAFE = $(TMPDIR)/
endif
BACKTRACES = \
-fno-schedule-insns2 \
@@ -94,6 +90,7 @@ DEFAULT_COPTS ?= \
-fstrict-overflow \
-fno-semantic-interposition
ifneq ($(TLSCC),)
ifeq ($(ARCH), x86_64)
# Microsoft says "[a]ny memory below the stack beyond the red zone
# [note: Windows defines the x64 red zone size as 0] is considered
@@ -103,6 +100,7 @@ DEFAULT_COPTS += \
-mno-red-zone \
-mno-tls-direct-seg-refs
endif
endif
ifeq ($(ARCH), aarch64)
#
+5
View File
@@ -99,3 +99,8 @@ rm -f cosmocc.zip cosmocc.zip.sha256sum
# commit output directory
cd "${OLDPWD}" || die
mv "${OUTPUT_TMP}" "${OUTPUT_DIR}" || die
# update current symlink
BASE=$(basename "${OUTPUT_DIR}")
DIR=$(dirname "${OUTPUT_DIR}")
ln -sfn "$BASE" "$DIR/current"
+1 -2
View File
@@ -23,8 +23,7 @@
# - tool/build/runitd.c
.PRECIOUS: o/$(MODE)/%.ok
o/$(MODE)/%.ok: private .PLEDGE = stdio rpath wpath cpath proc fattr inet dns
o/$(MODE)/%.ok: private .UNVEIL += r:/etc/resolv.conf
o/$(MODE)/%.ok: private .PLEDGE = fattr inet dns
o/$(MODE)/%.ok: \
o/$(MODE)/tool/build/runit \
o/$(MODE)/tool/build/runitd \
+10 -19
View File
@@ -145,16 +145,7 @@ o/%.zip.o: o/%
o/$(MODE)/%.zip.o: %
@$(COMPILE) -wAZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) $(OUTPUT_OPTION) $<
o/$(MODE)/%.zip.o: %
@$(COMPILE) -wAZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) $(OUTPUT_OPTION) $<
# an issue with sandboxing arises when creating directory entries in the
# zip file. we need the trailing slash (e.g. o//foo/.zip.o) but Landlock
# Make avoids sandboxing directory names that have a trailing slash (so
# they can be used to watch for deleted files, without creating overly
# broad unveiling). such rules need to be written more explicitly.
o/$(MODE)%/.zip.o: %
@$(COMPILE) -wAZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) $(OUTPUT_OPTION) $<
o/$(MODE)/%.zip.o: private .SANDBOXED = 0
################################################################################
# STRICT HEADER CHECKING
@@ -163,43 +154,43 @@ o/$(MODE)%/.zip.o: %
# and it would be too costly in terms of make latency to have every
# header file depend on $(HDRS) and $(INCS).
o/%.h.ok: private .UNSANDBOXED = 1
o/%.h.ok: private .SANDBOXED = 0
o/%.h.ok: %.h
@$(COMPILE) -ACHECK.h $(COMPILE.c) -xc -g0 -o $@ $<
o/$(MODE)/%.h.ok: private .UNSANDBOXED = 1
o/$(MODE)/%.h.ok: private .SANDBOXED = 0
o/$(MODE)/%.h.ok: %.h
@$(COMPILE) -ACHECK.h $(COMPILE.c) -xc -g0 -o $@ $<
o/$(MODE)/%.hh.ok: private .UNSANDBOXED = 1
o/$(MODE)/%.hh.ok: private .SANDBOXED = 0
o/$(MODE)/%.hh.ok: %.hh
@$(COMPILE) -ACHECK.h $(COMPILE.cxx) -xc++ -g0 -o $@ $<
o/%.okk: .UNSANDBOXED = 1
o/%.okk: .SANDBOXED = 0
o/%.okk: %
@$(COMPILE) -ACHECK.h $(COMPILE.cxx) -xc++ -g0 -o $@ $<
o/$(MODE)/%.okk: private .UNSANDBOXED = 1
o/$(MODE)/%.okk: private .SANDBOXED = 0
o/$(MODE)/%.okk: %
@$(COMPILE) -ACHECK.h $(COMPILE.cxx) -xc++ -g0 -o $@ $<
################################################################################
# EMACS ASSEMBLY GENERATION
o/$(MODE)/%-gcc.asm: private .UNSANDBOXED = 1
o/$(MODE)/%-gcc.asm: private .SANDBOXED = 0
o/$(MODE)/%-gcc.asm: %.c
@$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $<
o/$(MODE)/%-gcc.asm: private .UNSANDBOXED = 1
o/$(MODE)/%-gcc.asm: private .SANDBOXED = 0
o/$(MODE)/%-gcc.asm: %.cc
@$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.cxx) -S -g0 $(OUTPUT_OPTION) $<
o/$(MODE)/%-clang.asm: private .UNSANDBOXED = 1
o/$(MODE)/%-clang.asm: private .SANDBOXED = 0
o/$(MODE)/%-clang.asm: %.c
@$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $<
# TODO(jart): Make intrinsics support Clang.
o/$(MODE)/%-clang.asm: CC = $(CLANG)
o/$(MODE)/%-clang.asm: private .UNSANDBOXED = 1
o/$(MODE)/%-clang.asm: private .SANDBOXED = 0
o/$(MODE)/%-clang.asm: %.cc
@$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.cxx) -S -g0 $(OUTPUT_OPTION) $<
+10
View File
@@ -0,0 +1,10 @@
-nostdinc
-iquote
.
-isystem
libc/isystem
-include
libc/integral/normalize.inc
-D_COSMO_SOURCE
-DMODE="aarch64"
-Wno-unknown-pragmas
+1 -1
View File
@@ -6,7 +6,7 @@
namespace ctl {
struct string;
class string;
class istream : public ios
{
+1 -1
View File
@@ -4,7 +4,7 @@
#define COSMOPOLITAN_CTL_NEW_H_
#ifndef TINY
__static_yoink("__demangle");
__static_yoink("cosmo_demangle");
#endif
namespace ctl {
+44 -3
View File
@@ -97,12 +97,12 @@ class shared_ref
size_t use_count() const noexcept
{
return shared + 1;
return __atomic_load_n(&shared, __ATOMIC_RELAXED) + 1;
}
size_t weak_count() const noexcept
{
return weak;
return __atomic_load_n(&weak, __ATOMIC_RELAXED);
}
private:
@@ -349,7 +349,7 @@ class shared_ptr
template<typename U>
bool owner_before(const weak_ptr<U>& r) const noexcept
{
return !r.owner_before(*this);
return rc < r.rc;
}
private:
@@ -382,6 +382,34 @@ class weak_ptr
rc->keep_weak();
}
weak_ptr(const weak_ptr& r) noexcept : p(r.p), rc(r.rc)
{
if (rc)
rc->keep_weak();
}
template<typename U>
requires __::shared_ptr_compatible<T, U>
weak_ptr(const weak_ptr<U>& r) noexcept : p(r.p), rc(r.rc)
{
if (rc)
rc->keep_weak();
}
weak_ptr(weak_ptr&& r) noexcept : p(r.p), rc(r.rc)
{
r.p = nullptr;
r.rc = nullptr;
}
template<typename U>
requires __::shared_ptr_compatible<T, U>
weak_ptr(weak_ptr<U>&& r) noexcept : p(r.p), rc(r.rc)
{
r.p = nullptr;
r.rc = nullptr;
}
~weak_ptr()
{
if (rc)
@@ -410,6 +438,19 @@ class weak_ptr
swap(rc, r.rc);
}
weak_ptr& operator=(weak_ptr r) noexcept
{
swap(r);
return *this;
}
template<typename U>
requires __::shared_ptr_compatible<T, U>
weak_ptr& operator=(weak_ptr<U> r) noexcept
{
weak_ptr<T>(move(r)).swap(*this);
}
shared_ptr<T> lock() const noexcept
{
if (expired())
+38
View File
@@ -0,0 +1,38 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
//
// Copyright 2026 Justin Alexander 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 "sort.h"
#include "libc/mem/alg.h"
namespace ctl {
namespace detail {
// This lives out of line so that programs calling ctl::sort() only need
// to depend on ctl, rather than on whichever library qsort_r() is in.
void
sort_r(void* a,
size_t n,
size_t es,
int (*cmp)(const void*, const void*, void*),
void* arg)
{
qsort_r(a, n, es, cmp, arg);
}
} // namespace detail
} // namespace ctl
+71 -9
View File
@@ -2,23 +2,54 @@
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_SORT_H_
#define CTL_SORT_H_
#include "is_same.h"
#include "iterator_traits.h"
#include "less.h"
#include "partition.h"
#include "new.h"
#include "utility.h"
namespace ctl {
namespace detail {
template<typename RandomIt, typename Compare>
void
quicksort(RandomIt first, RandomIt last, Compare comp)
sort_r(void*, size_t, size_t, int (*)(const void*, const void*, void*), void*);
template<typename T, typename Compare>
int
sort_compare(const T& x, const T& y, Compare& comp)
{
if (first < last) {
auto pivot = ctl::partition(first, last, comp);
quicksort(first, pivot, comp);
quicksort(pivot + 1, last, comp);
}
if (comp(x, y))
return -1;
if (comp(y, x))
return 1;
return 0;
}
template<typename T, typename Compare>
int
sort_direct(const void* a, const void* b, void* arg)
{
return sort_compare(*static_cast<const T*>(a),
*static_cast<const T*>(b),
*static_cast<Compare*>(arg));
}
template<typename RandomIt, typename Compare>
struct sort_context
{
RandomIt first;
Compare& comp;
};
template<typename RandomIt, typename Compare>
int
sort_indirect(const void* a, const void* b, void* arg)
{
auto* ctx = static_cast<sort_context<RandomIt, Compare>*>(arg);
return sort_compare(ctx->first[*static_cast<const size_t*>(a)],
ctx->first[*static_cast<const size_t*>(b)],
ctx->comp);
}
} // namespace detail
@@ -27,7 +58,38 @@ template<typename RandomIt, typename Compare>
void
sort(RandomIt first, RandomIt last, Compare comp)
{
detail::quicksort(first, last, comp);
using T = typename ctl::iterator_traits<RandomIt>::value_type;
size_t n = last - first;
if (n < 2)
return;
if constexpr (ctl::is_same_v<RandomIt, T*> && __is_trivially_copyable(T)) {
detail::sort_r(
first, n, sizeof(T), detail::sort_direct<T, Compare>, &comp);
return;
}
size_t* idx = new size_t[n];
for (size_t i = 0; i < n; ++i)
idx[i] = i;
detail::sort_context<RandomIt, Compare> ctx{ first, comp };
detail::sort_r(
idx, n, sizeof(size_t), detail::sort_indirect<RandomIt, Compare>, &ctx);
for (size_t i = 0; i < n; ++i) {
if (idx[i] == i)
continue;
T tmp(ctl::move(first[i]));
size_t j = i;
for (;;) {
size_t k = idx[j];
idx[j] = j;
if (k == i) {
first[j] = ctl::move(tmp);
break;
}
first[j] = ctl::move(first[k]);
j = k;
}
}
delete[] idx;
}
template<typename RandomIt>
+1 -1
View File
@@ -277,7 +277,7 @@ size_t
string::find(const char ch, const size_t pos) const noexcept
{
char* q;
if ((q = (char*)memchr(data(), ch, size())))
if (pos < size() && (q = (char*)memchr(data() + pos, ch, size() - pos)))
return q - data();
return npos;
}
+1 -1
View File
@@ -29,7 +29,7 @@ size_t
string_view::find(const char ch, const size_t pos) const noexcept
{
char* q;
if (n && (q = (char*)memchr(p, ch, n)))
if (pos < n && (q = (char*)memchr(p + pos, ch, n - pos)))
return q - p;
return npos;
}
File diff suppressed because it is too large. Load diff
+1
View File
@@ -0,0 +1 @@
../../../third_party/miniaudio/miniaudio.h
+1
View File
@@ -167,6 +167,7 @@ See below for detailed the API documentation.
#include <stdint.h>
#include <stdio.h>
#include <cosmotime.h>
#include <time.h>
+3
View File
@@ -13,6 +13,7 @@ DSP_PROG_BINS = $(DSP_PROG_COMS) $(DSP_PROG_COMS:%=%.dbg)
DSP_PROG_DIRECTDEPS = \
DSP_AUDIO \
LIBC_CALLS \
LIBC_FMT \
LIBC_INTRIN \
LIBC_NEXGEN32E \
LIBC_RUNTIME \
@@ -20,6 +21,8 @@ DSP_PROG_DIRECTDEPS = \
LIBC_STDIO \
LIBC_SYSV \
LIBC_TINYMATH \
THIRD_PARTY_GETOPT \
THIRD_PARTY_MINIAUDIO \
THIRD_PARTY_MUSL \
DSP_PROG_DEPS := \
+154
View File
@@ -0,0 +1,154 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2025 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 "dsp/audio/cosmoaudio/cosmoaudio.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/sig.h"
#include "third_party/getopt/getopt.internal.h"
#include "third_party/miniaudio/miniaudio.h"
/**
* @fileoverview audio file player
*
* This program provides a command line interface for playing .wav,
* .mp3, .flac, and .ogg on the system speaker.
*/
volatile int gotsig;
void onsig(int sig) {
gotsig = sig;
}
void usage(FILE *f) {
fprintf(f, "usage: %s [-hrv] [-s 44100] [-c 2] FILE...\n",
program_invocation_short_name);
}
int main(int argc, char *argv[]) {
// parse flags
int opt;
int flag_repeat = 0;
int flag_verbose = 0;
int flag_channels = 2;
int flag_samprate = 44100;
while ((opt = getopt(argc, argv, "hrvc:s:")) != -1) {
switch (opt) {
case 'c':
flag_channels = atoi(optarg);
if (flag_channels < 1) {
fprintf(stderr, "error: invalid channel count\n");
exit(1);
}
break;
case 's':
flag_samprate = atoi(optarg);
if (flag_samprate < 1) {
fprintf(stderr, "error: invalid sampling rate\n");
exit(1);
}
break;
case 'v':
++flag_verbose;
break;
case 'r':
++flag_repeat;
break;
case 'h':
usage(stdout);
exit(0);
default:
usage(stderr);
exit(1);
}
}
// open speaker
int status;
struct CosmoAudio *ca;
struct CosmoAudioOpenOptions cao = {0};
cao.sizeofThis = sizeof(struct CosmoAudioOpenOptions);
cao.deviceType = kCosmoAudioDeviceTypePlayback;
cao.sampleRate = flag_samprate;
cao.debugLog = flag_verbose > 1;
cao.channels = flag_channels;
status = cosmoaudio_open(&ca, &cao);
if (status != COSMOAUDIO_SUCCESS) {
fprintf(stderr, "failed to open speaker: %d\n", status);
exit(1);
}
// intercept ctrl-c
signal(SIGINT, onsig);
// play files
int exit_code = 0;
do {
for (int arg = optind; arg < argc; ++arg) {
const char *fname = argv[arg];
if (flag_verbose)
fprintf(stderr, "playing %s\n", fname);
// create decoder
ma_decoder_config decoderConfig =
ma_decoder_config_init(ma_format_f32, flag_channels, flag_samprate);
decoderConfig.resampling.algorithm = ma_resample_algorithm_linear;
decoderConfig.resampling.linear.lpfOrder = 8;
// open input file
ma_decoder decoder;
ma_result rc = ma_decoder_init_file(fname, &decoderConfig, &decoder);
if (rc != MA_SUCCESS) {
fprintf(stderr,
"%s: failed to open audio file: %s (we support "
".wav, .mp3, .flac, and .ogg)\n",
fname, ma_result_description(rc));
exit_code = 1;
goto exit;
}
// decode audio and transfer to speaker
while (!gotsig) {
float buf[512];
ma_uint64 got = 0;
ma_uint64 max = sizeof(buf) / sizeof(*buf) / flag_channels;
ma_decoder_read_pcm_frames(&decoder, buf, max, &got);
if (!got)
break;
int can = got;
cosmoaudio_poll(ca, NULL, &can);
cosmoaudio_write(ca, buf, got);
}
// cleanup
ma_decoder_uninit(&decoder);
}
} while (!gotsig && flag_repeat);
// we're done
exit:
cosmoaudio_flush(ca);
cosmoaudio_close(ca);
exit(exit_code);
}
+2 -14
View File
@@ -56,7 +56,6 @@ EXAMPLES_DIRECTDEPS = \
LIBC_NT_IPHLPAPI \
LIBC_NT_KERNEL32 \
LIBC_NT_MEMORY \
LIBC_NT_NTDLL \
LIBC_NT_USER32 \
LIBC_NT_WS2_32 \
LIBC_PROC \
@@ -80,6 +79,7 @@ EXAMPLES_DIRECTDEPS = \
THIRD_PARTY_DOUBLECONVERSION \
THIRD_PARTY_GDTOA \
THIRD_PARTY_GETOPT \
THIRD_PARTY_HACLSTAR \
THIRD_PARTY_HIREDIS \
THIRD_PARTY_LIBCXX \
THIRD_PARTY_LIBCXXABI \
@@ -87,6 +87,7 @@ EXAMPLES_DIRECTDEPS = \
THIRD_PARTY_LINENOISE \
THIRD_PARTY_LUA \
THIRD_PARTY_MBEDTLS \
THIRD_PARTY_MINIAUDIO \
THIRD_PARTY_MUSL \
THIRD_PARTY_NSYNC \
THIRD_PARTY_NSYNC_MEM \
@@ -109,11 +110,6 @@ o/$(MODE)/examples/examples.pkg: \
$(EXAMPLES_OBJS) \
$(foreach x,$(EXAMPLES_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/examples/unbourne.o: private \
CPPFLAGS += \
-DSTACK_FRAME_UNLIMITED \
-fpie
o/$(MODE)/examples/%.dbg: \
$(EXAMPLES_DEPS) \
o/$(MODE)/examples/%.o \
@@ -129,14 +125,6 @@ o/$(MODE)/examples/hellolua.dbg: \
$(EXAMPLES_BOOTLOADER)
@$(APELINK)
o/$(MODE)/examples/ispell.dbg: \
$(EXAMPLES_DEPS) \
o/$(MODE)/examples/ispell.o \
o/$(MODE)/usr/share/dict/words.zip.o \
o/$(MODE)/examples/examples.pkg \
$(EXAMPLES_BOOTLOADER)
@$(APELINK)
o/$(MODE)/examples/nesemu1.dbg: \
$(EXAMPLES_DEPS) \
o/$(MODE)/examples/nesemu1.o \
+3 -3
View File
@@ -60,10 +60,10 @@ struct List {
int count;
};
atomic_uintptr_t list;
_Atomic(struct List*) list;
void push(struct List* elem) {
uintptr_t tip;
struct List* tip;
assert(!TAG(elem));
for (tip = atomic_load_explicit(&list, memory_order_relaxed);;) {
elem->next = (struct List*)PTR(tip);
@@ -76,7 +76,7 @@ void push(struct List* elem) {
}
struct List* pop(void) {
uintptr_t tip;
struct List* tip;
struct List* elem;
tip = atomic_load_explicit(&list, memory_order_relaxed);
while ((elem = (struct List*)PTR(tip))) {
+146
View File
@@ -0,0 +1,146 @@
// clang-format off
//
// this program implements ancient roman cryptography
//
// example usage:
//
// make -j o//examples/caesar # compile
// o//examples/caesar 23 <file.txt | # encrypt
// o//examples/caesar # decrypt
//
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Rick Adams.
*
* Authors:
* Stan King, John Eldridge, based on algorithm suggested by
* Bob Morris
* 29-Sep-82
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <errno.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#define LINELENGTH 2048
#define ROTATE(ch, perm) \
isascii(ch) ? ( \
isupper(ch) ? ('A' + (ch - 'A' + perm) % 26) : \
islower(ch) ? ('a' + (ch - 'a' + perm) % 26) : ch) : ch
/*
* letter frequencies (taken from some unix(tm) documentation)
* (unix is a trademark of Bell Laboratories)
*/
static double stdf[26] = {
7.97, 1.35, 3.61, 4.78, 12.37, 2.01, 1.46, 4.49, 6.39, 0.04,
0.42, 3.81, 2.69, 5.92, 6.96, 2.91, 0.08, 6.63, 8.77, 9.68,
2.62, 0.81, 1.88, 0.23, 2.07, 0.06,
};
static void
printit(char *arg)
{
int ch, rot;
if ((rot = atoi(arg)) < 0) {
fprintf(stderr, "caesar: bad rotation value.\n");
exit(1);
}
while ((ch = getchar()) != EOF)
putchar(ROTATE(ch, rot));
exit(0);
}
int
main(int argc, char **argv)
{
int ch, dot, i, nread, winnerdot = 0;
unsigned char inbuf[LINELENGTH];
int obs[26], try, winner;
if (argc > 1)
printit(argv[1]);
/* adjust frequency table to weight low probs REAL low */
for (i = 0; i < 26; ++i)
stdf[i] = log(stdf[i]) + log(26.0 / 100.0);
/* zero out observation table */
bzero(obs, 26 * sizeof(int));
if ((nread = read(STDIN_FILENO, inbuf, LINELENGTH)) < 0) {
perror("caesar");
exit(1);
}
for (i = nread; i--;) {
ch = inbuf[i];
if (isascii(ch)) {
if (islower(ch))
++obs[ch - 'a'];
else if (isupper(ch))
++obs[ch - 'A'];
}
}
/*
* now "dot" the freqs with the observed letter freqs
* and keep track of best fit
*/
for (try = winner = 0; try < 26; ++try) { /* += 13) { */
dot = 0;
for (i = 0; i < 26; i++)
dot += obs[i] * stdf[(i + try) % 26];
/* initialize winning score */
if (try == 0)
winnerdot = dot;
if (dot > winnerdot) {
/* got a new winner! */
winner = try;
winnerdot = dot;
}
}
while (nread) {
for (i = 0; i < nread; ++i) {
ch = inbuf[i];
putchar(ROTATE(ch, winner));
}
if ((nread = read(STDIN_FILENO, inbuf, LINELENGTH)) < 0) {
perror("caesar");
exit(1);
}
}
}
+1 -1
View File
@@ -89,7 +89,7 @@ int main(int argc, char *argv[]) {
// not the case when you use sigprocmask() to block signals which is
// useful for kicking the can down the road.
WRITE("doing cpu task...\n");
for (volatile int i = 0; i < INT_MAX / 3; ++i) {
for (volatile int i = 0; i < (int)(INT_MAX * .4); ++i) {
if (gotsig) {
WRITE("\rgot ctrl+c asynchronously\n");
exit(0);
+1 -1
View File
@@ -259,7 +259,7 @@ int main(int argc, char *argv[]) {
unassert(!sigaction(SIGTERM, &sa, 0));
// you can pass the number of threads you want as the first command arg
threads = argc > 1 ? atoi(argv[1]) : __get_cpu_count();
threads = argc > 1 ? atoi(argv[1]) : cosmo_cpu_count();
if (!(1 <= threads && threads <= 100000)) {
tinyprint(2, "error: invalid number of threads\n", NULL);
exit(1);
+111
View File
@@ -0,0 +1,111 @@
#/*─────────────────────────────────────────────────────────────────╗
│ 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/ │
╚─────────────────────────────────────────────────────────────────*/
#include <ctype.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
// POSIX kill command
//
// - kill -l
// - kill -9 123 456
// - kill -KILL 123 456
// - kill -SIGKILL 123 456
// - kill -s SIGKILL 123 456
//
const char kSignals[] = {
SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS,
SIGFPE, SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM,
SIGTERM, SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU,
SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, SIGSYS,
};
const char kSignalNames[][8] = {
"HUP", "INT", "QUIT", "ILL", "TRAP", "ABRT", "BUS",
"FPE", "KILL", "USR1", "SEGV", "USR2", "PIPE", "ALRM",
"TERM", "CHLD", "CONT", "STOP", "TSTP", "TTIN", "TTOU",
"URG", "XCPU", "XFSZ", "VTALRM", "PROF", "WINCH", "SYS",
};
void list_signals(void) {
for (int i = 0; i < sizeof(kSignals); i += 4) {
for (int j = 0; j < 4; ++j) {
if (i + j < sizeof(kSignals)) {
int sig = kSignals[i + j];
printf("%2d) SIG%-7s", sig, kSignalNames[i + j]);
}
}
printf("\n");
}
}
int main(int argc, char *argv[]) {
const char *prog = argv[0];
if (!prog)
prog = "kill";
int arg = 1;
const char *sigstr = 0;
if (arg < argc) {
if (argv[arg][0] == '-') {
if (argv[arg][1] == 's' && !argv[arg][2]) {
if (++arg < argc)
sigstr = argv[arg++];
} else if (argv[arg][1] == 'l' && !argv[arg][2]) {
list_signals();
exit(0);
} else {
sigstr = argv[arg++] + 1;
}
}
}
if (arg == argc) {
fprintf(stderr, "%s: missing operand\n", prog);
exit(1);
}
int sig;
if (!sigstr) {
sig = SIGTERM;
} else {
sig = atoi(sigstr);
if (sig) {
if (!(1 <= sig && sig <= NSIG)) {
fprintf(stderr, "%s: bad signal number: %d\n", prog, sig);
exit(1);
}
} else {
if (toupper(sigstr[0]) == 'S' && //
toupper(sigstr[1]) == 'I' && //
toupper(sigstr[2]) == 'G')
sigstr += 3;
for (int i = 0; i < sizeof(kSignals); ++i)
if (!strcasecmp(sigstr, kSignalNames[i]))
sig = kSignals[i];
if (!sig) {
fprintf(stderr, "%s: bad signal name: %s\n", prog, sigstr);
exit(1);
}
}
}
int rc = 0;
for (int i = arg; i < argc; ++i) {
int pid = atoi(argv[i]);
if (kill(pid, sig)) {
fprintf(stderr, "%s: %d: %s\n", prog, pid, strerror(errno));
rc = 1;
}
}
exit(rc);
}
+98
View File
@@ -0,0 +1,98 @@
#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 <cosmo.h>
#include <malloc.h>
#include <pthread.h>
#include <stdlib.h>
// cosmo bulitin memory leak detector demo
//
// you can use cosmo's memory leak detector to track backtraces for your
// memory allocations and then print error messages using addr2line. you
// generally want to have your app override malloc with your own malloc.
// you can use libc's builtin dlmalloc implementation like this as well.
// using this leak detector makes malloc() go 10x slower and allocations
// will each use 200 bytes of additional memory. if you don't care about
// backtraces, then you can create a leak detector for free by using the
// CheckForMemoryLeaks() function at the end of main().
//
// $ make -j o//examples/memleak_backtrace
// $ o//examples/memleak_backtrace
// let's demo the builtin memory leak detector
// error: memory leak detected 0x778dd0979fc0
// 42175f4 in malloc at /home/jart/cosmo/examples/memleak_backtrace.c:34
// 42049b7 in main at /home/jart/cosmo/examples/memleak_backtrace.c:67
// 4204db4 in cosmo at /home/jart/cosmo/libc/runtime/cosmo.S:103
// 42045d9 in _start at /home/jart/cosmo/libc/crt/crt.S:128
// error: memory leak detected 0x778dd0979fe0
// 42175f4 in malloc at /home/jart/cosmo/examples/memleak_backtrace.c:34
// 42049aa in main at /home/jart/cosmo/examples/memleak_backtrace.c:66
// 4204db4 in cosmo at /home/jart/cosmo/libc/runtime/cosmo.S:103
// 42045d9 in _start at /home/jart/cosmo/libc/crt/crt.S:128
//
// wrap cosmopolitan's memory allocator to track allocations
static pthread_mutex_t mu = PTHREAD_MUTEX_INITIALIZER;
void *malloc(size_t n) {
pthread_mutex_lock(&mu);
void *r = cosmo_leak_track(__dlmalloc(n));
pthread_mutex_unlock(&mu);
return r;
}
void *calloc(size_t n, size_t z) {
pthread_mutex_lock(&mu);
void *r = cosmo_leak_track(__dlcalloc(n, z));
pthread_mutex_unlock(&mu);
return r;
}
void *realloc(void *p, size_t n) {
pthread_mutex_lock(&mu);
void *t = cosmo_leak_track(__dlrealloc(p, n));
if (t && t != p)
cosmo_leak_untrack(p);
pthread_mutex_unlock(&mu);
return t;
}
void *memalign(size_t a, size_t n) {
pthread_mutex_lock(&mu);
void *r = cosmo_leak_track(__dlmemalign(a, n));
pthread_mutex_unlock(&mu);
return r;
}
void free(void *p) {
pthread_mutex_lock(&mu);
__dlfree(cosmo_leak_untrack(p));
pthread_mutex_unlock(&mu);
}
// the c standard says this function can't be optimized away
void *identity(void *arg) {
return arg;
}
void *(*pIdentity)(void *) = identity;
int main(void) {
kprintf("let's demo the builtin memory leak detector\n");
// leak two allocations, one small, one large
pIdentity(malloc(1));
pIdentity(malloc(257));
// wait for any detached posix threads to exit
while (!pthread_orphan_np())
pthread_decimate_np();
// this runs atexit functions and thread/process finalizers
cosmo_leak_finalize();
// print information about memory leaks with backtraces
if (cosmo_leak_print(0) > 0)
_Exit(73);
}
+39
View File
@@ -0,0 +1,39 @@
#/*─────────────────────────────────────────────────────────────────╗
│ 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/ │
╚─────────────────────────────────────────────────────────────────*/
#include <cosmo.h>
#include <stdlib.h>
// zero-overhead memory leak detector demo
//
// $ make -j o//examples/memleak_zerocost
// $ o//examples/memleak_zerocost
// error: leaked 128 byte allocation at 0x7a1483eabf50
// error: leaked 16 byte allocation at 0x7a1483eacfe0
// error: leaked 1'008 byte allocation at 0x42671e0
// you forgot to call free 3 times
//
void NoOp(void *p) {
}
void (*pNoOp)(void *) = NoOp;
int main(int argc, char *argv[]) {
// run program, which leaks memory
pNoOp(malloc(10));
pNoOp(malloc(100));
pNoOp(malloc(1000));
// check for memory leaks. this has zero overhead, because it crawls
// the data structures used by cosmopolitan's malloc implementation.
// this is great thing to always use so you know when there's a leak
// and if you have trouble tracking down where it came from then you
// can swap this out with the code in examples/memleak_backtrace.c
CheckForMemoryLeaks();
}
-143
View File
@@ -1,143 +0,0 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
│ To the extent possible under law, Justine Tunney has waived │
│ all copyright and related or neighboring rights to this file, │
│ as it is written in the following disclaimers: │
│ • http://unlicense.org/ │
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
╚─────────────────────────────────────────────────────────────────*/
#endif
#include <cosmo.h>
#include <getopt.h>
#include <netdb.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
// clang-format off
/**
* @fileoverview netcat clone
*
* Implemented because BusyBox's netcat doesn't detect remote close and
* lingers in the CLOSE_WAIT wait possibly due to file descriptor leaks
*
* Here's an example usage:
*
* make -j8 o//examples/nc.com
* printf 'GET /\r\nHost: justine.lol\r\n\r\n' | o//examples/nc.com justine.lol 80
*
* Once upon time we called this command basically "telnet"
*/
#define ARRAYLEN(A) \
((sizeof(A) / sizeof(*(A))) / ((unsigned)!(sizeof(A) % sizeof(*(A)))))
int main(int argc, char *argv[]) {
ssize_t rc;
size_t i, got;
int opt, sock;
char buf[1500];
bool halfclose = true;
const char *host, *port;
struct addrinfo *ai = NULL;
struct linger linger = {true, 1};
struct pollfd fds[2] = {{-1, POLLIN}, {-1, POLLIN}};
struct addrinfo hint = {AI_NUMERICSERV, AF_INET, SOCK_STREAM, IPPROTO_TCP};
while ((opt = getopt(argc, argv, "hH")) != -1) {
switch (opt) {
case 'H':
halfclose = false;
break;
case 'h':
tinyprint(1, "Usage: ", argv[0], " [-hH] IP PORT\n", NULL);
exit(0);
default:
fprintf(stderr, "bad option %d\n", opt);
exit(1);
}
}
if (argc - optind != 2) {
fputs("missing args\n", stderr);
exit(1);
}
host = argv[optind + 0];
port = argv[optind + 1];
if ((rc = getaddrinfo(host, port, &hint, &ai))) {
tinyprint(2, host, ": ", gai_strerror(rc), "\n", NULL);
exit(1);
}
if ((sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) == -1) {
perror("socket");
exit(1);
}
if (setsockopt(sock, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger)) == -1) {
perror("SO_LINGER");
exit(1);
}
if (connect(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
perror(host);
exit(1);
}
fds[0].fd = 0;
fds[1].fd = sock;
for (;;) {
fds[0].revents = 0;
fds[1].revents = 0;
if (poll(fds, ARRAYLEN(fds), -1) == -1) {
perror("poll");
exit(1);
}
if (fds[0].revents & (POLLIN | POLLERR | POLLHUP)) {
if ((rc = read(0, buf, 1400)) == -1) {
perror("read(stdin)");
exit(1);
}
if (!(got = rc)) {
if (halfclose) {
shutdown(sock, SHUT_WR);
}
fds[0].fd = -1;
}
for (i = 0; i < got; i += rc) {
if ((rc = write(sock, buf + i, got - i)) == -1) {
perror("write(sock)");
exit(1);
}
}
}
if (fds[1].revents & (POLLIN | POLLERR | POLLHUP)) {
if ((rc = read(sock, buf, 1500)) == -1) {
perror("read(sock)");
exit(1);
}
if (!(got = rc)) {
break;
}
for (i = 0; i < got; i += rc) {
if ((rc = write(1, buf + i, got - i)) == -1) {
perror("write(stdout)");
exit(1);
}
}
}
}
if (close(sock) == -1) {
perror("close");
exit(1);
}
freeaddrinfo(ai);
return 0;
}
+1
View File
@@ -16,6 +16,7 @@
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/winsize.h"
#include "libc/calls/termios.h"
#include "libc/cosmotime.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
+1 -1
View File
@@ -11,5 +11,5 @@
#include <stdio.h>
int main(int argc, char *argv[]) {
printf("%d\n", __get_cpu_count());
printf("%d\n", cosmo_cpu_count());
}
+1
View File
@@ -10,6 +10,7 @@
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/timeval.h"
#include "libc/cosmotime.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/fmt/magnumstrs.internal.h"
-1022
View File
File diff suppressed because it is too large. Load diff
+4 -2
View File
@@ -13,7 +13,9 @@
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/timespec.h"
#include "libc/cosmotime.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/appendresourcereport.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/append.h"
@@ -27,7 +29,7 @@ int main(int argc, char *argv[]) {
prog = "rusage";
if (argc < 2) {
tinyprint(2, prog, ": missing command\n", NULL);
fprintf(stderr, "%s: missing command\n", prog);
exit(1);
}
@@ -42,7 +44,7 @@ int main(int argc, char *argv[]) {
struct timespec started = timespec_real();
// launch subprocess
int child = fork();
int child = vfork();
if (child == -1) {
perror(prog);
exit(1);
+58
View File
@@ -0,0 +1,58 @@
#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 <pthread.h>
#include <semaphore.h>
#include <stdatomic.h>
#include <stdio.h>
#include <stdlib.h>
#define PHILOSOPHERS 9 // number of hungry philosophers
#define THOUGHTS 3 // number of breaks for thinking
#define SEATS 3 // number of seats at the tables
atomic_int occupied;
sem_t sem;
void *philosopher(void *arg) {
int tid = (long)arg;
printf("philosopher#%d arrives\n", tid);
for (int i = 0; i < THOUGHTS; ++i) {
sem_wait(&sem);
printf("philosopher#%d sat down to eat (%d occupied)\n", tid, ++occupied);
usleep(rand() % 1000000);
printf("philosopher#%d gets up to think (%d occupied)\n", tid, --occupied);
sem_post(&sem);
usleep(rand() % 1000000);
}
printf("philosopher#%d leaves\n", tid);
return 0;
}
int main(int argc, char *argv[]) {
printf("inviting %d philosophers to %d person dinner\n", PHILOSOPHERS, SEATS);
sem_init(&sem, 0, SEATS);
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
for (long i = 0; i < PHILOSOPHERS; ++i) {
pthread_t th;
pthread_create(&th, &attr, philosopher, (void *)i);
}
pthread_exit(0);
}
+3 -1
View File
@@ -9,7 +9,9 @@
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ucontext.h>
#include <unistd.h>
/**
* @fileoverview swapcontext() and makecontext() example
@@ -20,7 +22,7 @@ static ucontext_t uctx_main;
static ucontext_t uctx_func1;
static ucontext_t uctx_func2;
#define say(s) write(1, s, strlen(s))
#define say(s) (void)!write(1, s, strlen(s))
#define handle_error(msg) \
do { \
perror(msg); \
+13 -10
View File
@@ -12,6 +12,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <time.h>
/**
@@ -62,7 +63,6 @@ const char *DescribeFileType(unsigned mode) {
void PrintFileMetadata(const char *pathname, struct stat *st) {
int fd;
printf("\n%s:", pathname);
if (numeric) {
fd = atoi(pathname);
if (fstat(fd, st)) {
@@ -70,15 +70,16 @@ void PrintFileMetadata(const char *pathname, struct stat *st) {
exit(1);
}
} else {
if (stat(pathname, st)) {
if (lstat(pathname, st)) {
perror(pathname);
exit(1);
}
}
printf("\n"
"%-32s%,ld\n"
"%-32s%,ld\n"
"%-32s%#lx\n"
"%s:\n"
"%-32s%,ld\n" // bytes in file
"%-32s%,ld\n" // physical bytes
"%-32s%u,%u\n" // device id
"%-32s%#lx\n"
"%-32s%ld\n"
"%-32s%#o (%s)\n"
@@ -92,11 +93,13 @@ void PrintFileMetadata(const char *pathname, struct stat *st) {
"%-32s%s\n"
"%-32s%s\n"
"%-32s%s\n",
"bytes in file:", st->st_size, "physical bytes:", st->st_blocks * 512,
"device id w/ file:", st->st_dev, "inode:", st->st_ino,
"hard link count:", st->st_nlink, "mode / permissions:", st->st_mode,
DescribeFileType(st->st_mode), "owner id:", st->st_uid,
"group id:", st->st_gid, "flags:", st->st_flags, "gen:", st->st_gen,
pathname, "bytes in file:", st->st_size,
"physical bytes:", st->st_blocks * 512,
"device id w/ file:", major(st->st_dev), minor(st->st_dev),
"inode:", st->st_ino, "hard link count:", st->st_nlink,
"mode / permissions:", st->st_mode, DescribeFileType(st->st_mode),
"owner id:", st->st_uid, "group id:", st->st_gid,
"flags:", st->st_flags, "gen:", st->st_gen,
"device id (if special):", st->st_rdev, "block size:", st->st_blksize,
"access time:", gc(xiso8601(st->st_atim)),
"modified time:", gc(xiso8601(st->st_mtim)),
+3
View File
@@ -45,4 +45,7 @@ int main(int argc, char *argv[]) {
return 0;
}
#else
int main(int argc, char *argv[]) {
}
#endif /* __x86_64__ */
+3
View File
@@ -61,4 +61,7 @@ int main(int argc, char *argv[]) {
}
}
#else
int main(int argc, char *argv[]) {
}
#endif /* __x86_64__ */
+3
View File
@@ -43,4 +43,7 @@ int main(int argc, char *argv[]) {
;
}
#else
int main(int argc, char *argv[]) {
}
#endif /* __x86_64__ */
+22
View File
@@ -0,0 +1,22 @@
#/*─────────────────────────────────────────────────────────────────╗
│ 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/ │
╚─────────────────────────────────────────────────────────────────*/
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
void onsig(int sig) {
fprintf(stderr, "got %s\n", strsignal(sig));
}
int main(int argc, char *argv[]) {
fprintf(stderr, "my pid is %d\n", getpid());
for (int sig = 1; sig <= NSIG; ++sig)
signal(sig, onsig);
pause();
}
+10 -1
View File
@@ -13,12 +13,17 @@ libc/isystem/arm_fp16.h \
libc/isystem/arm_neon.h \
libc/isystem/arpa/inet.h \
libc/isystem/arpa/nameser.h \
libc/isystem/arpa/telnet.h \
libc/isystem/assert.h \
libc/isystem/bsd/readpassphrase.h \
libc/isystem/bsd/stdlib.h \
libc/isystem/bsd/string.h \
libc/isystem/byteswap.h \
libc/isystem/clzerointrin.h \
libc/isystem/complex.h \
libc/isystem/cosmo.h \
libc/isystem/cosmoaudio.h \
libc/isystem/cosmotime.h \
libc/isystem/cpio.h \
libc/isystem/cpuid.h \
libc/isystem/crypt.h \
@@ -49,9 +54,12 @@ libc/isystem/langinfo.h \
libc/isystem/libgen.h \
libc/isystem/limits.h \
libc/isystem/link.h \
libc/isystem/linux/f2fs.h \
libc/isystem/linux/futex.h \
libc/isystem/linux/ioctl.h \
libc/isystem/linux/limits.h \
libc/isystem/linux/param.h \
libc/isystem/linux/rseq.h \
libc/isystem/linux/types.h \
libc/isystem/locale.h \
libc/isystem/malloc.h \
@@ -68,6 +76,7 @@ libc/isystem/net/if.h \
libc/isystem/net/if_arp.h \
libc/isystem/netdb.h \
libc/isystem/netinet/in.h \
libc/isystem/netinet/in_systm.h \
libc/isystem/netinet/ip.h \
libc/isystem/netinet/tcp.h \
libc/isystem/netinet/udp.h \
@@ -94,6 +103,7 @@ libc/isystem/popcntintrin.h \
libc/isystem/pthread.h \
libc/isystem/pty.h \
libc/isystem/pwd.h \
libc/isystem/readpassphrase.h \
libc/isystem/regex.h \
libc/isystem/resolv.h \
libc/isystem/sched.h \
@@ -135,7 +145,6 @@ libc/isystem/sys/param.h \
libc/isystem/sys/poll.h \
libc/isystem/sys/prctl.h \
libc/isystem/sys/procfs.h \
libc/isystem/sys/ptrace.h \
libc/isystem/sys/random.h \
libc/isystem/sys/reboot.h \
libc/isystem/sys/resource.h \
+2 -1
View File
@@ -23,7 +23,8 @@ void unassert(const char *, const char *, int) libcesque;
#define assert(x) ((void)((x) || (__assert_fail(#x, __FILE__, __LINE__), 0)))
#endif
#if __STDC_VERSION__ >= 201112L && !defined(__cplusplus)
#if !defined(__cplusplus) && defined(__STDC_VERSION__) && \
__STDC_VERSION__ >= 201112L && __STDC_VERSION__ <= 201710L
#undef static_assert
#define static_assert _Static_assert
#endif
+15
View File
@@ -0,0 +1,15 @@
#ifndef COSMOPOLITAN_LIBC_BSDSTDLIB_H_
#define COSMOPOLITAN_LIBC_BSDSTDLIB_H_
COSMOPOLITAN_C_START_
uint32_t arc4random(void);
void arc4random_buf(void *, size_t);
uint32_t arc4random_uniform(uint32_t);
void *reallocarray(void *, size_t, size_t);
long long strtonum(const char *, long long, long long, const char **);
int heapsort(void *, size_t, size_t, int (*)(const void *, const void *));
int mergesort(void *, size_t, size_t, int (*)(const void *, const void *));
COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_LIBC_BSDSTDLIB_H_ */
+7 -2
View File
@@ -50,6 +50,7 @@ LIBC_CALLS_A_DIRECTDEPS = \
LIBC_NT_PSAPI \
LIBC_NT_REALTIME \
LIBC_NT_SYNCHRONIZATION \
LIBC_NT_WINMM \
LIBC_NT_WS2_32 \
LIBC_STR \
LIBC_SYSV \
@@ -111,7 +112,7 @@ o//libc/calls/prctl.o: \
# we always want -Os because:
# it's early runtime mandatory and quite huge without it
o//libc/calls/getcwd.greg.o \
o//libc/calls/getcwd.o \
o//libc/calls/statfs2cosmo.o: private \
CFLAGS += \
-Os
@@ -174,7 +175,6 @@ o//libc/calls/gettimeofday.o \
o//libc/calls/ioctl.o \
o//libc/calls/lutimes.o \
o//libc/calls/metaflock.o \
o//libc/calls/ntaccesscheck.o \
o//libc/calls/ntspawn.o \
o//libc/calls/open-nt.o \
o//libc/calls/pledge-linux.o \
@@ -215,6 +215,11 @@ o//libc/calls/writev.o: private \
COPTS += \
-mgeneral-regs-only
# it's too early to use memmove() due to __vex and WinMain
o/$(MODE)/libc/calls/mkunixpath.o: private \
CFLAGS += \
-ffreestanding
# these assembly files are safe to build on aarch64
o/$(MODE)/libc/calls/stackjump.o: libc/calls/stackjump.S
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
+42 -6
View File
@@ -17,10 +17,20 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/sigset.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/sig.h"
#include "libc/thread/posixthread.internal.h"
#include "libc/thread/thread.h"
alignas(64) static struct {
pthread_mutex_t lock;
int phase;
} __abort = {
PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
};
/**
* Terminates program abnormally.
@@ -33,10 +43,36 @@
* @noreturn
*/
wontreturn void abort(void) {
sigset_t m = 1ull << (SIGABRT - 1);
sigprocmask(SIG_UNBLOCK, &m, 0);
raise(SIGABRT);
signal(SIGABRT, SIG_DFL);
raise(SIGABRT);
_Exit(128 + SIGABRT);
sigset_t mask;
if (!__spawned)
pthread_mutex_lock(&__abort.lock);
switch (__abort.phase) {
case 0:
mask = 1ull << (SIGABRT - 1);
sigprocmask(SIG_UNBLOCK, &mask, 0);
__abort.phase = 1;
// fallthrough
case 1:
__abort.phase = 0;
if (!__spawned)
pthread_mutex_unlock(&__abort.lock);
raise(SIGABRT);
if (!__spawned)
pthread_mutex_lock(&__abort.lock);
__abort.phase = 2;
// fallthrough
case 2:
__abort.phase = 3;
signal(SIGABRT, SIG_DFL);
// fallthrough
case 3:
__abort.phase = 4;
raise(SIGABRT);
// fallthrough
case 4:
__abort.phase = 5;
_Exit(128 + SIGABRT);
}
for (;;)
notpossible;
}
+4 -2
View File
@@ -20,12 +20,14 @@
#include "libc/sysv/consts/at.h"
/**
* Checks if effective user can access path in particular ways.
* Checks if file can be accessed in particular way.
*
* This is equivalent to saying:
* This function is equivalent to:
*
* faccessat(AT_FDCWD, path, mode, 0);
*
* Please see faccessat() for further documentation.
*
* @param path is a filename or directory
* @param mode can be R_OK, W_OK, X_OK, F_OK
* @return 0 if ok, or -1 w/ errno
+330
View File
@@ -0,0 +1,330 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
│ vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi │
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright (c) 1996, David Mazieres <[email protected]> │
│ Copyright (c) 2008, Damien Miller <[email protected]> │
│ Copyright (c) 2013, Markus Friedl <[email protected]> │
│ Copyright (c) 2014, Theo de Raadt <[email protected]> │
│ Copyright (c) Robert Clausecker <[email protected]> │
│ │
│ 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/state.internal.h"
#include "libc/calls/typedef/u.h"
#include "libc/cosmo.h"
#include "libc/stdio/rand.h"
#include "libc/str/str.h"
#include "libc/thread/posixthread.internal.h"
#include "libc/thread/thread.h"
// clang-format off
#define FAIR_SHARE 1024
#define USE_CURRENT_CPU 1
#define USE_THREAD_COUNT 1
__notice(arc4random_notice, "arc4random (ISC)\n\
Copyright (c) 1996, David Mazieres <[email protected]>\n\
Copyright (c) 2008, Damien Miller <[email protected]>\n\
Copyright (c) 2013, Markus Friedl <[email protected]>\n\
Copyright (c) 2014, Theo de Raadt <[email protected]>\n\
Copyright (c) 2024, Robert Clausecker <[email protected]>\n\
Copyright (c) 2025, Justine Tunney <[email protected]>\n\
Based upon D. J. Bernstein's public domain ChaCha code\n\
Based upon Daniel Lemire's arc4random_uniform research");
#define KEYSTREAM_ONLY
#include "libc/str/chacha.inc"
#define minimum(a, b) ((a) < (b) ? (a) : (b))
#define KEYSZ 32
#define IVSZ 8
#define BLOCKSZ 64
#define RSBUFSZ (16*BLOCKSZ)
#define REKEY_BASE (1024*1024) /* NB. should be a power of 2 */
/* This is zero'd out in forked children. */
struct _rs {
size_t rs_have; /* valid bytes at end of rs_buf */
size_t rs_count; /* bytes till reseed */
};
/* Optional to preserve in forked children. */
struct _rsx {
chacha_ctx rs_chacha; /* chacha context for random keystream */
u_char rs_buf[RSBUFSZ]; /* keystream blocks */
};
struct _rng {
alignas(64) pthread_mutex_t mtx;
bool once;
struct _rs rs;
struct _rsx rsx;
};
static struct _rng _rs_state[COSMO_SHARDS];
void
__arc4random_fork_prepare(void)
{
if (__isthreaded < 2)
return;
for (int i = 0; i < COSMO_SHARDS; ++i)
if (_rs_state[i].once)
pthread_mutex_lock(&_rs_state[i].mtx);
}
void
__arc4random_fork_parent(void)
{
if (__isthreaded < 2)
return;
for (int i = COSMO_SHARDS; i--;)
if (_rs_state[i].once)
pthread_mutex_unlock(&_rs_state[i].mtx);
}
void
__arc4random_fork_child(void)
{
for (int i = 0; i < COSMO_SHARDS; ++i) {
if (!_rs_state[i].once)
continue;
pthread_mutex_wipe_np(&_rs_state[i].mtx);
memset(&_rs_state[i].rs, 0, sizeof(_rs_state[i].rs));
}
}
static inline void
_rs_init(struct _rng *rng, u_char *buf, size_t n)
{
if (n < KEYSZ + IVSZ)
return;
chacha_keysetup(&rng->rsx.rs_chacha, buf, KEYSZ * 8);
chacha_ivsetup(&rng->rsx.rs_chacha, buf + KEYSZ);
rng->once = true;
}
static inline void
_rs_rekey(struct _rng *rng, u_char *dat, size_t datlen)
{
#ifndef KEYSTREAM_ONLY
memset(rng->rsx.rs_buf, 0, sizeof(rng->rsx.rs_buf));
#endif
/* fill rs_buf with the keystream */
chacha_encrypt_bytes(&rng->rsx.rs_chacha, rng->rsx.rs_buf,
rng->rsx.rs_buf, sizeof(rng->rsx.rs_buf));
/* mix in optional user provided data */
if (dat) {
size_t i, m;
m = minimum(datlen, KEYSZ + IVSZ);
for (i = 0; i < m; i++)
rng->rsx.rs_buf[i] ^= dat[i];
}
/* immediately reinit for backtracking resistance */
_rs_init(rng, rng->rsx.rs_buf, KEYSZ + IVSZ);
memset(rng->rsx.rs_buf, 0, KEYSZ + IVSZ);
rng->rs.rs_have = sizeof(rng->rsx.rs_buf) - KEYSZ - IVSZ;
}
static void
_rs_stir(struct _rng *rng)
{
u_char rnd[KEYSZ + IVSZ];
uint32_t rekey_fuzz = 0;
if (getentropy(rnd, sizeof rnd) == -1)
notpossible;
if (!rng->once) {
_rs_init(rng, rnd, sizeof(rnd));
} else {
_rs_rekey(rng, rnd, sizeof(rnd));
}
explicit_bzero(rnd, sizeof(rnd)); /* discard source seed */
/* invalidate rs_buf */
rng->rs.rs_have = 0;
memset(rng->rsx.rs_buf, 0, sizeof(rng->rsx.rs_buf));
/* rekey interval should not be predictable */
chacha_encrypt_bytes(&rng->rsx.rs_chacha, (uint8_t *)&rekey_fuzz,
(uint8_t *)&rekey_fuzz, sizeof(rekey_fuzz));
rng->rs.rs_count = REKEY_BASE + (rekey_fuzz % REKEY_BASE);
}
static inline void
_rs_stir_if_needed(struct _rng *rng, size_t len)
{
if (!rng->once || rng->rs.rs_count <= len)
_rs_stir(rng);
if (rng->rs.rs_count <= len)
rng->rs.rs_count = 0;
else
rng->rs.rs_count -= len;
}
static inline void
_rs_random_buf(struct _rng *rng, void *_buf, size_t n)
{
u_char *buf = (u_char *)_buf;
u_char *keystream;
size_t m;
_rs_stir_if_needed(rng, n);
while (n > 0) {
if (rng->rs.rs_have > 0) {
m = minimum(n, rng->rs.rs_have);
keystream = rng->rsx.rs_buf + sizeof(rng->rsx.rs_buf)
- rng->rs.rs_have;
memcpy(buf, keystream, m);
memset(keystream, 0, m);
buf += m;
n -= m;
rng->rs.rs_have -= m;
}
if (rng->rs.rs_have == 0)
_rs_rekey(rng, NULL, 0);
}
}
/**
* Fills buffer with random data.
*
* This is the best random number generator provided by cosmo libc.
*
* This RNG is simple. Unlike getrandom() which can fail in numerous
* ways, this API always succeeds and returns the full number of bytes.
*
* This RNG is cryptographic grade. It uses D.J. Bernstein's ChaCha
* algorithm. The code for this implementation was originally copied
* from the OpenBSD and FreeBSD codebases.
*
* This RNG is fast. arc4random runs in userspace and occasionally
* reseeds itself using getentropy(). This gives you a 10x performance
* boost by avoiding costly system calls.
*
* This RNG is scalable. The Cosmopolitan Libc authors have modified the
* original OpenBSD source code so it doesn't use a GIL. We instead load
* balance threads across a fixed number of arc4random states which are
* indexed based on the current cpu if possible otherwise the thread id.
* This way threads needn't wait in sequence and can work concurrently.
* The only other fast cryptographic userspace PRNG we've seen that can
* do this is Microsoft's ProcessPrng() in Windows 10+.
*
* This RNG makes the single-threaded case go fast. Similar to FreeBSD
* our integration with the C library enables us to know when it's safe
* to avoid mutexes entirely. If your app never creates a thread, then
* arc4random() will never need to pay the cost of locks.
*
* This RNG is fork() safe. Naive random number generators oftentimes
* have an issue where forked child processes are likely to generate the
* same numbers as the parent. Our libc system call wrapper ensures the
* RNG state is appropriately wiped. However if you talk directly to the
* kernel, using functions like sys_fork(), you're on your own. vfork()
* should be safe, since the child process is actually just a thread.
*/
void
arc4random_buf(void *buf, size_t n)
{
size_t i, w;
struct _rng *rng;
FORBIDDEN_IN_POSIX_SPAWN;
/* load balance threads across fixed number of shards */
rng = &_rs_state[cosmo_shard()];
/* avoid one thread hogging shard */
for (i = 0; i < n; i += w) {
w = n - i;
if (w > FAIR_SHARE)
w = FAIR_SHARE;
if (__isthreaded >= 2)
pthread_mutex_lock(&rng->mtx);
_rs_random_buf(rng, (char *)buf + i, w);
if (__isthreaded >= 2)
pthread_mutex_unlock(&rng->mtx);
}
}
/**
* Returns single random 32-bit value.
*
* The arc4random() function returns pseudo-random numbers in the range
* of 0 to (2**32)−1, and has twice the range of rand(3) and random(3).
*
* This function is a wrapper around arc4random_buf() which can be used
* to obtain an arbitrary number of bytes.
*
* Be careful about using the euclidean remainder operator (`%`) on the
* result of this function. It's only safe to do that if you keep the
* result unsigned and the denominator is a two power. What you almost
* certainly want instead is arc4random_uniform() to do safe modulus.
*/
uint32_t
arc4random(void)
{
uint32_t val;
arc4random_buf(&val, sizeof(val));
return val;
}
/**
* Returns random number less than `upper_bound`.
*
* This is like arc4random() except the arc4random_uniform() function
* will calculate a uniformly distributed random number that's less than
* `upper_bound` while avoiding "modulo bias".
*
* This implementation uses the optimized technique discovered by Daniel
* Lemire in his paper "Fast Random Integer Generation in an Interval",
* Association for Computing Machinery, ACM Trans. Model. Comput.
* Simul., no. 1, vol. 29, pp. 1--12, New York, NY, USA, January 2019.
* Available: https://r-libre.teluq.ca/1437/1/rangedrng.pdf
*/
uint32_t
arc4random_uniform(uint32_t upper_bound)
{
uint64_t product;
/*
* The paper uses these variable names:
*
* L -- log2(UINT32_MAX+1)
* s -- upper_bound
* x -- arc4random() return value
* m -- product
* l -- (uint32_t)product
* t -- threshold
*/
if (upper_bound <= 1)
return 0;
product = upper_bound * (uint64_t)arc4random();
if ((uint32_t)product < upper_bound) {
uint32_t threshold;
/* threshold = (2**32 - upper_bound) % upper_bound */
threshold = -upper_bound % upper_bound;
while ((uint32_t)product < threshold)
product = upper_bound * (uint64_t)arc4random();
}
return product >> 32;
}
+4 -2
View File
@@ -22,6 +22,7 @@
#include "libc/errno.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/describebacktrace.h"
#include "libc/log/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.internal.h"
@@ -32,8 +33,9 @@ void __assert_fail(const char *expr, const char *file, int line) {
char ibuf[12];
sigset_t m = __sig_block();
FormatInt32(ibuf, line);
tinyprint(2, file, ":", ibuf, ": \e[31;1massert(", expr,
") failed\e[0m (cosmoaddr2line ", FindDebugBinary(), " ",
tinyprint(2, file, ":", ibuf, ": ", __nocolor ? "" : "\e[31;1m", "assert(",
expr, ") failed", __nocolor ? "" : "\e[0m", " (cosmoaddr2line ",
FindDebugBinary(), " ",
DescribeBacktrace(__builtin_frame_address(0)), ")\n", NULL);
__sig_unblock(m);
abort();
+24 -47
View File
@@ -42,28 +42,15 @@
#define MAP_FAILED ((void *)-1)
#define WTERMSIG(x) (127 & (x))
#define WCOREDUMP(x) (128 & (x))
#define WIFEXITED(x) (!WTERMSIG(x))
#define WEXITSTATUS(x) ((x) >> 8)
#define WSTOPSIG(x) ((0xff00 & (x)) >> 8)
#define WIFSTOPPED(x) __wifstopped(x)
#define WIFSIGNALED(x) __wifsignaled(x)
#define WIFCONTINUED(x) __wifcontinued(x)
#define W_STOPCODE(x) ((x) << 8 | 0177)
#ifdef _COSMO_SOURCE
#define clone __clone
#define commandv __commandv
#define fileexists __fileexists
#define ischardev __ischardev
#define isdirectory __isdirectory
#define isexecutable __isexecutable
#define isregularfile __isregularfile
#define issymlink __issymlink
#define makedirs __makedirs
#define tmpfd __tmpfd
#endif
#define WEXITSTATUS(s) ((s) >> 8)
#define WTERMSIG(s) ((s) & 0x7f)
#define WSTOPSIG(s) (((s) & 0xff00) >> 8)
#define WIFEXITED(s) (!WTERMSIG(s))
#define WIFSTOPPED(s) (((s) & 0xff) == 0x7f)
#define WIFSIGNALED(s) (((signed char)(((s) & 0x7f) + 1) >> 1) > 0)
#define WCOREDUMP(s) ((s) & 0x80)
#define WIFCONTINUED(s) (((s) & 0xffff) == 0xffff)
#define W_STOPCODE(s) ((s) << 8 | 0x7f)
COSMOPOLITAN_C_START_
/*───────────────────────────────────────────────────────────────────────────│─╗
@@ -83,8 +70,6 @@ int chmod(const char *, unsigned) libcesque __read_only(1);
int chown(const char *, unsigned, unsigned) libcesque __read_only(1);
int chroot(const char *) libcesque __read_only(1);
int close(int) libcesque;
int close_range(unsigned, unsigned, unsigned) libcesque;
int closefrom(int) libcesque;
int creat(const char *, unsigned) libcesque __read_only(1);
int dup(int) libcesque;
int dup2(int, int) libcesque;
@@ -101,7 +86,6 @@ int fchmod(int, unsigned) libcesque;
int fchmodat(int, const char *, unsigned, int) libcesque __read_only(2);
int fchown(int, unsigned, unsigned) libcesque;
int fchownat(int, const char *, unsigned, unsigned, int) libcesque __read_only(2);
int fcntl(int, int, ...) libcesque;
int fdatasync(int) libcesque;
int fexecve(int, char *const[], char *const[]) libcesque __read_only(2) __read_only(3);
int flock(int, int) libcesque;
@@ -171,7 +155,7 @@ int ttyname_r(int, char *, size_t) libcesque __write_only(2, 3);
int unlink(const char *) libcesque __read_only(1);
int unlinkat(int, const char *, int) libcesque __read_only(2);
int usleep(uint64_t) libcesque;
int vfork(void) libcesque returnstwice;
int vfork(void) dontthrow returnstwice;
int wait(int *) libcesque __write_only(1);
int waitpid(int, int *, int) libcesque __write_only(2);
int64_t clock(void) libcesque;
@@ -194,6 +178,11 @@ unsigned ualarm(unsigned, unsigned) libcesque;
unsigned umask(unsigned) libcesque;
void sync(void) libcesque;
#if defined(_COSMO_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
int madvise(void *, size_t, int);
void closefrom(int) libcesque;
#endif
#if defined(_COSMO_SOURCE) || defined(_GNU_SOURCE)
int syncfs(int) libcesque;
int prctl(int, ...) libcesque;
@@ -204,26 +193,21 @@ int getresgid(unsigned *, unsigned *, unsigned *) libcesque __write_only(1) __wr
int getresuid(unsigned *, unsigned *, unsigned *) libcesque __write_only(1) __write_only(2) __write_only(3);
char *get_current_dir_name(void) libcesque __wur;
ssize_t splice(int, int64_t *, int, int64_t *, size_t, unsigned) libcesque __read_write(2) __read_write(4);
int memfd_create(const char *, unsigned int) libcesque __read_only(1);
int execvpe(const char *, char *const[], char *const[]) libcesque __read_only(1) __read_only(2) __read_only(3);
int euidaccess(const char *, int) libcesque __read_only(1);
int eaccess(const char *, int) libcesque __read_only(1);
int madvise(void *, uint64_t, int) libcesque __read_write(1);
int getcpu(unsigned *, unsigned *) libcesque __write_only(1) __write_only(2);
int close_range(unsigned, unsigned, unsigned) libcesque;
#endif
#ifdef _COSMO_SOURCE
bool32 fdexists(int) libcesque;
bool32 fileexists(const char *) libcesque __read_only(1);
bool32 ischardev(int) libcesque;
bool32 isdirectory(const char *) libcesque __read_only(1);
bool32 isexecutable(const char *) libcesque __read_only(1);
bool32 isregularfile(const char *) libcesque __read_only(1);
bool32 issymlink(const char *) libcesque __read_only(1);
#if defined(_COSMO_SOURCE) || defined(_BSD_SOURCE)
#define commandv __commandv
#define copyfd __copyfd
#define makedirs __makedirs
#define tmpfd __tmpfd
char *commandv(const char *, char *, size_t) libcesque __read_only(1) __write_only(2, 3);
int __getcwd(char *, size_t) libcesque __write_only(1, 2);
int clone(void *, void *, size_t, int, void *, void *, void *, void *);
int fadvise(int, uint64_t, uint64_t, int) libcesque;
int __clone(void *, void *, size_t, int, void *, void *, void *, void *);
int __getcwd(char *, size_t) libcesque;
int makedirs(const char *, unsigned) libcesque __read_only(1);
int pivot_root(const char *, const char *) libcesque __read_only(1) __read_only(2);
int pledge(const char *, const char *) libcesque __read_only(1) __read_only(2);
@@ -237,26 +221,19 @@ int sys_mlockall(int) libcesque;
int sys_munlock(const void *, size_t) libcesque __read_only(1);
int sys_munlockall(void) libcesque;
int sys_personality(uint64_t) libcesque;
int sys_ptrace(int, ...) libcesque;
int sysctl(int *, unsigned, void *, size_t *, void *, size_t) libcesque __read_write(1) __read_write(4) __read_write(5);
int sysctlbyname(const char *, void *, size_t *, void *, size_t) libcesque __read_only(1) __write_only(2) __read_write(3) __read_only(4);
int sysctlnametomib(const char *, int *, size_t *) libcesque __read_only(1) __write_only(2) __read_write(3);
int tmpfd(void) libcesque;
int touch(const char *, unsigned) libcesque __read_only(1);
int unveil(const char *, const char *) libcesque __read_only(1);
long ptrace(int, ...) libcesque;
ssize_t copyfd(int, int, size_t) libcesque;
ssize_t readansi(int, char *, size_t) libcesque;
ssize_t tinyprint(int, const char *, ...) libcesque nullterminated();
void shm_path_np(const char *, char[hasatleast 78]) libcesque;
#endif /* _COSMO_SOURCE */
#endif
int system(const char *) libcesque;
int __wifstopped(int) libcesque pureconst;
int __wifcontinued(int) libcesque pureconst;
int __wifsignaled(int) libcesque pureconst;
#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
#define lseek64 lseek
#define pread64 pread
+40 -37
View File
@@ -16,48 +16,53 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/errno.h"
#include "libc/limits.h"
#include "libc/nt/errors.h"
#include "libc/nt/files.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/sysv/errfuns.h"
#include "libc/sysv/errno.h"
textwindows int sys_chdir_nt_impl(char16_t path[hasatleast PATH_MAX],
uint32_t len) {
uint32_t n;
char16_t var[4];
if (len && path[len - 1] != u'\\') {
if (len + 2 > PATH_MAX)
return enametoolong();
path[len + 0] = u'\\';
path[len + 1] = u'\0';
}
if (SetCurrentDirectory(path)) {
/*
* Now we need to set a magic environment variable.
*/
if ((n = GetCurrentDirectory(PATH_MAX, path))) {
if (n < PATH_MAX) {
if (!((path[0] == '/' && path[1] == '/') ||
(path[0] == '\\' && path[1] == '\\'))) {
var[0] = '=';
var[1] = path[0];
var[2] = ':';
var[3] = 0;
if (!SetEnvironmentVariable(var, path))
return __winerr();
}
return 0;
textwindows int sys_chdir_nt16(char16_t path[hasatleast PATH_MAX],
uint32_t len) {
// the win32 SetCurrentDirectory() API wants us to put back a trailing
// slash that was removed earlier, when __mkntpath() normalized things
if (len + 2 > PATH_MAX)
return enametoolong();
if (SetCurrentDirectory(path))
return 0;
// remap win32 error codes to unix
uint32_t dwErrorCode;
switch ((dwErrorCode = GetLastError())) {
case kNtErrorFileNotFound: // 2 a.k.a. ENOENT
// it does this when the parent components exist but file didn't
errno = ENOENT;
break;
case kNtErrorPathNotFound: // 3 a.k.a. ENOTDIR
// with Windows, this means that the file doesn't exist, because
// a parent component didn't exist. however unix still considers
// that to be an ENOENT error. on UNIX this only becomes ENOTDIR
// if a parent component DID exist, but was not a real directory
if (__hasregularparent(path)) {
errno = ENOTDIR;
} else {
return enametoolong();
errno = ENOENT;
}
} else {
return __winerr();
}
} else {
return __fix_enotdir(__winerr(), path);
break;
case kNtErrorDirectory: // 267 a.k.a. EISDIR
// it'll do this when try to chdir to a regular file that exists
// it could also be an ELOOP error although not worth supporting
errno = ENOTDIR;
break;
default:
errno = __errno_windows2linux(dwErrorCode);
break;
}
return -1;
}
textwindows int sys_chdir_nt(const char *path) {
@@ -65,7 +70,5 @@ textwindows int sys_chdir_nt(const char *path) {
char16_t path16[PATH_MAX];
if ((len = __mkntpath(path, path16)) == -1)
return -1;
if (!len)
return enoent();
return sys_chdir_nt_impl(path16, len);
return sys_chdir_nt16(path16, len);
}
+11 -8
View File
@@ -20,6 +20,7 @@
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/strace.h"
#include "libc/intrin/weaken.h"
#include "libc/log/log.h"
@@ -33,14 +34,19 @@
* The current directory is shared by all threads in a process. This
* does not update the `PWD` environment variable.
*
* On Windows it's important to consider that when you chdir() into a
* directory, any attempt to rmdir() that directory will raise EACCES.
*
* @return 0 on success, or -1 w/ errno
* @raise ELOOP if a loop was detected resolving components of `path`
* @raise EACCES if search permission was denied on directory
* @raise ENOTDIR if component of `path` isn't a directory
* @raise ENOTDIR if parent of `path` exists as non-directory
* @raise ENOTDIR if `path` is a regular file that exists
* @raise ENOMEM if insufficient memory was available
* @raise EFAULT if `path` points to invalid memory
* @raise ENOTSUP if `path` is a `/zip/...` file
* @raise ENAMETOOLONG if `path` was too long
* @raise ENOENT if `path` is empty string
* @raise ENOENT if `path` doesn't exist
* @raise EIO if an i/o error happened
* @asyncsignalsafe
@@ -49,16 +55,13 @@
int chdir(const char *path) {
int rc;
struct ZiposUri zipname;
if (_weaken(__get_tmpdir)) {
if (_weaken(__get_tmpdir))
_weaken(__get_tmpdir)();
}
if (_weaken(GetAddr2linePath)) {
if (_weaken(GetAddr2linePath))
_weaken(GetAddr2linePath)();
}
if (_weaken(GetProgramExecutableName)) {
if (_weaken(GetProgramExecutableName))
_weaken(GetProgramExecutableName)();
}
if (!path) {
if (kisdangerous(path)) {
rc = efault();
} else if (_weaken(__zipos_parseuri) &&
_weaken(__zipos_parseuri)(path, &zipname) != -1) {
+2 -1
View File
@@ -18,9 +18,10 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/dce.h"
#include "libc/intrin/weaken.h"
#include "libc/sysv/errfuns.h"
#ifdef __x86_64__
#if SupportsWindows()
textwindows int _check_signal(bool restartable) {
int status;
+2 -1
View File
@@ -19,6 +19,7 @@
#include "libc/calls/calls.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/strace.h"
#include "libc/sysv/errfuns.h"
@@ -48,7 +49,7 @@
*/
int chroot(const char *path) {
int rc;
if (!path) {
if (kisdangerous(path)) {
rc = efault();
} else {
rc = sys_chroot(path);
+1
View File
@@ -17,6 +17,7 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/struct/timespec.internal.h"
#include "libc/cosmotime.h"
#include "libc/dce.h"
#include "libc/intrin/describeflags.h"
#include "libc/intrin/strace.h"
+12 -23
View File
@@ -16,45 +16,29 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/atomic.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/cosmotime.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/atomic.h"
#include "libc/nt/enum/status.h"
#include "libc/nt/ntdll.h"
#include "libc/stdio/sysparam.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/consts/timer.h"
#include "libc/thread/tls.h"
#ifdef __x86_64__
static atomic_int usingRes;
static atomic_bool changedRes;
#include "libc/nt/thunk/msabi.h"
#include "libc/nt/winmm.h"
#if SupportsWindows()
static textwindows int sys_clock_nanosleep_nt_impl(int clock,
struct timespec abs,
sigset_t waitmask) {
struct timespec now, wall;
uint32_t minRes, maxRes, oldRes;
sys_clock_gettime_nt(0, &wall);
if (sys_clock_gettime_nt(clock, &now))
return -1;
bool wantRes = clock == CLOCK_REALTIME || //
clock == CLOCK_MONOTONIC || //
clock == CLOCK_BOOTTIME;
if (wantRes && !atomic_fetch_add(&usingRes, 1))
changedRes = NtSuccess(NtQueryTimerResolution(&minRes, &maxRes, &oldRes)) &&
NtSuccess(NtSetTimerResolution(maxRes, true, &oldRes));
if (timespec_cmp(abs, now) > 0)
wall = timespec_add(wall, timespec_sub(abs, now));
int rc = _park_norestart(wall, waitmask);
if (wantRes && atomic_fetch_sub(&usingRes, 1) == 1 && changedRes)
NtSetTimerResolution(0, false, &minRes);
return rc;
return _park_norestart(wall, waitmask);
}
textwindows int sys_clock_nanosleep_nt(int clock, int flags,
@@ -82,4 +66,9 @@ BailOut:
return rc;
}
// called by WinMain() if clock_nanosleep() is linked
__msabi textwindows dontinstrument void sys_clock_nanosleep_nt_init(void) {
__imp_timeBeginPeriod(1); // make sleep(1ms) not take 15ms
}
#endif /* __x86_64__ */
+1
View File
@@ -19,6 +19,7 @@
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/cosmotime.h"
#include "libc/errno.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/errfuns.h"
-3
View File
@@ -54,8 +54,5 @@ int sys_clock_nanosleep(int clock, int flags, //
rc = ecanceled();
}
END_CANCELATION_POINT;
STRACE("sys_clock_nanosleep(%s, %s, %s, [%s]) → %d% m",
DescribeClockName(clock), DescribeSleepFlags(flags),
DescribeTimespec(0, req), DescribeTimespec(rc, rem), rc);
return rc;
}
+1
View File
@@ -21,6 +21,7 @@
#include "libc/calls/struct/timespec.internal.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/cosmotime.h"
#include "libc/errno.h"
#include "libc/intrin/weaken.h"
#include "libc/runtime/syslib.internal.h"
+8
View File
@@ -17,11 +17,16 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/describeflags.h"
#include "libc/intrin/strace.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/consts/timer.h"
int sys_clock_nanosleep(int, int, const struct timespec *, struct timespec *);
/**
* Sleeps for particular amount of time.
*
@@ -99,5 +104,8 @@ errno_t clock_nanosleep(int clock, int flags, //
rc = sys_clock_nanosleep(clock, flags, req, rem);
err = !rc ? 0 : errno;
errno = old;
STRACE("clock_nanosleep(%s, %s, %s, [%s]) → %s", DescribeClockName(clock),
DescribeSleepFlags(flags), DescribeTimespec(0, req),
DescribeTimespec(rc, rem), DescribeErrno(err));
return err;
}
+1 -2
View File
@@ -16,10 +16,9 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/struct/timeval.internal.h"
#include "libc/cosmotime.h"
#include "libc/dce.h"
#include "libc/intrin/describeflags.h"
#include "libc/intrin/strace.h"
+74 -42
View File
@@ -16,54 +16,100 @@
│ 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/flocks.h"
#include "libc/calls/internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/fds.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/strace.h"
#include "libc/intrin/weaken.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/zipos.internal.h"
#include "libc/sock/syscall_fd.internal.h"
#include "libc/sysv/errfuns.h"
// for performance reasons we want to avoid holding __fds_lock()
// while sys_close() is happening. this leaves the kernel / libc
// having a temporarily inconsistent state. routines that obtain
// file descriptors the way __zipos_open() does need to retry if
// there's indication this race condition happened.
#include "libc/sysv/pib.h"
static int close_impl(int fd) {
if (fd < 0) {
// handle obvious case
if (fd < 0)
return ebadf();
}
// give kprintf() the opportunity to dup() stderr
if (fd == 2 && _weaken(kloghandle)) {
if (fd == 2 && !__vforked && _weaken(kloghandle))
_weaken(kloghandle)();
}
if (__isfdkind(fd, kFdZip)) {
unassert(_weaken(__zipos_close));
return _weaken(__zipos_close)(fd);
}
if (!IsWindows() && !IsMetal()) {
// unix isn't required to track fds
if (fd >= __get_pib()->fds.n) {
if (IsWindows() || IsMetal())
return ebadf();
return sys_close(fd);
}
if (IsWindows()) {
return sys_close_nt(fd, fd);
// if we're vforked on unix then we can't even modify f->kind
if (__vforked && !(IsWindows() || IsMetal()))
return sys_close(fd);
// atomically close file descriptor table entry
int rc = 0;
struct Fd *f = __get_pib()->fds.p + fd;
switch (atomic_exchange(&f->kind, kFdReserved)) {
case kFdEmpty:
if (IsWindows() || IsMetal()) {
rc = ebadf();
} else {
rc = sys_close(fd);
}
break;
case kFdReserved:
return ebadf();
case kFdZip:
if (_weaken(__zipos_close))
rc = _weaken(__zipos_close)(fd);
break;
#if SupportsMetal()
case kFdSerial:
break;
#endif
#if SupportsWindows()
case kFdDevRandom:
break;
case kFdFile:
if (!__vforked)
if (_weaken(__flocks_close))
_weaken(__flocks_close)(f);
if (!__vforked || f->was_created_during_vfork) {
if (f->cursor)
__cursor_unref(f->cursor);
if (!CloseHandle(f->handle))
rc = __winerr();
}
break;
case kFdDevNull:
case kFdConsole:
if (!__vforked || f->was_created_during_vfork)
if (!CloseHandle(f->handle))
rc = __winerr();
break;
case kFdSocket:
if (!__vforked || f->was_created_during_vfork)
if (_weaken(sys_closesocket_nt))
rc = _weaken(sys_closesocket_nt)(f);
break;
#endif
default:
rc = ebadf();
break;
}
return 0;
// wipe fd and update lowest file descriptor number
// we do this even if there was an underlying os error
__releasefd(fd);
return rc;
}
/**
@@ -74,6 +120,8 @@ static int close_impl(int fd) {
* - openat()
* - socket()
* - accept()
* - pipe()
* - socketpair()
* - landlock_create_ruleset()
*
* This function should never be reattempted if an error is returned;
@@ -82,29 +130,13 @@ static int close_impl(int fd) {
*
* @return 0 on success, or -1 w/ errno
* @raise EINTR if signal was delivered; do *not* retry
* @raise EBADF if `fd` is negative or not open; however, an exception
* is made by Cosmopolitan Libc for `close(-1)` which returns zero
* and does nothing, in order to assist with code that may wish to
* close the same resource multiple times without dirtying `errno`
* @raise EBADF if `fd` is negative or not open
* @raise EIO if a low-level i/o error occurred
* @asyncsignalsafe
* @vforksafe
*/
int close(int fd) {
int rc;
if (__isfdkind(fd, kFdZip)) { // XXX IsWindows()?
BLOCK_SIGNALS;
__fds_lock();
rc = close_impl(fd);
if (!__vforked)
__releasefd(fd);
__fds_unlock();
ALLOW_SIGNALS;
} else {
rc = close_impl(fd);
if (!__vforked)
__releasefd(fd);
}
int rc = close_impl(fd);
STRACE("close(%d) → %d% m", fd, rc);
return rc;
}
+7 -12
View File
@@ -23,29 +23,24 @@
#include "libc/sysv/errfuns.h"
/**
* Closes inclusive range of file descriptors, e.g.
* Closes inclusive range of file descriptors.
*
* // close all non-stdio file descriptors
* if (close_range(3, -1, 0) == -1) {
* for (int i = 3; i < 256; ++i) {
* close(i);
* }
* }
* This system call is only supported on Linux 5.9+ and FreeBSD 13+.
* Consider using closefrom() which will work on all platforms.
*
* The following flags are available:
*
* - `CLOSE_RANGE_UNSHARE` (Linux-only)
* - `CLOSE_RANGE_CLOEXEC` (Linux-only)
* - `CLOSE_RANGE_CLOEXEC` to mark file descriptors as close-on-exec
* instead of actually closing them.
*
* This is only supported on Linux 5.9+ and FreeBSD 13+. Consider using
* closefrom() which will work on OpenBSD too.
* - `CLOSE_RANGE_UNSHARE` (Linux only) can improve performance in
* situations where threads are in play.
*
* @return 0 on success, or -1 w/ errno
* @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+ or FreeBSD 13+
* @error ENOMEM on Linux maybe
* @see closefrom()
*/
int close_range(unsigned int first, unsigned int last, unsigned int flags) {
int rc;
+36 -29
View File
@@ -18,47 +18,54 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/blockcancel.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/rlimit.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/strace.h"
#include "libc/limits.h"
#include "libc/sysv/errfuns.h"
#include "libc/sysv/pib.h"
/**
* Closes extra file descriptors, e.g.
* Closes extra file descriptors.
*
* if (closefrom(3))
* for (int i = 3; i < 256; ++i)
* close(i);
*
* @return 0 on success, or -1 w/ errno
* @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 EINTR possibly on OpenBSD
* @raise ENOMEM on Linux maybe
* This system call is always successful.
*/
int closefrom(int first) {
int rc;
void closefrom(int minfd) {
BLOCK_CANCELATION;
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);
// fix arg
if (minfd < 0)
minfd = 0;
// try syscall
int rc;
int olderr = errno;
if (IsFreebsd() || IsOpenbsd()) {
rc = sys_closefrom(minfd);
} else if (IsLinux()) {
rc = sys_close_range(first, 0xffffffffu, 0);
rc = sys_close_range(minfd, 0xffffffffu, 0);
} else if (IsNetbsd()) {
rc = __sys_fcntl(first, 10 /*F_CLOSEM*/, first);
rc = __sys_fcntl(minfd, 10 /*F_CLOSEM*/, minfd);
} else {
rc = enosys();
rc = -1;
}
// try polyfill
if (rc == -1) {
long maxfd = 1024;
if (IsWindows() || IsMetal()) {
maxfd = __get_pib()->fds.n;
} else {
struct rlimit rl;
if (!getrlimit(RLIMIT_NOFILE, &rl))
if (rl.rlim_cur <= 0x7fffffffu)
maxfd = rl.rlim_cur;
}
for (long fd = minfd; fd < maxfd; ++fd)
close(fd);
errno = olderr;
}
ALLOW_CANCELATION;
STRACE("closefrom(%d) → %d% m", first, rc);
return rc;
STRACE("closefrom(%d)", minfd);
}
+3 -1
View File
@@ -23,10 +23,12 @@
/**
* Creates file.
*
* This is equivalent to saying:
* This function is equivalent to:
*
* int fd = openat(AT_FDCWD, file, O_CREAT | O_WRONLY | O_TRUNC, mode);
*
* Please see openat() for further documentation.
*
* @param file specifies filesystem path to create
* @param mode is octal bits, e.g. 0644 usually
* @return file descriptor, or -1 w/ errno
+24 -49
View File
@@ -18,7 +18,6 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/createfileflags.internal.h"
#include "libc/nt/createfile.h"
#include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/creationdisposition.h"
@@ -33,19 +32,10 @@ textwindows int GetNtOpenFlags(int flags, int mode, uint32_t *out_perm,
bool is_creating_file;
uint32_t perm, share, disp, attr;
if (flags &
~(O_ACCMODE | _O_APPEND | _O_CREAT | _O_EXCL | _O_TRUNC | _O_DIRECTORY |
_O_UNLINK | _O_NONBLOCK | _O_RANDOM | _O_SEQUENTIAL | _O_COMPRESSED |
_O_INDEXED | _O_CLOEXEC | _O_DIRECT)) {
if (flags & ~(O_ACCMODE | O_APPEND | O_CREAT | O_EXCL | O_TRUNC | O_NOCTTY |
O_DIRECTORY | O_UNLINK | O_NONBLOCK | O_CLOEXEC | O_DIRECT |
_O_TMPFILE | O_DSYNC | O_LARGEFILE))
return einval();
}
// "Some of these flags should not be combined. For instance,
// combining kNtFileFlagRandomAccess with kNtFileFlagSequentialScan
// is self-defeating." -Quoth MSDN § CreateFileW
if ((flags & _O_SEQUENTIAL) && (flags & _O_RANDOM)) {
return einval();
}
switch (flags & O_ACCMODE) {
case O_RDONLY:
@@ -53,14 +43,13 @@ textwindows int GetNtOpenFlags(int flags, int mode, uint32_t *out_perm,
break;
case O_WRONLY:
perm = kNtFileGenericWrite;
if (flags & _O_APPEND) {
if (flags & O_APPEND)
// kNtFileAppendData is already present in kNtFileGenericWrite.
// WIN32 wont act on append access when write is already there.
perm = kNtFileAppendData;
}
break;
case O_RDWR:
if (flags & _O_APPEND) {
if (flags & O_APPEND) {
perm = kNtFileGenericRead | kNtFileAppendData;
} else {
perm = kNtFileGenericRead | kNtFileGenericWrite;
@@ -71,7 +60,7 @@ textwindows int GetNtOpenFlags(int flags, int mode, uint32_t *out_perm,
}
attr = 0;
is_creating_file = !!(flags & _O_CREAT);
is_creating_file = !!(flags & O_CREAT);
// POSIX O_EXEC doesn't mean the same thing as kNtGenericExecute. We
// request execute access when we can determine it from mode's bits.
@@ -79,12 +68,10 @@ textwindows int GetNtOpenFlags(int flags, int mode, uint32_t *out_perm,
// mmap() won't fail. If it causes CreateFile() to fail, our wrapper
// will try calling CreateFile a second time without execute access.
if (is_creating_file) {
if (mode & 0111) {
if (mode & 0100)
perm |= kNtGenericExecute;
}
if (~mode & 0200) {
if (~mode & 0200)
attr |= kNtFileAttributeReadonly; // not sure why anyone would
}
} else {
perm |= kNtGenericExecute;
}
@@ -96,37 +83,25 @@ textwindows int GetNtOpenFlags(int flags, int mode, uint32_t *out_perm,
share = kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete;
// These POSIX to WIN32 mappings are relatively straightforward.
if (flags & _O_EXCL) {
if (flags & O_EXCL) {
if (is_creating_file) {
disp = kNtCreateNew;
} else {
return einval();
}
} else if (is_creating_file) {
if (flags & _O_TRUNC) {
if (flags & O_TRUNC) {
disp = kNtCreateAlways;
} else {
disp = kNtOpenAlways;
}
} else if (flags & _O_TRUNC) {
} else if (flags & O_TRUNC) {
disp = kNtTruncateExisting;
} else {
disp = kNtOpenExisting;
}
if (~flags & _O_INDEXED) {
// The Windows content indexing service ravages performance similar to
// Windows Defender. Please pass O_INDEXED to openat() to enable this.
attr |= kNtFileAttributeNotContentIndexed;
}
if (flags & _O_COMPRESSED) {
// Windows' transparent filesystem compression is really cool, as such
// we've introduced a nonstandard O_COMPRESSED flag to help you use it
attr |= kNtFileAttributeCompressed;
}
if (flags & kNtFileAttributeTemporary) { // subset of _O_UNLINK
if (flags & _O_TMPFILE)
// "Specifying the kNtFileAttributeTemporary attribute causes file
// systems to avoid writing data back to mass storage if sufficient
// cache memory is available, because an application deletes a
@@ -139,29 +114,29 @@ textwindows int GetNtOpenFlags(int flags, int mode, uint32_t *out_perm,
// hold as much as possible in the system cache without writing and
// therefore may be of concern for certain applications." -MSDN
attr |= kNtFileAttributeTemporary;
}
if (!attr) {
if (!attr)
// "All other file attributes override kNtFileAttributeNormal [...]
// [which] is valid only if used alone." -Quoth MSDN § CreateFileW
attr |= kNtFileAttributeNormal;
}
attr |= flags & kNtFileFlagDeleteOnClose; // subset of _O_UNLINK
if (flags & O_UNLINK)
attr |= kNtFileFlagDeleteOnClose;
if (flags & _O_DIRECTORY) {
if (flags & O_DIRECTORY)
// "You must set this flag to obtain a handle to a directory."
// -Quoth MSDN § CreateFileW
attr |= kNtFileFlagBackupSemantics;
}
// Not certain yet what benefit these flags offer.
if (flags & _O_SEQUENTIAL)
attr |= kNtFileFlagSequentialScan;
if (flags & _O_RANDOM)
attr |= kNtFileFlagRandomAccess;
if (flags & _O_DIRECT)
// flags for slowing down performance
if (flags & O_DSYNC)
attr |= kNtFileFlagWriteThrough;
if (flags & O_DIRECT) {
if (flags & O_APPEND)
return einval();
attr |= kNtFileFlagNoBuffering;
perm &= ~kNtFileAppendData; // ∈ kNtFileGenericWrite
}
// TODO(jart): Should we *always* open with write permission if the
// kernel will give it to us? We'd then deny write access
-22
View File
@@ -1,22 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_CREATEFILEFLAGS_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_CREATEFILEFLAGS_INTERNAL_H_
// code size optimization
// <sync libc/sysv/consts.sh>
#define _O_APPEND 0x00000400 // kNtFileAppendData
#define _O_CREAT 0x00000040 // kNtOpenAlways
#define _O_EXCL 0x00000080 // kNtCreateNew
#define _O_TRUNC 0x00000200 // kNtCreateAlways
#define _O_DIRECTORY 0x00010000 // kNtFileFlagBackupSemantics
#define _O_UNLINK 0x04000100 // kNtFileAttributeTemporary|DeleteOnClose
#define _O_DIRECT 0x00004000 // kNtFileFlagNoBuffering
#define _O_NONBLOCK 0x00000800 // kNtFileFlagWriteThrough (not sent to win32)
#define _O_RANDOM 0x80000000 // kNtFileFlagRandomAccess
#define _O_SEQUENTIAL 0x40000000 // kNtFileFlagSequentialScan
#define _O_COMPRESSED 0x20000000 // kNtFileAttributeCompressed
#define _O_INDEXED 0x10000000 // !kNtFileAttributeNotContentIndexed
#define _O_NOFOLLOW 0x00020000 // kNtFileFlagOpenReparsePoint
#define _O_CLOEXEC 0x00080000
// </sync libc/sysv/consts.sh>
#endif /* COSMOPOLITAN_LIBC_CALLS_CREATEFILEFLAGS_INTERNAL_H_ */
+3 -2
View File
@@ -20,15 +20,16 @@
#include "libc/fmt/internal.h"
#include "libc/intrin/atomic.h"
#include "libc/runtime/internal.h"
#include "libc/sysv/pib.h"
// This function is called very early by WinMain().
textwindows char16_t *__create_pipe_name(char16_t *a) {
char16_t *p = a;
const char *q = "\\\\?\\pipe\\cosmo\\";
const char *q = "\\\\.\\pipe\\cosmo\\";
static atomic_uint x;
while (*q)
*p++ = *q++;
p = __itoa16(p, __pid);
p = __itoa16(p, __get_pib()->pid);
*p++ = '-';
p = __itoa16(p, atomic_fetch_add(&x, 1));
*p = 0;
+42 -30
View File
@@ -18,14 +18,13 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/createfileflags.internal.h"
#include "libc/calls/internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/rlimit.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/errno.h"
#include "libc/intrin/fds.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/weaken.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
@@ -34,63 +33,76 @@
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
#include "libc/sysv/pib.h"
// Implements dup(), dup2(), dup3(), and F_DUPFD for Windows.
static textwindows int sys_dup_nt_impl(int oldfd, int newfd, int flags,
textwindows static int sys_dup_nt_impl(int oldfd, int newfd, int flags,
int start) {
int64_t rc, handle;
int64_t handle;
unassert(!(flags & ~O_CLOEXEC));
// validate args
if (!__isfdopen(oldfd))
return ebadf();
__fds_lock();
if (!__isfdopen(oldfd) || newfd < -1) {
__fds_unlock();
return ebadf();
}
// allocate a new file descriptor
// determine new fd
bool reserved = false;
if (newfd == -1) {
if ((newfd = __reservefd_unlocked(start)) == -1) {
__fds_unlock();
return -1;
}
reserved = true;
} else {
if (newfd >= ~__get_pib()->rlimit[RLIMIT_NOFILE].rlim_cur) {
__fds_unlock();
return emfile();
}
if (__ensurefds_unlocked(newfd) == -1) {
__fds_unlock();
return -1;
}
if (g_fds.p[newfd].kind) {
sys_close_nt(newfd, newfd);
}
}
if (__isfdkind(oldfd, kFdZip)) {
handle = (intptr_t)_weaken(__zipos_keep)(
(struct ZiposHandle *)(intptr_t)g_fds.p[oldfd].handle);
rc = newfd;
(struct ZiposHandle *)(intptr_t)__get_pib()->fds.p[oldfd].handle);
} else {
if (DuplicateHandle(GetCurrentProcess(), g_fds.p[oldfd].handle,
GetCurrentProcess(), &handle, 0, true,
kNtDuplicateSameAccess)) {
rc = newfd;
} else {
rc = __winerr();
__releasefd(newfd);
if (!DuplicateHandle(GetCurrentProcess(), __get_pib()->fds.p[oldfd].handle,
GetCurrentProcess(), &handle, 0, true,
kNtDuplicateSameAccess)) {
if (reserved)
__releasefd(newfd);
__fds_unlock();
return rc;
return __winerr();
}
}
g_fds.p[newfd] = g_fds.p[oldfd];
g_fds.p[newfd].handle = handle;
__cursor_ref(g_fds.p[newfd].cursor);
if (flags & _O_CLOEXEC) {
g_fds.p[newfd].flags |= _O_CLOEXEC;
// close overwritten fd upon success
if (!reserved) {
if (__get_pib()->fds.p[newfd].kind) {
if (!__vforked || __get_pib()->fds.p[newfd].was_created_during_vfork) {
int e = errno;
close(newfd); // needs fds mutex to be recursive :(
errno = e;
}
}
}
// track fd to file descriptors table
__get_pib()->fds.p[newfd] = __get_pib()->fds.p[oldfd];
__get_pib()->fds.p[newfd].handle = handle;
__get_pib()->fds.p[newfd].was_created_during_vfork = __vforked;
__cursor_ref(__get_pib()->fds.p[newfd].cursor);
if (flags & O_CLOEXEC) {
__get_pib()->fds.p[newfd].flags |= O_CLOEXEC;
} else {
g_fds.p[newfd].flags &= ~_O_CLOEXEC;
__get_pib()->fds.p[newfd].flags &= ~O_CLOEXEC;
}
__fds_unlock();
return rc;
return newfd;
}
textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
+5 -5
View File
@@ -79,11 +79,11 @@ int dup2(int oldfd, int newfd) {
if (!IsWindows()) {
if (__isfdkind(oldfd, kFdZip) || __isfdkind(newfd, kFdZip)) {
if (__vforked) {
return enotsup();
}
rc = sys_dup2(oldfd, newfd, 0);
if (rc != -1) {
_weaken(__zipos_postdup)(oldfd, newfd);
rc = enotsup();
} else {
rc = sys_dup2(oldfd, newfd, 0);
if (rc != -1)
_weaken(__zipos_postdup)(oldfd, newfd);
}
} else {
rc = sys_dup2(oldfd, newfd, 0);
+20 -1
View File
@@ -61,7 +61,26 @@ int32_t sys_dup3(int32_t oldfd, int32_t newfd, int flags) {
cosmo_once(&g_dup3.once, sys_dup3_test);
if (!g_dup3.demodernize) {
return __sys_dup3(oldfd, newfd, flags);
int flags2;
if (IsLinux()) {
flags2 = flags;
} else {
flags2 = 0;
if (flags & O_CLOEXEC) {
if (IsXnu()) {
flags2 |= 0x01000000;
} else if (IsFreebsd()) {
flags2 |= 0x00100000;
} else if (IsOpenbsd()) {
flags2 |= 0x00010000;
} else if (IsNetbsd()) {
flags2 |= 0x00400000;
} else {
return einval();
}
}
}
return __sys_dup3(oldfd, newfd, flags2);
} else {
return __fixupnewfd(sys_dup2(oldfd, newfd, 0), flags);
}
+5 -5
View File
@@ -74,11 +74,11 @@ int dup3(int oldfd, int newfd, int flags) {
} else if (!IsWindows()) {
if (__isfdkind(oldfd, kFdZip) || __isfdkind(newfd, kFdZip)) {
if (__vforked) {
return enotsup();
}
rc = sys_dup3(oldfd, newfd, flags);
if (rc != -1) {
_weaken(__zipos_postdup)(oldfd, newfd);
rc = enotsup();
} else {
rc = sys_dup3(oldfd, newfd, flags);
if (rc != -1)
_weaken(__zipos_postdup)(oldfd, newfd);
}
} else {
rc = sys_dup3(oldfd, newfd, flags);
+137 -5
View File
@@ -16,15 +16,147 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/internal.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/limits.h"
#include "libc/nt/createfile.h"
#include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/creationdisposition.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/nt/enum/filesharemode.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/byhandlefileinformation.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/ok.h"
#include "libc/sysv/errfuns.h"
#include "libc/sysv/pib.h"
textwindows int sys_faccessat_nt(int dirfd, const char *path, int mode,
uint32_t flags) {
char16_t path16[PATH_MAX];
if (__mkntpathat(dirfd, path, 0, path16) == -1)
static int Atoi(const char *str) {
int c;
unsigned x = 0;
if (!*str)
return -1;
return __fix_enotdir(ntaccesscheck(path16, mode), path16);
while ((c = *str++)) {
if ('0' <= c && c <= '9') {
x *= 10;
x += c - '0';
} else {
return -1;
}
}
return x;
}
static int sys_faccessat_nt_dev(int amode, bool readable, bool writable) {
if (amode == F_OK)
return 0;
if (amode == X_OK)
return eacces();
if (amode == R_OK)
if (!readable)
return eacces();
if (amode == W_OK)
if (!writable)
return eacces();
return 0;
}
textwindows static int sys_faccessat_nt_impl(const char16_t *path16, int amode,
int flags) {
// create access mask
uint32_t dwDesiredAccess;
if (amode == F_OK) {
dwDesiredAccess = kNtFileReadAttributes;
} else {
// W or X implies R
dwDesiredAccess = kNtGenericRead;
if (amode & W_OK)
dwDesiredAccess |= kNtGenericWrite;
}
// open file
intptr_t hFile;
if ((hFile = CreateFile(
path16, dwDesiredAccess,
kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete, 0,
kNtOpenExisting,
kNtFileAttributeNormal | kNtFileFlagBackupSemantics |
((flags & AT_SYMLINK_NOFOLLOW) ? kNtFileFlagOpenReparsePoint
: 0),
0)) == -1)
return __winerr();
// check for write and execute access
int rc = 0;
if (amode & (W_OK | X_OK)) {
struct NtByHandleFileInformation wst;
if (!GetFileInformationByHandle(hFile, &wst))
rc = __winerr();
// handle read-only files
if (!rc)
if (amode & W_OK)
if (wst.dwFileAttributes & kNtFileAttributeReadonly)
rc = eacces();
// executables, directories, and symlinks are always executable
if (!rc)
if (amode & X_OK)
if (!(wst.dwFileAttributes & kNtFileAttributeReparsePoint) &&
!(wst.dwFileAttributes & kNtFileAttributeDirectory) &&
!IsWindowsExecutable(hFile, path16))
rc = eacces();
}
// close file
CloseHandle(hFile);
// return result
return rc;
}
textwindows int sys_faccessat_nt(int dirfd, const char *path, int amode,
int flags) {
// validate arguments
if (amode & ~(R_OK | W_OK | X_OK))
return einval();
if (flags & ~(AT_EACCESS | AT_SYMLINK_NOFOLLOW))
return einval();
// handle special files
if (startswith(path, "/dev/")) {
int fd;
if (!strcmp(path + 5, "tty")) {
return sys_faccessat_nt_dev(amode, true, true);
} else if (!strcmp(path + 5, "null")) {
return sys_faccessat_nt_dev(amode, true, true);
} else if (!strcmp(path + 5, "random") || !strcmp(path + 5, "urandom")) {
return sys_faccessat_nt_dev(amode, true, false);
} else if (!strcmp(path + 5, "stdin")) {
return sys_faccessat_nt_dev(amode, true, false);
} else if (!strcmp(path + 5, "stdout")) {
return sys_faccessat_nt_dev(amode, false, true);
} else if (!strcmp(path + 5, "stderr")) {
return sys_faccessat_nt_dev(amode, false, true);
} else if (startswith(path + 5, "fd/") && (fd = Atoi(path + 8)) != -1) {
return sys_faccessat_nt_dev(
amode, (__get_pib()->fds.p[fd].flags & O_ACCMODE) != O_WRONLY,
(__get_pib()->fds.p[fd].flags & O_ACCMODE) != O_RDONLY);
}
}
char16_t path16[PATH_MAX];
if (__mkntpathat(dirfd, path, path16) == -1)
return -1;
int rc;
BLOCK_SIGNALS;
rc = __fix_enotdir(sys_faccessat_nt_impl(path16, amode, flags), path16);
ALLOW_SIGNALS;
return rc;
}
+37 -5
View File
@@ -22,27 +22,57 @@
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/describeflags.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/strace.h"
#include "libc/intrin/weaken.h"
#include "libc/mem/alloca.h"
#include "libc/runtime/zipos.internal.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/ok.h"
#include "libc/sysv/errfuns.h"
#define DescribeAccessMode(amode) _DescribeAccessMode(alloca(13), amode)
static char *_DescribeAccessMode(char buf[13], int amode) {
switch (amode) {
case F_OK:
return "F_OK";
case R_OK:
return "R_OK";
case W_OK:
return "W_OK";
case X_OK:
return "X_OK";
case R_OK | W_OK:
return "R_OK|W_OK";
case R_OK | X_OK:
return "R_OK|X_OK";
case W_OK | X_OK:
return "W_OK|X_OK";
case R_OK | W_OK | X_OK:
return "R_OK|W_OK|X_OK";
default:
FormatOctal32(buf, amode, true);
return buf;
}
}
/**
* Checks if effective user can access path in particular ways.
*
* @param dirfd is normally AT_FDCWD but if it's an open directory and
* file is a relative path, then file is opened relative to dirfd
* @param path is a filename or directory
* @param amode can be `R_OK`, `W_OK`, `X_OK`, or `F_OK`
* @param amode can be `F_OK` or a mixture of `R_OK`, `W_OK`, and `X_OK`
* @param flags can have `AT_EACCESS` and/or `AT_SYMLINK_NOFOLLOW`
* @return 0 if ok, or -1 and sets errno
* @raise EINVAL if `amode` or `flags` had invalid values
* @raise EINVAL if `AT_SYMLINK_NOFOLLOW` is used on FreeBSD
* @raise EPERM if pledge() is in play without rpath promise
* @raise EACCES if access for requested `amode` would be denied
* @raise ENOTDIR if a directory component in `path` exists as non-directory
* @raise EILSEQ on Windows if `path` has bad utf-8 of control characters
* @raise ENOENT if component of `path` doesn't exist or `path` is empty
* @raise ENOTSUP if `path` is a zip file and `dirfd` isn't `AT_FDCWD`
* @note on Linux `flags` is only supported on Linux 5.8+
@@ -51,8 +81,10 @@
int faccessat(int dirfd, const char *path, int amode, int flags) {
int e, rc;
struct ZiposUri zipname;
if ((flags & ~(AT_SYMLINK_NOFOLLOW | AT_EACCESS)) ||
!(amode == F_OK || !(amode & ~(R_OK | W_OK | X_OK)))) {
if (kisdangerous(path)) {
rc = efault();
} else if ((flags & ~(AT_SYMLINK_NOFOLLOW | AT_EACCESS)) ||
!(amode == F_OK || !(amode & ~(R_OK | W_OK | X_OK)))) {
rc = einval();
} else if (__isfdkind(dirfd, kFdZip)) {
rc = enotsup();
@@ -73,7 +105,7 @@ int faccessat(int dirfd, const char *path, int amode, int flags) {
} else {
rc = sys_faccessat_nt(dirfd, path, amode, flags);
}
STRACE("faccessat(%s, %#s, %#o, %#x) → %d% m", DescribeDirfd(dirfd), path,
amode, flags, rc);
STRACE("faccessat(%s, %#s, %s, %#x) → %d% m", DescribeDirfd(dirfd), path,
DescribeAccessMode(amode), flags, rc);
return rc;
}
-69
View File
@@ -1,69 +0,0 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│ vi: set et 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/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/strace.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
int sys_fadvise_netbsd(int, int, int64_t, int64_t, int) asm("sys_fadvise");
/**
* Drops hints to O/S about intended I/O behavior.
*
* It makes a huge difference. For example, when copying a large file,
* it can stop the system from persisting GBs of useless memory content.
*
* @param len 0 means until end of file
* @param advice can be MADV_SEQUENTIAL, MADV_RANDOM, etc.
* @return 0 on success, or -1 w/ errno
* @raise EBADF if `fd` isn't a valid file descriptor
* @raise ESPIPE if `fd` refers to a pipe
* @raise EINVAL if `advice` was invalid
* @raise ENOSYS on XNU and OpenBSD
*/
int fadvise(int fd, uint64_t offset, uint64_t len, int advice) {
int rc;
if (IsLinux()) {
rc = sys_fadvise(fd, offset, len, advice);
} else if (IsFreebsd() || IsNetbsd()) {
if (IsFreebsd()) {
rc = sys_fadvise(fd, offset, len, advice);
} else {
rc = sys_fadvise_netbsd(fd, offset, offset, len, advice);
}
npassert(rc >= 0);
if (rc) {
errno = rc;
rc = -1;
}
} else if (IsWindows()) {
rc = sys_fadvise_nt(fd, offset, len, advice);
} else {
rc = enosys();
}
STRACE("fadvise(%d, %'lu, %'lu, %d) → %d% m", fd, offset, len, advice, rc);
return rc;
}
__weak_reference(fadvise, fadvise64);
+5 -3
View File
@@ -22,14 +22,16 @@
#include "libc/dce.h"
#include "libc/nt/files.h"
#include "libc/sysv/errfuns.h"
#include "libc/sysv/pib.h"
int sys_chdir_nt_impl(char16_t[hasatleast PATH_MAX], uint32_t);
int sys_chdir_nt16(char16_t[hasatleast PATH_MAX], uint32_t);
textwindows int sys_fchdir_nt(int dirfd) {
char16_t dir[PATH_MAX];
if (!__isfdkind(dirfd, kFdFile))
return ebadf();
return sys_chdir_nt_impl(
dir, GetFinalPathNameByHandle(g_fds.p[dirfd].handle, dir, ARRAYLEN(dir),
return sys_chdir_nt16(
dir, GetFinalPathNameByHandle(__get_pib()->fds.p[dirfd].handle, dir,
ARRAYLEN(dir),
kNtFileNameNormalized | kNtVolumeNameDos));
}
+35 -17
View File
@@ -17,43 +17,61 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/internal.h"
#include "libc/intrin/fds.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/intrin/fds.h"
#include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/nt/enum/fileinfobyhandleclass.h"
#include "libc/nt/files.h"
#include "libc/nt/struct/filebasicinfo.h"
#include "libc/sysv/errfuns.h"
#include "libc/sysv/pib.h"
textwindows int sys_fchmod_nt(int fd, uint32_t mode) {
// validate file descriptor
if (fd + 0u >= g_fds.n)
return ebadf();
if (g_fds.p[fd].kind == kFdEmpty)
return ebadf();
textwindows bool32 sys_fchmod_nt_handle(intptr_t handle, uint32_t mode) {
// get current information
struct NtFileBasicInfo fbi;
if (!GetFileInformationByHandleEx(g_fds.p[fd].handle, kNtFileBasicInfo, &fbi,
sizeof(fbi))) {
return __winerr();
}
if (!GetFileInformationByHandleEx(handle, kNtFileBasicInfo, &fbi,
sizeof(fbi)))
return false;
// change attributes
if (mode & 0222) {
if (mode & 0200) {
fbi.FileAttributes &= ~kNtFileAttributeReadonly;
} else {
fbi.FileAttributes |= kNtFileAttributeReadonly;
}
// set new attributes
if (!SetFileInformationByHandle(g_fds.p[fd].handle, kNtFileBasicInfo, &fbi,
sizeof(fbi))) {
return __winerr();
}
if (!SetFileInformationByHandle(handle, kNtFileBasicInfo, &fbi, sizeof(fbi)))
return false;
// on unix saying `chmod -w dir` prevents writing files in that dir.
// however on windows, setting kNtFileAttributeReadonly on a directory
// doesn't prevent us from creating files within that directory. so we
// need to do something special to make the expected behavior happen.
unsigned dwDenyMask = 0;
if (fbi.FileAttributes & kNtFileAttributeDirectory)
if (fbi.FileAttributes & kNtFileAttributeReadonly)
dwDenyMask |=
kNtFileAddFile | kNtFileAddSubdirectory | kNtFileDeleteChild;
if (~mode & 0400)
dwDenyMask |= kNtFileReadData;
if (!RestrictFileWin32(handle, 0))
return false;
if (dwDenyMask)
if (!RestrictFileWin32(handle, dwDenyMask))
return false;
// all good
return true;
}
textwindows int sys_fchmod_nt(int fd, uint32_t mode) {
if (!__isfdkind(fd, kFdFile))
return ebadf();
if (!sys_fchmod_nt_handle(__get_pib()->fds.p[fd].handle, mode))
return __winerr();
return 0;
}
+1 -1
View File
@@ -59,7 +59,7 @@ int sys_fchmodat_linux(int fd, const char *path, unsigned mode, int flag) {
return -1;
if (S_ISLNK(st.st_mode))
return eopnotsupp();
if ((fd2 = sys_openat(fd, path, (O_RDONLY | O_PATH | O_NOFOLLOW |
if ((fd2 = sys_openat(fd, path, (O_RDONLY | _O_PATH | O_NOFOLLOW |
O_NOCTTY | O_CLOEXEC), 0)) < 0) {
if (fd2 == -ELOOP)
return eopnotsupp();
+34 -12
View File
@@ -18,25 +18,47 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/limits.h"
#include "libc/nt/createfile.h"
#include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/creationdisposition.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/nt/enum/filesharemode.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
textwindows int sys_fchmodat_nt(int dirfd, const char *path, uint32_t mode,
int flags) {
uint32_t attr;
if (flags & ~AT_SYMLINK_NOFOLLOW)
return einval();
// translate path
uint16_t path16[PATH_MAX];
if (__mkntpathat(dirfd, path, 0, path16) == -1)
if (__mkntpathat(dirfd, path, path16) == -1)
return -1;
if ((attr = GetFileAttributes(path16)) != -1u) {
if (mode & 0222) {
attr &= ~kNtFileAttributeReadonly;
} else {
attr |= kNtFileAttributeReadonly;
}
if (SetFileAttributes(path16, attr)) {
return 0;
}
// open file
intptr_t hFile;
if ((hFile = CreateFile(
path16,
kNtFileReadAttributes | kNtFileWriteAttributes | kNtReadControl |
kNtWriteDac,
kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete, 0,
kNtOpenExisting,
kNtFileAttributeNormal | kNtFileFlagBackupSemantics |
((flags & AT_SYMLINK_NOFOLLOW) ? kNtFileFlagOpenReparsePoint
: 0),
0)) == -1)
return __winerr();
if (!sys_fchmod_nt_handle(hFile, mode)) {
CloseHandle(hFile);
return __winerr();
}
return __winerr();
CloseHandle(hFile);
return 0;
}
+23 -4
View File
@@ -23,6 +23,7 @@
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/describeflags.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/strace.h"
#include "libc/intrin/weaken.h"
#include "libc/runtime/zipos.internal.h"
@@ -43,15 +44,33 @@ int sys_fchmodat2(int, const char *, unsigned, int);
* @param flags can have `AT_SYMLINK_NOFOLLOW`
* @raise EROFS if `dirfd` or `path` use zip file system
* @raise EOPNOTSUP on Linux if `path` is a symbolic link, `AT_SYMLINK_NOFOLLOW`
* is set in `flags`, and filesystem does not support setting the mode of
* symbolic links.
* @errors ENOENT, ENOTDIR, ENOSYS
* is set in `flags`, and filesystem does not support setting the mode of
* symbolic links.
* @raise EACCES if denied access to component in path prefix
* @raise EIO if i/o error occurred while reading from filesystem
* @raise ELOOP if a symbolic link loop exists in `path`
* @raise ENAMETOOLONG if a component in `path` exceeds `NAME_MAX`
* @raise EPERM if geteuid() doesn't match owner of file and not root
* @raise ENOENT on empty string or if component in path doesn't exist
* @raise ENOTDIR if a parent component existed that wasn't a directory
* @raise ENOTDIR if `path` is relative and `dirfd` isn't an open directory
* @raise ENOMEM if insufficient memory was available to the implementation
* @raise EILSEQ on Windows if `path` has bad utf-8 of control characters
* @raise EROFS if `path` points to the `/zip/...` synthetic filesystem
* @raise ELOOP may ahappen if `SYMLOOP_MAX` symlinks were dereferenced
* @raise ENAMETOOLONG if resolved `path` exceeded `PATH_MAX`
* @raise EROFS if `path` resides on a real-only filesystem
* @raise EFAULT if `path` points to invalid memory
* @raise EINVAL if `flags` has unsupported bits
* @asyncsignalsafe
* @see fchmod()
*/
int fchmodat(int dirfd, const char *path, uint32_t mode, int flags) {
int rc;
if (_weaken(__zipos_notat) && (rc = __zipos_notat(dirfd, path)) == -1) {
if (kisdangerous(path)) {
rc = efault();
} else if (_weaken(__zipos_notat) &&
(rc = __zipos_notat(dirfd, path)) == -1) {
rc = erofs();
} else if (!IsWindows()) {
if (IsLinux() && flags) {
Loaded 100 of 2897 files, more files were not shown because too many files have changed in this diff. Show more