/*
* linux/kernel/sys.c
*
* (C) 1991 Linus Torvalds
*/

#include <errno.h>		// ͷļϵͳиֳš(Linus minix )

#include <linux/sched.h>	// ȳͷļṹtask_structʼ0 ݣ
// һЩйúͻȡǶʽຯ䡣
#include <linux/tty.h>		// tty ͷļйtty_ioͨŷĲ
#include <linux/kernel.h>	// ںͷļһЩں˳úԭζ塣
#include <asm/segment.h>	// βͷļйضμĴǶʽຯ
#include <sys/times.h>		// ˽ʱĽṹtms Լtimes()ԭ͡
#include <sys/utsname.h>	// ϵͳƽṹͷļ

// ںʱ䡣
int
sys_ftime ()
{
  return -ENOSYS;
}

//
int
sys_break ()
{
  return -ENOSYS;
}

// ڵǰ̶ӽ̽е(degugging)
int
sys_ptrace ()
{
  return -ENOSYS;
}

// ı䲢ӡնá
int
sys_stty ()
{
  return -ENOSYS;
}

// ȡնϢ
int
sys_gtty ()
{
  return -ENOSYS;
}

// ޸ļ
int
sys_rename ()
{
  return -ENOSYS;
}

//
int
sys_prof ()
{
  return -ENOSYS;
}

// õǰʵԼ/ЧIDgidûгûȨ
// ôֻܻʵID ЧIDгûȨЧĺʵ
// IDgidsaved gidóЧgid ֵͬ
int
sys_setregid (int rgid, int egid)
{
  if (rgid > 0)
    {
      if ((current->gid == rgid) || suser ())
	current->gid = rgid;
      else
	return (-EPERM);
    }
  if (egid > 0)
    {
      if ((current->gid == egid) ||
	  (current->egid == egid) || (current->sgid == egid) || suser ())
	current->egid = egid;
      else
	return (-EPERM);
    }
  return 0;
}

// ý(gid)ûгûȨʹsetgid()Чgid
// effective gidΪ䱣gid(saved gid)ʵgid(real gid)
// ûȨʵgidЧgid ͱgid óɲָgid
int
sys_setgid (int gid)
{
  return (sys_setregid (gid, gid));
}

// 򿪻رս̼ʹܡ
int
sys_acct ()
{
  return -ENOSYS;
}

// ӳڴ浽̵ַռ䡣
int
sys_phys ()
{
  return -ENOSYS;
}

int
sys_lock ()
{
  return -ENOSYS;
}

int
sys_mpx ()
{
  return -ENOSYS;
}

int
sys_ulimit ()
{
  return -ENOSYS;
}

// ش1970 1 1 00:00:00 GMT ʼʱʱֵ룩tloc Ϊnullʱֵ
// Ҳ洢
int
sys_time (long *tloc)
{
  int i;

  i = CURRENT_TIME;
  if (tloc)
    {
      verify_area (tloc, 4);	// ֤ڴǷ񹻣4 ֽڣ
      put_fs_long (i, (unsigned long *) tloc);	// Ҳûݶtloc 
    }
  return i;
}

/*
* Unprivileged users may change the real user id to the effective uid
* or vice versa.
*/
/*
* ȨûԼʵûʶ(real uid)ĳЧûʶ(effective uid)֮ҲȻ
*/
// ʵԼ/ЧûIDuidûгûȨôֻܻ
// ʵûID ЧûIDгûȨЧĺʵʵûID
// uidsaved uidóЧuid ֵͬ
int
sys_setreuid (int ruid, int euid)
{
  int old_ruid = current->uid;

  if (ruid > 0)
    {
      if ((current->euid == ruid) || (old_ruid == ruid) || suser ())
	current->uid = ruid;
      else
	return (-EPERM);
    }
  if (euid > 0)
    {
      if ((old_ruid == euid) || (current->euid == euid) || suser ())
	current->euid = euid;
      else
	{
	  current->uid = old_ruid;
	  return (-EPERM);
	}
    }
  return 0;
}

// û(uid)ûгûȨʹsetuid()Чuid
// effective uidó䱣uid(saved uid)ʵuid(real uid)
// ûȨʵuidЧuid ͱuid óɲָuid
int
sys_setuid (int uid)
{
  return (sys_setreuid (uid, uid));
}

