diff --git a/CHANGELOG b/CHANGELOG
index d9e752806..09183e775 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,4 +1,12 @@
# Nmap Changelog ($Id$); -*-text-*-
+
+o Nmap's output options (-oA, -oX, etc.) now support strftime()-like
+ conversions in the filename. %H, %M, %S, %T, %R, %m, %d, %y, and
+ %Y are all the same as in strftime(). %t is the same as %H%M%S,
+ %r is the same as %H%M, and %D is the same as %m%d%y. This means
+ that "-oX 'scan-%T-%D.xml'" uses an XML file in the form of
+ "scan-14:48:40-121307.xml". [Kris]
+
4.50
o Bumped up the version number to the big 4.50!
diff --git a/docs/refguide.xml b/docs/refguide.xml
index ea9d0e5d7..e73787c68 100644
--- a/docs/refguide.xml
+++ b/docs/refguide.xml
@@ -2868,6 +2868,18 @@ compatibility feature of Nmap will cause the creation of
G- and Xscan.xml
respectively.
+All of these arguments support strftime()-like
+conversions in the filename. %H, %M,
+%S, %T, %R,
+%m, %d, %y,
+and %Y are all exactly the same as in
+strftime(). %t is the same as
+%H%M%S, %r is the same as
+%H%M, and %D is the same as
+%m%d%y. So
+will use an XML file in the form of
+scan-14:48:40-121307.xml.
+
Nmap also offers options to control scan verbosity and to append
to output files rather than clobbering them. All of these options are
described below.
diff --git a/nmap.cc b/nmap.cc
index 081c2aa71..4a403dc63 100644
--- a/nmap.cc
+++ b/nmap.cc
@@ -472,6 +472,8 @@ int nmap_main(int argc, char *argv[]) {
int num_host_exp_groups;
char *machinefilename = NULL, *kiddiefilename = NULL,
*normalfilename = NULL, *xmlfilename = NULL;
+ time_t now;
+ struct tm *tm;
HostGroupState *hstate = NULL;
char *endptr = NULL;
struct scan_lists *ports = NULL;
@@ -647,6 +649,9 @@ int nmap_main(int argc, char *argv[]) {
win_pre_init();
#endif
+ now = time(NULL);
+ tm = localtime(&now);
+
/* OK, lets parse these args! */
optind = 1; /* so it can be called multiple times */
while((arg = getopt_long_only(argc,fakeargv,"6Ab:D:d::e:Ffg:hIi:M:m:nO::o:P:p:qRrS:s:T:Vv", long_options, &option_index)) != EOF) {
@@ -816,23 +821,23 @@ int nmap_main(int argc, char *argv[]) {
} else if (strcmp(long_options[option_index].name, "webxml") == 0) {
o.setXSLStyleSheet("http://www.insecure.org/nmap/data/nmap.xsl");
} else if (strcmp(long_options[option_index].name, "oN") == 0) {
- normalfilename = optarg;
+ normalfilename = logfilename(optarg, tm);
} else if (strcmp(long_options[option_index].name, "oG") == 0 ||
strcmp(long_options[option_index].name, "oM") == 0) {
- machinefilename = optarg;
+ machinefilename = logfilename(optarg, tm);
} else if (strcmp(long_options[option_index].name, "oS") == 0) {
- kiddiefilename = optarg;
+ kiddiefilename = logfilename(optarg, tm);
} 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.");
} else if (strcmp(long_options[option_index].name, "oX") == 0) {
- xmlfilename = optarg;
+ xmlfilename = logfilename(optarg, tm);
} else if (strcmp(long_options[option_index].name, "oA") == 0) {
char buf[MAXPATHLEN];
- Snprintf(buf, sizeof(buf), "%s.nmap", optarg);
+ Snprintf(buf, sizeof(buf), "%s.nmap", logfilename(optarg, tm));
normalfilename = strdup(buf);
- Snprintf(buf, sizeof(buf), "%s.gnmap", optarg);
+ Snprintf(buf, sizeof(buf), "%s.gnmap", logfilename(optarg, tm));
machinefilename = strdup(buf);
- Snprintf(buf, sizeof(buf), "%s.xml", optarg);
+ Snprintf(buf, sizeof(buf), "%s.xml", logfilename(optarg, tm));
xmlfilename = strdup(buf);
} else if (strcmp(long_options[option_index].name, "thc") == 0) {
printf("!!Greets to Van Hauser, Plasmoid, Skyper and the rest of THC!!\n");
@@ -1008,7 +1013,7 @@ int nmap_main(int argc, char *argv[]) {
fatal("Unknown argument to -O.");
break;
case 'o':
- normalfilename = optarg;
+ normalfilename = logfilename(optarg, tm);
break;
case 'P':
if (*optarg == '\0' || *optarg == 'I' || *optarg == 'E')
@@ -1244,10 +1249,6 @@ int nmap_main(int argc, char *argv[]) {
if (!o.interactivemode) {
char tbuf[128];
- struct tm *tm;
- time_t now = time(NULL);
- if (!(tm = localtime(&now)))
- fatal("Unable to get current localtime()#!#");
// 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)
fatal("Unable to properly format time");
diff --git a/output.cc b/output.cc
index 1696cfa1b..6221edaff 100644
--- a/output.cc
+++ b/output.cc
@@ -830,6 +830,77 @@ char* xml_convert (const char* str) {
return temp;
}
+char *logfilename(const char *str, struct tm *tm)
+{
+ char *ret, *end, *p;
+ char tbuf[10];
+ int retlen = strlen(str) * 6 + 1;
+
+ ret = (char *) safe_malloc(retlen);
+ end = ret + retlen;
+
+ for (p = ret; *str; str++) {
+ if (*str == '%') {
+ str++;
+
+ if (!*str)
+ break;
+
+ switch (*str) {
+ case 'H':
+ strftime(tbuf, sizeof tbuf, "%H", tm);
+ break;
+ case 'M':
+ strftime(tbuf, sizeof tbuf, "%M", tm);
+ break;
+ case 'S':
+ strftime(tbuf, sizeof tbuf, "%S", tm);
+ break;
+ case 'T':
+ strftime(tbuf, sizeof tbuf, "%T", tm);
+ break;
+ case 't':
+ strftime(tbuf, sizeof tbuf, "%H%M%S", tm);
+ break;
+ case 'R':
+ strftime(tbuf, sizeof tbuf, "%R", tm);
+ break;
+ case 'r':
+ strftime(tbuf, sizeof tbuf, "%H%M", tm);
+ break;
+ case 'm':
+ strftime(tbuf, sizeof tbuf, "%m", tm);
+ break;
+ case 'd':
+ strftime(tbuf, sizeof tbuf, "%d", tm);
+ break;
+ case 'y':
+ strftime(tbuf, sizeof tbuf, "%y", tm);
+ break;
+ case 'Y':
+ strftime(tbuf, sizeof tbuf, "%Y", tm);
+ break;
+ case 'D':
+ strftime(tbuf, sizeof tbuf, "%m%d%y", tm);
+ break;
+ default:
+ *p++ = *str;
+ continue;
+ }
+
+ assert(end - p > 1);
+ Strncpy(p, tbuf, end - p - 1);
+ p += strlen(tbuf);
+ } else {
+ *p++ = *str;
+ }
+ }
+
+ *p = 0;
+
+ return (char *) safe_realloc(ret, strlen(ret) + 1);
+}
+
/* This is the workhorse of the logging functions. Usually it is
called through log_write(), but it can be called directly if you
are dealing with a vfprintf-style va_list. Unlike log_write, YOU
diff --git a/output.h b/output.h
index 772bbda44..6ec6654ad 100644
--- a/output.h
+++ b/output.h
@@ -138,6 +138,8 @@ void printportoutput(Target *currenths, PortList *plist);
in a certain place to conform to DTD. */
void printmacinfo(Target *currenths);
+char *logfilename(const char *str, struct tm *tm);
+
/* Write some information (printf style args) to the given log stream(s).
Remember to watch out for format string bugs. */
void log_write(int logt, const char *fmt, ...)