From bf03b2e64c1f38f2e20cbd0126dc858d31f9ead4 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Sun, 18 Apr 2021 11:34:59 -0700 Subject: [PATCH] Make major improvements to redbean and libraries The most exciting improvement is dynamic pages will soon be able to use the executable itself as an object store. it required a heroic technique for overcoming ETXTBSY restrictions which lets us open the executable in read/write mode, which means (1) wa can restore the APE header, and (2) we can potentially containerize redbean extension code so that modules you download for your redbean online will only impact your redbean. Here's a list of breaking changes to redbean: - Remove /tool/net/ prefix from magic ZIP paths - GetHeader() now returns NIL if header is absent Here's a list of fixes and enhancements to redbean: - Support 64-bit ZIP archives - Record User-Agent header in logs - Add twelve error handlers to accept() - Display octal st_mode on listing page - Show ZIP file comments on listing page - Restore APE MZ header on redbean startup - Track request count on redbean index page - Report server uptime on redbean index page - Don't bind server socket using SO_REUSEPORT - Fix #151 where Lua LoadAsset() could free twice - Report rusage accounting when workers exit w/ -vv - Use ZIP iattr field as text/plain vs. binary hint - Add ParseUrl() API for parsing things like a.href - Add ParseParams() API for parsing HTTP POST bodies - Add IsAcceptablePath() API for checking dots, etc. - Add IsValidHttpToken() API for validating sane ASCII - Add IsAcceptableHostPort() for validating HOST[:PORT] - Send 400 response to HTTP/1.1 requests without a Host - Send 403 response if ZIP or file isn't other readable - Add virtual hosting that tries prepending Host to path - Route requests based on Host in Request-URI if present - Host routing will attempt to remove or add the www. prefix - Sign-extend UNIX timestamps and don't adjust FileTime zone Here's some of the improvements made to Cosmopolitan Libc: - Fix ape.S indentation - Improve consts.sh magnums - Write pretty good URL parser - Improve rusage accounting apis - Bring mremap() closer to working - Added ZIP APIs which will change - Check for overflow in reallocarray() - Remove overly fancy linkage in strerror() - Fix GDB attach on crash w/ OpenBSD msyscall() - Make sigqueue() portable to most UNIX distros - Make integer serialization macros more elegant - Bring back 34x tprecode8to16() performance boost - Make malloc() more resilient to absurdly large sizes --- ape/ape.S | 76 +- build/bootstrap/package.com | Bin 122376 -> 437768 bytes build/bootstrap/zipobj.com | Bin 130568 -> 134664 bytes libc/alg/bisect.internal.h | 30 +- libc/bits/bitreverse16.c | 4 +- libc/bits/bitreverse32.c | 8 +- libc/bits/bitreverse64.c | 6 +- libc/bits/bitreverse8.c | 4 +- libc/bits/bits.h | 198 ++- libc/calls/calls.h | 2 + libc/calls/clock_gettime.c | 9 +- libc/calls/getrusage-sysv.c | 35 + libc/calls/internal.h | 8 + libc/calls/kill.c | 2 +- libc/calls/mprotect.greg.c | 4 +- libc/calls/open-nt.c | 13 +- .../wut_test.c => libc/calls/rusage2linux.c | 18 +- libc/calls/sigaction.c | 2 + libc/calls/sigqueue.c | 59 + libc/calls/struct/rlimit.h | 4 +- libc/calls/struct/rusage.h | 12 +- libc/calls/struct/siginfo.h | 4 +- libc/calls/wait4-sysv.c | 31 + libc/calls/weirdtypes.h | 1 + libc/dce.h | 6 - libc/fmt/strerror_r.c | 430 ++---- libc/log/gdbexec.c | 2 +- libc/mem/reallocarray.c | 9 +- libc/runtime/clktck.c | 75 + libc/runtime/clktck.h | 12 + libc/runtime/mmap.c | 4 +- libc/runtime/mremap-sysv.c | 55 + libc/runtime/mremap.c | 43 +- libc/runtime/openexecutable.S | 188 +++ libc/runtime/runtime.h | 3 +- libc/runtime/sysconf.c | 26 +- libc/runtime/sysconf.h | 22 - libc/runtime/winmain.greg.c | 18 +- libc/stdio/system.c | 16 +- libc/stdio/systemexec.c | 25 +- libc/str/getzipcdir.c | 53 + libc/str/getzipcdiroffset.c | 30 + libc/str/getzipcdirrecords.c | 30 + libc/str/getzipcfilecompressedsize.c | 37 + libc/str/getzipcfilemode.c | 47 + libc/str/getzipcfileoffset.c | 37 + libc/str/getzipcfileuncompressedsize.c | 37 + libc/str/getziplfilecompressedsize.c | 37 + libc/str/getziplfileuncompressedsize.c | 38 + libc/str/iszipcdir32.c | 38 + libc/str/iszipcdir64.c | 41 + libc/str/memccpy.c | 8 +- libc/str/strcasecmp16.c | 2 +- libc/str/strchrnul.c | 16 +- libc/str/strcmp.c | 9 +- libc/str/strlen-pure.c | 11 +- libc/str/strnlen.c | 7 +- libc/str/tprecode8to16.c | 39 +- libc/str/undeflate.c | 2 +- libc/str/utf16.h | 18 +- libc/str/zipfindcentraldir.c | 10 +- libc/sysv/calls/__sys_getrusage.s | 2 + libc/sysv/calls/__sys_mremap.s | 2 + libc/sysv/calls/__sys_wait4.s | 2 + libc/sysv/calls/rt_sigqueueinfo.s | 2 - libc/sysv/calls/sigqueue.s | 2 - libc/sysv/calls/sys_getrusage.s | 2 - libc/sysv/calls/sys_mremap.s | 2 - libc/sysv/calls/sys_sigqueue.s | 2 + libc/sysv/calls/sys_sigqueueinfo.s | 2 + libc/sysv/calls/sys_wait4.s | 2 - libc/sysv/consensus.py | 32 - libc/sysv/consts.sh | 743 +++++----- libc/sysv/consts/BUS_ADRALN.S | 2 +- libc/sysv/consts/BUS_ADRERR.S | 2 +- libc/sysv/consts/BUS_MCEERR_AO.S | 2 +- libc/sysv/consts/BUS_MCEERR_AR.S | 2 +- libc/sysv/consts/BUS_OBJERR.S | 2 +- libc/sysv/consts/CLD_CONTINUED.S | 2 +- libc/sysv/consts/CLD_DUMPED.S | 2 +- libc/sysv/consts/CLD_EXITED.S | 2 +- libc/sysv/consts/CLD_KILLED.S | 2 +- libc/sysv/consts/CLD_STOPPED.S | 2 +- libc/sysv/consts/CLD_TRAPPED.S | 2 +- libc/sysv/consts/CLOCK_BOOTTIME.S | 2 +- libc/sysv/consts/CLOCK_BOOTTIME_ALARM.S | 2 +- libc/sysv/consts/CLOCK_MONOTONIC_COARSE.S | 2 +- libc/sysv/consts/CLOCK_PROCESS_CPUTIME_ID.S | 2 +- libc/sysv/consts/CLOCK_REALTIME_ALARM.S | 2 +- libc/sysv/consts/CLOCK_REALTIME_COARSE.S | 2 +- libc/sysv/consts/CLOCK_TAI.S | 2 +- libc/sysv/consts/CLOCK_THREAD_CPUTIME_ID.S | 2 +- libc/sysv/consts/EADV.S | 2 +- libc/sysv/consts/EBADE.S | 2 +- libc/sysv/consts/EBADFD.S | 2 +- libc/sysv/consts/EBADR.S | 2 +- libc/sysv/consts/EBADRQC.S | 2 +- libc/sysv/consts/EBADSLT.S | 2 +- libc/sysv/consts/ECHRNG.S | 2 +- libc/sysv/consts/ECOMM.S | 2 +- libc/sysv/consts/EDOTDOT.S | 2 +- libc/sysv/consts/EHWPOISON.S | 2 +- libc/sysv/consts/EISNAM.S | 2 +- libc/sysv/consts/EKEYEXPIRED.S | 2 +- libc/sysv/consts/EKEYREJECTED.S | 2 +- libc/sysv/consts/EKEYREVOKED.S | 2 +- libc/sysv/consts/EL2HLT.S | 2 +- libc/sysv/consts/EL2NSYNC.S | 2 +- libc/sysv/consts/EL3HLT.S | 2 +- libc/sysv/consts/EL3RST.S | 2 +- libc/sysv/consts/ELIBACC.S | 2 +- libc/sysv/consts/ELIBBAD.S | 2 +- libc/sysv/consts/ELIBEXEC.S | 2 +- libc/sysv/consts/ELIBMAX.S | 2 +- libc/sysv/consts/ELIBSCN.S | 2 +- libc/sysv/consts/ELNRNG.S | 2 +- libc/sysv/consts/EMEDIUMTYPE.S | 2 +- libc/sysv/consts/EMULTIHOP.S | 2 +- libc/sysv/consts/ENAVAIL.S | 2 +- libc/sysv/consts/ENOANO.S | 2 +- libc/sysv/consts/ENOCSI.S | 2 +- libc/sysv/consts/ENODATA.S | 2 +- libc/sysv/consts/ENOKEY.S | 2 +- libc/sysv/consts/ENOLINK.S | 2 +- libc/sysv/consts/ENOMEDIUM.S | 2 +- libc/sysv/consts/ENOPKG.S | 2 +- libc/sysv/consts/ENOSR.S | 2 +- libc/sysv/consts/ENOSTR.S | 2 +- libc/sysv/consts/ENOTNAM.S | 2 +- libc/sysv/consts/ENOTUNIQ.S | 2 +- libc/sysv/consts/EREMCHG.S | 2 +- libc/sysv/consts/EREMOTEIO.S | 2 +- libc/sysv/consts/ERFKILL.S | 2 +- libc/sysv/consts/ESRMNT.S | 2 +- libc/sysv/consts/ESTRPIPE.S | 2 +- libc/sysv/consts/ETIME.S | 2 +- libc/sysv/consts/EUCLEAN.S | 2 +- libc/sysv/consts/EUNATCH.S | 2 +- libc/sysv/consts/EWOULDBLOCK.S | 2 +- libc/sysv/consts/EXFULL.S | 2 +- libc/sysv/consts/FPE_FLTDIV.S | 2 +- libc/sysv/consts/FPE_FLTINV.S | 2 +- libc/sysv/consts/FPE_FLTOVF.S | 2 +- libc/sysv/consts/FPE_FLTRES.S | 2 +- libc/sysv/consts/FPE_FLTSUB.S | 2 +- libc/sysv/consts/FPE_FLTUND.S | 2 +- libc/sysv/consts/FPE_INTDIV.S | 2 +- libc/sysv/consts/FPE_INTOVF.S | 2 +- libc/sysv/consts/ILL_BADSTK.S | 2 +- libc/sysv/consts/ILL_COPROC.S | 2 +- libc/sysv/consts/ILL_ILLADR.S | 2 +- libc/sysv/consts/ILL_ILLOPC.S | 2 +- libc/sysv/consts/ILL_ILLOPN.S | 2 +- libc/sysv/consts/ILL_ILLTRP.S | 2 +- libc/sysv/consts/ILL_PRVOPC.S | 2 +- libc/sysv/consts/ILL_PRVREG.S | 2 +- libc/sysv/consts/MADV_DONTDUMP.S | 2 +- libc/sysv/consts/POLL_ERR.S | 2 +- libc/sysv/consts/POLL_HUP.S | 2 +- libc/sysv/consts/POLL_IN.S | 2 +- libc/sysv/consts/POLL_MSG.S | 2 +- libc/sysv/consts/POLL_OUT.S | 2 +- libc/sysv/consts/POLL_PRI.S | 2 +- libc/sysv/consts/RLIMIT_AS.S | 2 +- libc/sysv/consts/RLIMIT_CORE.S | 2 +- libc/sysv/consts/RLIMIT_CPU.S | 2 +- libc/sysv/consts/RLIMIT_DATA.S | 2 +- libc/sysv/consts/RLIMIT_FSIZE.S | 2 +- libc/sysv/consts/RLIMIT_LOCKS.S | 2 +- libc/sysv/consts/RLIMIT_MEMLOCK.S | 2 +- libc/sysv/consts/RLIMIT_MSGQUEUE.S | 2 +- libc/sysv/consts/RLIMIT_NICE.S | 2 +- libc/sysv/consts/RLIMIT_NLIMITS.S | 2 - libc/sysv/consts/RLIMIT_NOFILE.S | 2 +- libc/sysv/consts/RLIMIT_NPROC.S | 2 +- libc/sysv/consts/RLIMIT_RSS.S | 2 +- libc/sysv/consts/RLIMIT_RTPRIO.S | 2 +- libc/sysv/consts/RLIMIT_SIGPENDING.S | 2 +- libc/sysv/consts/RLIMIT_STACK.S | 2 +- libc/sysv/consts/{EBFONT.S => RLIMIT_VMEM.S} | 2 +- libc/sysv/consts/RLIM_INFINITY.S | 2 +- libc/sysv/consts/RLIM_NLIMITS.S | 2 +- libc/sysv/consts/RLIM_SAVED_CUR.S | 2 +- libc/sysv/consts/RLIM_SAVED_MAX.S | 2 +- libc/sysv/consts/SA_NOCLDSTOP.S | 2 +- libc/sysv/consts/SA_NOCLDWAIT.S | 2 +- libc/sysv/consts/SA_NODEFER.S | 2 +- libc/sysv/consts/SA_NOMASK.S | 2 +- libc/sysv/consts/SA_ONESHOT.S | 2 +- libc/sysv/consts/SA_ONSTACK.S | 2 +- libc/sysv/consts/SA_RESETHAND.S | 2 +- libc/sysv/consts/SA_RESTART.S | 2 +- libc/sysv/consts/SA_RESTORER.S | 2 - libc/sysv/consts/SA_SIGINFO.S | 2 +- libc/sysv/consts/SEGV_ACCERR.S | 2 +- libc/sysv/consts/SEGV_MAPERR.S | 2 +- libc/sysv/consts/SIGIOT.S | 2 +- libc/sysv/consts/SIGPOLL.S | 2 +- libc/sysv/consts/SIGPWR.S | 2 +- libc/sysv/consts/SIGSTKFLT.S | 2 - libc/sysv/consts/SIGSTKSZ.S | 2 +- libc/sysv/consts/SIGUNUSED.S | 2 - libc/sysv/consts/SIGURG.S | 2 +- libc/sysv/consts/SI_ASYNCIO.S | 2 +- libc/sysv/consts/SI_ASYNCNL.S | 2 +- libc/sysv/consts/SI_KERNEL.S | 2 +- libc/sysv/consts/SI_LOAD_SHIFT.S | 2 - libc/sysv/consts/SI_MESGQ.S | 2 +- libc/sysv/consts/SI_NOINFO.S | 2 + libc/sysv/consts/SI_QUEUE.S | 2 +- libc/sysv/consts/SI_SIGIO.S | 2 - libc/sysv/consts/SI_TIMER.S | 2 +- libc/sysv/consts/SI_TKILL.S | 2 +- libc/sysv/consts/SI_USER.S | 2 +- libc/sysv/consts/S_IEXEC.S | 2 +- libc/sysv/consts/S_IREAD.S | 2 +- libc/sysv/consts/S_IRGRP.S | 2 +- libc/sysv/consts/S_IROTH.S | 2 +- libc/sysv/consts/S_IRUSR.S | 2 +- libc/sysv/consts/S_IRWXG.S | 2 +- libc/sysv/consts/S_IRWXO.S | 2 +- libc/sysv/consts/S_IRWXU.S | 2 +- libc/sysv/consts/S_ISGID.S | 2 +- libc/sysv/consts/S_ISUID.S | 2 +- libc/sysv/consts/S_ISVTX.S | 2 +- libc/sysv/consts/S_IWGRP.S | 2 +- libc/sysv/consts/S_IWOTH.S | 2 +- libc/sysv/consts/S_IWRITE.S | 2 +- libc/sysv/consts/S_IWUSR.S | 2 +- libc/sysv/consts/S_IXGRP.S | 2 +- libc/sysv/consts/S_IXOTH.S | 2 +- libc/sysv/consts/S_IXUSR.S | 2 +- libc/sysv/consts/TRAP_BRKPT.S | 2 +- libc/sysv/consts/TRAP_TRACE.S | 2 +- libc/sysv/consts/bus.h | 24 - libc/sysv/consts/cld.h | 11 - libc/sysv/consts/ill.h | 28 - libc/sysv/consts/rlimit.h | 32 +- libc/sysv/consts/s.h | 84 +- libc/sysv/consts/sa.h | 14 +- libc/sysv/consts/segv.h | 16 - libc/sysv/consts/sicode.h | 105 ++ libc/sysv/consts/sigpoll.h | 24 - libc/sysv/consts/trap.h | 16 - libc/sysv/netbsd.py | 62 - libc/sysv/newconsts.py | 74 - libc/sysv/nr.py | 20 - libc/sysv/syscalls.sh | 20 +- libc/sysv/versions.txt | 12 - libc/x/x.h | 3 +- libc/x/xrealloc.c | 24 +- libc/zip.h | 74 +- libc/zipos/find.c | 17 +- libc/zipos/get.c | 2 +- libc/zipos/open.c | 8 +- libc/zipos/stat-impl.c | 6 +- net/http/decodebase64.c | 18 +- net/http/decodelatin1.c | 16 +- net/http/encodebase64.c | 13 +- net/http/encodehttpheadervalue.c | 10 +- net/http/escapeurl.c | 2 + net/http/escapeurlfragment.c | 2 + net/http/escapeurlparam.c | 2 + net/http/escapeurlpath.c | 2 + net/http/escapeurlpathsegment.c | 2 + net/http/http.h | 3 +- net/http/indentlines.c | 8 +- net/http/isacceptablehostport.c | 106 ++ ...lehttprequestpath.c => isacceptablepath.c} | 30 +- net/http/isvalidhttptoken.c | 9 +- net/http/parseurl.c | 346 +++++ net/http/url.h | 36 + net/http/visualizecontrolcodes.c | 11 +- test/libc/bits/bitreverse_test.c | 25 +- .../calls/mprotect_test.c} | 69 +- test/libc/fmt/strerror_test.c | 10 +- test/libc/release/test.mk | 2 +- test/net/http/decodelatin1_test.c | 13 + test/net/http/encodebase64_test.c | 12 + test/net/http/encodehttpheadervalue_test.c | 6 + test/net/http/escapeurlparam_test.c | 14 +- test/net/http/isacceptablehostport_test.c | 59 + test/net/http/isacceptablepath_test.c | 92 ++ test/net/http/parsehttprequest_test.c | 29 + test/net/http/parseurl_test.c | 357 +++++ test/net/http/visualizecontrolcodes_test.c | 6 + third_party/chibicc/as.c | 24 +- third_party/dlmalloc/dlmalloc.c | 9 +- third_party/dlmalloc/dlmalloc.internal.h | 2 +- tool/build/lib/cvt.c | 1 + tool/build/lib/endian.h | 129 +- tool/build/lib/machine.c | 7 +- tool/build/lib/stack.c | 1 + tool/build/lib/syscall.c | 2 + tool/build/lib/word.c | 1 + tool/build/package.c | 63 +- tool/build/zipobj.c | 147 +- tool/decode/lib/zipnames.c | 4 +- tool/decode/zip.c | 312 ++-- tool/net/.init.lua | 1 - tool/net/{redbean.ico => favicon.ico} | Bin tool/net/{redbean.html => index.html} | 4 +- tool/net/net.mk | 33 +- tool/net/redbean-form.lua | 2 +- tool/net/redbean-xhr.lua | 9 +- tool/net/redbean.c | 1269 +++++++++-------- tool/net/redbean.lua | 4 +- 307 files changed, 4557 insertions(+), 2581 deletions(-) create mode 100644 libc/calls/getrusage-sysv.c rename test/tool/build/lib/wut_test.c => libc/calls/rusage2linux.c (83%) create mode 100644 libc/calls/sigqueue.c create mode 100644 libc/calls/wait4-sysv.c create mode 100644 libc/runtime/clktck.c create mode 100644 libc/runtime/clktck.h create mode 100644 libc/runtime/mremap-sysv.c create mode 100644 libc/runtime/openexecutable.S create mode 100644 libc/str/getzipcdir.c create mode 100644 libc/str/getzipcdiroffset.c create mode 100644 libc/str/getzipcdirrecords.c create mode 100644 libc/str/getzipcfilecompressedsize.c create mode 100644 libc/str/getzipcfilemode.c create mode 100644 libc/str/getzipcfileoffset.c create mode 100644 libc/str/getzipcfileuncompressedsize.c create mode 100644 libc/str/getziplfilecompressedsize.c create mode 100644 libc/str/getziplfileuncompressedsize.c create mode 100644 libc/str/iszipcdir32.c create mode 100644 libc/str/iszipcdir64.c create mode 100644 libc/sysv/calls/__sys_getrusage.s create mode 100644 libc/sysv/calls/__sys_mremap.s create mode 100644 libc/sysv/calls/__sys_wait4.s delete mode 100644 libc/sysv/calls/rt_sigqueueinfo.s delete mode 100644 libc/sysv/calls/sigqueue.s delete mode 100644 libc/sysv/calls/sys_getrusage.s delete mode 100644 libc/sysv/calls/sys_mremap.s create mode 100644 libc/sysv/calls/sys_sigqueue.s create mode 100644 libc/sysv/calls/sys_sigqueueinfo.s delete mode 100644 libc/sysv/calls/sys_wait4.s delete mode 100755 libc/sysv/consensus.py delete mode 100644 libc/sysv/consts/RLIMIT_NLIMITS.S rename libc/sysv/consts/{EBFONT.S => RLIMIT_VMEM.S} (50%) delete mode 100644 libc/sysv/consts/SA_RESTORER.S delete mode 100644 libc/sysv/consts/SIGSTKFLT.S delete mode 100644 libc/sysv/consts/SIGUNUSED.S delete mode 100644 libc/sysv/consts/SI_LOAD_SHIFT.S create mode 100644 libc/sysv/consts/SI_NOINFO.S delete mode 100644 libc/sysv/consts/SI_SIGIO.S delete mode 100644 libc/sysv/consts/bus.h delete mode 100644 libc/sysv/consts/cld.h delete mode 100644 libc/sysv/consts/ill.h delete mode 100644 libc/sysv/consts/segv.h create mode 100644 libc/sysv/consts/sicode.h delete mode 100644 libc/sysv/consts/sigpoll.h delete mode 100644 libc/sysv/consts/trap.h delete mode 100644 libc/sysv/netbsd.py delete mode 100644 libc/sysv/newconsts.py delete mode 100644 libc/sysv/nr.py delete mode 100644 libc/sysv/versions.txt create mode 100644 net/http/isacceptablehostport.c rename net/http/{isacceptablehttprequestpath.c => isacceptablepath.c} (84%) create mode 100644 net/http/parseurl.c create mode 100644 net/http/url.h rename test/{net/http/isacceptablehttprequestpath_test.c => libc/calls/mprotect_test.c} (54%) create mode 100644 test/net/http/isacceptablehostport_test.c create mode 100644 test/net/http/isacceptablepath_test.c create mode 100644 test/net/http/parseurl_test.c rename tool/net/{redbean.ico => favicon.ico} (100%) rename tool/net/{redbean.html => index.html} (86%) diff --git a/ape/ape.S b/ape/ape.S index ad4986203..e355ae632 100644 --- a/ape/ape.S +++ b/ape/ape.S @@ -865,48 +865,48 @@ ape_macho: @see "The Portable Executable File Format from Top to Bottom", Randy Kath, Microsoft Developer Network Technology Group. */ -// ┌14:Uniprocessor Machine ┌─────────────────────────┐ -// │┌13:DLL │ PE File Characteristics │ -// ││┌12:System ├─────────────────────────┤ -// │││┌11:If Net Run From Swap │ r │ reserved │ -// ││││┌10:If Removable Run From Swap │ d │ deprecated │ -// │││││┌9:Debug Stripped │ D │ deprecated with │ -// ││││││┌8:32bit Machine │ │ extreme prejudice │ -// │││││││ ┌5:Large Address Aware └───┴─────────────────────┘ -// │││││││ │ ┌1:Executable -// │││││││ │ │┌0:Relocs Stripped -// d│││││││dr│Ddd││ -PEEXE = 0b0000001000100011 +// ┌14:Uniprocessor Machine ┌─────────────────────────┐ +// │┌13:DLL │ PE File Characteristics │ +// ││┌12:System ├─────────────────────────┤ +// │││┌11:If Net Run From Swap │ r │ reserved │ +// ││││┌10:If Removable Run From Swap │ d │ deprecated │ +// │││││┌9:Debug Stripped │ D │ deprecated with │ +// ││││││┌8:32bit Machine │ │ extreme prejudice │ +// │││││││ ┌5:Large Address Aware └───┴─────────────────────┘ +// │││││││ │ ┌1:Executable +// │││││││ │ │┌0:Relocs Stripped +// d│││││││dr│Ddd││ +PEEXE = 0b00000001000100011 -// ┌15:TERMINAL_SERVER_AWARE ┌─────────────────────────┐ -// │┌14:GUARD_CF │ PE DLL Characteristics │ -// ││┌13:WDM_DRIVER ├─────────────────────────┤ -// │││┌12:APPCONTAINER │ r │ reserved │ -// ││││┌11:NO_BIND └───┴─────────────────────┘ -// │││││┌10:NO_SEH -// ││││││┌9:NO_ISOLATION -// │││││││┌8:NX_COMPAT -// ││││││││┌7:FORCE_INTEGRITY -// │││││││││┌6:DYNAMIC_BASE -// ││││││││││┌5:HIGH_ENTROPY_VA -// │││││││││││rrrrr +// ┌15:TERMINAL_SERVER_AWARE ┌─────────────────────────┐ +// │┌14:GUARD_CF │ PE DLL Characteristics │ +// ││┌13:WDM_DRIVER ├─────────────────────────┤ +// │││┌12:APPCONTAINER │ r │ reserved │ +// ││││┌11:NO_BIND └───┴─────────────────────┘ +// │││││┌10:NO_SEH +// ││││││┌9:NO_ISOLATION +// │││││││┌8:NX_COMPAT +// ││││││││┌7:FORCE_INTEGRITY +// │││││││││┌6:DYNAMIC_BASE +// ││││││││││┌5:HIGH_ENTROPY_VA +// │││││││││││rrrrr DLLSTD = 0b0000000100100000 DLLPIE = 0b0000000001100000 DLLEXE = DLLSTD -// ┌31:Writeable ┌─────────────────────────┐ -// │┌30:Readable │ PE Section Flags │ -// ││┌29:Executable ├─────────────────────────┤ -// │││┌28:Shareable │ o │ for object files │ -// ││││┌27:Unpageable │ r │ reserved │ -// │││││┌26:Uncacheable └───┴─────────────────────┘ -// ││││││┌25:Discardable -// │││││││┌24:Contains Extended Relocations -// ││││││││ ┌15:Contains Global Pointer (GP) Relative Data -// ││││││││ │ ┌7:Contains Uninitialized Data -// ││││││││ │ │┌6:Contains Initialized Data -// ││││││││ o │ ││┌5:Contains Code -// ││││││││┌┴─┐rrrr│ ooror│││rorrr +// ┌31:Writeable ┌─────────────────────────┐ +// │┌30:Readable │ PE Section Flags │ +// ││┌29:Executable ├─────────────────────────┤ +// │││┌28:Shareable │ o │ for object files │ +// ││││┌27:Unpageable │ r │ reserved │ +// │││││┌26:Uncacheable └───┴─────────────────────┘ +// ││││││┌25:Discardable +// │││││││┌24:Contains Extended Relocations +// ││││││││ ┌15:Contains Global Pointer (GP) Relative Data +// ││││││││ │ ┌7:Contains Uninitialized Data +// ││││││││ │ │┌6:Contains Initialized Data +// ││││││││ o │ ││┌5:Contains Code +// ││││││││┌┴─┐rrrr│ ooror│││rorrr PETEXT = 0b01110000000000000000000001100000 PEDATA = 0b11000000000000000000000011000000 PEIMPS = 0b11000000000000000000000001000000 @@ -1437,7 +1437,7 @@ long: push $GDT_LONG_DATA .endfn long /* ▄▄▒▀▀▀▀▒▒▄ -█████▓▓▄░░░░ ▒▒▄░ +█████▓▓▄░░░░ ▒▒▄ ▐█▓▓█▓▄█████▓░ ▀▒▄ ▓█▓▓▓▓▓▓▓▓▓█▓ ░▀▒░ ▀▀▓█▓▓▓▓▓▓█▓ ░▀▒▄▄▒▄▄▄▒▒▒▀▀▀▀▀▀▀▀▀▀▀▀▀▀▒▒▄▒ diff --git a/build/bootstrap/package.com b/build/bootstrap/package.com index c166f101844afb4fd400166e110fe71e08a43db1..4266ab544f1bcaca4143c1082dee4b8a5eadfbb8 100755 GIT binary patch literal 437768 zcmce<3w#sB`ZvC56WSuWK|xVLB38wtXzK-Ap^!)lyO>J3$VEWVLd6~h4kUmIlAbic zx-Q@a<>&37M?D-tMMVfj+LS^A-l(90_ky>LLFA&PfRgw7%xuym4eI~@dEZ}^nc10V zp1D2q%rnnCGby?C9|Na5i!N<12v(s*;D06|+inEO8$2T6BO$1tCJ1lXBSNIp(xs7h zl5c-@{?1K;5V3^USOwuXvHQY)O|`=G{OybDjxXM=ym#V^?z$k{R(W8C5D+p-OSAH$ z8-$D_F92|7^vA_EL0J6h2I2fbsjxVhAIy&)dD(m1?mkQJEM%=QZ=W1!4HGwb}2VHRFm!JG?*i_wEfg)-~2Gc>jWS-Se9lH`G`=FFg7p{k_or(Nzzx zdSun;mme8hf2;SfH$RA6M?Ec3uAGYfNi1-al*1=o#G}YVbAK7B`#> z-q5aV=UJz(F`aC@;8%H*l-Crz^5RgR3)df28J{v9)m z3T!j~e%JJ(9ya>B_UdbU*vh7Prn-#?Tfy}dF?Cka)M@S+o~dQFtNUFwY4WVArh4wa zyZz+5QR3t|lgn(^_w9#DOzUA3HGRfiQ{CmZOULD3e|@oQ;JB;D<>SA+eEduK?`rzK zzBk->T0Y{g27De;()_#T8pIP!nzX+ZXVie2jF_!#@jBr1Y?6y^Gv<{ zp2@ae_gvP)c43iiPC@Spy|0ZA5xR3|%FzB}@;#nj9PF}K_p;jb$Q?>WVl-K~yk2Ef zrr9RXm@#d}4YsM1Cr`2^9?S-=G zp1URq)9#)$^Y7E9-7QQmxH?amI_>UhQ|}Zy2*QAJvAa_c3WT+}sS_d^Ma+|;!2CxH z|H&Q3x8Xna8vlOuH6dfoE9VP>NjN!V=(qdLgbi$J`q}W$6FOJ~p+b1(4ZCOy`kGFP zJ%Z&w-f9yB{kzlj-oNQzoCeONcM$Y-f_|5vcQfhtnVufqyv6Hrl|NlRx?HI%-zW$+ zp*(+2d1?7GEUvK5U09yOziUy5w_Ir{A0$3sUf44Ce1s9AXj}P($IA4vFIWHXiQ1vU;!t^hv^@Xw@_-FhDBsWpS<0(R9VNrx?>yt8^1?>X1^(^s zGknK7&uG_N+{xt0^o6>V`#*QLtBeZP8Qbb>AIa4xoH%|#esFP6TD+%Lu+&&Bmpo`G zeb8KbNrOdbFh?)(7DY!dGLODwk)^xG9xw^|6~dZVzMrIDEUal{-nSD=^)AAi5Ao4a z7~LV``-ysvu;x{KW(bjge>-VqhUa)aJd^u){fYVu0>ZtE_mqd)38k5hSpo${X9jt| zp1Fnx@-kQOfGu+=4_GOH6`?$kiALr(mn-IS3yqPlA$#B9@_^8kC5S!tbgw@ynl9+k zS+q5kpS~hPKwMM#2CpCl#jDFtH<=KTCz{S)nTw$;KOLyN<-Vp97||aOUD8vi$Q!+Q z&*H|#!NpCB^|u8fTPV)|wmAQ%;{4{~{Am8?`9Iwvg+cn`wo9rr)CJhZDh&xv#@jMrW6(vb98!tdi-lq>k7Pzfr2(92KcS`>1Ks#mv2|(XA>UNZPftd~=W5 zOrrn3Xf#@^G~T3LE8MJgXg63HvBNr8aqj5i@NG7Q$060R0plP<3Y8$MsMaAQX%4GX zc?VS-228spZ6xY5%PJ}VfIm1}QlxB29ft2xs{<`8F8pxjSf{cLeYcTiyLOmX8dW}& z&>l%0x5FwGjyr0d`L9?3*P?)dR-TS7*dc2Y+G)4Cl!3ti58$5;{4(%MR;4krQc?$5 zr6L-CbZxdEi8pSRl&sJoj5T%Ts19St*E`iA9h`+jvfVC8y9F)+0 zusR~tWpL(*5UTRYjPrd#lQJmVfmwfvv^+LCC@w3qS*mOxGM1FYaTFcy()u=dPjql!>S)d~c|yfiKe^9#DM$5dke#UTLdmx+Q%03mJBalNE~Q2C zZOI<%80Q%8xXm$Pd_9kke4nOLzsX9okvv$ctYiB@UQ$lT$}jrf-=a~M^1Y;dt-DYNnlZj!?CzzO5%pmXC;ZuY*cOXwX9Nr% z<3oRxkH^H)2eNpY}(dQ;wv9J^|np=)QtP1BMPQt$l6G|O}if=6*HUu9@f3~ErQ+*Jg z<@h&Y!ieJ0N&7LoktMlqvAPmH&^(CMXTpS72k>ld@LBCVf%=91&_|HMTK}j!68@-O zI{rHv%$ynf zfS-yl`&C}QmZ4M&{+Ea^)?cwS2#x}YUQ@0KJn-n+4<3m5)Jw#Xsg-}jzt%r{Yw&+D zG^^uZD_87Z#cGwx=X=UZR8l-aNx3DUFFuZiyoTW9(AGU@UgQBORJ@I7D*SIaE+wk( zX~EK>)JsZe1JMdwosPVWRmxbhqzmg^%04;s7Asp5B-In7Y+1*U?X>aRB&CZC;R!iQ z3McoRbsk*Xtp7;r_<)=_KHFvbMlSryCEj=>@`~)+S|C^c9spyUneR}G1z(Fvd~9Bi+^xuHCWoc&`z+aU2`SPotrIbBfhXozHbla{}iyGcWb3P1_~RjlOWe!cC0R( zc|=;3AM|ZUC+t2fy(THgnk^0gZYN~BJCbB4sU}IYTT3gtOUhoXQ_rIF#M2rq|0a;g zQ`G%ze^W~YSrgQYg$BzLH{=NBkYyP>yGs_td}uEkEFJsg2$>b8(TZi!p=?31+z2;h zDL9xd1WmFq9EF`d1<1WqK)T+Ftcr{ZldQCm%qc#<%20ujD#CGtFe@VYLe|K^rH*F% z`Bt}$ylnUBfHXDwn%enV+POP8#Omo?x{`aXWo)3i>i|Jo74Q_3=PUa7sdhrp^XTeQwm7w%A}pIy0+1WQNd-Y8~VG#K41 zzJ~wn9GYx`7isT^1|#c1K6c?l9YtMbXC-zI4iGjBh0|==ghEXiqB?06Sj{ait=Bn^ zg1P$k+cw-8C>Elfy`}90S=l1JLZZ(3lD3qPxs<)p&Qp!d2KsR92>7RkKArSw8&mzX zwHVEN`pI^JRquKUkDGfY#XW~Oo1Trh4bKj@3l*kYskzb42Zo?MXoQSuAgvlcQq7Wm z{RL0P8f*S`xw7w$uRsX+vdg}{JA^wmIl~k72N7YCR*9Q}8#6lD1#z7@Q!{5qo3gCu z_PG4oq6(pA$Khfja&0VddBx>5-G4<)kBTuhS2iPXZbf0u9ls!8t>|CVk$|%*uBlmm zq*xej3Fc8vM%7OIO%f`jYe11RZP-jFy2p+&Sf#<2g!&TOxQRLfCBiWU&UoI@MDSIHoW z?T(@D?n5-!X;HZ@VwLN{)&`Twsf@{XDsl&9XeXyKw2NcRZ4>p^F>9qeFiLImm zTle|0>OtC})qSs$MCS*6$B|nV^!zM6d>dv@Qx_T3vP7uJSYq#>c3yyLDy8NP!E7{I zk-CKJHe$JwV(FWiBj`61-s)e#IP{xZi)_I+YNSG%p{hAqef2zyhC|tM+k}Wkzwk_p z5EzXSmkL9kLjfyDLMm+V{II(}J~LA`2OGs+@JAG0I8b_gVIWLw51mhN|u2vO0U!2c9{;rmTX^;zreYSH5YsPwDfqtWs8pn!#^VUl=8 zVk{n{5M)~fXH$@9I%Jv4V%cEb%YrMgP*OSx1R=|>XYdecwB0hAl}%vY+n^w@Tm=|T zgbFshzskxdva&-T4MGV_|EgHnu=IN(@H%(L(xEyDgi-65(ULEi9rbq{J>Rxi~xWy)G7v#dGIEs!ZBs5BDj z@&QRb6D%QxTJOPj+E;IK7DnbzE3RtxtOp{tl_p3=2Ht8;*UMdML5V-={;V9-BD< zs+JFAAyAMt@qml6bx zD!X<06AUMO2YkIRIoHEs94>(pMl)T{FOss$rOjLFD{{R88uj!q(WcquP}Z9dzU7di zl6qrhF(mLo)@kRHJi|Ddq!cd-d8xLC@E7u$iA5ecawNPAT~TX?qu)d|KnK4eE1}3M zY{t3J{k0#PAtl|?1R~pl&XS-ttUCZUQNx<9&B&6KgEDv}I-KE`m7NZBhqGX}Lwt6# zy((%KmxUZv$3_2klme#WC^!hF0%cPWDGm0jqoV&cq)6)3l9Dg0B~6mjo^}YD>wJ?- zbDp08?hLIB>7}eE!Ga6x#VQ&=S?lnH48T;5r>t(GK#Hz!n zfnN8K!I4~;?*GDvq!llPPRetEq!urdct4|tBy){U*f?N_&gk7#%z!rjYWzvca;j!z zSDLZ@T~dzlfi7D`1ARw{Hal^kgT_FQ?e?bwU7}4sDSx$>a*NpqfPk)hFzEnP-kO54<>E^S?MV+4>~m($tsXUp11RD`uDKKxN4K+MwG zopA~X>CfQf{~84_jqb)3eIYPdmkhve@_y)q8MiT5vgo&flSocDSz);qn1O*Y2V>^qh&sD(rns2I1!Z^_ z4wIK2hS-KOJdeXjZD7oOGatB587>7{ApW5wTXGvbWvII?mROLIcoPx}Vu__GiPsVS%0Cg_DcJ+%*dP#=Vk5-Ym8 z5zXsGPET?!C8q~D-QbAb*#e?p-JZZ#m zQl39wXcm-uUrW@JrR-s(WkA@ztj?M@q#^V%lo@Z?c>NVd04J`A3M+=J}KR5mtI zqJJ+j8>qn8$TcLch5mP05{=v-^ljpHNc68qnoAjiULAsd+D4ZetMBsP#QlD>Il?=FXl-%S%n`jWkJ_ zK;43AnB0gSEFa?0WvOXruzaKJNCOXGBwg;~LbK>U1{NW9yi-Er=r)PpvcyrNkr*4| z)|@+7;-D#p)Bqlr_a0UkC8S@${M~w2!|!DHR>RLWe1Z8P{kL~1-){XN^F#W6!`BVJ z$?*5U*MBxXelYy6nZHBdW%%zJe!Y=iYxwI8|24z^kKzB@@SigLN8z_+5^*By3?AT8 zyQ4?4Q;9xG6G9zj5Lq(oh_Eywvb2-YBrg6C5MURBKxLyqWyXBvdtQUNWEO10N(ss2 z6~L;1IwgrcM#$9kB<5vRVI+o`olHh|BMq~Dx}+`fVtCWj?+^kiTh9QrL32`Z6fhh^ z=AetxOzs{?rMXX3oMv*L#*-PbmbRVyq{yMUUz$4izhU&xhDBEDq4COecsJ4v6-57g zERBzgtZbGc3p(NwN^JJKF#BC;rz@ZRgSxo1L0z#2GPph)7<}^S@5IP}>tkqUqcDYr zW|S>Hh-|YF6IqgHe=?OM&;I1Jw-@yDd-1VIsq9 z@Ptz>>OX_x%f+c+4Qa)ZJxFGo^!Sp0s%pFmNOi&=EcZ_`R1^LRgP9FbSJ^a>F-^5( zf-0jl_0Cc>X<~X3msxJ4wyr7h`F0)BAVZBt8YT$C+`6PB2?lLa+aoI`KbH&Iq{di- zJw0p4N;f+1^Ldk&W0UT$T>RveEE~IzX940=AT=a%Y(p;K;$UX0TyQUd6%q?h#TX_s zY!eKzAi2+7NOLLEdZH0|spC<=(ilU9Sdg4Am!*wL%NVRklay01h7)XYKZRKEJxe@= zSnwfBguD>bnsKF3r!Aa2Sed_DH^bMX^?cz!YWP1J{twI#>E9UNyN&N%hQGt`Lxx`q zU;o7T_`vWRn7>=EHvBgX|79cnCBuK#@EvYCN@CC1j!R3!eHi|jfUs4r`-wIOn~c@^Vx%Sr2&u_u@Z^|)keYlH zM4eVZ_@2!K8XOp*)sfoOVH}8v{v9k0%o`&I9Sx}n9r01EMk3<_SpOj*u=PJ>fABAW z(Ei}BNeGM){E>vf89{7pk_m|z0rmiYzzAadgXDa~2u>v-{O>UW{mdZe0_~Zk~~PTb&+v|46pF((1Wr zrQLnD{>BNYFh#BrYN0?0j#q|_8iS+pp3%nqooY!-VVyW| zGwefViQc(c(Q)qV@{l=e9IOtcXvjN1I?iKm7!2A;U60Cat z&F-ru?PddMvZlS!0mBX775%W~K<^$UO+S*K;EIEz zXqBVj`1}uWZsXpLWIg;g4MIrY3twD!MhYNvDcWDDN9EID(s$D=s8swAGWeu8a zKJo$;uT6(uoNeO7bqZldMOc3wo6ok2lb|8Sc?bAYU0v8*Av(r53D-S{R#0k)VUY?C ziwmBjT51DL2Fo|lVZ+4FNIvBF#v-G*ZlI~I3FCB#&hO%YhYdh+Nk0H#GgQ?ZKDA6l zi_j@~X#EFH({>pK#dhyW^h_@RxIlO8n1(6iOB6!^{=xkBX}q^l$L`o@7RD!0vlEBM zuS|i73pD>{!1BDgc4@N{hU=j7n4Rn`8?s^cR>Q0zV1^9ST5Xe#*+r%fNI=7V>|1ab zO4>6AkpgphLP}%gTG~?0UGk z=JXMra~syUZop?cLZkyO%~Vkc{kN;c|C76&Tv#l)hgHw{ z4aOSa2{}?BP7i(t06&w7M|GejP#c~BydMFtrT~z6A zaKGAvRJl7SbRor!rqGo45xSW|MHJ_xke%XgpimbIn!D|G$~)Rl*%+I7uOTEJJY1x#8OJqq!hB0Ytp1#%2LivlhTc)L_4;vwaQYy zOOx_2OL;d<$_|$DdYY6?EaizbDetnBd1+D(v6QkjDd%jV-jUO!T+C9gilw~A)=%FS zFB?Beo9AVQM%7-LZ_nX;KUC~(hp=jS57t(`maGTP!QB&_EZdEFt(>f-^k`%40?P9I zPn?1{ItVVfnT5Y{UxCeoyCK1h$S;z52CmpB^dYX_>H9HHD%*)kGFVd17S~&~!Hwm< zV>z=v5ZKVrC3iDycKtGakeT8tl3cs0oDIH2*_L;0*dx3*bcdg_-SOK%JBl@vg z{GMd0k9-7)s*5p^=q?I1o*~`v%4)Db6|5sM^3Wtkv;|>+#ZUp8x%DVQQX`oyab>_v`M|N zd+hu1QdlACx7{rWH))-&aFBf;3_XGXj;b9#ej15tr;nGDr6L{aM|H;;u#-0JAFOox zj&d?Xij%C&?@)`#H8r_F;DoS6m&0(As3KaT9K+#0L(Dn7+IK4}^dqzo{f)a;4KR2- zDD|=Y1BP((<`yfzvfAM`&K2POTNk06>MlUbig^IVP>O1139hmh8LK{3UhVqvLjb+3 zUMl-ss{6)DH-uoB)of|yF5)Nn9XyB~$=u!Sav zmDwI;vOw>@vs!rdUI+w6-(jak#B&B?wU`@A_3?*sicj&i7)?QMuE0{bSJEaoj&EC72PMRF*^Z=d(leFNKwYr1p&v+T& zGmFRz31qb+h3wfApM$kn$ZkE_4;9638K|ZJBE%Hk306CY4<8PBvq=ljLLDe12#B*H zgeZi%u(%9_y2j&r#zR-I5KP;=1q_bz_Kl~G<8enq-iZjoL>bZTKs zRIEAxvpmJ`rgmr>gRmdb3t=Im)YA-k3zcFsT4ewP?|%dElF?CpSf_~owa7av@ce!~tX2 z!b1^usV~w1$r^4Dqe-&%c5V~C`J9;eI+%d%F3tpYV_Qeb69HCDTf7<@#!#1bz)Hr* zm8v&=5yBfPifb&#g`SJyT9gLY4N15dgf<6C z;N*Ip%b@H9t+nJ}iG8*PiE%Q0h|wPr93dt)E^Ae}Hqb;V1!&Mp>1s)Zi7yzA01>gIUe{8AO9d}? zL=Amg^2o5GTz!V7c6cxx{q0xy#(5ij{WUm5DE0JF1E-e8QD07fCs$&(3jZ4 zUK8-*UO`gF5j(DC>8j=Rw?T1rO*tg^(%qn{c}Q$apU+b%WsK*+sMC&JYbI={UpSgz zL!ERKNu(Ic0*8s$tydFGA|+XOcq^ghj6hPC(r7_Z3hGZjI_^tQ%BbvsJ+&o&qm(~C zMmwDqWASf<1UbkYVyqY|C%6vdL8o9IUnkPn+T0*&CmT$Ji7xuX&73i&<2?UKXu8UH zQ>$>Jk4DBYLFnUFfkZ~ZsijfUOAu!ss!Z zaCRq5&~Kc0nfqr^GWDMxW-+_<-{I?Dkh7bdofHjAY6wA)G)Rhq_^}#wgo!lbYq_!` zd18;Fe(htqM~BtDHiAAlf|v+|%ChA>9dq_*u~egbNL5!QU{#g+5nK~R+6hunUz}wE~YUmdlya4A>|;XMwZF6jq;NS7tbG~ZL;W_ zXw*;TV%}wkN!G912ia{iv#RIHoLJ-1HoZqIl{a0NegQo^1{S4D|HV)YAm>JMir^&5 zcgV;2f11_KGe}aoP^E4pie$2&{u8OCG!|jB##nPa-D1d$N}PT>NJ)V1SP!j4(VNNn z_ zSjztn)zoB3HD5dtnKRjnF}nZw6xPg&>^C-;!XH zzlJRzp%5r9s(&{DghaOnEHl2t{X#RD)M676rhQv16VMAaJ>cj|(9v{pu1>cqmO^Ck z1v@I1YbmFtH(ZjTLY6#)2pm^4au7tNuw*<#w>4zt3%PQuAasOX=R{U8%7HRTQa*+0 z72!UhlQQ0+Y^A*l+rdQUQQH=uk9yUHe@7*5KqYu+I6`Emxf8f>5wKh@}2$yu%b|x_9oR_BF`i^0>6n=&LP$u;$q)o8$sos32@Ry`VK~^ zy;!c{sn{g=nh>h!4m&fSj*v@JDWU{hH04vL@?*`J=h^}PHO2!K#VlqjA$=RB35%kI zGK+xZBH2(tiS_ zNxl=# zRCnCQa?|q2C@a2sEm3qQH0a2C(FCf2k+B;9vHJ~QM!vR~UI3Dn56Wqa4LQ=5NbbeT zK~|w8GCw(v4OSfA$MG6t!;HRe-7xd&VBr3J8)bo}kX6BbJAVqJr10mNa;W${^L4w>F3glS4hx*P@AR!Cx#~*3J}>8io5}A?lVcn`!y1X zN(P{wkv=ZvAT%hE{>6$OUI?n>Q_cqAf_+xoP*_++0^9#HZ6jfChs^qyd$AaXHq$i5 zwuuaVV^4j=)hm(;yAKK1GDLB`Ag*tuW2W+ph2P4HgfHCt;O@ai2+aY2EOEUF_3eZ$ z`W`{3+t*%$4IOk2O5^x?Wpjk7UJPn#K`X8v0^ty{zTBtOIupnGgK;BS%3hQKev$3@ zzO4#L;yZ65b8l)6&Gn6X-LJzR$OL??9 zejA=ZIt`uBX&7B^^6c|}E>`&fB}3m)Qh0JE#E;^D)TcN&!@>qgQcG6i37bPLh6??1 z--#YLne&~%`5Z2ni~bjpS^0_;(wTK8DnTp)mEfgW@!X1MJBoa6D7#Tr17b94^)29h z^R_{MP=>6n@$VrX^;ki3^gKzuC4gEimo9rp^64h2aI=I{%m%Xwr+88KIWjI#pyDOs zKxll5R}K!DTL?d?RD4^cgmGn?bd)yEb0({8CtgXM)0iT(pZz4@d^IXSnqx^^{ z>JBqqN!dtC6YjI+qD^~d^yD*&%6}i_qgt7feXVgD5J#CJ>!s>dFY`az${xkFmPQFz z!+rZsf)3=uEe`Rqt>H=(6enbvlwG?xbKA?T$m&ngGQVZ%33Mvd3Yu+M>RSYL7oD!M)tXY1t>ZV$K*IuTPXC5M(di|Yj0bL z{3A7T;lY`f0W?-HesC!}+tPNnF)!$1A;`Ls$Qrorm9$$8&0yq$*1J2G5rsjQ=8Kq0 zw7V^Ea!0`Yqi?R@?&_f9$FfFO;qjRtlt4sNOB!!ht~lgS8X`50hGKMeSpzOF&Fnxa zQpjA_N+#I}WWr}oWG7n=VupOJ6A;IFC-HvNuP$v;7A{Bcw=%I=&xhqd#Hba(sh9tY zO!&#WiL|*ZspIReHj^!%P#EZP5 zKbQa#Q*Ayr>JLTzM<`1l%Rj#$Q6CpFV&$GvRA!fG&Y%(DO)`|9&O%*W!tNIFK0tmh zb#u*vxb8uLNqX_igyKUVfLiIuw*kI>>9Y_^dysP>IbGp!PSk1>7FaaeE`*E6aLa=D z15w5(oxt!o-k$g>HvfEUWmw!mwSgO11&uh14vPL4&_ZvYt3*H9oEfhr4e~RlIILLt zDNvBS6ZOn>UDWG>SF)jCO-Z=N)u-3RNN`ULOixKFLsAb)nk3`Nj2v2gzO76D&t3 zh=t<+CP5q6+Fu+rLL|+sHjIus0$T~p`%Cq8=yz<~YjhfQRAJ|1zy@o9q8||9K8vmT zk#71m-w|KpSCZ-xjvOxc-Eft=w}f}eT!nQrzX8ePQj=kTQNxG%6I_MF+5#JlxgV0X z1Qz(+dVf^6Jd`mG2cvN=RSinQb{9@6m#ExNa)VLnO%sXYlp~U|j6GoD#p&>TMV)3stQ7rMLNQT-{+%d8a_6^4ow?aMC`1l9bFK4lu|tsjL57KiBeamJ zO=@Ta%?P68BM8#whLpq=W(?ijTnHKIu9P)lf;&P3gI$nI)*jfFyde|)Tahk@25v(# zrDNGnhvfy1rIAC;3MPte#KkkXV2Stm(8#DR52sP{PeIs_!o(^MaT<2g(Ym=Yva#Jl z4IOYXxf_or$$T5ZM9&*3qv9_hWXflf`WEl*kX~TJI#2ha-1o|wpY4OyWz_Y6;RE51 zfj)>`4F|nB>dA|GdPY6AC`05_OS(8Jw+m)6AS}iMbZodJbr}sF5K*zU)NFn2FlxXS z8)>fp2N7)bmbHOF(sPxEyfjKJEe+lb^64l)n~wf#(HdB0P*-5sQA;e3>-T!-%jAX|mv7o#ip??JWL zM8H*f7@k-G;w!pxI;h-ps|#lnNR~pG{HSF>_HV=kLj$bDE@kW~>-K}dt8!Z@yehYo zLDvr7?>Kk50HZ(qs$z6!KSY>3=T&4n#z%VB5?=j0w3eiSC&;qo5yq3lR}!iEezFj> zxUdtxD$YO-b47+@yj->wyx-5%kTE(>)$njN4e5CS?NqO2(8Xjo_8j6IzLU^bZlzRh zAyHSg7hx_ZD(vKpNO>aS{O)f5B#Elvdbax$;Ns&I4$h5OF}eJU-k5nDqHiz%I%6lUKJxj{-#c zg{A0xbyGGa{u7C{gjS!95bLXmg`to%jYdr>{M7Te*kAxNsF4o_g<%;)1Dzn1U{D#o zY>25{WaS|?j^q<>l4@F0*5+Cf6WNeTJX0|3;>4r8<%K3lS+)qSq-b;CxwK77;rWWb zyaxm&`pK%NL|bo1wi4x+gp2np))40$WZinJ9ZTm42{&d!z8F=7e8e^n9Woyd`KV^> z_|C_U@95CZM|IS2qG5Ge~N2@p&V7@IhZ;l-{2{SM+NR$e6l z$0p>#^mse>AREYZ>xl_HM&v~hnE;2HpGLiQC5bC3=RKcMy5I7`3y=b8hf@H)B z`r=W5?}p3QIV6oFWaoy`Q7jSlm!%V!#f!Af`T40Xoxd*TgN zIUm4@k0`Q|Z2@hTf7YKUiH)dl6OAio8r>>X*&wH{lIY(62tr4cWk9OD^7@XO_~G$W z4CIf9t3`AA|{foEw(f7aU1j23GhmkCjB8a z#5gqe@+X)0ZDCnmNBLapD~xxd3l|O|$e-yEIaymk*iui!UZ)AAuA?M<44~Wck|zKm zsi$9oU0A&97kC*eV``^gLhnL8BSTpg&p>3Xnd{Q=Av-H&PPTqrN>_D|p0z{B4Dm=*65+0-_!~md` zgMv=zM=H0_s+X{m>fgMNbz9jIc~Y-i0xI~(_*C^*@rm`Dh)&;(Few_Jr8vkKkHhDT z=plr3A36Vw$IYS7Y2-WzC-(daHdMp~$v|l%qQhi19r)K0>|9k)9$TD83^#T)C)#un z2`{63eN66Ac*X$-rir{j^lQ{;_5N(V5LATL(0;Ft>@(fh$LyZTG{}zuo~>f&30xGY zUyNq8LF>t5C`W@Pa8T@7mmg`>76*Vxk$8LhfH z5VgH#-{TFUqd3vt3FtPR%~TotX$oaweefMOiBI63gqa@yf{Jqw5*)tY zz!ASi2v1n)n{Fg^51jy1ZAMhva_MrQT($+G2IgQ_TCb^dQ2g*y7EilAyjCdsSER+r z7(-^avsnI=!DiL>B3mdk8zniFZ}ijA(;(coHM<>PlG^#*-ROog7<}d0<+^V(2Wze# zcvkeVq}>QwOMd^LkmZ;GLqZ%~WbhZvjgt=LxPE>y@Im=ciz;0+Zd;;>i;cj?oiK8Z=bV+5|vK5wD-o9+COB4s{mW9+?{KVT&A!62r_Pc#KvWT zMm08z8xYbrk@GhO!8U+R2AjYH*^kG#_yGG~hd>hfnos^Elw$!LB7!fj!(r)gr1G?x zh^7g!5I&E&oyFi~uXxN5gy%Tg(tfS;h?CwO1MuS)%;xE4ttgCceLf3?T8{Kc9jzqp@8b2Ti}sp=9K7=B}nzwI#JZNXGkh2R=$K ze%G^P9K4{UV5)5uk&Ud3KtdXmDs~G;EwxcjXmyh0w)vC`76qxsQ=Y#|s=a`6K+ltC zR^b^XE6&_T64Hcl6`WdXjb5#QfM^;GqM=f@hWo?U3lOVc1BcVp>GYXR&PC*$TmuOB7n<>_U2x3Ug^a~Np28<{v#Rd#@Hne3bn*o##rso-P`o~`A5HqVb5B{_a~Xxzdytx}mP$wV=x+7oqxkv`OFR6AeM?s1Hb?gj`{Yb$6#T2*U#Z*tYz zp1<2qrCQ_KN*+)OAea(DoU(wLP<6F$5x6r$CH-n z_YC(`xKKyXBt!^mvDXk{A{{hJteXoz75yWCKt>tFX9)#`dD*CaK*w-=@}9cZV!q$Q#D&~JC~UI zN)*tboNYLO$M3Y*5yUAcHN#*ukFeDz#*7vcYGq&-fJjE+<-XVkZyFM1ZGP)=w21P` z+MqX+^@O-kiG66w`>~=Ql7YZfh^=qPitGh2S)IRH-*G*VD+482840%a08CmK$7n5G z;H9sP_ereujen{11}rRXN`D=ZD1EIyl$VYtHb+iG=~LR2{xCsm^XY~t7t>;;ulh@+ zk4jhijlA?1^j*DK+oz!P=_mxNuu({oXwVJd4s{Te{Y^GNVS96mwSqrsM3)0WC0ism z;CZR*-KR)Kf9IjK1x9)C6^_JroX8ZAc@;{+U0$O;>E(~*tfWD2GwYlmGrh5wu>7ou zcEEu1tv|$2#xcBSG%Y3?7<%XUQt4n|qZ)aWAd@Ew5ZL;#@&;o0n-6g$T^F|Ja!`^z zwIsS7fs*XuVYI7udGRc=9Tf}T0F4IID27W&7cv|P`baqJ8mxW|eGZC$=F(?D{IfHC zn#lQWKAiI@bT&CZ;gh869QtUYw9m;oPR@tq934r0Iik(HpO)4}b?lu%&cDa-Pha z4Xm`uOf=_-jYxItxyLfl z5|f9@w|_JnCkGz1S3HZ9TdHWH$O;DOrr~Um8rdKv&6N&oxgd6@=TGJe^k8%Dkjp-5 zt4CtHoIah`G~mq0-gZ;zMWG32Mh^q54a+5M-DF>XlY26o37A1;dLy29$KZ(mCLl;A zGr{%{_M$LbxyWgQiUI$S)@<7j!{{Dnn~Y<-YI7H4|o-{`%r~N?s!b!eZ)fW_6g7-Jhk?@{Dxg%sAXM^y1f+*Sz%a(eF zcOHdmY#4ev^^Z=1jO?9D6jJqXbY=~4yojh@2lLMG8ho$_-}j~jj6LEQ9{@&n3c_CC zT!*ZZb{~w|);T*1MYZ@87p{j(;`vPALdEEPk`}yDf)}0LmH^rN6_KT_xRBOddSnAX zT5x;Kb6l95rXMJ_$%(Mk)gBL}&r zp6phKs8<{fZziTV0GT6ojAV?>QRK~3;_JzHj7&c!_$!QQxA9ZUn|yP>15vdjqtD1; zZj}j}+QFLnyY6V74HWGa;i zexspy8<|YN(rYu>n5pvu`f{YY)X70MUPNEG3;u)Xv!VAH8HS%jROLxFZnr9jW8;Q9 zD2@#@bn;~%8mX`VPd|2_$aws~onHcz%>m-NPS~aMVf&s9+b1RXp~o*B8`!X|<-_(K z;*<}_Y82E$=WMv31xf-9ce)ur2kAxEOvc%p)r0rxH)CqvU7~gcUED}?(djI4-QlX8 z_tsUOq~?eV`xDK;?s>O{leahpTo9)KfRcn@g$3E z9H^PXyHPh9*nzQu{VaK4EB6P80d#j_u#`X{Yz zNK}U|1ur3W=nMCgI&^gL1XB&054{i|@fhL%ubD!H|$nXeol} zL4ypG(hblRrv#-}AVWS%7t9Q6@RXo#21@Cjcm?d(0aR0%@jm@CvMq+H3bE;{MNh$o ze3Y)>iVZ+>6G78&&*=5%kdFY*HnBWC6Z3d!L5gXgzrlP9`6zt_M}I{kXnOQ(Ssnt6 zn!2M(Z?f8J8)+!?-IuZ+X=?3}_$IRw`EYPaN%V)d2(5+1p(b)DO5#wDdJ%MKtiPGu z&2Hh)HjT;~h4R2!F4TKm0qiiF)*ht-YR(Wc1pQW)DEd1Br+#P+op?5!qFA!0!F@6m zrMJgxq<~7-1UmVGs*#fPZ@OmUXX&6T{Rok%k|)g!q9clDv%v`S89)MW6_XQVFhupS zFi|>%*?R~{ETER=tNsFHUZ$z)gH0o8$giQzt$J3@$HZzLxKhy5OzUWbrzQKX4h&(|q=HJq4Y)ukM-p^hgZs|E4l zGN4LjyK~SVH8{f&04gEUj{gv0n>O5s@~1q2=H1U^j>>OD z>YuN`TWENs%AfOSu;{>7*udU`_~jB#qqssI^^DU;^@P0IQtBz8=1XmwcLmU2Na%a% zO&}y2U8j+8yaIfdegk2MYH1=o|Ad+~4 z#9xMqG{miH6E>}E6Cx`bu_buKk>K$St46CYzIt*mk9)LPl@c-75rJ(wksIk6BHrW~ z;M>oi_)+FT_2&sXluwirJUmyQx;Yd5X6jSbQW{9ND--=cgJ31>%JkjnYhMe@arYr6 z^&*1ke+Ous>ctPwg{j-okBTq+CG|>z=qF{bQ`vV~=Z63UAvB1$Hm+=2A$sZErCl*r zuKO+%GLkE^XzhBK{FH1{=e?(QA|9*FZ=-s=3z=m6q&HE5SVf1psrMd4KmEJ|D?gW& zkKax8HC)%W{9XX#<@RkY_i3<1lndcLS>;JDIHO!^TQt9-4zA2zE$d)lpv^JXixfZFnyes%Re>%7Wwr@IQUo`*8p}mDxDwq^lT- z4><9i^nkyE;QPU8TOrz3fKV=_iljM=eu*W|vFWeoazgR%#)N5$#>de#;prLN%ovM* zux%ux)THC<3NkyymKX7fzX9bLB`Ns%c~*Q9yc4I|Ho&8wlj8FwX6$?Z;<;@g}XS9q%_~ z%Gly%UZ<_ihEUN$g!(|r1o6y;zMD-B_k>hbp2<>Xx1q?J)?8~?h>m_SRQH2s43$1R zdcl|RMN?WT+u~Xn2ipka zUb6$wtp3_+*F?vQFrcfZn@41IX&iNU?vO6BoIMA>?>I3fVK^?2U5o@z#~QkOMKZ(D zA?&i#09RSPQ#l5PfQ#!+DCm8BVUuA~<#v$4Px5}Blf*@+axE32pNmi&1w&3qWKNI8HZH(ZN0D`MXbTC>kynyins94ER(@CB$_7mQ?!@7KOh%!NP22kux31&5#Tvy9 z*7H?c8=2Vc35=Odzu`12-fucGAy#Z*yzz7()t^U%;_rYmS)7Zwm{vOx-&1H|tq|yf z4&8_+m+9)+ip*42`r_`O2ZjGo8*HpN%bnVag0IlAD?ZrS^3|GSz?WU`OBmu=ZOB^9 z?bqWYiXW^a{-<6Scpdz+>?69j2yXa^!GBW^rpT%&l*I{k2ndz^DjnWt{U>d%@QEvS zu*r26Y&L$$=zf5z8uhsXaP~fV;x9Lf{ySLd8WaVPc=0PcWy`3u{-hSyrK^Rw?v12M z*b5FDzpHZ^Re}vXG2}FrAiE+7iyFT|4u#25!h|nl;u*g(whLgz%4Aw*TIVPOZJnbA z=o)~kY}_46v6(BGa2d%;Z7bX(`rk!5ET^a#geb`L1qhPaYO;h=8$`7JWkEEk*E3O{~jt){dYL@;~2j(f46>!B6TCO$%y;{KF!reN_>}` z&Ces7x`_rv|Ew#7NQ?d&qSQ@PfPOv|hC-%{4Tadr>#yGH49RZ`%)NUx;w%k)!jj#w;E0Cq?@Vkc#|arEhnn<(OGy` zxt{6Mn3fEkWjw{ecFobo$lg?rupEmxD_Pm(B6$P*mSqy{)D+DQ4_la0c(@ekD{8!f zafq`(LM7U2I*Y{qDB&96954xXjj&O(qbI*fy$xe$BTP46NPgwFTu7EAE4q+x5kj1a8$&Y}AwEdnc&I8KiVdM*)*9P|&zIGH@parw^Bk%tqU))uSa}Qsfdhq};K#Gd zDv#ZW_KFK%1&LK2qqd7aXigD^*>+G|a370DOi=Xy6JZBVrJ*kWFPvIxmHyD}M)!9@ zhtrOcW-5Cx1IhX)a4L^saqx0$5Oq!Y2~rg8ERsZj!o@=H8QmF7(Tq7 zY{w=nYPj~s2`2nM_^7OV_hhs`+h$6;n*MvPjrRE0v%E+ZB6BM1(Ea^=$8aI=Jr+$U zu;vAc3~3+86@Z@>K+*7*uL%APm;kMs*$qL(e>V+rOP09gY*qwO8eR27EW7G?8)B0v z+ZaruXBtDQX)0wC5hYNzagFG|mB(Ong%Kes(1=@R_*&($w=#s_>7d_w7v3}%`5~xNTtpVA7XO@At5XyHL#QkQmyKn4o@=>5P8bw9K<}yw;YCvFYE`J1&@M}nnPv^7~APr-G z;U&h{F9(7I#{QD^uQB$dXBxO^dc;<)Sf%Rs-{XH0OwRFC2IN@DcQR+zIJ%{tE>SZ- zBAJ480CL%8ye2P$+u#Ujh;MTqorvJUdPq7C(_F?UyWNG~Z2WNUWAqIF66j#{1>?;E zG7O4aNnu}5XzrQb5c1O89(O6>A|gI^8!OnkN; z^~G!1o1Im=Jj>AxN5Q-FBgVy5pW_G69aZmmeB%1^z(-QstU(E-Bq45WoY7h zh~%-|k(am2c-FyO74-B|_Q1%3fWT~fD|lPE(}?or*zg(s6Th4HAs;=uoA(@@FFvim zI~Kh1d2;sRltTGTX^^$PBlM@RhMMY~_)U7{b3}l03{fRX>@&q)16_gkl!vl<3HnpO zg6EA4G$VkR$wE-sgGxAc3(#q1 z{33c^=O5$g20TPzt$QroZfLp{t^AyvPvEp!OtB~#veDfrh8>eGn}`rLO{AG)1{u}) zY;pYw%}p?ud5=a17tZ%TZvSI*8L(2E1GFl0TTN$hzMW@CKL^xJQ~~|n*J)3+6#|fZ zD0W(Tv0aZBPa$x{B9rs@)3k_$dG(p#YsRBglx-5^B-R4Vtz*0BXmBgBzu#b;O6D^| zQV%g=nnn_NQbcj4qCE%Q#ttI*uBARq98_26MmXf0)iGm;1Yx);muOX1s@QF9^0_LK z9}UvC%}DQQ_*@-XmCN*zNto<_pzb3XjoF*s5}QBqmjYs@G?H=xKWgjJ?t#5oRvsI& zcd#^;XdZjw>E~XI8=Zc>vD{7yxl_D^0TGD3V)O*>mFazaIU0kXGuPVQvV)BRDu!Ej zx(DN}j$ef5*zuSXmwm*W_YlgXn2=;Dm#nP(4{|~e)Ff-Onz$v`9gu?R^b6Qag!C*W z>q*+PRAZ5Awa?o%+c4`Q6F664SoA+js9ImGz)I29dT912gB~xUl^F+P=fh{eu|OK2 zZ%2aBQYo~W9K{DkZh^1YlJl7nv)9d#u7Ah6hvmxPtuAm{R=z32?(+M zR+vaHc3dRYw%X#=61j(mAeFI_R)K)tc4&YQh+n30#(xoujW)iLciYba3>~WubS5aE zME_x)dk)@RGZ4hbv;zqu+QOx%uA~l}10#f_oZqpW3s|zkpi&Xgn_NKPWe6BxDvpOa z4hEqxz*HPJa2(4y4gyTYVdXd$5rndk08??yup8c>g4iB+(`+-@=M#fT=k4avZFADg#Wd#CirX5GLUZc?(%3 z5^Xf`%eo~TO#lUn>qizCrKAAaI3|0!@&o~<2O^_uG>XR{ za%BnS_!H=b9QWHCcfV6ZlW1{^OIy+eNT8++s8a#epZ|Vsd@4OmNy@?|coJSrVGyD5 z)dEH?ES!$#o7lXj-@6Lw?qQ@u3h9dsf1=^fG5k`)pJMoS!;irgq`>t|f$M^A{Tddz zL%-ZeyvXoR4CRHNWqe1B?@Z(SbL0Dn;lFG6-x&Tz!{252tKg@KL_~ry{Q~Y?O2qU? z=H|~AY0s1*!dLWCPqx6m1Yqcrz0`B97lv94(J1;aJ648M*mQF{Vn10Fk-kA9vv75j z9oY5vz}oO8mt6T9?Cs}QlOu}*KjH@vNt-;UtPNQst2mfYSxt2tmL6E7=IhV3r}LtF zJP#0+3Xy)bR7brZ8q9>5K`4jxiv6j)7fNXdIe$%Dykx?*p~5J@<%~5rsHJw3o%Xc} z2emjVrTS9|q%MM&u&LH%pw%ZXhR!D#ladn8TDg$KPHQ7|$)gZEXT__RLC7?+@`()d z!)zGrS!Le=6B&$llX2NHb_epB{)8+yt2R@$LdDytdd4n3PY>XnLVuH-SK;8v z(YC^X$1U|4o;_oxjF&e`3J=Vxa48X-2bojjJWsiB zZbs71yrBLVN!28vcBc)aiQb&Vg6Y2x-5Q=lqi_N0gY(;MSoIT65P^cp$ZY$>FbxK# z$fwCY2Ge)6^3Un^z{QMiBLHqox3&Nm>DNF1|Br4vfnoe5y5;Y6wV~Y{rm>uTN>Uu1 zLW(2)Dk*Z}cie0ce+H28}Qiixa z;4IkAo{N$>NBfz^0Vn6*Ww#T;9kKCc-@g5}Xy?xmwY@$-+Ew=EAfP6^Z4ttIp+7Tn zjiT?*Tfc|UH~kcpkv@pNH@1HFr|(txE@!{*7<-3OVlz&)Ebn1K-N&!Mp(C!2kg|tP ztr|pgErjG+IAol`{wKiXtKc=iT2QWFWH6G3;Fy$zJNs`{uADGDC|-yntZ`b z{DM4t0*APpOS`cNZwmhq7XkvrR3*N=LqD{LK9Pvr_JR<0QT2G1k+ea@RlE2cWU8C( zNI?|#XiOtC9i>R>;3j)P3q58O^$e4$H{E#OcOO4ii<81_q+AOK(|(pQwzv%T<2m#u z@m)LF=IXK!p{G*t?-4wrpCK21;Tb5k9(;kb@oPO?l(=j#NIMq}y9q`@#U=QtwWDGB z!w6xalEmUY;kPhNW3zH&Y}+9z&r;(etCGfpUn)^8*%!vf19z~#r12odx=R~?@%TDn zJXpv5%*I1Y7?0q8FdhpDKl_oQg=T~j#)J2$q|8Vh4>KzuWjxmW!FV+A@o0{Z$2(|v zn(=^%4<*FLLu~Mj0Gj7)b+e5bSPDduc!g#XU1R<1#wK zs9=ba1uz|V#8FXHq9Rt?F1SI!CGY!A-P>Cd_`mn^`=z>WEvL3qr%s(Zb!wTa!xt{1 zEOQ2TDhD?y@^FS(TS!dQ3Q`ErFVzwF<$IW%p)&1Y{=e_B6=;!lTR(LEWNkTW@7pLJ zaOVBJP`8W!h;>QkHCAIG5D|px2L(VHLQKMYwD#1$h2JYv-&OqnXX^VJe%GeHujF@i z>iZIY&vd?>BF{mnU8EB7wLS$dX_ndD9 zvW7``Y?G?!3+eICGX5+l-g4LTo2Nnq)4nUFhl>&AtyE_g|;v*P6q2(?Z>Xgp;0I*0Hj>b3nH3APdX6O!P}tqtI? zx_#3@fO57^J9s!I6%COLcE<=m$tdduMrmaqJb6IddoH=X(+H1CZG>JZ7+9?%bSolh z)vxHA9=7P*2vKBX??uw(7qH7hSx>1o*gNmHhVL4n*Z&GrMsJ2>B%SMm(uij!5!lSgw&G!$dAQ zT7C%MX^K0r3PXJ15U_KzP78>A>I<*%Ek;Nmr>u)#2`)+XhJ0db+v#Pljuk|$sfA~h zxu#ao;nF^}7C!H)wxMNw6@2ZgLL}5%z6$snYvE|r+E4*40MVTM!Go#t95(Ydz=}Tt z7G?DgEI=%;e0fzN!tJLo8nS?e0ZdJ&JOHZSQ`-pOxfFm}d_xa!cK}KW;A&Rn4;fI% zW7yRwEW-T5+ncrc?WP*PgAl4XBn7EztV{uDL&iO{V>JM995?}ra5 zvi5UEIF9f!(cxd<$7SXw$Ib67(vHwi)ZZ7OWN)k&=Ly6yc{UYw#we+z zY%4%sEvZLy3*@S6;=7L!af$iXyId&TW)1AbP?B{8OUmxe$J_F^pM?+Hff^zbnamZ4 z27#f%!>Ag-MXJsww~X)xr1D2}RP;rPPqQih3Y~&cFzN%9&=)Dw%|69j!qOr^iHhFb znryIUU7{m5cWP468t1&T$rEZZ!V>|3d+0Shtb{4a(S#TqDdI=`u16dAy^+7@(}CIb zJPPSyYh@rXvpTzWdr9p^RwJ$^J0Ev9fLp`PM+3Q3FV4;{OLb)AVwCI2&d;S9<$92B zS#~~dd(6nlWr(ZI&bLUHTWjia$p$=;oqxK{{{+gNl$~FgBWv^|*~> z85UP%ittPc0?B-nGUU67rVSocNtKp?8!g_7(_AD-lTgBI&qT~DnSMx(YGhn+(&hml zC*vpwZKVt4roeK@lL;H9?HN?iM6}Ztq?B*deW+SE(VVKXXkuSlyU}N+Z`mTU=``|lXr_L@Y zaJfH%uSNXm`YdRaycBP;-0h+%u z%*nLMg}4R}oW^Q6x>Nc9lsbh_PM~u<9A~`oNDhZdkNH0!gXEZhh<>xjJbpME^Yf|5 zR=~Xf9ci~nwr{_u>frJ0kvk2a4?@hfTdfDYvdEOhsD&qcYRy4`m?$1R!6y8^nVsMY zCKxu&yx~Y>2M;jA)Eu=y{tPP96rjj*-h~9=L1c!0sef68kVO~i@7FiO4yFSST!jjeJ$0b-R;}~7@>Cd9*l}W=b0noD~=h_lK}+8mqZUL zwe2*hp!wD6dYS%4_!3MJ(@Li%;iK5qP0-B@bBNH`PDJGdWFk=kXeK!)dO{(R4ax4Y zy_js+v>`^&%~HA`F^4jRCNX#~Ns6<{%ngaI$cz#G2KzX4%Rt@cE%<`6fWrmGx`;lg#y>X8j0xJ&s~2Di z%;fHnE1$@dd|z2$q)tB~^YlU}?<>dTd1an=CF-)dj)A~x;W~Jn8Vz&b2*jkd<6z0& zJ%z*II)(BWW=5BB2bsoKJc0cq`HIKZcpScBITB{`6#(&rZkF6&vN;UgZxRkehmkWv zI&dA%j?#>UTLBD#uJ~`cq?;&Q#ZE#mlBeZ03A?iKi{V$tB1RR``Sh&x@!AL3?D2AW zNzWj>!EZeQXG^nQC`S<+Pb52h%YcIHDM#HWpH(#gRxmp$jTqraB^D7_&(#_0dq8B> zA~jvaf?OleRbVHs-!~7mtP0P0wzwNS2&7hV&Vh34^|Xd+JHRKY0!KGA*#VpTN{am& zTqAXs<29U{GPfov;V9X&Nio@%pzmDqx7c|-&@%Pg32+)HyGRNoj8qrZN*8VGzKfRl z0q9-8Xz=ZctHj#ZP11ZX?Jh8^X2&oaSO1#2za8zk?J` zuMKe3$x=%j!b1+oYCGVIKL6)hg3!C-QG)yk#|#ZkHiR(_NLQJzwSGnfke&h!J9KnNqE?>P9)$S?xedV0k=vlNPv3$ zHO~K+W&X=0DKTGfuTq`%Dfw6?!y#n$25&|A;W_YjgB3>T7kg>@kxQE&haGA#oGxk` zxT3q72FiVwO{grK0r|kWz%En?iqxCT%+*w`AYP_LXv8}_4N-^wkpo`!pMj{rQ*@?L z+K?nEG&gKhT@PkQd8EC2lHvugrfwsQ33R5@84IW8Zr=VuttJVr&)luiV2R&)j#1^& zDcGL9SkXnQ#Y{EqQAQcT8hjw#)GpF}h$t{|KeK&iZcvgqy^*P>4_*`tqI49L)RJ7! z9kS#`$3g0Bzh=6UAuyKcg)&BI5tU<_ZQYnxjBpj8;DVQ@=sg6}jO0?7hBU&H2|R)w z;iGJq4^|J1(C_HU?nXu=NT(x{B?3+)8!C;HD%3ZjA^@ng_WU=EEsgLq(!ZY$6E9jxbKxuK9(xA6;^|53inr?5cfSC-*GRnq?Cs=i z7ZC>Jc4_bQ((EmOLWk%@!5_WNx0gl-sIll_B;&5)9?qj*vCHqK5@~nE&S(ir$8`fa zE#-bKL6!~u144fo(A9l(s_EP;g*_+us?jm+_~7R!^nQ(3_I^E$Q@MZV9_4Rqdc;(f7~r8c)w zw2-U~@A29by-jMPc2}DVS(}>)@j5sT&pAx^%YYY*CizG3z_NiN;&jOl$Et015fC!u zo(`w#aK;XTNaN&p063>%6wq9o?h7SfN@q~QHD zds0-4+M`s+>jl$RJ!gx{2weft<H(4ue{r5k%*7#T{S`(&=hw`q`IT%56>OYiSoqsdL)W*Scp@Yn>Qou`k*s*Sa^k z)?rce7)x8cq3?|_HV9npir$u^E*@@qLhl)2?&`4GNnN2vXa;Ys!Fu-qLPgZlg=}Oa z;viEUXawJ3-Yyg~Vj!F6MhD>ewk>$R?K3lXe4z;o)Yet`n-fByqT|_}&_-0+rS5L7*-y!~$drmb`YOoVGWg--eWpv0)@!`rAAmP9I3_l0&~@UWl6d9J zFFZ}(=6Q^j+hJu0=k$Z1eSjg_B9-fnEpuw(+&VD36MqKR4Q2;|x3X$~P8*2QY>Wm- z0@i>`-g70JDO(tt+FaOReL zP9e3c7c{Vt5Q0|RYNcfIHYs{H9b_!1MH29Sp=J10+YiUFUG%Ey@%#9-4PPn&NA?fg z=cTJMTn+6iV&!Ti#TA$ubVr8@LWq!}bQ4mPt_fJ+x5{dEyZ%EPQQgc!XTnKxBTE=^ zB^+7KhRJdkI0{`XjCd@?4s=@XWs!51d!0N@xqBHYRpOP*1$5rmQ&DMqr57bVTqVHE zk&$Q!Xj>W)C7h&kVD66~UPibl=uMZ(fx{f-zz5&;V4L%QR1QqH*p`9OxsF+YWiL}6i_1jAyO6|*w)mFZ#xBm6MZYi?r^}_0Z}rK+^siDHewP45O11E=_n}%C zz6Hg}(cSA3*`<2ic1CIS!men}N32<7MnO{b(27#C$y&-D7FIxA{CBm z@!lJ|9`5nGpvM;=4Fu`^XA5 ze4;==erwu5N%SBSfi!N56RA>4ifa+xjgn&Kq{9P&n8PCv!DJ=>_9ZAUbqhA*SFP@c zdHf(8mav$=-C-}(0IE{)eygH0`u2e)09LHcYBUmBhpD|N=E(WTd%@J&(Ksu+JVkjt z_}+tl-^YJMrCT9XNRckSt7J22T2E0he|OYt8G)=m7;W50=N&k^YvA3f_}w>f3KF7$ zgHXM+240z}UmF_;5z1~fAb&jrb^G%8^ahg5Ia{+mYe2q80Br}MU7O(Su3ayt;&fHIlb696h!&|rz)p`X)McS+C$TO*4+CEn>%Y{Ubg8^{g4gJe;$nMwDnXu z&M>a<2KTAM+=ue6?Ui*KT^Y&(MwqLWb>J<>jBH_XDg1y;puG+^u>Y8ywzpM)!I$ z7pOp)zj&HwW+`IEWyRcoZuH7;T(V8etsEykmzlx{-AH!x9Mnbm-~dJze;qi-Z;dQM z_@vC7fngX>Dg;i=3I}U{^VC%*KI3uK=VKVvpYc#Q6if8WF%ZRkwjav+n9fExnOviD zL)RDi4L8tQAsWgqwZLbUP4Y*lcW7Y;9&WvhprUYi@)yRhMMey}fL66H%Hc|CRwciG|cXN4>HwO?TI5ynXYN8F|NqrSftrI>_s9wB0C70Pi2r zuKNM7)0j5Jamzo_3)?Aq(WWn%Q+vl6IEJDANTDDZh9L8*dWV{giel5&s;-AejiFP< zx_42=@!geikS=4OmZIJ7k3c`l0oxBA+rnz6>-LlV#mCH?4D{(laAp7@aY`UPZsv|e zd?%F;TDS3A10evXiPTk?8SJ3&NCd;~Ku%(@y4A4n9>?<#DE*zLHt*wef7|Vuc!nB> z#OiE1qu>boXlr#M<$}>Y%t~cq7|6}OPDH>wcIik_(eCk?KDXVdb+UvGPJ>1Ino_$Gluu5n#ZEEW~mYOu< zLPR$hYAiSkX}Cu{1i!@8@z|_)35+%;eOBoJOb3yDr5|-9-@>F}0*ynr8f$Pg3UR!^wyhaGvR+CweiB(o@TVqD=?ten#>U4{xb9m z9;@DoOHm;tE46z0Xb$iLn*K{d{6HY)5+bfbZx38y?QP~XchZj=Pm+EM7Y zJL&vH=Q}voNNOLeS=E1kq@}sR8QJWy-^K%Eyor zgWL%z#d?E<@F-fJp}RyhjAKgi0rEv{ByphLYxhQHt)a7;&K$@pv?k)z5FXEY5@FrU zsFQq_o@wf^)39FzGET4Whl*3%6k17JsEL(!yF^_IP+b#YkYD}wN}?ZYbUG4xVW=c8 z&j=Agy^v6%p=eB|l%N-uIx;aZVvR#`Tdr6mBHYM&St62$1{vY@qltt?urKS@TEjrV*qjd-pV0Y$&ixtCc=~HY zbNTnMnVC*#O9^8!9gB`X1KQ>kv}!9g6H81u58_SoCMr{ho&01NYX&x|A4yQBW#e899%fQG&da#- z=tL}TLA<86q??&&ah1f8BIW(j7rkHr@Fw$N13wc)cKLD-(v&-9ny}W5L9A=`TWvFXred-YpjLL`p5A1gq`ipOE zHReBqz+n3zJSAku@?9Z5Uz&&KOY`40LZ50Hh*={8msEBZ+SsfL(K=6R<~R&;r^y2- zoIIV+vMwTgo@H^(;!1NSG$McidJ??{)n!hii;=3UNpuv$yPrh7w2(fDxVGEf(&Z%j z2n>9Si<4uwlL${yc3={5a_n{z-7D#OaB}Q+5>-h$vIgBvB4g16q~X$9j$buA7sz`I zog?6Ix*R0G@2h>~_bt_vkvVqY_dPiIGE^tXb2!=$xY(4o%aF%CThwRYcXUh^gDBoK zBTT6)T+Y_+NS}2H4yD7J0`3=GMCjrlf%4$|-&Qb&n%Jgpk-~=_#`%SabZ#XumivSP z_3I!EIaJcd+G)};EpUP_B8SzTj=lp2`ywpbvGQ~P3Q{N08N?#(N54K7?#gb0SJZ&x zRD`Au#=ALruF^B}1AnF&Z{NIj-i4TT5!Qkpm~S)A8x!qwkUb?KwG`$b)~&rTl3iBx z!CZG)=#{`KoErBwbGBt(KK9`WVx%fXs#X!JljcV&d1MwzC?@XRgC zgAxu@%rndIiY-iygEBbPFkumbrn>D~%r33zcMd9Bo@smAA9+nuZDL(F1unv=^dWwj z=*~)39(mmx+=4cJuG5`aGYRhuH)94E<=9UZZIw?hr@xb7hBhET$v4f;C8Xu!!ndvmU64`VFrM^P@Mbg=*&DS5P9ul(+wg_)E`};)quvmCr6g^ zfiSq4QGtVOIYy0yMX4~>^SL`#cyXN~zg&(kM-^Q1g9mHcj&5u?Ln+@IyPfwucoz^` zy27;m%P1UX*B71xu0);!WM$N|I4!OTPlVSIV>DKvDk`5%C8JH%eJCY~O<<11wBOP8 zDR6=}=ivcqZXvz47z2|zojw@hWt3e|dG-IWo%t)$PAM(Eez-CJI(V^Fc$fB}JIy#b z=BHAx+V%*S8dz*bEh&8j{VmL{!TAiIcXJ_cCK&TYeQ9^6xyFLykb#8y2>hy>q4d%f z-@qrD%pD{1PXYS}%@{6IoynsSCWp|SR<9Ap2Gj1G$cO5`53?;{lhtK=p6m{0kKMwI z3)?BQ_Cs}<^p6O18Y*PeW9p%gbEzZ{@{tyFq4V(!X{!Y_982&IUE1WB84cSr#|ZUd z=ClM^qkf&h(D^M-lhZ5+TBN{q8e)V;N#e1EAPK&=m95btNs`Y!QG$gxr&7;79gIA| zk{uW3yLuS&=VJ2u$yoJ7sJEWC;;L5@pIy+#C33D}5E`L1IOl*#%&fr{ByysynNa72 zGS_EmmJE_|swP6S`VKI2et^QB28VO+NV^ZRQqcBllD0D37um~O-3|%UQUNRp!5xh| z&wGBy3J)sgJ@0(nkUq;>SBpW>3UItLugM5d-=$CfpXrZ!1=kIUKZK4~KkdS_`;N|6 zbiSa|MrRY9_vpM$rxlL3z81tN{xgONt*4hLs{YIPC+Iv%=kIWMDf%w{+R7Wz+3PcB zkf?bIL9%AAS3Qpgmf{%}G{RrJE%1jlyX7|3LG6(ugI7_-D8Lu%x$hZmW$D&PZfAGd z+2qDkOekk};?-g5dr0B!gAVqRb>Ka{AuZyY>|d(b$3RJWB$i)Sf6K4Us%;BqrcInY zSq(EOU-ir!#hHsGES+!#mW+*F@(qr^@E&09B?HFEGj*9sjL;3}1a&E@r2YiQwt;K2 zTp4ZnAFp>uzK`q@G4q$|-+0xEl{{`Me<6APQay&_ecQ|1ZVYO9v76IyzF|ig!4>p$67U5c!}?7Mj%`X8!o9#9ybmc< zHFL^Tq3xzMy%2HO7G=bRCbM5gv9i4&{TR#T|#@XVo#;$T~w3K6~)g-C&IwZ4-Fi%-LX~@hn!~iGKD<60WCW^-22X|)aS94q~y`FO>YR(v6Ca8 z{@7U?Mn)bxdvliuY+bTEd3@b6D z9{`2Dg07AB+Lgf7D;CXoA*Zla&2F*hsrNFxswt{51Gi%kx#IqWE~0A8*Zl2tE)T0A zEDk?xIDWJ;dXUQKDWZmOwmcE#h%{V`vKw74Tzii~ZlOtoy5UTW_WM8Qy3(TeO-AcI zUGbYY>~G?(M$X%2@tZUEllmvz@)K;!!Ha2Vh%50E3$Zi2?=|jjGK=3b?rHMknVf^o z;`fZZ*C00nLTjq_(>dJoqd~A^(m`Yrz>7?)7k83r4}mW0F4%WL?u6JICQyvbJ zgZ^ARi5kV@j+q+vgRmDcb7w)A+Dy*T4@Aeg?H_(Zk7J0BmfyG3q4w|o_|3%R;MY^_ zP3~%PeK^Uj_2H=>+WEd1U0_CU0(Y2BxQ#H4P@2{a2;ZjF>uh24woGC4Wk_Zn5#D5k zDE)(J6U_6@fPB_v2;Z0iD0NONQf&e%wT>wZZ!s3KPH9$B><%)*)d(-Q*bSLQP~)WB zg5fHnc_StyES-Rvf&K$Iw26qdXF%i=9s40-BVwJ9Is`I>WJiob3$yEg7gCs&YaIEG zFLyMlHAX0NpE{k%f_T;ywm;y-sRVXmiGQoHls!;PTX-HGF*T=F;0MMZ#?kl#(z#Yu zzzZ$e+J;(q8r$FqeyXGQM>9tMpoe%Eew7QLKvt8$d^WIJf|N|F+Td*{JRg86;AlV} z><2)cU>j?PXse2qmOx%=^CXX{Mf ze*Va{t@^k&{vG<5D03r@0{Ht^{Hkl=nSKC2Av(; zQUmLt%5$Ojf)45Bsh$a#UspI7h%UFMM7LM=&Obb{5ICY(Mb9vAgOP^K|jaoY=L76g5>Q*k^1N; z-ifOGgl{^Sxs#jlQZ?zyuk9TjLm|be2XpGh8F^{(RWBI}M`C-?6-_;ytU)DCQMJt6 zrm4WcbSBaW?*f@Ntw{)Xq}55WJFRs1ts$BcXXbiSqNW1dH)qPCpj$_P!C|1$lQ1#m zoeRFa)YbI53rT$zSK^K4pjI^e37@gL#assWUB0{sv+cq5BaGXxXKAoMm^HN?mFx#& zQ`N|mEj4uqq#;<07Bf6LH*2ctn)$4WI3yW^|B)UPxSWeVy7p3JW!K)Xvtq(!&f;b% zYGOahY6XyOv-*Rb=PATt_C8_emQ`b7q8(080wr$~My$KbyJbbKywHSgIBcvpm4#r< zTaA}{-z zzsU3FUfX0^(3-+&-?wQu32_@7S$vTRKpI~1&m7ll2`&=AlkrVC*p&eL%9>K`Nn!>c zdzL52@CKxXM+Kr69MNGOGhs39G7s8Lgs}w;-s(DGe2q|lWKq9X8}YmB6XG>Di%A2|Yi3`OaRhy-(i&w{Bc^k~@)P z@6+!=T>WF9%CH_x8HAqr=d7~TJ*#G06Y6MZ9=ztxlSob0nZ;$TM))D*MjQ8DlGF=@ zR2o2}oi;3W;@V{FR>o!uF&fzxb$vY7)yVp*tLS4j)y43s!y)465P|Mg&!5myGwqJ5 zMXyo8(}h6C7;beYPw_n_n)(PLgcQ-6W#_I&F4`MyVs2|fYlG_|kUS3@-SU;p`nQa% zvz@F+w1$UHAH4_P7|{R3nGouw*XzPYg-IyS+QAwUXOV6T{a06feW zEP1G%LAV!M(ic9P@N}sV$L&J(*^uFKt&h1cXGZ*4`)p#y%4X<~ftY0yuJe)9w9YQY z<9$(HTs5Pkac<#$atDi&xt~0oZEh{2b!#_xD0!oS~#faj6RO8;a!jBxDpR( zGkY;8s%cfi)$pmO={ybx8G7u#WyhdpRmYf-l0%s;=6>rZJrY58D*|%jrRX1Z2|!uy zIs{-%i@5&-Pie8b^?0n5o#soRkBAc7uL2PEl_#~6ZOKf25a%}0j?OBSF6 zSKt7<|7bFTxc=_v-E`d;lliQbpa z3HKg7Of^9|@0>pD0;AoGBb<3<~qe!59Rcb^c7KHU>>zYz(@p));i{a$``S z$ryC&dc5IF!(g!DA1v9vN`!o}n@X7!xW9r+(a3@u_Vr?g{K(h*buJ&9<%FU^0s6(H zfSe?T?K4ypXu4rGg%Jg)fF%D42Yu??%;a?k_w`Ehz0_DH#ufrvZ1kN3tu@K^ z9JBSy%%*iKHGF|NI(f0YyF8*!#_V=f)6drd zQ{(oOJ#M(Cx!ZBWVDX$yB&UHI^$2=^$KB&0{cp=$$^t&0HL8sdB$uU+70#SGzd-wQ zn>{>J?BTf-zv@^@Gggx%OkjL0SI&6S9{gJ%qm_7CI%C$cNca&F+Ut4pHRE|-_jBe0 z&d4_c9_9qm7;{35J4If{HHPxY8-6QLh`BHbbAhu1b3spurFu$C#+0}UQ{q}oi2$a= ztxZ<{56{eZS+t3IYk_J76{#e2Ebt2mwpJFP-?rbSG#dJR&54&QhS`X{nRL>m*!Bj1B%g%R6^SJT?? z$RcSY6yY(@SUZNJAhUA4zxcCR=bM$A%whd+O7wCC3Nxzt7i4OvKG~;xN}c*w)cPW+ z?JEEsFGm}_4dUfJ4)1F5UITAOtGNtsdCVNNO1HuN?)`4p7^`nv!=|)4?G5n0j&L&b(Yx z_z9q9|L-XLKmh7Y;WcWF9paCUEyTT62&FA)111nH_E^$7RfUN~x}QNy96AlSr2FiV z^b?p01gnQXl8I-8iZKunf5uPYuT4vm)`0kgI@c%%qELQKSB}JW6cqxL&UB>)1;`Ni zqtB3H;PLZd$tTZBukDTb=Zij6jU?=)SeZ+!+LYywK?mZyVB>*a?7zP4{DP2k42CP% z&Rec^ZEkFKF$=nT0^tR;J?6gbyIw9HUe|5eLvqURWA33yPJ&gZ_K=)s2{CtXBuCp^ zbzkoxxhcs%`4&5FCf~M)g)a$!CZG6hqth0OSoM zGA;M3AU_dzDPUn$TV78RC=*cK_$;`;W!a$r##~)IARuStmis|K!y5y2NYbi~fI$I$ z1WR((SPe(*_o0o9pMlSV+$YX6mqw1QTKEAtLk^n?(Z>-{H_^w=R@3QYKdLG8v5V9t z^s)8o4Eoq&WzxrLtE1slC2*{v53vBA_qM7_-z2463l+X!dd3O&Td@Y} zDGh4FM!PAAb1a<$ckj-Ipz;ATx@6?cqd^ED&4P?AU3)Qb0pIsqj+YxR#-VqfId4rx z9;;C`V7dBBEUg+t_gsw#su5OWQ4Q|Z{*2%9;_m_j@p=*`Eqa#b3ew&U=EO{+1e|@@ z`XQ1NkJgZHOvoc->h%7Y>GuP;J=1M&`U#+?%yM6ZR<_h9kW6!Fqh>?HMWlw&)l_&= zkFH|<)~eNZf)*yYj0v!e%|~R+b=3_wTt6k|$-4oWCb`w!c1kXZ4OiPKFG0#FG1r+$ zG8R{xfJr&NO1yUZiHcu=vU1i=iRCig%{jOS_1@)JN{_VbP%MzEE^6S?%kq2L zKnkI_j~wHAn9&uYrZwmXz1s9T3=rq7V{4`BCa=}2-w_~e+D9vPsTEOtiN}(QTCl@C z>)1#~$AI6e(U3YHnv^)IZX$mUtsBLk1L`j1PoFyOQxopGQv7r#s*_UP4MW5aEtb`2 zbFgIoGeTF}5bcjX=fO|fqEu0-7o`&qFp9iVw*r33onS2AD^CbB78wgo;yY!3a+PRGrT6kmc% zGL}}Lc>M-Wfi(?HKmnAk1&J4;dfW$0N9Q~96;GFNNC=`k-HEUN2Uy&*?Snz!%1z_u zjT{VBhNwpNyBbCxyI7q9pE`lgNIGZ1>0+6e3Uv7vM@r8E(X3m%68N6YbroR@Y_5x{ z9N0;4=psv%e7uH@HMxFpUff`SE!c*iV9Bdb3GU7VPf#9R(S}B+GX#r)ykrPo>raN@ z>u&eV(1#&^qBUZ)zpw5?pmk^fl|_i+P`5Wir=TeDyow6f)&6@_CI+90=#B$_TI6

3B;n>~nEaFY#(g%F=D8dgVo(=PKHR?r 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

{laSk&^OMB& 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 diff --git a/build/bootstrap/zipobj.com b/build/bootstrap/zipobj.com index d148bd22d1517623e7cfa3d7edc7af20f74ce807..bbe95476f5d8cbafc89ef5bafc8fb7868a787084 100755 GIT binary patch delta 48905 zcmcG%3s_WD_Xm8=z##X73W|yfiVETdR8&-y12cNY21OBXX<8(icCnmMD`Bt!<#-&m zww9Hay>D;XTfJFU;td8-2DKEWi*`k`JmXlR72qZ3`>ive*8lxK-~aiZ=i{k4d#}Cr z-fOSD_S$=|z4o^3X1lVjfg8u@xRB?@E(umSRpKUFuV0LPuKc;)E8R3g6Il6TyvMK79RRDkqu2X5@-?=_wNmioD}a>+ zN3^dC_5tgHGqgY*dpmeJ{}hW0c}TzT9iAJ*p5t@1(2f_+Ugf(z9~zXp6Xj76ZC_sr z+V6ahTQcau`z`lVjOe2_5U!Jr4Sl6O#qR!dvWubP_?@hO*tqs>t!!(RlRX_aF0u{U z)@GCt3X-}pH7qVTJX0&IF&=va9B zm;ey6XGaxFZXcry*0D+LqbJ^iGzlR!`fb5FF3|G|)l(S=k}BrECvr9V_4n#Hf0uq8 zJ_(Ozaze^G&%d*XpDF7z0g?41@$1re!mslYwzK{H1I}N{;G}oTZ|Oz)^lYM-I8Dqm zI|g1F!EqoqcF!9xh@3a7>OU;KLzja8@SIfYGzo^o(mS5-CHtXRajrP0e0L}nV3r%` zN2Q+@>7Bh-o)Ni^g%szzWmWG=e4X^pts~a!w?4D}BH3$n<<>{gx}ErG(m!>B=OQG* zSVcKgC(dU3I}EiYE#|rV7G=zq6n!sLt9}YO^F_N+^Z=r2pLY0(#m{?-VrT8`Xrscs z*HM`I9bp5;iV5bA3S!kGfbFpj$>0|8v#Dv`sB7<`J!phUF@pZw=}J43eH>@i?Tkoa zk98bvj(lI_Ji``o6#0^ha|SBALpPv#oD42{;r0AgThX=lW%5HQO>PLc;SK#Kl}n5X+58vJ{qE4hj?lvKG9KkC#)Y`kkYFA@tO>5#W}_A^E0B{=+1HX_8N!h?3%fbvw zOpPHe=6DexwNlzaOBcxz`laNEtT8LWW`#G)L1tMe$p<~}YeeKqj(NAHN+&&%w_5TZ zljN^e=Jk3dme#pP?rHb+6>HfzdI#*N3osq7(hz^waHH9({nXRHa}9SB?f$oyntP z9M)rIxmhiPWJ``hG^Iu@TF7&i{)90c7-sphItbrNi6HT}^ITA;-IZq|>CxOO|I@=eKc;B>Rs zn=8rn(yB|zkV3U|I?q*PAXjUe8rzu(ty<{3hKf9b$?G)PTLP_T#PVDK%yMZts#GnYtm49E2-gfi z_s+pjiBl2`$MOG{;xx0Op;bHrc#4zsy@M#NB!O2WLy4USW@BsQ9^?Vg~ED`TbIExkYJ0}Ac? z8c-%@d1f!IuqqC>6=F;|uWszaVtS0R9S00$PThMHfra#AR*H838wH;XqB5ZR?KcCh zTmROGlyB5deg0?DbbyWS?%&9Bg`=S-{1A}x>oJU!VRaG&aX>z#gxG=6rhXCMA0_;) z-Bs~C=Q;4V+SGUA8Q(K1ig;*DX)>n#q7_07SryNcdZwrRDT7VrNY2qxAQ;{nB!4p| zUOgE2Kk4ik&tB@;r%#d}XfY_M+$0@m39eiY!qkM{III)eBZZf5H0ej)WIy)oWt$y_ z?vPy&uYgb8(2krsVj}5Cp;U`RwnnZ}%KIn*!&oRePYrbxIyqqMtRyzZ<`lV=erOct z2lXV120iu`uVs-z=`#=0w`f1_Z!A48DN#?L7AqH`xBPL>uI0vwTth zUL675?ATWfOm*TF6l6b?&^lF!^L(mN?Isa}z}7Mds_MKB#pIySCkSC6{|l=S_1^?t zi)Hv+_iG3$`qwV;T$LI)RR25zV}=PO3qcRf47n2978h(Ah(aZ~wDuOp8L=1>2MSB= zhK5$YsSSvb)Io@-TQNrE(o4VtkAxBdcze5p+=};sCA-u;V87azM(1Y$RD>W2L;6qP z%T*Bmd06mDuF}(p*AdZ9YNTAs`u2*jeFH${4+LEX(JFD4zlbo@hK3C!%H-*U+zkk9 zqBK`&U0bm98_NjEe#2|^mz24Id#)kbB%j{v#W%%Sk>DdE5R;60a-2qj6FL8ZR8NPR zQi5|sQ5*q*%BjE1Xu|nD%#3T71#p;JrX%Pgf|m)tt^$*PMSK57BUN^40U_om@^K$G9M z5#FmU=SxpnI%l@JqtXpPH~ogBa~u+!KED8J0JTm$?~JkJYg#bv`l<$4HqjpmhkFyB<@`ZD$#EFduY&6qp+yb&t$6;#@jk-jf)y< z&|wlf0xSu*X#;bqa03*`6R}au}MY*lnO%6+Z z;NEDIp?-;EvB?l0qq7EKJ#4ZciuTl*=H&xHRHns;w&qB@Dpma)A?2Tvs?J47s}9n( zKz#*yJ;&Ne;)#;sa%``;UX&>7Ujx7!C2wMW119U{Z(`F1BzM2XP!cVqN_WFQi-RjG%en21HM8>WUNCZLg1E=T?Ft&W)Ox;q(P7aLMIT&jm zC?Y9sPbp6xW^+5}D{~XI69K1;vHg?zb!Ef@q zXGgJrq&$;L9iMBex)hP4zHku)=buK`=ftDyGo;1U(aOd$AQ;jv+JX#eJJumw7;Z>A zXX|Z9+fK2SU5Pi6QnnEhNP{=Ze?40=q?7G~VHup8>xvRfz19GgUGaK-`y*}7`iD5p zB;U;47mI;fJZ`XcktBaF%3rE$#?s_v?FL5lj^cksqee${#m6!jfkX<7ksM30IlG|F z@u3Eo9r^t|{Q>Pr(DAL%Q2-C}L;~D{z{x(aKcJ~*`CJ7}9kkIIDpHpoOmRx9u3rGm z+D#qB#toHqPp@M~hbHSrI@ryjUAo^N2$6DHo{*G0%!StN*^d2CiL_Vpssq`OVJV}U z6|DnuKzwg?&Sb2UqSZWnMEh}XcIhvcII3+;CoH2n6Ns3m3EqWuY}>Hux{L?eAH(|g zd*~h_=axa%rqPsB2HEAUtI==94w?4|qNBVRG^*`cW~wOk8;CvpGHJ0hTJqEP8pxhc z?G@C7A&Z4n^8j`rH7h*&R}8kNrTnj@-rf6pSorW*-Jek`d3X=qcTp^7cuygBtwwY# zhz?V8vRTpaae;?TJjC?}nH?TJz#K;i%Ez@(6QG||mb#-Ox>Wht36RNA7@=-Kd}99A z19bpEOKpIDHOb#fi@%AMl$Fte>Ngs`et8m09}#B@G(sv8qS}lfx%P3qB;T+m_=IS3 zpf~CP*+&ypTn8WY9zee>^Fbx$nLzas6lovrFUp6kP&Us*sP_UO#vMv=VzF!0t3hTU zI~Fuz`PsTBhs?o_Sn7>?Dp;L)$?J7v?FLczN~6>FVR$Z$lNSE~di9_5XSYUlv0d>1 zWiL=f`%SO4lj?4vrS&1qLRL|hHUNan(-#L4DW5Y-wZLPi;>`AD~qsL{)vf13R7; ztNVO4YfS4Jsz;)7z)TZ#I_oqlsr&1zeO*J7E7qsjUF>b3W}>{ljWyb5SzX%Ns@DO)MtDEG(2l20Q1#FEM)XF-o)mQPO*)a?(V}@e*8q{u0K+m#A%Wv z?=&e8NJuoT3_*@poepag*fR?InNylY=z^LBkX#L*04;zWYOIDLY{vG}dfJC~LG1w` zEgv8{hbCx^iPmdd7k2NMR6dD4Hzq3N*%8<`IWZIEPhcO6Ng116+9Z_x3(cjidba}6 z>G$%s>Yp$^VI-=? zetVKK?3{Zl=47oXqKCxd?hTYlzG0-zAdKWbyPu{*KhMp%$G-9l(BXKJx9GFwtDegf z9sYlGMi*e7w>LCOiH9V|%6LJtUuZO^)mu84lxg3Akne3!*XqSUs46!#BHS#03Du~c z1_Z@GBC(_q_tQ)!9w2$lPCF@-kPUL85_2M@N%+KnsN|T=%T?I(%3A(Vk9%ShxK*nx~8IopCrGN9yQvS`zO$o+4SN7}_3)nN09Z$&t^ z$S~BD(-H)`!L?cz%V)G4A&_IU6Q2sK9yxU^8z-jojjT}YrTgY<_PQ7uw*N;O7KEvO z@FP1YCbmz-zC@JKjkR8p7J8qun_`?zTy>;47IRPUJ~zI{sOvA56Kl<-1Aj-Z&po!|G=aY8AriYjPg$Ly%d`^-VWQ}Sx5 zv%n^e@n$8xp^(5614Zvwv=*|r=&WQRdI^R26u%UUBvzOeXp2SRMFc1Pg)FoNmL)88 zr^aH*8{t`|gf0ILyjgrBx?&P)hEW0~nUSOUq#^FCnQxJghD2F_B4;}#Y+Y493^nM0 zT7}}{10^rkO$JQS!M_lFwO+R!gkmL)EERb+Uy)|N^y@uzT+mUq20S*&6Czsm>3Kk1 zoIi3H>{@$hkvj^J_q}auUZE(LJ8JN@&u~W;($TNDfxx{gGzuQl}fnZ zpB9%1~ zckyUeB<&s#wf_aJ7=I@_8EnHhB>4o27^!{(D*tQI`78cfv|hE3LQymMS?numd|(IS zEEFs=P8?-|sMO=&#*Gb>W>`Y}7{!O)iC0q`;?$PDkK!Hg#CK8LkDZ56^=#WB6LZJtuz^|EFn9mVERb(Ai9}mrGsYqh__B6+s8>v#M|zhckhwv zPxHj`nJ^UYEyWMbi`w~t+?*pRVSP?u+&Tb<;qJ3lzQvmDFje8w{|o)NnX{fP)Z7FFPS#Q9{^AQ9g-xnW4@i!39^~Hx#d=r-1SqP+@f`#o^43Vq% zL)=YAKs!|((iMF)P{l<5cqv~Wh9LI#ev*y%!?D_N zXamj~l+pw%@e7}Nz1l)H#aS)!x1_Y@rNPDH{FXs|xI9;O@-TeRzUpelAe0O)XiFk> z@DNagVKoxxJK6>xyi@matI^KSVNUmfV9o$k&4Aq#sO=?tb)X*0m-(yN;K_r9x>S@0 zwc;b=XZGmim7U^2xLJNL86Q*HAIk!1QzIT@-pR4Lv)x%-PA3Byj#M%sNlI=q=FS8P zVq<58zAY6W)}56fQD+^2soEsFDx?^iX0A)183Z@Z*0q>xcQn!gU8SS82Gdd|6=fyH9kP7Px)2>!~ zO-2w$dC6{&0J=<$VFAR!Q?P@#^}wFHdf+&ABbW#(;(c9kk-DJ%CF19=m_V}SD=9~i zT|3KBA7HV$y=>z`HEyd9qeNPuU#QTST8ufYt%5^$RWL=Xpr*BpuTuHbwep*^F1}s( z9ON%hHfxM?5aX!iz9_oDpe&7+H&Zvtjs&j_g83A1ef(53xM?p}Jobz4KiI|_%2otO zjunH-q+kWeV6U7LULZ@MibG?zL0*y|OA(5Lm_>cT>trcXaS&?@Tp9iY{orVzIEd$n z5=pWYqc}*qHO|UXR_s~_$$w2o2v;V>uXXhH;r56}v@bICf*~uT5B~4Rxib1g-oO^E zb6fjT#U6Uew7I%ZOWBEO-MVVyz=^F3HV_(L071|&S3M57!mgdk=>QfSm_cVFK&}m4urMY4FHW1Pju`-A(`lw#7KZgj1%=di4?zWdhf=WZ zQ|ET2Qx_htO7?z)KwS?sJ4wutA^ z2B^gV($1bSXf~ZaFJ{Cm=yE91pVgI6aV8})-h_QuV8udcUF`(v!gCt`?r{Ea74#_F zJ+P2X9aKw)+80xtA*p@{hNMPmzg`#5sfF0ziLxO+LUyq)XGO*xKc$%+b{G}FvXw{T zW1I9%2YJrl(#0Sfzg0hFA+rbSem%fO&F&hp9o3s$hWLaGVxzqedvJEIL3GSbMo080 zrv^b~nUwunL^}Xio6#G$A&;$QAI)BGt+y1LybZ*kvDNj*ddH7$aZ!YQ8jbn1gbR8VDnuVFU#gI{q-_me2ke$UE z;MM;KOnZ6*emP5g@#s;O?mhQh(fTjy%5EqLCA~u()`kIa41hL#o<%I^Y+Fm%_|wW* z;+e16Y+z(gwIabYUeOogORb|gu_i*=Vp0r;!7lw&Lg|ebrz7BeB$J~$``Xj95#{!T zqZ-RP_oJi{UHY!AC|>;l$`v4%V*$d=W^XQdEu>eePp|0JA6ZU8bjUwfYr{jYR(-^l z77Via9{};?w8zvAre*z&{RF^NuQ{QDlB)zz^u70Cm#hB;krd}|?*K3a0I0mv6773; zV8^5k+eY368Vn|&2QaE|{v2q9flL{rCBg9kCei8;Nx!%t1FbYV+e?exE;hMDgv_z zPSO7;PX8?c+_WZ2vb9kzyji3F5piB^#zcZ9TN{>w~yv6M|?ZVHN7)?Zefh>$nWg^gM@zgeFETu%o@|JaA*+2BWuUVS8BYxUvyom-=ChYw#}qxX`_$y$92 zKGhX;R$pnskNX8Qvp8J<)W%t}@@n*Y!lO!meEW8#z0`u86w#m6VQ)d}dng|j@>v<( z9>k1z3yF&U5E9|Zr|9<~P@Pw~qLum(P(K&Bgw5Dp+-}n!Rq)NAse{Uc`OOvRYuV`l zmb19$$OA~G1p^Xepkgc?l+;%~fb3yOu>{t1EFHRH;oyl9=V0GZ!S#lN*4(-7-}dc# zYw=~BE_p56^4RP28U1+f*vUk-OFsY~&65&N67ZkU$G62D_8cscQciig0UA!oYeAMv ze}ktW`}FZXx`rj}x5r1&XTXxKfzMJGNU&o}T9Vq)+yP|STOyWqtZ)&W0sg|05BZI| za-R5w*Tt@7V!l*|-&~ZYR31+=TLSO(5;SiEE7H#kv zIRNWwUMQ_WL~`Wqr`=#u8wSL~HyiChz@`}AfIi<&SY~1KDc?!7eukD#2)CFfj<;b6`zQUMp{izpadw zPkV6;&?L$eLd8|KP?*SJ;D;u~WQ=1lDiO=@-$cdcpK>bgtD*s-@JUJME$Aqi_33C5 zmRELVMcn9i1T!x_9-Yl!Gb+zf<-#X;9I=XAV^i&u96hn0O>R|424(c125zo1#t1 zM4SoEpGDa z%66=gGLeP$Ea6B@^rK<6UT0VT0_L*TcfNY7;>2158T8^5sM4C!InoWIrNM=1MG%HhDMy3f(}Cf zFQp?dC#-oHe!6>Ut5ZR!n5xKSM2)-F2Bp1E8}u#UVWX{~6KoctG6Fi@qijm*r8i*? zmoH<9GxsBKNIr}`AAI9bhwR#`zE0VHR)74M2FzuXT;ubfQ~&rk`UNLj>%)PFMwSJz zInO*kw@V`l^?~guSuQ<9b+z+BwrCJ?4O9QPtl?}Vh@V{gDZ$SAU}Xf$!Xc$gJ>i2C zYmh)#des9gVP*1&Agp6V`;8&O8ZQQ<{QywY|!RpUPl69jEJ zu@tCLJ3$|z2TOyrg1TS@E0o?sP9-Z;RI)=Ik%9K>Lxc?;_O@+!fT&pgQ;x8!wt2Ir zD!KmHgM1b(d8@of$$e+^%KGRc8Q@jd-v>i%r6$FEI9kfTjv+3aZ$yi0*Xeyj-syKw zVA;CS6p?fN(`sx--FX;xB<}jf?5*OFx^|81Z1F7qT{e2vfbgtEQ0PvNW+oW1h*?(+ z9!Rse`bZ0rZs{}&GO8Jn#5t9eFxUM9P8xh0dwcrSMs{*l*L#OH^4iF+B;KgIA4dPm z`VIinoQhI#hCn1Jskbik*jyC?e#SsvY**D6AdK)Bumnr4tYkAP@N_mgULc)-!M_Kq zi1E)R=-$1&Yss_s^Sp>-hy=m;M)gK#tei(?{>(hctSR158~RG@EQ8^WlB~i@+WLQ@lP4+KxXo zme?BHbmC!8f18TKTB|4ueO=k`I9BAJ|Kf9S`w0kS5_uH8jq~DkFXF-r2j!?`$g?~Q zJoVu}@~cKzE|p~M>Lcg70*#yuz(9^r@)$@ZLFKFlY@8B*!C7gAZ=r>`7pSXT#4Xnv zC${byz_o@`ZwCWggQ^ZyxyjsxR{eAd=4Vu?(OCbxCZr|pTI(5QZI5~m0!2-RKZ*M? zh6VC`0DxvO3{eL|@qkfZyT4$Mmv&w7sD@C8)6zpYjk<`L3MO zp*>D1&C2}1CVjz+u$161`SBX;JA-Mz9joTlz}B1oyGp#k0Xc2K%NO`)+_`}LS~{SB zbU|^tase1Z=~DdWRnBbfcWnWP+X{hzs$JgFI)-{PK-{k_mX&lps#HIHlbGwms8whG zOPe?+P(LX*39QWt#Wz{;>aMn$i&QhrYwxLOUV)1n48^~KR~KKx@J%(m(x%xz-hpwZ z{}jgxn%lQfvK?$yt5Hp>*-j`~4~Rk0?*I-tD9SY{Ud@-nCsk8nkb?5pEPM}Plvd0^ zi?VIh_iIOm+ z2d1M=48^hdctTopKMyk*HXHo`tI;RnmnUp}c`^1SIJhJRigTh`uNUDcoQeQK01()F zYZ8QjMyeg2{7&@Wif!!tn#3-HkqO0XoOP)mVueEO5lSLh-?Ein(RY5T)l*#xjddrr3N{F_*(wf%JWHnVYS zhj%&i@@-!_-%Uvwt{`HL`W#!oc4*LdNX3Nr^ULh$+Bv#aKd}U513!(GD=T9&qtKZc zY8XKv*YcjE7|XDHpmnZEZl{jfHErF0biI;NiCQorEh|GK)quDzf)|u?rb;9ZrV2ozyJx+KQ zC$q>1spk}B4*XQ?7yS&1LIp|6z8nAy4v`o6sw6w43F{L(AvuQvQUd_yVZ*eYAYygp#lE%Z@$2kfpy6%EmoESa)s+VUEg&V(@A; zdt2-Cv#*H7c-}?I=C{A4;wlBo0a=`zvC8KU^T*j)7RgU$FSGIdlUn#U*2L0>{MqfV zoM>p{#3*diz==BdLP({sdl$8t{G!s>f=#`|ZJ6d{JMlzO=vPv9QR@|^G36S#Hu^TF z98dE}cA~}Z_LKJ!LYaRj=Gv5bn;}CtC$a}N4;>zcJ4s%xJnQ%FJzBBKPJH~dcDuCt z5ar~9vX2u^;giVr?8xT0xD}G3q53)p`T{OKJnqxUS~u08LjHxh{QGR)3(5R`w(*6? zPU&cZq_i?|4)sGBepou2z)vIu-LYo&3Nz|{9Z3A=AK$g~#rAyn*FT5g>(z}zi5pq- zF|z-Z9l3(i8s~CepbQRYT0{%p~3}>z2=h_k^2)mzO zy>^%7B^}@GyQ3K}0ZhmtB$It*yo57UvV2SKqr0Aa8TaZYUu8L4U+-Ts1oh)wZUklw zGZv+xKN9n^M%q^-^VW`#@%eDsFk=nHvu@jRhAQ?F@LN(k+MWFk$^)@gEq-F!A>rA3 zsCVGLl6c6+uq3;Ripe~Alx^F#M0Ycu39lOYbu91I0XpR@v%lJp4`c7V+LeEu)x4Ua z3pmRHUmKzOtbvKI4c2XKU{Ai5mn=3Ph7S>#8e-{ae<~1rZfUeuu28ZB^}$D0Z2r>V zx2qgg8Pc8zWX-Ro=+6JZ`fnc#$$WVGp@?tepkDZQh!#m1t-it1UpIE(TUUdtv6;8u z&7< zu>{xVPyVB`+5aNYh256;`RX+{R^K=W$BA`JqNd*neLn5guwmlV&#Y`~j+4SD6XdOn7=fmz8b*BX({&&Z&e`bn&3 zsC-NgLTP3o>89qS!dkxYkeh4-t;MO!&#?7xCg>K_u<|!&cMC#ES}9aQ`2{LrIZ9{} zO3T>5w{mo^9%i<;W_Qaxd>7i4pYKAeV!s3Jt3z!3j^UyAQi_j_16kRQvH5w2TJyDW znyR@8$HG>u<9cE?j+i)WtZ1(!Ez4Ou;i^PQ7?yC@(+9pxx~XIr@J#t@B9RV_CCJ}X zxA?Qs+#$}hGeQ!)ij${H#gZkD3F+m{yczowOiMhKr&v55Bu z!+$j6y_EjPePsQOL6hKV*VSg?x8= z2y+OM^j!L$dEVcyTXupucG?5ZgC*`6tkVZ^yp@goAi>78SxnhQyfWcFHGft3Bv@AJ z5QP_-WufrNDEmH=BfaRz@rvL*CYVmP{=z4r;SZmBC5+=9_9o88?~(ox8vZ(e6gWC9 z^+^2`&>ro>?6QC`ADB;=^$+?md$VuhLeI&JYSWe-!s@vgdTu?t_Q42U-U&A3!x6fe z6KwH^A9r0jrzpdmUuOUXlN^yRX6L^g8H%l4{__!R?5>gHVqVCWPZk){V&a#E%j;f@ zKpO4oaIxLmVf@;UI){Rf<41nfj=syjH?*S22YIJ^5vttv@vbD^)(gW1(lTDyJ?G5; z_{XlVA~vL*5lVjWhhU|h64sMT5GrefjHe#!=#QDCYxB-W)>3A^o~02VER zfyAslo?up%N5Dr`*-%VKLD#Y!g?xdm#murTA*(EOkfcmbz>wO_4(;w`t8Xcg*AQ-& z!w}Uduc5L%9qJnl{Kc3*;Al)KBZ*C~GO6PW9&uyt^PsOYl+e z(aCin>BUKR@$aA^@l=}aB%o$uphnx{5pA?-WVMlGb}VhJ-`pMZqQ<`Wi8zh)R^kk0 z145M7T4_r>bDOkG$Fz=Zq;(+Dz}VZQjcn^ryXq(GcG|Cn7tMvk8roccjw%Y#Fk2fb zIcC8+GY@Qt3}&YCM0U^akO$~WT73g7wyoXe9tME@da$q|8eJpoer+o8Uxrih*XROb zLJl>zz$kz9f0P%tfA{E#VPgHc0)vlm{)~^SJ{hoI3oFXEt2!bYO^^@%zf(TU76ICz zRfXNB>d)D${8~BU?nu%k?0$c`k7l3P5Y5ww=KBpKKg<8OJ|b(Y4a^Dc(I(+{y67n_ z%}_SX*F_It{8S~L5$msKI?PFp1qPoKdBX2%C1mKY%?v6ku&a3B;s4moS$jrxjJ974 z(c0MBKzmg?_Vyl$|At-NlVmFi#3Ti`e6c(NgU76F(DpBKort4yqwq-#FFG<|%0K7_ zGon8aNNA9cMHCAIs!3 zN{pj;oygHzVKW+MNQ!Y}Fx`7>*Jj%HmB&1&xR z7u`V3X;WOrvH_t6<*nO_>nxFHbC_fPH~Pjaq1!m{&&N*aTcHHj4=yvwf1C4pv2_kW z*Q3iZ=FscVUpOV2cb9I>zpYvyYGWZ(Yd0DjKGn)b@9S!V7Cm$K91!xCIpD}&<^V&Q zww4jr@PFb^OW3_yN7K|E5?&ww405d@(MgliYO;70&8JO2#_Ru7WoE||^xKSt@nw;? zi#h`o?e-1U$>7;kEh(dHSo=0ze*~(&ZKA?CjP5T)Ruu%XKM&m0jsBh8s2Hi^e`l$c zYxotr4pgT4>E3G87Tp#Wkm)MkLo76`xo@3S8O@M@C5M8v1iT1-ovZC?E5+ z$RxLzHquot5i^0PcbuB&g*RKHe0>+H-*4vn{U)|RsWvv_oc{-xuv&fMtir&*B8st7rt&Xl!b;XLw6IC60gdC z>5G8B_r+c9c7Mwj9DaZ1H?S(093RCy!FF0B9z$GIHpTDs#VIKs+DU!>7azP9Z~{gL z16T+kMX2l4=a93!0~jTIvawiUkJKb4k*C=bnu@(n+?U9}saQm~L@<*7VyF z$Tl3EYU>FelxXPxT^!-A;h5k}s}VM2p~tgZ$1sLBU2mq5i~Bw5zhKybUn(3=)Rz&2 zvpt}s0(8)_^j!>_2E213X5YE2=-vi%(@bVQwj8_cL&y5SUVHIapV0LeGjOE{kN%XG zU1Z%p?WT)7zH8*Cyq~U91{-}MF5*1)>SPd{4QI(F{ZHfABPUYFH|eog=X92?WbyJH zF2GY`q$Hn&MNY)4TPRT(O6qy;PNc(lN0z&XTZ^Jsx!f>7uoLc8Y;j$f4URwLXM7Sj zCNL3bK4uPUBWy#Bm6<0pIG2%ZzMSe_iN!6hIQc2Y7T+D7+$nUCeK<}p8Z9`LaLj~T z=M5Y)Y$B=@y@!CxnA3!$#}i?mvnr01=%pF!6_3?!3x$u*4a;fCNK?FRL83;AFEa`2hgQVavf}`76C!lz34c`eZAg6X6S+ z34-v>z+0dWj<7-r1d8GpCh{;_u0_O6G*B0SJ}D8~uW&P>!2hFa3|ipI3M97ixe=a;kU-}o$ADn?eK`&C zSMXputt}_aa(1m5&)=x;kl#tGK)iw@KnMgm)3rCH9fmY?2dS;nfTPe@yefI;e437? zTdxd%hMp;~NkS1G@4K`@F5D_x%OrU-SuasZvC3zm5+!}b%P8OYE@asfp{|C-1&(#| z0i!>?Az6?rAO7Uht?qK=GujLd4vi!VG7DFzEEtN$~enw5NqMG^)OGge>Bw zB?Z;>u**oYvD|$emK%HFyL?e^(O!r(fPje3BDjq2(t6ATr!_>|A&MARASB?8K&uUp z7ZrYbRcJrAT)oi|eVSKGb;I6U10t)`$Ua_}M=e7Oz^gL_!k2T)6>IrGFD7lN${lM= z`DPU?cLL5VkKk_YIH~F^8jV-FtmU5hit*Du8K_DALEJ}#@^y}#L$Fv$ydu`0ca(KN zu>P`bPb`uE3c6YUqy1K#Nyz@zTYFU!`u_%^tmQbSq#CKRRXA~NmoDQD)a`W{ zxBEV2gy_lhq1YfXWt=S?NLmK^0jBR$Mjy|B*1~W`s=3@4aETa2I!m3hal0_N#S?-Q zKx7x<26-EuqN4A%Ex}hk1PVYBY@-nxKzOb6A;77n1_h`#92Y=#Egg#w5S-H{H^E@s z0{2FH;r4Lh1*ajlL9P-?%w%A|i)+}ew;1H>l_b;l2BGS@zbNdz5JEDl-C3RimtA^s33o&+0T3O|Yjd5vj%9VA$BhCCcOp*%nwmJcuNof0bU%0*Pd*_Yqf!% z3p9G1#u9o&(YO=s-Dy8S;>KA<-;1J*s5T<(%zhe_gKL*1pxw9-Z!g@z3G4B2C1{_e zuSTk3-61+AqbEV3ai=E?@2}wf0FNF&DNPs*B(YT1ER2eoVK41x1HbAC9SgdetOIFm zSWpOXvUj4MDq+nKJvJXR!X9g_SXdJRfE)L0ILCPO&=xom3MF_afbxWuVVcF=Com{f zV>8Oj-dT0I=c?;8af!lfPHJSW7~5in&1x>jVnm-y`{0-j@MEM?qAp;+s2xvBm5)AP zvOlu=rxZ9k!e)fWvZx6AS%GlBLXTd}6lO(gV^7>eT&JSHqD~9Mz@60|CO|l%1)jWa z^-#(wW63G_;a=BrV^E(YdY?jV5Cq#<%syb)oCZp*19Og|@t+E-XM_KQH&MeId{kI1 z0Rl&Was#$OHCzf-HoV&i<%d!(p#T;6J`>iw3R30MNyc(47uVC73Kfa}4_*}pIB{7W z{h->N$z@q6ea_(m8}(>~`yx(_TDcN+b}zC0JSxwo&hoKSQy(Y-6!yQUH+=Zx&D1v+6dp6S9JE4l9 z*20Ai!N9}Xuq$FM{HmP*Mp=^c*6^Q4|4PfpfX{0MRC}zQA$YL zOr-xdB~}~p%+V+sKL+_%o24)94gP^cQr{y1C`Wx38BVs+MOww$04YmL}VXK#aV+|XL_qjXx5M#n_n7~h8vfH zIAD66WquSL<%=Q+Rq9i?#vMWl_88Qu=wsT{sNbPaB&BeBYaGI3PFt|u8m=Cq1guBg z&%!jReu7vl3i^%U>OTQ;FF>N*rcJc#VF$j`H>g%Mq6TPkUjsmdk3k_CgM{^D!fqq0 zDDp0n?m@wz!}AHAW7-ZRFds~ufnS}a-)#o|q6w$QKpXaPS0S+)2a`1p_HWf*xJJD; z*IRr&4ZB5BV4gd|>FMD;SQbIACTV(()LgRV4^LoQtuz1=z(ac1rnjUmDFosTEQ8>e z8iphiVYrdlI1gL`PDrEYmM;q_e#V>Z+qYi^t?C8PFDW0>zDRUT;Bg%QMHO>$fTbNs zDVF4Dq6j;!6?cpt)p^C~uRe(KX}>is7q6Oiz_y8Bz;pABnQ(V}7HPcwMv$#L-anQU zf7=%v;Iz38laxS74%OnGd~rX@;A9+soEII2c(|`ijxnYEh@z^?ekefp+He4@e;4K9 zLK@!Or1GVz>wXe{9naXsB0Ic>9FZ-!PPqn1o*=2}f}i>!^p89fuaeCVm0TGS9J|%f zxkD*{k`j4XBSjvAFY9;qFh8IDa<;oJa2pFfw}#)tHl54m7cli)0xqQS{aD5YN%wsVTYJH%d-WPSd7*PwigRrwo-6ck zR~Fe0w(gQsRtOvJ*J-yp(c0XUZ>BhMI;UMP4DeR-PS0;}6?_!ta!8xqiARC-JxW-l zIa>}zrBIyx9A_nAg5m3 zQo|imf1pAB@raTBIiQ;5KF?APC2A=?CPkoE_Hj3$szDFG>&Lai0^xNv8PA0*!T$?! z@lC=2jxrKD9K_Zai5OphdF_lIJq^*Wl=equbF15))`t;IRdE_=cFczn=YmQXNoWX# zgIGLiM(>yX@Vw^8;k$;aJs3x~^FGhTmf%JuU0{OgBSDokA@xIExM|}qlV_!fom9Nm z=Ckk%tkAAHwKu|L4CZe%`?NZth^9+=1rV=-Z4v445Z?6|ZOfzJXeZ@2sacRFq9$3A z{m8*^v^gKs+s|qe!3%u%5g5|QUD-i)or~&kuvnl_G(Q1`2ThyIt@ifWA4gr#k|#C8 zv6*fbEYZ_S%-;l3somXZ+@hwAO&KkImar6hhlv{hAY)@LjnVbJf7jEOHsdN}(ysQu zX7cwKw)3(<_wroUba_M~o*qpE*D%jsRSzVfOn6pz_T7^B9AQ`tm6V-{c4nt~A&Z%#KO$#-ryjl%iNNcntys#9hmlkK*+qoL(eI3jQxWf`5WV znH-Db4z~VEG|Txd(za(NNfYwmLB>h3s4*F6mVqc71w57P>D@-xGya}grnDuo)&P(e zi(ZshXqDD_GLe%Cx1=Fgf|hHrq)6c03Ht>+1?2U!_LS^rZ{dAJzzBX)vLAs937Bh> zBixNdfwCenqsfK)Jq~JbT2_K}s07QXB;&zHm`5f1QDm4Ns4=s&f^xXBNb%7(kiPD> z0W>SQv8FVvqL3H$EJYjYv}*0O$c`t{}#ve=+VBk^by+yRc6(pFJNSqGcsyL(LfZ#~vVc9y>< z!IYNqUwW)Pnh5%E{Q(LEzM%4oWMb4^Ofsci1ryO>Zr|OX3+TNSVBcSms3SFbzD^fs zmXFXjKT1c3e^C7e9Dr6!rPr-NLD%JunBqNn!#M|BT7v(d1Rtm4J3iWNYt}gX6_y2o zatp*Tsk|p37$GQfc@N=$cTZo$O>(`xxo6_F#1>P%$1I<*pXD96;Z~(Q<1cEfZF&4i z%#)I9Jcc6X)KVASfOUWmf!M)FYT=Tprl9he1ylfo03kkYy1b_=DgXJ$VUY z%c)uTzX&gSj!&lAp$=QsIP}RXZv#NWnsjvXzE}h?I>PY`mSY}9i0#KlC3V_N-@FCB z%8m8v4nNC1&2`u$@>O6f7DR{DNpu#H2`Po7rd_v&2)mBUsojwc3rKkeXm~oJ>a3r9 z)PB@Yu9vV{lI-TdK;AtR>J}5@jTxA*(oPHZC$SHp0|g!fPCGoYVWIIA-nDdujx)$7 zntw0^orr6ZtD4Wm)e8G-wd%*TRzD%a44F5lov?=2pKCr9_obY=73F#YO;Ai`C?*v0 z8JdTA6>9mYl!$*a>Q>L?k+*4@=%Z;nhAut%!^4(;bSiG+IE(~c~K9>is&I#lKP7C0DBr>qF%KriG#FC1*s3v6<8KmJ>`yt!v@ z|9Ij_HVVVPZZUIYwj+Py#5Di!s7`D0L^<-O9h2Ce=6K!tJoZELAltQ`!fH*c$w$qO zNGza^L7S2uoC!Wp4V*0hKgGRye3Mo7Kc1U5ZCcts0a|EFOIxHsk)?&QL|SRu1QJNn z(gn&YT0{gDgoFZ85=g5&#EdNBb!KpekAuqS#~Iw9fIt_eAPNOsK$J}eo)DBxODRjf z@AD)@oN<1y-+!O-B6of6a_+t7o_p@O=R`#kcuWKyc@=xLXWTE9)ho_o)`8V1yzmz0 zEKO8*ZZg&3`r!(JaQ(W*R)ey&XkFyZwViijc>$WuL1@MTn(O{~bI=1c&E^x!FM3?StJNJRuBd0=E9eFY#bZR@EV zR4>+9~LtOCJ14p!2GDWYmbfqDmyF=c@=2{ zg)txr^YLF7Z-QTyaPk3P5(? z514^L+`5yu%GlTIvTvt4KBA7f4uHUnTZ|h~qxReRj}x+Vt5#4DbINryWnnMu1h{?N>N0E4+0Kg6}Au;RE3SPVupdEBa3=+@R9*Beg~Yw3A}!j+wNBV z0zjMDXU#JJ;d%&<=a#{_}_i%0GKnhqi(hHOO~*mxnT^?|H! z%314?yP6_ons1ESDuyb(o9GKS&GMTr5Y>JRUU!-cq!kqkIDcpjQe`q>(a#K$w_ku# zzG?5&PLbyJMycMj7^?PNCvZgpVtM^;HZMv>tAodgIY6uYA;x+upE2_a#-@#kGy^YW z2M}cTF98GzdQTsLef_GK>%-kSp$4L}iB4%pkn`ic5&Sk|Bb6_Y<+(~WP{s(r+h52S zA-4?Q0hP)WMGoTlDkUpp>HM^krLs`YLfEK8nlhkJ<@sX~@()WtOF*s~)j11)G=z2O z^&R@86FQDb#TeAd@Jp|U)1+#`uRKFVRjq};7Q(u*SiU`k4IX~Vgx-MW!g(xI-k)o( z0n1$zO z{}GC=?B}5>mg?AiGpNoJ=LVc?u!-W7dlNzlSBL>H-t5-3f+rx;Ql8jwT}vH~Pa@i` zb3!|)``Ih@o<`4<%v56r7`!K?w{dk%$Fq9*#FYFxfav{5_TMnFD@JW@xe?fOeWqX8L;FYoU2GX4n*yc9Be+&y$Z+^W^G3^%?Lny!&A# zLd3a>J{%;I9^ygQc@O}1L+m{Q$0=0=iop>IWC^HUd3hDWtMpF7GB&#B<3zO=C#q)Z zyf*I6D6G!O;AVUWk5SD1QFb8ZpgKT4!cp4XW;t?#+D?j!_8>ri@NQ`Lj!^A_S9tyg zcAJS=EtB_bbfD8yy#p|f&F;80NHl4WK}z|c9rDOFq{VeY3Enf*Byl{(ZobC*C3v9JR}5`F zhW2Y3S|VnC9oqRA+A-}zJHLHsX@OyAK|0(&wD(39*?xN%o2Pe=8IHr4#WQj27;Rw1 z+ksrNzjxd>>SKOy)bF)^k^!TRBU#b!j5>~F#c1Ra8z3{j54whF({MkqOrZ5201y*U zh<7Ossp~u_84U8jWu&=4kd&1sROZV}e|Ovo{eM9c4SIe@%^r_=1Q{^N$AZ!%)HN@H zrNw6=4*2s6>LFxvWyF?^5dV7wvunP={jxoJlDrE}p6V^<10q>@&zFG?z~(VF)j6>j znKMoswZ|$ulKBvol$IdxaiRQwBUx(1d_0n*L+DX{Jd&+qrF=#QHnyJ{@BWOQ0?j?y zANfGw*Hi*9H@tR;@4>i;T&H(AKh=Rf&|Ob)%kMf+-NJBbS62vYMB`04E#?R*jHgDi zo(a?g$x0Ik6^79^?i)dD_KSRK6zdhS34%$)GyfBRF^ctefY$;ZAHaXM71%38sA-@t zgKQg!EdA)sqZQ`Cfl&+5a@B`ReMEvJ{egoZacC~2`9=5)fv+o zA%u_xA*rQ z079Fv;!P?F-{SoiC|vB}pm2u<8g~%8U9fQnS$pGX>Ka9~Z@T)f39`4Sq_k(M_btq9 z`pWExpy{tPiDk%RR5N-6jl&zNgeR3efmMK^+6*MuhpMO3J8O`e6OS_f?8cVv9)&HV!LA9iN_1(VJ-sKXY%w1jMv=yQIDl400j-P&TDd}Kg~$ONu#QpQ zG4g;`reVd_(T*_+_@a(>jA=kCAb3vT_-OV_yr1m`R*k1TfL4s{Jf0)Ar}ge>Kr6=! zJxSl0v>(Vko-C8-DpwL(LzzLg98Q$j5eA}iRDf+c{a(xUJ!Lk}d>N?~iI-BG=aqII(+)2W~R`EZ0 zOGnnHL*%@G0$+*E;~AY;kN7W%8V`y%g2U||;ezg_80k8%=)?wvEsusqlpFldomdjP z%WFG<7B~({!{83>3B?0JwKuN)N@*#UFs&ikT*8|WY9*eKGxu*gfKI4cgWs|}v(}@@ z;5rA){6G_n1}jZ6#s{WBgskoq91QGrs-JP+3KmFzH5{>~88=zdkC1AIE|(}OqvjaJ z2=RPYXEro?$!)Pwi8rJ`{L;xMQTp^%Q1nOz zN$dIaSQh8_HKGU=29k;){RmT5eRIKW1oO2{z`zJCr=ID@Br~MO|7872B%o!sg=0D)pk|I<3L|mr!#R zU_~^*WZ9yJ7$2;ANYWs@1+vsZe_`z&GJBotmwASkEz4AUa3a*(vnFwJ08YS zTDHX30ye1z27t8Jm!<06#ZWNTwlqfX$w|?VSfXAQt;5?BqaR25hIrozy=Q5-et zt1FstZI@!&gLXI}=7KRc)DhK-25m-zwun`=QaKtVH=-7~U@6{uOfnz}QWTpVXyulB zX?gCdTC-qnHM3jB`dirCrq(TumJW5GO`ypuUxinkLVX&t-Qzl>X;CGGz+Ak&2L$k7 zr%l$qb4q$bUZ)^cA>s`Cw1DYI-!PoOAH{;B_SWpP9fC0yIX^h(r}Sxf8EC0RYwM(b z_!dp7L)&WU2I?)7>yY2~tWnzt!sjaHn5$}^!aiWEr!*G#PhT5EuR#RKdr@PozpL3p zfHad`rInagP};B$B|PB6br`PBa40RS19bLD)mR{u2wA8)*yFK(;QKQHMn;O5;kc*! z1{NkOqK(h1yl#O~MFQ)?mhg8HSQ@*`zer%C zle=J-Ho`KMUc7D`F)ejL0ohSAGao69+0L^PSwYkbx9<9JqYr()(hJ;~$cA>##+s9H za#KC@HTeB;Bj4cr6Iu68e|>`zKFKtCWJw*VW){Dh$dY^ac>>B^Aq8DJ%x|psYqpzH zbqdgYfTs*gFAfR{Y#2PZ8%vMbfH}K4%+?=0Qh6PGUN_b?sVj1r+<727>b!k5cx-2> z0FeJxq#Gxh`QN&+qCTW26XtCa<%d`FU`Q>!3pfCugwvg&+80TnIrt0jmc$0I@Aw!v z%7u^eB}pJ5aazYx{gQMWiN8qbuOEVskcrop?GvgqkqB;aq(M7VExgnNA;KMIc8xg9 zkUGbMPto$R@Di3gB+-!EO222*Dq*5r=E7VV_N-)1F!oOIuE}v8ZK6!<^4UBIa+~UQA|uo|4YeO5QCe z)O0~Q5iYBv8wE_W`wy?^6g#M+X7&T29Wj_^TOdyl#O?kF-IVi4a{{UDl!tc>Uzg4v zC{F{OLgan8^Z_)j`W}N|n9-95afwzGjDx0!V$IlmcMn8_NxUO{UFaIYH zW9z@0l;}}2FOK0cy;%Byg+Mr}4F`)Cgmo`aDL z@6{N;AJPMHSw~t_eS@h$)C%vh7=ETVR?kkH^%eGsqFr()zXiVt`x1Xk1FyL1lG`rP zUI;t5aUP_A;CUbI_Nj7v(kER&6C#%FRV^Y%OnwrMFMY3yT&A0-qepc_?v^90ut!bA zgEvHYN1<@39zVcvViULbVHxrM;h632+$-d0tM&yRPVM-^MZUEU8=B6_(3=+AY2hID ztr>@4EI#R}@c{nvyS0x&x3Yv|XZ~Yhig^-ZN9tF%*#$ zFgMzQ+noil8z(Q^t3%mj1x%pY!lc~RyVytE4z;%!u#xe^B#LTL^+SoFcI<7}yem>L z%Vn#jTTsmWFezOADp1%Ph>{Da7J#DMaj%`_r~0yFM-0BV!%&dw>9hFStw1fR9duR% zuM3CdOru*?!q_M4NZzXKu6flh_9$nLCKsAG@eZ3c<~@|HA<4)F-)SQrANZQ(lLE%* zG=K#Vr_xkt1VjO10x;w(Wqb0t1i*vE{f&ItgDlKZd4swKT0KmfLSDCO+R{MO?d>7)**TzoY;b z$*cC;`|gnlseDQMJ3vGa?Yy+#xm9b?>v~B&SXBd0PPXk|ZdK(^e0o2YCiKJPbLTGm ziIDy7pV#x%{aE*ho06%)pbZD^{tiWA@?C)p)!u3qIST1r1CoKWRJDQBMIEF}bOOtX zY!SBcOZ`|cwwrhE&qgS>{m6^@vjL6}9GLLZtXZu3P8ypeX9hX@NQ)}>M?5xjSK%Jr z-t4vqZe^qayFka2s+9d{gSN-y@`jReRZd@Dr+N}wjfjz;nhB-=VeMKmC& zkkF)C0?#-|5eWKfd+nyMFHq@>2d>;C8!e$UX^vDN~>{bF< z)aI|m!f18};xIp88Y2>w1H<4BRJ?@hpve=Z`G$#~>9Nats#f}s`ue(6xtI8#2C!}s z$KnZJN^3gt-2>QghYES2CPOuM5WrB;WY*R#=wY0*5Bp&B3`DuKVUW9ZFIJQ0V%L6u z?VqUr)9&cEe1WZ0<+XG}v$b_tKH_zhh3ym!fj;=w79}rj*5qwKo$dZLogplpD`0O{ z*oW6R{EM=U72g2aT+YHuhDF^5+PW_y&;)ScGq>ss1hh?6QIOmf-izCVklouTziQ1b zMk~NPhg_xD7DS9Oh$6(;L~CFoDx>KyvodzkCIeAAvpanW3NclDhl|4GMerKL^9y=` zE`$`crQ)1fcrSetVsW0Ha}=$Kn~H#5c(1R0Z@?&UKc14w5+<#^7^rD7)l}AAll(N4 z1om98VVpb{d3542@Up-dyp8(tLR^Q7#@1yEqoqaH2-VklHv&<*{1LXF%oTp~h}?q9 zd~GHh;z&fYZwn|aSMJ6U0GAE3?hdQ`V@qSGP(z0#SrPjg0+Od{L<}f2=VYpM+92O*OLNF@$eeOJg1>a5ijw zv+po`(!ZrKH5krDuzO3RCJ=n$Ap|3(aJ11I$rog?CCZ;%9D~@Ot>wvs*ojV6S{mXE zk{s_krXqA#-V7c&m?gqCH}5r=Wk2{QXd`aKHyV)U$+K>uDB=5{lJyvkE-s~gN#E5iZ-UNn^T z67=p+nB#<547t1oJXgzl2y2XxF>=bV`bMfY@@KRxEle&pou3=ZazacMbv$(#i&e=* z@xjB`d7e0&UF?JeGjYkkhDcJdniwrh{kLjflBgeM%ImiTykOC;uMK!X;jEXHwQwO0-;wC!iT33fy-j3}|p88kTI?G@OagqmM4t^P}) zzMW73u?F=)H;M2J3AN+2^WJGVfH0|QrD(C4((wu$Vancs{Q|H5o~lROY&mZ0noj~* zo(g8!i=dEEGmlCT*FQtC?ls2{DXw=00^iAjY6NyT(SK=SE^tl(g8!wZ-bF~8DJ%@E zE^Uw<3At_EIG9iW7PLaFUC@E#0(vcUrJ!y~cIHvMTlH!hA6~#R zJGD?n6>%r}$h*pjxV^{tk^=Uy`D-l^=BK_^D5l#oh++cd_c(E6G(sF6CdSWSk!GHe zsV2}gizptF@Zq?$A-`E%peCVs5ym1XA)ndXBl0;{T^S*TPSex9TNTj zxn$=wkssCrmFKVIKkC^79X($KXv@1mNT4m!6gXZBm*#;{eI&FNvfer8W4xYOZWtD{26i~(Q z`RE-;e^C01y?D|n_M~#{MgGDlmOQKPmsn5olQle|T=XzH4bGkd@=#z8fx37O0oQP5 zPlrl)GVe_%j;#H%^$&0srN=^Ko%k`*(<9KGWa;%2*oV6qJW-(rkB%%zv|_F;jFj3= z@Tk$O&!dxu5)BAu$0@qJU`HeqB7$SkeuR_h;v2i&@(})uEF6`HN5@Ii``|DGCZ4o` z>d@$Rt+<$nZT&~E$lgW_2v?t3QuFnrnN~S3fj5t4v!cfjLFug7x4%&u_boRVS+(-O zaelzaraH!>VFaKUP>RH_*z(0)*rmBd#3op!jWY)bDb=)46swK3Jt5xapE*6rpKd&i z0&7QX33)#RKmPRLa#)oaH^0XaXE%R(A2}TMX!434eN&VD>G5(nqA2P}@~1^n{&ck* zW>=FOgHm)lWM~BjG}eYpS3IT&n~ujbk{nK5tz4_jSgrJ@ACtpr8&$8XCT&#t)Az~Y z=(Oau-L+@XpjtU>tW!0prqm&QvmCapj#75tzZw<3Du;XLv3wSr$NcFl<#3|L5ejV( z<2w4&7s(MFR)?+)HLVWyr_YkZicG~IMMx$ZR4#`*JHuCmFLH(h0&-a0F}XOU;D6A7 z;c_^>F66z~zGvb90XZCfTB%GNkcV)*9F9?hza88@t6ubfNhC=025<-Ks^T!O+m`hBz{iBW4T*pNaN{aK`Wf( zg=1N~qe(!auw(0M2J3YtlxE=3I}VbopyVWULm(DSQ{5H#2P-=gsN12b{1u2wnOIl)kU<%Y29MtJdvE zrEHBl=K-g07h)W^wmG2oeIV?<>iQ|ubvL3ijdYstR(g!h&YKaHF@`x;Bhem%#~jw| zy8uA|pUHW%ul-@2JF2Ja=0NCi`wS;u`Nm%-M)mZ`+QA@jJ_d|$T)OMsk+_9g9EVzz zx*NxJJNi@oVJL@gFi$ug!w1;s3cHQa|9Bvkwh{;-c{5$8IU(!Bugw@a=LEIFGbNJCdAjlN`1(XWJ~>WM`Y%z5v%M zy4_$ODBfqjXPj+M!9rWx9NQFUo6R=R*|x;i*H@&WFtsW)Gc<*eqKIIRax1t+S90QR;SMR|Ozq0~HeDo5zeW>WEY8O8%UM z_35`5gglO^oA;z6r*|$wIirN?Pp}8%j25a-gMi902-VAgj=ffX$ifoYEBvB`4UYCl zA!)8{V$M9F<~r|dWxcXLN0e?$Xzfm*sywHEk*%k9J4Lw;CC?kq(tK zTSAbNS6f+H#-a&g=qS^&YW_2hYFES3oz((uLEAH#f&Ttw=x zImo0GHkC`tzyA2xxr#3U|cM>OJo%5sytP6}7QCY_N+%Abe|JKjzY>3%#VW z$Q1FZZ!qn>YGgu^?>eq~#Ur}_%7w<8sl$uZ{SV>XDK3LQf{!}Lz>Z>tJKvW=Gl<-nA zJm{!F{E@ncuQljey@Qnhm?FM#-3oQgkooQpmTmGxt*4gAjGCioYoM*_3@Y=C@q4m6 zMO;m**GG7T>Vt@4&D2^Hi9VuiD%d3K_}37@wFRlh!&DpWRt2Hp{j=O;l|35J5X9#Z z@;mB$yHMk9G)_@}R*5=}o(I5dytetC#eO~HXCeKoueofi*hx)-)?M5dr$Rc=l=eNE z4P}!*fl43c+Xk4TR9nX;!=^AQ>vX6s({I@1gKjJdafp(KRUT3dSS&IiIX#2M$#)q! zfDqc%^pGe@3a*p4)7DhqmI8H|Sy%Y#a<%}PGd3~TQ9lX3bb(*NJ56Lc1EQ||=Nf1w zn&N<6`t91VYrUuV(up{_?k17?`<5(>n!LleOk`cVt)rBRs@0SlobpaY$<>{i$hxIZ z4Sst6sxbv}sAQ|HP@S=fr%hr5Sp*+9iFI|jr*6tP0CvG2$m$ZxeHGyHAE=j-fID-- z?yG3u6_~=7Ax*=1J{4dxrTs!vxSnzWGQVAmuOh$h#z~)M4{fBu*18Z`OCu^a&Z&#k zYp>)j!*lE_RKOo^-102SBzcMotWX(`jYn?3Wh1QK!DE=y66wPe_V%9FbU~zdFn@3| z8|c8wU0LM!oy8H+m~o}iwEc_E1Aj)b4Y(K^35f{YIAg-Y99Z&k)j_otRC{`I)*6}L zlmYF6-?*AG^H(kngG?Is%7gh(*pG`CV#Fpve{vULYfcyx&vk)N1X~#ec|-}qw+-{p z$xo?`{P<+{qw-P|-#3LdPM)N5onydX8HVa}ww?y?wnH~ZK?BGEUsv7oJ1?R4m4kp% zbpB8GR>$R`iBf!;#cMgYSLuNNwJ0{Pv?PO|u{#(7;s?gkF4V>7Q!e|1p;2Fo`WhSX;zTO3bpl zJTNh;YTX7+-l{6FHZ1#A8umgHA3Z9u_iCvJA(YB-@s^ICy@tIClVAXg^UNvdekWxH zzVqqu(_+{cY8#$2(w?!$j1Gc(R_kvDA=Z5T;O z1(BVVh9;j*{sf}PfefRN!H@;Kc`rliUWcJcj>Gp!NcIVP5kaLO;@o381xiSTfjkfc z^y--!WQW!jJefZ)Ed*QL*U?$^sr)Kkjv9w3bH!;NjuNC&L@J5FcVvwA1WenV@Re>y z?-W!BPB=CVg&YWes<5l%6cQ1PB;70YvHvhmN7`=}?8|7heS&5vA<_*Y8RDh2NW}f2 zt-S%qKSMQy_&q2~zp4t43@+(hH<(3x$<`4nWXlw=0!fBCk;xWK7Bi+}xp^PO4;6;1 z8pD?0NZ3F3+EE&T-d0GB5^8YKfwv614KRNCI1?L|pY+qB7 z#E($(2mD%~GeNvJA*vXBoM9}h+8&v?5b zAV=3shR++tiyvph9Ie6&htW4vMicChY3psBbgOL9tp02m>2r8v#tz&yrsA7%c@&`hE9V(3!(Or!q(qRX3SOC!?H$l+>opOkRt!;XmPoBy8DIY$^#hEN=Mwc)W zA=@i`^ut~Mv`2`dptJm%P-G2#0SlAvsb{)&;kwZe1G)MJU(C#=8abq>r8GQt+l31| zzd^i7EcQ~+Gu!*oiXMU=T<(eCJjuF-YzkpK@kzEK;)f4_##IRjzVRe`u*>GzSe~N26<0747Sk2wL+x#r{YOl|O`xPk;DrDr zW<=;sZOv*i-MHrKh@xO|@&;n?Ik$c%cE@WxTo(X%b}c^1L&tywU9!*|YRiJ|As377ft*{pl$ZBxQ8{MKxiJRsE~ z&Qkke4;QNTAw?CuV6Hgg?TF^WtW z^Q>U&9Mt~7pP7rphQ8xlAI@b;Wxl|-KFfM42SxGk;IbCZ=CiKsXPz)0JakhuH_T^0 zv+Mk!1-M~>+PFI14x*g`x+U+8BG@xoCybEx!HZ5|Ye?=MWD)-GB7V06y(@C5gN}Hy z-XNa5aah>8A7cSc_+=^pFBx)k+eH~`zi{{Y@ zck8_xViu7FK(lsl)G4yua$8YW%jabx+=3 z`Rg_|IMKZJHV(IEg!+r2#*Bl;qY{uSPOmyq!!O&|R}P%sgK#wg3S|~(x{-OL^uP{x zWOVIha@|%!3|!b6rWenc$mr`QY9n+pqowDdmD%LFBwKYiyk$m!1n3V#b~Gf1*_Px$ zk?lr63uJ!{iL&E+%HulM>N*pSw!m!D?G(A_F83FG))>+3JBNt{jnybU6@`MOkP~9m zp0cITja77@S~U{XzA)XYFtke6D1`^s;w^6>sxraS9|-8(M>h~F*7B;f{B^KivDv1g zJrKQo75>^(#-}f2d90TI&q7SYEqwbzmZq%Rz`t9Fb7n&&9u~BAwsnH?cEp8NLUeH! z?^Vfk%AL3Qla*|3eyuSCXdI8^U+51!2*wX~x~k2nZ#C@LOgDKxqBclR(NPWZc(6?* z8eS!$1PbC+a?&`SyNLCR!6%1kH})7lm)^a_D;KfMXeU}O8a~JEsYQF5zf;K)_!o;< zbgTmLH;(AjKJ$b|(&g%T$mH^$P)ed26U%M?Twal13R|Dwh@7Mze?p&4QXsjyC;>k`TCJ7WG-}2kNzF3mL3CM=V$uq(BgD(W<#)`>i@k#)@O>G3F zti4t_j$U_VK;_5HxP^x0IbEqZdkzdzc8xW9%#nD~a<#JmOt-CT=uEAxYnVL^#@M<> zk{?RR=CllOo4ZD74^~Eon7cx*_ptB^k6Z$*5|ht|E@5+(o>czU685?BPztv{$6o0> zAq5vf!h&P!nZiT*1Dct_+~iU@>T*5&`(_F!pt0~Fy{dZ(AF`Cau6gb!nm8((>_k`n z#4jvm4{M&rT>F)CE2Qv&RhT9T+s0Kf2V>p%;bm;Ga!|@Pvx5~g$Gd+7D;`g4F&Evr z>@T!uoS%Jaw*RG3>X*W@j?C8RCb?BUH(hz2gZ)s54y1P}OZlEO+0=cmYq;ob&0I6o7LP6#0>O30? zN*gN_DCm$sE+ZFTgT*vkFh}Tr=k0(&T}TC4xGj@@UAb zr1A)W)uT{ssg7i~N_>@nx}5dbP6X0aK%C5#>)$}WFd#!g)d)GEkw^)(#nIJ=bg}8K zf2ycD4iN*A!fBNDZ{!cIVC7ME#LV`WL;i;UaobBPm^RGuz=k{&gm3XrjsMrzwue<< zKdA2uhbdC=@7MHDq-zwJe+cAP!%yk=hn))Nec@Du6s$d+LQ1Bn2>mre$q=Dw52H=; z-$u8t-K*#fAJJy?N5&N7zZZW^?~VxKMA9GGS)f1Xi`(87SqmF;E10oE@I#`>=&wsK zoECHk1YK>=wFKSv{1?`5yXa;s!q&aa68ZCM+54GtG5GmdJjUNYvLR>iTbsXnpv9!k zed}la9pQ~ZukjZTsdr3HFPQtkGx~(>i(Iz`s7tqw4G0NQD)_v0Y;)*LP$S#Azsv-t zF0+oc7EZ7#c>ndRkHcUsESXrMFccYzEeZq-)>4I`q`1JSFqo{R#fU056)Fsa@=c@V z>(YtTPHUlDRH35?ZI`_mhq9ug!eZ(R$|$`rOvRR=L4`#D zAG}4Q?n~GGCV*;9Rx}7>0WZG524W(R8cOvv?&K-67GtC^#tsCE4J8KDT2N@U>hjS5 z0|u1>!FX$7ei;GPR6>z*Cj*`mV_C37fYPF~PAoQ1K7y3Kuq;?2;?Ne9Xe=xV<|bcz z0~`jO8BNgx=q4-RFdCJj3_y>Dzt~{Gn8@=@9*P2;wZLGe($En@F^#6&o?^5YL!!&4 zkF1606Mc(92$}`PVj5)gAZy7)D<+J2u#u*wd2lf%qr+gf%E@I`T`2*?T3AqGqTF&O zO!PqYn4smO%FG1DLY);;04c@e0!yJJFw;xq)l#U3v1H0sLTjh6Xl!79$@5XC$Gk5o zw$KtQD70W!SsYj0F!9R@%m!Uxz%buYa&RJ;O5~sn+zAF+-L!V~rZQ@f?6%L*u?CC_ehlSB zreXp+{Kbaxg=6pe#~2Fa`BFS;tcjpwoKRF~Dk-$`()G-^&MI_ZtG8`j&t?g|HowE# z@tEQtufSi&6vyt1JH3G^GVA!6YpjbyNXb)7e=CsxnV{@IV$)I~F z=!R_$loK0tdj#F=pgSt)mImEfo0&r{b4f7b<)Hg!(ET{*9t^r?gKlfk?ezCRh5dqV ze$Xusx(kEuD?xWt(5(x)&3|_U3OFB(XbZYgZwKPL2i*ZdS08kz1l{>T*BNwQ47wYF z?uS8lZ_xcN=w1rCVY=Y3BnI7nL3dQpof350L9dC+lf6kncik)7ly9+)tZd)|=@An( zWsyU2hj!?lX6P8xEl*cGzGr9`)$q87<5T*K9F#q{>#)vBwI!-V(KpE|Xk+sq>D50W ztbgfrHXwD%gBd+WE4n|_FF9mXPR@u#J#Net5!l_jbe<$vI9dJ;{_wS%@%9da?Hh11 zkpEapc=Tfxk9L?JF-B7r`NZ5=4@^v3f=0}H_QBExXvFNeKJh7&dd`^nc-JSl33Fn5yIA=n31N?nUBTG&)X`HX_sB2n{?xSO5ZlAgJe@e9lR}?u88TekZdHyBvVllzY&+A3{)s`d1bnJAN7>Cn_E( zQ%t%CK;H3fmOkq@z`GFM-nuE8^53*>V(IU;Zc_UYPVF@rt(!0nt$XCZ4Pjg?NoUX> z(bw&NeE-|52ggKAaO|;uVExD%rog0hvQMpFSod0e>TTAvudLhHg^*LM*?QQjP<&{8 z**f8S^**axdC=Od46U^uvNl*hu{K%{D4VQXB9!$^5reBTYj2jg-x{)pDYja7Sx>5u zsdwS)sNL456+5lltv$Z6DsB$=%=)o4VQc8uR>kMm4hO6+voEb3(XueixCi;pcUbmQ zPW*xO#Bg>C!W&a8Foe@I6MqAwNmG6oNR!)vG>hi>%+eG69bC(rXoQ2%tr zqYA}i758AY;(sCB$hN-AT9yC#6T^T#|1XgzJt`&U@3_t)QSYC>4P^fQ`hUs1 z{4g?~{#njkbtaHGo zyU^$7K<4^3mV95nhI>t0F0uHSo{H_kMYm~rRcqjje@INtFW>r2@xS)y$ZfeT`TjuW Z=sUkHz6)_!sK_Y%+lLGIzH}|1_?K3#}QnBomzsIZmha zZc5+v-oCi4wpuNrBom2Dyi`MOiE1^dI%BkyHVMi+-*qNId+-1A{Ct?R_u6}}z4lsb zuf6x$>m0>z1Q-9=YF&n|srAbv7PYSDREZmJy>T)2<&u}XFG*BY-)!|KUs*w-dfInw zo%hdOfm|sU__4!f37zoZ#?m*~ll<@eVD_-?pFybuW)4V6VUYm?S$se+8x>$;F9q27 z0jzD{x_~rpEBh!gXTVQ^9R5UboGTK~c3hyI;}&plex4;Hxa{?}g>J677pEt1oO&)) z9r3679ZS;BYqL7h8(g*_(Hl^y4M5$yj8`P>FAI2VO)g!jpE^-Uv7jW~}QG%PV<$2HC?Qgew zR%hGB6NMbt@&v8)hoC`}Xn}7NDaUa&&Gnn>ak+oZPdIORRBPvIhI3bZzJ+L4-;&p` z;Kz@Et!o_-S>4(XtZtp9C92tHt(WpPmK-`yAN(HAWw4j|iCSvQ#xpuyr?&kpk1exM z)y=?4h&Hp1Ve#Qa3(-rEZESSd>yebZ_s=$VHEblmnGFmd8QC(TmJw`YFNBYbYJs+l z4;aGGeJ6G$yld;*qK2%A=UJyVeIr&>wx2Qj@%f&X=k}>>w(vuR_#&;=WJx|RPBEtV z#0O3CZE>>6yhJV74}*FQ3fzMvT|p zZdFiq?K|Xh+LI^ZnlmK zbn73*gPWAi2`L}_{UGJ_JIbU@7TP(9}hq-U@oaAts1jBymBkyU+UYQ`y5@(j24J8C- zxt@Mh`e~9r+CB7nk^53eacwOw-zxDn(nq%sSa00^+WL!RuhNyg_yk7h!cT+#IWNye zNP@APTBddr*`Bt8Y|lK-a}O=Znl35&Zs=D14!Y&fcB1SdWYs~f@Y4@JA1_FlwtHee zA@f}XGSy490jn(_SRgt`P)`81%P}yETfk4Jq4}b(zlrf+5GKV4`X@f9v@+R8a#r28 zh!pm8yW!>?TSU$~cmY?cC3-LDUHZ$1fOK0ht@P?gNOV|`UYbUbhy^1{d8*uM!JyKm z{}#Ea`Z+HUPo|U&2+QVH`lLwqN4q|qXAK35wXXR${9R9ZQ0;-K`_OE)l8uN;wk0HH zgTA%g0^QoIFeUn>KY32h4cwIwmCZ@A6zk4PARXV;_ZSe#2PHXofF$c(f{rUG9IUmZ zR#Tf>6$07+yVb>b9f$6-F;O0xeV~GrNn%H$LLXi=0kT)DO-lan>i5w56xV?YMZa<} zD0b^F-ml}*9tK{w{z7w7)<>FkT!o}$rhpL75X=E>226Uutn?^AFAaKk1J4Co+lb1F z#4zjAt98d)rzgx41p>AxN0zbK~Sb^-v;j7aiyAybD9)cEdb!r7AF$UBQo9b(`ag zT-L*K-3)Oi)c2uT6_P!(1DbQz2Z5;Wf;P@*0&rSVM@euUM77eOfe>PS6SAB^%Wp=$ zI@qnhfnG5~G0B#7^QR!3asV~vit?W(`45wP+$4Xa*5B~?O0K+*Ilz6u95Fp?XE8d1 ze8DXLYL>5>lHE$ms-uLbeU~?AGPyb zp4+|1A#$E-GbFT_Ql*qyLa8q(wTx09BDJyHz(?6=)+n7%rK8U^n8#(yQLJW=e4JK{ zrcq52DV={vlB?8hKwoB{8XZx?EMHdJ;#pQqkl;IQE~vj}-EFgi+Pp|Le)d7sc{d5M z`f+oONJ2ZEs;s3dl|GK8bn0Ns06k?nG@|T=W~F~nlp9LlMI~`EOsV{*1ElTD8)xfTy^~>N|T`)KC9Xri?@>>3I$yu; z^GVJPRN}8%f~vczQE4ksk}`W6C=DL<)Q5?Pxr8MZcn0p|m|TO%=_e#}bY7SsmfFMbu?lduZzb8{WC$N1n?c4s-Db5>j3*CYCa|MuH+f^f0u9*nv5z=5?P041XK< zcwq4E{abHpI-rvCvHCk!>23vMN`o=w7Y!*5Oz6%!$7i<6EC$<}9PHuvsF?R!{WqcS zbYn_qP z57KcMS(saIMT-7-Td9d4!27Pz;VTGsj=E*9zxA{w)*v^U<%{xZH4P@(`Bfomstd0G zk-ajhSvKNqzl~HIC1MGQ-@6XO^fjekM+y^p(?y)SZ$di=R7>u&)XJAWlg{CGWqfQOQX25X?^}rIL z2x~33yEDiuy^LD2Ta^+}>1+rzA$&DdBNRoL!naUgE{C#5j0D@kh2K7oH)JMyd z(u`5-1KFu=ea4OfLeQBDOp@ZzsC7Hikh|YsFx6i`;{thE$W71+jGIuM`UG?ipy+x+ z_bA&WDs(#*X%H>B49WQ#)L3{{8>F%LIe&g#bAEI4bBpYUZ)?t%toP?#8b@SfjpR1g zHJ8;7^_Qs_3#Z!j5YAgOc^hZ1_DL%%(=fytvnr6m-fD~r$?6>gbld{pROD@1-g+m$ zQ_DYgC*R6L^(WuSkJR$UJNcnnKJ{<;9+ZDd>)=zZLiC*qWm;Z;C*KO1E9?L0-$Ia2 zD?fiH-(D;K_D+6`mfwFT|F)L@vOlXy><~JlCw6Sk{6cl_H1>O9Pn|H6#r0Sh-!UhP z^S-z16EhxfnVpjogC+Y%vuJq^-yQc?Kl};mzu$rYD`)W>R zHV!3O3hUa_6ipdP*~>wSDyfAzJ@r@&v-P~c!@G&luKVMZiLqw+XKVwEDF;koxO$eI z>pAl2TQaoLUYTX`RY~@WSdRg1cXQk*oTgmRik6gx((91wf(%~ zn5CUY94W0Y`u$=JZGxu5n12yO*U}km-F>O88!@4@xx1Eqb6@)m=M-?cBE{u6B{;B` zhTYmd2gfbR`DMv1^y=KZ4G(o~caG*tQ6g%Xo$s9ntaJrq-IBVcMh!w=PUlZlTiL5M z;;XB;1j)IGR~rYy63hop7`c2Jb~C&yc28*!vgeXUcl-iKVM9ZD>#)T*0CV%rw>+0C zmdshtP9}98KM&_}@MeGy{r1DSfL)_yPB$%GO>|8{dUwM8U_Lm|75Klu0BXwXL+G&Q ztG2d5BNtWd-HjQOyC-3vhgLlWGiF%xh{cy3tkQk@4hDg2&lf5$5d%%>3YN9eJF)aD2 zRQ_{>ly^)jKN}&f+(&zR^>sA$9{X>h+XvspsgCFhEpluDC0@O{2O_iY-HMFQ(q7RL zvg2K%@_Hbf(`#f@RgWxM7%e(q&2AcCm44D0w!K$s_Jgai7J6=xisT__R{BQav7lj^ z==*ke5$)36#Siv;Td2$|AlIv(QgL8=kaMDJpT#bq$et3m38wm%MIxlZ6SvAEl(ny z-^P%B*4EvSzL|0>IuaWsrFan;17C$N`gXoXN`iMMHdShhOIx~URg~-;oW*%+I-(1Q z&l;q@_M6X#^A3AuVB~yEy~2_GtqUaiv?w1}U(Td8%G${wU+o?pa2n`_N5|n|>5oKj zN@PgR#W-PIQ0Mxq2AQ3Cy}Z2uZAZ}DyU>2#C_uXqbXX=62E{~W(#b;Jm*SFE-nam1 zSUagAOCKcbEGt;$paF3M{q$!+AxNE`#DRQ^S-v4*o&SJE4DQ4~%lZsX8TQ+9ZJ4RLQR`w<-OezA0=)6caS>~`7{h`6LF)tMD+R?8Ve>AvN06 z%skqT?MxljCjM7UmFK0r@1*XX2b^NTLlShQF|5~+F1oj3*w`WQLeBFV(Fq_rTwQZN zTQ+25ux|_xRXq6|D;v_s+=(hEUsnGKYc5|VL!?I0UQYSa1(3;^AE5>!KQ`};y)^*9 z_B`HJhq?2;^u(!HNm&satd7y@>nF5jLx*+^8exRgo7h7`C1rWATGx)_?85^^xzZX2K!oZBK zb1ShfSVhr(*yni%Wpo_Ozy{6dvUqdyE&<~RV9a^qm)LB3MiOTUHprT%Rj*Be=4dcXVnAiX$=W+fEhK4k1^oTZ(T6(~9Mb53Ad zw32^RH(q4VrH_a#h4UM>nf7kbJ~g!+t4>eQ9a+LIrgsc`28GIAGp&z%S;Vm3y4RPm z%wZjLa|~?iup#^=wszRW?o9$=$j8xYlqAU$bJYue00uN_DgblT<4iw%5`UIWAD&{f zj)oYWk6poRzvIRLMZ6>}kBUhomeEHp#zhKBJTd$vIiY zUQPvZKJ`ijt-#h0?;N!=Al`?-wU^Npy9yjNj`c zF|x-pQbxk#)5**?9idUD>&E9C14|SlPkpOsAwTd#KIAr1!kzR)Il2! zd2+S-V)pj`WX#}g_VXB7j3ig!uslu~eAY7oJ0D;m(nyEyJ^Pr*5W&T5k{ijzeVlw9 z6H`v*nv}pFX%^x%41WCvx_)R61US6HVRl7It~5JmCJH9|xhpy8=Pgn9D^ZuVA^m9b z+4id`tzf<`U=$Xt9oVnI4My114uGflpu=C$(k1T2IJlhjdZ7r~&y82YDpDFmVMkz! zQe-!o}Fz5Z2liZji-!{sZ#o7x7`MU1_ z>pQYT`xwc$Ph4Y;^c5YjWS7?m+0Tp&srH^{Ge?e0mwfKIqCDyO+tNxOG1S^h4fqKx zOO(nlMp(~y;e$I)N1E=?7&v4+VR+6J-GR@u|BPIy>pg-Qvy%B6Y+=^G&Yy>9`V_9V zfzt{q@&qYueY)R>Zl%g-59l_0)0fx2#P5ChISD>+U?r zbAn?Wy7JPg85=HCQ)i#0iA4?7NoScwOpbgGM=Mc=9IJgI?dguPPsFY^C}ZUj6s$Z@ zn1F3!SJm9T$43BIdXV@GDBg?QZsIx$C3_QZ?BEjZ^*Yh+(s}z}BljlC&0Q}_FmL{% z+bGgg%?`)xXIpuL#S)TM%CX#)=b*}0cKP?Wdr6rW4CHXiz6PT;eHvQ$tchwVhOH^D zy(!lkVRrN#LDaNTUps>V>eXQ*+4AfpTkRz>nESQC*l*z^JRW_R^7ezCi{y3~g(L&BlIeJgz+;0& z-w9}bg1t#+O#?H!5OVt^TY{uW3HOwBMp*!rDN-=JR_J^zHn~{|lAImkU7&>Dht7eu zUa#Xy$Dwz47#fe7_#X{j&&UTuqmxi9=eSfJ^G(TdndC9SlFwyrW5CLtPX-=B^DY8{ zw}BuuJko~xrIY=5DPJXVD`#;!@v6U6>x& z&e7C|Kzd$jRTKv;rF}(OAM*rlAMFl;s(^kKMv! z(RNw&MBzyC`8YWY0#lmS4@E1qoYUN2IMYxOorkbstDB)y&_^wUQ9oSOwhowFYEN*(8?1gfj3te6>AIw{i(|U#LUk-$YM*#^J|vCp z1#GNdG4An3t3GVnHOfSL(^K$QuSsW;w9^JtcY*^j z$-W{nn6rl9+!0~&edGNZtH&lHFo#Ymuz)#AP>#c8mW_p$xhCboCOF8pNpk)=C}Ocn zLy?sGgUyPu(Cp0Fii?QJ#kqcy@Y6h=ga5m70G7dZenPi;+fh?B11usaO&`nSSi~he z&Lsg7?=}q&dbW+^Gj1~3t0K(9^EX)wu^qIALLX=ongt&>uIjw0M1?vWz0($f2tel# zV7mIdUVyHtXR+;FSsfS(7<7YOG7Wn~h&K@7dh266=lKlcp^Kju;CuqU|2NR*rYod3S6rKfiQ@oaz&-`o9q0Fe?{x0$}|2_SLq2ZCt(1JgS0j=0XE?xbJ~VsAfr`VE#ga{Mi0(*Ib3JHX58ii51r z_yk>-I5uv4j4csGDtXIroXXN3dnE!{$v!I+VP^IwA)mo_a6yK$gM4Zw|G_||-kNuH z?#lNF#0A4C8%qr{(6HE%iKH?rwp?vxzrx$=`C>-~AlMniFG;w!r$Dsm&dSFpiYiun zN!dW1mtN9DUiLeQZWoSjCfQv&tP`!&*lAu?JHAHt>h>;@y0)H>5vyc9bNjS=rY}4) zM|`_*koRdkQ;)I7aueG&4x=U)U~gsDSm)pY>PGf@Zdd+Gwl_D{_D(f%34a}$d+viV zsH_Xh-G zmzmodXo)X##q!I+0N_^NL2?tTvVw?bBsW0YC>nZW@v>IPwN)G>eX&>yMlMFtq=gnC z9AUtrM5|2wPa?O>lfAIMItK^Qu*z^*&?1WK_lV-Fwj_%E&7!zSqKLz)h7}&`MUMPi z$^o?21fq^-i4SzM^$F9su09BaDaTNV`Ha4v!g}9=KM)$8;_{1ngoeMW8UIzn|Mo`0 z(4dL>4ssLP``i{IoQrv^v9efdtvHFlhT>%*vJ{~>NosQq@}f4f6s0(ctyNjU93n6j zC-J^2E0minOL2;mX24u`R+mJ|Ck$BQq#dNK&GcV>pt*;Lt$_D z1+)5c>X9V2dg831Vc>}Ls?>PBnMEcZ_cb~EQL{Wg%+DtmPKY>~X?&98?}$%bUtygl z^$y6n%`?-aiK*{Eno8=!Uy<2@OIc+n;KRVCI$YA+KHvD%pDV!|=a*M*gK2KutEsR2 zhaH{Nqul}*$+%M6Lwt_wG&S)E3z-}r^9Eh?DqqsrC7j73z7(P~jFT_;)Fmc|1>*lu=06HGY2 z{n}N*ewo~>jU7!Sr?nn-?~=NQ^?0yn0ODELxChUV+_6WyZo|Q2xwJbA_)%}ORDK~y z3Rpf>)%5^21zrMYE)U0mq@5}54u9}I_Ux1wbboxs8m1)ZG80+s)XutvQ{Yg9x)WzKfWG$U zZtd4{Wg72I%HTwG$x#jRam%<_?yOkzLdDMr7m@ggmdQv|r)h~5iHp?n&E>^Zp52_; zOqo<puI8MLaTH zXZwsj`ACwktOI)m4_h2_J(4u!A}*6TYiqauG!kT0;KHM`&zpdKCk1fkNI4(ejz~E ztC{gYz~M7_9c_KIWHzT}hLVdK7ol{q)gCms^@%9!i$2LyP7^pf005yB*N|Os#J?(}J>CXb3})Q|OwW>$pun>lKZVQqVYt_G>sS8DGx5=wnNI?bceJ9n z;7OySyqI2D5Fu?cDTe*DTQpIX?r1X@iOmzUIqI~hJ=1_Jw`&~wvApPcitMRdAK6^R zr|*sqwmjSbj|XXD&7ojQ@F;9lcDE7$|`hUu!VvX|z? z>OPKQTjs@ee(5Ua7py&xW%4U5lenM3rfD-$swIk@nYTjMHi*rhKR)VVRK)DNTTNx{ z*uMGQbqng)h566h%omA>nT46zTEaZJ?8DU}Sax20&qZQ!(+U$^`YC|w3B48yu|ZFF z>fW}B-ti8_hXl|TS|0$|8vQK~&&{gRH{iinROx@E=NkP5JSs{lI-=|g{CHl0#0xWn z0JU+}QIo6me(60a`|j4&j3v)E(>}nJ_C>4X!_g{u1jyUI1^`;(u8&hbDK5Gb92}B(gl}wx<$q8)2H5{#{*AK z9I@&*G<56p@X&%#5rYzg{EU{o)1KRlHlE&2fEocUE(Td{{Xi|r&OO~j$34tiFC3c4 zA%@j^z@R)4hR%)Y=L>pf3#DIlm$EUIeHgB~5dNgc7N)lQmw+zqO%Y4lm9_#hbvNK2 zFZ?{XCD?oWoJGIzx;e#c{IflE_eHa%&pIg=v^bp};^N-)czW>>8o~&R)Zrd4lKs*$ zxN$bo^||_LYxb6fCnD*m8mkpvpG-+Ng3iS$xi#idS z!-?2U1g2}LHAd{ygd!8#WMo(qOuqd&@~?>03nENbKuyj9jgWQ-Z}(DUg<8z!TJN(N zo2h{ni}3V9Ma8(eZ$ukh^BdmY+T=1Cv7sz`GqFAC{com(I1$2 zRGWjGh|O7`(Yfn$oHyVE&)f#%E3EB~PT;Y#6&vJo19@DH>&&uq4lKP{-Y}mGzPxuC z9_nBauH?YeFu4%*Bt?Vbkhq8nX;fxKt8Z4`Bv5k&3~HUpzAwU*USU==v;}b{Is3|} zsv`5I9w0bJp5BCv&HO5IoVO$LcM380vZ+uj<3&5@*CE`q!5v`jX^@+CJ&G2uHeT2K z^p0cJwgg)T7669Glw-nr7lKdcKxQUi`Qxs_378F=B)$pZ$AS|_Z<@y*6($nQUXU0} zyn_hf?aH|Y=Yy@ls;ozI1UM%oF7i7OEg&VhNtDg;JgS;y^XKcK)V;Tmo70#lBq zpD5^q+nu5)8Yr%3=;GPT*R#`0yABT|nE8n#u{r!1qw+HKW-MN>K}GwnnbbLA&gG+G z@`0SZ13A38GFEz`A=adPF_;Zo*2#94KoUI(o5+WU8Pb>6YZ`J#h3=|Av(h|?>T;cS z=XM>#&vqIH>9j$4en&RP2@T68t*~ywfekjs40~t9p-6%W55O%)gM}Sh7N+an#7-_V zwk}+V64Lopmh@atUG5(&_qkZxkUuo2HB>CTJ|5;tPou<=elU(JGYE%zm z{W0Ql@}*c*#2||!Sl06kXZ?Ix({Nf}Wk)6T^&dZElLm1SWS<|hjvxWD<1oQK@xzJ< zHVPNkZuJd6q)>yv`QcL6u(0I=hPKm_Qr#RVtPVlSzLz@TEa8UXT6cou8fGst)RQIL zzL%b`B|osm%d_u$4P}^r+W<>x$jLh>rZ*OJ740_yts!b9A{?YmxRE;kEBk)=@Ypn} z>vMTeo1Gt#U4ed^5#&FQ^j8F6C5<5l~G}$k`v~P3bx-ED6IX1ISYogQ^0w}8klkb!3`8uW#6Y` z2MT6CI35R-uVW=&xiox5ZE(TMS!@1JkQ)2Ru_@0!gVmJ;X(Q%LYBGS4I28nyL zJ+_khivz=d9wpFH%x87bzqA!|42g0(Ld=_&f-RK9QlRsD<(A$DdBUpGT5VHHRig7( z7*qQymdIDTs_1i$nqL~d2Py;%)w~}0oKI7J1=-C z`a`HdGRG)f-9bT2(fo}DPOT<^Vx&s>%qFX46Vr^E(KVp5j zMHoU6Ev|TV!3B?Swz6Un;%1fwbkcze^xTZHu&T1UUIRY zR(I`r4c8%>zKQm)ed^0|{5mJ&=@rxouWP{)(_d%3i@WLeHn8!9IQXg-1PP@_Fb}=2D*u5yxm?xBo|OlM96>3Tx)ZOmPvn_8 z>p2#-W-b3Hdt=QCehBNJbm3FBrzxN4_*{0u8L#X3D+_+ZRD$4@1o{8~1pk z*xHv~G%5B!!8ZF1ov^9^oF2}uAS=A^EYb!=3B*HDX0}I-ivg1IRW4E@U*6mPJ8Bu6 zBJW&;=ma}eV2`f7A8*WVTbslOv6E{*<4c*cu0vP&H97lNwAtZ=BJIXXVcU@LRZEIO z=-8ok&X|UQ=trYOQie;i9W#MbA7@X$9NT>t*_7+}@wt2&JqoFE_mezWAKFdo1j0R%A4j$q{mFsOM>g4Sj+u#b+v285-4r}7pCkH7C zb-;}42MrFx>s>w#pY^ooV?f1;WmMR26T}+oa<=g&fYp(SJ-XRifw&iJ~)rS&BZq zz3^4Mo>*|1jePx`UT;GmyuBr5D3$`+qz|vBsXZ#qzH9(*ZHK#tIf$S!V|x_GTECGy zP*U0{_9Do@pgfXbclA;p2rh35fG1FRVGQUHlPmq2(OXk2`KVmQoNp}B4e7yrZx|8O zXneDe?yJ*m@tgPYZP@E?cI5xbcD$LT8*-X8y*X5O>j#$dR)5{$AJ`*rO~zGhsA38h z8}}oW%V&vn9Kf~1a1C#BI3Ggq8jl+SwwGXxhV z2L2<`acH}`jrHAZY^%dTllFPbaWc2x)C;ShWks8Zh5qUx`({WS;OWZ_Z0^$L55%{M zU|a%c9q9Rl{jqs$B!y6kdx;u<#jPy&oke^SD}SfGIpQL!3p*`|b5uQ&bd8P+@3dsi zI8pUEqI*p6GoVC0iS3HXZcBoOtcT}PwA+Hy1;^`{54e<7b$vLt@}E&G?Vpz;zXT?K z%_78>BXnbX+P@xy==QVE-fOqO2xQ)HQ5h3#Z!!uFQe2ZVB~7wF9}5d`4q0L60|{d9 zDOvL5N|Q1M_Yk(&9Azn<_XStF|Xt=l6PMYAu%SI}o^M z@CpkGQ(T@m*sLwzOibxS2v++=GSVck*39g`exkv)@*9V<*m-C>IQxwN!SN!@qCwb^ zT09ee^_5yrIv^BQ;~q#;i%rb-@44n>9sd{Ji|6j(wX`k)CeCvaBP_u`&Qp(HP)a6} z)7%_F(boWZ9$_gTR`*^_a152qtW)Am0jo6wON-R20EzNi&9+_)sNz_Uk4D0_KK7Am zrk#qEjsD^7B)gflW^hb%5<8;--oP&OC}~ zZ<$ROPIOZBsaILf$31k$8fN)8h0kX149HtRk+ z%!)s?2a#AkGg#!duKY?iXj_s^TW-w$h1Vn>F!M)+9g#94b8U1SusjJF^P+QtPjs4i z`&XoTdYq1<+TtgpwX*$t)Uzc$e(?2hF!Ax4PM%@i2SjvoE^{ zFRny?1zG02>T%AvwFW3aP9BR0!znKB^(dC|dD_UqujI%_=Ni)oCqCQ5+IIAs_3gu= zIc{{?`d0K@5^0cM+(-@NeZ0$KK}XGbikHT>1-5Vbyf<%)#YDrc)@Whp%=d%Rj|wlr zMZy`=PYOlf(nL!?CcN|xAf~)>v$M}?qp)*B7}-T(=bLTtG|E-VT5ZXZYsBQ!we_K^ z3nA&bvi5-8FL*#w#wVGTr4eT5bG%u$C5gp>c>iil61cr{WqTW0|M4hXrWG2B2lL8m zKf?0la;G8oidcI?)*uLa*ht8|!Td>C>(qBpa6CZ_%mJy*bSR%v9mo^GkKnK&{g6=f zvNnLDW@pq!5dK>80RBM(u!-__V(nRD$VH>PUrheCr4upz>-C6j@$V#wev+o#A<56pXEk~a#eE|0P?UVs zIjN(@O+P_?ZjQc(oh=;HI<;SKQ}D1|4G?y^?A{R zR3uB@F?jAkm@a4TEn(-r+IoAr&Ja@5tOuS{l-O^y7S?tlrQiAX1Af(^apxil%@Na& zG^H}X!dwGB%YtJn70arcLr}nn!GlAx-H?7j zcu920jDHD>?XWq{4WWxqlBK%4TyjyO)lr%6Qnz5tlwK+cGtU_b8i z`d|ZJXSI!U2Cg#5hhPP=bg*TRUqy0-SbNSGat?gfrfB-1nEVMe5=og2G9Lz+^FU@? zC_DI7qV0eo`K0JH1YjaHp@nAVJoBL5e7WZdJkW6+`Ymh<&gP8HO>kx6s2%qf`Wl3P zPw0&DHGg+T`LHqhQcI^|`r-WXe)i3~M`7X+2Buk?5B%0I-{%VLYo6n35hQ;c$*A^DtGTW@GK z;?2WLKa@YNg&!uf^Kmd_As7-ENwz^5zyKV)o3W=#3+~;S^i9=Y;OY zHTK!wG@a`j^X^^E58b}FG&MlCS!N%W_plYpY@PuF!?(bCl-iTb&VsDxU zOg(9HhI(S7Dn{GxA{2H;zjvr*Pf$uW1LjP>9w1TvjWEG{{cWpqphc<3IQ`!YmtV<~ zt8l}{U6Fr_^V_Q08_ldB!Ik?5==qZkul#iCO}IHs&My*O;5Thpy~v9QQrqUwQ&A!; zhHAx~3&E=aCtz%A0O!y}3^F7$^)s|AX^U|QJJz{mmc2i@H?Dc`UQHGps}bP#`ou-V zXiOy68|q0c5#kE zmoD1z{1=g|qq|cwp&_n1chhBwu+wM19$K(Slzq5xN~FDx#zsR(6Z^wG(->QO!CtQa zAEUi1BtJUL!duOlZZu;$+l;A(Fpc^D#pEow)k2#_RTxoqvl-X9W?Xf^HO3ZJ3lnfh zHhwMfY8?dr4^r`U!4hrLuw%6gMx}*v81)y6XwPkst844UQ2#jY$cE%MOY1cUk(!u; z(;$kOP@>{MHsiqP_Mu>Kiw+8^jh zJ?s!4pu5BAe6ioOG2l9Ew}I+h5v z8hR&cuW?)M7x5;R?~wOfqkPFb0(bv*TNpw>Zd$t7mq&1xKKA8NoVDj*a{9J|1)zRA zhX*Cg5~gl;0eg4T#Ttzczz zpwwMIZX}2quAhg8c5BK3M%$4$UTNs zk@J3oU~{+#;ZAC>1|SX392{cfs_;&uqoE*3PJL4QLPRxvbAj&Ia3wJTr#q}Iv5GBB zZJ;O!^lXhofJU z@Cqz|fMGxV*tV-e#ANo(vElQ6$6m)f1koXd+E+r#Zc)CcFvT@j=vVW6Zv-$Z4lQtq zY7ok@rK?4JGli1sb9g~Ul8q&vb?`eN2EKZ(kc4sPAHFI?;=7_f+hI+%R%?B|T^nsX zHdi=4xda}|zVvb<7N!Ja%BhuSVJ2};b`Wpnj>I=nKriM|PKkH6Vm!=WajqMPHOqb@ zp&)iw7Wzy+3MY8&S!Z!ufNQ-W_`54XgV&zBDha)=`KraQh&Yg7EkS$}^+#Q;ya?yR z75<(ct_r-M543b5kYxmZb#CJpYGM(P39tp0t7w{a_F%IL>!-0Xi)xE1G} zjHZ-8u$NZM*U84MK9>VDZWhKjc~jlS^(aO&ty&rFOMnhEVqly7k9AbR8wwO?E4$Is zAlqgYLns@x5HlW)?D?D97?fGXq(Q$7te(kNygq9w^h2 z`@jOul4Q@{$_Xz`#4yo|egH}p>sIIeU?<2kZUY;wo8^<1`!161!D;2=cPpp8?* zL%w3OPQ=?_=lYWVs_;^ShNm$V`M?F;yrsq7d26zixvs@yGJZ@hfi()Ibk?FA8tF(8)>g{SXbbPE2UBcEP*CCGF9o z$K;m2sd+9ko|7!JuB+`wNbYL3FfHzD5*zOBsO^s=ors*gqgu(g#6+XKPxO@^y%&e!vIKJ)6qQ|)}YnJtAdT{_p5w9KrmbZ zD*Ha5$@QgQu_ja9r$6P^C8n z;ma71Y%I1vn!kxF=s+J=i~`V*p1(;H#=Db^#mUA^Fu_L0F9pM>1B3jlr6;ZK`Vcy= zHE7WnmFjuiR3RFK0$hee-iSb^$d5+#N3EwSt$%eh>wl`l#1aj(9~PG{i12^f4|Mve zPrsX&O2|lR%bvry%^DB&)K>6+b6ma665%rzi$1r%I?p~h72mc3{lWuLk^p3eWS4<& zVs)oF+uF!Ac2^va>b#pbZnEbWa|LY_YcWyxk)JvmbsI#xAjntU)J$EoK|+`gKJnYA zuE%JxcSxhSrN&YmJvrYY^<9Xac!G!-p{NqGLyKzCO4VYmY%6C2pKZ&$trg>D7A7Xihb^M{TZO&#y8=?lfbF0sj z^pyM(v;5d*(Azv_M<}KYtSSgXh%_cPmS6P|@J9>jxhxyEG;_5D|Sx5f@cxKc8T7uK#pGRHZFUjv0LZsoa*v58f! z($U=W4$}Vh<3Tu3h=(@+7(wPX^=*g~ux{>PSFKq&jX6t9%T7Zb4 zMhJ}*LBsJZ#zr`x3V2oBZQP6klr%Q87`;$5EjrcaOO6%OBq0yFKC)J?M1#vMY6x8Dr0 zb;b@^QUbr-JO%M_bj*|#yuu%*<-K!RVSSV-%5fjKjBR^>jE}iwd`l`vP5VlUej4yd za=En9LwKd~>-fybL43R}0UhBpX*}LR$xKBZg!0q{v+wGAv?W_8DN*~i4&@9yS>&1h z{493jOlRG|*IC1v)rcG_I6IMlgdID3rSBZNAixghD@xz2{FM%}|VSb^HU&t&Z_IyzUUoSNXwjZME{3-VR) zF7GuQ(hUe{lJOxmS0K7>`y8uNr?!0sFnpr$vtU042EV=YWt_4EupdY2Bz2@FEHnwwUiI`@W{TJs zfkF>Zlu|Y9vk`z}v_)Vfb!tcf)D6y%AyQtA_Th-WaJDML&3P*3x0*y~5rs-`jp8%X zk~~~;=2Qa{6&}f_KAXSLJgdUj;d}&p`bs>1kiB%ppqpxB z|G6^sKC^tplniEERo8+v_=TT^b&!u z*3~t@6OO7T*_MSRAS=SdX&u5Nl#}um+jrtOUqa z&e900_GW9>XlRv=R!Lf`{%~x;)|K1O1W5Ml0oeNCzu>_)0std8l&#u^TXuYSOOEk) zwUujhu-M?j3lPN`KPDzf>5G%B1Eqk8V94?$w2hGL2hnCqusQvN;Lu`)-J=p{jCdme zmJbqnhcKldw_bs~?3SQbTi4k2SEzg>D232fY71U4E18`mPR(JcZS=NB0MuY|h->-;|?M(28x znB@uf($yH-y|Nki|0A0uQ~IL+Asa;R6FCPgV258ee(v942bc+VK{B4nU_1)Jn%fW$ z?9d<*6^SUSJ^6gWBdk7}Ru9$oL`pknU`Q=O+zt5p;8kl#$W^)B#?v8u$F_|czm7}g zzXr=!@ZweP5|;93)EtvsYj228{w?{6sn%aICyXOM=J&-Ur4iU$FQ7Nazis>Hi8zufeWK zu9o-%@EMMzrNpcRRuOMu?5n&dBsrsMV@+$mSBHD7Dh$E|*!p^OC#;^y1~kOl60*pw zoutvrS8CNQ0hS4kHF#B+FUQ~w&akhEHZ0xyt5fOo!3Qx-Bg{%xggM=94HdQ@kyB5P z#2Sq+T`q&Njft=y48VU(Ax{k+Yc~f6^ByzIqFD(qM;3Z>xYES+RNodafNDj<_QcZwC5jAhA0sl+D2wDU)Bhe3W%NZ4d7!q{yEpf)^ zsIdyh5X?sSHT7Sksy7f{`~w}&SUKvK;#9V& zDN*;YOjg>|&(;*bGzQBc>=F2qOOi|g$Ife~gME+#b}olt_sCjJh2S3u9xn&#h+ih+ zm-em(b_=G=W=3UzQD>k+w}?>&#}RyqFa-Z!!*w||2vvwr8gIa#3EhP z25ml~b*SWd9GydRZCGQ3)mvakBFdN!(5Lb`) zu0Lb3{$#hTKbke8FWG>pSzzi^VyY%Ejj2C?sm7a$y82=4iJK`=;3!^dyTj24aI_oS zels;~4z50+Oo*Op)+NVnYxw_H+?B^SRb~I&G-=cI1!!m~Elr_?mbHa~4Q-(*4JMeB zBKwZkscb3(35!}%NUJXcU4WKN3aB8678H0fE}%|Xgy#1> zFDc?U^Y@ewx$my;zH{$A_ndRjJtrKy$#HRH5%K~P$qL(#R_vS>?3@;{B;NbZCjG6k z%5Myt9=J8Ak3366)olvJk#8EX*x<>@2d#!|q;2~9t*Pvz7jEmFZ_{_W4uibYrJ<17 zaAx^KAQ-dg87MI06C8G6AG(peGL0;*$+jn>f65^sAH!(tG;+bmF&ksNGR#`kpCFh1 zQIazn5j$DLT=InC?u@^ zgd#LVZS>$)k3%YY{9*2<&u{CLujg*+xSgi_*VRo)otetmoJ|uuGp2j*!CVPR>x;p) z=BD+dKun88AUst_8?KlpAmSZGdw^TLf=YWH3Yl-l#oUyAR>K#9D?`rGT>-?&{yc1O zMt?YZ)3MG(XBsSlLEI6zxg&Sft=@)WxHXIevaM7>R6mbkWf&f+DaRc>39rDC5UL1y z5r`3&ziAi6A)Q>mBaqR6KGn5i+<+REQe83a5dc9+WQM-c5!!;HjYg<7>PNJ_tjHW)V)jrtyE7G)>iZmIdu|71`Almg$-J7 z53DWecQ|i?u5}o#GjZfHl=E7#*Z_rnH0EyIehNG)u=@ub*>3d#M4dY{j)9P&_qP}h zE>E! zzYNuk;!UILf<~yCj--N$%a|TEJfRs>yhrZFcpwX1HZyGI%;t39-U_00eFa$KVFYl> zfc?Etd^wbTRR!E1oU@=JG8;0fbTPmmj$RFMz^%yv?`Mjc}U~4L)cW7!FPo) zJ=5?LA#D6Knn)HylLbZ&cG`r(gq`J*bLM7NjOgk_}*xa1~Iy*2g z0-RBsqkEk^Et*nvdxoLD4&@1f6GHcDF^( zTxO22IsJk;nxGG{dM5B&p)AeWHOpc@qM@a#LH?&u=6^CVA@GHhGJXB;^ezOw^UdjE zflBnm0+q;Q#eScuiv`L<#dNviaOeVHA2{B{0`)b!E@0DAH$bPt>=Y@lDL^Ak$787X zepoHgTTRaL+eT_|JW>$xD_Fnq#x!zRFW8#=H(0DqvCFUFCfEtgZr(ok|Q5EL>Cu$Rw zMQRQ*=hP5b>DOh>34{P~PT$`(qDNt{!YiNKh|_>ymutPWWm(-$VxKecfKH9y|bKf1N>X)N^H&YcD?O%+gDvX$_egNR4%k?N zD9QJTuaa+quPUskfphDAk81xB6|5V~KMiNUiRps^nB4b))+B^AF@mMUe>Vs_hM0Gh zJ`pO&GCIpfjBkiw4(&_GbwtmSM}78O?@S&Y$!7H53VIqs8gom7eCbq2o_VFTn zD3~^_FBeBEQX3y0&H9JGyNpoDHR;d%foL|siRlI)evfr^y`bX&ZZtJe&2_R0!78!< z?JdNVFnd-(wMV@)9dp_6{c>2)fqC3)g(c&<#c)M6Z$r%H32d^`yG@G&- ziak#b*IP4ikaLCJcgN^TWLv%e@tC~cD$Pqv3aaIyy@n0 zFjqH8s3tr`hL&BIn9Wm^kD1VB4u=|1YY5m-P>o89SPmYcKx1)PKn#)zAe#XSh>jvl z2$XK1n2NT9r@jM@L=%>b8i0V@E)Wt&~%cr zA>L$7)jPeiggu-%LzK3Gax!Ze-TDOMhIisYPY>S5F`sPiNkDH+5c2e;*JIqExZd4j zxGt>kh6J0~Y!#1N+#upJehMI#n=)eQZ*floVrg<{gTg3diYnE62F;qsiG{!`C0Z|$ zk!T+xzD7ILG*Ld7<10do=@!}wNQ{OE@CC$ZNC8>_nmfFyxLqwNR9Can14!M)!iCSV3i>(!wffK3Gnv20e=Q1K!;8P;PD8+l1TG+?byR% zOI$vZ;McTloVEeLCH++(<;!BTw1`jW#!^zY)0BrKUyF_4MS1!cD)yKSg>bdvcMPws z_wr}DvA*FCAj=mf9qqwuy0Lr1yUDfu_N6?mI~(i7RSyjr%19vRHc`+ZERYu`ye+{> zz&{3{>I;+up~`o@7iY+Qn%g|Jwr4jZK2`QLD_fhMOfXkL0jO;cxlSe@83?d`T|SM! zhwnT1OMC^42#nU)vmwgX;~?VUm$BMa?jib@`M&NfJu)7;YNSmj36Jq>-C5uG7l{^! z=noi$6an42F5KCTk>2E4J=pNj>777e&+JN?)?lm1pF|9gQ1v{1r|w+{t&KaMGa1Gr;DtpYeG2_o`mS)Hk__Vq$><_6H(Mg)oDt3C614ZWuu}uETvL7ZH4E7rF=~+aNzj4 zIMtPn1c@!u@!5p&zJ(NCI>2|wvJB;dJbpfw^>nVdNv^I2W3XT@Vitr{u+1_93X0N~ zOJpR8izvYC($@>o+E(1t-n$?VxOK%01=)H^G`jYwjO%X6t4p{me<J{l^=U}wFH0oZMy04OOPP!KAsrhMb_@&4;vU00 zbZib&@X0;d@PV&AjBaN5z~iLD`3t<`CM?406IH1eF?1*M#YnefWGe_g1^&;TEH|J0 zlY!zSB@rA}$ZCp{G5gBn%u7zh8-7pTs+^Ho4Tj&7cPimeaQV(ipS9T?ZM~`B1LD{~ z2r4kU=GeqzWw=M@m|O-;)8bn67!1`%<~o{1v~}RzW|(Ylt8G=LxwH{Jb}ruljB$_T z0I!Z?eVxu|Y>Il+gKZHb=}tyk*1^&*v|9iPcl3~d0ok8d8C{)zhXyhqJRMbbG;7H- z6i!CUTctRnmfdju0Lu9?frfNA{|^nKS7Cb<6$-5{PPDa3qq1>qYHQ8+LqzDjyq7#8 zTRfFyP8^_f>va8LOOwEY%?dJ3ttU3jW@uX58^jMR9^H5{+%Qd39&Mz%3OLnq9f?Jto|ZBEs&5tmGU3P61XU;odHJ!g*{A1S~RtR`nqwPTyEC-G!LCmeMA3Rja-3 z8Z{xe^;J;{Y&c&kf~yf3(m!I-QspAJ9HH}~=e(QH!UWHh0qBn({rSWM_vvsa16qY3 zDJ{bELOHec6{aVBxxBuCe#rm|?CRsdE6pmBwR1*A0uJQqeE@@0XGXAYVU(t z*zA&f@$Y)EQKQn4=Nl>A#Mlz)FvzX`;(MqBsT|2Wly)fB;8^~$Gzn-d@JOxB^(y%6 z1eVSI#;X%pI$OivO<*bPTYffy-J7Jtu4;BWP8Y%Ye(pT|igDzB%gTJD*<8!V_GaUv z{(7s^?+b@=>S?KoKiiv)>aiX;K*p&pjksy<_v>sg@l(B7pYE@}L>cgN;dx(HRy_GI z4@+c816G#7>LmPOPq{}1)4Tb}xN6l&aFU_q9gpw9PQdR=WN9&fzk)9cwGY7;sl99Y z+C&zYs0QO;af7B28@yw>K?&GaiUGM;Vw@yJ@Lh?lBz*%cBEYh6f_&?OG>J9RKL7_H zk1#r^)A%9?G%+1KBZ&=V1NjUD%6$v?h9nSvCGz6yG{S0%cuGEw6&o$$5wpS8DpZ08 zrG*q>GOX1I&!r(|UUCpHx>_VliETSghU-P5={?~&I=c_J zSvHtj?OLPZ(-qNV2*zZ1GE}n``mNAHUee%1YgdX4UpR_Q2C4kvBEy=fwPy3W^41E> z7e@q4qXR)e+YOD=v@!aRN*|zoOX)tNf1eRPC~c)*QmeKlU%~^}($J`J;*|ax-&$&| zSCL^+)RR3r)K7m)^C=mXQK?8=6jfwct#S6pZ`9J>^dEQgNB@9<`# zRInZ{8^v)^(k67sw-haw53ry$(p+H|atrzSWR{RnU|x5l0)=5t=v_6+4M(ja(RM^i zu)2a0FeH!5r61w+Hd(^lXB%x5UrtS-JU-Fjz&KcXEe<*%PdWw8t@Xtirgo zLKHsjx38um59?NvrtGZGDJ#SQ&_U{(k0%Q!ulw6m-+b= z_I7APB~&Y#YW~od8Cc940qTJcn&3)9fKlB|Y`^Gb(> z>Wwuo@uOb8kj9@)W0^hP?he?frJ4RtXwqC3Oz$k@V z_|X0=W%8}*@&HJ0h0%g^j0b+HfA&SV4?$NIR`vxUo72HE&jrf#MOyt^_)NKsR2RtY zq8Gf2__qG6U(~W$Sd1XT!=z)K{CIyBoAb9$AS)|2()wX&+alhUPFMnEy32hc!l)sT zVjm*ARwuL&ejiU7z|w}!1)AwlpSVaXC2sFWc)iq2dn?Yd@Rq6G_t0kj>QLf`FH6_? zvH>hb6O0|>zZ<|@;V$Cx!}io};%VvZrIAAt6mZefp`QLFHL3RM`;v|jZO@@vzu$1p zuFE?KI5%`sKrgLrsORjLt6djT~=~+CBFsA=t3b^_5ui<)*$OQO8)!C7Q z3l?5L-lxu|s|${v2h_hoDm$Q_Pl1?Jg20z{KusYt&NPy|Zfyu&nYmJw+ie3iZ0e2^78!|Y?QNP3Tf%!pb5Ou87r7m ztSD*ERKR^*=N1dpTZB90J;-@%ci8Ey!mc3;(Hva7ib>P);2Y3YNT{3z9F7t4w|PtO zB$Yxj1`{n20myMIIv5NO+@z7WN+;|a>mC^hi3mD{aeMwk0LVvs0gMj{P#aUP4JJLT zN754*45Igm+`f)a?@-T|vvbS=*H-SN57C%(0p>LbyyF1gW+VW-tr#F&^2^oTi>cul zC?>szbYDu}U`6S%aAFu5b~3nTgMz!~eNr})BKz`$K`c$V{Sr40VzJHxAd~O`GCKfw zh6Bh{ok5+RjB||Mgubyf`yoP06L*GJYwE65;hxn6x7u@_c0^2{e}2>Hm$$`6d?K2_ zB^&Zvd9e?K{Mz6uZAZj4mf1t4nXqaK5IHs8hY1)7Y7^Q~IY`9ey$^ly?!z1e2v42l zy#}+Sg=S&1@W%98!`00wp>6NN=M9Sq*P8VP~AK0%?w@td70A24S7oVboy)FP%>s!g>w4 zL`(lT29Z7-lAkZVui^{b>Vr5|kUhV@hljju`$f0t$h z-ZF&s8S_RG^$wKUu=+EEvpw%$fgaI;N;L%v=|>Z?fmzhGf!x)RQXG1W$xg20&hvgl zS%3CCpD>i=D!=`VKRuKUb#@1nVip~3V)>`i@I<*V2+a8%YWrunUGFZ(k+h@DZ98qZ zuFJmwir$ZoJ44AZuWz(l7ykv#!68SHfm8f5(v{wF3)DrJ-cP!L1!3<2ORxZ!qF#v~ z7>Z5ATkb4Ao;{4^=x+Y2)9+o6Y-=gpNq}nlc+b~Q^L4|RE_a@YN!#Z3(B%z~$Yedg z7v6>ik8{F?b7((IdJolo_lSpzpeybv-{3##8wj)f=lJnqF#7f9c*12;?^ymXyvk`o zSr|=LKb3&*E^Vrr z)*@0Q>>B7e5ODW8k1xn#y=I*}8+enI-gKnvO~D&;ld)u6R9Rkx8KTU5qsz;rL)T9=6j+zF7zSTP>W8mRrXn09`fi^b4l+Df5sZbvgC z_v5A=Kt@74>Or@|Yz}Xuk|pa=5^CkXdpep6$X4qR)7A$^q1KR&Wy6Fw$yN0vJl|$F_AtTrjR>5bFU}uMJN}*BCAU~CH6G~O@lM8g$^{};} zW;M<~K{cpS$-1*?aNXBt#H85!=qq73VGF96J)0$vr9TLd^{(m6X4T3l zoajO|2khaxeP;f^XqF&YOI7fp2*dj5r||4@zHv0`E9lJFj4NdLo{}_XzGpN`iMFh3 zppTGSPvR*#ERQe9VX^%29Cncz`Fv>4f)#=Y`r{(;n32yO&Gi4)`m=KDF>`^O?zCRQ z>+r^3G;XN5Fq&nsyBe!W%46YoC-9tnHV`hV`9t|k-`nQdKs}S5Dhz&n5kLXU!dCY< zz9pZHVh#LQK8p+0lo^Fb3;5Tl<1ERvc$Sp_dNT-m;^r*~U?Kt1)XiH1j|F(#5qN~) zb~8blY$)KdHt-1IWV7sa+Fhc@Be|qT0W%)kowG6mAf)R~mZzcI4@8V_oK)lu`_ zg{*(*=Xj}fhTmJr^ojiddPwY7sUW?aU=>eUSc92N=wuv|`fyhvyN8wWJ%#Kq+P96k zj9Yb`wqg89oqX9iHq&_q(jnSx;=+El*+e1fSDOvhrOoECgI$|V8oC_-`LLhZ@ZWR=yG(RE zl@v`^9ETug!#A46x^x?9vb>pzAb9P43h0%|d-RmfvU8i)|KVa_bDX8=7ZFpPUEz?_-k^;9ssE?trK!&qH_N?A?mVhFtAwS>^K zRa}9iFr28tuiR(S8ou1b#!dJN9fxXBDw0`YV4^KWRlmd z>xqafPpNhovO4P8X)Llw(*n`mR&l?HWyDRTTJnSee!U$~Qs49VMm}~tR2JrmeD-+O zuiH*w6TLav0J6-|)?%?zfds)0PVgTQGFI(gc{hD^ledLe% z9TY5c<<1c*U&9mG`^{Bv*^dQO`3J;tRc`edqIxV1Zcw;sdp~EDM?B?hndmSO>%2}dayje55{kg%!^x zB58j~ls|2T9A{S(hbJ42$T!RJkOhhd6`>1o*CR)c>#LP7C^M>+{n{Ug%>uj}B?%xVb^yq@L4&{OgU>L0ff{(%I)=HC`ym2?GjPA&V_w{oB(H zL%wr)gB%5jsEl=k@M51YFVh~Ax4_;v58ldaV!I&2)8!uSz3Z$Mtyaa^^9&Ron<)6=Pa*H3HnP$zu&|^Fi!%+-J@k=on*! zk3b$;!umZ>VZHdV>#I!H z&G1!8S!acMu)xchXM+4D#;j3d>Qw^HQGXBJqAkQNJ56vSRY0i-Hi24 z3L%SLK4?mi~~_K?>&(vuowBLiEKpl zjVN%(kJ)GDEfcD~;VUPy{;>y;WZbE$-2=>1P~l%~PxZdVcTQxwNF>0-#?BCA@wSO9 zCE}D8F91vLeT@G!krgRTW!zZ87U?%v85Je;W=rW|c!M!cvzFp~-!HYmB*Ltj-mUyl z3418&(y;;}w;U05o2&TfNo*SqYtO+>mGaUtKIndSQ}+~9*5v+YqW^FLPuP1oA3d3+ z&$l28GHUQB@>^~ObB80@RsNpB`RKpbi$@OZ7fK;z$AxWErhW$E$nBI`eN za~qGC#(MX93c2W0>@WKyR6febOk*Q5Mcm4&nWaHdYi>Vq1 zS~w;AN{=(f?0^vy&ju#b&>xGo?M0&3+;~ZE4!>#$XElekH7}X%CE>c3GD4#!awq5S2e5-qf!k%$R+lR2OHaUPS+#bb;ibTBH`^) zZw>b%y_PT_&MEcgltxSV(O|cHF)gO;=pM{+RMW^oD+0aL8^LP|m5f0qg2|5ymC+5=_S{PY9KCZteOhN_dWLT|_I!LEvu^zoFd@9Yrr) zKdGD#$)fF|jPE^Bo2fH(D5^Mlp{h-&JccLF1ivS{d-&Cq#-ebqQ28FeHiIQO{|`Cl z;}RP4o3>N;E#dpUqTDC7BOGMLnl&(Y0K1qSa&wKBl%8V$$qPkQU)jshA})P&FA8rg zs`A>W@1d6#dZGs6zM>uo*phM%fDo^q{0bKv48B^Np`tw;TGfMeRA7s?ry2|V2Yek+ zTo!PU(E);?M`ODR&Tixs-*-m&!n&(`dzWDpd$N1#cDHH!yR?%u-b~JF<6q8XD+HWn zGuKH!>3Qg&p}`-X#qx%B`~KGx{x)s@haJ){7lOm!{gNM_1@^ER`IKiV4Xjl-D%dF} zk>@qX4j`@7-GUQ&3#FHqS5ta0sR~JWJ#ZlI=ysLY1~RL5q03&FDhW*cJ8N60oQO1h zfVx&qE*g!njl@^YX2YBU(%}^h&`ibfxNX&zaGZ}j-Zy4^AiGX_44*>o;EFJ(d~n6@mj{JPU`zm8c}({E_7Y5~(k~b6pHSi2-0gt{JEv>KZa}K6g&;OB zX^6-*ZC~4gA)wm7yY`c3btWk%lw#q^h;KFu`)yl=%1k^Mm+X(gLZh9#3r1D(NcWE9 z<#X6DVE5POu=shT9zcSQo6y*_xEh${+IhNg3|;jX%&ftZ(PSm_3Ymo)ibBB`UpI@V zAOa0vb-3_=DwL#G&|AVg zeaXlonW^$id!(td!=c&{MYe-5JHgx*5KP(4BEuuvm9fTkx1YnHt%^LL%ryF8zpKfI zll!}hQ5(IChI1?aQ_%}Mv_j=J)Hk|rsDu|Acjz5fQ;l^#YgR%pQTrhKK-o{j+aF}M zZsu^p3}9=Td~b>;YTIApV@g?y_NO?kO`Od@oy4b+G~xWQQkLj6PPO4OG%kj^zRq!* zv>WGw@h=AeVPgq88MqI>V}q$?!`yeE+~w%s(Fp2CzZu6~Y4|x{s!>=36K=7b|GeU0 z1(gTO?3;j}4pXbjZp<6&pslBNFJx=>oIn5D=OSj(nK%{ws zR0WBs?i&$ofGPwoTxOj$)}KKw z3%sD91a-lY3Vw_DpBtb#eSJ~XKC1GpqbTbv<=QV)l<$V+pJ170l(CjdzW#EH%ax#4 z&&pld7Hrh&4Cq9Z$ABq==Pa@r;Rp|!c=FA87eG)@yI68|Z7{Z5;ZVzuG*ctUIsmCv z_>Tj7=T6`f8%NwM>VH+cQq8gl}sS^4+F6R%-y8$n; zv5T%Bn9Xnz2o;k*)#BfW0q;?Hmh4Qyc0tuVpnvat{B$*D^nVP&{!y<9ZJ~>TeIk9j zP*siA;K~s)N^*26Hem}z3a(?}_gWL_-3pag@toFxpL}Npeub*1@oN)rVJg}@CPKW9 z*L@ox28vA;+t3e9C9MBDP_-;gaf{kjmgOr>3srxoY9zawi9FAGMLOA6FhO1Oa$|dh z=S8g|6`ig^AtIr>+8Khf)P@QPO9gK-qG-PIL4@A!{5NIn9%qB_^eKFnC8Hthpcx95 z-HjXVQLOPosM+7>x->TYd!N_Bj&(u8Dw?(e8nC3W6~L`hQ9}wa%rf}lOWf9))v)e- zCAxu|R4T_rVfUTsFVB8>KooX2Ts!R>>7EK1v!fQ~!7*6JKs*4#4c>P!YV!1^spx$e zE#H|#-kHRhyY}VWrJ)0BO_*r)FXI9~7$S*C=h~O2@EH%Y!E?U6*a>HIdleu_ZDRW* zjncm;E3KhO^V~83vv2?gc}#KcNpW>7P8lrrQP`UMXayV z_bP8)#D<4#@+tW3MJz644Ibhav-RQeuY#shfBTh!Z(Ga;^?Yp+33eQ~p#k*OV!DD( zDG2iHTf`iTxJ(nghI7IK^?Iny zn9&@G455MW@e1(!-(yF}>abixIJM2E1Cs>zbrd^5drBY~P1-d=x~a`5WGI|;TuFG{ zEWCdZ|2x2mnOz;YfqQjq##M{(my?#07djdXY=Y?w{vU^Ip(E==)xp&!h`6od=TKC` z0G`67gbr&jY!)ZzrfOs7ScpMfml-KN!;(qLXV#QcmW)nIuWL5pA7_~VV8L!?Iqvh- z6y%dhGE)=vDbglp+TbRN^wP6V%$)bL(iRS%yb#SPM4T?V{LYnn;r(OoDBFb1JZmW% z9Qq7~OY-v4rEEkuC9Y(O4Zd^N+L{Am4*tecwk6@>1$?5TXT9E4`_0}36QMeG9sJn= z_0bD_!6U4f_V>>#U^z3EZizzFc0QVmkFbn1Dkz@vwc`$JTh}!lX<`o=3@9*R>%Ar! zd(@nIggt>n1&=DH;(}loHpYhXdCS09*|mS&zKkiA%VYSf%UP=O!AO1tA?wetE@yEp zm4~l@_23NVqlCpVDe`;)b)~5PSyvn~WQ+-TjpZ?Z1T&ch~u`;jO-l7^KpC66vlS z?g5_k``^8dNPtUNH7d=ImKwi`z&Qj2*Xx=Tn3#>{wc)Uzfr{%FQ$kW z^uR!@M6#>nZ?GB;thxyGvyt97q(RevMOay3i|St4!92Xgkz5Ni7~VgCN>0G>!E^0f zu<`A_CG6hYzJ%6e;GH7UpIpYJPm}5RE@tY3z5oWq9Ua`O@ zP=IJ4K`wNBu-s@F)dCEFxM{1!bxXObH_WHU6p808kx1Y7TgGNwTI*}dw19k&BJ9qKfD81%>y)iofgmg3)DboD_-hN0$tk{>DDU{ z;9`r^<8^3d3!ZoK!>d>!+sR{AV`A*!{a3S;feWzz7vb)qzd?S%r7#O#XWU?ifpJ6I zawwx;?_uu_yUPn+;=e_CFut2sGov!;Hvf1vd!cZrImEQXYB()CO&bPjfC4LTMGvZN zp7I42&pXsD=>uX6fwsZu!!{2-Y$t3xtL3b>_}|yC!7-?EjPxlzrX!MYi+{O>Wya{y zHPLhg2e3B7z7@Rh<18(9D;D9k6GbV9JgNvfo4q9Bvt~ce2KQc!QvkQ)h`eS#6m~yV zK!goE$Whg8sOoG-RV+KXHajHVfQZ#{(reE67}|ZX=_3BLuKWlI&V?$vk=S9X#SKb_ zys0!`?=WKq-L-uX`RwY{t(;-@jQ?s~URcR}>QJoBFh{OXGbJn*T9VqHxLC4kaGBd0 zrYbX7!?Hphdbpemi=c?c5xeAIPxq9tD8unp;UQDP=pw_)C^KB7k)->dXx=LFeNSNJ zb{hGWC)i`k%f0ynPqHJ*jNW`$IeTf~t^_*zS#erZCX6mRtSu8BOL{|2`mPbrFo1X# zhUi8YsaGfP@5!wYJ+ z`nVj5Ei%vPRv(h1(p0>pL!BCEsNq#Kq;5dYybiS%X{#N51ogCh22MqAJ%(Y}TaB$5 zD_Z3j)+n9+ux4Zn>t`URL*2enq0rbryLJZZ4{g4Wr@D2=kb;%h(G+Tr$6XS8AGdnn zlRylTW`w#14|&<7j-$?$yW)$h03+NTD^ic8e$21)f-@vx)ndhB#Z7@FrV5e1TPV&T zKCsYC$@t!!|C6>rVb>BV8%YNl(&a5=tOp>CLZjGOoJnrAWh1Y0u_1 z!jq0r%pO7A3?(u@_AOs_1)13Yq zHr6b5vko>P*BwZ>FBlR%MSs(R@dtw8qrq@ZF!Th&uJRW*)%@MV)`xCN6=He8i>x*T zTQ$$!3@z$vzI-#=5gORKYx=yz1ja{lmd;=Q1G`rxBo`=l|B)>e`kVj4z49kMy zlfm$rVEC#r_)r%Nj|9U@!SGfv>;iqdu0Vdw4u+dvtaOx`MHWb*x!GSi=oPo8B?UG-4eZ{qG*G&~<&TbnlSiKu}E#yN>&^ZE-* zVh5}Q(wX1O8an^J^^7gh-`jic?7qc?Yo=DRK1=5%g_!Kq#yt8+f+K5s_fZP|+CN#U zv!bFx|BF6;CWJ+2W(9#ag8-wQ{%hb({g1$#2H?%R1H73s@a9hq0B_dp0Pr5{KTQVS z0|4HFL3$Z_;Oc@9x&y{JU0__a6I=c-!FW0Bt}f1zyEx-lU7R`Pzjje^r;CB{RZNYV zb@%wr?LV8kIDH>`!qGhDTE|@9#cpt~cmI7*tY}lJYKs-eiWN=8 z`-+>34=WWdsIoI$*(k5A7!Ozzecz1g z^8MV#lws6^Z`E=SzW+E-E+bT#cvrdRJ0BApCYNhG6(~0`?AISNS`+x*PpQbzyIR@L zCo-j)-nJlIE|PpM&`QZSER<)3Dr4^|EW>5+kNAZDi;zDd{mVe%#t3E7UFDkYbZy;r z79W$Ukfo{ebS{?yHQu-mODNw({-XJxzvx7i+?T@d0)?Zaf7yIbVwtG9DEw>1iQK>| Hv{?Qh7fq|_ diff --git a/libc/alg/bisect.internal.h b/libc/alg/bisect.internal.h index beaa9be7b..242d50668 100644 --- a/libc/alg/bisect.internal.h +++ b/libc/alg/bisect.internal.h @@ -6,19 +6,23 @@ COSMOPOLITAN_C_START_ forceinline void *bisect(const void *k, const void *data, size_t n, size_t size, int cmp(const void *a, const void *b, void *arg), void *arg) { - int dir; - const char *p, *pos; - p = data; - while (n > 0) { - pos = p + size * (n / 2); - dir = cmp(k, pos, arg); - if (dir < 0) { - n /= 2; - } else if (dir > 0) { - p = pos + size; - n -= n / 2 + 1; - } else { - return (void *)pos; + int c; + const char *p; + ssize_t m, l, r; + if (n) { + l = 0; + r = n - 1; + p = data; + while (l <= r) { + m = (l + r) >> 1; + c = cmp(k, p + m * size, arg); + if (c > 0) { + l = m + 1; + } else if (c < 0) { + r = m - 1; + } else { + return p + m * size; + } } } return NULL; diff --git a/libc/bits/bitreverse16.c b/libc/bits/bitreverse16.c index c3a8058a7..7769ec82c 100644 --- a/libc/bits/bitreverse16.c +++ b/libc/bits/bitreverse16.c @@ -21,6 +21,6 @@ /** * Reverses bits in 16-bit word. */ -uint16_t(bitreverse16)(uint16_t x) { - return kReverseBits[x & 0x00FF] << 8 | kReverseBits[(x & 0xFF00) >> 8]; +int bitreverse16(int x) { + return BITREVERSE16(x); } diff --git a/libc/bits/bitreverse32.c b/libc/bits/bitreverse32.c index 405068a13..126e5403a 100644 --- a/libc/bits/bitreverse32.c +++ b/libc/bits/bitreverse32.c @@ -22,10 +22,10 @@ /** * Reverses bits in 32-bit word. */ -uint32_t(bitreverse32)(uint32_t x) { +uint32_t bitreverse32(uint32_t x) { x = bswap_32(x); - x = ((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1); - x = ((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2); - x = ((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4); + x = (x & 0xaaaaaaaa) >> 1 | (x & 0x55555555) << 1; + x = (x & 0xcccccccc) >> 2 | (x & 0x33333333) << 2; + x = (x & 0xf0f0f0f0) >> 4 | (x & 0x0f0f0f0f) << 4; return x; } diff --git a/libc/bits/bitreverse64.c b/libc/bits/bitreverse64.c index be0abb1fe..4bacc907e 100644 --- a/libc/bits/bitreverse64.c +++ b/libc/bits/bitreverse64.c @@ -24,8 +24,8 @@ */ uint64_t bitreverse64(uint64_t x) { x = bswap_64(x); - x = ((x & 0xaaaaaaaaaaaaaaaa) >> 1) | ((x & 0x5555555555555555) << 1); - x = ((x & 0xcccccccccccccccc) >> 2) | ((x & 0x3333333333333333) << 2); - x = ((x & 0xf0f0f0f0f0f0f0f0) >> 4) | ((x & 0x0f0f0f0f0f0f0f0f) << 4); + x = (x & 0xaaaaaaaaaaaaaaaa) >> 1 | (x & 0x5555555555555555) << 1; + x = (x & 0xcccccccccccccccc) >> 2 | (x & 0x3333333333333333) << 2; + x = (x & 0xf0f0f0f0f0f0f0f0) >> 4 | (x & 0x0f0f0f0f0f0f0f0f) << 4; return x; } diff --git a/libc/bits/bitreverse8.c b/libc/bits/bitreverse8.c index 5ce08fc45..e9788f47b 100644 --- a/libc/bits/bitreverse8.c +++ b/libc/bits/bitreverse8.c @@ -21,6 +21,6 @@ /** * Reverses bits in 8-bit word. */ -uint8_t(bitreverse8)(uint8_t x) { - return kReverseBits[x]; +int bitreverse8(int x) { + return BITREVERSE8(x); } diff --git a/libc/bits/bits.h b/libc/bits/bits.h index 4b2a2ee6a..d4a4c5b4f 100644 --- a/libc/bits/bits.h +++ b/libc/bits/bits.h @@ -13,8 +13,8 @@ extern const uint8_t kReverseBits[256]; uint32_t gray(uint32_t) pureconst; uint32_t ungray(uint32_t) pureconst; -uint8_t bitreverse8(uint8_t) libcesque pureconst; -uint16_t bitreverse16(uint16_t) libcesque pureconst; +int bitreverse8(int) libcesque pureconst; +int bitreverse16(int) libcesque pureconst; uint32_t bitreverse32(uint32_t) libcesque pureconst; uint64_t bitreverse64(uint64_t) libcesque pureconst; unsigned long roundup2pow(unsigned long) libcesque pureconst; @@ -31,106 +31,104 @@ intptr_t atomic_store(void *, intptr_t, size_t); │ cosmopolitan § bits » no assembly required ─╬─│┼ ╚────────────────────────────────────────────────────────────────────────────│*/ -#define bitreverse8(X) (kReverseBits[(uint8_t)(X)]) -#define bitreverse16(X) \ - ((uint16_t)kReverseBits[(uint8_t)(X)] << 010 | \ - kReverseBits[((uint16_t)(X) >> 010) & 0xff]) +#define BITREVERSE8(X) (kReverseBits[255 & (X)]) +#define BITREVERSE16(X) \ + (kReverseBits[0x00FF & (X)] << 8 | kReverseBits[(0xFF00 & (X)) >> 8]) -#define READ16LE(S) \ - ((uint16_t)((unsigned char *)(S))[1] << 010 | \ - (uint16_t)((unsigned char *)(S))[0] << 000) -#define READ32LE(S) \ - ((uint32_t)((unsigned char *)(S))[3] << 030 | \ - (uint32_t)((unsigned char *)(S))[2] << 020 | \ - (uint32_t)((unsigned char *)(S))[1] << 010 | \ - (uint32_t)((unsigned char *)(S))[0] << 000) -#define READ64LE(S) \ - ((uint64_t)((unsigned char *)(S))[7] << 070 | \ - (uint64_t)((unsigned char *)(S))[6] << 060 | \ - (uint64_t)((unsigned char *)(S))[5] << 050 | \ - (uint64_t)((unsigned char *)(S))[4] << 040 | \ - (uint64_t)((unsigned char *)(S))[3] << 030 | \ - (uint64_t)((unsigned char *)(S))[2] << 020 | \ - (uint64_t)((unsigned char *)(S))[1] << 010 | \ - (uint64_t)((unsigned char *)(S))[0] << 000) +#ifdef __STRICT_ANSI__ +#define READ16LE(S) ((255 & (S)[1]) << 8 | (255 & (S)[0])) +#define READ16BE(S) ((255 & (S)[0]) << 8 | (255 & (S)[1])) +#define READ32LE(S) \ + ((uint32_t)(255 & (S)[3]) << 030 | (uint32_t)(255 & (S)[2]) << 020 | \ + (uint32_t)(255 & (S)[1]) << 010 | (uint32_t)(255 & (S)[0]) << 000) +#define READ32BE(S) \ + ((uint32_t)(255 & (S)[0]) << 030 | (uint32_t)(255 & (S)[1]) << 020 | \ + (uint32_t)(255 & (S)[2]) << 010 | (uint32_t)(255 & (S)[3]) << 000) +#define READ64LE(S) \ + ((uint64_t)(255 & (S)[7]) << 070 | (uint64_t)(255 & (S)[6]) << 060 | \ + (uint64_t)(255 & (S)[5]) << 050 | (uint64_t)(255 & (S)[4]) << 040 | \ + (uint64_t)(255 & (S)[3]) << 030 | (uint64_t)(255 & (S)[2]) << 020 | \ + (uint64_t)(255 & (S)[1]) << 010 | (uint64_t)(255 & (S)[0]) << 000) +#define READ64BE(S) \ + ((uint64_t)(255 & (S)[0]) << 070 | (uint64_t)(255 & (S)[1]) << 060 | \ + (uint64_t)(255 & (S)[2]) << 050 | (uint64_t)(255 & (S)[3]) << 040 | \ + (uint64_t)(255 & (S)[4]) << 030 | (uint64_t)(255 & (S)[5]) << 020 | \ + (uint64_t)(255 & (S)[6]) << 010 | (uint64_t)(255 & (S)[7]) << 000) +#else /* gcc needs help knowing above are mov if s isn't a variable */ +#define READ16LE(S) \ + ({ \ + const uint8_t *Ptr = (const uint8_t *)(S); \ + Ptr[1] << 8 | Ptr[0]; \ + }) +#define READ16BE(S) \ + ({ \ + const uint8_t *Ptr = (const uint8_t *)(S); \ + Ptr[0] << 8 | Ptr[1]; \ + }) +#define READ32LE(S) \ + ({ \ + const uint8_t *Ptr = (const uint8_t *)(S); \ + ((uint32_t)Ptr[3] << 030 | (uint32_t)Ptr[2] << 020 | \ + (uint32_t)Ptr[1] << 010 | (uint32_t)Ptr[0] << 000); \ + }) +#define READ32BE(S) \ + ({ \ + const uint8_t *Ptr = (const uint8_t *)(S); \ + ((uint32_t)Ptr[0] << 030 | (uint32_t)Ptr[1] << 020 | \ + (uint32_t)Ptr[2] << 010 | (uint32_t)Ptr[3] << 000); \ + }) +#define READ64LE(S) \ + ({ \ + const uint8_t *Ptr = (const uint8_t *)(S); \ + ((uint64_t)Ptr[7] << 070 | (uint64_t)Ptr[6] << 060 | \ + (uint64_t)Ptr[5] << 050 | (uint64_t)Ptr[4] << 040 | \ + (uint64_t)Ptr[3] << 030 | (uint64_t)Ptr[2] << 020 | \ + (uint64_t)Ptr[1] << 010 | (uint64_t)Ptr[0] << 000); \ + }) +#define READ64BE(S) \ + ({ \ + const uint8_t *Ptr = (const uint8_t *)(S); \ + ((uint64_t)Ptr[0] << 070 | (uint64_t)Ptr[1] << 060 | \ + (uint64_t)Ptr[2] << 050 | (uint64_t)Ptr[3] << 040 | \ + (uint64_t)Ptr[4] << 030 | (uint64_t)Ptr[5] << 020 | \ + (uint64_t)Ptr[6] << 010 | (uint64_t)Ptr[7] << 000); \ + }) +#endif -#define READ16BE(S) \ - ((uint16_t)((unsigned char *)(S))[0] << 010 | \ - (uint16_t)((unsigned char *)(S))[1] << 000) -#define READ32BE(S) \ - ((uint32_t)((unsigned char *)(S))[0] << 030 | \ - (uint32_t)((unsigned char *)(S))[1] << 020 | \ - (uint32_t)((unsigned char *)(S))[2] << 010 | \ - (uint32_t)((unsigned char *)(S))[3] << 000) -#define READ64BE(S) \ - ((uint64_t)((unsigned char *)(S))[0] << 070 | \ - (uint64_t)((unsigned char *)(S))[1] << 060 | \ - (uint64_t)((unsigned char *)(S))[2] << 050 | \ - (uint64_t)((unsigned char *)(S))[3] << 040 | \ - (uint64_t)((unsigned char *)(S))[4] << 030 | \ - (uint64_t)((unsigned char *)(S))[5] << 020 | \ - (uint64_t)((unsigned char *)(S))[6] << 010 | \ - (uint64_t)((unsigned char *)(S))[7] << 000) - -#define WRITE16LE(P, V) \ - do { \ - uint8_t *Ple = (uint8_t *)(P); \ - uint16_t Vle = (V); \ - Ple[0] = (uint8_t)(Vle >> 000); \ - Ple[1] = (uint8_t)(Vle >> 010); \ - } while (0) -#define WRITE32LE(P, V) \ - do { \ - uint8_t *Ple = (uint8_t *)(P); \ - uint32_t Vle = (V); \ - Ple[0] = (uint8_t)(Vle >> 000); \ - Ple[1] = (uint8_t)(Vle >> 010); \ - Ple[2] = (uint8_t)(Vle >> 020); \ - Ple[3] = (uint8_t)(Vle >> 030); \ - } while (0) -#define WRITE64LE(P, V) \ - do { \ - uint8_t *Ple = (uint8_t *)(P); \ - uint64_t Vle = (V); \ - Ple[0] = (uint8_t)(Vle >> 000); \ - Ple[1] = (uint8_t)(Vle >> 010); \ - Ple[2] = (uint8_t)(Vle >> 020); \ - Ple[3] = (uint8_t)(Vle >> 030); \ - Ple[4] = (uint8_t)(Vle >> 040); \ - Ple[5] = (uint8_t)(Vle >> 050); \ - Ple[6] = (uint8_t)(Vle >> 060); \ - Ple[7] = (uint8_t)(Vle >> 070); \ - } while (0) - -#define WRITE16BE(P, V) \ - do { \ - uint8_t *Ple = (uint8_t *)(P); \ - uint16_t Vle = (V); \ - Ple[1] = (uint8_t)(Vle >> 000); \ - Ple[0] = (uint8_t)(Vle >> 010); \ - } while (0) -#define WRITE32BE(P, V) \ - do { \ - uint8_t *Ple = (uint8_t *)(P); \ - uint32_t Vle = (V); \ - Ple[3] = (uint8_t)(Vle >> 000); \ - Ple[2] = (uint8_t)(Vle >> 010); \ - Ple[1] = (uint8_t)(Vle >> 020); \ - Ple[0] = (uint8_t)(Vle >> 030); \ - } while (0) -#define WRITE64BE(P, V) \ - do { \ - uint8_t *Ple = (uint8_t *)(P); \ - uint64_t Vle = (V); \ - Ple[7] = (uint8_t)(Vle >> 000); \ - Ple[6] = (uint8_t)(Vle >> 010); \ - Ple[5] = (uint8_t)(Vle >> 020); \ - Ple[4] = (uint8_t)(Vle >> 030); \ - Ple[3] = (uint8_t)(Vle >> 040); \ - Ple[2] = (uint8_t)(Vle >> 050); \ - Ple[1] = (uint8_t)(Vle >> 060); \ - Ple[0] = (uint8_t)(Vle >> 070); \ - } while (0) +#define WRITE16LE(P, V) \ + ((P)[0] = (0x00000000000000FF & (V)) >> 000, \ + (P)[1] = (0x000000000000FF00 & (V)) >> 010, (P) + 2) +#define WRITE16BE(P, V) \ + ((P)[0] = (0x000000000000FF00 & (V)) >> 010, \ + (P)[1] = (0x00000000000000FF & (V)) >> 000, (P) + 2) +#define WRITE32LE(P, V) \ + ((P)[0] = (0x00000000000000FF & (V)) >> 000, \ + (P)[1] = (0x000000000000FF00 & (V)) >> 010, \ + (P)[2] = (0x0000000000FF0000 & (V)) >> 020, \ + (P)[3] = (0x00000000FF000000 & (V)) >> 030, (P) + 4) +#define WRITE32BE(P, V) \ + ((P)[0] = (0x00000000FF000000 & (V)) >> 030, \ + (P)[1] = (0x0000000000FF0000 & (V)) >> 020, \ + (P)[2] = (0x000000000000FF00 & (V)) >> 010, \ + (P)[3] = (0x00000000000000FF & (V)) >> 000, (P) + 4) +#define WRITE64LE(P, V) \ + ((P)[0] = (0x00000000000000FF & (V)) >> 000, \ + (P)[1] = (0x000000000000FF00 & (V)) >> 010, \ + (P)[2] = (0x0000000000FF0000 & (V)) >> 020, \ + (P)[3] = (0x00000000FF000000 & (V)) >> 030, \ + (P)[4] = (0x000000FF00000000 & (V)) >> 040, \ + (P)[5] = (0x0000FF0000000000 & (V)) >> 050, \ + (P)[6] = (0x00FF000000000000 & (V)) >> 060, \ + (P)[7] = (0xFF00000000000000 & (V)) >> 070, (P) + 8) +#define WRITE64BE(P, V) \ + ((P)[0] = (0xFF00000000000000 & (V)) >> 070, \ + (P)[1] = (0x00FF000000000000 & (V)) >> 060, \ + (P)[2] = (0x0000FF0000000000 & (V)) >> 050, \ + (P)[3] = (0x000000FF00000000 & (V)) >> 040, \ + (P)[4] = (0x00000000FF000000 & (V)) >> 030, \ + (P)[5] = (0x0000000000FF0000 & (V)) >> 020, \ + (P)[6] = (0x000000000000FF00 & (V)) >> 010, \ + (P)[7] = (0x00000000000000FF & (V)) >> 000, (P) + 8) /*───────────────────────────────────────────────────────────────────────────│─╗ │ cosmopolitan § bits » some assembly required ─╬─│┼ diff --git a/libc/calls/calls.h b/libc/calls/calls.h index 19e188607..20d0a80e8 100644 --- a/libc/calls/calls.h +++ b/libc/calls/calls.h @@ -5,6 +5,7 @@ #include "libc/calls/struct/rlimit.h" #include "libc/calls/struct/rusage.h" #include "libc/calls/struct/sigaction.h" +#include "libc/calls/struct/sigval.h" #include "libc/calls/struct/stat.h" #include "libc/calls/struct/sysinfo.h" #include "libc/calls/struct/timespec.h" @@ -120,6 +121,7 @@ int getrlimit(int, struct rlimit *); int getrusage(int, struct rusage *); int kill(int, int); int killpg(int, int); +int sigqueue(int, int, const union sigval); int link(const char *, const char *) nothrow; int linkat(int, const char *, int, const char *, uint32_t); int lstat(const char *, struct stat *); diff --git a/libc/calls/clock_gettime.c b/libc/calls/clock_gettime.c index 336fe2f13..e9e3e975c 100644 --- a/libc/calls/clock_gettime.c +++ b/libc/calls/clock_gettime.c @@ -30,14 +30,10 @@ * time. Among the more popular is CLOCK_MONOTONIC. This function has a * zero syscall implementation of that on modern x86. * - * @param clockid can be CLOCK_REALTIME, CLOCK_MONOTONIC, etc. noting - * that on Linux CLOCK_MONOTONIC is redefined to use the monotonic - * clock that's actually monotonic lool + * @param clockid can be CLOCK_REALTIME, CLOCK_MONOTONIC, etc. * @param ts is where the result is stored * @return 0 on success, or -1 w/ errno - * @error ENOSYS if clockid isn't available; in which case this function - * guarantees an ordinary timestamp is still stored to ts; and - * errno isn't restored to its original value, to detect prec. loss + * @error EINVAL if clockid isn't supported on this system * @see strftime(), gettimeofday() * @asyncsignalsafe */ @@ -46,6 +42,7 @@ int clock_gettime(int clockid, struct timespec *ts) { axdx_t ad; struct NtFileTime ft; if (!ts) return efault(); + if (clockid == -1) return einval(); if (!IsWindows()) { if ((rc = sys_clock_gettime(clockid, ts)) == -1 && errno == ENOSYS) { ad = sys_gettimeofday((struct timeval *)ts, NULL, NULL); diff --git a/libc/calls/getrusage-sysv.c b/libc/calls/getrusage-sysv.c new file mode 100644 index 000000000..4e3261c5e --- /dev/null +++ b/libc/calls/getrusage-sysv.c @@ -0,0 +1,35 @@ +/*-*- 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/calls/internal.h" +#include "libc/sysv/errfuns.h" + +/** + * Returns resource usage statistics. + * + * @param who can be RUSAGE_{SELF,CHILDREN,THREAD} + * @return 0 on success, or -1 w/ errno + */ +int sys_getrusage(int who, struct rusage *usage) { + int rc; + if ((rc = __sys_getrusage(who, usage)) != -1) { + __rusage2linux(usage); + } + return rc; +} diff --git a/libc/calls/internal.h b/libc/calls/internal.h index 32e057289..d523e8e44 100644 --- a/libc/calls/internal.h +++ b/libc/calls/internal.h @@ -4,7 +4,10 @@ #include "libc/calls/internal.h" #include "libc/calls/struct/iovec.h" #include "libc/calls/struct/itimerval.h" +#include "libc/calls/struct/rusage.h" #include "libc/calls/struct/sigaction-xnu.internal.h" +#include "libc/calls/struct/siginfo.h" +#include "libc/calls/struct/sigval.h" #include "libc/calls/struct/timespec.h" #include "libc/calls/struct/timeval.h" #include "libc/dce.h" @@ -108,9 +111,11 @@ i32 __sys_dup3(i32, i32, i32) hidden; i32 __sys_execve(const char *, char *const[], char *const[]) hidden; i32 __sys_fstat(i32, struct stat *) hidden; i32 __sys_fstatat(i32, const char *, struct stat *, i32) hidden; +i32 __sys_getrusage(i32, struct rusage *) hidden; i32 __sys_openat(i32, const char *, i32, u32) hidden; i32 __sys_pipe2(i32[hasatleast 2], u32) hidden; i32 __sys_utimensat(i32, const char *, const struct timespec *, i32) hidden; +i32 __sys_wait4(i32, i32 *, i32, struct rusage *) hidden; i32 getdents(i32, char *, u32, i64 *) hidden; i32 sys_chdir(const char *) hidden; i32 sys_clock_gettime(i32, struct timespec *) hidden; @@ -170,6 +175,8 @@ i32 sys_setrlimit(i32, const struct rlimit *) hidden; i32 sys_setsid(void) hidden; i32 sys_sigaction(i32, const void *, void *, i64, i64) hidden; i32 sys_sigprocmask(i32, const sigset *, sigset *, u64) hidden; +i32 sys_sigqueue(i32, i32, const union sigval) hidden; +i32 sys_sigqueueinfo(i32, const siginfo_t *) hidden; i32 sys_sigsuspend(const sigset *, u64) hidden; i32 sys_symlinkat(const char *, i32, const char *) hidden; i32 sys_sync(void) hidden; @@ -220,6 +227,7 @@ int gethostname_linux(char *, size_t) hidden; int gethostname_bsd(char *, size_t) hidden; int gethostname_nt(char *, size_t) hidden; size_t __iovec_size(const struct iovec *, size_t) hidden; +void __rusage2linux(struct rusage *) hidden; /*───────────────────────────────────────────────────────────────────────────│─╗ │ cosmopolitan § syscalls » windows nt » veneers ─╬─│┼ diff --git a/libc/calls/kill.c b/libc/calls/kill.c index f72bab6e4..26b9f0c84 100644 --- a/libc/calls/kill.c +++ b/libc/calls/kill.c @@ -33,7 +33,7 @@ * <-1 signals all processes in -pid process group * @param sig can be: * >0 can be SIGINT, SIGTERM, SIGKILL, SIGUSR1, etc. - * =0 is for error checking + * =0 checks both if pid exists and we can signal it * @return 0 if something was accomplished, or -1 w/ errno * @asyncsignalsafe */ diff --git a/libc/calls/mprotect.greg.c b/libc/calls/mprotect.greg.c index f2ff0b7fc..dedc7a909 100644 --- a/libc/calls/mprotect.greg.c +++ b/libc/calls/mprotect.greg.c @@ -39,12 +39,12 @@ privileged int mprotect(void *addr, uint64_t len, int prot) { int64_t rc; uint32_t oldprot; if (!IsWindows()) { - asm volatile(CFLAG_ASM("syscall") + asm volatile(CFLAG_ASM("clc\n\tsyscall") : CFLAG_CONSTRAINT(cf), "=a"(rc) : "1"(__NR_mprotect), "D"(addr), "S"(len), "d"(prot) : "rcx", "r11", "memory", "cc"); if (cf) { - rc = -rc; + errno = rc; rc = -1; } else if (rc > -4096ul) { errno = -rc; diff --git a/libc/calls/open-nt.c b/libc/calls/open-nt.c index b29e70871..819256869 100644 --- a/libc/calls/open-nt.c +++ b/libc/calls/open-nt.c @@ -47,14 +47,11 @@ static textwindows int64_t sys_open_nt_impl(int dirfd, const char *path, ? kNtFileShareExclusive : kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete, &kNtIsInheritable, - (flags & O_CREAT) && (flags & O_EXCL) - ? kNtCreateNew - : (flags & O_CREAT) && (flags & O_TRUNC) - ? kNtCreateAlways - : (flags & O_CREAT) - ? kNtOpenAlways - : (flags & O_TRUNC) ? kNtTruncateExisting - : kNtOpenExisting, + (flags & O_CREAT) && (flags & O_EXCL) ? kNtCreateNew + : (flags & O_CREAT) && (flags & O_TRUNC) ? kNtCreateAlways + : (flags & O_CREAT) ? kNtOpenAlways + : (flags & O_TRUNC) ? kNtTruncateExisting + : kNtOpenExisting, /* TODO(jart): Should we just always set overlapped? */ (/* note: content indexer demolishes unix-ey i/o performance */ kNtFileAttributeNotContentIndexed | kNtFileAttributeNormal | diff --git a/test/tool/build/lib/wut_test.c b/libc/calls/rusage2linux.c similarity index 83% rename from test/tool/build/lib/wut_test.c rename to libc/calls/rusage2linux.c index 1359316a0..855fd8dbe 100644 --- a/test/tool/build/lib/wut_test.c +++ b/libc/calls/rusage2linux.c @@ -1,7 +1,7 @@ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ ╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2020 Justine Alexandra Roberts Tunney │ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ @@ -16,16 +16,10 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/mem/mem.h" -#include "libc/str/str.h" -#include "libc/testlib/testlib.h" +#include "libc/calls/internal.h" -TEST(memcpy, testBackwardsOverlap3) { - volatile char *c; - c = malloc(3); - memcpy(c, "\e[C", 3); - memcpy(c, c + 1, VEIL("r", 3) - 1); - EXPECT_EQ('[', c[0]); - EXPECT_EQ('C', c[1]); - free(c); +void __rusage2linux(struct rusage *ru) { + if (IsXnu()) { + ru->ru_maxrss /= 1024; + } } diff --git a/libc/calls/sigaction.c b/libc/calls/sigaction.c index ac36db971..eeb16c371 100644 --- a/libc/calls/sigaction.c +++ b/libc/calls/sigaction.c @@ -39,6 +39,8 @@ #include "libc/sysv/consts/sig.h" #include "libc/sysv/errfuns.h" +#define SA_RESTORER 0x04000000 + #ifndef SWITCHEROO #define SWITCHEROO(S1, S2, A, B, C, D) \ do { \ diff --git a/libc/calls/sigqueue.c b/libc/calls/sigqueue.c new file mode 100644 index 000000000..d0171e66c --- /dev/null +++ b/libc/calls/sigqueue.c @@ -0,0 +1,59 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/calls/internal.h" +#include "libc/calls/struct/siginfo.h" +#include "libc/calls/struct/sigval.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/sicode.h" + +/* TODO(jart): XNU */ + +/** + * Sends signal to process, with data. + * + * The impact of this action can be terminating the process, or + * interrupting it to request something happen. + * + * @param pid can be: + * >0 signals one process by id + * =0 signals all processes in current process group + * -1 signals all processes possible (except init) + * <-1 signals all processes in -pid process group + * @param sig can be: + * >0 can be SIGINT, SIGTERM, SIGKILL, SIGUSR1, etc. + * =0 checks both if pid exists and we can signal it + * @return 0 if something was accomplished, or -1 w/ errno + * @note this isn't supported on OpenBSD + * @asyncsignalsafe + */ +int sigqueue(int pid, int sig, const union sigval value) { + siginfo_t info; + if (IsFreebsd()) { + return sys_sigqueue(pid, sig, value); + } else { + memset(&info, 0, sizeof(info)); + info.si_signo = sig; + info.si_code = SI_QUEUE; + info.si_pid = getpid(); + info.si_uid = geteuid(); + info.si_value = value; + return sys_sigqueueinfo(pid, &info); + } +} diff --git a/libc/calls/struct/rlimit.h b/libc/calls/struct/rlimit.h index a52e5cdc0..edbe0dfb5 100644 --- a/libc/calls/struct/rlimit.h +++ b/libc/calls/struct/rlimit.h @@ -3,8 +3,8 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) struct rlimit { - int64_t rlim_cur; - int64_t rlim_max; + uint64_t rlim_cur; /* current (soft) limit in bytes */ + uint64_t rlim_max; /* maximum limit in bytes */ }; #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/calls/struct/rusage.h b/libc/calls/struct/rusage.h index 32d3207ce..ed08ebc71 100644 --- a/libc/calls/struct/rusage.h +++ b/libc/calls/struct/rusage.h @@ -8,12 +8,12 @@ struct rusage { struct { struct timeval ru_utime; /* user CPU time used */ struct timeval ru_stime; /* system CPU time used */ - int64_t ru_maxrss; /* maximum resident set size */ - int64_t ru_ixrss; /* integral shared memory size */ - int64_t ru_idrss; /* integral unshared data size */ - int64_t ru_isrss; /* integral unshared stack size */ - int64_t ru_minflt; /* page reclaims (soft page faults) */ - int64_t ru_majflt; /* page faults (hard page faults) */ + int64_t ru_maxrss; /* maximum resident set size in (kb) */ + int64_t ru_ixrss; /* shared memory size (integral kb CLK_TCK) */ + int64_t ru_idrss; /* unshared data size (integral kb CLK_TCK) */ + int64_t ru_isrss; /* unshared stack size (integral kb CLK_TCK) */ + int64_t ru_minflt; /* page reclaims */ + int64_t ru_majflt; /* page faults */ int64_t ru_nswap; /* swaps */ int64_t ru_inblock; /* block input operations */ int64_t ru_oublock; /* block output operations */ diff --git a/libc/calls/struct/siginfo.h b/libc/calls/struct/siginfo.h index 72ca1d1d4..105ad24c5 100644 --- a/libc/calls/struct/siginfo.h +++ b/libc/calls/struct/siginfo.h @@ -6,7 +6,7 @@ struct siginfo { int32_t si_signo; int32_t si_errno; - int32_t si_code; + int32_t si_code; /* {SICODE,SEGV,ILL,FPE,POLL}_xxx */ union { struct { union { @@ -20,7 +20,7 @@ struct siginfo { }; }; union { - union sigval si_value; + union sigval si_value; /* provided by third arg of sigqueue(2) */ struct { int32_t si_status; int64_t si_utime, si_stime; diff --git a/libc/calls/wait4-sysv.c b/libc/calls/wait4-sysv.c new file mode 100644 index 000000000..7e1ebccf8 --- /dev/null +++ b/libc/calls/wait4-sysv.c @@ -0,0 +1,31 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/calls/internal.h" + +int sys_wait4(int pid, int *opt_out_wstatus, int options, + struct rusage *opt_out_rusage) { + int rc; + if ((rc = __sys_wait4(pid, opt_out_wstatus, options, opt_out_rusage)) != -1) { + if (opt_out_rusage) { + __rusage2linux(opt_out_rusage); + } + } + return rc; +} diff --git a/libc/calls/weirdtypes.h b/libc/calls/weirdtypes.h index f23cad207..bd7c7fe70 100644 --- a/libc/calls/weirdtypes.h +++ b/libc/calls/weirdtypes.h @@ -37,6 +37,7 @@ #define time_t int64_t #define timer_t void* #define uid_t uint32_t +#define rlim_t uint64_t /* int64_t on bsd */ #define int_fast8_t __INT_FAST8_TYPE__ #define uint_fast8_t __UINT_FAST8_TYPE__ diff --git a/libc/dce.h b/libc/dce.h index e100c4da0..73cde783f 100644 --- a/libc/dce.h +++ b/libc/dce.h @@ -45,12 +45,6 @@ #define IsTrustworthy() 0 #endif -#ifdef SECURITY_BLANKETS -#define UseSecurityBlankets() 1 -#else -#define UseSecurityBlankets() 0 -#endif - #ifdef TINY #define IsTiny() 1 #else diff --git a/libc/fmt/strerror_r.c b/libc/fmt/strerror_r.c index 4efb8b872..dbd893fc8 100644 --- a/libc/fmt/strerror_r.c +++ b/libc/fmt/strerror_r.c @@ -26,285 +26,153 @@ #include "libc/nt/runtime.h" #include "libc/str/str.h" -STATIC_YOINK("E2BIG"); -STATIC_YOINK("EACCES"); -STATIC_YOINK("EADDRINUSE"); -STATIC_YOINK("EADDRNOTAVAIL"); -STATIC_YOINK("EADV"); -STATIC_YOINK("EAFNOSUPPORT"); -STATIC_YOINK("EAGAIN"); -STATIC_YOINK("EALREADY"); -STATIC_YOINK("EBADE"); -STATIC_YOINK("EBADF"); -STATIC_YOINK("EBADFD"); -STATIC_YOINK("EBADMSG"); -STATIC_YOINK("EBADR"); -STATIC_YOINK("EBADRQC"); -STATIC_YOINK("EBADSLT"); -STATIC_YOINK("EBFONT"); -STATIC_YOINK("EBUSY"); -STATIC_YOINK("ECANCELED"); -STATIC_YOINK("ECHILD"); -STATIC_YOINK("ECHRNG"); -STATIC_YOINK("ECOMM"); -STATIC_YOINK("ECONNABORTED"); -STATIC_YOINK("ECONNREFUSED"); -STATIC_YOINK("ECONNRESET"); -STATIC_YOINK("EDEADLK"); -STATIC_YOINK("EDESTADDRREQ"); -STATIC_YOINK("EDOM"); -STATIC_YOINK("EDOTDOT"); -STATIC_YOINK("EDQUOT"); -STATIC_YOINK("EEXIST"); -STATIC_YOINK("EFAULT"); -STATIC_YOINK("EFBIG"); -STATIC_YOINK("EHOSTDOWN"); -STATIC_YOINK("EHOSTUNREACH"); -STATIC_YOINK("EHWPOISON"); -STATIC_YOINK("EIDRM"); -STATIC_YOINK("EILSEQ"); -STATIC_YOINK("EINPROGRESS"); -STATIC_YOINK("EINTR"); -STATIC_YOINK("EINVAL"); -STATIC_YOINK("EIO"); -STATIC_YOINK("EISCONN"); -STATIC_YOINK("EISDIR"); -STATIC_YOINK("EISNAM"); -STATIC_YOINK("EKEYEXPIRED"); -STATIC_YOINK("EKEYREJECTED"); -STATIC_YOINK("EKEYREVOKED"); -STATIC_YOINK("EL2HLT"); -STATIC_YOINK("EL2NSYNC"); -STATIC_YOINK("EL3HLT"); -STATIC_YOINK("EL3RST"); -STATIC_YOINK("ELIBACC"); -STATIC_YOINK("ELIBBAD"); -STATIC_YOINK("ELIBEXEC"); -STATIC_YOINK("ELIBMAX"); -STATIC_YOINK("ELIBSCN"); -STATIC_YOINK("ELNRNG"); -STATIC_YOINK("ELOOP"); -STATIC_YOINK("EMEDIUMTYPE"); -STATIC_YOINK("EMFILE"); -STATIC_YOINK("EMLINK"); -STATIC_YOINK("EMSGSIZE"); -STATIC_YOINK("EMULTIHOP"); -STATIC_YOINK("ENAMETOOLONG"); -STATIC_YOINK("ENAVAIL"); -STATIC_YOINK("ENETDOWN"); -STATIC_YOINK("ENETRESET"); -STATIC_YOINK("ENETUNREACH"); -STATIC_YOINK("ENFILE"); -STATIC_YOINK("ENOANO"); -STATIC_YOINK("ENOBUFS"); -STATIC_YOINK("ENOCSI"); -STATIC_YOINK("ENODATA"); -STATIC_YOINK("ENODEV"); -STATIC_YOINK("ENOENT"); -STATIC_YOINK("ENOEXEC"); -STATIC_YOINK("ENOKEY"); -STATIC_YOINK("ENOLCK"); -STATIC_YOINK("ENOLINK"); -STATIC_YOINK("ENOMEDIUM"); -STATIC_YOINK("ENOMEM"); -STATIC_YOINK("ENOMSG"); -STATIC_YOINK("ENONET"); -STATIC_YOINK("ENOPKG"); -STATIC_YOINK("ENOPROTOOPT"); -STATIC_YOINK("ENOSPC"); -STATIC_YOINK("ENOSR"); -STATIC_YOINK("ENOSTR"); -STATIC_YOINK("ENOSYS"); -STATIC_YOINK("ENOTBLK"); -STATIC_YOINK("ENOTCONN"); -STATIC_YOINK("ENOTDIR"); -STATIC_YOINK("ENOTEMPTY"); -STATIC_YOINK("ENOTNAM"); -STATIC_YOINK("ENOTRECOVERABLE"); -STATIC_YOINK("ENOTSOCK"); -STATIC_YOINK("ENOTSUP"); -STATIC_YOINK("ENOTTY"); -STATIC_YOINK("ENOTUNIQ"); -STATIC_YOINK("ENXIO"); -STATIC_YOINK("EOPNOTSUPP"); -STATIC_YOINK("EOVERFLOW"); -STATIC_YOINK("EOWNERDEAD"); -STATIC_YOINK("EPERM"); -STATIC_YOINK("EPFNOSUPPORT"); -STATIC_YOINK("EPIPE"); -STATIC_YOINK("EPROTO"); -STATIC_YOINK("EPROTONOSUPPORT"); -STATIC_YOINK("EPROTOTYPE"); -STATIC_YOINK("ERANGE"); -STATIC_YOINK("EREMCHG"); -STATIC_YOINK("EREMOTE"); -STATIC_YOINK("EREMOTEIO"); -STATIC_YOINK("ERESTART"); -STATIC_YOINK("ERFKILL"); -STATIC_YOINK("EROFS"); -STATIC_YOINK("ESHUTDOWN"); -STATIC_YOINK("ESOCKTNOSUPPORT"); -STATIC_YOINK("ESPIPE"); -STATIC_YOINK("ESRCH"); -STATIC_YOINK("ESRMNT"); -STATIC_YOINK("ESTALE"); -STATIC_YOINK("ESTRPIPE"); -STATIC_YOINK("ETIME"); -STATIC_YOINK("ETIMEDOUT"); -STATIC_YOINK("ETOOMANYREFS"); -STATIC_YOINK("ETXTBSY"); -STATIC_YOINK("EUCLEAN"); -STATIC_YOINK("EUNATCH"); -STATIC_YOINK("EUSERS"); -STATIC_YOINK("EXDEV"); -STATIC_YOINK("EXFULL"); +const struct Error { + const long *x; + const char *s; +} kErrors[] = { + {&ENOSYS, "ENOSYS"}, + {&EPERM, "EPERM"}, + {&ENOENT, "ENOENT"}, + {&ESRCH, "ESRCH"}, + {&EINTR, "EINTR"}, + {&EIO, "EIO"}, + {&ENXIO, "ENXIO"}, + {&E2BIG, "E2BIG"}, + {&ENOEXEC, "ENOEXEC"}, + {&EBADF, "EBADF"}, + {&ECHILD, "ECHILD"}, + {&EAGAIN, "EAGAIN"}, + {&ENOMEM, "ENOMEM"}, + {&EACCES, "EACCES"}, + {&EFAULT, "EFAULT"}, + {&ENOTBLK, "ENOTBLK"}, + {&EBUSY, "EBUSY"}, + {&EEXIST, "EEXIST"}, + {&EXDEV, "EXDEV"}, + {&ENODEV, "ENODEV"}, + {&ENOTDIR, "ENOTDIR"}, + {&EISDIR, "EISDIR"}, + {&EINVAL, "EINVAL"}, + {&ENFILE, "ENFILE"}, + {&EMFILE, "EMFILE"}, + {&ENOTTY, "ENOTTY"}, + {&ETXTBSY, "ETXTBSY"}, + {&EFBIG, "EFBIG"}, + {&ENOSPC, "ENOSPC"}, + {&EDQUOT, "EDQUOT"}, + {&ESPIPE, "ESPIPE"}, + {&EROFS, "EROFS"}, + {&EMLINK, "EMLINK"}, + {&EPIPE, "EPIPE"}, + {&EDOM, "EDOM"}, + {&ERANGE, "ERANGE"}, + {&EDEADLK, "EDEADLK"}, + {&ENAMETOOLONG, "ENAMETOOLONG"}, + {&ENOLCK, "ENOLCK"}, + {&ENOTEMPTY, "ENOTEMPTY"}, + {&ELOOP, "ELOOP"}, + {&ENOMSG, "ENOMSG"}, + {&EIDRM, "EIDRM"}, + {&ETIME, "ETIME"}, + {&EPROTO, "EPROTO"}, + {&EOVERFLOW, "EOVERFLOW"}, + {&EILSEQ, "EILSEQ"}, + {&EUSERS, "EUSERS"}, + {&ENOTSOCK, "ENOTSOCK"}, + {&EDESTADDRREQ, "EDESTADDRREQ"}, + {&EMSGSIZE, "EMSGSIZE"}, + {&EPROTOTYPE, "EPROTOTYPE"}, + {&ENOPROTOOPT, "ENOPROTOOPT"}, + {&EPROTONOSUPPORT, "EPROTONOSUPPORT"}, + {&ESOCKTNOSUPPORT, "ESOCKTNOSUPPORT"}, + {&ENOTSUP, "ENOTSUP"}, + {&EOPNOTSUPP, "EOPNOTSUPP"}, + {&EPFNOSUPPORT, "EPFNOSUPPORT"}, + {&EAFNOSUPPORT, "EAFNOSUPPORT"}, + {&EADDRINUSE, "EADDRINUSE"}, + {&EADDRNOTAVAIL, "EADDRNOTAVAIL"}, + {&ENETDOWN, "ENETDOWN"}, + {&ENETUNREACH, "ENETUNREACH"}, + {&ENETRESET, "ENETRESET"}, + {&ECONNABORTED, "ECONNABORTED"}, + {&ECONNRESET, "ECONNRESET"}, + {&ENOBUFS, "ENOBUFS"}, + {&EISCONN, "EISCONN"}, + {&ENOTCONN, "ENOTCONN"}, + {&ESHUTDOWN, "ESHUTDOWN"}, + {&ETOOMANYREFS, "ETOOMANYREFS"}, + {&ETIMEDOUT, "ETIMEDOUT"}, + {&ECONNREFUSED, "ECONNREFUSED"}, + {&EHOSTDOWN, "EHOSTDOWN"}, + {&EHOSTUNREACH, "EHOSTUNREACH"}, + {&EALREADY, "EALREADY"}, + {&EINPROGRESS, "EINPROGRESS"}, + {&ESTALE, "ESTALE"}, + {&EREMOTE, "EREMOTE"}, + {&EBADMSG, "EBADMSG"}, + {&ECANCELED, "ECANCELED"}, + {&EOWNERDEAD, "EOWNERDEAD"}, + {&ENOTRECOVERABLE, "ENOTRECOVERABLE"}, + {&ENONET, "ENONET"}, + {&ERESTART, "ERESTART"}, + {&ECHRNG, "ECHRNG"}, + {&EL2NSYNC, "EL2NSYNC"}, + {&EL3HLT, "EL3HLT"}, + {&EL3RST, "EL3RST"}, + {&ELNRNG, "ELNRNG"}, + {&EUNATCH, "EUNATCH"}, + {&ENOCSI, "ENOCSI"}, + {&EL2HLT, "EL2HLT"}, + {&EBADE, "EBADE"}, + {&EBADR, "EBADR"}, + {&EXFULL, "EXFULL"}, + {&ENOANO, "ENOANO"}, + {&EBADRQC, "EBADRQC"}, + {&EBADSLT, "EBADSLT"}, + {&ENOSTR, "ENOSTR"}, + {&ENODATA, "ENODATA"}, + {&ENOSR, "ENOSR"}, + {&ENOPKG, "ENOPKG"}, + {&ENOLINK, "ENOLINK"}, + {&EADV, "EADV"}, + {&ESRMNT, "ESRMNT"}, + {&ECOMM, "ECOMM"}, + {&EMULTIHOP, "EMULTIHOP"}, + {&EDOTDOT, "EDOTDOT"}, + {&ENOTUNIQ, "ENOTUNIQ"}, + {&EBADFD, "EBADFD"}, + {&EREMCHG, "EREMCHG"}, + {&ELIBACC, "ELIBACC"}, + {&ELIBBAD, "ELIBBAD"}, + {&ELIBSCN, "ELIBSCN"}, + {&ELIBMAX, "ELIBMAX"}, + {&ELIBEXEC, "ELIBEXEC"}, + {&ESTRPIPE, "ESTRPIPE"}, + {&EUCLEAN, "EUCLEAN"}, + {&ENOTNAM, "ENOTNAM"}, + {&ENAVAIL, "ENAVAIL"}, + {&EISNAM, "EISNAM"}, + {&EREMOTEIO, "EREMOTEIO"}, + {&ENOMEDIUM, "ENOMEDIUM"}, + {&EMEDIUMTYPE, "EMEDIUMTYPE"}, + {&ENOKEY, "ENOKEY"}, + {&EKEYEXPIRED, "EKEYEXPIRED"}, + {&EKEYREVOKED, "EKEYREVOKED"}, + {&EKEYREJECTED, "EKEYREJECTED"}, + {&ERFKILL, "ERFKILL"}, + {&EHWPOISON, "EHWPOISON"}, +}; -_Alignas(char) static const char kErrnoNames[] = "\ -2BIG\000\ -ACCES\000\ -ADDRINUSE\000\ -ADDRNOTAVAIL\000\ -ADV\000\ -AFNOSUPPORT\000\ -AGAIN\000\ -ALREADY\000\ -BADE\000\ -BADF\000\ -BADFD\000\ -BADMSG\000\ -BADR\000\ -BADRQC\000\ -BADSLT\000\ -BFONT\000\ -BUSY\000\ -CANCELED\000\ -CHILD\000\ -CHRNG\000\ -COMM\000\ -CONNABORTED\000\ -CONNREFUSED\000\ -CONNRESET\000\ -DEADLK\000\ -DESTADDRREQ\000\ -DOM\000\ -DOTDOT\000\ -DQUOT\000\ -EXIST\000\ -FAULT\000\ -FBIG\000\ -HOSTDOWN\000\ -HOSTUNREACH\000\ -HWPOISON\000\ -IDRM\000\ -ILSEQ\000\ -INPROGRESS\000\ -INTR\000\ -INVAL\000\ -IO\000\ -ISCONN\000\ -ISDIR\000\ -ISNAM\000\ -KEYEXPIRED\000\ -KEYREJECTED\000\ -KEYREVOKED\000\ -L2HLT\000\ -L2NSYNC\000\ -L3HLT\000\ -L3RST\000\ -LIBACC\000\ -LIBBAD\000\ -LIBEXEC\000\ -LIBMAX\000\ -LIBSCN\000\ -LNRNG\000\ -LOOP\000\ -MEDIUMTYPE\000\ -MFILE\000\ -MLINK\000\ -MSGSIZE\000\ -MULTIHOP\000\ -NAMETOOLONG\000\ -NAVAIL\000\ -NETDOWN\000\ -NETRESET\000\ -NETUNREACH\000\ -NFILE\000\ -NOANO\000\ -NOBUFS\000\ -NOCSI\000\ -NODATA\000\ -NODEV\000\ -NOENT\000\ -NOEXEC\000\ -NOKEY\000\ -NOLCK\000\ -NOLINK\000\ -NOMEDIUM\000\ -NOMEM\000\ -NOMSG\000\ -NONET\000\ -NOPKG\000\ -NOPROTOOPT\000\ -NOSPC\000\ -NOSR\000\ -NOSTR\000\ -NOSYS\000\ -NOTBLK\000\ -NOTCONN\000\ -NOTDIR\000\ -NOTEMPTY\000\ -NOTNAM\000\ -NOTRECOVERABLE\000\ -NOTSOCK\000\ -NOTSUP\000\ -NOTTY\000\ -NOTUNIQ\000\ -NXIO\000\ -OPNOTSUPP\000\ -OVERFLOW\000\ -OWNERDEAD\000\ -PERM\000\ -PFNOSUPPORT\000\ -PIPE\000\ -PROTO\000\ -PROTONOSUPPORT\000\ -PROTOTYPE\000\ -RANGE\000\ -REMCHG\000\ -REMOTE\000\ -REMOTEIO\000\ -RESTART\000\ -RFKILL\000\ -ROFS\000\ -SHUTDOWN\000\ -SOCKTNOSUPPORT\000\ -SPIPE\000\ -SRCH\000\ -SRMNT\000\ -STALE\000\ -STRPIPE\000\ -TIME\000\ -TIMEDOUT\000\ -TOOMANYREFS\000\ -TXTBSY\000\ -UCLEAN\000\ -UNATCH\000\ -USERS\000\ -XDEV\000\ -XFULL\000\ -\000"; - -static const char *geterrname(long code) { - const long *e; - size_t i, n; - e = &E2BIG; - n = &EXFULL + 1 - e; - for (i = 0; i < n; ++i) { - if (code == e[i]) { - return IndexDoubleNulString(kErrnoNames, i); +static const char *geterrname(long x) { + int i; + if (!IsTiny() && x) { + for (i = 0; i < ARRAYLEN(kErrors); ++i) { + if (x == *kErrors[i].x) { + return kErrors[i].s; + } } } - return NULL; + return "EUNKNOWN"; } /** @@ -315,13 +183,9 @@ int strerror_r(int err, char *buf, size_t size) { const char *s; char16_t buf16[100]; int winstate, sysvstate; - if (!err || IsTiny()) { - s = "?"; - } else { - s = firstnonnull(geterrname(err), "?"); - } + s = geterrname(err); if (!SupportsWindows()) { - (snprintf)(buf, size, "E%s[%d]", s, err); + (snprintf)(buf, size, "%s[%d]", s, err); } else { winstate = GetLastError(); sysvstate = errno; @@ -332,7 +196,7 @@ int strerror_r(int err, char *buf, size_t size) { } else { buf16[0] = u'\0'; } - (snprintf)(buf, size, "E%s/err=%d/errno:%d/GetLastError:%d%s%hs", s, err, + (snprintf)(buf, size, "%s/err=%d/errno:%d/GetLastError:%d%s%hs", s, err, sysvstate, winstate, buf16[0] ? " " : "", buf16); } return 0; diff --git a/libc/log/gdbexec.c b/libc/log/gdbexec.c index fc781f4ed..13a345c9c 100644 --- a/libc/log/gdbexec.c +++ b/libc/log/gdbexec.c @@ -28,7 +28,7 @@ /** * Attachs GDB temporarilly, to do something like print a variable. */ -int(gdbexec)(const char *cmd) { +privileged int(gdbexec)(const char *cmd) { struct StackFrame *bp; int pid, ttyin, ttyout; intptr_t continuetoaddr; diff --git a/libc/mem/reallocarray.c b/libc/mem/reallocarray.c index a7cb94c1b..0c1c5750b 100644 --- a/libc/mem/reallocarray.c +++ b/libc/mem/reallocarray.c @@ -16,6 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/errno.h" #include "libc/fmt/conv.h" #include "libc/mem/mem.h" @@ -27,5 +28,11 @@ * @return new address or NULL w/ errno and ptr is NOT free()'d */ void *reallocarray(void *ptr, size_t nmemb, size_t itemsize) { - return realloc(ptr, nmemb * itemsize); + size_t n; + if (!__builtin_mul_overflow(nmemb, itemsize, &n)) { + return realloc(ptr, n); + } else { + errno = ENOMEM; + return NULL; + } } diff --git a/libc/runtime/clktck.c b/libc/runtime/clktck.c new file mode 100644 index 000000000..8fe9f3fa6 --- /dev/null +++ b/libc/runtime/clktck.c @@ -0,0 +1,75 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/dce.h" +#include "libc/runtime/clktck.h" +#include "libc/sysv/consts/auxv.h" + +struct clockinfo_netbsd { + int32_t hz; // number of clock ticks per second + int32_t tick; // µs per tick + int32_t tickadj; // skew rate for adjtime() + int32_t stathz; // statistics clock frequency + int32_t profhz; // profiling clock frequency +}; + +static int clk_tck; + +static noinline int __clk_tck_init(void) { + int x; + int cmd[2]; + size_t len; + struct clockinfo_netbsd clock; + if (IsXnu() || IsOpenbsd()) { + x = 100; + } else if (IsFreebsd()) { + x = 128; + } else if (IsNetbsd()) { + cmd[0] = 1; // CTL_KERN + cmd[1] = 12; // KERN_CLOCKRATE + len = sizeof(clock); + if (sysctl(cmd, 2, &clock, &len, NULL, 0) != -1) { + x = clock.hz; + } else { + x = -1; + } + } else { + x = getauxval(AT_CLKTCK); + } + if (x < 1) x = 100; + clk_tck = x; + return x; +} + +/** + * Returns system clock ticks per second. + * + * The returned value is memoized. This function is intended to be + * used via the `CLK_TCK` macro wrapper. + * + * The returned value is always greater than zero. It's usually 100 + * hertz which means each clock tick is 10 milliseconds long. + */ +int __clk_tck(void) { + if (clk_tck) { + return clk_tck; + } else { + return __clk_tck_init(); + } +} diff --git a/libc/runtime/clktck.h b/libc/runtime/clktck.h new file mode 100644 index 000000000..3ab13648a --- /dev/null +++ b/libc/runtime/clktck.h @@ -0,0 +1,12 @@ +#ifndef COSMOPOLITAN_LIBC_RUNTIME_CLKTCK_H_ +#define COSMOPOLITAN_LIBC_RUNTIME_CLKTCK_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +#define CLK_TCK (__clk_tck()) + +int __clk_tck(void) pureconst; + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_RUNTIME_CLKTCK_H_ */ diff --git a/libc/runtime/mmap.c b/libc/runtime/mmap.c index 3992db5c1..0d507e953 100644 --- a/libc/runtime/mmap.c +++ b/libc/runtime/mmap.c @@ -59,8 +59,9 @@ */ void *mmap(void *addr, size_t size, int prot, int flags, int fd, int64_t off) { struct DirectMap dm; - int i, x, n, a, b, f; + int i, x, n, m, a, b, f; if (!size) return VIP(einval()); + if (size > 0x0000010000000000) return VIP(enomem()); if (!ALIGNED(off)) return VIP(einval()); if (!ALIGNED(addr)) return VIP(einval()); if (!CANONICAL(addr)) return VIP(einval()); @@ -77,6 +78,7 @@ void *mmap(void *addr, size_t size, int prot, int flags, int fd, int64_t off) { n = ROUNDUP(size, FRAMESIZE) >> 16; for (i = 0; i < _mmi.i; ++i) { if (_mmi.p[i].y < x) continue; + if (__builtin_add_overflow(_mmi.p[i].y, n, &m)) return VIP(enomem()); if (_mmi.p[i].x > x + n - 1) break; x = _mmi.p[i].y + 1; } diff --git a/libc/runtime/mremap-sysv.c b/libc/runtime/mremap-sysv.c new file mode 100644 index 000000000..76303f161 --- /dev/null +++ b/libc/runtime/mremap-sysv.c @@ -0,0 +1,55 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/bits.h" +#include "libc/calls/calls.h" +#include "libc/sysv/consts/map.h" +#include "libc/sysv/consts/mremap.h" +#include "libc/sysv/errfuns.h" + +privileged void *sys_mremap(void *p, size_t n, size_t m, int f, void *q) { + bool cf; + uintptr_t rax, rdi, rsi, rdx; + register uintptr_t r8 asm("r8"); + register uintptr_t r10 asm("r10"); + if (IsLinux()) { + r10 = f; + r8 = (uintptr_t)q; + asm("syscall" + : "=a"(rax) + : "0"(0x019), "D"(p), "S"(n), "d"(m), "r"(r10), "r"(r8) + : "rcx", "r11", "memory", "cc"); + if (rax > -4096ul) errno = -rax, rax = -1; + } else if (IsNetbsd()) { + if (f & MREMAP_MAYMOVE) { + rax = 0x19B; + r10 = m; + r8 = (f & MREMAP_FIXED) ? MAP_FIXED : 0; + asm(CFLAG_ASM("syscall") + : CFLAG_CONSTRAINT(cf), "+a"(rax) + : "D"(p), "S"(n), "d"(q), "r"(r10), "r"(r8) + : "rcx", "r11", "memory", "cc"); + if (cf) errno = rax, rax = -1; + } else { + rax = einval(); + } + } else { + rax = enosys(); + } + return (void *)rax; +} diff --git a/libc/runtime/mremap.c b/libc/runtime/mremap.c index cd4133c95..e7fbd0b5b 100644 --- a/libc/runtime/mremap.c +++ b/libc/runtime/mremap.c @@ -17,9 +17,46 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" +#include "libc/dce.h" +#include "libc/macros.internal.h" +#include "libc/sysv/consts/mremap.h" #include "libc/sysv/errfuns.h" -void *mremap(void *old_address, size_t old_size, size_t new_size, int flags, - void *new_address) { - return (void *)(intptr_t)enosys(); +#define IP(X) (intptr_t)(X) +#define VIP(X) (void *)IP(X) +#define ALIGNED(p) (!(IP(p) & (FRAMESIZE - 1))) + +/** + * Relocates mapping. + * + * @param p is old address + * @param n is old size + * @param m is new size + * @param f should have MREMAP_MAYMOVE and may have MAP_FIXED + * @param q is new address + */ +void *mremap(void *p, size_t n, size_t m, int f, ... /* void *q */) { + return VIP(enosys()); /* TODO: Implement Me! */ + void *q; + va_list va; + if (!IsWindows()) { + if (!n) return VIP(einval()); + if (!m) return VIP(einval()); + if (!ALIGNED(p)) return VIP(einval()); + n = ROUNDUP(n, FRAMESIZE); + m = ROUNDUP(m, FRAMESIZE); + if (f & MREMAP_FIXED) { + va_start(va, f); + q = va_arg(va, void *); + va_end(va); + if (!ALIGNED(q)) return VIP(einval()); + } else { + q = NULL; + if (!(f & MREMAP_MAYMOVE)) { + } + } + return VIP(enosys()); + } else { + return VIP(enosys()); + } } diff --git a/libc/runtime/openexecutable.S b/libc/runtime/openexecutable.S new file mode 100644 index 000000000..b3dde6bc1 --- /dev/null +++ b/libc/runtime/openexecutable.S @@ -0,0 +1,188 @@ +/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ +│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/dce.h" +#include "libc/macros.internal.h" +#include "libc/sysv/consts/auxv.h" +#include "libc/sysv/consts/prot.h" +.privileged + +// Opens executable in O_RDWR mode. +// +// To avoid ETXTBSY we need to unmap the running executable first, +// then open the file, and finally load the code back into memory. +// +// @return file descriptor +// @note only works on .com binary (not .com.dbg) +// @note only supports linux, freebsd, openbsd, and netbsd +OpenExecutable: + push %rbp + mov %rsp,%rbp + pushq __NR_open(%rip) # -0x08(%rbp) + pushq __NR_mmap(%rip) # -0x10(%rbp) + pushq __NR_munmap(%rip) # -0x18(%rbp) + pushq O_RDWR(%rip) # -0x20(%rbp) + pushq MAP_ANONYMOUS(%rip) # -0x28(%rbp) + pushq MAP_PRIVATE(%rip) # -0x30(%rbp) + pushq MAP_FIXED(%rip) # -0x38(%rbp) + pushq MAP_SHARED(%rip) # -0x40(%rbp) + push %rbx # code buffer + push %r12 # data buffer + push %r14 # filename + push %r15 # fd + +// Get filename. + mov AT_EXECFN,%edi + call getauxval + mov %rax,%r14 + +// Allocate code buffer. + mov -0x10(%rbp),%eax # __NR_mmap + xor %edi,%edi + mov $PAGESIZE,%esi + mov $PROT_READ|PROT_WRITE|PROT_EXEC,%edx + mov -0x28(%rbp),%r10d # MAP_ANONYMOUS + or -0x30(%rbp),%r10d # MAP_PRIVATE + mov $-1,%r8 + mov $0,%r9 + push %r9 # openbsd:pad + push %r9 # openbsd:align + syscall + pop %r9 + pop %r9 + mov %rax,%rbx + +// Allocate data buffer. + mov -0x10(%rbp),%eax # __NR_mmap + xor %edi,%edi + mov $ape_ram_filesz,%esi + mov $PROT_READ|PROT_WRITE,%edx + mov -0x28(%rbp),%r10d # MAP_ANONYMOUS + or -0x30(%rbp),%r10d # MAP_PRIVATE + mov $-1,%r8 + mov $0,%r9 + push %r9 # openbsd:pad + push %r9 # openbsd:align + syscall + pop %r9 + pop %r9 + mov %rax,%r12 + +// Move data. + mov %r12,%rdi + mov $ape_ram_vaddr,%esi + mov $ape_ram_filesz,%ecx + rep movsb + +// Move code. + mov %rbx,%rdi + mov $8f,%esi + mov $9f-8f,%ecx + rep movsb + jmp *%rbx + +// + +// Unmap code segment. +8: mov -0x18(%rbp),%eax # __NR_munmap + mov $ape_rom_vaddr,%edi + mov $ape_rom_filesz,%esi + syscall + +// Unmap data segment. + mov -0x18(%rbp),%eax # __NR_munmap + mov $ape_ram_vaddr,%edi + mov $ape_ram_filesz,%esi + syscall + +// Open executable in read-write mode. + mov -0x08(%rbp),%eax # __NR_open + mov %r14,%rdi + mov -0x20(%rbp),%esi # O_RDWR + syscall + mov %eax,%r15d + +// Map code segment. + mov -0x10(%rbp),%eax # __NR_mmap + mov $ape_rom_vaddr,%edi + mov $ape_rom_filesz,%esi + mov $PROT_READ|PROT_EXEC,%edx + mov -0x38(%rbp),%r10d # MAP_FIXED + or -0x40(%rbp),%r10d # MAP_SHARED + mov %r15d,%r8d + mov $ape_rom_offset,%r9d + push %r9 # openbsd:pad + push %r9 # openbsd:align + syscall + pop %r9 + pop %r9 + +// Allocate data segment. + mov -0x10(%rbp),%eax # __NR_mmap + mov $ape_ram_vaddr,%edi + mov $ape_ram_filesz,%esi + mov $PROT_READ|PROT_WRITE,%edx + mov -0x38(%rbp),%r10d # MAP_FIXED + or -0x30(%rbp),%r10d # MAP_PRIVATE + or -0x28(%rbp),%r10d # MAP_ANONYMOUS + mov $-1,%r8 + mov $0,%r9 + push %r9 # openbsd:pad + push %r9 # openbsd:align + syscall + pop %r9 + pop %r9 + +// Put data back. + mov $ape_ram_vaddr,%edi + xchg %eax,%esi + mov $ape_ram_filesz,%ecx + rep movsb + +// Jump back. + mov $9f,%eax + jmp *%rax + +// + +// Deallocate code buffer. +9: mov __NR_munmap,%eax + mov %rbx,%rdi + mov $PAGESIZE,%esi + syscall + +// Deallocate data buffer. + mov __NR_munmap,%eax + mov %r12,%rdi + mov $ape_ram_filesz,%esi + syscall + + mov %r15d,%eax + pop %r15 + pop %r14 + pop %r12 + pop %rbx + leave + ret +9: .endfn OpenExecutable,globl + + .weak ape_rom_vaddr + .weak ape_rom_filesz + .weak ape_rom_offset + .weak ape_ram_vaddr + .weak ape_ram_filesz diff --git a/libc/runtime/runtime.h b/libc/runtime/runtime.h index ef34b22ff..3cc0faed5 100644 --- a/libc/runtime/runtime.h +++ b/libc/runtime/runtime.h @@ -55,7 +55,7 @@ int clearenv(void); void fpreset(void); int issetugid(void); void *mmap(void *, uint64_t, int32_t, int32_t, int32_t, int64_t); -void *mremap(void *, uint64_t, uint64_t, int32_t, void *); +void *mremap(void *, size_t, size_t, int, ...); int munmap(void *, uint64_t); int mprotect(void *, uint64_t, int) privileged; int msync(void *, size_t, int); @@ -87,6 +87,7 @@ void _savexmm(void *); void _weakfree(void *); void free_s(void *) paramsnonnull() libcesque; int close_s(int *) paramsnonnull() libcesque; +int OpenExecutable(void); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/runtime/sysconf.c b/libc/runtime/sysconf.c index fbfc8fbf8..3fd5699aa 100644 --- a/libc/runtime/sysconf.c +++ b/libc/runtime/sysconf.c @@ -16,10 +16,32 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/runtime/clktck.h" #include "libc/runtime/sysconf.h" /** * Returns configuration value about system. - * @param thing can be _SC_XXX + * + * The following parameters are supported: + * + * - `_SC_CLK_TCK` returns number of clock ticks per second + * - `_SC_ARG_MAX` currently always returns 32768 due to Windows + * - `_SC_PAGESIZE` currently always returns 65536 due to Windows + * + * You are encouraged to undiamond calls to this API as follows: + * + * - Use `CLK_TCK` instead of `getconf(_SC_CLK_TCK)` + * - Use `PAGESIZE` or `FRAMESIZE` instead of `getconf(_SC_PAGESIZE)` */ -long(sysconf)(int thing) { return __sysconf(thing); } +long sysconf(int name) { + switch (name) { + case _SC_ARG_MAX: + return ARG_MAX; + case _SC_CLK_TCK: + return CLK_TCK; + case _SC_PAGESIZE: + return FRAMESIZE; + default: + return -1; + } +} diff --git a/libc/runtime/sysconf.h b/libc/runtime/sysconf.h index 0afd83eaf..465ece060 100644 --- a/libc/runtime/sysconf.h +++ b/libc/runtime/sysconf.h @@ -1,7 +1,5 @@ #ifndef COSMOPOLITAN_LIBC_RUNTIME_SYSCONF_H_ #define COSMOPOLITAN_LIBC_RUNTIME_SYSCONF_H_ -#include "libc/runtime/runtime.h" -#include "libc/sysv/consts/auxv.h" #define _SC_ARG_MAX 0 #define _SC_CLK_TCK 2 @@ -13,26 +11,6 @@ COSMOPOLITAN_C_START_ long sysconf(int); -#if defined(__GNUC__) && !defined(__STRICT_ANSI__) -#define sysconf(X) __sysconf(X) -forceinline long __sysconf(int thing) { - switch (thing) { - case _SC_ARG_MAX: - return ARG_MAX; - case _SC_CLK_TCK: { - extern const long __AT_CLKTCK asm("AT_CLKTCK"); - long res = getauxval(__AT_CLKTCK); - if (!res) res = 100; - return res; - } - case _SC_PAGESIZE: - return FRAMESIZE; - default: - return -1; - } -} -#endif /* GNU && !ANSI */ - COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_LIBC_RUNTIME_SYSCONF_H_ */ diff --git a/libc/runtime/winmain.greg.c b/libc/runtime/winmain.greg.c index 77844de97..2adfc81f7 100644 --- a/libc/runtime/winmain.greg.c +++ b/libc/runtime/winmain.greg.c @@ -160,17 +160,15 @@ static noasan textwindows wontreturn void WinMainNew(void) { * able to assume that stack addresses are located at higher * addresses than heap and program memory. * - * 5. Windows users are afraid of "drive-by downloads" where someone - * might accidentally an evil DLL to their Downloads folder which - * then overrides the behavior of a legitimate EXE being run from - * the downloads folder. Since we don't even use dynamic linking, - * we've cargo culted some API calls, that may harden against it. + * 5. Reconfigure x87 FPU so long double is actually long (80 bits). * - * 6. Reconfigure x87 FPU so long double is actually long (80 bits). - * - * 7. Finally, we need fork. Microsoft designed Windows to prevent us - * from having fork() so we pass pipe handles in an environment - * variable literally copy all the memory. + * 6. Finally, we need fork. Since disagreeing with fork is axiomatic to + * Microsoft's engineering culture, we need to go to great lengths to + * have it anyway without breaking Microsoft's rules: using the WIN32 + * API (i.e. not NTDLL) to copy MAP_PRIVATE pages via a pipe. It'd go + * faster if the COW pages CreateFileMappingNuma claims to have turns + * out to be true. Until then we have a "PC Scale" and entirely legal + * workaround that they hopefully won't block using Windows Defender. * * @param hInstance call GetModuleHandle(NULL) from main if you need it */ diff --git a/libc/stdio/system.c b/libc/stdio/system.c index ef58b0fc3..dd1fee19b 100644 --- a/libc/stdio/system.c +++ b/libc/stdio/system.c @@ -42,7 +42,7 @@ int system(const char *cmdline) { struct sigaction ignore, saveint, savequit; if (!cmdline) { if (IsWindows()) return 1; - if (access(_PATH_BSHELL, X_OK) == 0) return 1; + if (!access(_PATH_BSHELL, X_OK)) return 1; return 0; } ignore.sa_flags = 0; @@ -54,13 +54,13 @@ int system(const char *cmdline) { sigaddset(&chldmask, SIGCHLD); sigprocmask(SIG_BLOCK, &chldmask, &savemask); if (!(pid = fork())) { - sigaction(SIGINT, &saveint, NULL); - sigaction(SIGQUIT, &savequit, NULL); - sigprocmask(SIG_SETMASK, &savemask, NULL); + sigaction(SIGINT, &saveint, 0); + sigaction(SIGQUIT, &savequit, 0); + sigprocmask(SIG_SETMASK, &savemask, 0); systemexec(cmdline); _exit(127); } else if (pid != -1) { - while (wait4(pid, &wstatus, 0, NULL) == -1) { + while (wait4(pid, &wstatus, 0, 0) == -1) { if (errno != EINTR) { wstatus = -1; break; @@ -69,8 +69,8 @@ int system(const char *cmdline) { } else { wstatus = -1; } - sigaction(SIGINT, &saveint, NULL); - sigaction(SIGQUIT, &savequit, NULL); - sigprocmask(SIG_SETMASK, &savemask, NULL); + sigaction(SIGINT, &saveint, 0); + sigaction(SIGQUIT, &savequit, 0); + sigprocmask(SIG_SETMASK, &savemask, 0); return wstatus; } diff --git a/libc/stdio/systemexec.c b/libc/stdio/systemexec.c index cb9b3fd76..70134991a 100644 --- a/libc/stdio/systemexec.c +++ b/libc/stdio/systemexec.c @@ -20,19 +20,28 @@ #include "libc/dce.h" #include "libc/paths.h" #include "libc/runtime/runtime.h" -#include "libc/stdio/stdio.h" #include "libc/str/str.h" +#include "libc/sysv/errfuns.h" /** * Executes system command replacing current process. * @vforksafe */ int systemexec(const char *cmdline) { - char comspec[128]; - const char *prog, *arg; - strcpy(comspec, kNtSystemDirectory); - strcat(comspec, "cmd.exe"); - prog = !IsWindows() ? _PATH_BSHELL : comspec; - arg = !IsWindows() ? "-c" : "/C"; - return execv(prog, (char *const[]){prog, arg, cmdline, NULL}); + size_t n, m; + char *a, *b, *argv[4], comspec[PATH_MAX + 1]; + if (!IsWindows()) { + argv[0] = _PATH_BSHELL; + argv[1] = "-c"; + } else { + b = "cmd.exe"; + a = kNtSystemDirectory; + if ((n = strlen(a)) + (m = strlen(b)) > PATH_MAX) return enametoolong(); + memcpy(mempcpy(comspec, a, n), b, m + 1); + argv[0] = comspec; + argv[1] = "/C"; + } + argv[2] = cmdline; + argv[3] = NULL; + return execv(argv[0], argv); } diff --git a/libc/str/getzipcdir.c b/libc/str/getzipcdir.c new file mode 100644 index 000000000..18d1d956e --- /dev/null +++ b/libc/str/getzipcdir.c @@ -0,0 +1,53 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/zip.h" + +/** + * Locates End Of Central Directory record in ZIP file. + * + * The ZIP spec says this header can be anywhere in the last 64kb. + * We search it backwards for the ZIP-64 "PK♠♠" magic number. If that's + * not found, then we search again for the original "PK♣♠" magnum. The + * caller needs to check the first four bytes of the returned value to + * determine whether to use ZIP_CDIR_xxx() or ZIP_CDIR64_xxx() macros. + * + * @param p points to file memory + * @param n is byte size of file + * @return pointer to EOCD64 or EOCD, or NULL if not found + */ +uint8_t *GetZipCdir(const uint8_t *p, size_t n) { + size_t i, j; + if (n >= kZipCdirHdrMinSize) { + i = n - kZipCdirHdrMinSize; + do { + if (READ32LE(p + i) == kZipCdir64HdrMagic && IsZipCdir64(p, n, i)) { + return (/*unconst*/ uint8_t *)(p + i); + } else if (READ32LE(p + i) == kZipCdirHdrMagic && IsZipCdir32(p, n, i)) { + j = i; + do { + if (READ32LE(p + j) == kZipCdir64HdrMagic && IsZipCdir64(p, n, j)) { + return (/*unconst*/ uint8_t *)(p + j); + } + } while (j-- && i - j < 64 * 1024); + return (/*unconst*/ uint8_t *)(p + i); + } + } while (i--); + } + return NULL; +} diff --git a/libc/str/getzipcdiroffset.c b/libc/str/getzipcdiroffset.c new file mode 100644 index 000000000..c50ff6d7a --- /dev/null +++ b/libc/str/getzipcdiroffset.c @@ -0,0 +1,30 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/zip.h" + +/** + * Returns offset of zip central directory. + */ +uint64_t GetZipCdirOffset(const uint8_t *eocd) { + if (READ32LE(eocd) == kZipCdir64HdrMagic) { + return ZIP_CDIR64_OFFSET(eocd); + } else { + return ZIP_CDIR_OFFSET(eocd); + } +} diff --git a/libc/str/getzipcdirrecords.c b/libc/str/getzipcdirrecords.c new file mode 100644 index 000000000..722bd31d8 --- /dev/null +++ b/libc/str/getzipcdirrecords.c @@ -0,0 +1,30 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/zip.h" + +/** + * Returns number of records in zip central directory. + */ +uint64_t GetZipCdirRecords(const uint8_t *eocd) { + if (READ32LE(eocd) == kZipCdir64HdrMagic) { + return ZIP_CDIR64_RECORDS(eocd); + } else { + return ZIP_CDIR_RECORDS(eocd); + } +} diff --git a/libc/str/getzipcfilecompressedsize.c b/libc/str/getzipcfilecompressedsize.c new file mode 100644 index 000000000..9391bcce7 --- /dev/null +++ b/libc/str/getzipcfilecompressedsize.c @@ -0,0 +1,37 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/zip.h" + +/** + * Returns compressed size in bytes from zip central directory header. + */ +uint64_t GetZipCfileCompressedSize(const uint8_t *z) { + uint64_t x; + const uint8_t *p, *pe; + if ((x = ZIP_CFILE_COMPRESSEDSIZE(z)) == 0xFFFFFFFF) { + for (p = ZIP_CFILE_EXTRA(z), pe = p + ZIP_CFILE_EXTRASIZE(z); p < pe; + p += ZIP_EXTRA_SIZE(p)) { + if (ZIP_EXTRA_HEADERID(p) == kZipExtraZip64 && + 8 + 8 <= ZIP_EXTRA_CONTENTSIZE(p)) { + return READ64LE(ZIP_EXTRA_CONTENT(p) + 8); + } + } + } + return x; +} diff --git a/libc/str/getzipcfilemode.c b/libc/str/getzipcfilemode.c new file mode 100644 index 000000000..7a51b551d --- /dev/null +++ b/libc/str/getzipcfilemode.c @@ -0,0 +1,47 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/nt/enum/fileflagandattributes.h" +#include "libc/sysv/consts/s.h" +#include "libc/zip.h" + +static int ConvertWindowsToUnixMode(int x) { + int m; + if (x & kNtFileAttributeReadonly) { + m = 0444; + } else { + m = 0644; + } + if (x & kNtFileAttributeDirectory) { + m |= S_IFDIR | 0111; + } else { + m |= S_IFREG; + } + return m; +} + +/** + * Returns st_mode from ZIP central directory record. + */ +int GetZipCfileMode(const uint8_t *p) { + if (ZIP_CFILE_FILEATTRCOMPAT(p) == kZipOsUnix) { + return ZIP_CFILE_EXTERNALATTRIBUTES(p) >> 16; + } else { + return ConvertWindowsToUnixMode(ZIP_CFILE_EXTERNALATTRIBUTES(p)); + } +} diff --git a/libc/str/getzipcfileoffset.c b/libc/str/getzipcfileoffset.c new file mode 100644 index 000000000..59f519fb3 --- /dev/null +++ b/libc/str/getzipcfileoffset.c @@ -0,0 +1,37 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/zip.h" + +/** + * Returns offset of local file header. + */ +uint64_t GetZipCfileOffset(const uint8_t *z) { + uint64_t x; + const uint8_t *p, *pe; + if ((x = ZIP_CFILE_OFFSET(z)) == 0xFFFFFFFF) { + for (p = ZIP_CFILE_EXTRA(z), pe = p + ZIP_CFILE_EXTRASIZE(z); p < pe; + p += ZIP_EXTRA_SIZE(p)) { + if (ZIP_EXTRA_HEADERID(p) == kZipExtraZip64 && + 16 + 8 <= ZIP_EXTRA_CONTENTSIZE(p)) { + return READ64LE(ZIP_EXTRA_CONTENT(p) + 16); + } + } + } + return x; +} diff --git a/libc/str/getzipcfileuncompressedsize.c b/libc/str/getzipcfileuncompressedsize.c new file mode 100644 index 000000000..0db56764b --- /dev/null +++ b/libc/str/getzipcfileuncompressedsize.c @@ -0,0 +1,37 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/zip.h" + +/** + * Returns uncompressed size in bytes from zip central directory header. + */ +uint64_t GetZipCfileUncompressedSize(const uint8_t *z) { + uint64_t x; + const uint8_t *p, *pe; + if ((x = ZIP_CFILE_UNCOMPRESSEDSIZE(z)) == 0xFFFFFFFF) { + for (p = ZIP_CFILE_EXTRA(z), pe = p + ZIP_CFILE_EXTRASIZE(z); p < pe; + p += ZIP_EXTRA_SIZE(p)) { + if (ZIP_EXTRA_HEADERID(p) == kZipExtraZip64 && + 0 + 8 <= ZIP_EXTRA_CONTENTSIZE(p)) { + return READ64LE(ZIP_EXTRA_CONTENT(p) + 0); + } + } + } + return x; +} diff --git a/libc/str/getziplfilecompressedsize.c b/libc/str/getziplfilecompressedsize.c new file mode 100644 index 000000000..e2b978333 --- /dev/null +++ b/libc/str/getziplfilecompressedsize.c @@ -0,0 +1,37 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/zip.h" + +/** + * Returns compressed size in bytes from zip local file header. + */ +uint64_t GetZipLfileCompressedSize(const uint8_t *z) { + uint64_t x; + const uint8_t *p, *pe; + if ((x = ZIP_LFILE_COMPRESSEDSIZE(z)) == 0xFFFFFFFF) { + for (p = ZIP_LFILE_EXTRA(z), pe = p + ZIP_LFILE_EXTRASIZE(z); p < pe; + p += ZIP_EXTRA_SIZE(p)) { + if (ZIP_EXTRA_HEADERID(p) == kZipExtraZip64 && + 8 + 8 <= ZIP_EXTRA_CONTENTSIZE(p)) { + return READ64LE(ZIP_EXTRA_CONTENT(p) + 8); + } + } + } + return x; +} diff --git a/libc/str/getziplfileuncompressedsize.c b/libc/str/getziplfileuncompressedsize.c new file mode 100644 index 000000000..2afb9deea --- /dev/null +++ b/libc/str/getziplfileuncompressedsize.c @@ -0,0 +1,38 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/zip.h" + +/** + * Returns uncompressed size in bytes from zip local file header. + */ +uint64_t GetZipLfileUncompressedSize(const uint8_t *z) { + uint64_t x; + const uint8_t *p, *pe; + x = ZIP_LFILE_UNCOMPRESSEDSIZE(z); + if (x == 0xFFFFFFFF) { + for (p = ZIP_LFILE_EXTRA(z), pe = p + ZIP_LFILE_EXTRASIZE(z); p < pe; + p += ZIP_EXTRA_SIZE(p)) { + if (ZIP_EXTRA_HEADERID(p) == kZipExtraZip64 && + 0 + 8 <= ZIP_EXTRA_CONTENTSIZE(p)) { + return READ64LE(ZIP_EXTRA_CONTENT(p) + 0); + } + } + } + return x; +} diff --git a/libc/str/iszipcdir32.c b/libc/str/iszipcdir32.c new file mode 100644 index 000000000..27382a230 --- /dev/null +++ b/libc/str/iszipcdir32.c @@ -0,0 +1,38 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/bits.h" +#include "libc/zip.h" + +/** + * Returns true if zip end of central directory header seems legit. + */ +bool IsZipCdir32(const uint8_t *p, size_t n, size_t i) { + if (i > n || n - i < kZipCdirHdrMinSize) return false; + if (READ32LE(p + i) != kZipCdirHdrMagic) return false; + if (i + ZIP_CDIR_HDRSIZE(p + i) > n) return false; + if (ZIP_CDIR_DISK(p + i) != ZIP_CDIR_STARTINGDISK(p + i)) return false; + if (ZIP_CDIR_RECORDSONDISK(p + i) != ZIP_CDIR_RECORDS(p + i)) return false; + if (ZIP_CDIR_RECORDS(p + i) * kZipCfileHdrMinSize > ZIP_CDIR_SIZE(p + i)) { + return false; + } + if (ZIP_CDIR_OFFSET(p + i) + ZIP_CDIR_SIZE(p + i) > i) { + return false; + } + return true; +} diff --git a/libc/str/iszipcdir64.c b/libc/str/iszipcdir64.c new file mode 100644 index 000000000..ca18dcee2 --- /dev/null +++ b/libc/str/iszipcdir64.c @@ -0,0 +1,41 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/bits.h" +#include "libc/zip.h" + +/** + * Returns true if zip64 end of central directory header seems legit. + */ +bool IsZipCdir64(const uint8_t *p, size_t n, size_t i) { + if (i > n || n - i < kZipCdir64HdrMinSize) return false; + if (READ32LE(p + i) != kZipCdir64HdrMagic) return false; + if (i + ZIP_CDIR64_HDRSIZE(p + i) > n) return false; + if (ZIP_CDIR64_DISK(p + i) != ZIP_CDIR64_STARTINGDISK(p + i)) return false; + if (ZIP_CDIR64_RECORDSONDISK(p + i) != ZIP_CDIR64_RECORDS(p + i)) { + return false; + } + if (ZIP_CDIR64_RECORDS(p + i) * kZipCfileHdrMinSize > + ZIP_CDIR64_SIZE(p + i)) { + return false; + } + if (ZIP_CDIR64_OFFSET(p + i) + ZIP_CDIR64_SIZE(p + i) > i) { + return false; + } + return true; +} diff --git a/libc/str/memccpy.c b/libc/str/memccpy.c index adcd21eec..708a85fe5 100644 --- a/libc/str/memccpy.c +++ b/libc/str/memccpy.c @@ -16,12 +16,14 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/bits.h" #include "libc/str/str.h" static inline noasan uint64_t UncheckedAlignedRead64(unsigned char *p) { - return (uint64_t)p[7] << 070 | (uint64_t)p[6] << 060 | (uint64_t)p[5] << 050 | - (uint64_t)p[4] << 040 | (uint64_t)p[3] << 030 | (uint64_t)p[2] << 020 | - (uint64_t)p[1] << 010 | (uint64_t)p[0] << 000; + return (uint64_t)(255 & p[7]) << 070 | (uint64_t)(255 & p[6]) << 060 | + (uint64_t)(255 & p[5]) << 050 | (uint64_t)(255 & p[4]) << 040 | + (uint64_t)(255 & p[3]) << 030 | (uint64_t)(255 & p[2]) << 020 | + (uint64_t)(255 & p[1]) << 010 | (uint64_t)(255 & p[0]) << 000; } /** diff --git a/libc/str/strcasecmp16.c b/libc/str/strcasecmp16.c index 663265ba6..5f3869e69 100644 --- a/libc/str/strcasecmp16.c +++ b/libc/str/strcasecmp16.c @@ -29,6 +29,6 @@ int strcasecmp16(const char16_t *l, const char16_t *r) { int x, y; size_t i = 0; - while ((x = tolower(l[i])) == (y = tolower(r[i])) && r[i]) ++i; + while ((x = towlower(l[i])) == (y = towlower(r[i])) && r[i]) ++i; return x - y; } diff --git a/libc/str/strchrnul.c b/libc/str/strchrnul.c index 09c4f738b..cde51302f 100644 --- a/libc/str/strchrnul.c +++ b/libc/str/strchrnul.c @@ -19,14 +19,14 @@ #include "libc/assert.h" #include "libc/str/str.h" -noasan static const unsigned char *strchrnul_x64(const unsigned char *p, - uint64_t c) { +noasan static const char *strchrnul_x64(const char *p, uint64_t c) { unsigned a, b; uint64_t w, x, y; for (c *= 0x0101010101010101;; p += 8) { - w = (uint64_t)p[7] << 070 | (uint64_t)p[6] << 060 | (uint64_t)p[5] << 050 | - (uint64_t)p[4] << 040 | (uint64_t)p[3] << 030 | (uint64_t)p[2] << 020 | - (uint64_t)p[1] << 010 | (uint64_t)p[0] << 000; + w = (uint64_t)(255 & p[7]) << 070 | (uint64_t)(255 & p[6]) << 060 | + (uint64_t)(255 & p[5]) << 050 | (uint64_t)(255 & p[4]) << 040 | + (uint64_t)(255 & p[3]) << 030 | (uint64_t)(255 & p[2]) << 020 | + (uint64_t)(255 & p[1]) << 010 | (uint64_t)(255 & p[0]) << 000; if ((x = ~(w ^ c) & ((w ^ c) - 0x0101010101010101) & 0x8080808080808080) | (y = ~w & (w - 0x0101010101010101) & 0x8080808080808080)) { if (x) { @@ -59,11 +59,11 @@ noasan static const unsigned char *strchrnul_x64(const unsigned char *p, */ char *strchrnul(const char *s, int c) { char *r; - for (c &= 0xff; (uintptr_t)s & 7; ++s) { + for (c &= 255; (uintptr_t)s & 7; ++s) { if ((*s & 0xff) == c) return s; if (!*s) return s; } - r = (char *)strchrnul_x64((const unsigned char *)s, c); - assert((*r & 0xff) == c || !*r); + r = strchrnul_x64(s, c); + assert((*r & 255) == c || !*r); return r; } diff --git a/libc/str/strcmp.c b/libc/str/strcmp.c index 53cc44cf5..0917ecac2 100644 --- a/libc/str/strcmp.c +++ b/libc/str/strcmp.c @@ -18,10 +18,11 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" -static inline noasan uint64_t UncheckedAlignedRead64(unsigned char *p) { - return (uint64_t)p[7] << 070 | (uint64_t)p[6] << 060 | (uint64_t)p[5] << 050 | - (uint64_t)p[4] << 040 | (uint64_t)p[3] << 030 | (uint64_t)p[2] << 020 | - (uint64_t)p[1] << 010 | (uint64_t)p[0] << 000; +static inline noasan uint64_t UncheckedAlignedRead64(const char *p) { + return (uint64_t)(255 & p[7]) << 070 | (uint64_t)(255 & p[6]) << 060 | + (uint64_t)(255 & p[5]) << 050 | (uint64_t)(255 & p[4]) << 040 | + (uint64_t)(255 & p[3]) << 030 | (uint64_t)(255 & p[2]) << 020 | + (uint64_t)(255 & p[1]) << 010 | (uint64_t)(255 & p[0]) << 000; } /** diff --git a/libc/str/strlen-pure.c b/libc/str/strlen-pure.c index 6df045f16..8463fce55 100644 --- a/libc/str/strlen-pure.c +++ b/libc/str/strlen-pure.c @@ -17,20 +17,15 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" +#include "libc/bits/bits.h" #include "libc/str/str.h" static noasan size_t strlen_pure_x64(const char *s, size_t i) { uint64_t w; - const unsigned char *p; - for (;;) { - p = (const unsigned char *)s + i; - w = (uint64_t)p[7] << 070 | (uint64_t)p[6] << 060 | (uint64_t)p[5] << 050 | - (uint64_t)p[4] << 040 | (uint64_t)p[3] << 030 | (uint64_t)p[2] << 020 | - (uint64_t)p[1] << 010 | (uint64_t)p[0] << 000; + for (;; i += 8) { + w = READ64LE(s + i); if ((w = ~w & (w - 0x0101010101010101) & 0x8080808080808080)) { return i + ((unsigned)__builtin_ctzll(w) >> 3); - } else { - i += 8; } } } diff --git a/libc/str/strnlen.c b/libc/str/strnlen.c index 61b326f18..f07286a36 100644 --- a/libc/str/strnlen.c +++ b/libc/str/strnlen.c @@ -17,16 +17,13 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" +#include "libc/bits/bits.h" #include "libc/str/str.h" static noasan size_t strnlen_x64(const char *s, size_t n, size_t i) { uint64_t w; - const unsigned char *p; for (; i + 8 < n; i += 8) { - p = (const unsigned char *)s + i; - w = (uint64_t)p[7] << 070 | (uint64_t)p[6] << 060 | (uint64_t)p[5] << 050 | - (uint64_t)p[4] << 040 | (uint64_t)p[3] << 030 | (uint64_t)p[2] << 020 | - (uint64_t)p[1] << 010 | (uint64_t)p[0] << 000; + w = READ64LE(s + i); if ((w = ~w & (w - 0x0101010101010101) & 0x8080808080808080)) { i += (unsigned)__builtin_ctzll(w) >> 3; break; diff --git a/libc/str/tprecode8to16.c b/libc/str/tprecode8to16.c index 7d9956659..f06e7d104 100644 --- a/libc/str/tprecode8to16.c +++ b/libc/str/tprecode8to16.c @@ -25,8 +25,8 @@ #include "libc/str/utf16.h" /* 34x speedup for ascii */ -static noasan axdx_t tprecode8to16_sse2(char16_t *dst, size_t dstsize, - const char *src, axdx_t r) { +static inline noasan axdx_t tprecode8to16_sse2(char16_t *dst, size_t dstsize, + const char *src, axdx_t r) { uint8_t v1[16], v2[16], vz[16]; memset(vz, 0, 16); while (r.ax + 16 < dstsize) { @@ -54,26 +54,25 @@ static noasan axdx_t tprecode8to16_sse2(char16_t *dst, size_t dstsize, */ axdx_t tprecode8to16(char16_t *dst, size_t dstsize, const char *src) { axdx_t r; - unsigned n; - uint64_t w; - wint_t x, y; + unsigned w; + int x, y, a, b, i, n; r.ax = 0; r.dx = 0; for (;;) { - /* TODO(jart): Why is it now so much slower refactored? */ - /* if (!IsTiny() && !((uintptr_t)(src + r.dx) & 15)) { */ - /* tprecode8to16_sse2(dst, dstsize, src, r); */ - /* } */ - x = src[r.dx++] & 0xff; - if (ThomPikeCont(x)) continue; - if (!isascii(x)) { - n = ThomPikeLen(x); - x = ThomPikeByte(x); - while (--n) { - if ((y = src[r.dx++] & 0xff)) { - x = ThomPikeMerge(x, y); - } else { - x = 0; + if (!IsTiny() && !((uintptr_t)(src + r.dx) & 15)) { + r = tprecode8to16_sse2(dst, dstsize, src, r); + } + x = src[r.dx++] & 0377; + if (x >= 0300) { + a = ThomPikeByte(x); + n = ThomPikeLen(x) - 1; + for (i = 0;;) { + if (!(b = src[r.dx + i] & 0377)) break; + if (!ThomPikeCont(b)) break; + a = ThomPikeMerge(a, b); + if (++i == n) { + r.dx += i; + x = a; break; } } @@ -81,7 +80,7 @@ axdx_t tprecode8to16(char16_t *dst, size_t dstsize, const char *src) { if (!x) break; w = EncodeUtf16(x); while (w && r.ax + 1 < dstsize) { - dst[r.ax++] = w & 0xFFFF; + dst[r.ax++] = w; w >>= 16; } } diff --git a/libc/str/undeflate.c b/libc/str/undeflate.c index d849417d2..60b165efa 100644 --- a/libc/str/undeflate.c +++ b/libc/str/undeflate.c @@ -104,7 +104,7 @@ static struct DeflateHold undeflatesymbol(struct DeflateHold hold, uint32_t search, key; left = 0; right = treecount; - search = bitreverse16(hold.word); + search = BITREVERSE16(hold.word); search <<= 16; search |= 0xffff; while (left < right) { /* TODO(jart): Make this O(1) like Zlib. */ diff --git a/libc/str/utf16.h b/libc/str/utf16.h index 7bc999f7d..0e8e391d7 100644 --- a/libc/str/utf16.h +++ b/libc/str/utf16.h @@ -11,15 +11,15 @@ COSMOPOLITAN_C_START_ #define IsUcs2(wc) (((wc)&UTF16_MASK) != UTF16_MOAR) #define IsUtf16Cont(wc) (((wc)&UTF16_MASK) == UTF16_CONT) #define MergeUtf16(lo, hi) ((((lo)-0xD800) << 10) + ((hi)-0xDC00) + 0x10000) -#define EncodeUtf16(wc) \ - (__builtin_expect(((0x0000 <= (wc) && (wc) <= 0xFFFF) || \ - (0xE000 <= (wc) && (wc) <= 0xFFFF)), \ - 1) \ - ? (wc) \ - : 0x10000 <= (wc) && (wc) <= 0x10FFFF \ - ? (((((wc)-0x10000) >> 10) + 0xD800) | \ - ((((wc)-0x10000) & 1023) + 0xDC00) << 16) \ - : 0xFFFD) +#define EncodeUtf16(wc) \ + (__builtin_expect(((0x0000 <= (wc) && (wc) <= 0xFFFF) || \ + (0xE000 <= (wc) && (wc) <= 0xFFFF)), \ + 1) \ + ? (wc) \ + : 0x10000 <= (wc) && (wc) <= 0x10FFFF \ + ? (((((wc)-0x10000) >> 10) + 0xD800) | \ + (unsigned)((((wc)-0x10000) & 1023) + 0xDC00) << 16) \ + : 0xFFFD) COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/str/zipfindcentraldir.c b/libc/str/zipfindcentraldir.c index 431a75ea1..42a966d66 100644 --- a/libc/str/zipfindcentraldir.c +++ b/libc/str/zipfindcentraldir.c @@ -18,6 +18,8 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/zip.h" +/* TODO(jart): DELETE */ + /** * Locates End Of Central Directory record in ZIP file. * @@ -36,13 +38,7 @@ uint8_t *zipfindcentraldir(const uint8_t *p, size_t n) { if (n >= kZipCdirHdrMinSize) { i = n - kZipCdirHdrMinSize; do { - if (ZIP_CDIR_MAGIC(p + i) == kZipCdirHdrMagic && - i + ZIP_CDIR_HDRSIZE(p + i) <= n && - ZIP_CDIR_DISK(p + i) == ZIP_CDIR_STARTINGDISK(p + i) && - ZIP_CDIR_RECORDSONDISK(p + i) == ZIP_CDIR_RECORDS(p + i) && - ZIP_CDIR_RECORDS(p + i) * kZipCdirHdrMinSize <= - ZIP_CDIR_SIZE(p + i) && - ZIP_CDIR_OFFSET(p + i) + ZIP_CDIR_SIZE(p + i) <= i) { + if (ZIP_CDIR_MAGIC(p + i) == kZipCdirHdrMagic && IsZipCdir32(p, n, i)) { return (/*unconst*/ uint8_t *)(p + i); } } while (i--); diff --git a/libc/sysv/calls/__sys_getrusage.s b/libc/sysv/calls/__sys_getrusage.s new file mode 100644 index 000000000..49b33c68d --- /dev/null +++ b/libc/sysv/calls/__sys_getrusage.s @@ -0,0 +1,2 @@ +.include "o/libc/sysv/macros.internal.inc" +.scall __sys_getrusage,0x1bd0130752075062,globl,hidden diff --git a/libc/sysv/calls/__sys_mremap.s b/libc/sysv/calls/__sys_mremap.s new file mode 100644 index 000000000..9e32e0e10 --- /dev/null +++ b/libc/sysv/calls/__sys_mremap.s @@ -0,0 +1,2 @@ +.include "o/libc/sysv/macros.internal.inc" +.scall __sys_mremap,0x19bffffffffff019,globl,hidden diff --git a/libc/sysv/calls/__sys_wait4.s b/libc/sysv/calls/__sys_wait4.s new file mode 100644 index 000000000..15180408c --- /dev/null +++ b/libc/sysv/calls/__sys_wait4.s @@ -0,0 +1,2 @@ +.include "o/libc/sysv/macros.internal.inc" +.scall __sys_wait4,0x1c100b007200703d,globl,hidden diff --git a/libc/sysv/calls/rt_sigqueueinfo.s b/libc/sysv/calls/rt_sigqueueinfo.s deleted file mode 100644 index 0b821b76e..000000000 --- a/libc/sysv/calls/rt_sigqueueinfo.s +++ /dev/null @@ -1,2 +0,0 @@ -.include "o/libc/sysv/macros.internal.inc" -.scall rt_sigqueueinfo,0xfffffffffffff081,globl diff --git a/libc/sysv/calls/sigqueue.s b/libc/sysv/calls/sigqueue.s deleted file mode 100644 index 7f813ba9e..000000000 --- a/libc/sysv/calls/sigqueue.s +++ /dev/null @@ -1,2 +0,0 @@ -.include "o/libc/sysv/macros.internal.inc" -.scall sigqueue,0xffffff1c8fffffff,globl diff --git a/libc/sysv/calls/sys_getrusage.s b/libc/sysv/calls/sys_getrusage.s deleted file mode 100644 index a59cee99c..000000000 --- a/libc/sysv/calls/sys_getrusage.s +++ /dev/null @@ -1,2 +0,0 @@ -.include "o/libc/sysv/macros.internal.inc" -.scall sys_getrusage,0x1bd0130752075062,globl,hidden diff --git a/libc/sysv/calls/sys_mremap.s b/libc/sysv/calls/sys_mremap.s deleted file mode 100644 index 759973cd9..000000000 --- a/libc/sysv/calls/sys_mremap.s +++ /dev/null @@ -1,2 +0,0 @@ -.include "o/libc/sysv/macros.internal.inc" -.scall sys_mremap,0x19bffffffffff019,globl,hidden diff --git a/libc/sysv/calls/sys_sigqueue.s b/libc/sysv/calls/sys_sigqueue.s new file mode 100644 index 000000000..5faa160bf --- /dev/null +++ b/libc/sysv/calls/sys_sigqueue.s @@ -0,0 +1,2 @@ +.include "o/libc/sysv/macros.internal.inc" +.scall sys_sigqueue,0xffffff1c8fffffff,globl diff --git a/libc/sysv/calls/sys_sigqueueinfo.s b/libc/sysv/calls/sys_sigqueueinfo.s new file mode 100644 index 000000000..4e521ca9f --- /dev/null +++ b/libc/sysv/calls/sys_sigqueueinfo.s @@ -0,0 +1,2 @@ +.include "o/libc/sysv/macros.internal.inc" +.scall sys_sigqueueinfo,0x0f5ffffffffff081,globl diff --git a/libc/sysv/calls/sys_wait4.s b/libc/sysv/calls/sys_wait4.s deleted file mode 100644 index 4a1674eee..000000000 --- a/libc/sysv/calls/sys_wait4.s +++ /dev/null @@ -1,2 +0,0 @@ -.include "o/libc/sysv/macros.internal.inc" -.scall sys_wait4,0x1c100b007200703d,globl,hidden diff --git a/libc/sysv/consensus.py b/libc/sysv/consensus.py deleted file mode 100755 index fbd61bfd5..000000000 --- a/libc/sysv/consensus.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -import sys - -lineno = 0 - -def atoi(s): - try: - if s == '0': - return 0 - elif s.startswith('0x'): - return int(s[2:], 16) - elif s.startswith('0b'): - return int(s[2:], 2) - elif s.startswith('0'): - return int(s[1:], 8) - return int(s) - except ValueError: - sys.stderr.write('error: %s on line %d\n' % (s, lineno)) - sys.exit(1) - -for line in open('consts.sh'): - f = line.split() - lineno = lineno + 1 - if len(f) >= 8 and f[0] == 'syscon': - linux = atoi(f[3]) - xnu = atoi(f[4]) - freebsd = atoi(f[5]) - openbsd = atoi(f[6]) - windows = atoi(f[7]) - if linux == xnu and xnu == freebsd and freebsd == openbsd and openbsd == windows: - sys.stdout.write('%s\t%s\n' % (f[1], f[2])) diff --git a/libc/sysv/consts.sh b/libc/sysv/consts.sh index 80e50605e..665f3afdc 100755 --- a/libc/sysv/consts.sh +++ b/libc/sysv/consts.sh @@ -23,180 +23,176 @@ dir=libc/sysv/consts # » catalogue of carnage # # group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD NetBSD Windows Commentary -syscon errno ENOSYS 38 78 78 78 78 1 # bsd consensus & kNtErrorInvalidFunction -syscon errno EPERM 1 1 1 1 1 12 # unix consensus & kNtErrorInvalidAccess (should be kNtErrorNotOwner but is that mutex only??) -syscon errno ENOENT 2 2 2 2 2 2 # unix consensus & kNtErrorFileNotFound -syscon errno ESRCH 3 3 3 3 3 566 # "no such process" & kNtErrorThreadNotInProcess (cf. kNtErrorInvalidHandle) -syscon errno EINTR 4 4 4 4 4 10004 # unix consensus & WSAEINTR -syscon errno EIO 5 5 5 5 5 1117 # unix consensus & kNtErrorIoDevice -syscon errno ENXIO 6 6 6 6 6 1112 # unix consensus & kNtErrorNoMediaInDrive -syscon errno E2BIG 7 7 7 7 7 1639 # unix consensus & kNtErrorInvalidCommandLine -syscon errno ENOEXEC 8 8 8 8 8 193 # unix consensus & kNtErrorBadExeFormat -syscon errno EBADF 9 9 9 9 9 6 # bad file descriptor; cf. EBADFD; unix consensus & kNtErrorInvalidHandle -syscon errno ECHILD 10 10 10 10 10 128 # unix consensus & kNtErrorWaitNoChildren -syscon errno EAGAIN 11 35 35 35 35 0x2733 # bsd consensus & WSAEWOULDBLOCK -syscon errno EWOULDBLOCK 11 35 35 35 35 0x2733 # bsd consensus & WSAEWOULDBLOCK -syscon errno ENOMEM 12 12 12 12 12 14 # unix consensus & kNtErrorOutofmemory -syscon errno EACCES 13 13 13 13 13 5 # unix consensus & kNtErrorAccessDenied -syscon errno EFAULT 14 14 14 14 14 487 # unix consensus & kNtErrorInvalidAddress -syscon errno ENOTBLK 15 15 15 15 15 26 # unix consensus & kNtErrorNotDosDisk -syscon errno EBUSY 16 16 16 16 16 170 # unix consensus & kNtErrorBusy -syscon errno EEXIST 17 17 17 17 17 183 # unix consensus & kNtErrorAlreadyExists (should be kNtErrorFileExists too) -syscon errno EXDEV 18 18 18 18 18 17 # unix consensus & kNtErrorNotSameDevice -syscon errno ENODEV 19 19 19 19 19 1200 # unix consensus & kNtErrorBadDevice -syscon errno ENOTDIR 20 20 20 20 20 3 # unix consensus & kNtErrorPathNotFound -syscon errno EISDIR 21 21 21 21 21 267 # unix consensus & kNtErrorDirectoryNotSupported -syscon errno EINVAL 22 22 22 22 22 87 # unix consensus & kNtErrorInvalidParameter -syscon errno ENFILE 23 23 23 23 23 331 # unix consensus & kNtErrorTooManyDescriptors -syscon errno EMFILE 24 24 24 24 24 336 # unix consensus & kNtErrorTooManyOpenFiles -syscon errno ENOTTY 25 25 25 25 25 1118 # unix consensus & kNtErrorSerialNoDevice -syscon errno ETXTBSY 26 26 26 26 26 148 # unix consensus & kNtErrorPathBusy -syscon errno EFBIG 27 27 27 27 27 223 # unix consensus & kNtErrorFileTooLarge -syscon errno ENOSPC 28 28 28 28 28 39 # unix consensus & kNtErrorDiskFull -syscon errno EDQUOT 122 69 69 69 69 0x2755 # bsd consensus -syscon errno ESPIPE 29 29 29 29 29 25 # unix consensus & kNtErrorSeek -syscon errno EROFS 30 30 30 30 30 6009 # unix consensus & kNtErrorFileReadOnly -syscon errno EMLINK 31 31 31 31 31 4 # unix consensus & kNtErrorTooManyLinks -syscon errno EPIPE 32 32 32 32 32 109 # unix consensus & kNtErrorBrokenPipe -syscon errno EDOM 33 33 33 33 33 33 # bsd consensus & fudged on NT -syscon errno ERANGE 34 34 34 34 34 34 # bsd consensus & fudged on NT -syscon errno EDEADLK 35 11 11 11 11 1131 # bsd consensus & kNtErrorPossibleDeadlock -syscon errno ENAMETOOLONG 36 63 63 63 63 0x274f # bsd consensus & WSAENAMETOOLONG -syscon errno ENOLCK 37 77 77 77 77 0 # bsd consensus -syscon errno ENOTEMPTY 39 66 66 66 66 145 # bsd consensus & kNtErrorDirNotEmpty (TODO: What is WSAENOTEMPTY? 0x2752) -syscon errno ELOOP 40 62 62 62 62 0x274e # bsd consensus & WSAELOOP -syscon errno ENOMSG 42 91 83 90 83 0 -syscon errno EIDRM 43 90 82 89 82 0 -syscon errno EUSERS 87 68 68 68 68 0x2754 # bsd consensus & WSAEUSERS -syscon errno ENOTSOCK 88 38 38 38 38 0x2736 # bsd consensus & WSAENOTSOCK -syscon errno EDESTADDRREQ 89 39 39 39 39 0x2737 # bsd consensus & WSAEDESTADDRREQ -syscon errno EMSGSIZE 90 40 40 40 40 0x2738 # bsd consensus & WSAEMSGSIZE -syscon errno EPROTOTYPE 91 41 41 41 41 0x2739 # bsd consensus & WSAEPROTOTYPE -syscon errno ENOPROTOOPT 92 42 42 42 42 0x273a # bsd consensus & WSAENOPROTOOPT -syscon errno EPROTONOSUPPORT 93 43 43 43 43 0x273b # bsd consensus & WSAEPROTONOSUPPORT -syscon errno ESOCKTNOSUPPORT 94 44 44 44 44 0x273c # bsd consensus & WSAESOCKTNOSUPPORT -syscon errno ENOTSUP 95 45 45 91 86 0x273d -syscon errno EOPNOTSUPP 95 102 45 45 45 0x273d -syscon errno EPFNOSUPPORT 96 46 46 46 46 0x273e # bsd consensus & WSAEPFNOSUPPORT -syscon errno EAFNOSUPPORT 97 47 47 47 47 0x273f # bsd consensus & WSAEAFNOSUPPORT -syscon errno EADDRINUSE 98 48 48 48 48 0x2740 # bsd consensus & WSAEADDRINUSE -syscon errno EADDRNOTAVAIL 99 49 49 49 49 0x2741 # bsd consensus & WSAEADDRNOTAVAIL -syscon errno ENETDOWN 100 50 50 50 50 0x2742 # bsd consensus & WSAENETDOWN -syscon errno ENETUNREACH 101 51 51 51 51 0x2743 # bsd consensus & WSAENETUNREACH -syscon errno ENETRESET 102 52 52 52 52 0x2744 # bsd consensus & WSAENETRESET -syscon errno ECONNABORTED 103 53 53 53 53 0x2745 # bsd consensus & WSAECONNABORTED -syscon errno ECONNRESET 104 54 54 54 54 0x2746 # bsd consensus & WSAECONNRESET -syscon errno ENOBUFS 105 55 55 55 55 0x2747 # bsd consensus & WSAENOBUFS -syscon errno EISCONN 106 56 56 56 56 0x2748 # bsd consensus & WSAEISCONN -syscon errno ENOTCONN 107 57 57 57 57 0x2749 # bsd consensus & WSAENOTCONN -syscon errno ESHUTDOWN 108 58 58 58 58 0x274a # bsd consensus & WSAESHUTDOWN -syscon errno ETOOMANYREFS 109 59 59 59 59 0x274b # bsd consensus & WSAETOOMANYREFS -syscon errno ETIMEDOUT 110 60 60 60 60 0x274c # bsd consensus & WSAETIMEDOUT -syscon errno ECONNREFUSED 111 61 61 61 61 0x274d # bsd consensus & WSAECONNREFUSED -syscon errno EHOSTDOWN 112 64 64 64 64 0x2750 # bsd consensus & WSAEHOSTDOWN -syscon errno EHOSTUNREACH 113 65 65 65 65 0x2751 # bsd consensus & WSAEHOSTUNREACH -syscon errno EALREADY 114 37 37 37 37 0x2735 # bsd consensus & WSAEALREADY -syscon errno EINPROGRESS 115 36 36 36 36 0x2734 # bsd consensus & WSAEINPROGRESS -syscon errno ESTALE 116 70 70 70 70 0x2756 # bsd consensus & WSAESTALE -syscon errno ECHRNG 44 0 0 0 0 0 # bsd consensus -syscon errno EL2NSYNC 45 0 0 0 0 0 # bsd consensus -syscon errno EL3HLT 46 0 0 0 0 0 # bsd consensus -syscon errno EL3RST 47 0 0 0 0 0 # bsd consensus -syscon errno ELNRNG 48 0 0 0 0 0 # bsd consensus -syscon errno EUNATCH 49 0 0 0 0 0 # bsd consensus -syscon errno ENOCSI 50 0 0 0 0 0 # bsd consensus -syscon errno EL2HLT 51 0 0 0 0 0 # bsd consensus -syscon errno EBADE 52 0 0 0 0 0 # bsd consensus -syscon errno EBADR 53 0 0 0 0 0 # bsd consensus -syscon errno EXFULL 54 0 0 0 0 0 # bsd consensus -syscon errno ENOANO 55 0 0 0 0 0 # bsd consensus -syscon errno EBADRQC 56 0 0 0 0 0 # bsd consensus -syscon errno EBADSLT 57 0 0 0 0 0 # bsd consensus -syscon errno EBFONT 59 0 0 0 0 0 # bsd consensus -syscon errno ENOSTR 60 99 0 0 91 0 -syscon errno ENODATA 61 96 0 0 89 0 -syscon errno ETIME 62 101 0 0 92 0 -syscon errno ENOSR 63 98 0 0 90 0 -syscon errno ENONET 64 0 0 0 0 0 # bsd consensus -syscon errno ENOPKG 65 0 0 0 0 0 # bsd consensus +syscon errno ENOSYS 38 78 78 78 78 1 # system call unavailable; bsd consensus; kNtErrorInvalidFunction +syscon errno EPERM 1 1 1 1 1 12 # operation not permitted; unix consensus; kNtErrorInvalidAccess (should be kNtErrorNotOwner but is that mutex only??); raised by accept(2), acct(2), add_key(2), adjtimex(2), arch_prctl(2), bdflush(2), bpf(2), capget(2), chmod(2), chown(2), chroot(2), clock_getres(2), clone(2), copy_file_range(2), create_module(2), delete_module(2), epoll_ctl(2), execve(2), fallocate(2), fanotify_init(2), fcntl(2), futex(2), get_robust_list(2), getdomainname(2), getgroups(2), gethostname(2), getpriority(2), getrlimit(2), getsid(2), gettimeofday(2), idle(2), init_module(2), io_submit(2), ioctl_console(2), ioctl_ficlonerange(2), ioctl_fideduperange(2), ioctl_ns(2), ioctl_tty(2), ioperm(2), iopl(2), ioprio_set(2), kcmp(2), kexec_load(2), keyctl(2), kill(2), link(2), lookup_dcookie(2), madvise(2), mbind(2), membarrier(2), migrate_pages(2), mkdir(2), mknod(2), mlock(2), mmap(2), mount(2), move_pages(2), msgctl(2), nice(2), open(2), open_by_handle_at(2), pciconfig_read(2), perf_event_open(2), pidfd_getfd(2), pidfd_send_signal(2), pivot_root(2), prctl(2), process_vm_readv(2), ptrace(2), quotactl(2), reboot(2), rename(2), request_key(2), rmdir(2), rt_sigqueueinfo(2), sched_setaffinity(2), sched_setattr(2), sched_setparam(2), sched_setscheduler(2), semctl(2), seteuid(2), setfsgid(2), setfsuid(2), setgid(2), setns(2), setpgid(2), setresuid(2), setreuid(2), setsid(2), setuid(2), setup(2), setxattr(2), shmctl(2), shmget(2), sigaltstack(2), spu_create(2), stime(2), swapon(2), symlink(2), syslog(2), timer_create(2), timerfd_create(2), tkill(2), truncate(2), umount(2), unlink(2), unshare(2), utime(2), utimensat(2), vhangup(2), vm86(2), write(2), unix(7), ip(7) +syscon errno ENOENT 2 2 2 2 2 2 # no such file or directory; unix consensus; kNtErrorFileNotFound; raised by access(2), acct(2), alloc_hugepages(2), bind(2), bpf(2), chdir(2), chmod(2), chown(2), chroot(2), clock_getres(2), delete_module(2), epoll_ctl(2), execve(2), execveat(2), fanotify_mark(2), getdents(2), inotify_add_watch(2), ioctl_fat(2), kcmp(2), keyctl(2), link(2), mkdir(2), mknod(2), mount(2), msgget(2), open(2), open_by_handle_at(2), perf_event_open(2), query_module(2), quotactl(2), readdir(2), readlink(2), rename(2), rmdir(2), semget(2), shmget(2), spu_create(2), stat(2), statfs(2), statx(2), swapon(2), symlink(2), truncate(2), umount(2), unlink(2), utime(2), utimensat(2), unix(7), ip(7) +syscon errno ESRCH 3 3 3 3 3 566 # no such process; kNtErrorThreadNotInProcess (cf. kNtErrorInvalidHandle); raised by capget(2), get_robust_list(2), getpriority(2), getrlimit(2), getsid(2), ioprio_set(2), kcmp(2), kill(2), migrate_pages(2), move_pages(2), perf_event_open(2), pidfd_getfd(2), pidfd_open(2), pidfd_send_signal(2), process_vm_readv(2), ptrace(2), quotactl(2), rt_sigqueueinfo(2), sched_rr_get_interval(2), sched_setaffinity(2), sched_setattr(2), sched_setparam(2), sched_setscheduler(2), set_thread_area(2), setpgid(2), tkill(2), utimensat(2), unix(7) +syscon errno EINTR 4 4 4 4 4 10004 # crucial for building real time reliable software; unix consensus; WSAEINTR; raised by accept(2), clock_nanosleep(2), close(2), connect(2), dup(2), epoll_wait(2), fallocate(2), fcntl(2), flock(2), futex(2), getrandom(2), io_getevents(2), msgop(2), nanosleep(2), open(2), pause(2), perf_event_open(2), poll(2), ptrace(2), read(2), recv(2), request_key(2), select(2), semop(2), send(2), sigsuspend(2), sigwaitinfo(2), spu_run(2), statfs(2), truncate(2), wait(2), write(2), +syscon errno EIO 5 5 5 5 5 1117 # unix consensus; kNtErrorIoDevice; raised by access(2) acct(2) chdir(2) chmod(2) chown(2) chroot(2) close(2) copy_file_range(2) execve(2) fallocate(2) fsync(2) ioperm(2) link(2) madvise(2) mbind(2) pciconfig_read(2) ptrace(2) read(2) readlink(2) sendfile(2) statfs(2) symlink(2) sync_file_range(2) truncate(2) unlink(2) write(2) +syscon errno ENXIO 6 6 6 6 6 1112 # no such device or address; unix consensus; kNtErrorNoMediaInDrive; raised by lseek(2), mount(2), open(2), prctl(2) +syscon errno E2BIG 7 7 7 7 7 1639 # argument list too long; unix consensus; kNtErrorInvalidCommandLine; raised by bpf(2), execve(2), getxattr(2), listxattr(2), move_pages(2), msgop(2), openat2(2), perf_event_open(2), sched_setattr(2), semop(2), +syscon errno ENOEXEC 8 8 8 8 8 193 # exec format error; unix consensus; kNtErrorBadExeFormat; raised by execve(2), init_module(2), kexec_load(2), uselib(2) +syscon errno EBADF 9 9 9 9 9 6 # bad file descriptor; cf. EBADFD; unix consensus; kNtErrorInvalidHandle; raised by accept(2), access(2), bind(2), bpf(2), chdir(2), chmod(2), chown(2), close(2), connect(2), copy_file_range(2), dup(2), epoll_ctl(2), epoll_wait(2), execveat(2), fallocate(2), fanotify_mark(2), fcntl(2), flock(2), fsync(2), futimesat(2), getdents(2), getpeername(2), getsockname(2), getsockopt(2), init_module(2), inotify_add_watch(2), inotify_rm_watch(2), io_submit(2), ioctl(2), ioctl_console(2), ioctl_ficlonerange(2), ioctl_fideduperange(2), ioctl_getfsmap(2), kcmp(2), kexec_load(2), link(2), listen(2), llseek(2), lseek(2), madvise(2), mkdir(2), mknod(2), mmap(2), open(2), open_by_handle_at(2), perf_event_open(2), pidfd_getfd(2), pidfd_send_signal(2), posix_fadvise(2), prctl(2), read(2), readahead(2), readdir(2), readlink(2), recv(2), rename(2), select(2), send(2), sendfile(2), setns(2), shutdown(2), signalfd(2), splice(2), spu_run(2), stat(2), statfs(2), statx(2), symlink(2), sync(2), sync_file_range(2), timerfd_create(2), truncate(2), unlink(2), utimensat(2), vmsplice(2), write(2), unix(7) +syscon errno ECHILD 10 10 10 10 10 128 # no child process; unix consensus; kNtErrorWaitNoChildren; raised by wait(2), waitpid(2), waitid(2), wait3(2), wait4(2) +syscon errno EAGAIN 11 35 35 35 35 0x2733 # resource temporarily unavailable (e.g. too many processes, read or write with O_NONBLOCK needs polling, too much memory locked, etc.); bsd consensus; WSAEWOULDBLOCK; raised by accept(2), clone(2), connect(2), eventfd(2), fcntl(2), fork(2), futex(2), getrandom(2), io_cancel(2), io_setup(2), io_submit(2), ioctl_userfaultfd(2), keyctl(2), madvise(2), mincore(2), mlock(2), mmap(2), mremap(2), msgop(2), openat2(2), poll(2), read(2), rt_sigqueueinfo(2), select(2), semop(2), send(2), sendfile(2), setresuid(2), setreuid(2), setuid(2), signalfd(2), sigwaitinfo(2), splice(2), tee(2), timer_create(2), timerfd_create(2), tkill(2), umount(2), vmsplice(2), write(2), ip(7) +syscon errno ENOMEM 12 12 12 12 12 14 # we require more vespene gas; unix consensus; kNtErrorOutofmemory; raised by access(2), acct(2), add_key(2), bind(2), bpf(2), chdir(2), chmod(2), chown(2), chroot(2), clone(2), copy_file_range(2), create_module(2), epoll_create(2), epoll_ctl(2), eventfd(2), execve(2), fanotify_init(2), fanotify_mark(2), fork(2), getgroups(2), getrlimit(2), init_module(2), inotify_add_watch(2), inotify_init(2), io_setup(2), ioctl_fideduperange(2), ioctl_getfsmap(2), ioperm(2), kexec_load(2), keyctl(2), link(2), lookup_dcookie(2), madvise(2), mbind(2), memfd_create(2), mincore(2), mkdir(2), mknod(2), mlock(2), mmap(2), mount(2), mprotect(2), mremap(2), msgget(2), msgop(2), msync(2), open(2), pidfd_open(2), poll(2), process_vm_readv(2), readlink(2), recv(2), rename(2), request_key(2), rmdir(2), s390_guarded_storage(2), s390_pci_mmio_write(2), s390_runtime_instr(2), s390_sthyi(2), select(2), semget(2), semop(2), send(2), sendfile(2), set_mempolicy(2), setns(2), shmctl(2), shmget(2), shmop(2), sigaltstack(2), signalfd(2), splice(2), spu_create(2), spu_run(2), stat(2), statfs(2), statx(2), subpage_prot(2), swapon(2), symlink(2), sync_file_range(2), tee(2), timer_create(2), timerfd_create(2), umount(2), unlink(2), unshare(2), userfaultfd(2), vmsplice(2), unix(7), ip(7) +syscon errno EACCES 13 13 13 13 13 5 # permission denied; unix consensus; kNtErrorAccessDenied; raised by access(2), acct(2), add_key(2), bind(2), bpf(2), chdir(2), chmod(2), chown(2), chroot(2), clock_getres(2), connect(2), execve(2), fcntl(2), futex(2), getpriority(2), inotify_add_watch(2), keyctl(2), link(2), madvise(2), mkdir(2), mknod(2), mmap(2), mount(2), move_pages(2), mprotect(2), msgctl(2), msgget(2), msgop(2), open(2), perf_event_open(2), prctl(2), ptrace(2), quotactl(2), readlink(2), rename(2), request_key(2), rmdir(2), semctl(2), semget(2), semop(2), send(2), setpgid(2), shmctl(2), shmget(2), shmop(2), socket(2), spu_create(2), stat(2), statfs(2), statx(2), symlink(2), truncate(2), unlink(2), uselib(2), utime(2), utimensat(2), ip(7) +syscon errno EFAULT 14 14 14 14 14 487 # pointer passed to system call that would otherwise segfault; unix consensus; kNtErrorInvalidAddress; raised by accept(2), access(2), acct(2), add_key(2), adjtimex(2), arch_prctl(2), bdflush(2), bind(2), bpf(2), cacheflush(2), capget(2), chdir(2), chmod(2), chown(2), chroot(2), clock_getres(2), clock_nanosleep(2), connect(2), create_module(2), delete_module(2), epoll_wait(2), execve(2), fcntl(2), futex(2), get_mempolicy(2), get_robust_list(2), getcpu(2), getdents(2), getdomainname(2), getgroups(2), gethostname(2), getitimer(2), getpeername(2), getrandom(2), getresuid(2), getrlimit(2), getrusage(2), getsockname(2), getsockopt(2), gettimeofday(2), getunwind(2), init_module(2), inotify_add_watch(2), io_cancel(2), io_destroy(2), io_getevents(2), io_setup(2), io_submit(2), ioctl(2), ioctl_getfsmap(2), ioctl_userfaultfd(2), kcmp(2), keyctl(2), link(2), llseek(2), lookup_dcookie(2), mbind(2), memfd_create(2), migrate_pages(2), mincore(2), mkdir(2), mknod(2), mmap2(2), modify_ldt(2), mount(2), move_pages(2), mremap(2), msgctl(2), msgop(2), msync(2), nanosleep(2), open(2), open_by_handle_at(2), perf_event_open(2), pipe(2), poll(2), prctl(2), process_vm_readv(2), ptrace(2), query_module(2), quotactl(2), read(2), readdir(2), readlink(2), reboot(2), recv(2), rename(2), request_key(2), rmdir(2), s390_guarded_storage(2), s390_pci_mmio_write(2), s390_sthyi(2), sched_rr_get_interval(2), sched_setaffinity(2), semctl(2), semop(2), send(2), sendfile(2), set_mempolicy(2), set_thread_area(2), shmctl(2), sigaction(2), sigaltstack(2), sigpending(2), sigprocmask(2), sigsuspend(2), socketpair(2), spu_create(2), spu_run(2), stat(2), statfs(2), statx(2), stime(2), subpage_prot(2), symlink(2), sysctl(2), sysfs(2), sysinfo(2), time(2), timer_settime(2), timerfd_create(2), times(2), truncate(2), umount(2), uname(2), unlink(2), ustat(2), utimensat(2), vm86(2), write(2), unix(7) +syscon errno ENOTBLK 15 15 15 15 15 26 # block device required; unix consensus; kNtErrorNotDosDisk; raised by mount(2), quotactl(2), umount(2) +syscon errno EBUSY 16 16 16 16 16 170 # device or resource busy; unix consensus; kNtErrorBusy; raised by bdflush(2), delete_module(2), dup(2), fcntl(2), init_module(2), ioctl_tty(2), ioctl_userfaultfd(2), kexec_load(2), mount(2), msync(2), pivot_root(2), prctl(2), ptrace(2), quotactl(2), rename(2), rmdir(2), sched_setattr(2), swapon(2), umount(2) +syscon errno EEXIST 17 17 17 17 17 183 # file exists; unix consensus; kNtErrorAlreadyExists (should be kNtErrorFileExists too); raised by bpf(2), create_module(2), epoll_ctl(2), init_module(2), inotify_add_watch(2), keyctl(2), link(2), mkdir(2), mknod(2), mmap(2), msgget(2), open(2), rename(2), rmdir(2), semget(2), setxattr(2), shmget(2), spu_create(2), symlink(2) +syscon errno EXDEV 18 18 18 18 18 17 # improper link; unix consensus; kNtErrorNotSameDevice; raised by copy_file_range(2), fanotify_mark(2), ioctl_ficlonerange(2), ioctl_fideduperange(2), link(2), openat2(2), rename(2) +syscon errno ENODEV 19 19 19 19 19 1200 # no such device; unix consensus; kNtErrorBadDevice; raised by arch_prctl(2), eventfd(2), fallocate(2), fanotify_mark(2), mmap(2), mount(2), move_pages(2), open(2), pciconfig_read(2), perf_event_open(2), pidfd_open(2), prctl(2), s390_pci_mmio_write(2), signalfd(2), spu_create(2), timerfd_create(2) +syscon errno ENOTDIR 20 20 20 20 20 3 # not a directory; unix consensus; kNtErrorPathNotFound; raised by access(2), acct(2), bind(2), chdir(2), chmod(2), chown(2), chroot(2), execve(2), execveat(2), fanotify_mark(2), fcntl(2), futimesat(2), getdents(2), inotify_add_watch(2), ioctl_fat(2), keyctl(2), link(2), mkdir(2), mknod(2), mount(2), open(2), open_by_handle_at(2), pivot_root(2), readdir(2), readlink(2), rename(2), rmdir(2), spu_create(2), stat(2), statfs(2), statx(2), symlink(2), sysctl(2), truncate(2), unlink(2), utimensat(2) +syscon errno EISDIR 21 21 21 21 21 267 # is a a directory; unix consensus; kNtErrorDirectoryNotSupported; raised by acct(2), copy_file_range(2), execve(2), ioctl_ficlonerange(2), ioctl_fideduperange(2), open(2), read(2), rename(2), truncate(2), unlink(2) +syscon errno EINVAL 22 22 22 22 22 87 # invalid argument; unix consensus; kNtErrorInvalidParameter; raised by accept(2), access(2), add_key(2), adjtimex(2), arch_prctl(2), bdflush(2), bind(2), bpf(2), cacheflush(2), capget(2), chmod(2), chown(2), clock_getres(2), clock_nanosleep(2), clone(2), copy_file_range(2), create_module(2), dup(2), epoll_create(2), epoll_ctl(2), epoll_wait(2), eventfd(2), execve(2), execveat(2), fallocate(2), fanotify_init(2), fanotify_mark(2), fcntl(2), flock(2), futex(2), get_mempolicy(2), get_robust_list(2), getdents(2), getdomainname(2), getgroups(2), gethostname(2), getitimer(2), getpeername(2), getpriority(2), getrandom(2), getrlimit(2), getrusage(2), getsockname(2), getsockopt(2), gettimeofday(2), init_module(2), inotify_add_watch(2), inotify_init(2), inotify_rm_watch(2), io_cancel(2), io_destroy(2), io_getevents(2), io_setup(2), io_submit(2), ioctl(2), ioctl_console(2), ioctl_ficlonerange(2), ioctl_fideduperange(2), ioctl_getfsmap(2), ioctl_ns(2), ioctl_tty(2), ioctl_userfaultfd(2), ioperm(2), iopl(2), ioprio_set(2), kcmp(2), kexec_load(2), keyctl(2), kill(2), link(2), llseek(2), lookup_dcookie(2), lseek(2), madvise(2), mbind(2), membarrier(2), memfd_create(2), migrate_pages(2), mincore(2), mkdir(2), mknod(2), mlock(2), mmap(2), mmap2(2), modify_ldt(2), mount(2), move_pages(2), mprotect(2), mremap(2), msgctl(2), msgop(2), msync(2), nanosleep(2), open(2), open_by_handle_at(2), openat2(2), pciconfig_read(2), perf_event_open(2), personality(2), pidfd_getfd(2), pidfd_open(2), pidfd_send_signal(2), pipe(2), pivot_root(2), pkey_alloc(2), poll(2), posix_fadvise(2), prctl(2), process_vm_readv(2), ptrace(2), query_module(2), quotactl(2), read(2), readahead(2), readdir(2), readlink(2), readv(2), reboot(2), recv(2), recvmmsg(2), remap_file_pages(2), rename(2), request_key(2), rmdir(2), rt_sigqueueinfo(2), s390_guarded_storage(2), s390_pci_mmio_write(2), s390_runtime_instr(2), s390_sthyi(2), sched_get_priority_max(2), sched_rr_get_interval(2), sched_setaffinity(2), sched_setattr(2), sched_setparam(2), sched_setscheduler(2), seccomp(2), select(2), semctl(2), semget(2), semop(2), send(2), sendfile(2), set_mempolicy(2), set_thread_area(2), seteuid(2), setfsgid(2), setfsuid(2), setgid(2), setns(2), setpgid(2), setresuid(2), setreuid(2), setuid(2), shmctl(2), shmget(2), shmop(2), shutdown(2), sigaction(2), sigaltstack(2), signal(2), signalfd(2), sigprocmask(2), sigsuspend(2), sigwaitinfo(2), socket(2), splice(2), spu_create(2), spu_run(2), stat(2), statx(2), subpage_prot(2), swapon(2), sync_file_range(2), sysfs(2), syslog(2), tee(2), timer_create(2), timer_delete(2), timer_getoverrun(2), timer_settime(2), timerfd_create(2), tkill(2), truncate(2), umount(2), unlink(2), unshare(2), userfaultfd(2), ustat(2), utimensat(2), vmsplice(2), wait(2), write(2), unix(7), ip(7) +syscon errno ENFILE 23 23 23 23 23 331 # too many open files in system; unix consensus; kNtErrorTooManyDescriptors; raised by accept(2), acct(2), epoll_create(2), eventfd(2), execve(2), futex(2), inotify_init(2), memfd_create(2), mmap(2), open(2), pidfd_getfd(2), pidfd_open(2), pipe(2), shmget(2), signalfd(2), socket(2), socketpair(2), spu_create(2), swapon(2), timerfd_create(2), uselib(2), userfaultfd(2) +syscon errno EMFILE 24 24 24 24 24 336 # too many open files; unix consensus; kNtErrorTooManyOpenFiles; raised by accept(2), dup(2), epoll_create(2), eventfd(2), execve(2), fanotify_init(2), fcntl(2), inotify_init(2), memfd_create(2), mount(2), open(2), perf_event_open(2), pidfd_getfd(2), pidfd_open(2), pipe(2), signalfd(2), socket(2), socketpair(2), spu_create(2), timerfd_create(2) +syscon errno ENOTTY 25 25 25 25 25 1118 # inappropriate i/o control operation; unix consensus; kNtErrorSerialNoDevice; raised by ioctl(2), ioctl_console(2), ioctl_fat(2), ioctl_ns(2), ioctl_tty(2) +syscon errno ETXTBSY 26 26 26 26 26 148 # won't open executable that's executing in write mode; try UnlockExecutable(); unix consensus; kNtErrorPathBusy; raised by access(2), copy_file_range(2), execve(2), fallocate(2), ioctl_ficlonerange(2), ioctl_fideduperange(2), mmap(2), open(2), truncate(2) +syscon errno EFBIG 27 27 27 27 27 223 # file too large; unix consensus; kNtErrorFileTooLarge; raised by copy_file_range(2), fallocate(2), init_module(2), open(2), semop(2), truncate(2), write(2) +syscon errno ENOSPC 28 28 28 28 28 39 # no space left on device; unix consensus; kNtErrorDiskFull; raised by copy_file_range(2), epoll_ctl(2), fallocate(2), fanotify_mark(2), fsync(2), inotify_add_watch(2), link(2), mkdir(2), mknod(2), msgget(2), open(2), perf_event_open(2), pkey_alloc(2), query_module(2), rename(2), semget(2), setxattr(2), shmget(2), spu_create(2), symlink(2), sync_file_range(2), write(2) +syscon errno EDQUOT 122 69 69 69 69 0x2755 # disk quota exceeded; bsd consensus; raised by add_key(2), keyctl(2), link(2), mkdir(2), mknod(2), open(2), rename(2), request_key(2), setxattr(2), symlink(2), write(2) +syscon errno ESPIPE 29 29 29 29 29 25 # invalid seek; unix consensus; kNtErrorSeek; raised by fallocate(2), lseek(2), posix_fadvise(2), sendfile(2), splice(2), sync_file_range(2) +syscon errno EROFS 30 30 30 30 30 6009 # read-only filesystem; unix consensus; kNtErrorFileReadOnly; raised by access(2), acct(2), bind(2), chmod(2), chown(2), link(2), mkdir(2), mknod(2), mount(2), open(2), rename(2), rmdir(2), symlink(2), truncate(2), unlink(2), utime(2), utimensat(2) +syscon errno EMLINK 31 31 31 31 31 4 # too many links; unix consensus; kNtErrorTooManyLinks; raised by link(2), mkdir(2), rename(2) +syscon errno EPIPE 32 32 32 32 32 109 # broken pipe; unix consensus; kNtErrorBrokenPipe; raised by send(2), write(2), tcp(7), unix(7), ip(7) +syscon errno EDOM 33 33 33 33 33 33 # mathematics argument out of domain of function; bsd consensus; fudged on NT; returned by cos(3), fmod(3), log1p(3), sin(3), tan(3), tgamma(3) +syscon errno ERANGE 34 34 34 34 34 34 # result too large; bsd consensus; fudged on NT; raised by getxattr(2), listxattr(2), lookup_dcookie(2), prctl(2), quotactl(2), semctl(2), semop(2), setxattr(2) +syscon errno EDEADLK 35 11 11 11 11 1131 # resource deadlock avoided; bsd consensus; kNtErrorPossibleDeadlock; raised by fcntl(2), keyctl(2) +syscon errno ENAMETOOLONG 36 63 63 63 63 0x274f # filename too long; bsd consensus; WSAENAMETOOLONG; raised by access(2), acct(2), bind(2), chdir(2), chmod(2), chown(2), chroot(2), execve(2), gethostname(2), inotify_add_watch(2), link(2), lookup_dcookie(2), mkdir(2), mknod(2), mount(2), open(2), readlink(2), rename(2), rmdir(2), spu_create(2), stat(2), statfs(2), statx(2), symlink(2), truncate(2), umount(2), unlink(2), utimensat(2) +syscon errno ENOLCK 37 77 77 77 77 0 # no locks available; bsd consensus; raised by fcntl(2), flock(2) +syscon errno ENOTEMPTY 39 66 66 66 66 145 # directory not empty; bsd consensus; kNtErrorDirNotEmpty (TODO: What is WSAENOTEMPTY? 0x2752); raised by rmdir(2) +syscon errno ELOOP 40 62 62 62 62 0x274e # too many levels of symbolic links; bsd consensus; WSAELOOP; raised by access(2), acct(2), bind(2), chdir(2), chmod(2), chown(2), chroot(2), epoll_ctl(2), execve(2), execveat(2), keyctl(2), link(2), mkdir(2), mknod(2), mount(2), open(2), open_by_handle_at(2), openat2(2), readlink(2), rename(2), rmdir(2), spu_create(2), stat(2), statfs(2), statx(2), symlink(2), truncate(2), unlink(2), utimensat(2) +syscon errno ENOMSG 42 91 83 90 83 0 # raised by msgop(2) +syscon errno EIDRM 43 90 82 89 82 0 # identifier removed; raised by msgctl(2), msgget(2), msgop(2), semctl(2), semop(2), shmctl(2), shmget(2), shmop(2) +syscon errno ETIME 62 101 60 60 92 0 # timer expired; timer expired; raised by connect(2), futex(2), keyctl(2), mq_receive(2), mq_send(2), rtime(2), sem_wait(2) +syscon errno EPROTO 71 100 92 95 96 0 # raised by accept(2), connect(2), socket(2), socketpair(2) +syscon errno EOVERFLOW 75 84 84 87 84 0 # raised by aio_read(2), copy_file_range(2), ctime(2), fanotify_init(2), lseek(2), mmap(2), open(2), open_by_handle_at(2), sem_post(2), sendfile(2), shmctl(2), stat(2), statfs(2), statvfs(2), time(2), timegm(2) +syscon errno EILSEQ 84 92 86 84 85 0 # returned by fgetwc(3), fputwc(3), getwchar(3), putwchar(3), scanf(3), ungetwc(3) +syscon errno EUSERS 87 68 68 68 68 0x2754 # too many users; bsd consensus; WSAEUSERS; raised by acct(2) +syscon errno ENOTSOCK 88 38 38 38 38 0x2736 # not a socket; bsd consensus; WSAENOTSOCK; raised by accept(2), bind(2), connect(2), getpeername(2), getsockname(2), getsockopt(2), listen(2), recv(2), send(2), shutdown(2) +syscon errno EDESTADDRREQ 89 39 39 39 39 0x2737 # destination address required; bsd consensus; WSAEDESTADDRREQ; raised by send(2), write(2) +syscon errno EMSGSIZE 90 40 40 40 40 0x2738 # message too long; bsd consensus; WSAEMSGSIZE; raised by keyctl(2), send(2), ip(7) +syscon errno EPROTOTYPE 91 41 41 41 41 0x2739 # protocol wrong type for socket; bsd consensus; WSAEPROTOTYPE; raised by connect(2), unix(7) +syscon errno ENOPROTOOPT 92 42 42 42 42 0x273a # protocol not available; bsd consensus; WSAENOPROTOOPT; raised by getsockopt(2), accept(2), ip(7) +syscon errno EPROTONOSUPPORT 93 43 43 43 43 0x273b # protocol not supported; bsd consensus; WSAEPROTONOSUPPORT; raised by socket(2), socketpair(2), unix(7) +syscon errno ESOCKTNOSUPPORT 94 44 44 44 44 0x273c # socket type not supported; bsd consensus; WSAESOCKTNOSUPPORT; raised by unix(7), ip(7) +syscon errno ENOTSUP 95 45 45 91 86 0x273d # operation not supported; raised by chmod(2), clock_getres(2), clock_nanosleep(2), getxattr(2), listxattr(2), removexattr(2), setxattr(2), timer_create(2) +syscon errno EOPNOTSUPP 95 102 45 45 45 0x273d # socket operation not supported; raised by accept(2), fallocate(2), fanotify_mark(2), ioctl_ficlonerange(2), ioctl_fideduperange(2), ioctl_getfsmap(2), keyctl(2), listen(2), mmap(2), open_by_handle_at(2), pciconfig_read(2), perf_event_open(2), prctl(2), readv(2), s390_guarded_storage(2), s390_runtime_instr(2), s390_sthyi(2), send(2), socketpair(2), unix(7), ip(7) +syscon errno EPFNOSUPPORT 96 46 46 46 46 0x273e # protocol family not supported; bsd consensus; WSAEPFNOSUPPORT +syscon errno EAFNOSUPPORT 97 47 47 47 47 0x273f # address family not supported; bsd consensus; WSAEAFNOSUPPORT; raised by connect(2), socket(2), socketpair(2), tcp(7) +syscon errno EADDRINUSE 98 48 48 48 48 0x2740 # address already in use; bsd consensus; WSAEADDRINUSE; raised by bind(2), connect(2), listen(2), unix(7), ip(7) +syscon errno EADDRNOTAVAIL 99 49 49 49 49 0x2741 # address not available; bsd consensus; WSAEADDRNOTAVAIL; raised by bind(2), connect(2), kexec_load(2), ip(7) +syscon errno ENETDOWN 100 50 50 50 50 0x2742 # network is down; bsd consensus; WSAENETDOWN; raised by accept(2) +syscon errno ENETUNREACH 101 51 51 51 51 0x2743 # host is unreachable; bsd consensus; WSAENETUNREACH; raised by accept(2), connect(2) +syscon errno ENETRESET 102 52 52 52 52 0x2744 # connection reset by network; bsd consensus; WSAENETRESET +syscon errno ECONNABORTED 103 53 53 53 53 0x2745 # connection reset before accept; bsd consensus; WSAECONNABORTED; raised by accept(2) +syscon errno ECONNRESET 104 54 54 54 54 0x2746 # connection reset by client; bsd consensus; WSAECONNRESET; raised by send(2), unix(7) +syscon errno ENOBUFS 105 55 55 55 55 0x2747 # no buffer space available; bsd consensus; WSAENOBUFS; raised by getpeername(2), getsockname(2), send(2), ip(7) +syscon errno EISCONN 106 56 56 56 56 0x2748 # socket is connected; bsd consensus; WSAEISCONN; raised by connect(2), send(2), unix(7), ip(7) +syscon errno ENOTCONN 107 57 57 57 57 0x2749 # socket is not connected; bsd consensus; WSAENOTCONN; raised by getpeername(2), recv(2), send(2), shutdown(2), ip(7) +syscon errno ESHUTDOWN 108 58 58 58 58 0x274a # cannot send after transport endpoint shutdown; note that shutdown write is an EPIPE; bsd consensus; WSAESHUTDOWN +syscon errno ETOOMANYREFS 109 59 59 59 59 0x274b # too many references: cannot splice; bsd consensus; WSAETOOMANYREFS; raised by sendmsg(2), unix(7) +syscon errno ETIMEDOUT 110 60 60 60 60 0x274c # connection timed out; bsd consensus; WSAETIMEDOUT; raised by connect(2), futex(2), keyctl(2), tcp(7) +syscon errno ECONNREFUSED 111 61 61 61 61 0x274d # bsd consensus; WSAECONNREFUSED; raised by connect(2), listen(2), recv(2), unix(7), udp(7)system-imposed limit on the number of threads was encountered. +syscon errno EHOSTDOWN 112 64 64 64 64 0x2750 # bsd consensus; WSAEHOSTDOWN; raised by accept(2) +syscon errno EHOSTUNREACH 113 65 65 65 65 0x2751 # bsd consensus; WSAEHOSTUNREACH; raised by accept(2), ip(7) +syscon errno EALREADY 114 37 37 37 37 0x2735 # connection already in progress; bsd consensus; WSAEALREADY; raised by connect(2), send(2), ip(7) +syscon errno EINPROGRESS 115 36 36 36 36 0x2734 # bsd consensus; WSAEINPROGRESS; raised by connect(2) w/ O_NONBLOCK +syscon errno ESTALE 116 70 70 70 70 0x2756 # bsd consensus; WSAESTALE; raised by open_by_handle_at(2) syscon errno EREMOTE 66 71 71 71 71 0x2757 # bsd consensus -syscon errno ENOLINK 67 97 91 0 95 0 -syscon errno EADV 68 0 0 0 0 0 # bsd consensus -syscon errno ESRMNT 69 0 0 0 0 0 # bsd consensus -syscon errno ECOMM 70 0 0 0 0 0 # bsd consensus -syscon errno EPROTO 71 100 92 95 96 0 -syscon errno EMULTIHOP 72 95 90 0 94 0 -syscon errno EDOTDOT 73 0 0 0 0 0 # bsd consensus -syscon errno EBADMSG 74 94 89 92 88 0 -syscon errno EOVERFLOW 75 84 84 87 84 0 -syscon errno ENOTUNIQ 76 0 0 0 0 0 # bsd consensus -syscon errno EBADFD 77 9 9 9 9 6 # file descriptor in bad state; cf. EBADF; fudged on non-Linux -syscon errno EREMCHG 78 0 0 0 0 0 # bsd consensus -syscon errno ELIBACC 79 0 0 0 0 0 # bsd consensus -syscon errno ELIBBAD 80 0 0 0 0 0 # bsd consensus -syscon errno ELIBSCN 81 0 0 0 0 0 # bsd consensus -syscon errno ELIBMAX 82 0 0 0 0 0 # bsd consensus -syscon errno ELIBEXEC 83 0 0 0 0 0 # bsd consensus -syscon errno EILSEQ 84 92 86 84 85 0 -syscon errno ERESTART 85 0 0 0 -3 0 # bsd consensus -syscon errno ESTRPIPE 86 0 0 0 0 0 # bsd consensus -syscon errno EUCLEAN 117 0 0 0 0 0 # bsd consensus -syscon errno ENOTNAM 118 0 0 0 0 0 # bsd consensus -syscon errno ENAVAIL 119 0 0 0 0 0 # bsd consensus -syscon errno EISNAM 120 0 0 0 0 0 # bsd consensus -syscon errno EREMOTEIO 121 0 0 0 0 0 # bsd consensus -syscon errno ENOMEDIUM 123 0 0 85 85 0 -syscon errno EMEDIUMTYPE 124 0 0 86 86 0 -syscon errno ECANCELED 125 89 85 88 87 0 -syscon errno ENOKEY 126 0 0 0 0 0 # bsd consensus -syscon errno EKEYEXPIRED 127 0 0 0 0 0 # bsd consensus -syscon errno EKEYREVOKED 128 0 0 0 0 0 # bsd consensus -syscon errno EKEYREJECTED 129 0 0 0 0 0 # bsd consensus -syscon errno EOWNERDEAD 130 105 96 94 97 0 -syscon errno ENOTRECOVERABLE 131 104 95 93 98 0 -syscon errno ERFKILL 132 0 0 0 0 0 # bsd consensus -syscon errno EHWPOISON 133 0 0 0 0 0 # bsd consensus +syscon errno EBADMSG 74 94 89 92 88 0 # raised by ioctl_getfsmap(2) +syscon errno ECANCELED 125 89 85 88 87 0 # raised by timerfd_create(2) +syscon errno EOWNERDEAD 130 105 96 94 97 0 # raised by pthread_cond_timedwait(3), pthread_mutex_consistent(3), pthread_mutex_getprioceiling(3), pthread_mutex_lock(3), pthread_mutex_timedlock(3), pthread_mutexattr_getrobust(3), pthread_mutexattr_setrobust(3) +syscon errno ENOTRECOVERABLE 131 104 95 93 98 0 # raised by pthread_cond_timedwait(3), pthread_mutex_consistent(3), pthread_mutex_getprioceiling(3), pthread_mutex_lock(3), pthread_mutex_timedlock(3), pthread_mutexattr_getrobust(3), pthread_mutexattr_setrobust(3) +syscon errno ENONET 64 0 0 0 0 0 # bsd consensus; raised by accept(2) +syscon errno ERESTART 85 0 0 0 -3 0 # bsd consensus; should only be seen in ptrace() +syscon junkerr ECHRNG 44 0 0 0 0 0 # bsd consensus +syscon junkerr EL2NSYNC 45 0 0 0 0 0 # bsd consensus +syscon junkerr EL3HLT 46 0 0 0 0 0 # bsd consensus +syscon junkerr EL3RST 47 0 0 0 0 0 # bsd consensus +syscon junkerr ELNRNG 48 0 0 0 0 0 # bsd consensus +syscon junkerr EUNATCH 49 0 0 0 0 0 # bsd consensus +syscon junkerr ENOCSI 50 0 0 0 0 0 # bsd consensus +syscon junkerr EL2HLT 51 0 0 0 0 0 # bsd consensus +syscon junkerr EBADE 52 0 0 0 0 0 # bsd consensus +syscon junkerr EBADR 53 0 0 0 0 0 # bsd consensus +syscon junkerr EXFULL 54 0 0 0 0 0 # bsd consensus +syscon junkerr ENOANO 55 0 0 0 0 0 # bsd consensus +syscon junkerr EBADRQC 56 0 0 0 0 0 # bsd consensus +syscon junkerr EBADSLT 57 0 0 0 0 0 # bsd consensus +syscon junkerr ENOSTR 60 99 0 0 91 0 # +syscon junkerr ENODATA 61 96 0 0 89 0 # raised by getxattr(2), removexattr(2), setxattr(2) +syscon junkerr ENOSR 63 98 0 0 90 0 # +syscon junkerr ENOPKG 65 0 0 0 0 0 # bsd consensus, ip(7) +syscon junkerr ENOLINK 67 97 91 0 95 0 # +syscon junkerr EADV 68 0 0 0 0 0 # bsd consensus +syscon junkerr ESRMNT 69 0 0 0 0 0 # bsd consensus +syscon junkerr ECOMM 70 0 0 0 0 0 # bsd consensus +syscon junkerr EMULTIHOP 72 95 90 0 94 0 # +syscon junkerr EDOTDOT 73 0 0 0 0 0 # bsd consensus +syscon junkerr ENOTUNIQ 76 0 0 0 0 0 # bsd consensus +syscon junkerr EREMCHG 78 0 0 0 0 0 # bsd consensus +syscon junkerr ELIBACC 79 0 0 0 0 0 # bsd consensus +syscon junkerr ELIBBAD 80 0 0 0 0 0 # bsd consensus +syscon junkerr ELIBSCN 81 0 0 0 0 0 # bsd consensus +syscon junkerr ELIBMAX 82 0 0 0 0 0 # bsd consensus +syscon junkerr ELIBEXEC 83 0 0 0 0 0 # bsd consensus +syscon junkerr ESTRPIPE 86 0 0 0 0 0 # bsd consensus +syscon junkerr EUCLEAN 117 0 0 0 0 0 # bsd consensus +syscon junkerr ENOTNAM 118 0 0 0 0 0 # bsd consensus +syscon junkerr ENAVAIL 119 0 0 0 0 0 # bsd consensus +syscon junkerr EISNAM 120 0 0 0 0 0 # bsd consensus +syscon junkerr EREMOTEIO 121 0 0 0 0 0 # bsd consensus +syscon junkerr ENOMEDIUM 123 0 0 85 85 0 # +syscon junkerr EMEDIUMTYPE 124 0 0 86 86 0 # +syscon junkerr ENOKEY 126 0 0 0 0 0 # bsd consensus +syscon junkerr EKEYEXPIRED 127 0 0 0 0 0 # bsd consensus +syscon junkerr EKEYREVOKED 128 0 0 0 0 0 # bsd consensus +syscon junkerr EKEYREJECTED 129 0 0 0 0 0 # bsd consensus +syscon junkerr ERFKILL 132 0 0 0 0 0 # bsd consensus +syscon junkerr EHWPOISON 133 0 0 0 0 0 # bsd consensus +syscon junkerr EBADFD 77 9 9 9 9 6 # file descriptor in bad state; cf. EBADF; fudged on non-Linux +syscon compat EWOULDBLOCK 11 35 35 35 35 0x2733 # same as EWOULDBLOCK # signals # # group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD NetBSD XENIX Commentary -syscon sig SIGHUP 1 1 1 1 1 1 # unix consensus & faked on nt -syscon sig SIGINT 2 2 2 2 2 2 # unix consensus & faked on nt -syscon sig SIGQUIT 3 3 3 3 3 3 # unix consensus & faked on nt -syscon sig SIGILL 4 4 4 4 4 4 # unix consensus & faked on nt -syscon sig SIGTRAP 5 5 5 5 5 5 # unix consensus & faked on nt -syscon sig SIGABRT 6 6 6 6 6 6 # unix consensus & faked on nt -syscon sig SIGIOT 6 6 6 6 6 6 # unix consensus & faked on nt -syscon sig SIGFPE 8 8 8 8 8 8 # unix consensus & faked on nt -syscon sig SIGKILL 9 9 9 9 9 9 # unix consensus & faked on nt -syscon sig SIGSEGV 11 11 11 11 11 11 # unix consensus & faked on nt -syscon sig SIGPIPE 13 13 13 13 13 13 # unix consensus & faked on nt -syscon sig SIGALRM 14 14 14 14 14 14 # unix consensus & faked on nt -syscon sig SIGTERM 15 15 15 15 15 15 # unix consensus & faked on nt -syscon sig SIGTTIN 21 21 21 21 21 21 # unix consensus & faked on nt -syscon sig SIGTTOU 22 22 22 22 22 22 # unix consensus & faked on nt -syscon sig SIGXCPU 24 24 24 24 24 24 # unix consensus & faked on nt -syscon sig SIGXFSZ 25 25 25 25 25 25 # unix consensus & faked on nt -syscon sig SIGVTALRM 26 26 26 26 26 26 # unix consensus & faked on nt -syscon sig SIGPROF 27 27 27 27 27 27 # unix consensus & faked on nt -syscon sig SIGWINCH 28 28 28 28 28 28 # unix consensus & faked on nt -syscon sig SIGBUS 7 10 10 10 10 7 # bsd consensus -syscon sig SIGUSR1 10 30 30 30 30 10 # bsd consensus -syscon sig SIGCHLD 17 20 20 20 20 17 # bsd consensus -syscon sig SIGCONT 18 19 19 19 19 18 # bsd consensus +syscon sig SIGHUP 1 1 1 1 1 1 # terminal hangup or daemon reload; resumable; auto-broadcasted to process group; unix consensus & faked on nt +syscon sig SIGINT 2 2 2 2 2 2 # terminal ctrl-c keystroke; resumable; auto-broadcasted to process group; unix consensus & faked on nt +syscon sig SIGQUIT 3 3 3 3 3 3 # terminal ctrl-\ keystroke; resumable; unix consensus & faked on nt +syscon sig SIGILL 4 4 4 4 4 4 # illegal instruction; unresumable (unless you longjmp() or edit ucontex->rip+=ild(ucontex->rip)); unix consensus & faked on nt +syscon sig SIGTRAP 5 5 5 5 5 5 # int3 instruction; resumable; unix consensus & faked on nt +syscon sig SIGABRT 6 6 6 6 6 6 # process aborted; resumable; unix consensus & faked on nt +syscon sig SIGBUS 7 10 10 10 10 7 # valid memory access that went beyond underlying end of file; bsd consensus +syscon sig SIGFPE 8 8 8 8 8 8 # illegal math; unresumable (unless you longjmp() or edit ucontex->rip+=ild(ucontex->rip)); unix consensus & faked on nt +syscon sig SIGKILL 9 9 9 9 9 9 # terminate with extreme prejudice; unreceivable; unix consensus & faked on nt +syscon sig SIGUSR1 10 30 30 30 30 10 # do whatever you want; bsd consensus +syscon sig SIGSEGV 11 11 11 11 11 11 # invalid memory access; unresumable (unless you longjmp() or edit ucontex->rip+=ild(ucontex->rip)); unix consensus & faked on nt +syscon sig SIGUSR2 12 31 31 31 31 12 # do whatever you want; bsd consensus +syscon sig SIGPIPE 13 13 13 13 13 13 # write to closed file descriptor; unix consensus & faked on nt +syscon sig SIGALRM 14 14 14 14 14 14 # sent by setitimer(2) or timer_settime(2); unix consensus & faked on nt +syscon sig SIGTERM 15 15 15 15 15 15 # terminate; resumable; unix consensus & faked on nt +syscon sig SIGCHLD 17 20 20 20 20 17 # child process exited or terminated and is now a zombie (unless this is SIG_IGN or SA_NOCLDWAIT) or child process stopped due to terminal i/o or profiling/debugging (unless you used SA_NOCLDSTOP); bsd consensus +syscon sig SIGCONT 18 19 19 19 19 18 # child process resumed from profiling/debugging; bsd consensus +syscon sig SIGSTOP 19 17 17 17 17 19 # child process stopped due to profiling/debugging; bsd consensus +syscon sig SIGTSTP 20 18 18 18 18 20 # terminal ctrl-z keystroke; bsd consensus +syscon sig SIGTTIN 21 21 21 21 21 21 # terminal input for background process; resumable; unix consensus & faked on nt +syscon sig SIGTTOU 22 22 22 22 22 22 # terminal output for background process; resumable; unix consensus & faked on nt +syscon sig SIGURG 23 16 16 16 16 23 # bsd consensus +syscon sig SIGXCPU 24 24 24 24 24 24 # cpu time limit exceeded; unix consensus & faked on nt +syscon sig SIGXFSZ 25 25 25 25 25 25 # file size limit exceeded; unix consensus & faked on nt +syscon sig SIGVTALRM 26 26 26 26 26 26 # virtual alarm clock; wut; unix consensus & faked on nt +syscon sig SIGPROF 27 27 27 27 27 27 # profiling timer expired; unix consensus & faked on nt +syscon sig SIGWINCH 28 28 28 28 28 28 # terminal resized; unix consensus & faked on nt syscon sig SIGIO 29 23 23 23 23 29 # bsd consensus -syscon sig SIGSTOP 19 17 17 17 17 19 # bsd consensus -syscon sig SIGSYS 31 12 12 12 12 31 # bsd consensus -syscon sig SIGTSTP 20 18 18 18 18 20 # bsd consensus -syscon sig SIGURG 23 0x10 0x10 0x10 0x10 23 # bsd consensus -syscon sig SIGUSR2 12 31 31 31 31 12 # bsd consensus -syscon sig SIGSTKSZ 0x2000 0x020000 0x8800 0x7000 0x7000 0x2000 -syscon sig SIGPOLL 29 0 0 0 0 29 -syscon sig SIGPWR 30 0 0 0 32 30 -syscon sig SIGSTKFLT 0x10 0 0 0 0 0x10 -syscon sig SIGUNUSED 31 0 0 0 0 31 +syscon sig SIGSYS 31 12 12 12 12 31 # wut; bsd consensus syscon sig SIGRTMAX 0 0 126 0 63 0 syscon sig SIGRTMIN 0 0 65 0 33 0 +syscon compat SIGPOLL 29 23 23 23 23 29 # same as SIGIO +syscon compat SIGIOT 6 6 6 6 6 6 # PDP-11 feature; same as SIGABRT +syscon compat SIGPWR 30 30 30 30 32 30 # not implemented in most community editions of system five; consider doing this using SIGUSR1 or SIGUSR2 instead # open() flags ┌──────hoo boy # ┌──────┐ @@ -232,6 +228,10 @@ syscon open O_EXEC 0 0 0x040000 0 0x4000000 0 syscon open O_TTY_INIT 0 0 0x080000 0 0 0 syscon compat O_LARGEFILE 0 0 0 0 0 0 +# mmap() flags +# the revolutionary praxis of malloc() +# +# group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD NetBSD XENIX Commentary syscon compat MAP_FILE 0 0 0 0 0 0 # consensus syscon mmap MAP_SHARED 1 1 1 1 1 1 # forced consensus & faked nt syscon mmap MAP_PRIVATE 2 2 2 2 2 2 # forced consensus & faked nt @@ -254,6 +254,10 @@ syscon compat MAP_EXECUTABLE 0x1000 0 0 0 0 0 # ignored syscon compat MAP_DENYWRITE 0x0800 0 0 0 0 0 syscon compat MAP_32BIT 0x40 0 0x080000 0 0 0 # iffy +# madvise() flags +# beneath the iceberg memory management +# +# group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD NetBSD XENIX Commentary syscon madv MADV_NORMAL 0 0 0 0 0 0x00000080 # consensus & kNtFileAttributeNormal syscon compat POSIX_FADV_NORMAL 0 0 0 0 0 0x00000080 # consensus & kNtFileAttributeNormal syscon compat POSIX_MADV_NORMAL 0 0 0 0 0 0x00000080 # consensus & kNtFileAttributeNormal @@ -276,7 +280,7 @@ syscon madv MADV_HUGEPAGE 14 0 0 0 0 0 # TODO(jart): why would we syscon madv MADV_NOHUGEPAGE 15 0 0 0 0 0 # TODO(jart): why would we need it? syscon madv MADV_DODUMP 17 0 0 0 0 0 # TODO(jart): what is it? syscon madv MADV_DOFORK 11 0 0 0 0 0 # TODO(jart): what is it? -syscon madv MADV_DONTDUMP 0x10 0 0 0 0 0 # TODO(jart): what is it? +syscon madv MADV_DONTDUMP 16 0 0 0 0 0 # TODO(jart): what is it? syscon madv MADV_DONTFORK 10 0 0 0 0 0 # TODO(jart): what is it? syscon madv MADV_HWPOISON 100 0 0 0 0 0 # TODO(jart): what is it? syscon madv MADV_REMOVE 9 0 0 0 0 0 # TODO(jart): what is it? @@ -293,9 +297,16 @@ syscon mprot PROT_EXEC 4 4 4 4 4 4 # mmap, mprotect, unix consens syscon mprot PROT_GROWSDOWN 0x01000000 0 0 0 0 0 # intended for mprotect; see MAP_GROWSDOWN for mmap() (todo: what was 0x01000000 on nt) syscon mprot PROT_GROWSUP 0x02000000 0 0 0 0 0 # intended for mprotect; see MAP_GROWSDOWN for mmap() +# mremap() flags +# the revolutionary praxis of realloc() +# +# group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD NetBSD XENIX Commentary syscon mremap MREMAP_MAYMOVE 1 1 1 1 1 1 # faked non-linux (b/c linux only) syscon mremap MREMAP_FIXED 2 2 2 2 2 2 # faked non-linux (b/c linux only) +# splice() flags +# +# group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD NetBSD XENIX Commentary syscon splice SPLICE_F_MOVE 1 0 0 0 0 0 # can be safely ignored by polyfill; it's a hint syscon splice SPLICE_F_NONBLOCK 2 0 0 0 0 0 # can be safely ignored by polyfill, since linux says it doesn't apply to underlying FDs syscon splice SPLICE_F_MORE 4 0 0 0 0 0 # can be safely ignored by polyfill; it's a hint @@ -320,7 +331,7 @@ syscon lock LOCK_UN 8 8 8 8 8 8 # unlock [unix consensus & faked # waitpid() / wait4() options # # group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD NetBSD XENIX Commentary -syscon waitpid WNOHANG 1 1 1 1 1 0 # unix consensus +syscon waitpid WNOHANG 1 1 1 1 1 0 # helps you reap zombies; unix consensus syscon waitpid WUNTRACED 2 2 2 2 2 0 # unix consensus syscon waitpid WCONTINUED 8 0x10 4 8 16 0 @@ -334,41 +345,32 @@ syscon waitid WNOWAIT 0x01000000 0x20 8 0 0x10000 0 # stat::st_mode constants # # group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD NetBSD XENIX Commentary -syscon stat S_IFREG 0100000 0100000 0100000 0100000 0100000 0100000 -syscon stat S_IFBLK 0060000 0060000 0060000 0060000 0060000 0060000 -syscon stat S_IFCHR 0020000 0020000 0020000 0020000 0020000 0020000 -syscon stat S_IFDIR 0040000 0040000 0040000 0040000 0040000 0040000 -syscon stat S_IFIFO 0010000 0010000 0010000 0010000 0010000 0010000 -syscon stat S_IFMT 0170000 0170000 0170000 0170000 0170000 0170000 -syscon stat S_IFLNK 0120000 0120000 0120000 0120000 0120000 0120000 -syscon stat S_IFSOCK 0140000 0140000 0140000 0140000 0140000 0140000 - -# chmod() permission flag constants -# consider just typing the octal codes -# -# group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD NetBSD XENIX Commentary -syscon stat S_ISVTX 01000 01000 01000 01000 01000 01000 # unix consensus STICKY BIT -syscon stat S_ISGID 02000 02000 02000 02000 02000 02000 # unix consensus a.k.a. setgid bit -syscon stat S_ISUID 04000 04000 04000 04000 04000 04000 # unix consensus a.k.a. setuid bit - -syscon stat S_IEXEC 00100 00100 00100 00100 00100 00100 # unix consensus -syscon stat S_IWRITE 00200 00200 00200 00200 00200 00200 # unix consensus -syscon stat S_IREAD 00400 00400 00400 00400 00400 00400 # unix consensus - -syscon stat S_IXUSR 00100 00100 00100 00100 00100 00100 # unix consensus -syscon stat S_IWUSR 00200 00200 00200 00200 00200 00200 # unix consensus -syscon stat S_IRUSR 00400 00400 00400 00400 00400 00400 # unix consensus -syscon stat S_IRWXU 00700 00700 00700 00700 00700 00700 # unix consensus - -syscon stat S_IXGRP 00010 00010 00010 00010 00010 00010 # unix consensus -syscon stat S_IWGRP 00020 00020 00020 00020 00020 00020 # unix consensus -syscon stat S_IRGRP 00040 00040 00040 00040 00040 00040 # unix consensus -syscon stat S_IRWXG 00070 00070 00070 00070 00070 00070 # unix consensus - -syscon stat S_IXOTH 00001 00001 00001 00001 00001 00001 # unix consensus -syscon stat S_IWOTH 00002 00002 00002 00002 00002 00002 # unix consensus -syscon stat S_IROTH 00004 00004 00004 00004 00004 00004 # unix consensus -syscon stat S_IRWXO 00007 00007 00007 00007 00007 00007 # unix consensus +syscon stat S_IFREG 0100000 0100000 0100000 0100000 0100000 0100000 # regular file (unix consensus; faked nt) +syscon stat S_IFBLK 0060000 0060000 0060000 0060000 0060000 0060000 # block device (unix consensus; faked nt) +syscon stat S_IFCHR 0020000 0020000 0020000 0020000 0020000 0020000 # character device (unix consensus; faked nt) +syscon stat S_IFDIR 0040000 0040000 0040000 0040000 0040000 0040000 # directory (unix consensus; faked nt) +syscon stat S_IFIFO 0010000 0010000 0010000 0010000 0010000 0010000 # pipe (unix consensus; faked nt) +syscon stat S_IFLNK 0120000 0120000 0120000 0120000 0120000 0120000 # symbolic link (unix consensus; faked nt) +syscon stat S_IFSOCK 0140000 0140000 0140000 0140000 0140000 0140000 # socket (unix consensus; faked nt) +syscon stat S_IFMT 0170000 0170000 0170000 0170000 0170000 0170000 # FILE TYPE MASK (unix consensus; faked nt) +syscon stat S_ISVTX 0001000 0001000 0001000 0001000 0001000 0001000 # THE STICKY BIT (unix consensus; faked nt) +syscon stat S_ISGID 0002000 0002000 0002000 0002000 0002000 0002000 # the setgid bit (unix consensus; faked nt) +syscon stat S_ISUID 0004000 0004000 0004000 0004000 0004000 0004000 # the setuid bit (unix consensus; faked nt) +syscon stat S_IEXEC 0000100 0000100 0000100 0000100 0000100 0000100 # just use octal (unix consensus; faked nt) +syscon stat S_IWRITE 0000200 0000200 0000200 0000200 0000200 0000200 # just use octal (unix consensus; faked nt) +syscon stat S_IREAD 0000400 0000400 0000400 0000400 0000400 0000400 # just use octal (unix consensus; faked nt) +syscon stat S_IXUSR 0000100 0000100 0000100 0000100 0000100 0000100 # just use octal (unix consensus; faked nt) +syscon stat S_IWUSR 0000200 0000200 0000200 0000200 0000200 0000200 # just use octal (unix consensus; faked nt) +syscon stat S_IRUSR 0000400 0000400 0000400 0000400 0000400 0000400 # just use octal (unix consensus; faked nt) +syscon stat S_IRWXU 0000700 0000700 0000700 0000700 0000700 0000700 # just use octal (unix consensus; faked nt) +syscon stat S_IXGRP 0000010 0000010 0000010 0000010 0000010 0000010 # just use octal (unix consensus; faked nt) +syscon stat S_IWGRP 0000020 0000020 0000020 0000020 0000020 0000020 # just use octal (unix consensus; faked nt) +syscon stat S_IRGRP 0000040 0000040 0000040 0000040 0000040 0000040 # just use octal (unix consensus; faked nt) +syscon stat S_IRWXG 0000070 0000070 0000070 0000070 0000070 0000070 # just use octal (unix consensus; faked nt) +syscon stat S_IXOTH 0000001 0000001 0000001 0000001 0000001 0000001 # just use octal (unix consensus; faked nt) +syscon stat S_IWOTH 0000002 0000002 0000002 0000002 0000002 0000002 # just use octal (unix consensus; faked nt) +syscon stat S_IROTH 0000004 0000004 0000004 0000004 0000004 0000004 # just use octal (unix consensus; faked nt) +syscon stat S_IRWXO 0000007 0000007 0000007 0000007 0000007 0000007 # just use octal (unix consensus; faked nt) # fcntl() # @@ -428,17 +430,24 @@ syscon at AT_EACCESS 0x0200 0x10 0x0100 1 0x100 0 syscon at AT_SYMLINK_FOLLOW 0x0400 0x40 0x0400 4 4 0 syscon at AT_EMPTY_PATH 0x1000 0 0 0 0 0 # linux 2.6.39+; see unlink, O_TMPFILE, etc. +# memfd_create() flags +# +# Unsupported flags are encoded as 0. +# +# group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD NetBSD XENIX Commentary syscon memfd MFD_CLOEXEC 1 0 0 0 0 0 syscon memfd MFD_ALLOW_SEALING 2 0 0 0 0 0 -# utimensat() +# utimensat() special values # # group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD NetBSD XENIX Commentary -syscon utime UTIME_NOW 0x3fffffff 0x3fffffff -1 -2 0x3fffffff -2 # polyfilled xnu/nt -syscon utime UTIME_OMIT 0x3ffffffe 0x3ffffffe -2 -1 0x3ffffffe -1 # polyfilled xnu/nt +syscon utime UTIME_NOW 0x3fffffff 0x3fffffff -1 -2 0x3fffffff -2 # timespec::tv_sec may be this; polyfilled xnu/nt +syscon utime UTIME_OMIT 0x3ffffffe 0x3ffffffe -2 -1 0x3ffffffe -1 # timespec::tv_nsec may be this; polyfilled xnu/nt # getauxval() keys # +# Unsupported values are encoded as 0. +# # group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD NetBSD XENIX Commentary syscon auxv AT_EXECFD 2 0 2 0 2 0 # file descriptor of program syscon auxv AT_PHDR 3 0 3 0 3 0 # address of program headers of executable @@ -468,81 +477,121 @@ syscon auxv AT_EXECFN 31 31 999 999 2014 31 # address of string c syscon auxv AT_SYSINFO_EHDR 33 0 0 0 0 0 syscon auxv AT_NO_AUTOMOUNT 0x0800 0 0 0 0 0 -# ptrace() codes +# getrlimit() / setrlimit() resource parameter +# +# Unsupported values are encoded as 127. # # group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD NetBSD XENIX Commentary -syscon ptrace PTRACE_TRACEME 0 0 0 0 -1 -1 # unix consensus a.k.a. PT_TRACE_ME -syscon ptrace PTRACE_PEEKTEXT 1 1 1 1 -1 -1 # unix consensus a.k.a. PT_READ_I -syscon ptrace PTRACE_PEEKDATA 2 2 2 2 -1 -1 # unix consensus a.k.a. PT_READ_D -syscon ptrace PTRACE_PEEKUSER 3 3 -1 -1 -1 -1 # a.k.a. PT_READ_U -syscon ptrace PTRACE_POKETEXT 4 4 4 4 -1 -1 # unix consensus a.k.a. PT_WRITE_I -syscon ptrace PTRACE_POKEDATA 5 5 5 5 -1 -1 # unix consensus a.k.a. PT_WRITE_D -syscon ptrace PTRACE_POKEUSER 6 6 -1 -1 -1 -1 # a.k.a. PT_WRITE_U -syscon ptrace PTRACE_CONT 7 7 7 7 -1 -1 # unix consensus a.k.a. PT_CONTINUE -syscon ptrace PTRACE_KILL 8 8 8 8 -1 -1 # unix consensus a.k.a. PT_KILL -syscon ptrace PTRACE_SINGLESTEP 9 9 9 32 -1 -1 # a.k.a. PT_STEP -syscon ptrace PTRACE_GETREGS 12 -1 33 33 -1 -1 # a.k.a. PT_GETREGS -syscon ptrace PTRACE_SETREGS 13 -1 34 34 -1 -1 # a.k.a. PT_SETREGS -syscon ptrace PTRACE_GETFPREGS 14 -1 35 35 -1 -1 # a.k.a. PT_GETFPREGS -syscon ptrace PTRACE_SETFPREGS 15 -1 36 36 -1 -1 # a.k.a. PT_SETFPREGS -syscon ptrace PTRACE_ATTACH 16 10 10 9 -1 -1 # a.k.a. PT_ATTACH -syscon ptrace PTRACE_DETACH 17 11 11 10 -1 -1 # a.k.a. PT_DETACH -syscon ptrace PTRACE_GETFPXREGS 18 -1 -1 -1 -1 -1 # a.k.a. PT_GETFPXREGS -syscon ptrace PTRACE_SETFPXREGS 19 -1 -1 -1 -1 -1 # a.k.a. PT_SETFPXREGS -syscon ptrace PTRACE_SYSCALL 24 -1 22 -1 -1 -1 # a.k.a. PT_SYSCALL -syscon ptrace PTRACE_GETEVENTMSG 0x4201 -1 -1 -1 -1 -1 -syscon ptrace PTRACE_GETSIGINFO 0x4202 -1 -1 -1 -1 -1 -syscon ptrace PTRACE_SETOPTIONS 0x4200 -1 -1 -1 -1 -1 -syscon ptrace PTRACE_SETSIGINFO 0x4203 -1 -1 -1 -1 -1 -syscon ptrace PTRACE_GETREGSET 0x4204 -1 -1 -1 -1 -1 -syscon ptrace PTRACE_GETSIGMASK 0x420a -1 -1 -1 -1 -1 -syscon ptrace PTRACE_INTERRUPT 0x4207 -1 -1 -1 -1 -1 -syscon ptrace PTRACE_LISTEN 0x4208 -1 -1 -1 -1 -1 -syscon ptrace PTRACE_PEEKSIGINFO 0x4209 -1 -1 -1 -1 -1 -syscon ptrace PTRACE_SECCOMP_GET_FILTER 0x420c -1 -1 -1 -1 -1 -syscon ptrace PTRACE_SEIZE 0x4206 -1 -1 -1 -1 -1 -syscon ptrace PTRACE_SETREGSET 0x4205 -1 -1 -1 -1 -1 -syscon ptrace PTRACE_SETSIGMASK 0x420b -1 -1 -1 -1 -1 -syscon ptrace PTRACE_O_TRACESYSGOOD 0x0001 -1 -1 -1 -1 -1 -syscon ptrace PTRACE_O_TRACEFORK 0x0002 -1 -1 -1 -1 -1 -syscon ptrace PTRACE_O_TRACEVFORK 0x0004 -1 -1 -1 -1 -1 -syscon ptrace PTRACE_O_TRACECLONE 0x0008 -1 -1 -1 -1 -1 -syscon ptrace PTRACE_O_TRACEEXEC 0x0010 -1 -1 -1 -1 -1 -syscon ptrace PTRACE_O_TRACEVFORKDONE 0x0020 -1 -1 -1 -1 -1 -syscon ptrace PTRACE_O_TRACEEXIT 0x0040 -1 -1 -1 -1 -1 -syscon ptrace PTRACE_O_MASK 0x007f -1 -1 -1 -1 -1 -syscon ptrace PTRACE_EVENT_FORK 1 -1 -1 -1 -1 -1 -syscon ptrace PTRACE_EVENT_VFORK 2 -1 -1 -1 -1 -1 -syscon ptrace PTRACE_EVENT_CLONE 3 -1 -1 -1 -1 -1 -syscon ptrace PTRACE_EVENT_EXEC 4 -1 -1 -1 -1 -1 -syscon ptrace PTRACE_EVENT_VFORK_DONE 5 -1 -1 -1 -1 -1 -syscon ptrace PTRACE_EVENT_EXIT 6 -1 -1 -1 -1 -1 +syscon rlimit RLIMIT_CPU 0 0 0 0 0 127 # max cpu time in seconds; see SIGXCPU; unix consensus +syscon rlimit RLIMIT_FSIZE 1 1 1 1 1 127 # max file size in bytes; unix consensus +syscon rlimit RLIMIT_DATA 2 2 2 2 2 127 # max mmap() / brk() / sbrk() size in bytes; unix consensus +syscon rlimit RLIMIT_STACK 3 3 3 3 3 127 # max stack size in bytes; see SIGXFSZ; unix consensus +syscon rlimit RLIMIT_CORE 4 4 4 4 4 127 # max core file size in bytes; unix consensus +syscon rlimit RLIMIT_RSS 5 5 5 5 5 127 # max physical memory size in bytes; see mmap()→ENOMEM; unix consensus +syscon rlimit RLIMIT_NPROC 6 7 7 7 7 127 # max number of processes; see fork()→EAGAIN; bsd consensus +syscon rlimit RLIMIT_NOFILE 7 8 8 8 8 127 # max number of open files; see accept()→EMFILE/ENFILE; bsd consensus +syscon rlimit RLIMIT_MEMLOCK 8 6 6 6 6 127 # max locked-in-memory address space; bsd consensus +syscon rlimit RLIMIT_AS 9 5 10 127 10 127 # max virtual memory size in bytes +syscon rlimit RLIMIT_LOCKS 10 127 127 127 127 127 # max flock() / fcntl() locks; bsd consensus +syscon rlimit RLIMIT_SIGPENDING 11 127 127 127 127 127 # max sigqueue() can enqueue; bsd consensus +syscon rlimit RLIMIT_MSGQUEUE 12 127 127 127 127 127 # meh posix message queues; bsd consensus +syscon rlimit RLIMIT_NICE 13 127 127 127 127 127 # max scheduling priority; 𝑥 ∈ [1,40]; niceness is traditionally displayed as as 𝟸𝟶-𝑥, therefore 𝑥=1 (lowest priority) prints as 19 and 𝑥=40 (highest priority) prints as -20; bsd consensus +syscon rlimit RLIMIT_RTPRIO 14 127 127 127 127 127 # bsd consensus +syscon compat RLIMIT_VMEM 9 5 10 127 10 127 # same as RLIMIT_AS + +# resource limit special values +# +# group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD NetBSD XENIX Commentary +syscon rlim RLIM_NLIMITS 16 9 15 9 12 0 # no clue why we need it +syscon rlim RLIM_INFINITY 0xffffffffffffffff 0x7fffffffffffffff 0x7fffffffffffffff 0x7fffffffffffffff 0x7fffffffffffffff 0 +syscon rlim RLIM_SAVED_CUR 0xffffffffffffffff 0x7fffffffffffffff 0x7fffffffffffffff 0x7fffffffffffffff 0x7fffffffffffffff 0 +syscon rlim RLIM_SAVED_MAX 0xffffffffffffffff 0x7fffffffffffffff 0x7fffffffffffffff 0x7fffffffffffffff 0x7fffffffffffffff 0 # sigaction() codes # # group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD NetBSD XENIX Commentary -syscon sigact SA_RESTORER 0x04000000 0 0 0 0 0 -syscon sigact SA_ONSTACK 0x08000000 1 1 1 1 0 # bsd consensus -syscon sigact SA_RESTART 0x10000000 2 2 2 2 0 # bsd consensus -syscon sigact SA_NOCLDSTOP 1 8 8 8 8 0 # bsd consensus -syscon sigact SA_NOCLDWAIT 2 0x20 0x20 0x20 0x20 0 # bsd consensus -syscon sigact SA_SIGINFO 4 0x40 0x40 0x40 0x40 0 # bsd consensus -syscon sigact SA_NODEFER 0x40000000 0x10 0x10 0x10 0x10 0 # bsd consensus -syscon sigact SA_NOMASK 0x40000000 0x10 0x10 0x10 0x10 0 # linux/obsolete -syscon sigact SA_RESETHAND 0x80000000 4 4 4 4 0 # bsd consensus -syscon sigact SA_ONESHOT 0x80000000 0 0 0 0 0 +syscon sigact SA_NOCLDSTOP 1 8 8 8 8 1 # lets you set SIGCHLD handler that's only notified on exit/termination and not notified on SIGSTOP/SIGTSTP/SIGTTIN/SIGTTOU/SIGCONT lool; bsd consensus +syscon sigact SA_NOCLDWAIT 2 32 32 32 32 2 # changes SIGCHLD so the zombie is gone and you can't call wait(2) anymore; similar to SIGCHLD+SIG_IGN but may still deliver the SIGCHLD; bsd consensus +syscon sigact SA_SIGINFO 4 64 64 64 64 4 # asks kernel to provide ucontext_t argument, which has mutable cpu/fpu state of signalled process; and it is polyfilled by cosmopolitan; bsd consensus +syscon sigact SA_ONSTACK 0x08000000 1 1 1 1 0x08000000 # causes signal handler to be called on stack provided by sigaltstack(2); bsd consensus +syscon sigact SA_RESTART 0x10000000 2 2 2 2 0x10000000 # prevents signal delivery from triggering EINTR on i/o calls (e.g. read/write/open/wait/accept) but doesn't impact non-i/o blocking calls (e.g. poll, sigsuspend, nanosleep) which will still EINTR; bsd consensus +syscon sigact SA_NODEFER 0x40000000 16 16 16 16 0x40000000 # blocks signal delivery during signal handling (i.e. lets you use longjmp() in the signal handler); bsd consensus +syscon sigact SA_RESETHAND 0x80000000 4 4 4 4 0x80000000 # causes signal handler to be called at most once and then set to SIG_DFL automatically; bsd consensus +syscon compat SA_NOMASK 0x40000000 16 16 16 16 0x40000000 # same as SA_NODEFER +syscon compat SA_ONESHOT 0x80000000 4 4 4 4 0x80000000 # same as SA_RESETHAND +# siginfo::si_code values +# +# Windows NT is polyfilled as Linux. +# Unsupported values are encoded as 0x80000000. +# +# group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD NetBSD XENIX Commentary +syscon sicode SI_USER 0 0x010001 0x010001 0 0 0 # sent by kill(2); openbsd defines si_code<=0 as originating from user +syscon sicode SI_QUEUE -1 0x010002 0x010002 -2 -1 -1 # sent by sigqueue(2) +syscon sicode SI_TIMER -2 0x010003 0x010003 -3 -2 -2 # sent by setitimer(2) or clock_settime(2) +syscon sicode SI_TKILL -6 0x80000000 0x010007 -1 -5 -6 # sent by tkill(2) or tgkill(2) or thr_kill(2) or lwp_kill(2) or _lwp_kill(2); cries +syscon sicode SI_MESGQ -3 0x010005 0x010005 0x80000000 -4 -3 # sent by mq_notify(2); lool +syscon sicode SI_ASYNCIO -4 0x010004 0x010004 0x80000000 -3 -4 # aio completion; no thank you +syscon sicode SI_ASYNCNL -60 0x80000000 0x80000000 0x80000000 0x80000000 0x80000000 # aio completion for dns; the horror +syscon sicode SI_KERNEL 0x80 0x80000000 0x010006 0x80000000 0x80000000 0x80 # wut; openbsd defines as si_code>0 +syscon sicode SI_NOINFO 32767 0x80000000 0 32767 32767 32767 # no signal specific info available +syscon sicode CLD_EXITED 1 1 1 1 1 1 # SIGCHLD; child exited; unix consensus +syscon sicode CLD_KILLED 2 2 2 2 2 2 # SIGCHLD; child terminated w/o core; unix consensus +syscon sicode CLD_DUMPED 3 3 3 3 3 3 # SIGCHLD; child terminated w/ core; unix consensus +syscon sicode CLD_TRAPPED 4 4 4 4 4 4 # SIGCHLD; traced child trapped; unix consensus +syscon sicode CLD_STOPPED 5 5 5 5 5 5 # SIGCHLD; child stopped; unix consensus +syscon sicode CLD_CONTINUED 6 6 6 6 6 6 # SIGCHLD; stopped child continued; unix consensus +syscon sicode TRAP_BRKPT 1 1 1 1 1 1 # SIGTRAP; unix consensus +syscon sicode TRAP_TRACE 2 2 2 2 2 2 # SIGTRAP; unix consensus +syscon sicode SEGV_MAPERR 1 1 1 1 1 1 # SIGSEGV; unix consensus +syscon sicode SEGV_ACCERR 2 2 2 2 2 2 # SIGSEGV; unix consensus +syscon sicode FPE_INTDIV 1 7 2 1 1 1 # SIGFPE; integer divide by zero +syscon sicode FPE_INTOVF 2 8 1 2 2 2 # SIGFPE; integer overflow +syscon sicode FPE_FLTDIV 3 1 3 3 3 3 # SIGFPE; floating point divide by zero +syscon sicode FPE_FLTOVF 4 2 4 4 4 4 # SIGFPE; floating point overflow +syscon sicode FPE_FLTUND 5 3 5 5 5 5 # SIGFPE; floating point underflow +syscon sicode FPE_FLTRES 6 4 6 6 6 6 # SIGFPE; floating point inexact +syscon sicode FPE_FLTINV 7 5 7 7 7 7 # SIGFPE; invalid floating point operation +syscon sicode FPE_FLTSUB 8 6 8 8 8 8 # SIGFPE; subscript out of range +syscon sicode ILL_ILLOPC 1 1 1 1 1 1 # SIGILL; illegal opcode; unix consensus +syscon sicode ILL_ILLOPN 2 4 2 2 2 2 # SIGILL; illegal operand +syscon sicode ILL_ILLADR 3 5 3 3 3 3 # SIGILL; illegal addressing mode +syscon sicode ILL_ILLTRP 4 2 4 4 4 4 # SIGILL; illegal trap +syscon sicode ILL_PRVOPC 5 3 5 5 5 5 # SIGILL; privileged opcode +syscon sicode ILL_PRVREG 6 6 6 6 6 6 # SIGILL; privileged register; unix consensus +syscon sicode ILL_COPROC 7 7 7 7 7 7 # SIGILL; coprocessor error; unix consensus +syscon sicode ILL_BADSTK 8 8 8 8 8 8 # SIGILL; internal stack error; unix consensus +syscon sicode BUS_ADRALN 1 1 1 1 1 1 # SIGBUS; invalid address alignment; unix consensus +syscon sicode BUS_ADRERR 2 2 2 2 2 2 # SIGBUS; non-existent physical address; unix consensus +syscon sicode BUS_OBJERR 3 3 3 3 3 3 # SIGBUS; object specific hardware error; unix consensus +syscon sicode BUS_MCEERR_AR 4 0x80000000 0x80000000 0x80000000 0x80000000 0x80000000 # SIGBUS; Linux 2.6.32+ +syscon sicode BUS_MCEERR_AO 5 0x80000000 0x80000000 0x80000000 0x80000000 0x80000000 # SIGBUS; Linux 2.6.32+ +syscon sicode POLL_IN 1 1 1 1 1 1 # SIGIO; data input available; unix consensus +syscon sicode POLL_OUT 2 2 2 2 2 2 # SIGIO; output buffer available; unix consensus +syscon sicode POLL_MSG 3 3 3 3 3 3 # SIGIO; input message available; unix consensus +syscon sicode POLL_ERR 4 4 4 4 4 4 # SIGIO; i/o error; unix consensus +syscon sicode POLL_PRI 5 5 5 5 5 5 # SIGIO; high priority input available; unix consensus +syscon sicode POLL_HUP 6 6 6 6 6 6 # SIGIO; device disconnected; unix consensus + +# sigalstack() values +# +# group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD NetBSD XENIX Commentary +syscon ss SIGSTKSZ 0x2000 0x020000 0x8800 0x7000 0x7000 0x2000 + +# clock_{gettime,settime} timers +# +# group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD NetBSD XENIX Commentary syscon clock CLOCK_REALTIME 0 0 0 0 0 0 # consensus -syscon clock CLOCK_MONOTONIC 1 1 4 3 3 1 # XNU/NT faked -syscon clock CLOCK_PROCESS_CPUTIME_ID 2 0 15 2 0x40000000 0 -syscon clock CLOCK_THREAD_CPUTIME_ID 3 0 14 4 0x20000000 0 -syscon clock CLOCK_MONOTONIC_RAW 4 4 0x4000 0x4000 0x4000 4 # XNU/NT/FreeBSD/OpenBSD faked, not available on RHEL5 -syscon clock CLOCK_REALTIME_COARSE 5 0 0 0 0 0 # bsd consensus -syscon clock CLOCK_MONOTONIC_COARSE 6 0 0 0 0 0 # bsd consensus -syscon clock CLOCK_BOOTTIME 7 0 0 6 6 0 -syscon clock CLOCK_REALTIME_ALARM 8 0 0 0 0 0 # bsd consensus -syscon clock CLOCK_BOOTTIME_ALARM 9 0 0 0 0 0 # bsd consensus -syscon clock CLOCK_TAI 11 0 0 0 0 0 # bsd consensus +syscon clock CLOCK_MONOTONIC 1 1 4 3 3 1 # XNU/NT faked; could move backwards if NTP introduces negative leap second +syscon clock CLOCK_PROCESS_CPUTIME_ID 2 -1 15 2 0x40000000 -1 +syscon clock CLOCK_THREAD_CPUTIME_ID 3 -1 14 4 0x20000000 -1 +syscon clock CLOCK_MONOTONIC_RAW 4 4 0x4000 0x4000 0x4000 4 # actually monotonic; not subject to NTP adjustments; Linux 2.6.28+; XNU/NT/FreeBSD/OpenBSD faked; not available on RHEL5 +syscon clock CLOCK_REALTIME_COARSE 5 -1 -1 -1 -1 -1 # Linux 2.6.32+; bsd consensus; not available on RHEL5 +syscon clock CLOCK_MONOTONIC_COARSE 6 -1 -1 -1 -1 -1 # Linux 2.6.32+; bsd consensus; not available on RHEL5 +syscon clock CLOCK_BOOTTIME 7 -1 -1 6 6 -1 +syscon clock CLOCK_REALTIME_ALARM 8 -1 -1 -1 -1 -1 # bsd consensus +syscon clock CLOCK_BOOTTIME_ALARM 9 -1 -1 -1 -1 -1 # bsd consensus +syscon clock CLOCK_TAI 11 -1 -1 -1 -1 -1 # bsd consensus # epoll # @@ -586,7 +635,7 @@ syscon so SO_OOBINLINE 10 0x0100 0x0100 0x0100 0x0100 0x0100 # bs syscon so SO_SNDBUF 7 0x1001 0x1001 0x1001 0x1001 0x1001 # bsd consensus syscon so SO_RCVBUF 8 0x1002 0x1002 0x1002 0x1002 0x1002 # bsd consensus syscon so SO_RCVLOWAT 18 0x1004 0x1004 0x1004 0x1004 0x1004 # bsd consensus -syscon so SO_RCVTIMEO 20 0x1006 0x1006 0x1006 0x100c 0x1006 # bsd consensus +syscon so SO_RCVTIMEO 20 0x1006 0x1006 0x1006 0x100c 0x1006 # overrides SA_RESTART restoring EINTR behavior on recv/send/connect/accept/etc.; bsd consensus syscon so SO_EXCLUSIVEADDRUSE 0 0 0 0 0 0xfffffffb # hoo boy syscon so SO_SNDLOWAT 19 0x1003 0x1003 0x1003 0x1003 0x1003 # bsd consensus syscon so SO_SNDTIMEO 21 0x1005 0x1005 0x1005 0x100b 0x1005 # bsd consensus @@ -699,6 +748,56 @@ syscon tcp TCP_REPAIR_OPTIONS 22 0 0 0 0 0 # what is it syscon tcp TCP_REPAIR_QUEUE 20 0 0 0 0 0 # what is it syscon tcp TCP_THIN_LINEAR_TIMEOUTS 16 0 0 0 0 0 # what is it +# ptrace() codes +# +# group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD NetBSD XENIX Commentary +syscon ptrace PTRACE_TRACEME 0 0 0 0 -1 -1 # unix consensus a.k.a. PT_TRACE_ME +syscon ptrace PTRACE_PEEKTEXT 1 1 1 1 -1 -1 # unix consensus a.k.a. PT_READ_I +syscon ptrace PTRACE_PEEKDATA 2 2 2 2 -1 -1 # unix consensus a.k.a. PT_READ_D +syscon ptrace PTRACE_PEEKUSER 3 3 -1 -1 -1 -1 # a.k.a. PT_READ_U +syscon ptrace PTRACE_POKETEXT 4 4 4 4 -1 -1 # unix consensus a.k.a. PT_WRITE_I +syscon ptrace PTRACE_POKEDATA 5 5 5 5 -1 -1 # unix consensus a.k.a. PT_WRITE_D +syscon ptrace PTRACE_POKEUSER 6 6 -1 -1 -1 -1 # a.k.a. PT_WRITE_U +syscon ptrace PTRACE_CONT 7 7 7 7 -1 -1 # unix consensus a.k.a. PT_CONTINUE +syscon ptrace PTRACE_KILL 8 8 8 8 -1 -1 # unix consensus a.k.a. PT_KILL +syscon ptrace PTRACE_SINGLESTEP 9 9 9 32 -1 -1 # a.k.a. PT_STEP +syscon ptrace PTRACE_GETREGS 12 -1 33 33 -1 -1 # a.k.a. PT_GETREGS +syscon ptrace PTRACE_SETREGS 13 -1 34 34 -1 -1 # a.k.a. PT_SETREGS +syscon ptrace PTRACE_GETFPREGS 14 -1 35 35 -1 -1 # a.k.a. PT_GETFPREGS +syscon ptrace PTRACE_SETFPREGS 15 -1 36 36 -1 -1 # a.k.a. PT_SETFPREGS +syscon ptrace PTRACE_ATTACH 16 10 10 9 -1 -1 # a.k.a. PT_ATTACH +syscon ptrace PTRACE_DETACH 17 11 11 10 -1 -1 # a.k.a. PT_DETACH +syscon ptrace PTRACE_GETFPXREGS 18 -1 -1 -1 -1 -1 # a.k.a. PT_GETFPXREGS +syscon ptrace PTRACE_SETFPXREGS 19 -1 -1 -1 -1 -1 # a.k.a. PT_SETFPXREGS +syscon ptrace PTRACE_SYSCALL 24 -1 22 -1 -1 -1 # a.k.a. PT_SYSCALL +syscon ptrace PTRACE_GETEVENTMSG 0x4201 -1 -1 -1 -1 -1 +syscon ptrace PTRACE_GETSIGINFO 0x4202 -1 -1 -1 -1 -1 +syscon ptrace PTRACE_SETOPTIONS 0x4200 -1 -1 -1 -1 -1 +syscon ptrace PTRACE_SETSIGINFO 0x4203 -1 -1 -1 -1 -1 +syscon ptrace PTRACE_GETREGSET 0x4204 -1 -1 -1 -1 -1 +syscon ptrace PTRACE_GETSIGMASK 0x420a -1 -1 -1 -1 -1 +syscon ptrace PTRACE_INTERRUPT 0x4207 -1 -1 -1 -1 -1 +syscon ptrace PTRACE_LISTEN 0x4208 -1 -1 -1 -1 -1 +syscon ptrace PTRACE_PEEKSIGINFO 0x4209 -1 -1 -1 -1 -1 +syscon ptrace PTRACE_SECCOMP_GET_FILTER 0x420c -1 -1 -1 -1 -1 +syscon ptrace PTRACE_SEIZE 0x4206 -1 -1 -1 -1 -1 +syscon ptrace PTRACE_SETREGSET 0x4205 -1 -1 -1 -1 -1 +syscon ptrace PTRACE_SETSIGMASK 0x420b -1 -1 -1 -1 -1 +syscon ptrace PTRACE_O_TRACESYSGOOD 0x0001 -1 -1 -1 -1 -1 +syscon ptrace PTRACE_O_TRACEFORK 0x0002 -1 -1 -1 -1 -1 +syscon ptrace PTRACE_O_TRACEVFORK 0x0004 -1 -1 -1 -1 -1 +syscon ptrace PTRACE_O_TRACECLONE 0x0008 -1 -1 -1 -1 -1 +syscon ptrace PTRACE_O_TRACEEXEC 0x0010 -1 -1 -1 -1 -1 +syscon ptrace PTRACE_O_TRACEVFORKDONE 0x0020 -1 -1 -1 -1 -1 +syscon ptrace PTRACE_O_TRACEEXIT 0x0040 -1 -1 -1 -1 -1 +syscon ptrace PTRACE_O_MASK 0x007f -1 -1 -1 -1 -1 +syscon ptrace PTRACE_EVENT_FORK 1 -1 -1 -1 -1 -1 +syscon ptrace PTRACE_EVENT_VFORK 2 -1 -1 -1 -1 -1 +syscon ptrace PTRACE_EVENT_CLONE 3 -1 -1 -1 -1 -1 +syscon ptrace PTRACE_EVENT_EXEC 4 -1 -1 -1 -1 -1 +syscon ptrace PTRACE_EVENT_VFORK_DONE 5 -1 -1 -1 -1 -1 +syscon ptrace PTRACE_EVENT_EXIT 6 -1 -1 -1 -1 -1 + syscon iproto IPPROTO_IP 0 0 0 0 0 0 # consensus syscon iproto IPPROTO_ICMP 1 1 1 1 1 1 # consensus syscon iproto IPPROTO_TCP 6 6 6 6 6 6 # consensus @@ -1318,13 +1417,6 @@ syscon poll POLLWRBAND 0x0200 0x0100 0x0100 0x0100 0x0100 0x20 # syscon poll POLLWRNORM 0x0100 4 4 4 4 0x10 # bsd consensus syscon poll POLLRDHUP 0x2000 0x10 0x10 0x10 0x10 2 # bsd consensus (POLLHUP on non-Linux) -syscon sigpoll POLL_ERR 4 4 4 0 0 0 -syscon sigpoll POLL_HUP 6 6 6 0 0 0 -syscon sigpoll POLL_IN 1 1 1 0 0 0 -syscon sigpoll POLL_MSG 3 3 3 0 0 0 -syscon sigpoll POLL_OUT 2 2 2 0 0 0 -syscon sigpoll POLL_PRI 5 5 5 0 0 0 - syscon c C_IXOTH 0000001 0000001 0000001 0000001 0000001 0 # unix consensus syscon c C_IWOTH 0000002 0000002 0000002 0000002 0000002 0 # unix consensus syscon c C_IROTH 0000004 0000004 0000004 0000004 0000004 0 # unix consensus @@ -1547,23 +1639,6 @@ syscon nd ND_ROUTER_ADVERT 134 134 134 134 134 0 # unix consensus syscon nd ND_ROUTER_SOLICIT 133 133 133 133 133 0 # unix consensus syscon nd ND_RA_FLAG_HOME_AGENT 0x20 0 0 0 0 0x20 # bsd consensus -syscon rlim RLIMIT_CPU 0 0 0 0 0 127 # unix consensus -syscon rlim RLIMIT_FSIZE 1 1 1 1 1 127 # unix consensus -syscon rlim RLIMIT_DATA 2 2 2 2 2 127 # unix consensus -syscon rlim RLIMIT_STACK 3 3 3 3 3 127 # unix consensus -syscon rlim RLIMIT_CORE 4 4 4 4 4 127 # unix consensus -syscon rlim RLIMIT_RSS 5 5 5 5 5 127 # unix consensus -syscon rlim RLIMIT_NPROC 6 7 7 7 7 127 # bsd consensus -syscon rlim RLIMIT_NOFILE 7 8 8 8 8 127 # bsd consensus -syscon rlim RLIMIT_MEMLOCK 8 6 6 6 6 127 # bsd consensus -syscon rlim RLIMIT_AS 9 5 10 127 127 127 -syscon rlim RLIMIT_LOCKS 10 127 127 127 127 127 # bsd consensus -syscon rlim RLIMIT_SIGPENDING 11 127 127 127 127 127 # bsd consensus -syscon rlim RLIMIT_MSGQUEUE 12 127 127 127 127 127 # bsd consensus -syscon rlim RLIMIT_NICE 13 127 127 127 127 127 # bsd consensus -syscon rlim RLIMIT_RTPRIO 14 127 127 127 127 127 # bsd consensus -syscon rlim RLIMIT_NLIMITS 16 127 127 127 127 127 # bsd consensus - syscon misc TCFLSH 0x540b 0 0 0 0 0 syscon misc TCIFLUSH 0 1 1 1 1 0 # bsd consensus syscon misc TCIOFF 2 3 3 3 3 0 # bsd consensus @@ -1771,13 +1846,7 @@ syscon misc SCSI_IOCTL_SYNC 4 0 0 0 0 0 syscon misc SCSI_IOCTL_TAGGED_DISABLE 0x5384 0 0 0 0 0 syscon misc SCSI_IOCTL_TAGGED_ENABLE 0x5383 0 0 0 0 0 syscon misc SCSI_IOCTL_TEST_UNIT_READY 2 0 0 0 0 0 - -syscon misc CLD_CONTINUED 6 6 6 6 6 6 # unix consensus -syscon misc CLD_DUMPED 3 3 3 3 3 3 # unix consensus -syscon misc CLD_EXITED 1 1 1 1 1 1 # unix consensus -syscon misc CLD_KILLED 2 2 2 2 2 2 # unix consensus -syscon misc CLD_STOPPED 5 5 5 5 5 5 # unix consensus -syscon misc CLD_TRAPPED 4 4 4 4 4 4 # unix consensus +syscon misc BUS_DEVICE_RESET 12 0 0 0 0 0 # SIGBUS; syscon misc READ_10 40 0 0 0 0 0 syscon misc READ_12 168 0 0 0 0 0 @@ -1838,15 +1907,6 @@ syscon misc WRITE_SAME 65 0 0 0 0 0 syscon misc WRITE_VERIFY 46 0 0 0 0 0 syscon misc WRITE_VERIFY_12 174 0 0 0 0 0 -syscon misc ILL_BADSTK 8 8 8 8 8 0 # unix consensus -syscon misc ILL_COPROC 7 7 7 7 7 0 # unix consensus -syscon misc ILL_ILLOPC 1 1 1 1 1 0 # unix consensus -syscon misc ILL_PRVREG 6 6 6 6 6 0 # unix consensus -syscon misc ILL_ILLADR 3 5 3 3 3 0 -syscon misc ILL_ILLOPN 2 4 2 2 2 0 -syscon misc ILL_ILLTRP 4 2 4 4 4 0 -syscon misc ILL_PRVOPC 5 3 5 5 5 0 - syscon lock LOCK_UNLOCK_CACHE 54 0 0 0 0 0 # wut syscon misc ARPHRD_ETHER 1 1 1 1 1 0 # unix consensus @@ -1858,13 +1918,6 @@ syscon misc ARPHRD_IEEE802154 804 0 0 0 0 0 syscon misc ARPHRD_IEEE802_TR 800 0 0 0 0 0 syscon misc ARPHRD_LOCALTLK 773 0 0 0 0 0 -syscon misc BUS_ADRALN 1 1 1 1 1 0 # unix consensus -syscon misc BUS_ADRERR 2 2 2 2 2 0 # unix consensus -syscon misc BUS_OBJERR 3 3 3 3 3 0 # unix consensus -syscon misc BUS_DEVICE_RESET 12 0 0 0 0 0 -syscon misc BUS_MCEERR_AO 5 0 0 0 0 0 -syscon misc BUS_MCEERR_AR 4 0 0 0 0 0 - syscon misc IP6F_MORE_FRAG 0x0100 0x0100 0x0100 0x0100 0x0100 0x0100 # consensus syscon misc IP6F_OFF_MASK 0xf8ff 0xf8ff 0xf8ff 0xf8ff 0xf8ff 0xf8ff # consensus syscon misc IP6F_RESERVED_MASK 0x0600 0x0600 0x0600 0x0600 0x0600 0x0600 # consensus @@ -1954,17 +2007,6 @@ syscon misc SEARCH_HIGH_12 176 0 0 0 0 0 syscon misc SEARCH_LOW 50 0 0 0 0 0 syscon misc SEARCH_LOW_12 178 0 0 0 0 0 -syscon misc SI_QUEUE -1 0x010002 0x010002 -2 -2 0 -syscon misc SI_TIMER -2 0x010003 0x010003 -3 -3 0 -syscon misc SI_ASYNCIO -4 0x010004 0x010004 0 0 0 -syscon misc SI_MESGQ -3 0x010005 0x010005 0 0 0 -syscon misc SI_KERNEL 0x80 0 0x010006 0 0 0 -syscon misc SI_USER 0 0x010001 0x010001 0 0 0 -syscon misc SI_ASYNCNL -60 0 0 0 0 0 -syscon misc SI_LOAD_SHIFT 0x10 0 0 0 0 0 -syscon misc SI_SIGIO -5 0 0 0 0 0 -syscon misc SI_TKILL -6 0 0 0 0 0 - syscon misc STRU_F 1 1 1 1 1 0 # unix consensus syscon misc STRU_P 3 3 3 3 3 0 # unix consensus syscon misc STRU_R 2 2 2 2 2 0 # unix consensus @@ -2050,12 +2092,6 @@ syscon misc SCHED_BATCH 3 0 0 0 0 0 syscon misc SCHED_IDLE 5 0 0 0 0 0 syscon misc SCHED_RESET_ON_FORK 0x40000000 0 0 0 0 0 -syscon misc SEGV_ACCERR 2 2 2 2 2 0 # unix consensus -syscon misc SEGV_MAPERR 1 1 1 1 1 0 # unix consensus - -syscon misc TRAP_BRKPT 1 1 1 1 1 0 # unix consensus -syscon misc TRAP_TRACE 2 2 2 2 2 0 # unix consensus - syscon misc WRDE_APPEND 0 1 1 0 0 0 syscon misc WRDE_BADCHAR 0 1 1 0 0 0 syscon misc WRDE_BADVAL 0 2 2 0 0 0 @@ -2112,14 +2148,6 @@ syscon misc TFD_NONBLOCK 0x0800 0 0 0 0 0 syscon misc TFD_TIMER_ABSTIME 1 0 0 0 0 0 syscon misc USRQUOTA 0 0 0 0 0 0 -syscon misc FPE_FLTDIV 3 1 3 3 3 0 -syscon misc FPE_FLTINV 7 5 7 7 7 0 -syscon misc FPE_FLTOVF 4 2 4 4 4 0 -syscon misc FPE_FLTRES 6 4 6 6 6 0 -syscon misc FPE_FLTSUB 8 6 8 8 8 0 -syscon misc FPE_FLTUND 5 3 5 5 5 0 -syscon misc FPE_INTDIV 1 7 2 1 1 0 -syscon misc FPE_INTOVF 2 8 1 2 2 0 syscon misc ABDAY_1 0x020000 14 14 13 13 0 syscon misc ABDAY_2 0x020001 15 15 14 14 0 @@ -2287,11 +2315,6 @@ syscon misc BC_DIM_MAX 0x0800 0x0800 0x0800 0xffff 0xffff 0 syscon misc BC_SCALE_MAX 99 99 99 0x7fffffff 0x7fffffff 0 syscon misc BC_STRING_MAX 0x03e8 0x03e8 0x03e8 0x7fffffff 0x7fffffff 0 -syscon misc RLIM_NLIMITS 0x10 9 15 9 9 0 -syscon misc RLIM_INFINITY -1 0 0x7fffffffffffffff 0 0 0 -syscon misc RLIM_SAVED_CUR -1 0 0x7fffffffffffffff 0 0 0 -syscon misc RLIM_SAVED_MAX -1 0 0x7fffffffffffffff 0 0 0 - syscon misc ABORTED_COMMAND 11 0 0 0 0 0 syscon misc ACORE 0 8 8 8 8 0 # bsd consensus syscon misc AFORK 0 1 1 1 1 0 # bsd consensus @@ -2512,22 +2535,22 @@ syscon termios VDISCARD 13 15 15 15 15 0 # termios.c_cc[VDISCARD] syscon termios VWERASE 14 4 4 4 4 0 # termios.c_cc[VWERASE]=𝑥 syscon termios VLNEXT 15 14 14 14 14 0 # termios.c_cc[VLNEXT]=𝑥 -syscon termios TIOCSERGETLSR 0x5459 0 0 0 0 0 # -syscon termios TIOCSERGETMULTI 0x545a 0 0 0 0 0 # -syscon termios TIOCSERSETMULTI 0x545b 0 0 0 0 0 # -syscon termios TIOCSER_TEMT 1 0 0 0 0 0 # +syscon termios TIOCSERGETLSR 0x5459 0 0 0 0 0 # +syscon termios TIOCSERGETMULTI 0x545a 0 0 0 0 0 # +syscon termios TIOCSERSETMULTI 0x545b 0 0 0 0 0 # +syscon termios TIOCSER_TEMT 1 0 0 0 0 0 # syscon termios VERIFY 47 0 0 0 0 0 -syscon termios PARENB 0x0100 0x1000 0x1000 0x1000 0x1000 0 # -syscon termios PARODD 0x0200 0x2000 0x2000 0x2000 0x2000 0 # +syscon termios PARENB 0x0100 0x1000 0x1000 0x1000 0x1000 0 # +syscon termios PARODD 0x0200 0x2000 0x2000 0x2000 0x2000 0 # syscon termios CIBAUD 0x100f0000 0 0 0 0 0 -syscon termios CLOCAL 0x0800 0x8000 0x8000 0x8000 0x8000 0 # +syscon termios CLOCAL 0x0800 0x8000 0x8000 0x8000 0x8000 0 # syscon termios CMSPAR 0x40000000 0 0 0 0 0 syscon termios BUSY 4 0 0 0 0 0 syscon termios CANBSIZ 255 0 0 0 0 0 syscon termios CBAUD 0x100f 0 0 0 0 0 syscon termios CBAUDEX 0x1000 0 0 0 0 0 -syscon termios CBRK 0 255 255 255 255 0 # -syscon termios CEOL 0 255 255 255 255 0 # +syscon termios CBRK 0 255 255 255 255 0 # +syscon termios CEOL 0 255 255 255 255 0 # # Pseudoteletypewriter Control # diff --git a/libc/sysv/consts/BUS_ADRALN.S b/libc/sysv/consts/BUS_ADRALN.S index f5c0c5e04..1ef06bbbc 100644 --- a/libc/sysv/consts/BUS_ADRALN.S +++ b/libc/sysv/consts/BUS_ADRALN.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,BUS_ADRALN,1,1,1,1,1,0 +.syscon sicode,BUS_ADRALN,1,1,1,1,1,1 diff --git a/libc/sysv/consts/BUS_ADRERR.S b/libc/sysv/consts/BUS_ADRERR.S index b51d4eab4..67cd338da 100644 --- a/libc/sysv/consts/BUS_ADRERR.S +++ b/libc/sysv/consts/BUS_ADRERR.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,BUS_ADRERR,2,2,2,2,2,0 +.syscon sicode,BUS_ADRERR,2,2,2,2,2,2 diff --git a/libc/sysv/consts/BUS_MCEERR_AO.S b/libc/sysv/consts/BUS_MCEERR_AO.S index ba125b0fa..6da2b9896 100644 --- a/libc/sysv/consts/BUS_MCEERR_AO.S +++ b/libc/sysv/consts/BUS_MCEERR_AO.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,BUS_MCEERR_AO,5,0,0,0,0,0 +.syscon sicode,BUS_MCEERR_AO,5,0x80000000,0x80000000,0x80000000,0x80000000,0x80000000 diff --git a/libc/sysv/consts/BUS_MCEERR_AR.S b/libc/sysv/consts/BUS_MCEERR_AR.S index 1ed98654b..45e32fdbe 100644 --- a/libc/sysv/consts/BUS_MCEERR_AR.S +++ b/libc/sysv/consts/BUS_MCEERR_AR.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,BUS_MCEERR_AR,4,0,0,0,0,0 +.syscon sicode,BUS_MCEERR_AR,4,0x80000000,0x80000000,0x80000000,0x80000000,0x80000000 diff --git a/libc/sysv/consts/BUS_OBJERR.S b/libc/sysv/consts/BUS_OBJERR.S index 160ad33bb..96dc0771c 100644 --- a/libc/sysv/consts/BUS_OBJERR.S +++ b/libc/sysv/consts/BUS_OBJERR.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,BUS_OBJERR,3,3,3,3,3,0 +.syscon sicode,BUS_OBJERR,3,3,3,3,3,3 diff --git a/libc/sysv/consts/CLD_CONTINUED.S b/libc/sysv/consts/CLD_CONTINUED.S index 556196233..3665d1432 100644 --- a/libc/sysv/consts/CLD_CONTINUED.S +++ b/libc/sysv/consts/CLD_CONTINUED.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,CLD_CONTINUED,6,6,6,6,6,6 +.syscon sicode,CLD_CONTINUED,6,6,6,6,6,6 diff --git a/libc/sysv/consts/CLD_DUMPED.S b/libc/sysv/consts/CLD_DUMPED.S index 1edbbadfa..5dbe99925 100644 --- a/libc/sysv/consts/CLD_DUMPED.S +++ b/libc/sysv/consts/CLD_DUMPED.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,CLD_DUMPED,3,3,3,3,3,3 +.syscon sicode,CLD_DUMPED,3,3,3,3,3,3 diff --git a/libc/sysv/consts/CLD_EXITED.S b/libc/sysv/consts/CLD_EXITED.S index d6b6c972f..ff63e185d 100644 --- a/libc/sysv/consts/CLD_EXITED.S +++ b/libc/sysv/consts/CLD_EXITED.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,CLD_EXITED,1,1,1,1,1,1 +.syscon sicode,CLD_EXITED,1,1,1,1,1,1 diff --git a/libc/sysv/consts/CLD_KILLED.S b/libc/sysv/consts/CLD_KILLED.S index 04d2a2f0f..3453b6985 100644 --- a/libc/sysv/consts/CLD_KILLED.S +++ b/libc/sysv/consts/CLD_KILLED.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,CLD_KILLED,2,2,2,2,2,2 +.syscon sicode,CLD_KILLED,2,2,2,2,2,2 diff --git a/libc/sysv/consts/CLD_STOPPED.S b/libc/sysv/consts/CLD_STOPPED.S index 0dc66af27..2ec88545d 100644 --- a/libc/sysv/consts/CLD_STOPPED.S +++ b/libc/sysv/consts/CLD_STOPPED.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,CLD_STOPPED,5,5,5,5,5,5 +.syscon sicode,CLD_STOPPED,5,5,5,5,5,5 diff --git a/libc/sysv/consts/CLD_TRAPPED.S b/libc/sysv/consts/CLD_TRAPPED.S index 7b027f015..35f858ef6 100644 --- a/libc/sysv/consts/CLD_TRAPPED.S +++ b/libc/sysv/consts/CLD_TRAPPED.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,CLD_TRAPPED,4,4,4,4,4,4 +.syscon sicode,CLD_TRAPPED,4,4,4,4,4,4 diff --git a/libc/sysv/consts/CLOCK_BOOTTIME.S b/libc/sysv/consts/CLOCK_BOOTTIME.S index 6093b3969..4a093dab4 100644 --- a/libc/sysv/consts/CLOCK_BOOTTIME.S +++ b/libc/sysv/consts/CLOCK_BOOTTIME.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon clock,CLOCK_BOOTTIME,7,0,0,6,6,0 +.syscon clock,CLOCK_BOOTTIME,7,-1,-1,6,6,-1 diff --git a/libc/sysv/consts/CLOCK_BOOTTIME_ALARM.S b/libc/sysv/consts/CLOCK_BOOTTIME_ALARM.S index 1c510dc53..aa660bfd3 100644 --- a/libc/sysv/consts/CLOCK_BOOTTIME_ALARM.S +++ b/libc/sysv/consts/CLOCK_BOOTTIME_ALARM.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon clock,CLOCK_BOOTTIME_ALARM,9,0,0,0,0,0 +.syscon clock,CLOCK_BOOTTIME_ALARM,9,-1,-1,-1,-1,-1 diff --git a/libc/sysv/consts/CLOCK_MONOTONIC_COARSE.S b/libc/sysv/consts/CLOCK_MONOTONIC_COARSE.S index 431a181a0..d12e8ec95 100644 --- a/libc/sysv/consts/CLOCK_MONOTONIC_COARSE.S +++ b/libc/sysv/consts/CLOCK_MONOTONIC_COARSE.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon clock,CLOCK_MONOTONIC_COARSE,6,0,0,0,0,0 +.syscon clock,CLOCK_MONOTONIC_COARSE,6,-1,-1,-1,-1,-1 diff --git a/libc/sysv/consts/CLOCK_PROCESS_CPUTIME_ID.S b/libc/sysv/consts/CLOCK_PROCESS_CPUTIME_ID.S index 507a56999..5a080feb2 100644 --- a/libc/sysv/consts/CLOCK_PROCESS_CPUTIME_ID.S +++ b/libc/sysv/consts/CLOCK_PROCESS_CPUTIME_ID.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon clock,CLOCK_PROCESS_CPUTIME_ID,2,0,15,2,0x40000000,0 +.syscon clock,CLOCK_PROCESS_CPUTIME_ID,2,-1,15,2,0x40000000,-1 diff --git a/libc/sysv/consts/CLOCK_REALTIME_ALARM.S b/libc/sysv/consts/CLOCK_REALTIME_ALARM.S index 4845de579..795e372e4 100644 --- a/libc/sysv/consts/CLOCK_REALTIME_ALARM.S +++ b/libc/sysv/consts/CLOCK_REALTIME_ALARM.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon clock,CLOCK_REALTIME_ALARM,8,0,0,0,0,0 +.syscon clock,CLOCK_REALTIME_ALARM,8,-1,-1,-1,-1,-1 diff --git a/libc/sysv/consts/CLOCK_REALTIME_COARSE.S b/libc/sysv/consts/CLOCK_REALTIME_COARSE.S index cb2e53004..7f40a4d9e 100644 --- a/libc/sysv/consts/CLOCK_REALTIME_COARSE.S +++ b/libc/sysv/consts/CLOCK_REALTIME_COARSE.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon clock,CLOCK_REALTIME_COARSE,5,0,0,0,0,0 +.syscon clock,CLOCK_REALTIME_COARSE,5,-1,-1,-1,-1,-1 diff --git a/libc/sysv/consts/CLOCK_TAI.S b/libc/sysv/consts/CLOCK_TAI.S index 144ee41e5..0925bb74a 100644 --- a/libc/sysv/consts/CLOCK_TAI.S +++ b/libc/sysv/consts/CLOCK_TAI.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon clock,CLOCK_TAI,11,0,0,0,0,0 +.syscon clock,CLOCK_TAI,11,-1,-1,-1,-1,-1 diff --git a/libc/sysv/consts/CLOCK_THREAD_CPUTIME_ID.S b/libc/sysv/consts/CLOCK_THREAD_CPUTIME_ID.S index 59a0db26f..d7358df70 100644 --- a/libc/sysv/consts/CLOCK_THREAD_CPUTIME_ID.S +++ b/libc/sysv/consts/CLOCK_THREAD_CPUTIME_ID.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon clock,CLOCK_THREAD_CPUTIME_ID,3,0,14,4,0x20000000,0 +.syscon clock,CLOCK_THREAD_CPUTIME_ID,3,-1,14,4,0x20000000,-1 diff --git a/libc/sysv/consts/EADV.S b/libc/sysv/consts/EADV.S index 08cbe9082..aa434b681 100644 --- a/libc/sysv/consts/EADV.S +++ b/libc/sysv/consts/EADV.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,EADV,68,0,0,0,0,0 +.syscon junkerr,EADV,68,0,0,0,0,0 diff --git a/libc/sysv/consts/EBADE.S b/libc/sysv/consts/EBADE.S index ecaf458fc..74b94ea93 100644 --- a/libc/sysv/consts/EBADE.S +++ b/libc/sysv/consts/EBADE.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,EBADE,52,0,0,0,0,0 +.syscon junkerr,EBADE,52,0,0,0,0,0 diff --git a/libc/sysv/consts/EBADFD.S b/libc/sysv/consts/EBADFD.S index 71f5f1687..3d23845e6 100644 --- a/libc/sysv/consts/EBADFD.S +++ b/libc/sysv/consts/EBADFD.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,EBADFD,77,9,9,9,9,6 +.syscon junkerr,EBADFD,77,9,9,9,9,6 diff --git a/libc/sysv/consts/EBADR.S b/libc/sysv/consts/EBADR.S index b1375b239..c63e4745e 100644 --- a/libc/sysv/consts/EBADR.S +++ b/libc/sysv/consts/EBADR.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,EBADR,53,0,0,0,0,0 +.syscon junkerr,EBADR,53,0,0,0,0,0 diff --git a/libc/sysv/consts/EBADRQC.S b/libc/sysv/consts/EBADRQC.S index 134bfb5af..da7aa46d1 100644 --- a/libc/sysv/consts/EBADRQC.S +++ b/libc/sysv/consts/EBADRQC.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,EBADRQC,56,0,0,0,0,0 +.syscon junkerr,EBADRQC,56,0,0,0,0,0 diff --git a/libc/sysv/consts/EBADSLT.S b/libc/sysv/consts/EBADSLT.S index fb1bff43d..da3094623 100644 --- a/libc/sysv/consts/EBADSLT.S +++ b/libc/sysv/consts/EBADSLT.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,EBADSLT,57,0,0,0,0,0 +.syscon junkerr,EBADSLT,57,0,0,0,0,0 diff --git a/libc/sysv/consts/ECHRNG.S b/libc/sysv/consts/ECHRNG.S index 861ee6ebd..53c7a71ce 100644 --- a/libc/sysv/consts/ECHRNG.S +++ b/libc/sysv/consts/ECHRNG.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,ECHRNG,44,0,0,0,0,0 +.syscon junkerr,ECHRNG,44,0,0,0,0,0 diff --git a/libc/sysv/consts/ECOMM.S b/libc/sysv/consts/ECOMM.S index f84f311a4..4b86f5212 100644 --- a/libc/sysv/consts/ECOMM.S +++ b/libc/sysv/consts/ECOMM.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,ECOMM,70,0,0,0,0,0 +.syscon junkerr,ECOMM,70,0,0,0,0,0 diff --git a/libc/sysv/consts/EDOTDOT.S b/libc/sysv/consts/EDOTDOT.S index 8329e10d7..743fbc8ed 100644 --- a/libc/sysv/consts/EDOTDOT.S +++ b/libc/sysv/consts/EDOTDOT.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,EDOTDOT,73,0,0,0,0,0 +.syscon junkerr,EDOTDOT,73,0,0,0,0,0 diff --git a/libc/sysv/consts/EHWPOISON.S b/libc/sysv/consts/EHWPOISON.S index 7c94d3942..ff444df5f 100644 --- a/libc/sysv/consts/EHWPOISON.S +++ b/libc/sysv/consts/EHWPOISON.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,EHWPOISON,133,0,0,0,0,0 +.syscon junkerr,EHWPOISON,133,0,0,0,0,0 diff --git a/libc/sysv/consts/EISNAM.S b/libc/sysv/consts/EISNAM.S index 12029e087..bdcc5c3e9 100644 --- a/libc/sysv/consts/EISNAM.S +++ b/libc/sysv/consts/EISNAM.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,EISNAM,120,0,0,0,0,0 +.syscon junkerr,EISNAM,120,0,0,0,0,0 diff --git a/libc/sysv/consts/EKEYEXPIRED.S b/libc/sysv/consts/EKEYEXPIRED.S index 161ed2852..fd5498a77 100644 --- a/libc/sysv/consts/EKEYEXPIRED.S +++ b/libc/sysv/consts/EKEYEXPIRED.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,EKEYEXPIRED,127,0,0,0,0,0 +.syscon junkerr,EKEYEXPIRED,127,0,0,0,0,0 diff --git a/libc/sysv/consts/EKEYREJECTED.S b/libc/sysv/consts/EKEYREJECTED.S index e8f1fb54a..c9e5d2225 100644 --- a/libc/sysv/consts/EKEYREJECTED.S +++ b/libc/sysv/consts/EKEYREJECTED.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,EKEYREJECTED,129,0,0,0,0,0 +.syscon junkerr,EKEYREJECTED,129,0,0,0,0,0 diff --git a/libc/sysv/consts/EKEYREVOKED.S b/libc/sysv/consts/EKEYREVOKED.S index beb4031f6..be58ba181 100644 --- a/libc/sysv/consts/EKEYREVOKED.S +++ b/libc/sysv/consts/EKEYREVOKED.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,EKEYREVOKED,128,0,0,0,0,0 +.syscon junkerr,EKEYREVOKED,128,0,0,0,0,0 diff --git a/libc/sysv/consts/EL2HLT.S b/libc/sysv/consts/EL2HLT.S index 0415c820d..e55005ac5 100644 --- a/libc/sysv/consts/EL2HLT.S +++ b/libc/sysv/consts/EL2HLT.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,EL2HLT,51,0,0,0,0,0 +.syscon junkerr,EL2HLT,51,0,0,0,0,0 diff --git a/libc/sysv/consts/EL2NSYNC.S b/libc/sysv/consts/EL2NSYNC.S index 31ddd4a99..4da833ae8 100644 --- a/libc/sysv/consts/EL2NSYNC.S +++ b/libc/sysv/consts/EL2NSYNC.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,EL2NSYNC,45,0,0,0,0,0 +.syscon junkerr,EL2NSYNC,45,0,0,0,0,0 diff --git a/libc/sysv/consts/EL3HLT.S b/libc/sysv/consts/EL3HLT.S index c0e150d1c..607b6f6a6 100644 --- a/libc/sysv/consts/EL3HLT.S +++ b/libc/sysv/consts/EL3HLT.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,EL3HLT,46,0,0,0,0,0 +.syscon junkerr,EL3HLT,46,0,0,0,0,0 diff --git a/libc/sysv/consts/EL3RST.S b/libc/sysv/consts/EL3RST.S index 96e3fa638..0b5ea0c3c 100644 --- a/libc/sysv/consts/EL3RST.S +++ b/libc/sysv/consts/EL3RST.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,EL3RST,47,0,0,0,0,0 +.syscon junkerr,EL3RST,47,0,0,0,0,0 diff --git a/libc/sysv/consts/ELIBACC.S b/libc/sysv/consts/ELIBACC.S index 76c50141b..97fe15688 100644 --- a/libc/sysv/consts/ELIBACC.S +++ b/libc/sysv/consts/ELIBACC.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,ELIBACC,79,0,0,0,0,0 +.syscon junkerr,ELIBACC,79,0,0,0,0,0 diff --git a/libc/sysv/consts/ELIBBAD.S b/libc/sysv/consts/ELIBBAD.S index 9596cc363..6622fadb0 100644 --- a/libc/sysv/consts/ELIBBAD.S +++ b/libc/sysv/consts/ELIBBAD.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,ELIBBAD,80,0,0,0,0,0 +.syscon junkerr,ELIBBAD,80,0,0,0,0,0 diff --git a/libc/sysv/consts/ELIBEXEC.S b/libc/sysv/consts/ELIBEXEC.S index cd9ae7540..3245cdf4f 100644 --- a/libc/sysv/consts/ELIBEXEC.S +++ b/libc/sysv/consts/ELIBEXEC.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,ELIBEXEC,83,0,0,0,0,0 +.syscon junkerr,ELIBEXEC,83,0,0,0,0,0 diff --git a/libc/sysv/consts/ELIBMAX.S b/libc/sysv/consts/ELIBMAX.S index 2f18e3b08..b319adea2 100644 --- a/libc/sysv/consts/ELIBMAX.S +++ b/libc/sysv/consts/ELIBMAX.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,ELIBMAX,82,0,0,0,0,0 +.syscon junkerr,ELIBMAX,82,0,0,0,0,0 diff --git a/libc/sysv/consts/ELIBSCN.S b/libc/sysv/consts/ELIBSCN.S index 680f8da4d..3776c44d9 100644 --- a/libc/sysv/consts/ELIBSCN.S +++ b/libc/sysv/consts/ELIBSCN.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,ELIBSCN,81,0,0,0,0,0 +.syscon junkerr,ELIBSCN,81,0,0,0,0,0 diff --git a/libc/sysv/consts/ELNRNG.S b/libc/sysv/consts/ELNRNG.S index bda2fc53d..236df0e89 100644 --- a/libc/sysv/consts/ELNRNG.S +++ b/libc/sysv/consts/ELNRNG.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,ELNRNG,48,0,0,0,0,0 +.syscon junkerr,ELNRNG,48,0,0,0,0,0 diff --git a/libc/sysv/consts/EMEDIUMTYPE.S b/libc/sysv/consts/EMEDIUMTYPE.S index ba830f328..488841a65 100644 --- a/libc/sysv/consts/EMEDIUMTYPE.S +++ b/libc/sysv/consts/EMEDIUMTYPE.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,EMEDIUMTYPE,124,0,0,86,86,0 +.syscon junkerr,EMEDIUMTYPE,124,0,0,86,86,0 diff --git a/libc/sysv/consts/EMULTIHOP.S b/libc/sysv/consts/EMULTIHOP.S index 434e78754..cfff27b7d 100644 --- a/libc/sysv/consts/EMULTIHOP.S +++ b/libc/sysv/consts/EMULTIHOP.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,EMULTIHOP,72,95,90,0,94,0 +.syscon junkerr,EMULTIHOP,72,95,90,0,94,0 diff --git a/libc/sysv/consts/ENAVAIL.S b/libc/sysv/consts/ENAVAIL.S index 5cbd8fda4..2b89fb282 100644 --- a/libc/sysv/consts/ENAVAIL.S +++ b/libc/sysv/consts/ENAVAIL.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,ENAVAIL,119,0,0,0,0,0 +.syscon junkerr,ENAVAIL,119,0,0,0,0,0 diff --git a/libc/sysv/consts/ENOANO.S b/libc/sysv/consts/ENOANO.S index 235babdad..2ecd8abe2 100644 --- a/libc/sysv/consts/ENOANO.S +++ b/libc/sysv/consts/ENOANO.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,ENOANO,55,0,0,0,0,0 +.syscon junkerr,ENOANO,55,0,0,0,0,0 diff --git a/libc/sysv/consts/ENOCSI.S b/libc/sysv/consts/ENOCSI.S index 9c5de5dd5..29453b515 100644 --- a/libc/sysv/consts/ENOCSI.S +++ b/libc/sysv/consts/ENOCSI.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,ENOCSI,50,0,0,0,0,0 +.syscon junkerr,ENOCSI,50,0,0,0,0,0 diff --git a/libc/sysv/consts/ENODATA.S b/libc/sysv/consts/ENODATA.S index e9b938bbb..c406f9ae6 100644 --- a/libc/sysv/consts/ENODATA.S +++ b/libc/sysv/consts/ENODATA.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,ENODATA,61,96,0,0,89,0 +.syscon junkerr,ENODATA,61,96,0,0,89,0 diff --git a/libc/sysv/consts/ENOKEY.S b/libc/sysv/consts/ENOKEY.S index bc11fdebf..46c2fc42a 100644 --- a/libc/sysv/consts/ENOKEY.S +++ b/libc/sysv/consts/ENOKEY.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,ENOKEY,126,0,0,0,0,0 +.syscon junkerr,ENOKEY,126,0,0,0,0,0 diff --git a/libc/sysv/consts/ENOLINK.S b/libc/sysv/consts/ENOLINK.S index 875ea6b1b..9d890098e 100644 --- a/libc/sysv/consts/ENOLINK.S +++ b/libc/sysv/consts/ENOLINK.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,ENOLINK,67,97,91,0,95,0 +.syscon junkerr,ENOLINK,67,97,91,0,95,0 diff --git a/libc/sysv/consts/ENOMEDIUM.S b/libc/sysv/consts/ENOMEDIUM.S index 0c9a5d03a..7243999b8 100644 --- a/libc/sysv/consts/ENOMEDIUM.S +++ b/libc/sysv/consts/ENOMEDIUM.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,ENOMEDIUM,123,0,0,85,85,0 +.syscon junkerr,ENOMEDIUM,123,0,0,85,85,0 diff --git a/libc/sysv/consts/ENOPKG.S b/libc/sysv/consts/ENOPKG.S index d05ef3a03..e2580a4ab 100644 --- a/libc/sysv/consts/ENOPKG.S +++ b/libc/sysv/consts/ENOPKG.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,ENOPKG,65,0,0,0,0,0 +.syscon junkerr,ENOPKG,65,0,0,0,0,0 diff --git a/libc/sysv/consts/ENOSR.S b/libc/sysv/consts/ENOSR.S index 86ff4c52b..ea4d91cf0 100644 --- a/libc/sysv/consts/ENOSR.S +++ b/libc/sysv/consts/ENOSR.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,ENOSR,63,98,0,0,90,0 +.syscon junkerr,ENOSR,63,98,0,0,90,0 diff --git a/libc/sysv/consts/ENOSTR.S b/libc/sysv/consts/ENOSTR.S index 749624fa4..9dde57279 100644 --- a/libc/sysv/consts/ENOSTR.S +++ b/libc/sysv/consts/ENOSTR.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,ENOSTR,60,99,0,0,91,0 +.syscon junkerr,ENOSTR,60,99,0,0,91,0 diff --git a/libc/sysv/consts/ENOTNAM.S b/libc/sysv/consts/ENOTNAM.S index b1b4db47e..94e0ff0d3 100644 --- a/libc/sysv/consts/ENOTNAM.S +++ b/libc/sysv/consts/ENOTNAM.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,ENOTNAM,118,0,0,0,0,0 +.syscon junkerr,ENOTNAM,118,0,0,0,0,0 diff --git a/libc/sysv/consts/ENOTUNIQ.S b/libc/sysv/consts/ENOTUNIQ.S index 3212f49c8..a4b4922f9 100644 --- a/libc/sysv/consts/ENOTUNIQ.S +++ b/libc/sysv/consts/ENOTUNIQ.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,ENOTUNIQ,76,0,0,0,0,0 +.syscon junkerr,ENOTUNIQ,76,0,0,0,0,0 diff --git a/libc/sysv/consts/EREMCHG.S b/libc/sysv/consts/EREMCHG.S index 0097bc85d..40c2b77fb 100644 --- a/libc/sysv/consts/EREMCHG.S +++ b/libc/sysv/consts/EREMCHG.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,EREMCHG,78,0,0,0,0,0 +.syscon junkerr,EREMCHG,78,0,0,0,0,0 diff --git a/libc/sysv/consts/EREMOTEIO.S b/libc/sysv/consts/EREMOTEIO.S index 99326c177..274433d49 100644 --- a/libc/sysv/consts/EREMOTEIO.S +++ b/libc/sysv/consts/EREMOTEIO.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,EREMOTEIO,121,0,0,0,0,0 +.syscon junkerr,EREMOTEIO,121,0,0,0,0,0 diff --git a/libc/sysv/consts/ERFKILL.S b/libc/sysv/consts/ERFKILL.S index 2f331d26e..fb48e5305 100644 --- a/libc/sysv/consts/ERFKILL.S +++ b/libc/sysv/consts/ERFKILL.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,ERFKILL,132,0,0,0,0,0 +.syscon junkerr,ERFKILL,132,0,0,0,0,0 diff --git a/libc/sysv/consts/ESRMNT.S b/libc/sysv/consts/ESRMNT.S index 99b5f9605..7c3147570 100644 --- a/libc/sysv/consts/ESRMNT.S +++ b/libc/sysv/consts/ESRMNT.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,ESRMNT,69,0,0,0,0,0 +.syscon junkerr,ESRMNT,69,0,0,0,0,0 diff --git a/libc/sysv/consts/ESTRPIPE.S b/libc/sysv/consts/ESTRPIPE.S index 8892e8b26..f89d8fa13 100644 --- a/libc/sysv/consts/ESTRPIPE.S +++ b/libc/sysv/consts/ESTRPIPE.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,ESTRPIPE,86,0,0,0,0,0 +.syscon junkerr,ESTRPIPE,86,0,0,0,0,0 diff --git a/libc/sysv/consts/ETIME.S b/libc/sysv/consts/ETIME.S index e338e9f62..38366adf2 100644 --- a/libc/sysv/consts/ETIME.S +++ b/libc/sysv/consts/ETIME.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,ETIME,62,101,0,0,92,0 +.syscon errno,ETIME,62,101,60,60,92,0 diff --git a/libc/sysv/consts/EUCLEAN.S b/libc/sysv/consts/EUCLEAN.S index a827c02e0..a0eecf2db 100644 --- a/libc/sysv/consts/EUCLEAN.S +++ b/libc/sysv/consts/EUCLEAN.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,EUCLEAN,117,0,0,0,0,0 +.syscon junkerr,EUCLEAN,117,0,0,0,0,0 diff --git a/libc/sysv/consts/EUNATCH.S b/libc/sysv/consts/EUNATCH.S index 5595e478a..679c2a8fc 100644 --- a/libc/sysv/consts/EUNATCH.S +++ b/libc/sysv/consts/EUNATCH.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,EUNATCH,49,0,0,0,0,0 +.syscon junkerr,EUNATCH,49,0,0,0,0,0 diff --git a/libc/sysv/consts/EWOULDBLOCK.S b/libc/sysv/consts/EWOULDBLOCK.S index 91f2f0ba8..16f6e6d55 100644 --- a/libc/sysv/consts/EWOULDBLOCK.S +++ b/libc/sysv/consts/EWOULDBLOCK.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,EWOULDBLOCK,11,35,35,35,35,0x2733 +.syscon compat,EWOULDBLOCK,11,35,35,35,35,0x2733 diff --git a/libc/sysv/consts/EXFULL.S b/libc/sysv/consts/EXFULL.S index 0c0aad1d2..bd1fd87c3 100644 --- a/libc/sysv/consts/EXFULL.S +++ b/libc/sysv/consts/EXFULL.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,EXFULL,54,0,0,0,0,0 +.syscon junkerr,EXFULL,54,0,0,0,0,0 diff --git a/libc/sysv/consts/FPE_FLTDIV.S b/libc/sysv/consts/FPE_FLTDIV.S index 3390eed37..779be8461 100644 --- a/libc/sysv/consts/FPE_FLTDIV.S +++ b/libc/sysv/consts/FPE_FLTDIV.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,FPE_FLTDIV,3,1,3,3,3,0 +.syscon sicode,FPE_FLTDIV,3,1,3,3,3,3 diff --git a/libc/sysv/consts/FPE_FLTINV.S b/libc/sysv/consts/FPE_FLTINV.S index 24a2d9b9d..efd268e49 100644 --- a/libc/sysv/consts/FPE_FLTINV.S +++ b/libc/sysv/consts/FPE_FLTINV.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,FPE_FLTINV,7,5,7,7,7,0 +.syscon sicode,FPE_FLTINV,7,5,7,7,7,7 diff --git a/libc/sysv/consts/FPE_FLTOVF.S b/libc/sysv/consts/FPE_FLTOVF.S index 6ccf5937c..ff290e423 100644 --- a/libc/sysv/consts/FPE_FLTOVF.S +++ b/libc/sysv/consts/FPE_FLTOVF.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,FPE_FLTOVF,4,2,4,4,4,0 +.syscon sicode,FPE_FLTOVF,4,2,4,4,4,4 diff --git a/libc/sysv/consts/FPE_FLTRES.S b/libc/sysv/consts/FPE_FLTRES.S index 7d4881f0b..8dcf2076d 100644 --- a/libc/sysv/consts/FPE_FLTRES.S +++ b/libc/sysv/consts/FPE_FLTRES.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,FPE_FLTRES,6,4,6,6,6,0 +.syscon sicode,FPE_FLTRES,6,4,6,6,6,6 diff --git a/libc/sysv/consts/FPE_FLTSUB.S b/libc/sysv/consts/FPE_FLTSUB.S index f17fa18c1..1c16c937e 100644 --- a/libc/sysv/consts/FPE_FLTSUB.S +++ b/libc/sysv/consts/FPE_FLTSUB.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,FPE_FLTSUB,8,6,8,8,8,0 +.syscon sicode,FPE_FLTSUB,8,6,8,8,8,8 diff --git a/libc/sysv/consts/FPE_FLTUND.S b/libc/sysv/consts/FPE_FLTUND.S index 7556e5724..9a93a8dd8 100644 --- a/libc/sysv/consts/FPE_FLTUND.S +++ b/libc/sysv/consts/FPE_FLTUND.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,FPE_FLTUND,5,3,5,5,5,0 +.syscon sicode,FPE_FLTUND,5,3,5,5,5,5 diff --git a/libc/sysv/consts/FPE_INTDIV.S b/libc/sysv/consts/FPE_INTDIV.S index 87d9e0340..23ea84b2a 100644 --- a/libc/sysv/consts/FPE_INTDIV.S +++ b/libc/sysv/consts/FPE_INTDIV.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,FPE_INTDIV,1,7,2,1,1,0 +.syscon sicode,FPE_INTDIV,1,7,2,1,1,1 diff --git a/libc/sysv/consts/FPE_INTOVF.S b/libc/sysv/consts/FPE_INTOVF.S index dfcfe321c..dd44f7bbc 100644 --- a/libc/sysv/consts/FPE_INTOVF.S +++ b/libc/sysv/consts/FPE_INTOVF.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,FPE_INTOVF,2,8,1,2,2,0 +.syscon sicode,FPE_INTOVF,2,8,1,2,2,2 diff --git a/libc/sysv/consts/ILL_BADSTK.S b/libc/sysv/consts/ILL_BADSTK.S index 0dbf521d0..296262949 100644 --- a/libc/sysv/consts/ILL_BADSTK.S +++ b/libc/sysv/consts/ILL_BADSTK.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,ILL_BADSTK,8,8,8,8,8,0 +.syscon sicode,ILL_BADSTK,8,8,8,8,8,8 diff --git a/libc/sysv/consts/ILL_COPROC.S b/libc/sysv/consts/ILL_COPROC.S index 3c7d9a3a3..220f3d6ba 100644 --- a/libc/sysv/consts/ILL_COPROC.S +++ b/libc/sysv/consts/ILL_COPROC.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,ILL_COPROC,7,7,7,7,7,0 +.syscon sicode,ILL_COPROC,7,7,7,7,7,7 diff --git a/libc/sysv/consts/ILL_ILLADR.S b/libc/sysv/consts/ILL_ILLADR.S index f7bd4dd40..7aff4a492 100644 --- a/libc/sysv/consts/ILL_ILLADR.S +++ b/libc/sysv/consts/ILL_ILLADR.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,ILL_ILLADR,3,5,3,3,3,0 +.syscon sicode,ILL_ILLADR,3,5,3,3,3,3 diff --git a/libc/sysv/consts/ILL_ILLOPC.S b/libc/sysv/consts/ILL_ILLOPC.S index f3cc6c998..9343caf39 100644 --- a/libc/sysv/consts/ILL_ILLOPC.S +++ b/libc/sysv/consts/ILL_ILLOPC.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,ILL_ILLOPC,1,1,1,1,1,0 +.syscon sicode,ILL_ILLOPC,1,1,1,1,1,1 diff --git a/libc/sysv/consts/ILL_ILLOPN.S b/libc/sysv/consts/ILL_ILLOPN.S index 802e290fe..ad757bc07 100644 --- a/libc/sysv/consts/ILL_ILLOPN.S +++ b/libc/sysv/consts/ILL_ILLOPN.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,ILL_ILLOPN,2,4,2,2,2,0 +.syscon sicode,ILL_ILLOPN,2,4,2,2,2,2 diff --git a/libc/sysv/consts/ILL_ILLTRP.S b/libc/sysv/consts/ILL_ILLTRP.S index 8dde415d1..722e291f4 100644 --- a/libc/sysv/consts/ILL_ILLTRP.S +++ b/libc/sysv/consts/ILL_ILLTRP.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,ILL_ILLTRP,4,2,4,4,4,0 +.syscon sicode,ILL_ILLTRP,4,2,4,4,4,4 diff --git a/libc/sysv/consts/ILL_PRVOPC.S b/libc/sysv/consts/ILL_PRVOPC.S index a3ea0bcc2..438b12a21 100644 --- a/libc/sysv/consts/ILL_PRVOPC.S +++ b/libc/sysv/consts/ILL_PRVOPC.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,ILL_PRVOPC,5,3,5,5,5,0 +.syscon sicode,ILL_PRVOPC,5,3,5,5,5,5 diff --git a/libc/sysv/consts/ILL_PRVREG.S b/libc/sysv/consts/ILL_PRVREG.S index c80307d9c..bfbb3b56a 100644 --- a/libc/sysv/consts/ILL_PRVREG.S +++ b/libc/sysv/consts/ILL_PRVREG.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,ILL_PRVREG,6,6,6,6,6,0 +.syscon sicode,ILL_PRVREG,6,6,6,6,6,6 diff --git a/libc/sysv/consts/MADV_DONTDUMP.S b/libc/sysv/consts/MADV_DONTDUMP.S index c24e42a02..feba10977 100644 --- a/libc/sysv/consts/MADV_DONTDUMP.S +++ b/libc/sysv/consts/MADV_DONTDUMP.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon madv,MADV_DONTDUMP,0x10,0,0,0,0,0 +.syscon madv,MADV_DONTDUMP,16,0,0,0,0,0 diff --git a/libc/sysv/consts/POLL_ERR.S b/libc/sysv/consts/POLL_ERR.S index 8f6024588..1c0e2ffd5 100644 --- a/libc/sysv/consts/POLL_ERR.S +++ b/libc/sysv/consts/POLL_ERR.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon sigpoll,POLL_ERR,4,4,4,0,0,0 +.syscon sicode,POLL_ERR,4,4,4,4,4,4 diff --git a/libc/sysv/consts/POLL_HUP.S b/libc/sysv/consts/POLL_HUP.S index 5c4abccf5..514a3cef2 100644 --- a/libc/sysv/consts/POLL_HUP.S +++ b/libc/sysv/consts/POLL_HUP.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon sigpoll,POLL_HUP,6,6,6,0,0,0 +.syscon sicode,POLL_HUP,6,6,6,6,6,6 diff --git a/libc/sysv/consts/POLL_IN.S b/libc/sysv/consts/POLL_IN.S index edb282b17..1c2be195e 100644 --- a/libc/sysv/consts/POLL_IN.S +++ b/libc/sysv/consts/POLL_IN.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon sigpoll,POLL_IN,1,1,1,0,0,0 +.syscon sicode,POLL_IN,1,1,1,1,1,1 diff --git a/libc/sysv/consts/POLL_MSG.S b/libc/sysv/consts/POLL_MSG.S index 326e10ceb..acd5a6183 100644 --- a/libc/sysv/consts/POLL_MSG.S +++ b/libc/sysv/consts/POLL_MSG.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon sigpoll,POLL_MSG,3,3,3,0,0,0 +.syscon sicode,POLL_MSG,3,3,3,3,3,3 diff --git a/libc/sysv/consts/POLL_OUT.S b/libc/sysv/consts/POLL_OUT.S index 9aede8bb9..5b9eb0746 100644 --- a/libc/sysv/consts/POLL_OUT.S +++ b/libc/sysv/consts/POLL_OUT.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon sigpoll,POLL_OUT,2,2,2,0,0,0 +.syscon sicode,POLL_OUT,2,2,2,2,2,2 diff --git a/libc/sysv/consts/POLL_PRI.S b/libc/sysv/consts/POLL_PRI.S index 4c8e61db9..13d080839 100644 --- a/libc/sysv/consts/POLL_PRI.S +++ b/libc/sysv/consts/POLL_PRI.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon sigpoll,POLL_PRI,5,5,5,0,0,0 +.syscon sicode,POLL_PRI,5,5,5,5,5,5 diff --git a/libc/sysv/consts/RLIMIT_AS.S b/libc/sysv/consts/RLIMIT_AS.S index 98cade3b7..00f1f8ea2 100644 --- a/libc/sysv/consts/RLIMIT_AS.S +++ b/libc/sysv/consts/RLIMIT_AS.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon rlim,RLIMIT_AS,9,5,10,127,127,127 +.syscon rlimit,RLIMIT_AS,9,5,10,127,10,127 diff --git a/libc/sysv/consts/RLIMIT_CORE.S b/libc/sysv/consts/RLIMIT_CORE.S index 5901b08f7..0b70c7a64 100644 --- a/libc/sysv/consts/RLIMIT_CORE.S +++ b/libc/sysv/consts/RLIMIT_CORE.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon rlim,RLIMIT_CORE,4,4,4,4,4,127 +.syscon rlimit,RLIMIT_CORE,4,4,4,4,4,127 diff --git a/libc/sysv/consts/RLIMIT_CPU.S b/libc/sysv/consts/RLIMIT_CPU.S index 5acec12a7..3c722caf1 100644 --- a/libc/sysv/consts/RLIMIT_CPU.S +++ b/libc/sysv/consts/RLIMIT_CPU.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon rlim,RLIMIT_CPU,0,0,0,0,0,127 +.syscon rlimit,RLIMIT_CPU,0,0,0,0,0,127 diff --git a/libc/sysv/consts/RLIMIT_DATA.S b/libc/sysv/consts/RLIMIT_DATA.S index dded0c054..492ee8dcc 100644 --- a/libc/sysv/consts/RLIMIT_DATA.S +++ b/libc/sysv/consts/RLIMIT_DATA.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon rlim,RLIMIT_DATA,2,2,2,2,2,127 +.syscon rlimit,RLIMIT_DATA,2,2,2,2,2,127 diff --git a/libc/sysv/consts/RLIMIT_FSIZE.S b/libc/sysv/consts/RLIMIT_FSIZE.S index 8e1daa55b..1ba468e45 100644 --- a/libc/sysv/consts/RLIMIT_FSIZE.S +++ b/libc/sysv/consts/RLIMIT_FSIZE.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon rlim,RLIMIT_FSIZE,1,1,1,1,1,127 +.syscon rlimit,RLIMIT_FSIZE,1,1,1,1,1,127 diff --git a/libc/sysv/consts/RLIMIT_LOCKS.S b/libc/sysv/consts/RLIMIT_LOCKS.S index 3656d1bd6..fc4b768f1 100644 --- a/libc/sysv/consts/RLIMIT_LOCKS.S +++ b/libc/sysv/consts/RLIMIT_LOCKS.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon rlim,RLIMIT_LOCKS,10,127,127,127,127,127 +.syscon rlimit,RLIMIT_LOCKS,10,127,127,127,127,127 diff --git a/libc/sysv/consts/RLIMIT_MEMLOCK.S b/libc/sysv/consts/RLIMIT_MEMLOCK.S index 9b7e9e9a6..1b6453b6b 100644 --- a/libc/sysv/consts/RLIMIT_MEMLOCK.S +++ b/libc/sysv/consts/RLIMIT_MEMLOCK.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon rlim,RLIMIT_MEMLOCK,8,6,6,6,6,127 +.syscon rlimit,RLIMIT_MEMLOCK,8,6,6,6,6,127 diff --git a/libc/sysv/consts/RLIMIT_MSGQUEUE.S b/libc/sysv/consts/RLIMIT_MSGQUEUE.S index 6b5265367..5f5b72750 100644 --- a/libc/sysv/consts/RLIMIT_MSGQUEUE.S +++ b/libc/sysv/consts/RLIMIT_MSGQUEUE.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon rlim,RLIMIT_MSGQUEUE,12,127,127,127,127,127 +.syscon rlimit,RLIMIT_MSGQUEUE,12,127,127,127,127,127 diff --git a/libc/sysv/consts/RLIMIT_NICE.S b/libc/sysv/consts/RLIMIT_NICE.S index 0e023da20..96ce1be85 100644 --- a/libc/sysv/consts/RLIMIT_NICE.S +++ b/libc/sysv/consts/RLIMIT_NICE.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon rlim,RLIMIT_NICE,13,127,127,127,127,127 +.syscon rlimit,RLIMIT_NICE,13,127,127,127,127,127 diff --git a/libc/sysv/consts/RLIMIT_NLIMITS.S b/libc/sysv/consts/RLIMIT_NLIMITS.S deleted file mode 100644 index 841045785..000000000 --- a/libc/sysv/consts/RLIMIT_NLIMITS.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon rlim,RLIMIT_NLIMITS,16,127,127,127,127,127 diff --git a/libc/sysv/consts/RLIMIT_NOFILE.S b/libc/sysv/consts/RLIMIT_NOFILE.S index 2708a6cd5..264b45dce 100644 --- a/libc/sysv/consts/RLIMIT_NOFILE.S +++ b/libc/sysv/consts/RLIMIT_NOFILE.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon rlim,RLIMIT_NOFILE,7,8,8,8,8,127 +.syscon rlimit,RLIMIT_NOFILE,7,8,8,8,8,127 diff --git a/libc/sysv/consts/RLIMIT_NPROC.S b/libc/sysv/consts/RLIMIT_NPROC.S index a4bb784eb..060763a46 100644 --- a/libc/sysv/consts/RLIMIT_NPROC.S +++ b/libc/sysv/consts/RLIMIT_NPROC.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon rlim,RLIMIT_NPROC,6,7,7,7,7,127 +.syscon rlimit,RLIMIT_NPROC,6,7,7,7,7,127 diff --git a/libc/sysv/consts/RLIMIT_RSS.S b/libc/sysv/consts/RLIMIT_RSS.S index 2ab654e5b..552e12ba5 100644 --- a/libc/sysv/consts/RLIMIT_RSS.S +++ b/libc/sysv/consts/RLIMIT_RSS.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon rlim,RLIMIT_RSS,5,5,5,5,5,127 +.syscon rlimit,RLIMIT_RSS,5,5,5,5,5,127 diff --git a/libc/sysv/consts/RLIMIT_RTPRIO.S b/libc/sysv/consts/RLIMIT_RTPRIO.S index c6c036385..d1b418404 100644 --- a/libc/sysv/consts/RLIMIT_RTPRIO.S +++ b/libc/sysv/consts/RLIMIT_RTPRIO.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon rlim,RLIMIT_RTPRIO,14,127,127,127,127,127 +.syscon rlimit,RLIMIT_RTPRIO,14,127,127,127,127,127 diff --git a/libc/sysv/consts/RLIMIT_SIGPENDING.S b/libc/sysv/consts/RLIMIT_SIGPENDING.S index f3c872177..7e8014a74 100644 --- a/libc/sysv/consts/RLIMIT_SIGPENDING.S +++ b/libc/sysv/consts/RLIMIT_SIGPENDING.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon rlim,RLIMIT_SIGPENDING,11,127,127,127,127,127 +.syscon rlimit,RLIMIT_SIGPENDING,11,127,127,127,127,127 diff --git a/libc/sysv/consts/RLIMIT_STACK.S b/libc/sysv/consts/RLIMIT_STACK.S index e4bde29ac..ca5899cad 100644 --- a/libc/sysv/consts/RLIMIT_STACK.S +++ b/libc/sysv/consts/RLIMIT_STACK.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon rlim,RLIMIT_STACK,3,3,3,3,3,127 +.syscon rlimit,RLIMIT_STACK,3,3,3,3,3,127 diff --git a/libc/sysv/consts/EBFONT.S b/libc/sysv/consts/RLIMIT_VMEM.S similarity index 50% rename from libc/sysv/consts/EBFONT.S rename to libc/sysv/consts/RLIMIT_VMEM.S index 4ddb766ff..30017ab72 100644 --- a/libc/sysv/consts/EBFONT.S +++ b/libc/sysv/consts/RLIMIT_VMEM.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon errno,EBFONT,59,0,0,0,0,0 +.syscon compat,RLIMIT_VMEM,9,5,10,127,10,127 diff --git a/libc/sysv/consts/RLIM_INFINITY.S b/libc/sysv/consts/RLIM_INFINITY.S index 9f0fbfef5..422e8ccc7 100644 --- a/libc/sysv/consts/RLIM_INFINITY.S +++ b/libc/sysv/consts/RLIM_INFINITY.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,RLIM_INFINITY,-1,0,0x7fffffffffffffff,0,0,0 +.syscon rlim,RLIM_INFINITY,0xffffffffffffffff,0x7fffffffffffffff,0x7fffffffffffffff,0x7fffffffffffffff,0x7fffffffffffffff,0 diff --git a/libc/sysv/consts/RLIM_NLIMITS.S b/libc/sysv/consts/RLIM_NLIMITS.S index 6de03aefe..ca3b0635d 100644 --- a/libc/sysv/consts/RLIM_NLIMITS.S +++ b/libc/sysv/consts/RLIM_NLIMITS.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,RLIM_NLIMITS,0x10,9,15,9,9,0 +.syscon rlim,RLIM_NLIMITS,16,9,15,9,12,0 diff --git a/libc/sysv/consts/RLIM_SAVED_CUR.S b/libc/sysv/consts/RLIM_SAVED_CUR.S index be886de01..78d294007 100644 --- a/libc/sysv/consts/RLIM_SAVED_CUR.S +++ b/libc/sysv/consts/RLIM_SAVED_CUR.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,RLIM_SAVED_CUR,-1,0,0x7fffffffffffffff,0,0,0 +.syscon rlim,RLIM_SAVED_CUR,0xffffffffffffffff,0x7fffffffffffffff,0x7fffffffffffffff,0x7fffffffffffffff,0x7fffffffffffffff,0 diff --git a/libc/sysv/consts/RLIM_SAVED_MAX.S b/libc/sysv/consts/RLIM_SAVED_MAX.S index 312626bed..67b4fc5d6 100644 --- a/libc/sysv/consts/RLIM_SAVED_MAX.S +++ b/libc/sysv/consts/RLIM_SAVED_MAX.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,RLIM_SAVED_MAX,-1,0,0x7fffffffffffffff,0,0,0 +.syscon rlim,RLIM_SAVED_MAX,0xffffffffffffffff,0x7fffffffffffffff,0x7fffffffffffffff,0x7fffffffffffffff,0x7fffffffffffffff,0 diff --git a/libc/sysv/consts/SA_NOCLDSTOP.S b/libc/sysv/consts/SA_NOCLDSTOP.S index b31167ec4..01f482ea8 100644 --- a/libc/sysv/consts/SA_NOCLDSTOP.S +++ b/libc/sysv/consts/SA_NOCLDSTOP.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon sigact,SA_NOCLDSTOP,1,8,8,8,8,0 +.syscon sigact,SA_NOCLDSTOP,1,8,8,8,8,1 diff --git a/libc/sysv/consts/SA_NOCLDWAIT.S b/libc/sysv/consts/SA_NOCLDWAIT.S index 71708bee5..921c1c347 100644 --- a/libc/sysv/consts/SA_NOCLDWAIT.S +++ b/libc/sysv/consts/SA_NOCLDWAIT.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon sigact,SA_NOCLDWAIT,2,0x20,0x20,0x20,0x20,0 +.syscon sigact,SA_NOCLDWAIT,2,32,32,32,32,2 diff --git a/libc/sysv/consts/SA_NODEFER.S b/libc/sysv/consts/SA_NODEFER.S index e6da9b8d5..785678705 100644 --- a/libc/sysv/consts/SA_NODEFER.S +++ b/libc/sysv/consts/SA_NODEFER.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon sigact,SA_NODEFER,0x40000000,0x10,0x10,0x10,0x10,0 +.syscon sigact,SA_NODEFER,0x40000000,16,16,16,16,0x40000000 diff --git a/libc/sysv/consts/SA_NOMASK.S b/libc/sysv/consts/SA_NOMASK.S index f3ebc2b4c..77d364345 100644 --- a/libc/sysv/consts/SA_NOMASK.S +++ b/libc/sysv/consts/SA_NOMASK.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon sigact,SA_NOMASK,0x40000000,0x10,0x10,0x10,0x10,0 +.syscon compat,SA_NOMASK,0x40000000,16,16,16,16,0x40000000 diff --git a/libc/sysv/consts/SA_ONESHOT.S b/libc/sysv/consts/SA_ONESHOT.S index b408be2c0..f719357fc 100644 --- a/libc/sysv/consts/SA_ONESHOT.S +++ b/libc/sysv/consts/SA_ONESHOT.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon sigact,SA_ONESHOT,0x80000000,0,0,0,0,0 +.syscon compat,SA_ONESHOT,0x80000000,4,4,4,4,0x80000000 diff --git a/libc/sysv/consts/SA_ONSTACK.S b/libc/sysv/consts/SA_ONSTACK.S index 7c461f57b..10237f767 100644 --- a/libc/sysv/consts/SA_ONSTACK.S +++ b/libc/sysv/consts/SA_ONSTACK.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon sigact,SA_ONSTACK,0x08000000,1,1,1,1,0 +.syscon sigact,SA_ONSTACK,0x08000000,1,1,1,1,0x08000000 diff --git a/libc/sysv/consts/SA_RESETHAND.S b/libc/sysv/consts/SA_RESETHAND.S index 9c697d4a8..57447ed2e 100644 --- a/libc/sysv/consts/SA_RESETHAND.S +++ b/libc/sysv/consts/SA_RESETHAND.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon sigact,SA_RESETHAND,0x80000000,4,4,4,4,0 +.syscon sigact,SA_RESETHAND,0x80000000,4,4,4,4,0x80000000 diff --git a/libc/sysv/consts/SA_RESTART.S b/libc/sysv/consts/SA_RESTART.S index 0f36b4a49..4d55eea7e 100644 --- a/libc/sysv/consts/SA_RESTART.S +++ b/libc/sysv/consts/SA_RESTART.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon sigact,SA_RESTART,0x10000000,2,2,2,2,0 +.syscon sigact,SA_RESTART,0x10000000,2,2,2,2,0x10000000 diff --git a/libc/sysv/consts/SA_RESTORER.S b/libc/sysv/consts/SA_RESTORER.S deleted file mode 100644 index 7f9491980..000000000 --- a/libc/sysv/consts/SA_RESTORER.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon sigact,SA_RESTORER,0x04000000,0,0,0,0,0 diff --git a/libc/sysv/consts/SA_SIGINFO.S b/libc/sysv/consts/SA_SIGINFO.S index 4f1b53071..46ca4be61 100644 --- a/libc/sysv/consts/SA_SIGINFO.S +++ b/libc/sysv/consts/SA_SIGINFO.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon sigact,SA_SIGINFO,4,0x40,0x40,0x40,0x40,0 +.syscon sigact,SA_SIGINFO,4,64,64,64,64,4 diff --git a/libc/sysv/consts/SEGV_ACCERR.S b/libc/sysv/consts/SEGV_ACCERR.S index cc37aade6..bafc738d8 100644 --- a/libc/sysv/consts/SEGV_ACCERR.S +++ b/libc/sysv/consts/SEGV_ACCERR.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,SEGV_ACCERR,2,2,2,2,2,0 +.syscon sicode,SEGV_ACCERR,2,2,2,2,2,2 diff --git a/libc/sysv/consts/SEGV_MAPERR.S b/libc/sysv/consts/SEGV_MAPERR.S index f6025fdd4..3f77bd82c 100644 --- a/libc/sysv/consts/SEGV_MAPERR.S +++ b/libc/sysv/consts/SEGV_MAPERR.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,SEGV_MAPERR,1,1,1,1,1,0 +.syscon sicode,SEGV_MAPERR,1,1,1,1,1,1 diff --git a/libc/sysv/consts/SIGIOT.S b/libc/sysv/consts/SIGIOT.S index b8c19047f..0da16e1b9 100644 --- a/libc/sysv/consts/SIGIOT.S +++ b/libc/sysv/consts/SIGIOT.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon sig,SIGIOT,6,6,6,6,6,6 +.syscon compat,SIGIOT,6,6,6,6,6,6 diff --git a/libc/sysv/consts/SIGPOLL.S b/libc/sysv/consts/SIGPOLL.S index 1bdcef26a..9fc61e573 100644 --- a/libc/sysv/consts/SIGPOLL.S +++ b/libc/sysv/consts/SIGPOLL.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon sig,SIGPOLL,29,0,0,0,0,29 +.syscon compat,SIGPOLL,29,23,23,23,23,29 diff --git a/libc/sysv/consts/SIGPWR.S b/libc/sysv/consts/SIGPWR.S index 0adb12f32..5d15017a3 100644 --- a/libc/sysv/consts/SIGPWR.S +++ b/libc/sysv/consts/SIGPWR.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon sig,SIGPWR,30,0,0,0,32,30 +.syscon compat,SIGPWR,30,30,30,30,32,30 diff --git a/libc/sysv/consts/SIGSTKFLT.S b/libc/sysv/consts/SIGSTKFLT.S deleted file mode 100644 index 7c26a6b74..000000000 --- a/libc/sysv/consts/SIGSTKFLT.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon sig,SIGSTKFLT,0x10,0,0,0,0,0x10 diff --git a/libc/sysv/consts/SIGSTKSZ.S b/libc/sysv/consts/SIGSTKSZ.S index 652bf9c05..1a557a4b5 100644 --- a/libc/sysv/consts/SIGSTKSZ.S +++ b/libc/sysv/consts/SIGSTKSZ.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon sig,SIGSTKSZ,0x2000,0x020000,0x8800,0x7000,0x7000,0x2000 +.syscon ss,SIGSTKSZ,0x2000,0x020000,0x8800,0x7000,0x7000,0x2000 diff --git a/libc/sysv/consts/SIGUNUSED.S b/libc/sysv/consts/SIGUNUSED.S deleted file mode 100644 index 9ef68febf..000000000 --- a/libc/sysv/consts/SIGUNUSED.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon sig,SIGUNUSED,31,0,0,0,0,31 diff --git a/libc/sysv/consts/SIGURG.S b/libc/sysv/consts/SIGURG.S index a9c7cc2e1..9dbe9cb7e 100644 --- a/libc/sysv/consts/SIGURG.S +++ b/libc/sysv/consts/SIGURG.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon sig,SIGURG,23,0x10,0x10,0x10,0x10,23 +.syscon sig,SIGURG,23,16,16,16,16,23 diff --git a/libc/sysv/consts/SI_ASYNCIO.S b/libc/sysv/consts/SI_ASYNCIO.S index d2782fb59..bc1cfc07d 100644 --- a/libc/sysv/consts/SI_ASYNCIO.S +++ b/libc/sysv/consts/SI_ASYNCIO.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,SI_ASYNCIO,-4,0x010004,0x010004,0,0,0 +.syscon sicode,SI_ASYNCIO,-4,0x010004,0x010004,0x80000000,-3,-4 diff --git a/libc/sysv/consts/SI_ASYNCNL.S b/libc/sysv/consts/SI_ASYNCNL.S index b6c952205..090ab2518 100644 --- a/libc/sysv/consts/SI_ASYNCNL.S +++ b/libc/sysv/consts/SI_ASYNCNL.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,SI_ASYNCNL,-60,0,0,0,0,0 +.syscon sicode,SI_ASYNCNL,-60,0x80000000,0x80000000,0x80000000,0x80000000,0x80000000 diff --git a/libc/sysv/consts/SI_KERNEL.S b/libc/sysv/consts/SI_KERNEL.S index db6a4ca4c..63c917744 100644 --- a/libc/sysv/consts/SI_KERNEL.S +++ b/libc/sysv/consts/SI_KERNEL.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,SI_KERNEL,0x80,0,0x010006,0,0,0 +.syscon sicode,SI_KERNEL,0x80,0x80000000,0x010006,0x80000000,0x80000000,0x80 diff --git a/libc/sysv/consts/SI_LOAD_SHIFT.S b/libc/sysv/consts/SI_LOAD_SHIFT.S deleted file mode 100644 index 1efc6e161..000000000 --- a/libc/sysv/consts/SI_LOAD_SHIFT.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon misc,SI_LOAD_SHIFT,0x10,0,0,0,0,0 diff --git a/libc/sysv/consts/SI_MESGQ.S b/libc/sysv/consts/SI_MESGQ.S index b6e439c31..7021509b3 100644 --- a/libc/sysv/consts/SI_MESGQ.S +++ b/libc/sysv/consts/SI_MESGQ.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,SI_MESGQ,-3,0x010005,0x010005,0,0,0 +.syscon sicode,SI_MESGQ,-3,0x010005,0x010005,0x80000000,-4,-3 diff --git a/libc/sysv/consts/SI_NOINFO.S b/libc/sysv/consts/SI_NOINFO.S new file mode 100644 index 000000000..be65136ff --- /dev/null +++ b/libc/sysv/consts/SI_NOINFO.S @@ -0,0 +1,2 @@ +#include "libc/sysv/consts/syscon.internal.h" +.syscon sicode,SI_NOINFO,32767,0x80000000,0,32767,32767,32767 diff --git a/libc/sysv/consts/SI_QUEUE.S b/libc/sysv/consts/SI_QUEUE.S index ec9ce4e06..2379cf591 100644 --- a/libc/sysv/consts/SI_QUEUE.S +++ b/libc/sysv/consts/SI_QUEUE.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,SI_QUEUE,-1,0x010002,0x010002,-2,-2,0 +.syscon sicode,SI_QUEUE,-1,0x010002,0x010002,-2,-1,-1 diff --git a/libc/sysv/consts/SI_SIGIO.S b/libc/sysv/consts/SI_SIGIO.S deleted file mode 100644 index 6f9717af5..000000000 --- a/libc/sysv/consts/SI_SIGIO.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon misc,SI_SIGIO,-5,0,0,0,0,0 diff --git a/libc/sysv/consts/SI_TIMER.S b/libc/sysv/consts/SI_TIMER.S index 64c46cd1a..bd9120da4 100644 --- a/libc/sysv/consts/SI_TIMER.S +++ b/libc/sysv/consts/SI_TIMER.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,SI_TIMER,-2,0x010003,0x010003,-3,-3,0 +.syscon sicode,SI_TIMER,-2,0x010003,0x010003,-3,-2,-2 diff --git a/libc/sysv/consts/SI_TKILL.S b/libc/sysv/consts/SI_TKILL.S index 6f59973a4..b9802a707 100644 --- a/libc/sysv/consts/SI_TKILL.S +++ b/libc/sysv/consts/SI_TKILL.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,SI_TKILL,-6,0,0,0,0,0 +.syscon sicode,SI_TKILL,-6,0x80000000,0x010007,-1,-5,-6 diff --git a/libc/sysv/consts/SI_USER.S b/libc/sysv/consts/SI_USER.S index d97a740b4..ffc2deea0 100644 --- a/libc/sysv/consts/SI_USER.S +++ b/libc/sysv/consts/SI_USER.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,SI_USER,0,0x010001,0x010001,0,0,0 +.syscon sicode,SI_USER,0,0x010001,0x010001,0,0,0 diff --git a/libc/sysv/consts/S_IEXEC.S b/libc/sysv/consts/S_IEXEC.S index 5e8189256..cec133e38 100644 --- a/libc/sysv/consts/S_IEXEC.S +++ b/libc/sysv/consts/S_IEXEC.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IEXEC,00100,00100,00100,00100,00100,00100 +.syscon stat,S_IEXEC,0000100,0000100,0000100,0000100,0000100,0000100 diff --git a/libc/sysv/consts/S_IREAD.S b/libc/sysv/consts/S_IREAD.S index d42eeedff..5e0bee1c4 100644 --- a/libc/sysv/consts/S_IREAD.S +++ b/libc/sysv/consts/S_IREAD.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IREAD,00400,00400,00400,00400,00400,00400 +.syscon stat,S_IREAD,0000400,0000400,0000400,0000400,0000400,0000400 diff --git a/libc/sysv/consts/S_IRGRP.S b/libc/sysv/consts/S_IRGRP.S index d29b91cae..ad9f3a6f8 100644 --- a/libc/sysv/consts/S_IRGRP.S +++ b/libc/sysv/consts/S_IRGRP.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IRGRP,00040,00040,00040,00040,00040,00040 +.syscon stat,S_IRGRP,0000040,0000040,0000040,0000040,0000040,0000040 diff --git a/libc/sysv/consts/S_IROTH.S b/libc/sysv/consts/S_IROTH.S index 1492a931b..6179fbf38 100644 --- a/libc/sysv/consts/S_IROTH.S +++ b/libc/sysv/consts/S_IROTH.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IROTH,00004,00004,00004,00004,00004,00004 +.syscon stat,S_IROTH,0000004,0000004,0000004,0000004,0000004,0000004 diff --git a/libc/sysv/consts/S_IRUSR.S b/libc/sysv/consts/S_IRUSR.S index 69802c4cf..7720d0f60 100644 --- a/libc/sysv/consts/S_IRUSR.S +++ b/libc/sysv/consts/S_IRUSR.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IRUSR,00400,00400,00400,00400,00400,00400 +.syscon stat,S_IRUSR,0000400,0000400,0000400,0000400,0000400,0000400 diff --git a/libc/sysv/consts/S_IRWXG.S b/libc/sysv/consts/S_IRWXG.S index dd2f6f755..e35589566 100644 --- a/libc/sysv/consts/S_IRWXG.S +++ b/libc/sysv/consts/S_IRWXG.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IRWXG,00070,00070,00070,00070,00070,00070 +.syscon stat,S_IRWXG,0000070,0000070,0000070,0000070,0000070,0000070 diff --git a/libc/sysv/consts/S_IRWXO.S b/libc/sysv/consts/S_IRWXO.S index 17fb95261..c9a4db418 100644 --- a/libc/sysv/consts/S_IRWXO.S +++ b/libc/sysv/consts/S_IRWXO.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IRWXO,00007,00007,00007,00007,00007,00007 +.syscon stat,S_IRWXO,0000007,0000007,0000007,0000007,0000007,0000007 diff --git a/libc/sysv/consts/S_IRWXU.S b/libc/sysv/consts/S_IRWXU.S index 3be366d68..3a291a499 100644 --- a/libc/sysv/consts/S_IRWXU.S +++ b/libc/sysv/consts/S_IRWXU.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IRWXU,00700,00700,00700,00700,00700,00700 +.syscon stat,S_IRWXU,0000700,0000700,0000700,0000700,0000700,0000700 diff --git a/libc/sysv/consts/S_ISGID.S b/libc/sysv/consts/S_ISGID.S index 3b5294408..108508726 100644 --- a/libc/sysv/consts/S_ISGID.S +++ b/libc/sysv/consts/S_ISGID.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_ISGID,02000,02000,02000,02000,02000,02000 +.syscon stat,S_ISGID,0002000,0002000,0002000,0002000,0002000,0002000 diff --git a/libc/sysv/consts/S_ISUID.S b/libc/sysv/consts/S_ISUID.S index 796799484..170183946 100644 --- a/libc/sysv/consts/S_ISUID.S +++ b/libc/sysv/consts/S_ISUID.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_ISUID,04000,04000,04000,04000,04000,04000 +.syscon stat,S_ISUID,0004000,0004000,0004000,0004000,0004000,0004000 diff --git a/libc/sysv/consts/S_ISVTX.S b/libc/sysv/consts/S_ISVTX.S index 5f1251d1c..33636aff5 100644 --- a/libc/sysv/consts/S_ISVTX.S +++ b/libc/sysv/consts/S_ISVTX.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_ISVTX,01000,01000,01000,01000,01000,01000 +.syscon stat,S_ISVTX,0001000,0001000,0001000,0001000,0001000,0001000 diff --git a/libc/sysv/consts/S_IWGRP.S b/libc/sysv/consts/S_IWGRP.S index 22defc1eb..27dd51e4c 100644 --- a/libc/sysv/consts/S_IWGRP.S +++ b/libc/sysv/consts/S_IWGRP.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IWGRP,00020,00020,00020,00020,00020,00020 +.syscon stat,S_IWGRP,0000020,0000020,0000020,0000020,0000020,0000020 diff --git a/libc/sysv/consts/S_IWOTH.S b/libc/sysv/consts/S_IWOTH.S index c760e0098..61e7b7ae8 100644 --- a/libc/sysv/consts/S_IWOTH.S +++ b/libc/sysv/consts/S_IWOTH.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IWOTH,00002,00002,00002,00002,00002,00002 +.syscon stat,S_IWOTH,0000002,0000002,0000002,0000002,0000002,0000002 diff --git a/libc/sysv/consts/S_IWRITE.S b/libc/sysv/consts/S_IWRITE.S index 9663e1a6f..df2360188 100644 --- a/libc/sysv/consts/S_IWRITE.S +++ b/libc/sysv/consts/S_IWRITE.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IWRITE,00200,00200,00200,00200,00200,00200 +.syscon stat,S_IWRITE,0000200,0000200,0000200,0000200,0000200,0000200 diff --git a/libc/sysv/consts/S_IWUSR.S b/libc/sysv/consts/S_IWUSR.S index e6493ff0b..7df8df706 100644 --- a/libc/sysv/consts/S_IWUSR.S +++ b/libc/sysv/consts/S_IWUSR.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IWUSR,00200,00200,00200,00200,00200,00200 +.syscon stat,S_IWUSR,0000200,0000200,0000200,0000200,0000200,0000200 diff --git a/libc/sysv/consts/S_IXGRP.S b/libc/sysv/consts/S_IXGRP.S index 9db4c424b..f23c82907 100644 --- a/libc/sysv/consts/S_IXGRP.S +++ b/libc/sysv/consts/S_IXGRP.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IXGRP,00010,00010,00010,00010,00010,00010 +.syscon stat,S_IXGRP,0000010,0000010,0000010,0000010,0000010,0000010 diff --git a/libc/sysv/consts/S_IXOTH.S b/libc/sysv/consts/S_IXOTH.S index 74329aeef..ff3cc2474 100644 --- a/libc/sysv/consts/S_IXOTH.S +++ b/libc/sysv/consts/S_IXOTH.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IXOTH,00001,00001,00001,00001,00001,00001 +.syscon stat,S_IXOTH,0000001,0000001,0000001,0000001,0000001,0000001 diff --git a/libc/sysv/consts/S_IXUSR.S b/libc/sysv/consts/S_IXUSR.S index d91c11525..fb7f231b5 100644 --- a/libc/sysv/consts/S_IXUSR.S +++ b/libc/sysv/consts/S_IXUSR.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IXUSR,00100,00100,00100,00100,00100,00100 +.syscon stat,S_IXUSR,0000100,0000100,0000100,0000100,0000100,0000100 diff --git a/libc/sysv/consts/TRAP_BRKPT.S b/libc/sysv/consts/TRAP_BRKPT.S index 3dc73994e..a2a5e7b4d 100644 --- a/libc/sysv/consts/TRAP_BRKPT.S +++ b/libc/sysv/consts/TRAP_BRKPT.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,TRAP_BRKPT,1,1,1,1,1,0 +.syscon sicode,TRAP_BRKPT,1,1,1,1,1,1 diff --git a/libc/sysv/consts/TRAP_TRACE.S b/libc/sysv/consts/TRAP_TRACE.S index a2b0c356c..1daca2f96 100644 --- a/libc/sysv/consts/TRAP_TRACE.S +++ b/libc/sysv/consts/TRAP_TRACE.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,TRAP_TRACE,2,2,2,2,2,0 +.syscon sicode,TRAP_TRACE,2,2,2,2,2,2 diff --git a/libc/sysv/consts/bus.h b/libc/sysv/consts/bus.h deleted file mode 100644 index e6f9dddac..000000000 --- a/libc/sysv/consts/bus.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef COSMOPOLITAN_LIBC_SYSV_CONSTS_BUS_H_ -#define COSMOPOLITAN_LIBC_SYSV_CONSTS_BUS_H_ -#include "libc/runtime/symbolic.h" - -#define BUS_ADRALN SYMBOLIC(BUS_ADRALN) -#define BUS_ADRERR SYMBOLIC(BUS_ADRERR) -#define BUS_DEVICE_RESET SYMBOLIC(BUS_DEVICE_RESET) -#define BUS_MCEERR_AO SYMBOLIC(BUS_MCEERR_AO) -#define BUS_MCEERR_AR SYMBOLIC(BUS_MCEERR_AR) -#define BUS_OBJERR SYMBOLIC(BUS_OBJERR) - -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ - -extern const long BUS_ADRALN; -extern const long BUS_ADRERR; -extern const long BUS_DEVICE_RESET; -extern const long BUS_MCEERR_AO; -extern const long BUS_MCEERR_AR; -extern const long BUS_OBJERR; - -COSMOPOLITAN_C_END_ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_BUS_H_ */ diff --git a/libc/sysv/consts/cld.h b/libc/sysv/consts/cld.h deleted file mode 100644 index 9dd866ea9..000000000 --- a/libc/sysv/consts/cld.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef COSMOPOLITAN_LIBC_SYSV_CONSTS_CLD_H_ -#define COSMOPOLITAN_LIBC_SYSV_CONSTS_CLD_H_ - -#define CLD_CONTINUED 6 -#define CLD_DUMPED 3 -#define CLD_EXITED 1 -#define CLD_KILLED 2 -#define CLD_STOPPED 5 -#define CLD_TRAPPED 4 - -#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_CLD_H_ */ diff --git a/libc/sysv/consts/ill.h b/libc/sysv/consts/ill.h deleted file mode 100644 index 141f3e391..000000000 --- a/libc/sysv/consts/ill.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef COSMOPOLITAN_LIBC_SYSV_CONSTS_ILL_H_ -#define COSMOPOLITAN_LIBC_SYSV_CONSTS_ILL_H_ -#include "libc/runtime/symbolic.h" - -#define ILL_BADSTK SYMBOLIC(ILL_BADSTK) -#define ILL_COPROC SYMBOLIC(ILL_COPROC) -#define ILL_ILLADR SYMBOLIC(ILL_ILLADR) -#define ILL_ILLOPC SYMBOLIC(ILL_ILLOPC) -#define ILL_ILLOPN SYMBOLIC(ILL_ILLOPN) -#define ILL_ILLTRP SYMBOLIC(ILL_ILLTRP) -#define ILL_PRVOPC SYMBOLIC(ILL_PRVOPC) -#define ILL_PRVREG SYMBOLIC(ILL_PRVREG) - -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ - -extern const long ILL_BADSTK; -extern const long ILL_COPROC; -extern const long ILL_ILLADR; -extern const long ILL_ILLOPC; -extern const long ILL_ILLOPN; -extern const long ILL_ILLTRP; -extern const long ILL_PRVOPC; -extern const long ILL_PRVREG; - -COSMOPOLITAN_C_END_ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_ILL_H_ */ diff --git a/libc/sysv/consts/rlimit.h b/libc/sysv/consts/rlimit.h index 1ab7163ac..c847974e4 100644 --- a/libc/sysv/consts/rlimit.h +++ b/libc/sysv/consts/rlimit.h @@ -2,22 +2,22 @@ #define COSMOPOLITAN_LIBC_SYSV_CONSTS_RLIMIT_H_ #include "libc/runtime/symbolic.h" -#define RLIMIT_AS SYMBOLIC(RLIMIT_AS) -#define RLIMIT_CORE SYMBOLIC(RLIMIT_CORE) -#define RLIMIT_CPU SYMBOLIC(RLIMIT_CPU) -#define RLIMIT_DATA SYMBOLIC(RLIMIT_DATA) -#define RLIMIT_FSIZE SYMBOLIC(RLIMIT_FSIZE) -#define RLIMIT_LOCKS SYMBOLIC(RLIMIT_LOCKS) -#define RLIMIT_MEMLOCK SYMBOLIC(RLIMIT_MEMLOCK) -#define RLIMIT_MSGQUEUE SYMBOLIC(RLIMIT_MSGQUEUE) -#define RLIMIT_NICE SYMBOLIC(RLIMIT_NICE) -#define RLIMIT_NLIMITS SYMBOLIC(RLIMIT_NLIMITS) -#define RLIMIT_NOFILE SYMBOLIC(RLIMIT_NOFILE) -#define RLIMIT_NPROC SYMBOLIC(RLIMIT_NPROC) -#define RLIMIT_RSS SYMBOLIC(RLIMIT_RSS) -#define RLIMIT_RTPRIO SYMBOLIC(RLIMIT_RTPRIO) +#define RLIMIT_AS SYMBOLIC(RLIMIT_AS) +#define RLIMIT_CORE SYMBOLIC(RLIMIT_CORE) +#define RLIMIT_CPU SYMBOLIC(RLIMIT_CPU) +#define RLIMIT_DATA SYMBOLIC(RLIMIT_DATA) +#define RLIMIT_FSIZE SYMBOLIC(RLIMIT_FSIZE) +#define RLIMIT_LOCKS SYMBOLIC(RLIMIT_LOCKS) +#define RLIMIT_MEMLOCK SYMBOLIC(RLIMIT_MEMLOCK) +#define RLIMIT_MSGQUEUE SYMBOLIC(RLIMIT_MSGQUEUE) +#define RLIMIT_NICE SYMBOLIC(RLIMIT_NICE) +#define RLIMIT_NOFILE SYMBOLIC(RLIMIT_NOFILE) +#define RLIMIT_NPROC SYMBOLIC(RLIMIT_NPROC) +#define RLIMIT_RSS SYMBOLIC(RLIMIT_RSS) +#define RLIMIT_RTPRIO SYMBOLIC(RLIMIT_RTPRIO) #define RLIMIT_SIGPENDING SYMBOLIC(RLIMIT_SIGPENDING) -#define RLIMIT_STACK SYMBOLIC(RLIMIT_STACK) +#define RLIMIT_STACK SYMBOLIC(RLIMIT_STACK) +#define RLIMIT_VMEM SYMBOLIC(RLIMIT_VMEM) #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ @@ -31,13 +31,13 @@ extern const long RLIMIT_LOCKS; extern const long RLIMIT_MEMLOCK; extern const long RLIMIT_MSGQUEUE; extern const long RLIMIT_NICE; -extern const long RLIMIT_NLIMITS; extern const long RLIMIT_NOFILE; extern const long RLIMIT_NPROC; extern const long RLIMIT_RSS; extern const long RLIMIT_RTPRIO; extern const long RLIMIT_SIGPENDING; extern const long RLIMIT_STACK; +extern const long RLIMIT_VMEM; COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/sysv/consts/s.h b/libc/sysv/consts/s.h index e1ac2f0c2..07b2ae6bc 100644 --- a/libc/sysv/consts/s.h +++ b/libc/sysv/consts/s.h @@ -1,64 +1,32 @@ #ifndef COSMOPOLITAN_LIBC_SYSV_CONSTS_S_H_ #define COSMOPOLITAN_LIBC_SYSV_CONSTS_S_H_ -#include "libc/runtime/symbolic.h" -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ -extern const long S_IEXEC; -extern const long S_IFBLK; -extern const long S_IFCHR; -extern const long S_IFDIR; -extern const long S_IFIFO; -extern const long S_IFLNK; -extern const long S_IFMT; -extern const long S_IFREG; -extern const long S_IFSOCK; -extern const long S_IREAD; -extern const long S_IRGRP; -extern const long S_IROTH; -extern const long S_IRUSR; -extern const long S_IRWXG; -extern const long S_IRWXO; -extern const long S_IRWXU; -extern const long S_ISGID; -extern const long S_ISUID; -extern const long S_ISVTX; -extern const long S_IWGRP; -extern const long S_IWOTH; -extern const long S_IWRITE; -extern const long S_IWUSR; -extern const long S_IXGRP; -extern const long S_IXOTH; -extern const long S_IXUSR; +#define S_ISVTX 01000 /* THE STICKY BIT */ +#define S_ISGID 02000 /* the setgid bit */ +#define S_ISUID 04000 /* the setuid bit */ +#define S_IXUSR 00100 /* user --x; just use octal */ +#define S_IWUSR 00200 /* user -w-; just use octal */ +#define S_IRUSR 00400 /* user r--; just use octal */ +#define S_IRWXU 00700 /* user rwx; just use octal */ +#define S_IXGRP 00010 /* group --x; just use octal */ +#define S_IWGRP 00020 /* group -w-; just use octal */ +#define S_IRGRP 00040 /* group r--; just use octal */ +#define S_IRWXG 00070 /* group rwx; just use octal */ +#define S_IXOTH 00001 /* other --x; just use octal */ +#define S_IWOTH 00002 /* other -w-; just use octal */ +#define S_IROTH 00004 /* other r--; just use octal */ +#define S_IRWXO 00007 /* other rwx; just use octal */ +#define S_IREAD 00400 /* just use octal */ +#define S_IEXEC 00100 /* just use octal */ +#define S_IWRITE 00200 /* just use octal */ -COSMOPOLITAN_C_END_ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ - -#define S_IFREG LITERALLY(0100000) -#define S_IFBLK LITERALLY(0060000) -#define S_IFCHR LITERALLY(0020000) -#define S_IFDIR LITERALLY(0040000) -#define S_IFIFO LITERALLY(0010000) -#define S_IFMT LITERALLY(0170000) -#define S_IFLNK LITERALLY(0120000) -#define S_IFSOCK LITERALLY(0140000) -#define S_ISVTX LITERALLY(01000) -#define S_ISGID LITERALLY(02000) -#define S_ISUID LITERALLY(04000) -#define S_IEXEC LITERALLY(00100) -#define S_IWRITE LITERALLY(00200) -#define S_IREAD LITERALLY(00400) -#define S_IXUSR LITERALLY(00100) -#define S_IWUSR LITERALLY(00200) -#define S_IRUSR LITERALLY(00400) -#define S_IRWXU LITERALLY(00700) -#define S_IXGRP LITERALLY(00010) -#define S_IWGRP LITERALLY(00020) -#define S_IRGRP LITERALLY(00040) -#define S_IRWXG LITERALLY(00070) -#define S_IXOTH LITERALLY(00001) -#define S_IWOTH LITERALLY(00002) -#define S_IROTH LITERALLY(00004) -#define S_IRWXO LITERALLY(00007) +#define S_IFIFO (1 << 12) /* pipe */ +#define S_IFCHR (2 << 12) /* character device */ +#define S_IFDIR (4 << 12) /* directory */ +#define S_IFBLK (6 << 12) /* block device */ +#define S_IFREG (8 << 12) /* regular file */ +#define S_IFLNK (10 << 12) /* symbolic link */ +#define S_IFSOCK (12 << 12) /* socket */ +#define S_IFMT (15 << 12) /* mask of file types above */ #endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_S_H_ */ diff --git a/libc/sysv/consts/sa.h b/libc/sysv/consts/sa.h index b175276b4..aa85f7660 100644 --- a/libc/sysv/consts/sa.h +++ b/libc/sysv/consts/sa.h @@ -4,14 +4,13 @@ #define SA_NOCLDSTOP SYMBOLIC(SA_NOCLDSTOP) #define SA_NOCLDWAIT SYMBOLIC(SA_NOCLDWAIT) -#define SA_NODEFER SYMBOLIC(SA_NODEFER) -#define SA_NOMASK SYMBOLIC(SA_NOMASK) -#define SA_ONESHOT SYMBOLIC(SA_ONESHOT) -#define SA_ONSTACK SYMBOLIC(SA_ONSTACK) +#define SA_NODEFER SYMBOLIC(SA_NODEFER) +#define SA_NOMASK SYMBOLIC(SA_NOMASK) +#define SA_ONESHOT SYMBOLIC(SA_ONESHOT) +#define SA_ONSTACK SYMBOLIC(SA_ONSTACK) #define SA_RESETHAND SYMBOLIC(SA_RESETHAND) -#define SA_RESTART SYMBOLIC(SA_RESTART) -#define SA_RESTORER SYMBOLIC(SA_RESTORER) -#define SA_SIGINFO SYMBOLIC(SA_SIGINFO) +#define SA_RESTART SYMBOLIC(SA_RESTART) +#define SA_SIGINFO SYMBOLIC(SA_SIGINFO) #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ @@ -24,7 +23,6 @@ extern const long SA_ONESHOT; extern const long SA_ONSTACK; extern const long SA_RESETHAND; extern const long SA_RESTART; -extern const long SA_RESTORER; extern const long SA_SIGINFO; COSMOPOLITAN_C_END_ diff --git a/libc/sysv/consts/segv.h b/libc/sysv/consts/segv.h deleted file mode 100644 index 711fb69fd..000000000 --- a/libc/sysv/consts/segv.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef COSMOPOLITAN_LIBC_SYSV_CONSTS_SEGV_H_ -#define COSMOPOLITAN_LIBC_SYSV_CONSTS_SEGV_H_ -#include "libc/runtime/symbolic.h" - -#define SEGV_ACCERR SYMBOLIC(SEGV_ACCERR) -#define SEGV_MAPERR SYMBOLIC(SEGV_MAPERR) - -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ - -extern const long SEGV_ACCERR; -extern const long SEGV_MAPERR; - -COSMOPOLITAN_C_END_ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_SEGV_H_ */ diff --git a/libc/sysv/consts/sicode.h b/libc/sysv/consts/sicode.h new file mode 100644 index 000000000..11922b88d --- /dev/null +++ b/libc/sysv/consts/sicode.h @@ -0,0 +1,105 @@ +#ifndef COSMOPOLITAN_LIBC_SYSV_CONSTS_SICODE_H_ +#define COSMOPOLITAN_LIBC_SYSV_CONSTS_SICODE_H_ +#include "libc/runtime/symbolic.h" +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +extern const long SI_USER; +extern const long SI_QUEUE; +extern const long SI_TIMER; +extern const long SI_MESGQ; +extern const long SI_ASYNCIO; +extern const long SI_TKILL; +extern const long SI_ASYNCNL; +extern const long SI_KERNEL; +extern const long SI_NOINFO; +extern const long CLD_EXITED; +extern const long CLD_KILLED; +extern const long CLD_DUMPED; +extern const long CLD_TRAPPED; +extern const long CLD_STOPPED; +extern const long CLD_CONTINUED; +extern const long TRAP_BRKPT; +extern const long TRAP_TRACE; +extern const long SEGV_MAPERR; +extern const long SEGV_ACCERR; +extern const long FPE_INTDIV; +extern const long FPE_INTOVF; +extern const long FPE_FLTDIV; +extern const long FPE_FLTOVF; +extern const long FPE_FLTUND; +extern const long FPE_FLTRES; +extern const long FPE_FLTINV; +extern const long FPE_FLTSUB; +extern const long ILL_ILLOPC; +extern const long ILL_ILLOPN; +extern const long ILL_ILLADR; +extern const long ILL_ILLTRP; +extern const long ILL_PRVOPC; +extern const long ILL_PRVREG; +extern const long ILL_COPROC; +extern const long ILL_BADSTK; +extern const long BUS_ADRALN; +extern const long BUS_ADRERR; +extern const long BUS_OBJERR; +extern const long BUS_MCEERR_AR; +extern const long BUS_MCEERR_AO; +extern const long POLL_IN; +extern const long POLL_OUT; +extern const long POLL_MSG; +extern const long POLL_ERR; +extern const long POLL_PRI; +extern const long POLL_HUP; + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ + +#define CLD_EXITED LITERALLY(1) +#define CLD_KILLED LITERALLY(2) +#define CLD_DUMPED LITERALLY(3) +#define CLD_TRAPPED LITERALLY(4) +#define CLD_STOPPED LITERALLY(5) +#define CLD_CONTINUED LITERALLY(6) +#define TRAP_BRKPT LITERALLY(1) +#define TRAP_TRACE LITERALLY(2) +#define SEGV_MAPERR LITERALLY(1) +#define SEGV_ACCERR LITERALLY(2) +#define ILL_ILLOPC LITERALLY(1) +#define ILL_PRVREG LITERALLY(6) +#define ILL_COPROC LITERALLY(7) +#define ILL_BADSTK LITERALLY(8) +#define BUS_ADRALN LITERALLY(1) +#define BUS_ADRERR LITERALLY(2) +#define BUS_OBJERR LITERALLY(3) +#define POLL_IN LITERALLY(1) +#define POLL_OUT LITERALLY(2) +#define POLL_MSG LITERALLY(3) +#define POLL_ERR LITERALLY(4) +#define POLL_PRI LITERALLY(5) +#define POLL_HUP LITERALLY(6) + +#define SI_USER SYMBOLIC(SI_USER) +#define SI_QUEUE SYMBOLIC(SI_QUEUE) +#define SI_TIMER SYMBOLIC(SI_TIMER) +#define SI_MESGQ SYMBOLIC(SI_MESGQ) +#define SI_ASYNCIO SYMBOLIC(SI_ASYNCIO) +#define SI_TKILL SYMBOLIC(SI_TKILL) +#define SI_ASYNCNL SYMBOLIC(SI_ASYNCNL) +#define SI_KERNEL SYMBOLIC(SI_KERNEL) +#define SI_NOINFO SYMBOLIC(SI_NOINFO) +#define FPE_INTDIV SYMBOLIC(FPE_INTDIV) +#define FPE_INTOVF SYMBOLIC(FPE_INTOVF) +#define FPE_FLTDIV SYMBOLIC(FPE_FLTDIV) +#define FPE_FLTOVF SYMBOLIC(FPE_FLTOVF) +#define FPE_FLTUND SYMBOLIC(FPE_FLTUND) +#define FPE_FLTRES SYMBOLIC(FPE_FLTRES) +#define FPE_FLTINV SYMBOLIC(FPE_FLTINV) +#define FPE_FLTSUB SYMBOLIC(FPE_FLTSUB) +#define ILL_ILLOPN SYMBOLIC(ILL_ILLOPN) +#define ILL_ILLADR SYMBOLIC(ILL_ILLADR) +#define ILL_ILLTRP SYMBOLIC(ILL_ILLTRP) +#define ILL_PRVOPC SYMBOLIC(ILL_PRVOPC) +#define BUS_MCEERR_AR SYMBOLIC(BUS_MCEERR_AR) +#define BUS_MCEERR_AO SYMBOLIC(BUS_MCEERR_AO) + +#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_SICODE_H_ */ diff --git a/libc/sysv/consts/sigpoll.h b/libc/sysv/consts/sigpoll.h deleted file mode 100644 index 8c4258648..000000000 --- a/libc/sysv/consts/sigpoll.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef COSMOPOLITAN_LIBC_SYSV_CONSTS_POLL_H_ -#define COSMOPOLITAN_LIBC_SYSV_CONSTS_POLL_H_ -#include "libc/runtime/symbolic.h" - -#define POLL_ERR SYMBOLIC(POLL_ERR) -#define POLL_HUP SYMBOLIC(POLL_HUP) -#define POLL_IN SYMBOLIC(POLL_IN) -#define POLL_MSG SYMBOLIC(POLL_MSG) -#define POLL_OUT SYMBOLIC(POLL_OUT) -#define POLL_PRI SYMBOLIC(POLL_PRI) - -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ - -extern const long POLL_ERR; -extern const long POLL_HUP; -extern const long POLL_IN; -extern const long POLL_MSG; -extern const long POLL_OUT; -extern const long POLL_PRI; - -COSMOPOLITAN_C_END_ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_POLL_H_ */ diff --git a/libc/sysv/consts/trap.h b/libc/sysv/consts/trap.h deleted file mode 100644 index b0f6d8fca..000000000 --- a/libc/sysv/consts/trap.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef COSMOPOLITAN_LIBC_SYSV_CONSTS_TRAP_H_ -#define COSMOPOLITAN_LIBC_SYSV_CONSTS_TRAP_H_ -#include "libc/runtime/symbolic.h" - -#define TRAP_BRKPT SYMBOLIC(TRAP_BRKPT) -#define TRAP_TRACE SYMBOLIC(TRAP_TRACE) - -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ - -extern const long TRAP_BRKPT; -extern const long TRAP_TRACE; - -COSMOPOLITAN_C_END_ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_TRAP_H_ */ diff --git a/libc/sysv/netbsd.py b/libc/sysv/netbsd.py deleted file mode 100644 index cb97b60a5..000000000 --- a/libc/sysv/netbsd.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -import re -import sys -NETBSD = {} -MAXBIT = 0 - -def bsr(x): - r = -1 - while x: - r += 1 - x >>= 1 - return r - -def binify(x): - return "%016x" % (x) - -lines = open('libc/sysv/netbsd.txt').read().split('\n') -for line in lines: - if 'STD' not in line: continue - m = re.search(r'^(\d+).*?([_0-9A-Za-z]+)\(', line) - if not m: continue - NETBSD[m.group(2)] = int(m.group(1)) - -lines = open('libc/sysv/syscalls.sh').read().split('\n') -for line in lines: - if line.startswith('scall'): - fields = line.split() - name = fields[1] - if name.startswith("'"): name = name[1:] - if name.endswith("'"): name = name[:-1] - if name.startswith("__"): name = name[2:] - if name.startswith("sys_"): name = name[4:] - if name.endswith("_bsd"): name = name[:-4] - if name.endswith("_freebsd"): name = name[:-8] - numbas = fields[2][2:] - numbers = int(numbas, 16) - systemd = (numbers >> 000) & 0xffff - xnu = (numbers >> 020) & 0x0fff - xnukind = (numbers >> 034) & 0xf - freebsd = (numbers >> 040) & 0xffff - openbsd = (numbers >> 060) & 0xffff - netbsd = NETBSD.get(name, 0xffff) - com = "" - if netbsd != 0xffff: - if netbsd == systemd: com += " SYSTEMD" - if netbsd == xnu: com += " xnu" - if netbsd == freebsd: com += " freebsd" - if netbsd == openbsd: com += " openbsd" - getbit = lambda x: 0 if x == 0xffff else bsr(x) - maxbit = max([getbit(systemd), getbit(xnu), getbit(freebsd), getbit(openbsd), getbit(netbsd)]) - MAXBIT = max(maxbit, MAXBIT) - # print "%-30s %04x %04x %04x %04x %04x %3d %3d %s" % (name, systemd, xnu, freebsd, openbsd, netbsd, maxbit, MAXBIT, com) - systemd &= 0b111111111111 - xnu &= 0b111111111111 - freebsd &= 0b111111111111 - openbsd &= 0b111111111111 - netbsd &= 0b111111111111 - numba = netbsd << (4*13) | openbsd << (4*10) | freebsd << (4*7) | xnukind << (4*6) | xnu << (4*3) | systemd - assert numbas in line - line = line.replace(numbas, binify(numba)) - print line diff --git a/libc/sysv/newconsts.py b/libc/sysv/newconsts.py deleted file mode 100644 index 7285ef653..000000000 --- a/libc/sysv/newconsts.py +++ /dev/null @@ -1,74 +0,0 @@ -import sys - -H = '/home/jart/vendor/netbsd/sys/sys/spawn.h' -G = 'errno' - -MAGNUMS = {} - -def ParseInt(x): - s = 1 - if x.startswith('-'): - x = x[1:] - s = -1 - if x.startswith('0x'): - x = int(x[2:], 16) - elif x.startswith('0b'): - x = int(x[2:], 2) - elif x.startswith('0'): - x = int(x, 8) - else: - x = int(x, 10) - return x * s - -def FormatInt(x): - if x == -1: - return "-1" - if -128 <= x < 128: - return "%d" % (x) - else: - return "%#x" % (x) - -for line in open(H): - if line.startswith('#define'): - a = line.split() - if len(a) >= 3: - try: - MAGNUMS[a[1]] = ParseInt(a[2]) - except ValueError: - pass - -GROUP_COLUMN = 2 -NAME_COLUMN = 4 -SYSTEMD_COLUMN = 6 -XNU_COLUMN = 8 -FREEBSD_COLUMN = 10 -OPENBSD_COLUMN = 12 -NETBSD_COLUMN = 14 - -print """\ -# The Fifth Bell System, Community Edition -# > catalogue of carnage -# -# group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD NetBSD XENIX Commentary""" - -for line in open('libc/sysv/consts.sh'): - if not line.startswith('syscon'): continue - fields = [""] - i = 0 - t = 0 - for i in range(len(line)): - if t == 0: - if line[i] == '\t': - fields.append("") - t = 1 - elif t == 1: - if line[i] != '\t': - fields.append("") - t = 0 - fields[-1] = fields[-1] + line[i] - k = fields[NAME_COLUMN] - v = ParseInt(fields[NETBSD_COLUMN]) - if k in MAGNUMS and MAGNUMS[k] != v: - fields[NETBSD_COLUMN] = FormatInt(MAGNUMS[k]) - # if fields[GROUP_COLUMN] == G: - sys.stdout.write("".join(fields)) diff --git a/libc/sysv/nr.py b/libc/sysv/nr.py deleted file mode 100644 index 138b11798..000000000 --- a/libc/sysv/nr.py +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -lines = open('libc/sysv/syscalls.sh').read().split('\n') -for line in lines: - if not line.startswith('scall'): - continue - fields = line.split() - name = fields[1] - if name.startswith("'"): name = name[1:] - if name.endswith("'"): name = name[:-1] - if name.startswith("__"): name = name[2:] - if name.startswith("sys_"): name = name[4:] - if name.endswith("_bsd"): name = name[:-4] - if name.endswith("_freebsd"): name = name[:-8] - numbers = int(fields[2][2:], 16) - systemd = (numbers >> 000) & 0xffff - xnu = (numbers >> 020) & 0x0fff | ((numbers >> 28) & 0xf) << 20 - freebsd = (numbers >> 040) & 0xffff - openbsd = (numbers >> 060) & 0xffff - print "syscon\tnr\t__NR_%s\t\t\t\t0x%04x\t\t\t0x%07x\t\t0x%04x\t\t\t0x%04x\t\t\t-1" % (name, systemd, xnu, freebsd, openbsd) diff --git a/libc/sysv/syscalls.sh b/libc/sysv/syscalls.sh index fd9ac3c22..09976ccae 100755 --- a/libc/sysv/syscalls.sh +++ b/libc/sysv/syscalls.sh @@ -61,7 +61,7 @@ scall sys_select 0x1a104705d205d017 globl hidden scall pselect 0x1b406e20a218afff globl scall pselect6 0xfffffffffffff10e globl scall sys_sched_yield 0x15e12a14b103c018 globl hidden # swtch() on xnu -scall sys_mremap 0x19bffffffffff019 globl hidden +scall __sys_mremap 0x19bffffffffff019 globl hidden scall mincore 0x04e04e04e204e01b globl scall sys_madvise 0x04b04b04b204b01c globl hidden scall shmget 0x0e71210e7210901d globl # consider mmap @@ -95,7 +95,7 @@ scall sys_fork 0x0020020022002039 globl hidden # xnu needs eax&=~-edx bc eax al #scall vfork 0x042042042204203a globl # this syscall is from the moon so we implement it by hand in libc/calls/hefty/vfork.S scall sys_posix_spawn 0xfffffffff20f4fff globl hidden # good luck figuring out how xnu defines this scall __sys_execve 0x03b03b03b203b03b globl hidden -scall sys_wait4 0x1c100b007200703d globl hidden +scall __sys_wait4 0x1c100b007200703d globl hidden scall sys_kill 0x02507a025202503e globl hidden # kill(pid, sig, 1) b/c xnu scall sys_killpg 0xffffff092fffffff globl hidden scall clone 0xfffffffffffff038 globl @@ -137,7 +137,7 @@ scall sys_lchown 0x1130fe0fe216c05e globl hidden # impl. w/ fchownat() scall umask 0x03c03c03c203c05f globl scall sys_gettimeofday 0x1a20430742074060 globl hidden # xnu esi/edx=0 scall sys_getrlimit 0x0c20c20c220c2061 globl hidden -scall sys_getrusage 0x1bd0130752075062 globl hidden +scall __sys_getrusage 0x1bd0130752075062 globl hidden scall sys_sysinfo 0xfffffffffffff063 globl hidden scall sys_times 0xfffffffffffff064 globl hidden scall sys_ptrace 0x01a01a01a201a065 globl hidden @@ -190,7 +190,8 @@ scall setfsgid 0xfffffffffffff07b globl scall capget 0xfffffffffffff07d globl scall capset 0xfffffffffffff07e globl scall sigtimedwait 0xffffff159ffff080 globl -scall rt_sigqueueinfo 0xfffffffffffff081 globl +scall sys_sigqueue 0xffffff1c8fffffff globl +scall sys_sigqueueinfo 0x0f5ffffffffff081 globl # rt_sigqueueinfo on linux scall personality 0xfffffffffffff087 globl scall ustat 0xfffffffffffff088 globl scall sysfs 0xfffffffffffff08b globl @@ -254,6 +255,11 @@ scall timer_settime 0x1beffffffffff0df globl scall timer_gettime 0x1bfffffffffff0e0 globl scall timer_getoverrun 0x0efffffffffff0e1 globl scall timer_delete 0x0ecffffffffff0e2 globl +scall ktimer_create 0xffffff0ebfffffff globl +scall ktimer_delete 0xffffff0ecfffffff globl +scall ktimer_getoverrun 0xffffff0effffffff globl +scall ktimer_gettime 0xffffff0eefffffff globl +scall ktimer_settime 0xffffff0edfffffff globl scall clock_settime 0x1ac0580e9ffff0e3 globl scall sys_clock_gettime 0x1ab0570e8ffff0e4 globl hidden # Linux 2.6+ (c. 2003); XNU uses magic address scall clock_getres 0x1ad0590eaffff0e5 globl @@ -690,11 +696,6 @@ scall ksem_timedwait 0xffffff1b9fffffff globl scall ksem_trywait 0xffffff193fffffff globl scall ksem_unlink 0xffffff196fffffff globl scall ksem_wait 0xffffff192fffffff globl -scall ktimer_create 0xffffff0ebfffffff globl -scall ktimer_delete 0xffffff0ecfffffff globl -scall ktimer_getoverrun 0xffffff0effffffff globl -scall ktimer_gettime 0xffffff0eefffffff globl -scall ktimer_settime 0xffffff0edfffffff globl scall lchflags 0x130fff187fffffff globl scall lchmod 0x112fff112fffffff globl scall lgetfh 0xffffff0a0fffffff globl @@ -734,7 +735,6 @@ scall setfib 0xffffff0affffffff globl scall sethostid 0xffffff08ffffffff globl scall setloginclass 0xffffff20cfffffff globl scall sigblock 0xffffff06dfffffff globl -scall sigqueue 0xffffff1c8fffffff globl scall sigsetmask 0xffffff06efffffff globl scall sigstack 0xffffff070fffffff globl scall sigvec 0xffffff06cfffffff globl diff --git a/libc/sysv/versions.txt b/libc/sysv/versions.txt deleted file mode 100644 index a99dd23e9..000000000 --- a/libc/sysv/versions.txt +++ /dev/null @@ -1,12 +0,0 @@ -1993 FreeBSD 1.o -1994 FreeBSD 2 -1998 FreeBSD 3 -2000 FreeBSD 4 (EOL 2007) -2003 FreeBSD 5 -2005 FreeBSD 6 -2008 FreeBSD 7 (EOL 2013) -2009 FreeBSD 8 (EOL 2015) -2012 FreeBSD 9 (EOL 2016) -2014 FreeBSD 10 (EOL 2018) -2016 FreeBSD 11 -2018 FreeBSD 12 diff --git a/libc/x/x.h b/libc/x/x.h index a5b6199a9..dd359878f 100644 --- a/libc/x/x.h +++ b/libc/x/x.h @@ -36,7 +36,8 @@ char *xasprintf(const char *, ...) printfesque(1) paramsnonnull((1)) _XMAL; char *xvasprintf(const char *, va_list) _XPNN _XMAL; char *xgetline(struct FILE *) _XPNN mallocesque; void *xmalloc(size_t) attributeallocsize((1)) _XMAL; -void *xrealloc(void *, size_t) attributeallocsize((2)) _XRET; +void *xrealloc(void *, size_t) + attributeallocsize((2)) nothrow nocallback nodiscard; void *xcalloc(size_t, size_t) attributeallocsize((1, 2)) _XMAL; void *xvalloc(size_t) attributeallocsize((1)) _XMALPG; void *xmemalign(size_t, size_t) attributeallocalign((1)) diff --git a/libc/x/xrealloc.c b/libc/x/xrealloc.c index 4318b43bc..f61cace06 100644 --- a/libc/x/xrealloc.c +++ b/libc/x/xrealloc.c @@ -21,13 +21,23 @@ #include "libc/x/x.h" /** - * Relocates, extends, and/or shrinks memory──or die. + * Allocates/expands/shrinks/frees memory, or die. * - * This API is fabulous since it categorically eliminates an extremely - * common type of memory bug, by simply redefining it as a crash. + * This API enables you to do the following: + * + * p = xrealloc(p, n) + * + * The standard behaviors for realloc() still apply: + * + * - `!p` means xmalloc (returns non-NULL) + * - `p && n` means resize (returns non-NULL) + * - `p && !n` means free (returns NULL) + * + * The complexity of resizing is guaranteed to be amortized. */ -void *xrealloc(void *p1, size_t newsize) { - void *p2 = realloc(p1, newsize); - if (!p2) xdie(); - return p2; +void *xrealloc(void *p, size_t n) { + void *q; + q = realloc(p, n); + if (!q && !(p && !n)) xdie(); + return q; } diff --git a/libc/zip.h b/libc/zip.h index 619dfcf3b..4c999ecb0 100644 --- a/libc/zip.h +++ b/libc/zip.h @@ -10,7 +10,7 @@ #define kZipAlign 2 -#define kZipCosmopolitanVersion 20 +#define kZipCosmopolitanVersion kZipEra2001 #define kZipOsDos 0 #define kZipOsAmiga 1 @@ -37,8 +37,8 @@ #define kZipEra1993 20 /* PKZIP 2.0: deflate/subdir/etc. support */ #define kZipEra2001 45 /* PKZIP 4.5: kZipExtraZip64 support */ -#define kZipIattrBinary 0 -#define kZipIattrAscii 1 +#define kZipIattrBinary 0 /* first bit not set */ +#define kZipIattrText 1 /* first bit set */ #define kZipCompressionNone 0 #define kZipCompressionDeflate 8 @@ -49,6 +49,9 @@ #define kZipCdirHdrLinkableSize \ ROUNDUP(kZipCfileHdrMinSize + PATH_MAX, kZipCdirAlign) +#define kZipCdir64HdrMagic 0x06064b50 /* PK♣♠ "PK\6\6" */ +#define kZipCdir64HdrMinSize 56 + #define kZipCfileHdrMagic 0x02014b50 /* PK☺☻ "PK\1\2" */ #define kZipCfileHdrMinSize 46 #define kZipCfileOffsetGeneralflag 8 @@ -73,10 +76,12 @@ #define kZipGflagUtf8 0x800 -#define kZipExtraHdrSize 4 -#define kZipExtraZip64 0x0001 -#define kZipExtraNtfs 0x000a -#define kZipExtraExtendedTimestamp 0x5455 +#define kZipExtraHdrSize 4 +#define kZipExtraZip64 0x0001 +#define kZipExtraNtfs 0x000a +#define kZipExtraUnix 0x000d +#define kZipExtraExtendedTimestamp 0x5455 +#define kZipExtraInfoZipNewUnixExtra 0x7875 #define kZipCfileMagic "PK\001\002" @@ -91,15 +96,30 @@ #define ZIP_CDIR_SIZE(P) READ32LE((P) + 12) #define ZIP_CDIR_OFFSET(P) READ32LE((P) + 16) #define ZIP_CDIR_COMMENTSIZE(P) READ16LE((P) + 20) -#define ZIP_CDIR_COMMENT(P) (&(P)[22]) +#define ZIP_CDIR_COMMENT(P) ((P) + 22) /* recommend stopping at nul */ #define ZIP_CDIR_HDRSIZE(P) (ZIP_CDIR_COMMENTSIZE(P) + kZipCdirHdrMinSize) +/* zip64 end of central directory record */ +#define ZIP_CDIR64_MAGIC(P) READ32LE(P) +#define ZIP_CDIR64_HDRSIZE(P) (READ64LE((P) + 4) + 12) +#define ZIP_CDIR64_VERSIONMADE(P) READ16LE((P) + 12) +#define ZIP_CDIR64_VERSIONNEED(P) READ16LE((P) + 14) +#define ZIP_CDIR64_DISK(P) READ32LE((P) + 16) +#define ZIP_CDIR64_STARTINGDISK(P) READ32LE((P) + 20) +#define ZIP_CDIR64_RECORDSONDISK(P) READ64LE((P) + 24) +#define ZIP_CDIR64_RECORDS(P) READ64LE((P) + 32) +#define ZIP_CDIR64_SIZE(P) READ64LE((P) + 40) +#define ZIP_CDIR64_OFFSET(P) READ64LE((P) + 48) +#define ZIP_CDIR64_COMMENTSIZE(P) \ + (ZIP_CDIR64_HDRSIZE(P) >= 56 ? ZIP_CDIR64_HDRSIZE(P) - 56 : 0) +#define ZIP_CDIR64_COMMENT(P) ((P) + 56) /* recommend stopping at nul */ + /* central directory file header */ #define ZIP_CFILE_MAGIC(P) READ32LE(P) -#define ZIP_CFILE_VERSIONMADE(P) ((P)[4]) -#define ZIP_CFILE_FILEATTRCOMPAT(P) ((P)[5]) -#define ZIP_CFILE_VERSIONNEED(P) ((P)[6]) -#define ZIP_CFILE_OSNEED(P) ((P)[7]) +#define ZIP_CFILE_VERSIONMADE(P) (255 & (P)[4]) +#define ZIP_CFILE_FILEATTRCOMPAT(P) (255 & (P)[5]) +#define ZIP_CFILE_VERSIONNEED(P) (255 & (P)[6]) +#define ZIP_CFILE_OSNEED(P) (255 & (P)[7]) #define ZIP_CFILE_GENERALFLAG(P) READ16LE((P) + kZipCfileOffsetGeneralflag) #define ZIP_CFILE_COMPRESSIONMETHOD(P) \ READ16LE((P) + kZipCfileOffsetCompressionmethod) @@ -119,18 +139,19 @@ #define ZIP_CFILE_EXTERNALATTRIBUTES(P) \ READ32LE((P) + kZipCfileOffsetExternalattributes) #define ZIP_CFILE_OFFSET(P) READ32LE((P) + kZipCfileOffsetOffset) -#define ZIP_CFILE_NAME(P) ((const char *)(&(P)[46])) /* not nul-terminated */ -#define ZIP_CFILE_EXTRA(P) (&(P)[46 + ZIP_CFILE_NAMESIZE(P)]) -#define ZIP_CFILE_COMMENT(P) \ - (&(P)[46 + ZIP_CFILE_NAMESIZE(P) + ZIP_CFILE_EXTRASIZE(P)]) +#define ZIP_CFILE_NAME(P) ((const char *)((P) + 46)) /* not nul-terminated */ +#define ZIP_CFILE_EXTRA(P) ((P) + 46 + ZIP_CFILE_NAMESIZE(P)) +#define ZIP_CFILE_COMMENT(P) \ + ((const char *)((P) + 46 + ZIP_CFILE_NAMESIZE(P) + \ + ZIP_CFILE_EXTRASIZE(P))) /* recommend stopping at nul */ #define ZIP_CFILE_HDRSIZE(P) \ (ZIP_CFILE_NAMESIZE(P) + ZIP_CFILE_EXTRASIZE(P) + ZIP_CFILE_COMMENTSIZE(P) + \ kZipCfileHdrMinSize) /* local file header */ #define ZIP_LFILE_MAGIC(P) READ32LE(P) -#define ZIP_LFILE_VERSIONNEED(P) ((P)[4]) -#define ZIP_LFILE_OSNEED(P) ((P)[5]) +#define ZIP_LFILE_VERSIONNEED(P) (255 & (P)[4]) +#define ZIP_LFILE_OSNEED(P) (255 & (P)[5]) #define ZIP_LFILE_GENERALFLAG(P) READ16LE((P) + kZipLfileOffsetGeneralflag) #define ZIP_LFILE_COMPRESSIONMETHOD(P) \ READ16LE((P) + kZipLfileOffsetCompressionmethod) @@ -145,8 +166,8 @@ READ32LE((P) + kZipLfileOffsetUncompressedsize) #define ZIP_LFILE_NAMESIZE(P) READ16LE((P) + 26) #define ZIP_LFILE_EXTRASIZE(P) READ16LE((P) + 28) -#define ZIP_LFILE_NAME(P) ((const char *)(&(P)[30])) -#define ZIP_LFILE_EXTRA(P) (&(P)[30 + ZIP_LFILE_NAMESIZE(P)]) +#define ZIP_LFILE_NAME(P) ((const char *)((P) + 30)) +#define ZIP_LFILE_EXTRA(P) ((P) + 30 + ZIP_LFILE_NAMESIZE(P)) #define ZIP_LFILE_HDRSIZE(P) \ (ZIP_LFILE_NAMESIZE(P) + ZIP_LFILE_EXTRASIZE(P) + kZipLfileHdrMinSize) #define ZIP_LFILE_CONTENT(P) ((P) + ZIP_LFILE_HDRSIZE(P)) @@ -154,9 +175,20 @@ #define ZIP_EXTRA_HEADERID(P) READ16LE(P) #define ZIP_EXTRA_CONTENTSIZE(P) READ16LE((P) + 2) -#define ZIP_EXTRA_CONTENT(P) (&(P)[4]) +#define ZIP_EXTRA_CONTENT(P) ((P) + 4) #define ZIP_EXTRA_SIZE(P) (ZIP_EXTRA_CONTENTSIZE(P) + kZipExtraHdrSize) +uint8_t *GetZipCdir(const uint8_t *, size_t); +bool IsZipCdir32(const uint8_t *, size_t, size_t); +bool IsZipCdir64(const uint8_t *, size_t, size_t); +int GetZipCfileMode(const uint8_t *); +uint64_t GetZipCdirOffset(const uint8_t *); +uint64_t GetZipCdirRecords(const uint8_t *); +uint64_t GetZipCfileUncompressedSize(const uint8_t *); +uint64_t GetZipCfileCompressedSize(const uint8_t *); +uint64_t GetZipCfileOffset(const uint8_t *); +uint64_t GetZipLfileUncompressedSize(const uint8_t *); +uint64_t GetZipLfileCompressedSize(const uint8_t *); uint8_t *zipfindcentraldir(const uint8_t *, size_t); #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/zipos/find.c b/libc/zipos/find.c index e38571305..9263bbd00 100644 --- a/libc/zipos/find.c +++ b/libc/zipos/find.c @@ -24,15 +24,14 @@ #include "libc/zipos/zipos.internal.h" ssize_t __zipos_find(struct Zipos *zipos, const struct ZiposUri *name) { - size_t i, cf; - assert(ZIP_CDIR_MAGIC(zipos->cdir) == kZipCdirHdrMagic); - for (i = 0, cf = ZIP_CDIR_OFFSET(zipos->cdir); - i < ZIP_CDIR_RECORDS(zipos->cdir); - ++i, cf += ZIP_CFILE_HDRSIZE(zipos->map + cf)) { - assert(ZIP_CFILE_MAGIC(zipos->map + cf) == kZipCfileHdrMagic); - if (name->len == ZIP_CFILE_NAMESIZE(zipos->map + cf) && - memcmp(name->path, ZIP_CFILE_NAME(zipos->map + cf), name->len) == 0) { - return cf; + size_t i, n, c; + c = GetZipCdirOffset(zipos->cdir); + n = GetZipCdirRecords(zipos->cdir); + for (i = 0; i < n; ++i, c += ZIP_CFILE_HDRSIZE(zipos->map + c)) { + assert(ZIP_CFILE_MAGIC(zipos->map + c) == kZipCfileHdrMagic); + if (name->len == ZIP_CFILE_NAMESIZE(zipos->map + c) && + memcmp(name->path, ZIP_CFILE_NAME(zipos->map + c), name->len) == 0) { + return c; } } return -1; diff --git a/libc/zipos/get.c b/libc/zipos/get.c index 985ef310b..af443f8ab 100644 --- a/libc/zipos/get.c +++ b/libc/zipos/get.c @@ -59,7 +59,7 @@ struct Zipos *__zipos_get(void) { } else { base = map; } - if ((cdir = zipfindcentraldir(base, size))) { + if ((cdir = GetZipCdir(base, size))) { zipos.map = base; zipos.cdir = cdir; } else { diff --git a/libc/zipos/open.c b/libc/zipos/open.c index 3847a5c9b..e4e4705b9 100644 --- a/libc/zipos/open.c +++ b/libc/zipos/open.c @@ -87,20 +87,20 @@ static int __zipos_load(struct Zipos *zipos, size_t cf, unsigned flags, int fd; size_t lf; struct ZiposHandle *h; - lf = ZIP_CFILE_OFFSET(zipos->map + cf); + lf = GetZipCfileOffset(zipos->map + cf); assert(ZIP_LFILE_MAGIC(zipos->map + lf) == kZipLfileHdrMagic); assert(ZIP_LFILE_COMPRESSIONMETHOD(zipos->map + lf) == kZipCompressionNone || ZIP_LFILE_COMPRESSIONMETHOD(zipos->map + lf) == kZipCompressionDeflate); if (!(h = calloc(1, sizeof(*h)))) return -1; h->cfile = cf; - if ((h->size = ZIP_LFILE_UNCOMPRESSEDSIZE(zipos->map + lf))) { + if ((h->size = GetZipLfileUncompressedSize(zipos->map + lf))) { if (ZIP_LFILE_COMPRESSIONMETHOD(zipos->map + lf)) { - assert(ZIP_LFILE_COMPRESSEDSIZE(zipos->map + lf)); + assert(GetZipLfileCompressedSize(zipos->map + lf)); if ((h->freeme = malloc(h->size)) && (IsTiny() ? __zipos_inflate_tiny : __zipos_inflate_fast)( h, ZIP_LFILE_CONTENT(zipos->map + lf), - ZIP_LFILE_COMPRESSEDSIZE(zipos->map + lf)) != -1) { + GetZipLfileCompressedSize(zipos->map + lf)) != -1) { h->mem = h->freeme; } } else { diff --git a/libc/zipos/stat-impl.c b/libc/zipos/stat-impl.c index 170eb1b52..8bb989b6d 100644 --- a/libc/zipos/stat-impl.c +++ b/libc/zipos/stat-impl.c @@ -25,6 +25,7 @@ #include "libc/zipos/zipos.internal.h" int __zipos_stat_impl(struct Zipos *zipos, size_t cf, struct stat *st) { + size_t lf; if (zipos && st) { memset(st, 0, sizeof(*st)); if (ZIP_CFILE_FILEATTRCOMPAT(zipos->map + cf) == kZipOsUnix) { @@ -32,9 +33,10 @@ int __zipos_stat_impl(struct Zipos *zipos, size_t cf, struct stat *st) { } else { st->st_mode = 0100644; } - st->st_size = ZIP_CFILE_UNCOMPRESSEDSIZE(zipos->map + cf); + lf = GetZipCfileOffset(zipos->map + cf); + st->st_size = GetZipLfileUncompressedSize(zipos->map + lf); st->st_blocks = - roundup(ZIP_CFILE_COMPRESSEDSIZE(zipos->map + cf), 512) / 512; + roundup(GetZipLfileCompressedSize(zipos->map + lf), 512) / 512; return 0; } else { return einval(); diff --git a/net/http/decodebase64.c b/net/http/decodebase64.c index 7a8a1a72d..5932e8e56 100644 --- a/net/http/decodebase64.c +++ b/net/http/decodebase64.c @@ -41,13 +41,18 @@ static const signed char kBase64[256] = { /** * Decodes base64 ascii representation to binary. + * + * @param data is input value + * @param size if -1 implies strlen + * @param out_size if non-NULL receives output length + * @return allocated NUL-terminated buffer, or NULL w/ errno */ void *DecodeBase64(const char *data, size_t size, size_t *out_size) { - unsigned w; + size_t n; char *r, *q; - int a, b, c, d; + int a, b, c, d, w; const char *p, *pe; - if (size == -1) size = strlen(data); + if (size == -1) size = data ? strlen(data) : 0; if ((r = malloc(size / 4 * 3 + 1))) { q = r; p = data; @@ -77,9 +82,14 @@ void *DecodeBase64(const char *data, size_t size, size_t *out_size) { if (d != -2) *q++ = (w & 0x0000FF) >> 000; } Done: - if (out_size) *out_size = q - r; + n = q - r; *q++ = '\0'; if ((q = realloc(r, q - r))) r = q; + } else { + n = 0; + } + if (out_size) { + *out_size = n; } return r; } diff --git a/net/http/decodelatin1.c b/net/http/decodelatin1.c index aef372ccd..d3d86ef72 100644 --- a/net/http/decodelatin1.c +++ b/net/http/decodelatin1.c @@ -16,6 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/intrin/pcmpgtb.h" +#include "libc/intrin/pmovmskb.h" #include "libc/mem/mem.h" #include "libc/str/str.h" #include "net/http/http.h" @@ -25,14 +27,15 @@ * * @param data is input value * @param size if -1 implies strlen - * @param out_size if non-NULL receives output length on success + * @param out_size if non-NULL receives output length * @return allocated NUL-terminated buffer, or NULL w/ errno */ char *DecodeLatin1(const char *data, size_t size, size_t *out_size) { int c; + size_t n; char *r, *q; const char *p, *e; - if (size == -1) size = strlen(data); + if (size == -1) size = data ? strlen(data) : 0; if ((r = malloc(size * 2 + 1))) { q = r; p = data; @@ -46,9 +49,14 @@ char *DecodeLatin1(const char *data, size_t size, size_t *out_size) { *q++ = 0200 | c & 077; } } - if (out_size) *out_size = q - r; + n = q - r; *q++ = '\0'; - if ((q = realloc(r, q - r))) r = q; + if ((q = realloc(r, n + 1))) r = q; + } else { + n = 0; + } + if (out_size) { + *out_size = n; } return r; } diff --git a/net/http/encodebase64.c b/net/http/encodebase64.c index 1515bdfd0..f7543a9cb 100644 --- a/net/http/encodebase64.c +++ b/net/http/encodebase64.c @@ -17,22 +17,28 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/mem/mem.h" +#include "libc/str/str.h" #include "net/http/base64.h" #define CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" /** * Encodes binary to base64 ascii representation. + * + * @param data is input value + * @param size if -1 implies strlen + * @param out_size if non-NULL receives output length + * @return allocated NUL-terminated buffer, or NULL w/ errno */ char *EncodeBase64(const void *data, size_t size, size_t *out_size) { size_t n; unsigned w; char *r, *q; const unsigned char *p, *pe; + if (size == -1) size = data ? strlen(data) : 0; if ((n = size) % 3) n += 3 - size % 3; n /= 3, n *= 4; if ((r = malloc(n + 1))) { - if (out_size) *out_size = n; for (q = r, p = data, pe = p + size; p < pe; p += 3) { w = p[0] << 020; if (p + 1 < pe) w |= p[1] << 010; @@ -43,6 +49,11 @@ char *EncodeBase64(const void *data, size_t size, size_t *out_size) { *q++ = p + 2 < pe ? CHARS[w & 077] : '='; } *q++ = '\0'; + } else { + n = 0; + } + if (out_size) { + *out_size = n; } return r; } diff --git a/net/http/encodehttpheadervalue.c b/net/http/encodehttpheadervalue.c index ee5829e10..03b8b91ec 100644 --- a/net/http/encodehttpheadervalue.c +++ b/net/http/encodehttpheadervalue.c @@ -42,9 +42,10 @@ char *EncodeHttpHeaderValue(const char *data, size_t size, size_t *out_size) { bool t; wint_t x; + size_t n; char *r, *q; const char *p, *e; - if (size == -1) size = strlen(data); + if (size == -1) size = data ? strlen(data) : 0; if ((r = malloc(size + 1))) { t = 0; q = r; @@ -77,9 +78,14 @@ char *EncodeHttpHeaderValue(const char *data, size_t size, size_t *out_size) { } } while (q > r && (q[-1] == ' ' || q[-1] == '\t')) --q; - if (out_size) *out_size = q - r; + n = q - r; *q++ = '\0'; if ((q = realloc(r, q - r))) r = q; + } else { + n = 0; + } + if (out_size) { + *out_size = n; } return r; } diff --git a/net/http/escapeurl.c b/net/http/escapeurl.c index 09dfddb1e..0b7615cce 100644 --- a/net/http/escapeurl.c +++ b/net/http/escapeurl.c @@ -25,6 +25,7 @@ * This function is agnostic to the underlying charset. * Always using UTF-8 is a good idea. * + * @param size if -1 implies strlen * @see EscapeUrlParam * @see EscapeUrlFragment * @see EscapeUrlPathSegment @@ -35,6 +36,7 @@ struct EscapeResult EscapeUrl(const char *data, size_t size, char *p; size_t i; struct EscapeResult r; + if (size == -1) size = data ? strlen(data) : 0; p = r.data = xmalloc(size * 6 + 1); for (i = 0; i < size; ++i) { if (!xlat[(c = data[i] & 0xff)]) { diff --git a/net/http/escapeurlfragment.c b/net/http/escapeurlfragment.c index a03406b82..ef5b1e204 100644 --- a/net/http/escapeurlfragment.c +++ b/net/http/escapeurlfragment.c @@ -46,6 +46,8 @@ static const char kEscapeUrlFragment[256] = { /** * Escapes URL fragment. + * + * @param size if -1 implies strlen */ struct EscapeResult EscapeUrlFragment(const char *data, size_t size) { return EscapeUrl(data, size, kEscapeUrlFragment); diff --git a/net/http/escapeurlparam.c b/net/http/escapeurlparam.c index 88b2ab672..cc20b06c2 100644 --- a/net/http/escapeurlparam.c +++ b/net/http/escapeurlparam.c @@ -44,6 +44,8 @@ static const char kEscapeUrlParam[256] = { /** * Escapes query/form name/parameter. + * + * @param size if -1 implies strlen */ struct EscapeResult EscapeUrlParam(const char *data, size_t size) { return EscapeUrl(data, size, kEscapeUrlParam); diff --git a/net/http/escapeurlpath.c b/net/http/escapeurlpath.c index 55789eb47..9a3afda23 100644 --- a/net/http/escapeurlpath.c +++ b/net/http/escapeurlpath.c @@ -48,6 +48,8 @@ static const char kEscapeUrlPath[256] = { * Escapes URL path. * * This is the same as EscapeUrlPathSegment() except slash is allowed. + * + * @param size if -1 implies strlen */ struct EscapeResult EscapeUrlPath(const char *data, size_t size) { return EscapeUrl(data, size, kEscapeUrlPath); diff --git a/net/http/escapeurlpathsegment.c b/net/http/escapeurlpathsegment.c index 47667ec0a..c878f1f58 100644 --- a/net/http/escapeurlpathsegment.c +++ b/net/http/escapeurlpathsegment.c @@ -49,6 +49,8 @@ static const char kEscapeUrlPathSegment[256] = { * * Please note this will URI encode the slash character. That's because * segments are the labels between the slashes in a path. + * + * @param size if -1 implies strlen */ struct EscapeResult EscapeUrlPathSegment(const char *data, size_t size) { return EscapeUrl(data, size, kEscapeUrlPathSegment); diff --git a/net/http/http.h b/net/http/http.h index 79766d17a..12464ab24 100644 --- a/net/http/http.h +++ b/net/http/http.h @@ -125,7 +125,8 @@ bool IsValidHttpToken(const char *, size_t); char *EncodeHttpHeaderValue(const char *, size_t, size_t *); char *VisualizeControlCodes(const char *, size_t, size_t *); char *IndentLines(const char *, size_t, size_t *, size_t); -bool IsAcceptableHttpRequestPath(const char *, size_t); +bool IsAcceptablePath(const char *, size_t); +bool IsAcceptableHostPort(const char *, size_t); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/net/http/indentlines.c b/net/http/indentlines.c index 2bd9aa1fa..580074153 100644 --- a/net/http/indentlines.c +++ b/net/http/indentlines.c @@ -25,7 +25,7 @@ * * @param data is input value * @param size if -1 implies strlen - * @param out_size if non-NULL receives output length on success + * @param out_size if non-NULL receives output length * @param amt is number of spaces to use * @return allocated NUL-terminated buffer, or NULL w/ errno */ @@ -33,7 +33,7 @@ char *IndentLines(const char *data, size_t size, size_t *out_size, size_t amt) { char *r; const char *p; size_t i, n, m, a; - if (size == -1) size = strlen(data); + if (size == -1) size = data ? strlen(data) : 0; r = 0; n = 0; do { @@ -51,7 +51,9 @@ char *IndentLines(const char *data, size_t size, size_t *out_size, size_t amt) { data += m; size -= m; } while (p); - if (out_size) *out_size = n; + if (out_size) { + *out_size = n; + } r[n] = '\0'; return r; } diff --git a/net/http/isacceptablehostport.c b/net/http/isacceptablehostport.c new file mode 100644 index 000000000..3313c688c --- /dev/null +++ b/net/http/isacceptablehostport.c @@ -0,0 +1,106 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/str/str.h" +#include "net/http/http.h" + +/** + * Returns true if HOST[:PORT] seems legit. + * + * This parser is permissive and imposes the subset of restrictions + * that'll make things easier for the caller. For example, only one + * colon is allowed to appear, which makes memchr() so much easier. + * + * Here's examples of permitted inputs: + * + * - 1.2.3.4 + * - 1.2.3.4.arpa + * - 1.2.3.4:8080 + * - localservice + * - hello.example + * - _hello.example + * - -hello.example + * - hi-there.example + * - hello.example:443 + * + * Here's some examples of forbidden inputs: + * + * - :443 + * - 1.2.3 + * - 1.2.3.4.5 + * - [::1]:8080 + * - .hi.example + * - hi..example + * - hi.example::80 + * - hi.example:-80 + * - hi.example:65536 + * + * @param n if -1 implies strlen + */ +bool IsAcceptableHostPort(const char *s, size_t n) { + size_t i; + bool isip; + int c, t, p, b, j; + if (n == -1) n = s ? strlen(s) : 0; + if (!n) return false; + for (isip = true, b = j = p = t = i = 0; i < n; ++i) { + c = s[i] & 255; + if (!t) { + if (c == ':') { + if (!i || s[i - 1] == '.') { + return false; + } else { + t = 1; + } + } else if (c == '.' && (!i || s[i - 1] == '.')) { + return false; + } else if (!(isalnum(c) || c == '-' || c == '_' || c == '.')) { + return false; + } + if (isip) { + if (isdigit(c)) { + b *= 10; + b += c - '0'; + if (b > 255) { + return false; + } + } else if (c == '.') { + b = 0; + ++j; + } else { + isip = false; + } + } + } else { + if (c == ':') { + return false; + } else if ('0' <= c && c <= '9') { + p *= 10; + p += c - '0'; + if (p > 65535) { + return false; + } + } else { + return false; + } + } + } + if (isip && j != 3) return false; + if (!t && s[i - 1] == '.') return false; + return true; +} diff --git a/net/http/isacceptablehttprequestpath.c b/net/http/isacceptablepath.c similarity index 84% rename from net/http/isacceptablehttprequestpath.c rename to net/http/isacceptablepath.c index c093a7b89..8ff2b7903 100644 --- a/net/http/isacceptablehttprequestpath.c +++ b/net/http/isacceptablepath.c @@ -16,29 +16,29 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/str/str.h" #include "libc/str/thompike.h" #include "net/http/http.h" /** * Returns true if request path seems legit. * - * 1. Request path must start with '/'. - * 2. The substring "//" is disallowed. - * 3. We won't serve hidden files (segment starts with '.'). - * 4. We won't serve paths with segments equal to "." or "..". + * 1. The substring "//" is disallowed. + * 2. We won't serve hidden files (segment starts with '.'). + * 3. We won't serve paths with segments equal to "." or "..". * * It is assumed that the URI parser already took care of percent * escape decoding as well as ISO-8859-1 decoding. The input needs * to be a UTF-8 string. + * + * @param size if -1 implies strlen */ -bool IsAcceptableHttpRequestPath(const char *data, size_t size) { - bool t; - size_t i; - unsigned n; - wint_t x, y, a, b; +bool IsAcceptablePath(const char *data, size_t size) { const char *p, *e; - if (!size || *data != '/') return false; + int x, y, a, b, t, i, n; + if (size == -1) size = data ? strlen(data) : 0; t = 0; + y = '/'; p = data; e = p + size; while (p < e) { @@ -62,14 +62,12 @@ bool IsAcceptableHttpRequestPath(const char *data, size_t size) { if (x == '\\') { x = '/'; } - if (!t) { - t = true; - } else { - if ((x == '/' || x == '.') && y == '/') { - return false; - } + if (y == '/') { + if (x == '.') return false; + if (x == '/' && t) return false; } y = x; + t = 1; } return true; } diff --git a/net/http/isvalidhttptoken.c b/net/http/isvalidhttptoken.c index b3e61791b..e82994ffa 100644 --- a/net/http/isvalidhttptoken.c +++ b/net/http/isvalidhttptoken.c @@ -21,7 +21,7 @@ // http/1.1 token dispatch // 0 is CTLs, SP, ()<>@,;:\"/[]?={} -// 1 is legal ascii +// 1 is what remains of ascii static const char kHttpToken[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x00 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x10 @@ -41,10 +41,15 @@ static const char kHttpToken[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xf0 }; +/** + * Returns true if string is ASCII without delimiters. + * + * @param n if -1 implies strlen + */ bool IsValidHttpToken(const char *s, size_t n) { size_t i; if (!n) return false; - if (n == -1) n = strlen(s); + if (n == -1) n = s ? strlen(s) : 0; for (i = 0; i < n; ++i) { if (!kHttpToken[s[i] & 0xff]) { return false; diff --git a/net/http/parseurl.c b/net/http/parseurl.c new file mode 100644 index 000000000..786ed90e9 --- /dev/null +++ b/net/http/parseurl.c @@ -0,0 +1,346 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/likely.h" +#include "libc/limits.h" +#include "libc/str/str.h" +#include "libc/x/x.h" +#include "net/http/url.h" + +struct UrlParser { + int i; + int c; + const char *data; + int size; + bool isform; + bool islatin1; + char *p; + char *q; +}; + +static const signed char kHexToInt[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x00 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x10 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x20 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, // 0x30 + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x40 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x50 + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x60 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x70 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x80 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x90 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0xa0 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0xb0 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0xc0 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0xd0 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0xe0 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0xf0 +}; + +static void EmitLatin1(struct UrlParser *u, int c) { + u->p[0] = 0300 | c >> 6; + u->p[1] = 0200 | c & 077; + u->p += 2; +} + +static void EmitKey(struct UrlParser *u, struct UrlParams *h) { + h->p = xrealloc(h->p, ++h->n * sizeof(*h->p)); + h->p[h->n - 1].key.p = u->q; + h->p[h->n - 1].key.n = u->p - u->q; + u->q = u->p; +} + +static void EmitVal(struct UrlParser *u, struct UrlParams *h, bool t) { + if (!t) { + if (u->p > u->q) { + EmitKey(u, h); + h->p[h->n - 1].val.p = NULL; + h->p[h->n - 1].val.n = SIZE_MAX; + } + } else { + h->p[h->n - 1].val.p = u->q; + h->p[h->n - 1].val.n = u->p - u->q; + u->q = u->p; + } +} + +static void ParseEscape(struct UrlParser *u) { + int a, b; + if (u->i + 2 <= u->size && + ((a = kHexToInt[u->data[u->i + 0] & 0xff]) != -1 && + (b = kHexToInt[u->data[u->i + 1] & 0xff]) != -1)) { + u->c = a << 4 | b; + u->i += 2; + } + *u->p++ = u->c; +} + +static bool ParseScheme(struct UrlParser *u, struct Url *h) { + while (u->i < u->size) { + u->c = u->data[u->i++] & 0xff; + if (u->c == '/') { + if (u->i == 1 && u->i < u->size && u->data[u->i] == '/') { + ++u->i; + return true; + } else { + *u->p++ = u->c; + return false; + } + } else if (u->c == ':') { + h->scheme.p = u->q; + h->scheme.n = u->p - u->q; + u->q = u->p; + if (u->i + 2 <= u->size && + (u->data[u->i + 1] == '/' && u->data[u->i + 1] == '/')) { + u->i += 2; + return true; + } else { + return false; + } + } else if (u->c == '#' || u->c == '?') { + h->path.p = u->q; + h->path.n = u->p - u->q; + u->q = u->p; + return false; + } else if (u->c == '%') { + ParseEscape(u); + } else if (u->c >= 0200 && u->islatin1) { + EmitLatin1(u, u->c); + } else { + *u->p++ = u->c; + } + } + return false; +} + +static void ParseAuthority(struct UrlParser *u, struct Url *h) { + bool b = false; + const char *c = NULL; + while (u->i < u->size) { + u->c = u->data[u->i++] & 0xff; + if (u->c == '/' || u->c == '#' || u->c == '?') { + break; + } else if (u->c == '[') { + b = true; + } else if (u->c == ']') { + b = false; + } else if (u->c == ':' && !b) { + c = u->p; + } else if (u->c == '@') { + if (c) { + h->user.p = u->q; + h->user.n = c - u->q; + h->pass.p = c; + h->pass.n = u->p - c; + c = NULL; + } else { + h->user.p = u->q; + h->user.n = u->p - u->q; + } + u->q = u->p; + } else if (u->c == '%') { + ParseEscape(u); + } else if (u->c >= 0200 && u->islatin1) { + EmitLatin1(u, u->c); + } else { + *u->p++ = u->c; + } + } + if (c) { + h->host.p = u->q; + h->host.n = c - u->q; + h->port.p = c; + h->port.n = u->p - c; + c = NULL; + } else { + h->host.p = u->q; + h->host.n = u->p - u->q; + } + u->q = u->p; + if (u->c == '/') { + *u->p++ = u->c; + } +} + +static void ParsePath(struct UrlParser *u, struct UrlView *h) { + while (u->i < u->size) { + u->c = u->data[u->i++] & 0xff; + if (u->c == '#' || u->c == '?') { + break; + } else if (u->c == '%') { + ParseEscape(u); + } else if (u->c >= 0200 && u->islatin1) { + EmitLatin1(u, u->c); + } else { + *u->p++ = u->c; + } + } + h->p = u->q; + h->n = u->p - u->q; + u->q = u->p; +} + +static void ParseKeyValues(struct UrlParser *u, struct UrlParams *h) { + bool t = false; + while (u->i < u->size) { + u->c = u->data[u->i++] & 0xff; + if (u->c == '#') { + break; + } else if (u->c == '%') { + ParseEscape(u); + } else if (u->c == '+') { + *u->p++ = u->isform ? ' ' : '+'; + } else if (u->c == '&') { + EmitVal(u, h, t); + t = false; + } else if (u->c == '=') { + if (!t) { + if (u->p > u->q) { + EmitKey(u, h); + t = true; + } + } else { + *u->p++ = '='; + } + } else if (u->c >= 0200 && u->islatin1) { + EmitLatin1(u, u->c); + } else { + *u->p++ = u->c; + } + } + EmitVal(u, h, t); +} + +static void ParseFragment(struct UrlParser *u, struct UrlView *h) { + while (u->i < u->size) { + u->c = u->data[u->i++] & 0xff; + if (u->c == '%') { + ParseEscape(u); + } else if (u->c >= 0200 && u->islatin1) { + EmitLatin1(u, u->c); + } else { + *u->p++ = u->c; + } + } + h->p = u->q; + h->n = u->p - u->q; + u->q = u->p; +} + +static char *ParseUrlImpl(const char *data, size_t size, struct Url *h, + bool latin1) { + char *m; + struct UrlParser u; + if (size == -1) size = data ? strlen(data) : 0; + u.i = 0; + u.c = 0; + u.isform = false; + u.islatin1 = latin1; + u.data = data; + u.size = size; + memset(h, 0, sizeof(*h)); + u.q = u.p = m = xmalloc(u.size * 2); + if (ParseScheme(&u, h)) ParseAuthority(&u, h); + if (u.c != '#' && u.c != '?') ParsePath(&u, &h->path); + if (u.c == '?') ParseKeyValues(&u, &h->params); + if (u.c == '#') ParseFragment(&u, &h->fragment); + return xrealloc(m, u.p - m); +} + +/** + * Parses URL. + * + * There's no failure condition for this routine. This is a permissive + * parser that doesn't impose character restrictions beyond what is + * necessary for parsing. This doesn't normalize path segments like `.` + * or `..`. Use IsAcceptablePath() to check for those. + * + * This parser is charset agnostic. Returned values might contain things + * like NUL characters, control codes, and non-canonical encodings. + * + * This parser doesn't support the ability to accurately parse path + * segments which contain percent-encoded slash. There's also no support + * for semicolon parameters at the moment. + * + * @param data is value like `/hi?x=y&z` or `http://a.example/hi#x` + * @param size is byte length and -1 implies strlen + * @param h is assumed to be uninitialized + * @return memory backing UrlView needing free (and h.params.p too) + */ +char *ParseUrl(const char *data, size_t size, struct Url *h) { + return ParseUrlImpl(data, size, h, false); +} + +/** + * Parses HTTP Request-URI. + * + * The input is ISO-8859-1 which is transcoded to UTF-8. Therefore we + * assume percent-encoded bytes are expressed as UTF-8. Returned values + * might contain things like NUL characters, C0, and C1 control codes. + * UTF-8 isn't checked for validity and may contain overlong values. + * + * There's no failure condition for this routine. This is a permissive + * parser that doesn't impose character restrictions beyond what is + * necessary for parsing. This doesn't normalize path segments like `.` + * or `..`. Use IsAcceptablePath() to check for those. + * + * This parser doesn't support the ability to accurately parse path + * segments which contain percent-encoded slash. + * + * @param data is value like `/hi?x=y&z` or `http://a.example/hi#x` + * @param size is byte length and -1 implies strlen + * @param h is assumed to be uninitialized + * @return memory backing UrlView needing free (and h.params.p too) + */ +char *ParseRequestUri(const char *data, size_t size, struct Url *h) { + return ParseUrlImpl(data, size, h, true); +} + +/** + * Parses HTTP POST key-value params. + * + * These are similar to the parameters found in a Request-URI. The main + * difference is that `+` is translated into space here. The mime type + * for this is application/x-www-form-urlencoded. + * + * This parser is charset agnostic. Returned values might contain things + * like NUL characters, control codes, and non-canonical encodings. + * + * There's no failure condition for this routine. This is a permissive + * parser that doesn't impose character restrictions beyond what is + * necessary for parsing. + * + * @param data is value like `foo=bar&x=y&z` + * @param size is byte length and -1 implies strlen + * @param h must be zeroed by caller and this appends if reused + * @return UrlView memory with same size needing free (h.p needs free too) + */ +char *ParseParams(const char *data, size_t size, struct UrlParams *h) { + char *m; + struct UrlParser u; + if (size == -1) size = data ? strlen(data) : 0; + u.i = 0; + u.c = 0; + u.isform = true; + u.islatin1 = false; + u.data = data; + u.size = size; + u.q = u.p = m = xmalloc(u.size); + ParseKeyValues(&u, h); + return m; +} diff --git a/net/http/url.h b/net/http/url.h new file mode 100644 index 000000000..c0fdda679 --- /dev/null +++ b/net/http/url.h @@ -0,0 +1,36 @@ +#ifndef COSMOPOLITAN_NET_HTTP_URL_H_ +#define COSMOPOLITAN_NET_HTTP_URL_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +struct UrlView { + size_t n; + char *p; /* not allocated; not nul terminated */ +}; + +struct UrlParams { + size_t n; + struct Param { + struct UrlView key; + struct UrlView val; /* val.n may be SIZE_MAX */ + } * p; +}; + +struct Url { + struct UrlView scheme; + struct UrlView user; + struct UrlView pass; + struct UrlView host; + struct UrlView port; + struct UrlView path; + struct UrlParams params; + struct UrlView fragment; +}; + +char *ParseUrl(const char *, size_t, struct Url *); +char *ParseParams(const char *, size_t, struct UrlParams *); +char *ParseRequestUri(const char *, size_t, struct Url *); + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_NET_HTTP_URL_H_ */ diff --git a/net/http/visualizecontrolcodes.c b/net/http/visualizecontrolcodes.c index d1049731d..42efb54d7 100644 --- a/net/http/visualizecontrolcodes.c +++ b/net/http/visualizecontrolcodes.c @@ -31,7 +31,7 @@ * * @param data is input value * @param size if -1 implies strlen - * @param out_size if non-NULL receives output length on success + * @param out_size if non-NULL receives output length * @return allocated NUL-terminated buffer, or NULL w/ errno */ char *VisualizeControlCodes(const char *data, size_t size, size_t *out_size) { @@ -40,7 +40,7 @@ char *VisualizeControlCodes(const char *data, size_t size, size_t *out_size) { unsigned i, n; wint_t x, a, b; const char *p, *e; - if (size == -1) size = strlen(data); + if (size == -1) size = data ? strlen(data) : 0; if ((r = malloc(size * 6 + 1))) { q = r; p = data; @@ -85,9 +85,14 @@ char *VisualizeControlCodes(const char *data, size_t size, size_t *out_size) { } while ((w >>= 8)); } } - if (out_size) *out_size = q - r; + n = q - r; *q++ = '\0'; if ((q = realloc(r, q - r))) r = q; + } else { + n = 0; + } + if (out_size) { + *out_size = n; } return r; } diff --git a/test/libc/bits/bitreverse_test.c b/test/libc/bits/bitreverse_test.c index ae2a8014a..acd47ae28 100644 --- a/test/libc/bits/bitreverse_test.c +++ b/test/libc/bits/bitreverse_test.c @@ -21,29 +21,24 @@ #include "libc/testlib/testlib.h" TEST(bitreverse, test) { + EXPECT_EQ(0xde, BITREVERSE8(123)); EXPECT_EQ(0xde, bitreverse8(123)); - EXPECT_EQ(0xde, (bitreverse8)(123)); + EXPECT_EQ(0xde00, BITREVERSE16(123)); EXPECT_EQ(0xde00, bitreverse16(123)); - EXPECT_EQ(0xde00, (bitreverse16)(123)); EXPECT_EQ(0xde000000u, bitreverse32(123)); - EXPECT_EQ(0xde000000u, (bitreverse32)(123)); EXPECT_EQ(0xde00000000000000ul, bitreverse64(123)); - EXPECT_EQ(0xde00000000000000ul, (bitreverse64)(123)); EXPECT_EQ(0x482d96c305f7c697ul, bitreverse64(0xe963efa0c369b412)); - EXPECT_EQ(0x482d96c305f7c697ul, (bitreverse64)(0xe963efa0c369b412)); } BENCH(bitreverse, bench) { - EZBENCH2("bitreverse8 mac", donothing, + EZBENCH2("BITREVERSE8", donothing, + EXPROPRIATE(BITREVERSE8(CONCEAL("r", 123)))); + EZBENCH2("bitreverse8", donothing, EXPROPRIATE(bitreverse8(CONCEAL("r", 123)))); - EZBENCH2("bitreverse8 fun", donothing, - EXPROPRIATE((bitreverse8)(CONCEAL("r", 123)))); - EZBENCH2("bitreverse16 mac", donothing, - EXPROPRIATE(bitreverse16(CONCEAL("r", 123)))); - EZBENCH2("bitreverse16 fun", donothing, - EXPROPRIATE((bitreverse16)(CONCEAL("r", 123)))); - EZBENCH2("bitreverse32 mac", donothing, + EZBENCH2("BITREVERSE16", donothing, + EXPROPRIATE(BITREVERSE16(CONCEAL("r", 123)))); + EZBENCH2("bitreverse32", donothing, EXPROPRIATE(bitreverse32(CONCEAL("r", 123)))); - EZBENCH2("bitreverse32 fun", donothing, - EXPROPRIATE((bitreverse32)(CONCEAL("r", (123))))); + EZBENCH2("bitreverse64", donothing, + EXPROPRIATE(bitreverse64(CONCEAL("r", 123)))); } diff --git a/test/net/http/isacceptablehttprequestpath_test.c b/test/libc/calls/mprotect_test.c similarity index 54% rename from test/net/http/isacceptablehttprequestpath_test.c rename to test/libc/calls/mprotect_test.c index a256bdf55..7857f1066 100644 --- a/test/net/http/isacceptablehttprequestpath_test.c +++ b/test/libc/calls/mprotect_test.c @@ -16,46 +16,51 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/runtime/gc.internal.h" -#include "libc/testlib/ezbench.h" +#include "libc/calls/calls.h" +#include "libc/runtime/runtime.h" +#include "libc/sysv/consts/prot.h" +#include "libc/sysv/consts/sa.h" #include "libc/testlib/testlib.h" -#include "net/http/escape.h" -#include "net/http/http.h" -TEST(IsAcceptableHttpRequestPath, test) { - EXPECT_TRUE(IsAcceptableHttpRequestPath("/", 1)); - EXPECT_TRUE(IsAcceptableHttpRequestPath("/index.html", 11)); +jmp_buf jb; +bool gotsegv; +struct sigaction old[2]; + +void OnSigSegv(int sig) { + gotsegv = true; + longjmp(jb, 1); } -TEST(IsAcceptableHttpRequestPath, testDoubleSlash_notAllowed) { - EXPECT_FALSE(IsAcceptableHttpRequestPath("//", 2)); - EXPECT_FALSE(IsAcceptableHttpRequestPath("/foo//bar", 9)); +void SetUp(void) { + sigaction(SIGBUS, NULL, &old[0]); + sigaction(SIGSEGV, NULL, &old[1]); } -TEST(IsAcceptableHttpRequestPath, testDoesntStartWithSlash_notAllowed) { - EXPECT_FALSE(IsAcceptableHttpRequestPath(NULL, 0)); - EXPECT_FALSE(IsAcceptableHttpRequestPath("*", 1)); +void TearDown(void) { + sigaction(SIGBUS, &old[0], NULL); + sigaction(SIGSEGV, &old[1], NULL); } -TEST(IsAcceptableHttpRequestPath, testNoncanonicalDirectories_areForbidden) { - EXPECT_FALSE(IsAcceptableHttpRequestPath("/.", 2)); - EXPECT_FALSE(IsAcceptableHttpRequestPath("/./", 3)); - EXPECT_FALSE(IsAcceptableHttpRequestPath("/../", 4)); +TEST(mprotect, test) { + char *p = gc(memalign(PAGESIZE, PAGESIZE)); + p[0] = 0; + ASSERT_NE(-1, mprotect(p, PAGESIZE, PROT_READ | PROT_WRITE)); + p[0] = 1; + EXPECT_EQ(1, p[0]); } -TEST(IsAcceptableHttpRequestPath, testNoncanonicalWindowsDirs_areForbidden) { - EXPECT_FALSE(IsAcceptableHttpRequestPath("\\.", 2)); - EXPECT_FALSE(IsAcceptableHttpRequestPath("\\.\\", 3)); - EXPECT_FALSE(IsAcceptableHttpRequestPath("\\..\\", 4)); -} - -TEST(IsAcceptableHttpRequestPath, testOverlongSlashDot_isDetected) { - EXPECT_FALSE(IsAcceptableHttpRequestPath("/\300\256", 3)); - EXPECT_FALSE(IsAcceptableHttpRequestPath("/\300\257", 3)); - EXPECT_FALSE(IsAcceptableHttpRequestPath("\300\256\300\256", 4)); -} - -BENCH(IsAcceptableHttpRequestPath, bench) { - EZBENCH2("IsAcceptableHttpRequestPath", donothing, - IsAcceptableHttpRequestPath("/index.html", 11)); +TEST(mprotect, testSegfault) { + char *p; + struct sigaction ss = {.sa_handler = OnSigSegv, .sa_flags = SA_NODEFER}; + if (IsWindows()) return; /* TODO */ + p = gc(memalign(PAGESIZE, PAGESIZE)); + EXPECT_NE(-1, sigaction(SIGBUS, &ss, NULL)); + EXPECT_NE(-1, sigaction(SIGSEGV, &ss, NULL)); + if (!setjmp(jb)) p[0] = 1; + EXPECT_FALSE(gotsegv); + EXPECT_NE(-1, mprotect(p, sizeof(p), PROT_READ)); + if (!setjmp(jb)) p[0] = 2; + EXPECT_TRUE(gotsegv); + EXPECT_EQ(1, p[0]); + EXPECT_NE(-1, mprotect(p, sizeof(p), PROT_READ | PROT_WRITE)); } diff --git a/test/libc/fmt/strerror_test.c b/test/libc/fmt/strerror_test.c index b6b607136..331f49008 100644 --- a/test/libc/fmt/strerror_test.c +++ b/test/libc/fmt/strerror_test.c @@ -45,8 +45,8 @@ TEST(strerror, einval) { } TEST(strerror, symbolizingTheseNumbersAsErrorsIsHeresyInUnixStyle) { - EXPECT_STARTSWITH("E?", strerror(0)); - EXPECT_STARTSWITH("E?", strerror(-1)); + EXPECT_STARTSWITH("EUNKNOWN", strerror(0)); + EXPECT_STARTSWITH("EUNKNOWN", strerror(-1)); } TEST(strerror, enotconn_orLinkerIsntUsingLocaleC_orCodeIsOutOfSync) { @@ -55,9 +55,9 @@ TEST(strerror, enotconn_orLinkerIsntUsingLocaleC_orCodeIsOutOfSync) { } TEST(strerror, exfull_orLinkerIsntUsingLocaleC_orCodeIsOutOfSync) { - if (IsLinux() && !IsTiny()) { - EXPECT_STARTSWITH("EXFULL", strerror(EXFULL)); + if (!IsTiny()) { + EXPECT_STARTSWITH("ETXTBSY", strerror(ETXTBSY)); } else { - EXPECT_STARTSWITH("E?", strerror(EXFULL)); + EXPECT_STARTSWITH("EUNKNOWN", strerror(ETXTBSY)); } } diff --git a/test/libc/release/test.mk b/test/libc/release/test.mk index 01aac0224..872f9395d 100644 --- a/test/libc/release/test.mk +++ b/test/libc/release/test.mk @@ -8,7 +8,7 @@ o/$(MODE)/test/libc/release/cosmopolitan.zip: \ o/$(MODE)/ape/ape.o \ o/$(MODE)/ape/ape-no-modify-self.o \ o/$(MODE)/cosmopolitan.a - @$(COMPILE) -AZIP -T$@ zip -j $@ $^ + @$(COMPILE) -AZIP -T$@ zip -qj $@ $^ o/$(MODE)/test/libc/release/smoke.com: \ o/$(MODE)/test/libc/release/smoke.com.dbg diff --git a/test/net/http/decodelatin1_test.c b/test/net/http/decodelatin1_test.c index ccb507181..f1a86e0cf 100644 --- a/test/net/http/decodelatin1_test.c +++ b/test/net/http/decodelatin1_test.c @@ -16,6 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/testlib/ezbench.h" +#include "libc/testlib/hyperion.h" #include "libc/testlib/testlib.h" #include "net/http/http.h" @@ -26,3 +28,14 @@ TEST(DecodeLatin1, test) { EXPECT_STREQ("¥atta", DecodeLatin1("\245atta", -1, &n)); EXPECT_EQ(6, n); } + +TEST(DecodeLatin1, testOom_returnsNullAndSetsSizeToZero) { + n = 31337; + EXPECT_EQ(NULL, DecodeLatin1("hello", 0x1000000000000, &n)); + EXPECT_EQ(0, n); +} + +BENCH(DecodeLatin1, bench) { + EZBENCH2("DecodeLatin1", donothing, + DecodeLatin1(kHyperion, kHyperionSize, 0)); +} diff --git a/test/net/http/encodebase64_test.c b/test/net/http/encodebase64_test.c index 4e4f23a30..3af1b5091 100644 --- a/test/net/http/encodebase64_test.c +++ b/test/net/http/encodebase64_test.c @@ -126,6 +126,18 @@ TEST(DecodeBase64, testInvalidSequences_skipsOverThem) { EXPECT_BINEQ(u"♦ ", gc(DecodeBase64("====BB==", 8, 0))); } +TEST(DecodeBase64, testOom_returnsNullAndSetsSizeToZero) { + n = 31337; + EXPECT_EQ(NULL, DecodeBase64("hello", 0x1000000000000, &n)); + EXPECT_EQ(0, n); +} + +TEST(EncodeBase64, testOom_returnsNullAndSetsSizeToZero) { + n = 31337; + EXPECT_EQ(NULL, EncodeBase64("hello", 0x1000000000000, &n)); + EXPECT_EQ(0, n); +} + TEST(Base64, RoundTrip) { for (i = 0; i < 1000; ++i) { n = rand() % 32; diff --git a/test/net/http/encodehttpheadervalue_test.c b/test/net/http/encodehttpheadervalue_test.c index 9df05d12b..c3f9dc996 100644 --- a/test/net/http/encodehttpheadervalue_test.c +++ b/test/net/http/encodehttpheadervalue_test.c @@ -70,6 +70,12 @@ TEST(EncodeHttpHeaderValue, testC1_isForbidden) { EXPECT_EQ(NULL, gc(EncodeHttpHeaderValue("\302\205", 2, 0))); } +TEST(EncodeHttpHeaderValue, testOom_returnsNullAndSetsSizeToZero) { + n = 31337; + EXPECT_EQ(NULL, EncodeHttpHeaderValue("hello", 0x1000000000000, &n)); + EXPECT_EQ(0, n); +} + BENCH(EncodeHttpHeaderValue, bench) { n = 22851; p = gc(malloc(n)); diff --git a/test/net/http/escapeurlparam_test.c b/test/net/http/escapeurlparam_test.c index c7469c700..2bb7745c8 100644 --- a/test/net/http/escapeurlparam_test.c +++ b/test/net/http/escapeurlparam_test.c @@ -25,29 +25,29 @@ char *escapeparam(const char *s) { struct EscapeResult r; - r = EscapeUrlParam(s, strlen(s)); + r = EscapeUrlParam(s, -1); ASSERT_EQ(strlen(r.data), r.size); return r.data; } -TEST(escapeparam, test) { +TEST(EscapeUrlParam, test) { EXPECT_STREQ("abc%20%26%3C%3E%22%27%01%02", gc(escapeparam("abc &<>\"'\1\2"))); } -TEST(escapeparam, testLargeGrowth) { +TEST(EscapeUrlParam, testLargeGrowth) { EXPECT_STREQ("%22%22%22", gc(escapeparam("\"\"\""))); } -TEST(escapeparam, testEmpty) { +TEST(EscapeUrlParam, testEmpty) { EXPECT_STREQ("", gc(escapeparam(""))); } -TEST(escapeparam, testAstralPlanes_usesUtf8HexEncoding) { +TEST(EscapeUrlParam, testAstralPlanes_usesUtf8HexEncoding) { EXPECT_STREQ("%F0%90%8C%B0", escapeparam("𐌰")); } -BENCH(escapeparam, bench) { - EZBENCH2("escapeparam", donothing, +BENCH(EscapeUrlParam, bench) { + EZBENCH2("EscapeUrlParam", donothing, free(EscapeUrlParam(kHyperion, kHyperionSize).data)); } diff --git a/test/net/http/isacceptablehostport_test.c b/test/net/http/isacceptablehostport_test.c new file mode 100644 index 000000000..7d392dba5 --- /dev/null +++ b/test/net/http/isacceptablehostport_test.c @@ -0,0 +1,59 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/testlib/testlib.h" +#include "net/http/http.h" + +TEST(IsAcceptableHostPort, test) { + EXPECT_FALSE(IsAcceptableHostPort("", -1)); + EXPECT_FALSE(IsAcceptableHostPort(":", -1)); + EXPECT_FALSE(IsAcceptableHostPort(":80", -1)); + EXPECT_TRUE(IsAcceptableHostPort("0.0.0.0", -1)); + EXPECT_FALSE(IsAcceptableHostPort("1.2.3", -1)); + EXPECT_TRUE(IsAcceptableHostPort("1.2.3.4", -1)); + EXPECT_FALSE(IsAcceptableHostPort("1.2.3.4.5", -1)); + EXPECT_TRUE(IsAcceptableHostPort("1.2.3.4.5.arpa", -1)); + EXPECT_TRUE(IsAcceptableHostPort("255.255.255.255", -1)); + EXPECT_FALSE(IsAcceptableHostPort("255.255.255", -1)); + EXPECT_FALSE(IsAcceptableHostPort("256.255.255.255", -1)); + EXPECT_TRUE(IsAcceptableHostPort("hello.example", -1)); + EXPECT_FALSE(IsAcceptableHostPort("hello..example", -1)); + EXPECT_TRUE(IsAcceptableHostPort("hello.example:80", -1)); + EXPECT_FALSE(IsAcceptableHostPort("hello.example:80:", -1)); + EXPECT_FALSE(IsAcceptableHostPort("hello.example::80", -1)); + EXPECT_FALSE(IsAcceptableHostPort("hello.example:-80", -1)); + EXPECT_FALSE(IsAcceptableHostPort(":80", -1)); + EXPECT_TRUE(IsAcceptableHostPort("hello.example:65535", -1)); + EXPECT_FALSE(IsAcceptableHostPort("hello.example:65536", -1)); + EXPECT_FALSE(IsAcceptableHostPort("hello.example:-80", -1)); + EXPECT_FALSE(IsAcceptableHostPort(" hello .example:80", -1)); + EXPECT_FALSE(IsAcceptableHostPort("hello.example:80h", -1)); + EXPECT_TRUE(IsAcceptableHostPort("hello", -1)); + EXPECT_FALSE(IsAcceptableHostPort("hello\177", -1)); + EXPECT_FALSE(IsAcceptableHostPort("hello.example\300\200:80", -1)); + EXPECT_FALSE(IsAcceptableHostPort(".", -1)); + EXPECT_FALSE(IsAcceptableHostPort(".e", -1)); + EXPECT_FALSE(IsAcceptableHostPort("e.", -1)); + EXPECT_FALSE(IsAcceptableHostPort(".hi.example", -1)); + EXPECT_FALSE(IsAcceptableHostPort("hi..example", -1)); + EXPECT_TRUE(IsAcceptableHostPort("hi-there.example", -1)); + EXPECT_TRUE(IsAcceptableHostPort("_there.example", -1)); + EXPECT_TRUE(IsAcceptableHostPort("-there.example", -1)); + EXPECT_TRUE(IsAcceptableHostPort("there-.example", -1)); + EXPECT_FALSE(IsAcceptableHostPort("ther#e.example", -1)); +} diff --git a/test/net/http/isacceptablepath_test.c b/test/net/http/isacceptablepath_test.c new file mode 100644 index 000000000..4472b9f7e --- /dev/null +++ b/test/net/http/isacceptablepath_test.c @@ -0,0 +1,92 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/runtime/gc.internal.h" +#include "libc/testlib/ezbench.h" +#include "libc/testlib/testlib.h" +#include "net/http/escape.h" +#include "net/http/http.h" + +TEST(IsAcceptablePath, test) { + EXPECT_TRUE(IsAcceptablePath("/", 1)); + EXPECT_TRUE(IsAcceptablePath("index.html", 10)); + EXPECT_TRUE(IsAcceptablePath("/index.html", 11)); + EXPECT_TRUE(IsAcceptablePath("/index.html", -1)); +} + +TEST(IsAcceptablePath, testEmptyString_allowedIfYouLikeImplicitLeadingSlash) { + EXPECT_TRUE(IsAcceptablePath(0, 0)); + EXPECT_TRUE(IsAcceptablePath(0, -1)); + EXPECT_TRUE(IsAcceptablePath("", 0)); +} + +TEST(IsAcceptablePath, testHiddenFiles_notAllowed) { + EXPECT_FALSE(IsAcceptablePath("/.index.html", 12)); + EXPECT_FALSE(IsAcceptablePath("/x/.index.html", 14)); +} + +TEST(IsAcceptablePath, testDoubleSlash_notAllowed) { + EXPECT_FALSE(IsAcceptablePath("//", 2)); + EXPECT_FALSE(IsAcceptablePath("foo//", 5)); + EXPECT_FALSE(IsAcceptablePath("/foo//", 6)); + EXPECT_FALSE(IsAcceptablePath("/foo//bar", 9)); +} + +TEST(IsAcceptablePath, testNoncanonicalDirectories_areForbidden) { + EXPECT_FALSE(IsAcceptablePath(".", 1)); + EXPECT_FALSE(IsAcceptablePath("..", 2)); + EXPECT_FALSE(IsAcceptablePath("/.", 2)); + EXPECT_FALSE(IsAcceptablePath("/..", 3)); + EXPECT_FALSE(IsAcceptablePath("./", 2)); + EXPECT_FALSE(IsAcceptablePath("../", 3)); + EXPECT_FALSE(IsAcceptablePath("/./", 3)); + EXPECT_FALSE(IsAcceptablePath("/../", 4)); + EXPECT_FALSE(IsAcceptablePath("x/.", 3)); + EXPECT_FALSE(IsAcceptablePath("x/..", 4)); + EXPECT_FALSE(IsAcceptablePath("x/./", 4)); + EXPECT_FALSE(IsAcceptablePath("x/../", 5)); + EXPECT_FALSE(IsAcceptablePath("/x/./", 5)); + EXPECT_FALSE(IsAcceptablePath("/x/../", 6)); +} + +TEST(IsAcceptablePath, testNoncanonicalWindowsDirs_areForbidden) { + EXPECT_FALSE(IsAcceptablePath(".", 1)); + EXPECT_FALSE(IsAcceptablePath("..", 2)); + EXPECT_FALSE(IsAcceptablePath("\\.", 2)); + EXPECT_FALSE(IsAcceptablePath("\\..", 3)); + EXPECT_FALSE(IsAcceptablePath(".\\", 2)); + EXPECT_FALSE(IsAcceptablePath("..\\", 3)); + EXPECT_FALSE(IsAcceptablePath("\\.\\", 3)); + EXPECT_FALSE(IsAcceptablePath("\\..\\", 4)); + EXPECT_FALSE(IsAcceptablePath("x\\.", 3)); + EXPECT_FALSE(IsAcceptablePath("x\\..", 4)); + EXPECT_FALSE(IsAcceptablePath("x\\.\\", 4)); + EXPECT_FALSE(IsAcceptablePath("x\\..\\", 5)); + EXPECT_FALSE(IsAcceptablePath("\\x\\.\\", 5)); + EXPECT_FALSE(IsAcceptablePath("\\x\\..\\", 6)); +} + +TEST(IsAcceptablePath, testOverlongSlashDot_isDetected) { + EXPECT_FALSE(IsAcceptablePath("/\300\256", 3)); + EXPECT_FALSE(IsAcceptablePath("/\300\257", 3)); + EXPECT_FALSE(IsAcceptablePath("\300\256\300\256", 4)); +} + +BENCH(IsAcceptablePath, bench) { + EZBENCH2("IsAcceptablePath", donothing, IsAcceptablePath("/index.html", 11)); +} diff --git a/test/net/http/parsehttprequest_test.c b/test/net/http/parsehttprequest_test.c index 5047fa829..3aec4789e 100644 --- a/test/net/http/parsehttprequest_test.c +++ b/test/net/http/parsehttprequest_test.c @@ -202,6 +202,35 @@ User-Agent: \t hi there \t \r\n\ EXPECT_STREQ("hi there", gc(slice(m, req->headers[kHttpUserAgent]))); } +TEST(ParseHttpRequest, testAbsentHost_setsSliceToZero) { + static const char m[] = "\ +GET / HTTP/1.1\r\n\ +\r\n"; + EXPECT_EQ(strlen(m), ParseHttpRequest(req, m, strlen(m))); + EXPECT_EQ(0, req->headers[kHttpHost].a); + EXPECT_EQ(0, req->headers[kHttpHost].b); +} + +TEST(ParseHttpRequest, testEmptyHost_setsSliceToNonzeroValue) { + static const char m[] = "\ +GET / HTTP/1.1\r\n\ +Host:\r\n\ +\r\n"; + EXPECT_EQ(strlen(m), ParseHttpRequest(req, m, strlen(m))); + EXPECT_NE(0, req->headers[kHttpHost].a); + EXPECT_EQ(req->headers[kHttpHost].a, req->headers[kHttpHost].b); +} + +TEST(ParseHttpRequest, testEmptyHost2_setsSliceToNonzeroValue) { + static const char m[] = "\ +GET / HTTP/1.1\r\n\ +Host: \r\n\ +\r\n"; + EXPECT_EQ(strlen(m), ParseHttpRequest(req, m, strlen(m))); + EXPECT_NE(0, req->headers[kHttpHost].a); + EXPECT_EQ(req->headers[kHttpHost].a, req->headers[kHttpHost].b); +} + void DoTiniestHttpRequest(void) { static const char m[] = "\ GET /\r\n\ diff --git a/test/net/http/parseurl_test.c b/test/net/http/parseurl_test.c new file mode 100644 index 000000000..219ae77aa --- /dev/null +++ b/test/net/http/parseurl_test.c @@ -0,0 +1,357 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/limits.h" +#include "libc/mem/mem.h" +#include "libc/rand/rand.h" +#include "libc/testlib/ezbench.h" +#include "libc/testlib/hyperion.h" +#include "libc/testlib/testlib.h" +#include "net/http/url.h" + +TEST(ParseRequestUri, testEmpty) { + struct Url h; + gc(ParseRequestUri(0, 0, &h)); + gc(h.params.p); + ASSERT_EQ(0, h.params.n); +} + +TEST(ParseRequestUri, testFragment) { + struct Url h; + gc(ParseRequestUri("#x", -1, &h)); + gc(h.params.p); + ASSERT_EQ(0, h.path.n); + ASSERT_EQ(1, h.fragment.n); + ASSERT_BINEQ(u"x", h.fragment.p); +} + +TEST(ParseRequestUri, testFragmentAbsent_isNull) { + struct Url h; + gc(ParseRequestUri("", -1, &h)); + gc(h.params.p); + ASSERT_EQ(0, h.fragment.p); + ASSERT_EQ(0, h.fragment.n); +} + +TEST(ParseRequestUri, testFragmentEmpty_isNonNull) { + struct Url h; + gc(ParseRequestUri("#", -1, &h)); + gc(h.params.p); + ASSERT_NE(0, h.fragment.p); + ASSERT_EQ(0, h.fragment.n); +} + +TEST(ParseRequestUri, testPathFragment) { + struct Url h; + gc(ParseRequestUri("x#y", -1, &h)); + gc(h.params.p); + ASSERT_EQ(1, h.path.n); + ASSERT_EQ('x', h.path.p[0]); + ASSERT_EQ(1, h.fragment.n); + ASSERT_EQ('y', h.fragment.p[0]); +} + +TEST(ParseRequestUri, testAbsolutePath) { + struct Url h; + gc(ParseRequestUri("/x/y", -1, &h)); + gc(h.params.p); + ASSERT_EQ(4, h.path.n); + ASSERT_BINEQ(u"/x/y", h.path.p); +} + +TEST(ParseRequestUri, testRelativePath1) { + struct Url h; + gc(ParseRequestUri("x", -1, &h)); + gc(h.params.p); + ASSERT_EQ(1, h.path.n); + ASSERT_EQ('x', h.path.p[0]); +} + +TEST(ParseRequestUri, testOptions) { + struct Url h; + gc(ParseRequestUri("*", -1, &h)); + gc(h.params.p); + ASSERT_EQ(1, h.path.n); + ASSERT_EQ('*', h.path.p[0]); +} + +TEST(ParseRequestUri, testRelativePath2) { + struct Url h; + gc(ParseRequestUri("x/y", -1, &h)); + gc(h.params.p); + ASSERT_EQ(3, h.path.n); + ASSERT_BINEQ(u"x/y", h.path.p); +} + +TEST(ParseRequestUri, testRoot) { + struct Url h; + gc(ParseRequestUri("/", -1, &h)); + gc(h.params.p); + ASSERT_EQ(1, h.path.n); + ASSERT_EQ('/', h.path.p[0]); +} + +TEST(ParseRequestUri, testSchemePath) { + struct Url h; + gc(ParseRequestUri("x:y", -1, &h)); + gc(h.params.p); + ASSERT_EQ(1, h.scheme.n); + ASSERT_BINEQ(u"x", h.scheme.p); + ASSERT_EQ(1, h.path.n); + ASSERT_BINEQ(u"y", h.path.p); +} + +TEST(ParseRequestUri, testSchemeAuthority) { + struct Url h; + gc(ParseRequestUri("x://y", -1, &h)); + gc(h.params.p); + ASSERT_EQ(1, h.scheme.n); + ASSERT_EQ('x', h.scheme.p[0]); + ASSERT_EQ(1, h.host.n); + ASSERT_EQ('y', h.host.p[0]); +} + +TEST(ParseRequestUri, testParamsQuestion_doesntTurnIntoSpace) { + struct Url h; + gc(ParseRequestUri("x?+", -1, &h)); + gc(h.params.p); + ASSERT_EQ(1, h.path.n); + ASSERT_BINEQ(u"x", h.path.p); + ASSERT_EQ(1, h.params.n); + ASSERT_EQ(1, h.params.p[0].key.n); + ASSERT_EQ('+', h.params.p[0].key.p[0]); +} + +TEST(ParseRequestUri, testUrl) { + struct Url h; + gc(ParseRequestUri("a://b:B@c:C/d?e#f", -1, &h)); + gc(h.params.p); + ASSERT_EQ(1, h.scheme.n); + ASSERT_EQ('a', h.scheme.p[0]); + ASSERT_EQ(1, h.user.n); + ASSERT_EQ('b', h.user.p[0]); + ASSERT_EQ(1, h.pass.n); + ASSERT_EQ('B', h.pass.p[0]); + ASSERT_EQ(1, h.host.n); + ASSERT_EQ('c', h.host.p[0]); + ASSERT_EQ(1, h.port.n); + ASSERT_EQ('C', h.port.p[0]); + ASSERT_EQ(2, h.path.n); + ASSERT_BINEQ(u"/d", h.path.p); + ASSERT_EQ(1, h.params.n); + ASSERT_EQ(1, h.params.p[0].key.n); + ASSERT_BINEQ(u"e", h.params.p[0].key.p); + ASSERT_EQ(SIZE_MAX, h.params.p[0].val.n); + ASSERT_EQ(1, h.fragment.n); + ASSERT_BINEQ(u"f", h.fragment.p); +} + +TEST(ParseRequestUri, testUrlWithoutScheme) { + struct Url h; + gc(ParseRequestUri("//b@c/d?e#f", -1, &h)); + gc(h.params.p); + ASSERT_EQ(0, h.scheme.n); + ASSERT_EQ(1, h.user.n); + ASSERT_EQ('b', h.user.p[0]); + ASSERT_EQ(1, h.host.n); + ASSERT_EQ('c', h.host.p[0]); + ASSERT_EQ(2, h.path.n); + ASSERT_BINEQ(u"/d", h.path.p); + ASSERT_EQ(1, h.params.n); + ASSERT_EQ(1, h.params.p[0].key.n); + ASSERT_BINEQ(u"e", h.params.p[0].key.p); + ASSERT_EQ(SIZE_MAX, h.params.p[0].val.n); + ASSERT_EQ(1, h.fragment.n); + ASSERT_BINEQ(u"f", h.fragment.p); +} + +TEST(ParseRequestUri, testUrlWithoutUser) { + struct Url h; + gc(ParseRequestUri("a://c/d?e#f", -1, &h)); + gc(h.params.p); + ASSERT_EQ(1, h.scheme.n); + ASSERT_EQ('a', h.scheme.p[0]); + ASSERT_EQ(0, h.user.n); + ASSERT_EQ(0, h.pass.n); + ASSERT_EQ(1, h.host.n); + ASSERT_EQ('c', h.host.p[0]); + ASSERT_EQ(0, h.port.n); + ASSERT_EQ(2, h.path.n); + ASSERT_BINEQ(u"/d", h.path.p); + ASSERT_EQ(1, h.params.n); + ASSERT_EQ(1, h.params.p[0].key.n); + ASSERT_EQ('e', h.params.p[0].key.p[0]); + ASSERT_EQ(SIZE_MAX, h.params.p[0].val.n); + ASSERT_EQ(1, h.fragment.n); + ASSERT_EQ('f', h.fragment.p[0]); +} + +TEST(ParseRequestUri, testLolv6) { + struct Url h; + gc(ParseRequestUri("//[::1]:31337", -1, &h)); + gc(h.params.p); + ASSERT_EQ(3, h.host.n); + ASSERT_BINEQ(u"::1", h.host.p); + ASSERT_EQ(5, h.port.n); + ASSERT_BINEQ(u"31337", h.port.p); +} + +TEST(ParseRequestUri, testUrlWithoutParams) { + struct Url h; + gc(ParseRequestUri("a://b@c/d#f", -1, &h)); + gc(h.params.p); + ASSERT_EQ(1, h.scheme.n); + ASSERT_EQ('a', h.scheme.p[0]); + ASSERT_EQ(1, h.user.n); + ASSERT_EQ('b', h.user.p[0]); + ASSERT_EQ(1, h.host.n); + ASSERT_EQ('c', h.host.p[0]); + ASSERT_EQ(2, h.path.n); + ASSERT_BINEQ(u"/d", h.path.p); + ASSERT_EQ(0, h.params.n); + ASSERT_EQ(1, h.fragment.n); + ASSERT_EQ('f', h.fragment.p[0]); +} + +TEST(ParseUrl, testLatin1_doesNothing) { + struct Url h; + const char b[1] = {0377}; + gc(ParseUrl(b, 1, &h)); + gc(h.params.p); + ASSERT_EQ(1, h.path.n); + ASSERT_EQ(0, memcmp("\377", h.path.p, 1)); +} + +TEST(ParseRequestUri, testLatin1_expandsMemoryToUtf8) { + struct Url h; + const char b[1] = {0377}; + gc(ParseRequestUri(b, 1, &h)); + gc(h.params.p); + ASSERT_EQ(2, h.path.n); + ASSERT_EQ(0, memcmp("\303\277", h.path.p, 2)); +} + +TEST(ParseRequestUri, testPercentShrinkingMemory) { + struct Url h; + gc(ParseRequestUri("%Ff", 3, &h)); + gc(h.params.p); + ASSERT_EQ(1, h.path.n); + ASSERT_EQ(0, memcmp("\377", h.path.p, 1)); +} + +TEST(ParseRequestUri, testBadPercent_getsIgnored) { + struct Url h; + gc(ParseRequestUri("%FZ", 3, &h)); + gc(h.params.p); + ASSERT_EQ(3, h.path.n); + ASSERT_EQ(0, memcmp("%FZ", h.path.p, 3)); +} + +TEST(ParseRequestUri, testFileUrl) { + struct Url h; + gc(ParseRequestUri("file:///etc/passwd", -1, &h)); + gc(h.params.p); + ASSERT_EQ(4, h.scheme.n); + ASSERT_BINEQ(u"file", h.scheme.p); + ASSERT_EQ(11, h.path.n); + ASSERT_BINEQ(u"/etc/passwd", h.path.p); +} + +TEST(ParseRequestUri, testZipUri2) { + struct Url h; + gc(ParseRequestUri("zip:etc/passwd", -1, &h)); + gc(h.params.p); + ASSERT_EQ(3, h.scheme.n); + ASSERT_BINEQ(u"zip", h.scheme.p); + ASSERT_EQ(10, h.path.n); + ASSERT_BINEQ(u"etc/passwd", h.path.p); +} + +TEST(ParseParams, testEmpty) { + struct UrlParams h = {0}; + gc(ParseParams(0, 0, &h)); + gc(h.p); + ASSERT_EQ(0, h.n); +} + +TEST(ParseParams, test) { + struct UrlParams h = {0}; + gc(ParseParams("a=b&c&x+y%7A=", -1, &h)); + gc(h.p); + ASSERT_EQ(3, h.n); + ASSERT_EQ(1, h.p[0].key.n); + ASSERT_EQ(1, h.p[0].val.n); + ASSERT_EQ(1, h.p[1].key.n); + ASSERT_EQ(SIZE_MAX, h.p[1].val.n); + ASSERT_EQ(4, h.p[2].key.n); + ASSERT_EQ(0, h.p[2].val.n); + EXPECT_EQ('a', h.p[0].key.p[0]); + EXPECT_EQ('b', h.p[0].val.p[0]); + EXPECT_EQ('c', h.p[1].key.p[0]); + EXPECT_BINEQ(u"x yz", h.p[2].key.p); +} + +TEST(ParseParams, testLatin1_doesNothing) { + struct UrlParams h = {0}; + gc(ParseParams("\200", -1, &h)); + gc(h.p); + ASSERT_EQ(1, h.n); + ASSERT_EQ(1, h.p[0].key.n); + ASSERT_EQ(0200, h.p[0].key.p[0] & 255); +} + +TEST(ParseParams, testUtf8_doesNothing) { + struct UrlParams h = {0}; + gc(ParseParams("\300\200", -1, &h)); + gc(h.p); + ASSERT_EQ(1, h.n); + ASSERT_EQ(2, h.p[0].key.n); + ASSERT_EQ(0300, h.p[0].key.p[0] & 255); + ASSERT_EQ(0200, h.p[0].key.p[1] & 255); +} + +TEST(ParseRequestUri, fuzz) { + int i, j; + struct Url h; + char B[13], C[] = "/:#?%[]:@&=abc123xyz\200\300"; + for (i = 0; i < 1024; ++i) { + for (j = 0; j < sizeof(B); ++j) { + B[j] = C[rand() % sizeof(C)]; + } + free(ParseRequestUri(B, 8, &h)); + free(h.params.p); + } +} + +void A(void) { + struct UrlParams h = {0}; + free(ParseParams(kHyperion, kHyperionSize, &h)); + free(h.p); +} + +BENCH(url, bench) { + struct Url h; + EZBENCH2("ParseParams", donothing, A()); + EZBENCH2("URI a", donothing, free(ParseRequestUri("a", -1, &h))); + EZBENCH2("URI a://b@c/d#f", donothing, + free(ParseRequestUri("a://b@c/d#f", -1, &h))); + EZBENCH2("URI a://b@c/d?z#f", donothing, ({ + free(ParseRequestUri("a://b@c/?zd#f", -1, &h)); + free(h.params.p); + })); +} diff --git a/test/net/http/visualizecontrolcodes_test.c b/test/net/http/visualizecontrolcodes_test.c index b307f0b4d..8c33ccd37 100644 --- a/test/net/http/visualizecontrolcodes_test.c +++ b/test/net/http/visualizecontrolcodes_test.c @@ -28,6 +28,12 @@ TEST(VisualizeControlCodes, test) { EXPECT_STREQ("hello\\u0085", VisualizeControlCodes("hello\302\205", -1, 0)); } +TEST(VisualizeControlCodes, testOom_returnsNullAndSetsSizeToZero) { + size_t n = 31337; + EXPECT_EQ(NULL, VisualizeControlCodes("hello", 0x1000000000000, &n)); + EXPECT_EQ(0, n); +} + BENCH(VisualizeControlCodes, bench) { EZBENCH2("VisualizeControlCodes", donothing, free(VisualizeControlCodes(kHyperion, kHyperionSize, 0))); diff --git a/third_party/chibicc/as.c b/third_party/chibicc/as.c index 8d59d04a6..88c430b49 100644 --- a/third_party/chibicc/as.c +++ b/third_party/chibicc/as.c @@ -16,6 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/bits.h" #include "libc/calls/calls.h" #include "libc/calls/struct/stat.h" #include "libc/elf/def.h" @@ -138,16 +139,7 @@ #define APPEND(L) L.p = realloc(L.p, ++L.n * sizeof(*L.p)) #define IS(P, N, S) (N == sizeof(S) - 1 && !strncasecmp(P, S, sizeof(S) - 1)) #define MAX(X, Y) ((Y) < (X) ? (X) : (Y)) -#define LOAD128BE(S) ((unsigned __int128)LOAD64BE(S) << 64 | LOAD64BE((S) + 8)) -#define LOAD64BE(S) \ - ((unsigned long)((unsigned char *)(S))[0] << 070 | \ - (unsigned long)((unsigned char *)(S))[1] << 060 | \ - (unsigned long)((unsigned char *)(S))[2] << 050 | \ - (unsigned long)((unsigned char *)(S))[3] << 040 | \ - (unsigned long)((unsigned char *)(S))[4] << 030 | \ - (unsigned long)((unsigned char *)(S))[5] << 020 | \ - (unsigned long)((unsigned char *)(S))[6] << 010 | \ - (unsigned long)((unsigned char *)(S))[7] << 000) +#define READ128BE(S) ((unsigned __int128)READ64BE(S) << 64 | READ64BE((S) + 8)) struct As { int i; // things @@ -1911,13 +1903,13 @@ static void CopyLower(char *k, const char *p, int n) { static unsigned long MakeKey64(const char *p, int n) { char k[8] = {0}; CopyLower(k, p, n); - return LOAD64BE(k); + return READ64BE(k); } static unsigned __int128 MakeKey128(const char *p, int n) { char k[16] = {0}; CopyLower(k, p, n); - return LOAD128BE(k); + return READ128BE(k); } static bool Prefix(struct As *a, const char *p, int n) { @@ -1929,7 +1921,7 @@ static bool Prefix(struct As *a, const char *p, int n) { r = ARRAYLEN(kPrefix) - 1; while (l <= r) { m = (l + r) >> 1; - y = LOAD64BE(kPrefix[m]); + y = READ64BE(kPrefix[m]); if (x < y) { r = m - 1; } else if (x > y) { @@ -1954,7 +1946,7 @@ static bool FindReg(const char *p, int n, struct Reg *out_reg) { r = ARRAYLEN(kRegs) - 1; while (l <= r) { m = (l + r) >> 1; - y = LOAD64BE(kRegs[m].s); + y = READ64BE(kRegs[m].s); if (x < y) { r = m - 1; } else if (x > y) { @@ -3710,7 +3702,7 @@ static bool OnDirective8(struct As *a, struct Slice s) { r = ARRAYLEN(kDirective8) - 1; while (l <= r) { m = (l + r) >> 1; - y = LOAD64BE(kDirective8[m].s); + y = READ64BE(kDirective8[m].s); if (x < y) { r = m - 1; } else if (x > y) { @@ -3733,7 +3725,7 @@ static bool OnDirective16(struct As *a, struct Slice s) { r = ARRAYLEN(kDirective16) - 1; while (l <= r) { m = (l + r) >> 1; - y = LOAD128BE(kDirective16[m].s); + y = READ128BE(kDirective16[m].s); if (x < y) { r = m - 1; } else if (x > y) { diff --git a/third_party/dlmalloc/dlmalloc.c b/third_party/dlmalloc/dlmalloc.c index 4bf1b9810..4b33edc6c 100644 --- a/third_party/dlmalloc/dlmalloc.c +++ b/third_party/dlmalloc/dlmalloc.c @@ -37,9 +37,10 @@ hidden struct MallocParams g_mparams; */ static void *dlmalloc_requires_more_vespene_gas(size_t size) { char *p; - p = mapanon(size); - if (weaken(__asan_poison)) { - weaken(__asan_poison)((uintptr_t)p, size, kAsanHeapFree); + if ((p = mapanon(size)) != MAP_FAILED) { + if (weaken(__asan_poison)) { + weaken(__asan_poison)((uintptr_t)p, size, kAsanHeapFree); + } } return p; } @@ -836,7 +837,7 @@ textstartup void dlmalloc_init(void) { if (g_mparams.magic == 0) { size_t magic; size_t psize = PAGESIZE; - size_t gsize = FRAMESIZE; + size_t gsize = DEFAULT_GRANULARITY; /* Sanity-check configuration: size_t must be unsigned and as wide as pointer type. ints must be at least 4 bytes. diff --git a/third_party/dlmalloc/dlmalloc.internal.h b/third_party/dlmalloc/dlmalloc.internal.h index a88b8000d..5be234213 100644 --- a/third_party/dlmalloc/dlmalloc.internal.h +++ b/third_party/dlmalloc/dlmalloc.internal.h @@ -907,7 +907,7 @@ extern struct MallocParams g_mparams; #else /* GNUC */ #define RTCHECK(e) (e) #endif /* GNUC */ -#else /* !IsTrustworthy() */ +#else /* !IsTrustworthy() */ #define RTCHECK(e) (1) #endif /* !IsTrustworthy() */ diff --git a/tool/build/lib/cvt.c b/tool/build/lib/cvt.c index 7a85bb262..04f4373dc 100644 --- a/tool/build/lib/cvt.c +++ b/tool/build/lib/cvt.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.internal.h" #include "libc/math.h" +#include "libc/str/str.h" #include "tool/build/lib/cvt.h" #include "tool/build/lib/endian.h" #include "tool/build/lib/machine.h" diff --git a/tool/build/lib/endian.h b/tool/build/lib/endian.h index da716f707..f23d1d39b 100644 --- a/tool/build/lib/endian.h +++ b/tool/build/lib/endian.h @@ -1,116 +1,53 @@ #ifndef COSMOPOLITAN_TOOL_BUILD_LIB_ENDIAN_H_ #define COSMOPOLITAN_TOOL_BUILD_LIB_ENDIAN_H_ -#include "libc/dce.h" -#include "libc/str/str.h" -#if !(__ASSEMBLER__ + __LINKER__ + 0) -#if __BYTE_ORDER__ + 0 == 1234 +#include "libc/bits/bits.h" -#define Read8(P) \ - ({ \ - uint8_t *Ptr = (P); \ - *Ptr; \ +#define Read8(P) (*(const uint8_t *)(P)) + +#define Read16(P) \ + ({ \ + const uint8_t *Ptr = (const uint8_t *)(P); \ + READ16LE(P); \ }) -#define Read16(P) \ - ({ \ - uint16_t Res; \ - uint8_t *Ptr = (P); \ - memcpy(&Res, Ptr, 2); \ - Res; \ +#define Read32(P) \ + ({ \ + const uint8_t *Ptr = (const uint8_t *)(P); \ + READ32LE(P); \ }) -#define Read32(P) \ - ({ \ - uint32_t Res; \ - uint8_t *Ptr = (P); \ - memcpy(&Res, Ptr, 4); \ - Res; \ +#define Read64(P) \ + ({ \ + const uint8_t *Ptr = (const uint8_t *)(P); \ + READ64LE(P); \ }) -#define Read64(P) \ - ({ \ - uint64_t Res; \ - uint8_t *Ptr = (P); \ - memcpy(&Res, Ptr, 8); \ - Res; \ - }) - -#define Write8(P, B) \ +#define Write8(P, V) \ do { \ + uint8_t Val = (V); \ uint8_t *Ptr = (P); \ - *Ptr = (B); \ + *Ptr = Val; \ } while (0) -#define Write16(P, V) \ - do { \ - uint16_t Val = (V); \ - uint8_t *Ptr = (P); \ - memcpy(Ptr, &Val, 2); \ +#define Write16(P, V) \ + do { \ + uint16_t Val = (V); \ + uint8_t *Ptr = (P); \ + WRITE16LE(Ptr, Val); \ } while (0) -#define Write32(P, V) \ - do { \ - uint32_t Val = (V); \ - uint8_t *Ptr = (P); \ - memcpy(Ptr, &Val, 4); \ +#define Write32(P, V) \ + do { \ + uint32_t Val = (V); \ + uint8_t *Ptr = (P); \ + WRITE32LE(Ptr, Val); \ } while (0) -#define Write64(P, V) \ - do { \ - uint64_t Val = (V); \ - uint8_t *Ptr = (P); \ - memcpy(Ptr, &Val, 8); \ +#define Write64(P, V) \ + do { \ + uint64_t Val = (V); \ + uint8_t *Ptr = (P); \ + WRITE64LE(Ptr, Val); \ } while (0) -#else - -forceinline uint16_t Read8(const uint8_t p[hasatleast 1]) { - return p[0]; -} - -forceinline uint16_t Read16(const uint8_t p[hasatleast 2]) { - return p[0] | p[1] << 010; -} - -forceinline uint32_t Read32(const uint8_t bytes[hasatleast 4]) { - return (uint32_t)bytes[0] << 000 | (uint32_t)bytes[1] << 010 | - (uint32_t)bytes[2] << 020 | (uint32_t)bytes[3] << 030; -} - -forceinline uint64_t Read64(const uint8_t bytes[hasatleast 8]) { - return (uint64_t)bytes[0] << 000 | (uint64_t)bytes[1] << 010 | - (uint64_t)bytes[2] << 020 | (uint64_t)bytes[3] << 030 | - (uint64_t)bytes[4] << 040 | (uint64_t)bytes[5] << 050 | - (uint64_t)bytes[6] << 060 | (uint64_t)bytes[7] << 070; -} - -forceinline void Write8(unsigned char p[hasatleast 1], uint8_t x) { - p[0] = x >> 000; -} - -forceinline void Write16(unsigned char p[hasatleast 2], uint16_t x) { - p[0] = x >> 000; - p[1] = x >> 010; -} - -forceinline void Write32(unsigned char p[hasatleast 4], uint64_t x) { - p[0] = x >> 000; - p[1] = x >> 010; - p[2] = x >> 020; - p[3] = x >> 030; -} - -forceinline void Write64(unsigned char p[hasatleast 8], uint64_t x) { - p[0] = x >> 000; - p[1] = x >> 010; - p[2] = x >> 020; - p[3] = x >> 030; - p[4] = x >> 040; - p[5] = x >> 050; - p[6] = x >> 060; - p[7] = x >> 070; -} - -#endif /* ENDIAN */ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_TOOL_BUILD_LIB_ENDIAN_H_ */ diff --git a/tool/build/lib/machine.c b/tool/build/lib/machine.c index c6478ce4b..72a42522a 100644 --- a/tool/build/lib/machine.c +++ b/tool/build/lib/machine.c @@ -20,6 +20,7 @@ #include "libc/macros.internal.h" #include "libc/rand/rand.h" #include "libc/runtime/runtime.h" +#include "libc/str/str.h" #include "tool/build/lib/abp.h" #include "tool/build/lib/address.h" #include "tool/build/lib/alu.h" @@ -1568,7 +1569,11 @@ static void Op1ae(struct Machine *m, uint32_t rde) { } static void OpSalc(struct Machine *m, uint32_t rde) { - Write8(m->ax, GetFlag(m->flags, FLAGS_CF)); + if (GetFlag(m->flags, FLAGS_CF)) { + m->ax[0] = 255; + } else { + m->ax[0] = 0; + } } static void OpBofram(struct Machine *m, uint32_t rde) { diff --git a/tool/build/lib/stack.c b/tool/build/lib/stack.c index 0ebe775dc..b646183a5 100644 --- a/tool/build/lib/stack.c +++ b/tool/build/lib/stack.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/log/check.h" #include "libc/macros.internal.h" +#include "libc/str/str.h" #include "tool/build/lib/address.h" #include "tool/build/lib/endian.h" #include "tool/build/lib/memory.h" diff --git a/tool/build/lib/syscall.c b/tool/build/lib/syscall.c index e22a07d0e..9ffd239f8 100644 --- a/tool/build/lib/syscall.c +++ b/tool/build/lib/syscall.c @@ -77,6 +77,8 @@ #include "tool/build/lib/throw.h" #include "tool/build/lib/xlaterrno.h" +#define SA_RESTORER 0x04000000 + #define AT_FDCWD_LINUX -100 #define TIOCGWINSZ_LINUX 0x5413 #define TCGETS_LINUX 0x5401 diff --git a/tool/build/lib/word.c b/tool/build/lib/word.c index f77df94b1..fd5d0ab8e 100644 --- a/tool/build/lib/word.c +++ b/tool/build/lib/word.c @@ -16,6 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/str/str.h" #include "tool/build/lib/endian.h" #include "tool/build/lib/memory.h" #include "tool/build/lib/word.h" diff --git a/tool/build/package.c b/tool/build/package.c index b9d1bbe49..a6c1f8184 100644 --- a/tool/build/package.c +++ b/tool/build/package.c @@ -25,6 +25,7 @@ #include "libc/bits/safemacros.internal.h" #include "libc/calls/calls.h" #include "libc/calls/struct/stat.h" +#include "libc/dce.h" #include "libc/elf/def.h" #include "libc/elf/elf.h" #include "libc/elf/struct/rela.h" @@ -165,8 +166,8 @@ struct Packages { }; int CompareSymbolName(const struct Symbol *a, const struct Symbol *b, - const char *strs[hasatleast 2]) { - return strcmp(&strs[0][a->name], &strs[1][b->name]); + const char *tab) { + return strcmp(tab + a->name, tab + b->name); } struct Package *LoadPackage(const char *path) { @@ -189,6 +190,7 @@ struct Package *LoadPackage(const char *path) { pkg->strings.p); pkg->addr = pkg; pkg->size = st.st_size; + CHECK_NE(-1, mprotect(pkg, st.st_size, PROT_READ)); return pkg; } @@ -378,37 +380,48 @@ void LoadObjects(struct Package *pkg) { size_t i; struct Object *obj; for (i = 0; i < pkg->objects.i; ++i) { - obj = &pkg->objects.p[i]; + obj = pkg->objects.p + i; OpenObject(pkg, obj, O_RDONLY, PROT_READ, MAP_SHARED); LoadSymbols(pkg, i); CloseObject(obj); } - qsort_r(&pkg->symbols.p[0], pkg->symbols.i, sizeof(pkg->symbols.p[0]), - (void *)CompareSymbolName, - (const char *[2]){pkg->strings.p, pkg->strings.p}); + qsort_r(pkg->symbols.p, pkg->symbols.i, sizeof(*pkg->symbols.p), + (void *)CompareSymbolName, pkg->strings.p); +} + +struct Symbol *BisectSymbol(struct Package *pkg, const char *name) { + int c; + long m, l, r; + l = 0; + r = pkg->symbols.i - 1; + while (l <= r) { + m = (l + r) >> 1; + c = strcmp(pkg->strings.p + pkg->symbols.p[m].name, name); + if (c < 0) { + l = m + 1; + } else if (c > 0) { + r = m - 1; + } else { + return pkg->symbols.p + m; + } + } + return NULL; } bool FindSymbol(const char *name, struct Package *pkg, struct Packages *directdeps, struct Package **out_pkg, struct Symbol **out_sym) { - size_t i; - struct Package *dep; - struct Symbol key, *sym; - key.name = 0; - if ((sym = bisect(&key, &pkg->symbols.p[0], pkg->symbols.i, - sizeof(pkg->symbols.p[0]), (void *)CompareSymbolName, - (const char *[2]){name, pkg->strings.p}))) { - if (out_pkg) *out_pkg = pkg; + size_t i, j; + struct Symbol *sym; + if ((sym = BisectSymbol(pkg, name))) { if (out_sym) *out_sym = sym; + if (out_pkg) *out_pkg = pkg; return true; } for (i = 0; i < directdeps->i; ++i) { - dep = directdeps->p[i]; - if ((sym = bisect(&key, &dep->symbols.p[0], dep->symbols.i, - sizeof(dep->symbols.p[0]), (void *)CompareSymbolName, - (const char *[2]){name, dep->strings.p}))) { - if (out_pkg) *out_pkg = dep; + if ((sym = BisectSymbol(directdeps->p[i], name))) { if (out_sym) *out_sym = sym; + if (out_pkg) *out_pkg = directdeps->p[i]; return true; } } @@ -422,15 +435,15 @@ void CheckStrictDeps(struct Package *pkg, struct Packages *deps) { for (i = 0; i < pkg->undefs.i; ++i) { undef = &pkg->undefs.p[i]; if (undef->bind == STB_WEAK) continue; - if (!FindSymbol(&pkg->strings.p[undef->name], pkg, deps, NULL, NULL)) { - fprintf(stderr, "%s: %s (%s) %s %s\n", "error", - &pkg->strings.p[undef->name], - &pkg->strings.p[pkg->objects.p[undef->object].path], - "not defined by direct deps of", &pkg->strings.p[pkg->path]); + if (!FindSymbol(pkg->strings.p + undef->name, pkg, deps, NULL, NULL)) { + fprintf(stderr, "%s: %`'s (%s) %s %s\n", "error", + pkg->strings.p + undef->name, + pkg->strings.p + pkg->objects.p[undef->object].path, + "not defined by direct deps of", pkg->strings.p + pkg->path); for (j = 0; j < deps->i; ++j) { dep = deps->p[j]; fputc('\t', stderr); - fputs(&dep->strings.p[dep->path], stderr); + fputs(dep->strings.p + dep->path, stderr); fputc('\n', stderr); } exit(1); diff --git a/tool/build/zipobj.c b/tool/build/zipobj.c index 5804775c6..3b6f21186 100644 --- a/tool/build/zipobj.c +++ b/tool/build/zipobj.c @@ -55,16 +55,6 @@ #define ZIP_LOCALFILE_SECTION ".zip.2." #define ZIP_DIRECTORY_SECTION ".zip.4." -#define PUT8(P, V) *P++ = V -#define PUT16(P, V) P[0] = V & 0xff, P[1] = V >> 010 & 0xff, P += 2 -#define PUT32(P, V) \ - P[0] = V & 0xff, P[1] = V >> 010 & 0xff, P[2] = V >> 020 & 0xff, \ - P[3] = V >> 030 & 0xff, P += 4 -#define PUT64(P, V) \ - P[0] = V & 0xff, P[1] = V >> 010 & 0xff, P[2] = V >> 020 & 0xff, \ - P[3] = V >> 030 & 0xff, P[4] = V >> 040 & 0xff, P[5] = V >> 050 & 0xff, \ - P[6] = V >> 060 & 0xff, P[7] = V >> 070 & 0xff, P += 8 - #define DOS_DATE(YEAR, MONTH_IDX1, DAY_IDX1) \ (((YEAR)-1980) << 9 | (MONTH_IDX1) << 5 | (DAY_IDX1)) #define DOS_TIME(HOUR, MINUTE, SECOND) \ @@ -116,10 +106,24 @@ void GetOpts(int *argc, char ***argv) { CHECK_NOTNULL(outpath_); } -bool IsPureAscii(const void *data, size_t size) { +bool IsUtf8(const void *data, size_t size) { + const unsigned char *p, *pe; + for (p = data, pe = p + size; p + 2 <= pe; ++p) { + if (*p >= 0300) { + if (*p >= 0200 && *p < 0300) { + return true; + } else { + return false; + } + } + } + return false; +} + +bool IsText(const void *data, size_t size) { const unsigned char *p, *pe; for (p = data, pe = p + size; p < pe; ++p) { - if (!*p || *p >= 0x80) { + if (*p <= 3) { return false; } } @@ -146,86 +150,81 @@ void GetDosLocalTime(int64_t utcunixts, uint16_t *out_time, *out_date = DOS_DATE(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday + 1); } -static unsigned char *EmitZipLfileHdr(unsigned char *op, const void *name, +static int DetermineVersionNeededToExtract(int method) { + if (method == kZipCompressionDeflate) { + return kZipEra1993; + } else { + return kZipEra1989; + } +} + +static unsigned char *EmitZipLfileHdr(unsigned char *p, const void *name, size_t namesize, uint32_t crc, uint8_t era, uint16_t gflags, uint16_t method, uint16_t mtime, uint16_t mdate, size_t compsize, size_t uncompsize) { - PUT32(op, kZipLfileHdrMagic); - PUT8(op, kZipEra1993); - PUT8(op, kZipOsDos); - PUT16(op, gflags); - PUT16(op, method); - PUT16(op, mtime); - PUT16(op, mdate); - PUT32(op, crc); - PUT32(op, compsize); - PUT32(op, uncompsize); - PUT16(op, namesize); - PUT16(op, 0); /* extra */ - return mempcpy(op, name, namesize); + p = WRITE32LE(p, kZipLfileHdrMagic); + *p++ = era; + *p++ = kZipOsDos; + p = WRITE16LE(p, gflags); + p = WRITE16LE(p, method); + p = WRITE16LE(p, mtime); + p = WRITE16LE(p, mdate); + p = WRITE32LE(p, crc); + p = WRITE32LE(p, compsize); + p = WRITE32LE(p, uncompsize); + p = WRITE16LE(p, namesize); + p = WRITE16LE(p, 0); /* extra */ + return mempcpy(p, name, namesize); } -static void EmitZipCdirHdr(unsigned char *op, const void *name, size_t namesize, +static void EmitZipCdirHdr(unsigned char *p, const void *name, size_t namesize, uint32_t crc, uint8_t era, uint16_t gflags, uint16_t method, uint16_t mtime, uint16_t mdate, uint16_t iattrs, uint16_t dosmode, uint16_t unixmode, size_t compsize, size_t uncompsize, size_t commentsize, struct stat *st) { uint64_t mt, at, ct; - PUT32(op, kZipCfileHdrMagic); - PUT8(op, 20); - PUT8(op, kZipOsDos); - PUT8(op, kZipEra1993); - PUT8(op, kZipOsDos); - PUT16(op, gflags); - PUT16(op, method); - PUT16(op, mtime); - PUT16(op, mdate); + p = WRITE32LE(p, kZipCfileHdrMagic); + *p++ = kZipCosmopolitanVersion; + *p++ = kZipOsUnix; + *p++ = era; + *p++ = kZipOsDos; + p = WRITE16LE(p, gflags); + p = WRITE16LE(p, method); + p = WRITE16LE(p, mtime); + p = WRITE16LE(p, mdate); /* 16 */ - PUT32(op, crc); - PUT32(op, compsize); - PUT32(op, uncompsize); - PUT16(op, namesize); -#if 0 -#define CFILE_HDR_SIZE kZipCfileHdrMinSize - PUT16(op, 0); /* extra size */ - /* 32 */ - PUT16(op, commentsize); - PUT16(op, 0); /* disk */ - PUT16(op, iattrs); - PUT16(op, dosmode); - PUT16(op, unixmode); - PUT32(op, 0); /* RELOCATE ME (kZipCfileOffsetOffset) */ - /* 46 */ - memcpy(op, name, namesize); -#else + p = WRITE32LE(p, crc); + p = WRITE32LE(p, compsize); + p = WRITE32LE(p, uncompsize); + p = WRITE16LE(p, namesize); #define CFILE_HDR_SIZE (kZipCfileHdrMinSize + 36) - PUT16(op, 36); /* extra size */ + p = WRITE16LE(p, 36); /* extra size */ /* 32 */ - PUT16(op, commentsize); - PUT16(op, 0); /* disk */ - PUT16(op, iattrs); - PUT32(op, dosmode); - PUT32(op, 0); /* RELOCATE ME (kZipCfileOffsetOffset) */ + p = WRITE16LE(p, commentsize); + p = WRITE16LE(p, 0); /* disk */ + p = WRITE16LE(p, iattrs); + p = WRITE16LE(p, dosmode); + p = WRITE16LE(p, unixmode); + p = WRITE32LE(p, 0); /* RELOCATE ME (kZipCfileOffsetOffset) */ /* 46 */ - memcpy(op, name, namesize); - op += namesize; - PUT16(op, kZipExtraNtfs); - PUT16(op, 32); - PUT32(op, 0); - PUT16(op, 1); - PUT16(op, 24); + memcpy(p, name, namesize); + p += namesize; + p = WRITE16LE(p, kZipExtraNtfs); + p = WRITE16LE(p, 32); + p = WRITE32LE(p, 0); + p = WRITE16LE(p, 1); + p = WRITE16LE(p, 24); #define NTTIME(t) \ (t.tv_sec + MODERNITYSECONDS) * HECTONANOSECONDS + t.tv_nsec / 100 mt = NTTIME(st->st_mtim); at = NTTIME(st->st_atim); ct = NTTIME(st->st_ctim); - PUT64(op, mt); - PUT64(op, at); - PUT64(op, ct); -#endif + p = WRITE64LE(p, mt); + p = WRITE64LE(p, at); + p = WRITE64LE(p, ct); } void EmitZip(struct ElfWriter *elf, const char *name, size_t namesize, @@ -238,15 +237,17 @@ void EmitZip(struct ElfWriter *elf, const char *name, size_t namesize, size_t lfilehdrsize, uncompsize, compsize, commentsize; uint16_t method, gflags, mtime, mdate, iattrs, dosmode; + gflags = 0; + iattrs = 0; compsize = st->st_size; uncompsize = st->st_size; CHECK_LE(uncompsize, UINT32_MAX); lfilehdrsize = kZipLfileHdrMinSize + namesize; crc = crc32_z(0, data, uncompsize); GetDosLocalTime(st->st_mtim.tv_sec, &mtime, &mdate); - gflags = IsPureAscii(name, namesize) ? 0 : kZipGflagUtf8; + if (IsUtf8(name, namesize)) gflags |= kZipGflagUtf8; + if (IsText(data, st->st_size)) iattrs |= kZipIattrText; commentsize = kZipCdirHdrLinkableSize - (CFILE_HDR_SIZE + namesize); - iattrs = IsPureAscii(data, st->st_size) ? kZipIattrAscii : kZipIattrBinary; dosmode = !(st->st_mode & 0200) ? kNtFileAttributeReadonly : 0; method = (st->st_size >= kMinCompressSize && ShouldCompress(name, namesize)) ? kZipCompressionDeflate @@ -280,7 +281,7 @@ void EmitZip(struct ElfWriter *elf, const char *name, size_t namesize, if (method == kZipCompressionNone) { memcpy(lfile + lfilehdrsize, data, uncompsize); } - era = (gflags || method) ? kZipEra1993 : kZipEra1989; + era = method ? kZipEra1993 : kZipEra1989; EmitZipLfileHdr(lfile, name, namesize, crc, era, gflags, method, mtime, mdate, compsize, uncompsize); elfwriter_commit(elf, lfilehdrsize + compsize); diff --git a/tool/decode/lib/zipnames.c b/tool/decode/lib/zipnames.c index 23bb65d28..39f028f7d 100644 --- a/tool/decode/lib/zipnames.c +++ b/tool/decode/lib/zipnames.c @@ -29,13 +29,15 @@ const struct IdName kZipCompressionNames[] = { const struct IdName kZipExtraNames[] = { {kZipExtraZip64, "kZipExtraZip64"}, {kZipExtraNtfs, "kZipExtraNtfs"}, + {kZipExtraUnix, "kZipExtraUnix"}, {kZipExtraExtendedTimestamp, "kZipExtraExtendedTimestamp"}, + {kZipExtraInfoZipNewUnixExtra, "kZipExtraInfoZipNewUnixExtra"}, {0, 0}, }; const struct IdName kZipIattrNames[] = { {kZipIattrBinary, "kZipIattrBinary"}, - {kZipIattrAscii, "kZipIattrAscii"}, + {kZipIattrText, "kZipIattrText"}, {0, 0}, }; diff --git a/tool/decode/zip.c b/tool/decode/zip.c index 3ee9bcb1c..151f74bd6 100644 --- a/tool/decode/zip.c +++ b/tool/decode/zip.c @@ -22,6 +22,7 @@ #include "libc/calls/struct/stat.h" #include "libc/fmt/conv.h" #include "libc/log/check.h" +#include "libc/log/log.h" #include "libc/mem/mem.h" #include "libc/nexgen32e/crc32.h" #include "libc/nt/struct/filetime.h" @@ -45,17 +46,17 @@ * @fileoverview Zip File Disassembler. */ -nodiscard char *formatdosdate(uint16_t dosdate) { +nodiscard char *FormatDosDate(uint16_t dosdate) { return xasprintf("%04u-%02u-%02u", ((dosdate >> 9) & 0b1111111) + 1980, (dosdate >> 5) & 0b1111, dosdate & 0b11111); } -nodiscard char *formatdostime(uint16_t dostime) { +nodiscard char *FormatDosTime(uint16_t dostime) { return xasprintf("%02u:%02u:%02u", (dostime >> 11) & 0b11111, (dostime >> 5) & 0b111111, (dostime << 1) & 0b111110); } -void advancepos(uint8_t *map, size_t *pos, size_t off) { +void AdvancePosition(uint8_t *map, size_t *pos, size_t off) { CHECK_GE(off, *pos); if (off > *pos) { printf("\n/\t<%s>\n", "LIMBO"); @@ -65,7 +66,7 @@ void advancepos(uint8_t *map, size_t *pos, size_t off) { *pos = off; } -void showgeneralflag(uint16_t generalflag) { +void ShowGeneralFlag(uint16_t generalflag) { puts("\ / ┌─utf8\n\ / │ ┌─strong encryption\n\ @@ -77,21 +78,21 @@ void showgeneralflag(uint16_t generalflag) { show(".short", format(b1, "0b%016b", generalflag), "generalflag"); } -void showtimestamp(uint16_t time, uint16_t date) { +void ShowTimestamp(uint16_t time, uint16_t date) { show(".short", format(b1, "%#04hx", time), - gc(xasprintf("%s (%s)", "lastmodifiedtime", gc(formatdostime(time))))); + gc(xasprintf("%s (%s)", "lastmodifiedtime", gc(FormatDosTime(time))))); show(".short", format(b1, "%#04hx", date), - gc(xasprintf("%s (%s)", "lastmodifieddate", gc(formatdosdate(date))))); + gc(xasprintf("%s (%s)", "lastmodifieddate", gc(FormatDosDate(date))))); } -void showcompressmethod(uint16_t compressmethod) { +void ShowCompressionMethod(uint16_t compressmethod) { show(".short", firstnonnull(findnamebyid(kZipCompressionNames, compressmethod), format(b1, "%hu", compressmethod)), "compressionmethod"); } -void showextrantfs(uint8_t *ntfs) { +void ShowNtfs(uint8_t *ntfs, size_t n) { struct timespec mtime, atime, ctime; mtime = FileTimeToTimeSpec( (struct NtFileTime){READ32LE(ntfs + 8), READ32LE(ntfs + 12)}); @@ -115,47 +116,85 @@ void showextrantfs(uint8_t *ntfs) { void ShowExtendedTimestamp(uint8_t *p, size_t n, bool islocal) { int flag; - int64_t x; - struct timespec ts; - flag = *p++; - show(".byte", gc(xasprintf("0b%03hhb", flag)), "fields present in local"); - if (!islocal) { - show(".quad", gc(xasprintf("%u", READ32LE(p))), - gc(xasprintf("%s (%s)", "last modified", gc(xiso8601(&ts))))); - } else { - if (flag & 1) { - ts = (struct timespec){READ32LE(p)}; - show(".quad", gc(xasprintf("%u", READ32LE(p))), - gc(xasprintf("%s (%s)", "last modified", gc(xiso8601(&ts))))); + if (n) { + --n; + flag = *p++; + show(".byte", gc(xasprintf("0b%03hhb", flag)), "fields present in local"); + if ((flag & 1) && n >= 4) { + show(".long", gc(xasprintf("%u", READ32LE(p))), + gc(xasprintf("%s (%s)", "last modified", + gc(xiso8601(&(struct timespec){READ32LE(p)}))))); p += 4; + n -= 4; } flag >>= 1; - if (flag & 1) { - ts = (struct timespec){READ32LE(p)}; - show(".quad", gc(xasprintf("%u", READ32LE(p))), - gc(xasprintf("%s (%s)", "access time", gc(xiso8601(&ts))))); - p += 4; - } - flag >>= 1; - if (flag & 1) { - ts = (struct timespec){READ32LE(p)}; - show(".quad", gc(xasprintf("%u", READ32LE(p))), - gc(xasprintf("%s (%s)", "creation time", gc(xiso8601(&ts))))); + if (islocal) { + if ((flag & 1) && n >= 4) { + show(".long", gc(xasprintf("%u", READ32LE(p))), + gc(xasprintf("%s (%s)", "access time", + gc(xiso8601(&(struct timespec){READ32LE(p)}))))); + p += 4; + n -= 4; + } + flag >>= 1; + if ((flag & 1) && n >= 4) { + show(".long", gc(xasprintf("%u", READ32LE(p))), + gc(xasprintf("%s (%s)", "creation time", + gc(xiso8601(&(struct timespec){READ32LE(p)}))))); + p += 4; + n -= 4; + } } } } -void showextra(uint8_t *extra, bool islocal) { +void ShowZip64(uint8_t *p, size_t n, bool islocal) { + if (n >= 8) { + show(".quad", gc(xasprintf("%lu", READ64LE(p))), + gc(xasprintf("uncompressed size (%,ld)", READ64LE(p)))); + } + if (n >= 16) { + show(".quad", gc(xasprintf("%lu", READ64LE(p + 8))), + gc(xasprintf("compressed size (%,ld)", READ64LE(p + 8)))); + } + if (n >= 24) { + show(".quad", gc(xasprintf("%lu", READ64LE(p + 16))), + gc(xasprintf("lfile hdr offset (%,ld)", READ64LE(p + 16)))); + } + if (n >= 28) { + show(".long", gc(xasprintf("%u", READ32LE(p + 24))), "disk number"); + } +} + +void ShowInfoZipNewUnixExtra(uint8_t *p, size_t n, bool islocal) { + if (p[0] == 1 && p[1] == 4 && p[6] == 4) { + show(".byte", "1", "version"); + show(".byte", "4", "uid length"); + show(".long", gc(xasprintf("%u", READ32LE(p + 2))), "uid"); + show(".byte", "4", "gid length"); + show(".long", gc(xasprintf("%u", READ32LE(p + 7))), "gid"); + } else { + disassemblehex(p, n, stdout); + } +} + +void ShowExtra(uint8_t *extra, bool islocal) { switch (ZIP_EXTRA_HEADERID(extra)) { case kZipExtraNtfs: - showextrantfs(ZIP_EXTRA_CONTENT(extra)); + ShowNtfs(ZIP_EXTRA_CONTENT(extra), ZIP_EXTRA_CONTENTSIZE(extra)); break; case kZipExtraExtendedTimestamp: ShowExtendedTimestamp(ZIP_EXTRA_CONTENT(extra), ZIP_EXTRA_CONTENTSIZE(extra), islocal); break; case kZipExtraZip64: - /* TODO */ + ShowZip64(ZIP_EXTRA_CONTENT(extra), ZIP_EXTRA_CONTENTSIZE(extra), + islocal); + break; + case kZipExtraInfoZipNewUnixExtra: + ShowInfoZipNewUnixExtra(ZIP_EXTRA_CONTENT(extra), + ZIP_EXTRA_CONTENTSIZE(extra), islocal); + break; default: disassemblehex(ZIP_EXTRA_CONTENT(extra), ZIP_EXTRA_CONTENTSIZE(extra), stdout); @@ -163,7 +202,7 @@ void showextra(uint8_t *extra, bool islocal) { } } -void showexternalattributes(uint8_t *cf) { +void ShowExternalAttributes(uint8_t *cf) { uint32_t ea; ea = ZIP_CFILE_EXTERNALATTRIBUTES(cf); if (ZIP_CFILE_FILEATTRCOMPAT(cf) == kZipOsUnix) { @@ -175,7 +214,7 @@ void showexternalattributes(uint8_t *cf) { } } -void showextras(uint8_t *extras, uint16_t extrassize, bool islocal) { +void ShowExtras(uint8_t *extras, uint16_t extrassize, bool islocal) { int i; bool first; uint8_t *p, *pe; @@ -194,14 +233,14 @@ void showextras(uint8_t *extras, uint16_t extrassize, bool islocal) { first = false; printf("%d:", (i + 1) * 10); } - showextra(p, islocal); + ShowExtra(p, islocal); printf("%d:", (i + 2) * 10); } } putchar('\n'); } -void showlocalfileheader(uint8_t *lf, uint16_t idx) { +void ShowLocalFileHeader(uint8_t *lf, uint16_t idx) { printf("\n/\t%s #%hu (%zu %s)\n", "local file", idx + 1, ZIP_LFILE_HDRSIZE(lf), "bytes"); show(".ascii", format(b1, "%`'.*s", 4, lf), "magic"); @@ -213,17 +252,23 @@ void showlocalfileheader(uint8_t *lf, uint16_t idx) { firstnonnull(findnamebyid(kZipOsNames, ZIP_LFILE_OSNEED(lf)), gc(xasprintf("%d", ZIP_LFILE_OSNEED(lf)))), "os need"); - showgeneralflag(ZIP_LFILE_GENERALFLAG(lf)); - showcompressmethod(ZIP_LFILE_COMPRESSIONMETHOD(lf)); - showtimestamp(ZIP_LFILE_LASTMODIFIEDTIME(lf), ZIP_LFILE_LASTMODIFIEDDATE(lf)); - show(".long", format(b1, "%#x", ZIP_LFILE_CRC32(lf)), - gc(xasprintf( - "%s (%#x)", "crc32z", - crc32_z(0, ZIP_LFILE_CONTENT(lf), ZIP_LFILE_COMPRESSEDSIZE(lf))))); - show(".long", "3f-2f", - format(b1, "%s (%u %s)", "compressedsize", ZIP_LFILE_COMPRESSEDSIZE(lf), - "bytes")); - show(".long", format(b1, "%u", ZIP_LFILE_UNCOMPRESSEDSIZE(lf)), + ShowGeneralFlag(ZIP_LFILE_GENERALFLAG(lf)); + ShowCompressionMethod(ZIP_LFILE_COMPRESSIONMETHOD(lf)); + ShowTimestamp(ZIP_LFILE_LASTMODIFIEDTIME(lf), ZIP_LFILE_LASTMODIFIEDDATE(lf)); + show( + ".long", + format(b1, "%#x", ZIP_LFILE_CRC32(lf)), gc(xasprintf("%s (%#x)", "crc32z", GetZipLfileCompressedSize(lf) /* crc32_z(0, ZIP_LFILE_CONTENT(lf), GetZipLfileCompressedSize(lf)) */))); + if (ZIP_LFILE_COMPRESSEDSIZE(lf) == 0xFFFFFFFF) { + show(".long", "0xFFFFFFFF", "compressedsize (zip64)"); + } else { + show(".long", "3f-2f", + format(b1, "%s (%u %s)", "compressedsize", + ZIP_LFILE_COMPRESSEDSIZE(lf), "bytes")); + } + show(".long", + ZIP_LFILE_UNCOMPRESSEDSIZE(lf) == 0xFFFFFFFF + ? "0xFFFFFFFF" + : format(b1, "%u", ZIP_LFILE_UNCOMPRESSEDSIZE(lf)), "uncompressedsize"); show(".short", "1f-0f", format(b1, "%s (%hu %s)", "namesize", ZIP_LFILE_NAMESIZE(lf), "bytes")); @@ -236,17 +281,19 @@ void showlocalfileheader(uint8_t *lf, uint16_t idx) { gc(strndup(ZIP_LFILE_NAME(lf), ZIP_LFILE_NAMESIZE(lf)))), "name"); printf("1:"); - showextras(ZIP_LFILE_EXTRA(lf), ZIP_LFILE_EXTRASIZE(lf), true); + ShowExtras(ZIP_LFILE_EXTRA(lf), ZIP_LFILE_EXTRASIZE(lf), true); printf("2:"); - disassemblehex(ZIP_LFILE_CONTENT(lf), ZIP_LFILE_COMPRESSEDSIZE(lf), stdout); + /* disassemblehex(ZIP_LFILE_CONTENT(lf), ZIP_LFILE_COMPRESSEDSIZE(lf), + * stdout); */ printf("3:\n"); } -void showcentralfileheader(uint8_t *cf) { +void ShowCentralFileHeader(uint8_t *cf) { printf("\n/\t%s (%zu %s)\n", "central directory file header", ZIP_CFILE_HDRSIZE(cf), "bytes"); show(".ascii", format(b1, "%`'.*s", 4, cf), "magic"); - show(".byte", gc(xasprintf("%d", ZIP_CFILE_VERSIONMADE(cf))), "version made"); + show(".byte", gc(xasprintf("%d", ZIP_CFILE_VERSIONMADE(cf))), + "zip version made"); show(".byte", firstnonnull(findnamebyid(kZipOsNames, ZIP_CFILE_FILEATTRCOMPAT(cf)), gc(xasprintf("%d", ZIP_CFILE_FILEATTRCOMPAT(cf)))), @@ -259,14 +306,22 @@ void showcentralfileheader(uint8_t *cf) { firstnonnull(findnamebyid(kZipOsNames, ZIP_CFILE_OSNEED(cf)), gc(xasprintf("%d", ZIP_CFILE_OSNEED(cf)))), "os need"); - showgeneralflag(ZIP_CFILE_GENERALFLAG(cf)); - showcompressmethod(ZIP_CFILE_COMPRESSIONMETHOD(cf)); - showtimestamp(ZIP_CFILE_LASTMODIFIEDTIME(cf), ZIP_CFILE_LASTMODIFIEDDATE(cf)); + ShowGeneralFlag(ZIP_CFILE_GENERALFLAG(cf)); + ShowCompressionMethod(ZIP_CFILE_COMPRESSIONMETHOD(cf)); + ShowTimestamp(ZIP_CFILE_LASTMODIFIEDTIME(cf), ZIP_CFILE_LASTMODIFIEDDATE(cf)); show(".long", format(b1, "%#x", ZIP_CFILE_CRC32(cf)), "crc32z"); - show(".long", format(b1, "%u", ZIP_CFILE_COMPRESSEDSIZE(cf)), - "compressedsize"); - show(".long", format(b1, "%u", ZIP_CFILE_UNCOMPRESSEDSIZE(cf)), - "uncompressedsize"); + if (ZIP_CFILE_COMPRESSEDSIZE(cf) == 0xFFFFFFFF) { + show(".long", "0xFFFFFFFF", "compressedsize (zip64)"); + } else { + show(".long", format(b1, "%u", ZIP_CFILE_COMPRESSEDSIZE(cf)), + "compressedsize"); + } + if (ZIP_CFILE_UNCOMPRESSEDSIZE(cf) == 0xFFFFFFFF) { + show(".long", "0xFFFFFFFF", "compressedsize (zip64)"); + } else { + show(".long", format(b1, "%u", ZIP_CFILE_UNCOMPRESSEDSIZE(cf)), + "uncompressedsize"); + } show(".short", "1f-0f", format(b1, "%s (%hu %s)", "namesize", ZIP_CFILE_NAMESIZE(cf), "bytes")); show( @@ -277,23 +332,29 @@ void showcentralfileheader(uint8_t *cf) { "bytes")); show(".short", format(b1, "%hu", ZIP_CFILE_DISK(cf)), "disk"); show(".short", - RecreateFlags(kZipIattrNames, ZIP_CFILE_INTERNALATTRIBUTES(cf)), + RecreateFlags(kZipIattrNames, ZIP_CFILE_INTERNALATTRIBUTES(cf) & 1), "internalattributes"); - showexternalattributes(cf); - show(".long", format(b1, "%u", ZIP_CFILE_OFFSET(cf)), "lfile hdr offset"); + ShowExternalAttributes(cf); + if (ZIP_CFILE_OFFSET(cf) == 0xFFFFFFFF) { + show(".long", "0xFFFFFFFF", "lfile hdr offset (zip64)"); + } else { + show(".long", format(b1, "%u", ZIP_CFILE_OFFSET(cf)), "lfile hdr offset"); + } printf("0:"); show(".ascii", format(b1, "%`'s", gc(strndup(ZIP_CFILE_NAME(cf), ZIP_CFILE_NAMESIZE(cf)))), "name"); printf("1:"); - showextras(ZIP_CFILE_EXTRA(cf), ZIP_CFILE_EXTRASIZE(cf), false); + ShowExtras(ZIP_CFILE_EXTRA(cf), ZIP_CFILE_EXTRASIZE(cf), false); printf("2:"); - disassemblehex(ZIP_CFILE_COMMENT(cf), ZIP_CFILE_COMMENTSIZE(cf), stdout); + show(".ascii", + format(b1, "%`'.*s", ZIP_CFILE_COMMENTSIZE(cf), ZIP_CFILE_COMMENT(cf)), + "comment"); printf("3:\n"); } -void showcentraldirheader(uint8_t *cd) { +void ShowCentralDirHeader32(uint8_t *cd) { printf("\n/\t%s (%zu %s)\n", "end of central directory header", ZIP_CDIR_HDRSIZE(cd), "bytes"); show(".ascii", format(b1, "%`'.*s", 4, cd), "magic"); @@ -312,39 +373,116 @@ void showcentraldirheader(uint8_t *cd) { printf("1:\n"); } -void disassemblezip(uint8_t *map, size_t mapsize) { +void ShowCentralDirHeader64(uint8_t *cd) { + printf("\n/\t%s (%zu %s)\n", "zip64 end of central directory header", + ZIP_CDIR64_HDRSIZE(cd), "bytes"); + show(".ascii", format(b1, "%`'.*s", 4, cd), "magic"); + show(".quad", format(b1, "%lu", ZIP_CDIR64_HDRSIZE(cd) - 12), "hdr size"); + show(".short", format(b1, "%hd", ZIP_CDIR64_VERSIONMADE(cd)), "version made"); + show(".short", format(b1, "%hd", ZIP_CDIR64_VERSIONNEED(cd)), "version need"); + show(".long", format(b1, "%d", ZIP_CDIR64_DISK(cd)), "disk"); + show(".long", format(b1, "%d", ZIP_CDIR64_STARTINGDISK(cd)), "startingdisk"); + show(".quad", format(b1, "%lu", ZIP_CDIR64_RECORDSONDISK(cd)), + "recordsondisk"); + show(".quad", format(b1, "%lu", ZIP_CDIR64_RECORDS(cd)), "records"); + show(".quad", format(b1, "%lu", ZIP_CDIR64_SIZE(cd)), "cdir size"); + show(".quad", format(b1, "%lu", ZIP_CDIR64_OFFSET(cd)), "cdir offset"); + printf("0:"); + disassemblehex(ZIP_CDIR64_COMMENT(cd), ZIP_CDIR64_COMMENTSIZE(cd), stdout); + printf("1:\n"); +} + +uint8_t *GetZipCdir32(const uint8_t *p, size_t n) { + size_t i; + if (n >= kZipCdirHdrMinSize) { + i = n - kZipCdirHdrMinSize; + do { + if (READ32LE(p + i) == kZipCdirHdrMagic && IsZipCdir32(p, n, i)) { + return (/*unconst*/ uint8_t *)(p + i); + } + } while (i--); + } + return NULL; +} + +uint8_t *GetZipCdir64(const uint8_t *p, size_t n) { + size_t i; + if (n >= kZipCdir64HdrMinSize) { + i = n - kZipCdir64HdrMinSize; + do { + if (READ32LE(p + i) == kZipCdir64HdrMagic && IsZipCdir64(p, n, i)) { + return (/*unconst*/ uint8_t *)(p + i); + } + } while (i--); + } + return NULL; +} + +void DisassembleZip(const char *path, uint8_t *p, size_t n) { size_t pos; uint16_t i; static int records; - uint8_t *cd, *cf, *lf; - CHECK_NOTNULL((cd = zipfindcentraldir(map, mapsize))); + uint8_t *eocd32, *eocd64, *cdir, *cf, *lf, *q; + if (endswith(path, ".com.dbg") && (q = memmem(p, n, "MZqFpD", 6))) { + n -= q - p; + p += q - p; + } + eocd32 = GetZipCdir32(p, n); + eocd64 = GetZipCdir64(p, n); + CHECK(eocd32 || eocd64); pos = 0; - records = ZIP_CDIR_RECORDS(cd); - for (i = 0, cf = map + ZIP_CDIR_OFFSET(cd); i < records; - ++i, cf += ZIP_CFILE_HDRSIZE(cf)) { - lf = map + ZIP_CFILE_OFFSET(cf); + if (eocd64) { + records = ZIP_CDIR64_RECORDS(eocd64); + cdir = p + ZIP_CDIR64_OFFSET(eocd64); + } else { + records = ZIP_CDIR_RECORDS(eocd32); + cdir = p + ZIP_CDIR_OFFSET(eocd32); + } + for (i = 0, cf = cdir; i < records; ++i, cf += ZIP_CFILE_HDRSIZE(cf)) { + lf = p + GetZipCfileOffset(cf); CHECK_EQ(kZipLfileHdrMagic, ZIP_LFILE_MAGIC(lf)); - advancepos(map, &pos, lf - map); - showlocalfileheader(lf, i); - pos = (lf - map) + ZIP_LFILE_SIZE(lf); + AdvancePosition(p, &pos, lf - p); + ShowLocalFileHeader(lf, i); + pos = (lf - p) + ZIP_LFILE_SIZE(lf); } - for (i = 0, cf = map + ZIP_CDIR_OFFSET(cd); i < records; - ++i, cf += ZIP_CFILE_HDRSIZE(cf)) { + for (i = 0, cf = cdir; i < records; ++i, cf += ZIP_CFILE_HDRSIZE(cf)) { CHECK_EQ(kZipCfileHdrMagic, ZIP_CFILE_MAGIC(cf)); - advancepos(map, &pos, cf - map); - showcentralfileheader(cf); - pos = (cf - map) + ZIP_CFILE_HDRSIZE(cf); + AdvancePosition(p, &pos, cf - p); + ShowCentralFileHeader(cf); + pos = (cf - p) + ZIP_CFILE_HDRSIZE(cf); } - advancepos(map, &pos, cd - map); - showcentraldirheader(cd); - pos = (cd - map) + ZIP_CDIR_HDRSIZE(cd); - advancepos(map, &pos, mapsize); + if (eocd32 && eocd64) { + if (eocd32 < eocd64) { + ShowCentralDirHeader32(eocd32); + AdvancePosition(p, &pos, eocd32 - p); + ShowCentralDirHeader64(eocd64); + AdvancePosition(p, &pos, eocd64 - p); + } else { + ShowCentralDirHeader64(eocd64); + AdvancePosition(p, &pos, eocd64 - p); + ShowCentralDirHeader32(eocd32); + AdvancePosition(p, &pos, eocd32 - p); + } + } else if (eocd32) { + ShowCentralDirHeader32(eocd32); + AdvancePosition(p, &pos, eocd32 - p); + } else { + ShowCentralDirHeader64(eocd64); + AdvancePosition(p, &pos, eocd64 - p); + } + if (!eocd64 || eocd32 > eocd64) { + pos = eocd32 - p + ZIP_CDIR_HDRSIZE(eocd32); + } else { + pos = eocd64 - p + ZIP_CDIR_HDRSIZE(eocd64); + } + AdvancePosition(p, &pos, n); } int main(int argc, char *argv[]) { int fd; uint8_t *map; struct stat st; + showcrashreports(); CHECK_EQ(2, argc); CHECK_NE(-1, (fd = open(argv[1], O_RDONLY))); CHECK_NE(-1, fstat(fd, &st)); @@ -353,7 +491,7 @@ int main(int argc, char *argv[]) { (map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0))); showtitle("αcτµαlly pδrταblε εxεcµταblε", "tool/decode/zip", basename(argv[1]), NULL, &kModelineAsm); - disassemblezip(map, st.st_size); + DisassembleZip(argv[1], map, st.st_size); CHECK_NE(-1, munmap(map, st.st_size)); CHECK_NE(-1, close(fd)); return 0; diff --git a/tool/net/.init.lua b/tool/net/.init.lua index 080402535..778f344ec 100644 --- a/tool/net/.init.lua +++ b/tool/net/.init.lua @@ -1,3 +1,2 @@ -- special script called by main redbean process at startup -ProgramRedirect(0, '/favicon.ico', '/tool/net/redbean.ico') HidePath('/usr/share/zoneinfo/') diff --git a/tool/net/redbean.ico b/tool/net/favicon.ico similarity index 100% rename from tool/net/redbean.ico rename to tool/net/favicon.ico diff --git a/tool/net/redbean.html b/tool/net/index.html similarity index 86% rename from tool/net/redbean.html rename to tool/net/index.html index c7f6fe5b8..8cca37ed7 100644 --- a/tool/net/redbean.html +++ b/tool/net/index.html @@ -1,8 +1,8 @@ redbean - - + +

redbean
diff --git a/tool/net/net.mk b/tool/net/net.mk index 8bd0dd324..a7385f5b7 100644 --- a/tool/net/net.mk +++ b/tool/net/net.mk @@ -63,20 +63,35 @@ o/$(MODE)/tool/net/%.com.dbg: \ o/$(MODE)/tool/net/redbean.com.dbg: \ $(TOOL_NET_DEPS) \ o/$(MODE)/tool/net/redbean.o \ - o/$(MODE)/tool/net/redbean.ico.zip.o \ - o/$(MODE)/tool/net/redbean.png.zip.o \ - o/$(MODE)/tool/net/redbean.css.zip.o \ - o/$(MODE)/tool/net/redbean.html.zip.o \ - o/$(MODE)/tool/net/redbean.lua.zip.o \ - o/$(MODE)/tool/net/redbean-form.lua.zip.o \ - o/$(MODE)/tool/net/redbean-xhr.lua.zip.o \ - o/$(MODE)/tool/net/.init.lua.zip.o \ - o/$(MODE)/tool/net/.reload.lua.zip.o \ o/$(MODE)/tool/net/net.pkg \ $(CRT) \ $(APE) @$(APELINK) +o/$(MODE)/tool/net/redbean.com: \ + o/$(MODE)/tool/net/redbean.com.dbg \ + tool/net/favicon.ico \ + tool/net/redbean.png \ + tool/net/.init.lua \ + tool/net/.reload.lua + @$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@ + @$(COMPILE) -ADD -T$@ dd if=$@ of=o/$(MODE)/tool/net/.ape bs=64 count=11 conv=notrunc 2>/dev/null + @$(COMPILE) -AZIP -T$@ zip -qj $@ o/$(MODE)/tool/net/.ape tool/net/.init.lua tool/net/.reload.lua tool/net/favicon.ico tool/net/redbean.png + +o/$(MODE)/tool/net/redbean-demo.com: \ + o/$(MODE)/tool/net/redbean.com \ + tool/net/redbean.mk \ + tool/net/index.html \ + tool/net/redbean.css \ + tool/net/redbean.lua \ + tool/net/redbean-form.lua \ + tool/net/redbean-xhr.lua \ + $(TOOL_NET_HDRS) \ + $(TOOL_NET_SRCS) + @$(COMPILE) -ACP -T$@ cp $< $@ + @$(COMPILE) -AZIP -T$@ zip -qj $@ tool/net/redbean.lua tool/net/redbean-form.lua tool/net/redbean-xhr.lua + @$(COMPILE) -AZIP -T$@ zip -q $@ tool/net tool/net/index.html tool/net/redbean.css $(TOOL_NET_HDRS) $(TOOL_NET_SRCS) + .PHONY: o/$(MODE)/tool/net o/$(MODE)/tool/net: \ $(TOOL_NET_BINS) \ diff --git a/tool/net/redbean-form.lua b/tool/net/redbean-form.lua index 5b8f03855..257df6b1c 100644 --- a/tool/net/redbean-form.lua +++ b/tool/net/redbean-form.lua @@ -63,7 +63,7 @@ local function main() Write('\n') Write('

') - Write('Click here ') + Write('Click here ') Write('to return to the previous page.\n') end diff --git a/tool/net/redbean-xhr.lua b/tool/net/redbean-xhr.lua index cd93d5d4e..a2daf44d1 100644 --- a/tool/net/redbean-xhr.lua +++ b/tool/net/redbean-xhr.lua @@ -1,3 +1,8 @@ -- redbean xhr handler demo -SetHeader('Vary', 'X-Custom-Header') -SetHeader('X-Custom-Header', 'hello ' .. GetHeader('x-custom-header')) +hdr = GetHeader('x-custom-header') +if hdr then + SetHeader('Vary', 'X-Custom-Header') + SetHeader('X-Custom-Header', 'hello ' .. hdr) +else + ServeError(400) +end diff --git a/tool/net/redbean.c b/tool/net/redbean.c index 8d91e634c..9fefc6111 100644 --- a/tool/net/redbean.c +++ b/tool/net/redbean.c @@ -23,6 +23,7 @@ #include "libc/calls/calls.h" #include "libc/calls/struct/iovec.h" #include "libc/calls/struct/itimerval.h" +#include "libc/calls/struct/rusage.h" #include "libc/calls/struct/stat.h" #include "libc/calls/weirdtypes.h" #include "libc/dce.h" @@ -39,7 +40,9 @@ #include "libc/nexgen32e/bsf.h" #include "libc/nexgen32e/bsr.h" #include "libc/nexgen32e/crc32.h" +#include "libc/nt/synchronization.h" #include "libc/rand/rand.h" +#include "libc/runtime/clktck.h" #include "libc/runtime/runtime.h" #include "libc/sock/sock.h" #include "libc/stdio/stdio.h" @@ -58,8 +61,11 @@ #include "libc/sysv/consts/ipproto.h" #include "libc/sysv/consts/itimer.h" #include "libc/sysv/consts/map.h" +#include "libc/sysv/consts/mlock.h" +#include "libc/sysv/consts/msync.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/prot.h" +#include "libc/sysv/consts/s.h" #include "libc/sysv/consts/sa.h" #include "libc/sysv/consts/shut.h" #include "libc/sysv/consts/sig.h" @@ -77,6 +83,7 @@ #include "net/http/base64.h" #include "net/http/escape.h" #include "net/http/http.h" +#include "net/http/url.h" #include "third_party/getopt/getopt.h" #include "third_party/lua/lauxlib.h" #include "third_party/lua/ltests.h" @@ -151,12 +158,19 @@ USAGE\n\ redbean imposes a 32kb limit on requests to limit the memory of\n\ connection processes, which grow to whatever number your system\n\ limits and tcp stack configuration allow. If fork() should fail\n\ - then redbean starts shutting idle connections down.\n\ + or accept runs out of file descriptors, then redbean will react\n\ + by closing idle connections, while sending out 503 responses in\n\ + the meantime from the main process. That way if you have a load\n\ + balancer with multiple instances, failover will happen quickly.\n\ \n" #define HASH_LOAD_FACTOR /* 1. / */ 4 #define DEFAULT_PORT 8080 +#define HeaderEqual(H, S) \ + SlicesEqual(S, strlen(S), inbuf.p + msg.headers[H].a, \ + msg.headers[H].b - msg.headers[H].a) + static const struct itimerval kHeartbeat = { {0, 500000}, {0, 500000}, @@ -175,25 +189,6 @@ static const uint8_t kGzipHeader[] = { kZipOsUnix, // OS }; -static const char kHexToInt[256] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x00 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x10 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x20 - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, // 0x30 - 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x40 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x50 - 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x60 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x70 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x80 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x90 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xa0 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xb0 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xc0 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xd0 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xe0 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xf0 -}; - static const struct ContentTypeExtension { unsigned char ext[8]; const char *mime; @@ -245,33 +240,8 @@ struct Strings { char **p; }; -struct Parser { - int i; - int c; - const char *data; - int size; - bool isform; - bool islatin1; - char *p; - char *q; -}; - -struct Params { - size_t n; - struct Param { - struct Buffer key; - struct Buffer val; // val.n may be SIZE_MAX - } * p; -}; - -struct Request { - struct Buffer path; - struct Params params; - struct Buffer fragment; -}; - static struct Freelist { - size_t n; + size_t n, c; void **p; } freelist; @@ -288,8 +258,10 @@ static struct Redirects { static struct Assets { uint32_t n; struct Asset { - uint32_t lf; + bool istext; uint32_t hash; + uint64_t cf; + uint64_t lf; int64_t lastmodified; char *lastmodifiedstr; struct File { @@ -300,7 +272,8 @@ static struct Assets { } assets; static struct Shared { - int workers; // + int workers; + long requestshandled; } * shared; static bool killed; @@ -309,7 +282,6 @@ static bool zombied; static bool gzipped; static bool branded; static bool meltdown; -static bool unbranded; static bool heartless; static bool printport; static bool heartbeat; @@ -331,13 +303,14 @@ static int client; static int daemonuid; static int daemongid; static int statuscode; -static unsigned httpversion; +static int httpversion; +static int requestshandled; static uint32_t clientaddrsize; static lua_State *L; static size_t zsize; static void *content; -static uint8_t *zdir; +static uint8_t *cdir; static uint8_t *zmap; static size_t hdrsize; static size_t msgsize; @@ -355,14 +328,14 @@ static const char *serverheader; static struct Strings stagedirs; static struct Strings hidepaths; -static struct Buffer logo; +static struct Url request; static struct Buffer inbuf; static struct Buffer hdrbuf; static struct Buffer outbuf; -static struct Request request; static long double nowish; static long double startread; +static long double startserver; static long double lastmeltdown; static long double startrequest; static long double startconnection; @@ -427,6 +400,14 @@ static int CompareSlicesCase(const char *a, size_t n, const char *b, size_t m) { return 0; } +static bool SlicesEqual(const char *a, size_t n, const char *b, size_t m) { + return n == m && !CompareSlices(a, n, b, m); +} + +static bool SlicesEqualCase(const char *a, size_t n, const char *b, size_t m) { + return n == m && !CompareSlicesCase(a, n, b, m); +} + static long FindRedirect(const char *path, size_t n) { int c, m, l, r, z; l = 0; @@ -489,7 +470,7 @@ static int CompareInts(const uint64_t x, uint64_t y) { return x > y ? 1 : x < y ? -1 : 0; } -static const char *FindContentType(uint64_t ext) { +static const char *BisectContentType(uint64_t ext) { int c, m, l, r; l = 0; r = ARRAYLEN(kContentTypeExtension) - 1; @@ -507,7 +488,7 @@ static const char *FindContentType(uint64_t ext) { return NULL; } -static const char *GetContentType2(const char *path, size_t n) { +static const char *FindContentType(const char *path, size_t n) { size_t i; uint64_t x; const char *p, *r; @@ -516,7 +497,7 @@ static const char *GetContentType2(const char *path, size_t n) { x <<= 8; x |= path[i] & 0xFF; } - if ((r = FindContentType(bswap_64(x)))) { + if ((r = BisectContentType(bswap_64(x)))) { return r; } } @@ -525,14 +506,14 @@ static const char *GetContentType2(const char *path, size_t n) { static const char *GetContentType(struct Asset *a, const char *path, size_t n) { const char *r; - if (a->file && (r = GetContentType2(a->file->path, strlen(a->file->path)))) { + if (a->file && (r = FindContentType(a->file->path, strlen(a->file->path)))) { return r; } return firstnonnull( - GetContentType2(path, n), - firstnonnull(GetContentType2(ZIP_LFILE_NAME(zmap + a->lf), + FindContentType(path, n), + firstnonnull(FindContentType(ZIP_LFILE_NAME(zmap + a->lf), ZIP_LFILE_NAMESIZE(zmap + a->lf)), - "application/octet-stream")); + a->istext ? "text/plain" : "application/octet-stream")); } static void DescribeAddress(char buf[32], const struct sockaddr_in *addr) { @@ -550,7 +531,6 @@ static void ProgramBrand(const char *s) { free(brand); free(serverheader); brand = strdup(s); - if (!strstr(s, "redbean")) unbranded = true; if (!(serverheader = EncodeHttpHeaderValue(brand, -1, 0))) { fprintf(stderr, "error: brand isn't latin1 encodable: %`'s", brand); exit(1); @@ -566,7 +546,7 @@ static void ProgramPort(long x) { } static void SetDefaults(void) { - ProgramBrand("redbean/0.3"); + ProgramBrand("redbean/0.4"); ProgramCache(-1); ProgramPort(DEFAULT_PORT); serveraddr.sin_family = AF_INET; @@ -594,8 +574,8 @@ static void AddString(struct Strings *l, char *s) { static void AddStagingDirectory(const char *dirpath) { char *s; s = RemoveTrailingSlashes(strdup(dirpath)); - if (!isdirectory(s)) { - fprintf(stderr, "error: not a directory: %s\n", s); + if (!*s || !isdirectory(s)) { + fprintf(stderr, "error: not a directory: %`'s\n", s); exit(1); } AddString(&stagedirs, s); @@ -691,27 +671,85 @@ static void Daemonize(void) { LOGIFNEG1(setgid(daemongid)); } -static void OnWorkerExit(int pid, int ws) { - int w; - w = --shared->workers; +static void ReportWorkerExit(int pid, int ws) { + --shared->workers; if (WIFEXITED(ws)) { if (WEXITSTATUS(ws)) { - WARNF("worker %d exited with %d (%,d workers remain)", pid, - WEXITSTATUS(ws), w); + WARNF("%d exited with %d (%,d workers remain)", pid, WEXITSTATUS(ws), + shared->workers); } else { - DEBUGF("worker %d exited (%,d workers remain)", pid, w); + DEBUGF("%d exited (%,d workers remain)", pid, shared->workers); } } else { - WARNF("worker %d terminated with %s (%,d workers remain)", pid, - strsignal(WTERMSIG(ws)), w); + WARNF("%d terminated with %s (%,d workers remain)", pid, + strsignal(WTERMSIG(ws)), shared->workers); + } +} + +static void ReportWorkerResources(int pid, struct rusage *ru) { + long utime, stime; + long double ticks; + /* + * NetBSD accounting literally uses calculus. + * OpenBSD and XNU are pretty good. + * Linux and FreeBSD track less. + */ + if (ru->ru_maxrss) { + DEBUGF("%d ballooned to %,ldkb of memory", pid, ru->ru_maxrss); + } + if ((utime = ru->ru_utime.tv_sec * 1000000 + ru->ru_utime.tv_usec) | + (stime = ru->ru_stime.tv_sec * 1000000 + ru->ru_stime.tv_usec)) { + ticks = ceill((long double)(utime + stime) / (1000000.L / CLK_TCK)); + DEBUGF("%d needed %,ldµs of cpu (%d%% kernel)", pid, utime + stime, + (int)((long double)utime / (utime + stime) * 100)); + if (ru->ru_idrss) { + DEBUGF("%d needed %,ldkb of memory on average", pid, + lroundl(ru->ru_idrss / ticks)); + } + if (ru->ru_isrss) { + DEBUGF("%d needed %,ldkb of stack memory on average", pid, + lroundl(ru->ru_isrss / ticks)); + } + if (ru->ru_ixrss) { + DEBUGF("%d mapped %,ldkb of shared memory on average", pid, + lroundl(ru->ru_ixrss / ticks)); + } + } + if (ru->ru_minflt || ru->ru_majflt) { + DEBUGF("%d caused %,ld page faults (%d%% memcpy)", pid, + ru->ru_minflt + ru->ru_majflt, + (int)((long double)ru->ru_minflt / (ru->ru_minflt + ru->ru_majflt) * + 100)); + } + if (ru->ru_nvcsw + ru->ru_nivcsw > 1) { + DEBUGF("%d triggered %,ld context switches (%d%% consensual)", pid, + ru->ru_nvcsw + ru->ru_nivcsw, + (int)((long double)ru->ru_nvcsw / (ru->ru_nvcsw + ru->ru_nivcsw) * + 100)); + } + if (ru->ru_inblock || ru->ru_oublock) { + DEBUGF("%d performed %,ld read and %,ld write i/o operations", pid, + ru->ru_inblock, ru->ru_oublock); + } + if (ru->ru_msgrcv || ru->ru_msgsnd) { + DEBUGF("%d received %,ld message and sent %,ld", pid, ru->ru_msgrcv, + ru->ru_msgsnd); + } + if (ru->ru_nsignals) { + DEBUGF("%d received %,ld signals", pid, ru->ru_nsignals); + } + if (ru->ru_nswap) { + DEBUGF("%d got swapped %,ld times", pid, ru->ru_nswap); } } static void WaitAll(void) { int ws, pid; + struct rusage ru; for (;;) { - if ((pid = wait(&ws)) != -1) { - OnWorkerExit(pid, ws); + if ((pid = wait4(-1, &ws, 0, &ru)) != -1) { + ReportWorkerExit(pid, ws); + ReportWorkerResources(pid, &ru); } else { if (errno == ECHILD) break; if (errno == EINTR) { @@ -730,11 +768,13 @@ static void WaitAll(void) { static void ReapZombies(void) { int ws, pid; - zombied = false; + struct rusage ru; do { - if ((pid = waitpid(-1, &ws, WNOHANG)) != -1) { + zombied = false; + if ((pid = wait4(-1, &ws, WNOHANG, &ru)) != -1) { if (pid) { - OnWorkerExit(pid, ws); + ReportWorkerExit(pid, ws); + ReportWorkerResources(pid, &ru); } else { break; } @@ -782,16 +822,7 @@ static uint32_t Hash(const void *data, size_t size) { } static bool HasHeader(int h) { - return msg.headers[h].b > msg.headers[h].a; -} - -static int CompareHeader(int h, const char *s) { - return CompareSlices(s, strlen(s), inbuf.p + msg.headers[h].a, - msg.headers[h].b - msg.headers[h].a); -} - -static bool HeaderEquals(int h, const char *s) { - return !CompareHeader(h, s); + return !!msg.headers[h].a; } static bool ClientAcceptsGzip(void) { @@ -822,20 +853,34 @@ static int64_t LocoTimeToZulu(int64_t x) { return x - gmtoff; } -static int64_t GetLastModifiedZip(const uint8_t *cfile) { +static int64_t GetZipCfileLastModified(const uint8_t *zcf) { const uint8_t *p, *pe; - for (p = ZIP_CFILE_EXTRA(cfile), pe = p + ZIP_CFILE_EXTRASIZE(cfile); p < pe; + for (p = ZIP_CFILE_EXTRA(zcf), pe = p + ZIP_CFILE_EXTRASIZE(zcf); p + 4 <= pe; p += ZIP_EXTRA_SIZE(p)) { - if (ZIP_EXTRA_HEADERID(p) == kZipExtraNtfs) { - return LocoTimeToZulu(READ64LE(ZIP_EXTRA_CONTENT(p) + 8) / - HECTONANOSECONDS - - MODERNITYSECONDS); - } else if (ZIP_EXTRA_HEADERID(p) == kZipExtraExtendedTimestamp) { - return READ32LE(ZIP_EXTRA_CONTENT(p) + 1); + if (ZIP_EXTRA_HEADERID(p) == kZipExtraNtfs && + ZIP_EXTRA_CONTENTSIZE(p) >= 4 + 4 + 8 * 3 && + READ16LE(ZIP_EXTRA_CONTENT(p) + 4) == 1 && + READ16LE(ZIP_EXTRA_CONTENT(p) + 6) == 24) { + return READ64LE(ZIP_EXTRA_CONTENT(p) + 8) / HECTONANOSECONDS - + MODERNITYSECONDS; } } - return LocoTimeToZulu(DosDateTimeToUnix(ZIP_CFILE_LASTMODIFIEDDATE(cfile), - ZIP_CFILE_LASTMODIFIEDTIME(cfile))); + for (p = ZIP_CFILE_EXTRA(zcf), pe = p + ZIP_CFILE_EXTRASIZE(zcf); p + 4 <= pe; + p += ZIP_EXTRA_SIZE(p)) { + if (ZIP_EXTRA_HEADERID(p) == kZipExtraExtendedTimestamp && + ZIP_EXTRA_CONTENTSIZE(p) >= 1 + 4 && (*ZIP_EXTRA_CONTENT(p) & 1)) { + return (int32_t)READ32LE(ZIP_EXTRA_CONTENT(p) + 1); + } + } + for (p = ZIP_CFILE_EXTRA(zcf), pe = p + ZIP_CFILE_EXTRASIZE(zcf); p + 4 <= pe; + p += ZIP_EXTRA_SIZE(p)) { + if (ZIP_EXTRA_HEADERID(p) == kZipExtraUnix && + ZIP_EXTRA_CONTENTSIZE(p) >= 4 + 4) { + return (int32_t)READ32LE(ZIP_EXTRA_CONTENT(p) + 4); + } + } + return LocoTimeToZulu(DosDateTimeToUnix(ZIP_CFILE_LASTMODIFIEDDATE(zcf), + ZIP_CFILE_LASTMODIFIEDTIME(zcf))); } static bool IsCompressed(struct Asset *a) { @@ -861,21 +906,21 @@ static char *FormatUnixHttpDateTime(char *s, int64_t t) { static void *FreeLater(void *p) { if (p) { - freelist.p = xrealloc(freelist.p, ++freelist.n * sizeof(*freelist.p)); + if (++freelist.n > freelist.c) { + freelist.c = freelist.n + 2; + freelist.c += freelist.c >> 1; + freelist.p = xrealloc(freelist.p, freelist.c * sizeof(*freelist.p)); + } freelist.p[freelist.n - 1] = p; } return p; } static void CollectGarbage(void) { - size_t i; - for (i = 0; i < freelist.n; ++i) free(freelist.p[i]); - free(freelist.p); - freelist.p = 0; - freelist.n = 0; - free(outbuf.p); - free(request.params.p); DestroyHttpRequest(&msg); + while (freelist.n) { + free(freelist.p[--freelist.n]); + } } static bool IsCompressionMethodSupported(int method) { @@ -884,24 +929,27 @@ static bool IsCompressionMethodSupported(int method) { static void IndexAssets(void) { int64_t lm; + uint64_t cf, lf; struct Asset *p; - uint32_t i, n, m, cf, step, hash; + uint32_t i, n, m, step, hash; CHECK_GE(HASH_LOAD_FACTOR, 2); - n = ZIP_CDIR_RECORDS(zdir); + CHECK(READ32LE(cdir) == kZipCdir64HdrMagic || + READ32LE(cdir) == kZipCdirHdrMagic); + n = GetZipCdirRecords(cdir); m = roundup2pow(MAX(1, n) * HASH_LOAD_FACTOR); p = xcalloc(m, sizeof(struct Asset)); - CHECK_EQ(kZipCdirHdrMagic, ZIP_CDIR_MAGIC(zdir)); - for (cf = ZIP_CDIR_OFFSET(zdir); n--; cf += ZIP_CFILE_HDRSIZE(zmap + cf)) { + for (cf = GetZipCdirOffset(cdir); n--; cf += ZIP_CFILE_HDRSIZE(zmap + cf)) { CHECK_EQ(kZipCfileHdrMagic, ZIP_CFILE_MAGIC(zmap + cf)); - if (!IsCompressionMethodSupported(ZIP_CFILE_COMPRESSIONMETHOD(zmap + cf))) { + lf = GetZipCfileOffset(zmap + cf); + if (!IsCompressionMethodSupported(ZIP_LFILE_COMPRESSIONMETHOD(zmap + lf))) { WARNF("don't understand zip compression method %d used by %`'.*s", - ZIP_CFILE_COMPRESSIONMETHOD(zmap + cf), + ZIP_LFILE_COMPRESSIONMETHOD(zmap + lf), ZIP_CFILE_NAMESIZE(zmap + cf), ZIP_CFILE_NAME(zmap + cf)); continue; } if (ZIP_CFILE_NAMESIZE(zmap + cf) > 1 && ZIP_CFILE_NAME(zmap + cf)[ZIP_CFILE_NAMESIZE(zmap + cf) - 1] == '/' && - !ZIP_CFILE_UNCOMPRESSEDSIZE(zmap + cf)) { + !GetZipLfileUncompressedSize(zmap + lf)) { continue; } hash = Hash(ZIP_CFILE_NAME(zmap + cf), ZIP_CFILE_NAMESIZE(zmap + cf)); @@ -910,9 +958,11 @@ static void IndexAssets(void) { i = (hash + (step * (step + 1)) >> 1) & (m - 1); ++step; } while (p[i].hash); - lm = GetLastModifiedZip(zmap + cf); + lm = GetZipCfileLastModified(zmap + cf); p[i].hash = hash; - p[i].lf = ZIP_CFILE_OFFSET(zmap + cf); + p[i].lf = lf; + p[i].cf = cf; + p[i].istext = !!(ZIP_CFILE_INTERNALATTRIBUTES(zmap + cf) & kZipIattrText); p[i].lastmodified = lm; p[i].lastmodifiedstr = FormatUnixHttpDateTime(xmalloc(30), lm); } @@ -929,7 +979,7 @@ static void OpenZip(const char *path) { CHECK((zsize = st.st_size)); CHECK_NE(MAP_FAILED, (zmap = mmap(NULL, zsize, PROT_READ, MAP_SHARED, fd, 0))); - CHECK_NOTNULL((zdir = zipfindcentraldir(zmap, zsize))); + CHECK_NOTNULL((cdir = GetZipCdir(zmap, zsize))); if (endswith(path, ".com.dbg") && (p = memmem(zmap, zsize, "MZqFpD", 6))) { zsize -= p - zmap; zmap = p; @@ -937,7 +987,7 @@ static void OpenZip(const char *path) { close(fd); } -static struct Asset *FindAsset(const char *path, size_t pathlen) { +static struct Asset *GetAsset(const char *path, size_t pathlen) { uint32_t i, step, hash; hash = Hash(path, pathlen); for (step = 0;; ++step) { @@ -954,14 +1004,14 @@ static struct Asset *FindAsset(const char *path, size_t pathlen) { static struct Asset *LocateAssetZip(const char *path, size_t pathlen) { char *p2, *p3, *p4; struct Asset *a; - if (pathlen && path[0] == '/') ++path, --pathlen; - if (!(a = FindAsset(path, pathlen)) && + if (pathlen > 1 && path[0] == '/') ++path, --pathlen; + if (!(a = GetAsset(path, pathlen)) && (!pathlen || (pathlen && path[pathlen - 1] == '/'))) { - p2 = strndup(path, pathlen); + p2 = xstrndup(path, pathlen); p3 = xjoinpaths(p2, "index.lua"); - if (!(a = FindAsset(p3, strlen(p3)))) { + if (!(a = GetAsset(p3, strlen(p3)))) { p4 = xjoinpaths(p2, "index.html"); - a = FindAsset(p4, strlen(p4)); + a = GetAsset(p4, strlen(p4)); free(p4); } free(p3); @@ -1007,144 +1057,6 @@ static struct Asset *LocateAsset(const char *path, size_t pathlen) { return a; } -static void EmitParamKey(struct Parser *u, struct Params *h) { - h->p = xrealloc(h->p, ++h->n * sizeof(*h->p)); - h->p[h->n - 1].key.p = u->q; - h->p[h->n - 1].key.n = u->p - u->q; - u->q = u->p; -} - -static void EmitParamVal(struct Parser *u, struct Params *h, bool t) { - if (!t) { - if (u->p > u->q) { - EmitParamKey(u, h); - h->p[h->n - 1].val.p = NULL; - h->p[h->n - 1].val.n = SIZE_MAX; - } - } else { - h->p[h->n - 1].val.p = u->q; - h->p[h->n - 1].val.n = u->p - u->q; - u->q = u->p; - } -} - -static void ParseLatin1(struct Parser *u) { - *u->p++ = 0300 | u->c >> 6; - *u->p++ = 0200 | u->c & 077; -} - -static void ParseEscape(struct Parser *u) { - int a, b; - a = u->i < u->size ? u->data[u->i++] & 0xff : 0; - b = u->i < u->size ? u->data[u->i++] & 0xff : 0; - *u->p++ = kHexToInt[a] << 4 | kHexToInt[b]; -} - -static void ParsePath(struct Parser *u, struct Buffer *h) { - while (u->i < u->size) { - u->c = u->data[u->i++] & 0xff; - if (u->c == '#' || u->c == '?') { - break; - } else if (u->c == '%') { - ParseEscape(u); - } else if (u->c >= 0200 && u->islatin1) { - ParseLatin1(u); - } else { - *u->p++ = u->c; - } - } - h->p = u->q; - h->n = u->p - u->q; - u->q = u->p; -} - -static void ParseParams(struct Parser *u, struct Params *h) { - bool t = false; - while (u->i < u->size) { - u->c = u->data[u->i++] & 0xff; - if (u->c == '#') { - break; - } else if (u->c == '%') { - ParseEscape(u); - } else if (u->c == '+') { - *u->p++ = u->isform ? ' ' : '+'; - } else if (u->c == '&') { - EmitParamVal(u, h, t); - t = false; - } else if (u->c == '=') { - if (!t) { - if (u->p > u->q) { - EmitParamKey(u, h); - t = true; - } - } else { - *u->p++ = '='; - } - } else if (u->c >= 0200 && u->islatin1) { - ParseLatin1(u); - } else { - *u->p++ = u->c; - } - } - EmitParamVal(u, h, t); -} - -static void ParseFragment(struct Parser *u, struct Buffer *h) { - while (u->i < u->size) { - u->c = u->data[u->i++] & 0xff; - if (u->c == '%') { - ParseEscape(u); - } else if (u->c >= 0200 && u->islatin1) { - ParseLatin1(u); - } else { - *u->p++ = u->c; - } - } - h->p = u->q; - h->n = u->p - u->q; - u->q = u->p; -} - -static void ParseRequestUri(void) { - struct Parser u; - u.i = 0; - u.c = 0; - u.isform = false; - u.islatin1 = true; - u.data = inbuf.p + msg.uri.a; - u.size = msg.uri.b - msg.uri.a; - memset(&request, 0, sizeof(request)); - if (u.size > 8 && !memcmp(u.data, "http", 4)) { - /* - * convert http://www.foo.com/index.html -> /www.foo.com/index.html - */ - if (u.data[4] == ':' && u.data[5] == '/' && u.data[6] == '/') { - u.data += 6; - u.size -= 6; - } else if (u.data[4] == 's' && u.data[5] == ':' && u.data[6] == '/' && - u.data[7] == '/') { - u.data += 7; - u.size -= 7; - } - } - u.q = u.p = FreeLater(xmalloc(u.size * 2)); - ParsePath(&u, &request.path); - if (u.c == '?') ParseParams(&u, &request.params); - if (u.c == '#') ParseFragment(&u, &request.fragment); -} - -static void ParseFormParams(void) { - struct Parser u; - u.i = 0; - u.c = 0; - u.isform = true; - u.islatin1 = false; - u.data = inbuf.p + hdrsize; - u.size = msgsize - hdrsize; - u.q = u.p = FreeLater(xmalloc(u.size)); - ParseParams(&u, &request.params); -} - static void *AddRange(char *content, long start, long length) { intptr_t mend, mstart; if (!__builtin_add_overflow((intptr_t)content, start, &mstart) || @@ -1168,17 +1080,14 @@ static bool MustNotIncludeMessageBody(void) { /* RFC2616 § 4.4 */ statuscode == 204 || statuscode == 304; } -static char *SetStatus(int code, const char *reason) { - char *p; +char *SetStatus(unsigned code, const char *reason) { statuscode = code; - p = hdrbuf.p; - p = stpcpy(p, "HTTP/1."); - *p++ = httpversion == 100 ? '0' : '1'; - *p++ = ' '; - p += uint64toarray_radix10(code, p); - *p++ = ' '; - p = stpcpy(p, reason); - return AppendCrlf(p); + stpcpy(hdrbuf.p, "HTTP/1.1 000 "); + if (httpversion == 100) hdrbuf.p[7] = '0'; + hdrbuf.p[9] += code / 100; + hdrbuf.p[10] += code / 10 % 10; + hdrbuf.p[11] += code % 10; + return AppendCrlf(stpcpy(hdrbuf.p + 13, reason)); } static char *AppendHeader(char *p, const char *k, const char *v) { @@ -1189,14 +1098,16 @@ static char *AppendHeader(char *p, const char *k, const char *v) { static char *AppendContentType(char *p, const char *ct) { p = stpcpy(p, "Content-Type: "); p = stpcpy(p, ct); - if (startswith(ct, "text/") && !strchr(ct, ';')) { - p = stpcpy(p, "; charset=utf-8"); + if (startswith(ct, "text/")) { istext = true; + if (!strchr(ct, ';')) { + p = stpcpy(p, "; charset=utf-8"); + } } return AppendCrlf(p); } -static char *ServeError(int code, const char *reason) { +static char *ServeError(unsigned code, const char *reason) { char *p; size_t reasonlen; reasonlen = strlen(reason); @@ -1204,7 +1115,7 @@ static char *ServeError(int code, const char *reason) { p = AppendContentType(p, "text/plain"); content = FreeLater(xmalloc(reasonlen + 3)); contentlength = reasonlen + 2; - stpcpy(stpcpy(content, reason), "\r\n"); + AppendCrlf(stpcpy(content, reason)); WARNF("%s %s %`'.*s %d %s", clientaddrstr, kHttpMethod[msg.method], msg.uri.b - msg.uri.a, inbuf.p + msg.uri.a, code, reason); return p; @@ -1219,12 +1130,14 @@ static char *AppendExpires(char *p, int64_t t) { } static char *AppendCache(char *p, int64_t seconds) { - struct tm tm; if (seconds < 0) return p; - p = stpcpy(p, "Cache-Control: "); - p = stpcpy(p, "max-age="); + p = stpcpy(p, "Cache-Control: max-age="); p += uint64toarray_radix10(seconds, p); - if (seconds) p = stpcpy(p, ", public"); + if (seconds) { + p = stpcpy(p, ", public"); + } else { + p = stpcpy(p, ", no-store"); + } p = AppendCrlf(p); return AppendExpires(p, (int64_t)nowish + seconds); } @@ -1251,10 +1164,8 @@ static char *AppendContentRange(char *p, long rangestart, long rangelength, return AppendCrlf(p); } -static bool Inflate(uint8_t *dp, size_t dn, const uint8_t *sp, size_t sn) { - bool ok; +static bool Inflate(void *dp, size_t dn, const void *sp, size_t sn) { z_stream zs; - ok = false; zs.next_in = sp; zs.avail_in = sn; zs.total_in = sn; @@ -1263,26 +1174,35 @@ static bool Inflate(uint8_t *dp, size_t dn, const uint8_t *sp, size_t sn) { zs.total_out = dn; zs.zfree = Z_NULL; zs.zalloc = Z_NULL; - if (inflateInit2(&zs, -MAX_WBITS) == Z_OK) { - switch (inflate(&zs, Z_NO_FLUSH)) { - case Z_STREAM_END: - ok = true; - break; - case Z_MEM_ERROR: - WARNF("Z_MEM_ERROR"); - break; - case Z_DATA_ERROR: - WARNF("Z_DATA_ERROR"); - break; - case Z_NEED_DICT: - WARNF("Z_NEED_DICT"); - break; - default: - abort(); - } - inflateEnd(&zs); + CHECK_EQ(Z_OK, inflateInit2(&zs, -MAX_WBITS)); + switch (inflate(&zs, Z_NO_FLUSH)) { + case Z_STREAM_END: + CHECK_EQ(Z_OK, inflateEnd(&zs)); + return true; + case Z_DATA_ERROR: + inflateEnd(&zs); + WARNF("Z_DATA_ERROR"); + return false; + case Z_NEED_DICT: + inflateEnd(&zs); + WARNF("Z_NEED_DICT"); + return false; + case Z_MEM_ERROR: + FATALF("Z_MEM_ERROR"); + default: + abort(); + } +} + +static bool Verify(void *data, size_t size, uint32_t crc) { + uint32_t got; + if (crc == (got = crc32_z(0, data, size))) { + return true; + } else { + WARNF("corrupt zip file at %`'.*s had crc 0x%08x but expected 0x%08x", + msg.uri.b - msg.uri.a, inbuf.p + msg.uri.a, got, crc); + return false; } - return ok; } static void *Deflate(const void *data, size_t size, size_t *out_size) { @@ -1303,12 +1223,12 @@ static void *Deflate(const void *data, size_t size, size_t *out_size) { static void *LoadAsset(struct Asset *a, size_t *out_size) { size_t size; uint8_t *data; - if (a->file) return FreeLater(xslurp(a->file->path, out_size)); - size = ZIP_LFILE_UNCOMPRESSEDSIZE(zmap + a->lf); + if (a->file) return xslurp(a->file->path, out_size); + size = GetZipLfileUncompressedSize(zmap + a->lf); data = xmalloc(size + 1); if (ZIP_LFILE_COMPRESSIONMETHOD(zmap + a->lf) == kZipCompressionDeflate) { - CHECK(Inflate(data, size, ZIP_LFILE_CONTENT(zmap + a->lf), - ZIP_LFILE_COMPRESSEDSIZE(zmap + a->lf))); + Inflate(data, size, ZIP_LFILE_CONTENT(zmap + a->lf), + GetZipLfileCompressedSize(zmap + a->lf)); } else { memcpy(data, ZIP_LFILE_CONTENT(zmap + a->lf), size); } @@ -1331,36 +1251,48 @@ static ssize_t Send(struct iovec *iov, int iovlen) { } static char *ServeAsset(struct Asset *a, const char *path, size_t pathlen) { - char *p; + size_t size; + uint32_t crc; + char *p, *buf; long rangestart, rangelength; if (IsNotModified(a)) { DEBUGF("%s %s %`'.*s not modified", clientaddrstr, kHttpMethod[msg.method], pathlen, path); p = SetStatus(304, "Not Modified"); } else { - if (!a->file) { + if (a->file) { + if (a->file->st.st_mode & 0004) { + content = FreeLater(xslurp(a->file->path, &contentlength)); + } else { + WARNF("local file lacks st_mode read bit for other users %`'.*s", + msg.uri.b - msg.uri.a, inbuf.p + msg.uri.a); + return ServeError(403, "Forbidden"); + } + } else if (GetZipCfileMode(zmap + a->cf) & 0004) { content = ZIP_LFILE_CONTENT(zmap + a->lf); - contentlength = ZIP_LFILE_COMPRESSEDSIZE(zmap + a->lf); + contentlength = GetZipLfileCompressedSize(zmap + a->lf); } else { - /* TODO(jart): Use sendfile(). */ - content = FreeLater(xslurp(a->file->path, &contentlength)); + WARNF("zip file lacks st_mode read bit for other users %`'.*s", + msg.uri.b - msg.uri.a, inbuf.p + msg.uri.a); + return ServeError(403, "Forbidden"); } - if (IsCompressed(a)) { + if (!a->file && IsCompressed(a)) { + crc = ZIP_LFILE_CRC32(zmap + a->lf); + size = GetZipLfileUncompressedSize(zmap + a->lf); if (ClientAcceptsGzip()) { gzipped = true; - memcpy(gzip_footer + 0, zmap + a->lf + kZipLfileOffsetCrc32, 4); - memcpy(gzip_footer + 4, zmap + a->lf + kZipLfileOffsetUncompressedsize, - 4); + WRITE32LE(gzip_footer + 0, crc); + WRITE32LE(gzip_footer + 4, size); p = SetStatus(200, "OK"); - p = AppendHeader(p, "Content-Encoding", "gzip"); + p = stpcpy(p, "Content-Encoding: gzip\r\n"); + } else if ((buf = FreeLater(malloc(size))) && + Inflate(buf, size, content, contentlength) && + Verify(buf, size, crc)) { + p = SetStatus(200, "OK"); + content = buf; + contentlength = size; } else { - CHECK(Inflate( - (content = - FreeLater(xmalloc(ZIP_LFILE_UNCOMPRESSEDSIZE(zmap + a->lf)))), - (contentlength = ZIP_LFILE_UNCOMPRESSEDSIZE(zmap + a->lf)), - ZIP_LFILE_CONTENT(zmap + a->lf), - ZIP_LFILE_COMPRESSEDSIZE(zmap + a->lf))); - p = SetStatus(200, "OK"); + return ServeError(500, "Internal Server Error"); } } else if (httpversion >= 101 && HasHeader(kHttpRange)) { if (ParseHttpRange(inbuf.p + msg.headers[kHttpRange].a, @@ -1381,20 +1313,32 @@ static char *ServeAsset(struct Asset *a, const char *path, size_t pathlen) { content = ""; contentlength = 0; } + } else if (a->file && ClientAcceptsGzip()) { + gzipped = true; + p = SetStatus(200, "OK"); + p = stpcpy(p, "Content-Encoding: gzip\r\n"); + crc = crc32_z(0, content, contentlength); + WRITE32LE(gzip_footer + 0, crc); + WRITE32LE(gzip_footer + 4, contentlength); + content = FreeLater(Deflate(content, contentlength, &contentlength)); + } else if (!a->file && ZIP_LFILE_COMPRESSIONMETHOD(zmap + a->lf) == + kZipCompressionNone) { + if (Verify(content, contentlength, ZIP_LFILE_CRC32(zmap + a->lf))) { + p = SetStatus(200, "OK"); + } else { + return ServeError(500, "Internal Server Error"); + } } else { p = SetStatus(200, "OK"); } } - if (httpversion >= 100) { - p = AppendHeader(p, "Last-Modified", a->lastmodifiedstr); - p = AppendContentType(p, GetContentType(a, path, pathlen)); - if (httpversion >= 101) { - p = AppendCache(p, cacheseconds); - if (!IsCompressed(a)) { - p = AppendHeader(p, "Accept-Ranges", "bytes"); - } else { - p = AppendHeader(p, "Vary", "Accept-Encoding"); - } + p = stpcpy(p, "Vary: Accept-Encoding\r\n"); + p = AppendHeader(p, "Last-Modified", a->lastmodifiedstr); + p = AppendContentType(p, GetContentType(a, path, pathlen)); + if (httpversion >= 101) { + p = AppendCache(p, cacheseconds); + if (a->file || !IsCompressed(a)) { + p = stpcpy(p, "Accept-Ranges: bytes\r\n"); } } return p; @@ -1411,38 +1355,43 @@ static void AppendString(const char *s) { } static void AppendFmt(const char *fmt, ...) { - int size; - char *data; + int n; + char *p; va_list va; - data = NULL; va_start(va, fmt); - CHECK_NE(-1, (size = vasprintf(&data, fmt, va))); + n = vasprintf(&p, fmt, va); va_end(va); - AppendData(data, size); - free(data); + CHECK_NE(-1, n); + AppendData(p, n); + free(p); } static char *CommitOutput(char *p) { + uint32_t crc; + p = stpcpy(p, "Vary: Accept-Encoding\r\n"); if (istext && outbuf.n >= 100 && ClientAcceptsGzip()) { gzipped = true; - p = AppendHeader(p, "Content-Encoding", "gzip"); - p = AppendHeader(p, "Vary", "Accept-Encoding"); - WRITE32LE(gzip_footer + 0, crc32_z(0, outbuf.p, outbuf.n)); + p = stpcpy(p, "Content-Encoding: gzip\r\n"); + crc = crc32_z(0, outbuf.p, outbuf.n); + WRITE32LE(gzip_footer + 0, crc); WRITE32LE(gzip_footer + 4, outbuf.n); content = FreeLater(Deflate(outbuf.p, outbuf.n, &contentlength)); + free(outbuf.p); } else { - content = outbuf.p; + content = FreeLater(outbuf.p); contentlength = outbuf.n; } + outbuf.p = 0; + outbuf.n = 0; return p; } -static char *GetAssetPath(uint32_t cf, size_t *out_size) { +static char *GetAssetPath(uint64_t cf, size_t *out_size) { char *p1, *p2; size_t n1, n2; p1 = ZIP_CFILE_NAME(zmap + cf); n1 = ZIP_CFILE_NAMESIZE(zmap + cf); - p2 = malloc(1 + n1 + 1); + p2 = xmalloc(1 + n1 + 1); n2 = 1 + n1 + 1; p2[0] = '/'; memcpy(p2 + 1, p1, n1); @@ -1491,7 +1440,7 @@ static int LuaServeAsset(lua_State *L) { return 0; } -static int LuaRespond(lua_State *L, char *respond(int, const char *)) { +static int LuaRespond(lua_State *L, char *respond(unsigned, const char *)) { char *p; int code; size_t reasonlen; @@ -1606,19 +1555,22 @@ static int LuaGetHeader(lua_State *L) { size_t i, keylen; key = luaL_checklstring(L, 1, &keylen); if ((h = GetHttpHeader(key, keylen)) != -1) { - LuaPushLatin1(L, inbuf.p + msg.headers[h].a, - msg.headers[h].b - msg.headers[h].a); - return 1; - } - for (i = 0; i < msg.xheaders.n; ++i) { - if (!CompareSlicesCase(key, keylen, inbuf.p + msg.xheaders.p[i].k.a, - msg.xheaders.p[i].k.b - msg.xheaders.p[i].k.a)) { - LuaPushLatin1(L, inbuf.p + msg.xheaders.p[i].v.a, - msg.xheaders.p[i].v.b - msg.xheaders.p[i].v.a); + if (msg.headers[h].a) { + LuaPushLatin1(L, inbuf.p + msg.headers[h].a, + msg.headers[h].b - msg.headers[h].a); return 1; } + } else { + for (i = 0; i < msg.xheaders.n; ++i) { + if (SlicesEqualCase(key, keylen, inbuf.p + msg.xheaders.p[i].k.a, + msg.xheaders.p[i].k.b - msg.xheaders.p[i].k.a)) { + LuaPushLatin1(L, inbuf.p + msg.xheaders.p[i].v.a, + msg.xheaders.p[i].v.b - msg.xheaders.p[i].v.a); + return 1; + } + } } - lua_pushstring(L, ""); + lua_pushnil(L); return 1; } @@ -1627,7 +1579,7 @@ static int LuaGetHeaders(lua_State *L) { char *name; lua_newtable(L); for (i = 0; i < kHttpHeadersMax; ++i) { - if (msg.headers[i].b - msg.headers[i].a) { + if (msg.headers[i].a) { LuaPushLatin1(L, inbuf.p + msg.headers[i].a, msg.headers[i].b - msg.headers[i].a); lua_setfield(L, -2, GetHttpHeaderName(i)); @@ -1673,11 +1625,6 @@ static int LuaSetHeader(lua_State *L) { p = luaheaderp; } switch (h) { - case kHttpDate: - case kHttpContentRange: - case kHttpContentLength: - case kHttpContentEncoding: - return luaL_argerror(L, 1, "abstracted"); case kHttpConnection: if (evallen != 5 || memcmp(eval, "close", 5)) { return luaL_argerror(L, 2, "unsupported"); @@ -1731,19 +1678,72 @@ static int LuaGetParam(lua_State *L) { return 1; } -static int LuaGetParams(lua_State *L) { +static void LuaPushParams(lua_State *L, struct UrlParams *h) { size_t i; lua_newtable(L); - for (i = 0; i < request.params.n; ++i) { + for (i = 0; i < h->n; ++i) { lua_newtable(L); - lua_pushlstring(L, request.params.p[i].key.p, request.params.p[i].key.n); + lua_pushlstring(L, h->p[i].key.p, h->p[i].key.n); lua_seti(L, -2, 1); - if (request.params.p[i].val.n != SIZE_MAX) { - lua_pushlstring(L, request.params.p[i].val.p, request.params.p[i].val.n); + if (h->p[i].val.n != SIZE_MAX) { + lua_pushlstring(L, h->p[i].val.p, h->p[i].val.n); lua_seti(L, -2, 2); } lua_seti(L, -2, i + 1); } +} + +static int LuaGetParams(lua_State *L) { + LuaPushParams(L, &request.params); + return 1; +} + +static int LuaParseParams(lua_State *L) { + void *m; + size_t size; + const char *data; + struct UrlParams h; + data = luaL_checklstring(L, 1, &size); + memset(&h, 0, sizeof(h)); + m = ParseParams(data, size, &h); + LuaPushParams(L, &h); + free(h.p); + free(m); + return 1; +} + +static void LuaPushUrlView(lua_State *L, struct UrlView *v) { + if (v->p) { + lua_pushlstring(L, v->p, v->n); + } else { + lua_pushnil(L); + } +} + +static void LuaSetUrlView(lua_State *L, struct UrlView *v, const char *k) { + LuaPushUrlView(L, v); + lua_setfield(L, -2, k); +} + +static int LuaParseUrl(lua_State *L) { + void *m; + size_t size; + struct Url h; + const char *data; + data = luaL_checklstring(L, 1, &size); + m = ParseUrl(data, size, &h); + lua_newtable(L); + LuaSetUrlView(L, &h.user, "user"); + LuaSetUrlView(L, &h.pass, "pass"); + LuaSetUrlView(L, &h.host, "host"); + LuaSetUrlView(L, &h.port, "port"); + LuaSetUrlView(L, &h.path, "path"); + LuaSetUrlView(L, &h.scheme, "scheme"); + LuaSetUrlView(L, &h.fragment, "fragment"); + LuaPushParams(L, &h.params); + lua_setfield(L, -2, "params"); + free(h.params.p); + free(m); return 1; } @@ -1756,6 +1756,30 @@ static int LuaWrite(lua_State *L) { return 0; } +static int LuaIsValidHttpToken(lua_State *L) { + size_t size; + const char *data; + data = luaL_checklstring(L, 1, &size); + lua_pushboolean(L, IsValidHttpToken(data, size)); + return 1; +} + +static int LuaIsAcceptablePath(lua_State *L) { + size_t size; + const char *data; + data = luaL_checklstring(L, 1, &size); + lua_pushboolean(L, IsAcceptablePath(data, size)); + return 1; +} + +static int LuaIsAcceptableHostPort(lua_State *L) { + size_t size; + const char *data; + data = luaL_checklstring(L, 1, &size); + lua_pushboolean(L, IsAcceptableHostPort(data, size)); + return 1; +} + static int LuaEscaper(lua_State *L, struct EscapeResult escape(const char *, size_t)) { size_t size; @@ -1891,7 +1915,10 @@ static int LuaSetLogLevel(lua_State *L) { } static int LuaHidePath(lua_State *L) { - AddString(&hidepaths, strdup(luaL_checkstring(L, 1))); + size_t pathlen; + const char *path; + path = luaL_checklstring(L, 1, &pathlen); + AddString(&hidepaths, strndup(path, pathlen)); return 0; } @@ -1917,13 +1944,12 @@ static int LuaIsHiddenPath(lua_State *L) { static int LuaGetZipPaths(lua_State *L) { char *path; - uint32_t cf; + uint64_t cf; size_t i, n, pathlen; lua_newtable(L); i = 0; - n = ZIP_CDIR_RECORDS(zdir); - CHECK_EQ(kZipCdirHdrMagic, ZIP_CDIR_MAGIC(zdir)); - for (cf = ZIP_CDIR_OFFSET(zdir); n--; cf += ZIP_CFILE_HDRSIZE(zmap + cf)) { + n = GetZipCdirRecords(cdir); + for (cf = GetZipCdirOffset(cdir); n--; cf += ZIP_CFILE_HDRSIZE(zmap + cf)) { CHECK_EQ(kZipCfileHdrMagic, ZIP_CFILE_MAGIC(zmap + cf)); path = GetAssetPath(cf, &pathlen); lua_pushlstring(L, path, pathlen); @@ -1954,50 +1980,55 @@ static void LuaRun(const char *path) { } static const luaL_Reg kLuaFuncs[] = { - {"DecodeBase64", LuaDecodeBase64}, // - {"EncodeBase64", LuaEncodeBase64}, // - {"EscapeFragment", LuaEscapeFragment}, // - {"EscapeHtml", LuaEscapeHtml}, // - {"EscapeLiteral", LuaEscapeLiteral}, // - {"EscapeParam", LuaEscapeParam}, // - {"EscapePath", LuaEscapePath}, // - {"EscapeSegment", LuaEscapeSegment}, // - {"FormatHttpDateTime", LuaFormatHttpDateTime}, // - {"GetClientAddr", LuaGetClientAddr}, // - {"GetDate", LuaGetDate}, // - {"GetHeader", LuaGetHeader}, // - {"GetHeaders", LuaGetHeaders}, // - {"GetLogLevel", LuaGetLogLevel}, // - {"GetMethod", LuaGetMethod}, // - {"GetParam", LuaGetParam}, // - {"GetParams", LuaGetParams}, // - {"GetPath", LuaGetPath}, // - {"GetPayload", LuaGetPayload}, // - {"GetServerAddr", LuaGetServerAddr}, // - {"GetUri", LuaGetUri}, // - {"GetVersion", LuaGetVersion}, // - {"GetZipPaths", LuaGetZipPaths}, // - {"LaunchBrowser", LuaLaunchBrowser}, // - {"HasParam", LuaHasParam}, // - {"HidePath", LuaHidePath}, // - {"LoadAsset", LuaLoadAsset}, // - {"Log", LuaLog}, // - {"ParseHttpDateTime", LuaParseHttpDateTime}, // - {"ProgramBrand", LuaProgramBrand}, // - {"ProgramCache", LuaProgramCache}, // - {"ProgramPort", LuaProgramPort}, // - {"ProgramRedirect", LuaProgramRedirect}, // - {"ServeAsset", LuaServeAsset}, // - {"ServeError", LuaServeError}, // - {"SetHeader", LuaSetHeader}, // - {"SetLogLevel", LuaSetLogLevel}, // - {"SetStatus", LuaSetStatus}, // - {"Write", LuaWrite}, // - {"bsf", LuaBsf}, // - {"bsr", LuaBsr}, // - {"crc32", LuaCrc32}, // - {"crc32c", LuaCrc32c}, // - {"popcnt", LuaPopcnt}, // + {"DecodeBase64", LuaDecodeBase64}, // + {"EncodeBase64", LuaEncodeBase64}, // + {"EscapeFragment", LuaEscapeFragment}, // + {"EscapeHtml", LuaEscapeHtml}, // + {"EscapeLiteral", LuaEscapeLiteral}, // + {"EscapeParam", LuaEscapeParam}, // + {"EscapePath", LuaEscapePath}, // + {"EscapeSegment", LuaEscapeSegment}, // + {"FormatHttpDateTime", LuaFormatHttpDateTime}, // + {"GetClientAddr", LuaGetClientAddr}, // + {"GetDate", LuaGetDate}, // + {"GetHeader", LuaGetHeader}, // + {"GetHeaders", LuaGetHeaders}, // + {"GetLogLevel", LuaGetLogLevel}, // + {"GetMethod", LuaGetMethod}, // + {"GetParam", LuaGetParam}, // + {"GetParams", LuaGetParams}, // + {"GetPath", LuaGetPath}, // + {"GetPayload", LuaGetPayload}, // + {"GetServerAddr", LuaGetServerAddr}, // + {"GetUri", LuaGetUri}, // + {"GetVersion", LuaGetVersion}, // + {"GetZipPaths", LuaGetZipPaths}, // + {"HasParam", LuaHasParam}, // + {"HidePath", LuaHidePath}, // + {"IsAcceptableHostPort", LuaIsAcceptableHostPort}, // + {"IsAcceptablePath", LuaIsAcceptablePath}, // + {"IsValidHttpToken", LuaIsValidHttpToken}, // + {"LaunchBrowser", LuaLaunchBrowser}, // + {"LoadAsset", LuaLoadAsset}, // + {"Log", LuaLog}, // + {"ParseHttpDateTime", LuaParseHttpDateTime}, // + {"ParseParams", LuaParseParams}, // + {"ParseUrl", LuaParseUrl}, // + {"ProgramBrand", LuaProgramBrand}, // + {"ProgramCache", LuaProgramCache}, // + {"ProgramPort", LuaProgramPort}, // + {"ProgramRedirect", LuaProgramRedirect}, // + {"ServeAsset", LuaServeAsset}, // + {"ServeError", LuaServeError}, // + {"SetHeader", LuaSetHeader}, // + {"SetLogLevel", LuaSetLogLevel}, // + {"SetStatus", LuaSetStatus}, // + {"Write", LuaWrite}, // + {"bsf", LuaBsf}, // + {"bsr", LuaBsr}, // + {"crc32", LuaCrc32}, // + {"crc32c", LuaCrc32c}, // + {"popcnt", LuaPopcnt}, // }; static void LuaSetArgv(lua_State *L) { @@ -2030,11 +2061,11 @@ static void LuaInit(void) { LuaSetConstant(L, "kLogWarn", kLogWarn); LuaSetConstant(L, "kLogError", kLogError); LuaSetConstant(L, "kLogFatal", kLogFatal); - LuaRun("/tool/net/.init.lua"); + LuaRun(".init.lua"); } static void LuaReload(void) { - LuaRun("/tool/net/.reload.lua"); + LuaRun(".reload.lua"); } static char *ServeLua(struct Asset *a) { @@ -2046,10 +2077,7 @@ static char *ServeLua(struct Asset *a) { p = SetStatus(200, "OK"); p = AppendContentType(p, "text/html"); } - if (outbuf.n) { - p = CommitOutput(p); - } - return p; + return CommitOutput(p); } else { WARNF("%s %s", clientaddrstr, lua_tostring(L, -1)); lua_pop(L, 1); /* remove message */ @@ -2080,23 +2108,22 @@ static char *HandleAsset(struct Asset *a, const char *path, size_t pathlen) { } static char *HandleRedirect(struct Redirect *r) { + int code; struct Asset *a; - if (!r->code) { - if ((a = LocateAsset(r->location, strlen(r->location)))) { - DEBUGF("%s %s %`'.*s rewritten %`'s", clientaddrstr, - kHttpMethod[msg.method], request.path.n, request.path.p, - r->location); - return HandleAsset(a, r->location, strlen(r->location)); - } else { - return ServeError(505, "HTTP Version Not Supported"); - } + if (!r->code && (a = LocateAsset(r->location, strlen(r->location)))) { + DEBUGF("%s %s %`'.*s rewritten %`'s", clientaddrstr, + kHttpMethod[msg.method], request.path.n, request.path.p, + r->location); + return HandleAsset(a, r->location, strlen(r->location)); } else if (httpversion == 9) { return ServeError(505, "HTTP Version Not Supported"); } else { + code = r->code; + if (!code) code = 307; DEBUGF("%s %s %`'.*s %d redirecting %`'s", clientaddrstr, - kHttpMethod[msg.method], request.path.n, request.path.p, r->code, + kHttpMethod[msg.method], request.path.n, request.path.p, code, r->location); - return AppendHeader(SetStatus(r->code, GetHttpReason(r->code)), "Location", + return AppendHeader(SetStatus(code, GetHttpReason(code)), "Location", FreeLater(EncodeHttpHeaderValue(r->location, -1, 0))); } } @@ -2104,31 +2131,33 @@ static char *HandleRedirect(struct Redirect *r) { static void LogMessage(const char *d, const char *s, size_t n) { size_t n2, n3, n4; char *s2, *s3, *s4; - if (!logmessages) return; - while (n && (s[n - 1] == '\r' || s[n - 1] == '\n')) --n; - if ((s2 = DecodeLatin1(s, n, &n2))) { - if ((s3 = VisualizeControlCodes(s2, n2, &n3))) { - if ((s4 = IndentLines(s3, n3, &n4, 1))) { - LOGF("%s %s %,ld byte message\n%.*s", clientaddrstr, d, n, n4, s4); - free(s4); + if (logmessages) { + while (n && (s[n - 1] == '\r' || s[n - 1] == '\n')) --n; + if ((s2 = DecodeLatin1(s, n, &n2))) { + if ((s3 = VisualizeControlCodes(s2, n2, &n3))) { + if ((s4 = IndentLines(s3, n3, &n4, 1))) { + LOGF("%s %s %,ld byte message\n%.*s", clientaddrstr, d, n, n4, s4); + free(s4); + } + free(s3); } - free(s3); + free(s2); } - free(s2); } } static void LogBody(const char *d, const char *s, size_t n) { char *s2, *s3; size_t n2, n3; - if (!n || !logbodies) return; - while (n && (s[n - 1] == '\r' || s[n - 1] == '\n')) --n; - if ((s2 = VisualizeControlCodes(s, n, &n2))) { - if ((s3 = IndentLines(s2, n2, &n3, 1))) { - LOGF("%s %s %,ld byte payload\n%.*s", clientaddrstr, d, n, n3, s3); - free(s3); + if (n && logbodies) { + while (n && (s[n - 1] == '\r' || s[n - 1] == '\n')) --n; + if ((s2 = VisualizeControlCodes(s, n, &n2))) { + if ((s3 = IndentLines(s2, n2, &n3, 1))) { + LOGF("%s %s %,ld byte payload\n%.*s", clientaddrstr, d, n, n3, s3); + free(s3); + } + free(s2); } - free(s2); } } @@ -2169,9 +2198,11 @@ Content-Length: 0\r\n\ static void LogClose(const char *reason) { if (amtread) { - WARNF("%s %s with %,ld bytes unprocessed", clientaddrstr, reason, amtread); + WARNF("%s %s with %,ld bytes unprocessed and %,d requests handled", + clientaddrstr, reason, amtread, requestshandled); } else { - DEBUGF("%s %s", clientaddrstr, reason); + DEBUGF("%s %s with %,d requests handled", clientaddrstr, reason, + requestshandled); } } @@ -2183,41 +2214,41 @@ static const char *DescribeClose(void) { return "destroyed"; } -static const char *DescribeCompressionRatio(char rb[8], uint32_t cf) { +static const char *DescribeCompressionRatio(char rb[8], uint64_t lf) { long percent; - if (ZIP_CFILE_COMPRESSIONMETHOD(zmap + cf) == kZipCompressionNone) { + if (ZIP_LFILE_COMPRESSIONMETHOD(zmap + lf) == kZipCompressionNone) { return "n/a"; } else { - percent = lround(100 - (double)ZIP_CFILE_COMPRESSEDSIZE(zmap + cf) / - ZIP_CFILE_UNCOMPRESSEDSIZE(zmap + cf) * 100); + percent = lround(100 - (double)GetZipLfileCompressedSize(zmap + lf) / + GetZipLfileUncompressedSize(zmap + lf) * 100); sprintf(rb, "%ld%%", MIN(999, MAX(-999, percent))); return rb; } } -static void LoadLogo(void) { - char *p; - size_t n; - struct Asset *a; - const char *logopath; - logopath = "/tool/net/redbean.png"; - if ((a = LocateAsset(logopath, strlen(logopath)))) { - p = LoadAsset(a, &n); - logo.p = EncodeBase64(p, n, &logo.n); - free(p); - } +static int GetDecimalWidth(int x) { + int w = x ? ceil(log10(x)) : 1; + return w + (w - 1) / 3; +} + +static int GetOctalWidth(int x) { + return !x ? 1 : x < 8 ? 2 : 1 + bsr(x) / 3; } static char *ServeListing(void) { + long x; + ldiv_t y; + int w[3]; char rb[8]; char tb[64]; - int w, x, y; struct tm tm; - char *p, *path; + const char *and; int64_t lastmod; - uint32_t cf, lf; + uint64_t cf, lf; + struct Asset *a; + char *p, *q, *path; size_t i, n, pathlen; - struct EscapeResult r[3]; + struct EscapeResult r[4]; AppendString("\ \n\ \n\ @@ -2238,51 +2269,60 @@ footer {\n\ }\n\ \n\

\n"); - if (logo.n) { + if ((a = LocateAsset("redbean.png", 11))) { + p = LoadAsset(a, &n); + q = EncodeBase64(p, n, &n); AppendString("\n"); + free(q); + free(p); } r[0] = EscapeHtml(brand, strlen(brand)); AppendData(r[0].data, r[0].size); free(r[0].data); AppendString("


\n");
-  w = x = 0;
-  n = ZIP_CDIR_RECORDS(zdir);
-  CHECK_EQ(kZipCdirHdrMagic, ZIP_CDIR_MAGIC(zdir));
-  for (cf = ZIP_CDIR_OFFSET(zdir); n--; cf += ZIP_CFILE_HDRSIZE(zmap + cf)) {
+  memset(w, 0, sizeof(w));
+  n = GetZipCdirRecords(cdir);
+  for (cf = GetZipCdirOffset(cdir); n--; cf += ZIP_CFILE_HDRSIZE(zmap + cf)) {
     CHECK_EQ(kZipCfileHdrMagic, ZIP_CFILE_MAGIC(zmap + cf));
-    if (!IsHiddenPath((path = GetAssetPath(cf, &pathlen)))) {
-      y = strwidth(path, 0);
-      w = MIN(80, MAX(w, y + 2));
-      y = ZIP_CFILE_UNCOMPRESSEDSIZE(zmap + cf);
-      y = y ? llog10(y) : 1;
-      x = MIN(80, MAX(x, y + (y - 1) / 3 + 2));
+    lf = GetZipCfileOffset(zmap + cf);
+    path = GetAssetPath(cf, &pathlen);
+    if (!IsHiddenPath(path)) {
+      w[0] = min(80, max(w[0], strwidth(path, 0) + 2));
+      w[1] = max(w[1], GetOctalWidth(GetZipCfileMode(zmap + cf)));
+      w[2] = max(w[2], GetDecimalWidth(GetZipLfileUncompressedSize(zmap + lf)));
     }
+    free(path);
   }
-  n = ZIP_CDIR_RECORDS(zdir);
-  for (cf = ZIP_CDIR_OFFSET(zdir); n--; cf += ZIP_CFILE_HDRSIZE(zmap + cf)) {
+  n = GetZipCdirRecords(cdir);
+  for (cf = GetZipCdirOffset(cdir); n--; cf += ZIP_CFILE_HDRSIZE(zmap + cf)) {
     CHECK_EQ(kZipCfileHdrMagic, ZIP_CFILE_MAGIC(zmap + cf));
+    lf = GetZipCfileOffset(zmap + cf);
     path = GetAssetPath(cf, &pathlen);
     if (!IsHiddenPath(path)) {
       r[0] = EscapeHtml(path, pathlen);
       r[1] = EscapeUrlPath(path, pathlen);
       r[2] = EscapeHtml(r[1].data, r[1].size);
-      lastmod = GetLastModifiedZip(zmap + cf);
+      r[3] = EscapeHtml(ZIP_CFILE_COMMENT(zmap + cf),
+                        ZIP_CFILE_COMMENTSIZE(zmap + cf));
+      lastmod = GetZipCfileLastModified(zmap + cf);
       localtime_r(&lastmod, &tm);
-      strftime(tb, sizeof(tb), "%Y-%m-%d %H:%M:%S", &tm);
+      strftime(tb, sizeof(tb), "%Y-%m-%d %H:%M:%S %Z", &tm);
       if (IsCompressionMethodSupported(
-              ZIP_CFILE_COMPRESSIONMETHOD(zmap + cf)) &&
-          IsAcceptableHttpRequestPath(path, pathlen)) {
-        AppendFmt("%-*.*s %s %4s %,*ld\n", r[2].size,
-                  r[2].data, w, r[0].size, r[0].data, tb,
-                  DescribeCompressionRatio(rb, cf), x,
-                  ZIP_CFILE_UNCOMPRESSEDSIZE(zmap + cf));
+              ZIP_LFILE_COMPRESSIONMETHOD(zmap + lf)) &&
+          IsAcceptablePath(path, pathlen)) {
+        AppendFmt("%-*.*s %s  %0*o %4s  %,*ld  %'s\n",
+                  r[2].size, r[2].data, w[0], r[0].size, r[0].data, tb, w[1],
+                  GetZipCfileMode(zmap + cf), DescribeCompressionRatio(rb, lf),
+                  w[2], GetZipLfileUncompressedSize(zmap + lf), r[3].data);
       } else {
-        AppendFmt("%-*.*s %s %4s %,*ld\n", w, r[0].size, r[0].data, tb,
-                  DescribeCompressionRatio(rb, cf), x,
-                  ZIP_CFILE_UNCOMPRESSEDSIZE(zmap + cf));
+        AppendFmt("%-*.*s %s  %0*o %4s  %,*ld  %'s\n", w[0], r[0].size,
+                  r[0].data, tb, w[1], GetZipCfileMode(zmap + cf),
+                  DescribeCompressionRatio(rb, lf), w[2],
+                  GetZipLfileUncompressedSize(zmap + lf), r[3].data);
       }
+      free(r[3].data);
       free(r[2].data);
       free(r[1].data);
       free(r[0].data);
@@ -2290,21 +2330,29 @@ footer {\n\
     free(path);
   }
   AppendString("

\n"); - if (!unbranded) { - AppendString("\ -this listing is for /\n\ -when there's no /index.lua or /index.html in your zip
\n\ -redbean is based on\n\ -cosmopolitan and\n\ -αcτµαlly\n\ -pδrταblε εxεcµταblε
\n\ -redbean is authored by Justine Tunney who's on\n\ -GitHub and\n\ -Twitter
\n\ -your redbean is "); + and = ""; + x = nowl() - startserver; + y = ldiv(x, 24L * 60 * 60); + if (y.quot) { + AppendFmt("%,ld day%s ", y.quot, y.quot == 1 ? "" : "s"); + and = "and "; } - w = shared->workers; - AppendFmt("currently servicing %,d connection%s\n", w, w == 1 ? "" : "s"); + y = ldiv(y.rem, 60 * 60); + if (y.quot) { + AppendFmt("%,ld hour%s ", y.quot, y.quot == 1 ? "" : "s"); + and = "and "; + } + y = ldiv(y.rem, 60); + if (y.quot) { + AppendFmt("%,ld minute%s ", y.quot, y.quot == 1 ? "" : "s"); + and = "and "; + } + AppendFmt("%s%,ld second%s of operation
", and, y.rem, + y.rem == 1 ? "" : "s"); + x = shared->requestshandled; + AppendFmt("%,ld request%s handled
\n", x, x == 1 ? "" : "s"); + x = shared->workers; + AppendFmt("%,ld connection%s active
\n", x, x == 1 ? "" : "s"); AppendString("

\n"); p = SetStatus(200, "OK"); p = AppendCache(p, 0); @@ -2321,24 +2369,30 @@ static char *ServeServerOptions(void) { return p; } -static char *HandleMessage(void) { +static char *TryPath(const char *path, size_t pathlen) { long r; - ssize_t cl, rc; struct Asset *a; - size_t got, need; + if ((a = LocateAsset(path, pathlen))) { + return HandleAsset(a, path, pathlen); + } else if ((r = FindRedirect(path, pathlen)) != -1) { + return HandleRedirect(redirects.p + r); + } else if (SlicesEqual(path, pathlen, "/", 1)) { + return ServeListing(); + } else { + return NULL; + } +} + +static char *HandleMessage(void) { + char *p, *path; + ssize_t cl, rc; + const char *host; + size_t got, need, pathlen, hostlen; httpversion = ParseHttpVersion(inbuf.p + msg.version.a, msg.version.b - msg.version.a); if (httpversion > 101) { return ServeError(505, "HTTP Version Not Supported"); } - if (HasHeader(kHttpExpect) && !HeaderEquals(kHttpExpect, "100-continue")) { - return ServeError(417, "Expectation Failed"); - } - if (msg.method == kHttpConnect || - (HasHeader(kHttpTransferEncoding) && - !HeaderEquals(kHttpTransferEncoding, "identity"))) { - return ServeError(501, "Not Implemented"); - } if (!HasHeader(kHttpContentLength) && (msg.method == kHttpPost || msg.method == kHttpPut)) { return ServeError(411, "Length Required"); @@ -2352,7 +2406,7 @@ static char *HandleMessage(void) { if (need > inbuf.n) { return ServeError(413, "Payload Too Large"); } - if (HeaderEquals(kHttpExpect, "100-continue") && httpversion >= 101) { + if (HeaderEqual(kHttpExpect, "100-continue") && httpversion >= 101) { SendContinue(); } while (amtread < need) { @@ -2381,36 +2435,84 @@ static char *HandleMessage(void) { } msgsize = need; /* we are now synchronized */ LogBody("received", inbuf.p + hdrsize, msgsize - hdrsize); - if (httpversion != 101 || !CompareHeader(kHttpConnection, "close")) { + if (httpversion != 101 || HeaderEqual(kHttpConnection, "close")) { connectionclose = true; } - ParseRequestUri(); + if (HasHeader(kHttpExpect) && !HeaderEqual(kHttpExpect, "100-continue")) { + return ServeError(417, "Expectation Failed"); + } + if (msg.method == kHttpConnect || + (HasHeader(kHttpTransferEncoding) && + !HeaderEqual(kHttpTransferEncoding, "identity"))) { + return ServeError(501, "Not Implemented"); + } + FreeLater( + ParseRequestUri(inbuf.p + msg.uri.a, msg.uri.b - msg.uri.a, &request)); + if (HeaderEqual(kHttpContentType, "application/x-www-form-urlencoded")) { + FreeLater( + ParseParams(inbuf.p + hdrsize, msgsize - hdrsize, &request.params)); + } + FreeLater(request.params.p); + if ((httpversion >= 101 && !HasHeader(kHttpHost)) || + (request.scheme.n && + !SlicesEqualCase(request.scheme.p, request.scheme.n, "http", 4) && + !SlicesEqualCase(request.scheme.p, request.scheme.n, "https", 5))) { + return ServeError(400, "Bad Request"); + } if (msg.method == kHttpOptions && !CompareSlices(request.path.p, request.path.n, "*", 1)) { return ServeServerOptions(); } - if (!IsAcceptableHttpRequestPath(request.path.p, request.path.n)) { - WARNF("%s could not parse request %`'.*s", clientaddrstr, - msg.uri.b - msg.uri.a, inbuf.p + msg.uri.a); + if (!request.path.n || request.path.p[0] != '/' || + !IsAcceptablePath(request.path.p, request.path.n)) { + WARNF("%s refusing path %`'.*s", clientaddrstr, msg.uri.b - msg.uri.a, + inbuf.p + msg.uri.a); connectionclose = true; return ServeError(400, "Bad Request"); } - if (HeaderEquals(kHttpContentType, "application/x-www-form-urlencoded")) { - ParseFormParams(); + if (!request.path.n || request.path.p[0] != '/' || + !IsAcceptablePath(request.path.p, request.path.n)) { + WARNF("%s refusing path %`'.*s", clientaddrstr, msg.uri.b - msg.uri.a, + inbuf.p + msg.uri.a); + return ServeError(400, "Bad Request"); } - VERBOSEF("%s %s %`'.*s referrer %`'.*s", clientaddrstr, - kHttpMethod[msg.method], request.path.n, request.path.p, - msg.headers[kHttpReferer].b - msg.headers[kHttpReferer].a, - inbuf.p + msg.headers[kHttpReferer].a); - if ((a = LocateAsset(request.path.p, request.path.n))) { - return HandleAsset(a, request.path.p, request.path.n); - } else if ((r = FindRedirect(request.path.p, request.path.n)) != -1) { - return HandleRedirect(redirects.p + r); - } else if (!CompareSlices(request.path.p, request.path.n, "/", 1)) { - return ServeListing(); + if (request.host.n) { + host = request.host.p; + hostlen = request.host.n; } else { - return ServeError(404, "Not Found"); + host = inbuf.p + msg.headers[kHttpHost].a; + hostlen = msg.headers[kHttpHost].b - msg.headers[kHttpHost].a; } + if (!IsAcceptableHostPort(host, hostlen)) { + WARNF("%s refusing host %`'.*s", clientaddrstr, hostlen, host); + return ServeError(400, "Bad Request"); + } + VERBOSEF("%s %s %`'.*s %`'.*s referrer %`'.*s from %`'.*s", clientaddrstr, + kHttpMethod[msg.method], hostlen, host, msg.uri.b - msg.uri.a, + inbuf.p + msg.uri.a, + msg.headers[kHttpReferer].b - msg.headers[kHttpReferer].a, + inbuf.p + msg.headers[kHttpReferer].a, + msg.headers[kHttpUserAgent].b - msg.headers[kHttpUserAgent].a, + inbuf.p + msg.headers[kHttpUserAgent].a); + if (hostlen) { + if ((p = memchr(host, ':', hostlen))) hostlen = p - host; + pathlen = 1 + hostlen + request.path.n; + path = FreeLater(xmalloc(pathlen + 4)); + path[0] = '/'; + mempcpy(mempcpy(path + 1, host, hostlen), request.path.p, request.path.n); + if ((p = TryPath(path, pathlen))) return p; + if (hostlen > 4 && !memcmp(host, "www.", 4)) { + mempcpy(mempcpy(path + 1, host + 4, hostlen - 4), request.path.p, + request.path.n); + if ((p = TryPath(path, pathlen))) return p; + } else { + mempcpy(mempcpy(mempcpy(path + 1, "www.", 4), host, hostlen), + request.path.p, request.path.n); + if ((p = TryPath(path, pathlen))) return p; + } + } + if ((p = TryPath(request.path.p, request.path.n))) return p; + return ServeError(404, "Not Found"); } static bool HandleRequest(void) { @@ -2483,15 +2585,14 @@ static bool HandleRequest(void) { iovlen = 1; } Send(iov, iovlen); - CollectGarbage(); + InterlockedAdd(&shared->requestshandled, 1); + ++requestshandled; return true; } static void InitRequest(void) { frags = 0; msgsize = 0; - outbuf.p = 0; - outbuf.n = 0; content = NULL; gzipped = false; branded = false; @@ -2499,7 +2600,7 @@ static void InitRequest(void) { InitHttpRequest(&msg); } -static void ProcessRequests(void) { +static void HandleRequests(void) { ssize_t rc; size_t got; long double now; @@ -2549,17 +2650,18 @@ static void ProcessRequests(void) { LogClose(DescribeClose()); return; } + CollectGarbage(); } } static void EnterMeltdownMode(void) { if (lastmeltdown && nowl() - lastmeltdown < 1) return; - WARNF("redbean is entering meltdown mode with %,d workers", shared->workers); + WARNF("redbean is melting down (%,d workers)", shared->workers); LOGIFNEG1(kill(0, SIGUSR2)); lastmeltdown = nowl(); } -static void ProcessConnection(void) { +static void HandleConnection(void) { int pid; clientaddrsize = sizeof(clientaddr); if ((client = accept4(server, &clientaddr, &clientaddrsize, SOCK_CLOEXEC)) != @@ -2567,6 +2669,7 @@ static void ProcessConnection(void) { startconnection = nowl(); if (uniprocess) { pid = -1; + requestshandled = 0; connectionclose = true; } else { switch ((pid = fork())) { @@ -2575,6 +2678,7 @@ static void ProcessConnection(void) { connectionclose = false; break; case -1: + WARNF("%s too man processes %s", serveraddrstr, strerror(errno)); EnterMeltdownMode(); SendServiceUnavailable(); /* fallthrough */ @@ -2586,33 +2690,82 @@ static void ProcessConnection(void) { } DescribeAddress(clientaddrstr, &clientaddr); DEBUGF("%s accept", clientaddrstr); - ProcessRequests(); + HandleRequests(); LOGIFNEG1(close(client)); - if (!pid) _exit(0); + if (!pid) { + _exit(0); + } else { + CollectGarbage(); + } } else if (errno != EINTR) { - FATALF("%s accept error %s", serveraddrstr, strerror(errno)); + if (errno == ENFILE) { + WARNF("%s too many open files", serveraddrstr); + EnterMeltdownMode(); + } else if (errno == EMFILE) { + WARNF("%s ran out of open file quota", serveraddrstr); + EnterMeltdownMode(); + } else if (errno == ENOMEM || errno == ENOBUFS) { + WARNF("%s ran out of memory"); + EnterMeltdownMode(); + } else if (errno == ENONET) { + WARNF("%s network gone", serveraddrstr); + sleep(1); + } else if (errno == ENETDOWN) { + WARNF("%s network down", serveraddrstr); + sleep(1); + } else if (errno == ECONNABORTED) { + WARNF("%s connection reset before accept"); + } else if (errno == ENETUNREACH || errno == EHOSTUNREACH || + errno == EOPNOTSUPP || errno == ENOPROTOOPT || errno == EPROTO) { + WARNF("%s ephemeral accept error %s", serveraddrstr, strerror(errno)); + } else { + FATALF("%s accept error %s", serveraddrstr, strerror(errno)); + } } } +static void HandleHeartbeat(void) { + UpdateCurrentDate(nowl()); +} + static void TuneServerSocket(void) { int yes = 1; - LOGIFNEG1(setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes))); - LOGIFNEG1(setsockopt(server, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))); - LOGIFNEG1(setsockopt(server, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes))); - LOGIFNEG1(setsockopt(server, IPPROTO_TCP, TCP_FASTOPEN, &yes, sizeof(yes))); - LOGIFNEG1(setsockopt(server, IPPROTO_TCP, TCP_QUICKACK, &yes, sizeof(yes))); + setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); + setsockopt(server, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)); + setsockopt(server, IPPROTO_TCP, TCP_FASTOPEN, &yes, sizeof(yes)); + setsockopt(server, IPPROTO_TCP, TCP_QUICKACK, &yes, sizeof(yes)); } -void RedBean(int argc, char *argv[]) { +static void RestoreApe(const char *prog) { + char *p; + size_t n; + struct Asset *a; + extern char ape_rom_vaddr[] __attribute__((__weak__)); + if (IsWindows()) return; + if (endswith(prog, ".com.dbg")) return; + close(OpenExecutable()); + if ((a = GetAsset(".ape", 4))) { + p = LoadAsset(a, &n); + mprotect(ape_rom_vaddr, PAGESIZE, PROT_READ | PROT_WRITE); + memcpy(ape_rom_vaddr, p, MIN(n, PAGESIZE)); + msync(ape_rom_vaddr, PAGESIZE, MS_ASYNC); + mprotect(ape_rom_vaddr, PAGESIZE, PROT_NONE); + free(p); + } +} + +void RedBean(int argc, char *argv[], const char *prog) { uint32_t addrsize; + startserver = nowl(); gmtoff = GetGmtOffset(); + CHECK_GT(CLK_TCK, 0); CHECK_NE(MAP_FAILED, (shared = mmap(NULL, ROUNDUP(sizeof(struct Shared), FRAMESIZE), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0))); - OpenZip((const char *)getauxval(AT_EXECFN)); + OpenZip(prog); IndexAssets(); - LoadLogo(); + RestoreApe(prog); SetDefaults(); GetOpts(argc, argv); LuaInit(); @@ -2662,13 +2815,11 @@ void RedBean(int argc, char *argv[]) { LuaReload(); invalidated = false; } else if (heartbeat) { - UpdateCurrentDate(nowl()); + HandleHeartbeat(); heartbeat = false; } else { - if (heartless) { - UpdateCurrentDate(nowl()); - } - ProcessConnection(); + if (heartless) HandleHeartbeat(); + HandleConnection(); } } VERBOSEF("%s shutting down", serveraddrstr); @@ -2684,6 +2835,6 @@ void RedBean(int argc, char *argv[]) { int main(int argc, char *argv[]) { showcrashreports(); - RedBean(argc, argv); + RedBean(argc, argv, (const char *)getauxval(AT_EXECFN)); return 0; } diff --git a/tool/net/redbean.lua b/tool/net/redbean.lua index ec8716733..fe186327c 100644 --- a/tool/net/redbean.lua +++ b/tool/net/redbean.lua @@ -69,7 +69,7 @@ local function main() Write([[

post request html form demo

-
+
@@ -92,7 +92,7 @@ local function main() r.onload = function() { document.getElementById("result").innerText = this.getResponseHeader('X-Custom-Header'); }; - r.open('POST', '/tool/net/redbean-xhr.lua'); + r.open('POST', 'redbean-xhr.lua'); r.setRequestHeader('X-Custom-Header', document.getElementById('x').value); r.send(); }