VM: simplify slab allocator
[minix.git] / servers / pm / misc.c
blobdbe979fbf0bef74e5a4a10af7cc41d4cde8a1c66
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 process slot number (Jorrit N. Herder)
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
12 #define brk _brk
14 #include "pm.h"
15 #include <minix/callnr.h>
16 #include <signal.h>
17 #include <sys/svrctl.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/vm.h>
25 #include <string.h>
26 #include <machine/archtypes.h>
27 #include <lib.h>
28 #include <assert.h>
29 #include "mproc.h"
30 #include "param.h"
31 #include "kernel/proc.h"
33 struct utsname uts_val = {
34 "Minix", /* system name */
35 "noname", /* node/network name */
36 OS_RELEASE, /* O.S. release (e.g. 1.5) */
37 OS_VERSION, /* O.S. version (e.g. 10) */
38 "xyzzy", /* machine (cpu) type (filled in later) */
39 #if defined(__i386__)
40 "i386", /* architecture */
41 #elif defined(__arm__)
42 "arm", /* architecture */
43 #else
44 #error /* oops, no 'uname -mk' */
45 #endif
48 static char *uts_tbl[] = {
49 uts_val.arch,
50 NULL, /* No kernel architecture */
51 uts_val.machine,
52 NULL, /* No hostname */
53 uts_val.nodename,
54 uts_val.release,
55 uts_val.version,
56 uts_val.sysname,
57 NULL, /* No bus */ /* No bus */
60 #if ENABLE_SYSCALL_STATS
61 unsigned long calls_stats[NCALLS];
62 #endif
64 /*===========================================================================*
65 * do_sysuname *
66 *===========================================================================*/
67 int do_sysuname()
69 /* Set or get uname strings. */
71 int r;
72 size_t n;
73 char *string;
74 #if 0 /* for updates */
75 char tmp[sizeof(uts_val.nodename)];
76 static short sizes[] = {
77 0, /* arch, (0 = read-only) */
78 0, /* kernel */
79 0, /* machine */
80 0, /* sizeof(uts_val.hostname), */
81 sizeof(uts_val.nodename),
82 0, /* release */
83 0, /* version */
84 0, /* sysname */
86 #endif
88 if ((unsigned) m_in.sysuname_field >= _UTS_MAX) return(EINVAL);
90 string = uts_tbl[m_in.sysuname_field];
91 if (string == NULL)
92 return EINVAL; /* Unsupported field */
94 switch (m_in.sysuname_req) {
95 case _UTS_GET:
96 /* Copy an uname string to the user. */
97 n = strlen(string) + 1;
98 if (n > m_in.sysuname_len) n = m_in.sysuname_len;
99 r = sys_vircopy(SELF, (phys_bytes) string,
100 mp->mp_endpoint, (phys_bytes) m_in.sysuname_value,
101 (phys_bytes) n);
102 if (r < 0) return(r);
103 break;
105 #if 0 /* no updates yet */
106 case _UTS_SET:
107 /* Set an uname string, needs root power. */
108 len = sizes[m_in.sysuname_field];
109 if (mp->mp_effuid != 0 || len == 0) return(EPERM);
110 n = len < m_in.sysuname_len ? len : m_in.sysuname_len;
111 if (n <= 0) return(EINVAL);
112 r = sys_vircopy(mp->mp_endpoint, (phys_bytes) m_in.sysuname_value,
113 SELF, (phys_bytes) tmp, (phys_bytes) n);
114 if (r < 0) return(r);
115 tmp[n-1] = 0;
116 strcpy(string, tmp);
117 break;
118 #endif
120 default:
121 return(EINVAL);
123 /* Return the number of bytes moved. */
124 return(n);
128 /*===========================================================================*
129 * do_getsysinfo *
130 *===========================================================================*/
131 int do_getsysinfo()
133 vir_bytes src_addr, dst_addr;
134 size_t len;
136 /* This call leaks important information. In the future, requests from
137 * non-system processes should be denied.
139 if (mp->mp_effuid != 0)
141 printf("PM: unauthorized call of do_getsysinfo by proc %d '%s'\n",
142 mp->mp_endpoint, mp->mp_name);
143 sys_sysctl_stacktrace(mp->mp_endpoint);
144 return EPERM;
147 switch(m_in.SI_WHAT) {
148 case SI_PROC_TAB: /* copy entire process table */
149 src_addr = (vir_bytes) mproc;
150 len = sizeof(struct mproc) * NR_PROCS;
151 break;
152 #if ENABLE_SYSCALL_STATS
153 case SI_CALL_STATS:
154 src_addr = (vir_bytes) calls_stats;
155 len = sizeof(calls_stats);
156 break;
157 #endif
158 default:
159 return(EINVAL);
162 if (len != m_in.SI_SIZE)
163 return(EINVAL);
165 dst_addr = (vir_bytes) m_in.SI_WHERE;
166 return sys_datacopy(SELF, src_addr, who_e, dst_addr, len);
169 /*===========================================================================*
170 * do_getprocnr *
171 *===========================================================================*/
172 int do_getprocnr()
174 register struct mproc *rmp;
175 static char search_key[PROC_NAME_LEN+1];
176 int key_len;
177 int s;
179 /* This call should be moved to DS. */
180 if (mp->mp_effuid != 0)
182 /* For now, allow non-root processes to request their own endpoint. */
183 if (m_in.pid < 0 && m_in.namelen == 0) {
184 mp->mp_reply.PM_ENDPT = who_e;
185 mp->mp_reply.PM_PENDPT = NONE;
186 return OK;
189 printf("PM: unauthorized call of do_getprocnr by proc %d\n",
190 mp->mp_endpoint);
191 sys_sysctl_stacktrace(mp->mp_endpoint);
192 return EPERM;
195 #if 0
196 printf("PM: do_getprocnr(%d) call from endpoint %d, %s\n",
197 m_in.pid, mp->mp_endpoint, mp->mp_name);
198 #endif
200 if (m_in.pid >= 0) { /* lookup process by pid */
201 if ((rmp = find_proc(m_in.pid)) != NULL) {
202 mp->mp_reply.PM_ENDPT = rmp->mp_endpoint;
203 #if 0
204 printf("PM: pid result: %d\n", rmp->mp_endpoint);
205 #endif
206 return(OK);
208 return(ESRCH);
209 } else if (m_in.namelen > 0) { /* lookup process by name */
210 key_len = MIN(m_in.namelen, PROC_NAME_LEN);
211 if (OK != (s=sys_datacopy(who_e, (vir_bytes) m_in.PMBRK_ADDR,
212 SELF, (vir_bytes) search_key, key_len)))
213 return(s);
214 search_key[key_len] = '\0'; /* terminate for safety */
215 for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) {
216 if (((rmp->mp_flags & (IN_USE | EXITING)) == IN_USE) &&
217 strncmp(rmp->mp_name, search_key, key_len)==0) {
218 mp->mp_reply.PM_ENDPT = rmp->mp_endpoint;
219 return(OK);
222 return(ESRCH);
223 } else { /* return own/parent process number */
224 #if 0
225 printf("PM: endpt result: %d\n", mp->mp_reply.PM_ENDPT);
226 #endif
227 mp->mp_reply.PM_ENDPT = who_e;
228 mp->mp_reply.PM_PENDPT = mproc[mp->mp_parent].mp_endpoint;
231 return(OK);
234 /*===========================================================================*
235 * do_getepinfo *
236 *===========================================================================*/
237 int do_getepinfo()
239 register struct mproc *rmp;
240 endpoint_t ep;
242 ep = m_in.PM_ENDPT;
244 for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) {
245 if ((rmp->mp_flags & IN_USE) && (rmp->mp_endpoint == ep)) {
246 mp->mp_reply.reply_res2 = rmp->mp_effuid;
247 mp->mp_reply.reply_res3 = rmp->mp_effgid;
248 return(rmp->mp_pid);
252 /* Process not found */
253 return(ESRCH);
256 /*===========================================================================*
257 * do_getepinfo_o *
258 *===========================================================================*/
259 int do_getepinfo_o()
261 register struct mproc *rmp;
262 endpoint_t ep;
264 /* This call should be moved to DS. */
265 if (mp->mp_effuid != 0) {
266 printf("PM: unauthorized call of do_getepinfo_o by proc %d\n",
267 mp->mp_endpoint);
268 sys_sysctl_stacktrace(mp->mp_endpoint);
269 return EPERM;
272 ep = m_in.PM_ENDPT;
274 for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) {
275 if ((rmp->mp_flags & IN_USE) && (rmp->mp_endpoint == ep)) {
276 mp->mp_reply.reply_res2 = (short) rmp->mp_effuid;
277 mp->mp_reply.reply_res3 = (char) rmp->mp_effgid;
278 return(rmp->mp_pid);
282 /* Process not found */
283 return(ESRCH);
286 /*===========================================================================*
287 * do_reboot *
288 *===========================================================================*/
289 int do_reboot()
291 message m;
293 /* Check permission to abort the system. */
294 if (mp->mp_effuid != SUPER_USER) return(EPERM);
296 /* See how the system should be aborted. */
297 abort_flag = (unsigned) m_in.reboot_flag;
298 if (abort_flag >= RBT_INVALID) return(EINVAL);
300 /* Order matters here. When VFS is told to reboot, it exits all its
301 * processes, and then would be confused if they're exited again by
302 * SIGKILL. So first kill, then reboot.
305 check_sig(-1, SIGKILL, FALSE /* ksig*/); /* kill all users except init */
306 sys_stop(INIT_PROC_NR); /* stop init, but keep it around */
308 /* Tell VFS to reboot */
309 m.m_type = PM_REBOOT;
311 tell_vfs(&mproc[VFS_PROC_NR], &m);
313 return(SUSPEND); /* don't reply to caller */
316 /*===========================================================================*
317 * do_getsetpriority *
318 *===========================================================================*/
319 int do_getsetpriority()
321 int r, arg_which, arg_who, arg_pri;
322 struct mproc *rmp;
324 arg_which = m_in.m1_i1;
325 arg_who = m_in.m1_i2;
326 arg_pri = m_in.m1_i3; /* for SETPRIORITY */
328 /* Code common to GETPRIORITY and SETPRIORITY. */
330 /* Only support PRIO_PROCESS for now. */
331 if (arg_which != PRIO_PROCESS)
332 return(EINVAL);
334 if (arg_who == 0)
335 rmp = mp;
336 else
337 if ((rmp = find_proc(arg_who)) == NULL)
338 return(ESRCH);
340 if (mp->mp_effuid != SUPER_USER &&
341 mp->mp_effuid != rmp->mp_effuid && mp->mp_effuid != rmp->mp_realuid)
342 return EPERM;
344 /* If GET, that's it. */
345 if (call_nr == GETPRIORITY) {
346 return(rmp->mp_nice - PRIO_MIN);
349 /* Only root is allowed to reduce the nice level. */
350 if (rmp->mp_nice > arg_pri && mp->mp_effuid != SUPER_USER)
351 return(EACCES);
353 /* We're SET, and it's allowed.
355 * The value passed in is currently between PRIO_MIN and PRIO_MAX.
356 * We have to scale this between MIN_USER_Q and MAX_USER_Q to match
357 * the kernel's scheduling queues.
360 if ((r = sched_nice(rmp, arg_pri)) != OK) {
361 return r;
364 rmp->mp_nice = arg_pri;
365 return(OK);
368 /*===========================================================================*
369 * do_svrctl *
370 *===========================================================================*/
371 int do_svrctl()
373 int s, req;
374 vir_bytes ptr;
375 #define MAX_LOCAL_PARAMS 2
376 static struct {
377 char name[30];
378 char value[30];
379 } local_param_overrides[MAX_LOCAL_PARAMS];
380 static int local_params = 0;
382 req = m_in.svrctl_req;
383 ptr = (vir_bytes) m_in.svrctl_argp;
385 /* Is the request indeed for the PM? */
386 if (((req >> 8) & 0xFF) != 'M') return(EINVAL);
388 /* Control operations local to the PM. */
389 switch(req) {
390 case PMSETPARAM:
391 case PMGETPARAM: {
392 struct sysgetenv sysgetenv;
393 char search_key[64];
394 char *val_start;
395 size_t val_len;
396 size_t copy_len;
398 /* Copy sysgetenv structure to PM. */
399 if (sys_datacopy(who_e, ptr, SELF, (vir_bytes) &sysgetenv,
400 sizeof(sysgetenv)) != OK) return(EFAULT);
402 /* Set a param override? */
403 if (req == PMSETPARAM) {
404 if (local_params >= MAX_LOCAL_PARAMS) return ENOSPC;
405 if (sysgetenv.keylen <= 0
406 || sysgetenv.keylen >=
407 sizeof(local_param_overrides[local_params].name)
408 || sysgetenv.vallen <= 0
409 || sysgetenv.vallen >=
410 sizeof(local_param_overrides[local_params].value))
411 return EINVAL;
413 if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.key,
414 SELF, (vir_bytes) local_param_overrides[local_params].name,
415 sysgetenv.keylen)) != OK)
416 return s;
417 if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.val,
418 SELF, (vir_bytes) local_param_overrides[local_params].value,
419 sysgetenv.vallen)) != OK)
420 return s;
421 local_param_overrides[local_params].name[sysgetenv.keylen] = '\0';
422 local_param_overrides[local_params].value[sysgetenv.vallen] = '\0';
424 local_params++;
426 return OK;
429 if (sysgetenv.keylen == 0) { /* copy all parameters */
430 val_start = monitor_params;
431 val_len = sizeof(monitor_params);
433 else { /* lookup value for key */
434 int p;
435 /* Try to get a copy of the requested key. */
436 if (sysgetenv.keylen > sizeof(search_key)) return(EINVAL);
437 if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.key,
438 SELF, (vir_bytes) search_key, sysgetenv.keylen)) != OK)
439 return(s);
441 /* Make sure key is null-terminated and lookup value.
442 * First check local overrides.
444 search_key[sysgetenv.keylen-1]= '\0';
445 for(p = 0; p < local_params; p++) {
446 if (!strcmp(search_key, local_param_overrides[p].name)) {
447 val_start = local_param_overrides[p].value;
448 break;
451 if (p >= local_params && (val_start = find_param(search_key)) == NULL)
452 return(ESRCH);
453 val_len = strlen(val_start) + 1;
456 /* See if it fits in the client's buffer. */
457 if (val_len > sysgetenv.vallen)
458 return E2BIG;
460 /* Value found, make the actual copy (as far as possible). */
461 copy_len = MIN(val_len, sysgetenv.vallen);
462 if ((s=sys_datacopy(SELF, (vir_bytes) val_start,
463 who_e, (vir_bytes) sysgetenv.val, copy_len)) != OK)
464 return(s);
466 return OK;
469 default:
470 return(EINVAL);
474 /*===========================================================================*
475 * _brk *
476 *===========================================================================*/
478 extern char *_brksize;
479 int brk(brk_addr)
480 #ifdef __NBSD_LIBC
481 void *brk_addr;
482 #else
483 char *brk_addr;
484 #endif
486 int r;
487 /* PM wants to call brk() itself. */
488 if((r=vm_brk(PM_PROC_NR, brk_addr)) != OK) {
489 #if 0
490 printf("PM: own brk(%p) failed: vm_brk() returned %d\n",
491 brk_addr, r);
492 #endif
493 return -1;
495 _brksize = brk_addr;
496 return 0;