/* ausearch-time.c - time handling utility functions
* Copyright 2006-08,2011,2016-17 Red Hat Inc., Durham, North Carolina.
* All Rights Reserved.
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Authors:
* Steve Grubb <sgrubb@redhat.com>
*/
#define _XOPEN_SOURCE
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include "ausearch-time.h"
#define SECONDS_IN_DAY 24*60*60
static void clear_tm(struct tm *t);
static void replace_time(struct tm *t1, struct tm *t2);
static void replace_date(struct tm *t1, struct tm *t2);
time_t start_time = 0, end_time = 0;
struct nv_pair {
int value;
const char *name;
};
static struct nv_pair timetab[] = {
{ T_NOW, "now" },
{ T_RECENT, "recent" },
{ T_BOOT, "boot" },
{ T_TODAY, "today" },
{ T_YESTERDAY, "yesterday" },
{ T_THIS_WEEK, "this-week" },
{ T_WEEK_AGO, "week-ago" },
{ T_THIS_MONTH, "this-month" },
{ T_THIS_YEAR, "this-year" },
};
#define TIME_NAMES (sizeof(timetab)/sizeof(timetab[0]))
int lookup_time(const char *name)
{
unsigned int i;
for (i = 0; i < TIME_NAMES; i++) {
if (strcmp(timetab[i].name, name) == 0) {
return timetab[i].value;
}
}
return -1;
}
/* static void print_time(struct tm *d)
{
char outstr[200];
strftime(outstr, sizeof(outstr), "%c", d);
printf("%s\n", outstr);
} */
static void clear_tm(struct tm *t)
{
t->tm_sec = 0; /* seconds */
t->tm_min = 0; /* minutes */
t->tm_hour = 0; /* hours */
t->tm_mday = 0; /* day of the month */
t->tm_mon = 0; /* month */
t->tm_year = 0; /* year */
t->tm_isdst = 0; /* DST flag */
}
static void set_tm_now(struct tm *d)
{
time_t t = time(NULL);
struct tm *tv = localtime(&t);
replace_time(d, tv);
replace_date(d, tv);
}
static void set_tm_today(struct tm *d)
{
time_t t = time(NULL);
struct tm *tv = localtime(&t);
d->tm_sec = 0; /* seconds */
d->tm_min = 0; /* minutes */
d->tm_hour = 0; /* hours */
replace_date(d, tv);
}
static void set_tm_yesterday(struct tm *d)
{
time_t t = time(NULL) - (time_t)(SECONDS_IN_DAY);
struct tm *tv = localtime(&t);
d->tm_sec = 0; /* seconds */
d->tm_min = 0; /* minutes */
d->tm_hour = 0; /* hours */
replace_date(d, tv);
}
static void set_tm_recent(struct tm *d)
{
time_t t = time(NULL) - (time_t)(10*60); /* 10 minutes ago */
struct tm *tv = localtime(&t);
replace_time(d, tv);
replace_date(d, tv);
}
static int set_tm_boot(struct tm *d)
{
char buf[128];
time_t t;
int rc, fd = open("/proc/uptime", O_RDONLY);
if (fd < 0) {
error_out:
fprintf(stderr, "Can't read uptime (%s)\n", strerror(errno));
return -1;
}
t = time(NULL);
rc = read(fd, buf, sizeof(buf)-1);
close(fd);
if (rc > 0) {
struct tm *tv;
float f_uptime;
unsigned long uptime;
char *ptr;
buf[rc] = 0;
ptr = strchr(buf, ' '); // Accurate only to the second
if (ptr)
*ptr = 0;
errno = 0;
f_uptime = strtof(buf, NULL);
uptime = f_uptime + 0.5;
if (errno)
goto error_out;
t -= uptime;
tv = localtime(&t);
replace_time(d, tv);
replace_date(d, tv);
} else
goto error_out;
return 0;
}
static void set_tm_this_week(struct tm *d)
{
time_t t = time(NULL);
struct tm *tv = localtime(&t);
d->tm_sec = 0; /* seconds */
d->tm_min = 0; /* minutes */
d->tm_hour = 0; /* hours */
t -= (time_t)(tv->tm_wday*(time_t)SECONDS_IN_DAY);
tv = localtime(&t);
replace_date(d, tv);
}
static void set_tm_week_ago(struct tm *d)
{
time_t t = time(NULL);
struct tm *tv;
d->tm_sec = 0; /* seconds */
d->tm_min = 0; /* minutes */
d->tm_hour = 0; /* hours */
t -= (time_t)(7*SECONDS_IN_DAY);
tv = localtime(&t);
replace_date(d, tv);
}
static void set_tm_this_month(struct tm *d)
{
time_t t = time(NULL);
struct tm *tv = localtime(&t);
d->tm_sec = 0; /* seconds */
d->tm_min = 0; /* minutes */
d->tm_hour = 0; /* hours */
replace_date(d, tv);
d->tm_mday = 1; /* override day of month */
}
static void set_tm_this_year(struct tm *d)
{
time_t t = time(NULL);
struct tm *tv = localtime(&t);
d->tm_sec = 0; /* seconds */
d->tm_min = 0; /* minutes */
d->tm_hour = 0; /* hours */
replace_date(d, tv);
d->tm_mday = 1; /* override day of month */
d->tm_mon = 0; /* override month */
d->tm_isdst = 0;
}
/* The time in t1 is replaced by t2 */
static void replace_time(struct tm *t1, struct tm *t2)
{
t1->tm_sec = t2->tm_sec; /* seconds */
t1->tm_min = t2->tm_min; /* minutes */
t1->tm_hour = t2->tm_hour; /* hours */
}
/* The date in t1 is replaced by t2 */
static void replace_date(struct tm *t1, struct tm *t2)
{
t1->tm_mday = t2->tm_mday; /* day */
t1->tm_mon = t2->tm_mon; /* month */
t1->tm_year = t2->tm_year; /* year */
t1->tm_isdst = t2->tm_isdst; /* daylight savings time */
t1->tm_wday = t2->tm_wday; /* Day of Week */
t1->tm_yday = t2->tm_yday; /* Day of Year */
}
static int lookup_and_set_time(const char *da, struct tm *d)
{
int retval = lookup_time(da);
if (retval >= 0) {
switch (retval)
{
case T_NOW:
set_tm_now(d);
break;
case T_RECENT:
set_tm_recent(d);
break;
case T_BOOT:
if (set_tm_boot(d))
return -2;
break;
case T_TODAY:
set_tm_today(d);
break;
case T_YESTERDAY:
set_tm_yesterday(d);
break;
case T_THIS_WEEK:
set_tm_this_week(d);
break;
case T_WEEK_AGO:
set_tm_week_ago(d);
break;
case T_THIS_MONTH:
set_tm_this_month(d);
break;
case T_THIS_YEAR:
set_tm_this_year(d);
break;
}
return 0;
} else
return -1;
}
int ausearch_time_start(const char *da, const char *ti)
{
/* If da == NULL, use current date */
/* If ti == NULL, then use midnight 00:00:00 */
int rc = 0;
struct tm d;
char *ret;
clear_tm(&d);
if (da == NULL)
set_tm_now(&d);
else {
if (lookup_and_set_time(da, &d) < 0) {
ret = strptime(da, "%x", &d);
if (ret == NULL) {
fprintf(stderr,
"Invalid start date (%s). Month, Day, and Year are required.\n",
da);
return 1;
}
if (*ret != 0) {
fprintf(stderr,
"Error parsing start date (%s)\n", da);
return 1;
}
// FIX DST flag
start_time = mktime(&d);
} else {
int keyword=lookup_time(da);
if (keyword == T_RECENT || keyword == T_NOW ||
keyword == T_BOOT) {
if (ti == NULL || strcmp(ti, "00:00:00") == 0)
goto set_it;
}
}
}
if (ti != NULL) {
char tmp_t[64];
if (strlen(ti) <= 5) {
snprintf(tmp_t, sizeof(tmp_t), "%s:00", ti);
} else {
tmp_t[0]=0;
strncat(tmp_t, ti, sizeof(tmp_t)-1);
}
ret = strptime(tmp_t, "%X", &d);
if (ret == NULL) {
fprintf(stderr,
"Invalid start time (%s). Hour, Minute, and Second are required.\n",
ti);
return 1;
}
if (*ret != 0) {
fprintf(stderr, "Error parsing start time (%s)\n", ti);
return 1;
}
} else
clear_tm(&d);
if (d.tm_year < 104) {
fprintf(stderr, "Error - year is %d\n", d.tm_year+1900);
return -1;
}
set_it:
start_time = mktime(&d);
// printf("start is: %s\n", ctime(&start_time));
if (start_time == -1) {
fprintf(stderr, "Error converting start time\n");
rc = -1;
}
return rc;
}
int ausearch_time_end(const char *da, const char *ti)
{
/* If date == NULL, use current date */
/* If ti == NULL, use current time */
int rc = 0;
struct tm d;
char *ret;
clear_tm(&d);
if (da == NULL)
set_tm_now(&d);
else {
if (lookup_and_set_time(da, &d) < 0) {
ret = strptime(da, "%x", &d);
if (ret == NULL) {
fprintf(stderr,
"Invalid end date (%s). Month, Day, and Year are required.\n",
da);
return 1;
}
if (*ret != 0) {
fprintf(stderr,
"Error parsing end date (%s)\n", da);
return 1;
}
// FIX DST flag
end_time = mktime(&d);
} else {
int keyword=lookup_time(da);
if (keyword == T_RECENT || keyword == T_NOW ||
keyword == T_BOOT) {
if (ti == NULL || strcmp(ti, "00:00:00") == 0)
goto set_it;
}
// Special case today
if (keyword == T_TODAY) {
set_tm_now(&d);
if (ti == NULL || strcmp(ti, "00:00:00") == 0)
goto set_it;
}
}
}
if (ti != NULL) {
char tmp_t[64];
if (strlen(ti) <= 5) {
snprintf(tmp_t, sizeof(tmp_t), "%s:00", ti);
} else {
tmp_t[0]=0;
strncat(tmp_t, ti, sizeof(tmp_t)-1);
}
ret = strptime(tmp_t, "%X", &d);
if (ret == NULL) {
fprintf(stderr,
"Invalid end time (%s). Hour, Minute, and Second are required.\n",
ti);
return 1;
}
if (*ret != 0) {
fprintf(stderr, "Error parsing end time (%s)\n", ti);
return 1;
}
} else {
time_t tt = time(NULL);
struct tm *tv = localtime(&tt);
d.tm_hour = tv->tm_hour;
d.tm_min = tv->tm_min;
d.tm_sec = tv->tm_sec;
d.tm_isdst = tv->tm_isdst;
}
if (d.tm_year < 104) {
fprintf(stderr, "Error - year is %d\n", d.tm_year+1900);
return -1;
}
set_it:
end_time = mktime(&d);
// printf("end is: %s\n", ctime(&end_time));
if (end_time == -1) {
fprintf(stderr, "Error converting end time\n");
rc = -1;
}
return rc;
}