// ϵͳʱڡtptr Ǵ1970 1 1 00:00:00 GMT ʼʱʱֵ룩
// ý̱гûȨޡ
int
sys_stime (long *tptr)
{
  if (!suser ())		// ǳûأɣ
    return -EPERM;
  startup_time = get_fs_long ((unsigned long *) tptr) - jiffies / HZ;
  return 0;
}

// ȡǰʱ䡣tms ṹаûʱ䡢ϵͳʱ䡢ӽûʱ䡢ӽϵͳʱ䡣
int
sys_times (struct tms *tbuf)
{
  if (tbuf)
    {
      verify_area (tbuf, sizeof *tbuf);
      put_fs_long (current->utime, (unsigned long *) &tbuf->tms_utime);
      put_fs_long (current->stime, (unsigned long *) &tbuf->tms_stime);
      put_fs_long (current->cutime, (unsigned long *) &tbuf->tms_cutime);
      put_fs_long (current->cstime, (unsigned long *) &tbuf->tms_cstime);
    }
  return jiffies;
}

// end_data_seg ֵϵͳȷʵ㹻ڴ棬ҽûгԽݶδС
// ʱúݶĩβΪend_data_seg ֵֵָڴβҪСڶջ
// β16KBֵݶε½βֵֵҪֵͬд
// úûֱӵãlibc ⺯аװҷֵҲһ
int
sys_brk (unsigned long end_data_seg)
{
  if (end_data_seg >= current->end_code &&	// >β
      end_data_seg < current->start_stack - 16384)	// Сڶջ-16KB
    current->brk = end_data_seg;	// ݶνβֵ
  return current->brk;		// ؽ̵ǰݶνβֵ
}

/*
* This needs some heave checking ...
* I just haven't get the stomach for it. I also don't fully
* understand sessions/pgrp etc. Let somebody who does explain it.
*/
/*
* ҪĳЩϸļ顭
* ֻûθЩҲȫsessions/pgrp ȡ˽ǵɡ
*/
// pid ̵ָĽID ópgidpid=0ʹõǰ̺š
// pgid Ϊ0ʹòpid ָĽ̵ID Ϊpgidúڽ̴һ
// Ƶһ飬ͬһỰ(session)£
// pgid ָҪнIDʱĻỰID 뽫Ҫ̵ͬ(193 )
int
sys_setpgid (int pid, int pgid)
{
  int i;

  if (!pid)			// pid=0ʹõǰ̺š
    pid = current->pid;
  if (!pgid)			// pgid Ϊ0ʹõǰpid Ϊpgid
    pgid = current->pid;	// [??POSIX г]
  for (i = 0; i < NR_TASKS; i++)	// ɨ飬ָ̺ŵ
    if (task[i] && task[i]->pid == pid)
      {
	if (task[i]->leader)	// Ѿ죬ء
	  return -EPERM;
	if (task[i]->session != current->session)	// ĻỰID
	  return -EPERM;	// 뵱ǰ̵Ĳͬء
	task[i]->pgrp = pgid;	// øpgrp
	return 0;
      }
  return -ESRCH;
}

// صǰ̵šgetpgid(0)ͬ
int
sys_getpgrp (void)
{
  return current->pgrp;
}

// һỰ(session)leader=1Ự==̺š
int
sys_setsid (void)
{
  if (current->leader && !suser ())	// ǰǻỰ첢Ҳǳû
    return -EPERM;		// ء
  current->leader = 1;		// õǰΪ»Ự졣
  current->session = current->pgrp = current->pid;	// ñsession = pid
  current->tty = -1;		// ʾǰûпնˡ
  return current->pgrp;		// ػỰID
}

// ȡϵͳϢutsname ṹ5 ֶΣֱǣ汾ϵͳơڵơ
// ǰм𡢰汾Ӳơ
int
sys_uname (struct utsname *name)
{
  static struct utsname thisname = {	// ˽ṹеϢֱ϶ı䡣
    "linux .0", "nodename", "release ", "version ", "machine "
  };
  int i;

  if (!name)
    return -ERROR;		// ϢĻָΪء
  verify_area (name, sizeof *name);	// ֤СǷޣѷڴȣ
  for (i = 0; i < sizeof *name; i++)	// utsname еϢֽڸƵûС
    put_fs_byte (((char *) &thisname)[i], i + (char *) name);
  return 0;
}

// õǰ̴ļΪmask & 0777ԭ롣
int
sys_umask (int mask)
{
  int old = current->umask;

  current->umask = mask & 0777;
  return (old);
}
