. service tells you which device it couldn't stat
[minix3.git] / servers / pm / misc.c
blob9aa6bdb2e64b0d5ecee2429a1eb5ad2e7f65b86c
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_procstat: request process status (Jorrit N. Herder)
6 * do_getsysinfo: request copy of PM data structure (Jorrit N. Herder)
7 * do_getprocnr: lookup process slot number (Jorrit N. Herder)
8 * do_allocmem: allocate a chunk of memory (Jorrit N. Herder)
9 * do_freemem: deallocate a chunk of memory (Jorrit N. Herder)
10 * do_getsetpriority: get/set process priority
11 * do_svrctl: process manager control
14 #define brk _brk
16 #include "pm.h"
17 #include <minix/callnr.h>
18 #include <signal.h>
19 #include <sys/svrctl.h>
20 #include <sys/resource.h>
21 #include <sys/utsname.h>
22 #include <minix/com.h>
23 #include <minix/config.h>
24 #include <minix/sysinfo.h>
25 #include <minix/type.h>
26 #include <string.h>
27 #include <archconst.h>
28 #include <archtypes.h>
29 #include <lib.h>
30 #include "mproc.h"
31 #include "param.h"
32 #include "../../kernel/proc.h"
34 PUBLIC struct utsname uts_val = {
35 "Minix", /* system name */
36 "noname", /* node/network name */
37 OS_RELEASE, /* O.S. release (e.g. 1.5) */
38 OS_VERSION, /* O.S. version (e.g. 10) */
39 "xyzzy", /* machine (cpu) type (filled in later) */
40 #if __i386
41 "i386", /* architecture */
42 #else
43 #error /* oops, no 'uname -mk' */
44 #endif
47 PRIVATE char *uts_tbl[] = {
48 uts_val.arch,
49 NULL, /* No kernel architecture */
50 uts_val.machine,
51 NULL, /* No hostname */
52 uts_val.nodename,
53 uts_val.release,
54 uts_val.version,
55 uts_val.sysname,
56 NULL, /* No bus */ /* No bus */
59 #if ENABLE_SYSCALL_STATS
60 PUBLIC unsigned long calls_stats[NCALLS];
61 #endif
63 /*===========================================================================*
64 * do_allocmem *
65 *===========================================================================*/
66 PUBLIC int do_allocmem()
68 vir_clicks mem_clicks;
69 phys_clicks mem_base;
71 /* This call is dangerous. Memory will be lost of the requesting process
72 * forgets about it.
74 if (mp->mp_effuid != 0)
76 printf("PM: unauthorized call of do_allocmem by proc %d\n",
77 mp->mp_endpoint);
78 return EPERM;
81 mem_clicks = (m_in.memsize + CLICK_SIZE -1 ) >> CLICK_SHIFT;
82 mem_base = alloc_mem(mem_clicks);
83 if (mem_base == NO_MEM) return(ENOMEM);
84 mp->mp_reply.membase = (phys_bytes) (mem_base << CLICK_SHIFT);
85 return(OK);
88 /*===========================================================================*
89 * do_freemem *
90 *===========================================================================*/
91 PUBLIC int do_freemem()
93 vir_clicks mem_clicks;
94 phys_clicks mem_base;
96 /* This call is dangerous. Even memory belonging to other processes can
97 * be freed.
99 if (mp->mp_effuid != 0)
101 printf("PM: unauthorized call of do_freemem by proc %d\n",
102 mp->mp_endpoint);
103 return EPERM;
106 mem_clicks = (m_in.memsize + CLICK_SIZE -1 ) >> CLICK_SHIFT;
107 mem_base = (m_in.membase + CLICK_SIZE -1 ) >> CLICK_SHIFT;
108 free_mem(mem_base, mem_clicks);
109 return(OK);
112 /*===========================================================================*
113 * do_procstat *
114 *===========================================================================*/
115 PUBLIC int do_procstat()
117 /* For the moment, this is only used to return pending signals to
118 * system processes that request the PM for their own status.
120 * Future use might include the FS requesting for process status of
121 * any user process.
124 /* This call should be removed, or made more general. */
125 if (mp->mp_effuid != 0)
127 printf("PM: unauthorized call of do_procstat by proc %d\n",
128 mp->mp_endpoint);
129 return EPERM;
132 if (m_in.stat_nr == SELF) {
133 mp->mp_reply.sig_set = mp->mp_sigpending;
134 sigemptyset(&mp->mp_sigpending);
136 else {
137 return(ENOSYS);
139 return(OK);
142 /*===========================================================================*
143 * do_sysuname *
144 *===========================================================================*/
145 PUBLIC int do_sysuname()
147 /* Set or get uname strings. */
149 int r;
150 size_t n;
151 char *string;
152 #if 0 /* for updates */
153 char tmp[sizeof(uts_val.nodename)];
154 static short sizes[] = {
155 0, /* arch, (0 = read-only) */
156 0, /* kernel */
157 0, /* machine */
158 0, /* sizeof(uts_val.hostname), */
159 sizeof(uts_val.nodename),
160 0, /* release */
161 0, /* version */
162 0, /* sysname */
164 #endif
166 if ((unsigned) m_in.sysuname_field >= _UTS_MAX) return(EINVAL);
168 string = uts_tbl[m_in.sysuname_field];
169 if (string == NULL)
170 return EINVAL; /* Unsupported field */
172 switch (m_in.sysuname_req) {
173 case _UTS_GET:
174 /* Copy an uname string to the user. */
175 n = strlen(string) + 1;
176 if (n > m_in.sysuname_len) n = m_in.sysuname_len;
177 r = sys_vircopy(SELF, D, (phys_bytes) string,
178 mp->mp_endpoint, D, (phys_bytes) m_in.sysuname_value,
179 (phys_bytes) n);
180 if (r < 0) return(r);
181 break;
183 #if 0 /* no updates yet */
184 case _UTS_SET:
185 /* Set an uname string, needs root power. */
186 len = sizes[m_in.sysuname_field];
187 if (mp->mp_effuid != 0 || len == 0) return(EPERM);
188 n = len < m_in.sysuname_len ? len : m_in.sysuname_len;
189 if (n <= 0) return(EINVAL);
190 r = sys_vircopy(mp->mp_endpoint, D, (phys_bytes) m_in.sysuname_value,
191 SELF, D, (phys_bytes) tmp, (phys_bytes) n);
192 if (r < 0) return(r);
193 tmp[n-1] = 0;
194 strcpy(string, tmp);
195 break;
196 #endif
198 default:
199 return(EINVAL);
201 /* Return the number of bytes moved. */
202 return(n);
206 /*===========================================================================*
207 * do_getsysinfo *
208 *===========================================================================*/
209 PUBLIC int do_getsysinfo()
211 struct mproc *proc_addr;
212 vir_bytes src_addr, dst_addr;
213 struct kinfo kinfo;
214 struct loadinfo loadinfo;
215 static struct proc proctab[NR_PROCS+NR_TASKS];
216 size_t len;
217 static struct pm_mem_info pmi;
218 int s, r;
219 size_t holesize;
221 /* This call leaks important information (the contents of registers).
222 * harmless data (such as the load should get their own calls)
224 if (mp->mp_effuid != 0)
226 printf("PM: unauthorized call of do_getsysinfo by proc %d '%s'\n",
227 mp->mp_endpoint, mp->mp_name);
228 sig_proc(mp, SIGEMT);
229 return EPERM;
232 switch(m_in.info_what) {
233 case SI_KINFO: /* kernel info is obtained via PM */
234 sys_getkinfo(&kinfo);
235 src_addr = (vir_bytes) &kinfo;
236 len = sizeof(struct kinfo);
237 break;
238 case SI_PROC_ADDR: /* get address of PM process table */
239 proc_addr = &mproc[0];
240 src_addr = (vir_bytes) &proc_addr;
241 len = sizeof(struct mproc *);
242 break;
243 case SI_PROC_TAB: /* copy entire process table */
244 src_addr = (vir_bytes) mproc;
245 len = sizeof(struct mproc) * NR_PROCS;
246 break;
247 case SI_KPROC_TAB: /* copy entire process table */
248 if((r=sys_getproctab(proctab)) != OK)
249 return r;
250 src_addr = (vir_bytes) proctab;
251 len = sizeof(proctab);
252 break;
253 case SI_MEM_ALLOC:
254 holesize = sizeof(pmi.pmi_holes);
255 if((r=mem_holes_copy(pmi.pmi_holes, &holesize,
256 &pmi.pmi_hi_watermark)) != OK)
257 return r;
258 src_addr = (vir_bytes) &pmi;
259 len = sizeof(pmi);
260 break;
261 case SI_LOADINFO: /* loadinfo is obtained via PM */
262 sys_getloadinfo(&loadinfo);
263 src_addr = (vir_bytes) &loadinfo;
264 len = sizeof(struct loadinfo);
265 break;
266 #if ENABLE_SYSCALL_STATS
267 case SI_CALL_STATS:
268 src_addr = (vir_bytes) calls_stats;
269 len = sizeof(calls_stats);
270 break;
271 #endif
272 default:
273 return(EINVAL);
276 dst_addr = (vir_bytes) m_in.info_where;
277 if (OK != (s=sys_datacopy(SELF, src_addr, who_e, dst_addr, len)))
278 return(s);
279 return(OK);
282 /*===========================================================================*
283 * do_getsysinfo_up *
284 *===========================================================================*/
285 PUBLIC int do_getsysinfo_up()
287 vir_bytes src_addr, dst_addr;
288 struct loadinfo loadinfo;
289 size_t len, real_len;
290 int s;
292 switch(m_in.SIU_WHAT) {
293 case SIU_LOADINFO: /* loadinfo is obtained via PM */
294 sys_getloadinfo(&loadinfo);
295 src_addr = (vir_bytes) &loadinfo;
296 real_len = sizeof(struct loadinfo);
297 break;
298 default:
299 return(EINVAL);
302 /* Let application know what the length was. */
303 len = real_len;
304 if(len > m_in.SIU_LEN)
305 len = m_in.SIU_LEN;
307 dst_addr = (vir_bytes) m_in.SIU_WHERE;
308 if (OK != (s=sys_datacopy(SELF, src_addr, who_e, dst_addr, len)))
309 return(s);
310 return(real_len);
313 /*===========================================================================*
314 * do_getprocnr *
315 *===========================================================================*/
316 PUBLIC int do_getprocnr()
318 register struct mproc *rmp;
319 static char search_key[PROC_NAME_LEN+1];
320 int key_len;
321 int s;
323 /* This call should be moved to DS. */
324 if (mp->mp_effuid != 0)
326 printf("PM: unauthorized call of do_procstat by proc %d\n",
327 mp->mp_endpoint);
328 return EPERM;
331 if (m_in.pid >= 0) { /* lookup process by pid */
332 for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) {
333 if ((rmp->mp_flags & IN_USE) && (rmp->mp_pid==m_in.pid)) {
334 mp->mp_reply.endpt = rmp->mp_endpoint;
335 return(OK);
338 return(ESRCH);
339 } else if (m_in.namelen > 0) { /* lookup process by name */
340 key_len = MIN(m_in.namelen, PROC_NAME_LEN);
341 if (OK != (s=sys_datacopy(who_e, (vir_bytes) m_in.addr,
342 SELF, (vir_bytes) search_key, key_len)))
343 return(s);
344 search_key[key_len] = '\0'; /* terminate for safety */
345 for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) {
346 if (((rmp->mp_flags & (IN_USE | ZOMBIE)) == IN_USE) &&
347 strncmp(rmp->mp_name, search_key, key_len)==0) {
348 mp->mp_reply.endpt = rmp->mp_endpoint;
349 return(OK);
352 return(ESRCH);
353 } else { /* return own/parent process number */
354 mp->mp_reply.endpt = who_e;
355 mp->mp_reply.pendpt = mproc[mp->mp_parent].mp_endpoint;
358 return(OK);
361 /*===========================================================================*
362 * do_reboot *
363 *===========================================================================*/
364 PUBLIC int do_reboot()
366 int r;
368 /* Check permission to abort the system. */
369 if (mp->mp_effuid != SUPER_USER) return(EPERM);
371 /* See how the system should be aborted. */
372 abort_flag = (unsigned) m_in.reboot_flag;
373 if (abort_flag >= RBT_INVALID) return(EINVAL);
374 if (RBT_MONITOR == abort_flag) {
375 int r;
376 if(m_in.reboot_strlen >= sizeof(monitor_code))
377 return EINVAL;
378 if((r = sys_datacopy(who_e, (vir_bytes) m_in.reboot_code,
379 SELF, (vir_bytes) monitor_code, m_in.reboot_strlen)) != OK)
380 return r;
381 monitor_code[m_in.reboot_strlen] = '\0';
383 else
384 monitor_code[0] = '\0';
386 /* Order matters here. When FS is told to reboot, it exits all its
387 * processes, and then would be confused if they're exited again by
388 * SIGKILL. So first kill, then reboot.
391 check_sig(-1, SIGKILL); /* kill all users except init */
392 sys_nice(INIT_PROC_NR, PRIO_STOP); /* stop init, but keep it around */
394 report_reboot= 1;
395 r= notify(FS_PROC_NR);
396 if (r != OK) panic("pm", "do_reboot: unable to notify FS", r);
398 return(SUSPEND); /* don't reply to caller */
401 /*===========================================================================*
402 * do_getsetpriority *
403 *===========================================================================*/
404 PUBLIC int do_getsetpriority()
406 int arg_which, arg_who, arg_pri;
407 int rmp_nr;
408 struct mproc *rmp;
410 arg_which = m_in.m1_i1;
411 arg_who = m_in.m1_i2;
412 arg_pri = m_in.m1_i3; /* for SETPRIORITY */
414 /* Code common to GETPRIORITY and SETPRIORITY. */
416 /* Only support PRIO_PROCESS for now. */
417 if (arg_which != PRIO_PROCESS)
418 return(EINVAL);
420 if (arg_who == 0)
421 rmp_nr = who_p;
422 else
423 if ((rmp_nr = proc_from_pid(arg_who)) < 0)
424 return(ESRCH);
426 rmp = &mproc[rmp_nr];
428 if (mp->mp_effuid != SUPER_USER &&
429 mp->mp_effuid != rmp->mp_effuid && mp->mp_effuid != rmp->mp_realuid)
430 return EPERM;
432 /* If GET, that's it. */
433 if (call_nr == GETPRIORITY) {
434 return(rmp->mp_nice - PRIO_MIN);
437 /* Only root is allowed to reduce the nice level. */
438 if (rmp->mp_nice > arg_pri && mp->mp_effuid != SUPER_USER)
439 return(EACCES);
441 /* We're SET, and it's allowed. Do it and tell kernel. */
442 rmp->mp_nice = arg_pri;
443 return sys_nice(rmp->mp_endpoint, arg_pri);
446 /*===========================================================================*
447 * do_svrctl *
448 *===========================================================================*/
449 PUBLIC int do_svrctl()
451 int s, req;
452 vir_bytes ptr;
453 #define MAX_LOCAL_PARAMS 2
454 static struct {
455 char name[30];
456 char value[30];
457 } local_param_overrides[MAX_LOCAL_PARAMS];
458 static int local_params = 0;
460 req = m_in.svrctl_req;
461 ptr = (vir_bytes) m_in.svrctl_argp;
463 /* Is the request indeed for the MM? */
464 if (((req >> 8) & 0xFF) != 'M') return(EINVAL);
466 /* Control operations local to the PM. */
467 switch(req) {
468 case MMSETPARAM:
469 case MMGETPARAM: {
470 struct sysgetenv sysgetenv;
471 char search_key[64];
472 char *val_start;
473 size_t val_len;
474 size_t copy_len;
476 /* Copy sysgetenv structure to PM. */
477 if (sys_datacopy(who_e, ptr, SELF, (vir_bytes) &sysgetenv,
478 sizeof(sysgetenv)) != OK) return(EFAULT);
480 /* Set a param override? */
481 if (req == MMSETPARAM) {
482 if (local_params >= MAX_LOCAL_PARAMS) return ENOSPC;
483 if (sysgetenv.keylen <= 0
484 || sysgetenv.keylen >=
485 sizeof(local_param_overrides[local_params].name)
486 || sysgetenv.vallen <= 0
487 || sysgetenv.vallen >=
488 sizeof(local_param_overrides[local_params].value))
489 return EINVAL;
491 if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.key,
492 SELF, (vir_bytes) local_param_overrides[local_params].name,
493 sysgetenv.keylen)) != OK)
494 return s;
495 if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.val,
496 SELF, (vir_bytes) local_param_overrides[local_params].value,
497 sysgetenv.keylen)) != OK)
498 return s;
499 local_param_overrides[local_params].name[sysgetenv.keylen] = '\0';
500 local_param_overrides[local_params].value[sysgetenv.vallen] = '\0';
502 local_params++;
504 return OK;
507 if (sysgetenv.keylen == 0) { /* copy all parameters */
508 val_start = monitor_params;
509 val_len = sizeof(monitor_params);
511 else { /* lookup value for key */
512 int p;
513 /* Try to get a copy of the requested key. */
514 if (sysgetenv.keylen > sizeof(search_key)) return(EINVAL);
515 if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.key,
516 SELF, (vir_bytes) search_key, sysgetenv.keylen)) != OK)
517 return(s);
519 /* Make sure key is null-terminated and lookup value.
520 * First check local overrides.
522 search_key[sysgetenv.keylen-1]= '\0';
523 for(p = 0; p < local_params; p++) {
524 if (!strcmp(search_key, local_param_overrides[p].name)) {
525 val_start = local_param_overrides[p].value;
526 break;
529 if (p >= local_params && (val_start = find_param(search_key)) == NULL)
530 return(ESRCH);
531 val_len = strlen(val_start) + 1;
534 /* See if it fits in the client's buffer. */
535 if (val_len > sysgetenv.vallen)
536 return E2BIG;
538 /* Value found, make the actual copy (as far as possible). */
539 copy_len = MIN(val_len, sysgetenv.vallen);
540 if ((s=sys_datacopy(SELF, (vir_bytes) val_start,
541 who_e, (vir_bytes) sysgetenv.val, copy_len)) != OK)
542 return(s);
544 return OK;
547 #if ENABLE_SWAP
548 case MMSWAPON: {
549 struct mmswapon swapon;
551 if (mp->mp_effuid != SUPER_USER) return(EPERM);
553 if (sys_datacopy(who_e, (phys_bytes) ptr,
554 PM_PROC_NR, (phys_bytes) &swapon,
555 (phys_bytes) sizeof(swapon)) != OK) return(EFAULT);
557 return(swap_on(swapon.file, swapon.offset, swapon.size)); }
559 case MMSWAPOFF: {
560 if (mp->mp_effuid != SUPER_USER) return(EPERM);
562 return(swap_off()); }
563 #endif /* SWAP */
565 default:
566 return(EINVAL);
570 /*===========================================================================*
571 * _brk *
572 *===========================================================================*/
574 extern char *_brksize;
575 PUBLIC int brk(brk_addr)
576 char *brk_addr;
578 /* PM wants to call brk() itself. */
579 if(real_brk(&mproc[PM_PROC_NR], (vir_bytes) brk_addr) != OK) {
580 return -1;
582 _brksize = brk_addr;
583 return 0;