1 /**
2  * Copyright (c) 2007-2012, Timothy Stack
3  *
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * * Redistributions of source code must retain the above copyright notice, this
10  * list of conditions and the following disclaimer.
11  * * Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  * * Neither the name of Timothy Stack nor the names of its contributors
15  * may be used to endorse or promote products derived from this software
16  * without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  * @file lnav.hh
30  */
31 
32 #ifndef lnav_hh
33 #define lnav_hh
34 
35 #include "config.h"
36 
37 #include <signal.h>
38 #include <sys/time.h>
39 
40 #include <map>
41 #include <set>
42 #include <list>
43 #include <stack>
44 #include <memory>
45 #include <unordered_map>
46 
47 #include "base/future_util.hh"
48 #include "base/isc.hh"
49 #include "safe/safe.h"
50 #include "logfile.hh"
51 #include "hist_source.hh"
52 #include "statusview_curses.hh"
53 #include "listview_curses.hh"
54 #include "top_status_source.hh"
55 #include "bottom_status_source.hh"
56 #include "doc_status_source.hh"
57 #include "grep_highlighter.hh"
58 #include "db_sub_source.hh"
59 #include "textfile_sub_source.hh"
60 #include "log_vtab_impl.hh"
61 #include "readline_curses.hh"
62 #include "piper_proc.hh"
63 #include "relative_time.hh"
64 #include "log_format_loader.hh"
65 #include "spectro_source.hh"
66 #include "command_executor.hh"
67 #include "plain_text_source.hh"
68 #include "input_dispatcher.hh"
69 #include "filter_sub_source.hh"
70 #include "files_sub_source.hh"
71 #include "filter_status_source.hh"
72 #include "preview_status_source.hh"
73 #include "sql_util.hh"
74 #include "archive_manager.hh"
75 #include "file_collection.hh"
76 #include "view_helpers.hh"
77 
78 /** The command modes that are available while viewing a file. */
79 typedef enum {
80     LNM_PAGING,
81     LNM_FILTER,
82     LNM_FILES,
83     LNM_COMMAND,
84     LNM_SEARCH,
85     LNM_SEARCH_FILTERS,
86     LNM_SEARCH_FILES,
87     LNM_CAPTURE,
88     LNM_SQL,
89     LNM_EXEC,
90     LNM_USER,
91 } ln_mode_t;
92 
93 enum {
94     LNB_SYSLOG,
95     LNB__MAX,
96 
97     LNB_TIMESTAMP,
98     LNB_HELP,
99     LNB_HEADLESS,
100     LNB_QUIET,
101     LNB_CHECK_CONFIG,
102     LNB_INSTALL,
103     LNB_UPDATE_FORMATS,
104     LNB_VERBOSE,
105     LNB_SECURE_MODE,
106     LNB_NO_DEFAULT,
107 };
108 
109 /** Flags set on the lnav command-line. */
110 typedef enum {
111     LNF_SYSLOG    = (1L << LNB_SYSLOG),
112 
113     LNF_TIMESTAMP = (1L << LNB_TIMESTAMP),
114     LNF_HELP      = (1L << LNB_HELP),
115     LNF_HEADLESS  = (1L << LNB_HEADLESS),
116     LNF_QUIET     = (1L << LNB_QUIET),
117     LNF_CHECK_CONFIG = (1L << LNB_CHECK_CONFIG),
118     LNF_INSTALL   = (1L << LNB_INSTALL),
119     LNF_UPDATE_FORMATS = (1L << LNB_UPDATE_FORMATS),
120     LNF_VERBOSE = (1L << LNB_VERBOSE),
121     LNF_SECURE_MODE = (1L << LNB_SECURE_MODE),
122     LNF_NO_DEFAULT = (1L << LNB_NO_DEFAULT),
123 
124     LNF__ALL      = (LNF_SYSLOG|LNF_HELP),
125 } lnav_flags_t;
126 
127 extern const char *lnav_zoom_strings[];
128 
129 /** The status bars. */
130 typedef enum {
131     LNS_TOP,
132     LNS_BOTTOM,
133     LNS_FILTER,
134     LNS_FILTER_HELP,
135     LNS_DOC,
136     LNS_PREVIEW,
137 
138     LNS__MAX
139 } lnav_status_t;
140 
141 typedef std::pair<int, int>                      ppid_time_pair_t;
142 typedef std::pair<ppid_time_pair_t, ghc::filesystem::path> session_pair_t;
143 
144 class input_state_tracker : public log_state_dumper {
145 public:
input_state_tracker()146     input_state_tracker() : ist_index(0) {
147         memset(this->ist_recent_key_presses, 0, sizeof(this->ist_recent_key_presses));
148     };
149 
log_state()150     void log_state() override {
151         log_info("recent_key_presses: index=%d", this->ist_index);
152         for (int lpc = 0; lpc < COUNT; lpc++) {
153             log_msg_extra(" 0x%x (%c)", this->ist_recent_key_presses[lpc],
154                     this->ist_recent_key_presses[lpc]);
155         }
156         log_msg_extra_complete();
157     };
158 
push_back(int ch)159     void push_back(int ch) {
160         this->ist_recent_key_presses[this->ist_index % COUNT] = ch;
161         this->ist_index = (this->ist_index + 1) % COUNT;
162     };
163 
164 private:
165     static const int COUNT = 10;
166 
167     int ist_recent_key_presses[COUNT];
168     size_t ist_index;
169 };
170 
171 struct key_repeat_history {
172     int krh_key{0};
173     int krh_count{0};
174     vis_line_t krh_start_line{0_vl};
175     struct timeval krh_last_press_time{0, 0};
176 
updatekey_repeat_history177     void update(int ch, vis_line_t top) {
178         struct timeval now, diff;
179 
180         gettimeofday(&now, nullptr);
181         timersub(&now, &this->krh_last_press_time, &diff);
182         if (diff.tv_sec >= 1 || diff.tv_usec > (750 * 1000)) {
183             this->krh_key = 0;
184             this->krh_count = 0;
185         }
186         this->krh_last_press_time = now;
187 
188         if (this->krh_key == ch) {
189             this->krh_count += 1;
190         } else {
191             this->krh_key = ch;
192             this->krh_count = 1;
193             this->krh_start_line = top;
194         }
195     };
196 };
197 
198 struct lnav_data_t {
199     std::map<std::string, std::list<session_pair_t>> ld_session_id;
200     time_t                                  ld_session_time;
201     time_t                                  ld_session_load_time;
202     const char *                            ld_program_name;
203     const char *                            ld_debug_log_name;
204 
205     std::list<std::string>                  ld_commands;
206     bool                                    ld_cmd_init_done;
207     bool                                    ld_session_loaded;
208     std::vector<ghc::filesystem::path>      ld_config_paths;
209     file_collection                         ld_active_files;
210     std::list<std::pair<std::string, int> > ld_files_to_front;
211     std::string                             ld_pt_search;
212     time_t                                  ld_pt_min_time;
213     time_t                                  ld_pt_max_time;
214     bool                                    ld_stdout_used;
215     sig_atomic_t                            ld_looping;
216     sig_atomic_t                            ld_winched;
217     sig_atomic_t                            ld_child_terminated;
218     unsigned long                           ld_flags;
219     WINDOW *                                ld_window;
220     ln_mode_t                               ld_mode;
221     ln_mode_t                               ld_last_config_mode{LNM_FILTER};
222 
223     statusview_curses                       ld_status[LNS__MAX];
224     top_status_source                       ld_top_source;
225     bottom_status_source                    ld_bottom_source;
226     filter_status_source                    ld_filter_status_source;
227     filter_help_status_source               ld_filter_help_status_source;
228     doc_status_source                       ld_doc_status_source;
229     preview_status_source                   ld_preview_status_source;
230     bool                                    ld_preview_hidden;
231     int64_t                                 ld_preview_generation{0};
232     action_broadcaster<listview_curses>     ld_scroll_broadcaster;
233     action_broadcaster<listview_curses>     ld_view_stack_broadcaster;
234 
235     plain_text_source                       ld_help_source;
236 
237     plain_text_source                       ld_doc_source;
238     textview_curses                         ld_doc_view;
239     filter_sub_source                       ld_filter_source;
240     textview_curses                         ld_filter_view;
241     files_sub_source                        ld_files_source;
242     files_overlay_source                    ld_files_overlay;
243     textview_curses                         ld_files_view;
244     plain_text_source                       ld_example_source;
245     textview_curses                         ld_example_view;
246     plain_text_source                       ld_match_source;
247     textview_curses                         ld_match_view;
248     plain_text_source                       ld_preview_source;
249     textview_curses                         ld_preview_view;
250 
251     view_stack<textview_curses>             ld_view_stack;
252     textview_curses *ld_last_view;
253     textview_curses                         ld_views[LNV__MAX];
254     std::shared_ptr<grep_proc<vis_line_t>> ld_meta_search;
255     vis_line_t                              ld_search_start_line;
256     readline_curses *                       ld_rl_view;
257 
258     logfile_sub_source                      ld_log_source;
259     hist_source2                            ld_hist_source2;
260     int                                     ld_zoom_level;
261     spectrogram_source ld_spectro_source;
262 
263     textfile_sub_source                     ld_text_source;
264 
265     std::map<textview_curses *, int>        ld_last_user_mark;
266     std::map<textview_curses *, int>        ld_select_start;
267 
268     db_label_source                         ld_db_row_source;
269     db_overlay_source                       ld_db_overlay;
270     std::vector<std::string>                ld_db_key_names;
271 
272     vis_line_t                              ld_last_pretty_print_top;
273 
274     std::unique_ptr<log_vtab_manager>       ld_vtab_manager;
275     auto_mem<sqlite3, sqlite_close_wrapper> ld_db;
276 
277     std::unordered_map<std::string, std::string> ld_table_ddl;
278 
279     std::list<pid_t>                        ld_children;
280     std::list<std::shared_ptr<piper_proc>>  ld_pipers;
281 
282     input_state_tracker ld_input_state;
283     input_dispatcher ld_input_dispatcher;
284 
285     exec_context ld_exec_context;
286 
287     int ld_fifo_counter;
288 
289     struct key_repeat_history ld_key_repeat_history;
290 };
291 
292 struct static_service {};
293 
294 class main_looper : public isc::service<main_looper>, public static_service {
295 public:
296 };
297 
298 extern struct lnav_data_t lnav_data;
299 
300 extern readline_context::command_map_t lnav_commands;
301 extern const int ZOOM_LEVELS[];
302 extern const ssize_t ZOOM_COUNT;
303 
304 #define HELP_MSG_1(x, msg) \
305     "Press '" ANSI_BOLD(#x) "' " msg
306 
307 #define HELP_MSG_2(x, y, msg) \
308     "Press " ANSI_BOLD(#x) "/" ANSI_BOLD(#y) " " msg
309 
310 void rebuild_hist();
311 size_t rebuild_indexes(nonstd::optional<ui_clock::time_point> deadline = nonstd::nullopt);
312 void rebuild_indexes_repeatedly();
313 
314 bool setup_logline_table(exec_context &ec);
315 
316 bool rescan_files(bool required = false);
317 bool update_active_files(const file_collection& new_files);
318 
319 void wait_for_children();
320 
321 textview_curses *get_textview_for_mode(ln_mode_t mode);
322 
323 #endif
324