patch-2.1.36 linux/arch/sparc64/kernel/sys_sparc32.c

Next file: linux/arch/sparc64/kernel/systbls.S
Previous file: linux/arch/sparc64/kernel/sparcelf32.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.35/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.3 1997/04/09 08:25:17 jj Exp $
+/* $Id: sys_sparc32.c,v 1.9 1997/04/21 08:34:24 jj Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -14,6 +14,7 @@
 #include <linux/resource.h>
 #include <linux/sched.h>
 #include <linux/times.h>
+#include <linux/utime.h>
 #include <linux/utsname.h>
 #include <linux/timex.h>
 #include <linux/smp.h>
@@ -21,6 +22,11 @@
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
+#include <linux/malloc.h>
+#include <linux/uio.h>
+#include <linux/nfs_fs.h>
+#include <linux/smb_fs.h>
+#include <linux/ncp_fs.h>
 
 #include <asm/types.h>
 #include <asm/poll.h>
@@ -32,9 +38,6 @@
  * produce warnings */
 #define A(x) ((unsigned long)x)
  
-/* FIXME: All struct * etc. stuff should be examined and proper structure conversions
- * added ASAP -JJ */
-
 extern asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on);
 extern asmlinkage unsigned long sys_brk(unsigned long brk);
 extern asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long off);
@@ -69,7 +72,6 @@
 extern asmlinkage long sys_write(unsigned int fd, const char * buf, unsigned long count);
 extern asmlinkage long sys_readv(unsigned long fd, const struct iovec * vector, unsigned long count);
 extern asmlinkage long sys_writev(unsigned long fd, const struct iovec * vector, unsigned long count);
-extern asmlinkage int sys_getdents(unsigned int fd, void * dirent, unsigned int count);
 extern asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp);
 extern asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, int timeout);
 extern asmlinkage int sys_newstat(char * filename, struct stat * statbuf);
@@ -102,7 +104,6 @@
 extern asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist);
 extern asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist);
 extern asmlinkage int sys_newuname(struct new_utsname * name);
-extern asmlinkage int sys_uname(struct old_utsname * name);
 extern asmlinkage int sys_olduname(struct oldold_utsname * name);
 extern asmlinkage int sys_sethostname(char *name, int len);
 extern asmlinkage int sys_gethostname(char *name, int len);
@@ -136,12 +137,57 @@
 extern asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned flags);
 extern asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags);
 extern asmlinkage int sys_socketcall(int call, unsigned long *args);
+extern asmlinkage int sys_nfsservctl(int cmd, void *argp, void *resp);
 
 asmlinkage int sys32_ioperm(u32 from, u32 num, int on)
 {
 	return sys_ioperm((unsigned long)from, (unsigned long)num, on);
 }
 
