git-svn: trunk@4383
Török Edvin authored on 2008/11/12 21:06:15... | ... |
@@ -1,3 +1,9 @@ |
1 |
+Wed Nov 12 13:06:33 EET 2008 (edwin) |
|
2 |
+------------------------------------ |
|
3 |
+ * contrib/clamdtop/Makefile, contrib/clamdtop/TODO, |
|
4 |
+ contrib/clamdtop/clamdtop.c: refactor, multiple clamd support. |
|
5 |
+ documentation, and detailview to come later. |
|
6 |
+ |
|
1 | 7 |
Wed Nov 12 11:21:45 CET 2008 (acab) |
2 | 8 |
----------------------------------- |
3 | 9 |
* docs/man/clamav-milter.8.in: avoid hyphen-used-as-minus-sign warnings |
... | ... |
@@ -1,8 +1,7 @@ |
1 |
-CFLAGS=-O2 -g -Wall -W -Wshadow |
|
1 |
+CFLAGS=-g -Wall -W -Wshadow -Wformat=2 -O2 |
|
2 | 2 |
CC=gcc |
3 | 3 |
OBJS=clamdtop.o |
4 |
-LDFLAGS= |
|
5 |
-CPPFLAGS= |
|
4 |
+CPPFLAGS=-D_FORTIFY_SOURCE=2 |
|
6 | 5 |
|
7 | 6 |
ifeq ($(MSYSTEM),MINGW32) |
8 | 7 |
LIBS=-lpdcurses -lws2_32 |
... | ... |
@@ -11,7 +10,7 @@ LIBS=-lncurses |
11 | 11 |
endif |
12 | 12 |
|
13 | 13 |
clamdtop: $(OBJS) Makefile |
14 |
- $(CC) $(CPPFLAGS) $(CFLAGS) $(OBJS) -o $@ $(LDFLAGS) $(LIBS) |
|
14 |
+ $(CC) $(OBJS) -o $@ $(LDFLAGS) $(LIBS) |
|
15 | 15 |
|
16 | 16 |
clean: |
17 | 17 |
rm -f clamdtop $(OBJS) |
... | ... |
@@ -1,12 +1,9 @@ |
1 |
-monitor more than one remote clamd |
|
1 |
+select one clamd when monitoring more, and show details for that only |
|
2 |
+better handling for connection errors (inform user within an ncurses window) |
|
2 | 3 |
write a manpage |
3 | 4 |
consider writing a GUI using Tk 8.5 (version 8.5 has much nicer widgets than 8.4) |
4 | 5 |
integrate into toplevel clamav, and build if ncurses is available (optional) |
5 | 6 |
figure out minimum version of ncurses required, I used 5.5 during development. |
6 |
-show mempool statistics too. |
|
7 |
-reconnect after a DB reload (we get a broken pipe) |
|
8 | 7 |
describe what the various fields mean, like what live/idle threads mean and why |
9 | 8 |
describe why the multiscan view is split |
10 | 9 |
explain what queue means, and why it is high with multiscan |
11 |
-figure a solution to represent multiple multiscan commands (though why would |
|
12 |
-somebody run 2 in parallel?) |
... | ... |
@@ -19,13 +19,17 @@ |
19 | 19 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
20 | 20 |
* MA 02110-1301, USA. |
21 | 21 |
*/ |
22 |
+#define _GNU_SOURCE |
|
23 |
+#define __EXTENSIONS |
|
24 |
+#define GCC_PRINTF |
|
25 |
+#define GCC_SCANF |
|
22 | 26 |
#include <unistd.h> |
23 | 27 |
#include <stdio.h> |
24 | 28 |
#include <stdlib.h> |
25 | 29 |
#include <string.h> |
26 | 30 |
#include <stdint.h> |
27 | 31 |
#include <sys/types.h> |
28 |
-#include <ncurses.h> |
|
32 |
+#include <curses.h> |
|
29 | 33 |
#include <time.h> |
30 | 34 |
#include <ctype.h> |
31 | 35 |
#include <signal.h> |
... | ... |
@@ -45,6 +49,49 @@ |
45 | 45 |
#include <assert.h> |
46 | 46 |
#include <errno.h> |
47 | 47 |
|
48 |
+/* Types, prototypes and globals*/ |
|
49 |
+typedef struct connection { |
|
50 |
+ int sd; |
|
51 |
+ const char *remote; |
|
52 |
+ int tcp; |
|
53 |
+ struct timeval tv_conn; |
|
54 |
+ char *version; |
|
55 |
+} conn_t; |
|
56 |
+ |
|
57 |
+struct global_stats { |
|
58 |
+ struct task *tasks; |
|
59 |
+ ssize_t n; |
|
60 |
+ struct stats *all_stats; |
|
61 |
+ size_t num_clamd; |
|
62 |
+ conn_t *conn; |
|
63 |
+}; |
|
64 |
+ |
|
65 |
+struct stats { |
|
66 |
+ const char *remote; |
|
67 |
+ char *engine_version; |
|
68 |
+ char *db_version; |
|
69 |
+ struct tm db_time; |
|
70 |
+ const char *version; |
|
71 |
+ uint8_t conn_hr, conn_min, conn_sec; |
|
72 |
+ /* threads - primary */ |
|
73 |
+ unsigned prim_live, prim_idle, prim_max; |
|
74 |
+ /* threads - sum */ |
|
75 |
+ unsigned live, idle, max; |
|
76 |
+ /* queue */ |
|
77 |
+ unsigned biggest_queue, current_q; |
|
78 |
+ double mem;/* in megabytes */ |
|
79 |
+ unsigned long lheapu, lmmapu, ltotalu, ltotalf, lreleasable, lpoolu, lpoolt; |
|
80 |
+ unsigned pools_cnt; |
|
81 |
+}; |
|
82 |
+ |
|
83 |
+static void cleanup(void); |
|
84 |
+static int send_string_noreconn(conn_t *conn, const char *cmd); |
|
85 |
+static void send_string(conn_t *conn, const char *cmd); |
|
86 |
+static void read_version(conn_t *conn); |
|
87 |
+ |
|
88 |
+static struct global_stats global; |
|
89 |
+static int curses_inited = 1; |
|
90 |
+static int maxystats=0; |
|
48 | 91 |
/* ---------------------- NCurses routines -----------------*/ |
49 | 92 |
enum colors { |
50 | 93 |
header_color=1, |
... | ... |
@@ -57,8 +104,6 @@ enum colors { |
57 | 57 |
red_color, |
58 | 58 |
}; |
59 | 59 |
|
60 |
- |
|
61 |
- |
|
62 | 60 |
#define UPDATE_INTERVAL 2 |
63 | 61 |
#define MIN_INTERVAL 1 |
64 | 62 |
|
... | ... |
@@ -69,7 +114,6 @@ enum colors { |
69 | 69 |
#define DESCR_ATTR COLOR_PAIR(descr_color) |
70 | 70 |
|
71 | 71 |
static WINDOW *header_window = NULL; |
72 |
-static WINDOW *version_window = NULL; |
|
73 | 72 |
static WINDOW *stats_head_window = NULL; |
74 | 73 |
static WINDOW *stats_window = NULL; |
75 | 74 |
static WINDOW *status_bar_window = NULL; |
... | ... |
@@ -78,8 +122,20 @@ static WINDOW *mem_window = NULL; |
78 | 78 |
static const char *status_bar_keys[10]; |
79 | 79 |
static unsigned maxy=0, maxx=0; |
80 | 80 |
static char *queue_header = NULL; |
81 |
-static const char *exit_reason = NULL; |
|
82 |
-#define CMDHEAD "COMMAND TIME QUEUED FILE" |
|
81 |
+static char *clamd_header = NULL; |
|
82 |
+ |
|
83 |
+#define CMDHEAD " COMMAND TIME QUEUED FILE" |
|
84 |
+#define CMDHEAD2 "NO COMMAND TIME QUEUED FILE" |
|
85 |
+ |
|
86 |
+/* |
|
87 |
+ * CLAMD - which local/remote clamd this is |
|
88 |
+ * CONNTIM - since when we are connected (TODO: zeroed at reconnect) |
|
89 |
+ * QUEUE - no of items in queue (total) |
|
90 |
+ * MAXQUEUE - max no of items in queue observed |
|
91 |
+ * LIVETHR - sum of live threads |
|
92 |
+ * IDLETHR - sum of idle threads |
|
93 |
+ */ |
|
94 |
+#define SUMHEAD "NO CONNTIME LIV IDL QUEUE MAXQ MEM HOST ENGINE DBVER DBTIME" |
|
83 | 95 |
|
84 | 96 |
static void resize(void) |
85 | 97 |
{ |
... | ... |
@@ -91,14 +147,23 @@ static void resize(void) |
91 | 91 |
maxx = new_maxx; |
92 | 92 |
maxy = new_maxy; |
93 | 93 |
free(queue_header); |
94 |
+ free(clamd_header); |
|
94 | 95 |
queue_header = malloc(maxx + 1); |
95 |
- if(!queue_header) |
|
96 |
+ clamd_header = malloc(maxx + 1); |
|
97 |
+ if(!queue_header || !clamd_header) { |
|
98 |
+ fprintf(stderr,"Out of memory\n"); |
|
96 | 99 |
exit(1); |
100 |
+ } |
|
101 |
+ strncpy(queue_header, global.num_clamd>1 ? CMDHEAD2 : CMDHEAD, maxx); |
|
102 |
+ strncpy(clamd_header, SUMHEAD, maxx); |
|
97 | 103 |
queue_header[maxx] = '\0'; |
98 |
- strncpy(queue_header, CMDHEAD, maxx); |
|
104 |
+ clamd_header[maxx] = '\0'; |
|
99 | 105 |
p = queue_header + strlen(queue_header); |
100 | 106 |
while(p < queue_header+maxx) |
101 | 107 |
*p++ = ' '; |
108 |
+ p = clamd_header + strlen(clamd_header); |
|
109 |
+ while(p < clamd_header+maxx) |
|
110 |
+ *p++ = ' '; |
|
102 | 111 |
} |
103 | 112 |
|
104 | 113 |
static void rm_windows(void) |
... | ... |
@@ -111,10 +176,6 @@ static void rm_windows(void) |
111 | 111 |
delwin(mem_window); |
112 | 112 |
mem_window = NULL; |
113 | 113 |
} |
114 |
- if(version_window) { |
|
115 |
- delwin(version_window); |
|
116 |
- version_window = NULL; |
|
117 |
- } |
|
118 | 114 |
if(stats_window) { |
119 | 115 |
delwin(stats_window); |
120 | 116 |
stats_window = NULL; |
... | ... |
@@ -129,30 +190,20 @@ static void rm_windows(void) |
129 | 129 |
} |
130 | 130 |
} |
131 | 131 |
|
132 |
-static int normal_exit = 0; |
|
133 |
- |
|
134 |
-static void cleanup_ncurses(void) |
|
135 |
-{ |
|
136 |
- werase(status_bar_window); |
|
137 |
- wrefresh(status_bar_window); |
|
138 |
- rm_windows(); |
|
139 |
- endwin(); |
|
140 |
- if(!normal_exit) |
|
141 |
- printf("Abnormal program termination %s\n", |
|
142 |
- exit_reason ? exit_reason : ""); |
|
143 |
-} |
|
144 | 132 |
|
145 |
-static void init_windows(void) |
|
133 |
+static void init_windows(int num_clamd) |
|
146 | 134 |
{ |
147 | 135 |
resize(); |
148 | 136 |
|
149 | 137 |
rm_windows(); |
138 |
+ /* non-overlapping windows */ |
|
150 | 139 |
header_window = subwin(stdscr, 1, maxx, 0, 0); |
151 |
- version_window = subwin(stdscr, 1, maxx, 1, 0); |
|
152 |
- stats_head_window = subwin(stdscr, 5, maxx-48, 3, 0); |
|
153 |
- stats_window = subwin(stdscr, maxy-9, maxx, 7, 0); |
|
154 |
- mem_window = subwin(stdscr, 6, 48, 3, maxx-48); |
|
155 |
- status_bar_window = subwin(stdscr, 1i, maxx, maxy-1, 0); |
|
140 |
+ stats_head_window = subwin(stdscr, num_clamd+1, maxx, 1, 0); |
|
141 |
+ maxystats = maxy-num_clamd-3; |
|
142 |
+ stats_window = subwin(stdscr, maxystats, maxx, num_clamd+2, 0); |
|
143 |
+ status_bar_window = subwin(stdscr, 1, maxx, maxy-1, 0); |
|
144 |
+ /* memwindow overlaps, used only in details mode */ |
|
145 |
+ mem_window = derwin(stats_window, 6, 48, 0, maxx-48); |
|
156 | 146 |
touchwin(stdscr); |
157 | 147 |
werase(stdscr); |
158 | 148 |
refresh(); |
... | ... |
@@ -161,9 +212,11 @@ static void init_windows(void) |
161 | 161 |
status_bar_keys[1] = "R - reset bar maximums"; |
162 | 162 |
} |
163 | 163 |
|
164 |
-static void init_ncurses(void) |
|
164 |
+static void init_ncurses(int num_clamd) |
|
165 | 165 |
{ |
166 | 166 |
initscr(); |
167 |
+ curses_inited = 1; |
|
168 |
+ |
|
167 | 169 |
start_color(); |
168 | 170 |
keypad(stdscr, TRUE); /* enable keyboard mapping */ |
169 | 171 |
nonl(); /* tell curses not to do NL->CR/NL on output */ |
... | ... |
@@ -181,9 +234,7 @@ static void init_ncurses(void) |
181 | 181 |
init_pair(dim_color, COLOR_GREEN, DEFAULT_COLOR); |
182 | 182 |
init_pair(red_color, COLOR_RED, DEFAULT_COLOR); |
183 | 183 |
|
184 |
- atexit(cleanup_ncurses); |
|
185 |
- |
|
186 |
- init_windows(); |
|
184 |
+ init_windows(num_clamd); |
|
187 | 185 |
} |
188 | 186 |
|
189 | 187 |
static void win_start(WINDOW *win, enum colors col) |
... | ... |
@@ -208,23 +259,27 @@ static void print_colored(WINDOW *win, const char *p) |
208 | 208 |
} |
209 | 209 |
} |
210 | 210 |
|
211 |
-static char *clamd_version = NULL; |
|
212 |
- |
|
213 | 211 |
static void header(void) |
214 | 212 |
{ |
215 | 213 |
size_t i, x=0; |
216 | 214 |
time_t t; |
217 | 215 |
|
216 |
+ |
|
218 | 217 |
win_start(header_window, header_color); |
219 | 218 |
mvwprintw(header_window, 0, 0, " ClamdTOP version 0.1 "); |
219 |
+/* mvwprintw(header_window, 0, 0, " __ ____ "); |
|
220 |
+ mvwprintw(header_window, 1, 0, " ____/ /__ ___ _ ___/ / /____ ___ "); |
|
221 |
+ mvwprintw(header_window, 2, 0, "/ __/ / _ `/ ' \\/ _ / __/ _ \\/ _ \\"); |
|
222 |
+ mvwprintw(header_window, 3, 0, "\\__/_/\\_,_/_/_/_/\\_,_/\\__/\\___/ .__/"); |
|
223 |
+ mvwprintw(header_window, 4, 0," /_/ ");*/ |
|
220 | 224 |
time(&t); |
221 | 225 |
wprintw(header_window, "%s", ctime(&t)); |
222 | 226 |
wrefresh(header_window); |
223 | 227 |
|
224 |
- win_start(version_window, version_color); |
|
228 |
+/* win_start(version_window, version_color); |
|
225 | 229 |
mvwprintw(version_window, 0, 0, "Connected to: "); |
226 | 230 |
print_colored(version_window, clamd_version ? clamd_version : "Unknown"); |
227 |
- wrefresh(version_window); |
|
231 |
+ wrefresh(version_window);*/ |
|
228 | 232 |
|
229 | 233 |
werase(status_bar_window); |
230 | 234 |
for(i=0;i<sizeof(status_bar_keys)/sizeof(status_bar_keys[0]);i++) { |
... | ... |
@@ -268,9 +323,75 @@ static void show_bar(WINDOW *win, size_t i, unsigned live, unsigned idle, |
268 | 268 |
} |
269 | 269 |
} |
270 | 270 |
|
271 |
+/* --------------------- Error handling ---------------------*/ |
|
272 |
+static int normal_exit = 0; |
|
273 |
+static const char *exit_reason = NULL; |
|
274 |
+static const char *exit_func = NULL; |
|
275 |
+static unsigned exit_line = 0; |
|
276 |
+ |
|
277 |
+static void cleanup(void) |
|
278 |
+{ |
|
279 |
+ unsigned i; |
|
280 |
+ if (curses_inited) { |
|
281 |
+ werase(status_bar_window); |
|
282 |
+ wrefresh(status_bar_window); |
|
283 |
+ rm_windows(); |
|
284 |
+ endwin(); |
|
285 |
+ } |
|
286 |
+ curses_inited = 0; |
|
287 |
+ for (i=0;i<global.num_clamd;i++) { |
|
288 |
+ if (global.conn[i].sd) |
|
289 |
+ send_string_noreconn(&global.conn[i], "END\n"); |
|
290 |
+ close(global.conn[i].sd); |
|
291 |
+ free(global.conn[i].version); |
|
292 |
+ } |
|
293 |
+ free(global.all_stats); |
|
294 |
+ free(global.conn); |
|
295 |
+ free(queue_header); |
|
296 |
+ free(clamd_header); |
|
297 |
+ if(!normal_exit) { |
|
298 |
+ fprintf(stderr, "Abnormal program termination"); |
|
299 |
+ if (exit_reason) fprintf(stderr, ": %s",exit_reason); |
|
300 |
+ if (exit_func) fprintf(stderr, " in %s", exit_func); |
|
301 |
+ if (exit_line) fprintf(stderr, " at line %u", exit_line); |
|
302 |
+ fputc('\n',stderr); |
|
303 |
+ } |
|
304 |
+} |
|
305 |
+ |
|
306 |
+enum exit_reason { |
|
307 |
+ FAIL_INITIAL_CONN=1, |
|
308 |
+ OUT_OF_MEMORY, |
|
309 |
+ RECONNECT_FAIL |
|
310 |
+}; |
|
311 |
+ |
|
312 |
+static void exit_program(enum exit_reason reason, const char *func, unsigned line) |
|
313 |
+{ |
|
314 |
+ switch(reason) { |
|
315 |
+ case FAIL_INITIAL_CONN: |
|
316 |
+ exit_reason = "Unable to connect to all clamds"; |
|
317 |
+ break; |
|
318 |
+ case OUT_OF_MEMORY: |
|
319 |
+ exit_reason = "Out of memory"; |
|
320 |
+ break; |
|
321 |
+ case RECONNECT_FAIL: |
|
322 |
+ exit_reason = "Failed to reconnect to clamd after connection was lost"; |
|
323 |
+ break; |
|
324 |
+ default: |
|
325 |
+ exit_reason = "Unknown"; |
|
326 |
+ break; |
|
327 |
+ } |
|
328 |
+ exit_func = func; |
|
329 |
+ exit_line = line; |
|
330 |
+ exit(reason); |
|
331 |
+} |
|
332 |
+ |
|
333 |
+#define EXIT_PROGRAM(r) exit_program(r, __PRETTY_FUNCTION__, __LINE__); |
|
334 |
+#define OOM_CHECK(p) do { if (!p) EXIT_PROGRAM(OUT_OF_MEMORY); } while (0) |
|
335 |
+ |
|
271 | 336 |
struct task { |
272 | 337 |
char *line; |
273 | 338 |
double tim; |
339 |
+ int clamd_no; |
|
274 | 340 |
}; |
275 | 341 |
|
276 | 342 |
static int tasks_compare(const void *a, const void *b) |
... | ... |
@@ -285,21 +406,16 @@ static int tasks_compare(const void *a, const void *b) |
285 | 285 |
} |
286 | 286 |
|
287 | 287 |
/* ----------- Socket routines ----------------------- */ |
288 |
-typedef struct connection { |
|
289 |
- int sd; |
|
290 |
- const char *remote; |
|
291 |
-} conn_t; |
|
292 |
- |
|
293 | 288 |
static void print_con_error(const char *fmt, ...) |
294 | 289 |
{ |
295 | 290 |
va_list ap; |
296 | 291 |
va_start(ap, fmt); |
297 |
- if (version_window) { |
|
292 |
+/* if (version_window) { |
|
298 | 293 |
werase(version_window); |
299 | 294 |
wmove(version_window, 0, 0); |
300 | 295 |
vwprintw(version_window, fmt, ap); |
301 | 296 |
wrefresh(version_window); |
302 |
- } else |
|
297 |
+ } else*/ |
|
303 | 298 |
vfprintf(stderr, fmt, ap); |
304 | 299 |
va_end(ap); |
305 | 300 |
} |
... | ... |
@@ -308,6 +424,7 @@ static void print_con_error(const char *fmt, ...) |
308 | 308 |
static int make_connection(const char *soname, conn_t *conn) |
309 | 309 |
{ |
310 | 310 |
int s; |
311 |
+ conn->tcp = 0; |
|
311 | 312 |
#ifdef _WIN32 |
312 | 313 |
{ |
313 | 314 |
#else |
... | ... |
@@ -333,6 +450,7 @@ static int make_connection(const char *soname, conn_t *conn) |
333 | 333 |
unsigned port = 0; |
334 | 334 |
char *name, *pt = strdup(soname); |
335 | 335 |
const char *host = pt; |
336 |
+ conn->tcp=1; |
|
336 | 337 |
name = strchr(pt, ':'); |
337 | 338 |
if(name) { |
338 | 339 |
*name++ = '\0'; |
... | ... |
@@ -362,28 +480,43 @@ static int make_connection(const char *soname, conn_t *conn) |
362 | 362 |
} |
363 | 363 |
conn->remote = soname; |
364 | 364 |
conn->sd = s; |
365 |
+ gettimeofday(&conn->tv_conn, NULL); |
|
366 |
+ send_string(conn, "SESSION\nVERSION\n"); |
|
367 |
+ read_version(conn); |
|
365 | 368 |
return 0; |
366 | 369 |
} |
367 | 370 |
|
368 |
-static void reconnect(conn_t *conn) |
|
369 |
-{ |
|
370 |
- print_con_error("%s: %s", conn->remote, strerror(errno)); |
|
371 |
- if (make_connection(conn->remote, conn) < 0) { |
|
372 |
- print_con_error("Unable to reconnect to %s: %s", conn->remote, strerror(errno)); |
|
373 |
- exit(3); |
|
374 |
- } |
|
375 |
-} |
|
371 |
+static void reconnect(conn_t *conn); |
|
376 | 372 |
|
377 |
-static void send_string(conn_t *conn, const char *cmd) |
|
373 |
+static int send_string_noreconn(conn_t *conn, const char *cmd) |
|
378 | 374 |
{ |
379 | 375 |
assert(cmd); |
380 | 376 |
assert(conn && conn->sd > 0); |
377 |
+ return send(conn->sd, cmd, strlen(cmd), 0); |
|
378 |
+} |
|
381 | 379 |
|
382 |
- while(send(conn->sd, cmd, strlen(cmd), 0) == -1) { |
|
380 |
+static void send_string(conn_t *conn, const char *cmd) |
|
381 |
+{ |
|
382 |
+ while(send_string_noreconn(conn, cmd) == -1) { |
|
383 | 383 |
reconnect(conn); |
384 | 384 |
} |
385 | 385 |
} |
386 | 386 |
|
387 |
+static int tries = 0; |
|
388 |
+static void reconnect(conn_t *conn) |
|
389 |
+{ |
|
390 |
+ if(++tries > 3) { |
|
391 |
+ EXIT_PROGRAM(RECONNECT_FAIL); |
|
392 |
+ } |
|
393 |
+ print_con_error("%s: %s", conn->remote, strerror(errno)); |
|
394 |
+ if (make_connection(conn->remote, conn) < 0) { |
|
395 |
+ print_con_error("Unable to reconnect to %s: %s", conn->remote, strerror(errno)); |
|
396 |
+ exit(3); |
|
397 |
+ } |
|
398 |
+ free(conn->version); |
|
399 |
+ tries = 0; |
|
400 |
+} |
|
401 |
+ |
|
387 | 402 |
static int recv_line(conn_t *conn, char *buf, size_t len) |
388 | 403 |
{ |
389 | 404 |
assert(len > 0); |
... | ... |
@@ -420,11 +553,52 @@ static int recv_line(conn_t *conn, char *buf, size_t len) |
420 | 420 |
return 1; |
421 | 421 |
} |
422 | 422 |
|
423 |
+static void output_queue(size_t line, ssize_t max) |
|
424 |
+{ |
|
425 |
+ ssize_t i; |
|
426 |
+ struct task *tasks = global.tasks; |
|
427 |
+ assert(tasks); |
|
428 |
+ wattron(stats_window, COLOR_PAIR(queue_header_color)); |
|
429 |
+ mvwprintw(stats_window, line++, 0, "%s", queue_header); |
|
430 |
+ wattroff(stats_window, COLOR_PAIR(queue_header_color)); |
|
431 |
+ if (max >= global.n) |
|
432 |
+ max = global.n; |
|
433 |
+ else |
|
434 |
+ --max; |
|
435 |
+ if (max < 0) max = 0; |
|
436 |
+ for(i=0;i<max;i++) { |
|
437 |
+ char *cmde = strchr(tasks[i].line, ' '); |
|
438 |
+ if(cmde) { |
|
439 |
+ char cmd[16]; |
|
440 |
+ const char *filstart = strchr(cmde + 1, ' '); |
|
441 |
+ strncpy(cmd, tasks[i].line, sizeof(cmd)-1); |
|
442 |
+ cmd[15]='\0'; |
|
443 |
+ if (tasks[i].line+15 > cmde) |
|
444 |
+ cmd[cmde - tasks[i].line] = '\0'; |
|
445 |
+ if(filstart) { |
|
446 |
+ ++filstart; |
|
447 |
+ if (global.num_clamd>1) |
|
448 |
+ mvwprintw(stats_window, line + i, 0, "%2u %s", tasks[i].clamd_no, cmd + 1); |
|
449 |
+ else |
|
450 |
+ mvwprintw(stats_window, line + i, 0, " %s", cmd + 1); |
|
451 |
+ mvwprintw(stats_window, line + i, 15, "%10.03fs", tasks[i].tim); |
|
452 |
+ mvwprintw(stats_window, line + i, 30, "%s",filstart); |
|
453 |
+ } |
|
454 |
+ } |
|
455 |
+ } |
|
456 |
+ if (max < global.n) { |
|
457 |
+ /* in summary mode we can only show a max amount of tasks */ |
|
458 |
+ wattron(stats_window, A_DIM | COLOR_PAIR(header_color)); |
|
459 |
+ mvwprintw(stats_window, line+i, 0, "*** %u more task(s) not shown ***", (unsigned)(global.n - max)); |
|
460 |
+ wattroff(stats_window, A_DIM | COLOR_PAIR(header_color)); |
|
461 |
+ } |
|
462 |
+} |
|
463 |
+ |
|
423 | 464 |
/* ---------------------- stats parsing routines ------------------- */ |
424 |
-static size_t parse_queue(conn_t *conn, size_t line, char* buf, size_t len) |
|
465 |
+ |
|
466 |
+ |
|
467 |
+static void parse_queue(conn_t *conn, char* buf, size_t len, unsigned idx) |
|
425 | 468 |
{ |
426 |
- struct task *tasks = NULL; |
|
427 |
- size_t n = 0, i; |
|
428 | 469 |
do { |
429 | 470 |
double tim; |
430 | 471 |
const char *t = strchr(buf, ' '); |
... | ... |
@@ -432,220 +606,407 @@ static size_t parse_queue(conn_t *conn, size_t line, char* buf, size_t len) |
432 | 432 |
continue; |
433 | 433 |
if(sscanf(t,"%lf", &tim) != 1) |
434 | 434 |
continue; |
435 |
- ++n; |
|
436 |
- tasks = realloc(tasks, sizeof(*tasks)*n); |
|
437 |
- if(!tasks) { |
|
435 |
+ ++global.n; |
|
436 |
+ global.tasks = realloc(global.tasks, sizeof(*global.tasks)*global.n); |
|
437 |
+ if(!global.tasks) { |
|
438 |
+ fprintf(stderr, "Out of memory\n"); |
|
438 | 439 |
/* OOM */ |
439 | 440 |
exit(1); |
440 | 441 |
} |
441 |
- tasks[n-1].line = strdup(buf); |
|
442 |
- if(!tasks[n-1].line) |
|
442 |
+ global.tasks[global.n-1].line = strdup(buf); |
|
443 |
+ if(!global.tasks[global.n-1].line) { |
|
444 |
+ fprintf(stderr, "Out of memory\n"); |
|
443 | 445 |
exit(1); |
444 |
- tasks[n-1].tim = tim; |
|
445 |
- } while (recv_line(conn, buf, len) && buf[0] == '\t' && strcmp("END\n", buf) != 0); |
|
446 |
- qsort(tasks, n, sizeof(*tasks), tasks_compare); |
|
447 |
- wattron(stats_window, COLOR_PAIR(queue_header_color)); |
|
448 |
- mvwprintw(stats_window, line++, 0, queue_header); |
|
449 |
- wattroff(stats_window, COLOR_PAIR(queue_header_color)); |
|
450 |
- for(i=0;i<n;i++) { |
|
451 |
- char *cmde = strchr(tasks[i].line, ' '); |
|
452 |
- if(cmde) { |
|
453 |
- const char *filstart = strchr(cmde + 1, ' '); |
|
454 |
- *cmde = '\0'; |
|
455 |
- if(filstart) { |
|
456 |
- ++filstart; |
|
457 |
- mvwprintw(stats_window, line + i, 0, " %s", tasks[i].line + 1); |
|
458 |
- mvwprintw(stats_window, line + i, 15, "%10.03fs", tasks[i].tim); |
|
459 |
- mvwprintw(stats_window, line + i, 30, "%s",filstart); |
|
460 |
- } |
|
461 | 446 |
} |
462 |
- free(tasks[i].line); |
|
463 |
- } |
|
464 |
- free(tasks); |
|
465 |
- return line + i + 1; |
|
447 |
+ global.tasks[global.n-1].tim = tim; |
|
448 |
+ global.tasks[global.n-1].clamd_no = idx; |
|
449 |
+ } while (recv_line(conn, buf, len) && buf[0] == '\t' && strcmp("END\n", buf) != 0); |
|
466 | 450 |
} |
467 | 451 |
|
468 | 452 |
static unsigned biggest_queue = 1, biggest_mem = 0; |
469 | 453 |
|
470 |
-static void output_memstats(const char* line) |
|
454 |
+static void output_memstats(struct stats *stats) |
|
471 | 455 |
{ |
472 | 456 |
char buf[128]; |
457 |
+ unsigned long totalmem; |
|
473 | 458 |
int blink = 0; |
474 |
- double heapu, mmapu, totalu, totalf, releasable, pools_used, pools_total; |
|
475 |
- unsigned pools_cnt; |
|
476 |
- unsigned long lheapu, lmmapu, ltotalu, ltotalf, lreleasable, totalmem, lpoolu, lpoolt; |
|
477 | 459 |
|
478 |
- if(sscanf(line, " heap %lfM mmap %lfM used %lfM free %lfM releasable %lfM pools %u pools_used %lfM pools_total %lfM", |
|
479 |
- &heapu, &mmapu, &totalu, &totalf, &releasable, &pools_cnt, &pools_used, &pools_total) != 8) |
|
480 |
- return; |
|
481 |
- lheapu = heapu*1000; |
|
482 |
- lmmapu = mmapu*1000; |
|
483 |
- ltotalu = totalu*1000; |
|
484 |
- ltotalf = totalf*1000; |
|
485 |
- lreleasable = releasable*1000; |
|
486 |
- lpoolu = pools_used*1000; |
|
487 |
- lpoolt = pools_total*1000; |
|
488 | 460 |
werase(mem_window); |
489 | 461 |
box(mem_window, 0, 0); |
490 | 462 |
|
491 | 463 |
snprintf(buf, sizeof(buf),"heap %4luM mmap %4luM releasable %3luM", |
492 |
- lheapu/1024, lmmapu/1024, lreleasable/1024); |
|
464 |
+ stats->lheapu/1024, stats->lmmapu/1024, stats->lreleasable/1024); |
|
493 | 465 |
mvwprintw(mem_window, 1, 1, "Memory: "); |
494 | 466 |
print_colored(mem_window, buf); |
495 | 467 |
|
496 | 468 |
mvwprintw(mem_window, 2, 1, "Malloc: "); |
497 | 469 |
snprintf(buf, sizeof(buf),"used %4luM free %4luM total %4luM", |
498 |
- ltotalu/1024, ltotalf/1024, (ltotalu+ltotalf)/1024); |
|
470 |
+ stats->ltotalu/1024, stats->ltotalf/1024, (stats->ltotalu+stats->ltotalf)/1024); |
|
499 | 471 |
print_colored(mem_window, buf); |
500 | 472 |
|
501 | 473 |
mvwprintw(mem_window, 3, 1, "Mempool: "); |
502 | 474 |
snprintf(buf, sizeof(buf), "count %u used %4luM total %4luM", |
503 |
- pools_cnt, lpoolu/1024, lpoolt/1024); |
|
475 |
+ stats->pools_cnt, stats->lpoolu/1024, stats->lpoolt/1024); |
|
504 | 476 |
print_colored(mem_window, buf); |
505 | 477 |
|
506 |
- totalmem = lheapu + lmmapu + lpoolt; |
|
478 |
+ totalmem = stats->lheapu + stats->lmmapu + stats->lpoolt; |
|
507 | 479 |
if(totalmem > biggest_mem) { |
508 | 480 |
biggest_mem = totalmem; |
509 | 481 |
blink = 1; |
510 | 482 |
} |
511 |
- show_bar(mem_window, 4, totalmem, lmmapu + lreleasable + lpoolt - lpoolu, |
|
483 |
+ show_bar(mem_window, 4, totalmem, stats->lmmapu + stats->lreleasable + stats->lpoolt - stats->lpoolu, |
|
512 | 484 |
biggest_mem, blink); |
513 | 485 |
wrefresh(mem_window); |
514 | 486 |
} |
515 | 487 |
|
516 |
-static struct timeval tv_conn; |
|
488 |
+static void parse_memstats(const char *line, struct stats *stats) |
|
489 |
+{ |
|
490 |
+ double heapu, mmapu, totalu, totalf, releasable, pools_used, pools_total; |
|
491 |
+ |
|
492 |
+ if(sscanf(line, " heap %lfM mmap %lfM used %lfM free %lfM releasable %lfM pools %u pools_used %lfM pools_total %lfM", |
|
493 |
+ &heapu, &mmapu, &totalu, &totalf, &releasable, &stats->pools_cnt, &pools_used, &pools_total) != 8) |
|
494 |
+ return; |
|
495 |
+ stats->lheapu = heapu*1000; |
|
496 |
+ stats->lmmapu = mmapu*1000; |
|
497 |
+ stats->ltotalu = totalu*1000; |
|
498 |
+ stats->ltotalf = totalf*1000; |
|
499 |
+ stats->lreleasable = releasable*1000; |
|
500 |
+ stats->lpoolu = pools_used*1000; |
|
501 |
+ stats->lpoolt = pools_total*1000; |
|
502 |
+ stats->mem = heapu + mmapu + pools_total; |
|
503 |
+} |
|
517 | 504 |
|
518 |
-static void parse_stats(conn_t *conn) |
|
505 |
+static int show_detail(int idx) |
|
519 | 506 |
{ |
507 |
+ if (global.num_clamd == 1) { |
|
508 |
+ assert(idx == 0); |
|
509 |
+ return 1; |
|
510 |
+ } |
|
511 |
+ return 0; |
|
512 |
+} |
|
513 |
+ |
|
514 |
+static int has_detail() |
|
515 |
+{ |
|
516 |
+ return global.num_clamd == 1; |
|
517 |
+} |
|
518 |
+ |
|
519 |
+static int output_stats(struct stats *stats, unsigned idx) |
|
520 |
+{ |
|
521 |
+ char buf[128]; |
|
522 |
+ char timbuf[15]; |
|
523 |
+ int blink = 0; |
|
524 |
+ size_t i= 0; |
|
525 |
+ char mem[6]; |
|
520 | 526 |
WINDOW *win = stats_head_window; |
527 |
+ |
|
528 |
+ if (stats->mem == -1) |
|
529 |
+ strcpy(mem, "N/A"); |
|
530 |
+ else { |
|
531 |
+ char c; |
|
532 |
+ double s; |
|
533 |
+ if (stats->mem > 999.0) { |
|
534 |
+ c = 'G'; |
|
535 |
+ s = stats->mem / 1024.0; |
|
536 |
+ } else { |
|
537 |
+ c = 'M'; |
|
538 |
+ s = stats->mem; |
|
539 |
+ } |
|
540 |
+ snprintf(mem, sizeof(mem), "%7.3f", s); |
|
541 |
+ i = 4; |
|
542 |
+ if (mem[i-1] == '.') i--; |
|
543 |
+ mem[i++] = c; |
|
544 |
+ mem[i] = '\0'; |
|
545 |
+ } |
|
546 |
+ i = idx+1; |
|
547 |
+ |
|
548 |
+ if (!stats->db_time.tm_year) |
|
549 |
+ strcpy(timbuf,"N/A"); |
|
550 |
+ else |
|
551 |
+ snprintf(timbuf, sizeof(timbuf), "%04u-%02u-%02u %02uh", |
|
552 |
+ 1900 + stats->db_time.tm_year, |
|
553 |
+ stats->db_time.tm_mon, |
|
554 |
+ stats->db_time.tm_mday, |
|
555 |
+ stats->db_time.tm_hour); |
|
556 |
+ |
|
557 |
+ mvwprintw(win, i++, 0,"%2u %02u:%02u:%02u %3u %3u %5u %5u %5s %-14s %-6s %5s %s", idx+1, stats->conn_hr, stats->conn_min, stats->conn_sec, |
|
558 |
+ stats->live, stats->idle, |
|
559 |
+ stats->current_q, stats->biggest_queue, |
|
560 |
+ mem, |
|
561 |
+ stats->remote, stats->engine_version, stats->db_version, timbuf); |
|
562 |
+ win = stats_window; |
|
563 |
+ i = 0; |
|
564 |
+ if (show_detail(idx)) { |
|
565 |
+ mvwprintw(win, i++, 0, "Primary threads: "); |
|
566 |
+ snprintf(buf, sizeof(buf), "live %3u idle %3u max %3u", stats->prim_live, stats->prim_idle, stats->prim_max); |
|
567 |
+ print_colored(win, buf); |
|
568 |
+ show_bar(win, i++, stats->prim_live, stats->prim_idle, stats->prim_max, 0); |
|
569 |
+ |
|
570 |
+ mvwprintw(win, i++, 0, "All threads: "); |
|
571 |
+ snprintf(buf, sizeof(buf), "live %3u idle %3u max %3u", stats->live, stats->idle, stats->max); |
|
572 |
+ print_colored(win, buf); |
|
573 |
+ show_bar(win, i++, stats->live, stats->idle, stats->max, 0); |
|
574 |
+ |
|
575 |
+ mvwprintw(win, i++, 0, "Queue:"); |
|
576 |
+ snprintf(buf, sizeof(buf), "%6u items %6u max", stats->current_q, stats->biggest_queue); |
|
577 |
+ print_colored(win, buf); |
|
578 |
+ werase(mem_window); |
|
579 |
+ output_memstats(stats); |
|
580 |
+ } |
|
581 |
+ blink = 0; |
|
582 |
+ if(stats->current_q > stats->biggest_queue) { |
|
583 |
+ stats->biggest_queue = stats->current_q; |
|
584 |
+ blink = 1; |
|
585 |
+ } |
|
586 |
+ if (show_detail(idx)) { |
|
587 |
+ show_bar(win, i++, stats->current_q, 0, biggest_queue, blink); |
|
588 |
+ } |
|
589 |
+ return i; |
|
590 |
+} |
|
591 |
+ |
|
592 |
+static void output_all(void) |
|
593 |
+{ |
|
594 |
+ unsigned i, stats_line=0; |
|
595 |
+ werase(stats_head_window); |
|
596 |
+ werase(stats_window); |
|
597 |
+ wattron(stats_head_window, COLOR_PAIR(queue_header_color)); |
|
598 |
+ mvwprintw(stats_head_window, 0, 0, "%s", clamd_header); |
|
599 |
+ wattroff(stats_head_window, COLOR_PAIR(queue_header_color)); |
|
600 |
+ for (i=0;i<global.num_clamd;i++) |
|
601 |
+ stats_line = output_stats(&global.all_stats[i], i); |
|
602 |
+ output_queue(stats_line, maxystats - stats_line-1); |
|
603 |
+ wrefresh(stats_head_window); |
|
604 |
+ wrefresh(stats_window); |
|
605 |
+ if (has_detail()) { |
|
606 |
+ /* overlaps, must be done at the end */ |
|
607 |
+ wrefresh(mem_window); |
|
608 |
+ } |
|
609 |
+} |
|
610 |
+ |
|
611 |
+static void parse_stats(conn_t *conn, struct stats *stats, unsigned idx) |
|
612 |
+{ |
|
521 | 613 |
char buf[1024]; |
522 |
- size_t i=0 ,j; |
|
614 |
+ size_t j; |
|
523 | 615 |
struct timeval tv; |
524 | 616 |
unsigned conn_dt; |
617 |
+ int primary = 0; |
|
618 |
+ const char *pstart, *p; |
|
619 |
+ |
|
620 |
+ if (conn->tcp) |
|
621 |
+ stats->remote = conn->remote; |
|
622 |
+ else |
|
623 |
+ stats->remote = "local"; |
|
624 |
+ |
|
625 |
+ p = pstart = conn->version; |
|
626 |
+ /* find digit in version */ |
|
627 |
+ while (*p && !isdigit(*p)) |
|
628 |
+ p++; |
|
629 |
+ /* rewind to first space or dash */ |
|
630 |
+ while (p > pstart && *p && *p != ' ' && *p != '-') |
|
631 |
+ p--; |
|
632 |
+ if (*p) p++; |
|
633 |
+ /* keep only base version, and cut -exp, and -gittags */ |
|
634 |
+ pstart = p; |
|
635 |
+ while (*p && *p != '-' && *p != '/') |
|
636 |
+ p++; |
|
637 |
+ |
|
638 |
+ stats->engine_version = malloc(p - pstart+1); |
|
639 |
+ if (!stats->engine_version) { |
|
640 |
+ fprintf(stderr,"Out of memory!\n"); |
|
641 |
+ exit(1); |
|
642 |
+ } |
|
525 | 643 |
|
526 |
- werase(stats_head_window); |
|
527 |
- werase(stats_window); |
|
528 |
- werase(mem_window); |
|
644 |
+ memcpy(stats->engine_version, pstart, p-pstart); |
|
645 |
+ stats->engine_version[p-pstart] = '\0'; |
|
646 |
+ |
|
647 |
+ pstart = strchr(p, '/'); |
|
648 |
+ if (!pstart) |
|
649 |
+ stats->db_version = strdup("????"); |
|
650 |
+ else { |
|
651 |
+ pstart++; |
|
652 |
+ p = strchr(pstart, '/'); |
|
653 |
+ if (!p) |
|
654 |
+ p = pstart + strlen(pstart); |
|
655 |
+ stats->db_version = malloc(p - pstart + 1); |
|
656 |
+ if (!stats->db_version) { |
|
657 |
+ fprintf(stderr, "Out of memory!\n"); |
|
658 |
+ exit(1); |
|
659 |
+ } |
|
660 |
+ memcpy(stats->db_version, pstart, p-pstart); |
|
661 |
+ stats->db_version[p-pstart] = '\0'; |
|
662 |
+ if(*p) p++; |
|
663 |
+ if (!*p || !strptime(p,"%a %b %d %H:%M:%S %Y", &stats->db_time)) { |
|
664 |
+ memset(&stats->db_time, 0, sizeof(stats->db_time)); |
|
665 |
+ } |
|
666 |
+ } |
|
667 |
+ if (maxx > 61 && strlen(stats->db_version) > (maxx-61)) { |
|
668 |
+ stats->db_version[maxx-61] = '\0'; |
|
669 |
+ } |
|
670 |
+ |
|
671 |
+ stats->version = conn->version; /* for details view */ |
|
529 | 672 |
gettimeofday(&tv, NULL); |
530 |
- tv.tv_sec -= tv_conn.tv_sec; |
|
531 |
- tv.tv_usec -= tv_conn.tv_usec; |
|
673 |
+ tv.tv_sec -= conn->tv_conn.tv_sec; |
|
674 |
+ tv.tv_usec -= conn->tv_conn.tv_usec; |
|
532 | 675 |
conn_dt = tv.tv_sec + tv.tv_usec/1e6; |
533 |
- mvwprintw(stats_head_window, i++, 0, "Connected since: %02u:%02u:%02u", |
|
534 |
- conn_dt/3600, (conn_dt/60)%60, conn_dt%60); |
|
676 |
+ |
|
677 |
+ stats->live = stats->idle = stats->max = 0; |
|
678 |
+ stats->conn_hr = conn_dt/3600; |
|
679 |
+ stats->conn_min = (conn_dt/60)%60; |
|
680 |
+ stats->conn_sec = conn_dt%60; |
|
681 |
+ |
|
535 | 682 |
while(recv_line(conn, buf, sizeof(buf)) && strcmp("END\n",buf) != 0) { |
536 | 683 |
char *val = strchr(buf, ':'); |
537 |
- if(i >= 4 && win == stats_head_window) { |
|
538 |
- win = stats_window; |
|
539 |
- i = 0; |
|
540 |
- } |
|
541 | 684 |
|
542 | 685 |
if(buf[0] == '\t') { |
543 |
- i = parse_queue(conn, i, buf, sizeof(buf)); |
|
686 |
+ parse_queue(conn, buf, sizeof(buf), idx); |
|
544 | 687 |
continue; |
545 | 688 |
} else if(val) |
546 | 689 |
*val++ = '\0'; |
547 | 690 |
if(!strcmp("MEMSTATS", buf)) { |
548 |
- output_memstats(val); |
|
691 |
+ parse_memstats(val, stats); |
|
549 | 692 |
continue; |
550 | 693 |
} |
551 | 694 |
for(j=1;j<strlen(buf);j++) |
552 | 695 |
buf[j] = tolower(buf[j]); |
553 |
- mvwprintw(win, i, 0, "%s", buf); |
|
696 |
+ /* mvwprintw(win, i, 0, "%s", buf); |
|
554 | 697 |
if(!val) { |
555 | 698 |
i++; |
556 | 699 |
continue; |
557 | 700 |
} |
558 | 701 |
waddch(win, ':'); |
559 | 702 |
print_colored(win, val); |
560 |
- i++; |
|
703 |
+ i++;*/ |
|
704 |
+ if(!strncmp("State",buf,5)) { |
|
705 |
+ if(strstr(val, "PRIMARY")) { |
|
706 |
+ /* primary thread pool */ |
|
707 |
+ primary = 1; |
|
708 |
+ } else { |
|
709 |
+ /* multiscan pool */ |
|
710 |
+ primary = 0; |
|
711 |
+ } |
|
712 |
+ } |
|
561 | 713 |
if(!strcmp("Threads",buf)) { |
562 | 714 |
unsigned live, idle, max; |
563 | 715 |
if(sscanf(val, " live %u idle %u max %u", &live, &idle, &max) != 3) |
564 | 716 |
continue; |
565 |
- show_bar(win, i++, live, idle, max, 0); |
|
717 |
+ if (primary) { |
|
718 |
+ stats->prim_live = live; |
|
719 |
+ stats->prim_idle = idle; |
|
720 |
+ assert(!stats->prim_max && "There can be only one primary pool!"); |
|
721 |
+ stats->prim_max = max; |
|
722 |
+ } |
|
723 |
+ stats->live += live; |
|
724 |
+ stats->idle += idle; |
|
725 |
+ stats->max += max; |
|
566 | 726 |
} else if (!strcmp("Queue",buf)) { |
567 |
- int blink = 0; |
|
568 | 727 |
unsigned len; |
569 | 728 |
if(sscanf(val, "%u", &len) != 1) |
570 | 729 |
continue; |
571 |
- if(len > biggest_queue) { |
|
572 |
- biggest_queue = len; |
|
573 |
- blink = 1; |
|
574 |
- } |
|
575 |
- show_bar(win, i++, len, 0, biggest_queue, blink); |
|
730 |
+ stats->current_q = len; |
|
576 | 731 |
} |
577 | 732 |
} |
578 |
- wrefresh(stats_head_window); |
|
579 |
- wrefresh(stats_window); |
|
580 | 733 |
} |
581 | 734 |
|
582 | 735 |
static void read_version(conn_t *conn) |
583 | 736 |
{ |
584 | 737 |
char buf[1024]; |
585 | 738 |
if(recv_line(conn, buf, sizeof(buf))) { |
586 |
- clamd_version = strdup(buf); |
|
739 |
+ conn->version = strdup(buf); |
|
587 | 740 |
} |
588 | 741 |
} |
589 | 742 |
|
590 |
-static conn_t conn; |
|
591 |
- |
|
592 |
-int main(int argc, char *argv[]) |
|
743 |
+/* -------------------------- Initialization ---------------- */ |
|
744 |
+static void setup_connections(int argc, char *argv[]) |
|
593 | 745 |
{ |
594 |
- int ch = 0, need_initwin=0; |
|
595 |
- fd_set rfds; |
|
596 |
- struct timeval tv_last, tv; |
|
597 |
- |
|
746 |
+ unsigned i; |
|
598 | 747 |
#ifdef _WIN32 |
599 | 748 |
WSADATA wsaData; |
600 | 749 |
if (WSAStartup(MAKEWORD(2,2), &wsaData) != NO_ERROR) { |
601 | 750 |
fprintf(stderr, "Error at WSAStartup(): %d\n", WSAGetLastError()); |
602 |
- exit(1); |
|
751 |
+ EXIT_PROGRAM(FAIL_INITIAL_CONN); |
|
603 | 752 |
} |
753 |
+#endif |
|
604 | 754 |
|
605 |
- if (make_connection(argc > 1 ? argv[1] : "localhost:3310", &conn) < 0) |
|
606 |
- exit(2); |
|
755 |
+ memset(&global, 0, sizeof(global)); |
|
756 |
+ if (argc == 1) { |
|
757 |
+ global.num_clamd = 1; |
|
758 |
+#ifdef _WIN32 |
|
759 |
+ argv[1] = "localhost:3310"; |
|
607 | 760 |
#else |
608 |
- /* TODO: parse clamd.conf */ |
|
609 |
- if (make_connection(argc > 1 ? argv[1] : "/tmp/clamd.socket", &conn) < 0) |
|
610 |
- exit(2); |
|
761 |
+ argv[1] = "/tmp/clamd.socket"; |
|
762 |
+#endif |
|
763 |
+ } else |
|
764 |
+ global.num_clamd = argc-1; |
|
765 |
+ global.all_stats = calloc(global.num_clamd, sizeof(*global.all_stats)); |
|
766 |
+ OOM_CHECK(global.all_stats); |
|
767 |
+ global.conn = calloc(global.num_clamd, sizeof(*global.conn)); |
|
768 |
+ OOM_CHECK(global.conn); |
|
769 |
+ for (i=0;i<global.num_clamd;i++) { |
|
770 |
+ if (make_connection(argv[i+1], &global.conn[i]) < 0) { |
|
771 |
+ EXIT_PROGRAM(FAIL_INITIAL_CONN); |
|
772 |
+ } |
|
611 | 773 |
|
774 |
+ } |
|
775 |
+#ifndef _WIN32 |
|
612 | 776 |
signal(SIGPIPE, SIG_IGN); |
613 | 777 |
#endif |
778 |
+} |
|
779 |
+ |
|
780 |
+static void free_global_stats(void) |
|
781 |
+{ |
|
782 |
+ unsigned i; |
|
783 |
+ for (i=0;i<global.n;i++) { |
|
784 |
+ free(global.tasks[i].line); |
|
785 |
+ } |
|
786 |
+ for (i=0;i<global.num_clamd;i++) { |
|
787 |
+ free(global.all_stats[i].engine_version); |
|
788 |
+ free(global.all_stats[i].db_version); |
|
789 |
+ } |
|
790 |
+ free(global.tasks); |
|
791 |
+ global.tasks = NULL; |
|
792 |
+ global.n=0; |
|
793 |
+} |
|
794 |
+ |
|
795 |
+int main(int argc, char *argv[]) |
|
796 |
+{ |
|
797 |
+ int ch = 0; |
|
798 |
+ struct timeval tv_last, tv; |
|
799 |
+ unsigned i; |
|
800 |
+ |
|
801 |
+ atexit(cleanup); |
|
802 |
+ setup_connections(argc, argv); |
|
614 | 803 |
|
615 |
- gettimeofday(&tv_conn, NULL); |
|
616 |
- send_string(&conn, "SESSION\nVERSION\n"); |
|
617 |
- read_version(&conn); |
|
618 |
- init_ncurses(); |
|
804 |
+ init_ncurses(global.num_clamd); |
|
619 | 805 |
|
620 |
- FD_ZERO(&rfds); |
|
621 |
- FD_SET(0, &rfds); |
|
622 | 806 |
memset(&tv_last, 0, sizeof(tv_last)); |
623 | 807 |
do { |
624 | 808 |
if(ch == KEY_RESIZE) { |
625 | 809 |
resize(); |
626 | 810 |
endwin(); |
627 | 811 |
refresh(); |
628 |
- need_initwin = 1; |
|
812 |
+ init_windows(global.num_clamd); |
|
629 | 813 |
} |
630 | 814 |
if(ch == 'R') { |
631 | 815 |
biggest_queue = 1; |
632 | 816 |
biggest_mem = 0; |
633 | 817 |
} |
634 | 818 |
gettimeofday(&tv, NULL); |
819 |
+ header(); |
|
635 | 820 |
if(tv.tv_sec - tv_last.tv_sec >= MIN_INTERVAL) { |
636 |
- if(need_initwin) { |
|
637 |
- init_windows(); |
|
638 |
- need_initwin = 0; |
|
821 |
+ free_global_stats(); |
|
822 |
+ for(i=0;i<global.num_clamd;i++) { |
|
823 |
+ struct stats *stats = &global.all_stats[i]; |
|
824 |
+ send_string(&global.conn[i], "STATS\n"); |
|
825 |
+ memset(stats, 0, sizeof(*stats)); |
|
826 |
+ parse_stats(&global.conn[i], stats, i); |
|
639 | 827 |
} |
640 |
- send_string(&conn, "STATS\n"); |
|
641 |
- header(); |
|
642 |
- parse_stats(&conn); |
|
828 |
+ assert(global.tasks); |
|
829 |
+ qsort(global.tasks, global.n, sizeof(*global.tasks), tasks_compare); |
|
643 | 830 |
tv_last = tv; |
644 | 831 |
} |
832 |
+ /* always show, so that screen resizes take effect instantly*/ |
|
833 |
+ output_all(); |
|
645 | 834 |
} while(toupper(ch = getch()) != 'Q'); |
646 |
- send_string(&conn, "END\n"); |
|
647 |
- close(conn.sd); |
|
648 |
- free(clamd_version); |
|
835 |
+ free_global_stats(); |
|
649 | 836 |
normal_exit = 1; |
650 | 837 |
return 0; |
651 | 838 |
} |