xref: /minix3/minix/servers/pm/misc.c (revision ea36b58e62e0b8cfeae6104541fe569eda34d629)
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
10433d6423SLionel Sambuc  */
11433d6423SLionel Sambuc 
12433d6423SLionel Sambuc #include "pm.h"
13433d6423SLionel Sambuc #include <minix/callnr.h>
14433d6423SLionel Sambuc #include <signal.h>
15433d6423SLionel Sambuc #include <sys/svrctl.h>
16433d6423SLionel Sambuc #include <sys/reboot.h>
17433d6423SLionel Sambuc #include <sys/resource.h>
18433d6423SLionel Sambuc #include <sys/utsname.h>
19433d6423SLionel Sambuc #include <minix/com.h>
20433d6423SLionel Sambuc #include <minix/config.h>
21433d6423SLionel Sambuc #include <minix/sysinfo.h>
22433d6423SLionel Sambuc #include <minix/type.h>
23433d6423SLionel Sambuc #include <minix/ds.h>
24433d6423SLionel Sambuc #include <machine/archtypes.h>
25433d6423SLionel Sambuc #include <lib.h>
26433d6423SLionel Sambuc #include <assert.h>
27433d6423SLionel Sambuc #include "mproc.h"
28433d6423SLionel Sambuc #include "kernel/proc.h"
29433d6423SLionel Sambuc 
30433d6423SLionel Sambuc struct utsname uts_val = {
31433d6423SLionel Sambuc   OS_NAME,		/* system name */
32433d6423SLionel Sambuc   "noname",		/* node/network name */
33433d6423SLionel Sambuc   OS_RELEASE,		/* O.S. release (e.g. 3.3.0) */
34433d6423SLionel Sambuc   OS_VERSION,		/* O.S. version (e.g. Minix 3.3.0 (GENERIC)) */
35433d6423SLionel Sambuc #if defined(__i386__)
36*ea36b58eSLionel Sambuc   "i386",		/* machine (cpu) type */
37433d6423SLionel Sambuc   "i386",		/* architecture */
38433d6423SLionel Sambuc #elif defined(__arm__)
39*ea36b58eSLionel Sambuc   "arm",		/* machine (cpu) type */
40433d6423SLionel Sambuc   "arm",		/* architecture */
41433d6423SLionel Sambuc #else
42433d6423SLionel Sambuc #error			/* oops, no 'uname -mk' */
43433d6423SLionel Sambuc #endif
44433d6423SLionel Sambuc };
45433d6423SLionel Sambuc 
46433d6423SLionel Sambuc static char *uts_tbl[] = {
47433d6423SLionel Sambuc   uts_val.arch,
48433d6423SLionel Sambuc   NULL,			/* No kernel architecture */
49433d6423SLionel Sambuc   uts_val.machine,
50433d6423SLionel Sambuc   NULL,			/* No hostname */
51433d6423SLionel Sambuc   uts_val.nodename,
52433d6423SLionel Sambuc   uts_val.release,
53433d6423SLionel Sambuc   uts_val.version,
54433d6423SLionel Sambuc   uts_val.sysname,
55433d6423SLionel Sambuc   NULL,			/* No bus */			/* No bus */
56433d6423SLionel Sambuc };
57433d6423SLionel Sambuc 
58433d6423SLionel Sambuc #if ENABLE_SYSCALL_STATS
59433d6423SLionel Sambuc unsigned long calls_stats[NR_PM_CALLS];
60433d6423SLionel Sambuc #endif
61433d6423SLionel Sambuc 
62433d6423SLionel Sambuc /*===========================================================================*
63433d6423SLionel Sambuc  *				do_sysuname				     *
64433d6423SLionel Sambuc  *===========================================================================*/
65433d6423SLionel Sambuc int do_sysuname()
66433d6423SLionel Sambuc {
67433d6423SLionel Sambuc /* Set or get uname strings. */
68433d6423SLionel Sambuc   int r;
69433d6423SLionel Sambuc   size_t n;
70433d6423SLionel Sambuc   char *string;
71433d6423SLionel Sambuc #if 0 /* for updates */
72433d6423SLionel Sambuc   char tmp[sizeof(uts_val.nodename)];
73433d6423SLionel Sambuc   static short sizes[] = {
74433d6423SLionel Sambuc 	0,	/* arch, (0 = read-only) */
75433d6423SLionel Sambuc 	0,	/* kernel */
76433d6423SLionel Sambuc 	0,	/* machine */
77433d6423SLionel Sambuc 	0,	/* sizeof(uts_val.hostname), */
78433d6423SLionel Sambuc 	sizeof(uts_val.nodename),
79433d6423SLionel Sambuc 	0,	/* release */
80433d6423SLionel Sambuc 	0,	/* version */
81433d6423SLionel Sambuc 	0,	/* sysname */
82433d6423SLionel Sambuc   };
83433d6423SLionel Sambuc #endif
84433d6423SLionel Sambuc 
85433d6423SLionel Sambuc   if (m_in.m_lc_pm_sysuname.field >= _UTS_MAX) return(EINVAL);
86433d6423SLionel Sambuc 
87433d6423SLionel Sambuc   string = uts_tbl[m_in.m_lc_pm_sysuname.field];
88433d6423SLionel Sambuc   if (string == NULL)
89433d6423SLionel Sambuc 	return EINVAL;	/* Unsupported field */
90433d6423SLionel Sambuc 
91433d6423SLionel Sambuc   switch (m_in.m_lc_pm_sysuname.req) {
92433d6423SLionel Sambuc   case _UTS_GET:
93433d6423SLionel Sambuc 	/* Copy an uname string to the user. */
94433d6423SLionel Sambuc 	n = strlen(string) + 1;
95433d6423SLionel Sambuc 	if (n > m_in.m_lc_pm_sysuname.len) n = m_in.m_lc_pm_sysuname.len;
96433d6423SLionel Sambuc 	r = sys_datacopy(SELF, (vir_bytes)string, mp->mp_endpoint,
97433d6423SLionel Sambuc 		m_in.m_lc_pm_sysuname.value, (phys_bytes)n);
98433d6423SLionel Sambuc 	if (r < 0) return(r);
99433d6423SLionel Sambuc 	break;
100433d6423SLionel Sambuc 
101433d6423SLionel Sambuc #if 0	/* no updates yet */
102433d6423SLionel Sambuc   case _UTS_SET:
103433d6423SLionel Sambuc 	/* Set an uname string, needs root power. */
104433d6423SLionel Sambuc 	len = sizes[m_in.m_lc_pm_sysuname.field];
105433d6423SLionel Sambuc 	if (mp->mp_effuid != 0 || len == 0) return(EPERM);
106433d6423SLionel Sambuc 	n = len < m_in.m_lc_pm_sysuname.len ? len : m_in.m_lc_pm_sysuname.len;
107433d6423SLionel Sambuc 	if (n <= 0) return(EINVAL);
108433d6423SLionel Sambuc 	r = sys_datacopy(mp->mp_endpoint, m_in.m_lc_pm_sysuname.value, SELF,
109433d6423SLionel Sambuc 		(phys_bytes)tmp, (phys_bytes)n);
110433d6423SLionel Sambuc 	if (r < 0) return(r);
111433d6423SLionel Sambuc 	tmp[n-1] = 0;
112433d6423SLionel Sambuc 	strcpy(string, tmp);
113433d6423SLionel Sambuc 	break;
114433d6423SLionel Sambuc #endif
115433d6423SLionel Sambuc 
116433d6423SLionel Sambuc   default:
117433d6423SLionel Sambuc 	return(EINVAL);
118433d6423SLionel Sambuc   }
119433d6423SLionel Sambuc   /* Return the number of bytes moved. */
120433d6423SLionel Sambuc   return(n);
121433d6423SLionel Sambuc }
122433d6423SLionel Sambuc 
123433d6423SLionel Sambuc 
124433d6423SLionel Sambuc /*===========================================================================*
125433d6423SLionel Sambuc  *				do_getsysinfo			       	     *
126433d6423SLionel Sambuc  *===========================================================================*/
127433d6423SLionel Sambuc int do_getsysinfo()
128433d6423SLionel Sambuc {
129433d6423SLionel Sambuc   vir_bytes src_addr, dst_addr;
130433d6423SLionel Sambuc   size_t len;
131433d6423SLionel Sambuc 
132433d6423SLionel Sambuc   /* This call leaks important information. In the future, requests from
133433d6423SLionel Sambuc    * non-system processes should be denied.
134433d6423SLionel Sambuc    */
135433d6423SLionel Sambuc   if (mp->mp_effuid != 0)
136433d6423SLionel Sambuc   {
137433d6423SLionel Sambuc 	printf("PM: unauthorized call of do_getsysinfo by proc %d '%s'\n",
138433d6423SLionel Sambuc 		mp->mp_endpoint, mp->mp_name);
139433d6423SLionel Sambuc 	sys_diagctl_stacktrace(mp->mp_endpoint);
140433d6423SLionel Sambuc 	return EPERM;
141433d6423SLionel Sambuc   }
142433d6423SLionel Sambuc 
143433d6423SLionel Sambuc   switch(m_in.m_lsys_getsysinfo.what) {
144433d6423SLionel Sambuc   case SI_PROC_TAB:			/* copy entire process table */
145433d6423SLionel Sambuc         src_addr = (vir_bytes) mproc;
146433d6423SLionel Sambuc         len = sizeof(struct mproc) * NR_PROCS;
147433d6423SLionel Sambuc         break;
148433d6423SLionel Sambuc #if ENABLE_SYSCALL_STATS
149433d6423SLionel Sambuc   case SI_CALL_STATS:
150433d6423SLionel Sambuc   	src_addr = (vir_bytes) calls_stats;
151433d6423SLionel Sambuc   	len = sizeof(calls_stats);
152433d6423SLionel Sambuc   	break;
153433d6423SLionel Sambuc #endif
154433d6423SLionel Sambuc   default:
155433d6423SLionel Sambuc   	return(EINVAL);
156433d6423SLionel Sambuc   }
157433d6423SLionel Sambuc 
158433d6423SLionel Sambuc   if (len != m_in.m_lsys_getsysinfo.size)
159433d6423SLionel Sambuc 	return(EINVAL);
160433d6423SLionel Sambuc 
161433d6423SLionel Sambuc   dst_addr = m_in.m_lsys_getsysinfo.where;
162433d6423SLionel Sambuc   return sys_datacopy(SELF, src_addr, who_e, dst_addr, len);
163433d6423SLionel Sambuc }
164433d6423SLionel Sambuc 
165433d6423SLionel Sambuc /*===========================================================================*
166433d6423SLionel Sambuc  *				do_getprocnr			             *
167433d6423SLionel Sambuc  *===========================================================================*/
168433d6423SLionel Sambuc int do_getprocnr(void)
169433d6423SLionel Sambuc {
170433d6423SLionel Sambuc   register struct mproc *rmp;
171433d6423SLionel Sambuc 
172433d6423SLionel Sambuc   /* This check should be replaced by per-call ACL checks. */
173433d6423SLionel Sambuc   if (who_e != RS_PROC_NR) {
174433d6423SLionel Sambuc 	printf("PM: unauthorized call of do_getprocnr by %d\n", who_e);
175433d6423SLionel Sambuc 	return EPERM;
176433d6423SLionel Sambuc   }
177433d6423SLionel Sambuc 
178433d6423SLionel Sambuc   if ((rmp = find_proc(m_in.m_lsys_pm_getprocnr.pid)) == NULL)
179433d6423SLionel Sambuc 	return(ESRCH);
180433d6423SLionel Sambuc 
181433d6423SLionel Sambuc   mp->mp_reply.m_pm_lsys_getprocnr.endpt = rmp->mp_endpoint;
182433d6423SLionel Sambuc   return(OK);
183433d6423SLionel Sambuc }
184433d6423SLionel Sambuc 
185433d6423SLionel Sambuc /*===========================================================================*
186433d6423SLionel Sambuc  *				do_getepinfo			             *
187433d6423SLionel Sambuc  *===========================================================================*/
188433d6423SLionel Sambuc int do_getepinfo(void)
189433d6423SLionel Sambuc {
190433d6423SLionel Sambuc   struct mproc *rmp;
191433d6423SLionel Sambuc   endpoint_t ep;
192433d6423SLionel Sambuc   int slot;
193433d6423SLionel Sambuc 
194433d6423SLionel Sambuc   ep = m_in.m_lsys_pm_getepinfo.endpt;
195433d6423SLionel Sambuc   if (pm_isokendpt(ep, &slot) != OK)
196433d6423SLionel Sambuc 	return(ESRCH);
197433d6423SLionel Sambuc 
198433d6423SLionel Sambuc   rmp = &mproc[slot];
199433d6423SLionel Sambuc   mp->mp_reply.m_pm_lsys_getepinfo.uid = rmp->mp_effuid;
200433d6423SLionel Sambuc   mp->mp_reply.m_pm_lsys_getepinfo.gid = rmp->mp_effgid;
201433d6423SLionel Sambuc   return(rmp->mp_pid);
202433d6423SLionel Sambuc }
203433d6423SLionel Sambuc 
204433d6423SLionel Sambuc /*===========================================================================*
205433d6423SLionel Sambuc  *				do_reboot				     *
206433d6423SLionel Sambuc  *===========================================================================*/
207433d6423SLionel Sambuc int do_reboot()
208433d6423SLionel Sambuc {
209433d6423SLionel Sambuc   message m;
210433d6423SLionel Sambuc 
211433d6423SLionel Sambuc   /* Check permission to abort the system. */
212433d6423SLionel Sambuc   if (mp->mp_effuid != SUPER_USER) return(EPERM);
213433d6423SLionel Sambuc 
214433d6423SLionel Sambuc   /* See how the system should be aborted. */
215433d6423SLionel Sambuc   abort_flag = m_in.m_lc_pm_reboot.how;
216433d6423SLionel Sambuc 
217433d6423SLionel Sambuc   /* notify readclock (some arm systems power off via RTC alarms) */
218433d6423SLionel Sambuc   if (abort_flag & RB_POWERDOWN) {
219433d6423SLionel Sambuc 	endpoint_t readclock_ep;
220433d6423SLionel Sambuc 	if (ds_retrieve_label_endpt("readclock.drv", &readclock_ep) == OK) {
221433d6423SLionel Sambuc 		message m; /* no params to set, nothing we can do if it fails */
222433d6423SLionel Sambuc 		_taskcall(readclock_ep, RTCDEV_PWR_OFF, &m);
223433d6423SLionel Sambuc 	}
224433d6423SLionel Sambuc   }
225433d6423SLionel Sambuc 
226433d6423SLionel Sambuc   /* Order matters here. When VFS is told to reboot, it exits all its
227433d6423SLionel Sambuc    * processes, and then would be confused if they're exited again by
228433d6423SLionel Sambuc    * SIGKILL. So first kill, then reboot.
229433d6423SLionel Sambuc    */
230433d6423SLionel Sambuc 
231433d6423SLionel Sambuc   check_sig(-1, SIGKILL, FALSE /* ksig*/); /* kill all users except init */
232433d6423SLionel Sambuc   sys_stop(INIT_PROC_NR);		   /* stop init, but keep it around */
233433d6423SLionel Sambuc 
234433d6423SLionel Sambuc   /* Tell VFS to reboot */
235433d6423SLionel Sambuc   memset(&m, 0, sizeof(m));
236433d6423SLionel Sambuc   m.m_type = VFS_PM_REBOOT;
237433d6423SLionel Sambuc 
238433d6423SLionel Sambuc   tell_vfs(&mproc[VFS_PROC_NR], &m);
239433d6423SLionel Sambuc 
240433d6423SLionel Sambuc   return(SUSPEND);			/* don't reply to caller */
241433d6423SLionel Sambuc }
242433d6423SLionel Sambuc 
243433d6423SLionel Sambuc /*===========================================================================*
244433d6423SLionel Sambuc  *				do_getsetpriority			     *
245433d6423SLionel Sambuc  *===========================================================================*/
246433d6423SLionel Sambuc int do_getsetpriority()
247433d6423SLionel Sambuc {
248433d6423SLionel Sambuc 	int r, arg_which, arg_who, arg_pri;
249433d6423SLionel Sambuc 	struct mproc *rmp;
250433d6423SLionel Sambuc 
251433d6423SLionel Sambuc 	arg_which = m_in.m_lc_pm_priority.which;
252433d6423SLionel Sambuc 	arg_who = m_in.m_lc_pm_priority.who;
253433d6423SLionel Sambuc 	arg_pri = m_in.m_lc_pm_priority.prio;	/* for SETPRIORITY */
254433d6423SLionel Sambuc 
255433d6423SLionel Sambuc 	/* Code common to GETPRIORITY and SETPRIORITY. */
256433d6423SLionel Sambuc 
257433d6423SLionel Sambuc 	/* Only support PRIO_PROCESS for now. */
258433d6423SLionel Sambuc 	if (arg_which != PRIO_PROCESS)
259433d6423SLionel Sambuc 		return(EINVAL);
260433d6423SLionel Sambuc 
261433d6423SLionel Sambuc 	if (arg_who == 0)
262433d6423SLionel Sambuc 		rmp = mp;
263433d6423SLionel Sambuc 	else
264433d6423SLionel Sambuc 		if ((rmp = find_proc(arg_who)) == NULL)
265433d6423SLionel Sambuc 			return(ESRCH);
266433d6423SLionel Sambuc 
267433d6423SLionel Sambuc 	if (mp->mp_effuid != SUPER_USER &&
268433d6423SLionel Sambuc 	   mp->mp_effuid != rmp->mp_effuid && mp->mp_effuid != rmp->mp_realuid)
269433d6423SLionel Sambuc 		return EPERM;
270433d6423SLionel Sambuc 
271433d6423SLionel Sambuc 	/* If GET, that's it. */
272433d6423SLionel Sambuc 	if (call_nr == PM_GETPRIORITY) {
273433d6423SLionel Sambuc 		return(rmp->mp_nice - PRIO_MIN);
274433d6423SLionel Sambuc 	}
275433d6423SLionel Sambuc 
276433d6423SLionel Sambuc 	/* Only root is allowed to reduce the nice level. */
277433d6423SLionel Sambuc 	if (rmp->mp_nice > arg_pri && mp->mp_effuid != SUPER_USER)
278433d6423SLionel Sambuc 		return(EACCES);
279433d6423SLionel Sambuc 
280433d6423SLionel Sambuc 	/* We're SET, and it's allowed.
281433d6423SLionel Sambuc 	 *
282433d6423SLionel Sambuc 	 * The value passed in is currently between PRIO_MIN and PRIO_MAX.
283433d6423SLionel Sambuc 	 * We have to scale this between MIN_USER_Q and MAX_USER_Q to match
284433d6423SLionel Sambuc 	 * the kernel's scheduling queues.
285433d6423SLionel Sambuc 	 */
286433d6423SLionel Sambuc 
287433d6423SLionel Sambuc 	if ((r = sched_nice(rmp, arg_pri)) != OK) {
288433d6423SLionel Sambuc 		return r;
289433d6423SLionel Sambuc 	}
290433d6423SLionel Sambuc 
291433d6423SLionel Sambuc 	rmp->mp_nice = arg_pri;
292433d6423SLionel Sambuc 	return(OK);
293433d6423SLionel Sambuc }
294433d6423SLionel Sambuc 
295433d6423SLionel Sambuc /*===========================================================================*
296433d6423SLionel Sambuc  *				do_svrctl				     *
297433d6423SLionel Sambuc  *===========================================================================*/
298433d6423SLionel Sambuc int do_svrctl()
299433d6423SLionel Sambuc {
300433d6423SLionel Sambuc   int s, req;
301433d6423SLionel Sambuc   vir_bytes ptr;
302433d6423SLionel Sambuc #define MAX_LOCAL_PARAMS 2
303433d6423SLionel Sambuc   static struct {
304433d6423SLionel Sambuc   	char name[30];
305433d6423SLionel Sambuc   	char value[30];
306433d6423SLionel Sambuc   } local_param_overrides[MAX_LOCAL_PARAMS];
307433d6423SLionel Sambuc   static int local_params = 0;
308433d6423SLionel Sambuc 
309433d6423SLionel Sambuc   req = m_in.m_lsys_svrctl.request;
310433d6423SLionel Sambuc   ptr = m_in.m_lsys_svrctl.arg;
311433d6423SLionel Sambuc 
312433d6423SLionel Sambuc   /* Is the request indeed for the PM? */
313433d6423SLionel Sambuc   if (((req >> 8) & 0xFF) != 'M') return(EINVAL);
314433d6423SLionel Sambuc 
315433d6423SLionel Sambuc   /* Control operations local to the PM. */
316433d6423SLionel Sambuc   switch(req) {
317433d6423SLionel Sambuc   case PMSETPARAM:
318433d6423SLionel Sambuc   case PMGETPARAM: {
319433d6423SLionel Sambuc       struct sysgetenv sysgetenv;
320433d6423SLionel Sambuc       char search_key[64];
321433d6423SLionel Sambuc       char *val_start;
322433d6423SLionel Sambuc       size_t val_len;
323433d6423SLionel Sambuc       size_t copy_len;
324433d6423SLionel Sambuc 
325433d6423SLionel Sambuc       /* Copy sysgetenv structure to PM. */
326433d6423SLionel Sambuc       if (sys_datacopy(who_e, ptr, SELF, (vir_bytes) &sysgetenv,
327433d6423SLionel Sambuc               sizeof(sysgetenv)) != OK) return(EFAULT);
328433d6423SLionel Sambuc 
329433d6423SLionel Sambuc       /* Set a param override? */
330433d6423SLionel Sambuc       if (req == PMSETPARAM) {
331433d6423SLionel Sambuc   	if (local_params >= MAX_LOCAL_PARAMS) return ENOSPC;
332433d6423SLionel Sambuc   	if (sysgetenv.keylen <= 0
333433d6423SLionel Sambuc   	 || sysgetenv.keylen >=
334433d6423SLionel Sambuc   	 	 sizeof(local_param_overrides[local_params].name)
335433d6423SLionel Sambuc   	 || sysgetenv.vallen <= 0
336433d6423SLionel Sambuc   	 || sysgetenv.vallen >=
337433d6423SLionel Sambuc   	 	 sizeof(local_param_overrides[local_params].value))
338433d6423SLionel Sambuc   		return EINVAL;
339433d6423SLionel Sambuc 
340433d6423SLionel Sambuc           if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.key,
341433d6423SLionel Sambuc             SELF, (vir_bytes) local_param_overrides[local_params].name,
342433d6423SLionel Sambuc                sysgetenv.keylen)) != OK)
343433d6423SLionel Sambuc                	return s;
344433d6423SLionel Sambuc           if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.val,
345433d6423SLionel Sambuc             SELF, (vir_bytes) local_param_overrides[local_params].value,
346433d6423SLionel Sambuc               sysgetenv.vallen)) != OK)
347433d6423SLionel Sambuc                	return s;
348433d6423SLionel Sambuc             local_param_overrides[local_params].name[sysgetenv.keylen] = '\0';
349433d6423SLionel Sambuc             local_param_overrides[local_params].value[sysgetenv.vallen] = '\0';
350433d6423SLionel Sambuc 
351433d6423SLionel Sambuc   	local_params++;
352433d6423SLionel Sambuc 
353433d6423SLionel Sambuc   	return OK;
354433d6423SLionel Sambuc       }
355433d6423SLionel Sambuc 
356433d6423SLionel Sambuc       if (sysgetenv.keylen == 0) {	/* copy all parameters */
357433d6423SLionel Sambuc           val_start = monitor_params;
358433d6423SLionel Sambuc           val_len = sizeof(monitor_params);
359433d6423SLionel Sambuc       }
360433d6423SLionel Sambuc       else {				/* lookup value for key */
361433d6423SLionel Sambuc       	  int p;
362433d6423SLionel Sambuc           /* Try to get a copy of the requested key. */
363433d6423SLionel Sambuc           if (sysgetenv.keylen > sizeof(search_key)) return(EINVAL);
364433d6423SLionel Sambuc           if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.key,
365433d6423SLionel Sambuc                   SELF, (vir_bytes) search_key, sysgetenv.keylen)) != OK)
366433d6423SLionel Sambuc               return(s);
367433d6423SLionel Sambuc 
368433d6423SLionel Sambuc           /* Make sure key is null-terminated and lookup value.
369433d6423SLionel Sambuc            * First check local overrides.
370433d6423SLionel Sambuc            */
371433d6423SLionel Sambuc           search_key[sysgetenv.keylen-1]= '\0';
372433d6423SLionel Sambuc           for(p = 0; p < local_params; p++) {
373433d6423SLionel Sambuc           	if (!strcmp(search_key, local_param_overrides[p].name)) {
374433d6423SLionel Sambuc           		val_start = local_param_overrides[p].value;
375433d6423SLionel Sambuc           		break;
376433d6423SLionel Sambuc           	}
377433d6423SLionel Sambuc           }
378433d6423SLionel Sambuc           if (p >= local_params && (val_start = find_param(search_key)) == NULL)
379433d6423SLionel Sambuc                return(ESRCH);
380433d6423SLionel Sambuc           val_len = strlen(val_start) + 1;
381433d6423SLionel Sambuc       }
382433d6423SLionel Sambuc 
383433d6423SLionel Sambuc       /* See if it fits in the client's buffer. */
384433d6423SLionel Sambuc       if (val_len > sysgetenv.vallen)
385433d6423SLionel Sambuc       	return E2BIG;
386433d6423SLionel Sambuc 
387433d6423SLionel Sambuc       /* Value found, make the actual copy (as far as possible). */
388433d6423SLionel Sambuc       copy_len = MIN(val_len, sysgetenv.vallen);
389433d6423SLionel Sambuc       if ((s=sys_datacopy(SELF, (vir_bytes) val_start,
390433d6423SLionel Sambuc               who_e, (vir_bytes) sysgetenv.val, copy_len)) != OK)
391433d6423SLionel Sambuc           return(s);
392433d6423SLionel Sambuc 
393433d6423SLionel Sambuc       return OK;
394433d6423SLionel Sambuc   }
395433d6423SLionel Sambuc 
396433d6423SLionel Sambuc   default:
397433d6423SLionel Sambuc 	return(EINVAL);
398433d6423SLionel Sambuc   }
399433d6423SLionel Sambuc }
400433d6423SLionel Sambuc 
401433d6423SLionel Sambuc /*===========================================================================*
402433d6423SLionel Sambuc  *				do_getrusage				     *
403433d6423SLionel Sambuc  *===========================================================================*/
404433d6423SLionel Sambuc int do_getrusage()
405433d6423SLionel Sambuc {
406433d6423SLionel Sambuc 	int res = 0;
407433d6423SLionel Sambuc 	clock_t user_time = 0;
408433d6423SLionel Sambuc 	clock_t sys_time = 0;
409433d6423SLionel Sambuc 	struct rusage r_usage;
410433d6423SLionel Sambuc 	u64_t usec;
411433d6423SLionel Sambuc 	if (m_in.m_lc_pm_rusage.who != RUSAGE_SELF &&
412433d6423SLionel Sambuc 		m_in.m_lc_pm_rusage.who != RUSAGE_CHILDREN)
413433d6423SLionel Sambuc 		return EINVAL;
414433d6423SLionel Sambuc 	if ((res = sys_getrusage(&r_usage, who_e)) < 0)
415433d6423SLionel Sambuc 		return res;
416433d6423SLionel Sambuc 
417433d6423SLionel Sambuc 	if (m_in.m_lc_pm_rusage.who == RUSAGE_CHILDREN) {
418433d6423SLionel Sambuc 		usec = mp->mp_child_utime * 1000000 / sys_hz();
419433d6423SLionel Sambuc 		r_usage.ru_utime.tv_sec = usec / 1000000;
420433d6423SLionel Sambuc 		r_usage.ru_utime.tv_usec = usec % 1000000;
421433d6423SLionel Sambuc 		usec = mp->mp_child_stime * 1000000 / sys_hz();
422433d6423SLionel Sambuc 		r_usage.ru_stime.tv_sec = usec / 1000000;
423433d6423SLionel Sambuc 		r_usage.ru_stime.tv_usec = usec % 1000000;
424433d6423SLionel Sambuc 	}
425433d6423SLionel Sambuc 
426433d6423SLionel Sambuc 	return sys_datacopy(SELF, (vir_bytes)&r_usage, who_e,
427433d6423SLionel Sambuc 		m_in.m_lc_pm_rusage.addr, (vir_bytes) sizeof(r_usage));
428433d6423SLionel Sambuc }
429