xref: /original-bsd/sys/kern/kern_resource.c (revision 89e46f9f)
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.15 (Berkeley) 03/15/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 /* ARGSUSED */
157 setrlimit(p, uap, retval)
158 	struct proc *p;
159 	register struct args {
160 		u_int	which;
161 		struct	rlimit *lim;
162 	} *uap;
163 	int *retval;
164 {
165 	struct rlimit alim;
166 	register struct rlimit *alimp;
167 	extern unsigned maxdmap;
168 	int error;
169 
170 	if (uap->which >= RLIM_NLIMITS)
171 		return (EINVAL);
172 	alimp = &p->p_rlimit[uap->which];
173 	if (error =
174 	    copyin((caddr_t)uap->lim, (caddr_t)&alim, sizeof (struct rlimit)))
175 		return (error);
176 	if (alim.rlim_cur > alimp->rlim_max || alim.rlim_max > alimp->rlim_max)
177 		if (error = suser(p->p_ucred, &p->p_acflag))
178 			return (error);
179 	if (alim.rlim_cur > alim.rlim_max)
180 		alim.rlim_cur = alim.rlim_max;
181 	if (p->p_limit->p_refcnt > 1 &&
182 	    (p->p_limit->p_lflags & PL_SHAREMOD) == 0) {
183 		p->p_limit->p_refcnt--;
184 		p->p_limit = limcopy(p->p_limit);
185 		alimp = &p->p_rlimit[uap->which];
186 	}
187 
188 	switch (uap->which) {
189 
190 	case RLIMIT_DATA:
191 		if (alim.rlim_cur > maxdmap)
192 			alim.rlim_cur = maxdmap;
193 		if (alim.rlim_max > maxdmap)
194 			alim.rlim_max = maxdmap;
195 		break;
196 
197 	case RLIMIT_STACK:
198 		if (alim.rlim_cur > maxdmap)
199 			alim.rlim_cur = maxdmap;
200 		if (alim.rlim_max > maxdmap)
201 			alim.rlim_max = maxdmap;
202 		/*
203 		 * Stack is allocated to the max at exec time with only
204 		 * "rlim_cur" bytes accessible.  If stack limit is going
205 		 * up make more accessible, if going down make inaccessible.
206 		 */
207 		if (alim.rlim_cur != alimp->rlim_cur) {
208 			vm_offset_t addr;
209 			vm_size_t size;
210 			vm_prot_t prot;
211 
212 			if (alim.rlim_cur > alimp->rlim_cur) {
213 				prot = VM_PROT_ALL;
214 				size = alim.rlim_cur - alimp->rlim_cur;
215 				addr = USRSTACK - alim.rlim_cur;
216 			} else {
217 				prot = VM_PROT_NONE;
218 				size = alimp->rlim_cur - alim.rlim_cur;
219 				addr = USRSTACK - alimp->rlim_cur;
220 			}
221 			addr = trunc_page(addr);
222 			size = round_page(size);
223 			(void) vm_map_protect(&p->p_vmspace->vm_map,
224 					      addr, addr+size, prot, FALSE);
225 		}
226 		break;
227 	}
228 	*alimp = alim;
229 	return (0);
230 }
231 
232 /* ARGSUSED */
233 getrlimit(p, uap, retval)
234 	struct proc *p;
235 	register struct args {
236 		u_int	which;
237 		struct	rlimit *rlp;
238 	} *uap;
239 	int *retval;
240 {
241 
242 	if (uap->which >= RLIM_NLIMITS)
243 		return (EINVAL);
244 	return (copyout((caddr_t)&p->p_rlimit[uap->which], (caddr_t)uap->rlp,
245 	    sizeof (struct rlimit)));
246 }
247 
248 /* ARGSUSED */
249 getrusage(p, uap, retval)
250 	register struct proc *p;
251 	register struct args {
252 		int	who;
253 		struct	rusage *rusage;
254 	} *uap;
255 	int *retval;
256 {
257 	register struct rusage *rup;
258 
259 	switch (uap->who) {
260 
261 	case RUSAGE_SELF: {
262 		int s;
263 
264 		rup = &p->p_stats->p_ru;
265 		s = splclock();
266 		rup->ru_stime = p->p_stime;
267 		rup->ru_utime = p->p_utime;
268 		splx(s);
269 		break;
270 	}
271 
272 	case RUSAGE_CHILDREN:
273 		rup = &p->p_stats->p_cru;
274 		break;
275 
276 	default:
277 		return (EINVAL);
278 	}
279 	return (copyout((caddr_t)rup, (caddr_t)uap->rusage,
280 	    sizeof (struct rusage)));
281 }
282 
283 ruadd(ru, ru2)
284 	register struct rusage *ru, *ru2;
285 {
286 	register long *ip, *ip2;
287 	register int i;
288 
289 	timevaladd(&ru->ru_utime, &ru2->ru_utime);
290 	timevaladd(&ru->ru_stime, &ru2->ru_stime);
291 	if (ru->ru_maxrss < ru2->ru_maxrss)
292 		ru->ru_maxrss = ru2->ru_maxrss;
293 	ip = &ru->ru_first; ip2 = &ru2->ru_first;
294 	for (i = &ru->ru_last - &ru->ru_first; i > 0; i--)
295 		*ip++ += *ip2++;
296 }
297 
298 /*
299  * Make a copy of the plimit structure.
300  * We share these structures copy-on-write after fork,
301  * and copy when a limit is changed.
302  */
303 struct plimit *
304 limcopy(lim)
305 	struct plimit *lim;
306 {
307 	register struct plimit *copy;
308 
309 	MALLOC(copy, struct plimit *, sizeof(struct plimit),
310 	    M_SUBPROC, M_WAITOK);
311 	bcopy(lim->pl_rlimit, copy->pl_rlimit,
312 	    sizeof(struct rlimit) * RLIM_NLIMITS);
313 	copy->p_lflags = 0;
314 	copy->p_refcnt = 1;
315 	return (copy);
316 }
317