1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (c) 2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 /*
29 * This file implements Solaris compatible hasmntopt() 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
getmntent(FILE * fp,struct mnttab * mp)179 getmntent(FILE *fp, struct mnttab *mp)
180 {
181 int error, nfs;
182
183 nfs = (int)lseek(fileno(fp), 0, SEEK_CUR);
184 if (nfs == -1)
185 return (errno);
186 /* If nfs is 0, we want to refresh out cache. */
187 if (nfs == 0 || gsfs == NULL) {
188 error = statfs_init();
189 if (error != 0)
190 return (error);
191 }
192 (void) pthread_rwlock_rdlock(&gsfs_lock);
193 if (nfs >= allfs) {
194 (void) pthread_rwlock_unlock(&gsfs_lock);
195 return (-1);
196 }
197 statfs2mnttab(&gsfs[nfs], mp);
198 (void) pthread_rwlock_unlock(&gsfs_lock);
199 if (lseek(fileno(fp), 1, SEEK_CUR) == -1)
200 return (errno);
201 return (0);
202 }
203