+struct msgbuf32 { s32 mtype; char mtext[1]; };
+
+struct ipc_perm32
+{
+	key_t    	  key;
+        __kernel_uid_t32  uid;
+        __kernel_gid_t32  gid;
+        __kernel_uid_t32  cuid;
+        __kernel_gid_t32  cgid;
+        __kernel_mode_t32 mode;
+        unsigned short  seq;
+};
+
+struct msqid_ds32
+{
+        struct ipc_perm32 msg_perm;
+        u32 msg_first;
+        u32 msg_last;
+        __kernel_time_t32 msg_stime;
+        __kernel_time_t32 msg_rtime;
+        __kernel_time_t32 msg_ctime;
+        u32 wwait;
+        u32 rwait;
+        unsigned short msg_cbytes;
+        unsigned short msg_qnum;  
+        unsigned short msg_qbytes;
+        __kernel_ipc_pid_t32 msg_lspid;
+        __kernel_ipc_pid_t32 msg_lrpid;
+};
+
+struct shmid_ds32 {
+        struct ipc_perm32       shm_perm;
+        int                     shm_segsz;
+        __kernel_time_t32       shm_atime;
+        __kernel_time_t32       shm_dtime;
+        __kernel_time_t32       shm_ctime;
+        __kernel_ipc_pid_t32    shm_cpid; 
+        __kernel_ipc_pid_t32    shm_lpid; 
+        unsigned short          shm_nattch;
+        unsigned short          shm_npages;
+        u32			shm_pages;
+        u32			attaches; 
+};
+                                                        
 /*
  * sys32_ipc() is the de-multiplexer for the SysV IPC calls in 32bit emulation..
  *
@@ -184,32 +230,111 @@
 	if (call <= MSGCTL) 
 		switch (call) {
 		case MSGSND:
-			/* XXX struct msgbuf has a long first :(( */
-			err = sys_msgsnd (first, (struct msgbuf *) A(ptr), 
-					  second, third);
+			{
+				struct msgbuf *p = kmalloc (second + sizeof (struct msgbuf), GFP_KERNEL);
+				
+				if (!p) err = -ENOMEM;
+				else {
+					if (get_user(p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
+					    __copy_from_user(p->mtext, &(((struct msgbuf32 *)A(ptr))->mtext), second))
+						err = -EFAULT;
+					else {
+						unsigned long old_fs = get_fs();
+						set_fs (KERNEL_DS);
+						err = sys_msgsnd (first, p, second, third);
+						set_fs (old_fs);
+					}
+					kfree (p);
+				}
+			}
 			goto out;
 		case MSGRCV:
-			switch (version) {
-			case 0: {
-				struct ipc_kludge tmp;
-				err = -EINVAL;
-				if (!ptr)
-					goto out;
-				err = -EFAULT;
-				if(copy_from_user(&tmp,(struct ipc_kludge *) ptr, sizeof (tmp)))
+			{
+				struct msgbuf *p;
+				unsigned long old_fs;
+				
+				if (!version) {
+					struct ipc_kludge tmp;
+					err = -EINVAL;
+					if (!ptr)
+						goto out;
+					err = -EFAULT;
+					if(copy_from_user(&tmp,(struct ipc_kludge *)A(ptr), sizeof (tmp)))
+						goto out;
+					ptr = tmp.msgp;
+					fifth = tmp.msgtyp;
+				}
+				p = kmalloc (second + sizeof (struct msgbuf), GFP_KERNEL);
+				if (!p) {
+					err = -EFAULT;
 					goto out;
-				err = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
-				goto out;
 				}
-			case 1: default:
-				err = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third);
+				old_fs = get_fs();
+				set_fs (KERNEL_DS);
+				err = sys_msgrcv (first, p, second, fifth, third);
+				set_fs (old_fs);
+				if (put_user (p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
+				    __copy_to_user(&(((struct msgbuf32 *)A(ptr))->mtext), p->mtext, second))
+					err = -EFAULT;
+				kfree (p);
 				goto out;
 			}
 		case MSGGET:
 			err = sys_msgget ((key_t) first, second);
 			goto out;
 		case MSGCTL:
-			err = sys_msgctl (first, second, (struct msqid_ds *) ptr);
+			{
+				struct msqid_ds m;
+				unsigned long old_fs;
+				
+				switch (second) {
+					case IPC_INFO:
+					case MSG_INFO:
+						/* struct msginfo is the same */
+					case IPC_RMID:
+						/* and this doesn't care about ptr */
+						err = sys_msgctl (first, second, (struct msqid_ds *)A(ptr));
+						goto out;
+						
+					case IPC_SET:
+						if (get_user (m.msg_perm.uid, &(((struct msqid_ds32 *)A(ptr))->msg_perm.uid)) ||
+						    __get_user (m.msg_perm.gid, &(((struct msqid_ds32 *)A(ptr))->msg_perm.gid)) ||
+						    __get_user (m.msg_perm.mode, &(((struct msqid_ds32 *)A(ptr))->msg_perm.mode)) ||
+						    __get_user (m.msg_qbytes, &(((struct msqid_ds32 *)A(ptr))->msg_qbytes))) {
+							err = -EFAULT;  
+							goto out;
+						}
+					default:
+						break;
+				}
+				old_fs = get_fs();
+				set_fs (KERNEL_DS);
+				err = sys_msgctl (first, second, &m);
+				set_fs (old_fs);
+				switch (second) {
+					case MSG_STAT:
+					case IPC_STAT:
+						if (put_user (m.msg_perm.key, &(((struct msqid_ds32 *)A(ptr))->msg_perm.key)) ||
+						    __put_user (m.msg_perm.uid, &(((struct msqid_ds32 *)A(ptr))->msg_perm.uid)) ||
+						    __put_user (m.msg_perm.gid, &(((struct msqid_ds32 *)A(ptr))->msg_perm.gid)) ||
+						    __put_user (m.msg_perm.cuid, &(((struct msqid_ds32 *)A(ptr))->msg_perm.cuid)) ||
+						    __put_user (m.msg_perm.cgid, &(((struct msqid_ds32 *)A(ptr))->msg_perm.cgid)) ||
+						    __put_user (m.msg_perm.mode, &(((struct msqid_ds32 *)A(ptr))->msg_perm.mode)) ||
+						    __put_user (m.msg_perm.seq, &(((struct msqid_ds32 *)A(ptr))->msg_perm.seq)) ||
+						    __put_user (m.msg_stime, &(((struct msqid_ds32 *)A(ptr))->msg_stime)) ||
+						    __put_user (m.msg_rtime, &(((struct msqid_ds32 *)A(ptr))->msg_rtime)) ||
+						    __put_user (m.msg_ctime, &(((struct msqid_ds32 *)A(ptr))->msg_ctime)) ||
+						    __put_user (m.msg_cbytes, &(((struct msqid_ds32 *)A(ptr))->msg_cbytes)) ||
+						    __put_user (m.msg_qnum, &(((struct msqid_ds32 *)A(ptr))->msg_qnum)) ||
+						    __put_user (m.msg_qbytes, &(((struct msqid_ds32 *)A(ptr))->msg_qbytes)) ||
+						    __put_user (m.msg_lspid, &(((struct msqid_ds32 *)A(ptr))->msg_lspid)) ||
+						    __put_user (m.msg_lrpid, &(((struct msqid_ds32 *)A(ptr))->msg_lrpid)))
+							err = -EFAULT;
+						break;
+					default:
+						break;
+				}
+			}
 			goto out;
 		default:
 			err = -EINVAL;
@@ -220,28 +345,92 @@
 		case SHMAT:
 			switch (version) {
 			case 0: default: {
-				ulong raddr;
-				err = sys_shmat (first, (char *) ptr, second, &raddr);
+				unsigned long raddr;
+				err = sys_shmat (first, (char *)A(ptr), second, &raddr);
 				if (err)
 					goto out;
 				err = -EFAULT;
-				if(put_user (raddr, (ulong *) third))
+				if(put_user (raddr, ((u32 *)A(third))))
 					goto out;
 				err = 0;
 				goto out;
 				}
-			case 1:	/* iBCS2 emulator entry point */
-				err = sys_shmat (first, (char *) ptr, second, (ulong *) third);
+			case 1: /* If iBCS2 should ever run, then for sure in 64bit mode, not 32bit... */
+				err = -EINVAL;
 				goto out;
 			}
 		case SHMDT: 
-			err = sys_shmdt ((char *)ptr);
+			err = sys_shmdt ((char *)A(ptr));
 			goto out;
 		case SHMGET:
 			err = sys_shmget (first, second, third);
 			goto out;
 		case SHMCTL:
-			err = sys_shmctl (first, second, (struct shmid_ds *) ptr);
+			{
+				struct shmid_ds s;
+				unsigned long old_fs;
+				
+				switch (second) {
+					case IPC_INFO:
+						/* struct shminfo is the same */
+					case SHM_LOCK:
+					case SHM_UNLOCK:
+					case IPC_RMID:
+						/* and these three aren't using ptr at all */
+						err = sys_shmctl (first, second, (struct shmid_ds *)A(ptr));
+						goto out;
+						
+					case IPC_SET:
+						if (get_user (s.shm_perm.uid, &(((struct shmid_ds32 *)A(ptr))->shm_perm.uid)) ||
+						    __get_user (s.shm_perm.gid, &(((struct shmid_ds32 *)A(ptr))->shm_perm.gid)) ||
+						    __get_user (s.shm_perm.mode, &(((struct shmid_ds32 *)A(ptr))->shm_perm.mode))) {
+							err = -EFAULT; 
+							goto out;
+						}
+					default:
+						break;
+				}
+				old_fs = get_fs();
+				set_fs (KERNEL_DS);
+				err = sys_shmctl (first, second, &s);
+				set_fs (old_fs);
+				switch (second) {
+					case SHM_INFO:
+						{
+							struct shm_info32 { int used_ids; u32 shm_tot; u32 shm_rss; u32 shm_swp; u32 swap_attempts; u32 swap_successes; };
+							struct shm_info *si = (struct shm_info *)&s;
+
+							if (put_user (si->used_ids, &(((struct shm_info32 *)A(ptr))->used_ids)) ||
+							    __put_user (si->shm_tot, &(((struct shm_info32 *)A(ptr))->shm_tot)) ||
+							    __put_user (si->shm_rss, &(((struct shm_info32 *)A(ptr))->shm_rss)) ||
+							    __put_user (si->shm_swp, &(((struct shm_info32 *)A(ptr))->shm_swp)) ||
+							    __put_user (si->swap_attempts, &(((struct shm_info32 *)A(ptr))->swap_attempts)) ||
+							    __put_user (si->swap_successes, &(((struct shm_info32 *)A(ptr))->swap_successes)))
+								err = -EFAULT;
+						}
+						break;
+					case SHM_STAT:
+					case IPC_STAT:
+						if (put_user (s.shm_perm.key, &(((struct shmid_ds32 *)A(ptr))->shm_perm.key)) ||
+						    __put_user (s.shm_perm.uid, &(((struct shmid_ds32 *)A(ptr))->shm_perm.uid)) ||
+						    __put_user (s.shm_perm.gid, &(((struct shmid_ds32 *)A(ptr))->shm_perm.gid)) ||
+						    __put_user (s.shm_perm.cuid, &(((struct shmid_ds32 *)A(ptr))->shm_perm.cuid)) ||
+						    __put_user (s.shm_perm.cgid, &(((struct shmid_ds32 *)A(ptr))->shm_perm.cgid)) ||
+						    __put_user (s.shm_perm.mode, &(((struct shmid_ds32 *)A(ptr))->shm_perm.mode)) ||
+						    __put_user (s.shm_perm.seq, &(((struct shmid_ds32 *)A(ptr))->shm_perm.seq)) ||
+						    __put_user (s.shm_atime, &(((struct shmid_ds32 *)A(ptr))->shm_atime)) ||
+						    __put_user (s.shm_dtime, &(((struct shmid_ds32 *)A(ptr))->shm_dtime)) ||
+						    __put_user (s.shm_ctime, &(((struct shmid_ds32 *)A(ptr))->shm_ctime)) ||
+						    __put_user (s.shm_segsz, &(((struct shmid_ds32 *)A(ptr))->shm_segsz)) ||
+						    __put_user (s.shm_nattch, &(((struct shmid_ds32 *)A(ptr))->shm_nattch)) ||
+						    __put_user (s.shm_lpid, &(((struct shmid_ds32 *)A(ptr))->shm_cpid)) ||
+						    __put_user (s.shm_cpid, &(((struct shmid_ds32 *)A(ptr))->shm_lpid)))
+							err = -EFAULT;
+						break;
+					default:
+						break;
+				}
+			}
 			goto out;
 		default:
 			err = -EINVAL;
@@ -272,15 +461,45 @@
 
 asmlinkage long sys32_fcntl(unsigned int fd, unsigned int cmd, u32 arg)
 {
-	return sys_fcntl(fd, cmd, (unsigned long)arg);
+	switch (cmd) {
+	case F_GETLK:
+	case F_SETLK:
+	case F_SETLKW:
+		{
+			struct flock f;
+			unsigned long old_fs;
+			long ret;
+			
+			if (get_user (f.l_type, &(((struct flock32 *)A(arg))->l_type)) ||
+			    __get_user (f.l_whence, &(((struct flock32 *)A(arg))->l_whence)) ||
+			    __get_user (f.l_start, &(((struct flock32 *)A(arg))->l_start)) ||
+			    __get_user (f.l_len, &(((struct flock32 *)A(arg))->l_len)) ||
+			    __get_user (f.l_pid, &(((struct flock32 *)A(arg))->l_pid)))
+				return -EFAULT;
+			old_fs = get_fs(); set_fs (KERNEL_DS);
+			ret = sys_fcntl(fd, cmd, (unsigned long)&f);
+			set_fs (old_fs);
+   			if (__put_user (f.l_type, &(((struct flock32 *)A(arg))->l_type)) ||
+			    __put_user (f.l_whence, &(((struct flock32 *)A(arg))->l_whence)) ||
+			    __put_user (f.l_start, &(((struct flock32 *)A(arg))->l_start)) ||
+			    __put_user (f.l_len, &(((struct flock32 *)A(arg))->l_len)) ||
+			    __put_user (f.l_pid, &(((struct flock32 *)A(arg))->l_pid)))
+				return -EFAULT;
+			return ret;
+		}
+	default:
+		return sys_fcntl(fd, cmd, (unsigned long)arg);
+	}
 }
 
+/* Conversion of args should be probably done in all the locations where it is handled,
+   using if (current->tss.flags & SPARC_FLAG_32BIT */
 asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
 {
 	return sys_ioctl(fd, cmd, (unsigned long)arg);
 }
 
-asmlinkage int sys32_mknod(u32 filename, int mode, dev_t dev)
+asmlinkage int sys32_mknod(u32 filename, int mode, __kernel_dev_t32 dev)
 {
 	return sys_mknod((const char *)A(filename), mode, dev);
 }
@@ -315,19 +534,52 @@
 	return sys_rename((const char *)A(oldname), (const char *)A(newname));
 }
 
+/* XXX: Play with the addr, it will be ugly :(( */
 asmlinkage int sys32_quotactl(int cmd, u32 special, int id, u32 addr)
 {
 	return sys_quotactl(cmd, (const char *)A(special), id, (caddr_t)A(addr));
 }
 
+static int put_statfs (u32 buf, struct statfs *s)
+{
+	if (put_user (s->f_type, &(((struct statfs32 *)A(buf))->f_type)) ||
+	    __put_user (s->f_bsize, &(((struct statfs32 *)A(buf))->f_bsize)) ||
+	    __put_user (s->f_blocks, &(((struct statfs32 *)A(buf))->f_blocks)) ||
+	    __put_user (s->f_bfree, &(((struct statfs32 *)A(buf))->f_bfree)) ||
+	    __put_user (s->f_bavail, &(((struct statfs32 *)A(buf))->f_bavail)) ||
+	    __put_user (s->f_files, &(((struct statfs32 *)A(buf))->f_files)) ||
+	    __put_user (s->f_ffree, &(((struct statfs32 *)A(buf))->f_ffree)) ||
+	    __put_user (s->f_namelen, &(((struct statfs32 *)A(buf))->f_namelen)) ||
+	    __put_user (s->f_fsid.val[0], &(((struct statfs32 *)A(buf))->f_fsid.val[0])) ||
+	    __put_user (s->f_fsid.val[1], &(((struct statfs32 *)A(buf))->f_fsid.val[1])))
+		return -EFAULT;
+	return 0;
+}
+
 asmlinkage int sys32_statfs(u32 path, u32 buf)
 {
-	return sys_statfs((const char *)A(path), (struct statfs *)A(buf));
+	int ret;
+	struct statfs s;
+	unsigned long old_fs = get_fs();
+	
+	set_fs (KERNEL_DS);
+	ret = sys_statfs((const char *)A(path), &s);
+	set_fs (old_fs);
+	if (put_statfs(buf, &s)) return -EFAULT;
+	return ret;
 }
 
 asmlinkage int sys32_fstatfs(unsigned int fd, u32 buf)
 {
-	return sys_fstatfs(fd, (struct statfs *)A(buf));
+	int ret;
+	struct statfs s;
+	unsigned long old_fs = get_fs();
+	
+	set_fs (KERNEL_DS);
+	ret = sys_fstatfs(fd, &s);
+	set_fs (old_fs);
+	if (put_statfs(buf, &s)) return -EFAULT;
+	return ret;
 }
 
 asmlinkage int sys32_truncate(u32 path, u32 length)
@@ -342,11 +594,24 @@
 
 asmlinkage int sys32_utime(u32 filename, u32 times)
 {
-	return sys_utime((char *)A(filename), (struct utimbuf *)A(times));
+	struct utimbuf32 { __kernel_time_t32 actime, modtime; };
+	struct utimbuf t;
+	unsigned long old_fs;
+	int ret;
+	
+	if (get_user (t.actime, &(((struct utimbuf32 *)A(times))->actime)) ||
+	    __get_user (t.modtime, &(((struct utimbuf32 *)A(times))->modtime)))
+		return -EFAULT;
+	old_fs = get_fs();
+	set_fs (KERNEL_DS); 
+	ret = sys_utime((char *)A(filename), &t);
+	set_fs (old_fs);
+	return ret;
 }
 
 asmlinkage int sys32_utimes(u32 filename, u32 utimes)
 {
+	/* struct timeval is the same :)) */
 	return sys_utimes((char *)A(filename), (struct timeval *)A(utimes));
 }
 
@@ -365,12 +630,12 @@
 	return sys_chroot((const char *)A(filename));
 }
 
-asmlinkage int sys32_chmod(u32 filename, mode_t mode)
+asmlinkage int sys32_chmod(u32 filename, __kernel_mode_t32 mode)
 {
 	return sys_chmod((const char *)A(filename), mode);
 }
 
-asmlinkage int sys32_chown(u32 filename, uid_t user, gid_t group)
+asmlinkage int sys32_chown(u32 filename, __kernel_uid_t32 user, __kernel_gid_t32 group)
 {
 	return sys_chown((const char *)A(filename), user, group);
 }
@@ -392,6 +657,7 @@
 
 asmlinkage int sys32_llseek(unsigned int fd, u32 offset_high, u32 offset_low, u32 result, unsigned int origin)
 {
+	/* loff_t is the same :)) */
 	return sys_llseek(fd, (unsigned long)offset_high, (unsigned long)offset_low, (loff_t *)A(result), origin);
 }
 
@@ -405,24 +671,264 @@
 	return sys_write(fd, (const char *)A(buf), (unsigned long)count);
 }
 
