123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729 |
- /*
- * Copyright 2017 Yann Weber
- *
- * This file is part of Ttail.
- *
- * Ttail is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * any later version.
- *
- * Ttail 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Ttail. If not, see <http://www.gnu.org/licenses/>.
- */
- #include "ttail_init.h"
-
- void usage()
- {
- static struct option opts[] = TTAIL_LONG_OPT;
- static char *help[][2] = TTAIL_OPT_HELP;
- size_t i;
- printf("Usage : ttail -d DATE [OPTIONS] [LOGFILES]\n");
- printf("\t\n");
- printf("Options list\n");
- i=0;
- while(opts[i].name)
- {
- printf("\t-%c, --%s", opts[i].val, opts[i].name);
- if(opts[i].has_arg == required_argument)
- {
- printf("=%s\n",
- help[i][1]?help[i][1]:"ARG");
- }
- else if(opts[i].has_arg == optional_argument)
- {
- printf("[=%s]\n",
- help[i][1]?help[i][1]:"ARG");
- }
- else
- {
- printf("\n");
- }
- printf("\t\t%s\n\n", help[i][0]);
- i++;
- }
- printf(TTAIL_HELP_TEXT);
- }
-
- ttail_t *ttail_init(int argc, char **argv)
- {
- ttail_t *res;
- int c, opt_i, ret;
- size_t i;
- char *dates[2] = { NULL, NULL };
- char *date;
-
- res = malloc(sizeof(ttail_t));
- if(!res)
- {
- perror("Unable to allocate memory");
- goto ttail_init_alloc_err;
- }
-
- opterr = 1;
- optind = 0;
- res->verbose = 0;
- res->fmt = NULL;
- res->flag = 0;
- res->logfile = NULL;
- res->logfile_name = NULL;
- res->logfile_sz = 0;
- res->prefix_sz = 0;
- res->session = NULL;
- ttail_tm_init(&(res->date_min));
- ttail_tm_init(&(res->date_max));
-
- while(1)
- {
- static struct option long_options[] = TTAIL_LONG_OPT;
-
- c = getopt_long(argc, argv, TTAIL_SHORT_OPT, long_options, &opt_i);
- if(c == -1)
- break;
-
- switch(c)
- {
- case 'v':
- res->verbose++;
- break;
- case 'r':
- if(ttail_set_prefix(res, optarg))
- {
- goto ttail_init_err;
- }
- break;
- case 'p':
- if(res->flag & TTAIL_FLAG_PREFIX)
- {
- fprintf(stderr, "Preffix allready \
- set\n");
- goto ttail_init_err;
- }
- res->flag |= TTAIL_FLAG_PREFIX;
- res->prefix_sz = atoi(optarg);
- if(res->prefix_sz <= 0)
- {
- fprintf(stderr, "Prefix size have \
- to be > 0");
- goto ttail_init_err;
- }
- break;
- case 'E':
- if(ttail_set_flag_re_ex(res) < 0)
- {
- goto ttail_init_err;
- }
- break;
- case 'I':
- if(ttail_set_flag_re_ci(res) < 0)
- {
- goto ttail_init_err;
- }
- break;
- case 'f':
- if(res->flag & TTAIL_FLAG_FORMAT)
- {
- fprintf(stderr,"Multiple date format \
- given\n");
- goto ttail_init_err;
- }
- if(ttail_set_fmt(res, optarg) < 0)
- {
- goto ttail_init_err;
- }
-
- break;
- case 'h':
- usage();
- goto ttail_init_err;
- case 'd':
- case 'm':
- date = malloc(sizeof(char)*(strlen(optarg)+1));
- if(!date)
- {
- goto ttail_init_err;
- }
- strcpy(date, optarg);
- dates[c=='d'?0:1] = date;
- break;
- case 'P':
- if(res->flag & TTAIL_FLAG_PERMISSIVE)
- {
- fprintf(stderr, "Warning : looks like \
- -P --permissive flag was set more than once\n");
- }
- res->flag |= TTAIL_FLAG_PERMISSIVE;
- break;
- default: /* ? */
- goto ttail_init_err;
-
- }
- }
-
- for(i=optind; i<argc; i++)
- {
- ret = ttail_add_logfile(res, argv[i]);
- if(ret < 0)
- {
- goto ttail_init_err;
- }
- }
-
- if(ttail_set_dates(res, dates) < 0)
- {
- goto ttail_init_err;
- }
-
- return res;
- ttail_init_err:
- if(dates[0]) { free(dates[0]); }
- if(dates[1]) { free(dates[1]); }
- ttail_free(res);
- ttail_init_alloc_err:
- return NULL;
- }
-
- int ttail_init_check(ttail_t* t)
- {
- size_t i, ret;
- if(t->logfile_sz)
- {
- ret = 0;
- for(i=0; i<t->logfile_sz; i++)
- {
- if(t->logfile[i])
- {
- ret = 1;
- break;
- }
- }
- if(!ret)
- {
- fprintf(stderr, "Unable to read from any of the files \
- given as argument\n");
- return -1;
- }
- }
- if(!(t->flag & TTAIL_FLAG_DATE_MIN) && !(t->flag & TTAIL_FLAG_DATE_MAX))
- {
- fprintf(stderr, "one of --date-min -d --date-max -m is \
- mandatory\n");
- return -1;
- }
- if((t->flag & TTAIL_FLAG_DATE_MIN) && (t->flag & TTAIL_FLAG_DATE_MAX))
- {
- if(ttail_tm_cmp(&(t->date_min), &(t->date_max)) > 0)
- {
- fprintf(stderr, "date-min > date-max.\n");
- return -1;
- }
- }
- return 0;
- }
-
- int ttail_add_logfile(ttail_t* res, const char* filename)
- {
- void *tmp;
- FILE *fp;
- char *fname;
- int ret, i;
-
- for(i=0; i<res->logfile_sz; i++)
- {
- if(strcmp(filename, res->logfile_name[i]) == 0)
- {
- fprintf(stderr, "File '%s' allready added\n",
- filename);
- return -1;
- }
- }
-
- res->logfile_sz++;
- tmp = res->logfile;
- res->logfile = realloc(res->logfile,
- sizeof(FILE*)*res->logfile_sz);
- ret = 0;
- if(!res->logfile)
- {
- perror("Unable to allocate memory for logfiles");
- res->logfile = tmp;
- goto ttail_add_logfile_fpalloc_err;
- }
- fp = fopen(filename, "r");
- if(!fp)
- {
- fprintf(stderr, "Unable to open file : %s\n", filename);
- res->logfile[res->logfile_sz-1] = NULL;
- ret = 1;
- }
- res->logfile[res->logfile_sz-1] = fp;
-
- tmp = res->logfile_name;
- res->logfile_name = realloc(res->logfile_name,
- sizeof(char*)*res->logfile_sz);
- if(!res->logfile_name)
- {
- perror("Unable to allocate memory for logfiles");
- res->logfile_name = tmp;
- goto ttail_add_logfile_fnalloc_err;
-
- }
- fname = malloc(sizeof(char)*(strlen(filename)+1));
- if(!fname)
- {
- perror("Unable to allocate memory for logfiles");
- goto ttail_add_logfile_fnalloc_err;
- }
- strcpy(fname, filename);
- res->logfile_name[res->logfile_sz-1] = fname;
-
- return ret;
-
- ttail_add_logfile_fnalloc_err:
- fclose(res->logfile[res->logfile_sz-2]);
- ttail_add_logfile_fpalloc_err:
- res->logfile_sz--;
- return -1;
- }
-
- int ttail_set_prefix(ttail_t* res, const char* regex)
- {
- int ret, cflags;
- char *re_errbuff;
- size_t re_errbuff_sz;
-
- if(res->flag & TTAIL_FLAG_PREFIX)
- {
- fprintf(stderr, "Regex prefix allready set");
- return 1;
- }
- res->flag |= TTAIL_FLAG_PREFIX;
- cflags = 0; /** @todo checks */
- if(res->flag & TTAIL_FLAG_EXTENDED_RE)
- {
- cflags |= REG_EXTENDED;
- }
- if(res->flag & TTAIL_FLAG_CI_RE)
- {
- cflags |= REG_ICASE;
- }
- ret = regcomp(&res->date_prefix, regex, cflags);
- if(!ret)
- {
- res->prefix_sz = -1;
- return 0;
- }
- /*compilation error */
- res->flag ^= TTAIL_FLAG_PREFIX;
- re_errbuff_sz = regerror(ret,
- &res->date_prefix, NULL, 0);
- re_errbuff = malloc(
- sizeof(char)*re_errbuff_sz);
- if(!re_errbuff)
- {
- perror("Failed to allocate memory for regex compilation \
- error message");
- goto ttail_set_prefix_err;
- }
- regerror(ret, &res->date_prefix,
- re_errbuff,
- sizeof(char)*re_errbuff_sz);
- fprintf(stderr, "Regex compilation fails : %s", re_errbuff);
-
- free(re_errbuff);
- ttail_set_prefix_err:
- return -1;
- }
-
- int ttail_set_fmt(ttail_t* t, const char* fmt)
- {
- size_t len;
- if(t->flag & TTAIL_FLAG_FORMAT)
- {
- return -1;
- }
- len = strlen(fmt);
- t->fmt = malloc(sizeof(char)*(len+1));
- if(!t->fmt)
- {
- return -1;
- }
- strncpy(t->fmt, fmt, len);
- t->fmt[len] = '\0';
- t->flag |= TTAIL_FLAG_FORMAT;
- return 0;
- }
-
- /**@brief This function is used by bot @ref ttail_set_flag_re_ex() and
- *ttail_set_flag_re_ci() function
- *@param t ttail_t*
- *@return -1 on error else 0
- */
- static int _ttail_common_set_flag_re(ttail_t* ttail)
- {
- if(ttail->flag & TTAIL_FLAG_PREFIX)
- {
- fprintf(stderr, "Regex flags has to be set BEFORE the \
- prefix\n");
- return -1;
- }
- return 0;
- }
-
- int ttail_set_flag_re_ex(ttail_t* ttail)
- {
- if(_ttail_common_set_flag_re(ttail) < 0)
- {
- return -1;
- }
- ttail->flag |= TTAIL_FLAG_EXTENDED_RE;
- return 0;
- }
-
- int ttail_set_flag_re_ci(ttail_t* ttail)
- {
- if(_ttail_common_set_flag_re(ttail) < 0)
- {
- return -1;
- }
- ttail->flag |= TTAIL_FLAG_CI_RE;
- return 0;
- }
-
- int ttail_set_dates(ttail_t* res, char* dates[2])
- {
- int c, ret;
- char *date;
-
- for(c=0;c<2;c++)
- {
- ttail_tm_init(c==0?&(res->date_min):&(res->date_max));
- if(!dates[c])
- {
- continue;
- }
- date = dates[c];
- if(!strncmp(date, "#-", 2))
- {
- /* relative date */
- ret = _ttail_set_date_relative(res, date, c);
- }
- else
- {
- /* date from format */
- ret = _ttail_set_date_fmt(res, date, c);
- }
- if(ret < 0)
- {
- return -1;
- }
- res->flag |= c?TTAIL_FLAG_DATE_MAX:TTAIL_FLAG_DATE_MIN;
- }
-
- if(dates[0]) { free(dates[0]); dates[0] = NULL; }
- if(dates[1]) { free(dates[1]); dates[1] = NULL; }
-
- return 0;
- }
-
- int _ttail_set_date_fmt(ttail_t* res, char* date, int c)
- {
- int ret;
- char *endp;
- char *fmt[] = TTAIL_DEFAULT_FORMATS;
-
- if(!(res->flag & TTAIL_FLAG_FORMAT))
- {
- /* no format specified */
- ret = ttail_format_guess(date,
- c==0?&(res->date_min):&(res->date_max));
- if(ret < 0)
- {
- fprintf(stderr, "Unable to guess format for \
- date '%s'\n", date);
- return -1;
- }
- res->fmt = malloc(sizeof(char)*(strlen(fmt[ret])+1));
- if(!res->fmt)
- {
- perror("Unable to allocate memory for date format");
- res->flag ^= TTAIL_FLAG_FORMAT;
- }
- strcpy(res->fmt, fmt[ret]);
- res->flag |= TTAIL_FLAG_FORMAT;
-
- res->flag |= c?TTAIL_FLAG_DATE_MAX:TTAIL_FLAG_DATE_MIN;
- return 0;
- }
- endp = strptime(date, res->fmt,
- c==0?&(res->date_min):&(res->date_max));
- if(!endp)
- {
- fprintf(stderr, "Unable to parse date-%s '%s' with \
- format '%s'\n", c==0?"min":"max", date, res->fmt);
- return -1;
- }
- else if(*endp != '\0')
- {
- fprintf(stderr, "Leading caracters for date-%s : '%s' \
- is not matched in '%s'\n",\
- c==0?"min":"max", endp, date);
- return -1;
- }
- return 0;
- }
- int _ttail_set_date_relative(ttail_t* res, char* date, int c)
- {
- time_t now;
- char *unit, str_date[64];
- int value;
- struct tm *tm, *tm_p;
- short mod;
-
- tm = c==0?&(res->date_min):&(res->date_max);
- ttail_tm_init(tm);
- if(time(&now) < 0)
- {
- fprintf(stderr, "Unable to retrieve time using time()\n");
- return -1;
- }
- if(!(tm_p = localtime(&now)))
- {
- fprintf(stderr, "Unable to retrieve localtime using localtime()\n");
- return -1;
- }
-
- memcpy(tm, tm_p, sizeof(struct tm));
-
- mod = 0;
- unit = NULL;
- value = (int)strtol(date+2, &unit, 10);
- switch(*unit)
- {
- case 's':
- if(*(unit+1) == '\0' || !strcmp(unit, "sec"))
- {
- tm->tm_sec -= value;
- if(tm->tm_sec < 0)
- {
- mod = 1;
- value = abs(tm->tm_sec);
- tm->tm_sec = 60 - (value % 60);
- value /= 60;
- value++;
- }
- if(!mod)
- {
- break;
- }
- }
- case 'm':
- if(mod || *(unit+1) == '\0' || !strcmp(unit, "min"))
- {
- mod = 0;
- tm->tm_min -= value;
- if(tm->tm_min < 0)
- {
- mod = 1;
- value = abs(tm->tm_min);
- tm->tm_min = 60 - (value % 60);
- value /= 60;
- value++;
- printf("Value left : %d\n", value);
- }
- if(!mod)
- {
- break;
- }
- }
- case 'h':
- if(mod || *(unit+1) == '\0' || !strcmp(unit, "hour"))
- {
- mod = 0;
- tm->tm_hour -= value;
- if(tm->tm_hour < 0)
- {
- mod = 1;
- value = abs(tm->tm_hour);
- tm->tm_hour = 24 - (value % 24);
- value /= 24;
- value++;
- }
- if(!mod)
- {
- break;
- }
- }
- case 'd':
- if(mod || *(unit+1) == '\0' || !strcmp(unit, "day"))
- {
- mod = 0;
- tm->tm_mday -= value;
- if(tm->tm_mday < 0)
- {
- mod = 1;
- value = abs(tm->tm_mday);
- tm->tm_mday = 31 - (value % 31);
- value /= 31;
- value++;
- }
- if(!mod)
- {
- break;
- }
- }
- case 'M':
- if(*(unit+1) == '\0' || !strcmp(unit, "Month"))
- {
- mod = 0;
- tm->tm_mon -= value;
- if(tm->tm_mon < 0)
- {
- mod = 1;
- value = abs(tm->tm_mon);
- tm->tm_mon = 12 - (value % 12);
- value /= 12;
- value++;
- }
- if(!mod)
- {
- break;
- }
- }
- case 'y':
- if(mod || *(unit+1) == '\0' || !strcmp(unit, "year"))
- {
- tm->tm_year -= value;
- break;
- }
- default:
- fprintf(stderr,"Invalid relative date '%s'\n", date);
- return -1;
- }
- if(res->verbose > 0)
- {
- strftime(str_date, 64, "%c", tm);
- fprintf(stderr, "%s date set to %s\n",
- c?"stop":"start", str_date);
- }
- return 0;
-
- }
-
- int ttail_norm_dates(ttail_t* ttail)
- {
- struct tm *tm_p, tm;
- /* Huge buffer but no way to make a difference between error and
- buffer too small using strftime */
- char date[4096], *endp;
- size_t date_len;
- time_t now;
-
- if(time(&now) < 0)
- {
- perror("Unable to retrieve time using time()\n");
- return -1;
- }
- if(!(tm_p = localtime(&now)))
- {
- perror("Unable to retrieve localtime using localtime()\n");
- return -1;
- }
- if(!(date_len = strftime(date, sizeof(date), ttail->fmt, tm_p)))
- {
- fprintf(stderr, "Unable to print the current date using strftime()\n");
- return -1;
- }
- ttail_tm_init(&tm);
- endp = strptime(date, ttail->fmt, &tm);
- if(!endp || *endp != '\0')
- {
- fprintf(stderr, "An error occured, unable to strptime() a date\
- we just strftime() !\n");
- exit(EXIT_FAILURE);
- }
-
- TTAIL_NORMDATE(ttail, &tm, tm_sec);
- TTAIL_NORMDATE(ttail, &tm, tm_min);
- TTAIL_NORMDATE(ttail, &tm, tm_hour);
- TTAIL_NORMDATE(ttail, &tm, tm_mday);
- TTAIL_NORMDATE(ttail, &tm, tm_mon);
- TTAIL_NORMDATE(ttail, &tm, tm_year);
-
- return 0;
- }
-
- int ttail_format_guess(const char* date_str, struct tm* tm)
- {
- int i, res;
- char *res_ret, *ret;
- char *fmt[] = TTAIL_DEFAULT_FORMATS;
- struct tm dte;
-
- memset(&dte, 0, sizeof(struct tm));
-
- res = -1;
- res_ret = NULL;
- i=0;
- while(fmt[i])
- {
- ret = strptime(date_str, fmt[i], &dte);
- if(ret)
- {
- if(!res_ret || strlen(res_ret) > strlen(ret))
- {
- res_ret = ret;
- res = i;
- if(tm)
- {
- memcpy(tm, &dte, sizeof(struct tm));
- }
- }
- }
- i++;
- }
- if(!res_ret)
- {
- if(tm)
- {
- memset(tm, 0, sizeof(struct tm));
- }
- return -1;
- }
- return res;
- }
-
- void ttail_free(ttail_t* t)
- {
- size_t i;
- if(t->flag & TTAIL_FLAG_PREFIX && t->prefix_sz < 0)
- {
- regfree(&(t->date_prefix));
- }
- for(i=0; i<t->logfile_sz; i++)
- {
- if(t->logfile[i])
- {
- fclose(t->logfile[i]);
- }
- if(t->logfile_name[i])
- {
- free(t->logfile_name[i]);
- }
- }
- free(t->logfile);
- free(t->logfile_name);
- t->logfile_sz = 0;
- if(t->fmt != NULL)
- {
- free(t->fmt);
- }
- free(t);
- optind=0;
- }
|