summaryrefslogtreecommitdiffstats
path: root/kernel/sys.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-01-07 02:33:00 +0000
committer <ralf@linux-mips.org>1997-01-07 02:33:00 +0000
commitbeb116954b9b7f3bb56412b2494b562f02b864b1 (patch)
tree120e997879884e1b9d93b265221b939d2ef1ade1 /kernel/sys.c
parent908d4681a1dc3792ecafbe64265783a86c4cccb6 (diff)
Import of Linux/MIPS 2.1.14
Diffstat (limited to 'kernel/sys.c')
-rw-r--r--kernel/sys.c606
1 files changed, 377 insertions, 229 deletions
diff --git a/kernel/sys.c b/kernel/sys.c
index 171d2411c..b2cc8f154 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -4,6 +4,7 @@
* Copyright (C) 1991, 1992 Linus Torvalds
*/
+#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -17,19 +18,24 @@
#include <linux/stat.h>
#include <linux/mman.h>
#include <linux/mm.h>
+#include <linux/fcntl.h>
+#include <linux/acct.h>
+#include <linux/tty.h>
+#if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF)
+#include <linux/apm_bios.h>
+#endif
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/io.h>
+#include <asm/system.h>
/*
* this indicates whether you can reboot with ctrl-alt-del: the default is yes
*/
-static int C_A_D = 1;
+int C_A_D = 1;
extern void adjust_clock(void);
-#define PZERO 15
-
asmlinkage int sys_ni_syscall(void)
{
return -ENOSYS;
@@ -37,70 +43,101 @@ asmlinkage int sys_ni_syscall(void)
static int proc_sel(struct task_struct *p, int which, int who)
{
- switch (which) {
- case PRIO_PROCESS:
- if (!who && p == current)
- return 1;
- return(p->pid == who);
- case PRIO_PGRP:
- if (!who)
- who = current->pgrp;
- return(p->pgrp == who);
- case PRIO_USER:
- if (!who)
- who = current->uid;
- return(p->uid == who);
+ if(p->pid)
+ {
+ switch (which) {
+ case PRIO_PROCESS:
+ if (!who && p == current)
+ return 1;
+ return(p->pid == who);
+ case PRIO_PGRP:
+ if (!who)
+ who = current->pgrp;
+ return(p->pgrp == who);
+ case PRIO_USER:
+ if (!who)
+ who = current->uid;
+ return(p->uid == who);
+ }
}
return 0;
}
asmlinkage int sys_setpriority(int which, int who, int niceval)
{
- struct task_struct **p;
+ struct task_struct *p;
int error = ESRCH;
- int priority;
+ unsigned int priority;
if (which > 2 || which < 0)
return -EINVAL;
- if ((priority = PZERO - niceval) <= 0)
- priority = 1;
+ /* normalize: avoid signed division (rounding problems) */
+ priority = niceval;
+ if (niceval < 0)
+ priority = -niceval;
+ if (priority > 20)
+ priority = 20;
+ priority = (priority * DEF_PRIORITY + 10) / 20 + DEF_PRIORITY;
+
+ if (niceval >= 0) {
+ priority = 2*DEF_PRIORITY - priority;
+ if (!priority)
+ priority = 1;
+ }
- for(p = &LAST_TASK; p > &FIRST_TASK; --p) {
- if (!*p || !proc_sel(*p, which, who))
+ for_each_task(p) {
+ if (!proc_sel(p, which, who))
continue;
- if ((*p)->uid != current->euid &&
- (*p)->uid != current->uid && !suser()) {
+ if (p->uid != current->euid &&
+ p->uid != current->uid && !suser()) {
error = EPERM;
continue;
}
if (error == ESRCH)
error = 0;
- if (priority > (*p)->priority && !suser())
+ if (priority > p->priority && !suser())
error = EACCES;
else
- (*p)->priority = priority;
+ p->priority = priority;
}
return -error;
}
+/*
+ * Ugh. To avoid negative return values, "getpriority()" will
+ * not return the normal nice-value, but a value that has been
+ * offset by 20 (ie it returns 0..40 instead of -20..20)
+ */
asmlinkage int sys_getpriority(int which, int who)
{
- struct task_struct **p;
- int max_prio = 0;
+ struct task_struct *p;
+ long max_prio = -ESRCH;
if (which > 2 || which < 0)
return -EINVAL;
- for(p = &LAST_TASK; p > &FIRST_TASK; --p) {
- if (!*p || !proc_sel(*p, which, who))
+ for_each_task (p) {
+ if (!proc_sel(p, which, who))
continue;
- if ((*p)->priority > max_prio)
- max_prio = (*p)->priority;
+ if (p->priority > max_prio)
+ max_prio = p->priority;
}
- return(max_prio ? max_prio : -ESRCH);
+
+ /* scale the priority from timeslice to 0..40 */
+ if (max_prio > 0)
+ max_prio = (max_prio * 20 + DEF_PRIORITY/2) / DEF_PRIORITY;
+ return max_prio;
}
+#ifndef __alpha__
+
+/*
+ * Why do these exist? Binary compatibility with some other standard?
+ * If so, maybe they should be moved into the appropriate arch
+ * directory.
+ */
+
asmlinkage int sys_profil(void)
{
return -ENOSYS;
@@ -131,7 +168,8 @@ asmlinkage int sys_prof(void)
return -ENOSYS;
}
-extern void hard_reset_now(void);
+#endif
+
extern asmlinkage sys_kill(int, int);
/*
@@ -157,6 +195,9 @@ asmlinkage int sys_reboot(int magic, int magic_too, int flag)
else if (flag == 0xCDEF0123) {
printk(KERN_EMERG "System halted\n");
sys_kill(-1, SIGKILL);
+#if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF)
+ apm_set_power_state(APM_STATE_OFF);
+#endif
do_exit(0);
} else
return -EINVAL;
@@ -173,7 +214,7 @@ void ctrl_alt_del(void)
if (C_A_D)
hard_reset_now();
else
- send_sig(SIGINT,task[1],1);
+ kill_proc(1, SIGINT, 1);
}
@@ -195,6 +236,7 @@ void ctrl_alt_del(void)
asmlinkage int sys_setregid(gid_t rgid, gid_t egid)
{
int old_rgid = current->gid;
+ int old_egid = current->egid;
if (rgid != (gid_t) -1) {
if ((old_rgid == rgid) ||
@@ -209,7 +251,7 @@ asmlinkage int sys_setregid(gid_t rgid, gid_t egid)
(current->egid == egid) ||
(current->sgid == egid) ||
suser())
- current->egid = egid;
+ current->fsgid = current->egid = egid;
else {
current->gid = old_rgid;
return(-EPERM);
@@ -219,6 +261,8 @@ asmlinkage int sys_setregid(gid_t rgid, gid_t egid)
(egid != (gid_t) -1 && egid != old_rgid))
current->sgid = current->egid;
current->fsgid = current->egid;
+ if (current->egid != old_egid)
+ current->dumpable = 0;
return 0;
}
@@ -227,19 +271,134 @@ asmlinkage int sys_setregid(gid_t rgid, gid_t egid)
*/
asmlinkage int sys_setgid(gid_t gid)
{
+ int old_egid = current->egid;
+
if (suser())
current->gid = current->egid = current->sgid = current->fsgid = gid;
else if ((gid == current->gid) || (gid == current->sgid))
current->egid = current->fsgid = gid;
else
return -EPERM;
+ if (current->egid != old_egid)
+ current->dumpable = 0;
return 0;
}
+
+static char acct_active = 0;
+static struct file acct_file;
+
+int acct_process(long exitcode)
+{
+ struct acct ac;
+ unsigned short fs;
+
+ if (acct_active) {
+ strncpy(ac.ac_comm, current->comm, ACCT_COMM);
+ ac.ac_comm[ACCT_COMM-1] = '\0';
+ ac.ac_utime = current->utime;
+ ac.ac_stime = current->stime;
+ ac.ac_btime = CT_TO_SECS(current->start_time) + (xtime.tv_sec - (jiffies / HZ));
+ ac.ac_etime = CURRENT_TIME - ac.ac_btime;
+ ac.ac_uid = current->uid;
+ ac.ac_gid = current->gid;
+ ac.ac_tty = (current)->tty == NULL ? -1 :
+ kdev_t_to_nr(current->tty->device);
+ ac.ac_flag = 0;
+ if (current->flags & PF_FORKNOEXEC)
+ ac.ac_flag |= AFORK;
+ if (current->flags & PF_SUPERPRIV)
+ ac.ac_flag |= ASU;
+ if (current->flags & PF_DUMPCORE)
+ ac.ac_flag |= ACORE;
+ if (current->flags & PF_SIGNALED)
+ ac.ac_flag |= AXSIG;
+ ac.ac_minflt = current->min_flt;
+ ac.ac_majflt = current->maj_flt;
+ ac.ac_exitcode = exitcode;
+
+ /* Kernel segment override */
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+
+ acct_file.f_op->write(acct_file.f_inode, &acct_file,
+ (char *)&ac, sizeof(struct acct));
+
+ set_fs(fs);
+ }
+ return 0;
+}
+
+asmlinkage int sys_acct(const char *name)
+{
+ struct inode *inode = (struct inode *)0;
+ char *tmp;
+ int error;
+
+ if (!suser())
+ return -EPERM;
+
+ if (name == (char *)0) {
+ if (acct_active) {
+ if (acct_file.f_op->release)
+ acct_file.f_op->release(acct_file.f_inode, &acct_file);
+
+ if (acct_file.f_inode != (struct inode *) 0)
+ iput(acct_file.f_inode);
+
+ acct_active = 0;
+ }
+ return 0;
+ } else {
+ if (!acct_active) {
+
+ if ((error = getname(name, &tmp)) != 0)
+ return (error);
+
+ error = open_namei(tmp, O_RDWR, 0600, &inode, 0);
+ putname(tmp);
+
+ if (error)
+ return (error);
+
+ if (!S_ISREG(inode->i_mode)) {
+ iput(inode);
+ return -EACCES;
+ }
+
+ if (!inode->i_op || !inode->i_op->default_file_ops ||
+ !inode->i_op->default_file_ops->write) {
+ iput(inode);
+ return -EIO;
+ }
+
+ acct_file.f_mode = 3;
+ acct_file.f_flags = 0;
+ acct_file.f_count = 1;
+ acct_file.f_inode = inode;
+ acct_file.f_pos = inode->i_size;
+ acct_file.f_reada = 0;
+ acct_file.f_op = inode->i_op->default_file_ops;
+
+ if (acct_file.f_op->open)
+ if (acct_file.f_op->open(acct_file.f_inode, &acct_file)) {
+ iput(inode);
+ return -EIO;
+ }
+
+ acct_active = 1;
+ return 0;
+ } else
+ return -EBUSY;
+ }
+}
+
+#ifndef __alpha__
-asmlinkage int sys_acct(void)
-{
- return -ENOSYS;
-}
+/*
+ * Why do these exist? Binary compatibility with some other standard?
+ * If so, maybe they should be moved into the appropriate arch
+ * directory.
+ */
asmlinkage int sys_phys(void)
{
@@ -266,6 +425,8 @@ asmlinkage int sys_old_syscall(void)
return -ENOSYS;
}
+#endif
+
/*
* Unprivileged users may change the real uid to the effective uid
* or vice versa. (BSD-style)
@@ -284,6 +445,7 @@ asmlinkage int sys_old_syscall(void)
asmlinkage int sys_setreuid(uid_t ruid, uid_t euid)
{
int old_ruid = current->uid;
+ int old_euid = current->euid;
if (ruid != (uid_t) -1) {
if ((old_ruid == ruid) ||
@@ -298,7 +460,7 @@ asmlinkage int sys_setreuid(uid_t ruid, uid_t euid)
(current->euid == euid) ||
(current->suid == euid) ||
suser())
- current->euid = euid;
+ current->fsuid = current->euid = euid;
else {
current->uid = old_ruid;
return(-EPERM);
@@ -308,6 +470,8 @@ asmlinkage int sys_setreuid(uid_t ruid, uid_t euid)
(euid != (uid_t) -1 && euid != old_ruid))
current->suid = current->euid;
current->fsuid = current->euid;
+ if (current->euid != old_euid)
+ current->dumpable = 0;
return 0;
}
@@ -324,15 +488,61 @@ asmlinkage int sys_setreuid(uid_t ruid, uid_t euid)
*/
asmlinkage int sys_setuid(uid_t uid)
{
+ int old_euid = current->euid;
+
if (suser())
current->uid = current->euid = current->suid = current->fsuid = uid;
else if ((uid == current->uid) || (uid == current->suid))
current->fsuid = current->euid = uid;
else
return -EPERM;
+ if (current->euid != old_euid)
+ current->dumpable = 0;
return(0);
}
+
+/*
+ * This function implementes a generic ability to update ruid, euid,
+ * and suid. This allows you to implement the 4.4 compatible seteuid().
+ */
+asmlinkage int sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
+{
+ uid_t old_ruid, old_euid, old_suid;
+
+ old_ruid = current->uid;
+ old_euid = current->euid;
+ old_suid = current->suid;
+
+ if ((ruid != (uid_t) -1) && (ruid != current->uid) &&
+ (ruid != current->euid) && (ruid != current->suid))
+ return -EPERM;
+ if ((euid != (uid_t) -1) && (euid != current->uid) &&
+ (euid != current->euid) && (euid != current->suid))
+ return -EPERM;
+ if ((suid != (uid_t) -1) && (suid != current->uid) &&
+ (suid != current->euid) && (suid != current->suid))
+ return -EPERM;
+ if (ruid != (uid_t) -1)
+ current->uid = ruid;
+ if (euid != (uid_t) -1)
+ current->euid = euid;
+ if (suid != (uid_t) -1)
+ current->suid = suid;
+ return 0;
+}
+
+asmlinkage int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
+{
+ int retval;
+
+ if (!(retval = put_user(current->uid, ruid)) &&
+ !(retval = put_user(current->euid, euid)))
+ retval = put_user(current->suid, suid);
+ return retval;
+}
+
+
/*
* "setfsuid()" sets the fsuid - the uid used for filesystem checks. This
* is used for "access()" and for the NFS daemon (letting nfsd stay at
@@ -346,6 +556,8 @@ asmlinkage int sys_setfsuid(uid_t uid)
if (uid == current->uid || uid == current->euid ||
uid == current->suid || uid == current->fsuid || suser())
current->fsuid = uid;
+ if (current->fsuid != old_fsuid)
+ current->dumpable = 0;
return old_fsuid;
}
@@ -359,95 +571,31 @@ asmlinkage int sys_setfsgid(gid_t gid)
if (gid == current->gid || gid == current->egid ||
gid == current->sgid || gid == current->fsgid || suser())
current->fsgid = gid;
+ if (current->fsgid != old_fsgid)
+ current->dumpable = 0;
return old_fsgid;
}
-asmlinkage int sys_times(struct tms * tbuf)
+asmlinkage long sys_times(struct tms * tbuf)
{
+ int error;
if (tbuf) {
- int error = verify_area(VERIFY_WRITE,tbuf,sizeof *tbuf);
+ error = put_user(current->utime,&tbuf->tms_utime);
+ if (!error)
+ error = put_user(current->stime,&tbuf->tms_stime);
+ if (!error)
+ error = put_user(current->cutime,&tbuf->tms_cutime);
+ if (!error)
+ error = put_user(current->cstime,&tbuf->tms_cstime);
if (error)
- return error;
- 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 error;
}
return jiffies;
}
-asmlinkage unsigned long sys_brk(unsigned long brk)
-{
- int freepages;
- unsigned long rlim;
- unsigned long newbrk, oldbrk;
-
- if (brk < current->mm->end_code)
- return current->mm->brk;
- newbrk = PAGE_ALIGN(brk);
- oldbrk = PAGE_ALIGN(current->mm->brk);
- if (oldbrk == newbrk)
- return current->mm->brk = brk;
-
- /*
- * Always allow shrinking brk
- */
- if (brk <= current->mm->brk) {
- current->mm->brk = brk;
- do_munmap(newbrk, oldbrk-newbrk);
- return brk;
- }
- /*
- * Check against rlimit and stack..
- */
- rlim = current->rlim[RLIMIT_DATA].rlim_cur;
- if (rlim >= RLIM_INFINITY)
- rlim = ~0;
- if (brk - current->mm->end_code > rlim)
- return current->mm->brk;
- /*
- * Check against existing mmap mappings.
- */
- if (find_vma_intersection(current, oldbrk, newbrk+PAGE_SIZE))
- return current->mm->brk;
- /*
- * stupid algorithm to decide if we have enough memory: while
- * simple, it hopefully works in most obvious cases.. Easy to
- * fool it, but this should catch most mistakes.
- */
- freepages = buffermem >> 12;
- freepages += nr_free_pages;
- freepages += nr_swap_pages;
-#if 0
- /*
- * This assumes a PCish memory architecture...
- */
- freepages -= (high_memory - 0x100000) >> 16;
-#else
- freepages -= (high_memory - KSEG0) >> 16;
-#endif
- freepages -= (newbrk-oldbrk) >> 12;
- if (freepages < 0)
- return current->mm->brk;
-#if 0
- freepages += current->mm->rss;
- freepages -= oldbrk >> 12;
- if (freepages < 0)
- return current->mm->brk;
-#endif
- /*
- * Ok, we have probably got enough memory - let it rip.
- */
- current->mm->brk = brk;
- do_mmap(NULL, oldbrk, newbrk-oldbrk,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE, 0);
- return brk;
-}
-
/*
- * This needs some heave checking ...
- * I just haven't get the stomach for it. I also don't fully
+ * This needs some heavy checking ...
+ * I just haven't the stomach for it. I also don't fully
* understand sessions/pgrp etc. Let somebody who does explain it.
*
* OK, I think I have the protection semantics right.... this is really
@@ -516,10 +664,28 @@ asmlinkage int sys_getpgrp(void)
return current->pgrp;
}
+asmlinkage int sys_getsid(pid_t pid)
+{
+ struct task_struct * p;
+
+ if (!pid)
+ return current->session;
+ for_each_task(p) {
+ if (p->pid == pid)
+ return p->session;
+ }
+ return -ESRCH;
+}
+
asmlinkage int sys_setsid(void)
{
- if (current->leader)
- return -EPERM;
+ struct task_struct * p;
+
+ for_each_task(p) {
+ if (p->pgrp == current->pid)
+ return -EPERM;
+ }
+
current->leader = 1;
current->session = current->pgrp = current->pid;
current->tty = NULL;
@@ -533,88 +699,76 @@ asmlinkage int sys_setsid(void)
asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist)
{
int i;
- int * groups;
+ if (gidsetsize < 0)
+ return -EINVAL;
+ i = current->ngroups;
if (gidsetsize) {
- i = verify_area(VERIFY_WRITE, grouplist, sizeof(gid_t) * gidsetsize);
- if (i)
- return i;
+ if (i > gidsetsize)
+ return -EINVAL;
+ if (copy_to_user(grouplist, current->groups, sizeof(gid_t)*i))
+ return -EFAULT;
}
- groups = current->groups;
- for (i = 0 ; (i < NGROUPS) && (*groups != NOGROUP) ; i++, groups++) {
- if (!gidsetsize)
- continue;
- if (i >= gidsetsize)
- break;
- put_user(*groups, grouplist);
- grouplist++;
- }
- return(i);
+ return i;
}
asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist)
{
- int i;
+ int err;
if (!suser())
return -EPERM;
- if (gidsetsize > NGROUPS)
+ if ((unsigned) gidsetsize > NGROUPS)
return -EINVAL;
- for (i = 0; i < gidsetsize; i++, grouplist++) {
- current->groups[i] = get_fs_word((unsigned short *) grouplist);
- }
- if (i < NGROUPS)
- current->groups[i] = NOGROUP;
- return 0;
+ err = copy_from_user(current->groups, grouplist, gidsetsize * sizeof(gid_t));
+ if (err) {
+ gidsetsize = 0;
+ err = -EFAULT;
+ }
+ current->ngroups = gidsetsize;
+ return err;
}
int in_group_p(gid_t grp)
{
- int i;
-
- if (grp == current->fsgid)
- return 1;
-
- for (i = 0; i < NGROUPS; i++) {
- if (current->groups[i] == NOGROUP)
- break;
- if (current->groups[i] == grp)
- return 1;
+ if (grp != current->fsgid) {
+ int i = current->ngroups;
+ if (i) {
+ gid_t *groups = current->groups;
+ do {
+ if (*groups == grp)
+ goto out;
+ groups++;
+ i--;
+ } while (i);
+ }
+ return 0;
}
- return 0;
+out:
+ return 1;
}
asmlinkage int sys_newuname(struct new_utsname * name)
{
- int error;
-
if (!name)
return -EFAULT;
- error = verify_area(VERIFY_WRITE, name, sizeof *name);
- if (!error)
- memcpy_tofs(name,&system_utsname,sizeof *name);
- return error;
+ if (copy_to_user(name,&system_utsname,sizeof *name))
+ return -EFAULT;
+ return 0;
}
+#ifndef __alpha__
+
+/*
+ * Move these to arch dependent dir since they are for
+ * backward compatibility only?
+ */
asmlinkage int sys_uname(struct old_utsname * name)
{
- int error;
- if (!name)
- return -EFAULT;
- error = verify_area(VERIFY_WRITE, name,sizeof *name);
- if (error)
- return error;
- memcpy_tofs(&name->sysname,&system_utsname.sysname,
- sizeof (system_utsname.sysname));
- memcpy_tofs(&name->nodename,&system_utsname.nodename,
- sizeof (system_utsname.nodename));
- memcpy_tofs(&name->release,&system_utsname.release,
- sizeof (system_utsname.release));
- memcpy_tofs(&name->version,&system_utsname.version,
- sizeof (system_utsname.version));
- memcpy_tofs(&name->machine,&system_utsname.machine,
- sizeof (system_utsname.machine));
- return 0;
+ int error = -EFAULT;;
+ if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
+ error = 0;
+ return error;
}
asmlinkage int sys_olduname(struct oldold_utsname * name)
@@ -622,22 +776,30 @@ asmlinkage int sys_olduname(struct oldold_utsname * name)
int error;
if (!name)
return -EFAULT;
- error = verify_area(VERIFY_WRITE, name,sizeof *name);
- if (error)
- return error;
- memcpy_tofs(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
- put_fs_byte(0,name->sysname+__OLD_UTS_LEN);
- memcpy_tofs(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
- put_fs_byte(0,name->nodename+__OLD_UTS_LEN);
- memcpy_tofs(&name->release,&system_utsname.release,__OLD_UTS_LEN);
- put_fs_byte(0,name->release+__OLD_UTS_LEN);
- memcpy_tofs(&name->version,&system_utsname.version,__OLD_UTS_LEN);
- put_fs_byte(0,name->version+__OLD_UTS_LEN);
- memcpy_tofs(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
- put_fs_byte(0,name->machine+__OLD_UTS_LEN);
- return 0;
+ error = copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
+ if (!error)
+ error = put_user(0,name->sysname+__OLD_UTS_LEN);
+ if (!error)
+ error = copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
+ if (!error)
+ error = put_user(0,name->nodename+__OLD_UTS_LEN);
+ if (!error)
+ error = copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
+ if (!error)
+ error = put_user(0,name->release+__OLD_UTS_LEN);
+ if (!error)
+ error = copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
+ if (!error)
+ error = put_user(0,name->version+__OLD_UTS_LEN);
+ if (!error)
+ error = copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
+ if (!error)
+ error = put_user(0,name->machine+__OLD_UTS_LEN);
+ return error ? -EFAULT : 0;
}
+#endif
+
asmlinkage int sys_sethostname(char *name, int len)
{
int error;
@@ -646,10 +808,9 @@ asmlinkage int sys_sethostname(char *name, int len)
return -EPERM;
if (len < 0 || len > __NEW_UTS_LEN)
return -EINVAL;
- error = verify_area(VERIFY_READ, name, len);
+ error = copy_from_user(system_utsname.nodename, name, len);
if (error)
- return error;
- memcpy_fromfs(system_utsname.nodename, name, len);
+ return -EFAULT;
system_utsname.nodename[len] = 0;
return 0;
}
@@ -660,14 +821,10 @@ asmlinkage int sys_gethostname(char *name, int len)
if (len < 0)
return -EINVAL;
- i = verify_area(VERIFY_WRITE, name, len);
- if (i)
- return i;
i = 1+strlen(system_utsname.nodename);
if (i > len)
i = len;
- memcpy_tofs(name, system_utsname.nodename, i);
- return 0;
+ return copy_to_user(name, system_utsname.nodename, i) ? -EFAULT : 0;
}
/*
@@ -676,31 +833,25 @@ asmlinkage int sys_gethostname(char *name, int len)
*/
asmlinkage int sys_setdomainname(char *name, int len)
{
- int i;
+ int error;
if (!suser())
return -EPERM;
- if (len > __NEW_UTS_LEN)
+ if (len < 0 || len > __NEW_UTS_LEN)
return -EINVAL;
- for (i=0; i < len; i++) {
- if ((system_utsname.domainname[i] = get_fs_byte(name+i)) == 0)
- return 0;
- }
- system_utsname.domainname[i] = 0;
+ error = copy_from_user(system_utsname.domainname, name, len);
+ if (error)
+ return -EFAULT;
+ system_utsname.domainname[len] = 0;
return 0;
}
asmlinkage int sys_getrlimit(unsigned int resource, struct rlimit *rlim)
{
- int error;
-
if (resource >= RLIM_NLIMITS)
return -EINVAL;
- error = verify_area(VERIFY_WRITE,rlim,sizeof *rlim);
- if (error)
- return error;
- memcpy_tofs(rlim, current->rlim + resource, sizeof(*rlim));
- return 0;
+ return copy_to_user(rlim, current->rlim + resource, sizeof(*rlim))
+ ? -EFAULT : 0 ;
}
asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim)
@@ -710,10 +861,9 @@ asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim)
if (resource >= RLIM_NLIMITS)
return -EINVAL;
- err = verify_area(VERIFY_READ, rlim, sizeof(*rlim));
+ err = copy_from_user(&new_rlim, rlim, sizeof(*rlim));
if (err)
- return err;
- memcpy_fromfs(&new_rlim, rlim, sizeof(*rlim));
+ return -EFAULT;
old_rlim = current->rlim + resource;
if (((new_rlim.rlim_cur > old_rlim->rlim_max) ||
(new_rlim.rlim_max > old_rlim->rlim_max)) &&
@@ -737,12 +887,8 @@ asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim)
*/
int getrusage(struct task_struct *p, int who, struct rusage *ru)
{
- int error;
struct rusage r;
- error = verify_area(VERIFY_WRITE, ru, sizeof *ru);
- if (error)
- return error;
memset((char *) &r, 0, sizeof(r));
switch (who) {
case RUSAGE_SELF:
@@ -750,28 +896,30 @@ int getrusage(struct task_struct *p, int who, struct rusage *ru)
r.ru_utime.tv_usec = CT_TO_USECS(p->utime);
r.ru_stime.tv_sec = CT_TO_SECS(p->stime);
r.ru_stime.tv_usec = CT_TO_USECS(p->stime);
- r.ru_minflt = p->mm->min_flt;
- r.ru_majflt = p->mm->maj_flt;
+ r.ru_minflt = p->min_flt;
+ r.ru_majflt = p->maj_flt;
+ r.ru_nswap = p->nswap;
break;
case RUSAGE_CHILDREN:
r.ru_utime.tv_sec = CT_TO_SECS(p->cutime);
r.ru_utime.tv_usec = CT_TO_USECS(p->cutime);
r.ru_stime.tv_sec = CT_TO_SECS(p->cstime);
r.ru_stime.tv_usec = CT_TO_USECS(p->cstime);
- r.ru_minflt = p->mm->cmin_flt;
- r.ru_majflt = p->mm->cmaj_flt;
+ r.ru_minflt = p->cmin_flt;
+ r.ru_majflt = p->cmaj_flt;
+ r.ru_nswap = p->cnswap;
break;
default:
r.ru_utime.tv_sec = CT_TO_SECS(p->utime + p->cutime);
r.ru_utime.tv_usec = CT_TO_USECS(p->utime + p->cutime);
r.ru_stime.tv_sec = CT_TO_SECS(p->stime + p->cstime);
r.ru_stime.tv_usec = CT_TO_USECS(p->stime + p->cstime);
- r.ru_minflt = p->mm->min_flt + p->mm->cmin_flt;
- r.ru_majflt = p->mm->maj_flt + p->mm->cmaj_flt;
+ r.ru_minflt = p->min_flt + p->cmin_flt;
+ r.ru_majflt = p->maj_flt + p->cmaj_flt;
+ r.ru_nswap = p->nswap + p->cnswap;
break;
}
- memcpy_tofs(ru, &r, sizeof(r));
- return 0;
+ return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0;
}
asmlinkage int sys_getrusage(int who, struct rusage *ru)