xref: /original-bsd/sys/kern/kern_resource.c (revision 68d9582f)
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.17 (Berkeley) 05/31/92
8  */
9 
10 #include "param.h"
11 #include "resourcevar.h"
12 #include "malloc.h"
13 #include "proc.h"
14 
15 #include "vm/vm.h"
16 
17 /*
18  * Resource controls and accounting.
19  */
20 
21 getpriority(curp, uap, retval)
22 	struct proc *curp;
23 	register struct args {
24 		int	which;
25 		int	who;
26 	} *uap;
27 	int *retval;
28 {
29 	register struct proc *p;
30 	register int low = PRIO_MAX + 1;
31 
32 	switch (uap->which) {
33 
34 	case PRIO_PROCESS:
35 		if (uap->who == 0)
36 			p = curp;
37 		else
38 			p = pfind(uap->who);
39 		if (p == 0)
40 			break;
41 		low = p->p_nice;
42 		break;
43 
44 	case PRIO_PGRP: {
45 		register struct pgrp *pg;
46 
47 		if (uap->who == 0)
48 			pg = curp->p_pgrp;
49 		else if ((pg = pgfind(uap->who)) == NULL)
50 			break;
51 		for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) {
52 			if (p->p_nice < low)
53 				low = p->p_nice;
54 		}
55 		break;
56 	}
57 
58 	case PRIO_USER:
59 		if (uap->who == 0)
60 			uap->who = curp->p_ucred->cr_uid;
61 		for (p = allproc; p != NULL; p = p->p_nxt) {
62 			if (p->p_ucred->cr_uid == uap->who &&
63 			    p->p_nice < low)
64 				low = p->p_nice;
65 		}
66 		break;
67 
68 	default:
69 		return (EINVAL);
70 	}
71 	if (low == PRIO_MAX + 1)
72 		return (ESRCH);
73 	*retval = low;
74 	return (0);
75 }
76 
77 /* ARGSUSED */
78 setpriority(curp, uap, retval)
79 	struct proc *curp;
80 	register struct args {
81 		int	which;
82 		int	who;
83 		int	prio;
84 	} *uap;
85 	int *retval;
86 {
87 	register struct proc *p;
88 	int found = 0, error = 0;
89 
90 	switch (uap->which) {
91 
92 	case PRIO_PROCESS:
93 		if (uap->who == 0)
94 			p = curp;
95 		else
96 			p = pfind(uap->who);
97 		if (p == 0)
98 			break;
99 		error = donice(curp, p, uap->prio);
100 		found++;
101 		break;
102 
103 	case PRIO_PGRP: {
104 		register struct pgrp *pg;
105 
106 		if (uap->who == 0)
107 			pg = curp->p_pgrp;
108 		else if ((pg = pgfind(uap->who)) == NULL)
109 			break;
110 		for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) {
111 			error = donice(curp, p, uap->prio);
112 			found++;
113 		}
114 		break;
115 	}
116 
117 	case PRIO_USER:
118 		if (uap->who == 0)
119 			uap->who = curp->p_ucred->cr_uid;
120 		for (p = allproc; p != NULL; p = p->p_nxt)
121 			if (p->p_ucred->cr_uid == uap->who) {
122 				error = donice(curp, p, uap->prio);
123 				found++;
124 			}
125 		break;
126 
127 	default:
128 		return (EINVAL);
129 	}
130 	if (found == 0)
131 		return (ESRCH);
132 	return (0);
133 }
134 
135 donice(curp, chgp, n)
136 	register struct proc *curp, *chgp;
137 	register int n;
138 {
139 	register struct pcred *pcred = curp->p_cred;
140 
141 	if (pcred->pc_ucred->cr_uid && pcred->p_ruid &&
142 	    pcred->pc_ucred->cr_uid != chgp->p_ucred->cr_uid &&
143 	    pcred->p_ruid != chgp->p_ucred->cr_uid)
144 		return (EPERM);
145 	if (n > PRIO_MAX)
146 		n = PRIO_MAX;
147 	if (n < PRIO_MIN)
148 		n = PRIO_MIN;
149 	if (n < chgp->p_nice && suser(pcred->pc_ucred, &curp->p_acflag))
150 		return (EACCES);
151 	chgp->p_nice = n;
152 	(void) setpri(chgp);
153 	return (0);
154 }
155 
156 #ifdef COMPAT_43
157 /* ARGSUSED */
158 setrlimit(p, uap, retval)
159 	struct proc *p;
160 	register struct args {
161 		u_int	which;
162 		struct	orlimit *lim;
163 	} *uap;
164 	int *retval;
165 {
166 	struct orlimit olim;
167 	struct rlimit lim;
168 	int error;
169 
170 	if (error =
171 	    copyin((caddr_t)uap->lim, (caddr_t)&olim, sizeof (struct orlimit)))
172 		return (error);
173 	lim.rlim_cur = olim.rlim_cur;
174 	lim.rlim_max = olim.rlim_max;
175 	return (dosetrlimit(p, uap->which, &lim));
176 }
177 
178 /* ARGSUSED */
179 getrlimit(p, uap, retval)
180 	struct proc *p;
181 	register struct args {
182 		u_int	which;
183 		struct	orlimit *rlp;
184 	} *uap;
185 	int *retval;
186 {
187 	struct orlimit olim;
188 
189 	if (uap->which >= RLIM_NLIMITS)
190 		return (EINVAL);
191 	olim.rlim_cur = p->p_rlimit[uap->which].rlim_cur;
192 	if (olim.rlim_cur == -1)
193 		olim.rlim_cur = 0x7fffffff;
194 	olim.rlim_max = p->p_rlimit[uap->which].rlim_max;
195 	if (olim.rlim_max == -1)
196 		olim.rlim_max = 0x7fffffff;
197 	return (copyout((caddr_t)&olim, (caddr_t)uap->rlp, sizeof(olim)));
198 }
199 #endif /* COMPAT_43 */
200 
201 /* ARGSUSED */
202 __setrlimit(p, uap, retval)
203 	struct proc *p;
204 	register struct args {
205 		u_int	which;
206 		struct	rlimit *lim;
207 	} *uap;
208 	int *retval;
209 {
210 	struct rlimit alim;
211 	int error;
212 
213 	if (error =
214 	    copyin((caddr_t)uap->lim, (caddr_t)&alim, sizeof (struct rlimit)))
215 		return (error);
216 	return (dosetrlimit(p, uap->which, &alim));
217 }
218 
219 dosetrlimit(p, which, limp)
220 	struct proc *p;
221 	u_int which;
222 	struct rlimit *limp;
223 {
224 	register struct rlimit *alimp;
225 	extern unsigned maxdmap;
226 	int error;
227 
228 	if (which >= RLIM_NLIMITS)
229 		return (EINVAL);
230 	alimp = &p->p_rlimit[which];
231 	if (limp->rlim_cur > alimp->rlim_max ||
232 	    limp->rlim_max > alimp->rlim_max)
233 		if (error = suser(p->p_ucred, &p->p_acflag))
234 			return (error);
235 	if (limp->rlim_cur > limp->rlim_max)
236 		limp->rlim_cur = limp->rlim_max;
237 	if (p->p_limit->p_refcnt > 1 &&
238 	    (p->p_limit->p_lflags & PL_SHAREMOD) == 0) {
239 		p->p_limit->p_refcnt--;
240 		p->p_limit = limcopy(p->p_limit);
241 		alimp = &p->p_rlimit[which];
242 	}
243 
244 	switch (which) {
245 
246 	case RLIMIT_DATA:
247 		if (limp->rlim_cur > maxdmap)
248 			limp->rlim_cur = maxdmap;
249 		if (limp->rlim_max > maxdmap)
250 			limp->rlim_max = maxdmap;
251 		break;
252 
253 	case RLIMIT_STACK:
254 		if (limp->rlim_cur > maxdmap)
255 			limp->rlim_cur = maxdmap;
256 		if (limp->rlim_max > maxdmap)
257 			limp->rlim_max = maxdmap;
258 		/*
259 		 * Stack is allocated to the max at exec time with only
260 		 * "rlim_cur" bytes accessible.  If stack limit is going
261 		 * up make more accessible, if going down make inaccessible.
262 		 */
263 		if (limp->rlim_cur != alimp->rlim_cur) {
264 			vm_offset_t addr;
265 			vm_size_t size;
266 			vm_prot_t prot;
267 
268 			if (limp->rlim_cur > alimp->rlim_cur) {
269 				prot = VM_PROT_ALL;
270 				size = limp->rlim_cur - alimp->rlim_cur;
271 				addr = USRSTACK - limp->rlim_cur;
272 			} else {
273 				prot = VM_PROT_NONE;
274 				size = alimp->rlim_cur - limp->rlim_cur;
275 				addr = USRSTACK - alimp->rlim_cur;
276 			}
277 			addr = trunc_page(addr);
278 			size = round_page(size);
279 			(void) vm_map_protect(&p->p_vmspace->vm_map,
280 					      addr, addr+size, prot, FALSE);
281 		}
282 		break;
283 	}
284 	*alimp = *limp;
285 	return (0);
286 }
287 
288 /* ARGSUSED */
289 __getrlimit(p, uap, retval)
290 	struct proc *p;
291 	register struct args {
292 		u_int	which;
293 		struct	rlimit *rlp;
294 	} *uap;
295 	int *retval;
296 {
297 
298 	if (uap->which >= RLIM_NLIMITS)
299 		return (EINVAL);
300 	return (copyout((caddr_t)&p->p_rlimit[uap->which], (caddr_t)uap->rlp,
301 	    sizeof (struct rlimit)));
302 }
303 
304 /* ARGSUSED */
305 getrusage(p, uap, retval)
306 	register struct proc *p;
307 	register struct args {
308 		int	who;
309 		struct	rusage *rusage;
310 	} *uap;
311 	int *retval;
312 {
313 	register struct rusage *rup;
314 
315 	switch (uap->who) {
316 
317 	case RUSAGE_SELF: {
318 		int s;
319 
320 		rup = &p->p_stats->p_ru;
321 		s = splclock();
322 		rup->ru_stime = p->p_stime;
323 		rup->ru_utime = p->p_utime;
324 		splx(s);
325 		break;
326 	}
327 
328 	case RUSAGE_CHILDREN:
329 		rup = &p->p_stats->p_cru;
330 		break;
331 
332 	default:
333 		return (EINVAL);
334 	}
335 	return (copyout((caddr_t)rup, (caddr_t)uap->rusage,
336 	    sizeof (struct rusage)));
337 }
338 
339 ruadd(ru, ru2)
340 	register struct rusage *ru, *ru2;
341 {
342 	register long *ip, *ip2;
343 	register int i;
344 
345 	timevaladd(&ru->ru_utime, &ru2->ru_utime);
346 	timevaladd(&ru->ru_stime, &ru2->ru_stime);
347 	if (ru->ru_maxrss < ru2->ru_maxrss)
348 		ru->ru_maxrss = ru2->ru_maxrss;
349 	ip = &ru->ru_first; ip2 = &ru2->ru_first;
350 	for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
351 		*ip++ += *ip2++;
352 }
353 
354 /*
355  * Make a copy of the plimit structure.
356  * We share these structures copy-on-write after fork,
357  * and copy when a limit is changed.
358  */
359 struct plimit *
360 limcopy(lim)
361 	struct plimit *lim;
362 {
363 	register struct plimit *copy;
364 
365 	MALLOC(copy, struct plimit *, sizeof(struct plimit),
366 	    M_SUBPROC, M_WAITOK);
367 	bcopy(lim->pl_rlimit, copy->pl_rlimit,
368 	    sizeof(struct rlimit) * RLIM_NLIMITS);
369 	copy->p_lflags = 0;
370 	copy->p_refcnt = 1;
371 	return (copy);
372 }
373