diff options
Diffstat (limited to 'sys/compat/linux/linux_file.c')
-rw-r--r-- | sys/compat/linux/linux_file.c | 945 |
1 files changed, 558 insertions, 387 deletions
diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c index 2a5d673..3d16a94 100644 --- a/sys/compat/linux/linux_file.c +++ b/sys/compat/linux/linux_file.c @@ -149,175 +149,6 @@ linux_open(struct proc *p, struct linux_open_args *args) return error; } -struct linux_flock { - short l_type; - short l_whence; - linux_off_t l_start; - linux_off_t l_len; - linux_pid_t l_pid; -}; - -static void -linux_to_bsd_flock(struct linux_flock *linux_flock, struct flock *bsd_flock) -{ - switch (linux_flock->l_type) { - case LINUX_F_RDLCK: - bsd_flock->l_type = F_RDLCK; - break; - case LINUX_F_WRLCK: - bsd_flock->l_type = F_WRLCK; - break; - case LINUX_F_UNLCK: - bsd_flock->l_type = F_UNLCK; - break; - default: - bsd_flock->l_type = -1; - break; - } - bsd_flock->l_whence = linux_flock->l_whence; - bsd_flock->l_start = (off_t)linux_flock->l_start; - bsd_flock->l_len = (off_t)linux_flock->l_len; - bsd_flock->l_pid = (pid_t)linux_flock->l_pid; -} - -static void -bsd_to_linux_flock(struct flock *bsd_flock, struct linux_flock *linux_flock) -{ - switch (bsd_flock->l_type) { - case F_RDLCK: - linux_flock->l_type = LINUX_F_RDLCK; - break; - case F_WRLCK: - linux_flock->l_type = LINUX_F_WRLCK; - break; - case F_UNLCK: - linux_flock->l_type = LINUX_F_UNLCK; - break; - } - linux_flock->l_whence = bsd_flock->l_whence; - linux_flock->l_start = (linux_off_t)bsd_flock->l_start; - linux_flock->l_len = (linux_off_t)bsd_flock->l_len; - linux_flock->l_pid = (linux_pid_t)bsd_flock->l_pid; -} - -int -linux_fcntl(struct proc *p, struct linux_fcntl_args *args) -{ - int error, result; - struct fcntl_args /* { - int fd; - int cmd; - long arg; - } */ fcntl_args; - struct linux_flock linux_flock; - struct flock *bsd_flock; - struct filedesc *fdp; - struct file *fp; - caddr_t sg; - - sg = stackgap_init(); - bsd_flock = (struct flock *)stackgap_alloc(&sg, sizeof(struct flock)); - -#ifdef DEBUG - if (ldebug(fcntl)) - printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd); -#endif - fcntl_args.fd = args->fd; - - switch (args->cmd) { - case LINUX_F_DUPFD: - fcntl_args.cmd = F_DUPFD; - fcntl_args.arg = args->arg; - return fcntl(p, &fcntl_args); - - case LINUX_F_GETFD: - fcntl_args.cmd = F_GETFD; - return fcntl(p, &fcntl_args); - - case LINUX_F_SETFD: - fcntl_args.cmd = F_SETFD; - fcntl_args.arg = args->arg; - return fcntl(p, &fcntl_args); - - case LINUX_F_GETFL: - fcntl_args.cmd = F_GETFL; - error = fcntl(p, &fcntl_args); - result = p->p_retval[0]; - p->p_retval[0] = 0; - if (result & O_RDONLY) p->p_retval[0] |= LINUX_O_RDONLY; - if (result & O_WRONLY) p->p_retval[0] |= LINUX_O_WRONLY; - if (result & O_RDWR) p->p_retval[0] |= LINUX_O_RDWR; - if (result & O_NDELAY) p->p_retval[0] |= LINUX_O_NONBLOCK; - if (result & O_APPEND) p->p_retval[0] |= LINUX_O_APPEND; - if (result & O_FSYNC) p->p_retval[0] |= LINUX_O_SYNC; - if (result & O_ASYNC) p->p_retval[0] |= LINUX_FASYNC; - return error; - - case LINUX_F_SETFL: - fcntl_args.arg = 0; - if (args->arg & LINUX_O_NDELAY) fcntl_args.arg |= O_NONBLOCK; - if (args->arg & LINUX_O_APPEND) fcntl_args.arg |= O_APPEND; - if (args->arg & LINUX_O_SYNC) fcntl_args.arg |= O_FSYNC; - if (args->arg & LINUX_FASYNC) fcntl_args.arg |= O_ASYNC; - fcntl_args.cmd = F_SETFL; - return fcntl(p, &fcntl_args); - - case LINUX_F_GETLK: - if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock, - sizeof(struct linux_flock)))) - return error; - linux_to_bsd_flock(&linux_flock, bsd_flock); - fcntl_args.cmd = F_GETLK; - fcntl_args.arg = (long)bsd_flock; - error = fcntl(p, &fcntl_args); - if (error) - return error; - bsd_to_linux_flock(bsd_flock, &linux_flock); - return copyout((caddr_t)&linux_flock, (caddr_t)args->arg, - sizeof(struct linux_flock)); - - case LINUX_F_SETLK: - if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock, - sizeof(struct linux_flock)))) - return error; - linux_to_bsd_flock(&linux_flock, bsd_flock); - fcntl_args.cmd = F_SETLK; - fcntl_args.arg = (long)bsd_flock; - return fcntl(p, &fcntl_args); - - case LINUX_F_SETLKW: - if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock, - sizeof(struct linux_flock)))) - return error; - linux_to_bsd_flock(&linux_flock, bsd_flock); - fcntl_args.cmd = F_SETLKW; - fcntl_args.arg = (long)bsd_flock; - return fcntl(p, &fcntl_args); - - case LINUX_F_GETOWN: - fcntl_args.cmd = F_GETOWN; - return fcntl(p, &fcntl_args); - - case LINUX_F_SETOWN: - /* - * XXX some Linux applications depend on F_SETOWN having no - * significant effect for pipes (SIGIO is not delivered for - * pipes under Linux-2.2.35 at least). - */ - fdp = p->p_fd; - if ((u_int)args->fd >= fdp->fd_nfiles || - (fp = fdp->fd_ofiles[args->fd]) == NULL) - return EBADF; - if (fp->f_type == DTYPE_PIPE) - return EINVAL; - - fcntl_args.cmd = F_SETOWN; - fcntl_args.arg = args->arg; - return fcntl(p, &fcntl_args); - } - return EINVAL; -} - int linux_lseek(struct proc *p, struct linux_lseek_args *args) { @@ -333,7 +164,7 @@ linux_lseek(struct proc *p, struct linux_lseek_args *args) #ifdef DEBUG if (ldebug(lseek)) printf(ARGS(lseek, "%d, %ld, %d"), - args->fdes, args->off, args->whence); + args->fdes, (long)args->off, args->whence); #endif tmp_args.fd = args->fdes; tmp_args.offset = (off_t)args->off; @@ -372,17 +203,6 @@ linux_llseek(struct proc *p, struct linux_llseek_args *args) } #endif /*!__alpha__*/ - -struct linux_dirent { - long dino; - linux_off_t doff; - unsigned short dreclen; - char dname[LINUX_NAME_MAX + 1]; -}; - -#define LINUX_RECLEN(de,namlen) \ - ALIGN((((char *)&(de)->dname - (char *)de) + (namlen) + 1)) - #ifndef __alpha__ int linux_readdir(struct proc *p, struct linux_readdir_args *args) @@ -396,178 +216,250 @@ linux_readdir(struct proc *p, struct linux_readdir_args *args) } #endif /*!__alpha__*/ -int -linux_getdents(struct proc *p, struct linux_getdents_args *args) -{ - register struct dirent *bdp; - struct vnode *vp; - caddr_t inp, buf; /* BSD-format */ - int len, reclen; /* BSD-format */ - caddr_t outp; /* Linux-format */ - int resid, linuxreclen=0; /* Linux-format */ - struct file *fp; - struct uio auio; - struct iovec aiov; - struct vattr va; - off_t off; - struct linux_dirent linux_dirent; - int buflen, error, eofflag, nbytes, justone; - u_long *cookies = NULL, *cookiep; - int ncookies; +/* + * Note that linux_getdents(2) and linux_getdents64(2) have the same + * arguments. They only differ in the definition of struct dirent they + * operate on. We use this to common the code, with the exception of + * accessing struct dirent. Note that linux_readdir(2) is implemented + * by means of linux_getdents(2). In this case we never operate on + * struct dirent64 and thus don't need to handle it... + */ -#ifdef DEBUG - if (ldebug(getdents)) - printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count); -#endif - if ((error = getvnode(p->p_fd, args->fd, &fp)) != 0) { - return (error); - } +struct l_dirent { + l_long d_ino; + l_off_t d_off; + l_ushort d_reclen; + char d_name[LINUX_NAME_MAX + 1]; +}; - if ((fp->f_flag & FREAD) == 0) - return (EBADF); +struct l_dirent64 { + uint64_t d_ino; + int64_t d_off; + l_ushort d_reclen; + u_char d_type; + char d_name[LINUX_NAME_MAX + 1]; +}; - vp = (struct vnode *) fp->f_data; +#define LINUX_RECLEN(de,namlen) \ + ALIGN((((char *)&(de)->d_name - (char *)de) + (namlen) + 1)) - if (vp->v_type != VDIR) - return (EINVAL); +#define LINUX_DIRBLKSIZ 512 - if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p))) { - return error; - } +static int +getdents_common(struct proc *p, struct linux_getdents64_args *args, + int is64bit) +{ + register struct dirent *bdp; + struct vnode *vp; + caddr_t inp, buf; /* BSD-format */ + int len, reclen; /* BSD-format */ + caddr_t outp; /* Linux-format */ + int resid, linuxreclen=0; /* Linux-format */ + struct file *fp; + struct uio auio; + struct iovec aiov; + struct vattr va; + off_t off; + struct l_dirent linux_dirent; + struct l_dirent64 linux_dirent64; + int buflen, error, eofflag, nbytes, justone; + u_long *cookies = NULL, *cookiep; + int ncookies; + + if ((error = getvnode(p->p_fd, args->fd, &fp)) != 0) + return (error); + + if ((fp->f_flag & FREAD) == 0) + return (EBADF); + + vp = (struct vnode *) fp->f_data; + if (vp->v_type != VDIR) + return (EINVAL); + + if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p))) + return (error); + + nbytes = args->count; + if (nbytes == 1) { + /* readdir(2) case. Always struct dirent. */ + if (is64bit) + return (EINVAL); + nbytes = sizeof(linux_dirent); + justone = 1; + } else + justone = 0; + + off = fp->f_offset; + + buflen = max(LINUX_DIRBLKSIZ, nbytes); + buflen = min(buflen, MAXBSIZE); + buf = malloc(buflen, M_TEMP, M_WAITOK); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - nbytes = args->count; - if (nbytes == 1) { - nbytes = sizeof (struct linux_dirent); - justone = 1; - } - else - justone = 0; - - off = fp->f_offset; -#define DIRBLKSIZ 512 /* XXX we used to use ufs's DIRBLKSIZ */ - buflen = max(DIRBLKSIZ, nbytes); - buflen = min(buflen, MAXBSIZE); - buf = malloc(buflen, M_TEMP, M_WAITOK); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); again: - aiov.iov_base = buf; - aiov.iov_len = buflen; - auio.uio_iov = &aiov; - auio.uio_iovcnt = 1; - auio.uio_rw = UIO_READ; - auio.uio_segflg = UIO_SYSSPACE; - auio.uio_procp = p; - auio.uio_resid = buflen; - auio.uio_offset = off; - - if (cookies) { - free(cookies, M_TEMP); - cookies = NULL; - } - - error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, &cookies); - if (error) { - goto out; - } - - inp = buf; - outp = (caddr_t) args->dent; - resid = nbytes; - if ((len = buflen - auio.uio_resid) <= 0) { - goto eof; - } - - cookiep = cookies; - - if (cookies) { - /* - * When using cookies, the vfs has the option of reading from - * a different offset than that supplied (UFS truncates the - * offset to a block boundary to make sure that it never reads - * partway through a directory entry, even if the directory - * has been compacted). - */ - while (len > 0 && ncookies > 0 && *cookiep <= off) { - bdp = (struct dirent *) inp; - len -= bdp->d_reclen; - inp += bdp->d_reclen; - cookiep++; - ncookies--; - } - } - - while (len > 0) { - if (cookiep && ncookies == 0) - break; - bdp = (struct dirent *) inp; - reclen = bdp->d_reclen; - if (reclen & 3) { - printf("linux_readdir: reclen=%d\n", reclen); - error = EFAULT; - goto out; - } - - if (bdp->d_fileno == 0) { - inp += reclen; - if (cookiep) { - off = *cookiep++; - ncookies--; - } else - off += reclen; - len -= reclen; - continue; - } - linuxreclen = LINUX_RECLEN(&linux_dirent, bdp->d_namlen); - if (reclen > len || resid < linuxreclen) { - outp++; - break; + aiov.iov_base = buf; + aiov.iov_len = buflen; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_rw = UIO_READ; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_procp = p; + auio.uio_resid = buflen; + auio.uio_offset = off; + + if (cookies) { + free(cookies, M_TEMP); + cookies = NULL; } - linux_dirent.dino = (long) bdp->d_fileno; - if (justone) { - /* - * old linux-style readdir usage. - */ - linux_dirent.doff = (linux_off_t) linuxreclen; - linux_dirent.dreclen = (u_short) bdp->d_namlen; - } else { - if (cookiep) - linux_dirent.doff = (linux_off_t)*cookiep; - else - linux_dirent.doff = (linux_off_t)(off + reclen); - linux_dirent.dreclen = (u_short) linuxreclen; + + if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, + &cookies))) + goto out; + + inp = buf; + outp = (caddr_t)args->dirent; + resid = nbytes; + if ((len = buflen - auio.uio_resid) <= 0) + goto eof; + + cookiep = cookies; + + if (cookies) { + /* + * When using cookies, the vfs has the option of reading from + * a different offset than that supplied (UFS truncates the + * offset to a block boundary to make sure that it never reads + * partway through a directory entry, even if the directory + * has been compacted). + */ + while (len > 0 && ncookies > 0 && *cookiep <= off) { + bdp = (struct dirent *) inp; + len -= bdp->d_reclen; + inp += bdp->d_reclen; + cookiep++; + ncookies--; + } } - strcpy(linux_dirent.dname, bdp->d_name); - if ((error = copyout((caddr_t)&linux_dirent, outp, linuxreclen))) { - goto out; + + while (len > 0) { + if (cookiep && ncookies == 0) + break; + bdp = (struct dirent *) inp; + reclen = bdp->d_reclen; + if (reclen & 3) { + error = EFAULT; + goto out; + } + + if (bdp->d_fileno == 0) { + inp += reclen; + if (cookiep) { + off = *cookiep++; + ncookies--; + } else + off += reclen; + + len -= reclen; + continue; + } + + linuxreclen = (is64bit) + ? LINUX_RECLEN(&linux_dirent64, bdp->d_namlen) + : LINUX_RECLEN(&linux_dirent, bdp->d_namlen); + + if (reclen > len || resid < linuxreclen) { + outp++; + break; + } + + if (justone) { + /* readdir(2) case. */ + linux_dirent.d_ino = (l_long)bdp->d_fileno; + linux_dirent.d_off = (l_off_t)linuxreclen; + linux_dirent.d_reclen = (l_ushort)bdp->d_namlen; + strcpy(linux_dirent.d_name, bdp->d_name); + error = copyout(&linux_dirent, outp, linuxreclen); + } else { + if (is64bit) { + linux_dirent64.d_ino = bdp->d_fileno; + linux_dirent64.d_off = (cookiep) + ? (l_off_t)*cookiep + : (l_off_t)(off + reclen); + linux_dirent64.d_reclen = + (l_ushort)linuxreclen; + linux_dirent64.d_type = bdp->d_type; + strcpy(linux_dirent64.d_name, bdp->d_name); + error = copyout(&linux_dirent64, outp, + linuxreclen); + } else { + linux_dirent.d_ino = bdp->d_fileno; + linux_dirent.d_off = (cookiep) + ? (l_off_t)*cookiep + : (l_off_t)(off + reclen); + linux_dirent.d_reclen = (l_ushort)linuxreclen; + strcpy(linux_dirent.d_name, bdp->d_name); + error = copyout(&linux_dirent, outp, + linuxreclen); + } + } + if (error) + goto out; + + inp += reclen; + if (cookiep) { + off = *cookiep++; + ncookies--; + } else + off += reclen; + + outp += linuxreclen; + resid -= linuxreclen; + len -= reclen; + if (justone) + break; } - inp += reclen; - if (cookiep) { - off = *cookiep++; - ncookies--; - } else - off += reclen; - outp += linuxreclen; - resid -= linuxreclen; - len -= reclen; - if (justone) - break; - } - if (outp == (caddr_t) args->dent) - goto again; - fp->f_offset = off; + if (outp == (caddr_t)args->dirent) + goto again; - if (justone) - nbytes = resid + linuxreclen; + fp->f_offset = off; + if (justone) + nbytes = resid + linuxreclen; eof: - p->p_retval[0] = nbytes - resid; + p->p_retval[0] = nbytes - resid; + out: - if (cookies) - free(cookies, M_TEMP); - VOP_UNLOCK(vp, 0, p); - free(buf, M_TEMP); - return error; + if (cookies) + free(cookies, M_TEMP); + + VOP_UNLOCK(vp, 0, p); + free(buf, M_TEMP); + return (error); +} + +int +linux_getdents(struct proc *p, struct linux_getdents_args *args) +{ + +#ifdef DEBUG + if (ldebug(getdents)) + printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count); +#endif + + return (getdents_common(p, (struct linux_getdents64_args*)args, 0)); +} + +int +linux_getdents64(struct proc *p, struct linux_getdents64_args *args) +{ + +#ifdef DEBUG + if (ldebug(getdents64)) + printf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count); +#endif + + return (getdents_common(p, args, 1)); } /* @@ -649,50 +541,6 @@ linux_chmod(struct proc *p, struct linux_chmod_args *args) } int -linux_chown(struct proc *p, struct linux_chown_args *args) -{ - struct chown_args bsd; - caddr_t sg; - - sg = stackgap_init(); - CHECKALTEXIST(p, &sg, args->path); - -#ifdef DEBUG - if (ldebug(chown)) - printf(ARGS(chown, "%s, %d, %d"), - args->path, args->uid, args->gid); -#endif - bsd.path = args->path; - /* XXX size casts here */ - bsd.uid = args->uid; - bsd.gid = args->gid; - - return chown(p, &bsd); -} - -int -linux_lchown(struct proc *p, struct linux_lchown_args *args) -{ - struct lchown_args bsd; - caddr_t sg; - - sg = stackgap_init(); - CHECKALTEXIST(p, &sg, args->path); - -#ifdef DEBUG - if (ldebug(lchown)) - printf(ARGS(lchown, "%s, %d, %d"), - args->path, args->uid, args->gid); -#endif - bsd.path = args->path; - /* XXX size casts here */ - bsd.uid = args->uid; - bsd.gid = args->gid; - - return lchown(p, &bsd); -} - -int linux_mkdir(struct proc *p, struct linux_mkdir_args *args) { struct mkdir_args bsd; @@ -801,7 +649,8 @@ linux_truncate(struct proc *p, struct linux_truncate_args *args) #ifdef DEBUG if (ldebug(truncate)) - printf(ARGS(truncate, "%s, %ld"), args->path, args->length); + printf(ARGS(truncate, "%s, %ld"), args->path, + (long)args->length); #endif bsd.path = args->path; bsd.length = args->length; @@ -937,17 +786,17 @@ linux_mount(struct proc *p, struct linux_mount_args *args) } int -linux_umount(struct proc *p, struct linux_umount_args *args) +linux_oldumount(struct proc *p, struct linux_oldumount_args *args) { - struct linux_umount2_args args2; + struct linux_umount_args args2; args2.path = args->path; args2.flags = 0; - return (linux_umount2(p, &args2)); + return (linux_umount(p, &args2)); } int -linux_umount2(struct proc *p, struct linux_umount2_args *args) +linux_umount(struct proc *p, struct linux_umount_args *args) { struct unmount_args bsd; @@ -955,3 +804,325 @@ linux_umount2(struct proc *p, struct linux_umount2_args *args) bsd.flags = args->flags; /* XXX correct? */ return (unmount(p, &bsd)); } + +/* + * fcntl family of syscalls + */ + +struct l_flock { + l_short l_type; + l_short l_whence; + l_off_t l_start; + l_off_t l_len; + l_pid_t l_pid; +}; + +static void +linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock) +{ + switch (linux_flock->l_type) { + case LINUX_F_RDLCK: + bsd_flock->l_type = F_RDLCK; + break; + case LINUX_F_WRLCK: + bsd_flock->l_type = F_WRLCK; + break; + case LINUX_F_UNLCK: + bsd_flock->l_type = F_UNLCK; + break; + default: + bsd_flock->l_type = -1; + break; + } + bsd_flock->l_whence = linux_flock->l_whence; + bsd_flock->l_start = (off_t)linux_flock->l_start; + bsd_flock->l_len = (off_t)linux_flock->l_len; + bsd_flock->l_pid = (pid_t)linux_flock->l_pid; +} + +static void +bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock) +{ + switch (bsd_flock->l_type) { + case F_RDLCK: + linux_flock->l_type = LINUX_F_RDLCK; + break; + case F_WRLCK: + linux_flock->l_type = LINUX_F_WRLCK; + break; + case F_UNLCK: + linux_flock->l_type = LINUX_F_UNLCK; + break; + } + linux_flock->l_whence = bsd_flock->l_whence; + linux_flock->l_start = (l_off_t)bsd_flock->l_start; + linux_flock->l_len = (l_off_t)bsd_flock->l_len; + linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid; +} + +#if defined(__i386__) +struct l_flock64 { + l_short l_type; + l_short l_whence; + l_loff_t l_start; + l_loff_t l_len; + l_pid_t l_pid; +}; + +static void +linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock) +{ + switch (linux_flock->l_type) { + case LINUX_F_RDLCK: + bsd_flock->l_type = F_RDLCK; + break; + case LINUX_F_WRLCK: + bsd_flock->l_type = F_WRLCK; + break; + case LINUX_F_UNLCK: + bsd_flock->l_type = F_UNLCK; + break; + default: + bsd_flock->l_type = -1; + break; + } + bsd_flock->l_whence = linux_flock->l_whence; + bsd_flock->l_start = (off_t)linux_flock->l_start; + bsd_flock->l_len = (off_t)linux_flock->l_len; + bsd_flock->l_pid = (pid_t)linux_flock->l_pid; +} + +static void +bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock) +{ + switch (bsd_flock->l_type) { + case F_RDLCK: + linux_flock->l_type = LINUX_F_RDLCK; + break; + case F_WRLCK: + linux_flock->l_type = LINUX_F_WRLCK; + break; + case F_UNLCK: + linux_flock->l_type = LINUX_F_UNLCK; + break; + } + linux_flock->l_whence = bsd_flock->l_whence; + linux_flock->l_start = (l_loff_t)bsd_flock->l_start; + linux_flock->l_len = (l_loff_t)bsd_flock->l_len; + linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid; +} +#endif /* __i386__ */ + +#if defined(__alpha__) +#define linux_fcntl64_args linux_fcntl_args +#endif + +static int +fcntl_common(struct proc *p, struct linux_fcntl64_args *args) +{ + struct fcntl_args fcntl_args; + struct filedesc *fdp; + struct file *fp; + int error, result; + + fcntl_args.fd = args->fd; + + switch (args->cmd) { + case LINUX_F_DUPFD: + fcntl_args.cmd = F_DUPFD; + fcntl_args.arg = args->arg; + return (fcntl(p, &fcntl_args)); + + case LINUX_F_GETFD: + fcntl_args.cmd = F_GETFD; + return (fcntl(p, &fcntl_args)); + + case LINUX_F_SETFD: + fcntl_args.cmd = F_SETFD; + fcntl_args.arg = args->arg; + return (fcntl(p, &fcntl_args)); + + case LINUX_F_GETFL: + fcntl_args.cmd = F_GETFL; + error = fcntl(p, &fcntl_args); + result = p->p_retval[0]; + p->p_retval[0] = 0; + if (result & O_RDONLY) + p->p_retval[0] |= LINUX_O_RDONLY; + if (result & O_WRONLY) + p->p_retval[0] |= LINUX_O_WRONLY; + if (result & O_RDWR) + p->p_retval[0] |= LINUX_O_RDWR; + if (result & O_NDELAY) + p->p_retval[0] |= LINUX_O_NONBLOCK; + if (result & O_APPEND) + p->p_retval[0] |= LINUX_O_APPEND; + if (result & O_FSYNC) + p->p_retval[0] |= LINUX_O_SYNC; + if (result & O_ASYNC) + p->p_retval[0] |= LINUX_FASYNC; + return (error); + + case LINUX_F_SETFL: + fcntl_args.arg = 0; + if (args->arg & LINUX_O_NDELAY) + fcntl_args.arg |= O_NONBLOCK; + if (args->arg & LINUX_O_APPEND) + fcntl_args.arg |= O_APPEND; + if (args->arg & LINUX_O_SYNC) + fcntl_args.arg |= O_FSYNC; + if (args->arg & LINUX_FASYNC) + fcntl_args.arg |= O_ASYNC; + fcntl_args.cmd = F_SETFL; + return (fcntl(p, &fcntl_args)); + + case LINUX_F_GETOWN: + fcntl_args.cmd = F_GETOWN; + return (fcntl(p, &fcntl_args)); + + case LINUX_F_SETOWN: + /* + * XXX some Linux applications depend on F_SETOWN having no + * significant effect for pipes (SIGIO is not delivered for + * pipes under Linux-2.2.35 at least). + */ + fdp = p->p_fd; + if ((u_int)args->fd >= fdp->fd_nfiles || + (fp = fdp->fd_ofiles[args->fd]) == NULL) + return (EBADF); + if (fp->f_type == DTYPE_PIPE) + return (EINVAL); + + fcntl_args.cmd = F_SETOWN; + fcntl_args.arg = args->arg; + return (fcntl(p, &fcntl_args)); + } + + return (EINVAL); +} + +int +linux_fcntl(struct proc *p, struct linux_fcntl_args *args) +{ + struct linux_fcntl64_args args64; + struct fcntl_args fcntl_args; + struct l_flock linux_flock; + struct flock *bsd_flock; + int error; + caddr_t sg; + + sg = stackgap_init(); + bsd_flock = (struct flock *)stackgap_alloc(&sg, sizeof(bsd_flock)); + +#ifdef DEBUG + if (ldebug(fcntl)) + printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd); +#endif + + switch (args->cmd) { + case LINUX_F_GETLK: + error = copyin((caddr_t)args->arg, &linux_flock, + sizeof(linux_flock)); + if (error) + return (error); + linux_to_bsd_flock(&linux_flock, bsd_flock); + fcntl_args.fd = args->fd; + fcntl_args.cmd = F_GETLK; + fcntl_args.arg = (long)bsd_flock; + error = fcntl(p, &fcntl_args); + if (error) + return (error); + bsd_to_linux_flock(bsd_flock, &linux_flock); + return (copyout(&linux_flock, (caddr_t)args->arg, + sizeof(linux_flock))); + + case LINUX_F_SETLK: + error = copyin((caddr_t)args->arg, &linux_flock, + sizeof(linux_flock)); + if (error) + return (error); + linux_to_bsd_flock(&linux_flock, bsd_flock); + fcntl_args.fd = args->fd; + fcntl_args.cmd = F_SETLK; + fcntl_args.arg = (long)bsd_flock; + return (fcntl(p, &fcntl_args)); + + case LINUX_F_SETLKW: + error = copyin((caddr_t)args->arg, &linux_flock, + sizeof(linux_flock)); + if (error) + return (error); + linux_to_bsd_flock(&linux_flock, bsd_flock); + fcntl_args.fd = args->fd; + fcntl_args.cmd = F_SETLKW; + fcntl_args.arg = (long)bsd_flock; + return (fcntl(p, &fcntl_args)); + } + + args64.fd = args->fd; + args64.cmd = args->cmd; + args64.arg = args->arg; + return (fcntl_common(p, &args64)); +} + +#if defined(__i386__) +int +linux_fcntl64(struct proc *p, struct linux_fcntl64_args *args) +{ + struct fcntl_args fcntl_args; + struct l_flock64 linux_flock; + struct flock *bsd_flock; + int error; + caddr_t sg; + + sg = stackgap_init(); + bsd_flock = (struct flock *)stackgap_alloc(&sg, sizeof(bsd_flock)); + +#ifdef DEBUG + if (ldebug(fcntl64)) + printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd); +#endif + + switch (args->cmd) { + case LINUX_F_GETLK: + error = copyin((caddr_t)args->arg, &linux_flock, + sizeof(linux_flock)); + if (error) + return (error); + linux_to_bsd_flock64(&linux_flock, bsd_flock); + fcntl_args.fd = args->fd; + fcntl_args.cmd = F_GETLK; + fcntl_args.arg = (long)bsd_flock; + error = fcntl(p, &fcntl_args); + if (error) + return (error); + bsd_to_linux_flock64(bsd_flock, &linux_flock); + return (copyout(&linux_flock, (caddr_t)args->arg, + sizeof(linux_flock))); + + case LINUX_F_SETLK: + error = copyin((caddr_t)args->arg, &linux_flock, + sizeof(linux_flock)); + if (error) + return (error); + linux_to_bsd_flock64(&linux_flock, bsd_flock); + fcntl_args.fd = args->fd; + fcntl_args.cmd = F_SETLK; + fcntl_args.arg = (long)bsd_flock; + return (fcntl(p, &fcntl_args)); + + case LINUX_F_SETLKW: + error = copyin((caddr_t)args->arg, &linux_flock, + sizeof(linux_flock)); + if (error) + return (error); + linux_to_bsd_flock64(&linux_flock, bsd_flock); + fcntl_args.fd = args->fd; + fcntl_args.cmd = F_SETLKW; + fcntl_args.arg = (long)bsd_flock; + return (fcntl(p, &fcntl_args)); + } + + return (fcntl_common(p, args)); +} +#endif /* __i386__ */ |