Compare commits

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

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

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

- SOL_SOCKET + SO_BROADCAST
- IPPROTO_IPV6 + IPV6_V6ONLY

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

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

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

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

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

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

No files matched your search

-2
View File
@@ -4,12 +4,10 @@ on:
push:
branches:
- "master"
- "vista"
- "flake"
pull_request:
branches:
- "master"
- "vista"
# run workflow manually from the Actions tab
workflow_dispatch:
+93 -82
View File
@@ -61,13 +61,19 @@
SHELL = build/bootstrap/cocmd.com
HOSTS ?= freebsd openbsd netbsd rhel7 rhel5 win10 xnu
MAKEFLAGS += --no-builtin-rules
MAKEFLAGS += -j --no-builtin-rules
.SUFFIXES:
.DELETE_ON_ERROR:
.FEATURES: output-sync
.PHONY: all o bins check test depend tags
ifneq ($(m),)
ifeq ($(MODE),)
MODE := $(m)
endif
endif
all: o
o: o/$(MODE)
@@ -88,7 +94,7 @@ o/$(MODE): \
libc/disclaimer.inc \
rx:build/bootstrap \
rx:o/third_party/gcc \
/proc/self/status \
/proc/stat \
rw:/dev/null \
w:o/stack.log \
/etc/hosts \
@@ -128,6 +134,7 @@ include libc/mem/mem.mk #─┐
include libc/zipos/zipos.mk # ├──DYNAMIC RUNTIME
include third_party/gdtoa/gdtoa.mk # │ You can now use stdio
include libc/time/time.mk # │ You can finally call malloc()
include third_party/nsync/mem/mem.mk # │
include libc/thread/thread.mk # │
include libc/stdio/stdio.mk # │
include third_party/libcxx/libcxx.mk # │
@@ -265,98 +272,102 @@ o/$(MODE)/srcs-old.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(SRCS
o/$(MODE)/hdrs-old.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS) $(INCS),$(dir $(x))))
$(file >$@) $(foreach x,$(HDRS) $(INCS),$(file >>$@,$(x)))
TAGS: .UNSANDBOXED = 1
TAGS: private .UNSANDBOXED = 1
TAGS: o/$(MODE)/srcs-old.txt $(SRCS)
@$(RM) $@
@$(TAGS) $(TAGSFLAGS) -L $< -o $@
HTAGS: .UNSANDBOXED = 1
HTAGS: private .UNSANDBOXED = 1
HTAGS: o/$(MODE)/hdrs-old.txt $(HDRS)
@$(RM) $@
@build/htags -L $< -o $@
loc: .UNSANDBOXED = 1
loc: private .UNSANDBOXED = 1
loc: o/$(MODE)/tool/build/summy.com
find -name \*.h -or -name \*.c -or -name \*.S | \
$(XARGS) wc -l | grep total | awk '{print $$1}' | $<
COSMOPOLITAN_OBJECTS = \
NET_HTTP \
LIBC_DNS \
LIBC_SOCK \
LIBC_NT_WS2_32 \
LIBC_NT_IPHLPAPI \
LIBC_NT_MSWSOCK \
LIBC_X \
THIRD_PARTY_GETOPT \
LIBC_LOG \
LIBC_TIME \
LIBC_ZIPOS \
THIRD_PARTY_ZLIB \
THIRD_PARTY_MUSL \
LIBC_STDIO \
THIRD_PARTY_GDTOA \
THIRD_PARTY_REGEX \
LIBC_MEM \
THIRD_PARTY_DLMALLOC \
LIBC_RUNTIME \
THIRD_PARTY_NSYNC \
LIBC_ELF \
LIBC_CALLS \
LIBC_SYSV_CALLS \
LIBC_NT_PSAPI \
LIBC_NT_POWRPROF \
LIBC_NT_PDH \
LIBC_NT_GDI32 \
LIBC_NT_COMDLG32 \
LIBC_NT_URL \
LIBC_NT_USER32 \
LIBC_NT_NTDLL \
LIBC_NT_ADVAPI32 \
LIBC_FMT \
THIRD_PARTY_COMPILER_RT \
LIBC_THREAD \
LIBC_TINYMATH \
THIRD_PARTY_XED \
LIBC_STR \
LIBC_SYSV \
LIBC_INTRIN \
LIBC_NT_KERNEL32 \
LIBC_NEXGEN32E \
LIBC_VGA
# PLEASE: MAINTAIN TOPOLOGICAL ORDER
# FROM HIGHEST LEVEL TO LOWEST LEVEL
COSMOPOLITAN_OBJECTS = \
NET_HTTP \
LIBC_DNS \
LIBC_SOCK \
LIBC_NT_WS2_32 \
LIBC_NT_IPHLPAPI \
LIBC_NT_MSWSOCK \
LIBC_X \
THIRD_PARTY_GETOPT \
LIBC_LOG \
LIBC_TIME \
LIBC_ZIPOS \
THIRD_PARTY_ZLIB \
THIRD_PARTY_MUSL \
LIBC_STDIO \
THIRD_PARTY_GDTOA \
THIRD_PARTY_REGEX \
LIBC_THREAD \
THIRD_PARTY_NSYNC_MALLOC \
LIBC_MEM \
THIRD_PARTY_DLMALLOC \
LIBC_RUNTIME \
THIRD_PARTY_NSYNC \
LIBC_ELF \
LIBC_CALLS \
LIBC_SYSV_CALLS \
LIBC_VGA \
LIBC_NT_PSAPI \
LIBC_NT_POWRPROF \
LIBC_NT_PDH \
LIBC_NT_GDI32 \
LIBC_NT_COMDLG32 \
LIBC_NT_URL \
LIBC_NT_USER32 \
LIBC_NT_NTDLL \
LIBC_NT_ADVAPI32 \
LIBC_NT_SYNCHRONIZATION \
LIBC_FMT \
THIRD_PARTY_COMPILER_RT \
LIBC_TINYMATH \
THIRD_PARTY_XED \
LIBC_STR \
LIBC_SYSV \
LIBC_INTRIN \
LIBC_NT_KERNEL32 \
LIBC_NEXGEN32E
COSMOPOLITAN_HEADERS = \
APE \
LIBC \
LIBC_CALLS \
LIBC_DNS \
LIBC_ELF \
LIBC_FMT \
LIBC_INTRIN \
LIBC_LOG \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_NT \
LIBC_RUNTIME \
LIBC_SOCK \
LIBC_STDIO \
THIRD_PARTY_NSYNC \
THIRD_PARTY_XED \
LIBC_STR \
LIBC_SYSV \
LIBC_THREAD \
LIBC_TIME \
LIBC_TINYMATH \
LIBC_X \
LIBC_ZIPOS \
LIBC_VGA \
NET_HTTP \
THIRD_PARTY_DLMALLOC \
THIRD_PARTY_GDTOA \
THIRD_PARTY_GETOPT \
THIRD_PARTY_MUSL \
THIRD_PARTY_ZLIB \
THIRD_PARTY_ZLIB_GZ \
COSMOPOLITAN_HEADERS = \
APE \
LIBC \
LIBC_CALLS \
LIBC_DNS \
LIBC_ELF \
LIBC_FMT \
LIBC_INTRIN \
LIBC_LOG \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_NT \
LIBC_RUNTIME \
LIBC_SOCK \
LIBC_STDIO \
THIRD_PARTY_NSYNC \
THIRD_PARTY_XED \
LIBC_STR \
LIBC_SYSV \
LIBC_THREAD \
LIBC_TIME \
LIBC_TINYMATH \
LIBC_X \
LIBC_ZIPOS \
LIBC_VGA \
NET_HTTP \
THIRD_PARTY_DLMALLOC \
THIRD_PARTY_GDTOA \
THIRD_PARTY_GETOPT \
THIRD_PARTY_MUSL \
THIRD_PARTY_ZLIB \
THIRD_PARTY_ZLIB_GZ \
THIRD_PARTY_REGEX
o/$(MODE)/cosmopolitan.a: \
@@ -370,7 +381,7 @@ o/cosmopolitan.h: \
$(file >$(TMPDIR)/$(subst /,_,$@),libc/integral/normalize.inc $(foreach x,$(COSMOPOLITAN_HEADERS),$($(x)_HDRS)))
@$(COMPILE) -AROLLUP -T$@ o/$(MODE)/tool/build/rollup.com @$(TMPDIR)/$(subst /,_,$@) >$@
o/cosmopolitan.html: .UNSANDBOXED = 1
o/cosmopolitan.html: private .UNSANDBOXED = 1
o/cosmopolitan.html: \
o/$(MODE)/third_party/chibicc/chibicc.com.dbg \
$(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS))) \
+18 -20
View File
@@ -1,10 +1,7 @@
![Cosmopolitan Honeybadger](usr/share/img/honeybadger.png)
[![build](https://github.com/jart/cosmopolitan/actions/workflows/build.yml/badge.svg)](https://github.com/jart/cosmopolitan/actions/workflows/build.yml)
# Cosmopolitan (Vista Edition)
**This is a community supported legacy branch of Cosmopolitan 2.0 that's
intended to preserve compatibility with Windows Vista and Windows 7.**
# Cosmopolitan
[Cosmopolitan Libc](https://justine.lol/cosmopolitan/index.html) makes C
a build-once run-anywhere language, like Java, except it doesn't need an
@@ -26,11 +23,11 @@ If you're doing your development work on Linux or BSD then you need just
five files to get started. Here's what you do on Linux:
```sh
wget https://justine.lol/cosmopolitan/cosmopolitan-amalgamation-2.0.1.zip
unzip cosmopolitan-amalgamation-2.0.1.zip
wget https://justine.lol/cosmopolitan/cosmopolitan-amalgamation-2.1.zip
unzip cosmopolitan-amalgamation-2.1.zip
printf 'main() { printf("hello world\\n"); }\n' >hello.c
gcc -g -Os -static -nostdlib -nostdinc -fno-pie -no-pie -mno-red-zone \
-fno-omit-frame-pointer -pg -mnop-mcount -mno-tls-direct-seg-refs \
-fno-omit-frame-pointer -pg -mnop-mcount -mno-tls-direct-seg-refs -gdwarf-4 \
-o hello.com.dbg hello.c -fuse-ld=bfd -Wl,-T,ape.lds -Wl,--gc-sections \
-include cosmopolitan.h crt.o ape-no-modify-self.o cosmopolitan.a
objcopy -S -O binary hello.com.dbg hello.com
@@ -103,7 +100,7 @@ heavyweight features like tracing to your binaries by default. In that
case, you may want to consider using our build system:
```sh
make -j8 MODE=tiny
make m=tiny
```
Which will cause programs such as `hello.com` and `life.com` to shrink
@@ -158,7 +155,7 @@ cd cosmopolitan
This will build the entire repository and run all the tests:
```sh
build/bootstrap/make.com -j16
build/bootstrap/make.com
o//examples/hello.com
find o -name \*.com | xargs ls -rShal | less
```
@@ -177,7 +174,7 @@ having minimal deterministic builds. For example, if you wanted to build
only hello.com then you could do that as follows:
```sh
build/bootstrap/make.com -j16 o//examples/hello.com
build/bootstrap/make.com o//examples/hello.com
```
Sometimes it's desirable to build a subset of targets, without having to
@@ -186,7 +183,7 @@ directory name. For example, if you wanted to build only the targets and
subtargets of the chibicc package including its tests, you would say:
```sh
build/bootstrap/make.com -j16 o//third_party/chibicc
build/bootstrap/make.com o//third_party/chibicc
o//third_party/chibicc/chibicc.com --help
```
@@ -194,18 +191,19 @@ Cosmopolitan provides a variety of build modes. For example, if you want
really tiny binaries (as small as 12kb in size) then you'd say:
```sh
build/bootstrap/make.com -j16 MODE=tiny
build/bootstrap/make.com m=tiny
```
Here's some other build modes you can try:
```sh
build/bootstrap/make.com -j16 MODE=dbg # asan + ubsan + debug
build/bootstrap/make.com -j16 MODE=asan # production memory safety
build/bootstrap/make.com -j16 MODE=opt # -march=native optimizations
build/bootstrap/make.com -j16 MODE=rel # traditional release binaries
build/bootstrap/make.com -j16 MODE=optlinux # optimal linux-only performance
build/bootstrap/make.com -j16 MODE=tinylinux # tiniest linux-only 4kb binaries
build/bootstrap/make.com m=dbg # asan + ubsan + debug
build/bootstrap/make.com m=asan # production memory safety
build/bootstrap/make.com m=opt # -march=native optimizations
build/bootstrap/make.com m=rel # traditional release binaries
build/bootstrap/make.com m=optlinux # optimal linux-only performance
build/bootstrap/make.com m=fastbuild # build 28% faster w/o debugging
build/bootstrap/make.com m=tinylinux # tiniest linux-only 4kb binaries
```
For further details, see [//build/config.mk](build/config.mk).
@@ -247,11 +245,11 @@ gdb foo.com -ex 'add-symbol-file foo.com.dbg 0x401000'
| :--- | ---: | ---: |
| AMD | K8 Venus | 2005 |
| Intel | Core | 2006 |
| Windows | Vista | 2006 |
| Linux | 2.6.18 | 2007 |
| Windows | 8 | 2012 |
| Mac OS X | 15.6 | 2018 |
| FreeBSD | 13 | 2020 |
| OpenBSD | 6.4 | 2018 |
| FreeBSD | 13 | 2020 |
| NetBSD | 9.2 | 2021 |
## Special Thanks
+12 -12
View File
@@ -235,8 +235,9 @@ pc: cld
#endif
ljmp $0,$REAL(1f)
1: mov %cx,%ds
mov $IMAGE_BASE_REAL-0x0500,%cx # clears bss
mov $0x0500>>4,%ax # struct mman
.set mm,0x0500 # struct mman
mov $IMAGE_BASE_REAL-mm,%cx # clears bss
mov $mm>>4,%ax
mov %ax,%es
xor %ax,%ax
xor %di,%di
@@ -328,7 +329,7 @@ dsknfo: push %bx
movpp %es,%ds
xor %si,%si
mov %si,%es
mov $0x1d10,%si # mman::pc_drive_base_table
mov $mm+"struct mman::pc_drive_base_table",%si
xchg %si,%di
movsw #→ headunloadtime, headloadtime
movsw #→ shutofftime, bytespersector
@@ -381,11 +382,11 @@ pcread: push %ax
add $512>>4,%si
mov %si,%es
inc %al # ++sector
cmp 0x1d1c,%al # mman::pc_drive_last_sector
cmp mm+"struct mman::pc_drive_last_sector",%al
jbe 2f
mov $1,%al
inc %dh # ++head
cmp 0x1d20,%dh # mman::pc_drive_last_head
cmp mm+"struct mman::pc_drive_last_head",%dh
jbe 2f
xor %dh,%dh
inc %cx # ++cylinder
@@ -1288,10 +1289,9 @@ lcheck: pushf # check for i8086 / i8088 / i80186
.endfn lcheck
// Gets memory map from BIOS.
e820: mov $0x0510>>4,%di # mman::e820
mov %di,%es
xor %di,%di # es:di is destination buffer
xor %ebx,%ebx # ebx is an api state tracker
e820: xor %ebx,%ebx # %ebx is an api state tracker
mov %bx,%es
mov $mm+"struct mman::e820",%di # es:di is destination buffer
1: mov $0xE820,%eax # magic
mov $8+8+4+4,%ecx # sizeof(struct SmapEntry)
mov $0x534d4150,%edx # magic number
@@ -1315,7 +1315,7 @@ e820: mov $0x0510>>4,%di # mman::e820
4: add $8+8+4+4,%di # keep entry
5: test %ebx,%ebx # last entry?
jz 8f
cmp $(256-1)*(8+8+4+4),%di
cmp $mm+"struct mman::e820_end"-(8+8+4+4),%di
jb 1b
8: xor %ax,%ax # add a blank sentinel entry
mov $(8+8)/2,%cx
@@ -1425,7 +1425,7 @@ pinit: push %ds
//
// @see Intel Manual V3A §4.1.2
golong: cli
lidt 0x1d22 # mman::bad_idt
lidt mm+"struct mman::bad_idt"
mov %cr4,%eax
or $CR4_PAE|CR4_PGE|CR4_OSFXSR,%eax
mov %eax,%cr4
@@ -1458,7 +1458,7 @@ long: xor %eax,%eax
xor %ebx,%ebx
xor %ebp,%ebp
push %rbp
mov $0x0500,%rdi # mman
mov $mm,%rdi
mov %cr3,%rsi
mov $IMAGE_BASE_REAL,%edx
call __map_phdrs
+2
View File
@@ -458,6 +458,7 @@ SECTIONS {
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_line_str 0 : { *(.debug_line_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
.debug_weaknames 0 : { *(.debug_weaknames) }
@@ -466,6 +467,7 @@ SECTIONS {
.debug_varnames 0 : { *(.debug_varnames) }
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
.debug_rnglists 0 : { *(.debug_rnglists) }
.debug_macro 0 : { *(.debug_macro) }
.debug_addr 0 : { *(.debug_addr) }
.gnu.attributes 0 : { KEEP(*(.gnu.attributes)) }
+2
View File
@@ -65,6 +65,7 @@ o/$(MODE)/ape/ape.lds: \
libc/intrin/bits.h \
libc/thread/tls.h \
libc/calls/struct/timespec.h \
libc/thread/thread.h \
libc/dce.h \
libc/elf/def.h \
libc/elf/pf2prot.internal.h \
@@ -82,6 +83,7 @@ o/$(MODE)/ape/public/ape.lds: \
libc/intrin/bits.h \
libc/thread/tls.h \
libc/calls/struct/timespec.h \
libc/thread/thread.h \
libc/dce.h \
libc/elf/def.h \
libc/elf/pf2prot.internal.h \
+33 -33
View File
@@ -32,23 +32,23 @@
// @see ape/ape.lds
// @see winimp
.macro .imp dll:req fn:req actual:req hint
.dll \dll
.section .piro.data.sort.iat.2.\dll\().2.\actual,"aw",@progbits
.dll "\dll"
.section ".piro.data.sort.iat.2.\dll\().2.\actual","aw",@progbits
.type \fn,@object
.align __SIZEOF_POINTER__
\fn: .quad RVA((\dll\().\actual))
\fn: .quad RVA(("\dll\().\actual"))
.size \fn,.-\fn
.globl \fn
.hidden \fn
.previous
.section .idata.ro.ilt.\dll\().2.\actual,"a",@progbits
.Lidata.ilt.\dll\().\actual:
.quad RVA((\dll\().\actual))
.type .Lidata.ilt.\dll\().\actual,@object
.size .Lidata.ilt.\dll\().\actual,.-.Lidata.ilt.\dll\().\actual
.section ".idata.ro.ilt.\dll\().2.\actual","a",@progbits
".Lidata.ilt.\dll\().\actual":
.quad RVA("\dll\().\actual")
.type ".Lidata.ilt.\dll\().\actual",@object
.size ".Lidata.ilt.\dll\().\actual",.-".Lidata.ilt.\dll\().\actual"
.previous
.section .idata.ro.hnt.\dll\().2.\actual,"a",@progbits
\dll\().\actual:
.section ".idata.ro.hnt.\dll\().2.\actual","a",@progbits
"\dll\().\actual":
.ifnb \hint # hint i.e. guess function ordinal
.short \hint
.else
@@ -56,55 +56,55 @@
.endif
.asciz "\actual"
.align 2 # documented requirement
.globl \dll\().\actual
.hidden \dll\().\actual
.type \dll\().\actual,@object
.size \dll\().\actual,.-\dll\().\actual
.globl "\dll\().\actual"
.hidden "\dll\().\actual"
.type "\dll\().\actual",@object
.size "\dll\().\actual",.-"\dll\().\actual"
.previous
.endm
// Defines DLL import.
// @note this is an implementation detail of .imp
.macro .dll name:req
.section .idata.ro.idt.2.\name,"aG",@progbits,\name,comdat
.equ .Lidata.idt.\name,.
.long RVA(idata.ilt.\name) # ImportLookupTable
.section ".idata.ro.idt.2.\name","aG",@progbits,"\name",comdat
.equ ".Lidata.idt.\name",.
.long RVA("idata.ilt.\name") # ImportLookupTable
.long 0 # TimeDateStamp
.long 0 # ForwarderChain
.long RVA(.Lidata.str.\name) # DllNameRva
.long RVA(idata.iat.\name) # ImportAddressTable
.type .Lidata.idt.\name,@object
.size .Lidata.idt.\name,.-.Lidata.idt.\name
.long RVA(".Lidata.str.\name") # DllNameRva
.long RVA("idata.iat.\name") # ImportAddressTable
.type ".Lidata.idt.\name",@object
.size ".Lidata.idt.\name",.-".Lidata.idt.\name"
.previous
.section .idata.ro.ilt.\name\().1,"aG",@progbits,\name,comdat
.section ".idata.ro.ilt.\name\().1","aG",@progbits,"\name",comdat
.align __SIZEOF_POINTER__
.type idata.ilt.\name,@object
idata.ilt.\name:
.type "idata.ilt.\name",@object
"idata.ilt.\name":
.previous/*
...
decentralized content
...
*/.section .idata.ro.ilt.\name\().3,"aG",@progbits,\name,comdat
*/.section ".idata.ro.ilt.\name\().3","aG",@progbits,"\name",comdat
.quad 0
.previous
.section .idata.ro.hnt.\name\().1,"aG",@progbits,\name,comdat
.section ".idata.ro.hnt.\name\().1","aG",@progbits,"\name",comdat
.align __SIZEOF_POINTER__
.type idata.hnt.\name,@object
.equ idata.hnt.\name,.
.type "idata.hnt.\name",@object
.equ "idata.hnt.\name",.
.previous
.section .piro.data.sort.iat.2.\name\().1,"awG",@progbits,\name,comdat
.section ".piro.data.sort.iat.2.\name\().1","awG",@progbits,"\name",comdat
.align __SIZEOF_POINTER__
.type idata.iat.\name,@object
idata.iat.\name:
.type "idata.iat.\name",@object
"idata.iat.\name":
.previous/*
...
decentralized content
...
*/.section .piro.data.sort.iat.2.\name\().3,"awG",@progbits,\name,comdat
*/.section ".piro.data.sort.iat.2.\name\().3","awG",@progbits,"\name",comdat
.quad 0
.previous
.section .rodata.str1.1,"aSM",@progbits,1
.Lidata.str.\name:
".Lidata.str.\name":
.asciz "\name\().dll"
.previous
.endm
Binary file not shown.
+43 -1
View File
@@ -102,7 +102,7 @@ endif
# - Larger binaries
#
ifeq ($(MODE), asan)
CONFIG_CCFLAGS += $(BACKTRACES) -O2
CONFIG_CCFLAGS += $(BACKTRACES) -O2 -DSYSDEBUG
CONFIG_COPTS += -fsanitize=address
TARGET_ARCH ?= -msse3
endif
@@ -152,6 +152,10 @@ CONFIG_CCFLAGS += \
-fomit-frame-pointer \
-momit-leaf-frame-pointer \
-foptimize-sibling-calls
CONFIG_OFLAGS += \
-g0
CONFIG_LDFLAGS += \
-S
TARGET_ARCH ?= \
-msse3
PYFLAGS += \
@@ -180,6 +184,10 @@ CONFIG_CPPFLAGS += \
-DSUPPORT_VECTOR=1
DEFAULT_COPTS += \
-mred-zone
CONFIG_OFLAGS += \
-g0
CONFIG_LDFLAGS += \
-S
CONFIG_CCFLAGS += \
-Os \
-fno-align-functions \
@@ -212,6 +220,10 @@ CONFIG_CPPFLAGS += \
-DSUPPORT_VECTOR=113
DEFAULT_COPTS += \
-mred-zone
CONFIG_OFLAGS += \
-g0
CONFIG_LDFLAGS += \
-S
CONFIG_CCFLAGS += \
-Os \
-fno-align-functions \
@@ -249,6 +261,10 @@ CONFIG_CCFLAGS += \
-fno-align-jumps \
-fno-align-labels \
-fno-align-loops
CONFIG_OFLAGS += \
-g0
CONFIG_LDFLAGS += \
-S
TARGET_ARCH ?= \
-msse3
endif
@@ -278,10 +294,36 @@ CONFIG_CCFLAGS += \
-fno-align-jumps \
-fno-align-labels \
-fno-align-loops
CONFIG_OFLAGS += \
-g0
CONFIG_LDFLAGS += \
-S
TARGET_ARCH ?= \
-msse3
endif
# GCC11 Mode
# https://justine.lol/compilers/x86_64-linux-musl__x86_64-linux-musl__g++-11.2.0.tar.xz
ifeq ($(MODE), gcc11)
.UNVEIL += rx:/opt/gcc11
CONFIG_CCFLAGS += $(BACKTRACES) $(FTRACE) -DSYSDEBUG -O2
AS = /opt/gcc11/bin/x86_64-linux-musl-as
CC = /opt/gcc11/bin/x86_64-linux-musl-gcc
CXX = /opt/gcc11/bin/x86_64-linux-musl-g++
CXXFILT = /opt/gcc11/bin/x86_64-linux-musl-c++filt
LD = /opt/gcc11/bin/x86_64-linux-musl-ld.bfd
NM = /opt/gcc11/bin/x86_64-linux-musl-nm
GCC = /opt/gcc11/bin/x86_64-linux-musl-gcc
STRIP = /opt/gcc11/bin/x86_64-linux-musl-strip
OBJCOPY = /opt/gcc11/bin/x86_64-linux-musl-objcopy
OBJDUMP = /opt/gcc11/bin/x86_64-linux-musl-objdump
ADDR2LINE = /opt/gcc11/bin/x86_64-linux-musl-addr2line
CONFIG_CCFLAGS += $(BACKTRACES) $(FTRACE) -O2 -Wno-stringop-overread
CONFIG_CFLAGS += -Wno-old-style-definition
CONFIG_CPPFLAGS += -DNDEBUG -DSYSDEBUG
TARGET_ARCH ?= -msse3
endif
# LLVM Mode
ifeq ($(MODE), llvm)
TARGET_ARCH ?= -msse3
+1
View File
@@ -148,6 +148,7 @@ DEFAULT_CCFLAGS = \
DEFAULT_OFLAGS = \
-g \
-gdwarf-4 \
-gdescribe-dies
DEFAULT_COPTS = \
+8 -8
View File
@@ -163,15 +163,15 @@ o/$(MODE)%/.zip.o: %
# and it would be too costly in terms of make latency to have every
# header file depend on $(HDRS) and $(INCS).
o/%.h.ok: .UNSANDBOXED = 1
o/%.h.ok: private .UNSANDBOXED = 1
o/%.h.ok: %.h
@$(COMPILE) -ACHECK.h $(COMPILE.c) -xc -g0 -o $@ $<
o/$(MODE)/%.h.ok: .UNSANDBOXED = 1
o/$(MODE)/%.h.ok: private .UNSANDBOXED = 1
o/$(MODE)/%.h.ok: %.h
@$(COMPILE) -ACHECK.h $(COMPILE.c) -xc -g0 -o $@ $<
o/$(MODE)/%.hh.ok: .UNSANDBOXED = 1
o/$(MODE)/%.hh.ok: private .UNSANDBOXED = 1
o/$(MODE)/%.hh.ok: %.hh
@$(COMPILE) -ACHECK.h $(COMPILE.cxx) -xc++ -g0 -o $@ $<
@@ -179,7 +179,7 @@ o/%.okk: .UNSANDBOXED = 1
o/%.okk: %
@$(COMPILE) -ACHECK.h $(COMPILE.cxx) -xc++ -g0 -o $@ $<
o/$(MODE)/%.okk: .UNSANDBOXED = 1
o/$(MODE)/%.okk: private .UNSANDBOXED = 1
o/$(MODE)/%.okk: %
@$(COMPILE) -ACHECK.h $(COMPILE.cxx) -xc++ -g0 -o $@ $<
@@ -207,19 +207,19 @@ MAKE_SYMTAB_ZIP = \
################################################################################
# EMACS ASSEMBLY GENERATION
o/$(MODE)/%-gcc.asm: .UNSANDBOXED = 1
o/$(MODE)/%-gcc.asm: private .UNSANDBOXED = 1
o/$(MODE)/%-gcc.asm: %.c
@$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $<
o/$(MODE)/%-gcc.asm: .UNSANDBOXED = 1
o/$(MODE)/%-gcc.asm: private .UNSANDBOXED = 1
o/$(MODE)/%-gcc.asm: %.cc
@$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.cxx) -S -g0 $(OUTPUT_OPTION) $<
o/$(MODE)/%-clang.asm: .UNSANDBOXED = 1
o/$(MODE)/%-clang.asm: private .UNSANDBOXED = 1
o/$(MODE)/%-clang.asm: %.c
@$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $<
o/$(MODE)/%-clang.asm: CC = $(CLANG)
o/$(MODE)/%-clang.asm: .UNSANDBOXED = 1
o/$(MODE)/%-clang.asm: private .UNSANDBOXED = 1
o/$(MODE)/%-clang.asm: %.cc
@$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.cxx) -S -g0 $(OUTPUT_OPTION) $<
+1 -1
View File
@@ -30,7 +30,7 @@
* @see ttyconfig(), ttyrestore()
*/
int ttyconfig(int ttyfd, ttyconf_f fn, int64_t arg,
const struct termios *opt_out_oldconf) {
struct termios *opt_out_oldconf) {
struct termios conf[2];
if (tcgetattr(ttyfd, &conf[0]) != -1 &&
fn(memcpy(&conf[1], &conf[0], sizeof(conf[0])), arg) != -1 &&
+1 -1
View File
@@ -44,7 +44,7 @@ int ttysendtitle(int, const char *, const struct TtyIdent *);
int ttyident(struct TtyIdent *, int, int);
void ttyidentclear(struct TtyIdent *);
char *ttydescribe(char *, size_t, const struct TtyIdent *);
int ttyconfig(int, ttyconf_f, int64_t, const struct termios *);
int ttyconfig(int, ttyconf_f, int64_t, struct termios *);
int ttyrestore(int, const struct termios *);
int ttysetrawdeadline(struct termios *, int64_t);
int ttysetrawmode(struct termios *, int64_t);
+56
View File
@@ -0,0 +1,56 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
│ To the extent possible under law, Justine Tunney has waived │
│ all copyright and related or neighboring rights to this file, │
│ as it is written in the following disclaimers: │
│ • http://unlicense.org/ │
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
╚─────────────────────────────────────────────────────────────────*/
#endif
#include "libc/calls/struct/timespec.h"
#include "libc/errno.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/clock.h"
int n;
int shown[64];
void show(int clock) {
int i;
struct timespec ts;
if (clock == 127) return;
for (i = 0; i < n; ++i) {
if (shown[i] == clock) {
return;
}
}
shown[n++] = clock;
if (clock_getres(clock, &ts) != -1) {
kprintf("%s %'ld ns\n", DescribeClockName(clock), _timespec_tonanos(ts));
} else {
kprintf("%s %s\n", DescribeClockName(clock), _strerrno(errno));
}
}
int main(int argc, char *argv[]) {
show(CLOCK_REALTIME);
show(CLOCK_REALTIME_FAST);
show(CLOCK_REALTIME_PRECISE);
show(CLOCK_MONOTONIC);
show(CLOCK_MONOTONIC_RAW);
show(CLOCK_MONOTONIC_FAST);
show(CLOCK_MONOTONIC_PRECISE);
show(CLOCK_PROCESS_CPUTIME_ID);
show(CLOCK_THREAD_CPUTIME_ID);
show(CLOCK_PROF);
show(CLOCK_BOOTTIME);
show(CLOCK_REALTIME_ALARM);
show(CLOCK_BOOTTIME_ALARM);
show(CLOCK_TAI);
show(CLOCK_UPTIME);
show(CLOCK_UPTIME_PRECISE);
show(CLOCK_UPTIME_FAST);
show(CLOCK_SECOND);
}
+1 -1
View File
@@ -183,7 +183,7 @@ int main(int argc, char *argv[]) {
struct Url url;
char *host, *port;
bool usessl = false;
_gc(ParseUrl(urlarg, -1, &url));
_gc(ParseUrl(urlarg, -1, &url, kUrlPlus));
_gc(url.params.p);
if (url.scheme.n) {
if (url.scheme.n == 5 && !memcasecmp(url.scheme.p, "https", 5)) {
+1
View File
@@ -81,6 +81,7 @@ EXAMPLES_DIRECTDEPS = \
THIRD_PARTY_MBEDTLS \
THIRD_PARTY_MUSL \
THIRD_PARTY_NSYNC \
THIRD_PARTY_NSYNC_MEM \
THIRD_PARTY_QUICKJS \
THIRD_PARTY_STB \
THIRD_PARTY_XED \
+1 -1
View File
@@ -167,7 +167,7 @@ void *Worker(void *id) {
// wait for client connection
clientaddrsize = sizeof(clientaddr);
client = accept(server, (struct sockaddr *)&clientaddr, &clientaddrsize);
client = accept(server, &clientaddr, &clientaddrsize);
// accept() can raise a very diverse number of errors but none of
// them are really true showstoppers that would necessitate us to
+521
View File
@@ -0,0 +1,521 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
│vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright (c) 2010, 2012 David E. O'Brien │
│ Copyright (c) 1980, 1992, 1993 │
│ The Regents of the University of California. All rights reserved. │
│ │
│ Redistribution and use in source and binary forms, with or without │
│ modification, are permitted provided that the following conditions │
│ are met: │
│ 1. Redistributions of source code must retain the above copyright │
│ notice, this list of conditions and the following disclaimer. │
│ 2. Redistributions in binary form must reproduce the above copyright │
│ notice, this list of conditions and the following disclaimer in the │
│ documentation and/or other materials provided with the distribution. │
│ 3. Neither the name of the University nor the names of its contributors │
│ may be used to endorse or promote products derived from this software │
│ without specific prior written permission. │
│ │
│ THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND │
│ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE │
│ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE │
│ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE │
│ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL │
│ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS │
│ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) │
│ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT │
│ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY │
│ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF │
│ SUCH DAMAGE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/struct/termios.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/struct/winsize.h"
#include "libc/calls/termios.h"
#include "libc/calls/weirdtypes.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/intrin/bswap.h"
#include "libc/log/bsd.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
#include "libc/paths.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/select.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/s.h"
#include "libc/sysv/consts/termios.h"
#include "libc/time/time.h"
#include "third_party/getopt/getopt.h"
// clang-format off
/**
* @fileoverview Terminal Screencast Recorder / Player, e.g.
*
* make o//examples/script.com
* o//examples/script.com -r
* # type stuff..
* # CTRL-D
* o//examples/script.com -p typescript
*
* @note works on Linux, OpenBSD, NetBSD, FreeBSD, MacOS
* @see https://asciinema.org/
*/
asm(".ident\t\"\\n\\n\
FreeBSD Script (BSD-3 License)\\n\
Copyright (c) 2010, 2012 David E. O'Brien\\n\
Copyright (c) 1980, 1992, 1993\\n\
\tThe Regents of the University of California.\\n\
\tAll rights reserved.\"");
asm(".include \"libc/disclaimer.inc\"");
#define DEF_BUF 65536
struct stamp {
uint64_t scr_len; /* amount of data */
uint64_t scr_sec; /* time it arrived in seconds... */
uint32_t scr_usec; /* ...and microseconds */
uint32_t scr_direction; /* 'i', 'o', etc (also indicates endianness) */
};
static FILE *fscript;
static int master, slave;
static int child;
static const char *fname;
static char *fmfname;
static int qflg, ttyflg;
static int usesleep, rawout, showexit;
static struct termios tt;
static void done(int) wontreturn;
static void doshell(char **);
static void finish(void);
static void record(FILE *, char *, size_t, int);
static void consume(FILE *, off_t, char *, int);
static void playback(FILE *) wontreturn;
static void usage(void);
int
main(int argc, char *argv[])
{
int cc;
struct termios rtt, stt;
struct winsize win;
struct timeval tv, *tvp;
time_t tvec, start;
static char obuf[BUFSIZ];
static char ibuf[BUFSIZ];
fd_set rfd;
int aflg, Fflg, kflg, pflg, ch, k, n;
int flushtime, readstdin;
int fm_fd, fm_log;
aflg = Fflg = kflg = pflg = 0;
usesleep = 1;
rawout = 0;
flushtime = 30;
fm_fd = -1; /* Shut up stupid "may be used uninitialized" GCC
warning. (not needed w/clang) */
showexit = 0;
while ((ch = getopt(argc, argv, "adeFfkpqrt:")) != -1)
switch(ch) {
case 'a':
aflg = 1;
break;
case 'd':
usesleep = 0;
break;
case 'e': /* Default behavior, accepted for linux compat */
break;
case 'F':
Fflg = 1;
break;
case 'k':
kflg = 1;
break;
case 'p':
pflg = 1;
break;
case 'q':
qflg = 1;
break;
case 'r':
rawout = 1;
break;
case 't':
flushtime = atoi(optarg);
if (flushtime < 0)
err(1, "invalid flush time %d", flushtime);
break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
if (argc > 0) {
fname = argv[0];
argv++;
argc--;
} else
fname = "typescript";
if ((fscript = fopen(fname, pflg ? "r" : aflg ? "a" : "w")) == NULL)
err(1, "%s", fname);
if (pflg)
playback(fscript);
if (tcgetattr(STDIN_FILENO, &tt) == -1 ||
ioctl(STDIN_FILENO, TIOCGWINSZ, &win) == -1) {
if (errno != ENOTTY) /* For debugger. */
err(1, "tcgetattr/ioctl");
if (openpty(&master, &slave, NULL, NULL, NULL) == -1)
err(1, "openpty");
} else {
if (openpty(&master, &slave, NULL, &tt, &win) == -1)
err(1, "openpty");
ttyflg = 1;
}
if (rawout)
record(fscript, NULL, 0, 's');
if (!qflg) {
tvec = time(NULL);
printf("Script started, output file is %s\n", fname);
if (!rawout) {
fprintf(fscript, "Script started on %s",
ctime(&tvec));
if (argv[0]) {
showexit = 1;
fprintf(fscript, "Command: ");
for (k = 0 ; argv[k] ; ++k)
fprintf(fscript, "%s%s", k ? " " : "",
argv[k]);
fprintf(fscript, "\n");
}
}
fflush(fscript);
}
if (ttyflg) {
rtt = tt;
cfmakeraw(&rtt);
rtt.c_lflag &= ~ECHO;
tcsetattr(STDIN_FILENO, TCSAFLUSH, &rtt);
}
child = fork();
if (child < 0) {
warn("fork");
done(1);
}
if (child == 0) {
doshell(argv);
}
close(slave);
start = tvec = time(0);
readstdin = 1;
for (;;) {
FD_ZERO(&rfd);
FD_SET(master, &rfd);
if (readstdin)
FD_SET(STDIN_FILENO, &rfd);
if (!readstdin && ttyflg) {
tv.tv_sec = 1;
tv.tv_usec = 0;
tvp = &tv;
readstdin = 1;
} else if (flushtime > 0) {
tv.tv_sec = flushtime - (tvec - start);
tv.tv_usec = 0;
tvp = &tv;
} else {
tvp = NULL;
}
n = select(master + 1, &rfd, 0, 0, tvp);
if (n < 0 && errno != EINTR)
break;
if (n > 0 && FD_ISSET(STDIN_FILENO, &rfd)) {
cc = read(STDIN_FILENO, ibuf, BUFSIZ);
if (cc < 0)
break;
if (cc == 0) {
if (tcgetattr(master, &stt) == 0 &&
(stt.c_lflag & ICANON) != 0) {
write(master, &stt.c_cc[VEOF], 1);
}
readstdin = 0;
}
if (cc > 0) {
if (rawout)
record(fscript, ibuf, cc, 'i');
write(master, ibuf, cc);
if (kflg && tcgetattr(master, &stt) >= 0 &&
((stt.c_lflag & ECHO) == 0)) {
fwrite(ibuf, 1, cc, fscript);
}
}
}
if (n > 0 && FD_ISSET(master, &rfd)) {
cc = read(master, obuf, sizeof (obuf));
if (cc <= 0)
break;
write(STDOUT_FILENO, obuf, cc);
if (rawout)
record(fscript, obuf, cc, 'o');
else
fwrite(obuf, 1, cc, fscript);
}
tvec = time(0);
if (tvec - start >= flushtime) {
fflush(fscript);
start = tvec;
}
if (Fflg)
fflush(fscript);
}
finish();
done(0);
}
static void
usage(void)
{
fprintf(stderr,
"usage: script [-adfkpqr] [-t time] [file [command ...]]\n");
exit(1);
}
static void
finish(void)
{
int e, status;
if (waitpid(child, &status, 0) == child) {
if (WIFEXITED(status))
e = WEXITSTATUS(status);
else if (WIFSIGNALED(status))
e = WTERMSIG(status);
else /* can't happen */
e = 1;
done(e);
}
}
static void
doshell(char **av)
{
const char *shell;
shell = getenv("SHELL");
if (shell == NULL)
shell = _PATH_BSHELL;
close(master);
fclose(fscript);
free(fmfname);
login_tty(slave);
setenv("SCRIPT", fname, 1);
if (av[0]) {
execvp(av[0], av);
warn("%s", av[0]);
} else {
execl(shell, shell, "-i", 0);
warn("%s", shell);
}
exit(1);
}
static void
done(int eno)
{
time_t tvec;
if (ttyflg)
tcsetattr(STDIN_FILENO, TCSAFLUSH, &tt);
tvec = time(NULL);
if (rawout)
record(fscript, NULL, 0, 'e');
if (!qflg) {
if (!rawout) {
if (showexit)
fprintf(fscript, "\nCommand exit status:"
" %d", eno);
fprintf(fscript,"\nScript done on %s",
ctime(&tvec));
}
printf("\nScript done, output file is %s\n", fname);
}
fclose(fscript);
close(master);
exit(eno);
}
static void
record(FILE *fp, char *buf, size_t cc, int direction)
{
struct iovec iov[2];
struct stamp stamp;
struct timeval tv;
gettimeofday(&tv, NULL);
stamp.scr_len = cc;
stamp.scr_sec = tv.tv_sec;
stamp.scr_usec = tv.tv_usec;
stamp.scr_direction = direction;
iov[0].iov_len = sizeof(stamp);
iov[0].iov_base = &stamp;
iov[1].iov_len = cc;
iov[1].iov_base = buf;
if (writev(fileno(fp), &iov[0], 2) == -1)
err(1, "writev");
}
static void
consume(FILE *fp, off_t len, char *buf, int reg)
{
size_t l;
if (reg) {
if (fseeko(fp, len, SEEK_CUR) == -1)
err(1, NULL);
}
else {
while (len > 0) {
l = MIN(DEF_BUF, len);
if (fread(buf, sizeof(char), l, fp) != l)
err(1, "cannot read buffer");
len -= l;
}
}
}
#define swapstamp(stamp) do { \
if (stamp.scr_direction > 0xff) { \
stamp.scr_len = bswap_64(stamp.scr_len); \
stamp.scr_sec = bswap_64(stamp.scr_sec); \
stamp.scr_usec = bswap_32(stamp.scr_usec); \
stamp.scr_direction = bswap_32(stamp.scr_direction); \
} \
} while (0/*CONSTCOND*/)
static void
termset(void)
{
struct termios traw;
if (tcgetattr(STDOUT_FILENO, &tt) == -1) {
if (errno != ENOTTY) /* For debugger. */
err(1, "tcgetattr");
return;
}
ttyflg = 1;
traw = tt;
cfmakeraw(&traw);
traw.c_lflag |= ISIG;
tcsetattr(STDOUT_FILENO, TCSANOW, &traw);
}
static void
termreset(void)
{
if (ttyflg) {
tcsetattr(STDOUT_FILENO, TCSADRAIN, &tt);
ttyflg = 0;
}
}
static void
playback(FILE *fp)
{
struct timespec tsi, tso;
struct stamp stamp;
struct stat pst;
static char buf[DEF_BUF];
off_t nread, save_len;
size_t l;
time_t tclock;
int reg;
if (fstat(fileno(fp), &pst) == -1)
err(1, "fstat failed");
reg = S_ISREG(pst.st_mode);
for (nread = 0; !reg || nread < pst.st_size; nread += save_len) {
if (fread(&stamp, sizeof(stamp), 1, fp) != 1) {
if (reg)
err(1, "reading playback header");
else
break;
}
swapstamp(stamp);
save_len = sizeof(stamp);
if (reg && stamp.scr_len >
(uint64_t)(pst.st_size - save_len) - nread)
errx(1, "invalid stamp");
save_len += stamp.scr_len;
tclock = stamp.scr_sec;
tso.tv_sec = stamp.scr_sec;
tso.tv_nsec = stamp.scr_usec * 1000;
switch (stamp.scr_direction) {
case 's':
if (!qflg)
printf("Script started on %s",
ctime(&tclock));
tsi = tso;
consume(fp, stamp.scr_len, buf, reg);
termset();
atexit(termreset);
break;
case 'e':
termreset();
if (!qflg)
printf("\nScript done on %s",
ctime(&tclock));
consume(fp, stamp.scr_len, buf, reg);
break;
case 'i':
/* throw input away */
consume(fp, stamp.scr_len, buf, reg);
break;
case 'o':
tsi.tv_sec = tso.tv_sec - tsi.tv_sec;
tsi.tv_nsec = tso.tv_nsec - tsi.tv_nsec;
if (tsi.tv_nsec < 0) {
tsi.tv_sec -= 1;
tsi.tv_nsec += 1000000000;
}
if (usesleep)
nanosleep(&tsi, NULL);
tsi = tso;
while (stamp.scr_len > 0) {
l = MIN(DEF_BUF, stamp.scr_len);
if (fread(buf, sizeof(char), l, fp) != l)
err(1, "cannot read buffer");
write(STDOUT_FILENO, buf, l);
stamp.scr_len -= l;
}
break;
default:
errx(1, "invalid direction");
}
}
fclose(fp);
exit(0);
}
+100
View File
@@ -0,0 +1,100 @@
SCRIPT(1) Cosmopolitan General Commands Manual SCRIPT(1)
𝐍𝐀𝐌𝐄
𝘀𝗰𝗿𝗶𝗽𝘁 — make typescript of terminal session
𝐒𝐘𝐍𝐎𝐏𝐒𝐈𝐒
𝘀𝗰𝗿𝗶𝗽𝘁 [-𝗮𝗱𝗲𝗳𝗸𝗽𝗾𝗿] [-𝐅 p̲i̲p̲e̲] [-𝘁 t̲i̲m̲e̲] [f̲i̲l̲e̲ [c̲o̲m̲m̲a̲n̲d̲ .̲.̲.̲]]
𝐃𝐄𝐒𝐂𝐑𝐈𝐏𝐓𝐈𝐎𝐍
The 𝘀𝗰𝗿𝗶𝗽𝘁 utility makes a typescript of everything printed on your termi‐
nal. It is useful for students who need a hardcopy record of an interac‐
tive session as proof of an assignment, as the typescript file can be
printed out later with lpr(1).
If the argument f̲i̲l̲e̲ is given, 𝘀𝗰𝗿𝗶𝗽𝘁 saves all dialogue in f̲i̲l̲e̲. If no
file name is given, the typescript is saved in the file t̲y̲p̲e̲s̲c̲r̲i̲p̲t̲.
If the argument c̲o̲m̲m̲a̲n̲d̲ is given, 𝘀𝗰𝗿𝗶𝗽𝘁 will run the specified command
with an optional argument vector instead of an interactive shell.
The following options are available:
-𝗮 Append the output to f̲i̲l̲e̲ or t̲y̲p̲e̲s̲c̲r̲i̲p̲t̲, retaining the prior con‐
tents.
-𝗱 When playing back a session with the -𝗽 flag, do not sleep between
records when playing back a timestamped session.
-𝗲 Accepted for compatibility with u̲t̲i̲l̲-̲l̲i̲n̲u̲x̲ 𝘀𝗰𝗿𝗶𝗽𝘁. The child com‐
mand exit status is always the exit status of 𝘀𝗰𝗿𝗶𝗽𝘁.
-𝐅 p̲i̲p̲e̲
Immediately flush output after each write. This will allow a user
to create a named pipe using mkfifo(1) and another user may watch
the live session using a utility like cat(1).
-𝗸 Log keys sent to the program as well as output.
-𝗽 Play back a session recorded with the -𝗿 flag in real time.
-𝗾 Run in quiet mode, omit the start, stop and command status mes‐
sages.
-𝗿 Record a session with input, output, and timestamping.
-𝘁 t̲i̲m̲e̲
Specify the interval at which the script output file will be
flushed to disk, in seconds. A value of 0 causes 𝘀𝗰𝗿𝗶𝗽𝘁 to flush
after every character I/O event. The default interval is 30 sec‐
onds.
The script ends when the forked shell (or command) exits (a c̲o̲n̲t̲r̲o̲l̲-̲D̲ to
exit the Bourne shell (sh(1)), and e̲x̲i̲t̲, l̲o̲g̲o̲u̲t̲ or c̲o̲n̲t̲r̲o̲l̲-̲D̲ (if i̲g̲n̲o̲r̲e̲e̲o̲f̲
is not set) for the C-shell, csh(1)).
Certain interactive commands, such as vi(1), create garbage in the type‐
script file. The 𝘀𝗰𝗿𝗶𝗽𝘁 utility works best with commands that do not ma‐
nipulate the screen. The results are meant to emulate a hardcopy terminal,
not an addressable one.
𝐄𝐍𝐕𝐈𝐑𝐎𝐍𝐌𝐄𝐍𝐓
The following environment variables are utilized by 𝘀𝗰𝗿𝗶𝗽𝘁:
SCRIPT
The SCRIPT environment variable is added to the sub-shell. If
SCRIPT already existed in the users environment, its value is over‐
written within the sub-shell. The value of SCRIPT is the name of
the t̲y̲p̲e̲s̲c̲r̲i̲p̲t̲ file.
SHELL If the variable SHELL exists, the shell forked by 𝘀𝗰𝗿𝗶𝗽𝘁 will be
that shell. If SHELL is not set, the Bourne shell is assumed.
(Most shells set this variable automatically).
𝐒𝐄𝐄 𝐀𝐋𝐒𝐎
csh(1) (for the h̲i̲s̲t̲o̲r̲y̲ mechanism)
𝐇𝐈𝐒𝐓𝐎𝐑𝐘
The 𝘀𝗰𝗿𝗶𝗽𝘁 command appeared in 3.0BSD.
The -𝗱, -𝗽 and -𝗿 options first appeared in NetBSD 2.0 and were ported to
FreeBSD 9.2.
𝐁𝐔𝐆𝐒
The 𝘀𝗰𝗿𝗶𝗽𝘁 utility places 𝗲𝘃𝗲𝗿𝘆𝘁𝗵𝗶𝗻𝗴 in the log file, including linefeeds
and backspaces. This is not what the naive user expects.
It is not possible to specify a command without also naming the script file
because of argument parsing compatibility issues.
When running in -𝗸 mode, echo cancelling is far from ideal. The slave ter‐
minal mode is checked for ECHO mode to check when to avoid manual echo log‐
ging. This does not work when the terminal is in a raw mode where the pro‐
gram being run is doing manual echo.
If 𝘀𝗰𝗿𝗶𝗽𝘁 reads zero bytes from the terminal, it switches to a mode when it
only attempts to read once a second until there is data to read. This pre‐
vents 𝘀𝗰𝗿𝗶𝗽𝘁 from spinning on zero-byte reads, but might cause a 1-second
delay in processing of user input.
BSD September 1, 2020 BSD
+617
View File
@@ -0,0 +1,617 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
│vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright (c) 1980, 1993 │
│ The Regents of the University of California. All rights reserved. │
│ │
│ Redistribution and use in source and binary forms, with or without │
│ modification, are permitted provided that the following conditions │
│ are met: │
│ 1. Redistributions of source code must retain the above copyright │
│ notice, this list of conditions and the following disclaimer. │
│ 2. Redistributions in binary form must reproduce the above copyright │
│ notice, this list of conditions and the following disclaimer in the │
│ documentation and/or other materials provided with the distribution. │
│ 3. Neither the name of the University nor the names of its contributors │
│ may be used to endorse or promote products derived from this software │
│ without specific prior written permission. │
│ │
│ THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND │
│ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE │
│ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE │
│ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE │
│ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL │
│ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS │
│ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) │
│ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT │
│ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY │
│ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF │
│ SUCH DAMAGE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/dns/dns.h"
#include "libc/errno.h"
#include "libc/log/bsd.h"
#include "libc/mem/fmt.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/struct/pollfd.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/ex.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/poll.h"
#include "libc/sysv/consts/sock.h"
#include "third_party/getopt/getopt.h"
// clang-format off
asm(".ident\t\"\\n\\n\
FreeBSD Whois (BSD-3 License)\\n\
Copyright (c) 1980, 1993\\n\
\tThe Regents of the University of California.\\n\
\tAll rights reserved.\"");
asm(".include \"libc/disclaimer.inc\"");
#define ABUSEHOST "whois.abuse.net"
#define ANICHOST "whois.arin.net"
#define DENICHOST "whois.denic.de"
#define DKNICHOST "whois.dk-hostmaster.dk"
#define FNICHOST "whois.afrinic.net"
#define GNICHOST "whois.nic.gov"
#define IANAHOST "whois.iana.org"
#define INICHOST "whois.internic.net"
#define KNICHOST "whois.krnic.net"
#define LNICHOST "whois.lacnic.net"
#define MNICHOST "whois.ra.net"
#define PDBHOST "whois.peeringdb.com"
#define PNICHOST "whois.apnic.net"
#define QNICHOST_TAIL ".whois-servers.net"
#define RNICHOST "whois.ripe.net"
#define VNICHOST "whois.verisign-grs.com"
#define DEFAULT_PORT "whois"
#define WHOIS_RECURSE 0x01
#define WHOIS_QUICK 0x02
#define WHOIS_SPAM_ME 0x04
#define CHOPSPAM ">>> Last update of WHOIS database:"
#define ishost(h) (isalnum((unsigned char)h) || h == '.' || h == '-')
#define SCAN(p, end, check) \
while ((p) < (end)) \
if (check) ++(p); \
else break
static struct {
const char *suffix, *server;
} whoiswhere[] = {
/* Various handles */
{ "-ARIN", ANICHOST },
{ "-NICAT", "at" QNICHOST_TAIL },
{ "-NORID", "no" QNICHOST_TAIL },
{ "-RIPE", RNICHOST },
/* Nominet's whois server doesn't return referrals to JANET */
{ ".ac.uk", "ac.uk" QNICHOST_TAIL },
{ ".gov.uk", "ac.uk" QNICHOST_TAIL },
{ "", IANAHOST }, /* default */
{ NULL, NULL } /* safety belt */
};
#define WHOIS_REFERRAL(s) { s, sizeof(s) - 1 }
static struct {
const char *prefix;
size_t len;
} whois_referral[] = {
WHOIS_REFERRAL("whois:"), /* IANA */
WHOIS_REFERRAL("Whois Server:"),
WHOIS_REFERRAL("Registrar WHOIS Server:"), /* corporatedomains.com */
WHOIS_REFERRAL("ReferralServer: whois://"), /* ARIN */
WHOIS_REFERRAL("ReferralServer: rwhois://"), /* ARIN */
WHOIS_REFERRAL("descr: region. Please query"), /* AfriNIC */
{ NULL, 0 }
};
/*
* We have a list of patterns for RIRs that assert ignorance rather than
* providing referrals. If that happens, we guess that ARIN will be more
* helpful. But, before following a referral to an RIR, we check if we have
* asked that RIR already, and if so we make another guess.
*/
static const char *actually_arin[] = {
"netname: ERX-NETBLOCK\n", /* APNIC */
"netname: NON-RIPE-NCC-MANAGED-ADDRESS-BLOCK\n",
NULL
};
static struct {
int loop;
const char *host;
} try_rir[] = {
{ 0, ANICHOST },
{ 0, RNICHOST },
{ 0, PNICHOST },
{ 0, FNICHOST },
{ 0, LNICHOST },
{ 0, NULL }
};
static void
reset_rir(void) {
int i;
for (i = 0; try_rir[i].host != NULL; i++)
try_rir[i].loop = 0;
}
static const char *port = DEFAULT_PORT;
static const char *choose_server(char *);
static struct addrinfo *gethostinfo(const char *, const char *, int);
static void s_asprintf(char **ret, const char *format, ...);
static void usage(void);
static void whois(const char *, const char *, const char *, int);
int
main(int argc, char *argv[])
{
const char *country, *host;
int ch, flags;
#ifdef SOCKS
SOCKSinit(argv[0]);
#endif
country = host = NULL;
flags = 0;
while ((ch = getopt(argc, argv, "aAbc:fgh:iIklmp:PQrRS")) != -1) {
switch (ch) {
case 'a':
host = ANICHOST;
break;
case 'A':
host = PNICHOST;
break;
case 'b':
host = ABUSEHOST;
break;
case 'c':
country = optarg;
break;
case 'f':
host = FNICHOST;
break;
case 'g':
host = GNICHOST;
break;
case 'h':
host = optarg;
break;
case 'i':
host = INICHOST;
break;
case 'I':
host = IANAHOST;
break;
case 'k':
host = KNICHOST;
break;
case 'l':
host = LNICHOST;
break;
case 'm':
host = MNICHOST;
break;
case 'p':
port = optarg;
break;
case 'P':
host = PDBHOST;
break;
case 'Q':
flags |= WHOIS_QUICK;
break;
case 'r':
host = RNICHOST;
break;
case 'R':
flags |= WHOIS_RECURSE;
break;
case 'S':
flags |= WHOIS_SPAM_ME;
break;
case '?':
default:
usage();
/* NOTREACHED */
}
}
argc -= optind;
argv += optind;
if (!argc || (country != NULL && host != NULL))
usage();
/*
* If no host or country is specified, rely on referrals from IANA.
*/
if (host == NULL && country == NULL) {
if ((host = getenv("WHOIS_SERVER")) == NULL &&
(host = getenv("RA_SERVER")) == NULL) {
if (!(flags & WHOIS_QUICK))
flags |= WHOIS_RECURSE;
}
}
while (argc-- > 0) {
if (country != NULL) {
char *qnichost;
s_asprintf(&qnichost, "%s%s", country, QNICHOST_TAIL);
whois(*argv, qnichost, port, flags);
free(qnichost);
} else
whois(*argv, host != NULL ? host :
choose_server(*argv), port, flags);
reset_rir();
argv++;
}
exit(0);
}
static const char *
choose_server(char *domain)
{
size_t len = strlen(domain);
int i;
for (i = 0; whoiswhere[i].suffix != NULL; i++) {
size_t suffix_len = strlen(whoiswhere[i].suffix);
if (len > suffix_len &&
strcasecmp(domain + len - suffix_len,
whoiswhere[i].suffix) == 0)
return (whoiswhere[i].server);
}
errx(EX_SOFTWARE, "no default whois server");
}
static struct addrinfo *
gethostinfo(const char *host, const char *hport, int exit_on_noname)
{
struct addrinfo hints, *res;
int error;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
res = NULL;
error = getaddrinfo(host, hport, &hints, &res);
if (error && (exit_on_noname || error != EAI_NONAME))
err(EX_NOHOST, "%s: %s", host, gai_strerror(error));
return (res);
}
/*
* Wrapper for asprintf(3) that exits on error.
*/
static void
s_asprintf(char **ret, const char *format, ...)
{
va_list ap;
va_start(ap, format);
if (vasprintf(ret, format, ap) == -1) {
va_end(ap);
err(EX_OSERR, "vasprintf()");
}
va_end(ap);
}
static int
connect_to_any_host(struct addrinfo *hostres)
{
struct addrinfo *res;
nfds_t i, j;
size_t count;
struct pollfd *fds;
int timeout = 180, s = -1;
for (res = hostres, count = 0; res; res = res->ai_next)
count++;
fds = calloc(count, sizeof(*fds));
if (fds == NULL)
err(EX_OSERR, "calloc()");
/*
* Traverse the result list elements and make non-block
* connection attempts.
*/
count = i = 0;
for (res = hostres; res != NULL; res = res->ai_next) {
s = socket(res->ai_family, res->ai_socktype | SOCK_NONBLOCK,
res->ai_protocol);
if (s < 0)
continue;
if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
if (errno == EINPROGRESS) {
/* Add the socket to poll list */
fds[i].fd = s;
fds[i].events = POLLERR | POLLHUP |
POLLIN | POLLOUT;
/*
* From here until a socket connects, the
* socket fd is owned by the fds[] poll array.
*/
s = -1;
count++;
i++;
} else {
close(s);
s = -1;
/*
* Poll only if we have something to poll,
* otherwise just go ahead and try next
* address
*/
if (count == 0)
continue;
}
} else
goto done;
/*
* If we are at the last address, poll until a connection is
* established or we failed all connection attempts.
*/
if (res->ai_next == NULL)
timeout = INFTIM;
/*
* Poll the watched descriptors for successful connections:
* if we still have more untried resolved addresses, poll only
* once; otherwise, poll until all descriptors have errors,
* which will be considered as ETIMEDOUT later.
*/
do {
int n;
n = poll(fds, i, timeout);
if (n == 0) {
/*
* No event reported in time. Try with a
* smaller timeout (but cap at 2-3ms)
* after a new host have been added.
*/
if (timeout >= 3)
timeout >>= 1;
break;
} else if (n < 0) {
/*
* errno here can only be EINTR which we would
* want to clean up and bail out.
*/
s = -1;
goto done;
}
/*
* Check for the event(s) we have seen.
*/
for (j = 0; j < i; j++) {
if (fds[j].fd == -1 || fds[j].events == 0 ||
fds[j].revents == 0)
continue;
if (fds[j].revents & ~(POLLIN | POLLOUT)) {
close(fds[j].fd);
fds[j].fd = -1;
fds[j].events = 0;
count--;
continue;
} else if (fds[j].revents & (POLLIN | POLLOUT)) {
/* Connect succeeded. */
s = fds[j].fd;
fds[j].fd = -1;
goto done;
}
}
} while (timeout == INFTIM && count != 0);
}
/* All attempts were failed */
s = -1;
if (count == 0)
errno = ETIMEDOUT;
done:
/* Close all watched fds except the succeeded one */
for (j = 0; j < i; j++)
if (fds[j].fd != -1)
close(fds[j].fd);
free(fds);
return (s);
}
static void
whois(const char *query, const char *hostname, const char *hostport, int flags)
{
FILE *fp;
struct addrinfo *hostres;
char *buf, *host, *nhost, *nport, *p;
int comment, s, f;
size_t len, i;
hostres = gethostinfo(hostname, hostport, 1);
s = connect_to_any_host(hostres);
if (s == -1)
err(EX_OSERR, "connect()");
/* Restore default blocking behavior. */
if ((f = fcntl(s, F_GETFL)) == -1)
err(EX_OSERR, "fcntl()");
f &= ~O_NONBLOCK;
if (fcntl(s, F_SETFL, f) == -1)
err(EX_OSERR, "fcntl()");
fp = fdopen(s, "r+");
if (fp == NULL)
err(EX_OSERR, "fdopen()");
if (!(flags & WHOIS_SPAM_ME) &&
(strcasecmp(hostname, DENICHOST) == 0 ||
strcasecmp(hostname, "de" QNICHOST_TAIL) == 0)) {
const char *q;
int idn = 0;
for (q = query; *q != '\0'; q++)
if (!isascii(*q))
idn = 1;
fprintf(fp, "-T dn%s %s\r\n", idn ? "" : ",ace", query);
} else if (!(flags & WHOIS_SPAM_ME) &&
(strcasecmp(hostname, DKNICHOST) == 0 ||
strcasecmp(hostname, "dk" QNICHOST_TAIL) == 0))
fprintf(fp, "--show-handles %s\r\n", query);
else if ((flags & WHOIS_SPAM_ME) ||
strchr(query, ' ') != NULL)
fprintf(fp, "%s\r\n", query);
else if (strcasecmp(hostname, ANICHOST) == 0) {
if (strncasecmp(query, "AS", 2) == 0 &&
strspn(query+2, "0123456789") == strlen(query+2))
fprintf(fp, "+ a %s\r\n", query+2);
else
fprintf(fp, "+ %s\r\n", query);
} else if (strcasecmp(hostres->ai_canonname, VNICHOST) == 0)
fprintf(fp, "domain %s\r\n", query);
else
fprintf(fp, "%s\r\n", query);
fflush(fp);
comment = 0;
if (!(flags & WHOIS_SPAM_ME) &&
(strcasecmp(hostname, ANICHOST) == 0 ||
strcasecmp(hostname, RNICHOST) == 0)) {
comment = 2;
}
nhost = NULL;
while ((buf = fgetln(fp, &len)) != NULL) {
/* Nominet */
if (!(flags & WHOIS_SPAM_ME) &&
len == 5 && strncmp(buf, "-- \r\n", 5) == 0)
break;
/* RIRs */
if (comment == 1 && buf[0] == '#')
break;
else if (comment == 2) {
if (strchr("#%\r\n", buf[0]) != NULL)
continue;
else
comment = 1;
}
printf("%.*s", (int)len, buf);
if ((flags & WHOIS_RECURSE) && nhost == NULL) {
for (i = 0; whois_referral[i].prefix != NULL; i++) {
p = buf;
SCAN(p, buf+len, *p == ' ');
if (strncasecmp(p, whois_referral[i].prefix,
whois_referral[i].len) != 0)
continue;
p += whois_referral[i].len;
SCAN(p, buf+len, *p == ' ');
host = p;
SCAN(p, buf+len, ishost(*p));
if (p > host) {
char *pstr;
s_asprintf(&nhost, "%.*s",
(int)(p - host), host);
if (*p != ':') {
s_asprintf(&nport, "%s", port);
break;
}
pstr = ++p;
SCAN(p, buf+len, isdigit(*p));
if (p > pstr && (p - pstr) < 6) {
s_asprintf(&nport, "%.*s",
(int)(p - pstr), pstr);
break;
}
/* Invalid port; don't recurse */
free(nhost);
nhost = NULL;
}
break;
}
for (i = 0; actually_arin[i] != NULL; i++) {
if (strncmp(buf, actually_arin[i], len) == 0) {
s_asprintf(&nhost, "%s", ANICHOST);
s_asprintf(&nport, "%s", port);
break;
}
}
}
/* Verisign etc. */
if (!(flags & WHOIS_SPAM_ME) &&
len >= sizeof(CHOPSPAM)-1 &&
(strncasecmp(buf, CHOPSPAM, sizeof(CHOPSPAM)-1) == 0 ||
strncasecmp(buf, CHOPSPAM+4, sizeof(CHOPSPAM)-5) == 0)) {
printf("\n");
break;
}
}
fclose(fp);
freeaddrinfo(hostres);
f = 0;
for (i = 0; try_rir[i].host != NULL; i++) {
/* Remember visits to RIRs */
if (try_rir[i].loop == 0 &&
strcasecmp(try_rir[i].host, hostname) == 0)
try_rir[i].loop = 1;
/* Do we need to find an alternative RIR? */
if (try_rir[i].loop != 0 && nhost != NULL &&
strcasecmp(try_rir[i].host, nhost) == 0) {
free(nhost);
nhost = NULL;
free(nport);
nport = NULL;
f = 1;
}
}
if (f) {
/* Find a replacement RIR */
for (i = 0; try_rir[i].host != NULL; i++) {
if (try_rir[i].loop == 0) {
s_asprintf(&nhost, "%s", try_rir[i].host);
s_asprintf(&nport, "%s", port);
break;
}
}
}
if (nhost != NULL) {
/* Ignore self-referrals */
if (strcasecmp(hostname, nhost) != 0) {
printf("# %s\n\n", nhost);
whois(query, nhost, nport, flags);
}
free(nhost);
free(nport);
}
}
static void
usage(void)
{
fprintf(stderr,
"usage: whois [-aAbfgiIklmPQrRS] [-c country-code | -h hostname] "
"[-p port] name ...\n");
exit(EX_USAGE);
}
+2 -3
View File
@@ -7,10 +7,9 @@ extern bool __assert_disable;
void __assert_fail(const char *, const char *, int) hidden relegated;
#ifdef NDEBUG
#define assert(EXPR) ((void)0)
#define assert(x) ((void)0)
#else
#define assert(EXPR) \
((void)((EXPR) || (__assert_fail(#EXPR, __FILE__, __LINE__), 0)))
#define assert(x) ((void)((x) || (__assert_fail(#x, __FILE__, __LINE__), 0)))
#endif
#ifndef __cplusplus
@@ -16,45 +16,78 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/fmt/conv.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/itoa.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/testlib/subprocess.h"
#include "libc/testlib/testlib.h"
#include "libc/sysv/consts/termios.h"
#include "libc/sysv/errfuns.h"
#define N 127
extern const unsigned FIODGNAME;
extern const unsigned TIOCPTSNAME;
extern const unsigned TIOCPTYGNAME;
char *GenBuf(char buf[8], int x) {
int i;
bzero(buf, 8);
for (i = 0; i < 7; ++i) {
buf[i] = x & 127; // nt doesn't respect invalid unicode?
x >>= 1;
struct fiodgname_arg {
int len;
void *buf;
};
struct ptmget {
int cfd;
int sfd;
char cn[1024];
char sn[1024];
};
int _ptsname(int fd, char *buf, size_t size) {
int pty;
size_t n;
struct ptmget t;
if (_isptmaster(fd)) {
return -1;
}
return buf;
}
__attribute__((__constructor__)) static void init(void) {
char buf[8];
if (__argc == 4 && !strcmp(__argv[1], "-")) {
ASSERT_STREQ(GenBuf(buf, atoi(__argv[2])), __argv[3]);
exit(0);
t.sn[0] = '/';
t.sn[1] = 'd';
t.sn[2] = 'e';
t.sn[3] = 'v';
t.sn[4] = '/';
t.sn[5] = 0;
if (IsLinux()) {
if (sys_ioctl(fd, TIOCGPTN, &pty)) return -1;
t.sn[5] = 'p';
t.sn[6] = 't';
t.sn[7] = 's';
t.sn[8] = '/';
FormatInt32(t.sn + 9, pty);
} else if (IsXnu()) {
if (sys_ioctl(fd, TIOCPTYGNAME, t.sn)) {
return -1;
}
} else if (IsFreebsd()) {
struct fiodgname_arg fgn = {sizeof(t.sn) - 5, t.sn + 5};
if (sys_ioctl(fd, FIODGNAME, &fgn) == -1) {
if (errno == EINVAL) {
errno = ERANGE;
}
return -1;
}
} else if (IsNetbsd()) {
if (sys_ioctl(fd, TIOCPTSNAME, &t)) {
return -1;
}
} else {
return enosys();
}
}
TEST(execve, testArgPassing) {
int i;
char ibuf[12], buf[8];
for (i = 0; i < N; ++i) {
FormatInt32(ibuf, i);
GenBuf(buf, i);
SPAWN(vfork);
execve(GetProgramExecutableName(),
(char *const[]){GetProgramExecutableName(), "-", ibuf, buf, 0},
(char *const[]){0});
notpossible;
EXITS(0);
if ((n = strlen(t.sn)) < size) {
memcpy(buf, t.sn, n + 1);
return 0;
} else {
return erange();
}
}
+1 -5
View File
@@ -19,13 +19,9 @@
#include "libc/assert.h"
#include "libc/calls/struct/timespec.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/consts/nr.h"
#include "libc/time/time.h"
struct timespec _timespec_mono(void) {
int ax, dx;
struct timespec ts;
ax = clock_gettime(CLOCK_MONOTONIC_FAST, &ts);
assert(!ax);
_npassert(!clock_gettime(CLOCK_MONOTONIC_FAST, &ts));
return ts;
}
+2 -5
View File
@@ -16,15 +16,12 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/calls/struct/timespec.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/consts/nr.h"
#include "libc/time/time.h"
struct timespec _timespec_real(void) {
int ax, dx;
struct timespec ts;
ax = clock_gettime(CLOCK_REALTIME_FAST, &ts);
if (ax) notpossible;
_npassert(!clock_gettime(CLOCK_REALTIME_FAST, &ts));
return ts;
}
+2
View File
@@ -27,6 +27,8 @@ int64_t _timespec_tomicros(struct timespec x) {
if (!__builtin_mul_overflow(x.tv_sec, 1000000ul, &us) &&
!__builtin_add_overflow(us, x.tv_nsec / 1000, &us)) {
return us;
} else if (x.tv_sec < 0) {
return INT64_MIN;
} else {
return INT64_MAX;
}
+2
View File
@@ -27,6 +27,8 @@ int64_t _timespec_tomillis(struct timespec x) {
if (!__builtin_mul_overflow(x.tv_sec, 1000ul, &ms) &&
!__builtin_add_overflow(ms, x.tv_nsec / 1000000, &ms)) {
return ms;
} else if (x.tv_sec < 0) {
return INT64_MIN;
} else {
return INT64_MAX;
}
+2
View File
@@ -27,6 +27,8 @@ int64_t _timespec_tonanos(struct timespec x) {
if (!__builtin_mul_overflow(x.tv_sec, 1000000000ul, &ns) &&
!__builtin_add_overflow(ns, x.tv_nsec, &ns)) {
return ns;
} else if (x.tv_sec < 0) {
return INT64_MIN;
} else {
return INT64_MAX;
}
+1
View File
@@ -97,6 +97,7 @@ o/$(MODE)/libc/calls/ntcontext2linux.o: private \
# we always want -O3 because:
# it makes the code size smaller too
o/$(MODE)/libc/calls/termios2host.o \
o/$(MODE)/libc/calls/sigenter-freebsd.o \
o/$(MODE)/libc/calls/sigenter-netbsd.o \
o/$(MODE)/libc/calls/sigenter-openbsd.o \
+25 -16
View File
@@ -26,35 +26,36 @@
#include "libc/nt/synchronization.h"
#include "libc/sysv/errfuns.h"
textwindows int sys_chdir_nt(const char *path) {
textwindows int sys_chdir_nt_impl(char16_t path[hasatleast PATH_MAX],
uint32_t len) {
uint32_t n;
int e, ms, err, len;
char16_t path16[PATH_MAX], var[4];
if ((len = __mkntpath(path, path16)) == -1) return -1;
if (!len) return enoent();
if (len && path16[len - 1] != u'\\') {
int e, ms, err;
char16_t var[4];
if (len && path[len - 1] != u'\\') {
if (len + 2 > PATH_MAX) return enametoolong();
path16[len + 0] = u'\\';
path16[len + 1] = u'\0';
path[len + 0] = u'\\';
path[len + 1] = u'\0';
}
/*
* chdir() seems flaky on windows 7
* in a similar way to rmdir() sigh
*/
for (err = errno, ms = 1;; ms *= 2) {
if (SetCurrentDirectory(path16)) {
if (SetCurrentDirectory(path)) {
/*
* Now we need to set a magic environment variable.
*/
if ((n = GetCurrentDirectory(ARRAYLEN(path16), path16))) {
if (n < ARRAYLEN(path16)) {
if (!((path16[0] == '/' && path16[1] == '/') ||
(path16[0] == '\\' && path16[1] == '\\'))) {
if ((n = GetCurrentDirectory(PATH_MAX, path))) {
if (n < PATH_MAX) {
if (!((path[0] == '/' && path[1] == '/') ||
(path[0] == '\\' && path[1] == '\\'))) {
var[0] = '=';
var[1] = path16[0];
var[1] = path[0];
var[2] = ':';
var[3] = 0;
if (!SetEnvironmentVariable(var, path16)) {
if (!SetEnvironmentVariable(var, path)) {
return __winerr();
}
}
@@ -77,5 +78,13 @@ textwindows int sys_chdir_nt(const char *path) {
}
}
}
return __fix_enotdir(-1, path16);
return __fix_enotdir(-1, path);
}
textwindows int sys_chdir_nt(const char *path) {
int len;
char16_t path16[PATH_MAX];
if ((len = __mkntpath(path, path16)) == -1) return -1;
if (!len) return enoent();
return sys_chdir_nt_impl(path16, len);
}
+15 -21
View File
@@ -17,10 +17,10 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/errno.h"
#include "libc/limits.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/errfuns.h"
/**
* Closes inclusive range of file descriptors, e.g.
@@ -32,33 +32,27 @@
* }
* }
*
* This is supported on Linux 5.9+, FreeBSD, and OpenBSD. On FreeBSD,
* `flags` must be zero. On OpenBSD, we call closefrom(int) so `last`
* should be `-1` in order to get OpenBSD support, otherwise `ENOSYS`
* will be returned. We also polyfill closefrom on FreeBSD since it's
* available on older kernels.
* The following flags are available:
*
* On Linux, the following flags are supported:
* - `CLOSE_RANGE_UNSHARE` (Linux-only)
* - `CLOSE_RANGE_CLOEXEC` (Linux-only)
*
* - CLOSE_RANGE_UNSHARE
* - CLOSE_RANGE_CLOEXEC
* This is only supported on Linux 5.9+ and FreeBSD 13+. Consider using
* closefrom() which will work on OpenBSD too.
*
* @return 0 on success, or -1 w/ errno
* @error ENOSYS if not Linux 5.9+ / FreeBSD / OpenBSD
* @error EBADF on OpenBSD if `first` is greater than highest fd
* @error EINVAL if flags are bad or first is greater than last
* @error EMFILE if a weird race condition happens on Linux
* @error EINTR possibly on OpenBSD
* @error ENOSYS if not Linux 5.9+ or FreeBSD 13+
* @error ENOMEM on Linux maybe
* @see closefrom()
*/
int close_range(unsigned int first, unsigned int last, unsigned int flags) {
int rc, err;
err = errno;
if ((rc = sys_close_range(first, last, flags)) == -1) {
if (errno == ENOSYS && first <= INT_MAX && last == UINT_MAX && !flags) {
errno = err;
rc = sys_closefrom(first);
}
int rc;
if (IsLinux() || IsFreebsd()) {
rc = sys_close_range(first, last, flags);
} else {
rc = enosys();
}
STRACE("close_range(%d, %d, %#x) → %d% m", first, last, flags, rc);
return rc;
+14 -12
View File
@@ -17,9 +17,10 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/strace.internal.h"
#include "libc/limits.h"
#include "libc/sysv/errfuns.h"
@@ -34,26 +35,27 @@
* }
*
* @return 0 on success, or -1 w/ errno
* @error ENOSYS if not Linux 5.9+ / FreeBSD / OpenBSD
* @error EBADF if `first` is negative
* @error EBADF on OpenBSD if `first` is greater than highest fd
* @error EINVAL if flags are bad or first is greater than last
* @error EMFILE if a weird race condition happens on Linux
* @error ENOSYS if not Linux 5.9+, FreeBSD 8+, or OpenBSD
* @error EINTR possibly on OpenBSD
* @error ENOMEM on Linux maybe
* @note supported on Linux 5.9+, FreeBSD 8+, and OpenBSD
*/
int closefrom(int first) {
int rc, err;
if (first >= 0) {
err = errno;
if ((rc = sys_close_range(first, -1, 0)) == -1) {
if (errno == ENOSYS) {
errno = err;
rc = sys_closefrom(first);
}
}
} else {
if (IsNetbsd() || IsWindows() || IsMetal()) {
rc = enosys();
} else if (first < 0) {
// consistent with openbsd
// freebsd allows this but it's dangerous
// necessary on linux due to type signature
rc = ebadf();
} else if (IsLinux()) {
rc = sys_close_range(first, 0xffffffffu, 0);
} else {
rc = sys_closefrom(first);
}
STRACE("closefrom(%d) → %d% m", first, rc);
return rc;
+115
View File
@@ -0,0 +1,115 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2022 Justine Alexandra Roberts Tunney │
│ │
│ Permission to use, copy, modify, and/or distribute this software for │
│ any purpose with or without fee is hereby granted, provided that the │
│ above copyright notice and this permission notice appear in all copies. │
│ │
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/thread.h"
static struct CopyFileRange {
pthread_once_t once;
bool ok;
} g_copy_file_range;
static bool HasCopyFileRange(void) {
bool ok;
int e, rc;
e = errno;
if (IsLinux()) {
// We modernize our detection by a few years for simplicity.
// This system call is chosen since it's listed by pledge().
// https://www.cygwin.com/bugzilla/show_bug.cgi?id=26338
ok = sys_close_range(-1, -2, 0) == -1 && errno == EINVAL;
} else if (IsFreebsd()) {
ok = sys_copy_file_range(-1, 0, -1, 0, 0, 0) == -1 && errno == EBADF;
} else {
ok = false;
}
errno = e;
return ok;
}
static void copy_file_range_init(void) {
g_copy_file_range.ok = HasCopyFileRange();
}
/**
* Transfers data between files.
*
* If this system call is available (Linux c. 2018 or FreeBSD c. 2021)
* and the file system supports it (e.g. ext4) and the source and dest
* files are on the same file system, then this system call shall make
* copies go about 2x faster.
*
* This implementation requires Linux 5.9+ even though the system call
* was introduced in Linux 4.5. That's to ensure ENOSYS works reliably
* due to a faulty backport, that happened in RHEL7. FreeBSD detection
* on the other hand will work fine.
*
* @param infd is source file, which should be on same file system
* @param opt_in_out_inoffset may be specified for pread() behavior
* @param outfd should be a writable file, but not `O_APPEND`
* @param opt_in_out_outoffset may be specified for pwrite() behavior
* @param uptobytes is maximum number of bytes to transfer
* @param flags is reserved for future use and must be zero
* @return number of bytes transferred, or -1 w/ errno
* @raise EXDEV if source and destination are on different filesystems
* @raise EBADF if `infd` or `outfd` aren't open files or append-only
* @raise EPERM if `fdout` refers to an immutable file on Linux
* @raise EINVAL if ranges overlap or `flags` is non-zero
* @raise EFBIG if `setrlimit(RLIMIT_FSIZE)` is exceeded
* @raise EFAULT if one of the pointers memory is bad
* @raise ERANGE if overflow happens computing ranges
* @raise ENOSPC if file system has run out of space
* @raise ETXTBSY if source or dest is a swap file
* @raise EINTR if a signal was delivered instead
* @raise EISDIR if source or dest is a directory
* @raise ENOSYS if not Linux 5.9+ or FreeBSD 13+
* @raise EIO if a low-level i/o error happens
* @see sendfile() for seekable → socket
* @see splice() for fd ↔ pipe
*/
ssize_t copy_file_range(int infd, int64_t *opt_in_out_inoffset, int outfd,
int64_t *opt_in_out_outoffset, size_t uptobytes,
uint32_t flags) {
ssize_t rc;
pthread_once(&g_copy_file_range.once, copy_file_range_init);
if (!g_copy_file_range.ok) {
rc = enosys();
} else if (IsAsan() && ((opt_in_out_inoffset &&
!__asan_is_valid(opt_in_out_inoffset, 8)) ||
(opt_in_out_outoffset &&
!__asan_is_valid(opt_in_out_outoffset, 8)))) {
rc = efault();
} else {
rc = sys_copy_file_range(infd, opt_in_out_inoffset, outfd,
opt_in_out_outoffset, uptobytes, flags);
}
STRACE("copy_file_range(%d, %s, %d, %s, %'zu, %#x) → %'ld% m", infd,
DescribeInOutInt64(rc, opt_in_out_inoffset), outfd,
DescribeInOutInt64(rc, opt_in_out_outoffset), uptobytes, flags);
return rc;
}
-66
View File
@@ -1,66 +0,0 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ Permission to use, copy, modify, and/or distribute this software for │
│ any purpose with or without fee is hereby granted, provided that the │
│ above copyright notice and this permission notice appear in all copies. │
│ │
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/macros.internal.h"
/**
* Copies data between file descriptors the slow way.
*
* @return -1 on error/interrupt, 0 on eof, or [1..size] on success
* @see copy_file_range() for file ↔ file
* @see sendfile() for seekable → socket
* @see splice() for fd ↔ pipe
*/
ssize_t copyfd(int infd, int64_t *inoutopt_inoffset, int outfd,
int64_t *inoutopt_outoffset, size_t size, uint32_t flags) {
ssize_t rc;
char buf[2048];
size_t i, j, n;
for (i = 0; i < size; i += j) {
n = MIN(size - i, sizeof(buf));
if (inoutopt_inoffset) {
rc = pread(infd, buf, n, *inoutopt_inoffset);
} else {
rc = read(infd, buf, n);
}
if (!rc) return i;
if (rc == -1) {
if (i) return i;
return -1;
}
n = rc;
for (j = 0; j < n; j += rc) {
TryAgain:
if (inoutopt_outoffset) {
rc = pwrite(outfd, buf + j, n - j, *inoutopt_outoffset);
} else {
rc = write(outfd, buf + j, n - j);
}
if (rc == -1) {
if (errno == EINTR) goto TryAgain;
if (errno == EWOULDBLOCK) goto TryAgain; /* suboptimal */
return -1;
}
if (inoutopt_inoffset) *inoutopt_inoffset += rc;
if (inoutopt_outoffset) *inoutopt_outoffset += rc;
}
}
return i;
}
+5 -7
View File
@@ -16,6 +16,7 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/state.internal.h"
@@ -27,15 +28,12 @@
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
/**
* Implements dup(), dup2(), dup3(), and F_DUPFD for Windows.
*/
// Implements dup(), dup2(), dup3(), and F_DUPFD for Windows.
textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
int64_t rc, proc, handle;
// validate the api usage
if (oldfd < 0) return ebadf();
if (flags & ~O_CLOEXEC) return einval();
_unassert(oldfd >= 0);
_unassert(newfd >= -1);
_unassert(!(flags & ~O_CLOEXEC));
__fds_lock();
+1 -1
View File
@@ -18,10 +18,10 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/errfuns.h"
/**
+33 -22
View File
@@ -16,41 +16,52 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/intrin/strace.internal.h"
#include "libc/assert.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/thread.h"
#define F_DUP2FD 10
#define F_DUP2FD_CLOEXEC 18
int32_t sys_dup3(int32_t oldfd, int32_t newfd, int flags) {
static bool once;
static bool demodernize;
int olderr, how, fd;
if (!once) {
olderr = errno;
fd = __sys_dup3(oldfd, newfd, flags);
if (fd == -1 && errno == ENOSYS) {
STRACE("demodernizing %s() due to %s", "dup3", "RHEL5:CVE-2010-3301");
demodernize = true;
once = true;
errno = olderr;
} else {
once = true;
return fd;
}
} else if (!demodernize) {
return __sys_dup3(oldfd, newfd, flags);
static struct Dup3 {
pthread_once_t once;
bool demodernize;
} g_dup3;
static void sys_dup3_test(void) {
int e = errno;
__sys_dup3(-1, -1, 0);
if ((g_dup3.demodernize = errno == ENOSYS)) {
STRACE("demodernizing %s() due to %s", "dup3", "ENOSYS");
}
if (oldfd == newfd) return einval();
if (flags & ~O_CLOEXEC) return einval();
errno = e;
}
int32_t sys_dup3(int32_t oldfd, int32_t newfd, int flags) {
int how;
_unassert(oldfd >= 0);
_unassert(newfd >= 0);
_unassert(!(flags & ~O_CLOEXEC));
if (IsFreebsd()) {
how = flags & O_CLOEXEC ? F_DUP2FD_CLOEXEC : F_DUP2FD;
if (flags & O_CLOEXEC) {
how = F_DUP2FD_CLOEXEC;
} else {
how = F_DUP2FD;
}
return __sys_fcntl(oldfd, how, newfd);
}
pthread_once(&g_dup3.once, sys_dup3_test);
if (!g_dup3.demodernize) {
return __sys_dup3(oldfd, newfd, flags);
} else {
return __fixupnewfd(sys_dup2(oldfd, newfd), flags);
}
+7 -6
View File
@@ -18,10 +18,11 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
/**
@@ -46,14 +47,14 @@
*/
int dup3(int oldfd, int newfd, int flags) {
int rc;
if (__isfdkind(oldfd, kFdZip)) {
if (oldfd == newfd || (flags & ~O_CLOEXEC)) {
rc = einval(); // NetBSD doesn't do this
} else if (oldfd < 0 || newfd < 0) {
rc = ebadf();
} else if (__isfdkind(oldfd, kFdZip)) {
rc = eopnotsupp();
} else if (oldfd == newfd) {
rc = einval();
} else if (!IsWindows()) {
rc = sys_dup3(oldfd, newfd, flags);
} else if (newfd < 0) {
rc = ebadf();
} else {
rc = sys_dup_nt(oldfd, newfd, flags, -1);
}
-4
View File
@@ -35,10 +35,6 @@
/**
* Replaces current process with program.
*
* On Windows, `argv` and `envp` can't contain binary strings. They need
* to be valid UTF-8 in order to round-trip the WIN32 API, without being
* corrupted.
*
* @param program will not be PATH searched, see commandv()
* @param argv[0] is the name of the program to run
* @param argv[1,n-2] optionally specify program arguments
+6
View File
@@ -21,6 +21,7 @@
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/nt/createfile.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/nt/enum/filetype.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/sysv/consts/madv.h"
@@ -33,6 +34,7 @@ textwindows int sys_fadvise_nt(int fd, uint64_t offset, uint64_t len,
int rc, flags, mode;
uint32_t perm, share, attr;
if ((int64_t)len < 0) return einval();
if (!__isfdkind(fd, kFdFile)) return ebadf();
h1 = g_fds.p[fd].handle;
mode = g_fds.p[fd].mode;
@@ -57,6 +59,10 @@ textwindows int sys_fadvise_nt(int fd, uint64_t offset, uint64_t len,
return -1;
}
if (GetFileType(h1) == kNtFileTypePipe) {
return espipe();
}
// MSDN says only these are allowed, otherwise it returns EINVAL.
attr &= kNtFileFlagBackupSemantics | kNtFileFlagDeleteOnClose |
kNtFileFlagNoBuffering | kNtFileFlagOpenNoRecall |
+30 -7
View File
@@ -16,11 +16,17 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/strace.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
int sys_fadvise_netbsd(int, int, int64_t, int64_t, int) asm("sys_fadvise");
/**
* Drops hints to O/S about intended I/O behavior.
@@ -28,16 +34,33 @@
* It makes a huge difference. For example, when copying a large file,
* it can stop the system from persisting GBs of useless memory content.
*
* @param len 0 means ‘til end of file
* @param len 0 means until end of file
* @param advice can be MADV_SEQUENTIAL, MADV_RANDOM, etc.
* @return -1 on error
* @return 0 on success, or -1 w/ errno
* @raise EBADF if `fd` isn't a valid file descriptor
* @raise ESPIPE if `fd` refers to a pipe
* @raise EINVAL if `advice` was invalid
* @raise ENOSYS on XNU and OpenBSD
*/
int fadvise(int fd, uint64_t offset, uint64_t len, int advice) {
int rc;
if (!IsWindows()) {
rc = sys_fadvise(fd, offset, len, advice); /* linux & freebsd */
} else {
int rc, e = errno;
if (IsLinux()) {
rc = sys_fadvise(fd, offset, len, advice);
} else if (IsFreebsd() || IsNetbsd()) {
if (IsFreebsd()) {
rc = sys_fadvise(fd, offset, len, advice);
} else {
rc = sys_fadvise_netbsd(fd, offset, offset, len, advice);
}
_npassert(rc >= 0);
if (rc) {
errno = rc;
rc = -1;
}
} else if (IsWindows()) {
rc = sys_fadvise_nt(fd, offset, len, advice);
} else {
rc = enosys();
}
STRACE("fadvise(%d, %'lu, %'lu, %d) → %d% m", fd, offset, len, advice, rc);
return rc;
+5 -13
View File
@@ -23,20 +23,12 @@
#include "libc/nt/files.h"
#include "libc/sysv/errfuns.h"
int sys_chdir_nt_impl(char16_t[hasatleast PATH_MAX], uint32_t);
textwindows int sys_fchdir_nt(int dirfd) {
uint32_t len;
char16_t dir[PATH_MAX];
if (!__isfdkind(dirfd, kFdFile)) return ebadf();
len = GetFinalPathNameByHandle(g_fds.p[dirfd].handle, dir, ARRAYLEN(dir),
kNtFileNameNormalized | kNtVolumeNameDos);
if (len + 1 + 1 > ARRAYLEN(dir)) return enametoolong();
if (dir[len - 1] != u'\\') {
dir[len + 0] = u'\\';
dir[len + 1] = u'\0';
}
if (SetCurrentDirectory(dir)) {
return 0;
} else {
return __winerr();
}
return sys_chdir_nt_impl(
dir, GetFinalPathNameByHandle(g_fds.p[dirfd].handle, dir, ARRAYLEN(dir),
kNtFileNameNormalized | kNtVolumeNameDos));
}
+3 -14
View File
@@ -24,21 +24,14 @@
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/calls/wincrash.internal.h"
#include "libc/errno.h"
#include "libc/intrin/cmpxchg.h"
#include "libc/macros.internal.h"
#include "libc/nt/createfile.h"
#include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/intrin/weaken.h"
#include "libc/log/backtrace.internal.h"
#include "libc/nt/enum/filelockflags.h"
#include "libc/nt/enum/filesharemode.h"
#include "libc/nt/enum/formatmessageflags.h"
#include "libc/nt/errors.h"
#include "libc/nt/files.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/byhandlefileinformation.h"
#include "libc/nt/struct/overlapped.h"
#include "libc/nt/synchronization.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/fd.h"
#include "libc/sysv/consts/o.h"
@@ -105,7 +98,6 @@ static textwindows int sys_fcntl_nt_lock(struct Fd *f, int cmd, uintptr_t arg) {
if (l->l_type == F_WRLCK) {
flags |= kNtLockfileExclusiveLock;
}
e = errno;
ok = LockFileEx(f->handle, flags, 0, len, len >> 32, &ov);
if (cmd == F_GETLK) {
if (ok) {
@@ -118,10 +110,7 @@ static textwindows int sys_fcntl_nt_lock(struct Fd *f, int cmd, uintptr_t arg) {
ok = true;
}
}
if (ok) {
return 0;
} else if (__force_sqlite_to_work_until_we_can_fix_it) {
errno = e;
if (ok || __force_sqlite_to_work_until_we_can_fix_it) {
return 0;
} else {
return -1;
+3 -5
View File
@@ -37,11 +37,9 @@
* CHECK_GE((newfd = fcntl(oldfd, F_DUPFD, 3)), 3);
* CHECK_GE((newfd = fcntl(oldfd, F_DUPFD_CLOEXEC, 3)), 3);
*
* This function implements POSIX Advisory Locks, e.g.
*
* CHECK_NE(-1, fcntl(zfd, F_SETLKW, &(struct flock){F_WRLCK}));
* // ...
* CHECK_NE(-1, fcntl(zfd, F_SETLK, &(struct flock){F_UNLCK}));
* This function implements POSIX Advisory Locks, which let independent
* processes (and on Windows, threads too!) read/write lock byte ranges
* of files. See `test/libc/calls/lock_test.c` for an example.
*
* Please be warned that locks currently do nothing on Windows since
* figuring out how to polyfill them correctly is a work in progress.
+5 -5
View File
@@ -16,19 +16,19 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/fd.h"
#include "libc/sysv/consts/o.h"
/**
* Applies file descriptor fixups on XNU or old Linux.
* @see __fixupnewsockfd() for socket file descriptors
*/
// Applies file descriptor fixups on XNU or old Linux.
// See __fixupnewsockfd() for socket file descriptors.
int __fixupnewfd(int fd, int flags) {
if (fd != -1) {
if (flags & O_CLOEXEC) {
__sys_fcntl(fd, F_SETFD, FD_CLOEXEC);
_npassert(!__sys_fcntl(fd, F_SETFD, FD_CLOEXEC));
}
}
return fd;
+34 -13
View File
@@ -17,28 +17,49 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/internal.h"
#include "libc/calls/struct/fd.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/nt/enum/filelockflags.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/byhandlefileinformation.h"
#include "libc/nt/struct/overlapped.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/lock.h"
#include "libc/sysv/errfuns.h"
#define _LOCK_SH 0
#define _LOCK_EX kNtLockfileExclusiveLock
#define _LOCK_NB kNtLockfileFailImmediately
#define _LOCK_UN 8
textwindows int sys_flock_nt(int fd, int op) {
struct NtOverlapped ov;
int64_t h;
struct NtByHandleFileInformation info;
if (!__isfdkind(fd, kFdFile)) return ebadf();
bzero(&ov, sizeof(ov));
if (GetFileInformationByHandle(g_fds.p[fd].handle, &info) &&
((!(op & LOCK_UN) &&
LockFileEx(g_fds.p[fd].handle, op, 0, info.nFileSizeLow,
info.nFileSizeHigh, &ov)) ||
((op & LOCK_UN) && UnlockFileEx(g_fds.p[fd].handle, 0, info.nFileSizeLow,
info.nFileSizeHigh, &ov)))) {
return 0;
} else {
h = g_fds.p[fd].handle;
struct NtOverlapped ov = {.hEvent = h};
if (!GetFileInformationByHandle(h, &info)) {
return __winerr();
}
if (op & _LOCK_UN) {
if (op & ~_LOCK_UN) {
return einval();
}
if (UnlockFileEx(h, 0, info.nFileSizeLow, info.nFileSizeHigh, &ov)) {
return 0;
} else {
return -1;
}
}
if (op & ~(_LOCK_SH | _LOCK_EX | _LOCK_NB)) {
return einval();
}
if (LockFileEx(h, op, 0, info.nFileSizeLow, info.nFileSizeHigh, &ov)) {
return 0;
} else {
return -1;
}
}
+1 -1
View File
@@ -24,7 +24,7 @@
#include "libc/sysv/errfuns.h"
/**
* Supports fstat(), etc. implementations.
* Forms fstat() on System Five.
* @asyncsignalsafe
*/
int32_t sys_fstat(int32_t fd, struct stat *st) {
+1 -1
View File
@@ -23,7 +23,7 @@
#include "libc/sysv/errfuns.h"
/**
* Supports stat(), lstat(), fstatat(), etc. implementations.
* Performs fstatat() on System Five.
* @asyncsignalsafe
*/
int32_t sys_fstatat(int32_t dirfd, const char *path, struct stat *st,
+2 -13
View File
@@ -22,6 +22,7 @@
#include "libc/calls/weirdtypes.h"
#include "libc/dce.h"
#include "libc/macros.internal.h"
#include "libc/nt/accounting.h"
#include "libc/nt/dll.h"
#include "libc/nt/struct/systeminfo.h"
#include "libc/nt/systeminfo.h"
@@ -61,18 +62,6 @@ static unsigned GetCpuCountBsd(void) {
}
}
static textwindows unsigned GetCpuCountWindows(void) {
struct NtSystemInfo si;
uint32_t (*f)(uint16_t);
if ((f = GetProcAddress(GetModuleHandle("KERNEL32"),
"GetMaximumProcessorCount"))) {
return f(ALL_PROCESSOR_GROUPS);
} else {
GetSystemInfo(&si);
return si.dwNumberOfProcessors;
}
}
static unsigned GetCpuCountImpl(void) {
if (!IsWindows()) {
if (!IsBsd()) {
@@ -81,7 +70,7 @@ static unsigned GetCpuCountImpl(void) {
return GetCpuCountBsd();
}
} else {
return GetCpuCountWindows();
return GetMaximumProcessorCount(ALL_PROCESSOR_GROUPS);
}
}
+1 -1
View File
@@ -17,9 +17,9 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/runtime/runtime.h"
/**
+1 -1
View File
@@ -17,9 +17,9 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
/**
* Returns effective user ID of calling process.
+3 -1
View File
@@ -33,7 +33,9 @@
*/
int getgroups(int size, uint32_t list[]) {
int rc;
if (IsAsan() && size && !__asan_is_valid(list, size * sizeof(list[0]))) {
size_t n;
if (IsAsan() && (__builtin_mul_overflow(size, sizeof(list[0]), &n) ||
!__asan_is_valid(list, n))) {
rc = efault();
} else if (IsLinux() || IsNetbsd() || IsOpenbsd() || IsFreebsd() || IsXnu()) {
rc = sys_getgroups(size, list);
+1 -1
View File
@@ -17,10 +17,10 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/sysinfo.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/errfuns.h"
#define CTL_VM 2
+1 -1
View File
@@ -17,9 +17,9 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/macros.internal.h"
#include "libc/nt/accounting.h"
#include "libc/runtime/runtime.h"
+25 -2
View File
@@ -16,6 +16,29 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/calls/termios.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
int grantpt(int fd) { return 0; }
extern const unsigned TIOCPTYGRANT;
/**
* Grants access to subordinate pseudoteletypewriter.
*
* @return 0 on success, or -1 w/ errno
* @raise EBADF if fd isn't open
* @raise EINVAL if fd is valid but not associated with pty
* @raise EACCES if pseudoterminal couldn't be accessed
*/
int grantpt(int fd) {
int rc;
if (IsXnu()) {
rc = sys_ioctl(fd, TIOCPTYGRANT);
} else {
rc = _isptmaster(fd);
}
STRACE("grantpt(%d) → %d% m", fd, rc);
return rc;
}
-7
View File
@@ -12,13 +12,6 @@ COSMOPOLITAN_C_START_
#define kIoMotion ((const int8_t[3]){1, 0, 0})
struct IoctlPtmGet {
int theduxfd;
int workerfd;
char theduxname[16];
char workername[16];
};
hidden extern struct Fds g_fds;
hidden extern const struct Fd kEmptyFd;
+3 -16
View File
@@ -29,7 +29,7 @@
#include "libc/sysv/consts/termios.h"
#include "libc/sysv/errfuns.h"
void __on_ioctl_tcsets(void);
void __on_ioctl_tcsets(int);
int ioctl_tcsets_nt(int, uint64_t, const struct termios *);
static int ioctl_tcsets_metal(int fd, uint64_t request,
@@ -37,19 +37,6 @@ static int ioctl_tcsets_metal(int fd, uint64_t request,
return 0;
}
static inline void *__termios2host(union metatermios *mt,
const struct termios *lt) {
if (!IsXnu() && !IsFreebsd() && !IsOpenbsd() && !IsNetbsd()) {
return (/*unconst*/ void *)lt;
} else if (IsXnu()) {
COPY_TERMIOS(&mt->xnu, lt);
return &mt->xnu;
} else {
COPY_TERMIOS(&mt->bsd, lt);
return &mt->bsd;
}
}
static int ioctl_tcsets_sysv(int fd, uint64_t request,
const struct termios *tio) {
union metatermios mt;
@@ -72,9 +59,9 @@ int ioctl_tcsets(int fd, uint64_t request, ...) {
va_start(va, request);
tio = va_arg(va, const struct termios *);
va_end(va);
if (_weaken(__on_ioctl_tcsets)) {
if (0 <= fd && fd <= 2 && _weaken(__on_ioctl_tcsets)) {
if (!once) {
_weaken(__on_ioctl_tcsets)();
_weaken(__on_ioctl_tcsets)(fd);
once = true;
}
}
@@ -17,13 +17,22 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/sysv/consts/termios.h"
/**
* Gets file descriptor table size.
*
* @return current limit on the number of open files per process
*/
int getdtablesize(void) {
return g_fds.n;
int _isptmaster(int fd) {
if (IsFreebsd()) {
if (!sys_ioctl(fd, TIOCPTMASTER)) {
return 0;
} else {
if (errno != EBADF) {
errno = EINVAL;
}
return -1;
}
} else {
return 0;
}
}
+22 -28
View File
@@ -34,15 +34,8 @@
static bool NeedsQuotes(const char *s) {
if (!*s) return true;
do {
switch (*s) {
case '"':
case ' ':
case '\t':
case '\v':
case '\n':
return true;
default:
break;
if (*s == ' ' || *s == '\t') {
return true;
}
} while (*s++);
return false;
@@ -52,21 +45,19 @@ static inline int IsAlpha(int c) {
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
}
// Converts System V argv to Windows-style command line.
//
// Escaping is performed and it's designed to round-trip with
// GetDosArgv() or GetDosArgv(). This function does NOT escape
// command interpreter syntax, e.g. $VAR (sh), %VAR% (cmd).
//
// TODO(jart): this needs fuzzing and security review
//
// @param cmdline is output buffer
// @param prog is frontloaded as argv[0]
// @param argv is an a NULL-terminated array of UTF-8 strings
// @return 0 on success, or -1 w/ errno
// @raise E2BIG if everything is too huge
// @see "Everyone quotes command line arguments the wrong way" MSDN
// @see libc/runtime/getdosargv.c
/**
* Converts System V argv to Windows-style command line.
*
* Escaping is performed and it's designed to round-trip with
* GetDosArgv() or GetDosArgv(). This function does NOT escape
* command interpreter syntax, e.g. $VAR (sh), %VAR% (cmd).
*
* @param cmdline is output buffer
* @param prog is used as argv[0]
* @param argv is an a NULL-terminated array of UTF-8 strings
* @return freshly allocated lpCommandLine or NULL w/ errno
* @see libc/runtime/dosargv.c
*/
textwindows int mkntcmdline(char16_t cmdline[ARG_MAX / 2], const char *prog,
char *const argv[]) {
char *arg;
@@ -111,8 +102,8 @@ textwindows int mkntcmdline(char16_t cmdline[ARG_MAX / 2], const char *prog,
} else {
// turn stuff like `less /c/...`
// into `less c:/...`
// turn stuff like `more <"/c/..."`
// into `more <"c:/..."`
// turn stuff like `more <\\\"/c/...\\\"`
// into `more <\\\"c:/...\\\"`
if (k > 3 && IsAlpha(cmdline[k - 1]) &&
(cmdline[k - 2] == '/' || cmdline[k - 2] == '\\') &&
(cmdline[k - 3] == '"' || cmdline[k - 3] == ' ')) {
@@ -124,8 +115,11 @@ textwindows int mkntcmdline(char16_t cmdline[ARG_MAX / 2], const char *prog,
if (x == '\\') {
++slashes;
} else if (x == '"') {
APPEND(u'"');
APPEND(u'"');
for (s = 0; s < slashes * 2; ++s) {
APPEND(u'\\');
}
slashes = 0;
APPEND(u'\\');
APPEND(u'"');
} else {
for (s = 0; s < slashes; ++s) {
+1 -20
View File
@@ -173,24 +173,5 @@ textwindows int __mkntpath2(const char *path,
p[j] = 0;
n = j;
// our path is now stored at `path16` with length `n`
n = x + m + n;
// To avoid toil like this:
//
// CMD.EXE was started with the above path as the current directory.
// UNC paths are not supported. Defaulting to Windows directory.
// Access is denied.
//
// Remove \\?\ prefix if we're within 260 character limit.
if (n > 4 && n < 260 && //
path16[0] == '\\' && //
path16[1] == '\\' && //
path16[2] == '?' && //
path16[3] == '\\') {
memmove(path16, path16 + 4, (n - 4 + 1) * sizeof(char16_t));
n -= 4;
}
return n;
return x + m + n;
}
+4 -4
View File
@@ -19,10 +19,10 @@
#include "libc/calls/asan.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/state.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/dce.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/errfuns.h"
/**
@@ -71,10 +71,10 @@ int nanosleep(const struct timespec *req, struct timespec *rem) {
rem->tv_nsec = 0;
}
#if defined(SYSDEBUG) && _POLLTRACE
#ifdef SYSDEBUG
if (!__time_critical) {
POLLTRACE("nanosleep(%s, [%s]) → %d% m", DescribeTimespec(rc, req),
DescribeTimespec(rc, rem), rc);
STRACE("nanosleep(%s, [%s]) → %d% m", DescribeTimespec(rc, req),
DescribeTimespec(rc, rem), rc);
}
#endif
+51 -19
View File
@@ -16,15 +16,33 @@
│ 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/ioctl.h"
#include "libc/calls/struct/metatermios.internal.h"
#include "libc/calls/struct/termios.h"
#include "libc/calls/struct/winsize.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/calls/termios.h"
#include "libc/fmt/itoa.h"
#include "libc/calls/termios.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/rop.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/pty.h"
#include "libc/sysv/consts/termios.h"
#include "libc/sysv/errfuns.h"
struct IoctlPtmGet {
int m;
int s;
char mname[16];
char sname[16];
};
/**
* Opens new pseudo teletypewriter.
*
@@ -37,24 +55,38 @@
*/
int openpty(int *mfd, int *sfd, char *name, const struct termios *tio,
const struct winsize *wsz) {
int m, s, n;
char buf[20];
if ((m = open("/dev/ptmx", O_RDWR | O_NOCTTY)) != -1) {
n = 0;
if (!ioctl(m, TIOCSPTLCK, &n) && !ioctl(m, TIOCGPTN, &n)) {
if (!name) name = buf;
name[0] = '/', name[1] = 'd', name[2] = 'e', name[3] = 'v';
name[4] = '/', name[5] = 'p', name[6] = 't', name[7] = 's';
name[8] = '/', FormatInt32(name + 9, n);
if ((s = open(name, O_RDWR | O_NOCTTY)) != -1) {
if (tio) ioctl(s, TCSETS, tio);
if (wsz) ioctl(s, TIOCSWINSZ, wsz);
*mfd = m;
*sfd = s;
return 0;
}
}
close(m);
int m, s, p;
union metatermios mt;
struct IoctlPtmGet t;
if (IsWindows() || IsMetal()) {
return enosys();
}
if (IsAsan() && (!__asan_is_valid(mfd, sizeof(int)) ||
!__asan_is_valid(sfd, sizeof(int)) ||
(name && !__asan_is_valid(name, 16)) ||
(tio && !__asan_is_valid(tio, sizeof(*tio))) ||
(wsz && !__asan_is_valid(wsz, sizeof(*wsz))))) {
return efault();
}
RETURN_ON_ERROR((m = posix_openpt(O_RDWR | O_NOCTTY)));
if (!IsOpenbsd()) {
RETURN_ON_ERROR(grantpt(m));
RETURN_ON_ERROR(unlockpt(m));
RETURN_ON_ERROR(_ptsname(m, t.sname, sizeof(t.sname)));
RETURN_ON_ERROR((s = sys_open(t.sname, O_RDWR, 0)));
} else {
RETURN_ON_ERROR(sys_ioctl(m, PTMGET, &t));
close(m);
m = t.m;
s = t.s;
}
*mfd = m;
*sfd = s;
if (name) strcpy(name, t.sname);
if (tio) _npassert(!sys_ioctl(s, TCSETSF, __termios2host(&mt, tio)));
if (wsz) _npassert(!sys_ioctl(s, TIOCGWINSZ, wsz));
return 0;
OnError:
if (m != -1) sys_close(m);
return -1;
}
+1 -1
View File
@@ -17,11 +17,11 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/errfuns.h"
/**
+7 -5
View File
@@ -24,16 +24,18 @@
#include "libc/sysv/errfuns.h"
int32_t sys_pipe2(int pipefd[hasatleast 2], unsigned flags) {
int rc, olderr;
int e, rc;
if (!flags) goto OldSkool;
olderr = errno;
e = errno;
rc = __sys_pipe2(pipefd, flags);
if (rc == -1 && errno == ENOSYS) {
errno = olderr;
errno = e;
OldSkool:
if ((rc = sys_pipe(pipefd)) != -1) {
__fixupnewfd(pipefd[0], flags);
__fixupnewfd(pipefd[1], flags);
if (flags) {
__fixupnewfd(pipefd[0], flags);
__fixupnewfd(pipefd[1], flags);
}
}
}
return rc;
+53 -47
View File
@@ -540,7 +540,8 @@ static const uint16_t kPledgeStdio[] = {
__NR_linux_sigsuspend, //
__NR_linux_sigpending, //
__NR_linux_kill | SELF, //
__NR_linux_tkill | SELF, //
__NR_linux_tkill, //
__NR_linux_tgkill | SELF, //
__NR_linux_socketpair, //
__NR_linux_getrusage, //
__NR_linux_times, //
@@ -660,15 +661,16 @@ static const uint16_t kPledgeUnix[] = {
};
static const uint16_t kPledgeDns[] = {
__NR_linux_socket | INET, //
__NR_linux_bind, //
__NR_linux_sendto, //
__NR_linux_connect, //
__NR_linux_recvfrom, //
__NR_linux_fstatat, //
__NR_linux_openat | READONLY, //
__NR_linux_read, //
__NR_linux_close, //
__NR_linux_socket | INET, //
__NR_linux_bind, //
__NR_linux_sendto, //
__NR_linux_connect, //
__NR_linux_recvfrom, //
__NR_linux_setsockopt | RESTRICT, //
__NR_linux_fstatat, //
__NR_linux_openat | READONLY, //
__NR_linux_read, //
__NR_linux_close, //
};
static const uint16_t kPledgeTty[] = {
@@ -690,6 +692,7 @@ static const uint16_t kPledgeProc[] = {
__NR_linux_vfork, //
__NR_linux_clone | RESTRICT, //
__NR_linux_kill, //
__NR_linux_tgkill, //
__NR_linux_setsid, //
__NR_linux_setpgid, //
__NR_linux_prlimit, //
@@ -706,8 +709,6 @@ static const uint16_t kPledgeProc[] = {
__NR_linux_sched_setaffinity, //
__NR_linux_sched_getparam, //
__NR_linux_sched_setparam, //
__NR_linux_tkill, //
__NR_linux_tgkill, //
};
static const uint16_t kPledgeId[] = {
@@ -1027,15 +1028,15 @@ static privileged void AllowKillSelf(struct Filter *f) {
AppendFilter(f, PLEDGE(fragment));
}
// The first argument of tkill() must be
// The first argument of tgkill() must be
//
// - gettid()
// - getpid()
//
static privileged void AllowTkillSelf(struct Filter *f) {
static privileged void AllowTgkillSelf(struct Filter *f) {
struct sock_filter fragment[] = {
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_tkill, 0, 4),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_tgkill, 0, 4),
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[0])),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, GetTid(), 0, 1),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, GetPid(), 0, 1),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
};
@@ -1160,7 +1161,7 @@ static privileged void AllowCloneThread(struct Filter *f) {
//
static privileged void AllowIoctlStdio(struct Filter *f) {
static const struct sock_filter fragment[] = {
/*L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_ioctl, 0, 8 - 1),
/*L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_ioctl, 0, 7),
/*L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[1])),
/*L2*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x541b, 3, 0),
/*L3*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x5421, 2, 0),
@@ -1206,7 +1207,7 @@ static privileged void AllowIoctlInet(struct Filter *f) {
//
static privileged void AllowIoctlTty(struct Filter *f) {
static const struct sock_filter fragment[] = {
/* L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_ioctl, 0, 16 - 1),
/* L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_ioctl, 0, 15),
/* L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[1])),
/* L2*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x5401, 11, 0),
/* L3*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x5402, 10, 0),
@@ -1232,6 +1233,7 @@ static privileged void AllowIoctlTty(struct Filter *f) {
// - SOL_IP (0)
// - SOL_SOCKET (1)
// - SOL_TCP (6)
// - SOL_IPV6 (41)
//
// The optname argument of setsockopt() must be one of:
//
@@ -1242,6 +1244,7 @@ static privileged void AllowIoctlTty(struct Filter *f) {
// - SO_TYPE (0x03)
// - SO_ERROR (0x04)
// - SO_DONTROUTE (0x05)
// - SO_BROADCAST (0x06)
// - SO_REUSEPORT (0x0f)
// - SO_REUSEADDR (0x02)
// - SO_KEEPALIVE (0x09)
@@ -1251,33 +1254,36 @@ static privileged void AllowIoctlTty(struct Filter *f) {
// - IP_RECVERR (0x0b)
// - TCP_FASTOPEN (0x17)
// - TCP_FASTOPEN_CONNECT (0x1e)
// - IPV6_V6ONLY (0x1a)
//
static privileged void AllowSetsockoptRestrict(struct Filter *f) {
static const int nr = __NR_linux_setsockopt;
static const struct sock_filter fragment[] = {
/* L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, nr, 0, 21 - 1),
/* L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[1])),
/* L2*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, 2, 0),
/* L3*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 1, 1, 0),
/* L4*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 6, 0, 20 - 5),
/* L5*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[2])),
/* L6*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0f, 13, 0),
/* L6*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x03, 12, 0),
/* L7*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0c, 11, 0),
/* L8*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x13, 10, 0),
/* L9*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x02, 9, 0),
/*L10*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x09, 8, 0),
/*L11*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x14, 7, 0),
/*L12*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x01, 6, 0),
/*L13*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0b, 5, 0),
/*L14*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x04, 4, 0),
/*L15*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x05, 3, 0),
/*L16*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x17, 2, 0),
/*L17*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x1e, 1, 0),
/*L18*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x15, 0, 1),
/*L19*/ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
/*L20*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
/*L21*/ /* next filter */
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_setsockopt, 0, 24),
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[1])),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 41, 3, 0),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, 2, 0),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 1, 1, 0),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 6, 0, 18),
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[2])),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x1a, 15, 0),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x06, 14, 0),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0f, 13, 0),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x03, 12, 0),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0c, 11, 0),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x13, 10, 0),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x02, 9, 0),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x09, 8, 0),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x14, 7, 0),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x01, 6, 0),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0b, 5, 0),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x04, 4, 0),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x05, 3, 0),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x17, 2, 0),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x1e, 1, 0),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x15, 0, 1),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
/* next filter */
};
AppendFilter(f, PLEDGE(fragment));
}
@@ -1300,10 +1306,10 @@ static privileged void AllowSetsockoptRestrict(struct Filter *f) {
static privileged void AllowGetsockoptRestrict(struct Filter *f) {
static const int nr = __NR_linux_getsockopt;
static const struct sock_filter fragment[] = {
/* L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, nr, 0, 14 - 1),
/* L0*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, nr, 0, 13),
/* L1*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[1])),
/* L2*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 1, 1, 0),
/* L3*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 6, 0, 13 - 4),
/* L3*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 6, 0, 9),
/* L4*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[2])),
/* L5*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x03, 6, 0),
/* L6*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x04, 5, 0),
@@ -1943,8 +1949,8 @@ static privileged void AppendPledge(struct Filter *f, //
case __NR_linux_kill | SELF:
AllowKillSelf(f);
break;
case __NR_linux_tkill | SELF:
AllowTkillSelf(f);
case __NR_linux_tgkill | SELF:
AllowTgkillSelf(f);
break;
default:
notpossible;
+1 -1
View File
@@ -42,7 +42,7 @@
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
/**
/*
* Polls on the New Technology.
*
* This function is used to implement poll() and select(). You may poll
+4 -2
View File
@@ -17,13 +17,13 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/intrin/strace.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/likely.h"
#include "libc/intrin/strace.internal.h"
#include "libc/macros.internal.h"
#include "libc/sock/internal.h"
#include "libc/sock/sock.h"
@@ -68,10 +68,12 @@
* @norestart
*/
int poll(struct pollfd *fds, size_t nfds, int timeout_ms) {
size_t n;
int i, rc;
uint64_t millis;
if (IsAsan() && !__asan_is_valid(fds, nfds * sizeof(struct pollfd))) {
if (IsAsan() && (__builtin_mul_overflow(nfds, sizeof(struct pollfd), &n) ||
!__asan_is_valid(fds, n))) {
rc = efault();
} else if (!IsWindows()) {
if (!IsMetal()) {
+46 -2
View File
@@ -16,8 +16,52 @@
│ 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.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
int(posix_fadvise)(int fd, uint64_t offset, uint64_t len, int advice) {
return fadvise(fd, offset, len, advice);
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 POSIX_FADV_SEQUENTIAL, POSIX_FADV_RANDOM, etc.
* @return 0 on success, or errno on error
* @raise EBADF if `fd` isn't a valid file descriptor
* @raise EINVAL if `advice` is invalid or `len` is huge
* @raise ESPIPE if `fd` refers to a pipe
* @raise ENOSYS on XNU and OpenBSD
*/
errno_t posix_fadvise(int fd, uint64_t offset, uint64_t len, int advice) {
int rc, e = errno;
if (IsLinux()) {
rc = sys_fadvise(fd, offset, len, advice);
} else if (IsFreebsd()) {
rc = sys_fadvise(fd, offset, len, advice);
_unassert(rc >= 0);
} else if (IsNetbsd()) {
rc = sys_fadvise_netbsd(fd, offset, offset, len, advice);
_unassert(rc >= 0);
} else if (IsWindows()) {
rc = sys_fadvise_nt(fd, offset, len, advice);
} else {
rc = enosys();
}
if (rc == -1) {
rc = errno;
errno = e;
}
STRACE("posix_fadvise(%d, %'lu, %'lu, %d) → %s", fd, offset, len, advice,
!rc ? "0" : _strerrno(rc));
return rc;
}
+16 -23
View File
@@ -16,43 +16,36 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/termios.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/pty.h"
#include "libc/sysv/consts/termios.h"
#include "libc/sysv/errfuns.h"
/**
* Opens new pseudo teletypewriter.
*
* @return fd of master pty, or -1 w/ errno
* @params flags is usually O_RDWR|O_NOCTTY
* @return file descriptor, or -1 w/ errno
*/
int posix_openpt(int flags) {
int fd, ilduce;
struct IoctlPtmGet ptm;
if ((flags & O_ACCMODE) != O_RDWR) return einval();
if (SupportsFreebsd() &&
((fd = sys_posix_openpt(flags)) != -1 || errno != ENOSYS)) {
return fd;
} else if ((fd = open("/dev/ptmx", flags)) != -1 || errno != ENOENT) {
return fd;
} else if (SupportsOpenbsd() &&
((fd = open("/dev/ptm", flags)) != -1 || errno != ENOENT)) {
if (ioctl(fd, PTMGET, &ptm) != -1) {
close(ptm.workerfd);
ilduce = ptm.theduxfd;
} else {
ilduce = -1;
}
close(fd);
return ilduce;
int rc;
if ((flags & O_ACCMODE) != O_RDWR) {
rc = einval();
} else if (IsLinux() || IsXnu() || IsNetbsd()) {
rc = sys_open("/dev/ptmx", flags, 0);
} else if (IsOpenbsd()) {
rc = sys_open("/dev/ptm", flags, 0);
} else if (IsFreebsd()) {
rc = sys_posix_openpt(flags);
if (rc == -1 && errno == ENOSPC) errno = EAGAIN;
} else {
return enosys();
rc = enosys();
}
STRACE("posix_openpt(%s) → %d% m", DescribeOpenFlags(flags), rc);
return rc;
}
+4 -2
View File
@@ -17,13 +17,13 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/struct/timespec.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/strace.internal.h"
#include "libc/macros.internal.h"
#include "libc/sock/struct/pollfd.h"
#include "libc/sock/struct/pollfd.internal.h"
@@ -57,12 +57,14 @@
*/
int ppoll(struct pollfd *fds, size_t nfds, const struct timespec *timeout,
const sigset_t *sigmask) {
size_t n;
int e, i, rc;
uint64_t millis;
sigset_t oldmask;
struct timespec ts, *tsp;
if (IsAsan() && (!__asan_is_valid(fds, nfds * sizeof(struct pollfd)) ||
if (IsAsan() && (__builtin_mul_overflow(nfds, sizeof(struct pollfd), &n) ||
!__asan_is_valid(fds, n) ||
(timeout && !__asan_is_valid(timeout, sizeof(timeout))) ||
(sigmask && !__asan_is_valid(sigmask, sizeof(sigmask))))) {
rc = efault();
+6 -3
View File
@@ -46,8 +46,11 @@
*/
ssize_t pread(int fd, void *buf, size_t size, int64_t offset) {
ssize_t rc;
if (fd == -1 || offset < 0) return einval();
if (IsAsan() && !__asan_is_valid(buf, size)) {
if (offset < 0) {
rc = einval();
} else if (fd < 0) {
rc = ebadf();
} else if (IsAsan() && !__asan_is_valid(buf, size)) {
rc = efault();
} else if (__isfdkind(fd, kFdZip)) {
rc = _weaken(__zipos_read)(
@@ -60,7 +63,7 @@ ssize_t pread(int fd, void *buf, size_t size, int64_t offset) {
} else {
rc = ebadf();
}
assert(rc == -1 || (size_t)rc <= size);
_npassert(rc == -1 || (size_t)rc <= size);
DATATRACE("pread(%d, [%#.*hhs%s], %'zu, %'zd) → %'zd% m", fd,
MAX(0, MIN(40, rc)), buf, rc > 40 ? "..." : "", size, offset, rc);
return rc;
+1 -6
View File
@@ -17,25 +17,20 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/iovec.internal.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/bits.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/likely.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/macros.internal.h"
#include "libc/sysv/consts/iov.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
+17 -2
View File
@@ -16,10 +16,25 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/calls/termios.h"
#include "libc/errno.h"
#include "libc/intrin/strace.internal.h"
static char g_ptsname[32];
static char g_ptsname[16];
/**
* Gets name subordinate pseudoteletypewriter.
*
* @return static string path on success, or NULL w/ errno
*/
char *ptsname(int fd) {
return ptsname_r(fd, g_ptsname, sizeof(g_ptsname)) ? g_ptsname : NULL;
char *res;
if (!_ptsname(fd, g_ptsname, sizeof(g_ptsname))) {
res = g_ptsname;
} else {
res = 0;
}
STRACE("ptsname(%d) → %#s% m", fd, res);
return res;
}
+13 -15
View File
@@ -16,24 +16,22 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/calls/termios.h"
#include "libc/errno.h"
#include "libc/fmt/itoa.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/termios.h"
#include "libc/sysv/errfuns.h"
/**
* Gets name subordinate pseudoteletypewriter.
*
* @return 0 on success, or errno on error
*/
errno_t ptsname_r(int fd, char *buf, size_t size) {
int pty;
char tb[32];
if (size) {
if (!buf) return einval();
if (ioctl(fd, TIOCGPTN, &pty) == -1) return errno;
FormatInt32(stpcpy(tb, "/dev/pts/"), pty);
if (strlen(tb) + 1 >= size) return (errno = ERANGE);
stpcpy(buf, tb);
/* TODO(jart): OpenBSD OMG */
int rc, e = errno;
if (!_ptsname(fd, buf, size)) {
rc = 0;
} else {
rc = errno;
errno = e;
}
return 0;
return rc;
}
+9 -7
View File
@@ -19,12 +19,12 @@
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/iovec.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/macros.internal.h"
#include "libc/sysv/errfuns.h"
@@ -46,9 +46,11 @@
ssize_t pwrite(int fd, const void *buf, size_t size, int64_t offset) {
ssize_t rc;
size_t wrote;
if (fd == -1 || offset < 0) return einval();
size = MIN(size, 0x7ffff000);
if (IsAsan() && !__asan_is_valid(buf, size)) {
if (offset < 0) {
rc = einval();
} else if (fd == -1) {
rc = ebadf();
} else if (IsAsan() && !__asan_is_valid(buf, size)) {
rc = efault();
} else if (!IsWindows()) {
rc = sys_pwrite(fd, buf, size, offset, offset);
@@ -59,10 +61,10 @@ ssize_t pwrite(int fd, const void *buf, size_t size, int64_t offset) {
}
if (rc != -1) {
wrote = (size_t)rc;
if (wrote == 0) {
assert(size == 0);
if (!wrote) {
_npassert(size == 0);
} else {
assert(wrote <= size);
_npassert(wrote <= size);
}
}
DATATRACE("pwrite(%d, %#.*hhs%s, %'zu, %'zd) → %'zd% m", fd,
+2 -4
View File
@@ -17,22 +17,20 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/iovec.internal.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/likely.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/macros.internal.h"
#include "libc/sysv/consts/iov.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
+16 -1
View File
@@ -16,14 +16,16 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/fd.internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/iovec.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/calls/wincrash.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/nt/enum/filetype.h"
#include "libc/nt/errors.h"
#include "libc/nt/files.h"
@@ -35,8 +37,10 @@
static textwindows ssize_t sys_read_nt_impl(struct Fd *fd, void *data,
size_t size, ssize_t offset) {
int64_t p;
uint32_t got, avail;
struct NtOverlapped overlap;
if (GetFileType(fd->handle) == kNtFileTypePipe) {
for (;;) {
if (!PeekNamedPipe(fd->handle, 0, 0, 0, &avail, 0)) break;
@@ -52,10 +56,20 @@ static textwindows ssize_t sys_read_nt_impl(struct Fd *fd, void *data,
}
POLLTRACE("sys_read_nt ready to read");
}
if (offset != -1) {
// windows changes the file pointer even if overlapped is passed
_npassert(SetFilePointerEx(fd->handle, 0, &p, SEEK_CUR));
}
if (ReadFile(fd->handle, data, _clampio(size), &got,
_offset2overlap(fd->handle, offset, &overlap))) {
if (offset != -1) {
_npassert(SetFilePointerEx(fd->handle, p, 0, SEEK_SET));
}
return got;
}
switch (GetLastError()) {
case kNtErrorBrokenPipe: // broken pipe
case kNtErrorNoData: // closing named pipe
@@ -73,6 +87,7 @@ textwindows ssize_t sys_read_nt(struct Fd *fd, const struct iovec *iov,
ssize_t rc;
uint32_t size;
size_t i, total;
if (opt_offset < -1) return einval();
if (_check_interrupts(true, fd)) return eintr();
while (iovlen && !iov[0].iov_len) iov++, iovlen--;
if (iovlen) {
+1 -2
View File
@@ -41,8 +41,7 @@ static volatile size_t mapsize;
/**
* Grows file descriptor array memory if needed.
*
* @see libc/runtime/memtrack64-128tib.txt
* @see libc/runtime/memtrack64-8tib.txt
* @see libc/runtime/memtrack64.txt
* @see libc/runtime/memtrack32.txt
* @asyncsignalsafe
*/
+1 -1
View File
@@ -22,7 +22,7 @@
/**
* Deletes empty directory.
*
* @return 0 on success or -1 w/ errno on error
* @return 0 on success, or -1 w/ errno
*/
int rmdir(const char *path) {
return unlinkat(AT_FDCWD, path, AT_REMOVEDIR);
+1 -1
View File
@@ -18,7 +18,7 @@ int sys_sched_setscheduler(int, int, const struct sched_param *);
int sys_sched_yield(void) hidden;
int64_t sys_sched_getaffinity(int, uint64_t, void *) hidden;
int sys_sched_getscheduler_netbsd(int);
int sys_sched_getscheduler_netbsd(int, struct sched_param *);
int sys_sched_setparam_netbsd(int, int, int, const struct sched_param *) //
asm("sys_sched_setparam");
int sys_sched_getparam_netbsd(int, int, int *, struct sched_param *) //
+10 -2
View File
@@ -16,11 +16,13 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/sched-sysv.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/cpuset.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/macros.internal.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/nt/thread.h"
@@ -52,7 +54,7 @@ static textwindows int sys_sched_getaffinity_nt(int tid, size_t size,
* @param bitset receives bitset and should be uint64_t[16] in order to
* work on older versions of Linux
* @return 0 on success, or -1 w/ errno
* @raise ENOSYS on non-Linux
* @raise ENOSYS if not Linux, NetBSD, or Windows
*/
int sched_getaffinity(int tid, size_t size, cpu_set_t *bitset) {
int rc;
@@ -60,6 +62,12 @@ int sched_getaffinity(int tid, size_t size, cpu_set_t *bitset) {
rc = einval();
} else if (IsWindows()) {
rc = sys_sched_getaffinity_nt(tid, size, bitset);
} else if (IsNetbsd()) {
if (!sys_sched_getaffinity_netbsd(0, tid, MIN(size, 32), bitset)) {
rc = MIN(size, 32);
} else {
rc = -1;
}
} else {
rc = sys_sched_getaffinity(tid, size, bitset);
}
+20 -2
View File
@@ -18,13 +18,31 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/sched-sysv.internal.h"
#include "libc/calls/struct/sched_param.h"
#include "libc/calls/struct/sched_param.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/errfuns.h"
/**
* Gets scheduler policy parameter.
*
* @return 0 on success, or -1 w/ errno
* @raise ENOSYS on XNU, Windows
* @raise ENOSYS on XNU, Windows, OpenBSD
*/
int sched_getparam(int pid, struct sched_param *param) {
return sys_sched_getparam(pid, param);
int rc;
struct sched_param p;
if (!param || (IsAsan() && !__asan_is_valid(param, sizeof(*param)))) {
rc = efault();
} else if (IsNetbsd()) {
if (!(rc = sys_sched_getscheduler_netbsd(pid, &p))) {
*param = p;
}
} else {
rc = sys_sched_getparam(pid, param);
}
STRACE("sched_getparam(%d, [%s]) → %d% m", pid, DescribeSchedParam(param),
rc);
return rc;
}
+2 -3
View File
@@ -20,10 +20,9 @@
#include "libc/calls/sched-sysv.internal.h"
#include "libc/calls/struct/sched_param.h"
int sys_sched_getscheduler_netbsd(int pid) {
int sys_sched_getscheduler_netbsd(int pid, struct sched_param *sp) {
int policy;
struct sched_param sp;
if (sys_sched_getparam_netbsd(pid, P_ALL_LWPS, &policy, &sp) != -1) {
if (sys_sched_getparam_netbsd(pid, P_ALL_LWPS, &policy, sp) != -1) {
return policy;
} else {
return -1;
+3 -2
View File
@@ -17,10 +17,10 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/sched-sysv.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/sched_param.h"
#include "libc/dce.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
/**
* Gets scheduler policy for `pid`.
@@ -40,7 +40,8 @@
int sched_getscheduler(int pid) {
int rc;
if (IsNetbsd()) {
rc = sys_sched_getscheduler_netbsd(pid);
struct sched_param p;
rc = sys_sched_getscheduler_netbsd(pid, &p);
} else {
rc = sys_sched_getscheduler(pid);
}
+14 -11
View File
@@ -18,13 +18,14 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/sched-sysv.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/cpuset.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/dce.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/limits.h"
#include "libc/macros.internal.h"
#include "libc/nt/enum/processaccess.h"
#include "libc/nt/enum/threadaccess.h"
#include "libc/nt/process.h"
@@ -34,14 +35,14 @@
#include "libc/sysv/errfuns.h"
static textwindows dontinline int sys_sched_setaffinity_nt(int pid,
uint64_t bitsetsize,
uint64_t size,
const void *bitset) {
int rc;
uintptr_t mask;
int64_t handle;
uintptr_t mask;
typeof(SetThreadAffinityMask) *SetAffinityMask = SetThreadAffinityMask;
mask = 0;
memcpy(&mask, bitset, min(bitsetsize, sizeof(uintptr_t)));
memcpy(&mask, bitset, min(size, sizeof(uintptr_t)));
handle = 0;
if (!pid) pid = GetCurrentThreadId();
if (0 < pid && pid <= UINT32_MAX) {
@@ -69,19 +70,21 @@ static textwindows dontinline int sys_sched_setaffinity_nt(int pid,
* Asks kernel to only schedule thread on particular CPUs.
*
* @param tid is the process or thread id (or 0 for caller)
* @param bitsetsize is byte length of bitset, which should be 128
* @param size is byte length of bitset, which should be 128
* @return 0 on success, or -1 w/ errno
* @raise ENOSYS if not Linux or Windows
* @raise ENOSYS if not Linux, NetBSD, or Windows
*/
int sched_setaffinity(int tid, size_t bitsetsize, const cpu_set_t *bitset) {
int sched_setaffinity(int tid, size_t size, const cpu_set_t *bitset) {
int rc;
if (bitsetsize != 128) {
if (size != 128) {
rc = einval();
} else if (IsWindows()) {
rc = sys_sched_setaffinity_nt(tid, bitsetsize, bitset);
rc = sys_sched_setaffinity_nt(tid, size, bitset);
} else if (IsNetbsd()) {
rc = sys_sched_setaffinity_netbsd(0, tid, MIN(size, 32), bitset);
} else {
rc = sys_sched_setaffinity(tid, bitsetsize, bitset);
rc = sys_sched_setaffinity(tid, size, bitset);
}
STRACE("sched_setaffinity(%d, %'zu, %p) → %d% m", tid, bitsetsize, bitset);
STRACE("sched_setaffinity(%d, %'zu, %p) → %d% m", tid, size, bitset);
return rc;
}
+21 -2
View File
@@ -18,11 +18,30 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/sched-sysv.internal.h"
#include "libc/calls/struct/sched_param.h"
#include "libc/calls/struct/sched_param.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/errfuns.h"
/**
* Sets scheduler policy parameter.
* @raise ENOSYS on XNU, Windows
*
* @return 0 on success, or -1 w/ errno
* @raise ENOSYS on XNU, Windows, OpenBSD
*/
int sched_setparam(int pid, const struct sched_param *param) {
return sys_sched_setparam(pid, param);
int rc, policy;
struct sched_param p;
if (!param || (IsAsan() && !__asan_is_valid(param, sizeof(*param)))) {
rc = efault();
} else if (IsNetbsd()) {
if ((rc = policy = sys_sched_getscheduler_netbsd(pid, &p)) != -1) {
rc = sys_sched_setparam_netbsd(pid, P_ALL_LWPS, policy, param);
}
} else {
rc = sys_sched_setparam(pid, param);
}
STRACE("sched_setparam(%d, %s) → %d% m", pid, DescribeSchedParam(param), rc);
return rc;
}
+4 -3
View File
@@ -17,14 +17,14 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/sched-sysv.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/sched_param.h"
#include "libc/calls/struct/sched_param.internal.h"
#include "libc/dce.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/thread/tls.h"
#include "libc/intrin/strace.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/tls.h"
/**
* Sets scheduling policy of process, e.g.
@@ -94,9 +94,10 @@
*/
int sched_setscheduler(int pid, int policy, const struct sched_param *param) {
int rc, old;
struct sched_param p;
if (IsNetbsd()) {
rc = sys_sched_getscheduler_netbsd(pid);
rc = sys_sched_getscheduler_netbsd(pid, &p);
} else {
rc = sys_sched_getscheduler(pid);
}
+3 -1
View File
@@ -39,7 +39,9 @@
*/
int setgroups(size_t size, const uint32_t list[]) {
int rc;
if (IsAsan() && size && !__asan_is_valid(list, size * sizeof(list[0]))) {
size_t n;
if (IsAsan() && (__builtin_mul_overflow(size, sizeof(list[0]), &n) ||
!__asan_is_valid(list, n))) {
rc = efault();
} else if (IsLinux() || IsNetbsd() || IsOpenbsd() || IsFreebsd() || IsXnu()) {
rc = sys_setgroups(size, list);
+60 -38
View File
@@ -17,58 +17,80 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/mem/alloca.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/thread.h"
static ssize_t splicer(int infd, int64_t *inoffset, int outfd,
int64_t *outoffset, size_t uptobytes, uint32_t flags,
int64_t impl(int infd, int64_t *inoffset, int outfd,
int64_t *outoffset, size_t uptobytes,
uint32_t flags)) {
int olderr;
ssize_t transferred;
if (!uptobytes || flags == -1) return einval();
if (IsModeDbg() && uptobytes > 1) uptobytes >>= 1;
olderr = errno;
if (__isfdkind(infd, kFdZip) || __isfdkind(outfd, kFdZip) ||
(transferred =
impl(infd, inoffset, outfd, outoffset, uptobytes, flags)) == -1 &&
errno == ENOSYS) {
errno = olderr;
transferred = copyfd(infd, inoffset, outfd, outoffset, uptobytes, flags);
static struct Splice {
pthread_once_t once;
bool ok;
} g_splice;
static bool HasSplice(void) {
bool ok;
int e, rc;
e = errno;
if (IsLinux()) {
// Our testing indicates splice() doesn't work as documneted on
// RHEL5 and RHEL7 so let's require a modern kernel to be safe.
// We choose close_range() for this since it's listed by pledge
ok = sys_close_range(-1, -2, 0) == -1 && errno == EINVAL;
} else {
ok = false;
}
return transferred;
errno = e;
return ok;
}
static void splice_init(void) {
g_splice.ok = HasSplice();
}
/**
* Transfers data to/from pipe.
*
* @param flags can have SPLICE_F_{MOVE,NONBLOCK,MORE,GIFT}
* @param opt_in_out_inoffset may be specified if `infd` isn't a pipe and is
* used as both an input and output parameter for pread() behavior
* @param opt_in_out_outoffset may be specified if `outfd` isn't a pipe and is
* used as both an input and output parameter for pwrite() behavior
* @return number of bytes transferred, 0 on input end, or -1 w/ errno
* @raise EBADF if `infd` or `outfd` aren't open files or append-only
* @raise ESPIPE if an offset arg was specified for a pipe fd
* @raise EINVAL if offset was given for non-seekable device
* @raise EINVAL if file system doesn't support splice()
* @raise EFAULT if one of the pointers memory is bad
* @raise EINVAL if `flags` is invalid
* @raise ENOSYS if not Linux 5.9+
* @see copy_file_range() for file ↔ file
* @see sendfile() for seekable → socket
*/
ssize_t splice(int infd, int64_t *inopt_out_inoffset, int outfd,
int64_t *inopt_out_outoffset, size_t uptobytes, uint32_t flags) {
return splicer(infd, inopt_out_inoffset, outfd, inopt_out_outoffset,
uptobytes, flags, sys_splice);
}
/**
* Transfers data between files.
*
* @param outfd should be a writable file, but not O_APPEND
* @param flags is reserved for future use
* @return number of bytes actually copied, or -1 w/ errno
* @see sendfile() for seekable → socket
* @see splice() for fd ↔ pipe
*/
ssize_t copy_file_range(int infd, int64_t *inopt_out_inoffset, int outfd,
int64_t *inopt_out_outoffset, size_t uptobytes,
uint32_t flags) {
return splicer(infd, inopt_out_inoffset, outfd, inopt_out_outoffset,
uptobytes, flags, sys_copy_file_range);
ssize_t splice(int infd, int64_t *opt_in_out_inoffset, int outfd,
int64_t *opt_in_out_outoffset, size_t uptobytes,
uint32_t flags) {
ssize_t rc;
pthread_once(&g_splice.once, splice_init);
if (!g_splice.ok) {
rc = enosys();
} else if (IsAsan() && ((opt_in_out_inoffset &&
!__asan_is_valid(opt_in_out_inoffset, 8)) ||
(opt_in_out_outoffset &&
!__asan_is_valid(opt_in_out_outoffset, 8)))) {
rc = efault();
} else {
rc = sys_splice(infd, opt_in_out_inoffset, outfd, opt_in_out_outoffset,
uptobytes, flags);
}
STRACE("splice(%d, %s, %d, %s, %'zu, %#x) → %'ld% m", infd,
DescribeInOutInt64(rc, opt_in_out_inoffset), outfd,
DescribeInOutInt64(rc, opt_in_out_outoffset), uptobytes, flags);
return rc;
}
+5 -5
View File
@@ -5,18 +5,18 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
int __sys_utimensat(int, const char *, const struct timespec *, int) hidden;
int __sys_utimensat(int, const char *, const struct timespec[2], int) hidden;
int sys_clock_getres(int, struct timespec *) hidden;
int sys_clock_gettime(int, struct timespec *) hidden;
int sys_clock_gettime_nt(int, struct timespec *) hidden;
int sys_clock_gettime_xnu(int, struct timespec *) hidden;
int sys_futimens(int, const struct timespec *) hidden;
int sys_futimens(int, const struct timespec[2]) hidden;
int sys_nanosleep(const struct timespec *, struct timespec *) hidden;
int sys_nanosleep_nt(const struct timespec *, struct timespec *) hidden;
int sys_nanosleep_xnu(const struct timespec *, struct timespec *) hidden;
int sys_utimensat(int, const char *, const struct timespec *, int) hidden;
int sys_utimensat_nt(int, const char *, const struct timespec *, int) hidden;
int sys_utimensat_xnu(int, const char *, const struct timespec *, int) hidden;
int sys_utimensat(int, const char *, const struct timespec[2], int) hidden;
int sys_utimensat_nt(int, const char *, const struct timespec[2], int) hidden;
int sys_utimensat_xnu(int, const char *, const struct timespec[2], int) hidden;
const char *DescribeTimespec(char[45], int, const struct timespec *);
#define DescribeTimespec(rc, ts) DescribeTimespec(alloca(45), rc, ts)
+1 -3
View File
@@ -28,9 +28,7 @@
#include "libc/nt/runtime.h"
#include "libc/sysv/consts/ok.h"
/**
* Flushes all open file handles and, if possible, all disk drives.
*/
// Flushes all open file handles and, if possible, all disk drives.
textwindows int sys_sync_nt(void) {
unsigned i;
int64_t volume;
+5 -5
View File
@@ -53,9 +53,9 @@ i32 sys_getpgid(i32) hidden;
i32 sys_getpgrp(void) hidden;
i32 sys_getppid(void) hidden;
i32 sys_getpriority(i32, u32) hidden;
i32 sys_getresgid(u32 *, u32 *, u32 *);
i32 sys_getresuid(u32 *, u32 *, u32 *);
i32 sys_getsid(int) hidden;
i32 sys_getresgid(u32 *, u32 *, u32 *) hidden;
i32 sys_getresuid(u32 *, u32 *, u32 *) hidden;
i32 sys_getsid(i32) hidden;
i32 sys_gettid(void) hidden;
i32 sys_ioctl(i32, u64, ...) hidden;
i32 sys_issetugid(void) hidden;
@@ -112,7 +112,7 @@ i64 sys_pread(i32, void *, u64, i64, i64) hidden;
i64 sys_pwrite(i32, const void *, u64, i64, i64) hidden;
i64 sys_read(i32, void *, u64) hidden;
i64 sys_readlink(const char *, char *, u64) hidden;
i64 sys_readlinkat(int, const char *, char *, u64) hidden;
i64 sys_readlinkat(i32, const char *, char *, u64) hidden;
i64 sys_sendfile(i32, i32, i64 *, u64) hidden;
i64 sys_splice(i32, i64 *, i32, i64 *, u64, u32) hidden;
i64 sys_write(i32, const void *, u64) hidden;
@@ -123,7 +123,7 @@ u32 sys_getuid(void) hidden;
u32 sys_umask(u32) hidden;
void *__sys_mmap(void *, u64, u32, u32, i64, i64, i64) hidden;
void *sys_mremap(void *, u64, u64, i32, void *) hidden;
void sys_exit(int) hidden;
void sys_exit(i32) hidden;
#undef i32
#undef i64
+4 -2
View File
@@ -20,8 +20,10 @@ void *__vdsosym(const char *, const char *) hidden;
void __onfork(void) hidden;
void __restore_rt() hidden;
void __restore_rt_netbsd(void) hidden;
void cosmo2flock(uintptr_t);
void flock2cosmo(uintptr_t);
void cosmo2flock(uintptr_t) hidden;
void flock2cosmo(uintptr_t) hidden;
int _ptsname(int, char *, size_t) hidden;
int _isptmaster(int) hidden;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
+1 -1
View File
@@ -17,7 +17,6 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/sysinfo.h"
#include "libc/calls/struct/sysinfo.internal.h"
#include "libc/calls/struct/timespec.h"
@@ -25,6 +24,7 @@
#include "libc/calls/struct/vmmeter-meta.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/macros.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
+1 -1
View File
@@ -51,7 +51,7 @@
*
* @param fd open file descriptor that isatty()
* @param tio is where result is stored
* @return -1 w/ errno on error
* @return 0 on success, or -1 w/ errno
* @asyncsignalsafe
*/
int(tcgetattr)(int fd, struct termios *tio) {
+2
View File
@@ -27,4 +27,6 @@
(TO)->c_ospeed = c_ospeed; \
} while (0)
void *__termios2host(union metatermios *, const struct termios *);
#endif /* COSMOPOLITAN_LIBC_CALLS_TERMIOS_INTERNAL_H_ */
@@ -16,17 +16,17 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/fmt/conv.h"
#include "libc/calls/termios.internal.h"
#include "libc/dce.h"
imaxdiv_t imaxdiv(intmax_t n, intmax_t d) {
imaxdiv_t retval;
retval.quot = n / d;
retval.rem = n % d;
// satisfy quot*denominator+rem == numerator
if (n > 0 && retval.rem < 0) {
retval.quot += 1;
retval.rem -= d;
void *__termios2host(union metatermios *mt, const struct termios *lt) {
if (!IsXnu() && !IsFreebsd() && !IsOpenbsd() && !IsNetbsd()) {
return (/*unconst*/ void *)lt;
} else if (IsXnu()) {
COPY_TERMIOS(&mt->xnu, lt);
return &mt->xnu;
} else {
COPY_TERMIOS(&mt->bsd, lt);
return &mt->bsd;
}
return (retval);
}
+4 -2
View File
@@ -17,12 +17,14 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/intrin/strace.internal.h"
/**
* Kills thread group.
* Kills thread, the Linux way.
*
* @param tgid is thread group id, which on Linux means process id
* @param tid is thread id
* @raises ENOSYS on non-Linux
* @see tkill()
*/
+26 -3
View File
@@ -17,11 +17,34 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/calls/termios.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/consts/pty.h"
#include "libc/sysv/errfuns.h"
extern const uint32_t TIOCPTYUNLK;
/**
* Unlocks pseudoteletypewriter pair.
*
* @return 0 on success, or -1 w/ errno
* @raise EBADF if fd isn't open
* @raise EINVAL if fd is valid but not associated with pty
*/
int unlockpt(int fd) {
int unlock = 0;
/* TODO(jart) */
return ioctl(fd, TIOCSPTLCK, &unlock);
int rc, unlock = 0;
if (IsFreebsd() || IsOpenbsd() || IsNetbsd()) {
rc = _isptmaster(fd);
} else if (IsXnu()) {
rc = sys_ioctl(fd, TIOCPTYUNLK);
} else if (IsLinux()) {
rc = sys_ioctl(fd, TIOCSPTLCK, &unlock);
} else {
rc = enosys();
}
STRACE("unlockpt(%d) → %d% m", fd, rc);
return rc;
}
+19 -2
View File
@@ -16,6 +16,8 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/struct/iovec.h"
@@ -26,6 +28,7 @@
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/nt/errors.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
@@ -35,12 +38,25 @@
static textwindows ssize_t sys_write_nt_impl(int fd, void *data, size_t size,
ssize_t offset) {
int64_t h, p;
uint32_t err, sent;
struct NtOverlapped overlap;
if (WriteFile(g_fds.p[fd].handle, data, _clampio(size), &sent,
_offset2overlap(g_fds.p[fd].handle, offset, &overlap))) {
h = g_fds.p[fd].handle;
if (offset != -1) {
// windows changes the file pointer even if overlapped is passed
_npassert(SetFilePointerEx(h, 0, &p, SEEK_CUR));
}
if (WriteFile(h, data, _clampio(size), &sent,
_offset2overlap(h, offset, &overlap))) {
if (offset != -1) {
_npassert(SetFilePointerEx(h, p, 0, SEEK_SET));
}
return sent;
}
switch (GetLastError()) {
// case kNtErrorInvalidHandle:
// return ebadf(); /* handled by consts.sh */
@@ -68,6 +84,7 @@ textwindows ssize_t sys_write_nt(int fd, const struct iovec *iov, size_t iovlen,
size_t i, total;
uint32_t size, wrote;
struct NtOverlapped overlap;
if (opt_offset < -1) return einval();
while (iovlen && !iov[0].iov_len) iov++, iovlen--;
if (iovlen) {
for (total = i = 0; i < iovlen; ++i) {
+1
View File
@@ -19,6 +19,7 @@
#include "libc/assert.h"
#include "libc/fmt/bing.internal.h"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
/**
* Turns binary octet into unicode glyph representation.
Loaded 100 of 521 files, more files were not shown because too many files have changed in this diff. Show more