[arc/remote] use a single work directory for archive/remote files

pull/870/head
Timothy Stack 3 years ago
parent e13816a8e3
commit be51a4e3de

@ -50,10 +50,10 @@ Archive Support
If **lnav** is compiled with `libarchive <https://www.libarchive.org>`_,
any files to be opened will be examined to see if they are a supported archive
type. If so, the contents of the archive will be extracted to the
:code:`$TMPDIR/lnav-${UID}-archives/` directory. Once extracted, the files
within will be loaded into lnav. To speed up opening large amounts of files,
any file that meets the following conditions will be automatically hidden and
not indexed:
:code:`$TMPDIR/lnav-user-${UID}-work/archives/` directory. Once extracted, the
files within will be loaded into lnav. To speed up opening large amounts of
files, any file that meets the following conditions will be automatically
hidden and not indexed:
* Binary files
* Plain text files that are larger than 128KB

@ -44,6 +44,7 @@
#include "base/injector.hh"
#include "base/lnav_log.hh"
#include "base/humanize.hh"
#include "base/paths.hh"
#include "lnav_util.hh"
#include "archive_manager.hh"
@ -164,10 +165,7 @@ bool is_archive(const fs::path& filename)
static
fs::path archive_cache_path()
{
auto subdir_name = fmt::format("lnav-{}-archives", getuid());
auto tmp_path = fs::temp_directory_path();
return tmp_path / fs::path(subdir_name);
return lnav::paths::workdir() / "archives";
}
fs::path

@ -13,6 +13,7 @@ add_library(base STATIC
lnav.gzip.cc
lnav_log.cc
network.tcp.cc
paths.cc
string_util.cc
time_util.cc
@ -33,6 +34,7 @@ add_library(base STATIC
lrucache.hpp
math_util.hh
network.tcp.hh
paths.hh
result.h
time_util.hh
)

@ -38,6 +38,7 @@ noinst_HEADERS = \
math_util.hh \
network.tcp.hh \
opt_util.hh \
paths.hh \
result.h \
string_util.hh \
time_util.hh
@ -54,6 +55,7 @@ libbase_a_SOURCES = \
lnav.gzip.cc \
lnav_log.cc \
network.tcp.cc \
paths.cc \
string_util.cc \
time_util.cc

@ -0,0 +1,83 @@
/**
* Copyright (c) 2021, Timothy Stack
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of Timothy Stack nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "paths.hh"
#include "fmt/format.h"
namespace lnav {
namespace paths {
ghc::filesystem::path dotlnav()
{
auto home_env = getenv("HOME");
auto xdg_config_home = getenv("XDG_CONFIG_HOME");
if (home_env != nullptr) {
auto home_path = ghc::filesystem::path(home_env);
if (ghc::filesystem::is_directory(home_path)) {
auto home_lnav = home_path / ".lnav";
if (ghc::filesystem::is_directory(home_lnav)) {
return home_lnav;
}
if (xdg_config_home != nullptr) {
auto xdg_path = ghc::filesystem::path(xdg_config_home);
if (ghc::filesystem::is_directory(xdg_path)) {
return xdg_path / "lnav";
}
}
auto home_config = home_path / ".config";
if (ghc::filesystem::is_directory(home_config)) {
return home_config / "lnav";
}
return home_lnav;
}
}
return ghc::filesystem::current_path();
}
ghc::filesystem::path workdir()
{
auto subdir_name = fmt::format("lnav-user-{}-work", getuid());
auto tmp_path = ghc::filesystem::temp_directory_path();
return tmp_path / ghc::filesystem::path(subdir_name);
}
}
}

@ -0,0 +1,51 @@
/**
* Copyright (c) 2021, Timothy Stack
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of Timothy Stack nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef lnav_paths_hh
#define lnav_paths_hh
#include "ghc/filesystem.hpp"
namespace lnav {
namespace paths {
/**
* Compute the path to a file in the user's '.lnav' directory.
*
* @param sub The path to the file in the '.lnav' directory.
* @return The full path
*/
ghc::filesystem::path dotlnav();
ghc::filesystem::path workdir();
}
}
#endif

