/* * Copyright (c) 2008 The DragonFly Project. All rights reserved. * * This code is derived from software contributed to The DragonFly Project * by Matthew Dillon * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. Neither the name of The DragonFly Project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific, prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $DragonFly: src/sbin/hammer/cmd_history.c,v 1.2 2008/05/05 20:34:52 dillon Exp $ */ #include "hammer.h" static void hammer_do_history(const char *path, off_t off, int len); static void dumpat(const char *path, off_t off, int len); /* * history ... */ void hammer_cmd_history(const char *offset_str, char **av, int ac) { off_t off; int i; int len; char *rptr; len = 32; if (*offset_str == '@') { off = strtoll(offset_str + 1, &rptr, 0); if (*rptr == ',') len = strtol(rptr + 1, NULL, 0); } else { off = -1; } for (i = 0; i < ac; ++i) hammer_do_history(av[i], off, len); } static void hammer_do_history(const char *path, off_t off, int len) { struct hammer_ioc_history hist; const char *status; int fd; int i; printf("%s\t", path); fd = open(path, O_RDONLY); if (fd < 0) { printf("%s\n", strerror(errno)); return; } bzero(&hist, sizeof(hist)); hist.beg_tid = HAMMER_MIN_TID; hist.end_tid = HAMMER_MAX_TID; if (off >= 0) { hist.head.flags |= HAMMER_IOC_HISTORY_ATKEY; hist.key = off; hist.nxt_key = off + 1; } if (ioctl(fd, HAMMERIOC_GETHISTORY, &hist) < 0) { printf("%s\n", strerror(errno)); close(fd); return; } status = ((hist.head.flags & HAMMER_IOC_HISTORY_UNSYNCED) ? "dirty" : "clean"); printf("%016llx %s {\n", hist.obj_id, status); for (;;) { for (i = 0; i < hist.count; ++i) { struct stat st; struct tm tp; time_t t; char timebuf1[64]; char timebuf2[64]; char *hist_path = NULL; t = (int64_t)hist.tid_ary[i] / 1000000000LL; localtime_r(&t, &tp); strftime(timebuf1, sizeof(timebuf1), "%e-%b-%Y %H:%M:%S", &tp); asprintf(&hist_path, "%s@@0x%016llx", path, hist.tid_ary[i]); if (off < 0 && stat(hist_path, &st) == 0) { localtime_r(&st.st_mtime, &tp); strftime(timebuf2, sizeof(timebuf2), "%e-%b-%Y %H:%M:%S %Z", &tp); } else { snprintf(timebuf2, sizeof(timebuf2), "?"); } if (off < 0) { printf(" %016llx %s contents-to %s", hist.tid_ary[i], timebuf1, timebuf2); } else { printf(" %016llx %s", hist.tid_ary[i], timebuf1); if (VerboseOpt) { printf(" '"); dumpat(hist_path, off, len); printf("'"); } } printf("\n"); free(hist_path); } if (hist.head.flags & HAMMER_IOC_HISTORY_EOF) break; if (hist.head.flags & HAMMER_IOC_HISTORY_NEXT_KEY) break; if ((hist.head.flags & HAMMER_IOC_HISTORY_NEXT_TID) == 0) break; hist.beg_tid = hist.nxt_tid; if (ioctl(fd, HAMMERIOC_GETHISTORY, &hist) < 0) { printf(" error: %s\n", strerror(errno)); break; } } printf("}\n"); close(fd); } static void dumpat(const char *path, off_t off, int len) { char buf[1024]; int fd; int n; int r; fd = open(path, O_RDONLY); if (fd < 0) return; lseek(fd, off, 0); while (len) { n = (len > (int)sizeof(buf)) ? (int)sizeof(buf) : len; r = read(fd, buf, n); if (r <= 0) break; len -= r; for (n = 0; n < r; ++n) { if (isprint(buf[n])) putc(buf[n], stdout); else putc('.', stdout); } } }