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