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