summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMasami Hiramatsu <mhiramat@redhat.com>2009-03-20 13:38:29 -0400
committerMasami Hiramatsu <mhiramat@redhat.com>2009-03-20 13:38:29 -0400
commit04ae1b090781725631ba3477ff77721b012cdaba (patch)
tree36249f31536ce30c49f66a5afb70b9f3d9bb2ce4
parentdc6e1d97c43aa173549ad00bb78d7ea86ec90c95 (diff)
downloadsystemtap-steved-04ae1b090781725631ba3477ff77721b012cdaba.tar.gz
systemtap-steved-04ae1b090781725631ba3477ff77721b012cdaba.tar.xz
systemtap-steved-04ae1b090781725631ba3477ff77721b012cdaba.zip
PR9821: staprun supports subset of strftime.
Add strftime subset format support for output file name to systemtap. This format will be evaluated when opening a new output file.
-rw-r--r--main.cxx4
-rw-r--r--runtime/staprun/common.c119
-rw-r--r--runtime/staprun/relay.c89
-rw-r--r--runtime/staprun/relay_old.c50
-rw-r--r--runtime/staprun/staprun.h6
-rw-r--r--stap.1.in2
-rw-r--r--staprun.8.in4
7 files changed, 240 insertions, 34 deletions
diff --git a/main.cxx b/main.cxx
index 6f4064a5..cdcae41a 100644
--- a/main.cxx
+++ b/main.cxx
@@ -108,7 +108,9 @@ usage (systemtap_session& s, int exitcode)
<< " " << s.kernel_build_tree << endl
<< " -m MODULE set probe module name, instead of " << endl
<< " " << s.module_name << endl
- << " -o FILE send script output to file, instead of stdout" << endl
+ << " -o FILE send script output to file, instead of stdout. This supports" << endl
+ << " a subset of strftime(3) (%%,%C,%Y,%y,%m,%d,%e,%F,%H,%I,%j,%k," << endl
+ << " %l,%M,%S,%R,%T,%u,%w) for FILE." << endl
<< " -c CMD start the probes, run CMD, and exit when it finishes" << endl
<< " -x PID sets target() to PID" << endl
<< " -F run as on-file flight recorder with -o." << endl
diff --git a/runtime/staprun/common.c b/runtime/staprun/common.c
index 194488ef..8200ec9d 100644
--- a/runtime/staprun/common.c
+++ b/runtime/staprun/common.c
@@ -53,6 +53,113 @@ static char *get_abspath(char *path)
return path_buf;
}
+int stap_strfloctime(char *buf, size_t max, const char *fmt, time_t t)
+{
+ char *c = buf;
+ const char *c2 = fmt, *end = buf + max;
+ int ret, num;
+ struct tm tm;
+ if (buf == NULL || fmt == NULL || max <= 1)
+ return -EINVAL;
+ localtime_r(&t, &tm);
+
+ while (*c2 != '\0'){
+ if (c + 1 >= end)
+ return -EINVAL;
+ if (*c2 != '%') {
+ *c++ = *c2++;
+ continue;
+ }
+ c2++;
+ switch (*c2++) {
+ case '%':
+ *c++ = '%';
+ break;
+ case 'Y':
+ num = tm.tm_year + 1900;
+ goto numbering;
+ case 'y':
+ num = tm.tm_year % 100;
+ goto numbering02;
+ case 'C':
+ num = ((tm.tm_year + 1900 - 1) / 100) + 1;
+ goto numbering;
+ case 'm':
+ num = tm.tm_mon + 1;
+ goto numbering02;
+ case 'd':
+ num = tm.tm_mday;
+ goto numbering02;
+ case 'e':
+ num = tm.tm_mday;
+ goto numbering;
+ case 'F':
+ ret = snprintf(c, end - c, "%d-%02d-%02d",
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
+ if (ret < 0) return ret;
+ c += ret;
+ break;
+ case 'H':
+ num = tm.tm_hour;
+ goto numbering02;
+ case 'I':
+ num = tm.tm_hour % 12;
+ if (num == 0) num = 12;
+ goto numbering02;
+ case 'j':
+ ret = snprintf(c, end - c, "%03d", tm.tm_yday);
+ if (ret < 0) return ret;
+ c += ret;
+ break;
+ case 'k':
+ num = tm.tm_hour;
+ goto numbering;
+ case 'l':
+ num = tm.tm_hour % 12;
+ if (num == 0) num = 12;
+ goto numbering;
+ case 'M':
+ num = tm.tm_min;
+ goto numbering02;
+ case 'S':
+ num = tm.tm_sec;
+ goto numbering02;
+ case 'R':
+ ret = snprintf(c, end - c, "%02d:%02d",
+ tm.tm_hour, tm.tm_min);
+ if (ret < 0) return ret;
+ c += ret;
+ break;
+ case 'T':
+ ret = snprintf(c, end - c, "%02d:%02d:%02d",
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
+ if (ret < 0) return ret;
+ c += ret;
+ break;
+ case 'u':
+ num = tm.tm_wday == 0 ? 7 : tm.tm_wday;
+ goto numbering;
+ case 'w':
+ num = tm.tm_wday;
+ goto numbering;
+ default:
+ return -EINVAL;
+ }
+ continue;
+numbering:
+ ret = snprintf(c, end - c, "%d", num);
+ if (ret < 0) return ret;
+ c += ret;
+ continue;
+numbering02:
+ ret = snprintf(c, end - c, "%02d", num);
+ if (ret < 0) return ret;
+ c += ret;
+ }
+ *c = '\0';
+ return c - buf;
+}
+
void parse_args(int argc, char **argv)
{
int c;
@@ -125,11 +232,19 @@ void parse_args(int argc, char **argv)
}
}
if (outfile_name) {
+ char tmp[PATH_MAX];
+ int ret;
outfile_name = get_abspath(outfile_name);
if (outfile_name == NULL) {
err("File name is too long.\n");
usage(argv[0]);
}
+ ret = stap_strfloctime(tmp, PATH_MAX - 18, /* = _cpuNNN.SSSSSSSSSS */
+ outfile_name, time(NULL));
+ if (ret < 0) {
+ err("Filename format is invalid or too long.\n");
+ usage(argv[0]);
+ }
}
if (attach_mod && load_only) {
err("You can't specify the '-A' and '-L' options together.\n");
@@ -191,7 +306,9 @@ void usage(char *prog)
err(" exit when it does. The '_stp_target' variable\n");
err(" will contain the pid for the command.\n");
err("-x pid Sets the '_stp_target' variable to pid.\n");
- err("-o FILE Send output to FILE.\n");
+ err("-o FILE Send output to FILE. This supports a subset of\n");
+ err(" strftime(3) (%%%%,%%C,%%Y,%%y,%%m,%%d,%%e,%%F,%%H,%%I\n");
+ err(" %%j,%%k,%%l,%%M,%%S,%%R,%%T,%%u,%%w) for FILE.\n");
err("-b buffer size The systemtap module specifies a buffer size.\n");
err(" Setting one here will override that value. The\n");
err(" value should be an integer between 1 and 4095 \n");
diff --git a/runtime/staprun/relay.c b/runtime/staprun/relay.c
index 891913b0..50f295b5 100644
--- a/runtime/staprun/relay.c
+++ b/runtime/staprun/relay.c
@@ -17,6 +17,9 @@ static pthread_t reader[NR_CPUS];
static int relay_fd[NR_CPUS];
static int bulkmode = 0;
static volatile int stop_threads = 0;
+static time_t *time_backlog[NR_CPUS];
+static int backlog_order=0;
+#define BACKLOG_MASK ((1 << backlog_order) - 1)
/*
* ppoll exists in glibc >= 2.4
@@ -44,20 +47,52 @@ static int ppoll(struct pollfd *fds, nfds_t nfds,
}
#endif
-int make_outfile_name(char *buf, int max, int fnum, int cpu)
+int init_backlog(int cpu)
{
+ int order = 0;
+ if (!fnum_max)
+ return 0;
+ while (fnum_max >> order) order++;
+ if (fnum_max == 1<<(order-1)) order--;
+ time_backlog[cpu] = (time_t *)calloc(1<<order, sizeof(time_t));
+ if (time_backlog[cpu] == NULL) {
+ _err("Memory allocation failed\n");
+ return -1;
+ }
+ backlog_order = order;
+ return 0;
+}
+
+void write_backlog(int cpu, int fnum, time_t t)
+{
+ time_backlog[cpu][fnum & BACKLOG_MASK] = t;
+}
+
+time_t read_backlog(int cpu, int fnum)
+{
+ return time_backlog[cpu][fnum & BACKLOG_MASK];
+}
+
+int make_outfile_name(char *buf, int max, int fnum, int cpu, time_t t)
+{
+ int len;
+ len = stap_strfloctime(buf, max, outfile_name, t);
+ if (len < 0) {
+ err("Invalid FILE name format\n");
+ return -1;
+ }
if (bulkmode) {
/* special case: for testing we sometimes want to write to /dev/null */
if (strcmp(outfile_name, "/dev/null") == 0) {
strcpy(buf, "/dev/null");
} else {
- if (snprintf_chk(buf, max, "%s_cpu%d.%d",
- outfile_name, cpu, fnum))
+ if (snprintf_chk(&buf[len], PATH_MAX - len,
+ "_cpu%d.%d", cpu, fnum))
return -1;
}
} else {
/* stream mode */
- if (snprintf_chk(buf, max, "%s.%d", outfile_name, fnum))
+ if (snprintf_chk(&buf[len], PATH_MAX - len, ".%d", fnum))
return -1;
}
return 0;
@@ -66,19 +101,25 @@ int make_outfile_name(char *buf, int max, int fnum, int cpu)
static int open_outfile(int fnum, int cpu, int remove_file)
{
char buf[PATH_MAX];
+ time_t t;
if (!outfile_name) {
_err("-S is set without -o. Please file a bug report.\n");
return -1;
}
- if (remove_file) {
- /* remove oldest file */
- if (make_outfile_name(buf, PATH_MAX, fnum - fnum_max, cpu) < 0)
- return -1;
- remove(buf); /* don't care */
+ time(&t);
+ if (fnum_max) {
+ if (remove_file) {
+ /* remove oldest file */
+ if (make_outfile_name(buf, PATH_MAX, fnum - fnum_max,
+ cpu, read_backlog(cpu, fnum - fnum_max)) < 0)
+ return -1;
+ remove(buf); /* don't care */
+ }
+ write_backlog(cpu, fnum, t);
}
- if (make_outfile_name(buf, PATH_MAX, fnum, cpu) < 0)
+ if (make_outfile_name(buf, PATH_MAX, fnum, cpu, t) < 0)
return -1;
out_fd[cpu] = open (buf, O_CREAT|O_TRUNC|O_WRONLY, 0666);
if (out_fd[cpu] < 0) {
@@ -178,7 +219,7 @@ static void *reader_thread(void *data)
*/
int init_relayfs(void)
{
- int i;
+ int i, len;
struct statfs st;
char rqbuf[128];
char buf[PATH_MAX], relay_filebase[PATH_MAX];
@@ -227,9 +268,12 @@ int init_relayfs(void)
if (fsize_max) {
/* switch file mode */
- for (i = 0; i < ncpus; i++)
- if (open_outfile(0, i, 0) < 0)
+ for (i = 0; i < ncpus; i++) {
+ if (init_backlog(i) < 0)
return -1;
+ if (open_outfile(0, i, 0) < 0)
+ return -1;
+ }
} else if (bulkmode) {
for (i = 0; i < ncpus; i++) {
if (outfile_name) {
@@ -237,7 +281,14 @@ int init_relayfs(void)
if (strcmp(outfile_name, "/dev/null") == 0) {
strcpy(buf, "/dev/null");
} else {
- if (sprintf_chk(buf, "%s_%d", outfile_name, i))
+ len = stap_strfloctime(buf, PATH_MAX,
+ outfile_name, time(NULL));
+ if (len < 0) {
+ err("Invalid FILE name format\n");
+ return -1;
+ }
+ if (snprintf_chk(&buf[len],
+ PATH_MAX - len, "_%d", i))
return -1;
}
} else {
@@ -256,9 +307,15 @@ int init_relayfs(void)
} else {
/* stream mode */
if (outfile_name) {
- out_fd[0] = open (outfile_name, O_CREAT|O_TRUNC|O_WRONLY, 0666);
+ len = stap_strfloctime(buf, PATH_MAX,
+ outfile_name, time(NULL));
+ if (len < 0) {
+ err("Invalid FILE name format\n");
+ return -1;
+ }
+ out_fd[0] = open (buf, O_CREAT|O_TRUNC|O_WRONLY, 0666);
if (out_fd[0] < 0) {
- perr("Couldn't open output file %s", outfile_name);
+ perr("Couldn't open output file %s", buf);
return -1;
}
if (set_clexec(out_fd[i]) < 0)
diff --git a/runtime/staprun/relay_old.c b/runtime/staprun/relay_old.c
index 25ba93bf..ef8fd0da 100644
--- a/runtime/staprun/relay_old.c
+++ b/runtime/staprun/relay_old.c
@@ -81,15 +81,20 @@ void close_oldrelayfs(int detach)
static int open_oldoutfile(int fnum, int cpu, int remove_file)
{
char buf[PATH_MAX];
+ time_t t;
if (outfile_name) {
- if (remove_file) {
- /* remove oldest file */
- if (make_outfile_name(buf, PATH_MAX, fnum - fnum_max,
- cpu) < 0)
- return -1;
- remove(buf); /* don't care */
+ time(&t);
+ if (fnum_max) {
+ if (remove_file) {
+ /* remove oldest file */
+ if (make_outfile_name(buf, PATH_MAX, fnum - fnum_max,
+ cpu, read_backlog(cpu, fnum - fnum_max)) < 0)
+ return -1;
+ remove(buf); /* don't care */
+ }
+ write_backlog(cpu, fnum, t);
}
- if (make_outfile_name(buf, PATH_MAX, fnum, cpu) < 0)
+ if (make_outfile_name(buf, PATH_MAX, fnum, cpu, t) < 0)
return -1;
} else if (bulkmode) {
if (sprintf_chk(buf, "stpd_cpu%d.%d", cpu, fnum))
@@ -143,6 +148,8 @@ static int open_relayfs_files(int cpu, const char *relay_filebase, const char *p
}
if (fsize_max) {
+ if (init_backlog(cpu) < 0)
+ goto err2;
if (open_oldoutfile(0, cpu, 0) < 0)
goto err2;
goto opened;
@@ -153,12 +160,18 @@ static int open_relayfs_files(int cpu, const char *relay_filebase, const char *p
if (strcmp(outfile_name, "/dev/null") == 0) {
strcpy(tmp, "/dev/null");
} else {
- if (sprintf_chk(tmp, "%s_%d", outfile_name, cpu))
- goto err1;
+ int len;
+ len = stap_strfloctime(tmp, PATH_MAX, outfile_name, time(NULL));
+ if (len < 0) {
+ err("Invalid FILE name format\n");
+ goto err2;
+ }
+ if (snprintf_chk(&tmp[len], PATH_MAX - len, "_%d", cpu))
+ goto err2;
}
} else {
if (sprintf_chk(tmp, "stpd_cpu%d", cpu))
- goto err1;
+ goto err2;
}
if((percpu_tmpfile[cpu] = fopen(tmp, "w+")) == NULL) {
@@ -334,13 +347,22 @@ int init_oldrelayfs(void)
bulkmode = 1;
if (!bulkmode) {
- if (fsize_max)
+ int len;
+ char tmp[PATH_MAX];
+ if (fsize_max) {
+ if (init_backlog(0))
+ return -1;
return open_oldoutfile(0, 0, 0);
-
+ }
if (outfile_name) {
- out_fd[0] = open (outfile_name, O_CREAT|O_TRUNC|O_WRONLY, 0666);
+ len = stap_strfloctime(tmp, PATH_MAX, outfile_name, time(NULL));
+ if (len < 0) {
+ err("Invalid FILE name format\n");
+ return -1;
+ }
+ out_fd[0] = open (tmp, O_CREAT|O_TRUNC|O_WRONLY, 0666);
if (out_fd[0] < 0 || set_clexec(out_fd[0]) < 0) {
- perr("Couldn't open output file '%s'", outfile_name);
+ perr("Couldn't open output file '%s'", tmp);
return -1;
}
} else
diff --git a/runtime/staprun/staprun.h b/runtime/staprun/staprun.h
index 6d0f9179..acc533b2 100644
--- a/runtime/staprun/staprun.h
+++ b/runtime/staprun/staprun.h
@@ -119,7 +119,10 @@ int init_oldrelayfs(void);
void close_oldrelayfs(int);
int write_realtime_data(void *data, ssize_t nb);
void setup_signals(void);
-int make_outfile_name(char *buf, int max, int fnum, int cpu);
+int make_outfile_name(char *buf, int max, int fnum, int cpu, time_t t);
+int init_backlog(int cpu);
+void write_backlog(int cpu, int fnum, time_t t);
+time_t read_backlog(int cpu, int fnum);
/* staprun_funcs.c */
void setup_staprun_signals(void);
const char *moderror(int err);
@@ -131,6 +134,7 @@ void start_symbol_thread(void);
void stop_symbol_thread(void);
/* common.c functions */
+int stap_strfloctime(char *buf, size_t max, const char *fmt, time_t t);
void parse_args(int argc, char **argv);
void usage(char *prog);
void parse_modpath(const char *);
diff --git a/stap.1.in b/stap.1.in
index f997b788..50c092ee 100644
--- a/stap.1.in
+++ b/stap.1.in
@@ -176,6 +176,8 @@ even if they do not have an explicit probe placed into them.
.BI \-o " FILE"
Send standard output to named file. In bulk mode, percpu files will
start with FILE_ (FILE_cpu with -F) followed by the cpu number.
+This supports a subset of strftime(3) (%%, %C, %Y, %y, %m, %d, %e, %F,
+%H, %I, %j, %l, %M, %S, %R, %T, %u, %w) for FILE.
.TP
.BI \-c " CMD"
Start the probes, run CMD, and exit when CMD finishes.
diff --git a/staprun.8.in b/staprun.8.in
index 68b5c947..01ef2320 100644
--- a/staprun.8.in
+++ b/staprun.8.in
@@ -53,7 +53,9 @@ The '_stp_target' variable will be set to PID.
.B \-o FILE
Send output to FILE. If the module uses bulk mode, the output will
be in percpu files FILE_x(FILE_cpux in backgroud and bulk mode)
-where 'x' is the cpu number.
+where 'x' is the cpu number. This supports a subset of strftime(3)
+(%%, %C, %Y, %y, %m, %d, %e, %F, %H, %I, %j, %l, %M, %S, %R, %T, %u, %w)
+for FILE.
.TP
.B \-b BUFFER_SIZE
The systemtap module will specify a buffer size.