+ talloc_free(path);
+ return dev->mount_path;
+}
+
+static bool check_existing_mount(struct discover_device *dev)
+{
+ struct stat devstat, mntstat;
+ const char *device_path;
+ struct mntent *mnt;
+ FILE *fp;
+ int rc;
+
+ device_path = get_device_path(dev);
+
+ rc = stat(device_path, &devstat);
+ if (rc) {
+ pb_debug("%s: stat failed: %s\n", __func__, strerror(errno));
+ return false;
+ }
+
+ if (!S_ISBLK(devstat.st_mode)) {
+ pb_debug("%s: %s isn't a block device?\n", __func__,
+ dev->device_path);
+ return false;
+ }
+
+ fp = fopen("/proc/self/mounts", "r");
+
+ for (;;) {
+ mnt = getmntent(fp);
+ if (!mnt)
+ break;
+
+ if (!mnt->mnt_fsname || mnt->mnt_fsname[0] != '/')
+ continue;
+
+ rc = stat(mnt->mnt_fsname, &mntstat);
+ if (rc)
+ continue;
+
+ if (!S_ISBLK(mntstat.st_mode))
+ continue;
+
+ if (mntstat.st_rdev == devstat.st_rdev) {
+ dev->mount_path = talloc_strdup(dev, mnt->mnt_dir);
+ dev->root_path = check_subvols(dev);
+ dev->mounted_rw = !!hasmntopt(mnt, "rw");
+ dev->mounted = true;
+ dev->unmount = false;
+
+ pb_debug("%s: %s is already mounted (r%c) at %s\n",
+ __func__, dev->device_path,
+ dev->mounted_rw ? 'w' : 'o',
+ mnt->mnt_dir);
+ break;
+ }
+ }
+
+ fclose(fp);
+
+ return mnt != NULL;
+}
+
+/*
+ * Attempt to mount a filesystem safely, while handling certain filesytem-
+ * specific options
+ */
+static int try_mount(const char *device_path, const char *mount_path,
+ const char *fstype, unsigned long flags,
+ bool have_snapshot)
+{
+ const char *fs, *safe_opts;
+ int rc;
+
+ /* Mount ext3 as ext4 instead so 'norecovery' can be used */
+ if (strncmp(fstype, "ext3", strlen("ext3")) == 0) {
+ pb_debug("Mounting ext3 filesystem as ext4\n");
+ fs = "ext4";
+ } else
+ fs = fstype;
+
+ if (strncmp(fs, "xfs", strlen("xfs")) == 0 ||
+ strncmp(fs, "ext4", strlen("ext4")) == 0)
+ safe_opts = "norecovery";
+ else
+ safe_opts = NULL;
+
+ errno = 0;
+ /* If no snapshot is available don't attempt recovery */
+ if (!have_snapshot)
+ return mount(device_path, mount_path, fs, flags, safe_opts);
+
+ rc = mount(device_path, mount_path, fs, flags, NULL);
+
+ if (!rc)
+ return rc;
+
+ /* Mounting failed; some filesystems will fail to mount if a recovery
+ * journal exists (eg. cross-endian XFS), so try again with norecovery
+ * where that option is available.
+ * If mounting read-write just return the error as norecovery is not a
+ * valid option */
+ if ((flags & MS_RDONLY) != MS_RDONLY || !safe_opts)
+ return rc;
+
+ errno = 0;
+ return mount(device_path, mount_path, fs, flags, safe_opts);
+}
+
+static int mount_device(struct discover_device *dev)
+{
+ const char *fstype, *device_path;
+ int rc;
+
+ if (!dev->device_path)
+ return -1;
+
+ if (dev->mounted)