Add generic sys_old_select()
[safe/jmp/linux-2.6] / arch / x86 / kernel / sys_i386_32.c
1 /*
2  * This file contains various random system calls that
3  * have a non-standard calling sequence on the Linux/i386
4  * platform.
5  */
6
7 #include <linux/errno.h>
8 #include <linux/sched.h>
9 #include <linux/mm.h>
10 #include <linux/fs.h>
11 #include <linux/smp.h>
12 #include <linux/sem.h>
13 #include <linux/msg.h>
14 #include <linux/shm.h>
15 #include <linux/stat.h>
16 #include <linux/syscalls.h>
17 #include <linux/mman.h>
18 #include <linux/file.h>
19 #include <linux/utsname.h>
20 #include <linux/ipc.h>
21
22 #include <linux/uaccess.h>
23 #include <linux/unistd.h>
24
25 #include <asm/syscalls.h>
26
27 /*
28  * Perform the select(nd, in, out, ex, tv) and mmap() system
29  * calls. Linux/i386 didn't use to be able to handle more than
30  * 4 system call parameters, so these system calls used a memory
31  * block for parameter passing..
32  */
33
34 struct mmap_arg_struct {
35         unsigned long addr;
36         unsigned long len;
37         unsigned long prot;
38         unsigned long flags;
39         unsigned long fd;
40         unsigned long offset;
41 };
42
43 asmlinkage int old_mmap(struct mmap_arg_struct __user *arg)
44 {
45         struct mmap_arg_struct a;
46         int err = -EFAULT;
47
48         if (copy_from_user(&a, arg, sizeof(a)))
49                 goto out;
50
51         err = -EINVAL;
52         if (a.offset & ~PAGE_MASK)
53                 goto out;
54
55         err = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags,
56                         a.fd, a.offset >> PAGE_SHIFT);
57 out:
58         return err;
59 }
60
61 /*
62  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
63  *
64  * This is really horribly ugly.
65  */
66 asmlinkage int sys_ipc(uint call, int first, int second,
67                         int third, void __user *ptr, long fifth)
68 {
69         int version, ret;
70
71         version = call >> 16; /* hack for backward compatibility */
72         call &= 0xffff;
73
74         switch (call) {
75         case SEMOP:
76                 return sys_semtimedop(first, (struct sembuf __user *)ptr, second, NULL);
77         case SEMTIMEDOP:
78                 return sys_semtimedop(first, (struct sembuf __user *)ptr, second,
79                                         (const struct timespec __user *)fifth);
80
81         case SEMGET:
82                 return sys_semget(first, second, third);
83         case SEMCTL: {
84                 union semun fourth;
85                 if (!ptr)
86                         return -EINVAL;
87                 if (get_user(fourth.__pad, (void __user * __user *) ptr))
88                         return -EFAULT;
89                 return sys_semctl(first, second, third, fourth);
90         }
91
92         case MSGSND:
93                 return sys_msgsnd(first, (struct msgbuf __user *) ptr,
94                                    second, third);
95         case MSGRCV:
96                 switch (version) {
97                 case 0: {
98                         struct ipc_kludge tmp;
99                         if (!ptr)
100                                 return -EINVAL;
101
102                         if (copy_from_user(&tmp,
103                                            (struct ipc_kludge __user *) ptr,
104                                            sizeof(tmp)))
105                                 return -EFAULT;
106                         return sys_msgrcv(first, tmp.msgp, second,
107                                            tmp.msgtyp, third);
108                 }
109                 default:
110                         return sys_msgrcv(first,
111                                            (struct msgbuf __user *) ptr,
112                                            second, fifth, third);
113                 }
114         case MSGGET:
115                 return sys_msgget((key_t) first, second);
116         case MSGCTL:
117                 return sys_msgctl(first, second, (struct msqid_ds __user *) ptr);
118
119         case SHMAT:
120                 switch (version) {
121                 default: {
122                         ulong raddr;
123                         ret = do_shmat(first, (char __user *) ptr, second, &raddr);
124                         if (ret)
125                                 return ret;
126                         return put_user(raddr, (ulong __user *) third);
127                 }
128                 case 1: /* iBCS2 emulator entry point */
129                         if (!segment_eq(get_fs(), get_ds()))
130                                 return -EINVAL;
131                         /* The "(ulong *) third" is valid _only_ because of the kernel segment thing */
132                         return do_shmat(first, (char __user *) ptr, second, (ulong *) third);
133                 }
134         case SHMDT:
135                 return sys_shmdt((char __user *)ptr);
136         case SHMGET:
137                 return sys_shmget(first, second, third);
138         case SHMCTL:
139                 return sys_shmctl(first, second,
140                                    (struct shmid_ds __user *) ptr);
141         default:
142                 return -ENOSYS;
143         }
144 }
145
146 /*
147  * Old cruft
148  */
149 asmlinkage int sys_uname(struct old_utsname __user *name)
150 {
151         int err;
152         if (!name)
153                 return -EFAULT;
154         down_read(&uts_sem);
155         err = copy_to_user(name, utsname(), sizeof(*name));
156         up_read(&uts_sem);
157         return err? -EFAULT:0;
158 }
159
160 asmlinkage int sys_olduname(struct oldold_utsname __user *name)
161 {
162         int error;
163
164         if (!name)
165                 return -EFAULT;
166         if (!access_ok(VERIFY_WRITE, name, sizeof(struct oldold_utsname)))
167                 return -EFAULT;
168
169         down_read(&uts_sem);
170
171         error = __copy_to_user(&name->sysname, &utsname()->sysname,
172                                __OLD_UTS_LEN);
173         error |= __put_user(0, name->sysname + __OLD_UTS_LEN);
174         error |= __copy_to_user(&name->nodename, &utsname()->nodename,
175                                 __OLD_UTS_LEN);
176         error |= __put_user(0, name->nodename + __OLD_UTS_LEN);
177         error |= __copy_to_user(&name->release, &utsname()->release,
178                                 __OLD_UTS_LEN);
179         error |= __put_user(0, name->release + __OLD_UTS_LEN);
180         error |= __copy_to_user(&name->version, &utsname()->version,
181                                 __OLD_UTS_LEN);
182         error |= __put_user(0, name->version + __OLD_UTS_LEN);
183         error |= __copy_to_user(&name->machine, &utsname()->machine,
184                                 __OLD_UTS_LEN);
185         error |= __put_user(0, name->machine + __OLD_UTS_LEN);
186
187         up_read(&uts_sem);
188
189         error = error ? -EFAULT : 0;
190
191         return error;
192 }
193
194
195 /*
196  * Do a system call from kernel instead of calling sys_execve so we
197  * end up with proper pt_regs.
198  */
199 int kernel_execve(const char *filename, char *const argv[], char *const envp[])
200 {
201         long __res;
202         asm volatile ("push %%ebx ; movl %2,%%ebx ; int $0x80 ; pop %%ebx"
203         : "=a" (__res)
204         : "0" (__NR_execve), "ri" (filename), "c" (argv), "d" (envp) : "memory");
205         return __res;
206 }