xref: /minix3/minix/servers/pm/misc.c (revision bfa518c7ec394377db1e3fd9e5221a2b1a74e06b)
1433d6423SLionel Sambuc /* Miscellaneous system calls.				Author: Kees J. Bot
2433d6423SLionel Sambuc  *								31 Mar 2000
3433d6423SLionel Sambuc  * The entry points into this file are:
4433d6423SLionel Sambuc  *   do_reboot: kill all processes, then reboot system
5433d6423SLionel Sambuc  *   do_getsysinfo: request copy of PM data structure  (Jorrit N. Herder)
6433d6423SLionel Sambuc  *   do_getprocnr: lookup endpoint by process ID
7433d6423SLionel Sambuc  *   do_getepinfo: get the pid/uid/gid of a process given its endpoint
8433d6423SLionel Sambuc  *   do_getsetpriority: get/set process priority
9433d6423SLionel Sambuc  *   do_svrctl: process manager control
10bc2d75faSDavid van Moolenbroek  *   do_getrusage: obtain process resource usage information
11433d6423SLionel Sambuc  */
12433d6423SLionel Sambuc 
13433d6423SLionel Sambuc #include "pm.h"
14433d6423SLionel Sambuc #include <minix/callnr.h>
15433d6423SLionel Sambuc #include <signal.h>
16433d6423SLionel Sambuc #include <sys/svrctl.h>
17433d6423SLionel Sambuc #include <sys/reboot.h>
18433d6423SLionel Sambuc #include <sys/resource.h>
19433d6423SLionel Sambuc #include <sys/utsname.h>
20433d6423SLionel Sambuc #include <minix/com.h>
21433d6423SLionel Sambuc #include <minix/config.h>
22433d6423SLionel Sambuc #include <minix/sysinfo.h>
23433d6423SLionel Sambuc #include <minix/type.h>
24433d6423SLionel Sambuc #include <minix/ds.h>
25433d6423SLionel Sambuc #include <machine/archtypes.h>
26433d6423SLionel Sambuc #include <lib.h>
27433d6423SLionel Sambuc #include <assert.h>
28433d6423SLionel Sambuc #include "mproc.h"
29433d6423SLionel Sambuc #include "kernel/proc.h"
30433d6423SLionel Sambuc 
31d991a2beSDavid van Moolenbroek /* START OF COMPATIBILITY BLOCK */
32433d6423SLionel Sambuc struct utsname uts_val = {
33433d6423SLionel Sambuc   OS_NAME,		/* system name */
34433d6423SLionel Sambuc   "noname",		/* node/network name */
35433d6423SLionel Sambuc   OS_RELEASE,		/* O.S. release (e.g. 3.3.0) */
36433d6423SLionel Sambuc   OS_VERSION,		/* O.S. version (e.g. Minix 3.3.0 (GENERIC)) */
37433d6423SLionel Sambuc #if defined(__i386__)
38ea36b58eSLionel Sambuc   "i386",		/* machine (cpu) type */
39433d6423SLionel Sambuc #elif defined(__arm__)
40d991a2beSDavid van Moolenbroek   "evbarm",		/* machine (cpu) type */
41433d6423SLionel Sambuc #else
42433d6423SLionel Sambuc #error			/* oops, no 'uname -mk' */
43433d6423SLionel Sambuc #endif
44433d6423SLionel Sambuc };
45433d6423SLionel Sambuc 
46433d6423SLionel Sambuc static char *uts_tbl[] = {
47d991a2beSDavid van Moolenbroek #if defined(__i386__)
48d991a2beSDavid van Moolenbroek   "i386",		/* architecture */
49d991a2beSDavid van Moolenbroek #elif defined(__arm__)
50d991a2beSDavid van Moolenbroek   "evbarm",		/* architecture */
51d991a2beSDavid van Moolenbroek #endif
52433d6423SLionel Sambuc   NULL,			/* No kernel architecture */
53433d6423SLionel Sambuc   uts_val.machine,
54433d6423SLionel Sambuc   NULL,			/* No hostname */
55433d6423SLionel Sambuc   uts_val.nodename,
56433d6423SLionel Sambuc   uts_val.release,
57433d6423SLionel Sambuc   uts_val.version,
58433d6423SLionel Sambuc   uts_val.sysname,
59433d6423SLionel Sambuc   NULL,			/* No bus */			/* No bus */
60433d6423SLionel Sambuc };
61d991a2beSDavid van Moolenbroek /* END OF COMPATIBILITY BLOCK */
62433d6423SLionel Sambuc 
63433d6423SLionel Sambuc #if ENABLE_SYSCALL_STATS
64433d6423SLionel Sambuc unsigned long calls_stats[NR_PM_CALLS];
65433d6423SLionel Sambuc #endif
66433d6423SLionel Sambuc 
67d991a2beSDavid van Moolenbroek /* START OF COMPATIBILITY BLOCK */
68433d6423SLionel Sambuc /*===========================================================================*
69433d6423SLionel Sambuc  *				do_sysuname				     *
70433d6423SLionel Sambuc  *===========================================================================*/
71637f688fSRichard Sailer int
do_sysuname(void)72637f688fSRichard Sailer do_sysuname(void)
73433d6423SLionel Sambuc {
74433d6423SLionel Sambuc /* Set or get uname strings. */
75433d6423SLionel Sambuc   int r;
76433d6423SLionel Sambuc   size_t n;
77433d6423SLionel Sambuc   char *string;
78433d6423SLionel Sambuc 
79d991a2beSDavid van Moolenbroek   if (m_in.m_lc_pm_sysuname.field >= __arraycount(uts_tbl)) return(EINVAL);
80433d6423SLionel Sambuc 
81433d6423SLionel Sambuc   string = uts_tbl[m_in.m_lc_pm_sysuname.field];
82433d6423SLionel Sambuc   if (string == NULL)
83433d6423SLionel Sambuc 	return EINVAL;	/* Unsupported field */
84433d6423SLionel Sambuc 
85433d6423SLionel Sambuc   switch (m_in.m_lc_pm_sysuname.req) {
86d991a2beSDavid van Moolenbroek   case 0:
87433d6423SLionel Sambuc 	/* Copy an uname string to the user. */
88433d6423SLionel Sambuc 	n = strlen(string) + 1;
89433d6423SLionel Sambuc 	if (n > m_in.m_lc_pm_sysuname.len) n = m_in.m_lc_pm_sysuname.len;
90433d6423SLionel Sambuc 	r = sys_datacopy(SELF, (vir_bytes)string, mp->mp_endpoint,
91433d6423SLionel Sambuc 		m_in.m_lc_pm_sysuname.value, (phys_bytes)n);
92433d6423SLionel Sambuc 	if (r < 0) return(r);
93433d6423SLionel Sambuc 	break;
94433d6423SLionel Sambuc 
95433d6423SLionel Sambuc   default:
96433d6423SLionel Sambuc 	return(EINVAL);
97433d6423SLionel Sambuc   }
98433d6423SLionel Sambuc   /* Return the number of bytes moved. */
99433d6423SLionel Sambuc   return(n);
100433d6423SLionel Sambuc }
101d991a2beSDavid van Moolenbroek /* END OF COMPATIBILITY BLOCK */
102433d6423SLionel Sambuc 
103433d6423SLionel Sambuc 
104433d6423SLionel Sambuc /*===========================================================================*
105433d6423SLionel Sambuc  *				do_getsysinfo			       	     *
106433d6423SLionel Sambuc  *===========================================================================*/
107637f688fSRichard Sailer int
do_getsysinfo(void)108637f688fSRichard Sailer do_getsysinfo(void)
109433d6423SLionel Sambuc {
110433d6423SLionel Sambuc   vir_bytes src_addr, dst_addr;
111433d6423SLionel Sambuc   size_t len;
112433d6423SLionel Sambuc 
113433d6423SLionel Sambuc   /* This call leaks important information. In the future, requests from
114433d6423SLionel Sambuc    * non-system processes should be denied.
115433d6423SLionel Sambuc    */
116433d6423SLionel Sambuc   if (mp->mp_effuid != 0)
117433d6423SLionel Sambuc   {
118433d6423SLionel Sambuc 	printf("PM: unauthorized call of do_getsysinfo by proc %d '%s'\n",
119433d6423SLionel Sambuc 		mp->mp_endpoint, mp->mp_name);
120433d6423SLionel Sambuc 	sys_diagctl_stacktrace(mp->mp_endpoint);
121433d6423SLionel Sambuc 	return EPERM;
122433d6423SLionel Sambuc   }
123433d6423SLionel Sambuc 
124433d6423SLionel Sambuc   switch(m_in.m_lsys_getsysinfo.what) {
125433d6423SLionel Sambuc   case SI_PROC_TAB:			/* copy entire process table */
126433d6423SLionel Sambuc         src_addr = (vir_bytes) mproc;
127433d6423SLionel Sambuc         len = sizeof(struct mproc) * NR_PROCS;
128433d6423SLionel Sambuc         break;
129433d6423SLionel Sambuc #if ENABLE_SYSCALL_STATS
130433d6423SLionel Sambuc   case SI_CALL_STATS:
131433d6423SLionel Sambuc   	src_addr = (vir_bytes) calls_stats;
132433d6423SLionel Sambuc   	len = sizeof(calls_stats);
133433d6423SLionel Sambuc   	break;
134433d6423SLionel Sambuc #endif
135433d6423SLionel Sambuc   default:
136433d6423SLionel Sambuc   	return(EINVAL);
137433d6423SLionel Sambuc   }
138433d6423SLionel Sambuc 
139433d6423SLionel Sambuc   if (len != m_in.m_lsys_getsysinfo.size)
140433d6423SLionel Sambuc 	return(EINVAL);
141433d6423SLionel Sambuc 
142433d6423SLionel Sambuc   dst_addr = m_in.m_lsys_getsysinfo.where;
143433d6423SLionel Sambuc   return sys_datacopy(SELF, src_addr, who_e, dst_addr, len);
144433d6423SLionel Sambuc }
145433d6423SLionel Sambuc 
146433d6423SLionel Sambuc /*===========================================================================*
147433d6423SLionel Sambuc  *				do_getprocnr			             *
148433d6423SLionel Sambuc  *===========================================================================*/
do_getprocnr(void)149433d6423SLionel Sambuc int do_getprocnr(void)
150433d6423SLionel Sambuc {
151433d6423SLionel Sambuc   register struct mproc *rmp;
152433d6423SLionel Sambuc 
153433d6423SLionel Sambuc   /* This check should be replaced by per-call ACL checks. */
154433d6423SLionel Sambuc   if (who_e != RS_PROC_NR) {
155433d6423SLionel Sambuc 	printf("PM: unauthorized call of do_getprocnr by %d\n", who_e);
156433d6423SLionel Sambuc 	return EPERM;
157433d6423SLionel Sambuc   }
158433d6423SLionel Sambuc 
159433d6423SLionel Sambuc   if ((rmp = find_proc(m_in.m_lsys_pm_getprocnr.pid)) == NULL)
160433d6423SLionel Sambuc 	return(ESRCH);
161433d6423SLionel Sambuc 
162433d6423SLionel Sambuc   mp->mp_reply.m_pm_lsys_getprocnr.endpt = rmp->mp_endpoint;
163433d6423SLionel Sambuc   return(OK);
164433d6423SLionel Sambuc }
165433d6423SLionel Sambuc 
166433d6423SLionel Sambuc /*===========================================================================*
167433d6423SLionel Sambuc  *				do_getepinfo			             *
168433d6423SLionel Sambuc  *===========================================================================*/
do_getepinfo(void)169433d6423SLionel Sambuc int do_getepinfo(void)
170433d6423SLionel Sambuc {
171433d6423SLionel Sambuc   struct mproc *rmp;
172433d6423SLionel Sambuc   endpoint_t ep;
173*bfa518c7SDavid van Moolenbroek   int r, slot, ngroups;
174433d6423SLionel Sambuc 
175433d6423SLionel Sambuc   ep = m_in.m_lsys_pm_getepinfo.endpt;
176433d6423SLionel Sambuc   if (pm_isokendpt(ep, &slot) != OK)
177433d6423SLionel Sambuc 	return(ESRCH);
178433d6423SLionel Sambuc   rmp = &mproc[slot];
179*bfa518c7SDavid van Moolenbroek 
180*bfa518c7SDavid van Moolenbroek   mp->mp_reply.m_pm_lsys_getepinfo.uid = rmp->mp_realuid;
181*bfa518c7SDavid van Moolenbroek   mp->mp_reply.m_pm_lsys_getepinfo.euid = rmp->mp_effuid;
182*bfa518c7SDavid van Moolenbroek   mp->mp_reply.m_pm_lsys_getepinfo.gid = rmp->mp_realgid;
183*bfa518c7SDavid van Moolenbroek   mp->mp_reply.m_pm_lsys_getepinfo.egid = rmp->mp_effgid;
184*bfa518c7SDavid van Moolenbroek   mp->mp_reply.m_pm_lsys_getepinfo.ngroups = ngroups = rmp->mp_ngroups;
185*bfa518c7SDavid van Moolenbroek   if (ngroups > m_in.m_lsys_pm_getepinfo.ngroups)
186*bfa518c7SDavid van Moolenbroek 	ngroups = m_in.m_lsys_pm_getepinfo.ngroups;
187*bfa518c7SDavid van Moolenbroek   if (ngroups > 0) {
188*bfa518c7SDavid van Moolenbroek 	if ((r = sys_datacopy(SELF, (vir_bytes)rmp->mp_sgroups, who_e,
189*bfa518c7SDavid van Moolenbroek 	    m_in.m_lsys_pm_getepinfo.groups, ngroups * sizeof(gid_t))) != OK)
190*bfa518c7SDavid van Moolenbroek 		return(r);
191*bfa518c7SDavid van Moolenbroek   }
192433d6423SLionel Sambuc   return(rmp->mp_pid);
193433d6423SLionel Sambuc }
194433d6423SLionel Sambuc 
195433d6423SLionel Sambuc /*===========================================================================*
196433d6423SLionel Sambuc  *				do_reboot				     *
197433d6423SLionel Sambuc  *===========================================================================*/
198637f688fSRichard Sailer int
do_reboot(void)199637f688fSRichard Sailer do_reboot(void)
200433d6423SLionel Sambuc {
201433d6423SLionel Sambuc   message m;
202433d6423SLionel Sambuc 
203433d6423SLionel Sambuc   /* Check permission to abort the system. */
204433d6423SLionel Sambuc   if (mp->mp_effuid != SUPER_USER) return(EPERM);
205433d6423SLionel Sambuc 
206433d6423SLionel Sambuc   /* See how the system should be aborted. */
207433d6423SLionel Sambuc   abort_flag = m_in.m_lc_pm_reboot.how;
208433d6423SLionel Sambuc 
209433d6423SLionel Sambuc   /* notify readclock (some arm systems power off via RTC alarms) */
210433d6423SLionel Sambuc   if (abort_flag & RB_POWERDOWN) {
211433d6423SLionel Sambuc 	endpoint_t readclock_ep;
212433d6423SLionel Sambuc 	if (ds_retrieve_label_endpt("readclock.drv", &readclock_ep) == OK) {
213433d6423SLionel Sambuc 		message m; /* no params to set, nothing we can do if it fails */
214433d6423SLionel Sambuc 		_taskcall(readclock_ep, RTCDEV_PWR_OFF, &m);
215433d6423SLionel Sambuc 	}
216433d6423SLionel Sambuc   }
217433d6423SLionel Sambuc 
218433d6423SLionel Sambuc   /* Order matters here. When VFS is told to reboot, it exits all its
219433d6423SLionel Sambuc    * processes, and then would be confused if they're exited again by
220433d6423SLionel Sambuc    * SIGKILL. So first kill, then reboot.
221433d6423SLionel Sambuc    */
222433d6423SLionel Sambuc 
223433d6423SLionel Sambuc   check_sig(-1, SIGKILL, FALSE /* ksig*/); /* kill all users except init */
224433d6423SLionel Sambuc   sys_stop(INIT_PROC_NR);		   /* stop init, but keep it around */
225433d6423SLionel Sambuc 
226433d6423SLionel Sambuc   /* Tell VFS to reboot */
227433d6423SLionel Sambuc   memset(&m, 0, sizeof(m));
228433d6423SLionel Sambuc   m.m_type = VFS_PM_REBOOT;
229433d6423SLionel Sambuc 
230433d6423SLionel Sambuc   tell_vfs(&mproc[VFS_PROC_NR], &m);
231433d6423SLionel Sambuc 
232433d6423SLionel Sambuc   return(SUSPEND);			/* don't reply to caller */
233433d6423SLionel Sambuc }
234433d6423SLionel Sambuc 
235433d6423SLionel Sambuc /*===========================================================================*
236433d6423SLionel Sambuc  *				do_getsetpriority			     *
237433d6423SLionel Sambuc  *===========================================================================*/
238637f688fSRichard Sailer int
do_getsetpriority(void)239637f688fSRichard Sailer do_getsetpriority(void)
240433d6423SLionel Sambuc {
241433d6423SLionel Sambuc 	int r, arg_which, arg_who, arg_pri;
242433d6423SLionel Sambuc 	struct mproc *rmp;
243433d6423SLionel Sambuc 
244433d6423SLionel Sambuc 	arg_which = m_in.m_lc_pm_priority.which;
245433d6423SLionel Sambuc 	arg_who = m_in.m_lc_pm_priority.who;
246433d6423SLionel Sambuc 	arg_pri = m_in.m_lc_pm_priority.prio;	/* for SETPRIORITY */
247433d6423SLionel Sambuc 
248433d6423SLionel Sambuc 	/* Code common to GETPRIORITY and SETPRIORITY. */
249433d6423SLionel Sambuc 
250433d6423SLionel Sambuc 	/* Only support PRIO_PROCESS for now. */
251433d6423SLionel Sambuc 	if (arg_which != PRIO_PROCESS)
252433d6423SLionel Sambuc 		return(EINVAL);
253433d6423SLionel Sambuc 
254433d6423SLionel Sambuc 	if (arg_who == 0)
255433d6423SLionel Sambuc 		rmp = mp;
256433d6423SLionel Sambuc 	else
257433d6423SLionel Sambuc 		if ((rmp = find_proc(arg_who)) == NULL)
258433d6423SLionel Sambuc 			return(ESRCH);
259433d6423SLionel Sambuc 
260433d6423SLionel Sambuc 	if (mp->mp_effuid != SUPER_USER &&
261433d6423SLionel Sambuc 	   mp->mp_effuid != rmp->mp_effuid && mp->mp_effuid != rmp->mp_realuid)
262433d6423SLionel Sambuc 		return EPERM;
263433d6423SLionel Sambuc 
264433d6423SLionel Sambuc 	/* If GET, that's it. */
265433d6423SLionel Sambuc 	if (call_nr == PM_GETPRIORITY) {
266433d6423SLionel Sambuc 		return(rmp->mp_nice - PRIO_MIN);
267433d6423SLionel Sambuc 	}
268433d6423SLionel Sambuc 
269433d6423SLionel Sambuc 	/* Only root is allowed to reduce the nice level. */
270433d6423SLionel Sambuc 	if (rmp->mp_nice > arg_pri && mp->mp_effuid != SUPER_USER)
271433d6423SLionel Sambuc 		return(EACCES);
272433d6423SLionel Sambuc 
273433d6423SLionel Sambuc 	/* We're SET, and it's allowed.
274433d6423SLionel Sambuc 	 *
275433d6423SLionel Sambuc 	 * The value passed in is currently between PRIO_MIN and PRIO_MAX.
276433d6423SLionel Sambuc 	 * We have to scale this between MIN_USER_Q and MAX_USER_Q to match
277433d6423SLionel Sambuc 	 * the kernel's scheduling queues.
278433d6423SLionel Sambuc 	 */
279433d6423SLionel Sambuc 
280433d6423SLionel Sambuc 	if ((r = sched_nice(rmp, arg_pri)) != OK) {
281433d6423SLionel Sambuc 		return r;
282433d6423SLionel Sambuc 	}
283433d6423SLionel Sambuc 
284433d6423SLionel Sambuc 	rmp->mp_nice = arg_pri;
285433d6423SLionel Sambuc 	return(OK);
286433d6423SLionel Sambuc }
287433d6423SLionel Sambuc 
288433d6423SLionel Sambuc /*===========================================================================*
289433d6423SLionel Sambuc  *				do_svrctl				     *
290433d6423SLionel Sambuc  *===========================================================================*/
do_svrctl(void)291f737eea6SDavid van Moolenbroek int do_svrctl(void)
292433d6423SLionel Sambuc {
293f737eea6SDavid van Moolenbroek   unsigned long req;
294f737eea6SDavid van Moolenbroek   int s;
295433d6423SLionel Sambuc   vir_bytes ptr;
296433d6423SLionel Sambuc #define MAX_LOCAL_PARAMS 2
297433d6423SLionel Sambuc   static struct {
298433d6423SLionel Sambuc   	char name[30];
299433d6423SLionel Sambuc   	char value[30];
300433d6423SLionel Sambuc   } local_param_overrides[MAX_LOCAL_PARAMS];
301433d6423SLionel Sambuc   static int local_params = 0;
302433d6423SLionel Sambuc 
303f737eea6SDavid van Moolenbroek   req = m_in.m_lc_svrctl.request;
304f737eea6SDavid van Moolenbroek   ptr = m_in.m_lc_svrctl.arg;
305433d6423SLionel Sambuc 
306f737eea6SDavid van Moolenbroek   /* Is the request indeed for the PM? ('M' is old and being phased out) */
307f737eea6SDavid van Moolenbroek   if (IOCGROUP(req) != 'P' && IOCGROUP(req) != 'M') return(EINVAL);
308433d6423SLionel Sambuc 
309433d6423SLionel Sambuc   /* Control operations local to the PM. */
310433d6423SLionel Sambuc   switch(req) {
311f737eea6SDavid van Moolenbroek   case OPMSETPARAM:
312f737eea6SDavid van Moolenbroek   case OPMGETPARAM:
313433d6423SLionel Sambuc   case PMSETPARAM:
314433d6423SLionel Sambuc   case PMGETPARAM: {
315433d6423SLionel Sambuc       struct sysgetenv sysgetenv;
316433d6423SLionel Sambuc       char search_key[64];
317433d6423SLionel Sambuc       char *val_start;
318433d6423SLionel Sambuc       size_t val_len;
319433d6423SLionel Sambuc       size_t copy_len;
320433d6423SLionel Sambuc 
321433d6423SLionel Sambuc       /* Copy sysgetenv structure to PM. */
322433d6423SLionel Sambuc       if (sys_datacopy(who_e, ptr, SELF, (vir_bytes) &sysgetenv,
323433d6423SLionel Sambuc               sizeof(sysgetenv)) != OK) return(EFAULT);
324433d6423SLionel Sambuc 
325433d6423SLionel Sambuc       /* Set a param override? */
326f737eea6SDavid van Moolenbroek       if (req == PMSETPARAM || req == OPMSETPARAM) {
327433d6423SLionel Sambuc   	if (local_params >= MAX_LOCAL_PARAMS) return ENOSPC;
328433d6423SLionel Sambuc   	if (sysgetenv.keylen <= 0
329433d6423SLionel Sambuc   	 || sysgetenv.keylen >=
330433d6423SLionel Sambuc   	 	 sizeof(local_param_overrides[local_params].name)
331433d6423SLionel Sambuc   	 || sysgetenv.vallen <= 0
332433d6423SLionel Sambuc   	 || sysgetenv.vallen >=
333433d6423SLionel Sambuc   	 	 sizeof(local_param_overrides[local_params].value))
334433d6423SLionel Sambuc   		return EINVAL;
335433d6423SLionel Sambuc 
336433d6423SLionel Sambuc           if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.key,
337433d6423SLionel Sambuc             SELF, (vir_bytes) local_param_overrides[local_params].name,
338433d6423SLionel Sambuc                sysgetenv.keylen)) != OK)
339433d6423SLionel Sambuc                	return s;
340433d6423SLionel Sambuc           if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.val,
341433d6423SLionel Sambuc             SELF, (vir_bytes) local_param_overrides[local_params].value,
342433d6423SLionel Sambuc               sysgetenv.vallen)) != OK)
343433d6423SLionel Sambuc                	return s;
344433d6423SLionel Sambuc             local_param_overrides[local_params].name[sysgetenv.keylen] = '\0';
345433d6423SLionel Sambuc             local_param_overrides[local_params].value[sysgetenv.vallen] = '\0';
346433d6423SLionel Sambuc 
347433d6423SLionel Sambuc   	local_params++;
348433d6423SLionel Sambuc 
349433d6423SLionel Sambuc   	return OK;
350433d6423SLionel Sambuc       }
351433d6423SLionel Sambuc 
352433d6423SLionel Sambuc       if (sysgetenv.keylen == 0) {	/* copy all parameters */
353433d6423SLionel Sambuc           val_start = monitor_params;
354433d6423SLionel Sambuc           val_len = sizeof(monitor_params);
355433d6423SLionel Sambuc       }
356433d6423SLionel Sambuc       else {				/* lookup value for key */
357433d6423SLionel Sambuc       	  int p;
358433d6423SLionel Sambuc           /* Try to get a copy of the requested key. */
359433d6423SLionel Sambuc           if (sysgetenv.keylen > sizeof(search_key)) return(EINVAL);
360433d6423SLionel Sambuc           if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.key,
361433d6423SLionel Sambuc                   SELF, (vir_bytes) search_key, sysgetenv.keylen)) != OK)
362433d6423SLionel Sambuc               return(s);
363433d6423SLionel Sambuc 
364433d6423SLionel Sambuc           /* Make sure key is null-terminated and lookup value.
365433d6423SLionel Sambuc            * First check local overrides.
366433d6423SLionel Sambuc            */
367433d6423SLionel Sambuc           search_key[sysgetenv.keylen-1]= '\0';
368433d6423SLionel Sambuc           for(p = 0; p < local_params; p++) {
369433d6423SLionel Sambuc           	if (!strcmp(search_key, local_param_overrides[p].name)) {
370433d6423SLionel Sambuc           		val_start = local_param_overrides[p].value;
371433d6423SLionel Sambuc           		break;
372433d6423SLionel Sambuc           	}
373433d6423SLionel Sambuc           }
374433d6423SLionel Sambuc           if (p >= local_params && (val_start = find_param(search_key)) == NULL)
375433d6423SLionel Sambuc                return(ESRCH);
376433d6423SLionel Sambuc           val_len = strlen(val_start) + 1;
377433d6423SLionel Sambuc       }
378433d6423SLionel Sambuc 
379433d6423SLionel Sambuc       /* See if it fits in the client's buffer. */
380433d6423SLionel Sambuc       if (val_len > sysgetenv.vallen)
381433d6423SLionel Sambuc       	return E2BIG;
382433d6423SLionel Sambuc 
383433d6423SLionel Sambuc       /* Value found, make the actual copy (as far as possible). */
384433d6423SLionel Sambuc       copy_len = MIN(val_len, sysgetenv.vallen);
385433d6423SLionel Sambuc       if ((s=sys_datacopy(SELF, (vir_bytes) val_start,
386433d6423SLionel Sambuc               who_e, (vir_bytes) sysgetenv.val, copy_len)) != OK)
387433d6423SLionel Sambuc           return(s);
388433d6423SLionel Sambuc 
389433d6423SLionel Sambuc       return OK;
390433d6423SLionel Sambuc   }
391433d6423SLionel Sambuc 
392433d6423SLionel Sambuc   default:
393433d6423SLionel Sambuc 	return(EINVAL);
394433d6423SLionel Sambuc   }
395433d6423SLionel Sambuc }
396433d6423SLionel Sambuc 
397433d6423SLionel Sambuc /*===========================================================================*
398433d6423SLionel Sambuc  *				do_getrusage				     *
399433d6423SLionel Sambuc  *===========================================================================*/
400bc2d75faSDavid van Moolenbroek int
do_getrusage(void)401bc2d75faSDavid van Moolenbroek do_getrusage(void)
402433d6423SLionel Sambuc {
403bc2d75faSDavid van Moolenbroek 	clock_t user_time, sys_time;
404433d6423SLionel Sambuc 	struct rusage r_usage;
405bc2d75faSDavid van Moolenbroek 	int r, children;
406bc2d75faSDavid van Moolenbroek 
407433d6423SLionel Sambuc 	if (m_in.m_lc_pm_rusage.who != RUSAGE_SELF &&
408433d6423SLionel Sambuc 	    m_in.m_lc_pm_rusage.who != RUSAGE_CHILDREN)
409433d6423SLionel Sambuc 		return EINVAL;
410433d6423SLionel Sambuc 
411bc2d75faSDavid van Moolenbroek 	/*
412bc2d75faSDavid van Moolenbroek 	 * TODO: first relay the call to VFS.  As is, VFS does not have any
413bc2d75faSDavid van Moolenbroek 	 * fields it can fill with meaningful values, but this may change in
414bc2d75faSDavid van Moolenbroek 	 * the future.  In that case, PM would first have to use the tell_vfs()
415bc2d75faSDavid van Moolenbroek 	 * system to get those values from VFS, and do the rest here upon
416bc2d75faSDavid van Moolenbroek 	 * getting the response.
417bc2d75faSDavid van Moolenbroek 	 */
418bc2d75faSDavid van Moolenbroek 
419bc2d75faSDavid van Moolenbroek 	memset(&r_usage, 0, sizeof(r_usage));
420bc2d75faSDavid van Moolenbroek 
421bc2d75faSDavid van Moolenbroek 	children = (m_in.m_lc_pm_rusage.who == RUSAGE_CHILDREN);
422bc2d75faSDavid van Moolenbroek 
423bc2d75faSDavid van Moolenbroek 	/*
424bc2d75faSDavid van Moolenbroek 	 * Get system times.  For RUSAGE_SELF, get the times for the calling
425bc2d75faSDavid van Moolenbroek 	 * process from the kernel.  For RUSAGE_CHILDREN, we already have the
426bc2d75faSDavid van Moolenbroek 	 * values we should return right here.
427bc2d75faSDavid van Moolenbroek 	 */
428bc2d75faSDavid van Moolenbroek 	if (!children) {
429bc2d75faSDavid van Moolenbroek 		if ((r = sys_times(who_e, &user_time, &sys_time, NULL,
430bc2d75faSDavid van Moolenbroek 		    NULL)) != OK)
431bc2d75faSDavid van Moolenbroek 			return r;
432bc2d75faSDavid van Moolenbroek 	} else {
433bc2d75faSDavid van Moolenbroek 		user_time = mp->mp_child_utime;
434bc2d75faSDavid van Moolenbroek 		sys_time = mp->mp_child_stime;
435433d6423SLionel Sambuc 	}
436433d6423SLionel Sambuc 
437bc2d75faSDavid van Moolenbroek 	/* In both cases, convert from clock ticks to microseconds. */
43829346ab0SDavid van Moolenbroek 	set_rusage_times(&r_usage, user_time, sys_time);
439bc2d75faSDavid van Moolenbroek 
440bc2d75faSDavid van Moolenbroek 	/* Get additional fields from VM. */
441bc2d75faSDavid van Moolenbroek 	if ((r = vm_getrusage(who_e, &r_usage, children)) != OK)
442bc2d75faSDavid van Moolenbroek 		return r;
443bc2d75faSDavid van Moolenbroek 
444bc2d75faSDavid van Moolenbroek 	/* Finally copy the structure to the caller. */
445433d6423SLionel Sambuc 	return sys_datacopy(SELF, (vir_bytes)&r_usage, who_e,
446433d6423SLionel Sambuc 	    m_in.m_lc_pm_rusage.addr, (vir_bytes)sizeof(r_usage));
447433d6423SLionel Sambuc }
448