1 /*
2 **
3 ** Copyright (c) 2010-2017 The SquirrelMail Project Team
4 ** Copyright (c) 2002-2010 Dave McMurtrie
5 **
6 ** Licensed under the GNU GPL. For full terms see the file COPYING.
7 **
8 ** This file is part of SquirrelMail IMAP Proxy.
9 **
10 ** Facility:
11 **
12 ** pimpstat.c
13 **
14 ** Abstract:
15 **
16 ** Polling Imap Mail Proxy STATistical display tool.
17 **
18 ** Authors:
19 **
20 ** Dave McMurtrie <davemcmurtrie@hotmail.com>
21 **
22 ** Version:
23 **
24 ** $Id: pimpstat.c 14647 2017-01-27 20:53:57Z pdontthink $
25 **
26 ** Modification History:
27 **
28 ** $Log$
29 **
30 ** Revision 1.9 2006/02/17 01:42:37 dave64
31 ** Spelling correction (Connectsions) by Matt Selsky.
32 **
33 ** Revision 1.8 2005/06/15 12:11:36 dgm
34 ** Patch by Mathew Anderson to add -c flag and behavior.
35 **
36 ** Revision 1.7 2004/02/24 14:56:10 dgm
37 ** Added SELECT cache stuff.
38 **
39 ** Revision 1.6 2003/05/20 19:08:02 dgm
40 ** Comment changes only.
41 **
42 ** Revision 1.5 2003/05/15 11:33:22 dgm
43 ** Patch by Ken Murchison <ken@oceana.com> to clean up build process:
44 ** Conditionally include <sys/param.h> instead of defining MAXPATHLEN.
45 **
46 ** Revision 1.4 2003/05/13 11:41:02 dgm
47 ** Patches by Ken Murchison <ken@oceana.com> to clean up build process.
48 **
49 ** Revision 1.3 2003/01/27 13:49:36 dgm
50 ** Added patch by Frode Nordahl <frode@powertech.no> to allow
51 ** compilation on Linux platforms.
52 **
53 ** Revision 1.2 2002/12/17 14:24:11 dgm
54 ** Added support for global configuration structure.
55 **
56 ** Revision 1.1 2002/08/30 13:32:55 dgm
57 ** Initial revision
58 **
59 */
60
61
62 #include "imapproxy.h"
63 #include <errno.h>
64 #include <stdlib.h>
65 #include <string.h>
66 #include <sys/mman.h>
67 #include <sys/types.h>
68 #include <sys/stat.h>
69 #include <fcntl.h>
70 #include <curses.h>
71 #include <time.h>
72 #include <strings.h>
73 #include <signal.h>
74
75 #if HAVE_SYS_PARAM_H
76 #include <sys/param.h>
77 #endif
78
79 #if HAVE_UNISTD_H
80 #include <unistd.h>
81 #endif
82
83 #define DIGITS 11
84
85 extern WINDOW *stdscr;
86
87 static void Exit( int );
88 static void Handler();
89 static void Usage( void );
90
91
92 ProxyConfig_Struct PC_Struct;
93
94
95 /*++
96 * Function: Exit
97 *
98 * Purpose: Set the terminal back to normal and then exit
99 *
100 * Parameters: int -- exit code to be passed to exit()
101 *
102 * Returns: nada
103 *
104 * Authors: Dave McMurtrie <davemcmurtrie@hotmail.com>
105 *
106 * Notes:
107 *--
108 */
Exit(int ExitCode)109 static void Exit( int ExitCode )
110 {
111 clear();
112 refresh();
113 endwin();
114 exit( ExitCode );
115 }
116
117
118 /*++
119 * Function: Handler
120 *
121 * Purpose: SIGINT handler routine
122 *
123 * Parameters: nada
124 *
125 * Returns: nada
126 *
127 * Authors: Dave McMurtrie <davemcmurtrie@hotmail.com>
128 *
129 * Notes:
130 *--
131 */
Handler()132 static void Handler()
133 {
134 Exit( 0 );
135 }
136
137
138
main(int argc,char * argv[])139 int main( int argc, char *argv[] )
140 {
141 IMAPCounter_Struct *IMAPCount;
142 int fd;
143 char *fn = "pimpstat";
144 int i, command;
145 char ccc[DIGITS+1]; /* current client conns */
146 char pcc[DIGITS+1]; /* peak client conns */
147 char asc[DIGITS+1]; /* active server conns */
148 char psc[DIGITS+1]; /* peak server conns */
149 char rsc[DIGITS+1]; /* retained (cached) server conns */
150 char prsc[DIGITS+1]; /* peak retained (cached) server conns */
151 char tcca[DIGITS+1]; /* total client connections accepted */
152 char tcl[DIGITS+1]; /* total client logins */
153 char tscc[DIGITS+1]; /* total server conns created */
154 char tscr[DIGITS+1]; /* total server conns reused */
155 char ssrr[DIGITS+4]; /* server socket reuse ration */
156 char tsch[DIGITS+1]; /* total select cache hits */
157 char tscm[DIGITS+1]; /* total select cache misses */
158 float Ratio;
159 char stimebuf[64];
160 char ctimebuf[64];
161 char *CP;
162 extern char *optarg;
163 extern int optind;
164 char ConfigFile[ MAXPATHLEN ];
165
166 ConfigFile[0] = '\0';
167
168 signal( SIGINT, (void (*)()) Handler );
169
170 command = 0;
171
172 while (( i = getopt( argc, argv, "f:ch" ) ) != EOF )
173 {
174
175 switch( i )
176 {
177
178 case 'f':
179 /* user specified a config filename */
180 strncpy( ConfigFile, optarg, sizeof ConfigFile -1 );
181 break;
182
183 case 'c':
184 /* user wants output via command line */
185 command=1;
186 break;
187
188 case 'h':
189 Usage();
190 exit( 0 );
191
192 case '?':
193 Usage();
194
195 exit( 1 );
196
197 }
198
199 }
200
201 if ( ! ConfigFile[0] )
202 {
203
204 strncpy( ConfigFile, DEFAULT_CONFIG_FILE, sizeof ConfigFile -1 );
205 }
206
207 SetConfigOptions( ConfigFile );
208
209 fd = open( PC_Struct.stat_filename, O_RDONLY );
210 if ( fd == -1 )
211 {
212 printf("%s: open() failed for '%s': %s -- Exiting.\n", fn,
213 PC_Struct.stat_filename, strerror( errno ) );
214 exit( 1 );
215 }
216
217
218 IMAPCount = ( IMAPCounter_Struct *)mmap( 0, sizeof( IMAPCounter_Struct ),
219 PROT_READ, MAP_SHARED, fd, 0 );
220
221 if ( IMAPCount == MAP_FAILED )
222 {
223 printf("%s: mmap() failed: %s -- Exiting.\n", fn, strerror( errno ) );
224 exit( 1 );
225 }
226
227
228 if ( command == 0 )
229 {
230 stdscr = initscr();
231
232 if ( !stdscr )
233 {
234 printf("%s: failed to initialize screen -- exiting.\n", fn );
235 exit( 1 );
236 }
237
238 border( 0, 0, 0, 0, 0, 0, 0, 0 );
239 mvaddstr( 2, 8, "Server Start Time:" );
240 mvaddstr( 3, 2, "Last Counter Reset Time:" );
241 mvaddstr( 5, 2, "CLIENT CONNECTIONS" );
242 mvaddstr( 7, 5, "current:" );
243 mvaddstr( 7, 40, "peak:" );
244 mvaddstr( 9, 2, "ACTIVE SERVER CONNECTIONS" );
245 mvaddstr( 11, 5, "current:" );
246 mvaddstr( 11, 40, "peak:" );
247 mvaddstr( 13, 2, "CACHED SERVER CONNECTIONS" );
248 mvaddstr( 15, 5, "current:");
249 mvaddstr( 15, 40, "peak:" );
250 mvaddstr( 17, 2, "CONNECTION TOTALS" );
251 mvaddstr( 19, 5, "client connections accepted:" );
252 mvaddstr( 20, 5, "client logins:" );
253 mvaddstr( 21, 5, "server connections created:" );
254 mvaddstr( 22, 5, "server connection reuses:" );
255 mvaddstr( 23, 5, "client login to server login ratio:" );
256 if ( PC_Struct.enable_select_cache )
257 {
258 mvaddstr( 25, 2, "SELECT CACHE TOTALS" );
259 mvaddstr( 27, 5, "hit:" );
260 mvaddstr( 27, 40, "miss:" );
261 }
262 else
263 {
264 mvaddstr( 25, 2, "SELECT CACHE NOT ENABLED" );
265 }
266
267 mvaddstr( 29, 2, "CTRL-C to quit." );
268
269 for ( ; ; )
270 {
271 /*
272 * I don't know crap about curses. There's prolly an easy way to
273 * accomplish this, but I don't know how. Basically we have to
274 * turn all of our numbers into strings so curses can display them.
275 * I'd guess there's a printf equivalent in curses, but I dunno.
276 */
277
278 if ( IMAPCount->TotalServerConnectionsCreated == 0 )
279 {
280 snprintf( ssrr, DIGITS + 3, " N/A" );
281 }
282 else
283 {
284 Ratio = (float)IMAPCount->TotalClientLogins /
285 (float)IMAPCount->TotalServerConnectionsCreated;
286 snprintf( ssrr, DIGITS + 3, "%9.2f : 1", Ratio );
287 }
288
289 /*
290 * ctime is putting a \n at the end of the string and that's
291 * making curses do goofy stuff that I don't understand. Rather
292 * than figure out why it's breaking curses, I'm just going to
293 * copy ctime's strings into my own buffers and get rid of the
294 * \n.
295 */
296 strncpy( stimebuf, ctime( &IMAPCount->StartTime ),
297 sizeof stimebuf - 1 );
298 strncpy( ctimebuf, ctime( &IMAPCount->CountTime ),
299 sizeof ctimebuf - 1 );
300
301 CP = strrchr( stimebuf, '\n' );
302 if (CP)
303 *CP = '\0';
304
305 CP = strrchr( ctimebuf, '\n' );
306 if (CP)
307 *CP ='\0';
308
309 snprintf( ccc, DIGITS, "%9d", IMAPCount->CurrentClientConnections );
310 snprintf( pcc, DIGITS, "%9d", IMAPCount->PeakClientConnections );
311 snprintf( asc, DIGITS, "%9d", IMAPCount->InUseServerConnections );
312 snprintf( psc, DIGITS, "%9d", IMAPCount->PeakInUseServerConnections );
313 snprintf( rsc, DIGITS, "%9d", IMAPCount->RetainedServerConnections );
314 snprintf( prsc, DIGITS, "%9d", IMAPCount->PeakRetainedServerConnections );
315 snprintf( tcca, DIGITS, "%9d", IMAPCount->TotalClientConnectionsAccepted );
316 snprintf( tcl, DIGITS, "%9d", IMAPCount->TotalClientLogins );
317 snprintf( tscr, DIGITS, "%9d", IMAPCount->TotalServerConnectionsReused );
318 snprintf( tscc, DIGITS, "%9d", IMAPCount->TotalServerConnectionsCreated );
319 snprintf( tsch, DIGITS, "%9d", IMAPCount->SelectCacheHits );
320 snprintf( tscm, DIGITS, "%9d", IMAPCount->SelectCacheMisses );
321
322 mvaddstr( 2, 31, stimebuf );
323 mvaddstr( 3, 31, ctimebuf );
324 mvaddstr( 7, 14, ccc );
325 mvaddstr( 7, 46, pcc );
326 mvaddstr( 11, 14, asc );
327 mvaddstr( 11, 46, psc );
328 mvaddstr( 15, 14, rsc );
329 mvaddstr( 15, 46, prsc );
330 mvaddstr( 19, 46, tcca );
331 mvaddstr( 20, 46, tcl );
332 mvaddstr( 21, 46, tscc );
333 mvaddstr( 22, 46, tscr );
334 mvaddstr( 23, 42, ssrr );
335 if ( PC_Struct.enable_select_cache )
336 {
337 mvaddstr( 27, 14, tsch );
338 mvaddstr( 27, 46, tscm );
339 }
340
341 refresh();
342
343 sleep( 1 );
344 }
345
346 }
347 else
348 {
349 /*
350 * We only get here if command is non-zero.
351 */
352 printf( " %d Current Client Connections\n %d Peak Client Connections\n %d In Use Connections\n %d Peak In Use Connections\n %d Retained Server Connections\n %d Peak Retained Server Connections\n %d Total Client Connections\n %d Total Client Logins\n %d Total Reused Connections\n %d Total Created Connections\n %d Cache Hits\n %d Cache Misses\n", IMAPCount->CurrentClientConnections,
353 IMAPCount->PeakClientConnections,
354 IMAPCount->InUseServerConnections,
355 IMAPCount->PeakInUseServerConnections,
356 IMAPCount->RetainedServerConnections,
357 IMAPCount->PeakRetainedServerConnections,
358 IMAPCount->TotalClientConnectionsAccepted,
359 IMAPCount->TotalClientLogins,
360 IMAPCount->TotalServerConnectionsReused,
361 IMAPCount->TotalServerConnectionsCreated,
362 IMAPCount->SelectCacheHits,
363 IMAPCount->SelectCacheMisses );
364
365 exit( 0 );
366 }
367 }
368
369
370
371 /*++
372 * Function: Usage
373 *
374 * Purpose: Display a usage string to stdout
375 *
376 * Parameters: None.
377 *
378 * Returns: nada
379 *
380 * Authors: Dave McMurtrie <davemcmurtrie@hotmail.com>
381 *
382 * Notes:
383 *--
384 */
Usage(void)385 void Usage( void )
386 {
387 printf( "Usage: pimpstat [-f config filename] [-h] [-c]\n" );
388 printf( " -c is for simple command line output format instead of curses.\n" );
389
390 return;
391 }
392
393 /*
394 * _________
395 * / |
396 * / |
397 * / ______|
398 * / / ________
399 * | | | /
400 * | | |_____/
401 * | | ______
402 * | | | \
403 * | | |______\
404 * \ \_______
405 * \ |
406 * \ |
407 * \_________|
408 */
409
410
411