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.6 (Berkeley) 08/22/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_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 calcru(p, up, sp, ip) 334 register struct proc *p; 335 register struct timeval *up; 336 register struct timeval *sp; 337 register struct timeval *ip; 338 { 339 register u_quad_t u, st, ut, it, tot; 340 register u_long sec, usec; 341 register int s; 342 struct timeval tv; 343 344 s = splstatclock(); 345 st = p->p_sticks; 346 ut = p->p_uticks; 347 it = p->p_iticks; 348 splx(s); 349 350 tot = st + ut + it; 351 if (tot == 0) { 352 up->tv_sec = up->tv_usec = 0; 353 sp->tv_sec = sp->tv_usec = 0; 354 if (ip != NULL) 355 ip->tv_sec = ip->tv_usec = 0; 356 return; 357 } 358 359 sec = p->p_rtime.tv_sec; 360 usec = p->p_rtime.tv_usec; 361 if (p == curproc) { 362 /* 363 * Adjust for the current time slice. This is actually fairly 364 * important since the error here is on the order of a time 365 * quantum, which is much greater than the sampling error. 366 */ 367 microtime(&tv); 368 sec += tv.tv_sec - runtime.tv_sec; 369 usec += tv.tv_usec - runtime.tv_usec; 370 } 371 u = sec * 1000000 + usec; 372 st = (u * st) / tot; 373 sp->tv_sec = st / 1000000; 374 sp->tv_usec = st % 1000000; 375 ut = (u * ut) / tot; 376 up->tv_sec = ut / 1000000; 377 up->tv_usec = ut % 1000000; 378 if (ip != NULL) { 379 it = (u * it) / tot; 380 ip->tv_sec = it / 1000000; 381 ip->tv_usec = it % 1000000; 382 } 383 } 384 385 struct getrusage_args { 386 int who; 387 struct rusage *rusage; 388 }; 389 /* ARGSUSED */ 390 getrusage(p, uap, retval) 391 register struct proc *p; 392 register struct getrusage_args *uap; 393 int *retval; 394 { 395 register struct rusage *rup; 396 397 switch (uap->who) { 398 399 case RUSAGE_SELF: 400 rup = &p->p_stats->p_ru; 401 calcru(p, &rup->ru_utime, &rup->ru_stime, NULL); 402 break; 403 404 case RUSAGE_CHILDREN: 405 rup = &p->p_stats->p_cru; 406 break; 407 408 default: 409 return (EINVAL); 410 } 411 return (copyout((caddr_t)rup, (caddr_t)uap->rusage, 412 sizeof (struct rusage))); 413 } 414 415 ruadd(ru, ru2) 416 register struct rusage *ru, *ru2; 417 { 418 register long *ip, *ip2; 419 register int i; 420 421 timevaladd(&ru->ru_utime, &ru2->ru_utime); 422 timevaladd(&ru->ru_stime, &ru2->ru_stime); 423 if (ru->ru_maxrss < ru2->ru_maxrss) 424 ru->ru_maxrss = ru2->ru_maxrss; 425 ip = &ru->ru_first; ip2 = &ru2->ru_first; 426 for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--) 427 *ip++ += *ip2++; 428 } 429 430 /* 431 * Make a copy of the plimit structure. 432 * We share these structures copy-on-write after fork, 433 * and copy when a limit is changed. 434 */ 435 struct plimit * 436 limcopy(lim) 437 struct plimit *lim; 438 { 439 register struct plimit *copy; 440 441 MALLOC(copy, struct plimit *, sizeof(struct plimit), 442 M_SUBPROC, M_WAITOK); 443 bcopy(lim->pl_rlimit, copy->pl_rlimit, 444 sizeof(struct rlimit) * RLIM_NLIMITS); 445 copy->p_lflags = 0; 446 copy->p_refcnt = 1; 447 return (copy); 448 } 449