Skip to content

Commit

Permalink
Fix redbean zip central directory lookup
Browse files Browse the repository at this point in the history
This regression snuck in at some point. It resulted in the program
sometimes failing to load when the zip content was changed.
  • Loading branch information
jart committed Feb 27, 2021
1 parent 19d0c15 commit 133d059
Show file tree
Hide file tree
Showing 9 changed files with 179 additions and 7 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ include test/tool/build/lib/test.mk
include test/tool/build/test.mk
include test/tool/viz/lib/test.mk
include test/tool/viz/test.mk
include test/tool/net/test.mk
include test/tool/test.mk
include test/dsp/core/test.mk
include test/dsp/scale/test.mk
Expand Down
1 change: 1 addition & 0 deletions build/definitions.mk
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ MATHEMATICAL = \
-fwrapv

DEFAULT_CPPFLAGS = \
-DMODE='"$(MODE)"' \
-DIMAGE_BASE_VIRTUAL=$(IMAGE_BASE_VIRTUAL) \
-nostdinc \
-iquote.
Expand Down
5 changes: 5 additions & 0 deletions build/gdb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/sh
exec gdb -q -nh -i=mi $1 \
-ex "set confirm off" \
-ex "add-symbol-file $1.dbg 0x401000" \
-ex "run"
9 changes: 8 additions & 1 deletion libc/zipos/get.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/bits/safemacros.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/limits.h"
Expand All @@ -33,12 +34,18 @@
struct Zipos *__zipos_get(void) {
static struct Zipos zipos;
static bool once;
const char *exe;
const char *exe, *dir;
char path[PATH_MAX];
size_t mapsize;
uint8_t *cdir;
void *map;
if (!once) {
dir = nulltoempty(getenv("PWD")); /* suboptimal */
exe = (const char *)getauxval(AT_EXECFN);
if (!fileexists(exe) && strlen(dir) + 1 + strlen(exe) + 1 <= PATH_MAX) {
stpcpy(stpcpy(stpcpy(path, dir), "/"), exe);
exe = path;
}
if ((zipos.fd = open(exe, O_RDONLY)) != -1) {
if ((mapsize = getfiledescriptorsize(zipos.fd)) != SIZE_MAX &&
(map = mmap(NULL, mapsize, PROT_READ, MAP_SHARED, zipos.fd, 0)) !=
Expand Down
8 changes: 4 additions & 4 deletions test/libc/stdio/mkostempsm_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
#include "libc/sysv/consts/o.h"
#include "libc/testlib/testlib.h"

#define MODE() \
#define Mode() \
({ \
va_list va; \
unsigned Mode; \
Expand All @@ -40,7 +40,7 @@ static int MockOpen1(const char *file, int flags, ...) {
once = true;
EXPECT_STREQ("/tmp/mkostemps.ctre5m", file);
EXPECT_EQ(O_RDWR | O_CREAT | O_EXCL, flags);
EXPECT_EQ(0600, MODE());
EXPECT_EQ(0600, Mode());
return 123;
}

Expand All @@ -59,14 +59,14 @@ static int MockOpen2(const char *file, int flags, ...) {
state = 1;
EXPECT_STREQ("/tmp/mkostemps.ctre5m", file);
EXPECT_EQ((unsigned)(O_RDWR | O_CREAT | O_EXCL), flags);
EXPECT_EQ(0600, MODE());
EXPECT_EQ(0600, Mode());
errno = EEXIST;
return -1;
case 1:
state = 1;
EXPECT_STREQ("/tmp/mkostemps.jl1h61", file);
EXPECT_EQ((unsigned)(O_RDWR | O_CREAT | O_EXCL), flags);
EXPECT_EQ(0600, MODE());
EXPECT_EQ(0600, Mode());
return 123;
default:
abort();
Expand Down
76 changes: 76 additions & 0 deletions test/tool/net/redbean_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*-*- 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/sigbits.h"
#include "libc/fmt/conv.h"
#include "libc/runtime/gc.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sig.h"
#include "libc/testlib/testlib.h"
#include "libc/x/x.h"

/* TODO(jart): Finish this */

STATIC_YOINK("zip_uri_support");
STATIC_YOINK("o/" MODE "/tool/net/redbean.com");
char testlib_enable_tmp_setup_teardown;

void SetUp(void) {
return;
ssize_t n;
char buf[512];
int fdin, fdout;
ASSERT_NE(-1, mkdir("bin", 0755));
ASSERT_NE(-1, (fdin = open("zip:o/" MODE "/tool/net/redbean.com", O_RDONLY)));
ASSERT_NE(-1, (fdout = creat("bin/redbean.com", 0755)));
for (;;) {
ASSERT_NE(-1, (n = read(fdin, buf, sizeof(buf))));
if (!n) break;
ASSERT_EQ(n, write(fdout, buf, sizeof(buf)));
}
close(fdout);
close(fdin);
}

TEST(redbean, test) {
return;
char portbuf[16];
int pid, port, pipefds[2];
sigset_t chldmask, savemask;
sigaddset(&chldmask, SIGCHLD);
sigprocmask(SIG_BLOCK, &chldmask, &savemask);
ASSERT_NE(-1, pipe2(pipefds, O_CLOEXEC));
ASSERT_NE(-1, (pid = vfork()));
if (!pid) {
dup2(pipefds[1], 1);
sigprocmask(SIG_SETMASK, &savemask, NULL);
execv("bin/redbean.com",
(char *const[]){"bin/redbean.com", "-zp0", "-l127.0.0.1", 0});
_exit(127);
}
EXPECT_NE(-1, close(pipefds[1]));
EXPECT_NE(-1, read(pipefds[0], portbuf, sizeof(portbuf)));
port = atoi(portbuf);
printf("port %d\n", port);
EXPECT_NE(-1, kill(pid, SIGTERM));
EXPECT_NE(-1, wait(0));
}
69 changes: 69 additions & 0 deletions test/tool/net/test.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘

PKGS += TEST_TOOL_NET

TEST_TOOL_NET = $(TOOL_NET_A_DEPS) $(TOOL_NET_A)
TEST_TOOL_NET_A = o/$(MODE)/test/tool/net/net.a
TEST_TOOL_NET_FILES := $(wildcard test/tool/net/*)
TEST_TOOL_NET_SRCS = $(filter %.c,$(TEST_TOOL_NET_FILES))
TEST_TOOL_NET_SRCS_TEST = $(filter %_test.c,$(TEST_TOOL_NET_SRCS))
TEST_TOOL_NET_HDRS = $(filter %.h,$(TEST_TOOL_NET_FILES))
TEST_TOOL_NET_COMS = $(TEST_TOOL_NET_OBJS:%.o=%.com)
TEST_TOOL_NET_COMS = $(TEST_TOOL_NET_SRCS:%.c=o/$(MODE)/%.com)

TEST_TOOL_NET_OBJS = \
$(TEST_TOOL_NET_SRCS:%.c=o/$(MODE)/%.o) \
o/$(MODE)/tool/net/redbean.com.zip.o

TEST_TOOL_NET_BINS = \
$(TEST_TOOL_NET_COMS) \
$(TEST_TOOL_NET_COMS:%=%.dbg)

TEST_TOOL_NET_TESTS = \
$(TEST_TOOL_NET_SRCS_TEST:%.c=o/$(MODE)/%.com.ok)

TEST_TOOL_NET_CHECKS = \
$(TEST_TOOL_NET_HDRS:%=o/$(MODE)/%.ok) \
$(TEST_TOOL_NET_SRCS_TEST:%.c=o/$(MODE)/%.com.runs)

TEST_TOOL_NET_DIRECTDEPS = \
LIBC_CALLS \
LIBC_STUBS \
LIBC_FMT \
LIBC_STDIO \
LIBC_INTRIN \
LIBC_NEXGEN32E \
LIBC_SYSV \
LIBC_MEM \
LIBC_RUNTIME \
LIBC_X \
LIBC_TESTLIB \
LIBC_ZIPOS

TEST_TOOL_NET_DEPS := \
$(call uniq,$(foreach x,$(TEST_TOOL_NET_DIRECTDEPS),$($(x))))

$(TEST_TOOL_NET_A): \
test/tool/net/ \
$(TEST_TOOL_NET_A).pkg \
$(TEST_TOOL_NET_OBJS)

$(TEST_TOOL_NET_A).pkg: \
$(TEST_TOOL_NET_OBJS) \
$(foreach x,$(TEST_TOOL_NET_DIRECTDEPS),$($(x)_A).pkg)

o/$(MODE)/test/tool/net/%.com.dbg: \
$(TEST_TOOL_NET_DEPS) \
$(TEST_TOOL_NET_A) \
o/$(MODE)/test/tool/net/%.o \
$(TEST_TOOL_NET_A).pkg \
$(LIBC_TESTMAIN) \
$(CRT) \
$(APE)
@$(APELINK)

.PHONY: o/$(MODE)/test/tool/net
o/$(MODE)/test/tool/net: \
$(TEST_TOOL_NET_BINS) \
$(TEST_TOOL_NET_CHECKS)
1 change: 1 addition & 0 deletions test/tool/test.mk
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@
.PHONY: o/$(MODE)/test/tool
o/$(MODE)/test/tool: \
o/$(MODE)/test/tool/build \
o/$(MODE)/test/tool/net \
o/$(MODE)/test/tool/viz
16 changes: 14 additions & 2 deletions tool/net/redbean.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ FLAGS\n\
-v verbosity\n\
-d daemonize\n\
-s uniprocess\n\
-z print port\n\
-m log messages\n\
-c INT cache seconds\n\
-r /X=/Y redirect X to Y\n\
Expand Down Expand Up @@ -216,6 +217,7 @@ static struct Assets {

static bool killed;
static bool notimer;
static bool printport;
static bool heartbeat;
static bool daemonize;
static bool terminated;
Expand Down Expand Up @@ -372,7 +374,7 @@ void GetOpts(int argc, char *argv[]) {
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(DEFAULT_PORT);
serveraddr.sin_addr.s_addr = INADDR_ANY;
while ((opt = getopt(argc, argv, "hduvml:p:w:r:c:L:P:U:G:B:")) != -1) {
while ((opt = getopt(argc, argv, "zhduvml:p:w:r:c:L:P:U:G:B:")) != -1) {
switch (opt) {
case 'v':
g_loglevel++;
Expand All @@ -386,6 +388,9 @@ void GetOpts(int argc, char *argv[]) {
case 'm':
logmessages = true;
break;
case 'z':
printport = true;
break;
case 'r':
AddRedirect(optarg);
break;
Expand Down Expand Up @@ -646,7 +651,7 @@ static bool OpenZip(const char *path) {
if ((fd = open(path, O_RDONLY)) != -1 && fstat(fd, &st) != -1 &&
st.st_size &&
(map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) &&
(cdir = zipfindcentraldir(zmap, zmapsize)) && IndexAssets(map, cdir)) {
(cdir = zipfindcentraldir(map, st.st_size)) && IndexAssets(map, cdir)) {
ok = true;
zmap = map;
zbase = map;
Expand Down Expand Up @@ -1144,6 +1149,7 @@ static void TuneServerSocket(void) {
}

void RedBean(void) {
uint32_t addrsize;
gmtoff = GetGmtOffset();
programfile = (const char *)getauxval(AT_EXECFN);
CHECK(OpenZip(programfile));
Expand All @@ -1159,9 +1165,15 @@ void RedBean(void) {
TuneServerSocket();
CHECK_NE(-1, bind(server, &serveraddr, sizeof(serveraddr)));
CHECK_NE(-1, listen(server, 10));
addrsize = sizeof(serveraddr);
CHECK_NE(-1, getsockname(server, &serveraddr, &addrsize));
DescribeAddress(serveraddrstr, &serveraddr);
if (daemonize) Daemonize();
VERBOSEF("%s listen", serveraddrstr);
if (printport) {
printf("%d\n", ntohs(serveraddr.sin_port));
fflush(stdout);
}
heartbeat = true;
while (!terminated) {
if (invalidated) {
Expand Down

0 comments on commit 133d059

Please sign in to comment.