vfs_syscalls_43.c revision 1.15.2.5 1 /* $NetBSD: vfs_syscalls_43.c,v 1.15.2.5 2002/05/29 21:32:17 nathanw Exp $ */
2
3 /*
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
6 * (c) UNIX System Laboratories, Inc.
7 * All or some portions of this file are derived from material licensed
8 * to the University of California by American Telephone and Telegraph
9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10 * the permission of UNIX System Laboratories, Inc.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the University of
23 * California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 * @(#)vfs_syscalls.c 8.28 (Berkeley) 12/10/94
41 */
42
43 #include <sys/cdefs.h>
44 __KERNEL_RCSID(0, "$NetBSD: vfs_syscalls_43.c,v 1.15.2.5 2002/05/29 21:32:17 nathanw Exp $");
45
46 #if defined(_KERNEL_OPT)
47 #include "fs_union.h"
48 #endif
49
50 #include <sys/param.h>
51 #include <sys/systm.h>
52 #include <sys/filedesc.h>
53 #include <sys/kernel.h>
54 #include <sys/lwp.h>
55 #include <sys/proc.h>
56 #include <sys/file.h>
57 #include <sys/vnode.h>
58 #include <sys/namei.h>
59 #include <sys/dirent.h>
60 #include <sys/socket.h>
61 #include <sys/socketvar.h>
62 #include <sys/stat.h>
63 #include <sys/ioctl.h>
64 #include <sys/fcntl.h>
65 #include <sys/malloc.h>
66 #include <sys/syslog.h>
67 #include <sys/unistd.h>
68 #include <sys/resourcevar.h>
69
70 #include <sys/mount.h>
71 #include <sys/sa.h>
72 #include <sys/syscallargs.h>
73
74 static void cvtstat __P((struct stat *, struct stat43 *));
75
76 /*
77 * Convert from an old to a new stat structure.
78 */
79 static void
80 cvtstat(st, ost)
81 struct stat *st;
82 struct stat43 *ost;
83 {
84
85 ost->st_dev = st->st_dev;
86 ost->st_ino = st->st_ino;
87 ost->st_mode = st->st_mode & 0xffff;
88 ost->st_nlink = st->st_nlink;
89 ost->st_uid = st->st_uid;
90 ost->st_gid = st->st_gid;
91 ost->st_rdev = st->st_rdev;
92 if (st->st_size < (quad_t)1 << 32)
93 ost->st_size = st->st_size;
94 else
95 ost->st_size = -2;
96 ost->st_atime = st->st_atime;
97 ost->st_mtime = st->st_mtime;
98 ost->st_ctime = st->st_ctime;
99 ost->st_blksize = st->st_blksize;
100 ost->st_blocks = st->st_blocks;
101 ost->st_flags = st->st_flags;
102 ost->st_gen = st->st_gen;
103 }
104
105 /*
106 * Get file status; this version follows links.
107 */
108 /* ARGSUSED */
109 int
110 compat_43_sys_stat(struct lwp *l, void *v, register_t *retval)
111 {
112 struct compat_43_sys_stat_args /* {
113 syscallarg(char *) path;
114 syscallarg(struct stat43 *) ub;
115 } */ *uap = v;
116 struct proc *p = l->l_proc;
117 struct stat sb;
118 struct stat43 osb;
119 int error;
120 struct nameidata nd;
121
122 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
123 SCARG(uap, path), p);
124 if ((error = namei(&nd)) != 0)
125 return (error);
126 error = vn_stat(nd.ni_vp, &sb, p);
127 vput(nd.ni_vp);
128 if (error)
129 return (error);
130 cvtstat(&sb, &osb);
131 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
132 return (error);
133 }
134
135 /*
136 * Get file status; this version does not follow links.
137 */
138 /* ARGSUSED */
139 int
140 compat_43_sys_lstat(struct lwp *l, void *v, register_t *retval)
141 {
142 struct compat_43_sys_lstat_args /* {
143 syscallarg(char *) path;
144 syscallarg(struct ostat *) ub;
145 } */ *uap = v;
146 struct proc *p = l->l_proc;
147 struct vnode *vp, *dvp;
148 struct stat sb, sb1;
149 struct stat43 osb;
150 int error;
151 struct nameidata nd;
152 int ndflags;
153
154 ndflags = NOFOLLOW | LOCKLEAF | LOCKPARENT;
155 again:
156 NDINIT(&nd, LOOKUP, ndflags, UIO_USERSPACE, SCARG(uap, path), p);
157 if ((error = namei(&nd))) {
158 if (error == EISDIR && (ndflags & LOCKPARENT) != 0) {
159 /*
160 * Should only happen on '/'. Retry without LOCKPARENT;
161 * this is safe since the vnode won't be a VLNK.
162 */
163 ndflags &= ~LOCKPARENT;
164 goto again;
165 }
166 return (error);
167 }
168 /*
169 * For symbolic links, always return the attributes of its
170 * containing directory, except for mode, size, and links.
171 */
172 vp = nd.ni_vp;
173 dvp = nd.ni_dvp;
174 if (vp->v_type != VLNK) {
175 if ((ndflags & LOCKPARENT) != 0) {
176 if (dvp == vp)
177 vrele(dvp);
178 else
179 vput(dvp);
180 }
181 error = vn_stat(vp, &sb, p);
182 vput(vp);
183 if (error)
184 return (error);
185 } else {
186 error = vn_stat(dvp, &sb, p);
187 vput(dvp);
188 if (error) {
189 vput(vp);
190 return (error);
191 }
192 error = vn_stat(vp, &sb1, p);
193 vput(vp);
194 if (error)
195 return (error);
196 sb.st_mode &= ~S_IFDIR;
197 sb.st_mode |= S_IFLNK;
198 sb.st_nlink = sb1.st_nlink;
199 sb.st_size = sb1.st_size;
200 sb.st_blocks = sb1.st_blocks;
201 }
202 cvtstat(&sb, &osb);
203 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
204 return (error);
205 }
206
207 /*
208 * Return status information about a file descriptor.
209 */
210 /* ARGSUSED */
211 int
212 compat_43_sys_fstat(struct lwp *l, void *v, register_t *retval)
213 {
214 struct compat_43_sys_fstat_args /* {
215 syscallarg(int) fd;
216 syscallarg(struct stat43 *) sb;
217 } */ *uap = v;
218 struct proc *p = l->l_proc;
219 int fd = SCARG(uap, fd);
220 struct filedesc *fdp = p->p_fd;
221 struct file *fp;
222 struct stat ub;
223 struct stat43 oub;
224 int error;
225
226 if ((fp = fd_getfile(fdp, fd)) == NULL)
227 return (EBADF);
228
229 FILE_USE(fp);
230 error = (*fp->f_ops->fo_stat)(fp, &ub, p);
231 FILE_UNUSE(fp, p);
232
233 if (error == 0) {
234 cvtstat(&ub, &oub);
235 error = copyout((caddr_t)&oub, (caddr_t)SCARG(uap, sb),
236 sizeof (oub));
237 }
238
239
240 return (error);
241 }
242
243
244 /*
245 * Truncate a file given a file descriptor.
246 */
247 /* ARGSUSED */
248 int
249 compat_43_sys_ftruncate(struct lwp *l, void *v, register_t *retval)
250 {
251 struct compat_43_sys_ftruncate_args /* {
252 syscallarg(int) fd;
253 syscallarg(long) length;
254 } */ *uap = v;
255 struct sys_ftruncate_args /* {
256 syscallarg(int) fd;
257 syscallarg(int) pad;
258 syscallarg(off_t) length;
259 } */ nuap;
260
261 SCARG(&nuap, fd) = SCARG(uap, fd);
262 SCARG(&nuap, length) = SCARG(uap, length);
263 return (sys_ftruncate(l, &nuap, retval));
264 }
265
266 /*
267 * Truncate a file given its path name.
268 */
269 /* ARGSUSED */
270 int
271 compat_43_sys_truncate(struct lwp *l, void *v, register_t *retval)
272 {
273 struct compat_43_sys_truncate_args /* {
274 syscallarg(char *) path;
275 syscallarg(long) length;
276 } */ *uap = v;
277 struct sys_truncate_args /* {
278 syscallarg(char *) path;
279 syscallarg(int) pad;
280 syscallarg(off_t) length;
281 } */ nuap;
282
283 SCARG(&nuap, path) = SCARG(uap, path);
284 SCARG(&nuap, length) = SCARG(uap, length);
285 return (sys_truncate(l, &nuap, retval));
286 }
287
288
289 /*
290 * Reposition read/write file offset.
291 */
292 int
293 compat_43_sys_lseek(struct lwp *l, void *v, register_t *retval)
294 {
295 struct compat_43_sys_lseek_args /* {
296 syscallarg(int) fd;
297 syscallarg(long) offset;
298 syscallarg(int) whence;
299 } */ *uap = v;
300 struct sys_lseek_args /* {
301 syscallarg(int) fd;
302 syscallarg(int) pad;
303 syscallarg(off_t) offset;
304 syscallarg(int) whence;
305 } */ nuap;
306 off_t qret;
307 int error;
308
309 SCARG(&nuap, fd) = SCARG(uap, fd);
310 SCARG(&nuap, offset) = SCARG(uap, offset);
311 SCARG(&nuap, whence) = SCARG(uap, whence);
312 error = sys_lseek(l, &nuap, (register_t *)&qret);
313 *(long *)retval = qret;
314 return (error);
315 }
316
317
318 /*
319 * Create a file.
320 */
321 int
322 compat_43_sys_creat(struct lwp *l, void *v, register_t *retval)
323 {
324 struct compat_43_sys_creat_args /* {
325 syscallarg(char *) path;
326 syscallarg(int) mode;
327 } */ *uap = v;
328 struct sys_open_args /* {
329 syscallarg(char *) path;
330 syscallarg(int) flags;
331 syscallarg(int) mode;
332 } */ nuap;
333
334 SCARG(&nuap, path) = SCARG(uap, path);
335 SCARG(&nuap, mode) = SCARG(uap, mode);
336 SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC;
337 return (sys_open(l, &nuap, retval));
338 }
339
340 /*ARGSUSED*/
341 int
342 compat_43_sys_quota(struct lwp *l, void *v, register_t *retval)
343 {
344
345 return (ENOSYS);
346 }
347
348
349 /*
350 * Read a block of directory entries in a file system independent format.
351 */
352 int
353 compat_43_sys_getdirentries(struct lwp *l, void *v, register_t *retval)
354 {
355 struct compat_43_sys_getdirentries_args /* {
356 syscallarg(int) fd;
357 syscallarg(char *) buf;
358 syscallarg(u_int) count;
359 syscallarg(long *) basep;
360 } */ *uap = v;
361 struct proc *p = l->l_proc;
362 struct vnode *vp;
363 struct file *fp;
364 struct uio auio, kuio;
365 struct iovec aiov, kiov;
366 struct dirent *dp, *edp;
367 caddr_t dirbuf;
368 int error, eofflag, readcnt;
369 long loff;
370
371 /* getvnode() will use the descriptor for us */
372 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
373 return (error);
374 if ((fp->f_flag & FREAD) == 0) {
375 error = EBADF;
376 goto out;
377 }
378 vp = (struct vnode *)fp->f_data;
379 unionread:
380 if (vp->v_type != VDIR) {
381 error = EINVAL;
382 goto out;
383 }
384 aiov.iov_base = SCARG(uap, buf);
385 aiov.iov_len = SCARG(uap, count);
386 auio.uio_iov = &aiov;
387 auio.uio_iovcnt = 1;
388 auio.uio_rw = UIO_READ;
389 auio.uio_segflg = UIO_USERSPACE;
390 auio.uio_procp = p;
391 auio.uio_resid = SCARG(uap, count);
392 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
393 loff = auio.uio_offset = fp->f_offset;
394 # if (BYTE_ORDER != LITTLE_ENDIAN)
395 if (vp->v_mount->mnt_maxsymlinklen <= 0) {
396 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
397 (off_t **)0, (int *)0);
398 fp->f_offset = auio.uio_offset;
399 } else
400 # endif
401 {
402 kuio = auio;
403 kuio.uio_iov = &kiov;
404 kuio.uio_segflg = UIO_SYSSPACE;
405 kiov.iov_len = SCARG(uap, count);
406 MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK);
407 kiov.iov_base = dirbuf;
408 error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
409 (off_t **)0, (int *)0);
410 fp->f_offset = kuio.uio_offset;
411 if (error == 0) {
412 readcnt = SCARG(uap, count) - kuio.uio_resid;
413 edp = (struct dirent *)&dirbuf[readcnt];
414 for (dp = (struct dirent *)dirbuf; dp < edp; ) {
415 # if (BYTE_ORDER == LITTLE_ENDIAN)
416 /*
417 * The expected low byte of
418 * dp->d_namlen is our dp->d_type.
419 * The high MBZ byte of dp->d_namlen
420 * is our dp->d_namlen.
421 */
422 dp->d_type = dp->d_namlen;
423 dp->d_namlen = 0;
424 # else
425 /*
426 * The dp->d_type is the high byte
427 * of the expected dp->d_namlen,
428 * so must be zero'ed.
429 */
430 dp->d_type = 0;
431 # endif
432 if (dp->d_reclen > 0) {
433 dp = (struct dirent *)
434 ((char *)dp + dp->d_reclen);
435 } else {
436 error = EIO;
437 break;
438 }
439 }
440 if (dp >= edp)
441 error = uiomove(dirbuf, readcnt, &auio);
442 }
443 FREE(dirbuf, M_TEMP);
444 }
445 VOP_UNLOCK(vp, 0);
446 if (error)
447 goto out;
448
449 #ifdef UNION
450 {
451 extern int (**union_vnodeop_p) __P((void *));
452 extern struct vnode *union_dircache __P((struct vnode *));
453
454 if ((SCARG(uap, count) == auio.uio_resid) &&
455 (vp->v_op == union_vnodeop_p)) {
456 struct vnode *lvp;
457
458 lvp = union_dircache(vp);
459 if (lvp != NULLVP) {
460 struct vattr va;
461
462 /*
463 * If the directory is opaque,
464 * then don't show lower entries
465 */
466 error = VOP_GETATTR(vp, &va, fp->f_cred, p);
467 if (va.va_flags & OPAQUE) {
468 vput(lvp);
469 lvp = NULL;
470 }
471 }
472
473 if (lvp != NULLVP) {
474 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
475 VOP_UNLOCK(lvp, 0);
476
477 if (error) {
478 vrele(lvp);
479 goto out;
480 }
481 fp->f_data = (caddr_t) lvp;
482 fp->f_offset = 0;
483 error = vn_close(vp, FREAD, fp->f_cred, p);
484 if (error)
485 goto out;
486 vp = lvp;
487 goto unionread;
488 }
489 }
490 }
491 #endif /* UNION */
492
493 if ((SCARG(uap, count) == auio.uio_resid) &&
494 (vp->v_flag & VROOT) &&
495 (vp->v_mount->mnt_flag & MNT_UNION)) {
496 struct vnode *tvp = vp;
497 vp = vp->v_mount->mnt_vnodecovered;
498 VREF(vp);
499 fp->f_data = (caddr_t) vp;
500 fp->f_offset = 0;
501 vrele(tvp);
502 goto unionread;
503 }
504 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
505 sizeof(long));
506 *retval = SCARG(uap, count) - auio.uio_resid;
507 out:
508 FILE_UNUSE(fp, p);
509 return (error);
510 }
511