+struct iovec32 { u32 iov_base; __kernel_size_t32 iov_len; };
+
 asmlinkage long sys32_readv(u32 fd, u32 vector, u32 count)
 {
-	return sys_readv((unsigned long)fd, (const struct iovec *)A(vector), (unsigned long)count);
+	struct iovec *v;
+	struct iovec vf[UIO_FASTIOV];
+	u32 i;
+	long ret;
+	unsigned long old_fs;
+	
+	if (!count) return 0; if (count > UIO_MAXIOV) return -EINVAL;
+	if (count <= UIO_FASTIOV)
+		v = vf;
+	else {
+		lock_kernel ();
+		v = kmalloc (count * sizeof (struct iovec), GFP_KERNEL);
+		if (!v) {
+			ret = -ENOMEM;
+			goto out;
+		}
+	}
+	for (i = 0; i < count; i++) {
+		if (__get_user ((unsigned long)(v[i].iov_base), &((((struct iovec32 *)A(vector))+i)->iov_base)) ||
+		    __get_user (v[i].iov_len, &((((struct iovec32 *)A(vector))+i)->iov_len))) {
+		    	ret = -EFAULT;
+		    	goto out;
+		}
+	}
+	old_fs = get_fs();
+	set_fs (KERNEL_DS);
+	ret = sys_readv((unsigned long)fd, v, (unsigned long)count);
+	set_fs (old_fs);
+out:
+	if (count > UIO_FASTIOV) {
+		kfree (v);
+		unlock_kernel ();
+	}
+	return ret;
 }
 
 asmlinkage long sys32_writev(u32 fd, u32 vector, u32 count)
 {
-	return sys_writev((unsigned long)fd, (const struct iovec *)A(vector), (unsigned long)count);
+	struct iovec *v;
+	struct iovec vf[UIO_FASTIOV];
+	u32 i;
+	long ret;
+	unsigned long old_fs;
+	
+	if (!count) return 0; if (count > UIO_MAXIOV) return -EINVAL;
+	if (count <= UIO_FASTIOV)
+		v = vf;
+	else {
+		lock_kernel ();
+		v = kmalloc (count * sizeof (struct iovec), GFP_KERNEL);
+		if (!v) {
+			ret = -ENOMEM;
+			goto out;
+		}
+	}
+	for (i = 0; i < count; i++) {
+		if (__get_user ((unsigned long)(v[i].iov_base), &((((struct iovec32 *)A(vector))+i)->iov_base)) ||
+		    __get_user (v[i].iov_len, &((((struct iovec32 *)A(vector))+i)->iov_len))) {
+			ret = -EFAULT;
+			goto out;
+		}
+	}
+	old_fs = get_fs();
+	set_fs (KERNEL_DS);
+	ret = sys_writev((unsigned long)fd, v, (unsigned long)count);
+	set_fs (old_fs);
+out:	
+	if (count > UIO_FASTIOV) {
+		kfree (v);
+		unlock_kernel ();
+	}
+	return ret;
+}
+
+/* readdir & getdents */
+
+#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
+#define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1))
+
+struct old_linux_dirent32 {
+	u32		d_ino;
+	u32		d_offset;
+	unsigned short	d_namlen;
+	char		d_name[1];
+};
+
+struct readdir_callback32 {
+	struct old_linux_dirent32 * dirent;
+	int count;
+};
+
+static int fillonedir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino)
+{
+	struct readdir_callback32 * buf = (struct readdir_callback32 *) __buf;
+	struct old_linux_dirent32 * dirent;
+
+	if (buf->count)
+		return -EINVAL;
+	buf->count++;
+	dirent = buf->dirent;
+	put_user(ino, &dirent->d_ino);
+	put_user(offset, &dirent->d_offset);
+	put_user(namlen, &dirent->d_namlen);
+	copy_to_user(dirent->d_name, name, namlen);
+	put_user(0, dirent->d_name + namlen);
+	return 0;
+}
+
+asmlinkage int old32_readdir(unsigned int fd, u32 dirent, unsigned int count)
+{
+	int error = -EBADF;
+	struct file * file;
+	struct readdir_callback32 buf;
+
+	lock_kernel();
+	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+		goto out;
+	error = -ENOTDIR;
+	if (!file->f_op || !file->f_op->readdir)
+		goto out;
+	error = verify_area(VERIFY_WRITE, (void *)A(dirent), sizeof(struct old_linux_dirent32));
+	if (error)
+		goto out;
+	buf.count = 0;
+	buf.dirent = (struct old_linux_dirent32 *)A(dirent);
+	error = file->f_op->readdir(file->f_inode, file, &buf, fillonedir);
+	if (error < 0)
+		goto out;
+	error = buf.count;
+out:
+	unlock_kernel();
+	return error;
+}
+
+struct linux_dirent32 {
+	u32		d_ino;
+	u32		d_off;
+	unsigned short	d_reclen;
+	char		d_name[1];
+};
+
+struct getdents_callback32 {
+	struct linux_dirent32 * current_dir;
+	struct linux_dirent32 * previous;
+	int count;
+	int error;
+};
+
+static int filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino)
+{
+	struct linux_dirent32 * dirent;
+	struct getdents_callback32 * buf = (struct getdents_callback32 *) __buf;
+	int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
+
+	buf->error = -EINVAL;	/* only used if we fail.. */
+	if (reclen > buf->count)
+		return -EINVAL;
+	dirent = buf->previous;
+	if (dirent)
+		put_user(offset, &dirent->d_off);
+	dirent = buf->current_dir;
+	buf->previous = dirent;
+	put_user(ino, &dirent->d_ino);
+	put_user(reclen, &dirent->d_reclen);
+	copy_to_user(dirent->d_name, name, namlen);
+	put_user(0, dirent->d_name + namlen);
+	((char *) dirent) += reclen;
+	buf->current_dir = dirent;
+	buf->count -= reclen;
+	return 0;
 }
 
 asmlinkage int sys32_getdents(unsigned int fd, u32 dirent, unsigned int count)
 {
-	return sys_getdents(fd, (void *)A(dirent), count);
+	struct file * file;
+	struct linux_dirent32 * lastdirent;
+	struct getdents_callback32 buf;
+	int error = -EBADF;
+
+	lock_kernel();
+	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+		goto out;
+	error = -ENOTDIR;
+	if (!file->f_op || !file->f_op->readdir)
+		goto out;
+	error = verify_area(VERIFY_WRITE, (void *)A(dirent), count);
+	if (error)
+		goto out;
+	buf.current_dir = (struct linux_dirent32 *) A(dirent);
+	buf.previous = NULL;
+	buf.count = count;
+	buf.error = 0;
+	error = file->f_op->readdir(file->f_inode, file, &buf, filldir);
+	if (error < 0)
+		goto out;
+	lastdirent = buf.previous;
+	if (!lastdirent) {
+		error = buf.error;
+	} else {
+		put_user(file->f_pos, &lastdirent->d_off);
+		error = count - buf.count;
+	}
+out:
+	unlock_kernel();
+	return error;
 }
 
