View of xos/kernel/sys_proc.c


XOS | Parent Directory | View | Download

/* 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 <http://www.gnu.org/licenses/>. */
 
#include "current.h"
#include "get_proc.h"
#include "signal.h"
 
#include <utsname_struct.h>
#include <verify_area.h>
#include <sleep.h>
#include <segment.h>
#include <it_stack_structs.h>
#include <errno.h>
#include <consts.h>
#include <enums.h>
#include <config.h>
#include <stddef.h>
#include <limits.h>
 
#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;
}