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 void
95 statfs2mnttab(struct statfs *sfs, struct mnttab *mp)
96 {
97 	static char mntopts[MNTMAXSTR];
98 	long flags;
99 
100 	mntopts[0] = '\0';
101 
102 	flags = sfs->f_flags;
103 #define	OPTADD(opt)	optadd(mntopts, sizeof (mntopts), (opt))
104 	if (flags & MNT_RDONLY)
105 		OPTADD(MNTOPT_RO);
106 	else
107 		OPTADD(MNTOPT_RW);
108 	if (flags & MNT_NOSUID)
109 		OPTADD(MNTOPT_NOSETUID);
110 	else
111 		OPTADD(MNTOPT_SETUID);
112 	if (flags & MNT_UPDATE)
113 		OPTADD(MNTOPT_REMOUNT);
114 	if (flags & MNT_NOATIME)
115 		OPTADD(MNTOPT_NOATIME);
116 	else
117 		OPTADD(MNTOPT_ATIME);
118 	OPTADD(MNTOPT_NOXATTR);
119 	if (flags & MNT_NOEXEC)
120 		OPTADD(MNTOPT_NOEXEC);
121 	else
122 		OPTADD(MNTOPT_EXEC);
123 #undef	OPTADD
124 	mp->mnt_special = strdup(sfs->f_mntfromname);
125 	mp->mnt_mountp = strdup(sfs->f_mntonname);
126 	mp->mnt_fstype = strdup(sfs->f_fstypename);
127 	mp->mnt_mntopts = strdup(mntopts);
128 }
129 
130 static struct statfs *gsfs = NULL;
131 static int allfs = 0;
132 
133 static int
134 statfs_init(void)
135 {
136 	struct statfs *sfs;
137 	int error;
138 
139 	if (gsfs != NULL) {
140 		free(gsfs);
141 		gsfs = NULL;
142 	}
143 	allfs = getfsstat(NULL, 0, MNT_WAIT);
144 	if (allfs == -1)
145 		goto fail;
146 	gsfs = malloc(sizeof (gsfs[0]) * allfs * 2);
147 	if (gsfs == NULL)
148 		goto fail;
149 	allfs = getfsstat(gsfs, (long)(sizeof (gsfs[0]) * allfs * 2),
150 	    MNT_WAIT);
151 	if (allfs == -1)
152 		goto fail;
153 	sfs = realloc(gsfs, allfs * sizeof (gsfs[0]));
154 	if (sfs != NULL)
155 		gsfs = sfs;
156 	return (0);
157 fail:
158 	error = errno;
159 	if (gsfs != NULL)
160 		free(gsfs);
161 	gsfs = NULL;
162 	allfs = 0;
163 	return (error);
164 }
165 
166 int
167 getmntany(FILE *fd __unused, struct mnttab *mgetp, struct mnttab *mrefp)
168 {
169 	//	struct statfs *sfs;
170 	int i, error;
171 
172 	error = statfs_init();
173 	if (error != 0)
174 		return (error);
175 
176 	for (i = 0; i < allfs; i++) {
177 		if (mrefp->mnt_special != NULL &&
178 		    strcmp(mrefp->mnt_special, gsfs[i].f_mntfromname) != 0) {
179 			continue;
180 		}
181 		if (mrefp->mnt_mountp != NULL &&
182 		    strcmp(mrefp->mnt_mountp, gsfs[i].f_mntonname) != 0) {
183 			continue;
184 		}
185 		if (mrefp->mnt_fstype != NULL &&
186 		    strcmp(mrefp->mnt_fstype, gsfs[i].f_fstypename) != 0) {
187 			continue;
188 		}
189 		statfs2mnttab(&gsfs[i], mgetp);
190 		return (0);
191 	}
192 	return (-1);
193 }
194 
195 int
196 getmntent(FILE *fp, struct mnttab *mp)
197 {
198 	//	struct statfs *sfs;
199 	int error, nfs;
200 
201 	nfs = (int)lseek(fileno(fp), 0, SEEK_CUR);
202 	if (nfs == -1)
203 		return (errno);
204 	/* If nfs is 0, we want to refresh out cache. */
205 	if (nfs == 0 || gsfs == NULL) {
206 		error = statfs_init();
207 		if (error != 0)
208 			return (error);
209 	}
210 	if (nfs >= allfs)
211 		return (-1);
212 	statfs2mnttab(&gsfs[nfs], mp);
213 	if (lseek(fileno(fp), 1, SEEK_CUR) == -1)
214 		return (errno);
215 	return (0);
216 }
217