+/* end of readdir & getdents */
+
 asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp)
 {
-	return sys_select(n, (fd_set *)A(inp), (fd_set *)A(outp), (fd_set *)A(exp), (struct timeval *)A(tvp));
+	unsigned long old_fs;
+	char *p;
+	u32 *q;
+	int i, ret = -EINVAL, nn;
+	u32 *Inp, *Outp, *Exp;
+	
+	if (n < 0 || n > PAGE_SIZE*2) return -EINVAL;
+	lock_kernel ();
+	p = (char *)__get_free_page (GFP_KERNEL);
+	if (!p) goto out;
+	q = (u32 *)p;
+	nn = (n + 8 * sizeof(unsigned long) - 1) / (8 * sizeof (unsigned long));
+	Inp = (u32 *)A(inp); Outp = (u32 *)A(outp); Exp = (u32 *)A(exp);
+	ret = -EFAULT;
+	for (i = 0; i < ret; i++, Inp += 2, Outp += 2, Exp += 2, q += 2) {
+		if (__get_user (q[1], Inp) ||
+		    __get_user (q[0], Inp+1) ||
+		    __get_user (q[1+PAGE_SIZE/4], Outp) ||
+		    __get_user (q[PAGE_SIZE/4], Outp+1) ||
+		    __get_user (q[1+PAGE_SIZE/2], Exp) ||
+		    __get_user (q[PAGE_SIZE/2], Exp+1))
+			goto out;
+	}
+	old_fs = get_fs ();
+	set_fs (KERNEL_DS);
+	ret = sys_select(n, (fd_set *)p, (fd_set *)(p + PAGE_SIZE/4), (fd_set *)(p + PAGE_SIZE/2), (struct timeval *)A(tvp));
+	set_fs (old_fs);
+	q = (u32 *)p;
+	Inp = (u32 *)A(inp); Outp = (u32 *)A(outp); Exp = (u32 *)A(exp);
+	for (i = 0; i < ret; i++, Inp += 2, Outp += 2, Exp += 2, q += 2) {
+		if (__put_user (q[1], Inp) ||
+		    __put_user (q[0], Inp+1) ||
+		    __put_user (q[1+PAGE_SIZE/4], Outp) ||
+		    __put_user (q[PAGE_SIZE/4], Outp+1) ||
+		    __put_user (q[1+PAGE_SIZE/2], Exp) ||
+		    __put_user (q[PAGE_SIZE/2], Exp+1)) {
+		    	ret = -EFAULT;
+			goto out;
+		}
+	}
+out:
+	free_page ((unsigned long)p);
+	return ret;
 }
 
 asmlinkage int sys32_poll(u32 ufds, unsigned int nfds, int timeout)