@ -86,6 +86,7 @@
#include "base/isc.hh"
#include "base/string_util.hh"
#include "base/lnav_log.hh"
#include "base/paths.hh"
#include "bound_tags.hh"
#include "lnav_util.hh"
#include "ansi_scrubber.hh"
@ -1399,7 +1400,7 @@ static void looper()
sc.window_change();
}
auto session_path = dotlnav_path() / "session";
auto session_path = lnav::paths::dotlnav() / "session";
execute_file(ec, session_path.string());
sb(*lnav_data.ld_view_stack.top());
@ -1928,7 +1929,7 @@ int main(int argc, char *argv[])
lnav_data.ld_debug_log_name = "/dev/null";
lnav_data.ld_config_paths.emplace_back("/etc/lnav");
lnav_data.ld_config_paths.emplace_back(SYSCONFDIR "/lnav");
lnav_data.ld_config_paths.emplace_back(dotlnav_path());
lnav_data.ld_config_paths.emplace_back(lnav::paths::dotlnav());
while ((c = getopt(argc, argv, "hHarRCc:I:iuf:d:nNqtw:vVW")) != -1) {
switch (c) {
case 'h':
@ -2075,8 +2076,8 @@ int main(int argc, char *argv[])
}
if (lnav_data.ld_flags & LNF_INSTALL) {
auto formats_installed_path = dotlnav_path() / "formats/installed";
auto configs_installed_path = dotlnav_path() / "configs/installed";
auto formats_installed_path = lnav::paths::dotlnav() / "formats/installed";
auto configs_installed_path = lnav::paths::dotlnav() / "configs/installed";
if (argc == 0) {
fprintf(stderr, "error: expecting file format paths\n");
@ -2604,7 +2605,7 @@ SELECT tbl_name FROM sqlite_master WHERE sql LIKE 'CREATE VIRTUAL TABLE%'
if (load_stdin && !isatty(STDIN_FILENO) && !is_dev_null(STDIN_FILENO) && !exec_stdin) {
if (stdin_out == nullptr) {
auto pattern = dotlnav_path() / "stdin-captures/stdin.XXXXXX";
auto pattern = lnav::paths::dotlnav() / "stdin-captures/stdin.XXXXXX";
auto open_result = open_temp_file(pattern);
if (open_result.isErr()) {

@ -47,6 +47,7 @@
#include "base/humanize.network.hh"
#include "base/injector.hh"
#include "base/isc.hh"
#include "base/paths.hh"
#include "base/string_util.hh"
#include "curl_looper.hh"
#include "lnav.hh"
@ -1248,7 +1249,7 @@ static Result<string, string> com_pipe_to(exec_context &ec, string cmdline, vect
string path;
dup2(STDOUT_FILENO, STDERR_FILENO);
path_v.emplace_back(dotlnav_path() / "formats/default");
path_v.emplace_back(lnav::paths::dotlnav() / "formats/default");
if (pipe_line_to && tc == &lnav_data.ld_views[LNV_LOG]) {
logfile_sub_source &lss = lnav_data.ld_log_source;
@ -2050,8 +2051,8 @@ static Result<string, string> com_session(exec_context &ec, string cmdline, vect
}
else {
auto saved_cmd = trim(remaining_args(cmdline, args));
auto old_file_name = dotlnav_path() / "session";
auto new_file_name = dotlnav_path() / "session.tmp";
auto old_file_name = lnav::paths::dotlnav() / "session";
auto new_file_name = lnav::paths::dotlnav() / "session.tmp";
ifstream session_file(old_file_name.string());
ofstream new_session_file(new_file_name.string());

@ -49,6 +49,7 @@
#include "auto_fd.hh"
#include "base/injector.hh"
#include "base/injector.bind.hh"
#include "base/paths.hh"
#include "base/string_util.hh"
#include "base/lnav_log.hh"
#include "lnav_util.hh"
@ -86,42 +87,6 @@ static auto lc = injector::bind<lnav::logfile::config>::to_instance(+[]() {
return &lnav_config.lc_logfile;
});
ghc::filesystem::path dotlnav_path()
{
auto home_env = getenv("HOME");
auto xdg_config_home = getenv("XDG_CONFIG_HOME");
if (home_env != nullptr) {
auto home_path = ghc::filesystem::path(home_env);
if (ghc::filesystem::is_directory(home_path)) {
auto home_lnav = home_path / ".lnav";
if (ghc::filesystem::is_directory(home_lnav)) {
return home_lnav;
}
if (xdg_config_home != nullptr) {
auto xdg_path = ghc::filesystem::path(xdg_config_home);
if (ghc::filesystem::is_directory(xdg_path)) {
return xdg_path / "lnav";
}
}
auto home_config = home_path / ".config";
if (ghc::filesystem::is_directory(home_config)) {
return home_config / "lnav";
}
return home_lnav;
}
}
return ghc::filesystem::current_path();
}
bool check_experimental(const char *feature_name)
{
const char *env_value = getenv("LNAV_EXP");
@ -150,7 +115,7 @@ void ensure_dotlnav()
"crash",
};
auto path = dotlnav_path();
auto path = lnav::paths::dotlnav();
for (auto sub_path : subdirs) {
auto full_path = path / sub_path;
@ -203,9 +168,9 @@ bool install_from_git(const char *repo)
{
static const std::regex repo_name_converter("[^\\w]");
auto formats_path = dotlnav_path() / "formats";
auto configs_path = dotlnav_path() / "configs";
auto staging_path = dotlnav_path() / "staging";
auto formats_path = lnav::paths::dotlnav() / "formats";
auto configs_path = lnav::paths::dotlnav() / "configs";
auto staging_path = lnav::paths::dotlnav() / "staging";
string local_name = std::regex_replace(repo, repo_name_converter, "_");
auto local_formats_path = formats_path / local_name;
@ -289,7 +254,7 @@ bool install_from_git(const char *repo)
bool update_installs_from_git()
{
static_root_mem<glob_t, globfree> gl;
auto git_formats = dotlnav_path() / "formats/*/.git";
auto git_formats = lnav::paths::dotlnav() / "formats/*/.git";
bool found = false, retval = true;
if (glob(git_formats.c_str(), GLOB_NOCHECK, nullptr, gl.inout()) == 0) {
@ -341,7 +306,7 @@ static struct json_path_container format_handlers = {
void install_extra_formats()
{
auto config_root = dotlnav_path() / "remote-config";
auto config_root = lnav::paths::dotlnav() / "remote-config";
auto_fd fd;
if (access(config_root.c_str(), R_OK) == 0) {
@ -1131,10 +1096,10 @@ static void load_default_configs(struct _lnav_config &config_obj,
void load_config(const vector<ghc::filesystem::path> &extra_paths, vector<string> &errors)
{
auto user_config = dotlnav_path() / "config.json";
auto user_config = lnav::paths::dotlnav() / "config.json";
for (auto& bsf : lnav_config_json) {
auto sample_path = dotlnav_path() /
auto sample_path = lnav::paths::dotlnav() /
"configs" /
"default" /
fmt::format("{}.sample", bsf.get_name());
@ -1199,8 +1164,8 @@ string save_config()
{
yajlpp_gen gen;
auto filename = fmt::format("config.json.{}.tmp", getpid());
auto user_config_tmp = dotlnav_path() / filename;
auto user_config = dotlnav_path() / "config.json";
auto user_config_tmp = lnav::paths::dotlnav() / filename;
auto user_config = lnav::paths::dotlnav() / "config.json";
yajl_gen_config(gen, yajl_gen_beautify, true);
yajlpp_gen_context ygc(gen, lnav_config_handlers);

@ -50,14 +50,6 @@
#include "file_vtab.cfg.hh"
#include "logfile.cfg.hh"
/**
* Compute the path to a file in the user's '.lnav' directory.
*
* @param sub The path to the file in the '.lnav' directory.
* @return The full path
*/
ghc::filesystem::path dotlnav_path();
/**
* Check if an experimental feature should be enabled by
* examining the LNAV_EXP environment variable.

@ -42,6 +42,7 @@
#include "fmt/format.h"
#include "base/paths.hh"
#include "base/string_util.hh"
#include "yajlpp/yajlpp.hh"
#include "yajlpp/yajlpp_def.hh"
@ -760,7 +761,7 @@ struct json_path_container root_format_handler = json_path_container {
static void write_sample_file()
{
for (const auto& bsf : lnav_format_json) {
auto sample_path = dotlnav_path() /
auto sample_path = lnav::paths::dotlnav() /
fmt::format("formats/default/{}.sample", bsf.get_name());
auto sf = bsf.to_string_fragment();
auto_fd sample_fd;
@ -777,7 +778,7 @@ static void write_sample_file()
}
for (const auto& bsf : lnav_sh_scripts) {
auto sh_path = dotlnav_path() / fmt::format("formats/default/{}", bsf.get_name());
auto sh_path = lnav::paths::dotlnav() / fmt::format("formats/default/{}", bsf.get_name());
auto sf = bsf.to_string_fragment();
auto_fd sh_fd;
@ -799,7 +800,7 @@ static void write_sample_file()
extract_metadata(sf.data(), sf.length(), meta);
snprintf(path, sizeof(path), "formats/default/%s.lnav", meta.sm_name.c_str());
auto script_path = dotlnav_path() / path;
auto script_path = lnav::paths::dotlnav() / path;
if (statp(script_path, &st) == 0 && st.st_size == sf.length()) {
// Assume it's the right contents and move on...
continue;
@ -922,7 +923,7 @@ static void load_from_path(const ghc::filesystem::path &path, std::vector<string
void load_formats(const std::vector<ghc::filesystem::path> &extra_paths,
std::vector<std::string> &errors)
{
auto default_source = dotlnav_path() / "default";
auto default_source = lnav::paths::dotlnav() / "default";
yajlpp_parse_context ypc_builtin(default_source.string(), &root_format_handler);
std::vector<intern_string_t> retval;
struct userdata ud;

@ -54,9 +54,9 @@
#include <string>
#include <utility>
#include "base/paths.hh"
#include "base/string_util.hh"
#include "fmt/format.h"
#include "lnav_config.hh"
#include "shlex.hh"
#include "auto_mem.hh"
#include "base/lnav_log.hh"
@ -502,7 +502,7 @@ readline_context::readline_context(std::string name,
memset(&this->rc_history, 0, sizeof(this->rc_history));
history_set_history_state(&this->rc_history);
auto config_dir = dotlnav_path();
auto config_dir = lnav::paths::dotlnav();
auto hpath = (config_dir / this->rc_name).string() + ".history";
read_history(hpath.c_str());
this->save();
@ -946,7 +946,7 @@ void readline_curses::start()
}
}
auto config_dir = dotlnav_path();
auto config_dir = lnav::paths::dotlnav();
for (auto& pair : this->rc_contexts) {
pair.second->load();

@ -41,6 +41,7 @@
#include <yajl/api/yajl_tree.h>
#include "base/isc.hh"
#include "base/paths.hh"
#include "tailer/tailer.looper.hh"
#include "yajlpp/yajlpp.hh"
#include "yajlpp/yajlpp_def.hh"
@ -48,7 +49,6 @@
#include "logfile.hh"
#include "sql_util.hh"
#include "lnav_util.hh"
#include "lnav_config.hh"
#include "session_data.hh"
#include "command_executor.hh"
#include "log_format_ext.hh"
@ -231,7 +231,7 @@ static void cleanup_session_data()
static_root_mem<glob_t, globfree> session_file_list;
std::list<struct session_file_info> session_info_list;
map<string, int> session_count;
auto session_file_pattern = dotlnav_path() / "*-*.ts*.json";
auto session_file_pattern = lnav::paths::dotlnav() / "*-*.ts*.json";
if (glob(session_file_pattern.c_str(),
0,
@ -349,7 +349,7 @@ nonstd::optional<session_pair_t> scan_sessions()
snprintf(view_info_pattern_base, sizeof(view_info_pattern_base),
"view-info-%s.*.json",
session_id.value().c_str());
auto view_info_pattern = dotlnav_path() / view_info_pattern_base;
auto view_info_pattern = lnav::paths::dotlnav() / view_info_pattern_base;
if (glob(view_info_pattern.c_str(), 0, nullptr,
view_info_list.inout()) == 0) {
for (size_t lpc = 0; lpc < view_info_list->gl_pathc; lpc++) {
@ -401,7 +401,7 @@ void load_time_bookmarks()
logfile_sub_source &lss = lnav_data.ld_log_source;
std::map<content_line_t, bookmark_metadata> &bm_meta = lss.get_user_bookmark_metadata();
auto_mem<sqlite3, sqlite_close_wrapper> db;
auto db_path = dotlnav_path() / LOG_METADATA_NAME;
auto db_path = lnav::paths::dotlnav() / LOG_METADATA_NAME;
auto_mem<sqlite3_stmt> stmt(sqlite3_finalize);
logfile_sub_source::iterator file_iter;
bool reload_needed = false;
@ -1065,7 +1065,7 @@ static void save_user_bookmarks(
static void save_time_bookmarks()
{
auto_mem<sqlite3, sqlite_close_wrapper> db;
auto db_path = dotlnav_path() / LOG_METADATA_NAME;
auto db_path = lnav::paths::dotlnav() / LOG_METADATA_NAME;
auto_mem<char, sqlite3_free> errmsg;
auto_mem<sqlite3_stmt> stmt(sqlite3_finalize);
@ -1370,7 +1370,7 @@ static void save_session_with_id(const std::string session_id)
lnav_data.ld_session_time,
getppid());
auto view_file_name = dotlnav_path() / view_base_name;
auto view_file_name = lnav::paths::dotlnav() / view_base_name;
auto view_file_tmp_name = view_file_name.string() + ".tmp";

@ -33,6 +33,7 @@
#include "base/humanize.network.hh"
#include "base/lnav_log.hh"
#include "base/paths.hh"
#include "tailer.looper.hh"
#include "tailer.h"
#include "tailerpp.hh"
@ -303,8 +304,7 @@ tailer::looper::host_tailer::for_host(const std::string& netloc)
ghc::filesystem::path tailer::looper::host_tailer::tmp_path()
{
auto local_path = ghc::filesystem::temp_directory_path() /
fmt::format("lnav-{}-remotes", getuid());
auto local_path = lnav::paths::workdir() / "remotes";
ghc::filesystem::create_directories(local_path);
auto_mem<char> resolved_path;

@ -60,14 +60,14 @@ EOF
run_test env TMPDIR=tmp ${lnav_test} -d /tmp/lnav.err -n \
logfile_syslog.1.xz
sed -e "s|lnav-[0-9]*-archives|lnav-NNN-archives|g" \
sed -e "s|lnav-user-[0-9]*-work|lnav-user-NNN-work|g" \
-e "s|arc-[0-9a-z]*-logfile|arc-NNN-logfile|g" \
-e "s|space on disk \(.*\) is|space on disk (NNN) is|g" \
-e "s|${builddir}||g" \
`test_err_filename` > test_logfile.big.out
mv test_logfile.big.out `test_err_filename`
check_error_output "decompression worked?" <<EOF
error: unable to open file: /logfile_syslog.1.xz -- available space on disk (NNN) is below the minimum-free threshold (1.0PB). Unable to unpack 'logfile_syslog.1.xz' to 'tmp/lnav-NNN-archives/arc-NNN-logfile_syslog.1.xz'
error: unable to open file: /logfile_syslog.1.xz -- available space on disk (NNN) is below the minimum-free threshold (1.0PB). Unable to unpack 'logfile_syslog.1.xz' to 'tmp/lnav-user-NNN-work/archives/arc-NNN-logfile_syslog.1.xz'
EOF
run_test env TMPDIR=tmp ${lnav_test} -n \
@ -101,12 +101,12 @@ EOF
10.112.81.15 - - [15/Feb/2013:06:00:31 +0000] "-" 400 0 "-" "-"
EOF
if ! test -f tmp/*/*-test-logs.tgz/test/logfile_access_log.0; then
if ! test -f tmp/*/archives/*-test-logs.tgz/test/logfile_access_log.0; then
echo "archived file not unpacked"
exit 1
fi
if test -w tmp/*/*-test-logs.tgz/test/logfile_access_log.0; then
if test -w tmp/*/archives/*-test-logs.tgz/test/logfile_access_log.0; then
echo "archived file is writable"
exit 1
fi
@ -115,7 +115,7 @@ EOF
-c ':config /tuning/archive-manager/cache-ttl 0d' \
-n -q ${srcdir}/logfile_syslog.0
if test -f tmp/lnav*/*-test-logs.tgz/test/logfile_access_log.0; then
if test -f tmp/lnav*/archives/*-test-logs.tgz/test/logfile_access_log.0; then
echo "archive cache not deleted?"
exit 1
fi
@ -144,14 +144,14 @@ EOF
chmod ugo-w rotmp
run_test env TMPDIR=rotmp ${lnav_test} -n test-logs.tgz
sed -e "s|lnav-[0-9]*-archives|lnav-NNN-archives|g" \
sed -e "s|lnav-user-[0-9]*-work|lnav-user-NNN-work|g" \
-e "s|arc-[0-9a-z]*-test|arc-NNN-test|g" \
-e "s|${builddir}||g" \
`test_err_filename` | head -1 \
> test_logfile.rotmp.out
mv test_logfile.rotmp.out `test_err_filename`
cp test_logfile.rotmp.out `test_err_filename`
check_error_output "archive not unpacked" <<EOF
error: unable to open file: /test-logs.tgz -- unable to write entry: rotmp/lnav-NNN-archives/arc-NNN-test-logs.tgz/test/logfile_access_log.0 -- Failed to create dir 'rotmp/lnav-NNN-archives'
error: unable to open file: /test-logs.tgz -- unable to write entry: rotmp/lnav-user-NNN-work/archives/arc-NNN-test-logs.tgz/test/logfile_access_log.0 -- Failed to create dir 'rotmp/lnav-user-NNN-work'
EOF
fi

Loading…
Cancel
Save