source: rtems-libbsd/freebsd/sys/kern/vfs_syscalls.c @ 6e4709b

6-freebsd-12
Last change on this file since 6e4709b was 6e4709b, checked in by Sebastian Huber <sebastian.huber@…>, on 01/05/23 at 16:42:48

vfs/nfs: Revert white space changes

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