[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[PATCH 6/7] nbd-trplay: Add simple CLI



Add an initial CLI.
Planned CLI extentions:
- define what TRIM should do: keep unchanged, set to 0, take the content
  from another block.
- do not apply all sectors, instead behave like a write-back cache
  and drop a few random sectors.
- Create a log file of what was skipped/applied.
- Replay a log file.

Signed-off-by: Manfred Spraul <manfred.spraul@de.bosch.com>
---
 nbd-trplay.c | 119 +++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 102 insertions(+), 17 deletions(-)

diff --git a/nbd-trplay.c b/nbd-trplay.c
index e31bb3b..fa13e49 100644
--- a/nbd-trplay.c
+++ b/nbd-trplay.c
@@ -1,14 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * nbd-trplay.c
  *
  * Takes an nbd transaction log file and replays some/all of the write commands.
+ *
+ * Based on nbd-trdump
+ * (C) Robert Bosch GmbH, 2021
  */
 
 #include <stdlib.h>
+#include <limits.h>
 #include <stdio.h>
 #include <string.h>
 #include <sys/time.h>
 #include <sys/types.h>
+#include <fcntl.h>
 #include <stdint.h>
 #include <unistd.h>
 #include "config.h"
@@ -21,6 +27,16 @@
 #define BUFSIZE	131072
 static char tmpbuf[BUFSIZE];
 
+#define	VERBOSE_DEBUG	3
+#define	VERBOSE_DETAILS	2
+#define	VERBOSE_NORMAL	1
+#define	VERBOSE_OFF	0
+
+int g_verbose = 0;
+
+unsigned long g_blocksize = 512;
+unsigned long long g_max_blocks = ULLONG_MAX;
+
 static inline void doread(int f, void *buf, size_t len) {
         ssize_t res;
 
@@ -36,7 +52,7 @@ static inline void doread(int f, void *buf, size_t len) {
         }
 }
 
-int main(int argc, char**argv) {
+int main_loop(int logfd, int imagefd) {
 	struct nbd_request req;
 	struct nbd_reply rep;
 	uint32_t magic;
@@ -46,26 +62,14 @@ int main(int argc, char**argv) {
 	uint32_t len;
 	uint64_t offset;
 	const char * ctext;
-	int readfd = 0; /* stdin */
-
-	if(argc > 1) {
-		int retval=0;
-		if(strcmp(argv[1], "--help") && strcmp(argv[1], "-h")) {
-			printf("E: unknown option %s.\n", argv[1]);
-			retval=1;
-		}
-		printf("This is nbd-trplay, part of nbd %s.\n", PACKAGE_VERSION);
-		printf("Use: %s < transactionlog\n", argv[0]);
-		return retval;
-	}
 
 	while (1) {
 		/* Read a request or reply from the transaction file */
-		doread(readfd, &magic, sizeof(magic));
+		doread(logfd, &magic, sizeof(magic));
 		magic = ntohl(magic);
 		switch (magic) {
 		case NBD_REQUEST_MAGIC:
-			doread(readfd, sizeof(magic)+(char *)(&req), sizeof(struct nbd_request)-sizeof(magic));
+			doread(logfd, sizeof(magic)+(char *)(&req), sizeof(struct nbd_request)-sizeof(magic));
 			handle = ntohll(*((long long int *)(req.handle)));
 			offset = ntohll(req.from);
 			len = ntohl(req.len);
@@ -86,14 +90,14 @@ int main(int argc, char**argv) {
 
 					if (tmplen > BUFSIZE)
 						tmplen = BUFSIZE;
-					doread(readfd, tmpbuf, tmplen);
+					doread(logfd, tmpbuf, tmplen);
 					len -= tmplen;
 				}
 			}
 
 			break;
 		case NBD_REPLY_MAGIC:
-			doread(readfd, sizeof(magic)+(char *)(&rep), sizeof(struct nbd_reply)-sizeof(magic));
+			doread(logfd, sizeof(magic)+(char *)(&rep), sizeof(struct nbd_reply)-sizeof(magic));
 			handle = ntohll(*((long long int *)(rep.handle)));
 			error = ntohl(rep.error);
 
@@ -111,3 +115,84 @@ int main(int argc, char**argv) {
 	/* never reached */
 	return 0;
 }
+
+static void show_help(const char *progname) {
+	printf("\n");
+	printf("This is nbd-trplay, part of nbd %s.\n", PACKAGE_VERSION);
+	printf("Use: %s -i <image> -l <log> [-m <max blocks>] [-b <block size]\n", progname);
+	printf(" Applies up to <max blocks> elements from file <log> to disk image <image>.\n");
+	printf(" Command line parameters:\n");
+	printf(" <image>: name of the initial image file.\n");
+	printf(" <log>: nbd trace log. Must contain actual data (datalog=true).\n");
+	printf(" <block size>: device block size. Default 512.\n");
+	printf(" <max blocks>: where to stop the replay. Default all.\n");
+	printf("  -v: Increase verbose level. Specify multiple times to increase further.\n");
+
+}
+
+
+int main(int argc, char **argv) {
+	int opt;
+	int imagefd = -1;
+	int logfd = -1;
+
+	printf("%s -i <image> -l <log> [-m <max blocks>] [-b <block size]\n", argv[0]);
+
+	while ((opt = getopt(argc, argv, "i:l:m:b:hv")) != -1) {
+		switch(opt) {
+		case 'v':
+			g_verbose++;
+			break;
+		default:
+		case '?':
+		case 'h':
+			show_help(argv[0]);
+			return 0;
+		case 'm':
+			g_max_blocks = strtoull(optarg, NULL, 0);
+			if (g_max_blocks == 0) {
+				printf("  Invalid block count.\n");
+				return 1;
+			}
+		case 'b':
+			g_blocksize = strtoul(optarg, NULL, 0);
+			if (g_blocksize == 0) {
+				printf("  Invalid block size.\n");
+				return 1;
+			}
+			if (g_blocksize > BUFSIZE) {
+				printf(" block size is larger than %d, not supported.\n", (int)BUFSIZE);
+				return 1;
+			}
+		case 'i':
+			imagefd = open(optarg, O_RDWR, 0);
+			if (imagefd == -1) {
+				printf("  Opening disk image failed, errno %d.", errno);
+				return 1;
+			}
+		case 'l':
+			logfd = open(optarg, O_RDONLY, 0);
+			if (logfd == -1) {
+				printf("  Opening disk image failed, errno %d.", errno);
+				return 1;
+			}
+		}
+	}
+
+	if (logfd == -1) {
+		printf("  Log file not specified, this is mandatory.\n");
+		return 1;
+	}
+	if (imagefd == -1) {
+		printf("  Disk image not specified, this is mandatory.\n");
+		return 1;
+	}
+
+	if (g_verbose >= VERBOSE_NORMAL) {
+		printf(" block size: %ld bytes (0x%lx bytes).\n", g_blocksize, g_blocksize);
+		printf(" max blocks to apply: %llx.\n", g_max_blocks);
+	}
+	main_loop(logfd, imagefd);
+
+	return 0;
+}
-- 
2.33.1


Reply to: