Deleted Added
full compact
vfs_syscalls.c (101983) vfs_syscalls.c (102112)
1/*
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. 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
1/*
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. 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 * $FreeBSD: head/sys/kern/vfs_syscalls.c 101983 2002-08-16 12:52:03Z rwatson $
39 * $FreeBSD: head/sys/kern/vfs_syscalls.c 102112 2002-08-19 16:43:25Z rwatson $
40 */
41
42/* For 4.3 integer FS ID compatibility */
43#include "opt_compat.h"
44#include "opt_mac.h"
45
46#include <sys/param.h>
47#include <sys/systm.h>
48#include <sys/bio.h>
49#include <sys/buf.h>
50#include <sys/sysent.h>
51#include <sys/mac.h>
52#include <sys/malloc.h>
53#include <sys/mount.h>
54#include <sys/mutex.h>
55#include <sys/sysproto.h>
56#include <sys/namei.h>
57#include <sys/filedesc.h>
58#include <sys/kernel.h>
59#include <sys/fcntl.h>
60#include <sys/file.h>
61#include <sys/linker.h>
62#include <sys/stat.h>
63#include <sys/sx.h>
64#include <sys/unistd.h>
65#include <sys/vnode.h>
66#include <sys/proc.h>
67#include <sys/dirent.h>
68#include <sys/extattr.h>
69#include <sys/jail.h>
70#include <sys/sysctl.h>
71
72#include <machine/limits.h>
73#include <machine/stdarg.h>
74
75#include <vm/vm.h>
76#include <vm/vm_object.h>
77#include <vm/vm_page.h>
78#include <vm/uma.h>
79
80static int change_dir(struct nameidata *ndp, struct thread *td);
81static int chroot_refuse_vdir_fds(struct filedesc *fdp);
82static int getutimes(const struct timeval *, struct timespec *);
83static int setfown(struct thread *td, struct vnode *, uid_t, gid_t);
84static int setfmode(struct thread *td, struct vnode *, int);
85static int setfflags(struct thread *td, struct vnode *, int);
86static int setutimes(struct thread *td, struct vnode *,
87 const struct timespec *, int, int);
88static int vn_access(struct vnode *vp, int user_flags, struct ucred *cred,
89 struct thread *td);
90
91int (*union_dircheckp)(struct thread *td, struct vnode **, struct file *);
92int (*softdep_fsync_hook)(struct vnode *);
93
94/*
95 * Sync each mounted filesystem.
96 */
97#ifndef _SYS_SYSPROTO_H_
98struct sync_args {
99 int dummy;
100};
101#endif
102
103#ifdef DEBUG
104static int syncprt = 0;
105SYSCTL_INT(_debug, OID_AUTO, syncprt, CTLFLAG_RW, &syncprt, 0, "");
106#endif
107
108/* ARGSUSED */
109int
110sync(td, uap)
111 struct thread *td;
112 struct sync_args *uap;
113{
114 struct mount *mp, *nmp;
115 int asyncflag;
116
117 mtx_lock(&mountlist_mtx);
118 for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) {
119 if (vfs_busy(mp, LK_NOWAIT, &mountlist_mtx, td)) {
120 nmp = TAILQ_NEXT(mp, mnt_list);
121 continue;
122 }
123 if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
124 vn_start_write(NULL, &mp, V_NOWAIT) == 0) {
125 asyncflag = mp->mnt_flag & MNT_ASYNC;
126 mp->mnt_flag &= ~MNT_ASYNC;
127 vfs_msync(mp, MNT_NOWAIT);
128 VFS_SYNC(mp, MNT_NOWAIT,
129 ((td != NULL) ? td->td_ucred : NOCRED), td);
130 mp->mnt_flag |= asyncflag;
131 vn_finished_write(mp);
132 }
133 mtx_lock(&mountlist_mtx);
134 nmp = TAILQ_NEXT(mp, mnt_list);
135 vfs_unbusy(mp, td);
136 }
137 mtx_unlock(&mountlist_mtx);
138#if 0
139/*
140 * XXX don't call vfs_bufstats() yet because that routine
141 * was not imported in the Lite2 merge.
142 */
143#ifdef DIAGNOSTIC
144 if (syncprt)
145 vfs_bufstats();
146#endif /* DIAGNOSTIC */
147#endif
148 return (0);
149}
150
151/* XXX PRISON: could be per prison flag */
152static int prison_quotas;
153#if 0
154SYSCTL_INT(_kern_prison, OID_AUTO, quotas, CTLFLAG_RW, &prison_quotas, 0, "");
155#endif
156
157/*
158 * Change filesystem quotas.
159 */
160#ifndef _SYS_SYSPROTO_H_
161struct quotactl_args {
162 char *path;
163 int cmd;
164 int uid;
165 caddr_t arg;
166};
167#endif
168/* ARGSUSED */
169int
170quotactl(td, uap)
171 struct thread *td;
172 register struct quotactl_args /* {
173 syscallarg(char *) path;
174 syscallarg(int) cmd;
175 syscallarg(int) uid;
176 syscallarg(caddr_t) arg;
177 } */ *uap;
178{
179 struct mount *mp;
180 int error;
181 struct nameidata nd;
182
183 if (jailed(td->td_ucred) && !prison_quotas)
184 return (EPERM);
185 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
186 if ((error = namei(&nd)) != 0)
187 return (error);
188 NDFREE(&nd, NDF_ONLY_PNBUF);
189 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
190 vrele(nd.ni_vp);
191 if (error)
192 return (error);
193 error = VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
194 SCARG(uap, arg), td);
195 vn_finished_write(mp);
196 return (error);
197}
198
199/*
200 * Get filesystem statistics.
201 */
202#ifndef _SYS_SYSPROTO_H_
203struct statfs_args {
204 char *path;
205 struct statfs *buf;
206};
207#endif
208/* ARGSUSED */
209int
210statfs(td, uap)
211 struct thread *td;
212 register struct statfs_args /* {
213 syscallarg(char *) path;
214 syscallarg(struct statfs *) buf;
215 } */ *uap;
216{
217 register struct mount *mp;
218 register struct statfs *sp;
219 int error;
220 struct nameidata nd;
221 struct statfs sb;
222
223 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
224 if ((error = namei(&nd)) != 0)
225 return (error);
226 mp = nd.ni_vp->v_mount;
227 sp = &mp->mnt_stat;
228 NDFREE(&nd, NDF_ONLY_PNBUF);
229 vrele(nd.ni_vp);
230#ifdef MAC
231 error = mac_check_mount_stat(td->td_ucred, mp);
232 if (error)
233 return (error);
234#endif
235 error = VFS_STATFS(mp, sp, td);
236 if (error)
237 return (error);
238 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
239 if (suser(td)) {
240 bcopy(sp, &sb, sizeof(sb));
241 sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
242 sp = &sb;
243 }
244 return (copyout(sp, SCARG(uap, buf), sizeof(*sp)));
245}
246
247/*
248 * Get filesystem statistics.
249 */
250#ifndef _SYS_SYSPROTO_H_
251struct fstatfs_args {
252 int fd;
253 struct statfs *buf;
254};
255#endif
256/* ARGSUSED */
257int
258fstatfs(td, uap)
259 struct thread *td;
260 register struct fstatfs_args /* {
261 syscallarg(int) fd;
262 syscallarg(struct statfs *) buf;
263 } */ *uap;
264{
265 struct file *fp;
266 struct mount *mp;
267 register struct statfs *sp;
268 int error;
269 struct statfs sb;
270
271 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
272 return (error);
273 mp = ((struct vnode *)fp->f_data)->v_mount;
274 fdrop(fp, td);
275 if (mp == NULL)
276 return (EBADF);
277#ifdef MAC
278 error = mac_check_mount_stat(td->td_ucred, mp);
279 if (error)
280 return (error);
281#endif
282 sp = &mp->mnt_stat;
283 error = VFS_STATFS(mp, sp, td);
284 if (error)
285 return (error);
286 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
287 if (suser(td)) {
288 bcopy(sp, &sb, sizeof(sb));
289 sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
290 sp = &sb;
291 }
292 return (copyout(sp, SCARG(uap, buf), sizeof(*sp)));
293}
294
295/*
296 * Get statistics on all filesystems.
297 */
298#ifndef _SYS_SYSPROTO_H_
299struct getfsstat_args {
300 struct statfs *buf;
301 long bufsize;
302 int flags;
303};
304#endif
305int
306getfsstat(td, uap)
307 struct thread *td;
308 register struct getfsstat_args /* {
309 syscallarg(struct statfs *) buf;
310 syscallarg(long) bufsize;
311 syscallarg(int) flags;
312 } */ *uap;
313{
314 register struct mount *mp, *nmp;
315 register struct statfs *sp;
316 caddr_t sfsp;
317 long count, maxcount, error;
318
319 maxcount = SCARG(uap, bufsize) / sizeof(struct statfs);
320 sfsp = (caddr_t)SCARG(uap, buf);
321 count = 0;
322 mtx_lock(&mountlist_mtx);
323 for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) {
324#ifdef MAC
325 if (mac_check_mount_stat(td->td_ucred, mp) != 0) {
326 nmp = TAILQ_NEXT(mp, mnt_list);
327 continue;
328 }
329#endif
330 if (vfs_busy(mp, LK_NOWAIT, &mountlist_mtx, td)) {
331 nmp = TAILQ_NEXT(mp, mnt_list);
332 continue;
333 }
334 if (sfsp && count < maxcount) {
335 sp = &mp->mnt_stat;
336 /*
337 * If MNT_NOWAIT or MNT_LAZY is specified, do not
338 * refresh the fsstat cache. MNT_NOWAIT or MNT_LAZY
339 * overrides MNT_WAIT.
340 */
341 if (((SCARG(uap, flags) & (MNT_LAZY|MNT_NOWAIT)) == 0 ||
342 (SCARG(uap, flags) & MNT_WAIT)) &&
343 (error = VFS_STATFS(mp, sp, td))) {
344 mtx_lock(&mountlist_mtx);
345 nmp = TAILQ_NEXT(mp, mnt_list);
346 vfs_unbusy(mp, td);
347 continue;
348 }
349 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
350 error = copyout(sp, sfsp, sizeof(*sp));
351 if (error) {
352 vfs_unbusy(mp, td);
353 return (error);
354 }
355 sfsp += sizeof(*sp);
356 }
357 count++;
358 mtx_lock(&mountlist_mtx);
359 nmp = TAILQ_NEXT(mp, mnt_list);
360 vfs_unbusy(mp, td);
361 }
362 mtx_unlock(&mountlist_mtx);
363 if (sfsp && count > maxcount)
364 td->td_retval[0] = maxcount;
365 else
366 td->td_retval[0] = count;
367 return (0);
368}
369
370/*
371 * Change current working directory to a given file descriptor.
372 */
373#ifndef _SYS_SYSPROTO_H_
374struct fchdir_args {
375 int fd;
376};
377#endif
378/* ARGSUSED */
379int
380fchdir(td, uap)
381 struct thread *td;
382 struct fchdir_args /* {
383 syscallarg(int) fd;
384 } */ *uap;
385{
386 register struct filedesc *fdp = td->td_proc->p_fd;
387 struct vnode *vp, *tdp, *vpold;
388 struct mount *mp;
389 struct file *fp;
390 int error;
391
392 if ((error = getvnode(fdp, SCARG(uap, fd), &fp)) != 0)
393 return (error);
394 vp = (struct vnode *)fp->f_data;
395 VREF(vp);
396 fdrop(fp, td);
397 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
398 if (vp->v_type != VDIR)
399 error = ENOTDIR;
400#ifdef MAC
401 else if ((error = mac_check_vnode_chdir(td->td_ucred, vp)) != 0) {
402 }
403#endif
404 else
405 error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td);
406 while (!error && (mp = vp->v_mountedhere) != NULL) {
407 if (vfs_busy(mp, 0, 0, td))
408 continue;
409 error = VFS_ROOT(mp, &tdp);
410 vfs_unbusy(mp, td);
411 if (error)
412 break;
413 vput(vp);
414 vp = tdp;
415 }
416 if (error) {
417 vput(vp);
418 return (error);
419 }
420 VOP_UNLOCK(vp, 0, td);
421 FILEDESC_LOCK(fdp);
422 vpold = fdp->fd_cdir;
423 fdp->fd_cdir = vp;
424 FILEDESC_UNLOCK(fdp);
425 vrele(vpold);
426 return (0);
427}
428
429/*
430 * Change current working directory (``.'').
431 */
432#ifndef _SYS_SYSPROTO_H_
433struct chdir_args {
434 char *path;
435};
436#endif
437/* ARGSUSED */
438int
439chdir(td, uap)
440 struct thread *td;
441 struct chdir_args /* {
442 syscallarg(char *) path;
443 } */ *uap;
444{
445 register struct filedesc *fdp = td->td_proc->p_fd;
446 int error;
447 struct nameidata nd;
448 struct vnode *vp;
449
450 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
451 SCARG(uap, path), td);
452 if ((error = change_dir(&nd, td)) != 0)
453 return (error);
454 NDFREE(&nd, NDF_ONLY_PNBUF);
455 FILEDESC_LOCK(fdp);
456 vp = fdp->fd_cdir;
457 fdp->fd_cdir = nd.ni_vp;
458 FILEDESC_UNLOCK(fdp);
459 vrele(vp);
460 return (0);
461}
462
463/*
464 * Helper function for raised chroot(2) security function: Refuse if
465 * any filedescriptors are open directories.
466 */
467static int
468chroot_refuse_vdir_fds(fdp)
469 struct filedesc *fdp;
470{
471 struct vnode *vp;
472 struct file *fp;
473 int fd;
474
475 FILEDESC_LOCK_ASSERT(fdp, MA_OWNED);
476 for (fd = 0; fd < fdp->fd_nfiles ; fd++) {
477 fp = fget_locked(fdp, fd);
478 if (fp == NULL)
479 continue;
480 if (fp->f_type == DTYPE_VNODE) {
481 vp = (struct vnode *)fp->f_data;
482 if (vp->v_type == VDIR)
483 return (EPERM);
484 }
485 }
486 return (0);
487}
488
489/*
490 * This sysctl determines if we will allow a process to chroot(2) if it
491 * has a directory open:
492 * 0: disallowed for all processes.
493 * 1: allowed for processes that were not already chroot(2)'ed.
494 * 2: allowed for all processes.
495 */
496
497static int chroot_allow_open_directories = 1;
498
499SYSCTL_INT(_kern, OID_AUTO, chroot_allow_open_directories, CTLFLAG_RW,
500 &chroot_allow_open_directories, 0, "");
501
502/*
503 * Change notion of root (``/'') directory.
504 */
505#ifndef _SYS_SYSPROTO_H_
506struct chroot_args {
507 char *path;
508};
509#endif
510/* ARGSUSED */
511int
512chroot(td, uap)
513 struct thread *td;
514 struct chroot_args /* {
515 syscallarg(char *) path;
516 } */ *uap;
517{
518 register struct filedesc *fdp = td->td_proc->p_fd;
519 int error;
520 struct nameidata nd;
521 struct vnode *vp;
522
523 error = suser_cred(td->td_ucred, PRISON_ROOT);
524 if (error)
525 return (error);
526 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
527 SCARG(uap, path), td);
528 mtx_lock(&Giant);
529 if ((error = change_dir(&nd, td)) != 0)
530 goto error;
531#ifdef MAC
532 if ((error = mac_check_vnode_chroot(td->td_ucred, nd.ni_vp)))
533 goto error;
534#endif
535 FILEDESC_LOCK(fdp);
536 if (chroot_allow_open_directories == 0 ||
537 (chroot_allow_open_directories == 1 && fdp->fd_rdir != rootvnode)) {
538 error = chroot_refuse_vdir_fds(fdp);
539 if (error)
540 goto error_unlock;
541 }
542 vp = fdp->fd_rdir;
543 fdp->fd_rdir = nd.ni_vp;
544 if (!fdp->fd_jdir) {
545 fdp->fd_jdir = nd.ni_vp;
546 VREF(fdp->fd_jdir);
547 }
548 FILEDESC_UNLOCK(fdp);
549 NDFREE(&nd, NDF_ONLY_PNBUF);
550 vrele(vp);
551 mtx_unlock(&Giant);
552 return (0);
553error_unlock:
554 FILEDESC_UNLOCK(fdp);
555error:
556 mtx_unlock(&Giant);
557 NDFREE(&nd, 0);
558 return (error);
559}
560
561/*
562 * Common routine for chroot and chdir.
563 */
564static int
565change_dir(ndp, td)
566 register struct nameidata *ndp;
567 struct thread *td;
568{
569 struct vnode *vp;
570 int error;
571
572 error = namei(ndp);
573 if (error)
574 return (error);
575 vp = ndp->ni_vp;
576 if (vp->v_type != VDIR)
577 error = ENOTDIR;
578#ifdef MAC
579 else if ((error = mac_check_vnode_chdir(td->td_ucred, vp)) != 0) {
580 }
581#endif
582 else
583 error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td);
584 if (error)
585 vput(vp);
586 else
587 VOP_UNLOCK(vp, 0, td);
588 return (error);
589}
590
591/*
592 * Check permissions, allocate an open file structure,
593 * and call the device open routine if any.
594 */
595#ifndef _SYS_SYSPROTO_H_
596struct open_args {
597 char *path;
598 int flags;
599 int mode;
600};
601#endif
602int
603open(td, uap)
604 struct thread *td;
605 register struct open_args /* {
606 syscallarg(char *) path;
607 syscallarg(int) flags;
608 syscallarg(int) mode;
609 } */ *uap;
610{
611 struct proc *p = td->td_proc;
612 struct filedesc *fdp = p->p_fd;
613 struct file *fp;
614 struct vnode *vp;
615 struct vattr vat;
616 struct mount *mp;
617 int cmode, flags, oflags;
618 struct file *nfp;
619 int type, indx, error;
620 struct flock lf;
621 struct nameidata nd;
622
623 oflags = SCARG(uap, flags);
624 if ((oflags & O_ACCMODE) == O_ACCMODE)
625 return (EINVAL);
626 flags = FFLAGS(oflags);
627 error = falloc(td, &nfp, &indx);
628 if (error)
629 return (error);
630 fp = nfp;
631 FILEDESC_LOCK(fdp);
632 cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
633 FILEDESC_UNLOCK(fdp);
634 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
635 td->td_dupfd = -indx - 1; /* XXX check for fdopen */
636 /*
637 * Bump the ref count to prevent another process from closing
638 * the descriptor while we are blocked in vn_open()
639 */
640 fhold(fp);
641 error = vn_open(&nd, &flags, cmode);
642 if (error) {
643 /*
644 * release our own reference
645 */
646 fdrop(fp, td);
647
648 /*
649 * handle special fdopen() case. bleh. dupfdopen() is
650 * responsible for dropping the old contents of ofiles[indx]
651 * if it succeeds.
652 */
653 if ((error == ENODEV || error == ENXIO) &&
654 td->td_dupfd >= 0 && /* XXX from fdopen */
655 (error =
656 dupfdopen(td, fdp, indx, td->td_dupfd, flags, error)) == 0) {
657 td->td_retval[0] = indx;
658 return (0);
659 }
660 /*
661 * Clean up the descriptor, but only if another thread hadn't
662 * replaced or closed it.
663 */
664 FILEDESC_LOCK(fdp);
665 if (fdp->fd_ofiles[indx] == fp) {
666 fdp->fd_ofiles[indx] = NULL;
667 FILEDESC_UNLOCK(fdp);
668 fdrop(fp, td);
669 } else
670 FILEDESC_UNLOCK(fdp);
671
672 if (error == ERESTART)
673 error = EINTR;
674 return (error);
675 }
676 td->td_dupfd = 0;
677 NDFREE(&nd, NDF_ONLY_PNBUF);
678 vp = nd.ni_vp;
679
680 /*
681 * There should be 2 references on the file, one from the descriptor
682 * table, and one for us.
683 *
684 * Handle the case where someone closed the file (via its file
685 * descriptor) while we were blocked. The end result should look
686 * like opening the file succeeded but it was immediately closed.
687 */
688 FILEDESC_LOCK(fdp);
689 FILE_LOCK(fp);
690 if (fp->f_count == 1) {
691 KASSERT(fdp->fd_ofiles[indx] != fp,
692 ("Open file descriptor lost all refs"));
693 FILEDESC_UNLOCK(fdp);
694 FILE_UNLOCK(fp);
695 VOP_UNLOCK(vp, 0, td);
696 vn_close(vp, flags & FMASK, fp->f_cred, td);
697 fdrop(fp, td);
698 td->td_retval[0] = indx;
699 return 0;
700 }
701
702 /* assert that vn_open created a backing object if one is needed */
703 KASSERT(!vn_canvmio(vp) || VOP_GETVOBJECT(vp, NULL) == 0,
704 ("open: vmio vnode has no backing object after vn_open"));
705
706 fp->f_data = vp;
707 fp->f_flag = flags & FMASK;
708 fp->f_ops = &vnops;
709 fp->f_type = (vp->v_type == VFIFO ? DTYPE_FIFO : DTYPE_VNODE);
710 FILEDESC_UNLOCK(fdp);
711 FILE_UNLOCK(fp);
712 VOP_UNLOCK(vp, 0, td);
713 if (flags & (O_EXLOCK | O_SHLOCK)) {
714 lf.l_whence = SEEK_SET;
715 lf.l_start = 0;
716 lf.l_len = 0;
717 if (flags & O_EXLOCK)
718 lf.l_type = F_WRLCK;
719 else
720 lf.l_type = F_RDLCK;
721 type = F_FLOCK;
722 if ((flags & FNONBLOCK) == 0)
723 type |= F_WAIT;
724 if ((error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf,
725 type)) != 0)
726 goto bad;
727 fp->f_flag |= FHASLOCK;
728 }
729 if (flags & O_TRUNC) {
730 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
731 goto bad;
732 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
733 VATTR_NULL(&vat);
734 vat.va_size = 0;
735 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
736#ifdef MAC
40 */
41
42/* For 4.3 integer FS ID compatibility */
43#include "opt_compat.h"
44#include "opt_mac.h"
45
46#include <sys/param.h>
47#include <sys/systm.h>
48#include <sys/bio.h>
49#include <sys/buf.h>
50#include <sys/sysent.h>
51#include <sys/mac.h>
52#include <sys/malloc.h>
53#include <sys/mount.h>
54#include <sys/mutex.h>
55#include <sys/sysproto.h>
56#include <sys/namei.h>
57#include <sys/filedesc.h>
58#include <sys/kernel.h>
59#include <sys/fcntl.h>
60#include <sys/file.h>
61#include <sys/linker.h>
62#include <sys/stat.h>
63#include <sys/sx.h>
64#include <sys/unistd.h>
65#include <sys/vnode.h>
66#include <sys/proc.h>
67#include <sys/dirent.h>
68#include <sys/extattr.h>
69#include <sys/jail.h>
70#include <sys/sysctl.h>
71
72#include <machine/limits.h>
73#include <machine/stdarg.h>
74
75#include <vm/vm.h>
76#include <vm/vm_object.h>
77#include <vm/vm_page.h>
78#include <vm/uma.h>
79
80static int change_dir(struct nameidata *ndp, struct thread *td);
81static int chroot_refuse_vdir_fds(struct filedesc *fdp);
82static int getutimes(const struct timeval *, struct timespec *);
83static int setfown(struct thread *td, struct vnode *, uid_t, gid_t);
84static int setfmode(struct thread *td, struct vnode *, int);
85static int setfflags(struct thread *td, struct vnode *, int);
86static int setutimes(struct thread *td, struct vnode *,
87 const struct timespec *, int, int);
88static int vn_access(struct vnode *vp, int user_flags, struct ucred *cred,
89 struct thread *td);
90
91int (*union_dircheckp)(struct thread *td, struct vnode **, struct file *);
92int (*softdep_fsync_hook)(struct vnode *);
93
94/*
95 * Sync each mounted filesystem.
96 */
97#ifndef _SYS_SYSPROTO_H_
98struct sync_args {
99 int dummy;
100};
101#endif
102
103#ifdef DEBUG
104static int syncprt = 0;
105SYSCTL_INT(_debug, OID_AUTO, syncprt, CTLFLAG_RW, &syncprt, 0, "");
106#endif
107
108/* ARGSUSED */
109int
110sync(td, uap)
111 struct thread *td;
112 struct sync_args *uap;
113{
114 struct mount *mp, *nmp;
115 int asyncflag;
116
117 mtx_lock(&mountlist_mtx);
118 for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) {
119 if (vfs_busy(mp, LK_NOWAIT, &mountlist_mtx, td)) {
120 nmp = TAILQ_NEXT(mp, mnt_list);
121 continue;
122 }
123 if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
124 vn_start_write(NULL, &mp, V_NOWAIT) == 0) {
125 asyncflag = mp->mnt_flag & MNT_ASYNC;
126 mp->mnt_flag &= ~MNT_ASYNC;
127 vfs_msync(mp, MNT_NOWAIT);
128 VFS_SYNC(mp, MNT_NOWAIT,
129 ((td != NULL) ? td->td_ucred : NOCRED), td);
130 mp->mnt_flag |= asyncflag;
131 vn_finished_write(mp);
132 }
133 mtx_lock(&mountlist_mtx);
134 nmp = TAILQ_NEXT(mp, mnt_list);
135 vfs_unbusy(mp, td);
136 }
137 mtx_unlock(&mountlist_mtx);
138#if 0
139/*
140 * XXX don't call vfs_bufstats() yet because that routine
141 * was not imported in the Lite2 merge.
142 */
143#ifdef DIAGNOSTIC
144 if (syncprt)
145 vfs_bufstats();
146#endif /* DIAGNOSTIC */
147#endif
148 return (0);
149}
150
151/* XXX PRISON: could be per prison flag */
152static int prison_quotas;
153#if 0
154SYSCTL_INT(_kern_prison, OID_AUTO, quotas, CTLFLAG_RW, &prison_quotas, 0, "");
155#endif
156
157/*
158 * Change filesystem quotas.
159 */
160#ifndef _SYS_SYSPROTO_H_
161struct quotactl_args {
162 char *path;
163 int cmd;
164 int uid;
165 caddr_t arg;
166};
167#endif
168/* ARGSUSED */
169int
170quotactl(td, uap)
171 struct thread *td;
172 register struct quotactl_args /* {
173 syscallarg(char *) path;
174 syscallarg(int) cmd;
175 syscallarg(int) uid;
176 syscallarg(caddr_t) arg;
177 } */ *uap;
178{
179 struct mount *mp;
180 int error;
181 struct nameidata nd;
182
183 if (jailed(td->td_ucred) && !prison_quotas)
184 return (EPERM);
185 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
186 if ((error = namei(&nd)) != 0)
187 return (error);
188 NDFREE(&nd, NDF_ONLY_PNBUF);
189 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
190 vrele(nd.ni_vp);
191 if (error)
192 return (error);
193 error = VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
194 SCARG(uap, arg), td);
195 vn_finished_write(mp);
196 return (error);
197}
198
199/*
200 * Get filesystem statistics.
201 */
202#ifndef _SYS_SYSPROTO_H_
203struct statfs_args {
204 char *path;
205 struct statfs *buf;
206};
207#endif
208/* ARGSUSED */
209int
210statfs(td, uap)
211 struct thread *td;
212 register struct statfs_args /* {
213 syscallarg(char *) path;
214 syscallarg(struct statfs *) buf;
215 } */ *uap;
216{
217 register struct mount *mp;
218 register struct statfs *sp;
219 int error;
220 struct nameidata nd;
221 struct statfs sb;
222
223 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
224 if ((error = namei(&nd)) != 0)
225 return (error);
226 mp = nd.ni_vp->v_mount;
227 sp = &mp->mnt_stat;
228 NDFREE(&nd, NDF_ONLY_PNBUF);
229 vrele(nd.ni_vp);
230#ifdef MAC
231 error = mac_check_mount_stat(td->td_ucred, mp);
232 if (error)
233 return (error);
234#endif
235 error = VFS_STATFS(mp, sp, td);
236 if (error)
237 return (error);
238 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
239 if (suser(td)) {
240 bcopy(sp, &sb, sizeof(sb));
241 sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
242 sp = &sb;
243 }
244 return (copyout(sp, SCARG(uap, buf), sizeof(*sp)));
245}
246
247/*
248 * Get filesystem statistics.
249 */
250#ifndef _SYS_SYSPROTO_H_
251struct fstatfs_args {
252 int fd;
253 struct statfs *buf;
254};
255#endif
256/* ARGSUSED */
257int
258fstatfs(td, uap)
259 struct thread *td;
260 register struct fstatfs_args /* {
261 syscallarg(int) fd;
262 syscallarg(struct statfs *) buf;
263 } */ *uap;
264{
265 struct file *fp;
266 struct mount *mp;
267 register struct statfs *sp;
268 int error;
269 struct statfs sb;
270
271 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
272 return (error);
273 mp = ((struct vnode *)fp->f_data)->v_mount;
274 fdrop(fp, td);
275 if (mp == NULL)
276 return (EBADF);
277#ifdef MAC
278 error = mac_check_mount_stat(td->td_ucred, mp);
279 if (error)
280 return (error);
281#endif
282 sp = &mp->mnt_stat;
283 error = VFS_STATFS(mp, sp, td);
284 if (error)
285 return (error);
286 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
287 if (suser(td)) {
288 bcopy(sp, &sb, sizeof(sb));
289 sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
290 sp = &sb;
291 }
292 return (copyout(sp, SCARG(uap, buf), sizeof(*sp)));
293}
294
295/*
296 * Get statistics on all filesystems.
297 */
298#ifndef _SYS_SYSPROTO_H_
299struct getfsstat_args {
300 struct statfs *buf;
301 long bufsize;
302 int flags;
303};
304#endif
305int
306getfsstat(td, uap)
307 struct thread *td;
308 register struct getfsstat_args /* {
309 syscallarg(struct statfs *) buf;
310 syscallarg(long) bufsize;
311 syscallarg(int) flags;
312 } */ *uap;
313{
314 register struct mount *mp, *nmp;
315 register struct statfs *sp;
316 caddr_t sfsp;
317 long count, maxcount, error;
318
319 maxcount = SCARG(uap, bufsize) / sizeof(struct statfs);
320 sfsp = (caddr_t)SCARG(uap, buf);
321 count = 0;
322 mtx_lock(&mountlist_mtx);
323 for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) {
324#ifdef MAC
325 if (mac_check_mount_stat(td->td_ucred, mp) != 0) {
326 nmp = TAILQ_NEXT(mp, mnt_list);
327 continue;
328 }
329#endif
330 if (vfs_busy(mp, LK_NOWAIT, &mountlist_mtx, td)) {
331 nmp = TAILQ_NEXT(mp, mnt_list);
332 continue;
333 }
334 if (sfsp && count < maxcount) {
335 sp = &mp->mnt_stat;
336 /*
337 * If MNT_NOWAIT or MNT_LAZY is specified, do not
338 * refresh the fsstat cache. MNT_NOWAIT or MNT_LAZY
339 * overrides MNT_WAIT.
340 */
341 if (((SCARG(uap, flags) & (MNT_LAZY|MNT_NOWAIT)) == 0 ||
342 (SCARG(uap, flags) & MNT_WAIT)) &&
343 (error = VFS_STATFS(mp, sp, td))) {
344 mtx_lock(&mountlist_mtx);
345 nmp = TAILQ_NEXT(mp, mnt_list);
346 vfs_unbusy(mp, td);
347 continue;
348 }
349 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
350 error = copyout(sp, sfsp, sizeof(*sp));
351 if (error) {
352 vfs_unbusy(mp, td);
353 return (error);
354 }
355 sfsp += sizeof(*sp);
356 }
357 count++;
358 mtx_lock(&mountlist_mtx);
359 nmp = TAILQ_NEXT(mp, mnt_list);
360 vfs_unbusy(mp, td);
361 }
362 mtx_unlock(&mountlist_mtx);
363 if (sfsp && count > maxcount)
364 td->td_retval[0] = maxcount;
365 else
366 td->td_retval[0] = count;
367 return (0);
368}
369
370/*
371 * Change current working directory to a given file descriptor.
372 */
373#ifndef _SYS_SYSPROTO_H_
374struct fchdir_args {
375 int fd;
376};
377#endif
378/* ARGSUSED */
379int
380fchdir(td, uap)
381 struct thread *td;
382 struct fchdir_args /* {
383 syscallarg(int) fd;
384 } */ *uap;
385{
386 register struct filedesc *fdp = td->td_proc->p_fd;
387 struct vnode *vp, *tdp, *vpold;
388 struct mount *mp;
389 struct file *fp;
390 int error;
391
392 if ((error = getvnode(fdp, SCARG(uap, fd), &fp)) != 0)
393 return (error);
394 vp = (struct vnode *)fp->f_data;
395 VREF(vp);
396 fdrop(fp, td);
397 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
398 if (vp->v_type != VDIR)
399 error = ENOTDIR;
400#ifdef MAC
401 else if ((error = mac_check_vnode_chdir(td->td_ucred, vp)) != 0) {
402 }
403#endif
404 else
405 error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td);
406 while (!error && (mp = vp->v_mountedhere) != NULL) {
407 if (vfs_busy(mp, 0, 0, td))
408 continue;
409 error = VFS_ROOT(mp, &tdp);
410 vfs_unbusy(mp, td);
411 if (error)
412 break;
413 vput(vp);
414 vp = tdp;
415 }
416 if (error) {
417 vput(vp);
418 return (error);
419 }
420 VOP_UNLOCK(vp, 0, td);
421 FILEDESC_LOCK(fdp);
422 vpold = fdp->fd_cdir;
423 fdp->fd_cdir = vp;
424 FILEDESC_UNLOCK(fdp);
425 vrele(vpold);
426 return (0);
427}
428
429/*
430 * Change current working directory (``.'').
431 */
432#ifndef _SYS_SYSPROTO_H_
433struct chdir_args {
434 char *path;
435};
436#endif
437/* ARGSUSED */
438int
439chdir(td, uap)
440 struct thread *td;
441 struct chdir_args /* {
442 syscallarg(char *) path;
443 } */ *uap;
444{
445 register struct filedesc *fdp = td->td_proc->p_fd;
446 int error;
447 struct nameidata nd;
448 struct vnode *vp;
449
450 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
451 SCARG(uap, path), td);
452 if ((error = change_dir(&nd, td)) != 0)
453 return (error);
454 NDFREE(&nd, NDF_ONLY_PNBUF);
455 FILEDESC_LOCK(fdp);
456 vp = fdp->fd_cdir;
457 fdp->fd_cdir = nd.ni_vp;
458 FILEDESC_UNLOCK(fdp);
459 vrele(vp);
460 return (0);
461}
462
463/*
464 * Helper function for raised chroot(2) security function: Refuse if
465 * any filedescriptors are open directories.
466 */
467static int
468chroot_refuse_vdir_fds(fdp)
469 struct filedesc *fdp;
470{
471 struct vnode *vp;
472 struct file *fp;
473 int fd;
474
475 FILEDESC_LOCK_ASSERT(fdp, MA_OWNED);
476 for (fd = 0; fd < fdp->fd_nfiles ; fd++) {
477 fp = fget_locked(fdp, fd);
478 if (fp == NULL)
479 continue;
480 if (fp->f_type == DTYPE_VNODE) {
481 vp = (struct vnode *)fp->f_data;
482 if (vp->v_type == VDIR)
483 return (EPERM);
484 }
485 }
486 return (0);
487}
488
489/*
490 * This sysctl determines if we will allow a process to chroot(2) if it
491 * has a directory open:
492 * 0: disallowed for all processes.
493 * 1: allowed for processes that were not already chroot(2)'ed.
494 * 2: allowed for all processes.
495 */
496
497static int chroot_allow_open_directories = 1;
498
499SYSCTL_INT(_kern, OID_AUTO, chroot_allow_open_directories, CTLFLAG_RW,
500 &chroot_allow_open_directories, 0, "");
501
502/*
503 * Change notion of root (``/'') directory.
504 */
505#ifndef _SYS_SYSPROTO_H_
506struct chroot_args {
507 char *path;
508};
509#endif
510/* ARGSUSED */
511int
512chroot(td, uap)
513 struct thread *td;
514 struct chroot_args /* {
515 syscallarg(char *) path;
516 } */ *uap;
517{
518 register struct filedesc *fdp = td->td_proc->p_fd;
519 int error;
520 struct nameidata nd;
521 struct vnode *vp;
522
523 error = suser_cred(td->td_ucred, PRISON_ROOT);
524 if (error)
525 return (error);
526 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
527 SCARG(uap, path), td);
528 mtx_lock(&Giant);
529 if ((error = change_dir(&nd, td)) != 0)
530 goto error;
531#ifdef MAC
532 if ((error = mac_check_vnode_chroot(td->td_ucred, nd.ni_vp)))
533 goto error;
534#endif
535 FILEDESC_LOCK(fdp);
536 if (chroot_allow_open_directories == 0 ||
537 (chroot_allow_open_directories == 1 && fdp->fd_rdir != rootvnode)) {
538 error = chroot_refuse_vdir_fds(fdp);
539 if (error)
540 goto error_unlock;
541 }
542 vp = fdp->fd_rdir;
543 fdp->fd_rdir = nd.ni_vp;
544 if (!fdp->fd_jdir) {
545 fdp->fd_jdir = nd.ni_vp;
546 VREF(fdp->fd_jdir);
547 }
548 FILEDESC_UNLOCK(fdp);
549 NDFREE(&nd, NDF_ONLY_PNBUF);
550 vrele(vp);
551 mtx_unlock(&Giant);
552 return (0);
553error_unlock:
554 FILEDESC_UNLOCK(fdp);
555error:
556 mtx_unlock(&Giant);
557 NDFREE(&nd, 0);
558 return (error);
559}
560
561/*
562 * Common routine for chroot and chdir.
563 */
564static int
565change_dir(ndp, td)
566 register struct nameidata *ndp;
567 struct thread *td;
568{
569 struct vnode *vp;
570 int error;
571
572 error = namei(ndp);
573 if (error)
574 return (error);
575 vp = ndp->ni_vp;
576 if (vp->v_type != VDIR)
577 error = ENOTDIR;
578#ifdef MAC
579 else if ((error = mac_check_vnode_chdir(td->td_ucred, vp)) != 0) {
580 }
581#endif
582 else
583 error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td);
584 if (error)
585 vput(vp);
586 else
587 VOP_UNLOCK(vp, 0, td);
588 return (error);
589}
590
591/*
592 * Check permissions, allocate an open file structure,
593 * and call the device open routine if any.
594 */
595#ifndef _SYS_SYSPROTO_H_
596struct open_args {
597 char *path;
598 int flags;
599 int mode;
600};
601#endif
602int
603open(td, uap)
604 struct thread *td;
605 register struct open_args /* {
606 syscallarg(char *) path;
607 syscallarg(int) flags;
608 syscallarg(int) mode;
609 } */ *uap;
610{
611 struct proc *p = td->td_proc;
612 struct filedesc *fdp = p->p_fd;
613 struct file *fp;
614 struct vnode *vp;
615 struct vattr vat;
616 struct mount *mp;
617 int cmode, flags, oflags;
618 struct file *nfp;
619 int type, indx, error;
620 struct flock lf;
621 struct nameidata nd;
622
623 oflags = SCARG(uap, flags);
624 if ((oflags & O_ACCMODE) == O_ACCMODE)
625 return (EINVAL);
626 flags = FFLAGS(oflags);
627 error = falloc(td, &nfp, &indx);
628 if (error)
629 return (error);
630 fp = nfp;
631 FILEDESC_LOCK(fdp);
632 cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
633 FILEDESC_UNLOCK(fdp);
634 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
635 td->td_dupfd = -indx - 1; /* XXX check for fdopen */
636 /*
637 * Bump the ref count to prevent another process from closing
638 * the descriptor while we are blocked in vn_open()
639 */
640 fhold(fp);
641 error = vn_open(&nd, &flags, cmode);
642 if (error) {
643 /*
644 * release our own reference
645 */
646 fdrop(fp, td);
647
648 /*
649 * handle special fdopen() case. bleh. dupfdopen() is
650 * responsible for dropping the old contents of ofiles[indx]
651 * if it succeeds.
652 */
653 if ((error == ENODEV || error == ENXIO) &&
654 td->td_dupfd >= 0 && /* XXX from fdopen */
655 (error =
656 dupfdopen(td, fdp, indx, td->td_dupfd, flags, error)) == 0) {
657 td->td_retval[0] = indx;
658 return (0);
659 }
660 /*
661 * Clean up the descriptor, but only if another thread hadn't
662 * replaced or closed it.
663 */
664 FILEDESC_LOCK(fdp);
665 if (fdp->fd_ofiles[indx] == fp) {
666 fdp->fd_ofiles[indx] = NULL;
667 FILEDESC_UNLOCK(fdp);
668 fdrop(fp, td);
669 } else
670 FILEDESC_UNLOCK(fdp);
671
672 if (error == ERESTART)
673 error = EINTR;
674 return (error);
675 }
676 td->td_dupfd = 0;
677 NDFREE(&nd, NDF_ONLY_PNBUF);
678 vp = nd.ni_vp;
679
680 /*
681 * There should be 2 references on the file, one from the descriptor
682 * table, and one for us.
683 *
684 * Handle the case where someone closed the file (via its file
685 * descriptor) while we were blocked. The end result should look
686 * like opening the file succeeded but it was immediately closed.
687 */
688 FILEDESC_LOCK(fdp);
689 FILE_LOCK(fp);
690 if (fp->f_count == 1) {
691 KASSERT(fdp->fd_ofiles[indx] != fp,
692 ("Open file descriptor lost all refs"));
693 FILEDESC_UNLOCK(fdp);
694 FILE_UNLOCK(fp);
695 VOP_UNLOCK(vp, 0, td);
696 vn_close(vp, flags & FMASK, fp->f_cred, td);
697 fdrop(fp, td);
698 td->td_retval[0] = indx;
699 return 0;
700 }
701
702 /* assert that vn_open created a backing object if one is needed */
703 KASSERT(!vn_canvmio(vp) || VOP_GETVOBJECT(vp, NULL) == 0,
704 ("open: vmio vnode has no backing object after vn_open"));
705
706 fp->f_data = vp;
707 fp->f_flag = flags & FMASK;
708 fp->f_ops = &vnops;
709 fp->f_type = (vp->v_type == VFIFO ? DTYPE_FIFO : DTYPE_VNODE);
710 FILEDESC_UNLOCK(fdp);
711 FILE_UNLOCK(fp);
712 VOP_UNLOCK(vp, 0, td);
713 if (flags & (O_EXLOCK | O_SHLOCK)) {
714 lf.l_whence = SEEK_SET;
715 lf.l_start = 0;
716 lf.l_len = 0;
717 if (flags & O_EXLOCK)
718 lf.l_type = F_WRLCK;
719 else
720 lf.l_type = F_RDLCK;
721 type = F_FLOCK;
722 if ((flags & FNONBLOCK) == 0)
723 type |= F_WAIT;
724 if ((error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf,
725 type)) != 0)
726 goto bad;
727 fp->f_flag |= FHASLOCK;
728 }
729 if (flags & O_TRUNC) {
730 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
731 goto bad;
732 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
733 VATTR_NULL(&vat);
734 vat.va_size = 0;
735 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
736#ifdef MAC
737 error = mac_check_vnode_op(td->td_ucred, vp,
738 MAC_OP_VNODE_WRITE);
737 error = mac_check_vnode_write(td->td_ucred, vp);
739 if (error == 0)
740#endif
741 error = VOP_SETATTR(vp, &vat, td->td_ucred, td);
742 VOP_UNLOCK(vp, 0, td);
743 vn_finished_write(mp);
744 if (error)
745 goto bad;
746 }
747 /*
748 * Release our private reference, leaving the one associated with
749 * the descriptor table intact.
750 */
751 fdrop(fp, td);
752 td->td_retval[0] = indx;
753 return (0);
754bad:
755 FILEDESC_LOCK(fdp);
756 if (fdp->fd_ofiles[indx] == fp) {
757 fdp->fd_ofiles[indx] = NULL;
758 FILEDESC_UNLOCK(fdp);
759 fdrop(fp, td);
760 } else
761 FILEDESC_UNLOCK(fdp);
762 return (error);
763}
764
765#ifdef COMPAT_43
766/*
767 * Create a file.
768 */
769#ifndef _SYS_SYSPROTO_H_
770struct ocreat_args {
771 char *path;
772 int mode;
773};
774#endif
775int
776ocreat(td, uap)
777 struct thread *td;
778 register struct ocreat_args /* {
779 syscallarg(char *) path;
780 syscallarg(int) mode;
781 } */ *uap;
782{
783 struct open_args /* {
784 syscallarg(char *) path;
785 syscallarg(int) flags;
786 syscallarg(int) mode;
787 } */ nuap;
788
789 SCARG(&nuap, path) = SCARG(uap, path);
790 SCARG(&nuap, mode) = SCARG(uap, mode);
791 SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC;
792 return (open(td, &nuap));
793}
794#endif /* COMPAT_43 */
795
796/*
797 * Create a special file.
798 */
799#ifndef _SYS_SYSPROTO_H_
800struct mknod_args {
801 char *path;
802 int mode;
803 int dev;
804};
805#endif
806/* ARGSUSED */
807int
808mknod(td, uap)
809 struct thread *td;
810 register struct mknod_args /* {
811 syscallarg(char *) path;
812 syscallarg(int) mode;
813 syscallarg(int) dev;
814 } */ *uap;
815{
816 struct vnode *vp;
817 struct mount *mp;
818 struct vattr vattr;
819 int error;
820 int whiteout = 0;
821 struct nameidata nd;
822
823 switch (SCARG(uap, mode) & S_IFMT) {
824 case S_IFCHR:
825 case S_IFBLK:
826 error = suser(td);
827 break;
828 default:
829 error = suser_cred(td->td_ucred, PRISON_ROOT);
830 break;
831 }
832 if (error)
833 return (error);
834restart:
835 bwillwrite();
836 NDINIT(&nd, CREATE, LOCKPARENT | SAVENAME, UIO_USERSPACE,
837 SCARG(uap, path), td);
838 if ((error = namei(&nd)) != 0)
839 return (error);
840 vp = nd.ni_vp;
841 if (vp != NULL) {
842 vrele(vp);
843 error = EEXIST;
844 } else {
845 VATTR_NULL(&vattr);
846 FILEDESC_LOCK(td->td_proc->p_fd);
847 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ td->td_proc->p_fd->fd_cmask;
848 FILEDESC_UNLOCK(td->td_proc->p_fd);
849 vattr.va_rdev = SCARG(uap, dev);
850 whiteout = 0;
851
852 switch (SCARG(uap, mode) & S_IFMT) {
853 case S_IFMT: /* used by badsect to flag bad sectors */
854 vattr.va_type = VBAD;
855 break;
856 case S_IFCHR:
857 vattr.va_type = VCHR;
858 break;
859 case S_IFBLK:
860 vattr.va_type = VBLK;
861 break;
862 case S_IFWHT:
863 whiteout = 1;
864 break;
865 default:
866 error = EINVAL;
867 break;
868 }
869 }
870 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
871 NDFREE(&nd, NDF_ONLY_PNBUF);
872 vput(nd.ni_dvp);
873 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
874 return (error);
875 goto restart;
876 }
877 if (!error) {
878 VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
879 if (whiteout)
880 error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
881 else {
882 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp,
883 &nd.ni_cnd, &vattr);
884 if (error == 0)
885 vput(nd.ni_vp);
886 }
887 }
888 NDFREE(&nd, NDF_ONLY_PNBUF);
889 vput(nd.ni_dvp);
890 vn_finished_write(mp);
891 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mknod");
892 ASSERT_VOP_UNLOCKED(nd.ni_vp, "mknod");
893 return (error);
894}
895
896/*
897 * Create a named pipe.
898 */
899#ifndef _SYS_SYSPROTO_H_
900struct mkfifo_args {
901 char *path;
902 int mode;
903};
904#endif
905/* ARGSUSED */
906int
907mkfifo(td, uap)
908 struct thread *td;
909 register struct mkfifo_args /* {
910 syscallarg(char *) path;
911 syscallarg(int) mode;
912 } */ *uap;
913{
914 struct mount *mp;
915 struct vattr vattr;
916 int error;
917 struct nameidata nd;
918
919restart:
920 bwillwrite();
921 NDINIT(&nd, CREATE, LOCKPARENT | SAVENAME, UIO_USERSPACE,
922 SCARG(uap, path), td);
923 if ((error = namei(&nd)) != 0)
924 return (error);
925 if (nd.ni_vp != NULL) {
926 NDFREE(&nd, NDF_ONLY_PNBUF);
927 vrele(nd.ni_vp);
928 vput(nd.ni_dvp);
929 return (EEXIST);
930 }
931 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
932 NDFREE(&nd, NDF_ONLY_PNBUF);
933 vput(nd.ni_dvp);
934 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
935 return (error);
936 goto restart;
937 }
938 VATTR_NULL(&vattr);
939 vattr.va_type = VFIFO;
940 FILEDESC_LOCK(td->td_proc->p_fd);
941 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ td->td_proc->p_fd->fd_cmask;
942 FILEDESC_UNLOCK(td->td_proc->p_fd);
943 VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
944 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
945 if (error == 0)
946 vput(nd.ni_vp);
947 NDFREE(&nd, NDF_ONLY_PNBUF);
948 vput(nd.ni_dvp);
949 vn_finished_write(mp);
950 return (error);
951}
952
953/*
954 * Make a hard file link.
955 */
956#ifndef _SYS_SYSPROTO_H_
957struct link_args {
958 char *path;
959 char *link;
960};
961#endif
962/* ARGSUSED */
963int
964link(td, uap)
965 struct thread *td;
966 register struct link_args /* {
967 syscallarg(char *) path;
968 syscallarg(char *) link;
969 } */ *uap;
970{
971 struct vnode *vp;
972 struct mount *mp;
973 struct nameidata nd;
974 int error;
975
976 bwillwrite();
977 NDINIT(&nd, LOOKUP, FOLLOW|NOOBJ, UIO_USERSPACE, SCARG(uap, path), td);
978 if ((error = namei(&nd)) != 0)
979 return (error);
980 NDFREE(&nd, NDF_ONLY_PNBUF);
981 vp = nd.ni_vp;
982 if (vp->v_type == VDIR) {
983 vrele(vp);
984 return (EPERM); /* POSIX */
985 }
986 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) {
987 vrele(vp);
988 return (error);
989 }
990 NDINIT(&nd, CREATE, LOCKPARENT | NOOBJ | SAVENAME, UIO_USERSPACE,
991 SCARG(uap, link), td);
992 if ((error = namei(&nd)) == 0) {
993 if (nd.ni_vp != NULL) {
994 vrele(nd.ni_vp);
995 error = EEXIST;
996 } else {
997 VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
998 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
999 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
1000 }
1001 NDFREE(&nd, NDF_ONLY_PNBUF);
1002 vput(nd.ni_dvp);
1003 }
1004 vrele(vp);
1005 vn_finished_write(mp);
1006 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "link");
1007 ASSERT_VOP_UNLOCKED(nd.ni_vp, "link");
1008 return (error);
1009}
1010
1011/*
1012 * Make a symbolic link.
1013 */
1014#ifndef _SYS_SYSPROTO_H_
1015struct symlink_args {
1016 char *path;
1017 char *link;
1018};
1019#endif
1020/* ARGSUSED */
1021int
1022symlink(td, uap)
1023 struct thread *td;
1024 register struct symlink_args /* {
1025 syscallarg(char *) path;
1026 syscallarg(char *) link;
1027 } */ *uap;
1028{
1029 struct mount *mp;
1030 struct vattr vattr;
1031 char *path;
1032 int error;
1033 struct nameidata nd;
1034
1035 path = uma_zalloc(namei_zone, M_WAITOK);
1036 if ((error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL)) != 0)
1037 goto out;
1038restart:
1039 bwillwrite();
1040 NDINIT(&nd, CREATE, LOCKPARENT | NOOBJ | SAVENAME, UIO_USERSPACE,
1041 SCARG(uap, link), td);
1042 if ((error = namei(&nd)) != 0)
1043 goto out;
1044 if (nd.ni_vp) {
1045 NDFREE(&nd, NDF_ONLY_PNBUF);
1046 vrele(nd.ni_vp);
1047 vput(nd.ni_dvp);
1048 error = EEXIST;
1049 goto out;
1050 }
1051 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1052 NDFREE(&nd, NDF_ONLY_PNBUF);
1053 vput(nd.ni_dvp);
1054 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
1055 return (error);
1056 goto restart;
1057 }
1058 VATTR_NULL(&vattr);
1059 FILEDESC_LOCK(td->td_proc->p_fd);
1060 vattr.va_mode = ACCESSPERMS &~ td->td_proc->p_fd->fd_cmask;
1061 FILEDESC_UNLOCK(td->td_proc->p_fd);
1062 VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
1063 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
1064 NDFREE(&nd, NDF_ONLY_PNBUF);
1065 if (error == 0)
1066 vput(nd.ni_vp);
1067 vput(nd.ni_dvp);
1068 vn_finished_write(mp);
1069 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "symlink");
1070 ASSERT_VOP_UNLOCKED(nd.ni_vp, "symlink");
1071out:
1072 uma_zfree(namei_zone, path);
1073 return (error);
1074}
1075
1076/*
1077 * Delete a whiteout from the filesystem.
1078 */
1079/* ARGSUSED */
1080int
1081undelete(td, uap)
1082 struct thread *td;
1083 register struct undelete_args /* {
1084 syscallarg(char *) path;
1085 } */ *uap;
1086{
1087 int error;
1088 struct mount *mp;
1089 struct nameidata nd;
1090
1091restart:
1092 bwillwrite();
1093 NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE,
1094 SCARG(uap, path), td);
1095 error = namei(&nd);
1096 if (error)
1097 return (error);
1098
1099 if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
1100 NDFREE(&nd, NDF_ONLY_PNBUF);
1101 if (nd.ni_vp)
1102 vrele(nd.ni_vp);
1103 vput(nd.ni_dvp);
1104 return (EEXIST);
1105 }
1106 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1107 NDFREE(&nd, NDF_ONLY_PNBUF);
1108 vput(nd.ni_dvp);
1109 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
1110 return (error);
1111 goto restart;
1112 }
1113 VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
1114 error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE);
1115 NDFREE(&nd, NDF_ONLY_PNBUF);
1116 vput(nd.ni_dvp);
1117 vn_finished_write(mp);
1118 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "undelete");
1119 ASSERT_VOP_UNLOCKED(nd.ni_vp, "undelete");
1120 return (error);
1121}
1122
1123/*
1124 * Delete a name from the filesystem.
1125 */
1126#ifndef _SYS_SYSPROTO_H_
1127struct unlink_args {
1128 char *path;
1129};
1130#endif
1131/* ARGSUSED */
1132int
1133unlink(td, uap)
1134 struct thread *td;
1135 struct unlink_args /* {
1136 syscallarg(char *) path;
1137 } */ *uap;
1138{
1139 struct mount *mp;
1140 struct vnode *vp;
1141 int error;
1142 struct nameidata nd;
1143
1144restart:
1145 bwillwrite();
1146 NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), td);
1147 if ((error = namei(&nd)) != 0)
1148 return (error);
1149 vp = nd.ni_vp;
1150 if (vp->v_type == VDIR)
1151 error = EPERM; /* POSIX */
1152 else {
1153 /*
1154 * The root of a mounted filesystem cannot be deleted.
1155 *
1156 * XXX: can this only be a VDIR case?
1157 */
1158 mp_fixme("Accessing vflags w/o the vn lock.");
1159 if (vp->v_vflag & VV_ROOT)
1160 error = EBUSY;
1161 }
1162 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1163 NDFREE(&nd, NDF_ONLY_PNBUF);
1164 vrele(vp);
1165 vput(nd.ni_dvp);
1166 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
1167 return (error);
1168 goto restart;
1169 }
1170 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
1171 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
1172 if (!error) {
1173 VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
1174 error = VOP_REMOVE(nd.ni_dvp, vp, &nd.ni_cnd);
1175 }
1176 NDFREE(&nd, NDF_ONLY_PNBUF);
1177 vput(nd.ni_dvp);
1178 vput(vp);
1179 vn_finished_write(mp);
1180 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "unlink");
1181 ASSERT_VOP_UNLOCKED(nd.ni_vp, "unlink");
1182 return (error);
1183}
1184
1185/*
1186 * Reposition read/write file offset.
1187 */
1188#ifndef _SYS_SYSPROTO_H_
1189struct lseek_args {
1190 int fd;
1191 int pad;
1192 off_t offset;
1193 int whence;
1194};
1195#endif
1196int
1197lseek(td, uap)
1198 struct thread *td;
1199 register struct lseek_args /* {
1200 syscallarg(int) fd;
1201 syscallarg(int) pad;
1202 syscallarg(off_t) offset;
1203 syscallarg(int) whence;
1204 } */ *uap;
1205{
1206 struct ucred *cred = td->td_ucred;
1207 struct file *fp;
1208 struct vnode *vp;
1209 struct vattr vattr;
1210 off_t offset;
1211 int error, noneg;
1212
1213 if ((error = fget(td, uap->fd, &fp)) != 0)
1214 return (error);
1215 if (fp->f_type != DTYPE_VNODE) {
1216 fdrop(fp, td);
1217 return (ESPIPE);
1218 }
1219 vp = (struct vnode *)fp->f_data;
1220 noneg = (vp->v_type != VCHR);
1221 offset = SCARG(uap, offset);
1222 switch (SCARG(uap, whence)) {
1223 case L_INCR:
1224 if (noneg &&
1225 (fp->f_offset < 0 ||
1226 (offset > 0 && fp->f_offset > OFF_MAX - offset)))
1227 return (EOVERFLOW);
1228 offset += fp->f_offset;
1229 break;
1230 case L_XTND:
1231 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
1232 error = VOP_GETATTR(vp, &vattr, cred, td);
1233 VOP_UNLOCK(vp, 0, td);
1234 if (error)
1235 return (error);
1236 if (noneg &&
1237 (vattr.va_size > OFF_MAX ||
1238 (offset > 0 && vattr.va_size > OFF_MAX - offset)))
1239 return (EOVERFLOW);
1240 offset += vattr.va_size;
1241 break;
1242 case L_SET:
1243 break;
1244 default:
1245 fdrop(fp, td);
1246 return (EINVAL);
1247 }
1248 if (noneg && offset < 0)
1249 return (EINVAL);
1250 fp->f_offset = offset;
1251 *(off_t *)(td->td_retval) = fp->f_offset;
1252 fdrop(fp, td);
1253 return (0);
1254}
1255
1256#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1257/*
1258 * Reposition read/write file offset.
1259 */
1260#ifndef _SYS_SYSPROTO_H_
1261struct olseek_args {
1262 int fd;
1263 long offset;
1264 int whence;
1265};
1266#endif
1267int
1268olseek(td, uap)
1269 struct thread *td;
1270 register struct olseek_args /* {
1271 syscallarg(int) fd;
1272 syscallarg(long) offset;
1273 syscallarg(int) whence;
1274 } */ *uap;
1275{
1276 struct lseek_args /* {
1277 syscallarg(int) fd;
1278 syscallarg(int) pad;
1279 syscallarg(off_t) offset;
1280 syscallarg(int) whence;
1281 } */ nuap;
1282 int error;
1283
1284 SCARG(&nuap, fd) = SCARG(uap, fd);
1285 SCARG(&nuap, offset) = SCARG(uap, offset);
1286 SCARG(&nuap, whence) = SCARG(uap, whence);
1287 error = lseek(td, &nuap);
1288 return (error);
1289}
1290#endif /* COMPAT_43 */
1291
1292/*
1293 * Check access permissions using passed credentials.
1294 */
1295static int
1296vn_access(vp, user_flags, cred, td)
1297 struct vnode *vp;
1298 int user_flags;
1299 struct ucred *cred;
1300 struct thread *td;
1301{
1302 int error, flags;
1303
1304 /* Flags == 0 means only check for existence. */
1305 error = 0;
1306 if (user_flags) {
1307 flags = 0;
1308 if (user_flags & R_OK)
1309 flags |= VREAD;
1310 if (user_flags & W_OK)
1311 flags |= VWRITE;
1312 if (user_flags & X_OK)
1313 flags |= VEXEC;
1314#ifdef MAC
1315 error = mac_check_vnode_access(cred, vp, flags);
1316 if (error)
1317 return (error);
1318#endif
1319 if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
1320 error = VOP_ACCESS(vp, flags, cred, td);
1321 }
1322 return (error);
1323}
1324
1325/*
1326 * Check access permissions using "real" credentials.
1327 */
1328#ifndef _SYS_SYSPROTO_H_
1329struct access_args {
1330 char *path;
1331 int flags;
1332};
1333#endif
1334int
1335access(td, uap)
1336 struct thread *td;
1337 register struct access_args /* {
1338 syscallarg(char *) path;
1339 syscallarg(int) flags;
1340 } */ *uap;
1341{
1342 struct ucred *cred, *tmpcred;
1343 register struct vnode *vp;
1344 int error;
1345 struct nameidata nd;
1346
1347 /*
1348 * Create and modify a temporary credential instead of one that
1349 * is potentially shared. This could also mess up socket
1350 * buffer accounting which can run in an interrupt context.
1351 *
1352 * XXX - Depending on how "threads" are finally implemented, it
1353 * may be better to explicitly pass the credential to namei()
1354 * rather than to modify the potentially shared process structure.
1355 */
1356 cred = td->td_ucred;
1357 tmpcred = crdup(cred);
1358 tmpcred->cr_uid = cred->cr_ruid;
1359 tmpcred->cr_groups[0] = cred->cr_rgid;
1360 td->td_ucred = tmpcred;
1361 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1362 SCARG(uap, path), td);
1363 if ((error = namei(&nd)) != 0)
1364 goto out1;
1365 vp = nd.ni_vp;
1366
1367 error = vn_access(vp, SCARG(uap, flags), tmpcred, td);
1368 NDFREE(&nd, NDF_ONLY_PNBUF);
1369 vput(vp);
1370out1:
1371 td->td_ucred = cred;
1372 crfree(tmpcred);
1373 return (error);
1374}
1375
1376/*
1377 * Check access permissions using "effective" credentials.
1378 */
1379#ifndef _SYS_SYSPROTO_H_
1380struct eaccess_args {
1381 char *path;
1382 int flags;
1383};
1384#endif
1385int
1386eaccess(td, uap)
1387 struct thread *td;
1388 register struct eaccess_args /* {
1389 syscallarg(char *) path;
1390 syscallarg(int) flags;
1391 } */ *uap;
1392{
1393 struct nameidata nd;
1394 struct vnode *vp;
1395 int error;
1396
1397 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1398 SCARG(uap, path), td);
1399 if ((error = namei(&nd)) != 0)
1400 return (error);
1401 vp = nd.ni_vp;
1402
1403 error = vn_access(vp, SCARG(uap, flags), td->td_ucred, td);
1404 NDFREE(&nd, NDF_ONLY_PNBUF);
1405 vput(vp);
1406 return (error);
1407}
1408
1409#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1410/*
1411 * Get file status; this version follows links.
1412 */
1413#ifndef _SYS_SYSPROTO_H_
1414struct ostat_args {
1415 char *path;
1416 struct ostat *ub;
1417};
1418#endif
1419/* ARGSUSED */
1420int
1421ostat(td, uap)
1422 struct thread *td;
1423 register struct ostat_args /* {
1424 syscallarg(char *) path;
1425 syscallarg(struct ostat *) ub;
1426 } */ *uap;
1427{
1428 struct stat sb;
1429 struct ostat osb;
1430 int error;
1431 struct nameidata nd;
1432
1433 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1434 SCARG(uap, path), td);
1435 if ((error = namei(&nd)) != 0)
1436 return (error);
1437 NDFREE(&nd, NDF_ONLY_PNBUF);
1438 error = vn_stat(nd.ni_vp, &sb, td->td_ucred, NOCRED, td);
1439 vput(nd.ni_vp);
1440 if (error)
1441 return (error);
1442 cvtstat(&sb, &osb);
1443 error = copyout(&osb, SCARG(uap, ub), sizeof (osb));
1444 return (error);
1445}
1446
1447/*
1448 * Get file status; this version does not follow links.
1449 */
1450#ifndef _SYS_SYSPROTO_H_
1451struct olstat_args {
1452 char *path;
1453 struct ostat *ub;
1454};
1455#endif
1456/* ARGSUSED */
1457int
1458olstat(td, uap)
1459 struct thread *td;
1460 register struct olstat_args /* {
1461 syscallarg(char *) path;
1462 syscallarg(struct ostat *) ub;
1463 } */ *uap;
1464{
1465 struct vnode *vp;
1466 struct stat sb;
1467 struct ostat osb;
1468 int error;
1469 struct nameidata nd;
1470
1471 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1472 SCARG(uap, path), td);
1473 if ((error = namei(&nd)) != 0)
1474 return (error);
1475 vp = nd.ni_vp;
1476 error = vn_stat(vp, &sb, td->td_ucred, NOCRED, td);
1477 NDFREE(&nd, NDF_ONLY_PNBUF);
1478 vput(vp);
1479 if (error)
1480 return (error);
1481 cvtstat(&sb, &osb);
1482 error = copyout(&osb, SCARG(uap, ub), sizeof (osb));
1483 return (error);
1484}
1485
1486/*
1487 * Convert from an old to a new stat structure.
1488 */
1489void
1490cvtstat(st, ost)
1491 struct stat *st;
1492 struct ostat *ost;
1493{
1494
1495 ost->st_dev = st->st_dev;
1496 ost->st_ino = st->st_ino;
1497 ost->st_mode = st->st_mode;
1498 ost->st_nlink = st->st_nlink;
1499 ost->st_uid = st->st_uid;
1500 ost->st_gid = st->st_gid;
1501 ost->st_rdev = st->st_rdev;
1502 if (st->st_size < (quad_t)1 << 32)
1503 ost->st_size = st->st_size;
1504 else
1505 ost->st_size = -2;
1506 ost->st_atime = st->st_atime;
1507 ost->st_mtime = st->st_mtime;
1508 ost->st_ctime = st->st_ctime;
1509 ost->st_blksize = st->st_blksize;
1510 ost->st_blocks = st->st_blocks;
1511 ost->st_flags = st->st_flags;
1512 ost->st_gen = st->st_gen;
1513}
1514#endif /* COMPAT_43 || COMPAT_SUNOS */
1515
1516/*
1517 * Get file status; this version follows links.
1518 */
1519#ifndef _SYS_SYSPROTO_H_
1520struct stat_args {
1521 char *path;
1522 struct stat *ub;
1523};
1524#endif
1525/* ARGSUSED */
1526int
1527stat(td, uap)
1528 struct thread *td;
1529 register struct stat_args /* {
1530 syscallarg(char *) path;
1531 syscallarg(struct stat *) ub;
1532 } */ *uap;
1533{
1534 struct stat sb;
1535 int error;
1536 struct nameidata nd;
1537
1538#ifdef LOOKUP_SHARED
1539 NDINIT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | NOOBJ,
1540 UIO_USERSPACE, SCARG(uap, path), td);
1541#else
1542 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1543 SCARG(uap, path), td);
1544#endif
1545 if ((error = namei(&nd)) != 0)
1546 return (error);
1547 error = vn_stat(nd.ni_vp, &sb, td->td_ucred, NOCRED, td);
1548 NDFREE(&nd, NDF_ONLY_PNBUF);
1549 vput(nd.ni_vp);
1550 if (error)
1551 return (error);
1552 error = copyout(&sb, SCARG(uap, ub), sizeof (sb));
1553 return (error);
1554}
1555
1556/*
1557 * Get file status; this version does not follow links.
1558 */
1559#ifndef _SYS_SYSPROTO_H_
1560struct lstat_args {
1561 char *path;
1562 struct stat *ub;
1563};
1564#endif
1565/* ARGSUSED */
1566int
1567lstat(td, uap)
1568 struct thread *td;
1569 register struct lstat_args /* {
1570 syscallarg(char *) path;
1571 syscallarg(struct stat *) ub;
1572 } */ *uap;
1573{
1574 int error;
1575 struct vnode *vp;
1576 struct stat sb;
1577 struct nameidata nd;
1578
1579 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1580 SCARG(uap, path), td);
1581 if ((error = namei(&nd)) != 0)
1582 return (error);
1583 vp = nd.ni_vp;
1584 error = vn_stat(vp, &sb, td->td_ucred, NOCRED, td);
1585 NDFREE(&nd, NDF_ONLY_PNBUF);
1586 vput(vp);
1587 if (error)
1588 return (error);
1589 error = copyout(&sb, SCARG(uap, ub), sizeof (sb));
1590 return (error);
1591}
1592
1593/*
1594 * Implementation of the NetBSD stat() function.
1595 * XXX This should probably be collapsed with the FreeBSD version,
1596 * as the differences are only due to vn_stat() clearing spares at
1597 * the end of the structures. vn_stat could be split to avoid this,
1598 * and thus collapse the following to close to zero code.
1599 */
1600void
1601cvtnstat(sb, nsb)
1602 struct stat *sb;
1603 struct nstat *nsb;
1604{
1605 bzero(nsb, sizeof *nsb);
1606 nsb->st_dev = sb->st_dev;
1607 nsb->st_ino = sb->st_ino;
1608 nsb->st_mode = sb->st_mode;
1609 nsb->st_nlink = sb->st_nlink;
1610 nsb->st_uid = sb->st_uid;
1611 nsb->st_gid = sb->st_gid;
1612 nsb->st_rdev = sb->st_rdev;
1613 nsb->st_atimespec = sb->st_atimespec;
1614 nsb->st_mtimespec = sb->st_mtimespec;
1615 nsb->st_ctimespec = sb->st_ctimespec;
1616 nsb->st_size = sb->st_size;
1617 nsb->st_blocks = sb->st_blocks;
1618 nsb->st_blksize = sb->st_blksize;
1619 nsb->st_flags = sb->st_flags;
1620 nsb->st_gen = sb->st_gen;
1621 nsb->st_birthtimespec = sb->st_birthtimespec;
1622}
1623
1624#ifndef _SYS_SYSPROTO_H_
1625struct nstat_args {
1626 char *path;
1627 struct nstat *ub;
1628};
1629#endif
1630/* ARGSUSED */
1631int
1632nstat(td, uap)
1633 struct thread *td;
1634 register struct nstat_args /* {
1635 syscallarg(char *) path;
1636 syscallarg(struct nstat *) ub;
1637 } */ *uap;
1638{
1639 struct stat sb;
1640 struct nstat nsb;
1641 int error;
1642 struct nameidata nd;
1643
1644 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1645 SCARG(uap, path), td);
1646 if ((error = namei(&nd)) != 0)
1647 return (error);
1648 NDFREE(&nd, NDF_ONLY_PNBUF);
1649 error = vn_stat(nd.ni_vp, &sb, td->td_ucred, NOCRED, td);
1650 vput(nd.ni_vp);
1651 if (error)
1652 return (error);
1653 cvtnstat(&sb, &nsb);
1654 error = copyout(&nsb, SCARG(uap, ub), sizeof (nsb));
1655 return (error);
1656}
1657
1658/*
1659 * NetBSD lstat. Get file status; this version does not follow links.
1660 */
1661#ifndef _SYS_SYSPROTO_H_
1662struct lstat_args {
1663 char *path;
1664 struct stat *ub;
1665};
1666#endif
1667/* ARGSUSED */
1668int
1669nlstat(td, uap)
1670 struct thread *td;
1671 register struct nlstat_args /* {
1672 syscallarg(char *) path;
1673 syscallarg(struct nstat *) ub;
1674 } */ *uap;
1675{
1676 int error;
1677 struct vnode *vp;
1678 struct stat sb;
1679 struct nstat nsb;
1680 struct nameidata nd;
1681
1682 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1683 SCARG(uap, path), td);
1684 if ((error = namei(&nd)) != 0)
1685 return (error);
1686 vp = nd.ni_vp;
1687 NDFREE(&nd, NDF_ONLY_PNBUF);
1688 error = vn_stat(vp, &sb, td->td_ucred, NOCRED, td);
1689 vput(vp);
1690 if (error)
1691 return (error);
1692 cvtnstat(&sb, &nsb);
1693 error = copyout(&nsb, SCARG(uap, ub), sizeof (nsb));
1694 return (error);
1695}
1696
1697/*
1698 * Get configurable pathname variables.
1699 */
1700#ifndef _SYS_SYSPROTO_H_
1701struct pathconf_args {
1702 char *path;
1703 int name;
1704};
1705#endif
1706/* ARGSUSED */
1707int
1708pathconf(td, uap)
1709 struct thread *td;
1710 register struct pathconf_args /* {
1711 syscallarg(char *) path;
1712 syscallarg(int) name;
1713 } */ *uap;
1714{
1715 int error;
1716 struct nameidata nd;
1717
1718 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1719 SCARG(uap, path), td);
1720 if ((error = namei(&nd)) != 0)
1721 return (error);
1722 NDFREE(&nd, NDF_ONLY_PNBUF);
1723 error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), td->td_retval);
1724 vput(nd.ni_vp);
1725 return (error);
1726}
1727
1728/*
1729 * Return target name of a symbolic link.
1730 */
1731#ifndef _SYS_SYSPROTO_H_
1732struct readlink_args {
1733 char *path;
1734 char *buf;
1735 int count;
1736};
1737#endif
1738/* ARGSUSED */
1739int
1740readlink(td, uap)
1741 struct thread *td;
1742 register struct readlink_args /* {
1743 syscallarg(char *) path;
1744 syscallarg(char *) buf;
1745 syscallarg(int) count;
1746 } */ *uap;
1747{
1748 register struct vnode *vp;
1749 struct iovec aiov;
1750 struct uio auio;
1751 int error;
1752 struct nameidata nd;
1753
1754 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1755 SCARG(uap, path), td);
1756 if ((error = namei(&nd)) != 0)
1757 return (error);
1758 NDFREE(&nd, NDF_ONLY_PNBUF);
1759 vp = nd.ni_vp;
1760#ifdef MAC
1761 error = mac_check_vnode_readlink(td->td_ucred, vp);
1762 if (error) {
1763 vput(vp);
1764 return (error);
1765 }
1766#endif
1767 if (vp->v_type != VLNK)
1768 error = EINVAL;
1769 else {
1770 aiov.iov_base = SCARG(uap, buf);
1771 aiov.iov_len = SCARG(uap, count);
1772 auio.uio_iov = &aiov;
1773 auio.uio_iovcnt = 1;
1774 auio.uio_offset = 0;
1775 auio.uio_rw = UIO_READ;
1776 auio.uio_segflg = UIO_USERSPACE;
1777 auio.uio_td = td;
1778 auio.uio_resid = SCARG(uap, count);
1779 error = VOP_READLINK(vp, &auio, td->td_ucred);
1780 }
1781 vput(vp);
1782 td->td_retval[0] = SCARG(uap, count) - auio.uio_resid;
1783 return (error);
1784}
1785
1786/*
1787 * Common implementation code for chflags() and fchflags().
1788 */
1789static int
1790setfflags(td, vp, flags)
1791 struct thread *td;
1792 struct vnode *vp;
1793 int flags;
1794{
1795 int error;
1796 struct mount *mp;
1797 struct vattr vattr;
1798
1799 /*
1800 * Prevent non-root users from setting flags on devices. When
1801 * a device is reused, users can retain ownership of the device
1802 * if they are allowed to set flags and programs assume that
1803 * chown can't fail when done as root.
1804 */
1805 if (vp->v_type == VCHR || vp->v_type == VBLK) {
1806 error = suser_cred(td->td_ucred, PRISON_ROOT);
1807 if (error)
1808 return (error);
1809 }
1810
1811 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
1812 return (error);
1813 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
1814 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
1815#ifdef MAC
1816 error = mac_check_vnode_setflags(td->td_ucred, vp, vattr.va_flags);
1817 if (error == 0) {
1818#endif
1819 VATTR_NULL(&vattr);
1820 vattr.va_flags = flags;
1821 error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
1822#ifdef MAC
1823 }
1824#endif
1825 VOP_UNLOCK(vp, 0, td);
1826 vn_finished_write(mp);
1827 return (error);
1828}
1829
1830/*
1831 * Change flags of a file given a path name.
1832 */
1833#ifndef _SYS_SYSPROTO_H_
1834struct chflags_args {
1835 char *path;
1836 int flags;
1837};
1838#endif
1839/* ARGSUSED */
1840int
1841chflags(td, uap)
1842 struct thread *td;
1843 register struct chflags_args /* {
1844 syscallarg(char *) path;
1845 syscallarg(int) flags;
1846 } */ *uap;
1847{
1848 int error;
1849 struct nameidata nd;
1850
1851 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
1852 if ((error = namei(&nd)) != 0)
1853 return (error);
1854 NDFREE(&nd, NDF_ONLY_PNBUF);
1855 error = setfflags(td, nd.ni_vp, SCARG(uap, flags));
1856 vrele(nd.ni_vp);
1857 return error;
1858}
1859
1860/*
1861 * Same as chflags() but doesn't follow symlinks.
1862 */
1863int
1864lchflags(td, uap)
1865 struct thread *td;
1866 register struct lchflags_args /* {
1867 syscallarg(char *) path;
1868 syscallarg(int) flags;
1869 } */ *uap;
1870{
1871 int error;
1872 struct nameidata nd;
1873
1874 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
1875 if ((error = namei(&nd)) != 0)
1876 return (error);
1877 NDFREE(&nd, NDF_ONLY_PNBUF);
1878 error = setfflags(td, nd.ni_vp, SCARG(uap, flags));
1879 vrele(nd.ni_vp);
1880 return error;
1881}
1882
1883/*
1884 * Change flags of a file given a file descriptor.
1885 */
1886#ifndef _SYS_SYSPROTO_H_
1887struct fchflags_args {
1888 int fd;
1889 int flags;
1890};
1891#endif
1892/* ARGSUSED */
1893int
1894fchflags(td, uap)
1895 struct thread *td;
1896 register struct fchflags_args /* {
1897 syscallarg(int) fd;
1898 syscallarg(int) flags;
1899 } */ *uap;
1900{
1901 struct file *fp;
1902 int error;
1903
1904 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
1905 return (error);
1906 error = setfflags(td, (struct vnode *) fp->f_data, SCARG(uap, flags));
1907 fdrop(fp, td);
1908 return (error);
1909}
1910
1911/*
1912 * Common implementation code for chmod(), lchmod() and fchmod().
1913 */
1914static int
1915setfmode(td, vp, mode)
1916 struct thread *td;
1917 struct vnode *vp;
1918 int mode;
1919{
1920 int error;
1921 struct mount *mp;
1922 struct vattr vattr;
1923
1924 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
1925 return (error);
1926 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
1927 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
1928 VATTR_NULL(&vattr);
1929 vattr.va_mode = mode & ALLPERMS;
1930#ifdef MAC
1931 error = mac_check_vnode_setmode(td->td_ucred, vp, vattr.va_mode);
1932 if (error == 0)
1933#endif
1934 error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
1935 VOP_UNLOCK(vp, 0, td);
1936 vn_finished_write(mp);
1937 return error;
1938}
1939
1940/*
1941 * Change mode of a file given path name.
1942 */
1943#ifndef _SYS_SYSPROTO_H_
1944struct chmod_args {
1945 char *path;
1946 int mode;
1947};
1948#endif
1949/* ARGSUSED */
1950int
1951chmod(td, uap)
1952 struct thread *td;
1953 register struct chmod_args /* {
1954 syscallarg(char *) path;
1955 syscallarg(int) mode;
1956 } */ *uap;
1957{
1958 int error;
1959 struct nameidata nd;
1960
1961 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
1962 if ((error = namei(&nd)) != 0)
1963 return (error);
1964 NDFREE(&nd, NDF_ONLY_PNBUF);
1965 error = setfmode(td, nd.ni_vp, SCARG(uap, mode));
1966 vrele(nd.ni_vp);
1967 return error;
1968}
1969
1970/*
1971 * Change mode of a file given path name (don't follow links.)
1972 */
1973#ifndef _SYS_SYSPROTO_H_
1974struct lchmod_args {
1975 char *path;
1976 int mode;
1977};
1978#endif
1979/* ARGSUSED */
1980int
1981lchmod(td, uap)
1982 struct thread *td;
1983 register struct lchmod_args /* {
1984 syscallarg(char *) path;
1985 syscallarg(int) mode;
1986 } */ *uap;
1987{
1988 int error;
1989 struct nameidata nd;
1990
1991 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
1992 if ((error = namei(&nd)) != 0)
1993 return (error);
1994 NDFREE(&nd, NDF_ONLY_PNBUF);
1995 error = setfmode(td, nd.ni_vp, SCARG(uap, mode));
1996 vrele(nd.ni_vp);
1997 return error;
1998}
1999
2000/*
2001 * Change mode of a file given a file descriptor.
2002 */
2003#ifndef _SYS_SYSPROTO_H_
2004struct fchmod_args {
2005 int fd;
2006 int mode;
2007};
2008#endif
2009/* ARGSUSED */
2010int
2011fchmod(td, uap)
2012 struct thread *td;
2013 register struct fchmod_args /* {
2014 syscallarg(int) fd;
2015 syscallarg(int) mode;
2016 } */ *uap;
2017{
2018 struct file *fp;
2019 struct vnode *vp;
2020 int error;
2021
2022 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
2023 return (error);
2024 vp = (struct vnode *)fp->f_data;
2025 error = setfmode(td, (struct vnode *)fp->f_data, SCARG(uap, mode));
2026 fdrop(fp, td);
2027 return (error);
2028}
2029
2030/*
2031 * Common implementation for chown(), lchown(), and fchown()
2032 */
2033static int
2034setfown(td, vp, uid, gid)
2035 struct thread *td;
2036 struct vnode *vp;
2037 uid_t uid;
2038 gid_t gid;
2039{
2040 int error;
2041 struct mount *mp;
2042 struct vattr vattr;
2043
2044 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
2045 return (error);
2046 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
2047 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2048 VATTR_NULL(&vattr);
2049 vattr.va_uid = uid;
2050 vattr.va_gid = gid;
2051#ifdef MAC
2052 error = mac_check_vnode_setowner(td->td_ucred, vp, vattr.va_uid,
2053 vattr.va_gid);
2054 if (error == 0)
2055#endif
2056 error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
2057 VOP_UNLOCK(vp, 0, td);
2058 vn_finished_write(mp);
2059 return error;
2060}
2061
2062/*
2063 * Set ownership given a path name.
2064 */
2065#ifndef _SYS_SYSPROTO_H_
2066struct chown_args {
2067 char *path;
2068 int uid;
2069 int gid;
2070};
2071#endif
2072/* ARGSUSED */
2073int
2074chown(td, uap)
2075 struct thread *td;
2076 register struct chown_args /* {
2077 syscallarg(char *) path;
2078 syscallarg(int) uid;
2079 syscallarg(int) gid;
2080 } */ *uap;
2081{
2082 int error;
2083 struct nameidata nd;
2084
2085 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2086 if ((error = namei(&nd)) != 0)
2087 return (error);
2088 NDFREE(&nd, NDF_ONLY_PNBUF);
2089 error = setfown(td, nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid));
2090 vrele(nd.ni_vp);
2091 return (error);
2092}
2093
2094/*
2095 * Set ownership given a path name, do not cross symlinks.
2096 */
2097#ifndef _SYS_SYSPROTO_H_
2098struct lchown_args {
2099 char *path;
2100 int uid;
2101 int gid;
2102};
2103#endif
2104/* ARGSUSED */
2105int
2106lchown(td, uap)
2107 struct thread *td;
2108 register struct lchown_args /* {
2109 syscallarg(char *) path;
2110 syscallarg(int) uid;
2111 syscallarg(int) gid;
2112 } */ *uap;
2113{
2114 int error;
2115 struct nameidata nd;
2116
2117 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2118 if ((error = namei(&nd)) != 0)
2119 return (error);
2120 NDFREE(&nd, NDF_ONLY_PNBUF);
2121 error = setfown(td, nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid));
2122 vrele(nd.ni_vp);
2123 return (error);
2124}
2125
2126/*
2127 * Set ownership given a file descriptor.
2128 */
2129#ifndef _SYS_SYSPROTO_H_
2130struct fchown_args {
2131 int fd;
2132 int uid;
2133 int gid;
2134};
2135#endif
2136/* ARGSUSED */
2137int
2138fchown(td, uap)
2139 struct thread *td;
2140 register struct fchown_args /* {
2141 syscallarg(int) fd;
2142 syscallarg(int) uid;
2143 syscallarg(int) gid;
2144 } */ *uap;
2145{
2146 struct file *fp;
2147 struct vnode *vp;
2148 int error;
2149
2150 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
2151 return (error);
2152 vp = (struct vnode *)fp->f_data;
2153 error = setfown(td, (struct vnode *)fp->f_data,
2154 SCARG(uap, uid), SCARG(uap, gid));
2155 fdrop(fp, td);
2156 return (error);
2157}
2158
2159/*
2160 * Common implementation code for utimes(), lutimes(), and futimes().
2161 */
2162static int
2163getutimes(usrtvp, tsp)
2164 const struct timeval *usrtvp;
2165 struct timespec *tsp;
2166{
2167 struct timeval tv[2];
2168 int error;
2169
2170 if (usrtvp == NULL) {
2171 microtime(&tv[0]);
2172 TIMEVAL_TO_TIMESPEC(&tv[0], &tsp[0]);
2173 tsp[1] = tsp[0];
2174 } else {
2175 if ((error = copyin(usrtvp, tv, sizeof (tv))) != 0)
2176 return (error);
2177 TIMEVAL_TO_TIMESPEC(&tv[0], &tsp[0]);
2178 TIMEVAL_TO_TIMESPEC(&tv[1], &tsp[1]);
2179 }
2180 return 0;
2181}
2182
2183/*
2184 * Common implementation code for utimes(), lutimes(), and futimes().
2185 */
2186static int
2187setutimes(td, vp, ts, numtimes, nullflag)
2188 struct thread *td;
2189 struct vnode *vp;
2190 const struct timespec *ts;
2191 int numtimes;
2192 int nullflag;
2193{
2194 int error, setbirthtime;
2195 struct mount *mp;
2196 struct vattr vattr;
2197
2198 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
2199 return (error);
2200 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
2201 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2202 setbirthtime = 0;
2203 if (numtimes < 3 && VOP_GETATTR(vp, &vattr, td->td_ucred, td) == 0 &&
2204 timespeccmp(&ts[1], &vattr.va_birthtime, < ))
2205 setbirthtime = 1;
2206 VATTR_NULL(&vattr);
2207 vattr.va_atime = ts[0];
2208 vattr.va_mtime = ts[1];
2209 if (setbirthtime)
2210 vattr.va_birthtime = ts[1];
2211 if (numtimes > 2)
2212 vattr.va_birthtime = ts[2];
2213 if (nullflag)
2214 vattr.va_vaflags |= VA_UTIMES_NULL;
2215#ifdef MAC
2216 error = mac_check_vnode_setutimes(td->td_ucred, vp, vattr.va_atime,
2217 vattr.va_mtime);
2218 if (error == 0)
2219#endif
2220 error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
2221 VOP_UNLOCK(vp, 0, td);
2222 vn_finished_write(mp);
2223 return error;
2224}
2225
2226/*
2227 * Set the access and modification times of a file.
2228 */
2229#ifndef _SYS_SYSPROTO_H_
2230struct utimes_args {
2231 char *path;
2232 struct timeval *tptr;
2233};
2234#endif
2235/* ARGSUSED */
2236int
2237utimes(td, uap)
2238 struct thread *td;
2239 register struct utimes_args /* {
2240 syscallarg(char *) path;
2241 syscallarg(struct timeval *) tptr;
2242 } */ *uap;
2243{
2244 struct timespec ts[2];
2245 struct timeval *usrtvp;
2246 int error;
2247 struct nameidata nd;
2248
2249 usrtvp = SCARG(uap, tptr);
2250 if ((error = getutimes(usrtvp, ts)) != 0)
2251 return (error);
2252 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2253 if ((error = namei(&nd)) != 0)
2254 return (error);
2255 NDFREE(&nd, NDF_ONLY_PNBUF);
2256 error = setutimes(td, nd.ni_vp, ts, 2, usrtvp == NULL);
2257 vrele(nd.ni_vp);
2258 return (error);
2259}
2260
2261/*
2262 * Set the access and modification times of a file.
2263 */
2264#ifndef _SYS_SYSPROTO_H_
2265struct lutimes_args {
2266 char *path;
2267 struct timeval *tptr;
2268};
2269#endif
2270/* ARGSUSED */
2271int
2272lutimes(td, uap)
2273 struct thread *td;
2274 register struct lutimes_args /* {
2275 syscallarg(char *) path;
2276 syscallarg(struct timeval *) tptr;
2277 } */ *uap;
2278{
2279 struct timespec ts[2];
2280 struct timeval *usrtvp;
2281 int error;
2282 struct nameidata nd;
2283
2284 usrtvp = SCARG(uap, tptr);
2285 if ((error = getutimes(usrtvp, ts)) != 0)
2286 return (error);
2287 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2288 if ((error = namei(&nd)) != 0)
2289 return (error);
2290 NDFREE(&nd, NDF_ONLY_PNBUF);
2291 error = setutimes(td, nd.ni_vp, ts, 2, usrtvp == NULL);
2292 vrele(nd.ni_vp);
2293 return (error);
2294}
2295
2296/*
2297 * Set the access and modification times of a file.
2298 */
2299#ifndef _SYS_SYSPROTO_H_
2300struct futimes_args {
2301 int fd;
2302 struct timeval *tptr;
2303};
2304#endif
2305/* ARGSUSED */
2306int
2307futimes(td, uap)
2308 struct thread *td;
2309 register struct futimes_args /* {
2310 syscallarg(int ) fd;
2311 syscallarg(struct timeval *) tptr;
2312 } */ *uap;
2313{
2314 struct timespec ts[2];
2315 struct file *fp;
2316 struct timeval *usrtvp;
2317 int error;
2318
2319 usrtvp = SCARG(uap, tptr);
2320 if ((error = getutimes(usrtvp, ts)) != 0)
2321 return (error);
2322 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
2323 return (error);
2324 error = setutimes(td, (struct vnode *)fp->f_data, ts, 2, usrtvp==NULL);
2325 fdrop(fp, td);
2326 return (error);
2327}
2328
2329/*
2330 * Truncate a file given its path name.
2331 */
2332#ifndef _SYS_SYSPROTO_H_
2333struct truncate_args {
2334 char *path;
2335 int pad;
2336 off_t length;
2337};
2338#endif
2339/* ARGSUSED */
2340int
2341truncate(td, uap)
2342 struct thread *td;
2343 register struct truncate_args /* {
2344 syscallarg(char *) path;
2345 syscallarg(int) pad;
2346 syscallarg(off_t) length;
2347 } */ *uap;
2348{
2349 struct mount *mp;
2350 struct vnode *vp;
2351 struct vattr vattr;
2352 int error;
2353 struct nameidata nd;
2354
2355 if (uap->length < 0)
2356 return(EINVAL);
2357 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2358 if ((error = namei(&nd)) != 0)
2359 return (error);
2360 vp = nd.ni_vp;
2361 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) {
2362 vrele(vp);
2363 return (error);
2364 }
2365 NDFREE(&nd, NDF_ONLY_PNBUF);
2366 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
2367 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2368 if (vp->v_type == VDIR)
2369 error = EISDIR;
2370#ifdef MAC
738 if (error == 0)
739#endif
740 error = VOP_SETATTR(vp, &vat, td->td_ucred, td);
741 VOP_UNLOCK(vp, 0, td);
742 vn_finished_write(mp);
743 if (error)
744 goto bad;
745 }
746 /*
747 * Release our private reference, leaving the one associated with
748 * the descriptor table intact.
749 */
750 fdrop(fp, td);
751 td->td_retval[0] = indx;
752 return (0);
753bad:
754 FILEDESC_LOCK(fdp);
755 if (fdp->fd_ofiles[indx] == fp) {
756 fdp->fd_ofiles[indx] = NULL;
757 FILEDESC_UNLOCK(fdp);
758 fdrop(fp, td);
759 } else
760 FILEDESC_UNLOCK(fdp);
761 return (error);
762}
763
764#ifdef COMPAT_43
765/*
766 * Create a file.
767 */
768#ifndef _SYS_SYSPROTO_H_
769struct ocreat_args {
770 char *path;
771 int mode;
772};
773#endif
774int
775ocreat(td, uap)
776 struct thread *td;
777 register struct ocreat_args /* {
778 syscallarg(char *) path;
779 syscallarg(int) mode;
780 } */ *uap;
781{
782 struct open_args /* {
783 syscallarg(char *) path;
784 syscallarg(int) flags;
785 syscallarg(int) mode;
786 } */ nuap;
787
788 SCARG(&nuap, path) = SCARG(uap, path);
789 SCARG(&nuap, mode) = SCARG(uap, mode);
790 SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC;
791 return (open(td, &nuap));
792}
793#endif /* COMPAT_43 */
794
795/*
796 * Create a special file.
797 */
798#ifndef _SYS_SYSPROTO_H_
799struct mknod_args {
800 char *path;
801 int mode;
802 int dev;
803};
804#endif
805/* ARGSUSED */
806int
807mknod(td, uap)
808 struct thread *td;
809 register struct mknod_args /* {
810 syscallarg(char *) path;
811 syscallarg(int) mode;
812 syscallarg(int) dev;
813 } */ *uap;
814{
815 struct vnode *vp;
816 struct mount *mp;
817 struct vattr vattr;
818 int error;
819 int whiteout = 0;
820 struct nameidata nd;
821
822 switch (SCARG(uap, mode) & S_IFMT) {
823 case S_IFCHR:
824 case S_IFBLK:
825 error = suser(td);
826 break;
827 default:
828 error = suser_cred(td->td_ucred, PRISON_ROOT);
829 break;
830 }
831 if (error)
832 return (error);
833restart:
834 bwillwrite();
835 NDINIT(&nd, CREATE, LOCKPARENT | SAVENAME, UIO_USERSPACE,
836 SCARG(uap, path), td);
837 if ((error = namei(&nd)) != 0)
838 return (error);
839 vp = nd.ni_vp;
840 if (vp != NULL) {
841 vrele(vp);
842 error = EEXIST;
843 } else {
844 VATTR_NULL(&vattr);
845 FILEDESC_LOCK(td->td_proc->p_fd);
846 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ td->td_proc->p_fd->fd_cmask;
847 FILEDESC_UNLOCK(td->td_proc->p_fd);
848 vattr.va_rdev = SCARG(uap, dev);
849 whiteout = 0;
850
851 switch (SCARG(uap, mode) & S_IFMT) {
852 case S_IFMT: /* used by badsect to flag bad sectors */
853 vattr.va_type = VBAD;
854 break;
855 case S_IFCHR:
856 vattr.va_type = VCHR;
857 break;
858 case S_IFBLK:
859 vattr.va_type = VBLK;
860 break;
861 case S_IFWHT:
862 whiteout = 1;
863 break;
864 default:
865 error = EINVAL;
866 break;
867 }
868 }
869 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
870 NDFREE(&nd, NDF_ONLY_PNBUF);
871 vput(nd.ni_dvp);
872 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
873 return (error);
874 goto restart;
875 }
876 if (!error) {
877 VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
878 if (whiteout)
879 error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
880 else {
881 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp,
882 &nd.ni_cnd, &vattr);
883 if (error == 0)
884 vput(nd.ni_vp);
885 }
886 }
887 NDFREE(&nd, NDF_ONLY_PNBUF);
888 vput(nd.ni_dvp);
889 vn_finished_write(mp);
890 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mknod");
891 ASSERT_VOP_UNLOCKED(nd.ni_vp, "mknod");
892 return (error);
893}
894
895/*
896 * Create a named pipe.
897 */
898#ifndef _SYS_SYSPROTO_H_
899struct mkfifo_args {
900 char *path;
901 int mode;
902};
903#endif
904/* ARGSUSED */
905int
906mkfifo(td, uap)
907 struct thread *td;
908 register struct mkfifo_args /* {
909 syscallarg(char *) path;
910 syscallarg(int) mode;
911 } */ *uap;
912{
913 struct mount *mp;
914 struct vattr vattr;
915 int error;
916 struct nameidata nd;
917
918restart:
919 bwillwrite();
920 NDINIT(&nd, CREATE, LOCKPARENT | SAVENAME, UIO_USERSPACE,
921 SCARG(uap, path), td);
922 if ((error = namei(&nd)) != 0)
923 return (error);
924 if (nd.ni_vp != NULL) {
925 NDFREE(&nd, NDF_ONLY_PNBUF);
926 vrele(nd.ni_vp);
927 vput(nd.ni_dvp);
928 return (EEXIST);
929 }
930 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
931 NDFREE(&nd, NDF_ONLY_PNBUF);
932 vput(nd.ni_dvp);
933 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
934 return (error);
935 goto restart;
936 }
937 VATTR_NULL(&vattr);
938 vattr.va_type = VFIFO;
939 FILEDESC_LOCK(td->td_proc->p_fd);
940 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ td->td_proc->p_fd->fd_cmask;
941 FILEDESC_UNLOCK(td->td_proc->p_fd);
942 VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
943 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
944 if (error == 0)
945 vput(nd.ni_vp);
946 NDFREE(&nd, NDF_ONLY_PNBUF);
947 vput(nd.ni_dvp);
948 vn_finished_write(mp);
949 return (error);
950}
951
952/*
953 * Make a hard file link.
954 */
955#ifndef _SYS_SYSPROTO_H_
956struct link_args {
957 char *path;
958 char *link;
959};
960#endif
961/* ARGSUSED */
962int
963link(td, uap)
964 struct thread *td;
965 register struct link_args /* {
966 syscallarg(char *) path;
967 syscallarg(char *) link;
968 } */ *uap;
969{
970 struct vnode *vp;
971 struct mount *mp;
972 struct nameidata nd;
973 int error;
974
975 bwillwrite();
976 NDINIT(&nd, LOOKUP, FOLLOW|NOOBJ, UIO_USERSPACE, SCARG(uap, path), td);
977 if ((error = namei(&nd)) != 0)
978 return (error);
979 NDFREE(&nd, NDF_ONLY_PNBUF);
980 vp = nd.ni_vp;
981 if (vp->v_type == VDIR) {
982 vrele(vp);
983 return (EPERM); /* POSIX */
984 }
985 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) {
986 vrele(vp);
987 return (error);
988 }
989 NDINIT(&nd, CREATE, LOCKPARENT | NOOBJ | SAVENAME, UIO_USERSPACE,
990 SCARG(uap, link), td);
991 if ((error = namei(&nd)) == 0) {
992 if (nd.ni_vp != NULL) {
993 vrele(nd.ni_vp);
994 error = EEXIST;
995 } else {
996 VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
997 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
998 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
999 }
1000 NDFREE(&nd, NDF_ONLY_PNBUF);
1001 vput(nd.ni_dvp);
1002 }
1003 vrele(vp);
1004 vn_finished_write(mp);
1005 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "link");
1006 ASSERT_VOP_UNLOCKED(nd.ni_vp, "link");
1007 return (error);
1008}
1009
1010/*
1011 * Make a symbolic link.
1012 */
1013#ifndef _SYS_SYSPROTO_H_
1014struct symlink_args {
1015 char *path;
1016 char *link;
1017};
1018#endif
1019/* ARGSUSED */
1020int
1021symlink(td, uap)
1022 struct thread *td;
1023 register struct symlink_args /* {
1024 syscallarg(char *) path;
1025 syscallarg(char *) link;
1026 } */ *uap;
1027{
1028 struct mount *mp;
1029 struct vattr vattr;
1030 char *path;
1031 int error;
1032 struct nameidata nd;
1033
1034 path = uma_zalloc(namei_zone, M_WAITOK);
1035 if ((error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL)) != 0)
1036 goto out;
1037restart:
1038 bwillwrite();
1039 NDINIT(&nd, CREATE, LOCKPARENT | NOOBJ | SAVENAME, UIO_USERSPACE,
1040 SCARG(uap, link), td);
1041 if ((error = namei(&nd)) != 0)
1042 goto out;
1043 if (nd.ni_vp) {
1044 NDFREE(&nd, NDF_ONLY_PNBUF);
1045 vrele(nd.ni_vp);
1046 vput(nd.ni_dvp);
1047 error = EEXIST;
1048 goto out;
1049 }
1050 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1051 NDFREE(&nd, NDF_ONLY_PNBUF);
1052 vput(nd.ni_dvp);
1053 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
1054 return (error);
1055 goto restart;
1056 }
1057 VATTR_NULL(&vattr);
1058 FILEDESC_LOCK(td->td_proc->p_fd);
1059 vattr.va_mode = ACCESSPERMS &~ td->td_proc->p_fd->fd_cmask;
1060 FILEDESC_UNLOCK(td->td_proc->p_fd);
1061 VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
1062 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
1063 NDFREE(&nd, NDF_ONLY_PNBUF);
1064 if (error == 0)
1065 vput(nd.ni_vp);
1066 vput(nd.ni_dvp);
1067 vn_finished_write(mp);
1068 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "symlink");
1069 ASSERT_VOP_UNLOCKED(nd.ni_vp, "symlink");
1070out:
1071 uma_zfree(namei_zone, path);
1072 return (error);
1073}
1074
1075/*
1076 * Delete a whiteout from the filesystem.
1077 */
1078/* ARGSUSED */
1079int
1080undelete(td, uap)
1081 struct thread *td;
1082 register struct undelete_args /* {
1083 syscallarg(char *) path;
1084 } */ *uap;
1085{
1086 int error;
1087 struct mount *mp;
1088 struct nameidata nd;
1089
1090restart:
1091 bwillwrite();
1092 NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE,
1093 SCARG(uap, path), td);
1094 error = namei(&nd);
1095 if (error)
1096 return (error);
1097
1098 if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
1099 NDFREE(&nd, NDF_ONLY_PNBUF);
1100 if (nd.ni_vp)
1101 vrele(nd.ni_vp);
1102 vput(nd.ni_dvp);
1103 return (EEXIST);
1104 }
1105 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1106 NDFREE(&nd, NDF_ONLY_PNBUF);
1107 vput(nd.ni_dvp);
1108 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
1109 return (error);
1110 goto restart;
1111 }
1112 VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
1113 error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE);
1114 NDFREE(&nd, NDF_ONLY_PNBUF);
1115 vput(nd.ni_dvp);
1116 vn_finished_write(mp);
1117 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "undelete");
1118 ASSERT_VOP_UNLOCKED(nd.ni_vp, "undelete");
1119 return (error);
1120}
1121
1122/*
1123 * Delete a name from the filesystem.
1124 */
1125#ifndef _SYS_SYSPROTO_H_
1126struct unlink_args {
1127 char *path;
1128};
1129#endif
1130/* ARGSUSED */
1131int
1132unlink(td, uap)
1133 struct thread *td;
1134 struct unlink_args /* {
1135 syscallarg(char *) path;
1136 } */ *uap;
1137{
1138 struct mount *mp;
1139 struct vnode *vp;
1140 int error;
1141 struct nameidata nd;
1142
1143restart:
1144 bwillwrite();
1145 NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), td);
1146 if ((error = namei(&nd)) != 0)
1147 return (error);
1148 vp = nd.ni_vp;
1149 if (vp->v_type == VDIR)
1150 error = EPERM; /* POSIX */
1151 else {
1152 /*
1153 * The root of a mounted filesystem cannot be deleted.
1154 *
1155 * XXX: can this only be a VDIR case?
1156 */
1157 mp_fixme("Accessing vflags w/o the vn lock.");
1158 if (vp->v_vflag & VV_ROOT)
1159 error = EBUSY;
1160 }
1161 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1162 NDFREE(&nd, NDF_ONLY_PNBUF);
1163 vrele(vp);
1164 vput(nd.ni_dvp);
1165 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
1166 return (error);
1167 goto restart;
1168 }
1169 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
1170 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
1171 if (!error) {
1172 VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
1173 error = VOP_REMOVE(nd.ni_dvp, vp, &nd.ni_cnd);
1174 }
1175 NDFREE(&nd, NDF_ONLY_PNBUF);
1176 vput(nd.ni_dvp);
1177 vput(vp);
1178 vn_finished_write(mp);
1179 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "unlink");
1180 ASSERT_VOP_UNLOCKED(nd.ni_vp, "unlink");
1181 return (error);
1182}
1183
1184/*
1185 * Reposition read/write file offset.
1186 */
1187#ifndef _SYS_SYSPROTO_H_
1188struct lseek_args {
1189 int fd;
1190 int pad;
1191 off_t offset;
1192 int whence;
1193};
1194#endif
1195int
1196lseek(td, uap)
1197 struct thread *td;
1198 register struct lseek_args /* {
1199 syscallarg(int) fd;
1200 syscallarg(int) pad;
1201 syscallarg(off_t) offset;
1202 syscallarg(int) whence;
1203 } */ *uap;
1204{
1205 struct ucred *cred = td->td_ucred;
1206 struct file *fp;
1207 struct vnode *vp;
1208 struct vattr vattr;
1209 off_t offset;
1210 int error, noneg;
1211
1212 if ((error = fget(td, uap->fd, &fp)) != 0)
1213 return (error);
1214 if (fp->f_type != DTYPE_VNODE) {
1215 fdrop(fp, td);
1216 return (ESPIPE);
1217 }
1218 vp = (struct vnode *)fp->f_data;
1219 noneg = (vp->v_type != VCHR);
1220 offset = SCARG(uap, offset);
1221 switch (SCARG(uap, whence)) {
1222 case L_INCR:
1223 if (noneg &&
1224 (fp->f_offset < 0 ||
1225 (offset > 0 && fp->f_offset > OFF_MAX - offset)))
1226 return (EOVERFLOW);
1227 offset += fp->f_offset;
1228 break;
1229 case L_XTND:
1230 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
1231 error = VOP_GETATTR(vp, &vattr, cred, td);
1232 VOP_UNLOCK(vp, 0, td);
1233 if (error)
1234 return (error);
1235 if (noneg &&
1236 (vattr.va_size > OFF_MAX ||
1237 (offset > 0 && vattr.va_size > OFF_MAX - offset)))
1238 return (EOVERFLOW);
1239 offset += vattr.va_size;
1240 break;
1241 case L_SET:
1242 break;
1243 default:
1244 fdrop(fp, td);
1245 return (EINVAL);
1246 }
1247 if (noneg && offset < 0)
1248 return (EINVAL);
1249 fp->f_offset = offset;
1250 *(off_t *)(td->td_retval) = fp->f_offset;
1251 fdrop(fp, td);
1252 return (0);
1253}
1254
1255#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1256/*
1257 * Reposition read/write file offset.
1258 */
1259#ifndef _SYS_SYSPROTO_H_
1260struct olseek_args {
1261 int fd;
1262 long offset;
1263 int whence;
1264};
1265#endif
1266int
1267olseek(td, uap)
1268 struct thread *td;
1269 register struct olseek_args /* {
1270 syscallarg(int) fd;
1271 syscallarg(long) offset;
1272 syscallarg(int) whence;
1273 } */ *uap;
1274{
1275 struct lseek_args /* {
1276 syscallarg(int) fd;
1277 syscallarg(int) pad;
1278 syscallarg(off_t) offset;
1279 syscallarg(int) whence;
1280 } */ nuap;
1281 int error;
1282
1283 SCARG(&nuap, fd) = SCARG(uap, fd);
1284 SCARG(&nuap, offset) = SCARG(uap, offset);
1285 SCARG(&nuap, whence) = SCARG(uap, whence);
1286 error = lseek(td, &nuap);
1287 return (error);
1288}
1289#endif /* COMPAT_43 */
1290
1291/*
1292 * Check access permissions using passed credentials.
1293 */
1294static int
1295vn_access(vp, user_flags, cred, td)
1296 struct vnode *vp;
1297 int user_flags;
1298 struct ucred *cred;
1299 struct thread *td;
1300{
1301 int error, flags;
1302
1303 /* Flags == 0 means only check for existence. */
1304 error = 0;
1305 if (user_flags) {
1306 flags = 0;
1307 if (user_flags & R_OK)
1308 flags |= VREAD;
1309 if (user_flags & W_OK)
1310 flags |= VWRITE;
1311 if (user_flags & X_OK)
1312 flags |= VEXEC;
1313#ifdef MAC
1314 error = mac_check_vnode_access(cred, vp, flags);
1315 if (error)
1316 return (error);
1317#endif
1318 if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
1319 error = VOP_ACCESS(vp, flags, cred, td);
1320 }
1321 return (error);
1322}
1323
1324/*
1325 * Check access permissions using "real" credentials.
1326 */
1327#ifndef _SYS_SYSPROTO_H_
1328struct access_args {
1329 char *path;
1330 int flags;
1331};
1332#endif
1333int
1334access(td, uap)
1335 struct thread *td;
1336 register struct access_args /* {
1337 syscallarg(char *) path;
1338 syscallarg(int) flags;
1339 } */ *uap;
1340{
1341 struct ucred *cred, *tmpcred;
1342 register struct vnode *vp;
1343 int error;
1344 struct nameidata nd;
1345
1346 /*
1347 * Create and modify a temporary credential instead of one that
1348 * is potentially shared. This could also mess up socket
1349 * buffer accounting which can run in an interrupt context.
1350 *
1351 * XXX - Depending on how "threads" are finally implemented, it
1352 * may be better to explicitly pass the credential to namei()
1353 * rather than to modify the potentially shared process structure.
1354 */
1355 cred = td->td_ucred;
1356 tmpcred = crdup(cred);
1357 tmpcred->cr_uid = cred->cr_ruid;
1358 tmpcred->cr_groups[0] = cred->cr_rgid;
1359 td->td_ucred = tmpcred;
1360 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1361 SCARG(uap, path), td);
1362 if ((error = namei(&nd)) != 0)
1363 goto out1;
1364 vp = nd.ni_vp;
1365
1366 error = vn_access(vp, SCARG(uap, flags), tmpcred, td);
1367 NDFREE(&nd, NDF_ONLY_PNBUF);
1368 vput(vp);
1369out1:
1370 td->td_ucred = cred;
1371 crfree(tmpcred);
1372 return (error);
1373}
1374
1375/*
1376 * Check access permissions using "effective" credentials.
1377 */
1378#ifndef _SYS_SYSPROTO_H_
1379struct eaccess_args {
1380 char *path;
1381 int flags;
1382};
1383#endif
1384int
1385eaccess(td, uap)
1386 struct thread *td;
1387 register struct eaccess_args /* {
1388 syscallarg(char *) path;
1389 syscallarg(int) flags;
1390 } */ *uap;
1391{
1392 struct nameidata nd;
1393 struct vnode *vp;
1394 int error;
1395
1396 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1397 SCARG(uap, path), td);
1398 if ((error = namei(&nd)) != 0)
1399 return (error);
1400 vp = nd.ni_vp;
1401
1402 error = vn_access(vp, SCARG(uap, flags), td->td_ucred, td);
1403 NDFREE(&nd, NDF_ONLY_PNBUF);
1404 vput(vp);
1405 return (error);
1406}
1407
1408#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1409/*
1410 * Get file status; this version follows links.
1411 */
1412#ifndef _SYS_SYSPROTO_H_
1413struct ostat_args {
1414 char *path;
1415 struct ostat *ub;
1416};
1417#endif
1418/* ARGSUSED */
1419int
1420ostat(td, uap)
1421 struct thread *td;
1422 register struct ostat_args /* {
1423 syscallarg(char *) path;
1424 syscallarg(struct ostat *) ub;
1425 } */ *uap;
1426{
1427 struct stat sb;
1428 struct ostat osb;
1429 int error;
1430 struct nameidata nd;
1431
1432 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1433 SCARG(uap, path), td);
1434 if ((error = namei(&nd)) != 0)
1435 return (error);
1436 NDFREE(&nd, NDF_ONLY_PNBUF);
1437 error = vn_stat(nd.ni_vp, &sb, td->td_ucred, NOCRED, td);
1438 vput(nd.ni_vp);
1439 if (error)
1440 return (error);
1441 cvtstat(&sb, &osb);
1442 error = copyout(&osb, SCARG(uap, ub), sizeof (osb));
1443 return (error);
1444}
1445
1446/*
1447 * Get file status; this version does not follow links.
1448 */
1449#ifndef _SYS_SYSPROTO_H_
1450struct olstat_args {
1451 char *path;
1452 struct ostat *ub;
1453};
1454#endif
1455/* ARGSUSED */
1456int
1457olstat(td, uap)
1458 struct thread *td;
1459 register struct olstat_args /* {
1460 syscallarg(char *) path;
1461 syscallarg(struct ostat *) ub;
1462 } */ *uap;
1463{
1464 struct vnode *vp;
1465 struct stat sb;
1466 struct ostat osb;
1467 int error;
1468 struct nameidata nd;
1469
1470 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1471 SCARG(uap, path), td);
1472 if ((error = namei(&nd)) != 0)
1473 return (error);
1474 vp = nd.ni_vp;
1475 error = vn_stat(vp, &sb, td->td_ucred, NOCRED, td);
1476 NDFREE(&nd, NDF_ONLY_PNBUF);
1477 vput(vp);
1478 if (error)
1479 return (error);
1480 cvtstat(&sb, &osb);
1481 error = copyout(&osb, SCARG(uap, ub), sizeof (osb));
1482 return (error);
1483}
1484
1485/*
1486 * Convert from an old to a new stat structure.
1487 */
1488void
1489cvtstat(st, ost)
1490 struct stat *st;
1491 struct ostat *ost;
1492{
1493
1494 ost->st_dev = st->st_dev;
1495 ost->st_ino = st->st_ino;
1496 ost->st_mode = st->st_mode;
1497 ost->st_nlink = st->st_nlink;
1498 ost->st_uid = st->st_uid;
1499 ost->st_gid = st->st_gid;
1500 ost->st_rdev = st->st_rdev;
1501 if (st->st_size < (quad_t)1 << 32)
1502 ost->st_size = st->st_size;
1503 else
1504 ost->st_size = -2;
1505 ost->st_atime = st->st_atime;
1506 ost->st_mtime = st->st_mtime;
1507 ost->st_ctime = st->st_ctime;
1508 ost->st_blksize = st->st_blksize;
1509 ost->st_blocks = st->st_blocks;
1510 ost->st_flags = st->st_flags;
1511 ost->st_gen = st->st_gen;
1512}
1513#endif /* COMPAT_43 || COMPAT_SUNOS */
1514
1515/*
1516 * Get file status; this version follows links.
1517 */
1518#ifndef _SYS_SYSPROTO_H_
1519struct stat_args {
1520 char *path;
1521 struct stat *ub;
1522};
1523#endif
1524/* ARGSUSED */
1525int
1526stat(td, uap)
1527 struct thread *td;
1528 register struct stat_args /* {
1529 syscallarg(char *) path;
1530 syscallarg(struct stat *) ub;
1531 } */ *uap;
1532{
1533 struct stat sb;
1534 int error;
1535 struct nameidata nd;
1536
1537#ifdef LOOKUP_SHARED
1538 NDINIT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | NOOBJ,
1539 UIO_USERSPACE, SCARG(uap, path), td);
1540#else
1541 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1542 SCARG(uap, path), td);
1543#endif
1544 if ((error = namei(&nd)) != 0)
1545 return (error);
1546 error = vn_stat(nd.ni_vp, &sb, td->td_ucred, NOCRED, td);
1547 NDFREE(&nd, NDF_ONLY_PNBUF);
1548 vput(nd.ni_vp);
1549 if (error)
1550 return (error);
1551 error = copyout(&sb, SCARG(uap, ub), sizeof (sb));
1552 return (error);
1553}
1554
1555/*
1556 * Get file status; this version does not follow links.
1557 */
1558#ifndef _SYS_SYSPROTO_H_
1559struct lstat_args {
1560 char *path;
1561 struct stat *ub;
1562};
1563#endif
1564/* ARGSUSED */
1565int
1566lstat(td, uap)
1567 struct thread *td;
1568 register struct lstat_args /* {
1569 syscallarg(char *) path;
1570 syscallarg(struct stat *) ub;
1571 } */ *uap;
1572{
1573 int error;
1574 struct vnode *vp;
1575 struct stat sb;
1576 struct nameidata nd;
1577
1578 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1579 SCARG(uap, path), td);
1580 if ((error = namei(&nd)) != 0)
1581 return (error);
1582 vp = nd.ni_vp;
1583 error = vn_stat(vp, &sb, td->td_ucred, NOCRED, td);
1584 NDFREE(&nd, NDF_ONLY_PNBUF);
1585 vput(vp);
1586 if (error)
1587 return (error);
1588 error = copyout(&sb, SCARG(uap, ub), sizeof (sb));
1589 return (error);
1590}
1591
1592/*
1593 * Implementation of the NetBSD stat() function.
1594 * XXX This should probably be collapsed with the FreeBSD version,
1595 * as the differences are only due to vn_stat() clearing spares at
1596 * the end of the structures. vn_stat could be split to avoid this,
1597 * and thus collapse the following to close to zero code.
1598 */
1599void
1600cvtnstat(sb, nsb)
1601 struct stat *sb;
1602 struct nstat *nsb;
1603{
1604 bzero(nsb, sizeof *nsb);
1605 nsb->st_dev = sb->st_dev;
1606 nsb->st_ino = sb->st_ino;
1607 nsb->st_mode = sb->st_mode;
1608 nsb->st_nlink = sb->st_nlink;
1609 nsb->st_uid = sb->st_uid;
1610 nsb->st_gid = sb->st_gid;
1611 nsb->st_rdev = sb->st_rdev;
1612 nsb->st_atimespec = sb->st_atimespec;
1613 nsb->st_mtimespec = sb->st_mtimespec;
1614 nsb->st_ctimespec = sb->st_ctimespec;
1615 nsb->st_size = sb->st_size;
1616 nsb->st_blocks = sb->st_blocks;
1617 nsb->st_blksize = sb->st_blksize;
1618 nsb->st_flags = sb->st_flags;
1619 nsb->st_gen = sb->st_gen;
1620 nsb->st_birthtimespec = sb->st_birthtimespec;
1621}
1622
1623#ifndef _SYS_SYSPROTO_H_
1624struct nstat_args {
1625 char *path;
1626 struct nstat *ub;
1627};
1628#endif
1629/* ARGSUSED */
1630int
1631nstat(td, uap)
1632 struct thread *td;
1633 register struct nstat_args /* {
1634 syscallarg(char *) path;
1635 syscallarg(struct nstat *) ub;
1636 } */ *uap;
1637{
1638 struct stat sb;
1639 struct nstat nsb;
1640 int error;
1641 struct nameidata nd;
1642
1643 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1644 SCARG(uap, path), td);
1645 if ((error = namei(&nd)) != 0)
1646 return (error);
1647 NDFREE(&nd, NDF_ONLY_PNBUF);
1648 error = vn_stat(nd.ni_vp, &sb, td->td_ucred, NOCRED, td);
1649 vput(nd.ni_vp);
1650 if (error)
1651 return (error);
1652 cvtnstat(&sb, &nsb);
1653 error = copyout(&nsb, SCARG(uap, ub), sizeof (nsb));
1654 return (error);
1655}
1656
1657/*
1658 * NetBSD lstat. Get file status; this version does not follow links.
1659 */
1660#ifndef _SYS_SYSPROTO_H_
1661struct lstat_args {
1662 char *path;
1663 struct stat *ub;
1664};
1665#endif
1666/* ARGSUSED */
1667int
1668nlstat(td, uap)
1669 struct thread *td;
1670 register struct nlstat_args /* {
1671 syscallarg(char *) path;
1672 syscallarg(struct nstat *) ub;
1673 } */ *uap;
1674{
1675 int error;
1676 struct vnode *vp;
1677 struct stat sb;
1678 struct nstat nsb;
1679 struct nameidata nd;
1680
1681 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1682 SCARG(uap, path), td);
1683 if ((error = namei(&nd)) != 0)
1684 return (error);
1685 vp = nd.ni_vp;
1686 NDFREE(&nd, NDF_ONLY_PNBUF);
1687 error = vn_stat(vp, &sb, td->td_ucred, NOCRED, td);
1688 vput(vp);
1689 if (error)
1690 return (error);
1691 cvtnstat(&sb, &nsb);
1692 error = copyout(&nsb, SCARG(uap, ub), sizeof (nsb));
1693 return (error);
1694}
1695
1696/*
1697 * Get configurable pathname variables.
1698 */
1699#ifndef _SYS_SYSPROTO_H_
1700struct pathconf_args {
1701 char *path;
1702 int name;
1703};
1704#endif
1705/* ARGSUSED */
1706int
1707pathconf(td, uap)
1708 struct thread *td;
1709 register struct pathconf_args /* {
1710 syscallarg(char *) path;
1711 syscallarg(int) name;
1712 } */ *uap;
1713{
1714 int error;
1715 struct nameidata nd;
1716
1717 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1718 SCARG(uap, path), td);
1719 if ((error = namei(&nd)) != 0)
1720 return (error);
1721 NDFREE(&nd, NDF_ONLY_PNBUF);
1722 error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), td->td_retval);
1723 vput(nd.ni_vp);
1724 return (error);
1725}
1726
1727/*
1728 * Return target name of a symbolic link.
1729 */
1730#ifndef _SYS_SYSPROTO_H_
1731struct readlink_args {
1732 char *path;
1733 char *buf;
1734 int count;
1735};
1736#endif
1737/* ARGSUSED */
1738int
1739readlink(td, uap)
1740 struct thread *td;
1741 register struct readlink_args /* {
1742 syscallarg(char *) path;
1743 syscallarg(char *) buf;
1744 syscallarg(int) count;
1745 } */ *uap;
1746{
1747 register struct vnode *vp;
1748 struct iovec aiov;
1749 struct uio auio;
1750 int error;
1751 struct nameidata nd;
1752
1753 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1754 SCARG(uap, path), td);
1755 if ((error = namei(&nd)) != 0)
1756 return (error);
1757 NDFREE(&nd, NDF_ONLY_PNBUF);
1758 vp = nd.ni_vp;
1759#ifdef MAC
1760 error = mac_check_vnode_readlink(td->td_ucred, vp);
1761 if (error) {
1762 vput(vp);
1763 return (error);
1764 }
1765#endif
1766 if (vp->v_type != VLNK)
1767 error = EINVAL;
1768 else {
1769 aiov.iov_base = SCARG(uap, buf);
1770 aiov.iov_len = SCARG(uap, count);
1771 auio.uio_iov = &aiov;
1772 auio.uio_iovcnt = 1;
1773 auio.uio_offset = 0;
1774 auio.uio_rw = UIO_READ;
1775 auio.uio_segflg = UIO_USERSPACE;
1776 auio.uio_td = td;
1777 auio.uio_resid = SCARG(uap, count);
1778 error = VOP_READLINK(vp, &auio, td->td_ucred);
1779 }
1780 vput(vp);
1781 td->td_retval[0] = SCARG(uap, count) - auio.uio_resid;
1782 return (error);
1783}
1784
1785/*
1786 * Common implementation code for chflags() and fchflags().
1787 */
1788static int
1789setfflags(td, vp, flags)
1790 struct thread *td;
1791 struct vnode *vp;
1792 int flags;
1793{
1794 int error;
1795 struct mount *mp;
1796 struct vattr vattr;
1797
1798 /*
1799 * Prevent non-root users from setting flags on devices. When
1800 * a device is reused, users can retain ownership of the device
1801 * if they are allowed to set flags and programs assume that
1802 * chown can't fail when done as root.
1803 */
1804 if (vp->v_type == VCHR || vp->v_type == VBLK) {
1805 error = suser_cred(td->td_ucred, PRISON_ROOT);
1806 if (error)
1807 return (error);
1808 }
1809
1810 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
1811 return (error);
1812 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
1813 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
1814#ifdef MAC
1815 error = mac_check_vnode_setflags(td->td_ucred, vp, vattr.va_flags);
1816 if (error == 0) {
1817#endif
1818 VATTR_NULL(&vattr);
1819 vattr.va_flags = flags;
1820 error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
1821#ifdef MAC
1822 }
1823#endif
1824 VOP_UNLOCK(vp, 0, td);
1825 vn_finished_write(mp);
1826 return (error);
1827}
1828
1829/*
1830 * Change flags of a file given a path name.
1831 */
1832#ifndef _SYS_SYSPROTO_H_
1833struct chflags_args {
1834 char *path;
1835 int flags;
1836};
1837#endif
1838/* ARGSUSED */
1839int
1840chflags(td, uap)
1841 struct thread *td;
1842 register struct chflags_args /* {
1843 syscallarg(char *) path;
1844 syscallarg(int) flags;
1845 } */ *uap;
1846{
1847 int error;
1848 struct nameidata nd;
1849
1850 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
1851 if ((error = namei(&nd)) != 0)
1852 return (error);
1853 NDFREE(&nd, NDF_ONLY_PNBUF);
1854 error = setfflags(td, nd.ni_vp, SCARG(uap, flags));
1855 vrele(nd.ni_vp);
1856 return error;
1857}
1858
1859/*
1860 * Same as chflags() but doesn't follow symlinks.
1861 */
1862int
1863lchflags(td, uap)
1864 struct thread *td;
1865 register struct lchflags_args /* {
1866 syscallarg(char *) path;
1867 syscallarg(int) flags;
1868 } */ *uap;
1869{
1870 int error;
1871 struct nameidata nd;
1872
1873 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
1874 if ((error = namei(&nd)) != 0)
1875 return (error);
1876 NDFREE(&nd, NDF_ONLY_PNBUF);
1877 error = setfflags(td, nd.ni_vp, SCARG(uap, flags));
1878 vrele(nd.ni_vp);
1879 return error;
1880}
1881
1882/*
1883 * Change flags of a file given a file descriptor.
1884 */
1885#ifndef _SYS_SYSPROTO_H_
1886struct fchflags_args {
1887 int fd;
1888 int flags;
1889};
1890#endif
1891/* ARGSUSED */
1892int
1893fchflags(td, uap)
1894 struct thread *td;
1895 register struct fchflags_args /* {
1896 syscallarg(int) fd;
1897 syscallarg(int) flags;
1898 } */ *uap;
1899{
1900 struct file *fp;
1901 int error;
1902
1903 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
1904 return (error);
1905 error = setfflags(td, (struct vnode *) fp->f_data, SCARG(uap, flags));
1906 fdrop(fp, td);
1907 return (error);
1908}
1909
1910/*
1911 * Common implementation code for chmod(), lchmod() and fchmod().
1912 */
1913static int
1914setfmode(td, vp, mode)
1915 struct thread *td;
1916 struct vnode *vp;
1917 int mode;
1918{
1919 int error;
1920 struct mount *mp;
1921 struct vattr vattr;
1922
1923 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
1924 return (error);
1925 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
1926 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
1927 VATTR_NULL(&vattr);
1928 vattr.va_mode = mode & ALLPERMS;
1929#ifdef MAC
1930 error = mac_check_vnode_setmode(td->td_ucred, vp, vattr.va_mode);
1931 if (error == 0)
1932#endif
1933 error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
1934 VOP_UNLOCK(vp, 0, td);
1935 vn_finished_write(mp);
1936 return error;
1937}
1938
1939/*
1940 * Change mode of a file given path name.
1941 */
1942#ifndef _SYS_SYSPROTO_H_
1943struct chmod_args {
1944 char *path;
1945 int mode;
1946};
1947#endif
1948/* ARGSUSED */
1949int
1950chmod(td, uap)
1951 struct thread *td;
1952 register struct chmod_args /* {
1953 syscallarg(char *) path;
1954 syscallarg(int) mode;
1955 } */ *uap;
1956{
1957 int error;
1958 struct nameidata nd;
1959
1960 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
1961 if ((error = namei(&nd)) != 0)
1962 return (error);
1963 NDFREE(&nd, NDF_ONLY_PNBUF);
1964 error = setfmode(td, nd.ni_vp, SCARG(uap, mode));
1965 vrele(nd.ni_vp);
1966 return error;
1967}
1968
1969/*
1970 * Change mode of a file given path name (don't follow links.)
1971 */
1972#ifndef _SYS_SYSPROTO_H_
1973struct lchmod_args {
1974 char *path;
1975 int mode;
1976};
1977#endif
1978/* ARGSUSED */
1979int
1980lchmod(td, uap)
1981 struct thread *td;
1982 register struct lchmod_args /* {
1983 syscallarg(char *) path;
1984 syscallarg(int) mode;
1985 } */ *uap;
1986{
1987 int error;
1988 struct nameidata nd;
1989
1990 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
1991 if ((error = namei(&nd)) != 0)
1992 return (error);
1993 NDFREE(&nd, NDF_ONLY_PNBUF);
1994 error = setfmode(td, nd.ni_vp, SCARG(uap, mode));
1995 vrele(nd.ni_vp);
1996 return error;
1997}
1998
1999/*
2000 * Change mode of a file given a file descriptor.
2001 */
2002#ifndef _SYS_SYSPROTO_H_
2003struct fchmod_args {
2004 int fd;
2005 int mode;
2006};
2007#endif
2008/* ARGSUSED */
2009int
2010fchmod(td, uap)
2011 struct thread *td;
2012 register struct fchmod_args /* {
2013 syscallarg(int) fd;
2014 syscallarg(int) mode;
2015 } */ *uap;
2016{
2017 struct file *fp;
2018 struct vnode *vp;
2019 int error;
2020
2021 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
2022 return (error);
2023 vp = (struct vnode *)fp->f_data;
2024 error = setfmode(td, (struct vnode *)fp->f_data, SCARG(uap, mode));
2025 fdrop(fp, td);
2026 return (error);
2027}
2028
2029/*
2030 * Common implementation for chown(), lchown(), and fchown()
2031 */
2032static int
2033setfown(td, vp, uid, gid)
2034 struct thread *td;
2035 struct vnode *vp;
2036 uid_t uid;
2037 gid_t gid;
2038{
2039 int error;
2040 struct mount *mp;
2041 struct vattr vattr;
2042
2043 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
2044 return (error);
2045 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
2046 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2047 VATTR_NULL(&vattr);
2048 vattr.va_uid = uid;
2049 vattr.va_gid = gid;
2050#ifdef MAC
2051 error = mac_check_vnode_setowner(td->td_ucred, vp, vattr.va_uid,
2052 vattr.va_gid);
2053 if (error == 0)
2054#endif
2055 error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
2056 VOP_UNLOCK(vp, 0, td);
2057 vn_finished_write(mp);
2058 return error;
2059}
2060
2061/*
2062 * Set ownership given a path name.
2063 */
2064#ifndef _SYS_SYSPROTO_H_
2065struct chown_args {
2066 char *path;
2067 int uid;
2068 int gid;
2069};
2070#endif
2071/* ARGSUSED */
2072int
2073chown(td, uap)
2074 struct thread *td;
2075 register struct chown_args /* {
2076 syscallarg(char *) path;
2077 syscallarg(int) uid;
2078 syscallarg(int) gid;
2079 } */ *uap;
2080{
2081 int error;
2082 struct nameidata nd;
2083
2084 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2085 if ((error = namei(&nd)) != 0)
2086 return (error);
2087 NDFREE(&nd, NDF_ONLY_PNBUF);
2088 error = setfown(td, nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid));
2089 vrele(nd.ni_vp);
2090 return (error);
2091}
2092
2093/*
2094 * Set ownership given a path name, do not cross symlinks.
2095 */
2096#ifndef _SYS_SYSPROTO_H_
2097struct lchown_args {
2098 char *path;
2099 int uid;
2100 int gid;
2101};
2102#endif
2103/* ARGSUSED */
2104int
2105lchown(td, uap)
2106 struct thread *td;
2107 register struct lchown_args /* {
2108 syscallarg(char *) path;
2109 syscallarg(int) uid;
2110 syscallarg(int) gid;
2111 } */ *uap;
2112{
2113 int error;
2114 struct nameidata nd;
2115
2116 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2117 if ((error = namei(&nd)) != 0)
2118 return (error);
2119 NDFREE(&nd, NDF_ONLY_PNBUF);
2120 error = setfown(td, nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid));
2121 vrele(nd.ni_vp);
2122 return (error);
2123}
2124
2125/*
2126 * Set ownership given a file descriptor.
2127 */
2128#ifndef _SYS_SYSPROTO_H_
2129struct fchown_args {
2130 int fd;
2131 int uid;
2132 int gid;
2133};
2134#endif
2135/* ARGSUSED */
2136int
2137fchown(td, uap)
2138 struct thread *td;
2139 register struct fchown_args /* {
2140 syscallarg(int) fd;
2141 syscallarg(int) uid;
2142 syscallarg(int) gid;
2143 } */ *uap;
2144{
2145 struct file *fp;
2146 struct vnode *vp;
2147 int error;
2148
2149 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
2150 return (error);
2151 vp = (struct vnode *)fp->f_data;
2152 error = setfown(td, (struct vnode *)fp->f_data,
2153 SCARG(uap, uid), SCARG(uap, gid));
2154 fdrop(fp, td);
2155 return (error);
2156}
2157
2158/*
2159 * Common implementation code for utimes(), lutimes(), and futimes().
2160 */
2161static int
2162getutimes(usrtvp, tsp)
2163 const struct timeval *usrtvp;
2164 struct timespec *tsp;
2165{
2166 struct timeval tv[2];
2167 int error;
2168
2169 if (usrtvp == NULL) {
2170 microtime(&tv[0]);
2171 TIMEVAL_TO_TIMESPEC(&tv[0], &tsp[0]);
2172 tsp[1] = tsp[0];
2173 } else {
2174 if ((error = copyin(usrtvp, tv, sizeof (tv))) != 0)
2175 return (error);
2176 TIMEVAL_TO_TIMESPEC(&tv[0], &tsp[0]);
2177 TIMEVAL_TO_TIMESPEC(&tv[1], &tsp[1]);
2178 }
2179 return 0;
2180}
2181
2182/*
2183 * Common implementation code for utimes(), lutimes(), and futimes().
2184 */
2185static int
2186setutimes(td, vp, ts, numtimes, nullflag)
2187 struct thread *td;
2188 struct vnode *vp;
2189 const struct timespec *ts;
2190 int numtimes;
2191 int nullflag;
2192{
2193 int error, setbirthtime;
2194 struct mount *mp;
2195 struct vattr vattr;
2196
2197 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
2198 return (error);
2199 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
2200 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2201 setbirthtime = 0;
2202 if (numtimes < 3 && VOP_GETATTR(vp, &vattr, td->td_ucred, td) == 0 &&
2203 timespeccmp(&ts[1], &vattr.va_birthtime, < ))
2204 setbirthtime = 1;
2205 VATTR_NULL(&vattr);
2206 vattr.va_atime = ts[0];
2207 vattr.va_mtime = ts[1];
2208 if (setbirthtime)
2209 vattr.va_birthtime = ts[1];
2210 if (numtimes > 2)
2211 vattr.va_birthtime = ts[2];
2212 if (nullflag)
2213 vattr.va_vaflags |= VA_UTIMES_NULL;
2214#ifdef MAC
2215 error = mac_check_vnode_setutimes(td->td_ucred, vp, vattr.va_atime,
2216 vattr.va_mtime);
2217 if (error == 0)
2218#endif
2219 error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
2220 VOP_UNLOCK(vp, 0, td);
2221 vn_finished_write(mp);
2222 return error;
2223}
2224
2225/*
2226 * Set the access and modification times of a file.
2227 */
2228#ifndef _SYS_SYSPROTO_H_
2229struct utimes_args {
2230 char *path;
2231 struct timeval *tptr;
2232};
2233#endif
2234/* ARGSUSED */
2235int
2236utimes(td, uap)
2237 struct thread *td;
2238 register struct utimes_args /* {
2239 syscallarg(char *) path;
2240 syscallarg(struct timeval *) tptr;
2241 } */ *uap;
2242{
2243 struct timespec ts[2];
2244 struct timeval *usrtvp;
2245 int error;
2246 struct nameidata nd;
2247
2248 usrtvp = SCARG(uap, tptr);
2249 if ((error = getutimes(usrtvp, ts)) != 0)
2250 return (error);
2251 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2252 if ((error = namei(&nd)) != 0)
2253 return (error);
2254 NDFREE(&nd, NDF_ONLY_PNBUF);
2255 error = setutimes(td, nd.ni_vp, ts, 2, usrtvp == NULL);
2256 vrele(nd.ni_vp);
2257 return (error);
2258}
2259
2260/*
2261 * Set the access and modification times of a file.
2262 */
2263#ifndef _SYS_SYSPROTO_H_
2264struct lutimes_args {
2265 char *path;
2266 struct timeval *tptr;
2267};
2268#endif
2269/* ARGSUSED */
2270int
2271lutimes(td, uap)
2272 struct thread *td;
2273 register struct lutimes_args /* {
2274 syscallarg(char *) path;
2275 syscallarg(struct timeval *) tptr;
2276 } */ *uap;
2277{
2278 struct timespec ts[2];
2279 struct timeval *usrtvp;
2280 int error;
2281 struct nameidata nd;
2282
2283 usrtvp = SCARG(uap, tptr);
2284 if ((error = getutimes(usrtvp, ts)) != 0)
2285 return (error);
2286 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2287 if ((error = namei(&nd)) != 0)
2288 return (error);
2289 NDFREE(&nd, NDF_ONLY_PNBUF);
2290 error = setutimes(td, nd.ni_vp, ts, 2, usrtvp == NULL);
2291 vrele(nd.ni_vp);
2292 return (error);
2293}
2294
2295/*
2296 * Set the access and modification times of a file.
2297 */
2298#ifndef _SYS_SYSPROTO_H_
2299struct futimes_args {
2300 int fd;
2301 struct timeval *tptr;
2302};
2303#endif
2304/* ARGSUSED */
2305int
2306futimes(td, uap)
2307 struct thread *td;
2308 register struct futimes_args /* {
2309 syscallarg(int ) fd;
2310 syscallarg(struct timeval *) tptr;
2311 } */ *uap;
2312{
2313 struct timespec ts[2];
2314 struct file *fp;
2315 struct timeval *usrtvp;
2316 int error;
2317
2318 usrtvp = SCARG(uap, tptr);
2319 if ((error = getutimes(usrtvp, ts)) != 0)
2320 return (error);
2321 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
2322 return (error);
2323 error = setutimes(td, (struct vnode *)fp->f_data, ts, 2, usrtvp==NULL);
2324 fdrop(fp, td);
2325 return (error);
2326}
2327
2328/*
2329 * Truncate a file given its path name.
2330 */
2331#ifndef _SYS_SYSPROTO_H_
2332struct truncate_args {
2333 char *path;
2334 int pad;
2335 off_t length;
2336};
2337#endif
2338/* ARGSUSED */
2339int
2340truncate(td, uap)
2341 struct thread *td;
2342 register struct truncate_args /* {
2343 syscallarg(char *) path;
2344 syscallarg(int) pad;
2345 syscallarg(off_t) length;
2346 } */ *uap;
2347{
2348 struct mount *mp;
2349 struct vnode *vp;
2350 struct vattr vattr;
2351 int error;
2352 struct nameidata nd;
2353
2354 if (uap->length < 0)
2355 return(EINVAL);
2356 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2357 if ((error = namei(&nd)) != 0)
2358 return (error);
2359 vp = nd.ni_vp;
2360 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) {
2361 vrele(vp);
2362 return (error);
2363 }
2364 NDFREE(&nd, NDF_ONLY_PNBUF);
2365 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
2366 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2367 if (vp->v_type == VDIR)
2368 error = EISDIR;
2369#ifdef MAC
2371 else if ((error = mac_check_vnode_op(td->td_ucred, vp,
2372 MAC_OP_VNODE_WRITE))) {}
2370 else if ((error = mac_check_vnode_write(td->td_ucred, vp))) {}
2373#endif
2374 else if ((error = vn_writechk(vp)) == 0 &&
2375 (error = VOP_ACCESS(vp, VWRITE, td->td_ucred, td)) == 0) {
2376 VATTR_NULL(&vattr);
2377 vattr.va_size = SCARG(uap, length);
2378 error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
2379 }
2380 vput(vp);
2381 vn_finished_write(mp);
2382 return (error);
2383}
2384
2385/*
2386 * Truncate a file given a file descriptor.
2387 */
2388#ifndef _SYS_SYSPROTO_H_
2389struct ftruncate_args {
2390 int fd;
2391 int pad;
2392 off_t length;
2393};
2394#endif
2395/* ARGSUSED */
2396int
2397ftruncate(td, uap)
2398 struct thread *td;
2399 register struct ftruncate_args /* {
2400 syscallarg(int) fd;
2401 syscallarg(int) pad;
2402 syscallarg(off_t) length;
2403 } */ *uap;
2404{
2405 struct mount *mp;
2406 struct vattr vattr;
2407 struct vnode *vp;
2408 struct file *fp;
2409 int error;
2410
2411 if (uap->length < 0)
2412 return(EINVAL);
2413 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
2414 return (error);
2415 if ((fp->f_flag & FWRITE) == 0) {
2416 fdrop(fp, td);
2417 return (EINVAL);
2418 }
2419 vp = (struct vnode *)fp->f_data;
2420 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) {
2421 fdrop(fp, td);
2422 return (error);
2423 }
2424 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
2425 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2426 if (vp->v_type == VDIR)
2427 error = EISDIR;
2428#ifdef MAC
2371#endif
2372 else if ((error = vn_writechk(vp)) == 0 &&
2373 (error = VOP_ACCESS(vp, VWRITE, td->td_ucred, td)) == 0) {
2374 VATTR_NULL(&vattr);
2375 vattr.va_size = SCARG(uap, length);
2376 error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
2377 }
2378 vput(vp);
2379 vn_finished_write(mp);
2380 return (error);
2381}
2382
2383/*
2384 * Truncate a file given a file descriptor.
2385 */
2386#ifndef _SYS_SYSPROTO_H_
2387struct ftruncate_args {
2388 int fd;
2389 int pad;
2390 off_t length;
2391};
2392#endif
2393/* ARGSUSED */
2394int
2395ftruncate(td, uap)
2396 struct thread *td;
2397 register struct ftruncate_args /* {
2398 syscallarg(int) fd;
2399 syscallarg(int) pad;
2400 syscallarg(off_t) length;
2401 } */ *uap;
2402{
2403 struct mount *mp;
2404 struct vattr vattr;
2405 struct vnode *vp;
2406 struct file *fp;
2407 int error;
2408
2409 if (uap->length < 0)
2410 return(EINVAL);
2411 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
2412 return (error);
2413 if ((fp->f_flag & FWRITE) == 0) {
2414 fdrop(fp, td);
2415 return (EINVAL);
2416 }
2417 vp = (struct vnode *)fp->f_data;
2418 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) {
2419 fdrop(fp, td);
2420 return (error);
2421 }
2422 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
2423 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2424 if (vp->v_type == VDIR)
2425 error = EISDIR;
2426#ifdef MAC
2429 else if ((error = mac_check_vnode_op(td->td_ucred, vp,
2430 MAC_OP_VNODE_WRITE))) {}
2427 else if ((error = mac_check_vnode_write(td->td_ucred, vp))) {}
2431#endif
2432 else if ((error = vn_writechk(vp)) == 0) {
2433 VATTR_NULL(&vattr);
2434 vattr.va_size = SCARG(uap, length);
2435 error = VOP_SETATTR(vp, &vattr, fp->f_cred, td);
2436 }
2437 VOP_UNLOCK(vp, 0, td);
2438 vn_finished_write(mp);
2439 fdrop(fp, td);
2440 return (error);
2441}
2442
2443#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
2444/*
2445 * Truncate a file given its path name.
2446 */
2447#ifndef _SYS_SYSPROTO_H_
2448struct otruncate_args {
2449 char *path;
2450 long length;
2451};
2452#endif
2453/* ARGSUSED */
2454int
2455otruncate(td, uap)
2456 struct thread *td;
2457 register struct otruncate_args /* {
2458 syscallarg(char *) path;
2459 syscallarg(long) length;
2460 } */ *uap;
2461{
2462 struct truncate_args /* {
2463 syscallarg(char *) path;
2464 syscallarg(int) pad;
2465 syscallarg(off_t) length;
2466 } */ nuap;
2467
2468 SCARG(&nuap, path) = SCARG(uap, path);
2469 SCARG(&nuap, length) = SCARG(uap, length);
2470 return (truncate(td, &nuap));
2471}
2472
2473/*
2474 * Truncate a file given a file descriptor.
2475 */
2476#ifndef _SYS_SYSPROTO_H_
2477struct oftruncate_args {
2478 int fd;
2479 long length;
2480};
2481#endif
2482/* ARGSUSED */
2483int
2484oftruncate(td, uap)
2485 struct thread *td;
2486 register struct oftruncate_args /* {
2487 syscallarg(int) fd;
2488 syscallarg(long) length;
2489 } */ *uap;
2490{
2491 struct ftruncate_args /* {
2492 syscallarg(int) fd;
2493 syscallarg(int) pad;
2494 syscallarg(off_t) length;
2495 } */ nuap;
2496
2497 SCARG(&nuap, fd) = SCARG(uap, fd);
2498 SCARG(&nuap, length) = SCARG(uap, length);
2499 return (ftruncate(td, &nuap));
2500}
2501#endif /* COMPAT_43 || COMPAT_SUNOS */
2502
2503/*
2504 * Sync an open file.
2505 */
2506#ifndef _SYS_SYSPROTO_H_
2507struct fsync_args {
2508 int fd;
2509};
2510#endif
2511/* ARGSUSED */
2512int
2513fsync(td, uap)
2514 struct thread *td;
2515 struct fsync_args /* {
2516 syscallarg(int) fd;
2517 } */ *uap;
2518{
2519 struct vnode *vp;
2520 struct mount *mp;
2521 struct file *fp;
2522 vm_object_t obj;
2523 int error;
2524
2525 GIANT_REQUIRED;
2526
2527 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
2528 return (error);
2529 vp = (struct vnode *)fp->f_data;
2530 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) {
2531 fdrop(fp, td);
2532 return (error);
2533 }
2534 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2535 if (VOP_GETVOBJECT(vp, &obj) == 0) {
2536 vm_object_page_clean(obj, 0, 0, 0);
2537 }
2538 error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, td);
2539 if (error == 0 && vp->v_mount && (vp->v_mount->mnt_flag & MNT_SOFTDEP)
2540 && softdep_fsync_hook != NULL)
2541 error = (*softdep_fsync_hook)(vp);
2542
2543 VOP_UNLOCK(vp, 0, td);
2544 vn_finished_write(mp);
2545 fdrop(fp, td);
2546 return (error);
2547}
2548
2549/*
2550 * Rename files. Source and destination must either both be directories,
2551 * or both not be directories. If target is a directory, it must be empty.
2552 */
2553#ifndef _SYS_SYSPROTO_H_
2554struct rename_args {
2555 char *from;
2556 char *to;
2557};
2558#endif
2559/* ARGSUSED */
2560int
2561rename(td, uap)
2562 struct thread *td;
2563 register struct rename_args /* {
2564 syscallarg(char *) from;
2565 syscallarg(char *) to;
2566 } */ *uap;
2567{
2568 struct mount *mp;
2569 struct vnode *tvp, *fvp, *tdvp;
2570 struct nameidata fromnd, tond;
2571 int error;
2572
2573 bwillwrite();
2574 NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
2575 SCARG(uap, from), td);
2576 if ((error = namei(&fromnd)) != 0)
2577 return (error);
2578 fvp = fromnd.ni_vp;
2579 if ((error = vn_start_write(fvp, &mp, V_WAIT | PCATCH)) != 0) {
2580 NDFREE(&fromnd, NDF_ONLY_PNBUF);
2581 vrele(fromnd.ni_dvp);
2582 vrele(fvp);
2583 goto out1;
2584 }
2585 NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART | NOOBJ,
2586 UIO_USERSPACE, SCARG(uap, to), td);
2587 if (fromnd.ni_vp->v_type == VDIR)
2588 tond.ni_cnd.cn_flags |= WILLBEDIR;
2589 if ((error = namei(&tond)) != 0) {
2590 /* Translate error code for rename("dir1", "dir2/."). */
2591 if (error == EISDIR && fvp->v_type == VDIR)
2592 error = EINVAL;
2593 NDFREE(&fromnd, NDF_ONLY_PNBUF);
2594 vrele(fromnd.ni_dvp);
2595 vrele(fvp);
2596 goto out1;
2597 }
2598 tdvp = tond.ni_dvp;
2599 tvp = tond.ni_vp;
2600 if (tvp != NULL) {
2601 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
2602 error = ENOTDIR;
2603 goto out;
2604 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
2605 error = EISDIR;
2606 goto out;
2607 }
2608 }
2609 if (fvp == tdvp)
2610 error = EINVAL;
2611 /*
2612 * If source is the same as the destination (that is the
2613 * same inode number with the same name in the same directory),
2614 * then there is nothing to do.
2615 */
2616 if (fvp == tvp && fromnd.ni_dvp == tdvp &&
2617 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
2618 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
2619 fromnd.ni_cnd.cn_namelen))
2620 error = -1;
2621out:
2622 if (!error) {
2623 VOP_LEASE(tdvp, td, td->td_ucred, LEASE_WRITE);
2624 if (fromnd.ni_dvp != tdvp) {
2625 VOP_LEASE(fromnd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
2626 }
2627 if (tvp) {
2628 VOP_LEASE(tvp, td, td->td_ucred, LEASE_WRITE);
2629 }
2630 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
2631 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
2632 NDFREE(&fromnd, NDF_ONLY_PNBUF);
2633 NDFREE(&tond, NDF_ONLY_PNBUF);
2634 } else {
2635 NDFREE(&fromnd, NDF_ONLY_PNBUF);
2636 NDFREE(&tond, NDF_ONLY_PNBUF);
2637 if (tdvp == tvp)
2638 vrele(tdvp);
2639 else
2640 vput(tdvp);
2641 if (tvp)
2642 vput(tvp);
2643 vrele(fromnd.ni_dvp);
2644 vrele(fvp);
2645 }
2646 vrele(tond.ni_startdir);
2647 vn_finished_write(mp);
2648 ASSERT_VOP_UNLOCKED(fromnd.ni_dvp, "rename");
2649 ASSERT_VOP_UNLOCKED(fromnd.ni_vp, "rename");
2650 ASSERT_VOP_UNLOCKED(tond.ni_dvp, "rename");
2651 ASSERT_VOP_UNLOCKED(tond.ni_vp, "rename");
2652out1:
2653 if (fromnd.ni_startdir)
2654 vrele(fromnd.ni_startdir);
2655 if (error == -1)
2656 return (0);
2657 return (error);
2658}
2659
2660/*
2661 * Make a directory file.
2662 */
2663#ifndef _SYS_SYSPROTO_H_
2664struct mkdir_args {
2665 char *path;
2666 int mode;
2667};
2668#endif
2669/* ARGSUSED */
2670int
2671mkdir(td, uap)
2672 struct thread *td;
2673 register struct mkdir_args /* {
2674 syscallarg(char *) path;
2675 syscallarg(int) mode;
2676 } */ *uap;
2677{
2678
2679 return vn_mkdir(uap->path, uap->mode, UIO_USERSPACE, td);
2680}
2681
2682int
2683vn_mkdir(path, mode, segflg, td)
2684 char *path;
2685 int mode;
2686 enum uio_seg segflg;
2687 struct thread *td;
2688{
2689 struct mount *mp;
2690 struct vnode *vp;
2691 struct vattr vattr;
2692 int error;
2693 struct nameidata nd;
2694
2695restart:
2696 bwillwrite();
2697 NDINIT(&nd, CREATE, LOCKPARENT | SAVENAME, segflg, path, td);
2698 nd.ni_cnd.cn_flags |= WILLBEDIR;
2699 if ((error = namei(&nd)) != 0)
2700 return (error);
2701 vp = nd.ni_vp;
2702 if (vp != NULL) {
2703 NDFREE(&nd, NDF_ONLY_PNBUF);
2704 vrele(vp);
2705 /*
2706 * XXX namei called with LOCKPARENT but not LOCKLEAF has
2707 * the strange behaviour of leaving the vnode unlocked
2708 * if the target is the same vnode as the parent.
2709 */
2710 if (vp == nd.ni_dvp)
2711 vrele(nd.ni_dvp);
2712 else
2713 vput(nd.ni_dvp);
2714 return (EEXIST);
2715 }
2716 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
2717 NDFREE(&nd, NDF_ONLY_PNBUF);
2718 vput(nd.ni_dvp);
2719 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
2720 return (error);
2721 goto restart;
2722 }
2723 VATTR_NULL(&vattr);
2724 vattr.va_type = VDIR;
2725 FILEDESC_LOCK(td->td_proc->p_fd);
2726 vattr.va_mode = (mode & ACCESSPERMS) &~ td->td_proc->p_fd->fd_cmask;
2727 FILEDESC_UNLOCK(td->td_proc->p_fd);
2728 VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
2729 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
2730 NDFREE(&nd, NDF_ONLY_PNBUF);
2731 vput(nd.ni_dvp);
2732 if (!error)
2733 vput(nd.ni_vp);
2734 vn_finished_write(mp);
2735 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mkdir");
2736 ASSERT_VOP_UNLOCKED(nd.ni_vp, "mkdir");
2737 return (error);
2738}
2739
2740/*
2741 * Remove a directory file.
2742 */
2743#ifndef _SYS_SYSPROTO_H_
2744struct rmdir_args {
2745 char *path;
2746};
2747#endif
2748/* ARGSUSED */
2749int
2750rmdir(td, uap)
2751 struct thread *td;
2752 struct rmdir_args /* {
2753 syscallarg(char *) path;
2754 } */ *uap;
2755{
2756 struct mount *mp;
2757 struct vnode *vp;
2758 int error;
2759 struct nameidata nd;
2760
2761restart:
2762 bwillwrite();
2763 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
2764 SCARG(uap, path), td);
2765 if ((error = namei(&nd)) != 0)
2766 return (error);
2767 vp = nd.ni_vp;
2768 if (vp->v_type != VDIR) {
2769 error = ENOTDIR;
2770 goto out;
2771 }
2772 /*
2773 * No rmdir "." please.
2774 */
2775 if (nd.ni_dvp == vp) {
2776 error = EINVAL;
2777 goto out;
2778 }
2779 /*
2780 * The root of a mounted filesystem cannot be deleted.
2781 */
2782 if (vp->v_vflag & VV_ROOT) {
2783 error = EBUSY;
2784 goto out;
2785 }
2786 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
2787 NDFREE(&nd, NDF_ONLY_PNBUF);
2788 if (nd.ni_dvp == vp)
2789 vrele(nd.ni_dvp);
2790 else
2791 vput(nd.ni_dvp);
2792 vput(vp);
2793 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
2794 return (error);
2795 goto restart;
2796 }
2797 VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
2798 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
2799 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
2800 vn_finished_write(mp);
2801out:
2802 NDFREE(&nd, NDF_ONLY_PNBUF);
2803 if (nd.ni_dvp == vp)
2804 vrele(nd.ni_dvp);
2805 else
2806 vput(nd.ni_dvp);
2807 vput(vp);
2808 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "rmdir");
2809 ASSERT_VOP_UNLOCKED(nd.ni_vp, "rmdir");
2810 return (error);
2811}
2812
2813#ifdef COMPAT_43
2814/*
2815 * Read a block of directory entries in a filesystem independent format.
2816 */
2817#ifndef _SYS_SYSPROTO_H_
2818struct ogetdirentries_args {
2819 int fd;
2820 char *buf;
2821 u_int count;
2822 long *basep;
2823};
2824#endif
2825int
2826ogetdirentries(td, uap)
2827 struct thread *td;
2828 register struct ogetdirentries_args /* {
2829 syscallarg(int) fd;
2830 syscallarg(char *) buf;
2831 syscallarg(u_int) count;
2832 syscallarg(long *) basep;
2833 } */ *uap;
2834{
2835 struct vnode *vp;
2836 struct file *fp;
2837 struct uio auio, kuio;
2838 struct iovec aiov, kiov;
2839 struct dirent *dp, *edp;
2840 caddr_t dirbuf;
2841 int error, eofflag, readcnt;
2842 long loff;
2843
2844 /* XXX arbitrary sanity limit on `count'. */
2845 if (SCARG(uap, count) > 64 * 1024)
2846 return (EINVAL);
2847 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
2848 return (error);
2849 if ((fp->f_flag & FREAD) == 0) {
2850 fdrop(fp, td);
2851 return (EBADF);
2852 }
2853 vp = (struct vnode *)fp->f_data;
2854unionread:
2855 if (vp->v_type != VDIR) {
2856 fdrop(fp, td);
2857 return (EINVAL);
2858 }
2859 aiov.iov_base = SCARG(uap, buf);
2860 aiov.iov_len = SCARG(uap, count);
2861 auio.uio_iov = &aiov;
2862 auio.uio_iovcnt = 1;
2863 auio.uio_rw = UIO_READ;
2864 auio.uio_segflg = UIO_USERSPACE;
2865 auio.uio_td = td;
2866 auio.uio_resid = SCARG(uap, count);
2867 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2868 loff = auio.uio_offset = fp->f_offset;
2869#ifdef MAC
2870 error = mac_check_vnode_readdir(td->td_ucred, vp);
2871 if (error) {
2872 VOP_UNLOCK(vp, 0, td);
2873 fdrop(fp, td);
2874 return (error);
2875 }
2876#endif
2877# if (BYTE_ORDER != LITTLE_ENDIAN)
2878 if (vp->v_mount->mnt_maxsymlinklen <= 0) {
2879 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
2880 NULL, NULL);
2881 fp->f_offset = auio.uio_offset;
2882 } else
2883# endif
2884 {
2885 kuio = auio;
2886 kuio.uio_iov = &kiov;
2887 kuio.uio_segflg = UIO_SYSSPACE;
2888 kiov.iov_len = SCARG(uap, count);
2889 MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK);
2890 kiov.iov_base = dirbuf;
2891 error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
2892 NULL, NULL);
2893 fp->f_offset = kuio.uio_offset;
2894 if (error == 0) {
2895 readcnt = SCARG(uap, count) - kuio.uio_resid;
2896 edp = (struct dirent *)&dirbuf[readcnt];
2897 for (dp = (struct dirent *)dirbuf; dp < edp; ) {
2898# if (BYTE_ORDER == LITTLE_ENDIAN)
2899 /*
2900 * The expected low byte of
2901 * dp->d_namlen is our dp->d_type.
2902 * The high MBZ byte of dp->d_namlen
2903 * is our dp->d_namlen.
2904 */
2905 dp->d_type = dp->d_namlen;
2906 dp->d_namlen = 0;
2907# else
2908 /*
2909 * The dp->d_type is the high byte
2910 * of the expected dp->d_namlen,
2911 * so must be zero'ed.
2912 */
2913 dp->d_type = 0;
2914# endif
2915 if (dp->d_reclen > 0) {
2916 dp = (struct dirent *)
2917 ((char *)dp + dp->d_reclen);
2918 } else {
2919 error = EIO;
2920 break;
2921 }
2922 }
2923 if (dp >= edp)
2924 error = uiomove(dirbuf, readcnt, &auio);
2925 }
2926 FREE(dirbuf, M_TEMP);
2927 }
2928 VOP_UNLOCK(vp, 0, td);
2929 if (error) {
2930 fdrop(fp, td);
2931 return (error);
2932 }
2933 if (SCARG(uap, count) == auio.uio_resid) {
2934 if (union_dircheckp) {
2935 error = union_dircheckp(td, &vp, fp);
2936 if (error == -1)
2937 goto unionread;
2938 if (error) {
2939 fdrop(fp, td);
2940 return (error);
2941 }
2942 }
2943 mp_fixme("Accessing vflags w/o vn lock.");
2944 if ((vp->v_vflag & VV_ROOT) &&
2945 (vp->v_mount->mnt_flag & MNT_UNION)) {
2946 struct vnode *tvp = vp;
2947 vp = vp->v_mount->mnt_vnodecovered;
2948 VREF(vp);
2949 fp->f_data = vp;
2950 fp->f_offset = 0;
2951 vrele(tvp);
2952 goto unionread;
2953 }
2954 }
2955 error = copyout(&loff, SCARG(uap, basep), sizeof(long));
2956 fdrop(fp, td);
2957 td->td_retval[0] = SCARG(uap, count) - auio.uio_resid;
2958 return (error);
2959}
2960#endif /* COMPAT_43 */
2961
2962/*
2963 * Read a block of directory entries in a filesystem independent format.
2964 */
2965#ifndef _SYS_SYSPROTO_H_
2966struct getdirentries_args {
2967 int fd;
2968 char *buf;
2969 u_int count;
2970 long *basep;
2971};
2972#endif
2973int
2974getdirentries(td, uap)
2975 struct thread *td;
2976 register struct getdirentries_args /* {
2977 syscallarg(int) fd;
2978 syscallarg(char *) buf;
2979 syscallarg(u_int) count;
2980 syscallarg(long *) basep;
2981 } */ *uap;
2982{
2983 struct vnode *vp;
2984 struct file *fp;
2985 struct uio auio;
2986 struct iovec aiov;
2987 long loff;
2988 int error, eofflag;
2989
2990 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
2991 return (error);
2992 if ((fp->f_flag & FREAD) == 0) {
2993 fdrop(fp, td);
2994 return (EBADF);
2995 }
2996 vp = (struct vnode *)fp->f_data;
2997unionread:
2998 if (vp->v_type != VDIR) {
2999 fdrop(fp, td);
3000 return (EINVAL);
3001 }
3002 aiov.iov_base = SCARG(uap, buf);
3003 aiov.iov_len = SCARG(uap, count);
3004 auio.uio_iov = &aiov;
3005 auio.uio_iovcnt = 1;
3006 auio.uio_rw = UIO_READ;
3007 auio.uio_segflg = UIO_USERSPACE;
3008 auio.uio_td = td;
3009 auio.uio_resid = SCARG(uap, count);
3010 /* vn_lock(vp, LK_SHARED | LK_RETRY, td); */
3011 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
3012 loff = auio.uio_offset = fp->f_offset;
3013#ifdef MAC
3014 error = mac_check_vnode_readdir(td->td_ucred, vp);
3015 if (error == 0)
3016#endif
3017 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, NULL,
3018 NULL);
3019 fp->f_offset = auio.uio_offset;
3020 VOP_UNLOCK(vp, 0, td);
3021 if (error) {
3022 fdrop(fp, td);
3023 return (error);
3024 }
3025 if (SCARG(uap, count) == auio.uio_resid) {
3026 if (union_dircheckp) {
3027 error = union_dircheckp(td, &vp, fp);
3028 if (error == -1)
3029 goto unionread;
3030 if (error) {
3031 fdrop(fp, td);
3032 return (error);
3033 }
3034 }
3035 mp_fixme("Accessing vflag without vn lock.");
3036 if ((vp->v_vflag & VV_ROOT) &&
3037 (vp->v_mount->mnt_flag & MNT_UNION)) {
3038 struct vnode *tvp = vp;
3039 vp = vp->v_mount->mnt_vnodecovered;
3040 VREF(vp);
3041 fp->f_data = vp;
3042 fp->f_offset = 0;
3043 vrele(tvp);
3044 goto unionread;
3045 }
3046 }
3047 if (SCARG(uap, basep) != NULL) {
3048 error = copyout(&loff, SCARG(uap, basep), sizeof(long));
3049 }
3050 td->td_retval[0] = SCARG(uap, count) - auio.uio_resid;
3051 fdrop(fp, td);
3052 return (error);
3053}
3054#ifndef _SYS_SYSPROTO_H_
3055struct getdents_args {
3056 int fd;
3057 char *buf;
3058 size_t count;
3059};
3060#endif
3061int
3062getdents(td, uap)
3063 struct thread *td;
3064 register struct getdents_args /* {
3065 syscallarg(int) fd;
3066 syscallarg(char *) buf;
3067 syscallarg(u_int) count;
3068 } */ *uap;
3069{
3070 struct getdirentries_args ap;
3071 ap.fd = uap->fd;
3072 ap.buf = uap->buf;
3073 ap.count = uap->count;
3074 ap.basep = NULL;
3075 return getdirentries(td, &ap);
3076}
3077
3078/*
3079 * Set the mode mask for creation of filesystem nodes.
3080 *
3081 * MP SAFE
3082 */
3083#ifndef _SYS_SYSPROTO_H_
3084struct umask_args {
3085 int newmask;
3086};
3087#endif
3088int
3089umask(td, uap)
3090 struct thread *td;
3091 struct umask_args /* {
3092 syscallarg(int) newmask;
3093 } */ *uap;
3094{
3095 register struct filedesc *fdp;
3096
3097 FILEDESC_LOCK(td->td_proc->p_fd);
3098 fdp = td->td_proc->p_fd;
3099 td->td_retval[0] = fdp->fd_cmask;
3100 fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS;
3101 FILEDESC_UNLOCK(td->td_proc->p_fd);
3102 return (0);
3103}
3104
3105/*
3106 * Void all references to file by ripping underlying filesystem
3107 * away from vnode.
3108 */
3109#ifndef _SYS_SYSPROTO_H_
3110struct revoke_args {
3111 char *path;
3112};
3113#endif
3114/* ARGSUSED */
3115int
3116revoke(td, uap)
3117 struct thread *td;
3118 register struct revoke_args /* {
3119 syscallarg(char *) path;
3120 } */ *uap;
3121{
3122 struct mount *mp;
3123 struct vnode *vp;
3124 struct vattr vattr;
3125 int error;
3126 struct nameidata nd;
3127
3128 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, SCARG(uap, path),
3129 td);
3130 if ((error = namei(&nd)) != 0)
3131 return (error);
3132 vp = nd.ni_vp;
3133 NDFREE(&nd, NDF_ONLY_PNBUF);
3134 if (vp->v_type != VCHR) {
3135 vput(vp);
3136 return (EINVAL);
3137 }
3138#ifdef MAC
3139 error = mac_check_vnode_revoke(td->td_ucred, vp);
3140 if (error) {
3141 vput(vp);
3142 return (error);
3143 }
3144#endif
3145 error = VOP_GETATTR(vp, &vattr, td->td_ucred, td);
3146 if (error) {
3147 vput(vp);
3148 return (error);
3149 }
3150 VOP_UNLOCK(vp, 0, td);
3151 if (td->td_ucred->cr_uid != vattr.va_uid) {
3152 error = suser_cred(td->td_ucred, PRISON_ROOT);
3153 if (error)
3154 goto out;
3155 }
3156 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
3157 goto out;
3158 if (vcount(vp) > 1)
3159 VOP_REVOKE(vp, REVOKEALL);
3160 vn_finished_write(mp);
3161out:
3162 vrele(vp);
3163 return (error);
3164}
3165
3166/*
3167 * Convert a user file descriptor to a kernel file entry.
3168 * The file entry is locked upon returning.
3169 */
3170int
3171getvnode(fdp, fd, fpp)
3172 struct filedesc *fdp;
3173 int fd;
3174 struct file **fpp;
3175{
3176 int error;
3177 struct file *fp;
3178
3179 fp = NULL;
3180 if (fdp == NULL)
3181 error = EBADF;
3182 else {
3183 FILEDESC_LOCK(fdp);
3184 if ((u_int)fd >= fdp->fd_nfiles ||
3185 (fp = fdp->fd_ofiles[fd]) == NULL)
3186 error = EBADF;
3187 else if (fp->f_type != DTYPE_VNODE && fp->f_type != DTYPE_FIFO) {
3188 fp = NULL;
3189 error = EINVAL;
3190 } else {
3191 fhold(fp);
3192 error = 0;
3193 }
3194 FILEDESC_UNLOCK(fdp);
3195 }
3196 *fpp = fp;
3197 return (error);
3198}
3199/*
3200 * Get (NFS) file handle
3201 */
3202#ifndef _SYS_SYSPROTO_H_
3203struct getfh_args {
3204 char *fname;
3205 fhandle_t *fhp;
3206};
3207#endif
3208int
3209getfh(td, uap)
3210 struct thread *td;
3211 register struct getfh_args *uap;
3212{
3213 struct nameidata nd;
3214 fhandle_t fh;
3215 register struct vnode *vp;
3216 int error;
3217
3218 /*
3219 * Must be super user
3220 */
3221 error = suser(td);
3222 if (error)
3223 return (error);
3224 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, td);
3225 error = namei(&nd);
3226 if (error)
3227 return (error);
3228 NDFREE(&nd, NDF_ONLY_PNBUF);
3229 vp = nd.ni_vp;
3230 bzero(&fh, sizeof(fh));
3231 fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
3232 error = VFS_VPTOFH(vp, &fh.fh_fid);
3233 vput(vp);
3234 if (error)
3235 return (error);
3236 error = copyout(&fh, uap->fhp, sizeof (fh));
3237 return (error);
3238}
3239
3240/*
3241 * syscall for the rpc.lockd to use to translate a NFS file handle into
3242 * an open descriptor.
3243 *
3244 * warning: do not remove the suser() call or this becomes one giant
3245 * security hole.
3246 */
3247#ifndef _SYS_SYSPROTO_H_
3248struct fhopen_args {
3249 const struct fhandle *u_fhp;
3250 int flags;
3251};
3252#endif
3253int
3254fhopen(td, uap)
3255 struct thread *td;
3256 struct fhopen_args /* {
3257 syscallarg(const struct fhandle *) u_fhp;
3258 syscallarg(int) flags;
3259 } */ *uap;
3260{
3261 struct proc *p = td->td_proc;
3262 struct mount *mp;
3263 struct vnode *vp;
3264 struct fhandle fhp;
3265 struct vattr vat;
3266 struct vattr *vap = &vat;
3267 struct flock lf;
3268 struct file *fp;
3269 register struct filedesc *fdp = p->p_fd;
3270 int fmode, mode, error, type;
3271 struct file *nfp;
3272 int indx;
3273
3274 /*
3275 * Must be super user
3276 */
3277 error = suser(td);
3278 if (error)
3279 return (error);
3280
3281 fmode = FFLAGS(SCARG(uap, flags));
3282 /* why not allow a non-read/write open for our lockd? */
3283 if (((fmode & (FREAD | FWRITE)) == 0) || (fmode & O_CREAT))
3284 return (EINVAL);
3285 error = copyin(SCARG(uap,u_fhp), &fhp, sizeof(fhp));
3286 if (error)
3287 return(error);
3288 /* find the mount point */
3289 mp = vfs_getvfs(&fhp.fh_fsid);
3290 if (mp == NULL)
3291 return (ESTALE);
3292 /* now give me my vnode, it gets returned to me locked */
3293 error = VFS_FHTOVP(mp, &fhp.fh_fid, &vp);
3294 if (error)
3295 return (error);
3296 /*
3297 * from now on we have to make sure not
3298 * to forget about the vnode
3299 * any error that causes an abort must vput(vp)
3300 * just set error = err and 'goto bad;'.
3301 */
3302
3303 /*
3304 * from vn_open
3305 */
3306 if (vp->v_type == VLNK) {
3307 error = EMLINK;
3308 goto bad;
3309 }
3310 if (vp->v_type == VSOCK) {
3311 error = EOPNOTSUPP;
3312 goto bad;
3313 }
3314 mode = 0;
3315 if (fmode & (FWRITE | O_TRUNC)) {
3316 if (vp->v_type == VDIR) {
3317 error = EISDIR;
3318 goto bad;
3319 }
3320 error = vn_writechk(vp);
3321 if (error)
3322 goto bad;
3323 mode |= VWRITE;
3324 }
3325 if (fmode & FREAD)
3326 mode |= VREAD;
3327 if (fmode & O_APPEND)
3328 mode |= VAPPEND;
3329#ifdef MAC
3330 error = mac_check_vnode_open(td->td_ucred, vp, mode);
3331 if (error)
3332 goto bad;
3333#endif
3334 if (mode) {
3335 error = VOP_ACCESS(vp, mode, td->td_ucred, td);
3336 if (error)
3337 goto bad;
3338 }
3339 if (fmode & O_TRUNC) {
3340 VOP_UNLOCK(vp, 0, td); /* XXX */
3341 if ((error = vn_start_write(NULL, &mp, V_WAIT | PCATCH)) != 0) {
3342 vrele(vp);
3343 return (error);
3344 }
3345 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
3346 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); /* XXX */
3347#ifdef MAC
2428#endif
2429 else if ((error = vn_writechk(vp)) == 0) {
2430 VATTR_NULL(&vattr);
2431 vattr.va_size = SCARG(uap, length);
2432 error = VOP_SETATTR(vp, &vattr, fp->f_cred, td);
2433 }
2434 VOP_UNLOCK(vp, 0, td);
2435 vn_finished_write(mp);
2436 fdrop(fp, td);
2437 return (error);
2438}
2439
2440#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
2441/*
2442 * Truncate a file given its path name.
2443 */
2444#ifndef _SYS_SYSPROTO_H_
2445struct otruncate_args {
2446 char *path;
2447 long length;
2448};
2449#endif
2450/* ARGSUSED */
2451int
2452otruncate(td, uap)
2453 struct thread *td;
2454 register struct otruncate_args /* {
2455 syscallarg(char *) path;
2456 syscallarg(long) length;
2457 } */ *uap;
2458{
2459 struct truncate_args /* {
2460 syscallarg(char *) path;
2461 syscallarg(int) pad;
2462 syscallarg(off_t) length;
2463 } */ nuap;
2464
2465 SCARG(&nuap, path) = SCARG(uap, path);
2466 SCARG(&nuap, length) = SCARG(uap, length);
2467 return (truncate(td, &nuap));
2468}
2469
2470/*
2471 * Truncate a file given a file descriptor.
2472 */
2473#ifndef _SYS_SYSPROTO_H_
2474struct oftruncate_args {
2475 int fd;
2476 long length;
2477};
2478#endif
2479/* ARGSUSED */
2480int
2481oftruncate(td, uap)
2482 struct thread *td;
2483 register struct oftruncate_args /* {
2484 syscallarg(int) fd;
2485 syscallarg(long) length;
2486 } */ *uap;
2487{
2488 struct ftruncate_args /* {
2489 syscallarg(int) fd;
2490 syscallarg(int) pad;
2491 syscallarg(off_t) length;
2492 } */ nuap;
2493
2494 SCARG(&nuap, fd) = SCARG(uap, fd);
2495 SCARG(&nuap, length) = SCARG(uap, length);
2496 return (ftruncate(td, &nuap));
2497}
2498#endif /* COMPAT_43 || COMPAT_SUNOS */
2499
2500/*
2501 * Sync an open file.
2502 */
2503#ifndef _SYS_SYSPROTO_H_
2504struct fsync_args {
2505 int fd;
2506};
2507#endif
2508/* ARGSUSED */
2509int
2510fsync(td, uap)
2511 struct thread *td;
2512 struct fsync_args /* {
2513 syscallarg(int) fd;
2514 } */ *uap;
2515{
2516 struct vnode *vp;
2517 struct mount *mp;
2518 struct file *fp;
2519 vm_object_t obj;
2520 int error;
2521
2522 GIANT_REQUIRED;
2523
2524 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
2525 return (error);
2526 vp = (struct vnode *)fp->f_data;
2527 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) {
2528 fdrop(fp, td);
2529 return (error);
2530 }
2531 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2532 if (VOP_GETVOBJECT(vp, &obj) == 0) {
2533 vm_object_page_clean(obj, 0, 0, 0);
2534 }
2535 error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, td);
2536 if (error == 0 && vp->v_mount && (vp->v_mount->mnt_flag & MNT_SOFTDEP)
2537 && softdep_fsync_hook != NULL)
2538 error = (*softdep_fsync_hook)(vp);
2539
2540 VOP_UNLOCK(vp, 0, td);
2541 vn_finished_write(mp);
2542 fdrop(fp, td);
2543 return (error);
2544}
2545
2546/*
2547 * Rename files. Source and destination must either both be directories,
2548 * or both not be directories. If target is a directory, it must be empty.
2549 */
2550#ifndef _SYS_SYSPROTO_H_
2551struct rename_args {
2552 char *from;
2553 char *to;
2554};
2555#endif
2556/* ARGSUSED */
2557int
2558rename(td, uap)
2559 struct thread *td;
2560 register struct rename_args /* {
2561 syscallarg(char *) from;
2562 syscallarg(char *) to;
2563 } */ *uap;
2564{
2565 struct mount *mp;
2566 struct vnode *tvp, *fvp, *tdvp;
2567 struct nameidata fromnd, tond;
2568 int error;
2569
2570 bwillwrite();
2571 NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
2572 SCARG(uap, from), td);
2573 if ((error = namei(&fromnd)) != 0)
2574 return (error);
2575 fvp = fromnd.ni_vp;
2576 if ((error = vn_start_write(fvp, &mp, V_WAIT | PCATCH)) != 0) {
2577 NDFREE(&fromnd, NDF_ONLY_PNBUF);
2578 vrele(fromnd.ni_dvp);
2579 vrele(fvp);
2580 goto out1;
2581 }
2582 NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART | NOOBJ,
2583 UIO_USERSPACE, SCARG(uap, to), td);
2584 if (fromnd.ni_vp->v_type == VDIR)
2585 tond.ni_cnd.cn_flags |= WILLBEDIR;
2586 if ((error = namei(&tond)) != 0) {
2587 /* Translate error code for rename("dir1", "dir2/."). */
2588 if (error == EISDIR && fvp->v_type == VDIR)
2589 error = EINVAL;
2590 NDFREE(&fromnd, NDF_ONLY_PNBUF);
2591 vrele(fromnd.ni_dvp);
2592 vrele(fvp);
2593 goto out1;
2594 }
2595 tdvp = tond.ni_dvp;
2596 tvp = tond.ni_vp;
2597 if (tvp != NULL) {
2598 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
2599 error = ENOTDIR;
2600 goto out;
2601 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
2602 error = EISDIR;
2603 goto out;
2604 }
2605 }
2606 if (fvp == tdvp)
2607 error = EINVAL;
2608 /*
2609 * If source is the same as the destination (that is the
2610 * same inode number with the same name in the same directory),
2611 * then there is nothing to do.
2612 */
2613 if (fvp == tvp && fromnd.ni_dvp == tdvp &&
2614 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
2615 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
2616 fromnd.ni_cnd.cn_namelen))
2617 error = -1;
2618out:
2619 if (!error) {
2620 VOP_LEASE(tdvp, td, td->td_ucred, LEASE_WRITE);
2621 if (fromnd.ni_dvp != tdvp) {
2622 VOP_LEASE(fromnd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
2623 }
2624 if (tvp) {
2625 VOP_LEASE(tvp, td, td->td_ucred, LEASE_WRITE);
2626 }
2627 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
2628 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
2629 NDFREE(&fromnd, NDF_ONLY_PNBUF);
2630 NDFREE(&tond, NDF_ONLY_PNBUF);
2631 } else {
2632 NDFREE(&fromnd, NDF_ONLY_PNBUF);
2633 NDFREE(&tond, NDF_ONLY_PNBUF);
2634 if (tdvp == tvp)
2635 vrele(tdvp);
2636 else
2637 vput(tdvp);
2638 if (tvp)
2639 vput(tvp);
2640 vrele(fromnd.ni_dvp);
2641 vrele(fvp);
2642 }
2643 vrele(tond.ni_startdir);
2644 vn_finished_write(mp);
2645 ASSERT_VOP_UNLOCKED(fromnd.ni_dvp, "rename");
2646 ASSERT_VOP_UNLOCKED(fromnd.ni_vp, "rename");
2647 ASSERT_VOP_UNLOCKED(tond.ni_dvp, "rename");
2648 ASSERT_VOP_UNLOCKED(tond.ni_vp, "rename");
2649out1:
2650 if (fromnd.ni_startdir)
2651 vrele(fromnd.ni_startdir);
2652 if (error == -1)
2653 return (0);
2654 return (error);
2655}
2656
2657/*
2658 * Make a directory file.
2659 */
2660#ifndef _SYS_SYSPROTO_H_
2661struct mkdir_args {
2662 char *path;
2663 int mode;
2664};
2665#endif
2666/* ARGSUSED */
2667int
2668mkdir(td, uap)
2669 struct thread *td;
2670 register struct mkdir_args /* {
2671 syscallarg(char *) path;
2672 syscallarg(int) mode;
2673 } */ *uap;
2674{
2675
2676 return vn_mkdir(uap->path, uap->mode, UIO_USERSPACE, td);
2677}
2678
2679int
2680vn_mkdir(path, mode, segflg, td)
2681 char *path;
2682 int mode;
2683 enum uio_seg segflg;
2684 struct thread *td;
2685{
2686 struct mount *mp;
2687 struct vnode *vp;
2688 struct vattr vattr;
2689 int error;
2690 struct nameidata nd;
2691
2692restart:
2693 bwillwrite();
2694 NDINIT(&nd, CREATE, LOCKPARENT | SAVENAME, segflg, path, td);
2695 nd.ni_cnd.cn_flags |= WILLBEDIR;
2696 if ((error = namei(&nd)) != 0)
2697 return (error);
2698 vp = nd.ni_vp;
2699 if (vp != NULL) {
2700 NDFREE(&nd, NDF_ONLY_PNBUF);
2701 vrele(vp);
2702 /*
2703 * XXX namei called with LOCKPARENT but not LOCKLEAF has
2704 * the strange behaviour of leaving the vnode unlocked
2705 * if the target is the same vnode as the parent.
2706 */
2707 if (vp == nd.ni_dvp)
2708 vrele(nd.ni_dvp);
2709 else
2710 vput(nd.ni_dvp);
2711 return (EEXIST);
2712 }
2713 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
2714 NDFREE(&nd, NDF_ONLY_PNBUF);
2715 vput(nd.ni_dvp);
2716 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
2717 return (error);
2718 goto restart;
2719 }
2720 VATTR_NULL(&vattr);
2721 vattr.va_type = VDIR;
2722 FILEDESC_LOCK(td->td_proc->p_fd);
2723 vattr.va_mode = (mode & ACCESSPERMS) &~ td->td_proc->p_fd->fd_cmask;
2724 FILEDESC_UNLOCK(td->td_proc->p_fd);
2725 VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
2726 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
2727 NDFREE(&nd, NDF_ONLY_PNBUF);
2728 vput(nd.ni_dvp);
2729 if (!error)
2730 vput(nd.ni_vp);
2731 vn_finished_write(mp);
2732 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mkdir");
2733 ASSERT_VOP_UNLOCKED(nd.ni_vp, "mkdir");
2734 return (error);
2735}
2736
2737/*
2738 * Remove a directory file.
2739 */
2740#ifndef _SYS_SYSPROTO_H_
2741struct rmdir_args {
2742 char *path;
2743};
2744#endif
2745/* ARGSUSED */
2746int
2747rmdir(td, uap)
2748 struct thread *td;
2749 struct rmdir_args /* {
2750 syscallarg(char *) path;
2751 } */ *uap;
2752{
2753 struct mount *mp;
2754 struct vnode *vp;
2755 int error;
2756 struct nameidata nd;
2757
2758restart:
2759 bwillwrite();
2760 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
2761 SCARG(uap, path), td);
2762 if ((error = namei(&nd)) != 0)
2763 return (error);
2764 vp = nd.ni_vp;
2765 if (vp->v_type != VDIR) {
2766 error = ENOTDIR;
2767 goto out;
2768 }
2769 /*
2770 * No rmdir "." please.
2771 */
2772 if (nd.ni_dvp == vp) {
2773 error = EINVAL;
2774 goto out;
2775 }
2776 /*
2777 * The root of a mounted filesystem cannot be deleted.
2778 */
2779 if (vp->v_vflag & VV_ROOT) {
2780 error = EBUSY;
2781 goto out;
2782 }
2783 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
2784 NDFREE(&nd, NDF_ONLY_PNBUF);
2785 if (nd.ni_dvp == vp)
2786 vrele(nd.ni_dvp);
2787 else
2788 vput(nd.ni_dvp);
2789 vput(vp);
2790 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
2791 return (error);
2792 goto restart;
2793 }
2794 VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
2795 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
2796 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
2797 vn_finished_write(mp);
2798out:
2799 NDFREE(&nd, NDF_ONLY_PNBUF);
2800 if (nd.ni_dvp == vp)
2801 vrele(nd.ni_dvp);
2802 else
2803 vput(nd.ni_dvp);
2804 vput(vp);
2805 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "rmdir");
2806 ASSERT_VOP_UNLOCKED(nd.ni_vp, "rmdir");
2807 return (error);
2808}
2809
2810#ifdef COMPAT_43
2811/*
2812 * Read a block of directory entries in a filesystem independent format.
2813 */
2814#ifndef _SYS_SYSPROTO_H_
2815struct ogetdirentries_args {
2816 int fd;
2817 char *buf;
2818 u_int count;
2819 long *basep;
2820};
2821#endif
2822int
2823ogetdirentries(td, uap)
2824 struct thread *td;
2825 register struct ogetdirentries_args /* {
2826 syscallarg(int) fd;
2827 syscallarg(char *) buf;
2828 syscallarg(u_int) count;
2829 syscallarg(long *) basep;
2830 } */ *uap;
2831{
2832 struct vnode *vp;
2833 struct file *fp;
2834 struct uio auio, kuio;
2835 struct iovec aiov, kiov;
2836 struct dirent *dp, *edp;
2837 caddr_t dirbuf;
2838 int error, eofflag, readcnt;
2839 long loff;
2840
2841 /* XXX arbitrary sanity limit on `count'. */
2842 if (SCARG(uap, count) > 64 * 1024)
2843 return (EINVAL);
2844 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
2845 return (error);
2846 if ((fp->f_flag & FREAD) == 0) {
2847 fdrop(fp, td);
2848 return (EBADF);
2849 }
2850 vp = (struct vnode *)fp->f_data;
2851unionread:
2852 if (vp->v_type != VDIR) {
2853 fdrop(fp, td);
2854 return (EINVAL);
2855 }
2856 aiov.iov_base = SCARG(uap, buf);
2857 aiov.iov_len = SCARG(uap, count);
2858 auio.uio_iov = &aiov;
2859 auio.uio_iovcnt = 1;
2860 auio.uio_rw = UIO_READ;
2861 auio.uio_segflg = UIO_USERSPACE;
2862 auio.uio_td = td;
2863 auio.uio_resid = SCARG(uap, count);
2864 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2865 loff = auio.uio_offset = fp->f_offset;
2866#ifdef MAC
2867 error = mac_check_vnode_readdir(td->td_ucred, vp);
2868 if (error) {
2869 VOP_UNLOCK(vp, 0, td);
2870 fdrop(fp, td);
2871 return (error);
2872 }
2873#endif
2874# if (BYTE_ORDER != LITTLE_ENDIAN)
2875 if (vp->v_mount->mnt_maxsymlinklen <= 0) {
2876 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
2877 NULL, NULL);
2878 fp->f_offset = auio.uio_offset;
2879 } else
2880# endif
2881 {
2882 kuio = auio;
2883 kuio.uio_iov = &kiov;
2884 kuio.uio_segflg = UIO_SYSSPACE;
2885 kiov.iov_len = SCARG(uap, count);
2886 MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK);
2887 kiov.iov_base = dirbuf;
2888 error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
2889 NULL, NULL);
2890 fp->f_offset = kuio.uio_offset;
2891 if (error == 0) {
2892 readcnt = SCARG(uap, count) - kuio.uio_resid;
2893 edp = (struct dirent *)&dirbuf[readcnt];
2894 for (dp = (struct dirent *)dirbuf; dp < edp; ) {
2895# if (BYTE_ORDER == LITTLE_ENDIAN)
2896 /*
2897 * The expected low byte of
2898 * dp->d_namlen is our dp->d_type.
2899 * The high MBZ byte of dp->d_namlen
2900 * is our dp->d_namlen.
2901 */
2902 dp->d_type = dp->d_namlen;
2903 dp->d_namlen = 0;
2904# else
2905 /*
2906 * The dp->d_type is the high byte
2907 * of the expected dp->d_namlen,
2908 * so must be zero'ed.
2909 */
2910 dp->d_type = 0;
2911# endif
2912 if (dp->d_reclen > 0) {
2913 dp = (struct dirent *)
2914 ((char *)dp + dp->d_reclen);
2915 } else {
2916 error = EIO;
2917 break;
2918 }
2919 }
2920 if (dp >= edp)
2921 error = uiomove(dirbuf, readcnt, &auio);
2922 }
2923 FREE(dirbuf, M_TEMP);
2924 }
2925 VOP_UNLOCK(vp, 0, td);
2926 if (error) {
2927 fdrop(fp, td);
2928 return (error);
2929 }
2930 if (SCARG(uap, count) == auio.uio_resid) {
2931 if (union_dircheckp) {
2932 error = union_dircheckp(td, &vp, fp);
2933 if (error == -1)
2934 goto unionread;
2935 if (error) {
2936 fdrop(fp, td);
2937 return (error);
2938 }
2939 }
2940 mp_fixme("Accessing vflags w/o vn lock.");
2941 if ((vp->v_vflag & VV_ROOT) &&
2942 (vp->v_mount->mnt_flag & MNT_UNION)) {
2943 struct vnode *tvp = vp;
2944 vp = vp->v_mount->mnt_vnodecovered;
2945 VREF(vp);
2946 fp->f_data = vp;
2947 fp->f_offset = 0;
2948 vrele(tvp);
2949 goto unionread;
2950 }
2951 }
2952 error = copyout(&loff, SCARG(uap, basep), sizeof(long));
2953 fdrop(fp, td);
2954 td->td_retval[0] = SCARG(uap, count) - auio.uio_resid;
2955 return (error);
2956}
2957#endif /* COMPAT_43 */
2958
2959/*
2960 * Read a block of directory entries in a filesystem independent format.
2961 */
2962#ifndef _SYS_SYSPROTO_H_
2963struct getdirentries_args {
2964 int fd;
2965 char *buf;
2966 u_int count;
2967 long *basep;
2968};
2969#endif
2970int
2971getdirentries(td, uap)
2972 struct thread *td;
2973 register struct getdirentries_args /* {
2974 syscallarg(int) fd;
2975 syscallarg(char *) buf;
2976 syscallarg(u_int) count;
2977 syscallarg(long *) basep;
2978 } */ *uap;
2979{
2980 struct vnode *vp;
2981 struct file *fp;
2982 struct uio auio;
2983 struct iovec aiov;
2984 long loff;
2985 int error, eofflag;
2986
2987 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
2988 return (error);
2989 if ((fp->f_flag & FREAD) == 0) {
2990 fdrop(fp, td);
2991 return (EBADF);
2992 }
2993 vp = (struct vnode *)fp->f_data;
2994unionread:
2995 if (vp->v_type != VDIR) {
2996 fdrop(fp, td);
2997 return (EINVAL);
2998 }
2999 aiov.iov_base = SCARG(uap, buf);
3000 aiov.iov_len = SCARG(uap, count);
3001 auio.uio_iov = &aiov;
3002 auio.uio_iovcnt = 1;
3003 auio.uio_rw = UIO_READ;
3004 auio.uio_segflg = UIO_USERSPACE;
3005 auio.uio_td = td;
3006 auio.uio_resid = SCARG(uap, count);
3007 /* vn_lock(vp, LK_SHARED | LK_RETRY, td); */
3008 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
3009 loff = auio.uio_offset = fp->f_offset;
3010#ifdef MAC
3011 error = mac_check_vnode_readdir(td->td_ucred, vp);
3012 if (error == 0)
3013#endif
3014 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, NULL,
3015 NULL);
3016 fp->f_offset = auio.uio_offset;
3017 VOP_UNLOCK(vp, 0, td);
3018 if (error) {
3019 fdrop(fp, td);
3020 return (error);
3021 }
3022 if (SCARG(uap, count) == auio.uio_resid) {
3023 if (union_dircheckp) {
3024 error = union_dircheckp(td, &vp, fp);
3025 if (error == -1)
3026 goto unionread;
3027 if (error) {
3028 fdrop(fp, td);
3029 return (error);
3030 }
3031 }
3032 mp_fixme("Accessing vflag without vn lock.");
3033 if ((vp->v_vflag & VV_ROOT) &&
3034 (vp->v_mount->mnt_flag & MNT_UNION)) {
3035 struct vnode *tvp = vp;
3036 vp = vp->v_mount->mnt_vnodecovered;
3037 VREF(vp);
3038 fp->f_data = vp;
3039 fp->f_offset = 0;
3040 vrele(tvp);
3041 goto unionread;
3042 }
3043 }
3044 if (SCARG(uap, basep) != NULL) {
3045 error = copyout(&loff, SCARG(uap, basep), sizeof(long));
3046 }
3047 td->td_retval[0] = SCARG(uap, count) - auio.uio_resid;
3048 fdrop(fp, td);
3049 return (error);
3050}
3051#ifndef _SYS_SYSPROTO_H_
3052struct getdents_args {
3053 int fd;
3054 char *buf;
3055 size_t count;
3056};
3057#endif
3058int
3059getdents(td, uap)
3060 struct thread *td;
3061 register struct getdents_args /* {
3062 syscallarg(int) fd;
3063 syscallarg(char *) buf;
3064 syscallarg(u_int) count;
3065 } */ *uap;
3066{
3067 struct getdirentries_args ap;
3068 ap.fd = uap->fd;
3069 ap.buf = uap->buf;
3070 ap.count = uap->count;
3071 ap.basep = NULL;
3072 return getdirentries(td, &ap);
3073}
3074
3075/*
3076 * Set the mode mask for creation of filesystem nodes.
3077 *
3078 * MP SAFE
3079 */
3080#ifndef _SYS_SYSPROTO_H_
3081struct umask_args {
3082 int newmask;
3083};
3084#endif
3085int
3086umask(td, uap)
3087 struct thread *td;
3088 struct umask_args /* {
3089 syscallarg(int) newmask;
3090 } */ *uap;
3091{
3092 register struct filedesc *fdp;
3093
3094 FILEDESC_LOCK(td->td_proc->p_fd);
3095 fdp = td->td_proc->p_fd;
3096 td->td_retval[0] = fdp->fd_cmask;
3097 fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS;
3098 FILEDESC_UNLOCK(td->td_proc->p_fd);
3099 return (0);
3100}
3101
3102/*
3103 * Void all references to file by ripping underlying filesystem
3104 * away from vnode.
3105 */
3106#ifndef _SYS_SYSPROTO_H_
3107struct revoke_args {
3108 char *path;
3109};
3110#endif
3111/* ARGSUSED */
3112int
3113revoke(td, uap)
3114 struct thread *td;
3115 register struct revoke_args /* {
3116 syscallarg(char *) path;
3117 } */ *uap;
3118{
3119 struct mount *mp;
3120 struct vnode *vp;
3121 struct vattr vattr;
3122 int error;
3123 struct nameidata nd;
3124
3125 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, SCARG(uap, path),
3126 td);
3127 if ((error = namei(&nd)) != 0)
3128 return (error);
3129 vp = nd.ni_vp;
3130 NDFREE(&nd, NDF_ONLY_PNBUF);
3131 if (vp->v_type != VCHR) {
3132 vput(vp);
3133 return (EINVAL);
3134 }
3135#ifdef MAC
3136 error = mac_check_vnode_revoke(td->td_ucred, vp);
3137 if (error) {
3138 vput(vp);
3139 return (error);
3140 }
3141#endif
3142 error = VOP_GETATTR(vp, &vattr, td->td_ucred, td);
3143 if (error) {
3144 vput(vp);
3145 return (error);
3146 }
3147 VOP_UNLOCK(vp, 0, td);
3148 if (td->td_ucred->cr_uid != vattr.va_uid) {
3149 error = suser_cred(td->td_ucred, PRISON_ROOT);
3150 if (error)
3151 goto out;
3152 }
3153 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
3154 goto out;
3155 if (vcount(vp) > 1)
3156 VOP_REVOKE(vp, REVOKEALL);
3157 vn_finished_write(mp);
3158out:
3159 vrele(vp);
3160 return (error);
3161}
3162
3163/*
3164 * Convert a user file descriptor to a kernel file entry.
3165 * The file entry is locked upon returning.
3166 */
3167int
3168getvnode(fdp, fd, fpp)
3169 struct filedesc *fdp;
3170 int fd;
3171 struct file **fpp;
3172{
3173 int error;
3174 struct file *fp;
3175
3176 fp = NULL;
3177 if (fdp == NULL)
3178 error = EBADF;
3179 else {
3180 FILEDESC_LOCK(fdp);
3181 if ((u_int)fd >= fdp->fd_nfiles ||
3182 (fp = fdp->fd_ofiles[fd]) == NULL)
3183 error = EBADF;
3184 else if (fp->f_type != DTYPE_VNODE && fp->f_type != DTYPE_FIFO) {
3185 fp = NULL;
3186 error = EINVAL;
3187 } else {
3188 fhold(fp);
3189 error = 0;
3190 }
3191 FILEDESC_UNLOCK(fdp);
3192 }
3193 *fpp = fp;
3194 return (error);
3195}
3196/*
3197 * Get (NFS) file handle
3198 */
3199#ifndef _SYS_SYSPROTO_H_
3200struct getfh_args {
3201 char *fname;
3202 fhandle_t *fhp;
3203};
3204#endif
3205int
3206getfh(td, uap)
3207 struct thread *td;
3208 register struct getfh_args *uap;
3209{
3210 struct nameidata nd;
3211 fhandle_t fh;
3212 register struct vnode *vp;
3213 int error;
3214
3215 /*
3216 * Must be super user
3217 */
3218 error = suser(td);
3219 if (error)
3220 return (error);
3221 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, td);
3222 error = namei(&nd);
3223 if (error)
3224 return (error);
3225 NDFREE(&nd, NDF_ONLY_PNBUF);
3226 vp = nd.ni_vp;
3227 bzero(&fh, sizeof(fh));
3228 fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
3229 error = VFS_VPTOFH(vp, &fh.fh_fid);
3230 vput(vp);
3231 if (error)
3232 return (error);
3233 error = copyout(&fh, uap->fhp, sizeof (fh));
3234 return (error);
3235}
3236
3237/*
3238 * syscall for the rpc.lockd to use to translate a NFS file handle into
3239 * an open descriptor.
3240 *
3241 * warning: do not remove the suser() call or this becomes one giant
3242 * security hole.
3243 */
3244#ifndef _SYS_SYSPROTO_H_
3245struct fhopen_args {
3246 const struct fhandle *u_fhp;
3247 int flags;
3248};
3249#endif
3250int
3251fhopen(td, uap)
3252 struct thread *td;
3253 struct fhopen_args /* {
3254 syscallarg(const struct fhandle *) u_fhp;
3255 syscallarg(int) flags;
3256 } */ *uap;
3257{
3258 struct proc *p = td->td_proc;
3259 struct mount *mp;
3260 struct vnode *vp;
3261 struct fhandle fhp;
3262 struct vattr vat;
3263 struct vattr *vap = &vat;
3264 struct flock lf;
3265 struct file *fp;
3266 register struct filedesc *fdp = p->p_fd;
3267 int fmode, mode, error, type;
3268 struct file *nfp;
3269 int indx;
3270
3271 /*
3272 * Must be super user
3273 */
3274 error = suser(td);
3275 if (error)
3276 return (error);
3277
3278 fmode = FFLAGS(SCARG(uap, flags));
3279 /* why not allow a non-read/write open for our lockd? */
3280 if (((fmode & (FREAD | FWRITE)) == 0) || (fmode & O_CREAT))
3281 return (EINVAL);
3282 error = copyin(SCARG(uap,u_fhp), &fhp, sizeof(fhp));
3283 if (error)
3284 return(error);
3285 /* find the mount point */
3286 mp = vfs_getvfs(&fhp.fh_fsid);
3287 if (mp == NULL)
3288 return (ESTALE);
3289 /* now give me my vnode, it gets returned to me locked */
3290 error = VFS_FHTOVP(mp, &fhp.fh_fid, &vp);
3291 if (error)
3292 return (error);
3293 /*
3294 * from now on we have to make sure not
3295 * to forget about the vnode
3296 * any error that causes an abort must vput(vp)
3297 * just set error = err and 'goto bad;'.
3298 */
3299
3300 /*
3301 * from vn_open
3302 */
3303 if (vp->v_type == VLNK) {
3304 error = EMLINK;
3305 goto bad;
3306 }
3307 if (vp->v_type == VSOCK) {
3308 error = EOPNOTSUPP;
3309 goto bad;
3310 }
3311 mode = 0;
3312 if (fmode & (FWRITE | O_TRUNC)) {
3313 if (vp->v_type == VDIR) {
3314 error = EISDIR;
3315 goto bad;
3316 }
3317 error = vn_writechk(vp);
3318 if (error)
3319 goto bad;
3320 mode |= VWRITE;
3321 }
3322 if (fmode & FREAD)
3323 mode |= VREAD;
3324 if (fmode & O_APPEND)
3325 mode |= VAPPEND;
3326#ifdef MAC
3327 error = mac_check_vnode_open(td->td_ucred, vp, mode);
3328 if (error)
3329 goto bad;
3330#endif
3331 if (mode) {
3332 error = VOP_ACCESS(vp, mode, td->td_ucred, td);
3333 if (error)
3334 goto bad;
3335 }
3336 if (fmode & O_TRUNC) {
3337 VOP_UNLOCK(vp, 0, td); /* XXX */
3338 if ((error = vn_start_write(NULL, &mp, V_WAIT | PCATCH)) != 0) {
3339 vrele(vp);
3340 return (error);
3341 }
3342 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
3343 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); /* XXX */
3344#ifdef MAC
3348 error = mac_check_vnode_op(td->td_ucred, vp,
3349 MAC_OP_VNODE_WRITE);
3345 error = mac_check_vnode_write(td->td_ucred, vp);
3350 if (error == 0) {
3351#endif
3352 VATTR_NULL(vap);
3353 vap->va_size = 0;
3354 error = VOP_SETATTR(vp, vap, td->td_ucred, td);
3355#ifdef MAC
3356 }
3357#endif
3358 vn_finished_write(mp);
3359 if (error)
3360 goto bad;
3361 }
3362 error = VOP_OPEN(vp, fmode, td->td_ucred, td);
3363 if (error)
3364 goto bad;
3365 /*
3366 * Make sure that a VM object is created for VMIO support.
3367 */
3368 if (vn_canvmio(vp) == TRUE) {
3369 if ((error = vfs_object_create(vp, td, td->td_ucred)) != 0)
3370 goto bad;
3371 }
3372 if (fmode & FWRITE)
3373 vp->v_writecount++;
3374
3375 /*
3376 * end of vn_open code
3377 */
3378
3379 if ((error = falloc(td, &nfp, &indx)) != 0) {
3380 if (fmode & FWRITE)
3381 vp->v_writecount--;
3382 goto bad;
3383 }
3384 fp = nfp;
3385
3386 /*
3387 * Hold an extra reference to avoid having fp ripped out
3388 * from under us while we block in the lock op
3389 */
3390 fhold(fp);
3391 nfp->f_data = vp;
3392 nfp->f_flag = fmode & FMASK;
3393 nfp->f_ops = &vnops;
3394 nfp->f_type = DTYPE_VNODE;
3395 if (fmode & (O_EXLOCK | O_SHLOCK)) {
3396 lf.l_whence = SEEK_SET;
3397 lf.l_start = 0;
3398 lf.l_len = 0;
3399 if (fmode & O_EXLOCK)
3400 lf.l_type = F_WRLCK;
3401 else
3402 lf.l_type = F_RDLCK;
3403 type = F_FLOCK;
3404 if ((fmode & FNONBLOCK) == 0)
3405 type |= F_WAIT;
3406 VOP_UNLOCK(vp, 0, td);
3407 if ((error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf,
3408 type)) != 0) {
3409 /*
3410 * The lock request failed. Normally close the
3411 * descriptor but handle the case where someone might
3412 * have dup()d or close()d it when we weren't looking.
3413 */
3414 FILEDESC_LOCK(fdp);
3415 if (fdp->fd_ofiles[indx] == fp) {
3416 fdp->fd_ofiles[indx] = NULL;
3417 FILEDESC_UNLOCK(fdp);
3418 fdrop(fp, td);
3419 } else
3420 FILEDESC_UNLOCK(fdp);
3421 /*
3422 * release our private reference
3423 */
3424 fdrop(fp, td);
3425 return(error);
3426 }
3427 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
3428 fp->f_flag |= FHASLOCK;
3429 }
3430 if ((vp->v_type == VREG) && (VOP_GETVOBJECT(vp, NULL) != 0))
3431 vfs_object_create(vp, td, td->td_ucred);
3432
3433 VOP_UNLOCK(vp, 0, td);
3434 fdrop(fp, td);
3435 td->td_retval[0] = indx;
3436 return (0);
3437
3438bad:
3439 vput(vp);
3440 return (error);
3441}
3442
3443/*
3444 * Stat an (NFS) file handle.
3445 */
3446#ifndef _SYS_SYSPROTO_H_
3447struct fhstat_args {
3448 struct fhandle *u_fhp;
3449 struct stat *sb;
3450};
3451#endif
3452int
3453fhstat(td, uap)
3454 struct thread *td;
3455 register struct fhstat_args /* {
3456 syscallarg(struct fhandle *) u_fhp;
3457 syscallarg(struct stat *) sb;
3458 } */ *uap;
3459{
3460 struct stat sb;
3461 fhandle_t fh;
3462 struct mount *mp;
3463 struct vnode *vp;
3464 int error;
3465
3466 /*
3467 * Must be super user
3468 */
3469 error = suser(td);
3470 if (error)
3471 return (error);
3472
3473 error = copyin(SCARG(uap, u_fhp), &fh, sizeof(fhandle_t));
3474 if (error)
3475 return (error);
3476
3477 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
3478 return (ESTALE);
3479 if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
3480 return (error);
3481 error = vn_stat(vp, &sb, td->td_ucred, NOCRED, td);
3482 vput(vp);
3483 if (error)
3484 return (error);
3485 error = copyout(&sb, SCARG(uap, sb), sizeof(sb));
3486 return (error);
3487}
3488
3489/*
3490 * Implement fstatfs() for (NFS) file handles.
3491 */
3492#ifndef _SYS_SYSPROTO_H_
3493struct fhstatfs_args {
3494 struct fhandle *u_fhp;
3495 struct statfs *buf;
3496};
3497#endif
3498int
3499fhstatfs(td, uap)
3500 struct thread *td;
3501 struct fhstatfs_args /* {
3502 syscallarg(struct fhandle) *u_fhp;
3503 syscallarg(struct statfs) *buf;
3504 } */ *uap;
3505{
3506 struct statfs *sp;
3507 struct mount *mp;
3508 struct vnode *vp;
3509 struct statfs sb;
3510 fhandle_t fh;
3511 int error;
3512
3513 /*
3514 * Must be super user
3515 */
3516 error = suser(td);
3517 if (error)
3518 return (error);
3519
3520 if ((error = copyin(SCARG(uap, u_fhp), &fh, sizeof(fhandle_t))) != 0)
3521 return (error);
3522
3523 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
3524 return (ESTALE);
3525 if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
3526 return (error);
3527 mp = vp->v_mount;
3528 sp = &mp->mnt_stat;
3529 vput(vp);
3530#ifdef MAC
3531 error = mac_check_mount_stat(td->td_ucred, mp);
3532 if (error)
3533 return (error);
3534#endif
3535 if ((error = VFS_STATFS(mp, sp, td)) != 0)
3536 return (error);
3537 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
3538 if (suser(td)) {
3539 bcopy(sp, &sb, sizeof(sb));
3540 sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
3541 sp = &sb;
3542 }
3543 return (copyout(sp, SCARG(uap, buf), sizeof(*sp)));
3544}
3545
3546/*
3547 * Syscall to push extended attribute configuration information into the
3548 * VFS. Accepts a path, which it converts to a mountpoint, as well as
3549 * a command (int cmd), and attribute name and misc data. For now, the
3550 * attribute name is left in userspace for consumption by the VFS_op.
3551 * It will probably be changed to be copied into sysspace by the
3552 * syscall in the future, once issues with various consumers of the
3553 * attribute code have raised their hands.
3554 *
3555 * Currently this is used only by UFS Extended Attributes.
3556 */
3557int
3558extattrctl(td, uap)
3559 struct thread *td;
3560 struct extattrctl_args /* {
3561 syscallarg(const char *) path;
3562 syscallarg(int) cmd;
3563 syscallarg(const char *) filename;
3564 syscallarg(int) attrnamespace;
3565 syscallarg(const char *) attrname;
3566 } */ *uap;
3567{
3568 struct vnode *filename_vp;
3569 struct nameidata nd;
3570 struct mount *mp, *mp_writable;
3571 char attrname[EXTATTR_MAXNAMELEN];
3572 int error;
3573
3574 /*
3575 * uap->attrname is not always defined. We check again later when we
3576 * invoke the VFS call so as to pass in NULL there if needed.
3577 */
3578 if (uap->attrname != NULL) {
3579 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN,
3580 NULL);
3581 if (error)
3582 return (error);
3583 }
3584
3585 /*
3586 * uap->filename is not always defined. If it is, grab a vnode lock,
3587 * which VFS_EXTATTRCTL() will later release.
3588 */
3589 filename_vp = NULL;
3590 if (uap->filename != NULL) {
3591 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
3592 uap->filename, td);
3593 if ((error = namei(&nd)) != 0)
3594 return (error);
3595 filename_vp = nd.ni_vp;
3596 NDFREE(&nd, NDF_NO_VP_RELE | NDF_NO_VP_UNLOCK);
3597 }
3598
3599 /* uap->path is always defined. */
3600 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
3601 if ((error = namei(&nd)) != 0) {
3602 if (filename_vp != NULL)
3603 vput(filename_vp);
3604 return (error);
3605 }
3606 mp = nd.ni_vp->v_mount;
3607 error = vn_start_write(nd.ni_vp, &mp_writable, V_WAIT | PCATCH);
3608 NDFREE(&nd, 0);
3609 if (error) {
3610 if (filename_vp != NULL)
3611 vput(filename_vp);
3612 return (error);
3613 }
3614
3615 error = VFS_EXTATTRCTL(mp, uap->cmd, filename_vp, uap->attrnamespace,
3616 uap->attrname != NULL ? attrname : NULL, td);
3617
3618 vn_finished_write(mp_writable);
3619 /*
3620 * VFS_EXTATTRCTL will have unlocked, but not de-ref'd,
3621 * filename_vp, so vrele it if it is defined.
3622 */
3623 if (filename_vp != NULL)
3624 vrele(filename_vp);
3625
3626 return (error);
3627}
3628
3629/*-
3630 * Set a named extended attribute on a file or directory
3631 *
3632 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
3633 * kernelspace string pointer "attrname", userspace buffer
3634 * pointer "data", buffer length "nbytes", thread "td".
3635 * Returns: 0 on success, an error number otherwise
3636 * Locks: none
3637 * References: vp must be a valid reference for the duration of the call
3638 */
3639static int
3640extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
3641 void *data, size_t nbytes, struct thread *td)
3642{
3643 struct mount *mp;
3644 struct uio auio;
3645 struct iovec aiov;
3646 ssize_t cnt;
3647 int error;
3648
3649 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
3650 return (error);
3651 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
3652 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
3653
3654 aiov.iov_base = data;
3655 aiov.iov_len = nbytes;
3656 auio.uio_iov = &aiov;
3657 auio.uio_iovcnt = 1;
3658 auio.uio_offset = 0;
3659 if (nbytes > INT_MAX) {
3660 error = EINVAL;
3661 goto done;
3662 }
3663 auio.uio_resid = nbytes;
3664 auio.uio_rw = UIO_WRITE;
3665 auio.uio_segflg = UIO_USERSPACE;
3666 auio.uio_td = td;
3667 cnt = nbytes;
3668
3669#ifdef MAC
3670 error = mac_check_vnode_setextattr(td->td_ucred, vp, attrnamespace,
3671 attrname, &auio);
3672 if (error)
3673 goto done;
3674#endif
3675
3676 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio,
3677 td->td_ucred, td);
3678 cnt -= auio.uio_resid;
3679 td->td_retval[0] = cnt;
3680
3681done:
3682 VOP_UNLOCK(vp, 0, td);
3683 vn_finished_write(mp);
3684 return (error);
3685}
3686
3687int
3688extattr_set_file(td, uap)
3689 struct thread *td;
3690 struct extattr_set_file_args /* {
3691 syscallarg(const char *) path;
3692 syscallarg(int) attrnamespace;
3693 syscallarg(const char *) attrname;
3694 syscallarg(void *) data;
3695 syscallarg(size_t) nbytes;
3696 } */ *uap;
3697{
3698 struct nameidata nd;
3699 char attrname[EXTATTR_MAXNAMELEN];
3700 int error;
3701
3702 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
3703 if (error)
3704 return (error);
3705
3706 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
3707 if ((error = namei(&nd)) != 0)
3708 return (error);
3709 NDFREE(&nd, NDF_ONLY_PNBUF);
3710
3711 error = extattr_set_vp(nd.ni_vp, uap->attrnamespace, attrname,
3712 uap->data, uap->nbytes, td);
3713
3714 vrele(nd.ni_vp);
3715 return (error);
3716}
3717
3718int
3719extattr_set_fd(td, uap)
3720 struct thread *td;
3721 struct extattr_set_fd_args /* {
3722 syscallarg(int) fd;
3723 syscallarg(int) attrnamespace;
3724 syscallarg(const char *) attrname;
3725 syscallarg(void *) data;
3726 syscallarg(size_t) nbytes;
3727 } */ *uap;
3728{
3729 struct file *fp;
3730 char attrname[EXTATTR_MAXNAMELEN];
3731 int error;
3732
3733 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
3734 if (error)
3735 return (error);
3736
3737 if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0)
3738 return (error);
3739
3740 error = extattr_set_vp((struct vnode *)fp->f_data, uap->attrnamespace,
3741 attrname, uap->data, uap->nbytes, td);
3742 fdrop(fp, td);
3743
3744 return (error);
3745}
3746
3747/*-
3748 * Get a named extended attribute on a file or directory
3749 *
3750 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
3751 * kernelspace string pointer "attrname", userspace buffer
3752 * pointer "data", buffer length "nbytes", thread "td".
3753 * Returns: 0 on success, an error number otherwise
3754 * Locks: none
3755 * References: vp must be a valid reference for the duration of the call
3756 */
3757static int
3758extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname,
3759 void *data, size_t nbytes, struct thread *td)
3760{
3761 struct uio auio, *auiop;
3762 struct iovec aiov;
3763 ssize_t cnt;
3764 size_t size, *sizep;
3765 int error;
3766
3767 VOP_LEASE(vp, td, td->td_ucred, LEASE_READ);
3768 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
3769
3770 /*
3771 * Slightly unusual semantics: if the user provides a NULL data
3772 * pointer, they don't want to receive the data, just the
3773 * maximum read length.
3774 */
3775 auiop = NULL;
3776 sizep = NULL;
3777 cnt = 0;
3778 if (data != NULL) {
3779 aiov.iov_base = data;
3780 aiov.iov_len = nbytes;
3781 auio.uio_iov = &aiov;
3782 auio.uio_offset = 0;
3783 if (nbytes > INT_MAX) {
3784 error = EINVAL;
3785 goto done;
3786 }
3787 auio.uio_resid = nbytes;
3788 auio.uio_rw = UIO_READ;
3789 auio.uio_segflg = UIO_USERSPACE;
3790 auio.uio_td = td;
3791 auiop = &auio;
3792 cnt = nbytes;
3793 } else
3794 sizep = &size;
3795
3796#ifdef MAC
3797 error = mac_check_vnode_getextattr(td->td_ucred, vp, attrnamespace,
3798 attrname, &auio);
3799 if (error)
3800 goto done;
3801#endif
3802
3803 error = VOP_GETEXTATTR(vp, attrnamespace, attrname, auiop, sizep,
3804 td->td_ucred, td);
3805
3806 if (auiop != NULL) {
3807 cnt -= auio.uio_resid;
3808 td->td_retval[0] = cnt;
3809 } else
3810 td->td_retval[0] = size;
3811
3812done:
3813 VOP_UNLOCK(vp, 0, td);
3814 return (error);
3815}
3816
3817int
3818extattr_get_file(td, uap)
3819 struct thread *td;
3820 struct extattr_get_file_args /* {
3821 syscallarg(const char *) path;
3822 syscallarg(int) attrnamespace;
3823 syscallarg(const char *) attrname;
3824 syscallarg(void *) data;
3825 syscallarg(size_t) nbytes;
3826 } */ *uap;
3827{
3828 struct nameidata nd;
3829 char attrname[EXTATTR_MAXNAMELEN];
3830 int error;
3831
3832 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
3833 if (error)
3834 return (error);
3835
3836 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
3837 if ((error = namei(&nd)) != 0)
3838 return (error);
3839 NDFREE(&nd, NDF_ONLY_PNBUF);
3840
3841 error = extattr_get_vp(nd.ni_vp, uap->attrnamespace, attrname,
3842 uap->data, uap->nbytes, td);
3843
3844 vrele(nd.ni_vp);
3845 return (error);
3846}
3847
3848int
3849extattr_get_fd(td, uap)
3850 struct thread *td;
3851 struct extattr_get_fd_args /* {
3852 syscallarg(int) fd;
3853 syscallarg(int) attrnamespace;
3854 syscallarg(const char *) attrname;
3855 syscallarg(void *) data;
3856 syscallarg(size_t) nbytes;
3857 } */ *uap;
3858{
3859 struct file *fp;
3860 char attrname[EXTATTR_MAXNAMELEN];
3861 int error;
3862
3863 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
3864 if (error)
3865 return (error);
3866
3867 if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0)
3868 return (error);
3869
3870 error = extattr_get_vp((struct vnode *)fp->f_data, uap->attrnamespace,
3871 attrname, uap->data, uap->nbytes, td);
3872
3873 fdrop(fp, td);
3874 return (error);
3875}
3876
3877/*
3878 * extattr_delete_vp(): Delete a named extended attribute on a file or
3879 * directory
3880 *
3881 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
3882 * kernelspace string pointer "attrname", proc "p"
3883 * Returns: 0 on success, an error number otherwise
3884 * Locks: none
3885 * References: vp must be a valid reference for the duration of the call
3886 */
3887static int
3888extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname,
3889 struct thread *td)
3890{
3891 struct mount *mp;
3892 int error;
3893
3894 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
3895 return (error);
3896 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
3897 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
3898
3899#ifdef MAC
3900 error = mac_check_vnode_setextattr(td->td_ucred, vp, attrnamespace,
3901 attrname, NULL);
3902#endif
3903
3904 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL, td->td_ucred,
3905 td);
3906
3907 VOP_UNLOCK(vp, 0, td);
3908 vn_finished_write(mp);
3909 return (error);
3910}
3911
3912int
3913extattr_delete_file(td, uap)
3914 struct thread *td;
3915 struct extattr_delete_file_args /* {
3916 syscallarg(const char *) path;
3917 syscallarg(int) attrnamespace;
3918 syscallarg(const char *) attrname;
3919 } */ *uap;
3920{
3921 struct nameidata nd;
3922 char attrname[EXTATTR_MAXNAMELEN];
3923 int error;
3924
3925 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
3926 if (error)
3927 return(error);
3928
3929 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
3930 if ((error = namei(&nd)) != 0)
3931 return(error);
3932 NDFREE(&nd, NDF_ONLY_PNBUF);
3933
3934 error = extattr_delete_vp(nd.ni_vp, uap->attrnamespace, attrname, td);
3935
3936 vrele(nd.ni_vp);
3937 return(error);
3938}
3939
3940int
3941extattr_delete_fd(td, uap)
3942 struct thread *td;
3943 struct extattr_delete_fd_args /* {
3944 syscallarg(int) fd;
3945 syscallarg(int) attrnamespace;
3946 syscallarg(const char *) attrname;
3947 } */ *uap;
3948{
3949 struct file *fp;
3950 struct vnode *vp;
3951 char attrname[EXTATTR_MAXNAMELEN];
3952 int error;
3953
3954 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
3955 if (error)
3956 return (error);
3957
3958 if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0)
3959 return (error);
3960 vp = (struct vnode *)fp->f_data;
3961
3962 error = extattr_delete_vp(vp, uap->attrnamespace, attrname, td);
3963
3964 fdrop(fp, td);
3965 return (error);
3966}
3346 if (error == 0) {
3347#endif
3348 VATTR_NULL(vap);
3349 vap->va_size = 0;
3350 error = VOP_SETATTR(vp, vap, td->td_ucred, td);
3351#ifdef MAC
3352 }
3353#endif
3354 vn_finished_write(mp);
3355 if (error)
3356 goto bad;
3357 }
3358 error = VOP_OPEN(vp, fmode, td->td_ucred, td);
3359 if (error)
3360 goto bad;
3361 /*
3362 * Make sure that a VM object is created for VMIO support.
3363 */
3364 if (vn_canvmio(vp) == TRUE) {
3365 if ((error = vfs_object_create(vp, td, td->td_ucred)) != 0)
3366 goto bad;
3367 }
3368 if (fmode & FWRITE)
3369 vp->v_writecount++;
3370
3371 /*
3372 * end of vn_open code
3373 */
3374
3375 if ((error = falloc(td, &nfp, &indx)) != 0) {
3376 if (fmode & FWRITE)
3377 vp->v_writecount--;
3378 goto bad;
3379 }
3380 fp = nfp;
3381
3382 /*
3383 * Hold an extra reference to avoid having fp ripped out
3384 * from under us while we block in the lock op
3385 */
3386 fhold(fp);
3387 nfp->f_data = vp;
3388 nfp->f_flag = fmode & FMASK;
3389 nfp->f_ops = &vnops;
3390 nfp->f_type = DTYPE_VNODE;
3391 if (fmode & (O_EXLOCK | O_SHLOCK)) {
3392 lf.l_whence = SEEK_SET;
3393 lf.l_start = 0;
3394 lf.l_len = 0;
3395 if (fmode & O_EXLOCK)
3396 lf.l_type = F_WRLCK;
3397 else
3398 lf.l_type = F_RDLCK;
3399 type = F_FLOCK;
3400 if ((fmode & FNONBLOCK) == 0)
3401 type |= F_WAIT;
3402 VOP_UNLOCK(vp, 0, td);
3403 if ((error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf,
3404 type)) != 0) {
3405 /*
3406 * The lock request failed. Normally close the
3407 * descriptor but handle the case where someone might
3408 * have dup()d or close()d it when we weren't looking.
3409 */
3410 FILEDESC_LOCK(fdp);
3411 if (fdp->fd_ofiles[indx] == fp) {
3412 fdp->fd_ofiles[indx] = NULL;
3413 FILEDESC_UNLOCK(fdp);
3414 fdrop(fp, td);
3415 } else
3416 FILEDESC_UNLOCK(fdp);
3417 /*
3418 * release our private reference
3419 */
3420 fdrop(fp, td);
3421 return(error);
3422 }
3423 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
3424 fp->f_flag |= FHASLOCK;
3425 }
3426 if ((vp->v_type == VREG) && (VOP_GETVOBJECT(vp, NULL) != 0))
3427 vfs_object_create(vp, td, td->td_ucred);
3428
3429 VOP_UNLOCK(vp, 0, td);
3430 fdrop(fp, td);
3431 td->td_retval[0] = indx;
3432 return (0);
3433
3434bad:
3435 vput(vp);
3436 return (error);
3437}
3438
3439/*
3440 * Stat an (NFS) file handle.
3441 */
3442#ifndef _SYS_SYSPROTO_H_
3443struct fhstat_args {
3444 struct fhandle *u_fhp;
3445 struct stat *sb;
3446};
3447#endif
3448int
3449fhstat(td, uap)
3450 struct thread *td;
3451 register struct fhstat_args /* {
3452 syscallarg(struct fhandle *) u_fhp;
3453 syscallarg(struct stat *) sb;
3454 } */ *uap;
3455{
3456 struct stat sb;
3457 fhandle_t fh;
3458 struct mount *mp;
3459 struct vnode *vp;
3460 int error;
3461
3462 /*
3463 * Must be super user
3464 */
3465 error = suser(td);
3466 if (error)
3467 return (error);
3468
3469 error = copyin(SCARG(uap, u_fhp), &fh, sizeof(fhandle_t));
3470 if (error)
3471 return (error);
3472
3473 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
3474 return (ESTALE);
3475 if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
3476 return (error);
3477 error = vn_stat(vp, &sb, td->td_ucred, NOCRED, td);
3478 vput(vp);
3479 if (error)
3480 return (error);
3481 error = copyout(&sb, SCARG(uap, sb), sizeof(sb));
3482 return (error);
3483}
3484
3485/*
3486 * Implement fstatfs() for (NFS) file handles.
3487 */
3488#ifndef _SYS_SYSPROTO_H_
3489struct fhstatfs_args {
3490 struct fhandle *u_fhp;
3491 struct statfs *buf;
3492};
3493#endif
3494int
3495fhstatfs(td, uap)
3496 struct thread *td;
3497 struct fhstatfs_args /* {
3498 syscallarg(struct fhandle) *u_fhp;
3499 syscallarg(struct statfs) *buf;
3500 } */ *uap;
3501{
3502 struct statfs *sp;
3503 struct mount *mp;
3504 struct vnode *vp;
3505 struct statfs sb;
3506 fhandle_t fh;
3507 int error;
3508
3509 /*
3510 * Must be super user
3511 */
3512 error = suser(td);
3513 if (error)
3514 return (error);
3515
3516 if ((error = copyin(SCARG(uap, u_fhp), &fh, sizeof(fhandle_t))) != 0)
3517 return (error);
3518
3519 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
3520 return (ESTALE);
3521 if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
3522 return (error);
3523 mp = vp->v_mount;
3524 sp = &mp->mnt_stat;
3525 vput(vp);
3526#ifdef MAC
3527 error = mac_check_mount_stat(td->td_ucred, mp);
3528 if (error)
3529 return (error);
3530#endif
3531 if ((error = VFS_STATFS(mp, sp, td)) != 0)
3532 return (error);
3533 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
3534 if (suser(td)) {
3535 bcopy(sp, &sb, sizeof(sb));
3536 sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
3537 sp = &sb;
3538 }
3539 return (copyout(sp, SCARG(uap, buf), sizeof(*sp)));
3540}
3541
3542/*
3543 * Syscall to push extended attribute configuration information into the
3544 * VFS. Accepts a path, which it converts to a mountpoint, as well as
3545 * a command (int cmd), and attribute name and misc data. For now, the
3546 * attribute name is left in userspace for consumption by the VFS_op.
3547 * It will probably be changed to be copied into sysspace by the
3548 * syscall in the future, once issues with various consumers of the
3549 * attribute code have raised their hands.
3550 *
3551 * Currently this is used only by UFS Extended Attributes.
3552 */
3553int
3554extattrctl(td, uap)
3555 struct thread *td;
3556 struct extattrctl_args /* {
3557 syscallarg(const char *) path;
3558 syscallarg(int) cmd;
3559 syscallarg(const char *) filename;
3560 syscallarg(int) attrnamespace;
3561 syscallarg(const char *) attrname;
3562 } */ *uap;
3563{
3564 struct vnode *filename_vp;
3565 struct nameidata nd;
3566 struct mount *mp, *mp_writable;
3567 char attrname[EXTATTR_MAXNAMELEN];
3568 int error;
3569
3570 /*
3571 * uap->attrname is not always defined. We check again later when we
3572 * invoke the VFS call so as to pass in NULL there if needed.
3573 */
3574 if (uap->attrname != NULL) {
3575 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN,
3576 NULL);
3577 if (error)
3578 return (error);
3579 }
3580
3581 /*
3582 * uap->filename is not always defined. If it is, grab a vnode lock,
3583 * which VFS_EXTATTRCTL() will later release.
3584 */
3585 filename_vp = NULL;
3586 if (uap->filename != NULL) {
3587 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
3588 uap->filename, td);
3589 if ((error = namei(&nd)) != 0)
3590 return (error);
3591 filename_vp = nd.ni_vp;
3592 NDFREE(&nd, NDF_NO_VP_RELE | NDF_NO_VP_UNLOCK);
3593 }
3594
3595 /* uap->path is always defined. */
3596 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
3597 if ((error = namei(&nd)) != 0) {
3598 if (filename_vp != NULL)
3599 vput(filename_vp);
3600 return (error);
3601 }
3602 mp = nd.ni_vp->v_mount;
3603 error = vn_start_write(nd.ni_vp, &mp_writable, V_WAIT | PCATCH);
3604 NDFREE(&nd, 0);
3605 if (error) {
3606 if (filename_vp != NULL)
3607 vput(filename_vp);
3608 return (error);
3609 }
3610
3611 error = VFS_EXTATTRCTL(mp, uap->cmd, filename_vp, uap->attrnamespace,
3612 uap->attrname != NULL ? attrname : NULL, td);
3613
3614 vn_finished_write(mp_writable);
3615 /*
3616 * VFS_EXTATTRCTL will have unlocked, but not de-ref'd,
3617 * filename_vp, so vrele it if it is defined.
3618 */
3619 if (filename_vp != NULL)
3620 vrele(filename_vp);
3621
3622 return (error);
3623}
3624
3625/*-
3626 * Set a named extended attribute on a file or directory
3627 *
3628 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
3629 * kernelspace string pointer "attrname", userspace buffer
3630 * pointer "data", buffer length "nbytes", thread "td".
3631 * Returns: 0 on success, an error number otherwise
3632 * Locks: none
3633 * References: vp must be a valid reference for the duration of the call
3634 */
3635static int
3636extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
3637 void *data, size_t nbytes, struct thread *td)
3638{
3639 struct mount *mp;
3640 struct uio auio;
3641 struct iovec aiov;
3642 ssize_t cnt;
3643 int error;
3644
3645 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
3646 return (error);
3647 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
3648 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
3649
3650 aiov.iov_base = data;
3651 aiov.iov_len = nbytes;
3652 auio.uio_iov = &aiov;
3653 auio.uio_iovcnt = 1;
3654 auio.uio_offset = 0;
3655 if (nbytes > INT_MAX) {
3656 error = EINVAL;
3657 goto done;
3658 }
3659 auio.uio_resid = nbytes;
3660 auio.uio_rw = UIO_WRITE;
3661 auio.uio_segflg = UIO_USERSPACE;
3662 auio.uio_td = td;
3663 cnt = nbytes;
3664
3665#ifdef MAC
3666 error = mac_check_vnode_setextattr(td->td_ucred, vp, attrnamespace,
3667 attrname, &auio);
3668 if (error)
3669 goto done;
3670#endif
3671
3672 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio,
3673 td->td_ucred, td);
3674 cnt -= auio.uio_resid;
3675 td->td_retval[0] = cnt;
3676
3677done:
3678 VOP_UNLOCK(vp, 0, td);
3679 vn_finished_write(mp);
3680 return (error);
3681}
3682
3683int
3684extattr_set_file(td, uap)
3685 struct thread *td;
3686 struct extattr_set_file_args /* {
3687 syscallarg(const char *) path;
3688 syscallarg(int) attrnamespace;
3689 syscallarg(const char *) attrname;
3690 syscallarg(void *) data;
3691 syscallarg(size_t) nbytes;
3692 } */ *uap;
3693{
3694 struct nameidata nd;
3695 char attrname[EXTATTR_MAXNAMELEN];
3696 int error;
3697
3698 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
3699 if (error)
3700 return (error);
3701
3702 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
3703 if ((error = namei(&nd)) != 0)
3704 return (error);
3705 NDFREE(&nd, NDF_ONLY_PNBUF);
3706
3707 error = extattr_set_vp(nd.ni_vp, uap->attrnamespace, attrname,
3708 uap->data, uap->nbytes, td);
3709
3710 vrele(nd.ni_vp);
3711 return (error);
3712}
3713
3714int
3715extattr_set_fd(td, uap)
3716 struct thread *td;
3717 struct extattr_set_fd_args /* {
3718 syscallarg(int) fd;
3719 syscallarg(int) attrnamespace;
3720 syscallarg(const char *) attrname;
3721 syscallarg(void *) data;
3722 syscallarg(size_t) nbytes;
3723 } */ *uap;
3724{
3725 struct file *fp;
3726 char attrname[EXTATTR_MAXNAMELEN];
3727 int error;
3728
3729 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
3730 if (error)
3731 return (error);
3732
3733 if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0)
3734 return (error);
3735
3736 error = extattr_set_vp((struct vnode *)fp->f_data, uap->attrnamespace,
3737 attrname, uap->data, uap->nbytes, td);
3738 fdrop(fp, td);
3739
3740 return (error);
3741}
3742
3743/*-
3744 * Get a named extended attribute on a file or directory
3745 *
3746 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
3747 * kernelspace string pointer "attrname", userspace buffer
3748 * pointer "data", buffer length "nbytes", thread "td".
3749 * Returns: 0 on success, an error number otherwise
3750 * Locks: none
3751 * References: vp must be a valid reference for the duration of the call
3752 */
3753static int
3754extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname,
3755 void *data, size_t nbytes, struct thread *td)
3756{
3757 struct uio auio, *auiop;
3758 struct iovec aiov;
3759 ssize_t cnt;
3760 size_t size, *sizep;
3761 int error;
3762
3763 VOP_LEASE(vp, td, td->td_ucred, LEASE_READ);
3764 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
3765
3766 /*
3767 * Slightly unusual semantics: if the user provides a NULL data
3768 * pointer, they don't want to receive the data, just the
3769 * maximum read length.
3770 */
3771 auiop = NULL;
3772 sizep = NULL;
3773 cnt = 0;
3774 if (data != NULL) {
3775 aiov.iov_base = data;
3776 aiov.iov_len = nbytes;
3777 auio.uio_iov = &aiov;
3778 auio.uio_offset = 0;
3779 if (nbytes > INT_MAX) {
3780 error = EINVAL;
3781 goto done;
3782 }
3783 auio.uio_resid = nbytes;
3784 auio.uio_rw = UIO_READ;
3785 auio.uio_segflg = UIO_USERSPACE;
3786 auio.uio_td = td;
3787 auiop = &auio;
3788 cnt = nbytes;
3789 } else
3790 sizep = &size;
3791
3792#ifdef MAC
3793 error = mac_check_vnode_getextattr(td->td_ucred, vp, attrnamespace,
3794 attrname, &auio);
3795 if (error)
3796 goto done;
3797#endif
3798
3799 error = VOP_GETEXTATTR(vp, attrnamespace, attrname, auiop, sizep,
3800 td->td_ucred, td);
3801
3802 if (auiop != NULL) {
3803 cnt -= auio.uio_resid;
3804 td->td_retval[0] = cnt;
3805 } else
3806 td->td_retval[0] = size;
3807
3808done:
3809 VOP_UNLOCK(vp, 0, td);
3810 return (error);
3811}
3812
3813int
3814extattr_get_file(td, uap)
3815 struct thread *td;
3816 struct extattr_get_file_args /* {
3817 syscallarg(const char *) path;
3818 syscallarg(int) attrnamespace;
3819 syscallarg(const char *) attrname;
3820 syscallarg(void *) data;
3821 syscallarg(size_t) nbytes;
3822 } */ *uap;
3823{
3824 struct nameidata nd;
3825 char attrname[EXTATTR_MAXNAMELEN];
3826 int error;
3827
3828 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
3829 if (error)
3830 return (error);
3831
3832 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
3833 if ((error = namei(&nd)) != 0)
3834 return (error);
3835 NDFREE(&nd, NDF_ONLY_PNBUF);
3836
3837 error = extattr_get_vp(nd.ni_vp, uap->attrnamespace, attrname,
3838 uap->data, uap->nbytes, td);
3839
3840 vrele(nd.ni_vp);
3841 return (error);
3842}
3843
3844int
3845extattr_get_fd(td, uap)
3846 struct thread *td;
3847 struct extattr_get_fd_args /* {
3848 syscallarg(int) fd;
3849 syscallarg(int) attrnamespace;
3850 syscallarg(const char *) attrname;
3851 syscallarg(void *) data;
3852 syscallarg(size_t) nbytes;
3853 } */ *uap;
3854{
3855 struct file *fp;
3856 char attrname[EXTATTR_MAXNAMELEN];
3857 int error;
3858
3859 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
3860 if (error)
3861 return (error);
3862
3863 if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0)
3864 return (error);
3865
3866 error = extattr_get_vp((struct vnode *)fp->f_data, uap->attrnamespace,
3867 attrname, uap->data, uap->nbytes, td);
3868
3869 fdrop(fp, td);
3870 return (error);
3871}
3872
3873/*
3874 * extattr_delete_vp(): Delete a named extended attribute on a file or
3875 * directory
3876 *
3877 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
3878 * kernelspace string pointer "attrname", proc "p"
3879 * Returns: 0 on success, an error number otherwise
3880 * Locks: none
3881 * References: vp must be a valid reference for the duration of the call
3882 */
3883static int
3884extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname,
3885 struct thread *td)
3886{
3887 struct mount *mp;
3888 int error;
3889
3890 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
3891 return (error);
3892 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
3893 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
3894
3895#ifdef MAC
3896 error = mac_check_vnode_setextattr(td->td_ucred, vp, attrnamespace,
3897 attrname, NULL);
3898#endif
3899
3900 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL, td->td_ucred,
3901 td);
3902
3903 VOP_UNLOCK(vp, 0, td);
3904 vn_finished_write(mp);
3905 return (error);
3906}
3907
3908int
3909extattr_delete_file(td, uap)
3910 struct thread *td;
3911 struct extattr_delete_file_args /* {
3912 syscallarg(const char *) path;
3913 syscallarg(int) attrnamespace;
3914 syscallarg(const char *) attrname;
3915 } */ *uap;
3916{
3917 struct nameidata nd;
3918 char attrname[EXTATTR_MAXNAMELEN];
3919 int error;
3920
3921 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
3922 if (error)
3923 return(error);
3924
3925 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
3926 if ((error = namei(&nd)) != 0)
3927 return(error);
3928 NDFREE(&nd, NDF_ONLY_PNBUF);
3929
3930 error = extattr_delete_vp(nd.ni_vp, uap->attrnamespace, attrname, td);
3931
3932 vrele(nd.ni_vp);
3933 return(error);
3934}
3935
3936int
3937extattr_delete_fd(td, uap)
3938 struct thread *td;
3939 struct extattr_delete_fd_args /* {
3940 syscallarg(int) fd;
3941 syscallarg(int) attrnamespace;
3942 syscallarg(const char *) attrname;
3943 } */ *uap;
3944{
3945 struct file *fp;
3946 struct vnode *vp;
3947 char attrname[EXTATTR_MAXNAMELEN];
3948 int error;
3949
3950 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
3951 if (error)
3952 return (error);
3953
3954 if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0)
3955 return (error);
3956 vp = (struct vnode *)fp->f_data;
3957
3958 error = extattr_delete_vp(vp, uap->attrnamespace, attrname, td);
3959
3960 fdrop(fp, td);
3961 return (error);
3962}