/* 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; }