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