@@ -430,19 +936,62 @@
 	return sys_poll((struct pollfd *)A(ufds), nfds, timeout);
 }
 
+static inline int putstat(u32 statbuf, struct stat *s)
+{
+	if (put_user (s->st_dev, &(((struct stat32 *)A(statbuf))->st_dev)) ||
+	    __put_user (s->st_ino, &(((struct stat32 *)A(statbuf))->st_ino)) ||
+	    __put_user (s->st_mode, &(((struct stat32 *)A(statbuf))->st_mode)) ||
+	    __put_user (s->st_nlink, &(((struct stat32 *)A(statbuf))->st_nlink)) ||
+	    __put_user (s->st_uid, &(((struct stat32 *)A(statbuf))->st_uid)) ||
+	    __put_user (s->st_gid, &(((struct stat32 *)A(statbuf))->st_gid)) ||
+	    __put_user (s->st_rdev, &(((struct stat32 *)A(statbuf))->st_rdev)) ||
+	    __put_user (s->st_size, &(((struct stat32 *)A(statbuf))->st_size)) ||
+	    __put_user (s->st_atime, &(((struct stat32 *)A(statbuf))->st_atime)) ||
+	    __put_user (s->st_mtime, &(((struct stat32 *)A(statbuf))->st_mtime)) ||
+	    __put_user (s->st_ctime, &(((struct stat32 *)A(statbuf))->st_ctime)) ||
+	    __put_user (s->st_blksize, &(((struct stat32 *)A(statbuf))->st_blksize)) ||
+	    __put_user (s->st_blocks, &(((struct stat32 *)A(statbuf))->st_blocks)))
+		return -EFAULT;
+	return 0;
+}
+
 asmlinkage int sys32_newstat(u32 filename, u32 statbuf)
 {
-	return sys_newstat((char *)A(filename), (struct stat *)A(statbuf));
+	int ret;
+	struct stat s;
+	unsigned long old_fs = get_fs();
+	
+	set_fs (KERNEL_DS);
+	ret = sys_newstat((char *)A(filename), &s);
+	set_fs (old_fs);
+	if (putstat (statbuf, &s)) return -EFAULT;
+	return ret;
 }
 
 asmlinkage int sys32_newlstat(u32 filename, u32 statbuf)
 {
-	return sys_newlstat((char *)A(filename), (struct stat *)A(statbuf));
+	int ret;
+	struct stat s;
+	unsigned long old_fs = get_fs();
+	
+	set_fs (KERNEL_DS);
+	ret = sys_newlstat((char *)A(filename), &s);
+	set_fs (old_fs);
+	if (putstat (statbuf, &s)) return -EFAULT;
+	return ret;
 }
 
 asmlinkage int sys32_newfstat(unsigned int fd, u32 statbuf)
 {
-	return sys_newfstat(fd, (struct stat *)A(statbuf));
+	int ret;
+	struct stat s;
+	unsigned long old_fs = get_fs();
+	
+	set_fs (KERNEL_DS);
+	ret = sys_newfstat(fd, &s);
+	set_fs (old_fs);
+	if (putstat (statbuf, &s)) return -EFAULT;
+	return ret;
 }
 
 asmlinkage int sys32_readlink(u32 path, u32 buf, int bufsiz)
