10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 54830Skeerthi * Common Development and Distribution License (the "License"). 64830Skeerthi * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 214830Skeerthi 220Sstevel@tonic-gate /* 23*10910SRobert.Harris@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate /* Copyright (c) 1988 AT&T */ 280Sstevel@tonic-gate /* All Rights Reserved */ 290Sstevel@tonic-gate 306812Sraf #include "lint.h" 310Sstevel@tonic-gate #include <mtlib.h> 320Sstevel@tonic-gate #include <stdio.h> 330Sstevel@tonic-gate #include <sys/types.h> 340Sstevel@tonic-gate #include <sys/stat.h> 350Sstevel@tonic-gate #include <sys/mnttab.h> 360Sstevel@tonic-gate #include <sys/mntio.h> 370Sstevel@tonic-gate #include <string.h> 380Sstevel@tonic-gate #include <ctype.h> 390Sstevel@tonic-gate #include <errno.h> 400Sstevel@tonic-gate #include <stdlib.h> 410Sstevel@tonic-gate #include <thread.h> 420Sstevel@tonic-gate #include <synch.h> 430Sstevel@tonic-gate #include <libc.h> 440Sstevel@tonic-gate #include <unistd.h> 450Sstevel@tonic-gate #include "tsd.h" 46*10910SRobert.Harris@Sun.COM #include <atomic.h> 47*10910SRobert.Harris@Sun.COM #include <strings.h> 480Sstevel@tonic-gate 490Sstevel@tonic-gate static int getmntent_compat(FILE *fp, struct mnttab *mp); 500Sstevel@tonic-gate 510Sstevel@tonic-gate #define GETTOK_R(xx, ll, tmp)\ 520Sstevel@tonic-gate if ((mp->xx = (char *)strtok_r(ll, sepstr, tmp)) == NULL)\ 530Sstevel@tonic-gate return (MNT_TOOFEW);\ 540Sstevel@tonic-gate if (strcmp(mp->xx, dash) == 0)\ 550Sstevel@tonic-gate mp->xx = NULL 560Sstevel@tonic-gate 570Sstevel@tonic-gate #define DIFF(xx)\ 580Sstevel@tonic-gate (mrefp->xx != NULL && (mgetp->xx == NULL ||\ 590Sstevel@tonic-gate strcmp(mrefp->xx, mgetp->xx) != 0)) 600Sstevel@tonic-gate 610Sstevel@tonic-gate #define SDIFF(xx, typem, typer)\ 620Sstevel@tonic-gate ((mgetp->xx == NULL) || (stat64(mgetp->xx, &statb) == -1) ||\ 630Sstevel@tonic-gate ((statb.st_mode & S_IFMT) != typem) ||\ 640Sstevel@tonic-gate (statb.st_rdev != typer)) 650Sstevel@tonic-gate 660Sstevel@tonic-gate static const char sepstr[] = " \t\n"; 670Sstevel@tonic-gate static const char dash[] = "-"; 680Sstevel@tonic-gate 690Sstevel@tonic-gate typedef struct { 700Sstevel@tonic-gate size_t buflen; 710Sstevel@tonic-gate char *buf; 720Sstevel@tonic-gate } thread_data_t; 730Sstevel@tonic-gate 740Sstevel@tonic-gate static void 750Sstevel@tonic-gate destroy_thread_data(void *arg) 760Sstevel@tonic-gate { 770Sstevel@tonic-gate thread_data_t *thread_data = arg; 780Sstevel@tonic-gate 790Sstevel@tonic-gate if (thread_data->buf != NULL) { 800Sstevel@tonic-gate free(thread_data->buf); 810Sstevel@tonic-gate thread_data->buf = NULL; 820Sstevel@tonic-gate } 830Sstevel@tonic-gate thread_data->buflen = 0; 840Sstevel@tonic-gate } 850Sstevel@tonic-gate 860Sstevel@tonic-gate static char * 870Sstevel@tonic-gate getmntbuf(size_t size) 880Sstevel@tonic-gate { 890Sstevel@tonic-gate thread_data_t *thread_data; 900Sstevel@tonic-gate 910Sstevel@tonic-gate thread_data = tsdalloc(_T_GETMNTENT, 920Sstevel@tonic-gate sizeof (thread_data_t), destroy_thread_data); 930Sstevel@tonic-gate if (thread_data == NULL) 940Sstevel@tonic-gate return (NULL); 950Sstevel@tonic-gate if (thread_data->buf == NULL || 960Sstevel@tonic-gate thread_data->buflen < size) { 970Sstevel@tonic-gate if (thread_data->buf != NULL) 980Sstevel@tonic-gate free(thread_data->buf); 990Sstevel@tonic-gate thread_data->buflen = 0; 1000Sstevel@tonic-gate if ((thread_data->buf = malloc(size)) == NULL) 1010Sstevel@tonic-gate return (NULL); 1020Sstevel@tonic-gate thread_data->buflen = size; 1030Sstevel@tonic-gate } 1040Sstevel@tonic-gate return (thread_data->buf); 1050Sstevel@tonic-gate } 1060Sstevel@tonic-gate 107*10910SRobert.Harris@Sun.COM static int 108*10910SRobert.Harris@Sun.COM getmntany_compat(FILE *fp, struct mnttab *mgetp, struct mnttab *mrefp) 1090Sstevel@tonic-gate { 1100Sstevel@tonic-gate int ret, bstat; 1110Sstevel@tonic-gate mode_t bmode; 1120Sstevel@tonic-gate dev_t brdev; 1130Sstevel@tonic-gate struct stat64 statb; 1140Sstevel@tonic-gate 115380Seschrock /* 116380Seschrock * Ignore specials that don't correspond to real devices to avoid doing 117380Seschrock * unnecessary lookups in stat64(). 118380Seschrock */ 119380Seschrock if (mrefp->mnt_special && mrefp->mnt_special[0] == '/' && 120380Seschrock stat64(mrefp->mnt_special, &statb) == 0 && 1210Sstevel@tonic-gate ((bmode = (statb.st_mode & S_IFMT)) == S_IFBLK || 1220Sstevel@tonic-gate bmode == S_IFCHR)) { 1230Sstevel@tonic-gate bstat = 1; 1240Sstevel@tonic-gate brdev = statb.st_rdev; 1250Sstevel@tonic-gate } else { 1260Sstevel@tonic-gate bstat = 0; 1270Sstevel@tonic-gate } 1280Sstevel@tonic-gate 129*10910SRobert.Harris@Sun.COM while ((ret = getmntent_compat(fp, mgetp)) == 0 && 1300Sstevel@tonic-gate ((bstat == 0 && DIFF(mnt_special)) || 1310Sstevel@tonic-gate (bstat == 1 && SDIFF(mnt_special, bmode, brdev)) || 1320Sstevel@tonic-gate DIFF(mnt_mountp) || 1330Sstevel@tonic-gate DIFF(mnt_fstype) || 1340Sstevel@tonic-gate DIFF(mnt_mntopts) || 1350Sstevel@tonic-gate DIFF(mnt_time))) 1360Sstevel@tonic-gate ; 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate return (ret); 1390Sstevel@tonic-gate } 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate int 142*10910SRobert.Harris@Sun.COM getmntany(FILE *fp, struct mnttab *mgetp, struct mnttab *mrefp) 1430Sstevel@tonic-gate { 144*10910SRobert.Harris@Sun.COM struct mntentbuf embuf; 145*10910SRobert.Harris@Sun.COM char *copyp, *bufp; 146*10910SRobert.Harris@Sun.COM int ret; 147*10910SRobert.Harris@Sun.COM 148*10910SRobert.Harris@Sun.COM 149*10910SRobert.Harris@Sun.COM /* 150*10910SRobert.Harris@Sun.COM * We collect all of the text strings pointed to by members of the 151*10910SRobert.Harris@Sun.COM * user's preferences struct into a single buffer. At the same time 152*10910SRobert.Harris@Sun.COM * populate the members of the results struct to point to the 153*10910SRobert.Harris@Sun.COM * corresponding words. We then ask the kernel to figure out the 154*10910SRobert.Harris@Sun.COM * rest; if this is a non-mntfs file then we handover to 155*10910SRobert.Harris@Sun.COM * getmntany_compat(). 156*10910SRobert.Harris@Sun.COM */ 157*10910SRobert.Harris@Sun.COM if ((copyp = bufp = getmntbuf(MNT_LINE_MAX)) == NULL) { 158*10910SRobert.Harris@Sun.COM errno = ENOMEM; 159*10910SRobert.Harris@Sun.COM return (-1); 160*10910SRobert.Harris@Sun.COM } 161*10910SRobert.Harris@Sun.COM bzero(mgetp, sizeof (struct mnttab)); 162*10910SRobert.Harris@Sun.COM if (mrefp->mnt_special) { 163*10910SRobert.Harris@Sun.COM mgetp->mnt_special = copyp; 164*10910SRobert.Harris@Sun.COM copyp += snprintf(mgetp->mnt_special, MNT_LINE_MAX, "%s", 165*10910SRobert.Harris@Sun.COM mrefp->mnt_special) + 1; 166*10910SRobert.Harris@Sun.COM } 167*10910SRobert.Harris@Sun.COM if (mrefp->mnt_mountp) { 168*10910SRobert.Harris@Sun.COM mgetp->mnt_mountp = copyp; 169*10910SRobert.Harris@Sun.COM copyp += snprintf(mgetp->mnt_mountp, 170*10910SRobert.Harris@Sun.COM bufp + MNT_LINE_MAX - copyp, "%s", mrefp->mnt_mountp) + 1; 171*10910SRobert.Harris@Sun.COM } 172*10910SRobert.Harris@Sun.COM if (mrefp->mnt_fstype) { 173*10910SRobert.Harris@Sun.COM mgetp->mnt_fstype = copyp; 174*10910SRobert.Harris@Sun.COM copyp += snprintf(mgetp->mnt_fstype, 175*10910SRobert.Harris@Sun.COM bufp + MNT_LINE_MAX - copyp, "%s", mrefp->mnt_fstype) + 1; 176*10910SRobert.Harris@Sun.COM } 177*10910SRobert.Harris@Sun.COM if (mrefp->mnt_mntopts) { 178*10910SRobert.Harris@Sun.COM mgetp->mnt_mntopts = copyp; 179*10910SRobert.Harris@Sun.COM copyp += snprintf(mgetp->mnt_mntopts, 180*10910SRobert.Harris@Sun.COM bufp + MNT_LINE_MAX - copyp, "%s", mrefp->mnt_mntopts) + 1; 181*10910SRobert.Harris@Sun.COM } 182*10910SRobert.Harris@Sun.COM if (mrefp->mnt_time) { 183*10910SRobert.Harris@Sun.COM mgetp->mnt_time = copyp; 184*10910SRobert.Harris@Sun.COM (void) snprintf(mgetp->mnt_time, bufp + MNT_LINE_MAX - copyp, 185*10910SRobert.Harris@Sun.COM "%s", mrefp->mnt_time); 186*10910SRobert.Harris@Sun.COM } 187*10910SRobert.Harris@Sun.COM 188*10910SRobert.Harris@Sun.COM embuf.mbuf_emp = (struct extmnttab *)mgetp; 189*10910SRobert.Harris@Sun.COM embuf.mbuf_bufsize = MNT_LINE_MAX; 190*10910SRobert.Harris@Sun.COM embuf.mbuf_buf = bufp; 1910Sstevel@tonic-gate 192*10910SRobert.Harris@Sun.COM switch (ret = ioctl(fileno(fp), MNTIOC_GETMNTANY, &embuf)) { 193*10910SRobert.Harris@Sun.COM case 0: 194*10910SRobert.Harris@Sun.COM /* Success. */ 195*10910SRobert.Harris@Sun.COM return (0); 196*10910SRobert.Harris@Sun.COM case MNTFS_EOF: 197*10910SRobert.Harris@Sun.COM return (-1); 198*10910SRobert.Harris@Sun.COM case MNTFS_TOOLONG: 199*10910SRobert.Harris@Sun.COM return (MNT_TOOLONG); 200*10910SRobert.Harris@Sun.COM default: 201*10910SRobert.Harris@Sun.COM /* A failure of some kind. */ 202*10910SRobert.Harris@Sun.COM if (errno == ENOTTY) 203*10910SRobert.Harris@Sun.COM return (getmntany_compat(fp, mgetp, mrefp)); 204*10910SRobert.Harris@Sun.COM else 205*10910SRobert.Harris@Sun.COM return (ret); 206*10910SRobert.Harris@Sun.COM } 207*10910SRobert.Harris@Sun.COM } 208*10910SRobert.Harris@Sun.COM 209*10910SRobert.Harris@Sun.COM /* 210*10910SRobert.Harris@Sun.COM * Common code for getmntent() and getextmntent(). 211*10910SRobert.Harris@Sun.COM * 212*10910SRobert.Harris@Sun.COM * These functions serve to populate a structure supplied by the user. Common 213*10910SRobert.Harris@Sun.COM * to both struct mnttab and struct extmnttab is a set of pointers to the 214*10910SRobert.Harris@Sun.COM * individual text fields that form an entry in /etc/mnttab. We arrange for the 215*10910SRobert.Harris@Sun.COM * text itself to be stored in some thread-local storage, and for the kernel to 216*10910SRobert.Harris@Sun.COM * populate both this buffer and the structure directly. 217*10910SRobert.Harris@Sun.COM * 218*10910SRobert.Harris@Sun.COM * If getmntent() passes a file that isn't provided by mntfs then we assume that 219*10910SRobert.Harris@Sun.COM * it is a simple text file and give it to getmntent_compat() to parse. For 220*10910SRobert.Harris@Sun.COM * getextmntent() we give up; it requires major and minor numbers that only the 221*10910SRobert.Harris@Sun.COM * kernel can provide. 222*10910SRobert.Harris@Sun.COM */ 223*10910SRobert.Harris@Sun.COM static int 224*10910SRobert.Harris@Sun.COM getmntent_common(FILE *fp, struct extmnttab *emp, int command) 225*10910SRobert.Harris@Sun.COM { 226*10910SRobert.Harris@Sun.COM struct mntentbuf embuf; 227*10910SRobert.Harris@Sun.COM static size_t bufsize = MNT_LINE_MAX; 228*10910SRobert.Harris@Sun.COM int ret; 229*10910SRobert.Harris@Sun.COM 230*10910SRobert.Harris@Sun.COM embuf.mbuf_emp = emp; 231*10910SRobert.Harris@Sun.COM embuf.mbuf_bufsize = bufsize; 232*10910SRobert.Harris@Sun.COM if ((embuf.mbuf_buf = getmntbuf(embuf.mbuf_bufsize)) == NULL) { 233*10910SRobert.Harris@Sun.COM errno = ENOMEM; 234*10910SRobert.Harris@Sun.COM return (-1); 235*10910SRobert.Harris@Sun.COM } 236*10910SRobert.Harris@Sun.COM 237*10910SRobert.Harris@Sun.COM while ((ret = ioctl(fileno(fp), command, &embuf)) == MNTFS_TOOLONG) { 238*10910SRobert.Harris@Sun.COM /* The buffer wasn't large enough. */ 239*10910SRobert.Harris@Sun.COM (void) atomic_swap_ulong((unsigned long *)&bufsize, 240*10910SRobert.Harris@Sun.COM 2 * embuf.mbuf_bufsize); 241*10910SRobert.Harris@Sun.COM embuf.mbuf_bufsize = bufsize; 242*10910SRobert.Harris@Sun.COM if ((embuf.mbuf_buf = getmntbuf(embuf.mbuf_bufsize)) == NULL) { 243*10910SRobert.Harris@Sun.COM errno = ENOMEM; 244*10910SRobert.Harris@Sun.COM return (-1); 245*10910SRobert.Harris@Sun.COM } 246*10910SRobert.Harris@Sun.COM } 2470Sstevel@tonic-gate 2480Sstevel@tonic-gate switch (ret) { 249*10910SRobert.Harris@Sun.COM case 0: 250*10910SRobert.Harris@Sun.COM /* 251*10910SRobert.Harris@Sun.COM * We were successful, but we may have to enforce getmntent()'s 252*10910SRobert.Harris@Sun.COM * documented limit on the line length. 253*10910SRobert.Harris@Sun.COM */ 254*10910SRobert.Harris@Sun.COM if (command == MNTIOC_GETMNTENT && 255*10910SRobert.Harris@Sun.COM (emp->mnt_time + strlen(emp->mnt_time) + 1 - 256*10910SRobert.Harris@Sun.COM emp->mnt_special > MNT_LINE_MAX)) 257*10910SRobert.Harris@Sun.COM return (MNT_TOOLONG); 258*10910SRobert.Harris@Sun.COM else 259*10910SRobert.Harris@Sun.COM return (0); 260*10910SRobert.Harris@Sun.COM case MNTFS_EOF: 261*10910SRobert.Harris@Sun.COM /* EOF. */ 262*10910SRobert.Harris@Sun.COM return (-1); 263*10910SRobert.Harris@Sun.COM default: 264*10910SRobert.Harris@Sun.COM /* A non-mntfs file. */ 265*10910SRobert.Harris@Sun.COM if (command == MNTIOC_GETMNTENT) 266*10910SRobert.Harris@Sun.COM return (getmntent_compat(fp, (struct mnttab *)emp)); 267*10910SRobert.Harris@Sun.COM else 268*10910SRobert.Harris@Sun.COM return (ret); 2690Sstevel@tonic-gate } 2700Sstevel@tonic-gate } 2710Sstevel@tonic-gate 272*10910SRobert.Harris@Sun.COM int 273*10910SRobert.Harris@Sun.COM getmntent(FILE *fp, struct mnttab *mp) 274*10910SRobert.Harris@Sun.COM { 275*10910SRobert.Harris@Sun.COM return (getmntent_common(fp, (struct extmnttab *)mp, MNTIOC_GETMNTENT)); 276*10910SRobert.Harris@Sun.COM } 277*10910SRobert.Harris@Sun.COM 278*10910SRobert.Harris@Sun.COM /*ARGSUSED*/ 279*10910SRobert.Harris@Sun.COM int 280*10910SRobert.Harris@Sun.COM getextmntent(FILE *fp, struct extmnttab *emp, size_t len) 281*10910SRobert.Harris@Sun.COM { 282*10910SRobert.Harris@Sun.COM return (getmntent_common(fp, emp, MNTIOC_GETEXTMNTENT)); 283*10910SRobert.Harris@Sun.COM } 284*10910SRobert.Harris@Sun.COM 2850Sstevel@tonic-gate char * 2860Sstevel@tonic-gate mntopt(char **p) 2870Sstevel@tonic-gate { 2880Sstevel@tonic-gate char *cp = *p; 2890Sstevel@tonic-gate char *retstr; 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate while (*cp && isspace(*cp)) 2920Sstevel@tonic-gate cp++; 2930Sstevel@tonic-gate 2940Sstevel@tonic-gate retstr = cp; 2950Sstevel@tonic-gate while (*cp && *cp != ',') 2960Sstevel@tonic-gate cp++; 2970Sstevel@tonic-gate 2980Sstevel@tonic-gate if (*cp) { 2990Sstevel@tonic-gate *cp = '\0'; 3000Sstevel@tonic-gate cp++; 3010Sstevel@tonic-gate } 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate *p = cp; 3040Sstevel@tonic-gate return (retstr); 3050Sstevel@tonic-gate } 3060Sstevel@tonic-gate 3070Sstevel@tonic-gate char * 3080Sstevel@tonic-gate hasmntopt(struct mnttab *mnt, char *opt) 3090Sstevel@tonic-gate { 3100Sstevel@tonic-gate char tmpopts[MNT_LINE_MAX]; 3110Sstevel@tonic-gate char *f, *opts = tmpopts; 3124830Skeerthi size_t len; 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate if (mnt->mnt_mntopts == NULL) 3150Sstevel@tonic-gate return (NULL); 3160Sstevel@tonic-gate (void) strcpy(opts, mnt->mnt_mntopts); 3174830Skeerthi len = strlen(opt); 3180Sstevel@tonic-gate f = mntopt(&opts); 3190Sstevel@tonic-gate for (; *f; f = mntopt(&opts)) { 3204830Skeerthi /* 3214830Skeerthi * Match only complete substrings. For options 3224830Skeerthi * which use a delimiter (such as 'retry=3'), 3234830Skeerthi * treat the delimiter as the end of the substring. 3244830Skeerthi */ 3254830Skeerthi if (strncmp(opt, f, len) == 0 && 3264830Skeerthi (f[len] == '\0' || !isalnum(f[len]))) 3270Sstevel@tonic-gate return (f - tmpopts + mnt->mnt_mntopts); 3280Sstevel@tonic-gate } 3290Sstevel@tonic-gate return (NULL); 3300Sstevel@tonic-gate } 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate void 3330Sstevel@tonic-gate resetmnttab(FILE *fp) 3340Sstevel@tonic-gate { 3350Sstevel@tonic-gate rewind(fp); 3360Sstevel@tonic-gate } 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate /* 3390Sstevel@tonic-gate * Compatibility for non-mntfs files. For backwards compatibility, we continue 3400Sstevel@tonic-gate * to have to support this broken interface. Note that getextmntent() has 3410Sstevel@tonic-gate * always failed when using a file other than /etc/mnttab, because it relies on 3420Sstevel@tonic-gate * an ioctl() call. 3430Sstevel@tonic-gate */ 3440Sstevel@tonic-gate static int 3450Sstevel@tonic-gate getline(char *lp, FILE *fp) 3460Sstevel@tonic-gate { 3470Sstevel@tonic-gate char *cp; 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate while ((lp = fgets(lp, MNT_LINE_MAX, fp)) != NULL) { 3500Sstevel@tonic-gate if (strlen(lp) == MNT_LINE_MAX-1 && lp[MNT_LINE_MAX-2] != '\n') 3510Sstevel@tonic-gate return (MNT_TOOLONG); 3520Sstevel@tonic-gate 3530Sstevel@tonic-gate for (cp = lp; *cp == ' ' || *cp == '\t'; cp++) 3540Sstevel@tonic-gate ; 3550Sstevel@tonic-gate 3560Sstevel@tonic-gate if (*cp != '#' && *cp != '\n') 3570Sstevel@tonic-gate return (0); 3580Sstevel@tonic-gate } 3590Sstevel@tonic-gate return (-1); 3600Sstevel@tonic-gate } 3610Sstevel@tonic-gate 3620Sstevel@tonic-gate static int 3630Sstevel@tonic-gate getmntent_compat(FILE *fp, struct mnttab *mp) 3640Sstevel@tonic-gate { 3650Sstevel@tonic-gate int ret; 3660Sstevel@tonic-gate char *tmp; 3670Sstevel@tonic-gate char *line = getmntbuf(MNT_LINE_MAX); 3680Sstevel@tonic-gate 3690Sstevel@tonic-gate if (line == NULL) { 3700Sstevel@tonic-gate errno = ENOMEM; 3710Sstevel@tonic-gate return (-1); 3720Sstevel@tonic-gate } 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate /* skip leading spaces and comments */ 3750Sstevel@tonic-gate if ((ret = getline(line, fp)) != 0) 3760Sstevel@tonic-gate return (ret); 3770Sstevel@tonic-gate 3780Sstevel@tonic-gate /* split up each field */ 3790Sstevel@tonic-gate GETTOK_R(mnt_special, line, &tmp); 3800Sstevel@tonic-gate GETTOK_R(mnt_mountp, NULL, &tmp); 3810Sstevel@tonic-gate GETTOK_R(mnt_fstype, NULL, &tmp); 3820Sstevel@tonic-gate GETTOK_R(mnt_mntopts, NULL, &tmp); 3830Sstevel@tonic-gate GETTOK_R(mnt_time, NULL, &tmp); 3840Sstevel@tonic-gate 3850Sstevel@tonic-gate /* check for too many fields */ 3860Sstevel@tonic-gate if (strtok_r(NULL, sepstr, &tmp) != NULL) 3870Sstevel@tonic-gate return (MNT_TOOMANY); 3880Sstevel@tonic-gate 3890Sstevel@tonic-gate return (0); 3900Sstevel@tonic-gate } 391