/* Copyright (C) 2008 Emmanuel Varoquaux
This file is part of XOS.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see . */
#include "current.h"
#include "get_proc.h"
#include "signal.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SEC_MAX (ULONG_MAX / 1000)
static struct proc_struct *get_child(int pid)
{
struct proc_struct *proc;
if (!(proc = get_proc(pid)))
return NULL;
if (!(is_child(proc)))
return NULL;
return proc;
}
void __attribute__ ((noreturn)) do_exit(int status)
{
exit(status & 0377);
}
int do_fork(struct syscall_args_struct args)
{
return fork(args.registers, args.interrupted_instruction);
}
int do_exec(struct syscall_args_struct args)
{
int status;
int rv;
if ((rv = exec((char *)args.arg1, (char **)args.arg2, (char **)args.arg3, args.registers, args.interrupted_instruction, &status)) < 0)
return rv;
if (status < 0)
signal_self(SIGSEGV);
return 0;
}
int do_getpid()
{
return get_pid();
}
int do_getpgid()
{
return get_pgid();
}
int do_setpgid(int pid, int pgid)
{
struct proc_struct *child;
struct proc_group_struct *proc_group;
if (pgid < 0)
return -EINVAL;
if (!pid)
pid = get_pid();
if (!pgid)
pgid = pid;
if (!(proc_group = get_proc_group(pgid)) && pgid != pid)
return -EPERM;
if (pid == get_pid()) {
if (proc_group) {
change_set_proc_group(proc_group);
return 0;
}
else
return change_create_proc_group();
}
else {
if (!(child = get_child(pid)))
return -ESRCH;
if (proc_group)
return change_set_child_proc_group(child, proc_group);
else
return change_create_child_proc_group(child);
}
}
int do_chdir(const char *fs_path)
{
return change_wd(fs_path);
}
int do_sbrk(int increment, void **fs_brk)
{
unsigned long new_brk;
int rv;
if ((rv = sbrk(increment, &new_brk)) < 0)
return rv;
if (fs_brk) {
if (!verify_area(fs_brk, sizeof (long), PF_WRITE))
return -EFAULT;
put_fs_long((long)new_brk, (long *)fs_brk);
}
return 0;
}
unsigned int do_sleep(unsigned int seconds)
{
int unslept;
if (!seconds)
return 0;
while (seconds > SEC_MAX) {
unslept = sleep(SEC_MAX * 1000);
seconds -= SEC_MAX;
if (unslept)
return seconds + unslept / 1000;
}
return sleep(seconds * 1000) / 1000;
}
static int wait_pid(int pid, int *status, int options)
{
struct proc_struct *child;
if (!(child = get_child(pid)))
return -ECHILD;
return wait(child, status, options);
}
static int wait_pgid(int pgid, int *status, int options)
{
struct proc_group_struct *proc_group;
if (!(proc_group = get_proc_group(pgid)))
return -ECHILD;
return wait_group_any(proc_group, status, options);
}
int do_wait(int pid, int *fs_status, int options)
{
int child_status;
int retval;
if (pid == -1) {
if ((retval = wait_any(&child_status, options)) < 0)
return retval;
}
else if (pid > 0) {
if ((retval = wait_pid(pid, &child_status, options)) < 0)
return retval;
}
else if (pid == 0) {
if ((retval = wait_pgid(get_pgid(), &child_status, options)) < 0)
return retval;
}
else { /* pid < -1 */
if ((retval = wait_pgid(-pid, &child_status, options)) < 0)
return retval;
}
if (fs_status) {
if (!verify_area(fs_status, sizeof (long), PF_WRITE))
return -EFAULT;
put_fs_long(child_status, (long *)fs_status);
}
return retval;
}
static int kill_proc(int pid, int sig)
{
struct proc_struct *proc;
if (!(proc = get_proc(pid)))
return -ESRCH;
if (sig < 0 || sig >=32)
return -EINVAL;
signal(proc, sig);
return 0;
}
static int kill_proc_group(int pgid, int sig)
{
struct proc_group_struct *proc_group;
if (!(proc_group = get_proc_group(pgid)))
return -ESRCH;
if (sig < 0 || sig >=32)
return -EINVAL;
signal_group(proc_group, sig);
return 0;
}
static int kill_all(int sig)
{
if (sig < 0 || sig >=32)
return -EINVAL;
signal_all(sig);
return 0;
}
int do_kill(int pid, int sig)
{
if (pid > 0)
return kill_proc(pid, sig);
else if (pid == 0)
return kill_proc_group(get_pgid(), sig);
else if (pid == -1)
return kill_all(sig);
else /* pid < -1 */
return kill_proc_group(-pid, sig);
}
int do_uname(struct utsname_struct *fs_name)
{
if (!verify_area(fs_name, sizeof (struct utsname_struct), PF_WRITE))
return -EFAULT;
memset_tofs(fs_name->sysname, '\0', UTSNAME_LENGTH);
strncpy_tofs(fs_name->sysname, OS_NAME, UTSNAME_LENGTH - 1);
memset_tofs(fs_name->release, '\0', UTSNAME_LENGTH);
strncpy_tofs(fs_name->release, OS_VERSION, UTSNAME_LENGTH - 1);
memset_tofs(fs_name->version, '\0', UTSNAME_LENGTH);
strncpy_tofs(fs_name->version, OS_BUILD, UTSNAME_LENGTH - 1);
memset_tofs(fs_name->machine, '\0', UTSNAME_LENGTH);
strncpy_tofs(fs_name->machine, OS_MACHINE, UTSNAME_LENGTH - 1);
return 0;
}