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