diff options
Diffstat (limited to '')
-rw-r--r-- | src/log_actions.cc | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/src/log_actions.cc b/src/log_actions.cc new file mode 100644 index 0000000..6e47440 --- /dev/null +++ b/src/log_actions.cc @@ -0,0 +1,237 @@ +/** + * Copyright (c) 2018, 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 "log_actions.hh" + +#include "base/fs_util.hh" +#include "base/injector.hh" +#include "bound_tags.hh" +#include "config.h" +#include "piper_proc.hh" + +std::string +action_delegate::execute_action(const std::string& action_name) +{ + static auto& lnav_flags = injector::get<unsigned long&, lnav_flags_tag>(); + + if (lnav_flags & LNF_SECURE_MODE) { + return "unavailable in secure mode"; + } + + auto& ldh = this->ad_log_helper; + auto value_index = this->ad_press_value; + logline_value& lv = ldh.ldh_line_values.lvv_values[value_index]; + auto lf = ldh.ldh_file; + const auto format = lf->get_format(); + pid_t child_pid; + std::string retval; + + auto iter = format->lf_action_defs.find(action_name); + + const log_format::action_def& action = iter->second; + + auto_pipe in_pipe(STDIN_FILENO); + auto_pipe out_pipe(STDOUT_FILENO); + + in_pipe.open(); + if (action.ad_capture_output) { + out_pipe.open(); + } + + child_pid = fork(); + + in_pipe.after_fork(child_pid); + out_pipe.after_fork(child_pid); + + switch (child_pid) { + case -1: + retval = fmt::format( + FMT_STRING("error: unable to fork child process -- {}"), + strerror(errno)); + break; + case 0: { + const char* args[action.ad_cmdline.size() + 1]; + std::set<std::string> path_set(format->get_source_path()); + char env_buffer[64]; + int value_line; + std::string path; + + dup2(STDOUT_FILENO, STDERR_FILENO); + setenv("LNAV_ACTION_FILE", lf->get_filename().c_str(), 1); + snprintf(env_buffer, + sizeof(env_buffer), + "%ld", + (ldh.ldh_line - lf->begin()) + 1); + setenv("LNAV_ACTION_FILE_LINE", env_buffer, 1); + snprintf( + env_buffer, sizeof(env_buffer), "%d", ldh.ldh_y_offset + 1); + setenv("LNAV_ACTION_MSG_LINE", env_buffer, 1); + setenv("LNAV_ACTION_VALUE_NAME", lv.lv_meta.lvm_name.get(), 1); + value_line = ldh.ldh_y_offset - ldh.get_value_line(lv) + 1; + snprintf(env_buffer, sizeof(env_buffer), "%d", value_line); + setenv("LNAV_ACTION_VALUE_LINE", env_buffer, 1); + + for (const auto& path_iter : path_set) { + if (!path.empty()) { + path += ":"; + } + path += path_iter; + } + path += ":" + std::string(getenv("PATH")); + setenv("PATH", path.c_str(), 1); + for (size_t lpc = 0; lpc < action.ad_cmdline.size(); lpc++) { + args[lpc] = action.ad_cmdline[lpc].c_str(); + } + args[action.ad_cmdline.size()] = nullptr; + execvp(args[0], (char* const*) args); + fprintf(stderr, + "error: could not exec process -- %s:%s\n", + args[0], + strerror(errno)); + _exit(0); + } break; + default: { + static int exec_count = 0; + + const auto value = lv.to_string(); + + this->ad_child_cb(child_pid); + + if (write(in_pipe.write_end(), value.c_str(), value.size()) == -1) { + perror("execute_action write"); + } + in_pipe.close(); + + if (out_pipe.read_end() != -1) { + auto pp = std::make_shared<piper_proc>( + std::move(out_pipe.read_end()), + false, + lnav::filesystem::open_temp_file( + ghc::filesystem::temp_directory_path() + / "lnav.action.XXXXXX") + .map([](auto pair) { + ghc::filesystem::remove(pair.first); + + return pair; + }) + .expect("Cannot create temporary file for action") + .second); + auto desc = fmt::format(FMT_STRING("[{}] Output of {}"), + exec_count++, + action.ad_cmdline[0]); + + this->ad_piper_cb(desc, pp); + } + + return ""; + } break; + } + + return retval; +} + +bool +action_delegate::text_handle_mouse(textview_curses& tc, mouse_event& me) +{ + bool retval = false; + + if (me.me_button != mouse_button_t::BUTTON_LEFT) { + return false; + } + + vis_line_t mouse_line = vis_line_t(tc.get_top() + me.me_y); + int mouse_left = tc.get_left() + me.me_x; + + switch (me.me_state) { + case mouse_button_state_t::BUTTON_STATE_PRESSED: + if (mouse_line >= 0_vl && mouse_line <= tc.get_bottom()) { + size_t line_end_index = 0; + int x_offset; + + this->ad_press_line = mouse_line; + this->ad_log_helper.parse_line(mouse_line, true); + + this->ad_log_helper.get_line_bounds(this->ad_line_index, + line_end_index); + + struct line_range lr(this->ad_line_index, line_end_index); + + this->ad_press_value = -1; + + x_offset = this->ad_line_index + mouse_left; + if (lr.contains(x_offset)) { + for (size_t lpc = 0; + lpc < this->ad_log_helper.ldh_line_values.lvv_values + .size(); + lpc++) + { + auto& lv = this->ad_log_helper.ldh_line_values + .lvv_values[lpc]; + + if (lv.lv_origin.contains(x_offset)) { + this->ad_press_value = lpc; + break; + } + } + } + } + break; + case mouse_button_state_t::BUTTON_STATE_DRAGGED: + if (mouse_line != this->ad_press_line) { + this->ad_press_value = -1; + } + if (this->ad_press_value != -1) { + retval = true; + } + break; + case mouse_button_state_t::BUTTON_STATE_RELEASED: + if (this->ad_press_value != -1 && this->ad_press_line == mouse_line) + { + auto& lv = this->ad_log_helper.ldh_line_values + .lvv_values[this->ad_press_value]; + int x_offset = this->ad_line_index + mouse_left; + + if (lv.lv_origin.contains(x_offset)) { + auto lf = this->ad_log_helper.ldh_file; + const std::vector<std::string>* actions; + + actions = lf->get_format()->get_actions(lv); + if (actions != nullptr && !actions->empty()) { + const auto rc = execute_action(actions->at(0)); + + // lnav_data.ld_rl_view->set_value(rc); + } + } + retval = true; + } + break; + } + + return retval; +} |