From 2837a13ef9f279bbe34b1030d4ee6e47ca010a4f Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Mon, 21 Feb 2022 15:35:41 +0300 Subject: [PATCH] zdtm: add mountinfo parsing to test lib For mount testing it is nice to be able to parse mountinfo from zdtm test itself, for instance to be able to compare mountinfo topology before and after c/r, or for anything else. So let's add a helper mntns_parse_mountinfo() which parses current mount namespace mountinfo. Signed-off-by: Pavel Tikhomirov --- test/zdtm/lib/Makefile | 2 +- test/zdtm/lib/mountinfo.c | 139 ++++++++++++++++++++++++++++++++++++++ test/zdtm/lib/mountinfo.h | 27 ++++++++ 3 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 test/zdtm/lib/mountinfo.c create mode 100644 test/zdtm/lib/mountinfo.h diff --git a/test/zdtm/lib/Makefile b/test/zdtm/lib/Makefile index 949dc123a..90bd28f9e 100644 --- a/test/zdtm/lib/Makefile +++ b/test/zdtm/lib/Makefile @@ -4,7 +4,7 @@ CFLAGS += $(USERCFLAGS) LIB := libzdtmtst.a -LIBSRC := datagen.c msg.c parseargs.c test.c streamutil.c lock.c ns.c tcp.c unix.c fs.c sysctl.c mem.c file.c +LIBSRC := datagen.c msg.c parseargs.c test.c streamutil.c lock.c ns.c tcp.c unix.c fs.c sysctl.c mem.c file.c mountinfo.c PKG_CONFIG ?= pkg-config pkg-config-check = $(shell sh -c '$(PKG_CONFIG) $(1) && echo y') diff --git a/test/zdtm/lib/mountinfo.c b/test/zdtm/lib/mountinfo.c new file mode 100644 index 000000000..3e9d44581 --- /dev/null +++ b/test/zdtm/lib/mountinfo.c @@ -0,0 +1,139 @@ +#include +#include + +#include "mountinfo.h" +#include "fs.h" +#include "xmalloc.h" + +/* + * mountinfo contains mangled paths. space, tab and back slash were replaced + * with usual octal escape. This function replaces these symbols back. + */ +static void cure_path(char *path) +{ + int i, len, off = 0; + + if (strchr(path, '\\') == NULL) /* fast path */ + return; + + len = strlen(path); + for (i = 0; i < len; i++) { + if (!strncmp(path + i, "\\040", 4)) { + path[i - off] = ' '; + goto replace; + } else if (!strncmp(path + i, "\\011", 4)) { + path[i - off] = '\t'; + goto replace; + } else if (!strncmp(path + i, "\\134", 4)) { + path[i - off] = '\\'; + goto replace; + } + if (off) + path[i - off] = path[i]; + continue; + replace: + off += 3; + i += 3; + } + path[len - off] = 0; +} + +static struct mountinfo_zdtm *mountinfo_zdtm_alloc(struct mntns_zdtm *mntns) +{ + struct mountinfo_zdtm *new; + + new = xzalloc(sizeof(struct mountinfo_zdtm)); + if (new) + list_add_tail(&new->list, &mntns->mountinfo_list); + return new; +} + +static void mountinfo_zdtm_free(struct mountinfo_zdtm *mountinfo) +{ + list_del(&mountinfo->list); + xfree(mountinfo->mountpoint); + xfree(mountinfo->root); + xfree(mountinfo->fstype); + xfree(mountinfo); +} + +static void mountinfo_zdtm_free_all(struct mntns_zdtm *mntns) +{ + struct mountinfo_zdtm *mountinfo, *tmp; + + list_for_each_entry_safe(mountinfo, tmp, &mntns->mountinfo_list, list) + mountinfo_zdtm_free(mountinfo); +} + +#define BUF_SIZE 4096 +char buf[BUF_SIZE]; + +int mntns_parse_mountinfo(struct mntns_zdtm *mntns) +{ + FILE *f; + int ret; + + INIT_LIST_HEAD(&mntns->mountinfo_list); + + f = fopen("/proc/self/mountinfo", "r"); + if (!f) { + pr_perror("Failed to open mountinfo"); + return -1; + } + + while (fgets(buf, BUF_SIZE, f)) { + struct mountinfo_zdtm *new; + unsigned int kmaj, kmin; + char *str, *hyphen, *shared, *master; + int n; + + new = mountinfo_zdtm_alloc(mntns); + if (!new) { + pr_perror("Failed to alloc mountinfo_zdtm"); + goto free; + } + + ret = sscanf(buf, "%i %i %u:%u %ms %ms %*s %n", &new->mnt_id, &new->parent_mnt_id, &kmaj, &kmin, + &new->root, &new->mountpoint, &n); + if (ret != 6) { + pr_perror("Failed to parse mountinfo line \"%s\"", buf); + goto free; + } + cure_path(new->root); + cure_path(new->mountpoint); + new->s_dev = MKKDEV(kmaj, kmin); + + str = buf + n; + hyphen = strstr(buf, " - "); + if (!hyphen) { + pr_perror("Failed to find \" - \" in mountinfo line \"%s\"", buf); + goto free; + } + *hyphen++ = '\0'; + + shared = strstr(str, "shared:"); + if (shared) + new->shared_id = atoi(shared + 7); + master = strstr(str, "master:"); + if (master) + new->master_id = atoi(master + 7); + + ret = sscanf(hyphen, "- %ms", &new->fstype); + if (ret != 1) { + pr_perror("Failed to parse fstype in mountinfo tail \"%s\"", hyphen); + goto free; + } + } + + fclose(f); + return 0; +free: + mountinfo_zdtm_free_all(mntns); + fclose(f); + return -1; +} + +void mntns_free_all(struct mntns_zdtm *mntns) +{ + mountinfo_zdtm_free_all(mntns); +} diff --git a/test/zdtm/lib/mountinfo.h b/test/zdtm/lib/mountinfo.h new file mode 100644 index 000000000..8b7459d21 --- /dev/null +++ b/test/zdtm/lib/mountinfo.h @@ -0,0 +1,27 @@ +#ifndef __ZDTM_MOUNTINFO__ +#define __ZDTM_MOUNTINFO__ + +#include "list.h" + +struct mountinfo_zdtm { + int mnt_id; + int parent_mnt_id; + char *mountpoint; + char *root; + unsigned int s_dev; + int shared_id; + int master_id; + char *fstype; + + /* list of all mounts */ + struct list_head list; +}; + +struct mntns_zdtm { + struct list_head mountinfo_list; +}; + +extern int mntns_parse_mountinfo(struct mntns_zdtm *mntns); +extern void mntns_free_all(struct mntns_zdtm *mntns); + +#endif