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