xref: /freebsd-src/sys/contrib/openzfs/lib/libspl/os/freebsd/mnttab.c (revision be181ee2a28aa2b4b0e76684bce9f673ef668874)
1eda14cbcSMatt Macy /*
2eda14cbcSMatt Macy  * Copyright (c) 2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3eda14cbcSMatt Macy  * All rights reserved.
4eda14cbcSMatt Macy  *
5eda14cbcSMatt Macy  * Redistribution and use in source and binary forms, with or without
6eda14cbcSMatt Macy  * modification, are permitted provided that the following conditions
7eda14cbcSMatt Macy  * are met:
8eda14cbcSMatt Macy  * 1. Redistributions of source code must retain the above copyright
9eda14cbcSMatt Macy  *    notice, this list of conditions and the following disclaimer.
10eda14cbcSMatt Macy  * 2. Redistributions in binary form must reproduce the above copyright
11eda14cbcSMatt Macy  *    notice, this list of conditions and the following disclaimer in the
12eda14cbcSMatt Macy  *    documentation and/or other materials provided with the distribution.
13eda14cbcSMatt Macy  *
14eda14cbcSMatt Macy  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15eda14cbcSMatt Macy  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16eda14cbcSMatt Macy  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17eda14cbcSMatt Macy  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18eda14cbcSMatt Macy  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19eda14cbcSMatt Macy  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20eda14cbcSMatt Macy  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21eda14cbcSMatt Macy  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22eda14cbcSMatt Macy  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23eda14cbcSMatt Macy  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24eda14cbcSMatt Macy  * SUCH DAMAGE.
25eda14cbcSMatt Macy  */
26eda14cbcSMatt Macy 
27eda14cbcSMatt Macy /*
28eda14cbcSMatt Macy  * This file implements Solaris compatible getmntany() and hasmntopt()
29eda14cbcSMatt Macy  * functions.
30eda14cbcSMatt Macy  */
31eda14cbcSMatt Macy 
32eda14cbcSMatt Macy #include <sys/cdefs.h>
33eda14cbcSMatt Macy __FBSDID("$FreeBSD$");
34eda14cbcSMatt Macy 
35eda14cbcSMatt Macy #include <sys/param.h>
36eda14cbcSMatt Macy #include <sys/mount.h>
37eda14cbcSMatt Macy #include <sys/mntent.h>
38eda14cbcSMatt Macy #include <sys/mnttab.h>
39eda14cbcSMatt Macy 
40eda14cbcSMatt Macy #include <ctype.h>
41eda14cbcSMatt Macy #include <errno.h>
42e3aa18adSMartin Matuska #include <pthread.h>
43eda14cbcSMatt Macy #include <stdio.h>
44eda14cbcSMatt Macy #include <stdlib.h>
45eda14cbcSMatt Macy #include <string.h>
46eda14cbcSMatt Macy 
47eda14cbcSMatt Macy static char *
48eda14cbcSMatt Macy mntopt(char **p)
49eda14cbcSMatt Macy {
50eda14cbcSMatt Macy 	char *cp = *p;
51eda14cbcSMatt Macy 	char *retstr;
52eda14cbcSMatt Macy 
53eda14cbcSMatt Macy 	while (*cp && isspace(*cp))
54eda14cbcSMatt Macy 		cp++;
55eda14cbcSMatt Macy 
56eda14cbcSMatt Macy 	retstr = cp;
57eda14cbcSMatt Macy 	while (*cp && *cp != ',')
58eda14cbcSMatt Macy 		cp++;
59eda14cbcSMatt Macy 
60eda14cbcSMatt Macy 	if (*cp) {
61eda14cbcSMatt Macy 		*cp = '\0';
62eda14cbcSMatt Macy 		cp++;
63eda14cbcSMatt Macy 	}
64eda14cbcSMatt Macy 
65eda14cbcSMatt Macy 	*p = cp;
66eda14cbcSMatt Macy 	return (retstr);
67eda14cbcSMatt Macy }
68eda14cbcSMatt Macy 
69eda14cbcSMatt Macy char *
70a0b956f5SMartin Matuska hasmntopt(struct mnttab *mnt, const char *opt)
71eda14cbcSMatt Macy {
72eda14cbcSMatt Macy 	char tmpopts[MNT_LINE_MAX];
73eda14cbcSMatt Macy 	char *f, *opts = tmpopts;
74eda14cbcSMatt Macy 
75eda14cbcSMatt Macy 	if (mnt->mnt_mntopts == NULL)
76eda14cbcSMatt Macy 		return (NULL);
77*be181ee2SMartin Matuska 	(void) strlcpy(opts, mnt->mnt_mntopts, MNT_LINE_MAX);
78eda14cbcSMatt Macy 	f = mntopt(&opts);
79eda14cbcSMatt Macy 	for (; *f; f = mntopt(&opts)) {
80eda14cbcSMatt Macy 		if (strncmp(opt, f, strlen(opt)) == 0)
81eda14cbcSMatt Macy 			return (f - tmpopts + mnt->mnt_mntopts);
82eda14cbcSMatt Macy 	}
83eda14cbcSMatt Macy 	return (NULL);
84eda14cbcSMatt Macy }
85eda14cbcSMatt Macy 
86eda14cbcSMatt Macy static void
87eda14cbcSMatt Macy optadd(char *mntopts, size_t size, const char *opt)
88eda14cbcSMatt Macy {
89eda14cbcSMatt Macy 
90eda14cbcSMatt Macy 	if (mntopts[0] != '\0')
91eda14cbcSMatt Macy 		strlcat(mntopts, ",", size);
92eda14cbcSMatt Macy 	strlcat(mntopts, opt, size);
93eda14cbcSMatt Macy }
94eda14cbcSMatt Macy 
95e92ffd9bSMartin Matuska static __thread char gfstypename[MFSNAMELEN];
96e92ffd9bSMartin Matuska static __thread char gmntfromname[MNAMELEN];
97e92ffd9bSMartin Matuska static __thread char gmntonname[MNAMELEN];
98e92ffd9bSMartin Matuska static __thread char gmntopts[MNTMAXSTR];
99e92ffd9bSMartin Matuska 
100eda14cbcSMatt Macy void
101eda14cbcSMatt Macy statfs2mnttab(struct statfs *sfs, struct mnttab *mp)
102eda14cbcSMatt Macy {
103eda14cbcSMatt Macy 	long flags;
104eda14cbcSMatt Macy 
105e92ffd9bSMartin Matuska 	strlcpy(gfstypename, sfs->f_fstypename, sizeof (gfstypename));
106e92ffd9bSMartin Matuska 	mp->mnt_fstype = gfstypename;
107e92ffd9bSMartin Matuska 
108e92ffd9bSMartin Matuska 	strlcpy(gmntfromname, sfs->f_mntfromname, sizeof (gmntfromname));
109e92ffd9bSMartin Matuska 	mp->mnt_special = gmntfromname;
110e92ffd9bSMartin Matuska 
111e92ffd9bSMartin Matuska 	strlcpy(gmntonname, sfs->f_mntonname, sizeof (gmntonname));
112e92ffd9bSMartin Matuska 	mp->mnt_mountp = gmntonname;
113eda14cbcSMatt Macy 
114eda14cbcSMatt Macy 	flags = sfs->f_flags;
115e92ffd9bSMartin Matuska 	gmntopts[0] = '\0';
116e92ffd9bSMartin Matuska #define	OPTADD(opt)	optadd(gmntopts, sizeof (gmntopts), (opt))
117eda14cbcSMatt Macy 	if (flags & MNT_RDONLY)
118eda14cbcSMatt Macy 		OPTADD(MNTOPT_RO);
119eda14cbcSMatt Macy 	else
120eda14cbcSMatt Macy 		OPTADD(MNTOPT_RW);
121eda14cbcSMatt Macy 	if (flags & MNT_NOSUID)
122eda14cbcSMatt Macy 		OPTADD(MNTOPT_NOSETUID);
123eda14cbcSMatt Macy 	else
124eda14cbcSMatt Macy 		OPTADD(MNTOPT_SETUID);
125eda14cbcSMatt Macy 	if (flags & MNT_UPDATE)
126eda14cbcSMatt Macy 		OPTADD(MNTOPT_REMOUNT);
127eda14cbcSMatt Macy 	if (flags & MNT_NOATIME)
128eda14cbcSMatt Macy 		OPTADD(MNTOPT_NOATIME);
129eda14cbcSMatt Macy 	else
130eda14cbcSMatt Macy 		OPTADD(MNTOPT_ATIME);
131eda14cbcSMatt Macy 	OPTADD(MNTOPT_NOXATTR);
132eda14cbcSMatt Macy 	if (flags & MNT_NOEXEC)
133eda14cbcSMatt Macy 		OPTADD(MNTOPT_NOEXEC);
134eda14cbcSMatt Macy 	else
135eda14cbcSMatt Macy 		OPTADD(MNTOPT_EXEC);
136eda14cbcSMatt Macy #undef	OPTADD
137e92ffd9bSMartin Matuska 	mp->mnt_mntopts = gmntopts;
138eda14cbcSMatt Macy }
139eda14cbcSMatt Macy 
140e3aa18adSMartin Matuska static pthread_rwlock_t gsfs_lock = PTHREAD_RWLOCK_INITIALIZER;
141eda14cbcSMatt Macy static struct statfs *gsfs = NULL;
142eda14cbcSMatt Macy static int allfs = 0;
143eda14cbcSMatt Macy 
144eda14cbcSMatt Macy static int
145eda14cbcSMatt Macy statfs_init(void)
146eda14cbcSMatt Macy {
147eda14cbcSMatt Macy 	struct statfs *sfs;
148eda14cbcSMatt Macy 	int error;
149eda14cbcSMatt Macy 
150e3aa18adSMartin Matuska 	(void) pthread_rwlock_wrlock(&gsfs_lock);
151e3aa18adSMartin Matuska 
152eda14cbcSMatt Macy 	if (gsfs != NULL) {
153eda14cbcSMatt Macy 		free(gsfs);
154eda14cbcSMatt Macy 		gsfs = NULL;
155eda14cbcSMatt Macy 	}
15616038816SMartin Matuska 	allfs = getfsstat(NULL, 0, MNT_NOWAIT);
157eda14cbcSMatt Macy 	if (allfs == -1)
158eda14cbcSMatt Macy 		goto fail;
159eda14cbcSMatt Macy 	gsfs = malloc(sizeof (gsfs[0]) * allfs * 2);
160eda14cbcSMatt Macy 	if (gsfs == NULL)
161eda14cbcSMatt Macy 		goto fail;
162eda14cbcSMatt Macy 	allfs = getfsstat(gsfs, (long)(sizeof (gsfs[0]) * allfs * 2),
16316038816SMartin Matuska 	    MNT_NOWAIT);
164eda14cbcSMatt Macy 	if (allfs == -1)
165eda14cbcSMatt Macy 		goto fail;
166eda14cbcSMatt Macy 	sfs = realloc(gsfs, allfs * sizeof (gsfs[0]));
167eda14cbcSMatt Macy 	if (sfs != NULL)
168eda14cbcSMatt Macy 		gsfs = sfs;
169e3aa18adSMartin Matuska 	(void) pthread_rwlock_unlock(&gsfs_lock);
170eda14cbcSMatt Macy 	return (0);
171eda14cbcSMatt Macy fail:
172eda14cbcSMatt Macy 	error = errno;
173eda14cbcSMatt Macy 	if (gsfs != NULL)
174eda14cbcSMatt Macy 		free(gsfs);
175eda14cbcSMatt Macy 	gsfs = NULL;
176eda14cbcSMatt Macy 	allfs = 0;
177e3aa18adSMartin Matuska 	(void) pthread_rwlock_unlock(&gsfs_lock);
178eda14cbcSMatt Macy 	return (error);
179eda14cbcSMatt Macy }
180eda14cbcSMatt Macy 
181eda14cbcSMatt Macy int
182eda14cbcSMatt Macy getmntany(FILE *fd __unused, struct mnttab *mgetp, struct mnttab *mrefp)
183eda14cbcSMatt Macy {
184eda14cbcSMatt Macy 	int i, error;
185eda14cbcSMatt Macy 
186eda14cbcSMatt Macy 	error = statfs_init();
187eda14cbcSMatt Macy 	if (error != 0)
188eda14cbcSMatt Macy 		return (error);
189eda14cbcSMatt Macy 
190e3aa18adSMartin Matuska 	(void) pthread_rwlock_rdlock(&gsfs_lock);
191e3aa18adSMartin Matuska 
192eda14cbcSMatt Macy 	for (i = 0; i < allfs; i++) {
193eda14cbcSMatt Macy 		if (mrefp->mnt_special != NULL &&
194eda14cbcSMatt Macy 		    strcmp(mrefp->mnt_special, gsfs[i].f_mntfromname) != 0) {
195eda14cbcSMatt Macy 			continue;
196eda14cbcSMatt Macy 		}
197eda14cbcSMatt Macy 		if (mrefp->mnt_mountp != NULL &&
198eda14cbcSMatt Macy 		    strcmp(mrefp->mnt_mountp, gsfs[i].f_mntonname) != 0) {
199eda14cbcSMatt Macy 			continue;
200eda14cbcSMatt Macy 		}
201eda14cbcSMatt Macy 		if (mrefp->mnt_fstype != NULL &&
202eda14cbcSMatt Macy 		    strcmp(mrefp->mnt_fstype, gsfs[i].f_fstypename) != 0) {
203eda14cbcSMatt Macy 			continue;
204eda14cbcSMatt Macy 		}
205eda14cbcSMatt Macy 		statfs2mnttab(&gsfs[i], mgetp);
206e3aa18adSMartin Matuska 		(void) pthread_rwlock_unlock(&gsfs_lock);
207eda14cbcSMatt Macy 		return (0);
208eda14cbcSMatt Macy 	}
209e3aa18adSMartin Matuska 	(void) pthread_rwlock_unlock(&gsfs_lock);
210eda14cbcSMatt Macy 	return (-1);
211eda14cbcSMatt Macy }
212eda14cbcSMatt Macy 
213eda14cbcSMatt Macy int
214eda14cbcSMatt Macy getmntent(FILE *fp, struct mnttab *mp)
215eda14cbcSMatt Macy {
216eda14cbcSMatt Macy 	int error, nfs;
217eda14cbcSMatt Macy 
218eda14cbcSMatt Macy 	nfs = (int)lseek(fileno(fp), 0, SEEK_CUR);
219eda14cbcSMatt Macy 	if (nfs == -1)
220eda14cbcSMatt Macy 		return (errno);
221eda14cbcSMatt Macy 	/* If nfs is 0, we want to refresh out cache. */
222eda14cbcSMatt Macy 	if (nfs == 0 || gsfs == NULL) {
223eda14cbcSMatt Macy 		error = statfs_init();
224eda14cbcSMatt Macy 		if (error != 0)
225eda14cbcSMatt Macy 			return (error);
226eda14cbcSMatt Macy 	}
227e3aa18adSMartin Matuska 	(void) pthread_rwlock_rdlock(&gsfs_lock);
228e3aa18adSMartin Matuska 	if (nfs >= allfs) {
229e3aa18adSMartin Matuska 		(void) pthread_rwlock_unlock(&gsfs_lock);
230eda14cbcSMatt Macy 		return (-1);
231e3aa18adSMartin Matuska 	}
232eda14cbcSMatt Macy 	statfs2mnttab(&gsfs[nfs], mp);
233e3aa18adSMartin Matuska 	(void) pthread_rwlock_unlock(&gsfs_lock);
234eda14cbcSMatt Macy 	if (lseek(fileno(fp), 1, SEEK_CUR) == -1)
235eda14cbcSMatt Macy 		return (errno);
236eda14cbcSMatt Macy 	return (0);
237eda14cbcSMatt Macy }
238