1/*-
2 * Copyright (c) 2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27/*
28 * This file implements Solaris compatible getmntany() and hasmntopt()
29 * functions.
30 */
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD: releng/10.3/cddl/compat/opensolaris/misc/mnttab.c 209962 2010-07-12 23:49:04Z mm $");
34
35#include <sys/param.h>
36#include <sys/mount.h>
37#include <sys/mntent.h>
38#include <sys/mnttab.h>
39
40#include <ctype.h>
41#include <errno.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45
46static char *
47mntopt(char **p)
48{
49	char *cp = *p;
50	char *retstr;
51
52	while (*cp && isspace(*cp))
53		cp++;
54
55	retstr = cp;
56	while (*cp && *cp != ',')
57		cp++;
58
59	if (*cp) {
60		*cp = '\0';
61		cp++;
62	}
63
64	*p = cp;
65	return (retstr);
66}
67
68char *
69hasmntopt(struct mnttab *mnt, char *opt)
70{
71	char tmpopts[MNT_LINE_MAX];
72	char *f, *opts = tmpopts;
73
74	if (mnt->mnt_mntopts == NULL)
75		return (NULL);
76	(void) strcpy(opts, mnt->mnt_mntopts);
77	f = mntopt(&opts);
78	for (; *f; f = mntopt(&opts)) {
79		if (strncmp(opt, f, strlen(opt)) == 0)
80			return (f - tmpopts + mnt->mnt_mntopts);
81	}
82	return (NULL);
83}
84
85static void
86optadd(char *mntopts, size_t size, const char *opt)
87{
88
89	if (mntopts[0] != '\0')
90		strlcat(mntopts, ",", size);
91	strlcat(mntopts, opt, size);
92}
93
94void
95statfs2mnttab(struct statfs *sfs, struct mnttab *mp)
96{
97	static char mntopts[MNTMAXSTR];
98	long flags;
99
100	mntopts[0] = '\0';
101
102	flags = sfs->f_flags;
103#define	OPTADD(opt)	optadd(mntopts, sizeof(mntopts), (opt))
104	if (flags & MNT_RDONLY)
105		OPTADD(MNTOPT_RO);
106	else
107		OPTADD(MNTOPT_RW);
108	if (flags & MNT_NOSUID)
109		OPTADD(MNTOPT_NOSUID);
110	else
111		OPTADD(MNTOPT_SETUID);
112	if (flags & MNT_UPDATE)
113		OPTADD(MNTOPT_REMOUNT);
114	if (flags & MNT_NOATIME)
115		OPTADD(MNTOPT_NOATIME);
116	else
117		OPTADD(MNTOPT_ATIME);
118	OPTADD(MNTOPT_NOXATTR);
119	if (flags & MNT_NOEXEC)
120		OPTADD(MNTOPT_NOEXEC);
121	else
122		OPTADD(MNTOPT_EXEC);
123#undef	OPTADD
124	mp->mnt_special = sfs->f_mntfromname;
125	mp->mnt_mountp = sfs->f_mntonname;
126	mp->mnt_fstype = sfs->f_fstypename;
127	mp->mnt_mntopts = mntopts;
128}
129
130static struct statfs *gsfs = NULL;
131static int allfs = 0;
132
133static int
134statfs_init(void)
135{
136	struct statfs *sfs;
137	int error;
138
139	if (gsfs != NULL) {
140		free(gsfs);
141		gsfs = NULL;
142	}
143	allfs = getfsstat(NULL, 0, MNT_WAIT);
144	if (allfs == -1)
145		goto fail;
146	gsfs = malloc(sizeof(gsfs[0]) * allfs * 2);
147	if (gsfs == NULL)
148		goto fail;
149	allfs = getfsstat(gsfs, (long)(sizeof(gsfs[0]) * allfs * 2),
150	    MNT_WAIT);
151	if (allfs == -1)
152		goto fail;
153	sfs = realloc(gsfs, allfs * sizeof(gsfs[0]));
154	if (sfs != NULL)
155		gsfs = sfs;
156	return (0);
157fail:
158	error = errno;
159	if (gsfs != NULL)
160		free(gsfs);
161	gsfs = NULL;
162	allfs = 0;
163	return (error);
164}
165
166int
167getmntany(FILE *fd __unused, struct mnttab *mgetp, struct mnttab *mrefp)
168{
169	struct statfs *sfs;
170	int i, error;
171
172	error = statfs_init();
173	if (error != 0)
174		return (error);
175
176	for (i = 0; i < allfs; i++) {
177		if (mrefp->mnt_special != NULL &&
178		    strcmp(mrefp->mnt_special, gsfs[i].f_mntfromname) != 0) {
179			continue;
180		}
181		if (mrefp->mnt_mountp != NULL &&
182		    strcmp(mrefp->mnt_mountp, gsfs[i].f_mntonname) != 0) {
183			continue;
184		}
185		if (mrefp->mnt_fstype != NULL &&
186		    strcmp(mrefp->mnt_fstype, gsfs[i].f_fstypename) != 0) {
187			continue;
188		}
189		statfs2mnttab(&gsfs[i], mgetp);
190		return (0);
191	}
192	return (-1);
193}
194
195int
196getmntent(FILE *fp, struct mnttab *mp)
197{
198	struct statfs *sfs;
199	int error, nfs;
200
201	nfs = (int)lseek(fileno(fp), 0, SEEK_CUR);
202	if (nfs == -1)
203		return (errno);
204	/* If nfs is 0, we want to refresh out cache. */
205	if (nfs == 0 || gsfs == NULL) {
206		error = statfs_init();
207		if (error != 0)
208			return (error);
209	}
210	if (nfs >= allfs)
211		return (-1);
212	statfs2mnttab(&gsfs[nfs], mp);
213	if (lseek(fileno(fp), 1, SEEK_CUR) == -1)
214		return (errno);
215	return (0);
216}
217