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