home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / kernel / sys.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-04  |  17.7 KB  |  773 lines

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