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

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