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