1 /*
2 * Copyright (c) 2006 Pawel Jakub Dawidek <[email protected]>
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 *
mntopt(char ** p)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 *
hasmntopt(struct mnttab * mnt,char * opt)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
optadd(char * mntopts,size_t size,const char * opt)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
statfs2mnttab(struct statfs * sfs,struct mnttab * mp)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
statfs_init(void)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
getmntany(FILE * fd __unused,struct mnttab * mgetp,struct mnttab * mrefp)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
getmntent(FILE * fp,struct mnttab * mp)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