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