1 /* $OpenBSD: vfs_syscalls.c,v 1.360 2022/08/14 01:58:28 jsg Exp $ */ 2 /* $NetBSD: vfs_syscalls.c,v 1.71 1996/04/23 10:29:02 mycroft Exp $ */ 3 4 /* 5 * Copyright (c) 1989, 1993 6 * The Regents of the University of California. All rights reserved. 7 * (c) UNIX System Laboratories, Inc. 8 * All or some portions of this file are derived from material licensed 9 * to the University of California by American Telephone and Telegraph 10 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 11 * the permission of UNIX System Laboratories, Inc. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * @(#)vfs_syscalls.c 8.28 (Berkeley) 12/10/94 38 */ 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/namei.h> 43 #include <sys/filedesc.h> 44 #include <sys/conf.h> 45 #include <sys/fcntl.h> 46 #include <sys/file.h> 47 #include <sys/stat.h> 48 #include <sys/lock.h> 49 #include <sys/vnode.h> 50 #include <sys/mount.h> 51 #include <sys/proc.h> 52 #include <sys/pledge.h> 53 #include <sys/uio.h> 54 #include <sys/malloc.h> 55 #include <sys/pool.h> 56 #include <sys/ktrace.h> 57 #include <sys/unistd.h> 58 #include <sys/specdev.h> 59 #include <sys/resourcevar.h> 60 #include <sys/signalvar.h> 61 62 #include <sys/syscallargs.h> 63 64 extern int suid_clear; 65 66 static int change_dir(struct nameidata *, struct proc *); 67 68 void checkdirs(struct vnode *); 69 70 int copyout_statfs(struct statfs *, void *, struct proc *); 71 72 int doopenat(struct proc *, int, const char *, int, mode_t, register_t *); 73 int domknodat(struct proc *, int, const char *, mode_t, dev_t); 74 int dolinkat(struct proc *, int, const char *, int, const char *, int); 75 int dosymlinkat(struct proc *, const char *, int, const char *); 76 int dounlinkat(struct proc *, int, const char *, int); 77 int dofaccessat(struct proc *, int, const char *, int, int); 78 int dofstatat(struct proc *, int, const char *, struct stat *, int); 79 int doreadlinkat(struct proc *, int, const char *, char *, size_t, 80 register_t *); 81 int dochflagsat(struct proc *, int, const char *, u_int, int); 82 int dovchflags(struct proc *, struct vnode *, u_int); 83 int dofchmodat(struct proc *, int, const char *, mode_t, int); 84 int dofchownat(struct proc *, int, const char *, uid_t, gid_t, int); 85 int dorenameat(struct proc *, int, const char *, int, const char *); 86 int domkdirat(struct proc *, int, const char *, mode_t); 87 int doutimensat(struct proc *, int, const char *, struct timespec [2], int); 88 int dovutimens(struct proc *, struct vnode *, struct timespec [2]); 89 int dofutimens(struct proc *, int, struct timespec [2]); 90 int dounmount_leaf(struct mount *, int, struct proc *); 91 92 /* 93 * Virtual File System System Calls 94 */ 95 96 /* 97 * Mount a file system. 98 */ 99 int 100 sys_mount(struct proc *p, void *v, register_t *retval) 101 { 102 struct sys_mount_args /* { 103 syscallarg(const char *) type; 104 syscallarg(const char *) path; 105 syscallarg(int) flags; 106 syscallarg(void *) data; 107 } */ *uap = v; 108 struct vnode *vp; 109 struct mount *mp; 110 int error, mntflag = 0; 111 char fstypename[MFSNAMELEN]; 112 char fspath[MNAMELEN]; 113 struct nameidata nd; 114 struct vfsconf *vfsp; 115 int flags = SCARG(uap, flags); 116 void *args = NULL; 117 118 if ((error = suser(p))) 119 return (error); 120 121 /* 122 * Mount points must fit in MNAMELEN, not MAXPATHLEN. 123 */ 124 error = copyinstr(SCARG(uap, path), fspath, MNAMELEN, NULL); 125 if (error) 126 return(error); 127 128 /* 129 * Get vnode to be covered 130 */ 131 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspath, p); 132 if ((error = namei(&nd)) != 0) 133 goto fail; 134 vp = nd.ni_vp; 135 if (flags & MNT_UPDATE) { 136 if ((vp->v_flag & VROOT) == 0) { 137 vput(vp); 138 error = EINVAL; 139 goto fail; 140 } 141 mp = vp->v_mount; 142 vfsp = mp->mnt_vfc; 143 144 args = malloc(vfsp->vfc_datasize, M_TEMP, M_WAITOK | M_ZERO); 145 error = copyin(SCARG(uap, data), args, vfsp->vfc_datasize); 146 if (error) { 147 vput(vp); 148 goto fail; 149 } 150 151 mntflag = mp->mnt_flag; 152 /* 153 * We only allow the filesystem to be reloaded if it 154 * is currently mounted read-only. 155 */ 156 if ((flags & MNT_RELOAD) && 157 ((mp->mnt_flag & MNT_RDONLY) == 0)) { 158 vput(vp); 159 error = EOPNOTSUPP; /* Needs translation */ 160 goto fail; 161 } 162 163 if ((error = vfs_busy(mp, VB_READ|VB_NOWAIT)) != 0) { 164 vput(vp); 165 goto fail; 166 } 167 mp->mnt_flag |= flags & (MNT_RELOAD | MNT_UPDATE); 168 goto update; 169 } 170 /* 171 * Do not allow disabling of permission checks unless exec and access to 172 * device files is disabled too. 173 */ 174 if ((flags & MNT_NOPERM) && 175 (flags & (MNT_NODEV | MNT_NOEXEC)) != (MNT_NODEV | MNT_NOEXEC)) { 176 vput(vp); 177 error = EPERM; 178 goto fail; 179 } 180 if ((error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, INFSLP)) != 0) { 181 vput(vp); 182 goto fail; 183 } 184 if (vp->v_type != VDIR) { 185 vput(vp); 186 goto fail; 187 } 188 error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL); 189 if (error) { 190 vput(vp); 191 goto fail; 192 } 193 vfsp = vfs_byname(fstypename); 194 if (vfsp == NULL) { 195 vput(vp); 196 error = EOPNOTSUPP; 197 goto fail; 198 } 199 200 args = malloc(vfsp->vfc_datasize, M_TEMP, M_WAITOK | M_ZERO); 201 error = copyin(SCARG(uap, data), args, vfsp->vfc_datasize); 202 if (error) { 203 vput(vp); 204 goto fail; 205 } 206 207 if (vp->v_mountedhere != NULL) { 208 vput(vp); 209 error = EBUSY; 210 goto fail; 211 } 212 213 /* 214 * Allocate and initialize the file system. 215 */ 216 mp = vfs_mount_alloc(vp, vfsp); 217 mp->mnt_stat.f_owner = p->p_ucred->cr_uid; 218 219 update: 220 /* Ensure that the parent mountpoint does not get unmounted. */ 221 error = vfs_busy(vp->v_mount, VB_READ|VB_NOWAIT|VB_DUPOK); 222 if (error) { 223 if (mp->mnt_flag & MNT_UPDATE) { 224 mp->mnt_flag = mntflag; 225 vfs_unbusy(mp); 226 } else { 227 vfs_unbusy(mp); 228 vfs_mount_free(mp); 229 } 230 vput(vp); 231 goto fail; 232 } 233 234 /* 235 * Set the mount level flags. 236 */ 237 if (flags & MNT_RDONLY) 238 mp->mnt_flag |= MNT_RDONLY; 239 else if (mp->mnt_flag & MNT_RDONLY) 240 mp->mnt_flag |= MNT_WANTRDWR; 241 mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_WXALLOWED | MNT_NODEV | 242 MNT_SYNCHRONOUS | MNT_ASYNC | MNT_SOFTDEP | MNT_NOATIME | 243 MNT_NOPERM | MNT_FORCE); 244 mp->mnt_flag |= flags & (MNT_NOSUID | MNT_NOEXEC | MNT_WXALLOWED | 245 MNT_NODEV | MNT_SYNCHRONOUS | MNT_ASYNC | MNT_SOFTDEP | 246 MNT_NOATIME | MNT_NOPERM | MNT_FORCE); 247 /* 248 * Mount the filesystem. 249 */ 250 error = VFS_MOUNT(mp, fspath, args, &nd, p); 251 if (!error) { 252 mp->mnt_stat.f_ctime = gettime(); 253 } 254 if (mp->mnt_flag & MNT_UPDATE) { 255 vfs_unbusy(vp->v_mount); 256 vput(vp); 257 if (mp->mnt_flag & MNT_WANTRDWR) 258 mp->mnt_flag &= ~MNT_RDONLY; 259 mp->mnt_flag &= ~MNT_OP_FLAGS; 260 if (error) 261 mp->mnt_flag = mntflag; 262 263 if ((mp->mnt_flag & MNT_RDONLY) == 0) { 264 if (mp->mnt_syncer == NULL) 265 error = vfs_allocate_syncvnode(mp); 266 } else { 267 if (mp->mnt_syncer != NULL) 268 vgone(mp->mnt_syncer); 269 mp->mnt_syncer = NULL; 270 } 271 272 vfs_unbusy(mp); 273 goto fail; 274 } 275 276 mp->mnt_flag &= ~MNT_OP_FLAGS; 277 vp->v_mountedhere = mp; 278 279 /* 280 * Put the new filesystem on the mount list after root. 281 */ 282 cache_purge(vp); 283 if (!error) { 284 TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); 285 checkdirs(vp); 286 vfs_unbusy(vp->v_mount); 287 VOP_UNLOCK(vp); 288 if ((mp->mnt_flag & MNT_RDONLY) == 0) 289 error = vfs_allocate_syncvnode(mp); 290 vfs_unbusy(mp); 291 (void) VFS_STATFS(mp, &mp->mnt_stat, p); 292 if ((error = VFS_START(mp, 0, p)) != 0) 293 vrele(vp); 294 } else { 295 mp->mnt_vnodecovered->v_mountedhere = NULL; 296 vfs_unbusy(mp); 297 vfs_mount_free(mp); 298 vfs_unbusy(vp->v_mount); 299 vput(vp); 300 } 301 fail: 302 if (args) 303 free(args, M_TEMP, vfsp->vfc_datasize); 304 return (error); 305 } 306 307 /* 308 * Scan all active processes to see if any of them have a current 309 * or root directory onto which the new filesystem has just been 310 * mounted. If so, replace them with the new mount point, keeping 311 * track of how many were replaced. That's the number of references 312 * the old vnode had that we've replaced, so finish by vrele()'ing 313 * it that many times. This puts off any possible sleeping until 314 * we've finished walking the allprocess list. 315 */ 316 void 317 checkdirs(struct vnode *olddp) 318 { 319 struct filedesc *fdp; 320 struct vnode *newdp; 321 struct process *pr; 322 u_int free_count = 0; 323 324 if (olddp->v_usecount == 1) 325 return; 326 if (VFS_ROOT(olddp->v_mountedhere, &newdp)) 327 panic("mount: lost mount"); 328 LIST_FOREACH(pr, &allprocess, ps_list) { 329 fdp = pr->ps_fd; 330 if (fdp->fd_cdir == olddp) { 331 free_count++; 332 vref(newdp); 333 fdp->fd_cdir = newdp; 334 } 335 if (fdp->fd_rdir == olddp) { 336 free_count++; 337 vref(newdp); 338 fdp->fd_rdir = newdp; 339 } 340 } 341 if (rootvnode == olddp) { 342 free_count++; 343 vref(newdp); 344 rootvnode = newdp; 345 } 346 while (free_count-- > 0) 347 vrele(olddp); 348 vput(newdp); 349 } 350 351 /* 352 * Unmount a file system. 353 * 354 * Note: unmount takes a path to the vnode mounted on as argument, 355 * not special file (as before). 356 */ 357 int 358 sys_unmount(struct proc *p, void *v, register_t *retval) 359 { 360 struct sys_unmount_args /* { 361 syscallarg(const char *) path; 362 syscallarg(int) flags; 363 } */ *uap = v; 364 struct vnode *vp; 365 struct mount *mp; 366 int error; 367 struct nameidata nd; 368 369 if ((error = suser(p)) != 0) 370 return (error); 371 372 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 373 SCARG(uap, path), p); 374 if ((error = namei(&nd)) != 0) 375 return (error); 376 vp = nd.ni_vp; 377 mp = vp->v_mount; 378 379 /* 380 * Don't allow unmounting the root file system. 381 */ 382 if (mp->mnt_flag & MNT_ROOTFS) { 383 vput(vp); 384 return (EINVAL); 385 } 386 387 /* 388 * Must be the root of the filesystem 389 */ 390 if ((vp->v_flag & VROOT) == 0) { 391 vput(vp); 392 return (EINVAL); 393 } 394 vput(vp); 395 396 if (vfs_busy(mp, VB_WRITE|VB_WAIT)) 397 return (EBUSY); 398 399 return (dounmount(mp, SCARG(uap, flags) & MNT_FORCE, p)); 400 } 401 402 /* 403 * Do the actual file system unmount. 404 */ 405 int 406 dounmount(struct mount *mp, int flags, struct proc *p) 407 { 408 SLIST_HEAD(, mount) mplist; 409 struct mount *nmp; 410 int error; 411 412 SLIST_INIT(&mplist); 413 SLIST_INSERT_HEAD(&mplist, mp, mnt_dounmount); 414 415 /* 416 * Collect nested mount points. This takes advantage of the mount list 417 * being ordered - nested mount points come after their parent. 418 */ 419 while ((mp = TAILQ_NEXT(mp, mnt_list)) != NULL) { 420 SLIST_FOREACH(nmp, &mplist, mnt_dounmount) { 421 if (mp->mnt_vnodecovered == NULLVP || 422 mp->mnt_vnodecovered->v_mount != nmp) 423 continue; 424 425 if ((flags & MNT_FORCE) == 0) { 426 error = EBUSY; 427 goto err; 428 } 429 error = vfs_busy(mp, VB_WRITE|VB_WAIT|VB_DUPOK); 430 if (error) { 431 if ((flags & MNT_DOOMED)) { 432 /* 433 * If the mount point was busy due to 434 * being unmounted, it has been removed 435 * from the mount list already. 436 * Restart the iteration from the last 437 * collected busy entry. 438 */ 439 mp = SLIST_FIRST(&mplist); 440 break; 441 } 442 goto err; 443 } 444 SLIST_INSERT_HEAD(&mplist, mp, mnt_dounmount); 445 break; 446 } 447 } 448 449 /* 450 * Nested mount points cannot appear during this loop as mounting 451 * requires a read lock for the parent mount point. 452 */ 453 while ((mp = SLIST_FIRST(&mplist)) != NULL) { 454 SLIST_REMOVE(&mplist, mp, mount, mnt_dounmount); 455 error = dounmount_leaf(mp, flags, p); 456 if (error) 457 goto err; 458 } 459 return (0); 460 461 err: 462 while ((mp = SLIST_FIRST(&mplist)) != NULL) { 463 SLIST_REMOVE(&mplist, mp, mount, mnt_dounmount); 464 vfs_unbusy(mp); 465 } 466 return (error); 467 } 468 469 int 470 dounmount_leaf(struct mount *mp, int flags, struct proc *p) 471 { 472 struct vnode *coveredvp; 473 struct vnode *vp, *nvp; 474 int error; 475 int hadsyncer = 0; 476 477 mp->mnt_flag &=~ MNT_ASYNC; 478 cache_purgevfs(mp); /* remove cache entries for this file sys */ 479 if (mp->mnt_syncer != NULL) { 480 hadsyncer = 1; 481 vgone(mp->mnt_syncer); 482 mp->mnt_syncer = NULL; 483 } 484 485 /* 486 * Before calling file system unmount, make sure 487 * all unveils to vnodes in here are dropped. 488 */ 489 TAILQ_FOREACH_SAFE(vp , &mp->mnt_vnodelist, v_mntvnodes, nvp) { 490 unveil_removevnode(vp); 491 } 492 493 if (((mp->mnt_flag & MNT_RDONLY) || 494 (error = VFS_SYNC(mp, MNT_WAIT, 0, p->p_ucred, p)) == 0) || 495 (flags & MNT_FORCE)) 496 error = VFS_UNMOUNT(mp, flags, p); 497 498 if (error && !(flags & MNT_DOOMED)) { 499 if ((mp->mnt_flag & MNT_RDONLY) == 0 && hadsyncer) 500 (void) vfs_allocate_syncvnode(mp); 501 vfs_unbusy(mp); 502 return (error); 503 } 504 505 TAILQ_REMOVE(&mountlist, mp, mnt_list); 506 if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) { 507 coveredvp->v_mountedhere = NULL; 508 vrele(coveredvp); 509 } 510 511 if (!TAILQ_EMPTY(&mp->mnt_vnodelist)) 512 panic("unmount: dangling vnode"); 513 514 vfs_unbusy(mp); 515 vfs_mount_free(mp); 516 517 return (0); 518 } 519 520 /* 521 * Sync each mounted filesystem. 522 */ 523 int 524 sys_sync(struct proc *p, void *v, register_t *retval) 525 { 526 struct mount *mp; 527 int asyncflag; 528 529 TAILQ_FOREACH_REVERSE(mp, &mountlist, mntlist, mnt_list) { 530 if (vfs_busy(mp, VB_READ|VB_NOWAIT)) 531 continue; 532 if ((mp->mnt_flag & MNT_RDONLY) == 0) { 533 asyncflag = mp->mnt_flag & MNT_ASYNC; 534 mp->mnt_flag &= ~MNT_ASYNC; 535 uvm_vnp_sync(mp); 536 VFS_SYNC(mp, MNT_NOWAIT, 0, p->p_ucred, p); 537 if (asyncflag) 538 mp->mnt_flag |= MNT_ASYNC; 539 } 540 vfs_unbusy(mp); 541 } 542 543 return (0); 544 } 545 546 /* 547 * Change filesystem quotas. 548 */ 549 int 550 sys_quotactl(struct proc *p, void *v, register_t *retval) 551 { 552 struct sys_quotactl_args /* { 553 syscallarg(const char *) path; 554 syscallarg(int) cmd; 555 syscallarg(int) uid; 556 syscallarg(char *) arg; 557 } */ *uap = v; 558 struct mount *mp; 559 int error; 560 struct nameidata nd; 561 562 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 563 if ((error = namei(&nd)) != 0) 564 return (error); 565 mp = nd.ni_vp->v_mount; 566 vrele(nd.ni_vp); 567 return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid), 568 SCARG(uap, arg), p)); 569 } 570 571 int 572 copyout_statfs(struct statfs *sp, void *uaddr, struct proc *p) 573 { 574 size_t co_sz1 = offsetof(struct statfs, f_fsid); 575 size_t co_off2 = co_sz1 + sizeof(fsid_t); 576 size_t co_sz2 = sizeof(struct statfs) - co_off2; 577 char *s, *d; 578 int error; 579 580 /* Don't let non-root see filesystem id (for NFS security) */ 581 if (suser(p)) { 582 fsid_t fsid; 583 584 s = (char *)sp; 585 d = (char *)uaddr; 586 587 memset(&fsid, 0, sizeof(fsid)); 588 589 if ((error = copyout(s, d, co_sz1)) != 0) 590 return (error); 591 if ((error = copyout(&fsid, d + co_sz1, sizeof(fsid))) != 0) 592 return (error); 593 return (copyout(s + co_off2, d + co_off2, co_sz2)); 594 } 595 596 return (copyout(sp, uaddr, sizeof(*sp))); 597 } 598 599 /* 600 * Get filesystem statistics. 601 */ 602 int 603 sys_statfs(struct proc *p, void *v, register_t *retval) 604 { 605 struct sys_statfs_args /* { 606 syscallarg(const char *) path; 607 syscallarg(struct statfs *) buf; 608 } */ *uap = v; 609 struct mount *mp; 610 struct statfs *sp; 611 int error; 612 struct nameidata nd; 613 614 NDINIT(&nd, LOOKUP, FOLLOW | BYPASSUNVEIL, UIO_USERSPACE, 615 SCARG(uap, path), p); 616 nd.ni_pledge = PLEDGE_RPATH; 617 nd.ni_unveil = UNVEIL_READ; 618 if ((error = namei(&nd)) != 0) 619 return (error); 620 mp = nd.ni_vp->v_mount; 621 sp = &mp->mnt_stat; 622 vrele(nd.ni_vp); 623 if ((error = VFS_STATFS(mp, sp, p)) != 0) 624 return (error); 625 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 626 627 return (copyout_statfs(sp, SCARG(uap, buf), p)); 628 } 629 630 /* 631 * Get filesystem statistics. 632 */ 633 int 634 sys_fstatfs(struct proc *p, void *v, register_t *retval) 635 { 636 struct sys_fstatfs_args /* { 637 syscallarg(int) fd; 638 syscallarg(struct statfs *) buf; 639 } */ *uap = v; 640 struct file *fp; 641 struct mount *mp; 642 struct statfs *sp; 643 int error; 644 645 if ((error = getvnode(p, SCARG(uap, fd), &fp)) != 0) 646 return (error); 647 mp = ((struct vnode *)fp->f_data)->v_mount; 648 if (!mp) { 649 FRELE(fp, p); 650 return (ENOENT); 651 } 652 sp = &mp->mnt_stat; 653 error = VFS_STATFS(mp, sp, p); 654 FRELE(fp, p); 655 if (error) 656 return (error); 657 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 658 659 return (copyout_statfs(sp, SCARG(uap, buf), p)); 660 } 661 662 /* 663 * Get statistics on all filesystems. 664 */ 665 int 666 sys_getfsstat(struct proc *p, void *v, register_t *retval) 667 { 668 struct sys_getfsstat_args /* { 669 syscallarg(struct statfs *) buf; 670 syscallarg(size_t) bufsize; 671 syscallarg(int) flags; 672 } */ *uap = v; 673 struct mount *mp; 674 struct statfs *sp; 675 struct statfs *sfsp; 676 size_t count, maxcount; 677 int error, flags = SCARG(uap, flags); 678 679 maxcount = SCARG(uap, bufsize) / sizeof(struct statfs); 680 sfsp = SCARG(uap, buf); 681 count = 0; 682 683 TAILQ_FOREACH(mp, &mountlist, mnt_list) { 684 if (vfs_busy(mp, VB_READ|VB_NOWAIT)) 685 continue; 686 if (sfsp && count < maxcount) { 687 sp = &mp->mnt_stat; 688 689 /* Refresh stats unless MNT_NOWAIT is specified */ 690 if (flags != MNT_NOWAIT && 691 flags != MNT_LAZY && 692 (flags == MNT_WAIT || 693 flags == 0) && 694 (error = VFS_STATFS(mp, sp, p))) { 695 vfs_unbusy(mp); 696 continue; 697 } 698 699 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 700 #if notyet 701 if (mp->mnt_flag & MNT_SOFTDEP) 702 sp->f_eflags = STATFS_SOFTUPD; 703 #endif 704 error = (copyout_statfs(sp, sfsp, p)); 705 if (error) { 706 vfs_unbusy(mp); 707 return (error); 708 } 709 sfsp++; 710 } 711 count++; 712 vfs_unbusy(mp); 713 } 714 715 if (sfsp && count > maxcount) 716 *retval = maxcount; 717 else 718 *retval = count; 719 720 return (0); 721 } 722 723 /* 724 * Change current working directory to a given file descriptor. 725 */ 726 int 727 sys_fchdir(struct proc *p, void *v, register_t *retval) 728 { 729 struct sys_fchdir_args /* { 730 syscallarg(int) fd; 731 } */ *uap = v; 732 struct filedesc *fdp = p->p_fd; 733 struct vnode *vp, *tdp, *old_cdir; 734 struct mount *mp; 735 struct file *fp; 736 int error; 737 738 if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL) 739 return (EBADF); 740 vp = fp->f_data; 741 if (fp->f_type != DTYPE_VNODE || vp->v_type != VDIR) { 742 FRELE(fp, p); 743 return (ENOTDIR); 744 } 745 vref(vp); 746 FRELE(fp, p); 747 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 748 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 749 750 while (!error && (mp = vp->v_mountedhere) != NULL) { 751 if (vfs_busy(mp, VB_READ|VB_WAIT)) 752 continue; 753 error = VFS_ROOT(mp, &tdp); 754 vfs_unbusy(mp); 755 if (error) 756 break; 757 vput(vp); 758 vp = tdp; 759 } 760 if (error) { 761 vput(vp); 762 return (error); 763 } 764 VOP_UNLOCK(vp); 765 old_cdir = fdp->fd_cdir; 766 fdp->fd_cdir = vp; 767 vrele(old_cdir); 768 return (0); 769 } 770 771 /* 772 * Change current working directory (``.''). 773 */ 774 int 775 sys_chdir(struct proc *p, void *v, register_t *retval) 776 { 777 struct sys_chdir_args /* { 778 syscallarg(const char *) path; 779 } */ *uap = v; 780 struct filedesc *fdp = p->p_fd; 781 struct vnode *old_cdir; 782 int error; 783 struct nameidata nd; 784 785 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 786 SCARG(uap, path), p); 787 nd.ni_pledge = PLEDGE_RPATH; 788 nd.ni_unveil = UNVEIL_READ; 789 if ((error = change_dir(&nd, p)) != 0) 790 return (error); 791 old_cdir = fdp->fd_cdir; 792 fdp->fd_cdir = nd.ni_vp; 793 vrele(old_cdir); 794 return (0); 795 } 796 797 /* 798 * Change notion of root (``/'') directory. 799 */ 800 int 801 sys_chroot(struct proc *p, void *v, register_t *retval) 802 { 803 struct sys_chroot_args /* { 804 syscallarg(const char *) path; 805 } */ *uap = v; 806 struct filedesc *fdp = p->p_fd; 807 struct vnode *old_cdir, *old_rdir; 808 int error; 809 struct nameidata nd; 810 811 if ((error = suser(p)) != 0) 812 return (error); 813 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 814 SCARG(uap, path), p); 815 if ((error = change_dir(&nd, p)) != 0) 816 return (error); 817 if (fdp->fd_rdir != NULL) { 818 /* 819 * A chroot() done inside a changed root environment does 820 * an automatic chdir to avoid the out-of-tree experience. 821 */ 822 vref(nd.ni_vp); 823 old_rdir = fdp->fd_rdir; 824 old_cdir = fdp->fd_cdir; 825 fdp->fd_rdir = fdp->fd_cdir = nd.ni_vp; 826 vrele(old_rdir); 827 vrele(old_cdir); 828 } else 829 fdp->fd_rdir = nd.ni_vp; 830 atomic_setbits_int(&p->p_p->ps_flags, PS_CHROOT); 831 return (0); 832 } 833 834 /* 835 * Common routine for chroot and chdir. 836 */ 837 static int 838 change_dir(struct nameidata *ndp, struct proc *p) 839 { 840 struct vnode *vp; 841 int error; 842 843 if ((error = namei(ndp)) != 0) 844 return (error); 845 vp = ndp->ni_vp; 846 if (vp->v_type != VDIR) 847 error = ENOTDIR; 848 else 849 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 850 if (error) 851 vput(vp); 852 else 853 VOP_UNLOCK(vp); 854 return (error); 855 } 856 857 int 858 sys___realpath(struct proc *p, void *v, register_t *retval) 859 { 860 struct sys___realpath_args /* { 861 syscallarg(const char *) pathname; 862 syscallarg(char *) resolved; 863 } */ *uap = v; 864 char *pathname; 865 char *rpbuf; 866 struct nameidata nd; 867 size_t pathlen; 868 int error = 0; 869 870 if (SCARG(uap, pathname) == NULL) 871 return (EINVAL); 872 873 pathname = pool_get(&namei_pool, PR_WAITOK); 874 rpbuf = pool_get(&namei_pool, PR_WAITOK); 875 876 if ((error = copyinstr(SCARG(uap, pathname), pathname, MAXPATHLEN, 877 &pathlen))) 878 goto end; 879 880 if (pathlen == 1) { /* empty string "" */ 881 error = ENOENT; 882 goto end; 883 } 884 if (pathlen < 2) { 885 error = EINVAL; 886 goto end; 887 } 888 889 /* Get cwd for relative path if needed, prepend to rpbuf */ 890 rpbuf[0] = '\0'; 891 if (pathname[0] != '/') { 892 int cwdlen = MAXPATHLEN * 4; /* for vfs_getcwd_common */ 893 char *cwdbuf, *bp; 894 895 cwdbuf = malloc(cwdlen, M_TEMP, M_WAITOK); 896 897 /* vfs_getcwd_common fills this in backwards */ 898 bp = &cwdbuf[cwdlen - 1]; 899 *bp = '\0'; 900 901 error = vfs_getcwd_common(p->p_fd->fd_cdir, NULL, &bp, cwdbuf, 902 cwdlen/2, GETCWD_CHECK_ACCESS, p); 903 904 if (error) { 905 free(cwdbuf, M_TEMP, cwdlen); 906 goto end; 907 } 908 909 if (strlcpy(rpbuf, bp, MAXPATHLEN) >= MAXPATHLEN) { 910 free(cwdbuf, M_TEMP, cwdlen); 911 error = ENAMETOOLONG; 912 goto end; 913 } 914 915 free(cwdbuf, M_TEMP, cwdlen); 916 } 917 918 NDINIT(&nd, LOOKUP, FOLLOW | SAVENAME | REALPATH, UIO_SYSSPACE, 919 pathname, p); 920 921 nd.ni_cnd.cn_rpbuf = rpbuf; 922 nd.ni_cnd.cn_rpi = strlen(rpbuf); 923 924 nd.ni_pledge = PLEDGE_RPATH; 925 nd.ni_unveil = UNVEIL_READ; 926 if ((error = namei(&nd)) != 0) 927 goto end; 928 929 /* release reference from namei */ 930 if (nd.ni_vp) 931 vrele(nd.ni_vp); 932 933 error = copyoutstr(nd.ni_cnd.cn_rpbuf, SCARG(uap, resolved), 934 MAXPATHLEN, NULL); 935 936 #ifdef KTRACE 937 if (KTRPOINT(p, KTR_NAMEI)) 938 ktrnamei(p, nd.ni_cnd.cn_rpbuf); 939 #endif 940 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 941 end: 942 pool_put(&namei_pool, rpbuf); 943 pool_put(&namei_pool, pathname); 944 return (error); 945 } 946 947 int 948 sys_unveil(struct proc *p, void *v, register_t *retval) 949 { 950 struct sys_unveil_args /* { 951 syscallarg(const char *) path; 952 syscallarg(const char *) permissions; 953 } */ *uap = v; 954 struct process *pr = p->p_p; 955 char *pathname, *c; 956 struct nameidata nd; 957 size_t pathlen; 958 char permissions[5]; 959 int error, allow; 960 961 if (SCARG(uap, path) == NULL && SCARG(uap, permissions) == NULL) { 962 pr->ps_uvdone = 1; 963 return (0); 964 } 965 966 if (pr->ps_uvdone != 0) 967 return EPERM; 968 969 error = copyinstr(SCARG(uap, permissions), permissions, 970 sizeof(permissions), NULL); 971 if (error) 972 return (error); 973 pathname = pool_get(&namei_pool, PR_WAITOK); 974 error = copyinstr(SCARG(uap, path), pathname, MAXPATHLEN, &pathlen); 975 if (error) 976 goto end; 977 978 #ifdef KTRACE 979 if (KTRPOINT(p, KTR_STRUCT)) 980 ktrstruct(p, "unveil", permissions, strlen(permissions)); 981 #endif 982 if (pathlen < 2) { 983 error = EINVAL; 984 goto end; 985 } 986 987 /* find root "/" or "//" */ 988 for (c = pathname; *c != '\0'; c++) { 989 if (*c != '/') 990 break; 991 } 992 if (*c == '\0') 993 /* root directory */ 994 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | SAVENAME, 995 UIO_SYSSPACE, pathname, p); 996 else 997 NDINIT(&nd, CREATE, FOLLOW | LOCKLEAF | LOCKPARENT | SAVENAME, 998 UIO_SYSSPACE, pathname, p); 999 1000 nd.ni_pledge = PLEDGE_UNVEIL; 1001 if ((error = namei(&nd)) != 0) 1002 goto end; 1003 1004 /* 1005 * XXX Any access to the file or directory will allow us to 1006 * pledge path it 1007 */ 1008 allow = ((nd.ni_vp && 1009 (VOP_ACCESS(nd.ni_vp, VREAD, p->p_ucred, p) == 0 || 1010 VOP_ACCESS(nd.ni_vp, VWRITE, p->p_ucred, p) == 0 || 1011 VOP_ACCESS(nd.ni_vp, VEXEC, p->p_ucred, p) == 0)) || 1012 (nd.ni_dvp && 1013 (VOP_ACCESS(nd.ni_dvp, VREAD, p->p_ucred, p) == 0 || 1014 VOP_ACCESS(nd.ni_dvp, VWRITE, p->p_ucred, p) == 0 || 1015 VOP_ACCESS(nd.ni_dvp, VEXEC, p->p_ucred, p) == 0))); 1016 1017 /* release lock from namei, but keep ref */ 1018 if (nd.ni_vp) 1019 VOP_UNLOCK(nd.ni_vp); 1020 if (nd.ni_dvp && nd.ni_dvp != nd.ni_vp) 1021 VOP_UNLOCK(nd.ni_dvp); 1022 1023 if (allow) 1024 error = unveil_add(p, &nd, permissions); 1025 else 1026 error = EPERM; 1027 1028 /* release vref from namei, but not vref from unveil_add */ 1029 if (nd.ni_vp) 1030 vrele(nd.ni_vp); 1031 if (nd.ni_dvp) 1032 vrele(nd.ni_dvp); 1033 1034 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1035 end: 1036 pool_put(&namei_pool, pathname); 1037 1038 return (error); 1039 } 1040 1041 /* 1042 * Check permissions, allocate an open file structure, 1043 * and call the device open routine if any. 1044 */ 1045 int 1046 sys_open(struct proc *p, void *v, register_t *retval) 1047 { 1048 struct sys_open_args /* { 1049 syscallarg(const char *) path; 1050 syscallarg(int) flags; 1051 syscallarg(mode_t) mode; 1052 } */ *uap = v; 1053 1054 return (doopenat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, flags), 1055 SCARG(uap, mode), retval)); 1056 } 1057 1058 int 1059 sys_openat(struct proc *p, void *v, register_t *retval) 1060 { 1061 struct sys_openat_args /* { 1062 syscallarg(int) fd; 1063 syscallarg(const char *) path; 1064 syscallarg(int) flags; 1065 syscallarg(mode_t) mode; 1066 } */ *uap = v; 1067 1068 return (doopenat(p, SCARG(uap, fd), SCARG(uap, path), 1069 SCARG(uap, flags), SCARG(uap, mode), retval)); 1070 } 1071 1072 int 1073 doopenat(struct proc *p, int fd, const char *path, int oflags, mode_t mode, 1074 register_t *retval) 1075 { 1076 struct filedesc *fdp = p->p_fd; 1077 struct file *fp; 1078 struct vnode *vp; 1079 struct vattr vattr; 1080 int flags, cloexec, cmode; 1081 int type, indx, error, localtrunc = 0; 1082 struct flock lf; 1083 struct nameidata nd; 1084 uint64_t ni_pledge = 0; 1085 u_char ni_unveil = 0; 1086 1087 if (oflags & (O_EXLOCK | O_SHLOCK)) { 1088 error = pledge_flock(p); 1089 if (error != 0) 1090 return (error); 1091 } 1092 1093 cloexec = (oflags & O_CLOEXEC) ? UF_EXCLOSE : 0; 1094 1095 fdplock(fdp); 1096 if ((error = falloc(p, &fp, &indx)) != 0) { 1097 fdpunlock(fdp); 1098 return (error); 1099 } 1100 fdpunlock(fdp); 1101 1102 flags = FFLAGS(oflags); 1103 if (flags & FREAD) { 1104 ni_pledge |= PLEDGE_RPATH; 1105 ni_unveil |= UNVEIL_READ; 1106 } 1107 if (flags & FWRITE) { 1108 ni_pledge |= PLEDGE_WPATH; 1109 ni_unveil |= UNVEIL_WRITE; 1110 } 1111 if (oflags & O_CREAT) { 1112 ni_pledge |= PLEDGE_CPATH; 1113 ni_unveil |= UNVEIL_CREATE; 1114 } 1115 1116 cmode = ((mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; 1117 if ((p->p_p->ps_flags & PS_PLEDGE)) 1118 cmode &= ACCESSPERMS; 1119 NDINITAT(&nd, 0, 0, UIO_USERSPACE, fd, path, p); 1120 nd.ni_pledge = ni_pledge; 1121 nd.ni_unveil = ni_unveil; 1122 p->p_dupfd = -1; /* XXX check for fdopen */ 1123 if ((flags & O_TRUNC) && (flags & (O_EXLOCK | O_SHLOCK))) { 1124 localtrunc = 1; 1125 flags &= ~O_TRUNC; /* Must do truncate ourselves */ 1126 } 1127 if ((error = vn_open(&nd, flags, cmode)) != 0) { 1128 fdplock(fdp); 1129 if (error == ENODEV && 1130 p->p_dupfd >= 0 && /* XXX from fdopen */ 1131 (error = 1132 dupfdopen(p, indx, flags)) == 0) { 1133 fdpunlock(fdp); 1134 closef(fp, p); 1135 *retval = indx; 1136 return (error); 1137 } 1138 if (error == ERESTART) 1139 error = EINTR; 1140 fdremove(fdp, indx); 1141 fdpunlock(fdp); 1142 closef(fp, p); 1143 return (error); 1144 } 1145 p->p_dupfd = 0; 1146 vp = nd.ni_vp; 1147 fp->f_flag = flags & FMASK; 1148 fp->f_type = DTYPE_VNODE; 1149 fp->f_ops = &vnops; 1150 fp->f_data = vp; 1151 if (flags & (O_EXLOCK | O_SHLOCK)) { 1152 lf.l_whence = SEEK_SET; 1153 lf.l_start = 0; 1154 lf.l_len = 0; 1155 if (flags & O_EXLOCK) 1156 lf.l_type = F_WRLCK; 1157 else 1158 lf.l_type = F_RDLCK; 1159 type = F_FLOCK; 1160 if ((flags & FNONBLOCK) == 0) 1161 type |= F_WAIT; 1162 VOP_UNLOCK(vp); 1163 error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type); 1164 if (error) { 1165 fdplock(fdp); 1166 /* closef will vn_close the file for us. */ 1167 fdremove(fdp, indx); 1168 fdpunlock(fdp); 1169 closef(fp, p); 1170 return (error); 1171 } 1172 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 1173 atomic_setbits_int(&fp->f_iflags, FIF_HASLOCK); 1174 } 1175 if (localtrunc) { 1176 if ((fp->f_flag & FWRITE) == 0) 1177 error = EACCES; 1178 else if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_RDONLY)) 1179 error = EROFS; 1180 else if (vp->v_type == VDIR) 1181 error = EISDIR; 1182 else if ((error = vn_writechk(vp)) == 0) { 1183 VATTR_NULL(&vattr); 1184 vattr.va_size = 0; 1185 error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 1186 } 1187 if (error) { 1188 VOP_UNLOCK(vp); 1189 fdplock(fdp); 1190 /* closef will close the file for us. */ 1191 fdremove(fdp, indx); 1192 fdpunlock(fdp); 1193 closef(fp, p); 1194 return (error); 1195 } 1196 } 1197 VOP_UNLOCK(vp); 1198 *retval = indx; 1199 fdplock(fdp); 1200 fdinsert(fdp, indx, cloexec, fp); 1201 fdpunlock(fdp); 1202 FRELE(fp, p); 1203 return (error); 1204 } 1205 1206 /* 1207 * Open a new created file (in /tmp) suitable for mmaping. 1208 */ 1209 int 1210 sys___tmpfd(struct proc *p, void *v, register_t *retval) 1211 { 1212 struct sys___tmpfd_args /* { 1213 syscallarg(int) flags; 1214 } */ *uap = v; 1215 struct filedesc *fdp = p->p_fd; 1216 struct file *fp; 1217 struct vnode *vp; 1218 int oflags = SCARG(uap, flags); 1219 int flags, cloexec, cmode; 1220 int indx, error; 1221 unsigned int i; 1222 struct nameidata nd; 1223 char path[64]; 1224 static const char *letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-"; 1225 1226 /* most flags are hardwired */ 1227 oflags = O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW | (oflags & O_CLOEXEC); 1228 1229 cloexec = (oflags & O_CLOEXEC) ? UF_EXCLOSE : 0; 1230 1231 fdplock(fdp); 1232 if ((error = falloc(p, &fp, &indx)) != 0) { 1233 fdpunlock(fdp); 1234 return (error); 1235 } 1236 fdpunlock(fdp); 1237 1238 flags = FFLAGS(oflags); 1239 1240 arc4random_buf(path, sizeof(path)); 1241 memcpy(path, "/tmp/", 5); 1242 for (i = 5; i < sizeof(path) - 1; i++) 1243 path[i] = letters[(unsigned char)path[i] & 63]; 1244 path[sizeof(path)-1] = 0; 1245 1246 cmode = 0600; 1247 NDINITAT(&nd, 0, KERNELPATH, UIO_SYSSPACE, AT_FDCWD, path, p); 1248 if ((error = vn_open(&nd, flags, cmode)) != 0) { 1249 if (error == ERESTART) 1250 error = EINTR; 1251 fdplock(fdp); 1252 fdremove(fdp, indx); 1253 fdpunlock(fdp); 1254 closef(fp, p); 1255 return (error); 1256 } 1257 vp = nd.ni_vp; 1258 fp->f_flag = flags & FMASK; 1259 fp->f_type = DTYPE_VNODE; 1260 fp->f_ops = &vnops; 1261 fp->f_data = vp; 1262 VOP_UNLOCK(vp); 1263 *retval = indx; 1264 fdplock(fdp); 1265 fdinsert(fdp, indx, cloexec, fp); 1266 fdpunlock(fdp); 1267 FRELE(fp, p); 1268 1269 /* unlink it */ 1270 /* XXX 1271 * there is a wee race here, although it is mostly inconsequential. 1272 * perhaps someday we can create a file like object without a name... 1273 */ 1274 NDINITAT(&nd, DELETE, KERNELPATH | LOCKPARENT | LOCKLEAF, UIO_SYSSPACE, 1275 AT_FDCWD, path, p); 1276 if ((error = namei(&nd)) != 0) { 1277 printf("can't unlink temp file! %d\n", error); 1278 error = 0; 1279 } else { 1280 vp = nd.ni_vp; 1281 uvm_vnp_uncache(vp); 1282 error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 1283 if (error) { 1284 printf("error removing vop: %d\n", error); 1285 error = 0; 1286 } 1287 } 1288 1289 return (error); 1290 } 1291 1292 /* 1293 * Get file handle system call 1294 */ 1295 int 1296 sys_getfh(struct proc *p, void *v, register_t *retval) 1297 { 1298 struct sys_getfh_args /* { 1299 syscallarg(const char *) fname; 1300 syscallarg(fhandle_t *) fhp; 1301 } */ *uap = v; 1302 struct vnode *vp; 1303 fhandle_t fh; 1304 int error; 1305 struct nameidata nd; 1306 1307 /* 1308 * Must be super user 1309 */ 1310 error = suser(p); 1311 if (error) 1312 return (error); 1313 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 1314 SCARG(uap, fname), p); 1315 error = namei(&nd); 1316 if (error) 1317 return (error); 1318 vp = nd.ni_vp; 1319 memset(&fh, 0, sizeof(fh)); 1320 fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid; 1321 error = VFS_VPTOFH(vp, &fh.fh_fid); 1322 vput(vp); 1323 if (error) 1324 return (error); 1325 error = copyout(&fh, SCARG(uap, fhp), sizeof(fh)); 1326 return (error); 1327 } 1328 1329 /* 1330 * Open a file given a file handle. 1331 * 1332 * Check permissions, allocate an open file structure, 1333 * and call the device open routine if any. 1334 */ 1335 int 1336 sys_fhopen(struct proc *p, void *v, register_t *retval) 1337 { 1338 struct sys_fhopen_args /* { 1339 syscallarg(const fhandle_t *) fhp; 1340 syscallarg(int) flags; 1341 } */ *uap = v; 1342 struct filedesc *fdp = p->p_fd; 1343 struct file *fp; 1344 struct vnode *vp = NULL; 1345 struct mount *mp; 1346 struct ucred *cred = p->p_ucred; 1347 int flags, cloexec; 1348 int type, indx, error=0; 1349 struct flock lf; 1350 struct vattr va; 1351 fhandle_t fh; 1352 1353 /* 1354 * Must be super user 1355 */ 1356 if ((error = suser(p))) 1357 return (error); 1358 1359 flags = FFLAGS(SCARG(uap, flags)); 1360 if ((flags & (FREAD | FWRITE)) == 0) 1361 return (EINVAL); 1362 if ((flags & O_CREAT)) 1363 return (EINVAL); 1364 1365 cloexec = (flags & O_CLOEXEC) ? UF_EXCLOSE : 0; 1366 1367 fdplock(fdp); 1368 if ((error = falloc(p, &fp, &indx)) != 0) { 1369 fdpunlock(fdp); 1370 fp = NULL; 1371 goto bad; 1372 } 1373 fdpunlock(fdp); 1374 1375 if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0) 1376 goto bad; 1377 1378 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) { 1379 error = ESTALE; 1380 goto bad; 1381 } 1382 1383 if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)) != 0) { 1384 vp = NULL; /* most likely unnecessary sanity for bad: */ 1385 goto bad; 1386 } 1387 1388 /* Now do an effective vn_open */ 1389 1390 if (vp->v_type == VSOCK) { 1391 error = EOPNOTSUPP; 1392 goto bad; 1393 } 1394 if ((flags & O_DIRECTORY) && vp->v_type != VDIR) { 1395 error = ENOTDIR; 1396 goto bad; 1397 } 1398 if (flags & FREAD) { 1399 if ((error = VOP_ACCESS(vp, VREAD, cred, p)) != 0) 1400 goto bad; 1401 } 1402 if (flags & (FWRITE | O_TRUNC)) { 1403 if (vp->v_type == VDIR) { 1404 error = EISDIR; 1405 goto bad; 1406 } 1407 if ((error = VOP_ACCESS(vp, VWRITE, cred, p)) != 0 || 1408 (error = vn_writechk(vp)) != 0) 1409 goto bad; 1410 } 1411 if (flags & O_TRUNC) { 1412 VATTR_NULL(&va); 1413 va.va_size = 0; 1414 if ((error = VOP_SETATTR(vp, &va, cred, p)) != 0) 1415 goto bad; 1416 } 1417 if ((error = VOP_OPEN(vp, flags, cred, p)) != 0) 1418 goto bad; 1419 if (flags & FWRITE) 1420 vp->v_writecount++; 1421 1422 /* done with modified vn_open, now finish what sys_open does. */ 1423 1424 fp->f_flag = flags & FMASK; 1425 fp->f_type = DTYPE_VNODE; 1426 fp->f_ops = &vnops; 1427 fp->f_data = vp; 1428 if (flags & (O_EXLOCK | O_SHLOCK)) { 1429 lf.l_whence = SEEK_SET; 1430 lf.l_start = 0; 1431 lf.l_len = 0; 1432 if (flags & O_EXLOCK) 1433 lf.l_type = F_WRLCK; 1434 else 1435 lf.l_type = F_RDLCK; 1436 type = F_FLOCK; 1437 if ((flags & FNONBLOCK) == 0) 1438 type |= F_WAIT; 1439 VOP_UNLOCK(vp); 1440 error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type); 1441 if (error) { 1442 vp = NULL; /* closef will vn_close the file */ 1443 goto bad; 1444 } 1445 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 1446 atomic_setbits_int(&fp->f_iflags, FIF_HASLOCK); 1447 } 1448 VOP_UNLOCK(vp); 1449 *retval = indx; 1450 fdplock(fdp); 1451 fdinsert(fdp, indx, cloexec, fp); 1452 fdpunlock(fdp); 1453 FRELE(fp, p); 1454 return (0); 1455 1456 bad: 1457 if (fp) { 1458 fdplock(fdp); 1459 fdremove(fdp, indx); 1460 fdpunlock(fdp); 1461 closef(fp, p); 1462 if (vp != NULL) 1463 vput(vp); 1464 } 1465 return (error); 1466 } 1467 1468 int 1469 sys_fhstat(struct proc *p, void *v, register_t *retval) 1470 { 1471 struct sys_fhstat_args /* { 1472 syscallarg(const fhandle_t *) fhp; 1473 syscallarg(struct stat *) sb; 1474 } */ *uap = v; 1475 struct stat sb; 1476 int error; 1477 fhandle_t fh; 1478 struct mount *mp; 1479 struct vnode *vp; 1480 1481 /* 1482 * Must be super user 1483 */ 1484 if ((error = suser(p))) 1485 return (error); 1486 1487 if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0) 1488 return (error); 1489 1490 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) 1491 return (ESTALE); 1492 if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp))) 1493 return (error); 1494 error = vn_stat(vp, &sb, p); 1495 vput(vp); 1496 if (error) 1497 return (error); 1498 error = copyout(&sb, SCARG(uap, sb), sizeof(sb)); 1499 return (error); 1500 } 1501 1502 int 1503 sys_fhstatfs(struct proc *p, void *v, register_t *retval) 1504 { 1505 struct sys_fhstatfs_args /* { 1506 syscallarg(const fhandle_t *) fhp; 1507 syscallarg(struct statfs *) buf; 1508 } */ *uap = v; 1509 struct statfs *sp; 1510 fhandle_t fh; 1511 struct mount *mp; 1512 struct vnode *vp; 1513 int error; 1514 1515 /* 1516 * Must be super user 1517 */ 1518 if ((error = suser(p))) 1519 return (error); 1520 1521 if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0) 1522 return (error); 1523 1524 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) 1525 return (ESTALE); 1526 if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp))) 1527 return (error); 1528 mp = vp->v_mount; 1529 sp = &mp->mnt_stat; 1530 vput(vp); 1531 if ((error = VFS_STATFS(mp, sp, p)) != 0) 1532 return (error); 1533 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 1534 return (copyout(sp, SCARG(uap, buf), sizeof(*sp))); 1535 } 1536 1537 /* 1538 * Create a special file or named pipe. 1539 */ 1540 int 1541 sys_mknod(struct proc *p, void *v, register_t *retval) 1542 { 1543 struct sys_mknod_args /* { 1544 syscallarg(const char *) path; 1545 syscallarg(mode_t) mode; 1546 syscallarg(int) dev; 1547 } */ *uap = v; 1548 1549 return (domknodat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, mode), 1550 SCARG(uap, dev))); 1551 } 1552 1553 int 1554 sys_mknodat(struct proc *p, void *v, register_t *retval) 1555 { 1556 struct sys_mknodat_args /* { 1557 syscallarg(int) fd; 1558 syscallarg(const char *) path; 1559 syscallarg(mode_t) mode; 1560 syscallarg(dev_t) dev; 1561 } */ *uap = v; 1562 1563 return (domknodat(p, SCARG(uap, fd), SCARG(uap, path), 1564 SCARG(uap, mode), SCARG(uap, dev))); 1565 } 1566 1567 int 1568 domknodat(struct proc *p, int fd, const char *path, mode_t mode, dev_t dev) 1569 { 1570 struct vnode *vp; 1571 struct vattr vattr; 1572 int error; 1573 struct nameidata nd; 1574 1575 if (dev == VNOVAL) 1576 return (EINVAL); 1577 NDINITAT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, fd, path, p); 1578 nd.ni_pledge = PLEDGE_DPATH; 1579 nd.ni_unveil = UNVEIL_CREATE; 1580 if ((error = namei(&nd)) != 0) 1581 return (error); 1582 vp = nd.ni_vp; 1583 if (!S_ISFIFO(mode) || dev != 0) { 1584 if (!vnoperm(nd.ni_dvp) && (error = suser(p)) != 0) 1585 goto out; 1586 if (p->p_fd->fd_rdir) { 1587 error = EINVAL; 1588 goto out; 1589 } 1590 } 1591 if (vp != NULL) 1592 error = EEXIST; 1593 else { 1594 VATTR_NULL(&vattr); 1595 vattr.va_mode = (mode & ALLPERMS) &~ p->p_fd->fd_cmask; 1596 if ((p->p_p->ps_flags & PS_PLEDGE)) 1597 vattr.va_mode &= ACCESSPERMS; 1598 vattr.va_rdev = dev; 1599 1600 switch (mode & S_IFMT) { 1601 case S_IFMT: /* used by badsect to flag bad sectors */ 1602 vattr.va_type = VBAD; 1603 break; 1604 case S_IFCHR: 1605 vattr.va_type = VCHR; 1606 break; 1607 case S_IFBLK: 1608 vattr.va_type = VBLK; 1609 break; 1610 case S_IFIFO: 1611 #ifndef FIFO 1612 error = EOPNOTSUPP; 1613 break; 1614 #else 1615 if (dev == 0) { 1616 vattr.va_type = VFIFO; 1617 break; 1618 } 1619 /* FALLTHROUGH */ 1620 #endif /* FIFO */ 1621 default: 1622 error = EINVAL; 1623 break; 1624 } 1625 } 1626 out: 1627 if (!error) { 1628 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 1629 vput(nd.ni_dvp); 1630 } else { 1631 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1632 if (nd.ni_dvp == vp) 1633 vrele(nd.ni_dvp); 1634 else 1635 vput(nd.ni_dvp); 1636 if (vp) 1637 vrele(vp); 1638 } 1639 return (error); 1640 } 1641 1642 /* 1643 * Create a named pipe. 1644 */ 1645 int 1646 sys_mkfifo(struct proc *p, void *v, register_t *retval) 1647 { 1648 struct sys_mkfifo_args /* { 1649 syscallarg(const char *) path; 1650 syscallarg(mode_t) mode; 1651 } */ *uap = v; 1652 1653 return (domknodat(p, AT_FDCWD, SCARG(uap, path), 1654 (SCARG(uap, mode) & ALLPERMS) | S_IFIFO, 0)); 1655 } 1656 1657 int 1658 sys_mkfifoat(struct proc *p, void *v, register_t *retval) 1659 { 1660 struct sys_mkfifoat_args /* { 1661 syscallarg(int) fd; 1662 syscallarg(const char *) path; 1663 syscallarg(mode_t) mode; 1664 } */ *uap = v; 1665 1666 return (domknodat(p, SCARG(uap, fd), SCARG(uap, path), 1667 (SCARG(uap, mode) & ALLPERMS) | S_IFIFO, 0)); 1668 } 1669 1670 /* 1671 * Make a hard file link. 1672 */ 1673 int 1674 sys_link(struct proc *p, void *v, register_t *retval) 1675 { 1676 struct sys_link_args /* { 1677 syscallarg(const char *) path; 1678 syscallarg(const char *) link; 1679 } */ *uap = v; 1680 1681 return (dolinkat(p, AT_FDCWD, SCARG(uap, path), AT_FDCWD, 1682 SCARG(uap, link), AT_SYMLINK_FOLLOW)); 1683 } 1684 1685 int 1686 sys_linkat(struct proc *p, void *v, register_t *retval) 1687 { 1688 struct sys_linkat_args /* { 1689 syscallarg(int) fd1; 1690 syscallarg(const char *) path1; 1691 syscallarg(int) fd2; 1692 syscallarg(const char *) path2; 1693 syscallarg(int) flag; 1694 } */ *uap = v; 1695 1696 return (dolinkat(p, SCARG(uap, fd1), SCARG(uap, path1), 1697 SCARG(uap, fd2), SCARG(uap, path2), SCARG(uap, flag))); 1698 } 1699 1700 int 1701 dolinkat(struct proc *p, int fd1, const char *path1, int fd2, 1702 const char *path2, int flag) 1703 { 1704 struct vnode *vp; 1705 struct nameidata nd; 1706 int error, follow; 1707 int flags; 1708 1709 if (flag & ~AT_SYMLINK_FOLLOW) 1710 return (EINVAL); 1711 1712 follow = (flag & AT_SYMLINK_FOLLOW) ? FOLLOW : NOFOLLOW; 1713 NDINITAT(&nd, LOOKUP, follow, UIO_USERSPACE, fd1, path1, p); 1714 nd.ni_pledge = PLEDGE_RPATH; 1715 nd.ni_unveil = UNVEIL_READ; 1716 if ((error = namei(&nd)) != 0) 1717 return (error); 1718 vp = nd.ni_vp; 1719 1720 flags = LOCKPARENT; 1721 if (vp->v_type == VDIR) { 1722 flags |= STRIPSLASHES; 1723 } 1724 1725 NDINITAT(&nd, CREATE, flags, UIO_USERSPACE, fd2, path2, p); 1726 nd.ni_pledge = PLEDGE_CPATH; 1727 nd.ni_unveil = UNVEIL_CREATE; 1728 if ((error = namei(&nd)) != 0) 1729 goto out; 1730 if (nd.ni_vp) { 1731 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1732 if (nd.ni_dvp == nd.ni_vp) 1733 vrele(nd.ni_dvp); 1734 else 1735 vput(nd.ni_dvp); 1736 vrele(nd.ni_vp); 1737 error = EEXIST; 1738 goto out; 1739 } 1740 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 1741 out: 1742 vrele(vp); 1743 return (error); 1744 } 1745 1746 /* 1747 * Make a symbolic link. 1748 */ 1749 int 1750 sys_symlink(struct proc *p, void *v, register_t *retval) 1751 { 1752 struct sys_symlink_args /* { 1753 syscallarg(const char *) path; 1754 syscallarg(const char *) link; 1755 } */ *uap = v; 1756 1757 return (dosymlinkat(p, SCARG(uap, path), AT_FDCWD, SCARG(uap, link))); 1758 } 1759 1760 int 1761 sys_symlinkat(struct proc *p, void *v, register_t *retval) 1762 { 1763 struct sys_symlinkat_args /* { 1764 syscallarg(const char *) path; 1765 syscallarg(int) fd; 1766 syscallarg(const char *) link; 1767 } */ *uap = v; 1768 1769 return (dosymlinkat(p, SCARG(uap, path), SCARG(uap, fd), 1770 SCARG(uap, link))); 1771 } 1772 1773 int 1774 dosymlinkat(struct proc *p, const char *upath, int fd, const char *link) 1775 { 1776 struct vattr vattr; 1777 char *path; 1778 int error; 1779 struct nameidata nd; 1780 1781 path = pool_get(&namei_pool, PR_WAITOK); 1782 error = copyinstr(upath, path, MAXPATHLEN, NULL); 1783 if (error) 1784 goto out; 1785 NDINITAT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, fd, link, p); 1786 nd.ni_pledge = PLEDGE_CPATH; 1787 nd.ni_unveil = UNVEIL_CREATE; 1788 if ((error = namei(&nd)) != 0) 1789 goto out; 1790 if (nd.ni_vp) { 1791 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1792 if (nd.ni_dvp == nd.ni_vp) 1793 vrele(nd.ni_dvp); 1794 else 1795 vput(nd.ni_dvp); 1796 vrele(nd.ni_vp); 1797 error = EEXIST; 1798 goto out; 1799 } 1800 VATTR_NULL(&vattr); 1801 vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask; 1802 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path); 1803 out: 1804 pool_put(&namei_pool, path); 1805 return (error); 1806 } 1807 1808 /* 1809 * Delete a name from the filesystem. 1810 */ 1811 int 1812 sys_unlink(struct proc *p, void *v, register_t *retval) 1813 { 1814 struct sys_unlink_args /* { 1815 syscallarg(const char *) path; 1816 } */ *uap = v; 1817 1818 return (dounlinkat(p, AT_FDCWD, SCARG(uap, path), 0)); 1819 } 1820 1821 int 1822 sys_unlinkat(struct proc *p, void *v, register_t *retval) 1823 { 1824 struct sys_unlinkat_args /* { 1825 syscallarg(int) fd; 1826 syscallarg(const char *) path; 1827 syscallarg(int) flag; 1828 } */ *uap = v; 1829 1830 return (dounlinkat(p, SCARG(uap, fd), SCARG(uap, path), 1831 SCARG(uap, flag))); 1832 } 1833 1834 int 1835 dounlinkat(struct proc *p, int fd, const char *path, int flag) 1836 { 1837 struct vnode *vp; 1838 int error; 1839 struct nameidata nd; 1840 1841 if (flag & ~AT_REMOVEDIR) 1842 return (EINVAL); 1843 1844 NDINITAT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, 1845 fd, path, p); 1846 nd.ni_pledge = PLEDGE_CPATH; 1847 nd.ni_unveil = UNVEIL_CREATE; 1848 if ((error = namei(&nd)) != 0) 1849 return (error); 1850 vp = nd.ni_vp; 1851 1852 if (flag & AT_REMOVEDIR) { 1853 if (vp->v_type != VDIR) { 1854 error = ENOTDIR; 1855 goto out; 1856 } 1857 /* 1858 * No rmdir "." please. 1859 */ 1860 if (nd.ni_dvp == vp) { 1861 error = EINVAL; 1862 goto out; 1863 } 1864 /* 1865 * A mounted on directory cannot be deleted. 1866 */ 1867 if (vp->v_mountedhere != NULL) { 1868 error = EBUSY; 1869 goto out; 1870 } 1871 } 1872 1873 /* 1874 * The root of a mounted filesystem cannot be deleted. 1875 */ 1876 if (vp->v_flag & VROOT) 1877 error = EBUSY; 1878 out: 1879 if (!error) { 1880 if (flag & AT_REMOVEDIR) { 1881 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 1882 } else { 1883 (void)uvm_vnp_uncache(vp); 1884 error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 1885 } 1886 } else { 1887 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1888 if (nd.ni_dvp == vp) 1889 vrele(nd.ni_dvp); 1890 else 1891 vput(nd.ni_dvp); 1892 vput(vp); 1893 } 1894 return (error); 1895 } 1896 1897 /* 1898 * Reposition read/write file offset. 1899 */ 1900 int 1901 sys_lseek(struct proc *p, void *v, register_t *retval) 1902 { 1903 struct sys_lseek_args /* { 1904 syscallarg(int) fd; 1905 syscallarg(off_t) offset; 1906 syscallarg(int) whence; 1907 } */ *uap = v; 1908 struct filedesc *fdp = p->p_fd; 1909 struct file *fp; 1910 off_t offset; 1911 int error; 1912 1913 if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL) 1914 return (EBADF); 1915 if (fp->f_ops->fo_seek == NULL) { 1916 error = ESPIPE; 1917 goto bad; 1918 } 1919 offset = SCARG(uap, offset); 1920 1921 error = (*fp->f_ops->fo_seek)(fp, &offset, SCARG(uap, whence), p); 1922 if (error) 1923 goto bad; 1924 1925 *(off_t *)retval = offset; 1926 mtx_enter(&fp->f_mtx); 1927 fp->f_seek++; 1928 mtx_leave(&fp->f_mtx); 1929 error = 0; 1930 bad: 1931 FRELE(fp, p); 1932 return (error); 1933 } 1934 1935 #if 1 1936 int 1937 sys_pad_lseek(struct proc *p, void *v, register_t *retval) 1938 { 1939 struct sys_pad_lseek_args *uap = v; 1940 struct sys_lseek_args unpad; 1941 1942 SCARG(&unpad, fd) = SCARG(uap, fd); 1943 SCARG(&unpad, offset) = SCARG(uap, offset); 1944 SCARG(&unpad, whence) = SCARG(uap, whence); 1945 return sys_lseek(p, &unpad, retval); 1946 } 1947 #endif 1948 1949 /* 1950 * Check access permissions. 1951 */ 1952 int 1953 sys_access(struct proc *p, void *v, register_t *retval) 1954 { 1955 struct sys_access_args /* { 1956 syscallarg(const char *) path; 1957 syscallarg(int) amode; 1958 } */ *uap = v; 1959 1960 return (dofaccessat(p, AT_FDCWD, SCARG(uap, path), 1961 SCARG(uap, amode), 0)); 1962 } 1963 1964 int 1965 sys_faccessat(struct proc *p, void *v, register_t *retval) 1966 { 1967 struct sys_faccessat_args /* { 1968 syscallarg(int) fd; 1969 syscallarg(const char *) path; 1970 syscallarg(int) amode; 1971 syscallarg(int) flag; 1972 } */ *uap = v; 1973 1974 return (dofaccessat(p, SCARG(uap, fd), SCARG(uap, path), 1975 SCARG(uap, amode), SCARG(uap, flag))); 1976 } 1977 1978 int 1979 dofaccessat(struct proc *p, int fd, const char *path, int amode, int flag) 1980 { 1981 struct vnode *vp; 1982 struct ucred *newcred, *oldcred; 1983 struct nameidata nd; 1984 int error; 1985 1986 if (amode & ~(R_OK | W_OK | X_OK)) 1987 return (EINVAL); 1988 if (flag & ~AT_EACCESS) 1989 return (EINVAL); 1990 1991 newcred = NULL; 1992 oldcred = p->p_ucred; 1993 1994 /* 1995 * If access as real ids was requested and they really differ, 1996 * give the thread new creds with them reset 1997 */ 1998 if ((flag & AT_EACCESS) == 0 && 1999 (oldcred->cr_uid != oldcred->cr_ruid || 2000 (oldcred->cr_gid != oldcred->cr_rgid))) { 2001 p->p_ucred = newcred = crdup(oldcred); 2002 newcred->cr_uid = newcred->cr_ruid; 2003 newcred->cr_gid = newcred->cr_rgid; 2004 } 2005 2006 NDINITAT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, fd, path, p); 2007 nd.ni_pledge = PLEDGE_RPATH; 2008 nd.ni_unveil = UNVEIL_READ; 2009 if ((error = namei(&nd)) != 0) 2010 goto out; 2011 vp = nd.ni_vp; 2012 2013 /* Flags == 0 means only check for existence. */ 2014 if (amode) { 2015 int vflags = 0; 2016 2017 if (amode & R_OK) 2018 vflags |= VREAD; 2019 if (amode & W_OK) 2020 vflags |= VWRITE; 2021 if (amode & X_OK) 2022 vflags |= VEXEC; 2023 2024 error = VOP_ACCESS(vp, vflags, p->p_ucred, p); 2025 if (!error && (vflags & VWRITE)) 2026 error = vn_writechk(vp); 2027 } 2028 vput(vp); 2029 out: 2030 if (newcred != NULL) { 2031 p->p_ucred = oldcred; 2032 crfree(newcred); 2033 } 2034 return (error); 2035 } 2036 2037 /* 2038 * Get file status; this version follows links. 2039 */ 2040 int 2041 sys_stat(struct proc *p, void *v, register_t *retval) 2042 { 2043 struct sys_stat_args /* { 2044 syscallarg(const char *) path; 2045 syscallarg(struct stat *) ub; 2046 } */ *uap = v; 2047 2048 return (dofstatat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, ub), 0)); 2049 } 2050 2051 int 2052 sys_fstatat(struct proc *p, void *v, register_t *retval) 2053 { 2054 struct sys_fstatat_args /* { 2055 syscallarg(int) fd; 2056 syscallarg(const char *) path; 2057 syscallarg(struct stat *) buf; 2058 syscallarg(int) flag; 2059 } */ *uap = v; 2060 2061 return (dofstatat(p, SCARG(uap, fd), SCARG(uap, path), 2062 SCARG(uap, buf), SCARG(uap, flag))); 2063 } 2064 2065 int 2066 dofstatat(struct proc *p, int fd, const char *path, struct stat *buf, int flag) 2067 { 2068 struct stat sb; 2069 int error, follow; 2070 struct nameidata nd; 2071 2072 if (flag & ~AT_SYMLINK_NOFOLLOW) 2073 return (EINVAL); 2074 2075 2076 follow = (flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW; 2077 NDINITAT(&nd, LOOKUP, follow | LOCKLEAF, UIO_USERSPACE, fd, path, p); 2078 nd.ni_pledge = PLEDGE_RPATH; 2079 nd.ni_unveil = UNVEIL_READ; 2080 if ((error = namei(&nd)) != 0) 2081 return (error); 2082 error = vn_stat(nd.ni_vp, &sb, p); 2083 vput(nd.ni_vp); 2084 if (error) 2085 return (error); 2086 /* Don't let non-root see generation numbers (for NFS security) */ 2087 if (suser(p)) 2088 sb.st_gen = 0; 2089 error = copyout(&sb, buf, sizeof(sb)); 2090 #ifdef KTRACE 2091 if (error == 0 && KTRPOINT(p, KTR_STRUCT)) 2092 ktrstat(p, &sb); 2093 #endif 2094 return (error); 2095 } 2096 2097 /* 2098 * Get file status; this version does not follow links. 2099 */ 2100 int 2101 sys_lstat(struct proc *p, void *v, register_t *retval) 2102 { 2103 struct sys_lstat_args /* { 2104 syscallarg(const char *) path; 2105 syscallarg(struct stat *) ub; 2106 } */ *uap = v; 2107 2108 return (dofstatat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, ub), 2109 AT_SYMLINK_NOFOLLOW)); 2110 } 2111 2112 /* 2113 * Get configurable pathname variables. 2114 */ 2115 int 2116 sys_pathconf(struct proc *p, void *v, register_t *retval) 2117 { 2118 struct sys_pathconf_args /* { 2119 syscallarg(const char *) path; 2120 syscallarg(int) name; 2121 } */ *uap = v; 2122 int error; 2123 struct nameidata nd; 2124 2125 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 2126 SCARG(uap, path), p); 2127 nd.ni_pledge = PLEDGE_RPATH; 2128 nd.ni_unveil = UNVEIL_READ; 2129 if ((error = namei(&nd)) != 0) 2130 return (error); 2131 error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval); 2132 vput(nd.ni_vp); 2133 return (error); 2134 } 2135 2136 /* 2137 * Return target name of a symbolic link. 2138 */ 2139 int 2140 sys_readlink(struct proc *p, void *v, register_t *retval) 2141 { 2142 struct sys_readlink_args /* { 2143 syscallarg(const char *) path; 2144 syscallarg(char *) buf; 2145 syscallarg(size_t) count; 2146 } */ *uap = v; 2147 2148 return (doreadlinkat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, buf), 2149 SCARG(uap, count), retval)); 2150 } 2151 2152 int 2153 sys_readlinkat(struct proc *p, void *v, register_t *retval) 2154 { 2155 struct sys_readlinkat_args /* { 2156 syscallarg(int) fd; 2157 syscallarg(const char *) path; 2158 syscallarg(char *) buf; 2159 syscallarg(size_t) count; 2160 } */ *uap = v; 2161 2162 return (doreadlinkat(p, SCARG(uap, fd), SCARG(uap, path), 2163 SCARG(uap, buf), SCARG(uap, count), retval)); 2164 } 2165 2166 int 2167 doreadlinkat(struct proc *p, int fd, const char *path, char *buf, 2168 size_t count, register_t *retval) 2169 { 2170 struct vnode *vp; 2171 struct iovec aiov; 2172 struct uio auio; 2173 int error; 2174 struct nameidata nd; 2175 2176 NDINITAT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, fd, path, p); 2177 nd.ni_pledge = PLEDGE_RPATH; 2178 nd.ni_unveil = UNVEIL_READ; 2179 if ((error = namei(&nd)) != 0) 2180 return (error); 2181 vp = nd.ni_vp; 2182 if (vp->v_type != VLNK) 2183 error = EINVAL; 2184 else { 2185 aiov.iov_base = buf; 2186 aiov.iov_len = count; 2187 auio.uio_iov = &aiov; 2188 auio.uio_iovcnt = 1; 2189 auio.uio_offset = 0; 2190 auio.uio_rw = UIO_READ; 2191 auio.uio_segflg = UIO_USERSPACE; 2192 auio.uio_procp = p; 2193 auio.uio_resid = count; 2194 error = VOP_READLINK(vp, &auio, p->p_ucred); 2195 *retval = count - auio.uio_resid; 2196 } 2197 vput(vp); 2198 return (error); 2199 } 2200 2201 /* 2202 * Change flags of a file given a path name. 2203 */ 2204 int 2205 sys_chflags(struct proc *p, void *v, register_t *retval) 2206 { 2207 struct sys_chflags_args /* { 2208 syscallarg(const char *) path; 2209 syscallarg(u_int) flags; 2210 } */ *uap = v; 2211 2212 return (dochflagsat(p, AT_FDCWD, SCARG(uap, path), 2213 SCARG(uap, flags), 0)); 2214 } 2215 2216 int 2217 sys_chflagsat(struct proc *p, void *v, register_t *retval) 2218 { 2219 struct sys_chflagsat_args /* { 2220 syscallarg(int) fd; 2221 syscallarg(const char *) path; 2222 syscallarg(u_int) flags; 2223 syscallarg(int) atflags; 2224 } */ *uap = v; 2225 2226 return (dochflagsat(p, SCARG(uap, fd), SCARG(uap, path), 2227 SCARG(uap, flags), SCARG(uap, atflags))); 2228 } 2229 2230 int 2231 dochflagsat(struct proc *p, int fd, const char *path, u_int flags, int atflags) 2232 { 2233 struct nameidata nd; 2234 int error, follow; 2235 2236 if (atflags & ~AT_SYMLINK_NOFOLLOW) 2237 return (EINVAL); 2238 2239 follow = (atflags & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW; 2240 NDINITAT(&nd, LOOKUP, follow, UIO_USERSPACE, fd, path, p); 2241 nd.ni_pledge = PLEDGE_FATTR | PLEDGE_RPATH; 2242 nd.ni_unveil = UNVEIL_WRITE; 2243 if ((error = namei(&nd)) != 0) 2244 return (error); 2245 return (dovchflags(p, nd.ni_vp, flags)); 2246 } 2247 2248 /* 2249 * Change flags of a file given a file descriptor. 2250 */ 2251 int 2252 sys_fchflags(struct proc *p, void *v, register_t *retval) 2253 { 2254 struct sys_fchflags_args /* { 2255 syscallarg(int) fd; 2256 syscallarg(u_int) flags; 2257 } */ *uap = v; 2258 struct file *fp; 2259 struct vnode *vp; 2260 int error; 2261 2262 if ((error = getvnode(p, SCARG(uap, fd), &fp)) != 0) 2263 return (error); 2264 vp = fp->f_data; 2265 vref(vp); 2266 FRELE(fp, p); 2267 return (dovchflags(p, vp, SCARG(uap, flags))); 2268 } 2269 2270 int 2271 dovchflags(struct proc *p, struct vnode *vp, u_int flags) 2272 { 2273 struct vattr vattr; 2274 int error; 2275 2276 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 2277 if (vp->v_mount && vp->v_mount->mnt_flag & MNT_RDONLY) 2278 error = EROFS; 2279 else if (flags == VNOVAL) 2280 error = EINVAL; 2281 else { 2282 if (suser(p)) { 2283 if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 2284 != 0) 2285 goto out; 2286 if (vattr.va_type == VCHR || vattr.va_type == VBLK) { 2287 error = EINVAL; 2288 goto out; 2289 } 2290 } 2291 VATTR_NULL(&vattr); 2292 vattr.va_flags = flags; 2293 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 2294 } 2295 out: 2296 vput(vp); 2297 return (error); 2298 } 2299 2300 /* 2301 * Change mode of a file given path name. 2302 */ 2303 int 2304 sys_chmod(struct proc *p, void *v, register_t *retval) 2305 { 2306 struct sys_chmod_args /* { 2307 syscallarg(const char *) path; 2308 syscallarg(mode_t) mode; 2309 } */ *uap = v; 2310 2311 return (dofchmodat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, mode), 0)); 2312 } 2313 2314 int 2315 sys_fchmodat(struct proc *p, void *v, register_t *retval) 2316 { 2317 struct sys_fchmodat_args /* { 2318 syscallarg(int) fd; 2319 syscallarg(const char *) path; 2320 syscallarg(mode_t) mode; 2321 syscallarg(int) flag; 2322 } */ *uap = v; 2323 2324 return (dofchmodat(p, SCARG(uap, fd), SCARG(uap, path), 2325 SCARG(uap, mode), SCARG(uap, flag))); 2326 } 2327 2328 int 2329 dofchmodat(struct proc *p, int fd, const char *path, mode_t mode, int flag) 2330 { 2331 struct vnode *vp; 2332 struct vattr vattr; 2333 int error, follow; 2334 struct nameidata nd; 2335 2336 if (mode & ~(S_IFMT | ALLPERMS)) 2337 return (EINVAL); 2338 if ((p->p_p->ps_flags & PS_PLEDGE)) 2339 mode &= ACCESSPERMS; 2340 if (flag & ~AT_SYMLINK_NOFOLLOW) 2341 return (EINVAL); 2342 2343 follow = (flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW; 2344 NDINITAT(&nd, LOOKUP, follow, UIO_USERSPACE, fd, path, p); 2345 nd.ni_pledge = PLEDGE_FATTR | PLEDGE_RPATH; 2346 nd.ni_unveil = UNVEIL_WRITE; 2347 if ((error = namei(&nd)) != 0) 2348 return (error); 2349 vp = nd.ni_vp; 2350 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 2351 if (vp->v_mount->mnt_flag & MNT_RDONLY) 2352 error = EROFS; 2353 else { 2354 VATTR_NULL(&vattr); 2355 vattr.va_mode = mode & ALLPERMS; 2356 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 2357 } 2358 vput(vp); 2359 return (error); 2360 } 2361 2362 /* 2363 * Change mode of a file given a file descriptor. 2364 */ 2365 int 2366 sys_fchmod(struct proc *p, void *v, register_t *retval) 2367 { 2368 struct sys_fchmod_args /* { 2369 syscallarg(int) fd; 2370 syscallarg(mode_t) mode; 2371 } */ *uap = v; 2372 struct vattr vattr; 2373 struct vnode *vp; 2374 struct file *fp; 2375 mode_t mode = SCARG(uap, mode); 2376 int error; 2377 2378 if (mode & ~(S_IFMT | ALLPERMS)) 2379 return (EINVAL); 2380 if ((p->p_p->ps_flags & PS_PLEDGE)) 2381 mode &= ACCESSPERMS; 2382 2383 if ((error = getvnode(p, SCARG(uap, fd), &fp)) != 0) 2384 return (error); 2385 vp = fp->f_data; 2386 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 2387 if (vp->v_mount && vp->v_mount->mnt_flag & MNT_RDONLY) 2388 error = EROFS; 2389 else { 2390 VATTR_NULL(&vattr); 2391 vattr.va_mode = mode & ALLPERMS; 2392 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 2393 } 2394 VOP_UNLOCK(vp); 2395 FRELE(fp, p); 2396 return (error); 2397 } 2398 2399 /* 2400 * Set ownership given a path name. 2401 */ 2402 int 2403 sys_chown(struct proc *p, void *v, register_t *retval) 2404 { 2405 struct sys_chown_args /* { 2406 syscallarg(const char *) path; 2407 syscallarg(uid_t) uid; 2408 syscallarg(gid_t) gid; 2409 } */ *uap = v; 2410 2411 return (dofchownat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, uid), 2412 SCARG(uap, gid), 0)); 2413 } 2414 2415 int 2416 sys_fchownat(struct proc *p, void *v, register_t *retval) 2417 { 2418 struct sys_fchownat_args /* { 2419 syscallarg(int) fd; 2420 syscallarg(const char *) path; 2421 syscallarg(uid_t) uid; 2422 syscallarg(gid_t) gid; 2423 syscallarg(int) flag; 2424 } */ *uap = v; 2425 2426 return (dofchownat(p, SCARG(uap, fd), SCARG(uap, path), 2427 SCARG(uap, uid), SCARG(uap, gid), SCARG(uap, flag))); 2428 } 2429 2430 int 2431 dofchownat(struct proc *p, int fd, const char *path, uid_t uid, gid_t gid, 2432 int flag) 2433 { 2434 struct vnode *vp; 2435 struct vattr vattr; 2436 int error, follow; 2437 struct nameidata nd; 2438 mode_t mode; 2439 2440 if (flag & ~AT_SYMLINK_NOFOLLOW) 2441 return (EINVAL); 2442 2443 follow = (flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW; 2444 NDINITAT(&nd, LOOKUP, follow, UIO_USERSPACE, fd, path, p); 2445 nd.ni_pledge = PLEDGE_CHOWN | PLEDGE_RPATH; 2446 nd.ni_unveil = UNVEIL_WRITE; 2447 if ((error = namei(&nd)) != 0) 2448 return (error); 2449 vp = nd.ni_vp; 2450 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 2451 if (vp->v_mount->mnt_flag & MNT_RDONLY) 2452 error = EROFS; 2453 else { 2454 if ((error = pledge_chown(p, uid, gid))) 2455 goto out; 2456 if ((uid != -1 || gid != -1) && 2457 !vnoperm(vp) && 2458 (suser(p) || suid_clear)) { 2459 error = VOP_GETATTR(vp, &vattr, p->p_ucred, p); 2460 if (error) 2461 goto out; 2462 mode = vattr.va_mode & ~(VSUID | VSGID); 2463 if (mode == vattr.va_mode) 2464 mode = VNOVAL; 2465 } else 2466 mode = VNOVAL; 2467 VATTR_NULL(&vattr); 2468 vattr.va_uid = uid; 2469 vattr.va_gid = gid; 2470 vattr.va_mode = mode; 2471 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 2472 } 2473 out: 2474 vput(vp); 2475 return (error); 2476 } 2477 2478 /* 2479 * Set ownership given a path name, without following links. 2480 */ 2481 int 2482 sys_lchown(struct proc *p, void *v, register_t *retval) 2483 { 2484 struct sys_lchown_args /* { 2485 syscallarg(const char *) path; 2486 syscallarg(uid_t) uid; 2487 syscallarg(gid_t) gid; 2488 } */ *uap = v; 2489 struct vnode *vp; 2490 struct vattr vattr; 2491 int error; 2492 struct nameidata nd; 2493 mode_t mode; 2494 uid_t uid = SCARG(uap, uid); 2495 gid_t gid = SCARG(uap, gid); 2496 2497 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 2498 nd.ni_pledge = PLEDGE_CHOWN | PLEDGE_RPATH; 2499 nd.ni_unveil = UNVEIL_WRITE; 2500 if ((error = namei(&nd)) != 0) 2501 return (error); 2502 vp = nd.ni_vp; 2503 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 2504 if (vp->v_mount->mnt_flag & MNT_RDONLY) 2505 error = EROFS; 2506 else { 2507 if ((error = pledge_chown(p, uid, gid))) 2508 goto out; 2509 if ((uid != -1 || gid != -1) && 2510 !vnoperm(vp) && 2511 (suser(p) || suid_clear)) { 2512 error = VOP_GETATTR(vp, &vattr, p->p_ucred, p); 2513 if (error) 2514 goto out; 2515 mode = vattr.va_mode & ~(VSUID | VSGID); 2516 if (mode == vattr.va_mode) 2517 mode = VNOVAL; 2518 } else 2519 mode = VNOVAL; 2520 VATTR_NULL(&vattr); 2521 vattr.va_uid = uid; 2522 vattr.va_gid = gid; 2523 vattr.va_mode = mode; 2524 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 2525 } 2526 out: 2527 vput(vp); 2528 return (error); 2529 } 2530 2531 /* 2532 * Set ownership given a file descriptor. 2533 */ 2534 int 2535 sys_fchown(struct proc *p, void *v, register_t *retval) 2536 { 2537 struct sys_fchown_args /* { 2538 syscallarg(int) fd; 2539 syscallarg(uid_t) uid; 2540 syscallarg(gid_t) gid; 2541 } */ *uap = v; 2542 struct vnode *vp; 2543 struct vattr vattr; 2544 int error; 2545 struct file *fp; 2546 mode_t mode; 2547 uid_t uid = SCARG(uap, uid); 2548 gid_t gid = SCARG(uap, gid); 2549 2550 if ((error = getvnode(p, SCARG(uap, fd), &fp)) != 0) 2551 return (error); 2552 vp = fp->f_data; 2553 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 2554 if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_RDONLY)) 2555 error = EROFS; 2556 else { 2557 if ((error = pledge_chown(p, uid, gid))) 2558 goto out; 2559 if ((uid != -1 || gid != -1) && 2560 !vnoperm(vp) && 2561 (suser(p) || suid_clear)) { 2562 error = VOP_GETATTR(vp, &vattr, p->p_ucred, p); 2563 if (error) 2564 goto out; 2565 mode = vattr.va_mode & ~(VSUID | VSGID); 2566 if (mode == vattr.va_mode) 2567 mode = VNOVAL; 2568 } else 2569 mode = VNOVAL; 2570 VATTR_NULL(&vattr); 2571 vattr.va_uid = uid; 2572 vattr.va_gid = gid; 2573 vattr.va_mode = mode; 2574 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 2575 } 2576 out: 2577 VOP_UNLOCK(vp); 2578 FRELE(fp, p); 2579 return (error); 2580 } 2581 2582 /* 2583 * Set the access and modification times given a path name. 2584 */ 2585 int 2586 sys_utimes(struct proc *p, void *v, register_t *retval) 2587 { 2588 struct sys_utimes_args /* { 2589 syscallarg(const char *) path; 2590 syscallarg(const struct timeval *) tptr; 2591 } */ *uap = v; 2592 2593 struct timespec ts[2]; 2594 struct timeval tv[2]; 2595 const struct timeval *tvp; 2596 int error; 2597 2598 tvp = SCARG(uap, tptr); 2599 if (tvp != NULL) { 2600 error = copyin(tvp, tv, sizeof(tv)); 2601 if (error) 2602 return (error); 2603 #ifdef KTRACE 2604 if (KTRPOINT(p, KTR_STRUCT)) 2605 ktrabstimeval(p, &tv); 2606 #endif 2607 if (!timerisvalid(&tv[0]) || !timerisvalid(&tv[1])) 2608 return (EINVAL); 2609 TIMEVAL_TO_TIMESPEC(&tv[0], &ts[0]); 2610 TIMEVAL_TO_TIMESPEC(&tv[1], &ts[1]); 2611 } else 2612 ts[0].tv_nsec = ts[1].tv_nsec = UTIME_NOW; 2613 2614 return (doutimensat(p, AT_FDCWD, SCARG(uap, path), ts, 0)); 2615 } 2616 2617 int 2618 sys_utimensat(struct proc *p, void *v, register_t *retval) 2619 { 2620 struct sys_utimensat_args /* { 2621 syscallarg(int) fd; 2622 syscallarg(const char *) path; 2623 syscallarg(const struct timespec *) times; 2624 syscallarg(int) flag; 2625 } */ *uap = v; 2626 2627 struct timespec ts[2]; 2628 const struct timespec *tsp; 2629 int error, i; 2630 2631 tsp = SCARG(uap, times); 2632 if (tsp != NULL) { 2633 error = copyin(tsp, ts, sizeof(ts)); 2634 if (error) 2635 return (error); 2636 for (i = 0; i < nitems(ts); i++) { 2637 if (ts[i].tv_nsec == UTIME_NOW) 2638 continue; 2639 if (ts[i].tv_nsec == UTIME_OMIT) 2640 continue; 2641 #ifdef KTRACE 2642 if (KTRPOINT(p, KTR_STRUCT)) 2643 ktrabstimespec(p, &ts[i]); 2644 #endif 2645 if (!timespecisvalid(&ts[i])) 2646 return (EINVAL); 2647 } 2648 } else 2649 ts[0].tv_nsec = ts[1].tv_nsec = UTIME_NOW; 2650 2651 return (doutimensat(p, SCARG(uap, fd), SCARG(uap, path), ts, 2652 SCARG(uap, flag))); 2653 } 2654 2655 int 2656 doutimensat(struct proc *p, int fd, const char *path, 2657 struct timespec ts[2], int flag) 2658 { 2659 struct vnode *vp; 2660 int error, follow; 2661 struct nameidata nd; 2662 2663 if (flag & ~AT_SYMLINK_NOFOLLOW) 2664 return (EINVAL); 2665 2666 follow = (flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW; 2667 NDINITAT(&nd, LOOKUP, follow, UIO_USERSPACE, fd, path, p); 2668 nd.ni_pledge = PLEDGE_FATTR | PLEDGE_RPATH; 2669 nd.ni_unveil = UNVEIL_WRITE; 2670 if ((error = namei(&nd)) != 0) 2671 return (error); 2672 vp = nd.ni_vp; 2673 2674 return (dovutimens(p, vp, ts)); 2675 } 2676 2677 int 2678 dovutimens(struct proc *p, struct vnode *vp, struct timespec ts[2]) 2679 { 2680 struct vattr vattr; 2681 struct timespec now; 2682 int error; 2683 2684 #ifdef KTRACE 2685 /* if they're both UTIME_NOW, then don't report either */ 2686 if ((ts[0].tv_nsec != UTIME_NOW || ts[1].tv_nsec != UTIME_NOW) && 2687 KTRPOINT(p, KTR_STRUCT)) { 2688 ktrabstimespec(p, &ts[0]); 2689 ktrabstimespec(p, &ts[1]); 2690 } 2691 #endif 2692 2693 VATTR_NULL(&vattr); 2694 2695 /* make sure ctime is updated even if neither mtime nor atime is */ 2696 vattr.va_vaflags = VA_UTIMES_CHANGE; 2697 2698 if (ts[0].tv_nsec == UTIME_NOW || ts[1].tv_nsec == UTIME_NOW) { 2699 if (ts[0].tv_nsec == UTIME_NOW && ts[1].tv_nsec == UTIME_NOW) 2700 vattr.va_vaflags |= VA_UTIMES_NULL; 2701 2702 getnanotime(&now); 2703 if (ts[0].tv_nsec == UTIME_NOW) 2704 ts[0] = now; 2705 if (ts[1].tv_nsec == UTIME_NOW) 2706 ts[1] = now; 2707 } 2708 2709 if (ts[0].tv_nsec != UTIME_OMIT) 2710 vattr.va_atime = ts[0]; 2711 if (ts[1].tv_nsec != UTIME_OMIT) 2712 vattr.va_mtime = ts[1]; 2713 2714 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 2715 if (vp->v_mount->mnt_flag & MNT_RDONLY) 2716 error = EROFS; 2717 else 2718 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 2719 vput(vp); 2720 return (error); 2721 } 2722 2723 /* 2724 * Set the access and modification times given a file descriptor. 2725 */ 2726 int 2727 sys_futimes(struct proc *p, void *v, register_t *retval) 2728 { 2729 struct sys_futimes_args /* { 2730 syscallarg(int) fd; 2731 syscallarg(const struct timeval *) tptr; 2732 } */ *uap = v; 2733 struct timeval tv[2]; 2734 struct timespec ts[2]; 2735 const struct timeval *tvp; 2736 int error; 2737 2738 tvp = SCARG(uap, tptr); 2739 if (tvp != NULL) { 2740 error = copyin(tvp, tv, sizeof(tv)); 2741 if (error) 2742 return (error); 2743 #ifdef KTRACE 2744 if (KTRPOINT(p, KTR_STRUCT)) { 2745 ktrabstimeval(p, &tv[0]); 2746 ktrabstimeval(p, &tv[1]); 2747 } 2748 #endif 2749 if (!timerisvalid(&tv[0]) || !timerisvalid(&tv[1])) 2750 return (EINVAL); 2751 TIMEVAL_TO_TIMESPEC(&tv[0], &ts[0]); 2752 TIMEVAL_TO_TIMESPEC(&tv[1], &ts[1]); 2753 } else 2754 ts[0].tv_nsec = ts[1].tv_nsec = UTIME_NOW; 2755 2756 return (dofutimens(p, SCARG(uap, fd), ts)); 2757 } 2758 2759 int 2760 sys_futimens(struct proc *p, void *v, register_t *retval) 2761 { 2762 struct sys_futimens_args /* { 2763 syscallarg(int) fd; 2764 syscallarg(const struct timespec *) times; 2765 } */ *uap = v; 2766 struct timespec ts[2]; 2767 const struct timespec *tsp; 2768 int error, i; 2769 2770 tsp = SCARG(uap, times); 2771 if (tsp != NULL) { 2772 error = copyin(tsp, ts, sizeof(ts)); 2773 if (error) 2774 return (error); 2775 for (i = 0; i < nitems(ts); i++) { 2776 if (ts[i].tv_nsec == UTIME_NOW) 2777 continue; 2778 if (ts[i].tv_nsec == UTIME_OMIT) 2779 continue; 2780 #ifdef KTRACE 2781 if (KTRPOINT(p, KTR_STRUCT)) 2782 ktrabstimespec(p, &ts[i]); 2783 #endif 2784 if (!timespecisvalid(&ts[i])) 2785 return (EINVAL); 2786 } 2787 } else 2788 ts[0].tv_nsec = ts[1].tv_nsec = UTIME_NOW; 2789 2790 return (dofutimens(p, SCARG(uap, fd), ts)); 2791 } 2792 2793 int 2794 dofutimens(struct proc *p, int fd, struct timespec ts[2]) 2795 { 2796 struct file *fp; 2797 struct vnode *vp; 2798 int error; 2799 2800 if ((error = getvnode(p, fd, &fp)) != 0) 2801 return (error); 2802 vp = fp->f_data; 2803 vref(vp); 2804 FRELE(fp, p); 2805 2806 return (dovutimens(p, vp, ts)); 2807 } 2808 2809 /* 2810 * Truncate a file given a vnode. 2811 */ 2812 int 2813 dotruncate(struct proc *p, struct vnode *vp, off_t len) 2814 { 2815 struct vattr vattr; 2816 int error; 2817 2818 if (len < 0) 2819 return EINVAL; 2820 if (vp->v_type == VDIR) 2821 return EISDIR; 2822 if ((error = vn_writechk(vp)) != 0) 2823 return error; 2824 if (vp->v_type == VREG && len > lim_cur_proc(p, RLIMIT_FSIZE)) { 2825 if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) != 0) 2826 return error; 2827 if (len > vattr.va_size) { 2828 /* if extending over the limit, send signal and fail */ 2829 psignal(p, SIGXFSZ); 2830 return EFBIG; 2831 } 2832 } 2833 VATTR_NULL(&vattr); 2834 vattr.va_size = len; 2835 return VOP_SETATTR(vp, &vattr, p->p_ucred, p); 2836 } 2837 2838 /* 2839 * Truncate a file given its path name. 2840 */ 2841 int 2842 sys_truncate(struct proc *p, void *v, register_t *retval) 2843 { 2844 struct sys_truncate_args /* { 2845 syscallarg(const char *) path; 2846 syscallarg(off_t) length; 2847 } */ *uap = v; 2848 struct vnode *vp; 2849 int error; 2850 struct nameidata nd; 2851 2852 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 2853 nd.ni_pledge = PLEDGE_FATTR | PLEDGE_RPATH; 2854 nd.ni_unveil = UNVEIL_WRITE; 2855 if ((error = namei(&nd)) != 0) 2856 return (error); 2857 vp = nd.ni_vp; 2858 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 2859 if ((error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) 2860 error = dotruncate(p, vp, SCARG(uap, length)); 2861 vput(vp); 2862 return (error); 2863 } 2864 2865 /* 2866 * Truncate a file given a file descriptor. 2867 */ 2868 int 2869 sys_ftruncate(struct proc *p, void *v, register_t *retval) 2870 { 2871 struct sys_ftruncate_args /* { 2872 syscallarg(int) fd; 2873 syscallarg(off_t) length; 2874 } */ *uap = v; 2875 struct vnode *vp; 2876 struct file *fp; 2877 int error; 2878 2879 if ((error = getvnode(p, SCARG(uap, fd), &fp)) != 0) 2880 return (error); 2881 if ((fp->f_flag & FWRITE) == 0) { 2882 error = EINVAL; 2883 goto bad; 2884 } 2885 vp = fp->f_data; 2886 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 2887 error = dotruncate(p, vp, SCARG(uap, length)); 2888 VOP_UNLOCK(vp); 2889 bad: 2890 FRELE(fp, p); 2891 return (error); 2892 } 2893 2894 #if 1 2895 int 2896 sys_pad_truncate(struct proc *p, void *v, register_t *retval) 2897 { 2898 struct sys_pad_truncate_args *uap = v; 2899 struct sys_truncate_args unpad; 2900 2901 SCARG(&unpad, path) = SCARG(uap, path); 2902 SCARG(&unpad, length) = SCARG(uap, length); 2903 return sys_truncate(p, &unpad, retval); 2904 } 2905 2906 int 2907 sys_pad_ftruncate(struct proc *p, void *v, register_t *retval) 2908 { 2909 struct sys_pad_ftruncate_args *uap = v; 2910 struct sys_ftruncate_args unpad; 2911 2912 SCARG(&unpad, fd) = SCARG(uap, fd); 2913 SCARG(&unpad, length) = SCARG(uap, length); 2914 return sys_ftruncate(p, &unpad, retval); 2915 } 2916 #endif 2917 2918 /* 2919 * Sync an open file. 2920 */ 2921 int 2922 sys_fsync(struct proc *p, void *v, register_t *retval) 2923 { 2924 struct sys_fsync_args /* { 2925 syscallarg(int) fd; 2926 } */ *uap = v; 2927 struct vnode *vp; 2928 struct file *fp; 2929 int error; 2930 2931 if ((error = getvnode(p, SCARG(uap, fd), &fp)) != 0) 2932 return (error); 2933 vp = fp->f_data; 2934 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 2935 error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p); 2936 #ifdef FFS_SOFTUPDATES 2937 if (error == 0 && vp->v_mount && (vp->v_mount->mnt_flag & MNT_SOFTDEP)) 2938 error = softdep_fsync(vp); 2939 #endif 2940 2941 VOP_UNLOCK(vp); 2942 FRELE(fp, p); 2943 return (error); 2944 } 2945 2946 /* 2947 * Rename files. Source and destination must either both be directories, 2948 * or both not be directories. If target is a directory, it must be empty. 2949 */ 2950 int 2951 sys_rename(struct proc *p, void *v, register_t *retval) 2952 { 2953 struct sys_rename_args /* { 2954 syscallarg(const char *) from; 2955 syscallarg(const char *) to; 2956 } */ *uap = v; 2957 2958 return (dorenameat(p, AT_FDCWD, SCARG(uap, from), AT_FDCWD, 2959 SCARG(uap, to))); 2960 } 2961 2962 int 2963 sys_renameat(struct proc *p, void *v, register_t *retval) 2964 { 2965 struct sys_renameat_args /* { 2966 syscallarg(int) fromfd; 2967 syscallarg(const char *) from; 2968 syscallarg(int) tofd; 2969 syscallarg(const char *) to; 2970 } */ *uap = v; 2971 2972 return (dorenameat(p, SCARG(uap, fromfd), SCARG(uap, from), 2973 SCARG(uap, tofd), SCARG(uap, to))); 2974 } 2975 2976 int 2977 dorenameat(struct proc *p, int fromfd, const char *from, int tofd, 2978 const char *to) 2979 { 2980 struct vnode *tvp, *fvp, *tdvp; 2981 struct nameidata fromnd, tond; 2982 int error; 2983 int flags; 2984 2985 NDINITAT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 2986 fromfd, from, p); 2987 fromnd.ni_pledge = PLEDGE_RPATH | PLEDGE_CPATH; 2988 fromnd.ni_unveil = UNVEIL_READ | UNVEIL_CREATE; 2989 if ((error = namei(&fromnd)) != 0) 2990 return (error); 2991 fvp = fromnd.ni_vp; 2992 2993 flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART; 2994 /* 2995 * rename("foo/", "bar/"); is OK 2996 */ 2997 if (fvp->v_type == VDIR) 2998 flags |= STRIPSLASHES; 2999 3000 NDINITAT(&tond, RENAME, flags, UIO_USERSPACE, tofd, to, p); 3001 tond.ni_pledge = PLEDGE_CPATH; 3002 tond.ni_unveil = UNVEIL_CREATE; 3003 if ((error = namei(&tond)) != 0) { 3004 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 3005 vrele(fromnd.ni_dvp); 3006 vrele(fvp); 3007 goto out1; 3008 } 3009 tdvp = tond.ni_dvp; 3010 tvp = tond.ni_vp; 3011 if (tvp != NULL) { 3012 if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 3013 error = ENOTDIR; 3014 goto out; 3015 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 3016 error = EISDIR; 3017 goto out; 3018 } 3019 } 3020 if (fvp == tdvp) 3021 error = EINVAL; 3022 /* 3023 * If source is the same as the destination (that is the 3024 * same inode number) 3025 */ 3026 if (fvp == tvp) 3027 error = -1; 3028 out: 3029 if (!error) { 3030 if (tvp) { 3031 (void)uvm_vnp_uncache(tvp); 3032 } 3033 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 3034 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 3035 } else { 3036 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 3037 if (tdvp == tvp) 3038 vrele(tdvp); 3039 else 3040 vput(tdvp); 3041 if (tvp) 3042 vput(tvp); 3043 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 3044 vrele(fromnd.ni_dvp); 3045 vrele(fvp); 3046 } 3047 vrele(tond.ni_startdir); 3048 pool_put(&namei_pool, tond.ni_cnd.cn_pnbuf); 3049 out1: 3050 if (fromnd.ni_startdir) 3051 vrele(fromnd.ni_startdir); 3052 pool_put(&namei_pool, fromnd.ni_cnd.cn_pnbuf); 3053 if (error == -1) 3054 return (0); 3055 return (error); 3056 } 3057 3058 /* 3059 * Make a directory file. 3060 */ 3061 int 3062 sys_mkdir(struct proc *p, void *v, register_t *retval) 3063 { 3064 struct sys_mkdir_args /* { 3065 syscallarg(const char *) path; 3066 syscallarg(mode_t) mode; 3067 } */ *uap = v; 3068 3069 return (domkdirat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, mode))); 3070 } 3071 3072 int 3073 sys_mkdirat(struct proc *p, void *v, register_t *retval) 3074 { 3075 struct sys_mkdirat_args /* { 3076 syscallarg(int) fd; 3077 syscallarg(const char *) path; 3078 syscallarg(mode_t) mode; 3079 } */ *uap = v; 3080 3081 return (domkdirat(p, SCARG(uap, fd), SCARG(uap, path), 3082 SCARG(uap, mode))); 3083 } 3084 3085 int 3086 domkdirat(struct proc *p, int fd, const char *path, mode_t mode) 3087 { 3088 struct vnode *vp; 3089 struct vattr vattr; 3090 int error; 3091 struct nameidata nd; 3092 3093 NDINITAT(&nd, CREATE, LOCKPARENT | STRIPSLASHES, UIO_USERSPACE, 3094 fd, path, p); 3095 nd.ni_pledge = PLEDGE_CPATH; 3096 nd.ni_unveil = UNVEIL_CREATE; 3097 if ((error = namei(&nd)) != 0) 3098 return (error); 3099 vp = nd.ni_vp; 3100 if (vp != NULL) { 3101 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 3102 if (nd.ni_dvp == vp) 3103 vrele(nd.ni_dvp); 3104 else 3105 vput(nd.ni_dvp); 3106 vrele(vp); 3107 return (EEXIST); 3108 } 3109 VATTR_NULL(&vattr); 3110 vattr.va_type = VDIR; 3111 vattr.va_mode = (mode & ACCESSPERMS) &~ p->p_fd->fd_cmask; 3112 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 3113 if (!error) 3114 vput(nd.ni_vp); 3115 return (error); 3116 } 3117 3118 /* 3119 * Remove a directory file. 3120 */ 3121 int 3122 sys_rmdir(struct proc *p, void *v, register_t *retval) 3123 { 3124 struct sys_rmdir_args /* { 3125 syscallarg(const char *) path; 3126 } */ *uap = v; 3127 3128 return (dounlinkat(p, AT_FDCWD, SCARG(uap, path), AT_REMOVEDIR)); 3129 } 3130 3131 /* 3132 * Read a block of directory entries in a file system independent format. 3133 */ 3134 int 3135 sys_getdents(struct proc *p, void *v, register_t *retval) 3136 { 3137 struct sys_getdents_args /* { 3138 syscallarg(int) fd; 3139 syscallarg(void *) buf; 3140 syscallarg(size_t) buflen; 3141 } */ *uap = v; 3142 struct vnode *vp; 3143 struct file *fp; 3144 struct uio auio; 3145 struct iovec aiov; 3146 size_t buflen; 3147 int error, eofflag; 3148 3149 buflen = SCARG(uap, buflen); 3150 3151 if (buflen > INT_MAX) 3152 return (EINVAL); 3153 if ((error = getvnode(p, SCARG(uap, fd), &fp)) != 0) 3154 return (error); 3155 if ((fp->f_flag & FREAD) == 0) { 3156 error = EBADF; 3157 goto bad; 3158 } 3159 vp = fp->f_data; 3160 if (vp->v_type != VDIR) { 3161 error = EINVAL; 3162 goto bad; 3163 } 3164 3165 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 3166 3167 if (fp->f_offset < 0) { 3168 VOP_UNLOCK(vp); 3169 error = EINVAL; 3170 goto bad; 3171 } 3172 3173 aiov.iov_base = SCARG(uap, buf); 3174 aiov.iov_len = buflen; 3175 auio.uio_iov = &aiov; 3176 auio.uio_iovcnt = 1; 3177 auio.uio_rw = UIO_READ; 3178 auio.uio_segflg = UIO_USERSPACE; 3179 auio.uio_procp = p; 3180 auio.uio_resid = buflen; 3181 auio.uio_offset = fp->f_offset; 3182 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag); 3183 mtx_enter(&fp->f_mtx); 3184 fp->f_offset = auio.uio_offset; 3185 mtx_leave(&fp->f_mtx); 3186 VOP_UNLOCK(vp); 3187 if (error) 3188 goto bad; 3189 *retval = buflen - auio.uio_resid; 3190 bad: 3191 FRELE(fp, p); 3192 return (error); 3193 } 3194 3195 /* 3196 * Set the mode mask for creation of filesystem nodes. 3197 */ 3198 int 3199 sys_umask(struct proc *p, void *v, register_t *retval) 3200 { 3201 struct sys_umask_args /* { 3202 syscallarg(mode_t) newmask; 3203 } */ *uap = v; 3204 struct filedesc *fdp = p->p_fd; 3205 3206 fdplock(fdp); 3207 *retval = fdp->fd_cmask; 3208 fdp->fd_cmask = SCARG(uap, newmask) & ACCESSPERMS; 3209 fdpunlock(fdp); 3210 return (0); 3211 } 3212 3213 /* 3214 * Void all references to file by ripping underlying filesystem 3215 * away from vnode. 3216 */ 3217 int 3218 sys_revoke(struct proc *p, void *v, register_t *retval) 3219 { 3220 struct sys_revoke_args /* { 3221 syscallarg(const char *) path; 3222 } */ *uap = v; 3223 struct vnode *vp; 3224 struct vattr vattr; 3225 int error; 3226 struct nameidata nd; 3227 3228 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 3229 nd.ni_pledge = PLEDGE_RPATH | PLEDGE_TTY; 3230 nd.ni_unveil = UNVEIL_READ; 3231 if ((error = namei(&nd)) != 0) 3232 return (error); 3233 vp = nd.ni_vp; 3234 if (vp->v_type != VCHR || (u_int)major(vp->v_rdev) >= nchrdev || 3235 cdevsw[major(vp->v_rdev)].d_type != D_TTY) { 3236 error = ENOTTY; 3237 goto out; 3238 } 3239 if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) != 0) 3240 goto out; 3241 if (p->p_ucred->cr_uid != vattr.va_uid && 3242 (error = suser(p))) 3243 goto out; 3244 if (vp->v_usecount > 1 || (vp->v_flag & (VALIASED))) 3245 VOP_REVOKE(vp, REVOKEALL); 3246 out: 3247 vrele(vp); 3248 return (error); 3249 } 3250 3251 /* 3252 * Convert a user file descriptor to a kernel file entry. 3253 * 3254 * On return *fpp is FREF:ed. 3255 */ 3256 int 3257 getvnode(struct proc *p, int fd, struct file **fpp) 3258 { 3259 struct file *fp; 3260 struct vnode *vp; 3261 3262 if ((fp = fd_getfile(p->p_fd, fd)) == NULL) 3263 return (EBADF); 3264 3265 if (fp->f_type != DTYPE_VNODE) { 3266 FRELE(fp, p); 3267 return (EINVAL); 3268 } 3269 3270 vp = fp->f_data; 3271 if (vp->v_type == VBAD) { 3272 FRELE(fp, p); 3273 return (EBADF); 3274 } 3275 3276 *fpp = fp; 3277 3278 return (0); 3279 } 3280 3281 /* 3282 * Positional read system call. 3283 */ 3284 int 3285 sys_pread(struct proc *p, void *v, register_t *retval) 3286 { 3287 struct sys_pread_args /* { 3288 syscallarg(int) fd; 3289 syscallarg(void *) buf; 3290 syscallarg(size_t) nbyte; 3291 syscallarg(off_t) offset; 3292 } */ *uap = v; 3293 struct iovec iov; 3294 struct uio auio; 3295 3296 iov.iov_base = SCARG(uap, buf); 3297 iov.iov_len = SCARG(uap, nbyte); 3298 if (iov.iov_len > SSIZE_MAX) 3299 return (EINVAL); 3300 3301 auio.uio_iov = &iov; 3302 auio.uio_iovcnt = 1; 3303 auio.uio_resid = iov.iov_len; 3304 auio.uio_offset = SCARG(uap, offset); 3305 3306 return (dofilereadv(p, SCARG(uap, fd), &auio, FO_POSITION, retval)); 3307 } 3308 3309 /* 3310 * Positional scatter read system call. 3311 */ 3312 int 3313 sys_preadv(struct proc *p, void *v, register_t *retval) 3314 { 3315 struct sys_preadv_args /* { 3316 syscallarg(int) fd; 3317 syscallarg(const struct iovec *) iovp; 3318 syscallarg(int) iovcnt; 3319 syscallarg(off_t) offset; 3320 } */ *uap = v; 3321 struct iovec aiov[UIO_SMALLIOV], *iov = NULL; 3322 int error, iovcnt = SCARG(uap, iovcnt); 3323 struct uio auio; 3324 size_t resid; 3325 3326 error = iovec_copyin(SCARG(uap, iovp), &iov, aiov, iovcnt, &resid); 3327 if (error) 3328 goto done; 3329 3330 auio.uio_iov = iov; 3331 auio.uio_iovcnt = iovcnt; 3332 auio.uio_resid = resid; 3333 auio.uio_offset = SCARG(uap, offset); 3334 3335 error = dofilereadv(p, SCARG(uap, fd), &auio, FO_POSITION, retval); 3336 done: 3337 iovec_free(iov, iovcnt); 3338 return (error); 3339 } 3340 3341 /* 3342 * Positional write system call. 3343 */ 3344 int 3345 sys_pwrite(struct proc *p, void *v, register_t *retval) 3346 { 3347 struct sys_pwrite_args /* { 3348 syscallarg(int) fd; 3349 syscallarg(const void *) buf; 3350 syscallarg(size_t) nbyte; 3351 syscallarg(off_t) offset; 3352 } */ *uap = v; 3353 struct iovec iov; 3354 struct uio auio; 3355 3356 iov.iov_base = (void *)SCARG(uap, buf); 3357 iov.iov_len = SCARG(uap, nbyte); 3358 if (iov.iov_len > SSIZE_MAX) 3359 return (EINVAL); 3360 3361 auio.uio_iov = &iov; 3362 auio.uio_iovcnt = 1; 3363 auio.uio_resid = iov.iov_len; 3364 auio.uio_offset = SCARG(uap, offset); 3365 3366 return (dofilewritev(p, SCARG(uap, fd), &auio, FO_POSITION, retval)); 3367 } 3368 3369 /* 3370 * Positional gather write system call. 3371 */ 3372 int 3373 sys_pwritev(struct proc *p, void *v, register_t *retval) 3374 { 3375 struct sys_pwritev_args /* { 3376 syscallarg(int) fd; 3377 syscallarg(const struct iovec *) iovp; 3378 syscallarg(int) iovcnt; 3379 syscallarg(off_t) offset; 3380 } */ *uap = v; 3381 struct iovec aiov[UIO_SMALLIOV], *iov = NULL; 3382 int error, iovcnt = SCARG(uap, iovcnt); 3383 struct uio auio; 3384 size_t resid; 3385 3386 error = iovec_copyin(SCARG(uap, iovp), &iov, aiov, iovcnt, &resid); 3387 if (error) 3388 goto done; 3389 3390 auio.uio_iov = iov; 3391 auio.uio_iovcnt = iovcnt; 3392 auio.uio_resid = resid; 3393 auio.uio_offset = SCARG(uap, offset); 3394 3395 error = dofilewritev(p, SCARG(uap, fd), &auio, FO_POSITION, retval); 3396 done: 3397 iovec_free(iov, iovcnt); 3398 return (error); 3399 } 3400 3401 #if 1 3402 int 3403 sys_pad_pread(struct proc *p, void *v, register_t *retval) 3404 { 3405 struct sys_pad_pread_args *uap = v; 3406 struct sys_pread_args unpad; 3407 3408 SCARG(&unpad, fd) = SCARG(uap, fd); 3409 SCARG(&unpad, buf) = SCARG(uap, buf); 3410 SCARG(&unpad, nbyte) = SCARG(uap, nbyte); 3411 SCARG(&unpad, offset) = SCARG(uap, offset); 3412 return sys_pread(p, &unpad, retval); 3413 } 3414 3415 int 3416 sys_pad_preadv(struct proc *p, void *v, register_t *retval) 3417 { 3418 struct sys_pad_preadv_args *uap = v; 3419 struct sys_preadv_args unpad; 3420 3421 SCARG(&unpad, fd) = SCARG(uap, fd); 3422 SCARG(&unpad, iovp) = SCARG(uap, iovp); 3423 SCARG(&unpad, iovcnt) = SCARG(uap, iovcnt); 3424 SCARG(&unpad, offset) = SCARG(uap, offset); 3425 return sys_preadv(p, &unpad, retval); 3426 } 3427 3428 int 3429 sys_pad_pwrite(struct proc *p, void *v, register_t *retval) 3430 { 3431 struct sys_pad_pwrite_args *uap = v; 3432 struct sys_pwrite_args unpad; 3433 3434 SCARG(&unpad, fd) = SCARG(uap, fd); 3435 SCARG(&unpad, buf) = SCARG(uap, buf); 3436 SCARG(&unpad, nbyte) = SCARG(uap, nbyte); 3437 SCARG(&unpad, offset) = SCARG(uap, offset); 3438 return sys_pwrite(p, &unpad, retval); 3439 } 3440 3441 int 3442 sys_pad_pwritev(struct proc *p, void *v, register_t *retval) 3443 { 3444 struct sys_pad_pwritev_args *uap = v; 3445 struct sys_pwritev_args unpad; 3446 3447 SCARG(&unpad, fd) = SCARG(uap, fd); 3448 SCARG(&unpad, iovp) = SCARG(uap, iovp); 3449 SCARG(&unpad, iovcnt) = SCARG(uap, iovcnt); 3450 SCARG(&unpad, offset) = SCARG(uap, offset); 3451 return sys_pwritev(p, &unpad, retval); 3452 } 3453 #endif 3454