@@ -454,7 +1003,7 @@
 {
         va_list args;
 	unsigned int x;
-	int ret;
+	int ret = -EINVAL;
 
         va_start(args, option);
         switch (option) {
@@ -475,6 +1024,7 @@
 
 asmlinkage int sys32_ustat(dev_t dev, u32 ubuf)
 {
+	/* ustat is the same :)) */
 	return sys_ustat(dev, (struct ustat *)A(ubuf));
 }
 
@@ -499,23 +1049,111 @@
 	return sys_personality((unsigned long)personality);
 }
 
-asmlinkage int sys32_wait4(pid_t pid, u32 stat_addr, int options, u32 ru)
-{
-	return sys_wait4(pid, (unsigned int *)A(stat_addr), options, (struct rusage *)A(ru));
+struct rusage32 {
+        struct timeval ru_utime;
+        struct timeval ru_stime;
+        s32    ru_maxrss;
+        s32    ru_ixrss;
+        s32    ru_idrss;
+        s32    ru_isrss;
+        s32    ru_minflt;
+        s32    ru_majflt;
+        s32    ru_nswap;
+        s32    ru_inblock;
+        s32    ru_oublock;
+        s32    ru_msgsnd; 
+        s32    ru_msgrcv; 
+        s32    ru_nsignals;
+        s32    ru_nvcsw;
+        s32    ru_nivcsw;
+};
+
+static int put_rusage (u32 ru, struct rusage *r)
+{
+	if (put_user (r->ru_utime.tv_sec, &(((struct rusage32 *)A(ru))->ru_utime.tv_sec)) ||
+	    __put_user (r->ru_utime.tv_usec, &(((struct rusage32 *)A(ru))->ru_utime.tv_usec)) ||
+	    __put_user (r->ru_stime.tv_sec, &(((struct rusage32 *)A(ru))->ru_stime.tv_sec)) ||
+	    __put_user (r->ru_stime.tv_usec, &(((struct rusage32 *)A(ru))->ru_stime.tv_usec)) ||
+	    __put_user (r->ru_maxrss, &(((struct rusage32 *)A(ru))->ru_maxrss)) ||
+	    __put_user (r->ru_ixrss, &(((struct rusage32 *)A(ru))->ru_ixrss)) ||
+	    __put_user (r->ru_idrss, &(((struct rusage32 *)A(ru))->ru_idrss)) ||
+	    __put_user (r->ru_isrss, &(((struct rusage32 *)A(ru))->ru_isrss)) ||
+	    __put_user (r->ru_minflt, &(((struct rusage32 *)A(ru))->ru_minflt)) ||
+	    __put_user (r->ru_majflt, &(((struct rusage32 *)A(ru))->ru_majflt)) ||
+	    __put_user (r->ru_nswap, &(((struct rusage32 *)A(ru))->ru_nswap)) ||
+	    __put_user (r->ru_inblock, &(((struct rusage32 *)A(ru))->ru_inblock)) ||
+	    __put_user (r->ru_oublock, &(((struct rusage32 *)A(ru))->ru_oublock)) ||
+	    __put_user (r->ru_msgsnd, &(((struct rusage32 *)A(ru))->ru_msgsnd)) ||
+	    __put_user (r->ru_msgrcv, &(((struct rusage32 *)A(ru))->ru_msgrcv)) ||
+	    __put_user (r->ru_nsignals, &(((struct rusage32 *)A(ru))->ru_nsignals)) ||
+	    __put_user (r->ru_nvcsw, &(((struct rusage32 *)A(ru))->ru_nvcsw)) ||
+	    __put_user (r->ru_nivcsw, &(((struct rusage32 *)A(ru))->ru_nivcsw)))
+		return -EFAULT;
+	return 0;
+}
+
+asmlinkage int sys32_wait4(__kernel_pid_t32 pid, u32 stat_addr, int options, u32 ru)
+{
+	if (!ru)
+		return sys_wait4(pid, (unsigned int *)A(stat_addr), options, NULL);
+	else {
+		struct rusage r;
+		int ret;
+		unsigned long old_fs = get_fs();
+		
+		set_fs (KERNEL_DS);
+		ret = sys_wait4(pid, (unsigned int *)A(stat_addr), options, &r);
+		set_fs (old_fs);
+		if (put_rusage (ru, &r)) return -EFAULT;
+		return ret;
+	}
 }
 
-asmlinkage int sys32_waitpid(pid_t pid, u32 stat_addr, int options)
+asmlinkage int sys32_waitpid(__kernel_pid_t32 pid, u32 stat_addr, int options)
 {
 	return sys_waitpid(pid, (unsigned int *)A(stat_addr), options);
 }
 
+struct sysinfo32 {
+        s32 uptime;
+        u32 loads[3];
+        u32 totalram;
+        u32 freeram;
+        u32 sharedram;
+        u32 bufferram;
+        u32 totalswap;
+        u32 freeswap;
+        unsigned short procs;
+        char _f[22];
+};
+
 asmlinkage int sys32_sysinfo(u32 info)
 {
-	return sys_sysinfo((struct sysinfo *)A(info));
+	struct sysinfo s;
+	int ret;
+	unsigned long old_fs = get_fs ();
+	
+	set_fs (KERNEL_DS);
+	ret = sys_sysinfo(&s);
+	set_fs (old_fs);
+	if (put_user (s.uptime, &(((struct sysinfo32 *)A(info))->uptime)) ||
+	    __put_user (s.loads[0], &(((struct sysinfo32 *)A(info))->loads[0])) ||
+	    __put_user (s.loads[1], &(((struct sysinfo32 *)A(info))->loads[1])) ||
+	    __put_user (s.loads[2], &(((struct sysinfo32 *)A(info))->loads[2])) ||
+	    __put_user (s.totalram, &(((struct sysinfo32 *)A(info))->totalram)) ||
+	    __put_user (s.freeram, &(((struct sysinfo32 *)A(info))->freeram)) ||
+	    __put_user (s.sharedram, &(((struct sysinfo32 *)A(info))->sharedram)) ||
+	    __put_user (s.bufferram, &(((struct sysinfo32 *)A(info))->bufferram)) ||
+	    __put_user (s.totalswap, &(((struct sysinfo32 *)A(info))->totalswap)) ||
+	    __put_user (s.freeswap, &(((struct sysinfo32 *)A(info))->freeswap)) ||
+	    __put_user (s.procs, &(((struct sysinfo32 *)A(info))->procs)))
+		return -EFAULT;
+	return ret;
 }
 
 asmlinkage int sys32_getitimer(int which, u32 value)
 {
+	/* itimerval is the same :)) */
 	return sys_getitimer(which, (struct itimerval *)A(value));
 }
 
@@ -524,39 +1162,87 @@
 	return sys_setitimer(which, (struct itimerval *)A(value), (struct itimerval *)A(ovalue));
 }
 
-asmlinkage int sys32_sched_setscheduler(pid_t pid, int policy, u32 param)
+asmlinkage int sys32_sched_setscheduler(__kernel_pid_t32 pid, int policy, u32 param)
 {
+	/* sched_param is the same :)) */
 	return sys_sched_setscheduler(pid, policy, (struct sched_param *)A(param));
 }
 
-asmlinkage int sys32_sched_setparam(pid_t pid, u32 param)
+asmlinkage int sys32_sched_setparam(__kernel_pid_t32 pid, u32 param)
 {
 	return sys_sched_setparam(pid, (struct sched_param *)A(param));
 }
 
-asmlinkage int sys32_sched_getparam(pid_t pid, u32 param)
+asmlinkage int sys32_sched_getparam(__kernel_pid_t32 pid, u32 param)
 {
 	return sys_sched_getparam(pid, (struct sched_param *)A(param));
 }
 
-asmlinkage int sys32_sched_rr_get_interval(pid_t pid, u32 interval)
+struct timespec32 {
+	s32    tv_sec;
+	s32    tv_nsec;
+};
+                
+asmlinkage int sys32_sched_rr_get_interval(__kernel_pid_t32 pid, u32 interval)
 {
-	return sys_sched_rr_get_interval(pid, (struct timespec *)A(interval));
+	struct timespec t;
+	int ret;
+	unsigned long old_fs = get_fs ();
+	
+	set_fs (KERNEL_DS);
+	ret = sys_sched_rr_get_interval(pid, &t);
+	set_fs (old_fs);
+	if (put_user (t.tv_sec, &(((struct timespec32 *)A(interval))->tv_sec)) ||
+	    __put_user (t.tv_nsec, &(((struct timespec32 *)A(interval))->tv_nsec)))
+		return -EFAULT;
+	return ret;
 }
 
 asmlinkage int sys32_nanosleep(u32 rqtp, u32 rmtp)
 {
-	return sys_nanosleep((struct timespec *)A(rqtp), (struct timespec *)A(rmtp));
+	struct timespec t;
+	int ret;
+	unsigned long old_fs = get_fs ();
+	
+	if (get_user (t.tv_sec, &(((struct timespec32 *)A(rqtp))->tv_sec)) ||
+	    __get_user (t.tv_nsec, &(((struct timespec32 *)A(rqtp))->tv_nsec)))
+		return -EFAULT;
+	set_fs (KERNEL_DS);
+	ret = sys_nanosleep(&t, rmtp ? &t : NULL);
+	set_fs (old_fs);
+	if (rmtp && ret == -EINTR) {
+		if (__put_user (t.tv_sec, &(((struct timespec32 *)A(rmtp))->tv_sec)) ||
+	    	    __put_user (t.tv_nsec, &(((struct timespec32 *)A(rmtp))->tv_nsec)))
+			return -EFAULT;
+	}
+	return ret;
 }
 
 asmlinkage int sys32_sigprocmask(int how, u32 set, u32 oset)
 {
-	return sys_sigprocmask(how, (sigset_t *)A(set), (sigset_t *)A(oset));
+	sigset_t s;
+	int ret;
+	unsigned long old_fs = get_fs();
+	
+	if (set && get_user (s, (sigset_t32 *)A(set))) return -EFAULT;
+	set_fs (KERNEL_DS);
+	ret = sys_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL);
+	set_fs (old_fs);
+	if (oset && put_user (s, (sigset_t32 *)A(oset))) return -EFAULT;
+	return ret;
 }
 
 asmlinkage int sys32_sigpending(u32 set)
 {
-	return sys_sigpending((sigset_t *)A(set));
+	sigset_t s;
+	int ret;
+	unsigned long old_fs = get_fs();
+		
+	set_fs (KERNEL_DS);
+	ret = sys_sigpending(&s);
+	set_fs (old_fs);
+	if (put_user (s, (sigset_t32 *)A(set))) return -EFAULT;
+	return ret;
 }
 
 asmlinkage unsigned long sys32_signal(int signum, u32 handler)
@@ -576,34 +1262,84 @@
 
 asmlinkage int sys32_getresuid(u32 ruid, u32 euid, u32 suid)
 {
-	return sys_getresuid((uid_t *)A(ruid), (uid_t *)A(euid), (uid_t *)A(suid));
+	uid_t a, b, c;
+	int ret;
+	unsigned long old_fs = get_fs();
+		
+	set_fs (KERNEL_DS);
+	ret = sys_getresuid(&a, &b, &c);
+	set_fs (old_fs);
+	if (put_user (a, (__kernel_uid_t32 *)A(ruid)) ||
+	    put_user (b, (__kernel_uid_t32 *)A(euid)) ||
+	    put_user (c, (__kernel_uid_t32 *)A(suid)))
+		return -EFAULT;
+	return ret;
 }
 
