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

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