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 c166f1018..4266ab544 100755
Binary files a/build/bootstrap/package.com and b/build/bootstrap/package.com differ
diff --git a/build/bootstrap/zipobj.com b/build/bootstrap/zipobj.com
index d148bd22d..bbe95476f 100755
Binary files a/build/bootstrap/zipobj.com and b/build/bootstrap/zipobj.com differ
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");
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
-