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