/** %a, %c, %t: ctime() */ static int bfs_printf_ctime(FILE *file, const struct bfs_printf *directive, struct BFTW *ftwbuf) { // Not using ctime() itself because GNU find adds nanoseconds static const char *days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; static const char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; const struct bfs_stat *statbuf = bftw_stat(ftwbuf, ftwbuf->stat_flags); if (!statbuf) { return -1; } const struct timespec *ts = bfs_stat_time(statbuf, directive->stat_field); if (!ts) { return -1; } struct tm tm; if (xlocaltime(&ts->tv_sec, &tm) != 0) { return -1; } BFS_PRINTF_BUF(buf, "%s %s %2d %.2d:%.2d:%.2d.%09ld0 %4d", days[tm.tm_wday], months[tm.tm_mon], tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, (long)ts->tv_nsec, 1900 + tm.tm_year); return fprintf(file, directive->str, buf); }
/** %A, %B/%W, %C, %T: strftime() */ static int bfs_printf_strftime(FILE *file, const struct bfs_printf *directive, struct BFTW *ftwbuf) { const struct bfs_stat *statbuf = bftw_stat(ftwbuf, ftwbuf->stat_flags); if (!statbuf) { return -1; } const struct timespec *ts = bfs_stat_time(statbuf, directive->stat_field); if (!ts) { return -1; } struct tm tm; if (xlocaltime(&ts->tv_sec, &tm) != 0) { return -1; } int ret; char buf[256]; char format[] = "% "; switch (directive->c) { // Non-POSIX strftime() features case '@': ret = snprintf(buf, sizeof(buf), "%lld.%09ld0", (long long)ts->tv_sec, (long)ts->tv_nsec); break; case '+': ret = snprintf(buf, sizeof(buf), "%4d-%.2d-%.2d+%.2d:%.2d:%.2d.%09ld0", 1900 + tm.tm_year, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, (long)ts->tv_nsec); break; case 'k': ret = snprintf(buf, sizeof(buf), "%2d", tm.tm_hour); break; case 'l': ret = snprintf(buf, sizeof(buf), "%2d", (tm.tm_hour + 11)%12 + 1); break; case 's': ret = snprintf(buf, sizeof(buf), "%lld", (long long)ts->tv_sec); break; case 'S': ret = snprintf(buf, sizeof(buf), "%.2d.%09ld0", tm.tm_sec, (long)ts->tv_nsec); break; case 'T': ret = snprintf(buf, sizeof(buf), "%.2d:%.2d:%.2d.%09ld0", tm.tm_hour, tm.tm_min, tm.tm_sec, (long)ts->tv_nsec); break; // POSIX strftime() features default: format[1] = directive->c; ret = strftime(buf, sizeof(buf), format, &tm); break; } assert(ret >= 0 && ret < sizeof(buf)); (void)ret; return fprintf(file, directive->str, buf); }
uschar * tod_stamp(int type) { time_t now = time(NULL); struct tm *t; /* Vary log type according to timezone requirement */ if (type == tod_log) type = log_timezone? tod_log_zone : tod_log_bare; /* Styles that don't need local time */ else if (type == tod_epoch) { (void) sprintf(CS timebuf, "%d", (int)now); /* Unix epoch format */ return timebuf; } else if (type == tod_zulu) { #if defined(MOSBENCH_NO_TZ_LOCK) t = xlocaltime(&now); #else t = gmtime(&now); #endif (void) sprintf(CS timebuf, "%04d%02d%02d%02d%02d%02dZ", 1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); return timebuf; } /* Convert to local time or UTC */ #if defined(MOSBENCH_NO_TZ_LOCK) t = xlocaltime(&now); #else t = timestamps_utc? gmtime(&now) : localtime(&now); #endif switch(type) { case tod_log_bare: /* Format used in logging without timezone */ (void) sprintf(CS timebuf, "%04d-%02d-%02d %02d:%02d:%02d", 1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); break; /* Format used as suffix of log file name when 'log_datestamp' is active. For testing purposes, it changes the file every second. */ case tod_log_datestamp: #ifdef TESTING_LOG_DATESTAMP (void) sprintf(CS timebuf, "%04d%02d%02d%02d%02d", 1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min); #else (void) sprintf(CS timebuf, "%04d%02d%02d", 1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday); #endif break; /* Format used in BSD inbox separator lines. Sort-of documented in RFC 976 ("UUCP Mail Interchange Format Standard") but only by example, not by explicit definition. The examples show no timezone offsets, and some MUAs appear to be sensitive to this, so Exim has been changed to remove the timezone offsets that originally appeared. */ case tod_bsdin: { int len = Ustrftime(timebuf, sizeof(timebuf), "%a %b %d %H:%M:%S", t); Ustrftime(timebuf + len, sizeof(timebuf) - len, " %Y", t); } break; /* Other types require the GMT offset to be calculated, or just set up in the case of UTC timestamping. We need to take a copy of the local time first. */ default: { int diff_hour, diff_min; struct tm local; memcpy(&local, t, sizeof(struct tm)); if (timestamps_utc) { diff_hour = diff_min = 0; } else { #if defined(MOSBENCH_NO_TZ_LOCK) struct tm *gmt = xlocaltime(&now); #else struct tm *gmt = gmtime(&now); #endif diff_min = 60*(local.tm_hour - gmt->tm_hour) + local.tm_min - gmt->tm_min; if (local.tm_year != gmt->tm_year) diff_min += (local.tm_year > gmt->tm_year)? 1440 : -1440; else if (local.tm_yday != gmt->tm_yday) diff_min += (local.tm_yday > gmt->tm_yday)? 1440 : -1440; diff_hour = diff_min/60; diff_min = abs(diff_min - diff_hour*60); } switch(type) { case tod_log_zone: /* Format used in logging with timezone */ (void) sprintf(CS timebuf, "%04d-%02d-%02d %02d:%02d:%02d %+03d%02d", 1900 + local.tm_year, 1 + local.tm_mon, local.tm_mday, local.tm_hour, local.tm_min, local.tm_sec, diff_hour, diff_min); break; case tod_zone: /* Just the timezone offset */ (void) sprintf(CS timebuf, "%+03d%02d", diff_hour, diff_min); break; /* tod_mbx: format used in MBX mailboxes - subtly different to tod_full */ #ifdef SUPPORT_MBX case tod_mbx: { int len; (void) sprintf(CS timebuf, "%02d-", local.tm_mday); len = Ustrlen(timebuf); len += Ustrftime(timebuf + len, sizeof(timebuf) - len, "%b-%Y %H:%M:%S", &local); (void) sprintf(CS timebuf + len, " %+03d%02d", diff_hour, diff_min); } break; #endif /* tod_full: format used in Received: headers (use as default just in case called with a junk type value) */ default: { int len = Ustrftime(timebuf, sizeof(timebuf), "%a, ", &local); (void) sprintf(CS timebuf + len, "%02d ", local.tm_mday); len += Ustrlen(timebuf + len); len += Ustrftime(timebuf + len, sizeof(timebuf) - len, "%b %Y %H:%M:%S", &local); (void) sprintf(CS timebuf + len, " %+03d%02d", diff_hour, diff_min); } break; } } break; } return timebuf; }