autofs-5.1.9 - add function table_lookup_ino()

From: Ian Kent <raven@themaw.net>

Add function table_lookup_ino() to try and locate a mount for a given
device, open a file handle for it, and return it's path in the provided
buffer.

Signed-off-by: Ian Kent <raven@themaw.net>
---
 CHANGELOG        |    1 +
 include/mounts.h |    1 +
 lib/mounts.c     |   78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 80 insertions(+)

diff --git a/CHANGELOG b/CHANGELOG
index 8b87d4306..f9b6322ae 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -78,6 +78,7 @@
 - fix direct mount trigger umount failure case.
 - refactor do_umount_autofs_direct().
 - fix stale direct mount trigger not umounted on expire.
+- add function table_lookup_ino().
 
 02/11/2023 autofs-5.1.9
 - fix kernel mount status notification.
diff --git a/include/mounts.h b/include/mounts.h
index 08b3ff424..39ca99965 100644
--- a/include/mounts.h
+++ b/include/mounts.h
@@ -175,6 +175,7 @@ void mnts_remove_amdmounts(struct autofs_point *ap);
 struct mnt_list *mnts_add_mount(struct autofs_point *ap, const char *name, unsigned int flags);
 void mnts_remove_mount(const char *mp, unsigned int flags);
 struct mnt_list *get_mnt_list(const char *path, int include);
+char *table_lookup_ino(struct autofs_point *ap, dev_t dev, ino_t ino, char *buf, size_t len, int *fd);
 unsigned int mnts_has_mounted_mounts(struct autofs_point *ap);
 int tree_traverse_inorder(struct tree_node *n, tree_work_fn_t work, void *ptr);
 void tree_free(struct tree_node *root);
diff --git a/lib/mounts.c b/lib/mounts.c
index 009e11447..b8c5e1a50 100644
--- a/lib/mounts.c
+++ b/lib/mounts.c
@@ -2335,6 +2335,84 @@ void free_mnt_list(struct mnt_list *list)
 	}
 }
 
+char *table_lookup_ino(struct autofs_point *ap,
+		       dev_t dev, ino_t ino,
+		       char *buf, size_t len, int *fd)
+{
+	struct ioctl_ops *ops;
+	struct mntent *mnt;
+	struct mntent mnt_wrk;
+	char tmp[PATH_MAX * 3];
+	char *path = NULL;
+	FILE *tab;
+	int ret = 0;
+
+	ops = get_ioctl_ops();
+	if (!ops) {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	tab = open_fopen_r(_PROC_MOUNTS);
+	if (!tab) {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	while ((mnt = local_getmntent_r(tab, &mnt_wrk, tmp, PATH_MAX * 3))) {
+		unsigned int type;
+		int ioctlfd;
+		dev_t devid;
+
+		if (strcmp(mnt->mnt_type, "autofs"))
+			continue;
+
+		type = t_direct;
+		if (strstr(mnt->mnt_opts, "indirect"))
+			type = t_indirect;
+		else if (strstr(mnt->mnt_opts, "offset"))
+			type = t_offset;
+
+		ret = ops->mount_device(ap->logopt, mnt->mnt_dir, type, &devid);
+		if (ret == -1 || ret == 0)
+			continue;
+
+		/* Our <device, inode> should be unique so there can only
+		 * be one.
+		 */
+		ioctlfd = open_ioctlfd(ap, mnt->mnt_dir, devid);
+		/* errno will be set on fail */
+		if (ioctlfd == -1)
+			break;
+		if (fd > 0) {
+			struct stat st;
+
+			if (fstat(ioctlfd, &st) == -1) {
+				ops->close(ap->logopt, ioctlfd);
+				break;
+			}
+
+			if (strlen(mnt->mnt_dir) >= len) {
+				ops->close(ap->logopt, ioctlfd);
+				errno = ENAMETOOLONG;
+				break;
+			}
+
+			if (st.st_dev == dev && st.st_ino == ino) {
+				strcpy(buf, mnt->mnt_dir);
+				path = buf;
+				*fd = ioctlfd;
+				break;
+			}
+			ops->close(ap->logopt, ioctlfd);
+			break;
+		}
+	}
+	fclose(tab);
+
+	return path;
+}
+
 static int table_is_mounted(const char *mp, unsigned int type)
 {
 	struct mntent *mnt;
