2005-04-17 06:20:36 +08: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 14:29:24 +08:00
|
|
|
#include "linux/ipc.h"
|
2005-04-17 06:20:36 +08: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 18:30:22 +08: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 06:20:36 +08:00
|
|
|
*/
|
|
|
|
long sys_clone(unsigned long clone_flags, unsigned long newsp,
|
2006-03-31 18:30:22 +08:00
|
|
|
int __user *parent_tid, void *newtls, int __user *child_tid)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
long ret;
|
|
|
|
|
2005-06-26 05:55:21 +08:00
|
|
|
if (!newsp)
|
|
|
|
newsp = UPT_SP(¤t->thread.regs.regs);
|
2006-03-31 18:30:22 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
current->thread.forking = 1;
|
2005-06-26 05:55:21 +08:00
|
|
|
ret = do_fork(clone_flags, newsp, ¤t->thread.regs, 0, parent_tid,
|
|
|
|
child_tid);
|
2005-04-17 06:20:36 +08:00
|
|
|
current->thread.forking = 0;
|
2006-03-31 18:30:22 +08:00
|
|
|
return ret;
|
2005-04-17 06:20:36 +08: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 17:51:48 +08:00
|
|
|
return sys_semtimedop(first, (struct sembuf __user *) ptr,
|
|
|
|
second, NULL);
|
2005-04-17 06:20:36 +08:00
|
|
|
case SEMTIMEDOP:
|
2006-06-04 17:51:48 +08:00
|
|
|
return sys_semtimedop(first, (struct sembuf __user *) ptr,
|
|
|
|
second,
|
|
|
|
(const struct timespec __user *) fifth);
|
2005-04-17 06:20:36 +08:00
|
|
|
case SEMGET:
|
|
|
|
return sys_semget (first, second, third);
|
|
|
|
case SEMCTL: {
|
|
|
|
union semun fourth;
|
|
|
|
if (!ptr)
|
|
|
|
return -EINVAL;
|
2006-03-31 18:30:15 +08:00
|
|
|
if (get_user(fourth.__pad, (void __user * __user *) ptr))
|
2005-04-17 06:20:36 +08: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;
|
|
|
|
}
|