libhammer - HAMMER filesystem library.
authorAntonio Huete Jimenez <tuxillo@quantumachine.net>
Tue, 25 Oct 2011 22:34:24 +0000 (00:34 +0200)
committerAntonio Huete Jimenez <tuxillo@quantumachine.net>
Tue, 25 Oct 2011 22:40:21 +0000 (00:40 +0200)
Initial work to bring a library to help operating
HAMMER filesystems from userland.

It's barebones as of now, only "info" directive is
adapted, progressively the rest of the directives
will be migrated

Help-from: @swildner, @sjg

lib/libhammer/Makefile [new file with mode: 0644]
lib/libhammer/info.c [new file with mode: 0644]
lib/libhammer/libhammer.h [new file with mode: 0644]
lib/libhammer/libhammer_get_volinfo.3 [new file with mode: 0644]
lib/libhammer/misc.c [new file with mode: 0644]

diff --git a/lib/libhammer/Makefile b/lib/libhammer/Makefile
new file mode 100644 (file)
index 0000000..da99a10
--- /dev/null
@@ -0,0 +1,20 @@
+# DragonflyBSD Makefile
+
+LIB=   hammer
+SRCS=  crc32.c info.c misc.c
+INCS=  libhammer.h
+
+SRCS+= crc32.c
+
+MAN+=   libhammer_get_volinfo.3
+
+MLINKS+= libhammer_get_volinfo.3 libhammer_get_next_pfs.3
+MLINKS+= libhammer_get_volinfo.3 libhammer_get_prev_pfs.3
+MLINKS+= libhammer_get_volinfo.3 libhammer_get_first_pfs.3
+MLINKS+= libhammer_get_volinfo.3 libhammer_get_last_pfs.3
+MLINKS+= libhammer_get_volinfo.3 libhammer_free_volinfo.3
+
+.PATH: ${.CURDIR}/../../sys/libkern
+SHLIB_MAJOR=   0
+
+.include <bsd.lib.mk>
diff --git a/lib/libhammer/info.c b/lib/libhammer/info.c
new file mode 100644 (file)
index 0000000..532cd35
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2011 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Antonio Huete <tuxillo@quantumachine.net>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <libhammer.h>
+
+static u_int32_t count_snapshots(u_int32_t, char *, char *, int *);
+
+libhammer_volinfo_t
+libhammer_get_volinfo(const char *path)
+{
+       struct hammer_ioc_pseudofs_rw pseudofs;
+       struct hammer_pseudofs_data *pfs_od;
+       struct hammer_ioc_info info;
+       libhammer_pfsinfo_t pfstmp;
+       libhammer_volinfo_t hvi;
+       int pfs_id;
+       int fd;
+
+       hvi = _libhammer_malloc(sizeof(*hvi));
+
+       TAILQ_INIT(&hvi->list_pseudo);
+
+       if ((fd = open(path, O_RDONLY)) < 0)
+               goto error1;
+
+       if ((ioctl(fd, HAMMERIOC_GET_INFO, &info)) < 0)
+               goto error1;
+
+       /* Fill volume information */
+       snprintf(hvi->vol_name, TXTLEN, "%s", info.vol_name);
+       hvi->vol_fsid = info.vol_fsid;
+       hvi->version = info.version;
+       hvi->nvolumes = info.nvolumes;
+       hvi->bigblocks = info.bigblocks;
+       hvi->rsvbigblocks = info.rsvbigblocks;
+
+       /*
+        * XXX - By now we iterate the whole range of +65000 possible
+        * pseudofs to discover the ones that are in use. Of course
+        * this is suboptimal. Best way would be to extract the
+        * pseudofs information from the control records in the
+        * B-Tree, that's in kernel land.
+        */
+       pfs_od = _libhammer_malloc(sizeof(*pfs_od));
+
+       for(pfs_id = 0; pfs_id < HAMMER_MAX_PFS; pfs_id++) {
+               /* Clear the struct to be passed to the ioctl. */
+               bzero(&pseudofs, sizeof(pseudofs));
+
+               pfstmp = _libhammer_malloc(sizeof(*pfstmp));
+
+               pseudofs.pfs_id = pfs_id;
+               pseudofs.ondisk = pfs_od;
+               pseudofs.bytes = sizeof(struct hammer_pseudofs_data);
+               pseudofs.version = HAMMER_IOC_PSEUDOFS_VERSION;
+               if (ioctl(fd, HAMMERIOC_GET_PSEUDOFS, &pseudofs) != -1) {
+                       /* XXX
+                        * It may be completely wrong in the case that we pass a path
+                        * that is in PFS 0 but isn't the mount path of it. There's no
+                        * easy way to do this.
+                        */
+                       pfstmp->ismaster = (pfs_od->mirror_flags & HAMMER_PFSD_SLAVE)
+                           ? 0 : 1;
+
+                       if (pfs_id == 0)
+                               pfstmp->mountedon = strdup(path);
+                       else
+                               pfstmp->mountedon = libhammer_find_pfs_mount(pfs_id,
+                                   hvi->vol_fsid, pfstmp->ismaster);
+                       /*
+                        * Fill in structs used in the library. We don't rely on
+                        * HAMMER own struct but we do fill our own.
+                        */
+                       pfstmp->version = pseudofs.version;
+                       pfstmp->pfs_id = pseudofs.pfs_id;
+                       pfstmp->mirror_flags = pfs_od->mirror_flags;
+                       pfstmp->snapcount = count_snapshots(hvi->version,
+                           pfstmp->snapshots, pfstmp->mountedon, &pfstmp->head.error);
+
+                       TAILQ_INSERT_TAIL(&hvi->list_pseudo, pfstmp, entries);
+               }
+       }
+
+       goto end;
+
+error1:
+       libhammer_free_volinfo(hvi);
+       if (fd != -1)
+               close(fd);
+
+end:
+       return (hvi);
+}
+
+void
+libhammer_free_volinfo(libhammer_volinfo_t volinfo)
+{
+       struct libhammer_pfsinfo *pfstmp;
+
+       while(!TAILQ_EMPTY(&volinfo->list_pseudo)) {
+               pfstmp = TAILQ_FIRST(&volinfo->list_pseudo);
+               free(pfstmp->mountedon);
+               TAILQ_REMOVE(&volinfo->list_pseudo, pfstmp, entries);
+               free(pfstmp);
+       }
+       free(volinfo);
+}
+
+static u_int32_t
+count_snapshots(u_int32_t version, char *pfs_snapshots, char *mountedon, int *errorp)
+{
+       struct hammer_ioc_snapshot snapinfo;
+       char *snapshots_path, *fpath;
+       struct dirent *den;
+       struct stat st;
+       DIR *dir;
+       u_int32_t snapshot_count;
+       int fd;
+
+       snapshot_count = 0;
+
+       bzero(&snapinfo, sizeof(struct hammer_ioc_snapshot));
+
+       fd = open(mountedon, O_RDONLY);
+       if (fd < 0) {
+               *errorp = errno;
+               return 0;
+       }
+
+       if (version < 3) {
+               /*
+                * old style: count the number of softlinks in the snapshots dir
+                */
+               if (pfs_snapshots[0])
+                       snapshots_path = pfs_snapshots;
+               else
+                       asprintf(&snapshots_path, "%s/snapshots", mountedon);
+               if ((dir = opendir(snapshots_path)) != NULL) {
+                       while ((den = readdir(dir)) != NULL) {
+                               if (den->d_name[0] == '.')
+                                       continue;
+                               asprintf(&fpath, "%s/%s", snapshots_path,
+                                   den->d_name);
+                               if (lstat(fpath, &st) == 0 &&
+                                   S_ISLNK(st.st_mode))
+                                       snapshot_count++;
+                               free(fpath);
+                       }
+                       closedir(dir);
+               }
+       } else {
+               /*
+                * new style: file system meta-data
+                */
+               do {
+                       if (ioctl(fd, HAMMERIOC_GET_SNAPSHOT, &snapinfo) < 0) {
+                               *errorp = errno;
+                               goto out;
+                       }
+
+                       snapshot_count += snapinfo.count;
+               } while (snapinfo.head.error == 0 && snapinfo.count);
+       }
+
+out:
+       if (fd != -1)
+               close(fd);
+       return snapshot_count;
+}
diff --git a/lib/libhammer/libhammer.h b/lib/libhammer/libhammer.h
new file mode 100644 (file)
index 0000000..915cca7
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2011 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Antonio Huete <tuxillo@quantumachine.net>
+ * by Matthew Dillon <dillon@backplane.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#ifndef _LIBHAMMER_H_
+#define _LIBHAMMER_H_
+
+#include <sys/queue.h>
+#include <sys/param.h>
+
+#include <vfs/hammer/hammer_disk.h>
+#include <vfs/hammer/hammer_ioctl.h>
+
+#define TXTLEN 64
+
+#define HAMMER_BUFLISTS                64
+#define HAMMER_BUFLISTMASK     (HAMMER_BUFLISTS - 1)
+#define COLLECT_HSIZE  1024
+#define COLLECT_HMASK  (COLLECT_HSIZE - 1)
+#define HAMMER_BUFINFO_READAHEAD       0x0001
+/*
+ * WARNING: Do not make the SNAPSHOTS_BASE "/var/snapshots" because
+ * it will interfere with the older HAMMER VERS < 3 snapshots directory
+ * for the /var PFS.
+ */
+#define SNAPSHOTS_BASE "/var/hammer"   /* HAMMER VERS >= 3 */
+#define WS     " \t\r\n"
+
+#define SERIALBUF_SIZE (512 * 1024)
+#define RD_HSIZE       32768
+#define RD_HMASK       (RD_HSIZE - 1)
+
+#define DICTF_MADEDIR  0x01
+#define DICTF_MADEFILE 0x02
+#define DICTF_PARENT   0x04    /* parent attached for real */
+#define DICTF_TRAVERSED        0x80
+#define FLAG_TOOFARLEFT                0x0001
+#define FLAG_TOOFARRIGHT       0x0002
+#define FLAG_BADTYPE           0x0004
+#define FLAG_BADCHILDPARENT    0x0008
+#define FLAG_BADMIRRORTID      0x0010
+
+/*
+ * Hammer information system structures
+ */
+struct libhammer_head {
+       int32_t error;
+       int32_t flags;
+       int32_t rsv[2];
+};
+
+typedef struct libhammer_pfsinfo {
+       struct libhammer_head head; /* Additional error and flags */
+
+       uint32_t  snapcount;        /* Snapshot count */
+       u_int32_t version;          /* HAMMER version */
+       char      *mountedon;       /* Mount path of the PFS */
+       int       ismaster;         /* Is a PFS master */
+       int       pfs_id;           /* PFS ID number */
+       int       mirror_flags;     /* Misc flags */
+       char      snapshots[64];    /* softlink dir for pruning */
+       uuid_t    unique_uuid;      /* unique uuid of this master/slave */
+       TAILQ_ENTRY(libhammer_pfsinfo) entries;
+} *libhammer_pfsinfo_t;
+
+typedef struct libhammer_volinfo {
+       struct libhammer_head head; /* Additional error and flags */
+
+       char     vol_name[TXTLEN];  /* Volume name */
+       uuid_t   vol_fsid;          /* Filesystem UUID */
+       int      version;           /* HAMMER version */
+       int      nvolumes;          /* Number of volumes */
+       int64_t  bigblocks;         /* Total big blocks */
+       int64_t  rsvbigblocks;      /* Reserved big blocks */
+       int32_t  rsv[8];
+       TAILQ_HEAD(pfslist, libhammer_pfsinfo) list_pseudo;
+} *libhammer_volinfo_t;
+
+/*
+ * INFO directive prototypes
+ */
+__BEGIN_DECLS
+libhammer_volinfo_t libhammer_get_volinfo(const char *);
+void libhammer_free_volinfo(libhammer_volinfo_t);
+__END_DECLS
+
+static __inline libhammer_pfsinfo_t
+libhammer_get_next_pfs(libhammer_pfsinfo_t pfsinfo)
+{
+       return TAILQ_NEXT(pfsinfo, entries);
+}
+
+static __inline libhammer_pfsinfo_t
+libhammer_get_prev_pfs(libhammer_pfsinfo_t pfsinfo)
+{
+       return TAILQ_PREV(pfsinfo, pfslist, entries);
+}
+
+static __inline libhammer_pfsinfo_t
+libhammer_get_first_pfs(libhammer_volinfo_t volinfo)
+{
+       return TAILQ_FIRST(&volinfo->list_pseudo);
+}
+
+static __inline libhammer_pfsinfo_t
+libhammer_get_last_pfs(libhammer_volinfo_t volinfo)
+{
+       return TAILQ_LAST(&volinfo->list_pseudo, pfslist);
+}
+
+#endif
+
+/*
+ * MISC directive prototypes
+ */
+__BEGIN_DECLS
+char *libhammer_find_pfs_mount(int, uuid_t, int);
+void *_libhammer_malloc(size_t);
+__END_DECLS
diff --git a/lib/libhammer/libhammer_get_volinfo.3 b/lib/libhammer/libhammer_get_volinfo.3
new file mode 100644 (file)
index 0000000..5df6651
--- /dev/null
@@ -0,0 +1,124 @@
+.\"
+.\" Copyright (c) 2011 The DragonFly Project.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to The DragonFly Project
+.\" by Antonio Huete Jimenez <tuxillo@quantumachine.net>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in
+.\"    the documentation and/or other materials provided with the
+.\"    distribution.
+.\" 3. Neither the name of The DragonFly Project nor the names of its
+.\"    contributors may be used to endorse or promote products derived
+.\"    from this software without specific, prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+.\" FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+.\" COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+.\" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+.\" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd October 25, 2011
+.Dt LIBHAMMER 3
+.Os
+.Sh NAME
+.Nm libhammer_get_volinfo
+.Nm libhammer_get_next_pfs
+.Nm libhammer_get_prev_pfs
+.Nm libhammer_get_first_pfs
+.Nm libhammer_get_last_pfs
+.Nm libhammer_free_volinfo
+.Nd libhammer information functions
+.Sh LIBRARY
+.Lb libhammer
+.Sh SYNOPSIS
+.In libhammer.h
+.Ft libhammer_volinfo_t
+.Fn libhammer_get_volinfo "const char *path"
+.Ft libhammer_pfsinfo_t
+.Fn libhammer_get_first_pfs "libhammer_volinfo_t volinfo"
+.Ft libhammer_pfsinfo_t
+.Fn libhammer_get_last_pfs "libhammer_volinfo_t volinfo"
+.Ft libhammer_pfsinfo_t
+.Fn libhammer_get_next_pfs "libhammer_pfsinfo_t pfsinfo"
+.Ft libhammer_pfsinfo_t
+.Fn libhammer_get_prev_pfs "libhammer_pfsinfo_t pfsinfo"
+.Ft void
+.Fn libhammer_free_volinfo "libhammer_volinfo_t volinfo"
+.Sh DESCRIPTION
+The
+.Fn libhammer_get_volinfo
+iterates all the PFSs from a given path belonging to a
+.Nm HAMMER
+filesystem and returns
+.Vt libhammer_volinfo_t
+.Fa volinfo
+which holds a
+.Nm TAILQ
+of
+.Vt libhammer_pfsinfo
+structs, one per PFS found.
+.Pp
+The list of found PFSs can be iterated with
+.Fn libhammer_get_first_pfs ,
+.Fn libhammer_get_last_pfs ,
+.Fn libhammer_get_next_pfs
+and
+.Fn libhammer_get_prev_pfs .
+.Pp
+Note that to use the next and previous functions described above you need
+to store the returning
+.Vt libhammer_pfsinfo_t
+value from the first and last functions.
+.Pp
+.Fn libhammer_free_volinfo
+frees up all the memory allocated previously by
+.Fn libhammer_get_volinfo .
+.Sh RETURN VALUES
+.Fn libhammer_get_volinfo
+returns a
+.Vt libhammer_volinfo_t
+in any case where path is in a
+.Nm HAMMER
+filesystem scope or
+.Dv NULL
+if there was any other problem.
+You can check
+.Nm errno
+in the error cases.
+.Pp
+.Fn libhammer_get_first_pfs
+and
+.Fn libhammer_get_last_pfs
+must return a
+.Vt libhammer_pfs_t
+if the
+.Fa volinfo
+passed in is valid.
+.Fn libhammer_get_next_pfs
+and
+.Fn libhammer_get_prev_pfs
+return a
+.Vt libhammer_pfsinfo_t
+or
+.Dv NULL
+in case there are no more elements.
+.Sh SEE ALSO
+.Xr HAMMER 5 ,
+.Xr hammer 8 ,
+.Sh AUTHORS
+This manpage was written by
+.An Antonio Huete Jimenez.
diff --git a/lib/libhammer/misc.c b/lib/libhammer/misc.c
new file mode 100644 (file)
index 0000000..a1b6d8e
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2011 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.com>
+ * by Antonio Huete <tuxillo@quantumachine.net>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <fcntl.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <uuid.h>
+
+#include <libhammer.h>
+
+char *
+libhammer_find_pfs_mount(int pfsid, uuid_t parentuuid, int ismaster)
+{
+       struct hammer_ioc_info hi;
+       struct statfs *mntbuf;
+       int mntsize;
+       int curmount;
+       int fd;
+       size_t  mntbufsize;
+       char *trailstr;
+       char *retval;
+
+       retval = NULL;
+
+       /* Do not continue if there are no mounted filesystems */
+       mntsize = getfsstat(NULL, 0, MNT_NOWAIT);
+       if (mntsize <= 0)
+               return retval;
+
+       mntbufsize = (mntsize) * sizeof(struct statfs);
+       mntbuf = _libhammer_malloc(mntbufsize);
+       if (mntbuf == NULL) {
+               perror("show_info");
+               exit(EXIT_FAILURE);
+       }
+
+       mntsize = getfsstat(mntbuf, (long)mntbufsize, MNT_NOWAIT);
+       curmount = mntsize - 1;
+
+       asprintf(&trailstr, ":%05d", pfsid);
+
+       /*
+        * Iterate all the mounted points looking for the PFS passed to
+        * this function.
+        */
+       while(curmount >= 0) {
+               /*
+                * We need to avoid that PFS belonging to other HAMMER
+                * filesystems are showed as mounted, so we compare
+                * against the FSID, which is presumable to be unique.
+                */
+               bzero(&hi, sizeof(hi));
+               if ((fd = open(mntbuf[curmount].f_mntfromname, O_RDONLY)) < 0) {
+                       curmount--;
+                       continue;
+               }
+
+               if ((ioctl(fd, HAMMERIOC_GET_INFO, &hi)) < 0) {
+                       curmount--;
+                       continue;
+               }
+
+               if (strstr(mntbuf[curmount].f_mntfromname, trailstr) != NULL &&
+                   (uuid_compare(&hi.vol_fsid, &parentuuid, NULL)) == 0) {
+                       if (ismaster) {
+                               if (strstr(mntbuf[curmount].f_mntfromname,
+                                   "@@-1") != NULL) {
+                                       retval =
+                                           strdup(mntbuf[curmount].f_mntonname);
+                                       break;
+                               }
+                       } else {
+                               if (strstr(mntbuf[curmount].f_mntfromname,
+                                   "@@0x") != NULL ) {
+                                       retval =
+                                           strdup(mntbuf[curmount].f_mntonname);
+                                       break;
+                               }
+                       }
+               }
+               curmount--;
+               close(fd);
+       }
+       free(trailstr);
+
+       return retval;
+}
+
+/*
+ * Allocate len bytes of memory and return the pointer.
+ * It'll exit in the case no memory could be allocated.
+ *
+ * To be used only by the library itself.
+ */
+void *
+_libhammer_malloc(size_t len)
+{
+       void *m;
+
+       m = calloc(len, sizeof(char));
+       if (m == NULL)
+               errx(1, "Failed to allocate %zd bytes", len);
+
+       return (m);
+}