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