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 
50 char *
mntopt(char ** p)51 mntopt(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 
72 char *
hasmntopt(struct mnttab * mnt,char * opt)73 hasmntopt(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 
89 static void
optadd(char * mntopts,size_t size,const char * opt)90 optadd(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 
98 void
statvfs2mnttab(struct statvfs * sfs,struct mnttab * mp)99 statvfs2mnttab(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 
134 static struct statvfs *gsfs;
135 static int allfs;
136 
137 static int
statvfs_init(void)138 statvfs_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);
160 fail:
161           error = errno;
162           if (gsfs != NULL)
163                     free(gsfs);
164           gsfs = NULL;
165           allfs = 0;
166           return (error);
167 }
168 
169 int
getmntany(FILE * fd,struct mnttab * mgetp,struct mnttab * mrefp)170 getmntany(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 
197 int
getmntent(FILE * fp,struct mnttab * mp)198 getmntent(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