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/param.h>
33 #include <sys/mount.h>
34 #include <sys/mntent.h>
35 #include <sys/mnttab.h>
36
37 #include <ctype.h>
38 #include <errno.h>
39 #include <pthread.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43
44 static char *
mntopt(char ** p)45 mntopt(char **p)
46 {
47 char *cp = *p;
48 char *retstr;
49
50 while (*cp && isspace(*cp))
51 cp++;
52
53 retstr = cp;
54 while (*cp && *cp != ',')
55 cp++;
56
57 if (*cp) {
58 *cp = '\0';
59 cp++;
60 }
61
62 *p = cp;
63 return (retstr);
64 }
65
66 char *
hasmntopt(struct mnttab * mnt,const char * opt)67 hasmntopt(struct mnttab *mnt, const char *opt)
68 {
69 char tmpopts[MNT_LINE_MAX];
70 char *f, *opts = tmpopts;
71
72 if (mnt->mnt_mntopts == NULL)
73 return (NULL);
74 (void) strlcpy(opts, mnt->mnt_mntopts, MNT_LINE_MAX);
75 f = mntopt(&opts);
76 for (; *f; f = mntopt(&opts)) {
77 if (strncmp(opt, f, strlen(opt)) == 0)
78 return (f - tmpopts + mnt->mnt_mntopts);
79 }
80 return (NULL);
81 }
82
83 static void
optadd(char * mntopts,size_t size,const char * opt)84 optadd(char *mntopts, size_t size, const char *opt)
85 {
86
87 if (mntopts[0] != '\0')
88 strlcat(mntopts, ",", size);
89 strlcat(mntopts, opt, size);
90 }
91
92 static __thread char gfstypename[MFSNAMELEN];
93 static __thread char gmntfromname[MNAMELEN];
94 static __thread char gmntonname[MNAMELEN];
95 static __thread char gmntopts[MNTMAXSTR];
96
97 void
statfs2mnttab(struct statfs * sfs,struct mnttab * mp)98 statfs2mnttab(struct statfs *sfs, struct mnttab *mp)
99 {
100 long flags;
101
102 strlcpy(gfstypename, sfs->f_fstypename, sizeof (gfstypename));
103 mp->mnt_fstype = gfstypename;
104
105 strlcpy(gmntfromname, sfs->f_mntfromname, sizeof (gmntfromname));
106 mp->mnt_special = gmntfromname;
107
108 strlcpy(gmntonname, sfs->f_mntonname, sizeof (gmntonname));
109 mp->mnt_mountp = gmntonname;
110
111 flags = sfs->f_flags;
112 gmntopts[0] = '\0';
113 #define OPTADD(opt) optadd(gmntopts, sizeof (gmntopts), (opt))
114 if (flags & MNT_RDONLY)
115 OPTADD(MNTOPT_RO);
116 else
117 OPTADD(MNTOPT_RW);
118 if (flags & MNT_NOSUID)
119 OPTADD(MNTOPT_NOSETUID);
120 else
121 OPTADD(MNTOPT_SETUID);
122 if (flags & MNT_UPDATE)
123 OPTADD(MNTOPT_REMOUNT);
124 if (flags & MNT_NOATIME)
125 OPTADD(MNTOPT_NOATIME);
126 else
127 OPTADD(MNTOPT_ATIME);
128 OPTADD(MNTOPT_NOXATTR);
129 if (flags & MNT_NOEXEC)
130 OPTADD(MNTOPT_NOEXEC);
131 else
132 OPTADD(MNTOPT_EXEC);
133 #undef OPTADD
134 mp->mnt_mntopts = gmntopts;
135 }
136
137 static pthread_rwlock_t gsfs_lock = PTHREAD_RWLOCK_INITIALIZER;
138 static struct statfs *gsfs = NULL;
139 static int allfs = 0;
140
141 static int
statfs_init(void)142 statfs_init(void)
143 {
144 struct statfs *sfs;
145 int error;
146
147 (void) pthread_rwlock_wrlock(&gsfs_lock);
148
149 if (gsfs != NULL) {
150 free(gsfs);
151 gsfs = NULL;
152 }
153 allfs = getfsstat(NULL, 0, MNT_NOWAIT);
154 if (allfs == -1)
155 goto fail;
156 gsfs = malloc(sizeof (gsfs[0]) * allfs * 2);
157 if (gsfs == NULL)
158 goto fail;
159 allfs = getfsstat(gsfs, (long)(sizeof (gsfs[0]) * allfs * 2),
160 MNT_NOWAIT);
161 if (allfs == -1)
162 goto fail;
163 sfs = realloc(gsfs, allfs * sizeof (gsfs[0]));
164 if (sfs != NULL)
165 gsfs = sfs;
166 (void) pthread_rwlock_unlock(&gsfs_lock);
167 return (0);
168 fail:
169 error = errno;
170 if (gsfs != NULL)
171 free(gsfs);
172 gsfs = NULL;
173 allfs = 0;
174 (void) pthread_rwlock_unlock(&gsfs_lock);
175 return (error);
176 }
177
178 int
getmntany(FILE * fd __unused,struct mnttab * mgetp,struct mnttab * mrefp)179 getmntany(FILE *fd __unused, struct mnttab *mgetp, struct mnttab *mrefp)
180 {
181 int i, error;
182
183 error = statfs_init();
184 if (error != 0)
185 return (error);
186
187 (void) pthread_rwlock_rdlock(&gsfs_lock);
188
189 for (i = 0; i < allfs; i++) {
190 if (mrefp->mnt_special != NULL &&
191 strcmp(mrefp->mnt_special, gsfs[i].f_mntfromname) != 0) {
192 continue;
193 }
194 if (mrefp->mnt_mountp != NULL &&
195 strcmp(mrefp->mnt_mountp, gsfs[i].f_mntonname) != 0) {
196 continue;
197 }
198 if (mrefp->mnt_fstype != NULL &&
199 strcmp(mrefp->mnt_fstype, gsfs[i].f_fstypename) != 0) {
200 continue;
201 }
202 statfs2mnttab(&gsfs[i], mgetp);
203 (void) pthread_rwlock_unlock(&gsfs_lock);
204 return (0);
205 }
206 (void) pthread_rwlock_unlock(&gsfs_lock);
207 return (-1);
208 }
209
210 int
getmntent(FILE * fp,struct mnttab * mp)211 getmntent(FILE *fp, struct mnttab *mp)
212 {
213 int error, nfs;
214
215 nfs = (int)lseek(fileno(fp), 0, SEEK_CUR);
216 if (nfs == -1)
217 return (errno);
218 /* If nfs is 0, we want to refresh out cache. */
219 if (nfs == 0 || gsfs == NULL) {
220 error = statfs_init();
221 if (error != 0)
222 return (error);
223 }
224 (void) pthread_rwlock_rdlock(&gsfs_lock);
225 if (nfs >= allfs) {
226 (void) pthread_rwlock_unlock(&gsfs_lock);
227 return (-1);
228 }
229 statfs2mnttab(&gsfs[nfs], mp);
230 (void) pthread_rwlock_unlock(&gsfs_lock);
231 if (lseek(fileno(fp), 1, SEEK_CUR) == -1)
232 return (errno);
233 return (0);
234 }
235