Commit | Line | Data |
---|---|---|
da7c5cc6 | 1 | /* |
47a73614 KB |
2 | * Copyright (c) 1989, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
adb35f79 KB |
4 | * (c) UNIX System Laboratories, Inc. |
5 | * All or some portions of this file are derived from material licensed | |
6 | * to the University of California by American Telephone and Telegraph | |
7 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with | |
8 | * the permission of UNIX System Laboratories, Inc. | |
da7c5cc6 | 9 | * |
dbf0c423 | 10 | * %sccs.include.redist.c% |
fc2aed1e | 11 | * |
f0e827e3 | 12 | * @(#)vfs_syscalls.c 8.11 (Berkeley) %G% |
da7c5cc6 | 13 | */ |
6459ebe0 | 14 | |
38a01dbe KB |
15 | #include <sys/param.h> |
16 | #include <sys/systm.h> | |
17 | #include <sys/namei.h> | |
18 | #include <sys/filedesc.h> | |
19 | #include <sys/kernel.h> | |
20 | #include <sys/file.h> | |
21 | #include <sys/stat.h> | |
22 | #include <sys/vnode.h> | |
23 | #include <sys/mount.h> | |
24 | #include <sys/proc.h> | |
25 | #include <sys/uio.h> | |
26 | #include <sys/malloc.h> | |
27 | #include <sys/dirent.h> | |
28 | ||
be320a2b | 29 | #include <vm/vm.h> |
6aecdd4c | 30 | #include <sys/sysctl.h> |
88a7a62a | 31 | |
7121fdf0 KB |
32 | static int change_dir __P((struct nameidata *ndp, struct proc *p)); |
33 | ||
a5368812 KM |
34 | #ifdef REF_DIAGNOSTIC |
35 | #define CURCOUNT (curproc ? curproc->p_spare[0] : 0) | |
36 | #define CHECKPOINTREF int oldrefcount = CURCOUNT; | |
37 | #define CHECKREFS(F) if (oldrefcount != CURCOUNT) \ | |
38 | printf("REFCOUNT: %s, old=%d, new=%d\n", (F), oldrefcount, CURCOUNT); | |
39 | #else | |
40 | #define CHECKPOINTREF | |
41 | #define CHECKREFS(D) | |
42 | #endif | |
43 | ||
fc2aed1e KM |
44 | /* |
45 | * Virtual File System System Calls | |
46 | */ | |
3e78e260 | 47 | |
4f083fd7 | 48 | /* |
7121fdf0 | 49 | * Mount a file system. |
4f083fd7 | 50 | */ |
9e97623a CT |
51 | struct mount_args { |
52 | int type; | |
7121fdf0 | 53 | char *path; |
9e97623a CT |
54 | int flags; |
55 | caddr_t data; | |
56 | }; | |
6a6a1e5f KM |
57 | /* ARGSUSED */ |
58 | mount(p, uap, retval) | |
5e00df3b | 59 | struct proc *p; |
9e97623a | 60 | register struct mount_args *uap; |
6a6a1e5f KM |
61 | int *retval; |
62 | { | |
d48157d5 KM |
63 | register struct vnode *vp; |
64 | register struct mount *mp; | |
47971887 | 65 | int error, flag; |
8429d022 | 66 | struct nameidata nd; |
3e78e260 | 67 | |
fc2aed1e KM |
68 | /* |
69 | * Must be super user | |
70 | */ | |
8429d022 MK |
71 | if (error = suser(p->p_ucred, &p->p_acflag)) |
72 | return (error); | |
fc2aed1e KM |
73 | /* |
74 | * Get vnode to be covered | |
75 | */ | |
7121fdf0 | 76 | NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); |
dd4c01c2 | 77 | if (error = namei(&nd)) |
8429d022 | 78 | return (error); |
dd4c01c2 | 79 | vp = nd.ni_vp; |
54fb9dc2 | 80 | if (uap->flags & MNT_UPDATE) { |
d48157d5 KM |
81 | if ((vp->v_flag & VROOT) == 0) { |
82 | vput(vp); | |
8429d022 | 83 | return (EINVAL); |
d48157d5 KM |
84 | } |
85 | mp = vp->v_mount; | |
db62a40f | 86 | flag = mp->mnt_flag; |
d48157d5 | 87 | /* |
db62a40f KM |
88 | * We only allow the filesystem to be reloaded if it |
89 | * is currently mounted read-only. | |
d48157d5 | 90 | */ |
db62a40f KM |
91 | if ((uap->flags & MNT_RELOAD) && |
92 | ((mp->mnt_flag & MNT_RDONLY) == 0)) { | |
d48157d5 | 93 | vput(vp); |
8429d022 | 94 | return (EOPNOTSUPP); /* Needs translation */ |
d48157d5 | 95 | } |
db62a40f KM |
96 | mp->mnt_flag |= |
97 | uap->flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE); | |
d48157d5 KM |
98 | VOP_UNLOCK(vp); |
99 | goto update; | |
100 | } | |
c05286bd | 101 | if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) |
09d2ef1a | 102 | return (error); |
fc2aed1e KM |
103 | if (vp->v_type != VDIR) { |
104 | vput(vp); | |
8429d022 | 105 | return (ENOTDIR); |
fc2aed1e | 106 | } |
7121fdf0 | 107 | if ((u_long)uap->type > MOUNT_MAXTYPE || vfssw[uap->type] == NULL) { |
fc2aed1e | 108 | vput(vp); |
8429d022 | 109 | return (ENODEV); |
fc2aed1e KM |
110 | } |
111 | ||
112 | /* | |
d48157d5 | 113 | * Allocate and initialize the file system. |
fc2aed1e KM |
114 | */ |
115 | mp = (struct mount *)malloc((u_long)sizeof(struct mount), | |
116 | M_MOUNT, M_WAITOK); | |
b1341251 | 117 | bzero((char *)mp, (u_long)sizeof(struct mount)); |
54fb9dc2 | 118 | mp->mnt_op = vfssw[uap->type]; |
d48157d5 KM |
119 | if (error = vfs_lock(mp)) { |
120 | free((caddr_t)mp, M_MOUNT); | |
121 | vput(vp); | |
8429d022 | 122 | return (error); |
d48157d5 | 123 | } |
7121fdf0 | 124 | if (vp->v_mountedhere != NULL) { |
d48157d5 KM |
125 | vfs_unlock(mp); |
126 | free((caddr_t)mp, M_MOUNT); | |
127 | vput(vp); | |
8429d022 | 128 | return (EBUSY); |
d48157d5 | 129 | } |
d48157d5 | 130 | vp->v_mountedhere = mp; |
54fb9dc2 | 131 | mp->mnt_vnodecovered = vp; |
d48157d5 KM |
132 | update: |
133 | /* | |
134 | * Set the mount level flags. | |
135 | */ | |
54fb9dc2 KM |
136 | if (uap->flags & MNT_RDONLY) |
137 | mp->mnt_flag |= MNT_RDONLY; | |
db62a40f KM |
138 | else if (mp->mnt_flag & MNT_RDONLY) |
139 | mp->mnt_flag |= MNT_WANTRDWR; | |
ac85da8a KM |
140 | mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | |
141 | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC); | |
142 | mp->mnt_flag |= uap->flags & (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | | |
143 | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC); | |
d48157d5 KM |
144 | /* |
145 | * Mount the filesystem. | |
146 | */ | |
7121fdf0 | 147 | error = VFS_MOUNT(mp, uap->path, uap->data, &nd, p); |
54fb9dc2 | 148 | if (mp->mnt_flag & MNT_UPDATE) { |
d48157d5 | 149 | vrele(vp); |
db62a40f KM |
150 | if (mp->mnt_flag & MNT_WANTRDWR) |
151 | mp->mnt_flag &= ~MNT_RDONLY; | |
152 | mp->mnt_flag &=~ | |
153 | (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR); | |
47971887 | 154 | if (error) |
54fb9dc2 | 155 | mp->mnt_flag = flag; |
8429d022 | 156 | return (error); |
d48157d5 | 157 | } |
92d0de98 KM |
158 | /* |
159 | * Put the new filesystem on the mount list after root. | |
160 | */ | |
fc2aed1e | 161 | cache_purge(vp); |
fc2aed1e | 162 | if (!error) { |
0f66cdec | 163 | TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); |
d48157d5 | 164 | VOP_UNLOCK(vp); |
fc2aed1e | 165 | vfs_unlock(mp); |
2c69fe14 | 166 | error = VFS_START(mp, 0, p); |
fc2aed1e | 167 | } else { |
0f66cdec KM |
168 | mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; |
169 | vfs_unlock(mp); | |
fc2aed1e | 170 | free((caddr_t)mp, M_MOUNT); |
d48157d5 | 171 | vput(vp); |
fc2aed1e | 172 | } |
8429d022 | 173 | return (error); |
3e78e260 BJ |
174 | } |
175 | ||
4f083fd7 | 176 | /* |
7121fdf0 | 177 | * Unmount a file system. |
fc2aed1e KM |
178 | * |
179 | * Note: unmount takes a path to the vnode mounted on as argument, | |
180 | * not special file (as before). | |
4f083fd7 | 181 | */ |
9e97623a | 182 | struct unmount_args { |
7121fdf0 | 183 | char *path; |
9e97623a CT |
184 | int flags; |
185 | }; | |
6a6a1e5f KM |
186 | /* ARGSUSED */ |
187 | unmount(p, uap, retval) | |
5e00df3b | 188 | struct proc *p; |
9e97623a | 189 | register struct unmount_args *uap; |
6a6a1e5f KM |
190 | int *retval; |
191 | { | |
fc2aed1e | 192 | register struct vnode *vp; |
9151110e | 193 | struct mount *mp; |
fc2aed1e | 194 | int error; |
8429d022 | 195 | struct nameidata nd; |
fc2aed1e | 196 | |
7121fdf0 | 197 | NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); |
dd4c01c2 | 198 | if (error = namei(&nd)) |
8429d022 | 199 | return (error); |
dd4c01c2 | 200 | vp = nd.ni_vp; |
f0e827e3 JSP |
201 | |
202 | /* | |
203 | * Unless this is a user mount, then must | |
204 | * have suser privilege. | |
205 | */ | |
206 | if (((vp->v_mount->mnt_flag & MNT_USER) == 0) && | |
207 | (error = suser(p->p_ucred, &p->p_acflag))) { | |
208 | vput(vp); | |
209 | return (error); | |
210 | } | |
211 | ||
fc2aed1e KM |
212 | /* |
213 | * Must be the root of the filesystem | |
214 | */ | |
215 | if ((vp->v_flag & VROOT) == 0) { | |
216 | vput(vp); | |
8429d022 | 217 | return (EINVAL); |
fc2aed1e KM |
218 | } |
219 | mp = vp->v_mount; | |
220 | vput(vp); | |
2c69fe14 | 221 | return (dounmount(mp, uap->flags, p)); |
9151110e KM |
222 | } |
223 | ||
224 | /* | |
7121fdf0 | 225 | * Do the actual file system unmount. |
9151110e | 226 | */ |
2c69fe14 | 227 | dounmount(mp, flags, p) |
9151110e KM |
228 | register struct mount *mp; |
229 | int flags; | |
2c69fe14 | 230 | struct proc *p; |
9151110e KM |
231 | { |
232 | struct vnode *coveredvp; | |
233 | int error; | |
234 | ||
54fb9dc2 | 235 | coveredvp = mp->mnt_vnodecovered; |
c001b1c3 KM |
236 | if (vfs_busy(mp)) |
237 | return (EBUSY); | |
54fb9dc2 | 238 | mp->mnt_flag |= MNT_UNMOUNT; |
fc2aed1e | 239 | if (error = vfs_lock(mp)) |
9151110e | 240 | return (error); |
fc2aed1e | 241 | |
1c295f6f | 242 | mp->mnt_flag &=~ MNT_ASYNC; |
9db58063 | 243 | vnode_pager_umount(mp); /* release cached vnodes */ |
fc2aed1e | 244 | cache_purgevfs(mp); /* remove cache entries for this file sys */ |
09d2ef1a KM |
245 | if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 || |
246 | (flags & MNT_FORCE)) | |
2c69fe14 | 247 | error = VFS_UNMOUNT(mp, flags, p); |
54fb9dc2 | 248 | mp->mnt_flag &= ~MNT_UNMOUNT; |
c001b1c3 | 249 | vfs_unbusy(mp); |
fc2aed1e KM |
250 | if (error) { |
251 | vfs_unlock(mp); | |
252 | } else { | |
253 | vrele(coveredvp); | |
0f66cdec KM |
254 | TAILQ_REMOVE(&mountlist, mp, mnt_list); |
255 | mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; | |
256 | vfs_unlock(mp); | |
257 | if (mp->mnt_vnodelist.lh_first != NULL) | |
ea2761aa | 258 | panic("unmount: dangling vnode"); |
fc2aed1e KM |
259 | free((caddr_t)mp, M_MOUNT); |
260 | } | |
9151110e | 261 | return (error); |
fc2aed1e KM |
262 | } |
263 | ||
264 | /* | |
fc2aed1e KM |
265 | * Sync each mounted filesystem. |
266 | */ | |
0649728d KM |
267 | #ifdef DIAGNOSTIC |
268 | int syncprt = 0; | |
6aecdd4c | 269 | struct ctldebug debug0 = { "syncprt", &syncprt }; |
0649728d KM |
270 | #endif |
271 | ||
9e97623a CT |
272 | struct sync_args { |
273 | int dummy; | |
274 | }; | |
ff4fb102 | 275 | /* ARGSUSED */ |
6a6a1e5f | 276 | sync(p, uap, retval) |
5e00df3b | 277 | struct proc *p; |
9e97623a | 278 | struct sync_args *uap; |
6a6a1e5f | 279 | int *retval; |
3e78e260 | 280 | { |
0f66cdec | 281 | register struct mount *mp, *nmp; |
1c295f6f | 282 | int asyncflag; |
fc2aed1e | 283 | |
0f66cdec KM |
284 | for (mp = mountlist.tqh_first; mp != NULL; mp = nmp) { |
285 | nmp = mp->mnt_list.tqe_next; | |
62e35d50 KM |
286 | /* |
287 | * The lock check below is to avoid races with mount | |
288 | * and unmount. | |
289 | */ | |
54fb9dc2 | 290 | if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && |
c001b1c3 | 291 | !vfs_busy(mp)) { |
1c295f6f KM |
292 | asyncflag = mp->mnt_flag & MNT_ASYNC; |
293 | mp->mnt_flag &= ~MNT_ASYNC; | |
09d2ef1a | 294 | VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p); |
1c295f6f KM |
295 | if (asyncflag) |
296 | mp->mnt_flag |= MNT_ASYNC; | |
0f66cdec KM |
297 | vfs_unbusy(mp); |
298 | } | |
299 | } | |
0649728d KM |
300 | #ifdef DIAGNOSTIC |
301 | if (syncprt) | |
302 | vfs_bufstats(); | |
303 | #endif /* DIAGNOSTIC */ | |
78eeb014 | 304 | return (0); |
fc2aed1e KM |
305 | } |
306 | ||
c001b1c3 | 307 | /* |
7121fdf0 | 308 | * Change filesystem quotas. |
c001b1c3 | 309 | */ |
9e97623a CT |
310 | struct quotactl_args { |
311 | char *path; | |
312 | int cmd; | |
313 | int uid; | |
314 | caddr_t arg; | |
315 | }; | |
6a6a1e5f KM |
316 | /* ARGSUSED */ |
317 | quotactl(p, uap, retval) | |
5e00df3b | 318 | struct proc *p; |
9e97623a | 319 | register struct quotactl_args *uap; |
6a6a1e5f KM |
320 | int *retval; |
321 | { | |
c001b1c3 | 322 | register struct mount *mp; |
c001b1c3 | 323 | int error; |
8429d022 | 324 | struct nameidata nd; |
c001b1c3 | 325 | |
dd4c01c2 KM |
326 | NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); |
327 | if (error = namei(&nd)) | |
8429d022 | 328 | return (error); |
dd4c01c2 KM |
329 | mp = nd.ni_vp->v_mount; |
330 | vrele(nd.ni_vp); | |
2c69fe14 | 331 | return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p)); |
c001b1c3 KM |
332 | } |
333 | ||
fc2aed1e | 334 | /* |
d4ed1dcd | 335 | * Get filesystem statistics. |
fc2aed1e | 336 | */ |
9e97623a CT |
337 | struct statfs_args { |
338 | char *path; | |
339 | struct statfs *buf; | |
340 | }; | |
6a6a1e5f KM |
341 | /* ARGSUSED */ |
342 | statfs(p, uap, retval) | |
5e00df3b | 343 | struct proc *p; |
9e97623a | 344 | register struct statfs_args *uap; |
6a6a1e5f KM |
345 | int *retval; |
346 | { | |
3f705640 | 347 | register struct mount *mp; |
62e35d50 | 348 | register struct statfs *sp; |
fc2aed1e | 349 | int error; |
8429d022 | 350 | struct nameidata nd; |
3e78e260 | 351 | |
dd4c01c2 KM |
352 | NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); |
353 | if (error = namei(&nd)) | |
8429d022 | 354 | return (error); |
dd4c01c2 | 355 | mp = nd.ni_vp->v_mount; |
54fb9dc2 | 356 | sp = &mp->mnt_stat; |
dd4c01c2 | 357 | vrele(nd.ni_vp); |
2c69fe14 | 358 | if (error = VFS_STATFS(mp, sp, p)) |
8429d022 | 359 | return (error); |
54fb9dc2 | 360 | sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; |
8429d022 | 361 | return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); |
fc2aed1e KM |
362 | } |
363 | ||
6a6a1e5f | 364 | /* |
d4ed1dcd | 365 | * Get filesystem statistics. |
6a6a1e5f | 366 | */ |
9e97623a CT |
367 | struct fstatfs_args { |
368 | int fd; | |
369 | struct statfs *buf; | |
370 | }; | |
6a6a1e5f KM |
371 | /* ARGSUSED */ |
372 | fstatfs(p, uap, retval) | |
5e00df3b | 373 | struct proc *p; |
9e97623a | 374 | register struct fstatfs_args *uap; |
6a6a1e5f KM |
375 | int *retval; |
376 | { | |
fc2aed1e | 377 | struct file *fp; |
3f705640 | 378 | struct mount *mp; |
62e35d50 | 379 | register struct statfs *sp; |
fc2aed1e KM |
380 | int error; |
381 | ||
5e00df3b | 382 | if (error = getvnode(p->p_fd, uap->fd, &fp)) |
8429d022 | 383 | return (error); |
3f705640 | 384 | mp = ((struct vnode *)fp->f_data)->v_mount; |
54fb9dc2 | 385 | sp = &mp->mnt_stat; |
2c69fe14 | 386 | if (error = VFS_STATFS(mp, sp, p)) |
8429d022 | 387 | return (error); |
54fb9dc2 | 388 | sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; |
8429d022 | 389 | return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); |
3e78e260 BJ |
390 | } |
391 | ||
bfcdbfbf | 392 | /* |
d4ed1dcd | 393 | * Get statistics on all filesystems. |
bfcdbfbf | 394 | */ |
9e97623a CT |
395 | struct getfsstat_args { |
396 | struct statfs *buf; | |
397 | long bufsize; | |
398 | int flags; | |
399 | }; | |
6a6a1e5f | 400 | getfsstat(p, uap, retval) |
5e00df3b | 401 | struct proc *p; |
9e97623a | 402 | register struct getfsstat_args *uap; |
6a6a1e5f KM |
403 | int *retval; |
404 | { | |
0f66cdec | 405 | register struct mount *mp, *nmp; |
62e35d50 | 406 | register struct statfs *sp; |
f62fad9a | 407 | caddr_t sfsp; |
bfcdbfbf KM |
408 | long count, maxcount, error; |
409 | ||
410 | maxcount = uap->bufsize / sizeof(struct statfs); | |
f62fad9a | 411 | sfsp = (caddr_t)uap->buf; |
0f66cdec KM |
412 | for (count = 0, mp = mountlist.tqh_first; mp != NULL; mp = nmp) { |
413 | nmp = mp->mnt_list.tqe_next; | |
54fb9dc2 KM |
414 | if (sfsp && count < maxcount && |
415 | ((mp->mnt_flag & MNT_MLOCK) == 0)) { | |
416 | sp = &mp->mnt_stat; | |
62e35d50 KM |
417 | /* |
418 | * If MNT_NOWAIT is specified, do not refresh the | |
419 | * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. | |
420 | */ | |
421 | if (((uap->flags & MNT_NOWAIT) == 0 || | |
422 | (uap->flags & MNT_WAIT)) && | |
0f66cdec | 423 | (error = VFS_STATFS(mp, sp, p))) |
fd8516be | 424 | continue; |
54fb9dc2 | 425 | sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; |
62e35d50 | 426 | if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) |
8429d022 | 427 | return (error); |
62e35d50 | 428 | sfsp += sizeof(*sp); |
bfcdbfbf | 429 | } |
f62fad9a | 430 | count++; |
0f66cdec | 431 | } |
bfcdbfbf | 432 | if (sfsp && count > maxcount) |
6a6a1e5f | 433 | *retval = maxcount; |
bfcdbfbf | 434 | else |
6a6a1e5f | 435 | *retval = count; |
8429d022 | 436 | return (0); |
bfcdbfbf KM |
437 | } |
438 | ||
6995a2cb KM |
439 | /* |
440 | * Change current working directory to a given file descriptor. | |
441 | */ | |
9e97623a CT |
442 | struct fchdir_args { |
443 | int fd; | |
444 | }; | |
6a6a1e5f KM |
445 | /* ARGSUSED */ |
446 | fchdir(p, uap, retval) | |
5e00df3b | 447 | struct proc *p; |
9e97623a | 448 | struct fchdir_args *uap; |
6a6a1e5f KM |
449 | int *retval; |
450 | { | |
5e00df3b | 451 | register struct filedesc *fdp = p->p_fd; |
6995a2cb KM |
452 | register struct vnode *vp; |
453 | struct file *fp; | |
454 | int error; | |
455 | ||
5e00df3b | 456 | if (error = getvnode(fdp, uap->fd, &fp)) |
8429d022 | 457 | return (error); |
6995a2cb KM |
458 | vp = (struct vnode *)fp->f_data; |
459 | VOP_LOCK(vp); | |
460 | if (vp->v_type != VDIR) | |
461 | error = ENOTDIR; | |
462 | else | |
2c69fe14 | 463 | error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); |
6995a2cb | 464 | VOP_UNLOCK(vp); |
ab214c34 | 465 | if (error) |
8429d022 | 466 | return (error); |
ab214c34 | 467 | VREF(vp); |
5e00df3b KM |
468 | vrele(fdp->fd_cdir); |
469 | fdp->fd_cdir = vp; | |
8429d022 | 470 | return (0); |
6995a2cb KM |
471 | } |
472 | ||
4f083fd7 | 473 | /* |
fc2aed1e | 474 | * Change current working directory (``.''). |
4f083fd7 | 475 | */ |
9e97623a | 476 | struct chdir_args { |
7121fdf0 | 477 | char *path; |
9e97623a | 478 | }; |
6a6a1e5f KM |
479 | /* ARGSUSED */ |
480 | chdir(p, uap, retval) | |
5e00df3b | 481 | struct proc *p; |
9e97623a | 482 | struct chdir_args *uap; |
6a6a1e5f KM |
483 | int *retval; |
484 | { | |
5e00df3b | 485 | register struct filedesc *fdp = p->p_fd; |
fc2aed1e | 486 | int error; |
8429d022 | 487 | struct nameidata nd; |
3e78e260 | 488 | |
7121fdf0 KB |
489 | NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); |
490 | if (error = change_dir(&nd, p)) | |
8429d022 | 491 | return (error); |
5e00df3b | 492 | vrele(fdp->fd_cdir); |
dd4c01c2 | 493 | fdp->fd_cdir = nd.ni_vp; |
8429d022 | 494 | return (0); |
fc2aed1e KM |
495 | } |
496 | ||
497 | /* | |
498 | * Change notion of root (``/'') directory. | |
499 | */ | |
9e97623a | 500 | struct chroot_args { |
7121fdf0 | 501 | char *path; |
9e97623a | 502 | }; |
6a6a1e5f KM |
503 | /* ARGSUSED */ |
504 | chroot(p, uap, retval) | |
5e00df3b | 505 | struct proc *p; |
9e97623a | 506 | struct chroot_args *uap; |
6a6a1e5f KM |
507 | int *retval; |
508 | { | |
5e00df3b | 509 | register struct filedesc *fdp = p->p_fd; |
fc2aed1e | 510 | int error; |
8429d022 | 511 | struct nameidata nd; |
fc2aed1e | 512 | |
8429d022 MK |
513 | if (error = suser(p->p_ucred, &p->p_acflag)) |
514 | return (error); | |
7121fdf0 KB |
515 | NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); |
516 | if (error = change_dir(&nd, p)) | |
8429d022 | 517 | return (error); |
5e00df3b KM |
518 | if (fdp->fd_rdir != NULL) |
519 | vrele(fdp->fd_rdir); | |
dd4c01c2 | 520 | fdp->fd_rdir = nd.ni_vp; |
8429d022 | 521 | return (0); |
fc2aed1e KM |
522 | } |
523 | ||
524 | /* | |
525 | * Common routine for chroot and chdir. | |
526 | */ | |
7121fdf0 KB |
527 | static int |
528 | change_dir(ndp, p) | |
dd4c01c2 | 529 | register struct nameidata *ndp; |
8429d022 | 530 | struct proc *p; |
fc2aed1e KM |
531 | { |
532 | struct vnode *vp; | |
533 | int error; | |
534 | ||
dd4c01c2 | 535 | if (error = namei(ndp)) |
fc2aed1e KM |
536 | return (error); |
537 | vp = ndp->ni_vp; | |
538 | if (vp->v_type != VDIR) | |
539 | error = ENOTDIR; | |
540 | else | |
2c69fe14 | 541 | error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); |
fc2aed1e KM |
542 | VOP_UNLOCK(vp); |
543 | if (error) | |
544 | vrele(vp); | |
545 | return (error); | |
3e78e260 BJ |
546 | } |
547 | ||
548 | /* | |
6a6a1e5f KM |
549 | * Check permissions, allocate an open file structure, |
550 | * and call the device open routine if any. | |
3e78e260 | 551 | */ |
9e97623a | 552 | struct open_args { |
7121fdf0 KB |
553 | char *path; |
554 | int flags; | |
9e97623a | 555 | int mode; |
9e97623a | 556 | }; |
6a6a1e5f | 557 | open(p, uap, retval) |
5e00df3b | 558 | struct proc *p; |
9e97623a | 559 | register struct open_args *uap; |
6a6a1e5f | 560 | int *retval; |
3e78e260 | 561 | { |
5e00df3b | 562 | register struct filedesc *fdp = p->p_fd; |
3e78e260 | 563 | register struct file *fp; |
6aaf085a | 564 | register struct vnode *vp; |
7121fdf0 | 565 | int flags, cmode; |
fc2aed1e | 566 | struct file *nfp; |
ff8d1617 KM |
567 | int type, indx, error; |
568 | struct flock lf; | |
8429d022 | 569 | struct nameidata nd; |
fc2aed1e KM |
570 | extern struct fileops vnops; |
571 | ||
5e00df3b | 572 | if (error = falloc(p, &nfp, &indx)) |
8429d022 | 573 | return (error); |
fc2aed1e | 574 | fp = nfp; |
7121fdf0 KB |
575 | flags = FFLAGS(uap->flags); |
576 | cmode = ((uap->mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; | |
577 | NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); | |
03951846 | 578 | p->p_dupfd = -indx - 1; /* XXX check for fdopen */ |
7121fdf0 | 579 | if (error = vn_open(&nd, flags, cmode)) { |
336f999d | 580 | ffree(fp); |
f0e12026 KM |
581 | if ((error == ENODEV || error == ENXIO) && |
582 | p->p_dupfd >= 0 && /* XXX from fdopen */ | |
7121fdf0 KB |
583 | (error = |
584 | dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) { | |
6a6a1e5f | 585 | *retval = indx; |
8429d022 | 586 | return (0); |
6a6a1e5f | 587 | } |
b10521d6 KM |
588 | if (error == ERESTART) |
589 | error = EINTR; | |
78eeb014 | 590 | fdp->fd_ofiles[indx] = NULL; |
8429d022 | 591 | return (error); |
528f664c | 592 | } |
da5acac3 | 593 | p->p_dupfd = 0; |
dd4c01c2 | 594 | vp = nd.ni_vp; |
7121fdf0 | 595 | fp->f_flag = flags & FMASK; |
8932276d KM |
596 | fp->f_type = DTYPE_VNODE; |
597 | fp->f_ops = &vnops; | |
598 | fp->f_data = (caddr_t)vp; | |
7121fdf0 | 599 | if (flags & (O_EXLOCK | O_SHLOCK)) { |
ff8d1617 KM |
600 | lf.l_whence = SEEK_SET; |
601 | lf.l_start = 0; | |
602 | lf.l_len = 0; | |
7121fdf0 | 603 | if (flags & O_EXLOCK) |
ff8d1617 KM |
604 | lf.l_type = F_WRLCK; |
605 | else | |
606 | lf.l_type = F_RDLCK; | |
607 | type = F_FLOCK; | |
7121fdf0 | 608 | if ((flags & FNONBLOCK) == 0) |
ff8d1617 | 609 | type |= F_WAIT; |
70b7fe1d | 610 | VOP_UNLOCK(vp); |
6aaf085a | 611 | if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { |
6aaf085a | 612 | (void) vn_close(vp, fp->f_flag, fp->f_cred, p); |
336f999d | 613 | ffree(fp); |
ff8d1617 KM |
614 | fdp->fd_ofiles[indx] = NULL; |
615 | return (error); | |
616 | } | |
70b7fe1d | 617 | VOP_LOCK(vp); |
b40ecf6f | 618 | fp->f_flag |= FHASLOCK; |
ff8d1617 | 619 | } |
6aaf085a | 620 | VOP_UNLOCK(vp); |
6a6a1e5f | 621 | *retval = indx; |
8429d022 | 622 | return (0); |
3e78e260 BJ |
623 | } |
624 | ||
4fde03dc | 625 | #ifdef COMPAT_43 |
3e78e260 | 626 | /* |
7121fdf0 | 627 | * Create a file. |
3e78e260 | 628 | */ |
9e97623a | 629 | struct ocreat_args { |
7121fdf0 KB |
630 | char *path; |
631 | int mode; | |
9e97623a | 632 | }; |
4fde03dc | 633 | ocreat(p, uap, retval) |
6a6a1e5f | 634 | struct proc *p; |
9e97623a | 635 | register struct ocreat_args *uap; |
6a6a1e5f | 636 | int *retval; |
3e78e260 | 637 | { |
9e97623a | 638 | struct open_args openuap; |
6a6a1e5f | 639 | |
7121fdf0 KB |
640 | openuap.path = uap->path; |
641 | openuap.mode = uap->mode; | |
642 | openuap.flags = O_WRONLY | O_CREAT | O_TRUNC; | |
8429d022 | 643 | return (open(p, &openuap, retval)); |
6a6a1e5f | 644 | } |
4fde03dc | 645 | #endif /* COMPAT_43 */ |
6a6a1e5f KM |
646 | |
647 | /* | |
7121fdf0 | 648 | * Create a special file. |
6a6a1e5f | 649 | */ |
9e97623a | 650 | struct mknod_args { |
7121fdf0 KB |
651 | char *path; |
652 | int mode; | |
9e97623a CT |
653 | int dev; |
654 | }; | |
6a6a1e5f KM |
655 | /* ARGSUSED */ |
656 | mknod(p, uap, retval) | |
5e00df3b | 657 | struct proc *p; |
9e97623a | 658 | register struct mknod_args *uap; |
6a6a1e5f KM |
659 | int *retval; |
660 | { | |
fc2aed1e KM |
661 | register struct vnode *vp; |
662 | struct vattr vattr; | |
663 | int error; | |
8429d022 | 664 | struct nameidata nd; |
3e78e260 | 665 | |
a5368812 | 666 | CHECKPOINTREF; |
8429d022 MK |
667 | if (error = suser(p->p_ucred, &p->p_acflag)) |
668 | return (error); | |
7121fdf0 | 669 | NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); |
dd4c01c2 | 670 | if (error = namei(&nd)) |
8429d022 | 671 | return (error); |
dd4c01c2 | 672 | vp = nd.ni_vp; |
cf5ef508 | 673 | if (vp != NULL) |
fc2aed1e | 674 | error = EEXIST; |
cf5ef508 KB |
675 | else { |
676 | VATTR_NULL(&vattr); | |
677 | vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask; | |
678 | vattr.va_rdev = uap->dev; | |
679 | ||
680 | switch (uap->mode & S_IFMT) { | |
681 | case S_IFMT: /* used by badsect to flag bad sectors */ | |
682 | vattr.va_type = VBAD; | |
683 | break; | |
684 | case S_IFCHR: | |
685 | vattr.va_type = VCHR; | |
686 | break; | |
687 | case S_IFBLK: | |
688 | vattr.va_type = VBLK; | |
689 | break; | |
690 | default: | |
691 | error = EINVAL; | |
692 | break; | |
693 | } | |
3e78e260 | 694 | } |
66955caf | 695 | if (!error) { |
dd4c01c2 KM |
696 | LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); |
697 | error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); | |
66955caf | 698 | } else { |
dd4c01c2 KM |
699 | VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); |
700 | if (nd.ni_dvp == vp) | |
701 | vrele(nd.ni_dvp); | |
6c44e83b | 702 | else |
dd4c01c2 | 703 | vput(nd.ni_dvp); |
66955caf KM |
704 | if (vp) |
705 | vrele(vp); | |
706 | } | |
a5368812 | 707 | CHECKREFS("mknod"); |
8429d022 | 708 | return (error); |
3e78e260 BJ |
709 | } |
710 | ||
4751dd21 | 711 | /* |
7121fdf0 | 712 | * Create named pipe. |
4751dd21 | 713 | */ |
9e97623a | 714 | struct mkfifo_args { |
7121fdf0 KB |
715 | char *path; |
716 | int mode; | |
9e97623a | 717 | }; |
6a6a1e5f KM |
718 | /* ARGSUSED */ |
719 | mkfifo(p, uap, retval) | |
5e00df3b | 720 | struct proc *p; |
9e97623a | 721 | register struct mkfifo_args *uap; |
6a6a1e5f KM |
722 | int *retval; |
723 | { | |
4751dd21 KM |
724 | struct vattr vattr; |
725 | int error; | |
8429d022 | 726 | struct nameidata nd; |
4751dd21 KM |
727 | |
728 | #ifndef FIFO | |
8429d022 | 729 | return (EOPNOTSUPP); |
4751dd21 | 730 | #else |
7121fdf0 | 731 | NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); |
dd4c01c2 | 732 | if (error = namei(&nd)) |
8429d022 | 733 | return (error); |
dd4c01c2 KM |
734 | if (nd.ni_vp != NULL) { |
735 | VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); | |
736 | if (nd.ni_dvp == nd.ni_vp) | |
737 | vrele(nd.ni_dvp); | |
6c44e83b | 738 | else |
dd4c01c2 KM |
739 | vput(nd.ni_dvp); |
740 | vrele(nd.ni_vp); | |
8429d022 | 741 | return (EEXIST); |
4751dd21 | 742 | } |
3658f091 KB |
743 | VATTR_NULL(&vattr); |
744 | vattr.va_type = VFIFO; | |
7121fdf0 | 745 | vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask; |
dd4c01c2 KM |
746 | LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); |
747 | return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); | |
4751dd21 KM |
748 | #endif /* FIFO */ |
749 | } | |
750 | ||
3e78e260 | 751 | /* |
7121fdf0 | 752 | * Make a hard file link. |
3e78e260 | 753 | */ |
9e97623a | 754 | struct link_args { |
7121fdf0 KB |
755 | char *path; |
756 | char *link; | |
9e97623a | 757 | }; |
6a6a1e5f KM |
758 | /* ARGSUSED */ |
759 | link(p, uap, retval) | |
5e00df3b | 760 | struct proc *p; |
9e97623a | 761 | register struct link_args *uap; |
6a6a1e5f KM |
762 | int *retval; |
763 | { | |
7121fdf0 | 764 | register struct vnode *vp; |
8429d022 | 765 | struct nameidata nd; |
7121fdf0 | 766 | int error; |
3e78e260 | 767 | |
a5368812 | 768 | CHECKPOINTREF; |
7121fdf0 | 769 | NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); |
dd4c01c2 | 770 | if (error = namei(&nd)) |
8429d022 | 771 | return (error); |
dd4c01c2 | 772 | vp = nd.ni_vp; |
cf5ef508 KB |
773 | if (vp->v_type != VDIR || |
774 | (error = suser(p->p_ucred, &p->p_acflag)) == 0) { | |
775 | nd.ni_cnd.cn_nameiop = CREATE; | |
776 | nd.ni_cnd.cn_flags = LOCKPARENT; | |
777 | nd.ni_dirp = uap->link; | |
778 | if ((error = namei(&nd)) == 0) { | |
779 | if (nd.ni_vp != NULL) | |
780 | error = EEXIST; | |
781 | if (!error) { | |
782 | LEASE_CHECK(nd.ni_dvp, | |
783 | p, p->p_ucred, LEASE_WRITE); | |
784 | LEASE_CHECK(vp, | |
785 | p, p->p_ucred, LEASE_WRITE); | |
786 | error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); | |
787 | } else { | |
788 | VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); | |
789 | if (nd.ni_dvp == nd.ni_vp) | |
790 | vrele(nd.ni_dvp); | |
791 | else | |
792 | vput(nd.ni_dvp); | |
793 | if (nd.ni_vp) | |
794 | vrele(nd.ni_vp); | |
795 | } | |
796 | } | |
66955caf | 797 | } |
cf5ef508 | 798 | vrele(vp); |
a5368812 | 799 | CHECKREFS("link"); |
8429d022 | 800 | return (error); |
3e78e260 BJ |
801 | } |
802 | ||
803 | /* | |
d4ed1dcd | 804 | * Make a symbolic link. |
3e78e260 | 805 | */ |
9e97623a | 806 | struct symlink_args { |
7121fdf0 KB |
807 | char *path; |
808 | char *link; | |
9e97623a | 809 | }; |
6a6a1e5f KM |
810 | /* ARGSUSED */ |
811 | symlink(p, uap, retval) | |
5e00df3b | 812 | struct proc *p; |
9e97623a | 813 | register struct symlink_args *uap; |
6a6a1e5f KM |
814 | int *retval; |
815 | { | |
fc2aed1e | 816 | struct vattr vattr; |
7121fdf0 | 817 | char *path; |
fc2aed1e | 818 | int error; |
8429d022 | 819 | struct nameidata nd; |
3e78e260 | 820 | |
a5368812 | 821 | CHECKPOINTREF; |
7121fdf0 KB |
822 | MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); |
823 | if (error = copyinstr(uap->path, path, MAXPATHLEN, NULL)) | |
66955caf | 824 | goto out; |
7121fdf0 | 825 | NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->link, p); |
dd4c01c2 | 826 | if (error = namei(&nd)) |
66955caf | 827 | goto out; |
dd4c01c2 KM |
828 | if (nd.ni_vp) { |
829 | VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); | |
830 | if (nd.ni_dvp == nd.ni_vp) | |
831 | vrele(nd.ni_dvp); | |
6c44e83b | 832 | else |
dd4c01c2 KM |
833 | vput(nd.ni_dvp); |
834 | vrele(nd.ni_vp); | |
fc2aed1e KM |
835 | error = EEXIST; |
836 | goto out; | |
3e78e260 | 837 | } |
3ee1461b | 838 | VATTR_NULL(&vattr); |
7121fdf0 | 839 | vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask; |
dd4c01c2 | 840 | LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); |
7121fdf0 | 841 | error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path); |
fc2aed1e | 842 | out: |
7121fdf0 | 843 | FREE(path, M_NAMEI); |
a5368812 | 844 | CHECKREFS("symlink"); |
8429d022 | 845 | return (error); |
3e78e260 BJ |
846 | } |
847 | ||
848 | /* | |
d4ed1dcd | 849 | * Delete a name from the filesystem. |
3e78e260 | 850 | */ |
9e97623a | 851 | struct unlink_args { |
7121fdf0 | 852 | char *path; |
9e97623a | 853 | }; |
6a6a1e5f KM |
854 | /* ARGSUSED */ |
855 | unlink(p, uap, retval) | |
5e00df3b | 856 | struct proc *p; |
9e97623a | 857 | struct unlink_args *uap; |
6a6a1e5f KM |
858 | int *retval; |
859 | { | |
fc2aed1e KM |
860 | register struct vnode *vp; |
861 | int error; | |
8429d022 | 862 | struct nameidata nd; |
3e78e260 | 863 | |
a5368812 | 864 | CHECKPOINTREF; |
7121fdf0 | 865 | NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->path, p); |
dd4c01c2 | 866 | if (error = namei(&nd)) |
8429d022 | 867 | return (error); |
dd4c01c2 | 868 | vp = nd.ni_vp; |
dbcf7de6 KM |
869 | LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); |
870 | VOP_LOCK(vp); | |
7121fdf0 | 871 | |
cf5ef508 KB |
872 | if (vp->v_type != VDIR || |
873 | (error = suser(p->p_ucred, &p->p_acflag)) == 0) { | |
874 | /* | |
875 | * The root of a mounted filesystem cannot be deleted. | |
876 | */ | |
877 | if (vp->v_flag & VROOT) | |
878 | error = EBUSY; | |
879 | else | |
880 | (void)vnode_pager_uncache(vp); | |
881 | } | |
882 | ||
883 | if (!error) { | |
dd4c01c2 | 884 | LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); |
dd4c01c2 | 885 | error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); |
66955caf | 886 | } else { |
dd4c01c2 KM |
887 | VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); |
888 | if (nd.ni_dvp == vp) | |
889 | vrele(nd.ni_dvp); | |
6c44e83b | 890 | else |
dd4c01c2 | 891 | vput(nd.ni_dvp); |
66955caf KM |
892 | vput(vp); |
893 | } | |
a5368812 | 894 | CHECKREFS("unlink"); |
8429d022 | 895 | return (error); |
3e78e260 BJ |
896 | } |
897 | ||
7121fdf0 KB |
898 | /* |
899 | * Reposition read/write file offset. | |
900 | */ | |
95c0eb1e | 901 | struct lseek_args { |
7121fdf0 | 902 | int fd; |
2f2b3b3d | 903 | int pad; |
7121fdf0 KB |
904 | off_t offset; |
905 | int whence; | |
2f2b3b3d | 906 | }; |
201e5411 | 907 | lseek(p, uap, retval) |
5e00df3b | 908 | struct proc *p; |
95c0eb1e | 909 | register struct lseek_args *uap; |
9e97623a | 910 | int *retval; |
6a6a1e5f | 911 | { |
8429d022 | 912 | struct ucred *cred = p->p_ucred; |
5e00df3b | 913 | register struct filedesc *fdp = p->p_fd; |
6a6a1e5f | 914 | register struct file *fp; |
fc2aed1e KM |
915 | struct vattr vattr; |
916 | int error; | |
917 | ||
7121fdf0 KB |
918 | if ((u_int)uap->fd >= fdp->fd_nfiles || |
919 | (fp = fdp->fd_ofiles[uap->fd]) == NULL) | |
8429d022 | 920 | return (EBADF); |
fc2aed1e | 921 | if (fp->f_type != DTYPE_VNODE) |
8429d022 | 922 | return (ESPIPE); |
7121fdf0 | 923 | switch (uap->whence) { |
b4d1aee9 | 924 | case L_INCR: |
7121fdf0 | 925 | fp->f_offset += uap->offset; |
b4d1aee9 | 926 | break; |
b4d1aee9 | 927 | case L_XTND: |
7121fdf0 KB |
928 | if (error = |
929 | VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p)) | |
8429d022 | 930 | return (error); |
7121fdf0 | 931 | fp->f_offset = uap->offset + vattr.va_size; |
b4d1aee9 | 932 | break; |
b4d1aee9 | 933 | case L_SET: |
7121fdf0 | 934 | fp->f_offset = uap->offset; |
b4d1aee9 | 935 | break; |
b4d1aee9 | 936 | default: |
8429d022 | 937 | return (EINVAL); |
b4d1aee9 | 938 | } |
9e97623a | 939 | *(off_t *)retval = fp->f_offset; |
8429d022 | 940 | return (0); |
3e78e260 BJ |
941 | } |
942 | ||
201e5411 | 943 | #if defined(COMPAT_43) || defined(COMPAT_SUNOS) |
64deb204 | 944 | /* |
7121fdf0 | 945 | * Reposition read/write file offset. |
64deb204 | 946 | */ |
95c0eb1e | 947 | struct olseek_args { |
7121fdf0 KB |
948 | int fd; |
949 | long offset; | |
950 | int whence; | |
64deb204 | 951 | }; |
201e5411 | 952 | olseek(p, uap, retval) |
64deb204 | 953 | struct proc *p; |
95c0eb1e | 954 | register struct olseek_args *uap; |
64deb204 KM |
955 | int *retval; |
956 | { | |
95c0eb1e | 957 | struct lseek_args nuap; |
64deb204 KM |
958 | off_t qret; |
959 | int error; | |
960 | ||
7121fdf0 KB |
961 | nuap.fd = uap->fd; |
962 | nuap.offset = uap->offset; | |
963 | nuap.whence = uap->whence; | |
95c0eb1e | 964 | error = lseek(p, &nuap, &qret); |
64deb204 KM |
965 | *(long *)retval = qret; |
966 | return (error); | |
967 | } | |
201e5411 | 968 | #endif /* COMPAT_43 */ |
64deb204 | 969 | |
3e78e260 | 970 | /* |
d4ed1dcd | 971 | * Check access permissions. |
3e78e260 | 972 | */ |
b54e8954 | 973 | struct access_args { |
7121fdf0 KB |
974 | char *path; |
975 | int flags; | |
9e97623a | 976 | }; |
b54e8954 | 977 | access(p, uap, retval) |
5e00df3b | 978 | struct proc *p; |
b54e8954 | 979 | register struct access_args *uap; |
6a6a1e5f KM |
980 | int *retval; |
981 | { | |
8429d022 | 982 | register struct ucred *cred = p->p_ucred; |
fc2aed1e | 983 | register struct vnode *vp; |
cf5ef508 | 984 | int error, flags, t_gid, t_uid; |
8429d022 | 985 | struct nameidata nd; |
3e78e260 | 986 | |
cf5ef508 KB |
987 | t_uid = cred->cr_uid; |
988 | t_gid = cred->cr_groups[0]; | |
8429d022 MK |
989 | cred->cr_uid = p->p_cred->p_ruid; |
990 | cred->cr_groups[0] = p->p_cred->p_rgid; | |
7121fdf0 | 991 | NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); |
dd4c01c2 | 992 | if (error = namei(&nd)) |
fc2aed1e | 993 | goto out1; |
dd4c01c2 | 994 | vp = nd.ni_vp; |
7121fdf0 KB |
995 | |
996 | /* Flags == 0 means only check for existence. */ | |
997 | if (uap->flags) { | |
998 | flags = 0; | |
999 | if (uap->flags & R_OK) | |
1000 | flags |= VREAD; | |
1001 | if (uap->flags & W_OK) | |
1002 | flags |= VWRITE; | |
1003 | if (uap->flags & X_OK) | |
1004 | flags |= VEXEC; | |
1005 | if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) | |
1006 | error = VOP_ACCESS(vp, flags, cred, p); | |
3e78e260 | 1007 | } |
fc2aed1e KM |
1008 | vput(vp); |
1009 | out1: | |
cf5ef508 KB |
1010 | cred->cr_uid = t_uid; |
1011 | cred->cr_groups[0] = t_gid; | |
8429d022 | 1012 | return (error); |
3e78e260 | 1013 | } |
d67a03eb | 1014 | |
8932276d | 1015 | #if defined(COMPAT_43) || defined(COMPAT_SUNOS) |
d67a03eb | 1016 | /* |
7121fdf0 | 1017 | * Get file status; this version follows links. |
d67a03eb | 1018 | */ |
9e97623a | 1019 | struct ostat_args { |
7121fdf0 | 1020 | char *path; |
9e97623a CT |
1021 | struct ostat *ub; |
1022 | }; | |
6a6a1e5f | 1023 | /* ARGSUSED */ |
ae9b6dc3 | 1024 | ostat(p, uap, retval) |
be320a2b | 1025 | struct proc *p; |
9e97623a | 1026 | register struct ostat_args *uap; |
be320a2b KM |
1027 | int *retval; |
1028 | { | |
1029 | struct stat sb; | |
1030 | struct ostat osb; | |
1031 | int error; | |
1032 | struct nameidata nd; | |
1033 | ||
7121fdf0 | 1034 | NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); |
be320a2b KM |
1035 | if (error = namei(&nd)) |
1036 | return (error); | |
1037 | error = vn_stat(nd.ni_vp, &sb, p); | |
1038 | vput(nd.ni_vp); | |
1039 | if (error) | |
1040 | return (error); | |
1041 | cvtstat(&sb, &osb); | |
1042 | error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); | |
1043 | return (error); | |
1044 | } | |
1045 | ||
1046 | /* | |
7121fdf0 | 1047 | * Get file status; this version does not follow links. |
be320a2b | 1048 | */ |
9e97623a | 1049 | struct olstat_args { |
7121fdf0 | 1050 | char *path; |
9e97623a CT |
1051 | struct ostat *ub; |
1052 | }; | |
be320a2b | 1053 | /* ARGSUSED */ |
ae9b6dc3 | 1054 | olstat(p, uap, retval) |
be320a2b | 1055 | struct proc *p; |
9e97623a | 1056 | register struct olstat_args *uap; |
be320a2b KM |
1057 | int *retval; |
1058 | { | |
1059 | struct stat sb; | |
1060 | struct ostat osb; | |
1061 | int error; | |
1062 | struct nameidata nd; | |
1063 | ||
7121fdf0 | 1064 | NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); |
be320a2b KM |
1065 | if (error = namei(&nd)) |
1066 | return (error); | |
1067 | error = vn_stat(nd.ni_vp, &sb, p); | |
1068 | vput(nd.ni_vp); | |
1069 | if (error) | |
1070 | return (error); | |
1071 | cvtstat(&sb, &osb); | |
1072 | error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); | |
1073 | return (error); | |
1074 | } | |
1075 | ||
1076 | /* | |
7121fdf0 | 1077 | * Convert from an old to a new stat structure. |
be320a2b KM |
1078 | */ |
1079 | cvtstat(st, ost) | |
1080 | struct stat *st; | |
1081 | struct ostat *ost; | |
1082 | { | |
1083 | ||
1084 | ost->st_dev = st->st_dev; | |
1085 | ost->st_ino = st->st_ino; | |
1086 | ost->st_mode = st->st_mode; | |
1087 | ost->st_nlink = st->st_nlink; | |
1088 | ost->st_uid = st->st_uid; | |
1089 | ost->st_gid = st->st_gid; | |
1090 | ost->st_rdev = st->st_rdev; | |
1091 | if (st->st_size < (quad_t)1 << 32) | |
1092 | ost->st_size = st->st_size; | |
1093 | else | |
1094 | ost->st_size = -2; | |
1095 | ost->st_atime = st->st_atime; | |
1096 | ost->st_mtime = st->st_mtime; | |
1097 | ost->st_ctime = st->st_ctime; | |
1098 | ost->st_blksize = st->st_blksize; | |
1099 | ost->st_blocks = st->st_blocks; | |
1100 | ost->st_flags = st->st_flags; | |
1101 | ost->st_gen = st->st_gen; | |
1102 | } | |
8932276d | 1103 | #endif /* COMPAT_43 || COMPAT_SUNOS */ |
be320a2b KM |
1104 | |
1105 | /* | |
7121fdf0 | 1106 | * Get file status; this version follows links. |
be320a2b | 1107 | */ |
9e97623a | 1108 | struct stat_args { |
7121fdf0 | 1109 | char *path; |
9e97623a CT |
1110 | struct stat *ub; |
1111 | }; | |
be320a2b | 1112 | /* ARGSUSED */ |
ae9b6dc3 | 1113 | stat(p, uap, retval) |
5e00df3b | 1114 | struct proc *p; |
9e97623a | 1115 | register struct stat_args *uap; |
6a6a1e5f | 1116 | int *retval; |
d67a03eb | 1117 | { |
6a6a1e5f KM |
1118 | struct stat sb; |
1119 | int error; | |
8429d022 | 1120 | struct nameidata nd; |
d67a03eb | 1121 | |
7121fdf0 | 1122 | NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); |
dd4c01c2 | 1123 | if (error = namei(&nd)) |
8429d022 | 1124 | return (error); |
dd4c01c2 KM |
1125 | error = vn_stat(nd.ni_vp, &sb, p); |
1126 | vput(nd.ni_vp); | |
6a6a1e5f | 1127 | if (error) |
8429d022 | 1128 | return (error); |
6a6a1e5f | 1129 | error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); |
8429d022 | 1130 | return (error); |
d67a03eb BJ |
1131 | } |
1132 | ||
5485e062 | 1133 | /* |
7121fdf0 | 1134 | * Get file status; this version does not follow links. |
5485e062 | 1135 | */ |
9e97623a | 1136 | struct lstat_args { |
7121fdf0 | 1137 | char *path; |
9e97623a CT |
1138 | struct stat *ub; |
1139 | }; | |
6a6a1e5f | 1140 | /* ARGSUSED */ |
ae9b6dc3 | 1141 | lstat(p, uap, retval) |
5e00df3b | 1142 | struct proc *p; |
9e97623a | 1143 | register struct lstat_args *uap; |
6a6a1e5f KM |
1144 | int *retval; |
1145 | { | |
fc2aed1e | 1146 | int error; |
49f762b8 KM |
1147 | struct vnode *vp, *dvp; |
1148 | struct stat sb, sb1; | |
8429d022 | 1149 | struct nameidata nd; |
5485e062 | 1150 | |
49f762b8 | 1151 | NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, |
7121fdf0 | 1152 | uap->path, p); |
dd4c01c2 | 1153 | if (error = namei(&nd)) |
8429d022 | 1154 | return (error); |
49f762b8 KM |
1155 | /* |
1156 | * For symbolic links, always return the attributes of its | |
1157 | * containing directory, except for mode, size, and links. | |
1158 | */ | |
1159 | vp = nd.ni_vp; | |
1160 | dvp = nd.ni_dvp; | |
1161 | if (vp->v_type != VLNK) { | |
1162 | if (dvp == vp) | |
1163 | vrele(dvp); | |
1164 | else | |
1165 | vput(dvp); | |
1166 | error = vn_stat(vp, &sb, p); | |
1167 | vput(vp); | |
1168 | if (error) | |
1169 | return (error); | |
1170 | } else { | |
1171 | error = vn_stat(dvp, &sb, p); | |
1172 | vput(dvp); | |
1173 | if (error) { | |
1174 | vput(vp); | |
1175 | return (error); | |
1176 | } | |
1177 | error = vn_stat(vp, &sb1, p); | |
1178 | vput(vp); | |
1179 | if (error) | |
1180 | return (error); | |
1181 | sb.st_mode &= ~S_IFDIR; | |
1182 | sb.st_mode |= S_IFLNK; | |
1183 | sb.st_nlink = sb1.st_nlink; | |
1184 | sb.st_size = sb1.st_size; | |
1185 | sb.st_blocks = sb1.st_blocks; | |
1186 | } | |
fc2aed1e | 1187 | error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); |
8429d022 | 1188 | return (error); |
d67a03eb BJ |
1189 | } |
1190 | ||
201e5411 | 1191 | /* |
7121fdf0 | 1192 | * Get configurable pathname variables. |
201e5411 KM |
1193 | */ |
1194 | struct pathconf_args { | |
7121fdf0 | 1195 | char *path; |
201e5411 KM |
1196 | int name; |
1197 | }; | |
1198 | /* ARGSUSED */ | |
1199 | pathconf(p, uap, retval) | |
1200 | struct proc *p; | |
1201 | register struct pathconf_args *uap; | |
1202 | int *retval; | |
1203 | { | |
1204 | int error; | |
1205 | struct nameidata nd; | |
1206 | ||
7121fdf0 | 1207 | NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); |
201e5411 KM |
1208 | if (error = namei(&nd)) |
1209 | return (error); | |
1210 | error = VOP_PATHCONF(nd.ni_vp, uap->name, retval); | |
1211 | vput(nd.ni_vp); | |
1212 | return (error); | |
1213 | } | |
1214 | ||
d67a03eb | 1215 | /* |
d4ed1dcd | 1216 | * Return target name of a symbolic link. |
5485e062 | 1217 | */ |
9e97623a | 1218 | struct readlink_args { |
7121fdf0 | 1219 | char *path; |
9e97623a CT |
1220 | char *buf; |
1221 | int count; | |
1222 | }; | |
6a6a1e5f KM |
1223 | /* ARGSUSED */ |
1224 | readlink(p, uap, retval) | |
5e00df3b | 1225 | struct proc *p; |
9e97623a | 1226 | register struct readlink_args *uap; |
6a6a1e5f KM |
1227 | int *retval; |
1228 | { | |
fc2aed1e KM |
1229 | register struct vnode *vp; |
1230 | struct iovec aiov; | |
1231 | struct uio auio; | |
1232 | int error; | |
8429d022 | 1233 | struct nameidata nd; |
5485e062 | 1234 | |
a5368812 | 1235 | CHECKPOINTREF; |
7121fdf0 | 1236 | NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); |
dd4c01c2 | 1237 | if (error = namei(&nd)) |
8429d022 | 1238 | return (error); |
dd4c01c2 | 1239 | vp = nd.ni_vp; |
7121fdf0 | 1240 | if (vp->v_type != VLNK) |
fc2aed1e | 1241 | error = EINVAL; |
7121fdf0 KB |
1242 | else { |
1243 | aiov.iov_base = uap->buf; | |
1244 | aiov.iov_len = uap->count; | |
1245 | auio.uio_iov = &aiov; | |
1246 | auio.uio_iovcnt = 1; | |
1247 | auio.uio_offset = 0; | |
1248 | auio.uio_rw = UIO_READ; | |
1249 | auio.uio_segflg = UIO_USERSPACE; | |
1250 | auio.uio_procp = p; | |
1251 | auio.uio_resid = uap->count; | |
1252 | error = VOP_READLINK(vp, &auio, p->p_ucred); | |
5485e062 | 1253 | } |
fc2aed1e | 1254 | vput(vp); |
6a6a1e5f | 1255 | *retval = uap->count - auio.uio_resid; |
a5368812 | 1256 | CHECKREFS("readlink"); |
8429d022 | 1257 | return (error); |
5485e062 BJ |
1258 | } |
1259 | ||
6995a2cb | 1260 | /* |
7121fdf0 | 1261 | * Change flags of a file given a path name. |
6995a2cb | 1262 | */ |
9e97623a | 1263 | struct chflags_args { |
7121fdf0 | 1264 | char *path; |
9e97623a CT |
1265 | int flags; |
1266 | }; | |
6a6a1e5f KM |
1267 | /* ARGSUSED */ |
1268 | chflags(p, uap, retval) | |
5e00df3b | 1269 | struct proc *p; |
9e97623a | 1270 | register struct chflags_args *uap; |
6a6a1e5f KM |
1271 | int *retval; |
1272 | { | |
6995a2cb KM |
1273 | register struct vnode *vp; |
1274 | struct vattr vattr; | |
1275 | int error; | |
8429d022 | 1276 | struct nameidata nd; |
6995a2cb | 1277 | |
7121fdf0 | 1278 | NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); |
dd4c01c2 | 1279 | if (error = namei(&nd)) |
8429d022 | 1280 | return (error); |
dd4c01c2 | 1281 | vp = nd.ni_vp; |
dbcf7de6 KM |
1282 | LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); |
1283 | VOP_LOCK(vp); | |
7121fdf0 | 1284 | if (vp->v_mount->mnt_flag & MNT_RDONLY) |
6995a2cb | 1285 | error = EROFS; |
7121fdf0 KB |
1286 | else { |
1287 | VATTR_NULL(&vattr); | |
1288 | vattr.va_flags = uap->flags; | |
1289 | error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); | |
6995a2cb | 1290 | } |
6995a2cb | 1291 | vput(vp); |
8429d022 | 1292 | return (error); |
6995a2cb KM |
1293 | } |
1294 | ||
1295 | /* | |
1296 | * Change flags of a file given a file descriptor. | |
1297 | */ | |
9e97623a CT |
1298 | struct fchflags_args { |
1299 | int fd; | |
1300 | int flags; | |
1301 | }; | |
6a6a1e5f KM |
1302 | /* ARGSUSED */ |
1303 | fchflags(p, uap, retval) | |
5e00df3b | 1304 | struct proc *p; |
9e97623a | 1305 | register struct fchflags_args *uap; |
6a6a1e5f KM |
1306 | int *retval; |
1307 | { | |
6995a2cb KM |
1308 | struct vattr vattr; |
1309 | struct vnode *vp; | |
1310 | struct file *fp; | |
1311 | int error; | |
1312 | ||
5e00df3b | 1313 | if (error = getvnode(p->p_fd, uap->fd, &fp)) |
8429d022 | 1314 | return (error); |
6995a2cb | 1315 | vp = (struct vnode *)fp->f_data; |
dbcf7de6 | 1316 | LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); |
6995a2cb | 1317 | VOP_LOCK(vp); |
7121fdf0 | 1318 | if (vp->v_mount->mnt_flag & MNT_RDONLY) |
6995a2cb | 1319 | error = EROFS; |
7121fdf0 KB |
1320 | else { |
1321 | VATTR_NULL(&vattr); | |
1322 | vattr.va_flags = uap->flags; | |
1323 | error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); | |
6995a2cb | 1324 | } |
6995a2cb | 1325 | VOP_UNLOCK(vp); |
8429d022 | 1326 | return (error); |
6995a2cb KM |
1327 | } |
1328 | ||
4f083fd7 SL |
1329 | /* |
1330 | * Change mode of a file given path name. | |
1331 | */ | |
9e97623a | 1332 | struct chmod_args { |
7121fdf0 KB |
1333 | char *path; |
1334 | int mode; | |
9e97623a | 1335 | }; |
6a6a1e5f KM |
1336 | /* ARGSUSED */ |
1337 | chmod(p, uap, retval) | |
5e00df3b | 1338 | struct proc *p; |
9e97623a | 1339 | register struct chmod_args *uap; |
6a6a1e5f KM |
1340 | int *retval; |
1341 | { | |
fc2aed1e KM |
1342 | register struct vnode *vp; |
1343 | struct vattr vattr; | |
1344 | int error; | |
8429d022 | 1345 | struct nameidata nd; |
5485e062 | 1346 | |
7121fdf0 | 1347 | NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); |
dd4c01c2 | 1348 | if (error = namei(&nd)) |
8429d022 | 1349 | return (error); |
dd4c01c2 | 1350 | vp = nd.ni_vp; |
dbcf7de6 KM |
1351 | LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); |
1352 | VOP_LOCK(vp); | |
7121fdf0 | 1353 | if (vp->v_mount->mnt_flag & MNT_RDONLY) |
fc2aed1e | 1354 | error = EROFS; |
7121fdf0 KB |
1355 | else { |
1356 | VATTR_NULL(&vattr); | |
1357 | vattr.va_mode = uap->mode & ALLPERMS; | |
1358 | error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); | |
fc2aed1e | 1359 | } |
fc2aed1e | 1360 | vput(vp); |
8429d022 | 1361 | return (error); |
528f664c | 1362 | } |
f94ceb3b | 1363 | |
4f083fd7 SL |
1364 | /* |
1365 | * Change mode of a file given a file descriptor. | |
1366 | */ | |
9e97623a CT |
1367 | struct fchmod_args { |
1368 | int fd; | |
7121fdf0 | 1369 | int mode; |
9e97623a | 1370 | }; |
6a6a1e5f KM |
1371 | /* ARGSUSED */ |
1372 | fchmod(p, uap, retval) | |
5e00df3b | 1373 | struct proc *p; |
9e97623a | 1374 | register struct fchmod_args *uap; |
6a6a1e5f KM |
1375 | int *retval; |
1376 | { | |
fc2aed1e KM |
1377 | struct vattr vattr; |
1378 | struct vnode *vp; | |
1379 | struct file *fp; | |
1380 | int error; | |
1381 | ||
5e00df3b | 1382 | if (error = getvnode(p->p_fd, uap->fd, &fp)) |
8429d022 | 1383 | return (error); |
fc2aed1e | 1384 | vp = (struct vnode *)fp->f_data; |
dbcf7de6 | 1385 | LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); |
fc2aed1e | 1386 | VOP_LOCK(vp); |
7121fdf0 | 1387 | if (vp->v_mount->mnt_flag & MNT_RDONLY) |
fc2aed1e | 1388 | error = EROFS; |
7121fdf0 KB |
1389 | else { |
1390 | VATTR_NULL(&vattr); | |
1391 | vattr.va_mode = uap->mode & ALLPERMS; | |
1392 | error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); | |
f94ceb3b | 1393 | } |
fc2aed1e | 1394 | VOP_UNLOCK(vp); |
8429d022 | 1395 | return (error); |
5485e062 BJ |
1396 | } |
1397 | ||
4f083fd7 SL |
1398 | /* |
1399 | * Set ownership given a path name. | |
1400 | */ | |
9e97623a | 1401 | struct chown_args { |
7121fdf0 | 1402 | char *path; |
9e97623a CT |
1403 | int uid; |
1404 | int gid; | |
1405 | }; | |
6a6a1e5f KM |
1406 | /* ARGSUSED */ |
1407 | chown(p, uap, retval) | |
5e00df3b | 1408 | struct proc *p; |
9e97623a | 1409 | register struct chown_args *uap; |
6a6a1e5f KM |
1410 | int *retval; |
1411 | { | |
fc2aed1e KM |
1412 | register struct vnode *vp; |
1413 | struct vattr vattr; | |
1414 | int error; | |
8429d022 | 1415 | struct nameidata nd; |
d67a03eb | 1416 | |
7121fdf0 | 1417 | NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, p); |
dd4c01c2 | 1418 | if (error = namei(&nd)) |
8429d022 | 1419 | return (error); |
dd4c01c2 | 1420 | vp = nd.ni_vp; |
dbcf7de6 KM |
1421 | LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); |
1422 | VOP_LOCK(vp); | |
7121fdf0 | 1423 | if (vp->v_mount->mnt_flag & MNT_RDONLY) |
fc2aed1e | 1424 | error = EROFS; |
7121fdf0 KB |
1425 | else { |
1426 | VATTR_NULL(&vattr); | |
1427 | vattr.va_uid = uap->uid; | |
1428 | vattr.va_gid = uap->gid; | |
1429 | error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); | |
fc2aed1e | 1430 | } |
fc2aed1e | 1431 | vput(vp); |
8429d022 | 1432 | return (error); |
528f664c | 1433 | } |
f94ceb3b | 1434 | |
4f083fd7 SL |
1435 | /* |
1436 | * Set ownership given a file descriptor. | |
1437 | */ | |
9e97623a CT |
1438 | struct fchown_args { |
1439 | int fd; | |
1440 | int uid; | |
1441 | int gid; | |
1442 | }; | |
6a6a1e5f KM |
1443 | /* ARGSUSED */ |
1444 | fchown(p, uap, retval) | |
5e00df3b | 1445 | struct proc *p; |
9e97623a | 1446 | register struct fchown_args *uap; |
6a6a1e5f KM |
1447 | int *retval; |
1448 | { | |
fc2aed1e KM |
1449 | struct vattr vattr; |
1450 | struct vnode *vp; | |
1451 | struct file *fp; | |
1452 | int error; | |
1453 | ||
5e00df3b | 1454 | if (error = getvnode(p->p_fd, uap->fd, &fp)) |
8429d022 | 1455 | return (error); |
fc2aed1e | 1456 | vp = (struct vnode *)fp->f_data; |
dbcf7de6 | 1457 | LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); |
fc2aed1e | 1458 | VOP_LOCK(vp); |
7121fdf0 | 1459 | if (vp->v_mount->mnt_flag & MNT_RDONLY) |
fc2aed1e | 1460 | error = EROFS; |
7121fdf0 KB |
1461 | else { |
1462 | VATTR_NULL(&vattr); | |
1463 | vattr.va_uid = uap->uid; | |
1464 | vattr.va_gid = uap->gid; | |
1465 | error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); | |
fc2aed1e | 1466 | } |
fc2aed1e | 1467 | VOP_UNLOCK(vp); |
8429d022 | 1468 | return (error); |
d67a03eb BJ |
1469 | } |
1470 | ||
6a6a1e5f KM |
1471 | /* |
1472 | * Set the access and modification times of a file. | |
1473 | */ | |
9e97623a | 1474 | struct utimes_args { |
7121fdf0 | 1475 | char *path; |
9e97623a CT |
1476 | struct timeval *tptr; |
1477 | }; | |
6a6a1e5f KM |
1478 | /* ARGSUSED */ |
1479 | utimes(p, uap, retval) | |
5e00df3b | 1480 | struct proc *p; |
9e97623a | 1481 | register struct utimes_args *uap; |
6a6a1e5f KM |
1482 | int *retval; |
1483 | { | |
fc2aed1e | 1484 | register struct vnode *vp; |
bb1b75f4 | 1485 | struct timeval tv[2]; |
fc2aed1e | 1486 | struct vattr vattr; |
8e88b0cd | 1487 | int error; |
8429d022 | 1488 | struct nameidata nd; |
bb1b75f4 | 1489 | |
f8ee9a49 KB |
1490 | VATTR_NULL(&vattr); |
1491 | if (uap->tptr == NULL) { | |
1492 | microtime(&tv[0]); | |
1493 | tv[1] = tv[0]; | |
fcba749b | 1494 | vattr.va_vaflags |= VA_UTIMES_NULL; |
f8ee9a49 KB |
1495 | } else if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) |
1496 | return (error); | |
7121fdf0 | 1497 | NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); |
dd4c01c2 | 1498 | if (error = namei(&nd)) |
8429d022 | 1499 | return (error); |
dd4c01c2 | 1500 | vp = nd.ni_vp; |
dbcf7de6 KM |
1501 | LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); |
1502 | VOP_LOCK(vp); | |
7121fdf0 | 1503 | if (vp->v_mount->mnt_flag & MNT_RDONLY) |
fc2aed1e | 1504 | error = EROFS; |
7121fdf0 KB |
1505 | else { |
1506 | vattr.va_atime.ts_sec = tv[0].tv_sec; | |
1507 | vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000; | |
1508 | vattr.va_mtime.ts_sec = tv[1].tv_sec; | |
1509 | vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000; | |
1510 | error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); | |
bb1b75f4 | 1511 | } |
fc2aed1e | 1512 | vput(vp); |
8429d022 | 1513 | return (error); |
d67a03eb | 1514 | } |
64d3a787 | 1515 | |
7121fdf0 KB |
1516 | /* |
1517 | * Truncate a file given its path name. | |
1518 | */ | |
95c0eb1e | 1519 | struct truncate_args { |
7121fdf0 | 1520 | char *path; |
2f2b3b3d CT |
1521 | int pad; |
1522 | off_t length; | |
1523 | }; | |
be320a2b | 1524 | /* ARGSUSED */ |
201e5411 | 1525 | truncate(p, uap, retval) |
5e00df3b | 1526 | struct proc *p; |
95c0eb1e | 1527 | register struct truncate_args *uap; |
6a6a1e5f KM |
1528 | int *retval; |
1529 | { | |
fc2aed1e KM |
1530 | register struct vnode *vp; |
1531 | struct vattr vattr; | |
1532 | int error; | |
8429d022 | 1533 | struct nameidata nd; |
528f664c | 1534 | |
7121fdf0 | 1535 | NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); |
dd4c01c2 | 1536 | if (error = namei(&nd)) |
8429d022 | 1537 | return (error); |
dd4c01c2 | 1538 | vp = nd.ni_vp; |
dbcf7de6 KM |
1539 | LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); |
1540 | VOP_LOCK(vp); | |
7121fdf0 | 1541 | if (vp->v_type == VDIR) |
fc2aed1e | 1542 | error = EISDIR; |
7121fdf0 KB |
1543 | else if ((error = vn_writechk(vp)) == 0 && |
1544 | (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) { | |
1545 | VATTR_NULL(&vattr); | |
1546 | vattr.va_size = uap->length; | |
1547 | error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); | |
528f664c | 1548 | } |
fc2aed1e | 1549 | vput(vp); |
8429d022 | 1550 | return (error); |
528f664c SL |
1551 | } |
1552 | ||
7121fdf0 KB |
1553 | /* |
1554 | * Truncate a file given a file descriptor. | |
1555 | */ | |
95c0eb1e | 1556 | struct ftruncate_args { |
2f2b3b3d CT |
1557 | int fd; |
1558 | int pad; | |
1559 | off_t length; | |
1560 | }; | |
6a6a1e5f | 1561 | /* ARGSUSED */ |
201e5411 | 1562 | ftruncate(p, uap, retval) |
5e00df3b | 1563 | struct proc *p; |
95c0eb1e | 1564 | register struct ftruncate_args *uap; |
6a6a1e5f KM |
1565 | int *retval; |
1566 | { | |
fc2aed1e KM |
1567 | struct vattr vattr; |
1568 | struct vnode *vp; | |
528f664c | 1569 | struct file *fp; |
fc2aed1e KM |
1570 | int error; |
1571 | ||
5e00df3b | 1572 | if (error = getvnode(p->p_fd, uap->fd, &fp)) |
8429d022 | 1573 | return (error); |
fc2aed1e | 1574 | if ((fp->f_flag & FWRITE) == 0) |
8429d022 | 1575 | return (EINVAL); |
fc2aed1e | 1576 | vp = (struct vnode *)fp->f_data; |
dbcf7de6 | 1577 | LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); |
fc2aed1e | 1578 | VOP_LOCK(vp); |
7121fdf0 | 1579 | if (vp->v_type == VDIR) |
fc2aed1e | 1580 | error = EISDIR; |
7121fdf0 KB |
1581 | else if ((error = vn_writechk(vp)) == 0) { |
1582 | VATTR_NULL(&vattr); | |
1583 | vattr.va_size = uap->length; | |
1584 | error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); | |
528f664c | 1585 | } |
fc2aed1e | 1586 | VOP_UNLOCK(vp); |
8429d022 | 1587 | return (error); |
4f083fd7 SL |
1588 | } |
1589 | ||
2f2b3b3d CT |
1590 | #if defined(COMPAT_43) || defined(COMPAT_SUNOS) |
1591 | /* | |
1592 | * Truncate a file given its path name. | |
1593 | */ | |
95c0eb1e | 1594 | struct otruncate_args { |
7121fdf0 | 1595 | char *path; |
9e97623a CT |
1596 | long length; |
1597 | }; | |
2f2b3b3d | 1598 | /* ARGSUSED */ |
51a9a1cf | 1599 | otruncate(p, uap, retval) |
2f2b3b3d | 1600 | struct proc *p; |
95c0eb1e | 1601 | register struct otruncate_args *uap; |
2f2b3b3d CT |
1602 | int *retval; |
1603 | { | |
95c0eb1e | 1604 | struct truncate_args nuap; |
2f2b3b3d | 1605 | |
7121fdf0 | 1606 | nuap.path = uap->path; |
2f2b3b3d | 1607 | nuap.length = uap->length; |
95c0eb1e | 1608 | return (truncate(p, &nuap, retval)); |
2f2b3b3d CT |
1609 | } |
1610 | ||
1611 | /* | |
1612 | * Truncate a file given a file descriptor. | |
1613 | */ | |
95c0eb1e | 1614 | struct oftruncate_args { |
9e97623a CT |
1615 | int fd; |
1616 | long length; | |
1617 | }; | |
2f2b3b3d | 1618 | /* ARGSUSED */ |
51a9a1cf | 1619 | oftruncate(p, uap, retval) |
2f2b3b3d | 1620 | struct proc *p; |
95c0eb1e | 1621 | register struct oftruncate_args *uap; |
2f2b3b3d CT |
1622 | int *retval; |
1623 | { | |
95c0eb1e | 1624 | struct ftruncate_args nuap; |
2f2b3b3d CT |
1625 | |
1626 | nuap.fd = uap->fd; | |
1627 | nuap.length = uap->length; | |
95c0eb1e | 1628 | return (ftruncate(p, &nuap, retval)); |
2f2b3b3d CT |
1629 | } |
1630 | #endif /* COMPAT_43 || COMPAT_SUNOS */ | |
1631 | ||
4f083fd7 | 1632 | /* |
7121fdf0 | 1633 | * Sync an open file. |
4f083fd7 | 1634 | */ |
9e97623a CT |
1635 | struct fsync_args { |
1636 | int fd; | |
1637 | }; | |
6a6a1e5f KM |
1638 | /* ARGSUSED */ |
1639 | fsync(p, uap, retval) | |
5e00df3b | 1640 | struct proc *p; |
9e97623a | 1641 | struct fsync_args *uap; |
6a6a1e5f KM |
1642 | int *retval; |
1643 | { | |
e79467ea | 1644 | register struct vnode *vp; |
4f083fd7 | 1645 | struct file *fp; |
fc2aed1e | 1646 | int error; |
4f083fd7 | 1647 | |
5e00df3b | 1648 | if (error = getvnode(p->p_fd, uap->fd, &fp)) |
8429d022 | 1649 | return (error); |
e79467ea KM |
1650 | vp = (struct vnode *)fp->f_data; |
1651 | VOP_LOCK(vp); | |
09d2ef1a | 1652 | error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p); |
e79467ea | 1653 | VOP_UNLOCK(vp); |
8429d022 | 1654 | return (error); |
528f664c SL |
1655 | } |
1656 | ||
4f083fd7 | 1657 | /* |
7121fdf0 KB |
1658 | * Rename files. Source and destination must either both be directories, |
1659 | * or both not be directories. If target is a directory, it must be empty. | |
4f083fd7 | 1660 | */ |
9e97623a CT |
1661 | struct rename_args { |
1662 | char *from; | |
1663 | char *to; | |
1664 | }; | |
6a6a1e5f KM |
1665 | /* ARGSUSED */ |
1666 | rename(p, uap, retval) | |
5e00df3b | 1667 | struct proc *p; |
9e97623a | 1668 | register struct rename_args *uap; |
6a6a1e5f KM |
1669 | int *retval; |
1670 | { | |
fc2aed1e | 1671 | register struct vnode *tvp, *fvp, *tdvp; |
5718fad3 | 1672 | struct nameidata fromnd, tond; |
fc2aed1e | 1673 | int error; |
4f083fd7 | 1674 | |
a5368812 | 1675 | CHECKPOINTREF; |
dd4c01c2 KM |
1676 | NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, |
1677 | uap->from, p); | |
1678 | if (error = namei(&fromnd)) | |
8429d022 | 1679 | return (error); |
5718fad3 | 1680 | fvp = fromnd.ni_vp; |
dd4c01c2 KM |
1681 | NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, |
1682 | UIO_USERSPACE, uap->to, p); | |
1683 | if (error = namei(&tond)) { | |
cfef4373 | 1684 | VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); |
5718fad3 | 1685 | vrele(fromnd.ni_dvp); |
66955caf KM |
1686 | vrele(fvp); |
1687 | goto out1; | |
1688 | } | |
fc2aed1e KM |
1689 | tdvp = tond.ni_dvp; |
1690 | tvp = tond.ni_vp; | |
1691 | if (tvp != NULL) { | |
1692 | if (fvp->v_type == VDIR && tvp->v_type != VDIR) { | |
9259ee95 | 1693 | error = ENOTDIR; |
fc2aed1e KM |
1694 | goto out; |
1695 | } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { | |
9259ee95 | 1696 | error = EISDIR; |
fc2aed1e | 1697 | goto out; |
a5390dce | 1698 | } |
64d3a787 | 1699 | } |
fe562f32 | 1700 | if (fvp == tdvp) |
fc2aed1e | 1701 | error = EINVAL; |
fe562f32 | 1702 | /* |
5718fad3 KM |
1703 | * If source is the same as the destination (that is the |
1704 | * same inode number with the same name in the same directory), | |
fe562f32 KM |
1705 | * then there is nothing to do. |
1706 | */ | |
5718fad3 | 1707 | if (fvp == tvp && fromnd.ni_dvp == tdvp && |
dd4c01c2 KM |
1708 | fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && |
1709 | !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, | |
1710 | fromnd.ni_cnd.cn_namelen)) | |
fe562f32 | 1711 | error = -1; |
fc2aed1e | 1712 | out: |
66955caf | 1713 | if (!error) { |
e62d4143 KM |
1714 | LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE); |
1715 | if (fromnd.ni_dvp != tdvp) | |
1716 | LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); | |
1717 | if (tvp) | |
1718 | LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE); | |
cfef4373 JH |
1719 | error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, |
1720 | tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); | |
66955caf | 1721 | } else { |
cfef4373 | 1722 | VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); |
6c44e83b KM |
1723 | if (tdvp == tvp) |
1724 | vrele(tdvp); | |
1725 | else | |
1726 | vput(tdvp); | |
66955caf KM |
1727 | if (tvp) |
1728 | vput(tvp); | |
cfef4373 | 1729 | VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); |
5718fad3 | 1730 | vrele(fromnd.ni_dvp); |
66955caf | 1731 | vrele(fvp); |
64d3a787 | 1732 | } |
c03959f9 | 1733 | p->p_spare[1]--; |
5718fad3 | 1734 | vrele(tond.ni_startdir); |
dd4c01c2 | 1735 | FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); |
fc2aed1e | 1736 | out1: |
c03959f9 | 1737 | p->p_spare[1]--; |
5718fad3 | 1738 | vrele(fromnd.ni_startdir); |
dd4c01c2 | 1739 | FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); |
a5368812 | 1740 | CHECKREFS("rename"); |
fe562f32 | 1741 | if (error == -1) |
8429d022 MK |
1742 | return (0); |
1743 | return (error); | |
64d3a787 | 1744 | } |
88a7a62a | 1745 | |
88a7a62a | 1746 | /* |
7121fdf0 | 1747 | * Make a directory file. |
88a7a62a | 1748 | */ |
9e97623a | 1749 | struct mkdir_args { |
7121fdf0 KB |
1750 | char *path; |
1751 | int mode; | |
9e97623a | 1752 | }; |
6a6a1e5f KM |
1753 | /* ARGSUSED */ |
1754 | mkdir(p, uap, retval) | |
5e00df3b | 1755 | struct proc *p; |
9e97623a | 1756 | register struct mkdir_args *uap; |
6a6a1e5f KM |
1757 | int *retval; |
1758 | { | |
fc2aed1e KM |
1759 | register struct vnode *vp; |
1760 | struct vattr vattr; | |
1761 | int error; | |
8429d022 | 1762 | struct nameidata nd; |
88a7a62a | 1763 | |
a5368812 | 1764 | CHECKPOINTREF; |
7121fdf0 | 1765 | NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); |
dd4c01c2 | 1766 | if (error = namei(&nd)) |
8429d022 | 1767 | return (error); |
dd4c01c2 | 1768 | vp = nd.ni_vp; |
fc2aed1e | 1769 | if (vp != NULL) { |
dd4c01c2 KM |
1770 | VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); |
1771 | if (nd.ni_dvp == vp) | |
1772 | vrele(nd.ni_dvp); | |
6c44e83b | 1773 | else |
dd4c01c2 | 1774 | vput(nd.ni_dvp); |
66955caf | 1775 | vrele(vp); |
a5368812 | 1776 | CHECKREFS("mkdir1"); |
8429d022 | 1777 | return (EEXIST); |
88a7a62a | 1778 | } |
3ee1461b | 1779 | VATTR_NULL(&vattr); |
fc2aed1e | 1780 | vattr.va_type = VDIR; |
7121fdf0 | 1781 | vattr.va_mode = (uap->mode & ACCESSPERMS) &~ p->p_fd->fd_cmask; |
dd4c01c2 KM |
1782 | LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); |
1783 | error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); | |
5dfd04f0 | 1784 | if (!error) |
dd4c01c2 | 1785 | vput(nd.ni_vp); |
a5368812 | 1786 | CHECKREFS("mkdir2"); |
8429d022 | 1787 | return (error); |
88a7a62a SL |
1788 | } |
1789 | ||
1790 | /* | |
7121fdf0 | 1791 | * Remove a directory file. |
88a7a62a | 1792 | */ |
9e97623a | 1793 | struct rmdir_args { |
7121fdf0 | 1794 | char *path; |
9e97623a | 1795 | }; |
6a6a1e5f KM |
1796 | /* ARGSUSED */ |
1797 | rmdir(p, uap, retval) | |
5e00df3b | 1798 | struct proc *p; |
9e97623a | 1799 | struct rmdir_args *uap; |
6a6a1e5f KM |
1800 | int *retval; |
1801 | { | |
fc2aed1e KM |
1802 | register struct vnode *vp; |
1803 | int error; | |
8429d022 | 1804 | struct nameidata nd; |
88a7a62a | 1805 | |
a5368812 | 1806 | CHECKPOINTREF; |
7121fdf0 | 1807 | NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->path, p); |
dd4c01c2 | 1808 | if (error = namei(&nd)) |
8429d022 | 1809 | return (error); |
dd4c01c2 | 1810 | vp = nd.ni_vp; |
fc2aed1e KM |
1811 | if (vp->v_type != VDIR) { |
1812 | error = ENOTDIR; | |
88a7a62a SL |
1813 | goto out; |
1814 | } | |
1815 | /* | |
fc2aed1e | 1816 | * No rmdir "." please. |
88a7a62a | 1817 | */ |
dd4c01c2 | 1818 | if (nd.ni_dvp == vp) { |
fc2aed1e | 1819 | error = EINVAL; |
88a7a62a SL |
1820 | goto out; |
1821 | } | |
1822 | /* | |
d4ed1dcd | 1823 | * The root of a mounted filesystem cannot be deleted. |
88a7a62a | 1824 | */ |
fc2aed1e KM |
1825 | if (vp->v_flag & VROOT) |
1826 | error = EBUSY; | |
88a7a62a | 1827 | out: |
66955caf | 1828 | if (!error) { |
dd4c01c2 | 1829 | LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); |
e62d4143 | 1830 | LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); |
dd4c01c2 | 1831 | error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); |
66955caf | 1832 | } else { |
dd4c01c2 KM |
1833 | VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); |
1834 | if (nd.ni_dvp == vp) | |
1835 | vrele(nd.ni_dvp); | |
6c44e83b | 1836 | else |
dd4c01c2 | 1837 | vput(nd.ni_dvp); |
66955caf KM |
1838 | vput(vp); |
1839 | } | |
a5368812 | 1840 | CHECKREFS("rmdir"); |
8429d022 | 1841 | return (error); |
88a7a62a SL |
1842 | } |
1843 | ||
3d92fa10 KM |
1844 | #ifdef COMPAT_43 |
1845 | /* | |
1846 | * Read a block of directory entries in a file system independent format. | |
1847 | */ | |
9e97623a CT |
1848 | struct ogetdirentries_args { |
1849 | int fd; | |
1850 | char *buf; | |
7121fdf0 | 1851 | u_int count; |
9e97623a CT |
1852 | long *basep; |
1853 | }; | |
3d92fa10 KM |
1854 | ogetdirentries(p, uap, retval) |
1855 | struct proc *p; | |
9e97623a | 1856 | register struct ogetdirentries_args *uap; |
3d92fa10 KM |
1857 | int *retval; |
1858 | { | |
3d92fa10 KM |
1859 | register struct vnode *vp; |
1860 | struct file *fp; | |
1861 | struct uio auio, kuio; | |
1862 | struct iovec aiov, kiov; | |
1863 | struct dirent *dp, *edp; | |
1864 | caddr_t dirbuf; | |
1865 | int error, readcnt; | |
d80c3f56 | 1866 | long loff; |
3d92fa10 KM |
1867 | |
1868 | if (error = getvnode(p->p_fd, uap->fd, &fp)) | |
1869 | return (error); | |
1870 | if ((fp->f_flag & FREAD) == 0) | |
1871 | return (EBADF); | |
1872 | vp = (struct vnode *)fp->f_data; | |
1873 | if (vp->v_type != VDIR) | |
1874 | return (EINVAL); | |
1875 | aiov.iov_base = uap->buf; | |
1876 | aiov.iov_len = uap->count; | |
1877 | auio.uio_iov = &aiov; | |
1878 | auio.uio_iovcnt = 1; | |
1879 | auio.uio_rw = UIO_READ; | |
1880 | auio.uio_segflg = UIO_USERSPACE; | |
1881 | auio.uio_procp = p; | |
1882 | auio.uio_resid = uap->count; | |
1883 | VOP_LOCK(vp); | |
d80c3f56 | 1884 | loff = auio.uio_offset = fp->f_offset; |
3d92fa10 | 1885 | # if (BYTE_ORDER != LITTLE_ENDIAN) |
a801b5ab | 1886 | if (vp->v_mount->mnt_maxsymlinklen <= 0) { |
3d92fa10 | 1887 | error = VOP_READDIR(vp, &auio, fp->f_cred); |
a801b5ab KM |
1888 | fp->f_offset = auio.uio_offset; |
1889 | } else | |
3d92fa10 KM |
1890 | # endif |
1891 | { | |
1892 | kuio = auio; | |
1893 | kuio.uio_iov = &kiov; | |
1894 | kuio.uio_segflg = UIO_SYSSPACE; | |
1895 | kiov.iov_len = uap->count; | |
1896 | MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK); | |
1897 | kiov.iov_base = dirbuf; | |
1898 | error = VOP_READDIR(vp, &kuio, fp->f_cred); | |
a801b5ab | 1899 | fp->f_offset = kuio.uio_offset; |
3d92fa10 KM |
1900 | if (error == 0) { |
1901 | readcnt = uap->count - kuio.uio_resid; | |
1902 | edp = (struct dirent *)&dirbuf[readcnt]; | |
1903 | for (dp = (struct dirent *)dirbuf; dp < edp; ) { | |
3d92fa10 | 1904 | # if (BYTE_ORDER == LITTLE_ENDIAN) |
d80c3f56 | 1905 | /* |
30445fe6 KM |
1906 | * The expected low byte of |
1907 | * dp->d_namlen is our dp->d_type. | |
1908 | * The high MBZ byte of dp->d_namlen | |
1909 | * is our dp->d_namlen. | |
d80c3f56 | 1910 | */ |
30445fe6 KM |
1911 | dp->d_type = dp->d_namlen; |
1912 | dp->d_namlen = 0; | |
1913 | # else | |
1914 | /* | |
1915 | * The dp->d_type is the high byte | |
1916 | * of the expected dp->d_namlen, | |
1917 | * so must be zero'ed. | |
1918 | */ | |
1919 | dp->d_type = 0; | |
3d92fa10 KM |
1920 | # endif |
1921 | if (dp->d_reclen > 0) { | |
1922 | dp = (struct dirent *) | |
1923 | ((char *)dp + dp->d_reclen); | |
1924 | } else { | |
1925 | error = EIO; | |
1926 | break; | |
1927 | } | |
1928 | } | |
1929 | if (dp >= edp) | |
1930 | error = uiomove(dirbuf, readcnt, &auio); | |
1931 | } | |
1932 | FREE(dirbuf, M_TEMP); | |
1933 | } | |
3d92fa10 KM |
1934 | VOP_UNLOCK(vp); |
1935 | if (error) | |
1936 | return (error); | |
d80c3f56 | 1937 | error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); |
3d92fa10 KM |
1938 | *retval = uap->count - auio.uio_resid; |
1939 | return (error); | |
1940 | } | |
1941 | #endif | |
1942 | ||
fc2aed1e | 1943 | /* |
d4ed1dcd | 1944 | * Read a block of directory entries in a file system independent format. |
fc2aed1e | 1945 | */ |
9e97623a CT |
1946 | struct getdirentries_args { |
1947 | int fd; | |
1948 | char *buf; | |
7121fdf0 | 1949 | u_int count; |
9e97623a CT |
1950 | long *basep; |
1951 | }; | |
6a6a1e5f | 1952 | getdirentries(p, uap, retval) |
5e00df3b | 1953 | struct proc *p; |
9e97623a | 1954 | register struct getdirentries_args *uap; |
6a6a1e5f KM |
1955 | int *retval; |
1956 | { | |
e79467ea | 1957 | register struct vnode *vp; |
8462a185 | 1958 | struct file *fp; |
fc2aed1e KM |
1959 | struct uio auio; |
1960 | struct iovec aiov; | |
d80c3f56 | 1961 | long loff; |
09d2ef1a | 1962 | int error; |
fc2aed1e | 1963 | |
5e00df3b | 1964 | if (error = getvnode(p->p_fd, uap->fd, &fp)) |
8429d022 | 1965 | return (error); |
fc2aed1e | 1966 | if ((fp->f_flag & FREAD) == 0) |
8429d022 | 1967 | return (EBADF); |
e79467ea | 1968 | vp = (struct vnode *)fp->f_data; |
95a9cadb | 1969 | unionread: |
e79467ea | 1970 | if (vp->v_type != VDIR) |
8429d022 | 1971 | return (EINVAL); |
fc2aed1e KM |
1972 | aiov.iov_base = uap->buf; |
1973 | aiov.iov_len = uap->count; | |
1974 | auio.uio_iov = &aiov; | |
1975 | auio.uio_iovcnt = 1; | |
1976 | auio.uio_rw = UIO_READ; | |
1977 | auio.uio_segflg = UIO_USERSPACE; | |
2c69fe14 | 1978 | auio.uio_procp = p; |
fc2aed1e | 1979 | auio.uio_resid = uap->count; |
e79467ea | 1980 | VOP_LOCK(vp); |
d80c3f56 | 1981 | loff = auio.uio_offset = fp->f_offset; |
09d2ef1a | 1982 | error = VOP_READDIR(vp, &auio, fp->f_cred); |
e79467ea KM |
1983 | fp->f_offset = auio.uio_offset; |
1984 | VOP_UNLOCK(vp); | |
1985 | if (error) | |
8429d022 | 1986 | return (error); |
57b06c10 JSP |
1987 | |
1988 | #ifdef UNION | |
1989 | { | |
1990 | extern int (**union_vnodeop_p)(); | |
1991 | extern struct vnode *union_lowervp __P((struct vnode *)); | |
1992 | ||
1993 | if ((uap->count == auio.uio_resid) && | |
1994 | (vp->v_op == union_vnodeop_p)) { | |
1995 | struct vnode *tvp = vp; | |
1996 | ||
1997 | vp = union_lowervp(vp); | |
1998 | if (vp != NULLVP) { | |
1999 | VOP_LOCK(vp); | |
2000 | error = VOP_OPEN(vp, FREAD); | |
2001 | VOP_UNLOCK(vp); | |
2002 | ||
2003 | if (error) { | |
2004 | vrele(vp); | |
2005 | return (error); | |
2006 | } | |
2007 | fp->f_data = (caddr_t) vp; | |
2008 | fp->f_offset = 0; | |
2009 | error = vn_close(tvp, FREAD, fp->f_cred, p); | |
2010 | if (error) | |
2011 | return (error); | |
2012 | goto unionread; | |
2013 | } | |
2014 | } | |
2015 | } | |
2016 | #endif | |
2017 | ||
95a9cadb JSP |
2018 | if ((uap->count == auio.uio_resid) && |
2019 | (vp->v_flag & VROOT) && | |
2020 | (vp->v_mount->mnt_flag & MNT_UNION)) { | |
2021 | struct vnode *tvp = vp; | |
2022 | vp = vp->v_mount->mnt_vnodecovered; | |
2023 | VREF(vp); | |
2024 | fp->f_data = (caddr_t) vp; | |
2025 | fp->f_offset = 0; | |
2026 | vrele(tvp); | |
2027 | goto unionread; | |
2028 | } | |
d80c3f56 | 2029 | error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); |
6a6a1e5f | 2030 | *retval = uap->count - auio.uio_resid; |
8429d022 | 2031 | return (error); |
88a7a62a SL |
2032 | } |
2033 | ||
2034 | /* | |
d4ed1dcd | 2035 | * Set the mode mask for creation of filesystem nodes. |
88a7a62a | 2036 | */ |
9e97623a | 2037 | struct umask_args { |
7121fdf0 | 2038 | int newmask; |
9e97623a CT |
2039 | }; |
2040 | mode_t /* XXX */ | |
6a6a1e5f | 2041 | umask(p, uap, retval) |
5e00df3b | 2042 | struct proc *p; |
9e97623a | 2043 | struct umask_args *uap; |
6a6a1e5f KM |
2044 | int *retval; |
2045 | { | |
7121fdf0 | 2046 | register struct filedesc *fdp; |
88a7a62a | 2047 | |
7121fdf0 | 2048 | fdp = p->p_fd; |
5e00df3b | 2049 | *retval = fdp->fd_cmask; |
7121fdf0 | 2050 | fdp->fd_cmask = uap->newmask & ALLPERMS; |
8429d022 | 2051 | return (0); |
fc2aed1e KM |
2052 | } |
2053 | ||
b0a98f13 MT |
2054 | /* |
2055 | * Void all references to file by ripping underlying filesystem | |
2056 | * away from vnode. | |
2057 | */ | |
9e97623a | 2058 | struct revoke_args { |
7121fdf0 | 2059 | char *path; |
9e97623a | 2060 | }; |
6a6a1e5f KM |
2061 | /* ARGSUSED */ |
2062 | revoke(p, uap, retval) | |
5e00df3b | 2063 | struct proc *p; |
9e97623a | 2064 | register struct revoke_args *uap; |
6a6a1e5f KM |
2065 | int *retval; |
2066 | { | |
b0a98f13 MT |
2067 | register struct vnode *vp; |
2068 | struct vattr vattr; | |
2069 | int error; | |
8429d022 | 2070 | struct nameidata nd; |
b0a98f13 | 2071 | |
7121fdf0 | 2072 | NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); |
dd4c01c2 | 2073 | if (error = namei(&nd)) |
8429d022 | 2074 | return (error); |
dd4c01c2 | 2075 | vp = nd.ni_vp; |
b0a98f13 MT |
2076 | if (vp->v_type != VCHR && vp->v_type != VBLK) { |
2077 | error = EINVAL; | |
2078 | goto out; | |
2079 | } | |
2c69fe14 | 2080 | if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) |
b0a98f13 | 2081 | goto out; |
8429d022 MK |
2082 | if (p->p_ucred->cr_uid != vattr.va_uid && |
2083 | (error = suser(p->p_ucred, &p->p_acflag))) | |
b0a98f13 | 2084 | goto out; |
8b81d198 | 2085 | if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) |
c9345cca | 2086 | vgoneall(vp); |
b0a98f13 MT |
2087 | out: |
2088 | vrele(vp); | |
8429d022 | 2089 | return (error); |
b0a98f13 MT |
2090 | } |
2091 | ||
d4ed1dcd KM |
2092 | /* |
2093 | * Convert a user file descriptor to a kernel file entry. | |
2094 | */ | |
7121fdf0 | 2095 | getvnode(fdp, fd, fpp) |
5e00df3b | 2096 | struct filedesc *fdp; |
fc2aed1e | 2097 | struct file **fpp; |
7121fdf0 | 2098 | int fd; |
fc2aed1e KM |
2099 | { |
2100 | struct file *fp; | |
2101 | ||
7121fdf0 KB |
2102 | if ((u_int)fd >= fdp->fd_nfiles || |
2103 | (fp = fdp->fd_ofiles[fd]) == NULL) | |
fc2aed1e KM |
2104 | return (EBADF); |
2105 | if (fp->f_type != DTYPE_VNODE) | |
2106 | return (EINVAL); | |
2107 | *fpp = fp; | |
2108 | return (0); | |
88a7a62a | 2109 | } |