xref: /dflybsd-src/sbin/hammer/cmd_history.c (revision 005a4da7c7e9f1ce1486991786575353476f9282)
113ce745dSMatthew Dillon /*
213ce745dSMatthew Dillon  * Copyright (c) 2008 The DragonFly Project.  All rights reserved.
313ce745dSMatthew Dillon  *
413ce745dSMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
513ce745dSMatthew Dillon  * by Matthew Dillon <dillon@backplane.com>
613ce745dSMatthew Dillon  *
713ce745dSMatthew Dillon  * Redistribution and use in source and binary forms, with or without
813ce745dSMatthew Dillon  * modification, are permitted provided that the following conditions
913ce745dSMatthew Dillon  * are met:
1013ce745dSMatthew Dillon  *
1113ce745dSMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
1213ce745dSMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
1313ce745dSMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
1413ce745dSMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
1513ce745dSMatthew Dillon  *    the documentation and/or other materials provided with the
1613ce745dSMatthew Dillon  *    distribution.
1713ce745dSMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
1813ce745dSMatthew Dillon  *    contributors may be used to endorse or promote products derived
1913ce745dSMatthew Dillon  *    from this software without specific, prior written permission.
2013ce745dSMatthew Dillon  *
2113ce745dSMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2213ce745dSMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2313ce745dSMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2413ce745dSMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
2513ce745dSMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2613ce745dSMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
2713ce745dSMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2813ce745dSMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2913ce745dSMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
3013ce745dSMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
3113ce745dSMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3213ce745dSMatthew Dillon  * SUCH DAMAGE.
3313ce745dSMatthew Dillon  *
341d9f6aa1SMatthew Dillon  * $DragonFly: src/sbin/hammer/cmd_history.c,v 1.4 2008/06/24 17:40:21 dillon Exp $
3513ce745dSMatthew Dillon  */
3613ce745dSMatthew Dillon 
37b45803e3STomohiro Kusumi #include "hammer.h"
38b45803e3STomohiro Kusumi 
398907a51bSTomohiro Kusumi typedef struct cmd_attr {
408907a51bSTomohiro Kusumi 	char *path;
416b2fa60fSTomohiro Kusumi 	int64_t offset;
428907a51bSTomohiro Kusumi 	long length;
438907a51bSTomohiro Kusumi } cmd_attr_t;
448907a51bSTomohiro Kusumi 
456b2fa60fSTomohiro Kusumi static void hammer_do_history(const char *path, off_t off, long len);
468907a51bSTomohiro Kusumi static int parse_attr(const char *s, cmd_attr_t *ca);
478907a51bSTomohiro Kusumi static int parse_attr_path(const char *s, cmd_attr_t *ca);
486b2fa60fSTomohiro Kusumi static void dumpat(const char *path, off_t off, long len);
4946137e17STomohiro Kusumi static const char *timestr32(uint32_t time32);
508f10d7e0STomohiro Kusumi static __inline int test_strtol(int res, long val);
518f10d7e0STomohiro Kusumi static __inline int test_strtoll(int res, long long val);
5213ce745dSMatthew Dillon 
5313ce745dSMatthew Dillon /*
5413ce745dSMatthew Dillon  * history <file1> ... <fileN>
5513ce745dSMatthew Dillon  */
5613ce745dSMatthew Dillon void
hammer_cmd_history(const char * offset_str,char ** av,int ac)5713ce745dSMatthew Dillon hammer_cmd_history(const char *offset_str, char **av, int ac)
5813ce745dSMatthew Dillon {
5900b46268SAntonio Huete Jimenez 	int i;
608907a51bSTomohiro Kusumi 	int old_behavior = 0;
618907a51bSTomohiro Kusumi 	cmd_attr_t ca;
6213ce745dSMatthew Dillon 
638907a51bSTomohiro Kusumi 	bzero(&ca, sizeof(ca));
648907a51bSTomohiro Kusumi 	if (parse_attr(offset_str, &ca) == 0)
658907a51bSTomohiro Kusumi 		old_behavior = 1;
6613ce745dSMatthew Dillon 
678907a51bSTomohiro Kusumi 	for (i = 0; i < ac; ++i) {
688907a51bSTomohiro Kusumi 		if (!old_behavior)
698907a51bSTomohiro Kusumi 			parse_attr_path(av[i], &ca);
708907a51bSTomohiro Kusumi 		if (ca.path == NULL)
718907a51bSTomohiro Kusumi 			ca.path = strdup(av[i]);
728907a51bSTomohiro Kusumi 		hammer_do_history(ca.path, ca.offset, ca.length);
738907a51bSTomohiro Kusumi 		free(ca.path);
748907a51bSTomohiro Kusumi 		ca.path = NULL;
758907a51bSTomohiro Kusumi 	}
7613ce745dSMatthew Dillon }
7713ce745dSMatthew Dillon 
78*005a4da7STomohiro Kusumi static
79*005a4da7STomohiro Kusumi void
hammer_do_history(const char * path,off_t off,long len)806b2fa60fSTomohiro Kusumi hammer_do_history(const char *path, off_t off, long len)
8113ce745dSMatthew Dillon {
8213ce745dSMatthew Dillon 	struct hammer_ioc_history hist;
8313ce745dSMatthew Dillon 	const char *status;
8413ce745dSMatthew Dillon 	int fd;
8513ce745dSMatthew Dillon 	int i;
8613ce745dSMatthew Dillon 
8713ce745dSMatthew Dillon 	printf("%s\t", path);
8813ce745dSMatthew Dillon 	fd = open(path, O_RDONLY);
8913ce745dSMatthew Dillon 	if (fd < 0) {
9013ce745dSMatthew Dillon 		printf("%s\n", strerror(errno));
9113ce745dSMatthew Dillon 		return;
9213ce745dSMatthew Dillon 	}
9313ce745dSMatthew Dillon 	bzero(&hist, sizeof(hist));
9413ce745dSMatthew Dillon 	hist.beg_tid = HAMMER_MIN_TID;
9513ce745dSMatthew Dillon 	hist.end_tid = HAMMER_MAX_TID;
9613ce745dSMatthew Dillon 
9713ce745dSMatthew Dillon 	if (off >= 0) {
9867db3a94SMatthew Dillon 		hist.head.flags |= HAMMER_IOC_HISTORY_ATKEY;
9913ce745dSMatthew Dillon 		hist.key = off;
10013ce745dSMatthew Dillon 		hist.nxt_key = off + 1;
10113ce745dSMatthew Dillon 	}
10213ce745dSMatthew Dillon 
10313ce745dSMatthew Dillon 
10413ce745dSMatthew Dillon 	if (ioctl(fd, HAMMERIOC_GETHISTORY, &hist) < 0) {
10513ce745dSMatthew Dillon 		printf("%s\n", strerror(errno));
10613ce745dSMatthew Dillon 		close(fd);
10713ce745dSMatthew Dillon 		return;
10813ce745dSMatthew Dillon 	}
10967db3a94SMatthew Dillon 	status = ((hist.head.flags & HAMMER_IOC_HISTORY_UNSYNCED) ?
11013ce745dSMatthew Dillon 		 "dirty" : "clean");
111a276dc6bSMatthew Dillon 	printf("%016jx %s {\n", (uintmax_t)hist.obj_id, status);
11213ce745dSMatthew Dillon 	for (;;) {
11313ce745dSMatthew Dillon 		for (i = 0; i < hist.count; ++i) {
11413ce745dSMatthew Dillon 			char *hist_path = NULL;
11513ce745dSMatthew Dillon 
116a276dc6bSMatthew Dillon 			asprintf(&hist_path, "%s@@0x%016jx",
117a276dc6bSMatthew Dillon 				 path, (uintmax_t)hist.hist_ary[i].tid);
118a276dc6bSMatthew Dillon 			printf("    %016jx %s",
119a276dc6bSMatthew Dillon 			       (uintmax_t)hist.hist_ary[i].tid,
1201d9f6aa1SMatthew Dillon 			       timestr32(hist.hist_ary[i].time32));
121f254e677STomohiro Kusumi 			if (off >= 0) {
12213ce745dSMatthew Dillon 				if (VerboseOpt) {
12313ce745dSMatthew Dillon 					printf(" '");
12413ce745dSMatthew Dillon 					dumpat(hist_path, off, len);
12513ce745dSMatthew Dillon 					printf("'");
12613ce745dSMatthew Dillon 				}
127f254e677STomohiro Kusumi 			}
12813ce745dSMatthew Dillon 			printf("\n");
12913ce745dSMatthew Dillon 			free(hist_path);
13013ce745dSMatthew Dillon 		}
13167db3a94SMatthew Dillon 		if (hist.head.flags & HAMMER_IOC_HISTORY_EOF)
13213ce745dSMatthew Dillon 			break;
13367db3a94SMatthew Dillon 		if (hist.head.flags & HAMMER_IOC_HISTORY_NEXT_KEY)
13413ce745dSMatthew Dillon 			break;
13567db3a94SMatthew Dillon 		if ((hist.head.flags & HAMMER_IOC_HISTORY_NEXT_TID) == 0)
13613ce745dSMatthew Dillon 			break;
13713ce745dSMatthew Dillon 		hist.beg_tid = hist.nxt_tid;
13813ce745dSMatthew Dillon 		if (ioctl(fd, HAMMERIOC_GETHISTORY, &hist) < 0) {
13913ce745dSMatthew Dillon 			printf("    error: %s\n", strerror(errno));
14013ce745dSMatthew Dillon 			break;
14113ce745dSMatthew Dillon 		}
14213ce745dSMatthew Dillon 	}
14313ce745dSMatthew Dillon 	printf("}\n");
14413ce745dSMatthew Dillon 	close(fd);
14513ce745dSMatthew Dillon }
14613ce745dSMatthew Dillon 
147*005a4da7STomohiro Kusumi static
148*005a4da7STomohiro Kusumi int
parse_attr(const char * s,cmd_attr_t * ca)1498907a51bSTomohiro Kusumi parse_attr(const char *s, cmd_attr_t *ca)
1508907a51bSTomohiro Kusumi {
1518907a51bSTomohiro Kusumi 	long long offset;
1528907a51bSTomohiro Kusumi 	long length;
1538907a51bSTomohiro Kusumi 	char *rptr;
1548907a51bSTomohiro Kusumi 
1558907a51bSTomohiro Kusumi 	ca->offset = -1;  /* Don't use offset as a key */
1568907a51bSTomohiro Kusumi 	ca->length = 32;  /* Default dump size */
1578907a51bSTomohiro Kusumi 
1588907a51bSTomohiro Kusumi 	if (*s != '@')
1598907a51bSTomohiro Kusumi 		return(-1);  /* not parsed */
1608907a51bSTomohiro Kusumi 
1618907a51bSTomohiro Kusumi 	errno = 0;  /* clear */
1628907a51bSTomohiro Kusumi 	offset = strtoll(s + 1, &rptr, 0);
1638907a51bSTomohiro Kusumi 	if (test_strtoll(errno, offset)) {
1648907a51bSTomohiro Kusumi 		*rptr = '\0';  /* side effect */
16502318f07STomohiro Kusumi 		err(1, "%s", s);
166052fd72bSTomohiro Kusumi 		/* not reached */
1678907a51bSTomohiro Kusumi 	}
1688907a51bSTomohiro Kusumi 	ca->offset = offset;
1698907a51bSTomohiro Kusumi 
1708907a51bSTomohiro Kusumi 	if (*rptr == ',') {
1718907a51bSTomohiro Kusumi 		errno = 0;  /* clear */
1728907a51bSTomohiro Kusumi 		length = strtol(rptr + 1, NULL, 0);
173052fd72bSTomohiro Kusumi 		if (test_strtol(errno, length)) {
17402318f07STomohiro Kusumi 			err(1, "%s", rptr);
175052fd72bSTomohiro Kusumi 			/* not reached */
176052fd72bSTomohiro Kusumi 		}
1778907a51bSTomohiro Kusumi 		if (length >= 0)
1788907a51bSTomohiro Kusumi 			ca->length = length;
1798907a51bSTomohiro Kusumi 	}
1808907a51bSTomohiro Kusumi 
1818907a51bSTomohiro Kusumi 	return(0);
1828907a51bSTomohiro Kusumi }
1838907a51bSTomohiro Kusumi 
184*005a4da7STomohiro Kusumi static
185*005a4da7STomohiro Kusumi int
parse_attr_path(const char * s,cmd_attr_t * ca)1868907a51bSTomohiro Kusumi parse_attr_path(const char *s, cmd_attr_t *ca)
1878907a51bSTomohiro Kusumi {
1888907a51bSTomohiro Kusumi 	int length, ret;
1898907a51bSTomohiro Kusumi 	char *p;
1908907a51bSTomohiro Kusumi 	struct stat st;
1918907a51bSTomohiro Kusumi 
1928907a51bSTomohiro Kusumi 	ca->path = NULL;
1938907a51bSTomohiro Kusumi 
1948907a51bSTomohiro Kusumi 	if (stat(s, &st) == 0)
1958907a51bSTomohiro Kusumi 		return(-1);  /* real path */
1968907a51bSTomohiro Kusumi 
1978907a51bSTomohiro Kusumi 	p = strstr(s, "@");
1988907a51bSTomohiro Kusumi 	if (p == NULL || p == s)
1998907a51bSTomohiro Kusumi 		return(-1);  /* no attr specified */
2008907a51bSTomohiro Kusumi 
2018907a51bSTomohiro Kusumi 	ret = parse_attr(p, ca);
2028907a51bSTomohiro Kusumi 
2038907a51bSTomohiro Kusumi 	length = p - s + 1;
2046153075aSTomohiro Kusumi 	ca->path = calloc(1, length);
2058907a51bSTomohiro Kusumi 	strncpy(ca->path, s, length - 1);
2068907a51bSTomohiro Kusumi 
2078907a51bSTomohiro Kusumi 	return(ret);
2088907a51bSTomohiro Kusumi }
2098907a51bSTomohiro Kusumi 
210*005a4da7STomohiro Kusumi static
211*005a4da7STomohiro Kusumi void
dumpat(const char * path,off_t off,long len)2126b2fa60fSTomohiro Kusumi dumpat(const char *path, off_t off, long len)
21313ce745dSMatthew Dillon {
21413ce745dSMatthew Dillon 	char buf[1024];
21513ce745dSMatthew Dillon 	int fd;
21613ce745dSMatthew Dillon 	int n;
21713ce745dSMatthew Dillon 	int r;
21813ce745dSMatthew Dillon 
21913ce745dSMatthew Dillon 	fd = open(path, O_RDONLY);
22013ce745dSMatthew Dillon 	if (fd < 0)
22113ce745dSMatthew Dillon 		return;
22213ce745dSMatthew Dillon 	lseek(fd, off, 0);
22313ce745dSMatthew Dillon 	while (len) {
22413ce745dSMatthew Dillon 		n = (len > (int)sizeof(buf)) ? (int)sizeof(buf) : len;
22513ce745dSMatthew Dillon 		r = read(fd, buf, n);
22613ce745dSMatthew Dillon 		if (r <= 0)
22713ce745dSMatthew Dillon 			break;
22813ce745dSMatthew Dillon 		len -= r;
22913ce745dSMatthew Dillon 		for (n = 0; n < r; ++n) {
23013ce745dSMatthew Dillon 			if (isprint(buf[n]))
23113ce745dSMatthew Dillon 				putc(buf[n], stdout);
23213ce745dSMatthew Dillon 			else
23313ce745dSMatthew Dillon 				putc('.', stdout);
23413ce745dSMatthew Dillon 		}
23513ce745dSMatthew Dillon 	}
236da6430b6STomohiro Kusumi 	close(fd);
23713ce745dSMatthew Dillon }
23813ce745dSMatthew Dillon 
2391d9f6aa1SMatthew Dillon /*
2401d9f6aa1SMatthew Dillon  * Return a human-readable timestamp
2411d9f6aa1SMatthew Dillon  */
242*005a4da7STomohiro Kusumi static
243*005a4da7STomohiro Kusumi const char *
timestr32(uint32_t time32)24446137e17STomohiro Kusumi timestr32(uint32_t time32)
2451d9f6aa1SMatthew Dillon {
2461d9f6aa1SMatthew Dillon 	static char timebuf[64];
2471d9f6aa1SMatthew Dillon 	time_t t = (time_t)time32;
2481d9f6aa1SMatthew Dillon 	struct tm *tp;
2491d9f6aa1SMatthew Dillon 
2501d9f6aa1SMatthew Dillon 	tp = localtime(&t);
2511d9f6aa1SMatthew Dillon 	strftime(timebuf, sizeof(timebuf), "%d-%b-%Y %H:%M:%S", tp);
2521d9f6aa1SMatthew Dillon 	return(timebuf);
2531d9f6aa1SMatthew Dillon }
2548f10d7e0STomohiro Kusumi 
2558f10d7e0STomohiro Kusumi /*
2568f10d7e0STomohiro Kusumi  * Return non-zero on either overflow or underflow
2578f10d7e0STomohiro Kusumi  */
258*005a4da7STomohiro Kusumi static __inline
259*005a4da7STomohiro Kusumi int
test_strtol(int res,long val)2608f10d7e0STomohiro Kusumi test_strtol(int res, long val)
2618f10d7e0STomohiro Kusumi {
2628f10d7e0STomohiro Kusumi 	return(res == ERANGE && (val == LONG_MIN || val == LONG_MAX));
2638f10d7e0STomohiro Kusumi }
2648f10d7e0STomohiro Kusumi 
265*005a4da7STomohiro Kusumi static __inline
266*005a4da7STomohiro Kusumi int
test_strtoll(int res,long long val)2678f10d7e0STomohiro Kusumi test_strtoll(int res, long long val)
2688f10d7e0STomohiro Kusumi {
2698f10d7e0STomohiro Kusumi 	return(res == ERANGE && (val == LLONG_MIN || val == LLONG_MAX));
2708f10d7e0STomohiro Kusumi }
271