1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-06 04:31:29 +00:00

Replace localtime calls with thread-safe alternative. See #1834

This commit is contained in:
dmiller
2019-12-15 05:05:57 +00:00
parent 6995af0743
commit 4a1c9424d3
10 changed files with 132 additions and 49 deletions

11
nbase/configure vendored
View File

@@ -4255,7 +4255,7 @@ fi
done done
for ac_func in usleep gettimeofday sleep for ac_func in usleep gettimeofday sleep localtime_s localtime_r
do : do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
@@ -4264,16 +4264,15 @@ if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
_ACEOF _ACEOF
else fi
case " $LIBOBJS " in done
case " $LIBOBJS " in
*" nbase_time.$ac_objext "* ) ;; *" nbase_time.$ac_objext "* ) ;;
*) LIBOBJS="$LIBOBJS nbase_time.$ac_objext" *) LIBOBJS="$LIBOBJS nbase_time.$ac_objext"
;; ;;
esac esac
fi
done
ac_fn_c_check_func "$LINENO" "getopt_long_only" "ac_cv_func_getopt_long_only" ac_fn_c_check_func "$LINENO" "getopt_long_only" "ac_cv_func_getopt_long_only"
if test "x$ac_cv_func_getopt_long_only" = xyes; then : if test "x$ac_cv_func_getopt_long_only" = xyes; then :

View File

@@ -157,8 +157,9 @@ fi
AC_CHECK_FUNCS( getopt getopt_long_only) AC_CHECK_FUNCS( getopt getopt_long_only)
AC_CHECK_FUNCS(usleep gettimeofday sleep, , AC_CHECK_FUNCS(usleep gettimeofday sleep localtime_s localtime_r)
[ AC_LIBOBJ([nbase_time]) ]) dnl Some of these time functions are always needed
AC_LIBOBJ([nbase_time])
AC_CHECK_FUNC(getopt_long_only, , AC_CHECK_FUNC(getopt_long_only, ,
[ AC_LIBOBJ([getopt]) ]) [ AC_LIBOBJ([getopt]) ])

View File

@@ -186,6 +186,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <ctype.h> #include <ctype.h>
#include <time.h>
#if HAVE_SYS_SELECT_H #if HAVE_SYS_SELECT_H
#include <sys/select.h> #include <sys/select.h>
@@ -357,6 +358,7 @@ extern "C" int vsnprintf (char *, size_t, const char *, va_list);
#define open _open #define open _open
#define stricmp _stricmp #define stricmp _stricmp
#define putenv _putenv #define putenv _putenv
#define tzset _tzset
#if !defined(__GNUC__) #if !defined(__GNUC__)
#define snprintf _snprintf #define snprintf _snprintf
@@ -453,6 +455,10 @@ void usleep(unsigned long usec);
#endif #endif
#endif #endif
/* localtime is not thread safe. This will use a thread safe alternative on
* supported platforms. */
int n_localtime(const time_t *timer, struct tm *result);
/***************** String functions -- See nbase_str.c ******************/ /***************** String functions -- See nbase_str.c ******************/
/* I modified this conditional because !@# Redhat does not easily provide /* I modified this conditional because !@# Redhat does not easily provide
the prototype even though the function exists */ the prototype even though the function exists */

View File

