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
Cache object: 200d5e9eb734aefd46cee12d10114a7c
|