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 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * @(#)kern_resource.c 8.5 (Berkeley) 1/21/94 39 */ 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/kernel.h> 44 #include <sys/file.h> 45 #include <sys/resourcevar.h> 46 #include <sys/malloc.h> 47 #include <sys/proc.h> 48 49 #include <vm/vm.h> 50 51 /* 52 * Resource controls and accounting. 53 */ 54 55 struct getpriority_args { 56 int which; 57 int who; 58 }; 59 int 60 getpriority(curp, uap, retval) 61 struct proc *curp; 62 register struct getpriority_args *uap; 63 int *retval; 64 { 65 register struct proc *p; 66 register int low = PRIO_MAX + 1; 67 68 switch (uap->which) { 69 70 case PRIO_PROCESS: 71 if (uap->who == 0) 72 p = curp; 73 else 74 p = pfind(uap->who); 75 if (p == 0) 76 break; 77 low = p->p_nice; 78 break; 79 80 case PRIO_PGRP: { 81 register struct pgrp *pg; 82 83 if (uap->who == 0) 84 pg = curp->p_pgrp; 85 else if ((pg = pgfind(uap->who)) == NULL) 86 break; 87 for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) { 88 if (p->p_nice < low) 89 low = p->p_nice; 90 } 91 break; 92 } 93 94 case PRIO_USER: 95 if (uap->who == 0) 96 uap->who = curp->p_ucred->cr_uid; 97 for (p = (struct proc *)allproc; p != NULL; p = p->p_next) { 98 if (p->p_ucred->cr_uid == uap->who && 99 p->p_nice < low) 100 low = p->p_nice; 101 } 102 break; 103 104 default: 105 return (EINVAL); 106 } 107 if (low == PRIO_MAX + 1) 108 return (ESRCH); 109 *retval = low; 110 return (0); 111 } 112 113 struct setpriority_args { 114 int which; 115 int who; 116 int prio; 117 }; 118 /* ARGSUSED */ 119 int 120 setpriority(curp, uap, retval) 121 struct proc *curp; 122 register struct setpriority_args *uap; 123 int *retval; 124 { 125 register struct proc *p; 126 int found = 0, error = 0; 127 128 switch (uap->which) { 129 130 case PRIO_PROCESS: 131 if (uap->who == 0) 132 p = curp; 133 else 134 p = pfind(uap->who); 135 if (p == 0) 136 break; 137 error = donice(curp, p, uap->prio); 138 found++; 139 break; 140 141 case PRIO_PGRP: { 142 register struct pgrp *pg; 143 144 if (uap->who == 0) 145 pg = curp->p_pgrp; 146 else if ((pg = pgfind(uap->who)) == NULL) 147 break; 148 for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) { 149 error = donice(curp, p, uap->prio); 150 found++; 151 } 152 break; 153 } 154 155 case PRIO_USER: 156 if (uap->who == 0) 157 uap->who = curp->p_ucred->cr_uid; 158 for (p = (struct proc *)allproc; p != NULL; p = p->p_next) 159 if (p->p_ucred->cr_uid == uap->who) { 160 error = donice(curp, p, uap->prio); 161 found++; 162 } 163 break; 164 165 default: 166 return (EINVAL); 167 } 168 if (found == 0) 169 return (ESRCH); 170 return (error); 171 } 172 173 int 174 donice(curp, chgp, n) 175 register struct proc *curp, *chgp; 176 register int n; 177 { 178 register struct pcred *pcred = curp->p_cred; 179 180 if (pcred->pc_ucred->cr_uid && pcred->p_ruid && 181 pcred->pc_ucred->cr_uid != chgp->p_ucred->cr_uid && 182 pcred->p_ruid != chgp->p_ucred->cr_uid) 183 return (EPERM); 184 if (n > PRIO_MAX) 185 n = PRIO_MAX; 186 if (n < PRIO_MIN) 187 n = PRIO_MIN; 188 if (n < chgp->p_nice && suser(pcred->pc_ucred, &curp->p_acflag)) 189 return (EACCES); 190 chgp->p_nice = n; 191 (void)resetpriority(chgp); 192 return (0); 193 } 194 195 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 196 struct setrlimit_args { 197 u_int which; 198 struct orlimit *lim; 199 }; 200 /* ARGSUSED */ 201 int 202 osetrlimit(p, uap, retval) 203 struct proc *p; 204 register struct setrlimit_args *uap; 205 int *retval; 206 { 207 struct orlimit olim; 208 struct rlimit lim; 209 int error; 210 211 if (error = 212 copyin((caddr_t)uap->lim, (caddr_t)&olim, sizeof (struct orlimit))) 213 return (error); 214 lim.rlim_cur = olim.rlim_cur; 215 lim.rlim_max = olim.rlim_max; 216 return (dosetrlimit(p, uap->which, &lim)); 217 } 218 219 struct getrlimit_args { 220 u_int which; 221 struct orlimit *rlp; 222 }; 223 /* ARGSUSED */ 224 int 225 ogetrlimit(p, uap, retval) 226 struct proc *p; 227 register struct getrlimit_args *uap; 228 int *retval; 229 { 230 struct orlimit olim; 231 232 if (uap->which >= RLIM_NLIMITS) 233 return (EINVAL); 234 olim.rlim_cur = p->p_rlimit[uap->which].rlim_cur; 235 if (olim.rlim_cur == -1) 236 olim.rlim_cur = 0x7fffffff; 237 olim.rlim_max = p->p_rlimit[uap->which].rlim_max; 238 if (olim.rlim_max == -1) 239 olim.rlim_max = 0x7fffffff; 240 return (copyout((caddr_t)&olim, (caddr_t)uap->rlp, sizeof(olim))); 241 } 242 #endif /* COMPAT_43 || COMPAT_SUNOS */ 243 244 struct __setrlimit_args { 245 u_int which; 246 struct rlimit *lim; 247 }; 248 /* ARGSUSED */ 249 int 250 setrlimit(p, uap, retval) 251 struct proc *p; 252 register struct __setrlimit_args *uap; 253 int *retval; 254 { 255 struct rlimit alim; 256 int error; 257 258 if (error = 259 copyin((caddr_t)uap->lim, (caddr_t)&alim, sizeof (struct rlimit))) 260 return (error); 261 return (dosetrlimit(p, uap->which, &alim)); 262 } 263 264 int 265 dosetrlimit(p, which, limp) 266 struct proc *p; 267 u_int which; 268 struct rlimit *limp; 269 { 270 register struct rlimit *alimp; 271 int error; 272 273 if (which >= RLIM_NLIMITS) 274 return (EINVAL); 275 alimp = &p->p_rlimit[which]; 276 if (limp->rlim_cur > alimp->rlim_max || 277 limp->rlim_max > alimp->rlim_max) 278 if (error = suser(p->p_ucred, &p->p_acflag)) 279 return (error); 280 if (limp->rlim_cur > limp->rlim_max) 281 limp->rlim_cur = limp->rlim_max; 282 if (p->p_limit->p_refcnt > 1 && 283 (p->p_limit->p_lflags & PL_SHAREMOD) == 0) { 284 p->p_limit->p_refcnt--; 285 p->p_limit = limcopy(p->p_limit); 286 alimp = &p->p_rlimit[which]; 287 } 288 289 switch (which) { 290 291 case RLIMIT_DATA: 292 if (limp->rlim_cur > MAXDSIZ) 293 limp->rlim_cur = MAXDSIZ; 294 if (limp->rlim_max > MAXDSIZ) 295 limp->rlim_max = MAXDSIZ; 296 break; 297 298 case RLIMIT_STACK: 299 if (limp->rlim_cur > MAXSSIZ) 300 limp->rlim_cur = MAXSSIZ; 301 if (limp->rlim_max > MAXSSIZ) 302 limp->rlim_max = MAXSSIZ; 303 /* 304 * Stack is allocated to the max at exec time with only 305 * "rlim_cur" bytes accessible. If stack limit is going 306 * up make more accessible, if going down make inaccessible. 307 */ 308 if (limp->rlim_cur != alimp->rlim_cur) { 309 vm_offset_t addr; 310 vm_size_t size; 311 vm_prot_t prot; 312 313 if (limp->rlim_cur > alimp->rlim_cur) { 314 prot = VM_PROT_ALL; 315 size = limp->rlim_cur - alimp->rlim_cur; 316 addr = USRSTACK - limp->rlim_cur; 317 } else { 318 prot = VM_PROT_NONE; 319 size = alimp->rlim_cur - limp->rlim_cur; 320 addr = USRSTACK - alimp->rlim_cur; 321 } 322 addr = trunc_page(addr); 323 size = round_page(size); 324 (void) vm_map_protect(&p->p_vmspace->vm_map, 325 addr, addr+size, prot, FALSE); 326 } 327 break; 328 329 case RLIMIT_NOFILE: 330 if (limp->rlim_cur > maxfiles) 331 limp->rlim_cur = maxfiles; 332 if (limp->rlim_max > maxfiles) 333 limp->rlim_max = maxfiles; 334 break; 335 336 case RLIMIT_NPROC: 337 if (limp->rlim_cur > maxproc) 338 limp->rlim_cur = maxproc; 339 if (limp->rlim_max > maxproc) 340 limp->rlim_max = maxproc; 341 break; 342 } 343 *alimp = *limp; 344 return (0); 345 } 346 347 struct __getrlimit_args { 348 u_int which; 349 struct rlimit *rlp; 350 }; 351 /* ARGSUSED */ 352 int 353 getrlimit(p, uap, retval) 354 struct proc *p; 355 register struct __getrlimit_args *uap; 356 int *retval; 357 { 358 359 if (uap->which >= RLIM_NLIMITS) 360 return (EINVAL); 361 return (copyout((caddr_t)&p->p_rlimit[uap->which], (caddr_t)uap->rlp, 362 sizeof (struct rlimit))); 363 } 364 365 /* 366 * Transform the running time and tick information in proc p into user, 367 * system, and interrupt time usage. 368 */ 369 void 370 calcru(p, up, sp, ip) 371 register struct proc *p; 372 register struct timeval *up; 373 register struct timeval *sp; 374 register struct timeval *ip; 375 { 376 register u_quad_t u, st, ut, it, tot; 377 register u_long sec, usec; 378 register int s; 379 struct timeval tv; 380 381 s = splstatclock(); 382 st = p->p_sticks; 383 ut = p->p_uticks; 384 it = p->p_iticks; 385 splx(s); 386 387 tot = st + ut + it; 388 if (tot == 0) { 389 up->tv_sec = up->tv_usec = 0; 390 sp->tv_sec = sp->tv_usec = 0; 391 if (ip != NULL) 392 ip->tv_sec = ip->tv_usec = 0; 393 return; 394 } 395 396 sec = p->p_rtime.tv_sec; 397 usec = p->p_rtime.tv_usec; 398 if (p == curproc) { 399 /* 400 * Adjust for the current time slice. This is actually fairly 401 * important since the error here is on the order of a time 402 * quantum, which is much greater than the sampling error. 403 */ 404 microtime(&tv); 405 sec += tv.tv_sec - runtime.tv_sec; 406 usec += tv.tv_usec - runtime.tv_usec; 407 } 408 u = sec * 1000000 + usec; 409 st = (u * st) / tot; 410 sp->tv_sec = st / 1000000; 411 sp->tv_usec = st % 1000000; 412 ut = (u * ut) / tot; 413 up->tv_sec = ut / 1000000; 414 up->tv_usec = ut % 1000000; 415 if (ip != NULL) { 416 it = (u * it) / tot; 417 ip->tv_sec = it / 1000000; 418 ip->tv_usec = it % 1000000; 419 } 420 } 421 422 struct getrusage_args { 423 int who; 424 struct rusage *rusage; 425 }; 426 /* ARGSUSED */ 427 int 428 getrusage(p, uap, retval) 429 register struct proc *p; 430 register struct getrusage_args *uap; 431 int *retval; 432 { 433 register struct rusage *rup; 434 435 switch (uap->who) { 436 437 case RUSAGE_SELF: 438 rup = &p->p_stats->p_ru; 439 calcru(p, &rup->ru_utime, &rup->ru_stime, NULL); 440 break; 441 442 case RUSAGE_CHILDREN: 443 rup = &p->p_stats->p_cru; 444 break; 445 446 default: 447 return (EINVAL); 448 } 449 return (copyout((caddr_t)rup, (caddr_t)uap->rusage, 450 sizeof (struct rusage))); 451 } 452 453 void 454 ruadd(ru, ru2) 455 register struct rusage *ru, *ru2; 456 { 457 register long *ip, *ip2; 458 register int i; 459 460 timevaladd(&ru->ru_utime, &ru2->ru_utime); 461 timevaladd(&ru->ru_stime, &ru2->ru_stime); 462 if (ru->ru_maxrss < ru2->ru_maxrss) 463 ru->ru_maxrss = ru2->ru_maxrss; 464 ip = &ru->ru_first; ip2 = &ru2->ru_first; 465 for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--) 466 *ip++ += *ip2++; 467 } 468 469 /* 470 * Make a copy of the plimit structure. 471 * We share these structures copy-on-write after fork, 472 * and copy when a limit is changed. 473 */ 474 struct plimit * 475 limcopy(lim) 476 struct plimit *lim; 477 { 478 register struct plimit *copy; 479 480 MALLOC(copy, struct plimit *, sizeof(struct plimit), 481 M_SUBPROC, M_WAITOK); 482 bcopy(lim->pl_rlimit, copy->pl_rlimit, 483 sizeof(struct rlimit) * RLIM_NLIMITS); 484 copy->p_lflags = 0; 485 copy->p_refcnt = 1; 486 return (copy); 487 } 488