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