@@ -153,6 +153,43 @@ nanosleep(&ts, NULL);
} }
#endif #endif
/* Thread safe time stuff */
#ifdef WIN32
/* On Windows, use CRT function localtime_s:
* errno_t localtime_s(
* struct tm* const tmDest,
* time_t const* const sourceTime
* );
*/
#define n_localtime(timer, result) localtime_s(result, timer)
#else
#include <errno.h>
int n_localtime(const time_t *timer, struct tm *result) {
#ifdef HAVE_LOCALTIME_S
/* C11 localtime_s similar to Posix localtime_r, but with validity checking:
* struct tm *localtime_s(const time_t *restrict time, struct tm *restrict result);
*/
struct tm *tmp = localtime_s(timer, result);
#else
#ifdef HAVE_LOCALTIME_R
/* POSIX localtime_r thread-safe localtime function:
* struct tm *localtime_r(const time_t *timep, struct tm *result);
*/
struct tm *tmp = localtime_r(timer, result);
#else
/* No thread-safe alternative; use localtime. */
struct tm *tmp = localtime(timer);
if (tmp)
*result = *tmp;
#endif
#endif
if (!tmp) {
return errno;
}
return 0;
}
#endif
#ifdef WIN32 #ifdef WIN32
int gettimeofday(struct timeval *tv, struct timeval *tz) int gettimeofday(struct timeval *tv, struct timeval *tz)
{ {

37
nmap.cc
View File

@@ -556,7 +556,7 @@ public:
} delayed_options; } delayed_options;
struct tm *local_time; struct tm local_time;
static void test_file_name(const char *filename, const char *option) { static void test_file_name(const char *filename, const char *option) {
if (filename[0] == '-' && filename[1] != '\0') { if (filename[0] == '-' && filename[1] != '\0') {
@@ -922,29 +922,29 @@ void parse_options(int argc, char **argv) {
o.setXSLStyleSheet("https://svn.nmap.org/nmap/docs/nmap.xsl"); o.setXSLStyleSheet("https://svn.nmap.org/nmap/docs/nmap.xsl");
} else if (strcmp(long_options[option_index].name, "oN") == 0) { } else if (strcmp(long_options[option_index].name, "oN") == 0) {
test_file_name(optarg, long_options[option_index].name); test_file_name(optarg, long_options[option_index].name);
delayed_options.normalfilename = logfilename(optarg, local_time); delayed_options.normalfilename = logfilename(optarg, &local_time);
} else if (strcmp(long_options[option_index].name, "oG") == 0 } else if (strcmp(long_options[option_index].name, "oG") == 0
|| strcmp(long_options[option_index].name, "oM") == 0) { || strcmp(long_options[option_index].name, "oM") == 0) {
test_file_name(optarg, long_options[option_index].name); test_file_name(optarg, long_options[option_index].name);
delayed_options.machinefilename = logfilename(optarg, local_time); delayed_options.machinefilename = logfilename(optarg, &local_time);
if (long_options[option_index].name[1] == 'M') if (long_options[option_index].name[1] == 'M')
delayed_options.warn_deprecated("oM", "oG"); delayed_options.warn_deprecated("oM", "oG");
} else if (strcmp(long_options[option_index].name, "oS") == 0) { } else if (strcmp(long_options[option_index].name, "oS") == 0) {
test_file_name(optarg, long_options[option_index].name); test_file_name(optarg, long_options[option_index].name);
delayed_options.kiddiefilename = logfilename(optarg, local_time); delayed_options.kiddiefilename = logfilename(optarg, &local_time);
} else if (strcmp(long_options[option_index].name, "oH") == 0) { } else if (strcmp(long_options[option_index].name, "oH") == 0) {
fatal("HTML output is not directly supported, though Nmap includes an XSL for transforming XML output into HTML. See the man page."); fatal("HTML output is not directly supported, though Nmap includes an XSL for transforming XML output into HTML. See the man page.");
} else if (strcmp(long_options[option_index].name, "oX") == 0) { } else if (strcmp(long_options[option_index].name, "oX") == 0) {
test_file_name(optarg, long_options[option_index].name); test_file_name(optarg, long_options[option_index].name);
delayed_options.xmlfilename = logfilename(optarg, local_time); delayed_options.xmlfilename = logfilename(optarg, &local_time);
} else if (strcmp(long_options[option_index].name, "oA") == 0) { } else if (strcmp(long_options[option_index].name, "oA") == 0) {
char buf[MAXPATHLEN]; char buf[MAXPATHLEN];
test_file_name(optarg, long_options[option_index].name); test_file_name(optarg, long_options[option_index].name);
Snprintf(buf, sizeof(buf), "%s.nmap", logfilename(optarg, local_time)); Snprintf(buf, sizeof(buf), "%s.nmap", logfilename(optarg, &local_time));
delayed_options.normalfilename = strdup(buf); delayed_options.normalfilename = strdup(buf);
Snprintf(buf, sizeof(buf), "%s.gnmap", logfilename(optarg, local_time)); Snprintf(buf, sizeof(buf), "%s.gnmap", logfilename(optarg, &local_time));
delayed_options.machinefilename = strdup(buf); delayed_options.machinefilename = strdup(buf);
Snprintf(buf, sizeof(buf), "%s.xml", logfilename(optarg, local_time)); Snprintf(buf, sizeof(buf), "%s.xml", logfilename(optarg, &local_time));
delayed_options.xmlfilename = strdup(buf); delayed_options.xmlfilename = strdup(buf);
} else if (strcmp(long_options[option_index].name, "thc") == 0) { } else if (strcmp(long_options[option_index].name, "thc") == 0) {
log_write(LOG_STDOUT, "!!Greets to Van Hauser, Plasmoid, Skyper and the rest of THC!!\n"); log_write(LOG_STDOUT, "!!Greets to Van Hauser, Plasmoid, Skyper and the rest of THC!!\n");
@@ -1145,7 +1145,7 @@ void parse_options(int argc, char **argv) {
case 'm': case 'm':
delayed_options.warn_deprecated("m", "oG"); delayed_options.warn_deprecated("m", "oG");
test_file_name(optarg, "oG"); test_file_name(optarg, "oG");
delayed_options.machinefilename = logfilename(optarg, local_time); delayed_options.machinefilename = logfilename(optarg, &local_time);
break; break;
case 'n': case 'n':
o.noresolve = true; o.noresolve = true;
@@ -1161,7 +1161,7 @@ void parse_options(int argc, char **argv) {
case 'o': case 'o':
delayed_options.warn_deprecated("o", "oN"); delayed_options.warn_deprecated("o", "oN");
test_file_name(optarg, "o"); test_file_name(optarg, "o");
delayed_options.normalfilename = logfilename(optarg, local_time); delayed_options.normalfilename = logfilename(optarg, &local_time);
break; break;
case 'P': case 'P':
if (!optarg) { if (!optarg) {
@@ -1559,14 +1559,14 @@ void apply_delayed_options() {
o.reason = true; o.reason = true;
// ISO 8601 date/time -- http://www.cl.cam.ac.uk/~mgk25/iso-time.html // ISO 8601 date/time -- http://www.cl.cam.ac.uk/~mgk25/iso-time.html
if (strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %H:%M %Z", local_time) <= 0) if (strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %H:%M %Z", &local_time) <= 0)
fatal("Unable to properly format time"); fatal("Unable to properly format time");
log_write(LOG_STDOUT | LOG_SKID, "Starting %s %s ( %s ) at %s\n", NMAP_NAME, NMAP_VERSION, NMAP_URL, tbuf); log_write(LOG_STDOUT | LOG_SKID, "Starting %s %s ( %s ) at %s\n", NMAP_NAME, NMAP_VERSION, NMAP_URL, tbuf);
if (o.verbose) { if (o.verbose) {
if (local_time->tm_mon == 8 && local_time->tm_mday == 1) { if (local_time.tm_mon == 8 && local_time.tm_mday == 1) {
unsigned int a = (local_time->tm_year - 97)%100; unsigned int a = (local_time.tm_year - 97)%100;
log_write(LOG_STDOUT | LOG_SKID, "Happy %d%s Birthday to Nmap, may it live to be %d!\n", local_time->tm_year - 97,(a>=11&&a<=13?"th":(a%10==1?"st":(a%10==2?"nd":(a%10==3?"rd":"th")))), local_time->tm_year + 3); log_write(LOG_STDOUT | LOG_SKID, "Happy %d%s Birthday to Nmap, may it live to be %d!\n", local_time.tm_year - 97,(a>=11&&a<=13?"th":(a%10==1?"st":(a%10==2?"nd":(a%10==3?"rd":"th")))), local_time.tm_year + 3);
} else if (local_time->tm_mon == 11 && local_time->tm_mday == 25) { } else if (local_time.tm_mon == 11 && local_time.tm_mday == 25) {
log_write(LOG_STDOUT | LOG_SKID, "Nmap wishes you a merry Christmas! Specify -sX for Xmas Scan (https://nmap.org/book/man-port-scanning-techniques.html).\n"); log_write(LOG_STDOUT | LOG_SKID, "Nmap wishes you a merry Christmas! Specify -sX for Xmas Scan (https://nmap.org/book/man-port-scanning-techniques.html).\n");
} }
} }
@@ -1819,6 +1819,7 @@ int nmap_main(int argc, char *argv[]) {
char hostname[FQDN_LEN + 1] = ""; char hostname[FQDN_LEN + 1] = "";
struct sockaddr_storage ss; struct sockaddr_storage ss;
size_t sslen; size_t sslen;
int err;
#ifdef LINUX #ifdef LINUX
/* Check for WSL and warn that things may not go well. */ /* Check for WSL and warn that things may not go well. */
@@ -1832,8 +1833,12 @@ int nmap_main(int argc, char *argv[]) {
} }
#endif #endif
tzset();
now = time(NULL); now = time(NULL);
local_time = localtime(&now); err = n_localtime(&now, &local_time);
if (err) {
fatal("n_localtime failed: %s", strerror(err));
}
if (argc < 2){ if (argc < 2){
printusage(); printusage();

View File

@@ -165,7 +165,8 @@ void signal_handler(int signo);
* probe mode, echo client or echo server). */ * probe mode, echo client or echo server). */
int main(int argc, char *argv[] ){ int main(int argc, char *argv[] ){
struct tm *tm; /* For time display */ struct tm tm; /* For time display */
int err;
time_t now; /* Stores current time */ time_t now; /* Stores current time */
char tbuf[128]; /* Stores current time as a string */ char tbuf[128]; /* Stores current time as a string */
ArgParser a; /* Command line argument parser */ ArgParser a; /* Command line argument parser */
@@ -174,8 +175,11 @@ int main(int argc, char *argv[] ){
NpingTarget *t=NULL; NpingTarget *t=NULL;
/* Get current time */ /* Get current time */
tzset();
now = time(NULL); now = time(NULL);
tm = localtime(&now); err = n_localtime(&now, &tm);
if (err)
nping_fatal(QT_3,"Error in localtime: %s", strerror(err));
o.stats.startRuntime(); o.stats.startRuntime();
/* Some run-time tests to ensure everything works as expected */ /* Some run-time tests to ensure everything works as expected */
@@ -202,7 +206,7 @@ int main(int argc, char *argv[] ){
o.validateOptions(); o.validateOptions();
/* ISO 8601 date/time -- http://www.cl.cam.ac.uk/~mgk25/iso-time.html */ /* ISO 8601 date/time -- http://www.cl.cam.ac.uk/~mgk25/iso-time.html */
if ( strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %H:%M %Z", tm) <= 0) if ( strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %H:%M %Z", &tm) <= 0)
nping_fatal(QT_3,"Unable to properly format time"); nping_fatal(QT_3,"Unable to properly format time");
nping_print(QT_1, "\nStarting %s %s ( %s ) at %s", NPING_NAME, NPING_VERSION, NPING_URL, tbuf); nping_print(QT_1, "\nStarting %s %s ( %s ) at %s", NPING_NAME, NPING_VERSION, NPING_URL, tbuf);

View File

@@ -674,12 +674,15 @@ void WriteSInfo(char *ostr, int ostrlen, bool isGoodFP,
enum dist_calc_method distance_calculation_method, enum dist_calc_method distance_calculation_method,
const u8 *mac, int openTcpPort, const u8 *mac, int openTcpPort,
int closedTcpPort, int closedUdpPort) { int closedTcpPort, int closedUdpPort) {
struct tm *ltime; struct tm ltime;
int err;
time_t timep; time_t timep;
char dsbuf[10], otbuf[8], ctbuf[8], cubuf[8], dcbuf[8]; char dsbuf[10], otbuf[8], ctbuf[8], cubuf[8], dcbuf[8];
char macbuf[16]; char macbuf[16];
timep = time(NULL); timep = time(NULL);
ltime = localtime(&timep); err = n_localtime(&timep, &ltime);
if (err)
error("Error in localtime: %s", strerror(err));
otbuf[0] = '\0'; otbuf[0] = '\0';
if (openTcpPort != -1) if (openTcpPort != -1)
@@ -704,7 +707,7 @@ void WriteSInfo(char *ostr, int ostrlen, bool isGoodFP,
Snprintf(macbuf, sizeof(macbuf), "%%M=%02X%02X%02X", mac[0], mac[1], mac[2]); Snprintf(macbuf, sizeof(macbuf), "%%M=%02X%02X%02X", mac[0], mac[1], mac[2]);
Snprintf(ostr, ostrlen, "SCAN(V=%s%%E=%s%%D=%d/%d%%OT=%s%%CT=%s%%CU=%s%%PV=%c%s%s%%G=%c%s%%TM=%X%%P=%s)", Snprintf(ostr, ostrlen, "SCAN(V=%s%%E=%s%%D=%d/%d%%OT=%s%%CT=%s%%CU=%s%%PV=%c%s%s%%G=%c%s%%TM=%X%%P=%s)",
NMAP_VERSION, engine_id, ltime->tm_mon + 1, ltime->tm_mday, NMAP_VERSION, engine_id, err ? 0 : ltime.tm_mon + 1, err ? 0 : ltime.tm_mday,
otbuf, ctbuf, cubuf, isipprivate(addr) ? 'Y' : 'N', dsbuf, dcbuf, isGoodFP ? 'Y' : 'N', otbuf, ctbuf, cubuf, isipprivate(addr) ? 'Y' : 'N', dsbuf, dcbuf, isGoodFP ? 'Y' : 'N',
macbuf, (int) timep, NMAP_PLATFORM); macbuf, (int) timep, NMAP_PLATFORM);
} }

View File

@@ -645,16 +645,28 @@ void printportoutput(Target *currenths, PortList *plist) {
if (o.verbose > 1 || o.debugging) { if (o.verbose > 1 || o.debugging) {
time_t tm_secs, tm_sece; time_t tm_secs, tm_sece;
struct tm *tm; struct tm tm;
int err;
char tbufs[128]; char tbufs[128];
tm_secs = currenths->StartTime(); tm_secs = currenths->StartTime();
tm_sece = currenths->EndTime(); tm_sece = currenths->EndTime();
tm = localtime(&tm_secs); err = n_localtime(&tm_secs, &tm);
if (strftime(tbufs, sizeof(tbufs), "%Y-%m-%d %H:%M:%S %Z", tm) <= 0) if (err) {
fatal("Unable to properly format host start time"); error("Error in localtime: %s", strerror(err));
log_write(LOG_PLAIN, "Scanned for %lds\n",
log_write(LOG_PLAIN, "Scanned at %s for %lds\n", (long) (tm_sece - tm_secs));
tbufs, (long) (tm_sece - tm_secs)); }
else {
if (strftime(tbufs, sizeof(tbufs), "%Y-%m-%d %H:%M:%S %Z", &tm) <= 0) {
error("Unable to properly format host start time");
log_write(LOG_PLAIN, "Scanned for %lds\n",
(long) (tm_sece - tm_secs));
}
else {
log_write(LOG_PLAIN, "Scanned at %s for %lds\n",
tbufs, (long) (tm_sece - tm_secs));
}
}
} }
log_write(LOG_MACHINE, "Host: %s (%s)", currenths->targetipstr(), log_write(LOG_MACHINE, "Host: %s (%s)", currenths->targetipstr(),
currenths->HostName()); currenths->HostName());

View File

@@ -1725,8 +1725,9 @@ void ServiceNFO::addToServiceFingerprint(const char *probeName, const u8 *resp,
// the SF-PortXXXX-TCP stuff, etc // the SF-PortXXXX-TCP stuff, etc
int spaceneeded = respused * 5 + strlen(probeName) + 128; int spaceneeded = respused * 5 + strlen(probeName) + 128;
int srcidx; int srcidx;
struct tm *ltime; struct tm ltime;
time_t timep; time_t timep;
int err;
char buf[128]; char buf[128];
assert(resplen); assert(resplen);
@@ -1746,8 +1747,13 @@ void ServiceNFO::addToServiceFingerprint(const char *probeName, const u8 *resp,
if (servicefplen == 0) { if (servicefplen == 0) {
timep = time(NULL); timep = time(NULL);
ltime = localtime(&timep); err = n_localtime(&timep, &ltime);
Snprintf(buf, sizeof(buf), "SF-Port%hu-%s:V=%s%s%%I=%d%%D=%d/%d%%Time=%X%%P=%s", portno, proto2ascii_uppercase(proto), NMAP_VERSION, (tunnel == SERVICE_TUNNEL_SSL)? "%T=SSL" : "", o.version_intensity, ltime->tm_mon + 1, ltime->tm_mday, (int) timep, NMAP_PLATFORM); if (err)
error("Error in localtime: %s", strerror(err));
Snprintf(buf, sizeof(buf), "SF-Port%hu-%s:V=%s%s%%I=%d%%D=%d/%d%%Time=%X%%P=%s",
portno, proto2ascii_uppercase(proto), NMAP_VERSION,
(tunnel == SERVICE_TUNNEL_SSL)? "%T=SSL" : "", o.version_intensity,
err ? 0 : ltime.tm_mon + 1, err ? 0 : ltime.tm_mday, (int) timep, NMAP_PLATFORM);
addServiceString(buf, servicewrap); addServiceString(buf, servicewrap);
} }

View File

@@ -688,7 +688,8 @@ bool ScanProgressMeter::printStats(double perc_done,
struct timeval tvtmp; struct timeval tvtmp;
double time_left_s; double time_left_s;
time_t timet; time_t timet;
struct tm *ltime; struct tm ltime;
int err;
if (!now) { if (!now) {
gettimeofday(&tvtmp, NULL); gettimeofday(&tvtmp, NULL);
@@ -721,17 +722,17 @@ bool ScanProgressMeter::printStats(double perc_done,
/* Get the estimated time of day at completion */ /* Get the estimated time of day at completion */
timet = last_est.tv_sec; timet = last_est.tv_sec;
ltime = localtime(&timet); err = n_localtime(&timet, &ltime);
if (ltime) { if (!err) {
log_write(LOG_STDOUT, "%s Timing: About %.2f%% done; ETC: %02d:%02d (%.f:%02.f:%02.f remaining)\n", log_write(LOG_STDOUT, "%s Timing: About %.2f%% done; ETC: %02d:%02d (%.f:%02.f:%02.f remaining)\n",
scantypestr, perc_done * 100, ltime->tm_hour, ltime->tm_min, scantypestr, perc_done * 100, ltime.tm_hour, ltime.tm_min,
floor(time_left_s / 60.0 / 60.0), floor(time_left_s / 60.0 / 60.0),
floor(fmod(time_left_s / 60.0, 60.0)), floor(fmod(time_left_s / 60.0, 60.0)),
floor(fmod(time_left_s, 60.0))); floor(fmod(time_left_s, 60.0)));
} }
else { else {
log_write(LOG_STDERR, "Timing error: localtime(%f) is NULL\n", (double) timet); log_write(LOG_STDERR, "Timing error: n_localtime(%f): %s\n", (double) timet, strerror(err));
log_write(LOG_STDOUT, "%s Timing: About %.2f%% done; ETC: Unknown (%.f:%02.f:%02.f remaining)\n", log_write(LOG_STDOUT, "%s Timing: About %.2f%% done; ETC: Unknown (%.f:%02.f:%02.f remaining)\n",
scantypestr, perc_done * 100, scantypestr, perc_done * 100,
floor(time_left_s / 60.0 / 60.0), floor(time_left_s / 60.0 / 60.0),
@@ -757,7 +758,8 @@ bool ScanProgressMeter::printStats(double perc_done,
additional_info may be NULL if no additional information is necessary. */ additional_info may be NULL if no additional information is necessary. */
bool ScanProgressMeter::beginOrEndTask(const struct timeval *now, const char *additional_info, bool beginning) { bool ScanProgressMeter::beginOrEndTask(const struct timeval *now, const char *additional_info, bool beginning) {
struct timeval tvtmp; struct timeval tvtmp;
struct tm *tm; struct tm tm;
int err;
time_t tv_sec; time_t tv_sec;
if (!o.verbose) { if (!o.verbose) {
@@ -770,9 +772,14 @@ bool ScanProgressMeter::beginOrEndTask(const struct timeval *now, const char *ad
} }
tv_sec = now->tv_sec; tv_sec = now->tv_sec;
tm = localtime(&tv_sec); err = n_localtime(&tv_sec, &tm);
if (err)
log_write(LOG_STDERR, "Timing error: n_localtime(%f): %s\n", (double) tv_sec, strerror(err));
if (beginning) { if (beginning) {
log_write(LOG_STDOUT, "Initiating %s at %02d:%02d", scantypestr, tm->tm_hour, tm->tm_min); if (!err)
log_write(LOG_STDOUT, "Initiating %s at %02d:%02d", scantypestr, tm.tm_hour, tm.tm_min);
else
log_write(LOG_STDOUT, "Initiating %s", scantypestr);
xml_open_start_tag("taskbegin"); xml_open_start_tag("taskbegin");
xml_attribute("task", "%s", scantypestr); xml_attribute("task", "%s", scantypestr);
xml_attribute("time", "%lu", (unsigned long) now->tv_sec); xml_attribute("time", "%lu", (unsigned long) now->tv_sec);
@@ -784,7 +791,10 @@ bool ScanProgressMeter::beginOrEndTask(const struct timeval *now, const char *ad
xml_close_empty_tag(); xml_close_empty_tag();
xml_newline(); xml_newline();
} else { } else {
log_write(LOG_STDOUT, "Completed %s at %02d:%02d, %.2fs elapsed", scantypestr, tm->tm_hour, tm->tm_min, TIMEVAL_MSEC_SUBTRACT(*now, begin) / 1000.0); if (!err)
log_write(LOG_STDOUT, "Completed %s at %02d:%02d, %.2fs elapsed", scantypestr, tm.tm_hour, tm.tm_min, TIMEVAL_MSEC_SUBTRACT(*now, begin) / 1000.0);
else
log_write(LOG_STDOUT, "Completed %s, %.2fs elapsed", scantypestr, TIMEVAL_MSEC_SUBTRACT(*now, begin) / 1000.0);
xml_open_start_tag("taskend"); xml_open_start_tag("taskend");
xml_attribute("task", "%s", scantypestr); xml_attribute("task", "%s", scantypestr);
xml_attribute("time", "%lu", (unsigned long) now->tv_sec); xml_attribute("time", "%lu", (unsigned long) now->tv_sec);