xref: /original-bsd/sys/kern/kern_resource.c (revision 7f897caf)
1 /*-
2  * Copyright (c) 1982, 1986, 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)kern_resource.c	7.23 (Berkeley) 03/23/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 setrlimit(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 getrlimit(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 	*alimp = *limp;
299 	return (0);
300 }
301 
302 struct __getrlimit_args {
303 	u_int	which;
304 	struct	rlimit *rlp;
305 };
306 /* ARGSUSED */
307 __getrlimit(p, uap, retval)
308 	struct proc *p;
309 	register struct __getrlimit_args *uap;
310 	int *retval;
311 {
312 
313 	if (uap->which >= RLIM_NLIMITS)
314 		return (EINVAL);
315 	return (copyout((caddr_t)&p->p_rlimit[uap->which], (caddr_t)uap->rlp,
316 	    sizeof (struct rlimit)));
317 }
318 
319 /*
320  * Transform the running time and tick information in proc p into user,
321  * system, and interrupt time usage.
322  */
323 calcru(p, up, sp, ip)
324 	register struct proc *p;
325 	register struct timeval *up;
326 	register struct timeval *sp;
327 	register struct timeval *ip;
328 {
329 	register u_quad_t u, st, ut, it, tot;
330 	register u_long sec, usec;
331 	register int s;
332 	struct timeval tv;
333 
334 	s = splstatclock();
335 	st = p->p_sticks;
336 	ut = p->p_uticks;
337 	it = p->p_iticks;
338 	splx(s);
339 
340 	tot = st + ut + it;
341 	if (tot == 0) {
342 		up->tv_sec = up->tv_usec = 0;
343 		sp->tv_sec = sp->tv_usec = 0;
344 		if (ip != NULL)
345 			ip->tv_sec = ip->tv_usec = 0;
346 		return;
347 	}
348 
349 	sec = p->p_rtime.tv_sec;
350 	usec = p->p_rtime.tv_usec;
351 	if (p == curproc) {
352 		/*
353 		 * Adjust for the current time slice.  This is actually fairly
354 		 * important since the error here is on the order of a time
355 		 * quantum, which is much greater than the sampling error.
356 		 */
357 		microtime(&tv);
358 		sec += tv.tv_sec - runtime.tv_sec;
359 		usec += tv.tv_usec - runtime.tv_usec;
360 	}
361 	u = sec * 1000000 + usec;
362 	st = (u * st) / tot;
363 	sp->tv_sec = st / 1000000;
364 	sp->tv_usec = st % 1000000;
365 	ut = (u * ut) / tot;
366 	up->tv_sec = ut / 1000000;
367 	up->tv_usec = ut % 1000000;
368 	if (ip != NULL) {
369 		it = (u * it) / tot;
370 		ip->tv_sec = it / 1000000;
371 		ip->tv_usec = it % 1000000;
372 	}
373 }
374 
375 struct getrusage_args {
376 	int	who;
377 	struct	rusage *rusage;
378 };
379 /* ARGSUSED */
380 getrusage(p, uap, retval)
381 	register struct proc *p;
382 	register struct getrusage_args *uap;
383 	int *retval;
384 {
385 	register struct rusage *rup;
386 
387 	switch (uap->who) {
388 
389 	case RUSAGE_SELF:
390 		rup = &p->p_stats->p_ru;
391 		calcru(p, &rup->ru_utime, &rup->ru_stime, NULL);
392 		break;
393 
394 	case RUSAGE_CHILDREN:
395 		rup = &p->p_stats->p_cru;
396 		break;
397 
398 	default:
399 		return (EINVAL);
400 	}
401 	return (copyout((caddr_t)rup, (caddr_t)uap->rusage,
402 	    sizeof (struct rusage)));
403 }
404 
405 ruadd(ru, ru2)
406 	register struct rusage *ru, *ru2;
407 {
408 	register long *ip, *ip2;
409 	register int i;
410 
411 	timevaladd(&ru->ru_utime, &ru2->ru_utime);
412 	timevaladd(&ru->ru_stime, &ru2->ru_stime);
413 	if (ru->ru_maxrss < ru2->ru_maxrss)
414 		ru->ru_maxrss = ru2->ru_maxrss;
415 	ip = &ru->ru_first; ip2 = &ru2->ru_first;
416 	for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
417 		*ip++ += *ip2++;
418 }
419 
420 /*
421  * Make a copy of the plimit structure.
422  * We share these structures copy-on-write after fork,
423  * and copy when a limit is changed.
424  */
425 struct plimit *
426 limcopy(lim)
427 	struct plimit *lim;
428 {
429 	register struct plimit *copy;
430 
431 	MALLOC(copy, struct plimit *, sizeof(struct plimit),
432 	    M_SUBPROC, M_WAITOK);
433 	bcopy(lim->pl_rlimit, copy->pl_rlimit,
434 	    sizeof(struct rlimit) * RLIM_NLIMITS);
435 	copy->p_lflags = 0;
436 	copy->p_refcnt = 1;
437 	return (copy);
438 }
439