* Improvements
* Optimized syscall filtering.
+ * Improved representation of timestamps.
* Enhanced decoding of sched_setattr syscall.
* Added -e trace=%stat option for tracing variants of stat syscall.
* Added -e trace=%lstat option for tracing variants of lstat syscall.
extern void addflags(const struct xlat *, uint64_t);
extern int printflags64(const struct xlat *, uint64_t, const char *);
extern const char *sprintflags(const char *, const struct xlat *, uint64_t);
-extern const char *sprinttime(time_t);
+extern const char *sprinttime(long long sec);
+extern const char *sprinttime_nsec(long long sec, unsigned long long nsec);
+extern const char *sprinttime_usec(long long sec, unsigned long long usec);
extern void print_symbolic_mode_t(unsigned int);
extern void print_numeric_umode_t(unsigned short);
extern void print_numeric_long_umask(unsigned long);
#ifdef HAVE_STRUCT_STAT_ST_MTIME_NSEC
# define TIME_NSEC(arg) zero_extend_signed_to_ull(arg)
+# define HAVE_NSEC true
#else
# define TIME_NSEC(arg) 0
+# define HAVE_NSEC false
#endif
MPERS_PRINTER_DECL(bool, fetch_struct_stat,
dst->atime_nsec = TIME_NSEC(buf.st_atime_nsec);
dst->ctime_nsec = TIME_NSEC(buf.st_ctime_nsec);
dst->mtime_nsec = TIME_NSEC(buf.st_mtime_nsec);
+ dst->has_nsec = HAVE_NSEC;
return true;
#else /* !HAVE_STRUCT_STAT */
printaddr(addr);
#ifdef HAVE_STRUCT_STAT64_ST_MTIME_NSEC
# define TIME_NSEC(arg) zero_extend_signed_to_ull(arg)
+# define HAVE_NSEC true
#else
# define TIME_NSEC(arg) 0
+# define HAVE_NSEC false
#endif
MPERS_PRINTER_DECL(bool, fetch_struct_stat64,
dst->atime_nsec = TIME_NSEC(buf.st_atime_nsec);
dst->ctime_nsec = TIME_NSEC(buf.st_ctime_nsec);
dst->mtime_nsec = TIME_NSEC(buf.st_mtime_nsec);
+ dst->has_nsec = HAVE_NSEC;
return true;
#else /* !HAVE_STRUCT_STAT64 */
printaddr(addr);
}
if (!abbrev(tcp)) {
-#define PRINT_ST_TIME(field) \
- tprints(", st_" #field "="); \
- tprints(sprinttime(st->field)); \
- if (st->field ## _nsec) \
- tprintf(".%09llu", st->field ## _nsec)
+#define PRINT_ST_TIME(field) \
+ do { \
+ tprintf(", st_" #field "=%lld", (long long) st->field); \
+ tprints_comment(sprinttime_nsec(st->field, \
+ zero_extend_signed_to_ull(st->field ## _nsec)));\
+ if (st->has_nsec) \
+ tprintf(", st_" #field "_nsec=%llu", \
+ zero_extend_signed_to_ull( \
+ st->field ## _nsec)); \
+ } while (0)
PRINT_ST_TIME(atime);
PRINT_ST_TIME(mtime);
unsigned long long atime_nsec;
unsigned long long ctime_nsec;
unsigned long long mtime_nsec;
+ bool has_nsec;
};
#endif /* !STRACE_STAT_H */
#define PRINT_FIELD_TIME(field) \
do { \
- tprints(", " #field "="); \
- tprints(sprinttime(stx.field.sec)); \
- if (stx.field.nsec) \
- tprintf(".%09" PRId32, stx.field.nsec); \
+ tprintf(", " #field "={tv_sec=%" PRId64 \
+ ", tv_nsec=%" PRIu32 "}", \
+ stx.field.sec, stx.field.nsec); \
+ tprints_comment(sprinttime_nsec(stx.field.sec, \
+ zero_extend_signed_to_ull(stx.field.nsec))); \
} while (0)
struct_statx stx;
#include <stdio.h>
#include <time.h>
-void
-print_time_t_nsec(const time_t t, const unsigned long long nsec)
+static void
+print_time_t_ex(const time_t t, const unsigned long long part_sec,
+ const unsigned int max_part_sec, const int width,
+ const int comment)
{
- if (t) {
- const struct tm *const p = localtime(&t);
- char buf[256];
- if (!p) {
- perror_msg_and_fail("localtime");
- }
+ if ((!t && !part_sec) || part_sec > max_part_sec)
+ return;
+
+ const struct tm *const p = localtime(&t);
+ char buf[256];
+ if (!p || !strftime(buf, sizeof(buf), "%FT%T", p))
+ return;
+
+ if (comment)
+ fputs(" /* ", stdout);
+
+ fputs(buf, stdout);
+
+ if (part_sec)
+ printf(".%0*llu", width, part_sec);
- strftime(buf, sizeof(buf), "%FT%T%z", p);
+ if (strftime(buf, sizeof(buf), "%z", p))
fputs(buf, stdout);
- } else {
- putchar('0');
- }
- if (nsec) {
- printf(".%09llu", nsec);
- }
+ if (comment)
+ fputs(" */", stdout);
+
+ return;
+}
+
+void
+print_time_t_nsec(const time_t t, const unsigned long long nsec, int comment)
+{
+ print_time_t_ex(t, nsec, 999999999, 9, comment);
}
void print_quoted_memory(const char *, size_t);
/* Print time_t and nanoseconds in symbolic format. */
-void print_time_t_nsec(time_t, unsigned long long);
+void print_time_t_nsec(time_t, unsigned long long, int);
/* Read an int from the file. */
int read_int_from_file(const char *, int *);
rc = k_utime("utime\nfilename", tail_u);
const char *errstr = sprintrc(rc);
- printf("utime(\"utime\\nfilename\", {actime=");
- print_time_t_nsec(t, 0);
- printf(", modtime=");
- print_time_t_nsec(t, 0);
+ printf("utime(\"utime\\nfilename\", {actime=%lld", (long long) t);
+ print_time_t_nsec(t, 0, 1);
+ printf(", modtime=%lld", (long long) t);
+ print_time_t_nsec(t, 0, 1);
printf("}) = %s\n", errstr);
puts("+++ exited with 0 +++");
# if defined(HAVE_STRUCT_STAT_ST_MTIME_NSEC) && !OLD_STAT
# define TIME_NSEC(val) zero_extend_signed_to_ull(val)
+# define HAVE_NSEC 1
# else
-# define TIME_NSEC(val) 0
+# define TIME_NSEC(val) 0ULL
+# define HAVE_NSEC 0
# endif
-# define PRINT_ST_TIME(field) \
- printf(", st_" #field "="); \
+#define PRINT_ST_TIME(field) \
+ printf(", st_" #field "=%lld", \
+ sign_extend_unsigned_to_ll(st->st_ ## field)); \
print_time_t_nsec(sign_extend_unsigned_to_ll(st->st_ ## field), \
- TIME_NSEC(st->st_ ## field ## _nsec))
+ TIME_NSEC(st->st_ ## field ## _nsec), 1); \
+ if (HAVE_NSEC) \
+ printf(", st_" #field "_nsec=%llu", \
+ TIME_NSEC(st->st_ ## field ## _nsec))
PRINT_ST_TIME(atime);
PRINT_ST_TIME(mtime);
else \
printf(", %s=%llu", #field, (unsigned long long) st->field)
-# define PRINT_FIELD_TIME(field) \
- printf(", %s=", #field); \
- print_time_t_nsec(st->field.tv_sec, \
- zero_extend_signed_to_ull(st->field.tv_nsec))
+# define PRINT_FIELD_TIME(field) \
+ printf(", %s={tv_sec=%lld, tv_nsec=%u}", \
+ #field, (long long) st->field.tv_sec, \
+ (unsigned) st->field.tv_nsec); \
+ print_time_t_nsec(st->field.tv_sec, \
+ zero_extend_signed_to_ull(st->field.tv_nsec), 1);
printf("{stx_mask=");
printflags(statx_masks, st->stx_mask, "STATX_???");
}
#endif /* !current_klongsize */
+/**
+ * Prints time to a (static internal) buffer and returns pointer to it.
+ *
+ * @param sec Seconds since epoch.
+ * @param part_sec Amount of second parts since the start of a second.
+ * @param max_part_sec Maximum value of a valid part_sec.
+ * @param width 1 + floor(log10(max_part_sec)).
+ */
+static const char *
+sprinttime_ex(const long long sec, const unsigned long long part_sec,
+ const unsigned int max_part_sec, const int width)
+{
+ static char buf[sizeof(int) * 3 * 6 + sizeof(part_sec) * 3
+ + sizeof("+0000")];
+
+ if ((sec == 0 && part_sec == 0) || part_sec > max_part_sec)
+ return NULL;
+
+ time_t t = (time_t) sec;
+ struct tm *tmp = (sec == t) ? localtime(&t) : NULL;
+ if (!tmp)
+ return NULL;
+
+ size_t pos = strftime(buf, sizeof(buf), "%FT%T", tmp);
+ if (!pos)
+ return NULL;
+
+ if (part_sec > 0) {
+ int ret = snprintf(buf + pos, sizeof(buf) - pos, ".%0*llu",
+ width, part_sec);
+
+ if (ret < 0 || (size_t) ret >= sizeof(buf) - pos)
+ return NULL;
+
+ pos += ret;
+ }
+
+ return strftime(buf + pos, sizeof(buf) - pos, "%z", tmp) ? buf : NULL;
+}
+
const char *
-sprinttime(time_t t)
+sprinttime(long long sec)
{
- struct tm *tmp;
- static char buf[sizeof(int) * 3 * 6 + sizeof("+0000")];
-
- if (t == 0)
- return "0";
- tmp = localtime(&t);
- if (tmp)
- strftime(buf, sizeof(buf), "%FT%T%z", tmp);
- else
- snprintf(buf, sizeof(buf), "%lu", (unsigned long) t);
+ return sprinttime_ex(sec, 0, 0, 0);
+}
- return buf;
+const char *
+sprinttime_usec(long long sec, unsigned long long usec)
+{
+ return sprinttime_ex(sec, usec, 999999, 6);
+}
+
+const char *
+sprinttime_nsec(long long sec, unsigned long long nsec)
+{
+ return sprinttime_ex(sec, nsec, 999999999, 9);
}
enum sock_proto
printpath(tcp, tcp->u_arg[0]);
tprints(", ");
if (!umove_or_printaddr(tcp, tcp->u_arg[1], &u)) {
- tprintf("{actime=%s,", sprinttime(u.actime));
- tprintf(" modtime=%s}", sprinttime(u.modtime));
+ tprintf("{actime=%lld", (long long) u.actime);
+ tprints_comment(sprinttime(u.actime));
+ tprintf(", modtime=%lld", (long long) u.modtime);
+ tprints_comment(sprinttime(u.modtime));
+ tprints("}");
}
return RVAL_DECODED;