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