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