/* **************************************************************************** * * Duration::parse - */ int64_t Duration::parse(void) { seconds = parse8601(string); valid = (seconds == -1)? false : true; return seconds; }
/* * Parse a configuration file and return a linked list of all the logs * to process */ struct conf_entry * parse_file(int *nentries) { char line[BUFSIZ], *parse, *q, *errline, *group, *tmp, *ep; struct conf_entry *working = NULL, *first = NULL; struct passwd *pwd; struct group *grp; struct stat sb; int lineno; FILE *f; long l; if (strcmp(conf, "-") == 0) f = stdin; else if ((f = fopen(conf, "r")) == NULL) err(1, "can't open %s", conf); *nentries = 0; for (lineno = 1; fgets(line, sizeof(line), f); lineno++) { tmp = sob(line); if (*tmp == '\0' || *tmp == '#') continue; errline = strdup(tmp); if (errline == NULL) err(1, "strdup"); (*nentries)++; if (!first) { working = malloc(sizeof(struct conf_entry)); if (working == NULL) err(1, "malloc"); first = working; } else { working->next = malloc(sizeof(struct conf_entry)); if (working->next == NULL) err(1, "malloc"); working = working->next; } q = parse = missing_field(sob(line), errline, lineno); *(parse = son(line)) = '\0'; working->log = strdup(q); if (working->log == NULL) err(1, "strdup"); if ((working->logbase = strrchr(working->log, '/')) != NULL) working->logbase++; q = parse = missing_field(sob(++parse), errline, lineno); *(parse = son(parse)) = '\0'; if ((group = strchr(q, ':')) != NULL || (group = strrchr(q, '.')) != NULL) { *group++ = '\0'; if (*q) { if (!(isnumberstr(q))) { if ((pwd = getpwnam(q)) == NULL) errx(1, "%s:%d: unknown user: %s", conf, lineno, q); working->uid = pwd->pw_uid; } else working->uid = atoi(q); } else working->uid = (uid_t)-1; q = group; if (*q) { if (!(isnumberstr(q))) { if ((grp = getgrnam(q)) == NULL) errx(1, "%s:%d: unknown group: %s", conf, lineno, q); working->gid = grp->gr_gid; } else working->gid = atoi(q); } else working->gid = (gid_t)-1; q = parse = missing_field(sob(++parse), errline, lineno); *(parse = son(parse)) = '\0'; } else { working->uid = (uid_t)-1; working->gid = (gid_t)-1; } l = strtol(q, &ep, 8); if (*ep != '\0' || l < 0 || l > ALLPERMS) errx(1, "%s:%d: bad permissions: %s", conf, lineno, q); working->permissions = (mode_t)l; q = parse = missing_field(sob(++parse), errline, lineno); *(parse = son(parse)) = '\0'; l = strtol(q, &ep, 10); if (*ep != '\0' || l < 0 || l >= INT_MAX) errx(1, "%s:%d: bad number: %s", conf, lineno, q); working->numlogs = (int)l; q = parse = missing_field(sob(++parse), errline, lineno); *(parse = son(parse)) = '\0'; if (isdigit(*q)) working->size = atoi(q) * 1024; else working->size = -1; working->flags = 0; q = parse = missing_field(sob(++parse), errline, lineno); *(parse = son(parse)) = '\0'; l = strtol(q, &ep, 10); if (l < 0 || l >= INT_MAX) errx(1, "%s:%d: interval out of range: %s", conf, lineno, q); working->hours = (int)l; switch (*ep) { case '\0': break; case '@': working->trim_at = parse8601(ep + 1); if (working->trim_at == (time_t) - 1) errx(1, "%s:%d: bad time: %s", conf, lineno, q); working->flags |= CE_TRIMAT; break; case '$': working->trim_at = parseDWM(ep + 1); if (working->trim_at == (time_t) - 1) errx(1, "%s:%d: bad time: %s", conf, lineno, q); working->flags |= CE_TRIMAT; break; case '*': if (q == ep) break; /* FALLTHROUGH */ default: errx(1, "%s:%d: bad interval/at: %s", conf, lineno, q); break; } q = sob(++parse); /* Optional field */ if (*q == 'Z' || *q == 'z' || *q == 'B' || *q == 'b' || *q == 'M' || *q == 'm') { *(parse = son(q)) = '\0'; while (*q) { switch (*q) { case 'Z': case 'z': working->flags |= CE_COMPACT; break; case 'B': case 'b': working->flags |= CE_BINARY; break; case 'M': case 'm': working->flags |= CE_MONITOR; break; case 'F': case 'f': working->flags |= CE_FOLLOW; break; default: errx(1, "%s:%d: illegal flag: `%c'", conf, lineno, *q); break; } q++; } } else parse--; /* no flags so undo */ working->pidfile = PIDFILE; working->signal = SIGHUP; working->runcmd = NULL; working->whom = NULL; for (;;) { q = parse = sob(++parse); /* Optional field */ if (q == NULL || *q == '\0') break; if (*q == '/') { *(parse = son(parse)) = '\0'; if (strlen(q) >= MAXPATHLEN) errx(1, "%s:%d: pathname too long: %s", conf, lineno, q); working->pidfile = strdup(q); if (working->pidfile == NULL) err(1, "strdup"); } else if (*q == '"' && (tmp = strchr(q + 1, '"'))) { *(parse = tmp) = '\0'; if (*++q != '\0') { working->runcmd = strdup(q); if (working->runcmd == NULL) err(1, "strdup"); } working->pidfile = NULL; working->signal = -1; } else if (strncmp(q, "SIG", 3) == 0) { int i; *(parse = son(parse)) = '\0'; for (i = 1; i < NSIG; i++) { if (!strcmp(sys_signame[i], q + 3)) { working->signal = i; break; } } if (i == NSIG) errx(1, "%s:%d: unknown signal: %s", conf, lineno, q); } else if (working->flags & CE_MONITOR) { *(parse = son(parse)) = '\0'; working->whom = strdup(q); if (working->whom == NULL) err(1, "strdup"); } else errx(1, "%s:%d: unrecognized field: %s", conf, lineno, q); } free(errline); if ((working->flags & CE_MONITOR) && working->whom == NULL) errx(1, "%s:%d: missing monitor notification field", conf, lineno); /* If there is an arcdir, set working->backdir. */ if (arcdir != NULL && working->logbase != NULL) { if (*arcdir == '/') { /* Fully qualified arcdir */ working->backdir = arcdir; } else { /* arcdir is relative to log's parent dir */ *(working->logbase - 1) = '\0'; if ((asprintf(&working->backdir, "%s/%s", working->log, arcdir)) == -1) err(1, "malloc"); *(working->logbase - 1) = '/'; } /* Ignore arcdir if it doesn't exist. */ if (stat(working->backdir, &sb) != 0 || !S_ISDIR(sb.st_mode)) { if (working->backdir != arcdir) free(working->backdir); working->backdir = NULL; } } else working->backdir = NULL; /* Make sure we can't oflow MAXPATHLEN */ if (working->backdir != NULL) { if (snprintf(line, sizeof(line), "%s/%s.%d%s", working->backdir, working->logbase, working->numlogs, COMPRESS_POSTFIX) >= MAXPATHLEN) errx(1, "%s:%d: pathname too long: %s", conf, lineno, q); } else { if (snprintf(line, sizeof(line), "%s.%d%s", working->log, working->numlogs, COMPRESS_POSTFIX) >= MAXPATHLEN) errx(1, "%s:%d: pathname too long: %s", conf, lineno, working->log); } } if (working) working->next = NULL; (void)fclose(f); return (first); }
int ptime_relparse(struct ptime_data *ptime, int parseopts, time_t basetime, const char *str) { int dpm, pres; struct tm temp_tm; ptime->parseopts = parseopts; ptime->basesecs = basetime; ptime->basetm = *(localtime(&ptime->basesecs)); ptime->tm = ptime->basetm; ptime->tm.tm_hour = ptime->tm.tm_min = ptime->tm.tm_sec = 0; /* * Call a routine which sets ptime.tm and ptime.tspecs based * on the given string and parsing-options. Note that the * routine should not call mktime to set ptime.tsecs. */ if (parseopts & PTM_PARSE_DWM) pres = parseDWM(ptime, str); else pres = parse8601(ptime, str); if (pres < 0) { ptime->tsecs = (time_t)pres; return (pres); } /* * Before calling mktime, check to see if we ended up with a * "day-of-month" that does not exist in the selected month. * If we did call mktime with that info, then mktime will * make it look like the user specifically requested a day * in the following month (eg: Feb 31 turns into Mar 3rd). */ dpm = days_pmonth(ptime->tm.tm_mon, ptime->tm.tm_year); if ((parseopts & PTM_PARSE_MATCHDOM) && (ptime->tmspec & TSPEC_DAYOFMONTH) && (ptime->tm.tm_mday> dpm)) { /* * ptime_nxtime() will want a ptime->tsecs value, * but we need to avoid mktime resetting all the * ptime->tm values. */ if (verbose && dbg_at_times > 1) fprintf(stderr, "\t-- dom fixed: %4d/%02d/%02d %02d:%02d (%02d)", ptime->tm.tm_year, ptime->tm.tm_mon, ptime->tm.tm_mday, ptime->tm.tm_hour, ptime->tm.tm_min, dpm); temp_tm = ptime->tm; ptime->tsecs = mktime(&temp_tm); if (ptime->tsecs > (time_t)-1) ptimeset_nxtime(ptime); if (verbose && dbg_at_times > 1) fprintf(stderr, " to: %4d/%02d/%02d %02d:%02d\n", ptime->tm.tm_year, ptime->tm.tm_mon, ptime->tm.tm_mday, ptime->tm.tm_hour, ptime->tm.tm_min); } /* * Convert the ptime.tm into standard time_t seconds. Check * for invalid times, which includes things like the hour lost * when switching from "standard time" to "daylight saving". */ ptime->tsecs = mktime(&ptime->tm); if (ptime->tsecs == (time_t)-1) { ptime->tsecs = (time_t)-2; return (-2); } return (0); }
/* **************************************************************************** * * parse8601 - */ TEST(commonGlobals, parse8601) { int secs; const int oneYear = 365 * 24 * 3600 * 1; const int oneMonth = 30 * 24 * 3600 * 1; const int oneWeek = 7 * 24 * 3600 * 1; const int oneDay = 24 * 3600 * 1; const int oneHour = 3600 * 1; const int oneMinute = 60 * 1; const int oneSecond = 1; const int twoYears = 365 * 24 * 3600 * 2; const int twoMonths = 30 * 24 * 3600 * 2; const int twoWeeks = oneWeek * 2; const int twoDays = 24 * 3600 * 2; const int twoHours = 3600 * 2; const int twoMinutes = 60 * 2; const int twoSeconds = oneSecond * 2; const int threeYearsOneMonthOneDayOneHourOneMinuteAndElevenSeconds = 3 * oneYear + oneMonth + oneDay + oneHour + oneMinute + 11; secs = parse8601("P2Y"); EXPECT_EQ(twoYears, secs) << "bad value for two years"; secs = parse8601("PT2Y"); EXPECT_EQ(-1, secs) << "PT2Y should return -1 - parse error ..."; secs = parse8601("P2M"); EXPECT_EQ(twoMonths, secs) << "bad value for two months"; secs = parse8601("P2W"); EXPECT_EQ(twoWeeks, secs) << "bad value for two weeks"; secs = parse8601("PT2W"); EXPECT_EQ(-1, secs) << "PT2W should return -1 - parse error ..."; secs = parse8601("P2D"); EXPECT_EQ(twoDays, secs) << "bad value for two days"; secs = parse8601("PT2D"); EXPECT_EQ(-1, secs) << "PT2D should return -1 - parse error ..."; secs = parse8601("PT2H"); EXPECT_EQ(twoHours, secs) << "bad value for two hours"; secs = parse8601("P2H"); EXPECT_EQ(-1, secs) << "P2H should return -1 - parse error ..."; secs = parse8601("PT2M"); EXPECT_EQ(twoMinutes, secs) << "bad value for two minutes"; secs = parse8601("PT2S"); EXPECT_EQ(twoSeconds, secs) << "bad value for two seconds"; secs = parse8601("P2S"); EXPECT_EQ(-1, secs) << "P2S should return -1 - parse error ..."; secs = parse8601("P3Y1M1DT1H1M11S"); EXPECT_EQ(threeYearsOneMonthOneDayOneHourOneMinuteAndElevenSeconds, secs) << "parse error for 'P3Y1M1DT1H1M11S'"; }
/* **************************************************************************** * * Throttling::parse - */ int64_t Throttling::parse(void) { seconds = parse8601(string); return seconds; }