123373Smckusick /* 229093Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 323373Smckusick * All rights reserved. The Berkeley software License Agreement 423373Smckusick * specifies the terms and conditions for redistribution. 523373Smckusick * 6*48419Skarels * @(#)kern_resource.c 7.11 (Berkeley) 04/20/91 723373Smckusick */ 87Sbill 917092Sbloom #include "param.h" 1047541Skarels #include "resourcevar.h" 1147541Skarels #include "malloc.h" 1217092Sbloom #include "proc.h" 137Sbill 148176Sroot /* 158176Sroot * Resource controls and accounting. 168176Sroot */ 178176Sroot 1843365Smckusick getpriority(curp, uap, retval) 1943365Smckusick struct proc *curp; 2043365Smckusick register struct args { 218031Sroot int which; 228031Sroot int who; 2343365Smckusick } *uap; 2443365Smckusick int *retval; 2543365Smckusick { 268031Sroot register struct proc *p; 2735810Smarc register int low = PRIO_MAX + 1; 288031Sroot 298031Sroot switch (uap->which) { 308031Sroot 318031Sroot case PRIO_PROCESS: 328031Sroot if (uap->who == 0) 3343365Smckusick p = curp; 348031Sroot else 358031Sroot p = pfind(uap->who); 368031Sroot if (p == 0) 3728149Skarels break; 3817400Skarels low = p->p_nice; 398031Sroot break; 408031Sroot 4135810Smarc case PRIO_PGRP: { 4235810Smarc register struct pgrp *pg; 4335810Smarc 448031Sroot if (uap->who == 0) 4543365Smckusick pg = curp->p_pgrp; 4635810Smarc else if ((pg = pgfind(uap->who)) == NULL) 4735810Smarc break; 4835810Smarc for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) { 4935810Smarc if (p->p_nice < low) 5017400Skarels low = p->p_nice; 518176Sroot } 528031Sroot break; 5335810Smarc } 548031Sroot 558176Sroot case PRIO_USER: 568176Sroot if (uap->who == 0) 5747541Skarels uap->who = curp->p_ucred->cr_uid; 5816530Skarels for (p = allproc; p != NULL; p = p->p_nxt) { 5947541Skarels if (p->p_ucred->cr_uid == uap->who && 6017400Skarels p->p_nice < low) 6117400Skarels low = p->p_nice; 628176Sroot } 638176Sroot break; 648176Sroot 658031Sroot default: 6644405Skarels return (EINVAL); 678031Sroot } 6843365Smckusick if (low == PRIO_MAX + 1) 6944405Skarels return (ESRCH); 7043365Smckusick *retval = low; 7144405Skarels return (0); 728031Sroot } 738031Sroot 7443365Smckusick /* ARGSUSED */ 7543365Smckusick setpriority(curp, uap, retval) 7643365Smckusick struct proc *curp; 7743365Smckusick register struct args { 788031Sroot int which; 798031Sroot int who; 808031Sroot int prio; 8143365Smckusick } *uap; 8243365Smckusick int *retval; 8343365Smckusick { 848031Sroot register struct proc *p; 8543365Smckusick int found = 0, error = 0; 868031Sroot 878031Sroot switch (uap->which) { 888031Sroot 898031Sroot case PRIO_PROCESS: 908176Sroot if (uap->who == 0) 9143365Smckusick p = curp; 928176Sroot else 938176Sroot p = pfind(uap->who); 948031Sroot if (p == 0) 9528149Skarels break; 9643365Smckusick error = donice(curp, p, uap->prio); 9717400Skarels found++; 988031Sroot break; 998031Sroot 10035810Smarc case PRIO_PGRP: { 10135810Smarc register struct pgrp *pg; 10235810Smarc 1038176Sroot if (uap->who == 0) 10443365Smckusick pg = curp->p_pgrp; 10535810Smarc else if ((pg = pgfind(uap->who)) == NULL) 10635810Smarc break; 10735810Smarc for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) { 10843365Smckusick error = donice(curp, p, uap->prio); 10935810Smarc found++; 11035810Smarc } 1118031Sroot break; 11235810Smarc } 1138031Sroot 1148176Sroot case PRIO_USER: 1158176Sroot if (uap->who == 0) 11647541Skarels uap->who = curp->p_ucred->cr_uid; 11716530Skarels for (p = allproc; p != NULL; p = p->p_nxt) 11847541Skarels if (p->p_ucred->cr_uid == uap->who) { 11943365Smckusick error = donice(curp, p, uap->prio); 12017400Skarels found++; 12117400Skarels } 1228176Sroot break; 1238176Sroot 1248031Sroot default: 12544405Skarels return (EINVAL); 1268031Sroot } 12717400Skarels if (found == 0) 12844405Skarels return (ESRCH); 12944405Skarels return (0); 1308031Sroot } 1318031Sroot 13243365Smckusick donice(curp, chgp, n) 13343365Smckusick register struct proc *curp, *chgp; 1348031Sroot register int n; 1358031Sroot { 13647541Skarels register struct pcred *pcred = curp->p_cred; 1378031Sroot 13847541Skarels if (pcred->pc_ucred->cr_uid && pcred->p_ruid && 13947541Skarels pcred->pc_ucred->cr_uid != chgp->p_ucred->cr_uid && 14047541Skarels pcred->p_ruid != chgp->p_ucred->cr_uid) 14143365Smckusick return (EPERM); 14217400Skarels if (n > PRIO_MAX) 14317400Skarels n = PRIO_MAX; 14417400Skarels if (n < PRIO_MIN) 14517400Skarels n = PRIO_MIN; 14647541Skarels if (n < chgp->p_nice && suser(pcred->pc_ucred, &curp->p_acflag)) 14743365Smckusick return (EACCES); 14843365Smckusick chgp->p_nice = n; 14943365Smckusick (void) setpri(chgp); 15043365Smckusick return (0); 1518031Sroot } 1528031Sroot 15343365Smckusick /* ARGSUSED */ 15443365Smckusick setrlimit(p, uap, retval) 15543365Smckusick struct proc *p; 15643365Smckusick register struct args { 1578031Sroot u_int which; 1588031Sroot struct rlimit *lim; 15943365Smckusick } *uap; 16043365Smckusick int *retval; 16143365Smckusick { 1628031Sroot struct rlimit alim; 1638031Sroot register struct rlimit *alimp; 16425257Skarels extern unsigned maxdmap; 16543365Smckusick int error; 1668031Sroot 16743365Smckusick if (uap->which >= RLIM_NLIMITS) 16844405Skarels return (EINVAL); 16947541Skarels alimp = &p->p_rlimit[uap->which]; 17043365Smckusick if (error = 17143365Smckusick copyin((caddr_t)uap->lim, (caddr_t)&alim, sizeof (struct rlimit))) 17244405Skarels return (error); 1738031Sroot if (alim.rlim_cur > alimp->rlim_max || alim.rlim_max > alimp->rlim_max) 17447541Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 17544405Skarels return (error); 17647541Skarels if (p->p_limit->p_refcnt > 1 && 17747541Skarels (p->p_limit->p_lflags & PL_SHAREMOD) == 0) { 17847541Skarels p->p_limit->p_refcnt--; 17947541Skarels p->p_limit = limcopy(p->p_limit); 18047541Skarels } 18147541Skarels 1828031Sroot switch (uap->which) { 1838031Sroot 1848031Sroot case RLIMIT_DATA: 18518279Smckusick if (alim.rlim_cur > maxdmap) 18618279Smckusick alim.rlim_cur = maxdmap; 18718279Smckusick if (alim.rlim_max > maxdmap) 18818279Smckusick alim.rlim_max = maxdmap; 1898031Sroot break; 1908031Sroot 1918031Sroot case RLIMIT_STACK: 19218279Smckusick if (alim.rlim_cur > maxdmap) 19318279Smckusick alim.rlim_cur = maxdmap; 19418279Smckusick if (alim.rlim_max > maxdmap) 19518279Smckusick alim.rlim_max = maxdmap; 1968031Sroot break; 1978031Sroot } 198*48419Skarels p->p_rlimit[uap->which] = alim; 19944405Skarels return (0); 2008031Sroot } 2018031Sroot 20243365Smckusick /* ARGSUSED */ 20343365Smckusick getrlimit(p, uap, retval) 20443365Smckusick struct proc *p; 20543365Smckusick register struct args { 2068031Sroot u_int which; 2078031Sroot struct rlimit *rlp; 20843365Smckusick } *uap; 20943365Smckusick int *retval; 21043365Smckusick { 2118031Sroot 21243365Smckusick if (uap->which >= RLIM_NLIMITS) 21344405Skarels return (EINVAL); 21447541Skarels return (copyout((caddr_t)&p->p_rlimit[uap->which], (caddr_t)uap->rlp, 21543365Smckusick sizeof (struct rlimit))); 2168031Sroot } 2178031Sroot 21843365Smckusick /* ARGSUSED */ 21943365Smckusick getrusage(p, uap, retval) 22043365Smckusick register struct proc *p; 22143365Smckusick register struct args { 2228031Sroot int who; 2238031Sroot struct rusage *rusage; 22443365Smckusick } *uap; 22543365Smckusick int *retval; 22643365Smckusick { 2278031Sroot register struct rusage *rup; 2288031Sroot 2298031Sroot switch (uap->who) { 2308031Sroot 23140705Skarels case RUSAGE_SELF: { 23240705Skarels int s; 23340705Skarels 23447541Skarels rup = &p->p_stats->p_ru; 23540705Skarels s = splclock(); 23640705Skarels rup->ru_stime = p->p_stime; 23740705Skarels rup->ru_utime = p->p_utime; 23840705Skarels splx(s); 2398031Sroot break; 24040705Skarels } 2418031Sroot 2428031Sroot case RUSAGE_CHILDREN: 24347541Skarels rup = &p->p_stats->p_cru; 2448031Sroot break; 2458031Sroot 2468031Sroot default: 24744405Skarels return (EINVAL); 2488031Sroot } 24944405Skarels return (copyout((caddr_t)rup, (caddr_t)uap->rusage, 25043365Smckusick sizeof (struct rusage))); 2518031Sroot } 2528031Sroot 2538031Sroot ruadd(ru, ru2) 2548031Sroot register struct rusage *ru, *ru2; 2558031Sroot { 2568666Sroot register long *ip, *ip2; 2578031Sroot register int i; 2588031Sroot 2598031Sroot timevaladd(&ru->ru_utime, &ru2->ru_utime); 2608031Sroot timevaladd(&ru->ru_stime, &ru2->ru_stime); 2618031Sroot if (ru->ru_maxrss < ru2->ru_maxrss) 2628031Sroot ru->ru_maxrss = ru2->ru_maxrss; 2638031Sroot ip = &ru->ru_first; ip2 = &ru2->ru_first; 2648031Sroot for (i = &ru->ru_last - &ru->ru_first; i > 0; i--) 2658031Sroot *ip++ += *ip2++; 2668031Sroot } 26747541Skarels 26847541Skarels /* 26947541Skarels * Make a copy of the plimit structure. 27047541Skarels * We share these structures copy-on-write after fork, 27147541Skarels * and copy when a limit is changed. 27247541Skarels */ 27347541Skarels struct plimit * 27447541Skarels limcopy(lim) 27547541Skarels struct plimit *lim; 27647541Skarels { 27747541Skarels register struct plimit *copy; 27847541Skarels 27947541Skarels MALLOC(copy, struct plimit *, sizeof(struct plimit), 28047541Skarels M_SUBPROC, M_WAITOK); 28147541Skarels bcopy(lim->pl_rlimit, copy->pl_rlimit, 28247541Skarels sizeof(struct rlimit) * RLIM_NLIMITS); 28347541Skarels copy->p_lflags = 0; 28447541Skarels copy->p_refcnt = 1; 28547541Skarels return (copy); 28647541Skarels } 287