summaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/sys_sunos32.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64/kernel/sys_sunos32.c')
-rw-r--r--arch/sparc64/kernel/sys_sunos32.c130
1 files changed, 102 insertions, 28 deletions
diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c
index 4af388b99..ad7bac534 100644
--- a/arch/sparc64/kernel/sys_sunos32.c
+++ b/arch/sparc64/kernel/sys_sunos32.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos32.c,v 1.7 1997/12/11 15:15:19 jj Exp $
+/* $Id: sys_sunos32.c,v 1.11 1998/03/29 10:10:55 davem Exp $
* sys_sunos32.c: SunOS binary compatability layer on sparc64.
*
* Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -16,6 +16,7 @@
#include <linux/mm.h>
#include <linux/swap.h>
#include <linux/fs.h>
+#include <linux/file.h>
#include <linux/resource.h>
#include <linux/ipc.h>
#include <linux/shm.h>
@@ -70,23 +71,30 @@ asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 of
flags &= ~MAP_NORESERVE;
}
retval = -EBADF;
- if(!(flags & MAP_ANONYMOUS))
- if(fd >= SUNOS_NR_OPEN || !(file = current->files->fd[fd]))
+ if(!(flags & MAP_ANONYMOUS)) {
+ if(fd >= SUNOS_NR_OPEN)
goto out;
+ file = fget(fd);
+ if (!file)
+ goto out;
+ if (file->f_dentry && file->f_dentry->d_inode) {
+ struct inode * inode = file->f_dentry->d_inode;
+ if(MAJOR(inode->i_rdev) == MEM_MAJOR &&
+ MINOR(inode->i_rdev) == 5) {
+ flags |= MAP_ANONYMOUS;
+ fput(file);
+ file = NULL;
+ }
+ }
+ }
+
retval = -ENOMEM;
if(!(flags & MAP_FIXED) && !addr) {
unsigned long attempt = get_unmapped_area(addr, len);
if(!attempt || (attempt >= 0xf0000000UL))
- goto out;
+ goto out_putf;
addr = (u32) attempt;
}
- if(file->f_dentry && file->f_dentry->d_inode) {
- if(MAJOR(file->f_dentry->d_inode->i_rdev) == MEM_MAJOR &&
- MINOR(file->f_dentry->d_inode->i_rdev) == 5) {
- flags |= MAP_ANONYMOUS;
- file = 0;
- }
- }
if(!(flags & MAP_FIXED))
addr = 0;
ret_type = flags & _MAP_NEW;
@@ -98,6 +106,9 @@ asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 of
(unsigned long) off);
if(!ret_type)
retval = ((retval < 0xf0000000) ? 0 : retval);
+out_putf:
+ if (file)
+ fput(file);
out:
unlock_kernel();
return (u32) retval;
@@ -372,6 +383,7 @@ static int sunos_filldir(void * __buf, const char * name, int namlen,
asmlinkage int sunos_getdents(unsigned int fd, u32 u_dirent, int cnt)
{
struct file * file;
+ struct inode * inode;
struct sunos_dirent * lastdirent;
struct sunos_dirent_callback buf;
int error = -EBADF;
@@ -381,32 +393,39 @@ asmlinkage int sunos_getdents(unsigned int fd, u32 u_dirent, int cnt)
if(fd >= SUNOS_NR_OPEN)
goto out;
- file = current->files->fd[fd];
+ file = fget(fd);
if(!file)
goto out;
error = -ENOTDIR;
if (!file->f_op || !file->f_op->readdir)
- goto out;
+ goto out_putf;
error = -EINVAL;
if(cnt < (sizeof(struct sunos_dirent) + 255))
- goto out;
+ goto out_putf;
buf.curr = (struct sunos_dirent *) dirent;
buf.previous = NULL;
buf.count = cnt;
buf.error = 0;
+ inode = file->f_dentry->d_inode;
+ down(&inode->i_sem);
error = file->f_op->readdir(file, &buf, sunos_filldir);
+ up(&inode->i_sem);
if (error < 0)
- goto out;
+ goto out_putf;
+
lastdirent = buf.previous;
error = buf.error;
if (lastdirent) {
put_user(file->f_pos, &lastdirent->d_off);
error = cnt - buf.count;
}
+
+out_putf:
+ fput(file);
out:
unlock_kernel();
return error;
@@ -454,43 +473,51 @@ static int sunos_filldirentry(void * __buf, const char * name, int namlen,
asmlinkage int sunos_getdirentries(unsigned int fd, u32 u_dirent,
int cnt, u32 u_basep)
{
+ void *dirent = (void *) A(u_dirent);
+ unsigned int *basep = (unsigned int *)A(u_basep);
struct file * file;
+ struct inode * inode;
struct sunos_direntry * lastdirent;
- struct sunos_direntry_callback buf;
int error = -EBADF;
- void *dirent = (void *) A(u_dirent);
- unsigned int *basep = (unsigned int *)A(u_basep);
+ struct sunos_direntry_callback buf;
lock_kernel();
if(fd >= SUNOS_NR_OPEN)
goto out;
- file = current->files->fd[fd];
+ file = fget(fd);
if(!file)
goto out;
error = -ENOTDIR;
if (!file->f_op || !file->f_op->readdir)
- goto out;
+ goto out_putf;
error = -EINVAL;
if(cnt < (sizeof(struct sunos_direntry) + 255))
- goto out;
+ goto out_putf;
buf.curr = (struct sunos_direntry *) dirent;
buf.previous = NULL;
buf.count = cnt;
buf.error = 0;
+ inode = file->f_dentry->d_inode;
+ down(&inode->i_sem);
error = file->f_op->readdir(file, &buf, sunos_filldirentry);
+ up(&inode->i_sem);
if (error < 0)
- goto out;
+ goto out_putf;
+
lastdirent = buf.previous;
error = buf.error;
if (lastdirent) {
put_user(file->f_pos, basep);
error = cnt - buf.count;
}
+
+out_putf:
+ fput(file);
out:
unlock_kernel();
return error;
@@ -622,14 +649,28 @@ asmlinkage int sunos_pathconf(u32 u_path, int name)
extern asmlinkage int
sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp);
-asmlinkage int sunos_select(int width, u32 inp, u32 outp, u32 exp, u32 tvp)
+struct timeval32
+{
+ int tv_sec, tv_usec;
+};
+
+asmlinkage int sunos_select(int width, u32 inp, u32 outp, u32 exp, u32 tvp_x)
{
int ret;
/* SunOS binaries expect that select won't change the tvp contents */
lock_kernel();
current->personality |= STICKY_TIMEOUTS;
- ret = sys32_select (width, inp, outp, exp, tvp);
+ ret = sys32_select (width, inp, outp, exp, tvp_x);
+ if (ret == -EINTR && tvp_x) {
+ struct timeval32 *tvp = (struct timeval32 *)A(tvp_x);
+ time_t sec, usec;
+
+ __get_user(sec, &tvp->tv_sec);
+ __get_user(usec, &tvp->tv_usec);
+ if (sec == 0 && usec == 0)
+ ret = 0;
+ }
unlock_kernel();
return ret;
}
@@ -1297,8 +1338,11 @@ asmlinkage int sunos_open(u32 filename, int flags, int mode)
static inline int check_nonblock(int ret, int fd)
{
- if (ret == -EAGAIN && (current->files->fd[fd]->f_flags & O_NDELAY))
- return -SUNOS_EWOULDBLOCK;
+ if (ret == -EAGAIN) {
+ struct file * file = fcheck(fd);
+ if (file && (file->f_flags & O_NDELAY))
+ ret = -SUNOS_EWOULDBLOCK;
+ }
return ret;
}
@@ -1370,12 +1414,42 @@ asmlinkage int sunos_send(int fd, u32 buff, int len, unsigned flags)
return ret;
}
+extern asmlinkage int sys_setsockopt(int fd, int level, int optname,
+ char *optval, int optlen);
+
+asmlinkage int sunos_socket(int family, int type, int protocol)
+{
+ int ret, one = 1;
+
+ lock_kernel();
+ ret = sys_socket(family, type, protocol);
+ if (ret < 0)
+ goto out;
+
+ sys_setsockopt(ret, SOL_SOCKET, SO_BSDCOMPAT,
+ (char *)&one, sizeof(one));
+out:
+ unlock_kernel();
+ return ret;
+}
+
asmlinkage int sunos_accept(int fd, u32 sa, u32 addrlen)
{
- int ret;
+ int ret, one = 1;
lock_kernel();
- ret = check_nonblock(sys_accept(fd, (struct sockaddr *)A(sa), (int *)A(addrlen)), fd);
+ while (1) {
+ ret = check_nonblock(sys_accept(fd, (struct sockaddr *)A(sa),
+ (int *)A(addrlen)), fd);
+ if (ret != -ENETUNREACH && ret != -EHOSTUNREACH)
+ break;
+ }
+ if (ret < 0)
+ goto out;
+
+ sys_setsockopt(ret, SOL_SOCKET, SO_BSDCOMPAT,
+ (char *)&one, sizeof(one));
+out:
unlock_kernel();
return ret;
}