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

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