diff --git a/sbin/fsck/Makefile b/sbin/fsck/Makefile --- a/sbin/fsck/Makefile +++ b/sbin/fsck/Makefile @@ -4,6 +4,10 @@ PACKAGE=runtime PROG= fsck SRCS= fsck.c fsutil.c preen.c +SRCS+= getmntopts.c MAN= fsck.8 +MOUNT= ${SRCTOP}/sbin/mount +CFLAGS+= -I${MOUNT} +.PATH: ${MOUNT} .include diff --git a/sbin/fsck/fsck.c b/sbin/fsck/fsck.c --- a/sbin/fsck/fsck.c +++ b/sbin/fsck/fsck.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -206,7 +207,7 @@ _PATH_DEV, spec); spec = device; } - mntp = getmntpt(spec); + mntp = getmntpoint(spec); if (mntp != NULL) { spec = mntp->f_mntfromname; mntpt = mntp->f_mntonname; @@ -269,7 +270,7 @@ if (flags & DO_BACKGRD) { if (!strcmp(fs->fs_type, FSTAB_RO)) return (0); - if (getmntpt(fs->fs_spec) == NULL) + if (getmntpoint(fs->fs_spec) == NULL) return (0); if (checkfs(fs->fs_vfstype, fs->fs_spec, fs->fs_file, "-F", 0)) return (0); diff --git a/sbin/fsck/fsutil.h b/sbin/fsck/fsutil.h --- a/sbin/fsck/fsutil.h +++ b/sbin/fsck/fsutil.h @@ -39,7 +39,6 @@ const char *devcheck(const char *); const char *cdevname(void); void setcdevname(const char *, int); -struct statfs *getmntpt(const char *); void *emalloc(size_t); void *erealloc(void *, size_t); char *estrdup(const char *); diff --git a/sbin/fsck/fsutil.c b/sbin/fsck/fsutil.c --- a/sbin/fsck/fsutil.c +++ b/sbin/fsck/fsutil.c @@ -188,50 +188,6 @@ return (origname); } -/* - * Get the mount point information for name. - */ -struct statfs * -getmntpt(const char *name) -{ - struct stat devstat, mntdevstat; - char device[sizeof(_PATH_DEV) - 1 + MNAMELEN]; - char *dev_name; - struct statfs *mntbuf, *statfsp; - int i, mntsize, isdev; - - if (stat(name, &devstat) != 0) - return (NULL); - if (S_ISCHR(devstat.st_mode) || S_ISBLK(devstat.st_mode)) - isdev = 1; - else - isdev = 0; - mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); - for (i = 0; i < mntsize; i++) { - statfsp = &mntbuf[i]; - dev_name = statfsp->f_mntfromname; - if (*dev_name != '/') { - if (strlen(_PATH_DEV) + strlen(dev_name) + 1 > - sizeof(statfsp->f_mntfromname)) - continue; - strcpy(device, _PATH_DEV); - strcat(device, dev_name); - strcpy(statfsp->f_mntfromname, device); - } - if (isdev == 0) { - if (strcmp(name, statfsp->f_mntonname)) - continue; - return (statfsp); - } - if (stat(dev_name, &mntdevstat) == 0 && - mntdevstat.st_rdev == devstat.st_rdev) - return (statfsp); - } - statfsp = NULL; - return (statfsp); -} - - void * emalloc(size_t s) { diff --git a/sbin/fsck_ffs/main.c b/sbin/fsck_ffs/main.c --- a/sbin/fsck_ffs/main.c +++ b/sbin/fsck_ffs/main.c @@ -76,8 +76,6 @@ static intmax_t argtoimax(int flag, const char *req, const char *str, int base); static int checkfilesys(char *filesys); static int setup_bkgrdchk(struct statfs *mntp, int sbrdfailed, char **filesys); -static int chkdoreload(struct statfs *mntp); -static struct statfs *getmntpt(const char *); int main(int argc, char *argv[]) @@ -258,7 +256,7 @@ * if it is listed among the mounted file systems. Failing that * check to see if it is listed in /etc/fstab. */ - mntp = getmntpt(filesys); + mntp = getmntpoint(filesys); if (mntp != NULL) filesys = mntp->f_mntfromname; else @@ -311,7 +309,7 @@ (FS_UNCLEAN | FS_NEEDSFSCK)) == 0) { bufinit(); gjournal_check(filesys); - if (chkdoreload(mntp) == 0) + if (chkdoreload(mntp, pwarn) == 0) exit(0); exit(4); } else { @@ -357,7 +355,7 @@ sujrecovery = 1; if (suj_check(filesys) == 0) { printf("\n***** FILE SYSTEM MARKED CLEAN *****\n"); - if (chkdoreload(mntp) == 0) + if (chkdoreload(mntp, pwarn) == 0) exit(0); exit(4); } @@ -561,7 +559,7 @@ return (ERESTART); printf("\n***** PLEASE RERUN FSCK *****\n"); } - if (chkdoreload(mntp) != 0) { + if (chkdoreload(mntp, pwarn) != 0) { if (!fsmodified) return (0); if (!preen) @@ -715,92 +713,6 @@ return (1); } -static int -chkdoreload(struct statfs *mntp) -{ - struct iovec *iov; - int iovlen; - char errmsg[255]; - - if (mntp == NULL) - return (0); - - iov = NULL; - iovlen = 0; - errmsg[0] = '\0'; - /* - * We modified a mounted file system. Do a mount update on - * it unless it is read-write, so we can continue using it - * as safely as possible. - */ - if (mntp->f_flags & MNT_RDONLY) { - build_iovec(&iov, &iovlen, "fstype", "ffs", 4); - build_iovec(&iov, &iovlen, "from", mntp->f_mntfromname, - (size_t)-1); - build_iovec(&iov, &iovlen, "fspath", mntp->f_mntonname, - (size_t)-1); - build_iovec(&iov, &iovlen, "errmsg", errmsg, - sizeof(errmsg)); - build_iovec(&iov, &iovlen, "update", NULL, 0); - build_iovec(&iov, &iovlen, "reload", NULL, 0); - /* - * XX: We need the following line until we clean up - * nmount parsing of root mounts and NFS root mounts. - */ - build_iovec(&iov, &iovlen, "ro", NULL, 0); - if (nmount(iov, iovlen, mntp->f_flags) == 0) { - return (0); - } - pwarn("mount reload of '%s' failed: %s %s\n\n", - mntp->f_mntonname, strerror(errno), errmsg); - return (1); - } - return (0); -} - -/* - * Get the mount point information for name. - */ -static struct statfs * -getmntpt(const char *name) -{ - struct stat devstat, mntdevstat; - char device[sizeof(_PATH_DEV) - 1 + MNAMELEN]; - char *ddevname; - struct statfs *mntbuf, *statfsp; - int i, mntsize, isdev; - - if (stat(name, &devstat) != 0) - return (NULL); - if (S_ISCHR(devstat.st_mode) || S_ISBLK(devstat.st_mode)) - isdev = 1; - else - isdev = 0; - mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); - for (i = 0; i < mntsize; i++) { - statfsp = &mntbuf[i]; - ddevname = statfsp->f_mntfromname; - if (*ddevname != '/') { - if (strlen(_PATH_DEV) + strlen(ddevname) + 1 > - sizeof(statfsp->f_mntfromname)) - continue; - strcpy(device, _PATH_DEV); - strcat(device, ddevname); - strcpy(statfsp->f_mntfromname, device); - } - if (isdev == 0) { - if (strcmp(name, statfsp->f_mntonname)) - continue; - return (statfsp); - } - if (stat(ddevname, &mntdevstat) == 0 && - mntdevstat.st_rdev == devstat.st_rdev) - return (statfsp); - } - statfsp = NULL; - return (statfsp); -} - static void usage(void) { diff --git a/sbin/growfs/growfs.c b/sbin/growfs/growfs.c --- a/sbin/growfs/growfs.c +++ b/sbin/growfs/growfs.c @@ -118,7 +118,6 @@ static void updcsloc(time_t, int, int, unsigned int); static void frag_adjust(ufs2_daddr_t, int); static void updclst(int); -static void mount_reload(const struct statfs *stfs); static void cgckhash(struct cg *); /* @@ -1263,76 +1262,11 @@ return (1); } -/* - * Return mountpoint on which the device is currently mounted. - */ -static const struct statfs * -dev_to_statfs(const char *dev) -{ - struct stat devstat, mntdevstat; - struct statfs *mntbuf, *statfsp; - char device[MAXPATHLEN]; - char *mntdevname; - int i, mntsize; - - /* - * First check the mounted filesystems. - */ - if (stat(dev, &devstat) != 0) - return (NULL); - if (!S_ISCHR(devstat.st_mode) && !S_ISBLK(devstat.st_mode)) - return (NULL); - - mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); - for (i = 0; i < mntsize; i++) { - statfsp = &mntbuf[i]; - mntdevname = statfsp->f_mntfromname; - if (*mntdevname != '/') { - strcpy(device, _PATH_DEV); - strcat(device, mntdevname); - mntdevname = device; - } - if (stat(mntdevname, &mntdevstat) == 0 && - mntdevstat.st_rdev == devstat.st_rdev) - return (statfsp); - } - - return (NULL); -} - static const char * -mountpoint_to_dev(const char *mountpoint) -{ - struct statfs *mntbuf, *statfsp; - struct fstab *fs; - int i, mntsize; - - /* - * First check the mounted filesystems. - */ - mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); - for (i = 0; i < mntsize; i++) { - statfsp = &mntbuf[i]; - - if (strcmp(statfsp->f_mntonname, mountpoint) == 0) - return (statfsp->f_mntfromname); - } - - /* - * Check the fstab. - */ - fs = getfsfile(mountpoint); - if (fs != NULL) - return (fs->fs_spec); - - return (NULL); -} - -static const char * -getdev(const char *name) +getdev(const char *name, struct statfs *statfsp) { static char device[MAXPATHLEN]; - const char *cp, *dev; + const char *cp; if (is_dev(name)) return (name); @@ -1344,9 +1278,8 @@ return (device); } - dev = mountpoint_to_dev(name); - if (dev != NULL && is_dev(dev)) - return (dev); + if (statfsp != NULL) + return (statfsp->f_mntfromname); return (NULL); } @@ -1378,7 +1311,7 @@ DBG_FUNC("main") struct fs *fs; const char *device; - const struct statfs *statfsp; + struct statfs *statfsp; uint64_t size = 0; off_t mediasize; int error, j, fsi, fso, ch, ret, Nflag = 0, yflag = 0; @@ -1430,12 +1363,11 @@ /* * Now try to guess the device name. */ - device = getdev(*argv); + statfsp = getmntpoint(*argv); + device = getdev(*argv, statfsp); if (device == NULL) errx(1, "cannot find special device for %s", *argv); - statfsp = dev_to_statfs(device); - fsi = open(device, O_RDONLY); if (fsi < 0) err(1, "%s", device); @@ -1666,8 +1598,9 @@ error = close(fso); if (error != 0) err(1, "close"); - if (statfsp != NULL && (statfsp->f_flags & MNT_RDONLY) != 0) - mount_reload(statfsp); + if (statfsp != NULL && (statfsp->f_flags & MNT_RDONLY) != 0 && + chkdoreload(statfsp, warn) != 0) + exit(9); } DBG_CLOSE; @@ -1734,29 +1667,6 @@ return; } -static void -mount_reload(const struct statfs *stfs) -{ - char errmsg[255]; - struct iovec *iov; - int iovlen; - - iov = NULL; - iovlen = 0; - *errmsg = '\0'; - build_iovec(&iov, &iovlen, "fstype", __DECONST(char *, "ffs"), 4); - build_iovec(&iov, &iovlen, "fspath", __DECONST(char *, stfs->f_mntonname), (size_t)-1); - build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); - build_iovec(&iov, &iovlen, "update", NULL, 0); - build_iovec(&iov, &iovlen, "reload", NULL, 0); - - if (nmount(iov, iovlen, stfs->f_flags) < 0) { - errmsg[sizeof(errmsg) - 1] = '\0'; - err(9, "%s: cannot reload filesystem%s%s", stfs->f_mntonname, - *errmsg != '\0' ? ": " : "", errmsg); - } -} - /* * Calculate the check-hash of the cylinder group. */ diff --git a/sbin/mount/Makefile b/sbin/mount/Makefile --- a/sbin/mount/Makefile +++ b/sbin/mount/Makefile @@ -4,8 +4,15 @@ PACKAGE=runtime PROG= mount SRCS= mount.c mount_fs.c getmntopts.c vfslist.c -MAN= mount.8 -# We do NOT install the getmntopts.3 man page. +MAN= mntopts.3 mount.8 +MLINKS+= mntopts.3 getmntopts.3 +MLINKS+= mntopts.3 getmntpoint.3 +MLINKS+= mntopts.3 chkdoreload.3 +MLINKS+= mntopts.3 build_iovec.3 +MLINKS+= mntopts.3 build_iovec_argf.3 +MLINKS+= mntopts.3 free_iovec.3 +MLINKS+= mntopts.3 checkpath.3 +MLINKS+= mntopts.3 rmslashes.3 LIBADD= util xo diff --git a/sbin/mount/getmntopts.3 b/sbin/mount/getmntopts.3 deleted file mode 100644 --- a/sbin/mount/getmntopts.3 +++ /dev/null @@ -1,181 +0,0 @@ -.\" Copyright (c) 1994 -.\" The Regents of the University of California. All rights reserved. -.\" -.\" 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 University 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 REGENTS 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 REGENTS 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. -.\" -.\" @(#)getmntopts.3 8.3 (Berkeley) 3/30/95 -.\" $FreeBSD$ -.\" -.Dd February 17, 2008 -.Dt GETMNTOPTS 3 -.Os -.Sh NAME -.Nm getmntopts -.Nd scan mount options -.Sh SYNOPSIS -.Fd #include \&"mntopts.h" -.Ft void -.Fo getmntopts -.Fa "const char *options" "const struct mntopt *mopts" -.Fa "int *flagp" "int *altflagp" -.Fc -.Sh DESCRIPTION -The -.Fn getmntopts -function takes a comma separated option list and a list -of valid option names, and computes the bitmask -corresponding to the requested set of options. -.Pp -The string -.Fa options -is broken down into a sequence of comma separated tokens. -Each token is looked up in the table described by -.Fa mopts -and the bits in -the word referenced by either -.Fa flagp -or -.Fa altflagp -(depending on the -.Va m_altloc -field of the option's table entry) -are updated. -The flag words are not initialized by -.Fn getmntopts . -The table, -.Fa mopts , -has the following format: -.Bd -literal -struct mntopt { - char *m_option; /* option name */ - int m_inverse; /* is this a negative option, e.g., "dev" */ - int m_flag; /* bit to set, e.g., MNT_RDONLY */ - int m_altloc; /* non-zero to use altflagp rather than flagp */ -}; -.Ed -.Pp -The members of this structure are: -.Bl -tag -width m_inverse -.It Va m_option -the option name, -for example -.Dq Li suid . -.It Va m_inverse -tells -.Fn getmntopts -that the name has the inverse meaning of the -bit. -For example, -.Dq Li suid -is the string, whereas the -mount flag is -.Dv MNT_NOSUID . -In this case, the sense of the string and the flag -are inverted, so the -.Va m_inverse -flag should be set. -.It Va m_flag -the value of the bit to be set or cleared in -the flag word when the option is recognized. -The bit is set when the option is discovered, -but cleared if the option name was preceded -by the letters -.Dq Li no . -The -.Va m_inverse -flag causes these two operations to be reversed. -.It Va m_altloc -the bit should be set or cleared in -.Fa altflagp -rather than -.Fa flagp . -.El -.Pp -Each of the user visible -.Dv MNT_ -flags has a corresponding -.Dv MOPT_ -macro which defines an appropriate -.Vt "struct mntopt" -entry. -To simplify the program interface and ensure consistency across all -programs, a general purpose macro, -.Dv MOPT_STDOPTS , -is defined which -contains an entry for all the generic VFS options. -In addition, the macros -.Dv MOPT_FORCE -and -.Dv MOPT_UPDATE -exist to enable the -.Dv MNT_FORCE -and -.Dv MNT_UPDATE -flags to be set. -Finally, the table must be terminated by an entry with a -.Dv NULL -first element. -.Sh EXAMPLES -Most commands will use the standard option set. -Local file systems which support the -.Dv MNT_UPDATE -flag, would also have an -.Dv MOPT_UPDATE -entry. -This can be declared and used as follows: -.Bd -literal -#include "mntopts.h" - -struct mntopt mopts[] = { - MOPT_STDOPTS, - MOPT_UPDATE, - { NULL } -}; - - ... - mntflags = mntaltflags = 0; - ... - getmntopts(options, mopts, &mntflags, &mntaltflags); - ... -.Ed -.Sh DIAGNOSTICS -If the external integer variable -.Va getmnt_silent -is zero, then the -.Fn getmntopts -function displays an error message and exits if an -unrecognized option is encountered. -Otherwise unrecognized options are silently ignored. -By default -.Va getmnt_silent -is zero. -.Sh SEE ALSO -.Xr err 3 , -.Xr mount 8 -.Sh HISTORY -The -.Fn getmntopts -function appeared in -.Bx 4.4 . diff --git a/sbin/mount/getmntopts.c b/sbin/mount/getmntopts.c --- a/sbin/mount/getmntopts.c +++ b/sbin/mount/getmntopts.c @@ -44,6 +44,7 @@ #include #include +#include #include #include #include @@ -153,6 +154,98 @@ return (0); } +/* + * Get the mount point information for name. Name may be mount point name + * or device name (with or without /dev/ preprended). + */ +struct statfs * +getmntpoint(const char *name) +{ + struct stat devstat, mntdevstat; + char device[sizeof(_PATH_DEV) - 1 + MNAMELEN]; + char *ddevname; + struct statfs *mntbuf, *statfsp; + int i, mntsize, isdev; + + if (stat(name, &devstat) != 0) + return (NULL); + if (S_ISCHR(devstat.st_mode) || S_ISBLK(devstat.st_mode)) + isdev = 1; + else + isdev = 0; + mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); + for (i = 0; i < mntsize; i++) { + statfsp = &mntbuf[i]; + ddevname = statfsp->f_mntfromname; + if (*ddevname != '/') { + if (strlen(_PATH_DEV) + strlen(ddevname) + 1 > + sizeof(statfsp->f_mntfromname)) + continue; + strcpy(device, _PATH_DEV); + strcat(device, ddevname); + strcpy(statfsp->f_mntfromname, device); + } + if (isdev == 0) { + if (strcmp(name, statfsp->f_mntonname)) + continue; + return (statfsp); + } + if (stat(ddevname, &mntdevstat) == 0 && + mntdevstat.st_rdev == devstat.st_rdev) + return (statfsp); + } + return (NULL); +} + +/* + * If possible reload a mounted filesystem. + * When prtmsg != NULL print a warning if a reload is attempted, but fails. + * Return 0 on success, 1 on failure. + */ +int +chkdoreload(struct statfs *mntp, + void (*prtmsg)(const char *, ...) __printflike(1,2)) +{ + struct iovec *iov; + int iovlen, error; + char errmsg[255]; + + /* + * If the filesystem is not mounted it does not need to be reloaded. + * If it is mounted for writing, then it could not have been opened + * for writing by a utility, so does not need to be reloaded. + */ + if (mntp == NULL || (mntp->f_flags & MNT_RDONLY) == 0) + return (0); + + /* + * We modified a mounted file system. Do a mount update on + * it so we can continue using it as safely as possible. + */ + iov = NULL; + iovlen = 0; + errmsg[0] = '\0'; + build_iovec(&iov, &iovlen, "fstype", __DECONST(void *, "ffs"), 4); + build_iovec(&iov, &iovlen, "from", mntp->f_mntfromname, (size_t)-1); + build_iovec(&iov, &iovlen, "fspath", mntp->f_mntonname, (size_t)-1); + build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); + build_iovec(&iov, &iovlen, "update", NULL, 0); + build_iovec(&iov, &iovlen, "reload", NULL, 0); + /* + * XX: We need the following line until we clean up + * nmount parsing of root mounts and NFS root mounts. + */ + build_iovec(&iov, &iovlen, "ro", NULL, 0); + error = nmount(iov, iovlen, mntp->f_flags); + free_iovec(&iov, &iovlen); + if (error == 0) + return (0); + if (prtmsg != NULL) + prtmsg("mount reload of '%s' failed: %s %s\n\n", + mntp->f_mntonname, strerror(errno), errmsg); + return (1); +} + void build_iovec(struct iovec **iov, int *iovlen, const char *name, void *val, size_t len) @@ -207,7 +300,7 @@ { int i; - for (i = 0; i < *iovlen; i++) + for (i = 0; i < *iovlen; i += 2) free((*iov)[i].iov_base); free(*iov); } diff --git a/sbin/mount/mntopts.h b/sbin/mount/mntopts.h --- a/sbin/mount/mntopts.h +++ b/sbin/mount/mntopts.h @@ -104,6 +104,8 @@ void rmslashes(char *, char *); int checkpath(const char *, char resolved_path[]); int checkpath_allow_file(const char *, char resolved_path[]); +struct statfs *getmntpoint(const char *); +int chkdoreload(struct statfs *, void (*)(const char *, ...) __printflike(1,2)); extern int getmnt_silent; void build_iovec(struct iovec **iov, int *iovlen, const char *name, void *val, size_t len); void build_iovec_argf(struct iovec **iov, int *iovlen, const char *name, const char *fmt, ...); diff --git a/sbin/mount/mntopts.3 b/sbin/mount/mntopts.3 new file mode 100644 --- /dev/null +++ b/sbin/mount/mntopts.3 @@ -0,0 +1,381 @@ +.\" Copyright (c) 2023 Marshall Kirk McKusick +.\" Copyright (c) 1994 The Regents of the University of California. +.\" +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 AUTHORS 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. +.\" +.\" @(#)getmntopts.3 8.3 (Berkeley) 3/30/95 +.\" +.Dd January 19, 2023 +.Dt MNTOPTS 3 +.Os +.Sh NAME +.Nm getmntopts , +.Nm getmntpoint , +.Nm chkdoreload , +.Nm build_iovec , +.Nm build_iovec_argf , +.Nm free_iovec , +.Nm checkpath , +.Nm rmslashes +.Nd "mount point operations" +.Sh SYNOPSIS +.In mntopts.h +.Ft void +.Fo getmntopts +.Fa "const char *options" "const struct mntopt *mopts" +.Fa "int *flagp" "int *altflagp" +.Fc +.Ft struct statfs * +.Fn getmntpoint "const char *name" +.Ft int +.Fo chkdoreload +.Fa "struct statfs *mntp" +.Fa "void (*prtmsg)(const char *fmt, ...)" +.Fc +.Ft void +.Fo build_iovec +.Fa "struct iovec **iov" "int *iovlen" "const char *name" "void *val" +.Fa "size_t len" +.Fc +.Ft void +.Fo build_iovec_argf +.Fa "struct iovec **iov" "int *iovlen" "const char *name" +.Fa "const char *fmt" "..." +.Fc +.Ft void +.Fn free_iovec "struct iovec **iov" "int *iovlen" +.Ft int +.Fn checkpath "const char *path" "char *resolved" +.Ft void +.Fn rmslashes "char *rrpin" "char *rrpout" +.Sh DESCRIPTION +The +.Nm mntopts +functions support operations associated with a mount point. +For historic reasons are in a file in the sources for the +.Xr mount 8 +program. +Thus, to access them the following lines need to be added to the +.Nm Makefile +of the program wanting to use them: +.Bd -literal +SRCS+= getmntopts.c +MOUNT= ${SRCTOP}/sbin/mount +CFLAGS+= -I${MOUNT} +\&.PATH: ${MOUNT} +.Ed +.Pp +The +.Fn getmntopts +function takes a comma separated option list and a list +of valid option names, and computes the bitmask +corresponding to the requested set of options. +.Pp +The string +.Fa options +is broken down into a sequence of comma separated tokens. +Each token is looked up in the table described by +.Fa mopts +and the bits in +the word referenced by either +.Fa flagp +or +.Fa altflagp +(depending on the +.Va m_altloc +field of the option's table entry) +are updated. +The flag words are not initialized by +.Fn getmntopts . +The table, +.Fa mopts , +has the following format: +.Bd -literal +struct mntopt { + char *m_option; /* option name */ + int m_inverse; /* is this a negative option, e.g., "dev" */ + int m_flag; /* bit to set, e.g., MNT_RDONLY */ + int m_altloc; /* non-zero to use altflagp rather than flagp */ +}; +.Ed +.Pp +The members of this structure are: +.Bl -tag -width m_inverse +.It Va m_option +the option name, +for example +.Dq Li suid . +.It Va m_inverse +tells +.Fn getmntopts +that the name has the inverse meaning of the +bit. +For example, +.Dq Li suid +is the string, whereas the +mount flag is +.Dv MNT_NOSUID . +In this case, the sense of the string and the flag +are inverted, so the +.Va m_inverse +flag should be set. +.It Va m_flag +the value of the bit to be set or cleared in +the flag word when the option is recognized. +The bit is set when the option is discovered, +but cleared if the option name was preceded +by the letters +.Dq Li no . +The +.Va m_inverse +flag causes these two operations to be reversed. +.It Va m_altloc +the bit should be set or cleared in +.Fa altflagp +rather than +.Fa flagp . +.El +.Pp +Each of the user visible +.Dv MNT_ +flags has a corresponding +.Dv MOPT_ +macro which defines an appropriate +.Vt "struct mntopt" +entry. +To simplify the program interface and ensure consistency across all +programs, a general purpose macro, +.Dv MOPT_STDOPTS , +is defined which +contains an entry for all the generic VFS options. +In addition, the macros +.Dv MOPT_FORCE +and +.Dv MOPT_UPDATE +exist to enable the +.Dv MNT_FORCE +and +.Dv MNT_UPDATE +flags to be set. +Finally, the table must be terminated by an entry with a +.Dv NULL +first element. +.Pp +The +.Fn getmntpoint +function takes the pathname of a possible mount point +or of a device (with or without +.Pa /dev/ +prepended to it). +If the pathname is a directory or a file, +.Fn getmntpoint +checks to see if the mount point currently has a filesystem +mounted on it. +If the pathname is a device, +.Fn getmntpoint +checks to see if it is currently mounted. +If there is an associated mount, a pointer to a +.Vt "struct statfs" +is returned. +The returned result is stored in a static buffer that is over-written +each time the +.Fn getmntpoint +function or the +.Xr getmntinfo 3 +library routine is called. +If no mount is found, NULL is returned. +.Pp +The +.Fn chkdoreload +function takes a pointer to a +.Vt "struct statfs" . +If the filesystem associated with the mount point is mounted read-only, +.Fn chkdoreload +requests the filesystem to reload all of its metadata from its backing store. +The second parameter is the function to call to print an error message +if the reload fails. +If no error message is desired, a +.Dv NULL +can be passed as the second argument. +The +.Fn chkdoreload +function returns zero on success or non-zero on failure. +.Pp +The +.Fn build_iovec +function adds a parameter to a list of parameters to be passed to the +.Xr nmount 2 +system call. +The parameter list is built up in +.Va iov +and its length is kept in +.Va iovlen . +Before the first call to +.Fn build_iovec , +.Va iov +should be set to +.Dv NULL +and +.Va iovlen +should be set to 0. +The parameter name is passed in +.Va name . +The value of the parameter name is pointed to by +.Va val . +The size of the value is passed in +.Va len . +If the value is a string, a +.Va len +of -1 is passed to indicate that the length should be determined using +.Xr strlen 3 . +If the parameter has no value, +.Va name +should be +.Dv NULL +and +.Va len +should be 0. +.Pp +The +.Fn build_iovec_argf +function adds a formatted parameter to a list of parameters to be passed +to the +.Xr nmount 2 +system call. +The parameter list is built up in +.Va iov +and its length is kept in +.Va iovlen . +Before the first call to +.Fn build_iovec_argf , +.Va iov +should be set to +.Dv NULL +and +.Va iovlen +should be set to 0. +The parameter name is passed in +.Va name . +The value of the parameter name is described by a format string pointed to by +.Va fmt . +If the parameter has no value, +.Va name +should be +.Dv NULL . +.Pp +The +.Fn free_iovec +function frees the memory in the +.Va iov +vector of the length specified in +.Va iovlen +that was previously allocated by the +.Fn build_iovec +and / or +.Fn build_iovec_argf +functions. +The +.Va iov +is set to +.Dv NULL +and the +.Va iovlen +is set to 0 to indicate that the space has been freed. +.Pp +The +.Fn checkpath +function uses +.Xr realpath 3 +to verify that its +.Va path +argument is valid and references a directory. +The +.Fn checkpath +function returns zero on success or non-zero on failure. +.Pp +The +.Fn rmslashes +function removes all double slashes and trailing slashes from its +.Va rrpin +pathname parameter and returns the resulting pathname in its +.Va rrpout +parameter. +.Sh EXAMPLES +Most commands will use the standard option set. +Local file systems which support the +.Dv MNT_UPDATE +flag, would also have an +.Dv MOPT_UPDATE +entry. +This can be declared and used as follows: +.Bd -literal +#include "mntopts.h" + +struct mntopt mopts[] = { + MOPT_STDOPTS, + MOPT_UPDATE, + { NULL } +}; + + ... + mntflags = mntaltflags = 0; + ... + getmntopts(options, mopts, &mntflags, &mntaltflags); + ... +.Ed +.Sh DIAGNOSTICS +If the external integer variable +.Va getmnt_silent +is zero, then the +.Fn getmntopts +function displays an error message and exits if an +unrecognized option is encountered. +Otherwise unrecognized options are silently ignored. +By default +.Va getmnt_silent +is zero. +.Sh SEE ALSO +.Xr err 3 , +.Xr mount 8 , +.Xr nmount 8 +.Sh HISTORY +The +.Fn getmntopts +function appeared in +.Bx 4.4 . +The +.Fn build_iovec , +.Fn build_iovec_argf , +.Fn free_iovec , +.Fn checkpath , +and +.Fn rmslashes +functions were added with +.Xr nmount 8 +in +.Fx 5.0 . +The +.Fn getmntpoint +and +.Fn chkdoreload +functions were added in +.Fx 14.0 . diff --git a/sbin/mount/mount.c b/sbin/mount/mount.c --- a/sbin/mount/mount.c +++ b/sbin/mount/mount.c @@ -85,7 +85,6 @@ }; char *catopt(char *, const char *); -struct statfs *getmntpt(const char *); int hasopt(const char *, const char *); int ismounted(struct fstab *, struct statfs *, int); int isremountable(const char *); @@ -369,7 +368,7 @@ if (init_flags & MNT_UPDATE) { mntfromname = NULL; have_fstab = 0; - if ((mntbuf = getmntpt(*argv)) == NULL) + if ((mntbuf = getmntpoint(*argv)) == NULL) xo_errx(1, "not currently mounted %s", *argv); /* * Only get the mntflags from fstab if both mntpoint @@ -719,21 +718,6 @@ xo_emit("{D:)}\n"); } -struct statfs * -getmntpt(const char *name) -{ - struct statfs *mntbuf; - int i, mntsize; - - mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); - for (i = mntsize - 1; i >= 0; i--) { - if (strcmp(mntbuf[i].f_mntfromname, name) == 0 || - strcmp(mntbuf[i].f_mntonname, name) == 0) - return (&mntbuf[i]); - } - return (NULL); -} - char * catopt(char *s0, const char *s1) { diff --git a/sbin/tunefs/tunefs.c b/sbin/tunefs/tunefs.c --- a/sbin/tunefs/tunefs.c +++ b/sbin/tunefs/tunefs.c @@ -91,18 +91,14 @@ { const char *avalue, *jvalue, *Jvalue, *Lvalue, *lvalue, *Nvalue, *nvalue; const char *tvalue; - const char *special, *on; + const char *special; const char *name; - int active; + char *diskname; int Aflag, aflag, eflag, evalue, fflag, fvalue, jflag, Jflag, kflag; int kvalue, Lflag, lflag, mflag, mvalue, Nflag, nflag, oflag, ovalue; int pflag, sflag, svalue, Svalue, tflag; int ch, found_arg, i; - int iovlen = 0; const char *chg[2]; - struct statfs stfs; - struct iovec *iov = NULL; - char errmsg[255] = {0}; if (argc < 3) usage(); @@ -110,7 +106,6 @@ lflag = mflag = Nflag = nflag = oflag = pflag = sflag = tflag = 0; avalue = jvalue = Jvalue = Lvalue = lvalue = Nvalue = nvalue = NULL; evalue = fvalue = mvalue = ovalue = svalue = Svalue = 0; - active = 0; found_arg = 0; /* At least one arg is required. */ while ((ch = getopt(argc, argv, "Aa:e:f:j:J:k:L:l:m:N:n:o:ps:S:t:")) != -1) @@ -309,7 +304,7 @@ if (found_arg == 0 || argc != 1) usage(); - on = special = argv[0]; + special = argv[0]; if (ufs_disk_fillout(&disk, special) == -1) goto err; /* @@ -319,13 +314,6 @@ (sblock.fs_flags & (FS_UNCLEAN | FS_NEEDSFSCK)) != 0) && (found_arg > 1 || !pflag)) errx(1, "%s is not clean - run fsck.\n", special); - if (disk.d_name != special) { - if (statfs(special, &stfs) != 0) - warn("Can't stat %s", special); - if (strcmp(special, stfs.f_mntonname) == 0) - active = 1; - } - if (pflag) { printfs(); exit(0); @@ -570,20 +558,9 @@ if (sbwrite(&disk, Aflag) == -1) goto err; + diskname = strdup(disk.d_name); ufs_disk_close(&disk); - if (active) { - build_iovec_argf(&iov, &iovlen, "fstype", "ufs"); - build_iovec_argf(&iov, &iovlen, "fspath", "%s", on); - build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); - if (nmount(iov, iovlen, - stfs.f_flags | MNT_UPDATE | MNT_RELOAD) < 0) { - if (errmsg[0]) - err(9, "%s: reload: %s", special, errmsg); - else - err(9, "%s: reload", special); - } - warnx("file system reloaded"); - } + chkdoreload(getmntpoint(diskname), warnx); exit(0); err: if (disk.d_error != NULL)