+struct tms32 {
+	__kernel_clock_t32 tms_utime;
+	__kernel_clock_t32 tms_stime;
+	__kernel_clock_t32 tms_cutime;
+	__kernel_clock_t32 tms_cstime;
+};
+                                
 asmlinkage long sys32_times(u32 tbuf)
 {
-	return sys_times((struct tms *)A(tbuf));
+	struct tms t;
+	long ret;
+	unsigned long old_fs = get_fs ();
+	
+	set_fs (KERNEL_DS);
+	ret = sys_times(tbuf ? &t : NULL);
+	set_fs (old_fs);
+	if (tbuf && (
+	    put_user (t.tms_utime, &(((struct tms32 *)A(tbuf))->tms_utime)) ||
+	    __put_user (t.tms_stime, &(((struct tms32 *)A(tbuf))->tms_stime)) ||
+	    __put_user (t.tms_cutime, &(((struct tms32 *)A(tbuf))->tms_cutime)) ||
+	    __put_user (t.tms_cstime, &(((struct tms32 *)A(tbuf))->tms_cstime))))
+		return -EFAULT;
+	return ret;
 }
 
 asmlinkage int sys32_getgroups(int gidsetsize, u32 grouplist)
 {
-	return sys_getgroups(gidsetsize, (gid_t *)A(grouplist));
+	gid_t gl[NGROUPS];
+	int ret, i;
+	unsigned long old_fs = get_fs ();
+	
+	set_fs (KERNEL_DS);
+	ret = sys_getgroups(gidsetsize, gl);
+	set_fs (old_fs);
+	if (ret > 0 && ret <= NGROUPS)
+		for (i = 0; i < ret; i++, grouplist += sizeof(__kernel_gid_t32))
+			if (__put_user (gl[i], (__kernel_gid_t32 *)A(grouplist)))
+				return -EFAULT;
+	return ret;
 }
 
 asmlinkage int sys32_setgroups(int gidsetsize, u32 grouplist)
 {
-	return sys_setgroups(gidsetsize, (gid_t *)A(grouplist));
+	gid_t gl[NGROUPS];
+	int ret, i;
+	unsigned long old_fs = get_fs ();
+	
+	if ((unsigned) gidsetsize > NGROUPS)
+		return -EINVAL;
+	for (i = 0; i < gidsetsize; i++, grouplist += sizeof(__kernel_gid_t32))
+		if (__get_user (gl[i], (__kernel_gid_t32 *)A(grouplist)))
+			return -EFAULT;
+        set_fs (KERNEL_DS);
+	ret = sys_setgroups(gidsetsize, gl);
+	set_fs (old_fs);
+	return ret;
 }
 
 asmlinkage int sys32_newuname(u32 name)
 {
+	/* utsname is the same :)) */
 	return sys_newuname((struct new_utsname *)A(name));
 }
 
-asmlinkage int sys32_uname(u32 name)
-{
-	return sys_uname((struct old_utsname *)A(name));
-}
-
 asmlinkage int sys32_olduname(u32 name)
 {
 	return sys_olduname((struct oldold_utsname *)A(name));
@@ -624,19 +1360,54 @@
 	return sys_setdomainname((char *)A(name), len);
 }
 
+struct rlimit32 {
+	s32	rlim_cur;
+	s32	rlim_max;
+};
+
 asmlinkage int sys32_getrlimit(unsigned int resource, u32 rlim)
 {
-	return sys_getrlimit(resource, (struct rlimit *)A(rlim));
+	struct rlimit r;
+	int ret;
+	unsigned long old_fs = get_fs ();
+	
+	set_fs (KERNEL_DS);
+	ret = sys_getrlimit(resource, &r);
+	set_fs (old_fs);
+	if (!ret && (
+	    put_user (r.rlim_cur, &(((struct rlimit32 *)A(rlim))->rlim_cur)) ||
+	    __put_user (r.rlim_max, &(((struct rlimit32 *)A(rlim))->rlim_max))))
+		return -EFAULT;
+	return ret;
 }
 
 asmlinkage int sys32_setrlimit(unsigned int resource, u32 rlim)
 {
-	return sys_setrlimit(resource, (struct rlimit *)A(rlim));
+	struct rlimit r;
+	int ret;
+	unsigned long old_fs = get_fs ();
+
+	if (resource >= RLIM_NLIMITS) return -EINVAL;	
+	if (get_user (r.rlim_cur, &(((struct rlimit32 *)A(rlim))->rlim_cur)) ||
+	    __get_user (r.rlim_max, &(((struct rlimit32 *)A(rlim))->rlim_max)))
+		return -EFAULT;
+	set_fs (KERNEL_DS);
+	ret = sys_setrlimit(resource, &r);
+	set_fs (old_fs);
+	return ret;
 }
 
 asmlinkage int sys32_getrusage(int who, u32 ru)
 {
-	return sys_getrusage(who, (struct rusage *)A(ru));
+	struct rusage r;
+	int ret;
+	unsigned long old_fs = get_fs();
+		
+	set_fs (KERNEL_DS);
+	ret = sys_getrusage(who, &r);
+	set_fs (old_fs);
+	if (put_rusage (ru, &r)) return -EFAULT;
+	return ret;
 }
 
 asmlinkage int sys32_time(u32 tloc)
@@ -646,6 +1417,7 @@
 
 asmlinkage int sys32_gettimeofday(u32 tv, u32 tz)
 {
+	/* both timeval and timezone are ok :)) */
 	return sys_gettimeofday((struct timeval *)A(tv), (struct timezone *)A(tz));
 }
 
@@ -654,22 +1426,86 @@
 	return sys_settimeofday((struct timeval *)A(tv), (struct timezone *)A(tz));
 }
 
+struct timex32 {
+	unsigned int modes;
+	s32 offset;
+	s32 freq;
+	s32 maxerror;
+	s32 esterror;
+	int status;
+	s32 constant;
+	s32 precision;
+	s32 tolerance;
+	struct timeval time;
+	s32 tick;
+	s32 ppsfreq;
+	s32 jitter;
+	int shift;
+	s32 stabil;
+	s32 jitcnt;
+	s32 calcnt;
+	s32 errcnt;
+	s32 stbcnt;
+	int  :32; int  :32; int  :32; int  :32;
+	int  :32; int  :32; int  :32; int  :32;
+	int  :32; int  :32; int  :32; int  :32;
+};
+
 asmlinkage int sys32_adjtimex(u32 txc_p)
 {
-	return sys_adjtimex((struct timex *)A(txc_p));
+	struct timex t;
+	int ret;
+	unsigned long old_fs = get_fs ();
+
+	if (get_user (t.modes, &(((struct timex32 *)A(txc_p))->modes)) ||
+	    __get_user (t.offset, &(((struct timex32 *)A(txc_p))->offset)) ||
+	    __get_user (t.freq, &(((struct timex32 *)A(txc_p))->freq)) ||
+	    __get_user (t.maxerror, &(((struct timex32 *)A(txc_p))->maxerror)) ||
+	    __get_user (t.esterror, &(((struct timex32 *)A(txc_p))->esterror)) ||
+	    __get_user (t.status, &(((struct timex32 *)A(txc_p))->status)) ||
+	    __get_user (t.constant, &(((struct timex32 *)A(txc_p))->constant)) ||
+	    __get_user (t.tick, &(((struct timex32 *)A(txc_p))->tick)) ||
+	    __get_user (t.shift, &(((struct timex32 *)A(txc_p))->shift)))
+		return -EFAULT;
+	set_fs (KERNEL_DS);
+	ret = sys_adjtimex(&t);
+	set_fs (old_fs);
+	if ((unsigned)ret >= 0 && (
+	    __put_user (t.modes, &(((struct timex32 *)A(txc_p))->modes)) ||
+	    __put_user (t.offset, &(((struct timex32 *)A(txc_p))->offset)) ||
+	    __put_user (t.freq, &(((struct timex32 *)A(txc_p))->freq)) ||
+	    __put_user (t.maxerror, &(((struct timex32 *)A(txc_p))->maxerror)) ||
+	    __put_user (t.esterror, &(((struct timex32 *)A(txc_p))->esterror)) ||
+	    __put_user (t.status, &(((struct timex32 *)A(txc_p))->status)) ||
+	    __put_user (t.constant, &(((struct timex32 *)A(txc_p))->constant)) ||
+	    __put_user (t.precision, &(((struct timex32 *)A(txc_p))->precision)) ||
+	    __put_user (t.tolerance, &(((struct timex32 *)A(txc_p))->tolerance)) ||
+	    __put_user (t.time.tv_sec, &(((struct timex32 *)A(txc_p))->time.tv_sec)) ||
+	    __put_user (t.time.tv_usec, &(((struct timex32 *)A(txc_p))->time.tv_usec)) ||
+	    __put_user (t.tick, &(((struct timex32 *)A(txc_p))->tick)) ||
+	    __put_user (t.ppsfreq, &(((struct timex32 *)A(txc_p))->ppsfreq)) ||
+	    __put_user (t.jitter, &(((struct timex32 *)A(txc_p))->jitter)) ||
+	    __put_user (t.shift, &(((struct timex32 *)A(txc_p))->shift)) ||
+	    __put_user (t.stabil, &(((struct timex32 *)A(txc_p))->stabil)) ||
+	    __put_user (t.jitcnt, &(((struct timex32 *)A(txc_p))->jitcnt)) ||
+	    __put_user (t.calcnt, &(((struct timex32 *)A(txc_p))->calcnt)) ||
+	    __put_user (t.errcnt, &(((struct timex32 *)A(txc_p))->errcnt)) ||
+	    __put_user (t.stbcnt, &(((struct timex32 *)A(txc_p))->stbcnt))))
+		return -EFAULT;
+	return ret;
 }
 
