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