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