xref: /dragonfly/sbin/hammer/cmd_history.c (revision 6b5c5d0d)
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.1 2008/02/04 08:34:22 dillon Exp $
35  */
36 
37 #include "hammer.h"
38 
39 static void hammer_do_history(const char *path, off_t off, int len);
40 static void dumpat(const char *path, off_t off, int len);
41 
42 /*
43  * history <file1> ... <fileN>
44  */
45 void
46 hammer_cmd_history(const char *offset_str, char **av, int ac)
47 {
48 	off_t off;
49 	int i;
50 	int len;
51 	char *rptr;
52 
53 	len = 32;
54 	if (*offset_str == '@') {
55 		off = strtoll(offset_str + 1, &rptr, 0);
56 		if (*rptr == ',')
57 			len = strtol(rptr + 1, NULL, 0);
58 	} else {
59 		off = -1;
60 	}
61 
62 	for (i = 0; i < ac; ++i)
63 		hammer_do_history(av[i], off, len);
64 }
65 
66 static void
67 hammer_do_history(const char *path, off_t off, int len)
68 {
69 	struct hammer_ioc_history hist;
70 	const char *status;
71 	int fd;
72 	int i;
73 
74 	printf("%s\t", path);
75 	fd = open(path, O_RDONLY);
76 	if (fd < 0) {
77 		printf("%s\n", strerror(errno));
78 		return;
79 	}
80 	bzero(&hist, sizeof(hist));
81 	hist.beg_tid = HAMMER_MIN_TID;
82 	hist.end_tid = HAMMER_MAX_TID;
83 
84 	if (off >= 0) {
85 		hist.flags |= HAMMER_IOC_HISTORY_ATKEY;
86 		hist.key = off;
87 		hist.nxt_key = off + 1;
88 	}
89 
90 
91 	if (ioctl(fd, HAMMERIOC_GETHISTORY, &hist) < 0) {
92 		printf("%s\n", strerror(errno));
93 		close(fd);
94 		return;
95 	}
96 	status = ((hist.flags & HAMMER_IOC_HISTORY_UNSYNCED) ?
97 		 "dirty" : "clean");
98 	printf("%016llx %s {\n", hist.obj_id, status);
99 	for (;;) {
100 		for (i = 0; i < hist.count; ++i) {
101 			struct stat st;
102 			struct tm tp;
103 			time_t t;
104 			char timebuf1[64];
105 			char timebuf2[64];
106 			char *hist_path = NULL;
107 
108 			t = (int64_t)hist.tid_ary[i] / 1000000000LL;
109 			localtime_r(&t, &tp);
110 			strftime(timebuf1, sizeof(timebuf1),
111 				 "%e-%b-%Y %H:%M:%S", &tp);
112 
113 			asprintf(&hist_path, "%s@@0x%016llx",
114 				 path, hist.tid_ary[i]);
115 			if (off < 0 && stat(hist_path, &st) == 0) {
116 				localtime_r(&st.st_mtime, &tp);
117 				strftime(timebuf2, sizeof(timebuf2),
118 					 "%e-%b-%Y %H:%M:%S %Z", &tp);
119 			} else {
120 				snprintf(timebuf2, sizeof(timebuf2), "?");
121 			}
122 			if (off < 0) {
123 				printf("    %016llx %s contents-to %s",
124 				       hist.tid_ary[i],
125 				       timebuf1, timebuf2);
126 			} else {
127 				printf("    %016llx %s",
128 				       hist.tid_ary[i],
129 				       timebuf1);
130 				if (VerboseOpt) {
131 					printf(" '");
132 					dumpat(hist_path, off, len);
133 					printf("'");
134 				}
135 			}
136 			printf("\n");
137 			free(hist_path);
138 		}
139 		if (hist.flags & HAMMER_IOC_HISTORY_EOF)
140 			break;
141 		if (hist.flags & HAMMER_IOC_HISTORY_NEXT_KEY)
142 			break;
143 		if ((hist.flags & HAMMER_IOC_HISTORY_NEXT_TID) == 0)
144 			break;
145 		hist.beg_tid = hist.nxt_tid;
146 		if (ioctl(fd, HAMMERIOC_GETHISTORY, &hist) < 0) {
147 			printf("    error: %s\n", strerror(errno));
148 			break;
149 		}
150 	}
151 	printf("}\n");
152 	close(fd);
153 }
154 
155 static void
156 dumpat(const char *path, off_t off, int len)
157 {
158 	char buf[1024];
159 	int fd;
160 	int n;
161 	int r;
162 
163 	fd = open(path, O_RDONLY);
164 	if (fd < 0)
165 		return;
166 	lseek(fd, off, 0);
167 	while (len) {
168 		n = (len > (int)sizeof(buf)) ? (int)sizeof(buf) : len;
169 		r = read(fd, buf, n);
170 		if (r <= 0)
171 			break;
172 		len -= r;
173 		for (n = 0; n < r; ++n) {
174 			if (isprint(buf[n]))
175 				putc(buf[n], stdout);
176 			else
177 				putc('.', stdout);
178 		}
179 	}
180 }
181 
182