source: rtems-libbsd/freebsd/sys/kern/vfs_syscalls.c @ 6514d56

6-freebsd-12
Last change on this file since 6514d56 was 6514d56, checked in by Chris Johns <chrisj@…>, on 08/02/21 at 05:09:41

sys/kern: Add VFS support

  • Refactor the libio interface
  • Move syscalls into an rtemsbsd location
  • Provide a root directory mount point

Update #4475

  • 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
3540        NDINIT_ATRIGHTS(&fromnd, DELETE, WANTPARENT | SAVESTART | AUDITVNODE1,
3541            pathseg, old, oldfd,
3542            &cap_renameat_source_rights, td);
3543#endif
3544
3545        if ((error = namei(&fromnd)) != 0)
3546                return (error);
3547#ifdef MAC
3548        error = mac_vnode_check_rename_from(td->td_ucred, fromnd.ni_dvp,
3549            fromnd.ni_vp, &fromnd.ni_cnd);
3550        VOP_UNLOCK(fromnd.ni_dvp, 0);
3551        if (fromnd.ni_dvp != fromnd.ni_vp)
3552                VOP_UNLOCK(fromnd.ni_vp, 0);
3553#endif
3554        fvp = fromnd.ni_vp;
3555        NDINIT_ATRIGHTS(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE |
3556            SAVESTART | AUDITVNODE2, pathseg, new, newfd,
3557            &cap_renameat_target_rights, td);
3558        if (fromnd.ni_vp->v_type == VDIR)
3559                tond.ni_cnd.cn_flags |= WILLBEDIR;
3560        if ((error = namei(&tond)) != 0) {
3561                /* Translate error code for rename("dir1", "dir2/."). */
3562                if (error == EISDIR && fvp->v_type == VDIR)
3563                        error = EINVAL;
3564                NDFREE(&fromnd, NDF_ONLY_PNBUF);
3565                vrele(fromnd.ni_dvp);
3566                vrele(fvp);
3567                goto out1;
3568        }
3569        tdvp = tond.ni_dvp;
3570        tvp = tond.ni_vp;
3571        error = vn_start_write(fvp, &mp, V_NOWAIT);
3572        if (error != 0) {
3573                NDFREE(&fromnd, NDF_ONLY_PNBUF);
3574                NDFREE(&tond, NDF_ONLY_PNBUF);
3575                if (tvp != NULL)
3576                        vput(tvp);
3577                if (tdvp == tvp)
3578                        vrele(tdvp);
3579                else
3580                        vput(tdvp);
3581                vrele(fromnd.ni_dvp);
3582                vrele(fvp);
3583                vrele(tond.ni_startdir);
3584                if (fromnd.ni_startdir != NULL)
3585                        vrele(fromnd.ni_startdir);
3586                error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH);
3587                if (error != 0)
3588                        return (error);
3589                goto again;
3590        }
3591        if (tvp != NULL) {
3592                if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
3593                        error = ENOTDIR;
3594                        goto out;
3595                } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
3596                        error = EISDIR;
3597                        goto out;
3598                }
3599#ifdef CAPABILITIES
3600                if (newfd != AT_FDCWD && (tond.ni_resflags & NIRES_ABS) == 0) {
3601                        /*
3602                         * If the target already exists we require CAP_UNLINKAT
3603                         * from 'newfd', when newfd was used for the lookup.
3604                         */
3605                        error = cap_check(&tond.ni_filecaps.fc_rights,
3606                            &cap_unlinkat_rights);
3607                        if (error != 0)
3608                                goto out;
3609                }
3610#endif
3611        }
3612        if (fvp == tdvp) {
3613                error = EINVAL;
3614                goto out;
3615        }
3616        /*
3617         * If the source is the same as the destination (that is, if they
3618         * are links to the same vnode), then there is nothing to do.
3619         */
3620        if (fvp == tvp)
3621                error = -1;
3622#ifdef MAC
3623        else
3624                error = mac_vnode_check_rename_to(td->td_ucred, tdvp,
3625                    tond.ni_vp, fromnd.ni_dvp == tdvp, &tond.ni_cnd);
3626#endif
3627out:
3628        if (error == 0) {
3629                error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
3630                    tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
3631                NDFREE(&fromnd, NDF_ONLY_PNBUF);
3632                NDFREE(&tond, NDF_ONLY_PNBUF);
3633        } else {
3634                NDFREE(&fromnd, NDF_ONLY_PNBUF);
3635                NDFREE(&tond, NDF_ONLY_PNBUF);
3636                if (tvp != NULL)
3637                        vput(tvp);
3638                if (tdvp == tvp)
3639                        vrele(tdvp);
3640                else
3641                        vput(tdvp);
3642                vrele(fromnd.ni_dvp);
3643                vrele(fvp);
3644        }
3645        vrele(tond.ni_startdir);
3646        vn_finished_write(mp);
3647out1:
3648        if (fromnd.ni_startdir)
3649                vrele(fromnd.ni_startdir);
3650        if (error == -1)
3651                return (0);
3652        return (error);
3653}
3654
3655/*
3656 * Make a directory file.
3657 */
3658#ifndef _SYS_SYSPROTO_H_
3659struct mkdir_args {
3660        char    *path;
3661        int     mode;
3662};
3663#endif
3664int
3665sys_mkdir(struct thread *td, struct mkdir_args *uap)
3666{
3667
3668        return (kern_mkdirat(td, AT_FDCWD, uap->path, UIO_USERSPACE,
3669            uap->mode));
3670}
3671
3672#ifndef _SYS_SYSPROTO_H_
3673struct mkdirat_args {
3674        int     fd;
3675        char    *path;
3676        mode_t  mode;
3677};
3678#endif
3679int
3680sys_mkdirat(struct thread *td, struct mkdirat_args *uap)
3681{
3682
3683        return (kern_mkdirat(td, uap->fd, uap->path, UIO_USERSPACE, uap->mode));
3684}
3685
3686int
3687kern_mkdirat(struct thread *td, int fd, char *path, enum uio_seg segflg,
3688    int mode)
3689{
3690        struct mount *mp;
3691        struct vnode *vp;
3692        struct vattr vattr;
3693        struct nameidata nd;
3694        int error;
3695
3696        AUDIT_ARG_MODE(mode);
3697restart:
3698        bwillwrite();
3699        NDINIT_ATRIGHTS(&nd, CREATE, LOCKPARENT | SAVENAME | AUDITVNODE1 |
3700            NOCACHE, segflg, path, fd, &cap_mkdirat_rights,
3701            td);
3702        nd.ni_cnd.cn_flags |= WILLBEDIR;
3703        if ((error = namei(&nd)) != 0)
3704                return (error);
3705        vp = nd.ni_vp;
3706        if (vp != NULL) {
3707                NDFREE(&nd, NDF_ONLY_PNBUF);
3708                /*
3709                 * XXX namei called with LOCKPARENT but not LOCKLEAF has
3710                 * the strange behaviour of leaving the vnode unlocked
3711                 * if the target is the same vnode as the parent.
3712                 */
3713                if (vp == nd.ni_dvp)
3714                        vrele(nd.ni_dvp);
3715                else
3716                        vput(nd.ni_dvp);
3717                vrele(vp);
3718                return (EEXIST);
3719        }
3720        if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
3721                NDFREE(&nd, NDF_ONLY_PNBUF);
3722                vput(nd.ni_dvp);
3723                if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
3724                        return (error);
3725                goto restart;
3726        }
3727        VATTR_NULL(&vattr);
3728        vattr.va_type = VDIR;
3729        vattr.va_mode = (mode & ACCESSPERMS) &~ td->td_proc->p_fd->fd_cmask;
3730#ifdef MAC
3731        error = mac_vnode_check_create(td->td_ucred, nd.ni_dvp, &nd.ni_cnd,
3732            &vattr);
3733        if (error != 0)
3734                goto out;
3735#endif
3736        error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
3737#ifdef MAC
3738out:
3739#endif
3740        NDFREE(&nd, NDF_ONLY_PNBUF);
3741        vput(nd.ni_dvp);
3742        if (error == 0)
3743                vput(nd.ni_vp);
3744        vn_finished_write(mp);
3745        return (error);
3746}
3747
3748/*
3749 * Remove a directory file.
3750 */
3751#ifndef _SYS_SYSPROTO_H_
3752struct rmdir_args {
3753        char    *path;
3754};
3755#endif
3756int
3757sys_rmdir(struct thread *td, struct rmdir_args *uap)
3758{
3759
3760        return (kern_rmdirat(td, AT_FDCWD, uap->path, UIO_USERSPACE));
3761}
3762
3763int
3764kern_rmdirat(struct thread *td, int fd, char *path, enum uio_seg pathseg)
3765{
3766        struct mount *mp;
3767        struct vnode *vp;
3768        struct nameidata nd;
3769        int error;
3770
3771restart:
3772        bwillwrite();
3773        NDINIT_ATRIGHTS(&nd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNODE1,
3774            pathseg, path, fd, &cap_unlinkat_rights, td);
3775        if ((error = namei(&nd)) != 0)
3776                return (error);
3777        vp = nd.ni_vp;
3778        if (vp->v_type != VDIR) {
3779                error = ENOTDIR;
3780                goto out;
3781        }
3782        /*
3783         * No rmdir "." please.
3784         */
3785        if (nd.ni_dvp == vp) {
3786                error = EINVAL;
3787                goto out;
3788        }
3789        /*
3790         * The root of a mounted filesystem cannot be deleted.
3791         */
3792        if (vp->v_vflag & VV_ROOT) {
3793                error = EBUSY;
3794                goto out;
3795        }
3796#ifdef MAC
3797        error = mac_vnode_check_unlink(td->td_ucred, nd.ni_dvp, vp,
3798            &nd.ni_cnd);
3799        if (error != 0)
3800                goto out;
3801#endif
3802        if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
3803                NDFREE(&nd, NDF_ONLY_PNBUF);
3804                vput(vp);
3805                if (nd.ni_dvp == vp)
3806                        vrele(nd.ni_dvp);
3807                else
3808                        vput(nd.ni_dvp);
3809                if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
3810                        return (error);
3811                goto restart;
3812        }
3813        vfs_notify_upper(vp, VFS_NOTIFY_UPPER_UNLINK);
3814        error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
3815        vn_finished_write(mp);
3816out:
3817        NDFREE(&nd, NDF_ONLY_PNBUF);
3818        vput(vp);
3819        if (nd.ni_dvp == vp)
3820                vrele(nd.ni_dvp);
3821        else
3822                vput(nd.ni_dvp);
3823        return (error);
3824}
3825
3826#if defined(COMPAT_43) || defined(COMPAT_FREEBSD11)
3827int
3828freebsd11_kern_getdirentries(struct thread *td, int fd, char *ubuf, u_int count,
3829    long *basep, void (*func)(struct freebsd11_dirent *))
3830{
3831        struct freebsd11_dirent dstdp;
3832        struct dirent *dp, *edp;
3833        char *dirbuf;
3834        off_t base;
3835        ssize_t resid, ucount;
3836        int error;
3837
3838        /* XXX arbitrary sanity limit on `count'. */
3839        count = min(count, 64 * 1024);
3840
3841        dirbuf = malloc(count, M_TEMP, M_WAITOK);
3842
3843        error = kern_getdirentries(td, fd, dirbuf, count, &base, &resid,
3844            UIO_SYSSPACE);
3845        if (error != 0)
3846                goto done;
3847        if (basep != NULL)
3848                *basep = base;
3849
3850        ucount = 0;
3851        for (dp = (struct dirent *)dirbuf,
3852            edp = (struct dirent *)&dirbuf[count - resid];
3853            ucount < count && dp < edp; ) {
3854                if (dp->d_reclen == 0)
3855                        break;
3856                MPASS(dp->d_reclen >= _GENERIC_DIRLEN(0));
3857                if (dp->d_namlen >= sizeof(dstdp.d_name))
3858                        continue;
3859                dstdp.d_type = dp->d_type;
3860                dstdp.d_namlen = dp->d_namlen;
3861                dstdp.d_fileno = dp->d_fileno;          /* truncate */
3862                if (dstdp.d_fileno != dp->d_fileno) {
3863                        switch (ino64_trunc_error) {
3864                        default:
3865                        case 0:
3866                                break;
3867                        case 1:
3868                                error = EOVERFLOW;
3869                                goto done;
3870                        case 2:
3871                                dstdp.d_fileno = UINT32_MAX;
3872                                break;
3873                        }
3874                }
3875                dstdp.d_reclen = sizeof(dstdp) - sizeof(dstdp.d_name) +
3876                    ((dp->d_namlen + 1 + 3) &~ 3);
3877                bcopy(dp->d_name, dstdp.d_name, dstdp.d_namlen);
3878                bzero(dstdp.d_name + dstdp.d_namlen,
3879                    dstdp.d_reclen - offsetof(struct freebsd11_dirent, d_name) -
3880                    dstdp.d_namlen);
3881                MPASS(dstdp.d_reclen <= dp->d_reclen);
3882                MPASS(ucount + dstdp.d_reclen <= count);
3883                if (func != NULL)
3884                        func(&dstdp);
3885                error = copyout(&dstdp, ubuf + ucount, dstdp.d_reclen);
3886                if (error != 0)
3887                        break;
3888                dp = (struct dirent *)((char *)dp + dp->d_reclen);
3889                ucount += dstdp.d_reclen;
3890        }
3891
3892done:
3893        free(dirbuf, M_TEMP);
3894        if (error == 0)
3895                td->td_retval[0] = ucount;
3896        return (error);
3897}
3898#endif /* COMPAT */
3899
3900#ifdef COMPAT_43
3901static void
3902ogetdirentries_cvt(struct freebsd11_dirent *dp)
3903{
3904#if (BYTE_ORDER == LITTLE_ENDIAN)
3905        /*
3906         * The expected low byte of dp->d_namlen is our dp->d_type.
3907         * The high MBZ byte of dp->d_namlen is our dp->d_namlen.
3908         */
3909        dp->d_type = dp->d_namlen;
3910        dp->d_namlen = 0;
3911#else
3912        /*
3913         * The dp->d_type is the high byte of the expected dp->d_namlen,
3914         * so must be zero'ed.
3915         */
3916        dp->d_type = 0;
3917#endif
3918}
3919
3920/*
3921 * Read a block of directory entries in a filesystem independent format.
3922 */
3923#ifndef _SYS_SYSPROTO_H_
3924struct ogetdirentries_args {
3925        int     fd;
3926        char    *buf;
3927        u_int   count;
3928        long    *basep;
3929};
3930#endif
3931int
3932ogetdirentries(struct thread *td, struct ogetdirentries_args *uap)
3933{
3934        long loff;
3935        int error;
3936
3937        error = kern_ogetdirentries(td, uap, &loff);
3938        if (error == 0)
3939                error = copyout(&loff, uap->basep, sizeof(long));
3940        return (error);
3941}
3942
3943int
3944kern_ogetdirentries(struct thread *td, struct ogetdirentries_args *uap,
3945    long *ploff)
3946{
3947        long base;
3948        int error;
3949
3950        /* XXX arbitrary sanity limit on `count'. */
3951        if (uap->count > 64 * 1024)
3952                return (EINVAL);
3953
3954        error = freebsd11_kern_getdirentries(td, uap->fd, uap->buf, uap->count,
3955            &base, ogetdirentries_cvt);
3956
3957        if (error == 0 && uap->basep != NULL)
3958                error = copyout(&base, uap->basep, sizeof(long));
3959
3960        return (error);
3961}
3962#endif /* COMPAT_43 */
3963
3964#if defined(COMPAT_FREEBSD11)
3965#ifndef _SYS_SYSPROTO_H_
3966struct freebsd11_getdirentries_args {
3967        int     fd;
3968        char    *buf;
3969        u_int   count;
3970        long    *basep;
3971};
3972#endif
3973int
3974freebsd11_getdirentries(struct thread *td,
3975    struct freebsd11_getdirentries_args *uap)
3976{
3977        long base;
3978        int error;
3979
3980        error = freebsd11_kern_getdirentries(td, uap->fd, uap->buf, uap->count,
3981            &base, NULL);
3982
3983        if (error == 0 && uap->basep != NULL)
3984                error = copyout(&base, uap->basep, sizeof(long));
3985        return (error);
3986}
3987
3988int
3989freebsd11_getdents(struct thread *td, struct freebsd11_getdents_args *uap)
3990{
3991        struct freebsd11_getdirentries_args ap;
3992
3993        ap.fd = uap->fd;
3994        ap.buf = uap->buf;
3995        ap.count = uap->count;
3996        ap.basep = NULL;
3997        return (freebsd11_getdirentries(td, &ap));
3998}
3999#endif /* COMPAT_FREEBSD11 */
4000
4001/*
4002 * Read a block of directory entries in a filesystem independent format.
4003 */
4004int
4005sys_getdirentries(struct thread *td, struct getdirentries_args *uap)
4006{
4007        off_t base;
4008        int error;
4009
4010        error = kern_getdirentries(td, uap->fd, uap->buf, uap->count, &base,
4011            NULL, UIO_USERSPACE);
4012        if (error != 0)
4013                return (error);
4014        if (uap->basep != NULL)
4015                error = copyout(&base, uap->basep, sizeof(off_t));
4016        return (error);
4017}
4018
4019int
4020kern_getdirentries(struct thread *td, int fd, char *buf, size_t count,
4021    off_t *basep, ssize_t *residp, enum uio_seg bufseg)
4022{
4023        struct vnode *vp;
4024        struct file *fp;
4025        struct uio auio;
4026        struct iovec aiov;
4027        off_t loff;
4028        int error, eofflag;
4029        off_t foffset;
4030
4031        AUDIT_ARG_FD(fd);
4032        if (count > IOSIZE_MAX)
4033                return (EINVAL);
4034        auio.uio_resid = count;
4035        error = getvnode(td, fd, &cap_read_rights, &fp);
4036        if (error != 0)
4037                return (error);
4038        if ((fp->f_flag & FREAD) == 0) {
4039                fdrop(fp, td);
4040                return (EBADF);
4041        }
4042        vp = fp->f_vnode;
4043        foffset = foffset_lock(fp, 0);
4044unionread:
4045        if (vp->v_type != VDIR) {
4046                error = EINVAL;
4047                goto fail;
4048        }
4049        aiov.iov_base = buf;
4050        aiov.iov_len = count;
4051        auio.uio_iov = &aiov;
4052        auio.uio_iovcnt = 1;
4053        auio.uio_rw = UIO_READ;
4054        auio.uio_segflg = bufseg;
4055        auio.uio_td = td;
4056        vn_lock(vp, LK_SHARED | LK_RETRY);
4057        AUDIT_ARG_VNODE1(vp);
4058        loff = auio.uio_offset = foffset;
4059#ifdef MAC
4060        error = mac_vnode_check_readdir(td->td_ucred, vp);
4061        if (error == 0)
4062#endif
4063                error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, NULL,
4064                    NULL);
4065        foffset = auio.uio_offset;
4066        if (error != 0) {
4067                VOP_UNLOCK(vp, 0);
4068                goto fail;
4069        }
4070        if (count == auio.uio_resid &&
4071            (vp->v_vflag & VV_ROOT) &&
4072            (vp->v_mount->mnt_flag & MNT_UNION)) {
4073                struct vnode *tvp = vp;
4074
4075                vp = vp->v_mount->mnt_vnodecovered;
4076                VREF(vp);
4077                fp->f_vnode = vp;
4078                fp->f_data = vp;
4079                foffset = 0;
4080                vput(tvp);
4081                goto unionread;
4082        }
4083        VOP_UNLOCK(vp, 0);
4084        *basep = loff;
4085        if (residp != NULL)
4086                *residp = auio.uio_resid;
4087        td->td_retval[0] = count - auio.uio_resid;
4088fail:
4089        foffset_unlock(fp, foffset, 0);
4090        fdrop(fp, td);
4091        return (error);
4092}
4093
4094#ifndef __rtems__
4095/*
4096 * Set the mode mask for creation of filesystem nodes.
4097 */
4098#ifndef _SYS_SYSPROTO_H_
4099struct umask_args {
4100        int     newmask;
4101};
4102#endif
4103int
4104sys_umask(struct thread *td, struct umask_args *uap)
4105{
4106        struct filedesc *fdp;
4107
4108        fdp = td->td_proc->p_fd;
4109        FILEDESC_XLOCK(fdp);
4110        td->td_retval[0] = fdp->fd_cmask;
4111        fdp->fd_cmask = uap->newmask & ALLPERMS;
4112        FILEDESC_XUNLOCK(fdp);
4113        return (0);
4114}
4115
4116/*
4117 * Void all references to file by ripping underlying filesystem away from
4118 * vnode.
4119 */
4120#ifndef _SYS_SYSPROTO_H_
4121struct revoke_args {
4122        char    *path;
4123};
4124#endif
4125int
4126sys_revoke(struct thread *td, struct revoke_args *uap)
4127{
4128        struct vnode *vp;
4129        struct vattr vattr;
4130        struct nameidata nd;
4131        int error;
4132
4133        NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1, UIO_USERSPACE,
4134            uap->path, td);
4135        if ((error = namei(&nd)) != 0)
4136                return (error);
4137        vp = nd.ni_vp;
4138        NDFREE(&nd, NDF_ONLY_PNBUF);
4139        if (vp->v_type != VCHR || vp->v_rdev == NULL) {
4140                error = EINVAL;
4141                goto out;
4142        }
4143#ifdef MAC
4144        error = mac_vnode_check_revoke(td->td_ucred, vp);
4145        if (error != 0)
4146                goto out;
4147#endif
4148        error = VOP_GETATTR(vp, &vattr, td->td_ucred);
4149        if (error != 0)
4150                goto out;
4151        if (td->td_ucred->cr_uid != vattr.va_uid) {
4152                error = priv_check(td, PRIV_VFS_ADMIN);
4153                if (error != 0)
4154                        goto out;
4155        }
4156        if (vcount(vp) > 1)
4157                VOP_REVOKE(vp, REVOKEALL);
4158out:
4159        vput(vp);
4160        return (error);
4161}
4162#endif /* __rtems__ */
4163
4164/*
4165 * Convert a user file descriptor to a kernel file entry and check that, if it
4166 * is a capability, the correct rights are present. A reference on the file
4167 * entry is held upon returning.
4168 */
4169int
4170getvnode(struct thread *td, int fd, cap_rights_t *rightsp, struct file **fpp)
4171{
4172        struct file *fp;
4173        int error;
4174
4175        error = fget_unlocked(td->td_proc->p_fd, fd, rightsp, &fp, NULL);
4176        if (error != 0)
4177                return (error);
4178
4179        /*
4180         * The file could be not of the vnode type, or it may be not
4181         * yet fully initialized, in which case the f_vnode pointer
4182         * may be set, but f_ops is still badfileops.  E.g.,
4183         * devfs_open() transiently create such situation to
4184         * facilitate csw d_fdopen().
4185         *
4186         * Dupfdopen() handling in kern_openat() installs the
4187         * half-baked file into the process descriptor table, allowing
4188         * other thread to dereference it. Guard against the race by
4189         * checking f_ops.
4190         */
4191        if (fp->f_vnode == NULL || fp->f_ops == &badfileops) {
4192                fdrop(fp, td);
4193                return (EINVAL);
4194        }
4195        *fpp = fp;
4196        return (0);
4197}
4198
4199
4200#ifndef __rtems__
4201/*
4202 * Get an (NFS) file handle.
4203 */
4204#ifndef _SYS_SYSPROTO_H_
4205struct lgetfh_args {
4206        char *fname;
4207        fhandle_t *fhp;
4208};
4209#endif
4210int
4211sys_lgetfh(struct thread *td, struct lgetfh_args *uap)
4212{
4213
4214        return (kern_getfhat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->fname,
4215            UIO_USERSPACE, uap->fhp));
4216}
4217
4218#ifndef _SYS_SYSPROTO_H_
4219struct getfh_args {
4220        char *fname;
4221        fhandle_t *fhp;
4222};
4223#endif
4224int
4225sys_getfh(struct thread *td, struct getfh_args *uap)
4226{
4227
4228        return (kern_getfhat(td, 0, AT_FDCWD, uap->fname, UIO_USERSPACE,
4229            uap->fhp));
4230}
4231
4232/*
4233 * syscall for the rpc.lockd to use to translate an open descriptor into
4234 * a NFS file handle.
4235 *
4236 * warning: do not remove the priv_check() call or this becomes one giant
4237 * security hole.
4238 */
4239#ifndef _SYS_SYSPROTO_H_
4240struct getfhat_args {
4241        int fd;
4242        char *path;
4243        fhandle_t *fhp;
4244        int flags;
4245};
4246#endif
4247int
4248sys_getfhat(struct thread *td, struct getfhat_args *uap)
4249{
4250
4251        if ((uap->flags & ~(AT_SYMLINK_NOFOLLOW)) != 0)
4252            return (EINVAL);
4253        return (kern_getfhat(td, uap->flags, uap->fd, uap->path, UIO_USERSPACE,
4254            uap->fhp));
4255}
4256
4257static int
4258kern_getfhat(struct thread *td, int flags, int fd, const char *path,
4259    enum uio_seg pathseg, fhandle_t *fhp)
4260{
4261        struct nameidata nd;
4262        fhandle_t fh;
4263        struct vnode *vp;
4264        int error;
4265
4266        error = priv_check(td, PRIV_VFS_GETFH);
4267        if (error != 0)
4268                return (error);
4269        NDINIT_AT(&nd, LOOKUP, ((flags & AT_SYMLINK_NOFOLLOW) != 0 ? NOFOLLOW :
4270            FOLLOW) | /*((flags & AT_BENEATH) != 0 ? BENEATH : 0) |*/ LOCKLEAF |
4271            AUDITVNODE1, pathseg, path, fd, td);
4272        error = namei(&nd);
4273        if (error != 0)
4274                return (error);
4275        NDFREE(&nd, NDF_ONLY_PNBUF);
4276        vp = nd.ni_vp;
4277        bzero(&fh, sizeof(fh));
4278        fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
4279        error = VOP_VPTOFH(vp, &fh.fh_fid);
4280        vput(vp);
4281        if (error == 0)
4282                error = copyout(&fh, fhp, sizeof (fh));
4283        return (error);
4284}
4285
4286#ifndef _SYS_SYSPROTO_H_
4287struct fhlink_args {
4288        fhandle_t *fhp;
4289        const char *to;
4290};
4291#endif
4292int
4293sys_fhlink(struct thread *td, struct fhlink_args *uap)
4294{
4295
4296        return (kern_fhlinkat(td, AT_FDCWD, uap->to, UIO_USERSPACE, uap->fhp));
4297}
4298
4299#ifndef _SYS_SYSPROTO_H_
4300struct fhlinkat_args {
4301        fhandle_t *fhp;
4302        int tofd;
4303        const char *to;
4304};
4305#endif
4306int
4307sys_fhlinkat(struct thread *td, struct fhlinkat_args *uap)
4308{
4309
4310        return (kern_fhlinkat(td, uap->tofd, uap->to, UIO_USERSPACE, uap->fhp));
4311}
4312
4313static int
4314kern_fhlinkat(struct thread *td, int fd, const char *path,
4315    enum uio_seg pathseg, fhandle_t *fhp)
4316{
4317        fhandle_t fh;
4318        struct mount *mp;
4319        struct vnode *vp;
4320        int error;
4321
4322        error = priv_check(td, PRIV_VFS_GETFH);
4323        if (error != 0)
4324                return (error);
4325        error = copyin(fhp, &fh, sizeof(fh));
4326        if (error != 0)
4327                return (error);
4328        do {
4329                bwillwrite();
4330                if ((mp = vfs_busyfs(&fh.fh_fsid)) == NULL)
4331                        return (ESTALE);
4332                error = VFS_FHTOVP(mp, &fh.fh_fid, LK_SHARED, &vp);
4333                vfs_unbusy(mp);
4334                if (error != 0)
4335                        return (error);
4336                VOP_UNLOCK(vp, 0);
4337        } while ((error = kern_linkat_vp(td, vp, fd, path, pathseg)) == EAGAIN);
4338        return (error);
4339}
4340
4341#ifndef _SYS_SYSPROTO_H_
4342struct fhreadlink_args {
4343        fhandle_t *fhp;
4344        char *buf;
4345        size_t bufsize;
4346};
4347#endif
4348int
4349sys_fhreadlink(struct thread *td, struct fhreadlink_args *uap)
4350{
4351        fhandle_t fh;
4352        struct mount *mp;
4353        struct vnode *vp;
4354        int error;
4355
4356        error = priv_check(td, PRIV_VFS_GETFH);
4357        if (error != 0)
4358                return (error);
4359        if (uap->bufsize > IOSIZE_MAX)
4360                return (EINVAL);
4361        error = copyin(uap->fhp, &fh, sizeof(fh));
4362        if (error != 0)
4363                return (error);
4364        if ((mp = vfs_busyfs(&fh.fh_fsid)) == NULL)
4365                return (ESTALE);
4366        error = VFS_FHTOVP(mp, &fh.fh_fid, LK_SHARED, &vp);
4367        vfs_unbusy(mp);
4368        if (error != 0)
4369                return (error);
4370        error = kern_readlink_vp(vp, uap->buf, UIO_USERSPACE, uap->bufsize, td);
4371        vput(vp);
4372        return (error);
4373}
4374
4375/*
4376 * syscall for the rpc.lockd to use to translate a NFS file handle into an
4377 * open descriptor.
4378 *
4379 * warning: do not remove the priv_check() call or this becomes one giant
4380 * security hole.
4381 */
4382#ifndef _SYS_SYSPROTO_H_
4383struct fhopen_args {
4384        const struct fhandle *u_fhp;
4385        int flags;
4386};
4387#endif
4388int
4389sys_fhopen(struct thread *td, struct fhopen_args *uap)
4390{
4391        struct mount *mp;
4392        struct vnode *vp;
4393        struct fhandle fhp;
4394        struct file *fp;
4395        int fmode, error;
4396        int indx;
4397
4398        error = priv_check(td, PRIV_VFS_FHOPEN);
4399        if (error != 0)
4400                return (error);
4401        indx = -1;
4402        fmode = FFLAGS(uap->flags);
4403        /* why not allow a non-read/write open for our lockd? */
4404        if (((fmode & (FREAD | FWRITE)) == 0) || (fmode & O_CREAT))
4405                return (EINVAL);
4406        error = copyin(uap->u_fhp, &fhp, sizeof(fhp));
4407        if (error != 0)
4408                return(error);
4409        /* find the mount point */
4410        mp = vfs_busyfs(&fhp.fh_fsid);
4411        if (mp == NULL)
4412                return (ESTALE);
4413        /* now give me my vnode, it gets returned to me locked */
4414        error = VFS_FHTOVP(mp, &fhp.fh_fid, LK_EXCLUSIVE, &vp);
4415        vfs_unbusy(mp);
4416        if (error != 0)
4417                return (error);
4418
4419        error = falloc_noinstall(td, &fp);
4420        if (error != 0) {
4421                vput(vp);
4422                return (error);
4423        }
4424        /*
4425         * An extra reference on `fp' has been held for us by
4426         * falloc_noinstall().
4427         */
4428
4429#ifdef INVARIANTS
4430        td->td_dupfd = -1;
4431#endif
4432        error = vn_open_vnode(vp, fmode, td->td_ucred, td, fp);
4433        if (error != 0) {
4434                KASSERT(fp->f_ops == &badfileops,
4435                    ("VOP_OPEN in fhopen() set f_ops"));
4436                KASSERT(td->td_dupfd < 0,
4437                    ("fhopen() encountered fdopen()"));
4438
4439                vput(vp);
4440                goto bad;
4441        }
4442#ifdef INVARIANTS
4443        td->td_dupfd = 0;
4444#endif
4445        fp->f_vnode = vp;
4446        fp->f_seqcount = 1;
4447        finit(fp, (fmode & FMASK) | (fp->f_flag & FHASLOCK), DTYPE_VNODE, vp,
4448            &vnops);
4449        VOP_UNLOCK(vp, 0);
4450        if ((fmode & O_TRUNC) != 0) {
4451                error = fo_truncate(fp, 0, td->td_ucred, td);
4452                if (error != 0)
4453                        goto bad;
4454        }
4455
4456        error = finstall(td, fp, &indx, fmode, NULL);
4457bad:
4458        fdrop(fp, td);
4459        td->td_retval[0] = indx;
4460        return (error);
4461}
4462
4463/*
4464 * Stat an (NFS) file handle.
4465 */
4466#ifndef _SYS_SYSPROTO_H_
4467struct fhstat_args {
4468        struct fhandle *u_fhp;
4469        struct stat *sb;
4470};
4471#endif
4472int
4473sys_fhstat(struct thread *td, struct fhstat_args *uap)
4474{
4475        struct stat sb;
4476        struct fhandle fh;
4477        int error;
4478
4479        error = copyin(uap->u_fhp, &fh, sizeof(fh));
4480        if (error != 0)
4481                return (error);
4482        error = kern_fhstat(td, fh, &sb);
4483        if (error == 0)
4484                error = copyout(&sb, uap->sb, sizeof(sb));
4485        return (error);
4486}
4487
4488int
4489kern_fhstat(struct thread *td, struct fhandle fh, struct stat *sb)
4490{
4491        struct mount *mp;
4492        struct vnode *vp;
4493        int error;
4494
4495        error = priv_check(td, PRIV_VFS_FHSTAT);
4496        if (error != 0)
4497                return (error);
4498        if ((mp = vfs_busyfs(&fh.fh_fsid)) == NULL)
4499                return (ESTALE);
4500        error = VFS_FHTOVP(mp, &fh.fh_fid, LK_EXCLUSIVE, &vp);
4501        vfs_unbusy(mp);
4502        if (error != 0)
4503                return (error);
4504        error = vn_stat(vp, sb, td->td_ucred, NOCRED, td);
4505        vput(vp);
4506        return (error);
4507}
4508
4509/*
4510 * Implement fstatfs() for (NFS) file handles.
4511 */
4512#ifndef _SYS_SYSPROTO_H_
4513struct fhstatfs_args {
4514        struct fhandle *u_fhp;
4515        struct statfs *buf;
4516};
4517#endif
4518int
4519sys_fhstatfs(struct thread *td, struct fhstatfs_args *uap)
4520{
4521        struct statfs *sfp;
4522        fhandle_t fh;
4523        int error;
4524
4525        error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t));
4526        if (error != 0)
4527                return (error);
4528        sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
4529        error = kern_fhstatfs(td, fh, sfp);
4530        if (error == 0)
4531                error = copyout(sfp, uap->buf, sizeof(*sfp));
4532        free(sfp, M_STATFS);
4533        return (error);
4534}
4535
4536int
4537kern_fhstatfs(struct thread *td, fhandle_t fh, struct statfs *buf)
4538{
4539        struct statfs *sp;
4540        struct mount *mp;
4541        struct vnode *vp;
4542        int error;
4543
4544        error = priv_check(td, PRIV_VFS_FHSTATFS);
4545        if (error != 0)
4546                return (error);
4547        if ((mp = vfs_busyfs(&fh.fh_fsid)) == NULL)
4548                return (ESTALE);
4549        error = VFS_FHTOVP(mp, &fh.fh_fid, LK_EXCLUSIVE, &vp);
4550        if (error != 0) {
4551                vfs_unbusy(mp);
4552                return (error);
4553        }
4554        vput(vp);
4555        error = prison_canseemount(td->td_ucred, mp);
4556        if (error != 0)
4557                goto out;
4558#ifdef MAC
4559        error = mac_mount_check_stat(td->td_ucred, mp);
4560        if (error != 0)
4561                goto out;
4562#endif
4563        /*
4564         * Set these in case the underlying filesystem fails to do so.
4565         */
4566        sp = &mp->mnt_stat;
4567        sp->f_version = STATFS_VERSION;
4568        sp->f_namemax = NAME_MAX;
4569        sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
4570        error = VFS_STATFS(mp, sp);
4571        if (error == 0)
4572                *buf = *sp;
4573out:
4574        vfs_unbusy(mp);
4575        return (error);
4576}
4577#endif /* __rtems__ */
4578
4579int
4580kern_posix_fallocate(struct thread *td, int fd, off_t offset, off_t len)
4581{
4582        struct file *fp;
4583        struct mount *mp;
4584        struct vnode *vp;
4585        off_t olen, ooffset;
4586        int error;
4587#ifdef AUDIT
4588        int audited_vnode1 = 0;
4589#endif
4590
4591        AUDIT_ARG_FD(fd);
4592        if (offset < 0 || len <= 0)
4593                return (EINVAL);
4594        /* Check for wrap. */
4595        if (offset > OFF_MAX - len)
4596                return (EFBIG);
4597        AUDIT_ARG_FD(fd);
4598        error = fget(td, fd, &cap_pwrite_rights, &fp);
4599        if (error != 0)
4600                return (error);
4601        AUDIT_ARG_FILE(td->td_proc, fp);
4602        if ((fp->f_ops->fo_flags & DFLAG_SEEKABLE) == 0) {
4603                error = ESPIPE;
4604                goto out;
4605        }
4606        if ((fp->f_flag & FWRITE) == 0) {
4607                error = EBADF;
4608                goto out;
4609        }
4610        if (fp->f_type != DTYPE_VNODE) {
4611                error = ENODEV;
4612                goto out;
4613        }
4614        vp = fp->f_vnode;
4615        if (vp->v_type != VREG) {
4616                error = ENODEV;
4617                goto out;
4618        }
4619
4620        /* Allocating blocks may take a long time, so iterate. */
4621        for (;;) {
4622                olen = len;
4623                ooffset = offset;
4624
4625                bwillwrite();
4626                mp = NULL;
4627                error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
4628                if (error != 0)
4629                        break;
4630                error = vn_lock(vp, LK_EXCLUSIVE);
4631                if (error != 0) {
4632                        vn_finished_write(mp);
4633                        break;
4634                }
4635#ifdef AUDIT
4636                if (!audited_vnode1) {
4637                        AUDIT_ARG_VNODE1(vp);
4638                        audited_vnode1 = 1;
4639                }
4640#endif
4641#ifdef MAC
4642                error = mac_vnode_check_write(td->td_ucred, fp->f_cred, vp);
4643                if (error == 0)
4644#endif
4645                        error = VOP_ALLOCATE(vp, &offset, &len);
4646                VOP_UNLOCK(vp, 0);
4647                vn_finished_write(mp);
4648
4649                if (olen + ooffset != offset + len) {
4650                        panic("offset + len changed from %jx/%jx to %jx/%jx",
4651                            ooffset, olen, offset, len);
4652                }
4653                if (error != 0 || len == 0)
4654                        break;
4655                KASSERT(olen > len, ("Iteration did not make progress?"));
4656                maybe_yield();
4657        }
4658 out:
4659        fdrop(fp, td);
4660        return (error);
4661}
4662
4663#ifndef __rtems__
4664int
4665sys_posix_fallocate(struct thread *td, struct posix_fallocate_args *uap)
4666{
4667        int error;
4668
4669        error = kern_posix_fallocate(td, uap->fd, uap->offset, uap->len);
4670        return (kern_posix_error(td, error));
4671}
4672
4673/*
4674 * Unlike madvise(2), we do not make a best effort to remember every
4675 * possible caching hint.  Instead, we remember the last setting with
4676 * the exception that we will allow POSIX_FADV_NORMAL to adjust the
4677 * region of any current setting.
4678 */
4679int
4680kern_posix_fadvise(struct thread *td, int fd, off_t offset, off_t len,
4681    int advice)
4682{
4683        struct fadvise_info *fa, *new;
4684        struct file *fp;
4685        struct vnode *vp;
4686        off_t end;
4687        int error;
4688
4689        if (offset < 0 || len < 0 || offset > OFF_MAX - len)
4690                return (EINVAL);
4691        AUDIT_ARG_VALUE(advice);
4692        switch (advice) {
4693        case POSIX_FADV_SEQUENTIAL:
4694        case POSIX_FADV_RANDOM:
4695        case POSIX_FADV_NOREUSE:
4696                new = malloc(sizeof(*fa), M_FADVISE, M_WAITOK);
4697                break;
4698        case POSIX_FADV_NORMAL:
4699        case POSIX_FADV_WILLNEED:
4700        case POSIX_FADV_DONTNEED:
4701                new = NULL;
4702                break;
4703        default:
4704                return (EINVAL);
4705        }
4706        /* XXX: CAP_POSIX_FADVISE? */
4707        AUDIT_ARG_FD(fd);
4708        error = fget(td, fd, &cap_no_rights, &fp);
4709        if (error != 0)
4710                goto out;
4711        AUDIT_ARG_FILE(td->td_proc, fp);
4712        if ((fp->f_ops->fo_flags & DFLAG_SEEKABLE) == 0) {
4713                error = ESPIPE;
4714                goto out;
4715        }
4716        if (fp->f_type != DTYPE_VNODE) {
4717                error = ENODEV;
4718                goto out;
4719        }
4720        vp = fp->f_vnode;
4721        if (vp->v_type != VREG) {
4722                error = ENODEV;
4723                goto out;
4724        }
4725        if (len == 0)
4726                end = OFF_MAX;
4727        else
4728                end = offset + len - 1;
4729        switch (advice) {
4730        case POSIX_FADV_SEQUENTIAL:
4731        case POSIX_FADV_RANDOM:
4732        case POSIX_FADV_NOREUSE:
4733                /*
4734                 * Try to merge any existing non-standard region with
4735                 * this new region if possible, otherwise create a new
4736                 * non-standard region for this request.
4737                 */
4738                mtx_pool_lock(mtxpool_sleep, fp);
4739                fa = fp->f_advice;
4740                if (fa != NULL && fa->fa_advice == advice &&
4741                    ((fa->fa_start <= end && fa->fa_end >= offset) ||
4742                    (end != OFF_MAX && fa->fa_start == end + 1) ||
4743                    (fa->fa_end != OFF_MAX && fa->fa_end + 1 == offset))) {
4744                        if (offset < fa->fa_start)
4745                                fa->fa_start = offset;
4746                        if (end > fa->fa_end)
4747                                fa->fa_end = end;
4748                } else {
4749                        new->fa_advice = advice;
4750                        new->fa_start = offset;
4751                        new->fa_end = end;
4752                        fp->f_advice = new;
4753                        new = fa;
4754                }
4755                mtx_pool_unlock(mtxpool_sleep, fp);
4756                break;
4757        case POSIX_FADV_NORMAL:
4758                /*
4759                 * If a the "normal" region overlaps with an existing
4760                 * non-standard region, trim or remove the
4761                 * non-standard region.
4762                 */
4763                mtx_pool_lock(mtxpool_sleep, fp);
4764                fa = fp->f_advice;
4765                if (fa != NULL) {
4766                        if (offset <= fa->fa_start && end >= fa->fa_end) {
4767                                new = fa;
4768                                fp->f_advice = NULL;
4769                        } else if (offset <= fa->fa_start &&
4770                            end >= fa->fa_start)
4771                                fa->fa_start = end + 1;
4772                        else if (offset <= fa->fa_end && end >= fa->fa_end)
4773                                fa->fa_end = offset - 1;
4774                        else if (offset >= fa->fa_start && end <= fa->fa_end) {
4775                                /*
4776                                 * If the "normal" region is a middle
4777                                 * portion of the existing
4778                                 * non-standard region, just remove
4779                                 * the whole thing rather than picking
4780                                 * one side or the other to
4781                                 * preserve.
4782                                 */
4783                                new = fa;
4784                                fp->f_advice = NULL;
4785                        }
4786                }
4787                mtx_pool_unlock(mtxpool_sleep, fp);
4788                break;
4789        case POSIX_FADV_WILLNEED:
4790        case POSIX_FADV_DONTNEED:
4791                error = VOP_ADVISE(vp, offset, end, advice);
4792                break;
4793        }
4794out:
4795        if (fp != NULL)
4796                fdrop(fp, td);
4797        free(new, M_FADVISE);
4798        return (error);
4799}
4800
4801int
4802sys_posix_fadvise(struct thread *td, struct posix_fadvise_args *uap)
4803{
4804        int error;
4805
4806        error = kern_posix_fadvise(td, uap->fd, uap->offset, uap->len,
4807            uap->advice);
4808        return (kern_posix_error(td, error));
4809}
4810#endif /* __rtems__ */
Note: See TracBrowser for help on using the repository browser.