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