/* * Compile like... gcc -W -Wall -O2 -o log_tree_mon log_tree_mon.c \ `pkg-config --cflags --libs gtk+-2.0 vstr` * Use like... ./log_tree_mon T:ret T:frm_group T:req /local/file ssh-uh:my_ssh_alias ssh-file:/path/to/log/file ./log_tree_mon T:main_ref T:ref /local/file ssh-uh:my_ssh_alias ssh-file:/path/to/log/file ./log_tree_mon T:main_ref T:ref /local/file ssh-uh:my_ssh_alias ssh-file:/path/to/log/file */ /* * Copyright (C) 2003 James Antill * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * email: james@and.org */ #define _GNU_SOURCE 1 /* for strptime */ #define VSTR_COMPILE_INCLUDE 1 #include #include #include #include #include #define LTM_DEBUG 0 #define LTM_CONF_ADD_ENTERIES_PER_LOOP 250 #define FALSE 0 #define TRUE 1 #define LTM_INDENT_ON_TYPE_DEF LTM_INDENT_ON_TYPE_REQ #define LTM_INDENT_ON_TYPE_USR 1 #define LTM_INDENT_ON_TYPE_MAIN_USR 2 #define LTM_INDENT_ON_TYPE_FRM 3 #define LTM_INDENT_ON_TYPE_REF 4 #define LTM_INDENT_ON_TYPE_MAIN_REF 5 #define LTM_INDENT_ON_TYPE_REQ 6 #define LTM_INDENT_ON_TYPE_MAIN_REQ 7 #define LTM_INDENT_ON_TYPE_RET 8 #define LTM_INDENT_ON_TYPE_FRM_GROUP 9 #define LTM_INDENT_ON_TYPE_ALL 10 #define LTM_INDENT_ON_TYPE_LAST 11 #define LTM_INDENT_ON_TYPE_END 0 #define LTM_INDENT_ON_NUM 12 #define LTM_INDENT_ON_SZ 6 static unsigned int ltm_conf_indent_on_type[LTM_INDENT_ON_SZ] = { LTM_INDENT_ON_TYPE_DEF, LTM_INDENT_ON_TYPE_END, LTM_INDENT_ON_TYPE_END, LTM_INDENT_ON_TYPE_END, LTM_INDENT_ON_TYPE_END, LTM_INDENT_ON_TYPE_END, }; static const char *ltm_conf_indent_name_map[LTM_INDENT_ON_NUM] = { "", "User Agent", "User Agent, ignoring versions", "From IP address", "Referrer URL", "Referrer URL, group on certain hosts", "Request", "Request, group certain requests", "Return Code", "Group clients", "All", }; typedef struct Ltm_vstr_pt { Vstr_base *vs; size_t pos; size_t len; unsigned int h_val; } Ltm_vstr_pt; static struct { const char *name; Ltm_vstr_pt pt; unsigned int sect_num; } ltm_readables[] = { #define LTM_READABLE_VAL_ALL 0 { "All", {NULL,0,0,0},0}, #define LTM_READABLE_VAL_OTHER 1 { "Other", {NULL,0,0,0},0}, #define LTM_READABLE_VAL_AND_ORG 2 { "And.org", {NULL,0,0,0},0}, #define LTM_READABLE_VAL_LAST 3 { "-- LAST --", {NULL,0,0,0},0}, { "groups.google", {NULL,0,0,0},0}, { "google", {NULL,0,0,0},0}, { "search.yahoo.com", {NULL,0,0,0},0}, { "altavista.com", {NULL,0,0,0},0}, { "msn", {NULL,0,0,0},0}, { "mysearch.com", {NULL,0,0,0},0}, { "search.aol.com", {NULL,0,0,0},0}, { "search.netscape.com", {NULL,0,0,0},0}, { "hotbot.com", {NULL,0,0,0},0}, { "search.com", {NULL,0,0,0},0}, { "ask", {NULL,0,0,0},0}, { "alltheweb.com", {NULL,0,0,0},0}, { "and.org/vstr", {NULL,0,0,0},0}, { "and.org/pictures", {NULL,0,0,0},0}, { "and.org", {NULL,0,0,0},0}, { "www.and.org", {NULL,0,0,0},0}, { "http://www.and.org", {NULL,0,0,0},0}, { "http://and.org", {NULL,0,0,0},0}, { "crazylands.org", {NULL,0,0,0},0}, { "freshmeat", {NULL,0,0,0},0}, { "gnu.org/directory", {NULL,0,0,0},0}, { "gnu.org/search", {NULL,0,0,0},0}, { "sourceforge.net", {NULL,0,0,0},0}, { "sf.net", {NULL,0,0,0},0}, { "cuj.com", {NULL,0,0,0},0}, { "slashdot.org", {NULL,0,0,0},0}, { "news", {NULL,0,0,0},0}, { "nntp", {NULL,0,0,0},0}, /* search bots... */ { "Scooter", {NULL,0,0,0},0}, { "Googlebot", {NULL,0,0,0},0}, { "ia_archiver", {NULL,0,0,0},0}, { "FAST-WebCrawler", {NULL,0,0,0},0}, { "webcollage", {NULL,0,0,0},0}, { "WebFilter", {NULL,0,0,0},0}, { "fmII", {NULL,0,0,0},0}, { "Dillo", {NULL,0,0,0},0}, { "sitecheck.internetseer.com", {NULL,0,0,0},0}, { "NPBot", {NULL,0,0,0},0}, { "Slurp", {NULL,0,0,0},0}, { "Wget", {NULL,0,0,0},0}, { "curl", {NULL,0,0,0},0}, { "gURLChecker", {NULL,0,0,0},0}, { "almaden.ibm.com/cs/crawler", {NULL,0,0,0},0}, /* requests */ { "/pictures/People/img_thumb", {NULL,0,0,0},0}, { "/pictures/Animals/img_thumb", {NULL,0,0,0},0}, { "/pictures/House/img_thumb", {NULL,0,0,0},0}, { "/pictures/Snow/img_thumb", {NULL,0,0,0},0}, { "/pictures/Quilts/img_thumb", {NULL,0,0,0},0}, { "/pictures/Ridge%20Hill%20Road/img_thumb", {NULL,0,0,0},0}, { "/pictures/Garlic%20Festival%202003/img_thumb", {NULL,0,0,0},0}, { "/icons", {NULL,0,0,0},0}, { NULL, {NULL,0,0,0},0}, }; #include struct Ltm_file_data { Vstr_base *io_r; size_t pos; size_t len; size_t unparsed_len; Vstr_sects *sects; unsigned int skip_num; unsigned int parsed_num; unsigned int unknown_lines; unsigned int idle_id; Vstr_base *t1; /* gtk stuff... */ GHashTable *h_iter; GtkTreeView *view; GtkTreeStore *store; GtkWidget *label; }; #define F_DATA_DECL(x, y) x y = f_data-> y struct Ltm_hash_data { GtkTreeIter parent_iter; int sz; int req_num; GHashTable *h_next_iter; }; static GHashTable *ltm_readable_strings = NULL; /* If we have a readable string for this point, then give that section number */ #define LTM_SET_PARENT_SECTION_READABLE(x) do { \ unsigned int *ltm__local_num = g_hash_table_lookup(ltm_readable_strings, pt); \ \ if (!ltm__local_num) { \ fprintf(stderr, "Not found readable string: %s\n", \ vstr_export_cstr_ptr(pt->vs, pt->pos, pt->len)); \ break; } \ \ ltm_parent_sect_typ = (x); \ ltm_parent_sect_num = *ltm__local_num; \ } while (FALSE) #define LTM_IS_PARENT_SECTION_READABLE(x) \ (((ltm_parent_sect_typ == (x)) || \ (ltm_parent_sect_typ == LTM_INDENT_ON_TYPE_ALL)) && ltm_parent_sect_num) static int ltm_skip_chr(Vstr_base *io_r, size_t *pos, size_t *len, char chr) { if (vstr_export_chr(io_r, *pos) != chr) return (FALSE); *pos += 1; *len -= 1; return (TRUE); } static int ltm_add_sect_term_chr(Vstr_sects *sects, Vstr_base *io_r, size_t *pos, size_t *len, char chr) { size_t tmp = vstr_srch_chr_fwd(io_r, *pos, *len, chr); if (!tmp) return (FALSE); vstr_sects_add(sects, *pos, tmp - *pos); *len -= vstr_sc_posdiff(*pos, tmp); *pos = tmp + 1; return (TRUE); } static int ltm_add_sect_between_chrs(Vstr_sects *sects, Vstr_base *io_r, size_t *pos, size_t *len, char beg_chr, char end_chr, char skip_chr) { char buf[2]; size_t tmp = 0; if (!ltm_skip_chr(io_r, pos, len, beg_chr)) return (FALSE); buf[0] = end_chr; buf[1] = skip_chr; tmp = vstr_srch_buf_fwd(io_r, *pos, *len, buf, 2); if (!tmp) return (FALSE); vstr_sects_add(sects, *pos, tmp - *pos); *len -= vstr_sc_posdiff(*pos, tmp) + 1; *pos = tmp + 2; return (TRUE); } guint ltm_hash_gen(gconstpointer passed_pt) { Ltm_vstr_pt *pt = (void *)passed_pt; Vstr_iter iter[1]; guint h = 0; // fprintf(stderr, "%p [%p.%zu.%zu] %u\n", pt, pt->vs, pt->pos, pt->len, // pt->h_val); if (!pt->len) return (0); if (pt->h_val) return (pt->h_val); if (!vstr_iter_fwd_beg(pt->vs, pt->pos, pt->len, iter)) g_assert_not_reached(); do { while (iter->len--) /* borrowed from glib, and altered to be case safe */ { guint val = *iter->ptr; if ((val >= 'A') && (val <= 'Z')) /* NOTE: ASSUMES ASCII */ val += ('a' - 'A'); h = (h << 5) - h + val; iter->ptr++; } } while (vstr_iter_fwd_nxt(iter)); pt->h_val = h; return (h); } gboolean ltm_hash_eq(gconstpointer passed_pt1, gconstpointer passed_pt2) { const Ltm_vstr_pt *pt1 = passed_pt1; const Ltm_vstr_pt *pt2 = passed_pt2; return (vstr_cmp_case_eq(pt1->vs, pt1->pos, pt1->len, pt2->vs, pt2->pos, pt2->len)); } #define LTM_GTK_COL_T_USR 0 /* vstr */ #define LTM_GTK_COL_T_DAT 1 /* time_t * */ #define LTM_GTK_COL_T_FRM 2 /* vstr */ #define LTM_GTK_COL_T_SIZ 3 /* uint */ #define LTM_GTK_COL_T_REQ 4 /* vstr */ #define LTM_GTK_COL_T_REF 5 /* vstr */ #define LTM_GTK_COL_T_NUM 6 /* uint */ #define LTM_GTK_COL_T_CNT 7 /* uint */ #define LTM_GTK_COL_T_RET 8 /* uint */ #define LTM_GTK_COL_SZ 9 static void ltm_cell_render_int(GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, guint t_off, Vstr_base *t1) { const char *ptr = NULL; int info = 0; size_t tmp = t1->len; gtk_tree_model_get(model, iter, t_off, &info, -1); vstr_add_fmt(t1, tmp, "%'u", (unsigned int)info); ptr = vstr_export_cstr_ptr(t1, tmp + 1, vstr_sc_posdiff(tmp + 1, t1->len)); g_object_set(GTK_CELL_RENDERER (cell), "text", ptr, NULL); if (t1->len > (1024 * 4)) vstr_del(t1, 1, t1->len / 2); } static void ltm_cell_render_sect(GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, guint t_off, struct Ltm_file_data *f_data) { F_DATA_DECL(Vstr_base *, io_r); F_DATA_DECL(Vstr_sects *, sects); const char *ptr = NULL; int info = 0; gtk_tree_model_get(model, iter, t_off, &info, -1); ptr = vstr_export_cstr_ptr(io_r, VSTR_SECTS_NUM(sects, info)->pos, VSTR_SECTS_NUM(sects, info)->len); g_object_set(GTK_CELL_RENDERER (cell), "text", ptr, NULL); } static void ltm_cell_render_siz(GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, guint t_off, Vstr_base *t1) { const char *ptr = NULL; int info = 0; size_t tmp = t1->len; gtk_tree_model_get(model, iter, t_off, &info, -1); vstr_add_fmt(t1, tmp, "${BKMG.u:%u}", (unsigned int)info); ptr = vstr_export_cstr_ptr(t1, tmp + 1, vstr_sc_posdiff(tmp + 1, t1->len)); g_object_set(GTK_CELL_RENDERER (cell), "text", ptr, NULL); if (t1->len > (1024 * 4)) vstr_del(t1, 1, t1->len / 2); } static void ltm_cell_render_time(GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, guint t_off, Vstr_base *t1) { const char *ptr = NULL; time_t *info = NULL; size_t tmp = t1->len; time_t now = time(NULL); struct tm real_now_tm; struct tm *now_tm = localtime(&now); struct tm *info_tm = NULL; gtk_tree_model_get(model, iter, t_off, &info, -1); real_now_tm = *now_tm; now_tm = &real_now_tm; info_tm = localtime(info); if ((now_tm->tm_year == info_tm->tm_year) && (now_tm->tm_mon == info_tm->tm_mon) && (now_tm->tm_mday == info_tm->tm_mday)) vstr_add_fmt(t1, t1->len, "Today %02u:%02u:%02u", info_tm->tm_hour, info_tm->tm_min, info_tm->tm_sec); else if (difftime(now, *info) < 0) { if (difftime(*info, now) < (60 * 60 * 18)) vstr_add_fmt(t1, t1->len, "Tomorrow %02u:%02u:%02u", info_tm->tm_hour, info_tm->tm_min, info_tm->tm_sec); else vstr_add_fmt(t1, t1->len, "%04u-%02u-%02u %02u:%02u:%02u", info_tm->tm_year + 1900, info_tm->tm_mon + 1, info_tm->tm_mday, info_tm->tm_hour, info_tm->tm_min, info_tm->tm_sec); } else if (difftime(now, *info) < (60 * 60 * 18)) vstr_add_fmt(t1, t1->len, "Yesterday %02u:%02u:%02u", info_tm->tm_hour, info_tm->tm_min, info_tm->tm_sec); else if (difftime(now, *info) < (60 * 60 * 24 * 4)) { char day_buf[1024]; strftime(day_buf, sizeof(day_buf), "%A", info_tm); vstr_add_fmt(t1, t1->len, "%s %02u:%02u:%02u", day_buf, info_tm->tm_hour, info_tm->tm_min, info_tm->tm_sec); } else vstr_add_fmt(t1, t1->len, "%04u-%02u-%02u %02u:%02u:%02u", info_tm->tm_year + 1900, info_tm->tm_mon + 1, info_tm->tm_mday, info_tm->tm_hour, info_tm->tm_min, info_tm->tm_sec); ptr = vstr_export_cstr_ptr(t1, tmp + 1, vstr_sc_posdiff(tmp + 1, t1->len)); g_object_set(GTK_CELL_RENDERER (cell), "text", ptr, NULL); if (t1->len > (1024 * 4)) vstr_del(t1, 1, t1->len / 2); } static void __attribute__((unused)) ltm_cell_num(GtkTreeViewColumn *tree_column __attribute__((unused)), GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data) { ltm_cell_render_int(cell, model, iter, LTM_GTK_COL_T_NUM, data); } static void ltm_cell_cnt(GtkTreeViewColumn *tree_column __attribute__((unused)), GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data) { ltm_cell_render_int(cell, model, iter, LTM_GTK_COL_T_CNT, data); } static void ltm_cell_ret(GtkTreeViewColumn *tree_column __attribute__((unused)), GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data) { ltm_cell_render_int(cell, model, iter, LTM_GTK_COL_T_RET, data); } static void ltm_cell_usr(GtkTreeViewColumn *tree_column __attribute__((unused)), GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data) { ltm_cell_render_sect(cell, model, iter, LTM_GTK_COL_T_USR, data); } static void ltm_cell_dat(GtkTreeViewColumn *tree_column __attribute__((unused)), GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data) { ltm_cell_render_time(cell, model, iter, LTM_GTK_COL_T_DAT, data); } static void ltm_cell_siz(GtkTreeViewColumn *tree_column __attribute__((unused)), GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data) { ltm_cell_render_siz(cell, model, iter, LTM_GTK_COL_T_SIZ, data); } static void ltm_cell_frm(GtkTreeViewColumn *tree_column __attribute__((unused)), GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data) { ltm_cell_render_sect(cell, model, iter, LTM_GTK_COL_T_FRM, data); } static void ltm_cell_req(GtkTreeViewColumn *tree_column __attribute__((unused)), GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data) { ltm_cell_render_sect(cell, model, iter, LTM_GTK_COL_T_REQ, data); } static void ltm_cell_ref(GtkTreeViewColumn *tree_column __attribute__((unused)), GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data) { ltm_cell_render_sect(cell, model, iter, LTM_GTK_COL_T_REF, data); } static gint ltm_cmp_dat(GtkTreeModel *model, GtkTreeIter *iter_a, GtkTreeIter *iter_b, gpointer user_data __attribute__((unused))) { time_t *a = NULL; time_t *b = NULL; gtk_tree_model_get(model, iter_a, LTM_GTK_COL_T_DAT, &a, -1); gtk_tree_model_get(model, iter_b, LTM_GTK_COL_T_DAT, &b, -1); if (!a && !b) return (0); if (!b) return (1); if (!a) return (-1); return (difftime(*a, *b)); } static void ltm_trans_ptr_str(const GValue *src_value __attribute__((unused)), GValue *dest_value) { g_value_set_static_string(dest_value, ""); } static void ltm_hash_data_free(void *ptr) { struct Ltm_hash_data *h_vals = ptr; if (h_vals->h_next_iter) /* stupid, stupid, stupid... */ g_hash_table_destroy(h_vals->h_next_iter); g_free(h_vals); } static void ltm_gtk_list(Vstr_base *io_r, struct Ltm_file_data *f_data) { GtkTreeStore *store; GtkWidget *treeview; int dum_argc = 1; char *dum_argv1[] = { "abcd", NULL }; char **dum_argv = &dum_argv1[0]; Vstr_base *t1 = NULL; f_data->t1 = t1 = vstr_make_base(io_r->conf); ltm_readable_strings = g_hash_table_new_full(ltm_hash_gen, ltm_hash_eq, (GDestroyNotify)vstr_ref_cb_free_nothing, (GDestroyNotify)vstr_ref_cb_free_nothing); { unsigned int scan = 0; while (ltm_readables[scan].name) { Ltm_vstr_pt *pt = <m_readables[scan].pt; unsigned int *sect_num = <m_readables[scan].sect_num; size_t len = strlen(ltm_readables[scan].name); size_t pos = io_r->len + 1; vstr_add_ptr(io_r, pos - 1, ltm_readables[scan].name, len); vstr_sects_add(f_data->sects, pos, len); *sect_num = f_data->sects->num; pt->vs = io_r; pt->pos = pos; pt->len = len; g_hash_table_insert(ltm_readable_strings, pt, sect_num); ++scan; } f_data->skip_num += scan; f_data->parsed_num += scan; f_data->pos = io_r->len + 1; f_data->len = 0; } gtk_init(&dum_argc, &dum_argv); /* g_warns without this... *sigh* */ g_value_register_transform_func(G_TYPE_POINTER, G_TYPE_STRING, ltm_trans_ptr_str); f_data->h_iter = g_hash_table_new_full(ltm_hash_gen, ltm_hash_eq, g_free, ltm_hash_data_free); store = gtk_tree_store_new(LTM_GTK_COL_SZ, G_TYPE_UINT, /* vstr */ G_TYPE_POINTER, G_TYPE_UINT, /* vstr */ G_TYPE_UINT, G_TYPE_UINT, /* vstr */ G_TYPE_UINT, /* vstr */ G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT); gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store), LTM_GTK_COL_T_DAT, ltm_cmp_dat, NULL, NULL); f_data->store = store; treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); f_data->view = GTK_TREE_VIEW(treeview); gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE); gtk_tree_view_set_reorderable(GTK_TREE_VIEW(treeview), TRUE); gtk_tree_view_set_search_column(GTK_TREE_VIEW(treeview), LTM_GTK_COL_T_REQ); g_object_unref(G_OBJECT(store)); { /* create columns in view */ GtkCellRenderer *renderer; GtkTreeViewColumn *column = NULL; renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes("Count", renderer, "text", LTM_GTK_COL_T_CNT, NULL); gtk_tree_view_column_set_cell_data_func(column, renderer, ltm_cell_cnt, t1, NULL); gtk_tree_view_column_set_sort_column_id(column, LTM_GTK_COL_T_CNT); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes("Return Code", renderer, "text", LTM_GTK_COL_T_RET, NULL); gtk_tree_view_column_set_cell_data_func(column, renderer, ltm_cell_ret, t1, NULL); gtk_tree_view_column_set_sort_column_id(column, LTM_GTK_COL_T_RET); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes("User-agent", renderer, "text", LTM_GTK_COL_T_USR, NULL); gtk_tree_view_column_set_cell_data_func(column, renderer, ltm_cell_usr, f_data, NULL); gtk_tree_view_column_set_resizable(column, TRUE); gtk_tree_view_column_set_sort_column_id(column, LTM_GTK_COL_T_USR); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes("Date", renderer, "text", LTM_GTK_COL_T_DAT, NULL); gtk_tree_view_column_set_cell_data_func(column, renderer, ltm_cell_dat, t1, NULL); gtk_tree_view_column_set_sort_column_id(column, LTM_GTK_COL_T_DAT); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes("From IP", renderer, "text", LTM_GTK_COL_T_FRM, NULL); gtk_tree_view_column_set_cell_data_func(column, renderer, ltm_cell_frm, f_data, NULL); gtk_tree_view_column_set_sort_column_id(column, LTM_GTK_COL_T_FRM); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes("Size", renderer, "text", LTM_GTK_COL_T_SIZ, NULL); gtk_tree_view_column_set_cell_data_func(column, renderer, ltm_cell_siz, t1, NULL); gtk_tree_view_column_set_sort_column_id(column, LTM_GTK_COL_T_SIZ); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes("Request", renderer, "text", LTM_GTK_COL_T_REQ, NULL); gtk_tree_view_column_set_cell_data_func(column, renderer, ltm_cell_req, f_data, NULL); gtk_tree_view_column_set_resizable(column, TRUE); gtk_tree_view_column_set_sort_column_id(column, LTM_GTK_COL_T_REQ); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes("Referrer", renderer, "text", LTM_GTK_COL_T_REF, NULL); gtk_tree_view_column_set_cell_data_func(column, renderer, ltm_cell_ref, f_data, NULL); gtk_tree_view_column_set_sort_column_id(column, LTM_GTK_COL_T_REF); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); } { GtkWidget *window; GtkWidget *vbox; GtkWidget *sw; window = gtk_window_new(GTK_WINDOW_TOPLEVEL); { size_t tmp = t1->len; const char *ptr = NULL; int scan = 0; vstr_add_fmt(t1, t1->len, "Log tree monitor: %s", ltm_conf_indent_name_map[ltm_conf_indent_on_type[0]]); ++scan; while (ltm_conf_indent_on_type[scan] && (scan < LTM_INDENT_ON_SZ)) { vstr_add_fmt(t1, t1->len, ", %s", ltm_conf_indent_name_map[ltm_conf_indent_on_type[scan]]); ++scan; } ptr = vstr_export_cstr_ptr(t1, tmp + 1, vstr_sc_posdiff(tmp + 1, t1->len)); gtk_window_set_title(GTK_WINDOW(window), ptr); } g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL); vbox = gtk_vbox_new(FALSE, 8); gtk_container_add(GTK_CONTAINER(window), vbox); f_data->label = gtk_label_new(""); gtk_box_pack_start(GTK_BOX(vbox), f_data->label, FALSE, FALSE, 0); sw = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_ETCHED_IN); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0); gtk_container_add(GTK_CONTAINER(sw), treeview); gtk_window_set_default_size(GTK_WINDOW(window), 280, 250); gtk_widget_show_all(window); } vstr_del(t1, 1, t1->len); gtk_main(); g_hash_table_destroy(f_data->h_iter); vstr_del(io_r, 1, io_r->len); vstr_free_base(t1); } #define BEG_MATCH(x) \ (vstr_cmp_bod_cstr_eq(io_r, VSTR_SECTS_NUM(sects, sects->num)->pos, \ VSTR_SECTS_NUM(sects, sects->num)->len, (x)) && \ (VSTR_SECTS_NUM(sects, sects->num)->len >= strlen(x))) #define BEG_SKIP(x) do { \ VSTR_SECTS_NUM(sects, sects->num)->pos += strlen(x); \ VSTR_SECTS_NUM(sects, sects->num)->len -= strlen(x); \ } while (FALSE) #define END_MATCH(x) \ (vstr_cmp_eod_cstr_eq(io_r, VSTR_SECTS_NUM(sects, sects->num)->pos, \ VSTR_SECTS_NUM(sects, sects->num)->len, (x)) && \ (VSTR_SECTS_NUM(sects, sects->num)->len >= strlen(x))) #define END_SKIP(x) do { \ VSTR_SECTS_NUM(sects, sects->num)->len -= strlen(x); \ } while (FALSE) #define TST_SET_REF(x, y, z) \ else if ((tmp = vstr_srch_case_cstr_buf_fwd(io_r, pt->pos, pt->len, (x)))) \ do { \ pt->pos = tmp + (y); \ if ((z) > 0) pt->len = (z); \ else if ((z) < 0) pt->len = (strlen(x) - (y)) + (z); \ else pt->len = strlen(x) - (y); \ LTM_SET_PARENT_SECTION_READABLE(LTM_INDENT_ON_TYPE_REF); \ } while (FALSE) #define TST_BEG_SET_REF(x, y, z) \ else if ((tmp = vstr_srch_case_cstr_buf_fwd(io_r, pt->pos, pt->len, (x))) && \ (tmp == pt->pos)) \ do { \ pt->pos = tmp + (y); \ if ((z) > 0) pt->len = (z); \ else if ((z) < 0) pt->len = (strlen(x) - (y)) + (z); \ else pt->len = strlen(x) - (y); \ LTM_SET_PARENT_SECTION_READABLE(LTM_INDENT_ON_TYPE_REF); \ } while (FALSE) #define TST_SET_REQ(x, y, z) \ else if ((tmp = vstr_srch_case_cstr_buf_fwd(io_r, pt->pos, pt->len, (x)))) \ do { \ pt->pos = tmp + (y); \ if ((z) > 0) pt->len = (z); \ else if ((z) < 0) pt->len = (strlen(x) - (y)) + (z); \ else pt->len = strlen(x) - (y); \ LTM_SET_PARENT_SECTION_READABLE(LTM_INDENT_ON_TYPE_REQ); \ } while (FALSE) #define LTM_DISPLAY_ITER_DATA() \ (!h_iter && (ltm_conf_indent_on_type[scan] != LTM_INDENT_ON_TYPE_LAST)) static gboolean ltm_idle_tree_insert_cb(gpointer userdata) { struct Ltm_file_data *f_data = userdata; F_DATA_DECL(Vstr_base *, io_r); F_DATA_DECL(size_t, pos); F_DATA_DECL(size_t, len); F_DATA_DECL(Vstr_sects *, sects); F_DATA_DECL(unsigned int, parsed_num); F_DATA_DECL(Vstr_base *, t1); F_DATA_DECL(GtkTreeStore *, store); unsigned int count = 0; Ltm_vstr_pt *pt = NULL; unsigned int added_entries = 0; if (len != f_data->unparsed_len) { f_data->len = f_data->unparsed_len; return (TRUE); } /* SECT: parse combined log info. into sections */ while (len) { size_t loop_pos = pos; size_t loop_len = len; size_t del_num = 0; if (!ltm_add_sect_term_chr(sects, io_r, &pos, &len, ' ')) goto next_0; if (!ltm_add_sect_term_chr(sects, io_r, &pos, &len, ' ')) goto next_1; if (!ltm_add_sect_term_chr(sects, io_r, &pos, &len, ' ')) goto next_2; if (!ltm_add_sect_between_chrs(sects, io_r, &pos, &len, '[', ']', ' ')) goto next_3; if (!ltm_add_sect_between_chrs(sects, io_r, &pos, &len, '"', '"', ' ')) goto next_4; if (BEG_MATCH("GET ")) BEG_SKIP("GET "); else if (BEG_MATCH("HEAD ")) BEG_SKIP("HEAD "); if (END_MATCH(" HTTP/1.0")) END_SKIP(" HTTP/1.0"); else if (END_MATCH(" HTTP/1.1")) END_SKIP(" HTTP/1.1"); if (!ltm_add_sect_term_chr(sects, io_r, &pos, &len, ' ')) goto next_5; if (!ltm_add_sect_term_chr(sects, io_r, &pos, &len, ' ')) goto next_6; if (!ltm_add_sect_between_chrs(sects, io_r, &pos, &len, '"', '"', ' ')) goto next_7; if (!ltm_add_sect_between_chrs(sects, io_r, &pos, &len, '"', '"', '\n')) goto next_8; continue; next_8: ++del_num; next_7: ++del_num; next_6: ++del_num; next_5: ++del_num; next_4: ++del_num; next_3: ++del_num; next_2: ++del_num; next_1: ++del_num; next_0: { size_t tmp = vstr_srch_chr_fwd(io_r, pos, len, '\n'); while (del_num--) vstr_sects_del(sects, sects->num); if (!tmp) { pos = loop_pos; len = loop_len; break; } ++f_data->unknown_lines; len -= vstr_sc_posdiff(pos, tmp); pos = tmp + 1; } } /* SECT: update gtk */ g_object_freeze_notify(G_OBJECT(store)); pt = g_new(Ltm_vstr_pt, 1); count = parsed_num; while ((count + 8) <= sects->num) { /* create content */ const char *ptr = NULL; size_t tmp = 0; GtkTreeIter *parent_iter = NULL; size_t comment_pos = 0; int *sz = NULL; int *req_num = NULL; int tot_req_num = (count + 8) / 9; GtkTreeIter iter; F_DATA_DECL(GHashTable *, h_iter); struct Ltm_hash_data *h_vals = NULL; unsigned int scan = 0; pt->vs = io_r; while (ltm_conf_indent_on_type[scan] && (scan < LTM_INDENT_ON_SZ)) { unsigned int ltm_parent_sect_num = 0; unsigned int ltm_parent_sect_typ = 0; switch (ltm_conf_indent_on_type[scan]) { case LTM_INDENT_ON_TYPE_USR: pt->pos = VSTR_SECTS_NUM(sects, count + 8)->pos; pt->len = VSTR_SECTS_NUM(sects, count + 8)->len; break; case LTM_INDENT_ON_TYPE_MAIN_USR: pt->pos = VSTR_SECTS_NUM(sects, count + 8)->pos; pt->len = VSTR_SECTS_NUM(sects, count + 8)->len; if ((comment_pos = vstr_srch_cstr_buf_fwd(io_r, pt->pos, pt->len, " ("))) pt->len = vstr_sc_posdiff(pt->pos, comment_pos) - 1; break; case LTM_INDENT_ON_TYPE_FRM: pt->pos = VSTR_SECTS_NUM(sects, count)->pos; pt->len = VSTR_SECTS_NUM(sects, count)->len; break; case LTM_INDENT_ON_TYPE_REF: pt->pos = VSTR_SECTS_NUM(sects, count + 7)->pos; pt->len = VSTR_SECTS_NUM(sects, count + 7)->len; break; case LTM_INDENT_ON_TYPE_MAIN_REF: { pt->pos = VSTR_SECTS_NUM(sects, count + 7)->pos; pt->len = VSTR_SECTS_NUM(sects, count + 7)->len; pt->h_val = 0; if (0) { } TST_SET_REF("groups.google.at/", 0, strlen("groups.google")); TST_SET_REF("groups.google.be/", 0, strlen("groups.google")); TST_SET_REF("groups.google.ca/", 0, strlen("groups.google")); TST_SET_REF("groups.google.ch/", 0, strlen("groups.google")); TST_SET_REF("groups.google.com/", 0, strlen("groups.google")); TST_SET_REF("groups.google.com.ar/", 0, strlen("groups.google")); TST_SET_REF("groups.google.com.au/", 0, strlen("groups.google")); TST_SET_REF("groups.google.com.br/", 0, strlen("groups.google")); TST_SET_REF("groups.google.com.gr/", 0, strlen("groups.google")); TST_SET_REF("groups.google.com.hk/", 0, strlen("groups.google")); TST_SET_REF("groups.google.com.mx/", 0, strlen("groups.google")); TST_SET_REF("groups.google.com.my/", 0, strlen("groups.google")); TST_SET_REF("groups.google.com.ru/", 0, strlen("groups.google")); TST_SET_REF("groups.google.com.sg/", 0, strlen("groups.google")); TST_SET_REF("groups.google.com.tw/", 0, strlen("groups.google")); TST_SET_REF("groups.google.com.vn/", 0, strlen("groups.google")); TST_SET_REF("groups.google.co.uk/", 0, strlen("groups.google")); TST_SET_REF("groups.google.co.fi/", 0, strlen("groups.google")); TST_SET_REF("groups.google.co.fr/", 0, strlen("groups.google")); TST_SET_REF("groups.google.co.il/", 0, strlen("groups.google")); TST_SET_REF("groups.google.co.in/", 0, strlen("groups.google")); TST_SET_REF("groups.google.co.kr/", 0, strlen("groups.google")); TST_SET_REF("groups.google.co.jp/", 0, strlen("groups.google")); TST_SET_REF("groups.google.de/", 0, strlen("groups.google")); TST_SET_REF("groups.google.fi/", 0, strlen("groups.google")); TST_SET_REF("groups.google.fr/", 0, strlen("groups.google")); TST_SET_REF("groups.google.it/", 0, strlen("groups.google")); TST_SET_REF("groups.google.lt/", 0, strlen("groups.google")); TST_SET_REF("groups.google.nl/", 0, strlen("groups.google")); TST_SET_REF("groups.google.pl/", 0, strlen("groups.google")); TST_SET_REF("groups.google.pt/", 0, strlen("groups.google")); TST_SET_REF("groups.google.ti/", 0, strlen("groups.google")); TST_SET_REF("google.at/", 0, strlen("google")); TST_SET_REF("google.be/", 0, strlen("google")); TST_SET_REF("google.ca/", 0, strlen("google")); TST_SET_REF("google.ch/", 0, strlen("google")); TST_SET_REF("google.com/", 0, strlen("google")); TST_SET_REF("google.com.ar/", 0, strlen("google")); TST_SET_REF("google.com.au/", 0, strlen("google")); TST_SET_REF("google.com.br/", 0, strlen("google")); TST_SET_REF("google.com.gr/", 0, strlen("google")); TST_SET_REF("google.com.hk/", 0, strlen("google")); TST_SET_REF("google.com.mx/", 0, strlen("google")); TST_SET_REF("google.com.my/", 0, strlen("google")); TST_SET_REF("google.com.ru/", 0, strlen("google")); TST_SET_REF("google.com.sg/", 0, strlen("google")); TST_SET_REF("google.com.tw/", 0, strlen("google")); TST_SET_REF("google.com.vn/", 0, strlen("google")); TST_SET_REF("google.co.uk/", 0, strlen("google")); TST_SET_REF("google.co.fi/", 0, strlen("google")); TST_SET_REF("google.co.fr/", 0, strlen("google")); TST_SET_REF("google.co.il/", 0, strlen("google")); TST_SET_REF("google.co.in/", 0, strlen("google")); TST_SET_REF("google.co.kr/", 0, strlen("google")); TST_SET_REF("google.co.jp/", 0, strlen("google")); TST_SET_REF("google.de/", 0, strlen("google")); TST_SET_REF("google.fi/", 0, strlen("google")); TST_SET_REF("google.fr/", 0, strlen("google")); TST_SET_REF("google.it/", 0, strlen("google")); TST_SET_REF("google.lt/", 0, strlen("google")); TST_SET_REF("google.nl/", 0, strlen("google")); TST_SET_REF("google.pl/", 0, strlen("google")); TST_SET_REF("google.pt/", 0, strlen("google")); TST_SET_REF("google.ti/", 0, strlen("google")); TST_SET_REF("search.yahoo.com/", 0, -1); TST_SET_REF("altavista.com/", 0, -1); TST_SET_REF("msn.com/", 0, strlen("msn")); TST_SET_REF("msn.nl/", 0, strlen("msn")); TST_SET_REF("mysearch.com/", 0, -1); TST_SET_REF("search.aol.com/", 0, -1); TST_SET_REF("search.netscape.com/", 0, -1); TST_SET_REF("hotbot.com/", 0, -1); TST_SET_REF("search.com/", 0, -1); TST_SET_REF("ask.com/", 0, strlen("ask")); TST_SET_REF("ask.co.uk/", 0, strlen("ask")); TST_SET_REF("alltheweb.com/", 0, -1); TST_SET_REF("and.org/vstr", 0, 0); TST_SET_REF("and.org/pictures", 0, 0); TST_BEG_SET_REF("and.org", 0, 0); TST_BEG_SET_REF("www.and.org", 0, 0); TST_SET_REF("http://www.and.org", 0, 0); TST_SET_REF("http://and.org", 0, 0); TST_SET_REF("crazylands.org/", 0, -1); TST_SET_REF("http://www.freshmeat.net", strlen("http://www."), strlen("freshmeat")); TST_SET_REF("http://freshmeat.net", strlen("http://"), strlen("freshmeat")); TST_SET_REF("gnu.org/directory", 0, 0); TST_SET_REF("gnu.org/search", 0, 0); TST_SET_REF("sourceforge.net/", 0, -1); TST_SET_REF("sf.net/", 0, -1); TST_SET_REF("cuj.com/", 0, -1); TST_SET_REF("slashdot.org/", 0, -1); TST_BEG_SET_REF("news://", 0, strlen("news")); TST_BEG_SET_REF("nntp://", 0, strlen("nntp")); } break; case LTM_INDENT_ON_TYPE_FRM_GROUP: pt->pos = VSTR_SECTS_NUM(sects, count + 8)->pos; pt->len = VSTR_SECTS_NUM(sects, count + 8)->len; if ((comment_pos = vstr_srch_chr_fwd(io_r, pt->pos, pt->len, '/'))) pt->len = vstr_sc_posdiff(pt->pos, comment_pos) - 1; if ((comment_pos = vstr_srch_chr_fwd(io_r, pt->pos, pt->len, ' '))) pt->len = vstr_sc_posdiff(pt->pos, comment_pos) - 1; pt->h_val = 0; if (0) { } else if (vstr_cmp_cstr_eq(io_r, pt->pos, pt->len, "Scooter")) { LTM_SET_PARENT_SECTION_READABLE(LTM_INDENT_ON_TYPE_USR); break; } else if (vstr_cmp_cstr_eq(io_r, pt->pos, pt->len, "Googlebot")) { LTM_SET_PARENT_SECTION_READABLE(LTM_INDENT_ON_TYPE_USR); break; } else if (vstr_cmp_cstr_eq(io_r, pt->pos, pt->len, "ia_archiver")) { LTM_SET_PARENT_SECTION_READABLE(LTM_INDENT_ON_TYPE_USR); break; } else if (vstr_cmp_cstr_eq(io_r, pt->pos, pt->len, "FAST-WebCrawler")) { LTM_SET_PARENT_SECTION_READABLE(LTM_INDENT_ON_TYPE_USR); break; } else if (vstr_cmp_cstr_eq(io_r, pt->pos, pt->len, "webcollage")) { LTM_SET_PARENT_SECTION_READABLE(LTM_INDENT_ON_TYPE_USR); break; } else if (vstr_cmp_cstr_eq(io_r, pt->pos, pt->len, "WebFilter")) { LTM_SET_PARENT_SECTION_READABLE(LTM_INDENT_ON_TYPE_USR); break; } else if (vstr_cmp_cstr_eq(io_r, pt->pos, pt->len, "fmII")) { LTM_SET_PARENT_SECTION_READABLE(LTM_INDENT_ON_TYPE_USR); break; } else if (vstr_cmp_cstr_eq(io_r, pt->pos, pt->len, "Dillo")) { LTM_SET_PARENT_SECTION_READABLE(LTM_INDENT_ON_TYPE_USR); break; } else if (vstr_cmp_cstr_eq(io_r, pt->pos, pt->len, "sitecheck.internetseer.com")) { LTM_SET_PARENT_SECTION_READABLE(LTM_INDENT_ON_TYPE_USR); break; } else if (vstr_cmp_cstr_eq(io_r, pt->pos, pt->len, "NPBot")) { LTM_SET_PARENT_SECTION_READABLE(LTM_INDENT_ON_TYPE_USR); break; } else { pt->pos = VSTR_SECTS_NUM(sects, count + 8)->pos; pt->len = VSTR_SECTS_NUM(sects, count + 8)->len; if (0) { } else if ((tmp = vstr_srch_cstr_buf_fwd(io_r, pt->pos, pt->len, "Slurp/"))) { pt->pos = tmp; pt->len = strlen("Slurp"); pt->h_val = 0; LTM_SET_PARENT_SECTION_READABLE(LTM_INDENT_ON_TYPE_USR); break; } else if ((tmp = vstr_srch_case_cstr_buf_fwd(io_r, pt->pos, pt->len, "Wget/"))) { pt->pos = tmp; pt->len = strlen("Wget"); pt->h_val = 0; LTM_SET_PARENT_SECTION_READABLE(LTM_INDENT_ON_TYPE_USR); break; } else if ((tmp = vstr_srch_case_cstr_buf_fwd(io_r, pt->pos, pt->len, "curl/"))) { pt->pos = tmp; pt->len = strlen("curl"); pt->h_val = 0; LTM_SET_PARENT_SECTION_READABLE(LTM_INDENT_ON_TYPE_USR); break; } else if ((tmp = vstr_srch_case_cstr_buf_fwd(io_r, pt->pos, pt->len, "gURLChecker/"))) { pt->pos = tmp; pt->len = strlen("gURLChecker"); pt->h_val = 0; LTM_SET_PARENT_SECTION_READABLE(LTM_INDENT_ON_TYPE_USR); break; } else if ((tmp = vstr_srch_cstr_buf_fwd(io_r, pt->pos, pt->len, "http://www.almaden.ibm.com/cs/crawler"))) { pt->pos = tmp + strlen("http://www."); pt->len = strlen("almaden.ibm.com/cs/crawler"); pt->h_val = 0; LTM_SET_PARENT_SECTION_READABLE(LTM_INDENT_ON_TYPE_USR); break; } else { pt->pos = VSTR_SECTS_NUM(sects, count)->pos; pt->len = VSTR_SECTS_NUM(sects, count)->len; if (0) { } else if ((tmp = vstr_srch_cstr_buf_fwd(io_r, pt->pos, pt->len, "63.113.167.33"))) { pt->pos = ltm_readables[LTM_READABLE_VAL_AND_ORG].pt.pos; pt->len = ltm_readables[LTM_READABLE_VAL_AND_ORG].pt.len; pt->h_val = 0; LTM_SET_PARENT_SECTION_READABLE(LTM_INDENT_ON_TYPE_FRM); break; } } } pt->pos = ltm_readables[LTM_READABLE_VAL_OTHER].pt.pos; pt->len = ltm_readables[LTM_READABLE_VAL_OTHER].pt.len; pt->h_val = 0; LTM_SET_PARENT_SECTION_READABLE(LTM_INDENT_ON_TYPE_USR); break; case LTM_INDENT_ON_TYPE_REQ: pt->pos = VSTR_SECTS_NUM(sects, count + 4)->pos; pt->len = VSTR_SECTS_NUM(sects, count + 4)->len; break; case LTM_INDENT_ON_TYPE_MAIN_REQ: pt->pos = VSTR_SECTS_NUM(sects, count + 4)->pos; pt->len = VSTR_SECTS_NUM(sects, count + 4)->len; pt->h_val = 0; if (0) { } TST_SET_REQ("/pictures/People/img_thumb/", 0, -1); TST_SET_REQ("/pictures/Animals/img_thumb/", 0, -1); TST_SET_REQ("/pictures/House/img_thumb/", 0, -1); TST_SET_REQ("/pictures/Snow/img_thumb/", 0, -1); TST_SET_REQ("/pictures/Quilts/img_thumb/", 0, -1); TST_SET_REQ("/pictures/Ridge%20Hill%20Road/img_thumb/", 0, -1); TST_SET_REQ("/pictures/Garlic%20Festival%202003/img_thumb/", 0, -1); TST_SET_REQ("/icons/", 0, -1); break; case LTM_INDENT_ON_TYPE_RET: pt->pos = VSTR_SECTS_NUM(sects, count + 5)->pos; pt->len = VSTR_SECTS_NUM(sects, count + 5)->len; break; case LTM_INDENT_ON_TYPE_ALL: pt->pos = ltm_readables[LTM_READABLE_VAL_ALL].pt.pos; pt->len = ltm_readables[LTM_READABLE_VAL_ALL].pt.len; pt->h_val = 0; LTM_SET_PARENT_SECTION_READABLE(LTM_INDENT_ON_TYPE_ALL); break; case LTM_INDENT_ON_TYPE_LAST: pt->pos = ltm_readables[LTM_READABLE_VAL_LAST].pt.pos; pt->len = ltm_readables[LTM_READABLE_VAL_LAST].pt.len; break; default: g_assert_not_reached(); } pt->h_val = 0; if ((h_vals = g_hash_table_lookup(h_iter, pt))) { parent_iter = &h_vals->parent_iter; sz = &h_vals->sz; req_num = &h_vals->req_num; h_iter = h_vals->h_next_iter; ++*req_num; } else { int nxt_scan = scan + 1; if (ltm_conf_indent_on_type[scan] == LTM_INDENT_ON_TYPE_LAST) iter = *parent_iter; else gtk_tree_store_append (store, &iter, parent_iter); h_vals = g_new(struct Ltm_hash_data, 1); h_vals->parent_iter = iter; h_vals->sz = 0; h_vals->req_num = 1; g_hash_table_insert(h_iter, pt, h_vals); h_iter = NULL; if ((nxt_scan < LTM_INDENT_ON_SZ) && ltm_conf_indent_on_type[nxt_scan]) h_iter = g_hash_table_new_full(ltm_hash_gen, ltm_hash_eq, g_free, ltm_hash_data_free); h_vals->h_next_iter = h_iter; parent_iter = &h_vals->parent_iter; sz = &h_vals->sz; req_num = &h_vals->req_num; { Ltm_vstr_pt *tmp_pt = g_new(Ltm_vstr_pt, 1); memcpy(tmp_pt, pt, sizeof(Ltm_vstr_pt)); pt = tmp_pt; } } if (!h_iter && (ltm_conf_indent_on_type[scan] != LTM_INDENT_ON_TYPE_LAST)) { gtk_tree_store_append (store, &iter, parent_iter); gtk_tree_store_set(store, &iter, LTM_GTK_COL_T_NUM, tot_req_num, -1); gtk_tree_store_set(store, &iter, LTM_GTK_COL_T_CNT, *req_num, -1); gtk_tree_store_set(store, &iter, LTM_GTK_COL_T_FRM, count, -1); } gtk_tree_store_set(store, parent_iter, LTM_GTK_COL_T_NUM, tot_req_num, -1); gtk_tree_store_set(store, parent_iter, LTM_GTK_COL_T_CNT, *req_num, -1); if (!LTM_IS_PARENT_SECTION_READABLE(LTM_INDENT_ON_TYPE_FRM)) gtk_tree_store_set(store, parent_iter, LTM_GTK_COL_T_FRM, count, -1); else gtk_tree_store_set(store, parent_iter, LTM_GTK_COL_T_FRM, ltm_parent_sect_num, -1); { /* FIXME: timezone ignored */ time_t now = time(NULL); struct tm *tm = localtime(&now); time_t *val = g_new(time_t, 1); ptr = vstr_export_cstr_ptr(io_r, VSTR_SECTS_NUM(sects, count + 3)->pos, VSTR_SECTS_NUM(sects, count + 3)->len); strptime(ptr, "%d/%b/%Y:%H:%M:%S", tm); *val = mktime(tm); if (LTM_DISPLAY_ITER_DATA()) gtk_tree_store_set(store, &iter, LTM_GTK_COL_T_DAT, val, -1); gtk_tree_store_set(store, parent_iter, LTM_GTK_COL_T_DAT, val, -1); } if (LTM_DISPLAY_ITER_DATA()) gtk_tree_store_set(store, &iter, LTM_GTK_COL_T_REQ, count + 4, -1); if (!LTM_IS_PARENT_SECTION_READABLE(LTM_INDENT_ON_TYPE_REQ)) gtk_tree_store_set(store, parent_iter, LTM_GTK_COL_T_REQ, count + 4, -1); else gtk_tree_store_set(store, parent_iter, LTM_GTK_COL_T_REQ, ltm_parent_sect_num, -1); { unsigned int ret_code = 0; ret_code = vstr_parse_uint(io_r, VSTR_SECTS_NUM(sects, count + 5)->pos, VSTR_SECTS_NUM(sects, count + 5)->len, VSTR_FLAG_PARSE_NUM_DEF | 10, NULL, NULL); if (LTM_DISPLAY_ITER_DATA()) gtk_tree_store_set(store, &iter, LTM_GTK_COL_T_RET, ret_code, -1); gtk_tree_store_set(store, parent_iter, LTM_GTK_COL_T_RET, ret_code, -1); } ptr = vstr_export_cstr_ptr(io_r, VSTR_SECTS_NUM(sects, count + 6)->pos, VSTR_SECTS_NUM(sects, count + 6)->len); *sz += atoi(ptr); if (LTM_DISPLAY_ITER_DATA()) gtk_tree_store_set(store, &iter, LTM_GTK_COL_T_SIZ, atoi(ptr), -1); gtk_tree_store_set(store, parent_iter, LTM_GTK_COL_T_SIZ, *sz, -1); if (LTM_DISPLAY_ITER_DATA()) gtk_tree_store_set(store, &iter, LTM_GTK_COL_T_REF, count + 7, -1); if (!LTM_IS_PARENT_SECTION_READABLE(LTM_INDENT_ON_TYPE_REF)) gtk_tree_store_set(store, parent_iter, LTM_GTK_COL_T_REF, count + 7, -1); else gtk_tree_store_set(store, parent_iter, LTM_GTK_COL_T_REF, ltm_parent_sect_num, -1); if (LTM_DISPLAY_ITER_DATA()) gtk_tree_store_set(store, &iter, LTM_GTK_COL_T_USR, count + 8, -1); if (!LTM_IS_PARENT_SECTION_READABLE(LTM_INDENT_ON_TYPE_USR)) gtk_tree_store_set(store, parent_iter, LTM_GTK_COL_T_USR, count + 8, -1); else gtk_tree_store_set(store, parent_iter, LTM_GTK_COL_T_USR, ltm_parent_sect_num, -1); ++scan; } g_assert(!h_iter); count += 9; if (++added_entries >= LTM_CONF_ADD_ENTERIES_PER_LOOP) break; } g_object_thaw_notify(G_OBJECT(store)); g_free(pt); /* update the label... */ { const char *ptr = NULL; size_t tmp = t1->len; unsigned int cnum = (count - f_data->skip_num) / 9; unsigned int tnum = (sects->num - f_data->skip_num) / 9; vstr_add_fmt(t1, t1->len, "%'u entries", cnum); if (f_data->unknown_lines) vstr_add_fmt(t1, t1->len, ", %'u unknown entries", f_data->unknown_lines); if (cnum < tnum) vstr_add_fmt(t1, t1->len, ", %'u total entries", sects->num / 9); if (len) vstr_add_fmt(t1, t1->len, ", ${BKMG.u:%u} of data left", len); ++tmp; ptr = vstr_export_cstr_ptr(t1, tmp, vstr_sc_posdiff(tmp, t1->len)); gtk_label_set_markup(GTK_LABEL(f_data->label), ptr); if (t1->len > (1024 * 4)) vstr_del(t1, 1, t1->len / 2); } /* SECT: update file data for next time around ... */ f_data->pos = pos; f_data->unparsed_len = len; f_data->len = len; f_data->parsed_num = count; if (!added_entries) f_data->idle_id = 0; return (!!added_entries); } static gboolean ltm_gio_cb(GIOChannel *source, GIOCondition condition, gpointer userdata) { struct Ltm_file_data *f_data = userdata; F_DATA_DECL(Vstr_base *, io_r); int fd = g_io_channel_unix_get_fd(source); size_t prev_len = io_r->len; if (condition & (G_IO_ERR|G_IO_HUP|G_IO_NVAL)) { if (vstr_sc_read_iov_fd(f_data->io_r, io_r->len, fd, 1024, 1024, NULL)) goto got_data; return (FALSE); } if (!vstr_sc_read_iov_fd(f_data->io_r, io_r->len, fd, 1024, 1024, NULL)) return (FALSE); got_data: f_data->unparsed_len += io_r->len - prev_len; if (!f_data->idle_id) f_data->idle_id = g_idle_add(ltm_idle_tree_insert_cb, f_data); return (TRUE); } int main(int argc, char *argv[]) { Vstr_base *io_r = NULL; Vstr_base *io_w = NULL; int arg_count = 1; int scan = 0; struct Ltm_file_data *f_data = g_new0(struct Ltm_file_data, 1); Vstr_sects *sects = NULL; const char *ssh_usr = NULL; f_data->pos = 1; f_data->parsed_num = 1; if (!vstr_init()) abort(); vstr_cntl_conf(NULL, VSTR_CNTL_CONF_SET_NUM_BUF_SZ, 4096); io_r = vstr_make_base(NULL); io_w = vstr_make_base(NULL); sects = vstr_sects_make(1024); if (!io_r || !io_w || !sects) abort(); vstr_cntl_conf(io_w->conf, VSTR_CNTL_CONF_SET_FMT_CHAR_ESC, '$'); vstr_cntl_conf(io_w->conf, VSTR_CNTL_CONF_SET_LOC_CSTR_THOU_SEP, "_"); vstr_cntl_conf(io_w->conf, VSTR_CNTL_CONF_SET_LOC_CSTR_THOU_GRP, "\3"); vstr_sc_fmt_add_all(io_w->conf); if (argc < 2) { vstr_add_fmt(io_w, io_w->len, " Usage: %s \n%s\n", argv[0], " :\n" " T:all = Group everyone\n" " T:frm = Group on the From IP address\n" " T:frm_group = Group on clients\n" " T:last = Throw away all but last\n" " T:main_ref = Group on sub sections of the Referrer URL\n" " T:main_req = Group on sub sections of the Request\n" " T:main_usr = Group on the User header, ignoring versions\n" " T:ref = Group on the Referrer URL\n" " T:req = Group on the Request\n" " T:ret = Group on the Return code\n" " T:usr = Group on the User header\n" "their own groups\n"); while (io_w->len) if (!vstr_sc_write_fd(io_w, 1, io_w->len, 2, NULL)) abort(); exit (EXIT_FAILURE); } while ((arg_count < argc) && (scan < LTM_INDENT_ON_SZ)) { if (0) { } else if (!strcmp(argv[arg_count], "T:all")) ltm_conf_indent_on_type[scan] = LTM_INDENT_ON_TYPE_ALL; else if (!strcmp(argv[arg_count], "T:frm")) ltm_conf_indent_on_type[scan] = LTM_INDENT_ON_TYPE_FRM; else if (!strcmp(argv[arg_count], "T:frm_group")) ltm_conf_indent_on_type[scan] = LTM_INDENT_ON_TYPE_FRM_GROUP; else if (!strcmp(argv[arg_count], "T:last")) ltm_conf_indent_on_type[scan] = LTM_INDENT_ON_TYPE_LAST; else if (!strcmp(argv[arg_count], "T:main_ref")) ltm_conf_indent_on_type[scan] = LTM_INDENT_ON_TYPE_MAIN_REF; else if (!strcmp(argv[arg_count], "T:main_req")) ltm_conf_indent_on_type[scan] = LTM_INDENT_ON_TYPE_MAIN_REQ; else if (!strcmp(argv[arg_count], "T:main_usr")) ltm_conf_indent_on_type[scan] = LTM_INDENT_ON_TYPE_MAIN_USR; else if (!strcmp(argv[arg_count], "T:ref")) ltm_conf_indent_on_type[scan] = LTM_INDENT_ON_TYPE_REF; else if (!strcmp(argv[arg_count], "T:req")) ltm_conf_indent_on_type[scan] = LTM_INDENT_ON_TYPE_REQ; else if (!strcmp(argv[arg_count], "T:ret")) ltm_conf_indent_on_type[scan] = LTM_INDENT_ON_TYPE_RET; else if (!strcmp(argv[arg_count], "T:usr")) ltm_conf_indent_on_type[scan] = LTM_INDENT_ON_TYPE_USR; else break; ++arg_count; ++scan; } while (arg_count < argc) { char *spawn_argv[16]; pid_t spawn_pid = 0; int spawn_io_1 = -1; GIOChannel *spawn_gio = NULL; GError *spawn_err = NULL; unsigned int spawn_argc = 0; size_t len = strlen(argv[arg_count]); if (0) { } else if ((len >= strlen("tail:")) && !memcmp(argv[arg_count], "tail:", strlen("tail:"))) { argv[arg_count] += strlen("tail:"); spawn_argv[spawn_argc++] = (char *)"tail"; spawn_argv[spawn_argc++] = (char *)"Apache logfile monitor"; spawn_argv[spawn_argc++] = (char *)"-n"; spawn_argv[spawn_argc++] = (char *)"0"; spawn_argv[spawn_argc++] = (char *)"-f"; } else if ((len >= strlen("ssh-uh:")) && !memcmp(argv[arg_count], "ssh-uh:", strlen("ssh-uh:"))) { ssh_usr = argv[arg_count++]; ssh_usr += strlen("ssh-uh:"); continue; } else if (ssh_usr && (len >= strlen("ssh-file:")) && !memcmp(argv[arg_count], "ssh-file:", strlen("ssh-file:"))) { argv[arg_count] += strlen("ssh-file:"); spawn_argv[spawn_argc++] = (char *)"ssh"; spawn_argv[spawn_argc++] = (char *)"Apache remote logfile monitor"; spawn_argv[spawn_argc++] = (char *)ssh_usr; spawn_argv[spawn_argc++] = (char *)"--"; spawn_argv[spawn_argc++] = (char *)"tail"; spawn_argv[spawn_argc++] = (char *)"-n"; spawn_argv[spawn_argc++] = (char *)"0"; spawn_argv[spawn_argc++] = (char *)"-f"; } else { if ((len >= strlen("file:")) && !memcmp(argv[arg_count], "file:", strlen("file:"))) argv[arg_count] += strlen("file:"); spawn_argv[spawn_argc++] = (char *)"cat"; spawn_argv[spawn_argc++] = (char *)"Apache logfile dumper"; } spawn_argv[spawn_argc++] = (char *)"--"; spawn_argv[spawn_argc++] = argv[arg_count]; spawn_argv[spawn_argc++] = NULL; g_assert(spawn_argc <= (sizeof(spawn_argv) / sizeof(spawn_argv[0]))); if (!g_spawn_async_with_pipes(".", spawn_argv, NULL, G_SPAWN_LEAVE_DESCRIPTORS_OPEN | G_SPAWN_SEARCH_PATH | G_SPAWN_STDERR_TO_DEV_NULL | G_SPAWN_CHILD_INHERITS_STDIN | G_SPAWN_FILE_AND_ARGV_ZERO, NULL, NULL, &spawn_pid, NULL, &spawn_io_1, NULL, &spawn_err)) g_error("g_spawn: %s", spawn_err->message); spawn_gio = g_io_channel_unix_new(spawn_io_1); g_io_add_watch(spawn_gio, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, ltm_gio_cb, f_data); ++arg_count; } f_data->sects = sects; f_data->io_r = io_r; ltm_gtk_list(io_r, f_data); vstr_sects_free(sects); vstr_free_base(io_r); vstr_free_base(io_w); vstr_exit(); g_free(f_data); return (EXIT_SUCCESS); }