linux_file.c revision 63285
177218Sphk/*-
277218Sphk * Copyright (c) 1994-1995 S�ren Schmidt
377218Sphk * All rights reserved.
477218Sphk *
577218Sphk * Redistribution and use in source and binary forms, with or without
677218Sphk * modification, are permitted provided that the following conditions
777218Sphk * are met:
877218Sphk * 1. Redistributions of source code must retain the above copyright
977218Sphk *    notice, this list of conditions and the following disclaimer
1077218Sphk *    in this position and unchanged.
1177218Sphk * 2. Redistributions in binary form must reproduce the above copyright
1291454Sbrooks *    notice, this list of conditions and the following disclaimer in the
1391454Sbrooks *    documentation and/or other materials provided with the distribution.
1477218Sphk * 3. The name of the author may not be used to endorse or promote products
1577218Sphk *    derived from this software withough specific prior written permission
1677218Sphk *
1777218Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1877218Sphk * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1977218Sphk * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2077218Sphk * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2177218Sphk * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2277218Sphk * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2377218Sphk * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2477218Sphk * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2577218Sphk * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2677218Sphk * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2777218Sphk *
2877218Sphk * $FreeBSD: head/sys/compat/linux/linux_file.c 63285 2000-07-17 00:17:07Z marcel $
2977218Sphk */
3077218Sphk
3177218Sphk#include "opt_compat.h"
3277218Sphk
3377218Sphk#include <sys/param.h>
3477218Sphk#include <sys/systm.h>
3577218Sphk#include <sys/sysproto.h>
3677218Sphk#include <sys/fcntl.h>
3777218Sphk#include <sys/file.h>
3877218Sphk#include <sys/filedesc.h>
3977218Sphk#include <sys/lock.h>
4077218Sphk#include <sys/proc.h>
4177218Sphk#include <sys/vnode.h>
4277218Sphk#include <sys/malloc.h>
4377218Sphk#include <sys/dirent.h>
4477218Sphk#include <sys/conf.h>
4577218Sphk#include <sys/tty.h>
4677218Sphk
4777218Sphk#include <i386/linux/linux.h>
4877218Sphk#include <i386/linux/linux_proto.h>
4977218Sphk#include <i386/linux/linux_util.h>
5077218Sphk
5177218Sphkint
5277218Sphklinux_creat(struct proc *p, struct linux_creat_args *args)
5377218Sphk{
5477218Sphk    struct open_args /* {
5577218Sphk	char *path;
5677218Sphk	int flags;
5777218Sphk	int mode;
5877218Sphk    } */ bsd_open_args;
5977218Sphk    caddr_t sg;
6077218Sphk
6177218Sphk    sg = stackgap_init();
6277218Sphk    CHECKALTCREAT(p, &sg, args->path);
6377218Sphk
6477218Sphk#ifdef DEBUG
6577218Sphk    printf("Linux-emul(%d): creat(%s, %d)\n",
6677218Sphk	   p->p_pid, args->path, args->mode);
6777218Sphk#endif
6877218Sphk    bsd_open_args.path = args->path;
6977218Sphk    bsd_open_args.mode = args->mode;
70138593Ssam    bsd_open_args.flags = O_WRONLY | O_CREAT | O_TRUNC;
7177218Sphk    return open(p, &bsd_open_args);
72138593Ssam}
73116957Ssam
74190456Ssamint
75190456Ssamlinux_open(struct proc *p, struct linux_open_args *args)
76190456Ssam{
77195618Srpaulo    struct open_args /* {
7877218Sphk	char *path;
79187801Ssam	int flags;
8077218Sphk	int mode;
8177218Sphk    } */ bsd_open_args;
8277218Sphk    int error;
8377218Sphk    caddr_t sg;
84146873Sjhb
8577218Sphk    sg = stackgap_init();
8677218Sphk
8777218Sphk    if (args->flags & LINUX_O_CREAT)
8877218Sphk	CHECKALTCREAT(p, &sg, args->path);
89155931Ssam    else
90173275Ssam	CHECKALTEXIST(p, &sg, args->path);
9177218Sphk
9277218Sphk#ifdef DEBUG
93178354Ssam    printf("Linux-emul(%d): open(%s, 0x%x, 0x%x)\n",
9477218Sphk	   p->p_pid, args->path, args->flags, args->mode);
95178354Ssam#endif
96178354Ssam    bsd_open_args.flags = 0;
97178354Ssam    if (args->flags & LINUX_O_RDONLY)
98178354Ssam	bsd_open_args.flags |= O_RDONLY;
99178354Ssam    if (args->flags & LINUX_O_WRONLY)
100178354Ssam	bsd_open_args.flags |= O_WRONLY;
101194136Ssam    if (args->flags & LINUX_O_RDWR)
102194136Ssam	bsd_open_args.flags |= O_RDWR;
103194136Ssam    if (args->flags & LINUX_O_NDELAY)
104194136Ssam	bsd_open_args.flags |= O_NONBLOCK;
105194136Ssam    if (args->flags & LINUX_O_APPEND)
106194136Ssam	bsd_open_args.flags |= O_APPEND;
107194136Ssam    if (args->flags & LINUX_O_SYNC)
108194136Ssam	bsd_open_args.flags |= O_FSYNC;
109194136Ssam    if (args->flags & LINUX_O_NONBLOCK)
110194136Ssam	bsd_open_args.flags |= O_NONBLOCK;
111194136Ssam    if (args->flags & LINUX_FASYNC)
112194136Ssam	bsd_open_args.flags |= O_ASYNC;
113194136Ssam    if (args->flags & LINUX_O_CREAT)
114194136Ssam	bsd_open_args.flags |= O_CREAT;
115194136Ssam    if (args->flags & LINUX_O_TRUNC)
116194136Ssam	bsd_open_args.flags |= O_TRUNC;
117194136Ssam    if (args->flags & LINUX_O_EXCL)
118194136Ssam	bsd_open_args.flags |= O_EXCL;
119194136Ssam    if (args->flags & LINUX_O_NOCTTY)
120178354Ssam	bsd_open_args.flags |= O_NOCTTY;
121178354Ssam    bsd_open_args.path = args->path;
122187801Ssam    bsd_open_args.mode = args->mode;
123187801Ssam
124173275Ssam    error = open(p, &bsd_open_args);
125173275Ssam    if (!error && !(bsd_open_args.flags & O_NOCTTY) &&
126173275Ssam	SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
127173275Ssam	struct filedesc *fdp = p->p_fd;
128173275Ssam	struct file *fp = fdp->fd_ofiles[p->p_retval[0]];
129173275Ssam
130173275Ssam	if (fp->f_type == DTYPE_VNODE)
131173275Ssam	    fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, p);
132188784Ssam    }
133188784Ssam#ifdef DEBUG
134188784Ssam    printf("Linux-emul(%d): open returns error %d\n",
135188784Ssam	   p->p_pid, error);
136188784Ssam#endif
137188784Ssam    return error;
138188784Ssam}
139188784Ssam
140188784Ssamstruct linux_flock {
141188784Ssam    short l_type;
142188784Ssam    short l_whence;
143188784Ssam    linux_off_t l_start;
144188784Ssam    linux_off_t l_len;
145173275Ssam    linux_pid_t l_pid;
146173275Ssam};
147178354Ssam
148173275Ssamstatic void
149173275Ssamlinux_to_bsd_flock(struct linux_flock *linux_flock, struct flock *bsd_flock)
150173275Ssam{
15177218Sphk    switch (linux_flock->l_type) {
15277218Sphk    case LINUX_F_RDLCK:
15377218Sphk	bsd_flock->l_type = F_RDLCK;
154178354Ssam	break;
155178354Ssam    case LINUX_F_WRLCK:
156178354Ssam	bsd_flock->l_type = F_WRLCK;
157178354Ssam	break;
158178354Ssam    case LINUX_F_UNLCK:
159195618Srpaulo	bsd_flock->l_type = F_UNLCK;
16077218Sphk	break;
161187801Ssam    default:
162178354Ssam        bsd_flock->l_type = -1;
163178354Ssam        break;
164178354Ssam    }
165178354Ssam    bsd_flock->l_whence = linux_flock->l_whence;
166178354Ssam    bsd_flock->l_start = (off_t)linux_flock->l_start;
167178354Ssam    bsd_flock->l_len = (off_t)linux_flock->l_len;
168173275Ssam    bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
169173275Ssam}
170178354Ssam
171173275Ssamstatic void
172173275Ssambsd_to_linux_flock(struct flock *bsd_flock, struct linux_flock *linux_flock)
173170531Ssam{
174173275Ssam    switch (bsd_flock->l_type) {
175173275Ssam    case F_RDLCK:
176173275Ssam	linux_flock->l_type = LINUX_F_RDLCK;
177173275Ssam	break;
178173275Ssam    case F_WRLCK:
179173275Ssam	linux_flock->l_type = LINUX_F_WRLCK;
180173275Ssam	break;
181173275Ssam    case F_UNLCK:
182173275Ssam	linux_flock->l_type = LINUX_F_UNLCK;
183173275Ssam	break;
184170531Ssam    }
185170531Ssam    linux_flock->l_whence = bsd_flock->l_whence;
186170531Ssam    linux_flock->l_start = (linux_off_t)bsd_flock->l_start;
187170531Ssam    linux_flock->l_len = (linux_off_t)bsd_flock->l_len;
188170531Ssam    linux_flock->l_pid = (linux_pid_t)bsd_flock->l_pid;
189170531Ssam}
190170531Ssam
191187801Ssamint
192170531Ssamlinux_fcntl(struct proc *p, struct linux_fcntl_args *args)
193187801Ssam{
194187801Ssam    int error, result;
195187801Ssam    struct fcntl_args /* {
196187801Ssam	int fd;
197187801Ssam	int cmd;
198187801Ssam	int arg;
199170531Ssam    } */ fcntl_args;
200173275Ssam    struct linux_flock linux_flock;
201170531Ssam    struct flock *bsd_flock;
202170531Ssam    caddr_t sg;
203178354Ssam
204178354Ssam    sg = stackgap_init();
205178354Ssam    bsd_flock = (struct flock *)stackgap_alloc(&sg, sizeof(struct flock));
206178354Ssam
207178354Ssam#ifdef DEBUG
208178354Ssam    printf("Linux-emul(%d): fcntl(%d, %08x, *)\n",
209178354Ssam	   p->p_pid, args->fd, args->cmd);
210181198Ssam#endif
211178354Ssam    fcntl_args.fd = args->fd;
212178354Ssam
213178354Ssam    switch (args->cmd) {
214178354Ssam    case LINUX_F_DUPFD:
215170531Ssam	fcntl_args.cmd = F_DUPFD;
216170531Ssam	fcntl_args.arg = args->arg;
217170531Ssam	return fcntl(p, &fcntl_args);
218170531Ssam
219170531Ssam    case LINUX_F_GETFD:
220170531Ssam	fcntl_args.cmd = F_GETFD;
221170531Ssam	return fcntl(p, &fcntl_args);
222138593Ssam
223170531Ssam    case LINUX_F_SETFD:
224170531Ssam	fcntl_args.cmd = F_SETFD;
225187801Ssam	fcntl_args.arg = args->arg;
226170531Ssam	return fcntl(p, &fcntl_args);
227170531Ssam
228170531Ssam    case LINUX_F_GETFL:
229170531Ssam	fcntl_args.cmd = F_GETFL;
230170531Ssam	error = fcntl(p, &fcntl_args);
231187801Ssam	result = p->p_retval[0];
232187801Ssam	p->p_retval[0] = 0;
233187801Ssam	if (result & O_RDONLY) p->p_retval[0] |= LINUX_O_RDONLY;
234170531Ssam	if (result & O_WRONLY) p->p_retval[0] |= LINUX_O_WRONLY;
235170531Ssam	if (result & O_RDWR) p->p_retval[0] |= LINUX_O_RDWR;
236187801Ssam	if (result & O_NDELAY) p->p_retval[0] |= LINUX_O_NONBLOCK;
237187801Ssam	if (result & O_APPEND) p->p_retval[0] |= LINUX_O_APPEND;
238170531Ssam	if (result & O_FSYNC) p->p_retval[0] |= LINUX_O_SYNC;
239170531Ssam	if (result & O_ASYNC) p->p_retval[0] |= LINUX_FASYNC;
240170531Ssam	return error;
241170531Ssam
242170531Ssam    case LINUX_F_SETFL:
243170531Ssam	fcntl_args.arg = 0;
244170531Ssam	if (args->arg & LINUX_O_NDELAY) fcntl_args.arg |= O_NONBLOCK;
245170531Ssam	if (args->arg & LINUX_O_APPEND) fcntl_args.arg |= O_APPEND;
246170531Ssam	if (args->arg & LINUX_O_SYNC) fcntl_args.arg |= O_FSYNC;
247170531Ssam	if (args->arg & LINUX_FASYNC) fcntl_args.arg |= O_ASYNC;
248170531Ssam	fcntl_args.cmd = F_SETFL;
249170531Ssam	return fcntl(p, &fcntl_args);
250170531Ssam
251170531Ssam    case LINUX_F_GETLK:
252170531Ssam	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
253170531Ssam		   	    sizeof(struct linux_flock))))
254170531Ssam	    return error;
255170531Ssam	linux_to_bsd_flock(&linux_flock, bsd_flock);
256170531Ssam	fcntl_args.cmd = F_GETLK;
257170531Ssam	fcntl_args.arg = (int)bsd_flock;
258170531Ssam	error = fcntl(p, &fcntl_args);
259170531Ssam	if (error)
260170531Ssam	    return error;
261170531Ssam	bsd_to_linux_flock(bsd_flock, &linux_flock);
262170531Ssam	return copyout((caddr_t)&linux_flock, (caddr_t)args->arg,
263170531Ssam		       sizeof(struct linux_flock));
264170531Ssam
265170531Ssam    case LINUX_F_SETLK:
266170531Ssam	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
267170531Ssam		   	    sizeof(struct linux_flock))))
268170531Ssam	    return error;
269170531Ssam	linux_to_bsd_flock(&linux_flock, bsd_flock);
270170531Ssam	fcntl_args.cmd = F_SETLK;
271170531Ssam	fcntl_args.arg = (int)bsd_flock;
272170531Ssam	return fcntl(p, &fcntl_args);
273170531Ssam
274170531Ssam    case LINUX_F_SETLKW:
275170531Ssam	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
276170531Ssam		   	    sizeof(struct linux_flock))))
277170531Ssam	    return error;
278170531Ssam	linux_to_bsd_flock(&linux_flock, bsd_flock);
279173275Ssam	fcntl_args.cmd = F_SETLKW;
280170531Ssam	fcntl_args.arg = (int)bsd_flock;
281170531Ssam	return fcntl(p, &fcntl_args);
282173275Ssam
283173275Ssam    case LINUX_F_GETOWN:
284173275Ssam	fcntl_args.cmd = F_GETOWN;
285173275Ssam	return fcntl(p, &fcntl_args);
286173275Ssam
287173275Ssam    case LINUX_F_SETOWN:
288170531Ssam	fcntl_args.cmd = F_SETOWN;
289173275Ssam	fcntl_args.arg = args->arg;
290170531Ssam	return fcntl(p, &fcntl_args);
291170531Ssam    }
292173275Ssam    return EINVAL;
293173275Ssam}
294173275Ssam
295173275Ssamint
296173275Ssamlinux_lseek(struct proc *p, struct linux_lseek_args *args)
297173275Ssam{
298170531Ssam
299170531Ssam    struct lseek_args /* {
300170531Ssam	int fd;
301170531Ssam	int pad;
302170531Ssam	off_t offset;
303170531Ssam	int whence;
304170531Ssam    } */ tmp_args;
305170531Ssam    int error;
306170531Ssam
307187801Ssam#ifdef DEBUG
308187801Ssam    printf("Linux-emul(%ld): lseek(%d, %ld, %d)\n",
309170531Ssam	   (long)p->p_pid, args->fdes, args->off, args->whence);
310170531Ssam#endif
311170531Ssam    tmp_args.fd = args->fdes;
312170531Ssam    tmp_args.offset = (off_t)args->off;
313187801Ssam    tmp_args.whence = args->whence;
314170531Ssam    error = lseek(p, &tmp_args);
315170531Ssam    return error;
316170531Ssam}
317170531Ssam
318170531Ssamint
319170531Ssamlinux_llseek(struct proc *p, struct linux_llseek_args *args)
320170531Ssam{
321170531Ssam	struct lseek_args bsd_args;
322170531Ssam	int error;
323170531Ssam	off_t off;
324170531Ssam
325170531Ssam#ifdef DEBUG
326170531Ssam        printf("Linux-emul(%d): llseek(%d, %d:%d, %d)\n",
327187801Ssam	   p->p_pid, args->fd, args->ohigh, args->olow, args->whence);
328187801Ssam#endif
329170531Ssam	off = (args->olow) | (((off_t) args->ohigh) << 32);
330170531Ssam
331170531Ssam	bsd_args.fd = args->fd;
332170531Ssam	bsd_args.offset = off;
333187801Ssam	bsd_args.whence = args->whence;
334170531Ssam
335170531Ssam	if ((error = lseek(p, &bsd_args)))
336170531Ssam		return error;
337170531Ssam
338170531Ssam	if ((error = copyout(p->p_retval, (caddr_t)args->res, sizeof (off_t))))
339173275Ssam		return error;
340170531Ssam
341170531Ssam	p->p_retval[0] = 0;
342173275Ssam	return 0;
343173275Ssam}
344173275Ssam
345173275Ssam
346173275Ssamstruct linux_dirent {
347173275Ssam    long dino;
348173275Ssam    linux_off_t doff;
349173275Ssam    unsigned short dreclen;
350173275Ssam    char dname[LINUX_NAME_MAX + 1];
351187801Ssam};
352173275Ssam
353173275Ssam#define LINUX_RECLEN(de,namlen) \
354173275Ssam    ALIGN((((char *)&(de)->dname - (char *)de) + (namlen) + 1))
355173275Ssam
356173275Ssamint
357173275Ssamlinux_readdir(struct proc *p, struct linux_readdir_args *args)
358173275Ssam{
359178354Ssam	struct linux_getdents_args lda;
360178354Ssam
361178354Ssam	lda.fd = args->fd;
362178354Ssam	lda.dent = args->dent;
363178354Ssam	lda.count = 1;
364178354Ssam	return linux_getdents(p, &lda);
365178354Ssam}
366178354Ssam
367178354Ssamint
368178354Ssamlinux_getdents(struct proc *p, struct linux_getdents_args *args)
369178354Ssam{
370178354Ssam    register struct dirent *bdp;
371178354Ssam    struct vnode *vp;
372178354Ssam    caddr_t inp, buf;		/* BSD-format */
373178354Ssam    int len, reclen;		/* BSD-format */
374188784Ssam    caddr_t outp;		/* Linux-format */
375188784Ssam    int resid, linuxreclen=0;	/* Linux-format */
376188784Ssam    struct file *fp;
377188784Ssam    struct uio auio;
378178354Ssam    struct iovec aiov;
379178354Ssam    struct vattr va;
380178354Ssam    off_t off;
381178354Ssam    struct linux_dirent linux_dirent;
382178354Ssam    int buflen, error, eofflag, nbytes, justone;
383178354Ssam    u_long *cookies = NULL, *cookiep;
384178354Ssam    int ncookies;
385178354Ssam
386178354Ssam#ifdef DEBUG
387178354Ssam    printf("Linux-emul(%d): getdents(%d, *, %d)\n",
388178354Ssam	   p->p_pid, args->fd, args->count);
389178354Ssam#endif
390178354Ssam    if ((error = getvnode(p->p_fd, args->fd, &fp)) != 0) {
391178354Ssam	return (error);
392178354Ssam    }
393178354Ssam
394187801Ssam    if ((fp->f_flag & FREAD) == 0)
395178354Ssam	return (EBADF);
396178354Ssam
397178354Ssam    vp = (struct vnode *) fp->f_data;
398178354Ssam
399178354Ssam    if (vp->v_type != VDIR)
400178354Ssam	return (EINVAL);
401178354Ssam
402178354Ssam    if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p))) {
403178354Ssam	return error;
404178354Ssam    }
405178354Ssam
406178354Ssam    nbytes = args->count;
407178354Ssam    if (nbytes == 1) {
408178354Ssam	nbytes = sizeof (struct linux_dirent);
409178354Ssam	justone = 1;
410178354Ssam    }
411178354Ssam    else
412187801Ssam	justone = 0;
413178354Ssam
414178354Ssam    off = fp->f_offset;
415178354Ssam#define	DIRBLKSIZ	512		/* XXX we used to use ufs's DIRBLKSIZ */
416178354Ssam    buflen = max(DIRBLKSIZ, nbytes);
417178354Ssam    buflen = min(buflen, MAXBSIZE);
418178354Ssam    buf = malloc(buflen, M_TEMP, M_WAITOK);
419178354Ssam    vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
420178354Ssamagain:
421178354Ssam    aiov.iov_base = buf;
422178354Ssam    aiov.iov_len = buflen;
423178354Ssam    auio.uio_iov = &aiov;
424178354Ssam    auio.uio_iovcnt = 1;
425178354Ssam    auio.uio_rw = UIO_READ;
426178354Ssam    auio.uio_segflg = UIO_SYSSPACE;
427178354Ssam    auio.uio_procp = p;
428178354Ssam    auio.uio_resid = buflen;
429178354Ssam    auio.uio_offset = off;
430187801Ssam
431178354Ssam    if (cookies) {
432178354Ssam	free(cookies, M_TEMP);
433178354Ssam	cookies = NULL;
434178354Ssam    }
435178354Ssam
436178354Ssam    error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, &cookies);
437187801Ssam    if (error) {
438187801Ssam	goto out;
439187801Ssam    }
440178354Ssam
441178354Ssam    inp = buf;
442178354Ssam    outp = (caddr_t) args->dent;
443178354Ssam    resid = nbytes;
444178354Ssam    if ((len = buflen - auio.uio_resid) <= 0) {
445187801Ssam	goto eof;
446178354Ssam    }
447187801Ssam
448178354Ssam    cookiep = cookies;
449178354Ssam
450186102Ssam    if (cookies) {
451178354Ssam	/*
452178354Ssam	 * When using cookies, the vfs has the option of reading from
453178354Ssam	 * a different offset than that supplied (UFS truncates the
454178354Ssam	 * offset to a block boundary to make sure that it never reads
455178354Ssam	 * partway through a directory entry, even if the directory
456178354Ssam	 * has been compacted).
457178354Ssam	 */
458178354Ssam	while (len > 0 && ncookies > 0 && *cookiep <= off) {
459178354Ssam	    bdp = (struct dirent *) inp;
460178354Ssam	    len -= bdp->d_reclen;
461178354Ssam	    inp += bdp->d_reclen;
462178354Ssam	    cookiep++;
463178354Ssam	    ncookies--;
464178354Ssam	}
465178354Ssam    }
466178354Ssam
467178354Ssam    while (len > 0) {
468178354Ssam	if (cookiep && ncookies == 0)
469178354Ssam	    break;
470178354Ssam	bdp = (struct dirent *) inp;
471178354Ssam	reclen = bdp->d_reclen;
472178354Ssam	if (reclen & 3) {
473178354Ssam	    printf("linux_readdir: reclen=%d\n", reclen);
474178354Ssam	    error = EFAULT;
475178354Ssam	    goto out;
476178354Ssam	}
477178354Ssam
478178354Ssam	if (bdp->d_fileno == 0) {
479178354Ssam	    inp += reclen;
480178354Ssam	    if (cookiep) {
481186102Ssam		off = *cookiep++;
482178354Ssam		ncookies--;
483178354Ssam	    } else
484178354Ssam		off += reclen;
485178354Ssam	    len -= reclen;
486178354Ssam	    continue;
487178354Ssam	}
488178354Ssam	linuxreclen = LINUX_RECLEN(&linux_dirent, bdp->d_namlen);
489178354Ssam	if (reclen > len || resid < linuxreclen) {
490178354Ssam	    outp++;
491178354Ssam	    break;
492178354Ssam	}
493187801Ssam	linux_dirent.dino = (long) bdp->d_fileno;
494187801Ssam	if (justone) {
495187801Ssam	    /*
496187801Ssam	     * old linux-style readdir usage.
497187801Ssam	     */
498178354Ssam	    linux_dirent.doff = (linux_off_t) linuxreclen;
499178354Ssam	    linux_dirent.dreclen = (u_short) bdp->d_namlen;
500187801Ssam	} else {
501187801Ssam	    linux_dirent.doff = (linux_off_t)(off + reclen);
502187801Ssam	    linux_dirent.dreclen = (u_short) linuxreclen;
503187801Ssam	}
504187801Ssam	strcpy(linux_dirent.dname, bdp->d_name);
505187801Ssam	if ((error = copyout((caddr_t)&linux_dirent, outp, linuxreclen))) {
506178354Ssam	    goto out;
507178354Ssam	}
508187801Ssam	inp += reclen;
509187801Ssam	if (cookiep) {
510187801Ssam	    off = *cookiep++;
511187801Ssam	    ncookies--;
512187801Ssam	} else
513178354Ssam	    off += reclen;
514178354Ssam	outp += linuxreclen;
515178354Ssam	resid -= linuxreclen;
516178354Ssam	len -= reclen;
517187801Ssam	if (justone)
518187801Ssam	    break;
519187801Ssam    }
520187801Ssam
521187801Ssam    if (outp == (caddr_t) args->dent)
522187801Ssam	goto again;
523187801Ssam    fp->f_offset = off;
524187801Ssam
525187801Ssam    if (justone)
526178354Ssam	nbytes = resid + linuxreclen;
527187801Ssam
528178354Ssameof:
529187801Ssam    p->p_retval[0] = nbytes - resid;
530187801Ssamout:
531187801Ssam    if (cookies)
532187801Ssam	free(cookies, M_TEMP);
533178354Ssam    VOP_UNLOCK(vp, 0, p);
534178354Ssam    free(buf, M_TEMP);
535170531Ssam    return error;
536170531Ssam}
537170531Ssam
538170531Ssam/*
539170531Ssam * These exist mainly for hooks for doing /compat/linux translation.
540170531Ssam */
541170531Ssam
542170531Ssamint
543170531Ssamlinux_access(struct proc *p, struct linux_access_args *args)
544138593Ssam{
545138593Ssam	struct access_args bsd;
546173275Ssam	caddr_t sg;
547173275Ssam
548138593Ssam	sg = stackgap_init();
549138593Ssam	CHECKALTEXIST(p, &sg, args->path);
550138593Ssam
55177218Sphk#ifdef DEBUG
55277218Sphk        printf("Linux-emul(%d): access(%s, %d)\n",
55377218Sphk	    p->p_pid, args->path, args->flags);
55477218Sphk#endif
555151883Sbrooks	bsd.path = args->path;
55677218Sphk	bsd.flags = args->flags;
55777218Sphk
558121827Sbrooks	return access(p, &bsd);
559178354Ssam}
56088748Sambrisko
56188748Sambriskoint
56288748Sambriskolinux_unlink(struct proc *p, struct linux_unlink_args *args)
56377218Sphk{
56477218Sphk	struct unlink_args bsd;
56577218Sphk	caddr_t sg;
566151883Sbrooks
567151883Sbrooks	sg = stackgap_init();
56877218Sphk	CHECKALTEXIST(p, &sg, args->path);
56977218Sphk
57077218Sphk#ifdef DEBUG
57177218Sphk	printf("Linux-emul(%d): unlink(%s)\n",
572138593Ssam	   p->p_pid, args->path);
573195618Srpaulo#endif
574195618Srpaulo	bsd.path = args->path;
575195618Srpaulo
576195618Srpaulo	return unlink(p, &bsd);
577195618Srpaulo}
578195618Srpaulo
579195618Srpauloint
580195618Srpaulolinux_chdir(struct proc *p, struct linux_chdir_args *args)
581195618Srpaulo{
582195618Srpaulo	struct chdir_args bsd;
583195618Srpaulo	caddr_t sg;
584195618Srpaulo
585195618Srpaulo	sg = stackgap_init();
586195618Srpaulo	CHECKALTEXIST(p, &sg, args->path);
58777218Sphk
58877218Sphk#ifdef DEBUG
58977218Sphk	printf("Linux-emul(%d): chdir(%s)\n",
59077218Sphk	   p->p_pid, args->path);
59177218Sphk#endif
59277218Sphk	bsd.path = args->path;
59377218Sphk
59477218Sphk	return chdir(p, &bsd);
59577218Sphk}
59677218Sphk
59777218Sphkint
59877218Sphklinux_chmod(struct proc *p, struct linux_chmod_args *args)
599138593Ssam{
600170531Ssam	struct chmod_args bsd;
601170531Ssam	caddr_t sg;
602170531Ssam
603170531Ssam	sg = stackgap_init();
604170531Ssam	CHECKALTEXIST(p, &sg, args->path);
605170531Ssam
606170531Ssam#ifdef DEBUG
607170531Ssam        printf("Linux-emul(%d): chmod(%s, %d)\n",
608170531Ssam	    p->p_pid, args->path, args->mode);
609170531Ssam#endif
610170531Ssam	bsd.path = args->path;
611170531Ssam	bsd.mode = args->mode;
612173275Ssam
613138593Ssam	return chmod(p, &bsd);
614170531Ssam}
615170531Ssam
616170531Ssamint
617138593Ssamlinux_chown(struct proc *p, struct linux_chown_args *args)
618170531Ssam{
619166015Ssam	struct chown_args bsd;
620170531Ssam	caddr_t sg;
621170531Ssam
622170531Ssam	sg = stackgap_init();
623170531Ssam	CHECKALTEXIST(p, &sg, args->path);
624170531Ssam
625170531Ssam#ifdef DEBUG
626170531Ssam        printf("Linux-emul(%d): chown(%s, %d, %d)\n",
627170531Ssam	    p->p_pid, args->path, args->uid, args->gid);
628170531Ssam#endif
629170531Ssam	bsd.path = args->path;
630170531Ssam	/* XXX size casts here */
631170531Ssam	bsd.uid = args->uid;
632170531Ssam	bsd.gid = args->gid;
633170531Ssam
634170531Ssam	return chown(p, &bsd);
635170531Ssam}
636170531Ssam
637170531Ssamint
638170531Ssamlinux_lchown(struct proc *p, struct linux_lchown_args *args)
639170531Ssam{
640170531Ssam	struct lchown_args bsd;
641170531Ssam	caddr_t sg;
642170531Ssam
643170531Ssam	sg = stackgap_init();
644170531Ssam	CHECKALTEXIST(p, &sg, args->path);
645170531Ssam
646170531Ssam#ifdef DEBUG
647170531Ssam        printf("Linux-emul(%d): lchown(%s, %d, %d)\n",
648170531Ssam	    p->p_pid, args->path, args->uid, args->gid);
649170531Ssam#endif
650170531Ssam	bsd.path = args->path;
651170531Ssam	/* XXX size casts here */
652170531Ssam	bsd.uid = args->uid;
653173275Ssam	bsd.gid = args->gid;
654170531Ssam
655170531Ssam	return lchown(p, &bsd);
656170531Ssam}
657170531Ssam
658170531Ssamint
659170531Ssamlinux_mkdir(struct proc *p, struct linux_mkdir_args *args)
660170531Ssam{
661170531Ssam	struct mkdir_args bsd;
662166015Ssam	caddr_t sg;
663170531Ssam
664170531Ssam	sg = stackgap_init();
665170531Ssam	CHECKALTCREAT(p, &sg, args->path);
666170531Ssam
667170531Ssam#ifdef DEBUG
668170531Ssam        printf("Linux-emul(%d): mkdir(%s, %d)\n",
669170531Ssam	    p->p_pid, args->path, args->mode);
670170531Ssam#endif
671170531Ssam	bsd.path = args->path;
672170531Ssam	bsd.mode = args->mode;
673170531Ssam
674170531Ssam	return mkdir(p, &bsd);
675170531Ssam}
676170531Ssam
677170531Ssamint
678170531Ssamlinux_rmdir(struct proc *p, struct linux_rmdir_args *args)
679170531Ssam{
680170531Ssam	struct rmdir_args bsd;
681173275Ssam	caddr_t sg;
682170531Ssam
683165570Ssam	sg = stackgap_init();
684170531Ssam	CHECKALTEXIST(p, &sg, args->path);
685170531Ssam
686170531Ssam#ifdef DEBUG
687170531Ssam        printf("Linux-emul(%d): rmdir(%s)\n",
688170531Ssam	    p->p_pid, args->path);
689170531Ssam#endif
690170531Ssam	bsd.path = args->path;
691170531Ssam
692170531Ssam	return rmdir(p, &bsd);
693170531Ssam}
694170531Ssam
695170531Ssamint
696170531Ssamlinux_rename(struct proc *p, struct linux_rename_args *args)
697170531Ssam{
698170531Ssam	struct rename_args bsd;
699170531Ssam	caddr_t sg;
700170531Ssam
701170531Ssam	sg = stackgap_init();
702170531Ssam	CHECKALTEXIST(p, &sg, args->from);
703173275Ssam	CHECKALTCREAT(p, &sg, args->to);
704173275Ssam
705173275Ssam#ifdef DEBUG
706173275Ssam        printf("Linux-emul(%d): rename(%s, %s)\n",
707173275Ssam	    p->p_pid, args->from, args->to);
708173275Ssam#endif
709173275Ssam	bsd.from = args->from;
710173275Ssam	bsd.to = args->to;
711173275Ssam
712173275Ssam	return rename(p, &bsd);
713173275Ssam}
714173275Ssam
715170531Ssamint
716170531Ssamlinux_symlink(struct proc *p, struct linux_symlink_args *args)
717170531Ssam{
718138593Ssam	struct symlink_args bsd;
719138593Ssam	caddr_t sg;
720138593Ssam
721186105Ssam	sg = stackgap_init();
722186105Ssam	CHECKALTEXIST(p, &sg, args->path);
723186105Ssam	CHECKALTCREAT(p, &sg, args->to);
724186105Ssam
725186105Ssam#ifdef DEBUG
726186105Ssam        printf("Linux-emul(%d): symlink(%s, %s)\n",
727186105Ssam	    p->p_pid, args->path, args->to);
728186105Ssam#endif
729186105Ssam	bsd.path = args->path;
730186105Ssam	bsd.link = args->to;
731186105Ssam
732186105Ssam	return symlink(p, &bsd);
733186105Ssam}
734186105Ssam
735186105Ssamint
736186105Ssamlinux_execve(struct proc *p, struct linux_execve_args *args)
737186105Ssam{
738186105Ssam	struct execve_args bsd;
739186105Ssam	caddr_t sg;
740186105Ssam
741186105Ssam	sg = stackgap_init();
742186105Ssam	CHECKALTEXIST(p, &sg, args->path);
743186105Ssam
744186105Ssam#ifdef DEBUG
745186105Ssam        printf("Linux-emul(%d): execve(%s)\n",
746186105Ssam	    p->p_pid, args->path);
747186105Ssam#endif
74877218Sphk	bsd.fname = args->path;
74977218Sphk	bsd.argv = args->argp;
750170531Ssam	bsd.envv = args->envp;
751170531Ssam
752186105Ssam	return execve(p, &bsd);
753170531Ssam}
75477218Sphk
75577218Sphkint
756138593Ssamlinux_readlink(struct proc *p, struct linux_readlink_args *args)
757178354Ssam{
758178354Ssam	struct readlink_args bsd;
759178354Ssam	caddr_t sg;
760178354Ssam
761186105Ssam	sg = stackgap_init();
762178354Ssam	CHECKALTEXIST(p, &sg, args->name);
763178354Ssam
764178354Ssam#ifdef DEBUG
765178354Ssam        printf("Linux-emul(%ld): readlink(%s, %p, %d)\n",
766178354Ssam	    (long)p->p_pid, args->name, (void *)args->buf, args->count);
767178354Ssam#endif
76877218Sphk	bsd.path = args->name;
76977218Sphk	bsd.buf = args->buf;
77077218Sphk	bsd.count = args->count;
77177218Sphk
77291454Sbrooks	return readlink(p, &bsd);
77377218Sphk}
77491454Sbrooks
77577218Sphkint
77691454Sbrookslinux_truncate(struct proc *p, struct linux_truncate_args *args)
77777218Sphk{
778138593Ssam	struct truncate_args bsd;
779138593Ssam	caddr_t sg;
780138593Ssam
781138593Ssam	sg = stackgap_init();
78277218Sphk	CHECKALTEXIST(p, &sg, args->path);
783150708Sru
78477218Sphk#ifdef DEBUG
78577218Sphk        printf("Linux-emul(%d): truncate(%s, %ld)\n",
78677218Sphk	    p->p_pid, args->path, args->length);
78777218Sphk#endif
78877218Sphk	bsd.path = args->path;
789138593Ssam	bsd.length = args->length;
79077218Sphk
79177218Sphk	return truncate(p, &bsd);
79277218Sphk}
79377218Sphk
79491454Sbrooksint
79577218Sphklinux_link(struct proc *p, struct linux_link_args *args)
79691454Sbrooks{
79777218Sphk    struct link_args bsd;
79891454Sbrooks    caddr_t sg;
79977218Sphk
80091454Sbrooks    sg = stackgap_init();
80177218Sphk    CHECKALTEXIST(p, &sg, args->path);
80291454Sbrooks    CHECKALTCREAT(p, &sg, args->to);
80377218Sphk
80477218Sphk#ifdef DEBUG
805150708Sru    printf("Linux-emul(%d): link(%s, %s)\n", p->p_pid, args->path, args->to);
80677218Sphk#endif
80777218Sphk
80877218Sphk    bsd.path = args->path;
80977218Sphk    bsd.link = args->to;
81077218Sphk
811138593Ssam    return link(p, &bsd);
81277218Sphk}
81377218Sphk
81477218Sphkint
81577218Sphklinux_getcwd(struct proc *p, struct linux_getcwd_args *args)
81677218Sphk{
81777218Sphk	struct __getcwd_args bsd;
81877218Sphk	caddr_t sg;
81977218Sphk	int error, len;
82077218Sphk
82177218Sphk#ifdef DEBUG
822138593Ssam	printf("Linux-emul(%ld): getcwd(%p, %ld)\n", (long)p->p_pid,
82377218Sphk	       args->buf, args->bufsize);
82477218Sphk#endif
82577218Sphk
82677218Sphk	sg = stackgap_init();
82777218Sphk	bsd.buf = stackgap_alloc(&sg, SPARE_USRSPACE);
828138593Ssam	bsd.buflen = SPARE_USRSPACE;
82977218Sphk	error = __getcwd(p, &bsd);
83077218Sphk	if (!error) {
83177218Sphk		len = strlen(bsd.buf) + 1;
83277218Sphk		if (len <= args->bufsize) {
83391454Sbrooks			p->p_retval[0] = len;
83477218Sphk			error = copyout(bsd.buf, args->buf, len);
83591454Sbrooks		}
83677218Sphk		else
83791454Sbrooks			error = ERANGE;
83877218Sphk	}
83977218Sphk	return (error);
840150708Sru}
84177218Sphk
84277218Sphkint
84377218Sphklinux_fdatasync(p, uap)
84477218Sphk	struct proc *p;
84577218Sphk	struct linux_fdatasync_args *uap;
846138593Ssam{
84777218Sphk	struct fsync_args bsd;
84877218Sphk
84977218Sphk	bsd.fd = uap->fd;
85077218Sphk	return fsync(p, &bsd);
85177218Sphk}
852139493Ssam
853139493Ssamint
854139493Ssamlinux_pread(p, uap)
855139493Ssam	struct proc *p;
856139493Ssam	struct linux_pread_args *uap;
857139493Ssam{
858138593Ssam	struct pread_args bsd;
85977218Sphk
86077218Sphk	bsd.fd = uap->fd;
861139493Ssam	bsd.buf = uap->buf;
862139493Ssam	bsd.nbyte = uap->nbyte;
863139493Ssam	bsd.offset = uap->offset;
864139493Ssam	return pread(p, &bsd);
86577218Sphk}
86677218Sphk
867138593Ssamint
86877218Sphklinux_pwrite(p, uap)
86977218Sphk	struct proc *p;
87077218Sphk	struct linux_pwrite_args *uap;
87177218Sphk{
872120178Ssam	struct pwrite_args bsd;
87377218Sphk
874178354Ssam	bsd.fd = uap->fd;
87577218Sphk	bsd.buf = uap->buf;
87677218Sphk	bsd.nbyte = uap->nbyte;
87777218Sphk	bsd.offset = uap->offset;
87877218Sphk	return pwrite(p, &bsd);
87977218Sphk}
88077218Sphk