Annotation of src/sys/kern/vfs_syscalls.c, Revision 1.267.2.2
1.267.2.2! ad 1: /* $NetBSD: vfs_syscalls.c,v 1.267.2.1 2006/09/11 00:20:01 ad Exp $ */
1.31 cgd 2:
3: /*
4: * Copyright (c) 1989, 1993
5: * The Regents of the University of California. All rights reserved.
6: * (c) UNIX System Laboratories, Inc.
7: * All or some portions of this file are derived from material licensed
8: * to the University of California by American Telephone and Telegraph
9: * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10: * the permission of UNIX System Laboratories, Inc.
11: *
12: * Redistribution and use in source and binary forms, with or without
13: * modification, are permitted provided that the following conditions
14: * are met:
15: * 1. Redistributions of source code must retain the above copyright
16: * notice, this list of conditions and the following disclaimer.
17: * 2. Redistributions in binary form must reproduce the above copyright
18: * notice, this list of conditions and the following disclaimer in the
19: * documentation and/or other materials provided with the distribution.
1.191 agc 20: * 3. Neither the name of the University nor the names of its contributors
1.31 cgd 21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: *
1.113 fvdl 36: * @(#)vfs_syscalls.c 8.42 (Berkeley) 7/31/95
1.31 cgd 37: */
1.173 lukem 38:
39: #include <sys/cdefs.h>
1.267.2.2! ad 40: __KERNEL_RCSID(0, "$NetBSD: vfs_syscalls.c,v 1.267.2.1 2006/09/11 00:20:01 ad Exp $");
1.111 mrg 41:
1.121 jonathan 42: #include "opt_compat_netbsd.h"
1.127 christos 43: #include "opt_compat_43.h"
1.258 elad 44: #include "opt_fileassoc.h"
1.192 drochner 45: #include "opt_ktrace.h"
1.202 hannken 46: #include "fss.h"
1.261 dogcow 47: #include "veriexec.h"
1.31 cgd 48:
49: #include <sys/param.h>
50: #include <sys/systm.h>
51: #include <sys/namei.h>
52: #include <sys/filedesc.h>
53: #include <sys/kernel.h>
54: #include <sys/file.h>
55: #include <sys/stat.h>
56: #include <sys/vnode.h>
57: #include <sys/mount.h>
58: #include <sys/proc.h>
59: #include <sys/uio.h>
60: #include <sys/malloc.h>
1.248 yamt 61: #include <sys/kmem.h>
1.31 cgd 62: #include <sys/dirent.h>
1.172 simonb 63: #include <sys/sysctl.h>
1.179 thorpej 64: #include <sys/sa.h>
1.35 cgd 65: #include <sys/syscallargs.h>
1.192 drochner 66: #ifdef KTRACE
67: #include <sys/ktrace.h>
68: #endif
1.251 elad 69: #ifdef FILEASSOC
70: #include <sys/fileassoc.h>
71: #endif /* FILEASSOC */
1.256 elad 72: #if NVERIEXEC > 0
1.219 blymn 73: #include <sys/verified_exec.h>
1.256 elad 74: #endif /* NVERIEXEC > 0 */
1.242 elad 75: #include <sys/kauth.h>
1.35 cgd 76:
1.148 fvdl 77: #include <miscfs/genfs/genfs.h>
78: #include <miscfs/syncfs/syncfs.h>
1.181 thorpej 79:
1.232 jmmv 80: #ifdef COMPAT_30
81: #include "opt_nfsserver.h"
82: #include <nfs/rpcv2.h>
1.267 yamt 83: #endif
1.232 jmmv 84: #include <nfs/nfsproto.h>
1.267 yamt 85: #ifdef COMPAT_30
1.232 jmmv 86: #include <nfs/nfs.h>
87: #include <nfs/nfs_var.h>
88: #endif
89:
1.202 hannken 90: #if NFSS > 0
91: #include <dev/fssvar.h>
92: #endif
93:
1.181 thorpej 94: MALLOC_DEFINE(M_MOUNT, "mount", "vfs mount struct");
1.110 mrg 95:
1.234 christos 96: static int change_dir(struct nameidata *, struct lwp *);
97: static int change_flags(struct vnode *, u_long, struct lwp *);
98: static int change_mode(struct vnode *, int, struct lwp *l);
99: static int change_owner(struct vnode *, uid_t, gid_t, struct lwp *, int);
1.205 junyoung 100: static int change_utimes(struct vnode *vp, const struct timeval *,
1.234 christos 101: struct lwp *l);
102: static int rename_files(const char *, const char *, struct lwp *, int);
1.63 christos 103:
1.205 junyoung 104: void checkdirs(struct vnode *);
1.31 cgd 105:
1.150 fvdl 106: int dovfsusermount = 0;
107:
1.31 cgd 108: /*
109: * Virtual File System System Calls
110: */
111:
112: /*
113: * Mount a file system.
114: */
1.99 thorpej 115:
1.167 jdolecek 116: #if defined(COMPAT_09) || defined(COMPAT_43)
1.99 thorpej 117: /*
118: * This table is used to maintain compatibility with 4.3BSD
119: * and NetBSD 0.9 mount syscalls. Note, the order is important!
1.124 thorpej 120: *
1.167 jdolecek 121: * Do not modify this table. It should only contain filesystems
122: * supported by NetBSD 0.9 and 4.3BSD.
1.99 thorpej 123: */
1.167 jdolecek 124: const char * const mountcompatnames[] = {
1.99 thorpej 125: NULL, /* 0 = MOUNT_NONE */
1.167 jdolecek 126: MOUNT_FFS, /* 1 = MOUNT_UFS */
1.99 thorpej 127: MOUNT_NFS, /* 2 */
128: MOUNT_MFS, /* 3 */
129: MOUNT_MSDOS, /* 4 */
1.167 jdolecek 130: MOUNT_CD9660, /* 5 = MOUNT_ISOFS */
131: MOUNT_FDESC, /* 6 */
132: MOUNT_KERNFS, /* 7 */
133: NULL, /* 8 = MOUNT_DEVFS */
134: MOUNT_AFS, /* 9 */
1.99 thorpej 135: };
1.113 fvdl 136: const int nmountcompatnames = sizeof(mountcompatnames) /
1.99 thorpej 137: sizeof(mountcompatnames[0]);
1.167 jdolecek 138: #endif /* COMPAT_09 || COMPAT_43 */
1.99 thorpej 139:
1.31 cgd 140: /* ARGSUSED */
1.63 christos 141: int
1.221 thorpej 142: sys_mount(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 143: {
1.155 augustss 144: struct sys_mount_args /* {
1.74 cgd 145: syscallarg(const char *) type;
146: syscallarg(const char *) path;
1.35 cgd 147: syscallarg(int) flags;
1.74 cgd 148: syscallarg(void *) data;
1.56 thorpej 149: } */ *uap = v;
1.113 fvdl 150: struct vnode *vp;
151: struct mount *mp;
1.63 christos 152: int error, flag = 0;
1.31 cgd 153: char fstypename[MFSNAMELEN];
1.43 mycroft 154: struct vattr va;
1.31 cgd 155: struct nameidata nd;
1.109 thorpej 156: struct vfsops *vfs;
1.31 cgd 157:
1.218 yamt 158: /*
159: * if MNT_GETARGS is specified, it should be only flag.
160: */
161:
162: if ((SCARG(uap, flags) & MNT_GETARGS) != 0 &&
163: (SCARG(uap, flags) & ~MNT_GETARGS) != 0) {
164: return EINVAL;
165: }
166:
1.177 christos 167: if (dovfsusermount == 0 && (SCARG(uap, flags) & MNT_GETARGS) == 0 &&
1.257 ad 168: (error = kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER,
169: &l->l_acflag)))
1.150 fvdl 170: return (error);
1.31 cgd 171: /*
172: * Get vnode to be covered
173: */
1.185 christos 174: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE,
1.234 christos 175: SCARG(uap, path), l);
1.63 christos 176: if ((error = namei(&nd)) != 0)
1.31 cgd 177: return (error);
178: vp = nd.ni_vp;
1.113 fvdl 179: /*
180: * A lookup in VFS_MOUNT might result in an attempt to
1.182 drochner 181: * lock this vnode again, so make the lock recursive.
1.113 fvdl 182: */
1.128 fvdl 183: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY | LK_SETRECURSE);
1.177 christos 184: if (SCARG(uap, flags) & (MNT_UPDATE | MNT_GETARGS)) {
1.31 cgd 185: if ((vp->v_flag & VROOT) == 0) {
186: vput(vp);
187: return (EINVAL);
188: }
189: mp = vp->v_mount;
190: flag = mp->mnt_flag;
1.109 thorpej 191: vfs = mp->mnt_op;
1.31 cgd 192: /*
193: * We only allow the filesystem to be reloaded if it
194: * is currently mounted read-only.
195: */
1.35 cgd 196: if ((SCARG(uap, flags) & MNT_RELOAD) &&
1.31 cgd 197: ((mp->mnt_flag & MNT_RDONLY) == 0)) {
198: vput(vp);
199: return (EOPNOTSUPP); /* Needs translation */
200: }
1.125 tls 201: /*
202: * In "highly secure" mode, don't let the caller do anything
203: * but downgrade a filesystem from read-write to read-only.
1.177 christos 204: * (see also below; MNT_UPDATE or MNT_GETARGS is required.)
1.125 tls 205: */
206: if (securelevel >= 2 &&
1.177 christos 207: SCARG(uap, flags) != MNT_GETARGS &&
208: SCARG(uap, flags) !=
1.125 tls 209: (mp->mnt_flag | MNT_RDONLY |
1.195 thorpej 210: MNT_RELOAD | MNT_FORCE | MNT_UPDATE)) {
1.125 tls 211: vput(vp);
212: return (EPERM);
213: }
1.177 christos 214: mp->mnt_flag |= SCARG(uap, flags) &
215: (MNT_RELOAD | MNT_FORCE | MNT_UPDATE | MNT_GETARGS);
1.43 mycroft 216: /*
217: * Only root, or the user that did the original mount is
218: * permitted to update it.
219: */
1.177 christos 220: if ((mp->mnt_flag & MNT_GETARGS) == 0 &&
1.257 ad 221: mp->mnt_stat.f_owner != kauth_cred_geteuid(l->l_cred) &&
222: (error = kauth_authorize_generic(l->l_cred,
223: KAUTH_GENERIC_ISSUSER, &l->l_acflag)) != 0) {
1.43 mycroft 224: vput(vp);
225: return (error);
226: }
227: /*
1.130 bouyer 228: * Do not allow NFS export by non-root users. For non-root
229: * users, silently enforce MNT_NOSUID and MNT_NODEV, and
230: * MNT_NOEXEC if mount point is already MNT_NOEXEC.
1.43 mycroft 231: */
1.257 ad 232: if (kauth_cred_geteuid(l->l_cred) != 0) {
1.43 mycroft 233: if (SCARG(uap, flags) & MNT_EXPORTED) {
234: vput(vp);
235: return (EPERM);
236: }
237: SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
1.130 bouyer 238: if (flag & MNT_NOEXEC)
239: SCARG(uap, flags) |= MNT_NOEXEC;
1.43 mycroft 240: }
1.113 fvdl 241: if (vfs_busy(mp, LK_NOWAIT, 0)) {
242: vput(vp);
243: return (EPERM);
1.205 junyoung 244: }
1.31 cgd 245: goto update;
1.125 tls 246: } else {
1.158 pooka 247: if (securelevel >= 2) {
248: vput(vp);
1.125 tls 249: return (EPERM);
1.158 pooka 250: }
1.31 cgd 251: }
1.43 mycroft 252: /*
253: * If the user is not root, ensure that they own the directory
254: * onto which we are attempting to mount.
255: */
1.257 ad 256: if ((error = VOP_GETATTR(vp, &va, l->l_cred, l)) != 0 ||
257: (va.va_uid != kauth_cred_geteuid(l->l_cred) &&
258: (error = kauth_authorize_generic(l->l_cred,
259: KAUTH_GENERIC_ISSUSER, &l->l_acflag)) != 0)) {
1.43 mycroft 260: vput(vp);
261: return (error);
262: }
263: /*
1.130 bouyer 264: * Do not allow NFS export by non-root users. For non-root users,
265: * silently enforce MNT_NOSUID and MNT_NODEV, and MNT_NOEXEC if the
266: * mount point is already MNT_NOEXEC.
1.43 mycroft 267: */
1.257 ad 268: if (kauth_cred_geteuid(l->l_cred) != 0) {
1.43 mycroft 269: if (SCARG(uap, flags) & MNT_EXPORTED) {
270: vput(vp);
271: return (EPERM);
272: }
273: SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
1.130 bouyer 274: if (vp->v_mount->mnt_flag & MNT_NOEXEC)
275: SCARG(uap, flags) |= MNT_NOEXEC;
1.43 mycroft 276: }
1.257 ad 277: if ((error = vinvalbuf(vp, V_SAVE, l->l_cred, l, 0, 0)) != 0) {
1.203 jdolecek 278: vput(vp);
1.31 cgd 279: return (error);
1.203 jdolecek 280: }
1.31 cgd 281: if (vp->v_type != VDIR) {
282: vput(vp);
283: return (ENOTDIR);
284: }
1.63 christos 285: error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL);
286: if (error) {
1.54 cgd 287: #if defined(COMPAT_09) || defined(COMPAT_43)
288: /*
1.227 jmmv 289: * Historically, filesystem types were identified by numbers.
1.54 cgd 290: * If we get an integer for the filesystem type instead of a
291: * string, we check to see if it matches one of the historic
292: * filesystem types.
1.205 junyoung 293: */
1.109 thorpej 294: u_long fsindex = (u_long)SCARG(uap, type);
1.99 thorpej 295: if (fsindex >= nmountcompatnames ||
296: mountcompatnames[fsindex] == NULL) {
1.54 cgd 297: vput(vp);
298: return (ENODEV);
299: }
1.99 thorpej 300: strncpy(fstypename, mountcompatnames[fsindex], MFSNAMELEN);
1.31 cgd 301: #else
302: vput(vp);
303: return (error);
304: #endif
305: }
1.58 gwr 306: #ifdef COMPAT_10
1.59 mycroft 307: /* Accept `ufs' as an alias for `ffs'. */
308: if (!strncmp(fstypename, "ufs", MFSNAMELEN))
309: strncpy(fstypename, "ffs", MFSNAMELEN);
1.58 gwr 310: #endif
1.109 thorpej 311: if ((vfs = vfs_getopsbyname(fstypename)) == NULL) {
1.31 cgd 312: vput(vp);
313: return (ENODEV);
314: }
1.43 mycroft 315: if (vp->v_mountedhere != NULL) {
316: vput(vp);
317: return (EBUSY);
318: }
1.31 cgd 319:
320: /*
321: * Allocate and initialize the file system.
322: */
323: mp = (struct mount *)malloc((u_long)sizeof(struct mount),
324: M_MOUNT, M_WAITOK);
1.123 perry 325: memset((char *)mp, 0, (u_long)sizeof(struct mount));
1.113 fvdl 326: lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0);
1.208 pk 327: simple_lock_init(&mp->mnt_slock);
1.113 fvdl 328: (void)vfs_busy(mp, LK_NOWAIT, 0);
1.109 thorpej 329: mp->mnt_op = vfs;
330: vfs->vfs_refcount++;
1.129 fvdl 331: mp->mnt_vnodecovered = vp;
1.257 ad 332: mp->mnt_stat.f_owner = kauth_cred_geteuid(l->l_cred);
1.190 fvdl 333: mp->mnt_unmounter = NULL;
1.210 hannken 334: mp->mnt_leaf = mp;
1.195 thorpej 335:
336: /*
337: * The underlying file system may refuse the mount for
1.198 thorpej 338: * various reasons. Allow the user to force it to happen.
1.195 thorpej 339: */
1.198 thorpej 340: mp->mnt_flag |= SCARG(uap, flags) & MNT_FORCE;
1.195 thorpej 341: update:
1.218 yamt 342: if ((SCARG(uap, flags) & MNT_GETARGS) == 0) {
343: /*
344: * Set the mount level flags.
345: */
346: if (SCARG(uap, flags) & MNT_RDONLY)
347: mp->mnt_flag |= MNT_RDONLY;
348: else if (mp->mnt_flag & MNT_RDONLY)
349: mp->mnt_iflag |= IMNT_WANTRDWR;
350: mp->mnt_flag &=
351: ~(MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
352: MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOCOREDUMP |
1.237 chs 353: MNT_NOATIME | MNT_NODEVMTIME | MNT_SYMPERM | MNT_SOFTDEP);
1.218 yamt 354: mp->mnt_flag |= SCARG(uap, flags) &
355: (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
356: MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOCOREDUMP |
357: MNT_NOATIME | MNT_NODEVMTIME | MNT_SYMPERM | MNT_SOFTDEP |
1.237 chs 358: MNT_IGNORE);
1.218 yamt 359: }
1.31 cgd 360: /*
361: * Mount the filesystem.
362: */
1.234 christos 363: error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, l);
1.177 christos 364: if (mp->mnt_flag & (MNT_UPDATE | MNT_GETARGS)) {
1.232 jmmv 365: #if defined(COMPAT_30) && defined(NFSSERVER)
366: if (mp->mnt_flag & MNT_UPDATE && error != 0) {
367: int error2;
368:
369: /* Update failed; let's try and see if it was an
370: * export request. */
371: error2 = nfs_update_exports_30(mp, SCARG(uap, path),
1.234 christos 372: SCARG(uap, data), l);
1.232 jmmv 373:
374: /* Only update error code if the export request was
375: * understood but some problem occurred while
376: * processing it. */
377: if (error2 != EJUSTRETURN)
378: error = error2;
379: }
380: #endif
1.196 dbj 381: if (mp->mnt_iflag & IMNT_WANTRDWR)
1.31 cgd 382: mp->mnt_flag &= ~MNT_RDONLY;
1.218 yamt 383: if (error)
1.177 christos 384: mp->mnt_flag = flag;
1.31 cgd 385: mp->mnt_flag &=~
1.196 dbj 386: (MNT_RELOAD | MNT_FORCE | MNT_UPDATE | MNT_GETARGS);
387: mp->mnt_iflag &=~ IMNT_WANTRDWR;
1.151 mycroft 388: if ((mp->mnt_flag & (MNT_RDONLY | MNT_ASYNC)) == 0) {
1.148 fvdl 389: if (mp->mnt_syncer == NULL)
390: error = vfs_allocate_syncvnode(mp);
391: } else {
1.160 mycroft 392: if (mp->mnt_syncer != NULL)
393: vfs_deallocate_syncvnode(mp);
1.148 fvdl 394: }
1.113 fvdl 395: vfs_unbusy(mp);
1.174 enami 396: VOP_UNLOCK(vp, 0);
397: vrele(vp);
1.31 cgd 398: return (error);
399: }
400: /*
401: * Put the new filesystem on the mount list after root.
402: */
403: cache_purge(vp);
404: if (!error) {
1.195 thorpej 405: mp->mnt_flag &=~
1.196 dbj 406: (MNT_RELOAD | MNT_FORCE | MNT_UPDATE | MNT_GETARGS);
407: mp->mnt_iflag &=~ IMNT_WANTRDWR;
1.128 fvdl 408: vp->v_mountedhere = mp;
1.113 fvdl 409: simple_lock(&mountlist_slock);
1.47 mycroft 410: CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
1.113 fvdl 411: simple_unlock(&mountlist_slock);
1.43 mycroft 412: checkdirs(vp);
1.113 fvdl 413: VOP_UNLOCK(vp, 0);
1.151 mycroft 414: if ((mp->mnt_flag & (MNT_RDONLY | MNT_ASYNC)) == 0)
1.148 fvdl 415: error = vfs_allocate_syncvnode(mp);
1.113 fvdl 416: vfs_unbusy(mp);
1.234 christos 417: (void) VFS_STATVFS(mp, &mp->mnt_stat, l);
418: if ((error = VFS_START(mp, 0, l)))
1.113 fvdl 419: vrele(vp);
1.31 cgd 420: } else {
1.128 fvdl 421: vp->v_mountedhere = (struct mount *)0;
1.109 thorpej 422: vfs->vfs_refcount--;
1.113 fvdl 423: vfs_unbusy(mp);
1.184 dsl 424: free(mp, M_MOUNT);
1.31 cgd 425: vput(vp);
426: }
427: return (error);
428: }
429:
430: /*
1.43 mycroft 431: * Scan all active processes to see if any of them have a current
432: * or root directory onto which the new filesystem has just been
433: * mounted. If so, replace them with the new mount point.
434: */
1.63 christos 435: void
1.221 thorpej 436: checkdirs(struct vnode *olddp)
1.43 mycroft 437: {
1.134 thorpej 438: struct cwdinfo *cwdi;
1.43 mycroft 439: struct vnode *newdp;
440: struct proc *p;
441:
442: if (olddp->v_usecount == 1)
443: return;
1.189 thorpej 444: if (VFS_ROOT(olddp->v_mountedhere, &newdp))
1.43 mycroft 445: panic("mount: lost mount");
1.267.2.1 ad 446: rw_enter(&proclist_lock, RW_READER);
1.212 yamt 447: PROCLIST_FOREACH(p, &allproc) {
1.134 thorpej 448: cwdi = p->p_cwdi;
1.215 dbj 449: if (!cwdi)
450: continue;
1.134 thorpej 451: if (cwdi->cwdi_cdir == olddp) {
452: vrele(cwdi->cwdi_cdir);
1.43 mycroft 453: VREF(newdp);
1.134 thorpej 454: cwdi->cwdi_cdir = newdp;
1.43 mycroft 455: }
1.134 thorpej 456: if (cwdi->cwdi_rdir == olddp) {
457: vrele(cwdi->cwdi_rdir);
1.43 mycroft 458: VREF(newdp);
1.134 thorpej 459: cwdi->cwdi_rdir = newdp;
1.43 mycroft 460: }
461: }
1.267.2.1 ad 462: rw_exit(&proclist_lock);
1.43 mycroft 463: if (rootvnode == olddp) {
464: vrele(rootvnode);
465: VREF(newdp);
466: rootvnode = newdp;
467: }
468: vput(newdp);
469: }
470:
471: /*
1.31 cgd 472: * Unmount a file system.
473: *
474: * Note: unmount takes a path to the vnode mounted on as argument,
475: * not special file (as before).
476: */
477: /* ARGSUSED */
1.63 christos 478: int
1.221 thorpej 479: sys_unmount(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 480: {
1.155 augustss 481: struct sys_unmount_args /* {
1.74 cgd 482: syscallarg(const char *) path;
1.35 cgd 483: syscallarg(int) flags;
1.56 thorpej 484: } */ *uap = v;
1.155 augustss 485: struct vnode *vp;
1.31 cgd 486: struct mount *mp;
487: int error;
488: struct nameidata nd;
489:
1.35 cgd 490: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1.234 christos 491: SCARG(uap, path), l);
1.63 christos 492: if ((error = namei(&nd)) != 0)
1.31 cgd 493: return (error);
494: vp = nd.ni_vp;
1.43 mycroft 495: mp = vp->v_mount;
1.31 cgd 496:
497: /*
1.43 mycroft 498: * Only root, or the user that did the original mount is
499: * permitted to unmount this filesystem.
1.31 cgd 500: */
1.257 ad 501: if ((mp->mnt_stat.f_owner != kauth_cred_geteuid(l->l_cred)) &&
502: (error = kauth_authorize_generic(l->l_cred,
503: KAUTH_GENERIC_ISSUSER, &l->l_acflag)) != 0) {
1.31 cgd 504: vput(vp);
505: return (error);
506: }
507:
508: /*
1.47 mycroft 509: * Don't allow unmounting the root file system.
510: */
511: if (mp->mnt_flag & MNT_ROOTFS) {
512: vput(vp);
513: return (EINVAL);
514: }
515:
516: /*
1.31 cgd 517: * Must be the root of the filesystem
518: */
519: if ((vp->v_flag & VROOT) == 0) {
520: vput(vp);
521: return (EINVAL);
522: }
523: vput(vp);
1.78 fvdl 524:
1.165 thorpej 525: /*
526: * XXX Freeze syncer. Must do this before locking the
527: * mount point. See dounmount() for details.
528: */
1.267.2.1 ad 529: mutex_enter(&syncer_mutex);
1.165 thorpej 530:
531: if (vfs_busy(mp, 0, 0)) {
1.267.2.1 ad 532: mutex_exit(&syncer_mutex);
1.78 fvdl 533: return (EBUSY);
1.165 thorpej 534: }
1.78 fvdl 535:
1.234 christos 536: return (dounmount(mp, SCARG(uap, flags), l));
1.31 cgd 537: }
538:
539: /*
1.78 fvdl 540: * Do the actual file system unmount. File system is assumed to have been
541: * marked busy by the caller.
1.31 cgd 542: */
1.63 christos 543: int
1.234 christos 544: dounmount(struct mount *mp, int flags, struct lwp *l)
1.31 cgd 545: {
546: struct vnode *coveredvp;
547: int error;
1.140 sommerfe 548: int async;
1.162 fvdl 549: int used_syncer;
1.31 cgd 550:
1.256 elad 551: #if NVERIEXEC > 0
1.251 elad 552: if (!doing_shutdown) {
1.259 elad 553: if (veriexec_strict >= VERIEXEC_LOCKDOWN) {
1.251 elad 554: printf("Veriexec: Lockdown mode, preventing unmount of"
555: " \"%s\". (uid=%u)\n", mp->mnt_stat.f_mntonname,
1.257 ad 556: kauth_cred_getuid(l->l_cred));
1.251 elad 557: return (EPERM);
558: }
559:
1.259 elad 560: if (veriexec_strict == VERIEXEC_IPS) {
1.251 elad 561: struct veriexec_table_entry *vte;
562:
563: /* Check if we have fingerprints on mount. */
564: vte = fileassoc_tabledata_lookup(mp, veriexec_hook);
565: if ((vte != NULL) && (vte->vte_count > 0)) {
566: printf("Veriexec: IPS mode, preventing unmount"
567: " of \"%s\" with monitored files. "
568: "(uid=%u)\n", mp->mnt_stat.f_mntonname,
1.257 ad 569: kauth_cred_getuid(l->l_cred));
1.251 elad 570: return (EPERM);
571: }
572: }
573: }
1.256 elad 574: #endif /* NVERIEXEC > 0 */
1.251 elad 575:
576: #ifdef FILEASSOC
577: (void)fileassoc_table_delete(mp);
578: #endif /* FILEASSOC */
579:
1.113 fvdl 580: simple_lock(&mountlist_slock);
1.148 fvdl 581: vfs_unbusy(mp);
1.162 fvdl 582: used_syncer = (mp->mnt_syncer != NULL);
583:
1.148 fvdl 584: /*
1.165 thorpej 585: * XXX Syncer must be frozen when we get here. This should really
586: * be done on a per-mountpoint basis, but especially the softdep
1.227 jmmv 587: * code possibly called from the syncer doesn't exactly work on a
1.165 thorpej 588: * per-mountpoint basis, so the softdep code would become a maze
589: * of vfs_busy() calls.
590: *
1.267.2.1 ad 591: * The caller of dounmount() must acquire syncer_mutex because
592: * the syncer itself acquires locks in syncer_mutex -> vfs_busy
1.165 thorpej 593: * order, and we must preserve that order to avoid deadlock.
594: *
595: * So, if the file system did not use the syncer, now is
1.267.2.1 ad 596: * the time to release the syncer_mutex.
1.148 fvdl 597: */
1.165 thorpej 598: if (used_syncer == 0)
1.267.2.1 ad 599: mutex_exit(&syncer_mutex);
1.148 fvdl 600:
1.196 dbj 601: mp->mnt_iflag |= IMNT_UNMOUNT;
1.234 christos 602: mp->mnt_unmounter = l;
1.113 fvdl 603: lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK, &mountlist_slock);
1.197 hannken 604: vn_start_write(NULL, &mp, V_WAIT);
605:
1.141 sommerfe 606: async = mp->mnt_flag & MNT_ASYNC;
1.151 mycroft 607: mp->mnt_flag &= ~MNT_ASYNC;
1.31 cgd 608: cache_purgevfs(mp); /* remove cache entries for this file sys */
1.160 mycroft 609: if (mp->mnt_syncer != NULL)
610: vfs_deallocate_syncvnode(mp);
1.209 hannken 611: error = 0;
612: if ((mp->mnt_flag & MNT_RDONLY) == 0) {
1.202 hannken 613: #if NFSS > 0
1.209 hannken 614: error = fss_umount_hook(mp, (flags & MNT_FORCE));
1.202 hannken 615: #endif
1.209 hannken 616: if (error == 0)
1.257 ad 617: error = VFS_SYNC(mp, MNT_WAIT, l->l_cred, l);
1.209 hannken 618: }
619: if (error == 0 || (flags & MNT_FORCE))
1.234 christos 620: error = VFS_UNMOUNT(mp, flags, l);
1.197 hannken 621: vn_finished_write(mp, 0);
1.113 fvdl 622: simple_lock(&mountlist_slock);
1.31 cgd 623: if (error) {
1.151 mycroft 624: if ((mp->mnt_flag & (MNT_RDONLY | MNT_ASYNC)) == 0)
1.148 fvdl 625: (void) vfs_allocate_syncvnode(mp);
1.196 dbj 626: mp->mnt_iflag &= ~IMNT_UNMOUNT;
1.148 fvdl 627: mp->mnt_unmounter = NULL;
1.140 sommerfe 628: mp->mnt_flag |= async;
1.113 fvdl 629: lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK | LK_REENABLE,
630: &mountlist_slock);
1.162 fvdl 631: if (used_syncer)
1.267.2.1 ad 632: mutex_exit(&syncer_mutex);
1.208 pk 633: simple_lock(&mp->mnt_slock);
1.151 mycroft 634: while (mp->mnt_wcnt > 0) {
1.184 dsl 635: wakeup(mp);
1.208 pk 636: ltsleep(&mp->mnt_wcnt, PVFS, "mntwcnt1",
637: 0, &mp->mnt_slock);
1.142 sommerfe 638: }
1.208 pk 639: simple_unlock(&mp->mnt_slock);
1.142 sommerfe 640: return (error);
1.113 fvdl 641: }
642: CIRCLEQ_REMOVE(&mountlist, mp, mnt_list);
643: if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) {
644: coveredvp->v_mountedhere = NULL;
645: vrele(coveredvp);
646: }
647: mp->mnt_op->vfs_refcount--;
1.267.2.2! ad 648: if (TAILQ_FIRST(&mp->mnt_vnodelist) != NULL)
1.113 fvdl 649: panic("unmount: dangling vnode");
1.196 dbj 650: mp->mnt_iflag |= IMNT_GONE;
1.113 fvdl 651: lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_slock);
1.162 fvdl 652: if (used_syncer)
1.267.2.1 ad 653: mutex_exit(&syncer_mutex);
1.208 pk 654: simple_lock(&mp->mnt_slock);
655: while (mp->mnt_wcnt > 0) {
1.184 dsl 656: wakeup(mp);
1.208 pk 657: ltsleep(&mp->mnt_wcnt, PVFS, "mntwcnt2", 0, &mp->mnt_slock);
1.142 sommerfe 658: }
1.208 pk 659: simple_unlock(&mp->mnt_slock);
1.231 jmmv 660: vfs_hooks_unmount(mp);
1.184 dsl 661: free(mp, M_MOUNT);
1.113 fvdl 662: return (0);
1.31 cgd 663: }
664:
665: /*
666: * Sync each mounted filesystem.
667: */
668: #ifdef DEBUG
669: int syncprt = 0;
670: struct ctldebug debug0 = { "syncprt", &syncprt };
671: #endif
672:
673: /* ARGSUSED */
1.63 christos 674: int
1.221 thorpej 675: sys_sync(struct lwp *l, void *v, register_t *retval)
1.31 cgd 676: {
1.155 augustss 677: struct mount *mp, *nmp;
1.31 cgd 678: int asyncflag;
1.257 ad 679:
680: if (l == NULL)
681: l = &lwp0;
1.31 cgd 682:
1.113 fvdl 683: simple_lock(&mountlist_slock);
1.77 mikel 684: for (mp = mountlist.cqh_last; mp != (void *)&mountlist; mp = nmp) {
1.113 fvdl 685: if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock)) {
686: nmp = mp->mnt_list.cqe_prev;
687: continue;
688: }
1.197 hannken 689: if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
690: vn_start_write(NULL, &mp, V_NOWAIT) == 0) {
1.31 cgd 691: asyncflag = mp->mnt_flag & MNT_ASYNC;
692: mp->mnt_flag &= ~MNT_ASYNC;
1.257 ad 693: VFS_SYNC(mp, MNT_NOWAIT, l->l_cred, l);
1.31 cgd 694: if (asyncflag)
1.113 fvdl 695: mp->mnt_flag |= MNT_ASYNC;
1.197 hannken 696: vn_finished_write(mp, 0);
1.31 cgd 697: }
1.113 fvdl 698: simple_lock(&mountlist_slock);
699: nmp = mp->mnt_list.cqe_prev;
700: vfs_unbusy(mp);
1.205 junyoung 701:
1.31 cgd 702: }
1.113 fvdl 703: simple_unlock(&mountlist_slock);
1.31 cgd 704: #ifdef DEBUG
705: if (syncprt)
706: vfs_bufstats();
707: #endif /* DEBUG */
708: return (0);
709: }
710:
711: /*
712: * Change filesystem quotas.
713: */
714: /* ARGSUSED */
1.63 christos 715: int
1.221 thorpej 716: sys_quotactl(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 717: {
1.155 augustss 718: struct sys_quotactl_args /* {
1.74 cgd 719: syscallarg(const char *) path;
1.35 cgd 720: syscallarg(int) cmd;
721: syscallarg(int) uid;
1.267.2.2! ad 722: syscallarg(void *) arg;
1.56 thorpej 723: } */ *uap = v;
1.155 augustss 724: struct mount *mp;
1.31 cgd 725: int error;
726: struct nameidata nd;
727:
1.234 christos 728: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
1.63 christos 729: if ((error = namei(&nd)) != 0)
1.31 cgd 730: return (error);
1.197 hannken 731: error = vn_start_write(nd.ni_vp, &mp, V_WAIT | V_PCATCH);
1.31 cgd 732: vrele(nd.ni_vp);
1.197 hannken 733: if (error)
734: return (error);
735: error = VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
1.234 christos 736: SCARG(uap, arg), l);
1.197 hannken 737: vn_finished_write(mp, 0);
738: return (error);
1.31 cgd 739: }
740:
1.206 christos 741: int
1.234 christos 742: dostatvfs(struct mount *mp, struct statvfs *sp, struct lwp *l, int flags,
1.185 christos 743: int root)
744: {
1.234 christos 745: struct cwdinfo *cwdi = l->l_proc->p_cwdi;
1.185 christos 746: int error = 0;
747:
748: /*
749: * If MNT_NOWAIT or MNT_LAZY is specified, do not
1.204 dbj 750: * refresh the fsstat cache. MNT_WAIT or MNT_LAZY
1.185 christos 751: * overrides MNT_NOWAIT.
752: */
753: if (flags == MNT_NOWAIT || flags == MNT_LAZY ||
754: (flags != MNT_WAIT && flags != 0)) {
755: memcpy(sp, &mp->mnt_stat, sizeof(*sp));
756: goto done;
757: }
1.205 junyoung 758:
1.211 jdolecek 759: /* Get the filesystem stats now */
760: memset(sp, 0, sizeof(*sp));
1.234 christos 761: if ((error = VFS_STATVFS(mp, sp, l)) != 0) {
1.185 christos 762: return error;
763: }
764:
765: if (cwdi->cwdi_rdir == NULL)
766: (void)memcpy(&mp->mnt_stat, sp, sizeof(mp->mnt_stat));
767: done:
768: if (cwdi->cwdi_rdir != NULL) {
769: size_t len;
770: char *bp;
1.236 yamt 771: char *path = PNBUF_GET();
1.185 christos 772: if (!path)
773: return ENOMEM;
774:
775: bp = path + MAXPATHLEN;
776: *--bp = '\0';
777: error = getcwd_common(cwdi->cwdi_rdir, rootvnode, &bp, path,
1.234 christos 778: MAXPATHLEN / 2, 0, l);
1.185 christos 779: if (error) {
1.236 yamt 780: PNBUF_PUT(path);
1.185 christos 781: return error;
782: }
783: len = strlen(bp);
784: /*
785: * for mount points that are below our root, we can see
786: * them, so we fix up the pathname and return them. The
787: * rest we cannot see, so we don't allow viewing the
788: * data.
789: */
790: if (strncmp(bp, sp->f_mntonname, len) == 0) {
1.187 itojun 791: strlcpy(sp->f_mntonname, &sp->f_mntonname[len],
792: sizeof(sp->f_mntonname));
1.185 christos 793: if (sp->f_mntonname[0] == '\0')
1.187 itojun 794: (void)strlcpy(sp->f_mntonname, "/",
795: sizeof(sp->f_mntonname));
1.185 christos 796: } else {
797: if (root)
1.187 itojun 798: (void)strlcpy(sp->f_mntonname, "/",
799: sizeof(sp->f_mntonname));
1.185 christos 800: else
801: error = EPERM;
802: }
1.236 yamt 803: PNBUF_PUT(path);
1.185 christos 804: }
1.206 christos 805: sp->f_flag = mp->mnt_flag & MNT_VISFLAGMASK;
1.185 christos 806: return error;
807: }
808:
1.31 cgd 809: /*
810: * Get filesystem statistics.
811: */
812: /* ARGSUSED */
1.63 christos 813: int
1.221 thorpej 814: sys_statvfs1(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 815: {
1.206 christos 816: struct sys_statvfs1_args /* {
1.74 cgd 817: syscallarg(const char *) path;
1.206 christos 818: syscallarg(struct statvfs *) buf;
819: syscallarg(int) flags;
1.56 thorpej 820: } */ *uap = v;
1.155 augustss 821: struct mount *mp;
1.241 yamt 822: struct statvfs *sb;
1.31 cgd 823: int error;
824: struct nameidata nd;
825:
1.234 christos 826: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
1.63 christos 827: if ((error = namei(&nd)) != 0)
1.185 christos 828: return error;
1.31 cgd 829: mp = nd.ni_vp->v_mount;
830: vrele(nd.ni_vp);
1.241 yamt 831: sb = STATVFSBUF_GET();
832: error = dostatvfs(mp, sb, l, SCARG(uap, flags), 1);
833: if (error == 0) {
834: error = copyout(sb, SCARG(uap, buf), sizeof(*sb));
835: }
836: STATVFSBUF_PUT(sb);
837: return error;
1.31 cgd 838: }
839:
840: /*
841: * Get filesystem statistics.
842: */
843: /* ARGSUSED */
1.63 christos 844: int
1.221 thorpej 845: sys_fstatvfs1(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 846: {
1.206 christos 847: struct sys_fstatvfs1_args /* {
1.35 cgd 848: syscallarg(int) fd;
1.206 christos 849: syscallarg(struct statvfs *) buf;
850: syscallarg(int) flags;
1.56 thorpej 851: } */ *uap = v;
1.179 thorpej 852: struct proc *p = l->l_proc;
1.31 cgd 853: struct file *fp;
854: struct mount *mp;
1.241 yamt 855: struct statvfs *sb;
1.31 cgd 856: int error;
857:
1.135 thorpej 858: /* getvnode() will use the descriptor for us */
1.63 christos 859: if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
1.31 cgd 860: return (error);
1.62 mycroft 861: mp = ((struct vnode *)fp->f_data)->v_mount;
1.241 yamt 862: sb = STATVFSBUF_GET();
863: if ((error = dostatvfs(mp, sb, l, SCARG(uap, flags), 1)) != 0)
1.135 thorpej 864: goto out;
1.241 yamt 865: error = copyout(sb, SCARG(uap, buf), sizeof(*sb));
1.135 thorpej 866: out:
1.234 christos 867: FILE_UNUSE(fp, l);
1.241 yamt 868: STATVFSBUF_PUT(sb);
1.185 christos 869: return error;
1.31 cgd 870: }
871:
1.185 christos 872:
1.31 cgd 873: /*
874: * Get statistics on all filesystems.
875: */
1.63 christos 876: int
1.221 thorpej 877: sys_getvfsstat(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 878: {
1.206 christos 879: struct sys_getvfsstat_args /* {
880: syscallarg(struct statvfs *) buf;
881: syscallarg(size_t) bufsize;
1.35 cgd 882: syscallarg(int) flags;
1.56 thorpej 883: } */ *uap = v;
1.185 christos 884: int root = 0;
1.179 thorpej 885: struct proc *p = l->l_proc;
1.155 augustss 886: struct mount *mp, *nmp;
1.241 yamt 887: struct statvfs *sb;
1.206 christos 888: struct statvfs *sfsp;
889: size_t count, maxcount;
890: int error = 0;
1.31 cgd 891:
1.241 yamt 892: sb = STATVFSBUF_GET();
1.206 christos 893: maxcount = SCARG(uap, bufsize) / sizeof(struct statvfs);
894: sfsp = SCARG(uap, buf);
1.113 fvdl 895: simple_lock(&mountlist_slock);
896: count = 0;
1.176 matt 897: for (mp = CIRCLEQ_FIRST(&mountlist); mp != (void *)&mountlist;
898: mp = nmp) {
1.113 fvdl 899: if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock)) {
1.176 matt 900: nmp = CIRCLEQ_NEXT(mp, mnt_list);
1.113 fvdl 901: continue;
902: }
903: if (sfsp && count < maxcount) {
1.241 yamt 904: error = dostatvfs(mp, sb, l, SCARG(uap, flags), 0);
1.185 christos 905: if (error) {
1.186 yamt 906: simple_lock(&mountlist_slock);
1.176 matt 907: nmp = CIRCLEQ_NEXT(mp, mnt_list);
1.113 fvdl 908: vfs_unbusy(mp);
1.31 cgd 909: continue;
1.113 fvdl 910: }
1.241 yamt 911: error = copyout(sb, sfsp, sizeof(*sfsp));
1.133 mycroft 912: if (error) {
913: vfs_unbusy(mp);
1.241 yamt 914: goto out;
1.133 mycroft 915: }
1.206 christos 916: sfsp++;
1.241 yamt 917: root |= strcmp(sb->f_mntonname, "/") == 0;
1.31 cgd 918: }
919: count++;
1.186 yamt 920: simple_lock(&mountlist_slock);
1.176 matt 921: nmp = CIRCLEQ_NEXT(mp, mnt_list);
1.113 fvdl 922: vfs_unbusy(mp);
1.31 cgd 923: }
1.113 fvdl 924: simple_unlock(&mountlist_slock);
1.185 christos 925: if (root == 0 && p->p_cwdi->cwdi_rdir) {
926: /*
927: * fake a root entry
928: */
1.241 yamt 929: if ((error = dostatvfs(p->p_cwdi->cwdi_rdir->v_mount, sb, l,
1.185 christos 930: SCARG(uap, flags), 1)) != 0)
1.241 yamt 931: goto out;
1.185 christos 932: if (sfsp)
1.241 yamt 933: error = copyout(sb, sfsp, sizeof(*sfsp));
1.185 christos 934: count++;
935: }
1.31 cgd 936: if (sfsp && count > maxcount)
937: *retval = maxcount;
938: else
939: *retval = count;
1.241 yamt 940: out:
941: STATVFSBUF_PUT(sb);
1.185 christos 942: return error;
1.31 cgd 943: }
944:
945: /*
946: * Change current working directory to a given file descriptor.
947: */
948: /* ARGSUSED */
1.63 christos 949: int
1.221 thorpej 950: sys_fchdir(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 951: {
1.57 mycroft 952: struct sys_fchdir_args /* {
1.35 cgd 953: syscallarg(int) fd;
1.56 thorpej 954: } */ *uap = v;
1.179 thorpej 955: struct proc *p = l->l_proc;
1.134 thorpej 956: struct filedesc *fdp = p->p_fd;
957: struct cwdinfo *cwdi = p->p_cwdi;
1.43 mycroft 958: struct vnode *vp, *tdp;
959: struct mount *mp;
1.31 cgd 960: struct file *fp;
961: int error;
962:
1.135 thorpej 963: /* getvnode() will use the descriptor for us */
1.63 christos 964: if ((error = getvnode(fdp, SCARG(uap, fd), &fp)) != 0)
1.31 cgd 965: return (error);
1.62 mycroft 966: vp = (struct vnode *)fp->f_data;
1.131 sommerfe 967:
1.43 mycroft 968: VREF(vp);
1.113 fvdl 969: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.31 cgd 970: if (vp->v_type != VDIR)
971: error = ENOTDIR;
972: else
1.257 ad 973: error = VOP_ACCESS(vp, VEXEC, l->l_cred, l);
1.43 mycroft 974: while (!error && (mp = vp->v_mountedhere) != NULL) {
1.113 fvdl 975: if (vfs_busy(mp, 0, 0))
1.43 mycroft 976: continue;
1.189 thorpej 977: error = VFS_ROOT(mp, &tdp);
1.113 fvdl 978: vfs_unbusy(mp);
979: if (error)
1.43 mycroft 980: break;
981: vput(vp);
982: vp = tdp;
983: }
984: if (error) {
1.113 fvdl 985: vput(vp);
1.135 thorpej 986: goto out;
1.43 mycroft 987: }
1.113 fvdl 988: VOP_UNLOCK(vp, 0);
1.131 sommerfe 989:
990: /*
991: * Disallow changing to a directory not under the process's
992: * current root directory (if there is one).
993: */
1.234 christos 994: if (cwdi->cwdi_rdir && !vn_isunder(vp, NULL, l)) {
1.131 sommerfe 995: vrele(vp);
1.135 thorpej 996: error = EPERM; /* operation not permitted */
997: goto out;
1.131 sommerfe 998: }
1.205 junyoung 999:
1.134 thorpej 1000: vrele(cwdi->cwdi_cdir);
1001: cwdi->cwdi_cdir = vp;
1.135 thorpej 1002: out:
1.234 christos 1003: FILE_UNUSE(fp, l);
1.135 thorpej 1004: return (error);
1.31 cgd 1005: }
1006:
1007: /*
1.221 thorpej 1008: * Change this process's notion of the root directory to a given file
1009: * descriptor.
1.131 sommerfe 1010: */
1011: int
1.221 thorpej 1012: sys_fchroot(struct lwp *l, void *v, register_t *retval)
1.131 sommerfe 1013: {
1014: struct sys_fchroot_args *uap = v;
1.179 thorpej 1015: struct proc *p = l->l_proc;
1.134 thorpej 1016: struct filedesc *fdp = p->p_fd;
1017: struct cwdinfo *cwdi = p->p_cwdi;
1.131 sommerfe 1018: struct vnode *vp;
1019: struct file *fp;
1020: int error;
1021:
1.267.2.2! ad 1022: if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_CHROOT,
! 1023: KAUTH_REQ_SYSTEM_CHROOT_FCHROOT, NULL, NULL, NULL)) != 0)
1.131 sommerfe 1024: return error;
1.135 thorpej 1025: /* getvnode() will use the descriptor for us */
1.131 sommerfe 1026: if ((error = getvnode(fdp, SCARG(uap, fd), &fp)) != 0)
1027: return error;
1028: vp = (struct vnode *) fp->f_data;
1029: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1030: if (vp->v_type != VDIR)
1031: error = ENOTDIR;
1032: else
1.257 ad 1033: error = VOP_ACCESS(vp, VEXEC, l->l_cred, l);
1.131 sommerfe 1034: VOP_UNLOCK(vp, 0);
1035: if (error)
1.135 thorpej 1036: goto out;
1.131 sommerfe 1037: VREF(vp);
1038:
1039: /*
1040: * Prevent escaping from chroot by putting the root under
1041: * the working directory. Silently chdir to / if we aren't
1042: * already there.
1043: */
1.234 christos 1044: if (!vn_isunder(cwdi->cwdi_cdir, vp, l)) {
1.131 sommerfe 1045: /*
1046: * XXX would be more failsafe to change directory to a
1047: * deadfs node here instead
1048: */
1.134 thorpej 1049: vrele(cwdi->cwdi_cdir);
1.131 sommerfe 1050: VREF(vp);
1.134 thorpej 1051: cwdi->cwdi_cdir = vp;
1.131 sommerfe 1052: }
1.205 junyoung 1053:
1.134 thorpej 1054: if (cwdi->cwdi_rdir != NULL)
1055: vrele(cwdi->cwdi_rdir);
1056: cwdi->cwdi_rdir = vp;
1.135 thorpej 1057: out:
1.234 christos 1058: FILE_UNUSE(fp, l);
1.135 thorpej 1059: return (error);
1.131 sommerfe 1060: }
1061:
1062: /*
1.31 cgd 1063: * Change current working directory (``.'').
1064: */
1065: /* ARGSUSED */
1.63 christos 1066: int
1.221 thorpej 1067: sys_chdir(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 1068: {
1.57 mycroft 1069: struct sys_chdir_args /* {
1.74 cgd 1070: syscallarg(const char *) path;
1.56 thorpej 1071: } */ *uap = v;
1.179 thorpej 1072: struct proc *p = l->l_proc;
1.134 thorpej 1073: struct cwdinfo *cwdi = p->p_cwdi;
1.31 cgd 1074: int error;
1075: struct nameidata nd;
1076:
1.35 cgd 1077: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1.234 christos 1078: SCARG(uap, path), l);
1079: if ((error = change_dir(&nd, l)) != 0)
1.31 cgd 1080: return (error);
1.134 thorpej 1081: vrele(cwdi->cwdi_cdir);
1082: cwdi->cwdi_cdir = nd.ni_vp;
1.31 cgd 1083: return (0);
1084: }
1085:
1086: /*
1087: * Change notion of root (``/'') directory.
1088: */
1089: /* ARGSUSED */
1.63 christos 1090: int
1.221 thorpej 1091: sys_chroot(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 1092: {
1.57 mycroft 1093: struct sys_chroot_args /* {
1.74 cgd 1094: syscallarg(const char *) path;
1.56 thorpej 1095: } */ *uap = v;
1.179 thorpej 1096: struct proc *p = l->l_proc;
1.134 thorpej 1097: struct cwdinfo *cwdi = p->p_cwdi;
1.131 sommerfe 1098: struct vnode *vp;
1.31 cgd 1099: int error;
1100: struct nameidata nd;
1101:
1.267.2.2! ad 1102: if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_CHROOT,
! 1103: KAUTH_REQ_SYSTEM_CHROOT_CHROOT, NULL, NULL, NULL)) != 0)
1.31 cgd 1104: return (error);
1.35 cgd 1105: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1.234 christos 1106: SCARG(uap, path), l);
1107: if ((error = change_dir(&nd, l)) != 0)
1.31 cgd 1108: return (error);
1.134 thorpej 1109: if (cwdi->cwdi_rdir != NULL)
1110: vrele(cwdi->cwdi_rdir);
1.131 sommerfe 1111: vp = nd.ni_vp;
1.134 thorpej 1112: cwdi->cwdi_rdir = vp;
1.131 sommerfe 1113:
1114: /*
1115: * Prevent escaping from chroot by putting the root under
1116: * the working directory. Silently chdir to / if we aren't
1117: * already there.
1118: */
1.234 christos 1119: if (!vn_isunder(cwdi->cwdi_cdir, vp, l)) {
1.131 sommerfe 1120: /*
1121: * XXX would be more failsafe to change directory to a
1122: * deadfs node here instead
1123: */
1.134 thorpej 1124: vrele(cwdi->cwdi_cdir);
1.131 sommerfe 1125: VREF(vp);
1.134 thorpej 1126: cwdi->cwdi_cdir = vp;
1.131 sommerfe 1127: }
1.205 junyoung 1128:
1.31 cgd 1129: return (0);
1130: }
1131:
1132: /*
1133: * Common routine for chroot and chdir.
1134: */
1135: static int
1.234 christos 1136: change_dir(struct nameidata *ndp, struct lwp *l)
1.31 cgd 1137: {
1138: struct vnode *vp;
1139: int error;
1140:
1.63 christos 1141: if ((error = namei(ndp)) != 0)
1.31 cgd 1142: return (error);
1143: vp = ndp->ni_vp;
1144: if (vp->v_type != VDIR)
1145: error = ENOTDIR;
1146: else
1.257 ad 1147: error = VOP_ACCESS(vp, VEXEC, l->l_cred, l);
1.205 junyoung 1148:
1.31 cgd 1149: if (error)
1.113 fvdl 1150: vput(vp);
1151: else
1152: VOP_UNLOCK(vp, 0);
1.31 cgd 1153: return (error);
1154: }
1155:
1156: /*
1157: * Check permissions, allocate an open file structure,
1158: * and call the device open routine if any.
1159: */
1.63 christos 1160: int
1.221 thorpej 1161: sys_open(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 1162: {
1.155 augustss 1163: struct sys_open_args /* {
1.74 cgd 1164: syscallarg(const char *) path;
1.35 cgd 1165: syscallarg(int) flags;
1166: syscallarg(int) mode;
1.56 thorpej 1167: } */ *uap = v;
1.179 thorpej 1168: struct proc *p = l->l_proc;
1.134 thorpej 1169: struct cwdinfo *cwdi = p->p_cwdi;
1.135 thorpej 1170: struct filedesc *fdp = p->p_fd;
1171: struct file *fp;
1172: struct vnode *vp;
1.31 cgd 1173: int flags, cmode;
1174: int type, indx, error;
1175: struct flock lf;
1176: struct nameidata nd;
1177:
1.104 mycroft 1178: flags = FFLAGS(SCARG(uap, flags));
1179: if ((flags & (FREAD | FWRITE)) == 0)
1180: return (EINVAL);
1.135 thorpej 1181: /* falloc() will use the file descriptor for us */
1.257 ad 1182: if ((error = falloc(l, &fp, &indx)) != 0)
1.31 cgd 1183: return (error);
1.134 thorpej 1184: cmode = ((SCARG(uap, mode) &~ cwdi->cwdi_cmask) & ALLPERMS) &~ S_ISTXT;
1.234 christos 1185: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
1.194 jdolecek 1186: l->l_dupfd = -indx - 1; /* XXX check for fdopen */
1.63 christos 1187: if ((error = vn_open(&nd, flags, cmode)) != 0) {
1.234 christos 1188: FILE_UNUSE(fp, l);
1.200 yamt 1189: fdp->fd_ofiles[indx] = NULL;
1.31 cgd 1190: ffree(fp);
1.213 christos 1191: if ((error == EDUPFD || error == EMOVEFD) &&
1.194 jdolecek 1192: l->l_dupfd >= 0 && /* XXX from fdopen */
1.45 mycroft 1193: (error =
1.234 christos 1194: dupfdopen(l, indx, l->l_dupfd, flags, error)) == 0) {
1.45 mycroft 1195: *retval = indx;
1196: return (0);
1197: }
1198: if (error == ERESTART)
1.44 mycroft 1199: error = EINTR;
1.153 thorpej 1200: fdremove(fdp, indx);
1.31 cgd 1201: return (error);
1202: }
1.194 jdolecek 1203: l->l_dupfd = 0;
1.31 cgd 1204: vp = nd.ni_vp;
1205: fp->f_flag = flags & FMASK;
1206: fp->f_type = DTYPE_VNODE;
1207: fp->f_ops = &vnops;
1.184 dsl 1208: fp->f_data = vp;
1.31 cgd 1209: if (flags & (O_EXLOCK | O_SHLOCK)) {
1210: lf.l_whence = SEEK_SET;
1211: lf.l_start = 0;
1212: lf.l_len = 0;
1213: if (flags & O_EXLOCK)
1214: lf.l_type = F_WRLCK;
1215: else
1216: lf.l_type = F_RDLCK;
1217: type = F_FLOCK;
1218: if ((flags & FNONBLOCK) == 0)
1219: type |= F_WAIT;
1.113 fvdl 1220: VOP_UNLOCK(vp, 0);
1.184 dsl 1221: error = VOP_ADVLOCK(vp, fp, F_SETLK, &lf, type);
1.63 christos 1222: if (error) {
1.234 christos 1223: (void) vn_close(vp, fp->f_flag, fp->f_cred, l);
1224: FILE_UNUSE(fp, l);
1.31 cgd 1225: ffree(fp);
1.153 thorpej 1226: fdremove(fdp, indx);
1.31 cgd 1227: return (error);
1228: }
1.113 fvdl 1229: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.31 cgd 1230: fp->f_flag |= FHASLOCK;
1231: }
1.113 fvdl 1232: VOP_UNLOCK(vp, 0);
1.31 cgd 1233: *retval = indx;
1.166 thorpej 1234: FILE_SET_MATURE(fp);
1.234 christos 1235: FILE_UNUSE(fp, l);
1.31 cgd 1236: return (0);
1.137 wrstuden 1237: }
1238:
1.249 yamt 1239: static void
1240: vfs__fhfree(fhandle_t *fhp)
1241: {
1242: size_t fhsize;
1243:
1244: if (fhp == NULL) {
1245: return;
1246: }
1247: fhsize = FHANDLE_SIZE(fhp);
1248: kmem_free(fhp, fhsize);
1249: }
1250:
1.137 wrstuden 1251: /*
1.243 yamt 1252: * vfs_composefh: compose a filehandle.
1253: */
1254:
1255: int
1.244 martin 1256: vfs_composefh(struct vnode *vp, fhandle_t *fhp, size_t *fh_size)
1.243 yamt 1257: {
1258: struct mount *mp;
1.250 yamt 1259: struct fid *fidp;
1.243 yamt 1260: int error;
1.250 yamt 1261: size_t needfhsize;
1262: size_t fidsize;
1.243 yamt 1263:
1264: mp = vp->v_mount;
1265: if (mp->mnt_op->vfs_vptofh == NULL) {
1266: return EOPNOTSUPP;
1267: }
1.250 yamt 1268: fidp = NULL;
1.252 martin 1269: if (*fh_size < FHANDLE_SIZE_MIN) {
1.250 yamt 1270: fidsize = 0;
1.244 martin 1271: } else {
1.250 yamt 1272: fidsize = *fh_size - offsetof(fhandle_t, fh_fid);
1273: if (fhp != NULL) {
1274: memset(fhp, 0, *fh_size);
1275: fhp->fh_fsid = mp->mnt_stat.f_fsidx;
1276: fidp = &fhp->fh_fid;
1277: }
1.244 martin 1278: }
1.250 yamt 1279: error = VFS_VPTOFH(vp, fidp, &fidsize);
1280: needfhsize = FHANDLE_SIZE_FROM_FILEID_SIZE(fidsize);
1281: if (error == 0 && *fh_size < needfhsize) {
1282: error = E2BIG;
1283: }
1284: *fh_size = needfhsize;
1.243 yamt 1285: return error;
1286: }
1287:
1.249 yamt 1288: int
1289: vfs_composefh_alloc(struct vnode *vp, fhandle_t **fhpp)
1290: {
1291: struct mount *mp;
1292: fhandle_t *fhp;
1293: size_t fhsize;
1294: size_t fidsize;
1295: int error;
1296:
1297: *fhpp = NULL;
1298: mp = vp->v_mount;
1299: if (mp->mnt_op->vfs_vptofh == NULL) {
1300: error = EOPNOTSUPP;
1301: goto out;
1302: }
1.255 christos 1303: fidsize = 0;
1.249 yamt 1304: error = VFS_VPTOFH(vp, NULL, &fidsize);
1305: KASSERT(error != 0);
1306: if (error != E2BIG) {
1307: goto out;
1308: }
1.250 yamt 1309: fhsize = FHANDLE_SIZE_FROM_FILEID_SIZE(fidsize);
1.249 yamt 1310: fhp = kmem_zalloc(fhsize, KM_SLEEP);
1311: if (fhp == NULL) {
1312: error = ENOMEM;
1313: goto out;
1314: }
1315: fhp->fh_fsid = mp->mnt_stat.f_fsidx;
1316: error = VFS_VPTOFH(vp, &fhp->fh_fid, &fidsize);
1317: if (error == 0) {
1318: KASSERT((FHANDLE_SIZE(fhp) == fhsize &&
1319: FHANDLE_FILEID(fhp)->fid_len == fidsize));
1320: *fhpp = fhp;
1321: } else {
1322: kmem_free(fhp, fhsize);
1323: }
1324: out:
1325: return error;
1326: }
1327:
1328: void
1329: vfs_composefh_free(fhandle_t *fhp)
1330: {
1331:
1332: vfs__fhfree(fhp);
1333: }
1334:
1.243 yamt 1335: /*
1.248 yamt 1336: * vfs_fhtovp: lookup a vnode by a filehandle.
1337: */
1338:
1339: int
1340: vfs_fhtovp(fhandle_t *fhp, struct vnode **vpp)
1341: {
1342: struct mount *mp;
1343: int error;
1344:
1345: *vpp = NULL;
1346: mp = vfs_getvfs(FHANDLE_FSID(fhp));
1347: if (mp == NULL) {
1348: error = ESTALE;
1349: goto out;
1350: }
1351: if (mp->mnt_op->vfs_fhtovp == NULL) {
1352: error = EOPNOTSUPP;
1353: goto out;
1354: }
1355: error = VFS_FHTOVP(mp, FHANDLE_FILEID(fhp), vpp);
1356: out:
1357: return error;
1358: }
1359:
1360: /*
1.265 yamt 1361: * vfs_copyinfh_alloc: allocate and copyin a filehandle, given
1.263 martin 1362: * the needed size.
1363: */
1364:
1365: int
1.265 yamt 1366: vfs_copyinfh_alloc(const void *ufhp, size_t fhsize, fhandle_t **fhpp)
1.263 martin 1367: {
1368: fhandle_t *fhp;
1369: int error;
1370:
1371: *fhpp = NULL;
1.250 yamt 1372: if (fhsize > FHANDLE_SIZE_MAX) {
1373: return EINVAL;
1374: }
1.265 yamt 1375: if (fhsize < FHANDLE_SIZE_MIN) {
1376: return EINVAL;
1377: }
1.267 yamt 1378: again:
1.248 yamt 1379: fhp = kmem_alloc(fhsize, KM_SLEEP);
1380: if (fhp == NULL) {
1381: return ENOMEM;
1382: }
1383: error = copyin(ufhp, fhp, fhsize);
1384: if (error == 0) {
1.265 yamt 1385: /* XXX this check shouldn't be here */
1386: if (FHANDLE_SIZE(fhp) == fhsize) {
1.263 martin 1387: *fhpp = fhp;
1388: return 0;
1.267 yamt 1389: } else if (fhsize == NFSX_V2FH && FHANDLE_SIZE(fhp) < fhsize) {
1390: /*
1391: * a kludge for nfsv2 padded handles.
1392: */
1393: size_t sz;
1394:
1395: sz = FHANDLE_SIZE(fhp);
1396: kmem_free(fhp, fhsize);
1397: fhsize = sz;
1398: goto again;
1.264 yamt 1399: } else {
1.265 yamt 1400: /*
1401: * userland told us wrong size.
1402: */
1.263 martin 1403: error = EINVAL;
1.264 yamt 1404: }
1.248 yamt 1405: }
1.263 martin 1406: kmem_free(fhp, fhsize);
1.248 yamt 1407: return error;
1408: }
1409:
1410: void
1411: vfs_copyinfh_free(fhandle_t *fhp)
1412: {
1413:
1.249 yamt 1414: vfs__fhfree(fhp);
1.248 yamt 1415: }
1416:
1417: /*
1.137 wrstuden 1418: * Get file handle system call
1419: */
1420: int
1.244 martin 1421: sys___getfh30(struct lwp *l, void *v, register_t *retval)
1.137 wrstuden 1422: {
1.244 martin 1423: struct sys___getfh30_args /* {
1.137 wrstuden 1424: syscallarg(char *) fname;
1425: syscallarg(fhandle_t *) fhp;
1.244 martin 1426: syscallarg(size_t *) fh_size;
1.137 wrstuden 1427: } */ *uap = v;
1.155 augustss 1428: struct vnode *vp;
1.244 martin 1429: fhandle_t *fh;
1.137 wrstuden 1430: int error;
1431: struct nameidata nd;
1.244 martin 1432: size_t sz;
1.249 yamt 1433: size_t usz;
1.137 wrstuden 1434:
1435: /*
1436: * Must be super user
1437: */
1.267.2.2! ad 1438: error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FILEHANDLE,
! 1439: 0, NULL, NULL, NULL);
1.137 wrstuden 1440: if (error)
1441: return (error);
1442: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1.234 christos 1443: SCARG(uap, fname), l);
1.137 wrstuden 1444: error = namei(&nd);
1445: if (error)
1446: return (error);
1447: vp = nd.ni_vp;
1.249 yamt 1448: error = vfs_composefh_alloc(vp, &fh);
1.247 yamt 1449: vput(vp);
1.249 yamt 1450: if (error != 0) {
1451: goto out;
1452: }
1453: error = copyin(SCARG(uap, fh_size), &usz, sizeof(size_t));
1454: if (error != 0) {
1455: goto out;
1456: }
1457: sz = FHANDLE_SIZE(fh);
1458: error = copyout(&sz, SCARG(uap, fh_size), sizeof(size_t));
1459: if (error != 0) {
1460: goto out;
1.244 martin 1461: }
1.249 yamt 1462: if (usz >= sz) {
1463: error = copyout(fh, SCARG(uap, fhp), sz);
1464: } else {
1465: error = E2BIG;
1.244 martin 1466: }
1.249 yamt 1467: out:
1468: vfs_composefh_free(fh);
1.137 wrstuden 1469: return (error);
1470: }
1471:
1472: /*
1473: * Open a file given a file handle.
1474: *
1475: * Check permissions, allocate an open file structure,
1476: * and call the device open routine if any.
1477: */
1.265 yamt 1478:
1.137 wrstuden 1479: int
1.265 yamt 1480: dofhopen(struct lwp *l, const void *ufhp, size_t fhsize, int oflags,
1481: register_t *retval)
1.137 wrstuden 1482: {
1.257 ad 1483: struct filedesc *fdp = l->l_proc->p_fd;
1.137 wrstuden 1484: struct file *fp;
1.139 wrstuden 1485: struct vnode *vp = NULL;
1.137 wrstuden 1486: struct mount *mp;
1.257 ad 1487: kauth_cred_t cred = l->l_cred;
1.137 wrstuden 1488: struct file *nfp;
1489: int type, indx, error=0;
1490: struct flock lf;
1491: struct vattr va;
1.248 yamt 1492: fhandle_t *fh;
1.265 yamt 1493: int flags;
1.137 wrstuden 1494:
1495: /*
1496: * Must be super user
1497: */
1.267.2.2! ad 1498: if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FILEHANDLE,
! 1499: 0, NULL, NULL, NULL)))
1.137 wrstuden 1500: return (error);
1501:
1.265 yamt 1502: flags = FFLAGS(oflags);
1.137 wrstuden 1503: if ((flags & (FREAD | FWRITE)) == 0)
1504: return (EINVAL);
1505: if ((flags & O_CREAT))
1506: return (EINVAL);
1.139 wrstuden 1507: /* falloc() will use the file descriptor for us */
1.257 ad 1508: if ((error = falloc(l, &nfp, &indx)) != 0)
1.137 wrstuden 1509: return (error);
1510: fp = nfp;
1.265 yamt 1511: error = vfs_copyinfh_alloc(ufhp, fhsize, &fh);
1.248 yamt 1512: if (error != 0) {
1.139 wrstuden 1513: goto bad;
1514: }
1.248 yamt 1515: error = vfs_fhtovp(fh, &vp);
1516: if (error != 0) {
1.139 wrstuden 1517: goto bad;
1518: }
1.137 wrstuden 1519:
1520: /* Now do an effective vn_open */
1521:
1522: if (vp->v_type == VSOCK) {
1523: error = EOPNOTSUPP;
1524: goto bad;
1525: }
1526: if (flags & FREAD) {
1.234 christos 1527: if ((error = VOP_ACCESS(vp, VREAD, cred, l)) != 0)
1.137 wrstuden 1528: goto bad;
1529: }
1530: if (flags & (FWRITE | O_TRUNC)) {
1531: if (vp->v_type == VDIR) {
1532: error = EISDIR;
1533: goto bad;
1534: }
1535: if ((error = vn_writechk(vp)) != 0 ||
1.234 christos 1536: (error = VOP_ACCESS(vp, VWRITE, cred, l)) != 0)
1.137 wrstuden 1537: goto bad;
1538: }
1539: if (flags & O_TRUNC) {
1.197 hannken 1540: if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0)
1541: goto bad;
1.137 wrstuden 1542: VOP_UNLOCK(vp, 0); /* XXX */
1.234 christos 1543: VOP_LEASE(vp, l, cred, LEASE_WRITE);
1.137 wrstuden 1544: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); /* XXX */
1545: VATTR_NULL(&va);
1546: va.va_size = 0;
1.234 christos 1547: error = VOP_SETATTR(vp, &va, cred, l);
1.197 hannken 1548: vn_finished_write(mp, 0);
1549: if (error)
1.137 wrstuden 1550: goto bad;
1551: }
1.234 christos 1552: if ((error = VOP_OPEN(vp, flags, cred, l)) != 0)
1.137 wrstuden 1553: goto bad;
1.164 chs 1554: if (vp->v_type == VREG &&
1555: uvn_attach(vp, flags & FWRITE ? VM_PROT_WRITE : 0) == NULL) {
1556: error = EIO;
1557: goto bad;
1558: }
1.137 wrstuden 1559: if (flags & FWRITE)
1560: vp->v_writecount++;
1561:
1562: /* done with modified vn_open, now finish what sys_open does. */
1563:
1564: fp->f_flag = flags & FMASK;
1565: fp->f_type = DTYPE_VNODE;
1566: fp->f_ops = &vnops;
1.184 dsl 1567: fp->f_data = vp;
1.137 wrstuden 1568: if (flags & (O_EXLOCK | O_SHLOCK)) {
1569: lf.l_whence = SEEK_SET;
1570: lf.l_start = 0;
1571: lf.l_len = 0;
1572: if (flags & O_EXLOCK)
1573: lf.l_type = F_WRLCK;
1574: else
1575: lf.l_type = F_RDLCK;
1576: type = F_FLOCK;
1577: if ((flags & FNONBLOCK) == 0)
1578: type |= F_WAIT;
1579: VOP_UNLOCK(vp, 0);
1.184 dsl 1580: error = VOP_ADVLOCK(vp, fp, F_SETLK, &lf, type);
1.137 wrstuden 1581: if (error) {
1.234 christos 1582: (void) vn_close(vp, fp->f_flag, fp->f_cred, l);
1583: FILE_UNUSE(fp, l);
1.137 wrstuden 1584: ffree(fp);
1.153 thorpej 1585: fdremove(fdp, indx);
1.137 wrstuden 1586: return (error);
1587: }
1588: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1589: fp->f_flag |= FHASLOCK;
1590: }
1591: VOP_UNLOCK(vp, 0);
1592: *retval = indx;
1.166 thorpej 1593: FILE_SET_MATURE(fp);
1.234 christos 1594: FILE_UNUSE(fp, l);
1.248 yamt 1595: vfs_copyinfh_free(fh);
1.137 wrstuden 1596: return (0);
1.139 wrstuden 1597:
1.137 wrstuden 1598: bad:
1.234 christos 1599: FILE_UNUSE(fp, l);
1.139 wrstuden 1600: ffree(fp);
1.153 thorpej 1601: fdremove(fdp, indx);
1.139 wrstuden 1602: if (vp != NULL)
1603: vput(vp);
1.248 yamt 1604: vfs_copyinfh_free(fh);
1.137 wrstuden 1605: return (error);
1606: }
1607:
1608: int
1.265 yamt 1609: sys___fhopen40(struct lwp *l, void *v, register_t *retval)
1.137 wrstuden 1610: {
1.265 yamt 1611: struct sys___fhopen40_args /* {
1.263 martin 1612: syscallarg(const void *) fhp;
1613: syscallarg(size_t) fh_size;
1.265 yamt 1614: syscallarg(int) flags;
1.137 wrstuden 1615: } */ *uap = v;
1.265 yamt 1616:
1617: return dofhopen(l, SCARG(uap, fhp), SCARG(uap, fh_size),
1618: SCARG(uap, flags), retval);
1619: }
1620:
1621: int
1622: dofhstat(struct lwp *l, const void *ufhp, size_t fhsize, struct stat *sbp,
1623: register_t *retval)
1624: {
1.137 wrstuden 1625: struct stat sb;
1626: int error;
1.248 yamt 1627: fhandle_t *fh;
1.137 wrstuden 1628: struct vnode *vp;
1629:
1630: /*
1631: * Must be super user
1632: */
1.267.2.2! ad 1633: if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FILEHANDLE,
! 1634: 0, NULL, NULL, NULL)))
1.137 wrstuden 1635: return (error);
1636:
1.265 yamt 1637: error = vfs_copyinfh_alloc(ufhp, fhsize, &fh);
1.248 yamt 1638: if (error != 0) {
1639: goto bad;
1640: }
1641: error = vfs_fhtovp(fh, &vp);
1642: if (error != 0) {
1643: goto bad;
1644: }
1.234 christos 1645: error = vn_stat(vp, &sb, l);
1.137 wrstuden 1646: vput(vp);
1.248 yamt 1647: if (error) {
1648: goto bad;
1649: }
1.265 yamt 1650: error = copyout(&sb, sbp, sizeof(sb));
1.248 yamt 1651: bad:
1652: vfs_copyinfh_free(fh);
1653: return error;
1.137 wrstuden 1654: }
1655:
1.265 yamt 1656:
1.137 wrstuden 1657: /* ARGSUSED */
1658: int
1.265 yamt 1659: sys___fhstat40(struct lwp *l, void *v, register_t *retval)
1.137 wrstuden 1660: {
1.265 yamt 1661: struct sys___fhstat40_args /* {
1662: syscallarg(const void *) fhp;
1.263 martin 1663: syscallarg(size_t) fh_size;
1.265 yamt 1664: syscallarg(struct stat *) sb;
1.137 wrstuden 1665: } */ *uap = v;
1.265 yamt 1666:
1667: return dofhstat(l, SCARG(uap, fhp), SCARG(uap, fh_size), SCARG(uap, sb),
1668: retval);
1669: }
1670:
1671: int
1672: dofhstatvfs(struct lwp *l, const void *ufhp, size_t fhsize, struct statvfs *buf,
1673: int flags, register_t *retval)
1674: {
1.248 yamt 1675: struct statvfs *sb = NULL;
1676: fhandle_t *fh;
1.137 wrstuden 1677: struct mount *mp;
1678: struct vnode *vp;
1679: int error;
1680:
1681: /*
1682: * Must be super user
1683: */
1.267.2.2! ad 1684: if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FILEHANDLE,
! 1685: 0, NULL, NULL, NULL)))
1.206 christos 1686: return error;
1.137 wrstuden 1687:
1.265 yamt 1688: error = vfs_copyinfh_alloc(ufhp, fhsize, &fh);
1.248 yamt 1689: if (error != 0) {
1690: goto out;
1691: }
1692: error = vfs_fhtovp(fh, &vp);
1693: if (error != 0) {
1694: goto out;
1695: }
1.137 wrstuden 1696: mp = vp->v_mount;
1.241 yamt 1697: sb = STATVFSBUF_GET();
1.265 yamt 1698: if ((error = dostatvfs(mp, sb, l, flags, 1)) != 0) {
1.206 christos 1699: vput(vp);
1.241 yamt 1700: goto out;
1.206 christos 1701: }
1.137 wrstuden 1702: vput(vp);
1.265 yamt 1703: error = copyout(sb, buf, sizeof(*sb));
1.241 yamt 1704: out:
1.248 yamt 1705: if (sb != NULL) {
1706: STATVFSBUF_PUT(sb);
1707: }
1708: vfs_copyinfh_free(fh);
1.241 yamt 1709: return error;
1.31 cgd 1710: }
1711:
1.265 yamt 1712: /* ARGSUSED */
1713: int
1714: sys___fhstatvfs140(struct lwp *l, void *v, register_t *retval)
1715: {
1716: struct sys___fhstatvfs140_args /* {
1.266 yamt 1717: syscallarg(const void *) fhp;
1.265 yamt 1718: syscallarg(size_t) fh_size;
1719: syscallarg(struct statvfs *) buf;
1720: syscallarg(int) flags;
1721: } */ *uap = v;
1722:
1723: return dofhstatvfs(l, SCARG(uap, fhp), SCARG(uap, fh_size),
1724: SCARG(uap, buf), SCARG(uap, flags), retval);
1725: }
1726:
1.31 cgd 1727: /*
1728: * Create a special file.
1729: */
1730: /* ARGSUSED */
1.63 christos 1731: int
1.221 thorpej 1732: sys_mknod(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 1733: {
1.155 augustss 1734: struct sys_mknod_args /* {
1.74 cgd 1735: syscallarg(const char *) path;
1.35 cgd 1736: syscallarg(int) mode;
1737: syscallarg(int) dev;
1.56 thorpej 1738: } */ *uap = v;
1.179 thorpej 1739: struct proc *p = l->l_proc;
1.155 augustss 1740: struct vnode *vp;
1.197 hannken 1741: struct mount *mp;
1.31 cgd 1742: struct vattr vattr;
1743: int error;
1.63 christos 1744: int whiteout = 0;
1.31 cgd 1745: struct nameidata nd;
1746:
1.267.2.2! ad 1747: if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MKNOD,
! 1748: 0, NULL, NULL, NULL)) != 0)
1.31 cgd 1749: return (error);
1.197 hannken 1750: restart:
1.234 christos 1751: NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), l);
1.63 christos 1752: if ((error = namei(&nd)) != 0)
1.31 cgd 1753: return (error);
1754: vp = nd.ni_vp;
1.43 mycroft 1755: if (vp != NULL)
1.31 cgd 1756: error = EEXIST;
1.43 mycroft 1757: else {
1758: VATTR_NULL(&vattr);
1.94 enami 1759: vattr.va_mode =
1.134 thorpej 1760: (SCARG(uap, mode) & ALLPERMS) &~ p->p_cwdi->cwdi_cmask;
1.43 mycroft 1761: vattr.va_rdev = SCARG(uap, dev);
1762: whiteout = 0;
1763:
1764: switch (SCARG(uap, mode) & S_IFMT) {
1765: case S_IFMT: /* used by badsect to flag bad sectors */
1766: vattr.va_type = VBAD;
1767: break;
1768: case S_IFCHR:
1769: vattr.va_type = VCHR;
1770: break;
1771: case S_IFBLK:
1772: vattr.va_type = VBLK;
1773: break;
1774: case S_IFWHT:
1775: whiteout = 1;
1776: break;
1777: default:
1778: error = EINVAL;
1779: break;
1780: }
1.31 cgd 1781: }
1.197 hannken 1782: if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1783: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1784: if (nd.ni_dvp == vp)
1785: vrele(nd.ni_dvp);
1786: else
1787: vput(nd.ni_dvp);
1788: if (vp)
1789: vrele(vp);
1790: if ((error = vn_start_write(NULL, &mp,
1791: V_WAIT | V_SLEEPONLY | V_PCATCH)) != 0)
1792: return (error);
1793: goto restart;
1794: }
1.43 mycroft 1795: if (!error) {
1.257 ad 1796: VOP_LEASE(nd.ni_dvp, l, l->l_cred, LEASE_WRITE);
1.43 mycroft 1797: if (whiteout) {
1798: error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
1799: if (error)
1800: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1801: vput(nd.ni_dvp);
1802: } else {
1803: error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp,
1804: &nd.ni_cnd, &vattr);
1.168 assar 1805: if (error == 0)
1806: vput(nd.ni_vp);
1.43 mycroft 1807: }
1808: } else {
1809: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1810: if (nd.ni_dvp == vp)
1811: vrele(nd.ni_dvp);
1812: else
1813: vput(nd.ni_dvp);
1814: if (vp)
1815: vrele(vp);
1.31 cgd 1816: }
1.197 hannken 1817: vn_finished_write(mp, 0);
1.31 cgd 1818: return (error);
1819: }
1820:
1821: /*
1822: * Create a named pipe.
1823: */
1824: /* ARGSUSED */
1.63 christos 1825: int
1.221 thorpej 1826: sys_mkfifo(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 1827: {
1.155 augustss 1828: struct sys_mkfifo_args /* {
1.74 cgd 1829: syscallarg(const char *) path;
1.35 cgd 1830: syscallarg(int) mode;
1.56 thorpej 1831: } */ *uap = v;
1.179 thorpej 1832: struct proc *p = l->l_proc;
1.197 hannken 1833: struct mount *mp;
1.31 cgd 1834: struct vattr vattr;
1835: int error;
1836: struct nameidata nd;
1837:
1.197 hannken 1838: restart:
1.234 christos 1839: NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), l);
1.63 christos 1840: if ((error = namei(&nd)) != 0)
1.31 cgd 1841: return (error);
1842: if (nd.ni_vp != NULL) {
1843: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1844: if (nd.ni_dvp == nd.ni_vp)
1845: vrele(nd.ni_dvp);
1846: else
1847: vput(nd.ni_dvp);
1848: vrele(nd.ni_vp);
1849: return (EEXIST);
1850: }
1.197 hannken 1851: if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1852: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1853: if (nd.ni_dvp == nd.ni_vp)
1854: vrele(nd.ni_dvp);
1855: else
1856: vput(nd.ni_dvp);
1857: if (nd.ni_vp)
1858: vrele(nd.ni_vp);
1859: if ((error = vn_start_write(NULL, &mp,
1860: V_WAIT | V_SLEEPONLY | V_PCATCH)) != 0)
1861: return (error);
1862: goto restart;
1863: }
1.31 cgd 1864: VATTR_NULL(&vattr);
1865: vattr.va_type = VFIFO;
1.134 thorpej 1866: vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_cwdi->cwdi_cmask;
1.257 ad 1867: VOP_LEASE(nd.ni_dvp, l, l->l_cred, LEASE_WRITE);
1.168 assar 1868: error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
1869: if (error == 0)
1870: vput(nd.ni_vp);
1.197 hannken 1871: vn_finished_write(mp, 0);
1.168 assar 1872: return (error);
1.31 cgd 1873: }
1874:
1875: /*
1876: * Make a hard file link.
1877: */
1878: /* ARGSUSED */
1.63 christos 1879: int
1.221 thorpej 1880: sys_link(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 1881: {
1.155 augustss 1882: struct sys_link_args /* {
1.74 cgd 1883: syscallarg(const char *) path;
1884: syscallarg(const char *) link;
1.56 thorpej 1885: } */ *uap = v;
1.155 augustss 1886: struct vnode *vp;
1.197 hannken 1887: struct mount *mp;
1.31 cgd 1888: struct nameidata nd;
1889: int error;
1890:
1.234 christos 1891: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
1.63 christos 1892: if ((error = namei(&nd)) != 0)
1.31 cgd 1893: return (error);
1894: vp = nd.ni_vp;
1.197 hannken 1895: if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0) {
1896: vrele(vp);
1897: return (error);
1898: }
1.234 christos 1899: NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), l);
1.66 mycroft 1900: if ((error = namei(&nd)) != 0)
1901: goto out;
1902: if (nd.ni_vp) {
1903: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1904: if (nd.ni_dvp == nd.ni_vp)
1905: vrele(nd.ni_dvp);
1906: else
1907: vput(nd.ni_dvp);
1908: vrele(nd.ni_vp);
1909: error = EEXIST;
1910: goto out;
1.31 cgd 1911: }
1.257 ad 1912: VOP_LEASE(nd.ni_dvp, l, l->l_cred, LEASE_WRITE);
1913: VOP_LEASE(vp, l, l->l_cred, LEASE_WRITE);
1.66 mycroft 1914: error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
1915: out:
1.31 cgd 1916: vrele(vp);
1.197 hannken 1917: vn_finished_write(mp, 0);
1.31 cgd 1918: return (error);
1919: }
1920:
1921: /*
1922: * Make a symbolic link.
1923: */
1924: /* ARGSUSED */
1.63 christos 1925: int
1.221 thorpej 1926: sys_symlink(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 1927: {
1.155 augustss 1928: struct sys_symlink_args /* {
1.74 cgd 1929: syscallarg(const char *) path;
1930: syscallarg(const char *) link;
1.56 thorpej 1931: } */ *uap = v;
1.179 thorpej 1932: struct proc *p = l->l_proc;
1.197 hannken 1933: struct mount *mp;
1.31 cgd 1934: struct vattr vattr;
1935: char *path;
1936: int error;
1937: struct nameidata nd;
1938:
1.161 thorpej 1939: path = PNBUF_GET();
1.63 christos 1940: error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL);
1941: if (error)
1.43 mycroft 1942: goto out;
1.197 hannken 1943: restart:
1.234 christos 1944: NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), l);
1.63 christos 1945: if ((error = namei(&nd)) != 0)
1.43 mycroft 1946: goto out;
1.31 cgd 1947: if (nd.ni_vp) {
1948: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1949: if (nd.ni_dvp == nd.ni_vp)
1950: vrele(nd.ni_dvp);
1951: else
1952: vput(nd.ni_dvp);
1953: vrele(nd.ni_vp);
1954: error = EEXIST;
1.43 mycroft 1955: goto out;
1.31 cgd 1956: }
1.197 hannken 1957: if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1958: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1959: if (nd.ni_dvp == nd.ni_vp)
1960: vrele(nd.ni_dvp);
1961: else
1962: vput(nd.ni_dvp);
1963: if ((error = vn_start_write(NULL, &mp,
1964: V_WAIT | V_SLEEPONLY | V_PCATCH)) != 0)
1965: return (error);
1966: goto restart;
1967: }
1.31 cgd 1968: VATTR_NULL(&vattr);
1.230 jmmv 1969: vattr.va_type = VLNK;
1.134 thorpej 1970: vattr.va_mode = ACCESSPERMS &~ p->p_cwdi->cwdi_cmask;
1.257 ad 1971: VOP_LEASE(nd.ni_dvp, l, l->l_cred, LEASE_WRITE);
1.31 cgd 1972: error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
1.168 assar 1973: if (error == 0)
1974: vput(nd.ni_vp);
1.197 hannken 1975: vn_finished_write(mp, 0);
1.43 mycroft 1976: out:
1.161 thorpej 1977: PNBUF_PUT(path);
1.31 cgd 1978: return (error);
1979: }
1980:
1981: /*
1.43 mycroft 1982: * Delete a whiteout from the filesystem.
1983: */
1984: /* ARGSUSED */
1.63 christos 1985: int
1.221 thorpej 1986: sys_undelete(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 1987: {
1.155 augustss 1988: struct sys_undelete_args /* {
1.74 cgd 1989: syscallarg(const char *) path;
1.56 thorpej 1990: } */ *uap = v;
1.43 mycroft 1991: int error;
1.197 hannken 1992: struct mount *mp;
1.43 mycroft 1993: struct nameidata nd;
1994:
1.197 hannken 1995: restart:
1.43 mycroft 1996: NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE,
1.234 christos 1997: SCARG(uap, path), l);
1.43 mycroft 1998: error = namei(&nd);
1999: if (error)
2000: return (error);
2001:
2002: if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
2003: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2004: if (nd.ni_dvp == nd.ni_vp)
2005: vrele(nd.ni_dvp);
2006: else
2007: vput(nd.ni_dvp);
2008: if (nd.ni_vp)
2009: vrele(nd.ni_vp);
2010: return (EEXIST);
2011: }
1.197 hannken 2012: if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
2013: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2014: if (nd.ni_dvp == nd.ni_vp)
2015: vrele(nd.ni_dvp);
2016: else
2017: vput(nd.ni_dvp);
2018: if ((error = vn_start_write(NULL, &mp,
2019: V_WAIT | V_SLEEPONLY | V_PCATCH)) != 0)
2020: return (error);
2021: goto restart;
2022: }
1.257 ad 2023: VOP_LEASE(nd.ni_dvp, l, l->l_cred, LEASE_WRITE);
1.63 christos 2024: if ((error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE)) != 0)
1.43 mycroft 2025: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2026: vput(nd.ni_dvp);
1.197 hannken 2027: vn_finished_write(mp, 0);
1.43 mycroft 2028: return (error);
2029: }
2030:
2031: /*
1.31 cgd 2032: * Delete a name from the filesystem.
2033: */
2034: /* ARGSUSED */
1.63 christos 2035: int
1.221 thorpej 2036: sys_unlink(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 2037: {
1.57 mycroft 2038: struct sys_unlink_args /* {
1.74 cgd 2039: syscallarg(const char *) path;
1.56 thorpej 2040: } */ *uap = v;
1.197 hannken 2041: struct mount *mp;
1.155 augustss 2042: struct vnode *vp;
1.31 cgd 2043: int error;
2044: struct nameidata nd;
2045:
1.197 hannken 2046: restart:
1.67 mycroft 2047: NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
1.234 christos 2048: SCARG(uap, path), l);
1.63 christos 2049: if ((error = namei(&nd)) != 0)
1.31 cgd 2050: return (error);
2051: vp = nd.ni_vp;
2052:
1.66 mycroft 2053: /*
2054: * The root of a mounted filesystem cannot be deleted.
2055: */
2056: if (vp->v_flag & VROOT) {
1.43 mycroft 2057: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2058: if (nd.ni_dvp == vp)
2059: vrele(nd.ni_dvp);
2060: else
2061: vput(nd.ni_dvp);
1.66 mycroft 2062: vput(vp);
2063: error = EBUSY;
2064: goto out;
1.31 cgd 2065: }
1.219 blymn 2066:
1.256 elad 2067: #if NVERIEXEC > 0
1.222 elad 2068: /* Handle remove requests for veriexec entries. */
1.262 elad 2069: if ((error = veriexec_removechk(vp, nd.ni_dirp, l)) != 0) {
1.219 blymn 2070: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2071: if (nd.ni_dvp == vp)
2072: vrele(nd.ni_dvp);
2073: else
2074: vput(nd.ni_dvp);
2075: vput(vp);
2076: goto out;
2077: }
1.256 elad 2078: #endif /* NVERIEXEC > 0 */
2079:
1.197 hannken 2080: if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
2081: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2082: if (nd.ni_dvp == vp)
2083: vrele(nd.ni_dvp);
2084: else
2085: vput(nd.ni_dvp);
2086: vput(vp);
2087: if ((error = vn_start_write(NULL, &mp,
2088: V_WAIT | V_SLEEPONLY | V_PCATCH)) != 0)
2089: return (error);
2090: goto restart;
2091: }
1.257 ad 2092: VOP_LEASE(nd.ni_dvp, l, l->l_cred, LEASE_WRITE);
2093: VOP_LEASE(vp, l, l->l_cred, LEASE_WRITE);
1.253 elad 2094: #ifdef FILEASSOC
2095: (void)fileassoc_file_delete(nd.ni_vp);
2096: #endif /* FILEASSOC */
1.66 mycroft 2097: error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1.197 hannken 2098: vn_finished_write(mp, 0);
1.66 mycroft 2099: out:
1.31 cgd 2100: return (error);
2101: }
2102:
2103: /*
2104: * Reposition read/write file offset.
2105: */
1.63 christos 2106: int
1.221 thorpej 2107: sys_lseek(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 2108: {
1.155 augustss 2109: struct sys_lseek_args /* {
1.35 cgd 2110: syscallarg(int) fd;
2111: syscallarg(int) pad;
2112: syscallarg(off_t) offset;
2113: syscallarg(int) whence;
1.56 thorpej 2114: } */ *uap = v;
1.179 thorpej 2115: struct proc *p = l->l_proc;
1.257 ad 2116: kauth_cred_t cred = l->l_cred;
1.155 augustss 2117: struct filedesc *fdp = p->p_fd;
2118: struct file *fp;
1.84 kleink 2119: struct vnode *vp;
1.31 cgd 2120: struct vattr vattr;
1.155 augustss 2121: off_t newoff;
1.31 cgd 2122: int error;
2123:
1.166 thorpej 2124: if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
1.31 cgd 2125: return (EBADF);
1.84 kleink 2126:
1.135 thorpej 2127: FILE_USE(fp);
2128:
1.84 kleink 2129: vp = (struct vnode *)fp->f_data;
1.135 thorpej 2130: if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
2131: error = ESPIPE;
2132: goto out;
2133: }
1.84 kleink 2134:
1.35 cgd 2135: switch (SCARG(uap, whence)) {
1.92 kleink 2136: case SEEK_CUR:
1.84 kleink 2137: newoff = fp->f_offset + SCARG(uap, offset);
1.31 cgd 2138: break;
1.92 kleink 2139: case SEEK_END:
1.234 christos 2140: error = VOP_GETATTR(vp, &vattr, cred, l);
1.63 christos 2141: if (error)
1.135 thorpej 2142: goto out;
1.84 kleink 2143: newoff = SCARG(uap, offset) + vattr.va_size;
1.31 cgd 2144: break;
1.92 kleink 2145: case SEEK_SET:
1.84 kleink 2146: newoff = SCARG(uap, offset);
1.31 cgd 2147: break;
2148: default:
1.135 thorpej 2149: error = EINVAL;
2150: goto out;
1.31 cgd 2151: }
1.84 kleink 2152: if ((error = VOP_SEEK(vp, fp->f_offset, newoff, cred)) != 0)
1.135 thorpej 2153: goto out;
1.84 kleink 2154:
2155: *(off_t *)retval = fp->f_offset = newoff;
1.135 thorpej 2156: out:
1.234 christos 2157: FILE_UNUSE(fp, l);
1.135 thorpej 2158: return (error);
1.120 thorpej 2159: }
2160:
2161: /*
2162: * Positional read system call.
2163: */
2164: int
1.221 thorpej 2165: sys_pread(struct lwp *l, void *v, register_t *retval)
1.120 thorpej 2166: {
2167: struct sys_pread_args /* {
2168: syscallarg(int) fd;
2169: syscallarg(void *) buf;
2170: syscallarg(size_t) nbyte;
2171: syscallarg(off_t) offset;
2172: } */ *uap = v;
1.179 thorpej 2173: struct proc *p = l->l_proc;
1.120 thorpej 2174: struct filedesc *fdp = p->p_fd;
2175: struct file *fp;
2176: struct vnode *vp;
2177: off_t offset;
2178: int error, fd = SCARG(uap, fd);
2179:
1.166 thorpej 2180: if ((fp = fd_getfile(fdp, fd)) == NULL)
2181: return (EBADF);
2182:
1.183 pk 2183: if ((fp->f_flag & FREAD) == 0) {
2184: simple_unlock(&fp->f_slock);
1.120 thorpej 2185: return (EBADF);
1.183 pk 2186: }
1.120 thorpej 2187:
1.135 thorpej 2188: FILE_USE(fp);
2189:
1.120 thorpej 2190: vp = (struct vnode *)fp->f_data;
1.135 thorpej 2191: if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
2192: error = ESPIPE;
2193: goto out;
2194: }
1.120 thorpej 2195:
2196: offset = SCARG(uap, offset);
2197:
2198: /*
2199: * XXX This works because no file systems actually
2200: * XXX take any action on the seek operation.
2201: */
2202: if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
1.135 thorpej 2203: goto out;
1.120 thorpej 2204:
1.135 thorpej 2205: /* dofileread() will unuse the descriptor for us */
1.234 christos 2206: return (dofileread(l, fd, fp, SCARG(uap, buf), SCARG(uap, nbyte),
1.120 thorpej 2207: &offset, 0, retval));
1.135 thorpej 2208:
2209: out:
1.234 christos 2210: FILE_UNUSE(fp, l);
1.135 thorpej 2211: return (error);
1.120 thorpej 2212: }
2213:
2214: /*
2215: * Positional scatter read system call.
2216: */
2217: int
1.221 thorpej 2218: sys_preadv(struct lwp *l, void *v, register_t *retval)
1.120 thorpej 2219: {
2220: struct sys_preadv_args /* {
2221: syscallarg(int) fd;
2222: syscallarg(const struct iovec *) iovp;
2223: syscallarg(int) iovcnt;
2224: syscallarg(off_t) offset;
2225: } */ *uap = v;
1.179 thorpej 2226: struct proc *p = l->l_proc;
1.120 thorpej 2227: struct filedesc *fdp = p->p_fd;
2228: struct file *fp;
2229: struct vnode *vp;
2230: off_t offset;
2231: int error, fd = SCARG(uap, fd);
2232:
1.166 thorpej 2233: if ((fp = fd_getfile(fdp, fd)) == NULL)
2234: return (EBADF);
2235:
1.183 pk 2236: if ((fp->f_flag & FREAD) == 0) {
2237: simple_unlock(&fp->f_slock);
1.120 thorpej 2238: return (EBADF);
1.183 pk 2239: }
1.120 thorpej 2240:
1.135 thorpej 2241: FILE_USE(fp);
2242:
1.120 thorpej 2243: vp = (struct vnode *)fp->f_data;
1.135 thorpej 2244: if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
2245: error = ESPIPE;
2246: goto out;
2247: }
1.120 thorpej 2248:
2249: offset = SCARG(uap, offset);
2250:
2251: /*
2252: * XXX This works because no file systems actually
2253: * XXX take any action on the seek operation.
2254: */
2255: if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
1.135 thorpej 2256: goto out;
1.120 thorpej 2257:
1.135 thorpej 2258: /* dofilereadv() will unuse the descriptor for us */
1.234 christos 2259: return (dofilereadv(l, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt),
1.120 thorpej 2260: &offset, 0, retval));
1.135 thorpej 2261:
2262: out:
1.234 christos 2263: FILE_UNUSE(fp, l);
1.135 thorpej 2264: return (error);
1.120 thorpej 2265: }
2266:
2267: /*
2268: * Positional write system call.
2269: */
2270: int
1.221 thorpej 2271: sys_pwrite(struct lwp *l, void *v, register_t *retval)
1.120 thorpej 2272: {
2273: struct sys_pwrite_args /* {
2274: syscallarg(int) fd;
2275: syscallarg(const void *) buf;
2276: syscallarg(size_t) nbyte;
2277: syscallarg(off_t) offset;
2278: } */ *uap = v;
1.179 thorpej 2279: struct proc *p = l->l_proc;
1.120 thorpej 2280: struct filedesc *fdp = p->p_fd;
2281: struct file *fp;
2282: struct vnode *vp;
2283: off_t offset;
2284: int error, fd = SCARG(uap, fd);
2285:
1.166 thorpej 2286: if ((fp = fd_getfile(fdp, fd)) == NULL)
2287: return (EBADF);
2288:
1.183 pk 2289: if ((fp->f_flag & FWRITE) == 0) {
2290: simple_unlock(&fp->f_slock);
1.120 thorpej 2291: return (EBADF);
1.183 pk 2292: }
1.120 thorpej 2293:
1.135 thorpej 2294: FILE_USE(fp);
2295:
1.120 thorpej 2296: vp = (struct vnode *)fp->f_data;
1.135 thorpej 2297: if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
2298: error = ESPIPE;
2299: goto out;
2300: }
1.120 thorpej 2301:
2302: offset = SCARG(uap, offset);
2303:
2304: /*
2305: * XXX This works because no file systems actually
2306: * XXX take any action on the seek operation.
2307: */
2308: if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
1.135 thorpej 2309: goto out;
1.120 thorpej 2310:
1.135 thorpej 2311: /* dofilewrite() will unuse the descriptor for us */
1.234 christos 2312: return (dofilewrite(l, fd, fp, SCARG(uap, buf), SCARG(uap, nbyte),
1.120 thorpej 2313: &offset, 0, retval));
1.135 thorpej 2314:
2315: out:
1.234 christos 2316: FILE_UNUSE(fp, l);
1.135 thorpej 2317: return (error);
1.120 thorpej 2318: }
2319:
2320: /*
2321: * Positional gather write system call.
2322: */
2323: int
1.221 thorpej 2324: sys_pwritev(struct lwp *l, void *v, register_t *retval)
1.120 thorpej 2325: {
2326: struct sys_pwritev_args /* {
2327: syscallarg(int) fd;
2328: syscallarg(const struct iovec *) iovp;
2329: syscallarg(int) iovcnt;
2330: syscallarg(off_t) offset;
2331: } */ *uap = v;
1.179 thorpej 2332: struct proc *p = l->l_proc;
1.120 thorpej 2333: struct filedesc *fdp = p->p_fd;
2334: struct file *fp;
2335: struct vnode *vp;
2336: off_t offset;
2337: int error, fd = SCARG(uap, fd);
2338:
1.166 thorpej 2339: if ((fp = fd_getfile(fdp, fd)) == NULL)
2340: return (EBADF);
2341:
1.183 pk 2342: if ((fp->f_flag & FWRITE) == 0) {
2343: simple_unlock(&fp->f_slock);
1.120 thorpej 2344: return (EBADF);
1.183 pk 2345: }
1.120 thorpej 2346:
1.135 thorpej 2347: FILE_USE(fp);
2348:
1.120 thorpej 2349: vp = (struct vnode *)fp->f_data;
1.135 thorpej 2350: if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
2351: error = ESPIPE;
2352: goto out;
2353: }
1.120 thorpej 2354:
2355: offset = SCARG(uap, offset);
2356:
2357: /*
2358: * XXX This works because no file systems actually
2359: * XXX take any action on the seek operation.
2360: */
2361: if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
1.135 thorpej 2362: goto out;
1.120 thorpej 2363:
1.135 thorpej 2364: /* dofilewritev() will unuse the descriptor for us */
1.234 christos 2365: return (dofilewritev(l, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt),
1.120 thorpej 2366: &offset, 0, retval));
1.135 thorpej 2367:
2368: out:
1.234 christos 2369: FILE_UNUSE(fp, l);
1.135 thorpej 2370: return (error);
1.31 cgd 2371: }
2372:
2373: /*
2374: * Check access permissions.
2375: */
1.63 christos 2376: int
1.221 thorpej 2377: sys_access(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 2378: {
1.155 augustss 2379: struct sys_access_args /* {
1.74 cgd 2380: syscallarg(const char *) path;
1.35 cgd 2381: syscallarg(int) flags;
1.56 thorpej 2382: } */ *uap = v;
1.242 elad 2383: kauth_cred_t cred;
1.155 augustss 2384: struct vnode *vp;
1.169 christos 2385: int error, flags;
1.31 cgd 2386: struct nameidata nd;
2387:
1.257 ad 2388: cred = kauth_cred_dup(l->l_cred);
2389: kauth_cred_seteuid(cred, kauth_cred_getuid(l->l_cred));
2390: kauth_cred_setegid(cred, kauth_cred_getgid(l->l_cred));
1.35 cgd 2391: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1.234 christos 2392: SCARG(uap, path), l);
1.169 christos 2393: /* Override default credentials */
2394: nd.ni_cnd.cn_cred = cred;
1.63 christos 2395: if ((error = namei(&nd)) != 0)
1.169 christos 2396: goto out;
1.31 cgd 2397: vp = nd.ni_vp;
2398:
2399: /* Flags == 0 means only check for existence. */
1.35 cgd 2400: if (SCARG(uap, flags)) {
1.31 cgd 2401: flags = 0;
1.35 cgd 2402: if (SCARG(uap, flags) & R_OK)
1.31 cgd 2403: flags |= VREAD;
1.35 cgd 2404: if (SCARG(uap, flags) & W_OK)
1.31 cgd 2405: flags |= VWRITE;
1.89 mycroft 2406: if (SCARG(uap, flags) & X_OK)
2407: flags |= VEXEC;
1.138 is 2408:
1.234 christos 2409: error = VOP_ACCESS(vp, flags, cred, l);
1.138 is 2410: if (!error && (flags & VWRITE))
2411: error = vn_writechk(vp);
1.31 cgd 2412: }
2413: vput(vp);
1.169 christos 2414: out:
1.242 elad 2415: kauth_cred_free(cred);
1.31 cgd 2416: return (error);
2417: }
2418:
2419: /*
2420: * Get file status; this version follows links.
2421: */
2422: /* ARGSUSED */
1.63 christos 2423: int
1.228 christos 2424: sys___stat30(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 2425: {
1.228 christos 2426: struct sys___stat30_args /* {
1.74 cgd 2427: syscallarg(const char *) path;
1.35 cgd 2428: syscallarg(struct stat *) ub;
1.56 thorpej 2429: } */ *uap = v;
1.31 cgd 2430: struct stat sb;
2431: int error;
2432: struct nameidata nd;
2433:
1.35 cgd 2434: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1.234 christos 2435: SCARG(uap, path), l);
1.63 christos 2436: if ((error = namei(&nd)) != 0)
1.31 cgd 2437: return (error);
1.234 christos 2438: error = vn_stat(nd.ni_vp, &sb, l);
1.31 cgd 2439: vput(nd.ni_vp);
2440: if (error)
2441: return (error);
1.122 perry 2442: error = copyout(&sb, SCARG(uap, ub), sizeof(sb));
1.31 cgd 2443: return (error);
2444: }
2445:
2446: /*
2447: * Get file status; this version does not follow links.
2448: */
2449: /* ARGSUSED */
1.63 christos 2450: int
1.228 christos 2451: sys___lstat30(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 2452: {
1.228 christos 2453: struct sys___lstat30_args /* {
1.74 cgd 2454: syscallarg(const char *) path;
1.35 cgd 2455: syscallarg(struct stat *) ub;
1.56 thorpej 2456: } */ *uap = v;
1.65 mycroft 2457: struct stat sb;
1.31 cgd 2458: int error;
2459: struct nameidata nd;
2460:
1.65 mycroft 2461: NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
1.234 christos 2462: SCARG(uap, path), l);
1.63 christos 2463: if ((error = namei(&nd)) != 0)
1.31 cgd 2464: return (error);
1.234 christos 2465: error = vn_stat(nd.ni_vp, &sb, l);
1.65 mycroft 2466: vput(nd.ni_vp);
1.64 jtc 2467: if (error)
2468: return (error);
1.122 perry 2469: error = copyout(&sb, SCARG(uap, ub), sizeof(sb));
1.31 cgd 2470: return (error);
2471: }
2472:
2473: /*
2474: * Get configurable pathname variables.
2475: */
2476: /* ARGSUSED */
1.63 christos 2477: int
1.221 thorpej 2478: sys_pathconf(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 2479: {
1.155 augustss 2480: struct sys_pathconf_args /* {
1.74 cgd 2481: syscallarg(const char *) path;
1.35 cgd 2482: syscallarg(int) name;
1.56 thorpej 2483: } */ *uap = v;
1.31 cgd 2484: int error;
2485: struct nameidata nd;
2486:
1.35 cgd 2487: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1.234 christos 2488: SCARG(uap, path), l);
1.63 christos 2489: if ((error = namei(&nd)) != 0)
1.31 cgd 2490: return (error);
1.35 cgd 2491: error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval);
1.31 cgd 2492: vput(nd.ni_vp);
2493: return (error);
2494: }
2495:
2496: /*
2497: * Return target name of a symbolic link.
2498: */
2499: /* ARGSUSED */
1.63 christos 2500: int
1.221 thorpej 2501: sys_readlink(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 2502: {
1.155 augustss 2503: struct sys_readlink_args /* {
1.74 cgd 2504: syscallarg(const char *) path;
1.35 cgd 2505: syscallarg(char *) buf;
1.115 kleink 2506: syscallarg(size_t) count;
1.56 thorpej 2507: } */ *uap = v;
1.155 augustss 2508: struct vnode *vp;
1.31 cgd 2509: struct iovec aiov;
2510: struct uio auio;
2511: int error;
2512: struct nameidata nd;
2513:
1.35 cgd 2514: NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
1.234 christos 2515: SCARG(uap, path), l);
1.63 christos 2516: if ((error = namei(&nd)) != 0)
1.31 cgd 2517: return (error);
2518: vp = nd.ni_vp;
2519: if (vp->v_type != VLNK)
2520: error = EINVAL;
1.106 enami 2521: else if (!(vp->v_mount->mnt_flag & MNT_SYMPERM) ||
1.257 ad 2522: (error = VOP_ACCESS(vp, VREAD, l->l_cred, l)) == 0) {
1.35 cgd 2523: aiov.iov_base = SCARG(uap, buf);
2524: aiov.iov_len = SCARG(uap, count);
1.31 cgd 2525: auio.uio_iov = &aiov;
2526: auio.uio_iovcnt = 1;
2527: auio.uio_offset = 0;
2528: auio.uio_rw = UIO_READ;
1.238 yamt 2529: KASSERT(l == curlwp);
2530: auio.uio_vmspace = l->l_proc->p_vmspace;
1.35 cgd 2531: auio.uio_resid = SCARG(uap, count);
1.257 ad 2532: error = VOP_READLINK(vp, &auio, l->l_cred);
1.31 cgd 2533: }
2534: vput(vp);
1.35 cgd 2535: *retval = SCARG(uap, count) - auio.uio_resid;
1.31 cgd 2536: return (error);
2537: }
2538:
2539: /*
2540: * Change flags of a file given a path name.
2541: */
2542: /* ARGSUSED */
1.63 christos 2543: int
1.221 thorpej 2544: sys_chflags(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 2545: {
1.155 augustss 2546: struct sys_chflags_args /* {
1.74 cgd 2547: syscallarg(const char *) path;
2548: syscallarg(u_long) flags;
1.56 thorpej 2549: } */ *uap = v;
1.155 augustss 2550: struct vnode *vp;
1.31 cgd 2551: int error;
2552: struct nameidata nd;
2553:
1.234 christos 2554: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
1.63 christos 2555: if ((error = namei(&nd)) != 0)
1.31 cgd 2556: return (error);
2557: vp = nd.ni_vp;
1.234 christos 2558: error = change_flags(vp, SCARG(uap, flags), l);
1.31 cgd 2559: vput(vp);
2560: return (error);
2561: }
2562:
2563: /*
2564: * Change flags of a file given a file descriptor.
2565: */
2566: /* ARGSUSED */
1.63 christos 2567: int
1.221 thorpej 2568: sys_fchflags(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 2569: {
1.155 augustss 2570: struct sys_fchflags_args /* {
1.35 cgd 2571: syscallarg(int) fd;
1.74 cgd 2572: syscallarg(u_long) flags;
1.56 thorpej 2573: } */ *uap = v;
1.179 thorpej 2574: struct proc *p = l->l_proc;
1.31 cgd 2575: struct vnode *vp;
2576: struct file *fp;
2577: int error;
2578:
1.135 thorpej 2579: /* getvnode() will use the descriptor for us */
1.63 christos 2580: if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
1.31 cgd 2581: return (error);
1.62 mycroft 2582: vp = (struct vnode *)fp->f_data;
1.234 christos 2583: error = change_flags(vp, SCARG(uap, flags), l);
1.113 fvdl 2584: VOP_UNLOCK(vp, 0);
1.234 christos 2585: FILE_UNUSE(fp, l);
1.156 mrg 2586: return (error);
2587: }
2588:
2589: /*
1.163 enami 2590: * Change flags of a file given a path name; this version does
1.156 mrg 2591: * not follow links.
2592: */
2593: int
1.221 thorpej 2594: sys_lchflags(struct lwp *l, void *v, register_t *retval)
1.156 mrg 2595: {
1.163 enami 2596: struct sys_lchflags_args /* {
1.156 mrg 2597: syscallarg(const char *) path;
2598: syscallarg(u_long) flags;
2599: } */ *uap = v;
1.163 enami 2600: struct vnode *vp;
1.156 mrg 2601: int error;
2602: struct nameidata nd;
2603:
1.234 christos 2604: NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
1.156 mrg 2605: if ((error = namei(&nd)) != 0)
2606: return (error);
2607: vp = nd.ni_vp;
1.234 christos 2608: error = change_flags(vp, SCARG(uap, flags), l);
1.163 enami 2609: vput(vp);
2610: return (error);
2611: }
2612:
2613: /*
2614: * Common routine to change flags of a file.
2615: */
2616: int
1.234 christos 2617: change_flags(struct vnode *vp, u_long flags, struct lwp *l)
1.163 enami 2618: {
1.197 hannken 2619: struct mount *mp;
1.163 enami 2620: struct vattr vattr;
2621: int error;
2622:
1.197 hannken 2623: if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0)
2624: return (error);
1.257 ad 2625: VOP_LEASE(vp, l, l->l_cred, LEASE_WRITE);
1.156 mrg 2626: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.163 enami 2627: /*
2628: * Non-superusers cannot change the flags on devices, even if they
2629: * own them.
2630: */
1.257 ad 2631: if (kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER,
2632: &l->l_acflag) != 0) {
2633: if ((error = VOP_GETATTR(vp, &vattr, l->l_cred, l)) != 0)
1.156 mrg 2634: goto out;
2635: if (vattr.va_type == VCHR || vattr.va_type == VBLK) {
2636: error = EINVAL;
2637: goto out;
2638: }
2639: }
2640: VATTR_NULL(&vattr);
1.163 enami 2641: vattr.va_flags = flags;
1.257 ad 2642: error = VOP_SETATTR(vp, &vattr, l->l_cred, l);
1.156 mrg 2643: out:
1.197 hannken 2644: vn_finished_write(mp, 0);
1.31 cgd 2645: return (error);
2646: }
2647:
2648: /*
1.98 enami 2649: * Change mode of a file given path name; this version follows links.
1.31 cgd 2650: */
2651: /* ARGSUSED */
1.63 christos 2652: int
1.221 thorpej 2653: sys_chmod(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 2654: {
1.155 augustss 2655: struct sys_chmod_args /* {
1.74 cgd 2656: syscallarg(const char *) path;
1.35 cgd 2657: syscallarg(int) mode;
1.56 thorpej 2658: } */ *uap = v;
1.31 cgd 2659: int error;
2660: struct nameidata nd;
2661:
1.234 christos 2662: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
1.63 christos 2663: if ((error = namei(&nd)) != 0)
1.31 cgd 2664: return (error);
1.97 enami 2665:
1.234 christos 2666: error = change_mode(nd.ni_vp, SCARG(uap, mode), l);
1.97 enami 2667:
2668: vrele(nd.ni_vp);
1.31 cgd 2669: return (error);
2670: }
2671:
2672: /*
2673: * Change mode of a file given a file descriptor.
2674: */
2675: /* ARGSUSED */
1.63 christos 2676: int
1.221 thorpej 2677: sys_fchmod(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 2678: {
1.155 augustss 2679: struct sys_fchmod_args /* {
1.35 cgd 2680: syscallarg(int) fd;
2681: syscallarg(int) mode;
1.56 thorpej 2682: } */ *uap = v;
1.179 thorpej 2683: struct proc *p = l->l_proc;
1.31 cgd 2684: struct file *fp;
2685: int error;
2686:
1.135 thorpej 2687: /* getvnode() will use the descriptor for us */
1.63 christos 2688: if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
1.31 cgd 2689: return (error);
1.97 enami 2690:
1.234 christos 2691: error = change_mode((struct vnode *)fp->f_data, SCARG(uap, mode), l);
2692: FILE_UNUSE(fp, l);
1.135 thorpej 2693: return (error);
1.97 enami 2694: }
2695:
2696: /*
1.98 enami 2697: * Change mode of a file given path name; this version does not follow links.
2698: */
2699: /* ARGSUSED */
2700: int
1.221 thorpej 2701: sys_lchmod(struct lwp *l, void *v, register_t *retval)
1.98 enami 2702: {
1.155 augustss 2703: struct sys_lchmod_args /* {
1.98 enami 2704: syscallarg(const char *) path;
2705: syscallarg(int) mode;
2706: } */ *uap = v;
2707: int error;
2708: struct nameidata nd;
2709:
1.234 christos 2710: NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
1.98 enami 2711: if ((error = namei(&nd)) != 0)
2712: return (error);
2713:
1.234 christos 2714: error = change_mode(nd.ni_vp, SCARG(uap, mode), l);
1.98 enami 2715:
2716: vrele(nd.ni_vp);
2717: return (error);
2718: }
2719:
2720: /*
1.97 enami 2721: * Common routine to set mode given a vnode.
2722: */
2723: static int
1.234 christos 2724: change_mode(struct vnode *vp, int mode, struct lwp *l)
1.97 enami 2725: {
1.197 hannken 2726: struct mount *mp;
1.97 enami 2727: struct vattr vattr;
2728: int error;
2729:
1.197 hannken 2730: if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0)
2731: return (error);
1.257 ad 2732: VOP_LEASE(vp, l, l->l_cred, LEASE_WRITE);
1.113 fvdl 2733: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2734: VATTR_NULL(&vattr);
2735: vattr.va_mode = mode & ALLPERMS;
1.257 ad 2736: error = VOP_SETATTR(vp, &vattr, l->l_cred, l);
1.113 fvdl 2737: VOP_UNLOCK(vp, 0);
1.197 hannken 2738: vn_finished_write(mp, 0);
1.31 cgd 2739: return (error);
2740: }
2741:
2742: /*
1.98 enami 2743: * Set ownership given a path name; this version follows links.
1.31 cgd 2744: */
2745: /* ARGSUSED */
1.63 christos 2746: int
1.221 thorpej 2747: sys_chown(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 2748: {
1.155 augustss 2749: struct sys_chown_args /* {
1.74 cgd 2750: syscallarg(const char *) path;
2751: syscallarg(uid_t) uid;
2752: syscallarg(gid_t) gid;
1.56 thorpej 2753: } */ *uap = v;
1.31 cgd 2754: int error;
2755: struct nameidata nd;
2756:
1.234 christos 2757: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
1.63 christos 2758: if ((error = namei(&nd)) != 0)
1.31 cgd 2759: return (error);
1.86 kleink 2760:
1.234 christos 2761: error = change_owner(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid), l, 0);
1.112 kleink 2762:
2763: vrele(nd.ni_vp);
2764: return (error);
2765: }
2766:
2767: /*
2768: * Set ownership given a path name; this version follows links.
2769: * Provides POSIX semantics.
2770: */
2771: /* ARGSUSED */
2772: int
1.221 thorpej 2773: sys___posix_chown(struct lwp *l, void *v, register_t *retval)
1.112 kleink 2774: {
1.155 augustss 2775: struct sys_chown_args /* {
1.112 kleink 2776: syscallarg(const char *) path;
2777: syscallarg(uid_t) uid;
2778: syscallarg(gid_t) gid;
2779: } */ *uap = v;
2780: int error;
2781: struct nameidata nd;
2782:
1.234 christos 2783: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
1.112 kleink 2784: if ((error = namei(&nd)) != 0)
2785: return (error);
2786:
1.234 christos 2787: error = change_owner(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid), l, 1);
1.86 kleink 2788:
2789: vrele(nd.ni_vp);
1.31 cgd 2790: return (error);
2791: }
2792:
2793: /*
2794: * Set ownership given a file descriptor.
2795: */
2796: /* ARGSUSED */
1.63 christos 2797: int
1.221 thorpej 2798: sys_fchown(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 2799: {
1.155 augustss 2800: struct sys_fchown_args /* {
1.35 cgd 2801: syscallarg(int) fd;
1.74 cgd 2802: syscallarg(uid_t) uid;
2803: syscallarg(gid_t) gid;
1.56 thorpej 2804: } */ *uap = v;
1.179 thorpej 2805: struct proc *p = l->l_proc;
1.71 mycroft 2806: int error;
1.31 cgd 2807: struct file *fp;
2808:
1.135 thorpej 2809: /* getvnode() will use the descriptor for us */
1.63 christos 2810: if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
1.31 cgd 2811: return (error);
1.86 kleink 2812:
1.135 thorpej 2813: error = change_owner((struct vnode *)fp->f_data, SCARG(uap, uid),
1.234 christos 2814: SCARG(uap, gid), l, 0);
2815: FILE_UNUSE(fp, l);
1.135 thorpej 2816: return (error);
1.112 kleink 2817: }
2818:
2819: /*
2820: * Set ownership given a file descriptor, providing POSIX/XPG semantics.
2821: */
2822: /* ARGSUSED */
2823: int
1.221 thorpej 2824: sys___posix_fchown(struct lwp *l, void *v, register_t *retval)
1.112 kleink 2825: {
1.155 augustss 2826: struct sys_fchown_args /* {
1.112 kleink 2827: syscallarg(int) fd;
2828: syscallarg(uid_t) uid;
2829: syscallarg(gid_t) gid;
2830: } */ *uap = v;
1.179 thorpej 2831: struct proc *p = l->l_proc;
1.112 kleink 2832: int error;
2833: struct file *fp;
2834:
1.135 thorpej 2835: /* getvnode() will use the descriptor for us */
1.112 kleink 2836: if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2837: return (error);
2838:
1.135 thorpej 2839: error = change_owner((struct vnode *)fp->f_data, SCARG(uap, uid),
1.234 christos 2840: SCARG(uap, gid), l, 1);
2841: FILE_UNUSE(fp, l);
1.135 thorpej 2842: return (error);
1.86 kleink 2843: }
2844:
2845: /*
1.98 enami 2846: * Set ownership given a path name; this version does not follow links.
2847: */
2848: /* ARGSUSED */
2849: int
1.221 thorpej 2850: sys_lchown(struct lwp *l, void *v, register_t *retval)
1.98 enami 2851: {
1.155 augustss 2852: struct sys_lchown_args /* {
1.98 enami 2853: syscallarg(const char *) path;
2854: syscallarg(uid_t) uid;
2855: syscallarg(gid_t) gid;
2856: } */ *uap = v;
2857: int error;
2858: struct nameidata nd;
2859:
1.234 christos 2860: NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
1.98 enami 2861: if ((error = namei(&nd)) != 0)
2862: return (error);
2863:
1.234 christos 2864: error = change_owner(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid), l, 0);
1.112 kleink 2865:
2866: vrele(nd.ni_vp);
2867: return (error);
2868: }
2869:
2870: /*
2871: * Set ownership given a path name; this version does not follow links.
2872: * Provides POSIX/XPG semantics.
2873: */
2874: /* ARGSUSED */
2875: int
1.221 thorpej 2876: sys___posix_lchown(struct lwp *l, void *v, register_t *retval)
1.112 kleink 2877: {
1.155 augustss 2878: struct sys_lchown_args /* {
1.112 kleink 2879: syscallarg(const char *) path;
2880: syscallarg(uid_t) uid;
2881: syscallarg(gid_t) gid;
2882: } */ *uap = v;
2883: int error;
2884: struct nameidata nd;
2885:
1.234 christos 2886: NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
1.112 kleink 2887: if ((error = namei(&nd)) != 0)
2888: return (error);
2889:
1.234 christos 2890: error = change_owner(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid), l, 1);
1.98 enami 2891:
2892: vrele(nd.ni_vp);
2893: return (error);
2894: }
2895:
2896: /*
1.205 junyoung 2897: * Common routine to set ownership given a vnode.
1.86 kleink 2898: */
2899: static int
1.234 christos 2900: change_owner(struct vnode *vp, uid_t uid, gid_t gid, struct lwp *l,
1.221 thorpej 2901: int posix_semantics)
1.86 kleink 2902: {
1.197 hannken 2903: struct mount *mp;
1.86 kleink 2904: struct vattr vattr;
1.112 kleink 2905: mode_t newmode;
1.86 kleink 2906: int error;
2907:
1.197 hannken 2908: if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0)
2909: return (error);
1.257 ad 2910: VOP_LEASE(vp, l, l->l_cred, LEASE_WRITE);
1.113 fvdl 2911: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.257 ad 2912: if ((error = VOP_GETATTR(vp, &vattr, l->l_cred, l)) != 0)
1.86 kleink 2913: goto out;
2914:
1.175 thorpej 2915: #define CHANGED(x) ((int)(x) != -1)
1.112 kleink 2916: newmode = vattr.va_mode;
2917: if (posix_semantics) {
2918: /*
1.114 kleink 2919: * POSIX/XPG semantics: if the caller is not the super-user,
2920: * clear set-user-id and set-group-id bits. Both POSIX and
2921: * the XPG consider the behaviour for calls by the super-user
2922: * implementation-defined; we leave the set-user-id and set-
2923: * group-id settings intact in that case.
1.112 kleink 2924: */
1.257 ad 2925: if (kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER,
1.242 elad 2926: NULL) != 0)
1.112 kleink 2927: newmode &= ~(S_ISUID | S_ISGID);
2928: } else {
2929: /*
2930: * NetBSD semantics: when changing owner and/or group,
2931: * clear the respective bit(s).
2932: */
2933: if (CHANGED(uid))
2934: newmode &= ~S_ISUID;
2935: if (CHANGED(gid))
2936: newmode &= ~S_ISGID;
2937: }
2938: /* Update va_mode iff altered. */
2939: if (vattr.va_mode == newmode)
2940: newmode = VNOVAL;
1.205 junyoung 2941:
1.86 kleink 2942: VATTR_NULL(&vattr);
1.175 thorpej 2943: vattr.va_uid = CHANGED(uid) ? uid : (uid_t)VNOVAL;
2944: vattr.va_gid = CHANGED(gid) ? gid : (gid_t)VNOVAL;
1.86 kleink 2945: vattr.va_mode = newmode;
1.257 ad 2946: error = VOP_SETATTR(vp, &vattr, l->l_cred, l);
1.112 kleink 2947: #undef CHANGED
1.205 junyoung 2948:
1.86 kleink 2949: out:
1.113 fvdl 2950: VOP_UNLOCK(vp, 0);
1.197 hannken 2951: vn_finished_write(mp, 0);
1.31 cgd 2952: return (error);
2953: }
2954:
2955: /*
1.98 enami 2956: * Set the access and modification times given a path name; this
2957: * version follows links.
1.31 cgd 2958: */
2959: /* ARGSUSED */
1.63 christos 2960: int
1.221 thorpej 2961: sys_utimes(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 2962: {
1.155 augustss 2963: struct sys_utimes_args /* {
1.74 cgd 2964: syscallarg(const char *) path;
2965: syscallarg(const struct timeval *) tptr;
1.56 thorpej 2966: } */ *uap = v;
1.31 cgd 2967: int error;
2968: struct nameidata nd;
2969:
1.234 christos 2970: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
1.96 enami 2971: if ((error = namei(&nd)) != 0)
2972: return (error);
1.97 enami 2973:
1.234 christos 2974: error = change_utimes(nd.ni_vp, SCARG(uap, tptr), l);
1.97 enami 2975:
2976: vrele(nd.ni_vp);
1.71 mycroft 2977: return (error);
2978: }
2979:
2980: /*
2981: * Set the access and modification times given a file descriptor.
2982: */
2983: /* ARGSUSED */
2984: int
1.221 thorpej 2985: sys_futimes(struct lwp *l, void *v, register_t *retval)
1.71 mycroft 2986: {
1.155 augustss 2987: struct sys_futimes_args /* {
1.71 mycroft 2988: syscallarg(int) fd;
1.74 cgd 2989: syscallarg(const struct timeval *) tptr;
1.71 mycroft 2990: } */ *uap = v;
1.179 thorpej 2991: struct proc *p = l->l_proc;
1.71 mycroft 2992: int error;
2993: struct file *fp;
2994:
1.135 thorpej 2995: /* getvnode() will use the descriptor for us */
1.96 enami 2996: if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2997: return (error);
1.97 enami 2998:
1.234 christos 2999: error = change_utimes((struct vnode *)fp->f_data, SCARG(uap, tptr), l);
3000: FILE_UNUSE(fp, l);
1.135 thorpej 3001: return (error);
1.98 enami 3002: }
3003:
3004: /*
3005: * Set the access and modification times given a path name; this
3006: * version does not follow links.
3007: */
3008: /* ARGSUSED */
3009: int
1.221 thorpej 3010: sys_lutimes(struct lwp *l, void *v, register_t *retval)
1.98 enami 3011: {
1.155 augustss 3012: struct sys_lutimes_args /* {
1.98 enami 3013: syscallarg(const char *) path;
3014: syscallarg(const struct timeval *) tptr;
3015: } */ *uap = v;
3016: int error;
3017: struct nameidata nd;
3018:
1.234 christos 3019: NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
1.98 enami 3020: if ((error = namei(&nd)) != 0)
3021: return (error);
3022:
1.234 christos 3023: error = change_utimes(nd.ni_vp, SCARG(uap, tptr), l);
1.98 enami 3024:
3025: vrele(nd.ni_vp);
3026: return (error);
1.97 enami 3027: }
3028:
3029: /*
3030: * Common routine to set access and modification times given a vnode.
3031: */
3032: static int
1.234 christos 3033: change_utimes(struct vnode *vp, const struct timeval *tptr, struct lwp *l)
1.97 enami 3034: {
1.197 hannken 3035: struct mount *mp;
1.97 enami 3036: struct vattr vattr;
3037: int error;
3038:
1.197 hannken 3039: if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0)
3040: return (error);
1.71 mycroft 3041: VATTR_NULL(&vattr);
1.97 enami 3042: if (tptr == NULL) {
1.233 yamt 3043: nanotime(&vattr.va_atime);
3044: vattr.va_mtime = vattr.va_atime;
1.71 mycroft 3045: vattr.va_vaflags |= VA_UTIMES_NULL;
3046: } else {
1.233 yamt 3047: struct timeval tv[2];
3048:
1.122 perry 3049: error = copyin(tptr, tv, sizeof(tv));
1.71 mycroft 3050: if (error)
1.197 hannken 3051: goto out;
1.233 yamt 3052: TIMEVAL_TO_TIMESPEC(&tv[0], &vattr.va_atime);
3053: TIMEVAL_TO_TIMESPEC(&tv[1], &vattr.va_mtime);
1.71 mycroft 3054: }
1.257 ad 3055: VOP_LEASE(vp, l, l->l_cred, LEASE_WRITE);
1.113 fvdl 3056: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.257 ad 3057: error = VOP_SETATTR(vp, &vattr, l->l_cred, l);
1.113 fvdl 3058: VOP_UNLOCK(vp, 0);
1.197 hannken 3059: out:
3060: vn_finished_write(mp, 0);
1.31 cgd 3061: return (error);
3062: }
3063:
3064: /*
3065: * Truncate a file given its path name.
3066: */
3067: /* ARGSUSED */
1.63 christos 3068: int
1.221 thorpej 3069: sys_truncate(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 3070: {
1.155 augustss 3071: struct sys_truncate_args /* {
1.74 cgd 3072: syscallarg(const char *) path;
1.35 cgd 3073: syscallarg(int) pad;
3074: syscallarg(off_t) length;
1.56 thorpej 3075: } */ *uap = v;
1.155 augustss 3076: struct vnode *vp;
1.197 hannken 3077: struct mount *mp;
1.31 cgd 3078: struct vattr vattr;
3079: int error;
3080: struct nameidata nd;
3081:
1.234 christos 3082: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
1.63 christos 3083: if ((error = namei(&nd)) != 0)
1.31 cgd 3084: return (error);
3085: vp = nd.ni_vp;
1.197 hannken 3086: if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0) {
3087: vrele(vp);
3088: return (error);
3089: }
1.257 ad 3090: VOP_LEASE(vp, l, l->l_cred, LEASE_WRITE);
1.113 fvdl 3091: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.31 cgd 3092: if (vp->v_type == VDIR)
3093: error = EISDIR;
3094: else if ((error = vn_writechk(vp)) == 0 &&
1.257 ad 3095: (error = VOP_ACCESS(vp, VWRITE, l->l_cred, l)) == 0) {
1.31 cgd 3096: VATTR_NULL(&vattr);
1.35 cgd 3097: vattr.va_size = SCARG(uap, length);
1.257 ad 3098: error = VOP_SETATTR(vp, &vattr, l->l_cred, l);
1.31 cgd 3099: }
3100: vput(vp);
1.197 hannken 3101: vn_finished_write(mp, 0);
1.31 cgd 3102: return (error);
3103: }
3104:
3105: /*
3106: * Truncate a file given a file descriptor.
3107: */
3108: /* ARGSUSED */
1.63 christos 3109: int
1.221 thorpej 3110: sys_ftruncate(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 3111: {
1.155 augustss 3112: struct sys_ftruncate_args /* {
1.35 cgd 3113: syscallarg(int) fd;
3114: syscallarg(int) pad;
3115: syscallarg(off_t) length;
1.56 thorpej 3116: } */ *uap = v;
1.179 thorpej 3117: struct proc *p = l->l_proc;
1.197 hannken 3118: struct mount *mp;
1.31 cgd 3119: struct vattr vattr;
3120: struct vnode *vp;
3121: struct file *fp;
3122: int error;
3123:
1.135 thorpej 3124: /* getvnode() will use the descriptor for us */
1.63 christos 3125: if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
1.31 cgd 3126: return (error);
1.135 thorpej 3127: if ((fp->f_flag & FWRITE) == 0) {
3128: error = EINVAL;
3129: goto out;
3130: }
1.62 mycroft 3131: vp = (struct vnode *)fp->f_data;
1.197 hannken 3132: if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0) {
1.234 christos 3133: FILE_UNUSE(fp, l);
1.197 hannken 3134: return (error);
3135: }
1.257 ad 3136: VOP_LEASE(vp, l, l->l_cred, LEASE_WRITE);
1.113 fvdl 3137: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.31 cgd 3138: if (vp->v_type == VDIR)
3139: error = EISDIR;
3140: else if ((error = vn_writechk(vp)) == 0) {
3141: VATTR_NULL(&vattr);
1.35 cgd 3142: vattr.va_size = SCARG(uap, length);
1.234 christos 3143: error = VOP_SETATTR(vp, &vattr, fp->f_cred, l);
1.31 cgd 3144: }
1.113 fvdl 3145: VOP_UNLOCK(vp, 0);
1.197 hannken 3146: vn_finished_write(mp, 0);
1.135 thorpej 3147: out:
1.234 christos 3148: FILE_UNUSE(fp, l);
1.31 cgd 3149: return (error);
3150: }
3151:
3152: /*
3153: * Sync an open file.
3154: */
3155: /* ARGSUSED */
1.63 christos 3156: int
1.221 thorpej 3157: sys_fsync(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 3158: {
1.57 mycroft 3159: struct sys_fsync_args /* {
1.35 cgd 3160: syscallarg(int) fd;
1.56 thorpej 3161: } */ *uap = v;
1.179 thorpej 3162: struct proc *p = l->l_proc;
1.155 augustss 3163: struct vnode *vp;
1.197 hannken 3164: struct mount *mp;
1.31 cgd 3165: struct file *fp;
3166: int error;
3167:
1.135 thorpej 3168: /* getvnode() will use the descriptor for us */
1.63 christos 3169: if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
1.31 cgd 3170: return (error);
1.62 mycroft 3171: vp = (struct vnode *)fp->f_data;
1.197 hannken 3172: if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0) {
1.234 christos 3173: FILE_UNUSE(fp, l);
1.197 hannken 3174: return (error);
3175: }
1.113 fvdl 3176: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.234 christos 3177: error = VOP_FSYNC(vp, fp->f_cred, FSYNC_WAIT, 0, 0, l);
1.148 fvdl 3178: if (error == 0 && bioops.io_fsync != NULL &&
3179: vp->v_mount && (vp->v_mount->mnt_flag & MNT_SOFTDEP))
1.216 wrstuden 3180: (*bioops.io_fsync)(vp, 0);
1.113 fvdl 3181: VOP_UNLOCK(vp, 0);
1.197 hannken 3182: vn_finished_write(mp, 0);
1.234 christos 3183: FILE_UNUSE(fp, l);
1.201 thorpej 3184: return (error);
3185: }
3186:
3187: /*
3188: * Sync a range of file data. API modeled after that found in AIX.
3189: *
3190: * FDATASYNC indicates that we need only save enough metadata to be able
3191: * to re-read the written data. Note we duplicate AIX's requirement that
3192: * the file be open for writing.
3193: */
3194: /* ARGSUSED */
3195: int
1.221 thorpej 3196: sys_fsync_range(struct lwp *l, void *v, register_t *retval)
1.201 thorpej 3197: {
3198: struct sys_fsync_range_args /* {
3199: syscallarg(int) fd;
3200: syscallarg(int) flags;
3201: syscallarg(off_t) start;
1.225 cube 3202: syscallarg(off_t) length;
1.201 thorpej 3203: } */ *uap = v;
3204: struct proc *p = l->l_proc;
3205: struct vnode *vp;
3206: struct file *fp;
3207: int flags, nflags;
3208: off_t s, e, len;
3209: int error;
3210:
3211: /* getvnode() will use the descriptor for us */
3212: if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
3213: return (error);
3214:
3215: if ((fp->f_flag & FWRITE) == 0) {
1.234 christos 3216: FILE_UNUSE(fp, l);
1.201 thorpej 3217: return (EBADF);
3218: }
3219:
3220: flags = SCARG(uap, flags);
3221: if (((flags & (FDATASYNC | FFILESYNC)) == 0) ||
3222: ((~flags & (FDATASYNC | FFILESYNC)) == 0)) {
3223: return (EINVAL);
3224: }
3225: /* Now set up the flags for value(s) to pass to VOP_FSYNC() */
3226: if (flags & FDATASYNC)
3227: nflags = FSYNC_DATAONLY | FSYNC_WAIT;
3228: else
3229: nflags = FSYNC_WAIT;
1.216 wrstuden 3230: if (flags & FDISKSYNC)
3231: nflags |= FSYNC_CACHE;
1.201 thorpej 3232:
3233: len = SCARG(uap, length);
3234: /* If length == 0, we do the whole file, and s = l = 0 will do that */
3235: if (len) {
3236: s = SCARG(uap, start);
3237: e = s + len;
3238: if (e < s) {
1.234 christos 3239: FILE_UNUSE(fp, l);
1.201 thorpej 3240: return (EINVAL);
3241: }
3242: } else {
3243: e = 0;
3244: s = 0;
3245: }
3246:
3247: vp = (struct vnode *)fp->f_data;
3248: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.234 christos 3249: error = VOP_FSYNC(vp, fp->f_cred, nflags, s, e, l);
1.201 thorpej 3250:
3251: if (error == 0 && bioops.io_fsync != NULL &&
3252: vp->v_mount && (vp->v_mount->mnt_flag & MNT_SOFTDEP))
1.216 wrstuden 3253: (*bioops.io_fsync)(vp, nflags);
1.201 thorpej 3254:
3255: VOP_UNLOCK(vp, 0);
1.234 christos 3256: FILE_UNUSE(fp, l);
1.31 cgd 3257: return (error);
3258: }
3259:
3260: /*
1.117 kleink 3261: * Sync the data of an open file.
3262: */
3263: /* ARGSUSED */
3264: int
1.221 thorpej 3265: sys_fdatasync(struct lwp *l, void *v, register_t *retval)
1.117 kleink 3266: {
3267: struct sys_fdatasync_args /* {
3268: syscallarg(int) fd;
3269: } */ *uap = v;
1.179 thorpej 3270: struct proc *p = l->l_proc;
1.117 kleink 3271: struct vnode *vp;
3272: struct file *fp;
3273: int error;
3274:
1.135 thorpej 3275: /* getvnode() will use the descriptor for us */
1.117 kleink 3276: if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
3277: return (error);
1.199 kleink 3278: if ((fp->f_flag & FWRITE) == 0) {
1.234 christos 3279: FILE_UNUSE(fp, l);
1.199 kleink 3280: return (EBADF);
3281: }
1.117 kleink 3282: vp = (struct vnode *)fp->f_data;
3283: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.234 christos 3284: error = VOP_FSYNC(vp, fp->f_cred, FSYNC_WAIT|FSYNC_DATAONLY, 0, 0, l);
1.117 kleink 3285: VOP_UNLOCK(vp, 0);
1.234 christos 3286: FILE_UNUSE(fp, l);
1.117 kleink 3287: return (error);
3288: }
3289:
3290: /*
1.90 kleink 3291: * Rename files, (standard) BSD semantics frontend.
1.31 cgd 3292: */
3293: /* ARGSUSED */
1.63 christos 3294: int
1.221 thorpej 3295: sys_rename(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 3296: {
1.155 augustss 3297: struct sys_rename_args /* {
1.74 cgd 3298: syscallarg(const char *) from;
3299: syscallarg(const char *) to;
1.56 thorpej 3300: } */ *uap = v;
1.90 kleink 3301:
1.234 christos 3302: return (rename_files(SCARG(uap, from), SCARG(uap, to), l, 0));
1.90 kleink 3303: }
3304:
3305: /*
3306: * Rename files, POSIX semantics frontend.
3307: */
3308: /* ARGSUSED */
3309: int
1.221 thorpej 3310: sys___posix_rename(struct lwp *l, void *v, register_t *retval)
1.90 kleink 3311: {
1.155 augustss 3312: struct sys___posix_rename_args /* {
1.90 kleink 3313: syscallarg(const char *) from;
3314: syscallarg(const char *) to;
3315: } */ *uap = v;
3316:
1.234 christos 3317: return (rename_files(SCARG(uap, from), SCARG(uap, to), l, 1));
1.90 kleink 3318: }
3319:
3320: /*
3321: * Rename files. Source and destination must either both be directories,
3322: * or both not be directories. If target is a directory, it must be empty.
3323: * If `from' and `to' refer to the same object, the value of the `retain'
3324: * argument is used to determine whether `from' will be
3325: *
3326: * (retain == 0) deleted unless `from' and `to' refer to the same
3327: * object in the file system's name space (BSD).
3328: * (retain == 1) always retained (POSIX).
3329: */
3330: static int
1.234 christos 3331: rename_files(const char *from, const char *to, struct lwp *l, int retain)
1.90 kleink 3332: {
1.197 hannken 3333: struct mount *mp = NULL;
1.155 augustss 3334: struct vnode *tvp, *fvp, *tdvp;
1.31 cgd 3335: struct nameidata fromnd, tond;
1.234 christos 3336: struct proc *p;
1.31 cgd 3337: int error;
3338:
3339: NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
1.234 christos 3340: from, l);
1.63 christos 3341: if ((error = namei(&fromnd)) != 0)
1.31 cgd 3342: return (error);
3343: fvp = fromnd.ni_vp;
1.197 hannken 3344: error = vn_start_write(fvp, &mp, V_WAIT | V_PCATCH);
3345: if (error != 0) {
3346: VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
3347: vrele(fromnd.ni_dvp);
3348: vrele(fvp);
3349: if (fromnd.ni_startdir)
3350: vrele(fromnd.ni_startdir);
3351: PNBUF_PUT(fromnd.ni_cnd.cn_pnbuf);
3352: return (error);
3353: }
1.193 christos 3354: NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART |
1.234 christos 3355: (fvp->v_type == VDIR ? CREATEDIR : 0), UIO_USERSPACE, to, l);
1.63 christos 3356: if ((error = namei(&tond)) != 0) {
1.31 cgd 3357: VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
3358: vrele(fromnd.ni_dvp);
3359: vrele(fvp);
3360: goto out1;
3361: }
3362: tdvp = tond.ni_dvp;
3363: tvp = tond.ni_vp;
1.90 kleink 3364:
1.31 cgd 3365: if (tvp != NULL) {
3366: if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
3367: error = ENOTDIR;
3368: goto out;
3369: } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
3370: error = EISDIR;
3371: goto out;
3372: }
3373: }
1.90 kleink 3374:
1.31 cgd 3375: if (fvp == tdvp)
3376: error = EINVAL;
1.90 kleink 3377:
1.82 kleink 3378: /*
1.90 kleink 3379: * Source and destination refer to the same object.
1.82 kleink 3380: */
1.90 kleink 3381: if (fvp == tvp) {
3382: if (retain)
3383: error = -1;
3384: else if (fromnd.ni_dvp == tdvp &&
3385: fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
1.123 perry 3386: !memcmp(fromnd.ni_cnd.cn_nameptr,
1.90 kleink 3387: tond.ni_cnd.cn_nameptr,
3388: fromnd.ni_cnd.cn_namelen))
1.82 kleink 3389: error = -1;
1.90 kleink 3390: }
3391:
1.256 elad 3392: #if NVERIEXEC > 0
1.229 elad 3393: if (!error)
1.262 elad 3394: error = veriexec_renamechk(fvp, fromnd.ni_dirp, tvp,
3395: tond.ni_dirp, l);
1.256 elad 3396: #endif /* NVERIEXEC > 0 */
1.229 elad 3397:
1.31 cgd 3398: out:
1.234 christos 3399: p = l->l_proc;
1.31 cgd 3400: if (!error) {
1.257 ad 3401: VOP_LEASE(tdvp, l, l->l_cred, LEASE_WRITE);
1.31 cgd 3402: if (fromnd.ni_dvp != tdvp)
1.257 ad 3403: VOP_LEASE(fromnd.ni_dvp, l, l->l_cred, LEASE_WRITE);
1.75 fvdl 3404: if (tvp) {
1.257 ad 3405: VOP_LEASE(tvp, l, l->l_cred, LEASE_WRITE);
1.75 fvdl 3406: }
1.31 cgd 3407: error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
3408: tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
3409: } else {
3410: VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
3411: if (tdvp == tvp)
3412: vrele(tdvp);
3413: else
3414: vput(tdvp);
3415: if (tvp)
3416: vput(tvp);
3417: VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
3418: vrele(fromnd.ni_dvp);
3419: vrele(fvp);
3420: }
3421: vrele(tond.ni_startdir);
1.161 thorpej 3422: PNBUF_PUT(tond.ni_cnd.cn_pnbuf);
1.31 cgd 3423: out1:
1.197 hannken 3424: vn_finished_write(mp, 0);
1.31 cgd 3425: if (fromnd.ni_startdir)
3426: vrele(fromnd.ni_startdir);
1.161 thorpej 3427: PNBUF_PUT(fromnd.ni_cnd.cn_pnbuf);
1.80 kleink 3428: return (error == -1 ? 0 : error);
1.31 cgd 3429: }
3430:
3431: /*
3432: * Make a directory file.
3433: */
3434: /* ARGSUSED */
1.63 christos 3435: int
1.221 thorpej 3436: sys_mkdir(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 3437: {
1.155 augustss 3438: struct sys_mkdir_args /* {
1.74 cgd 3439: syscallarg(const char *) path;
1.35 cgd 3440: syscallarg(int) mode;
1.56 thorpej 3441: } */ *uap = v;
1.179 thorpej 3442: struct proc *p = l->l_proc;
1.197 hannken 3443: struct mount *mp;
1.155 augustss 3444: struct vnode *vp;
1.31 cgd 3445: struct vattr vattr;
3446: int error;
3447: struct nameidata nd;
3448:
1.197 hannken 3449: restart:
1.193 christos 3450: NDINIT(&nd, CREATE, LOCKPARENT | CREATEDIR, UIO_USERSPACE,
1.234 christos 3451: SCARG(uap, path), l);
1.63 christos 3452: if ((error = namei(&nd)) != 0)
1.31 cgd 3453: return (error);
3454: vp = nd.ni_vp;
3455: if (vp != NULL) {
3456: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
3457: if (nd.ni_dvp == vp)
3458: vrele(nd.ni_dvp);
3459: else
3460: vput(nd.ni_dvp);
3461: vrele(vp);
3462: return (EEXIST);
3463: }
1.197 hannken 3464: if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
3465: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
3466: if (nd.ni_dvp == vp)
3467: vrele(nd.ni_dvp);
3468: else
3469: vput(nd.ni_dvp);
3470: if ((error = vn_start_write(NULL, &mp,
3471: V_WAIT | V_SLEEPONLY | V_PCATCH)) != 0)
3472: return (error);
3473: goto restart;
3474: }
1.31 cgd 3475: VATTR_NULL(&vattr);
3476: vattr.va_type = VDIR;
1.134 thorpej 3477: vattr.va_mode =
3478: (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_cwdi->cwdi_cmask;
1.257 ad 3479: VOP_LEASE(nd.ni_dvp, l, l->l_cred, LEASE_WRITE);
1.31 cgd 3480: error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
3481: if (!error)
3482: vput(nd.ni_vp);
1.197 hannken 3483: vn_finished_write(mp, 0);
1.31 cgd 3484: return (error);
3485: }
3486:
3487: /*
3488: * Remove a directory file.
3489: */
3490: /* ARGSUSED */
1.63 christos 3491: int
1.221 thorpej 3492: sys_rmdir(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 3493: {
1.57 mycroft 3494: struct sys_rmdir_args /* {
1.74 cgd 3495: syscallarg(const char *) path;
1.56 thorpej 3496: } */ *uap = v;
1.197 hannken 3497: struct mount *mp;
1.155 augustss 3498: struct vnode *vp;
1.31 cgd 3499: int error;
3500: struct nameidata nd;
3501:
1.197 hannken 3502: restart:
1.35 cgd 3503: NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
1.234 christos 3504: SCARG(uap, path), l);
1.63 christos 3505: if ((error = namei(&nd)) != 0)
1.31 cgd 3506: return (error);
3507: vp = nd.ni_vp;
3508: if (vp->v_type != VDIR) {
3509: error = ENOTDIR;
3510: goto out;
3511: }
3512: /*
3513: * No rmdir "." please.
3514: */
3515: if (nd.ni_dvp == vp) {
3516: error = EINVAL;
3517: goto out;
3518: }
3519: /*
3520: * The root of a mounted filesystem cannot be deleted.
3521: */
1.197 hannken 3522: if (vp->v_flag & VROOT) {
1.31 cgd 3523: error = EBUSY;
1.197 hannken 3524: goto out;
3525: }
3526: if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1.31 cgd 3527: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
3528: if (nd.ni_dvp == vp)
3529: vrele(nd.ni_dvp);
3530: else
3531: vput(nd.ni_dvp);
3532: vput(vp);
1.197 hannken 3533: if ((error = vn_start_write(NULL, &mp,
3534: V_WAIT | V_SLEEPONLY | V_PCATCH)) != 0)
3535: return (error);
3536: goto restart;
1.31 cgd 3537: }
1.257 ad 3538: VOP_LEASE(nd.ni_dvp, l, l->l_cred, LEASE_WRITE);
3539: VOP_LEASE(vp, l, l->l_cred, LEASE_WRITE);
1.197 hannken 3540: error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
3541: vn_finished_write(mp, 0);
3542: return (error);
3543:
3544: out:
3545: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
3546: if (nd.ni_dvp == vp)
3547: vrele(nd.ni_dvp);
3548: else
3549: vput(nd.ni_dvp);
3550: vput(vp);
1.31 cgd 3551: return (error);
3552: }
3553:
3554: /*
3555: * Read a block of directory entries in a file system independent format.
3556: */
1.63 christos 3557: int
1.228 christos 3558: sys___getdents30(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 3559: {
1.228 christos 3560: struct sys___getdents30_args /* {
1.35 cgd 3561: syscallarg(int) fd;
3562: syscallarg(char *) buf;
1.101 fvdl 3563: syscallarg(size_t) count;
1.56 thorpej 3564: } */ *uap = v;
1.179 thorpej 3565: struct proc *p = l->l_proc;
1.31 cgd 3566: struct file *fp;
1.101 fvdl 3567: int error, done;
1.31 cgd 3568:
1.135 thorpej 3569: /* getvnode() will use the descriptor for us */
1.63 christos 3570: if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
1.31 cgd 3571: return (error);
1.135 thorpej 3572: if ((fp->f_flag & FREAD) == 0) {
3573: error = EBADF;
3574: goto out;
3575: }
1.101 fvdl 3576: error = vn_readdir(fp, SCARG(uap, buf), UIO_USERSPACE,
1.234 christos 3577: SCARG(uap, count), &done, l, 0, 0);
1.192 drochner 3578: #ifdef KTRACE
3579: if (!error && KTRPOINT(p, KTR_GENIO)) {
3580: struct iovec iov;
3581: iov.iov_base = SCARG(uap, buf);
3582: iov.iov_len = done;
1.234 christos 3583: ktrgenio(l, SCARG(uap, fd), UIO_READ, &iov, done, 0);
1.192 drochner 3584: }
3585: #endif
1.101 fvdl 3586: *retval = done;
1.135 thorpej 3587: out:
1.234 christos 3588: FILE_UNUSE(fp, l);
1.31 cgd 3589: return (error);
3590: }
3591:
3592: /*
3593: * Set the mode mask for creation of filesystem nodes.
3594: */
1.56 thorpej 3595: int
1.221 thorpej 3596: sys_umask(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 3597: {
1.57 mycroft 3598: struct sys_umask_args /* {
1.103 mycroft 3599: syscallarg(mode_t) newmask;
1.56 thorpej 3600: } */ *uap = v;
1.179 thorpej 3601: struct proc *p = l->l_proc;
1.134 thorpej 3602: struct cwdinfo *cwdi;
1.31 cgd 3603:
1.134 thorpej 3604: cwdi = p->p_cwdi;
3605: *retval = cwdi->cwdi_cmask;
3606: cwdi->cwdi_cmask = SCARG(uap, newmask) & ALLPERMS;
1.31 cgd 3607: return (0);
3608: }
3609:
3610: /*
3611: * Void all references to file by ripping underlying filesystem
3612: * away from vnode.
3613: */
3614: /* ARGSUSED */
1.63 christos 3615: int
1.221 thorpej 3616: sys_revoke(struct lwp *l, void *v, register_t *retval)
1.56 thorpej 3617: {
1.155 augustss 3618: struct sys_revoke_args /* {
1.74 cgd 3619: syscallarg(const char *) path;
1.56 thorpej 3620: } */ *uap = v;
1.197 hannken 3621: struct mount *mp;
1.155 augustss 3622: struct vnode *vp;
1.31 cgd 3623: struct vattr vattr;
3624: int error;
3625: struct nameidata nd;
3626:
1.234 christos 3627: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
1.63 christos 3628: if ((error = namei(&nd)) != 0)
1.31 cgd 3629: return (error);
3630: vp = nd.ni_vp;
1.257 ad 3631: if ((error = VOP_GETATTR(vp, &vattr, l->l_cred, l)) != 0)
1.31 cgd 3632: goto out;
1.257 ad 3633: if (kauth_cred_geteuid(l->l_cred) != vattr.va_uid &&
3634: (error = kauth_authorize_generic(l->l_cred,
3635: KAUTH_GENERIC_ISSUSER, &l->l_acflag)) != 0)
1.31 cgd 3636: goto out;
1.197 hannken 3637: if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0)
3638: goto out;
1.145 wrstuden 3639: if (vp->v_usecount > 1 || (vp->v_flag & (VALIASED | VLAYER)))
1.113 fvdl 3640: VOP_REVOKE(vp, REVOKEALL);
1.197 hannken 3641: vn_finished_write(mp, 0);
1.31 cgd 3642: out:
3643: vrele(vp);
3644: return (error);
3645: }
3646:
3647: /*
3648: * Convert a user file descriptor to a kernel file entry.
3649: */
1.60 mycroft 3650: int
1.221 thorpej 3651: getvnode(struct filedesc *fdp, int fd, struct file **fpp)
1.31 cgd 3652: {
1.60 mycroft 3653: struct vnode *vp;
1.31 cgd 3654: struct file *fp;
3655:
1.166 thorpej 3656: if ((fp = fd_getfile(fdp, fd)) == NULL)
1.31 cgd 3657: return (EBADF);
1.135 thorpej 3658:
3659: FILE_USE(fp);
3660:
3661: if (fp->f_type != DTYPE_VNODE) {
3662: FILE_UNUSE(fp, NULL);
1.31 cgd 3663: return (EINVAL);
1.135 thorpej 3664: }
3665:
1.60 mycroft 3666: vp = (struct vnode *)fp->f_data;
1.135 thorpej 3667: if (vp->v_type == VBAD) {
3668: FILE_UNUSE(fp, NULL);
1.60 mycroft 3669: return (EBADF);
1.135 thorpej 3670: }
3671:
1.31 cgd 3672: *fpp = fp;
3673: return (0);
3674: }
CVSweb <webmaster@jp.NetBSD.org>