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_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
15 #include <minix/callnr.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>
26 #include <machine/archtypes.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) */
40 "i386", /* architecture */
41 #elif defined(__arm__)
42 "arm", /* architecture */
44 #error /* oops, no 'uname -mk' */
48 static char *uts_tbl
[] = {
50 NULL
, /* No kernel architecture */
52 NULL
, /* No hostname */
57 NULL
, /* No bus */ /* No bus */
60 #if ENABLE_SYSCALL_STATS
61 unsigned long calls_stats
[NCALLS
];
64 /*===========================================================================*
66 *===========================================================================*/
69 /* Set or get uname strings. */
74 #if 0 /* for updates */
75 char tmp
[sizeof(uts_val
.nodename
)];
76 static short sizes
[] = {
77 0, /* arch, (0 = read-only) */
80 0, /* sizeof(uts_val.hostname), */
81 sizeof(uts_val
.nodename
),
88 if ((unsigned) m_in
.sysuname_field
>= _UTS_MAX
) return(EINVAL
);
90 string
= uts_tbl
[m_in
.sysuname_field
];
92 return EINVAL
; /* Unsupported field */
94 switch (m_in
.sysuname_req
) {
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
,
102 if (r
< 0) return(r
);
105 #if 0 /* no updates yet */
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
);
123 /* Return the number of bytes moved. */
128 /*===========================================================================*
130 *===========================================================================*/
133 vir_bytes src_addr
, dst_addr
;
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
);
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
;
152 #if ENABLE_SYSCALL_STATS
154 src_addr
= (vir_bytes
) calls_stats
;
155 len
= sizeof(calls_stats
);
162 if (len
!= m_in
.SI_SIZE
)
165 dst_addr
= (vir_bytes
) m_in
.SI_WHERE
;
166 return sys_datacopy(SELF
, src_addr
, who_e
, dst_addr
, len
);
169 /*===========================================================================*
171 *===========================================================================*/
174 register struct mproc
*rmp
;
175 static char search_key
[PROC_NAME_LEN
+1];
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
;
189 printf("PM: unauthorized call of do_getprocnr by proc %d\n",
191 sys_sysctl_stacktrace(mp
->mp_endpoint
);
196 printf("PM: do_getprocnr(%d) call from endpoint %d, %s\n",
197 m_in
.pid
, mp
->mp_endpoint
, mp
->mp_name
);
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
;
204 printf("PM: pid result: %d\n", rmp
->mp_endpoint
);
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
)))
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
;
223 } else { /* return own/parent process number */
225 printf("PM: endpt result: %d\n", mp
->mp_reply
.PM_ENDPT
);
227 mp
->mp_reply
.PM_ENDPT
= who_e
;
228 mp
->mp_reply
.PM_PENDPT
= mproc
[mp
->mp_parent
].mp_endpoint
;
234 /*===========================================================================*
236 *===========================================================================*/
239 register struct mproc
*rmp
;
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
;
252 /* Process not found */
256 /*===========================================================================*
258 *===========================================================================*/
261 register struct mproc
*rmp
;
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",
268 sys_sysctl_stacktrace(mp
->mp_endpoint
);
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
;
282 /* Process not found */
286 /*===========================================================================*
288 *===========================================================================*/
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
;
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
)
337 if ((rmp
= find_proc(arg_who
)) == NULL
)
340 if (mp
->mp_effuid
!= SUPER_USER
&&
341 mp
->mp_effuid
!= rmp
->mp_effuid
&& mp
->mp_effuid
!= rmp
->mp_realuid
)
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
)
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
) {
364 rmp
->mp_nice
= arg_pri
;
368 /*===========================================================================*
370 *===========================================================================*/
375 #define MAX_LOCAL_PARAMS 2
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. */
392 struct sysgetenv sysgetenv
;
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
))
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
)
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
)
421 local_param_overrides
[local_params
].name
[sysgetenv
.keylen
] = '\0';
422 local_param_overrides
[local_params
].value
[sysgetenv
.vallen
] = '\0';
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 */
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
)
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
;
451 if (p
>= local_params
&& (val_start
= find_param(search_key
)) == NULL
)
453 val_len
= strlen(val_start
) + 1;
456 /* See if it fits in the client's buffer. */
457 if (val_len
> sysgetenv
.vallen
)
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
)
474 /*===========================================================================*
476 *===========================================================================*/
478 extern char *_brksize
;
487 /* PM wants to call brk() itself. */
488 if((r
=vm_brk(PM_PROC_NR
, brk_addr
)) != OK
) {
490 printf("PM: own brk(%p) failed: vm_brk() returned %d\n",