[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: