1 | #include <machine/rtems-bsd-kernel-space.h> |
---|
2 | |
---|
3 | /*- |
---|
4 | * SPDX-License-Identifier: BSD-3-Clause |
---|
5 | * |
---|
6 | * Copyright (c) 1989, 1993 |
---|
7 | * The Regents of the University of California. All rights reserved. |
---|
8 | * (c) UNIX System Laboratories, Inc. |
---|
9 | * All or some portions of this file are derived from material licensed |
---|
10 | * to the University of California by American Telephone and Telegraph |
---|
11 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with |
---|
12 | * the permission of UNIX System Laboratories, Inc. |
---|
13 | * |
---|
14 | * Redistribution and use in source and binary forms, with or without |
---|
15 | * modification, are permitted provided that the following conditions |
---|
16 | * are met: |
---|
17 | * 1. Redistributions of source code must retain the above copyright |
---|
18 | * notice, this list of conditions and the following disclaimer. |
---|
19 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
20 | * notice, this list of conditions and the following disclaimer in the |
---|
21 | * documentation and/or other materials provided with the distribution. |
---|
22 | * 3. Neither the name of the University nor the names of its contributors |
---|
23 | * may be used to endorse or promote products derived from this software |
---|
24 | * without specific prior written permission. |
---|
25 | * |
---|
26 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
---|
27 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
28 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
29 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
---|
30 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
---|
31 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
---|
32 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
---|
33 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
---|
34 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
---|
35 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
---|
36 | * SUCH DAMAGE. |
---|
37 | * |
---|
38 | * @(#)vfs_syscalls.c 8.13 (Berkeley) 4/15/94 |
---|
39 | */ |
---|
40 | |
---|
41 | #include <sys/cdefs.h> |
---|
42 | __FBSDID("$FreeBSD$"); |
---|
43 | |
---|
44 | #include <rtems/bsd/local/opt_capsicum.h> |
---|
45 | #include <rtems/bsd/local/opt_ktrace.h> |
---|
46 | |
---|
47 | #include <sys/param.h> |
---|
48 | #include <sys/systm.h> |
---|
49 | #include <sys/bio.h> |
---|
50 | #include <sys/buf.h> |
---|
51 | #include <sys/capsicum.h> |
---|
52 | #include <sys/disk.h> |
---|
53 | #include <sys/sysent.h> |
---|
54 | #include <sys/malloc.h> |
---|
55 | #include <sys/mount.h> |
---|
56 | #include <sys/mutex.h> |
---|
57 | #include <sys/sysproto.h> |
---|
58 | #include <sys/namei.h> |
---|
59 | #include <sys/filedesc.h> |
---|
60 | #include <sys/kernel.h> |
---|
61 | #include <sys/fcntl.h> |
---|
62 | #include <sys/file.h> |
---|
63 | #include <sys/filio.h> |
---|
64 | #include <sys/limits.h> |
---|
65 | #include <sys/linker.h> |
---|
66 | #include <sys/rwlock.h> |
---|
67 | #include <sys/sdt.h> |
---|
68 | #include <sys/stat.h> |
---|
69 | #include <sys/sx.h> |
---|
70 | #include <rtems/bsd/sys/unistd.h> |
---|
71 | #include <sys/vnode.h> |
---|
72 | #include <sys/priv.h> |
---|
73 | #include <sys/proc.h> |
---|
74 | #include <sys/dirent.h> |
---|
75 | #include <sys/jail.h> |
---|
76 | #include <sys/syscallsubr.h> |
---|
77 | #include <sys/sysctl.h> |
---|
78 | #ifdef KTRACE |
---|
79 | #include <sys/ktrace.h> |
---|
80 | #endif |
---|
81 | |
---|
82 | #include <machine/stdarg.h> |
---|
83 | |
---|
84 | #include <security/audit/audit.h> |
---|
85 | #include <security/mac/mac_framework.h> |
---|
86 | |
---|
87 | #include <vm/vm.h> |
---|
88 | #include <vm/vm_object.h> |
---|
89 | #include <vm/vm_page.h> |
---|
90 | #include <vm/uma.h> |
---|
91 | |
---|
92 | #ifndef __rtems__ |
---|
93 | #include <ufs/ufs/quota.h> |
---|
94 | #endif /* __rtems__ */ |
---|
95 | |
---|
96 | MALLOC_DEFINE(M_FADVISE, "fadvise", "posix_fadvise(2) information"); |
---|
97 | |
---|
98 | SDT_PROVIDER_DEFINE(vfs); |
---|
99 | SDT_PROBE_DEFINE2(vfs, , stat, mode, "char *", "int"); |
---|
100 | SDT_PROBE_DEFINE2(vfs, , stat, reg, "char *", "int"); |
---|
101 | |
---|
102 | static int kern_chflagsat(struct thread *td, int fd, const char *path, |
---|
103 | enum uio_seg pathseg, u_long flags, int atflag); |
---|
104 | static int setfflags(struct thread *td, struct vnode *, u_long); |
---|
105 | static int getutimes(const struct timeval *, enum uio_seg, struct timespec *); |
---|
106 | static int getutimens(const struct timespec *, enum uio_seg, |
---|
107 | struct timespec *, int *); |
---|
108 | static int setutimes(struct thread *td, struct vnode *, |
---|
109 | const struct timespec *, int, int); |
---|
110 | static int vn_access(struct vnode *vp, int user_flags, struct ucred *cred, |
---|
111 | struct thread *td); |
---|
112 | static int kern_fhlinkat(struct thread *td, int fd, const char *path, |
---|
113 | enum uio_seg pathseg, fhandle_t *fhp); |
---|
114 | static int kern_getfhat(struct thread *td, int flags, int fd, |
---|
115 | const char *path, enum uio_seg pathseg, fhandle_t *fhp); |
---|
116 | static int kern_readlink_vp(struct vnode *vp, char *buf, enum uio_seg bufseg, |
---|
117 | size_t count, struct thread *td); |
---|
118 | static int kern_linkat_vp(struct thread *td, struct vnode *vp, int fd, |
---|
119 | const char *path, enum uio_seg segflag); |
---|
120 | |
---|
121 | /* |
---|
122 | * Sync each mounted filesystem. |
---|
123 | */ |
---|
124 | #ifndef _SYS_SYSPROTO_H_ |
---|
125 | struct sync_args { |
---|
126 | int dummy; |
---|
127 | }; |
---|
128 | #endif |
---|
129 | /* ARGSUSED */ |
---|
130 | int |
---|
131 | sys_sync(struct thread *td, struct sync_args *uap) |
---|
132 | { |
---|
133 | struct mount *mp, *nmp; |
---|
134 | int save; |
---|
135 | |
---|
136 | mtx_lock(&mountlist_mtx); |
---|
137 | for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { |
---|
138 | if (vfs_busy(mp, MBF_NOWAIT | MBF_MNTLSTLOCK)) { |
---|
139 | nmp = TAILQ_NEXT(mp, mnt_list); |
---|
140 | continue; |
---|
141 | } |
---|
142 | if ((mp->mnt_flag & MNT_RDONLY) == 0 && |
---|
143 | vn_start_write(NULL, &mp, V_NOWAIT) == 0) { |
---|
144 | save = curthread_pflags_set(TDP_SYNCIO); |
---|
145 | vfs_msync(mp, MNT_NOWAIT); |
---|
146 | VFS_SYNC(mp, MNT_NOWAIT); |
---|
147 | curthread_pflags_restore(save); |
---|
148 | vn_finished_write(mp); |
---|
149 | } |
---|
150 | mtx_lock(&mountlist_mtx); |
---|
151 | nmp = TAILQ_NEXT(mp, mnt_list); |
---|
152 | vfs_unbusy(mp); |
---|
153 | } |
---|
154 | mtx_unlock(&mountlist_mtx); |
---|
155 | return (0); |
---|
156 | } |
---|
157 | |
---|
158 | #ifndef __rtems__ |
---|
159 | /* |
---|
160 | * Change filesystem quotas. |
---|
161 | */ |
---|
162 | #ifndef _SYS_SYSPROTO_H_ |
---|
163 | struct quotactl_args { |
---|
164 | char *path; |
---|
165 | int cmd; |
---|
166 | int uid; |
---|
167 | caddr_t arg; |
---|
168 | }; |
---|
169 | #endif |
---|
170 | int |
---|
171 | sys_quotactl(struct thread *td, struct quotactl_args *uap) |
---|
172 | { |
---|
173 | struct mount *mp; |
---|
174 | struct nameidata nd; |
---|
175 | int error; |
---|
176 | |
---|
177 | AUDIT_ARG_CMD(uap->cmd); |
---|
178 | AUDIT_ARG_UID(uap->uid); |
---|
179 | if (!prison_allow(td->td_ucred, PR_ALLOW_QUOTAS)) |
---|
180 | return (EPERM); |
---|
181 | NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1, UIO_USERSPACE, |
---|
182 | uap->path, td); |
---|
183 | if ((error = namei(&nd)) != 0) |
---|
184 | return (error); |
---|
185 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
186 | mp = nd.ni_vp->v_mount; |
---|
187 | vfs_ref(mp); |
---|
188 | vput(nd.ni_vp); |
---|
189 | error = vfs_busy(mp, 0); |
---|
190 | vfs_rel(mp); |
---|
191 | if (error != 0) |
---|
192 | return (error); |
---|
193 | error = VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg); |
---|
194 | |
---|
195 | /* |
---|
196 | * Since quota on operation typically needs to open quota |
---|
197 | * file, the Q_QUOTAON handler needs to unbusy the mount point |
---|
198 | * before calling into namei. Otherwise, unmount might be |
---|
199 | * started between two vfs_busy() invocations (first is our, |
---|
200 | * second is from mount point cross-walk code in lookup()), |
---|
201 | * causing deadlock. |
---|
202 | * |
---|
203 | * Require that Q_QUOTAON handles the vfs_busy() reference on |
---|
204 | * its own, always returning with ubusied mount point. |
---|
205 | */ |
---|
206 | if ((uap->cmd >> SUBCMDSHIFT) != Q_QUOTAON && |
---|
207 | (uap->cmd >> SUBCMDSHIFT) != Q_QUOTAOFF) |
---|
208 | vfs_unbusy(mp); |
---|
209 | return (error); |
---|
210 | } |
---|
211 | #endif /* __rtems__ */ |
---|
212 | |
---|
213 | /* |
---|
214 | * Used by statfs conversion routines to scale the block size up if |
---|
215 | * necessary so that all of the block counts are <= 'max_size'. Note |
---|
216 | * that 'max_size' should be a bitmask, i.e. 2^n - 1 for some non-zero |
---|
217 | * value of 'n'. |
---|
218 | */ |
---|
219 | void |
---|
220 | statfs_scale_blocks(struct statfs *sf, long max_size) |
---|
221 | { |
---|
222 | uint64_t count; |
---|
223 | int shift; |
---|
224 | |
---|
225 | KASSERT(powerof2(max_size + 1), ("%s: invalid max_size", __func__)); |
---|
226 | |
---|
227 | /* |
---|
228 | * Attempt to scale the block counts to give a more accurate |
---|
229 | * overview to userland of the ratio of free space to used |
---|
230 | * space. To do this, find the largest block count and compute |
---|
231 | * a divisor that lets it fit into a signed integer <= max_size. |
---|
232 | */ |
---|
233 | if (sf->f_bavail < 0) |
---|
234 | count = -sf->f_bavail; |
---|
235 | else |
---|
236 | count = sf->f_bavail; |
---|
237 | count = MAX(sf->f_blocks, MAX(sf->f_bfree, count)); |
---|
238 | if (count <= max_size) |
---|
239 | return; |
---|
240 | |
---|
241 | count >>= flsl(max_size); |
---|
242 | shift = 0; |
---|
243 | while (count > 0) { |
---|
244 | shift++; |
---|
245 | count >>=1; |
---|
246 | } |
---|
247 | |
---|
248 | sf->f_bsize <<= shift; |
---|
249 | sf->f_blocks >>= shift; |
---|
250 | sf->f_bfree >>= shift; |
---|
251 | sf->f_bavail >>= shift; |
---|
252 | } |
---|
253 | |
---|
254 | static int |
---|
255 | kern_do_statfs(struct thread *td, struct mount *mp, struct statfs *buf) |
---|
256 | { |
---|
257 | struct statfs *sp; |
---|
258 | int error; |
---|
259 | |
---|
260 | if (mp == NULL) |
---|
261 | return (EBADF); |
---|
262 | error = vfs_busy(mp, 0); |
---|
263 | vfs_rel(mp); |
---|
264 | if (error != 0) |
---|
265 | return (error); |
---|
266 | #ifdef MAC |
---|
267 | error = mac_mount_check_stat(td->td_ucred, mp); |
---|
268 | if (error != 0) |
---|
269 | goto out; |
---|
270 | #endif |
---|
271 | /* |
---|
272 | * Set these in case the underlying filesystem fails to do so. |
---|
273 | */ |
---|
274 | sp = &mp->mnt_stat; |
---|
275 | sp->f_version = STATFS_VERSION; |
---|
276 | sp->f_namemax = NAME_MAX; |
---|
277 | sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; |
---|
278 | error = VFS_STATFS(mp, sp); |
---|
279 | if (error != 0) |
---|
280 | goto out; |
---|
281 | *buf = *sp; |
---|
282 | if (priv_check(td, PRIV_VFS_GENERATION)) { |
---|
283 | buf->f_fsid.val[0] = buf->f_fsid.val[1] = 0; |
---|
284 | prison_enforce_statfs(td->td_ucred, mp, buf); |
---|
285 | } |
---|
286 | out: |
---|
287 | vfs_unbusy(mp); |
---|
288 | return (error); |
---|
289 | } |
---|
290 | |
---|
291 | /* |
---|
292 | * Get filesystem statistics. |
---|
293 | */ |
---|
294 | #ifndef _SYS_SYSPROTO_H_ |
---|
295 | struct statfs_args { |
---|
296 | char *path; |
---|
297 | struct statfs *buf; |
---|
298 | }; |
---|
299 | #endif |
---|
300 | int |
---|
301 | sys_statfs(struct thread *td, struct statfs_args *uap) |
---|
302 | { |
---|
303 | struct statfs *sfp; |
---|
304 | int error; |
---|
305 | |
---|
306 | sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); |
---|
307 | error = kern_statfs(td, uap->path, UIO_USERSPACE, sfp); |
---|
308 | if (error == 0) |
---|
309 | error = copyout(sfp, uap->buf, sizeof(struct statfs)); |
---|
310 | free(sfp, M_STATFS); |
---|
311 | return (error); |
---|
312 | } |
---|
313 | |
---|
314 | int |
---|
315 | kern_statfs(struct thread *td, char *path, enum uio_seg pathseg, |
---|
316 | struct statfs *buf) |
---|
317 | { |
---|
318 | struct mount *mp; |
---|
319 | struct nameidata nd; |
---|
320 | int error; |
---|
321 | |
---|
322 | NDINIT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | AUDITVNODE1, |
---|
323 | pathseg, path, td); |
---|
324 | error = namei(&nd); |
---|
325 | if (error != 0) |
---|
326 | return (error); |
---|
327 | mp = nd.ni_vp->v_mount; |
---|
328 | vfs_ref(mp); |
---|
329 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
330 | vput(nd.ni_vp); |
---|
331 | return (kern_do_statfs(td, mp, buf)); |
---|
332 | } |
---|
333 | |
---|
334 | /* |
---|
335 | * Get filesystem statistics. |
---|
336 | */ |
---|
337 | #ifndef _SYS_SYSPROTO_H_ |
---|
338 | struct fstatfs_args { |
---|
339 | int fd; |
---|
340 | struct statfs *buf; |
---|
341 | }; |
---|
342 | #endif |
---|
343 | int |
---|
344 | sys_fstatfs(struct thread *td, struct fstatfs_args *uap) |
---|
345 | { |
---|
346 | struct statfs *sfp; |
---|
347 | int error; |
---|
348 | |
---|
349 | sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); |
---|
350 | error = kern_fstatfs(td, uap->fd, sfp); |
---|
351 | if (error == 0) |
---|
352 | error = copyout(sfp, uap->buf, sizeof(struct statfs)); |
---|
353 | free(sfp, M_STATFS); |
---|
354 | return (error); |
---|
355 | } |
---|
356 | |
---|
357 | int |
---|
358 | kern_fstatfs(struct thread *td, int fd, struct statfs *buf) |
---|
359 | { |
---|
360 | struct file *fp; |
---|
361 | struct mount *mp; |
---|
362 | struct vnode *vp; |
---|
363 | int error; |
---|
364 | |
---|
365 | AUDIT_ARG_FD(fd); |
---|
366 | error = getvnode(td, fd, &cap_fstatfs_rights, &fp); |
---|
367 | if (error != 0) |
---|
368 | return (error); |
---|
369 | vp = fp->f_vnode; |
---|
370 | vn_lock(vp, LK_SHARED | LK_RETRY); |
---|
371 | #ifdef AUDIT |
---|
372 | AUDIT_ARG_VNODE1(vp); |
---|
373 | #endif |
---|
374 | mp = vp->v_mount; |
---|
375 | if (mp != NULL) |
---|
376 | vfs_ref(mp); |
---|
377 | VOP_UNLOCK(vp, 0); |
---|
378 | fdrop(fp, td); |
---|
379 | return (kern_do_statfs(td, mp, buf)); |
---|
380 | } |
---|
381 | |
---|
382 | /* |
---|
383 | * Get statistics on all filesystems. |
---|
384 | */ |
---|
385 | #ifndef _SYS_SYSPROTO_H_ |
---|
386 | struct getfsstat_args { |
---|
387 | struct statfs *buf; |
---|
388 | long bufsize; |
---|
389 | int mode; |
---|
390 | }; |
---|
391 | #endif |
---|
392 | int |
---|
393 | sys_getfsstat(struct thread *td, struct getfsstat_args *uap) |
---|
394 | { |
---|
395 | size_t count; |
---|
396 | int error; |
---|
397 | |
---|
398 | if (uap->bufsize < 0 || uap->bufsize > SIZE_MAX) |
---|
399 | return (EINVAL); |
---|
400 | error = kern_getfsstat(td, &uap->buf, uap->bufsize, &count, |
---|
401 | UIO_USERSPACE, uap->mode); |
---|
402 | if (error == 0) |
---|
403 | td->td_retval[0] = count; |
---|
404 | return (error); |
---|
405 | } |
---|
406 | |
---|
407 | /* |
---|
408 | * If (bufsize > 0 && bufseg == UIO_SYSSPACE) |
---|
409 | * The caller is responsible for freeing memory which will be allocated |
---|
410 | * in '*buf'. |
---|
411 | */ |
---|
412 | int |
---|
413 | kern_getfsstat(struct thread *td, struct statfs **buf, size_t bufsize, |
---|
414 | size_t *countp, enum uio_seg bufseg, int mode) |
---|
415 | { |
---|
416 | struct mount *mp, *nmp; |
---|
417 | struct statfs *sfsp, *sp, *sptmp, *tofree; |
---|
418 | size_t count, maxcount; |
---|
419 | int error; |
---|
420 | |
---|
421 | switch (mode) { |
---|
422 | case MNT_WAIT: |
---|
423 | case MNT_NOWAIT: |
---|
424 | break; |
---|
425 | default: |
---|
426 | if (bufseg == UIO_SYSSPACE) |
---|
427 | *buf = NULL; |
---|
428 | return (EINVAL); |
---|
429 | } |
---|
430 | restart: |
---|
431 | maxcount = bufsize / sizeof(struct statfs); |
---|
432 | if (bufsize == 0) { |
---|
433 | sfsp = NULL; |
---|
434 | tofree = NULL; |
---|
435 | } else if (bufseg == UIO_USERSPACE) { |
---|
436 | sfsp = *buf; |
---|
437 | tofree = NULL; |
---|
438 | } else /* if (bufseg == UIO_SYSSPACE) */ { |
---|
439 | count = 0; |
---|
440 | mtx_lock(&mountlist_mtx); |
---|
441 | TAILQ_FOREACH(mp, &mountlist, mnt_list) { |
---|
442 | count++; |
---|
443 | } |
---|
444 | mtx_unlock(&mountlist_mtx); |
---|
445 | if (maxcount > count) |
---|
446 | maxcount = count; |
---|
447 | tofree = sfsp = *buf = malloc(maxcount * sizeof(struct statfs), |
---|
448 | M_STATFS, M_WAITOK); |
---|
449 | } |
---|
450 | count = 0; |
---|
451 | mtx_lock(&mountlist_mtx); |
---|
452 | for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { |
---|
453 | if (prison_canseemount(td->td_ucred, mp) != 0) { |
---|
454 | nmp = TAILQ_NEXT(mp, mnt_list); |
---|
455 | continue; |
---|
456 | } |
---|
457 | #ifdef MAC |
---|
458 | if (mac_mount_check_stat(td->td_ucred, mp) != 0) { |
---|
459 | nmp = TAILQ_NEXT(mp, mnt_list); |
---|
460 | continue; |
---|
461 | } |
---|
462 | #endif |
---|
463 | if (mode == MNT_WAIT) { |
---|
464 | if (vfs_busy(mp, MBF_MNTLSTLOCK) != 0) { |
---|
465 | /* |
---|
466 | * If vfs_busy() failed, and MBF_NOWAIT |
---|
467 | * wasn't passed, then the mp is gone. |
---|
468 | * Furthermore, because of MBF_MNTLSTLOCK, |
---|
469 | * the mountlist_mtx was dropped. We have |
---|
470 | * no other choice than to start over. |
---|
471 | */ |
---|
472 | mtx_unlock(&mountlist_mtx); |
---|
473 | free(tofree, M_STATFS); |
---|
474 | goto restart; |
---|
475 | } |
---|
476 | } else { |
---|
477 | if (vfs_busy(mp, MBF_NOWAIT | MBF_MNTLSTLOCK) != 0) { |
---|
478 | nmp = TAILQ_NEXT(mp, mnt_list); |
---|
479 | continue; |
---|
480 | } |
---|
481 | } |
---|
482 | if (sfsp != NULL && count < maxcount) { |
---|
483 | sp = &mp->mnt_stat; |
---|
484 | /* |
---|
485 | * Set these in case the underlying filesystem |
---|
486 | * fails to do so. |
---|
487 | */ |
---|
488 | sp->f_version = STATFS_VERSION; |
---|
489 | sp->f_namemax = NAME_MAX; |
---|
490 | sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; |
---|
491 | /* |
---|
492 | * If MNT_NOWAIT is specified, do not refresh |
---|
493 | * the fsstat cache. |
---|
494 | */ |
---|
495 | if (mode != MNT_NOWAIT) { |
---|
496 | error = VFS_STATFS(mp, sp); |
---|
497 | if (error != 0) { |
---|
498 | mtx_lock(&mountlist_mtx); |
---|
499 | nmp = TAILQ_NEXT(mp, mnt_list); |
---|
500 | vfs_unbusy(mp); |
---|
501 | continue; |
---|
502 | } |
---|
503 | } |
---|
504 | if (priv_check(td, PRIV_VFS_GENERATION)) { |
---|
505 | sptmp = malloc(sizeof(struct statfs), M_STATFS, |
---|
506 | M_WAITOK); |
---|
507 | *sptmp = *sp; |
---|
508 | sptmp->f_fsid.val[0] = sptmp->f_fsid.val[1] = 0; |
---|
509 | prison_enforce_statfs(td->td_ucred, mp, sptmp); |
---|
510 | sp = sptmp; |
---|
511 | } else |
---|
512 | sptmp = NULL; |
---|
513 | if (bufseg == UIO_SYSSPACE) { |
---|
514 | bcopy(sp, sfsp, sizeof(*sp)); |
---|
515 | free(sptmp, M_STATFS); |
---|
516 | } else /* if (bufseg == UIO_USERSPACE) */ { |
---|
517 | error = copyout(sp, sfsp, sizeof(*sp)); |
---|
518 | free(sptmp, M_STATFS); |
---|
519 | if (error != 0) { |
---|
520 | vfs_unbusy(mp); |
---|
521 | return (error); |
---|
522 | } |
---|
523 | } |
---|
524 | sfsp++; |
---|
525 | } |
---|
526 | count++; |
---|
527 | mtx_lock(&mountlist_mtx); |
---|
528 | nmp = TAILQ_NEXT(mp, mnt_list); |
---|
529 | vfs_unbusy(mp); |
---|
530 | } |
---|
531 | mtx_unlock(&mountlist_mtx); |
---|
532 | if (sfsp != NULL && count > maxcount) |
---|
533 | *countp = maxcount; |
---|
534 | else |
---|
535 | *countp = count; |
---|
536 | return (0); |
---|
537 | } |
---|
538 | |
---|
539 | #ifdef COMPAT_FREEBSD4 |
---|
540 | /* |
---|
541 | * Get old format filesystem statistics. |
---|
542 | */ |
---|
543 | static void freebsd4_cvtstatfs(struct statfs *, struct ostatfs *); |
---|
544 | |
---|
545 | #ifndef _SYS_SYSPROTO_H_ |
---|
546 | struct freebsd4_statfs_args { |
---|
547 | char *path; |
---|
548 | struct ostatfs *buf; |
---|
549 | }; |
---|
550 | #endif |
---|
551 | int |
---|
552 | freebsd4_statfs(struct thread *td, struct freebsd4_statfs_args *uap) |
---|
553 | { |
---|
554 | struct ostatfs osb; |
---|
555 | struct statfs *sfp; |
---|
556 | int error; |
---|
557 | |
---|
558 | sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); |
---|
559 | error = kern_statfs(td, uap->path, UIO_USERSPACE, sfp); |
---|
560 | if (error == 0) { |
---|
561 | freebsd4_cvtstatfs(sfp, &osb); |
---|
562 | error = copyout(&osb, uap->buf, sizeof(osb)); |
---|
563 | } |
---|
564 | free(sfp, M_STATFS); |
---|
565 | return (error); |
---|
566 | } |
---|
567 | |
---|
568 | /* |
---|
569 | * Get filesystem statistics. |
---|
570 | */ |
---|
571 | #ifndef _SYS_SYSPROTO_H_ |
---|
572 | struct freebsd4_fstatfs_args { |
---|
573 | int fd; |
---|
574 | struct ostatfs *buf; |
---|
575 | }; |
---|
576 | #endif |
---|
577 | int |
---|
578 | freebsd4_fstatfs(struct thread *td, struct freebsd4_fstatfs_args *uap) |
---|
579 | { |
---|
580 | struct ostatfs osb; |
---|
581 | struct statfs *sfp; |
---|
582 | int error; |
---|
583 | |
---|
584 | sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); |
---|
585 | error = kern_fstatfs(td, uap->fd, sfp); |
---|
586 | if (error == 0) { |
---|
587 | freebsd4_cvtstatfs(sfp, &osb); |
---|
588 | error = copyout(&osb, uap->buf, sizeof(osb)); |
---|
589 | } |
---|
590 | free(sfp, M_STATFS); |
---|
591 | return (error); |
---|
592 | } |
---|
593 | |
---|
594 | /* |
---|
595 | * Get statistics on all filesystems. |
---|
596 | */ |
---|
597 | #ifndef _SYS_SYSPROTO_H_ |
---|
598 | struct freebsd4_getfsstat_args { |
---|
599 | struct ostatfs *buf; |
---|
600 | long bufsize; |
---|
601 | int mode; |
---|
602 | }; |
---|
603 | #endif |
---|
604 | int |
---|
605 | freebsd4_getfsstat(struct thread *td, struct freebsd4_getfsstat_args *uap) |
---|
606 | { |
---|
607 | struct statfs *buf, *sp; |
---|
608 | struct ostatfs osb; |
---|
609 | size_t count, size; |
---|
610 | int error; |
---|
611 | |
---|
612 | if (uap->bufsize < 0) |
---|
613 | return (EINVAL); |
---|
614 | count = uap->bufsize / sizeof(struct ostatfs); |
---|
615 | if (count > SIZE_MAX / sizeof(struct statfs)) |
---|
616 | return (EINVAL); |
---|
617 | size = count * sizeof(struct statfs); |
---|
618 | error = kern_getfsstat(td, &buf, size, &count, UIO_SYSSPACE, |
---|
619 | uap->mode); |
---|
620 | if (error == 0) |
---|
621 | td->td_retval[0] = count; |
---|
622 | if (size != 0) { |
---|
623 | sp = buf; |
---|
624 | while (count != 0 && error == 0) { |
---|
625 | freebsd4_cvtstatfs(sp, &osb); |
---|
626 | error = copyout(&osb, uap->buf, sizeof(osb)); |
---|
627 | sp++; |
---|
628 | uap->buf++; |
---|
629 | count--; |
---|
630 | } |
---|
631 | free(buf, M_STATFS); |
---|
632 | } |
---|
633 | return (error); |
---|
634 | } |
---|
635 | |
---|
636 | /* |
---|
637 | * Implement fstatfs() for (NFS) file handles. |
---|
638 | */ |
---|
639 | #ifndef _SYS_SYSPROTO_H_ |
---|
640 | struct freebsd4_fhstatfs_args { |
---|
641 | struct fhandle *u_fhp; |
---|
642 | struct ostatfs *buf; |
---|
643 | }; |
---|
644 | #endif |
---|
645 | int |
---|
646 | freebsd4_fhstatfs(struct thread *td, struct freebsd4_fhstatfs_args *uap) |
---|
647 | { |
---|
648 | struct ostatfs osb; |
---|
649 | struct statfs *sfp; |
---|
650 | fhandle_t fh; |
---|
651 | int error; |
---|
652 | |
---|
653 | error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t)); |
---|
654 | if (error != 0) |
---|
655 | return (error); |
---|
656 | sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); |
---|
657 | error = kern_fhstatfs(td, fh, sfp); |
---|
658 | if (error == 0) { |
---|
659 | freebsd4_cvtstatfs(sfp, &osb); |
---|
660 | error = copyout(&osb, uap->buf, sizeof(osb)); |
---|
661 | } |
---|
662 | free(sfp, M_STATFS); |
---|
663 | return (error); |
---|
664 | } |
---|
665 | |
---|
666 | /* |
---|
667 | * Convert a new format statfs structure to an old format statfs structure. |
---|
668 | */ |
---|
669 | static void |
---|
670 | freebsd4_cvtstatfs(struct statfs *nsp, struct ostatfs *osp) |
---|
671 | { |
---|
672 | |
---|
673 | statfs_scale_blocks(nsp, LONG_MAX); |
---|
674 | bzero(osp, sizeof(*osp)); |
---|
675 | osp->f_bsize = nsp->f_bsize; |
---|
676 | osp->f_iosize = MIN(nsp->f_iosize, LONG_MAX); |
---|
677 | osp->f_blocks = nsp->f_blocks; |
---|
678 | osp->f_bfree = nsp->f_bfree; |
---|
679 | osp->f_bavail = nsp->f_bavail; |
---|
680 | osp->f_files = MIN(nsp->f_files, LONG_MAX); |
---|
681 | osp->f_ffree = MIN(nsp->f_ffree, LONG_MAX); |
---|
682 | osp->f_owner = nsp->f_owner; |
---|
683 | osp->f_type = nsp->f_type; |
---|
684 | osp->f_flags = nsp->f_flags; |
---|
685 | osp->f_syncwrites = MIN(nsp->f_syncwrites, LONG_MAX); |
---|
686 | osp->f_asyncwrites = MIN(nsp->f_asyncwrites, LONG_MAX); |
---|
687 | osp->f_syncreads = MIN(nsp->f_syncreads, LONG_MAX); |
---|
688 | osp->f_asyncreads = MIN(nsp->f_asyncreads, LONG_MAX); |
---|
689 | strlcpy(osp->f_fstypename, nsp->f_fstypename, |
---|
690 | MIN(MFSNAMELEN, OMFSNAMELEN)); |
---|
691 | strlcpy(osp->f_mntonname, nsp->f_mntonname, |
---|
692 | MIN(MNAMELEN, OMNAMELEN)); |
---|
693 | strlcpy(osp->f_mntfromname, nsp->f_mntfromname, |
---|
694 | MIN(MNAMELEN, OMNAMELEN)); |
---|
695 | osp->f_fsid = nsp->f_fsid; |
---|
696 | } |
---|
697 | #endif /* COMPAT_FREEBSD4 */ |
---|
698 | |
---|
699 | #if defined(COMPAT_FREEBSD11) |
---|
700 | /* |
---|
701 | * Get old format filesystem statistics. |
---|
702 | */ |
---|
703 | static void freebsd11_cvtstatfs(struct statfs *, struct freebsd11_statfs *); |
---|
704 | |
---|
705 | int |
---|
706 | freebsd11_statfs(struct thread *td, struct freebsd11_statfs_args *uap) |
---|
707 | { |
---|
708 | struct freebsd11_statfs osb; |
---|
709 | struct statfs *sfp; |
---|
710 | int error; |
---|
711 | |
---|
712 | sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); |
---|
713 | error = kern_statfs(td, uap->path, UIO_USERSPACE, sfp); |
---|
714 | if (error == 0) { |
---|
715 | freebsd11_cvtstatfs(sfp, &osb); |
---|
716 | error = copyout(&osb, uap->buf, sizeof(osb)); |
---|
717 | } |
---|
718 | free(sfp, M_STATFS); |
---|
719 | return (error); |
---|
720 | } |
---|
721 | |
---|
722 | /* |
---|
723 | * Get filesystem statistics. |
---|
724 | */ |
---|
725 | int |
---|
726 | freebsd11_fstatfs(struct thread *td, struct freebsd11_fstatfs_args *uap) |
---|
727 | { |
---|
728 | struct freebsd11_statfs osb; |
---|
729 | struct statfs *sfp; |
---|
730 | int error; |
---|
731 | |
---|
732 | sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); |
---|
733 | error = kern_fstatfs(td, uap->fd, sfp); |
---|
734 | if (error == 0) { |
---|
735 | freebsd11_cvtstatfs(sfp, &osb); |
---|
736 | error = copyout(&osb, uap->buf, sizeof(osb)); |
---|
737 | } |
---|
738 | free(sfp, M_STATFS); |
---|
739 | return (error); |
---|
740 | } |
---|
741 | |
---|
742 | /* |
---|
743 | * Get statistics on all filesystems. |
---|
744 | */ |
---|
745 | int |
---|
746 | freebsd11_getfsstat(struct thread *td, struct freebsd11_getfsstat_args *uap) |
---|
747 | { |
---|
748 | struct freebsd11_statfs osb; |
---|
749 | struct statfs *buf, *sp; |
---|
750 | size_t count, size; |
---|
751 | int error; |
---|
752 | |
---|
753 | count = uap->bufsize / sizeof(struct ostatfs); |
---|
754 | size = count * sizeof(struct statfs); |
---|
755 | error = kern_getfsstat(td, &buf, size, &count, UIO_SYSSPACE, |
---|
756 | uap->mode); |
---|
757 | if (error == 0) |
---|
758 | td->td_retval[0] = count; |
---|
759 | if (size > 0) { |
---|
760 | sp = buf; |
---|
761 | while (count > 0 && error == 0) { |
---|
762 | freebsd11_cvtstatfs(sp, &osb); |
---|
763 | error = copyout(&osb, uap->buf, sizeof(osb)); |
---|
764 | sp++; |
---|
765 | uap->buf++; |
---|
766 | count--; |
---|
767 | } |
---|
768 | free(buf, M_STATFS); |
---|
769 | } |
---|
770 | return (error); |
---|
771 | } |
---|
772 | |
---|
773 | /* |
---|
774 | * Implement fstatfs() for (NFS) file handles. |
---|
775 | */ |
---|
776 | int |
---|
777 | freebsd11_fhstatfs(struct thread *td, struct freebsd11_fhstatfs_args *uap) |
---|
778 | { |
---|
779 | struct freebsd11_statfs osb; |
---|
780 | struct statfs *sfp; |
---|
781 | fhandle_t fh; |
---|
782 | int error; |
---|
783 | |
---|
784 | error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t)); |
---|
785 | if (error) |
---|
786 | return (error); |
---|
787 | sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); |
---|
788 | error = kern_fhstatfs(td, fh, sfp); |
---|
789 | if (error == 0) { |
---|
790 | freebsd11_cvtstatfs(sfp, &osb); |
---|
791 | error = copyout(&osb, uap->buf, sizeof(osb)); |
---|
792 | } |
---|
793 | free(sfp, M_STATFS); |
---|
794 | return (error); |
---|
795 | } |
---|
796 | |
---|
797 | /* |
---|
798 | * Convert a new format statfs structure to an old format statfs structure. |
---|
799 | */ |
---|
800 | static void |
---|
801 | freebsd11_cvtstatfs(struct statfs *nsp, struct freebsd11_statfs *osp) |
---|
802 | { |
---|
803 | |
---|
804 | bzero(osp, sizeof(*osp)); |
---|
805 | osp->f_version = FREEBSD11_STATFS_VERSION; |
---|
806 | osp->f_type = nsp->f_type; |
---|
807 | osp->f_flags = nsp->f_flags; |
---|
808 | osp->f_bsize = nsp->f_bsize; |
---|
809 | osp->f_iosize = nsp->f_iosize; |
---|
810 | osp->f_blocks = nsp->f_blocks; |
---|
811 | osp->f_bfree = nsp->f_bfree; |
---|
812 | osp->f_bavail = nsp->f_bavail; |
---|
813 | osp->f_files = nsp->f_files; |
---|
814 | osp->f_ffree = nsp->f_ffree; |
---|
815 | osp->f_syncwrites = nsp->f_syncwrites; |
---|
816 | osp->f_asyncwrites = nsp->f_asyncwrites; |
---|
817 | osp->f_syncreads = nsp->f_syncreads; |
---|
818 | osp->f_asyncreads = nsp->f_asyncreads; |
---|
819 | osp->f_namemax = nsp->f_namemax; |
---|
820 | osp->f_owner = nsp->f_owner; |
---|
821 | osp->f_fsid = nsp->f_fsid; |
---|
822 | strlcpy(osp->f_fstypename, nsp->f_fstypename, |
---|
823 | MIN(MFSNAMELEN, sizeof(osp->f_fstypename))); |
---|
824 | strlcpy(osp->f_mntonname, nsp->f_mntonname, |
---|
825 | MIN(MNAMELEN, sizeof(osp->f_mntonname))); |
---|
826 | strlcpy(osp->f_mntfromname, nsp->f_mntfromname, |
---|
827 | MIN(MNAMELEN, sizeof(osp->f_mntfromname))); |
---|
828 | } |
---|
829 | #endif /* COMPAT_FREEBSD11 */ |
---|
830 | |
---|
831 | /* |
---|
832 | * Change current working directory to a given file descriptor. |
---|
833 | */ |
---|
834 | #ifndef _SYS_SYSPROTO_H_ |
---|
835 | struct fchdir_args { |
---|
836 | int fd; |
---|
837 | }; |
---|
838 | #endif |
---|
839 | int |
---|
840 | sys_fchdir(struct thread *td, struct fchdir_args *uap) |
---|
841 | { |
---|
842 | struct vnode *vp, *tdp; |
---|
843 | struct mount *mp; |
---|
844 | struct file *fp; |
---|
845 | int error; |
---|
846 | |
---|
847 | AUDIT_ARG_FD(uap->fd); |
---|
848 | error = getvnode(td, uap->fd, &cap_fchdir_rights, |
---|
849 | &fp); |
---|
850 | if (error != 0) |
---|
851 | return (error); |
---|
852 | vp = fp->f_vnode; |
---|
853 | vrefact(vp); |
---|
854 | fdrop(fp, td); |
---|
855 | vn_lock(vp, LK_SHARED | LK_RETRY); |
---|
856 | AUDIT_ARG_VNODE1(vp); |
---|
857 | error = change_dir(vp, td); |
---|
858 | while (!error && (mp = vp->v_mountedhere) != NULL) { |
---|
859 | if (vfs_busy(mp, 0)) |
---|
860 | continue; |
---|
861 | error = VFS_ROOT(mp, LK_SHARED, &tdp); |
---|
862 | vfs_unbusy(mp); |
---|
863 | if (error != 0) |
---|
864 | break; |
---|
865 | vput(vp); |
---|
866 | vp = tdp; |
---|
867 | } |
---|
868 | if (error != 0) { |
---|
869 | vput(vp); |
---|
870 | return (error); |
---|
871 | } |
---|
872 | VOP_UNLOCK(vp, 0); |
---|
873 | pwd_chdir(td, vp); |
---|
874 | return (0); |
---|
875 | } |
---|
876 | |
---|
877 | /* |
---|
878 | * Change current working directory (``.''). |
---|
879 | */ |
---|
880 | #ifndef _SYS_SYSPROTO_H_ |
---|
881 | struct chdir_args { |
---|
882 | char *path; |
---|
883 | }; |
---|
884 | #endif |
---|
885 | int |
---|
886 | sys_chdir(struct thread *td, struct chdir_args *uap) |
---|
887 | { |
---|
888 | |
---|
889 | return (kern_chdir(td, uap->path, UIO_USERSPACE)); |
---|
890 | } |
---|
891 | |
---|
892 | int |
---|
893 | kern_chdir(struct thread *td, char *path, enum uio_seg pathseg) |
---|
894 | { |
---|
895 | struct nameidata nd; |
---|
896 | int error; |
---|
897 | |
---|
898 | NDINIT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | AUDITVNODE1, |
---|
899 | pathseg, path, td); |
---|
900 | if ((error = namei(&nd)) != 0) |
---|
901 | return (error); |
---|
902 | if ((error = change_dir(nd.ni_vp, td)) != 0) { |
---|
903 | vput(nd.ni_vp); |
---|
904 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
905 | return (error); |
---|
906 | } |
---|
907 | VOP_UNLOCK(nd.ni_vp, 0); |
---|
908 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
909 | pwd_chdir(td, nd.ni_vp); |
---|
910 | return (0); |
---|
911 | } |
---|
912 | |
---|
913 | #ifndef __rtems__ |
---|
914 | /* |
---|
915 | * Change notion of root (``/'') directory. |
---|
916 | */ |
---|
917 | #ifndef _SYS_SYSPROTO_H_ |
---|
918 | struct chroot_args { |
---|
919 | char *path; |
---|
920 | }; |
---|
921 | #endif |
---|
922 | int |
---|
923 | sys_chroot(struct thread *td, struct chroot_args *uap) |
---|
924 | { |
---|
925 | struct nameidata nd; |
---|
926 | int error; |
---|
927 | |
---|
928 | error = priv_check(td, PRIV_VFS_CHROOT); |
---|
929 | if (error != 0) |
---|
930 | return (error); |
---|
931 | NDINIT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | AUDITVNODE1, |
---|
932 | UIO_USERSPACE, uap->path, td); |
---|
933 | error = namei(&nd); |
---|
934 | if (error != 0) |
---|
935 | goto error; |
---|
936 | error = change_dir(nd.ni_vp, td); |
---|
937 | if (error != 0) |
---|
938 | goto e_vunlock; |
---|
939 | #ifdef MAC |
---|
940 | error = mac_vnode_check_chroot(td->td_ucred, nd.ni_vp); |
---|
941 | if (error != 0) |
---|
942 | goto e_vunlock; |
---|
943 | #endif |
---|
944 | VOP_UNLOCK(nd.ni_vp, 0); |
---|
945 | error = pwd_chroot(td, nd.ni_vp); |
---|
946 | vrele(nd.ni_vp); |
---|
947 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
948 | return (error); |
---|
949 | e_vunlock: |
---|
950 | vput(nd.ni_vp); |
---|
951 | error: |
---|
952 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
953 | return (error); |
---|
954 | } |
---|
955 | #endif /* __rtems__ */ |
---|
956 | |
---|
957 | /* |
---|
958 | * Common routine for chroot and chdir. Callers must provide a locked vnode |
---|
959 | * instance. |
---|
960 | */ |
---|
961 | int |
---|
962 | change_dir(struct vnode *vp, struct thread *td) |
---|
963 | { |
---|
964 | #ifdef MAC |
---|
965 | int error; |
---|
966 | #endif |
---|
967 | |
---|
968 | ASSERT_VOP_LOCKED(vp, "change_dir(): vp not locked"); |
---|
969 | if (vp->v_type != VDIR) |
---|
970 | return (ENOTDIR); |
---|
971 | #ifdef MAC |
---|
972 | error = mac_vnode_check_chdir(td->td_ucred, vp); |
---|
973 | if (error != 0) |
---|
974 | return (error); |
---|
975 | #endif |
---|
976 | return (VOP_ACCESS(vp, VEXEC, td->td_ucred, td)); |
---|
977 | } |
---|
978 | |
---|
979 | static __inline void |
---|
980 | flags_to_rights(int flags, cap_rights_t *rightsp) |
---|
981 | { |
---|
982 | |
---|
983 | if (flags & O_EXEC) { |
---|
984 | cap_rights_set(rightsp, CAP_FEXECVE); |
---|
985 | } else { |
---|
986 | switch ((flags & O_ACCMODE)) { |
---|
987 | case O_RDONLY: |
---|
988 | cap_rights_set(rightsp, CAP_READ); |
---|
989 | break; |
---|
990 | case O_RDWR: |
---|
991 | cap_rights_set(rightsp, CAP_READ); |
---|
992 | /* FALLTHROUGH */ |
---|
993 | case O_WRONLY: |
---|
994 | cap_rights_set(rightsp, CAP_WRITE); |
---|
995 | if (!(flags & (O_APPEND | O_TRUNC))) |
---|
996 | cap_rights_set(rightsp, CAP_SEEK); |
---|
997 | break; |
---|
998 | } |
---|
999 | } |
---|
1000 | |
---|
1001 | if (flags & O_CREAT) |
---|
1002 | cap_rights_set(rightsp, CAP_CREATE); |
---|
1003 | |
---|
1004 | if (flags & O_TRUNC) |
---|
1005 | cap_rights_set(rightsp, CAP_FTRUNCATE); |
---|
1006 | |
---|
1007 | if (flags & (O_SYNC | O_FSYNC)) |
---|
1008 | cap_rights_set(rightsp, CAP_FSYNC); |
---|
1009 | |
---|
1010 | #ifndef __rtems__ |
---|
1011 | if (flags & (O_EXLOCK | O_SHLOCK)) |
---|
1012 | cap_rights_set(rightsp, CAP_FLOCK); |
---|
1013 | #endif /* __rtems__ */ |
---|
1014 | } |
---|
1015 | |
---|
1016 | /* |
---|
1017 | * Check permissions, allocate an open file structure, and call the device |
---|
1018 | * open routine if any. |
---|
1019 | */ |
---|
1020 | #ifndef _SYS_SYSPROTO_H_ |
---|
1021 | struct open_args { |
---|
1022 | char *path; |
---|
1023 | int flags; |
---|
1024 | int mode; |
---|
1025 | }; |
---|
1026 | #endif |
---|
1027 | int |
---|
1028 | sys_open(struct thread *td, struct open_args *uap) |
---|
1029 | { |
---|
1030 | |
---|
1031 | return (kern_openat(td, AT_FDCWD, uap->path, UIO_USERSPACE, |
---|
1032 | uap->flags, uap->mode)); |
---|
1033 | } |
---|
1034 | |
---|
1035 | #ifndef _SYS_SYSPROTO_H_ |
---|
1036 | struct openat_args { |
---|
1037 | int fd; |
---|
1038 | char *path; |
---|
1039 | int flag; |
---|
1040 | int mode; |
---|
1041 | }; |
---|
1042 | #endif |
---|
1043 | int |
---|
1044 | sys_openat(struct thread *td, struct openat_args *uap) |
---|
1045 | { |
---|
1046 | |
---|
1047 | AUDIT_ARG_FD(uap->fd); |
---|
1048 | return (kern_openat(td, uap->fd, uap->path, UIO_USERSPACE, uap->flag, |
---|
1049 | uap->mode)); |
---|
1050 | } |
---|
1051 | |
---|
1052 | int |
---|
1053 | kern_openat(struct thread *td, int fd, char *path, enum uio_seg pathseg, |
---|
1054 | int flags, int mode) |
---|
1055 | { |
---|
1056 | struct proc *p = td->td_proc; |
---|
1057 | struct filedesc *fdp = p->p_fd; |
---|
1058 | struct file *fp; |
---|
1059 | struct vnode *vp; |
---|
1060 | struct nameidata nd; |
---|
1061 | cap_rights_t rights; |
---|
1062 | int cmode, error, indx; |
---|
1063 | |
---|
1064 | indx = -1; |
---|
1065 | |
---|
1066 | AUDIT_ARG_FFLAGS(flags); |
---|
1067 | AUDIT_ARG_MODE(mode); |
---|
1068 | cap_rights_init(&rights, CAP_LOOKUP); |
---|
1069 | flags_to_rights(flags, &rights); |
---|
1070 | /* |
---|
1071 | * Only one of the O_EXEC, O_RDONLY, O_WRONLY and O_RDWR flags |
---|
1072 | * may be specified. |
---|
1073 | */ |
---|
1074 | #ifndef __rtems__ |
---|
1075 | if (flags & O_EXEC) { |
---|
1076 | if (flags & O_ACCMODE) |
---|
1077 | return (EINVAL); |
---|
1078 | #else /* __rtems__ */ |
---|
1079 | if (false) { |
---|
1080 | #endif /* __rtems__ */ |
---|
1081 | } else if ((flags & O_ACCMODE) == O_ACCMODE) { |
---|
1082 | return (EINVAL); |
---|
1083 | } else { |
---|
1084 | flags = FFLAGS(flags); |
---|
1085 | } |
---|
1086 | |
---|
1087 | /* |
---|
1088 | * Allocate a file structure. The descriptor to reference it |
---|
1089 | * is allocated and set by finstall() below. |
---|
1090 | */ |
---|
1091 | error = falloc_noinstall(td, &fp); |
---|
1092 | if (error != 0) |
---|
1093 | return (error); |
---|
1094 | /* |
---|
1095 | * An extra reference on `fp' has been held for us by |
---|
1096 | * falloc_noinstall(). |
---|
1097 | */ |
---|
1098 | /* Set the flags early so the finit in devfs can pick them up. */ |
---|
1099 | fp->f_flag = flags & FMASK; |
---|
1100 | #ifndef __rtems__ |
---|
1101 | cmode = ((mode & ~fdp->fd_cmask) & ALLPERMS) & ~S_ISTXT; |
---|
1102 | #else /* __rtems__ */ |
---|
1103 | cmode = (mode & ~fdp->fd_cmask) & ALLPERMS; |
---|
1104 | #endif /* __rtems__ */ |
---|
1105 | NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | AUDITVNODE1, pathseg, path, fd, |
---|
1106 | &rights, td); |
---|
1107 | #ifndef __rtems__ |
---|
1108 | td->td_dupfd = -1; /* XXX check for fdopen */ |
---|
1109 | #endif /* __rtems__ */ |
---|
1110 | error = vn_open(&nd, &flags, cmode, fp); |
---|
1111 | if (error != 0) { |
---|
1112 | /* |
---|
1113 | * If the vn_open replaced the method vector, something |
---|
1114 | * wonderous happened deep below and we just pass it up |
---|
1115 | * pretending we know what we do. |
---|
1116 | */ |
---|
1117 | if (error == ENXIO && fp->f_ops != &badfileops) |
---|
1118 | goto success; |
---|
1119 | |
---|
1120 | /* |
---|
1121 | * Handle special fdopen() case. bleh. |
---|
1122 | * |
---|
1123 | * Don't do this for relative (capability) lookups; we don't |
---|
1124 | * understand exactly what would happen, and we don't think |
---|
1125 | * that it ever should. |
---|
1126 | */ |
---|
1127 | if ((nd.ni_lcf & NI_LCF_STRICTRELATIVE) == 0 && |
---|
1128 | (error == ENODEV || error == ENXIO) && |
---|
1129 | #ifndef __rtems__ |
---|
1130 | td->td_dupfd >= 0) { |
---|
1131 | error = dupfdopen(td, fdp, td->td_dupfd, flags, error, |
---|
1132 | &indx); |
---|
1133 | if (error == 0) |
---|
1134 | goto success; |
---|
1135 | #else /* __rtems__ */ |
---|
1136 | true) { |
---|
1137 | panic("fdopen() dup"); |
---|
1138 | #endif /* __rtems__ */ |
---|
1139 | } |
---|
1140 | |
---|
1141 | goto bad; |
---|
1142 | } |
---|
1143 | #ifndef __rtems__ |
---|
1144 | td->td_dupfd = 0; |
---|
1145 | #endif /* __rtems__ */ |
---|
1146 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
1147 | vp = nd.ni_vp; |
---|
1148 | |
---|
1149 | /* |
---|
1150 | * Store the vnode, for any f_type. Typically, the vnode use |
---|
1151 | * count is decremented by direct call to vn_closefile() for |
---|
1152 | * files that switched type in the cdevsw fdopen() method. |
---|
1153 | */ |
---|
1154 | fp->f_vnode = vp; |
---|
1155 | /* |
---|
1156 | * If the file wasn't claimed by devfs bind it to the normal |
---|
1157 | * vnode operations here. |
---|
1158 | */ |
---|
1159 | if (fp->f_ops == &badfileops) { |
---|
1160 | KASSERT(vp->v_type != VFIFO, ("Unexpected fifo.")); |
---|
1161 | fp->f_seqcount = 1; |
---|
1162 | finit(fp, (flags & FMASK) | (fp->f_flag & FHASLOCK), |
---|
1163 | DTYPE_VNODE, vp, &vnops); |
---|
1164 | } |
---|
1165 | |
---|
1166 | VOP_UNLOCK(vp, 0); |
---|
1167 | if (flags & O_TRUNC) { |
---|
1168 | error = fo_truncate(fp, 0, td->td_ucred, td); |
---|
1169 | if (error != 0) |
---|
1170 | goto bad; |
---|
1171 | } |
---|
1172 | success: |
---|
1173 | /* |
---|
1174 | * If we haven't already installed the FD (for dupfdopen), do so now. |
---|
1175 | */ |
---|
1176 | if (indx == -1) { |
---|
1177 | struct filecaps *fcaps; |
---|
1178 | |
---|
1179 | #ifdef CAPABILITIES |
---|
1180 | if ((nd.ni_lcf & NI_LCF_STRICTRELATIVE) != 0) |
---|
1181 | fcaps = &nd.ni_filecaps; |
---|
1182 | else |
---|
1183 | #endif |
---|
1184 | fcaps = NULL; |
---|
1185 | error = finstall(td, fp, &indx, flags, fcaps); |
---|
1186 | /* On success finstall() consumes fcaps. */ |
---|
1187 | if (error != 0) { |
---|
1188 | filecaps_free(&nd.ni_filecaps); |
---|
1189 | goto bad; |
---|
1190 | } |
---|
1191 | } else { |
---|
1192 | filecaps_free(&nd.ni_filecaps); |
---|
1193 | } |
---|
1194 | |
---|
1195 | /* |
---|
1196 | * Release our private reference, leaving the one associated with |
---|
1197 | * the descriptor table intact. |
---|
1198 | */ |
---|
1199 | fdrop(fp, td); |
---|
1200 | td->td_retval[0] = indx; |
---|
1201 | return (0); |
---|
1202 | bad: |
---|
1203 | KASSERT(indx == -1, ("indx=%d, should be -1", indx)); |
---|
1204 | fdrop(fp, td); |
---|
1205 | return (error); |
---|
1206 | } |
---|
1207 | |
---|
1208 | #ifdef COMPAT_43 |
---|
1209 | /* |
---|
1210 | * Create a file. |
---|
1211 | */ |
---|
1212 | #ifndef _SYS_SYSPROTO_H_ |
---|
1213 | struct ocreat_args { |
---|
1214 | char *path; |
---|
1215 | int mode; |
---|
1216 | }; |
---|
1217 | #endif |
---|
1218 | int |
---|
1219 | ocreat(struct thread *td, struct ocreat_args *uap) |
---|
1220 | { |
---|
1221 | |
---|
1222 | return (kern_openat(td, AT_FDCWD, uap->path, UIO_USERSPACE, |
---|
1223 | O_WRONLY | O_CREAT | O_TRUNC, uap->mode)); |
---|
1224 | } |
---|
1225 | #endif /* COMPAT_43 */ |
---|
1226 | |
---|
1227 | /* |
---|
1228 | * Create a special file. |
---|
1229 | */ |
---|
1230 | #ifndef _SYS_SYSPROTO_H_ |
---|
1231 | struct mknodat_args { |
---|
1232 | int fd; |
---|
1233 | char *path; |
---|
1234 | mode_t mode; |
---|
1235 | dev_t dev; |
---|
1236 | }; |
---|
1237 | #endif |
---|
1238 | int |
---|
1239 | sys_mknodat(struct thread *td, struct mknodat_args *uap) |
---|
1240 | { |
---|
1241 | |
---|
1242 | return (kern_mknodat(td, uap->fd, uap->path, UIO_USERSPACE, uap->mode, |
---|
1243 | uap->dev)); |
---|
1244 | } |
---|
1245 | |
---|
1246 | #if defined(COMPAT_FREEBSD11) |
---|
1247 | int |
---|
1248 | freebsd11_mknod(struct thread *td, |
---|
1249 | struct freebsd11_mknod_args *uap) |
---|
1250 | { |
---|
1251 | |
---|
1252 | return (kern_mknodat(td, AT_FDCWD, uap->path, UIO_USERSPACE, |
---|
1253 | uap->mode, uap->dev)); |
---|
1254 | } |
---|
1255 | |
---|
1256 | int |
---|
1257 | freebsd11_mknodat(struct thread *td, |
---|
1258 | struct freebsd11_mknodat_args *uap) |
---|
1259 | { |
---|
1260 | |
---|
1261 | return (kern_mknodat(td, uap->fd, uap->path, UIO_USERSPACE, uap->mode, |
---|
1262 | uap->dev)); |
---|
1263 | } |
---|
1264 | #endif /* COMPAT_FREEBSD11 */ |
---|
1265 | |
---|
1266 | int |
---|
1267 | kern_mknodat(struct thread *td, int fd, char *path, enum uio_seg pathseg, |
---|
1268 | int mode, dev_t dev) |
---|
1269 | { |
---|
1270 | struct vnode *vp; |
---|
1271 | struct mount *mp; |
---|
1272 | struct vattr vattr; |
---|
1273 | struct nameidata nd; |
---|
1274 | int error, whiteout = 0; |
---|
1275 | |
---|
1276 | AUDIT_ARG_MODE(mode); |
---|
1277 | AUDIT_ARG_DEV(dev); |
---|
1278 | switch (mode & S_IFMT) { |
---|
1279 | case S_IFCHR: |
---|
1280 | case S_IFBLK: |
---|
1281 | error = priv_check(td, PRIV_VFS_MKNOD_DEV); |
---|
1282 | if (error == 0 && dev == VNOVAL) |
---|
1283 | error = EINVAL; |
---|
1284 | break; |
---|
1285 | #ifndef __rtems__ |
---|
1286 | case S_IFWHT: |
---|
1287 | error = priv_check(td, PRIV_VFS_MKNOD_WHT); |
---|
1288 | break; |
---|
1289 | #endif /* __rtems__ */ |
---|
1290 | case S_IFIFO: |
---|
1291 | #ifndef __rtems__ |
---|
1292 | if (dev == 0) |
---|
1293 | return (kern_mkfifoat(td, fd, path, pathseg, mode)); |
---|
1294 | #endif /* __rtems__ */ |
---|
1295 | /* FALLTHROUGH */ |
---|
1296 | default: |
---|
1297 | error = EINVAL; |
---|
1298 | break; |
---|
1299 | } |
---|
1300 | if (error != 0) |
---|
1301 | return (error); |
---|
1302 | restart: |
---|
1303 | bwillwrite(); |
---|
1304 | NDINIT_ATRIGHTS(&nd, CREATE, LOCKPARENT | SAVENAME | AUDITVNODE1 | |
---|
1305 | NOCACHE, pathseg, path, fd, &cap_mknodat_rights, |
---|
1306 | td); |
---|
1307 | if ((error = namei(&nd)) != 0) |
---|
1308 | return (error); |
---|
1309 | vp = nd.ni_vp; |
---|
1310 | if (vp != NULL) { |
---|
1311 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
1312 | if (vp == nd.ni_dvp) |
---|
1313 | vrele(nd.ni_dvp); |
---|
1314 | else |
---|
1315 | vput(nd.ni_dvp); |
---|
1316 | vrele(vp); |
---|
1317 | return (EEXIST); |
---|
1318 | } else { |
---|
1319 | VATTR_NULL(&vattr); |
---|
1320 | vattr.va_mode = (mode & ALLPERMS) & |
---|
1321 | ~td->td_proc->p_fd->fd_cmask; |
---|
1322 | vattr.va_rdev = dev; |
---|
1323 | whiteout = 0; |
---|
1324 | |
---|
1325 | switch (mode & S_IFMT) { |
---|
1326 | case S_IFCHR: |
---|
1327 | vattr.va_type = VCHR; |
---|
1328 | break; |
---|
1329 | case S_IFBLK: |
---|
1330 | vattr.va_type = VBLK; |
---|
1331 | break; |
---|
1332 | #ifndef __rtems__ |
---|
1333 | case S_IFWHT: |
---|
1334 | whiteout = 1; |
---|
1335 | break; |
---|
1336 | #endif /* __rtems__ */ |
---|
1337 | default: |
---|
1338 | panic("kern_mknod: invalid mode"); |
---|
1339 | } |
---|
1340 | } |
---|
1341 | if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { |
---|
1342 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
1343 | vput(nd.ni_dvp); |
---|
1344 | if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0) |
---|
1345 | return (error); |
---|
1346 | goto restart; |
---|
1347 | } |
---|
1348 | #ifdef MAC |
---|
1349 | if (error == 0 && !whiteout) |
---|
1350 | error = mac_vnode_check_create(td->td_ucred, nd.ni_dvp, |
---|
1351 | &nd.ni_cnd, &vattr); |
---|
1352 | #endif |
---|
1353 | if (error == 0) { |
---|
1354 | if (whiteout) |
---|
1355 | error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE); |
---|
1356 | else { |
---|
1357 | error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, |
---|
1358 | &nd.ni_cnd, &vattr); |
---|
1359 | if (error == 0) |
---|
1360 | vput(nd.ni_vp); |
---|
1361 | } |
---|
1362 | } |
---|
1363 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
1364 | vput(nd.ni_dvp); |
---|
1365 | vn_finished_write(mp); |
---|
1366 | return (error); |
---|
1367 | } |
---|
1368 | |
---|
1369 | #ifndef __rtems__ |
---|
1370 | /* |
---|
1371 | * Create a named pipe. |
---|
1372 | */ |
---|
1373 | #ifndef _SYS_SYSPROTO_H_ |
---|
1374 | struct mkfifo_args { |
---|
1375 | char *path; |
---|
1376 | int mode; |
---|
1377 | }; |
---|
1378 | #endif |
---|
1379 | int |
---|
1380 | sys_mkfifo(struct thread *td, struct mkfifo_args *uap) |
---|
1381 | { |
---|
1382 | |
---|
1383 | return (kern_mkfifoat(td, AT_FDCWD, uap->path, UIO_USERSPACE, |
---|
1384 | uap->mode)); |
---|
1385 | } |
---|
1386 | |
---|
1387 | #ifndef _SYS_SYSPROTO_H_ |
---|
1388 | struct mkfifoat_args { |
---|
1389 | int fd; |
---|
1390 | char *path; |
---|
1391 | mode_t mode; |
---|
1392 | }; |
---|
1393 | #endif |
---|
1394 | int |
---|
1395 | sys_mkfifoat(struct thread *td, struct mkfifoat_args *uap) |
---|
1396 | { |
---|
1397 | |
---|
1398 | return (kern_mkfifoat(td, uap->fd, uap->path, UIO_USERSPACE, |
---|
1399 | uap->mode)); |
---|
1400 | } |
---|
1401 | |
---|
1402 | int |
---|
1403 | kern_mkfifoat(struct thread *td, int fd, char *path, enum uio_seg pathseg, |
---|
1404 | int mode) |
---|
1405 | { |
---|
1406 | struct mount *mp; |
---|
1407 | struct vattr vattr; |
---|
1408 | struct nameidata nd; |
---|
1409 | int error; |
---|
1410 | |
---|
1411 | AUDIT_ARG_MODE(mode); |
---|
1412 | restart: |
---|
1413 | bwillwrite(); |
---|
1414 | NDINIT_ATRIGHTS(&nd, CREATE, LOCKPARENT | SAVENAME | AUDITVNODE1 | |
---|
1415 | NOCACHE, pathseg, path, fd, &cap_mkfifoat_rights, |
---|
1416 | td); |
---|
1417 | if ((error = namei(&nd)) != 0) |
---|
1418 | return (error); |
---|
1419 | if (nd.ni_vp != NULL) { |
---|
1420 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
1421 | if (nd.ni_vp == nd.ni_dvp) |
---|
1422 | vrele(nd.ni_dvp); |
---|
1423 | else |
---|
1424 | vput(nd.ni_dvp); |
---|
1425 | vrele(nd.ni_vp); |
---|
1426 | return (EEXIST); |
---|
1427 | } |
---|
1428 | if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { |
---|
1429 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
1430 | vput(nd.ni_dvp); |
---|
1431 | if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0) |
---|
1432 | return (error); |
---|
1433 | goto restart; |
---|
1434 | } |
---|
1435 | VATTR_NULL(&vattr); |
---|
1436 | vattr.va_type = VFIFO; |
---|
1437 | vattr.va_mode = (mode & ALLPERMS) & ~td->td_proc->p_fd->fd_cmask; |
---|
1438 | #ifdef MAC |
---|
1439 | error = mac_vnode_check_create(td->td_ucred, nd.ni_dvp, &nd.ni_cnd, |
---|
1440 | &vattr); |
---|
1441 | if (error != 0) |
---|
1442 | goto out; |
---|
1443 | #endif |
---|
1444 | error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); |
---|
1445 | if (error == 0) |
---|
1446 | vput(nd.ni_vp); |
---|
1447 | #ifdef MAC |
---|
1448 | out: |
---|
1449 | #endif |
---|
1450 | vput(nd.ni_dvp); |
---|
1451 | vn_finished_write(mp); |
---|
1452 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
1453 | return (error); |
---|
1454 | } |
---|
1455 | #endif /* __rtems__ */ |
---|
1456 | |
---|
1457 | /* |
---|
1458 | * Make a hard file link. |
---|
1459 | */ |
---|
1460 | #ifndef _SYS_SYSPROTO_H_ |
---|
1461 | struct link_args { |
---|
1462 | char *path; |
---|
1463 | char *link; |
---|
1464 | }; |
---|
1465 | #endif |
---|
1466 | int |
---|
1467 | sys_link(struct thread *td, struct link_args *uap) |
---|
1468 | { |
---|
1469 | |
---|
1470 | return (kern_linkat(td, AT_FDCWD, AT_FDCWD, uap->path, uap->link, |
---|
1471 | UIO_USERSPACE, FOLLOW)); |
---|
1472 | } |
---|
1473 | |
---|
1474 | #ifndef _SYS_SYSPROTO_H_ |
---|
1475 | struct linkat_args { |
---|
1476 | int fd1; |
---|
1477 | char *path1; |
---|
1478 | int fd2; |
---|
1479 | char *path2; |
---|
1480 | int flag; |
---|
1481 | }; |
---|
1482 | #endif |
---|
1483 | int |
---|
1484 | sys_linkat(struct thread *td, struct linkat_args *uap) |
---|
1485 | { |
---|
1486 | int flag; |
---|
1487 | |
---|
1488 | flag = uap->flag; |
---|
1489 | if (flag & ~AT_SYMLINK_FOLLOW) |
---|
1490 | return (EINVAL); |
---|
1491 | |
---|
1492 | return (kern_linkat(td, uap->fd1, uap->fd2, uap->path1, uap->path2, |
---|
1493 | UIO_USERSPACE, (flag & AT_SYMLINK_FOLLOW) ? FOLLOW : NOFOLLOW)); |
---|
1494 | } |
---|
1495 | |
---|
1496 | int hardlink_check_uid = 0; |
---|
1497 | #ifndef __rtems__ |
---|
1498 | SYSCTL_INT(_security_bsd, OID_AUTO, hardlink_check_uid, CTLFLAG_RW, |
---|
1499 | &hardlink_check_uid, 0, |
---|
1500 | "Unprivileged processes cannot create hard links to files owned by other " |
---|
1501 | "users"); |
---|
1502 | #endif /* __rtems__ */ |
---|
1503 | static int hardlink_check_gid = 0; |
---|
1504 | #ifndef __rtems__ |
---|
1505 | SYSCTL_INT(_security_bsd, OID_AUTO, hardlink_check_gid, CTLFLAG_RW, |
---|
1506 | &hardlink_check_gid, 0, |
---|
1507 | "Unprivileged processes cannot create hard links to files owned by other " |
---|
1508 | "groups"); |
---|
1509 | #endif /* __rtems__ */ |
---|
1510 | |
---|
1511 | static int |
---|
1512 | can_hardlink(struct vnode *vp, struct ucred *cred) |
---|
1513 | { |
---|
1514 | struct vattr va; |
---|
1515 | int error; |
---|
1516 | |
---|
1517 | if (!hardlink_check_uid && !hardlink_check_gid) |
---|
1518 | return (0); |
---|
1519 | |
---|
1520 | error = VOP_GETATTR(vp, &va, cred); |
---|
1521 | if (error != 0) |
---|
1522 | return (error); |
---|
1523 | |
---|
1524 | if (hardlink_check_uid && cred->cr_uid != va.va_uid) { |
---|
1525 | error = priv_check_cred(cred, PRIV_VFS_LINK, 0); |
---|
1526 | if (error != 0) |
---|
1527 | return (error); |
---|
1528 | } |
---|
1529 | |
---|
1530 | if (hardlink_check_gid && !groupmember(va.va_gid, cred)) { |
---|
1531 | error = priv_check_cred(cred, PRIV_VFS_LINK, 0); |
---|
1532 | if (error != 0) |
---|
1533 | return (error); |
---|
1534 | } |
---|
1535 | |
---|
1536 | return (0); |
---|
1537 | } |
---|
1538 | |
---|
1539 | int |
---|
1540 | kern_linkat(struct thread *td, int fd1, int fd2, char *path1, char *path2, |
---|
1541 | enum uio_seg segflag, int follow) |
---|
1542 | { |
---|
1543 | struct nameidata nd; |
---|
1544 | int error; |
---|
1545 | |
---|
1546 | do { |
---|
1547 | bwillwrite(); |
---|
1548 | NDINIT_ATRIGHTS(&nd, LOOKUP, follow | AUDITVNODE1, segflag, |
---|
1549 | path1, fd1, &cap_linkat_source_rights, td); |
---|
1550 | if ((error = namei(&nd)) != 0) |
---|
1551 | return (error); |
---|
1552 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
1553 | error = kern_linkat_vp(td, nd.ni_vp, fd2, path2, segflag); |
---|
1554 | } while (error == EAGAIN); |
---|
1555 | return (error); |
---|
1556 | } |
---|
1557 | |
---|
1558 | static int |
---|
1559 | kern_linkat_vp(struct thread *td, struct vnode *vp, int fd, const char *path, |
---|
1560 | enum uio_seg segflag) |
---|
1561 | { |
---|
1562 | struct nameidata nd; |
---|
1563 | struct mount *mp; |
---|
1564 | int error; |
---|
1565 | |
---|
1566 | if (vp->v_type == VDIR) { |
---|
1567 | vrele(vp); |
---|
1568 | return (EPERM); /* POSIX */ |
---|
1569 | } |
---|
1570 | NDINIT_ATRIGHTS(&nd, CREATE, |
---|
1571 | LOCKPARENT | SAVENAME | AUDITVNODE2 | NOCACHE, segflag, path, fd, |
---|
1572 | &cap_linkat_target_rights, td); |
---|
1573 | if ((error = namei(&nd)) == 0) { |
---|
1574 | if (nd.ni_vp != NULL) { |
---|
1575 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
1576 | if (nd.ni_dvp == nd.ni_vp) |
---|
1577 | vrele(nd.ni_dvp); |
---|
1578 | else |
---|
1579 | vput(nd.ni_dvp); |
---|
1580 | vrele(nd.ni_vp); |
---|
1581 | vrele(vp); |
---|
1582 | return (EEXIST); |
---|
1583 | } else if (nd.ni_dvp->v_mount != vp->v_mount) { |
---|
1584 | /* |
---|
1585 | * Cross-device link. No need to recheck |
---|
1586 | * vp->v_type, since it cannot change, except |
---|
1587 | * to VBAD. |
---|
1588 | */ |
---|
1589 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
1590 | vput(nd.ni_dvp); |
---|
1591 | vrele(vp); |
---|
1592 | return (EXDEV); |
---|
1593 | } else if ((error = vn_lock(vp, LK_EXCLUSIVE)) == 0) { |
---|
1594 | error = can_hardlink(vp, td->td_ucred); |
---|
1595 | #ifdef MAC |
---|
1596 | if (error == 0) |
---|
1597 | error = mac_vnode_check_link(td->td_ucred, |
---|
1598 | nd.ni_dvp, vp, &nd.ni_cnd); |
---|
1599 | #endif |
---|
1600 | if (error != 0) { |
---|
1601 | vput(vp); |
---|
1602 | vput(nd.ni_dvp); |
---|
1603 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
1604 | return (error); |
---|
1605 | } |
---|
1606 | error = vn_start_write(vp, &mp, V_NOWAIT); |
---|
1607 | if (error != 0) { |
---|
1608 | vput(vp); |
---|
1609 | vput(nd.ni_dvp); |
---|
1610 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
1611 | error = vn_start_write(NULL, &mp, |
---|
1612 | V_XSLEEP | PCATCH); |
---|
1613 | if (error != 0) |
---|
1614 | return (error); |
---|
1615 | return (EAGAIN); |
---|
1616 | } |
---|
1617 | error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); |
---|
1618 | VOP_UNLOCK(vp, 0); |
---|
1619 | vput(nd.ni_dvp); |
---|
1620 | vn_finished_write(mp); |
---|
1621 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
1622 | } else { |
---|
1623 | vput(nd.ni_dvp); |
---|
1624 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
1625 | vrele(vp); |
---|
1626 | return (EAGAIN); |
---|
1627 | } |
---|
1628 | } |
---|
1629 | vrele(vp); |
---|
1630 | return (error); |
---|
1631 | } |
---|
1632 | |
---|
1633 | /* |
---|
1634 | * Make a symbolic link. |
---|
1635 | */ |
---|
1636 | #ifndef _SYS_SYSPROTO_H_ |
---|
1637 | struct symlink_args { |
---|
1638 | char *path; |
---|
1639 | char *link; |
---|
1640 | }; |
---|
1641 | #endif |
---|
1642 | int |
---|
1643 | sys_symlink(struct thread *td, struct symlink_args *uap) |
---|
1644 | { |
---|
1645 | |
---|
1646 | return (kern_symlinkat(td, uap->path, AT_FDCWD, uap->link, |
---|
1647 | UIO_USERSPACE)); |
---|
1648 | } |
---|
1649 | |
---|
1650 | #ifndef _SYS_SYSPROTO_H_ |
---|
1651 | struct symlinkat_args { |
---|
1652 | char *path; |
---|
1653 | int fd; |
---|
1654 | char *path2; |
---|
1655 | }; |
---|
1656 | #endif |
---|
1657 | int |
---|
1658 | sys_symlinkat(struct thread *td, struct symlinkat_args *uap) |
---|
1659 | { |
---|
1660 | |
---|
1661 | return (kern_symlinkat(td, uap->path1, uap->fd, uap->path2, |
---|
1662 | UIO_USERSPACE)); |
---|
1663 | } |
---|
1664 | |
---|
1665 | int |
---|
1666 | kern_symlinkat(struct thread *td, char *path1, int fd, char *path2, |
---|
1667 | enum uio_seg segflg) |
---|
1668 | { |
---|
1669 | struct mount *mp; |
---|
1670 | struct vattr vattr; |
---|
1671 | char *syspath; |
---|
1672 | struct nameidata nd; |
---|
1673 | int error; |
---|
1674 | |
---|
1675 | if (segflg == UIO_SYSSPACE) { |
---|
1676 | syspath = path1; |
---|
1677 | } else { |
---|
1678 | syspath = uma_zalloc(namei_zone, M_WAITOK); |
---|
1679 | if ((error = copyinstr(path1, syspath, MAXPATHLEN, NULL)) != 0) |
---|
1680 | goto out; |
---|
1681 | } |
---|
1682 | AUDIT_ARG_TEXT(syspath); |
---|
1683 | restart: |
---|
1684 | bwillwrite(); |
---|
1685 | NDINIT_ATRIGHTS(&nd, CREATE, LOCKPARENT | SAVENAME | AUDITVNODE1 | |
---|
1686 | NOCACHE, segflg, path2, fd, &cap_symlinkat_rights, |
---|
1687 | td); |
---|
1688 | if ((error = namei(&nd)) != 0) |
---|
1689 | goto out; |
---|
1690 | if (nd.ni_vp) { |
---|
1691 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
1692 | if (nd.ni_vp == nd.ni_dvp) |
---|
1693 | vrele(nd.ni_dvp); |
---|
1694 | else |
---|
1695 | vput(nd.ni_dvp); |
---|
1696 | vrele(nd.ni_vp); |
---|
1697 | error = EEXIST; |
---|
1698 | goto out; |
---|
1699 | } |
---|
1700 | if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { |
---|
1701 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
1702 | vput(nd.ni_dvp); |
---|
1703 | if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0) |
---|
1704 | goto out; |
---|
1705 | goto restart; |
---|
1706 | } |
---|
1707 | VATTR_NULL(&vattr); |
---|
1708 | vattr.va_mode = ACCESSPERMS &~ td->td_proc->p_fd->fd_cmask; |
---|
1709 | #ifdef MAC |
---|
1710 | vattr.va_type = VLNK; |
---|
1711 | error = mac_vnode_check_create(td->td_ucred, nd.ni_dvp, &nd.ni_cnd, |
---|
1712 | &vattr); |
---|
1713 | if (error != 0) |
---|
1714 | goto out2; |
---|
1715 | #endif |
---|
1716 | error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, syspath); |
---|
1717 | if (error == 0) |
---|
1718 | vput(nd.ni_vp); |
---|
1719 | #ifdef MAC |
---|
1720 | out2: |
---|
1721 | #endif |
---|
1722 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
1723 | vput(nd.ni_dvp); |
---|
1724 | vn_finished_write(mp); |
---|
1725 | out: |
---|
1726 | if (segflg != UIO_SYSSPACE) |
---|
1727 | uma_zfree(namei_zone, syspath); |
---|
1728 | return (error); |
---|
1729 | } |
---|
1730 | |
---|
1731 | #ifndef __rtems__ |
---|
1732 | /* |
---|
1733 | * Delete a whiteout from the filesystem. |
---|
1734 | */ |
---|
1735 | #ifndef _SYS_SYSPROTO_H_ |
---|
1736 | struct undelete_args { |
---|
1737 | char *path; |
---|
1738 | }; |
---|
1739 | #endif |
---|
1740 | int |
---|
1741 | sys_undelete(struct thread *td, struct undelete_args *uap) |
---|
1742 | { |
---|
1743 | struct mount *mp; |
---|
1744 | struct nameidata nd; |
---|
1745 | int error; |
---|
1746 | |
---|
1747 | restart: |
---|
1748 | bwillwrite(); |
---|
1749 | NDINIT(&nd, DELETE, LOCKPARENT | DOWHITEOUT | AUDITVNODE1, |
---|
1750 | UIO_USERSPACE, uap->path, td); |
---|
1751 | error = namei(&nd); |
---|
1752 | if (error != 0) |
---|
1753 | return (error); |
---|
1754 | |
---|
1755 | if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) { |
---|
1756 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
1757 | if (nd.ni_vp == nd.ni_dvp) |
---|
1758 | vrele(nd.ni_dvp); |
---|
1759 | else |
---|
1760 | vput(nd.ni_dvp); |
---|
1761 | if (nd.ni_vp) |
---|
1762 | vrele(nd.ni_vp); |
---|
1763 | return (EEXIST); |
---|
1764 | } |
---|
1765 | if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { |
---|
1766 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
1767 | vput(nd.ni_dvp); |
---|
1768 | if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0) |
---|
1769 | return (error); |
---|
1770 | goto restart; |
---|
1771 | } |
---|
1772 | error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE); |
---|
1773 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
1774 | vput(nd.ni_dvp); |
---|
1775 | vn_finished_write(mp); |
---|
1776 | return (error); |
---|
1777 | } |
---|
1778 | #endif /* __rtems__ */ |
---|
1779 | |
---|
1780 | /* |
---|
1781 | * Delete a name from the filesystem. |
---|
1782 | */ |
---|
1783 | #ifndef _SYS_SYSPROTO_H_ |
---|
1784 | struct unlink_args { |
---|
1785 | char *path; |
---|
1786 | }; |
---|
1787 | #endif |
---|
1788 | int |
---|
1789 | sys_unlink(struct thread *td, struct unlink_args *uap) |
---|
1790 | { |
---|
1791 | |
---|
1792 | return (kern_unlinkat(td, AT_FDCWD, uap->path, UIO_USERSPACE, 0)); |
---|
1793 | } |
---|
1794 | |
---|
1795 | #ifndef _SYS_SYSPROTO_H_ |
---|
1796 | struct unlinkat_args { |
---|
1797 | int fd; |
---|
1798 | char *path; |
---|
1799 | int flag; |
---|
1800 | }; |
---|
1801 | #endif |
---|
1802 | int |
---|
1803 | sys_unlinkat(struct thread *td, struct unlinkat_args *uap) |
---|
1804 | { |
---|
1805 | int flag = uap->flag; |
---|
1806 | int fd = uap->fd; |
---|
1807 | char *path = uap->path; |
---|
1808 | |
---|
1809 | if (flag & ~AT_REMOVEDIR) |
---|
1810 | return (EINVAL); |
---|
1811 | |
---|
1812 | if (flag & AT_REMOVEDIR) |
---|
1813 | return (kern_rmdirat(td, fd, path, UIO_USERSPACE)); |
---|
1814 | else |
---|
1815 | return (kern_unlinkat(td, fd, path, UIO_USERSPACE, 0)); |
---|
1816 | } |
---|
1817 | |
---|
1818 | int |
---|
1819 | kern_unlinkat(struct thread *td, int fd, char *path, enum uio_seg pathseg, |
---|
1820 | ino_t oldinum) |
---|
1821 | { |
---|
1822 | struct mount *mp; |
---|
1823 | struct vnode *vp; |
---|
1824 | struct nameidata nd; |
---|
1825 | struct stat sb; |
---|
1826 | int error; |
---|
1827 | |
---|
1828 | restart: |
---|
1829 | bwillwrite(); |
---|
1830 | NDINIT_ATRIGHTS(&nd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNODE1, |
---|
1831 | pathseg, path, fd, &cap_unlinkat_rights, td); |
---|
1832 | if ((error = namei(&nd)) != 0) |
---|
1833 | return (error == EINVAL ? EPERM : error); |
---|
1834 | vp = nd.ni_vp; |
---|
1835 | if (vp->v_type == VDIR && oldinum == 0) { |
---|
1836 | error = EPERM; /* POSIX */ |
---|
1837 | } else if (oldinum != 0 && |
---|
1838 | ((error = vn_stat(vp, &sb, td->td_ucred, NOCRED, td)) == 0) && |
---|
1839 | sb.st_ino != oldinum) { |
---|
1840 | error = EIDRM; /* Identifier removed */ |
---|
1841 | } else { |
---|
1842 | /* |
---|
1843 | * The root of a mounted filesystem cannot be deleted. |
---|
1844 | * |
---|
1845 | * XXX: can this only be a VDIR case? |
---|
1846 | */ |
---|
1847 | if (vp->v_vflag & VV_ROOT) |
---|
1848 | error = EBUSY; |
---|
1849 | } |
---|
1850 | if (error == 0) { |
---|
1851 | if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { |
---|
1852 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
1853 | vput(nd.ni_dvp); |
---|
1854 | if (vp == nd.ni_dvp) |
---|
1855 | vrele(vp); |
---|
1856 | else |
---|
1857 | vput(vp); |
---|
1858 | if ((error = vn_start_write(NULL, &mp, |
---|
1859 | V_XSLEEP | PCATCH)) != 0) |
---|
1860 | return (error); |
---|
1861 | goto restart; |
---|
1862 | } |
---|
1863 | #ifdef MAC |
---|
1864 | error = mac_vnode_check_unlink(td->td_ucred, nd.ni_dvp, vp, |
---|
1865 | &nd.ni_cnd); |
---|
1866 | if (error != 0) |
---|
1867 | goto out; |
---|
1868 | #endif |
---|
1869 | vfs_notify_upper(vp, VFS_NOTIFY_UPPER_UNLINK); |
---|
1870 | error = VOP_REMOVE(nd.ni_dvp, vp, &nd.ni_cnd); |
---|
1871 | #ifdef MAC |
---|
1872 | out: |
---|
1873 | #endif |
---|
1874 | vn_finished_write(mp); |
---|
1875 | } |
---|
1876 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
1877 | vput(nd.ni_dvp); |
---|
1878 | if (vp == nd.ni_dvp) |
---|
1879 | vrele(vp); |
---|
1880 | else |
---|
1881 | vput(vp); |
---|
1882 | return (error); |
---|
1883 | } |
---|
1884 | |
---|
1885 | /* |
---|
1886 | * Reposition read/write file offset. |
---|
1887 | */ |
---|
1888 | #ifndef _SYS_SYSPROTO_H_ |
---|
1889 | struct lseek_args { |
---|
1890 | int fd; |
---|
1891 | int pad; |
---|
1892 | off_t offset; |
---|
1893 | int whence; |
---|
1894 | }; |
---|
1895 | #endif |
---|
1896 | int |
---|
1897 | sys_lseek(struct thread *td, struct lseek_args *uap) |
---|
1898 | { |
---|
1899 | |
---|
1900 | return (kern_lseek(td, uap->fd, uap->offset, uap->whence)); |
---|
1901 | } |
---|
1902 | |
---|
1903 | int |
---|
1904 | kern_lseek(struct thread *td, int fd, off_t offset, int whence) |
---|
1905 | { |
---|
1906 | struct file *fp; |
---|
1907 | int error; |
---|
1908 | |
---|
1909 | AUDIT_ARG_FD(fd); |
---|
1910 | error = fget(td, fd, &cap_seek_rights, &fp); |
---|
1911 | if (error != 0) |
---|
1912 | return (error); |
---|
1913 | error = (fp->f_ops->fo_flags & DFLAG_SEEKABLE) != 0 ? |
---|
1914 | fo_seek(fp, offset, whence, td) : ESPIPE; |
---|
1915 | fdrop(fp, td); |
---|
1916 | return (error); |
---|
1917 | } |
---|
1918 | |
---|
1919 | #if defined(COMPAT_43) |
---|
1920 | /* |
---|
1921 | * Reposition read/write file offset. |
---|
1922 | */ |
---|
1923 | #ifndef _SYS_SYSPROTO_H_ |
---|
1924 | struct olseek_args { |
---|
1925 | int fd; |
---|
1926 | long offset; |
---|
1927 | int whence; |
---|
1928 | }; |
---|
1929 | #endif |
---|
1930 | int |
---|
1931 | olseek(struct thread *td, struct olseek_args *uap) |
---|
1932 | { |
---|
1933 | |
---|
1934 | return (kern_lseek(td, uap->fd, uap->offset, uap->whence)); |
---|
1935 | } |
---|
1936 | #endif /* COMPAT_43 */ |
---|
1937 | |
---|
1938 | #if defined(COMPAT_FREEBSD6) |
---|
1939 | /* Version with the 'pad' argument */ |
---|
1940 | int |
---|
1941 | freebsd6_lseek(struct thread *td, struct freebsd6_lseek_args *uap) |
---|
1942 | { |
---|
1943 | |
---|
1944 | return (kern_lseek(td, uap->fd, uap->offset, uap->whence)); |
---|
1945 | } |
---|
1946 | #endif |
---|
1947 | |
---|
1948 | /* |
---|
1949 | * Check access permissions using passed credentials. |
---|
1950 | */ |
---|
1951 | static int |
---|
1952 | vn_access(struct vnode *vp, int user_flags, struct ucred *cred, |
---|
1953 | struct thread *td) |
---|
1954 | { |
---|
1955 | accmode_t accmode; |
---|
1956 | int error; |
---|
1957 | |
---|
1958 | /* Flags == 0 means only check for existence. */ |
---|
1959 | if (user_flags == 0) |
---|
1960 | return (0); |
---|
1961 | |
---|
1962 | accmode = 0; |
---|
1963 | if (user_flags & R_OK) |
---|
1964 | accmode |= VREAD; |
---|
1965 | if (user_flags & W_OK) |
---|
1966 | accmode |= VWRITE; |
---|
1967 | if (user_flags & X_OK) |
---|
1968 | accmode |= VEXEC; |
---|
1969 | #ifdef MAC |
---|
1970 | error = mac_vnode_check_access(cred, vp, accmode); |
---|
1971 | if (error != 0) |
---|
1972 | return (error); |
---|
1973 | #endif |
---|
1974 | if ((accmode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) |
---|
1975 | error = VOP_ACCESS(vp, accmode, cred, td); |
---|
1976 | return (error); |
---|
1977 | } |
---|
1978 | |
---|
1979 | /* |
---|
1980 | * Check access permissions using "real" credentials. |
---|
1981 | */ |
---|
1982 | #ifndef _SYS_SYSPROTO_H_ |
---|
1983 | struct access_args { |
---|
1984 | char *path; |
---|
1985 | int amode; |
---|
1986 | }; |
---|
1987 | #endif |
---|
1988 | int |
---|
1989 | sys_access(struct thread *td, struct access_args *uap) |
---|
1990 | { |
---|
1991 | |
---|
1992 | return (kern_accessat(td, AT_FDCWD, uap->path, UIO_USERSPACE, |
---|
1993 | 0, uap->amode)); |
---|
1994 | } |
---|
1995 | |
---|
1996 | #ifndef __rtems__ |
---|
1997 | #ifndef _SYS_SYSPROTO_H_ |
---|
1998 | struct faccessat_args { |
---|
1999 | int dirfd; |
---|
2000 | char *path; |
---|
2001 | int amode; |
---|
2002 | int flag; |
---|
2003 | } |
---|
2004 | #endif |
---|
2005 | int |
---|
2006 | sys_faccessat(struct thread *td, struct faccessat_args *uap) |
---|
2007 | { |
---|
2008 | |
---|
2009 | return (kern_accessat(td, uap->fd, uap->path, UIO_USERSPACE, uap->flag, |
---|
2010 | uap->amode)); |
---|
2011 | } |
---|
2012 | |
---|
2013 | int |
---|
2014 | kern_accessat(struct thread *td, int fd, char *path, enum uio_seg pathseg, |
---|
2015 | int flag, int amode) |
---|
2016 | { |
---|
2017 | struct ucred *cred, *usecred; |
---|
2018 | struct vnode *vp; |
---|
2019 | struct nameidata nd; |
---|
2020 | int error; |
---|
2021 | |
---|
2022 | if (flag & ~AT_EACCESS) |
---|
2023 | return (EINVAL); |
---|
2024 | if (amode != F_OK && (amode & ~(R_OK | W_OK | X_OK)) != 0) |
---|
2025 | return (EINVAL); |
---|
2026 | |
---|
2027 | /* |
---|
2028 | * Create and modify a temporary credential instead of one that |
---|
2029 | * is potentially shared (if we need one). |
---|
2030 | */ |
---|
2031 | cred = td->td_ucred; |
---|
2032 | if ((flag & AT_EACCESS) == 0 && |
---|
2033 | ((cred->cr_uid != cred->cr_ruid || |
---|
2034 | cred->cr_rgid != cred->cr_groups[0]))) { |
---|
2035 | usecred = crdup(cred); |
---|
2036 | usecred->cr_uid = cred->cr_ruid; |
---|
2037 | usecred->cr_groups[0] = cred->cr_rgid; |
---|
2038 | td->td_ucred = usecred; |
---|
2039 | } else |
---|
2040 | usecred = cred; |
---|
2041 | AUDIT_ARG_VALUE(amode); |
---|
2042 | NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | |
---|
2043 | AUDITVNODE1, pathseg, path, fd, &cap_fstat_rights, |
---|
2044 | td); |
---|
2045 | if ((error = namei(&nd)) != 0) |
---|
2046 | goto out; |
---|
2047 | vp = nd.ni_vp; |
---|
2048 | |
---|
2049 | error = vn_access(vp, amode, usecred, td); |
---|
2050 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
2051 | vput(vp); |
---|
2052 | out: |
---|
2053 | if (usecred != cred) { |
---|
2054 | td->td_ucred = cred; |
---|
2055 | crfree(usecred); |
---|
2056 | } |
---|
2057 | return (error); |
---|
2058 | } |
---|
2059 | #endif /* __rtems__ */ |
---|
2060 | |
---|
2061 | #ifndef __rtems__ |
---|
2062 | /* |
---|
2063 | * Check access permissions using "effective" credentials. |
---|
2064 | */ |
---|
2065 | #ifndef _SYS_SYSPROTO_H_ |
---|
2066 | struct eaccess_args { |
---|
2067 | char *path; |
---|
2068 | int amode; |
---|
2069 | }; |
---|
2070 | #endif |
---|
2071 | int |
---|
2072 | sys_eaccess(struct thread *td, struct eaccess_args *uap) |
---|
2073 | { |
---|
2074 | |
---|
2075 | return (kern_accessat(td, AT_FDCWD, uap->path, UIO_USERSPACE, |
---|
2076 | AT_EACCESS, uap->amode)); |
---|
2077 | } |
---|
2078 | #endif /* __rtems__ */ |
---|
2079 | |
---|
2080 | #ifndef __rtems__ |
---|
2081 | #if defined(COMPAT_43) |
---|
2082 | /* |
---|
2083 | * Get file status; this version follows links. |
---|
2084 | */ |
---|
2085 | #ifndef _SYS_SYSPROTO_H_ |
---|
2086 | struct ostat_args { |
---|
2087 | char *path; |
---|
2088 | struct ostat *ub; |
---|
2089 | }; |
---|
2090 | #endif |
---|
2091 | int |
---|
2092 | ostat(struct thread *td, struct ostat_args *uap) |
---|
2093 | { |
---|
2094 | struct stat sb; |
---|
2095 | struct ostat osb; |
---|
2096 | int error; |
---|
2097 | |
---|
2098 | error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, |
---|
2099 | &sb, NULL); |
---|
2100 | if (error != 0) |
---|
2101 | return (error); |
---|
2102 | cvtstat(&sb, &osb); |
---|
2103 | return (copyout(&osb, uap->ub, sizeof (osb))); |
---|
2104 | } |
---|
2105 | |
---|
2106 | /* |
---|
2107 | * Get file status; this version does not follow links. |
---|
2108 | */ |
---|
2109 | #ifndef _SYS_SYSPROTO_H_ |
---|
2110 | struct olstat_args { |
---|
2111 | char *path; |
---|
2112 | struct ostat *ub; |
---|
2113 | }; |
---|
2114 | #endif |
---|
2115 | int |
---|
2116 | olstat(struct thread *td, struct olstat_args *uap) |
---|
2117 | { |
---|
2118 | struct stat sb; |
---|
2119 | struct ostat osb; |
---|
2120 | int error; |
---|
2121 | |
---|
2122 | error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path, |
---|
2123 | UIO_USERSPACE, &sb, NULL); |
---|
2124 | if (error != 0) |
---|
2125 | return (error); |
---|
2126 | cvtstat(&sb, &osb); |
---|
2127 | return (copyout(&osb, uap->ub, sizeof (osb))); |
---|
2128 | } |
---|
2129 | |
---|
2130 | /* |
---|
2131 | * Convert from an old to a new stat structure. |
---|
2132 | * XXX: many values are blindly truncated. |
---|
2133 | */ |
---|
2134 | void |
---|
2135 | cvtstat(struct stat *st, struct ostat *ost) |
---|
2136 | { |
---|
2137 | |
---|
2138 | bzero(ost, sizeof(*ost)); |
---|
2139 | ost->st_dev = st->st_dev; |
---|
2140 | ost->st_ino = st->st_ino; |
---|
2141 | ost->st_mode = st->st_mode; |
---|
2142 | ost->st_nlink = st->st_nlink; |
---|
2143 | ost->st_uid = st->st_uid; |
---|
2144 | ost->st_gid = st->st_gid; |
---|
2145 | ost->st_rdev = st->st_rdev; |
---|
2146 | ost->st_size = MIN(st->st_size, INT32_MAX); |
---|
2147 | ost->st_atim = st->st_atim; |
---|
2148 | ost->st_mtim = st->st_mtim; |
---|
2149 | ost->st_ctim = st->st_ctim; |
---|
2150 | ost->st_blksize = st->st_blksize; |
---|
2151 | ost->st_blocks = st->st_blocks; |
---|
2152 | ost->st_flags = st->st_flags; |
---|
2153 | ost->st_gen = st->st_gen; |
---|
2154 | } |
---|
2155 | #endif /* COMPAT_43 */ |
---|
2156 | |
---|
2157 | #if defined(COMPAT_43) || defined(COMPAT_FREEBSD11) |
---|
2158 | int ino64_trunc_error; |
---|
2159 | SYSCTL_INT(_vfs, OID_AUTO, ino64_trunc_error, CTLFLAG_RW, |
---|
2160 | &ino64_trunc_error, 0, |
---|
2161 | "Error on truncation of device, file or inode number, or link count"); |
---|
2162 | |
---|
2163 | int |
---|
2164 | freebsd11_cvtstat(struct stat *st, struct freebsd11_stat *ost) |
---|
2165 | { |
---|
2166 | |
---|
2167 | ost->st_dev = st->st_dev; |
---|
2168 | if (ost->st_dev != st->st_dev) { |
---|
2169 | switch (ino64_trunc_error) { |
---|
2170 | default: |
---|
2171 | /* |
---|
2172 | * Since dev_t is almost raw, don't clamp to the |
---|
2173 | * maximum for case 2, but ignore the error. |
---|
2174 | */ |
---|
2175 | break; |
---|
2176 | case 1: |
---|
2177 | return (EOVERFLOW); |
---|
2178 | } |
---|
2179 | } |
---|
2180 | ost->st_ino = st->st_ino; |
---|
2181 | if (ost->st_ino != st->st_ino) { |
---|
2182 | switch (ino64_trunc_error) { |
---|
2183 | default: |
---|
2184 | case 0: |
---|
2185 | break; |
---|
2186 | case 1: |
---|
2187 | return (EOVERFLOW); |
---|
2188 | case 2: |
---|
2189 | ost->st_ino = UINT32_MAX; |
---|
2190 | break; |
---|
2191 | } |
---|
2192 | } |
---|
2193 | ost->st_mode = st->st_mode; |
---|
2194 | ost->st_nlink = st->st_nlink; |
---|
2195 | if (ost->st_nlink != st->st_nlink) { |
---|
2196 | switch (ino64_trunc_error) { |
---|
2197 | default: |
---|
2198 | case 0: |
---|
2199 | break; |
---|
2200 | case 1: |
---|
2201 | return (EOVERFLOW); |
---|
2202 | case 2: |
---|
2203 | ost->st_nlink = UINT16_MAX; |
---|
2204 | break; |
---|
2205 | } |
---|
2206 | } |
---|
2207 | ost->st_uid = st->st_uid; |
---|
2208 | ost->st_gid = st->st_gid; |
---|
2209 | ost->st_rdev = st->st_rdev; |
---|
2210 | if (ost->st_rdev != st->st_rdev) { |
---|
2211 | switch (ino64_trunc_error) { |
---|
2212 | default: |
---|
2213 | break; |
---|
2214 | case 1: |
---|
2215 | return (EOVERFLOW); |
---|
2216 | } |
---|
2217 | } |
---|
2218 | ost->st_atim = st->st_atim; |
---|
2219 | ost->st_mtim = st->st_mtim; |
---|
2220 | ost->st_ctim = st->st_ctim; |
---|
2221 | ost->st_size = st->st_size; |
---|
2222 | ost->st_blocks = st->st_blocks; |
---|
2223 | ost->st_blksize = st->st_blksize; |
---|
2224 | ost->st_flags = st->st_flags; |
---|
2225 | ost->st_gen = st->st_gen; |
---|
2226 | ost->st_lspare = 0; |
---|
2227 | ost->st_birthtim = st->st_birthtim; |
---|
2228 | bzero((char *)&ost->st_birthtim + sizeof(ost->st_birthtim), |
---|
2229 | sizeof(*ost) - offsetof(struct freebsd11_stat, |
---|
2230 | st_birthtim) - sizeof(ost->st_birthtim)); |
---|
2231 | return (0); |
---|
2232 | } |
---|
2233 | |
---|
2234 | int |
---|
2235 | freebsd11_stat(struct thread *td, struct freebsd11_stat_args* uap) |
---|
2236 | { |
---|
2237 | struct stat sb; |
---|
2238 | struct freebsd11_stat osb; |
---|
2239 | int error; |
---|
2240 | |
---|
2241 | error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, |
---|
2242 | &sb, NULL); |
---|
2243 | if (error != 0) |
---|
2244 | return (error); |
---|
2245 | error = freebsd11_cvtstat(&sb, &osb); |
---|
2246 | if (error == 0) |
---|
2247 | error = copyout(&osb, uap->ub, sizeof(osb)); |
---|
2248 | return (error); |
---|
2249 | } |
---|
2250 | |
---|
2251 | int |
---|
2252 | freebsd11_lstat(struct thread *td, struct freebsd11_lstat_args* uap) |
---|
2253 | { |
---|
2254 | struct stat sb; |
---|
2255 | struct freebsd11_stat osb; |
---|
2256 | int error; |
---|
2257 | |
---|
2258 | error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path, |
---|
2259 | UIO_USERSPACE, &sb, NULL); |
---|
2260 | if (error != 0) |
---|
2261 | return (error); |
---|
2262 | error = freebsd11_cvtstat(&sb, &osb); |
---|
2263 | if (error == 0) |
---|
2264 | error = copyout(&osb, uap->ub, sizeof(osb)); |
---|
2265 | return (error); |
---|
2266 | } |
---|
2267 | |
---|
2268 | int |
---|
2269 | freebsd11_fhstat(struct thread *td, struct freebsd11_fhstat_args* uap) |
---|
2270 | { |
---|
2271 | struct fhandle fh; |
---|
2272 | struct stat sb; |
---|
2273 | struct freebsd11_stat osb; |
---|
2274 | int error; |
---|
2275 | |
---|
2276 | error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t)); |
---|
2277 | if (error != 0) |
---|
2278 | return (error); |
---|
2279 | error = kern_fhstat(td, fh, &sb); |
---|
2280 | if (error != 0) |
---|
2281 | return (error); |
---|
2282 | error = freebsd11_cvtstat(&sb, &osb); |
---|
2283 | if (error == 0) |
---|
2284 | error = copyout(&osb, uap->sb, sizeof(osb)); |
---|
2285 | return (error); |
---|
2286 | } |
---|
2287 | |
---|
2288 | int |
---|
2289 | freebsd11_fstatat(struct thread *td, struct freebsd11_fstatat_args* uap) |
---|
2290 | { |
---|
2291 | struct stat sb; |
---|
2292 | struct freebsd11_stat osb; |
---|
2293 | int error; |
---|
2294 | |
---|
2295 | error = kern_statat(td, uap->flag, uap->fd, uap->path, |
---|
2296 | UIO_USERSPACE, &sb, NULL); |
---|
2297 | if (error != 0) |
---|
2298 | return (error); |
---|
2299 | error = freebsd11_cvtstat(&sb, &osb); |
---|
2300 | if (error == 0) |
---|
2301 | error = copyout(&osb, uap->buf, sizeof(osb)); |
---|
2302 | return (error); |
---|
2303 | } |
---|
2304 | #endif /* COMPAT_FREEBSD11 */ |
---|
2305 | #endif /* __rtems__ */ |
---|
2306 | |
---|
2307 | /* |
---|
2308 | * Get file status |
---|
2309 | */ |
---|
2310 | #ifndef _SYS_SYSPROTO_H_ |
---|
2311 | struct fstatat_args { |
---|
2312 | int fd; |
---|
2313 | char *path; |
---|
2314 | struct stat *buf; |
---|
2315 | int flag; |
---|
2316 | } |
---|
2317 | #endif |
---|
2318 | int |
---|
2319 | sys_fstatat(struct thread *td, struct fstatat_args *uap) |
---|
2320 | { |
---|
2321 | struct stat sb; |
---|
2322 | int error; |
---|
2323 | |
---|
2324 | error = kern_statat(td, uap->flag, uap->fd, uap->path, |
---|
2325 | UIO_USERSPACE, &sb, NULL); |
---|
2326 | if (error == 0) |
---|
2327 | error = copyout(&sb, uap->buf, sizeof (sb)); |
---|
2328 | return (error); |
---|
2329 | } |
---|
2330 | |
---|
2331 | int |
---|
2332 | kern_statat(struct thread *td, int flag, int fd, char *path, |
---|
2333 | enum uio_seg pathseg, struct stat *sbp, |
---|
2334 | void (*hook)(struct vnode *vp, struct stat *sbp)) |
---|
2335 | { |
---|
2336 | struct nameidata nd; |
---|
2337 | struct stat sb; |
---|
2338 | int error; |
---|
2339 | |
---|
2340 | if (flag & ~AT_SYMLINK_NOFOLLOW) |
---|
2341 | return (EINVAL); |
---|
2342 | |
---|
2343 | NDINIT_ATRIGHTS(&nd, LOOKUP, ((flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : |
---|
2344 | FOLLOW) | LOCKSHARED | LOCKLEAF | AUDITVNODE1, pathseg, path, fd, |
---|
2345 | &cap_fstat_rights, td); |
---|
2346 | |
---|
2347 | if ((error = namei(&nd)) != 0) |
---|
2348 | return (error); |
---|
2349 | error = vn_stat(nd.ni_vp, &sb, td->td_ucred, NOCRED, td); |
---|
2350 | if (error == 0) { |
---|
2351 | SDT_PROBE2(vfs, , stat, mode, path, sb.st_mode); |
---|
2352 | if (S_ISREG(sb.st_mode)) |
---|
2353 | SDT_PROBE2(vfs, , stat, reg, path, pathseg); |
---|
2354 | if (__predict_false(hook != NULL)) |
---|
2355 | hook(nd.ni_vp, &sb); |
---|
2356 | } |
---|
2357 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
2358 | vput(nd.ni_vp); |
---|
2359 | if (error != 0) |
---|
2360 | return (error); |
---|
2361 | #ifdef __STAT_TIME_T_EXT |
---|
2362 | sb.st_atim_ext = 0; |
---|
2363 | sb.st_mtim_ext = 0; |
---|
2364 | sb.st_ctim_ext = 0; |
---|
2365 | sb.st_btim_ext = 0; |
---|
2366 | #endif |
---|
2367 | *sbp = sb; |
---|
2368 | #ifdef KTRACE |
---|
2369 | if (KTRPOINT(td, KTR_STRUCT)) |
---|
2370 | ktrstat(&sb); |
---|
2371 | #endif |
---|
2372 | return (0); |
---|
2373 | } |
---|
2374 | |
---|
2375 | #if defined(COMPAT_FREEBSD11) |
---|
2376 | /* |
---|
2377 | * Implementation of the NetBSD [l]stat() functions. |
---|
2378 | */ |
---|
2379 | void |
---|
2380 | freebsd11_cvtnstat(struct stat *sb, struct nstat *nsb) |
---|
2381 | { |
---|
2382 | |
---|
2383 | bzero(nsb, sizeof(*nsb)); |
---|
2384 | nsb->st_dev = sb->st_dev; |
---|
2385 | nsb->st_ino = sb->st_ino; |
---|
2386 | nsb->st_mode = sb->st_mode; |
---|
2387 | nsb->st_nlink = sb->st_nlink; |
---|
2388 | nsb->st_uid = sb->st_uid; |
---|
2389 | nsb->st_gid = sb->st_gid; |
---|
2390 | nsb->st_rdev = sb->st_rdev; |
---|
2391 | nsb->st_atim = sb->st_atim; |
---|
2392 | nsb->st_mtim = sb->st_mtim; |
---|
2393 | nsb->st_ctim = sb->st_ctim; |
---|
2394 | nsb->st_size = sb->st_size; |
---|
2395 | nsb->st_blocks = sb->st_blocks; |
---|
2396 | nsb->st_blksize = sb->st_blksize; |
---|
2397 | nsb->st_flags = sb->st_flags; |
---|
2398 | nsb->st_gen = sb->st_gen; |
---|
2399 | nsb->st_birthtim = sb->st_birthtim; |
---|
2400 | } |
---|
2401 | |
---|
2402 | #ifndef _SYS_SYSPROTO_H_ |
---|
2403 | struct freebsd11_nstat_args { |
---|
2404 | char *path; |
---|
2405 | struct nstat *ub; |
---|
2406 | }; |
---|
2407 | #endif |
---|
2408 | int |
---|
2409 | freebsd11_nstat(struct thread *td, struct freebsd11_nstat_args *uap) |
---|
2410 | { |
---|
2411 | struct stat sb; |
---|
2412 | struct nstat nsb; |
---|
2413 | int error; |
---|
2414 | |
---|
2415 | error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, |
---|
2416 | &sb, NULL); |
---|
2417 | if (error != 0) |
---|
2418 | return (error); |
---|
2419 | freebsd11_cvtnstat(&sb, &nsb); |
---|
2420 | return (copyout(&nsb, uap->ub, sizeof (nsb))); |
---|
2421 | } |
---|
2422 | |
---|
2423 | /* |
---|
2424 | * NetBSD lstat. Get file status; this version does not follow links. |
---|
2425 | */ |
---|
2426 | #ifndef _SYS_SYSPROTO_H_ |
---|
2427 | struct freebsd11_nlstat_args { |
---|
2428 | char *path; |
---|
2429 | struct nstat *ub; |
---|
2430 | }; |
---|
2431 | #endif |
---|
2432 | int |
---|
2433 | freebsd11_nlstat(struct thread *td, struct freebsd11_nlstat_args *uap) |
---|
2434 | { |
---|
2435 | struct stat sb; |
---|
2436 | struct nstat nsb; |
---|
2437 | int error; |
---|
2438 | |
---|
2439 | error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path, |
---|
2440 | UIO_USERSPACE, &sb, NULL); |
---|
2441 | if (error != 0) |
---|
2442 | return (error); |
---|
2443 | freebsd11_cvtnstat(&sb, &nsb); |
---|
2444 | return (copyout(&nsb, uap->ub, sizeof (nsb))); |
---|
2445 | } |
---|
2446 | #endif /* COMPAT_FREEBSD11 */ |
---|
2447 | |
---|
2448 | #ifndef __rtems__ |
---|
2449 | /* |
---|
2450 | * Get configurable pathname variables. |
---|
2451 | */ |
---|
2452 | #ifndef _SYS_SYSPROTO_H_ |
---|
2453 | struct pathconf_args { |
---|
2454 | char *path; |
---|
2455 | int name; |
---|
2456 | }; |
---|
2457 | #endif |
---|
2458 | int |
---|
2459 | sys_pathconf(struct thread *td, struct pathconf_args *uap) |
---|
2460 | { |
---|
2461 | long value; |
---|
2462 | int error; |
---|
2463 | |
---|
2464 | error = kern_pathconf(td, uap->path, UIO_USERSPACE, uap->name, FOLLOW, |
---|
2465 | &value); |
---|
2466 | if (error == 0) |
---|
2467 | td->td_retval[0] = value; |
---|
2468 | return (error); |
---|
2469 | } |
---|
2470 | |
---|
2471 | #ifndef _SYS_SYSPROTO_H_ |
---|
2472 | struct lpathconf_args { |
---|
2473 | char *path; |
---|
2474 | int name; |
---|
2475 | }; |
---|
2476 | #endif |
---|
2477 | int |
---|
2478 | sys_lpathconf(struct thread *td, struct lpathconf_args *uap) |
---|
2479 | { |
---|
2480 | long value; |
---|
2481 | int error; |
---|
2482 | |
---|
2483 | error = kern_pathconf(td, uap->path, UIO_USERSPACE, uap->name, |
---|
2484 | NOFOLLOW, &value); |
---|
2485 | if (error == 0) |
---|
2486 | td->td_retval[0] = value; |
---|
2487 | return (error); |
---|
2488 | } |
---|
2489 | |
---|
2490 | int |
---|
2491 | kern_pathconf(struct thread *td, char *path, enum uio_seg pathseg, int name, |
---|
2492 | u_long flags, long *valuep) |
---|
2493 | { |
---|
2494 | struct nameidata nd; |
---|
2495 | int error; |
---|
2496 | |
---|
2497 | NDINIT(&nd, LOOKUP, LOCKSHARED | LOCKLEAF | AUDITVNODE1 | flags, |
---|
2498 | pathseg, path, td); |
---|
2499 | if ((error = namei(&nd)) != 0) |
---|
2500 | return (error); |
---|
2501 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
2502 | |
---|
2503 | error = VOP_PATHCONF(nd.ni_vp, name, valuep); |
---|
2504 | vput(nd.ni_vp); |
---|
2505 | return (error); |
---|
2506 | } |
---|
2507 | #endif /* __rtems__ */ |
---|
2508 | |
---|
2509 | /* |
---|
2510 | * Return target name of a symbolic link. |
---|
2511 | */ |
---|
2512 | #ifndef _SYS_SYSPROTO_H_ |
---|
2513 | struct readlink_args { |
---|
2514 | char *path; |
---|
2515 | char *buf; |
---|
2516 | size_t count; |
---|
2517 | }; |
---|
2518 | #endif |
---|
2519 | int |
---|
2520 | sys_readlink(struct thread *td, struct readlink_args *uap) |
---|
2521 | { |
---|
2522 | |
---|
2523 | return (kern_readlinkat(td, AT_FDCWD, uap->path, UIO_USERSPACE, |
---|
2524 | uap->buf, UIO_USERSPACE, uap->count)); |
---|
2525 | } |
---|
2526 | #ifndef _SYS_SYSPROTO_H_ |
---|
2527 | struct readlinkat_args { |
---|
2528 | int fd; |
---|
2529 | char *path; |
---|
2530 | char *buf; |
---|
2531 | size_t bufsize; |
---|
2532 | }; |
---|
2533 | #endif |
---|
2534 | int |
---|
2535 | sys_readlinkat(struct thread *td, struct readlinkat_args *uap) |
---|
2536 | { |
---|
2537 | |
---|
2538 | return (kern_readlinkat(td, uap->fd, uap->path, UIO_USERSPACE, |
---|
2539 | uap->buf, UIO_USERSPACE, uap->bufsize)); |
---|
2540 | } |
---|
2541 | |
---|
2542 | int |
---|
2543 | kern_readlinkat(struct thread *td, int fd, char *path, enum uio_seg pathseg, |
---|
2544 | char *buf, enum uio_seg bufseg, size_t count) |
---|
2545 | { |
---|
2546 | struct vnode *vp; |
---|
2547 | struct nameidata nd; |
---|
2548 | int error; |
---|
2549 | |
---|
2550 | if (count > IOSIZE_MAX) |
---|
2551 | return (EINVAL); |
---|
2552 | |
---|
2553 | NDINIT_AT(&nd, LOOKUP, NOFOLLOW | LOCKSHARED | LOCKLEAF | AUDITVNODE1, |
---|
2554 | pathseg, path, fd, td); |
---|
2555 | |
---|
2556 | if ((error = namei(&nd)) != 0) |
---|
2557 | return (error); |
---|
2558 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
2559 | vp = nd.ni_vp; |
---|
2560 | |
---|
2561 | error = kern_readlink_vp(vp, buf, bufseg, count, td); |
---|
2562 | vput(vp); |
---|
2563 | |
---|
2564 | return (error); |
---|
2565 | } |
---|
2566 | |
---|
2567 | /* |
---|
2568 | * Helper function to readlink from a vnode |
---|
2569 | */ |
---|
2570 | static int |
---|
2571 | kern_readlink_vp(struct vnode *vp, char *buf, enum uio_seg bufseg, size_t count, |
---|
2572 | struct thread *td) |
---|
2573 | { |
---|
2574 | struct iovec aiov; |
---|
2575 | struct uio auio; |
---|
2576 | int error; |
---|
2577 | |
---|
2578 | ASSERT_VOP_LOCKED(vp, "kern_readlink_vp(): vp not locked"); |
---|
2579 | #ifdef MAC |
---|
2580 | error = mac_vnode_check_readlink(td->td_ucred, vp); |
---|
2581 | if (error != 0) |
---|
2582 | return (error); |
---|
2583 | #endif |
---|
2584 | if (vp->v_type != VLNK && (vp->v_vflag & VV_READLINK) == 0) |
---|
2585 | return (EINVAL); |
---|
2586 | |
---|
2587 | aiov.iov_base = buf; |
---|
2588 | aiov.iov_len = count; |
---|
2589 | auio.uio_iov = &aiov; |
---|
2590 | auio.uio_iovcnt = 1; |
---|
2591 | auio.uio_offset = 0; |
---|
2592 | auio.uio_rw = UIO_READ; |
---|
2593 | auio.uio_segflg = bufseg; |
---|
2594 | auio.uio_td = td; |
---|
2595 | auio.uio_resid = count; |
---|
2596 | error = VOP_READLINK(vp, &auio, td->td_ucred); |
---|
2597 | td->td_retval[0] = count - auio.uio_resid; |
---|
2598 | return (error); |
---|
2599 | } |
---|
2600 | |
---|
2601 | /* |
---|
2602 | * Common implementation code for chflags() and fchflags(). |
---|
2603 | */ |
---|
2604 | static int |
---|
2605 | setfflags(struct thread *td, struct vnode *vp, u_long flags) |
---|
2606 | { |
---|
2607 | struct mount *mp; |
---|
2608 | struct vattr vattr; |
---|
2609 | int error; |
---|
2610 | |
---|
2611 | /* We can't support the value matching VNOVAL. */ |
---|
2612 | if (flags == VNOVAL) |
---|
2613 | return (EOPNOTSUPP); |
---|
2614 | |
---|
2615 | /* |
---|
2616 | * Prevent non-root users from setting flags on devices. When |
---|
2617 | * a device is reused, users can retain ownership of the device |
---|
2618 | * if they are allowed to set flags and programs assume that |
---|
2619 | * chown can't fail when done as root. |
---|
2620 | */ |
---|
2621 | if (vp->v_type == VCHR || vp->v_type == VBLK) { |
---|
2622 | error = priv_check(td, PRIV_VFS_CHFLAGS_DEV); |
---|
2623 | if (error != 0) |
---|
2624 | return (error); |
---|
2625 | } |
---|
2626 | |
---|
2627 | if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) |
---|
2628 | return (error); |
---|
2629 | VATTR_NULL(&vattr); |
---|
2630 | vattr.va_flags = flags; |
---|
2631 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
---|
2632 | #ifdef MAC |
---|
2633 | error = mac_vnode_check_setflags(td->td_ucred, vp, vattr.va_flags); |
---|
2634 | if (error == 0) |
---|
2635 | #endif |
---|
2636 | error = VOP_SETATTR(vp, &vattr, td->td_ucred); |
---|
2637 | VOP_UNLOCK(vp, 0); |
---|
2638 | vn_finished_write(mp); |
---|
2639 | return (error); |
---|
2640 | } |
---|
2641 | |
---|
2642 | /* |
---|
2643 | * Change flags of a file given a path name. |
---|
2644 | */ |
---|
2645 | #ifndef _SYS_SYSPROTO_H_ |
---|
2646 | struct chflags_args { |
---|
2647 | const char *path; |
---|
2648 | u_long flags; |
---|
2649 | }; |
---|
2650 | #endif |
---|
2651 | int |
---|
2652 | sys_chflags(struct thread *td, struct chflags_args *uap) |
---|
2653 | { |
---|
2654 | |
---|
2655 | return (kern_chflagsat(td, AT_FDCWD, uap->path, UIO_USERSPACE, |
---|
2656 | uap->flags, 0)); |
---|
2657 | } |
---|
2658 | |
---|
2659 | #ifndef __rtems__ |
---|
2660 | #ifndef _SYS_SYSPROTO_H_ |
---|
2661 | struct chflagsat_args { |
---|
2662 | int fd; |
---|
2663 | const char *path; |
---|
2664 | u_long flags; |
---|
2665 | int atflag; |
---|
2666 | } |
---|
2667 | #endif |
---|
2668 | int |
---|
2669 | sys_chflagsat(struct thread *td, struct chflagsat_args *uap) |
---|
2670 | { |
---|
2671 | int fd = uap->fd; |
---|
2672 | const char *path = uap->path; |
---|
2673 | u_long flags = uap->flags; |
---|
2674 | int atflag = uap->atflag; |
---|
2675 | |
---|
2676 | if (atflag & ~AT_SYMLINK_NOFOLLOW) |
---|
2677 | return (EINVAL); |
---|
2678 | |
---|
2679 | return (kern_chflagsat(td, fd, path, UIO_USERSPACE, flags, atflag)); |
---|
2680 | } |
---|
2681 | |
---|
2682 | /* |
---|
2683 | * Same as chflags() but doesn't follow symlinks. |
---|
2684 | */ |
---|
2685 | #ifndef _SYS_SYSPROTO_H_ |
---|
2686 | struct lchflags_args { |
---|
2687 | const char *path; |
---|
2688 | u_long flags; |
---|
2689 | }; |
---|
2690 | #endif |
---|
2691 | int |
---|
2692 | sys_lchflags(struct thread *td, struct lchflags_args *uap) |
---|
2693 | { |
---|
2694 | |
---|
2695 | return (kern_chflagsat(td, AT_FDCWD, uap->path, UIO_USERSPACE, |
---|
2696 | uap->flags, AT_SYMLINK_NOFOLLOW)); |
---|
2697 | } |
---|
2698 | |
---|
2699 | static int |
---|
2700 | kern_chflagsat(struct thread *td, int fd, const char *path, |
---|
2701 | enum uio_seg pathseg, u_long flags, int atflag) |
---|
2702 | { |
---|
2703 | struct nameidata nd; |
---|
2704 | int error, follow; |
---|
2705 | |
---|
2706 | AUDIT_ARG_FFLAGS(flags); |
---|
2707 | follow = (atflag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW; |
---|
2708 | NDINIT_ATRIGHTS(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path, fd, |
---|
2709 | &cap_fchflags_rights, td); |
---|
2710 | if ((error = namei(&nd)) != 0) |
---|
2711 | return (error); |
---|
2712 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
2713 | error = setfflags(td, nd.ni_vp, flags); |
---|
2714 | vrele(nd.ni_vp); |
---|
2715 | return (error); |
---|
2716 | } |
---|
2717 | |
---|
2718 | /* |
---|
2719 | * Change flags of a file given a file descriptor. |
---|
2720 | */ |
---|
2721 | #ifndef _SYS_SYSPROTO_H_ |
---|
2722 | struct fchflags_args { |
---|
2723 | int fd; |
---|
2724 | u_long flags; |
---|
2725 | }; |
---|
2726 | #endif |
---|
2727 | int |
---|
2728 | sys_fchflags(struct thread *td, struct fchflags_args *uap) |
---|
2729 | { |
---|
2730 | struct file *fp; |
---|
2731 | int error; |
---|
2732 | |
---|
2733 | AUDIT_ARG_FD(uap->fd); |
---|
2734 | AUDIT_ARG_FFLAGS(uap->flags); |
---|
2735 | error = getvnode(td, uap->fd, &cap_fchflags_rights, |
---|
2736 | &fp); |
---|
2737 | if (error != 0) |
---|
2738 | return (error); |
---|
2739 | #ifdef AUDIT |
---|
2740 | vn_lock(fp->f_vnode, LK_SHARED | LK_RETRY); |
---|
2741 | AUDIT_ARG_VNODE1(fp->f_vnode); |
---|
2742 | VOP_UNLOCK(fp->f_vnode, 0); |
---|
2743 | #endif |
---|
2744 | error = setfflags(td, fp->f_vnode, uap->flags); |
---|
2745 | fdrop(fp, td); |
---|
2746 | return (error); |
---|
2747 | } |
---|
2748 | #endif /* __rtems__ */ |
---|
2749 | |
---|
2750 | /* |
---|
2751 | * Common implementation code for chmod(), lchmod() and fchmod(). |
---|
2752 | */ |
---|
2753 | int |
---|
2754 | setfmode(struct thread *td, struct ucred *cred, struct vnode *vp, int mode) |
---|
2755 | { |
---|
2756 | struct mount *mp; |
---|
2757 | struct vattr vattr; |
---|
2758 | int error; |
---|
2759 | |
---|
2760 | if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) |
---|
2761 | return (error); |
---|
2762 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
---|
2763 | VATTR_NULL(&vattr); |
---|
2764 | vattr.va_mode = mode & ALLPERMS; |
---|
2765 | #ifdef MAC |
---|
2766 | error = mac_vnode_check_setmode(cred, vp, vattr.va_mode); |
---|
2767 | if (error == 0) |
---|
2768 | #endif |
---|
2769 | error = VOP_SETATTR(vp, &vattr, cred); |
---|
2770 | VOP_UNLOCK(vp, 0); |
---|
2771 | vn_finished_write(mp); |
---|
2772 | return (error); |
---|
2773 | } |
---|
2774 | |
---|
2775 | /* |
---|
2776 | * Change mode of a file given path name. |
---|
2777 | */ |
---|
2778 | #ifndef _SYS_SYSPROTO_H_ |
---|
2779 | struct chmod_args { |
---|
2780 | char *path; |
---|
2781 | int mode; |
---|
2782 | }; |
---|
2783 | #endif |
---|
2784 | int |
---|
2785 | sys_chmod(struct thread *td, struct chmod_args *uap) |
---|
2786 | { |
---|
2787 | |
---|
2788 | return (kern_fchmodat(td, AT_FDCWD, uap->path, UIO_USERSPACE, |
---|
2789 | uap->mode, 0)); |
---|
2790 | } |
---|
2791 | |
---|
2792 | #ifndef _SYS_SYSPROTO_H_ |
---|
2793 | struct fchmodat_args { |
---|
2794 | int dirfd; |
---|
2795 | char *path; |
---|
2796 | mode_t mode; |
---|
2797 | int flag; |
---|
2798 | } |
---|
2799 | #endif |
---|
2800 | int |
---|
2801 | sys_fchmodat(struct thread *td, struct fchmodat_args *uap) |
---|
2802 | { |
---|
2803 | int flag = uap->flag; |
---|
2804 | int fd = uap->fd; |
---|
2805 | char *path = uap->path; |
---|
2806 | mode_t mode = uap->mode; |
---|
2807 | |
---|
2808 | if (flag & ~AT_SYMLINK_NOFOLLOW) |
---|
2809 | return (EINVAL); |
---|
2810 | |
---|
2811 | return (kern_fchmodat(td, fd, path, UIO_USERSPACE, mode, flag)); |
---|
2812 | } |
---|
2813 | |
---|
2814 | /* |
---|
2815 | * Change mode of a file given path name (don't follow links.) |
---|
2816 | */ |
---|
2817 | #ifndef _SYS_SYSPROTO_H_ |
---|
2818 | struct lchmod_args { |
---|
2819 | char *path; |
---|
2820 | int mode; |
---|
2821 | }; |
---|
2822 | #endif |
---|
2823 | int |
---|
2824 | sys_lchmod(struct thread *td, struct lchmod_args *uap) |
---|
2825 | { |
---|
2826 | |
---|
2827 | return (kern_fchmodat(td, AT_FDCWD, uap->path, UIO_USERSPACE, |
---|
2828 | uap->mode, AT_SYMLINK_NOFOLLOW)); |
---|
2829 | } |
---|
2830 | |
---|
2831 | int |
---|
2832 | kern_fchmodat(struct thread *td, int fd, char *path, enum uio_seg pathseg, |
---|
2833 | mode_t mode, int flag) |
---|
2834 | { |
---|
2835 | struct nameidata nd; |
---|
2836 | int error, follow; |
---|
2837 | |
---|
2838 | AUDIT_ARG_MODE(mode); |
---|
2839 | follow = (flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW; |
---|
2840 | NDINIT_ATRIGHTS(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path, fd, |
---|
2841 | &cap_fchmod_rights, td); |
---|
2842 | if ((error = namei(&nd)) != 0) |
---|
2843 | return (error); |
---|
2844 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
2845 | error = setfmode(td, td->td_ucred, nd.ni_vp, mode); |
---|
2846 | vrele(nd.ni_vp); |
---|
2847 | return (error); |
---|
2848 | } |
---|
2849 | |
---|
2850 | /* |
---|
2851 | * Change mode of a file given a file descriptor. |
---|
2852 | */ |
---|
2853 | #ifndef _SYS_SYSPROTO_H_ |
---|
2854 | struct fchmod_args { |
---|
2855 | int fd; |
---|
2856 | int mode; |
---|
2857 | }; |
---|
2858 | #endif |
---|
2859 | int |
---|
2860 | sys_fchmod(struct thread *td, struct fchmod_args *uap) |
---|
2861 | { |
---|
2862 | struct file *fp; |
---|
2863 | int error; |
---|
2864 | |
---|
2865 | AUDIT_ARG_FD(uap->fd); |
---|
2866 | AUDIT_ARG_MODE(uap->mode); |
---|
2867 | |
---|
2868 | error = fget(td, uap->fd, &cap_fchmod_rights, &fp); |
---|
2869 | if (error != 0) |
---|
2870 | return (error); |
---|
2871 | error = fo_chmod(fp, uap->mode, td->td_ucred, td); |
---|
2872 | fdrop(fp, td); |
---|
2873 | return (error); |
---|
2874 | } |
---|
2875 | |
---|
2876 | /* |
---|
2877 | * Common implementation for chown(), lchown(), and fchown() |
---|
2878 | */ |
---|
2879 | int |
---|
2880 | setfown(struct thread *td, struct ucred *cred, struct vnode *vp, uid_t uid, |
---|
2881 | gid_t gid) |
---|
2882 | { |
---|
2883 | struct mount *mp; |
---|
2884 | struct vattr vattr; |
---|
2885 | int error; |
---|
2886 | |
---|
2887 | if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) |
---|
2888 | return (error); |
---|
2889 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
---|
2890 | VATTR_NULL(&vattr); |
---|
2891 | vattr.va_uid = uid; |
---|
2892 | vattr.va_gid = gid; |
---|
2893 | #ifdef MAC |
---|
2894 | error = mac_vnode_check_setowner(cred, vp, vattr.va_uid, |
---|
2895 | vattr.va_gid); |
---|
2896 | if (error == 0) |
---|
2897 | #endif |
---|
2898 | error = VOP_SETATTR(vp, &vattr, cred); |
---|
2899 | VOP_UNLOCK(vp, 0); |
---|
2900 | vn_finished_write(mp); |
---|
2901 | return (error); |
---|
2902 | } |
---|
2903 | |
---|
2904 | /* |
---|
2905 | * Set ownership given a path name. |
---|
2906 | */ |
---|
2907 | #ifndef _SYS_SYSPROTO_H_ |
---|
2908 | struct chown_args { |
---|
2909 | char *path; |
---|
2910 | int uid; |
---|
2911 | int gid; |
---|
2912 | }; |
---|
2913 | #endif |
---|
2914 | int |
---|
2915 | sys_chown(struct thread *td, struct chown_args *uap) |
---|
2916 | { |
---|
2917 | |
---|
2918 | return (kern_fchownat(td, AT_FDCWD, uap->path, UIO_USERSPACE, uap->uid, |
---|
2919 | uap->gid, 0)); |
---|
2920 | } |
---|
2921 | |
---|
2922 | #ifndef _SYS_SYSPROTO_H_ |
---|
2923 | struct fchownat_args { |
---|
2924 | int fd; |
---|
2925 | const char * path; |
---|
2926 | uid_t uid; |
---|
2927 | gid_t gid; |
---|
2928 | int flag; |
---|
2929 | }; |
---|
2930 | #endif |
---|
2931 | int |
---|
2932 | sys_fchownat(struct thread *td, struct fchownat_args *uap) |
---|
2933 | { |
---|
2934 | int flag; |
---|
2935 | |
---|
2936 | flag = uap->flag; |
---|
2937 | if (flag & ~AT_SYMLINK_NOFOLLOW) |
---|
2938 | return (EINVAL); |
---|
2939 | |
---|
2940 | return (kern_fchownat(td, uap->fd, uap->path, UIO_USERSPACE, uap->uid, |
---|
2941 | uap->gid, uap->flag)); |
---|
2942 | } |
---|
2943 | |
---|
2944 | int |
---|
2945 | kern_fchownat(struct thread *td, int fd, char *path, enum uio_seg pathseg, |
---|
2946 | int uid, int gid, int flag) |
---|
2947 | { |
---|
2948 | struct nameidata nd; |
---|
2949 | int error, follow; |
---|
2950 | |
---|
2951 | AUDIT_ARG_OWNER(uid, gid); |
---|
2952 | follow = (flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW; |
---|
2953 | NDINIT_ATRIGHTS(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path, fd, |
---|
2954 | &cap_fchown_rights, td); |
---|
2955 | |
---|
2956 | if ((error = namei(&nd)) != 0) |
---|
2957 | return (error); |
---|
2958 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
2959 | error = setfown(td, td->td_ucred, nd.ni_vp, uid, gid); |
---|
2960 | vrele(nd.ni_vp); |
---|
2961 | return (error); |
---|
2962 | } |
---|
2963 | |
---|
2964 | /* |
---|
2965 | * Set ownership given a path name, do not cross symlinks. |
---|
2966 | */ |
---|
2967 | #ifndef _SYS_SYSPROTO_H_ |
---|
2968 | struct lchown_args { |
---|
2969 | char *path; |
---|
2970 | int uid; |
---|
2971 | int gid; |
---|
2972 | }; |
---|
2973 | #endif |
---|
2974 | int |
---|
2975 | sys_lchown(struct thread *td, struct lchown_args *uap) |
---|
2976 | { |
---|
2977 | |
---|
2978 | return (kern_fchownat(td, AT_FDCWD, uap->path, UIO_USERSPACE, |
---|
2979 | uap->uid, uap->gid, AT_SYMLINK_NOFOLLOW)); |
---|
2980 | } |
---|
2981 | |
---|
2982 | /* |
---|
2983 | * Set ownership given a file descriptor. |
---|
2984 | */ |
---|
2985 | #ifndef _SYS_SYSPROTO_H_ |
---|
2986 | struct fchown_args { |
---|
2987 | int fd; |
---|
2988 | int uid; |
---|
2989 | int gid; |
---|
2990 | }; |
---|
2991 | #endif |
---|
2992 | int |
---|
2993 | sys_fchown(struct thread *td, struct fchown_args *uap) |
---|
2994 | { |
---|
2995 | struct file *fp; |
---|
2996 | int error; |
---|
2997 | |
---|
2998 | AUDIT_ARG_FD(uap->fd); |
---|
2999 | AUDIT_ARG_OWNER(uap->uid, uap->gid); |
---|
3000 | error = fget(td, uap->fd, &cap_fchown_rights, &fp); |
---|
3001 | if (error != 0) |
---|
3002 | return (error); |
---|
3003 | error = fo_chown(fp, uap->uid, uap->gid, td->td_ucred, td); |
---|
3004 | fdrop(fp, td); |
---|
3005 | return (error); |
---|
3006 | } |
---|
3007 | |
---|
3008 | #ifndef __rtems__ |
---|
3009 | /* |
---|
3010 | * Common implementation code for utimes(), lutimes(), and futimes(). |
---|
3011 | */ |
---|
3012 | static int |
---|
3013 | getutimes(const struct timeval *usrtvp, enum uio_seg tvpseg, |
---|
3014 | struct timespec *tsp) |
---|
3015 | { |
---|
3016 | struct timeval tv[2]; |
---|
3017 | const struct timeval *tvp; |
---|
3018 | int error; |
---|
3019 | |
---|
3020 | if (usrtvp == NULL) { |
---|
3021 | vfs_timestamp(&tsp[0]); |
---|
3022 | tsp[1] = tsp[0]; |
---|
3023 | } else { |
---|
3024 | if (tvpseg == UIO_SYSSPACE) { |
---|
3025 | tvp = usrtvp; |
---|
3026 | } else { |
---|
3027 | if ((error = copyin(usrtvp, tv, sizeof(tv))) != 0) |
---|
3028 | return (error); |
---|
3029 | tvp = tv; |
---|
3030 | } |
---|
3031 | |
---|
3032 | if (tvp[0].tv_usec < 0 || tvp[0].tv_usec >= 1000000 || |
---|
3033 | tvp[1].tv_usec < 0 || tvp[1].tv_usec >= 1000000) |
---|
3034 | return (EINVAL); |
---|
3035 | TIMEVAL_TO_TIMESPEC(&tvp[0], &tsp[0]); |
---|
3036 | TIMEVAL_TO_TIMESPEC(&tvp[1], &tsp[1]); |
---|
3037 | } |
---|
3038 | return (0); |
---|
3039 | } |
---|
3040 | |
---|
3041 | /* |
---|
3042 | * Common implementation code for futimens(), utimensat(). |
---|
3043 | */ |
---|
3044 | #define UTIMENS_NULL 0x1 |
---|
3045 | #define UTIMENS_EXIT 0x2 |
---|
3046 | static int |
---|
3047 | getutimens(const struct timespec *usrtsp, enum uio_seg tspseg, |
---|
3048 | struct timespec *tsp, int *retflags) |
---|
3049 | { |
---|
3050 | struct timespec tsnow; |
---|
3051 | int error; |
---|
3052 | |
---|
3053 | vfs_timestamp(&tsnow); |
---|
3054 | *retflags = 0; |
---|
3055 | if (usrtsp == NULL) { |
---|
3056 | tsp[0] = tsnow; |
---|
3057 | tsp[1] = tsnow; |
---|
3058 | *retflags |= UTIMENS_NULL; |
---|
3059 | return (0); |
---|
3060 | } |
---|
3061 | if (tspseg == UIO_SYSSPACE) { |
---|
3062 | tsp[0] = usrtsp[0]; |
---|
3063 | tsp[1] = usrtsp[1]; |
---|
3064 | } else if ((error = copyin(usrtsp, tsp, sizeof(*tsp) * 2)) != 0) |
---|
3065 | return (error); |
---|
3066 | if (tsp[0].tv_nsec == UTIME_OMIT && tsp[1].tv_nsec == UTIME_OMIT) |
---|
3067 | *retflags |= UTIMENS_EXIT; |
---|
3068 | if (tsp[0].tv_nsec == UTIME_NOW && tsp[1].tv_nsec == UTIME_NOW) |
---|
3069 | *retflags |= UTIMENS_NULL; |
---|
3070 | if (tsp[0].tv_nsec == UTIME_OMIT) |
---|
3071 | tsp[0].tv_sec = VNOVAL; |
---|
3072 | else if (tsp[0].tv_nsec == UTIME_NOW) |
---|
3073 | tsp[0] = tsnow; |
---|
3074 | else if (tsp[0].tv_nsec < 0 || tsp[0].tv_nsec >= 1000000000L) |
---|
3075 | return (EINVAL); |
---|
3076 | if (tsp[1].tv_nsec == UTIME_OMIT) |
---|
3077 | tsp[1].tv_sec = VNOVAL; |
---|
3078 | else if (tsp[1].tv_nsec == UTIME_NOW) |
---|
3079 | tsp[1] = tsnow; |
---|
3080 | else if (tsp[1].tv_nsec < 0 || tsp[1].tv_nsec >= 1000000000L) |
---|
3081 | return (EINVAL); |
---|
3082 | |
---|
3083 | return (0); |
---|
3084 | } |
---|
3085 | |
---|
3086 | /* |
---|
3087 | * Common implementation code for utimes(), lutimes(), futimes(), futimens(), |
---|
3088 | * and utimensat(). |
---|
3089 | */ |
---|
3090 | static int |
---|
3091 | setutimes(struct thread *td, struct vnode *vp, const struct timespec *ts, |
---|
3092 | int numtimes, int nullflag) |
---|
3093 | { |
---|
3094 | struct mount *mp; |
---|
3095 | struct vattr vattr; |
---|
3096 | int error, setbirthtime; |
---|
3097 | |
---|
3098 | if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) |
---|
3099 | return (error); |
---|
3100 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
---|
3101 | setbirthtime = 0; |
---|
3102 | if (numtimes < 3 && !VOP_GETATTR(vp, &vattr, td->td_ucred) && |
---|
3103 | timespeccmp(&ts[1], &vattr.va_birthtime, < )) |
---|
3104 | setbirthtime = 1; |
---|
3105 | VATTR_NULL(&vattr); |
---|
3106 | vattr.va_atime = ts[0]; |
---|
3107 | vattr.va_mtime = ts[1]; |
---|
3108 | if (setbirthtime) |
---|
3109 | vattr.va_birthtime = ts[1]; |
---|
3110 | if (numtimes > 2) |
---|
3111 | vattr.va_birthtime = ts[2]; |
---|
3112 | if (nullflag) |
---|
3113 | vattr.va_vaflags |= VA_UTIMES_NULL; |
---|
3114 | #ifdef MAC |
---|
3115 | error = mac_vnode_check_setutimes(td->td_ucred, vp, vattr.va_atime, |
---|
3116 | vattr.va_mtime); |
---|
3117 | #endif |
---|
3118 | if (error == 0) |
---|
3119 | error = VOP_SETATTR(vp, &vattr, td->td_ucred); |
---|
3120 | VOP_UNLOCK(vp, 0); |
---|
3121 | vn_finished_write(mp); |
---|
3122 | return (error); |
---|
3123 | } |
---|
3124 | |
---|
3125 | /* |
---|
3126 | * Set the access and modification times of a file. |
---|
3127 | */ |
---|
3128 | #ifndef _SYS_SYSPROTO_H_ |
---|
3129 | struct utimes_args { |
---|
3130 | char *path; |
---|
3131 | struct timeval *tptr; |
---|
3132 | }; |
---|
3133 | #endif |
---|
3134 | int |
---|
3135 | sys_utimes(struct thread *td, struct utimes_args *uap) |
---|
3136 | { |
---|
3137 | |
---|
3138 | return (kern_utimesat(td, AT_FDCWD, uap->path, UIO_USERSPACE, |
---|
3139 | uap->tptr, UIO_USERSPACE)); |
---|
3140 | } |
---|
3141 | |
---|
3142 | #ifndef _SYS_SYSPROTO_H_ |
---|
3143 | struct futimesat_args { |
---|
3144 | int fd; |
---|
3145 | const char * path; |
---|
3146 | const struct timeval * times; |
---|
3147 | }; |
---|
3148 | #endif |
---|
3149 | int |
---|
3150 | sys_futimesat(struct thread *td, struct futimesat_args *uap) |
---|
3151 | { |
---|
3152 | |
---|
3153 | return (kern_utimesat(td, uap->fd, uap->path, UIO_USERSPACE, |
---|
3154 | uap->times, UIO_USERSPACE)); |
---|
3155 | } |
---|
3156 | |
---|
3157 | int |
---|
3158 | kern_utimesat(struct thread *td, int fd, char *path, enum uio_seg pathseg, |
---|
3159 | struct timeval *tptr, enum uio_seg tptrseg) |
---|
3160 | { |
---|
3161 | struct nameidata nd; |
---|
3162 | struct timespec ts[2]; |
---|
3163 | int error; |
---|
3164 | |
---|
3165 | if ((error = getutimes(tptr, tptrseg, ts)) != 0) |
---|
3166 | return (error); |
---|
3167 | NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | AUDITVNODE1, pathseg, path, fd, |
---|
3168 | &cap_futimes_rights, td); |
---|
3169 | |
---|
3170 | if ((error = namei(&nd)) != 0) |
---|
3171 | return (error); |
---|
3172 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
3173 | error = setutimes(td, nd.ni_vp, ts, 2, tptr == NULL); |
---|
3174 | vrele(nd.ni_vp); |
---|
3175 | return (error); |
---|
3176 | } |
---|
3177 | |
---|
3178 | /* |
---|
3179 | * Set the access and modification times of a file. |
---|
3180 | */ |
---|
3181 | #ifndef _SYS_SYSPROTO_H_ |
---|
3182 | struct lutimes_args { |
---|
3183 | char *path; |
---|
3184 | struct timeval *tptr; |
---|
3185 | }; |
---|
3186 | #endif |
---|
3187 | int |
---|
3188 | sys_lutimes(struct thread *td, struct lutimes_args *uap) |
---|
3189 | { |
---|
3190 | |
---|
3191 | return (kern_lutimes(td, uap->path, UIO_USERSPACE, uap->tptr, |
---|
3192 | UIO_USERSPACE)); |
---|
3193 | } |
---|
3194 | |
---|
3195 | int |
---|
3196 | kern_lutimes(struct thread *td, char *path, enum uio_seg pathseg, |
---|
3197 | struct timeval *tptr, enum uio_seg tptrseg) |
---|
3198 | { |
---|
3199 | struct timespec ts[2]; |
---|
3200 | struct nameidata nd; |
---|
3201 | int error; |
---|
3202 | |
---|
3203 | if ((error = getutimes(tptr, tptrseg, ts)) != 0) |
---|
3204 | return (error); |
---|
3205 | NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, pathseg, path, td); |
---|
3206 | if ((error = namei(&nd)) != 0) |
---|
3207 | return (error); |
---|
3208 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
3209 | error = setutimes(td, nd.ni_vp, ts, 2, tptr == NULL); |
---|
3210 | vrele(nd.ni_vp); |
---|
3211 | return (error); |
---|
3212 | } |
---|
3213 | |
---|
3214 | /* |
---|
3215 | * Set the access and modification times of a file. |
---|
3216 | */ |
---|
3217 | #ifndef _SYS_SYSPROTO_H_ |
---|
3218 | struct futimes_args { |
---|
3219 | int fd; |
---|
3220 | struct timeval *tptr; |
---|
3221 | }; |
---|
3222 | #endif |
---|
3223 | int |
---|
3224 | sys_futimes(struct thread *td, struct futimes_args *uap) |
---|
3225 | { |
---|
3226 | |
---|
3227 | return (kern_futimes(td, uap->fd, uap->tptr, UIO_USERSPACE)); |
---|
3228 | } |
---|
3229 | |
---|
3230 | int |
---|
3231 | kern_futimes(struct thread *td, int fd, struct timeval *tptr, |
---|
3232 | enum uio_seg tptrseg) |
---|
3233 | { |
---|
3234 | struct timespec ts[2]; |
---|
3235 | struct file *fp; |
---|
3236 | int error; |
---|
3237 | |
---|
3238 | AUDIT_ARG_FD(fd); |
---|
3239 | error = getutimes(tptr, tptrseg, ts); |
---|
3240 | if (error != 0) |
---|
3241 | return (error); |
---|
3242 | error = getvnode(td, fd, &cap_futimes_rights, &fp); |
---|
3243 | if (error != 0) |
---|
3244 | return (error); |
---|
3245 | #ifdef AUDIT |
---|
3246 | vn_lock(fp->f_vnode, LK_SHARED | LK_RETRY); |
---|
3247 | AUDIT_ARG_VNODE1(fp->f_vnode); |
---|
3248 | VOP_UNLOCK(fp->f_vnode, 0); |
---|
3249 | #endif |
---|
3250 | error = setutimes(td, fp->f_vnode, ts, 2, tptr == NULL); |
---|
3251 | fdrop(fp, td); |
---|
3252 | return (error); |
---|
3253 | } |
---|
3254 | |
---|
3255 | int |
---|
3256 | sys_futimens(struct thread *td, struct futimens_args *uap) |
---|
3257 | { |
---|
3258 | |
---|
3259 | return (kern_futimens(td, uap->fd, uap->times, UIO_USERSPACE)); |
---|
3260 | } |
---|
3261 | |
---|
3262 | int |
---|
3263 | kern_futimens(struct thread *td, int fd, struct timespec *tptr, |
---|
3264 | enum uio_seg tptrseg) |
---|
3265 | { |
---|
3266 | struct timespec ts[2]; |
---|
3267 | struct file *fp; |
---|
3268 | int error, flags; |
---|
3269 | |
---|
3270 | AUDIT_ARG_FD(fd); |
---|
3271 | error = getutimens(tptr, tptrseg, ts, &flags); |
---|
3272 | if (error != 0) |
---|
3273 | return (error); |
---|
3274 | if (flags & UTIMENS_EXIT) |
---|
3275 | return (0); |
---|
3276 | error = getvnode(td, fd, &cap_futimes_rights, &fp); |
---|
3277 | if (error != 0) |
---|
3278 | return (error); |
---|
3279 | #ifdef AUDIT |
---|
3280 | vn_lock(fp->f_vnode, LK_SHARED | LK_RETRY); |
---|
3281 | AUDIT_ARG_VNODE1(fp->f_vnode); |
---|
3282 | VOP_UNLOCK(fp->f_vnode, 0); |
---|
3283 | #endif |
---|
3284 | error = setutimes(td, fp->f_vnode, ts, 2, flags & UTIMENS_NULL); |
---|
3285 | fdrop(fp, td); |
---|
3286 | return (error); |
---|
3287 | } |
---|
3288 | |
---|
3289 | int |
---|
3290 | sys_utimensat(struct thread *td, struct utimensat_args *uap) |
---|
3291 | { |
---|
3292 | |
---|
3293 | return (kern_utimensat(td, uap->fd, uap->path, UIO_USERSPACE, |
---|
3294 | uap->times, UIO_USERSPACE, uap->flag)); |
---|
3295 | } |
---|
3296 | |
---|
3297 | int |
---|
3298 | kern_utimensat(struct thread *td, int fd, char *path, enum uio_seg pathseg, |
---|
3299 | struct timespec *tptr, enum uio_seg tptrseg, int flag) |
---|
3300 | { |
---|
3301 | struct nameidata nd; |
---|
3302 | struct timespec ts[2]; |
---|
3303 | int error, flags; |
---|
3304 | |
---|
3305 | if (flag & ~AT_SYMLINK_NOFOLLOW) |
---|
3306 | return (EINVAL); |
---|
3307 | |
---|
3308 | if ((error = getutimens(tptr, tptrseg, ts, &flags)) != 0) |
---|
3309 | return (error); |
---|
3310 | NDINIT_ATRIGHTS(&nd, LOOKUP, ((flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : |
---|
3311 | FOLLOW) | AUDITVNODE1, pathseg, path, fd, |
---|
3312 | &cap_futimes_rights, td); |
---|
3313 | if ((error = namei(&nd)) != 0) |
---|
3314 | return (error); |
---|
3315 | /* |
---|
3316 | * We are allowed to call namei() regardless of 2xUTIME_OMIT. |
---|
3317 | * POSIX states: |
---|
3318 | * "If both tv_nsec fields are UTIME_OMIT... EACCESS may be detected." |
---|
3319 | * "Search permission is denied by a component of the path prefix." |
---|
3320 | */ |
---|
3321 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
3322 | if ((flags & UTIMENS_EXIT) == 0) |
---|
3323 | error = setutimes(td, nd.ni_vp, ts, 2, flags & UTIMENS_NULL); |
---|
3324 | vrele(nd.ni_vp); |
---|
3325 | return (error); |
---|
3326 | } |
---|
3327 | #endif /* __rtems__ */ |
---|
3328 | |
---|
3329 | /* |
---|
3330 | * Truncate a file given its path name. |
---|
3331 | */ |
---|
3332 | #ifndef _SYS_SYSPROTO_H_ |
---|
3333 | struct truncate_args { |
---|
3334 | char *path; |
---|
3335 | int pad; |
---|
3336 | off_t length; |
---|
3337 | }; |
---|
3338 | #endif |
---|
3339 | int |
---|
3340 | sys_truncate(struct thread *td, struct truncate_args *uap) |
---|
3341 | { |
---|
3342 | |
---|
3343 | return (kern_truncate(td, uap->path, UIO_USERSPACE, uap->length)); |
---|
3344 | } |
---|
3345 | |
---|
3346 | int |
---|
3347 | kern_truncate(struct thread *td, char *path, enum uio_seg pathseg, off_t length) |
---|
3348 | { |
---|
3349 | struct mount *mp; |
---|
3350 | struct vnode *vp; |
---|
3351 | void *rl_cookie; |
---|
3352 | struct vattr vattr; |
---|
3353 | struct nameidata nd; |
---|
3354 | int error; |
---|
3355 | |
---|
3356 | if (length < 0) |
---|
3357 | return(EINVAL); |
---|
3358 | NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, pathseg, path, td); |
---|
3359 | if ((error = namei(&nd)) != 0) |
---|
3360 | return (error); |
---|
3361 | vp = nd.ni_vp; |
---|
3362 | rl_cookie = vn_rangelock_wlock(vp, 0, OFF_MAX); |
---|
3363 | if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) { |
---|
3364 | vn_rangelock_unlock(vp, rl_cookie); |
---|
3365 | vrele(vp); |
---|
3366 | return (error); |
---|
3367 | } |
---|
3368 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
3369 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
---|
3370 | if (vp->v_type == VDIR) |
---|
3371 | error = EISDIR; |
---|
3372 | #ifdef MAC |
---|
3373 | else if ((error = mac_vnode_check_write(td->td_ucred, NOCRED, vp))) { |
---|
3374 | } |
---|
3375 | #endif |
---|
3376 | else if ((error = vn_writechk(vp)) == 0 && |
---|
3377 | (error = VOP_ACCESS(vp, VWRITE, td->td_ucred, td)) == 0) { |
---|
3378 | VATTR_NULL(&vattr); |
---|
3379 | vattr.va_size = length; |
---|
3380 | error = VOP_SETATTR(vp, &vattr, td->td_ucred); |
---|
3381 | } |
---|
3382 | VOP_UNLOCK(vp, 0); |
---|
3383 | vn_finished_write(mp); |
---|
3384 | vn_rangelock_unlock(vp, rl_cookie); |
---|
3385 | vrele(vp); |
---|
3386 | return (error); |
---|
3387 | } |
---|
3388 | |
---|
3389 | #if defined(COMPAT_43) |
---|
3390 | /* |
---|
3391 | * Truncate a file given its path name. |
---|
3392 | */ |
---|
3393 | #ifndef _SYS_SYSPROTO_H_ |
---|
3394 | struct otruncate_args { |
---|
3395 | char *path; |
---|
3396 | long length; |
---|
3397 | }; |
---|
3398 | #endif |
---|
3399 | int |
---|
3400 | otruncate(struct thread *td, struct otruncate_args *uap) |
---|
3401 | { |
---|
3402 | |
---|
3403 | return (kern_truncate(td, uap->path, UIO_USERSPACE, uap->length)); |
---|
3404 | } |
---|
3405 | #endif /* COMPAT_43 */ |
---|
3406 | |
---|
3407 | #if defined(COMPAT_FREEBSD6) |
---|
3408 | /* Versions with the pad argument */ |
---|
3409 | int |
---|
3410 | freebsd6_truncate(struct thread *td, struct freebsd6_truncate_args *uap) |
---|
3411 | { |
---|
3412 | |
---|
3413 | return (kern_truncate(td, uap->path, UIO_USERSPACE, uap->length)); |
---|
3414 | } |
---|
3415 | |
---|
3416 | int |
---|
3417 | freebsd6_ftruncate(struct thread *td, struct freebsd6_ftruncate_args *uap) |
---|
3418 | { |
---|
3419 | |
---|
3420 | return (kern_ftruncate(td, uap->fd, uap->length)); |
---|
3421 | } |
---|
3422 | #endif |
---|
3423 | |
---|
3424 | int |
---|
3425 | kern_fsync(struct thread *td, int fd, bool fullsync) |
---|
3426 | { |
---|
3427 | struct vnode *vp; |
---|
3428 | struct mount *mp; |
---|
3429 | struct file *fp; |
---|
3430 | int error, lock_flags; |
---|
3431 | |
---|
3432 | AUDIT_ARG_FD(fd); |
---|
3433 | error = getvnode(td, fd, &cap_fsync_rights, &fp); |
---|
3434 | if (error != 0) |
---|
3435 | return (error); |
---|
3436 | vp = fp->f_vnode; |
---|
3437 | #if 0 |
---|
3438 | if (!fullsync) |
---|
3439 | /* XXXKIB: compete outstanding aio writes */; |
---|
3440 | #endif |
---|
3441 | error = vn_start_write(vp, &mp, V_WAIT | PCATCH); |
---|
3442 | if (error != 0) |
---|
3443 | goto drop; |
---|
3444 | if (MNT_SHARED_WRITES(mp) || |
---|
3445 | ((mp == NULL) && MNT_SHARED_WRITES(vp->v_mount))) { |
---|
3446 | lock_flags = LK_SHARED; |
---|
3447 | } else { |
---|
3448 | lock_flags = LK_EXCLUSIVE; |
---|
3449 | } |
---|
3450 | vn_lock(vp, lock_flags | LK_RETRY); |
---|
3451 | AUDIT_ARG_VNODE1(vp); |
---|
3452 | #ifndef __rtems__ |
---|
3453 | if (vp->v_object != NULL) { |
---|
3454 | VM_OBJECT_WLOCK(vp->v_object); |
---|
3455 | vm_object_page_clean(vp->v_object, 0, 0, 0); |
---|
3456 | VM_OBJECT_WUNLOCK(vp->v_object); |
---|
3457 | } |
---|
3458 | #endif /* __rtems__ */ |
---|
3459 | error = fullsync ? VOP_FSYNC(vp, MNT_WAIT, td) : VOP_FDATASYNC(vp, td); |
---|
3460 | VOP_UNLOCK(vp, 0); |
---|
3461 | vn_finished_write(mp); |
---|
3462 | drop: |
---|
3463 | fdrop(fp, td); |
---|
3464 | return (error); |
---|
3465 | } |
---|
3466 | |
---|
3467 | /* |
---|
3468 | * Sync an open file. |
---|
3469 | */ |
---|
3470 | #ifndef _SYS_SYSPROTO_H_ |
---|
3471 | struct fsync_args { |
---|
3472 | int fd; |
---|
3473 | }; |
---|
3474 | #endif |
---|
3475 | int |
---|
3476 | sys_fsync(struct thread *td, struct fsync_args *uap) |
---|
3477 | { |
---|
3478 | |
---|
3479 | return (kern_fsync(td, uap->fd, true)); |
---|
3480 | } |
---|
3481 | |
---|
3482 | int |
---|
3483 | sys_fdatasync(struct thread *td, struct fdatasync_args *uap) |
---|
3484 | { |
---|
3485 | |
---|
3486 | return (kern_fsync(td, uap->fd, false)); |
---|
3487 | } |
---|
3488 | |
---|
3489 | /* |
---|
3490 | * Rename files. Source and destination must either both be directories, or |
---|
3491 | * both not be directories. If target is a directory, it must be empty. |
---|
3492 | */ |
---|
3493 | #ifndef _SYS_SYSPROTO_H_ |
---|
3494 | struct rename_args { |
---|
3495 | char *from; |
---|
3496 | char *to; |
---|
3497 | }; |
---|
3498 | #endif |
---|
3499 | int |
---|
3500 | sys_rename(struct thread *td, struct rename_args *uap) |
---|
3501 | { |
---|
3502 | |
---|
3503 | return (kern_renameat(td, AT_FDCWD, uap->from, AT_FDCWD, |
---|
3504 | uap->to, UIO_USERSPACE)); |
---|
3505 | } |
---|
3506 | |
---|
3507 | #ifndef _SYS_SYSPROTO_H_ |
---|
3508 | struct renameat_args { |
---|
3509 | int oldfd; |
---|
3510 | char *old; |
---|
3511 | int newfd; |
---|
3512 | char *new; |
---|
3513 | }; |
---|
3514 | #endif |
---|
3515 | int |
---|
3516 | sys_renameat(struct thread *td, struct renameat_args *uap) |
---|
3517 | { |
---|
3518 | |
---|
3519 | return (kern_renameat(td, uap->oldfd, uap->old, uap->newfd, uap->new, |
---|
3520 | UIO_USERSPACE)); |
---|
3521 | } |
---|
3522 | |
---|
3523 | int |
---|
3524 | kern_renameat(struct thread *td, int oldfd, char *old, int newfd, char *new, |
---|
3525 | enum uio_seg pathseg) |
---|
3526 | { |
---|
3527 | struct mount *mp = NULL; |
---|
3528 | struct vnode *tvp, *fvp, *tdvp; |
---|
3529 | struct nameidata fromnd, tond; |
---|
3530 | int error; |
---|
3531 | |
---|
3532 | again: |
---|
3533 | bwillwrite(); |
---|
3534 | #ifdef MAC |
---|
3535 | NDINIT_ATRIGHTS(&fromnd, DELETE, LOCKPARENT | LOCKLEAF | SAVESTART | |
---|
3536 | AUDITVNODE1, pathseg, old, oldfd, |
---|
3537 | &cap_renameat_source_rights, td); |
---|
3538 | #else |
---|
3539 | NDINIT_ATRIGHTS(&fromnd, DELETE, WANTPARENT | SAVESTART | AUDITVNODE1, |
---|
3540 | pathseg, old, oldfd, |
---|
3541 | &cap_renameat_source_rights, td); |
---|
3542 | #endif |
---|
3543 | |
---|
3544 | if ((error = namei(&fromnd)) != 0) |
---|
3545 | return (error); |
---|
3546 | #ifdef MAC |
---|
3547 | error = mac_vnode_check_rename_from(td->td_ucred, fromnd.ni_dvp, |
---|
3548 | fromnd.ni_vp, &fromnd.ni_cnd); |
---|
3549 | VOP_UNLOCK(fromnd.ni_dvp, 0); |
---|
3550 | if (fromnd.ni_dvp != fromnd.ni_vp) |
---|
3551 | VOP_UNLOCK(fromnd.ni_vp, 0); |
---|
3552 | #endif |
---|
3553 | fvp = fromnd.ni_vp; |
---|
3554 | NDINIT_ATRIGHTS(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | |
---|
3555 | SAVESTART | AUDITVNODE2, pathseg, new, newfd, |
---|
3556 | &cap_renameat_target_rights, td); |
---|
3557 | if (fromnd.ni_vp->v_type == VDIR) |
---|
3558 | tond.ni_cnd.cn_flags |= WILLBEDIR; |
---|
3559 | if ((error = namei(&tond)) != 0) { |
---|
3560 | /* Translate error code for rename("dir1", "dir2/."). */ |
---|
3561 | if (error == EISDIR && fvp->v_type == VDIR) |
---|
3562 | error = EINVAL; |
---|
3563 | NDFREE(&fromnd, NDF_ONLY_PNBUF); |
---|
3564 | vrele(fromnd.ni_dvp); |
---|
3565 | vrele(fvp); |
---|
3566 | goto out1; |
---|
3567 | } |
---|
3568 | tdvp = tond.ni_dvp; |
---|
3569 | tvp = tond.ni_vp; |
---|
3570 | error = vn_start_write(fvp, &mp, V_NOWAIT); |
---|
3571 | if (error != 0) { |
---|
3572 | NDFREE(&fromnd, NDF_ONLY_PNBUF); |
---|
3573 | NDFREE(&tond, NDF_ONLY_PNBUF); |
---|
3574 | if (tvp != NULL) |
---|
3575 | vput(tvp); |
---|
3576 | if (tdvp == tvp) |
---|
3577 | vrele(tdvp); |
---|
3578 | else |
---|
3579 | vput(tdvp); |
---|
3580 | vrele(fromnd.ni_dvp); |
---|
3581 | vrele(fvp); |
---|
3582 | vrele(tond.ni_startdir); |
---|
3583 | if (fromnd.ni_startdir != NULL) |
---|
3584 | vrele(fromnd.ni_startdir); |
---|
3585 | error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH); |
---|
3586 | if (error != 0) |
---|
3587 | return (error); |
---|
3588 | goto again; |
---|
3589 | } |
---|
3590 | if (tvp != NULL) { |
---|
3591 | if (fvp->v_type == VDIR && tvp->v_type != VDIR) { |
---|
3592 | error = ENOTDIR; |
---|
3593 | goto out; |
---|
3594 | } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { |
---|
3595 | error = EISDIR; |
---|
3596 | goto out; |
---|
3597 | } |
---|
3598 | #ifdef CAPABILITIES |
---|
3599 | if (newfd != AT_FDCWD && (tond.ni_resflags & NIRES_ABS) == 0) { |
---|
3600 | /* |
---|
3601 | * If the target already exists we require CAP_UNLINKAT |
---|
3602 | * from 'newfd', when newfd was used for the lookup. |
---|
3603 | */ |
---|
3604 | error = cap_check(&tond.ni_filecaps.fc_rights, |
---|
3605 | &cap_unlinkat_rights); |
---|
3606 | if (error != 0) |
---|
3607 | goto out; |
---|
3608 | } |
---|
3609 | #endif |
---|
3610 | } |
---|
3611 | if (fvp == tdvp) { |
---|
3612 | error = EINVAL; |
---|
3613 | goto out; |
---|
3614 | } |
---|
3615 | /* |
---|
3616 | * If the source is the same as the destination (that is, if they |
---|
3617 | * are links to the same vnode), then there is nothing to do. |
---|
3618 | */ |
---|
3619 | if (fvp == tvp) |
---|
3620 | error = -1; |
---|
3621 | #ifdef MAC |
---|
3622 | else |
---|
3623 | error = mac_vnode_check_rename_to(td->td_ucred, tdvp, |
---|
3624 | tond.ni_vp, fromnd.ni_dvp == tdvp, &tond.ni_cnd); |
---|
3625 | #endif |
---|
3626 | out: |
---|
3627 | if (error == 0) { |
---|
3628 | error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, |
---|
3629 | tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); |
---|
3630 | NDFREE(&fromnd, NDF_ONLY_PNBUF); |
---|
3631 | NDFREE(&tond, NDF_ONLY_PNBUF); |
---|
3632 | } else { |
---|
3633 | NDFREE(&fromnd, NDF_ONLY_PNBUF); |
---|
3634 | NDFREE(&tond, NDF_ONLY_PNBUF); |
---|
3635 | if (tvp != NULL) |
---|
3636 | vput(tvp); |
---|
3637 | if (tdvp == tvp) |
---|
3638 | vrele(tdvp); |
---|
3639 | else |
---|
3640 | vput(tdvp); |
---|
3641 | vrele(fromnd.ni_dvp); |
---|
3642 | vrele(fvp); |
---|
3643 | } |
---|
3644 | vrele(tond.ni_startdir); |
---|
3645 | vn_finished_write(mp); |
---|
3646 | out1: |
---|
3647 | if (fromnd.ni_startdir) |
---|
3648 | vrele(fromnd.ni_startdir); |
---|
3649 | if (error == -1) |
---|
3650 | return (0); |
---|
3651 | return (error); |
---|
3652 | } |
---|
3653 | |
---|
3654 | /* |
---|
3655 | * Make a directory file. |
---|
3656 | */ |
---|
3657 | #ifndef _SYS_SYSPROTO_H_ |
---|
3658 | struct mkdir_args { |
---|
3659 | char *path; |
---|
3660 | int mode; |
---|
3661 | }; |
---|
3662 | #endif |
---|
3663 | int |
---|
3664 | sys_mkdir(struct thread *td, struct mkdir_args *uap) |
---|
3665 | { |
---|
3666 | |
---|
3667 | return (kern_mkdirat(td, AT_FDCWD, uap->path, UIO_USERSPACE, |
---|
3668 | uap->mode)); |
---|
3669 | } |
---|
3670 | |
---|
3671 | #ifndef _SYS_SYSPROTO_H_ |
---|
3672 | struct mkdirat_args { |
---|
3673 | int fd; |
---|
3674 | char *path; |
---|
3675 | mode_t mode; |
---|
3676 | }; |
---|
3677 | #endif |
---|
3678 | int |
---|
3679 | sys_mkdirat(struct thread *td, struct mkdirat_args *uap) |
---|
3680 | { |
---|
3681 | |
---|
3682 | return (kern_mkdirat(td, uap->fd, uap->path, UIO_USERSPACE, uap->mode)); |
---|
3683 | } |
---|
3684 | |
---|
3685 | int |
---|
3686 | kern_mkdirat(struct thread *td, int fd, char *path, enum uio_seg segflg, |
---|
3687 | int mode) |
---|
3688 | { |
---|
3689 | struct mount *mp; |
---|
3690 | struct vnode *vp; |
---|
3691 | struct vattr vattr; |
---|
3692 | struct nameidata nd; |
---|
3693 | int error; |
---|
3694 | |
---|
3695 | AUDIT_ARG_MODE(mode); |
---|
3696 | restart: |
---|
3697 | bwillwrite(); |
---|
3698 | NDINIT_ATRIGHTS(&nd, CREATE, LOCKPARENT | SAVENAME | AUDITVNODE1 | |
---|
3699 | NOCACHE, segflg, path, fd, &cap_mkdirat_rights, |
---|
3700 | td); |
---|
3701 | nd.ni_cnd.cn_flags |= WILLBEDIR; |
---|
3702 | if ((error = namei(&nd)) != 0) |
---|
3703 | return (error); |
---|
3704 | vp = nd.ni_vp; |
---|
3705 | if (vp != NULL) { |
---|
3706 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
3707 | /* |
---|
3708 | * XXX namei called with LOCKPARENT but not LOCKLEAF has |
---|
3709 | * the strange behaviour of leaving the vnode unlocked |
---|
3710 | * if the target is the same vnode as the parent. |
---|
3711 | */ |
---|
3712 | if (vp == nd.ni_dvp) |
---|
3713 | vrele(nd.ni_dvp); |
---|
3714 | else |
---|
3715 | vput(nd.ni_dvp); |
---|
3716 | vrele(vp); |
---|
3717 | return (EEXIST); |
---|
3718 | } |
---|
3719 | if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { |
---|
3720 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
3721 | vput(nd.ni_dvp); |
---|
3722 | if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0) |
---|
3723 | return (error); |
---|
3724 | goto restart; |
---|
3725 | } |
---|
3726 | VATTR_NULL(&vattr); |
---|
3727 | vattr.va_type = VDIR; |
---|
3728 | vattr.va_mode = (mode & ACCESSPERMS) &~ td->td_proc->p_fd->fd_cmask; |
---|
3729 | #ifdef MAC |
---|
3730 | error = mac_vnode_check_create(td->td_ucred, nd.ni_dvp, &nd.ni_cnd, |
---|
3731 | &vattr); |
---|
3732 | if (error != 0) |
---|
3733 | goto out; |
---|
3734 | #endif |
---|
3735 | error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); |
---|
3736 | #ifdef MAC |
---|
3737 | out: |
---|
3738 | #endif |
---|
3739 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
3740 | vput(nd.ni_dvp); |
---|
3741 | if (error == 0) |
---|
3742 | vput(nd.ni_vp); |
---|
3743 | vn_finished_write(mp); |
---|
3744 | return (error); |
---|
3745 | } |
---|
3746 | |
---|
3747 | /* |
---|
3748 | * Remove a directory file. |
---|
3749 | */ |
---|
3750 | #ifndef _SYS_SYSPROTO_H_ |
---|
3751 | struct rmdir_args { |
---|
3752 | char *path; |
---|
3753 | }; |
---|
3754 | #endif |
---|
3755 | int |
---|
3756 | sys_rmdir(struct thread *td, struct rmdir_args *uap) |
---|
3757 | { |
---|
3758 | |
---|
3759 | return (kern_rmdirat(td, AT_FDCWD, uap->path, UIO_USERSPACE)); |
---|
3760 | } |
---|
3761 | |
---|
3762 | int |
---|
3763 | kern_rmdirat(struct thread *td, int fd, char *path, enum uio_seg pathseg) |
---|
3764 | { |
---|
3765 | struct mount *mp; |
---|
3766 | struct vnode *vp; |
---|
3767 | struct nameidata nd; |
---|
3768 | int error; |
---|
3769 | |
---|
3770 | restart: |
---|
3771 | bwillwrite(); |
---|
3772 | NDINIT_ATRIGHTS(&nd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNODE1, |
---|
3773 | pathseg, path, fd, &cap_unlinkat_rights, td); |
---|
3774 | if ((error = namei(&nd)) != 0) |
---|
3775 | return (error); |
---|
3776 | vp = nd.ni_vp; |
---|
3777 | if (vp->v_type != VDIR) { |
---|
3778 | error = ENOTDIR; |
---|
3779 | goto out; |
---|
3780 | } |
---|
3781 | /* |
---|
3782 | * No rmdir "." please. |
---|
3783 | */ |
---|
3784 | if (nd.ni_dvp == vp) { |
---|
3785 | error = EINVAL; |
---|
3786 | goto out; |
---|
3787 | } |
---|
3788 | /* |
---|
3789 | * The root of a mounted filesystem cannot be deleted. |
---|
3790 | */ |
---|
3791 | if (vp->v_vflag & VV_ROOT) { |
---|
3792 | error = EBUSY; |
---|
3793 | goto out; |
---|
3794 | } |
---|
3795 | #ifdef MAC |
---|
3796 | error = mac_vnode_check_unlink(td->td_ucred, nd.ni_dvp, vp, |
---|
3797 | &nd.ni_cnd); |
---|
3798 | if (error != 0) |
---|
3799 | goto out; |
---|
3800 | #endif |
---|
3801 | if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { |
---|
3802 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
3803 | vput(vp); |
---|
3804 | if (nd.ni_dvp == vp) |
---|
3805 | vrele(nd.ni_dvp); |
---|
3806 | else |
---|
3807 | vput(nd.ni_dvp); |
---|
3808 | if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0) |
---|
3809 | return (error); |
---|
3810 | goto restart; |
---|
3811 | } |
---|
3812 | vfs_notify_upper(vp, VFS_NOTIFY_UPPER_UNLINK); |
---|
3813 | error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); |
---|
3814 | vn_finished_write(mp); |
---|
3815 | out: |
---|
3816 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
3817 | vput(vp); |
---|
3818 | if (nd.ni_dvp == vp) |
---|
3819 | vrele(nd.ni_dvp); |
---|
3820 | else |
---|
3821 | vput(nd.ni_dvp); |
---|
3822 | return (error); |
---|
3823 | } |
---|
3824 | |
---|
3825 | #if defined(COMPAT_43) || defined(COMPAT_FREEBSD11) |
---|
3826 | int |
---|
3827 | freebsd11_kern_getdirentries(struct thread *td, int fd, char *ubuf, u_int count, |
---|
3828 | long *basep, void (*func)(struct freebsd11_dirent *)) |
---|
3829 | { |
---|
3830 | struct freebsd11_dirent dstdp; |
---|
3831 | struct dirent *dp, *edp; |
---|
3832 | char *dirbuf; |
---|
3833 | off_t base; |
---|
3834 | ssize_t resid, ucount; |
---|
3835 | int error; |
---|
3836 | |
---|
3837 | /* XXX arbitrary sanity limit on `count'. */ |
---|
3838 | count = min(count, 64 * 1024); |
---|
3839 | |
---|
3840 | dirbuf = malloc(count, M_TEMP, M_WAITOK); |
---|
3841 | |
---|
3842 | error = kern_getdirentries(td, fd, dirbuf, count, &base, &resid, |
---|
3843 | UIO_SYSSPACE); |
---|
3844 | if (error != 0) |
---|
3845 | goto done; |
---|
3846 | if (basep != NULL) |
---|
3847 | *basep = base; |
---|
3848 | |
---|
3849 | ucount = 0; |
---|
3850 | for (dp = (struct dirent *)dirbuf, |
---|
3851 | edp = (struct dirent *)&dirbuf[count - resid]; |
---|
3852 | ucount < count && dp < edp; ) { |
---|
3853 | if (dp->d_reclen == 0) |
---|
3854 | break; |
---|
3855 | MPASS(dp->d_reclen >= _GENERIC_DIRLEN(0)); |
---|
3856 | if (dp->d_namlen >= sizeof(dstdp.d_name)) |
---|
3857 | continue; |
---|
3858 | dstdp.d_type = dp->d_type; |
---|
3859 | dstdp.d_namlen = dp->d_namlen; |
---|
3860 | dstdp.d_fileno = dp->d_fileno; /* truncate */ |
---|
3861 | if (dstdp.d_fileno != dp->d_fileno) { |
---|
3862 | switch (ino64_trunc_error) { |
---|
3863 | default: |
---|
3864 | case 0: |
---|
3865 | break; |
---|
3866 | case 1: |
---|
3867 | error = EOVERFLOW; |
---|
3868 | goto done; |
---|
3869 | case 2: |
---|
3870 | dstdp.d_fileno = UINT32_MAX; |
---|
3871 | break; |
---|
3872 | } |
---|
3873 | } |
---|
3874 | dstdp.d_reclen = sizeof(dstdp) - sizeof(dstdp.d_name) + |
---|
3875 | ((dp->d_namlen + 1 + 3) &~ 3); |
---|
3876 | bcopy(dp->d_name, dstdp.d_name, dstdp.d_namlen); |
---|
3877 | bzero(dstdp.d_name + dstdp.d_namlen, |
---|
3878 | dstdp.d_reclen - offsetof(struct freebsd11_dirent, d_name) - |
---|
3879 | dstdp.d_namlen); |
---|
3880 | MPASS(dstdp.d_reclen <= dp->d_reclen); |
---|
3881 | MPASS(ucount + dstdp.d_reclen <= count); |
---|
3882 | if (func != NULL) |
---|
3883 | func(&dstdp); |
---|
3884 | error = copyout(&dstdp, ubuf + ucount, dstdp.d_reclen); |
---|
3885 | if (error != 0) |
---|
3886 | break; |
---|
3887 | dp = (struct dirent *)((char *)dp + dp->d_reclen); |
---|
3888 | ucount += dstdp.d_reclen; |
---|
3889 | } |
---|
3890 | |
---|
3891 | done: |
---|
3892 | free(dirbuf, M_TEMP); |
---|
3893 | if (error == 0) |
---|
3894 | td->td_retval[0] = ucount; |
---|
3895 | return (error); |
---|
3896 | } |
---|
3897 | #endif /* COMPAT */ |
---|
3898 | |
---|
3899 | #ifdef COMPAT_43 |
---|
3900 | static void |
---|
3901 | ogetdirentries_cvt(struct freebsd11_dirent *dp) |
---|
3902 | { |
---|
3903 | #if (BYTE_ORDER == LITTLE_ENDIAN) |
---|
3904 | /* |
---|
3905 | * The expected low byte of dp->d_namlen is our dp->d_type. |
---|
3906 | * The high MBZ byte of dp->d_namlen is our dp->d_namlen. |
---|
3907 | */ |
---|
3908 | dp->d_type = dp->d_namlen; |
---|
3909 | dp->d_namlen = 0; |
---|
3910 | #else |
---|
3911 | /* |
---|
3912 | * The dp->d_type is the high byte of the expected dp->d_namlen, |
---|
3913 | * so must be zero'ed. |
---|
3914 | */ |
---|
3915 | dp->d_type = 0; |
---|
3916 | #endif |
---|
3917 | } |
---|
3918 | |
---|
3919 | /* |
---|
3920 | * Read a block of directory entries in a filesystem independent format. |
---|
3921 | */ |
---|
3922 | #ifndef _SYS_SYSPROTO_H_ |
---|
3923 | struct ogetdirentries_args { |
---|
3924 | int fd; |
---|
3925 | char *buf; |
---|
3926 | u_int count; |
---|
3927 | long *basep; |
---|
3928 | }; |
---|
3929 | #endif |
---|
3930 | int |
---|
3931 | ogetdirentries(struct thread *td, struct ogetdirentries_args *uap) |
---|
3932 | { |
---|
3933 | long loff; |
---|
3934 | int error; |
---|
3935 | |
---|
3936 | error = kern_ogetdirentries(td, uap, &loff); |
---|
3937 | if (error == 0) |
---|
3938 | error = copyout(&loff, uap->basep, sizeof(long)); |
---|
3939 | return (error); |
---|
3940 | } |
---|
3941 | |
---|
3942 | int |
---|
3943 | kern_ogetdirentries(struct thread *td, struct ogetdirentries_args *uap, |
---|
3944 | long *ploff) |
---|
3945 | { |
---|
3946 | long base; |
---|
3947 | int error; |
---|
3948 | |
---|
3949 | /* XXX arbitrary sanity limit on `count'. */ |
---|
3950 | if (uap->count > 64 * 1024) |
---|
3951 | return (EINVAL); |
---|
3952 | |
---|
3953 | error = freebsd11_kern_getdirentries(td, uap->fd, uap->buf, uap->count, |
---|
3954 | &base, ogetdirentries_cvt); |
---|
3955 | |
---|
3956 | if (error == 0 && uap->basep != NULL) |
---|
3957 | error = copyout(&base, uap->basep, sizeof(long)); |
---|
3958 | |
---|
3959 | return (error); |
---|
3960 | } |
---|
3961 | #endif /* COMPAT_43 */ |
---|
3962 | |
---|
3963 | #if defined(COMPAT_FREEBSD11) |
---|
3964 | #ifndef _SYS_SYSPROTO_H_ |
---|
3965 | struct freebsd11_getdirentries_args { |
---|
3966 | int fd; |
---|
3967 | char *buf; |
---|
3968 | u_int count; |
---|
3969 | long *basep; |
---|
3970 | }; |
---|
3971 | #endif |
---|
3972 | int |
---|
3973 | freebsd11_getdirentries(struct thread *td, |
---|
3974 | struct freebsd11_getdirentries_args *uap) |
---|
3975 | { |
---|
3976 | long base; |
---|
3977 | int error; |
---|
3978 | |
---|
3979 | error = freebsd11_kern_getdirentries(td, uap->fd, uap->buf, uap->count, |
---|
3980 | &base, NULL); |
---|
3981 | |
---|
3982 | if (error == 0 && uap->basep != NULL) |
---|
3983 | error = copyout(&base, uap->basep, sizeof(long)); |
---|
3984 | return (error); |
---|
3985 | } |
---|
3986 | |
---|
3987 | int |
---|
3988 | freebsd11_getdents(struct thread *td, struct freebsd11_getdents_args *uap) |
---|
3989 | { |
---|
3990 | struct freebsd11_getdirentries_args ap; |
---|
3991 | |
---|
3992 | ap.fd = uap->fd; |
---|
3993 | ap.buf = uap->buf; |
---|
3994 | ap.count = uap->count; |
---|
3995 | ap.basep = NULL; |
---|
3996 | return (freebsd11_getdirentries(td, &ap)); |
---|
3997 | } |
---|
3998 | #endif /* COMPAT_FREEBSD11 */ |
---|
3999 | |
---|
4000 | /* |
---|
4001 | * Read a block of directory entries in a filesystem independent format. |
---|
4002 | */ |
---|
4003 | int |
---|
4004 | sys_getdirentries(struct thread *td, struct getdirentries_args *uap) |
---|
4005 | { |
---|
4006 | off_t base; |
---|
4007 | int error; |
---|
4008 | |
---|
4009 | error = kern_getdirentries(td, uap->fd, uap->buf, uap->count, &base, |
---|
4010 | NULL, UIO_USERSPACE); |
---|
4011 | if (error != 0) |
---|
4012 | return (error); |
---|
4013 | if (uap->basep != NULL) |
---|
4014 | error = copyout(&base, uap->basep, sizeof(off_t)); |
---|
4015 | return (error); |
---|
4016 | } |
---|
4017 | |
---|
4018 | int |
---|
4019 | kern_getdirentries(struct thread *td, int fd, char *buf, size_t count, |
---|
4020 | off_t *basep, ssize_t *residp, enum uio_seg bufseg) |
---|
4021 | { |
---|
4022 | struct vnode *vp; |
---|
4023 | struct file *fp; |
---|
4024 | struct uio auio; |
---|
4025 | struct iovec aiov; |
---|
4026 | off_t loff; |
---|
4027 | int error, eofflag; |
---|
4028 | off_t foffset; |
---|
4029 | |
---|
4030 | AUDIT_ARG_FD(fd); |
---|
4031 | if (count > IOSIZE_MAX) |
---|
4032 | return (EINVAL); |
---|
4033 | auio.uio_resid = count; |
---|
4034 | error = getvnode(td, fd, &cap_read_rights, &fp); |
---|
4035 | if (error != 0) |
---|
4036 | return (error); |
---|
4037 | if ((fp->f_flag & FREAD) == 0) { |
---|
4038 | fdrop(fp, td); |
---|
4039 | return (EBADF); |
---|
4040 | } |
---|
4041 | vp = fp->f_vnode; |
---|
4042 | foffset = foffset_lock(fp, 0); |
---|
4043 | unionread: |
---|
4044 | if (vp->v_type != VDIR) { |
---|
4045 | error = EINVAL; |
---|
4046 | goto fail; |
---|
4047 | } |
---|
4048 | aiov.iov_base = buf; |
---|
4049 | aiov.iov_len = count; |
---|
4050 | auio.uio_iov = &aiov; |
---|
4051 | auio.uio_iovcnt = 1; |
---|
4052 | auio.uio_rw = UIO_READ; |
---|
4053 | auio.uio_segflg = bufseg; |
---|
4054 | auio.uio_td = td; |
---|
4055 | vn_lock(vp, LK_SHARED | LK_RETRY); |
---|
4056 | AUDIT_ARG_VNODE1(vp); |
---|
4057 | loff = auio.uio_offset = foffset; |
---|
4058 | #ifdef MAC |
---|
4059 | error = mac_vnode_check_readdir(td->td_ucred, vp); |
---|
4060 | if (error == 0) |
---|
4061 | #endif |
---|
4062 | error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, NULL, |
---|
4063 | NULL); |
---|
4064 | foffset = auio.uio_offset; |
---|
4065 | if (error != 0) { |
---|
4066 | VOP_UNLOCK(vp, 0); |
---|
4067 | goto fail; |
---|
4068 | } |
---|
4069 | if (count == auio.uio_resid && |
---|
4070 | (vp->v_vflag & VV_ROOT) && |
---|
4071 | (vp->v_mount->mnt_flag & MNT_UNION)) { |
---|
4072 | struct vnode *tvp = vp; |
---|
4073 | |
---|
4074 | vp = vp->v_mount->mnt_vnodecovered; |
---|
4075 | VREF(vp); |
---|
4076 | fp->f_vnode = vp; |
---|
4077 | fp->f_data = vp; |
---|
4078 | foffset = 0; |
---|
4079 | vput(tvp); |
---|
4080 | goto unionread; |
---|
4081 | } |
---|
4082 | VOP_UNLOCK(vp, 0); |
---|
4083 | *basep = loff; |
---|
4084 | if (residp != NULL) |
---|
4085 | *residp = auio.uio_resid; |
---|
4086 | td->td_retval[0] = count - auio.uio_resid; |
---|
4087 | fail: |
---|
4088 | foffset_unlock(fp, foffset, 0); |
---|
4089 | fdrop(fp, td); |
---|
4090 | return (error); |
---|
4091 | } |
---|
4092 | |
---|
4093 | #ifndef __rtems__ |
---|
4094 | /* |
---|
4095 | * Set the mode mask for creation of filesystem nodes. |
---|
4096 | */ |
---|
4097 | #ifndef _SYS_SYSPROTO_H_ |
---|
4098 | struct umask_args { |
---|
4099 | int newmask; |
---|
4100 | }; |
---|
4101 | #endif |
---|
4102 | int |
---|
4103 | sys_umask(struct thread *td, struct umask_args *uap) |
---|
4104 | { |
---|
4105 | struct filedesc *fdp; |
---|
4106 | |
---|
4107 | fdp = td->td_proc->p_fd; |
---|
4108 | FILEDESC_XLOCK(fdp); |
---|
4109 | td->td_retval[0] = fdp->fd_cmask; |
---|
4110 | fdp->fd_cmask = uap->newmask & ALLPERMS; |
---|
4111 | FILEDESC_XUNLOCK(fdp); |
---|
4112 | return (0); |
---|
4113 | } |
---|
4114 | |
---|
4115 | /* |
---|
4116 | * Void all references to file by ripping underlying filesystem away from |
---|
4117 | * vnode. |
---|
4118 | */ |
---|
4119 | #ifndef _SYS_SYSPROTO_H_ |
---|
4120 | struct revoke_args { |
---|
4121 | char *path; |
---|
4122 | }; |
---|
4123 | #endif |
---|
4124 | int |
---|
4125 | sys_revoke(struct thread *td, struct revoke_args *uap) |
---|
4126 | { |
---|
4127 | struct vnode *vp; |
---|
4128 | struct vattr vattr; |
---|
4129 | struct nameidata nd; |
---|
4130 | int error; |
---|
4131 | |
---|
4132 | NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1, UIO_USERSPACE, |
---|
4133 | uap->path, td); |
---|
4134 | if ((error = namei(&nd)) != 0) |
---|
4135 | return (error); |
---|
4136 | vp = nd.ni_vp; |
---|
4137 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
4138 | if (vp->v_type != VCHR || vp->v_rdev == NULL) { |
---|
4139 | error = EINVAL; |
---|
4140 | goto out; |
---|
4141 | } |
---|
4142 | #ifdef MAC |
---|
4143 | error = mac_vnode_check_revoke(td->td_ucred, vp); |
---|
4144 | if (error != 0) |
---|
4145 | goto out; |
---|
4146 | #endif |
---|
4147 | error = VOP_GETATTR(vp, &vattr, td->td_ucred); |
---|
4148 | if (error != 0) |
---|
4149 | goto out; |
---|
4150 | if (td->td_ucred->cr_uid != vattr.va_uid) { |
---|
4151 | error = priv_check(td, PRIV_VFS_ADMIN); |
---|
4152 | if (error != 0) |
---|
4153 | goto out; |
---|
4154 | } |
---|
4155 | if (vcount(vp) > 1) |
---|
4156 | VOP_REVOKE(vp, REVOKEALL); |
---|
4157 | out: |
---|
4158 | vput(vp); |
---|
4159 | return (error); |
---|
4160 | } |
---|
4161 | #endif /* __rtems__ */ |
---|
4162 | |
---|
4163 | /* |
---|
4164 | * Convert a user file descriptor to a kernel file entry and check that, if it |
---|
4165 | * is a capability, the correct rights are present. A reference on the file |
---|
4166 | * entry is held upon returning. |
---|
4167 | */ |
---|
4168 | int |
---|
4169 | getvnode(struct thread *td, int fd, cap_rights_t *rightsp, struct file **fpp) |
---|
4170 | { |
---|
4171 | struct file *fp; |
---|
4172 | int error; |
---|
4173 | |
---|
4174 | error = fget_unlocked(td->td_proc->p_fd, fd, rightsp, &fp, NULL); |
---|
4175 | if (error != 0) |
---|
4176 | return (error); |
---|
4177 | |
---|
4178 | /* |
---|
4179 | * The file could be not of the vnode type, or it may be not |
---|
4180 | * yet fully initialized, in which case the f_vnode pointer |
---|
4181 | * may be set, but f_ops is still badfileops. E.g., |
---|
4182 | * devfs_open() transiently create such situation to |
---|
4183 | * facilitate csw d_fdopen(). |
---|
4184 | * |
---|
4185 | * Dupfdopen() handling in kern_openat() installs the |
---|
4186 | * half-baked file into the process descriptor table, allowing |
---|
4187 | * other thread to dereference it. Guard against the race by |
---|
4188 | * checking f_ops. |
---|
4189 | */ |
---|
4190 | if (fp->f_vnode == NULL || fp->f_ops == &badfileops) { |
---|
4191 | fdrop(fp, td); |
---|
4192 | return (EINVAL); |
---|
4193 | } |
---|
4194 | *fpp = fp; |
---|
4195 | return (0); |
---|
4196 | } |
---|
4197 | |
---|
4198 | |
---|
4199 | #ifndef __rtems__ |
---|
4200 | /* |
---|
4201 | * Get an (NFS) file handle. |
---|
4202 | */ |
---|
4203 | #ifndef _SYS_SYSPROTO_H_ |
---|
4204 | struct lgetfh_args { |
---|
4205 | char *fname; |
---|
4206 | fhandle_t *fhp; |
---|
4207 | }; |
---|
4208 | #endif |
---|
4209 | int |
---|
4210 | sys_lgetfh(struct thread *td, struct lgetfh_args *uap) |
---|
4211 | { |
---|
4212 | |
---|
4213 | return (kern_getfhat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->fname, |
---|
4214 | UIO_USERSPACE, uap->fhp)); |
---|
4215 | } |
---|
4216 | |
---|
4217 | #ifndef _SYS_SYSPROTO_H_ |
---|
4218 | struct getfh_args { |
---|
4219 | char *fname; |
---|
4220 | fhandle_t *fhp; |
---|
4221 | }; |
---|
4222 | #endif |
---|
4223 | int |
---|
4224 | sys_getfh(struct thread *td, struct getfh_args *uap) |
---|
4225 | { |
---|
4226 | |
---|
4227 | return (kern_getfhat(td, 0, AT_FDCWD, uap->fname, UIO_USERSPACE, |
---|
4228 | uap->fhp)); |
---|
4229 | } |
---|
4230 | |
---|
4231 | /* |
---|
4232 | * syscall for the rpc.lockd to use to translate an open descriptor into |
---|
4233 | * a NFS file handle. |
---|
4234 | * |
---|
4235 | * warning: do not remove the priv_check() call or this becomes one giant |
---|
4236 | * security hole. |
---|
4237 | */ |
---|
4238 | #ifndef _SYS_SYSPROTO_H_ |
---|
4239 | struct getfhat_args { |
---|
4240 | int fd; |
---|
4241 | char *path; |
---|
4242 | fhandle_t *fhp; |
---|
4243 | int flags; |
---|
4244 | }; |
---|
4245 | #endif |
---|
4246 | int |
---|
4247 | sys_getfhat(struct thread *td, struct getfhat_args *uap) |
---|
4248 | { |
---|
4249 | |
---|
4250 | if ((uap->flags & ~(AT_SYMLINK_NOFOLLOW)) != 0) |
---|
4251 | return (EINVAL); |
---|
4252 | return (kern_getfhat(td, uap->flags, uap->fd, uap->path, UIO_USERSPACE, |
---|
4253 | uap->fhp)); |
---|
4254 | } |
---|
4255 | |
---|
4256 | static int |
---|
4257 | kern_getfhat(struct thread *td, int flags, int fd, const char *path, |
---|
4258 | enum uio_seg pathseg, fhandle_t *fhp) |
---|
4259 | { |
---|
4260 | struct nameidata nd; |
---|
4261 | fhandle_t fh; |
---|
4262 | struct vnode *vp; |
---|
4263 | int error; |
---|
4264 | |
---|
4265 | error = priv_check(td, PRIV_VFS_GETFH); |
---|
4266 | if (error != 0) |
---|
4267 | return (error); |
---|
4268 | NDINIT_AT(&nd, LOOKUP, ((flags & AT_SYMLINK_NOFOLLOW) != 0 ? NOFOLLOW : |
---|
4269 | FOLLOW) | /*((flags & AT_BENEATH) != 0 ? BENEATH : 0) |*/ LOCKLEAF | |
---|
4270 | AUDITVNODE1, pathseg, path, fd, td); |
---|
4271 | error = namei(&nd); |
---|
4272 | if (error != 0) |
---|
4273 | return (error); |
---|
4274 | NDFREE(&nd, NDF_ONLY_PNBUF); |
---|
4275 | vp = nd.ni_vp; |
---|
4276 | bzero(&fh, sizeof(fh)); |
---|
4277 | fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid; |
---|
4278 | error = VOP_VPTOFH(vp, &fh.fh_fid); |
---|
4279 | vput(vp); |
---|
4280 | if (error == 0) |
---|
4281 | error = copyout(&fh, fhp, sizeof (fh)); |
---|
4282 | return (error); |
---|
4283 | } |
---|
4284 | |
---|
4285 | #ifndef _SYS_SYSPROTO_H_ |
---|
4286 | struct fhlink_args { |
---|
4287 | fhandle_t *fhp; |
---|
4288 | const char *to; |
---|
4289 | }; |
---|
4290 | #endif |
---|
4291 | int |
---|
4292 | sys_fhlink(struct thread *td, struct fhlink_args *uap) |
---|
4293 | { |
---|
4294 | |
---|
4295 | return (kern_fhlinkat(td, AT_FDCWD, uap->to, UIO_USERSPACE, uap->fhp)); |
---|
4296 | } |
---|
4297 | |
---|
4298 | #ifndef _SYS_SYSPROTO_H_ |
---|
4299 | struct fhlinkat_args { |
---|
4300 | fhandle_t *fhp; |
---|
4301 | int tofd; |
---|
4302 | const char *to; |
---|
4303 | }; |
---|
4304 | #endif |
---|
4305 | int |
---|
4306 | sys_fhlinkat(struct thread *td, struct fhlinkat_args *uap) |
---|
4307 | { |
---|
4308 | |
---|
4309 | return (kern_fhlinkat(td, uap->tofd, uap->to, UIO_USERSPACE, uap->fhp)); |
---|
4310 | } |
---|
4311 | |
---|
4312 | static int |
---|
4313 | kern_fhlinkat(struct thread *td, int fd, const char *path, |
---|
4314 | enum uio_seg pathseg, fhandle_t *fhp) |
---|
4315 | { |
---|
4316 | fhandle_t fh; |
---|
4317 | struct mount *mp; |
---|
4318 | struct vnode *vp; |
---|
4319 | int error; |
---|
4320 | |
---|
4321 | error = priv_check(td, PRIV_VFS_GETFH); |
---|
4322 | if (error != 0) |
---|
4323 | return (error); |
---|
4324 | error = copyin(fhp, &fh, sizeof(fh)); |
---|
4325 | if (error != 0) |
---|
4326 | return (error); |
---|
4327 | do { |
---|
4328 | bwillwrite(); |
---|
4329 | if ((mp = vfs_busyfs(&fh.fh_fsid)) == NULL) |
---|
4330 | return (ESTALE); |
---|
4331 | error = VFS_FHTOVP(mp, &fh.fh_fid, LK_SHARED, &vp); |
---|
4332 | vfs_unbusy(mp); |
---|
4333 | if (error != 0) |
---|
4334 | return (error); |
---|
4335 | VOP_UNLOCK(vp, 0); |
---|
4336 | } while ((error = kern_linkat_vp(td, vp, fd, path, pathseg)) == EAGAIN); |
---|
4337 | return (error); |
---|
4338 | } |
---|
4339 | |
---|
4340 | #ifndef _SYS_SYSPROTO_H_ |
---|
4341 | struct fhreadlink_args { |
---|
4342 | fhandle_t *fhp; |
---|
4343 | char *buf; |
---|
4344 | size_t bufsize; |
---|
4345 | }; |
---|
4346 | #endif |
---|
4347 | int |
---|
4348 | sys_fhreadlink(struct thread *td, struct fhreadlink_args *uap) |
---|
4349 | { |
---|
4350 | fhandle_t fh; |
---|
4351 | struct mount *mp; |
---|
4352 | struct vnode *vp; |
---|
4353 | int error; |
---|
4354 | |
---|
4355 | error = priv_check(td, PRIV_VFS_GETFH); |
---|
4356 | if (error != 0) |
---|
4357 | return (error); |
---|
4358 | if (uap->bufsize > IOSIZE_MAX) |
---|
4359 | return (EINVAL); |
---|
4360 | error = copyin(uap->fhp, &fh, sizeof(fh)); |
---|
4361 | if (error != 0) |
---|
4362 | return (error); |
---|
4363 | if ((mp = vfs_busyfs(&fh.fh_fsid)) == NULL) |
---|
4364 | return (ESTALE); |
---|
4365 | error = VFS_FHTOVP(mp, &fh.fh_fid, LK_SHARED, &vp); |
---|
4366 | vfs_unbusy(mp); |
---|
4367 | if (error != 0) |
---|
4368 | return (error); |
---|
4369 | error = kern_readlink_vp(vp, uap->buf, UIO_USERSPACE, uap->bufsize, td); |
---|
4370 | vput(vp); |
---|
4371 | return (error); |
---|
4372 | } |
---|
4373 | |
---|
4374 | /* |
---|
4375 | * syscall for the rpc.lockd to use to translate a NFS file handle into an |
---|
4376 | * open descriptor. |
---|
4377 | * |
---|
4378 | * warning: do not remove the priv_check() call or this becomes one giant |
---|
4379 | * security hole. |
---|
4380 | */ |
---|
4381 | #ifndef _SYS_SYSPROTO_H_ |
---|
4382 | struct fhopen_args { |
---|
4383 | const struct fhandle *u_fhp; |
---|
4384 | int flags; |
---|
4385 | }; |
---|
4386 | #endif |
---|
4387 | int |
---|
4388 | sys_fhopen(struct thread *td, struct fhopen_args *uap) |
---|
4389 | { |
---|
4390 | struct mount *mp; |
---|
4391 | struct vnode *vp; |
---|
4392 | struct fhandle fhp; |
---|
4393 | struct file *fp; |
---|
4394 | int fmode, error; |
---|
4395 | int indx; |
---|
4396 | |
---|
4397 | error = priv_check(td, PRIV_VFS_FHOPEN); |
---|
4398 | if (error != 0) |
---|
4399 | return (error); |
---|
4400 | indx = -1; |
---|
4401 | fmode = FFLAGS(uap->flags); |
---|
4402 | /* why not allow a non-read/write open for our lockd? */ |
---|
4403 | if (((fmode & (FREAD | FWRITE)) == 0) || (fmode & O_CREAT)) |
---|
4404 | return (EINVAL); |
---|
4405 | error = copyin(uap->u_fhp, &fhp, sizeof(fhp)); |
---|
4406 | if (error != 0) |
---|
4407 | return(error); |
---|
4408 | /* find the mount point */ |
---|
4409 | mp = vfs_busyfs(&fhp.fh_fsid); |
---|
4410 | if (mp == NULL) |
---|
4411 | return (ESTALE); |
---|
4412 | /* now give me my vnode, it gets returned to me locked */ |
---|
4413 | error = VFS_FHTOVP(mp, &fhp.fh_fid, LK_EXCLUSIVE, &vp); |
---|
4414 | vfs_unbusy(mp); |
---|
4415 | if (error != 0) |
---|
4416 | return (error); |
---|
4417 | |
---|
4418 | error = falloc_noinstall(td, &fp); |
---|
4419 | if (error != 0) { |
---|
4420 | vput(vp); |
---|
4421 | return (error); |
---|
4422 | } |
---|
4423 | /* |
---|
4424 | * An extra reference on `fp' has been held for us by |
---|
4425 | * falloc_noinstall(). |
---|
4426 | */ |
---|
4427 | |
---|
4428 | #ifdef INVARIANTS |
---|
4429 | td->td_dupfd = -1; |
---|
4430 | #endif |
---|
4431 | error = vn_open_vnode(vp, fmode, td->td_ucred, td, fp); |
---|
4432 | if (error != 0) { |
---|
4433 | KASSERT(fp->f_ops == &badfileops, |
---|
4434 | ("VOP_OPEN in fhopen() set f_ops")); |
---|
4435 | KASSERT(td->td_dupfd < 0, |
---|
4436 | ("fhopen() encountered fdopen()")); |
---|
4437 | |
---|
4438 | vput(vp); |
---|
4439 | goto bad; |
---|
4440 | } |
---|
4441 | #ifdef INVARIANTS |
---|
4442 | td->td_dupfd = 0; |
---|
4443 | #endif |
---|
4444 | fp->f_vnode = vp; |
---|
4445 | fp->f_seqcount = 1; |
---|
4446 | finit(fp, (fmode & FMASK) | (fp->f_flag & FHASLOCK), DTYPE_VNODE, vp, |
---|
4447 | &vnops); |
---|
4448 | VOP_UNLOCK(vp, 0); |
---|
4449 | if ((fmode & O_TRUNC) != 0) { |
---|
4450 | error = fo_truncate(fp, 0, td->td_ucred, td); |
---|
4451 | if (error != 0) |
---|
4452 | goto bad; |
---|
4453 | } |
---|
4454 | |
---|
4455 | error = finstall(td, fp, &indx, fmode, NULL); |
---|
4456 | bad: |
---|
4457 | fdrop(fp, td); |
---|
4458 | td->td_retval[0] = indx; |
---|
4459 | return (error); |
---|
4460 | } |
---|
4461 | |
---|
4462 | /* |
---|
4463 | * Stat an (NFS) file handle. |
---|
4464 | */ |
---|
4465 | #ifndef _SYS_SYSPROTO_H_ |
---|
4466 | struct fhstat_args { |
---|
4467 | struct fhandle *u_fhp; |
---|
4468 | struct stat *sb; |
---|
4469 | }; |
---|
4470 | #endif |
---|
4471 | int |
---|
4472 | sys_fhstat(struct thread *td, struct fhstat_args *uap) |
---|
4473 | { |
---|
4474 | struct stat sb; |
---|
4475 | struct fhandle fh; |
---|
4476 | int error; |
---|
4477 | |
---|
4478 | error = copyin(uap->u_fhp, &fh, sizeof(fh)); |
---|
4479 | if (error != 0) |
---|
4480 | return (error); |
---|
4481 | error = kern_fhstat(td, fh, &sb); |
---|
4482 | if (error == 0) |
---|
4483 | error = copyout(&sb, uap->sb, sizeof(sb)); |
---|
4484 | return (error); |
---|
4485 | } |
---|
4486 | |
---|
4487 | int |
---|
4488 | kern_fhstat(struct thread *td, struct fhandle fh, struct stat *sb) |
---|
4489 | { |
---|
4490 | struct mount *mp; |
---|
4491 | struct vnode *vp; |
---|
4492 | int error; |
---|
4493 | |
---|
4494 | error = priv_check(td, PRIV_VFS_FHSTAT); |
---|
4495 | if (error != 0) |
---|
4496 | return (error); |
---|
4497 | if ((mp = vfs_busyfs(&fh.fh_fsid)) == NULL) |
---|
4498 | return (ESTALE); |
---|
4499 | error = VFS_FHTOVP(mp, &fh.fh_fid, LK_EXCLUSIVE, &vp); |
---|
4500 | vfs_unbusy(mp); |
---|
4501 | if (error != 0) |
---|
4502 | return (error); |
---|
4503 | error = vn_stat(vp, sb, td->td_ucred, NOCRED, td); |
---|
4504 | vput(vp); |
---|
4505 | return (error); |
---|
4506 | } |
---|
4507 | |
---|
4508 | /* |
---|
4509 | * Implement fstatfs() for (NFS) file handles. |
---|
4510 | */ |
---|
4511 | #ifndef _SYS_SYSPROTO_H_ |
---|
4512 | struct fhstatfs_args { |
---|
4513 | struct fhandle *u_fhp; |
---|
4514 | struct statfs *buf; |
---|
4515 | }; |
---|
4516 | #endif |
---|
4517 | int |
---|
4518 | sys_fhstatfs(struct thread *td, struct fhstatfs_args *uap) |
---|
4519 | { |
---|
4520 | struct statfs *sfp; |
---|
4521 | fhandle_t fh; |
---|
4522 | int error; |
---|
4523 | |
---|
4524 | error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t)); |
---|
4525 | if (error != 0) |
---|
4526 | return (error); |
---|
4527 | sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); |
---|
4528 | error = kern_fhstatfs(td, fh, sfp); |
---|
4529 | if (error == 0) |
---|
4530 | error = copyout(sfp, uap->buf, sizeof(*sfp)); |
---|
4531 | free(sfp, M_STATFS); |
---|
4532 | return (error); |
---|
4533 | } |
---|
4534 | |
---|
4535 | int |
---|
4536 | kern_fhstatfs(struct thread *td, fhandle_t fh, struct statfs *buf) |
---|
4537 | { |
---|
4538 | struct statfs *sp; |
---|
4539 | struct mount *mp; |
---|
4540 | struct vnode *vp; |
---|
4541 | int error; |
---|
4542 | |
---|
4543 | error = priv_check(td, PRIV_VFS_FHSTATFS); |
---|
4544 | if (error != 0) |
---|
4545 | return (error); |
---|
4546 | if ((mp = vfs_busyfs(&fh.fh_fsid)) == NULL) |
---|
4547 | return (ESTALE); |
---|
4548 | error = VFS_FHTOVP(mp, &fh.fh_fid, LK_EXCLUSIVE, &vp); |
---|
4549 | if (error != 0) { |
---|
4550 | vfs_unbusy(mp); |
---|
4551 | return (error); |
---|
4552 | } |
---|
4553 | vput(vp); |
---|
4554 | error = prison_canseemount(td->td_ucred, mp); |
---|
4555 | if (error != 0) |
---|
4556 | goto out; |
---|
4557 | #ifdef MAC |
---|
4558 | error = mac_mount_check_stat(td->td_ucred, mp); |
---|
4559 | if (error != 0) |
---|
4560 | goto out; |
---|
4561 | #endif |
---|
4562 | /* |
---|
4563 | * Set these in case the underlying filesystem fails to do so. |
---|
4564 | */ |
---|
4565 | sp = &mp->mnt_stat; |
---|
4566 | sp->f_version = STATFS_VERSION; |
---|
4567 | sp->f_namemax = NAME_MAX; |
---|
4568 | sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; |
---|
4569 | error = VFS_STATFS(mp, sp); |
---|
4570 | if (error == 0) |
---|
4571 | *buf = *sp; |
---|
4572 | out: |
---|
4573 | vfs_unbusy(mp); |
---|
4574 | return (error); |
---|
4575 | } |
---|
4576 | #endif /* __rtems__ */ |
---|
4577 | |
---|
4578 | int |
---|
4579 | kern_posix_fallocate(struct thread *td, int fd, off_t offset, off_t len) |
---|
4580 | { |
---|
4581 | struct file *fp; |
---|
4582 | struct mount *mp; |
---|
4583 | struct vnode *vp; |
---|
4584 | off_t olen, ooffset; |
---|
4585 | int error; |
---|
4586 | #ifdef AUDIT |
---|
4587 | int audited_vnode1 = 0; |
---|
4588 | #endif |
---|
4589 | |
---|
4590 | AUDIT_ARG_FD(fd); |
---|
4591 | if (offset < 0 || len <= 0) |
---|
4592 | return (EINVAL); |
---|
4593 | /* Check for wrap. */ |
---|
4594 | if (offset > OFF_MAX - len) |
---|
4595 | return (EFBIG); |
---|
4596 | AUDIT_ARG_FD(fd); |
---|
4597 | error = fget(td, fd, &cap_pwrite_rights, &fp); |
---|
4598 | if (error != 0) |
---|
4599 | return (error); |
---|
4600 | AUDIT_ARG_FILE(td->td_proc, fp); |
---|
4601 | if ((fp->f_ops->fo_flags & DFLAG_SEEKABLE) == 0) { |
---|
4602 | error = ESPIPE; |
---|
4603 | goto out; |
---|
4604 | } |
---|
4605 | if ((fp->f_flag & FWRITE) == 0) { |
---|
4606 | error = EBADF; |
---|
4607 | goto out; |
---|
4608 | } |
---|
4609 | if (fp->f_type != DTYPE_VNODE) { |
---|
4610 | error = ENODEV; |
---|
4611 | goto out; |
---|
4612 | } |
---|
4613 | vp = fp->f_vnode; |
---|
4614 | if (vp->v_type != VREG) { |
---|
4615 | error = ENODEV; |
---|
4616 | goto out; |
---|
4617 | } |
---|
4618 | |
---|
4619 | /* Allocating blocks may take a long time, so iterate. */ |
---|
4620 | for (;;) { |
---|
4621 | olen = len; |
---|
4622 | ooffset = offset; |
---|
4623 | |
---|
4624 | bwillwrite(); |
---|
4625 | mp = NULL; |
---|
4626 | error = vn_start_write(vp, &mp, V_WAIT | PCATCH); |
---|
4627 | if (error != 0) |
---|
4628 | break; |
---|
4629 | error = vn_lock(vp, LK_EXCLUSIVE); |
---|
4630 | if (error != 0) { |
---|
4631 | vn_finished_write(mp); |
---|
4632 | break; |
---|
4633 | } |
---|
4634 | #ifdef AUDIT |
---|
4635 | if (!audited_vnode1) { |
---|
4636 | AUDIT_ARG_VNODE1(vp); |
---|
4637 | audited_vnode1 = 1; |
---|
4638 | } |
---|
4639 | #endif |
---|
4640 | #ifdef MAC |
---|
4641 | error = mac_vnode_check_write(td->td_ucred, fp->f_cred, vp); |
---|
4642 | if (error == 0) |
---|
4643 | #endif |
---|
4644 | error = VOP_ALLOCATE(vp, &offset, &len); |
---|
4645 | VOP_UNLOCK(vp, 0); |
---|
4646 | vn_finished_write(mp); |
---|
4647 | |
---|
4648 | if (olen + ooffset != offset + len) { |
---|
4649 | panic("offset + len changed from %jx/%jx to %jx/%jx", |
---|
4650 | ooffset, olen, offset, len); |
---|
4651 | } |
---|
4652 | if (error != 0 || len == 0) |
---|
4653 | break; |
---|
4654 | KASSERT(olen > len, ("Iteration did not make progress?")); |
---|
4655 | maybe_yield(); |
---|
4656 | } |
---|
4657 | out: |
---|
4658 | fdrop(fp, td); |
---|
4659 | return (error); |
---|
4660 | } |
---|
4661 | |
---|
4662 | #ifndef __rtems__ |
---|
4663 | int |
---|
4664 | sys_posix_fallocate(struct thread *td, struct posix_fallocate_args *uap) |
---|
4665 | { |
---|
4666 | int error; |
---|
4667 | |
---|
4668 | error = kern_posix_fallocate(td, uap->fd, uap->offset, uap->len); |
---|
4669 | return (kern_posix_error(td, error)); |
---|
4670 | } |
---|
4671 | |
---|
4672 | /* |
---|
4673 | * Unlike madvise(2), we do not make a best effort to remember every |
---|
4674 | * possible caching hint. Instead, we remember the last setting with |
---|
4675 | * the exception that we will allow POSIX_FADV_NORMAL to adjust the |
---|
4676 | * region of any current setting. |
---|
4677 | */ |
---|
4678 | int |
---|
4679 | kern_posix_fadvise(struct thread *td, int fd, off_t offset, off_t len, |
---|
4680 | int advice) |
---|
4681 | { |
---|
4682 | struct fadvise_info *fa, *new; |
---|
4683 | struct file *fp; |
---|
4684 | struct vnode *vp; |
---|
4685 | off_t end; |
---|
4686 | int error; |
---|
4687 | |
---|
4688 | if (offset < 0 || len < 0 || offset > OFF_MAX - len) |
---|
4689 | return (EINVAL); |
---|
4690 | AUDIT_ARG_VALUE(advice); |
---|
4691 | switch (advice) { |
---|
4692 | case POSIX_FADV_SEQUENTIAL: |
---|
4693 | case POSIX_FADV_RANDOM: |
---|
4694 | case POSIX_FADV_NOREUSE: |
---|
4695 | new = malloc(sizeof(*fa), M_FADVISE, M_WAITOK); |
---|
4696 | break; |
---|
4697 | case POSIX_FADV_NORMAL: |
---|
4698 | case POSIX_FADV_WILLNEED: |
---|
4699 | case POSIX_FADV_DONTNEED: |
---|
4700 | new = NULL; |
---|
4701 | break; |
---|
4702 | default: |
---|
4703 | return (EINVAL); |
---|
4704 | } |
---|
4705 | /* XXX: CAP_POSIX_FADVISE? */ |
---|
4706 | AUDIT_ARG_FD(fd); |
---|
4707 | error = fget(td, fd, &cap_no_rights, &fp); |
---|
4708 | if (error != 0) |
---|
4709 | goto out; |
---|
4710 | AUDIT_ARG_FILE(td->td_proc, fp); |
---|
4711 | if ((fp->f_ops->fo_flags & DFLAG_SEEKABLE) == 0) { |
---|
4712 | error = ESPIPE; |
---|
4713 | goto out; |
---|
4714 | } |
---|
4715 | if (fp->f_type != DTYPE_VNODE) { |
---|
4716 | error = ENODEV; |
---|
4717 | goto out; |
---|
4718 | } |
---|
4719 | vp = fp->f_vnode; |
---|
4720 | if (vp->v_type != VREG) { |
---|
4721 | error = ENODEV; |
---|
4722 | goto out; |
---|
4723 | } |
---|
4724 | if (len == 0) |
---|
4725 | end = OFF_MAX; |
---|
4726 | else |
---|
4727 | end = offset + len - 1; |
---|
4728 | switch (advice) { |
---|
4729 | case POSIX_FADV_SEQUENTIAL: |
---|
4730 | case POSIX_FADV_RANDOM: |
---|
4731 | case POSIX_FADV_NOREUSE: |
---|
4732 | /* |
---|
4733 | * Try to merge any existing non-standard region with |
---|
4734 | * this new region if possible, otherwise create a new |
---|
4735 | * non-standard region for this request. |
---|
4736 | */ |
---|
4737 | mtx_pool_lock(mtxpool_sleep, fp); |
---|
4738 | fa = fp->f_advice; |
---|
4739 | if (fa != NULL && fa->fa_advice == advice && |
---|
4740 | ((fa->fa_start <= end && fa->fa_end >= offset) || |
---|
4741 | (end != OFF_MAX && fa->fa_start == end + 1) || |
---|
4742 | (fa->fa_end != OFF_MAX && fa->fa_end + 1 == offset))) { |
---|
4743 | if (offset < fa->fa_start) |
---|
4744 | fa->fa_start = offset; |
---|
4745 | if (end > fa->fa_end) |
---|
4746 | fa->fa_end = end; |
---|
4747 | } else { |
---|
4748 | new->fa_advice = advice; |
---|
4749 | new->fa_start = offset; |
---|
4750 | new->fa_end = end; |
---|
4751 | fp->f_advice = new; |
---|
4752 | new = fa; |
---|
4753 | } |
---|
4754 | mtx_pool_unlock(mtxpool_sleep, fp); |
---|
4755 | break; |
---|
4756 | case POSIX_FADV_NORMAL: |
---|
4757 | /* |
---|
4758 | * If a the "normal" region overlaps with an existing |
---|
4759 | * non-standard region, trim or remove the |
---|
4760 | * non-standard region. |
---|
4761 | */ |
---|
4762 | mtx_pool_lock(mtxpool_sleep, fp); |
---|
4763 | fa = fp->f_advice; |
---|
4764 | if (fa != NULL) { |
---|
4765 | if (offset <= fa->fa_start && end >= fa->fa_end) { |
---|
4766 | new = fa; |
---|
4767 | fp->f_advice = NULL; |
---|
4768 | } else if (offset <= fa->fa_start && |
---|
4769 | end >= fa->fa_start) |
---|
4770 | fa->fa_start = end + 1; |
---|
4771 | else if (offset <= fa->fa_end && end >= fa->fa_end) |
---|
4772 | fa->fa_end = offset - 1; |
---|
4773 | else if (offset >= fa->fa_start && end <= fa->fa_end) { |
---|
4774 | /* |
---|
4775 | * If the "normal" region is a middle |
---|
4776 | * portion of the existing |
---|
4777 | * non-standard region, just remove |
---|
4778 | * the whole thing rather than picking |
---|
4779 | * one side or the other to |
---|
4780 | * preserve. |
---|
4781 | */ |
---|
4782 | new = fa; |
---|
4783 | fp->f_advice = NULL; |
---|
4784 | } |
---|
4785 | } |
---|
4786 | mtx_pool_unlock(mtxpool_sleep, fp); |
---|
4787 | break; |
---|
4788 | case POSIX_FADV_WILLNEED: |
---|
4789 | case POSIX_FADV_DONTNEED: |
---|
4790 | error = VOP_ADVISE(vp, offset, end, advice); |
---|
4791 | break; |
---|
4792 | } |
---|
4793 | out: |
---|
4794 | if (fp != NULL) |
---|
4795 | fdrop(fp, td); |
---|
4796 | free(new, M_FADVISE); |
---|
4797 | return (error); |
---|
4798 | } |
---|
4799 | |
---|
4800 | int |
---|
4801 | sys_posix_fadvise(struct thread *td, struct posix_fadvise_args *uap) |
---|
4802 | { |
---|
4803 | int error; |
---|
4804 | |
---|
4805 | error = kern_posix_fadvise(td, uap->fd, uap->offset, uap->len, |
---|
4806 | uap->advice); |
---|
4807 | return (kern_posix_error(td, error)); |
---|
4808 | } |
---|
4809 | #endif /* __rtems__ */ |
---|