1 /*- 2 * Copyright (c) 1982, 1986, 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)kern_resource.c 7.17 (Berkeley) 05/31/92 8 */ 9 10 #include "param.h" 11 #include "resourcevar.h" 12 #include "malloc.h" 13 #include "proc.h" 14 15 #include "vm/vm.h" 16 17 /* 18 * Resource controls and accounting. 19 */ 20 21 getpriority(curp, uap, retval) 22 struct proc *curp; 23 register struct args { 24 int which; 25 int who; 26 } *uap; 27 int *retval; 28 { 29 register struct proc *p; 30 register int low = PRIO_MAX + 1; 31 32 switch (uap->which) { 33 34 case PRIO_PROCESS: 35 if (uap->who == 0) 36 p = curp; 37 else 38 p = pfind(uap->who); 39 if (p == 0) 40 break; 41 low = p->p_nice; 42 break; 43 44 case PRIO_PGRP: { 45 register struct pgrp *pg; 46 47 if (uap->who == 0) 48 pg = curp->p_pgrp; 49 else if ((pg = pgfind(uap->who)) == NULL) 50 break; 51 for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) { 52 if (p->p_nice < low) 53 low = p->p_nice; 54 } 55 break; 56 } 57 58 case PRIO_USER: 59 if (uap->who == 0) 60 uap->who = curp->p_ucred->cr_uid; 61 for (p = allproc; p != NULL; p = p->p_nxt) { 62 if (p->p_ucred->cr_uid == uap->who && 63 p->p_nice < low) 64 low = p->p_nice; 65 } 66 break; 67 68 default: 69 return (EINVAL); 70 } 71 if (low == PRIO_MAX + 1) 72 return (ESRCH); 73 *retval = low; 74 return (0); 75 } 76 77 /* ARGSUSED */ 78 setpriority(curp, uap, retval) 79 struct proc *curp; 80 register struct args { 81 int which; 82 int who; 83 int prio; 84 } *uap; 85 int *retval; 86 { 87 register struct proc *p; 88 int found = 0, error = 0; 89 90 switch (uap->which) { 91 92 case PRIO_PROCESS: 93 if (uap->who == 0) 94 p = curp; 95 else 96 p = pfind(uap->who); 97 if (p == 0) 98 break; 99 error = donice(curp, p, uap->prio); 100 found++; 101 break; 102 103 case PRIO_PGRP: { 104 register struct pgrp *pg; 105 106 if (uap->who == 0) 107 pg = curp->p_pgrp; 108 else if ((pg = pgfind(uap->who)) == NULL) 109 break; 110 for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) { 111 error = donice(curp, p, uap->prio); 112 found++; 113 } 114 break; 115 } 116 117 case PRIO_USER: 118 if (uap->who == 0) 119 uap->who = curp->p_ucred->cr_uid; 120 for (p = allproc; p != NULL; p = p->p_nxt) 121 if (p->p_ucred->cr_uid == uap->who) { 122 error = donice(curp, p, uap->prio); 123 found++; 124 } 125 break; 126 127 default: 128 return (EINVAL); 129 } 130 if (found == 0) 131 return (ESRCH); 132 return (0); 133 } 134 135 donice(curp, chgp, n) 136 register struct proc *curp, *chgp; 137 register int n; 138 { 139 register struct pcred *pcred = curp->p_cred; 140 141 if (pcred->pc_ucred->cr_uid && pcred->p_ruid && 142 pcred->pc_ucred->cr_uid != chgp->p_ucred->cr_uid && 143 pcred->p_ruid != chgp->p_ucred->cr_uid) 144 return (EPERM); 145 if (n > PRIO_MAX) 146 n = PRIO_MAX; 147 if (n < PRIO_MIN) 148 n = PRIO_MIN; 149 if (n < chgp->p_nice && suser(pcred->pc_ucred, &curp->p_acflag)) 150 return (EACCES); 151 chgp->p_nice = n; 152 (void) setpri(chgp); 153 return (0); 154 } 155 156 #ifdef COMPAT_43 157 /* ARGSUSED */ 158 setrlimit(p, uap, retval) 159 struct proc *p; 160 register struct args { 161 u_int which; 162 struct orlimit *lim; 163 } *uap; 164 int *retval; 165 { 166 struct orlimit olim; 167 struct rlimit lim; 168 int error; 169 170 if (error = 171 copyin((caddr_t)uap->lim, (caddr_t)&olim, sizeof (struct orlimit))) 172 return (error); 173 lim.rlim_cur = olim.rlim_cur; 174 lim.rlim_max = olim.rlim_max; 175 return (dosetrlimit(p, uap->which, &lim)); 176 } 177 178 /* ARGSUSED */ 179 getrlimit(p, uap, retval) 180 struct proc *p; 181 register struct args { 182 u_int which; 183 struct orlimit *rlp; 184 } *uap; 185 int *retval; 186 { 187 struct orlimit olim; 188 189 if (uap->which >= RLIM_NLIMITS) 190 return (EINVAL); 191 olim.rlim_cur = p->p_rlimit[uap->which].rlim_cur; 192 if (olim.rlim_cur == -1) 193 olim.rlim_cur = 0x7fffffff; 194 olim.rlim_max = p->p_rlimit[uap->which].rlim_max; 195 if (olim.rlim_max == -1) 196 olim.rlim_max = 0x7fffffff; 197 return (copyout((caddr_t)&olim, (caddr_t)uap->rlp, sizeof(olim))); 198 } 199 #endif /* COMPAT_43 */ 200 201 /* ARGSUSED */ 202 __setrlimit(p, uap, retval) 203 struct proc *p; 204 register struct args { 205 u_int which; 206 struct rlimit *lim; 207 } *uap; 208 int *retval; 209 { 210 struct rlimit alim; 211 int error; 212 213 if (error = 214 copyin((caddr_t)uap->lim, (caddr_t)&alim, sizeof (struct rlimit))) 215 return (error); 216 return (dosetrlimit(p, uap->which, &alim)); 217 } 218 219 dosetrlimit(p, which, limp) 220 struct proc *p; 221 u_int which; 222 struct rlimit *limp; 223 { 224 register struct rlimit *alimp; 225 extern unsigned maxdmap; 226 int error; 227 228 if (which >= RLIM_NLIMITS) 229 return (EINVAL); 230 alimp = &p->p_rlimit[which]; 231 if (limp->rlim_cur > alimp->rlim_max || 232 limp->rlim_max > alimp->rlim_max) 233 if (error = suser(p->p_ucred, &p->p_acflag)) 234 return (error); 235 if (limp->rlim_cur > limp->rlim_max) 236 limp->rlim_cur = limp->rlim_max; 237 if (p->p_limit->p_refcnt > 1 && 238 (p->p_limit->p_lflags & PL_SHAREMOD) == 0) { 239 p->p_limit->p_refcnt--; 240 p->p_limit = limcopy(p->p_limit); 241 alimp = &p->p_rlimit[which]; 242 } 243 244 switch (which) { 245 246 case RLIMIT_DATA: 247 if (limp->rlim_cur > maxdmap) 248 limp->rlim_cur = maxdmap; 249 if (limp->rlim_max > maxdmap) 250 limp->rlim_max = maxdmap; 251 break; 252 253 case RLIMIT_STACK: 254 if (limp->rlim_cur > maxdmap) 255 limp->rlim_cur = maxdmap; 256 if (limp->rlim_max > maxdmap) 257 limp->rlim_max = maxdmap; 258 /* 259 * Stack is allocated to the max at exec time with only 260 * "rlim_cur" bytes accessible. If stack limit is going 261 * up make more accessible, if going down make inaccessible. 262 */ 263 if (limp->rlim_cur != alimp->rlim_cur) { 264 vm_offset_t addr; 265 vm_size_t size; 266 vm_prot_t prot; 267 268 if (limp->rlim_cur > alimp->rlim_cur) { 269 prot = VM_PROT_ALL; 270 size = limp->rlim_cur - alimp->rlim_cur; 271 addr = USRSTACK - limp->rlim_cur; 272 } else { 273 prot = VM_PROT_NONE; 274 size = alimp->rlim_cur - limp->rlim_cur; 275 addr = USRSTACK - alimp->rlim_cur; 276 } 277 addr = trunc_page(addr); 278 size = round_page(size); 279 (void) vm_map_protect(&p->p_vmspace->vm_map, 280 addr, addr+size, prot, FALSE); 281 } 282 break; 283 } 284 *alimp = *limp; 285 return (0); 286 } 287 288 /* ARGSUSED */ 289 __getrlimit(p, uap, retval) 290 struct proc *p; 291 register struct args { 292 u_int which; 293 struct rlimit *rlp; 294 } *uap; 295 int *retval; 296 { 297 298 if (uap->which >= RLIM_NLIMITS) 299 return (EINVAL); 300 return (copyout((caddr_t)&p->p_rlimit[uap->which], (caddr_t)uap->rlp, 301 sizeof (struct rlimit))); 302 } 303 304 /* ARGSUSED */ 305 getrusage(p, uap, retval) 306 register struct proc *p; 307 register struct args { 308 int who; 309 struct rusage *rusage; 310 } *uap; 311 int *retval; 312 { 313 register struct rusage *rup; 314 315 switch (uap->who) { 316 317 case RUSAGE_SELF: { 318 int s; 319 320 rup = &p->p_stats->p_ru; 321 s = splclock(); 322 rup->ru_stime = p->p_stime; 323 rup->ru_utime = p->p_utime; 324 splx(s); 325 break; 326 } 327 328 case RUSAGE_CHILDREN: 329 rup = &p->p_stats->p_cru; 330 break; 331 332 default: 333 return (EINVAL); 334 } 335 return (copyout((caddr_t)rup, (caddr_t)uap->rusage, 336 sizeof (struct rusage))); 337 } 338 339 ruadd(ru, ru2) 340 register struct rusage *ru, *ru2; 341 { 342 register long *ip, *ip2; 343 register int i; 344 345 timevaladd(&ru->ru_utime, &ru2->ru_utime); 346 timevaladd(&ru->ru_stime, &ru2->ru_stime); 347 if (ru->ru_maxrss < ru2->ru_maxrss) 348 ru->ru_maxrss = ru2->ru_maxrss; 349 ip = &ru->ru_first; ip2 = &ru2->ru_first; 350 for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--) 351 *ip++ += *ip2++; 352 } 353 354 /* 355 * Make a copy of the plimit structure. 356 * We share these structures copy-on-write after fork, 357 * and copy when a limit is changed. 358 */ 359 struct plimit * 360 limcopy(lim) 361 struct plimit *lim; 362 { 363 register struct plimit *copy; 364 365 MALLOC(copy, struct plimit *, sizeof(struct plimit), 366 M_SUBPROC, M_WAITOK); 367 bcopy(lim->pl_rlimit, copy->pl_rlimit, 368 sizeof(struct rlimit) * RLIM_NLIMITS); 369 copy->p_lflags = 0; 370 copy->p_refcnt = 1; 371 return (copy); 372 } 373