xref: /illumos-gate/usr/src/lib/libc/port/gen/getmntent.c (revision b02637af6dc592eb1f43cb4c74f06268648dbd2d)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*	Copyright (c) 1988 AT&T	*/
30 /*	  All Rights Reserved  	*/
31 
32 
33 #pragma weak getmntany = _getmntany
34 #pragma weak getmntent = _getmntent
35 #pragma weak getextmntent = _getextmntent
36 #pragma weak resetmnttab = _resetmnttab
37 #pragma weak hasmntopt = _hasmntopt
38 
39 #include "synonyms.h"
40 #include <mtlib.h>
41 #include <stdio.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <sys/mnttab.h>
45 #include <sys/mntio.h>
46 #include <string.h>
47 #include <ctype.h>
48 #include <errno.h>
49 #include <stdlib.h>
50 #include <thread.h>
51 #include <synch.h>
52 #include <libc.h>
53 #include <unistd.h>
54 #include "tsd.h"
55 
56 static int getmntent_compat(FILE *fp, struct mnttab *mp);
57 static int convert_mntent(struct extmnttab *, struct extmnttab *, int);
58 
59 #define	GETTOK_R(xx, ll, tmp)\
60 	if ((mp->xx = (char *)strtok_r(ll, sepstr, tmp)) == NULL)\
61 		return (MNT_TOOFEW);\
62 	if (strcmp(mp->xx, dash) == 0)\
63 		mp->xx = NULL
64 
65 #define	DIFF(xx)\
66 	(mrefp->xx != NULL && (mgetp->xx == NULL ||\
67 	    strcmp(mrefp->xx, mgetp->xx) != 0))
68 
69 #define	SDIFF(xx, typem, typer)\
70 	((mgetp->xx == NULL) || (stat64(mgetp->xx, &statb) == -1) ||\
71 	((statb.st_mode & S_IFMT) != typem) ||\
72 	    (statb.st_rdev != typer))
73 
74 static const char	sepstr[] = " \t\n";
75 static const char	dash[] = "-";
76 
77 typedef struct {
78 	size_t	buflen;
79 	char	*buf;
80 } thread_data_t;
81 
82 static void
83 destroy_thread_data(void *arg)
84 {
85 	thread_data_t *thread_data = arg;
86 
87 	if (thread_data->buf != NULL) {
88 		free(thread_data->buf);
89 		thread_data->buf = NULL;
90 	}
91 	thread_data->buflen = 0;
92 }
93 
94 static char *
95 getmntbuf(size_t size)
96 {
97 	thread_data_t *thread_data;
98 
99 	if (size < MNT_LINE_MAX)
100 		size = MNT_LINE_MAX;
101 
102 	thread_data = tsdalloc(_T_GETMNTENT,
103 	    sizeof (thread_data_t), destroy_thread_data);
104 	if (thread_data == NULL)
105 		return (NULL);
106 	if (thread_data->buf == NULL ||
107 	    thread_data->buflen < size) {
108 		if (thread_data->buf != NULL)
109 			free(thread_data->buf);
110 		thread_data->buflen = 0;
111 		if ((thread_data->buf = malloc(size)) == NULL)
112 			return (NULL);
113 		thread_data->buflen = size;
114 	}
115 	return (thread_data->buf);
116 }
117 
118 int
119 getmntany(FILE *fp, struct mnttab *mgetp, struct mnttab *mrefp)
120 {
121 	int	ret, bstat;
122 	mode_t	bmode;
123 	dev_t	brdev;
124 	struct stat64	statb;
125 
126 	/*
127 	 * Ignore specials that don't correspond to real devices to avoid doing
128 	 * unnecessary lookups in stat64().
129 	 */
130 	if (mrefp->mnt_special && mrefp->mnt_special[0] == '/' &&
131 	    stat64(mrefp->mnt_special, &statb) == 0 &&
132 	    ((bmode = (statb.st_mode & S_IFMT)) == S_IFBLK ||
133 	    bmode == S_IFCHR)) {
134 		bstat = 1;
135 		brdev = statb.st_rdev;
136 	} else {
137 		bstat = 0;
138 	}
139 
140 	while ((ret = getmntent(fp, mgetp)) == 0 &&
141 	    ((bstat == 0 && DIFF(mnt_special)) ||
142 	    (bstat == 1 && SDIFF(mnt_special, bmode, brdev)) ||
143 	    DIFF(mnt_mountp) ||
144 	    DIFF(mnt_fstype) ||
145 	    DIFF(mnt_mntopts) ||
146 	    DIFF(mnt_time)))
147 		;
148 
149 	return (ret);
150 }
151 
152 int
153 getmntent(FILE *fp, struct mnttab *mp)
154 {
155 	int	ret;
156 	struct	extmnttab *emp;
157 
158 	ret = ioctl(fileno(fp), MNTIOC_GETMNTENT, &emp);
159 
160 	switch (ret) {
161 		case 0:
162 			return (convert_mntent(emp, (struct extmnttab *)mp, 0));
163 		case 1:
164 			return (-1);
165 		default:
166 			return (getmntent_compat(fp, mp));
167 	}
168 }
169 
170 char *
171 mntopt(char **p)
172 {
173 	char *cp = *p;
174 	char *retstr;
175 
176 	while (*cp && isspace(*cp))
177 		cp++;
178 
179 	retstr = cp;
180 	while (*cp && *cp != ',')
181 		cp++;
182 
183 	if (*cp) {
184 		*cp = '\0';
185 		cp++;
186 	}
187 
188 	*p = cp;
189 	return (retstr);
190 }
191 
192 char *
193 hasmntopt(struct mnttab *mnt, char *opt)
194 {
195 	char tmpopts[MNT_LINE_MAX];
196 	char *f, *opts = tmpopts;
197 	size_t	len;
198 
199 	if (mnt->mnt_mntopts == NULL)
200 		return (NULL);
201 	(void) strcpy(opts, mnt->mnt_mntopts);
202 	len = strlen(opt);
203 	f = mntopt(&opts);
204 	for (; *f; f = mntopt(&opts)) {
205 		/*
206 		 * Match only complete substrings. For options
207 		 * which use a delimiter (such as 'retry=3'),
208 		 * treat the delimiter as the end of the substring.
209 		 */
210 		if (strncmp(opt, f, len) == 0 &&
211 		    (f[len] == '\0' || !isalnum(f[len])))
212 			return (f - tmpopts + mnt->mnt_mntopts);
213 	}
214 	return (NULL);
215 }
216 
217 /*ARGSUSED*/
218 int
219 getextmntent(FILE *fp, struct extmnttab *mp, size_t len)
220 {
221 	int	ret;
222 	struct	extmnttab *emp;
223 
224 	ret = ioctl(fileno(fp), MNTIOC_GETMNTENT, &emp);
225 
226 	switch (ret) {
227 		case 0:
228 			return (convert_mntent(emp, mp, 1));
229 		case 1:
230 			return (-1);
231 		default:
232 			return (ret);
233 	}
234 }
235 
236 void
237 resetmnttab(FILE *fp)
238 {
239 	rewind(fp);
240 }
241 
242 /*
243  * This is a horrible function, necessary to support this broken interface.
244  * Some callers of get(ext)mntent assume that the memory is valid even after the
245  * file is closed.  Since we switched to a direct ioctl() interface, this is no
246  * longer true.  In order to support these apps, we have to put the data into a
247  * thread specific buffer.
248  */
249 static int
250 convert_mntent(struct extmnttab *src, struct extmnttab *dst, int isext)
251 {
252 	size_t len;
253 	char *buf;
254 
255 	len = src->mnt_time - src->mnt_special + strlen(src->mnt_time) + 1;
256 
257 	buf = getmntbuf(len);
258 	if (buf == NULL) {
259 		errno = ENOMEM;
260 		return (-1);
261 	}
262 
263 	memcpy(buf, src->mnt_special, len);
264 	dst->mnt_special = buf;
265 	dst->mnt_mountp = buf + (src->mnt_mountp - src->mnt_special);
266 	dst->mnt_fstype = buf + (src->mnt_fstype - src->mnt_special);
267 	dst->mnt_mntopts = buf + (src->mnt_mntopts - src->mnt_special);
268 	dst->mnt_time = buf + (src->mnt_time - src->mnt_special);
269 	if (isext) {
270 		dst->mnt_major = src->mnt_major;
271 		dst->mnt_minor = src->mnt_minor;
272 	}
273 
274 	return (0);
275 }
276 
277 /*
278  * Compatibility for non-mntfs files.  For backwards compatibility, we continue
279  * to have to support this broken interface.  Note that getextmntent() has
280  * always failed when using a file other than /etc/mnttab, because it relies on
281  * an ioctl() call.
282  */
283 static int
284 getline(char *lp, FILE *fp)
285 {
286 	char	*cp;
287 
288 	while ((lp = fgets(lp, MNT_LINE_MAX, fp)) != NULL) {
289 		if (strlen(lp) == MNT_LINE_MAX-1 && lp[MNT_LINE_MAX-2] != '\n')
290 			return (MNT_TOOLONG);
291 
292 		for (cp = lp; *cp == ' ' || *cp == '\t'; cp++)
293 			;
294 
295 		if (*cp != '#' && *cp != '\n')
296 			return (0);
297 	}
298 	return (-1);
299 }
300 
301 static int
302 getmntent_compat(FILE *fp, struct mnttab *mp)
303 {
304 	int	ret;
305 	char	*tmp;
306 	char	*line = getmntbuf(MNT_LINE_MAX);
307 
308 	if (line == NULL) {
309 		errno = ENOMEM;
310 		return (-1);
311 	}
312 
313 	/* skip leading spaces and comments */
314 	if ((ret = getline(line, fp)) != 0)
315 		return (ret);
316 
317 	/* split up each field */
318 	GETTOK_R(mnt_special, line, &tmp);
319 	GETTOK_R(mnt_mountp, NULL, &tmp);
320 	GETTOK_R(mnt_fstype, NULL, &tmp);
321 	GETTOK_R(mnt_mntopts, NULL, &tmp);
322 	GETTOK_R(mnt_time, NULL, &tmp);
323 
324 	/* check for too many fields */
325 	if (strtok_r(NULL, sepstr, &tmp) != NULL)
326 		return (MNT_TOOMANY);
327 
328 	return (0);
329 }
330