linux_file.c revision 51348
140516Swpaul/*-
2119868Swpaul * Copyright (c) 1994-1995 S�ren Schmidt
340516Swpaul * All rights reserved.
440516Swpaul *
540516Swpaul * Redistribution and use in source and binary forms, with or without
640516Swpaul * modification, are permitted provided that the following conditions
740516Swpaul * are met:
840516Swpaul * 1. Redistributions of source code must retain the above copyright
940516Swpaul *    notice, this list of conditions and the following disclaimer
1040516Swpaul *    in this position and unchanged.
1140516Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1240516Swpaul *    notice, this list of conditions and the following disclaimer in the
1340516Swpaul *    documentation and/or other materials provided with the distribution.
1440516Swpaul * 3. The name of the author may not be used to endorse or promote products
1540516Swpaul *    derived from this software withough specific prior written permission
1640516Swpaul *
1740516Swpaul * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1840516Swpaul * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1940516Swpaul * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2040516Swpaul * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2140516Swpaul * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2240516Swpaul * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2340516Swpaul * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2440516Swpaul * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2540516Swpaul * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2640516Swpaul * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2740516Swpaul *
2840516Swpaul * $FreeBSD: head/sys/compat/linux/linux_file.c 51348 1999-09-17 08:35:08Z marcel $
2940516Swpaul */
3040516Swpaul
3140516Swpaul#include "opt_compat.h"
3240516Swpaul
33122678Sobrien#include <sys/param.h>
34122678Sobrien#include <sys/systm.h>
35122678Sobrien#include <sys/sysproto.h>
3640516Swpaul#include <sys/fcntl.h>
37119868Swpaul#include <sys/file.h>
3840516Swpaul#include <sys/filedesc.h>
39119868Swpaul#include <sys/lock.h>
40119868Swpaul#include <sys/proc.h>
4140516Swpaul#include <sys/vnode.h>
4240516Swpaul#include <sys/malloc.h>
43119868Swpaul#include <sys/dirent.h>
44119868Swpaul#include <sys/conf.h>
45119868Swpaul#include <sys/tty.h>
4640516Swpaul
4740516Swpaul#include <i386/linux/linux.h>
4840516Swpaul#include <i386/linux/linux_proto.h>
4940516Swpaul#include <i386/linux/linux_util.h>
5040516Swpaul
5140516Swpaulint
5240516Swpaullinux_creat(struct proc *p, struct linux_creat_args *args)
5340516Swpaul{
5440516Swpaul    struct open_args /* {
5540516Swpaul	char *path;
5641569Swpaul	int flags;
5740516Swpaul	int mode;
5840516Swpaul    } */ bsd_open_args;
5940516Swpaul    caddr_t sg;
6040516Swpaul
6140516Swpaul    sg = stackgap_init();
6240516Swpaul    CHECKALTCREAT(p, &sg, args->path);
6340516Swpaul
6440516Swpaul#ifdef DEBUG
6540516Swpaul    printf("Linux-emul(%d): creat(%s, %d)\n",
6640516Swpaul	   p->p_pid, args->path, args->mode);
6740516Swpaul#endif
6840516Swpaul    bsd_open_args.path = args->path;
6940516Swpaul    bsd_open_args.mode = args->mode;
7040516Swpaul    bsd_open_args.flags = O_WRONLY | O_CREAT | O_TRUNC;
7140516Swpaul    return open(p, &bsd_open_args);
7240516Swpaul}
7340516Swpaul
7440516Swpaulint
7540516Swpaullinux_open(struct proc *p, struct linux_open_args *args)
7640516Swpaul{
7740516Swpaul    struct open_args /* {
7840516Swpaul	char *path;
7940516Swpaul	int flags;
8040516Swpaul	int mode;
8140516Swpaul    } */ bsd_open_args;
8240516Swpaul    int error;
8340516Swpaul    caddr_t sg;
8440516Swpaul
8540516Swpaul    sg = stackgap_init();
8640516Swpaul
87108729Sjake    if (args->flags & LINUX_O_CREAT)
8840516Swpaul	CHECKALTCREAT(p, &sg, args->path);
8940516Swpaul    else
9040516Swpaul	CHECKALTEXIST(p, &sg, args->path);
9140516Swpaul
9240516Swpaul#ifdef DEBUG
9340516Swpaul    printf("Linux-emul(%d): open(%s, 0x%x, 0x%x)\n",
9440516Swpaul	   p->p_pid, args->path, args->flags, args->mode);
9540516Swpaul#endif
9640516Swpaul    bsd_open_args.flags = 0;
9740516Swpaul    if (args->flags & LINUX_O_RDONLY)
9840516Swpaul	bsd_open_args.flags |= O_RDONLY;
9940516Swpaul    if (args->flags & LINUX_O_WRONLY)
10040516Swpaul	bsd_open_args.flags |= O_WRONLY;
10140516Swpaul    if (args->flags & LINUX_O_RDWR)
10240516Swpaul	bsd_open_args.flags |= O_RDWR;
10341569Swpaul    if (args->flags & LINUX_O_NDELAY)
10441569Swpaul	bsd_open_args.flags |= O_NONBLOCK;
10541569Swpaul    if (args->flags & LINUX_O_APPEND)
10650703Swpaul	bsd_open_args.flags |= O_APPEND;
10750703Swpaul    if (args->flags & LINUX_O_SYNC)
10850703Swpaul	bsd_open_args.flags |= O_FSYNC;
10940516Swpaul    if (args->flags & LINUX_O_NONBLOCK)
11050703Swpaul	bsd_open_args.flags |= O_NONBLOCK;
11150703Swpaul    if (args->flags & LINUX_FASYNC)
11250703Swpaul	bsd_open_args.flags |= O_ASYNC;
113119871Swpaul    if (args->flags & LINUX_O_CREAT)
114119871Swpaul	bsd_open_args.flags |= O_CREAT;
11540516Swpaul    if (args->flags & LINUX_O_TRUNC)
116113506Smdodd	bsd_open_args.flags |= O_TRUNC;
117113506Smdodd    if (args->flags & LINUX_O_EXCL)
11859758Speter	bsd_open_args.flags |= O_EXCL;
11959758Speter    if (args->flags & LINUX_O_NOCTTY)
12051089Speter	bsd_open_args.flags |= O_NOCTTY;
12150703Swpaul    bsd_open_args.path = args->path;
12250703Swpaul    bsd_open_args.mode = args->mode;
12340516Swpaul
12440516Swpaul    error = open(p, &bsd_open_args);
12540516Swpaul    if (!error && !(bsd_open_args.flags & O_NOCTTY) &&
12640516Swpaul	SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
12740516Swpaul	struct filedesc *fdp = p->p_fd;
12840516Swpaul	struct file *fp = fdp->fd_ofiles[p->p_retval[0]];
12940516Swpaul
13040516Swpaul	if (fp->f_type == DTYPE_VNODE)
13140516Swpaul	    (fp->f_ops->fo_ioctl)(fp, TIOCSCTTY, (caddr_t) 0, p);
13240516Swpaul    }
13340516Swpaul#ifdef DEBUG
13440516Swpaul    printf("Linux-emul(%d): open returns error %d\n",
13540516Swpaul	   p->p_pid, error);
13640516Swpaul#endif
13740516Swpaul    return error;
13840516Swpaul}
139117388Swpaul
14040516Swpaulstruct linux_flock {
141117388Swpaul    short l_type;
14240516Swpaul    short l_whence;
143117388Swpaul    linux_off_t l_start;
14467771Swpaul    linux_off_t l_len;
145118978Swpaul    linux_pid_t l_pid;
146118978Swpaul};
147117388Swpaul
14841243Swpaulstatic void
149117388Swpaullinux_to_bsd_flock(struct linux_flock *linux_flock, struct flock *bsd_flock)
15044238Swpaul{
151117388Swpaul    switch (linux_flock->l_type) {
15244238Swpaul    case LINUX_F_RDLCK:
153117388Swpaul	bsd_flock->l_type = F_RDLCK;
15472813Swpaul	break;
155117388Swpaul    case LINUX_F_WRLCK:
15696112Sjhb	bsd_flock->l_type = F_WRLCK;
157117388Swpaul	break;
15894400Swpaul    case LINUX_F_UNLCK:
159117388Swpaul	bsd_flock->l_type = F_UNLCK;
160103020Siwasaki	break;
161117388Swpaul    default:
162109095Ssanpei        bsd_flock->l_type = -1;
163117388Swpaul        break;
164111381Sdan    }
165117388Swpaul    bsd_flock->l_whence = linux_flock->l_whence;
166112379Ssanpei    bsd_flock->l_start = (off_t)linux_flock->l_start;
167117388Swpaul    bsd_flock->l_len = (off_t)linux_flock->l_len;
168117388Swpaul    bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
169117388Swpaul}
170117388Swpaul
171117388Swpaulstatic void
172117388Swpaulbsd_to_linux_flock(struct flock *bsd_flock, struct linux_flock *linux_flock)
173123740Speter{
17440516Swpaul    switch (bsd_flock->l_type) {
17540516Swpaul    case F_RDLCK:
17692739Salfred	linux_flock->l_type = LINUX_F_RDLCK;
17792739Salfred	break;
17892739Salfred    case F_WRLCK:
17940516Swpaul	linux_flock->l_type = LINUX_F_WRLCK;
180119868Swpaul	break;
18140516Swpaul    case F_UNLCK:
18292739Salfred	linux_flock->l_type = LINUX_F_UNLCK;
18392739Salfred	break;
18492739Salfred    }
18592739Salfred    linux_flock->l_whence = bsd_flock->l_whence;
18692739Salfred    linux_flock->l_start = (linux_off_t)bsd_flock->l_start;
18792739Salfred    linux_flock->l_len = (linux_off_t)bsd_flock->l_len;
18892739Salfred    linux_flock->l_pid = (linux_pid_t)bsd_flock->l_pid;
18992739Salfred}
19092739Salfred
19192739Salfredint
19292739Salfredlinux_fcntl(struct proc *p, struct linux_fcntl_args *args)
19392739Salfred{
19492739Salfred    int error, result;
19592739Salfred    struct fcntl_args /* {
19640516Swpaul	int fd;
19792739Salfred	int cmd;
19892739Salfred	int arg;
19992739Salfred    } */ fcntl_args;
20092739Salfred    struct linux_flock linux_flock;
20192739Salfred    struct flock *bsd_flock;
20292739Salfred    struct filedesc *fdp;
20392739Salfred    struct file *fp;
20440516Swpaul    struct vnode *vp;
20592739Salfred    long pgid;
20692739Salfred    struct pgrp *pgrp;
20792739Salfred    struct tty *tp, *(*d_tty) __P((dev_t));
20840516Swpaul    caddr_t sg;
209123289Sobrien    dev_t dev;
21092739Salfred
21192739Salfred    sg = stackgap_init();
21292739Salfred    bsd_flock = (struct flock *)stackgap_alloc(&sg, sizeof(struct flock));
21340516Swpaul    d_tty = NULL;
21492739Salfred
21592739Salfred#ifdef DEBUG
21681713Swpaul    printf("Linux-emul(%d): fcntl(%d, %08x, *)\n",
21750703Swpaul	   p->p_pid, args->fd, args->cmd);
21850703Swpaul#endif
21950703Swpaul    fcntl_args.fd = args->fd;
22050703Swpaul
22150703Swpaul    switch (args->cmd) {
22250703Swpaul    case LINUX_F_DUPFD:
22350703Swpaul	fcntl_args.cmd = F_DUPFD;
22450703Swpaul	fcntl_args.arg = args->arg;
22550703Swpaul	return fcntl(p, &fcntl_args);
22650703Swpaul
22750703Swpaul    case LINUX_F_GETFD:
22850703Swpaul	fcntl_args.cmd = F_GETFD;
22950703Swpaul	return fcntl(p, &fcntl_args);
23086822Siwasaki
23186822Siwasaki    case LINUX_F_SETFD:
23250703Swpaul	fcntl_args.cmd = F_SETFD;
23350703Swpaul	fcntl_args.arg = args->arg;
23450703Swpaul	return fcntl(p, &fcntl_args);
23550703Swpaul
23650703Swpaul    case LINUX_F_GETFL:
23750703Swpaul	fcntl_args.cmd = F_GETFL;
23850703Swpaul	error = fcntl(p, &fcntl_args);
23950703Swpaul	result = p->p_retval[0];
24050703Swpaul	p->p_retval[0] = 0;
24150703Swpaul	if (result & O_RDONLY) p->p_retval[0] |= LINUX_O_RDONLY;
24250703Swpaul	if (result & O_WRONLY) p->p_retval[0] |= LINUX_O_WRONLY;
24350703Swpaul	if (result & O_RDWR) p->p_retval[0] |= LINUX_O_RDWR;
24450703Swpaul	if (result & O_NDELAY) p->p_retval[0] |= LINUX_O_NONBLOCK;
24550703Swpaul	if (result & O_APPEND) p->p_retval[0] |= LINUX_O_APPEND;
24650703Swpaul	if (result & O_FSYNC) p->p_retval[0] |= LINUX_O_SYNC;
24751455Swpaul	if (result & O_ASYNC) p->p_retval[0] |= LINUX_FASYNC;
24850703Swpaul	return error;
24950703Swpaul
25050703Swpaul    case LINUX_F_SETFL:
25150703Swpaul	fcntl_args.arg = 0;
25250703Swpaul	if (args->arg & LINUX_O_NDELAY) fcntl_args.arg |= O_NONBLOCK;
25350703Swpaul	if (args->arg & LINUX_O_APPEND) fcntl_args.arg |= O_APPEND;
254113506Smdodd	if (args->arg & LINUX_O_SYNC) fcntl_args.arg |= O_FSYNC;
255123019Simp	if (args->arg & LINUX_FASYNC) fcntl_args.arg |= O_ASYNC;
25651473Swpaul	fcntl_args.cmd = F_SETFL;
25750703Swpaul	return fcntl(p, &fcntl_args);
25840516Swpaul
25940516Swpaul    case LINUX_F_GETLK:
26040516Swpaul	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
26140516Swpaul		   	    sizeof(struct linux_flock))))
26240516Swpaul	    return error;
26340516Swpaul	linux_to_bsd_flock(&linux_flock, bsd_flock);
26440516Swpaul	fcntl_args.cmd = F_GETLK;
26540516Swpaul	fcntl_args.arg = (int)bsd_flock;
26681713Swpaul	error = fcntl(p, &fcntl_args);
26781713Swpaul	if (error)
26881713Swpaul	    return error;
26981713Swpaul	bsd_to_linux_flock(bsd_flock, &linux_flock);
27081713Swpaul	return copyout((caddr_t)&linux_flock, (caddr_t)args->arg,
27181713Swpaul		       sizeof(struct linux_flock));
27281713Swpaul
27381713Swpaul    case LINUX_F_SETLK:
27481713Swpaul	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
27581713Swpaul		   	    sizeof(struct linux_flock))))
27681713Swpaul	    return error;
27781713Swpaul	linux_to_bsd_flock(&linux_flock, bsd_flock);
27881713Swpaul	fcntl_args.cmd = F_SETLK;
27981713Swpaul	fcntl_args.arg = (int)bsd_flock;
28081713Swpaul	return fcntl(p, &fcntl_args);
28181713Swpaul
28281713Swpaul    case LINUX_F_SETLKW:
28381713Swpaul	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
28481713Swpaul		   	    sizeof(struct linux_flock))))
28581713Swpaul	    return error;
28681713Swpaul	linux_to_bsd_flock(&linux_flock, bsd_flock);
28781713Swpaul	fcntl_args.cmd = F_SETLKW;
28881713Swpaul	fcntl_args.arg = (int)bsd_flock;
28981713Swpaul	return fcntl(p, &fcntl_args);
29081713Swpaul
29181713Swpaul    case LINUX_F_SETOWN:
29281713Swpaul    case LINUX_F_GETOWN:
29381713Swpaul	/*
29440516Swpaul	 * We need to route around the normal fcntl() for these calls,
29540516Swpaul	 * since it uses TIOC{G,S}PGRP, which is too restrictive for
29640516Swpaul	 * Linux F_{G,S}ETOWN semantics. For sockets, this problem
297102335Salfred	 * does not exist.
298102335Salfred	 */
29940516Swpaul	fdp = p->p_fd;
30041656Swpaul	if ((u_int)args->fd >= fdp->fd_nfiles ||
30140516Swpaul		(fp = fdp->fd_ofiles[args->fd]) == NULL)
30240516Swpaul	    return EBADF;
30340516Swpaul	if (fp->f_type == DTYPE_SOCKET) {
30467931Swpaul	    fcntl_args.cmd = args->cmd == LINUX_F_SETOWN ? F_SETOWN : F_GETOWN;
30540516Swpaul    	    fcntl_args.arg = args->arg;
30640516Swpaul	    return fcntl(p, &fcntl_args);
30755170Sbillf	}
30840516Swpaul	vp = (struct vnode *)fp->f_data;
30940516Swpaul	dev = vn_todev(vp);
31040516Swpaul	if (vp->v_type != VCHR || dev == NODEV)
31140516Swpaul	    return EINVAL;
31240516Swpaul	d_tty = devsw(dev)->d_devtotty;
31340516Swpaul	if (!d_tty || (!(tp = (*d_tty)(dev))))
31440516Swpaul	    return EINVAL;
31540516Swpaul	if (args->cmd == LINUX_F_GETOWN) {
31640516Swpaul	    p->p_retval[0] = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
31740516Swpaul	    return 0;
31840516Swpaul	}
31940516Swpaul	if ((long)args->arg <= 0) {
32040516Swpaul	    pgid = -(long)args->arg;
32140516Swpaul	} else {
32240516Swpaul	    struct proc *p1 = pfind((long)args->arg);
32340516Swpaul	    if (p1 == 0)
32440516Swpaul		return (ESRCH);
32540516Swpaul	    pgid = (long)p1->p_pgrp->pg_id;
32640516Swpaul	}
32740516Swpaul	pgrp = pgfind(pgid);
328102335Salfred	if (pgrp == NULL || pgrp->pg_session != p->p_session)
329102335Salfred	    return EPERM;
33040516Swpaul	tp->t_pgrp = pgrp;
33141656Swpaul	return 0;
33240516Swpaul    }
33340516Swpaul    return EINVAL;
33440516Swpaul}
33540516Swpaul
33640516Swpaulint
33740516Swpaullinux_lseek(struct proc *p, struct linux_lseek_args *args)
33840516Swpaul{
33940516Swpaul
34040516Swpaul    struct lseek_args /* {
34140516Swpaul	int fd;
34240516Swpaul	int pad;
34340516Swpaul	off_t offset;
34440516Swpaul	int whence;
34540516Swpaul    } */ tmp_args;
34640516Swpaul    int error;
34740516Swpaul
34840516Swpaul#ifdef DEBUG
34940516Swpaul    printf("Linux-emul(%ld): lseek(%d, %ld, %d)\n",
35040516Swpaul	   (long)p->p_pid, args->fdes, args->off, args->whence);
35140516Swpaul#endif
35240516Swpaul    tmp_args.fd = args->fdes;
35340516Swpaul    tmp_args.offset = (off_t)args->off;
35440516Swpaul    tmp_args.whence = args->whence;
35540516Swpaul    error = lseek(p, &tmp_args);
35640516Swpaul    return error;
35740516Swpaul}
35840516Swpaul
35940516Swpaulint
36040516Swpaullinux_llseek(struct proc *p, struct linux_llseek_args *args)
36140516Swpaul{
36240516Swpaul	struct lseek_args bsd_args;
36340516Swpaul	int error;
36440516Swpaul	off_t off;
36540516Swpaul
36640516Swpaul#ifdef DEBUG
36740516Swpaul        printf("Linux-emul(%d): llseek(%d, %d:%d, %d)\n",
36840516Swpaul	   p->p_pid, args->fd, args->ohigh, args->olow, args->whence);
36940516Swpaul#endif
370102335Salfred	off = (args->olow) | (((off_t) args->ohigh) << 32);
371102335Salfred
37240516Swpaul	bsd_args.fd = args->fd;
37340516Swpaul	bsd_args.offset = off;
37440516Swpaul	bsd_args.whence = args->whence;
37540516Swpaul
37640516Swpaul	if ((error = lseek(p, &bsd_args)))
37740516Swpaul		return error;
37840516Swpaul
37940516Swpaul	if ((error = copyout(p->p_retval, (caddr_t)args->res, sizeof (off_t))))
38040516Swpaul		return error;
38140516Swpaul
38240516Swpaul	p->p_retval[0] = 0;
38340516Swpaul	return 0;
38440516Swpaul}
38540516Swpaul
38640516Swpaul
38740516Swpaulstruct linux_dirent {
38840516Swpaul    long dino;
38940516Swpaul    linux_off_t doff;
39040516Swpaul    unsigned short dreclen;
39140516Swpaul    char dname[LINUX_NAME_MAX + 1];
39240516Swpaul};
39340516Swpaul
39440516Swpaul#define LINUX_RECLEN(de,namlen) \
39540516Swpaul    ALIGN((((char *)&(de)->dname - (char *)de) + (namlen) + 1))
39640516Swpaul
39740516Swpaulint
39840516Swpaullinux_readdir(struct proc *p, struct linux_readdir_args *args)
39940516Swpaul{
40040516Swpaul	struct linux_getdents_args lda;
40140516Swpaul
402105221Sphk	lda.fd = args->fd;
40340516Swpaul	lda.dent = args->dent;
40440516Swpaul	lda.count = 1;
40540516Swpaul	return linux_getdents(p, &lda);
406105221Sphk}
40740516Swpaul
40840516Swpaulint
40940516Swpaullinux_getdents(struct proc *p, struct linux_getdents_args *args)
41040516Swpaul{
411102335Salfred    register struct dirent *bdp;
412102335Salfred    struct vnode *vp;
41340516Swpaul    caddr_t inp, buf;		/* BSD-format */
41440516Swpaul    int len, reclen;		/* BSD-format */
41540516Swpaul    caddr_t outp;		/* Linux-format */
41640516Swpaul    int resid, linuxreclen=0;	/* Linux-format */
41740516Swpaul    struct file *fp;
41840516Swpaul    struct uio auio;
41940516Swpaul    struct iovec aiov;
42040516Swpaul    struct vattr va;
42140516Swpaul    off_t off;
42240516Swpaul    struct linux_dirent linux_dirent;
42340516Swpaul    int buflen, error, eofflag, nbytes, justone;
42440516Swpaul    u_long *cookies = NULL, *cookiep;
42540516Swpaul    int ncookies;
42640516Swpaul
42740516Swpaul#ifdef DEBUG
42840516Swpaul    printf("Linux-emul(%d): getdents(%d, *, %d)\n",
42940516Swpaul	   p->p_pid, args->fd, args->count);
43040516Swpaul#endif
43140516Swpaul    if ((error = getvnode(p->p_fd, args->fd, &fp)) != 0) {
432102335Salfred	return (error);
433102335Salfred    }
43440516Swpaul
43540516Swpaul    if ((fp->f_flag & FREAD) == 0)
43640516Swpaul	return (EBADF);
43740516Swpaul
43840516Swpaul    vp = (struct vnode *) fp->f_data;
43940516Swpaul
44040516Swpaul    if (vp->v_type != VDIR)
44140516Swpaul	return (EINVAL);
44240516Swpaul
443109109Sdes    if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p))) {
44440516Swpaul	return error;
445109109Sdes    }
44640516Swpaul
447109109Sdes    nbytes = args->count;
44840516Swpaul    if (nbytes == 1) {
44940516Swpaul	nbytes = sizeof (struct linux_dirent);
45040516Swpaul	justone = 1;
45140516Swpaul    }
45240516Swpaul    else
45340516Swpaul	justone = 0;
45440516Swpaul
45540516Swpaul    off = fp->f_offset;
45640516Swpaul#define	DIRBLKSIZ	512		/* XXX we used to use ufs's DIRBLKSIZ */
45740516Swpaul    buflen = max(DIRBLKSIZ, nbytes);
458102335Salfred    buflen = min(buflen, MAXBSIZE);
459102335Salfred    buf = malloc(buflen, M_TEMP, M_WAITOK);
46040516Swpaul    vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
46140516Swpaulagain:
462109109Sdes    aiov.iov_base = buf;
46340516Swpaul    aiov.iov_len = buflen;
46467087Swpaul    auio.uio_iov = &aiov;
46540516Swpaul    auio.uio_iovcnt = 1;
46667087Swpaul    auio.uio_rw = UIO_READ;
46740516Swpaul    auio.uio_segflg = UIO_SYSSPACE;
46840516Swpaul    auio.uio_procp = p;
46940516Swpaul    auio.uio_resid = buflen;
47040516Swpaul    auio.uio_offset = off;
47140516Swpaul
47240516Swpaul    if (cookies) {
47340516Swpaul	free(cookies, M_TEMP);
47440516Swpaul	cookies = NULL;
475109109Sdes    }
47640516Swpaul
47740516Swpaul    error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, &cookies);
47840516Swpaul    if (error) {
479109109Sdes	goto out;
48040516Swpaul    }
48140516Swpaul
48240516Swpaul    inp = buf;
48340516Swpaul    outp = (caddr_t) args->dent;
48440516Swpaul    resid = nbytes;
48540516Swpaul    if ((len = buflen - auio.uio_resid) <= 0) {
48640516Swpaul	goto eof;
48740516Swpaul    }
48840516Swpaul
48940516Swpaul    cookiep = cookies;
49040516Swpaul
49140516Swpaul    if (cookies) {
49240516Swpaul	/*
49340516Swpaul	 * When using cookies, the vfs has the option of reading from
49440516Swpaul	 * a different offset than that supplied (UFS truncates the
49540516Swpaul	 * offset to a block boundary to make sure that it never reads
49640516Swpaul	 * partway through a directory entry, even if the directory
49740516Swpaul	 * has been compacted).
49840516Swpaul	 */
49940516Swpaul	while (len > 0 && ncookies > 0 && *cookiep <= off) {
50040516Swpaul	    bdp = (struct dirent *) inp;
50140516Swpaul	    len -= bdp->d_reclen;
50240516Swpaul	    inp += bdp->d_reclen;
50340516Swpaul	    cookiep++;
50440516Swpaul	    ncookies--;
505109058Smbr	}
50640516Swpaul    }
50740516Swpaul
50840516Swpaul    while (len > 0) {
50940516Swpaul	if (cookiep && ncookies == 0)
51040516Swpaul	    break;
51140516Swpaul	bdp = (struct dirent *) inp;
51240516Swpaul	reclen = bdp->d_reclen;
51340516Swpaul	if (reclen & 3) {
51440516Swpaul	    printf("linux_readdir: reclen=%d\n", reclen);
51540516Swpaul	    error = EFAULT;
51640516Swpaul	    goto out;
51740516Swpaul	}
51840516Swpaul
51940516Swpaul	if (bdp->d_fileno == 0) {
52040516Swpaul	    inp += reclen;
52140516Swpaul	    if (cookiep) {
52240516Swpaul		off = *cookiep++;
52340516Swpaul		ncookies--;
52440516Swpaul	    } else
52540516Swpaul		off += reclen;
52640516Swpaul	    len -= reclen;
52740516Swpaul	    continue;
52840516Swpaul	}
52940516Swpaul	linuxreclen = LINUX_RECLEN(&linux_dirent, bdp->d_namlen);
53040516Swpaul	if (reclen > len || resid < linuxreclen) {
53140516Swpaul	    outp++;
53240516Swpaul	    break;
53340516Swpaul	}
53440516Swpaul	linux_dirent.dino = (long) bdp->d_fileno;
53540516Swpaul	if (justone) {
53640516Swpaul	    /*
53740516Swpaul	     * old linux-style readdir usage.
53840516Swpaul	     */
53940516Swpaul	    linux_dirent.doff = (linux_off_t) linuxreclen;
54040516Swpaul	    linux_dirent.dreclen = (u_short) bdp->d_namlen;
54140516Swpaul	} else {
54267087Swpaul	    linux_dirent.doff = (linux_off_t) off;
54340516Swpaul	    linux_dirent.dreclen = (u_short) linuxreclen;
54440516Swpaul	}
54540516Swpaul	strcpy(linux_dirent.dname, bdp->d_name);
54640516Swpaul	if ((error = copyout((caddr_t)&linux_dirent, outp, linuxreclen))) {
54740516Swpaul	    goto out;
54840516Swpaul	}
54940516Swpaul	inp += reclen;
55040516Swpaul	if (cookiep) {
55140516Swpaul	    off = *cookiep++;
552102335Salfred	    ncookies--;
553102335Salfred	} else
55440516Swpaul	    off += reclen;
55540516Swpaul	outp += linuxreclen;
556109109Sdes	resid -= linuxreclen;
55740516Swpaul	len -= reclen;
55867087Swpaul	if (justone)
55940516Swpaul	    break;
56040516Swpaul    }
56140516Swpaul
56240516Swpaul    if (outp == (caddr_t) args->dent)
56340516Swpaul	goto again;
56440516Swpaul    fp->f_offset = off;
56540516Swpaul
56640516Swpaul    if (justone)
567109109Sdes	nbytes = resid + linuxreclen;
56840516Swpaul
569109109Sdeseof:
57040516Swpaul    p->p_retval[0] = nbytes - resid;
57140516Swpaulout:
57240516Swpaul    if (cookies)
57340516Swpaul	free(cookies, M_TEMP);
57440516Swpaul    VOP_UNLOCK(vp, 0, p);
57540516Swpaul    free(buf, M_TEMP);
57640516Swpaul    return error;
57740516Swpaul}
57840516Swpaul
57940516Swpaul/*
58040516Swpaul * These exist mainly for hooks for doing /compat/linux translation.
58140516Swpaul */
58240516Swpaul
58340516Swpaulint
58440516Swpaullinux_access(struct proc *p, struct linux_access_args *args)
58540516Swpaul{
58640516Swpaul	struct access_args bsd;
58740516Swpaul	caddr_t sg;
58840516Swpaul
58940516Swpaul	sg = stackgap_init();
59040516Swpaul	CHECKALTEXIST(p, &sg, args->path);
59140516Swpaul
59240516Swpaul#ifdef DEBUG
59367087Swpaul        printf("Linux-emul(%d): access(%s, %d)\n",
59440516Swpaul	    p->p_pid, args->path, args->flags);
59540516Swpaul#endif
59640516Swpaul	bsd.path = args->path;
59740516Swpaul	bsd.flags = args->flags;
598102335Salfred
599102335Salfred	return access(p, &bsd);
60050703Swpaul}
60150703Swpaul
60250703Swpaulint
60340516Swpaullinux_unlink(struct proc *p, struct linux_unlink_args *args)
60440516Swpaul{
60540516Swpaul	struct unlink_args bsd;
60640516Swpaul	caddr_t sg;
60740516Swpaul
60850703Swpaul	sg = stackgap_init();
60967087Swpaul	CHECKALTEXIST(p, &sg, args->path);
61050703Swpaul
611119868Swpaul#ifdef DEBUG
61250703Swpaul	printf("Linux-emul(%d): unlink(%s)\n",
61367087Swpaul	   p->p_pid, args->path);
61467087Swpaul#endif
61550703Swpaul	bsd.path = args->path;
61667087Swpaul
61740516Swpaul	return unlink(p, &bsd);
61850703Swpaul}
61940516Swpaul
62040516Swpaulint
62150703Swpaullinux_chdir(struct proc *p, struct linux_chdir_args *args)
62240516Swpaul{
62340516Swpaul	struct chdir_args bsd;
62450703Swpaul	caddr_t sg;
62540516Swpaul
62640516Swpaul	sg = stackgap_init();
62750703Swpaul	CHECKALTEXIST(p, &sg, args->path);
62850703Swpaul
62950703Swpaul#ifdef DEBUG
63050703Swpaul	printf("Linux-emul(%d): chdir(%s)\n",
63140516Swpaul	   p->p_pid, args->path);
63240516Swpaul#endif
63350703Swpaul	bsd.path = args->path;
63450703Swpaul
63567087Swpaul	return chdir(p, &bsd);
63650703Swpaul}
63794149Swpaul
63894149Swpaulint
63994149Swpaullinux_chmod(struct proc *p, struct linux_chmod_args *args)
64094149Swpaul{
64194149Swpaul	struct chmod_args bsd;
64294149Swpaul	caddr_t sg;
64394149Swpaul
64494149Swpaul	sg = stackgap_init();
64594149Swpaul	CHECKALTEXIST(p, &sg, args->path);
64694149Swpaul
64740516Swpaul#ifdef DEBUG
64840516Swpaul        printf("Linux-emul(%d): chmod(%s, %d)\n",
64967087Swpaul	    p->p_pid, args->path, args->mode);
65040516Swpaul#endif
65140516Swpaul	bsd.path = args->path;
65240516Swpaul	bsd.mode = args->mode;
65367087Swpaul
65440516Swpaul	return chmod(p, &bsd);
65540516Swpaul}
65640516Swpaul
65740516Swpaulint
65840516Swpaullinux_chown(struct proc *p, struct linux_chown_args *args)
65950703Swpaul{
66040516Swpaul	struct chown_args bsd;
66140516Swpaul	caddr_t sg;
66267087Swpaul
66340516Swpaul	sg = stackgap_init();
66440516Swpaul	CHECKALTEXIST(p, &sg, args->path);
66540516Swpaul
66640516Swpaul#ifdef DEBUG
667102335Salfred        printf("Linux-emul(%d): chown(%s, %d, %d)\n",
668102335Salfred	    p->p_pid, args->path, args->uid, args->gid);
66950703Swpaul#endif
67050703Swpaul	bsd.path = args->path;
67150703Swpaul	/* XXX size casts here */
67240516Swpaul	bsd.uid = args->uid;
67340516Swpaul	bsd.gid = args->gid;
67440516Swpaul
67540516Swpaul	return chown(p, &bsd);
67650703Swpaul}
67767087Swpaul
67850703Swpaulint
679119868Swpaullinux_lchown(struct proc *p, struct linux_lchown_args *args)
68050703Swpaul{
68167087Swpaul	struct lchown_args bsd;
68267087Swpaul	caddr_t sg;
68350703Swpaul
68467087Swpaul	sg = stackgap_init();
68540516Swpaul	CHECKALTEXIST(p, &sg, args->path);
68650703Swpaul
68740516Swpaul#ifdef DEBUG
68840516Swpaul        printf("Linux-emul(%d): lchown(%s, %d, %d)\n",
68950703Swpaul	    p->p_pid, args->path, args->uid, args->gid);
69040516Swpaul#endif
69140516Swpaul	bsd.path = args->path;
69250703Swpaul	/* XXX size casts here */
69340516Swpaul	bsd.uid = args->uid;
69440516Swpaul	bsd.gid = args->gid;
69550703Swpaul
69650703Swpaul	return lchown(p, &bsd);
69750703Swpaul}
69850703Swpaul
69940516Swpaulint
70040516Swpaullinux_mkdir(struct proc *p, struct linux_mkdir_args *args)
70150703Swpaul{
70250703Swpaul	struct mkdir_args bsd;
70367087Swpaul	caddr_t sg;
70450703Swpaul
70550703Swpaul	sg = stackgap_init();
70640516Swpaul	CHECKALTCREAT(p, &sg, args->path);
70740516Swpaul
70867087Swpaul#ifdef DEBUG
70950703Swpaul        printf("Linux-emul(%d): mkdir(%s, %d)\n",
71040516Swpaul	    p->p_pid, args->path, args->mode);
71140516Swpaul#endif
71267087Swpaul	bsd.path = args->path;
71350703Swpaul	bsd.mode = args->mode;
71440516Swpaul
71540516Swpaul	return mkdir(p, &bsd);
71640516Swpaul}
71740516Swpaul
71850703Swpaulint
71940516Swpaullinux_rmdir(struct proc *p, struct linux_rmdir_args *args)
72040516Swpaul{
72140516Swpaul	struct rmdir_args bsd;
72240516Swpaul	caddr_t sg;
72340516Swpaul
72467087Swpaul	sg = stackgap_init();
72550703Swpaul	CHECKALTEXIST(p, &sg, args->path);
72650703Swpaul
72750703Swpaul#ifdef DEBUG
728102335Salfred        printf("Linux-emul(%d): rmdir(%s)\n",
729102335Salfred	    p->p_pid, args->path);
73050703Swpaul#endif
73150703Swpaul	bsd.path = args->path;
73240516Swpaul
73340516Swpaul	return rmdir(p, &bsd);
73440516Swpaul}
73540516Swpaul
73643062Swpaulint
73740516Swpaullinux_rename(struct proc *p, struct linux_rename_args *args)
738122625Sobrien{
739122625Sobrien	struct rename_args bsd;
740123289Sobrien	caddr_t sg;
74140516Swpaul
742123289Sobrien	sg = stackgap_init();
743123289Sobrien	CHECKALTEXIST(p, &sg, args->from);
744123289Sobrien	CHECKALTCREAT(p, &sg, args->to);
74540516Swpaul
74640516Swpaul#ifdef DEBUG
74740516Swpaul        printf("Linux-emul(%d): rename(%s, %s)\n",
74840516Swpaul	    p->p_pid, args->from, args->to);
749122625Sobrien#endif
750122625Sobrien	bsd.from = args->from;
751122625Sobrien	bsd.to = args->to;
75240516Swpaul
75340516Swpaul	return rename(p, &bsd);
75440516Swpaul}
75540516Swpaul
75640516Swpaulint
75740516Swpaullinux_symlink(struct proc *p, struct linux_symlink_args *args)
75840516Swpaul{
75943062Swpaul	struct symlink_args bsd;
76040516Swpaul	caddr_t sg;
76140516Swpaul
76240516Swpaul	sg = stackgap_init();
76340516Swpaul	CHECKALTEXIST(p, &sg, args->path);
76440516Swpaul	CHECKALTCREAT(p, &sg, args->to);
765102335Salfred
766102335Salfred#ifdef DEBUG
76740516Swpaul        printf("Linux-emul(%d): symlink(%s, %s)\n",
76840516Swpaul	    p->p_pid, args->path, args->to);
76940516Swpaul#endif
77040516Swpaul	bsd.path = args->path;
77140516Swpaul	bsd.link = args->to;
77240516Swpaul
77340516Swpaul	return symlink(p, &bsd);
77440516Swpaul}
77540516Swpaul
77640516Swpaulint
77740516Swpaullinux_execve(struct proc *p, struct linux_execve_args *args)
77840516Swpaul{
77940516Swpaul	struct execve_args bsd;
78043062Swpaul	caddr_t sg;
78140516Swpaul
78240516Swpaul	sg = stackgap_init();
78340516Swpaul	CHECKALTEXIST(p, &sg, args->path);
78440516Swpaul
78540516Swpaul#ifdef DEBUG
78640516Swpaul        printf("Linux-emul(%d): execve(%s)\n",
78740516Swpaul	    p->p_pid, args->path);
78840516Swpaul#endif
78940516Swpaul	bsd.fname = args->path;
79040516Swpaul	bsd.argv = args->argp;
79140516Swpaul	bsd.envv = args->envp;
79240516Swpaul
79372084Sphk	return execve(p, &bsd);
79440516Swpaul}
79540516Swpaul
796122625Sobrienint
79740516Swpaullinux_readlink(struct proc *p, struct linux_readlink_args *args)
79840516Swpaul{
79940516Swpaul	struct readlink_args bsd;
80040516Swpaul	caddr_t sg;
80140516Swpaul
80240516Swpaul	sg = stackgap_init();
80340516Swpaul	CHECKALTEXIST(p, &sg, args->name);
80440516Swpaul
80540516Swpaul#ifdef DEBUG
80640516Swpaul        printf("Linux-emul(%ld): readlink(%s, %p, %d)\n",
80740516Swpaul	    (long)p->p_pid, args->name, (void *)args->buf, args->count);
80840516Swpaul#endif
80940516Swpaul	bsd.path = args->name;
81040516Swpaul	bsd.buf = args->buf;
81140516Swpaul	bsd.count = args->count;
81240516Swpaul
81340516Swpaul	return readlink(p, &bsd);
81440516Swpaul}
81540516Swpaul
816102335Salfredint
817102335Salfredlinux_truncate(struct proc *p, struct linux_truncate_args *args)
81840516Swpaul{
81940516Swpaul	struct truncate_args bsd;
82040516Swpaul	caddr_t sg;
82140516Swpaul
82240516Swpaul	sg = stackgap_init();
82340516Swpaul	CHECKALTEXIST(p, &sg, args->path);
82440516Swpaul
82540516Swpaul#ifdef DEBUG
82640516Swpaul        printf("Linux-emul(%d): truncate(%s, %ld)\n",
82740516Swpaul	    p->p_pid, args->path, args->length);
82840516Swpaul#endif
82940516Swpaul	bsd.path = args->path;
83040516Swpaul	bsd.length = args->length;
83140516Swpaul
832109109Sdes	return truncate(p, &bsd);
83340516Swpaul}
83440516Swpaul
83540516Swpaulint
83640516Swpaullinux_link(struct proc *p, struct linux_link_args *args)
83740516Swpaul{
83840516Swpaul    struct link_args bsd;
839102335Salfred    caddr_t sg;
840102335Salfred
84150703Swpaul    sg = stackgap_init();
84240516Swpaul    CHECKALTEXIST(p, &sg, args->path);
84340516Swpaul    CHECKALTCREAT(p, &sg, args->to);
844119868Swpaul
845117388Swpaul#ifdef DEBUG
846117388Swpaul    printf("Linux-emul(%d): link(%s, %s)\n", p->p_pid, args->path, args->to);
84740516Swpaul#endif
84840516Swpaul
849117388Swpaul    bsd.path = args->path;
85040516Swpaul    bsd.link = args->to;
85140516Swpaul
85250703Swpaul    return link(p, &bsd);
85350703Swpaul}
854117388Swpaul
855117388Swpaulint
856117388Swpaullinux_getcwd(struct proc *p, struct linux_getcwd_args *args)
857117388Swpaul{
858117388Swpaul	struct __getcwd_args bsd;
859117388Swpaul	caddr_t sg;
860127135Snjl	int error, len;
861127135Snjl
862117388Swpaul#ifdef DEBUG
863117388Swpaul	printf("Linux-emul(%ld): getcwd(%p, %ld)\n", (long)p->p_pid,
864117388Swpaul	       args->buf, args->bufsize);
865117388Swpaul#endif
866117388Swpaul
867117388Swpaul	sg = stackgap_init();
868117388Swpaul	bsd.buf = stackgap_alloc(&sg, SPARE_USRSPACE);
869117388Swpaul	bsd.buflen = SPARE_USRSPACE;
870117388Swpaul	error = __getcwd(p, &bsd);
871117388Swpaul	if (!error) {
872119868Swpaul		len = strlen(bsd.buf) + 1;
873119868Swpaul		if (len <= args->bufsize) {
874119868Swpaul			p->p_retval[0] = len;
875117388Swpaul			error = copyout(bsd.buf, args->buf, len);
876117388Swpaul		}
877119868Swpaul		else
878119868Swpaul			error = ERANGE;
879119868Swpaul	}
880124076Swpaul	return (error);
881124076Swpaul}
882119954Swpaul