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