1 /** $MirOS: src/sys/compat/common/vfs_syscalls_43.c,v 1.3 2005/07/03 21:18:55 tg Exp $ */
2 /* $OpenBSD: vfs_syscalls_43.c,v 1.27 2005/05/26 01:15:12 pedro Exp $ */
3 /* $NetBSD: vfs_syscalls_43.c,v 1.4 1996/03/14 19:31:52 christos Exp $ */
4
5 /*
6 * Copyright (c) 1989, 1993
7 * The Regents of the University of California. All rights reserved.
8 * (c) UNIX System Laboratories, Inc.
9 * All or some portions of this file are derived from material licensed
10 * to the University of California by American Telephone and Telegraph
11 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
12 * the permission of UNIX System Laboratories, Inc.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 * 3. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * @(#)vfs_syscalls.c 8.28 (Berkeley) 12/10/94
39 */
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/filedesc.h>
44 #include <sys/kernel.h>
45 #include <sys/proc.h>
46 #include <sys/file.h>
47 #include <sys/vnode.h>
48 #include <sys/namei.h>
49 #include <sys/dirent.h>
50 #include <sys/socket.h>
51 #include <sys/socketvar.h>
52 #include <sys/stat.h>
53 #include <sys/ioctl.h>
54 #include <sys/fcntl.h>
55 #include <sys/malloc.h>
56 #include <sys/syslog.h>
57 #include <sys/unistd.h>
58 #include <sys/resourcevar.h>
59
60 #include <sys/mount.h>
61 #include <sys/syscallargs.h>
62
63 #include <uvm/uvm_extern.h>
64
65 #include <sys/pipe.h>
66
67 #include <compat/common/compat_util.h>
68 #include <compat/common/kern_gen.h>
69
70 struct stat43 {
71 u_int16_t st_dev; /* inode's device */
72 ino_t st_ino; /* inode's number */
73 u_int16_t st_mode; /* inode protection mode */
74 u_int16_t st_nlink; /* number of hard links */
75 u_int16_t st_uid; /* user ID of the file's owner */
76 u_int16_t st_gid; /* group ID of the file's group */
77 u_int16_t st_rdev; /* device type */
78 int32_t st_size; /* file size, in bytes */
79 struct timespec_compat st_atimespec; /* time of last access */
80 struct timespec_compat st_mtimespec; /* time of last data modification */
81 struct timespec_compat st_ctimespec; /* time of last file status change */
82 int32_t st_blksize; /* optimal blocksize for I/O */
83 int32_t st_blocks; /* blocks allocated for file */
84 u_int32_t st_flags; /* user defined flags for file */
85 u_int32_t st_gen; /* file generation number */
86 };
87
88 #if defined(COMPAT_OPENBSD) || defined(COMPAT_LINUX)
89 static void cvtstat(struct stat *, struct stat43 *);
90 #endif
91
92 #if defined(COMPAT_OPENBSD) || defined(COMPAT_LINUX)
93 /*
94 * Convert from a new to an old stat structure.
95 */
96 static void
cvtstat(st,ost)97 cvtstat(st, ost)
98 struct stat *st;
99 struct stat43 *ost;
100 {
101
102 ost->st_dev = st->st_dev;
103 ost->st_ino = st->st_ino;
104 ost->st_mode = st->st_mode;
105 ost->st_nlink = st->st_nlink;
106 ost->st_uid = st->st_uid;
107 ost->st_gid = st->st_gid;
108 ost->st_rdev = st->st_rdev;
109 if (st->st_size < (quad_t)1 << 32)
110 ost->st_size = st->st_size;
111 else
112 ost->st_size = -2;
113 ost->st_atime = __BOUNDLONG(st->st_atime);
114 ost->st_mtime = __BOUNDLONG(st->st_mtime);
115 ost->st_ctime = __BOUNDLONG(st->st_ctime);
116 ost->st_blksize = st->st_blksize;
117 ost->st_blocks = st->st_blocks;
118 ost->st_flags = st->st_flags;
119 ost->st_gen = st->st_gen;
120 }
121 #endif
122
123 #if defined(COMPAT_OPENBSD)
124
125 #include <compat/openbsd/compat_openbsd.h>
126
127 /*
128 * Get file status; this version follows links.
129 */
130 /* ARGSUSED */
131 int
compat_43_openbsd_sys_stat(p,v,retval)132 compat_43_openbsd_sys_stat(p, v, retval)
133 struct proc *p;
134 void *v;
135 register_t *retval;
136 {
137 struct compat_43_openbsd_sys_stat_args /* {
138 syscallarg(char *) path;
139 syscallarg(struct stat43 *) ub;
140 } */ *uap = v;
141 struct stat sb;
142 struct stat43 osb;
143 int error;
144 struct nameidata nd;
145 caddr_t sg = stackgap_init(p->p_emul);
146
147 OPENBSD_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
148 NDINIT(&nd, LOOKUP, FOLLOW | 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 /* Don't let non-root see generation numbers (for NFS security) */
157 if (suser(p, 0))
158 sb.st_gen = 0;
159 cvtstat(&sb, &osb);
160 error = copyout(&osb, SCARG(uap, ub), sizeof(osb));
161 return (error);
162 }
163 #endif
164
165 #if defined(COMPAT_OPENBSD) || defined(COMPAT_LINUX)
166 /*
167 * Get file status; this version does not follow links.
168 */
169 /* ARGSUSED */
170 int
compat_43_sys_lstat(p,v,retval)171 compat_43_sys_lstat(p, v, retval)
172 struct proc *p;
173 void *v;
174 register_t *retval;
175 {
176 register struct compat_43_sys_lstat_args /* {
177 syscallarg(char *) path;
178 syscallarg(struct stat43 *) ub;
179 } */ *uap = v;
180 struct stat sb;
181 struct stat43 osb;
182 int error;
183 struct nameidata nd;
184
185 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
186 SCARG(uap, path), p);
187 if ((error = namei(&nd)) != 0)
188 return (error);
189 error = vn_stat(nd.ni_vp, &sb, p);
190 vput(nd.ni_vp);
191 if (error)
192 return (error);
193 /* Don't let non-root see generation numbers (for NFS security) */
194 if (suser(p, 0))
195 sb.st_gen = 0;
196 cvtstat(&sb, &osb);
197 error = copyout(&osb, SCARG(uap, ub), sizeof(osb));
198 return (error);
199 }
200 #endif
201
202 #if defined(COMPAT_OPENBSD)
203 /*
204 * Return status information about a file descriptor.
205 */
206 /* ARGSUSED */
207 int
compat_43_sys_fstat(p,v,retval)208 compat_43_sys_fstat(p, v, retval)
209 struct proc *p;
210 void *v;
211 register_t *retval;
212 {
213 struct compat_43_sys_fstat_args /* {
214 syscallarg(int) fd;
215 syscallarg(struct stat43 *) sb;
216 } */ *uap = v;
217 int fd = SCARG(uap, fd);
218 struct filedesc *fdp = p->p_fd;
219 struct file *fp;
220 struct stat ub;
221 struct stat43 oub;
222 int error;
223
224 if ((fp = fd_getfile(fdp, fd)) == NULL)
225 return (EBADF);
226 FREF(fp);
227 error = (*fp->f_ops->fo_stat)(fp, &ub, p);
228 FRELE(fp);
229 if (error == 0) {
230 /* Don't let non-root see generation numbers
231 (for NFS security) */
232 if (suser(p, 0))
233 ub.st_gen = 0;
234 cvtstat(&ub, &oub);
235 error = copyout(&oub, SCARG(uap, sb), sizeof(oub));
236 }
237 return (error);
238 }
239 #endif
240
241 #if defined(COMPAT_OPENBSD) || defined(COMPAT_LINUX)
242 /*
243 * Truncate a file given a file descriptor.
244 */
245 /* ARGSUSED */
246 int
compat_43_sys_ftruncate(p,v,retval)247 compat_43_sys_ftruncate(p, v, retval)
248 struct proc *p;
249 void *v;
250 register_t *retval;
251 {
252 register struct compat_43_sys_ftruncate_args /* {
253 syscallarg(int) fd;
254 syscallarg(long) length;
255 } */ *uap = v;
256 struct sys_ftruncate_args /* {
257 syscallarg(int) fd;
258 syscallarg(int) pad;
259 syscallarg(off_t) length;
260 } */ nuap;
261
262 SCARG(&nuap, fd) = SCARG(uap, fd);
263 SCARG(&nuap, length) = SCARG(uap, length);
264 return (sys_ftruncate(p, &nuap, retval));
265 }
266
267 /*
268 * Truncate a file given its path name.
269 */
270 /* ARGSUSED */
271 int
compat_43_sys_truncate(p,v,retval)272 compat_43_sys_truncate(p, v, retval)
273 struct proc *p;
274 void *v;
275 register_t *retval;
276 {
277 register struct compat_43_sys_truncate_args /* {
278 syscallarg(char *) path;
279 syscallarg(long) length;
280 } */ *uap = v;
281 struct sys_truncate_args /* {
282 syscallarg(char *) path;
283 syscallarg(int) pad;
284 syscallarg(off_t) length;
285 } */ nuap;
286
287 SCARG(&nuap, path) = SCARG(uap, path);
288 SCARG(&nuap, length) = SCARG(uap, length);
289 return (sys_truncate(p, &nuap, retval));
290 }
291
292
293 /*
294 * Reposition read/write file offset.
295 */
296 int
compat_43_sys_lseek(p,v,retval)297 compat_43_sys_lseek(p, v, retval)
298 struct proc *p;
299 void *v;
300 register_t *retval;
301 {
302 register struct compat_43_sys_lseek_args /* {
303 syscallarg(int) fd;
304 syscallarg(long) offset;
305 syscallarg(int) whence;
306 } */ *uap = v;
307 struct sys_lseek_args /* {
308 syscallarg(int) fd;
309 syscallarg(int) pad;
310 syscallarg(off_t) offset;
311 syscallarg(int) whence;
312 } */ nuap;
313 off_t qret;
314 int error;
315
316 SCARG(&nuap, fd) = SCARG(uap, fd);
317 SCARG(&nuap, offset) = SCARG(uap, offset);
318 SCARG(&nuap, whence) = SCARG(uap, whence);
319 error = sys_lseek(p, &nuap, (register_t *)&qret);
320 *(long *)retval = qret;
321 return (error);
322 }
323 #endif
324
325 #if defined(COMPAT_OPENBSD)
326 /*
327 * Create a file.
328 */
329 int
compat_43_sys_creat(p,v,retval)330 compat_43_sys_creat(p, v, retval)
331 struct proc *p;
332 void *v;
333 register_t *retval;
334 {
335 register struct compat_43_sys_creat_args /* {
336 syscallarg(char *) path;
337 syscallarg(mode_t) mode;
338 } */ *uap = v;
339 struct sys_open_args /* {
340 syscallarg(char *) path;
341 syscallarg(int) flags;
342 syscallarg(mode_t) mode;
343 } */ nuap;
344
345 SCARG(&nuap, path) = SCARG(uap, path);
346 SCARG(&nuap, mode) = SCARG(uap, mode);
347 SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC;
348 return (sys_open(p, &nuap, retval));
349 }
350
351 /*
352 * Read a block of directory entries in a file system independent format.
353 */
354 int
compat_43_sys_getdirentries(p,v,retval)355 compat_43_sys_getdirentries(p, v, retval)
356 struct proc *p;
357 void *v;
358 register_t *retval;
359 {
360 register struct compat_43_sys_getdirentries_args /* {
361 syscallarg(int) fd;
362 syscallarg(char *) buf;
363 syscallarg(int) count;
364 syscallarg(long *) basep;
365 } */ *uap = v;
366 struct vnode *vp;
367 struct file *fp;
368 struct uio auio, kuio;
369 struct iovec aiov, kiov;
370 struct dirent *dp, *edp;
371 caddr_t dirbuf;
372 int error, eofflag, readcnt;
373 long loff;
374
375 if (SCARG(uap, count) < 0)
376 return EINVAL;
377 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
378 return (error);
379 if ((fp->f_flag & FREAD) == 0) {
380 error = EBADF;
381 goto bad;
382 }
383 vp = (struct vnode *)fp->f_data;
384 if (vp->v_type != VDIR) {
385 error = EINVAL;
386 goto bad;
387 }
388 aiov.iov_base = SCARG(uap, buf);
389 aiov.iov_len = SCARG(uap, count);
390 auio.uio_iov = &aiov;
391 auio.uio_iovcnt = 1;
392 auio.uio_rw = UIO_READ;
393 auio.uio_segflg = UIO_USERSPACE;
394 auio.uio_procp = p;
395 auio.uio_resid = SCARG(uap, count);
396
397 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
398 loff = auio.uio_offset = fp->f_offset;
399 # if (BYTE_ORDER != LITTLE_ENDIAN)
400 if (vp->v_mount->mnt_maxsymlinklen <= 0) {
401 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
402 (int *)0, (u_long **)0);
403 fp->f_offset = auio.uio_offset;
404 } else
405 # endif
406 {
407 u_int nbytes = SCARG(uap, count);
408
409 nbytes = min(nbytes, MAXBSIZE);
410
411 kuio = auio;
412 kuio.uio_iov = &kiov;
413 kuio.uio_segflg = UIO_SYSSPACE;
414 kiov.iov_len = nbytes;
415 dirbuf = (caddr_t)malloc(nbytes, M_TEMP, M_WAITOK);
416 kiov.iov_base = dirbuf;
417
418 error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
419 0, 0);
420 fp->f_offset = kuio.uio_offset;
421 if (error == 0) {
422 readcnt = nbytes - 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, p);
456 if (error)
457 goto bad;
458 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
459 sizeof(long));
460 *retval = SCARG(uap, count) - auio.uio_resid;
461 bad:
462 FRELE(fp);
463 return (error);
464 }
465 #endif
466