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