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