summaryrefslogtreecommitdiffstats
path: root/sys/compat/linux/linux_file.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/compat/linux/linux_file.c')
-rw-r--r--sys/compat/linux/linux_file.c945
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__ */
OpenPOWER on IntegriCloud