diff options
Diffstat (limited to '')
-rw-r--r-- | src/tailer/drive_tailer.cc | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/src/tailer/drive_tailer.cc b/src/tailer/drive_tailer.cc new file mode 100644 index 0000000..18ead43 --- /dev/null +++ b/src/tailer/drive_tailer.cc @@ -0,0 +1,288 @@ +/** + * 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 <thread> + +#include <unistd.h> + +#include "base/auto_fd.hh" +#include "base/auto_pid.hh" +#include "config.h" +#include "ghc/filesystem.hpp" +#include "line_buffer.hh" +#include "tailerpp.hh" + +static void +read_err_pipe(auto_fd& err, std::string& eq) +{ + while (true) { + char buffer[1024]; + auto rc = read(err.get(), buffer, sizeof(buffer)); + + if (rc <= 0) { + break; + } + + eq.append(buffer, rc); + } +} + +int +main(int argc, char* const* argv) +{ + if (argc != 3) { + fprintf(stderr, "usage: %s <cmd> <path>\n", argv[0]); + exit(EXIT_FAILURE); + } + + auto in_pipe_res = auto_pipe::for_child_fd(STDIN_FILENO); + if (in_pipe_res.isErr()) { + fprintf(stderr, + "cannot open stdin pipe for child: %s\n", + in_pipe_res.unwrapErr().c_str()); + exit(EXIT_FAILURE); + } + + auto out_pipe_res = auto_pipe::for_child_fd(STDOUT_FILENO); + if (out_pipe_res.isErr()) { + fprintf(stderr, + "cannot open stdout pipe for child: %s\n", + out_pipe_res.unwrapErr().c_str()); + exit(EXIT_FAILURE); + } + + auto err_pipe_res = auto_pipe::for_child_fd(STDERR_FILENO); + if (err_pipe_res.isErr()) { + fprintf(stderr, + "cannot open stderr pipe for child: %s\n", + err_pipe_res.unwrapErr().c_str()); + exit(EXIT_FAILURE); + } + + auto fork_res = lnav::pid::from_fork(); + if (fork_res.isErr()) { + fprintf( + stderr, "cannot start tailer: %s\n", fork_res.unwrapErr().c_str()); + exit(EXIT_FAILURE); + } + + auto in_pipe = in_pipe_res.unwrap(); + auto out_pipe = out_pipe_res.unwrap(); + auto err_pipe = err_pipe_res.unwrap(); + auto child = fork_res.unwrap(); + + in_pipe.after_fork(child.in()); + out_pipe.after_fork(child.in()); + err_pipe.after_fork(child.in()); + + if (child.in_child()) { + auto this_exe = ghc::filesystem::path(argv[0]); + auto exe_dir = this_exe.parent_path(); + auto tailer_exe = exe_dir / "tailer"; + + execlp(tailer_exe.c_str(), tailer_exe.c_str(), "-k", nullptr); + exit(EXIT_FAILURE); + } + + std::string error_queue; + std::thread err_reader( + [err = std::move(err_pipe.read_end()), &error_queue]() mutable { + read_err_pipe(err, error_queue); + }); + + auto& to_child = in_pipe.write_end(); + auto& from_child = out_pipe.read_end(); + auto cmd = std::string(argv[1]); + + if (cmd == "open") { + send_packet( + to_child.get(), TPT_OPEN_PATH, TPPT_STRING, argv[2], TPPT_DONE); + } else if (cmd == "preview") { + send_packet(to_child.get(), + TPT_LOAD_PREVIEW, + TPPT_STRING, + argv[2], + TPPT_INT64, + int64_t{1234}, + TPPT_DONE); + } else if (cmd == "possible") { + send_packet( + to_child.get(), TPT_COMPLETE_PATH, TPPT_STRING, argv[2], TPPT_DONE); + } else { + fprintf(stderr, "error: unknown command -- %s\n", cmd.c_str()); + exit(EXIT_FAILURE); + } + + close(to_child.get()); + + bool done = false; + while (!done) { + auto read_res = tailer::read_packet(from_child); + + if (read_res.isErr()) { + fprintf(stderr, "read error: %s\n", read_res.unwrapErr().c_str()); + exit(EXIT_FAILURE); + } + + auto packet = read_res.unwrap(); + packet.match( + [&](const tailer::packet_eof& te) { + printf("all done!\n"); + done = true; + }, + [&](const tailer::packet_announce& pa) {}, + [&](const tailer::packet_log& te) { + printf("log: %s\n", te.pl_msg.c_str()); + }, + [&](const tailer::packet_error& pe) { + printf("Got an error: %s -- %s\n", + pe.pe_path.c_str(), + pe.pe_msg.c_str()); + + auto remote_path = ghc::filesystem::absolute( + ghc::filesystem::path(pe.pe_path)) + .relative_path(); + + printf("removing %s\n", remote_path.c_str()); + }, + [&](const tailer::packet_offer_block& pob) { + printf("Got an offer: %s %lld - %lld\n", + pob.pob_path.c_str(), + pob.pob_offset, + pob.pob_length); + + auto remote_path = ghc::filesystem::absolute( + ghc::filesystem::path(pob.pob_path)) + .relative_path(); +#if 0 + auto local_path = tmppath / remote_path; + auto fd = auto_fd(open(local_path.c_str(), O_RDONLY)); + + if (fd == -1) { + printf("sending need block\n"); + send_packet(to_child.get(), + TPT_NEED_BLOCK, + TPPT_STRING, pob.pob_path.c_str(), + TPPT_DONE); + return; + } + + struct stat st; + + if (fstat(fd, &st) == -1 || !S_ISREG(st.st_mode)) { + ghc::filesystem::remove_all(local_path); + send_packet(to_child.get(), + TPT_NEED_BLOCK, + TPPT_STRING, pob.pob_path.c_str(), + TPPT_DONE); + return; + } + auto_mem<char> buffer; + + buffer = (char *) malloc(pob.pob_length); + auto bytes_read = pread(fd, buffer, pob.pob_length, + pob.pob_offset); + + // fprintf(stderr, "debug: bytes_read %ld\n", bytes_read); + if (bytes_read == pob.pob_length) { + tailer::hash_frag thf; + calc_sha_256(thf.thf_hash, buffer, bytes_read); + + if (thf == pob.pob_hash) { + send_packet(to_child.get(), + TPT_ACK_BLOCK, + TPPT_STRING, pob.pob_path.c_str(), + TPPT_DONE); + return; + } + } else if (bytes_read == -1) { + ghc::filesystem::remove_all(local_path); + } + send_packet(to_child.get(), + TPT_NEED_BLOCK, + TPPT_STRING, pob.pob_path.c_str(), + TPPT_DONE); +#endif + }, + [&](const tailer::packet_tail_block& ptb) { +#if 0 + //printf("got a tail: %s %lld %ld\n", ptb.ptb_path.c_str(), + // ptb.ptb_offset, ptb.ptb_bits.size()); + auto remote_path = ghc::filesystem::absolute( + ghc::filesystem::path(ptb.ptb_path)).relative_path(); + auto local_path = tmppath / remote_path; + + ghc::filesystem::create_directories(local_path.parent_path()); + auto fd = auto_fd( + open(local_path.c_str(), O_WRONLY | O_APPEND | O_CREAT, + 0600)); + + if (fd == -1) { + perror("open"); + } else { + ftruncate(fd, ptb.ptb_offset); + pwrite(fd, ptb.ptb_bits.data(), ptb.ptb_bits.size(), ptb.ptb_offset); + } +#endif + }, + [&](const tailer::packet_synced& ps) { + + }, + [&](const tailer::packet_link& pl) { + printf("link value: %s -> %s\n", + pl.pl_path.c_str(), + pl.pl_link_value.c_str()); + }, + [&](const tailer::packet_preview_error& ppe) { + fprintf(stderr, + "preview error: %s -- %s\n", + ppe.ppe_path.c_str(), + ppe.ppe_msg.c_str()); + }, + [&](const tailer::packet_preview_data& ppd) { + printf("preview of file: %s\n%.*s\n", + ppd.ppd_path.c_str(), + (int) ppd.ppd_bits.size(), + ppd.ppd_bits.data()); + }, + [&](const tailer::packet_possible_path& ppp) { + printf("possible path: %s\n", ppp.ppp_path.c_str()); + }); + } + + auto finished_child = std::move(child).wait_for_child(); + if (!finished_child.was_normal_exit()) { + fprintf(stderr, "error: child exited abnormally\n"); + } + + err_reader.join(); + + printf("tailer stderr:\n%s", error_queue.c_str()); + fprintf(stderr, "tailer stderr:\n%s", error_queue.c_str()); +} |