Commit | Line | Data |
---|---|---|
da7c5cc6 | 1 | /* |
fc2aed1e KM |
2 | * Copyright (c) 1989 The Regents of the University of California. |
3 | * All rights reserved. | |
da7c5cc6 | 4 | * |
dbf0c423 | 5 | * %sccs.include.redist.c% |
fc2aed1e | 6 | * |
8429d022 | 7 | * @(#)vfs_syscalls.c 7.65 (Berkeley) %G% |
da7c5cc6 | 8 | */ |
6459ebe0 | 9 | |
94368568 JB |
10 | #include "param.h" |
11 | #include "systm.h" | |
8429d022 | 12 | #include "namei.h" |
5e00df3b | 13 | #include "filedesc.h" |
94368568 JB |
14 | #include "kernel.h" |
15 | #include "file.h" | |
16 | #include "stat.h" | |
fc2aed1e | 17 | #include "vnode.h" |
fc2aed1e | 18 | #include "mount.h" |
94368568 | 19 | #include "proc.h" |
94368568 | 20 | #include "uio.h" |
fc2aed1e | 21 | #include "malloc.h" |
88a7a62a | 22 | |
fc2aed1e KM |
23 | /* |
24 | * Virtual File System System Calls | |
25 | */ | |
3e78e260 | 26 | |
4f083fd7 | 27 | /* |
fc2aed1e | 28 | * mount system call |
4f083fd7 | 29 | */ |
6a6a1e5f KM |
30 | /* ARGSUSED */ |
31 | mount(p, uap, retval) | |
5e00df3b | 32 | struct proc *p; |
6a6a1e5f | 33 | register struct args { |
fc2aed1e KM |
34 | int type; |
35 | char *dir; | |
36 | int flags; | |
37 | caddr_t data; | |
6a6a1e5f KM |
38 | } *uap; |
39 | int *retval; | |
40 | { | |
8429d022 | 41 | register struct nameidata *ndp; |
d48157d5 KM |
42 | register struct vnode *vp; |
43 | register struct mount *mp; | |
47971887 | 44 | int error, flag; |
8429d022 | 45 | struct nameidata nd; |
3e78e260 | 46 | |
fc2aed1e KM |
47 | /* |
48 | * Must be super user | |
49 | */ | |
8429d022 MK |
50 | if (error = suser(p->p_ucred, &p->p_acflag)) |
51 | return (error); | |
fc2aed1e KM |
52 | /* |
53 | * Get vnode to be covered | |
54 | */ | |
8429d022 | 55 | ndp = &nd; |
fc2aed1e KM |
56 | ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; |
57 | ndp->ni_segflg = UIO_USERSPACE; | |
58 | ndp->ni_dirp = uap->dir; | |
8429d022 MK |
59 | if (error = namei(ndp, p)) |
60 | return (error); | |
fc2aed1e | 61 | vp = ndp->ni_vp; |
54fb9dc2 | 62 | if (uap->flags & MNT_UPDATE) { |
d48157d5 KM |
63 | if ((vp->v_flag & VROOT) == 0) { |
64 | vput(vp); | |
8429d022 | 65 | return (EINVAL); |
d48157d5 KM |
66 | } |
67 | mp = vp->v_mount; | |
68 | /* | |
69 | * We allow going from read-only to read-write, | |
70 | * but not from read-write to read-only. | |
71 | */ | |
54fb9dc2 KM |
72 | if ((mp->mnt_flag & MNT_RDONLY) == 0 && |
73 | (uap->flags & MNT_RDONLY) != 0) { | |
d48157d5 | 74 | vput(vp); |
8429d022 | 75 | return (EOPNOTSUPP); /* Needs translation */ |
d48157d5 | 76 | } |
54fb9dc2 KM |
77 | flag = mp->mnt_flag; |
78 | mp->mnt_flag |= MNT_UPDATE; | |
d48157d5 KM |
79 | VOP_UNLOCK(vp); |
80 | goto update; | |
81 | } | |
89cdb378 | 82 | vinvalbuf(vp, 1); |
8b81d198 | 83 | if (vp->v_usecount != 1) { |
fc2aed1e | 84 | vput(vp); |
8429d022 | 85 | return (EBUSY); |
fc2aed1e KM |
86 | } |
87 | if (vp->v_type != VDIR) { | |
88 | vput(vp); | |
8429d022 | 89 | return (ENOTDIR); |
fc2aed1e | 90 | } |
62d239e5 | 91 | if ((unsigned long)uap->type > MOUNT_MAXTYPE || |
fc2aed1e KM |
92 | vfssw[uap->type] == (struct vfsops *)0) { |
93 | vput(vp); | |
8429d022 | 94 | return (ENODEV); |
fc2aed1e KM |
95 | } |
96 | ||
97 | /* | |
d48157d5 | 98 | * Allocate and initialize the file system. |
fc2aed1e KM |
99 | */ |
100 | mp = (struct mount *)malloc((u_long)sizeof(struct mount), | |
101 | M_MOUNT, M_WAITOK); | |
54fb9dc2 KM |
102 | mp->mnt_op = vfssw[uap->type]; |
103 | mp->mnt_flag = 0; | |
104 | mp->mnt_exroot = 0; | |
105 | mp->mnt_mounth = NULLVP; | |
d48157d5 KM |
106 | if (error = vfs_lock(mp)) { |
107 | free((caddr_t)mp, M_MOUNT); | |
108 | vput(vp); | |
8429d022 | 109 | return (error); |
d48157d5 KM |
110 | } |
111 | if (vp->v_mountedhere != (struct mount *)0) { | |
112 | vfs_unlock(mp); | |
113 | free((caddr_t)mp, M_MOUNT); | |
114 | vput(vp); | |
8429d022 | 115 | return (EBUSY); |
d48157d5 | 116 | } |
d48157d5 | 117 | vp->v_mountedhere = mp; |
54fb9dc2 | 118 | mp->mnt_vnodecovered = vp; |
d48157d5 KM |
119 | update: |
120 | /* | |
121 | * Set the mount level flags. | |
122 | */ | |
54fb9dc2 KM |
123 | if (uap->flags & MNT_RDONLY) |
124 | mp->mnt_flag |= MNT_RDONLY; | |
d48157d5 | 125 | else |
54fb9dc2 KM |
126 | mp->mnt_flag &= ~MNT_RDONLY; |
127 | if (uap->flags & MNT_NOSUID) | |
128 | mp->mnt_flag |= MNT_NOSUID; | |
d48157d5 | 129 | else |
54fb9dc2 KM |
130 | mp->mnt_flag &= ~MNT_NOSUID; |
131 | if (uap->flags & MNT_NOEXEC) | |
132 | mp->mnt_flag |= MNT_NOEXEC; | |
d48157d5 | 133 | else |
54fb9dc2 KM |
134 | mp->mnt_flag &= ~MNT_NOEXEC; |
135 | if (uap->flags & MNT_NODEV) | |
136 | mp->mnt_flag |= MNT_NODEV; | |
d48157d5 | 137 | else |
54fb9dc2 KM |
138 | mp->mnt_flag &= ~MNT_NODEV; |
139 | if (uap->flags & MNT_SYNCHRONOUS) | |
140 | mp->mnt_flag |= MNT_SYNCHRONOUS; | |
d48157d5 | 141 | else |
54fb9dc2 | 142 | mp->mnt_flag &= ~MNT_SYNCHRONOUS; |
d48157d5 KM |
143 | /* |
144 | * Mount the filesystem. | |
145 | */ | |
146 | error = VFS_MOUNT(mp, uap->dir, uap->data, ndp); | |
54fb9dc2 KM |
147 | if (mp->mnt_flag & MNT_UPDATE) { |
148 | mp->mnt_flag &= ~MNT_UPDATE; | |
d48157d5 | 149 | vrele(vp); |
47971887 | 150 | if (error) |
54fb9dc2 | 151 | mp->mnt_flag = flag; |
8429d022 | 152 | return (error); |
d48157d5 | 153 | } |
92d0de98 KM |
154 | /* |
155 | * Put the new filesystem on the mount list after root. | |
156 | */ | |
54fb9dc2 KM |
157 | mp->mnt_next = rootfs->mnt_next; |
158 | mp->mnt_prev = rootfs; | |
159 | rootfs->mnt_next = mp; | |
160 | mp->mnt_next->mnt_prev = mp; | |
fc2aed1e | 161 | cache_purge(vp); |
fc2aed1e | 162 | if (!error) { |
d48157d5 | 163 | VOP_UNLOCK(vp); |
fc2aed1e | 164 | vfs_unlock(mp); |
97d8a528 | 165 | error = VFS_START(mp, 0); |
fc2aed1e KM |
166 | } else { |
167 | vfs_remove(mp); | |
168 | free((caddr_t)mp, M_MOUNT); | |
d48157d5 | 169 | vput(vp); |
fc2aed1e | 170 | } |
8429d022 | 171 | return (error); |
3e78e260 BJ |
172 | } |
173 | ||
4f083fd7 | 174 | /* |
fc2aed1e KM |
175 | * Unmount system call. |
176 | * | |
177 | * Note: unmount takes a path to the vnode mounted on as argument, | |
178 | * not special file (as before). | |
4f083fd7 | 179 | */ |
6a6a1e5f KM |
180 | /* ARGSUSED */ |
181 | unmount(p, uap, retval) | |
5e00df3b | 182 | struct proc *p; |
6a6a1e5f | 183 | register struct args { |
fc2aed1e KM |
184 | char *pathp; |
185 | int flags; | |
6a6a1e5f KM |
186 | } *uap; |
187 | int *retval; | |
188 | { | |
fc2aed1e | 189 | register struct vnode *vp; |
8429d022 | 190 | register struct nameidata *ndp; |
9151110e | 191 | struct mount *mp; |
fc2aed1e | 192 | int error; |
8429d022 | 193 | struct nameidata nd; |
fc2aed1e KM |
194 | |
195 | /* | |
196 | * Must be super user | |
197 | */ | |
8429d022 MK |
198 | if (error = suser(p->p_ucred, &p->p_acflag)) |
199 | return (error); | |
fc2aed1e | 200 | |
8429d022 | 201 | ndp = &nd; |
fc2aed1e KM |
202 | ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; |
203 | ndp->ni_segflg = UIO_USERSPACE; | |
204 | ndp->ni_dirp = uap->pathp; | |
8429d022 MK |
205 | if (error = namei(ndp, p)) |
206 | return (error); | |
fc2aed1e KM |
207 | vp = ndp->ni_vp; |
208 | /* | |
209 | * Must be the root of the filesystem | |
210 | */ | |
211 | if ((vp->v_flag & VROOT) == 0) { | |
212 | vput(vp); | |
8429d022 | 213 | return (EINVAL); |
fc2aed1e KM |
214 | } |
215 | mp = vp->v_mount; | |
216 | vput(vp); | |
8429d022 | 217 | return (dounmount(mp, uap->flags)); |
9151110e KM |
218 | } |
219 | ||
220 | /* | |
221 | * Do an unmount. | |
222 | */ | |
223 | dounmount(mp, flags) | |
224 | register struct mount *mp; | |
225 | int flags; | |
226 | { | |
227 | struct vnode *coveredvp; | |
228 | int error; | |
229 | ||
54fb9dc2 | 230 | coveredvp = mp->mnt_vnodecovered; |
c001b1c3 KM |
231 | if (vfs_busy(mp)) |
232 | return (EBUSY); | |
54fb9dc2 | 233 | mp->mnt_flag |= MNT_UNMOUNT; |
fc2aed1e | 234 | if (error = vfs_lock(mp)) |
9151110e | 235 | return (error); |
fc2aed1e | 236 | |
a42e0ed8 | 237 | #ifdef NVM |
9db58063 | 238 | vnode_pager_umount(mp); /* release cached vnodes */ |
a42e0ed8 KM |
239 | #else |
240 | xumount(mp); /* remove unused sticky files from text table */ | |
241 | #endif | |
fc2aed1e | 242 | cache_purgevfs(mp); /* remove cache entries for this file sys */ |
a99a44da KM |
243 | if ((error = VFS_SYNC(mp, MNT_WAIT)) == 0 || (flags & MNT_FORCE)) |
244 | error = VFS_UNMOUNT(mp, flags); | |
54fb9dc2 | 245 | mp->mnt_flag &= ~MNT_UNMOUNT; |
c001b1c3 | 246 | vfs_unbusy(mp); |
fc2aed1e KM |
247 | if (error) { |
248 | vfs_unlock(mp); | |
249 | } else { | |
250 | vrele(coveredvp); | |
251 | vfs_remove(mp); | |
252 | free((caddr_t)mp, M_MOUNT); | |
253 | } | |
9151110e | 254 | return (error); |
fc2aed1e KM |
255 | } |
256 | ||
257 | /* | |
258 | * Sync system call. | |
259 | * Sync each mounted filesystem. | |
260 | */ | |
ff4fb102 | 261 | /* ARGSUSED */ |
6a6a1e5f | 262 | sync(p, uap, retval) |
5e00df3b | 263 | struct proc *p; |
8429d022 | 264 | void *uap; |
6a6a1e5f | 265 | int *retval; |
3e78e260 | 266 | { |
fc2aed1e | 267 | register struct mount *mp; |
c001b1c3 | 268 | struct mount *omp; |
fc2aed1e KM |
269 | |
270 | mp = rootfs; | |
271 | do { | |
62e35d50 KM |
272 | /* |
273 | * The lock check below is to avoid races with mount | |
274 | * and unmount. | |
275 | */ | |
54fb9dc2 | 276 | if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && |
c001b1c3 | 277 | !vfs_busy(mp)) { |
fc2aed1e | 278 | VFS_SYNC(mp, MNT_NOWAIT); |
c001b1c3 | 279 | omp = mp; |
54fb9dc2 | 280 | mp = mp->mnt_next; |
c001b1c3 KM |
281 | vfs_unbusy(omp); |
282 | } else | |
54fb9dc2 | 283 | mp = mp->mnt_next; |
fc2aed1e KM |
284 | } while (mp != rootfs); |
285 | } | |
286 | ||
c001b1c3 KM |
287 | /* |
288 | * operate on filesystem quotas | |
289 | */ | |
6a6a1e5f KM |
290 | /* ARGSUSED */ |
291 | quotactl(p, uap, retval) | |
5e00df3b | 292 | struct proc *p; |
6a6a1e5f | 293 | register struct args { |
c001b1c3 KM |
294 | char *path; |
295 | int cmd; | |
296 | int uid; | |
297 | caddr_t arg; | |
6a6a1e5f KM |
298 | } *uap; |
299 | int *retval; | |
300 | { | |
c001b1c3 | 301 | register struct mount *mp; |
8429d022 | 302 | register struct nameidata *ndp; |
c001b1c3 | 303 | int error; |
8429d022 | 304 | struct nameidata nd; |
c001b1c3 | 305 | |
8429d022 | 306 | ndp = &nd; |
c001b1c3 KM |
307 | ndp->ni_nameiop = LOOKUP | FOLLOW; |
308 | ndp->ni_segflg = UIO_USERSPACE; | |
309 | ndp->ni_dirp = uap->path; | |
8429d022 MK |
310 | if (error = namei(ndp, p)) |
311 | return (error); | |
c001b1c3 KM |
312 | mp = ndp->ni_vp->v_mount; |
313 | vrele(ndp->ni_vp); | |
8429d022 | 314 | return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg)); |
c001b1c3 KM |
315 | } |
316 | ||
fc2aed1e KM |
317 | /* |
318 | * get filesystem statistics | |
319 | */ | |
6a6a1e5f KM |
320 | /* ARGSUSED */ |
321 | statfs(p, uap, retval) | |
5e00df3b | 322 | struct proc *p; |
6a6a1e5f | 323 | register struct args { |
fc2aed1e KM |
324 | char *path; |
325 | struct statfs *buf; | |
6a6a1e5f KM |
326 | } *uap; |
327 | int *retval; | |
328 | { | |
3f705640 | 329 | register struct mount *mp; |
8429d022 | 330 | register struct nameidata *ndp; |
62e35d50 | 331 | register struct statfs *sp; |
fc2aed1e | 332 | int error; |
8429d022 | 333 | struct nameidata nd; |
3e78e260 | 334 | |
8429d022 | 335 | ndp = &nd; |
e114af99 | 336 | ndp->ni_nameiop = LOOKUP | FOLLOW; |
fc2aed1e KM |
337 | ndp->ni_segflg = UIO_USERSPACE; |
338 | ndp->ni_dirp = uap->path; | |
8429d022 MK |
339 | if (error = namei(ndp, p)) |
340 | return (error); | |
e114af99 | 341 | mp = ndp->ni_vp->v_mount; |
54fb9dc2 | 342 | sp = &mp->mnt_stat; |
e114af99 | 343 | vrele(ndp->ni_vp); |
62e35d50 | 344 | if (error = VFS_STATFS(mp, sp)) |
8429d022 | 345 | return (error); |
54fb9dc2 | 346 | sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; |
8429d022 | 347 | return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); |
fc2aed1e KM |
348 | } |
349 | ||
6a6a1e5f KM |
350 | /* |
351 | * get filesystem statistics | |
352 | */ | |
353 | /* ARGSUSED */ | |
354 | fstatfs(p, uap, retval) | |
5e00df3b | 355 | struct proc *p; |
6a6a1e5f | 356 | register struct args { |
fc2aed1e KM |
357 | int fd; |
358 | struct statfs *buf; | |
6a6a1e5f KM |
359 | } *uap; |
360 | int *retval; | |
361 | { | |
fc2aed1e | 362 | struct file *fp; |
3f705640 | 363 | struct mount *mp; |
62e35d50 | 364 | register struct statfs *sp; |
fc2aed1e KM |
365 | int error; |
366 | ||
5e00df3b | 367 | if (error = getvnode(p->p_fd, uap->fd, &fp)) |
8429d022 | 368 | return (error); |
3f705640 | 369 | mp = ((struct vnode *)fp->f_data)->v_mount; |
54fb9dc2 | 370 | sp = &mp->mnt_stat; |
62e35d50 | 371 | if (error = VFS_STATFS(mp, sp)) |
8429d022 | 372 | return (error); |
54fb9dc2 | 373 | sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; |
8429d022 | 374 | return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); |
3e78e260 BJ |
375 | } |
376 | ||
bfcdbfbf KM |
377 | /* |
378 | * get statistics on all filesystems | |
379 | */ | |
6a6a1e5f | 380 | getfsstat(p, uap, retval) |
5e00df3b | 381 | struct proc *p; |
6a6a1e5f | 382 | register struct args { |
bfcdbfbf KM |
383 | struct statfs *buf; |
384 | long bufsize; | |
62e35d50 | 385 | int flags; |
6a6a1e5f KM |
386 | } *uap; |
387 | int *retval; | |
388 | { | |
bfcdbfbf | 389 | register struct mount *mp; |
62e35d50 | 390 | register struct statfs *sp; |
f62fad9a | 391 | caddr_t sfsp; |
bfcdbfbf KM |
392 | long count, maxcount, error; |
393 | ||
394 | maxcount = uap->bufsize / sizeof(struct statfs); | |
f62fad9a | 395 | sfsp = (caddr_t)uap->buf; |
bfcdbfbf KM |
396 | mp = rootfs; |
397 | count = 0; | |
398 | do { | |
54fb9dc2 KM |
399 | if (sfsp && count < maxcount && |
400 | ((mp->mnt_flag & MNT_MLOCK) == 0)) { | |
401 | sp = &mp->mnt_stat; | |
62e35d50 KM |
402 | /* |
403 | * If MNT_NOWAIT is specified, do not refresh the | |
404 | * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. | |
405 | */ | |
406 | if (((uap->flags & MNT_NOWAIT) == 0 || | |
407 | (uap->flags & MNT_WAIT)) && | |
408 | (error = VFS_STATFS(mp, sp))) { | |
54fb9dc2 | 409 | mp = mp->mnt_prev; |
fd8516be KM |
410 | continue; |
411 | } | |
54fb9dc2 | 412 | sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; |
62e35d50 | 413 | if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) |
8429d022 | 414 | return (error); |
62e35d50 | 415 | sfsp += sizeof(*sp); |
bfcdbfbf | 416 | } |
f62fad9a | 417 | count++; |
54fb9dc2 | 418 | mp = mp->mnt_prev; |
bfcdbfbf KM |
419 | } while (mp != rootfs); |
420 | if (sfsp && count > maxcount) | |
6a6a1e5f | 421 | *retval = maxcount; |
bfcdbfbf | 422 | else |
6a6a1e5f | 423 | *retval = count; |
8429d022 | 424 | return (0); |
bfcdbfbf KM |
425 | } |
426 | ||
6995a2cb KM |
427 | /* |
428 | * Change current working directory to a given file descriptor. | |
429 | */ | |
6a6a1e5f KM |
430 | /* ARGSUSED */ |
431 | fchdir(p, uap, retval) | |
5e00df3b | 432 | struct proc *p; |
6a6a1e5f | 433 | struct args { |
6995a2cb | 434 | int fd; |
6a6a1e5f KM |
435 | } *uap; |
436 | int *retval; | |
437 | { | |
5e00df3b | 438 | register struct filedesc *fdp = p->p_fd; |
6995a2cb KM |
439 | register struct vnode *vp; |
440 | struct file *fp; | |
441 | int error; | |
442 | ||
5e00df3b | 443 | if (error = getvnode(fdp, uap->fd, &fp)) |
8429d022 | 444 | return (error); |
6995a2cb KM |
445 | vp = (struct vnode *)fp->f_data; |
446 | VOP_LOCK(vp); | |
447 | if (vp->v_type != VDIR) | |
448 | error = ENOTDIR; | |
449 | else | |
8429d022 | 450 | error = VOP_ACCESS(vp, VEXEC, p->p_ucred); |
6995a2cb | 451 | VOP_UNLOCK(vp); |
ab214c34 | 452 | if (error) |
8429d022 | 453 | return (error); |
ab214c34 | 454 | VREF(vp); |
5e00df3b KM |
455 | vrele(fdp->fd_cdir); |
456 | fdp->fd_cdir = vp; | |
8429d022 | 457 | return (0); |
6995a2cb KM |
458 | } |
459 | ||
4f083fd7 | 460 | /* |
fc2aed1e | 461 | * Change current working directory (``.''). |
4f083fd7 | 462 | */ |
6a6a1e5f KM |
463 | /* ARGSUSED */ |
464 | chdir(p, uap, retval) | |
5e00df3b | 465 | struct proc *p; |
6a6a1e5f | 466 | struct args { |
3e78e260 | 467 | char *fname; |
6a6a1e5f KM |
468 | } *uap; |
469 | int *retval; | |
470 | { | |
8429d022 | 471 | register struct nameidata *ndp; |
5e00df3b | 472 | register struct filedesc *fdp = p->p_fd; |
fc2aed1e | 473 | int error; |
8429d022 | 474 | struct nameidata nd; |
3e78e260 | 475 | |
8429d022 | 476 | ndp = &nd; |
fc2aed1e | 477 | ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; |
715baff1 KM |
478 | ndp->ni_segflg = UIO_USERSPACE; |
479 | ndp->ni_dirp = uap->fname; | |
8429d022 MK |
480 | if (error = chdirec(ndp, p)) |
481 | return (error); | |
5e00df3b KM |
482 | vrele(fdp->fd_cdir); |
483 | fdp->fd_cdir = ndp->ni_vp; | |
8429d022 | 484 | return (0); |
fc2aed1e KM |
485 | } |
486 | ||
487 | /* | |
488 | * Change notion of root (``/'') directory. | |
489 | */ | |
6a6a1e5f KM |
490 | /* ARGSUSED */ |
491 | chroot(p, uap, retval) | |
5e00df3b | 492 | struct proc *p; |
6a6a1e5f | 493 | struct args { |
fc2aed1e | 494 | char *fname; |
6a6a1e5f KM |
495 | } *uap; |
496 | int *retval; | |
497 | { | |
8429d022 | 498 | register struct nameidata *ndp; |
5e00df3b | 499 | register struct filedesc *fdp = p->p_fd; |
fc2aed1e | 500 | int error; |
8429d022 | 501 | struct nameidata nd; |
fc2aed1e | 502 | |
8429d022 MK |
503 | if (error = suser(p->p_ucred, &p->p_acflag)) |
504 | return (error); | |
505 | ndp = &nd; | |
fc2aed1e KM |
506 | ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; |
507 | ndp->ni_segflg = UIO_USERSPACE; | |
508 | ndp->ni_dirp = uap->fname; | |
8429d022 MK |
509 | if (error = chdirec(ndp, p)) |
510 | return (error); | |
5e00df3b KM |
511 | if (fdp->fd_rdir != NULL) |
512 | vrele(fdp->fd_rdir); | |
513 | fdp->fd_rdir = ndp->ni_vp; | |
8429d022 | 514 | return (0); |
fc2aed1e KM |
515 | } |
516 | ||
517 | /* | |
518 | * Common routine for chroot and chdir. | |
519 | */ | |
8429d022 MK |
520 | chdirec(ndp, p) |
521 | struct nameidata *ndp; | |
522 | struct proc *p; | |
fc2aed1e KM |
523 | { |
524 | struct vnode *vp; | |
525 | int error; | |
526 | ||
8429d022 | 527 | if (error = namei(ndp, p)) |
fc2aed1e KM |
528 | return (error); |
529 | vp = ndp->ni_vp; | |
530 | if (vp->v_type != VDIR) | |
531 | error = ENOTDIR; | |
532 | else | |
8429d022 | 533 | error = VOP_ACCESS(vp, VEXEC, p->p_ucred); |
fc2aed1e KM |
534 | VOP_UNLOCK(vp); |
535 | if (error) | |
536 | vrele(vp); | |
537 | return (error); | |
3e78e260 BJ |
538 | } |
539 | ||
540 | /* | |
541 | * Open system call. | |
6a6a1e5f KM |
542 | * Check permissions, allocate an open file structure, |
543 | * and call the device open routine if any. | |
3e78e260 | 544 | */ |
6a6a1e5f | 545 | open(p, uap, retval) |
5e00df3b | 546 | struct proc *p; |
6a6a1e5f | 547 | register struct args { |
3e78e260 | 548 | char *fname; |
528f664c | 549 | int mode; |
88a7a62a | 550 | int crtmode; |
6a6a1e5f KM |
551 | } *uap; |
552 | int *retval; | |
3e78e260 | 553 | { |
8429d022 | 554 | struct nameidata *ndp; |
5e00df3b | 555 | register struct filedesc *fdp = p->p_fd; |
3e78e260 | 556 | register struct file *fp; |
6a6a1e5f | 557 | int fmode, cmode; |
fc2aed1e KM |
558 | struct file *nfp; |
559 | int indx, error; | |
8429d022 | 560 | struct nameidata nd; |
fc2aed1e KM |
561 | extern struct fileops vnops; |
562 | ||
5e00df3b | 563 | if (error = falloc(p, &nfp, &indx)) |
8429d022 | 564 | return (error); |
fc2aed1e | 565 | fp = nfp; |
13b8b20b | 566 | fmode = FFLAGS(uap->mode); |
5e00df3b | 567 | cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX; |
8429d022 | 568 | ndp = &nd; |
6a6a1e5f KM |
569 | ndp->ni_segflg = UIO_USERSPACE; |
570 | ndp->ni_dirp = uap->fname; | |
03951846 | 571 | p->p_dupfd = -indx - 1; /* XXX check for fdopen */ |
8429d022 | 572 | if (error = vn_open(ndp, p, fmode, cmode)) { |
fc2aed1e KM |
573 | crfree(fp->f_cred); |
574 | fp->f_count--; | |
198ba51a | 575 | if (error == ENODEV && /* XXX from fdopen */ |
03951846 | 576 | p->p_dupfd >= 0 && |
5e00df3b | 577 | (error = dupfdopen(fdp, indx, p->p_dupfd, fmode)) == 0) { |
6a6a1e5f | 578 | *retval = indx; |
8429d022 | 579 | return (0); |
6a6a1e5f | 580 | } |
b10521d6 KM |
581 | if (error == ERESTART) |
582 | error = EINTR; | |
5e00df3b | 583 | OFILE(fdp, indx) = NULL; |
8429d022 | 584 | return (error); |
528f664c | 585 | } |
fc2aed1e KM |
586 | fp->f_flag = fmode & FMASK; |
587 | fp->f_type = DTYPE_VNODE; | |
588 | fp->f_ops = &vnops; | |
589 | fp->f_data = (caddr_t)ndp->ni_vp; | |
6a6a1e5f | 590 | *retval = indx; |
8429d022 | 591 | return (0); |
3e78e260 BJ |
592 | } |
593 | ||
4fde03dc | 594 | #ifdef COMPAT_43 |
3e78e260 | 595 | /* |
6a6a1e5f | 596 | * Creat system call. |
3e78e260 | 597 | */ |
4fde03dc | 598 | ocreat(p, uap, retval) |
6a6a1e5f KM |
599 | struct proc *p; |
600 | register struct args { | |
601 | char *fname; | |
602 | int fmode; | |
603 | } *uap; | |
604 | int *retval; | |
3e78e260 | 605 | { |
6a6a1e5f KM |
606 | struct args { |
607 | char *fname; | |
608 | int mode; | |
609 | int crtmode; | |
610 | } openuap; | |
611 | ||
612 | openuap.fname = uap->fname; | |
613 | openuap.crtmode = uap->fmode; | |
614 | openuap.mode = O_WRONLY | O_CREAT | O_TRUNC; | |
8429d022 | 615 | return (open(p, &openuap, retval)); |
6a6a1e5f | 616 | } |
4fde03dc | 617 | #endif /* COMPAT_43 */ |
6a6a1e5f KM |
618 | |
619 | /* | |
620 | * Mknod system call | |
621 | */ | |
622 | /* ARGSUSED */ | |
623 | mknod(p, uap, retval) | |
5e00df3b | 624 | struct proc *p; |
6a6a1e5f | 625 | register struct args { |
3e78e260 BJ |
626 | char *fname; |
627 | int fmode; | |
628 | int dev; | |
6a6a1e5f KM |
629 | } *uap; |
630 | int *retval; | |
631 | { | |
8429d022 | 632 | register struct nameidata *ndp; |
fc2aed1e KM |
633 | register struct vnode *vp; |
634 | struct vattr vattr; | |
635 | int error; | |
8429d022 | 636 | struct nameidata nd; |
3e78e260 | 637 | |
8429d022 MK |
638 | if (error = suser(p->p_ucred, &p->p_acflag)) |
639 | return (error); | |
640 | ndp = &nd; | |
fc2aed1e | 641 | ndp->ni_nameiop = CREATE | LOCKPARENT; |
715baff1 KM |
642 | ndp->ni_segflg = UIO_USERSPACE; |
643 | ndp->ni_dirp = uap->fname; | |
8429d022 MK |
644 | if (error = namei(ndp, p)) |
645 | return (error); | |
fc2aed1e KM |
646 | vp = ndp->ni_vp; |
647 | if (vp != NULL) { | |
648 | error = EEXIST; | |
88a7a62a | 649 | goto out; |
3e78e260 | 650 | } |
3ee1461b | 651 | VATTR_NULL(&vattr); |
ab389897 | 652 | switch (uap->fmode & S_IFMT) { |
88a7a62a | 653 | |
ab389897 | 654 | case S_IFMT: /* used by badsect to flag bad sectors */ |
fc2aed1e KM |
655 | vattr.va_type = VBAD; |
656 | break; | |
ab389897 | 657 | case S_IFCHR: |
fc2aed1e KM |
658 | vattr.va_type = VCHR; |
659 | break; | |
ab389897 | 660 | case S_IFBLK: |
fc2aed1e KM |
661 | vattr.va_type = VBLK; |
662 | break; | |
663 | default: | |
664 | error = EINVAL; | |
665 | goto out; | |
3e78e260 | 666 | } |
5e00df3b | 667 | vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; |
fc2aed1e | 668 | vattr.va_rdev = uap->dev; |
3e78e260 | 669 | out: |
66955caf | 670 | if (!error) { |
8429d022 | 671 | error = VOP_MKNOD(ndp, &vattr, p->p_ucred); |
66955caf KM |
672 | } else { |
673 | VOP_ABORTOP(ndp); | |
6c44e83b KM |
674 | if (ndp->ni_dvp == vp) |
675 | vrele(ndp->ni_dvp); | |
676 | else | |
677 | vput(ndp->ni_dvp); | |
66955caf KM |
678 | if (vp) |
679 | vrele(vp); | |
680 | } | |
8429d022 | 681 | return (error); |
3e78e260 BJ |
682 | } |
683 | ||
4751dd21 KM |
684 | /* |
685 | * Mkfifo system call | |
686 | */ | |
6a6a1e5f KM |
687 | /* ARGSUSED */ |
688 | mkfifo(p, uap, retval) | |
5e00df3b | 689 | struct proc *p; |
6a6a1e5f | 690 | register struct args { |
4751dd21 KM |
691 | char *fname; |
692 | int fmode; | |
6a6a1e5f KM |
693 | } *uap; |
694 | int *retval; | |
695 | { | |
8429d022 | 696 | register struct nameidata *ndp; |
4751dd21 KM |
697 | struct vattr vattr; |
698 | int error; | |
8429d022 | 699 | struct nameidata nd; |
4751dd21 KM |
700 | |
701 | #ifndef FIFO | |
8429d022 | 702 | return (EOPNOTSUPP); |
4751dd21 | 703 | #else |
8429d022 | 704 | ndp = &nd; |
4751dd21 KM |
705 | ndp->ni_nameiop = CREATE | LOCKPARENT; |
706 | ndp->ni_segflg = UIO_USERSPACE; | |
707 | ndp->ni_dirp = uap->fname; | |
8429d022 MK |
708 | if (error = namei(ndp, p)) |
709 | return (error); | |
4751dd21 KM |
710 | if (ndp->ni_vp != NULL) { |
711 | VOP_ABORTOP(ndp); | |
6c44e83b KM |
712 | if (ndp->ni_dvp == ndp->ni_vp) |
713 | vrele(ndp->ni_dvp); | |
714 | else | |
715 | vput(ndp->ni_dvp); | |
66955caf | 716 | vrele(ndp->ni_vp); |
8429d022 | 717 | return (EEXIST); |
4751dd21 | 718 | } |
3658f091 KB |
719 | VATTR_NULL(&vattr); |
720 | vattr.va_type = VFIFO; | |
5e00df3b | 721 | vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; |
8429d022 | 722 | return (VOP_MKNOD(ndp, &vattr, p->p_ucred)); |
4751dd21 KM |
723 | #endif /* FIFO */ |
724 | } | |
725 | ||
3e78e260 BJ |
726 | /* |
727 | * link system call | |
728 | */ | |
6a6a1e5f KM |
729 | /* ARGSUSED */ |
730 | link(p, uap, retval) | |
5e00df3b | 731 | struct proc *p; |
6a6a1e5f | 732 | register struct args { |
3e78e260 BJ |
733 | char *target; |
734 | char *linkname; | |
6a6a1e5f KM |
735 | } *uap; |
736 | int *retval; | |
737 | { | |
8429d022 | 738 | register struct nameidata *ndp; |
fc2aed1e KM |
739 | register struct vnode *vp, *xp; |
740 | int error; | |
8429d022 | 741 | struct nameidata nd; |
3e78e260 | 742 | |
8429d022 | 743 | ndp = &nd; |
715baff1 KM |
744 | ndp->ni_nameiop = LOOKUP | FOLLOW; |
745 | ndp->ni_segflg = UIO_USERSPACE; | |
746 | ndp->ni_dirp = uap->target; | |
8429d022 MK |
747 | if (error = namei(ndp, p)) |
748 | return (error); | |
fc2aed1e KM |
749 | vp = ndp->ni_vp; |
750 | if (vp->v_type == VDIR && | |
8429d022 | 751 | (error = suser(p->p_ucred, &p->p_acflag))) |
fc2aed1e KM |
752 | goto out1; |
753 | ndp->ni_nameiop = CREATE | LOCKPARENT; | |
715baff1 | 754 | ndp->ni_dirp = (caddr_t)uap->linkname; |
8429d022 | 755 | if (error = namei(ndp, p)) |
fc2aed1e KM |
756 | goto out1; |
757 | xp = ndp->ni_vp; | |
3e78e260 | 758 | if (xp != NULL) { |
fc2aed1e | 759 | error = EEXIST; |
3e78e260 BJ |
760 | goto out; |
761 | } | |
fc2aed1e KM |
762 | xp = ndp->ni_dvp; |
763 | if (vp->v_mount != xp->v_mount) | |
764 | error = EXDEV; | |
3e78e260 | 765 | out: |
66955caf | 766 | if (!error) { |
fc2aed1e | 767 | error = VOP_LINK(vp, ndp); |
66955caf KM |
768 | } else { |
769 | VOP_ABORTOP(ndp); | |
6c44e83b KM |
770 | if (ndp->ni_dvp == ndp->ni_vp) |
771 | vrele(ndp->ni_dvp); | |
772 | else | |
773 | vput(ndp->ni_dvp); | |
66955caf KM |
774 | if (ndp->ni_vp) |
775 | vrele(ndp->ni_vp); | |
776 | } | |
fc2aed1e KM |
777 | out1: |
778 | vrele(vp); | |
8429d022 | 779 | return (error); |
3e78e260 BJ |
780 | } |
781 | ||
782 | /* | |
783 | * symlink -- make a symbolic link | |
784 | */ | |
6a6a1e5f KM |
785 | /* ARGSUSED */ |
786 | symlink(p, uap, retval) | |
5e00df3b | 787 | struct proc *p; |
6a6a1e5f | 788 | register struct args { |
3e78e260 BJ |
789 | char *target; |
790 | char *linkname; | |
6a6a1e5f KM |
791 | } *uap; |
792 | int *retval; | |
793 | { | |
8429d022 | 794 | register struct nameidata *ndp; |
fc2aed1e KM |
795 | struct vattr vattr; |
796 | char *target; | |
797 | int error; | |
8429d022 | 798 | struct nameidata nd; |
3e78e260 | 799 | |
8429d022 | 800 | ndp = &nd; |
715baff1 KM |
801 | ndp->ni_segflg = UIO_USERSPACE; |
802 | ndp->ni_dirp = uap->linkname; | |
fc2aed1e KM |
803 | MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); |
804 | if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) | |
66955caf | 805 | goto out; |
fc2aed1e | 806 | ndp->ni_nameiop = CREATE | LOCKPARENT; |
8429d022 | 807 | if (error = namei(ndp, p)) |
66955caf KM |
808 | goto out; |
809 | if (ndp->ni_vp) { | |
810 | VOP_ABORTOP(ndp); | |
6c44e83b KM |
811 | if (ndp->ni_dvp == ndp->ni_vp) |
812 | vrele(ndp->ni_dvp); | |
813 | else | |
814 | vput(ndp->ni_dvp); | |
66955caf | 815 | vrele(ndp->ni_vp); |
fc2aed1e KM |
816 | error = EEXIST; |
817 | goto out; | |
3e78e260 | 818 | } |
3ee1461b | 819 | VATTR_NULL(&vattr); |
5e00df3b | 820 | vattr.va_mode = 0777 &~ p->p_fd->fd_cmask; |
66955caf | 821 | error = VOP_SYMLINK(ndp, &vattr, target); |
fc2aed1e | 822 | out: |
fc2aed1e | 823 | FREE(target, M_NAMEI); |
8429d022 | 824 | return (error); |
3e78e260 BJ |
825 | } |
826 | ||
827 | /* | |
828 | * Unlink system call. | |
829 | * Hard to avoid races here, especially | |
830 | * in unlinking directories. | |
831 | */ | |
6a6a1e5f KM |
832 | /* ARGSUSED */ |
833 | unlink(p, uap, retval) | |
5e00df3b | 834 | struct proc *p; |
6a6a1e5f | 835 | struct args { |
3e78e260 | 836 | char *fname; |
6a6a1e5f KM |
837 | } *uap; |
838 | int *retval; | |
839 | { | |
8429d022 | 840 | register struct nameidata *ndp; |
fc2aed1e KM |
841 | register struct vnode *vp; |
842 | int error; | |
8429d022 | 843 | struct nameidata nd; |
3e78e260 | 844 | |
8429d022 | 845 | ndp = &nd; |
fc2aed1e | 846 | ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; |
715baff1 KM |
847 | ndp->ni_segflg = UIO_USERSPACE; |
848 | ndp->ni_dirp = uap->fname; | |
8429d022 MK |
849 | if (error = namei(ndp, p)) |
850 | return (error); | |
fc2aed1e KM |
851 | vp = ndp->ni_vp; |
852 | if (vp->v_type == VDIR && | |
8429d022 | 853 | (error = suser(p->p_ucred, &p->p_acflag))) |
3e78e260 BJ |
854 | goto out; |
855 | /* | |
856 | * Don't unlink a mounted file. | |
857 | */ | |
fc2aed1e KM |
858 | if (vp->v_flag & VROOT) { |
859 | error = EBUSY; | |
3e78e260 BJ |
860 | goto out; |
861 | } | |
a42e0ed8 | 862 | #ifdef NVM |
9db58063 | 863 | (void) vnode_pager_uncache(vp); |
a42e0ed8 KM |
864 | #else |
865 | if (vp->v_flag & VTEXT) | |
866 | xrele(vp); /* try once to free text */ | |
867 | #endif | |
3e78e260 | 868 | out: |
66955caf | 869 | if (!error) { |
fc2aed1e | 870 | error = VOP_REMOVE(ndp); |
66955caf KM |
871 | } else { |
872 | VOP_ABORTOP(ndp); | |
6c44e83b KM |
873 | if (ndp->ni_dvp == vp) |
874 | vrele(ndp->ni_dvp); | |
875 | else | |
876 | vput(ndp->ni_dvp); | |
66955caf KM |
877 | vput(vp); |
878 | } | |
8429d022 | 879 | return (error); |
3e78e260 BJ |
880 | } |
881 | ||
882 | /* | |
883 | * Seek system call | |
884 | */ | |
6a6a1e5f | 885 | lseek(p, uap, retval) |
5e00df3b | 886 | struct proc *p; |
6a6a1e5f | 887 | register struct args { |
fc2aed1e | 888 | int fdes; |
3e78e260 BJ |
889 | off_t off; |
890 | int sbase; | |
6a6a1e5f KM |
891 | } *uap; |
892 | off_t *retval; | |
893 | { | |
8429d022 | 894 | struct ucred *cred = p->p_ucred; |
5e00df3b | 895 | register struct filedesc *fdp = p->p_fd; |
6a6a1e5f | 896 | register struct file *fp; |
fc2aed1e KM |
897 | struct vattr vattr; |
898 | int error; | |
899 | ||
8429d022 | 900 | if ((unsigned)uap->fdes >= fdp->fd_nfiles || |
5e00df3b | 901 | (fp = OFILE(fdp, uap->fdes)) == NULL) |
8429d022 | 902 | return (EBADF); |
fc2aed1e | 903 | if (fp->f_type != DTYPE_VNODE) |
8429d022 | 904 | return (ESPIPE); |
b4d1aee9 SL |
905 | switch (uap->sbase) { |
906 | ||
907 | case L_INCR: | |
908 | fp->f_offset += uap->off; | |
909 | break; | |
910 | ||
911 | case L_XTND: | |
fc2aed1e | 912 | if (error = VOP_GETATTR((struct vnode *)fp->f_data, |
6a6a1e5f | 913 | &vattr, cred)) |
8429d022 | 914 | return (error); |
fc2aed1e | 915 | fp->f_offset = uap->off + vattr.va_size; |
b4d1aee9 SL |
916 | break; |
917 | ||
918 | case L_SET: | |
919 | fp->f_offset = uap->off; | |
920 | break; | |
921 | ||
922 | default: | |
8429d022 | 923 | return (EINVAL); |
b4d1aee9 | 924 | } |
6a6a1e5f | 925 | *retval = fp->f_offset; |
8429d022 | 926 | return (0); |
3e78e260 BJ |
927 | } |
928 | ||
929 | /* | |
930 | * Access system call | |
931 | */ | |
6a6a1e5f KM |
932 | /* ARGSUSED */ |
933 | saccess(p, uap, retval) | |
5e00df3b | 934 | struct proc *p; |
6a6a1e5f | 935 | register struct args { |
3e78e260 BJ |
936 | char *fname; |
937 | int fmode; | |
6a6a1e5f KM |
938 | } *uap; |
939 | int *retval; | |
940 | { | |
8429d022 MK |
941 | register struct nameidata *ndp; |
942 | register struct ucred *cred = p->p_ucred; | |
fc2aed1e KM |
943 | register struct vnode *vp; |
944 | int error, mode, svuid, svgid; | |
8429d022 | 945 | struct nameidata nd; |
3e78e260 | 946 | |
8429d022 | 947 | ndp = &nd; |
6a6a1e5f KM |
948 | svuid = cred->cr_uid; |
949 | svgid = cred->cr_groups[0]; | |
8429d022 MK |
950 | cred->cr_uid = p->p_cred->p_ruid; |
951 | cred->cr_groups[0] = p->p_cred->p_rgid; | |
fc2aed1e | 952 | ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; |
715baff1 KM |
953 | ndp->ni_segflg = UIO_USERSPACE; |
954 | ndp->ni_dirp = uap->fname; | |
8429d022 | 955 | if (error = namei(ndp, p)) |
fc2aed1e KM |
956 | goto out1; |
957 | vp = ndp->ni_vp; | |
958 | /* | |
959 | * fmode == 0 means only check for exist | |
960 | */ | |
961 | if (uap->fmode) { | |
962 | mode = 0; | |
963 | if (uap->fmode & R_OK) | |
964 | mode |= VREAD; | |
965 | if (uap->fmode & W_OK) | |
966 | mode |= VWRITE; | |
967 | if (uap->fmode & X_OK) | |
968 | mode |= VEXEC; | |
9230ead4 | 969 | if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) |
8429d022 | 970 | error = VOP_ACCESS(vp, mode, cred); |
3e78e260 | 971 | } |
fc2aed1e KM |
972 | vput(vp); |
973 | out1: | |
6a6a1e5f KM |
974 | cred->cr_uid = svuid; |
975 | cred->cr_groups[0] = svgid; | |
8429d022 | 976 | return (error); |
3e78e260 | 977 | } |
d67a03eb | 978 | |
d67a03eb | 979 | /* |
6459ebe0 | 980 | * Stat system call. This version follows links. |
d67a03eb | 981 | */ |
6a6a1e5f KM |
982 | /* ARGSUSED */ |
983 | stat(p, uap, retval) | |
5e00df3b | 984 | struct proc *p; |
6a6a1e5f KM |
985 | register struct args { |
986 | char *fname; | |
987 | struct stat *ub; | |
988 | } *uap; | |
989 | int *retval; | |
d67a03eb | 990 | { |
8429d022 | 991 | register struct nameidata *ndp; |
6a6a1e5f KM |
992 | struct stat sb; |
993 | int error; | |
8429d022 | 994 | struct nameidata nd; |
d67a03eb | 995 | |
8429d022 | 996 | ndp = &nd; |
6a6a1e5f KM |
997 | ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; |
998 | ndp->ni_segflg = UIO_USERSPACE; | |
999 | ndp->ni_dirp = uap->fname; | |
8429d022 MK |
1000 | if (error = namei(ndp, p)) |
1001 | return (error); | |
6a6a1e5f KM |
1002 | error = vn_stat(ndp->ni_vp, &sb); |
1003 | vput(ndp->ni_vp); | |
1004 | if (error) | |
8429d022 | 1005 | return (error); |
6a6a1e5f | 1006 | error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); |
8429d022 | 1007 | return (error); |
d67a03eb BJ |
1008 | } |
1009 | ||
5485e062 | 1010 | /* |
6459ebe0 | 1011 | * Lstat system call. This version does not follow links. |
5485e062 | 1012 | */ |
6a6a1e5f KM |
1013 | /* ARGSUSED */ |
1014 | lstat(p, uap, retval) | |
5e00df3b | 1015 | struct proc *p; |
6a6a1e5f | 1016 | register struct args { |
5485e062 | 1017 | char *fname; |
88a7a62a | 1018 | struct stat *ub; |
6a6a1e5f KM |
1019 | } *uap; |
1020 | int *retval; | |
1021 | { | |
8429d022 | 1022 | register struct nameidata *ndp; |
fc2aed1e KM |
1023 | struct stat sb; |
1024 | int error; | |
8429d022 | 1025 | struct nameidata nd; |
5485e062 | 1026 | |
8429d022 | 1027 | ndp = &nd; |
6a6a1e5f | 1028 | ndp->ni_nameiop = LOOKUP | LOCKLEAF | NOFOLLOW; |
715baff1 KM |
1029 | ndp->ni_segflg = UIO_USERSPACE; |
1030 | ndp->ni_dirp = uap->fname; | |
8429d022 MK |
1031 | if (error = namei(ndp, p)) |
1032 | return (error); | |
fc2aed1e KM |
1033 | error = vn_stat(ndp->ni_vp, &sb); |
1034 | vput(ndp->ni_vp); | |
1035 | if (error) | |
8429d022 | 1036 | return (error); |
fc2aed1e | 1037 | error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); |
8429d022 | 1038 | return (error); |
d67a03eb BJ |
1039 | } |
1040 | ||
1041 | /* | |
5485e062 BJ |
1042 | * Return target name of a symbolic link |
1043 | */ | |
6a6a1e5f KM |
1044 | /* ARGSUSED */ |
1045 | readlink(p, uap, retval) | |
5e00df3b | 1046 | struct proc *p; |
6a6a1e5f | 1047 | register struct args { |
5485e062 BJ |
1048 | char *name; |
1049 | char *buf; | |
1050 | int count; | |
6a6a1e5f KM |
1051 | } *uap; |
1052 | int *retval; | |
1053 | { | |
8429d022 | 1054 | register struct nameidata *ndp; |
fc2aed1e KM |
1055 | register struct vnode *vp; |
1056 | struct iovec aiov; | |
1057 | struct uio auio; | |
1058 | int error; | |
8429d022 | 1059 | struct nameidata nd; |
5485e062 | 1060 | |
8429d022 | 1061 | ndp = &nd; |
fc2aed1e | 1062 | ndp->ni_nameiop = LOOKUP | LOCKLEAF; |
715baff1 KM |
1063 | ndp->ni_segflg = UIO_USERSPACE; |
1064 | ndp->ni_dirp = uap->name; | |
8429d022 MK |
1065 | if (error = namei(ndp, p)) |
1066 | return (error); | |
fc2aed1e KM |
1067 | vp = ndp->ni_vp; |
1068 | if (vp->v_type != VLNK) { | |
1069 | error = EINVAL; | |
5485e062 BJ |
1070 | goto out; |
1071 | } | |
fc2aed1e KM |
1072 | aiov.iov_base = uap->buf; |
1073 | aiov.iov_len = uap->count; | |
1074 | auio.uio_iov = &aiov; | |
1075 | auio.uio_iovcnt = 1; | |
1076 | auio.uio_offset = 0; | |
1077 | auio.uio_rw = UIO_READ; | |
1078 | auio.uio_segflg = UIO_USERSPACE; | |
1079 | auio.uio_resid = uap->count; | |
8429d022 | 1080 | error = VOP_READLINK(vp, &auio, p->p_ucred); |
5485e062 | 1081 | out: |
fc2aed1e | 1082 | vput(vp); |
6a6a1e5f | 1083 | *retval = uap->count - auio.uio_resid; |
8429d022 | 1084 | return (error); |
5485e062 BJ |
1085 | } |
1086 | ||
6995a2cb KM |
1087 | /* |
1088 | * Change flags of a file given path name. | |
1089 | */ | |
6a6a1e5f KM |
1090 | /* ARGSUSED */ |
1091 | chflags(p, uap, retval) | |
5e00df3b | 1092 | struct proc *p; |
6a6a1e5f | 1093 | register struct args { |
6995a2cb KM |
1094 | char *fname; |
1095 | int flags; | |
6a6a1e5f KM |
1096 | } *uap; |
1097 | int *retval; | |
1098 | { | |
8429d022 | 1099 | register struct nameidata *ndp; |
6995a2cb KM |
1100 | register struct vnode *vp; |
1101 | struct vattr vattr; | |
1102 | int error; | |
8429d022 | 1103 | struct nameidata nd; |
6995a2cb | 1104 | |
8429d022 | 1105 | ndp = &nd; |
6995a2cb KM |
1106 | ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; |
1107 | ndp->ni_segflg = UIO_USERSPACE; | |
1108 | ndp->ni_dirp = uap->fname; | |
8429d022 MK |
1109 | if (error = namei(ndp, p)) |
1110 | return (error); | |
6995a2cb | 1111 | vp = ndp->ni_vp; |
54fb9dc2 | 1112 | if (vp->v_mount->mnt_flag & MNT_RDONLY) { |
6995a2cb KM |
1113 | error = EROFS; |
1114 | goto out; | |
1115 | } | |
3658f091 KB |
1116 | VATTR_NULL(&vattr); |
1117 | vattr.va_flags = uap->flags; | |
8429d022 | 1118 | error = VOP_SETATTR(vp, &vattr, p->p_ucred); |
6995a2cb KM |
1119 | out: |
1120 | vput(vp); | |
8429d022 | 1121 | return (error); |
6995a2cb KM |
1122 | } |
1123 | ||
1124 | /* | |
1125 | * Change flags of a file given a file descriptor. | |
1126 | */ | |
6a6a1e5f KM |
1127 | /* ARGSUSED */ |
1128 | fchflags(p, uap, retval) | |
5e00df3b | 1129 | struct proc *p; |
6a6a1e5f | 1130 | register struct args { |
6995a2cb KM |
1131 | int fd; |
1132 | int flags; | |
6a6a1e5f KM |
1133 | } *uap; |
1134 | int *retval; | |
1135 | { | |
6995a2cb KM |
1136 | struct vattr vattr; |
1137 | struct vnode *vp; | |
1138 | struct file *fp; | |
1139 | int error; | |
1140 | ||
5e00df3b | 1141 | if (error = getvnode(p->p_fd, uap->fd, &fp)) |
8429d022 | 1142 | return (error); |
6995a2cb KM |
1143 | vp = (struct vnode *)fp->f_data; |
1144 | VOP_LOCK(vp); | |
54fb9dc2 | 1145 | if (vp->v_mount->mnt_flag & MNT_RDONLY) { |
6995a2cb KM |
1146 | error = EROFS; |
1147 | goto out; | |
1148 | } | |
3658f091 KB |
1149 | VATTR_NULL(&vattr); |
1150 | vattr.va_flags = uap->flags; | |
8429d022 | 1151 | error = VOP_SETATTR(vp, &vattr, p->p_ucred); |
6995a2cb KM |
1152 | out: |
1153 | VOP_UNLOCK(vp); | |
8429d022 | 1154 | return (error); |
6995a2cb KM |
1155 | } |
1156 | ||
4f083fd7 SL |
1157 | /* |
1158 | * Change mode of a file given path name. | |
1159 | */ | |
6a6a1e5f KM |
1160 | /* ARGSUSED */ |
1161 | chmod(p, uap, retval) | |
5e00df3b | 1162 | struct proc *p; |
6a6a1e5f | 1163 | register struct args { |
3e78e260 BJ |
1164 | char *fname; |
1165 | int fmode; | |
6a6a1e5f KM |
1166 | } *uap; |
1167 | int *retval; | |
1168 | { | |
8429d022 | 1169 | register struct nameidata *ndp; |
fc2aed1e KM |
1170 | register struct vnode *vp; |
1171 | struct vattr vattr; | |
1172 | int error; | |
8429d022 | 1173 | struct nameidata nd; |
5485e062 | 1174 | |
8429d022 | 1175 | ndp = &nd; |
fc2aed1e KM |
1176 | ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; |
1177 | ndp->ni_segflg = UIO_USERSPACE; | |
1178 | ndp->ni_dirp = uap->fname; | |
8429d022 MK |
1179 | if (error = namei(ndp, p)) |
1180 | return (error); | |
fc2aed1e | 1181 | vp = ndp->ni_vp; |
54fb9dc2 | 1182 | if (vp->v_mount->mnt_flag & MNT_RDONLY) { |
fc2aed1e KM |
1183 | error = EROFS; |
1184 | goto out; | |
1185 | } | |
3658f091 KB |
1186 | VATTR_NULL(&vattr); |
1187 | vattr.va_mode = uap->fmode & 07777; | |
8429d022 | 1188 | error = VOP_SETATTR(vp, &vattr, p->p_ucred); |
fc2aed1e KM |
1189 | out: |
1190 | vput(vp); | |
8429d022 | 1191 | return (error); |
528f664c | 1192 | } |
f94ceb3b | 1193 | |
4f083fd7 SL |
1194 | /* |
1195 | * Change mode of a file given a file descriptor. | |
1196 | */ | |
6a6a1e5f KM |
1197 | /* ARGSUSED */ |
1198 | fchmod(p, uap, retval) | |
5e00df3b | 1199 | struct proc *p; |
6a6a1e5f | 1200 | register struct args { |
528f664c SL |
1201 | int fd; |
1202 | int fmode; | |
6a6a1e5f KM |
1203 | } *uap; |
1204 | int *retval; | |
1205 | { | |
fc2aed1e KM |
1206 | struct vattr vattr; |
1207 | struct vnode *vp; | |
1208 | struct file *fp; | |
1209 | int error; | |
1210 | ||
5e00df3b | 1211 | if (error = getvnode(p->p_fd, uap->fd, &fp)) |
8429d022 | 1212 | return (error); |
fc2aed1e KM |
1213 | vp = (struct vnode *)fp->f_data; |
1214 | VOP_LOCK(vp); | |
54fb9dc2 | 1215 | if (vp->v_mount->mnt_flag & MNT_RDONLY) { |
fc2aed1e KM |
1216 | error = EROFS; |
1217 | goto out; | |
f94ceb3b | 1218 | } |
3658f091 KB |
1219 | VATTR_NULL(&vattr); |
1220 | vattr.va_mode = uap->fmode & 07777; | |
8429d022 | 1221 | error = VOP_SETATTR(vp, &vattr, p->p_ucred); |
fc2aed1e KM |
1222 | out: |
1223 | VOP_UNLOCK(vp); | |
8429d022 | 1224 | return (error); |
5485e062 BJ |
1225 | } |
1226 | ||
4f083fd7 SL |
1227 | /* |
1228 | * Set ownership given a path name. | |
1229 | */ | |
6a6a1e5f KM |
1230 | /* ARGSUSED */ |
1231 | chown(p, uap, retval) | |
5e00df3b | 1232 | struct proc *p; |
6a6a1e5f | 1233 | register struct args { |
3e78e260 BJ |
1234 | char *fname; |
1235 | int uid; | |
1236 | int gid; | |
6a6a1e5f KM |
1237 | } *uap; |
1238 | int *retval; | |
1239 | { | |
8429d022 | 1240 | register struct nameidata *ndp; |
fc2aed1e KM |
1241 | register struct vnode *vp; |
1242 | struct vattr vattr; | |
1243 | int error; | |
8429d022 | 1244 | struct nameidata nd; |
d67a03eb | 1245 | |
8429d022 | 1246 | ndp = &nd; |
fc2aed1e | 1247 | ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; |
18b0bce6 KB |
1248 | ndp->ni_segflg = UIO_USERSPACE; |
1249 | ndp->ni_dirp = uap->fname; | |
8429d022 MK |
1250 | if (error = namei(ndp, p)) |
1251 | return (error); | |
fc2aed1e | 1252 | vp = ndp->ni_vp; |
54fb9dc2 | 1253 | if (vp->v_mount->mnt_flag & MNT_RDONLY) { |
fc2aed1e KM |
1254 | error = EROFS; |
1255 | goto out; | |
1256 | } | |
3658f091 KB |
1257 | VATTR_NULL(&vattr); |
1258 | vattr.va_uid = uap->uid; | |
1259 | vattr.va_gid = uap->gid; | |
8429d022 | 1260 | error = VOP_SETATTR(vp, &vattr, p->p_ucred); |
fc2aed1e KM |
1261 | out: |
1262 | vput(vp); | |
8429d022 | 1263 | return (error); |
528f664c | 1264 | } |
f94ceb3b | 1265 | |
4f083fd7 SL |
1266 | /* |
1267 | * Set ownership given a file descriptor. | |
1268 | */ | |
6a6a1e5f KM |
1269 | /* ARGSUSED */ |
1270 | fchown(p, uap, retval) | |
5e00df3b | 1271 | struct proc *p; |
6a6a1e5f | 1272 | register struct args { |
528f664c SL |
1273 | int fd; |
1274 | int uid; | |
1275 | int gid; | |
6a6a1e5f KM |
1276 | } *uap; |
1277 | int *retval; | |
1278 | { | |
fc2aed1e KM |
1279 | struct vattr vattr; |
1280 | struct vnode *vp; | |
1281 | struct file *fp; | |
1282 | int error; | |
1283 | ||
5e00df3b | 1284 | if (error = getvnode(p->p_fd, uap->fd, &fp)) |
8429d022 | 1285 | return (error); |
fc2aed1e KM |
1286 | vp = (struct vnode *)fp->f_data; |
1287 | VOP_LOCK(vp); | |
54fb9dc2 | 1288 | if (vp->v_mount->mnt_flag & MNT_RDONLY) { |
fc2aed1e KM |
1289 | error = EROFS; |
1290 | goto out; | |
1291 | } | |
3658f091 KB |
1292 | VATTR_NULL(&vattr); |
1293 | vattr.va_uid = uap->uid; | |
1294 | vattr.va_gid = uap->gid; | |
8429d022 | 1295 | error = VOP_SETATTR(vp, &vattr, p->p_ucred); |
fc2aed1e KM |
1296 | out: |
1297 | VOP_UNLOCK(vp); | |
8429d022 | 1298 | return (error); |
d67a03eb BJ |
1299 | } |
1300 | ||
6a6a1e5f KM |
1301 | /* |
1302 | * Set the access and modification times of a file. | |
1303 | */ | |
1304 | /* ARGSUSED */ | |
1305 | utimes(p, uap, retval) | |
5e00df3b | 1306 | struct proc *p; |
6a6a1e5f | 1307 | register struct args { |
bb1b75f4 SL |
1308 | char *fname; |
1309 | struct timeval *tptr; | |
6a6a1e5f KM |
1310 | } *uap; |
1311 | int *retval; | |
1312 | { | |
8429d022 | 1313 | register struct nameidata *ndp; |
fc2aed1e | 1314 | register struct vnode *vp; |
bb1b75f4 | 1315 | struct timeval tv[2]; |
fc2aed1e KM |
1316 | struct vattr vattr; |
1317 | int error; | |
8429d022 | 1318 | struct nameidata nd; |
bb1b75f4 | 1319 | |
fc2aed1e | 1320 | if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) |
8429d022 MK |
1321 | return (error); |
1322 | ndp = &nd; | |
fc2aed1e KM |
1323 | ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; |
1324 | ndp->ni_segflg = UIO_USERSPACE; | |
1325 | ndp->ni_dirp = uap->fname; | |
8429d022 MK |
1326 | if (error = namei(ndp, p)) |
1327 | return (error); | |
fc2aed1e | 1328 | vp = ndp->ni_vp; |
54fb9dc2 | 1329 | if (vp->v_mount->mnt_flag & MNT_RDONLY) { |
fc2aed1e KM |
1330 | error = EROFS; |
1331 | goto out; | |
bb1b75f4 | 1332 | } |
3658f091 KB |
1333 | VATTR_NULL(&vattr); |
1334 | vattr.va_atime = tv[0]; | |
1335 | vattr.va_mtime = tv[1]; | |
8429d022 | 1336 | error = VOP_SETATTR(vp, &vattr, p->p_ucred); |
fc2aed1e KM |
1337 | out: |
1338 | vput(vp); | |
8429d022 | 1339 | return (error); |
d67a03eb | 1340 | } |
64d3a787 | 1341 | |
4f083fd7 SL |
1342 | /* |
1343 | * Truncate a file given its path name. | |
1344 | */ | |
6a6a1e5f KM |
1345 | /* ARGSUSED */ |
1346 | truncate(p, uap, retval) | |
5e00df3b | 1347 | struct proc *p; |
6a6a1e5f | 1348 | register struct args { |
528f664c | 1349 | char *fname; |
c979c6ce | 1350 | off_t length; |
6a6a1e5f KM |
1351 | } *uap; |
1352 | int *retval; | |
1353 | { | |
8429d022 | 1354 | register struct nameidata *ndp; |
fc2aed1e KM |
1355 | register struct vnode *vp; |
1356 | struct vattr vattr; | |
1357 | int error; | |
8429d022 | 1358 | struct nameidata nd; |
528f664c | 1359 | |
8429d022 | 1360 | ndp = &nd; |
fc2aed1e | 1361 | ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; |
715baff1 KM |
1362 | ndp->ni_segflg = UIO_USERSPACE; |
1363 | ndp->ni_dirp = uap->fname; | |
8429d022 MK |
1364 | if (error = namei(ndp, p)) |
1365 | return (error); | |
fc2aed1e KM |
1366 | vp = ndp->ni_vp; |
1367 | if (vp->v_type == VDIR) { | |
1368 | error = EISDIR; | |
1369 | goto out; | |
528f664c | 1370 | } |
d7b2a16c | 1371 | if ((error = vn_writechk(vp)) || |
8429d022 | 1372 | (error = VOP_ACCESS(vp, VWRITE, p->p_ucred))) |
fc2aed1e | 1373 | goto out; |
3658f091 KB |
1374 | VATTR_NULL(&vattr); |
1375 | vattr.va_size = uap->length; | |
8429d022 | 1376 | error = VOP_SETATTR(vp, &vattr, p->p_ucred); |
fc2aed1e KM |
1377 | out: |
1378 | vput(vp); | |
8429d022 | 1379 | return (error); |
528f664c SL |
1380 | } |
1381 | ||
4f083fd7 SL |
1382 | /* |
1383 | * Truncate a file given a file descriptor. | |
1384 | */ | |
6a6a1e5f KM |
1385 | /* ARGSUSED */ |
1386 | ftruncate(p, uap, retval) | |
5e00df3b | 1387 | struct proc *p; |
6a6a1e5f | 1388 | register struct args { |
528f664c | 1389 | int fd; |
c979c6ce | 1390 | off_t length; |
6a6a1e5f KM |
1391 | } *uap; |
1392 | int *retval; | |
1393 | { | |
fc2aed1e KM |
1394 | struct vattr vattr; |
1395 | struct vnode *vp; | |
528f664c | 1396 | struct file *fp; |
fc2aed1e KM |
1397 | int error; |
1398 | ||
5e00df3b | 1399 | if (error = getvnode(p->p_fd, uap->fd, &fp)) |
8429d022 | 1400 | return (error); |
fc2aed1e | 1401 | if ((fp->f_flag & FWRITE) == 0) |
8429d022 | 1402 | return (EINVAL); |
fc2aed1e KM |
1403 | vp = (struct vnode *)fp->f_data; |
1404 | VOP_LOCK(vp); | |
1405 | if (vp->v_type == VDIR) { | |
1406 | error = EISDIR; | |
1407 | goto out; | |
528f664c | 1408 | } |
d7b2a16c | 1409 | if (error = vn_writechk(vp)) |
fc2aed1e | 1410 | goto out; |
3658f091 KB |
1411 | VATTR_NULL(&vattr); |
1412 | vattr.va_size = uap->length; | |
fc2aed1e KM |
1413 | error = VOP_SETATTR(vp, &vattr, fp->f_cred); |
1414 | out: | |
1415 | VOP_UNLOCK(vp); | |
8429d022 | 1416 | return (error); |
4f083fd7 SL |
1417 | } |
1418 | ||
1419 | /* | |
1420 | * Synch an open file. | |
1421 | */ | |
6a6a1e5f KM |
1422 | /* ARGSUSED */ |
1423 | fsync(p, uap, retval) | |
5e00df3b | 1424 | struct proc *p; |
6a6a1e5f | 1425 | struct args { |
4f083fd7 | 1426 | int fd; |
6a6a1e5f KM |
1427 | } *uap; |
1428 | int *retval; | |
1429 | { | |
e79467ea | 1430 | register struct vnode *vp; |
4f083fd7 | 1431 | struct file *fp; |
fc2aed1e | 1432 | int error; |
4f083fd7 | 1433 | |
5e00df3b | 1434 | if (error = getvnode(p->p_fd, uap->fd, &fp)) |
8429d022 | 1435 | return (error); |
e79467ea KM |
1436 | vp = (struct vnode *)fp->f_data; |
1437 | VOP_LOCK(vp); | |
1438 | error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT); | |
1439 | VOP_UNLOCK(vp); | |
8429d022 | 1440 | return (error); |
528f664c SL |
1441 | } |
1442 | ||
4f083fd7 SL |
1443 | /* |
1444 | * Rename system call. | |
4f083fd7 SL |
1445 | * |
1446 | * Source and destination must either both be directories, or both | |
1447 | * not be directories. If target is a directory, it must be empty. | |
1448 | */ | |
6a6a1e5f KM |
1449 | /* ARGSUSED */ |
1450 | rename(p, uap, retval) | |
5e00df3b | 1451 | struct proc *p; |
6a6a1e5f | 1452 | register struct args { |
528f664c SL |
1453 | char *from; |
1454 | char *to; | |
6a6a1e5f KM |
1455 | } *uap; |
1456 | int *retval; | |
1457 | { | |
fc2aed1e | 1458 | register struct vnode *tvp, *fvp, *tdvp; |
8429d022 | 1459 | register struct nameidata *ndp; |
fc2aed1e | 1460 | int error; |
8429d022 | 1461 | struct nameidata nd, tond; |
4f083fd7 | 1462 | |
8429d022 | 1463 | ndp = &nd; |
fc2aed1e | 1464 | ndp->ni_nameiop = DELETE | WANTPARENT; |
715baff1 KM |
1465 | ndp->ni_segflg = UIO_USERSPACE; |
1466 | ndp->ni_dirp = uap->from; | |
8429d022 MK |
1467 | if (error = namei(ndp, p)) |
1468 | return (error); | |
fc2aed1e | 1469 | fvp = ndp->ni_vp; |
41eb2f3d | 1470 | nddup(ndp, &tond); |
fc2aed1e KM |
1471 | tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; |
1472 | tond.ni_segflg = UIO_USERSPACE; | |
1473 | tond.ni_dirp = uap->to; | |
8429d022 | 1474 | if (error = namei(&tond, p)) { |
66955caf KM |
1475 | VOP_ABORTOP(ndp); |
1476 | vrele(ndp->ni_dvp); | |
1477 | vrele(fvp); | |
1478 | goto out1; | |
1479 | } | |
fc2aed1e KM |
1480 | tdvp = tond.ni_dvp; |
1481 | tvp = tond.ni_vp; | |
1482 | if (tvp != NULL) { | |
1483 | if (fvp->v_type == VDIR && tvp->v_type != VDIR) { | |
9259ee95 | 1484 | error = ENOTDIR; |
fc2aed1e KM |
1485 | goto out; |
1486 | } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { | |
9259ee95 | 1487 | error = EISDIR; |
fc2aed1e | 1488 | goto out; |
a5390dce | 1489 | } |
73f5d967 KM |
1490 | if (fvp->v_mount != tvp->v_mount) { |
1491 | error = EXDEV; | |
1492 | goto out; | |
1493 | } | |
4f083fd7 | 1494 | } |
fc2aed1e KM |
1495 | if (fvp->v_mount != tdvp->v_mount) { |
1496 | error = EXDEV; | |
1497 | goto out; | |
64d3a787 | 1498 | } |
fe562f32 | 1499 | if (fvp == tdvp) |
fc2aed1e | 1500 | error = EINVAL; |
fe562f32 KM |
1501 | /* |
1502 | * If source is the same as the destination, | |
1503 | * then there is nothing to do. | |
1504 | */ | |
1505 | if (fvp == tvp) | |
1506 | error = -1; | |
fc2aed1e | 1507 | out: |
66955caf KM |
1508 | if (!error) { |
1509 | error = VOP_RENAME(ndp, &tond); | |
1510 | } else { | |
fc2aed1e | 1511 | VOP_ABORTOP(&tond); |
6c44e83b KM |
1512 | if (tdvp == tvp) |
1513 | vrele(tdvp); | |
1514 | else | |
1515 | vput(tdvp); | |
66955caf KM |
1516 | if (tvp) |
1517 | vput(tvp); | |
fc2aed1e | 1518 | VOP_ABORTOP(ndp); |
66955caf KM |
1519 | vrele(ndp->ni_dvp); |
1520 | vrele(fvp); | |
64d3a787 | 1521 | } |
fc2aed1e | 1522 | out1: |
41eb2f3d | 1523 | ndrele(&tond); |
fe562f32 | 1524 | if (error == -1) |
8429d022 MK |
1525 | return (0); |
1526 | return (error); | |
64d3a787 | 1527 | } |
88a7a62a | 1528 | |
88a7a62a SL |
1529 | /* |
1530 | * Mkdir system call | |
1531 | */ | |
6a6a1e5f KM |
1532 | /* ARGSUSED */ |
1533 | mkdir(p, uap, retval) | |
5e00df3b | 1534 | struct proc *p; |
6a6a1e5f | 1535 | register struct args { |
88a7a62a SL |
1536 | char *name; |
1537 | int dmode; | |
6a6a1e5f KM |
1538 | } *uap; |
1539 | int *retval; | |
1540 | { | |
8429d022 | 1541 | register struct nameidata *ndp; |
fc2aed1e KM |
1542 | register struct vnode *vp; |
1543 | struct vattr vattr; | |
1544 | int error; | |
8429d022 | 1545 | struct nameidata nd; |
88a7a62a | 1546 | |
8429d022 | 1547 | ndp = &nd; |
fc2aed1e | 1548 | ndp->ni_nameiop = CREATE | LOCKPARENT; |
715baff1 KM |
1549 | ndp->ni_segflg = UIO_USERSPACE; |
1550 | ndp->ni_dirp = uap->name; | |
8429d022 MK |
1551 | if (error = namei(ndp, p)) |
1552 | return (error); | |
fc2aed1e KM |
1553 | vp = ndp->ni_vp; |
1554 | if (vp != NULL) { | |
1555 | VOP_ABORTOP(ndp); | |
6c44e83b KM |
1556 | if (ndp->ni_dvp == vp) |
1557 | vrele(ndp->ni_dvp); | |
1558 | else | |
1559 | vput(ndp->ni_dvp); | |
66955caf | 1560 | vrele(vp); |
8429d022 | 1561 | return (EEXIST); |
88a7a62a | 1562 | } |
3ee1461b | 1563 | VATTR_NULL(&vattr); |
fc2aed1e | 1564 | vattr.va_type = VDIR; |
5e00df3b | 1565 | vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask; |
fc2aed1e | 1566 | error = VOP_MKDIR(ndp, &vattr); |
5dfd04f0 KM |
1567 | if (!error) |
1568 | vput(ndp->ni_vp); | |
8429d022 | 1569 | return (error); |
88a7a62a SL |
1570 | } |
1571 | ||
1572 | /* | |
1573 | * Rmdir system call. | |
1574 | */ | |
6a6a1e5f KM |
1575 | /* ARGSUSED */ |
1576 | rmdir(p, uap, retval) | |
5e00df3b | 1577 | struct proc *p; |
6a6a1e5f | 1578 | struct args { |
88a7a62a | 1579 | char *name; |
6a6a1e5f KM |
1580 | } *uap; |
1581 | int *retval; | |
1582 | { | |
8429d022 | 1583 | register struct nameidata *ndp; |
fc2aed1e KM |
1584 | register struct vnode *vp; |
1585 | int error; | |
8429d022 | 1586 | struct nameidata nd; |
88a7a62a | 1587 | |
8429d022 | 1588 | ndp = &nd; |
fc2aed1e | 1589 | ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; |
715baff1 KM |
1590 | ndp->ni_segflg = UIO_USERSPACE; |
1591 | ndp->ni_dirp = uap->name; | |
8429d022 MK |
1592 | if (error = namei(ndp, p)) |
1593 | return (error); | |
fc2aed1e KM |
1594 | vp = ndp->ni_vp; |
1595 | if (vp->v_type != VDIR) { | |
1596 | error = ENOTDIR; | |
88a7a62a SL |
1597 | goto out; |
1598 | } | |
1599 | /* | |
fc2aed1e | 1600 | * No rmdir "." please. |
88a7a62a | 1601 | */ |
fc2aed1e KM |
1602 | if (ndp->ni_dvp == vp) { |
1603 | error = EINVAL; | |
88a7a62a SL |
1604 | goto out; |
1605 | } | |
1606 | /* | |
fc2aed1e | 1607 | * Don't unlink a mounted file. |
88a7a62a | 1608 | */ |
fc2aed1e KM |
1609 | if (vp->v_flag & VROOT) |
1610 | error = EBUSY; | |
88a7a62a | 1611 | out: |
66955caf | 1612 | if (!error) { |
fc2aed1e | 1613 | error = VOP_RMDIR(ndp); |
66955caf KM |
1614 | } else { |
1615 | VOP_ABORTOP(ndp); | |
6c44e83b KM |
1616 | if (ndp->ni_dvp == vp) |
1617 | vrele(ndp->ni_dvp); | |
1618 | else | |
1619 | vput(ndp->ni_dvp); | |
66955caf KM |
1620 | vput(vp); |
1621 | } | |
8429d022 | 1622 | return (error); |
88a7a62a SL |
1623 | } |
1624 | ||
fc2aed1e KM |
1625 | /* |
1626 | * Read a block of directory entries in a file system independent format | |
1627 | */ | |
6a6a1e5f | 1628 | getdirentries(p, uap, retval) |
5e00df3b | 1629 | struct proc *p; |
6a6a1e5f | 1630 | register struct args { |
fc2aed1e KM |
1631 | int fd; |
1632 | char *buf; | |
1633 | unsigned count; | |
1634 | long *basep; | |
6a6a1e5f KM |
1635 | } *uap; |
1636 | int *retval; | |
1637 | { | |
e79467ea | 1638 | register struct vnode *vp; |
8462a185 | 1639 | struct file *fp; |
fc2aed1e KM |
1640 | struct uio auio; |
1641 | struct iovec aiov; | |
58030ad2 | 1642 | off_t off; |
c242ace6 | 1643 | int error, eofflag; |
fc2aed1e | 1644 | |
5e00df3b | 1645 | if (error = getvnode(p->p_fd, uap->fd, &fp)) |
8429d022 | 1646 | return (error); |
fc2aed1e | 1647 | if ((fp->f_flag & FREAD) == 0) |
8429d022 | 1648 | return (EBADF); |
e79467ea KM |
1649 | vp = (struct vnode *)fp->f_data; |
1650 | if (vp->v_type != VDIR) | |
8429d022 | 1651 | return (EINVAL); |
fc2aed1e KM |
1652 | aiov.iov_base = uap->buf; |
1653 | aiov.iov_len = uap->count; | |
1654 | auio.uio_iov = &aiov; | |
1655 | auio.uio_iovcnt = 1; | |
1656 | auio.uio_rw = UIO_READ; | |
1657 | auio.uio_segflg = UIO_USERSPACE; | |
1658 | auio.uio_resid = uap->count; | |
e79467ea KM |
1659 | VOP_LOCK(vp); |
1660 | auio.uio_offset = off = fp->f_offset; | |
c242ace6 | 1661 | error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag); |
e79467ea KM |
1662 | fp->f_offset = auio.uio_offset; |
1663 | VOP_UNLOCK(vp); | |
1664 | if (error) | |
8429d022 | 1665 | return (error); |
e79467ea | 1666 | error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); |
6a6a1e5f | 1667 | *retval = uap->count - auio.uio_resid; |
8429d022 | 1668 | return (error); |
88a7a62a SL |
1669 | } |
1670 | ||
1671 | /* | |
1672 | * mode mask for creation of files | |
1673 | */ | |
6a6a1e5f KM |
1674 | mode_t |
1675 | umask(p, uap, retval) | |
5e00df3b | 1676 | struct proc *p; |
6a6a1e5f | 1677 | struct args { |
88a7a62a | 1678 | int mask; |
6a6a1e5f KM |
1679 | } *uap; |
1680 | int *retval; | |
1681 | { | |
5e00df3b | 1682 | register struct filedesc *fdp = p->p_fd; |
88a7a62a | 1683 | |
5e00df3b KM |
1684 | *retval = fdp->fd_cmask; |
1685 | fdp->fd_cmask = uap->mask & 07777; | |
8429d022 | 1686 | return (0); |
fc2aed1e KM |
1687 | } |
1688 | ||
b0a98f13 MT |
1689 | /* |
1690 | * Void all references to file by ripping underlying filesystem | |
1691 | * away from vnode. | |
1692 | */ | |
6a6a1e5f KM |
1693 | /* ARGSUSED */ |
1694 | revoke(p, uap, retval) | |
5e00df3b | 1695 | struct proc *p; |
6a6a1e5f | 1696 | register struct args { |
b0a98f13 | 1697 | char *fname; |
6a6a1e5f KM |
1698 | } *uap; |
1699 | int *retval; | |
1700 | { | |
8429d022 | 1701 | register struct nameidata *ndp; |
b0a98f13 MT |
1702 | register struct vnode *vp; |
1703 | struct vattr vattr; | |
1704 | int error; | |
8429d022 | 1705 | struct nameidata nd; |
b0a98f13 | 1706 | |
8429d022 | 1707 | ndp = &nd; |
b0a98f13 MT |
1708 | ndp->ni_nameiop = LOOKUP | FOLLOW; |
1709 | ndp->ni_segflg = UIO_USERSPACE; | |
1710 | ndp->ni_dirp = uap->fname; | |
8429d022 MK |
1711 | if (error = namei(ndp, p)) |
1712 | return (error); | |
b0a98f13 MT |
1713 | vp = ndp->ni_vp; |
1714 | if (vp->v_type != VCHR && vp->v_type != VBLK) { | |
1715 | error = EINVAL; | |
1716 | goto out; | |
1717 | } | |
8429d022 | 1718 | if (error = VOP_GETATTR(vp, &vattr, p->p_ucred)) |
b0a98f13 | 1719 | goto out; |
8429d022 MK |
1720 | if (p->p_ucred->cr_uid != vattr.va_uid && |
1721 | (error = suser(p->p_ucred, &p->p_acflag))) | |
b0a98f13 | 1722 | goto out; |
8b81d198 | 1723 | if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) |
c9345cca | 1724 | vgoneall(vp); |
b0a98f13 MT |
1725 | out: |
1726 | vrele(vp); | |
8429d022 | 1727 | return (error); |
b0a98f13 MT |
1728 | } |
1729 | ||
5e00df3b KM |
1730 | getvnode(fdp, fdes, fpp) |
1731 | struct filedesc *fdp; | |
fc2aed1e KM |
1732 | struct file **fpp; |
1733 | int fdes; | |
1734 | { | |
1735 | struct file *fp; | |
1736 | ||
8429d022 | 1737 | if ((unsigned)fdes >= fdp->fd_nfiles || |
5e00df3b | 1738 | (fp = OFILE(fdp, fdes)) == NULL) |
fc2aed1e KM |
1739 | return (EBADF); |
1740 | if (fp->f_type != DTYPE_VNODE) | |
1741 | return (EINVAL); | |
1742 | *fpp = fp; | |
1743 | return (0); | |
88a7a62a | 1744 | } |