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