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 * 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 * 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 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 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 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 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 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