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 <limits.h> 38 39 #include "hammer.h" 40 41 static void hammer_do_history(const char *path, off_t off, int len); 42 static void dumpat(const char *path, off_t off, int len); 43 static const char *timestr32(u_int32_t time32); 44 static __inline int test_strtol(int res, long val); 45 static __inline int test_strtoll(int res, long long val); 46 47 /* 48 * history <file1> ... <fileN> 49 */ 50 void 51 hammer_cmd_history(const char *offset_str, char **av, int ac) 52 { 53 int i; 54 long long off; 55 long len; 56 char *rptr; 57 58 len = 32; 59 if (*offset_str == '@') { 60 errno = 0; /* clear */ 61 off = strtoll(offset_str + 1, &rptr, 0); 62 if (test_strtoll(errno, off)) { 63 *rptr = '\0'; /* side effect */ 64 printf("%s: %s\n", strerror(errno), offset_str); 65 exit(1); 66 } 67 if (*rptr == ',') { 68 errno = 0; /* clear */ 69 len = strtol(rptr + 1, NULL, 0); 70 if (test_strtol(errno, len)) { 71 printf("%s: %s\n", strerror(errno), rptr); 72 exit(1); 73 } 74 if (len < 0) 75 len = 32; 76 } 77 } else { 78 off = -1; 79 } 80 81 for (i = 0; i < ac; ++i) 82 hammer_do_history(av[i], (off_t)off, (int)len); 83 } 84 85 static void 86 hammer_do_history(const char *path, off_t off, int len) 87 { 88 struct hammer_ioc_history hist; 89 const char *status; 90 int fd; 91 int i; 92 93 printf("%s\t", path); 94 fd = open(path, O_RDONLY); 95 if (fd < 0) { 96 printf("%s\n", strerror(errno)); 97 return; 98 } 99 bzero(&hist, sizeof(hist)); 100 hist.beg_tid = HAMMER_MIN_TID; 101 hist.end_tid = HAMMER_MAX_TID; 102 103 if (off >= 0) { 104 hist.head.flags |= HAMMER_IOC_HISTORY_ATKEY; 105 hist.key = off; 106 hist.nxt_key = off + 1; 107 } 108 109 110 if (ioctl(fd, HAMMERIOC_GETHISTORY, &hist) < 0) { 111 printf("%s\n", strerror(errno)); 112 close(fd); 113 return; 114 } 115 status = ((hist.head.flags & HAMMER_IOC_HISTORY_UNSYNCED) ? 116 "dirty" : "clean"); 117 printf("%016jx %s {\n", (uintmax_t)hist.obj_id, status); 118 for (;;) { 119 for (i = 0; i < hist.count; ++i) { 120 char *hist_path = NULL; 121 122 asprintf(&hist_path, "%s@@0x%016jx", 123 path, (uintmax_t)hist.hist_ary[i].tid); 124 printf(" %016jx %s", 125 (uintmax_t)hist.hist_ary[i].tid, 126 timestr32(hist.hist_ary[i].time32)); 127 if (off >= 0) { 128 if (VerboseOpt) { 129 printf(" '"); 130 dumpat(hist_path, off, len); 131 printf("'"); 132 } 133 } 134 printf("\n"); 135 free(hist_path); 136 } 137 if (hist.head.flags & HAMMER_IOC_HISTORY_EOF) 138 break; 139 if (hist.head.flags & HAMMER_IOC_HISTORY_NEXT_KEY) 140 break; 141 if ((hist.head.flags & HAMMER_IOC_HISTORY_NEXT_TID) == 0) 142 break; 143 hist.beg_tid = hist.nxt_tid; 144 if (ioctl(fd, HAMMERIOC_GETHISTORY, &hist) < 0) { 145 printf(" error: %s\n", strerror(errno)); 146 break; 147 } 148 } 149 printf("}\n"); 150 close(fd); 151 } 152 153 static void 154 dumpat(const char *path, off_t off, int len) 155 { 156 char buf[1024]; 157 int fd; 158 int n; 159 int r; 160 161 fd = open(path, O_RDONLY); 162 if (fd < 0) 163 return; 164 lseek(fd, off, 0); 165 while (len) { 166 n = (len > (int)sizeof(buf)) ? (int)sizeof(buf) : len; 167 r = read(fd, buf, n); 168 if (r <= 0) 169 break; 170 len -= r; 171 for (n = 0; n < r; ++n) { 172 if (isprint(buf[n])) 173 putc(buf[n], stdout); 174 else 175 putc('.', stdout); 176 } 177 } 178 close(fd); 179 } 180 181 /* 182 * Return a human-readable timestamp 183 */ 184 static const char * 185 timestr32(u_int32_t time32) 186 { 187 static char timebuf[64]; 188 time_t t = (time_t)time32; 189 struct tm *tp; 190 191 tp = localtime(&t); 192 strftime(timebuf, sizeof(timebuf), "%d-%b-%Y %H:%M:%S", tp); 193 return(timebuf); 194 } 195 196 /* 197 * Return non-zero on either overflow or underflow 198 */ 199 static __inline int 200 test_strtol(int res, long val) 201 { 202 return(res == ERANGE && (val == LONG_MIN || val == LONG_MAX)); 203 } 204 205 static __inline int 206 test_strtoll(int res, long long val) 207 { 208 return(res == ERANGE && (val == LLONG_MIN || val == LLONG_MAX)); 209 } 210