1 /* 2 * Copyright (c) 2008 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * $DragonFly: src/sbin/hammer/cmd_history.c,v 1.4 2008/06/24 17:40:21 dillon Exp $ 35 */ 36 37 #include "hammer.h" 38 #include <limits.h> 39 40 static void hammer_do_history(const char *path, off_t off, int len); 41 static void dumpat(const char *path, off_t off, int len); 42 static const char *timestr32(u_int32_t time32); 43 static __inline int test_strtol(int res, long val); 44 static __inline int test_strtoll(int res, long long val); 45 46 /* 47 * history <file1> ... <fileN> 48 */ 49 void 50 hammer_cmd_history(const char *offset_str, char **av, int ac) 51 { 52 int i; 53 long long off; 54 long len; 55 char *rptr; 56 57 len = 32; 58 if (*offset_str == '@') { 59 errno = 0; /* clear */ 60 off = strtoll(offset_str + 1, &rptr, 0); 61 if (test_strtoll(errno, off)) { 62 *rptr = '\0'; /* side effect */ 63 printf("%s: %s\n", strerror(errno), offset_str); 64 exit(1); 65 } 66 if (*rptr == ',') { 67 errno = 0; /* clear */ 68 len = strtol(rptr + 1, NULL, 0); 69 if (test_strtol(errno, len)) { 70 printf("%s: %s\n", strerror(errno), rptr); 71 exit(1); 72 } 73 if (len < 0) 74 len = 32; 75 } 76 } else { 77 off = -1; 78 } 79 80 for (i = 0; i < ac; ++i) 81 hammer_do_history(av[i], (off_t)off, (int)len); 82 } 83 84 static void 85 hammer_do_history(const char *path, off_t off, int len) 86 { 87 struct hammer_ioc_history hist; 88 const char *status; 89 int fd; 90 int i; 91 92 printf("%s\t", path); 93 fd = open(path, O_RDONLY); 94 if (fd < 0) { 95 printf("%s\n", strerror(errno)); 96 return; 97 } 98 bzero(&hist, sizeof(hist)); 99 hist.beg_tid = HAMMER_MIN_TID; 100 hist.end_tid = HAMMER_MAX_TID; 101 102 if (off >= 0) { 103 hist.head.flags |= HAMMER_IOC_HISTORY_ATKEY; 104 hist.key = off; 105 hist.nxt_key = off + 1; 106 } 107 108 109 if (ioctl(fd, HAMMERIOC_GETHISTORY, &hist) < 0) { 110 printf("%s\n", strerror(errno)); 111 close(fd); 112 return; 113 } 114 status = ((hist.head.flags & HAMMER_IOC_HISTORY_UNSYNCED) ? 115 "dirty" : "clean"); 116 printf("%016jx %s {\n", (uintmax_t)hist.obj_id, status); 117 for (;;) { 118 for (i = 0; i < hist.count; ++i) { 119 char *hist_path = NULL; 120 121 asprintf(&hist_path, "%s@@0x%016jx", 122 path, (uintmax_t)hist.hist_ary[i].tid); 123 printf(" %016jx %s", 124 (uintmax_t)hist.hist_ary[i].tid, 125 timestr32(hist.hist_ary[i].time32)); 126 if (off >= 0) { 127 if (VerboseOpt) { 128 printf(" '"); 129 dumpat(hist_path, off, len); 130 printf("'"); 131 } 132 } 133 printf("\n"); 134 free(hist_path); 135 } 136 if (hist.head.flags & HAMMER_IOC_HISTORY_EOF) 137 break; 138 if (hist.head.flags & HAMMER_IOC_HISTORY_NEXT_KEY) 139 break; 140 if ((hist.head.flags & HAMMER_IOC_HISTORY_NEXT_TID) == 0) 141 break; 142 hist.beg_tid = hist.nxt_tid; 143 if (ioctl(fd, HAMMERIOC_GETHISTORY, &hist) < 0) { 144 printf(" error: %s\n", strerror(errno)); 145 break; 146 } 147 } 148 printf("}\n"); 149 close(fd); 150 } 151 152 static void 153 dumpat(const char *path, off_t off, int len) 154 { 155 char buf[1024]; 156 int fd; 157 int n; 158 int r; 159 160 fd = open(path, O_RDONLY); 161 if (fd < 0) 162 return; 163 lseek(fd, off, 0); 164 while (len) { 165 n = (len > (int)sizeof(buf)) ? (int)sizeof(buf) : len; 166 r = read(fd, buf, n); 167 if (r <= 0) 168 break; 169 len -= r; 170 for (n = 0; n < r; ++n) { 171 if (isprint(buf[n])) 172 putc(buf[n], stdout); 173 else 174 putc('.', stdout); 175 } 176 } 177 close(fd); 178 } 179 180 /* 181 * Return a human-readable timestamp 182 */ 183 static const char * 184 timestr32(u_int32_t time32) 185 { 186 static char timebuf[64]; 187 time_t t = (time_t)time32; 188 struct tm *tp; 189 190 tp = localtime(&t); 191 strftime(timebuf, sizeof(timebuf), "%d-%b-%Y %H:%M:%S", tp); 192 return(timebuf); 193 } 194 195 /* 196 * Return non-zero on either overflow or underflow 197 */ 198 static __inline int 199 test_strtol(int res, long val) 200 { 201 return(res == ERANGE && (val == LONG_MIN || val == LONG_MAX)); 202 } 203 204 static __inline int 205 test_strtoll(int res, long long val) 206 { 207 return(res == ERANGE && (val == LLONG_MIN || val == LLONG_MAX)); 208 } 209