Drop main() prototype. Syncs with NetBSD-8
[minix.git] / minix / servers / pm / misc.c
blob8e11e08c1ad7766f9206b94bd8b0f3a113da8a47
1 /* Miscellaneous system calls. Author: Kees J. Bot
2 * 31 Mar 2000
3 * The entry points into this file are:
4 * do_reboot: kill all processes, then reboot system
5 * do_getsysinfo: request copy of PM data structure (Jorrit N. Herder)
6 * do_getprocnr: lookup endpoint by process ID
7 * do_getepinfo: get the pid/uid/gid of a process given its endpoint
8 * do_getsetpriority: get/set process priority
9 * do_svrctl: process manager control
10 * do_getrusage: obtain process resource usage information
13 #include "pm.h"
14 #include <minix/callnr.h>
15 #include <signal.h>
16 #include <sys/svrctl.h>
17 #include <sys/reboot.h>
18 #include <sys/resource.h>
19 #include <sys/utsname.h>
20 #include <minix/com.h>
21 #include <minix/config.h>
22 #include <minix/sysinfo.h>
23 #include <minix/type.h>
24 #include <minix/ds.h>
25 #include <machine/archtypes.h>
26 #include <lib.h>
27 #include <assert.h>
28 #include "mproc.h"
29 #include "kernel/proc.h"
31 /* START OF COMPATIBILITY BLOCK */
32 struct utsname uts_val = {
33 OS_NAME, /* system name */
34 "noname", /* node/network name */
35 OS_RELEASE, /* O.S. release (e.g. 3.3.0) */
36 OS_VERSION, /* O.S. version (e.g. Minix 3.3.0 (GENERIC)) */
37 #if defined(__i386__)
38 "i386", /* machine (cpu) type */
39 #elif defined(__arm__)
40 "evbarm", /* machine (cpu) type */
41 #else
42 #error /* oops, no 'uname -mk' */
43 #endif
46 static char *uts_tbl[] = {
47 #if defined(__i386__)
48 "i386", /* architecture */
49 #elif defined(__arm__)
50 "evbarm", /* architecture */
51 #endif
52 NULL, /* No kernel architecture */
53 uts_val.machine,
54 NULL, /* No hostname */
55 uts_val.nodename,
56 uts_val.release,
57 uts_val.version,
58 uts_val.sysname,
59 NULL, /* No bus */ /* No bus */
61 /* END OF COMPATIBILITY BLOCK */
63 #if ENABLE_SYSCALL_STATS
64 unsigned long calls_stats[NR_PM_CALLS];
65 #endif
67 /* START OF COMPATIBILITY BLOCK */
68 /*===========================================================================*
69 * do_sysuname *
70 *===========================================================================*/
71 int
72 do_sysuname(void)
74 /* Set or get uname strings. */
75 int r;
76 size_t n;
77 char *string;
79 if (m_in.m_lc_pm_sysuname.field >= __arraycount(uts_tbl)) return(EINVAL);
81 string = uts_tbl[m_in.m_lc_pm_sysuname.field];
82 if (string == NULL)
83 return EINVAL; /* Unsupported field */
85 switch (m_in.m_lc_pm_sysuname.req) {
86 case 0:
87 /* Copy an uname string to the user. */
88 n = strlen(string) + 1;
89 if (n > m_in.m_lc_pm_sysuname.len) n = m_in.m_lc_pm_sysuname.len;
90 r = sys_datacopy(SELF, (vir_bytes)string, mp->mp_endpoint,
91 m_in.m_lc_pm_sysuname.value, (phys_bytes)n);
92 if (r < 0) return(r);
93 break;
95 default:
96 return(EINVAL);
98 /* Return the number of bytes moved. */
99 return(n);
101 /* END OF COMPATIBILITY BLOCK */
104 /*===========================================================================*
105 * do_getsysinfo *
106 *===========================================================================*/
108 do_getsysinfo(void)
110 vir_bytes src_addr, dst_addr;
111 size_t len;
113 /* This call leaks important information. In the future, requests from
114 * non-system processes should be denied.
116 if (mp->mp_effuid != 0)
118 printf("PM: unauthorized call of do_getsysinfo by proc %d '%s'\n",
119 mp->mp_endpoint, mp->mp_name);
120 sys_diagctl_stacktrace(mp->mp_endpoint);
121 return EPERM;
124 switch(m_in.m_lsys_getsysinfo.what) {
125 case SI_PROC_TAB: /* copy entire process table */
126 src_addr = (vir_bytes) mproc;
127 len = sizeof(struct mproc) * NR_PROCS;
128 break;
129 #if ENABLE_SYSCALL_STATS
130 case SI_CALL_STATS:
131 src_addr = (vir_bytes) calls_stats;
132 len = sizeof(calls_stats);
133 break;
134 #endif
135 default:
136 return(EINVAL);
139 if (len != m_in.m_lsys_getsysinfo.size)
140 return(EINVAL);
142 dst_addr = m_in.m_lsys_getsysinfo.where;
143 return sys_datacopy(SELF, src_addr, who_e, dst_addr, len);
146 /*===========================================================================*
147 * do_getprocnr *
148 *===========================================================================*/
149 int do_getprocnr(void)
151 register struct mproc *rmp;
153 /* This check should be replaced by per-call ACL checks. */
154 if (who_e != RS_PROC_NR) {
155 printf("PM: unauthorized call of do_getprocnr by %d\n", who_e);
156 return EPERM;
159 if ((rmp = find_proc(m_in.m_lsys_pm_getprocnr.pid)) == NULL)
160 return(ESRCH);
162 mp->mp_reply.m_pm_lsys_getprocnr.endpt = rmp->mp_endpoint;
163 return(OK);
166 /*===========================================================================*
167 * do_getepinfo *
168 *===========================================================================*/
169 int do_getepinfo(void)
171 struct mproc *rmp;
172 endpoint_t ep;
173 int r, slot, ngroups;
175 ep = m_in.m_lsys_pm_getepinfo.endpt;
176 if (pm_isokendpt(ep, &slot) != OK)
177 return(ESRCH);
178 rmp = &mproc[slot];
180 mp->mp_reply.m_pm_lsys_getepinfo.uid = rmp->mp_realuid;
181 mp->mp_reply.m_pm_lsys_getepinfo.euid = rmp->mp_effuid;
182 mp->mp_reply.m_pm_lsys_getepinfo.gid = rmp->mp_realgid;
183 mp->mp_reply.m_pm_lsys_getepinfo.egid = rmp->mp_effgid;
184 mp->mp_reply.m_pm_lsys_getepinfo.ngroups = ngroups = rmp->mp_ngroups;
185 if (ngroups > m_in.m_lsys_pm_getepinfo.ngroups)
186 ngroups = m_in.m_lsys_pm_getepinfo.ngroups;
187 if (ngroups > 0) {
188 if ((r = sys_datacopy(SELF, (vir_bytes)rmp->mp_sgroups, who_e,
189 m_in.m_lsys_pm_getepinfo.groups, ngroups * sizeof(gid_t))) != OK)
190 return(r);
192 return(rmp->mp_pid);
195 /*===========================================================================*
196 * do_reboot *
197 *===========================================================================*/
199 do_reboot(void)
201 message m;
203 /* Check permission to abort the system. */
204 if (mp->mp_effuid != SUPER_USER) return(EPERM);
206 /* See how the system should be aborted. */
207 abort_flag = m_in.m_lc_pm_reboot.how;
209 /* notify readclock (some arm systems power off via RTC alarms) */
210 if (abort_flag & RB_POWERDOWN) {
211 endpoint_t readclock_ep;
212 if (ds_retrieve_label_endpt("readclock.drv", &readclock_ep) == OK) {
213 message m; /* no params to set, nothing we can do if it fails */
214 _taskcall(readclock_ep, RTCDEV_PWR_OFF, &m);
218 /* Order matters here. When VFS is told to reboot, it exits all its
219 * processes, and then would be confused if they're exited again by
220 * SIGKILL. So first kill, then reboot.
223 check_sig(-1, SIGKILL, FALSE /* ksig*/); /* kill all users except init */
224 sys_stop(INIT_PROC_NR); /* stop init, but keep it around */
226 /* Tell VFS to reboot */
227 memset(&m, 0, sizeof(m));
228 m.m_type = VFS_PM_REBOOT;
230 tell_vfs(&mproc[VFS_PROC_NR], &m);
232 return(SUSPEND); /* don't reply to caller */
235 /*===========================================================================*
236 * do_getsetpriority *
237 *===========================================================================*/
239 do_getsetpriority(void)
241 int r, arg_which, arg_who, arg_pri;
242 struct mproc *rmp;
244 arg_which = m_in.m_lc_pm_priority.which;
245 arg_who = m_in.m_lc_pm_priority.who;
246 arg_pri = m_in.m_lc_pm_priority.prio; /* for SETPRIORITY */
248 /* Code common to GETPRIORITY and SETPRIORITY. */
250 /* Only support PRIO_PROCESS for now. */
251 if (arg_which != PRIO_PROCESS)
252 return(EINVAL);
254 if (arg_who == 0)
255 rmp = mp;
256 else
257 if ((rmp = find_proc(arg_who)) == NULL)
258 return(ESRCH);
260 if (mp->mp_effuid != SUPER_USER &&
261 mp->mp_effuid != rmp->mp_effuid && mp->mp_effuid != rmp->mp_realuid)
262 return EPERM;
264 /* If GET, that's it. */
265 if (call_nr == PM_GETPRIORITY) {
266 return(rmp->mp_nice - PRIO_MIN);
269 /* Only root is allowed to reduce the nice level. */
270 if (rmp->mp_nice > arg_pri && mp->mp_effuid != SUPER_USER)
271 return(EACCES);
273 /* We're SET, and it's allowed.
275 * The value passed in is currently between PRIO_MIN and PRIO_MAX.
276 * We have to scale this between MIN_USER_Q and MAX_USER_Q to match
277 * the kernel's scheduling queues.
280 if ((r = sched_nice(rmp, arg_pri)) != OK) {
281 return r;
284 rmp->mp_nice = arg_pri;
285 return(OK);
288 /*===========================================================================*
289 * do_svrctl *
290 *===========================================================================*/
291 int do_svrctl(void)
293 unsigned long req;
294 int s;
295 vir_bytes ptr;
296 #define MAX_LOCAL_PARAMS 2
297 static struct {
298 char name[30];
299 char value[30];
300 } local_param_overrides[MAX_LOCAL_PARAMS];
301 static int local_params = 0;
303 req = m_in.m_lc_svrctl.request;
304 ptr = m_in.m_lc_svrctl.arg;
306 /* Is the request indeed for the PM? ('M' is old and being phased out) */
307 if (IOCGROUP(req) != 'P' && IOCGROUP(req) != 'M') return(EINVAL);
309 /* Control operations local to the PM. */
310 switch(req) {
311 case OPMSETPARAM:
312 case OPMGETPARAM:
313 case PMSETPARAM:
314 case PMGETPARAM: {
315 struct sysgetenv sysgetenv;
316 char search_key[64];
317 char *val_start;
318 size_t val_len;
319 size_t copy_len;
321 /* Copy sysgetenv structure to PM. */
322 if (sys_datacopy(who_e, ptr, SELF, (vir_bytes) &sysgetenv,
323 sizeof(sysgetenv)) != OK) return(EFAULT);
325 /* Set a param override? */
326 if (req == PMSETPARAM || req == OPMSETPARAM) {
327 if (local_params >= MAX_LOCAL_PARAMS) return ENOSPC;
328 if (sysgetenv.keylen <= 0
329 || sysgetenv.keylen >=
330 sizeof(local_param_overrides[local_params].name)
331 || sysgetenv.vallen <= 0
332 || sysgetenv.vallen >=
333 sizeof(local_param_overrides[local_params].value))
334 return EINVAL;
336 if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.key,
337 SELF, (vir_bytes) local_param_overrides[local_params].name,
338 sysgetenv.keylen)) != OK)
339 return s;
340 if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.val,
341 SELF, (vir_bytes) local_param_overrides[local_params].value,
342 sysgetenv.vallen)) != OK)
343 return s;
344 local_param_overrides[local_params].name[sysgetenv.keylen] = '\0';
345 local_param_overrides[local_params].value[sysgetenv.vallen] = '\0';
347 local_params++;
349 return OK;
352 if (sysgetenv.keylen == 0) { /* copy all parameters */
353 val_start = monitor_params;
354 val_len = sizeof(monitor_params);
356 else { /* lookup value for key */
357 int p;
358 /* Try to get a copy of the requested key. */
359 if (sysgetenv.keylen > sizeof(search_key)) return(EINVAL);
360 if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.key,
361 SELF, (vir_bytes) search_key, sysgetenv.keylen)) != OK)
362 return(s);
364 /* Make sure key is null-terminated and lookup value.
365 * First check local overrides.
367 search_key[sysgetenv.keylen-1]= '\0';
368 for(p = 0; p < local_params; p++) {
369 if (!strcmp(search_key, local_param_overrides[p].name)) {
370 val_start = local_param_overrides[p].value;
371 break;
374 if (p >= local_params && (val_start = find_param(search_key)) == NULL)
375 return(ESRCH);
376 val_len = strlen(val_start) + 1;
379 /* See if it fits in the client's buffer. */
380 if (val_len > sysgetenv.vallen)
381 return E2BIG;
383 /* Value found, make the actual copy (as far as possible). */
384 copy_len = MIN(val_len, sysgetenv.vallen);
385 if ((s=sys_datacopy(SELF, (vir_bytes) val_start,
386 who_e, (vir_bytes) sysgetenv.val, copy_len)) != OK)
387 return(s);
389 return OK;
392 default:
393 return(EINVAL);
397 /*===========================================================================*
398 * do_getrusage *
399 *===========================================================================*/
401 do_getrusage(void)
403 clock_t user_time, sys_time;
404 struct rusage r_usage;
405 int r, children;
407 if (m_in.m_lc_pm_rusage.who != RUSAGE_SELF &&
408 m_in.m_lc_pm_rusage.who != RUSAGE_CHILDREN)
409 return EINVAL;
412 * TODO: first relay the call to VFS. As is, VFS does not have any
413 * fields it can fill with meaningful values, but this may change in
414 * the future. In that case, PM would first have to use the tell_vfs()
415 * system to get those values from VFS, and do the rest here upon
416 * getting the response.
419 memset(&r_usage, 0, sizeof(r_usage));
421 children = (m_in.m_lc_pm_rusage.who == RUSAGE_CHILDREN);
424 * Get system times. For RUSAGE_SELF, get the times for the calling
425 * process from the kernel. For RUSAGE_CHILDREN, we already have the
426 * values we should return right here.
428 if (!children) {
429 if ((r = sys_times(who_e, &user_time, &sys_time, NULL,
430 NULL)) != OK)
431 return r;
432 } else {
433 user_time = mp->mp_child_utime;
434 sys_time = mp->mp_child_stime;
437 /* In both cases, convert from clock ticks to microseconds. */
438 set_rusage_times(&r_usage, user_time, sys_time);
440 /* Get additional fields from VM. */
441 if ((r = vm_getrusage(who_e, &r_usage, children)) != OK)
442 return r;
444 /* Finally copy the structure to the caller. */
445 return sys_datacopy(SELF, (vir_bytes)&r_usage, who_e,
446 m_in.m_lc_pm_rusage.addr, (vir_bytes)sizeof(r_usage));