PageRenderTime 24ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/multitail-5.2.8/misc.c

#
C | 547 lines | 463 code | 74 blank | 10 comment | 138 complexity | 17720312a3c0dca5f7eaecae3c3cf264 MD5 | raw file
Possible License(s): AGPL-1.0
  1. #define _LARGEFILE64_SOURCE /* required for GLIBC to enable stat64 and friends */
  2. #include <sys/types.h>
  3. #include <regex.h>
  4. #include <sys/utsname.h>
  5. #include <string.h>
  6. #include <math.h>
  7. #include <time.h>
  8. #include <stdlib.h>
  9. #include <ctype.h>
  10. #include <errno.h>
  11. #include <sys/stat.h>
  12. #include <unistd.h>
  13. #include <time.h>
  14. #include <sys/time.h>
  15. #include <sys/resource.h>
  16. #include <sys/socket.h>
  17. #include <netinet/in.h>
  18. #include "mt.h"
  19. #include "term.h"
  20. #include "utils.h"
  21. #include "error.h"
  22. #include "mem.h"
  23. #include "help.h"
  24. #include "globals.h"
  25. #include "ui.h"
  26. void info(void)
  27. {
  28. NEWWIN *mywin = create_popup(19, 60);
  29. int line = 7;
  30. struct utsname uinfo;
  31. int proc_u_line;
  32. char *term = getenv("TERM");
  33. mvwprintw(mywin -> win, 1, 2, "-=* MultiTail " VERSION " *=-");
  34. mvwprintw(mywin -> win, 3, 2, "Written by folkert@vanheusden.com");
  35. mvwprintw(mywin -> win, 4, 2, "Website: http://www.vanheusden.com/multitail/");
  36. if (!use_colors)
  37. mvwprintw(mywin -> win, line++, 2, "Your terminal doesn't support colors");
  38. if (uname(&uinfo) == -1)
  39. error_popup("Retrieving system information", -1, "uname() failed\n");
  40. else
  41. {
  42. line++;
  43. mvwprintw(mywin -> win, line++, 2, "Running on:");
  44. #ifdef _GNU_SOURCE
  45. mvwprintw(mywin -> win, line++, 2, "%s/%s %s %s", uinfo.nodename, uinfo.sysname, uinfo.machine, uinfo.domainname);
  46. #else
  47. mvwprintw(mywin -> win, line++, 2, "%s/%s %s", uinfo.nodename, uinfo.sysname, uinfo.machine);
  48. #endif
  49. mvwprintw(mywin -> win, line++, 2, "%s %s", uinfo.release, uinfo.version);
  50. line++;
  51. }
  52. if (has_colors())
  53. mvwprintw(mywin -> win, line++, 2, "colors: %d, colorpairs: %d (%d), change colors: %s", COLORS, COLOR_PAIRS, cp.n_def, can_change_color()?"yes":"no");
  54. else
  55. mvwprintw(mywin -> win, line++, 2, "Terminal does not support colors.");
  56. if (term)
  57. mvwprintw(mywin -> win, line++, 2, "Terminal size: %dx%d, terminal: %s", max_x, max_y, term);
  58. else
  59. mvwprintw(mywin -> win, line++, 2, "Terminal size: %dx%d", max_x, max_y);
  60. if (beep_interval > 0)
  61. mvwprintw(mywin -> win, line++, 2, "Did %d beeps.", did_n_beeps);
  62. proc_u_line = line++;
  63. escape_print(mywin, 16, 2, "_Press any key to exit this screen_");
  64. #if defined(__FreeBSD__) || defined(linux) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) || defined(sun) || defined(__sun) || defined(__GNU__) || defined(__CYGWIN__)
  65. for(;;)
  66. {
  67. dtime_t run_time = get_ts() - mt_started;
  68. #ifndef __CYGWIN__
  69. double v1, v2, v3;
  70. get_load_values(&v1, &v2, &v3);
  71. mvwprintw(mywin -> win, 6, 2, "Current load of system: %f %f %f", v1, v2, v3);
  72. #endif
  73. if (run_time)
  74. {
  75. struct rusage usage;
  76. if (getrusage(RUSAGE_SELF, &usage) == -1)
  77. error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "getrusage() failed\n");
  78. mvwprintw(mywin -> win, proc_u_line, 2, "Runtime: %02d:%02d:%02d, avg.proc.usage: %.2f%% ints/s: %.1f",
  79. (int)(run_time / 3600), ((int)run_time / 60) % 60, (int)run_time % 60,
  80. ((double)usage.ru_utime.tv_sec + (double)usage.ru_utime.tv_usec / 1000000.0 +
  81. (double)usage.ru_stime.tv_sec + (double)usage.ru_stime.tv_usec / 1000000.0) * 100.0 / run_time,
  82. (double)total_wakeups / run_time);
  83. }
  84. mydoupdate();
  85. if (wait_for_keypress(-1, popup_refresh_interval, mywin, 0) != -1)
  86. break;
  87. }
  88. #else
  89. mydoupdate();
  90. wait_for_keypress(-1, 0, mywin, 0);
  91. #endif
  92. delete_popup(mywin);
  93. }
  94. void reset_counters(statistics_t *ps)
  95. {
  96. memset(ps, 0x0, sizeof(*ps));
  97. ps -> sccfirst = 1;
  98. }
  99. void statistics_popup(int f_index, proginfo *cur)
  100. {
  101. NEWWIN *popup = create_popup(16, 68);
  102. const char *title = "Statistics for ";
  103. char *abbr_fname = shorten_filename(cur -> filename, 54 - strlen(title));
  104. char buffer[54 + 1];
  105. snprintf(buffer, sizeof(buffer), "%s%s", title, abbr_fname);
  106. for(;;)
  107. {
  108. dtime_t time_running = get_ts() - cur -> statistics.start_ts;
  109. time_t start_ts = (time_t)cur -> statistics.start_ts;
  110. char *start_ts_str = mystrdup(ctime(&start_ts), __FILE__, __PRETTY_FUNCTION__, __LINE__);
  111. time_t lastevent = (time_t)cur -> statistics.lastevent;
  112. char *last_ts_str = mystrdup(ctime(&lastevent), __FILE__, __PRETTY_FUNCTION__, __LINE__);
  113. char *dummy;
  114. char *vmsize_str = NULL;
  115. char *fsize_str = NULL;
  116. char *total_data_processed_str = amount_to_str(cur -> statistics.bytes_processed);
  117. char *buffer_kb;
  118. off64_t fsize = -1;
  119. int c;
  120. int total_re = 0;
  121. int loop;
  122. if (cur -> wt == WT_COMMAND)
  123. {
  124. vmsize_str = amount_to_str(get_vmsize(cur -> pid));
  125. }
  126. else if (cur -> wt == WT_FILE)
  127. {
  128. (void)file_info(cur -> filename, &fsize, 0, NULL, NULL);
  129. fsize_str = amount_to_str(fsize);
  130. }
  131. dummy = strchr(start_ts_str, '\n');
  132. if (dummy) *dummy = 0x00;
  133. dummy = strchr(last_ts_str, '\n');
  134. if (dummy) *dummy = 0x00;
  135. werase(popup -> win);
  136. win_header(popup, buffer);
  137. ui_inverse_on(popup);
  138. mvwprintw(popup -> win, 3, 2, "# lines :");
  139. mvwprintw(popup -> win, 3, 27, "#l/s :");
  140. mvwprintw(popup -> win, 3, 44, "Avg len:");
  141. mvwprintw(popup -> win, 4, 2, "Data interval :");
  142. if (cur -> wt == WT_COMMAND)
  143. mvwprintw(popup -> win, 5, 2, "VM size :");
  144. else if (cur -> wt == WT_FILE)
  145. mvwprintw(popup -> win, 5, 2, "File size :");
  146. mvwprintw(popup -> win, 9, 2, "Data processed:");
  147. mvwprintw(popup -> win, 9, 27, "Bps :");
  148. mvwprintw(popup -> win, 6, 2, "Started at :");
  149. mvwprintw(popup -> win, 7, 2, "Last event :");
  150. mvwprintw(popup -> win, 8, 2, "Next expected@:");
  151. mvwprintw(popup -> win, 10, 2, "# matched r.e.:");
  152. mvwprintw(popup -> win, 11, 2, "Buffered lines:");
  153. mvwprintw(popup -> win, 11, 27, "Bytes:");
  154. mvwprintw(popup -> win, 11, 44, "Limit :");
  155. mvwprintw(popup -> win, 12, 2, "# of beeps: ");
  156. if (cur -> wt == WT_COMMAND)
  157. {
  158. mvwprintw(popup -> win, 13, 2, "Number of runs:");
  159. mvwprintw(popup -> win, 13, 27, "Last rc:");
  160. }
  161. ui_inverse_off(popup);
  162. mvwprintw(popup -> win, 3, 18, "%d", cur -> statistics.n_events);
  163. mvwprintw(popup -> win, 6, 18, "%s", start_ts_str);
  164. if (cur -> statistics.lastevent != (dtime_t)0.0)
  165. mvwprintw(popup -> win, 7, 18, "%s", last_ts_str);
  166. else
  167. mvwprintw(popup -> win, 7, 18, "---");
  168. if (cur -> statistics.n_events == 0)
  169. {
  170. mvwprintw(popup -> win, 4, 18, "Not yet available");
  171. }
  172. else
  173. {
  174. double avg = cur -> statistics.med / (double)cur -> statistics.n_events;
  175. double dev = sqrt((cur -> statistics.dev / (double)cur -> statistics.n_events) - pow(avg, 2.0));
  176. /* serial correlation coefficient */
  177. double scct1 = cur -> statistics.scct1 + cur -> statistics.scclast * cur -> statistics.sccu0;
  178. double med = cur -> statistics.med * cur -> statistics.med;
  179. double scc = (double)cur -> statistics.n_events * cur -> statistics.dev - med;
  180. if (scc != 0.0)
  181. {
  182. scc = ((double)cur -> statistics.n_events * scct1 - med) / scc;
  183. mvwprintw(popup -> win, 4, 18, "average: %.2f, std.dev.: %.2f, SCC: %1.6f", avg, dev, scc);
  184. }
  185. else
  186. mvwprintw(popup -> win, 4, 18, "average: %.2f, std.dev.: %.2f, not correlated", avg, dev);
  187. if (avg)
  188. {
  189. double dummy_d = (double)(time(NULL) - cur -> statistics.lastevent) / avg;
  190. time_t next_event = cur -> statistics.lastevent + (ceil(dummy_d) * avg);
  191. char *ne_str = mystrdup(ctime(&next_event), __FILE__, __PRETTY_FUNCTION__, __LINE__);
  192. char *dummy_str = strchr(ne_str, '\n');
  193. if (dummy_str) *dummy_str = 0x00;
  194. mvwprintw(popup -> win, 8, 18, "%s", ne_str);
  195. myfree(ne_str);
  196. }
  197. mvwprintw(popup -> win, 3, 53, "%.1f", (double)cur -> statistics.bytes_processed / (double)cur -> statistics.n_events);
  198. }
  199. if (cur -> wt == WT_COMMAND)
  200. mvwprintw(popup -> win, 5, 18, "%s", vmsize_str);
  201. else if (cur -> wt == WT_STDIN || cur -> wt == WT_SOCKET)
  202. mvwprintw(popup -> win, 5, 18, "n.a.");
  203. else if (cur -> wt == WT_FILE)
  204. mvwprintw(popup -> win, 5, 18, "%s", fsize_str);
  205. myfree(vmsize_str);
  206. myfree(fsize_str);
  207. mvwprintw(popup -> win, 9, 18, "%s", total_data_processed_str);
  208. myfree(total_data_processed_str);
  209. if (time_running > 0)
  210. {
  211. char *bps_str = amount_to_str((double)cur -> statistics.bytes_processed / (double)time_running);
  212. mvwprintw(popup -> win, 9, 34, "%s", bps_str);
  213. myfree(bps_str);
  214. mvwprintw(popup -> win, 3, 34, "%.4f", (double)cur -> statistics.n_events / (double)time_running);
  215. }
  216. buffer_kb = amount_to_str(lb[f_index].curbytes);
  217. mvwprintw(popup -> win, 11, 18, "%d", lb[f_index].curpos);
  218. mvwprintw(popup -> win, 11, 34, "%s", buffer_kb);
  219. myfree(buffer_kb);
  220. mvwprintw(popup -> win, 12, 18, "%d", cur -> beep.did_n_beeps);
  221. escape_print(popup, 14, 2, "Press ^r^ to reset counters, ^q^ to exit");
  222. myfree(start_ts_str);
  223. myfree(last_ts_str);
  224. for(loop=0; loop<cur -> n_re; loop++)
  225. total_re += (cur -> pre)[loop].match_count;
  226. if (cur -> statistics.n_events)
  227. mvwprintw(popup -> win, 10, 18, "%d (%.2f%%)", total_re, (total_re * 100.0) / (double)cur -> statistics.n_events);
  228. else
  229. mvwprintw(popup -> win, 10, 18, "%d", total_re);
  230. if (cur -> wt == WT_COMMAND)
  231. {
  232. mvwprintw(popup -> win, 13, 18, "%d", cur -> n_runs);
  233. mvwprintw(popup -> win, 13, 36, "%d", cur -> last_exit_rc);
  234. }
  235. if (lb[f_index].maxnlines > 0)
  236. {
  237. mvwprintw(popup -> win, 11, 53, "%d lines", lb[f_index].maxnlines);
  238. }
  239. else if (lb[f_index].maxbytes > 0)
  240. {
  241. char *str = amount_to_str(lb[f_index].maxbytes);
  242. mvwprintw(popup -> win, 11, 53, "%s", str);
  243. myfree(str);
  244. }
  245. draw_border(popup);
  246. mydoupdate();
  247. c = toupper(wait_for_keypress(HELP_STATISTICS_POPUP, popup_refresh_interval, popup, 0));
  248. if (c == 'Q' || c == abort_key)
  249. {
  250. break;
  251. }
  252. else if (c == 'R')
  253. {
  254. reset_counters(&cur -> statistics);
  255. }
  256. else if (c != -1)
  257. {
  258. wrong_key();
  259. }
  260. }
  261. delete_popup(popup);
  262. }
  263. void statistics_menu(void)
  264. {
  265. NEWWIN *mywin = create_popup(23, 65);
  266. int offset = 0, cur_line = 0;
  267. for(;;)
  268. {
  269. int c;
  270. int vmsize = get_vmsize(getpid());
  271. time_t now = time(NULL);
  272. struct tm *tmnow = localtime(&now);
  273. proginfo **plist = NULL;
  274. char *issub = NULL;
  275. int *winnr = NULL;
  276. int loop, nwin = 0;
  277. /* create list of (sub-)windows */
  278. for(loop=0; loop<nfd; loop++)
  279. {
  280. proginfo *cur = &pi[loop];
  281. while(cur)
  282. {
  283. plist = (proginfo **)myrealloc(plist, (nwin + 1) * sizeof(proginfo *), __FILE__, __PRETTY_FUNCTION__, __LINE__);
  284. issub = (char *) myrealloc(issub, (nwin + 1) * sizeof(char) , __FILE__, __PRETTY_FUNCTION__, __LINE__);
  285. winnr = (int *) myrealloc(winnr, (nwin + 1) * sizeof(int) , __FILE__, __PRETTY_FUNCTION__, __LINE__);
  286. plist[nwin] = cur;
  287. issub[nwin] = (cur != &pi[loop]);
  288. winnr[nwin] = loop;
  289. nwin++;
  290. cur = cur -> next;
  291. }
  292. }
  293. werase(mywin -> win);
  294. win_header(mywin, "Statistics");
  295. for(loop=0; loop<18; loop++)
  296. {
  297. int cur_index = loop + offset;
  298. int is_sub_indent;
  299. if (cur_index >= nwin) break;
  300. is_sub_indent = issub[cur_index];
  301. if (loop == cur_line) ui_inverse_on(mywin);
  302. if (is_sub_indent)
  303. mvwprintw(mywin -> win, 2 + loop, 7, "%s", shorten_filename(plist[cur_index] -> filename, 54));
  304. else
  305. mvwprintw(mywin -> win, 2 + loop, 2, "[%02d] %s", winnr[cur_index], shorten_filename(plist[cur_index] -> filename, 56));
  306. if (loop == cur_line) ui_inverse_off(mywin);
  307. }
  308. mvwprintw(mywin -> win, 20, 2, "Run-time: %.2f hours %02d:%02d", (get_ts() - mt_started) / 3600.0, tmnow -> tm_hour, tmnow -> tm_min);
  309. if (vmsize != -1)
  310. {
  311. char *vmsize_str = amount_to_str(vmsize);
  312. mvwprintw(mywin -> win, 20, 35, "Memory usage: %s", vmsize_str);
  313. myfree(vmsize_str);
  314. }
  315. escape_print(mywin, 21, 2, "Press ^r^ to reset counters, ^q^ to exit");
  316. draw_border(mywin);
  317. mydoupdate();
  318. c = toupper(wait_for_keypress(HELP_STATISTICS, popup_refresh_interval, mywin, 1));
  319. if (c == 'R')
  320. {
  321. for(loop=0; loop<nfd; loop++)
  322. {
  323. proginfo *cur = &pi[loop];
  324. while(cur)
  325. {
  326. reset_counters(&cur -> statistics);
  327. cur = cur -> next;
  328. }
  329. }
  330. }
  331. else if (c == KEY_UP)
  332. {
  333. if (cur_line)
  334. cur_line--;
  335. else if (offset)
  336. offset--;
  337. else
  338. wrong_key();
  339. }
  340. else if (c == KEY_DOWN)
  341. {
  342. if ((cur_line + offset) < (nwin - 1))
  343. {
  344. if (cur_line < (18 - 1))
  345. cur_line++;
  346. else
  347. offset++;
  348. }
  349. else
  350. wrong_key();
  351. }
  352. else if (c == 13 || c == ' ')
  353. {
  354. statistics_popup(winnr[cur_line + offset], plist[cur_line + offset]);
  355. }
  356. else if (c == 'Q' || c == abort_key)
  357. {
  358. myfree(plist);
  359. myfree(issub);
  360. myfree(winnr);
  361. break;
  362. }
  363. else if (c != -1)
  364. {
  365. wrong_key();
  366. }
  367. myfree(plist);
  368. myfree(issub);
  369. myfree(winnr);
  370. }
  371. delete_popup(mywin);
  372. }
  373. void heartbeat(void)
  374. {
  375. time_t now = time(NULL);
  376. struct tm *ptm = localtime(&now);
  377. static int x = 0, y = 0, dx = 1, dy = 1;
  378. static NEWWIN *hb_win = NULL;
  379. x += dx;
  380. y += dy;
  381. if (x >= (max_x - 8))
  382. {
  383. dx = -(myrand(1) + 1);
  384. x = max_x - (8 + 1);
  385. }
  386. else if (x < 0)
  387. {
  388. dx = (myrand(2) + 1);
  389. x = 0;
  390. }
  391. if (y >= max_y)
  392. {
  393. dy = -(myrand(2) + 1);
  394. y = max_y - 1;
  395. }
  396. else if (y < 0)
  397. {
  398. dy = (myrand(2) + 1);
  399. y = 0;
  400. }
  401. if (dx == 0 && dy == 0)
  402. {
  403. dy = 1;
  404. dy = -1;
  405. }
  406. if (!hb_win)
  407. {
  408. hb_win = create_popup(1, 8);
  409. }
  410. move_panel(hb_win -> pwin, y, x);
  411. ui_inverse_on(hb_win);
  412. mvwprintw(hb_win -> win, 0, 0, "%02d:%02d:%02d", ptm -> tm_hour, ptm -> tm_min, ptm -> tm_sec);
  413. ui_inverse_off(hb_win);
  414. mydoupdate();
  415. }
  416. void do_check_for_mail(dtime_t now)
  417. {
  418. if (check_for_mail > 0 && mail_spool_file != NULL && (now - msf_last_check) >= check_for_mail)
  419. {
  420. /* get current filesize */
  421. if (stat64(mail_spool_file, &msf_info) == -1)
  422. {
  423. if (errno != ENOENT)
  424. {
  425. check_for_mail = 0;
  426. error_popup("Check for new e-mail", -1, "Error doing stat64() on file %s.\ne-Mail check disabled.\n", mail_spool_file);
  427. }
  428. }
  429. /* filesize changed? */
  430. if (msf_info.st_size != msf_prev_size)
  431. {
  432. /* file became bigger: new mail
  433. * if it became less, the file changed because
  434. * mail was deleted or so
  435. */
  436. if (msf_info.st_size > msf_prev_size)
  437. {
  438. mail = 1;
  439. redraw_statuslines();
  440. if (do_refresh != 2) do_refresh = 1;
  441. }
  442. msf_prev_size = msf_info.st_size;
  443. }
  444. msf_last_check = now;
  445. }
  446. }
  447. void store_statistics(proginfo *cur, dtime_t now)
  448. {
  449. if (cur -> statistics.lastevent)
  450. {
  451. dtime_t cur_deltat = now - cur -> statistics.lastevent;
  452. if (cur -> statistics.n_events == 1)
  453. {
  454. cur -> statistics.total_deltat += (cur_deltat - cur -> statistics.prev_deltat);
  455. cur -> statistics.prev_deltat = cur_deltat;
  456. }
  457. cur -> statistics.med += cur_deltat;
  458. cur -> statistics.dev += pow(cur_deltat, 2.0);
  459. cur -> statistics.n_events++;
  460. /* Update calculation of serial correlation coefficient */
  461. /* (also uses cur -> med/dev) */
  462. if (cur -> statistics.sccfirst)
  463. {
  464. cur -> statistics.sccfirst = 0;
  465. cur -> statistics.scclast = 0;
  466. cur -> statistics.sccu0 = cur_deltat;
  467. }
  468. else
  469. cur -> statistics.scct1 = cur -> statistics.scct1 + cur -> statistics.scclast * cur_deltat;
  470. cur -> statistics.scclast = cur_deltat;
  471. }
  472. cur -> statistics.lastevent = now;
  473. }