timed tail for logfiles. Display loglines given a minimum date and/or a maximum date.
c
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ttail_init.c 9.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. #include "ttail_init.h"
  2. void usage()
  3. {
  4. static struct option opts[] = TTAIL_LONG_OPT;
  5. static char *help[][2] = TTAIL_OPT_HELP;
  6. size_t i;
  7. printf("Usage : ttail -d DATE [OPTIONS]\n");
  8. printf("\t\n");
  9. printf("Options list\n");
  10. i=0;
  11. while(opts[i].name)
  12. {
  13. printf("\t-%c, --%s", opts[i].val, opts[i].name);
  14. if(opts[i].has_arg == required_argument)
  15. {
  16. printf("=%s\n",
  17. help[i][1]?help[i][1]:"ARG");
  18. }
  19. else if(opts[i].has_arg == optional_argument)
  20. {
  21. printf("[=%s]\n",
  22. help[i][1]?help[i][1]:"ARG");
  23. }
  24. else
  25. {
  26. printf("\n");
  27. }
  28. printf("\t\t%s\n\n", help[i][0]);
  29. i++;
  30. }
  31. }
  32. ttail_t *ttail_init(int argc, char **argv)
  33. {
  34. ttail_t *res;
  35. int c, opt_i, ret;
  36. char *dates[2] = { NULL, NULL };
  37. char *date;
  38. res = malloc(sizeof(ttail_t));
  39. if(!res)
  40. {
  41. perror("Unable to allocate memory");
  42. goto ttail_init_alloc_err;
  43. }
  44. opterr = 0;
  45. optind = 0;
  46. res->verbose = 0;
  47. res->fmt = NULL;
  48. res->flag = 0;
  49. res->logfile = NULL;
  50. res->logfile_name = NULL;
  51. res->logfile_sz = 0;
  52. res->prefix_sz = -1;
  53. res->session = NULL;
  54. memset(&(res->date_min), 0, sizeof(struct tm));
  55. memset(&(res->date_max), 0, sizeof(struct tm));
  56. while(1)
  57. {
  58. static struct option long_options[] = TTAIL_LONG_OPT;
  59. c = getopt_long(argc, argv, TTAIL_SHORT_OPT, long_options, &opt_i);
  60. if(c == -1)
  61. break;
  62. switch(c)
  63. {
  64. case 'v':
  65. res->verbose++;
  66. break;
  67. case 'r':
  68. if(ttail_set_prefix(res, optarg))
  69. {
  70. goto ttail_init_err;
  71. }
  72. break;
  73. case 'p':
  74. if(res->flag & TTAIL_FLAG_PREFIX)
  75. {
  76. fprintf(stderr, "Preffix allready \
  77. set\n");
  78. goto ttail_init_err;
  79. }
  80. res->flag |= TTAIL_FLAG_PREFIX;
  81. res->prefix_sz = atoi(optarg);
  82. if(res->prefix_sz <= 0)
  83. {
  84. fprintf(stderr, "Prefix size have \
  85. to be > 0");
  86. goto ttail_init_err;
  87. }
  88. break;
  89. case 'E':
  90. if(ttail_set_flag_re_ex(res) < 0)
  91. {
  92. goto ttail_init_err;
  93. }
  94. break;
  95. case 'I':
  96. if(ttail_set_flag_re_ci(res) < 0)
  97. {
  98. goto ttail_init_err;
  99. }
  100. break;
  101. case 'f':
  102. if(res->flag & TTAIL_FLAG_FORMAT)
  103. {
  104. fprintf(stderr,"Multiple date format \
  105. given\n");
  106. goto ttail_init_err;
  107. }
  108. if(ttail_set_fmt(res, optarg) < 0)
  109. {
  110. goto ttail_init_err;
  111. }
  112. break;
  113. case 'l':
  114. ret = ttail_add_logfile(res, optarg);
  115. if(ret < 0)
  116. {
  117. goto ttail_init_err;
  118. }
  119. break;
  120. case 'd':
  121. case 'm':
  122. date = malloc(sizeof(char)*(strlen(optarg)+1));
  123. if(!date)
  124. {
  125. goto ttail_init_err;
  126. }
  127. strcpy(date, optarg);
  128. dates[c=='d'?0:1] = date;
  129. break;
  130. case '?':
  131. optind--;
  132. goto init_badarg;
  133. break;
  134. default:
  135. fprintf(stderr, "Bad argument\n");
  136. goto init_badarg;
  137. }
  138. }
  139. if(optind < argc)
  140. {
  141. init_badarg:
  142. fprintf(stderr, "bad option :");
  143. while(optind < argc)
  144. {
  145. fprintf(stderr, argv[optind++]);
  146. }
  147. fprintf(stderr, "\n");
  148. goto ttail_init_err;
  149. }
  150. if(ttail_set_dates(res, dates) < 0)
  151. {
  152. goto ttail_init_err;
  153. }
  154. return res;
  155. ttail_init_err:
  156. if(dates[0]) { free(dates[0]); }
  157. if(dates[1]) { free(dates[1]); }
  158. ttail_free(res);
  159. ttail_init_alloc_err:
  160. return NULL;
  161. }
  162. int ttail_init_check(ttail_t* t)
  163. {
  164. size_t i, ret;
  165. if(t->logfile_sz)
  166. {
  167. ret = 0;
  168. for(i=0; i<t->logfile_sz; i++)
  169. {
  170. if(t->logfile[i])
  171. {
  172. ret = 1;
  173. break;
  174. }
  175. }
  176. if(!ret)
  177. {
  178. fprintf(stderr, "Unable to read from any of the files \
  179. given as argument\n");
  180. return -1;
  181. }
  182. }
  183. if(t->flag & TTAIL_FLAG_DATE_MAX)
  184. {
  185. fprintf(stderr, "Warning : date-max not yet implemented\n");
  186. }
  187. if(!(t->flag & TTAIL_FLAG_DATE_MIN))
  188. {
  189. fprintf(stderr, "--date-min -d is mandatory\n");
  190. return -1;
  191. }
  192. if(!(t->flag & TTAIL_FLAG_FORMAT))
  193. {
  194. fprintf(stderr, "No date format set nor detected. Abording.\n");
  195. return -1;
  196. }
  197. else if(!t->fmt)
  198. {
  199. fprintf(stderr, "Date format flag set but no format found\n");
  200. return -1;
  201. }
  202. return 0;
  203. }
  204. int ttail_add_logfile(ttail_t* res, const char* filename)
  205. {
  206. void *tmp;
  207. FILE *fp;
  208. char *fname;
  209. int ret, i;
  210. for(i=0; i<res->logfile_sz; i++)
  211. {
  212. if(strcmp(filename, res->logfile_name[i]) == 0)
  213. {
  214. fprintf(stderr, "File '%s' allready added\n",
  215. filename);
  216. return -1;
  217. }
  218. }
  219. res->logfile_sz++;
  220. tmp = res->logfile;
  221. res->logfile = realloc(res->logfile,
  222. sizeof(FILE*)*res->logfile_sz);
  223. ret = 0;
  224. if(!res->logfile)
  225. {
  226. perror("Unable to allocate memory for logfiles");
  227. res->logfile = tmp;
  228. goto ttail_add_logfile_fpalloc_err;
  229. }
  230. fp = fopen(filename, "r");
  231. if(!fp)
  232. {
  233. fprintf(stderr, "Unable to open file : %s\n", filename);
  234. res->logfile[res->logfile_sz-1] = NULL;
  235. ret = 1;
  236. }
  237. res->logfile[res->logfile_sz-1] = fp;
  238. tmp = res->logfile_name;
  239. res->logfile_name = realloc(res->logfile_name,
  240. sizeof(char*)*res->logfile_sz);
  241. if(!res->logfile_name)
  242. {
  243. perror("Unable to allocate memory for logfiles");
  244. res->logfile_name = tmp;
  245. goto ttail_add_logfile_fnalloc_err;
  246. }
  247. fname = malloc(sizeof(char)*(strlen(filename)+1));
  248. if(!fname)
  249. {
  250. perror("Unable to allocate memory for logfiles");
  251. goto ttail_add_logfile_fnalloc_err;
  252. }
  253. strcpy(fname, filename);
  254. res->logfile_name[res->logfile_sz-1] = fname;
  255. return ret;
  256. ttail_add_logfile_fnalloc_err:
  257. fclose(res->logfile[res->logfile_sz-2]);
  258. ttail_add_logfile_fpalloc_err:
  259. res->logfile_sz--;
  260. return -1;
  261. }
  262. int ttail_set_prefix(ttail_t* res, const char* regex)
  263. {
  264. int ret, cflags;
  265. char *re_errbuff;
  266. size_t re_errbuff_sz;
  267. if(res->flag & TTAIL_FLAG_PREFIX)
  268. {
  269. fprintf(stderr, "Regex prefix allready set");
  270. return 1;
  271. }
  272. res->flag |= TTAIL_FLAG_PREFIX;
  273. cflags = 0; /** @todo checks */
  274. if(res->flag & TTAIL_FLAG_EXTENDED_RE)
  275. {
  276. cflags |= REG_EXTENDED;
  277. }
  278. if(res->flag & TTAIL_FLAG_CI_RE)
  279. {
  280. cflags |= REG_ICASE;
  281. }
  282. ret = regcomp(&res->date_prefix, regex, cflags);
  283. if(!ret)
  284. {
  285. return 0;
  286. }
  287. /*compilation error */
  288. res->flag ^= TTAIL_FLAG_PREFIX;
  289. re_errbuff_sz = regerror(ret,
  290. &res->date_prefix, NULL, 0);
  291. re_errbuff = malloc(
  292. sizeof(char)*re_errbuff_sz);
  293. if(!re_errbuff)
  294. {
  295. perror("Failed to allocate memory for regex compilation \
  296. error message");
  297. goto ttail_set_prefix_err;
  298. }
  299. regerror(ret, &res->date_prefix,
  300. re_errbuff,
  301. sizeof(char)*re_errbuff_sz);
  302. fprintf(stderr, "Regex compilation fails : %s", re_errbuff);
  303. free(re_errbuff);
  304. ttail_set_prefix_err:
  305. return -1;
  306. }
  307. int ttail_set_fmt(ttail_t* t, const char* fmt)
  308. {
  309. size_t len;
  310. if(t->flag & TTAIL_FLAG_FORMAT)
  311. {
  312. return -1;
  313. }
  314. len = strlen(fmt);
  315. t->fmt = malloc(sizeof(char)*(len+1));
  316. if(!t->fmt)
  317. {
  318. return -1;
  319. }
  320. strncpy(t->fmt, fmt, len);
  321. t->fmt[len] = '\0';
  322. t->flag |= TTAIL_FLAG_FORMAT;
  323. return 0;
  324. }
  325. /**@brief This function is used by bot @ref ttail_set_flag_re_ex() and
  326. *ttail_set_flag_re_ci() function
  327. *@param t ttail_t*
  328. *@return -1 on error else 0
  329. */
  330. static int _ttail_common_set_flag_re(ttail_t* ttail)
  331. {
  332. if(ttail->flag & TTAIL_FLAG_PREFIX)
  333. {
  334. fprintf(stderr, "Regex flags has to be set BEFORE the \
  335. prefix\n");
  336. return -1;
  337. }
  338. return 0;
  339. }
  340. int ttail_set_flag_re_ex(ttail_t* ttail)
  341. {
  342. if(_ttail_common_set_flag_re(ttail) < 0)
  343. {
  344. return -1;
  345. }
  346. ttail->flag |= TTAIL_FLAG_EXTENDED_RE;
  347. return 0;
  348. }
  349. int ttail_set_flag_re_ci(ttail_t* ttail)
  350. {
  351. if(_ttail_common_set_flag_re(ttail) < 0)
  352. {
  353. return -1;
  354. }
  355. ttail->flag |= TTAIL_FLAG_CI_RE;
  356. return 0;
  357. }
  358. int ttail_set_dates(ttail_t* res, char* dates[2])
  359. {
  360. int c, ret;
  361. char *date;
  362. for(c=0;c<2;c++)
  363. {
  364. memset(c==0?&(res->date_min):&(res->date_max), 0, \
  365. sizeof(struct tm));
  366. if(!dates[c])
  367. {
  368. continue;
  369. }
  370. if(!(res->flag & TTAIL_FLAG_FORMAT))
  371. {
  372. /* no format specified */
  373. ret = ttail_format_guess(res, dates[c],
  374. c==0?&(res->date_min):&(res->date_max));
  375. if(ret < 0)
  376. {
  377. fprintf(stderr, "Unable to guess format for \
  378. date '%s'\n", dates[c]);
  379. return -1;
  380. }
  381. res->flag |= c?TTAIL_FLAG_DATE_MAX:TTAIL_FLAG_DATE_MIN;
  382. continue;
  383. }
  384. date = strptime(dates[c], res->fmt,
  385. c==0?&(res->date_min):&(res->date_max));
  386. if(!date)
  387. {
  388. fprintf(stderr, "Unable to parse date-%s '%s' with \
  389. format '%s'\n", c==0?"min":"max", dates[c], res->fmt);
  390. return -1;
  391. }
  392. else if(*date != '\0')
  393. {
  394. fprintf(stderr, "Leading caracters for date-%s : %s\n",\
  395. c==0?"min":"max", date);
  396. }
  397. res->flag |= c?TTAIL_FLAG_DATE_MAX:TTAIL_FLAG_DATE_MIN;
  398. }
  399. if(dates[0]) { free(dates[0]); dates[0] = NULL; }
  400. if(dates[1]) { free(dates[1]); dates[1] = NULL; }
  401. return 0;
  402. }
  403. int ttail_format_guess(ttail_t* t, const char* date_str, struct tm* tm)
  404. {
  405. int i, res;
  406. char *res_ret, *ret;
  407. char *fmt[] = TTAIL_DEFAULT_FORMATS;
  408. struct tm dte;
  409. memset(&dte, 0, sizeof(struct tm));
  410. if(t->flag & TTAIL_FLAG_FORMAT)
  411. {
  412. fprintf(stderr, "Format allready set\n");
  413. return -2;
  414. }
  415. res = -1;
  416. res_ret = NULL;
  417. i=0;
  418. while(fmt[i])
  419. {
  420. ret = strptime(date_str, fmt[i], &dte);
  421. if(ret)
  422. {
  423. if(!res_ret || strlen(res_ret) > strlen(ret))
  424. {
  425. res_ret = ret;
  426. res = i;
  427. if(tm)
  428. {
  429. memcpy(tm, &dte, sizeof(struct tm));
  430. }
  431. if(t->fmt)
  432. {
  433. free(t->fmt);
  434. }
  435. t->fmt = malloc(
  436. sizeof(char)*(strlen(fmt[i])+1));
  437. if(!t->fmt)
  438. {
  439. perror("Unable to allocate memory\
  440. for date format");
  441. t->flag ^= TTAIL_FLAG_FORMAT;
  442. return -1;
  443. }
  444. strcpy(t->fmt, fmt[i]);
  445. t->flag |= TTAIL_FLAG_FORMAT;
  446. }
  447. }
  448. i++;
  449. }
  450. if(!res_ret)
  451. {
  452. if(tm)
  453. {
  454. memset(tm, 0, sizeof(struct tm));
  455. }
  456. return -1;
  457. }
  458. return res;
  459. }
  460. void ttail_free(ttail_t* t)
  461. {
  462. size_t i;
  463. if(t->flag & TTAIL_FLAG_PREFIX && t->prefix_sz < 0)
  464. {
  465. regfree(&(t->date_prefix));
  466. }
  467. for(i=0; i<t->logfile_sz; i++)
  468. {
  469. if(t->logfile[i])
  470. {
  471. fclose(t->logfile[i]);
  472. }
  473. if(t->logfile_name[i])
  474. {
  475. free(t->logfile_name[i]);
  476. }
  477. }
  478. free(t->logfile);
  479. free(t->logfile_name);
  480. t->logfile_sz = 0;
  481. if(t->fmt != NULL)
  482. {
  483. free(t->fmt);
  484. }
  485. free(t);
  486. optind=0;
  487. }