/*-
* Copyright (c) 2003 Andrey Simonenko
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "config.h"
#ifndef lint
static const char rcsid[] ATTR_UNUSED =
"@(#)$Id: ipa_time.c,v 1.2.2.3 2007/05/11 16:29:59 simon Exp $";
#endif /* !lint */
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/queue.h>
#include "ipa_mod.h"
#include "dlapi.h"
#include "confcommon.h"
#include "memfunc.h"
#include "ipa_time.h"
#include "ipa_log.h"
#include "ipa_main.h"
/*
* This file contains different time manipulation functions. I don't
* use standard library time manipulation functions, they can't be used
* directly and should be wrapped to fix time zone and summer time related
* errors, since ipa(8) doesn't need information about time zone and
* summer time, I found that implementing own functions is better,
* than writing wrappers for standard library time functions.
*
* May be for(;;) loops are not optimal, but for most cases
* they are not executed and the ideas of algorithms are easy.
*/
u_int wakeup_time; /* wakeup_time parameter. */
u_int freeze_time; /* freeze_time parameter. */
u_int sleep_after_dump; /* sleep_after_dump parameter. */
u_int sensitive_time; /* sensitive_time parameter. */
int debug_time; /* debug_time parameter. */
int debug_worktime; /* debug_worktime parameter. */
u_int worktimes_check_sec; /* When to call worktimes_check(). */
const struct worktime *global_worktime; /* global { worktime } */
struct worktime worktime_default; /* 00:00-24:00 for all days. */
static struct tint_set tint_set_default;
const struct tevent *global_update_tevent; /* global { update_time } */
const struct tevent *global_append_tevent; /* global { append_time } */
const char *const wdays[] = {
"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"
};
const char *const active_msg[] = {
"inactive", /* 0 */
"active" /* 1 */
};
ipa_mzone *tevent_mzone; /* Mzone for all struct tevent{}. */
struct tevents_list tevents_list; /* List of all tevents. */
ipa_mzone *tint_mzone; /* Mzone for all struct tint{}. */
struct tint_sets tint_sets; /* List of all tint_sets. */
ipa_mzone *worktime_mzone; /* Mzone for all worktimes. */
struct worktimes_list worktimes_list; /* List of all worktimes. */
ipa_tm curdate; /* Current human localdate. */
u_int cursec; /* Current time in seconds since midnight. */
u_int curwday; /* Current week day. */
int newday_flag = 0; /* Non-zero if new day came. */
#ifdef WITH_ANY_LIMITS
char *ipa_tm_buf = NULL; /* Pointer to buffer used in ipa_tm_to_buf(). */
#endif
char *tdiff_buf = NULL; /* Pointer to buffer used in tdiff_to_buf(). */
static int const last_mday_arr[] =
/* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
{ 0, 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
#ifdef WITH_ANY_LIMITS
/*
* Non-reentrant function for convert ipa_tm{} value to human readable
* value and return a pointer to allocated buffer with this value.
* If an error occurred, then a pointer to static string with error
* message is returned.
*/
const char *
ipa_tm_to_buf(const ipa_tm *tm)
{
mem_free(ipa_tm_buf, m_anon);
if (mem_asprintf(m_anon, &ipa_tm_buf, "%d.%02d.%02d/%02d:%02d:%02d",
tm->tm_year, tm->tm_mon, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec) < 0)
return "(ipa_tm_to_buf: mem_asprintf: no memory)";
return ipa_tm_buf;
}
/*
* Return last month day in the given year/mon.
*/
static int
last_mday(int year, int mon)
{
if (mon == 2) /* February */
return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ?
29 : 28;
return last_mday_arr[mon];
}
/*
* Check ipa_tm date for correct values, ignore nonexistent
* time (for example when time zone is changed as +1h, then some
* time does not exist).
*/
int
check_ipa_tm(const ipa_tm *tm)
{
int mon = tm->tm_mon;
int mday = tm->tm_mday;
if (mon == 0 || mon > 12 || mday > 31 || mday == 0 ||
mday > last_mday(tm->tm_year, mon) || tm->tm_hour > 23 ||
tm->tm_min > 59 || tm->tm_sec > 59)
return -1;
return 0;
}
/*
* If time in tm is 24:00:00, then convert it to 00:00:00 of the next day.
*/
void
fix_240000(ipa_tm *tm)
{
/* When tm_hour is 24, then tm_min and tm_sec == 0. */
if (tm->tm_hour == HOURS_IN_DAY) {
/* 24:00:00 --> next day 00:00:00 */
tm->tm_hour = 0;
if (tm->tm_mday == last_mday(tm->tm_year, tm->tm_mon)) {
tm->tm_mday = 1;
if (tm->tm_mon == MONTHES_IN_YEAR) {
tm->tm_mon = 1;
tm->tm_year++;
} else
tm->tm_mon++;
} else
tm->tm_mday++;
}
}
/*
* Compare two ipa_tm tm1 and tm2 structures:
* if (tm1 == tm2)
* return 0;
* if (tm1 > tm2)
* return 1;
* if (tm1 < tm2)
* return -1;
* This function correctly works with 24:00:00 time.
*/
int
cmp_ipa_tm(const ipa_tm *tm1, const ipa_tm *tm2)
{
/*
* We don't use mktime(3), because there can be problem
* with time zone and summer time.
*/
if (tm1->tm_year > tm2->tm_year)
return 1;
if (tm1->tm_year == tm2->tm_year) {
if (tm1->tm_mon > tm2->tm_mon)
return 1;
if (tm1->tm_mon == tm2->tm_mon) {
if (tm1->tm_mday > tm2->tm_mday)
return 1;
if (tm1->tm_mday == tm2->tm_mday) {
if (tm1->tm_hour > tm2->tm_hour)
return 1;
if (tm1->tm_hour == tm2->tm_hour) {
if (tm1->tm_min > tm2->tm_min)
return 1;
if (tm1->tm_min == tm2->tm_min) {
if (tm1->tm_sec > tm2->tm_sec)
return 1;
if (tm1->tm_sec == tm2->tm_sec)
return 0;
}
}
}
}
}
return -1;
}
/*
* Return difference in seconds between tm1 and tm0: tm1 - tm0,
* tm1 is expected to be greater than tm0.
*/
u_int
ipa_tm_diff(const ipa_tm *tm1_arg, const ipa_tm *tm0_arg)
{
u_int result, sec1, sec0;
ipa_tm tm1, tm0;
tm1 = *tm1_arg;
tm0 = *tm0_arg;
sec1 = tm1.tm_hour * SECONDS_IN_HOUR + tm1.tm_min * SECONDS_IN_MINUTE + tm1.tm_sec;
sec0 = tm0.tm_hour * SECONDS_IN_HOUR + tm0.tm_min * SECONDS_IN_MINUTE + tm0.tm_sec;
if (sec1 > sec0)
result = sec1 - sec0;
else {
result = HOURS_IN_DAY * SECONDS_IN_HOUR - sec0;
result += sec1;
if (tm0.tm_mday == last_mday(tm0.tm_year, tm0.tm_mon)) {
tm0.tm_mday = 1;
if (tm0.tm_mon == MONTHES_IN_YEAR) {
tm0.tm_mon = 1;
tm0.tm_year++;
} else
tm0.tm_mon++;
} else
tm0.tm_mday++;
}
for (; tm0.tm_year < tm1.tm_year; ++tm0.tm_year) {
for (; tm0.tm_mon <= MONTHES_IN_YEAR; tm0.tm_mon++) {
result += (last_mday(tm0.tm_year, tm0.tm_mon) - tm0.tm_mday + 1) * SECONDS_IN_DAY;
tm0.tm_mday = 1;
}
tm0.tm_mon = 1;
}
for (; tm0.tm_mon < tm1.tm_mon; tm0.tm_mon++) {
result += (last_mday(tm0.tm_year, tm0.tm_mon) - tm0.tm_mday + 1) * SECONDS_IN_DAY;
tm0.tm_mday = 1;
}
result += (tm1.tm_mday - tm0.tm_mday) * SECONDS_IN_DAY;
return result;
}
#endif /* WITH_ANY_LIMITS */
#ifdef WITH_LIMITS
/*
* Add some seconds to ipa_tm variable ignoring any time zone issues
* without using any standard time functions from the library.
*/
void
ipa_tm_addtime(ipa_tm *tm, u_int addsec)
{
int t, lmday, year, mon, mday, hour, min, sec;
year = tm->tm_year;
mon = tm->tm_mon;
mday = tm->tm_mday;
hour = tm->tm_hour;
min = tm->tm_min;
sec = tm->tm_sec;
t = addsec / SECONDS_IN_DAY;
addsec -= t * SECONDS_IN_DAY;
if (t != 0) {
for (;;) {
lmday = last_mday(year, mon);
if (mday + t > lmday) {
t -= lmday - mday;
if (mon == MONTHES_IN_YEAR) {
mon = 1;
year++;
} else
mon++;
mday = 1;
if (--t == 0)
break;
} else {
mday += t;
break;
}
}
}
if (addsec != 0) {
t = hour * SECONDS_IN_HOUR + min * SECONDS_IN_MINUTE + sec;
if (t + addsec >= SECONDS_IN_DAY) {
t += addsec - SECONDS_IN_DAY;
lmday = last_mday(year, mon);
if (++mday > lmday) {
if (mon == MONTHES_IN_YEAR) {
mon = 1;
year++;
} else
mon++;
mday = 1;
}
} else
t += addsec;
hour = t / SECONDS_IN_HOUR;
t -= hour * SECONDS_IN_HOUR;
min = t / SECONDS_IN_MINUTE;
sec = t - min * SECONDS_IN_MINUTE;
}
tm->tm_year = year;
tm->tm_mon = mon;
tm->tm_mday = mday;
tm->tm_hour = hour;
tm->tm_min = min;
tm->tm_sec = sec;
}
/*
* Convert given time in tm according to +upto.
*/
static void
ipa_tm_upto(ipa_tm *tm, char upto)
{
if (upto == TEXP_UPTO_SIMPLE)
return;
/* +M or +m -> +h -> +D -> +W */
if (upto == TEXP_UPTO_MONTH) { /* +M */
/* Up to the end of month. */
if (tm->tm_mon == MONTHES_IN_YEAR) {
tm->tm_mon = 1;
tm->tm_year++;
} else
tm->tm_mon++;
tm->tm_mday = 1;
tm->tm_hour = tm->tm_min = tm->tm_sec = 0;
return;
}
/* Up to the end of minute. */
ipa_tm_addtime(tm, SECONDS_IN_MINUTE - tm->tm_sec);
if (upto == TEXP_UPTO_MINUTE) /* +m */
return;
tm->tm_min++;
/* Up to the end of hour. */
ipa_tm_addtime(tm, SECONDS_IN_MINUTE * (MINUTES_IN_HOUR - tm->tm_min));
if (upto == TEXP_UPTO_HOUR) /* +h */
return;
tm->tm_hour++;
/* Up to the end of day. */
ipa_tm_addtime(tm, SECONDS_IN_HOUR * (HOURS_IN_DAY - tm->tm_hour));
if (upto == TEXP_UPTO_DAY) /* +D */
return;
tm->tm_wday++;
/* Up to the end of week. */
if (tm->tm_wday != 1) /* +W */
ipa_tm_addtime(tm, SECONDS_IN_DAY * (DAYS_IN_WEEK - tm->tm_wday));
}
/*
* Convert given time in tm according to texp.
*/
void
ipa_tm_texp(ipa_tm *tm, const struct texp *texp)
{
int right_side = texp->side;
if (!right_side)
ipa_tm_upto(tm, texp->upto);
ipa_tm_addtime(tm, texp->seconds);
if (right_side)
ipa_tm_upto(tm, texp->upto);
}
/*
* Set tm_wday in the given structure. mktime(3) ignores tm_wday
* and tm_wday is set on success. It is assumed, that 00:00:01 time
* exists in all time zones.
*/
int
set_wday(ipa_tm *tm_ptr)
{
struct tm tm;
tm = *tm_ptr;
tm.tm_year -= 1900;
tm.tm_mon--;
tm.tm_hour = tm.tm_min = 0;
tm.tm_sec = 1;
tm.tm_isdst = -1;
if (mktime(&tm) == (time_t)-1) {
logmsg(IPA_LOG_ERR, "set_wday: mktime failed");
return -1;
}
tm_ptr->tm_wday = tm.tm_wday;
return 0;
}
#endif /* WITH_LIMITS */
#ifdef WITH_THRESHOLDS
/*
* Subtract some seconds from ipa_tm variable ignoring any time zone issues
* without using any standard time functions from the library.
*/
void
ipa_tm_subtime(ipa_tm *tm, u_int subsec)
{
int t, year, mon, mday, hour, min, sec;
year = tm->tm_year;
mon = tm->tm_mon;
mday = tm->tm_mday;
hour = tm->tm_hour;
min = tm->tm_min;
sec = tm->tm_sec;
t = subsec / SECONDS_IN_DAY;
subsec -= t * SECONDS_IN_DAY;
if (t != 0) {
for (;;) {
if (mday > t) {
mday -= t;
break;
} else {
if (mon == 1) {
mon = MONTHES_IN_YEAR;
year--;
} else
mon--;
t -= mday;
mday = last_mday(year, mon);
if (t == 0)
break;
}
}
}
if (subsec != 0) {
t = hour * SECONDS_IN_HOUR + min * SECONDS_IN_MINUTE + sec;
if (t >= subsec)
t -= subsec;
else {
t = SECONDS_IN_DAY - (subsec - t);
if (--mday == 0) {
if (mon == 1) {
mon = 12;
year--;
} else
mon--;
mday = last_mday(year, mon);
}
}
hour = t / SECONDS_IN_HOUR;
t -= hour * SECONDS_IN_HOUR;
min = t / SECONDS_IN_MINUTE;
sec = t - min * SECONDS_IN_MINUTE;
}
tm->tm_year = year;
tm->tm_mon = mon;
tm->tm_mday = mday;
tm->tm_hour = hour;
tm->tm_min = min;
tm->tm_sec = sec;
}
#endif /* WITH_THRESHOLDS */
/*
* Non-reentrant function for converting number of seconds to hours,
* minutes and seconds and return a pointer to allocated buffer with
* this value. If an error occurred, then static string with error
* message is returned.
*/
const char *
time_to_buf(u_int t)
{
static char buf[BUF_TIME_SIZE];
int rv;
u_int h, m, s;
h = t / SECONDS_IN_HOUR;
t -= h * SECONDS_IN_HOUR;
m = t / SECONDS_IN_MINUTE;
s = t - m * SECONDS_IN_MINUTE;
if (h == 0) {
if (m == 0)
rv = snprintf(buf, sizeof buf, "%us", s);
else {
if (s == 0)
rv = snprintf(buf, sizeof buf, "%um", m);
else
rv = snprintf(buf, sizeof buf, "%um %02us", m, s);
}
} else
rv = snprintf(buf, sizeof buf, "%uh %02um %02us", h, m, s);
return rv < 0 ? "(time_to_buf: snprintf failed)" : buf;
}
/*
* The same as time_to_buf(), but argument is double and can be
* negative.
*/
const char *
tdiff_to_buf(double t)
{
const char *sign;
mem_free(tdiff_buf, m_anon);
if (t > UINT_MAX)
return mem_asprintf(m_anon, &tdiff_buf, "%.0f seconds", t) < 0 ?
"(tdiff_to_buf: mem_asprintf failed)" : tdiff_buf;
if (t < 0.0) {
t = -t;
sign = "-";
} else
sign = "";
return mem_asprintf(m_anon, &tdiff_buf, "%s%s", sign, time_to_buf((u_int)t)) < 0 ?
"(tdiff_to_buf: mem_asprintf failed)" : tdiff_buf;
}
/*
* Non-reentrant function for converting number of seconds to time.
*/
const char *
sec_to_buf(u_int sec)
{
static char buf[BUF_SEC_SIZE];
u_int h, m, s;
if (sec == SECONDS_IN_WEEK)
return "xx:xx:xx";
if (sec <= SECONDS_IN_DAY) {
h = sec / SECONDS_IN_HOUR;
sec -= h * SECONDS_IN_HOUR;
m = sec / SECONDS_IN_MINUTE;
s = sec - m * SECONDS_IN_MINUTE;
return snprintf(buf, sizeof buf, "%02u:%02u:%02u", h, m, s) < 0 ?
"(sec_to_buf: snprintf failed)" : buf;
}
return "??:??:??";
}
/*
* Non-reentrant function for converting time interval to string.
*/
const char *
tint_to_buf(const struct tint *tint)
{
static char buf[12]; /* xx:xx-xx:xx */
u_int h1, m1, h2, m2;
h1 = tint->sec1 / SECONDS_IN_HOUR;
m1 = (tint->sec1 - h1 * SECONDS_IN_HOUR) / SECONDS_IN_MINUTE;
h2 = tint->sec2 / SECONDS_IN_HOUR;
m2 = (tint->sec2 - h2 * SECONDS_IN_HOUR) / SECONDS_IN_MINUTE;
return snprintf(buf, sizeof buf, "%02u:%02u-%02u:%02u", h1, m1, h2, m2) < 0 ?
"(tint_to_buf: snprintf failed)" : buf;
}
/*
* Convert seconds since midnight to hours, minutes and seconds.
*/
void
sec_to_time(u_int sec, ipa_tm *tm)
{
int h, m, s;
h = sec / SECONDS_IN_HOUR;
sec -= h * SECONDS_IN_HOUR;
m = sec / SECONDS_IN_MINUTE;
s = sec - m * SECONDS_IN_MINUTE;
tm->tm_hour = h;
tm->tm_min = m;
tm->tm_sec = s;
}
void
init_worktime_default(void)
{
static struct tint tint;
u_int wday;
struct tint_list *list = &tint_set_default.list;
tint.sec1 = 0;
tint.sec2 = SECONDS_IN_DAY;
STAILQ_INIT(list);
STAILQ_INSERT_HEAD(list, &tint, link);
STAILQ_INSERT_HEAD(&tint_sets, &tint_set_default, link);
for (wday = 0; wday < DAYS_IN_WEEK; ++wday)
worktime_default.tint_list[wday] = list;
}
/*
* Release memory help by tint_set, including struct tint_set{}.
*/
void
free_tint_set(struct tint_set *set)
{
struct tint *tint, *tint_next;
for (tint = STAILQ_FIRST(&set->list); tint != NULL; tint = tint_next) {
tint_next = STAILQ_NEXT(tint, link);
mzone_free(tint_mzone, tint);
}
mem_free(set, m_anon);
}
/*
* Free all worktimes and worktime mzone.
*/
void
free_worktimes(void)
{
struct tint_set *set, *set_next;
/* Skip first tint, since it is tint_set_default. */
STAILQ_REMOVE_HEAD(&tint_sets, link);
/* Free other tint_sets. */
for (set = STAILQ_FIRST(&tint_sets); set != NULL; set = set_next) {
set_next = STAILQ_NEXT(set, link);
free_tint_set(set);
}
mzone_deinit(tint_mzone);
mzone_deinit(worktime_mzone);
}
/*
* Find next time interval for worktime starting from tint_start.
*/
static void
find_next_tint(struct worktime *wt, const struct tint *tint_start,
int report_skipping)
{
const struct tint *tint;
for (tint = tint_start; tint != NULL; tint = STAILQ_NEXT(tint, link)) {
if (cursec < tint->sec1) {
/* x [ ] */
wt->is_active = INACTIVE_FLAG;
if (worktimes_check_sec > tint->sec1)
worktimes_check_sec = tint->sec1;
if (debug_worktime)
logmsgx(IPA_LOG_INFO, "find_next_tint: %s left before start of %s %s worktime interval",
time_to_buf(tint->sec1 - cursec), wdays[curwday], tint_to_buf(tint));
break;
}
if (tint->sec1 <= cursec && cursec < tint->sec2) {
/* [ x ] */
wt->is_active = ACTIVE_FLAG;
if (worktimes_check_sec > tint->sec2)
worktimes_check_sec = tint->sec2;
if (debug_worktime)
logmsgx(IPA_LOG_INFO, "find_next_tint: %s left before end of %s %s worktime interval",
time_to_buf(tint->sec2 - cursec), wdays[curwday], tint_to_buf(tint));
break;
}
/* [ ] x */
if (report_skipping || debug_worktime)
logmsgx(IPA_LOG_WARNING, "find_next_tint: skipping %s %s worktime interval",
wdays[curwday], tint_to_buf(tint));
}
if (tint == NULL) {
/* There is no more time intervals for current week day. */
wt->is_active = INACTIVE_FLAG;
wt->active_sec = wt->inactive_sec = SECONDS_IN_WEEK;
if (debug_worktime)
logmsgx(IPA_LOG_INFO, "find_next_tint: there is no more worktime intervals for %s (current week day)",
wdays[curwday]);
} else {
wt->active_sec = tint->sec1;
wt->inactive_sec = tint->sec2;
}
/* Real tint or NULL for debugging purpose. */
wt->curtint = tint;
}
/*
* Check if current week day is set in worktime, find current
* active or inactive time interval.
*/
void
worktimes_newday(int report_skipping)
{
struct worktime *wt;
const struct tint_list *list;
worktimes_check_sec = SECONDS_IN_WEEK; /* Hint. */
SLIST_FOREACH(wt, &worktimes_list, link) {
list = wt->tint_list[curwday];
if (!STAILQ_EMPTY(list)) {
/* Current week day is set in worktime. */
find_next_tint(wt, STAILQ_FIRST(list), report_skipping);
} else {
/* Current week day is not set in worktime. */
wt->is_active = INACTIVE_FLAG;
/* Set NULL for debugging purpose. */
wt->curtint = NULL;
wt->active_sec = wt->inactive_sec = SECONDS_IN_WEEK;
if (debug_worktime)
logmsgx(IPA_LOG_INFO, "worktimes_newday: %s (current week day) is not set in worktime",
wdays[curwday]);
}
}
if (debug_worktime)
logmsgx(IPA_LOG_INFO, "worktimes_checks: worktimes_check_sec %s",
sec_to_buf(worktimes_check_sec));
}
/*
* Check if current time interval is still active, if it is
* time to make inactive time interval active.
*/
void
worktimes_check(void)
{
u_int delta;
struct worktime *wt;
worktimes_check_sec = SECONDS_IN_WEEK; /* Hint. */
SLIST_FOREACH(wt, &worktimes_list, link)
if (IS_ACTIVE(wt)) {
/* Is active. */
if (wt->inactive_sec <= cursec) {
/* It's time to make it inactive. */
delta = cursec - wt->inactive_sec;
if (delta > sensitive_time)
logmsgx(IPA_LOG_WARNING, "worktime interval %s %s became inactive too late: delta %s is greater than \"sensitive_time\" %u seconds",
wdays[curwday], tint_to_buf(wt->curtint), time_to_buf(delta), sensitive_time);
find_next_tint(wt, STAILQ_NEXT(wt->curtint, link), 1);
} else {
if (worktimes_check_sec > wt->inactive_sec)
worktimes_check_sec = wt->inactive_sec;
}
} else {
/* Is inactive. */
if (wt->active_sec <= cursec) {
/* It's time to make it active. */
delta = cursec - wt->active_sec;
if (delta > sensitive_time)
logmsgx(IPA_LOG_WARNING, "worktime interval %s %s became active too late: delta %s is greater than \"sensitive_time\" %u seconds",
wdays[curwday], tint_to_buf(wt->curtint), time_to_buf(delta), sensitive_time);
find_next_tint(wt, wt->curtint, 1);
} else {
if (worktimes_check_sec > wt->active_sec)
worktimes_check_sec = wt->active_sec;
}
}
if (debug_worktime)
logmsgx(IPA_LOG_INFO, "worktimes_checks: worktimes_check_sec %s",
sec_to_buf(worktimes_check_sec));
}
/*
* Try to find already registered worktime with the same settings as
* in wt1. If such worktime exist, then return its pointer, else
* return original one.
*/
const struct worktime *
find_worktime(struct worktime *wt1)
{
u_int wday;
struct worktime *wt2;
const struct tint_list * const *list1;
const struct tint_list * const *list2;
/* Check if there is already the same worktime. */
SLIST_FOREACH(wt2, &worktimes_list, link) {
list1 = wt1->tint_list;
list2 = wt2->tint_list;
for (wday = 0; wday < DAYS_IN_WEEK; ++wday) {
if (*list1 != *list2)
break;
++list1;
++list2;
}
if (wday == DAYS_IN_WEEK) {
/* The same worktime was found --> free original one. */
mzone_free(worktime_mzone, wt1);
return wt2;
}
}
/* New worktime, add it to the list. */
SLIST_INSERT_HEAD(&worktimes_list, wt1, link);
return wt1;
}
#ifdef WITH_ANY_LIMITS
/*
* Return 0 if wt2 is a subset of wt1, else return -1.
* Time intervals in limits' or thresholds' worktimes must be
* subsets of time intervals in their rule's worktime.
*/
int
check_worktime_subset(const struct worktime *wt1, const struct worktime *wt2)
{
u_int wday;
const struct tint *tint1, *tint2;
const struct tint_list * const *list1;
const struct tint_list * const *list2;
if (wt1 == NULL || wt2 == NULL || wt1 == wt2)
return 0;
list1 = wt1->tint_list;
list2 = wt2->tint_list;
for (wday = 0; wday < DAYS_IN_WEEK; ++list1, ++list2, ++wday) {
if (*list1 == *list2)
/* The same tint_list. */
continue;
if (STAILQ_EMPTY(*list2))
/* This day in wt2 is not for accounting. */
continue;
if (STAILQ_EMPTY(*list1))
/* This day in wt1 is not for accounting, but this day in wt2 is for accounting. */
return -1;
/* [ ] -- intervals in tint1, { } -- intervals in tint1. */
tint2 = STAILQ_FIRST(*list2);
STAILQ_FOREACH(tint1, *list1, link)
for (; tint2 != NULL; tint2 = STAILQ_NEXT(tint2, link)) {
if (tint2->sec1 >= tint1->sec1 &&
tint2->sec2 <= tint1->sec2)
/* [ { } ]*/
continue;
if (tint2->sec1 > tint1->sec2)
/* [ ] { } */
break;
/* { } [ ] or { }[ ] */
return -1;
}
if (tint2 != NULL)
/* [ ] { } */
return -1;
}
return 0;
}
#endif /* WITH_ANY_LIMITS */
syntax highlighted by Code2HTML, v. 0.9.1