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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 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 198 if (mnt->mnt_mntopts == NULL) 199 return (NULL); 200 (void) strcpy(opts, mnt->mnt_mntopts); 201 f = mntopt(&opts); 202 for (; *f; f = mntopt(&opts)) { 203 if (strncmp(opt, f, strlen(opt)) == 0) 204 return (f - tmpopts + mnt->mnt_mntopts); 205 } 206 return (NULL); 207 } 208 209 /*ARGSUSED*/ 210 int 211 getextmntent(FILE *fp, struct extmnttab *mp, size_t len) 212 { 213 int ret; 214 struct extmnttab *emp; 215 216 ret = ioctl(fileno(fp), MNTIOC_GETMNTENT, &emp); 217 218 switch (ret) { 219 case 0: 220 return (convert_mntent(emp, mp, 1)); 221 case 1: 222 return (-1); 223 default: 224 return (ret); 225 } 226 } 227 228 void 229 resetmnttab(FILE *fp) 230 { 231 rewind(fp); 232 } 233 234 /* 235 * This is a horrible function, necessary to support this broken interface. 236 * Some callers of get(ext)mntent assume that the memory is valid even after the 237 * file is closed. Since we switched to a direct ioctl() interface, this is no 238 * longer true. In order to support these apps, we have to put the data into a 239 * thread specific buffer. 240 */ 241 static int 242 convert_mntent(struct extmnttab *src, struct extmnttab *dst, int isext) 243 { 244 size_t len; 245 char *buf; 246 247 len = src->mnt_time - src->mnt_special + strlen(src->mnt_time) + 1; 248 249 buf = getmntbuf(len); 250 if (buf == NULL) { 251 errno = ENOMEM; 252 return (-1); 253 } 254 255 memcpy(buf, src->mnt_special, len); 256 dst->mnt_special = buf; 257 dst->mnt_mountp = buf + (src->mnt_mountp - src->mnt_special); 258 dst->mnt_fstype = buf + (src->mnt_fstype - src->mnt_special); 259 dst->mnt_mntopts = buf + (src->mnt_mntopts - src->mnt_special); 260 dst->mnt_time = buf + (src->mnt_time - src->mnt_special); 261 if (isext) { 262 dst->mnt_major = src->mnt_major; 263 dst->mnt_minor = src->mnt_minor; 264 } 265 266 return (0); 267 } 268 269 /* 270 * Compatibility for non-mntfs files. For backwards compatibility, we continue 271 * to have to support this broken interface. Note that getextmntent() has 272 * always failed when using a file other than /etc/mnttab, because it relies on 273 * an ioctl() call. 274 */ 275 static int 276 getline(char *lp, FILE *fp) 277 { 278 char *cp; 279 280 while ((lp = fgets(lp, MNT_LINE_MAX, fp)) != NULL) { 281 if (strlen(lp) == MNT_LINE_MAX-1 && lp[MNT_LINE_MAX-2] != '\n') 282 return (MNT_TOOLONG); 283 284 for (cp = lp; *cp == ' ' || *cp == '\t'; cp++) 285 ; 286 287 if (*cp != '#' && *cp != '\n') 288 return (0); 289 } 290 return (-1); 291 } 292 293 static int 294 getmntent_compat(FILE *fp, struct mnttab *mp) 295 { 296 int ret; 297 char *tmp; 298 char *line = getmntbuf(MNT_LINE_MAX); 299 300 if (line == NULL) { 301 errno = ENOMEM; 302 return (-1); 303 } 304 305 /* skip leading spaces and comments */ 306 if ((ret = getline(line, fp)) != 0) 307 return (ret); 308 309 /* split up each field */ 310 GETTOK_R(mnt_special, line, &tmp); 311 GETTOK_R(mnt_mountp, NULL, &tmp); 312 GETTOK_R(mnt_fstype, NULL, &tmp); 313 GETTOK_R(mnt_mntopts, NULL, &tmp); 314 GETTOK_R(mnt_time, NULL, &tmp); 315 316 /* check for too many fields */ 317 if (strtok_r(NULL, sepstr, &tmp) != NULL) 318 return (MNT_TOOMANY); 319 320 return (0); 321 } 322