Add syscalls to Blinkenlights and fix bugs

This commit is contained in:
Justine Tunney 2022-05-13 13:31:21 -07:00
parent f6df29cc3d
commit 578cb21591
25 changed files with 187 additions and 108 deletions

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/bits/safemacros.internal.h"
#include "libc/intrin/kprintf.h" #include "libc/intrin/kprintf.h"
#include "libc/log/color.internal.h" #include "libc/log/color.internal.h"
#include "libc/log/internal.h" #include "libc/log/internal.h"
@ -30,5 +31,6 @@ relegated void __start_fatal(const char *file, int line) {
__restore_tty(); __restore_tty();
kprintf("%r%serror%s:%s:%d:%s%s: ", !__nocolor ? "\e[J\e[30;101m" : "", kprintf("%r%serror%s:%s:%d:%s%s: ", !__nocolor ? "\e[J\e[30;101m" : "",
!__nocolor ? "\e[94;49m" : "", file, line, !__nocolor ? "\e[94;49m" : "", file, line,
program_invocation_short_name, !__nocolor ? "\e[0m" : ""); firstnonnull(program_invocation_short_name, "unknown"),
!__nocolor ? "\e[0m" : "");
} }

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/bits/safemacros.internal.h"
#include "libc/log/bsd.h" #include "libc/log/bsd.h"
#include "libc/log/color.internal.h" #include "libc/log/color.internal.h"
#include "libc/log/internal.h" #include "libc/log/internal.h"
@ -23,8 +24,9 @@
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
wontreturn void(verr)(int eval, const char *fmt, va_list va) { wontreturn void(verr)(int eval, const char *fmt, va_list va) {
fprintf(stderr, "%s: %s%s%s[%m]: ", program_invocation_name, RED2, "ERROR", fprintf(stderr,
RESET); "%s: %s%s%s[%m]: ", firstnonnull(program_invocation_name, "unknown"),
RED2, "ERROR", RESET);
if (fmt) (vfprintf)(stderr, fmt, va); if (fmt) (vfprintf)(stderr, fmt, va);
fprintf(stderr, "\n"); fprintf(stderr, "\n");
exit(eval); exit(eval);

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/bits/bits.h" #include "libc/bits/bits.h"
#include "libc/bits/safemacros.internal.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/strace.internal.h" #include "libc/calls/strace.internal.h"
#include "libc/calls/struct/stat.h" #include "libc/calls/struct/stat.h"
@ -96,7 +97,7 @@ void(vflogf)(unsigned level, const char *file, int line, FILE *f,
vflogf_ts.tv_nsec = nsec; vflogf_ts.tv_nsec = nsec;
localtime_r(&secs, &tm); localtime_r(&secs, &tm);
strcpy(iso8601(buf32, &tm), issamesecond ? "+" : "."); strcpy(iso8601(buf32, &tm), issamesecond ? "+" : ".");
prog = basename(program_invocation_name); prog = basename(firstnonnull(program_invocation_name, "unknown"));
bufmode = f->bufmode; bufmode = f->bufmode;
if (bufmode == _IOLBF) f->bufmode = _IOFBF; if (bufmode == _IOLBF) f->bufmode = _IOFBF;
if ((fprintf)(f, "%r%c%s%06ld:%s:%d:%.*s:%d] ", "FEWIVDNT"[level & 7], buf32, if ((fprintf)(f, "%r%c%s%06ld:%s:%d:%.*s:%d] ", "FEWIVDNT"[level & 7], buf32,

View file

@ -18,8 +18,13 @@
*/ */
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
// Supplies argv[0] the GNU way.
.initbss 300,_init_program_invocation_name .initbss 300,_init_program_invocation_name
// Supplies argv[0] the GNU way.
//
// If argv[0] isn't supplied, this value will be null.
//
// @see program_invocation_short_name
// @see GetProgramExecutableName()
program_invocation_name: program_invocation_name:
.quad 0 .quad 0
.endobj program_invocation_name,globl .endobj program_invocation_name,globl

View file

@ -344,6 +344,7 @@ static noasan inline void *Mmap(void *addr, size_t size, int prot, int flags,
return MAP_FAILED; return MAP_FAILED;
} }
f |= MAP_STACK_openbsd; f |= MAP_STACK_openbsd;
needguard = true;
} else if (IsLinux()) { } else if (IsLinux()) {
// by default MAP_GROWSDOWN will auto-allocate 10mb of pages. it's // by default MAP_GROWSDOWN will auto-allocate 10mb of pages. it's
// supposed to stop growing if an adjacent allocation exists, to // supposed to stop growing if an adjacent allocation exists, to

View file

@ -36,7 +36,8 @@ void __paginate(int fd, const char *s) {
((args[0] = commandv("less", progpath, sizeof(progpath))) || ((args[0] = commandv("less", progpath, sizeof(progpath))) ||
(args[0] = commandv("more", progpath, sizeof(progpath))))) { (args[0] = commandv("more", progpath, sizeof(progpath))))) {
snprintf(tmppath, sizeof(tmppath), "%s%s-%s-%d.txt", kTmpPath, snprintf(tmppath, sizeof(tmppath), "%s%s-%s-%d.txt", kTmpPath,
program_invocation_short_name, "paginate", getpid()); firstnonnull(program_invocation_short_name, "unknown"), "paginate",
getpid());
if ((tfd = open(tmppath, O_WRONLY | O_CREAT | O_TRUNC, 0644)) != -1) { if ((tfd = open(tmppath, O_WRONLY | O_CREAT | O_TRUNC, 0644)) != -1) {
write(tfd, s, strlen(s)); write(tfd, s, strlen(s));
close(tfd); close(tfd);

View file

@ -155,15 +155,18 @@
6666555555555544444444443333333333222222222211111111110000000000 6666555555555544444444443333333333222222222211111111110000000000
3210987654321098765432109876543210987654321098765432109876543210*/ 3210987654321098765432109876543210987654321098765432109876543210*/
#define PAGE_V /* */ 0b000000001 #define PAGE_V /* */ 0b000000000001
#define PAGE_RW /* */ 0b000000010 #define PAGE_RW /* */ 0b000000000010
#define PAGE_U /* */ 0b000000100 #define PAGE_U /* */ 0b000000000100
#define PAGE_4KB /* */ 0b010000000 #define PAGE_4KB /* */ 0b000010000000
#define PAGE_2MB /* */ 0b110000000 #define PAGE_2MB /* */ 0b000110000000
#define PAGE_1GB /* */ 0b110000000 #define PAGE_1GB /* */ 0b000110000000
#define PAGE_TA 0x00007ffffffff000 #define PAGE_IGN1 /* */ 0b111000000000
#define PAGE_PA2 0x00007fffffe00000 #define PAGE_RSRV /* blinkenlights reservation */ 0b001000000000
#define PAGE_XD 0x8000000000000000 #define PAGE_GROD /* blinkenlights MAP_GROWSDOWN */ 0b010000000000
#define PAGE_TA 0x00007ffffffff000
#define PAGE_PA2 0x00007fffffe00000
#define PAGE_XD 0x8000000000000000
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)

View file

@ -18,8 +18,13 @@
*/ */
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
// Supplies basename(argv[0]) The GNU Way.
.initbss 400,_init_program_invocation_short_name .initbss 400,_init_program_invocation_short_name
// Supplies basename(argv[0]) The GNU Way.
//
// If argv[0] isn't supplied, this value will be null.
//
// @see GetProgramExecutableName()
// @see program_invocation_name
program_invocation_short_name: program_invocation_short_name:
.quad 0 .quad 0
.endobj program_invocation_short_name,globl .endobj program_invocation_short_name,globl

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/bits/safemacros.internal.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/weirdtypes.h" #include "libc/calls/weirdtypes.h"
#include "libc/dce.h" #include "libc/dce.h"
@ -288,7 +289,7 @@ void openlog(const char *ident, int opt, int facility) {
__initlog(); __initlog();
} }
if (!ident) { if (!ident) {
ident = program_invocation_short_name; ident = firstnonnull(program_invocation_short_name, "unknown");
} }
tprecode8to16(log_ident, ARRAYLEN(log_ident), ident); tprecode8to16(log_ident, ARRAYLEN(log_ident), ident);
log_opt = opt; log_opt = opt;

View file

@ -36,7 +36,8 @@ FILE *tmpfile(void) {
tmp = firstnonnull(getenv("TMPDIR"), kTmpPath); tmp = firstnonnull(getenv("TMPDIR"), kTmpPath);
sep = !isempty(tmp) && !endswith(tmp, "/") ? "/" : ""; sep = !isempty(tmp) && !endswith(tmp, "/") ? "/" : "";
if ((snprintf)(tpl, PATH_MAX, "%s%stmp.%s.XXXXXX", tmp, sep, if ((snprintf)(tpl, PATH_MAX, "%s%stmp.%s.XXXXXX", tmp, sep,
program_invocation_short_name) <= PATH_MAX) { firstnonnull(program_invocation_short_name, "unknown")) <=
PATH_MAX) {
if ((fd = mkostemps(tpl, 0, 0)) != -1) { if ((fd = mkostemps(tpl, 0, 0)) != -1) {
return fdopen(fd, "w+"); return fdopen(fd, "w+");
} }

View file

@ -18,6 +18,7 @@
*/ */
#include "libc/bits/bits.h" #include "libc/bits/bits.h"
#include "libc/fmt/magnumstrs.internal.h" #include "libc/fmt/magnumstrs.internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/str/str.h" #include "libc/str/str.h"
@ -26,7 +27,7 @@ static char g_strsignal[12];
/** /**
* Returns string describing signal code. * Returns string describing signal code.
* *
* This returns SIGUNKNOWN for 0 which is the empty value. Textual names * This returns SIGZERO for 0 which is the empty value. Textual names
* should be available for signals 1 through 32. Signals in the range 33 * should be available for signals 1 through 32. Signals in the range 33
* and 128 are returned as a `SIG%03d` string. Everything else is SIGWUT * and 128 are returned as a `SIG%03d` string. Everything else is SIGWUT
* *
@ -34,24 +35,36 @@ static char g_strsignal[12];
* @return pointer to static memory that mutates on subsequent calls * @return pointer to static memory that mutates on subsequent calls
* @see sigaction() * @see sigaction()
*/ */
char *strsignal(int sig) { noasan noinstrument char *strsignal(int sig) {
char *p;
const char *s; const char *s;
strcpy(g_strsignal, "SIG"); p = g_strsignal;
p[0] = 'S';
p[1] = 'I';
p[2] = 'G';
p[3] = 0;
if (sig) { if (sig) {
if ((s = GetMagnumStr(kSignalNames, sig))) { if ((s = GetMagnumStr(kSignalNames, sig))) {
strcpy(g_strsignal + 3, s); __stpcpy(p + 3, s);
return g_strsignal; return p;
} }
} }
if (!sig) { if (!sig) {
strcpy(g_strsignal + 3, "UNKNOWN"); p[3] = 'Z';
p[4] = 'E';
p[5] = 'R';
p[6] = 'O';
p[7] = 0;
} else if (1 <= sig && sig <= 128) { } else if (1 <= sig && sig <= 128) {
g_strsignal[3] = '0' + sig / 100; p[3] = '0' + sig / 100;
g_strsignal[4] = '0' + sig / 10 % 10; p[4] = '0' + sig / 10 % 10;
g_strsignal[5] = '0' + sig % 10; p[5] = '0' + sig % 10;
g_strsignal[6] = 0; p[6] = 0;
} else { } else {
strcpy(g_strsignal + 3, "WUT"); p[3] = 'W';
p[4] = 'U';
p[5] = 'T';
p[6] = 0;
} }
return g_strsignal; return g_strsignal;
} }

View file

@ -88,8 +88,8 @@ testonly void testlib_showerror_(int line, const char *wantcode,
} }
kprintf("\t%s%s%s\n" kprintf("\t%s%s%s\n"
"\t%s%s @ %s%s\n", "\t%s%s @ %s%s\n",
SUBTLE, strerror(e), RESET, SUBTLE, program_invocation_name, hostname, SUBTLE, strerror(e), RESET, SUBTLE,
RESET); firstnonnull(program_invocation_name, "unknown"), hostname, RESET);
free_s(&FREED_want); free_s(&FREED_want);
free_s(&FREED_got); free_s(&FREED_got);
++g_testlib_failed; ++g_testlib_failed;

View file

@ -35,6 +35,7 @@
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/nexgen32e/vendor.internal.h"
#include "libc/nexgen32e/x86feature.h" #include "libc/nexgen32e/x86feature.h"
#include "libc/runtime/internal.h" #include "libc/runtime/internal.h"
#include "libc/runtime/memtrack.internal.h" #include "libc/runtime/memtrack.internal.h"
@ -71,7 +72,7 @@ static bool runbenchmarks_;
void PrintUsage(int rc, FILE *f) { void PrintUsage(int rc, FILE *f) {
fputs("Usage: ", f); fputs("Usage: ", f);
fputs(program_invocation_name, f); fputs(firstnonnull(program_invocation_name, "unknown"), f);
fputs(USAGE, f); fputs(USAGE, f);
exit(rc); exit(rc);
} }
@ -102,17 +103,26 @@ static void EmptySignalMask(void) {
} }
static void FixIrregularFds(void) { static void FixIrregularFds(void) {
int i; int i, fd;
struct pollfd pfds[64]; struct pollfd pfds[64];
for (i = 0; i < 3; ++i) { for (i = 0; i < 3; ++i) {
if (fcntl(0, F_GETFL) == -1) { if (fcntl(i, F_GETFL) == -1) {
CHECK_EQ(0, open("/dev/null", O_RDWR)); errno = 0;
fd = open("/dev/null", O_RDWR);
CHECK_NE(-1, fd);
if (fd != i) {
close(fd);
}
} }
} }
for (i = 0; i < ARRAYLEN(pfds); ++i) { for (i = 0; i < ARRAYLEN(pfds); ++i) {
pfds[i].fd = i + 3; pfds[i].fd = i + 3;
pfds[i].events = POLLIN; pfds[i].events = POLLIN;
} }
if (IsGenuineCosmo()) {
// TODO(jart): Fix Blinkenlights poll() / close()
return;
}
if (poll(pfds, ARRAYLEN(pfds), 0) != -1) { if (poll(pfds, ARRAYLEN(pfds), 0) != -1) {
for (i = 0; i < ARRAYLEN(pfds); ++i) { for (i = 0; i < ARRAYLEN(pfds); ++i) {
if (pfds[i].revents & POLLNVAL) continue; if (pfds[i].revents & POLLNVAL) continue;

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/bits/safemacros.internal.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h" #include "libc/calls/struct/stat.h"
#include "libc/dce.h" #include "libc/dce.h"
@ -33,7 +34,9 @@ const char *path;
TEST(ftruncate, test) { TEST(ftruncate, test) {
mkdir("o", 0755); mkdir("o", 0755);
mkdir("o/tmp", 0755); mkdir("o/tmp", 0755);
path = gc(xasprintf("o/tmp/%s.%d", program_invocation_short_name, getpid())); path = gc(xasprintf("o/tmp/%s.%d",
firstnonnull(program_invocation_short_name, "unknown"),
getpid()));
ASSERT_NE(-1, (fd = creat(path, 0755))); ASSERT_NE(-1, (fd = creat(path, 0755)));
ASSERT_EQ(5, write(fd, "hello", 5)); ASSERT_EQ(5, write(fd, "hello", 5));
errno = 31337; errno = 31337;

View file

@ -98,7 +98,7 @@ TEST(setrlimit, testFileSizeLimit) {
ASSERT_EQ(0, setrlimit(RLIMIT_FSIZE, &rlim)); ASSERT_EQ(0, setrlimit(RLIMIT_FSIZE, &rlim));
snprintf(tmpname, sizeof(tmpname), "%s/%s.%d", snprintf(tmpname, sizeof(tmpname), "%s/%s.%d",
firstnonnull(getenv("TMPDIR"), "/tmp"), firstnonnull(getenv("TMPDIR"), "/tmp"),
program_invocation_short_name, getpid()); firstnonnull(program_invocation_short_name, "unknown"), getpid());
ASSERT_NE(-1, (fd = open(tmpname, O_RDWR | O_CREAT | O_TRUNC))); ASSERT_NE(-1, (fd = open(tmpname, O_RDWR | O_CREAT | O_TRUNC)));
rngset(junkdata, 512, rand64, -1); rngset(junkdata, 512, rand64, -1);
for (i = 0; i < 5 * 1024 * 1024 / 512; ++i) { for (i = 0; i < 5 * 1024 * 1024 / 512; ++i) {

View file

@ -20,7 +20,7 @@
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
TEST(strsignal, test) { TEST(strsignal, test) {
EXPECT_STREQ("SIGUNKNOWN", strsignal(0)); EXPECT_STREQ("SIGZERO", strsignal(0));
EXPECT_STREQ("SIGINT", strsignal(SIGINT)); EXPECT_STREQ("SIGINT", strsignal(SIGINT));
EXPECT_STREQ("SIGQUIT", strsignal(SIGQUIT)); EXPECT_STREQ("SIGQUIT", strsignal(SIGQUIT));
EXPECT_STREQ("SIGALRM", strsignal(SIGALRM)); EXPECT_STREQ("SIGALRM", strsignal(SIGALRM));

View file

@ -79,8 +79,10 @@ hidden char *getopt_place;
char kGetoptEmsg[1] hidden; char kGetoptEmsg[1] hidden;
static void getopt_print_badch(const char *s) { static void getopt_print_badch(const char *s) {
fputs(program_invocation_name, stderr); if (program_invocation_name) {
fputs(": ", stderr); fputs(program_invocation_name, stderr);
fputs(": ", stderr);
}
fputs(s, stderr); fputs(s, stderr);
fputs(" -- ", stderr); fputs(" -- ", stderr);
fputc(optopt, stderr); fputc(optopt, stderr);

View file

@ -17,12 +17,13 @@
/* clang-format off */ /* clang-format off */
#include "third_party/make/config.h" #include "third_party/make/config.h"
#include "third_party/make/getprogname.h" #include "third_party/make/getprogname.h"
#include "libc/bits/safemacros.internal.h"
#include "third_party/make/dirname.h" #include "third_party/make/dirname.h"
char const * char const *
getprogname (void) getprogname (void)
{ {
return program_invocation_short_name; return firstnonnull(program_invocation_short_name, "unknown");
} }
/* /*

View file

@ -16,6 +16,7 @@
*/ */
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/bits/bits.h" #include "libc/bits/bits.h"
#include "libc/bits/safemacros.internal.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/fmt/conv.h" #include "libc/fmt/conv.h"
@ -1011,8 +1012,8 @@ int execute_tests(int argc, const char **argv, const char *default_filename) {
file = fopen(test_filename, "r"); file = fopen(test_filename, "r");
if (file == NULL) { if (file == NULL) {
WRITE("%s (%s) failed to open test file: %s %m\n", WRITE("%s (%s) failed to open test file: %s %m\n",
program_invocation_short_name, GetProgramExecutableName(), firstnonnull(program_invocation_short_name, "unknown"),
test_filename); GetProgramExecutableName(), test_filename);
if (outcome_file != NULL) fclose(outcome_file); if (outcome_file != NULL) fclose(outcome_file);
return 1; return 1;
} }

View file

@ -25,26 +25,21 @@ int MachineFdAdd(struct MachineFds *mf) {
int fd; int fd;
struct MachineFdClosed *closed; struct MachineFdClosed *closed;
if ((closed = mf->closed)) { if ((closed = mf->closed)) {
DCHECK_LT(closed->fd, mf->i);
fd = closed->fd; fd = closed->fd;
mf->closed = closed->next; mf->closed = closed->next;
free(closed); free(closed);
} else { } else {
DCHECK_LE(mf->i, mf->n); fd = mf->i;
if (mf->i == mf->n) { if (mf->i++ == mf->n) {
if (!__grow(&mf->p, &mf->n, sizeof(struct MachineFd), 0)) { mf->n = mf->i + (mf->i >> 1);
return -1; mf->p = realloc(mf->p, mf->n * sizeof(*mf->p));
}
} }
fd = mf->i++;
} }
return fd; return fd;
} }
void MachineFdRemove(struct MachineFds *mf, int fd) { void MachineFdRemove(struct MachineFds *mf, int fd) {
struct MachineFdClosed *closed; struct MachineFdClosed *closed;
DCHECK_GE(fd, 0);
DCHECK_LT(fd, mf->i);
mf->p[fd].cb = NULL; mf->p[fd].cb = NULL;
if ((closed = malloc(sizeof(struct MachineFdClosed)))) { if ((closed = malloc(sizeof(struct MachineFdClosed)))) {
closed->fd = fd; closed->fd = fd;

View file

@ -25,6 +25,7 @@
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/nexgen32e/vendor.internal.h" #include "libc/nexgen32e/vendor.internal.h"
#include "libc/runtime/pc.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/sysv/consts/fileno.h" #include "libc/sysv/consts/fileno.h"
@ -65,9 +66,12 @@ static void LoadElfLoadSegment(struct Machine *m, void *code, size_t codesize,
CHECK_GE(vend - vstart, fstart - fend); CHECK_GE(vend - vstart, fstart - fend);
CHECK_LE(phdr->p_filesz, phdr->p_memsz); CHECK_LE(phdr->p_filesz, phdr->p_memsz);
CHECK_EQ(felf + phdr->p_offset - fstart, phdr->p_vaddr - vstart); CHECK_EQ(felf + phdr->p_offset - fstart, phdr->p_vaddr - vstart);
CHECK_NE(-1, ReserveVirtual(m, vstart, fend - fstart, 0x0207)); CHECK_NE(-1, ReserveVirtual(m, vstart, fend - fstart,
PAGE_V | PAGE_RW | PAGE_U | PAGE_RSRV));
VirtualRecv(m, vstart, (void *)fstart, fend - fstart); VirtualRecv(m, vstart, (void *)fstart, fend - fstart);
if (bsssize) CHECK_NE(-1, ReserveVirtual(m, vbss, bsssize, 0x0207)); if (bsssize)
CHECK_NE(-1, ReserveVirtual(m, vbss, bsssize,
PAGE_V | PAGE_RW | PAGE_U | PAGE_RSRV));
if (phdr->p_memsz - phdr->p_filesz > bsssize) { if (phdr->p_memsz - phdr->p_filesz > bsssize) {
VirtualSet(m, phdr->p_vaddr + phdr->p_filesz, 0, VirtualSet(m, phdr->p_vaddr + phdr->p_filesz, 0,
phdr->p_memsz - phdr->p_filesz - bsssize); phdr->p_memsz - phdr->p_filesz - bsssize);
@ -158,7 +162,8 @@ void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars,
sp = 0x800000000000; sp = 0x800000000000;
Write64(m->sp, sp); Write64(m->sp, sp);
m->cr3 = AllocateLinearPage(m); m->cr3 = AllocateLinearPage(m);
CHECK_NE(-1, ReserveVirtual(m, sp - STACKSIZE, STACKSIZE, 0x0207)); CHECK_NE(-1, ReserveVirtual(m, sp - STACKSIZE, STACKSIZE,
PAGE_V | PAGE_RW | PAGE_U | PAGE_RSRV));
LoadArgv(m, prog, args, vars); LoadArgv(m, prog, args, vars);
if (memcmp(elf->map, "\177ELF", 4) == 0) { if (memcmp(elf->map, "\177ELF", 4) == 0) {
elf->ehdr = (void *)elf->map; elf->ehdr = (void *)elf->map;

View file

@ -46,13 +46,18 @@ void SetWriteAddr(struct Machine *m, int64_t addr, uint32_t size) {
} }
} }
uint64_t HandlePageFault(struct Machine *m, uint64_t entry, uint64_t table, uint64_t HandlePageFault(struct Machine *m, int64_t virt, uint64_t entry,
unsigned index) { uint64_t table, unsigned index) {
long page; long page;
if ((page = AllocateLinearPage(m)) != -1) { if ((page = AllocateLinearPage(m)) != -1) {
--m->memstat.reserved; --m->memstat.reserved;
if (entry & PAGE_GROD) {
ReserveVirtual(m, virt - 4096, 4096,
PAGE_GROD | PAGE_RSRV |
(entry & (PAGE_XD | PAGE_U | PAGE_RW | PAGE_V)));
}
return (*(uint64_t *)(m->real.p + table + index * 8) = return (*(uint64_t *)(m->real.p + table + index * 8) =
page | entry & ~0x7ffffffffe00); page | entry & ~(PAGE_TA | PAGE_IGN1));
} else { } else {
return 0; return 0;
} }
@ -61,7 +66,7 @@ uint64_t HandlePageFault(struct Machine *m, uint64_t entry, uint64_t table,
uint64_t FindPage(struct Machine *m, int64_t virt) { uint64_t FindPage(struct Machine *m, int64_t virt) {
uint64_t table, entry; uint64_t table, entry;
unsigned level, index, i; unsigned level, index, i;
virt &= -0x1000; virt &= -4096;
for (i = 0; i < ARRAYLEN(m->tlb); ++i) { for (i = 0; i < ARRAYLEN(m->tlb); ++i) {
if (m->tlb[i].virt == virt && (m->tlb[i].entry & 1)) { if (m->tlb[i].virt == virt && (m->tlb[i].entry & 1)) {
return m->tlb[i].entry; return m->tlb[i].entry;
@ -76,8 +81,8 @@ uint64_t FindPage(struct Machine *m, int64_t virt) {
entry = *(uint64_t *)(m->real.p + table + index * 8); entry = *(uint64_t *)(m->real.p + table + index * 8);
if (!(entry & 1)) return 0; if (!(entry & 1)) return 0;
} while ((level -= 9) >= 12); } while ((level -= 9) >= 12);
if ((entry & 0x0e00) && if ((entry & PAGE_RSRV) &&
(entry = HandlePageFault(m, entry, table, index)) == -1) { (entry = HandlePageFault(m, virt, entry, table, index)) == -1) {
return 0; return 0;
} }
m->tlbindex = (m->tlbindex + 1) & (ARRAYLEN(m->tlb) - 1); m->tlbindex = (m->tlbindex + 1) & (ARRAYLEN(m->tlb) - 1);
@ -113,21 +118,21 @@ void *ResolveAddress(struct Machine *m, int64_t v) {
void VirtualSet(struct Machine *m, int64_t v, char c, uint64_t n) { void VirtualSet(struct Machine *m, int64_t v, char c, uint64_t n) {
char *p; char *p;
uint64_t k; uint64_t k;
k = 0x1000 - (v & 0xfff); k = 4096 - (v & 0xfff);
while (n) { while (n) {
k = MIN(k, n); k = MIN(k, n);
p = ResolveAddress(m, v); p = ResolveAddress(m, v);
memset(p, c, k); memset(p, c, k);
n -= k; n -= k;
v += k; v += k;
k = 0x1000; k = 4096;
} }
} }
void VirtualCopy(struct Machine *m, int64_t v, char *r, uint64_t n, bool d) { void VirtualCopy(struct Machine *m, int64_t v, char *r, uint64_t n, bool d) {
char *p; char *p;
uint64_t k; uint64_t k;
k = 0x1000 - (v & 0xfff); k = 4096 - (v & 0xfff);
while (n) { while (n) {
k = MIN(k, n); k = MIN(k, n);
p = ResolveAddress(m, v); p = ResolveAddress(m, v);
@ -139,7 +144,7 @@ void VirtualCopy(struct Machine *m, int64_t v, char *r, uint64_t n, bool d) {
n -= k; n -= k;
r += k; r += k;
v += k; v += k;
k = 0x1000; k = 4096;
} }
} }
@ -165,7 +170,7 @@ void VirtualRecvWrite(struct Machine *m, int64_t addr, void *src, uint64_t n) {
void *ReserveAddress(struct Machine *m, int64_t v, size_t n) { void *ReserveAddress(struct Machine *m, int64_t v, size_t n) {
void *r; void *r;
DCHECK_LE(n, sizeof(m->stash)); DCHECK_LE(n, sizeof(m->stash));
if ((v & 0xfff) + n <= 0x1000) return ResolveAddress(m, v); if ((v & 0xfff) + n <= 4096) return ResolveAddress(m, v);
m->stashaddr = v; m->stashaddr = v;
m->stashsize = n; m->stashsize = n;
r = m->stash; r = m->stash;
@ -177,11 +182,11 @@ void *AccessRam(struct Machine *m, int64_t v, size_t n, void *p[2],
uint8_t *tmp, bool copy) { uint8_t *tmp, bool copy) {
unsigned k; unsigned k;
uint8_t *a, *b; uint8_t *a, *b;
DCHECK_LE(n, 0x1000); DCHECK_LE(n, 4096);
if ((v & 0xfff) + n <= 0x1000) return ResolveAddress(m, v); if ((v & 0xfff) + n <= 4096) return ResolveAddress(m, v);
k = 0x1000; k = 4096;
k -= v & 0xfff; k -= v & 0xfff;
DCHECK_LE(k, 0x1000); DCHECK_LE(k, 4096);
a = ResolveAddress(m, v); a = ResolveAddress(m, v);
b = ResolveAddress(m, v + k); b = ResolveAddress(m, v + k);
if (copy) { if (copy) {
@ -220,9 +225,9 @@ void *BeginLoadStore(struct Machine *m, int64_t v, size_t n, void *p[2],
void EndStore(struct Machine *m, int64_t v, size_t n, void *p[2], uint8_t *b) { void EndStore(struct Machine *m, int64_t v, size_t n, void *p[2], uint8_t *b) {
uint8_t *a; uint8_t *a;
unsigned k; unsigned k;
DCHECK_LE(n, 0x1000); DCHECK_LE(n, 4096);
if ((v & 0xfff) + n <= 0x1000) return; if ((v & 0xfff) + n <= 4096) return;
k = 0x1000; k = 4096;
k -= v & 0xfff; k -= v & 0xfff;
DCHECK_GT(k, n); DCHECK_GT(k, n);
DCHECK_NOTNULL(p[0]); DCHECK_NOTNULL(p[0]);
@ -239,7 +244,7 @@ void EndStoreNp(struct Machine *m, int64_t v, size_t n, void *p[2],
void *LoadStr(struct Machine *m, int64_t addr) { void *LoadStr(struct Machine *m, int64_t addr) {
size_t have; size_t have;
char *copy, *page, *p; char *copy, *page, *p;
have = 0x1000 - (addr & 0xfff); have = 4096 - (addr & 0xfff);
if (!addr) return NULL; if (!addr) return NULL;
if (!(page = FindReal(m, addr))) return NULL; if (!(page = FindReal(m, addr))) return NULL;
if ((p = memchr(page, '\0', have))) { if ((p = memchr(page, '\0', have))) {
@ -247,16 +252,16 @@ void *LoadStr(struct Machine *m, int64_t addr) {
return page; return page;
} }
CHECK_LT(m->freelist.i, ARRAYLEN(m->freelist.p)); CHECK_LT(m->freelist.i, ARRAYLEN(m->freelist.p));
if (!(copy = malloc(have + 0x1000))) return NULL; if (!(copy = malloc(have + 4096))) return NULL;
memcpy(copy, page, have); memcpy(copy, page, have);
for (;;) { for (;;) {
if (!(page = FindReal(m, addr + have))) break; if (!(page = FindReal(m, addr + have))) break;
if ((p = memccpy(copy + have, page, '\0', 0x1000))) { if ((p = memccpy(copy + have, page, '\0', 4096))) {
SetReadAddr(m, addr, have + (p - (copy + have)) + 1); SetReadAddr(m, addr, have + (p - (copy + have)) + 1);
return (m->freelist.p[m->freelist.i++] = copy); return (m->freelist.p[m->freelist.i++] = copy);
} }
have += 0x1000; have += 4096;
if (!(p = realloc(copy, have + 0x1000))) break; if (!(p = realloc(copy, have + 4096))) break;
copy = p; copy = p;
} }
free(copy); free(copy);
@ -266,7 +271,7 @@ void *LoadStr(struct Machine *m, int64_t addr) {
void *LoadBuf(struct Machine *m, int64_t addr, size_t size) { void *LoadBuf(struct Machine *m, int64_t addr, size_t size) {
size_t have, need; size_t have, need;
char *buf, *copy, *page; char *buf, *copy, *page;
have = 0x1000 - (addr & 0xfff); have = 4096 - (addr & 0xfff);
if (!addr) return NULL; if (!addr) return NULL;
if (!(buf = FindReal(m, addr))) return NULL; if (!(buf = FindReal(m, addr))) return NULL;
if (size > have) { if (size > have) {
@ -274,7 +279,7 @@ void *LoadBuf(struct Machine *m, int64_t addr, size_t size) {
if (!(copy = malloc(size))) return NULL; if (!(copy = malloc(size))) return NULL;
buf = memcpy(copy, buf, have); buf = memcpy(copy, buf, have);
do { do {
need = MIN(0x1000, size - have); need = MIN(4096, size - have);
if ((page = FindReal(m, addr + have))) { if ((page = FindReal(m, addr + have))) {
memcpy(copy + have, page, need); memcpy(copy + have, page, need);
have += need; have += need;

View file

@ -21,6 +21,7 @@
#include "libc/log/check.h" #include "libc/log/check.h"
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/runtime/pc.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
@ -66,7 +67,7 @@ void ResetMem(struct Machine *m) {
long AllocateLinearPage(struct Machine *m) { long AllocateLinearPage(struct Machine *m) {
long page; long page;
if ((page = AllocateLinearPageRaw(m)) != -1) { if ((page = AllocateLinearPageRaw(m)) != -1) {
bzero(m->real.p + page, 0x1000); bzero(m->real.p + page, 4096);
} }
return page; return page;
} }
@ -77,12 +78,12 @@ long AllocateLinearPageRaw(struct Machine *m) {
struct MachineRealFree *rf; struct MachineRealFree *rf;
if ((rf = m->realfree)) { if ((rf = m->realfree)) {
DCHECK(rf->n); DCHECK(rf->n);
DCHECK_EQ(0, rf->i & 0xfff); DCHECK_EQ(0, rf->i & 4095);
DCHECK_EQ(0, rf->n & 0xfff); DCHECK_EQ(0, rf->n & 4095);
DCHECK_LE(rf->i + rf->n, m->real.i); DCHECK_LE(rf->i + rf->n, m->real.i);
i = rf->i; i = rf->i;
rf->i += 0x1000; rf->i += 4096;
if (!(rf->n -= 0x1000)) { if (!(rf->n -= 4096)) {
m->realfree = rf->next; m->realfree = rf->next;
free(rf); free(rf);
} }
@ -96,9 +97,9 @@ long AllocateLinearPageRaw(struct Machine *m) {
if (n) { if (n) {
n += n >> 1; n += n >> 1;
} else { } else {
n = 0x10000; n = 65536;
} }
n = ROUNDUP(n, 0x1000); n = ROUNDUP(n, 4096);
if ((p = realloc(p, n))) { if ((p = realloc(p, n))) {
m->real.p = p; m->real.p = p;
m->real.n = n; m->real.n = n;
@ -108,10 +109,10 @@ long AllocateLinearPageRaw(struct Machine *m) {
return -1; return -1;
} }
} }
DCHECK_EQ(0, i & 0xfff); DCHECK_EQ(0, i & 4095);
DCHECK_EQ(0, n & 0xfff); DCHECK_EQ(0, n & 4095);
DCHECK_LE(i + 0x1000, n); DCHECK_LE(i + 4096, n);
m->real.i += 0x1000; m->real.i += 4096;
++m->memstat.allocated; ++m->memstat.allocated;
} }
++m->memstat.committed; ++m->memstat.committed;
@ -130,7 +131,7 @@ static void MachineWrite64(struct Machine *m, unsigned long i, uint64_t x) {
int ReserveReal(struct Machine *m, size_t n) { int ReserveReal(struct Machine *m, size_t n) {
uint8_t *p; uint8_t *p;
DCHECK_EQ(0, n & 0xfff); DCHECK_EQ(0, n & 4095);
if (m->real.n < n) { if (m->real.n < n) {
if ((p = realloc(m->real.p, n))) { if ((p = realloc(m->real.p, n))) {
m->real.p = p; m->real.p = p;
@ -148,9 +149,9 @@ int ReserveVirtual(struct Machine *m, int64_t virt, size_t size, uint64_t key) {
int64_t ti, mi, pt, end, level; int64_t ti, mi, pt, end, level;
for (end = virt + size;;) { for (end = virt + size;;) {
for (pt = m->cr3, level = 39; level >= 12; level -= 9) { for (pt = m->cr3, level = 39; level >= 12; level -= 9) {
pt = pt & 0x7ffffffff000; pt = pt & PAGE_TA;
ti = (virt >> level) & 511; ti = (virt >> level) & 511;
mi = (pt & 0x7ffffffff000) + ti * 8; mi = (pt & PAGE_TA) + ti * 8;
pt = MachineRead64(m, mi); pt = MachineRead64(m, mi);
if (level > 12) { if (level > 12) {
if (!(pt & 1)) { if (!(pt & 1)) {
@ -165,7 +166,7 @@ int ReserveVirtual(struct Machine *m, int64_t virt, size_t size, uint64_t key) {
MachineWrite64(m, mi, key); MachineWrite64(m, mi, key);
++m->memstat.reserved; ++m->memstat.reserved;
} }
if ((virt += 0x1000) >= end) return 0; if ((virt += 4096) >= end) return 0;
if (++ti == 512) break; if (++ti == 512) break;
pt = MachineRead64(m, (mi += 8)); pt = MachineRead64(m, (mi += 8));
} }
@ -179,13 +180,13 @@ int64_t FindVirtual(struct Machine *m, int64_t virt, size_t size) {
do { do {
if (virt >= 0x800000000000) return enomem(); if (virt >= 0x800000000000) return enomem();
for (pt = m->cr3, i = 39; i >= 12; i -= 9) { for (pt = m->cr3, i = 39; i >= 12; i -= 9) {
pt = MachineRead64(m, (pt & 0x7ffffffff000) + ((virt >> i) & 511) * 8); pt = MachineRead64(m, (pt & PAGE_TA) + ((virt >> i) & 511) * 8);
if (!(pt & 1)) break; if (!(pt & 1)) break;
} }
if (i >= 12) { if (i >= 12) {
got += 1ull << i; got += 1ull << i;
} else { } else {
virt += 0x1000; virt += 4096;
got = 0; got = 0;
} }
} while (got < size); } while (got < size);
@ -195,10 +196,10 @@ int64_t FindVirtual(struct Machine *m, int64_t virt, size_t size) {
static void AppendRealFree(struct Machine *m, uint64_t real) { static void AppendRealFree(struct Machine *m, uint64_t real) {
struct MachineRealFree *rf; struct MachineRealFree *rf;
if (m->realfree && real == m->realfree->i + m->realfree->n) { if (m->realfree && real == m->realfree->i + m->realfree->n) {
m->realfree->n += 0x1000; m->realfree->n += 4096;
} else if ((rf = malloc(sizeof(struct MachineRealFree)))) { } else if ((rf = malloc(sizeof(struct MachineRealFree)))) {
rf->i = real; rf->i = real;
rf->n = 0x1000; rf->n = 4096;
rf->next = m->realfree; rf->next = m->realfree;
m->realfree = rf; m->realfree = rf;
} }
@ -208,17 +209,17 @@ int FreeVirtual(struct Machine *m, int64_t base, size_t size) {
uint64_t i, mi, pt, end, virt; uint64_t i, mi, pt, end, virt;
for (virt = base, end = virt + size; virt < end; virt += 1ull << i) { for (virt = base, end = virt + size; virt < end; virt += 1ull << i) {
for (pt = m->cr3, i = 39;; i -= 9) { for (pt = m->cr3, i = 39;; i -= 9) {
mi = (pt & 0x7ffffffff000) + ((virt >> i) & 511) * 8; mi = (pt & PAGE_TA) + ((virt >> i) & 511) * 8;
pt = MachineRead64(m, mi); pt = MachineRead64(m, mi);
if (!(pt & 1)) { if (!(pt & 1)) {
break; break;
} else if (i == 12) { } else if (i == 12) {
++m->memstat.freed; ++m->memstat.freed;
if (pt & 0x0e00) { if (pt & PAGE_RSRV) {
--m->memstat.reserved; --m->memstat.reserved;
} else { } else {
--m->memstat.committed; --m->memstat.committed;
AppendRealFree(m, pt & 0x7ffffffff000); AppendRealFree(m, pt & PAGE_TA);
} }
MachineWrite64(m, mi, 0); MachineWrite64(m, mi, 0);
break; break;

View file

@ -37,6 +37,7 @@
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/nexgen32e/vendor.internal.h" #include "libc/nexgen32e/vendor.internal.h"
#include "libc/runtime/gc.internal.h" #include "libc/runtime/gc.internal.h"
#include "libc/runtime/pc.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/sock/select.h" #include "libc/sock/select.h"
#include "libc/sock/sock.h" #include "libc/sock/sock.h"
@ -221,6 +222,7 @@ static int XlatMapFlags(int x) {
if (x & 2) res |= MAP_PRIVATE; if (x & 2) res |= MAP_PRIVATE;
if (x & 16) res |= MAP_FIXED; if (x & 16) res |= MAP_FIXED;
if (x & 32) res |= MAP_ANONYMOUS; if (x & 32) res |= MAP_ANONYMOUS;
if (x & 256) res |= MAP_GROWSDOWN;
return res; return res;
} }
@ -522,7 +524,8 @@ static int OpMadvise(struct Machine *m, int64_t addr, size_t length,
static int64_t OpBrk(struct Machine *m, int64_t addr) { static int64_t OpBrk(struct Machine *m, int64_t addr) {
addr = ROUNDUP(addr, PAGESIZE); addr = ROUNDUP(addr, PAGESIZE);
if (addr > m->brk) { if (addr > m->brk) {
if (ReserveVirtual(m, m->brk, addr - m->brk, 0x0207) != -1) { if (ReserveVirtual(m, m->brk, addr - m->brk,
PAGE_V | PAGE_RW | PAGE_U | PAGE_RSRV) != -1) {
m->brk = addr; m->brk = addr;
} }
} else if (addr < m->brk) { } else if (addr < m->brk) {
@ -545,9 +548,10 @@ static int64_t OpMmap(struct Machine *m, int64_t virt, size_t size, int prot,
VERBOSEF("MMAP%s %012lx %,ld %#x %#x %d %#lx", GetSimulated(), virt, size, VERBOSEF("MMAP%s %012lx %,ld %#x %#x %d %#lx", GetSimulated(), virt, size,
prot, flags, fd, offset); prot, flags, fd, offset);
if (prot & PROT_READ) { if (prot & PROT_READ) {
key = 0x0205; key = PAGE_RSRV | PAGE_U | PAGE_V;
if (prot & PROT_WRITE) key |= 2; if (prot & PROT_WRITE) key |= PAGE_RW;
if (!(prot & PROT_EXEC)) key |= 0x8000000000000000; if (!(prot & PROT_EXEC)) key |= PAGE_XD;
if (flags & 256 /* MAP_GROWSDOWN */) key |= PAGE_GROD;
flags = XlatMapFlags(flags); flags = XlatMapFlags(flags);
if (fd != -1 && (fd = XlatFd(m, fd)) == -1) return -1; if (fd != -1 && (fd = XlatFd(m, fd)) == -1) return -1;
if (!(flags & MAP_FIXED)) { if (!(flags & MAP_FIXED)) {
@ -1127,6 +1131,21 @@ static int OpGetrlimit(struct Machine *m, int resource, int64_t rlimitaddr) {
return enosys(); return enosys();
} }
static ssize_t OpReadlinkat(struct Machine *m, int dirfd, int64_t pathaddr,
int64_t bufaddr, size_t size) {
char *buf;
ssize_t rc;
const char *path;
if ((dirfd = XlatAfd(m, dirfd)) == -1) return -1;
path = LoadStr(m, pathaddr);
if (!(buf = malloc(size))) return enomem();
if ((rc = readlinkat(dirfd, path, buf, size)) != -1) {
VirtualRecvWrite(m, bufaddr, buf, rc);
}
free(buf);
return rc;
}
static int64_t OpGetcwd(struct Machine *m, int64_t bufaddr, size_t size) { static int64_t OpGetcwd(struct Machine *m, int64_t bufaddr, size_t size) {
size_t n; size_t n;
char *buf; char *buf;
@ -1437,6 +1456,7 @@ void OpSyscall(struct Machine *m, uint32_t rde) {
SYSCALL(0x106, OpFstatat(m, di, si, dx, r0)); SYSCALL(0x106, OpFstatat(m, di, si, dx, r0));
SYSCALL(0x107, OpUnlinkat(m, di, si, dx)); SYSCALL(0x107, OpUnlinkat(m, di, si, dx));
SYSCALL(0x108, OpRenameat(m, di, si, dx, r0)); SYSCALL(0x108, OpRenameat(m, di, si, dx, r0));
SYSCALL(0x10B, OpReadlinkat(m, di, si, dx, r0));
SYSCALL(0x10D, OpFaccessat(m, di, si, dx, r0)); SYSCALL(0x10D, OpFaccessat(m, di, si, dx, r0));
SYSCALL(0x113, splice(di, P(si), dx, P(r0), r8, XlatAtf(r9))); SYSCALL(0x113, splice(di, P(si), dx, P(r0), r8, XlatAtf(r9)));
SYSCALL(0x115, sync_file_range(di, si, dx, XlatAtf(r0))); SYSCALL(0x115, sync_file_range(di, si, dx, XlatAtf(r0)));

View file

@ -521,7 +521,8 @@ static bool OpenSpeaker(void) {
if (sox_) tryspeakerfns_[i++] = TrySox; if (sox_) tryspeakerfns_[i++] = TrySox;
} }
snprintf(fifopath_, sizeof(fifopath_), "%s%s.%d.%d.wav", kTmpPath, snprintf(fifopath_, sizeof(fifopath_), "%s%s.%d.%d.wav", kTmpPath,
program_invocation_short_name, getpid(), count); firstnonnull(program_invocation_short_name, "unknown"), getpid(),
count);
for (i = 0; i < ARRAYLEN(tryspeakerfns_); ++i) { for (i = 0; i < ARRAYLEN(tryspeakerfns_); ++i) {
if (tryspeakerfns_[i]) { if (tryspeakerfns_[i]) {
if (++speakerfails_ <= 2 && tryspeakerfns_[i]()) { if (++speakerfails_ <= 2 && tryspeakerfns_[i]()) {
@ -1363,7 +1364,7 @@ static void PrintUsage(int rc, FILE *f) {
static void GetOpts(int argc, char *argv[]) { static void GetOpts(int argc, char *argv[]) {
int opt; int opt;
snprintf(logpath_, sizeof(logpath_), "%s%s.log", kTmpPath, snprintf(logpath_, sizeof(logpath_), "%s%s.log", kTmpPath,
program_invocation_short_name); firstnonnull(program_invocation_short_name, "unknown"));
while ((opt = getopt(argc, argv, "?34AGSTVYabdfhnpstxyzvL:")) != -1) { while ((opt = getopt(argc, argv, "?34AGSTVYabdfhnpstxyzvL:")) != -1) {
switch (opt) { switch (opt) {
case 'y': case 'y':