1 /* Miscellaneous system calls. Author: Kees J. Bot
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
17 #include <minix/callnr.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>
27 #include <archconst.h>
28 #include <archtypes.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) */
41 "i386", /* architecture */
43 #error /* oops, no 'uname -mk' */
47 PRIVATE
char *uts_tbl
[] = {
49 NULL
, /* No kernel architecture */
51 NULL
, /* No hostname */
56 NULL
, /* No bus */ /* No bus */
59 #if ENABLE_SYSCALL_STATS
60 PUBLIC
unsigned long calls_stats
[NCALLS
];
63 /*===========================================================================*
65 *===========================================================================*/
66 PUBLIC
int do_allocmem()
68 vir_clicks mem_clicks
;
71 /* This call is dangerous. Memory will be lost of the requesting process
74 if (mp
->mp_effuid
!= 0)
76 printf("PM: unauthorized call of do_allocmem by proc %d\n",
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
);
88 /*===========================================================================*
90 *===========================================================================*/
91 PUBLIC
int do_freemem()
93 vir_clicks mem_clicks
;
96 /* This call is dangerous. Even memory belonging to other processes can
99 if (mp
->mp_effuid
!= 0)
101 printf("PM: unauthorized call of do_freemem by proc %d\n",
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
);
112 /*===========================================================================*
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
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",
132 if (m_in
.stat_nr
== SELF
) {
133 mp
->mp_reply
.sig_set
= mp
->mp_sigpending
;
134 sigemptyset(&mp
->mp_sigpending
);
142 /*===========================================================================*
144 *===========================================================================*/
145 PUBLIC
int do_sysuname()
147 /* Set or get uname strings. */
152 #if 0 /* for updates */
153 char tmp
[sizeof(uts_val
.nodename
)];
154 static short sizes
[] = {
155 0, /* arch, (0 = read-only) */
158 0, /* sizeof(uts_val.hostname), */
159 sizeof(uts_val
.nodename
),
166 if ((unsigned) m_in
.sysuname_field
>= _UTS_MAX
) return(EINVAL
);
168 string
= uts_tbl
[m_in
.sysuname_field
];
170 return EINVAL
; /* Unsupported field */
172 switch (m_in
.sysuname_req
) {
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
,
180 if (r
< 0) return(r
);
183 #if 0 /* no updates yet */
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
);
201 /* Return the number of bytes moved. */
206 /*===========================================================================*
208 *===========================================================================*/
209 PUBLIC
int do_getsysinfo()
211 struct mproc
*proc_addr
;
212 vir_bytes src_addr
, dst_addr
;
214 struct loadinfo loadinfo
;
215 static struct proc proctab
[NR_PROCS
+NR_TASKS
];
217 static struct pm_mem_info pmi
;
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
);
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
);
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
*);
243 case SI_PROC_TAB
: /* copy entire process table */
244 src_addr
= (vir_bytes
) mproc
;
245 len
= sizeof(struct mproc
) * NR_PROCS
;
247 case SI_KPROC_TAB
: /* copy entire process table */
248 if((r
=sys_getproctab(proctab
)) != OK
)
250 src_addr
= (vir_bytes
) proctab
;
251 len
= sizeof(proctab
);
254 holesize
= sizeof(pmi
.pmi_holes
);
255 if((r
=mem_holes_copy(pmi
.pmi_holes
, &holesize
,
256 &pmi
.pmi_hi_watermark
)) != OK
)
258 src_addr
= (vir_bytes
) &pmi
;
261 case SI_LOADINFO
: /* loadinfo is obtained via PM */
262 sys_getloadinfo(&loadinfo
);
263 src_addr
= (vir_bytes
) &loadinfo
;
264 len
= sizeof(struct loadinfo
);
266 #if ENABLE_SYSCALL_STATS
268 src_addr
= (vir_bytes
) calls_stats
;
269 len
= sizeof(calls_stats
);
276 dst_addr
= (vir_bytes
) m_in
.info_where
;
277 if (OK
!= (s
=sys_datacopy(SELF
, src_addr
, who_e
, dst_addr
, len
)))
282 /*===========================================================================*
284 *===========================================================================*/
285 PUBLIC
int do_getsysinfo_up()
287 vir_bytes src_addr
, dst_addr
;
288 struct loadinfo loadinfo
;
289 size_t len
, real_len
;
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
);
302 /* Let application know what the length was. */
304 if(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
)))
313 /*===========================================================================*
315 *===========================================================================*/
316 PUBLIC
int do_getprocnr()
318 register struct mproc
*rmp
;
319 static char search_key
[PROC_NAME_LEN
+1];
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",
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
;
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
)))
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
;
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
;
361 /*===========================================================================*
363 *===========================================================================*/
364 PUBLIC
int do_reboot()
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
) {
376 if(m_in
.reboot_strlen
>= sizeof(monitor_code
))
378 if((r
= sys_datacopy(who_e
, (vir_bytes
) m_in
.reboot_code
,
379 SELF
, (vir_bytes
) monitor_code
, m_in
.reboot_strlen
)) != OK
)
381 monitor_code
[m_in
.reboot_strlen
] = '\0';
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 */
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
;
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
)
423 if ((rmp_nr
= proc_from_pid(arg_who
)) < 0)
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
)
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
)
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 /*===========================================================================*
448 *===========================================================================*/
449 PUBLIC
int do_svrctl()
453 #define MAX_LOCAL_PARAMS 2
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. */
470 struct sysgetenv sysgetenv
;
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
))
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
)
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
)
499 local_param_overrides
[local_params
].name
[sysgetenv
.keylen
] = '\0';
500 local_param_overrides
[local_params
].value
[sysgetenv
.vallen
] = '\0';
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 */
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
)
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
;
529 if (p
>= local_params
&& (val_start
= find_param(search_key
)) == NULL
)
531 val_len
= strlen(val_start
) + 1;
534 /* See if it fits in the client's buffer. */
535 if (val_len
> sysgetenv
.vallen
)
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
)
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
)); }
560 if (mp
->mp_effuid
!= SUPER_USER
) return(EPERM
);
562 return(swap_off()); }
570 /*===========================================================================*
572 *===========================================================================*/
574 extern char *_brksize
;
575 PUBLIC
int brk(brk_addr
)
578 /* PM wants to call brk() itself. */
579 if(real_brk(&mproc
[PM_PROC_NR
], (vir_bytes
) brk_addr
) != OK
) {