Annotation of src/sys/kern/vfs_syscalls.c, Revision 1.486
1.486 ! dholland 1: /* $NetBSD: vfs_syscalls.c,v 1.485 2014/06/26 01:46:03 christos Exp $ */
1.345 ad 2:
3: /*-
1.390 ad 4: * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
1.345 ad 5: * All rights reserved.
6: *
1.390 ad 7: * This code is derived from software contributed to The NetBSD Foundation
8: * by Andrew Doran.
9: *
1.345 ad 10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29: * POSSIBILITY OF SUCH DAMAGE.
30: */
1.31 cgd 31:
32: /*
33: * Copyright (c) 1989, 1993
34: * The Regents of the University of California. All rights reserved.
35: * (c) UNIX System Laboratories, Inc.
36: * All or some portions of this file are derived from material licensed
37: * to the University of California by American Telephone and Telegraph
38: * Co. or Unix System Laboratories, Inc. and are reproduced herein with
39: * the permission of UNIX System Laboratories, Inc.
40: *
41: * Redistribution and use in source and binary forms, with or without
42: * modification, are permitted provided that the following conditions
43: * are met:
44: * 1. Redistributions of source code must retain the above copyright
45: * notice, this list of conditions and the following disclaimer.
46: * 2. Redistributions in binary form must reproduce the above copyright
47: * notice, this list of conditions and the following disclaimer in the
48: * documentation and/or other materials provided with the distribution.
1.191 agc 49: * 3. Neither the name of the University nor the names of its contributors
1.31 cgd 50: * may be used to endorse or promote products derived from this software
51: * without specific prior written permission.
52: *
53: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63: * SUCH DAMAGE.
64: *
1.113 fvdl 65: * @(#)vfs_syscalls.c 8.42 (Berkeley) 7/31/95
1.31 cgd 66: */
1.173 lukem 67:
1.420 rmind 68: /*
69: * Virtual File System System Calls
70: */
71:
1.173 lukem 72: #include <sys/cdefs.h>
1.486 ! dholland 73: __KERNEL_RCSID(0, "$NetBSD: vfs_syscalls.c,v 1.485 2014/06/26 01:46:03 christos Exp $");
1.111 mrg 74:
1.378 ad 75: #ifdef _KERNEL_OPT
1.258 elad 76: #include "opt_fileassoc.h"
1.261 dogcow 77: #include "veriexec.h"
1.378 ad 78: #endif
1.31 cgd 79:
80: #include <sys/param.h>
81: #include <sys/systm.h>
82: #include <sys/namei.h>
83: #include <sys/filedesc.h>
84: #include <sys/kernel.h>
85: #include <sys/file.h>
1.433 manu 86: #include <sys/fcntl.h>
1.31 cgd 87: #include <sys/stat.h>
88: #include <sys/vnode.h>
89: #include <sys/mount.h>
90: #include <sys/proc.h>
91: #include <sys/uio.h>
1.248 yamt 92: #include <sys/kmem.h>
1.31 cgd 93: #include <sys/dirent.h>
1.172 simonb 94: #include <sys/sysctl.h>
1.35 cgd 95: #include <sys/syscallargs.h>
1.306 dsl 96: #include <sys/vfs_syscalls.h>
1.444 dholland 97: #include <sys/quota.h>
98: #include <sys/quotactl.h>
1.192 drochner 99: #include <sys/ktrace.h>
1.251 elad 100: #ifdef FILEASSOC
101: #include <sys/fileassoc.h>
102: #endif /* FILEASSOC */
1.430 manu 103: #include <sys/extattr.h>
1.219 blymn 104: #include <sys/verified_exec.h>
1.242 elad 105: #include <sys/kauth.h>
1.346 ad 106: #include <sys/atomic.h>
1.360 ad 107: #include <sys/module.h>
1.380 pooka 108: #include <sys/buf.h>
1.35 cgd 109:
1.148 fvdl 110: #include <miscfs/genfs/genfs.h>
111: #include <miscfs/syncfs/syncfs.h>
1.342 ad 112: #include <miscfs/specfs/specdev.h>
1.181 thorpej 113:
1.232 jmmv 114: #include <nfs/rpcv2.h>
115: #include <nfs/nfsproto.h>
116: #include <nfs/nfs.h>
117: #include <nfs/nfs_var.h>
118:
1.234 christos 119: static int change_flags(struct vnode *, u_long, struct lwp *);
1.476 njoly 120: static int change_mode(struct vnode *, int, struct lwp *);
1.234 christos 121: static int change_owner(struct vnode *, uid_t, gid_t, struct lwp *, int);
1.460 manu 122: static int do_sys_openat(lwp_t *, int, const char *, int, int, int *);
123: static int do_sys_mkdirat(struct lwp *l, int, const char *, mode_t,
124: enum uio_seg);
125: static int do_sys_mkfifoat(struct lwp *, int, const char *, mode_t);
126: static int do_sys_symlinkat(struct lwp *, const char *, int, const char *,
127: enum uio_seg);
128: static int do_sys_renameat(struct lwp *l, int, const char *, int, const char *,
129: enum uio_seg, int);
130: static int do_sys_readlinkat(struct lwp *, int, const char *, char *,
131: size_t, register_t *);
132: static int do_sys_unlinkat(struct lwp *, int, const char *, int, enum uio_seg);
133:
134: static int fd_nameiat(struct lwp *, int, struct nameidata *);
135: static int fd_nameiat_simple_user(struct lwp *, int, const char *,
136: namei_simple_flags_t, struct vnode **);
137:
1.63 christos 138:
1.99 thorpej 139: /*
140: * This table is used to maintain compatibility with 4.3BSD
1.378 ad 141: * and NetBSD 0.9 mount syscalls - and possibly other systems.
142: * Note, the order is important!
1.124 thorpej 143: *
1.167 jdolecek 144: * Do not modify this table. It should only contain filesystems
145: * supported by NetBSD 0.9 and 4.3BSD.
1.99 thorpej 146: */
1.167 jdolecek 147: const char * const mountcompatnames[] = {
1.99 thorpej 148: NULL, /* 0 = MOUNT_NONE */
1.167 jdolecek 149: MOUNT_FFS, /* 1 = MOUNT_UFS */
1.99 thorpej 150: MOUNT_NFS, /* 2 */
151: MOUNT_MFS, /* 3 */
152: MOUNT_MSDOS, /* 4 */
1.167 jdolecek 153: MOUNT_CD9660, /* 5 = MOUNT_ISOFS */
154: MOUNT_FDESC, /* 6 */
155: MOUNT_KERNFS, /* 7 */
156: NULL, /* 8 = MOUNT_DEVFS */
157: MOUNT_AFS, /* 9 */
1.99 thorpej 158: };
1.420 rmind 159:
160: const int nmountcompatnames = __arraycount(mountcompatnames);
1.99 thorpej 161:
1.460 manu 162: static int
163: fd_nameiat(struct lwp *l, int fdat, struct nameidata *ndp)
164: {
165: file_t *dfp;
166: int error;
167:
168: if (fdat != AT_FDCWD) {
169: if ((error = fd_getvnode(fdat, &dfp)) != 0)
170: goto out;
171:
172: NDAT(ndp, dfp->f_data);
173: }
174:
175: error = namei(ndp);
176:
177: if (fdat != AT_FDCWD)
178: fd_putfile(fdat);
179: out:
180: return error;
181: }
182:
183: static int
184: fd_nameiat_simple_user(struct lwp *l, int fdat, const char *path,
185: namei_simple_flags_t sflags, struct vnode **vp_ret)
186: {
187: file_t *dfp;
188: struct vnode *dvp;
189: int error;
190:
191: if (fdat != AT_FDCWD) {
192: if ((error = fd_getvnode(fdat, &dfp)) != 0)
193: goto out;
194:
195: dvp = dfp->f_data;
196: } else {
197: dvp = NULL;
198: }
199:
200: error = nameiat_simple_user(dvp, path, sflags, vp_ret);
201:
202: if (fdat != AT_FDCWD)
203: fd_putfile(fdat);
204: out:
205: return error;
206: }
207:
1.285 elad 208: static int
1.422 christos 209: open_setfp(struct lwp *l, file_t *fp, struct vnode *vp, int indx, int flags)
210: {
211: int error;
212:
213: fp->f_flag = flags & FMASK;
214: fp->f_type = DTYPE_VNODE;
215: fp->f_ops = &vnops;
216: fp->f_data = vp;
217:
218: if (flags & (O_EXLOCK | O_SHLOCK)) {
219: struct flock lf;
220: int type;
221:
222: lf.l_whence = SEEK_SET;
223: lf.l_start = 0;
224: lf.l_len = 0;
225: if (flags & O_EXLOCK)
226: lf.l_type = F_WRLCK;
227: else
228: lf.l_type = F_RDLCK;
229: type = F_FLOCK;
230: if ((flags & FNONBLOCK) == 0)
231: type |= F_WAIT;
232: VOP_UNLOCK(vp);
233: error = VOP_ADVLOCK(vp, fp, F_SETLK, &lf, type);
234: if (error) {
235: (void) vn_close(vp, fp->f_flag, fp->f_cred);
236: fd_abort(l->l_proc, fp, indx);
237: return error;
238: }
239: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
240: atomic_or_uint(&fp->f_flag, FHASLOCK);
241: }
242: if (flags & O_CLOEXEC)
243: fd_set_exclose(l, indx, true);
244: return 0;
245: }
246:
247: static int
1.283 elad 248: mount_update(struct lwp *l, struct vnode *vp, const char *path, int flags,
1.324 pooka 249: void *data, size_t *data_len)
1.56 thorpej 250: {
1.113 fvdl 251: struct mount *mp;
1.283 elad 252: int error = 0, saved_flags;
253:
254: mp = vp->v_mount;
255: saved_flags = mp->mnt_flag;
256:
1.329 ad 257: /* We can operate only on VV_ROOT nodes. */
258: if ((vp->v_vflag & VV_ROOT) == 0) {
259: error = EINVAL;
260: goto out;
261: }
1.31 cgd 262:
1.218 yamt 263: /*
1.283 elad 264: * We only allow the filesystem to be reloaded if it
1.373 ad 265: * is currently mounted read-only. Additionally, we
266: * prevent read-write to read-only downgrades.
1.283 elad 267: */
1.373 ad 268: if ((flags & (MNT_RELOAD | MNT_RDONLY)) != 0 &&
1.414 pooka 269: (mp->mnt_flag & MNT_RDONLY) == 0 &&
270: (mp->mnt_iflag & IMNT_CAN_RWTORO) == 0) {
1.329 ad 271: error = EOPNOTSUPP; /* Needs translation */
272: goto out;
273: }
1.292 elad 274:
275: error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
276: KAUTH_REQ_SYSTEM_MOUNT_UPDATE, mp, KAUTH_ARG(flags), data);
277: if (error)
1.329 ad 278: goto out;
1.292 elad 279:
1.358 ad 280: if (vfs_busy(mp, NULL)) {
1.329 ad 281: error = EPERM;
282: goto out;
283: }
1.283 elad 284:
1.358 ad 285: mutex_enter(&mp->mnt_updating);
286:
1.286 yamt 287: mp->mnt_flag &= ~MNT_OP_FLAGS;
1.441 christos 288: mp->mnt_flag |= flags & MNT_OP_FLAGS;
1.286 yamt 289:
1.283 elad 290: /*
291: * Set the mount level flags.
292: */
293: if (flags & MNT_RDONLY)
294: mp->mnt_flag |= MNT_RDONLY;
295: else if (mp->mnt_flag & MNT_RDONLY)
296: mp->mnt_iflag |= IMNT_WANTRDWR;
1.441 christos 297: mp->mnt_flag &= ~MNT_BASIC_FLAGS;
298: mp->mnt_flag |= flags & MNT_BASIC_FLAGS;
1.332 pooka 299: error = VFS_MOUNT(mp, path, data, data_len);
1.283 elad 300:
1.320 dsl 301: if (error && data != NULL) {
1.283 elad 302: int error2;
303:
1.378 ad 304: /*
305: * Update failed; let's try and see if it was an
1.379 ad 306: * export request. For compat with 3.0 and earlier.
1.378 ad 307: */
1.381 ad 308: error2 = vfs_hooks_reexport(mp, path, data);
1.283 elad 309:
1.381 ad 310: /*
311: * Only update error code if the export request was
1.283 elad 312: * understood but some problem occurred while
1.381 ad 313: * processing it.
314: */
1.283 elad 315: if (error2 != EJUSTRETURN)
316: error = error2;
317: }
1.381 ad 318:
1.283 elad 319: if (mp->mnt_iflag & IMNT_WANTRDWR)
320: mp->mnt_flag &= ~MNT_RDONLY;
321: if (error)
322: mp->mnt_flag = saved_flags;
1.286 yamt 323: mp->mnt_flag &= ~MNT_OP_FLAGS;
324: mp->mnt_iflag &= ~IMNT_WANTRDWR;
1.283 elad 325: if ((mp->mnt_flag & (MNT_RDONLY | MNT_ASYNC)) == 0) {
326: if (mp->mnt_syncer == NULL)
327: error = vfs_allocate_syncvnode(mp);
1.125 tls 328: } else {
1.283 elad 329: if (mp->mnt_syncer != NULL)
330: vfs_deallocate_syncvnode(mp);
331: }
1.358 ad 332: mutex_exit(&mp->mnt_updating);
1.354 ad 333: vfs_unbusy(mp, false, NULL);
1.283 elad 334:
1.430 manu 335: if ((error == 0) && !(saved_flags & MNT_EXTATTR) &&
336: (flags & MNT_EXTATTR)) {
1.452 manu 337: if (VFS_EXTATTRCTL(mp, EXTATTR_CMD_START,
1.430 manu 338: NULL, 0, NULL) != 0) {
339: printf("%s: failed to start extattr, error = %d",
1.452 manu 340: mp->mnt_stat.f_mntonname, error);
1.430 manu 341: mp->mnt_flag &= ~MNT_EXTATTR;
342: }
343: }
344:
345: if ((error == 0) && (saved_flags & MNT_EXTATTR) &&
346: !(flags & MNT_EXTATTR)) {
1.452 manu 347: if (VFS_EXTATTRCTL(mp, EXTATTR_CMD_STOP,
1.430 manu 348: NULL, 0, NULL) != 0) {
349: printf("%s: failed to stop extattr, error = %d",
1.452 manu 350: mp->mnt_stat.f_mntonname, error);
1.430 manu 351: mp->mnt_flag |= MNT_RDONLY;
352: }
353: }
1.329 ad 354: out:
1.283 elad 355: return (error);
356: }
357:
1.285 elad 358: static int
1.320 dsl 359: mount_get_vfsops(const char *fstype, struct vfsops **vfsops)
1.283 elad 360: {
1.322 christos 361: char fstypename[sizeof(((struct statvfs *)NULL)->f_fstypename)];
1.283 elad 362: int error;
363:
1.320 dsl 364: /* Copy file-system type from userspace. */
1.322 christos 365: error = copyinstr(fstype, fstypename, sizeof(fstypename), NULL);
1.63 christos 366: if (error) {
1.54 cgd 367: /*
1.227 jmmv 368: * Historically, filesystem types were identified by numbers.
1.54 cgd 369: * If we get an integer for the filesystem type instead of a
370: * string, we check to see if it matches one of the historic
371: * filesystem types.
1.205 junyoung 372: */
1.283 elad 373: u_long fsindex = (u_long)fstype;
1.99 thorpej 374: if (fsindex >= nmountcompatnames ||
1.320 dsl 375: mountcompatnames[fsindex] == NULL)
376: return ENODEV;
1.331 pooka 377: strlcpy(fstypename, mountcompatnames[fsindex],
378: sizeof(fstypename));
1.31 cgd 379: }
1.283 elad 380:
1.378 ad 381: /* Accept `ufs' as an alias for `ffs', for compatibility. */
1.320 dsl 382: if (strcmp(fstypename, "ufs") == 0)
383: fstypename[0] = 'f';
1.285 elad 384:
1.360 ad 385: if ((*vfsops = vfs_getopsbyname(fstypename)) != NULL)
386: return 0;
387:
388: /* If we can autoload a vfs module, try again */
1.400 martin 389: (void)module_autoload(fstypename, MODULE_CLASS_VFS);
1.360 ad 390:
391: if ((*vfsops = vfs_getopsbyname(fstypename)) != NULL)
392: return 0;
393:
394: return ENODEV;
1.320 dsl 395: }
396:
397: static int
1.283 elad 398: mount_getargs(struct lwp *l, struct vnode *vp, const char *path, int flags,
1.324 pooka 399: void *data, size_t *data_len)
1.283 elad 400: {
401: struct mount *mp;
402: int error;
403:
1.289 elad 404: /* If MNT_GETARGS is specified, it should be the only flag. */
1.320 dsl 405: if (flags & ~MNT_GETARGS)
406: return EINVAL;
1.289 elad 407:
1.283 elad 408: mp = vp->v_mount;
409:
1.292 elad 410: /* XXX: probably some notion of "can see" here if we want isolation. */
411: error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
412: KAUTH_REQ_SYSTEM_MOUNT_GET, mp, data, NULL);
413: if (error)
1.320 dsl 414: return error;
1.292 elad 415:
1.329 ad 416: if ((vp->v_vflag & VV_ROOT) == 0)
1.320 dsl 417: return EINVAL;
1.283 elad 418:
1.358 ad 419: if (vfs_busy(mp, NULL))
1.320 dsl 420: return EPERM;
1.283 elad 421:
1.358 ad 422: mutex_enter(&mp->mnt_updating);
1.286 yamt 423: mp->mnt_flag &= ~MNT_OP_FLAGS;
424: mp->mnt_flag |= MNT_GETARGS;
1.332 pooka 425: error = VFS_MOUNT(mp, path, data, data_len);
1.286 yamt 426: mp->mnt_flag &= ~MNT_OP_FLAGS;
1.358 ad 427: mutex_exit(&mp->mnt_updating);
1.283 elad 428:
1.354 ad 429: vfs_unbusy(mp, false, NULL);
1.283 elad 430: return (error);
431: }
432:
1.321 dsl 433: int
1.335 dsl 434: sys___mount50(struct lwp *l, const struct sys___mount50_args *uap, register_t *retval)
1.321 dsl 435: {
1.335 dsl 436: /* {
1.321 dsl 437: syscallarg(const char *) type;
438: syscallarg(const char *) path;
439: syscallarg(int) flags;
440: syscallarg(void *) data;
441: syscallarg(size_t) data_len;
1.335 dsl 442: } */
1.321 dsl 443:
444: return do_sys_mount(l, NULL, SCARG(uap, type), SCARG(uap, path),
445: SCARG(uap, flags), SCARG(uap, data), UIO_USERSPACE,
446: SCARG(uap, data_len), retval);
447: }
1.320 dsl 448:
449: int
450: do_sys_mount(struct lwp *l, struct vfsops *vfsops, const char *type,
451: const char *path, int flags, void *data, enum uio_seg data_seg,
452: size_t data_len, register_t *retval)
453: {
1.283 elad 454: struct vnode *vp;
1.320 dsl 455: void *data_buf = data;
1.403 pooka 456: bool vfsopsrele = false;
1.482 maxv 457: size_t alloc_sz = 0;
1.283 elad 458: int error;
459:
1.403 pooka 460: /* XXX: The calling convention of this routine is totally bizarre */
461: if (vfsops)
462: vfsopsrele = true;
463:
1.283 elad 464: /*
465: * Get vnode to be covered
466: */
1.395 dholland 467: error = namei_simple_user(path, NSM_FOLLOW_TRYEMULROOT, &vp);
1.403 pooka 468: if (error != 0) {
469: vp = NULL;
470: goto done;
471: }
1.283 elad 472:
1.320 dsl 473: if (vfsops == NULL) {
1.361 ad 474: if (flags & (MNT_GETARGS | MNT_UPDATE)) {
1.320 dsl 475: vfsops = vp->v_mount->mnt_op;
1.361 ad 476: } else {
1.320 dsl 477: /* 'type' is userspace */
478: error = mount_get_vfsops(type, &vfsops);
479: if (error != 0)
480: goto done;
1.403 pooka 481: vfsopsrele = true;
1.320 dsl 482: }
483: }
484:
1.479 maxv 485: /*
486: * We allow data to be NULL, even for userspace. Some fs's don't need
487: * it. The others will handle NULL.
488: */
1.320 dsl 489: if (data != NULL && data_seg == UIO_USERSPACE) {
490: if (data_len == 0) {
491: /* No length supplied, use default for filesystem */
492: data_len = vfsops->vfs_min_mount_data;
1.478 maxv 493:
1.378 ad 494: /*
495: * Hopefully a longer buffer won't make copyin() fail.
496: * For compatibility with 3.0 and earlier.
497: */
1.320 dsl 498: if (flags & MNT_UPDATE
499: && data_len < sizeof (struct mnt_export_args30))
500: data_len = sizeof (struct mnt_export_args30);
501: }
1.480 maxv 502: if ((data_len == 0) || (data_len > VFS_MAX_MOUNT_DATA)) {
1.478 maxv 503: error = EINVAL;
504: goto done;
505: }
1.482 maxv 506: alloc_sz = data_len;
507: data_buf = kmem_alloc(alloc_sz, KM_SLEEP);
1.283 elad 508:
1.320 dsl 509: /* NFS needs the buffer even for mnt_getargs .... */
510: error = copyin(data, data_buf, data_len);
511: if (error != 0)
512: goto done;
513: }
514:
515: if (flags & MNT_GETARGS) {
516: if (data_len == 0) {
517: error = EINVAL;
518: goto done;
519: }
1.324 pooka 520: error = mount_getargs(l, vp, path, flags, data_buf, &data_len);
1.320 dsl 521: if (error != 0)
522: goto done;
523: if (data_seg == UIO_USERSPACE)
524: error = copyout(data_buf, data, data_len);
525: *retval = data_len;
526: } else if (flags & MNT_UPDATE) {
1.324 pooka 527: error = mount_update(l, vp, path, flags, data_buf, &data_len);
1.283 elad 528: } else {
529: /* Locking is handled internally in mount_domount(). */
1.403 pooka 530: KASSERT(vfsopsrele == true);
1.320 dsl 531: error = mount_domount(l, &vp, vfsops, path, flags, data_buf,
1.405 hannken 532: &data_len);
1.403 pooka 533: vfsopsrele = false;
1.283 elad 534: }
535:
1.320 dsl 536: done:
1.403 pooka 537: if (vfsopsrele)
538: vfs_delref(vfsops);
1.337 ad 539: if (vp != NULL) {
1.405 hannken 540: vrele(vp);
1.337 ad 541: }
1.320 dsl 542: if (data_buf != data)
1.482 maxv 543: kmem_free(data_buf, alloc_sz);
1.31 cgd 544: return (error);
545: }
546:
547: /*
548: * Unmount a file system.
549: *
550: * Note: unmount takes a path to the vnode mounted on as argument,
551: * not special file (as before).
552: */
553: /* ARGSUSED */
1.63 christos 554: int
1.335 dsl 555: sys_unmount(struct lwp *l, const struct sys_unmount_args *uap, register_t *retval)
1.56 thorpej 556: {
1.335 dsl 557: /* {
1.74 cgd 558: syscallarg(const char *) path;
1.35 cgd 559: syscallarg(int) flags;
1.335 dsl 560: } */
1.155 augustss 561: struct vnode *vp;
1.31 cgd 562: struct mount *mp;
563: int error;
1.409 dholland 564: struct pathbuf *pb;
1.31 cgd 565: struct nameidata nd;
566:
1.409 dholland 567: error = pathbuf_copyin(SCARG(uap, path), &pb);
568: if (error) {
569: return error;
570: }
571:
572: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, pb);
573: if ((error = namei(&nd)) != 0) {
574: pathbuf_destroy(pb);
575: return error;
576: }
1.31 cgd 577: vp = nd.ni_vp;
1.409 dholland 578: pathbuf_destroy(pb);
579:
1.43 mycroft 580: mp = vp->v_mount;
1.358 ad 581: atomic_inc_uint(&mp->mnt_refcnt);
1.406 hannken 582: VOP_UNLOCK(vp);
1.31 cgd 583:
1.295 elad 584: error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
585: KAUTH_REQ_SYSTEM_MOUNT_UNMOUNT, mp, NULL, NULL);
586: if (error) {
1.345 ad 587: vrele(vp);
1.358 ad 588: vfs_destroy(mp);
1.31 cgd 589: return (error);
590: }
591:
592: /*
1.47 mycroft 593: * Don't allow unmounting the root file system.
594: */
595: if (mp->mnt_flag & MNT_ROOTFS) {
1.345 ad 596: vrele(vp);
1.358 ad 597: vfs_destroy(mp);
1.47 mycroft 598: return (EINVAL);
599: }
600:
601: /*
1.31 cgd 602: * Must be the root of the filesystem
603: */
1.329 ad 604: if ((vp->v_vflag & VV_ROOT) == 0) {
1.345 ad 605: vrele(vp);
1.358 ad 606: vfs_destroy(mp);
1.31 cgd 607: return (EINVAL);
608: }
1.78 fvdl 609:
1.359 ad 610: vrele(vp);
1.358 ad 611: error = dounmount(mp, SCARG(uap, flags), l);
1.374 ad 612: vfs_destroy(mp);
1.358 ad 613: return error;
1.31 cgd 614: }
615:
616: /*
617: * Sync each mounted filesystem.
618: */
619: #ifdef DEBUG
620: int syncprt = 0;
621: struct ctldebug debug0 = { "syncprt", &syncprt };
622: #endif
623:
1.425 dsl 624: void
625: do_sys_sync(struct lwp *l)
1.31 cgd 626: {
1.155 augustss 627: struct mount *mp, *nmp;
1.31 cgd 628: int asyncflag;
1.257 ad 629:
1.329 ad 630: mutex_enter(&mountlist_lock);
1.471 christos 631: for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) {
1.358 ad 632: if (vfs_busy(mp, &nmp)) {
1.113 fvdl 633: continue;
634: }
1.358 ad 635: mutex_enter(&mp->mnt_updating);
1.307 hannken 636: if ((mp->mnt_flag & MNT_RDONLY) == 0) {
1.31 cgd 637: asyncflag = mp->mnt_flag & MNT_ASYNC;
638: mp->mnt_flag &= ~MNT_ASYNC;
1.332 pooka 639: VFS_SYNC(mp, MNT_NOWAIT, l->l_cred);
1.31 cgd 640: if (asyncflag)
1.113 fvdl 641: mp->mnt_flag |= MNT_ASYNC;
1.31 cgd 642: }
1.358 ad 643: mutex_exit(&mp->mnt_updating);
1.354 ad 644: vfs_unbusy(mp, false, &nmp);
1.31 cgd 645: }
1.329 ad 646: mutex_exit(&mountlist_lock);
1.31 cgd 647: #ifdef DEBUG
648: if (syncprt)
649: vfs_bufstats();
650: #endif /* DEBUG */
1.425 dsl 651: }
652:
653: /* ARGSUSED */
654: int
655: sys_sync(struct lwp *l, const void *v, register_t *retval)
656: {
657: do_sys_sync(l);
1.31 cgd 658: return (0);
659: }
660:
1.425 dsl 661:
1.31 cgd 662: /*
1.444 dholland 663: * Access or change filesystem quotas.
664: *
665: * (this is really 14 different calls bundled into one)
1.31 cgd 666: */
1.444 dholland 667:
668: static int
669: do_sys_quotactl_stat(struct mount *mp, struct quotastat *info_u)
670: {
671: struct quotastat info_k;
672: int error;
673:
674: /* ensure any padding bytes are cleared */
675: memset(&info_k, 0, sizeof(info_k));
676:
677: error = vfs_quotactl_stat(mp, &info_k);
678: if (error) {
679: return error;
680: }
681:
682: return copyout(&info_k, info_u, sizeof(info_k));
683: }
684:
685: static int
686: do_sys_quotactl_idtypestat(struct mount *mp, int idtype,
687: struct quotaidtypestat *info_u)
688: {
689: struct quotaidtypestat info_k;
690: int error;
691:
692: /* ensure any padding bytes are cleared */
693: memset(&info_k, 0, sizeof(info_k));
694:
695: error = vfs_quotactl_idtypestat(mp, idtype, &info_k);
696: if (error) {
697: return error;
698: }
699:
700: return copyout(&info_k, info_u, sizeof(info_k));
701: }
702:
703: static int
704: do_sys_quotactl_objtypestat(struct mount *mp, int objtype,
705: struct quotaobjtypestat *info_u)
706: {
707: struct quotaobjtypestat info_k;
708: int error;
709:
710: /* ensure any padding bytes are cleared */
711: memset(&info_k, 0, sizeof(info_k));
712:
713: error = vfs_quotactl_objtypestat(mp, objtype, &info_k);
714: if (error) {
715: return error;
716: }
717:
718: return copyout(&info_k, info_u, sizeof(info_k));
719: }
720:
721: static int
722: do_sys_quotactl_get(struct mount *mp, const struct quotakey *key_u,
723: struct quotaval *val_u)
724: {
725: struct quotakey key_k;
726: struct quotaval val_k;
727: int error;
728:
729: /* ensure any padding bytes are cleared */
730: memset(&val_k, 0, sizeof(val_k));
731:
732: error = copyin(key_u, &key_k, sizeof(key_k));
733: if (error) {
734: return error;
735: }
736:
737: error = vfs_quotactl_get(mp, &key_k, &val_k);
738: if (error) {
739: return error;
740: }
741:
742: return copyout(&val_k, val_u, sizeof(val_k));
743: }
744:
745: static int
746: do_sys_quotactl_put(struct mount *mp, const struct quotakey *key_u,
747: const struct quotaval *val_u)
748: {
749: struct quotakey key_k;
750: struct quotaval val_k;
751: int error;
752:
753: error = copyin(key_u, &key_k, sizeof(key_k));
754: if (error) {
755: return error;
756: }
757:
758: error = copyin(val_u, &val_k, sizeof(val_k));
759: if (error) {
760: return error;
761: }
762:
763: return vfs_quotactl_put(mp, &key_k, &val_k);
764: }
765:
766: static int
1.486 ! dholland 767: do_sys_quotactl_del(struct mount *mp, const struct quotakey *key_u)
1.444 dholland 768: {
769: struct quotakey key_k;
770: int error;
771:
772: error = copyin(key_u, &key_k, sizeof(key_k));
773: if (error) {
774: return error;
775: }
776:
1.486 ! dholland 777: return vfs_quotactl_del(mp, &key_k);
1.444 dholland 778: }
779:
780: static int
781: do_sys_quotactl_cursoropen(struct mount *mp, struct quotakcursor *cursor_u)
782: {
783: struct quotakcursor cursor_k;
784: int error;
785:
786: /* ensure any padding bytes are cleared */
787: memset(&cursor_k, 0, sizeof(cursor_k));
788:
789: error = vfs_quotactl_cursoropen(mp, &cursor_k);
790: if (error) {
791: return error;
792: }
793:
794: return copyout(&cursor_k, cursor_u, sizeof(cursor_k));
795: }
796:
797: static int
798: do_sys_quotactl_cursorclose(struct mount *mp, struct quotakcursor *cursor_u)
799: {
800: struct quotakcursor cursor_k;
801: int error;
802:
803: error = copyin(cursor_u, &cursor_k, sizeof(cursor_k));
804: if (error) {
805: return error;
806: }
807:
808: return vfs_quotactl_cursorclose(mp, &cursor_k);
809: }
810:
811: static int
812: do_sys_quotactl_cursorskipidtype(struct mount *mp,
813: struct quotakcursor *cursor_u, int idtype)
814: {
815: struct quotakcursor cursor_k;
816: int error;
817:
818: error = copyin(cursor_u, &cursor_k, sizeof(cursor_k));
819: if (error) {
820: return error;
821: }
822:
823: error = vfs_quotactl_cursorskipidtype(mp, &cursor_k, idtype);
824: if (error) {
825: return error;
826: }
827:
828: return copyout(&cursor_k, cursor_u, sizeof(cursor_k));
829: }
830:
831: static int
832: do_sys_quotactl_cursorget(struct mount *mp, struct quotakcursor *cursor_u,
833: struct quotakey *keys_u, struct quotaval *vals_u, unsigned maxnum,
1.447 dholland 834: unsigned *ret_u)
1.444 dholland 835: {
836: #define CGET_STACK_MAX 8
837: struct quotakcursor cursor_k;
838: struct quotakey stackkeys[CGET_STACK_MAX];
839: struct quotaval stackvals[CGET_STACK_MAX];
840: struct quotakey *keys_k;
841: struct quotaval *vals_k;
1.447 dholland 842: unsigned ret_k;
1.444 dholland 843: int error;
844:
845: if (maxnum > 128) {
846: maxnum = 128;
847: }
848:
849: error = copyin(cursor_u, &cursor_k, sizeof(cursor_k));
850: if (error) {
851: return error;
852: }
853:
854: if (maxnum <= CGET_STACK_MAX) {
855: keys_k = stackkeys;
856: vals_k = stackvals;
857: /* ensure any padding bytes are cleared */
858: memset(keys_k, 0, maxnum * sizeof(keys_k[0]));
859: memset(vals_k, 0, maxnum * sizeof(vals_k[0]));
860: } else {
861: keys_k = kmem_zalloc(maxnum * sizeof(keys_k[0]), KM_SLEEP);
862: vals_k = kmem_zalloc(maxnum * sizeof(vals_k[0]), KM_SLEEP);
863: }
864:
865: error = vfs_quotactl_cursorget(mp, &cursor_k, keys_k, vals_k, maxnum,
866: &ret_k);
867: if (error) {
868: goto fail;
869: }
870:
871: error = copyout(keys_k, keys_u, ret_k * sizeof(keys_k[0]));
872: if (error) {
873: goto fail;
874: }
875:
876: error = copyout(vals_k, vals_u, ret_k * sizeof(vals_k[0]));
877: if (error) {
878: goto fail;
879: }
880:
881: error = copyout(&ret_k, ret_u, sizeof(ret_k));
882: if (error) {
883: goto fail;
884: }
885:
886: /* do last to maximize the chance of being able to recover a failure */
887: error = copyout(&cursor_k, cursor_u, sizeof(cursor_k));
888:
889: fail:
890: if (keys_k != stackkeys) {
891: kmem_free(keys_k, maxnum * sizeof(keys_k[0]));
892: }
893: if (vals_k != stackvals) {
894: kmem_free(vals_k, maxnum * sizeof(vals_k[0]));
895: }
896: return error;
897: }
898:
899: static int
900: do_sys_quotactl_cursoratend(struct mount *mp, struct quotakcursor *cursor_u,
901: int *ret_u)
902: {
903: struct quotakcursor cursor_k;
904: int ret_k;
905: int error;
906:
907: error = copyin(cursor_u, &cursor_k, sizeof(cursor_k));
908: if (error) {
909: return error;
910: }
911:
912: error = vfs_quotactl_cursoratend(mp, &cursor_k, &ret_k);
913: if (error) {
914: return error;
915: }
916:
917: error = copyout(&ret_k, ret_u, sizeof(ret_k));
918: if (error) {
919: return error;
920: }
921:
922: return copyout(&cursor_k, cursor_u, sizeof(cursor_k));
923: }
924:
925: static int
926: do_sys_quotactl_cursorrewind(struct mount *mp, struct quotakcursor *cursor_u)
927: {
928: struct quotakcursor cursor_k;
929: int error;
930:
931: error = copyin(cursor_u, &cursor_k, sizeof(cursor_k));
932: if (error) {
933: return error;
934: }
935:
936: error = vfs_quotactl_cursorrewind(mp, &cursor_k);
937: if (error) {
938: return error;
939: }
940:
941: return copyout(&cursor_k, cursor_u, sizeof(cursor_k));
942: }
943:
944: static int
945: do_sys_quotactl_quotaon(struct mount *mp, int idtype, const char *path_u)
946: {
947: char *path_k;
948: int error;
949:
950: /* XXX this should probably be a struct pathbuf */
951: path_k = PNBUF_GET();
952: error = copyin(path_u, path_k, PATH_MAX);
953: if (error) {
954: PNBUF_PUT(path_k);
955: return error;
956: }
957:
958: error = vfs_quotactl_quotaon(mp, idtype, path_k);
959:
960: PNBUF_PUT(path_k);
961: return error;
962: }
963:
964: static int
965: do_sys_quotactl_quotaoff(struct mount *mp, int idtype)
966: {
967: return vfs_quotactl_quotaoff(mp, idtype);
968: }
969:
1.63 christos 970: int
1.445 dholland 971: do_sys_quotactl(const char *path_u, const struct quotactl_args *args)
1.56 thorpej 972: {
1.155 augustss 973: struct mount *mp;
1.444 dholland 974: struct vnode *vp;
1.31 cgd 975: int error;
976:
1.445 dholland 977: error = namei_simple_user(path_u, NSM_FOLLOW_TRYEMULROOT, &vp);
1.395 dholland 978: if (error != 0)
1.31 cgd 979: return (error);
1.395 dholland 980: mp = vp->v_mount;
1.444 dholland 981:
1.445 dholland 982: switch (args->qc_op) {
1.444 dholland 983: case QUOTACTL_STAT:
1.446 dholland 984: error = do_sys_quotactl_stat(mp, args->u.stat.qc_info);
1.444 dholland 985: break;
986: case QUOTACTL_IDTYPESTAT:
987: error = do_sys_quotactl_idtypestat(mp,
1.445 dholland 988: args->u.idtypestat.qc_idtype,
989: args->u.idtypestat.qc_info);
1.444 dholland 990: break;
991: case QUOTACTL_OBJTYPESTAT:
992: error = do_sys_quotactl_objtypestat(mp,
1.445 dholland 993: args->u.objtypestat.qc_objtype,
994: args->u.objtypestat.qc_info);
1.444 dholland 995: break;
996: case QUOTACTL_GET:
997: error = do_sys_quotactl_get(mp,
1.445 dholland 998: args->u.get.qc_key,
1.446 dholland 999: args->u.get.qc_val);
1.444 dholland 1000: break;
1001: case QUOTACTL_PUT:
1002: error = do_sys_quotactl_put(mp,
1.445 dholland 1003: args->u.put.qc_key,
1004: args->u.put.qc_val);
1.444 dholland 1005: break;
1.486 ! dholland 1006: case QUOTACTL_DEL:
! 1007: error = do_sys_quotactl_del(mp, args->u.del.qc_key);
1.444 dholland 1008: break;
1009: case QUOTACTL_CURSOROPEN:
1010: error = do_sys_quotactl_cursoropen(mp,
1.445 dholland 1011: args->u.cursoropen.qc_cursor);
1.444 dholland 1012: break;
1013: case QUOTACTL_CURSORCLOSE:
1014: error = do_sys_quotactl_cursorclose(mp,
1.445 dholland 1015: args->u.cursorclose.qc_cursor);
1.444 dholland 1016: break;
1017: case QUOTACTL_CURSORSKIPIDTYPE:
1018: error = do_sys_quotactl_cursorskipidtype(mp,
1.445 dholland 1019: args->u.cursorskipidtype.qc_cursor,
1020: args->u.cursorskipidtype.qc_idtype);
1.444 dholland 1021: break;
1022: case QUOTACTL_CURSORGET:
1023: error = do_sys_quotactl_cursorget(mp,
1.445 dholland 1024: args->u.cursorget.qc_cursor,
1025: args->u.cursorget.qc_keys,
1026: args->u.cursorget.qc_vals,
1027: args->u.cursorget.qc_maxnum,
1028: args->u.cursorget.qc_ret);
1.444 dholland 1029: break;
1030: case QUOTACTL_CURSORATEND:
1031: error = do_sys_quotactl_cursoratend(mp,
1.445 dholland 1032: args->u.cursoratend.qc_cursor,
1033: args->u.cursoratend.qc_ret);
1.444 dholland 1034: break;
1035: case QUOTACTL_CURSORREWIND:
1036: error = do_sys_quotactl_cursorrewind(mp,
1.445 dholland 1037: args->u.cursorrewind.qc_cursor);
1.444 dholland 1038: break;
1039: case QUOTACTL_QUOTAON:
1040: error = do_sys_quotactl_quotaon(mp,
1.445 dholland 1041: args->u.quotaon.qc_idtype,
1042: args->u.quotaon.qc_quotafile);
1.444 dholland 1043: break;
1044: case QUOTACTL_QUOTAOFF:
1045: error = do_sys_quotactl_quotaoff(mp,
1.445 dholland 1046: args->u.quotaoff.qc_idtype);
1.444 dholland 1047: break;
1048: default:
1049: error = EINVAL;
1050: break;
1051: }
1052:
1.395 dholland 1053: vrele(vp);
1.444 dholland 1054: return error;
1.31 cgd 1055: }
1056:
1.445 dholland 1057: /* ARGSUSED */
1058: int
1059: sys___quotactl(struct lwp *l, const struct sys___quotactl_args *uap,
1060: register_t *retval)
1061: {
1062: /* {
1063: syscallarg(const char *) path;
1064: syscallarg(struct quotactl_args *) args;
1065: } */
1066: struct quotactl_args args;
1067: int error;
1068:
1069: error = copyin(SCARG(uap, args), &args, sizeof(args));
1070: if (error) {
1071: return error;
1072: }
1073:
1074: return do_sys_quotactl(SCARG(uap, path), &args);
1075: }
1076:
1.206 christos 1077: int
1.234 christos 1078: dostatvfs(struct mount *mp, struct statvfs *sp, struct lwp *l, int flags,
1.185 christos 1079: int root)
1080: {
1.234 christos 1081: struct cwdinfo *cwdi = l->l_proc->p_cwdi;
1.185 christos 1082: int error = 0;
1083:
1084: /*
1085: * If MNT_NOWAIT or MNT_LAZY is specified, do not
1.204 dbj 1086: * refresh the fsstat cache. MNT_WAIT or MNT_LAZY
1.185 christos 1087: * overrides MNT_NOWAIT.
1088: */
1089: if (flags == MNT_NOWAIT || flags == MNT_LAZY ||
1090: (flags != MNT_WAIT && flags != 0)) {
1091: memcpy(sp, &mp->mnt_stat, sizeof(*sp));
1092: goto done;
1093: }
1.205 junyoung 1094:
1.211 jdolecek 1095: /* Get the filesystem stats now */
1096: memset(sp, 0, sizeof(*sp));
1.332 pooka 1097: if ((error = VFS_STATVFS(mp, sp)) != 0) {
1.185 christos 1098: return error;
1099: }
1100:
1101: if (cwdi->cwdi_rdir == NULL)
1102: (void)memcpy(&mp->mnt_stat, sp, sizeof(mp->mnt_stat));
1103: done:
1104: if (cwdi->cwdi_rdir != NULL) {
1105: size_t len;
1106: char *bp;
1.364 christos 1107: char c;
1.236 yamt 1108: char *path = PNBUF_GET();
1.185 christos 1109:
1110: bp = path + MAXPATHLEN;
1111: *--bp = '\0';
1.328 ad 1112: rw_enter(&cwdi->cwdi_lock, RW_READER);
1.185 christos 1113: error = getcwd_common(cwdi->cwdi_rdir, rootvnode, &bp, path,
1.234 christos 1114: MAXPATHLEN / 2, 0, l);
1.328 ad 1115: rw_exit(&cwdi->cwdi_lock);
1.185 christos 1116: if (error) {
1.236 yamt 1117: PNBUF_PUT(path);
1.185 christos 1118: return error;
1119: }
1120: len = strlen(bp);
1.387 christos 1121: if (len != 1) {
1122: /*
1123: * for mount points that are below our root, we can see
1124: * them, so we fix up the pathname and return them. The
1125: * rest we cannot see, so we don't allow viewing the
1126: * data.
1127: */
1128: if (strncmp(bp, sp->f_mntonname, len) == 0 &&
1129: ((c = sp->f_mntonname[len]) == '/' || c == '\0')) {
1130: (void)strlcpy(sp->f_mntonname,
1.388 enami 1131: c == '\0' ? "/" : &sp->f_mntonname[len],
1.187 itojun 1132: sizeof(sp->f_mntonname));
1.387 christos 1133: } else {
1134: if (root)
1135: (void)strlcpy(sp->f_mntonname, "/",
1136: sizeof(sp->f_mntonname));
1137: else
1138: error = EPERM;
1139: }
1.185 christos 1140: }
1.236 yamt 1141: PNBUF_PUT(path);
1.185 christos 1142: }
1.206 christos 1143: sp->f_flag = mp->mnt_flag & MNT_VISFLAGMASK;
1.185 christos 1144: return error;
1145: }
1146:
1.31 cgd 1147: /*
1.311 dsl 1148: * Get filesystem statistics by path.
1.31 cgd 1149: */
1.311 dsl 1150: int
1151: do_sys_pstatvfs(struct lwp *l, const char *path, int flags, struct statvfs *sb)
1152: {
1153: struct mount *mp;
1154: int error;
1.395 dholland 1155: struct vnode *vp;
1.311 dsl 1156:
1.395 dholland 1157: error = namei_simple_user(path, NSM_FOLLOW_TRYEMULROOT, &vp);
1158: if (error != 0)
1.311 dsl 1159: return error;
1.395 dholland 1160: mp = vp->v_mount;
1.311 dsl 1161: error = dostatvfs(mp, sb, l, flags, 1);
1.395 dholland 1162: vrele(vp);
1.311 dsl 1163: return error;
1164: }
1165:
1.31 cgd 1166: /* ARGSUSED */
1.63 christos 1167: int
1.335 dsl 1168: sys_statvfs1(struct lwp *l, const struct sys_statvfs1_args *uap, register_t *retval)
1.56 thorpej 1169: {
1.335 dsl 1170: /* {
1.74 cgd 1171: syscallarg(const char *) path;
1.206 christos 1172: syscallarg(struct statvfs *) buf;
1173: syscallarg(int) flags;
1.335 dsl 1174: } */
1.241 yamt 1175: struct statvfs *sb;
1.31 cgd 1176: int error;
1177:
1.241 yamt 1178: sb = STATVFSBUF_GET();
1.311 dsl 1179: error = do_sys_pstatvfs(l, SCARG(uap, path), SCARG(uap, flags), sb);
1180: if (error == 0)
1.241 yamt 1181: error = copyout(sb, SCARG(uap, buf), sizeof(*sb));
1182: STATVFSBUF_PUT(sb);
1183: return error;
1.31 cgd 1184: }
1185:
1186: /*
1.311 dsl 1187: * Get filesystem statistics by fd.
1.31 cgd 1188: */
1.311 dsl 1189: int
1190: do_sys_fstatvfs(struct lwp *l, int fd, int flags, struct statvfs *sb)
1191: {
1.346 ad 1192: file_t *fp;
1.311 dsl 1193: struct mount *mp;
1194: int error;
1195:
1.346 ad 1196: /* fd_getvnode() will use the descriptor for us */
1197: if ((error = fd_getvnode(fd, &fp)) != 0)
1.311 dsl 1198: return (error);
1199: mp = ((struct vnode *)fp->f_data)->v_mount;
1.346 ad 1200: error = dostatvfs(mp, sb, curlwp, flags, 1);
1201: fd_putfile(fd);
1.311 dsl 1202: return error;
1203: }
1204:
1.31 cgd 1205: /* ARGSUSED */
1.63 christos 1206: int
1.335 dsl 1207: sys_fstatvfs1(struct lwp *l, const struct sys_fstatvfs1_args *uap, register_t *retval)
1.56 thorpej 1208: {
1.335 dsl 1209: /* {
1.35 cgd 1210: syscallarg(int) fd;
1.206 christos 1211: syscallarg(struct statvfs *) buf;
1212: syscallarg(int) flags;
1.335 dsl 1213: } */
1.241 yamt 1214: struct statvfs *sb;
1.31 cgd 1215: int error;
1216:
1.241 yamt 1217: sb = STATVFSBUF_GET();
1.311 dsl 1218: error = do_sys_fstatvfs(l, SCARG(uap, fd), SCARG(uap, flags), sb);
1.316 dsl 1219: if (error == 0)
1.311 dsl 1220: error = copyout(sb, SCARG(uap, buf), sizeof(*sb));
1.241 yamt 1221: STATVFSBUF_PUT(sb);
1.185 christos 1222: return error;
1.31 cgd 1223: }
1224:
1.185 christos 1225:
1.31 cgd 1226: /*
1227: * Get statistics on all filesystems.
1228: */
1.63 christos 1229: int
1.311 dsl 1230: do_sys_getvfsstat(struct lwp *l, void *sfsp, size_t bufsize, int flags,
1231: int (*copyfn)(const void *, void *, size_t), size_t entry_sz,
1232: register_t *retval)
1.56 thorpej 1233: {
1.185 christos 1234: int root = 0;
1.179 thorpej 1235: struct proc *p = l->l_proc;
1.155 augustss 1236: struct mount *mp, *nmp;
1.241 yamt 1237: struct statvfs *sb;
1.206 christos 1238: size_t count, maxcount;
1239: int error = 0;
1.31 cgd 1240:
1.241 yamt 1241: sb = STATVFSBUF_GET();
1.311 dsl 1242: maxcount = bufsize / entry_sz;
1.329 ad 1243: mutex_enter(&mountlist_lock);
1.113 fvdl 1244: count = 0;
1.471 christos 1245: for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) {
1.358 ad 1246: if (vfs_busy(mp, &nmp)) {
1.113 fvdl 1247: continue;
1248: }
1249: if (sfsp && count < maxcount) {
1.311 dsl 1250: error = dostatvfs(mp, sb, l, flags, 0);
1.185 christos 1251: if (error) {
1.354 ad 1252: vfs_unbusy(mp, false, &nmp);
1.365 christos 1253: error = 0;
1.31 cgd 1254: continue;
1.113 fvdl 1255: }
1.311 dsl 1256: error = copyfn(sb, sfsp, entry_sz);
1.133 mycroft 1257: if (error) {
1.354 ad 1258: vfs_unbusy(mp, false, NULL);
1.241 yamt 1259: goto out;
1.133 mycroft 1260: }
1.311 dsl 1261: sfsp = (char *)sfsp + entry_sz;
1.241 yamt 1262: root |= strcmp(sb->f_mntonname, "/") == 0;
1.31 cgd 1263: }
1264: count++;
1.354 ad 1265: vfs_unbusy(mp, false, &nmp);
1.31 cgd 1266: }
1.358 ad 1267: mutex_exit(&mountlist_lock);
1.331 pooka 1268:
1.185 christos 1269: if (root == 0 && p->p_cwdi->cwdi_rdir) {
1270: /*
1271: * fake a root entry
1272: */
1.331 pooka 1273: error = dostatvfs(p->p_cwdi->cwdi_rdir->v_mount,
1274: sb, l, flags, 1);
1.311 dsl 1275: if (error != 0)
1.241 yamt 1276: goto out;
1.365 christos 1277: if (sfsp) {
1.311 dsl 1278: error = copyfn(sb, sfsp, entry_sz);
1.365 christos 1279: if (error != 0)
1280: goto out;
1281: }
1.185 christos 1282: count++;
1283: }
1.31 cgd 1284: if (sfsp && count > maxcount)
1285: *retval = maxcount;
1286: else
1287: *retval = count;
1.241 yamt 1288: out:
1289: STATVFSBUF_PUT(sb);
1.185 christos 1290: return error;
1.31 cgd 1291: }
1292:
1.311 dsl 1293: int
1.335 dsl 1294: sys_getvfsstat(struct lwp *l, const struct sys_getvfsstat_args *uap, register_t *retval)
1.311 dsl 1295: {
1.335 dsl 1296: /* {
1.311 dsl 1297: syscallarg(struct statvfs *) buf;
1298: syscallarg(size_t) bufsize;
1299: syscallarg(int) flags;
1.335 dsl 1300: } */
1.311 dsl 1301:
1302: return do_sys_getvfsstat(l, SCARG(uap, buf), SCARG(uap, bufsize),
1303: SCARG(uap, flags), copyout, sizeof (struct statvfs), retval);
1304: }
1305:
1.31 cgd 1306: /*
1307: * Change current working directory to a given file descriptor.
1308: */
1309: /* ARGSUSED */
1.63 christos 1310: int
1.335 dsl 1311: sys_fchdir(struct lwp *l, const struct sys_fchdir_args *uap, register_t *retval)
1.56 thorpej 1312: {
1.335 dsl 1313: /* {
1.35 cgd 1314: syscallarg(int) fd;
1.335 dsl 1315: } */
1.179 thorpej 1316: struct proc *p = l->l_proc;
1.328 ad 1317: struct cwdinfo *cwdi;
1.43 mycroft 1318: struct vnode *vp, *tdp;
1319: struct mount *mp;
1.346 ad 1320: file_t *fp;
1321: int error, fd;
1.31 cgd 1322:
1.346 ad 1323: /* fd_getvnode() will use the descriptor for us */
1324: fd = SCARG(uap, fd);
1325: if ((error = fd_getvnode(fd, &fp)) != 0)
1.31 cgd 1326: return (error);
1.346 ad 1327: vp = fp->f_data;
1.131 sommerfe 1328:
1.402 pooka 1329: vref(vp);
1.113 fvdl 1330: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.31 cgd 1331: if (vp->v_type != VDIR)
1332: error = ENOTDIR;
1333: else
1.332 pooka 1334: error = VOP_ACCESS(vp, VEXEC, l->l_cred);
1.303 pooka 1335: if (error) {
1336: vput(vp);
1337: goto out;
1338: }
1.304 pooka 1339: while ((mp = vp->v_mountedhere) != NULL) {
1.358 ad 1340: error = vfs_busy(mp, NULL);
1.298 chs 1341: vput(vp);
1.357 xtraeme 1342: if (error != 0)
1.356 ad 1343: goto out;
1.189 thorpej 1344: error = VFS_ROOT(mp, &tdp);
1.354 ad 1345: vfs_unbusy(mp, false, NULL);
1.113 fvdl 1346: if (error)
1.303 pooka 1347: goto out;
1.43 mycroft 1348: vp = tdp;
1349: }
1.406 hannken 1350: VOP_UNLOCK(vp);
1.131 sommerfe 1351:
1352: /*
1353: * Disallow changing to a directory not under the process's
1354: * current root directory (if there is one).
1355: */
1.328 ad 1356: cwdi = p->p_cwdi;
1357: rw_enter(&cwdi->cwdi_lock, RW_WRITER);
1.234 christos 1358: if (cwdi->cwdi_rdir && !vn_isunder(vp, NULL, l)) {
1.131 sommerfe 1359: vrele(vp);
1.135 thorpej 1360: error = EPERM; /* operation not permitted */
1.328 ad 1361: } else {
1362: vrele(cwdi->cwdi_cdir);
1363: cwdi->cwdi_cdir = vp;
1.131 sommerfe 1364: }
1.328 ad 1365: rw_exit(&cwdi->cwdi_lock);
1.205 junyoung 1366:
1.135 thorpej 1367: out:
1.346 ad 1368: fd_putfile(fd);
1.135 thorpej 1369: return (error);
1.31 cgd 1370: }
1371:
1372: /*
1.221 thorpej 1373: * Change this process's notion of the root directory to a given file
1374: * descriptor.
1.131 sommerfe 1375: */
1376: int
1.335 dsl 1377: sys_fchroot(struct lwp *l, const struct sys_fchroot_args *uap, register_t *retval)
1.131 sommerfe 1378: {
1.179 thorpej 1379: struct proc *p = l->l_proc;
1.131 sommerfe 1380: struct vnode *vp;
1.346 ad 1381: file_t *fp;
1382: int error, fd = SCARG(uap, fd);
1.131 sommerfe 1383:
1.268 elad 1384: if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_CHROOT,
1385: KAUTH_REQ_SYSTEM_CHROOT_FCHROOT, NULL, NULL, NULL)) != 0)
1.131 sommerfe 1386: return error;
1.346 ad 1387: /* fd_getvnode() will use the descriptor for us */
1.397 bad 1388: if ((error = fd_getvnode(fd, &fp)) != 0)
1.131 sommerfe 1389: return error;
1.346 ad 1390: vp = fp->f_data;
1.131 sommerfe 1391: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1392: if (vp->v_type != VDIR)
1393: error = ENOTDIR;
1394: else
1.332 pooka 1395: error = VOP_ACCESS(vp, VEXEC, l->l_cred);
1.406 hannken 1396: VOP_UNLOCK(vp);
1.131 sommerfe 1397: if (error)
1.135 thorpej 1398: goto out;
1.402 pooka 1399: vref(vp);
1.131 sommerfe 1400:
1.397 bad 1401: change_root(p->p_cwdi, vp, l);
1.328 ad 1402:
1.135 thorpej 1403: out:
1.346 ad 1404: fd_putfile(fd);
1.135 thorpej 1405: return (error);
1.131 sommerfe 1406: }
1407:
1408: /*
1.31 cgd 1409: * Change current working directory (``.'').
1410: */
1411: /* ARGSUSED */
1.63 christos 1412: int
1.335 dsl 1413: sys_chdir(struct lwp *l, const struct sys_chdir_args *uap, register_t *retval)
1.56 thorpej 1414: {
1.335 dsl 1415: /* {
1.74 cgd 1416: syscallarg(const char *) path;
1.335 dsl 1417: } */
1.179 thorpej 1418: struct proc *p = l->l_proc;
1.328 ad 1419: struct cwdinfo *cwdi;
1.31 cgd 1420: int error;
1.397 bad 1421: struct vnode *vp;
1.31 cgd 1422:
1.397 bad 1423: if ((error = chdir_lookup(SCARG(uap, path), UIO_USERSPACE,
1424: &vp, l)) != 0)
1.31 cgd 1425: return (error);
1.328 ad 1426: cwdi = p->p_cwdi;
1427: rw_enter(&cwdi->cwdi_lock, RW_WRITER);
1.134 thorpej 1428: vrele(cwdi->cwdi_cdir);
1.397 bad 1429: cwdi->cwdi_cdir = vp;
1.328 ad 1430: rw_exit(&cwdi->cwdi_lock);
1.31 cgd 1431: return (0);
1432: }
1433:
1434: /*
1435: * Change notion of root (``/'') directory.
1436: */
1437: /* ARGSUSED */
1.63 christos 1438: int
1.335 dsl 1439: sys_chroot(struct lwp *l, const struct sys_chroot_args *uap, register_t *retval)
1.56 thorpej 1440: {
1.335 dsl 1441: /* {
1.74 cgd 1442: syscallarg(const char *) path;
1.335 dsl 1443: } */
1.179 thorpej 1444: struct proc *p = l->l_proc;
1.397 bad 1445: int error;
1.131 sommerfe 1446: struct vnode *vp;
1.31 cgd 1447:
1.268 elad 1448: if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_CHROOT,
1449: KAUTH_REQ_SYSTEM_CHROOT_CHROOT, NULL, NULL, NULL)) != 0)
1.31 cgd 1450: return (error);
1.397 bad 1451: if ((error = chdir_lookup(SCARG(uap, path), UIO_USERSPACE,
1452: &vp, l)) != 0)
1.31 cgd 1453: return (error);
1.328 ad 1454:
1.397 bad 1455: change_root(p->p_cwdi, vp, l);
1456:
1457: return (0);
1458: }
1459:
1460: /*
1461: * Common routine for chroot and fchroot.
1.398 bad 1462: * NB: callers need to properly authorize the change root operation.
1.397 bad 1463: */
1464: void
1465: change_root(struct cwdinfo *cwdi, struct vnode *vp, struct lwp *l)
1466: {
1.457 cheusov 1467: struct proc *p = l->l_proc;
1468: kauth_cred_t ncred;
1469:
1470: ncred = kauth_cred_alloc();
1.397 bad 1471:
1.328 ad 1472: rw_enter(&cwdi->cwdi_lock, RW_WRITER);
1.134 thorpej 1473: if (cwdi->cwdi_rdir != NULL)
1474: vrele(cwdi->cwdi_rdir);
1475: cwdi->cwdi_rdir = vp;
1.131 sommerfe 1476:
1477: /*
1478: * Prevent escaping from chroot by putting the root under
1479: * the working directory. Silently chdir to / if we aren't
1480: * already there.
1481: */
1.234 christos 1482: if (!vn_isunder(cwdi->cwdi_cdir, vp, l)) {
1.131 sommerfe 1483: /*
1484: * XXX would be more failsafe to change directory to a
1485: * deadfs node here instead
1486: */
1.134 thorpej 1487: vrele(cwdi->cwdi_cdir);
1.402 pooka 1488: vref(vp);
1.134 thorpej 1489: cwdi->cwdi_cdir = vp;
1.131 sommerfe 1490: }
1.328 ad 1491: rw_exit(&cwdi->cwdi_lock);
1.457 cheusov 1492:
1493: /* Get a write lock on the process credential. */
1494: proc_crmod_enter();
1495:
1496: kauth_cred_clone(p->p_cred, ncred);
1497: kauth_proc_chroot(ncred, p->p_cwdi);
1498:
1499: /* Broadcast our credentials to the process and other LWPs. */
1500: proc_crmod_leave(ncred, p->p_cred, true);
1.31 cgd 1501: }
1502:
1503: /*
1504: * Common routine for chroot and chdir.
1.409 dholland 1505: * XXX "where" should be enum uio_seg
1.31 cgd 1506: */
1.397 bad 1507: int
1508: chdir_lookup(const char *path, int where, struct vnode **vpp, struct lwp *l)
1.31 cgd 1509: {
1.409 dholland 1510: struct pathbuf *pb;
1.397 bad 1511: struct nameidata nd;
1.31 cgd 1512: int error;
1513:
1.409 dholland 1514: error = pathbuf_maybe_copyin(path, where, &pb);
1515: if (error) {
1516: return error;
1517: }
1518: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, pb);
1519: if ((error = namei(&nd)) != 0) {
1520: pathbuf_destroy(pb);
1521: return error;
1522: }
1.397 bad 1523: *vpp = nd.ni_vp;
1.409 dholland 1524: pathbuf_destroy(pb);
1525:
1.397 bad 1526: if ((*vpp)->v_type != VDIR)
1.31 cgd 1527: error = ENOTDIR;
1528: else
1.397 bad 1529: error = VOP_ACCESS(*vpp, VEXEC, l->l_cred);
1.205 junyoung 1530:
1.31 cgd 1531: if (error)
1.397 bad 1532: vput(*vpp);
1.113 fvdl 1533: else
1.406 hannken 1534: VOP_UNLOCK(*vpp);
1.31 cgd 1535: return (error);
1536: }
1537:
1538: /*
1.448 martin 1539: * Internals of sys_open - path has already been converted into a pathbuf
1540: * (so we can easily reuse this function from other parts of the kernel,
1541: * like posix_spawn post-processing).
1.31 cgd 1542: */
1.474 christos 1543: int
1.460 manu 1544: do_open(lwp_t *l, struct vnode *dvp, struct pathbuf *pb, int open_flags,
1545: int open_mode, int *fd)
1.56 thorpej 1546: {
1.179 thorpej 1547: struct proc *p = l->l_proc;
1.134 thorpej 1548: struct cwdinfo *cwdi = p->p_cwdi;
1.346 ad 1549: file_t *fp;
1.135 thorpej 1550: struct vnode *vp;
1.31 cgd 1551: int flags, cmode;
1.422 christos 1552: int indx, error;
1.31 cgd 1553: struct nameidata nd;
1554:
1.463 dholland 1555: if (open_flags & O_SEARCH) {
1556: open_flags &= ~(int)O_SEARCH;
1557: }
1558:
1.448 martin 1559: flags = FFLAGS(open_flags);
1.104 mycroft 1560: if ((flags & (FREAD | FWRITE)) == 0)
1.448 martin 1561: return EINVAL;
1.409 dholland 1562:
1563: if ((error = fd_allocfile(&fp, &indx)) != 0) {
1564: return error;
1565: }
1.455 rmind 1566:
1.328 ad 1567: /* We're going to read cwdi->cwdi_cmask unlocked here. */
1.448 martin 1568: cmode = ((open_mode &~ cwdi->cwdi_cmask) & ALLPERMS) &~ S_ISTXT;
1.409 dholland 1569: NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, pb);
1.460 manu 1570: if (dvp != NULL)
1571: NDAT(&nd, dvp);
1572:
1.194 jdolecek 1573: l->l_dupfd = -indx - 1; /* XXX check for fdopen */
1.63 christos 1574: if ((error = vn_open(&nd, flags, cmode)) != 0) {
1.346 ad 1575: fd_abort(p, fp, indx);
1.213 christos 1576: if ((error == EDUPFD || error == EMOVEFD) &&
1.194 jdolecek 1577: l->l_dupfd >= 0 && /* XXX from fdopen */
1.45 mycroft 1578: (error =
1.346 ad 1579: fd_dupopen(l->l_dupfd, &indx, flags, error)) == 0) {
1.448 martin 1580: *fd = indx;
1.455 rmind 1581: return 0;
1.45 mycroft 1582: }
1583: if (error == ERESTART)
1.44 mycroft 1584: error = EINTR;
1.448 martin 1585: return error;
1.31 cgd 1586: }
1.331 pooka 1587:
1.194 jdolecek 1588: l->l_dupfd = 0;
1.31 cgd 1589: vp = nd.ni_vp;
1.409 dholland 1590:
1.422 christos 1591: if ((error = open_setfp(l, fp, vp, indx, flags)))
1592: return error;
1593:
1.406 hannken 1594: VOP_UNLOCK(vp);
1.448 martin 1595: *fd = indx;
1.346 ad 1596: fd_affix(p, fp, indx);
1.448 martin 1597: return 0;
1598: }
1599:
1600: int
1601: fd_open(const char *path, int open_flags, int open_mode, int *fd)
1602: {
1603: struct pathbuf *pb;
1.455 rmind 1604: int error, oflags;
1.448 martin 1605:
1.449 martin 1606: oflags = FFLAGS(open_flags);
1607: if ((oflags & (FREAD | FWRITE)) == 0)
1.448 martin 1608: return EINVAL;
1609:
1610: pb = pathbuf_create(path);
1611: if (pb == NULL)
1612: return ENOMEM;
1613:
1.460 manu 1614: error = do_open(curlwp, NULL, pb, open_flags, open_mode, fd);
1.455 rmind 1615: pathbuf_destroy(pb);
1616:
1617: return error;
1.448 martin 1618: }
1619:
1620: /*
1621: * Check permissions, allocate an open file structure,
1622: * and call the device open routine if any.
1623: */
1.460 manu 1624: static int
1625: do_sys_openat(lwp_t *l, int fdat, const char *path, int flags,
1626: int mode, int *fd)
1627: {
1628: file_t *dfp = NULL;
1629: struct vnode *dvp = NULL;
1630: struct pathbuf *pb;
1631: int error;
1632:
1.475 christos 1633: #ifdef COMPAT_10 /* XXX: and perhaps later */
1.477 maxv 1634: if (path == NULL) {
1.475 christos 1635: pb = pathbuf_create(".");
1.477 maxv 1636: if (pb == NULL)
1637: return ENOMEM;
1638: } else
1.475 christos 1639: #endif
1640: {
1641: error = pathbuf_copyin(path, &pb);
1642: if (error)
1643: return error;
1644: }
1.460 manu 1645:
1646: if (fdat != AT_FDCWD) {
1647: /* fd_getvnode() will use the descriptor for us */
1648: if ((error = fd_getvnode(fdat, &dfp)) != 0)
1649: goto out;
1650:
1651: dvp = dfp->f_data;
1652: }
1653:
1654: error = do_open(l, dvp, pb, flags, mode, fd);
1655:
1656: if (dfp != NULL)
1657: fd_putfile(fdat);
1658: out:
1659: pathbuf_destroy(pb);
1660: return error;
1661: }
1662:
1.448 martin 1663: int
1664: sys_open(struct lwp *l, const struct sys_open_args *uap, register_t *retval)
1665: {
1666: /* {
1667: syscallarg(const char *) path;
1668: syscallarg(int) flags;
1669: syscallarg(int) mode;
1670: } */
1.460 manu 1671: int error;
1672: int fd;
1.448 martin 1673:
1.460 manu 1674: error = do_sys_openat(l, AT_FDCWD, SCARG(uap, path),
1675: SCARG(uap, flags), SCARG(uap, mode), &fd);
1.448 martin 1676:
1.460 manu 1677: if (error == 0)
1678: *retval = fd;
1.448 martin 1679:
1.455 rmind 1680: return error;
1.137 wrstuden 1681: }
1682:
1.433 manu 1683: int
1684: sys_openat(struct lwp *l, const struct sys_openat_args *uap, register_t *retval)
1685: {
1686: /* {
1687: syscallarg(int) fd;
1688: syscallarg(const char *) path;
1.460 manu 1689: syscallarg(int) oflags;
1.433 manu 1690: syscallarg(int) mode;
1691: } */
1.460 manu 1692: int error;
1693: int fd;
1694:
1695: error = do_sys_openat(l, SCARG(uap, fd), SCARG(uap, path),
1696: SCARG(uap, oflags), SCARG(uap, mode), &fd);
1697:
1698: if (error == 0)
1699: *retval = fd;
1.433 manu 1700:
1.460 manu 1701: return error;
1.433 manu 1702: }
1703:
1.249 yamt 1704: static void
1705: vfs__fhfree(fhandle_t *fhp)
1706: {
1707: size_t fhsize;
1708:
1709: fhsize = FHANDLE_SIZE(fhp);
1710: kmem_free(fhp, fhsize);
1711: }
1712:
1.137 wrstuden 1713: /*
1.243 yamt 1714: * vfs_composefh: compose a filehandle.
1715: */
1716:
1717: int
1.244 martin 1718: vfs_composefh(struct vnode *vp, fhandle_t *fhp, size_t *fh_size)
1.243 yamt 1719: {
1720: struct mount *mp;
1.250 yamt 1721: struct fid *fidp;
1.243 yamt 1722: int error;
1.250 yamt 1723: size_t needfhsize;
1724: size_t fidsize;
1.243 yamt 1725:
1726: mp = vp->v_mount;
1.250 yamt 1727: fidp = NULL;
1.252 martin 1728: if (*fh_size < FHANDLE_SIZE_MIN) {
1.250 yamt 1729: fidsize = 0;
1.244 martin 1730: } else {
1.250 yamt 1731: fidsize = *fh_size - offsetof(fhandle_t, fh_fid);
1732: if (fhp != NULL) {
1733: memset(fhp, 0, *fh_size);
1734: fhp->fh_fsid = mp->mnt_stat.f_fsidx;
1735: fidp = &fhp->fh_fid;
1736: }
1.244 martin 1737: }
1.250 yamt 1738: error = VFS_VPTOFH(vp, fidp, &fidsize);
1739: needfhsize = FHANDLE_SIZE_FROM_FILEID_SIZE(fidsize);
1740: if (error == 0 && *fh_size < needfhsize) {
1741: error = E2BIG;
1742: }
1743: *fh_size = needfhsize;
1.243 yamt 1744: return error;
1745: }
1746:
1.249 yamt 1747: int
1748: vfs_composefh_alloc(struct vnode *vp, fhandle_t **fhpp)
1749: {
1750: struct mount *mp;
1751: fhandle_t *fhp;
1752: size_t fhsize;
1753: size_t fidsize;
1754: int error;
1755:
1756: mp = vp->v_mount;
1.255 christos 1757: fidsize = 0;
1.249 yamt 1758: error = VFS_VPTOFH(vp, NULL, &fidsize);
1759: KASSERT(error != 0);
1760: if (error != E2BIG) {
1761: goto out;
1762: }
1.250 yamt 1763: fhsize = FHANDLE_SIZE_FROM_FILEID_SIZE(fidsize);
1.249 yamt 1764: fhp = kmem_zalloc(fhsize, KM_SLEEP);
1765: if (fhp == NULL) {
1766: error = ENOMEM;
1767: goto out;
1768: }
1769: fhp->fh_fsid = mp->mnt_stat.f_fsidx;
1770: error = VFS_VPTOFH(vp, &fhp->fh_fid, &fidsize);
1771: if (error == 0) {
1772: KASSERT((FHANDLE_SIZE(fhp) == fhsize &&
1773: FHANDLE_FILEID(fhp)->fid_len == fidsize));
1774: *fhpp = fhp;
1775: } else {
1776: kmem_free(fhp, fhsize);
1777: }
1778: out:
1779: return error;
1780: }
1781:
1782: void
1783: vfs_composefh_free(fhandle_t *fhp)
1784: {
1785:
1786: vfs__fhfree(fhp);
1787: }
1788:
1.243 yamt 1789: /*
1.248 yamt 1790: * vfs_fhtovp: lookup a vnode by a filehandle.
1791: */
1792:
1793: int
1794: vfs_fhtovp(fhandle_t *fhp, struct vnode **vpp)
1795: {
1796: struct mount *mp;
1797: int error;
1798:
1799: *vpp = NULL;
1800: mp = vfs_getvfs(FHANDLE_FSID(fhp));
1801: if (mp == NULL) {
1802: error = ESTALE;
1803: goto out;
1804: }
1805: if (mp->mnt_op->vfs_fhtovp == NULL) {
1806: error = EOPNOTSUPP;
1807: goto out;
1808: }
1809: error = VFS_FHTOVP(mp, FHANDLE_FILEID(fhp), vpp);
1810: out:
1811: return error;
1812: }
1813:
1814: /*
1.265 yamt 1815: * vfs_copyinfh_alloc: allocate and copyin a filehandle, given
1.263 martin 1816: * the needed size.
1817: */
1818:
1819: int
1.265 yamt 1820: vfs_copyinfh_alloc(const void *ufhp, size_t fhsize, fhandle_t **fhpp)
1.263 martin 1821: {
1822: fhandle_t *fhp;
1823: int error;
1824:
1.250 yamt 1825: if (fhsize > FHANDLE_SIZE_MAX) {
1826: return EINVAL;
1827: }
1.265 yamt 1828: if (fhsize < FHANDLE_SIZE_MIN) {
1829: return EINVAL;
1830: }
1.267 yamt 1831: again:
1.248 yamt 1832: fhp = kmem_alloc(fhsize, KM_SLEEP);
1833: if (fhp == NULL) {
1834: return ENOMEM;
1835: }
1836: error = copyin(ufhp, fhp, fhsize);
1837: if (error == 0) {
1.265 yamt 1838: /* XXX this check shouldn't be here */
1839: if (FHANDLE_SIZE(fhp) == fhsize) {
1.263 martin 1840: *fhpp = fhp;
1841: return 0;
1.267 yamt 1842: } else if (fhsize == NFSX_V2FH && FHANDLE_SIZE(fhp) < fhsize) {
1843: /*
1844: * a kludge for nfsv2 padded handles.
1845: */
1846: size_t sz;
1847:
1848: sz = FHANDLE_SIZE(fhp);
1849: kmem_free(fhp, fhsize);
1850: fhsize = sz;
1851: goto again;
1.264 yamt 1852: } else {
1.265 yamt 1853: /*
1854: * userland told us wrong size.
1855: */
1.263 martin 1856: error = EINVAL;
1.264 yamt 1857: }
1.248 yamt 1858: }
1.263 martin 1859: kmem_free(fhp, fhsize);
1.248 yamt 1860: return error;
1861: }
1862:
1863: void
1864: vfs_copyinfh_free(fhandle_t *fhp)
1865: {
1866:
1.249 yamt 1867: vfs__fhfree(fhp);
1.248 yamt 1868: }
1869:
1870: /*
1.137 wrstuden 1871: * Get file handle system call
1872: */
1873: int
1.335 dsl 1874: sys___getfh30(struct lwp *l, const struct sys___getfh30_args *uap, register_t *retval)
1.137 wrstuden 1875: {
1.335 dsl 1876: /* {
1.137 wrstuden 1877: syscallarg(char *) fname;
1878: syscallarg(fhandle_t *) fhp;
1.244 martin 1879: syscallarg(size_t *) fh_size;
1.335 dsl 1880: } */
1.155 augustss 1881: struct vnode *vp;
1.244 martin 1882: fhandle_t *fh;
1.137 wrstuden 1883: int error;
1.409 dholland 1884: struct pathbuf *pb;
1.137 wrstuden 1885: struct nameidata nd;
1.244 martin 1886: size_t sz;
1.249 yamt 1887: size_t usz;
1.137 wrstuden 1888:
1889: /*
1890: * Must be super user
1891: */
1.268 elad 1892: error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FILEHANDLE,
1893: 0, NULL, NULL, NULL);
1.137 wrstuden 1894: if (error)
1895: return (error);
1.409 dholland 1896:
1897: error = pathbuf_copyin(SCARG(uap, fname), &pb);
1898: if (error) {
1899: return error;
1900: }
1901: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, pb);
1.137 wrstuden 1902: error = namei(&nd);
1.409 dholland 1903: if (error) {
1904: pathbuf_destroy(pb);
1905: return error;
1906: }
1.137 wrstuden 1907: vp = nd.ni_vp;
1.409 dholland 1908: pathbuf_destroy(pb);
1909:
1.249 yamt 1910: error = vfs_composefh_alloc(vp, &fh);
1.247 yamt 1911: vput(vp);
1.249 yamt 1912: if (error != 0) {
1.485 christos 1913: return error;
1.249 yamt 1914: }
1915: error = copyin(SCARG(uap, fh_size), &usz, sizeof(size_t));
1916: if (error != 0) {
1917: goto out;
1918: }
1919: sz = FHANDLE_SIZE(fh);
1920: error = copyout(&sz, SCARG(uap, fh_size), sizeof(size_t));
1921: if (error != 0) {
1922: goto out;
1.244 martin 1923: }
1.249 yamt 1924: if (usz >= sz) {
1925: error = copyout(fh, SCARG(uap, fhp), sz);
1926: } else {
1927: error = E2BIG;
1.244 martin 1928: }
1.249 yamt 1929: out:
1930: vfs_composefh_free(fh);
1.137 wrstuden 1931: return (error);
1932: }
1933:
1934: /*
1935: * Open a file given a file handle.
1936: *
1937: * Check permissions, allocate an open file structure,
1938: * and call the device open routine if any.
1939: */
1.265 yamt 1940:
1.137 wrstuden 1941: int
1.265 yamt 1942: dofhopen(struct lwp *l, const void *ufhp, size_t fhsize, int oflags,
1943: register_t *retval)
1.137 wrstuden 1944: {
1.346 ad 1945: file_t *fp;
1.139 wrstuden 1946: struct vnode *vp = NULL;
1.257 ad 1947: kauth_cred_t cred = l->l_cred;
1.346 ad 1948: file_t *nfp;
1.422 christos 1949: int indx, error = 0;
1.137 wrstuden 1950: struct vattr va;
1.248 yamt 1951: fhandle_t *fh;
1.265 yamt 1952: int flags;
1.346 ad 1953: proc_t *p;
1954:
1955: p = curproc;
1.137 wrstuden 1956:
1957: /*
1958: * Must be super user
1959: */
1.269 elad 1960: if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FILEHANDLE,
1.270 elad 1961: 0, NULL, NULL, NULL)))
1.137 wrstuden 1962: return (error);
1963:
1.463 dholland 1964: if (oflags & O_SEARCH) {
1965: oflags &= ~(int)O_SEARCH;
1966: }
1967:
1.265 yamt 1968: flags = FFLAGS(oflags);
1.137 wrstuden 1969: if ((flags & (FREAD | FWRITE)) == 0)
1970: return (EINVAL);
1971: if ((flags & O_CREAT))
1972: return (EINVAL);
1.346 ad 1973: if ((error = fd_allocfile(&nfp, &indx)) != 0)
1.137 wrstuden 1974: return (error);
1975: fp = nfp;
1.265 yamt 1976: error = vfs_copyinfh_alloc(ufhp, fhsize, &fh);
1.248 yamt 1977: if (error != 0) {
1.139 wrstuden 1978: goto bad;
1979: }
1.248 yamt 1980: error = vfs_fhtovp(fh, &vp);
1.481 maxv 1981: vfs_copyinfh_free(fh);
1.248 yamt 1982: if (error != 0) {
1.139 wrstuden 1983: goto bad;
1984: }
1.137 wrstuden 1985:
1986: /* Now do an effective vn_open */
1987:
1988: if (vp->v_type == VSOCK) {
1989: error = EOPNOTSUPP;
1990: goto bad;
1991: }
1.333 yamt 1992: error = vn_openchk(vp, cred, flags);
1993: if (error != 0)
1994: goto bad;
1.137 wrstuden 1995: if (flags & O_TRUNC) {
1.406 hannken 1996: VOP_UNLOCK(vp); /* XXX */
1.137 wrstuden 1997: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); /* XXX */
1.402 pooka 1998: vattr_null(&va);
1.137 wrstuden 1999: va.va_size = 0;
1.332 pooka 2000: error = VOP_SETATTR(vp, &va, cred);
1.197 hannken 2001: if (error)
1.137 wrstuden 2002: goto bad;
2003: }
1.332 pooka 2004: if ((error = VOP_OPEN(vp, flags, cred)) != 0)
1.137 wrstuden 2005: goto bad;
1.346 ad 2006: if (flags & FWRITE) {
1.429 rmind 2007: mutex_enter(vp->v_interlock);
1.137 wrstuden 2008: vp->v_writecount++;
1.429 rmind 2009: mutex_exit(vp->v_interlock);
1.346 ad 2010: }
1.137 wrstuden 2011:
2012: /* done with modified vn_open, now finish what sys_open does. */
1.422 christos 2013: if ((error = open_setfp(l, fp, vp, indx, flags)))
2014: return error;
1.137 wrstuden 2015:
1.406 hannken 2016: VOP_UNLOCK(vp);
1.137 wrstuden 2017: *retval = indx;
1.346 ad 2018: fd_affix(p, fp, indx);
1.137 wrstuden 2019: return (0);
1.139 wrstuden 2020:
1.137 wrstuden 2021: bad:
1.346 ad 2022: fd_abort(p, fp, indx);
1.139 wrstuden 2023: if (vp != NULL)
2024: vput(vp);
1.137 wrstuden 2025: return (error);
2026: }
2027:
2028: int
1.335 dsl 2029: sys___fhopen40(struct lwp *l, const struct sys___fhopen40_args *uap, register_t *retval)
1.137 wrstuden 2030: {
1.335 dsl 2031: /* {
1.263 martin 2032: syscallarg(const void *) fhp;
2033: syscallarg(size_t) fh_size;
1.265 yamt 2034: syscallarg(int) flags;
1.335 dsl 2035: } */
1.265 yamt 2036:
2037: return dofhopen(l, SCARG(uap, fhp), SCARG(uap, fh_size),
2038: SCARG(uap, flags), retval);
2039: }
2040:
1.306 dsl 2041: int
2042: do_fhstat(struct lwp *l, const void *ufhp, size_t fhsize, struct stat *sb)
2043: {
1.137 wrstuden 2044: int error;
1.248 yamt 2045: fhandle_t *fh;
1.137 wrstuden 2046: struct vnode *vp;
2047:
2048: /*
2049: * Must be super user
2050: */
1.268 elad 2051: if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FILEHANDLE,
1.270 elad 2052: 0, NULL, NULL, NULL)))
1.137 wrstuden 2053: return (error);
2054:
1.265 yamt 2055: error = vfs_copyinfh_alloc(ufhp, fhsize, &fh);
1.306 dsl 2056: if (error != 0)
2057: return error;
2058:
1.248 yamt 2059: error = vfs_fhtovp(fh, &vp);
1.306 dsl 2060: vfs_copyinfh_free(fh);
2061: if (error != 0)
2062: return error;
2063:
1.346 ad 2064: error = vn_stat(vp, sb);
1.137 wrstuden 2065: vput(vp);
1.248 yamt 2066: return error;
1.137 wrstuden 2067: }
2068:
1.265 yamt 2069:
1.137 wrstuden 2070: /* ARGSUSED */
2071: int
1.383 christos 2072: sys___fhstat50(struct lwp *l, const struct sys___fhstat50_args *uap, register_t *retval)
1.137 wrstuden 2073: {
1.335 dsl 2074: /* {
1.265 yamt 2075: syscallarg(const void *) fhp;
1.263 martin 2076: syscallarg(size_t) fh_size;
1.265 yamt 2077: syscallarg(struct stat *) sb;
1.335 dsl 2078: } */
1.306 dsl 2079: struct stat sb;
2080: int error;
1.265 yamt 2081:
1.306 dsl 2082: error = do_fhstat(l, SCARG(uap, fhp), SCARG(uap, fh_size), &sb);
2083: if (error)
2084: return error;
2085: return copyout(&sb, SCARG(uap, sb), sizeof(sb));
1.265 yamt 2086: }
2087:
1.306 dsl 2088: int
2089: do_fhstatvfs(struct lwp *l, const void *ufhp, size_t fhsize, struct statvfs *sb,
2090: int flags)
2091: {
1.248 yamt 2092: fhandle_t *fh;
1.137 wrstuden 2093: struct mount *mp;
2094: struct vnode *vp;
2095: int error;
2096:
2097: /*
2098: * Must be super user
2099: */
1.268 elad 2100: if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FILEHANDLE,
1.270 elad 2101: 0, NULL, NULL, NULL)))
1.206 christos 2102: return error;
1.137 wrstuden 2103:
1.265 yamt 2104: error = vfs_copyinfh_alloc(ufhp, fhsize, &fh);
1.306 dsl 2105: if (error != 0)
2106: return error;
2107:
1.248 yamt 2108: error = vfs_fhtovp(fh, &vp);
1.306 dsl 2109: vfs_copyinfh_free(fh);
2110: if (error != 0)
2111: return error;
2112:
1.137 wrstuden 2113: mp = vp->v_mount;
1.306 dsl 2114: error = dostatvfs(mp, sb, l, flags, 1);
1.137 wrstuden 2115: vput(vp);
1.241 yamt 2116: return error;
1.31 cgd 2117: }
2118:
1.265 yamt 2119: /* ARGSUSED */
2120: int
1.335 dsl 2121: sys___fhstatvfs140(struct lwp *l, const struct sys___fhstatvfs140_args *uap, register_t *retval)
1.265 yamt 2122: {
1.335 dsl 2123: /* {
1.266 yamt 2124: syscallarg(const void *) fhp;
1.265 yamt 2125: syscallarg(size_t) fh_size;
2126: syscallarg(struct statvfs *) buf;
2127: syscallarg(int) flags;
1.335 dsl 2128: } */
1.306 dsl 2129: struct statvfs *sb = STATVFSBUF_GET();
2130: int error;
1.265 yamt 2131:
1.306 dsl 2132: error = do_fhstatvfs(l, SCARG(uap, fhp), SCARG(uap, fh_size), sb,
2133: SCARG(uap, flags));
2134: if (error == 0)
2135: error = copyout(sb, SCARG(uap, buf), sizeof(*sb));
2136: STATVFSBUF_PUT(sb);
2137: return error;
1.265 yamt 2138: }
2139:
1.31 cgd 2140: /*
2141: * Create a special file.
2142: */
2143: /* ARGSUSED */
1.63 christos 2144: int
1.383 christos 2145: sys___mknod50(struct lwp *l, const struct sys___mknod50_args *uap,
2146: register_t *retval)
1.56 thorpej 2147: {
1.335 dsl 2148: /* {
1.74 cgd 2149: syscallarg(const char *) path;
1.383 christos 2150: syscallarg(mode_t) mode;
2151: syscallarg(dev_t) dev;
1.335 dsl 2152: } */
1.460 manu 2153: return do_sys_mknodat(l, AT_FDCWD, SCARG(uap, path), SCARG(uap, mode),
1.399 haad 2154: SCARG(uap, dev), retval, UIO_USERSPACE);
1.383 christos 2155: }
2156:
2157: int
1.433 manu 2158: sys_mknodat(struct lwp *l, const struct sys_mknodat_args *uap,
2159: register_t *retval)
2160: {
2161: /* {
2162: syscallarg(int) fd;
2163: syscallarg(const char *) path;
2164: syscallarg(mode_t) mode;
1.468 njoly 2165: syscallarg(int) pad;
2166: syscallarg(dev_t) dev;
1.433 manu 2167: } */
2168:
1.460 manu 2169: return do_sys_mknodat(l, SCARG(uap, fd), SCARG(uap, path),
2170: SCARG(uap, mode), SCARG(uap, dev), retval, UIO_USERSPACE);
1.433 manu 2171: }
2172:
2173: int
1.383 christos 2174: do_sys_mknod(struct lwp *l, const char *pathname, mode_t mode, dev_t dev,
1.399 haad 2175: register_t *retval, enum uio_seg seg)
1.383 christos 2176: {
1.460 manu 2177: return do_sys_mknodat(l, AT_FDCWD, pathname, mode, dev, retval, seg);
2178: }
2179:
2180: int
2181: do_sys_mknodat(struct lwp *l, int fdat, const char *pathname, mode_t mode,
2182: dev_t dev, register_t *retval, enum uio_seg seg)
2183: {
1.179 thorpej 2184: struct proc *p = l->l_proc;
1.155 augustss 2185: struct vnode *vp;
1.31 cgd 2186: struct vattr vattr;
1.301 pooka 2187: int error, optype;
1.409 dholland 2188: struct pathbuf *pb;
1.315 christos 2189: struct nameidata nd;
1.409 dholland 2190: const char *pathstring;
1.31 cgd 2191:
1.268 elad 2192: if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MKNOD,
2193: 0, NULL, NULL, NULL)) != 0)
1.31 cgd 2194: return (error);
1.301 pooka 2195:
2196: optype = VOP_MKNOD_DESCOFFSET;
1.315 christos 2197:
1.409 dholland 2198: error = pathbuf_maybe_copyin(pathname, seg, &pb);
2199: if (error) {
2200: return error;
2201: }
2202: pathstring = pathbuf_stringcopy_get(pb);
2203: if (pathstring == NULL) {
2204: pathbuf_destroy(pb);
2205: return ENOMEM;
2206: }
1.315 christos 2207:
1.409 dholland 2208: NDINIT(&nd, CREATE, LOCKPARENT | TRYEMULROOT, pb);
1.460 manu 2209:
2210: if ((error = fd_nameiat(l, fdat, &nd)) != 0)
1.314 christos 2211: goto out;
1.31 cgd 2212: vp = nd.ni_vp;
1.409 dholland 2213:
1.43 mycroft 2214: if (vp != NULL)
1.31 cgd 2215: error = EEXIST;
1.43 mycroft 2216: else {
1.402 pooka 2217: vattr_null(&vattr);
1.328 ad 2218: /* We will read cwdi->cwdi_cmask unlocked. */
1.383 christos 2219: vattr.va_mode = (mode & ALLPERMS) &~ p->p_cwdi->cwdi_cmask;
2220: vattr.va_rdev = dev;
1.43 mycroft 2221:
1.383 christos 2222: switch (mode & S_IFMT) {
1.43 mycroft 2223: case S_IFMT: /* used by badsect to flag bad sectors */
2224: vattr.va_type = VBAD;
2225: break;
2226: case S_IFCHR:
2227: vattr.va_type = VCHR;
2228: break;
2229: case S_IFBLK:
2230: vattr.va_type = VBLK;
2231: break;
2232: case S_IFWHT:
1.301 pooka 2233: optype = VOP_WHITEOUT_DESCOFFSET;
2234: break;
2235: case S_IFREG:
1.314 christos 2236: #if NVERIEXEC > 0
1.409 dholland 2237: error = veriexec_openchk(l, nd.ni_vp, pathstring,
1.314 christos 2238: O_CREAT);
2239: #endif /* NVERIEXEC > 0 */
1.301 pooka 2240: vattr.va_type = VREG;
1.302 pooka 2241: vattr.va_rdev = VNOVAL;
1.301 pooka 2242: optype = VOP_CREATE_DESCOFFSET;
1.43 mycroft 2243: break;
2244: default:
2245: error = EINVAL;
2246: break;
2247: }
1.31 cgd 2248: }
1.432 martin 2249: if (error == 0 && optype == VOP_MKNOD_DESCOFFSET
2250: && vattr.va_rdev == VNOVAL)
1.431 hannken 2251: error = EINVAL;
1.43 mycroft 2252: if (!error) {
1.301 pooka 2253: switch (optype) {
2254: case VOP_WHITEOUT_DESCOFFSET:
1.43 mycroft 2255: error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
2256: if (error)
2257: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2258: vput(nd.ni_dvp);
1.301 pooka 2259: break;
2260:
2261: case VOP_MKNOD_DESCOFFSET:
1.43 mycroft 2262: error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp,
2263: &nd.ni_cnd, &vattr);
1.168 assar 2264: if (error == 0)
1.473 hannken 2265: vrele(nd.ni_vp);
1.472 hannken 2266: vput(nd.ni_dvp);
1.301 pooka 2267: break;
2268:
2269: case VOP_CREATE_DESCOFFSET:
2270: error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp,
2271: &nd.ni_cnd, &vattr);
2272: if (error == 0)
1.473 hannken 2273: vrele(nd.ni_vp);
1.472 hannken 2274: vput(nd.ni_dvp);
1.301 pooka 2275: break;
1.43 mycroft 2276: }
2277: } else {
2278: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2279: if (nd.ni_dvp == vp)
2280: vrele(nd.ni_dvp);
2281: else
2282: vput(nd.ni_dvp);
2283: if (vp)
2284: vrele(vp);
1.31 cgd 2285: }
1.314 christos 2286: out:
1.409 dholland 2287: pathbuf_stringcopy_put(pb, pathstring);
2288: pathbuf_destroy(pb);
1.31 cgd 2289: return (error);
2290: }
2291:
2292: /*
2293: * Create a named pipe.
2294: */
2295: /* ARGSUSED */
1.63 christos 2296: int
1.335 dsl 2297: sys_mkfifo(struct lwp *l, const struct sys_mkfifo_args *uap, register_t *retval)
1.56 thorpej 2298: {
1.335 dsl 2299: /* {
1.74 cgd 2300: syscallarg(const char *) path;
1.35 cgd 2301: syscallarg(int) mode;
1.335 dsl 2302: } */
1.460 manu 2303: return do_sys_mkfifoat(l, AT_FDCWD, SCARG(uap, path), SCARG(uap, mode));
2304: }
2305:
2306: int
2307: sys_mkfifoat(struct lwp *l, const struct sys_mkfifoat_args *uap,
2308: register_t *retval)
2309: {
2310: /* {
2311: syscallarg(int) fd;
2312: syscallarg(const char *) path;
2313: syscallarg(int) mode;
2314: } */
2315:
2316: return do_sys_mkfifoat(l, SCARG(uap, fd), SCARG(uap, path),
2317: SCARG(uap, mode));
2318: }
2319:
2320: static int
2321: do_sys_mkfifoat(struct lwp *l, int fdat, const char *path, mode_t mode)
2322: {
1.179 thorpej 2323: struct proc *p = l->l_proc;
1.31 cgd 2324: struct vattr vattr;
2325: int error;
1.409 dholland 2326: struct pathbuf *pb;
1.31 cgd 2327: struct nameidata nd;
2328:
1.460 manu 2329: error = pathbuf_copyin(path, &pb);
1.409 dholland 2330: if (error) {
2331: return error;
2332: }
2333: NDINIT(&nd, CREATE, LOCKPARENT | TRYEMULROOT, pb);
1.460 manu 2334:
2335: if ((error = fd_nameiat(l, fdat, &nd)) != 0) {
1.409 dholland 2336: pathbuf_destroy(pb);
2337: return error;
2338: }
1.31 cgd 2339: if (nd.ni_vp != NULL) {
2340: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2341: if (nd.ni_dvp == nd.ni_vp)
2342: vrele(nd.ni_dvp);
2343: else
2344: vput(nd.ni_dvp);
2345: vrele(nd.ni_vp);
1.409 dholland 2346: pathbuf_destroy(pb);
1.31 cgd 2347: return (EEXIST);
2348: }
1.402 pooka 2349: vattr_null(&vattr);
1.31 cgd 2350: vattr.va_type = VFIFO;
1.328 ad 2351: /* We will read cwdi->cwdi_cmask unlocked. */
1.460 manu 2352: vattr.va_mode = (mode & ALLPERMS) &~ p->p_cwdi->cwdi_cmask;
1.168 assar 2353: error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
2354: if (error == 0)
1.473 hannken 2355: vrele(nd.ni_vp);
1.472 hannken 2356: vput(nd.ni_dvp);
1.409 dholland 2357: pathbuf_destroy(pb);
1.168 assar 2358: return (error);
1.31 cgd 2359: }
2360:
2361: /*
2362: * Make a hard file link.
2363: */
2364: /* ARGSUSED */
1.469 chs 2365: int
1.460 manu 2366: do_sys_linkat(struct lwp *l, int fdpath, const char *path, int fdlink,
2367: const char *link, int follow, register_t *retval)
1.56 thorpej 2368: {
1.155 augustss 2369: struct vnode *vp;
1.409 dholland 2370: struct pathbuf *linkpb;
1.31 cgd 2371: struct nameidata nd;
1.460 manu 2372: namei_simple_flags_t ns_flags;
1.31 cgd 2373: int error;
2374:
1.460 manu 2375: if (follow & AT_SYMLINK_FOLLOW)
2376: ns_flags = NSM_FOLLOW_TRYEMULROOT;
1.433 manu 2377: else
1.460 manu 2378: ns_flags = NSM_NOFOLLOW_TRYEMULROOT;
1.433 manu 2379:
1.460 manu 2380: error = fd_nameiat_simple_user(l, fdpath, path, ns_flags, &vp);
1.395 dholland 2381: if (error != 0)
1.31 cgd 2382: return (error);
1.433 manu 2383: error = pathbuf_copyin(link, &linkpb);
1.409 dholland 2384: if (error) {
2385: goto out1;
2386: }
2387: NDINIT(&nd, CREATE, LOCKPARENT | TRYEMULROOT, linkpb);
1.460 manu 2388: if ((error = fd_nameiat(l, fdlink, &nd)) != 0)
1.409 dholland 2389: goto out2;
1.66 mycroft 2390: if (nd.ni_vp) {
2391: error = EEXIST;
1.419 yamt 2392: goto abortop;
2393: }
1.423 rmind 2394: /* Prevent hard links on directories. */
2395: if (vp->v_type == VDIR) {
2396: error = EPERM;
2397: goto abortop;
2398: }
2399: /* Prevent cross-mount operation. */
1.419 yamt 2400: if (nd.ni_dvp->v_mount != vp->v_mount) {
2401: error = EXDEV;
2402: goto abortop;
1.31 cgd 2403: }
1.66 mycroft 2404: error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
1.409 dholland 2405: out2:
2406: pathbuf_destroy(linkpb);
2407: out1:
1.31 cgd 2408: vrele(vp);
2409: return (error);
1.419 yamt 2410: abortop:
2411: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2412: if (nd.ni_dvp == nd.ni_vp)
2413: vrele(nd.ni_dvp);
2414: else
2415: vput(nd.ni_dvp);
2416: if (nd.ni_vp != NULL)
2417: vrele(nd.ni_vp);
2418: goto out2;
1.31 cgd 2419: }
2420:
1.63 christos 2421: int
1.433 manu 2422: sys_link(struct lwp *l, const struct sys_link_args *uap, register_t *retval)
2423: {
2424: /* {
2425: syscallarg(const char *) path;
2426: syscallarg(const char *) link;
2427: } */
2428: const char *path = SCARG(uap, path);
2429: const char *link = SCARG(uap, link);
2430:
1.460 manu 2431: return do_sys_linkat(l, AT_FDCWD, path, AT_FDCWD, link,
2432: AT_SYMLINK_FOLLOW, retval);
1.433 manu 2433: }
2434:
2435: int
2436: sys_linkat(struct lwp *l, const struct sys_linkat_args *uap,
2437: register_t *retval)
2438: {
2439: /* {
2440: syscallarg(int) fd1;
2441: syscallarg(const char *) name1;
2442: syscallarg(int) fd2;
2443: syscallarg(const char *) name2;
2444: syscallarg(int) flags;
2445: } */
1.460 manu 2446: int fd1 = SCARG(uap, fd1);
1.433 manu 2447: const char *name1 = SCARG(uap, name1);
1.460 manu 2448: int fd2 = SCARG(uap, fd2);
1.433 manu 2449: const char *name2 = SCARG(uap, name2);
2450: int follow;
2451:
2452: follow = SCARG(uap, flags) & AT_SYMLINK_FOLLOW;
2453:
1.460 manu 2454: return do_sys_linkat(l, fd1, name1, fd2, name2, follow, retval);
1.433 manu 2455: }
2456:
2457:
2458: int
1.407 pooka 2459: do_sys_symlink(const char *patharg, const char *link, enum uio_seg seg)
1.56 thorpej 2460: {
1.460 manu 2461: return do_sys_symlinkat(NULL, patharg, AT_FDCWD, link, seg);
2462: }
2463:
2464: static int
2465: do_sys_symlinkat(struct lwp *l, const char *patharg, int fdat,
2466: const char *link, enum uio_seg seg)
2467: {
1.407 pooka 2468: struct proc *p = curproc;
1.31 cgd 2469: struct vattr vattr;
2470: char *path;
2471: int error;
1.409 dholland 2472: struct pathbuf *linkpb;
1.31 cgd 2473: struct nameidata nd;
2474:
1.460 manu 2475: KASSERT(l != NULL || fdat == AT_FDCWD);
2476:
1.161 thorpej 2477: path = PNBUF_GET();
1.407 pooka 2478: if (seg == UIO_USERSPACE) {
2479: if ((error = copyinstr(patharg, path, MAXPATHLEN, NULL)) != 0)
1.409 dholland 2480: goto out1;
2481: if ((error = pathbuf_copyin(link, &linkpb)) != 0)
2482: goto out1;
1.407 pooka 2483: } else {
2484: KASSERT(strlen(patharg) < MAXPATHLEN);
2485: strcpy(path, patharg);
1.409 dholland 2486: linkpb = pathbuf_create(link);
2487: if (linkpb == NULL) {
2488: error = ENOMEM;
2489: goto out1;
2490: }
1.407 pooka 2491: }
1.433 manu 2492: ktrkuser("symlink-target", path, strlen(path));
2493:
1.409 dholland 2494: NDINIT(&nd, CREATE, LOCKPARENT | TRYEMULROOT, linkpb);
1.460 manu 2495: if ((error = fd_nameiat(l, fdat, &nd)) != 0)
1.409 dholland 2496: goto out2;
1.31 cgd 2497: if (nd.ni_vp) {
2498: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2499: if (nd.ni_dvp == nd.ni_vp)
2500: vrele(nd.ni_dvp);
2501: else
2502: vput(nd.ni_dvp);
2503: vrele(nd.ni_vp);
2504: error = EEXIST;
1.409 dholland 2505: goto out2;
1.31 cgd 2506: }
1.402 pooka 2507: vattr_null(&vattr);
1.230 jmmv 2508: vattr.va_type = VLNK;
1.328 ad 2509: /* We will read cwdi->cwdi_cmask unlocked. */
1.134 thorpej 2510: vattr.va_mode = ACCESSPERMS &~ p->p_cwdi->cwdi_cmask;
1.31 cgd 2511: error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
1.168 assar 2512: if (error == 0)
1.473 hannken 2513: vrele(nd.ni_vp);
1.472 hannken 2514: vput(nd.ni_dvp);
1.409 dholland 2515: out2:
2516: pathbuf_destroy(linkpb);
2517: out1:
1.161 thorpej 2518: PNBUF_PUT(path);
1.31 cgd 2519: return (error);
2520: }
2521:
2522: /*
1.407 pooka 2523: * Make a symbolic link.
2524: */
2525: /* ARGSUSED */
2526: int
2527: sys_symlink(struct lwp *l, const struct sys_symlink_args *uap, register_t *retval)
2528: {
2529: /* {
2530: syscallarg(const char *) path;
2531: syscallarg(const char *) link;
2532: } */
2533:
1.460 manu 2534: return do_sys_symlinkat(l, SCARG(uap, path), AT_FDCWD, SCARG(uap, link),
1.407 pooka 2535: UIO_USERSPACE);
2536: }
2537:
1.433 manu 2538: int
2539: sys_symlinkat(struct lwp *l, const struct sys_symlinkat_args *uap,
2540: register_t *retval)
2541: {
2542: /* {
1.460 manu 2543: syscallarg(const char *) path1;
1.433 manu 2544: syscallarg(int) fd;
1.460 manu 2545: syscallarg(const char *) path2;
1.433 manu 2546: } */
2547:
1.460 manu 2548: return do_sys_symlinkat(l, SCARG(uap, path1), SCARG(uap, fd),
2549: SCARG(uap, path2), UIO_USERSPACE);
1.433 manu 2550: }
2551:
1.407 pooka 2552: /*
1.43 mycroft 2553: * Delete a whiteout from the filesystem.
2554: */
2555: /* ARGSUSED */
1.63 christos 2556: int
1.335 dsl 2557: sys_undelete(struct lwp *l, const struct sys_undelete_args *uap, register_t *retval)
1.56 thorpej 2558: {
1.335 dsl 2559: /* {
1.74 cgd 2560: syscallarg(const char *) path;
1.335 dsl 2561: } */
1.43 mycroft 2562: int error;
1.409 dholland 2563: struct pathbuf *pb;
1.43 mycroft 2564: struct nameidata nd;
2565:
1.409 dholland 2566: error = pathbuf_copyin(SCARG(uap, path), &pb);
2567: if (error) {
2568: return error;
2569: }
2570:
2571: NDINIT(&nd, DELETE, LOCKPARENT | DOWHITEOUT | TRYEMULROOT, pb);
1.43 mycroft 2572: error = namei(&nd);
1.409 dholland 2573: if (error) {
2574: pathbuf_destroy(pb);
1.43 mycroft 2575: return (error);
1.409 dholland 2576: }
1.43 mycroft 2577:
2578: if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
2579: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2580: if (nd.ni_dvp == nd.ni_vp)
2581: vrele(nd.ni_dvp);
2582: else
2583: vput(nd.ni_dvp);
2584: if (nd.ni_vp)
2585: vrele(nd.ni_vp);
1.409 dholland 2586: pathbuf_destroy(pb);
1.43 mycroft 2587: return (EEXIST);
2588: }
1.63 christos 2589: if ((error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE)) != 0)
1.43 mycroft 2590: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2591: vput(nd.ni_dvp);
1.409 dholland 2592: pathbuf_destroy(pb);
1.43 mycroft 2593: return (error);
2594: }
2595:
2596: /*
1.31 cgd 2597: * Delete a name from the filesystem.
2598: */
2599: /* ARGSUSED */
1.63 christos 2600: int
1.335 dsl 2601: sys_unlink(struct lwp *l, const struct sys_unlink_args *uap, register_t *retval)
1.56 thorpej 2602: {
1.335 dsl 2603: /* {
1.74 cgd 2604: syscallarg(const char *) path;
1.335 dsl 2605: } */
1.336 ad 2606:
1.460 manu 2607: return do_sys_unlinkat(l, AT_FDCWD, SCARG(uap, path), 0, UIO_USERSPACE);
1.336 ad 2608: }
2609:
2610: int
1.433 manu 2611: sys_unlinkat(struct lwp *l, const struct sys_unlinkat_args *uap,
2612: register_t *retval)
2613: {
2614: /* {
2615: syscallarg(int) fd;
2616: syscallarg(const char *) path;
1.460 manu 2617: syscallarg(int) flag;
1.433 manu 2618: } */
2619:
1.460 manu 2620: return do_sys_unlinkat(l, SCARG(uap, fd), SCARG(uap, path),
2621: SCARG(uap, flag), UIO_USERSPACE);
1.433 manu 2622: }
2623:
2624: int
1.336 ad 2625: do_sys_unlink(const char *arg, enum uio_seg seg)
2626: {
1.460 manu 2627: return do_sys_unlinkat(NULL, AT_FDCWD, arg, 0, seg);
2628: }
2629:
2630: static int
2631: do_sys_unlinkat(struct lwp *l, int fdat, const char *arg, int flags,
2632: enum uio_seg seg)
2633: {
1.155 augustss 2634: struct vnode *vp;
1.31 cgd 2635: int error;
1.409 dholland 2636: struct pathbuf *pb;
1.31 cgd 2637: struct nameidata nd;
1.409 dholland 2638: const char *pathstring;
1.31 cgd 2639:
1.460 manu 2640: KASSERT(l != NULL || fdat == AT_FDCWD);
2641:
1.409 dholland 2642: error = pathbuf_maybe_copyin(arg, seg, &pb);
2643: if (error) {
2644: return error;
2645: }
2646: pathstring = pathbuf_stringcopy_get(pb);
2647: if (pathstring == NULL) {
2648: pathbuf_destroy(pb);
2649: return ENOMEM;
2650: }
1.313 elad 2651:
1.409 dholland 2652: NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF | TRYEMULROOT, pb);
1.460 manu 2653: if ((error = fd_nameiat(l, fdat, &nd)) != 0)
1.313 elad 2654: goto out;
1.31 cgd 2655: vp = nd.ni_vp;
2656:
1.66 mycroft 2657: /*
2658: * The root of a mounted filesystem cannot be deleted.
2659: */
1.460 manu 2660: if ((vp->v_vflag & VV_ROOT) != 0) {
2661: error = EBUSY;
2662: goto abort;
2663: }
2664:
2665: if ((vp->v_type == VDIR) && (vp->v_mountedhere != NULL)) {
1.66 mycroft 2666: error = EBUSY;
1.460 manu 2667: goto abort;
2668: }
2669:
2670: /*
2671: * No rmdir "." please.
2672: */
2673: if (nd.ni_dvp == vp) {
2674: error = EINVAL;
2675: goto abort;
2676: }
2677:
2678: /*
2679: * AT_REMOVEDIR is required to remove a directory
2680: */
2681: if (vp->v_type == VDIR) {
2682: if (!(flags & AT_REMOVEDIR)) {
2683: error = EPERM;
2684: goto abort;
2685: } else {
2686: error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
2687: goto out;
2688: }
2689: }
2690:
2691: /*
2692: * Starting here we only deal with non directories.
2693: */
2694: if (flags & AT_REMOVEDIR) {
2695: error = ENOTDIR;
2696: goto abort;
1.31 cgd 2697: }
1.219 blymn 2698:
1.460 manu 2699:
1.256 elad 2700: #if NVERIEXEC > 0
1.222 elad 2701: /* Handle remove requests for veriexec entries. */
1.409 dholland 2702: if ((error = veriexec_removechk(curlwp, nd.ni_vp, pathstring)) != 0) {
1.219 blymn 2703: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2704: if (nd.ni_dvp == vp)
2705: vrele(nd.ni_dvp);
2706: else
2707: vput(nd.ni_dvp);
2708: vput(vp);
2709: goto out;
2710: }
1.256 elad 2711: #endif /* NVERIEXEC > 0 */
2712:
1.253 elad 2713: #ifdef FILEASSOC
1.278 elad 2714: (void)fileassoc_file_delete(vp);
1.253 elad 2715: #endif /* FILEASSOC */
1.66 mycroft 2716: error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1.460 manu 2717: goto out;
2718:
2719: abort:
2720: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2721: if (nd.ni_dvp == vp)
2722: vrele(nd.ni_dvp);
2723: else
2724: vput(nd.ni_dvp);
2725: vput(vp);
2726:
1.66 mycroft 2727: out:
1.409 dholland 2728: pathbuf_stringcopy_put(pb, pathstring);
2729: pathbuf_destroy(pb);
1.31 cgd 2730: return (error);
2731: }
2732:
2733: /*
2734: * Reposition read/write file offset.
2735: */
1.63 christos 2736: int
1.335 dsl 2737: sys_lseek(struct lwp *l, const struct sys_lseek_args *uap, register_t *retval)
1.56 thorpej 2738: {
1.335 dsl 2739: /* {
1.35 cgd 2740: syscallarg(int) fd;
2741: syscallarg(int) pad;
2742: syscallarg(off_t) offset;
2743: syscallarg(int) whence;
1.335 dsl 2744: } */
1.257 ad 2745: kauth_cred_t cred = l->l_cred;
1.346 ad 2746: file_t *fp;
1.84 kleink 2747: struct vnode *vp;
1.31 cgd 2748: struct vattr vattr;
1.155 augustss 2749: off_t newoff;
1.346 ad 2750: int error, fd;
2751:
2752: fd = SCARG(uap, fd);
1.31 cgd 2753:
1.346 ad 2754: if ((fp = fd_getfile(fd)) == NULL)
1.31 cgd 2755: return (EBADF);
1.84 kleink 2756:
1.346 ad 2757: vp = fp->f_data;
1.135 thorpej 2758: if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
2759: error = ESPIPE;
2760: goto out;
2761: }
1.84 kleink 2762:
1.35 cgd 2763: switch (SCARG(uap, whence)) {
1.92 kleink 2764: case SEEK_CUR:
1.84 kleink 2765: newoff = fp->f_offset + SCARG(uap, offset);
1.31 cgd 2766: break;
1.92 kleink 2767: case SEEK_END:
1.440 hannken 2768: vn_lock(vp, LK_SHARED | LK_RETRY);
1.332 pooka 2769: error = VOP_GETATTR(vp, &vattr, cred);
1.440 hannken 2770: VOP_UNLOCK(vp);
1.328 ad 2771: if (error) {
1.135 thorpej 2772: goto out;
1.328 ad 2773: }
1.84 kleink 2774: newoff = SCARG(uap, offset) + vattr.va_size;
1.31 cgd 2775: break;
1.92 kleink 2776: case SEEK_SET:
1.84 kleink 2777: newoff = SCARG(uap, offset);
1.31 cgd 2778: break;
2779: default:
1.135 thorpej 2780: error = EINVAL;
2781: goto out;
1.31 cgd 2782: }
1.328 ad 2783: if ((error = VOP_SEEK(vp, fp->f_offset, newoff, cred)) == 0) {
2784: *(off_t *)retval = fp->f_offset = newoff;
2785: }
1.135 thorpej 2786: out:
1.346 ad 2787: fd_putfile(fd);
1.135 thorpej 2788: return (error);
1.120 thorpej 2789: }
2790:
2791: /*
2792: * Positional read system call.
2793: */
2794: int
1.335 dsl 2795: sys_pread(struct lwp *l, const struct sys_pread_args *uap, register_t *retval)
1.120 thorpej 2796: {
1.335 dsl 2797: /* {
1.120 thorpej 2798: syscallarg(int) fd;
2799: syscallarg(void *) buf;
2800: syscallarg(size_t) nbyte;
2801: syscallarg(off_t) offset;
1.335 dsl 2802: } */
1.346 ad 2803: file_t *fp;
1.120 thorpej 2804: struct vnode *vp;
2805: off_t offset;
2806: int error, fd = SCARG(uap, fd);
2807:
1.346 ad 2808: if ((fp = fd_getfile(fd)) == NULL)
1.166 thorpej 2809: return (EBADF);
2810:
1.183 pk 2811: if ((fp->f_flag & FREAD) == 0) {
1.346 ad 2812: fd_putfile(fd);
1.120 thorpej 2813: return (EBADF);
1.183 pk 2814: }
1.120 thorpej 2815:
1.346 ad 2816: vp = fp->f_data;
1.135 thorpej 2817: if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
2818: error = ESPIPE;
2819: goto out;
2820: }
1.120 thorpej 2821:
2822: offset = SCARG(uap, offset);
2823:
2824: /*
2825: * XXX This works because no file systems actually
2826: * XXX take any action on the seek operation.
2827: */
2828: if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
1.135 thorpej 2829: goto out;
1.120 thorpej 2830:
1.135 thorpej 2831: /* dofileread() will unuse the descriptor for us */
1.328 ad 2832: return (dofileread(fd, fp, SCARG(uap, buf), SCARG(uap, nbyte),
1.120 thorpej 2833: &offset, 0, retval));
1.135 thorpej 2834:
2835: out:
1.346 ad 2836: fd_putfile(fd);
1.135 thorpej 2837: return (error);
1.120 thorpej 2838: }
2839:
2840: /*
2841: * Positional scatter read system call.
2842: */
2843: int
1.335 dsl 2844: sys_preadv(struct lwp *l, const struct sys_preadv_args *uap, register_t *retval)
1.120 thorpej 2845: {
1.335 dsl 2846: /* {
1.120 thorpej 2847: syscallarg(int) fd;
2848: syscallarg(const struct iovec *) iovp;
2849: syscallarg(int) iovcnt;
2850: syscallarg(off_t) offset;
1.335 dsl 2851: } */
2852: off_t offset = SCARG(uap, offset);
1.120 thorpej 2853:
1.328 ad 2854: return do_filereadv(SCARG(uap, fd), SCARG(uap, iovp),
1.335 dsl 2855: SCARG(uap, iovcnt), &offset, 0, retval);
1.120 thorpej 2856: }
2857:
2858: /*
2859: * Positional write system call.
2860: */
2861: int
1.335 dsl 2862: sys_pwrite(struct lwp *l, const struct sys_pwrite_args *uap, register_t *retval)
1.120 thorpej 2863: {
1.335 dsl 2864: /* {
1.120 thorpej 2865: syscallarg(int) fd;
2866: syscallarg(const void *) buf;
2867: syscallarg(size_t) nbyte;
2868: syscallarg(off_t) offset;
1.335 dsl 2869: } */
1.346 ad 2870: file_t *fp;
1.120 thorpej 2871: struct vnode *vp;
2872: off_t offset;
2873: int error, fd = SCARG(uap, fd);
2874:
1.346 ad 2875: if ((fp = fd_getfile(fd)) == NULL)
1.166 thorpej 2876: return (EBADF);
2877:
1.183 pk 2878: if ((fp->f_flag & FWRITE) == 0) {
1.346 ad 2879: fd_putfile(fd);
1.120 thorpej 2880: return (EBADF);
1.183 pk 2881: }
1.120 thorpej 2882:
1.346 ad 2883: vp = fp->f_data;
1.135 thorpej 2884: if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
2885: error = ESPIPE;
2886: goto out;
2887: }
1.120 thorpej 2888:
2889: offset = SCARG(uap, offset);
2890:
2891: /*
2892: * XXX This works because no file systems actually
2893: * XXX take any action on the seek operation.
2894: */
2895: if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
1.135 thorpej 2896: goto out;
1.120 thorpej 2897:
1.135 thorpej 2898: /* dofilewrite() will unuse the descriptor for us */
1.328 ad 2899: return (dofilewrite(fd, fp, SCARG(uap, buf), SCARG(uap, nbyte),
1.120 thorpej 2900: &offset, 0, retval));
1.135 thorpej 2901:
2902: out:
1.346 ad 2903: fd_putfile(fd);
1.135 thorpej 2904: return (error);
1.120 thorpej 2905: }
2906:
2907: /*
2908: * Positional gather write system call.
2909: */
2910: int
1.335 dsl 2911: sys_pwritev(struct lwp *l, const struct sys_pwritev_args *uap, register_t *retval)
1.120 thorpej 2912: {
1.335 dsl 2913: /* {
1.120 thorpej 2914: syscallarg(int) fd;
2915: syscallarg(const struct iovec *) iovp;
2916: syscallarg(int) iovcnt;
2917: syscallarg(off_t) offset;
1.335 dsl 2918: } */
2919: off_t offset = SCARG(uap, offset);
1.120 thorpej 2920:
1.328 ad 2921: return do_filewritev(SCARG(uap, fd), SCARG(uap, iovp),
1.335 dsl 2922: SCARG(uap, iovcnt), &offset, 0, retval);
1.31 cgd 2923: }
2924:
2925: /*
2926: * Check access permissions.
2927: */
1.63 christos 2928: int
1.335 dsl 2929: sys_access(struct lwp *l, const struct sys_access_args *uap, register_t *retval)
1.56 thorpej 2930: {
1.335 dsl 2931: /* {
1.74 cgd 2932: syscallarg(const char *) path;
1.35 cgd 2933: syscallarg(int) flags;
1.335 dsl 2934: } */
1.460 manu 2935:
2936: return do_sys_accessat(l, AT_FDCWD, SCARG(uap, path),
2937: SCARG(uap, flags), 0);
2938: }
2939:
1.469 chs 2940: int
1.460 manu 2941: do_sys_accessat(struct lwp *l, int fdat, const char *path,
2942: int mode, int flags)
2943: {
1.242 elad 2944: kauth_cred_t cred;
1.155 augustss 2945: struct vnode *vp;
1.460 manu 2946: int error, nd_flag, vmode;
1.409 dholland 2947: struct pathbuf *pb;
1.31 cgd 2948: struct nameidata nd;
2949:
1.417 dholland 2950: CTASSERT(F_OK == 0);
1.460 manu 2951: if ((mode & ~(R_OK | W_OK | X_OK)) != 0) {
2952: /* nonsense mode */
1.415 dholland 2953: return EINVAL;
2954: }
2955:
1.460 manu 2956: nd_flag = FOLLOW | LOCKLEAF | TRYEMULROOT;
2957: if (flags & AT_SYMLINK_NOFOLLOW)
2958: nd_flag &= ~FOLLOW;
2959:
2960: error = pathbuf_copyin(path, &pb);
2961: if (error)
1.409 dholland 2962: return error;
1.460 manu 2963:
2964: NDINIT(&nd, LOOKUP, nd_flag, pb);
1.409 dholland 2965:
2966: /* Override default credentials */
1.257 ad 2967: cred = kauth_cred_dup(l->l_cred);
1.460 manu 2968: if (!(flags & AT_EACCESS)) {
2969: kauth_cred_seteuid(cred, kauth_cred_getuid(l->l_cred));
2970: kauth_cred_setegid(cred, kauth_cred_getgid(l->l_cred));
2971: }
1.169 christos 2972: nd.ni_cnd.cn_cred = cred;
1.409 dholland 2973:
1.460 manu 2974: if ((error = fd_nameiat(l, fdat, &nd)) != 0) {
1.409 dholland 2975: pathbuf_destroy(pb);
1.169 christos 2976: goto out;
1.409 dholland 2977: }
1.31 cgd 2978: vp = nd.ni_vp;
1.409 dholland 2979: pathbuf_destroy(pb);
1.31 cgd 2980:
2981: /* Flags == 0 means only check for existence. */
1.460 manu 2982: if (mode) {
2983: vmode = 0;
2984: if (mode & R_OK)
2985: vmode |= VREAD;
2986: if (mode & W_OK)
2987: vmode |= VWRITE;
2988: if (mode & X_OK)
2989: vmode |= VEXEC;
1.138 is 2990:
1.460 manu 2991: error = VOP_ACCESS(vp, vmode, cred);
2992: if (!error && (vmode & VWRITE))
1.138 is 2993: error = vn_writechk(vp);
1.31 cgd 2994: }
2995: vput(vp);
1.169 christos 2996: out:
1.242 elad 2997: kauth_cred_free(cred);
1.31 cgd 2998: return (error);
2999: }
3000:
1.433 manu 3001: int
3002: sys_faccessat(struct lwp *l, const struct sys_faccessat_args *uap,
3003: register_t *retval)
3004: {
3005: /* {
3006: syscallarg(int) fd;
3007: syscallarg(const char *) path;
3008: syscallarg(int) amode;
3009: syscallarg(int) flag;
3010: } */
3011:
1.460 manu 3012: return do_sys_accessat(l, SCARG(uap, fd), SCARG(uap, path),
3013: SCARG(uap, amode), SCARG(uap, flag));
1.433 manu 3014: }
3015:
1.31 cgd 3016: /*
1.306 dsl 3017: * Common code for all sys_stat functions, including compat versions.
3018: */
3019: int
1.460 manu 3020: do_sys_stat(const char *userpath, unsigned int nd_flag,
3021: struct stat *sb)
3022: {
3023: return do_sys_statat(NULL, AT_FDCWD, userpath, nd_flag, sb);
3024: }
3025:
1.465 matt 3026: int
1.460 manu 3027: do_sys_statat(struct lwp *l, int fdat, const char *userpath,
3028: unsigned int nd_flag, struct stat *sb)
1.306 dsl 3029: {
3030: int error;
1.409 dholland 3031: struct pathbuf *pb;
1.306 dsl 3032: struct nameidata nd;
3033:
1.460 manu 3034: KASSERT(l != NULL || fdat == AT_FDCWD);
3035:
1.409 dholland 3036: error = pathbuf_copyin(userpath, &pb);
3037: if (error) {
3038: return error;
3039: }
1.460 manu 3040:
3041: NDINIT(&nd, LOOKUP, nd_flag | LOCKLEAF | TRYEMULROOT, pb);
3042:
3043: error = fd_nameiat(l, fdat, &nd);
1.409 dholland 3044: if (error != 0) {
3045: pathbuf_destroy(pb);
1.306 dsl 3046: return error;
1.409 dholland 3047: }
1.346 ad 3048: error = vn_stat(nd.ni_vp, sb);
1.306 dsl 3049: vput(nd.ni_vp);
1.409 dholland 3050: pathbuf_destroy(pb);
1.306 dsl 3051: return error;
3052: }
3053:
3054: /*
1.31 cgd 3055: * Get file status; this version follows links.
3056: */
3057: /* ARGSUSED */
1.63 christos 3058: int
1.383 christos 3059: sys___stat50(struct lwp *l, const struct sys___stat50_args *uap, register_t *retval)
1.56 thorpej 3060: {
1.335 dsl 3061: /* {
1.74 cgd 3062: syscallarg(const char *) path;
1.35 cgd 3063: syscallarg(struct stat *) ub;
1.335 dsl 3064: } */
1.31 cgd 3065: struct stat sb;
3066: int error;
3067:
1.460 manu 3068: error = do_sys_statat(l, AT_FDCWD, SCARG(uap, path), FOLLOW, &sb);
1.31 cgd 3069: if (error)
1.306 dsl 3070: return error;
3071: return copyout(&sb, SCARG(uap, ub), sizeof(sb));
1.31 cgd 3072: }
3073:
3074: /*
3075: * Get file status; this version does not follow links.
3076: */
3077: /* ARGSUSED */
1.63 christos 3078: int
1.383 christos 3079: sys___lstat50(struct lwp *l, const struct sys___lstat50_args *uap, register_t *retval)
1.56 thorpej 3080: {
1.335 dsl 3081: /* {
1.74 cgd 3082: syscallarg(const char *) path;
1.35 cgd 3083: syscallarg(struct stat *) ub;
1.335 dsl 3084: } */
1.65 mycroft 3085: struct stat sb;
1.31 cgd 3086: int error;
3087:
1.460 manu 3088: error = do_sys_statat(l, AT_FDCWD, SCARG(uap, path), NOFOLLOW, &sb);
1.64 jtc 3089: if (error)
1.306 dsl 3090: return error;
3091: return copyout(&sb, SCARG(uap, ub), sizeof(sb));
1.31 cgd 3092: }
3093:
1.433 manu 3094: int
3095: sys_fstatat(struct lwp *l, const struct sys_fstatat_args *uap,
3096: register_t *retval)
3097: {
3098: /* {
3099: syscallarg(int) fd;
3100: syscallarg(const char *) path;
1.460 manu 3101: syscallarg(struct stat *) buf;
1.433 manu 3102: syscallarg(int) flag;
3103: } */
1.460 manu 3104: unsigned int nd_flag;
1.461 martin 3105: struct stat sb;
3106: int error;
1.433 manu 3107:
1.460 manu 3108: if (SCARG(uap, flag) & AT_SYMLINK_NOFOLLOW)
3109: nd_flag = NOFOLLOW;
3110: else
3111: nd_flag = FOLLOW;
3112:
1.461 martin 3113: error = do_sys_statat(l, SCARG(uap, fd), SCARG(uap, path), nd_flag,
3114: &sb);
3115: if (error)
3116: return error;
3117: return copyout(&sb, SCARG(uap, buf), sizeof(sb));
1.433 manu 3118: }
1.460 manu 3119:
1.31 cgd 3120: /*
3121: * Get configurable pathname variables.
3122: */
3123: /* ARGSUSED */
1.63 christos 3124: int
1.335 dsl 3125: sys_pathconf(struct lwp *l, const struct sys_pathconf_args *uap, register_t *retval)
1.56 thorpej 3126: {
1.335 dsl 3127: /* {
1.74 cgd 3128: syscallarg(const char *) path;
1.35 cgd 3129: syscallarg(int) name;
1.335 dsl 3130: } */
1.31 cgd 3131: int error;
1.409 dholland 3132: struct pathbuf *pb;
1.31 cgd 3133: struct nameidata nd;
3134:
1.409 dholland 3135: error = pathbuf_copyin(SCARG(uap, path), &pb);
3136: if (error) {
3137: return error;
3138: }
3139: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, pb);
3140: if ((error = namei(&nd)) != 0) {
3141: pathbuf_destroy(pb);
1.31 cgd 3142: return (error);
1.409 dholland 3143: }
1.35 cgd 3144: error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval);
1.31 cgd 3145: vput(nd.ni_vp);
1.409 dholland 3146: pathbuf_destroy(pb);
1.31 cgd 3147: return (error);
3148: }
3149:
3150: /*
3151: * Return target name of a symbolic link.
3152: */
3153: /* ARGSUSED */
1.63 christos 3154: int
1.460 manu 3155: sys_readlink(struct lwp *l, const struct sys_readlink_args *uap,
3156: register_t *retval)
1.56 thorpej 3157: {
1.335 dsl 3158: /* {
1.74 cgd 3159: syscallarg(const char *) path;
1.35 cgd 3160: syscallarg(char *) buf;
1.115 kleink 3161: syscallarg(size_t) count;
1.335 dsl 3162: } */
1.460 manu 3163: return do_sys_readlinkat(l, AT_FDCWD, SCARG(uap, path),
3164: SCARG(uap, buf), SCARG(uap, count), retval);
3165: }
3166:
3167: static int
3168: do_sys_readlinkat(struct lwp *l, int fdat, const char *path, char *buf,
3169: size_t count, register_t *retval)
3170: {
1.155 augustss 3171: struct vnode *vp;
1.31 cgd 3172: struct iovec aiov;
3173: struct uio auio;
3174: int error;
1.409 dholland 3175: struct pathbuf *pb;
1.31 cgd 3176: struct nameidata nd;
3177:
1.460 manu 3178: error = pathbuf_copyin(path, &pb);
1.409 dholland 3179: if (error) {
3180: return error;
3181: }
3182: NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | TRYEMULROOT, pb);
1.460 manu 3183: if ((error = fd_nameiat(l, fdat, &nd)) != 0) {
1.409 dholland 3184: pathbuf_destroy(pb);
3185: return error;
3186: }
1.31 cgd 3187: vp = nd.ni_vp;
1.409 dholland 3188: pathbuf_destroy(pb);
1.31 cgd 3189: if (vp->v_type != VLNK)
3190: error = EINVAL;
1.106 enami 3191: else if (!(vp->v_mount->mnt_flag & MNT_SYMPERM) ||
1.332 pooka 3192: (error = VOP_ACCESS(vp, VREAD, l->l_cred)) == 0) {
1.460 manu 3193: aiov.iov_base = buf;
3194: aiov.iov_len = count;
1.31 cgd 3195: auio.uio_iov = &aiov;
3196: auio.uio_iovcnt = 1;
3197: auio.uio_offset = 0;
3198: auio.uio_rw = UIO_READ;
1.238 yamt 3199: KASSERT(l == curlwp);
3200: auio.uio_vmspace = l->l_proc->p_vmspace;
1.460 manu 3201: auio.uio_resid = count;
1.464 christos 3202: if ((error = VOP_READLINK(vp, &auio, l->l_cred)) == 0)
3203: *retval = count - auio.uio_resid;
1.31 cgd 3204: }
3205: vput(vp);
3206: return (error);
3207: }
3208:
1.433 manu 3209: int
3210: sys_readlinkat(struct lwp *l, const struct sys_readlinkat_args *uap,
3211: register_t *retval)
3212: {
3213: /* {
3214: syscallarg(int) fd;
3215: syscallarg(const char *) path;
3216: syscallarg(char *) buf;
1.460 manu 3217: syscallarg(size_t) bufsize;
1.433 manu 3218: } */
3219:
1.460 manu 3220: return do_sys_readlinkat(l, SCARG(uap, fd), SCARG(uap, path),
3221: SCARG(uap, buf), SCARG(uap, bufsize), retval);
1.433 manu 3222: }
3223:
1.31 cgd 3224: /*
3225: * Change flags of a file given a path name.
3226: */
3227: /* ARGSUSED */
1.63 christos 3228: int
1.335 dsl 3229: sys_chflags(struct lwp *l, const struct sys_chflags_args *uap, register_t *retval)
1.56 thorpej 3230: {
1.335 dsl 3231: /* {
1.74 cgd 3232: syscallarg(const char *) path;
3233: syscallarg(u_long) flags;
1.335 dsl 3234: } */
1.155 augustss 3235: struct vnode *vp;
1.31 cgd 3236: int error;
3237:
1.395 dholland 3238: error = namei_simple_user(SCARG(uap, path),
3239: NSM_FOLLOW_TRYEMULROOT, &vp);
3240: if (error != 0)
1.31 cgd 3241: return (error);
1.234 christos 3242: error = change_flags(vp, SCARG(uap, flags), l);
1.31 cgd 3243: vput(vp);
3244: return (error);
3245: }
3246:
3247: /*
3248: * Change flags of a file given a file descriptor.
3249: */
3250: /* ARGSUSED */
1.63 christos 3251: int
1.335 dsl 3252: sys_fchflags(struct lwp *l, const struct sys_fchflags_args *uap, register_t *retval)
1.56 thorpej 3253: {
1.335 dsl 3254: /* {
1.35 cgd 3255: syscallarg(int) fd;
1.74 cgd 3256: syscallarg(u_long) flags;
1.335 dsl 3257: } */
1.31 cgd 3258: struct vnode *vp;
1.346 ad 3259: file_t *fp;
1.31 cgd 3260: int error;
3261:
1.346 ad 3262: /* fd_getvnode() will use the descriptor for us */
3263: if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
1.31 cgd 3264: return (error);
1.346 ad 3265: vp = fp->f_data;
1.234 christos 3266: error = change_flags(vp, SCARG(uap, flags), l);
1.406 hannken 3267: VOP_UNLOCK(vp);
1.346 ad 3268: fd_putfile(SCARG(uap, fd));
1.156 mrg 3269: return (error);
3270: }
3271:
3272: /*
1.163 enami 3273: * Change flags of a file given a path name; this version does
1.156 mrg 3274: * not follow links.
3275: */
3276: int
1.335 dsl 3277: sys_lchflags(struct lwp *l, const struct sys_lchflags_args *uap, register_t *retval)
1.156 mrg 3278: {
1.335 dsl 3279: /* {
1.156 mrg 3280: syscallarg(const char *) path;
3281: syscallarg(u_long) flags;
1.335 dsl 3282: } */
1.163 enami 3283: struct vnode *vp;
1.156 mrg 3284: int error;
3285:
1.395 dholland 3286: error = namei_simple_user(SCARG(uap, path),
3287: NSM_NOFOLLOW_TRYEMULROOT, &vp);
3288: if (error != 0)
1.156 mrg 3289: return (error);
1.234 christos 3290: error = change_flags(vp, SCARG(uap, flags), l);
1.163 enami 3291: vput(vp);
3292: return (error);
3293: }
3294:
3295: /*
3296: * Common routine to change flags of a file.
3297: */
3298: int
1.234 christos 3299: change_flags(struct vnode *vp, u_long flags, struct lwp *l)
1.163 enami 3300: {
3301: struct vattr vattr;
3302: int error;
3303:
1.156 mrg 3304: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.450 elad 3305:
1.402 pooka 3306: vattr_null(&vattr);
1.163 enami 3307: vattr.va_flags = flags;
1.332 pooka 3308: error = VOP_SETATTR(vp, &vattr, l->l_cred);
1.450 elad 3309:
1.31 cgd 3310: return (error);
3311: }
3312:
3313: /*
1.98 enami 3314: * Change mode of a file given path name; this version follows links.
1.31 cgd 3315: */
3316: /* ARGSUSED */
1.63 christos 3317: int
1.335 dsl 3318: sys_chmod(struct lwp *l, const struct sys_chmod_args *uap, register_t *retval)
1.56 thorpej 3319: {
1.335 dsl 3320: /* {
1.74 cgd 3321: syscallarg(const char *) path;
1.35 cgd 3322: syscallarg(int) mode;
1.335 dsl 3323: } */
1.460 manu 3324: return do_sys_chmodat(l, AT_FDCWD, SCARG(uap, path),
3325: SCARG(uap, mode), 0);
3326: }
3327:
1.469 chs 3328: int
1.460 manu 3329: do_sys_chmodat(struct lwp *l, int fdat, const char *path, int mode, int flags)
3330: {
1.31 cgd 3331: int error;
1.395 dholland 3332: struct vnode *vp;
1.460 manu 3333: namei_simple_flags_t ns_flag;
3334:
3335: if (flags & AT_SYMLINK_NOFOLLOW)
3336: ns_flag = NSM_NOFOLLOW_TRYEMULROOT;
3337: else
3338: ns_flag = NSM_FOLLOW_TRYEMULROOT;
1.31 cgd 3339:
1.460 manu 3340: error = fd_nameiat_simple_user(l, fdat, path, ns_flag, &vp);
1.395 dholland 3341: if (error != 0)
1.460 manu 3342: return error;
1.97 enami 3343:
1.460 manu 3344: error = change_mode(vp, mode, l);
1.97 enami 3345:
1.395 dholland 3346: vrele(vp);
1.460 manu 3347:
1.31 cgd 3348: return (error);
3349: }
3350:
3351: /*
3352: * Change mode of a file given a file descriptor.
3353: */
3354: /* ARGSUSED */
1.63 christos 3355: int
1.335 dsl 3356: sys_fchmod(struct lwp *l, const struct sys_fchmod_args *uap, register_t *retval)
1.56 thorpej 3357: {
1.335 dsl 3358: /* {
1.35 cgd 3359: syscallarg(int) fd;
3360: syscallarg(int) mode;
1.335 dsl 3361: } */
1.346 ad 3362: file_t *fp;
1.31 cgd 3363: int error;
3364:
1.346 ad 3365: /* fd_getvnode() will use the descriptor for us */
3366: if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
1.31 cgd 3367: return (error);
1.346 ad 3368: error = change_mode(fp->f_data, SCARG(uap, mode), l);
3369: fd_putfile(SCARG(uap, fd));
1.135 thorpej 3370: return (error);
1.97 enami 3371: }
3372:
1.433 manu 3373: int
3374: sys_fchmodat(struct lwp *l, const struct sys_fchmodat_args *uap,
3375: register_t *retval)
3376: {
3377: /* {
3378: syscallarg(int) fd;
3379: syscallarg(const char *) path;
3380: syscallarg(int) mode;
3381: syscallarg(int) flag;
3382: } */
3383:
1.460 manu 3384: return do_sys_chmodat(l, SCARG(uap, fd), SCARG(uap, path),
3385: SCARG(uap, mode), SCARG(uap, flag));
1.433 manu 3386: }
3387:
1.97 enami 3388: /*
1.98 enami 3389: * Change mode of a file given path name; this version does not follow links.
3390: */
3391: /* ARGSUSED */
3392: int
1.335 dsl 3393: sys_lchmod(struct lwp *l, const struct sys_lchmod_args *uap, register_t *retval)
1.98 enami 3394: {
1.335 dsl 3395: /* {
1.98 enami 3396: syscallarg(const char *) path;
3397: syscallarg(int) mode;
1.335 dsl 3398: } */
1.98 enami 3399: int error;
1.395 dholland 3400: struct vnode *vp;
1.98 enami 3401:
1.395 dholland 3402: error = namei_simple_user(SCARG(uap, path),
3403: NSM_NOFOLLOW_TRYEMULROOT, &vp);
3404: if (error != 0)
1.98 enami 3405: return (error);
3406:
1.395 dholland 3407: error = change_mode(vp, SCARG(uap, mode), l);
1.98 enami 3408:
1.395 dholland 3409: vrele(vp);
1.98 enami 3410: return (error);
3411: }
3412:
3413: /*
1.97 enami 3414: * Common routine to set mode given a vnode.
3415: */
3416: static int
1.234 christos 3417: change_mode(struct vnode *vp, int mode, struct lwp *l)
1.97 enami 3418: {
3419: struct vattr vattr;
3420: int error;
3421:
1.113 fvdl 3422: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.402 pooka 3423: vattr_null(&vattr);
1.113 fvdl 3424: vattr.va_mode = mode & ALLPERMS;
1.332 pooka 3425: error = VOP_SETATTR(vp, &vattr, l->l_cred);
1.406 hannken 3426: VOP_UNLOCK(vp);
1.31 cgd 3427: return (error);
3428: }
3429:
3430: /*
1.98 enami 3431: * Set ownership given a path name; this version follows links.
1.31 cgd 3432: */
3433: /* ARGSUSED */
1.63 christos 3434: int
1.335 dsl 3435: sys_chown(struct lwp *l, const struct sys_chown_args *uap, register_t *retval)
1.56 thorpej 3436: {
1.335 dsl 3437: /* {
1.74 cgd 3438: syscallarg(const char *) path;
3439: syscallarg(uid_t) uid;
3440: syscallarg(gid_t) gid;
1.335 dsl 3441: } */
1.460 manu 3442: return do_sys_chownat(l, AT_FDCWD, SCARG(uap, path), SCARG(uap,uid),
3443: SCARG(uap, gid), 0);
3444: }
3445:
1.469 chs 3446: int
1.460 manu 3447: do_sys_chownat(struct lwp *l, int fdat, const char *path, uid_t uid,
3448: gid_t gid, int flags)
3449: {
1.31 cgd 3450: int error;
1.395 dholland 3451: struct vnode *vp;
1.460 manu 3452: namei_simple_flags_t ns_flag;
3453:
3454: if (flags & AT_SYMLINK_NOFOLLOW)
3455: ns_flag = NSM_NOFOLLOW_TRYEMULROOT;
3456: else
3457: ns_flag = NSM_FOLLOW_TRYEMULROOT;
1.31 cgd 3458:
1.460 manu 3459: error = fd_nameiat_simple_user(l, fdat, path, ns_flag, &vp);
1.395 dholland 3460: if (error != 0)
1.460 manu 3461: return error;
1.86 kleink 3462:
1.460 manu 3463: error = change_owner(vp, uid, gid, l, 0);
1.112 kleink 3464:
1.395 dholland 3465: vrele(vp);
1.460 manu 3466:
1.112 kleink 3467: return (error);
3468: }
3469:
3470: /*
3471: * Set ownership given a path name; this version follows links.
3472: * Provides POSIX semantics.
3473: */
3474: /* ARGSUSED */
3475: int
1.335 dsl 3476: sys___posix_chown(struct lwp *l, const struct sys___posix_chown_args *uap, register_t *retval)
1.112 kleink 3477: {
1.335 dsl 3478: /* {
1.112 kleink 3479: syscallarg(const char *) path;
3480: syscallarg(uid_t) uid;
3481: syscallarg(gid_t) gid;
1.335 dsl 3482: } */
1.112 kleink 3483: int error;
1.395 dholland 3484: struct vnode *vp;
1.112 kleink 3485:
1.395 dholland 3486: error = namei_simple_user(SCARG(uap, path),
3487: NSM_FOLLOW_TRYEMULROOT, &vp);
3488: if (error != 0)
1.112 kleink 3489: return (error);
3490:
1.395 dholland 3491: error = change_owner(vp, SCARG(uap, uid), SCARG(uap, gid), l, 1);
1.86 kleink 3492:
1.395 dholland 3493: vrele(vp);
1.31 cgd 3494: return (error);
3495: }
3496:
3497: /*
3498: * Set ownership given a file descriptor.
3499: */
3500: /* ARGSUSED */
1.63 christos 3501: int
1.335 dsl 3502: sys_fchown(struct lwp *l, const struct sys_fchown_args *uap, register_t *retval)
1.56 thorpej 3503: {
1.335 dsl 3504: /* {
1.35 cgd 3505: syscallarg(int) fd;
1.74 cgd 3506: syscallarg(uid_t) uid;
3507: syscallarg(gid_t) gid;
1.335 dsl 3508: } */
1.71 mycroft 3509: int error;
1.346 ad 3510: file_t *fp;
1.31 cgd 3511:
1.346 ad 3512: /* fd_getvnode() will use the descriptor for us */
3513: if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
1.31 cgd 3514: return (error);
1.346 ad 3515: error = change_owner(fp->f_data, SCARG(uap, uid), SCARG(uap, gid),
3516: l, 0);
3517: fd_putfile(SCARG(uap, fd));
1.135 thorpej 3518: return (error);
1.112 kleink 3519: }
3520:
1.433 manu 3521: int
3522: sys_fchownat(struct lwp *l, const struct sys_fchownat_args *uap,
3523: register_t *retval)
3524: {
3525: /* {
3526: syscallarg(int) fd;
3527: syscallarg(const char *) path;
1.460 manu 3528: syscallarg(uid_t) owner;
3529: syscallarg(gid_t) group;
1.433 manu 3530: syscallarg(int) flag;
3531: } */
3532:
1.460 manu 3533: return do_sys_chownat(l, SCARG(uap, fd), SCARG(uap, path),
3534: SCARG(uap, owner), SCARG(uap, group),
3535: SCARG(uap, flag));
1.433 manu 3536: }
3537:
1.112 kleink 3538: /*
3539: * Set ownership given a file descriptor, providing POSIX/XPG semantics.
3540: */
3541: /* ARGSUSED */
3542: int
1.335 dsl 3543: sys___posix_fchown(struct lwp *l, const struct sys___posix_fchown_args *uap, register_t *retval)
1.112 kleink 3544: {
1.335 dsl 3545: /* {
1.112 kleink 3546: syscallarg(int) fd;
3547: syscallarg(uid_t) uid;
3548: syscallarg(gid_t) gid;
1.335 dsl 3549: } */
1.112 kleink 3550: int error;
1.346 ad 3551: file_t *fp;
1.112 kleink 3552:
1.346 ad 3553: /* fd_getvnode() will use the descriptor for us */
3554: if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
1.112 kleink 3555: return (error);
1.346 ad 3556: error = change_owner(fp->f_data, SCARG(uap, uid), SCARG(uap, gid),
3557: l, 1);
3558: fd_putfile(SCARG(uap, fd));
1.135 thorpej 3559: return (error);
1.86 kleink 3560: }
3561:
3562: /*
1.98 enami 3563: * Set ownership given a path name; this version does not follow links.
3564: */
3565: /* ARGSUSED */
3566: int
1.335 dsl 3567: sys_lchown(struct lwp *l, const struct sys_lchown_args *uap, register_t *retval)
1.98 enami 3568: {
1.335 dsl 3569: /* {
1.98 enami 3570: syscallarg(const char *) path;
3571: syscallarg(uid_t) uid;
3572: syscallarg(gid_t) gid;
1.335 dsl 3573: } */
1.98 enami 3574: int error;
1.395 dholland 3575: struct vnode *vp;
1.98 enami 3576:
1.395 dholland 3577: error = namei_simple_user(SCARG(uap, path),
3578: NSM_NOFOLLOW_TRYEMULROOT, &vp);
3579: if (error != 0)
1.98 enami 3580: return (error);
3581:
1.395 dholland 3582: error = change_owner(vp, SCARG(uap, uid), SCARG(uap, gid), l, 0);
1.112 kleink 3583:
1.395 dholland 3584: vrele(vp);
1.112 kleink 3585: return (error);
3586: }
3587:
3588: /*
3589: * Set ownership given a path name; this version does not follow links.
3590: * Provides POSIX/XPG semantics.
3591: */
3592: /* ARGSUSED */
3593: int
1.335 dsl 3594: sys___posix_lchown(struct lwp *l, const struct sys___posix_lchown_args *uap, register_t *retval)
1.112 kleink 3595: {
1.335 dsl 3596: /* {
1.112 kleink 3597: syscallarg(const char *) path;
3598: syscallarg(uid_t) uid;
3599: syscallarg(gid_t) gid;
1.335 dsl 3600: } */
1.112 kleink 3601: int error;
1.395 dholland 3602: struct vnode *vp;
1.112 kleink 3603:
1.395 dholland 3604: error = namei_simple_user(SCARG(uap, path),
3605: NSM_NOFOLLOW_TRYEMULROOT, &vp);
3606: if (error != 0)
1.112 kleink 3607: return (error);
3608:
1.395 dholland 3609: error = change_owner(vp, SCARG(uap, uid), SCARG(uap, gid), l, 1);
1.98 enami 3610:
1.395 dholland 3611: vrele(vp);
1.98 enami 3612: return (error);
3613: }
3614:
3615: /*
1.205 junyoung 3616: * Common routine to set ownership given a vnode.
1.86 kleink 3617: */
3618: static int
1.234 christos 3619: change_owner(struct vnode *vp, uid_t uid, gid_t gid, struct lwp *l,
1.221 thorpej 3620: int posix_semantics)
1.86 kleink 3621: {
3622: struct vattr vattr;
1.112 kleink 3623: mode_t newmode;
1.86 kleink 3624: int error;
3625:
1.113 fvdl 3626: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.332 pooka 3627: if ((error = VOP_GETATTR(vp, &vattr, l->l_cred)) != 0)
1.86 kleink 3628: goto out;
3629:
1.175 thorpej 3630: #define CHANGED(x) ((int)(x) != -1)
1.112 kleink 3631: newmode = vattr.va_mode;
3632: if (posix_semantics) {
3633: /*
1.114 kleink 3634: * POSIX/XPG semantics: if the caller is not the super-user,
3635: * clear set-user-id and set-group-id bits. Both POSIX and
3636: * the XPG consider the behaviour for calls by the super-user
3637: * implementation-defined; we leave the set-user-id and set-
3638: * group-id settings intact in that case.
1.112 kleink 3639: */
1.450 elad 3640: if (vattr.va_mode & S_ISUID) {
1.451 christos 3641: if (kauth_authorize_vnode(l->l_cred,
3642: KAUTH_VNODE_RETAIN_SUID, vp, NULL, EPERM) != 0)
1.450 elad 3643: newmode &= ~S_ISUID;
3644: }
3645: if (vattr.va_mode & S_ISGID) {
1.451 christos 3646: if (kauth_authorize_vnode(l->l_cred,
3647: KAUTH_VNODE_RETAIN_SGID, vp, NULL, EPERM) != 0)
1.450 elad 3648: newmode &= ~S_ISGID;
3649: }
1.112 kleink 3650: } else {
3651: /*
3652: * NetBSD semantics: when changing owner and/or group,
3653: * clear the respective bit(s).
3654: */
3655: if (CHANGED(uid))
3656: newmode &= ~S_ISUID;
3657: if (CHANGED(gid))
3658: newmode &= ~S_ISGID;
3659: }
3660: /* Update va_mode iff altered. */
3661: if (vattr.va_mode == newmode)
3662: newmode = VNOVAL;
1.205 junyoung 3663:
1.402 pooka 3664: vattr_null(&vattr);
1.175 thorpej 3665: vattr.va_uid = CHANGED(uid) ? uid : (uid_t)VNOVAL;
3666: vattr.va_gid = CHANGED(gid) ? gid : (gid_t)VNOVAL;
1.86 kleink 3667: vattr.va_mode = newmode;
1.332 pooka 3668: error = VOP_SETATTR(vp, &vattr, l->l_cred);
1.112 kleink 3669: #undef CHANGED
1.205 junyoung 3670:
1.86 kleink 3671: out:
1.406 hannken 3672: VOP_UNLOCK(vp);
1.31 cgd 3673: return (error);
3674: }
3675:
3676: /*
1.98 enami 3677: * Set the access and modification times given a path name; this
3678: * version follows links.
1.31 cgd 3679: */
3680: /* ARGSUSED */
1.63 christos 3681: int
1.383 christos 3682: sys___utimes50(struct lwp *l, const struct sys___utimes50_args *uap,
3683: register_t *retval)
1.56 thorpej 3684: {
1.335 dsl 3685: /* {
1.74 cgd 3686: syscallarg(const char *) path;
3687: syscallarg(const struct timeval *) tptr;
1.335 dsl 3688: } */
1.31 cgd 3689:
1.312 dsl 3690: return do_sys_utimes(l, NULL, SCARG(uap, path), FOLLOW,
1.346 ad 3691: SCARG(uap, tptr), UIO_USERSPACE);
1.71 mycroft 3692: }
3693:
3694: /*
3695: * Set the access and modification times given a file descriptor.
3696: */
3697: /* ARGSUSED */
3698: int
1.383 christos 3699: sys___futimes50(struct lwp *l, const struct sys___futimes50_args *uap,
3700: register_t *retval)
1.71 mycroft 3701: {
1.335 dsl 3702: /* {
1.71 mycroft 3703: syscallarg(int) fd;
1.74 cgd 3704: syscallarg(const struct timeval *) tptr;
1.335 dsl 3705: } */
1.71 mycroft 3706: int error;
1.346 ad 3707: file_t *fp;
1.71 mycroft 3708:
1.346 ad 3709: /* fd_getvnode() will use the descriptor for us */
3710: if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
1.96 enami 3711: return (error);
1.346 ad 3712: error = do_sys_utimes(l, fp->f_data, NULL, 0, SCARG(uap, tptr),
3713: UIO_USERSPACE);
3714: fd_putfile(SCARG(uap, fd));
1.135 thorpej 3715: return (error);
1.98 enami 3716: }
3717:
1.434 manu 3718: int
3719: sys_futimens(struct lwp *l, const struct sys_futimens_args *uap,
3720: register_t *retval)
3721: {
3722: /* {
3723: syscallarg(int) fd;
3724: syscallarg(const struct timespec *) tptr;
3725: } */
3726: int error;
3727: file_t *fp;
3728:
3729: /* fd_getvnode() will use the descriptor for us */
3730: if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
3731: return (error);
1.460 manu 3732: error = do_sys_utimensat(l, AT_FDCWD, fp->f_data, NULL, 0,
3733: SCARG(uap, tptr), UIO_USERSPACE);
1.434 manu 3734: fd_putfile(SCARG(uap, fd));
3735: return (error);
3736: }
3737:
1.98 enami 3738: /*
3739: * Set the access and modification times given a path name; this
3740: * version does not follow links.
3741: */
3742: int
1.383 christos 3743: sys___lutimes50(struct lwp *l, const struct sys___lutimes50_args *uap,
3744: register_t *retval)
1.98 enami 3745: {
1.335 dsl 3746: /* {
1.98 enami 3747: syscallarg(const char *) path;
3748: syscallarg(const struct timeval *) tptr;
1.335 dsl 3749: } */
1.98 enami 3750:
1.312 dsl 3751: return do_sys_utimes(l, NULL, SCARG(uap, path), NOFOLLOW,
1.346 ad 3752: SCARG(uap, tptr), UIO_USERSPACE);
1.97 enami 3753: }
3754:
1.433 manu 3755: int
3756: sys_utimensat(struct lwp *l, const struct sys_utimensat_args *uap,
3757: register_t *retval)
3758: {
3759: /* {
3760: syscallarg(int) fd;
3761: syscallarg(const char *) path;
3762: syscallarg(const struct timespec *) tptr;
3763: syscallarg(int) flag;
3764: } */
1.434 manu 3765: int follow;
3766: const struct timespec *tptr;
1.460 manu 3767: int error;
1.434 manu 3768:
3769: tptr = SCARG(uap, tptr);
3770: follow = (SCARG(uap, flag) & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW;
3771:
1.460 manu 3772: error = do_sys_utimensat(l, SCARG(uap, fd), NULL,
3773: SCARG(uap, path), follow, tptr, UIO_USERSPACE);
3774:
3775: return error;
1.433 manu 3776: }
3777:
1.97 enami 3778: /*
3779: * Common routine to set access and modification times given a vnode.
3780: */
1.312 dsl 3781: int
1.434 manu 3782: do_sys_utimens(struct lwp *l, struct vnode *vp, const char *path, int flag,
3783: const struct timespec *tptr, enum uio_seg seg)
1.97 enami 3784: {
1.460 manu 3785: return do_sys_utimensat(l, AT_FDCWD, vp, path, flag, tptr, seg);
3786: }
3787:
1.466 matt 3788: int
1.460 manu 3789: do_sys_utimensat(struct lwp *l, int fdat, struct vnode *vp,
3790: const char *path, int flag, const struct timespec *tptr, enum uio_seg seg)
3791: {
1.97 enami 3792: struct vattr vattr;
1.395 dholland 3793: int error, dorele = 0;
3794: namei_simple_flags_t sflags;
1.367 christos 3795: bool vanull, setbirthtime;
3796: struct timespec ts[2];
1.97 enami 3797:
1.460 manu 3798: KASSERT(l != NULL || fdat == AT_FDCWD);
3799:
1.395 dholland 3800: /*
3801: * I have checked all callers and they pass either FOLLOW,
3802: * NOFOLLOW, or 0 (when they don't pass a path), and NOFOLLOW
3803: * is 0. More to the point, they don't pass anything else.
3804: * Let's keep it that way at least until the namei interfaces
3805: * are fully sanitized.
3806: */
3807: KASSERT(flag == NOFOLLOW || flag == FOLLOW);
3808: sflags = (flag == FOLLOW) ?
3809: NSM_FOLLOW_TRYEMULROOT : NSM_NOFOLLOW_TRYEMULROOT;
3810:
1.97 enami 3811: if (tptr == NULL) {
1.367 christos 3812: vanull = true;
3813: nanotime(&ts[0]);
3814: ts[1] = ts[0];
1.71 mycroft 3815: } else {
1.367 christos 3816: vanull = false;
1.312 dsl 3817: if (seg != UIO_SYSSPACE) {
1.434 manu 3818: error = copyin(tptr, ts, sizeof (ts));
1.312 dsl 3819: if (error != 0)
3820: return error;
1.437 manu 3821: } else {
3822: ts[0] = tptr[0];
3823: ts[1] = tptr[1];
1.312 dsl 3824: }
1.71 mycroft 3825: }
1.312 dsl 3826:
1.438 enami 3827: if (ts[0].tv_nsec == UTIME_NOW) {
1.434 manu 3828: nanotime(&ts[0]);
1.438 enami 3829: if (ts[1].tv_nsec == UTIME_NOW) {
3830: vanull = true;
3831: ts[1] = ts[0];
3832: }
3833: } else if (ts[1].tv_nsec == UTIME_NOW)
1.434 manu 3834: nanotime(&ts[1]);
3835:
1.312 dsl 3836: if (vp == NULL) {
1.395 dholland 3837: /* note: SEG describes TPTR, not PATH; PATH is always user */
1.460 manu 3838: error = fd_nameiat_simple_user(l, fdat, path, sflags, &vp);
1.395 dholland 3839: if (error != 0)
1.367 christos 3840: return error;
1.395 dholland 3841: dorele = 1;
3842: }
1.312 dsl 3843:
1.113 fvdl 3844: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.367 christos 3845: setbirthtime = (VOP_GETATTR(vp, &vattr, l->l_cred) == 0 &&
3846: timespeccmp(&ts[1], &vattr.va_birthtime, <));
1.402 pooka 3847: vattr_null(&vattr);
1.434 manu 3848:
3849: if (ts[0].tv_nsec != UTIME_OMIT)
3850: vattr.va_atime = ts[0];
3851:
3852: if (ts[1].tv_nsec != UTIME_OMIT) {
3853: vattr.va_mtime = ts[1];
3854: if (setbirthtime)
3855: vattr.va_birthtime = ts[1];
3856: }
3857:
1.367 christos 3858: if (vanull)
1.392 yamt 3859: vattr.va_vaflags |= VA_UTIMES_NULL;
1.332 pooka 3860: error = VOP_SETATTR(vp, &vattr, l->l_cred);
1.406 hannken 3861: VOP_UNLOCK(vp);
1.312 dsl 3862:
1.395 dholland 3863: if (dorele != 0)
3864: vrele(vp);
1.312 dsl 3865:
1.367 christos 3866: return error;
1.31 cgd 3867: }
3868:
1.434 manu 3869: int
3870: do_sys_utimes(struct lwp *l, struct vnode *vp, const char *path, int flag,
3871: const struct timeval *tptr, enum uio_seg seg)
3872: {
3873: struct timespec ts[2];
3874: struct timespec *tsptr = NULL;
3875: int error;
3876:
3877: if (tptr != NULL) {
3878: struct timeval tv[2];
3879:
3880: if (seg != UIO_SYSSPACE) {
3881: error = copyin(tptr, tv, sizeof (tv));
3882: if (error != 0)
3883: return error;
3884: tptr = tv;
3885: }
3886:
3887: if ((tv[0].tv_usec == UTIME_NOW) ||
3888: (tv[0].tv_usec == UTIME_OMIT))
3889: ts[0].tv_nsec = tv[0].tv_usec;
3890: else
3891: TIMEVAL_TO_TIMESPEC(&tptr[0], &ts[0]);
3892:
3893: if ((tv[1].tv_usec == UTIME_NOW) ||
3894: (tv[1].tv_usec == UTIME_OMIT))
3895: ts[1].tv_nsec = tv[1].tv_usec;
3896: else
3897: TIMEVAL_TO_TIMESPEC(&tptr[1], &ts[1]);
3898:
3899: tsptr = &ts[0];
3900: }
3901:
3902: return do_sys_utimens(l, vp, path, flag, tsptr, UIO_SYSSPACE);
3903: }
3904:
1.31 cgd 3905: /*
3906: * Truncate a file given its path name.
3907: */
3908: /* ARGSUSED */
1.63 christos 3909: int
1.335 dsl 3910: sys_truncate(struct lwp *l, const struct sys_truncate_args *uap, register_t *retval)
1.56 thorpej 3911: {
1.335 dsl 3912: /* {
1.74 cgd 3913: syscallarg(const char *) path;
1.35 cgd 3914: syscallarg(int) pad;
3915: syscallarg(off_t) length;
1.335 dsl 3916: } */
1.155 augustss 3917: struct vnode *vp;
1.31 cgd 3918: struct vattr vattr;
3919: int error;
3920:
1.484 njoly 3921: if (SCARG(uap, length) < 0)
3922: return EINVAL;
3923:
1.395 dholland 3924: error = namei_simple_user(SCARG(uap, path),
3925: NSM_FOLLOW_TRYEMULROOT, &vp);
3926: if (error != 0)
1.31 cgd 3927: return (error);
1.113 fvdl 3928: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.31 cgd 3929: if (vp->v_type == VDIR)
3930: error = EISDIR;
3931: else if ((error = vn_writechk(vp)) == 0 &&
1.332 pooka 3932: (error = VOP_ACCESS(vp, VWRITE, l->l_cred)) == 0) {
1.402 pooka 3933: vattr_null(&vattr);
1.35 cgd 3934: vattr.va_size = SCARG(uap, length);
1.332 pooka 3935: error = VOP_SETATTR(vp, &vattr, l->l_cred);
1.31 cgd 3936: }
3937: vput(vp);
3938: return (error);
3939: }
3940:
3941: /*
3942: * Truncate a file given a file descriptor.
3943: */
3944: /* ARGSUSED */
1.63 christos 3945: int
1.335 dsl 3946: sys_ftruncate(struct lwp *l, const struct sys_ftruncate_args *uap, register_t *retval)
1.56 thorpej 3947: {
1.335 dsl 3948: /* {
1.35 cgd 3949: syscallarg(int) fd;
3950: syscallarg(int) pad;
3951: syscallarg(off_t) length;
1.335 dsl 3952: } */
1.31 cgd 3953: struct vattr vattr;
3954: struct vnode *vp;
1.346 ad 3955: file_t *fp;
1.31 cgd 3956: int error;
3957:
1.484 njoly 3958: if (SCARG(uap, length) < 0)
3959: return EINVAL;
3960:
1.346 ad 3961: /* fd_getvnode() will use the descriptor for us */
3962: if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
1.31 cgd 3963: return (error);
1.135 thorpej 3964: if ((fp->f_flag & FWRITE) == 0) {
3965: error = EINVAL;
3966: goto out;
3967: }
1.346 ad 3968: vp = fp->f_data;
1.113 fvdl 3969: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.31 cgd 3970: if (vp->v_type == VDIR)
3971: error = EISDIR;
3972: else if ((error = vn_writechk(vp)) == 0) {
1.402 pooka 3973: vattr_null(&vattr);
1.35 cgd 3974: vattr.va_size = SCARG(uap, length);
1.332 pooka 3975: error = VOP_SETATTR(vp, &vattr, fp->f_cred);
1.31 cgd 3976: }
1.406 hannken 3977: VOP_UNLOCK(vp);
1.135 thorpej 3978: out:
1.346 ad 3979: fd_putfile(SCARG(uap, fd));
1.31 cgd 3980: return (error);
3981: }
3982:
3983: /*
3984: * Sync an open file.
3985: */
3986: /* ARGSUSED */
1.63 christos 3987: int
1.335 dsl 3988: sys_fsync(struct lwp *l, const struct sys_fsync_args *uap, register_t *retval)
1.56 thorpej 3989: {
1.335 dsl 3990: /* {
1.35 cgd 3991: syscallarg(int) fd;
1.335 dsl 3992: } */
1.155 augustss 3993: struct vnode *vp;
1.346 ad 3994: file_t *fp;
1.31 cgd 3995: int error;
3996:
1.346 ad 3997: /* fd_getvnode() will use the descriptor for us */
3998: if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
1.31 cgd 3999: return (error);
1.346 ad 4000: vp = fp->f_data;
1.113 fvdl 4001: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.332 pooka 4002: error = VOP_FSYNC(vp, fp->f_cred, FSYNC_WAIT, 0, 0);
1.406 hannken 4003: VOP_UNLOCK(vp);
1.346 ad 4004: fd_putfile(SCARG(uap, fd));
1.201 thorpej 4005: return (error);
4006: }
4007:
4008: /*
4009: * Sync a range of file data. API modeled after that found in AIX.
4010: *
4011: * FDATASYNC indicates that we need only save enough metadata to be able
4012: * to re-read the written data. Note we duplicate AIX's requirement that
4013: * the file be open for writing.
4014: */
4015: /* ARGSUSED */
4016: int
1.335 dsl 4017: sys_fsync_range(struct lwp *l, const struct sys_fsync_range_args *uap, register_t *retval)
1.201 thorpej 4018: {
1.335 dsl 4019: /* {
1.201 thorpej 4020: syscallarg(int) fd;
4021: syscallarg(int) flags;
4022: syscallarg(off_t) start;
1.225 cube 4023: syscallarg(off_t) length;
1.335 dsl 4024: } */
1.201 thorpej 4025: struct vnode *vp;
1.346 ad 4026: file_t *fp;
1.201 thorpej 4027: int flags, nflags;
4028: off_t s, e, len;
4029: int error;
4030:
1.346 ad 4031: /* fd_getvnode() will use the descriptor for us */
4032: if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
1.201 thorpej 4033: return (error);
4034:
4035: if ((fp->f_flag & FWRITE) == 0) {
1.293 wrstuden 4036: error = EBADF;
4037: goto out;
1.201 thorpej 4038: }
4039:
4040: flags = SCARG(uap, flags);
4041: if (((flags & (FDATASYNC | FFILESYNC)) == 0) ||
4042: ((~flags & (FDATASYNC | FFILESYNC)) == 0)) {
1.293 wrstuden 4043: error = EINVAL;
4044: goto out;
1.201 thorpej 4045: }
4046: /* Now set up the flags for value(s) to pass to VOP_FSYNC() */
4047: if (flags & FDATASYNC)
4048: nflags = FSYNC_DATAONLY | FSYNC_WAIT;
4049: else
4050: nflags = FSYNC_WAIT;
1.216 wrstuden 4051: if (flags & FDISKSYNC)
4052: nflags |= FSYNC_CACHE;
1.201 thorpej 4053:
4054: len = SCARG(uap, length);
1.424 dsl 4055: /* If length == 0, we do the whole file, and s = e = 0 will do that */
1.201 thorpej 4056: if (len) {
4057: s = SCARG(uap, start);
4058: e = s + len;
4059: if (e < s) {
1.293 wrstuden 4060: error = EINVAL;
4061: goto out;
1.201 thorpej 4062: }
4063: } else {
4064: e = 0;
4065: s = 0;
4066: }
4067:
1.346 ad 4068: vp = fp->f_data;
1.201 thorpej 4069: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.332 pooka 4070: error = VOP_FSYNC(vp, fp->f_cred, nflags, s, e);
1.406 hannken 4071: VOP_UNLOCK(vp);
1.293 wrstuden 4072: out:
1.346 ad 4073: fd_putfile(SCARG(uap, fd));
1.31 cgd 4074: return (error);
4075: }
4076:
4077: /*
1.117 kleink 4078: * Sync the data of an open file.
4079: */
4080: /* ARGSUSED */
4081: int
1.335 dsl 4082: sys_fdatasync(struct lwp *l, const struct sys_fdatasync_args *uap, register_t *retval)
1.117 kleink 4083: {
1.335 dsl 4084: /* {
1.117 kleink 4085: syscallarg(int) fd;
1.335 dsl 4086: } */
1.117 kleink 4087: struct vnode *vp;
1.346 ad 4088: file_t *fp;
1.117 kleink 4089: int error;
4090:
1.346 ad 4091: /* fd_getvnode() will use the descriptor for us */
4092: if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
1.117 kleink 4093: return (error);
1.199 kleink 4094: if ((fp->f_flag & FWRITE) == 0) {
1.346 ad 4095: fd_putfile(SCARG(uap, fd));
1.199 kleink 4096: return (EBADF);
4097: }
1.346 ad 4098: vp = fp->f_data;
1.117 kleink 4099: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.332 pooka 4100: error = VOP_FSYNC(vp, fp->f_cred, FSYNC_WAIT|FSYNC_DATAONLY, 0, 0);
1.406 hannken 4101: VOP_UNLOCK(vp);
1.346 ad 4102: fd_putfile(SCARG(uap, fd));
1.117 kleink 4103: return (error);
4104: }
4105:
4106: /*
1.90 kleink 4107: * Rename files, (standard) BSD semantics frontend.
1.31 cgd 4108: */
4109: /* ARGSUSED */
1.63 christos 4110: int
1.335 dsl 4111: sys_rename(struct lwp *l, const struct sys_rename_args *uap, register_t *retval)
1.56 thorpej 4112: {
1.335 dsl 4113: /* {
1.74 cgd 4114: syscallarg(const char *) from;
4115: syscallarg(const char *) to;
1.335 dsl 4116: } */
1.90 kleink 4117:
1.460 manu 4118: return (do_sys_renameat(l, AT_FDCWD, SCARG(uap, from), AT_FDCWD,
4119: SCARG(uap, to), UIO_USERSPACE, 0));
1.90 kleink 4120: }
4121:
1.433 manu 4122: int
4123: sys_renameat(struct lwp *l, const struct sys_renameat_args *uap,
4124: register_t *retval)
4125: {
4126: /* {
4127: syscallarg(int) fromfd;
4128: syscallarg(const char *) from;
4129: syscallarg(int) tofd;
4130: syscallarg(const char *) to;
4131: } */
4132:
1.460 manu 4133: return (do_sys_renameat(l, SCARG(uap, fromfd), SCARG(uap, from),
4134: SCARG(uap, tofd), SCARG(uap, to), UIO_USERSPACE, 0));
1.433 manu 4135: }
4136:
1.90 kleink 4137: /*
4138: * Rename files, POSIX semantics frontend.
4139: */
4140: /* ARGSUSED */
4141: int
1.335 dsl 4142: sys___posix_rename(struct lwp *l, const struct sys___posix_rename_args *uap, register_t *retval)
1.90 kleink 4143: {
1.335 dsl 4144: /* {
1.90 kleink 4145: syscallarg(const char *) from;
4146: syscallarg(const char *) to;
1.335 dsl 4147: } */
1.90 kleink 4148:
1.460 manu 4149: return (do_sys_renameat(l, AT_FDCWD, SCARG(uap, from), AT_FDCWD,
4150: SCARG(uap, to), UIO_USERSPACE, 1));
1.90 kleink 4151: }
4152:
4153: /*
4154: * Rename files. Source and destination must either both be directories,
4155: * or both not be directories. If target is a directory, it must be empty.
4156: * If `from' and `to' refer to the same object, the value of the `retain'
4157: * argument is used to determine whether `from' will be
4158: *
4159: * (retain == 0) deleted unless `from' and `to' refer to the same
4160: * object in the file system's name space (BSD).
4161: * (retain == 1) always retained (POSIX).
1.458 riastrad 4162: *
4163: * XXX Synchronize with nfsrv_rename in nfs_serv.c.
1.90 kleink 4164: */
1.336 ad 4165: int
4166: do_sys_rename(const char *from, const char *to, enum uio_seg seg, int retain)
1.90 kleink 4167: {
1.460 manu 4168: return do_sys_renameat(NULL, AT_FDCWD, from, AT_FDCWD, to, seg, retain);
4169: }
4170:
4171: static int
4172: do_sys_renameat(struct lwp *l, int fromfd, const char *from, int tofd,
4173: const char *to, enum uio_seg seg, int retain)
4174: {
1.458 riastrad 4175: struct pathbuf *fpb, *tpb;
4176: struct nameidata fnd, tnd;
4177: struct vnode *fdvp, *fvp;
4178: struct vnode *tdvp, *tvp;
4179: struct mount *mp, *tmp;
1.31 cgd 4180: int error;
4181:
1.460 manu 4182: KASSERT(l != NULL || (fromfd == AT_FDCWD && tofd == AT_FDCWD));
1.458 riastrad 4183:
4184: error = pathbuf_maybe_copyin(from, seg, &fpb);
4185: if (error)
4186: goto out0;
4187: KASSERT(fpb != NULL);
4188:
4189: error = pathbuf_maybe_copyin(to, seg, &tpb);
4190: if (error)
4191: goto out1;
4192: KASSERT(tpb != NULL);
4193:
4194: /*
4195: * Lookup from.
4196: *
4197: * XXX LOCKPARENT is wrong because we don't actually want it
4198: * locked yet, but (a) namei is insane, and (b) VOP_RENAME is
4199: * insane, so for the time being we need to leave it like this.
4200: */
4201: NDINIT(&fnd, DELETE, (LOCKPARENT | TRYEMULROOT | INRENAME), fpb);
1.460 manu 4202: if ((error = fd_nameiat(l, fromfd, &fnd)) != 0)
1.458 riastrad 4203: goto out2;
4204:
4205: /*
4206: * Pull out the important results of the lookup, fdvp and fvp.
4207: * Of course, fvp is bogus because we're about to unlock fdvp.
4208: */
4209: fdvp = fnd.ni_dvp;
4210: fvp = fnd.ni_vp;
4211: KASSERT(fdvp != NULL);
4212: KASSERT(fvp != NULL);
4213: KASSERT((fdvp == fvp) || (VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE));
4214:
4215: /*
4216: * Make sure neither fdvp nor fvp is locked.
4217: */
4218: if (fdvp != fvp)
4219: VOP_UNLOCK(fdvp);
4220: /* XXX KASSERT(VOP_ISLOCKED(fdvp) != LK_EXCLUSIVE); */
4221: /* XXX KASSERT(VOP_ISLOCKED(fvp) != LK_EXCLUSIVE); */
4222:
4223: /*
4224: * Reject renaming `.' and `..'. Can't do this until after
4225: * namei because we need namei's parsing to find the final
4226: * component name. (namei should just leave us with the final
4227: * component name and not look it up itself, but anyway...)
4228: *
4229: * This was here before because we used to relookup from
4230: * instead of to and relookup requires the caller to check
4231: * this, but now file systems may depend on this check, so we
4232: * must retain it until the file systems are all rototilled.
4233: */
4234: if (((fnd.ni_cnd.cn_namelen == 1) &&
4235: (fnd.ni_cnd.cn_nameptr[0] == '.')) ||
4236: ((fnd.ni_cnd.cn_namelen == 2) &&
4237: (fnd.ni_cnd.cn_nameptr[0] == '.') &&
4238: (fnd.ni_cnd.cn_nameptr[1] == '.'))) {
4239: error = EINVAL; /* XXX EISDIR? */
4240: goto abort0;
1.409 dholland 4241: }
1.458 riastrad 4242:
4243: /*
4244: * Lookup to.
4245: *
4246: * XXX LOCKPARENT is wrong, but...insanity, &c. Also, using
4247: * fvp here to decide whether to add CREATEDIR is a load of
4248: * bollocks because fvp might be the wrong node by now, since
4249: * fdvp is unlocked.
4250: *
4251: * XXX Why not pass CREATEDIR always?
4252: */
4253: NDINIT(&tnd, RENAME,
4254: (LOCKPARENT | NOCACHE | TRYEMULROOT | INRENAME |
4255: ((fvp->v_type == VDIR)? CREATEDIR : 0)),
4256: tpb);
1.460 manu 4257: if ((error = fd_nameiat(l, tofd, &tnd)) != 0)
1.458 riastrad 4258: goto abort0;
4259:
4260: /*
4261: * Pull out the important results of the lookup, tdvp and tvp.
4262: * Of course, tvp is bogus because we're about to unlock tdvp.
4263: */
4264: tdvp = tnd.ni_dvp;
4265: tvp = tnd.ni_vp;
4266: KASSERT(tdvp != NULL);
4267: KASSERT((tdvp == tvp) || (VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE));
4268:
4269: /*
4270: * Make sure neither tdvp nor tvp is locked.
4271: */
4272: if (tdvp != tvp)
4273: VOP_UNLOCK(tdvp);
4274: /* XXX KASSERT(VOP_ISLOCKED(tdvp) != LK_EXCLUSIVE); */
4275: /* XXX KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) != LK_EXCLUSIVE)); */
4276:
4277: /*
4278: * Reject renaming onto `.' or `..'. relookup is unhappy with
4279: * these, which is why we must do this here. Once upon a time
4280: * we relooked up from instead of to, and consequently didn't
4281: * need this check, but now that we relookup to instead of
4282: * from, we need this; and we shall need it forever forward
4283: * until the VOP_RENAME protocol changes, because file systems
4284: * will no doubt begin to depend on this check.
4285: */
4286: if (((tnd.ni_cnd.cn_namelen == 1) &&
4287: (tnd.ni_cnd.cn_nameptr[0] == '.')) ||
4288: ((tnd.ni_cnd.cn_namelen == 2) &&
4289: (tnd.ni_cnd.cn_nameptr[0] == '.') &&
4290: (tnd.ni_cnd.cn_nameptr[1] == '.'))) {
4291: error = EINVAL; /* XXX EISDIR? */
4292: goto abort1;
1.409 dholland 4293: }
4294:
1.458 riastrad 4295: /*
4296: * Get the mount point. If the file system has been unmounted,
4297: * which it may be because we're not holding any vnode locks,
4298: * then v_mount will be NULL. We're not really supposed to
4299: * read v_mount without holding the vnode lock, but since we
4300: * have fdvp referenced, if fdvp->v_mount changes then at worst
4301: * it will be set to NULL, not changed to another mount point.
4302: * And, of course, since it is up to the file system to
4303: * determine the real lock order, we can't lock both fdvp and
4304: * tdvp at the same time.
4305: */
4306: mp = fdvp->v_mount;
4307: if (mp == NULL) {
4308: error = ENOENT;
4309: goto abort1;
1.344 dholland 4310: }
4311:
4312: /*
1.458 riastrad 4313: * Make sure the mount points match. Again, although we don't
4314: * hold any vnode locks, the v_mount fields may change -- but
4315: * at worst they will change to NULL, so this will never become
4316: * a cross-device rename, because we hold vnode references.
1.344 dholland 4317: *
1.458 riastrad 4318: * XXX Because nothing is locked and the compiler may reorder
4319: * things here, unmounting the file system at an inopportune
4320: * moment may cause rename to fail with ENXDEV when it really
4321: * should fail with ENOENT.
1.344 dholland 4322: */
1.458 riastrad 4323: tmp = tdvp->v_mount;
4324: if (tmp == NULL) {
4325: error = ENOENT;
4326: goto abort1;
1.348 dholland 4327: }
1.458 riastrad 4328:
4329: if (mp != tmp) {
4330: error = EXDEV;
4331: goto abort1;
1.344 dholland 4332: }
1.458 riastrad 4333:
4334: /*
4335: * Take the vfs rename lock to avoid cross-directory screw cases.
4336: * Nothing is locked currently, so taking this lock is safe.
4337: */
1.459 riastrad 4338: error = VFS_RENAMELOCK_ENTER(mp);
4339: if (error)
4340: goto abort1;
1.90 kleink 4341:
1.458 riastrad 4342: /*
4343: * Now fdvp, fvp, tdvp, and (if nonnull) tvp are referenced,
4344: * and nothing is locked except for the vfs rename lock.
4345: *
4346: * The next step is a little rain dance to conform to the
4347: * insane lock protocol, even though it does nothing to ward
4348: * off race conditions.
4349: *
4350: * We need tdvp and tvp to be locked. However, because we have
4351: * unlocked tdvp in order to hold no locks while we take the
4352: * vfs rename lock, tvp may be wrong here, and we can't safely
4353: * lock it even if the sensible file systems will just unlock
4354: * it straight away. Consequently, we must lock tdvp and then
4355: * relookup tvp to get it locked.
4356: *
4357: * Finally, because the VOP_RENAME protocol is brain-damaged
4358: * and various file systems insanely depend on the semantics of
4359: * this brain damage, the lookup of to must be the last lookup
4360: * before VOP_RENAME.
4361: */
4362: vn_lock(tdvp, LK_EXCLUSIVE | LK_RETRY);
4363: error = relookup(tdvp, &tnd.ni_vp, &tnd.ni_cnd, 0);
4364: if (error)
4365: goto abort2;
4366:
4367: /*
4368: * Drop the old tvp and pick up the new one -- which might be
4369: * the same, but that doesn't matter to us. After this, tdvp
4370: * and tvp should both be locked.
4371: */
4372: if (tvp != NULL)
4373: vrele(tvp);
4374: tvp = tnd.ni_vp;
4375: KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
4376: KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
4377:
4378: /*
4379: * The old do_sys_rename had various consistency checks here
4380: * involving fvp and tvp. fvp is bogus already here, and tvp
4381: * will become bogus soon in any sensible file system, so the
4382: * only purpose in putting these checks here is to give lip
4383: * service to these screw cases and to acknowledge that they
4384: * exist, not actually to handle them, but here you go
4385: * anyway...
4386: */
4387:
4388: /*
4389: * Acknowledge that directories and non-directories aren't
4390: * suposed to mix.
4391: */
1.31 cgd 4392: if (tvp != NULL) {
1.458 riastrad 4393: if ((fvp->v_type == VDIR) && (tvp->v_type != VDIR)) {
1.31 cgd 4394: error = ENOTDIR;
1.458 riastrad 4395: goto abort3;
4396: } else if ((fvp->v_type != VDIR) && (tvp->v_type == VDIR)) {
1.31 cgd 4397: error = EISDIR;
1.458 riastrad 4398: goto abort3;
1.31 cgd 4399: }
4400: }
1.90 kleink 4401:
1.458 riastrad 4402: /*
4403: * Acknowledge some random screw case, among the dozens that
4404: * might arise.
4405: */
4406: if (fvp == tdvp) {
1.31 cgd 4407: error = EINVAL;
1.458 riastrad 4408: goto abort3;
4409: }
1.90 kleink 4410:
1.82 kleink 4411: /*
1.458 riastrad 4412: * Acknowledge that POSIX has a wacky screw case.
4413: *
4414: * XXX Eventually the retain flag needs to be passed on to
4415: * VOP_RENAME.
1.82 kleink 4416: */
1.90 kleink 4417: if (fvp == tvp) {
1.458 riastrad 4418: if (retain) {
4419: error = 0;
4420: goto abort3;
4421: } else if ((fdvp == tdvp) &&
4422: (fnd.ni_cnd.cn_namelen == tnd.ni_cnd.cn_namelen) &&
4423: (0 == memcmp(fnd.ni_cnd.cn_nameptr, tnd.ni_cnd.cn_nameptr,
4424: fnd.ni_cnd.cn_namelen))) {
4425: error = 0;
4426: goto abort3;
4427: }
1.90 kleink 4428: }
1.458 riastrad 4429:
1.419 yamt 4430: /*
1.458 riastrad 4431: * Make sure veriexec can screw us up. (But a race can screw
4432: * up veriexec, of course -- remember, fvp and (soon) tvp are
4433: * bogus.)
1.419 yamt 4434: */
1.256 elad 4435: #if NVERIEXEC > 0
1.458 riastrad 4436: {
1.313 elad 4437: char *f1, *f2;
1.384 yamt 4438: size_t f1_len;
4439: size_t f2_len;
1.313 elad 4440:
1.458 riastrad 4441: f1_len = fnd.ni_cnd.cn_namelen + 1;
1.384 yamt 4442: f1 = kmem_alloc(f1_len, KM_SLEEP);
1.458 riastrad 4443: strlcpy(f1, fnd.ni_cnd.cn_nameptr, f1_len);
1.384 yamt 4444:
1.458 riastrad 4445: f2_len = tnd.ni_cnd.cn_namelen + 1;
1.384 yamt 4446: f2 = kmem_alloc(f2_len, KM_SLEEP);
1.458 riastrad 4447: strlcpy(f2, tnd.ni_cnd.cn_nameptr, f2_len);
1.282 elad 4448:
1.428 uebayasi 4449: error = veriexec_renamechk(curlwp, fvp, f1, tvp, f2);
1.282 elad 4450:
1.384 yamt 4451: kmem_free(f1, f1_len);
4452: kmem_free(f2, f2_len);
1.458 riastrad 4453:
4454: if (error)
4455: goto abort3;
1.282 elad 4456: }
1.256 elad 4457: #endif /* NVERIEXEC > 0 */
1.229 elad 4458:
1.458 riastrad 4459: /*
4460: * All ready. Incant the rename vop.
4461: */
4462: /* XXX KASSERT(VOP_ISLOCKED(fdvp) != LK_EXCLUSIVE); */
4463: /* XXX KASSERT(VOP_ISLOCKED(fvp) != LK_EXCLUSIVE); */
4464: KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
4465: KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
4466: error = VOP_RENAME(fdvp, fvp, &fnd.ni_cnd, tdvp, tvp, &tnd.ni_cnd);
4467:
4468: /*
4469: * VOP_RENAME releases fdvp, fvp, tdvp, and tvp, and unlocks
4470: * tdvp and tvp. But we can't assert any of that.
4471: */
4472: /* XXX KASSERT(VOP_ISLOCKED(fdvp) != LK_EXCLUSIVE); */
4473: /* XXX KASSERT(VOP_ISLOCKED(fvp) != LK_EXCLUSIVE); */
4474: /* XXX KASSERT(VOP_ISLOCKED(tdvp) != LK_EXCLUSIVE); */
4475: /* XXX KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) != LK_EXCLUSIVE)); */
4476:
4477: /*
4478: * So all we have left to do is to drop the rename lock and
4479: * destroy the pathbufs.
4480: */
1.459 riastrad 4481: VFS_RENAMELOCK_EXIT(mp);
1.458 riastrad 4482: goto out2;
4483:
4484: abort3: if ((tvp != NULL) && (tvp != tdvp))
4485: VOP_UNLOCK(tvp);
4486: abort2: VOP_UNLOCK(tdvp);
1.459 riastrad 4487: VFS_RENAMELOCK_EXIT(mp);
1.458 riastrad 4488: abort1: VOP_ABORTOP(tdvp, &tnd.ni_cnd);
4489: vrele(tdvp);
4490: if (tvp != NULL)
4491: vrele(tvp);
4492: abort0: VOP_ABORTOP(fdvp, &fnd.ni_cnd);
4493: vrele(fdvp);
4494: vrele(fvp);
4495: out2: pathbuf_destroy(tpb);
4496: out1: pathbuf_destroy(fpb);
4497: out0: return error;
1.31 cgd 4498: }
4499:
4500: /*
4501: * Make a directory file.
4502: */
4503: /* ARGSUSED */
1.63 christos 4504: int
1.335 dsl 4505: sys_mkdir(struct lwp *l, const struct sys_mkdir_args *uap, register_t *retval)
1.56 thorpej 4506: {
1.335 dsl 4507: /* {
1.74 cgd 4508: syscallarg(const char *) path;
1.35 cgd 4509: syscallarg(int) mode;
1.335 dsl 4510: } */
1.396 pooka 4511:
1.460 manu 4512: return do_sys_mkdirat(l, AT_FDCWD, SCARG(uap, path),
4513: SCARG(uap, mode), UIO_USERSPACE);
1.396 pooka 4514: }
4515:
4516: int
1.433 manu 4517: sys_mkdirat(struct lwp *l, const struct sys_mkdirat_args *uap,
4518: register_t *retval)
4519: {
4520: /* {
4521: syscallarg(int) fd;
4522: syscallarg(const char *) path;
4523: syscallarg(int) mode;
4524: } */
4525:
1.460 manu 4526: return do_sys_mkdirat(l, SCARG(uap, fd), SCARG(uap, path),
4527: SCARG(uap, mode), UIO_USERSPACE);
1.433 manu 4528: }
4529:
4530:
4531: int
1.399 haad 4532: do_sys_mkdir(const char *path, mode_t mode, enum uio_seg seg)
1.396 pooka 4533: {
1.460 manu 4534: return do_sys_mkdirat(NULL, AT_FDCWD, path, mode, UIO_USERSPACE);
4535: }
4536:
4537: static int
4538: do_sys_mkdirat(struct lwp *l, int fdat, const char *path, mode_t mode,
4539: enum uio_seg seg)
4540: {
1.396 pooka 4541: struct proc *p = curlwp->l_proc;
1.155 augustss 4542: struct vnode *vp;
1.31 cgd 4543: struct vattr vattr;
4544: int error;
1.409 dholland 4545: struct pathbuf *pb;
1.31 cgd 4546: struct nameidata nd;
4547:
1.460 manu 4548: KASSERT(l != NULL || fdat == AT_FDCWD);
4549:
1.409 dholland 4550: /* XXX bollocks, should pass in a pathbuf */
4551: error = pathbuf_maybe_copyin(path, seg, &pb);
4552: if (error) {
4553: return error;
4554: }
4555:
4556: NDINIT(&nd, CREATE, LOCKPARENT | CREATEDIR | TRYEMULROOT, pb);
1.460 manu 4557:
4558: if ((error = fd_nameiat(l, fdat, &nd)) != 0) {
1.409 dholland 4559: pathbuf_destroy(pb);
1.31 cgd 4560: return (error);
1.409 dholland 4561: }
1.31 cgd 4562: vp = nd.ni_vp;
4563: if (vp != NULL) {
4564: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
4565: if (nd.ni_dvp == vp)
4566: vrele(nd.ni_dvp);
4567: else
4568: vput(nd.ni_dvp);
4569: vrele(vp);
1.409 dholland 4570: pathbuf_destroy(pb);
1.31 cgd 4571: return (EEXIST);
4572: }
1.402 pooka 4573: vattr_null(&vattr);
1.31 cgd 4574: vattr.va_type = VDIR;
1.328 ad 4575: /* We will read cwdi->cwdi_cmask unlocked. */
1.396 pooka 4576: vattr.va_mode = (mode & ACCESSPERMS) &~ p->p_cwdi->cwdi_cmask;
1.31 cgd 4577: error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
4578: if (!error)
1.473 hannken 4579: vrele(nd.ni_vp);
1.472 hannken 4580: vput(nd.ni_dvp);
1.409 dholland 4581: pathbuf_destroy(pb);
1.31 cgd 4582: return (error);
4583: }
4584:
4585: /*
4586: * Remove a directory file.
4587: */
4588: /* ARGSUSED */
1.63 christos 4589: int
1.335 dsl 4590: sys_rmdir(struct lwp *l, const struct sys_rmdir_args *uap, register_t *retval)
1.56 thorpej 4591: {
1.460 manu 4592: return do_sys_unlinkat(l, AT_FDCWD, SCARG(uap, path),
4593: AT_REMOVEDIR, UIO_USERSPACE);
1.31 cgd 4594: }
4595:
4596: /*
4597: * Read a block of directory entries in a file system independent format.
4598: */
1.63 christos 4599: int
1.335 dsl 4600: sys___getdents30(struct lwp *l, const struct sys___getdents30_args *uap, register_t *retval)
1.56 thorpej 4601: {
1.335 dsl 4602: /* {
1.35 cgd 4603: syscallarg(int) fd;
4604: syscallarg(char *) buf;
1.101 fvdl 4605: syscallarg(size_t) count;
1.335 dsl 4606: } */
1.346 ad 4607: file_t *fp;
1.101 fvdl 4608: int error, done;
1.31 cgd 4609:
1.346 ad 4610: /* fd_getvnode() will use the descriptor for us */
4611: if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
1.31 cgd 4612: return (error);
1.135 thorpej 4613: if ((fp->f_flag & FREAD) == 0) {
4614: error = EBADF;
4615: goto out;
4616: }
1.101 fvdl 4617: error = vn_readdir(fp, SCARG(uap, buf), UIO_USERSPACE,
1.234 christos 4618: SCARG(uap, count), &done, l, 0, 0);
1.325 ad 4619: ktrgenio(SCARG(uap, fd), UIO_READ, SCARG(uap, buf), done, error);
1.101 fvdl 4620: *retval = done;
1.135 thorpej 4621: out:
1.346 ad 4622: fd_putfile(SCARG(uap, fd));
1.31 cgd 4623: return (error);
4624: }
4625:
4626: /*
4627: * Set the mode mask for creation of filesystem nodes.
4628: */
1.56 thorpej 4629: int
1.335 dsl 4630: sys_umask(struct lwp *l, const struct sys_umask_args *uap, register_t *retval)
1.56 thorpej 4631: {
1.335 dsl 4632: /* {
1.103 mycroft 4633: syscallarg(mode_t) newmask;
1.335 dsl 4634: } */
1.179 thorpej 4635: struct proc *p = l->l_proc;
1.134 thorpej 4636: struct cwdinfo *cwdi;
1.31 cgd 4637:
1.328 ad 4638: /*
4639: * cwdi->cwdi_cmask will be read unlocked elsewhere. What's
4640: * important is that we serialize changes to the mask. The
4641: * rw_exit() will issue a write memory barrier on our behalf,
4642: * and force the changes out to other CPUs (as it must use an
4643: * atomic operation, draining the local CPU's store buffers).
4644: */
1.134 thorpej 4645: cwdi = p->p_cwdi;
1.328 ad 4646: rw_enter(&cwdi->cwdi_lock, RW_WRITER);
1.134 thorpej 4647: *retval = cwdi->cwdi_cmask;
4648: cwdi->cwdi_cmask = SCARG(uap, newmask) & ALLPERMS;
1.328 ad 4649: rw_exit(&cwdi->cwdi_lock);
4650:
1.31 cgd 4651: return (0);
4652: }
4653:
1.340 elad 4654: int
4655: dorevoke(struct vnode *vp, kauth_cred_t cred)
4656: {
4657: struct vattr vattr;
1.450 elad 4658: int error, fs_decision;
1.340 elad 4659:
1.440 hannken 4660: vn_lock(vp, LK_SHARED | LK_RETRY);
4661: error = VOP_GETATTR(vp, &vattr, cred);
4662: VOP_UNLOCK(vp);
4663: if (error != 0)
1.342 ad 4664: return error;
1.450 elad 4665: fs_decision = (kauth_cred_geteuid(cred) == vattr.va_uid) ? 0 : EPERM;
4666: error = kauth_authorize_vnode(cred, KAUTH_VNODE_REVOKE, vp, NULL,
4667: fs_decision);
4668: if (!error)
1.340 elad 4669: VOP_REVOKE(vp, REVOKEALL);
4670: return (error);
4671: }
4672:
1.31 cgd 4673: /*
4674: * Void all references to file by ripping underlying filesystem
4675: * away from vnode.
4676: */
4677: /* ARGSUSED */
1.63 christos 4678: int
1.335 dsl 4679: sys_revoke(struct lwp *l, const struct sys_revoke_args *uap, register_t *retval)
1.56 thorpej 4680: {
1.335 dsl 4681: /* {
1.74 cgd 4682: syscallarg(const char *) path;
1.335 dsl 4683: } */
1.155 augustss 4684: struct vnode *vp;
1.31 cgd 4685: int error;
4686:
1.395 dholland 4687: error = namei_simple_user(SCARG(uap, path),
4688: NSM_FOLLOW_TRYEMULROOT, &vp);
4689: if (error != 0)
1.31 cgd 4690: return (error);
1.340 elad 4691: error = dorevoke(vp, l->l_cred);
1.31 cgd 4692: vrele(vp);
4693: return (error);
4694: }
CVSweb <webmaster@jp.NetBSD.org>