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.
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.
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]
23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
26 /* Copyright (c) 1988 AT&T */
27 /* All Rights Reserved */
32 #include <sys/types.h>
34 #include <sys/mnttab.h>
35 #include <sys/mntio.h>
48 static int getmntent_compat(FILE *fp
, struct mnttab
*mp
);
50 #define GETTOK_R(xx, ll, tmp)\
51 if ((mp->xx = (char *)strtok_r(ll, sepstr, tmp)) == NULL)\
53 if (strcmp(mp->xx, dash) == 0)\
57 (mrefp->xx != NULL && (mgetp->xx == NULL ||\
58 strcmp(mrefp->xx, mgetp->xx) != 0))
60 #define SDIFF(xx, typem, typer)\
61 ((mgetp->xx == NULL) || (stat64(mgetp->xx, &statb) == -1) ||\
62 ((statb.st_mode & S_IFMT) != typem) ||\
63 (statb.st_rdev != typer))
65 static const char sepstr
[] = " \t\n";
66 static const char dash
[] = "-";
74 destroy_thread_data(void *arg
)
76 thread_data_t
*thread_data
= arg
;
78 if (thread_data
->buf
!= NULL
) {
79 free(thread_data
->buf
);
80 thread_data
->buf
= NULL
;
82 thread_data
->buflen
= 0;
86 getmntbuf(size_t size
)
88 thread_data_t
*thread_data
;
90 thread_data
= tsdalloc(_T_GETMNTENT
,
91 sizeof (thread_data_t
), destroy_thread_data
);
92 if (thread_data
== NULL
)
94 if (thread_data
->buf
== NULL
||
95 thread_data
->buflen
< size
) {
96 free(thread_data
->buf
);
97 thread_data
->buflen
= 0;
98 if ((thread_data
->buf
= malloc(size
)) == NULL
)
100 thread_data
->buflen
= size
;
102 return (thread_data
->buf
);
106 getmntany_compat(FILE *fp
, struct mnttab
*mgetp
, struct mnttab
*mrefp
)
114 * Ignore specials that don't correspond to real devices to avoid doing
115 * unnecessary lookups in stat64().
117 if (mrefp
->mnt_special
&& mrefp
->mnt_special
[0] == '/' &&
118 stat64(mrefp
->mnt_special
, &statb
) == 0 &&
119 ((bmode
= (statb
.st_mode
& S_IFMT
)) == S_IFBLK
||
122 brdev
= statb
.st_rdev
;
127 while ((ret
= getmntent_compat(fp
, mgetp
)) == 0 &&
128 ((bstat
== 0 && DIFF(mnt_special
)) ||
129 (bstat
== 1 && SDIFF(mnt_special
, bmode
, brdev
)) ||
140 getmntany(FILE *fp
, struct mnttab
*mgetp
, struct mnttab
*mrefp
)
142 struct mntentbuf embuf
;
148 * We collect all of the text strings pointed to by members of the
149 * user's preferences struct into a single buffer. At the same time
150 * populate the members of the results struct to point to the
151 * corresponding words. We then ask the kernel to figure out the
152 * rest; if this is a non-mntfs file then we handover to
153 * getmntany_compat().
155 if ((copyp
= bufp
= getmntbuf(MNT_LINE_MAX
)) == NULL
) {
159 bzero(mgetp
, sizeof (struct mnttab
));
160 if (mrefp
->mnt_special
) {
161 mgetp
->mnt_special
= copyp
;
162 copyp
+= snprintf(mgetp
->mnt_special
, MNT_LINE_MAX
, "%s",
163 mrefp
->mnt_special
) + 1;
165 if (mrefp
->mnt_mountp
) {
166 mgetp
->mnt_mountp
= copyp
;
167 copyp
+= snprintf(mgetp
->mnt_mountp
,
168 bufp
+ MNT_LINE_MAX
- copyp
, "%s", mrefp
->mnt_mountp
) + 1;
170 if (mrefp
->mnt_fstype
) {
171 mgetp
->mnt_fstype
= copyp
;
172 copyp
+= snprintf(mgetp
->mnt_fstype
,
173 bufp
+ MNT_LINE_MAX
- copyp
, "%s", mrefp
->mnt_fstype
) + 1;
175 if (mrefp
->mnt_mntopts
) {
176 mgetp
->mnt_mntopts
= copyp
;
177 copyp
+= snprintf(mgetp
->mnt_mntopts
,
178 bufp
+ MNT_LINE_MAX
- copyp
, "%s", mrefp
->mnt_mntopts
) + 1;
180 if (mrefp
->mnt_time
) {
181 mgetp
->mnt_time
= copyp
;
182 (void) snprintf(mgetp
->mnt_time
, bufp
+ MNT_LINE_MAX
- copyp
,
183 "%s", mrefp
->mnt_time
);
186 embuf
.mbuf_emp
= (struct extmnttab
*)mgetp
;
187 embuf
.mbuf_bufsize
= MNT_LINE_MAX
;
188 embuf
.mbuf_buf
= bufp
;
190 switch (ret
= ioctl(fileno(fp
), MNTIOC_GETMNTANY
, &embuf
)) {
197 return (MNT_TOOLONG
);
199 /* A failure of some kind. */
201 return (getmntany_compat(fp
, mgetp
, mrefp
));
208 * Common code for getmntent() and getextmntent().
210 * These functions serve to populate a structure supplied by the user. Common
211 * to both struct mnttab and struct extmnttab is a set of pointers to the
212 * individual text fields that form an entry in /etc/mnttab. We arrange for the
213 * text itself to be stored in some thread-local storage, and for the kernel to
214 * populate both this buffer and the structure directly.
216 * If getmntent() passes a file that isn't provided by mntfs then we assume that
217 * it is a simple text file and give it to getmntent_compat() to parse. For
218 * getextmntent() we give up; it requires major and minor numbers that only the
219 * kernel can provide.
222 getmntent_common(FILE *fp
, struct extmnttab
*emp
, int command
)
224 struct mntentbuf embuf
;
225 static size_t bufsize
= MNT_LINE_MAX
;
228 embuf
.mbuf_emp
= emp
;
229 embuf
.mbuf_bufsize
= bufsize
;
230 if ((embuf
.mbuf_buf
= getmntbuf(embuf
.mbuf_bufsize
)) == NULL
) {
235 while ((ret
= ioctl(fileno(fp
), command
, &embuf
)) == MNTFS_TOOLONG
) {
236 /* The buffer wasn't large enough. */
237 (void) atomic_swap_ulong((unsigned long *)&bufsize
,
238 2 * embuf
.mbuf_bufsize
);
239 embuf
.mbuf_bufsize
= bufsize
;
240 if ((embuf
.mbuf_buf
= getmntbuf(embuf
.mbuf_bufsize
)) == NULL
) {
249 * We were successful, but we may have to enforce getmntent()'s
250 * documented limit on the line length.
252 if (command
== MNTIOC_GETMNTENT
&&
253 (emp
->mnt_time
+ strlen(emp
->mnt_time
) + 1 -
254 emp
->mnt_special
> MNT_LINE_MAX
))
255 return (MNT_TOOLONG
);
262 /* A non-mntfs file. */
263 if (command
== MNTIOC_GETMNTENT
)
264 return (getmntent_compat(fp
, (struct mnttab
*)emp
));
271 getmntent(FILE *fp
, struct mnttab
*mp
)
273 return (getmntent_common(fp
, (struct extmnttab
*)mp
, MNTIOC_GETMNTENT
));
278 getextmntent(FILE *fp
, struct extmnttab
*emp
, size_t len
)
280 return (getmntent_common(fp
, emp
, MNTIOC_GETEXTMNTENT
));
289 while (*cp
&& isspace(*cp
))
293 while (*cp
&& *cp
!= ',')
306 hasmntopt(struct mnttab
*mnt
, char *opt
)
308 char tmpopts
[MNT_LINE_MAX
];
309 char *f
, *opts
= tmpopts
;
312 if (mnt
->mnt_mntopts
== NULL
)
314 (void) strcpy(opts
, mnt
->mnt_mntopts
);
317 for (; *f
; f
= mntopt(&opts
)) {
319 * Match only complete substrings. For options
320 * which use a delimiter (such as 'retry=3'),
321 * treat the delimiter as the end of the substring.
323 if (strncmp(opt
, f
, len
) == 0 &&
324 (f
[len
] == '\0' || !isalnum(f
[len
])))
325 return (f
- tmpopts
+ mnt
->mnt_mntopts
);
331 resetmnttab(FILE *fp
)
337 * Compatibility for non-mntfs files. For backwards compatibility, we continue
338 * to have to support this broken interface. Note that getextmntent() has
339 * always failed when using a file other than /etc/mnttab, because it relies on
343 getaline(char *lp
, FILE *fp
)
347 while ((lp
= fgets(lp
, MNT_LINE_MAX
, fp
)) != NULL
) {
348 if (strlen(lp
) == MNT_LINE_MAX
-1 && lp
[MNT_LINE_MAX
-2] != '\n')
349 return (MNT_TOOLONG
);
351 for (cp
= lp
; *cp
== ' ' || *cp
== '\t'; cp
++)
354 if (*cp
!= '#' && *cp
!= '\n')
361 getmntent_compat(FILE *fp
, struct mnttab
*mp
)
365 char *line
= getmntbuf(MNT_LINE_MAX
);
372 /* skip leading spaces and comments */
373 if ((ret
= getaline(line
, fp
)) != 0)
376 /* split up each field */
377 GETTOK_R(mnt_special
, line
, &tmp
);
378 GETTOK_R(mnt_mountp
, NULL
, &tmp
);
379 GETTOK_R(mnt_fstype
, NULL
, &tmp
);
380 GETTOK_R(mnt_mntopts
, NULL
, &tmp
);
381 GETTOK_R(mnt_time
, NULL
, &tmp
);
383 /* check for too many fields */
384 if (strtok_r(NULL
, sepstr
, &tmp
) != NULL
)
385 return (MNT_TOOMANY
);