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