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