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