-asmlinkage int sys32_msync(u32 start, u32 len, int flags)
+asmlinkage int sys32_msync(u32 start, __kernel_size_t32 len, int flags)
 {
 	return sys_msync((unsigned long)start, (size_t)len, flags);
 }
 
-asmlinkage int sys32_mlock(u32 start, u32 len)
+asmlinkage int sys32_mlock(u32 start, __kernel_size_t32 len)
 {
 	return sys_mlock((unsigned long)start, (size_t)len);
 }
 
-asmlinkage int sys32_munlock(u32 start, u32 len)
+asmlinkage int sys32_munlock(u32 start, __kernel_size_t32 len)
 {
 	return sys_munlock((unsigned long)start, (size_t)len);
 }
@@ -679,12 +1515,12 @@
 	return sys_brk((unsigned long)brk);
 }
 
-asmlinkage int sys32_munmap(u32 addr, u32 len)
+asmlinkage int sys32_munmap(u32 addr, __kernel_size_t32 len)
 {
 	return sys_munmap((unsigned long)addr, (size_t)len);
 }
 
-asmlinkage int sys32_mprotect(u32 start, u32 len, u32 prot)
+asmlinkage int sys32_mprotect(u32 start, __kernel_size_t32 len, u32 prot)
 {
 	return sys_mprotect((unsigned long)start, (size_t)len, (unsigned long)prot);
 }
@@ -706,6 +1542,7 @@
 
 asmlinkage int sys32_bind(int fd, u32 umyaddr, int addrlen)
 {
+	/* sockaddr is the same :)) */
 	return sys_bind(fd, (struct sockaddr *)A(umyaddr), addrlen);
 }
 
@@ -729,28 +1566,31 @@
 	return sys_getpeername(fd, (struct sockaddr *)A(usockaddr), (int *)A(usockaddr_len));
 }
 
-asmlinkage int sys32_send(int fd, u32 buff, u32 len, unsigned flags)
+asmlinkage int sys32_send(int fd, u32 buff, __kernel_size_t32 len, unsigned flags)
 {
 	return sys_send(fd, (void *)A(buff), (size_t)len, flags);
 }
 
-asmlinkage int sys32_sendto(int fd, u32 buff, u32 len, unsigned flags, u32 addr, int addr_len)
+asmlinkage int sys32_sendto(int fd, u32 buff, __kernel_size_t32 len, unsigned flags, u32 addr, int addr_len)
 {
 	return sys_sendto(fd, (void *)A(buff), (size_t)len, flags, (struct sockaddr *)A(addr), addr_len);
 }
 
-asmlinkage int sys32_recv(int fd, u32 ubuf, u32 size, unsigned flags)
+asmlinkage int sys32_recv(int fd, u32 ubuf, __kernel_size_t32 size, unsigned flags)
 {
 	return sys_recv(fd, (void *)A(ubuf), (size_t)size, flags);
 }
 
-asmlinkage int sys32_recvfrom(int fd, u32 ubuf, u32 size, unsigned flags, u32 addr, u32 addr_len)
+asmlinkage int sys32_recvfrom(int fd, u32 ubuf, __kernel_size_t32 size, unsigned flags, u32 addr, u32 addr_len)
 {
 	return sys_recvfrom(fd, (void *)A(ubuf), (size_t)size, flags, (struct sockaddr *)A(addr), (int *)A(addr_len));
 }
  
 asmlinkage int sys32_setsockopt(int fd, int level, int optname, u32 optval, int optlen)
 {
+	/* XXX handle ip_fw32->ip_fw conversion for IP firewalling and accounting.
+	       Do it using some macro in ip_sockglue.c
+	   Other optval arguments are mostly just ints or 32<->64bit transparent */
 	return sys_setsockopt(fd, level, optname, (char *)A(optval), optlen);
 }
 
@@ -759,6 +1599,7 @@
 	return sys_getsockopt(fd, level, optname, (char *)A(optval), (int *)A(optlen));
 }
 
+/* Continue here */
 asmlinkage int sys32_sendmsg(int fd, u32 msg, unsigned flags)
 {
 	return sys_sendmsg(fd, (struct msghdr *)A(msg), flags);
@@ -809,7 +1650,7 @@
 	if (oldaction) {
 		err = -EFAULT;
 		old_sa.sa_handler = (unsigned)(u64)(p->sa_handler);
-		old_sa.sa_mask = (sigset32_t)(p->sa_mask);
+		old_sa.sa_mask = (sigset_t32)(p->sa_mask);
 		old_sa.sa_flags = (unsigned)(p->sa_flags);
 		old_sa.sa_restorer = (unsigned)(u64)(p->sa_restorer);
 		if (copy_to_user(A(oldaction), p, sizeof(struct sigaction32)))
@@ -828,4 +1669,73 @@
 out:
 	unlock_kernel();
 	return err;
+}
+
+asmlinkage int sys32_nfsservctl(int cmd, u32 argp, u32 resp)
+{
+	/* XXX handle argp and resp args */
+	return sys_nfsservctl(cmd, (void *)A(argp), (void *)A(resp));
+}
+
+struct ncp_mount_data32 {
+        int version;
+        unsigned int ncp_fd;
+        __kernel_uid_t32 mounted_uid;
+        __kernel_pid_t32 wdog_pid;
+        unsigned char mounted_vol[NCP_VOLNAME_LEN + 1];
+        unsigned int time_out;
+        unsigned int retry_count;
+        unsigned int flags;
+        __kernel_uid_t32 uid;
+        __kernel_gid_t32 gid;
+        __kernel_mode_t32 file_mode;
+        __kernel_mode_t32 dir_mode;
+};
+
+void *do_ncp_super_data_conv(void *raw_data)
+{
+	struct ncp_mount_data *n = (struct ncp_mount_data *)raw_data;
+	struct ncp_mount_data32 *n32 = (struct ncp_mount_data32 *)raw_data;
+
+	n->dir_mode = n32->dir_mode;
+	n->file_mode = n32->file_mode;
+	n->gid = n32->gid;
+	n->uid = n32->uid;
+	memmove (n->mounted_vol, n32->mounted_vol, (sizeof (n32->mounted_vol) + 3 * sizeof (unsigned int)));
+	n->wdog_pid = n32->wdog_pid;
+	n->mounted_uid = n32->mounted_uid;
+	return raw_data;
+}
+
+struct smb_mount_data32 {
+        int version;
+        unsigned int fd;
+        __kernel_uid_t32 mounted_uid;
+        struct sockaddr_in addr;
+        char server_name[17];
+        char client_name[17];
+        char service[64];
+        char root_path[64];
+        char username[64];
+        char password[64];
+        char domain[64];
+        unsigned short max_xmit;
+        __kernel_uid_t32 uid;
+        __kernel_gid_t32 gid;
+        __kernel_mode_t32 file_mode;
+        __kernel_mode_t32 dir_mode;
+};
+
+void *do_smb_super_data_conv(void *raw_data)
+{
+	struct smb_mount_data *s = (struct smb_mount_data *)raw_data;
+	struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data;
+
+	s->dir_mode = s32->dir_mode;
+	s->file_mode = s32->file_mode;
+	s->gid = s32->gid;
+	s->uid = s32->uid;
+	memmove (&s->addr, &s32->addr, (((long)&s->uid) - ((long)&s->addr)));
+	s->mounted_uid = s32->mounted_uid;
+	return raw_data;
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov