149594Sbostic /*- 263176Sbostic * Copyright (c) 1982, 1986, 1991, 1993 363176Sbostic * The Regents of the University of California. All rights reserved. 465771Sbostic * (c) UNIX System Laboratories, Inc. 565771Sbostic * All or some portions of this file are derived from material licensed 665771Sbostic * to the University of California by American Telephone and Telegraph 765771Sbostic * Co. or Unix System Laboratories, Inc. and are reproduced herein with 865771Sbostic * the permission of UNIX System Laboratories, Inc. 923373Smckusick * 1049594Sbostic * %sccs.include.redist.c% 1149594Sbostic * 12*67732Smckusick * @(#)kern_resource.c 8.6 (Berkeley) 08/22/94 1323373Smckusick */ 147Sbill 1556517Sbostic #include <sys/param.h> 1656517Sbostic #include <sys/kernel.h> 1758775Smckusick #include <sys/file.h> 1856517Sbostic #include <sys/resourcevar.h> 1956517Sbostic #include <sys/malloc.h> 2056517Sbostic #include <sys/proc.h> 217Sbill 2256517Sbostic #include <vm/vm.h> 2349282Shibler 248176Sroot /* 258176Sroot * Resource controls and accounting. 268176Sroot */ 278176Sroot 2854935Storek struct getpriority_args { 2954935Storek int which; 3054935Storek int who; 3154935Storek }; 3243365Smckusick getpriority(curp, uap, retval) 3343365Smckusick struct proc *curp; 3454935Storek register struct getpriority_args *uap; 3543365Smckusick int *retval; 3643365Smckusick { 378031Sroot register struct proc *p; 3835810Smarc register int low = PRIO_MAX + 1; 398031Sroot 408031Sroot switch (uap->which) { 418031Sroot 428031Sroot case PRIO_PROCESS: 438031Sroot if (uap->who == 0) 4443365Smckusick p = curp; 458031Sroot else 468031Sroot p = pfind(uap->who); 478031Sroot if (p == 0) 4828149Skarels break; 4917400Skarels low = p->p_nice; 508031Sroot break; 518031Sroot 5235810Smarc case PRIO_PGRP: { 5335810Smarc register struct pgrp *pg; 5435810Smarc 558031Sroot if (uap->who == 0) 5643365Smckusick pg = curp->p_pgrp; 5735810Smarc else if ((pg = pgfind(uap->who)) == NULL) 5835810Smarc break; 59*67732Smckusick for (p = pg->pg_members.lh_first; p != 0; 60*67732Smckusick p = p->p_pglist.le_next) 6135810Smarc if (p->p_nice < low) 6217400Skarels low = p->p_nice; 638031Sroot break; 6435810Smarc } 658031Sroot 668176Sroot case PRIO_USER: 678176Sroot if (uap->who == 0) 6847541Skarels uap->who = curp->p_ucred->cr_uid; 69*67732Smckusick for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) 70*67732Smckusick if (p->p_ucred->cr_uid == uap->who && p->p_nice < low) 7117400Skarels low = p->p_nice; 728176Sroot break; 738176Sroot 748031Sroot default: 7544405Skarels return (EINVAL); 768031Sroot } 7743365Smckusick if (low == PRIO_MAX + 1) 7844405Skarels return (ESRCH); 7943365Smckusick *retval = low; 8044405Skarels return (0); 818031Sroot } 828031Sroot 8354935Storek struct setpriority_args { 8454935Storek int which; 8554935Storek int who; 8654935Storek int prio; 8754935Storek }; 8843365Smckusick /* ARGSUSED */ 8943365Smckusick setpriority(curp, uap, retval) 9043365Smckusick struct proc *curp; 9154935Storek register struct setpriority_args *uap; 9243365Smckusick int *retval; 9343365Smckusick { 948031Sroot register struct proc *p; 9543365Smckusick int found = 0, error = 0; 968031Sroot 978031Sroot switch (uap->which) { 988031Sroot 998031Sroot case PRIO_PROCESS: 1008176Sroot if (uap->who == 0) 10143365Smckusick p = curp; 1028176Sroot else 1038176Sroot p = pfind(uap->who); 1048031Sroot if (p == 0) 10528149Skarels break; 10643365Smckusick error = donice(curp, p, uap->prio); 10717400Skarels found++; 1088031Sroot break; 1098031Sroot 11035810Smarc case PRIO_PGRP: { 11135810Smarc register struct pgrp *pg; 11235810Smarc 1138176Sroot if (uap->who == 0) 11443365Smckusick pg = curp->p_pgrp; 11535810Smarc else if ((pg = pgfind(uap->who)) == NULL) 11635810Smarc break; 117*67732Smckusick for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next) { 11843365Smckusick error = donice(curp, p, uap->prio); 11935810Smarc found++; 12035810Smarc } 1218031Sroot break; 12235810Smarc } 1238031Sroot 1248176Sroot case PRIO_USER: 1258176Sroot if (uap->who == 0) 12647541Skarels uap->who = curp->p_ucred->cr_uid; 127*67732Smckusick for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) 12847541Skarels if (p->p_ucred->cr_uid == uap->who) { 12943365Smckusick error = donice(curp, p, uap->prio); 13017400Skarels found++; 13117400Skarels } 1328176Sroot break; 1338176Sroot 1348031Sroot default: 13544405Skarels return (EINVAL); 1368031Sroot } 13717400Skarels if (found == 0) 13844405Skarels return (ESRCH); 13965081Smckusick return (error); 1408031Sroot } 1418031Sroot 14243365Smckusick donice(curp, chgp, n) 14343365Smckusick register struct proc *curp, *chgp; 1448031Sroot register int n; 1458031Sroot { 14647541Skarels register struct pcred *pcred = curp->p_cred; 1478031Sroot 14847541Skarels if (pcred->pc_ucred->cr_uid && pcred->p_ruid && 14947541Skarels pcred->pc_ucred->cr_uid != chgp->p_ucred->cr_uid && 15047541Skarels pcred->p_ruid != chgp->p_ucred->cr_uid) 15143365Smckusick return (EPERM); 15217400Skarels if (n > PRIO_MAX) 15317400Skarels n = PRIO_MAX; 15417400Skarels if (n < PRIO_MIN) 15517400Skarels n = PRIO_MIN; 15647541Skarels if (n < chgp->p_nice && suser(pcred->pc_ucred, &curp->p_acflag)) 15743365Smckusick return (EACCES); 15843365Smckusick chgp->p_nice = n; 15964407Sbostic (void)resetpriority(chgp); 16043365Smckusick return (0); 1618031Sroot } 1628031Sroot 16354345Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 16454935Storek struct setrlimit_args { 16554935Storek u_int which; 16654935Storek struct orlimit *lim; 16754935Storek }; 16843365Smckusick /* ARGSUSED */ 16960105Smckusick osetrlimit(p, uap, retval) 17043365Smckusick struct proc *p; 17154935Storek register struct setrlimit_args *uap; 17253761Smckusick int *retval; 17353761Smckusick { 17453761Smckusick struct orlimit olim; 17553761Smckusick struct rlimit lim; 17653761Smckusick int error; 17753761Smckusick 17853761Smckusick if (error = 17953761Smckusick copyin((caddr_t)uap->lim, (caddr_t)&olim, sizeof (struct orlimit))) 18053761Smckusick return (error); 18153761Smckusick lim.rlim_cur = olim.rlim_cur; 18253761Smckusick lim.rlim_max = olim.rlim_max; 18353761Smckusick return (dosetrlimit(p, uap->which, &lim)); 18453761Smckusick } 18553761Smckusick 18654935Storek struct getrlimit_args { 18754935Storek u_int which; 18854935Storek struct orlimit *rlp; 18954935Storek }; 19053761Smckusick /* ARGSUSED */ 19160105Smckusick ogetrlimit(p, uap, retval) 19253761Smckusick struct proc *p; 19354935Storek register struct getrlimit_args *uap; 19453761Smckusick int *retval; 19553761Smckusick { 19653761Smckusick struct orlimit olim; 19753761Smckusick 19853761Smckusick if (uap->which >= RLIM_NLIMITS) 19953761Smckusick return (EINVAL); 20053761Smckusick olim.rlim_cur = p->p_rlimit[uap->which].rlim_cur; 20153761Smckusick if (olim.rlim_cur == -1) 20253761Smckusick olim.rlim_cur = 0x7fffffff; 20353761Smckusick olim.rlim_max = p->p_rlimit[uap->which].rlim_max; 20453761Smckusick if (olim.rlim_max == -1) 20553761Smckusick olim.rlim_max = 0x7fffffff; 20653761Smckusick return (copyout((caddr_t)&olim, (caddr_t)uap->rlp, sizeof(olim))); 20753761Smckusick } 20854345Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 20953761Smckusick 21054935Storek struct __setrlimit_args { 21154935Storek u_int which; 21254935Storek struct rlimit *lim; 21354935Storek }; 21453761Smckusick /* ARGSUSED */ 21560411Smckusick setrlimit(p, uap, retval) 21653761Smckusick struct proc *p; 21754935Storek register struct __setrlimit_args *uap; 21843365Smckusick int *retval; 21943365Smckusick { 2208031Sroot struct rlimit alim; 22153761Smckusick int error; 22253761Smckusick 22353761Smckusick if (error = 22453761Smckusick copyin((caddr_t)uap->lim, (caddr_t)&alim, sizeof (struct rlimit))) 22553761Smckusick return (error); 22653761Smckusick return (dosetrlimit(p, uap->which, &alim)); 22753761Smckusick } 22853761Smckusick 22953761Smckusick dosetrlimit(p, which, limp) 23053761Smckusick struct proc *p; 23153761Smckusick u_int which; 23253761Smckusick struct rlimit *limp; 23353761Smckusick { 2348031Sroot register struct rlimit *alimp; 23525257Skarels extern unsigned maxdmap; 23643365Smckusick int error; 2378031Sroot 23853761Smckusick if (which >= RLIM_NLIMITS) 23944405Skarels return (EINVAL); 24053761Smckusick alimp = &p->p_rlimit[which]; 24153761Smckusick if (limp->rlim_cur > alimp->rlim_max || 24253761Smckusick limp->rlim_max > alimp->rlim_max) 24347541Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 24444405Skarels return (error); 24553761Smckusick if (limp->rlim_cur > limp->rlim_max) 24653761Smckusick limp->rlim_cur = limp->rlim_max; 24747541Skarels if (p->p_limit->p_refcnt > 1 && 24847541Skarels (p->p_limit->p_lflags & PL_SHAREMOD) == 0) { 24947541Skarels p->p_limit->p_refcnt--; 25047541Skarels p->p_limit = limcopy(p->p_limit); 25153761Smckusick alimp = &p->p_rlimit[which]; 25247541Skarels } 25347541Skarels 25453761Smckusick switch (which) { 2558031Sroot 2568031Sroot case RLIMIT_DATA: 25753761Smckusick if (limp->rlim_cur > maxdmap) 25853761Smckusick limp->rlim_cur = maxdmap; 25953761Smckusick if (limp->rlim_max > maxdmap) 26053761Smckusick limp->rlim_max = maxdmap; 2618031Sroot break; 2628031Sroot 2638031Sroot case RLIMIT_STACK: 26453761Smckusick if (limp->rlim_cur > maxdmap) 26553761Smckusick limp->rlim_cur = maxdmap; 26653761Smckusick if (limp->rlim_max > maxdmap) 26753761Smckusick limp->rlim_max = maxdmap; 26849282Shibler /* 26949282Shibler * Stack is allocated to the max at exec time with only 27049282Shibler * "rlim_cur" bytes accessible. If stack limit is going 27149282Shibler * up make more accessible, if going down make inaccessible. 27249282Shibler */ 27353761Smckusick if (limp->rlim_cur != alimp->rlim_cur) { 27449282Shibler vm_offset_t addr; 27549282Shibler vm_size_t size; 27649282Shibler vm_prot_t prot; 27749282Shibler 27853761Smckusick if (limp->rlim_cur > alimp->rlim_cur) { 27949282Shibler prot = VM_PROT_ALL; 28053761Smckusick size = limp->rlim_cur - alimp->rlim_cur; 28153761Smckusick addr = USRSTACK - limp->rlim_cur; 28249282Shibler } else { 28349282Shibler prot = VM_PROT_NONE; 28453761Smckusick size = alimp->rlim_cur - limp->rlim_cur; 28549282Shibler addr = USRSTACK - alimp->rlim_cur; 28649282Shibler } 28749282Shibler addr = trunc_page(addr); 28849282Shibler size = round_page(size); 28949282Shibler (void) vm_map_protect(&p->p_vmspace->vm_map, 29049282Shibler addr, addr+size, prot, FALSE); 29149282Shibler } 2928031Sroot break; 29358775Smckusick 29458775Smckusick case RLIMIT_NOFILE: 29558775Smckusick if (limp->rlim_cur > maxfiles) 29658775Smckusick limp->rlim_cur = maxfiles; 29758775Smckusick if (limp->rlim_max > maxfiles) 29858775Smckusick limp->rlim_max = maxfiles; 29958775Smckusick break; 30059614Smckusick 30159614Smckusick case RLIMIT_NPROC: 30259614Smckusick if (limp->rlim_cur > maxproc) 30359614Smckusick limp->rlim_cur = maxproc; 30459614Smckusick if (limp->rlim_max > maxproc) 30559614Smckusick limp->rlim_max = maxproc; 30659614Smckusick break; 3078031Sroot } 30853761Smckusick *alimp = *limp; 30944405Skarels return (0); 3108031Sroot } 3118031Sroot 31254935Storek struct __getrlimit_args { 31354935Storek u_int which; 31454935Storek struct rlimit *rlp; 31554935Storek }; 31643365Smckusick /* ARGSUSED */ 31760411Smckusick getrlimit(p, uap, retval) 31843365Smckusick struct proc *p; 31954935Storek register struct __getrlimit_args *uap; 32043365Smckusick int *retval; 32143365Smckusick { 3228031Sroot 32343365Smckusick if (uap->which >= RLIM_NLIMITS) 32444405Skarels return (EINVAL); 32547541Skarels return (copyout((caddr_t)&p->p_rlimit[uap->which], (caddr_t)uap->rlp, 32643365Smckusick sizeof (struct rlimit))); 3278031Sroot } 3288031Sroot 32954783Storek /* 33054783Storek * Transform the running time and tick information in proc p into user, 33154783Storek * system, and interrupt time usage. 33254783Storek */ 33354783Storek calcru(p, up, sp, ip) 33454783Storek register struct proc *p; 33554783Storek register struct timeval *up; 33654783Storek register struct timeval *sp; 33754783Storek register struct timeval *ip; 33854783Storek { 33954815Storek register u_quad_t u, st, ut, it, tot; 34054815Storek register u_long sec, usec; 34154815Storek register int s; 34254815Storek struct timeval tv; 34354783Storek 34454783Storek s = splstatclock(); 34554783Storek st = p->p_sticks; 34654783Storek ut = p->p_uticks; 34754783Storek it = p->p_iticks; 34854783Storek splx(s); 34954783Storek 35054783Storek tot = st + ut + it; 35154783Storek if (tot == 0) { 35254783Storek up->tv_sec = up->tv_usec = 0; 35354783Storek sp->tv_sec = sp->tv_usec = 0; 35454783Storek if (ip != NULL) 35554783Storek ip->tv_sec = ip->tv_usec = 0; 35654783Storek return; 35754783Storek } 35854815Storek 35954815Storek sec = p->p_rtime.tv_sec; 36054815Storek usec = p->p_rtime.tv_usec; 36154815Storek if (p == curproc) { 36254815Storek /* 36354815Storek * Adjust for the current time slice. This is actually fairly 36454815Storek * important since the error here is on the order of a time 36554815Storek * quantum, which is much greater than the sampling error. 36654815Storek */ 36754815Storek microtime(&tv); 36854815Storek sec += tv.tv_sec - runtime.tv_sec; 36954815Storek usec += tv.tv_usec - runtime.tv_usec; 37054815Storek } 37154815Storek u = sec * 1000000 + usec; 37254815Storek st = (u * st) / tot; 37354783Storek sp->tv_sec = st / 1000000; 37454783Storek sp->tv_usec = st % 1000000; 37554815Storek ut = (u * ut) / tot; 37654783Storek up->tv_sec = ut / 1000000; 37754783Storek up->tv_usec = ut % 1000000; 37854783Storek if (ip != NULL) { 37954815Storek it = (u * it) / tot; 38054783Storek ip->tv_sec = it / 1000000; 38154783Storek ip->tv_usec = it % 1000000; 38254783Storek } 38354783Storek } 38454783Storek 38554935Storek struct getrusage_args { 38654935Storek int who; 38754935Storek struct rusage *rusage; 38854935Storek }; 38943365Smckusick /* ARGSUSED */ 39043365Smckusick getrusage(p, uap, retval) 39143365Smckusick register struct proc *p; 39254935Storek register struct getrusage_args *uap; 39343365Smckusick int *retval; 39443365Smckusick { 3958031Sroot register struct rusage *rup; 3968031Sroot 3978031Sroot switch (uap->who) { 3988031Sroot 39954815Storek case RUSAGE_SELF: 40047541Skarels rup = &p->p_stats->p_ru; 40154815Storek calcru(p, &rup->ru_utime, &rup->ru_stime, NULL); 4028031Sroot break; 4038031Sroot 4048031Sroot case RUSAGE_CHILDREN: 40547541Skarels rup = &p->p_stats->p_cru; 4068031Sroot break; 4078031Sroot 4088031Sroot default: 40944405Skarels return (EINVAL); 4108031Sroot } 41144405Skarels return (copyout((caddr_t)rup, (caddr_t)uap->rusage, 41243365Smckusick sizeof (struct rusage))); 4138031Sroot } 4148031Sroot 4158031Sroot ruadd(ru, ru2) 4168031Sroot register struct rusage *ru, *ru2; 4178031Sroot { 4188666Sroot register long *ip, *ip2; 4198031Sroot register int i; 4208031Sroot 4218031Sroot timevaladd(&ru->ru_utime, &ru2->ru_utime); 4228031Sroot timevaladd(&ru->ru_stime, &ru2->ru_stime); 4238031Sroot if (ru->ru_maxrss < ru2->ru_maxrss) 4248031Sroot ru->ru_maxrss = ru2->ru_maxrss; 4258031Sroot ip = &ru->ru_first; ip2 = &ru2->ru_first; 42653644Sbostic for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--) 4278031Sroot *ip++ += *ip2++; 4288031Sroot } 42947541Skarels 43047541Skarels /* 43147541Skarels * Make a copy of the plimit structure. 43247541Skarels * We share these structures copy-on-write after fork, 43347541Skarels * and copy when a limit is changed. 43447541Skarels */ 43547541Skarels struct plimit * 43647541Skarels limcopy(lim) 43747541Skarels struct plimit *lim; 43847541Skarels { 43947541Skarels register struct plimit *copy; 44047541Skarels 44147541Skarels MALLOC(copy, struct plimit *, sizeof(struct plimit), 44247541Skarels M_SUBPROC, M_WAITOK); 44347541Skarels bcopy(lim->pl_rlimit, copy->pl_rlimit, 44447541Skarels sizeof(struct rlimit) * RLIM_NLIMITS); 44547541Skarels copy->p_lflags = 0; 44647541Skarels copy->p_refcnt = 1; 44747541Skarels return (copy); 44847541Skarels } 449