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

Andrew Price <[email protected]>
Newsgroups com.redhat.cluster-devel
Message-ID <[email protected]>
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 <[email protected]>
---
 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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.