more changes on original files
[linux-2.4.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/mman.h>
19 #include <linux/file.h>
20 #include <linux/utsname.h>
21
22 #include <asm/uaccess.h>
23 #include <asm/ipc.h>
24
25 /*
26  * sys_pipe() is the normal C calling standard for creating
27  * a pipe. It's not the way Unix traditionally does this, though.
28  */
29 asmlinkage int sys_pipe(unsigned long * fildes)
30 {
31         int fd[2];
32         int error;
33
34         error = do_pipe(fd);
35         if (!error) {
36                 if (copy_to_user(fildes, fd, 2*sizeof(int)))
37                         error = -EFAULT;
38         }
39         return error;
40 }
41
42 /* common code for old and new mmaps */
43 static inline long do_mmap2(
44         unsigned long addr, unsigned long len,
45         unsigned long prot, unsigned long flags,
46         unsigned long fd, unsigned long pgoff)
47 {
48         int error = -EBADF;
49         struct file * file = NULL;
50
51         flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
52         if (!(flags & MAP_ANONYMOUS)) {
53                 file = fget(fd);
54                 if (!file)
55                         goto out;
56         }
57
58         down_write(&current->mm->mmap_sem);
59         error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
60         up_write(&current->mm->mmap_sem);
61
62         if (file)
63                 fput(file);
64 out:
65         return error;
66 }
67
68 asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
69         unsigned long prot, unsigned long flags,
70         unsigned long fd, unsigned long pgoff)
71 {
72         return do_mmap2(addr, len, prot, flags, fd, pgoff);
73 }
74
75 /*
76  * Perform the select(nd, in, out, ex, tv) and mmap() system
77  * calls. Linux/i386 didn't use to be able to handle more than
78  * 4 system call parameters, so these system calls used a memory
79  * block for parameter passing..
80  */
81
82 struct mmap_arg_struct {
83         unsigned long addr;
84         unsigned long len;
85         unsigned long prot;
86         unsigned long flags;
87         unsigned long fd;
88         unsigned long offset;
89 };
90
91 asmlinkage int old_mmap(struct mmap_arg_struct *arg)
92 {
93         struct mmap_arg_struct a;
94         int err = -EFAULT;
95
96         if (copy_from_user(&a, arg, sizeof(a)))
97                 goto out;
98
99         err = -EINVAL;
100         if (a.offset & ~PAGE_MASK)
101                 goto out;
102
103         err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
104 out:
105         return err;
106 }
107
108
109 extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
110
111 struct sel_arg_struct {
112         unsigned long n;
113         fd_set *inp, *outp, *exp;
114         struct timeval *tvp;
115 };
116
117 asmlinkage int old_select(struct sel_arg_struct *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 *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 *)ptr, second, NULL);
143         case SEMTIMEDOP:
144                 return sys_semtimedop (first, (struct sembuf *)ptr, second, 
145                                        (const struct timespec *)fifth);
146         case SEMGET:
147                 return sys_semget (first, second, third);
148         case SEMCTL: {
149                 union semun fourth;
150                 if (!ptr)
151                         return -EINVAL;
152                 if (get_user(fourth.__pad, (void **) ptr))
153                         return -EFAULT;
154                 return sys_semctl (first, second, third, fourth);
155         }
156
157         case MSGSND:
158                 return sys_msgsnd (first, (struct msgbuf *) ptr, 
159                                    second, third);
160         case MSGRCV:
161                 switch (version) {
162                 case 0: {
163                         struct ipc_kludge tmp;
164                         if (!ptr)
165                                 return -EINVAL;
166                         
167                         if (copy_from_user(&tmp,
168                                            (struct ipc_kludge *) ptr, 
169                                            sizeof (tmp)))
170                                 return -EFAULT;
171                         return sys_msgrcv (first, tmp.msgp, second,
172                                            tmp.msgtyp, third);
173                 }
174                 default:
175                         return sys_msgrcv (first,
176                                            (struct msgbuf *) ptr,
177                                            second, fifth, third);
178                 }
179         case MSGGET:
180                 return sys_msgget ((key_t) first, second);
181         case MSGCTL:
182                 return sys_msgctl (first, second, (struct msqid_ds *) ptr);
183
184         case SHMAT:
185                 switch (version) {
186                 default: {
187                         ulong raddr;
188                         ret = sys_shmat (first, (char *) ptr, second, &raddr);
189                         if (ret)
190                                 return ret;
191                         return put_user (raddr, (ulong *) third);
192                 }
193                 case 1: /* iBCS2 emulator entry point */
194                         if (!segment_eq(get_fs(), get_ds()))
195                                 return -EINVAL;
196                         return sys_shmat (first, (char *) ptr, second, (ulong *) third);
197                 }
198         case SHMDT: 
199                 return sys_shmdt ((char *)ptr);
200         case SHMGET:
201                 return sys_shmget (first, second, third);
202         case SHMCTL:
203                 return sys_shmctl (first, second,
204                                    (struct shmid_ds *) ptr);
205         default:
206                 return -ENOSYS;
207         }
208 }
209
210 /*
211  * Old cruft
212  */
213 asmlinkage int sys_uname(struct old_utsname * name)
214 {
215         int err;
216         if (!name)
217                 return -EFAULT;
218         down_read(&uts_sem);
219         err=copy_to_user(name, &system_utsname, sizeof (*name));
220         up_read(&uts_sem);
221         return err?-EFAULT:0;
222 }
223
224 asmlinkage int sys_olduname(struct oldold_utsname * name)
225 {
226         int error;
227
228         if (!name)
229                 return -EFAULT;
230         if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
231                 return -EFAULT;
232   
233         down_read(&uts_sem);
234         
235         error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
236         error |= __put_user(0,name->sysname+__OLD_UTS_LEN);
237         error |= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
238         error |= __put_user(0,name->nodename+__OLD_UTS_LEN);
239         error |= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
240         error |= __put_user(0,name->release+__OLD_UTS_LEN);
241         error |= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
242         error |= __put_user(0,name->version+__OLD_UTS_LEN);
243         error |= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
244         error |= __put_user(0,name->machine+__OLD_UTS_LEN);
245         
246         up_read(&uts_sem);
247         
248         error = error ? -EFAULT : 0;
249
250         return error;
251 }
252
253 asmlinkage int sys_pause(void)
254 {
255         current->state = TASK_INTERRUPTIBLE;
256         schedule();
257         return -ERESTARTNOHAND;
258 }
259