From owner-svn-src-all@freebsd.org Tue Nov 17 19:56:48 2020 Return-Path: Delivered-To: svn-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 47D2246E002; Tue, 17 Nov 2020 19:56:48 +0000 (UTC) (envelope-from cem@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4CbGt81bBkz3NCV; Tue, 17 Nov 2020 19:56:48 +0000 (UTC) (envelope-from cem@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 295A925661; Tue, 17 Nov 2020 19:56:48 +0000 (UTC) (envelope-from cem@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id 0AHJumKh017644; Tue, 17 Nov 2020 19:56:48 GMT (envelope-from cem@FreeBSD.org) Received: (from cem@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id 0AHJumRE017643; Tue, 17 Nov 2020 19:56:48 GMT (envelope-from cem@FreeBSD.org) Message-Id: <202011171956.0AHJumRE017643@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: cem set sender to cem@FreeBSD.org using -f From: Conrad Meyer Date: Tue, 17 Nov 2020 19:56:48 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r367775 - head/sys/compat/linprocfs X-SVN-Group: head X-SVN-Commit-Author: cem X-SVN-Commit-Paths: head/sys/compat/linprocfs X-SVN-Commit-Revision: 367775 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 17 Nov 2020 19:56:48 -0000 Author: cem Date: Tue Nov 17 19:56:47 2020 New Revision: 367775 URL: https://svnweb.freebsd.org/changeset/base/367775 Log: linprocfs(5): Add rudimentary /proc//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 Modified: head/sys/compat/linprocfs/linprocfs.c Modified: head/sys/compat/linprocfs/linprocfs.c ============================================================================== --- head/sys/compat/linprocfs/linprocfs.c Tue Nov 17 19:53:59 2020 (r367774) +++ head/sys/compat/linprocfs/linprocfs.c Tue Nov 17 19:56:47 2020 (r367775) @@ -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//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,55 +503,112 @@ 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; + 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"); + } - if (strcmp(fstype, "autofs") == 0) { - /* - * FreeBSD uses eg "map -hosts", whereas Linux - * expects just "-hosts". - */ - if (strncmp(mntfrom, "map ", 4) == 0) - mntfrom += 4; - } + free(buf, M_TEMP); + free(flep, M_TEMP); + return (error); +} - 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"); +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; } -#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 - /* a real Linux mtab will also show NFS options */ - sbuf_printf(sb, " 0 0\n"); + + 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); @@ -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,