Deleted Added
full compact
57c57
< __FBSDID("$FreeBSD: head/usr.sbin/newsyslog/newsyslog.c 208649 2010-05-29 22:55:59Z gordon $");
---
> __FBSDID("$FreeBSD: head/usr.sbin/newsyslog/newsyslog.c 210372 2010-07-22 11:23:18Z simon $");
71a72
> #include <assert.h>
74a76
> #include <dirent.h>
82a85
> #include <libgen.h>
114a118
> #define DEFAULT_TIMEFNAME_FMT "%Y%m%dT%H%M%S"
115a120,121
> #define MAX_OLDLOGS 65536 /* Default maximum number of old logfiles */
>
157a164,168
> struct oldlog_entry {
> char *fname; /* Filename of the log file */
> time_t t; /* Parses timestamp of the logfile */
> };
>
184a196
> char *timefnamefmt = NULL; /* Use time based filenames instead of .0 etc */
588c600
< while ((ch = getopt(argc, argv, "a:d:f:nrsvCD:FNPR:")) != -1)
---
> while ((ch = getopt(argc, argv, "a:d:f:nrst:vCD:FNPR:")) != -1)
608a621,627
> case 't':
> if (optarg[0] == '\0' ||
> strcmp(optarg, "DEFAULT") == 0)
> timefnamefmt = strdup(DEFAULT_TIMEFNAME_FMT);
> else
> timefnamefmt = strdup(optarg);
> break;
731c750
< " [ [-R requestor] filename ... ]\n");
---
> " [-t timefmt ] [ [-R requestor] filename ... ]\n");
1367a1387,1557
> * In our sort we return it in the reverse of what qsort normally
> * would do, as we want the newest files first. If we have two
> * entries with the same time we don't really care about order.
> *
> * Support function for qsort() in delete_oldest_timelog().
> */
> static int
> oldlog_entry_compare(const void *a, const void *b)
> {
> const struct oldlog_entry *ola = a, *olb = b;
>
> if (ola->t > olb->t)
> return (-1);
> else if (ola->t < olb->t)
> return (1);
> else
> return (0);
> }
>
> /*
> * Delete the oldest logfiles, when using time based filenames.
> */
> static void
> delete_oldest_timelog(const struct conf_entry *ent, const char *archive_dir)
> {
> char *logfname, *s, *dir, errbuf[80];
> int logcnt, max_logcnt, dirfd, i;
> struct oldlog_entry *oldlogs;
> size_t logfname_len;
> struct dirent *dp;
> const char *cdir;
> struct tm tm;
> DIR *dirp;
>
> oldlogs = malloc(MAX_OLDLOGS * sizeof(struct oldlog_entry));
> max_logcnt = MAX_OLDLOGS;
> logcnt = 0;
>
> if (archive_dir != NULL && archive_dir[0] != '\0')
> cdir = archive_dir;
> else
> if ((cdir = dirname(ent->log)) == NULL)
> err(1, "dirname()");
> if ((dir = strdup(cdir)) == NULL)
> err(1, "strdup()");
>
> if ((s = basename(ent->log)) == NULL)
> err(1, "basename()");
> if ((logfname = strdup(s)) == NULL)
> err(1, "strdup()");
> logfname_len = strlen(logfname);
> if (strcmp(logfname, "/") == 0)
> errx(1, "Invalid log filename - became '/'");
>
> if (verbose > 2)
> printf("Searching for old logs in %s\n", dir);
>
> /* First we create a 'list' of all archived logfiles */
> if ((dirp = opendir(dir)) == NULL)
> err(1, "Cannot open log directory '%s'", dir);
> dirfd = dirfd(dirp);
> while ((dp = readdir(dirp)) != NULL) {
> if (dp->d_type != DT_REG)
> continue;
>
> /* Ignore everything but files with our logfile prefix */
> if (strncmp(dp->d_name, logfname, logfname_len) != 0)
> continue;
> /* Ignore the actual non-rotated logfile */
> if (dp->d_namlen == logfname_len)
> continue;
> /*
> * Make sure we created have found a logfile, so the
> * postfix is valid, IE format is: '.<time>(.[bg]z)?'.
> */
> if (dp->d_name[logfname_len] != '.') {
> if (verbose)
> printf("Ignoring %s which has unexpected "
> "extension '%s'\n", dp->d_name,
> &dp->d_name[logfname_len]);
> continue;
> }
> if ((s = strptime(&dp->d_name[logfname_len + 1],
> timefnamefmt, &tm)) == NULL) {
> /*
> * We could special case "old" sequentially
> * named logfiles here, but we do not as that
> * would require special handling to decide
> * which one was the oldest compared to "new"
> * time based logfiles.
> */
> if (verbose)
> printf("Ignoring %s which does not "
> "match time format\n", dp->d_name);
> continue;
> }
> if (*s != '\0' && !(strcmp(s, BZCOMPRESS_POSTFIX) == 0 ||
> strcmp(s, COMPRESS_POSTFIX) == 0)) {
> if (verbose)
> printf("Ignoring %s which has unexpected "
> "extension '%s'\n", dp->d_name, s);
> continue;
> }
>
> /*
> * We should now have old an old rotated logfile, so
> * add it to the 'list'.
> */
> if ((oldlogs[logcnt].t = timegm(&tm)) == -1)
> err(1, "Could not convert time string to time value");
> if ((oldlogs[logcnt].fname = strdup(dp->d_name)) == NULL)
> err(1, "strdup()");
> logcnt++;
>
> /*
> * It is very unlikely we ever run out of space in the
> * logfile array from the default size, but lets
> * handle it anyway...
> */
> if (logcnt >= max_logcnt) {
> max_logcnt *= 4;
> /* Detect integer overflow */
> if (max_logcnt < logcnt)
> errx(1, "Too many old logfiles found");
> oldlogs = realloc(oldlogs,
> max_logcnt * sizeof(struct oldlog_entry));
> if (oldlogs == NULL)
> err(1, "realloc()");
> }
> }
>
> /* Second, if needed we delete oldest archived logfiles */
> if (logcnt > 0 && logcnt >= ent->numlogs && ent->numlogs > 1) {
> oldlogs = realloc(oldlogs, logcnt *
> sizeof(struct oldlog_entry));
> if (oldlogs == NULL)
> err(1, "realloc()");
>
> /*
> * We now sort the logs in the order of newest to
> * oldest. That way we can simply skip over the
> * number of records we want to keep.
> */
> qsort(oldlogs, logcnt, sizeof(struct oldlog_entry),
> oldlog_entry_compare);
> for (i = ent->numlogs - 1; i < logcnt; i++) {
> if (noaction)
> printf("\trm -f %s/%s\n", dir,
> oldlogs[i].fname);
> else if (unlinkat(dirfd, oldlogs[i].fname, 0) != 0) {
> snprintf(errbuf, sizeof(errbuf),
> "Could not delet old logfile '%s'",
> oldlogs[i].fname);
> perror(errbuf);
> }
> }
> } else if (verbose > 1)
> printf("No old logs to delete for logfile %s\n", ent->log);
>
> /* Third, cleanup */
> closedir(dirp);
> for (i = 0; i < logcnt; i++) {
> assert(oldlogs[i].fname != NULL);
> free(oldlogs[i].fname);
> }
> free(oldlogs);
> free(logfname);
> free(dir);
> }
>
> /*
1400a1591
> char datetimestr[30];
1404a1596,1597
> struct tm tm;
> time_t now;
1438,1441d1630
< (void) snprintf(zfile1, sizeof(zfile1), "%s%s", file1,
< COMPRESS_POSTFIX);
< snprintf(jfile1, sizeof(jfile1), "%s%s", file1,
< BZCOMPRESS_POSTFIX);
1442a1632,1637
> /*
> * Tell delete_oldest_timelog() we are not using an
> * archive dir.
> */
> dirpart[0] = '\0';
>
1445a1641,1647
> }
>
> /* Delete old logs */
> if (timefnamefmt != NULL)
> delete_oldest_timelog(ent, dirpart);
> else {
> /* name of oldest log */
1450d1651
< }
1452,1459c1653,1661
< if (noaction) {
< printf("\trm -f %s\n", file1);
< printf("\trm -f %s\n", zfile1);
< printf("\trm -f %s\n", jfile1);
< } else {
< (void) unlink(file1);
< (void) unlink(zfile1);
< (void) unlink(jfile1);
---
> if (noaction) {
> printf("\trm -f %s\n", file1);
> printf("\trm -f %s\n", zfile1);
> printf("\trm -f %s\n", jfile1);
> } else {
> (void) unlink(file1);
> (void) unlink(zfile1);
> (void) unlink(jfile1);
> }
1461a1664,1682
> if (timefnamefmt != NULL) {
> /* If time functions fails we can't really do any sensible */
> if (time(&now) == (time_t)-1 ||
> localtime_r(&now, &tm) == NULL)
> bzero(&tm, sizeof(tm));
>
> strftime(datetimestr, sizeof(datetimestr), timefnamefmt, &tm);
> if (archtodir)
> (void) snprintf(file1, sizeof(file1), "%s/%s.%s",
> dirpart, namepart, datetimestr);
> else
> (void) snprintf(file1, sizeof(file1), "%s.%s",
> ent->log, datetimestr);
>
> /* Don't run the code to move down logs */
> numlogs_c = 0;
> } else
> numlogs_c = ent->numlogs; /* copy for countdown */
>
1463d1683
< numlogs_c = ent->numlogs; /* copy for countdown */