1 | /* $NetBSD: vfs_syscalls_20.c,v 1.39 2015/07/24 13:02:52 maxv Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 1989, 1993 |
5 | * The Regents of the University of California. All rights reserved. |
6 | * (c) UNIX System Laboratories, Inc. |
7 | * All or some portions of this file are derived from material licensed |
8 | * to the University of California by American Telephone and Telegraph |
9 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with |
10 | * the permission of UNIX System Laboratories, Inc. |
11 | * |
12 | * Redistribution and use in source and binary forms, with or without |
13 | * modification, are permitted provided that the following conditions |
14 | * are met: |
15 | * 1. Redistributions of source code must retain the above copyright |
16 | * notice, this list of conditions and the following disclaimer. |
17 | * 2. Redistributions in binary form must reproduce the above copyright |
18 | * notice, this list of conditions and the following disclaimer in the |
19 | * documentation and/or other materials provided with the distribution. |
20 | * 3. Neither the name of the University nor the names of its contributors |
21 | * may be used to endorse or promote products derived from this software |
22 | * without specific prior written permission. |
23 | * |
24 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
25 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
34 | * SUCH DAMAGE. |
35 | * |
36 | * @(#)vfs_syscalls.c 8.42 (Berkeley) 7/31/95 |
37 | */ |
38 | |
39 | #include <sys/cdefs.h> |
40 | __KERNEL_RCSID(0, "$NetBSD: vfs_syscalls_20.c,v 1.39 2015/07/24 13:02:52 maxv Exp $" ); |
41 | |
42 | #ifdef _KERNEL_OPT |
43 | #include "opt_compat_netbsd.h" |
44 | #endif |
45 | |
46 | #include <sys/param.h> |
47 | #include <sys/systm.h> |
48 | #include <sys/namei.h> |
49 | #include <sys/filedesc.h> |
50 | #include <sys/kernel.h> |
51 | #include <sys/file.h> |
52 | #include <sys/stat.h> |
53 | #include <sys/vnode.h> |
54 | #include <sys/mount.h> |
55 | #include <sys/proc.h> |
56 | #include <sys/uio.h> |
57 | #include <sys/malloc.h> |
58 | #include <sys/dirent.h> |
59 | #include <sys/sysctl.h> |
60 | #include <sys/syscallargs.h> |
61 | #include <sys/kauth.h> |
62 | |
63 | #include <compat/sys/mount.h> |
64 | |
65 | #define MOUNTNO_NONE 0 |
66 | #define MOUNTNO_UFS 1 /* UNIX "Fast" Filesystem */ |
67 | #define MOUNTNO_NFS 2 /* Network Filesystem */ |
68 | #define MOUNTNO_MFS 3 /* Memory Filesystem */ |
69 | #define MOUNTNO_MSDOS 4 /* MSDOS Filesystem */ |
70 | #define MOUNTNO_CD9660 5 /* iso9660 cdrom */ |
71 | #define MOUNTNO_FDESC 6 /* /dev/fd filesystem */ |
72 | #define MOUNTNO_KERNFS 7 /* kernel variable filesystem */ |
73 | #define MOUNTNO_DEVFS 8 /* device node filesystem */ |
74 | #define MOUNTNO_AFS 9 /* AFS 3.x */ |
75 | static const struct { |
76 | const char *name; |
77 | const int value; |
78 | } nv[] = { |
79 | { MOUNT_UFS, MOUNTNO_UFS }, |
80 | { MOUNT_NFS, MOUNTNO_NFS }, |
81 | { MOUNT_MFS, MOUNTNO_MFS }, |
82 | { MOUNT_MSDOS, MOUNTNO_MSDOS }, |
83 | { MOUNT_CD9660, MOUNTNO_CD9660 }, |
84 | { MOUNT_FDESC, MOUNTNO_FDESC }, |
85 | { MOUNT_KERNFS, MOUNTNO_KERNFS }, |
86 | { MOUNT_AFS, MOUNTNO_AFS }, |
87 | }; |
88 | |
89 | static int |
90 | vfs2fs(struct statfs12 *bfs, const struct statvfs *fs) |
91 | { |
92 | struct statfs12 ofs; |
93 | int i; |
94 | ofs.f_type = 0; |
95 | ofs.f_oflags = (short)fs->f_flag; |
96 | |
97 | for (i = 0; i < sizeof(nv) / sizeof(nv[0]); i++) { |
98 | if (strcmp(nv[i].name, fs->f_fstypename) == 0) { |
99 | ofs.f_type = nv[i].value; |
100 | break; |
101 | } |
102 | } |
103 | #define CLAMP(a) (long)(((a) & ~LONG_MAX) ? LONG_MAX : (a)) |
104 | ofs.f_bsize = CLAMP(fs->f_frsize); |
105 | ofs.f_iosize = CLAMP(fs->f_iosize); |
106 | ofs.f_blocks = CLAMP(fs->f_blocks); |
107 | ofs.f_bfree = CLAMP(fs->f_bfree); |
108 | if (fs->f_bfree > fs->f_bresvd) |
109 | ofs.f_bavail = CLAMP(fs->f_bfree - fs->f_bresvd); |
110 | else |
111 | ofs.f_bavail = -CLAMP(fs->f_bresvd - fs->f_bfree); |
112 | ofs.f_files = CLAMP(fs->f_files); |
113 | ofs.f_ffree = CLAMP(fs->f_ffree); |
114 | ofs.f_fsid = fs->f_fsidx; |
115 | ofs.f_owner = fs->f_owner; |
116 | ofs.f_flags = (long)fs->f_flag; |
117 | ofs.f_syncwrites = CLAMP(fs->f_syncwrites); |
118 | ofs.f_asyncwrites = CLAMP(fs->f_asyncwrites); |
119 | (void)strncpy(ofs.f_fstypename, fs->f_fstypename, |
120 | sizeof(ofs.f_fstypename)); |
121 | (void)strncpy(ofs.f_mntonname, fs->f_mntonname, |
122 | sizeof(ofs.f_mntonname)); |
123 | (void)strncpy(ofs.f_mntfromname, fs->f_mntfromname, |
124 | sizeof(ofs.f_mntfromname)); |
125 | |
126 | return copyout(&ofs, bfs, sizeof(ofs)); |
127 | } |
128 | |
129 | /* |
130 | * Get filesystem statistics. |
131 | */ |
132 | /* ARGSUSED */ |
133 | int |
134 | compat_20_sys_statfs(struct lwp *l, const struct compat_20_sys_statfs_args *uap, register_t *retval) |
135 | { |
136 | /* { |
137 | syscallarg(const char *) path; |
138 | syscallarg(struct statfs12 *) buf; |
139 | } */ |
140 | struct mount *mp; |
141 | struct statvfs *sbuf; |
142 | int error; |
143 | struct vnode *vp; |
144 | |
145 | error = namei_simple_user(SCARG(uap, path), |
146 | NSM_FOLLOW_TRYEMULROOT, &vp); |
147 | if (error != 0) |
148 | return error; |
149 | |
150 | mp = vp->v_mount; |
151 | |
152 | sbuf = malloc(sizeof(*sbuf), M_TEMP, M_WAITOK); |
153 | if ((error = dostatvfs(mp, sbuf, l, 0, 1)) != 0) |
154 | goto done; |
155 | |
156 | error = vfs2fs(SCARG(uap, buf), sbuf); |
157 | done: |
158 | vrele(vp); |
159 | free(sbuf, M_TEMP); |
160 | return error; |
161 | } |
162 | |
163 | /* |
164 | * Get filesystem statistics. |
165 | */ |
166 | /* ARGSUSED */ |
167 | int |
168 | compat_20_sys_fstatfs(struct lwp *l, const struct compat_20_sys_fstatfs_args *uap, register_t *retval) |
169 | { |
170 | /* { |
171 | syscallarg(int) fd; |
172 | syscallarg(struct statfs12 *) buf; |
173 | } */ |
174 | struct file *fp; |
175 | struct mount *mp; |
176 | struct statvfs *sbuf; |
177 | int error; |
178 | |
179 | /* fd_getvnode() will use the descriptor for us */ |
180 | if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) |
181 | return (error); |
182 | mp = fp->f_vnode->v_mount; |
183 | sbuf = malloc(sizeof(*sbuf), M_TEMP, M_WAITOK); |
184 | if ((error = dostatvfs(mp, sbuf, l, 0, 1)) != 0) |
185 | goto out; |
186 | error = vfs2fs(SCARG(uap, buf), sbuf); |
187 | out: |
188 | fd_putfile(SCARG(uap, fd)); |
189 | free(sbuf, M_TEMP); |
190 | return error; |
191 | } |
192 | |
193 | |
194 | /* |
195 | * Get statistics on all filesystems. |
196 | */ |
197 | int |
198 | compat_20_sys_getfsstat(struct lwp *l, const struct compat_20_sys_getfsstat_args *uap, register_t *retval) |
199 | { |
200 | /* { |
201 | syscallarg(struct statfs12 *) buf; |
202 | syscallarg(long) bufsize; |
203 | syscallarg(int) flags; |
204 | } */ |
205 | int root = 0; |
206 | struct mount *mp, *nmp; |
207 | struct statvfs *sbuf; |
208 | struct statfs12 *sfsp; |
209 | size_t count, maxcount; |
210 | int error = 0; |
211 | |
212 | sbuf = malloc(sizeof(*sbuf), M_TEMP, M_WAITOK); |
213 | maxcount = (size_t)SCARG(uap, bufsize) / sizeof(struct statfs12); |
214 | sfsp = SCARG(uap, buf); |
215 | mutex_enter(&mountlist_lock); |
216 | count = 0; |
217 | for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { |
218 | if (vfs_busy(mp, &nmp)) { |
219 | continue; |
220 | } |
221 | if (sfsp && count < maxcount) { |
222 | error = dostatvfs(mp, sbuf, l, SCARG(uap, flags), 0); |
223 | if (error) { |
224 | vfs_unbusy(mp, false, &nmp); |
225 | continue; |
226 | } |
227 | error = vfs2fs(sfsp, sbuf); |
228 | if (error) { |
229 | vfs_unbusy(mp, false, NULL); |
230 | goto out; |
231 | } |
232 | sfsp++; |
233 | root |= strcmp(sbuf->f_mntonname, "/" ) == 0; |
234 | } |
235 | count++; |
236 | vfs_unbusy(mp, false, &nmp); |
237 | } |
238 | mutex_exit(&mountlist_lock); |
239 | if (root == 0 && l->l_proc->p_cwdi->cwdi_rdir) { |
240 | /* |
241 | * fake a root entry |
242 | */ |
243 | if ((error = dostatvfs(l->l_proc->p_cwdi->cwdi_rdir->v_mount, |
244 | sbuf, l, SCARG(uap, flags), 1)) != 0) |
245 | goto out; |
246 | if (sfsp) |
247 | error = vfs2fs(sfsp, sbuf); |
248 | count++; |
249 | } |
250 | if (sfsp && count > maxcount) |
251 | *retval = maxcount; |
252 | else |
253 | *retval = count; |
254 | out: |
255 | free(sbuf, M_TEMP); |
256 | return error; |
257 | } |
258 | |
259 | int |
260 | compat_20_sys_fhstatfs(struct lwp *l, const struct compat_20_sys_fhstatfs_args *uap, register_t *retval) |
261 | { |
262 | /* { |
263 | syscallarg(const struct compat_30_fhandle *) fhp; |
264 | syscallarg(struct statfs12 *) buf; |
265 | } */ |
266 | struct statvfs *sbuf; |
267 | struct compat_30_fhandle fh; |
268 | struct mount *mp; |
269 | struct vnode *vp; |
270 | int error; |
271 | |
272 | /* |
273 | * Must be super user |
274 | */ |
275 | if ((error = kauth_authorize_system(l->l_cred, |
276 | KAUTH_SYSTEM_FILEHANDLE, 0, NULL, NULL, NULL))) |
277 | return (error); |
278 | |
279 | if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fh))) != 0) |
280 | return (error); |
281 | |
282 | if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) |
283 | return (ESTALE); |
284 | if ((error = VFS_FHTOVP(mp, (struct fid*)&fh.fh_fid, &vp))) |
285 | return (error); |
286 | mp = vp->v_mount; |
287 | VOP_UNLOCK(vp); |
288 | sbuf = malloc(sizeof(*sbuf), M_TEMP, M_WAITOK); |
289 | if ((error = VFS_STATVFS(mp, sbuf)) != 0) |
290 | goto out; |
291 | error = vfs2fs(SCARG(uap, buf), sbuf); |
292 | out: |
293 | vrele(vp); |
294 | free(sbuf, M_TEMP); |
295 | return error; |
296 | } |
297 | |