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

[Cluster-devel] [PATCH] libgfs2: Add a small testing language UI



This adds a minimal 'gfs2l' command to allow easy use of the testing
language. It takes one -f option to specify a script file and a single
argument to specify the path to the fs.

It can be used to build a rudimentary REPL e.g.

  # while read s; do echo "$s" | gfs2l -f- /dev/foo; done
  get sb
  ...

But it's mainly intended to be used as a component of in-tree test
scripts and will not be installed by the build system.

Signed-off-by: Andrew Price <anprice redhat com>
---
 gfs2/libgfs2/Makefile.am |   6 ++
 gfs2/libgfs2/gfs2l.c     | 146 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 152 insertions(+)
 create mode 100644 gfs2/libgfs2/gfs2l.c

diff --git a/gfs2/libgfs2/Makefile.am b/gfs2/libgfs2/Makefile.am
index 7103e09..9c4e96b 100644
--- a/gfs2/libgfs2/Makefile.am
+++ b/gfs2/libgfs2/Makefile.am
@@ -9,6 +9,8 @@ noinst_HEADERS		= libgfs2.h lang.h
 
 noinst_LTLIBRARIES	= libgfs2.la
 
+noinst_PROGRAMS		= gfs2l
+
 libgfs2_la_SOURCES	= block_list.c fs_bits.c gfs1.c misc.c rgrp.c super.c \
 			  buf.c fs_geometry.c gfs2_disk_hash.c ondisk.c \
 			  device_geometry.c fs_ops.c gfs2_log.c recovery.c \
@@ -19,6 +21,10 @@ libgfs2_la_CPPFLAGS	= -D_FILE_OFFSET_BITS=64 \
 			  -D_GNU_SOURCE \
 			  -I$(top_srcdir)/gfs2/include
 
+gfs2l_SOURCES		= gfs2l.c
+gfs2l_CPPFLAGS		= -I$(top_srcdir)/gfs2/include
+gfs2l_LDADD		= $(top_builddir)/gfs2/libgfs2/libgfs2.la
+
 # Autotools can't handle header files output by flex so we have to generate it manually
 lexer.h: lexer.l
 	$(LEX) -o lexer.c $(AM_LFLAGS) $^
diff --git a/gfs2/libgfs2/gfs2l.c b/gfs2/libgfs2/gfs2l.c
new file mode 100644
index 0000000..2eacb2d
--- /dev/null
+++ b/gfs2/libgfs2/gfs2l.c
@@ -0,0 +1,146 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include "libgfs2.h"
+
+static void usage(const char *cmd)
+{
+	fprintf(stderr, "Usage: %s -f <script_path> <fs_path>\n", cmd);
+	fprintf(stderr, "Use -f - for stdin\n");
+}
+
+struct cmdopts {
+	char *fspath;
+	FILE *src;
+};
+
+static int getopts(int argc, char *argv[], struct cmdopts *opts)
+{
+	int opt;
+	while ((opt = getopt(argc, argv, "f:")) != -1) {
+		switch (opt) {
+		case 'f':
+			if (!strcmp("-", optarg)) {
+				opts->src = stdin;
+			} else {
+				opts->src = fopen(optarg, "r");
+				if (opts->src == NULL) {
+					perror("Failed to open source file");
+					return 1;
+				}
+			}
+			break;
+		default:
+			usage(argv[0]);
+			return 1;
+		}
+	}
+
+	if (argc - optind != 1) {
+		usage(argv[0]);
+		return 1;
+	}
+
+	opts->fspath = strdup(argv[optind]);
+	if (opts->fspath == NULL) {
+		perror("getopts");
+		return 1;
+	}
+	return 0;
+}
+
+static struct gfs2_sbd *openfs(const char *path)
+{
+	int fd;
+	int ret;
+	int sane;
+	int count;
+	struct gfs2_sbd *sdp = calloc(1, sizeof(struct gfs2_sbd));
+	if (sdp == NULL) {
+		perror("calloc");
+		return NULL;
+	}
+
+	fd = open(path, O_RDWR);
+	if (fd < 0) {
+		fprintf(stderr, "Failed to open %s\n", path);
+		free(sdp);
+		return NULL;
+	}
+
+	memset(sdp, 0, sizeof(*sdp));
+	sdp->bsize = GFS2_BASIC_BLOCK;
+	sdp->device_fd = fd;
+	compute_constants(sdp);
+	lgfs2_get_dev_info(fd, &sdp->dinfo);
+	fix_device_geometry(sdp);
+
+	ret = read_sb(sdp);
+	if (ret != 0) {
+		perror("Could not read sb");
+		return NULL;
+	}
+
+	sdp->master_dir = lgfs2_inode_read(sdp, sdp->sd_sb.sb_master_dir.no_addr);
+	gfs2_lookupi(sdp->master_dir, "rindex", 6, &sdp->md.riinode);
+	sdp->fssize = sdp->device.length;
+	if (sdp->md.riinode) {
+		rindex_read(sdp, 0, &count, &sane);
+	} else {
+		perror("Failed to look up rindex");
+		free(sdp);
+		return NULL;
+	}
+	return sdp;
+}
+
+int main(int argc, char *argv[])
+{
+	int ret;
+	struct cmdopts opts = {NULL, NULL};
+	struct gfs2_sbd *sdp;
+	struct lgfs2_lang_result *result;
+	struct lgfs2_lang_state *state;
+
+	if (getopts(argc, argv, &opts)) {
+		exit(1);
+	}
+
+	sdp = openfs(argv[optind]);
+	if (sdp == NULL) {
+		exit(1);
+	}
+
+	state = lgfs2_lang_init();
+	if (state == NULL) {
+		perror("lgfs2_lang_init failed");
+		exit(1);
+	}
+
+	ret = lgfs2_lang_parsef(state, opts.src);
+	if (ret != 0) {
+		fprintf(stderr, "Parse failed\n");
+		return ret;
+	}
+
+	for (result = lgfs2_lang_result_next(state, sdp);
+	     result != NULL;
+	     result = lgfs2_lang_result_next(state, sdp)) {
+		if (result == NULL) {
+			fprintf(stderr, "Failed to interpret script\n");
+			return -1;
+		}
+		lgfs2_lang_result_print(result);
+		lgfs2_lang_result_free(&result);
+	}
+
+	gfs2_rgrp_free(&sdp->rgtree);
+	inode_put(&sdp->md.riinode);
+	inode_put(&sdp->master_dir);
+	lgfs2_lang_free(&state);
+	free(opts.fspath);
+	return 0;
+}
+
+// libgfs2 still requires an external print_it function
+void print_it(const char *label, const char *fmt, const char *fmt2, ...) { return; }
-- 
1.7.11.7


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