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*6812Sraf * Copyright 2008 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 30*6812Sraf #pragma ident "%Z%%M% %I% %E% SMI" 310Sstevel@tonic-gate 32*6812Sraf #include "lint.h" 330Sstevel@tonic-gate #include <mtlib.h> 340Sstevel@tonic-gate #include <stdio.h> 350Sstevel@tonic-gate #include <sys/types.h> 360Sstevel@tonic-gate #include <sys/stat.h> 370Sstevel@tonic-gate #include <sys/mnttab.h> 380Sstevel@tonic-gate #include <sys/mntio.h> 390Sstevel@tonic-gate #include <string.h> 400Sstevel@tonic-gate #include <ctype.h> 410Sstevel@tonic-gate #include <errno.h> 420Sstevel@tonic-gate #include <stdlib.h> 430Sstevel@tonic-gate #include <thread.h> 440Sstevel@tonic-gate #include <synch.h> 450Sstevel@tonic-gate #include <libc.h> 460Sstevel@tonic-gate #include <unistd.h> 470Sstevel@tonic-gate #include "tsd.h" 480Sstevel@tonic-gate 490Sstevel@tonic-gate static int getmntent_compat(FILE *fp, struct mnttab *mp); 500Sstevel@tonic-gate static int convert_mntent(struct extmnttab *, struct extmnttab *, int); 510Sstevel@tonic-gate 520Sstevel@tonic-gate #define GETTOK_R(xx, ll, tmp)\ 530Sstevel@tonic-gate if ((mp->xx = (char *)strtok_r(ll, sepstr, tmp)) == NULL)\ 540Sstevel@tonic-gate return (MNT_TOOFEW);\ 550Sstevel@tonic-gate if (strcmp(mp->xx, dash) == 0)\ 560Sstevel@tonic-gate mp->xx = NULL 570Sstevel@tonic-gate 580Sstevel@tonic-gate #define DIFF(xx)\ 590Sstevel@tonic-gate (mrefp->xx != NULL && (mgetp->xx == NULL ||\ 600Sstevel@tonic-gate strcmp(mrefp->xx, mgetp->xx) != 0)) 610Sstevel@tonic-gate 620Sstevel@tonic-gate #define SDIFF(xx, typem, typer)\ 630Sstevel@tonic-gate ((mgetp->xx == NULL) || (stat64(mgetp->xx, &statb) == -1) ||\ 640Sstevel@tonic-gate ((statb.st_mode & S_IFMT) != typem) ||\ 650Sstevel@tonic-gate (statb.st_rdev != typer)) 660Sstevel@tonic-gate 670Sstevel@tonic-gate static const char sepstr[] = " \t\n"; 680Sstevel@tonic-gate static const char dash[] = "-"; 690Sstevel@tonic-gate 700Sstevel@tonic-gate typedef struct { 710Sstevel@tonic-gate size_t buflen; 720Sstevel@tonic-gate char *buf; 730Sstevel@tonic-gate } thread_data_t; 740Sstevel@tonic-gate 750Sstevel@tonic-gate static void 760Sstevel@tonic-gate destroy_thread_data(void *arg) 770Sstevel@tonic-gate { 780Sstevel@tonic-gate thread_data_t *thread_data = arg; 790Sstevel@tonic-gate 800Sstevel@tonic-gate if (thread_data->buf != NULL) { 810Sstevel@tonic-gate free(thread_data->buf); 820Sstevel@tonic-gate thread_data->buf = NULL; 830Sstevel@tonic-gate } 840Sstevel@tonic-gate thread_data->buflen = 0; 850Sstevel@tonic-gate } 860Sstevel@tonic-gate 870Sstevel@tonic-gate static char * 880Sstevel@tonic-gate getmntbuf(size_t size) 890Sstevel@tonic-gate { 900Sstevel@tonic-gate thread_data_t *thread_data; 910Sstevel@tonic-gate 920Sstevel@tonic-gate if (size < MNT_LINE_MAX) 930Sstevel@tonic-gate size = MNT_LINE_MAX; 940Sstevel@tonic-gate 950Sstevel@tonic-gate thread_data = tsdalloc(_T_GETMNTENT, 960Sstevel@tonic-gate sizeof (thread_data_t), destroy_thread_data); 970Sstevel@tonic-gate if (thread_data == NULL) 980Sstevel@tonic-gate return (NULL); 990Sstevel@tonic-gate if (thread_data->buf == NULL || 1000Sstevel@tonic-gate thread_data->buflen < size) { 1010Sstevel@tonic-gate if (thread_data->buf != NULL) 1020Sstevel@tonic-gate free(thread_data->buf); 1030Sstevel@tonic-gate thread_data->buflen = 0; 1040Sstevel@tonic-gate if ((thread_data->buf = malloc(size)) == NULL) 1050Sstevel@tonic-gate return (NULL); 1060Sstevel@tonic-gate thread_data->buflen = size; 1070Sstevel@tonic-gate } 1080Sstevel@tonic-gate return (thread_data->buf); 1090Sstevel@tonic-gate } 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate int 1120Sstevel@tonic-gate getmntany(FILE *fp, struct mnttab *mgetp, struct mnttab *mrefp) 1130Sstevel@tonic-gate { 1140Sstevel@tonic-gate int ret, bstat; 1150Sstevel@tonic-gate mode_t bmode; 1160Sstevel@tonic-gate dev_t brdev; 1170Sstevel@tonic-gate struct stat64 statb; 1180Sstevel@tonic-gate 119380Seschrock /* 120380Seschrock * Ignore specials that don't correspond to real devices to avoid doing 121380Seschrock * unnecessary lookups in stat64(). 122380Seschrock */ 123380Seschrock if (mrefp->mnt_special && mrefp->mnt_special[0] == '/' && 124380Seschrock stat64(mrefp->mnt_special, &statb) == 0 && 1250Sstevel@tonic-gate ((bmode = (statb.st_mode & S_IFMT)) == S_IFBLK || 1260Sstevel@tonic-gate bmode == S_IFCHR)) { 1270Sstevel@tonic-gate bstat = 1; 1280Sstevel@tonic-gate brdev = statb.st_rdev; 1290Sstevel@tonic-gate } else { 1300Sstevel@tonic-gate bstat = 0; 1310Sstevel@tonic-gate } 1320Sstevel@tonic-gate 1330Sstevel@tonic-gate while ((ret = getmntent(fp, mgetp)) == 0 && 1340Sstevel@tonic-gate ((bstat == 0 && DIFF(mnt_special)) || 1350Sstevel@tonic-gate (bstat == 1 && SDIFF(mnt_special, bmode, brdev)) || 1360Sstevel@tonic-gate DIFF(mnt_mountp) || 1370Sstevel@tonic-gate DIFF(mnt_fstype) || 1380Sstevel@tonic-gate DIFF(mnt_mntopts) || 1390Sstevel@tonic-gate DIFF(mnt_time))) 1400Sstevel@tonic-gate ; 1410Sstevel@tonic-gate 1420Sstevel@tonic-gate return (ret); 1430Sstevel@tonic-gate } 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate int 1460Sstevel@tonic-gate getmntent(FILE *fp, struct mnttab *mp) 1470Sstevel@tonic-gate { 1480Sstevel@tonic-gate int ret; 1490Sstevel@tonic-gate struct extmnttab *emp; 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate ret = ioctl(fileno(fp), MNTIOC_GETMNTENT, &emp); 1520Sstevel@tonic-gate 1530Sstevel@tonic-gate switch (ret) { 1540Sstevel@tonic-gate case 0: 1550Sstevel@tonic-gate return (convert_mntent(emp, (struct extmnttab *)mp, 0)); 1560Sstevel@tonic-gate case 1: 1570Sstevel@tonic-gate return (-1); 1580Sstevel@tonic-gate default: 1590Sstevel@tonic-gate return (getmntent_compat(fp, mp)); 1600Sstevel@tonic-gate } 1610Sstevel@tonic-gate } 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate char * 1640Sstevel@tonic-gate mntopt(char **p) 1650Sstevel@tonic-gate { 1660Sstevel@tonic-gate char *cp = *p; 1670Sstevel@tonic-gate char *retstr; 1680Sstevel@tonic-gate 1690Sstevel@tonic-gate while (*cp && isspace(*cp)) 1700Sstevel@tonic-gate cp++; 1710Sstevel@tonic-gate 1720Sstevel@tonic-gate retstr = cp; 1730Sstevel@tonic-gate while (*cp && *cp != ',') 1740Sstevel@tonic-gate cp++; 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate if (*cp) { 1770Sstevel@tonic-gate *cp = '\0'; 1780Sstevel@tonic-gate cp++; 1790Sstevel@tonic-gate } 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate *p = cp; 1820Sstevel@tonic-gate return (retstr); 1830Sstevel@tonic-gate } 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate char * 1860Sstevel@tonic-gate hasmntopt(struct mnttab *mnt, char *opt) 1870Sstevel@tonic-gate { 1880Sstevel@tonic-gate char tmpopts[MNT_LINE_MAX]; 1890Sstevel@tonic-gate char *f, *opts = tmpopts; 1904830Skeerthi size_t len; 1910Sstevel@tonic-gate 1920Sstevel@tonic-gate if (mnt->mnt_mntopts == NULL) 1930Sstevel@tonic-gate return (NULL); 1940Sstevel@tonic-gate (void) strcpy(opts, mnt->mnt_mntopts); 1954830Skeerthi len = strlen(opt); 1960Sstevel@tonic-gate f = mntopt(&opts); 1970Sstevel@tonic-gate for (; *f; f = mntopt(&opts)) { 1984830Skeerthi /* 1994830Skeerthi * Match only complete substrings. For options 2004830Skeerthi * which use a delimiter (such as 'retry=3'), 2014830Skeerthi * treat the delimiter as the end of the substring. 2024830Skeerthi */ 2034830Skeerthi if (strncmp(opt, f, len) == 0 && 2044830Skeerthi (f[len] == '\0' || !isalnum(f[len]))) 2050Sstevel@tonic-gate return (f - tmpopts + mnt->mnt_mntopts); 2060Sstevel@tonic-gate } 2070Sstevel@tonic-gate return (NULL); 2080Sstevel@tonic-gate } 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate /*ARGSUSED*/ 2110Sstevel@tonic-gate int 2120Sstevel@tonic-gate getextmntent(FILE *fp, struct extmnttab *mp, size_t len) 2130Sstevel@tonic-gate { 2140Sstevel@tonic-gate int ret; 2150Sstevel@tonic-gate struct extmnttab *emp; 2160Sstevel@tonic-gate 2170Sstevel@tonic-gate ret = ioctl(fileno(fp), MNTIOC_GETMNTENT, &emp); 2180Sstevel@tonic-gate 2190Sstevel@tonic-gate switch (ret) { 2200Sstevel@tonic-gate case 0: 2210Sstevel@tonic-gate return (convert_mntent(emp, mp, 1)); 2220Sstevel@tonic-gate case 1: 2230Sstevel@tonic-gate return (-1); 2240Sstevel@tonic-gate default: 2250Sstevel@tonic-gate return (ret); 2260Sstevel@tonic-gate } 2270Sstevel@tonic-gate } 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate void 2300Sstevel@tonic-gate resetmnttab(FILE *fp) 2310Sstevel@tonic-gate { 2320Sstevel@tonic-gate rewind(fp); 2330Sstevel@tonic-gate } 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate /* 2360Sstevel@tonic-gate * This is a horrible function, necessary to support this broken interface. 2370Sstevel@tonic-gate * Some callers of get(ext)mntent assume that the memory is valid even after the 2380Sstevel@tonic-gate * file is closed. Since we switched to a direct ioctl() interface, this is no 2390Sstevel@tonic-gate * longer true. In order to support these apps, we have to put the data into a 2400Sstevel@tonic-gate * thread specific buffer. 2410Sstevel@tonic-gate */ 2420Sstevel@tonic-gate static int 2430Sstevel@tonic-gate convert_mntent(struct extmnttab *src, struct extmnttab *dst, int isext) 2440Sstevel@tonic-gate { 2450Sstevel@tonic-gate size_t len; 2460Sstevel@tonic-gate char *buf; 2470Sstevel@tonic-gate 2480Sstevel@tonic-gate len = src->mnt_time - src->mnt_special + strlen(src->mnt_time) + 1; 2490Sstevel@tonic-gate 2500Sstevel@tonic-gate buf = getmntbuf(len); 2510Sstevel@tonic-gate if (buf == NULL) { 2520Sstevel@tonic-gate errno = ENOMEM; 2530Sstevel@tonic-gate return (-1); 2540Sstevel@tonic-gate } 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate memcpy(buf, src->mnt_special, len); 2570Sstevel@tonic-gate dst->mnt_special = buf; 2580Sstevel@tonic-gate dst->mnt_mountp = buf + (src->mnt_mountp - src->mnt_special); 2590Sstevel@tonic-gate dst->mnt_fstype = buf + (src->mnt_fstype - src->mnt_special); 2600Sstevel@tonic-gate dst->mnt_mntopts = buf + (src->mnt_mntopts - src->mnt_special); 2610Sstevel@tonic-gate dst->mnt_time = buf + (src->mnt_time - src->mnt_special); 2620Sstevel@tonic-gate if (isext) { 2630Sstevel@tonic-gate dst->mnt_major = src->mnt_major; 2640Sstevel@tonic-gate dst->mnt_minor = src->mnt_minor; 2650Sstevel@tonic-gate } 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate return (0); 2680Sstevel@tonic-gate } 2690Sstevel@tonic-gate 2700Sstevel@tonic-gate /* 2710Sstevel@tonic-gate * Compatibility for non-mntfs files. For backwards compatibility, we continue 2720Sstevel@tonic-gate * to have to support this broken interface. Note that getextmntent() has 2730Sstevel@tonic-gate * always failed when using a file other than /etc/mnttab, because it relies on 2740Sstevel@tonic-gate * an ioctl() call. 2750Sstevel@tonic-gate */ 2760Sstevel@tonic-gate static int 2770Sstevel@tonic-gate getline(char *lp, FILE *fp) 2780Sstevel@tonic-gate { 2790Sstevel@tonic-gate char *cp; 2800Sstevel@tonic-gate 2810Sstevel@tonic-gate while ((lp = fgets(lp, MNT_LINE_MAX, fp)) != NULL) { 2820Sstevel@tonic-gate if (strlen(lp) == MNT_LINE_MAX-1 && lp[MNT_LINE_MAX-2] != '\n') 2830Sstevel@tonic-gate return (MNT_TOOLONG); 2840Sstevel@tonic-gate 2850Sstevel@tonic-gate for (cp = lp; *cp == ' ' || *cp == '\t'; cp++) 2860Sstevel@tonic-gate ; 2870Sstevel@tonic-gate 2880Sstevel@tonic-gate if (*cp != '#' && *cp != '\n') 2890Sstevel@tonic-gate return (0); 2900Sstevel@tonic-gate } 2910Sstevel@tonic-gate return (-1); 2920Sstevel@tonic-gate } 2930Sstevel@tonic-gate 2940Sstevel@tonic-gate static int 2950Sstevel@tonic-gate getmntent_compat(FILE *fp, struct mnttab *mp) 2960Sstevel@tonic-gate { 2970Sstevel@tonic-gate int ret; 2980Sstevel@tonic-gate char *tmp; 2990Sstevel@tonic-gate char *line = getmntbuf(MNT_LINE_MAX); 3000Sstevel@tonic-gate 3010Sstevel@tonic-gate if (line == NULL) { 3020Sstevel@tonic-gate errno = ENOMEM; 3030Sstevel@tonic-gate return (-1); 3040Sstevel@tonic-gate } 3050Sstevel@tonic-gate 3060Sstevel@tonic-gate /* skip leading spaces and comments */ 3070Sstevel@tonic-gate if ((ret = getline(line, fp)) != 0) 3080Sstevel@tonic-gate return (ret); 3090Sstevel@tonic-gate 3100Sstevel@tonic-gate /* split up each field */ 3110Sstevel@tonic-gate GETTOK_R(mnt_special, line, &tmp); 3120Sstevel@tonic-gate GETTOK_R(mnt_mountp, NULL, &tmp); 3130Sstevel@tonic-gate GETTOK_R(mnt_fstype, NULL, &tmp); 3140Sstevel@tonic-gate GETTOK_R(mnt_mntopts, NULL, &tmp); 3150Sstevel@tonic-gate GETTOK_R(mnt_time, NULL, &tmp); 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate /* check for too many fields */ 3180Sstevel@tonic-gate if (strtok_r(NULL, sepstr, &tmp) != NULL) 3190Sstevel@tonic-gate return (MNT_TOOMANY); 3200Sstevel@tonic-gate 3210Sstevel@tonic-gate return (0); 3220Sstevel@tonic-gate } 323