vfs_syscalls_43.c revision 1.13 1 /* $NetBSD: vfs_syscalls_43.c,v 1.13 2000/03/30 11:27:15 augustss 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 "fs_union.h"
44
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/filedesc.h>
48 #include <sys/kernel.h>
49 #include <sys/proc.h>
50 #include <sys/file.h>
51 #include <sys/vnode.h>
52 #include <sys/namei.h>
53 #include <sys/dirent.h>
54 #include <sys/socket.h>
55 #include <sys/socketvar.h>
56 #include <sys/stat.h>
57 #include <sys/ioctl.h>
58 #include <sys/fcntl.h>
59 #include <sys/malloc.h>
60 #include <sys/syslog.h>
61 #include <sys/unistd.h>
62 #include <sys/resourcevar.h>
63
64 #include <sys/mount.h>
65 #include <sys/syscallargs.h>
66
67 static void cvtstat __P((struct stat *, struct stat43 *));
68
69 /*
70 * Convert from an old to a new stat structure.
71 */
72 static void
73 cvtstat(st, ost)
74 struct stat *st;
75 struct stat43 *ost;
76 {
77
78 ost->st_dev = st->st_dev;
79 ost->st_ino = st->st_ino;
80 ost->st_mode = st->st_mode & 0xffff;
81 ost->st_nlink = st->st_nlink;
82 ost->st_uid = st->st_uid;
83 ost->st_gid = st->st_gid;
84 ost->st_rdev = st->st_rdev;
85 if (st->st_size < (quad_t)1 << 32)
86 ost->st_size = st->st_size;
87 else
88 ost->st_size = -2;
89 ost->st_atime = st->st_atime;
90 ost->st_mtime = st->st_mtime;
91 ost->st_ctime = st->st_ctime;
92 ost->st_blksize = st->st_blksize;
93 ost->st_blocks = st->st_blocks;
94 ost->st_flags = st->st_flags;
95 ost->st_gen = st->st_gen;
96 }
97
98 /*
99 * Get file status; this version follows links.
100 */
101 /* ARGSUSED */
102 int
103 compat_43_sys_stat(p, v, retval)
104 struct proc *p;
105 void *v;
106 register_t *retval;
107 {
108 struct compat_43_sys_stat_args /* {
109 syscallarg(char *) path;
110 syscallarg(struct stat43 *) ub;
111 } */ *uap = v;
112 struct stat sb;
113 struct stat43 osb;
114 int error;
115 struct nameidata nd;
116
117 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
118 SCARG(uap, path), p);
119 if ((error = namei(&nd)) != 0)
120 return (error);
121 error = vn_stat(nd.ni_vp, &sb, p);
122 vput(nd.ni_vp);
123 if (error)
124 return (error);
125 cvtstat(&sb, &osb);
126 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
127 return (error);
128 }
129
130 /*
131 * Get file status; this version does not follow links.
132 */
133 /* ARGSUSED */
134 int
135 compat_43_sys_lstat(p, v, retval)
136 struct proc *p;
137 void *v;
138 register_t *retval;
139 {
140 struct compat_43_sys_lstat_args /* {
141 syscallarg(char *) path;
142 syscallarg(struct ostat *) ub;
143 } */ *uap = v;
144 struct vnode *vp, *dvp;
145 struct stat sb, sb1;
146 struct stat43 osb;
147 int error;
148 struct nameidata nd;
149
150 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
151 SCARG(uap, path), p);
152 if ((error = namei(&nd)))
153 return (error);
154 /*
155 * For symbolic links, always return the attributes of its
156 * containing directory, except for mode, size, and links.
157 */
158 vp = nd.ni_vp;
159 dvp = nd.ni_dvp;
160 if (vp->v_type != VLNK) {
161 if (dvp == vp)
162 vrele(dvp);
163 else
164 vput(dvp);
165 error = vn_stat(vp, &sb, p);
166 vput(vp);
167 if (error)
168 return (error);
169 } else {
170 error = vn_stat(dvp, &sb, p);
171 vput(dvp);
172 if (error) {
173 vput(vp);
174 return (error);
175 }
176 error = vn_stat(vp, &sb1, p);
177 vput(vp);
178 if (error)
179 return (error);
180 sb.st_mode &= ~S_IFDIR;
181 sb.st_mode |= S_IFLNK;
182 sb.st_nlink = sb1.st_nlink;
183 sb.st_size = sb1.st_size;
184 sb.st_blocks = sb1.st_blocks;
185 }
186 cvtstat(&sb, &osb);
187 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
188 return (error);
189 }
190
191 /*
192 * Return status information about a file descriptor.
193 */
194 /* ARGSUSED */
195 int
196 compat_43_sys_fstat(p, v, retval)
197 struct proc *p;
198 void *v;
199 register_t *retval;
200 {
201 struct compat_43_sys_fstat_args /* {
202 syscallarg(int) fd;
203 syscallarg(struct stat43 *) sb;
204 } */ *uap = v;
205 int fd = SCARG(uap, fd);
206 struct filedesc *fdp = p->p_fd;
207 struct file *fp;
208 struct stat ub;
209 struct stat43 oub;
210 int error;
211
212 if ((u_int)fd >= fdp->fd_nfiles ||
213 (fp = fdp->fd_ofiles[fd]) == NULL)
214 return (EBADF);
215 switch (fp->f_type) {
216
217 case DTYPE_VNODE:
218 error = vn_stat((struct vnode *)fp->f_data, &ub, p);
219 break;
220
221 case DTYPE_SOCKET:
222 error = soo_stat((struct socket *)fp->f_data, &ub);
223 break;
224
225 default:
226 panic("ofstat");
227 /*NOTREACHED*/
228 }
229 cvtstat(&ub, &oub);
230 if (error == 0)
231 error = copyout((caddr_t)&oub, (caddr_t)SCARG(uap, sb),
232 sizeof (oub));
233 return (error);
234 }
235
236
237 /*
238 * Truncate a file given a file descriptor.
239 */
240 /* ARGSUSED */
241 int
242 compat_43_sys_ftruncate(p, v, retval)
243 struct proc *p;
244 void *v;
245 register_t *retval;
246 {
247 struct compat_43_sys_ftruncate_args /* {
248 syscallarg(int) fd;
249 syscallarg(long) length;
250 } */ *uap = v;
251 struct sys_ftruncate_args /* {
252 syscallarg(int) fd;
253 syscallarg(int) pad;
254 syscallarg(off_t) length;
255 } */ nuap;
256
257 SCARG(&nuap, fd) = SCARG(uap, fd);
258 SCARG(&nuap, length) = SCARG(uap, length);
259 return (sys_ftruncate(p, &nuap, retval));
260 }
261
262 /*
263 * Truncate a file given its path name.
264 */
265 /* ARGSUSED */
266 int
267 compat_43_sys_truncate(p, v, retval)
268 struct proc *p;
269 void *v;
270 register_t *retval;
271 {
272 struct compat_43_sys_truncate_args /* {
273 syscallarg(char *) path;
274 syscallarg(long) length;
275 } */ *uap = v;
276 struct sys_truncate_args /* {
277 syscallarg(char *) path;
278 syscallarg(int) pad;
279 syscallarg(off_t) length;
280 } */ nuap;
281
282 SCARG(&nuap, path) = SCARG(uap, path);
283 SCARG(&nuap, length) = SCARG(uap, length);
284 return (sys_truncate(p, &nuap, retval));
285 }
286
287
288 /*
289 * Reposition read/write file offset.
290 */
291 int
292 compat_43_sys_lseek(p, v, retval)
293 struct proc *p;
294 void *v;
295 register_t *retval;
296 {
297 struct compat_43_sys_lseek_args /* {
298 syscallarg(int) fd;
299 syscallarg(long) offset;
300 syscallarg(int) whence;
301 } */ *uap = v;
302 struct sys_lseek_args /* {
303 syscallarg(int) fd;
304 syscallarg(int) pad;
305 syscallarg(off_t) offset;
306 syscallarg(int) whence;
307 } */ nuap;
308 off_t qret;
309 int error;
310
311 SCARG(&nuap, fd) = SCARG(uap, fd);
312 SCARG(&nuap, offset) = SCARG(uap, offset);
313 SCARG(&nuap, whence) = SCARG(uap, whence);
314 error = sys_lseek(p, &nuap, (register_t *)&qret);
315 *(long *)retval = qret;
316 return (error);
317 }
318
319
320 /*
321 * Create a file.
322 */
323 int
324 compat_43_sys_creat(p, v, retval)
325 struct proc *p;
326 void *v;
327 register_t *retval;
328 {
329 struct compat_43_sys_creat_args /* {
330 syscallarg(char *) path;
331 syscallarg(int) mode;
332 } */ *uap = v;
333 struct sys_open_args /* {
334 syscallarg(char *) path;
335 syscallarg(int) flags;
336 syscallarg(int) mode;
337 } */ nuap;
338
339 SCARG(&nuap, path) = SCARG(uap, path);
340 SCARG(&nuap, mode) = SCARG(uap, mode);
341 SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC;
342 return (sys_open(p, &nuap, retval));
343 }
344
345 /*ARGSUSED*/
346 int
347 compat_43_sys_quota(p, v, retval)
348 struct proc *p;
349 void *v;
350 register_t *retval;
351 {
352
353 return (ENOSYS);
354 }
355
356
357 /*
358 * Read a block of directory entries in a file system independent format.
359 */
360 int
361 compat_43_sys_getdirentries(p, v, retval)
362 struct proc *p;
363 void *v;
364 register_t *retval;
365 {
366 struct compat_43_sys_getdirentries_args /* {
367 syscallarg(int) fd;
368 syscallarg(char *) buf;
369 syscallarg(u_int) count;
370 syscallarg(long *) basep;
371 } */ *uap = v;
372 struct vnode *vp;
373 struct file *fp;
374 struct uio auio, kuio;
375 struct iovec aiov, kiov;
376 struct dirent *dp, *edp;
377 caddr_t dirbuf;
378 int error, eofflag, readcnt;
379 long loff;
380
381 /* getvnode() will use the descriptor for us */
382 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
383 return (error);
384 if ((fp->f_flag & FREAD) == 0) {
385 error = EBADF;
386 goto out;
387 }
388 vp = (struct vnode *)fp->f_data;
389 unionread:
390 if (vp->v_type != VDIR) {
391 error = EINVAL;
392 goto out;
393 }
394 aiov.iov_base = SCARG(uap, buf);
395 aiov.iov_len = SCARG(uap, count);
396 auio.uio_iov = &aiov;
397 auio.uio_iovcnt = 1;
398 auio.uio_rw = UIO_READ;
399 auio.uio_segflg = UIO_USERSPACE;
400 auio.uio_procp = p;
401 auio.uio_resid = SCARG(uap, count);
402 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
403 loff = auio.uio_offset = fp->f_offset;
404 # if (BYTE_ORDER != LITTLE_ENDIAN)
405 if (vp->v_mount->mnt_maxsymlinklen <= 0) {
406 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
407 (off_t **)0, (int *)0);
408 fp->f_offset = auio.uio_offset;
409 } else
410 # endif
411 {
412 kuio = auio;
413 kuio.uio_iov = &kiov;
414 kuio.uio_segflg = UIO_SYSSPACE;
415 kiov.iov_len = SCARG(uap, count);
416 MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK);
417 kiov.iov_base = dirbuf;
418 error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
419 (off_t **)0, (int *)0);
420 fp->f_offset = kuio.uio_offset;
421 if (error == 0) {
422 readcnt = SCARG(uap, count) - kuio.uio_resid;
423 edp = (struct dirent *)&dirbuf[readcnt];
424 for (dp = (struct dirent *)dirbuf; dp < edp; ) {
425 # if (BYTE_ORDER == LITTLE_ENDIAN)
426 /*
427 * The expected low byte of
428 * dp->d_namlen is our dp->d_type.
429 * The high MBZ byte of dp->d_namlen
430 * is our dp->d_namlen.
431 */
432 dp->d_type = dp->d_namlen;
433 dp->d_namlen = 0;
434 # else
435 /*
436 * The dp->d_type is the high byte
437 * of the expected dp->d_namlen,
438 * so must be zero'ed.
439 */
440 dp->d_type = 0;
441 # endif
442 if (dp->d_reclen > 0) {
443 dp = (struct dirent *)
444 ((char *)dp + dp->d_reclen);
445 } else {
446 error = EIO;
447 break;
448 }
449 }
450 if (dp >= edp)
451 error = uiomove(dirbuf, readcnt, &auio);
452 }
453 FREE(dirbuf, M_TEMP);
454 }
455 VOP_UNLOCK(vp, 0);
456 if (error)
457 goto out;
458
459 #ifdef UNION
460 {
461 extern int (**union_vnodeop_p) __P((void *));
462 extern struct vnode *union_dircache __P((struct vnode *));
463
464 if ((SCARG(uap, count) == auio.uio_resid) &&
465 (vp->v_op == union_vnodeop_p)) {
466 struct vnode *lvp;
467
468 lvp = union_dircache(vp);
469 if (lvp != NULLVP) {
470 struct vattr va;
471
472 /*
473 * If the directory is opaque,
474 * then don't show lower entries
475 */
476 error = VOP_GETATTR(vp, &va, fp->f_cred, p);
477 if (va.va_flags & OPAQUE) {
478 vput(lvp);
479 lvp = NULL;
480 }
481 }
482
483 if (lvp != NULLVP) {
484 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
485 VOP_UNLOCK(lvp, 0);
486
487 if (error) {
488 vrele(lvp);
489 goto out;
490 }
491 fp->f_data = (caddr_t) lvp;
492 fp->f_offset = 0;
493 error = vn_close(vp, FREAD, fp->f_cred, p);
494 if (error)
495 goto out;
496 vp = lvp;
497 goto unionread;
498 }
499 }
500 }
501 #endif /* UNION */
502
503 if ((SCARG(uap, count) == auio.uio_resid) &&
504 (vp->v_flag & VROOT) &&
505 (vp->v_mount->mnt_flag & MNT_UNION)) {
506 struct vnode *tvp = vp;
507 vp = vp->v_mount->mnt_vnodecovered;
508 VREF(vp);
509 fp->f_data = (caddr_t) vp;
510 fp->f_offset = 0;
511 vrele(tvp);
512 goto unionread;
513 }
514 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
515 sizeof(long));
516 *retval = SCARG(uap, count) - auio.uio_resid;
517 out:
518 FILE_UNUSE(fp, p);
519 return (error);
520 }
521