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 <anpr...@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

Reply via email to