X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Fdird%2Frun_conf.c;h=c4a41578a6101cac935de83821d9eef7e72c4465;hb=735d035900d19889425fe083cc4a2227df0627c5;hp=15ba907004702751f50f3e42f5e773f5f1e305f5;hpb=a002d989df13b7bbd4199d1844a8536bc99586ec;p=bacula%2Fbacula diff --git a/bacula/src/dird/run_conf.c b/bacula/src/dird/run_conf.c index 15ba907004..c4a41578a6 100644 --- a/bacula/src/dird/run_conf.c +++ b/bacula/src/dird/run_conf.c @@ -1,3 +1,21 @@ +/* + Bacula(R) - The Network Backup Solution + + Copyright (C) 2000-2015 Kern Sibbald + + The original author of Bacula is Kern Sibbald, with contributions + from many others, a complete list can be found in the file AUTHORS. + + You may use this file and others of this release according to the + license defined in the LICENSE file, which includes the Affero General + Public License, v3.0 ("AGPLv3") and some additional permissions and + terms pursuant to its AGPLv3 Section 7. + + This notice must be preserved when any source code is + conveyed and/or propagated. + + Bacula(R) is a registered trademark of Kern Sibbald. +*/ /* * * Configuration parser for Director Run Configuration @@ -5,33 +23,19 @@ * * Kern Sibbald, May MM * - * Version $Id$ - */ -/* - Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker - - 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. - */ #include "bacula.h" #include "dird.h" +#if defined(_MSC_VER) +extern "C" { // work around visual compiler mangling variables + extern URES res_all; +} +#else extern URES res_all; -extern struct s_jl joblevels[]; +#endif +extern s_jl joblevels[]; /* Forward referenced subroutines */ @@ -47,134 +51,143 @@ enum e_state { s_weekly, s_monthly, s_hourly, - s_wpos, /* 1st, 2nd, ...*/ -}; + s_wom, /* 1st, 2nd, ...*/ + s_woy, /* week of year w00 - w53 */ + s_ldom /* last day of month */ +}; struct s_keyw { - char *name; /* keyword */ - enum e_state state; /* parser state */ - int code; /* state value */ + const char *name; /* keyword */ + enum e_state state; /* parser state */ + int code; /* state value */ }; /* Keywords understood by parser */ static struct s_keyw keyw[] = { - {N_("on"), s_none, 0}, - {N_("at"), s_at, 0}, - - {N_("sun"), s_wday, 0}, - {N_("mon"), s_wday, 1}, - {N_("tue"), s_wday, 2}, - {N_("wed"), s_wday, 3}, - {N_("thu"), s_wday, 4}, - {N_("fri"), s_wday, 5}, - {N_("sat"), s_wday, 6}, - {N_("jan"), s_month, 0}, - {N_("feb"), s_month, 1}, - {N_("mar"), s_month, 2}, - {N_("apr"), s_month, 3}, - {N_("may"), s_month, 4}, - {N_("jun"), s_month, 5}, - {N_("jul"), s_month, 6}, - {N_("aug"), s_month, 7}, - {N_("sep"), s_month, 8}, - {N_("oct"), s_month, 9}, - {N_("nov"), s_month, 10}, - {N_("dec"), s_month, 11}, - - {N_("sunday"), s_wday, 0}, - {N_("monday"), s_wday, 1}, - {N_("tuesday"), s_wday, 2}, - {N_("wednesday"), s_wday, 3}, - {N_("thursday"), s_wday, 4}, - {N_("friday"), s_wday, 5}, - {N_("saturday"), s_wday, 6}, - {N_("january"), s_month, 0}, - {N_("february"), s_month, 1}, - {N_("march"), s_month, 2}, - {N_("april"), s_month, 3}, - {N_("june"), s_month, 5}, - {N_("july"), s_month, 6}, - {N_("august"), s_month, 7}, - {N_("september"), s_month, 8}, - {N_("october"), s_month, 9}, - {N_("november"), s_month, 10}, - {N_("december"), s_month, 11}, - - {N_("daily"), s_daily, 0}, - {N_("weekly"), s_weekly, 0}, - {N_("monthly"), s_monthly, 0}, - {N_("hourly"), s_hourly, 0}, - - {N_("1st"), s_wpos, 0}, - {N_("2nd"), s_wpos, 1}, - {N_("3rd"), s_wpos, 2}, - {N_("4th"), s_wpos, 3}, - {N_("5th"), s_wpos, 4}, - - {N_("first"), s_wpos, 0}, - {N_("second"), s_wpos, 1}, - {N_("third"), s_wpos, 2}, - {N_("fourth"), s_wpos, 3}, - {N_("fifth"), s_wpos, 4}, - {NULL, s_none, 0} + {NT_("on"), s_none, 0}, + {NT_("at"), s_at, 0}, + {NT_("lastday"), s_ldom, 0}, + + {NT_("sun"), s_wday, 0}, + {NT_("mon"), s_wday, 1}, + {NT_("tue"), s_wday, 2}, + {NT_("wed"), s_wday, 3}, + {NT_("thu"), s_wday, 4}, + {NT_("fri"), s_wday, 5}, + {NT_("sat"), s_wday, 6}, + {NT_("jan"), s_month, 0}, + {NT_("feb"), s_month, 1}, + {NT_("mar"), s_month, 2}, + {NT_("apr"), s_month, 3}, + {NT_("may"), s_month, 4}, + {NT_("jun"), s_month, 5}, + {NT_("jul"), s_month, 6}, + {NT_("aug"), s_month, 7}, + {NT_("sep"), s_month, 8}, + {NT_("oct"), s_month, 9}, + {NT_("nov"), s_month, 10}, + {NT_("dec"), s_month, 11}, + + {NT_("sunday"), s_wday, 0}, + {NT_("monday"), s_wday, 1}, + {NT_("tuesday"), s_wday, 2}, + {NT_("wednesday"), s_wday, 3}, + {NT_("thursday"), s_wday, 4}, + {NT_("friday"), s_wday, 5}, + {NT_("saturday"), s_wday, 6}, + {NT_("january"), s_month, 0}, + {NT_("february"), s_month, 1}, + {NT_("march"), s_month, 2}, + {NT_("april"), s_month, 3}, + {NT_("june"), s_month, 5}, + {NT_("july"), s_month, 6}, + {NT_("august"), s_month, 7}, + {NT_("september"), s_month, 8}, + {NT_("october"), s_month, 9}, + {NT_("november"), s_month, 10}, + {NT_("december"), s_month, 11}, + + {NT_("daily"), s_daily, 0}, + {NT_("weekly"), s_weekly, 0}, + {NT_("monthly"), s_monthly, 0}, + {NT_("hourly"), s_hourly, 0}, + + {NT_("1st"), s_wom, 0}, + {NT_("2nd"), s_wom, 1}, + {NT_("3rd"), s_wom, 2}, + {NT_("4th"), s_wom, 3}, + {NT_("5th"), s_wom, 4}, + {NT_("6th"), s_wom, 5}, + + {NT_("first"), s_wom, 0}, + {NT_("second"), s_wom, 1}, + {NT_("third"), s_wom, 2}, + {NT_("fourth"), s_wom, 3}, + {NT_("fifth"), s_wom, 4}, + {NT_("sixth"), s_wom, 5}, + {NULL, s_none, 0} }; -static int have_hour, have_mday, have_wday, have_month, have_wpos; -static int have_at; +static bool have_hour, have_mday, have_wday, have_month, have_wom; +static bool have_at, have_woy; static RUN lrun; -static void clear_defaults() -{ - have_hour = have_mday = have_wday = have_month = have_wpos = TRUE; - clear_bit(0,lrun.hour); - clear_bits(0, 30, lrun.mday); - clear_bits(0, 6, lrun.wday); - clear_bits(0, 11, lrun.month); - clear_bits(0, 4, lrun.wpos); -} - static void set_defaults() { - have_hour = have_mday = have_wday = have_month = have_wpos = FALSE; - have_at = FALSE; - set_bit(0,lrun.hour); + have_hour = have_mday = have_wday = have_month = have_wom = have_woy = false; + have_at = false; + set_bits(0, 23, lrun.hour); set_bits(0, 30, lrun.mday); - set_bits(0, 6, lrun.wday); + set_bits(0, 6, lrun.wday); set_bits(0, 11, lrun.month); - set_bits(0, 4, lrun.wpos); + set_bits(0, 5, lrun.wom); + set_bits(0, 53, lrun.woy); } -/* Keywords (RHS) permitted in Run records */ -static struct s_kw RunFields[] = { - {"pool", 'P'}, - {"level", 'L'}, - {"storage", 'S'}, - {"messages", 'M'}, - {"priority", 'p'}, - {NULL, 0} +/* + * Keywords (RHS) permitted in Run records + * + * name token + */ +s_kw RunFields[] = { + {"Pool", 'P'}, + {"FullPool", 'f'}, + {"IncrementalPool", 'i'}, + {"DifferentialPool", 'd'}, + {"Level", 'L'}, + {"Storage", 'S'}, + {"Messages", 'M'}, + {"Priority", 'p'}, + {"SpoolData", 's'}, + {"writepartafterjob", 'W'}, + {"MaxRunSchedTime", 'm'}, + {"Accurate", 'a'}, + {"NextPool", 'N'}, + {NULL, 0} }; -/* - * Store Schedule Run information - * +/* + * Store Schedule Run information + * * Parse Run statement: * * Run [on] 2 january at 23:45 * * Default Run time is daily at 0:0 - * + * * There can be multiple run statements, they are simply chained * together. * */ -void store_run(LEX *lc, struct res_items *item, int index, int pass) +void store_run(LEX *lc, RES_ITEM *item, int index, int pass) { - int i, j, found; + int i, j; + bool found; + utime_t utime; int token, state, state2 = 0, code = 0, code2 = 0; int options = lc->options; - RUN **run = (RUN **)(item->value); - RUN *trun; + RUN **run = (RUN **)(item->value); char *p; RES *res; @@ -185,92 +198,165 @@ void store_run(LEX *lc, struct res_items *item, int index, int pass) memset(&lrun, 0, sizeof(RUN)); /* scan for Job level "full", "incremental", ... */ - for (found=TRUE; found; ) { - found = FALSE; + for (found=true; found; ) { + found = false; token = lex_get_token(lc, T_NAME); - for (i=0; RunFields[i].name; i++) { - if (strcasecmp(lc->str, RunFields[i].name) == 0) { - found = TRUE; - if (lex_get_token(lc, T_ALL) != T_EQUALS) { - scan_err1(lc, "Expected an equals, got: %s", lc->str); - /* NOT REACHED */ - } - switch (RunFields[i].token) { + for (i=0; !found && RunFields[i].name; i++) { + if (strcasecmp(lc->str, RunFields[i].name) == 0) { + found = true; + if (lex_get_token(lc, T_ALL) != T_EQUALS) { + scan_err1(lc, _("Expected an equals, got: %s"), lc->str); + /* NOT REACHED */ + } + switch (RunFields[i].token) { + case 's': /* Data spooling */ + token = lex_get_token(lc, T_NAME); + if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) { + lrun.spool_data = true; + lrun.spool_data_set = true; + } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) { + lrun.spool_data = false; + lrun.spool_data_set = true; + } else { + scan_err1(lc, _("Expect a YES or NO, got: %s"), lc->str); + } + break; + case 'W': /* Write part after job */ + token = lex_get_token(lc, T_NAME); + if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) { + lrun.write_part_after_job = true; + lrun.write_part_after_job_set = true; + } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) { + lrun.write_part_after_job = false; + lrun.write_part_after_job_set = true; + } else { + scan_err1(lc, _("Expect a YES or NO, got: %s"), lc->str); + } + break; case 'L': /* level */ - token = lex_get_token(lc, T_NAME); - for (j=0; joblevels[j].level_name; j++) { - if (strcasecmp(lc->str, joblevels[j].level_name) == 0) { - lrun.level = joblevels[j].level; - lrun.job_type = joblevels[j].job_type; - j = 0; - break; - } - } - if (j != 0) { + token = lex_get_token(lc, T_NAME); + for (j=0; joblevels[j].level_name; j++) { + if (strcasecmp(lc->str, joblevels[j].level_name) == 0) { + lrun.level = joblevels[j].level; + lrun.job_type = joblevels[j].job_type; + lrun.level_set = true; + j = 0; + break; + } + } + if (j != 0) { scan_err1(lc, _("Job level field: %s not found in run record"), lc->str); - /* NOT REACHED */ - } - break; + /* NOT REACHED */ + } + break; case 'p': /* Priority */ - token = lex_get_token(lc, T_PINT32); - if (pass == 2) { - lrun.Priority = lc->pint32_val; - } - break; + token = lex_get_token(lc, T_PINT32); + if (pass == 2) { + lrun.Priority = lc->pint32_val; + lrun.priority_set = true; + } + break; case 'P': /* Pool */ - token = lex_get_token(lc, T_NAME); - if (pass == 2) { - res = GetResWithName(R_POOL, lc->str); - if (res == NULL) { - scan_err1(lc, "Could not find specified Pool Resource: %s", - lc->str); - /* NOT REACHED */ - } - lrun.pool = (POOL *)res; - } - break; + case 'N': /* NextPool */ + case 'f': /* FullPool */ + case 'v': /* VFullPool */ + case 'i': /* IncPool */ + case 'd': /* DifPool */ + token = lex_get_token(lc, T_NAME); + if (pass == 2) { + res = GetResWithName(R_POOL, lc->str); + if (res == NULL) { + scan_err1(lc, _("Could not find specified Pool Resource: %s"), + lc->str); + /* NOT REACHED */ + } + switch(RunFields[i].token) { + case 'P': + lrun.pool = (POOL *)res; + break; + case 'N': + lrun.next_pool = (POOL *)res; + break; + case 'f': + lrun.full_pool = (POOL *)res; + break; + case 'v': + lrun.vfull_pool = (POOL *)res; + break; + case 'i': + lrun.inc_pool = (POOL *)res; + break; + case 'd': + lrun.diff_pool = (POOL *)res; + break; + } + } + break; case 'S': /* storage */ - token = lex_get_token(lc, T_NAME); - if (pass == 2) { - res = GetResWithName(R_STORAGE, lc->str); - if (res == NULL) { - scan_err1(lc, "Could not find specified Storage Resource: %s", - lc->str); - /* NOT REACHED */ - } - lrun.storage = (STORE *)res; - } - break; + token = lex_get_token(lc, T_NAME); + if (pass == 2) { + res = GetResWithName(R_STORAGE, lc->str); + if (res == NULL) { + scan_err1(lc, _("Could not find specified Storage Resource: %s"), + lc->str); + /* NOT REACHED */ + } + lrun.storage = (STORE *)res; + } + break; case 'M': /* messages */ - token = lex_get_token(lc, T_NAME); - if (pass == 2) { - res = GetResWithName(R_MSGS, lc->str); - if (res == NULL) { - scan_err1(lc, "Could not find specified Messages Resource: %s", - lc->str); - /* NOT REACHED */ - } - lrun.msgs = (MSGS *)res; - } - break; - default: - scan_err1(lc, "Expected a keyword name, got: %s", lc->str); - /* NOT REACHED */ - break; - } /* end switch */ - } /* end if strcasecmp */ + token = lex_get_token(lc, T_NAME); + if (pass == 2) { + res = GetResWithName(R_MSGS, lc->str); + if (res == NULL) { + scan_err1(lc, _("Could not find specified Messages Resource: %s"), + lc->str); + /* NOT REACHED */ + } + lrun.msgs = (MSGS *)res; + } + break; + case 'm': /* max run sched time */ + token = lex_get_token(lc, T_QUOTED_STRING); + if (!duration_to_utime(lc->str, &utime)) { + scan_err1(lc, _("expected a time period, got: %s"), lc->str); + return; + } + lrun.MaxRunSchedTime = utime; + lrun.MaxRunSchedTime_set = true; + break; + case 'a': /* accurate */ + token = lex_get_token(lc, T_NAME); + if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) { + lrun.accurate = true; + lrun.accurate_set = true; + } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) { + lrun.accurate = false; + lrun.accurate_set = true; + } else { + scan_err1(lc, _("Expect a YES or NO, got: %s"), lc->str); + } + break; + default: + scan_err1(lc, _("Expected a keyword name, got: %s"), lc->str); + /* NOT REACHED */ + break; + } /* end switch */ + } /* end if strcasecmp */ } /* end for RunFields */ /* At this point, it is not a keyword. Check for old syle * Job Levels without keyword. This form is depreciated!!! */ - for (j=0; joblevels[j].level_name; j++) { - if (strcasecmp(lc->str, joblevels[j].level_name) == 0) { - lrun.level = joblevels[j].level; - lrun.job_type = joblevels[j].job_type; - found = TRUE; - break; - } + if (!found) { + for (j=0; joblevels[j].level_name; j++) { + if (strcasecmp(lc->str, joblevels[j].level_name) == 0) { + lrun.level = joblevels[j].level; + lrun.job_type = joblevels[j].job_type; + found = true; + break; + } + } } } /* end for found */ @@ -283,261 +369,320 @@ void store_run(LEX *lc, struct res_items *item, int index, int pass) set_defaults(); for ( ; token != T_EOL; (token = lex_get_token(lc, T_ALL))) { - int len, pm = 0; + int len; + bool pm = false; + bool am = false; switch (token) { case T_NUMBER: - state = s_mday; - code = atoi(lc->str) - 1; - if (code < 0 || code > 30) { + state = s_mday; + code = atoi(lc->str) - 1; + if (code < 0 || code > 30) { scan_err0(lc, _("Day number out of range (1-31)")); - } - break; - case T_NAME: /* this handles drop through from keyword */ + } + break; + case T_NAME: /* this handles drop through from keyword */ case T_UNQUOTED_STRING: if (strchr(lc->str, (int)'-')) { - state = s_range; - break; - } + state = s_range; + break; + } if (strchr(lc->str, (int)':')) { - state = s_time; - break; - } - /* everything else must be a keyword */ - for (i=0; keyw[i].name; i++) { - if (strcasecmp(lc->str, keyw[i].name) == 0) { - state = keyw[i].state; - code = keyw[i].code; - i = 0; - break; - } - } - if (i != 0) { + state = s_time; + break; + } + if (lc->str_len == 3 && (lc->str[0] == 'w' || lc->str[0] == 'W') && + is_an_integer(lc->str+1)) { + code = atoi(lc->str+1); + if (code < 0 || code > 53) { + scan_err0(lc, _("Week number out of range (0-53)")); + /* NOT REACHED */ + } + state = s_woy; /* week of year */ + break; + } + /* everything else must be a keyword */ + for (i=0; keyw[i].name; i++) { + if (strcasecmp(lc->str, keyw[i].name) == 0) { + state = keyw[i].state; + code = keyw[i].code; + i = 0; + break; + } + } + if (i != 0) { scan_err1(lc, _("Job type field: %s in run record not found"), lc->str); - /* NOT REACHED */ - } - break; + /* NOT REACHED */ + } + break; case T_COMMA: - continue; + continue; default: scan_err2(lc, _("Unexpected token: %d:%s"), token, lc->str); - /* NOT REACHED */ - break; + /* NOT REACHED */ + break; } switch (state) { case s_none: - continue; - case s_mday: /* day of month */ - if (!have_mday) { - clear_bits(0, 30, lrun.mday); - clear_bits(0, 6, lrun.wday); - have_mday = TRUE; - } - set_bit(code, lrun.mday); - break; - case s_month: /* month of year */ - if (!have_month) { - clear_bits(0, 11, lrun.month); - have_month = TRUE; - } - set_bit(code, lrun.month); - break; - case s_wday: /* week day */ - if (!have_wday) { - clear_bits(0, 6, lrun.wday); - clear_bits(0, 30, lrun.mday); - have_wday = TRUE; - } - set_bit(code, lrun.wday); - break; - case s_wpos: /* Week position 1st, ... */ - if (!have_wpos) { - clear_bits(0, 4, lrun.wpos); - have_wpos = TRUE; - } - set_bit(code, lrun.wpos); - break; - case s_time: /* time */ - if (!have_at) { + continue; + case s_mday: /* day of month */ + if (!have_mday) { + clear_bits(0, 30, lrun.mday); + have_mday = true; + } + set_bit(code, lrun.mday); + break; + case s_month: /* month of year */ + if (!have_month) { + clear_bits(0, 11, lrun.month); + have_month = true; + } + set_bit(code, lrun.month); + break; + case s_wday: /* week day */ + if (!have_wday) { + clear_bits(0, 6, lrun.wday); + have_wday = true; + } + set_bit(code, lrun.wday); + break; + case s_wom: /* Week of month 1st, ... */ + if (!have_wom) { + clear_bits(0, 5, lrun.wom); + have_wom = true; + } + set_bit(code, lrun.wom); + break; + case s_woy: + if (!have_woy) { + clear_bits(0, 53, lrun.woy); + have_woy = true; + } + set_bit(code, lrun.woy); + break; + case s_time: /* time */ + if (!have_at) { scan_err0(lc, _("Time must be preceded by keyword AT.")); - /* NOT REACHED */ - } - if (!have_hour) { - clear_bit(0, lrun.hour); - } + /* NOT REACHED */ + } + if (!have_hour) { + clear_bits(0, 23, lrun.hour); + } +// Dmsg1(000, "s_time=%s\n", lc->str); p = strchr(lc->str, ':'); - if (!p) { + if (!p) { scan_err0(lc, _("Time logic error.\n")); - /* NOT REACHED */ - } - *p++ = 0; /* separate two halves */ - code = atoi(lc->str); - len = strlen(p); - if (len > 2 && p[len-1] == 'm') { - if (p[len-2] == 'a') { - pm = 0; - } else if (p[len-2] == 'p') { - pm = 1; - } else { - scan_err0(lc, _("Bad time specification.")); - /* NOT REACHED */ - } - } else { - pm = 0; - } - code2 = atoi(p); - if (pm) { - code += 12; - } - if (code < 0 || code > 23 || code2 < 0 || code2 > 59) { + /* NOT REACHED */ + } + *p++ = 0; /* separate two halves */ + code = atoi(lc->str); /* pick up hour */ + code2 = atoi(p); /* pick up minutes */ + len = strlen(p); + if (len >= 2) { + p += 2; + } + if (strcasecmp(p, "pm") == 0) { + pm = true; + } else if (strcasecmp(p, "am") == 0) { + am = true; + } else if (len != 2) { + scan_err0(lc, _("Bad time specification.")); + /* NOT REACHED */ + } + /* + * Note, according to NIST, 12am and 12pm are ambiguous and + * can be defined to anything. However, 12:01am is the same + * as 00:01 and 12:01pm is the same as 12:01, so we define + * 12am as 00:00 and 12pm as 12:00. + */ + if (pm) { + /* Convert to 24 hour time */ + if (code != 12) { + code += 12; + } + /* am */ + } else if (am && code == 12) { + code -= 12; + } + if (code < 0 || code > 23 || code2 < 0 || code2 > 59) { scan_err0(lc, _("Bad time specification.")); - /* NOT REACHED */ - } - set_bit(code, lrun.hour); - lrun.minute = code2; - have_hour = TRUE; - break; + /* NOT REACHED */ + } +// Dmsg2(000, "hour=%d min=%d\n", code, code2); + set_bit(code, lrun.hour); + lrun.minute = code2; + have_hour = true; + break; case s_at: - have_at = TRUE; - break; + have_at = true; + break; + case s_ldom: + if (!have_mday) { + clear_bits(0, 30, lrun.mday); + have_mday = true; + } + lrun.last_day_set = true; + set_bit(31, lrun.mday); /* day 32 => last day of month */ + break; case s_range: p = strchr(lc->str, '-'); - if (!p) { + if (!p) { scan_err0(lc, _("Range logic error.\n")); - } - *p++ = 0; /* separate two halves */ - - /* Check for day range */ - if (is_an_integer(lc->str) && is_an_integer(p)) { - code = atoi(lc->str) - 1; - code2 = atoi(p) - 1; - if (code < 0 || code > 30 || code2 < 0 || code2 > 30) { + } + *p++ = 0; /* separate two halves */ + + /* Check for day range */ + if (is_an_integer(lc->str) && is_an_integer(p)) { + code = atoi(lc->str) - 1; + code2 = atoi(p) - 1; + if (code < 0 || code > 30 || code2 < 0 || code2 > 30) { scan_err0(lc, _("Bad day range specification.")); - } - if (!have_mday) { - clear_bits(0, 30, lrun.mday); - clear_bits(0, 6, lrun.wday); - have_mday = TRUE; - } - if (code < code2) { - set_bits(code, code2, lrun.mday); - } else { - set_bits(code, 30, lrun.mday); - set_bits(0, code2, lrun.mday); - } - break; - } - - /* lookup first half of keyword range (week days or months) */ - lcase(lc->str); - for (i=0; keyw[i].name; i++) { - if (strcmp(lc->str, keyw[i].name) == 0) { - state = keyw[i].state; - code = keyw[i].code; - i = 0; - break; - } - } - if (i != 0 || (state != s_month && state != s_wday && state != s_wpos)) { + } + if (!have_mday) { + clear_bits(0, 30, lrun.mday); + have_mday = true; + } + if (code < code2) { + set_bits(code, code2, lrun.mday); + } else { + set_bits(code, 30, lrun.mday); + set_bits(0, code2, lrun.mday); + } + break; + } + /* Check for week of year range */ + if (strlen(lc->str) == 3 && strlen(p) == 3 && + (lc->str[0] == 'w' || lc->str[0] == 'W') && + (p[0] == 'w' || p[0] == 'W') && + is_an_integer(lc->str+1) && is_an_integer(p+1)) { + code = atoi(lc->str+1); + code2 = atoi(p+1); + if (code < 0 || code > 53 || code2 < 0 || code2 > 53) { + scan_err0(lc, _("Week number out of range (0-53)")); + } + if (!have_woy) { + clear_bits(0, 53, lrun.woy); + have_woy = true; + } + if (code < code2) { + set_bits(code, code2, lrun.woy); + } else { + set_bits(code, 53, lrun.woy); + set_bits(0, code2, lrun.woy); + } + break; + } + /* lookup first half of keyword range (week days or months) */ + lcase(lc->str); + for (i=0; keyw[i].name; i++) { + if (strcasecmp(lc->str, keyw[i].name) == 0) { + state = keyw[i].state; + code = keyw[i].code; + i = 0; + break; + } + } + if (i != 0 || (state != s_month && state != s_wday && state != s_wom)) { scan_err0(lc, _("Invalid month, week or position day range")); - /* NOT REACHED */ - } - - /* Lookup end of range */ - lcase(p); - for (i=0; keyw[i].name; i++) { - if (strcmp(p, keyw[i].name) == 0) { - state2 = keyw[i].state; - code2 = keyw[i].code; - i = 0; - break; - } - } - if (i != 0 || state != state2 || code == code2) { + /* NOT REACHED */ + } + + /* Lookup end of range */ + lcase(p); + for (i=0; keyw[i].name; i++) { + if (strcasecmp(p, keyw[i].name) == 0) { + state2 = keyw[i].state; + code2 = keyw[i].code; + i = 0; + break; + } + } + if (i != 0 || state != state2 || code == code2) { scan_err0(lc, _("Invalid month, weekday or position range")); - /* NOT REACHED */ - } - if (state == s_wday) { - if (!have_wday) { - clear_bits(0, 6, lrun.wday); - clear_bits(0, 30, lrun.mday); - have_wday = TRUE; - } - if (code < code2) { - set_bits(code, code2, lrun.wday); - } else { - set_bits(code, 6, lrun.wday); - set_bits(0, code2, lrun.wday); - } - } else if (state == s_month) { - if (!have_month) { - clear_bits(0, 30, lrun.month); - have_month = TRUE; - } - if (code < code2) { - set_bits(code, code2, lrun.month); - } else { - /* this is a bit odd, but we accept it anyway */ - set_bits(code, 30, lrun.month); - set_bits(0, code2, lrun.month); - } - } else { - /* Must be position */ - if (!have_wpos) { - clear_bits(0, 4, lrun.wpos); - have_wpos = TRUE; - } - if (code < code2) { - set_bits(code, code2, lrun.wpos); - } else { - set_bits(code, 4, lrun.wpos); - set_bits(0, code2, lrun.wpos); - } - } - break; + /* NOT REACHED */ + } + if (state == s_wday) { + if (!have_wday) { + clear_bits(0, 6, lrun.wday); + have_wday = true; + } + if (code < code2) { + set_bits(code, code2, lrun.wday); + } else { + set_bits(code, 6, lrun.wday); + set_bits(0, code2, lrun.wday); + } + } else if (state == s_month) { + if (!have_month) { + clear_bits(0, 11, lrun.month); + have_month = true; + } + if (code < code2) { + set_bits(code, code2, lrun.month); + } else { + /* this is a bit odd, but we accept it anyway */ + set_bits(code, 11, lrun.month); + set_bits(0, code2, lrun.month); + } + } else { + /* Must be position */ + if (!have_wom) { + clear_bits(0, 5, lrun.wom); + have_wom = true; + } + if (code < code2) { + set_bits(code, code2, lrun.wom); + } else { + set_bits(code, 5, lrun.wom); + set_bits(0, code2, lrun.wom); + } + } + break; case s_hourly: - clear_defaults(); - set_bits(0, 23, lrun.hour); - set_bits(0, 30, lrun.mday); - set_bits(0, 11, lrun.month); - set_bits(0, 4, lrun.wpos); - break; + have_hour = true; + set_bits(0, 23, lrun.hour); + break; case s_weekly: - clear_defaults(); - set_bit(0, lrun.wday); - set_bits(0, 11, lrun.month); - set_bits(0, 4, lrun.wpos); - break; + have_mday = have_wom = have_woy = true; + set_bits(0, 30, lrun.mday); + set_bits(0, 5, lrun.wom); + set_bits(0, 53, lrun.woy); + break; case s_daily: - clear_defaults(); - set_bits(0, 30, lrun.mday); - set_bits(0, 11, lrun.month); - set_bits(0, 4, lrun.wpos); - break; + have_mday = true; + set_bits(0, 6, lrun.wday); + break; case s_monthly: - clear_defaults(); - set_bits(0, 11, lrun.month); - set_bits(0, 4, lrun.wpos); - break; + have_month = true; + set_bits(0, 11, lrun.month); + break; default: scan_err0(lc, _("Unexpected run state\n")); - /* NOT REACHED */ - break; + /* NOT REACHED */ + break; } } /* Allocate run record, copy new stuff into it, - * and link it into the list of run records + * and append it to the list of run records * in the schedule resource. */ if (pass == 2) { - trun = (RUN *)malloc(sizeof(RUN)); - memcpy(trun, &lrun, sizeof(RUN)); - if (*run) { - trun->next = *run; + RUN *tail; + + /* Create new run record */ + RUN *nrun = (RUN *)malloc(sizeof(RUN)); + memcpy(nrun, &lrun, sizeof(RUN)); + nrun ->next = NULL; + + if (!*run) { /* if empty list */ + *run = nrun; /* add new record */ + } else { + for (tail = *run; tail->next; tail=tail->next) + { } + tail->next = nrun; } - *run = trun; } - lc->options = options; /* restore scanner options */ + lc->options = options; /* restore scanner options */ set_bit(index, res_all.res_sch.hdr.item_present); }