From caee314a5093c648b528bf874a882f4fb689d63d Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Fri, 29 Jan 2021 01:27:09 -0800 Subject: [PATCH] Make PATH search do the right thing w/ empty path --- libc/calls/commandv.c | 27 +++++++---- libc/log/backtrace2.c | 2 + libc/x/rmrf.c | 58 ++++++++++++++++++++++ libc/x/x.h | 8 +++- libc/x/x.mk | 1 + test/libc/calls/commandv_test.c | 85 ++++++++++++++++++++++----------- tool/build/runitd.c | 6 ++- 7 files changed, 147 insertions(+), 40 deletions(-) create mode 100644 libc/x/rmrf.c diff --git a/libc/calls/commandv.c b/libc/calls/commandv.c index 316bf19c5..37d69bb08 100644 --- a/libc/calls/commandv.c +++ b/libc/calls/commandv.c @@ -27,7 +27,9 @@ static bool AccessCommand(char path[hasatleast PATH_MAX], const char *name, size_t namelen, size_t pathlen) { if (pathlen + 1 + namelen + 1 + 4 + 1 > PATH_MAX) return -1; if (pathlen && (path[pathlen - 1] != '/' && path[pathlen - 1] != '\\')) { - path[pathlen++] = '/'; + path[pathlen] = + !IsWindows() ? '/' : memchr(path, '\\', pathlen) ? '\\' : '/'; + pathlen++; } memcpy(path + pathlen, name, namelen + 1); if (isexecutable(path)) return true; @@ -43,15 +45,18 @@ static bool SearchPath(char path[hasatleast PATH_MAX], const char *name, size_t i; const char *p; p = firstnonnull(emptytonull(getenv("PATH")), "/bin:/usr/local/bin:/usr/bin"); - for (;; p += i) { - while (*p == ':' || *p == ';') ++p; - if (!*p) break; - for (i = 0; i < PATH_MAX && p[i] && p[i] != ':' && p[i] != ';'; ++i) { - path[i] = p[i]; + for (;;) { + for (i = 0; p[i] && p[i] != ':' && p[i] != ';'; ++i) { + if (i < PATH_MAX) path[i] = p[i]; } if (AccessCommand(path, name, namelen, i)) { return true; } + if (p[i] == ':' || p[i] == ';') { + p += i + 1; + } else { + break; + } } return false; } @@ -71,9 +76,12 @@ char *commandv(const char *name, char pathbuf[hasatleast PATH_MAX]) { int rc, olderr; if (!(namelen = strlen(name))) return PROGN(enoent(), NULL); if (namelen + 1 > PATH_MAX) return PROGN(enametoolong(), NULL); - if (name[0] == '/' || name[0] == '\\') { - memcpy(pathbuf, name, namelen + 1); - return pathbuf; + if (strchr(name, '/') || strchr(name, '\\')) { + if (AccessCommand(strcpy(pathbuf, ""), name, namelen, 0)) { + return pathbuf; + } else { + return NULL; + } } olderr = errno; if ((IsWindows() && @@ -81,7 +89,6 @@ char *commandv(const char *name, char pathbuf[hasatleast PATH_MAX]) { stpcpy(pathbuf, kNtSystemDirectory) - pathbuf) || AccessCommand(pathbuf, name, namelen, stpcpy(pathbuf, kNtWindowsDirectory) - pathbuf))) || - AccessCommand(strcpy(pathbuf, ""), name, namelen, 0) || SearchPath(pathbuf, name, namelen)) { errno = olderr; return pathbuf; diff --git a/libc/log/backtrace2.c b/libc/log/backtrace2.c index 5ad1775d7..f2e6eb44c 100644 --- a/libc/log/backtrace2.c +++ b/libc/log/backtrace2.c @@ -46,6 +46,8 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) { const struct StackFrame *frame; const char *debugbin, *p1, *p2, *p3, *addr2line; char buf[kBacktraceBufSize], *argv[kBacktraceMaxFrames]; + if (IsOpenbsd()) return -1; + if (IsWindows()) return -1; if (!(debugbin = FindDebugBinary()) || !(addr2line = GetAddr2linePath())) { return -1; } diff --git a/libc/x/rmrf.c b/libc/x/rmrf.c new file mode 100644 index 000000000..a74bd58ba --- /dev/null +++ b/libc/x/rmrf.c @@ -0,0 +1,58 @@ +/*-*- 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/struct/dirent.h" +#include "libc/calls/struct/stat.h" +#include "libc/mem/mem.h" +#include "libc/runtime/runtime.h" +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/dt.h" +#include "libc/x/x.h" + +static int rmrfdir(const char *dirpath) { + int rc; + DIR *d; + char *path; + struct dirent *e; + if (!(d = opendir(dirpath))) return -1; + for (rc = 0; (e = readdir(d));) { + if (!strcmp(e->d_name, ".")) continue; + if (!strcmp(e->d_name, "..")) continue; + if (strchr(e->d_name, '/')) abort(); + path = xjoinpaths(dirpath, e->d_name); + if ((e->d_type == DT_DIR ? rmrfdir(path) : unlink(path)) == -1) { + free(path); + closedir(d); + return -1; + } + free(path); + } + return closedir(d); +} + +/** + * Recursively removes file or directory. + */ +int rmrf(const char *path) { + struct stat st; + if (stat(path, &st) == -1) return -1; + if (!S_ISDIR(st.st_mode)) return unlink(path); + return rmrfdir(path); +} diff --git a/libc/x/x.h b/libc/x/x.h index a3ecdaf56..bf5ac600a 100644 --- a/libc/x/x.h +++ b/libc/x/x.h @@ -45,9 +45,15 @@ char *xstrdup(const char *) _XPNN _XMAL; char *xstrndup(const char *, size_t) _XPNN _XMAL; char *xstrcat(const char *, ...) paramsnonnull((1)) nullterminated() _XMAL; char *xstrmul(const char *, size_t) paramsnonnull((1)) _XMAL; +char *xinet_ntop(int, const void *) _XPNN _XMAL; + +/*───────────────────────────────────────────────────────────────────────────│─╗ +│ cosmopolitan § eXtended apis » files ─╬─│┼ +╚────────────────────────────────────────────────────────────────────────────│*/ + +int rmrf(const char *); char *xdirname(const char *) paramsnonnull() _XMAL; char *xjoinpaths(const char *, const char *) paramsnonnull() _XMAL; -char *xinet_ntop(int, const void *) _XPNN _XMAL; /*───────────────────────────────────────────────────────────────────────────│─╗ │ cosmopolitan § eXtended apis » time ─╬─│┼ diff --git a/libc/x/x.mk b/libc/x/x.mk index 6a8ca91ef..8471121ae 100644 --- a/libc/x/x.mk +++ b/libc/x/x.mk @@ -34,6 +34,7 @@ LIBC_X_A_CHECKS = \ LIBC_X_A_DIRECTDEPS = \ LIBC_CALLS \ + LIBC_CALLS_HEFTY \ LIBC_FMT \ LIBC_INTRIN \ LIBC_MEM \ diff --git a/test/libc/calls/commandv_test.c b/test/libc/calls/commandv_test.c index 5a811f51f..e355a5319 100644 --- a/test/libc/calls/commandv_test.c +++ b/test/libc/calls/commandv_test.c @@ -16,52 +16,81 @@ │ 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/dirent.h" +#include "libc/calls/struct/stat.h" #include "libc/dce.h" +#include "libc/log/check.h" #include "libc/mem/mem.h" #include "libc/runtime/gc.h" #include "libc/runtime/internal.h" #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/dt.h" #include "libc/testlib/testlib.h" #include "libc/x/x.h" uint64_t i; char pathbuf[PATH_MAX]; -const char *oldpath, *bindir, *homedir, *binsh, *sh; +const char *testdir, *oldpath; -TEST(commandv_00, todo) { /* TODO(jart): Improve this on Windows. */ - if (IsWindows()) exit(0); -} - -TEST(commandv_001, setupFiles) { +void SetUp(void) { mkdir("o", 0755); mkdir("o/tmp", 0755); - oldpath = strdup(getenv("PATH")); - homedir = xasprintf("o/tmp/home.%d", getpid()); - bindir = xasprintf("o/tmp/bin.%d", getpid()); - binsh = xasprintf("%s/sh.com", bindir); - ASSERT_NE(-1, mkdir(homedir, 0755)); - ASSERT_NE(-1, mkdir(bindir, 0755)); - ASSERT_NE(-1, touch(binsh, 0755)); - ASSERT_NE(-1, setenv("PATH", bindir, true)); + testdir = xasprintf("o/tmp/%s.%d", program_invocation_short_name, getpid()); + mkdir(testdir, 0755); + CHECK_NE(-1, chdir(testdir)); + mkdir("bin", 0755); + mkdir("home", 0755); + oldpath = strdup(nulltoempty(getenv("PATH"))); + CHECK_NE(-1, setenv("PATH", "bin", true)); } -TEST(commandv_010, testSlashes_wontSearchPath_butChecksAccess) { - sh = defer(unlink, gc(xasprintf("%s/sh.com", homedir))); - EXPECT_NE(-1, touch(sh, 0755)); +void TearDown(void) { + CHECK_NE(-1, setenv("PATH", oldpath, true)); + CHECK_NE(-1, chdir("../../..")); + CHECK_NE(-1, rmrf(testdir)); +} + +TEST(commandv, testPathSearch) { + EXPECT_NE(-1, touch("bin/sh", 0755)); + EXPECT_STREQ("bin/sh", commandv("sh", pathbuf)); +} + +TEST(commandv, testPathSearch_appendsComExtension) { + EXPECT_NE(-1, touch("bin/sh.com", 0755)); + EXPECT_STREQ("bin/sh.com", commandv("sh", pathbuf)); +} + +TEST(commandv, testSlashes_wontSearchPath_butChecksAccess) { + EXPECT_NE(-1, touch("home/sh", 0755)); i = g_syscount; - EXPECT_STREQ(sh, commandv(sh, pathbuf)); - if (!IsWindows()) EXPECT_EQ(i + 1 /* access() */, g_syscount); + EXPECT_STREQ("home/sh", commandv("home/sh", pathbuf)); + if (!IsWindows()) EXPECT_EQ(i + 1, g_syscount); } -TEST(commandv_999, teardown) { - setenv("PATH", oldpath, true); - unlink(binsh); - rmdir(bindir); - rmdir(homedir); - free(bindir); - free(binsh); - free(homedir); - free(oldpath); +TEST(commandv, testSlashes_wontSearchPath_butStillAppendsComExtension) { + EXPECT_NE(-1, touch("home/sh.com", 0755)); + i = g_syscount; + EXPECT_STREQ("home/sh.com", commandv("home/sh", pathbuf)); + if (!IsWindows()) EXPECT_EQ(i + 2, g_syscount); +} + +TEST(commandv, testSameDir_doesntHappenByDefault) { + EXPECT_NE(-1, touch("bog", 0755)); + EXPECT_EQ(NULL, commandv("bog", pathbuf)); +} + +TEST(commandv, testSameDir_willHappenWithColonBlank) { + CHECK_NE(-1, setenv("PATH", "bin:", true)); + EXPECT_NE(-1, touch("bog", 0755)); + EXPECT_STREQ("bog", commandv("bog", pathbuf)); +} + +TEST(commandv, testSameDir_willHappenWithColonBlank2) { + CHECK_NE(-1, setenv("PATH", ":bin", true)); + EXPECT_NE(-1, touch("bog", 0755)); + EXPECT_STREQ("bog", commandv("bog", pathbuf)); } diff --git a/tool/build/runitd.c b/tool/build/runitd.c index 808698a8e..09bf86d6b 100644 --- a/tool/build/runitd.c +++ b/tool/build/runitd.c @@ -393,7 +393,11 @@ int Serve(void) { if (!Poll() && (!g_timeout || g_interrupted)) break; } close(g_servfd); - LOGF("timeout expired, shutting down"); + if (!g_timeout) { + LOGF("timeout expired, shutting down"); + } else { + LOGF("got ctrl-c, shutting down"); + } return 0; }