patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / arch / i386 / kernel / sys_i386.c
1 /*
2  * linux/arch/i386/kernel/sys_i386.c
3  *
4  * This file contains various random system calls that
5  * have a non-standard calling sequence on the Linux/i386
6  * platform.
7  */
8
9 #include <linux/errno.h>
10 #include <linux/sched.h>
11 #include <linux/mm.h>
12 #include <linux/smp.h>
13 #include <linux/smp_lock.h>
14 #include <linux/sem.h>
15 #include <linux/msg.h>
16 #include <linux/shm.h>
17 #include <linux/stat.h>
18 #include <linux/syscalls.h>
19 #include <linux/mman.h>
20 #include <linux/file.h>
21 #include <linux/utsname.h>
22 #include <linux/vs_cvirt.h>
23
24 #include <asm/uaccess.h>
25 #include <asm/ipc.h>
26
27 /*
28  * sys_pipe() is the normal C calling standard for creating
29  * a pipe. It's not the way Unix traditionally does this, though.
30  */
31 asmlinkage int sys_pipe(unsigned long __user * fildes)
32 {
33         int fd[2];
34         int error;
35
36         error = do_pipe(fd);
37         if (!error) {
38                 if (copy_to_user(fildes, fd, 2*sizeof(int)))
39                         error = -EFAULT;
40         }
41         return error;
42 }
43
44 /* common code for old and new mmaps */
45 static inline long do_mmap2(
46         unsigned long addr, unsigned long len,
47         unsigned long prot, unsigned long flags,
48         unsigned long fd, unsigned long pgoff)
49 {
50         int error = -EBADF;
51         struct file * file = NULL;
52
53         flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
54         if (!(flags & MAP_ANONYMOUS)) {
55                 file = fget(fd);
56                 if (!file)
57                         goto out;
58         }
59
60         down_write(&current->mm->mmap_sem);
61         error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
62         up_write(&current->mm->mmap_sem);
63
64         if (file)
65                 fput(file);
66 out:
67         return error;
68 }
69
70 asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
71         unsigned long prot, unsigned long flags,
72         unsigned long fd, unsigned long pgoff)
73 {
74         return do_mmap2(addr, len, prot, flags, fd, pgoff);
75 }
76
77 /*
78  * Perform the select(nd, in, out, ex, tv) and mmap() system
79  * calls. Linux/i386 didn't use to be able to handle more than
80  * 4 system call parameters, so these system calls used a memory
81  * block for parameter passing..
82  */
83
84 struct mmap_arg_struct {
85         unsigned long addr;
86         unsigned long len;
87         unsigned long prot;
88         unsigned long flags;
89         unsigned long fd;
90         unsigned long offset;
91 };
92
93 asmlinkage int old_mmap(struct mmap_arg_struct __user *arg)
94 {
95         struct mmap_arg_struct a;
96         int err = -EFAULT;
97
98         if (copy_from_user(&a, arg, sizeof(a)))
99                 goto out;
100
101         err = -EINVAL;
102         if (a.offset & ~PAGE_MASK)
103                 goto out;
104
105         err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
106 out:
107         return err;
108 }
109
110
111 struct sel_arg_struct {
112         unsigned long n;
113         fd_set __user *inp, *outp, *exp;
114         struct timeval __user *tvp;
115 };
116
117 asmlinkage int old_select(struct sel_arg_struct __user *arg)
118 {
119         struct sel_arg_struct a;
120
121         if (copy_from_user(&a, arg, sizeof(a)))
122                 return -EFAULT;
123         /* sys_select() does the appropriate kernel locking */
124         return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
125 }
126
127 /*
128  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
129  *
130  * This is really horribly ugly.
131  */
132 asmlinkage int sys_ipc (uint call, int first, int second,
133                         int third, void __user *ptr, long fifth)
134 {
135         int version, ret;
136
137         version = call >> 16; /* hack for backward compatibility */
138         call &= 0xffff;
139
140         switch (call) {
141         case SEMOP:
142                 return sys_semtimedop (first, (struct sembuf __user *)ptr, second, NULL);
143         case SEMTIMEDOP:
144                 return sys_semtimedop(first, (struct sembuf __user *)ptr, second,
145                                         (const struct timespec __user *)fifth);
146
147         case SEMGET:
148                 return sys_semget (first, second, third);
149         case SEMCTL: {
150                 union semun fourth;
151                 if (!ptr)
152                         return -EINVAL;
153                 if (get_user(fourth.__pad, (void * __user *) ptr))
154                         return -EFAULT;
155                 return sys_semctl (first, second, third, fourth);
156         }
157
158         case MSGSND:
159                 return sys_msgsnd (first, (struct msgbuf __user *) ptr, 
160                                    second, third);
161         case MSGRCV:
162                 switch (version) {
163                 case 0: {
164                         struct ipc_kludge tmp;
165                         if (!ptr)
166                                 return -EINVAL;
167                         
168                         if (copy_from_user(&tmp,
169                                            (struct ipc_kludge __user *) ptr, 
170                                            sizeof (tmp)))
171                                 return -EFAULT;
172                         return sys_msgrcv (first, tmp.msgp, second,
173                                            tmp.msgtyp, third);
174                 }
175                 default:
176                         return sys_msgrcv (first,
177                                            (struct msgbuf __user *) ptr,
178                                            second, fifth, third);
179                 }
180         case MSGGET:
181                 return sys_msgget ((key_t) first, second);
182         case MSGCTL:
183                 return sys_msgctl (first, second, (struct msqid_ds __user *) ptr);
184
185         case SHMAT:
186                 switch (version) {
187                 default: {
188                         ulong raddr;
189                         ret = do_shmat (first, (char __user *) ptr, second, &raddr);
190                         if (ret)
191                                 return ret;
192                         return put_user (raddr, (ulong __user *) third);
193                 }
194                 case 1: /* iBCS2 emulator entry point */
195                         if (!segment_eq(get_fs(), get_ds()))
196                                 return -EINVAL;
197                         /* The "(ulong *) third" is valid _only_ because of the kernel segment thing */
198                         return do_shmat (first, (char __user *) ptr, second, (ulong *) third);
199                 }
200         case SHMDT: 
201                 return sys_shmdt ((char __user *)ptr);
202         case SHMGET:
203                 return sys_shmget (first, second, third);
204         case SHMCTL:
205                 return sys_shmctl (first, second,
206                                    (struct shmid_ds __user *) ptr);
207         default:
208                 return -ENOSYS;
209         }
210 }
211
212 /*
213  * Old cruft
214  */
215 asmlinkage int sys_uname(struct old_utsname __user * name)
216 {
217         int err;
218         if (!name)
219                 return -EFAULT;
220         down_read(&uts_sem);
221         err=copy_to_user(name, vx_new_utsname(), sizeof (*name));
222         up_read(&uts_sem);
223         return err?-EFAULT:0;
224 }
225
226 asmlinkage int sys_olduname(struct oldold_utsname __user * name)
227 {
228         int error;
229         struct new_utsname *ptr;
230
231         if (!name)
232                 return -EFAULT;
233         if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
234                 return -EFAULT;
235   
236         down_read(&uts_sem);
237         
238         ptr = vx_new_utsname();
239         error = __copy_to_user(&name->sysname,ptr->sysname,__OLD_UTS_LEN);
240         error |= __put_user(0,name->sysname+__OLD_UTS_LEN);
241         error |= __copy_to_user(&name->nodename,ptr->nodename,__OLD_UTS_LEN);
242         error |= __put_user(0,name->nodename+__OLD_UTS_LEN);
243         error |= __copy_to_user(&name->release,ptr->release,__OLD_UTS_LEN);
244         error |= __put_user(0,name->release+__OLD_UTS_LEN);
245         error |= __copy_to_user(&name->version,ptr->version,__OLD_UTS_LEN);
246         error |= __put_user(0,name->version+__OLD_UTS_LEN);
247         error |= __copy_to_user(&name->machine,ptr->machine,__OLD_UTS_LEN);
248         error |= __put_user(0,name->machine+__OLD_UTS_LEN);
249         
250         up_read(&uts_sem);
251         
252         error = error ? -EFAULT : 0;
253
254         return error;
255 }