2005-04-17 02:20:36 +04:00
/*
* Copyright ( C ) 2000 - 2003 Jeff Dike ( jdike @ addtoit . com )
* Licensed under the GPL
*/
# include "linux/sched.h"
# include "linux/shm.h"
2007-10-17 10:29:24 +04:00
# include "linux/ipc.h"
2008-08-18 12:01:47 +04:00
# include "linux/syscalls.h"
2005-04-17 02:20:36 +04:00
# include "asm/mman.h"
# include "asm/uaccess.h"
# include "asm/unistd.h"
/*
* Perform the select ( nd , in , out , ex , tv ) and mmap ( ) system
* calls . Linux / i386 didn ' t use to be able to handle more than
* 4 system call parameters , so these system calls used a memory
* block for parameter passing . .
*/
struct mmap_arg_struct {
unsigned long addr ;
unsigned long len ;
unsigned long prot ;
unsigned long flags ;
unsigned long fd ;
unsigned long offset ;
} ;
extern int old_mmap ( unsigned long addr , unsigned long len ,
unsigned long prot , unsigned long flags ,
unsigned long fd , unsigned long offset ) ;
long old_mmap_i386 ( struct mmap_arg_struct __user * arg )
{
struct mmap_arg_struct a ;
int err = - EFAULT ;
if ( copy_from_user ( & a , arg , sizeof ( a ) ) )
goto out ;
err = old_mmap ( a . addr , a . len , a . prot , a . flags , a . fd , a . offset ) ;
out :
return err ;
}
struct sel_arg_struct {
unsigned long n ;
fd_set __user * inp ;
fd_set __user * outp ;
fd_set __user * exp ;
struct timeval __user * tvp ;
} ;
long old_select ( struct sel_arg_struct __user * arg )
{
struct sel_arg_struct a ;
if ( copy_from_user ( & a , arg , sizeof ( a ) ) )
return - EFAULT ;
/* sys_select() does the appropriate kernel locking */
return sys_select ( a . n , a . inp , a . outp , a . exp , a . tvp ) ;
}
2006-03-31 14:30:22 +04:00
/*
* The prototype on i386 is :
*
* int clone ( int flags , void * child_stack , int * parent_tidptr , struct user_desc * newtls , int * child_tidptr )
*
* and the " newtls " arg . on i386 is read by copy_thread directly from the
* register saved on the stack .
2005-04-17 02:20:36 +04:00
*/
long sys_clone ( unsigned long clone_flags , unsigned long newsp ,
2006-03-31 14:30:22 +04:00
int __user * parent_tid , void * newtls , int __user * child_tid )
2005-04-17 02:20:36 +04:00
{
long ret ;
2005-06-26 01:55:21 +04:00
if ( ! newsp )
newsp = UPT_SP ( & current - > thread . regs . regs ) ;
2006-03-31 14:30:22 +04:00
2005-04-17 02:20:36 +04:00
current - > thread . forking = 1 ;
2005-06-26 01:55:21 +04:00
ret = do_fork ( clone_flags , newsp , & current - > thread . regs , 0 , parent_tid ,
child_tid ) ;
2005-04-17 02:20:36 +04:00
current - > thread . forking = 0 ;
2006-03-31 14:30:22 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
/*
* sys_ipc ( ) is the de - multiplexer for the SysV IPC calls . .
*
* This is really horribly ugly .
*/
long sys_ipc ( uint call , int first , int second ,
int third , void __user * ptr , long fifth )
{
int version , ret ;
version = call > > 16 ; /* hack for backward compatibility */
call & = 0xffff ;
switch ( call ) {
case SEMOP :
2006-06-04 13:51:48 +04:00
return sys_semtimedop ( first , ( struct sembuf __user * ) ptr ,
second , NULL ) ;
2005-04-17 02:20:36 +04:00
case SEMTIMEDOP :
2006-06-04 13:51:48 +04:00
return sys_semtimedop ( first , ( struct sembuf __user * ) ptr ,
second ,
( const struct timespec __user * ) fifth ) ;
2005-04-17 02:20:36 +04:00
case SEMGET :
return sys_semget ( first , second , third ) ;
case SEMCTL : {
union semun fourth ;
if ( ! ptr )
return - EINVAL ;
2006-03-31 14:30:15 +04:00
if ( get_user ( fourth . __pad , ( void __user * __user * ) ptr ) )
2005-04-17 02:20:36 +04:00
return - EFAULT ;
return sys_semctl ( first , second , third , fourth ) ;
}
case MSGSND :
return sys_msgsnd ( first , ( struct msgbuf * ) ptr ,
second , third ) ;
case MSGRCV :
switch ( version ) {
case 0 : {
struct ipc_kludge tmp ;
if ( ! ptr )
return - EINVAL ;
if ( copy_from_user ( & tmp ,
( struct ipc_kludge * ) ptr ,
sizeof ( tmp ) ) )
return - EFAULT ;
return sys_msgrcv ( first , tmp . msgp , second ,
tmp . msgtyp , third ) ;
}
default :
panic ( " msgrcv with version != 0 " ) ;
return sys_msgrcv ( first ,
( struct msgbuf * ) ptr ,
second , fifth , third ) ;
}
case MSGGET :
return sys_msgget ( ( key_t ) first , second ) ;
case MSGCTL :
return sys_msgctl ( first , second , ( struct msqid_ds * ) ptr ) ;
case SHMAT :
switch ( version ) {
default : {
ulong raddr ;
ret = do_shmat ( first , ( char * ) ptr , second , & raddr ) ;
if ( ret )
return ret ;
return put_user ( raddr , ( ulong * ) third ) ;
}
case 1 : /* iBCS2 emulator entry point */
if ( ! segment_eq ( get_fs ( ) , get_ds ( ) ) )
return - EINVAL ;
return do_shmat ( first , ( char * ) ptr , second , ( ulong * ) third ) ;
}
case SHMDT :
return sys_shmdt ( ( char * ) ptr ) ;
case SHMGET :
return sys_shmget ( first , second , third ) ;
case SHMCTL :
return sys_shmctl ( first , second ,
( struct shmid_ds * ) ptr ) ;
default :
return - ENOSYS ;
}
}
long sys_sigaction ( int sig , const struct old_sigaction __user * act ,
struct old_sigaction __user * oact )
{
struct k_sigaction new_ka , old_ka ;
int ret ;
if ( act ) {
old_sigset_t mask ;
if ( ! access_ok ( VERIFY_READ , act , sizeof ( * act ) ) | |
__get_user ( new_ka . sa . sa_handler , & act - > sa_handler ) | |
__get_user ( new_ka . sa . sa_restorer , & act - > sa_restorer ) )
return - EFAULT ;
__get_user ( new_ka . sa . sa_flags , & act - > sa_flags ) ;
__get_user ( mask , & act - > sa_mask ) ;
siginitset ( & new_ka . sa . sa_mask , mask ) ;
}
ret = do_sigaction ( sig , act ? & new_ka : NULL , oact ? & old_ka : NULL ) ;
if ( ! ret & & oact ) {
if ( ! access_ok ( VERIFY_WRITE , oact , sizeof ( * oact ) ) | |
__put_user ( old_ka . sa . sa_handler , & oact - > sa_handler ) | |
__put_user ( old_ka . sa . sa_restorer , & oact - > sa_restorer ) )
return - EFAULT ;
__put_user ( old_ka . sa . sa_flags , & oact - > sa_flags ) ;
__put_user ( old_ka . sa . sa_mask . sig [ 0 ] , & oact - > sa_mask ) ;
}
return ret ;
}