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