root/kernel/sys.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sys_ni_syscall
  2. proc_sel
  3. sys_setpriority
  4. sys_getpriority
  5. sys_profil
  6. sys_ftime
  7. sys_break
  8. sys_stty
  9. sys_gtty
  10. sys_prof
  11. sys_reboot
  12. ctrl_alt_del
  13. sys_setregid
  14. sys_setgid
  15. sys_acct
  16. sys_phys
  17. sys_lock
  18. sys_mpx
  19. sys_ulimit
  20. sys_old_syscall
  21. sys_setreuid
  22. sys_setuid
  23. sys_setfsuid
  24. sys_setfsgid
  25. sys_times
  26. sys_brk
  27. sys_setpgid
  28. sys_getpgid
  29. sys_getpgrp
  30. sys_getsid
  31. sys_setsid
  32. sys_getgroups
  33. sys_setgroups
  34. in_group_p
  35. sys_newuname
  36. sys_uname
  37. sys_olduname
  38. sys_sethostname
  39. sys_gethostname
  40. sys_setdomainname
  41. sys_getrlimit
  42. sys_setrlimit
  43. getrusage
  44. sys_getrusage
  45. sys_umask

   1 /*
   2  *  linux/kernel/sys.c
   3  *
   4  *  Copyright (C) 1991, 1992  Linus Torvalds
   5  */
   6 
   7 #include <linux/errno.h>
   8 #include <linux/sched.h>
   9 #include <linux/kernel.h>
  10 #include <linux/times.h>
  11 #include <linux/utsname.h>
  12 #include <linux/param.h>
  13 #include <linux/resource.h>
  14 #include <linux/signal.h>
  15 #include <linux/string.h>
  16 #include <linux/ptrace.h>
  17 #include <linux/stat.h>
  18 #include <linux/mman.h>
  19 #include <linux/mm.h>
  20 #include <linux/pagemap.h>
  21 
  22 #include <asm/segment.h>
  23 #include <asm/io.h>
  24 
  25 /*
  26  * this indicates whether you can reboot with ctrl-alt-del: the default is yes
  27  */
  28 static int C_A_D = 1;
  29 
  30 extern void adjust_clock(void);
  31 
  32 asmlinkage int sys_ni_syscall(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  33 {
  34         return -ENOSYS;
  35 }
  36 
  37 static int proc_sel(struct task_struct *p, int which, int who)
     /* [previous][next][first][last][top][bottom][index][help] */
  38 {
  39         switch (which) {
  40                 case PRIO_PROCESS:
  41                         if (!who && p == current)
  42                                 return 1;
  43                         return(p->pid == who);
  44                 case PRIO_PGRP:
  45                         if (!who)
  46                                 who = current->pgrp;
  47                         return(p->pgrp == who);
  48                 case PRIO_USER:
  49                         if (!who)
  50                                 who = current->uid;
  51                         return(p->uid == who);
  52         }
  53         return 0;
  54 }
  55 
  56 asmlinkage int sys_setpriority(int which, int who, int niceval)
     /* [previous][next][first][last][top][bottom][index][help] */
  57 {
  58         struct task_struct *p;
  59         int error = ESRCH;
  60         unsigned int priority;
  61 
  62         if (which > 2 || which < 0)
  63                 return -EINVAL;
  64 
  65         /* normalize: avoid signed division (rounding problems) */
  66         priority = niceval;
  67         if (niceval < 0)
  68                 priority = -niceval;
  69         if (priority > 20)
  70                 priority = 20;
  71         priority = (priority * DEF_PRIORITY + 10) / 20 + DEF_PRIORITY;
  72 
  73         if (niceval >= 0) {
  74                 priority = 2*DEF_PRIORITY - priority;
  75                 if (!priority)
  76                         priority = 1;
  77         }
  78 
  79         for_each_task(p) {
  80                 if (!proc_sel(p, which, who))
  81                         continue;
  82                 if (p->uid != current->euid &&
  83                         p->uid != current->uid && !suser()) {
  84                         error = EPERM;
  85                         continue;
  86                 }
  87                 if (error == ESRCH)
  88                         error = 0;
  89                 if (priority > p->priority && !suser())
  90                         error = EACCES;
  91                 else
  92                         p->priority = priority;
  93         }
  94         return -error;
  95 }
  96 
  97 /*
  98  * Ugh. To avoid negative return values, "getpriority()" will
  99  * not return the normal nice-value, but a value that has been
 100  * offset by 20 (ie it returns 0..40 instead of -20..20)
 101  */
 102 asmlinkage int sys_getpriority(int which, int who)
     /* [previous][next][first][last][top][bottom][index][help] */
 103 {
 104         struct task_struct *p;
 105         long max_prio = -ESRCH;
 106 
 107         if (which > 2 || which < 0)
 108                 return -EINVAL;
 109 
 110         for_each_task (p) {
 111                 if (!proc_sel(p, which, who))
 112                         continue;
 113                 if (p->priority > max_prio)
 114                         max_prio = p->priority;
 115         }
 116 
 117         /* scale the priority from timeslice to 0..40 */
 118         if (max_prio > 0)
 119                 max_prio = (max_prio * 20 + DEF_PRIORITY/2) / DEF_PRIORITY;
 120         return max_prio;
 121 }
 122 
 123 asmlinkage int sys_profil(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 124 {
 125         return -ENOSYS;
 126 }
 127 
 128 asmlinkage int sys_ftime(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 129 {
 130         return -ENOSYS;
 131 }
 132 
 133 asmlinkage int sys_break(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 134 {
 135         return -ENOSYS;
 136 }
 137 
 138 asmlinkage int sys_stty(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 139 {
 140         return -ENOSYS;
 141 }
 142 
 143 asmlinkage int sys_gtty(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 144 {
 145         return -ENOSYS;
 146 }
 147 
 148 asmlinkage int sys_prof(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 149 {
 150         return -ENOSYS;
 151 }
 152 
 153 extern void hard_reset_now(void);
 154 extern asmlinkage sys_kill(int, int);
 155 
 156 /*
 157  * Reboot system call: for obvious reasons only root may call it,
 158  * and even root needs to set up some magic numbers in the registers
 159  * so that some mistake won't make this reboot the whole machine.
 160  * You can also set the meaning of the ctrl-alt-del-key here.
 161  *
 162  * reboot doesn't sync: do that yourself before calling this.
 163  */
 164 asmlinkage int sys_reboot(int magic, int magic_too, int flag)
     /* [previous][next][first][last][top][bottom][index][help] */
 165 {
 166         if (!suser())
 167                 return -EPERM;
 168         if (magic != 0xfee1dead || magic_too != 672274793)
 169                 return -EINVAL;
 170         if (flag == 0x01234567)
 171                 hard_reset_now();
 172         else if (flag == 0x89ABCDEF)
 173                 C_A_D = 1;
 174         else if (!flag)
 175                 C_A_D = 0;
 176         else if (flag == 0xCDEF0123) {
 177                 printk(KERN_EMERG "System halted\n");
 178                 sys_kill(-1, SIGKILL);
 179                 do_exit(0);
 180         } else
 181                 return -EINVAL;
 182         return (0);
 183 }
 184 
 185 /*
 186  * This function gets called by ctrl-alt-del - ie the keyboard interrupt.
 187  * As it's called within an interrupt, it may NOT sync: the only choice
 188  * is whether to reboot at once, or just ignore the ctrl-alt-del.
 189  */
 190 void ctrl_alt_del(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 191 {
 192         if (C_A_D)
 193                 hard_reset_now();
 194         else
 195                 kill_proc(1, SIGINT, 1);
 196 }
 197         
 198 
 199 /*
 200  * Unprivileged users may change the real gid to the effective gid
 201  * or vice versa.  (BSD-style)
 202  *
 203  * If you set the real gid at all, or set the effective gid to a value not
 204  * equal to the real gid, then the saved gid is set to the new effective gid.
 205  *
 206  * This makes it possible for a setgid program to completely drop its
 207  * privileges, which is often a useful assertion to make when you are doing
 208  * a security audit over a program.
 209  *
 210  * The general idea is that a program which uses just setregid() will be
 211  * 100% compatible with BSD.  A program which uses just setgid() will be
 212  * 100% compatible with POSIX w/ Saved ID's. 
 213  */
 214 asmlinkage int sys_setregid(gid_t rgid, gid_t egid)
     /* [previous][next][first][last][top][bottom][index][help] */
 215 {
 216         int old_rgid = current->gid;
 217         int old_egid = current->egid;
 218 
 219         if (rgid != (gid_t) -1) {
 220                 if ((old_rgid == rgid) ||
 221                     (current->egid==rgid) ||
 222                     suser())
 223                         current->gid = rgid;
 224                 else
 225                         return(-EPERM);
 226         }
 227         if (egid != (gid_t) -1) {
 228                 if ((old_rgid == egid) ||
 229                     (current->egid == egid) ||
 230                     (current->sgid == egid) ||
 231                     suser())
 232                         current->egid = egid;
 233                 else {
 234                         current->gid = old_rgid;
 235                         return(-EPERM);
 236                 }
 237         }
 238         if (rgid != (gid_t) -1 ||
 239             (egid != (gid_t) -1 && egid != old_rgid))
 240                 current->sgid = current->egid;
 241         current->fsgid = current->egid;
 242         if (current->egid != old_egid)
 243                 current->dumpable = 0;
 244         return 0;
 245 }
 246 
 247 /*
 248  * setgid() is implemented like SysV w/ SAVED_IDS 
 249  */
 250 asmlinkage int sys_setgid(gid_t gid)
     /* [previous][next][first][last][top][bottom][index][help] */
 251 {
 252         int old_egid = current->egid;
 253 
 254         if (suser())
 255                 current->gid = current->egid = current->sgid = current->fsgid = gid;
 256         else if ((gid == current->gid) || (gid == current->sgid))
 257                 current->egid = current->fsgid = gid;
 258         else
 259                 return -EPERM;
 260         if (current->egid != old_egid)
 261                 current->dumpable = 0;
 262         return 0;
 263 }
 264 
 265 asmlinkage int sys_acct(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 266 {
 267         return -ENOSYS;
 268 }
 269 
 270 asmlinkage int sys_phys(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 271 {
 272         return -ENOSYS;
 273 }
 274 
 275 asmlinkage int sys_lock(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 276 {
 277         return -ENOSYS;
 278 }
 279 
 280 asmlinkage int sys_mpx(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 281 {
 282         return -ENOSYS;
 283 }
 284 
 285 asmlinkage int sys_ulimit(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 286 {
 287         return -ENOSYS;
 288 }
 289 
 290 asmlinkage int sys_old_syscall(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 291 {
 292         return -ENOSYS;
 293 }
 294 
 295 /*
 296  * Unprivileged users may change the real uid to the effective uid
 297  * or vice versa.  (BSD-style)
 298  *
 299  * If you set the real uid at all, or set the effective uid to a value not
 300  * equal to the real uid, then the saved uid is set to the new effective uid.
 301  *
 302  * This makes it possible for a setuid program to completely drop its
 303  * privileges, which is often a useful assertion to make when you are doing
 304  * a security audit over a program.
 305  *
 306  * The general idea is that a program which uses just setreuid() will be
 307  * 100% compatible with BSD.  A program which uses just setuid() will be
 308  * 100% compatible with POSIX w/ Saved ID's. 
 309  */
 310 asmlinkage int sys_setreuid(uid_t ruid, uid_t euid)
     /* [previous][next][first][last][top][bottom][index][help] */
 311 {
 312         int old_ruid = current->uid;
 313         int old_euid = current->euid;
 314 
 315         if (ruid != (uid_t) -1) {
 316                 if ((old_ruid == ruid) || 
 317                     (current->euid==ruid) ||
 318                     suser())
 319                         current->uid = ruid;
 320                 else
 321                         return(-EPERM);
 322         }
 323         if (euid != (uid_t) -1) {
 324                 if ((old_ruid == euid) ||
 325                     (current->euid == euid) ||
 326                     (current->suid == euid) ||
 327                     suser())
 328                         current->euid = euid;
 329                 else {
 330                         current->uid = old_ruid;
 331                         return(-EPERM);
 332                 }
 333         }
 334         if (ruid != (uid_t) -1 ||
 335             (euid != (uid_t) -1 && euid != old_ruid))
 336                 current->suid = current->euid;
 337         current->fsuid = current->euid;
 338         if (current->euid != old_euid)
 339                 current->dumpable = 0;
 340         return 0;
 341 }
 342 
 343 /*
 344  * setuid() is implemented like SysV w/ SAVED_IDS 
 345  * 
 346  * Note that SAVED_ID's is deficient in that a setuid root program
 347  * like sendmail, for example, cannot set its uid to be a normal 
 348  * user and then switch back, because if you're root, setuid() sets
 349  * the saved uid too.  If you don't like this, blame the bright people
 350  * in the POSIX committee and/or USG.  Note that the BSD-style setreuid()
 351  * will allow a root program to temporarily drop privileges and be able to
 352  * regain them by swapping the real and effective uid.  
 353  */
 354 asmlinkage int sys_setuid(uid_t uid)
     /* [previous][next][first][last][top][bottom][index][help] */
 355 {
 356         int old_euid = current->euid;
 357 
 358         if (suser())
 359                 current->uid = current->euid = current->suid = current->fsuid = uid;
 360         else if ((uid == current->uid) || (uid == current->suid))
 361                 current->fsuid = current->euid = uid;
 362         else
 363                 return -EPERM;
 364         if (current->euid != old_euid)
 365                 current->dumpable = 0;
 366         return(0);
 367 }
 368 
 369 /*
 370  * "setfsuid()" sets the fsuid - the uid used for filesystem checks. This
 371  * is used for "access()" and for the NFS daemon (letting nfsd stay at
 372  * whatever uid it wants to). It normally shadows "euid", except when
 373  * explicitly set by setfsuid() or for access..
 374  */
 375 asmlinkage int sys_setfsuid(uid_t uid)
     /* [previous][next][first][last][top][bottom][index][help] */
 376 {
 377         int old_fsuid = current->fsuid;
 378 
 379         if (uid == current->uid || uid == current->euid ||
 380             uid == current->suid || uid == current->fsuid || suser())
 381                 current->fsuid = uid;
 382         if (current->fsuid != old_fsuid)
 383                 current->dumpable = 0;
 384         return old_fsuid;
 385 }
 386 
 387 /*
 388  * Samma på svenska..
 389  */
 390 asmlinkage int sys_setfsgid(gid_t gid)
     /* [previous][next][first][last][top][bottom][index][help] */
 391 {
 392         int old_fsgid = current->fsgid;
 393 
 394         if (gid == current->gid || gid == current->egid ||
 395             gid == current->sgid || gid == current->fsgid || suser())
 396                 current->fsgid = gid;
 397         if (current->fsgid != old_fsgid)
 398                 current->dumpable = 0;
 399         return old_fsgid;
 400 }
 401 
 402 asmlinkage int sys_times(struct tms * tbuf)
     /* [previous][next][first][last][top][bottom][index][help] */
 403 {
 404         if (tbuf) {
 405                 int error = verify_area(VERIFY_WRITE,tbuf,sizeof *tbuf);
 406                 if (error)
 407                         return error;
 408                 put_user(current->utime,&tbuf->tms_utime);
 409                 put_user(current->stime,&tbuf->tms_stime);
 410                 put_user(current->cutime,&tbuf->tms_cutime);
 411                 put_user(current->cstime,&tbuf->tms_cstime);
 412         }
 413         return jiffies;
 414 }
 415 
 416 asmlinkage unsigned long sys_brk(unsigned long brk)
     /* [previous][next][first][last][top][bottom][index][help] */
 417 {
 418         int freepages;
 419         unsigned long rlim;
 420         unsigned long newbrk, oldbrk;
 421 
 422         if (brk < current->mm->end_code)
 423                 return current->mm->brk;
 424         newbrk = PAGE_ALIGN(brk);
 425         oldbrk = PAGE_ALIGN(current->mm->brk);
 426         if (oldbrk == newbrk)
 427                 return current->mm->brk = brk;
 428 
 429         /*
 430          * Always allow shrinking brk
 431          */
 432         if (brk <= current->mm->brk) {
 433                 current->mm->brk = brk;
 434                 do_munmap(newbrk, oldbrk-newbrk);
 435                 return brk;
 436         }
 437         /*
 438          * Check against rlimit and stack..
 439          */
 440         rlim = current->rlim[RLIMIT_DATA].rlim_cur;
 441         if (rlim >= RLIM_INFINITY)
 442                 rlim = ~0;
 443         if (brk - current->mm->end_code > rlim)
 444                 return current->mm->brk;
 445         /*
 446          * Check against existing mmap mappings.
 447          */
 448         if (find_vma_intersection(current, oldbrk, newbrk+PAGE_SIZE))
 449                 return current->mm->brk;
 450         /*
 451          * stupid algorithm to decide if we have enough memory: while
 452          * simple, it hopefully works in most obvious cases.. Easy to
 453          * fool it, but this should catch most mistakes.
 454          */
 455         freepages = buffermem >> PAGE_SHIFT;
 456         freepages += page_cache_size;
 457         freepages >>= 1;
 458         freepages += nr_free_pages;
 459         freepages += nr_swap_pages;
 460         freepages -= MAP_NR(high_memory) >> 4;
 461         freepages -= (newbrk-oldbrk) >> PAGE_SHIFT;
 462         if (freepages < 0)
 463                 return current->mm->brk;
 464 #if 0
 465         freepages += current->mm->rss;
 466         freepages -= oldbrk >> 12;
 467         if (freepages < 0)
 468                 return current->mm->brk;
 469 #endif
 470         /*
 471          * Ok, we have probably got enough memory - let it rip.
 472          */
 473         current->mm->brk = brk;
 474         do_mmap(NULL, oldbrk, newbrk-oldbrk,
 475                 PROT_READ|PROT_WRITE|PROT_EXEC,
 476                 MAP_FIXED|MAP_PRIVATE, 0);
 477         return brk;
 478 }
 479 
 480 /*
 481  * This needs some heavy checking ...
 482  * I just haven't the stomach for it. I also don't fully
 483  * understand sessions/pgrp etc. Let somebody who does explain it.
 484  *
 485  * OK, I think I have the protection semantics right.... this is really
 486  * only important on a multi-user system anyway, to make sure one user
 487  * can't send a signal to a process owned by another.  -TYT, 12/12/91
 488  *
 489  * Auch. Had to add the 'did_exec' flag to conform completely to POSIX.
 490  * LBT 04.03.94
 491  */
 492 asmlinkage int sys_setpgid(pid_t pid, pid_t pgid)
     /* [previous][next][first][last][top][bottom][index][help] */
 493 {
 494         struct task_struct * p;
 495 
 496         if (!pid)
 497                 pid = current->pid;
 498         if (!pgid)
 499                 pgid = pid;
 500         if (pgid < 0)
 501                 return -EINVAL;
 502         for_each_task(p) {
 503                 if (p->pid == pid)
 504                         goto found_task;
 505         }
 506         return -ESRCH;
 507 
 508 found_task:
 509         if (p->p_pptr == current || p->p_opptr == current) {
 510                 if (p->session != current->session)
 511                         return -EPERM;
 512                 if (p->did_exec)
 513                         return -EACCES;
 514         } else if (p != current)
 515                 return -ESRCH;
 516         if (p->leader)
 517                 return -EPERM;
 518         if (pgid != pid) {
 519                 struct task_struct * tmp;
 520                 for_each_task (tmp) {
 521                         if (tmp->pgrp == pgid &&
 522                          tmp->session == current->session)
 523                                 goto ok_pgid;
 524                 }
 525                 return -EPERM;
 526         }
 527 
 528 ok_pgid:
 529         p->pgrp = pgid;
 530         return 0;
 531 }
 532 
 533 asmlinkage int sys_getpgid(pid_t pid)
     /* [previous][next][first][last][top][bottom][index][help] */
 534 {
 535         struct task_struct * p;
 536 
 537         if (!pid)
 538                 return current->pgrp;
 539         for_each_task(p) {
 540                 if (p->pid == pid)
 541                         return p->pgrp;
 542         }
 543         return -ESRCH;
 544 }
 545 
 546 asmlinkage int sys_getpgrp(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 547 {
 548         return current->pgrp;
 549 }
 550 
 551 asmlinkage int sys_getsid(pid_t pid)
     /* [previous][next][first][last][top][bottom][index][help] */
 552 {
 553         struct task_struct * p;
 554 
 555         if (!pid)
 556                 return current->session;
 557         for_each_task(p) {
 558                 if (p->pid == pid)
 559                         return p->session;
 560         }
 561         return -ESRCH;
 562 }
 563 
 564 asmlinkage int sys_setsid(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 565 {
 566         if (current->leader)
 567                 return -EPERM;
 568         current->leader = 1;
 569         current->session = current->pgrp = current->pid;
 570         current->tty = NULL;
 571         current->tty_old_pgrp = 0;
 572         return current->pgrp;
 573 }
 574 
 575 /*
 576  * Supplementary group ID's
 577  */
 578 asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist)
     /* [previous][next][first][last][top][bottom][index][help] */
 579 {
 580         int i;
 581         int * groups;
 582 
 583         if (gidsetsize) {
 584                 i = verify_area(VERIFY_WRITE, grouplist, sizeof(gid_t) * gidsetsize);
 585                 if (i)
 586                         return i;
 587         }
 588         groups = current->groups;
 589         for (i = 0 ; (i < NGROUPS) && (*groups != NOGROUP) ; i++, groups++) {
 590                 if (!gidsetsize)
 591                         continue;
 592                 if (i >= gidsetsize)
 593                         break;
 594                 put_user(*groups, grouplist);
 595                 grouplist++;
 596         }
 597         return(i);
 598 }
 599 
 600 asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist)
     /* [previous][next][first][last][top][bottom][index][help] */
 601 {
 602         int     i;
 603 
 604         if (!suser())
 605                 return -EPERM;
 606         if (gidsetsize > NGROUPS)
 607                 return -EINVAL;
 608         i = verify_area(VERIFY_READ, grouplist, sizeof(gid_t) * gidsetsize);
 609         if (i)
 610                 return i;
 611         for (i = 0; i < gidsetsize; i++, grouplist++) {
 612                 current->groups[i] = get_user(grouplist);
 613         }
 614         if (i < NGROUPS)
 615                 current->groups[i] = NOGROUP;
 616         return 0;
 617 }
 618 
 619 int in_group_p(gid_t grp)
     /* [previous][next][first][last][top][bottom][index][help] */
 620 {
 621         int     i;
 622 
 623         if (grp == current->fsgid)
 624                 return 1;
 625 
 626         for (i = 0; i < NGROUPS; i++) {
 627                 if (current->groups[i] == NOGROUP)
 628                         break;
 629                 if (current->groups[i] == grp)
 630                         return 1;
 631         }
 632         return 0;
 633 }
 634 
 635 asmlinkage int sys_newuname(struct new_utsname * name)
     /* [previous][next][first][last][top][bottom][index][help] */
 636 {
 637         int error;
 638 
 639         if (!name)
 640                 return -EFAULT;
 641         error = verify_area(VERIFY_WRITE, name, sizeof *name);
 642         if (!error)
 643                 memcpy_tofs(name,&system_utsname,sizeof *name);
 644         return error;
 645 }
 646 
 647 asmlinkage int sys_uname(struct old_utsname * name)
     /* [previous][next][first][last][top][bottom][index][help] */
 648 {
 649         int error;
 650         if (!name)
 651                 return -EFAULT;
 652         error = verify_area(VERIFY_WRITE, name,sizeof *name);
 653         if (error)
 654                 return error;
 655         memcpy_tofs(&name->sysname,&system_utsname.sysname,
 656                 sizeof (system_utsname.sysname));
 657         memcpy_tofs(&name->nodename,&system_utsname.nodename,
 658                 sizeof (system_utsname.nodename));
 659         memcpy_tofs(&name->release,&system_utsname.release,
 660                 sizeof (system_utsname.release));
 661         memcpy_tofs(&name->version,&system_utsname.version,
 662                 sizeof (system_utsname.version));
 663         memcpy_tofs(&name->machine,&system_utsname.machine,
 664                 sizeof (system_utsname.machine));
 665         return 0;
 666 }
 667 
 668 asmlinkage int sys_olduname(struct oldold_utsname * name)
     /* [previous][next][first][last][top][bottom][index][help] */
 669 {
 670         int error;
 671         if (!name)
 672                 return -EFAULT;
 673         error = verify_area(VERIFY_WRITE, name,sizeof *name);
 674         if (error)
 675                 return error;
 676         memcpy_tofs(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
 677         put_user(0,name->sysname+__OLD_UTS_LEN);
 678         memcpy_tofs(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
 679         put_user(0,name->nodename+__OLD_UTS_LEN);
 680         memcpy_tofs(&name->release,&system_utsname.release,__OLD_UTS_LEN);
 681         put_user(0,name->release+__OLD_UTS_LEN);
 682         memcpy_tofs(&name->version,&system_utsname.version,__OLD_UTS_LEN);
 683         put_user(0,name->version+__OLD_UTS_LEN);
 684         memcpy_tofs(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
 685         put_user(0,name->machine+__OLD_UTS_LEN);
 686         return 0;
 687 }
 688 
 689 asmlinkage int sys_sethostname(char *name, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 690 {
 691         int error;
 692 
 693         if (!suser())
 694                 return -EPERM;
 695         if (len < 0 || len > __NEW_UTS_LEN)
 696                 return -EINVAL;
 697         error = verify_area(VERIFY_READ, name, len);
 698         if (error)
 699                 return error;
 700         memcpy_fromfs(system_utsname.nodename, name, len);
 701         system_utsname.nodename[len] = 0;
 702         return 0;
 703 }
 704 
 705 asmlinkage int sys_gethostname(char *name, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 706 {
 707         int i;
 708 
 709         if (len < 0)
 710                 return -EINVAL;
 711         i = verify_area(VERIFY_WRITE, name, len);
 712         if (i)
 713                 return i;
 714         i = 1+strlen(system_utsname.nodename);
 715         if (i > len)
 716                 i = len;
 717         memcpy_tofs(name, system_utsname.nodename, i);
 718         return 0;
 719 }
 720 
 721 /*
 722  * Only setdomainname; getdomainname can be implemented by calling
 723  * uname()
 724  */
 725 asmlinkage int sys_setdomainname(char *name, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 726 {
 727         int error;
 728         
 729         if (!suser())
 730                 return -EPERM;
 731         if (len < 0 || len > __NEW_UTS_LEN)
 732                 return -EINVAL;
 733         error = verify_area(VERIFY_READ, name, len);
 734         if (error)
 735                 return error;
 736         memcpy_fromfs(system_utsname.domainname, name, len);
 737         system_utsname.domainname[len] = 0;
 738         return 0;
 739 }
 740 
 741 asmlinkage int sys_getrlimit(unsigned int resource, struct rlimit *rlim)
     /* [previous][next][first][last][top][bottom][index][help] */
 742 {
 743         int error;
 744 
 745         if (resource >= RLIM_NLIMITS)
 746                 return -EINVAL;
 747         error = verify_area(VERIFY_WRITE,rlim,sizeof *rlim);
 748         if (error)
 749                 return error;
 750         memcpy_tofs(rlim, current->rlim + resource, sizeof(*rlim));
 751         return 0;       
 752 }
 753 
 754 asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim)
     /* [previous][next][first][last][top][bottom][index][help] */
 755 {
 756         struct rlimit new_rlim, *old_rlim;
 757         int err;
 758 
 759         if (resource >= RLIM_NLIMITS)
 760                 return -EINVAL;
 761         err = verify_area(VERIFY_READ, rlim, sizeof(*rlim));
 762         if (err)
 763                 return err;
 764         memcpy_fromfs(&new_rlim, rlim, sizeof(*rlim));
 765         old_rlim = current->rlim + resource;
 766         if (((new_rlim.rlim_cur > old_rlim->rlim_max) ||
 767              (new_rlim.rlim_max > old_rlim->rlim_max)) &&
 768             !suser())
 769                 return -EPERM;
 770         if (resource == RLIMIT_NOFILE) {
 771                 if (new_rlim.rlim_cur > NR_OPEN || new_rlim.rlim_max > NR_OPEN)
 772                         return -EPERM;
 773         }
 774         *old_rlim = new_rlim;
 775         return 0;
 776 }
 777 
 778 /*
 779  * It would make sense to put struct rusage in the task_struct,
 780  * except that would make the task_struct be *really big*.  After
 781  * task_struct gets moved into malloc'ed memory, it would
 782  * make sense to do this.  It will make moving the rest of the information
 783  * a lot simpler!  (Which we're not doing right now because we're not
 784  * measuring them yet).
 785  */
 786 int getrusage(struct task_struct *p, int who, struct rusage *ru)
     /* [previous][next][first][last][top][bottom][index][help] */
 787 {
 788         int error;
 789         struct rusage r;
 790 
 791         error = verify_area(VERIFY_WRITE, ru, sizeof *ru);
 792         if (error)
 793                 return error;
 794         memset((char *) &r, 0, sizeof(r));
 795         switch (who) {
 796                 case RUSAGE_SELF:
 797                         r.ru_utime.tv_sec = CT_TO_SECS(p->utime);
 798                         r.ru_utime.tv_usec = CT_TO_USECS(p->utime);
 799                         r.ru_stime.tv_sec = CT_TO_SECS(p->stime);
 800                         r.ru_stime.tv_usec = CT_TO_USECS(p->stime);
 801                         r.ru_minflt = p->min_flt;
 802                         r.ru_majflt = p->maj_flt;
 803                         r.ru_nswap = p->nswap;
 804                         break;
 805                 case RUSAGE_CHILDREN:
 806                         r.ru_utime.tv_sec = CT_TO_SECS(p->cutime);
 807                         r.ru_utime.tv_usec = CT_TO_USECS(p->cutime);
 808                         r.ru_stime.tv_sec = CT_TO_SECS(p->cstime);
 809                         r.ru_stime.tv_usec = CT_TO_USECS(p->cstime);
 810                         r.ru_minflt = p->cmin_flt;
 811                         r.ru_majflt = p->cmaj_flt;
 812                         r.ru_nswap = p->cnswap;
 813                         break;
 814                 default:
 815                         r.ru_utime.tv_sec = CT_TO_SECS(p->utime + p->cutime);
 816                         r.ru_utime.tv_usec = CT_TO_USECS(p->utime + p->cutime);
 817                         r.ru_stime.tv_sec = CT_TO_SECS(p->stime + p->cstime);
 818                         r.ru_stime.tv_usec = CT_TO_USECS(p->stime + p->cstime);
 819                         r.ru_minflt = p->min_flt + p->cmin_flt;
 820                         r.ru_majflt = p->maj_flt + p->cmaj_flt;
 821                         r.ru_nswap = p->nswap + p->cnswap;
 822                         break;
 823         }
 824         memcpy_tofs(ru, &r, sizeof(r));
 825         return 0;
 826 }
 827 
 828 asmlinkage int sys_getrusage(int who, struct rusage *ru)
     /* [previous][next][first][last][top][bottom][index][help] */
 829 {
 830         if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN)
 831                 return -EINVAL;
 832         return getrusage(current, who, ru);
 833 }
 834 
 835 asmlinkage int sys_umask(int mask)
     /* [previous][next][first][last][top][bottom][index][help] */
 836 {
 837         int old = current->fs->umask;
 838 
 839         current->fs->umask = mask & S_IRWXUGO;
 840         return (old);
 841 }

/* [previous][next][first][last][top][bottom][index][help] */