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