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