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