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