1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* Copyright (c) 1988 AT&T */ 30 /* All Rights Reserved */ 31 32 33 #pragma weak getmntany = _getmntany 34 #pragma weak getmntent = _getmntent 35 #pragma weak getextmntent = _getextmntent 36 #pragma weak resetmnttab = _resetmnttab 37 #pragma weak hasmntopt = _hasmntopt 38 39 #include "synonyms.h" 40 #include <mtlib.h> 41 #include <stdio.h> 42 #include <sys/types.h> 43 #include <sys/stat.h> 44 #include <sys/mnttab.h> 45 #include <sys/mntio.h> 46 #include <string.h> 47 #include <ctype.h> 48 #include <errno.h> 49 #include <stdlib.h> 50 #include <thread.h> 51 #include <synch.h> 52 #include <libc.h> 53 #include <unistd.h> 54 #include "tsd.h" 55 56 static int getmntent_compat(FILE *fp, struct mnttab *mp); 57 static int convert_mntent(struct extmnttab *, struct extmnttab *, int); 58 59 #define GETTOK_R(xx, ll, tmp)\ 60 if ((mp->xx = (char *)strtok_r(ll, sepstr, tmp)) == NULL)\ 61 return (MNT_TOOFEW);\ 62 if (strcmp(mp->xx, dash) == 0)\ 63 mp->xx = NULL 64 65 #define DIFF(xx)\ 66 (mrefp->xx != NULL && (mgetp->xx == NULL ||\ 67 strcmp(mrefp->xx, mgetp->xx) != 0)) 68 69 #define SDIFF(xx, typem, typer)\ 70 ((mgetp->xx == NULL) || (stat64(mgetp->xx, &statb) == -1) ||\ 71 ((statb.st_mode & S_IFMT) != typem) ||\ 72 (statb.st_rdev != typer)) 73 74 static const char sepstr[] = " \t\n"; 75 static const char dash[] = "-"; 76 77 typedef struct { 78 size_t buflen; 79 char *buf; 80 } thread_data_t; 81 82 static void 83 destroy_thread_data(void *arg) 84 { 85 thread_data_t *thread_data = arg; 86 87 if (thread_data->buf != NULL) { 88 free(thread_data->buf); 89 thread_data->buf = NULL; 90 } 91 thread_data->buflen = 0; 92 } 93 94 static char * 95 getmntbuf(size_t size) 96 { 97 thread_data_t *thread_data; 98 99 if (size < MNT_LINE_MAX) 100 size = MNT_LINE_MAX; 101 102 thread_data = tsdalloc(_T_GETMNTENT, 103 sizeof (thread_data_t), destroy_thread_data); 104 if (thread_data == NULL) 105 return (NULL); 106 if (thread_data->buf == NULL || 107 thread_data->buflen < size) { 108 if (thread_data->buf != NULL) 109 free(thread_data->buf); 110 thread_data->buflen = 0; 111 if ((thread_data->buf = malloc(size)) == NULL) 112 return (NULL); 113 thread_data->buflen = size; 114 } 115 return (thread_data->buf); 116 } 117 118 int 119 getmntany(FILE *fp, struct mnttab *mgetp, struct mnttab *mrefp) 120 { 121 int ret, bstat; 122 mode_t bmode; 123 dev_t brdev; 124 struct stat64 statb; 125 126 /* 127 * Ignore specials that don't correspond to real devices to avoid doing 128 * unnecessary lookups in stat64(). 129 */ 130 if (mrefp->mnt_special && mrefp->mnt_special[0] == '/' && 131 stat64(mrefp->mnt_special, &statb) == 0 && 132 ((bmode = (statb.st_mode & S_IFMT)) == S_IFBLK || 133 bmode == S_IFCHR)) { 134 bstat = 1; 135 brdev = statb.st_rdev; 136 } else { 137 bstat = 0; 138 } 139 140 while ((ret = getmntent(fp, mgetp)) == 0 && 141 ((bstat == 0 && DIFF(mnt_special)) || 142 (bstat == 1 && SDIFF(mnt_special, bmode, brdev)) || 143 DIFF(mnt_mountp) || 144 DIFF(mnt_fstype) || 145 DIFF(mnt_mntopts) || 146 DIFF(mnt_time))) 147 ; 148 149 return (ret); 150 } 151 152 int 153 getmntent(FILE *fp, struct mnttab *mp) 154 { 155 int ret; 156 struct extmnttab *emp; 157 158 ret = ioctl(fileno(fp), MNTIOC_GETMNTENT, &emp); 159 160 switch (ret) { 161 case 0: 162 return (convert_mntent(emp, (struct extmnttab *)mp, 0)); 163 case 1: 164 return (-1); 165 default: 166 return (getmntent_compat(fp, mp)); 167 } 168 } 169 170 char * 171 mntopt(char **p) 172 { 173 char *cp = *p; 174 char *retstr; 175 176 while (*cp && isspace(*cp)) 177 cp++; 178 179 retstr = cp; 180 while (*cp && *cp != ',') 181 cp++; 182 183 if (*cp) { 184 *cp = '\0'; 185 cp++; 186 } 187 188 *p = cp; 189 return (retstr); 190 } 191 192 char * 193 hasmntopt(struct mnttab *mnt, char *opt) 194 { 195 char tmpopts[MNT_LINE_MAX]; 196 char *f, *opts = tmpopts; 197 size_t len; 198 199 if (mnt->mnt_mntopts == NULL) 200 return (NULL); 201 (void) strcpy(opts, mnt->mnt_mntopts); 202 len = strlen(opt); 203 f = mntopt(&opts); 204 for (; *f; f = mntopt(&opts)) { 205 /* 206 * Match only complete substrings. For options 207 * which use a delimiter (such as 'retry=3'), 208 * treat the delimiter as the end of the substring. 209 */ 210 if (strncmp(opt, f, len) == 0 && 211 (f[len] == '\0' || !isalnum(f[len]))) 212 return (f - tmpopts + mnt->mnt_mntopts); 213 } 214 return (NULL); 215 } 216 217 /*ARGSUSED*/ 218 int 219 getextmntent(FILE *fp, struct extmnttab *mp, size_t len) 220 { 221 int ret; 222 struct extmnttab *emp; 223 224 ret = ioctl(fileno(fp), MNTIOC_GETMNTENT, &emp); 225 226 switch (ret) { 227 case 0: 228 return (convert_mntent(emp, mp, 1)); 229 case 1: 230 return (-1); 231 default: 232 return (ret); 233 } 234 } 235 236 void 237 resetmnttab(FILE *fp) 238 { 239 rewind(fp); 240 } 241 242 /* 243 * This is a horrible function, necessary to support this broken interface. 244 * Some callers of get(ext)mntent assume that the memory is valid even after the 245 * file is closed. Since we switched to a direct ioctl() interface, this is no 246 * longer true. In order to support these apps, we have to put the data into a 247 * thread specific buffer. 248 */ 249 static int 250 convert_mntent(struct extmnttab *src, struct extmnttab *dst, int isext) 251 { 252 size_t len; 253 char *buf; 254 255 len = src->mnt_time - src->mnt_special + strlen(src->mnt_time) + 1; 256 257 buf = getmntbuf(len); 258 if (buf == NULL) { 259 errno = ENOMEM; 260 return (-1); 261 } 262 263 memcpy(buf, src->mnt_special, len); 264 dst->mnt_special = buf; 265 dst->mnt_mountp = buf + (src->mnt_mountp - src->mnt_special); 266 dst->mnt_fstype = buf + (src->mnt_fstype - src->mnt_special); 267 dst->mnt_mntopts = buf + (src->mnt_mntopts - src->mnt_special); 268 dst->mnt_time = buf + (src->mnt_time - src->mnt_special); 269 if (isext) { 270 dst->mnt_major = src->mnt_major; 271 dst->mnt_minor = src->mnt_minor; 272 } 273 274 return (0); 275 } 276 277 /* 278 * Compatibility for non-mntfs files. For backwards compatibility, we continue 279 * to have to support this broken interface. Note that getextmntent() has 280 * always failed when using a file other than /etc/mnttab, because it relies on 281 * an ioctl() call. 282 */ 283 static int 284 getline(char *lp, FILE *fp) 285 { 286 char *cp; 287 288 while ((lp = fgets(lp, MNT_LINE_MAX, fp)) != NULL) { 289 if (strlen(lp) == MNT_LINE_MAX-1 && lp[MNT_LINE_MAX-2] != '\n') 290 return (MNT_TOOLONG); 291 292 for (cp = lp; *cp == ' ' || *cp == '\t'; cp++) 293 ; 294 295 if (*cp != '#' && *cp != '\n') 296 return (0); 297 } 298 return (-1); 299 } 300 301 static int 302 getmntent_compat(FILE *fp, struct mnttab *mp) 303 { 304 int ret; 305 char *tmp; 306 char *line = getmntbuf(MNT_LINE_MAX); 307 308 if (line == NULL) { 309 errno = ENOMEM; 310 return (-1); 311 } 312 313 /* skip leading spaces and comments */ 314 if ((ret = getline(line, fp)) != 0) 315 return (ret); 316 317 /* split up each field */ 318 GETTOK_R(mnt_special, line, &tmp); 319 GETTOK_R(mnt_mountp, NULL, &tmp); 320 GETTOK_R(mnt_fstype, NULL, &tmp); 321 GETTOK_R(mnt_mntopts, NULL, &tmp); 322 GETTOK_R(mnt_time, NULL, &tmp); 323 324 /* check for too many fields */ 325 if (strtok_r(NULL, sepstr, &tmp) != NULL) 326 return (MNT_TOOMANY); 327 328 return (0); 329 } 330