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 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
13 #include <minix/callnr.h>
15 #include <sys/svrctl.h>
16 #include <sys/reboot.h>
17 #include <sys/resource.h>
18 #include <sys/utsname.h>
19 #include <minix/com.h>
20 #include <minix/config.h>
21 #include <minix/sysinfo.h>
22 #include <minix/type.h>
24 #include <machine/archtypes.h>
28 #include "kernel/proc.h"
30 struct utsname uts_val
= {
31 OS_NAME
, /* system name */
32 "noname", /* node/network name */
33 OS_RELEASE
, /* O.S. release (e.g. 3.3.0) */
34 OS_VERSION
, /* O.S. version (e.g. Minix 3.3.0 (GENERIC)) */
35 "xyzzy", /* machine (cpu) type (filled in later) */
37 "i386", /* architecture */
38 #elif defined(__arm__)
39 "arm", /* architecture */
41 #error /* oops, no 'uname -mk' */
45 static char *uts_tbl
[] = {
47 NULL
, /* No kernel architecture */
49 NULL
, /* No hostname */
54 NULL
, /* No bus */ /* No bus */
57 #if ENABLE_SYSCALL_STATS
58 unsigned long calls_stats
[NR_PM_CALLS
];
61 /*===========================================================================*
63 *===========================================================================*/
66 /* Set or get uname strings. */
70 #if 0 /* for updates */
71 char tmp
[sizeof(uts_val
.nodename
)];
72 static short sizes
[] = {
73 0, /* arch, (0 = read-only) */
76 0, /* sizeof(uts_val.hostname), */
77 sizeof(uts_val
.nodename
),
84 if ((unsigned) m_in
.PM_SYSUNAME_FIELD
>= _UTS_MAX
) return(EINVAL
);
86 string
= uts_tbl
[m_in
.PM_SYSUNAME_FIELD
];
88 return EINVAL
; /* Unsupported field */
90 switch (m_in
.PM_SYSUNAME_REQ
) {
92 /* Copy an uname string to the user. */
93 n
= strlen(string
) + 1;
94 if (n
> m_in
.PM_SYSUNAME_LEN
) n
= m_in
.PM_SYSUNAME_LEN
;
95 r
= sys_vircopy(SELF
, (phys_bytes
) string
,
96 mp
->mp_endpoint
, (phys_bytes
) m_in
.PM_SYSUNAME_VALUE
,
101 #if 0 /* no updates yet */
103 /* Set an uname string, needs root power. */
104 len
= sizes
[m_in
.PM_SYSUNAME_FIELD
];
105 if (mp
->mp_effuid
!= 0 || len
== 0) return(EPERM
);
106 n
= len
< m_in
.PM_SYSUNAME_LEN
? len
: m_in
.PM_SYSUNAME_LEN
;
107 if (n
<= 0) return(EINVAL
);
108 r
= sys_vircopy(mp
->mp_endpoint
, (phys_bytes
) m_in
.PM_SYSUNAME_VALUE
,
109 SELF
, (phys_bytes
) tmp
, (phys_bytes
) n
);
110 if (r
< 0) return(r
);
119 /* Return the number of bytes moved. */
124 /*===========================================================================*
126 *===========================================================================*/
129 vir_bytes src_addr
, dst_addr
;
132 /* This call leaks important information. In the future, requests from
133 * non-system processes should be denied.
135 if (mp
->mp_effuid
!= 0)
137 printf("PM: unauthorized call of do_getsysinfo by proc %d '%s'\n",
138 mp
->mp_endpoint
, mp
->mp_name
);
139 sys_diagctl_stacktrace(mp
->mp_endpoint
);
143 switch(m_in
.SI_WHAT
) {
144 case SI_PROC_TAB
: /* copy entire process table */
145 src_addr
= (vir_bytes
) mproc
;
146 len
= sizeof(struct mproc
) * NR_PROCS
;
148 #if ENABLE_SYSCALL_STATS
150 src_addr
= (vir_bytes
) calls_stats
;
151 len
= sizeof(calls_stats
);
158 if (len
!= m_in
.SI_SIZE
)
161 dst_addr
= (vir_bytes
) m_in
.SI_WHERE
;
162 return sys_datacopy(SELF
, src_addr
, who_e
, dst_addr
, len
);
165 /*===========================================================================*
167 *===========================================================================*/
168 int do_getprocnr(void)
170 register struct mproc
*rmp
;
172 /* This check should be replaced by per-call ACL checks. */
173 if (who_e
!= RS_PROC_NR
) {
174 printf("PM: unauthorized call of do_getprocnr by %d\n", who_e
);
178 if ((rmp
= find_proc(m_in
.PM_GETPROCNR_PID
)) == NULL
)
181 mp
->mp_reply
.PM_GETPROCNR_ENDPT
= rmp
->mp_endpoint
;
185 /*===========================================================================*
187 *===========================================================================*/
188 int do_getepinfo(void)
194 ep
= m_in
.PM_GETEPINFO_ENDPT
;
195 if (pm_isokendpt(ep
, &slot
) != OK
)
199 mp
->mp_reply
.PM_GETEPINFO_UID
= rmp
->mp_effuid
;
200 mp
->mp_reply
.PM_GETEPINFO_GID
= rmp
->mp_effgid
;
204 /*===========================================================================*
206 *===========================================================================*/
211 /* Check permission to abort the system. */
212 if (mp
->mp_effuid
!= SUPER_USER
) return(EPERM
);
214 /* See how the system should be aborted. */
215 abort_flag
= (unsigned) m_in
.PM_REBOOT_HOW
;
217 /* notify readclock (some arm systems power off via RTC alarms) */
218 if (abort_flag
& RB_POWERDOWN
) {
219 endpoint_t readclock_ep
;
220 if (ds_retrieve_label_endpt("readclock.drv", &readclock_ep
) == OK
) {
221 message m
; /* no params to set, nothing we can do if it fails */
222 _taskcall(readclock_ep
, RTCDEV_PWR_OFF
, &m
);
226 /* Order matters here. When VFS is told to reboot, it exits all its
227 * processes, and then would be confused if they're exited again by
228 * SIGKILL. So first kill, then reboot.
231 check_sig(-1, SIGKILL
, FALSE
/* ksig*/); /* kill all users except init */
232 sys_stop(INIT_PROC_NR
); /* stop init, but keep it around */
234 /* Tell VFS to reboot */
235 memset(&m
, 0, sizeof(m
));
236 m
.m_type
= VFS_PM_REBOOT
;
238 tell_vfs(&mproc
[VFS_PROC_NR
], &m
);
240 return(SUSPEND
); /* don't reply to caller */
243 /*===========================================================================*
244 * do_getsetpriority *
245 *===========================================================================*/
246 int do_getsetpriority()
248 int r
, arg_which
, arg_who
, arg_pri
;
251 arg_which
= m_in
.PM_PRIORITY_WHICH
;
252 arg_who
= m_in
.PM_PRIORITY_WHO
;
253 arg_pri
= m_in
.PM_PRIORITY_PRIO
; /* for SETPRIORITY */
255 /* Code common to GETPRIORITY and SETPRIORITY. */
257 /* Only support PRIO_PROCESS for now. */
258 if (arg_which
!= PRIO_PROCESS
)
264 if ((rmp
= find_proc(arg_who
)) == NULL
)
267 if (mp
->mp_effuid
!= SUPER_USER
&&
268 mp
->mp_effuid
!= rmp
->mp_effuid
&& mp
->mp_effuid
!= rmp
->mp_realuid
)
271 /* If GET, that's it. */
272 if (call_nr
== PM_GETPRIORITY
) {
273 return(rmp
->mp_nice
- PRIO_MIN
);
276 /* Only root is allowed to reduce the nice level. */
277 if (rmp
->mp_nice
> arg_pri
&& mp
->mp_effuid
!= SUPER_USER
)
280 /* We're SET, and it's allowed.
282 * The value passed in is currently between PRIO_MIN and PRIO_MAX.
283 * We have to scale this between MIN_USER_Q and MAX_USER_Q to match
284 * the kernel's scheduling queues.
287 if ((r
= sched_nice(rmp
, arg_pri
)) != OK
) {
291 rmp
->mp_nice
= arg_pri
;
295 /*===========================================================================*
297 *===========================================================================*/
302 #define MAX_LOCAL_PARAMS 2
306 } local_param_overrides
[MAX_LOCAL_PARAMS
];
307 static int local_params
= 0;
309 req
= m_in
.SVRCTL_REQ
;
310 ptr
= (vir_bytes
) m_in
.SVRCTL_ARG
;
312 /* Is the request indeed for the PM? */
313 if (((req
>> 8) & 0xFF) != 'M') return(EINVAL
);
315 /* Control operations local to the PM. */
319 struct sysgetenv sysgetenv
;
325 /* Copy sysgetenv structure to PM. */
326 if (sys_datacopy(who_e
, ptr
, SELF
, (vir_bytes
) &sysgetenv
,
327 sizeof(sysgetenv
)) != OK
) return(EFAULT
);
329 /* Set a param override? */
330 if (req
== PMSETPARAM
) {
331 if (local_params
>= MAX_LOCAL_PARAMS
) return ENOSPC
;
332 if (sysgetenv
.keylen
<= 0
333 || sysgetenv
.keylen
>=
334 sizeof(local_param_overrides
[local_params
].name
)
335 || sysgetenv
.vallen
<= 0
336 || sysgetenv
.vallen
>=
337 sizeof(local_param_overrides
[local_params
].value
))
340 if ((s
= sys_datacopy(who_e
, (vir_bytes
) sysgetenv
.key
,
341 SELF
, (vir_bytes
) local_param_overrides
[local_params
].name
,
342 sysgetenv
.keylen
)) != OK
)
344 if ((s
= sys_datacopy(who_e
, (vir_bytes
) sysgetenv
.val
,
345 SELF
, (vir_bytes
) local_param_overrides
[local_params
].value
,
346 sysgetenv
.vallen
)) != OK
)
348 local_param_overrides
[local_params
].name
[sysgetenv
.keylen
] = '\0';
349 local_param_overrides
[local_params
].value
[sysgetenv
.vallen
] = '\0';
356 if (sysgetenv
.keylen
== 0) { /* copy all parameters */
357 val_start
= monitor_params
;
358 val_len
= sizeof(monitor_params
);
360 else { /* lookup value for key */
362 /* Try to get a copy of the requested key. */
363 if (sysgetenv
.keylen
> sizeof(search_key
)) return(EINVAL
);
364 if ((s
= sys_datacopy(who_e
, (vir_bytes
) sysgetenv
.key
,
365 SELF
, (vir_bytes
) search_key
, sysgetenv
.keylen
)) != OK
)
368 /* Make sure key is null-terminated and lookup value.
369 * First check local overrides.
371 search_key
[sysgetenv
.keylen
-1]= '\0';
372 for(p
= 0; p
< local_params
; p
++) {
373 if (!strcmp(search_key
, local_param_overrides
[p
].name
)) {
374 val_start
= local_param_overrides
[p
].value
;
378 if (p
>= local_params
&& (val_start
= find_param(search_key
)) == NULL
)
380 val_len
= strlen(val_start
) + 1;
383 /* See if it fits in the client's buffer. */
384 if (val_len
> sysgetenv
.vallen
)
387 /* Value found, make the actual copy (as far as possible). */
388 copy_len
= MIN(val_len
, sysgetenv
.vallen
);
389 if ((s
=sys_datacopy(SELF
, (vir_bytes
) val_start
,
390 who_e
, (vir_bytes
) sysgetenv
.val
, copy_len
)) != OK
)
401 /*===========================================================================*
403 *===========================================================================*/
407 clock_t user_time
= 0;
408 clock_t sys_time
= 0;
409 struct rusage r_usage
;
411 if (m_in
.RU_WHO
!= RUSAGE_SELF
&& m_in
.RU_WHO
!= RUSAGE_CHILDREN
)
413 if ((res
= sys_getrusage(&r_usage
, who_e
)) < 0)
416 if (m_in
.RU_WHO
== RUSAGE_CHILDREN
) {
417 usec
= mp
->mp_child_utime
* 1000000 / sys_hz();
418 r_usage
.ru_utime
.tv_sec
= usec
/ 1000000;
419 r_usage
.ru_utime
.tv_usec
= usec
% 1000000;
420 usec
= mp
->mp_child_stime
* 1000000 / sys_hz();
421 r_usage
.ru_stime
.tv_sec
= usec
/ 1000000;
422 r_usage
.ru_stime
.tv_usec
= usec
% 1000000;
425 return sys_datacopy(SELF
, (vir_bytes
) &r_usage
, who_e
,
426 (vir_bytes
) m_in
.RU_RUSAGE_ADDR
, (vir_bytes
) sizeof(r_usage
));