mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
Make more fixes and improvements
This commit is contained in:
parent
01b25e267b
commit
1599b818d9
24 changed files with 858 additions and 538 deletions
2
Makefile
2
Makefile
|
@ -281,7 +281,7 @@ COSMOPOLITAN_OBJECTS = \
|
|||
LIBC_RAND \
|
||||
LIBC_SYSV_CALLS \
|
||||
LIBC_NT_PSAPI \
|
||||
LIBC_NT_POWERPROF \
|
||||
LIBC_NT_POWRPROF \
|
||||
LIBC_NT_PDH \
|
||||
LIBC_NT_SHELL32 \
|
||||
LIBC_NT_GDI32 \
|
||||
|
|
|
@ -46,7 +46,7 @@ LIBC_CALLS_A_DIRECTDEPS = \
|
|||
LIBC_NT_NTDLL \
|
||||
LIBC_NT_PDH \
|
||||
LIBC_NT_PSAPI \
|
||||
LIBC_NT_POWERPROF \
|
||||
LIBC_NT_POWRPROF \
|
||||
LIBC_NT_WS2_32 \
|
||||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
|
|
397
libc/fmt/fmt.c
397
libc/fmt/fmt.c
|
@ -21,7 +21,7 @@
|
|||
#include "libc/bits/weaken.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/fmt/fmts.h"
|
||||
#include "libc/fmt/fmt.internal.h"
|
||||
#include "libc/fmt/internal.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/nomultics.internal.h"
|
||||
|
@ -33,25 +33,6 @@
|
|||
#include "libc/sysv/errfuns.h"
|
||||
#include "third_party/gdtoa/gdtoa.h"
|
||||
|
||||
#define PUT(C) \
|
||||
do { \
|
||||
char Buf[1] = {C}; \
|
||||
if (out(Buf, arg, 1) == -1) { \
|
||||
return -1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static const char kSpecialFloats[2][2][4] = {{"INF", "inf"}, {"NAN", "nan"}};
|
||||
|
||||
static void __fmt_free_dtoa(char **mem) {
|
||||
if (*mem) {
|
||||
if (weaken(freedtoa)) {
|
||||
weaken(freedtoa)(*mem);
|
||||
}
|
||||
*mem = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int __fmt_atoi(const char **str) {
|
||||
int i;
|
||||
for (i = 0; '0' <= **str && **str <= '9'; ++*str) {
|
||||
|
@ -129,11 +110,6 @@ static int __fmt_atoi(const char **str) {
|
|||
* @vforksafe if floating point isn't used
|
||||
*/
|
||||
hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||
union {
|
||||
double d;
|
||||
uint32_t u[2];
|
||||
uint64_t q;
|
||||
} pun;
|
||||
long ld;
|
||||
void *p;
|
||||
unsigned u;
|
||||
|
@ -145,13 +121,12 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
|||
const char *alphabet;
|
||||
int (*out)(const char *, void *, size_t);
|
||||
unsigned char signbit, log2base;
|
||||
int c, d, k, w, n, i1, ui, bw, bex;
|
||||
char *s, *q, *se, *mem, qchar, special[8];
|
||||
int sgn, alt, sign, prec, prec1, flags, width, decpt, lasterr;
|
||||
char *s, *q, qchar;
|
||||
int d, w, n;
|
||||
int sign, prec, flags, width, lasterr;
|
||||
|
||||
lasterr = errno;
|
||||
out = fn ? fn : (void *)missingno;
|
||||
mem = 0;
|
||||
|
||||
while (*format) {
|
||||
if (*format != '%') {
|
||||
|
@ -361,7 +336,6 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'c':
|
||||
prec = 1;
|
||||
flags |= FLAGS_PRECISION;
|
||||
|
@ -369,12 +343,10 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
|||
p = charbuf;
|
||||
charbuf[0] = va_arg(va, int);
|
||||
goto FormatString;
|
||||
|
||||
case 'm':
|
||||
p = weaken(strerror) ? weaken(strerror)(lasterr) : "?";
|
||||
signbit = 0;
|
||||
goto FormatString;
|
||||
|
||||
case 'r':
|
||||
// undocumented %r specifier
|
||||
// used for good carriage return
|
||||
|
@ -385,11 +357,9 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
|||
p = "\r\e[K";
|
||||
goto FormatString;
|
||||
}
|
||||
|
||||
case 'q':
|
||||
flags |= FLAGS_QUOTE;
|
||||
/* fallthrough */
|
||||
|
||||
case 's':
|
||||
p = va_arg(va, void *);
|
||||
FormatString:
|
||||
|
@ -397,369 +367,40 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
|||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
// nonstandard %n specifier
|
||||
// used to print newlines that work in raw terminal modes
|
||||
if (__nomultics) PUT('\r');
|
||||
PUT('\n');
|
||||
if (__nomultics) __FMT_PUT('\r');
|
||||
__FMT_PUT('\n');
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
case 'f':
|
||||
if (!(flags & FLAGS_PRECISION)) prec = 6;
|
||||
if (longdouble) {
|
||||
pun.d = va_arg(va, long double);
|
||||
} else {
|
||||
pun.d = va_arg(va, double);
|
||||
}
|
||||
FormatDtoa:
|
||||
case 'G':
|
||||
case 'g':
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'a':
|
||||
case 'A':
|
||||
if (!weaken(__fmt_dtoa)) {
|
||||
p = "?";
|
||||
goto FormatThatThing;
|
||||
}
|
||||
assert(!mem);
|
||||
s = mem = weaken(__fmt_dtoa)(pun.d, 3, prec, &decpt, &sgn, &se);
|
||||
if (decpt == 9999) {
|
||||
Format9999:
|
||||
bzero(special, sizeof(special));
|
||||
p = q = special;
|
||||
if (sgn) {
|
||||
*q++ = '-';
|
||||
} else if (flags & FLAGS_PLUS) {
|
||||
*q++ = '+';
|
||||
} else if (flags & FLAGS_SPACE) {
|
||||
*q++ = ' ';
|
||||
}
|
||||
memcpy(q, kSpecialFloats[*s == 'N'][d >= 'a'], 4);
|
||||
FormatThatThing:
|
||||
__fmt_free_dtoa(&mem);
|
||||
mem = 0;
|
||||
prec = alt = 0;
|
||||
prec = 0;
|
||||
flags &= ~(FLAGS_PRECISION | FLAGS_PLUS | FLAGS_SPACE);
|
||||
goto FormatString;
|
||||
}
|
||||
FormatReal:
|
||||
if (sgn) sign = '-';
|
||||
if (prec > 0) width -= prec;
|
||||
if (width > 0) {
|
||||
if (sign) --width;
|
||||
if (decpt <= 0) {
|
||||
--width;
|
||||
if (prec > 0) --width;
|
||||
} else {
|
||||
if (s == se) decpt = 1;
|
||||
width -= decpt;
|
||||
if (prec > 0 || alt) --width;
|
||||
}
|
||||
}
|
||||
if (width > 0 && !(flags & FLAGS_LEFT)) {
|
||||
if (flags & FLAGS_ZEROPAD) {
|
||||
if (sign) PUT(sign);
|
||||
sign = 0;
|
||||
do PUT('0');
|
||||
while (--width > 0);
|
||||
} else {
|
||||
do PUT(' ');
|
||||
while (--width > 0);
|
||||
}
|
||||
}
|
||||
if (sign) PUT(sign);
|
||||
if (decpt <= 0) {
|
||||
PUT('0');
|
||||
if (prec > 0 || alt) PUT('.');
|
||||
while (decpt < 0) {
|
||||
PUT('0');
|
||||
prec--;
|
||||
decpt++;
|
||||
}
|
||||
} else {
|
||||
do {
|
||||
if ((c = *s)) {
|
||||
s++;
|
||||
} else {
|
||||
c = '0';
|
||||
}
|
||||
PUT(c);
|
||||
} while (--decpt > 0);
|
||||
if (prec > 0 || alt) PUT('.');
|
||||
}
|
||||
while (--prec >= 0) {
|
||||
if ((c = *s)) {
|
||||
s++;
|
||||
} else {
|
||||
c = '0';
|
||||
}
|
||||
PUT(c);
|
||||
}
|
||||
while (--width >= 0) {
|
||||
PUT(' ');
|
||||
}
|
||||
__fmt_free_dtoa(&mem);
|
||||
continue;
|
||||
|
||||
case 'G':
|
||||
case 'g':
|
||||
if (!(flags & FLAGS_PRECISION)) prec = 6;
|
||||
if (longdouble) {
|
||||
pun.d = va_arg(va, long double);
|
||||
} else {
|
||||
pun.d = va_arg(va, double);
|
||||
}
|
||||
if (prec < 0) prec = 0;
|
||||
if (!weaken(__fmt_dtoa)) {
|
||||
p = "?";
|
||||
goto FormatThatThing;
|
||||
}
|
||||
assert(!mem);
|
||||
s = mem =
|
||||
weaken(__fmt_dtoa)(pun.d, prec ? 2 : 0, prec, &decpt, &sgn, &se);
|
||||
if (decpt == 9999) goto Format9999;
|
||||
c = se - s;
|
||||
prec1 = prec;
|
||||
if (!prec) {
|
||||
prec = c;
|
||||
prec1 = c + (s[1] || alt ? 5 : 4);
|
||||
}
|
||||
if (decpt > -4 && decpt <= prec1) {
|
||||
if (alt) {
|
||||
prec -= decpt;
|
||||
} else {
|
||||
prec = c - decpt;
|
||||
}
|
||||
if (prec < 0) prec = 0;
|
||||
goto FormatReal;
|
||||
}
|
||||
d -= 2;
|
||||
if (!alt && prec > c) prec = c;
|
||||
--prec;
|
||||
goto FormatExpo;
|
||||
|
||||
case 'e':
|
||||
case 'E':
|
||||
if (!(flags & FLAGS_PRECISION)) prec = 6;
|
||||
if (longdouble) {
|
||||
pun.d = va_arg(va, long double);
|
||||
} else {
|
||||
pun.d = va_arg(va, double);
|
||||
}
|
||||
if (prec < 0) prec = 0;
|
||||
if (!weaken(__fmt_dtoa)) {
|
||||
p = "?";
|
||||
goto FormatThatThing;
|
||||
}
|
||||
assert(!mem);
|
||||
s = mem = weaken(__fmt_dtoa)(pun.d, 2, prec + 1, &decpt, &sgn, &se);
|
||||
if (decpt == 9999) goto Format9999;
|
||||
FormatExpo:
|
||||
if (sgn) sign = '-';
|
||||
if ((width -= prec + 5) > 0) {
|
||||
if (sign) --width;
|
||||
if (prec || alt) --width;
|
||||
}
|
||||
if ((c = --decpt) < 0) c = -c;
|
||||
while (c >= 100) {
|
||||
--width;
|
||||
c /= 10;
|
||||
}
|
||||
if (width > 0 && !(flags & FLAGS_LEFT)) {
|
||||
if (flags & FLAGS_ZEROPAD) {
|
||||
if (sign) PUT(sign);
|
||||
sign = 0;
|
||||
do PUT('0');
|
||||
while (--width > 0);
|
||||
} else {
|
||||
do PUT(' ');
|
||||
while (--width > 0);
|
||||
}
|
||||
}
|
||||
if (sign) PUT(sign);
|
||||
PUT(*s++);
|
||||
if (prec || alt) PUT('.');
|
||||
while (--prec >= 0) {
|
||||
if ((c = *s)) {
|
||||
s++;
|
||||
} else {
|
||||
c = '0';
|
||||
}
|
||||
PUT(c);
|
||||
}
|
||||
__fmt_free_dtoa(&mem);
|
||||
PUT(d);
|
||||
if (decpt < 0) {
|
||||
PUT('-');
|
||||
decpt = -decpt;
|
||||
} else {
|
||||
PUT('+');
|
||||
}
|
||||
for (c = 2, k = 10; 10 * k <= decpt; c++) k *= 10;
|
||||
for (;;) {
|
||||
i1 = decpt / k;
|
||||
PUT(i1 + '0');
|
||||
if (--c <= 0) break;
|
||||
decpt -= i1 * k;
|
||||
decpt *= 10;
|
||||
}
|
||||
while (--width >= 0) {
|
||||
PUT(' ');
|
||||
}
|
||||
continue;
|
||||
|
||||
case 'a':
|
||||
alphabet = "0123456789abcdefpx";
|
||||
goto FormatBinary;
|
||||
case 'A':
|
||||
alphabet = "0123456789ABCDEFPX";
|
||||
FormatBinary:
|
||||
if (longdouble) {
|
||||
pun.d = va_arg(va, long double);
|
||||
} else {
|
||||
pun.d = va_arg(va, double);
|
||||
}
|
||||
if ((pun.u[1] & 0x7ff00000) == 0x7ff00000) {
|
||||
goto FormatDtoa;
|
||||
}
|
||||
if (pun.u[1] & 0x80000000) {
|
||||
sign = '-';
|
||||
pun.u[1] &= 0x7fffffff;
|
||||
}
|
||||
if (pun.d) {
|
||||
c = '1';
|
||||
bex = (pun.u[1] >> 20) - 1023;
|
||||
pun.u[1] &= 0xfffff;
|
||||
if (bex == -1023) {
|
||||
++bex;
|
||||
if (pun.u[1]) {
|
||||
do {
|
||||
--bex;
|
||||
pun.u[1] <<= 1;
|
||||
if (pun.u[0] & 0x80000000) pun.u[1] |= 1;
|
||||
pun.u[0] <<= 1;
|
||||
} while (pun.u[1] < 0x100000);
|
||||
} else {
|
||||
while (!(pun.u[0] & 0x80000000)) {
|
||||
--bex;
|
||||
pun.u[0] <<= 1;
|
||||
}
|
||||
bex -= 21;
|
||||
pun.u[1] = pun.u[0] >> 11;
|
||||
pun.u[0] <<= 21;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
c = '0';
|
||||
bex = 0;
|
||||
}
|
||||
if (flags & FLAGS_PRECISION) {
|
||||
if (prec > 13) prec = 13;
|
||||
if (pun.d && prec < 13) {
|
||||
pun.u[1] |= 0x100000;
|
||||
if (prec < 5) {
|
||||
ui = 1u << ((5 - prec) * 4 - 1);
|
||||
if (pun.u[1] & ui) {
|
||||
if (pun.u[1] & ((ui - 1) | (ui << 1)) || pun.u[0]) {
|
||||
pun.u[1] += ui;
|
||||
BexCheck:
|
||||
if (pun.u[1] & 0x200000) {
|
||||
++bex;
|
||||
pun.u[1] >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (prec == 5) {
|
||||
if (pun.u[0] & 0x80000000) {
|
||||
BumpIt:
|
||||
++pun.u[1];
|
||||
goto BexCheck;
|
||||
}
|
||||
} else {
|
||||
i1 = (13 - prec) * 4;
|
||||
ui = 1u << (i1 - 1);
|
||||
if (pun.u[0] & ui && pun.u[0] & ((ui - 1) | (ui << 1))) {
|
||||
pun.u[0] += ui;
|
||||
if (!(pun.u[0] >> i1)) goto BumpIt;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ((ui = pun.u[0])) {
|
||||
ui = __builtin_ctz(ui);
|
||||
prec = 6 + ((32 - ROUNDDOWN(ui, 4)) >> 2) - 1;
|
||||
} else if ((ui = pun.u[1] & 0xfffff)) {
|
||||
ui = __builtin_ctz(ui);
|
||||
prec = (20 - ROUNDDOWN(ui, 4)) >> 2;
|
||||
} else {
|
||||
prec = 0;
|
||||
}
|
||||
}
|
||||
bw = 1;
|
||||
if (bex) {
|
||||
if ((i1 = bex) < 0) i1 = -i1;
|
||||
while (i1 >= 10) {
|
||||
++bw;
|
||||
i1 /= 10;
|
||||
}
|
||||
}
|
||||
if (pun.u[1] & 0x80000000) {
|
||||
pun.u[1] &= 0x7fffffff;
|
||||
if (pun.d || sign) sign = '-';
|
||||
}
|
||||
if ((width -= bw + 5) > 0) {
|
||||
if (sign) --width;
|
||||
if (prec || alt) --width;
|
||||
}
|
||||
if (pun.q && prec > 0) {
|
||||
width -= ROUNDUP(bsrl(pun.q) + 1, 4) >> 2;
|
||||
}
|
||||
if (width > 0 && !(flags & FLAGS_LEFT)) {
|
||||
if (flags & FLAGS_ZEROPAD) {
|
||||
if (sign) {
|
||||
PUT(sign);
|
||||
sign = 0;
|
||||
}
|
||||
do PUT('0');
|
||||
while (--width > 0);
|
||||
} else {
|
||||
do PUT(' ');
|
||||
while (--width > 0);
|
||||
}
|
||||
}
|
||||
if (sign) PUT(sign);
|
||||
PUT('0');
|
||||
PUT(alphabet[17]);
|
||||
PUT(c);
|
||||
if (prec > 0 || alt) PUT('.');
|
||||
while (prec-- > 0) {
|
||||
PUT(alphabet[(pun.q >> 48) & 0xf]);
|
||||
pun.q <<= 4;
|
||||
}
|
||||
PUT(alphabet[16]);
|
||||
if (bex < 0) {
|
||||
PUT('-');
|
||||
bex = -bex;
|
||||
} else {
|
||||
PUT('+');
|
||||
}
|
||||
for (c = 1; 10 * c <= bex;) c *= 10;
|
||||
for (;;) {
|
||||
i1 = bex / c;
|
||||
PUT('0' + i1);
|
||||
if (!--bw) break;
|
||||
bex -= i1 * c;
|
||||
bex *= 10;
|
||||
if (weaken(__fmt_dtoa)(out, arg, d, flags, prec, sign, width,
|
||||
longdouble, qchar, signbit, alphabet,
|
||||
va) == -1) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case '%':
|
||||
PUT('%');
|
||||
__FMT_PUT('%');
|
||||
break;
|
||||
|
||||
default:
|
||||
PUT(format[-1]);
|
||||
__FMT_PUT(format[-1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(!mem);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,19 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_FMT_FMTS_H_
|
||||
#define COSMOPOLITAN_LIBC_FMT_FMTS_H_
|
||||
#ifndef COSMOPOLITAN_LIBC_FMT_FMT_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_FMT_FMT_INTERNAL_H_
|
||||
|
||||
#define PRINTF_NTOA_BUFFER_SIZE 144
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define __FMT_PUT(C) \
|
||||
do { \
|
||||
char Buf[1] = {C}; \
|
||||
if (out(Buf, arg, 1) == -1) { \
|
||||
return -1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
int __fmt_pad(int (*)(const char *, void *, size_t), void *,
|
||||
unsigned long) hidden;
|
||||
int __fmt_stoa(int (*)(const char *, void *, size_t), void *, void *,
|
||||
|
@ -14,8 +22,9 @@ int __fmt_stoa(int (*)(const char *, void *, size_t), void *, void *,
|
|||
int __fmt_ntoa(int (*)(const char *, void *, size_t), void *, va_list,
|
||||
unsigned char, unsigned long, unsigned long, unsigned long,
|
||||
unsigned char, const char *) hidden;
|
||||
char *__fmt_dtoa(double, int, int, int *, int *, char **) hidden;
|
||||
int __fmt_dtoa(int (*)(const char *, void *, size_t), void *, int, int, int,
|
||||
int, int, bool, char, unsigned char, const char *, va_list);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_FMT_FMTS_H_ */
|
||||
#endif /* COSMOPOLITAN_LIBC_FMT_FMT_INTERNAL_H_ */
|
|
@ -20,7 +20,7 @@
|
|||
#include "libc/assert.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/divmod10.internal.h"
|
||||
#include "libc/fmt/fmts.h"
|
||||
#include "libc/fmt/fmt.internal.h"
|
||||
#include "libc/fmt/internal.h"
|
||||
#include "libc/limits.h"
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/fmts.h"
|
||||
#include "libc/fmt/fmt.internal.h"
|
||||
|
||||
int __fmt_pad(int out(const char *, void *, size_t), void *arg,
|
||||
unsigned long n) {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_FMT_PFLINK_H_
|
||||
#define COSMOPOLITAN_LIBC_FMT_PFLINK_H_
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/fmts.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
|
@ -23,7 +22,6 @@
|
|||
({ \
|
||||
if (___PFLINK(FMT, strpbrk, "faAeg")) STATIC_YOINK("__fmt_dtoa"); \
|
||||
if (___PFLINK(FMT, strpbrk, "cmrqs")) { \
|
||||
if (___PFLINK(FMT, strchr, '#')) STATIC_YOINK("kCp437"); \
|
||||
if (___PFLINK(FMT, strstr, "%m")) STATIC_YOINK("strerror"); \
|
||||
if (!IsTiny() && (___PFLINK(FMT, strstr, "%*") || \
|
||||
___PFLINK(FMT, strpbrk, "0123456789"))) { \
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/fmt/fmts.h"
|
||||
#include "libc/fmt/fmt.internal.h"
|
||||
#include "libc/fmt/internal.h"
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
#include "libc/str/str.h"
|
||||
|
@ -46,7 +46,7 @@ static int __fmt_stoa_wide(out_f out, void *a, uint64_t w) {
|
|||
|
||||
static int __fmt_stoa_bing(out_f out, void *a, uint64_t w) {
|
||||
char buf[8];
|
||||
w = tpenc((*weaken(kCp437))[w & 0xFF]);
|
||||
w = tpenc(kCp437[w & 0xFF]);
|
||||
WRITE64LE(buf, w);
|
||||
return out(buf, a, w ? (bsr(w) >> 3) + 1 : 1);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
.include "o/libc/nt/codegen.inc"
|
||||
.imp PowerProf,__imp_SetSuspendState,SetSuspendState,0
|
||||
.imp PowrProf,__imp_SetSuspendState,SetSuspendState,0
|
||||
|
||||
.text.windows
|
||||
SetSuspendState:
|
|
@ -4052,10 +4052,10 @@ imp 'SetTcpEntry' SetTcpEntry iphlpapi 0
|
|||
imp 'UnenableRouter' UnenableRouter iphlpapi 0
|
||||
imp 'UnregisterInterfaceTimestampConfigChange' UnregisterInterfaceTimestampConfigChange iphlpapi 0
|
||||
|
||||
# POWERPROF.DLL
|
||||
# POWRPROF.DLL
|
||||
#
|
||||
# Name Actual DLL Hint Arity
|
||||
imp 'SetSuspendState' SetSuspendState PowerProf 0 3
|
||||
imp 'SetSuspendState' SetSuspendState PowrProf 0 3
|
||||
|
||||
# PDH.DLL
|
||||
#
|
||||
|
|
|
@ -311,22 +311,22 @@ $(LIBC_NT_IPHLPAPI_A).pkg: \
|
|||
|
||||
#───────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
LIBC_NT_ARTIFACTS += LIBC_NT_POWERPROF_A
|
||||
LIBC_NT_POWERPROF = $(LIBC_NT_POWERPROF_A_DEPS) $(LIBC_NT_POWERPROF_A)
|
||||
LIBC_NT_POWERPROF_A = o/$(MODE)/libc/nt/powerprof.a
|
||||
LIBC_NT_POWERPROF_A_SRCS := $(wildcard libc/nt/PowerProf/*.s)
|
||||
LIBC_NT_POWERPROF_A_OBJS = $(LIBC_NT_POWERPROF_A_SRCS:%.s=o/$(MODE)/%.o)
|
||||
LIBC_NT_POWERPROF_A_CHECKS = $(LIBC_NT_POWERPROF_A).pkg
|
||||
LIBC_NT_POWERPROF_A_DIRECTDEPS = LIBC_NT_KERNEL32
|
||||
LIBC_NT_POWERPROF_A_DEPS := \
|
||||
$(call uniq,$(foreach x,$(LIBC_NT_POWERPROF_A_DIRECTDEPS),$($(x))))
|
||||
$(LIBC_NT_POWERPROF_A): \
|
||||
libc/nt/PowerProf/ \
|
||||
$(LIBC_NT_POWERPROF_A).pkg \
|
||||
$(LIBC_NT_POWERPROF_A_OBJS)
|
||||
$(LIBC_NT_POWERPROF_A).pkg: \
|
||||
$(LIBC_NT_POWERPROF_A_OBJS) \
|
||||
$(foreach x,$(LIBC_NT_POWERPROF_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
LIBC_NT_ARTIFACTS += LIBC_NT_POWRPROF_A
|
||||
LIBC_NT_POWRPROF = $(LIBC_NT_POWRPROF_A_DEPS) $(LIBC_NT_POWRPROF_A)
|
||||
LIBC_NT_POWRPROF_A = o/$(MODE)/libc/nt/powrprof.a
|
||||
LIBC_NT_POWRPROF_A_SRCS := $(wildcard libc/nt/PowrProf/*.s)
|
||||
LIBC_NT_POWRPROF_A_OBJS = $(LIBC_NT_POWRPROF_A_SRCS:%.s=o/$(MODE)/%.o)
|
||||
LIBC_NT_POWRPROF_A_CHECKS = $(LIBC_NT_POWRPROF_A).pkg
|
||||
LIBC_NT_POWRPROF_A_DIRECTDEPS = LIBC_NT_KERNEL32
|
||||
LIBC_NT_POWRPROF_A_DEPS := \
|
||||
$(call uniq,$(foreach x,$(LIBC_NT_POWRPROF_A_DIRECTDEPS),$($(x))))
|
||||
$(LIBC_NT_POWRPROF_A): \
|
||||
libc/nt/PowrProf/ \
|
||||
$(LIBC_NT_POWRPROF_A).pkg \
|
||||
$(LIBC_NT_POWRPROF_A_OBJS)
|
||||
$(LIBC_NT_POWRPROF_A).pkg: \
|
||||
$(LIBC_NT_POWRPROF_A_OBJS) \
|
||||
$(foreach x,$(LIBC_NT_POWRPROF_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
#───────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
|
@ -16,10 +16,379 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/fmts.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/fmt/fmt.internal.h"
|
||||
#include "libc/fmt/internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
#include "third_party/gdtoa/gdtoa.h"
|
||||
|
||||
char *__fmt_dtoa(double d0, int mode, int ndigits, int *decpt, int *sign,
|
||||
char **rve) {
|
||||
return dtoa(d0, mode, ndigits, decpt, sign, rve);
|
||||
static const char kSpecialFloats[2][2][4] = {{"INF", "inf"}, {"NAN", "nan"}};
|
||||
|
||||
static void __fmt_free_dtoa(char **mem) {
|
||||
if (*mem) {
|
||||
freedtoa(*mem);
|
||||
*mem = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int __fmt_dtoa(int (*out)(const char *, void *, size_t), void *arg, int d,
|
||||
int flags, int prec, int sign, int width, bool longdouble,
|
||||
char qchar, unsigned char signbit, const char *alphabet,
|
||||
va_list va) {
|
||||
union {
|
||||
double d;
|
||||
uint32_t u[2];
|
||||
uint64_t q;
|
||||
} pun;
|
||||
int c, k, i1, ui, bw, bex, sgn, prec1, decpt;
|
||||
char *s, *p, *q, *se, *mem, special[8];
|
||||
mem = 0;
|
||||
switch (d) {
|
||||
case 'F':
|
||||
case 'f':
|
||||
if (!(flags & FLAGS_PRECISION)) prec = 6;
|
||||
if (longdouble) {
|
||||
pun.d = va_arg(va, long double);
|
||||
} else {
|
||||
pun.d = va_arg(va, double);
|
||||
}
|
||||
FormatDtoa:
|
||||
assert(!mem);
|
||||
s = mem = dtoa(pun.d, 3, prec, &decpt, &sgn, &se);
|
||||
if (decpt == 9999) {
|
||||
Format9999:
|
||||
bzero(special, sizeof(special));
|
||||
p = q = special;
|
||||
if (sgn) {
|
||||
*q++ = '-';
|
||||
} else if (flags & FLAGS_PLUS) {
|
||||
*q++ = '+';
|
||||
} else if (flags & FLAGS_SPACE) {
|
||||
*q++ = ' ';
|
||||
}
|
||||
memcpy(q, kSpecialFloats[*s == 'N'][d >= 'a'], 4);
|
||||
FormatThatThing:
|
||||
__fmt_free_dtoa(&mem);
|
||||
mem = 0;
|
||||
prec = 0;
|
||||
flags &= ~(FLAGS_PRECISION | FLAGS_PLUS | FLAGS_SPACE);
|
||||
goto FormatString;
|
||||
}
|
||||
FormatReal:
|
||||
if (sgn) sign = '-';
|
||||
if (prec > 0) width -= prec;
|
||||
if (width > 0) {
|
||||
if (sign) --width;
|
||||
if (decpt <= 0) {
|
||||
--width;
|
||||
if (prec > 0) --width;
|
||||
} else {
|
||||
if (s == se) decpt = 1;
|
||||
width -= decpt;
|
||||
if (prec > 0) --width;
|
||||
}
|
||||
}
|
||||
if (width > 0 && !(flags & FLAGS_LEFT)) {
|
||||
if (flags & FLAGS_ZEROPAD) {
|
||||
if (sign) __FMT_PUT(sign);
|
||||
sign = 0;
|
||||
do
|
||||
__FMT_PUT('0');
|
||||
while (--width > 0);
|
||||
} else {
|
||||
do
|
||||
__FMT_PUT(' ');
|
||||
while (--width > 0);
|
||||
}
|
||||
}
|
||||
if (sign) __FMT_PUT(sign);
|
||||
if (decpt <= 0) {
|
||||
__FMT_PUT('0');
|
||||
if (prec > 0) __FMT_PUT('.');
|
||||
while (decpt < 0) {
|
||||
__FMT_PUT('0');
|
||||
prec--;
|
||||
decpt++;
|
||||
}
|
||||
} else {
|
||||
do {
|
||||
if ((c = *s)) {
|
||||
s++;
|
||||
} else {
|
||||
c = '0';
|
||||
}
|
||||
__FMT_PUT(c);
|
||||
} while (--decpt > 0);
|
||||
if (prec > 0) __FMT_PUT('.');
|
||||
}
|
||||
while (--prec >= 0) {
|
||||
if ((c = *s)) {
|
||||
s++;
|
||||
} else {
|
||||
c = '0';
|
||||
}
|
||||
__FMT_PUT(c);
|
||||
}
|
||||
while (--width >= 0) {
|
||||
__FMT_PUT(' ');
|
||||
}
|
||||
__fmt_free_dtoa(&mem);
|
||||
break;
|
||||
|
||||
case 'G':
|
||||
case 'g':
|
||||
if (!(flags & FLAGS_PRECISION)) prec = 6;
|
||||
if (longdouble) {
|
||||
pun.d = va_arg(va, long double);
|
||||
} else {
|
||||
pun.d = va_arg(va, double);
|
||||
}
|
||||
if (prec < 0) prec = 0;
|
||||
assert(!mem);
|
||||
s = mem = dtoa(pun.d, prec ? 2 : 0, prec, &decpt, &sgn, &se);
|
||||
if (decpt == 9999) goto Format9999;
|
||||
c = se - s;
|
||||
prec1 = prec;
|
||||
if (!prec) {
|
||||
prec = c;
|
||||
prec1 = c + (s[1] ? 5 : 4);
|
||||
}
|
||||
if (decpt > -4 && decpt <= prec1) {
|
||||
prec = c - decpt;
|
||||
if (prec < 0) prec = 0;
|
||||
goto FormatReal;
|
||||
}
|
||||
d -= 2;
|
||||
if (prec > c) prec = c;
|
||||
--prec;
|
||||
goto FormatExpo;
|
||||
|
||||
case 'e':
|
||||
case 'E':
|
||||
if (!(flags & FLAGS_PRECISION)) prec = 6;
|
||||
if (longdouble) {
|
||||
pun.d = va_arg(va, long double);
|
||||
} else {
|
||||
pun.d = va_arg(va, double);
|
||||
}
|
||||
if (prec < 0) prec = 0;
|
||||
if (!dtoa) {
|
||||
p = "?";
|
||||
goto FormatThatThing;
|
||||
}
|
||||
assert(!mem);
|
||||
s = mem = dtoa(pun.d, 2, prec + 1, &decpt, &sgn, &se);
|
||||
if (decpt == 9999) goto Format9999;
|
||||
FormatExpo:
|
||||
if (sgn) sign = '-';
|
||||
if ((width -= prec + 5) > 0) {
|
||||
if (sign) --width;
|
||||
if (prec) --width;
|
||||
}
|
||||
if ((c = --decpt) < 0) c = -c;
|
||||
while (c >= 100) {
|
||||
--width;
|
||||
c /= 10;
|
||||
}
|
||||
if (width > 0 && !(flags & FLAGS_LEFT)) {
|
||||
if (flags & FLAGS_ZEROPAD) {
|
||||
if (sign) __FMT_PUT(sign);
|
||||
sign = 0;
|
||||
do
|
||||
__FMT_PUT('0');
|
||||
while (--width > 0);
|
||||
} else {
|
||||
do
|
||||
__FMT_PUT(' ');
|
||||
while (--width > 0);
|
||||
}
|
||||
}
|
||||
if (sign) __FMT_PUT(sign);
|
||||
__FMT_PUT(*s++);
|
||||
if (prec) __FMT_PUT('.');
|
||||
while (--prec >= 0) {
|
||||
if ((c = *s)) {
|
||||
s++;
|
||||
} else {
|
||||
c = '0';
|
||||
}
|
||||
__FMT_PUT(c);
|
||||
}
|
||||
__fmt_free_dtoa(&mem);
|
||||
__FMT_PUT(d);
|
||||
if (decpt < 0) {
|
||||
__FMT_PUT('-');
|
||||
decpt = -decpt;
|
||||
} else {
|
||||
__FMT_PUT('+');
|
||||
}
|
||||
for (c = 2, k = 10; 10 * k <= decpt; c++) k *= 10;
|
||||
for (;;) {
|
||||
i1 = decpt / k;
|
||||
__FMT_PUT(i1 + '0');
|
||||
if (--c <= 0) break;
|
||||
decpt -= i1 * k;
|
||||
decpt *= 10;
|
||||
}
|
||||
while (--width >= 0) {
|
||||
__FMT_PUT(' ');
|
||||
}
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
alphabet = "0123456789abcdefpx";
|
||||
goto FormatBinary;
|
||||
case 'A':
|
||||
alphabet = "0123456789ABCDEFPX";
|
||||
FormatBinary:
|
||||
if (longdouble) {
|
||||
pun.d = va_arg(va, long double);
|
||||
} else {
|
||||
pun.d = va_arg(va, double);
|
||||
}
|
||||
if ((pun.u[1] & 0x7ff00000) == 0x7ff00000) {
|
||||
goto FormatDtoa;
|
||||
}
|
||||
if (pun.u[1] & 0x80000000) {
|
||||
sign = '-';
|
||||
pun.u[1] &= 0x7fffffff;
|
||||
}
|
||||
if (pun.d) {
|
||||
c = '1';
|
||||
bex = (pun.u[1] >> 20) - 1023;
|
||||
pun.u[1] &= 0xfffff;
|
||||
if (bex == -1023) {
|
||||
++bex;
|
||||
if (pun.u[1]) {
|
||||
do {
|
||||
--bex;
|
||||
pun.u[1] <<= 1;
|
||||
if (pun.u[0] & 0x80000000) pun.u[1] |= 1;
|
||||
pun.u[0] <<= 1;
|
||||
} while (pun.u[1] < 0x100000);
|
||||
} else {
|
||||
while (!(pun.u[0] & 0x80000000)) {
|
||||
--bex;
|
||||
pun.u[0] <<= 1;
|
||||
}
|
||||
bex -= 21;
|
||||
pun.u[1] = pun.u[0] >> 11;
|
||||
pun.u[0] <<= 21;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
c = '0';
|
||||
bex = 0;
|
||||
}
|
||||
if (flags & FLAGS_PRECISION) {
|
||||
if (prec > 13) prec = 13;
|
||||
if (pun.d && prec < 13) {
|
||||
pun.u[1] |= 0x100000;
|
||||
if (prec < 5) {
|
||||
ui = 1u << ((5 - prec) * 4 - 1);
|
||||
if (pun.u[1] & ui) {
|
||||
if (pun.u[1] & ((ui - 1) | (ui << 1)) || pun.u[0]) {
|
||||
pun.u[1] += ui;
|
||||
BexCheck:
|
||||
if (pun.u[1] & 0x200000) {
|
||||
++bex;
|
||||
pun.u[1] >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (prec == 5) {
|
||||
if (pun.u[0] & 0x80000000) {
|
||||
BumpIt:
|
||||
++pun.u[1];
|
||||
goto BexCheck;
|
||||
}
|
||||
} else {
|
||||
i1 = (13 - prec) * 4;
|
||||
ui = 1u << (i1 - 1);
|
||||
if (pun.u[0] & ui && pun.u[0] & ((ui - 1) | (ui << 1))) {
|
||||
pun.u[0] += ui;
|
||||
if (!(pun.u[0] >> i1)) goto BumpIt;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ((ui = pun.u[0])) {
|
||||
ui = __builtin_ctz(ui);
|
||||
prec = 6 + ((32 - ROUNDDOWN(ui, 4)) >> 2) - 1;
|
||||
} else if ((ui = pun.u[1] & 0xfffff)) {
|
||||
ui = __builtin_ctz(ui);
|
||||
prec = (20 - ROUNDDOWN(ui, 4)) >> 2;
|
||||
} else {
|
||||
prec = 0;
|
||||
}
|
||||
}
|
||||
bw = 1;
|
||||
if (bex) {
|
||||
if ((i1 = bex) < 0) i1 = -i1;
|
||||
while (i1 >= 10) {
|
||||
++bw;
|
||||
i1 /= 10;
|
||||
}
|
||||
}
|
||||
if (pun.u[1] & 0x80000000) {
|
||||
pun.u[1] &= 0x7fffffff;
|
||||
if (pun.d || sign) sign = '-';
|
||||
}
|
||||
if ((width -= bw + 5) > 0) {
|
||||
if (sign) --width;
|
||||
if (prec) --width;
|
||||
}
|
||||
if (pun.q && prec > 0) {
|
||||
width -= ROUNDUP(bsrl(pun.q) + 1, 4) >> 2;
|
||||
}
|
||||
if (width > 0 && !(flags & FLAGS_LEFT)) {
|
||||
if (flags & FLAGS_ZEROPAD) {
|
||||
if (sign) {
|
||||
__FMT_PUT(sign);
|
||||
sign = 0;
|
||||
}
|
||||
do
|
||||
__FMT_PUT('0');
|
||||
while (--width > 0);
|
||||
} else {
|
||||
do
|
||||
__FMT_PUT(' ');
|
||||
while (--width > 0);
|
||||
}
|
||||
}
|
||||
if (sign) __FMT_PUT(sign);
|
||||
__FMT_PUT('0');
|
||||
__FMT_PUT(alphabet[17]);
|
||||
__FMT_PUT(c);
|
||||
if (prec > 0) __FMT_PUT('.');
|
||||
while (prec-- > 0) {
|
||||
__FMT_PUT(alphabet[(pun.q >> 48) & 0xf]);
|
||||
pun.q <<= 4;
|
||||
}
|
||||
__FMT_PUT(alphabet[16]);
|
||||
if (bex < 0) {
|
||||
__FMT_PUT('-');
|
||||
bex = -bex;
|
||||
} else {
|
||||
__FMT_PUT('+');
|
||||
}
|
||||
for (c = 1; 10 * c <= bex;) c *= 10;
|
||||
for (;;) {
|
||||
i1 = bex / c;
|
||||
__FMT_PUT('0' + i1);
|
||||
if (!--bw) break;
|
||||
bex -= i1 * c;
|
||||
bex *= 10;
|
||||
}
|
||||
break;
|
||||
|
||||
FormatString:
|
||||
if (__fmt_stoa(out, arg, p, flags, prec, width, signbit, qchar) == -1) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
34
third_party/lua/lapi.c
vendored
34
third_party/lua/lapi.c
vendored
|
@ -1001,6 +1001,15 @@ LUA_API void lua_setfield (lua_State *L, int idx, const char *k) {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* lua_seti [-1, +0, e]
|
||||
*
|
||||
* Does the equivalent to t[n] = v, where t is the value at the given index
|
||||
* and v is the value on the top of the stack.
|
||||
*
|
||||
* This function pops the value from the stack. As in Lua, this function may
|
||||
* trigger a metamethod for the "newindex" event (see §2.4).
|
||||
*/
|
||||
LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
|
||||
TValue *t;
|
||||
const TValue *slot;
|
||||
|
@ -1033,11 +1042,27 @@ static void aux_rawset (lua_State *L, int idx, TValue *key, int n) {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* lua_rawset [-2, +0, m]
|
||||
*
|
||||
* Similar to lua_settable, but does a raw assignment (i.e., without
|
||||
* metamethods).
|
||||
*/
|
||||
LUA_API void lua_rawset (lua_State *L, int idx) {
|
||||
aux_rawset(L, idx, s2v(L->top - 2), 2);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* lua_rawsetp [-1, +0, m]
|
||||
*
|
||||
* Does the equivalent of t[p] = v, where t is the table at the given index,
|
||||
* p is encoded as a light userdata, and v is the value on the top of the
|
||||
* stack.
|
||||
*
|
||||
* This function pops the value from the stack. The assignment is raw, that
|
||||
* is, it does not use the __newindex metavalue.
|
||||
*/
|
||||
LUA_API void lua_rawsetp (lua_State *L, int idx, const void *p) {
|
||||
TValue k;
|
||||
setpvalue(&k, cast_voidp(p));
|
||||
|
@ -1045,6 +1070,15 @@ LUA_API void lua_rawsetp (lua_State *L, int idx, const void *p) {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* lua_rawseti [-1, +0, m]
|
||||
*
|
||||
* Does the equivalent of t[i] = v, where t is the table at the given index
|
||||
* and v is the value on the top of the stack.
|
||||
*
|
||||
* This function pops the value from the stack. The assignment is raw, that
|
||||
* is, it does not use the __newindex metavalue.
|
||||
*/
|
||||
LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) {
|
||||
Table *t;
|
||||
lua_lock(L);
|
||||
|
|
1
third_party/lua/llimits.h
vendored
1
third_party/lua/llimits.h
vendored
|
@ -86,7 +86,6 @@ typedef LUAI_UACINT l_uacInt;
|
|||
*/
|
||||
#if defined LUAI_ASSERT
|
||||
#undef NDEBUG
|
||||
#include <assert.h>
|
||||
#define lua_assert(c) assert(c)
|
||||
#endif
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ static const struct sock_filter kSandboxFilter[] = {
|
|||
_SECCOMP_ALLOW_SYSCALL(0x008), // lseek
|
||||
_SECCOMP_ALLOW_SYSCALL(0x009), // mmap
|
||||
_SECCOMP_ALLOW_SYSCALL(0x00b), // munmap
|
||||
_SECCOMP_ALLOW_SYSCALL(0x04f), // getcwd
|
||||
_SECCOMP_ALLOW_SYSCALL(0x003), // close
|
||||
_SECCOMP_ALLOW_SYSCALL(0x010), // ioctl todo
|
||||
_SECCOMP_ALLOW_SYSCALL(0x016), // pipe
|
||||
|
@ -60,6 +61,15 @@ static const struct sock_filter kSandboxFilter[] = {
|
|||
_SECCOMP_ALLOW_SYSCALL(0x127), // preadv
|
||||
_SECCOMP_ALLOW_SYSCALL(0x128), // pwritev
|
||||
_SECCOMP_ALLOW_SYSCALL(0x0d9), // getdents
|
||||
_SECCOMP_ALLOW_SYSCALL(0x027), // getpid
|
||||
_SECCOMP_ALLOW_SYSCALL(0x066), // getuid
|
||||
_SECCOMP_ALLOW_SYSCALL(0x068), // getgid
|
||||
_SECCOMP_ALLOW_SYSCALL(0x06e), // getppid
|
||||
_SECCOMP_ALLOW_SYSCALL(0x06f), // getpgrp
|
||||
_SECCOMP_ALLOW_SYSCALL(0x07c), // getsid
|
||||
_SECCOMP_ALLOW_SYSCALL(0x06b), // geteuid
|
||||
_SECCOMP_ALLOW_SYSCALL(0x06c), // getegid
|
||||
_SECCOMP_ALLOW_SYSCALL(0x061), // getrlimit
|
||||
_SECCOMP_ALLOW_SYSCALL(0x028), // sendfile
|
||||
_SECCOMP_ALLOW_SYSCALL(0x02d), // recvfrom
|
||||
_SECCOMP_ALLOW_SYSCALL(0x033), // getsockname
|
||||
|
@ -67,7 +77,6 @@ static const struct sock_filter kSandboxFilter[] = {
|
|||
_SECCOMP_ALLOW_SYSCALL(0x00f), // rt_sigreturn
|
||||
_SECCOMP_ALLOW_SYSCALL(0x0e4), // clock_gettime
|
||||
_SECCOMP_ALLOW_SYSCALL(0x060), // gettimeofday
|
||||
_SECCOMP_ALLOW_SYSCALL(0x027), // getpid
|
||||
_SECCOMP_ALLOW_SYSCALL(0x03f), // uname
|
||||
_SECCOMP_ALLOW_SYSCALL(0x03c), // exit
|
||||
_SECCOMP_ALLOW_SYSCALL(0x0e7), // exit_group
|
||||
|
|
80
tool/net/demo/unix-info.lua
Normal file
80
tool/net/demo/unix-info.lua
Normal file
|
@ -0,0 +1,80 @@
|
|||
local unix = require 'unix'
|
||||
|
||||
Write('<!doctype html>\r\n')
|
||||
Write('<title>redbean</title>\r\n')
|
||||
Write('<h3>UNIX Information Demo</h3>\r\n')
|
||||
|
||||
Write('<dl>\r\n')
|
||||
Write('<dt>getuid()\r\n')
|
||||
Write(string.format('<dd>%d\r\n', unix.getuid()))
|
||||
Write('<dt>getgid()\r\n')
|
||||
Write(string.format('<dd>%d\r\n', unix.getgid()))
|
||||
Write('<dt>getpid()\r\n')
|
||||
Write(string.format('<dd>%d\r\n', unix.getpid()))
|
||||
Write('<dt>getppid()\r\n')
|
||||
Write(string.format('<dd>%d\r\n', unix.getppid()))
|
||||
Write('<dt>getpgrp()\r\n')
|
||||
Write(string.format('<dd>%d\r\n', unix.getpgrp()))
|
||||
|
||||
Write('<dt>getsid(0)\r\n')
|
||||
sid, errno = unix.getsid(0)
|
||||
if sid then
|
||||
Write(string.format('<dd>%d\r\n', sid))
|
||||
else
|
||||
Write(string.format('<dd>%s\r\n', EscapeHtml(unix.strerrno(errno))))
|
||||
end
|
||||
|
||||
Write('<dt>gethostname()\r\n')
|
||||
Write(string.format('<dd>%s\r\n', EscapeHtml(unix.gethostname())))
|
||||
Write('<dt>getcwd()\r\n')
|
||||
Write(string.format('<dd>%s\r\n', EscapeHtml(unix.getcwd())))
|
||||
|
||||
function PrintResourceLimit(name, id)
|
||||
soft, hard, errno = unix.getrlimit(id)
|
||||
Write(string.format('<dt>getrlimit(%s)\r\n', name))
|
||||
if soft then
|
||||
Write('<dd>')
|
||||
Write('soft ')
|
||||
if soft == -1 then
|
||||
Write('∞')
|
||||
else
|
||||
Write(string.format('%d', soft))
|
||||
end
|
||||
Write('<br>\r\n')
|
||||
Write('hard ')
|
||||
if hard == -1 then
|
||||
Write('∞')
|
||||
else
|
||||
Write(string.format('%d', hard))
|
||||
end
|
||||
Write('\r\n')
|
||||
else
|
||||
Write(string.format('<dd>%s\r\n', EscapeHtml(unix.strerrno(errno))))
|
||||
end
|
||||
end
|
||||
PrintResourceLimit('RLIMIT_AS', unix.RLIMIT_AS)
|
||||
PrintResourceLimit('RLIMIT_RSS', unix.RLIMIT_RSS)
|
||||
PrintResourceLimit('RLIMIT_CPU', unix.RLIMIT_CPU)
|
||||
PrintResourceLimit('RLIMIT_FSIZE', unix.RLIMIT_FSIZE)
|
||||
PrintResourceLimit('RLIMIT_NPROC', unix.RLIMIT_NPROC)
|
||||
PrintResourceLimit('RLIMIT_NOFILE', unix.RLIMIT_NOFILE)
|
||||
|
||||
Write('<dt>siocgifconf()\r\n')
|
||||
Write('<dd>\r\n')
|
||||
ifs, errno = unix.siocgifconf()
|
||||
if ifs then
|
||||
for i = 1,#ifs do
|
||||
if ifs[i].netmask ~= 0 then
|
||||
cidr = 32 - Bsf(ifs[i].netmask)
|
||||
else
|
||||
cidr = 0
|
||||
end
|
||||
Write(string.format('%s %s/%d<br>\r\n',
|
||||
EscapeHtml(ifs[i].name),
|
||||
FormatIp(ifs[i].ip),
|
||||
cidr))
|
||||
end
|
||||
else
|
||||
Write(string.format('%s\r\n', EscapeHtml(unix.strerrno(errno))))
|
||||
end
|
||||
Write('</dl>\r\n')
|
44
tool/net/demo/unix-subprocess.lua
Normal file
44
tool/net/demo/unix-subprocess.lua
Normal file
|
@ -0,0 +1,44 @@
|
|||
-- example of how to run the ls command
|
||||
-- and pipe its output to the http user
|
||||
local unix = require "unix"
|
||||
function main()
|
||||
syscall = 'commandv'
|
||||
ls, errno = unix.commandv("ls")
|
||||
if ls then
|
||||
syscall = 'pipe'
|
||||
reader, writer, errno = unix.pipe()
|
||||
if reader then
|
||||
syscall = 'fork'
|
||||
child, errno = unix.fork()
|
||||
if child then
|
||||
if child == 0 then
|
||||
unix.close(1)
|
||||
unix.dup(writer)
|
||||
unix.close(writer)
|
||||
unix.close(reader)
|
||||
unix.execve(ls, {ls, "-Shal"})
|
||||
unix.exit(127)
|
||||
else
|
||||
unix.close(writer)
|
||||
SetStatus(200)
|
||||
SetHeader('Content-Type', 'text/plain')
|
||||
while true do
|
||||
data = unix.read(reader)
|
||||
if data ~= "" then
|
||||
Write(data)
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
unix.close(reader)
|
||||
unix.wait(-1)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
SetStatus(200)
|
||||
SetHeader('Content-Type', 'text/plain')
|
||||
Write(string.format('error %s calling %s()', unix.strerrno(errno), syscall))
|
||||
end
|
||||
main()
|
|
@ -1,26 +0,0 @@
|
|||
-- example of how to run the ls command
|
||||
-- and pipe its output to the http user
|
||||
local unix = require "unix"
|
||||
ls = unix.commandv("ls")
|
||||
reader, writer = unix.pipe()
|
||||
if unix.fork() == 0 then
|
||||
unix.close(1)
|
||||
unix.dup(writer)
|
||||
unix.close(writer)
|
||||
unix.close(reader)
|
||||
unix.execve(ls, {ls, "-Shal"})
|
||||
unix.exit(127)
|
||||
else
|
||||
unix.close(writer)
|
||||
SetHeader('Content-Type', 'text/plain')
|
||||
while true do
|
||||
data = unix.read(reader)
|
||||
if data ~= "" then
|
||||
Write(data)
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
unix.close(reader)
|
||||
unix.wait(-1)
|
||||
end
|
|
@ -47,15 +47,16 @@ void PrintUsage(char **argv) {
|
|||
}
|
||||
|
||||
void UdpServer(void) {
|
||||
int ip;
|
||||
ssize_t rc;
|
||||
struct sockaddr_in addr2;
|
||||
uint32_t addrsize2 = sizeof(struct sockaddr_in);
|
||||
CHECK_NE(-1, (sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)));
|
||||
CHECK_NE(-1, bind(sock, &addr, addrsize));
|
||||
CHECK_NE(-1, getsockname(sock, &addr2, &addrsize2));
|
||||
kprintf("udp server %hhu.%hhu.%hhu.%hhu %hu%n", addr2.sin_addr.s_addr >> 24,
|
||||
addr2.sin_addr.s_addr >> 16, addr2.sin_addr.s_addr >> 8,
|
||||
addr2.sin_addr.s_addr, addr2.sin_port);
|
||||
ip = ntohl(addr2.sin_addr.s_addr);
|
||||
kprintf("udp server %hhu.%hhu.%hhu.%hhu %hu%n", ip >> 24, ip >> 16, ip >> 8,
|
||||
ip, ntohs(addr2.sin_port));
|
||||
for (;;) {
|
||||
CHECK_NE(-1,
|
||||
(rc = recvfrom(sock, buf, sizeof(buf), 0, &addr2, &addrsize2)));
|
||||
|
@ -73,23 +74,23 @@ void UdpClient(void) {
|
|||
}
|
||||
|
||||
void TcpServer(void) {
|
||||
int client;
|
||||
ssize_t rc;
|
||||
int ip, client;
|
||||
struct sockaddr_in addr2;
|
||||
uint32_t addrsize2 = sizeof(struct sockaddr_in);
|
||||
CHECK_NE(-1, (sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)));
|
||||
CHECK_NE(-1, bind(sock, &addr, addrsize));
|
||||
CHECK_NE(-1, listen(sock, 10));
|
||||
CHECK_NE(-1, getsockname(sock, &addr2, &addrsize2));
|
||||
kprintf("tcp server %hhu.%hhu.%hhu.%hhu %hu%n", addr2.sin_addr.s_addr >> 24,
|
||||
addr2.sin_addr.s_addr >> 16, addr2.sin_addr.s_addr >> 8,
|
||||
addr2.sin_addr.s_addr, addr2.sin_port);
|
||||
ip = ntohl(addr2.sin_addr.s_addr);
|
||||
kprintf("tcp server %hhu.%hhu.%hhu.%hhu %hu%n", ip >> 24, ip >> 16, ip >> 8,
|
||||
ip, ntohs(addr2.sin_port));
|
||||
for (;;) {
|
||||
addrsize2 = sizeof(struct sockaddr_in);
|
||||
CHECK_NE(-1, (client = accept(sock, &addr2, &addrsize2)));
|
||||
kprintf("got client %hhu.%hhu.%hhu.%hhu %hu%n", addr2.sin_addr.s_addr >> 24,
|
||||
addr2.sin_addr.s_addr >> 16, addr2.sin_addr.s_addr >> 8,
|
||||
addr2.sin_addr.s_addr, addr2.sin_port);
|
||||
ip = ntohl(addr2.sin_addr.s_addr);
|
||||
kprintf("got client %hhu.%hhu.%hhu.%hhu %hu%n", ip >> 24, ip >> 16, ip >> 8,
|
||||
ip, ntohs(addr2.sin_port));
|
||||
for (;;) {
|
||||
CHECK_NE(-1, (rc = read(client, buf, sizeof(buf))));
|
||||
if (!rc) break;
|
||||
|
|
|
@ -1440,7 +1440,7 @@ UNIX MODULE
|
|||
end
|
||||
end
|
||||
unix.close(reader)
|
||||
unix.wait(-1)
|
||||
unix.wait()
|
||||
end
|
||||
|
||||
unix.wait([pid:int, options:int])
|
||||
|
@ -1705,6 +1705,28 @@ UNIX MODULE
|
|||
Further note that calling `unix.bind(sock)` is equivalent to not
|
||||
calling bind() at all, since the above behavior is the default.
|
||||
|
||||
unix.siocgifconf() → {{name:str,ip:uint32,netmask:uint32}, ...}[, errno:int]
|
||||
|
||||
Returns list of network adapter addresses.
|
||||
|
||||
unix.poll({fd:int=events:int, ...}[, timeoutms:int])
|
||||
→ {fd:int=revents:int, ...}[, errno:int]
|
||||
|
||||
Checks for events on a set of file descriptors.
|
||||
|
||||
The table of file descriptors to poll uses sparse integer keys. Any
|
||||
pairs with non-integer keys will be ignored. Pairs with negative
|
||||
keys are ignored by poll(). The returned table will be a subset of
|
||||
the supplied file descriptors.
|
||||
|
||||
`timeoutms` is the number of seconds to block. If this is set to -1
|
||||
then that means block as long as it takes until there's an event or
|
||||
an interrupt. If the timeout expires, an empty table is returned.
|
||||
|
||||
unix.gethostname() → host:str[, errno:int]
|
||||
|
||||
Returns hostname of system.
|
||||
|
||||
unix.listen(fd:int[, backlog]) → rc:int[, errno:int]
|
||||
|
||||
Begins listening for incoming connections on a socket.
|
||||
|
@ -1802,20 +1824,6 @@ UNIX MODULE
|
|||
unix.sigaction(unix.SIGALRM, MyOnSigAlrm, unix.SA_RESETHAND)
|
||||
unix.setitimer(unix.ITIMER_REAL, 0, 0, 1, 0)
|
||||
|
||||
unix.reboot(how:int) → str
|
||||
|
||||
Changes power status of system.
|
||||
|
||||
`how` may be `RB_AUTOBOOT` to reboot, `RB_POWER_OFF` to power
|
||||
down, `RB_HALT_SYSTEM` to literally just stop the processor, or
|
||||
`RB_SW_SUSPEND` to put the machine into a suspend state. These
|
||||
magnums will be set to -1 if the method isn't supported on the
|
||||
host platform.
|
||||
|
||||
By default, an implicit sync() is performed. That's to help
|
||||
prevent you from losing data. If you don't want to shutdown
|
||||
gracefully, then you can bitwise or `RB_NOSYNC` into `how`.
|
||||
|
||||
unix.strerrno(errno:int) → str
|
||||
|
||||
Turns `errno` code into its symbolic name, e.g. `"EINTR"`.
|
||||
|
@ -1829,6 +1837,41 @@ UNIX MODULE
|
|||
Turns platform-specific `sig` code into its name, e.g.
|
||||
`strsignal(9)` always returns `"SIGKILL"`.
|
||||
|
||||
unix.setrlimit(resource:int, soft:int[, hard:int]) → rc:int[, errno:int]
|
||||
|
||||
Changes resource limit.
|
||||
|
||||
`resource` may be one of:
|
||||
|
||||
- `RLIMIT_AS` limits the size of the virtual address space. This
|
||||
will work on all platforms. It's emulated on XNU and Windows which
|
||||
means it won't propagate across execve() currently.
|
||||
|
||||
- `RLIMIT_CPU` causes `SIGXCPU` to be sent to the process when the
|
||||
soft limit on CPU time is exceeded, and the process is destroyed
|
||||
when the hard limit is exceeded. It works everywhere but Windows
|
||||
where it should be possible to poll getrusage() with setitimer()
|
||||
|
||||
- `RLIMIT_FSIZE` causes `SIGXFSZ` to sent to the process when the
|
||||
soft limit on file size is exceeded and the process is destroyed
|
||||
when the hard limit is exceeded. It works everywhere but Windows
|
||||
|
||||
- `RLIMIT_NPROC` limits the number of simultaneous processes and it
|
||||
should work on all platforms except Windows. Please be advised it
|
||||
limits the process, with respect to the activities of the user id
|
||||
as a whole.
|
||||
|
||||
- `RLIMIT_NOFILE` limits the number of open file descriptors and it
|
||||
should work on all platforms except Windows (TODO)
|
||||
|
||||
If a limit isn't supported by the host platform, it'll be set to
|
||||
127. On most platforms these limits are enforced by the kernel and
|
||||
as such are inherited by subprocesses.
|
||||
|
||||
unix.getrlimit(resource:int) → soft:int, hard:int[, errno:int]
|
||||
|
||||
Returns information about resource limit.
|
||||
|
||||
unix.stat(x) → UnixStat*, errno:int
|
||||
|
||||
Gets information about file or directory. `x` may be a file or
|
||||
|
|
160
tool/net/lunix.c
160
tool/net/lunix.c
|
@ -18,6 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/ioctl.h"
|
||||
#include "libc/calls/sigbits.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/dirent.h"
|
||||
|
@ -27,6 +28,7 @@
|
|||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/calls/ucontext.h"
|
||||
#include "libc/dns/dns.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/fmt/kerrornames.internal.h"
|
||||
|
@ -52,13 +54,15 @@
|
|||
#include "libc/sysv/consts/nr.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/ok.h"
|
||||
#include "libc/sysv/consts/reboot.h"
|
||||
#include "libc/sysv/consts/rlim.h"
|
||||
#include "libc/sysv/consts/rlimit.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/sysv/consts/shut.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/consts/sio.h"
|
||||
#include "libc/sysv/consts/sock.h"
|
||||
#include "libc/sysv/consts/w.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "third_party/lua/lauxlib.h"
|
||||
|
@ -104,14 +108,6 @@ static dontinline int ReturnTimespec(lua_State *L, struct timespec *ts) {
|
|||
return 2;
|
||||
}
|
||||
|
||||
static int ReturnRc(lua_State *L, int64_t rc, int olderr) {
|
||||
lua_pushinteger(L, rc);
|
||||
if (rc != -1) return 1;
|
||||
lua_pushinteger(L, errno);
|
||||
errno = olderr;
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int ReturnErrno(lua_State *L, int nils, int olderr) {
|
||||
int i;
|
||||
for (i = 0; i < nils; ++i) {
|
||||
|
@ -122,6 +118,15 @@ static int ReturnErrno(lua_State *L, int nils, int olderr) {
|
|||
return nils + 1;
|
||||
}
|
||||
|
||||
static int ReturnRc(lua_State *L, int64_t rc, int olderr) {
|
||||
if (rc != -1) {
|
||||
lua_pushinteger(L, rc);
|
||||
return 1;
|
||||
} else {
|
||||
return ReturnErrno(L, 1, olderr);
|
||||
}
|
||||
}
|
||||
|
||||
static char **ConvertLuaArrayToStringList(lua_State *L, int i) {
|
||||
int j, n;
|
||||
char **p;
|
||||
|
@ -146,7 +151,7 @@ static char **ConvertLuaTableToEnvList(lua_State *L, int i) {
|
|||
lua_pushnil(L);
|
||||
for (n = 0; lua_next(L, i);) {
|
||||
if (lua_type(L, -2) == LUA_TSTRING) {
|
||||
p = xrealloc(p, (++n + 1) * sizeof(char *));
|
||||
p = xrealloc(p, (++n + 1) * sizeof(*p));
|
||||
p[n - 1] = xasprintf("%s=%s", lua_tostring(L, -2), lua_tostring(L, -1));
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
@ -322,12 +327,16 @@ static int LuaUnixChmod(lua_State *L) {
|
|||
|
||||
// unix.getcwd(path:str, mode:int) → rc:int[, errno:int]
|
||||
static int LuaUnixGetcwd(lua_State *L) {
|
||||
int olderr;
|
||||
char *path;
|
||||
path = getcwd(0, 0);
|
||||
assert(path);
|
||||
olderr = errno;
|
||||
if ((path = getcwd(0, 0))) {
|
||||
lua_pushstring(L, path);
|
||||
free(path);
|
||||
return 1;
|
||||
} else {
|
||||
return ReturnErrno(L, 1, olderr);
|
||||
}
|
||||
}
|
||||
|
||||
// unix.fork() → childpid|0:int[, errno:int]
|
||||
|
@ -374,9 +383,7 @@ static int LuaUnixExecve(lua_State *L) {
|
|||
execve(prog, argv, envp);
|
||||
FreeStringList(freeme1);
|
||||
FreeStringList(freeme2);
|
||||
lua_pushinteger(L, errno);
|
||||
errno = olderr;
|
||||
return 1;
|
||||
return ReturnErrno(L, 1, olderr);
|
||||
}
|
||||
|
||||
// unix.commandv(prog:str) → path:str[, errno:int]
|
||||
|
@ -450,8 +457,8 @@ static int LuaUnixGetrlimit(lua_State *L) {
|
|||
olderr = errno;
|
||||
resource = luaL_checkinteger(L, 1);
|
||||
if (!getrlimit(resource, &rlim)) {
|
||||
lua_pushinteger(L, rlim.rlim_cur);
|
||||
lua_pushinteger(L, rlim.rlim_max);
|
||||
lua_pushinteger(L, rlim.rlim_cur < RLIM_INFINITY ? rlim.rlim_cur : -1);
|
||||
lua_pushinteger(L, rlim.rlim_max < RLIM_INFINITY ? rlim.rlim_max : -1);
|
||||
return 2;
|
||||
} else {
|
||||
return ReturnErrno(L, 2, olderr);
|
||||
|
@ -931,7 +938,7 @@ static int LuaUnixGetsockname(lua_State *L) {
|
|||
}
|
||||
}
|
||||
|
||||
// unix.getpeername(fd) → ip, port, errno
|
||||
// unix.getpeername(fd:int) → ip:uint32, port:uint16[, errno:int]
|
||||
static int LuaUnixGetpeername(lua_State *L) {
|
||||
int fd, olderr;
|
||||
uint32_t addrsize;
|
||||
|
@ -948,7 +955,72 @@ static int LuaUnixGetpeername(lua_State *L) {
|
|||
}
|
||||
}
|
||||
|
||||
// unix.accept(serverfd:int) → clientfd:int, ip:uint32, port:uint16, errno
|
||||
// unix.siocgifconf() → {{name:str,ip:uint32,netmask:uint32}, ...}[, errno:int]
|
||||
static int LuaUnixSiocgifconf(lua_State *L) {
|
||||
size_t n;
|
||||
char *data;
|
||||
int i, fd, olderr;
|
||||
struct ifreq *ifr;
|
||||
struct ifconf conf;
|
||||
olderr = errno;
|
||||
if (!(data = malloc((n = 4096)))) {
|
||||
return ReturnErrno(L, 1, olderr);
|
||||
}
|
||||
if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
|
||||
free(data);
|
||||
return ReturnErrno(L, 1, olderr);
|
||||
}
|
||||
conf.ifc_buf = data;
|
||||
conf.ifc_len = n;
|
||||
if (ioctl(fd, SIOCGIFCONF, &conf) == -1) {
|
||||
close(fd);
|
||||
free(data);
|
||||
return ReturnErrno(L, 1, olderr);
|
||||
}
|
||||
lua_newtable(L);
|
||||
i = 0;
|
||||
for (ifr = (struct ifreq *)data; (char *)ifr < data + conf.ifc_len; ++ifr) {
|
||||
if (ifr->ifr_addr.sa_family != AF_INET) continue;
|
||||
lua_createtable(L, 0, 3);
|
||||
lua_pushstring(L, "name");
|
||||
lua_pushstring(L, ifr->ifr_name);
|
||||
lua_settable(L, -3);
|
||||
lua_pushstring(L, "ip");
|
||||
lua_pushinteger(
|
||||
L, ntohl(((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr.s_addr));
|
||||
lua_settable(L, -3);
|
||||
if (ioctl(fd, SIOCGIFNETMASK, ifr) != -1) {
|
||||
lua_pushstring(L, "netmask");
|
||||
lua_pushinteger(
|
||||
L, ntohl(((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr.s_addr));
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
lua_rawseti(L, -2, ++i);
|
||||
}
|
||||
close(fd);
|
||||
free(data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// unix.gethostname() → host:str[, errno:int]
|
||||
static int LuaUnixGethostname(lua_State *L) {
|
||||
int rc, olderr;
|
||||
char buf[DNS_NAME_MAX + 1];
|
||||
olderr = errno;
|
||||
if ((rc = gethostname(buf, sizeof(buf))) != -1) {
|
||||
if (strnlen(buf, sizeof(buf)) < sizeof(buf)) {
|
||||
lua_pushstring(L, buf);
|
||||
return 1;
|
||||
} else {
|
||||
enomem();
|
||||
return ReturnErrno(L, 1, olderr);
|
||||
}
|
||||
} else {
|
||||
return ReturnErrno(L, 1, olderr);
|
||||
}
|
||||
}
|
||||
|
||||
// unix.accept(serverfd:int) → clientfd:int, ip:uint32, port:uint16[, errno:int]
|
||||
static int LuaUnixAccept(lua_State *L) {
|
||||
uint32_t addrsize;
|
||||
struct sockaddr_in sa;
|
||||
|
@ -967,6 +1039,40 @@ static int LuaUnixAccept(lua_State *L) {
|
|||
}
|
||||
}
|
||||
|
||||
// unix.poll({fd:int=events:int, ...}[, timeoutms:int])
|
||||
// → {fd:int=revents:int, ...}[, errno:int]
|
||||
static int LuaUnixPoll(lua_State *L) {
|
||||
size_t nfds;
|
||||
struct pollfd *fds;
|
||||
int i, fd, olderr, events, timeoutms;
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
lua_pushnil(L);
|
||||
for (fds = 0, nfds = 0; lua_next(L, 1);) {
|
||||
if (lua_isinteger(L, -2)) {
|
||||
fds = xrealloc(fds, ++nfds * sizeof(*fds));
|
||||
fds[nfds - 1].fd = lua_tointeger(L, -2);
|
||||
fds[nfds - 1].events = lua_tointeger(L, -1);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
timeoutms = luaL_optinteger(L, 2, -1);
|
||||
olderr = errno;
|
||||
if ((events = poll(fds, nfds, timeoutms)) != -1) {
|
||||
lua_createtable(L, events, 0);
|
||||
for (i = 0; i < nfds; ++i) {
|
||||
if (fds[i].revents && fds[i].fd >= 0) {
|
||||
lua_pushinteger(L, fds[i].revents);
|
||||
lua_rawseti(L, -2, fds[i].fd);
|
||||
}
|
||||
}
|
||||
free(fds);
|
||||
return 1;
|
||||
} else {
|
||||
free(fds);
|
||||
return ReturnErrno(L, 1, olderr);
|
||||
}
|
||||
}
|
||||
|
||||
// unix.recvfrom(fd[, bufsiz[, flags]]) → data, ip, port[, errno]
|
||||
// flags can have MSG_{WAITALL,DONTROUTE,PEEK,OOB}, etc.
|
||||
static int LuaUnixRecvfrom(lua_State *L) {
|
||||
|
@ -1286,11 +1392,6 @@ static int LuaUnixWtermsig(lua_State *L) {
|
|||
return ReturnInteger(L, WTERMSIG(luaL_checkinteger(L, 1)));
|
||||
}
|
||||
|
||||
// unix.reboot(how:int) → rc:int[, errno:int]
|
||||
static int LuaUnixReboot(lua_State *L) {
|
||||
return ReturnInteger(L, reboot(luaL_checkinteger(L, 1)));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// UnixStat* object
|
||||
|
||||
|
@ -1568,10 +1669,12 @@ static const luaL_Reg kLuaUnix[] = {
|
|||
{"setuid", LuaUnixSetuid}, // set real user id of process
|
||||
{"getgid", LuaUnixGetgid}, // get real group id of process
|
||||
{"setgid", LuaUnixSetgid}, // set real group id of process
|
||||
{"gethostname", LuaUnixGethostname}, // get hostname of this machine
|
||||
{"clock_gettime", LuaUnixGettime}, // get timestamp w/ nano precision
|
||||
{"nanosleep", LuaUnixNanosleep}, // sleep w/ nano precision
|
||||
{"socket", LuaUnixSocket}, // create network communication fd
|
||||
{"socketpair", LuaUnixSocketpair}, // create bidirectional pipe
|
||||
{"poll", LuaUnixPoll}, // waits for file descriptor events
|
||||
{"bind", LuaUnixBind}, // reserve network interface address
|
||||
{"listen", LuaUnixListen}, // begin listening for clients
|
||||
{"accept", LuaUnixAccept}, // create client fd for client
|
||||
|
@ -1583,11 +1686,11 @@ static const luaL_Reg kLuaUnix[] = {
|
|||
{"shutdown", LuaUnixShutdown}, // make socket half empty or full
|
||||
{"getpeername", LuaUnixGetpeername}, // get address of remote end
|
||||
{"getsockname", LuaUnixGetsockname}, // get address of local end
|
||||
{"siocgifconf", LuaUnixSiocgifconf}, // get list of network interfaces
|
||||
{"sigaction", LuaUnixSigaction}, // install signal handler
|
||||
{"sigprocmask", LuaUnixSigprocmask}, // change signal mask
|
||||
{"sigsuspend", LuaUnixSigsuspend}, // wait for signal
|
||||
{"setitimer", LuaUnixSetitimer}, // set alarm clock
|
||||
{"reboot", LuaUnixReboot}, // reboots system
|
||||
{"strerror", LuaUnixStrerror}, // turn errno into string
|
||||
{"strerrno", LuaUnixStrerrno}, // turn errno into string
|
||||
{"strsignal", LuaUnixStrsignal}, // turn signal into string
|
||||
|
@ -1765,12 +1868,5 @@ int LuaUnix(lua_State *L) {
|
|||
LuaSetIntField(L, "LOG_INFO", LOG_INFO);
|
||||
LuaSetIntField(L, "LOG_DEBUG", LOG_DEBUG);
|
||||
|
||||
// reboot() howto
|
||||
LuaSetIntField(L, "RB_AUTOBOOT", RB_AUTOBOOT);
|
||||
LuaSetIntField(L, "RB_POWER_OFF", RB_POWER_OFF);
|
||||
LuaSetIntField(L, "RB_HALT_SYSTEM", RB_HALT_SYSTEM);
|
||||
LuaSetIntField(L, "RB_SW_SUSPEND", RB_SW_SUSPEND);
|
||||
LuaSetIntField(L, "RB_NOSYNC", RB_NOSYNC);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -171,7 +171,9 @@ o/tinylinux/tool/net/redbean.com: \
|
|||
o/$(MODE)/tool/net/demo/.init.lua.zip.o \
|
||||
o/$(MODE)/tool/net/demo/.reload.lua.zip.o \
|
||||
o/$(MODE)/tool/net/demo/sql.lua.zip.o \
|
||||
o/$(MODE)/tool/net/demo/unix.lua.zip.o \
|
||||
o/$(MODE)/tool/net/demo/unix-rawsocket.lua.zip.o \
|
||||
o/$(MODE)/tool/net/demo/unix-subprocess.lua.zip.o \
|
||||
o/$(MODE)/tool/net/demo/unix-info.lua.zip.o \
|
||||
o/$(MODE)/tool/net/demo/fetch.lua.zip.o \
|
||||
o/$(MODE)/tool/net/demo/hello.lua.zip.o \
|
||||
o/$(MODE)/tool/net/demo/maxmind.lua.zip.o \
|
||||
|
@ -213,8 +215,9 @@ o/$(MODE)/tool/net/redbean-demo.com.dbg: \
|
|||
o/$(MODE)/tool/net/largon2.o \
|
||||
o/$(MODE)/tool/net/net.pkg \
|
||||
o/$(MODE)/tool/net/demo/sql.lua.zip.o \
|
||||
o/$(MODE)/tool/net/demo/unix.lua.zip.o \
|
||||
o/$(MODE)/tool/net/demo/unix2.lua.zip.o \
|
||||
o/$(MODE)/tool/net/demo/unix-rawsocket.lua.zip.o \
|
||||
o/$(MODE)/tool/net/demo/unix-subprocess.lua.zip.o \
|
||||
o/$(MODE)/tool/net/demo/unix-info.lua.zip.o \
|
||||
o/$(MODE)/tool/net/demo/fetch.lua.zip.o \
|
||||
o/$(MODE)/tool/net/demo/hello.lua.zip.o \
|
||||
o/$(MODE)/tool/net/demo/redbean.lua.zip.o \
|
||||
|
|
|
@ -6608,45 +6608,65 @@ static int ExitWorker(void) {
|
|||
static const struct sock_filter kSandboxOnline[] = {
|
||||
_SECCOMP_MACHINE(AUDIT_ARCH_X86_64), //
|
||||
_SECCOMP_LOAD_SYSCALL_NR(), //
|
||||
_SECCOMP_ALLOW_SYSCALL(0x0013), // readv
|
||||
_SECCOMP_ALLOW_SYSCALL(0x0014), // writev
|
||||
_SECCOMP_ALLOW_SYSCALL(0x0009), // mmap
|
||||
_SECCOMP_ALLOW_SYSCALL(0x000b), // munmap
|
||||
_SECCOMP_ALLOW_SYSCALL(0x0000), // read
|
||||
_SECCOMP_ALLOW_SYSCALL(0x0001), // write
|
||||
_SECCOMP_ALLOW_SYSCALL(0x0003), // close
|
||||
_SECCOMP_ALLOW_SYSCALL(0x0008), // lseek
|
||||
_SECCOMP_ALLOW_SYSCALL(0x000f), // rt_sigreturn
|
||||
_SECCOMP_ALLOW_SYSCALL(0x00e7), // exit_group
|
||||
_SECCOMP_ALLOW_SYSCALL(0x0106), // newfstatat
|
||||
_SECCOMP_ALLOW_SYSCALL(0x00e4), // clock_gettime
|
||||
_SECCOMP_ALLOW_SYSCALL(0x003f), // uname
|
||||
_SECCOMP_ALLOW_SYSCALL(0x0048), // fcntl
|
||||
_SECCOMP_ALLOW_SYSCALL(0x0029), // socket
|
||||
_SECCOMP_ALLOW_SYSCALL(0x002a), // connect
|
||||
_SECCOMP_ALLOW_SYSCALL(0x002c), // sendto
|
||||
_SECCOMP_ALLOW_SYSCALL(0x002d), // recvfrom
|
||||
_SECCOMP_ALLOW_SYSCALL(0x0036), // setsockopt
|
||||
_SECCOMP_ALLOW_SYSCALL(0x013), // readv
|
||||
_SECCOMP_ALLOW_SYSCALL(0x014), // writev
|
||||
_SECCOMP_ALLOW_SYSCALL(0x009), // mmap
|
||||
_SECCOMP_ALLOW_SYSCALL(0x00b), // munmap
|
||||
_SECCOMP_ALLOW_SYSCALL(0x000), // read
|
||||
_SECCOMP_ALLOW_SYSCALL(0x001), // write
|
||||
_SECCOMP_ALLOW_SYSCALL(0x003), // close
|
||||
_SECCOMP_ALLOW_SYSCALL(0x008), // lseek
|
||||
_SECCOMP_ALLOW_SYSCALL(0x04f), // getcwd
|
||||
_SECCOMP_ALLOW_SYSCALL(0x027), // getpid
|
||||
_SECCOMP_ALLOW_SYSCALL(0x066), // getuid
|
||||
_SECCOMP_ALLOW_SYSCALL(0x068), // getgid
|
||||
_SECCOMP_ALLOW_SYSCALL(0x06e), // getppid
|
||||
_SECCOMP_ALLOW_SYSCALL(0x06f), // getpgrp
|
||||
_SECCOMP_ALLOW_SYSCALL(0x07c), // getsid
|
||||
_SECCOMP_ALLOW_SYSCALL(0x06b), // geteuid
|
||||
_SECCOMP_ALLOW_SYSCALL(0x06c), // getegid
|
||||
_SECCOMP_ALLOW_SYSCALL(0x061), // getrlimit
|
||||
_SECCOMP_ALLOW_SYSCALL(0x00f), // rt_sigreturn
|
||||
_SECCOMP_ALLOW_SYSCALL(0x0e7), // exit_group
|
||||
_SECCOMP_ALLOW_SYSCALL(0x106), // newfstatat
|
||||
_SECCOMP_ALLOW_SYSCALL(0x0e4), // clock_gettime
|
||||
_SECCOMP_ALLOW_SYSCALL(0x03f), // uname
|
||||
_SECCOMP_ALLOW_SYSCALL(0x048), // fcntl
|
||||
_SECCOMP_ALLOW_SYSCALL(0x029), // socket
|
||||
_SECCOMP_ALLOW_SYSCALL(0x02a), // connect
|
||||
_SECCOMP_ALLOW_SYSCALL(0x02c), // sendto
|
||||
_SECCOMP_ALLOW_SYSCALL(0x02d), // recvfrom
|
||||
_SECCOMP_ALLOW_SYSCALL(0x036), // setsockopt
|
||||
_SECCOMP_LOG_AND_RETURN_ERRNO(1), // EPERM
|
||||
};
|
||||
|
||||
static const struct sock_filter kSandboxOffline[] = {
|
||||
_SECCOMP_MACHINE(AUDIT_ARCH_X86_64), //
|
||||
_SECCOMP_LOAD_SYSCALL_NR(), //
|
||||
_SECCOMP_ALLOW_SYSCALL(0x0013), // readv
|
||||
_SECCOMP_ALLOW_SYSCALL(0x0014), // writev
|
||||
_SECCOMP_ALLOW_SYSCALL(0x0000), // read
|
||||
_SECCOMP_ALLOW_SYSCALL(0x0001), // write
|
||||
_SECCOMP_ALLOW_SYSCALL(0x0009), // mmap
|
||||
_SECCOMP_ALLOW_SYSCALL(0x000b), // munmap
|
||||
_SECCOMP_ALLOW_SYSCALL(0x0003), // close
|
||||
_SECCOMP_ALLOW_SYSCALL(0x0008), // lseek
|
||||
_SECCOMP_ALLOW_SYSCALL(0x000f), // rt_sigreturn
|
||||
_SECCOMP_ALLOW_SYSCALL(0x00e7), // exit_group
|
||||
_SECCOMP_ALLOW_SYSCALL(0x0106), // newfstatat
|
||||
_SECCOMP_ALLOW_SYSCALL(0x00e4), // clock_gettime
|
||||
_SECCOMP_ALLOW_SYSCALL(0x003f), // uname
|
||||
_SECCOMP_ALLOW_SYSCALL(0x0048), // fcntl
|
||||
_SECCOMP_ALLOW_SYSCALL(0x013), // readv
|
||||
_SECCOMP_ALLOW_SYSCALL(0x014), // writev
|
||||
_SECCOMP_ALLOW_SYSCALL(0x000), // read
|
||||
_SECCOMP_ALLOW_SYSCALL(0x001), // write
|
||||
_SECCOMP_ALLOW_SYSCALL(0x009), // mmap
|
||||
_SECCOMP_ALLOW_SYSCALL(0x00b), // munmap
|
||||
_SECCOMP_ALLOW_SYSCALL(0x003), // close
|
||||
_SECCOMP_ALLOW_SYSCALL(0x008), // lseek
|
||||
_SECCOMP_ALLOW_SYSCALL(0x04f), // getcwd
|
||||
_SECCOMP_ALLOW_SYSCALL(0x027), // getpid
|
||||
_SECCOMP_ALLOW_SYSCALL(0x066), // getuid
|
||||
_SECCOMP_ALLOW_SYSCALL(0x068), // getgid
|
||||
_SECCOMP_ALLOW_SYSCALL(0x06e), // getppid
|
||||
_SECCOMP_ALLOW_SYSCALL(0x06f), // getpgrp
|
||||
_SECCOMP_ALLOW_SYSCALL(0x07c), // getsid
|
||||
_SECCOMP_ALLOW_SYSCALL(0x06b), // geteuid
|
||||
_SECCOMP_ALLOW_SYSCALL(0x06c), // getegid
|
||||
_SECCOMP_ALLOW_SYSCALL(0x061), // getrlimit
|
||||
_SECCOMP_ALLOW_SYSCALL(0x00f), // rt_sigreturn
|
||||
_SECCOMP_ALLOW_SYSCALL(0x0e7), // exit_group
|
||||
_SECCOMP_ALLOW_SYSCALL(0x106), // newfstatat
|
||||
_SECCOMP_ALLOW_SYSCALL(0x0e4), // clock_gettime
|
||||
_SECCOMP_ALLOW_SYSCALL(0x03f), // uname
|
||||
_SECCOMP_ALLOW_SYSCALL(0x048), // fcntl
|
||||
_SECCOMP_LOG_AND_RETURN_ERRNO(1), // EPERM
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue