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