1168404Spjd/*-
2168404Spjd * Copyright (c) 2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3168404Spjd * All rights reserved.
4168404Spjd *
5168404Spjd * Redistribution and use in source and binary forms, with or without
6168404Spjd * modification, are permitted provided that the following conditions
7168404Spjd * are met:
8168404Spjd * 1. Redistributions of source code must retain the above copyright
9168404Spjd *    notice, this list of conditions and the following disclaimer.
10168404Spjd * 2. Redistributions in binary form must reproduce the above copyright
11168404Spjd *    notice, this list of conditions and the following disclaimer in the
12168404Spjd *    documentation and/or other materials provided with the distribution.
13168404Spjd *
14168404Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15168404Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16168404Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17168404Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18168404Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19168404Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20168404Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21168404Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22168404Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23168404Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24168404Spjd * SUCH DAMAGE.
25168404Spjd */
26168404Spjd
27168404Spjd/*
28168404Spjd * This file implements Solaris compatible getmntany() and hasmntopt()
29168404Spjd * functions.
30168404Spjd */
31168404Spjd
32168404Spjd#include <sys/cdefs.h>
33168404Spjd__FBSDID("$FreeBSD$");
34168404Spjd
35168404Spjd#include <sys/param.h>
36168404Spjd#include <sys/mount.h>
37168404Spjd#include <sys/mntent.h>
38168404Spjd#include <sys/mnttab.h>
39209962Smm
40209962Smm#include <ctype.h>
41209962Smm#include <errno.h>
42168404Spjd#include <stdio.h>
43185029Spjd#include <stdlib.h>
44185029Spjd#include <string.h>
45168404Spjd
46168404Spjdstatic char *
47168404Spjdmntopt(char **p)
48168404Spjd{
49168404Spjd	char *cp = *p;
50168404Spjd	char *retstr;
51168404Spjd
52168404Spjd	while (*cp && isspace(*cp))
53168404Spjd		cp++;
54168404Spjd
55168404Spjd	retstr = cp;
56168404Spjd	while (*cp && *cp != ',')
57168404Spjd		cp++;
58168404Spjd
59168404Spjd	if (*cp) {
60168404Spjd		*cp = '\0';
61168404Spjd		cp++;
62168404Spjd	}
63168404Spjd
64168404Spjd	*p = cp;
65168404Spjd	return (retstr);
66168404Spjd}
67168404Spjd
68168404Spjdchar *
69168404Spjdhasmntopt(struct mnttab *mnt, char *opt)
70168404Spjd{
71168404Spjd	char tmpopts[MNT_LINE_MAX];
72168404Spjd	char *f, *opts = tmpopts;
73168404Spjd
74168404Spjd	if (mnt->mnt_mntopts == NULL)
75168404Spjd		return (NULL);
76168404Spjd	(void) strcpy(opts, mnt->mnt_mntopts);
77168404Spjd	f = mntopt(&opts);
78168404Spjd	for (; *f; f = mntopt(&opts)) {
79168404Spjd		if (strncmp(opt, f, strlen(opt)) == 0)
80168404Spjd			return (f - tmpopts + mnt->mnt_mntopts);
81168404Spjd	}
82168404Spjd	return (NULL);
83168404Spjd}
84168404Spjd
85168404Spjdstatic void
86168404Spjdoptadd(char *mntopts, size_t size, const char *opt)
87168404Spjd{
88168404Spjd
89168404Spjd	if (mntopts[0] != '\0')
90168404Spjd		strlcat(mntopts, ",", size);
91168404Spjd	strlcat(mntopts, opt, size);
92168404Spjd}
93168404Spjd
94209962Smmvoid
95209962Smmstatfs2mnttab(struct statfs *sfs, struct mnttab *mp)
96168404Spjd{
97168404Spjd	static char mntopts[MNTMAXSTR];
98209962Smm	long flags;
99168404Spjd
100168404Spjd	mntopts[0] = '\0';
101168404Spjd
102209962Smm	flags = sfs->f_flags;
103209962Smm#define	OPTADD(opt)	optadd(mntopts, sizeof(mntopts), (opt))
104209962Smm	if (flags & MNT_RDONLY)
105209962Smm		OPTADD(MNTOPT_RO);
106209962Smm	else
107209962Smm		OPTADD(MNTOPT_RW);
108209962Smm	if (flags & MNT_NOSUID)
109209962Smm		OPTADD(MNTOPT_NOSUID);
110209962Smm	else
111209962Smm		OPTADD(MNTOPT_SETUID);
112209962Smm	if (flags & MNT_UPDATE)
113209962Smm		OPTADD(MNTOPT_REMOUNT);
114209962Smm	if (flags & MNT_NOATIME)
115209962Smm		OPTADD(MNTOPT_NOATIME);
116209962Smm	else
117209962Smm		OPTADD(MNTOPT_ATIME);
118209962Smm	OPTADD(MNTOPT_NOXATTR);
119209962Smm	if (flags & MNT_NOEXEC)
120209962Smm		OPTADD(MNTOPT_NOEXEC);
121209962Smm	else
122209962Smm		OPTADD(MNTOPT_EXEC);
123209962Smm#undef	OPTADD
124209962Smm	mp->mnt_special = sfs->f_mntfromname;
125209962Smm	mp->mnt_mountp = sfs->f_mntonname;
126209962Smm	mp->mnt_fstype = sfs->f_fstypename;
127209962Smm	mp->mnt_mntopts = mntopts;
128209962Smm}
129209962Smm
130209962Smmstatic struct statfs *gsfs = NULL;
131209962Smmstatic int allfs = 0;
132209962Smm
133209962Smmstatic int
134209962Smmstatfs_init(void)
135209962Smm{
136209962Smm	struct statfs *sfs;
137209962Smm	int error;
138209962Smm
139209962Smm	if (gsfs != NULL) {
140209962Smm		free(gsfs);
141209962Smm		gsfs = NULL;
142168404Spjd	}
143209962Smm	allfs = getfsstat(NULL, 0, MNT_WAIT);
144209962Smm	if (allfs == -1)
145209962Smm		goto fail;
146209962Smm	gsfs = malloc(sizeof(gsfs[0]) * allfs * 2);
147209962Smm	if (gsfs == NULL)
148209962Smm		goto fail;
149209962Smm	allfs = getfsstat(gsfs, (long)(sizeof(gsfs[0]) * allfs * 2),
150209962Smm	    MNT_WAIT);
151209962Smm	if (allfs == -1)
152209962Smm		goto fail;
153209962Smm	sfs = realloc(gsfs, allfs * sizeof(gsfs[0]));
154209962Smm	if (sfs != NULL)
155209962Smm		gsfs = sfs;
156209962Smm	return (0);
157209962Smmfail:
158209962Smm	error = errno;
159209962Smm	if (gsfs != NULL)
160209962Smm		free(gsfs);
161209962Smm	gsfs = NULL;
162209962Smm	allfs = 0;
163209962Smm	return (error);
164209962Smm}
165209962Smm
166209962Smmint
167209962Smmgetmntany(FILE *fd __unused, struct mnttab *mgetp, struct mnttab *mrefp)
168209962Smm{
169209962Smm	struct statfs *sfs;
170209962Smm	int i, error;
171209962Smm
172209962Smm	error = statfs_init();
173209962Smm	if (error != 0)
174209962Smm		return (error);
175209962Smm
176209962Smm	for (i = 0; i < allfs; i++) {
177168404Spjd		if (mrefp->mnt_special != NULL &&
178209962Smm		    strcmp(mrefp->mnt_special, gsfs[i].f_mntfromname) != 0) {
179168404Spjd			continue;
180168404Spjd		}
181168404Spjd		if (mrefp->mnt_mountp != NULL &&
182209962Smm		    strcmp(mrefp->mnt_mountp, gsfs[i].f_mntonname) != 0) {
183168404Spjd			continue;
184168404Spjd		}
185168404Spjd		if (mrefp->mnt_fstype != NULL &&
186209962Smm		    strcmp(mrefp->mnt_fstype, gsfs[i].f_fstypename) != 0) {
187168404Spjd			continue;
188168404Spjd		}
189209962Smm		statfs2mnttab(&gsfs[i], mgetp);
190168404Spjd		return (0);
191168404Spjd	}
192168404Spjd	return (-1);
193168404Spjd}
194209962Smm
195209962Smmint
196209962Smmgetmntent(FILE *fp, struct mnttab *mp)
197209962Smm{
198209962Smm	struct statfs *sfs;
199209962Smm	int error, nfs;
200209962Smm
201209962Smm	nfs = (int)lseek(fileno(fp), 0, SEEK_CUR);
202209962Smm	if (nfs == -1)
203209962Smm		return (errno);
204209962Smm	/* If nfs is 0, we want to refresh out cache. */
205209962Smm	if (nfs == 0 || gsfs == NULL) {
206209962Smm		error = statfs_init();
207209962Smm		if (error != 0)
208209962Smm			return (error);
209209962Smm	}
210209962Smm	if (nfs >= allfs)
211209962Smm		return (-1);
212209962Smm	statfs2mnttab(&gsfs[nfs], mp);
213209962Smm	if (lseek(fileno(fp), 1, SEEK_CUR) == -1)
214209962Smm		return (errno);
215209962Smm	return (0);
216209962Smm}
217