static const char DowAry[] ALIGN1 =
"sun""mon""tue""wed""thu""fri""sat"
/* "Sun""Mon""Tue""Wed""Thu""Fri""Sat" */
;
static const char MonAry[] ALIGN1 =
"jan""feb""mar""apr""may""jun""jul""aug""sep""oct""nov""dec"
/* "Jan""Feb""Mar""Apr""May""Jun""Jul""Aug""Sep""Oct""Nov""Dec" */
;
static void ParseField(char *user, char *ary, int modvalue, int off,
const char *names, char *ptr)
/* 'names' is a pointer to a set of 3-char abbreviations */
{
char *base = ptr;
int n1 = -1;
int n2 = -1;
// this can't happen due to config_read()
/*if (base == NULL)
return;*/
while (1) {
int skip = 0;
/* Handle numeric digit or symbol or '*' */
if (*ptr == '*') {
n1 = 0; /* everything will be filled */
n2 = modvalue - 1;
skip = 1;
++ptr;
} else if (isdigit(*ptr)) {
if (n1 < 0) {
n1 = strtol(ptr, &ptr, 10) + off;
} else {
n2 = strtol(ptr, &ptr, 10) + off;
}
skip = 1;
} else if (names) {
int i;
for (i = 0; names[i]; i += 3) {
/* was using strncmp before... */
if (strncasecmp(ptr, &names[i], 3) == 0) {
ptr += 3;
if (n1 < 0) {
n1 = i / 3;
} else {
n2 = i / 3;
}
skip = 1;
break;
}
}
}
/* handle optional range '-' */
if (skip == 0) {
goto err;
}
if (*ptr == '-' && n2 < 0) {
++ptr;
continue;
}
/*
* collapse single-value ranges, handle skipmark, and fill
* in the character array appropriately.
*/
if (n2 < 0) {
n2 = n1;
}
if (*ptr == '/') {
skip = strtol(ptr + 1, &ptr, 10);
}
/*
* fill array, using a failsafe is the easiest way to prevent
* an endless loop
*/
{
int s0 = 1;
int failsafe = 1024;
--n1;
do {
n1 = (n1 + 1) % modvalue;
if (--s0 == 0) {
ary[n1 % modvalue] = 1;
s0 = skip;
}
if (--failsafe == 0) {
goto err;
}
} while (n1 != n2);
}
if (*ptr != ',') {
break;
}
++ptr;
n1 = -1;
n2 = -1;
}
if (*ptr) {
err:
crondlog(WARN9 "user %s: parse error at %s", user, base);
return;
}
if (DebugOpt && (LogLevel <= 5)) { /* like LVL5 */
/* can't use crondlog, it inserts '\n' */
int i;
for (i = 0; i < modvalue; ++i)
fprintf(stderr, "%d", (unsigned char)ary[i]);
fputc('\n', stderr);
}
}
static void SynchronizeFile(const char *fileName)
{
struct parser_t *parser;
struct stat sbuf;
int maxLines;
char *tokens[6];
#if ENABLE_FEATURE_CROND_CALL_SENDMAIL
char *mailTo = NULL;
#endif
if (!fileName)
return;
DeleteFile(fileName);
parser = config_open(fileName);
if (!parser)
return;
maxLines = (strcmp(fileName, "root") == 0) ? 65535 : MAXLINES;
if (fstat(fileno(parser->fp), &sbuf) == 0 && sbuf.st_uid == DaemonUid) {
CronFile *file = xzalloc(sizeof(CronFile));
CronLine **pline;
int n;
file->cf_User = xstrdup(fileName);
pline = &file->cf_LineBase;
while (1) {
CronLine *line;
if (!--maxLines)
break;
n = config_read(parser, tokens, 6, 1, "# \t", PARSE_NORMAL | PARSE_KEEP_COPY);
if (!n)
break;
if (DebugOpt)
crondlog(LVL5 "user:%s entry:%s", fileName, parser->data);
/* check if line is setting MAILTO= */
if (0 == strncmp(tokens[0], "MAILTO=", 7)) {
#if ENABLE_FEATURE_CROND_CALL_SENDMAIL
free(mailTo);
mailTo = (tokens[0][7]) ? xstrdup(&tokens[0][7]) : NULL;
#endif /* otherwise just ignore such lines */
continue;
}
/* check if a minimum of tokens is specified */
if (n < 6)
continue;
*pline = line = xzalloc(sizeof(*line));
/* parse date ranges */
ParseField(file->cf_User, line->cl_Mins, 60, 0, NULL, tokens[0]);
ParseField(file->cf_User, line->cl_Hrs, 24, 0, NULL, tokens[1]);
ParseField(file->cf_User, line->cl_Days, 32, 0, NULL, tokens[2]);
ParseField(file->cf_User, line->cl_Mons, 12, -1, MonAry, tokens[3]);
ParseField(file->cf_User, line->cl_Dow, 7, 0, DowAry, tokens[4]);
/*
* fix days and dow - if one is not "*" and the other
* is "*", the other is set to 0, and vise-versa
*/
FixDayDow(line);
#if ENABLE_FEATURE_CROND_CALL_SENDMAIL
/* copy mailto (can be NULL) */
line->cl_MailTo = xstrdup(mailTo);
#endif
/* copy command */
line->cl_Shell = xstrdup(tokens[5]);
if (DebugOpt) {
crondlog(LVL5 " command:%s", tokens[5]);
}
pline = &line->cl_Next;
//bb_error_msg("M[%s]F[%s][%s][%s][%s][%s][%s]", mailTo, tokens[0], tokens[1], tokens[2], tokens[3], tokens[4], tokens[5]);
}
*pline = NULL;
file->cf_Next = FileBase;
FileBase = file;
if (maxLines == 0) {
crondlog(WARN9 "user %s: too many lines", fileName);
}
}
config_close(parser);
}