linprocfs(5): Add rudimentary /proc/<pid>/mountinfo
This is used by some Linux programs using filehandles (r367773) to locate the mountpoint for a given fsid. Differential Revision: https://reviews.freebsd.org/D27136
This commit is contained in:
parent
77eb984147
commit
b1976ea14c
@ -403,24 +403,85 @@ linprocfs_docpuinfo(PFS_FILL_ARGS)
|
||||
}
|
||||
#endif /* __i386__ || __amd64__ */
|
||||
|
||||
static const char *path_slash_sys = "/sys";
|
||||
static const char *fstype_sysfs = "sysfs";
|
||||
|
||||
static int
|
||||
_mtab_helper(const struct pfs_node *pn, const struct statfs *sp,
|
||||
const char **mntfrom, const char **mntto, const char **fstype)
|
||||
{
|
||||
/* determine device name */
|
||||
*mntfrom = sp->f_mntfromname;
|
||||
|
||||
/* determine mount point */
|
||||
*mntto = sp->f_mntonname;
|
||||
|
||||
/* determine fs type */
|
||||
*fstype = sp->f_fstypename;
|
||||
if (strcmp(*fstype, pn->pn_info->pi_name) == 0)
|
||||
*mntfrom = *fstype = "proc";
|
||||
else if (strcmp(*fstype, "procfs") == 0)
|
||||
return (ECANCELED);
|
||||
|
||||
if (strcmp(*fstype, "autofs") == 0) {
|
||||
/*
|
||||
* FreeBSD uses eg "map -hosts", whereas Linux
|
||||
* expects just "-hosts".
|
||||
*/
|
||||
if (strncmp(*mntfrom, "map ", 4) == 0)
|
||||
*mntfrom += 4;
|
||||
}
|
||||
|
||||
if (strcmp(*fstype, "linsysfs") == 0) {
|
||||
*mntfrom = path_slash_sys;
|
||||
*fstype = fstype_sysfs;
|
||||
} else {
|
||||
/* For Linux msdosfs is called vfat */
|
||||
if (strcmp(*fstype, "msdosfs") == 0)
|
||||
*fstype = "vfat";
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
_sbuf_mntoptions_helper(struct sbuf *sb, uint64_t f_flags)
|
||||
{
|
||||
sbuf_cat(sb, (f_flags & MNT_RDONLY) ? "ro" : "rw");
|
||||
#define ADD_OPTION(opt, name) \
|
||||
if (f_flags & (opt)) sbuf_cat(sb, "," name);
|
||||
ADD_OPTION(MNT_SYNCHRONOUS, "sync");
|
||||
ADD_OPTION(MNT_NOEXEC, "noexec");
|
||||
ADD_OPTION(MNT_NOSUID, "nosuid");
|
||||
ADD_OPTION(MNT_UNION, "union");
|
||||
ADD_OPTION(MNT_ASYNC, "async");
|
||||
ADD_OPTION(MNT_SUIDDIR, "suiddir");
|
||||
ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow");
|
||||
ADD_OPTION(MNT_NOATIME, "noatime");
|
||||
#undef ADD_OPTION
|
||||
}
|
||||
|
||||
/*
|
||||
* Filler function for proc/mtab
|
||||
* Filler function for proc/mtab and proc/<pid>/mounts.
|
||||
*
|
||||
* This file doesn't exist in Linux' procfs, but is included here so
|
||||
* /proc/mtab doesn't exist in Linux' procfs, but is included here so
|
||||
* users can symlink /compat/linux/etc/mtab to /proc/mtab
|
||||
*/
|
||||
static int
|
||||
linprocfs_domtab(PFS_FILL_ARGS)
|
||||
{
|
||||
struct nameidata nd;
|
||||
const char *lep;
|
||||
char *dlep, *flep, *mntto, *mntfrom, *fstype;
|
||||
const char *lep, *mntto, *mntfrom, *fstype;
|
||||
char *dlep, *flep;
|
||||
size_t lep_len;
|
||||
int error;
|
||||
struct statfs *buf, *sp;
|
||||
size_t count;
|
||||
|
||||
/* resolve symlinks etc. in the emulation tree prefix */
|
||||
/*
|
||||
* Ideally, this would use the current chroot rather than some
|
||||
* hardcoded path.
|
||||
*/
|
||||
NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
|
||||
flep = NULL;
|
||||
error = namei(&nd);
|
||||
@ -442,51 +503,18 @@ linprocfs_domtab(PFS_FILL_ARGS)
|
||||
}
|
||||
|
||||
for (sp = buf; count > 0; sp++, count--) {
|
||||
/* determine device name */
|
||||
mntfrom = sp->f_mntfromname;
|
||||
error = _mtab_helper(pn, sp, &mntfrom, &mntto, &fstype);
|
||||
if (error != 0) {
|
||||
MPASS(error == ECANCELED);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* determine mount point */
|
||||
mntto = sp->f_mntonname;
|
||||
if (strncmp(mntto, lep, lep_len) == 0 && mntto[lep_len] == '/')
|
||||
mntto += lep_len;
|
||||
|
||||
/* determine fs type */
|
||||
fstype = sp->f_fstypename;
|
||||
if (strcmp(fstype, pn->pn_info->pi_name) == 0)
|
||||
mntfrom = fstype = "proc";
|
||||
else if (strcmp(fstype, "procfs") == 0)
|
||||
continue;
|
||||
|
||||
if (strcmp(fstype, "autofs") == 0) {
|
||||
/*
|
||||
* FreeBSD uses eg "map -hosts", whereas Linux
|
||||
* expects just "-hosts".
|
||||
*/
|
||||
if (strncmp(mntfrom, "map ", 4) == 0)
|
||||
mntfrom += 4;
|
||||
}
|
||||
|
||||
if (strcmp(fstype, "linsysfs") == 0) {
|
||||
sbuf_printf(sb, "/sys %s sysfs %s", mntto,
|
||||
sp->f_flags & MNT_RDONLY ? "ro" : "rw");
|
||||
} else {
|
||||
/* For Linux msdosfs is called vfat */
|
||||
if (strcmp(fstype, "msdosfs") == 0)
|
||||
fstype = "vfat";
|
||||
sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
|
||||
sp->f_flags & MNT_RDONLY ? "ro" : "rw");
|
||||
}
|
||||
#define ADD_OPTION(opt, name) \
|
||||
if (sp->f_flags & (opt)) sbuf_printf(sb, "," name);
|
||||
ADD_OPTION(MNT_SYNCHRONOUS, "sync");
|
||||
ADD_OPTION(MNT_NOEXEC, "noexec");
|
||||
ADD_OPTION(MNT_NOSUID, "nosuid");
|
||||
ADD_OPTION(MNT_UNION, "union");
|
||||
ADD_OPTION(MNT_ASYNC, "async");
|
||||
ADD_OPTION(MNT_SUIDDIR, "suiddir");
|
||||
ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow");
|
||||
ADD_OPTION(MNT_NOATIME, "noatime");
|
||||
#undef ADD_OPTION
|
||||
sbuf_printf(sb, "%s %s %s ", mntfrom, mntto, fstype);
|
||||
_sbuf_mntoptions_helper(sb, sp->f_flags);
|
||||
/* a real Linux mtab will also show NFS options */
|
||||
sbuf_printf(sb, " 0 0\n");
|
||||
}
|
||||
@ -496,6 +524,96 @@ linprocfs_domtab(PFS_FILL_ARGS)
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
linprocfs_doprocmountinfo(PFS_FILL_ARGS)
|
||||
{
|
||||
struct nameidata nd;
|
||||
const char *mntfrom, *mntto, *fstype;
|
||||
const char *lep;
|
||||
char *dlep, *flep;
|
||||
struct statfs *buf, *sp;
|
||||
size_t count, lep_len;
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Ideally, this would use the current chroot rather than some
|
||||
* hardcoded path.
|
||||
*/
|
||||
NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
|
||||
flep = NULL;
|
||||
error = namei(&nd);
|
||||
lep = linux_emul_path;
|
||||
if (error == 0) {
|
||||
if (vn_fullpath(nd.ni_vp, &dlep, &flep) == 0)
|
||||
lep = dlep;
|
||||
vrele(nd.ni_vp);
|
||||
}
|
||||
lep_len = strlen(lep);
|
||||
|
||||
buf = NULL;
|
||||
error = kern_getfsstat(td, &buf, SIZE_T_MAX, &count,
|
||||
UIO_SYSSPACE, MNT_WAIT);
|
||||
if (error != 0)
|
||||
goto out;
|
||||
|
||||
for (sp = buf; count > 0; sp++, count--) {
|
||||
error = _mtab_helper(pn, sp, &mntfrom, &mntto, &fstype);
|
||||
if (error != 0) {
|
||||
MPASS(error == ECANCELED);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(mntto, lep, lep_len) == 0 && mntto[lep_len] == '/')
|
||||
mntto += lep_len;
|
||||
#if 0
|
||||
/*
|
||||
* If the prefix is a chroot, and this mountpoint is not under
|
||||
* the prefix, we should skip it. Leave it for now for
|
||||
* consistency with procmtab above.
|
||||
*/
|
||||
else
|
||||
continue;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* (1) mount id
|
||||
*
|
||||
* (2) parent mount id -- we don't have this cheaply, so
|
||||
* provide a dummy value
|
||||
*
|
||||
* (3) major:minor -- ditto
|
||||
*
|
||||
* (4) root filesystem mount -- probably a namespaces thing
|
||||
*
|
||||
* (5) mountto path
|
||||
*/
|
||||
sbuf_printf(sb, "%u 0 0:0 / %s ",
|
||||
sp->f_fsid.val[0] ^ sp->f_fsid.val[1], mntto);
|
||||
/* (6) mount options */
|
||||
_sbuf_mntoptions_helper(sb, sp->f_flags);
|
||||
/*
|
||||
* (7) zero or more optional fields -- again, namespace related
|
||||
*
|
||||
* (8) End of variable length fields separator ("-")
|
||||
*
|
||||
* (9) fstype
|
||||
*
|
||||
* (10) mount from
|
||||
*
|
||||
* (11) "superblock" options -- like (6), but different
|
||||
* semantics in Linux
|
||||
*/
|
||||
sbuf_printf(sb, " - %s %s %s\n", fstype, mntfrom,
|
||||
(sp->f_flags & MNT_RDONLY) ? "ro" : "rw");
|
||||
}
|
||||
|
||||
error = 0;
|
||||
out:
|
||||
free(buf, M_TEMP);
|
||||
free(flep, M_TEMP);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Filler function for proc/partitions
|
||||
*/
|
||||
@ -1889,6 +2007,8 @@ linprocfs_init(PFS_INIT_ARGS)
|
||||
NULL, NULL, NULL, PFS_RD | PFS_AUTODRAIN);
|
||||
pfs_create_file(dir, "mem", &linprocfs_doprocmem,
|
||||
procfs_attr_rw, &procfs_candebug, NULL, PFS_RDWR | PFS_RAW);
|
||||
pfs_create_file(dir, "mountinfo", &linprocfs_doprocmountinfo,
|
||||
NULL, NULL, NULL, PFS_RD);
|
||||
pfs_create_file(dir, "mounts", &linprocfs_domtab,
|
||||
NULL, NULL, NULL, PFS_RD);
|
||||
pfs_create_link(dir, "root", &linprocfs_doprocroot,
|
||||
|
Loading…
x
Reference in New Issue
Block a user