diff options
Diffstat (limited to 'src/schedule.c')
-rw-r--r-- | src/schedule.c | 482 |
1 files changed, 0 insertions, 482 deletions
diff --git a/src/schedule.c b/src/schedule.c deleted file mode 100644 index 1f0816f..0000000 --- a/src/schedule.c +++ /dev/null @@ -1,482 +0,0 @@ -/* - * Copyright (C) 2020-2021 Soleta Networks <info@soleta.eu> - * - * This program is free software: you can redistribute it and/or modify it under - * the terms of the GNU Affero General Public License as published by the - * Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - */ - -#include "schedule.h" -#include "list.h" -#include <sys/types.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdlib.h> -#include <syslog.h> -#include <time.h> -#include <ev.h> - -struct og_schedule *current_schedule = NULL; -static LIST_HEAD(schedule_list); - -static void og_schedule_add(struct og_schedule *new) -{ - struct og_schedule *schedule, *next; - - list_for_each_entry_safe(schedule, next, &schedule_list, list) { - if (new->seconds < schedule->seconds) { - list_add_tail(&new->list, &schedule->list); - return; - } - } - list_add_tail(&new->list, &schedule_list); -} - -/* Returns the days in a month from the weekday. */ -static void get_days_from_weekday(struct tm *tm, int wday, int *days, int *j) -{ - int i, mday = 0; - - tm->tm_mday = 1; - - //Shift week to start on Sunday instead of Monday - if (wday == 6) - wday = 0; - else - wday++; - - /* A bit bruteforce, but simple. */ - for (i = 0; i <= 30; i++) { - mktime(tm); - /* Not this weekday, skip. */ - if (tm->tm_wday != wday) { - tm->tm_mday++; - continue; - } - /* Not interested in next month. */ - if (tm->tm_mday < mday) - break; - - /* Found a matching. */ - mday = tm->tm_mday; - days[(*j)++] = tm->tm_mday; - tm->tm_mday++; - } -} - -/* Returns the days in the given week. */ -static void get_days_from_week(struct tm *tm, int week, int *days, int *k) -{ - int i, j, week_counter = 0; - bool week_over = false; - - tm->tm_mday = 1; - - /* Remaining days of this month. */ - for (i = 0; i <= 30; i++) { - mktime(tm); - - /* Last day of this week? */ - if (tm->tm_wday == 6) - week_over = true; - - /* Not the week we are searching for. */ - if (week != week_counter) { - tm->tm_mday++; - if (week_over) { - week_counter++; - week_over = false; - } - continue; - } - - /* Found matching. */ - for (j = tm->tm_wday; j <= 6; j++) { - days[(*k)++] = tm->tm_mday++; - mktime(tm); - } - break; - } -} - -static int monthdays[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - -static int last_month_day(struct tm *tm) -{ - /* Leap year? Adjust it. */ - if (tm->tm_mon == 1) { - tm->tm_mday = 29; - mktime(tm); - if (tm->tm_mday == 29) - return 29; - - tm->tm_mon = 1; - } - - return monthdays[tm->tm_mon]; -} - -/* Returns the days in the given week. */ -static void get_last_week(struct tm *tm, int *days, int *j) -{ - int i, last_day; - - last_day = last_month_day(tm); - tm->tm_mday = last_day; - - for (i = last_day; i >= last_day - 6; i--) { - mktime(tm); - - days[(*j)++] = tm->tm_mday; - - - /* Last day of this week? */ - if (tm->tm_wday == 1) - break; - - tm->tm_mday--; - } -} - -static void og_parse_years(uint16_t years_mask, int years[]) -{ - int i, j = 0; - - for (i = 0; i < 16; i++) { - if ((1 << i) & years_mask) - years[j++] = 2010 + i - 1900; - } -} - -static void og_parse_months(uint16_t months_mask, int months[]) -{ - int i, j = 0; - - for (i = 0; i < 12; i++) { - if ((1 << i) & months_mask) - months[j++] = i + 1; - } -} - -static void og_parse_days(uint32_t days_mask, int *days) -{ - int i, j = 0; - - for (i = 0; i < 31; i++) { - if ((1 << i) & days_mask) - days[j++] = i + 1; - } -} - -static void og_parse_hours(uint16_t hours_mask, uint8_t am_pm, int hours[]) -{ - int pm = 12 * am_pm; - int i, j = 0; - - for (i = 0; i < 12; i++) { - if ((1 << i) & hours_mask) - hours[j++] = i + pm + 1; - } -} - -static void og_schedule_remove_duplicates() -{ - struct og_schedule *schedule, *next, *prev = NULL; - - list_for_each_entry_safe(schedule, next, &schedule_list, list) { - if (!prev) { - prev = schedule; - continue; - } - if (prev->seconds == schedule->seconds && - prev->task_id == schedule->task_id) { - list_del(&prev->list); - free(prev); - } - prev = schedule; - } -} - -static bool og_schedule_stale(time_t seconds) -{ - time_t now; - - now = time(NULL); - if (seconds < now) - return true; - - return false; -} - -static void og_schedule_create_weekdays(int month, int year, - int *hours, int minutes, int week_days, - uint32_t task_id, uint32_t schedule_id, - enum og_schedule_type type, - bool check_stale) -{ - struct og_schedule *schedule; - int month_days[5]; - int n_month_days; - time_t seconds; - uint32_t wday; - struct tm tm; - int k, l; - - for (wday = 0; wday < 7; wday++) { - if (!((1 << wday) & week_days)) - continue; - - memset(&tm, 0, sizeof(tm)); - tm.tm_mon = month; - tm.tm_year = year; - - n_month_days = 0; - memset(month_days, 0, sizeof(month_days)); - get_days_from_weekday(&tm, wday, month_days, &n_month_days); - - for (k = 0; month_days[k] != 0 && k < n_month_days; k++) { - for (l = 0; hours[l] != 0 && l < 31; l++) { - memset(&tm, 0, sizeof(tm)); - tm.tm_year = year; - tm.tm_mon = month; - tm.tm_mday = month_days[k]; - tm.tm_hour = hours[l] - 1; - tm.tm_min = minutes; - tm.tm_isdst = -1; - seconds = mktime(&tm); - - if (check_stale && og_schedule_stale(seconds)) - continue; - - schedule = (struct og_schedule *) - calloc(1, sizeof(struct og_schedule)); - if (!schedule) - return; - - schedule->seconds = seconds; - schedule->task_id = task_id; - schedule->schedule_id = schedule_id; - schedule->type = type; - og_schedule_add(schedule); - } - } - } -} - -static void og_schedule_create_weeks(int month, int year, - int *hours, int minutes, int weeks, - uint32_t task_id, uint32_t schedule_id, - enum og_schedule_type type, bool check_stale) -{ - struct og_schedule *schedule; - int month_days[7]; - int n_month_days; - time_t seconds; - struct tm tm; - int week; - int k, l; - - for (week = 0; week < 5; week++) { - if (!((1 << week) & weeks)) - continue; - - memset(&tm, 0, sizeof(tm)); - tm.tm_mon = month; - tm.tm_year = year; - - n_month_days = 0; - memset(month_days, 0, sizeof(month_days)); - if (week == 5) - get_last_week(&tm, month_days, &n_month_days); - else - get_days_from_week(&tm, week, month_days, &n_month_days); - - for (k = 0; month_days[k] != 0 && k < n_month_days; k++) { - for (l = 0; hours[l] != 0 && l < 31; l++) { - memset(&tm, 0, sizeof(tm)); - tm.tm_year = year; - tm.tm_mon = month; - tm.tm_mday = month_days[k]; - tm.tm_hour = hours[l] - 1; - tm.tm_min = minutes; - tm.tm_isdst = -1; - seconds = mktime(&tm); - - if (check_stale && og_schedule_stale(seconds)) - continue; - - schedule = (struct og_schedule *) - calloc(1, sizeof(struct og_schedule)); - if (!schedule) - return; - - schedule->seconds = seconds; - schedule->task_id = task_id; - schedule->schedule_id = schedule_id; - schedule->type = type; - og_schedule_add(schedule); - } - } - } -} - -static void og_schedule_create_days(int month, int year, - int *hours, int minutes, int *days, - uint32_t task_id, uint32_t schedule_id, - enum og_schedule_type type, bool check_stale) -{ - struct og_schedule *schedule; - time_t seconds; - struct tm tm; - int k, l; - - for (k = 0; days[k] != 0 && k < 31; k++) { - for (l = 0; hours[l] != 0 && l < 31; l++) { - - memset(&tm, 0, sizeof(tm)); - tm.tm_year = year; - tm.tm_mon = month; - tm.tm_mday = days[k]; - tm.tm_hour = hours[l] - 1; - tm.tm_min = minutes; - tm.tm_isdst = -1; - seconds = mktime(&tm); - - if (check_stale && og_schedule_stale(seconds)) - continue; - - schedule = (struct og_schedule *) - calloc(1, sizeof(struct og_schedule)); - if (!schedule) - return; - - schedule->seconds = seconds; - schedule->task_id = task_id; - schedule->schedule_id = schedule_id; - schedule->type = type; - og_schedule_add(schedule); - } - } -} - -void og_schedule_create(unsigned int schedule_id, unsigned int task_id, - enum og_schedule_type type, - struct og_schedule_time *time) -{ - int year, month, minutes; - int months[12] = {}; - int years[12] = {}; - int hours[12] = {}; - int days[31] = {}; - int i, j; - - og_parse_years(time->years, years); - og_parse_months(time->months, months); - og_parse_days(time->days, days); - og_parse_hours(time->hours, time->am_pm, hours); - minutes = time->minutes; - - for (i = 0; years[i] != 0 && i < 12; i++) { - for (j = 0; months[j] != 0 && j < 12; j++) { - month = months[j] - 1; - year = years[i]; - - if (time->week_days) - og_schedule_create_weekdays(month, year, - hours, minutes, - time->week_days, - task_id, - schedule_id, - type, - time->check_stale); - - if (time->weeks) - og_schedule_create_weeks(month, year, - hours, minutes, - time->weeks, - task_id, - schedule_id, - type, time->check_stale); - - if (time->days) - og_schedule_create_days(month, year, - hours, minutes, - days, - task_id, - schedule_id, - type, time->check_stale); - } - } - - og_schedule_remove_duplicates(); -} - -void og_schedule_delete(struct ev_loop *loop, uint32_t schedule_id) -{ - struct og_schedule *schedule, *next; - - list_for_each_entry_safe(schedule, next, &schedule_list, list) { - if (schedule->schedule_id != schedule_id) - continue; - - list_del(&schedule->list); - if (current_schedule == schedule) { - ev_timer_stop(loop, &schedule->timer); - current_schedule = NULL; - og_schedule_refresh(loop); - } - free(schedule); - } -} - -void og_schedule_update(struct ev_loop *loop, unsigned int schedule_id, - unsigned int task_id, struct og_schedule_time *time) -{ - og_schedule_delete(loop, schedule_id); - og_schedule_create(schedule_id, task_id, OG_SCHEDULE_TASK, time); -} - -static void og_agent_timer_cb(struct ev_loop *loop, ev_timer *timer, int events) -{ - struct og_schedule *current; - - current = container_of(timer, struct og_schedule, timer); - og_schedule_run(current->task_id, current->schedule_id, current->type); - - ev_timer_stop(loop, timer); - list_del(¤t->list); - free(current); - - og_schedule_next(loop); -} - -void og_schedule_next(struct ev_loop *loop) -{ - struct og_schedule *schedule; - time_t now, seconds; - - if (list_empty(&schedule_list)) { - current_schedule = NULL; - return; - } - - schedule = list_first_entry(&schedule_list, struct og_schedule, list); - now = time(NULL); - if (schedule->seconds <= now) - seconds = 0; - else - seconds = schedule->seconds - now; - - ev_timer_init(&schedule->timer, og_agent_timer_cb, seconds, 0.); - ev_timer_start(loop, &schedule->timer); - current_schedule = schedule; -} - -void og_schedule_refresh(struct ev_loop *loop) -{ - if (current_schedule) - ev_timer_stop(loop, ¤t_schedule->timer); - - og_schedule_next(loop); -} |