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 2004 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 if (mrefp->mnt_special && stat64(mrefp->mnt_special, &statb) == 0 && 127 ((bmode = (statb.st_mode & S_IFMT)) == S_IFBLK || 128 bmode == S_IFCHR)) { 129 bstat = 1; 130 brdev = statb.st_rdev; 131 } else { 132 bstat = 0; 133 } 134 135 while ((ret = getmntent(fp, mgetp)) == 0 && 136 ((bstat == 0 && DIFF(mnt_special)) || 137 (bstat == 1 && SDIFF(mnt_special, bmode, brdev)) || 138 DIFF(mnt_mountp) || 139 DIFF(mnt_fstype) || 140 DIFF(mnt_mntopts) || 141 DIFF(mnt_time))) 142 ; 143 144 return (ret); 145 } 146 147 int 148 getmntent(FILE *fp, struct mnttab *mp) 149 { 150 int ret; 151 struct extmnttab *emp; 152 153 ret = ioctl(fileno(fp), MNTIOC_GETMNTENT, &emp); 154 155 switch (ret) { 156 case 0: 157 return (convert_mntent(emp, (struct extmnttab *)mp, 0)); 158 case 1: 159 return (-1); 160 default: 161 return (getmntent_compat(fp, mp)); 162 } 163 } 164 165 char * 166 mntopt(char **p) 167 { 168 char *cp = *p; 169 char *retstr; 170 171 while (*cp && isspace(*cp)) 172 cp++; 173 174 retstr = cp; 175 while (*cp && *cp != ',') 176 cp++; 177 178 if (*cp) { 179 *cp = '\0'; 180 cp++; 181 } 182 183 *p = cp; 184 return (retstr); 185 } 186 187 char * 188 hasmntopt(struct mnttab *mnt, char *opt) 189 { 190 char tmpopts[MNT_LINE_MAX]; 191 char *f, *opts = tmpopts; 192 193 if (mnt->mnt_mntopts == NULL) 194 return (NULL); 195 (void) strcpy(opts, mnt->mnt_mntopts); 196 f = mntopt(&opts); 197 for (; *f; f = mntopt(&opts)) { 198 if (strncmp(opt, f, strlen(opt)) == 0) 199 return (f - tmpopts + mnt->mnt_mntopts); 200 } 201 return (NULL); 202 } 203 204 /*ARGSUSED*/ 205 int 206 getextmntent(FILE *fp, struct extmnttab *mp, size_t len) 207 { 208 int ret; 209 struct extmnttab *emp; 210 211 ret = ioctl(fileno(fp), MNTIOC_GETMNTENT, &emp); 212 213 switch (ret) { 214 case 0: 215 return (convert_mntent(emp, mp, 1)); 216 case 1: 217 return (-1); 218 default: 219 return (ret); 220 } 221 } 222 223 void 224 resetmnttab(FILE *fp) 225 { 226 rewind(fp); 227 } 228 229 /* 230 * This is a horrible function, necessary to support this broken interface. 231 * Some callers of get(ext)mntent assume that the memory is valid even after the 232 * file is closed. Since we switched to a direct ioctl() interface, this is no 233 * longer true. In order to support these apps, we have to put the data into a 234 * thread specific buffer. 235 */ 236 static int 237 convert_mntent(struct extmnttab *src, struct extmnttab *dst, int isext) 238 { 239 size_t len; 240 char *buf; 241 242 len = src->mnt_time - src->mnt_special + strlen(src->mnt_time) + 1; 243 244 buf = getmntbuf(len); 245 if (buf == NULL) { 246 errno = ENOMEM; 247 return (-1); 248 } 249 250 memcpy(buf, src->mnt_special, len); 251 dst->mnt_special = buf; 252 dst->mnt_mountp = buf + (src->mnt_mountp - src->mnt_special); 253 dst->mnt_fstype = buf + (src->mnt_fstype - src->mnt_special); 254 dst->mnt_mntopts = buf + (src->mnt_mntopts - src->mnt_special); 255 dst->mnt_time = buf + (src->mnt_time - src->mnt_special); 256 if (isext) { 257 dst->mnt_major = src->mnt_major; 258 dst->mnt_minor = src->mnt_minor; 259 } 260 261 return (0); 262 } 263 264 /* 265 * Compatibility for non-mntfs files. For backwards compatibility, we continue 266 * to have to support this broken interface. Note that getextmntent() has 267 * always failed when using a file other than /etc/mnttab, because it relies on 268 * an ioctl() call. 269 */ 270 static int 271 getline(char *lp, FILE *fp) 272 { 273 char *cp; 274 275 while ((lp = fgets(lp, MNT_LINE_MAX, fp)) != NULL) { 276 if (strlen(lp) == MNT_LINE_MAX-1 && lp[MNT_LINE_MAX-2] != '\n') 277 return (MNT_TOOLONG); 278 279 for (cp = lp; *cp == ' ' || *cp == '\t'; cp++) 280 ; 281 282 if (*cp != '#' && *cp != '\n') 283 return (0); 284 } 285 return (-1); 286 } 287 288 static int 289 getmntent_compat(FILE *fp, struct mnttab *mp) 290 { 291 int ret; 292 char *tmp; 293 char *line = getmntbuf(MNT_LINE_MAX); 294 295 if (line == NULL) { 296 errno = ENOMEM; 297 return (-1); 298 } 299 300 /* skip leading spaces and comments */ 301 if ((ret = getline(line, fp)) != 0) 302 return (ret); 303 304 /* split up each field */ 305 GETTOK_R(mnt_special, line, &tmp); 306 GETTOK_R(mnt_mountp, NULL, &tmp); 307 GETTOK_R(mnt_fstype, NULL, &tmp); 308 GETTOK_R(mnt_mntopts, NULL, &tmp); 309 GETTOK_R(mnt_time, NULL, &tmp); 310 311 /* check for too many fields */ 312 if (strtok_r(NULL, sepstr, &tmp) != NULL) 313 return (MNT_TOOMANY); 314 315 return (0); 316 } 317