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
10 * do_getrusage: obtain process resource usage information
14 #include <minix/callnr.h>
16 #include <sys/svrctl.h>
17 #include <sys/reboot.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>
25 #include <machine/archtypes.h>
29 #include "kernel/proc.h"
31 /* START OF COMPATIBILITY BLOCK */
32 struct utsname uts_val
= {
33 OS_NAME
, /* system name */
34 "noname", /* node/network name */
35 OS_RELEASE
, /* O.S. release (e.g. 3.3.0) */
36 OS_VERSION
, /* O.S. version (e.g. Minix 3.3.0 (GENERIC)) */
38 "i386", /* machine (cpu) type */
39 #elif defined(__arm__)
40 "evbarm", /* machine (cpu) type */
42 #error /* oops, no 'uname -mk' */
46 static char *uts_tbl
[] = {
48 "i386", /* architecture */
49 #elif defined(__arm__)
50 "evbarm", /* architecture */
52 NULL
, /* No kernel architecture */
54 NULL
, /* No hostname */
59 NULL
, /* No bus */ /* No bus */
61 /* END OF COMPATIBILITY BLOCK */
63 #if ENABLE_SYSCALL_STATS
64 unsigned long calls_stats
[NR_PM_CALLS
];
67 /* START OF COMPATIBILITY BLOCK */
68 /*===========================================================================*
70 *===========================================================================*/
74 /* Set or get uname strings. */
79 if (m_in
.m_lc_pm_sysuname
.field
>= __arraycount(uts_tbl
)) return(EINVAL
);
81 string
= uts_tbl
[m_in
.m_lc_pm_sysuname
.field
];
83 return EINVAL
; /* Unsupported field */
85 switch (m_in
.m_lc_pm_sysuname
.req
) {
87 /* Copy an uname string to the user. */
88 n
= strlen(string
) + 1;
89 if (n
> m_in
.m_lc_pm_sysuname
.len
) n
= m_in
.m_lc_pm_sysuname
.len
;
90 r
= sys_datacopy(SELF
, (vir_bytes
)string
, mp
->mp_endpoint
,
91 m_in
.m_lc_pm_sysuname
.value
, (phys_bytes
)n
);
98 /* Return the number of bytes moved. */
101 /* END OF COMPATIBILITY BLOCK */
104 /*===========================================================================*
106 *===========================================================================*/
110 vir_bytes src_addr
, dst_addr
;
113 /* This call leaks important information. In the future, requests from
114 * non-system processes should be denied.
116 if (mp
->mp_effuid
!= 0)
118 printf("PM: unauthorized call of do_getsysinfo by proc %d '%s'\n",
119 mp
->mp_endpoint
, mp
->mp_name
);
120 sys_diagctl_stacktrace(mp
->mp_endpoint
);
124 switch(m_in
.m_lsys_getsysinfo
.what
) {
125 case SI_PROC_TAB
: /* copy entire process table */
126 src_addr
= (vir_bytes
) mproc
;
127 len
= sizeof(struct mproc
) * NR_PROCS
;
129 #if ENABLE_SYSCALL_STATS
131 src_addr
= (vir_bytes
) calls_stats
;
132 len
= sizeof(calls_stats
);
139 if (len
!= m_in
.m_lsys_getsysinfo
.size
)
142 dst_addr
= m_in
.m_lsys_getsysinfo
.where
;
143 return sys_datacopy(SELF
, src_addr
, who_e
, dst_addr
, len
);
146 /*===========================================================================*
148 *===========================================================================*/
149 int do_getprocnr(void)
151 register struct mproc
*rmp
;
153 /* This check should be replaced by per-call ACL checks. */
154 if (who_e
!= RS_PROC_NR
) {
155 printf("PM: unauthorized call of do_getprocnr by %d\n", who_e
);
159 if ((rmp
= find_proc(m_in
.m_lsys_pm_getprocnr
.pid
)) == NULL
)
162 mp
->mp_reply
.m_pm_lsys_getprocnr
.endpt
= rmp
->mp_endpoint
;
166 /*===========================================================================*
168 *===========================================================================*/
169 int do_getepinfo(void)
175 ep
= m_in
.m_lsys_pm_getepinfo
.endpt
;
176 if (pm_isokendpt(ep
, &slot
) != OK
)
180 mp
->mp_reply
.m_pm_lsys_getepinfo
.uid
= rmp
->mp_effuid
;
181 mp
->mp_reply
.m_pm_lsys_getepinfo
.gid
= rmp
->mp_effgid
;
185 /*===========================================================================*
187 *===========================================================================*/
193 /* Check permission to abort the system. */
194 if (mp
->mp_effuid
!= SUPER_USER
) return(EPERM
);
196 /* See how the system should be aborted. */
197 abort_flag
= m_in
.m_lc_pm_reboot
.how
;
199 /* notify readclock (some arm systems power off via RTC alarms) */
200 if (abort_flag
& RB_POWERDOWN
) {
201 endpoint_t readclock_ep
;
202 if (ds_retrieve_label_endpt("readclock.drv", &readclock_ep
) == OK
) {
203 message m
; /* no params to set, nothing we can do if it fails */
204 _taskcall(readclock_ep
, RTCDEV_PWR_OFF
, &m
);
208 /* Order matters here. When VFS is told to reboot, it exits all its
209 * processes, and then would be confused if they're exited again by
210 * SIGKILL. So first kill, then reboot.
213 check_sig(-1, SIGKILL
, FALSE
/* ksig*/); /* kill all users except init */
214 sys_stop(INIT_PROC_NR
); /* stop init, but keep it around */
216 /* Tell VFS to reboot */
217 memset(&m
, 0, sizeof(m
));
218 m
.m_type
= VFS_PM_REBOOT
;
220 tell_vfs(&mproc
[VFS_PROC_NR
], &m
);
222 return(SUSPEND
); /* don't reply to caller */
225 /*===========================================================================*
226 * do_getsetpriority *
227 *===========================================================================*/
229 do_getsetpriority(void)
231 int r
, arg_which
, arg_who
, arg_pri
;
234 arg_which
= m_in
.m_lc_pm_priority
.which
;
235 arg_who
= m_in
.m_lc_pm_priority
.who
;
236 arg_pri
= m_in
.m_lc_pm_priority
.prio
; /* for SETPRIORITY */
238 /* Code common to GETPRIORITY and SETPRIORITY. */
240 /* Only support PRIO_PROCESS for now. */
241 if (arg_which
!= PRIO_PROCESS
)
247 if ((rmp
= find_proc(arg_who
)) == NULL
)
250 if (mp
->mp_effuid
!= SUPER_USER
&&
251 mp
->mp_effuid
!= rmp
->mp_effuid
&& mp
->mp_effuid
!= rmp
->mp_realuid
)
254 /* If GET, that's it. */
255 if (call_nr
== PM_GETPRIORITY
) {
256 return(rmp
->mp_nice
- PRIO_MIN
);
259 /* Only root is allowed to reduce the nice level. */
260 if (rmp
->mp_nice
> arg_pri
&& mp
->mp_effuid
!= SUPER_USER
)
263 /* We're SET, and it's allowed.
265 * The value passed in is currently between PRIO_MIN and PRIO_MAX.
266 * We have to scale this between MIN_USER_Q and MAX_USER_Q to match
267 * the kernel's scheduling queues.
270 if ((r
= sched_nice(rmp
, arg_pri
)) != OK
) {
274 rmp
->mp_nice
= arg_pri
;
278 /*===========================================================================*
280 *===========================================================================*/
286 #define MAX_LOCAL_PARAMS 2
290 } local_param_overrides
[MAX_LOCAL_PARAMS
];
291 static int local_params
= 0;
293 req
= m_in
.m_lc_svrctl
.request
;
294 ptr
= m_in
.m_lc_svrctl
.arg
;
296 /* Is the request indeed for the PM? ('M' is old and being phased out) */
297 if (IOCGROUP(req
) != 'P' && IOCGROUP(req
) != 'M') return(EINVAL
);
299 /* Control operations local to the PM. */
305 struct sysgetenv sysgetenv
;
311 /* Copy sysgetenv structure to PM. */
312 if (sys_datacopy(who_e
, ptr
, SELF
, (vir_bytes
) &sysgetenv
,
313 sizeof(sysgetenv
)) != OK
) return(EFAULT
);
315 /* Set a param override? */
316 if (req
== PMSETPARAM
|| req
== OPMSETPARAM
) {
317 if (local_params
>= MAX_LOCAL_PARAMS
) return ENOSPC
;
318 if (sysgetenv
.keylen
<= 0
319 || sysgetenv
.keylen
>=
320 sizeof(local_param_overrides
[local_params
].name
)
321 || sysgetenv
.vallen
<= 0
322 || sysgetenv
.vallen
>=
323 sizeof(local_param_overrides
[local_params
].value
))
326 if ((s
= sys_datacopy(who_e
, (vir_bytes
) sysgetenv
.key
,
327 SELF
, (vir_bytes
) local_param_overrides
[local_params
].name
,
328 sysgetenv
.keylen
)) != OK
)
330 if ((s
= sys_datacopy(who_e
, (vir_bytes
) sysgetenv
.val
,
331 SELF
, (vir_bytes
) local_param_overrides
[local_params
].value
,
332 sysgetenv
.vallen
)) != OK
)
334 local_param_overrides
[local_params
].name
[sysgetenv
.keylen
] = '\0';
335 local_param_overrides
[local_params
].value
[sysgetenv
.vallen
] = '\0';
342 if (sysgetenv
.keylen
== 0) { /* copy all parameters */
343 val_start
= monitor_params
;
344 val_len
= sizeof(monitor_params
);
346 else { /* lookup value for key */
348 /* Try to get a copy of the requested key. */
349 if (sysgetenv
.keylen
> sizeof(search_key
)) return(EINVAL
);
350 if ((s
= sys_datacopy(who_e
, (vir_bytes
) sysgetenv
.key
,
351 SELF
, (vir_bytes
) search_key
, sysgetenv
.keylen
)) != OK
)
354 /* Make sure key is null-terminated and lookup value.
355 * First check local overrides.
357 search_key
[sysgetenv
.keylen
-1]= '\0';
358 for(p
= 0; p
< local_params
; p
++) {
359 if (!strcmp(search_key
, local_param_overrides
[p
].name
)) {
360 val_start
= local_param_overrides
[p
].value
;
364 if (p
>= local_params
&& (val_start
= find_param(search_key
)) == NULL
)
366 val_len
= strlen(val_start
) + 1;
369 /* See if it fits in the client's buffer. */
370 if (val_len
> sysgetenv
.vallen
)
373 /* Value found, make the actual copy (as far as possible). */
374 copy_len
= MIN(val_len
, sysgetenv
.vallen
);
375 if ((s
=sys_datacopy(SELF
, (vir_bytes
) val_start
,
376 who_e
, (vir_bytes
) sysgetenv
.val
, copy_len
)) != OK
)
387 /*===========================================================================*
389 *===========================================================================*/
393 clock_t user_time
, sys_time
;
394 struct rusage r_usage
;
397 if (m_in
.m_lc_pm_rusage
.who
!= RUSAGE_SELF
&&
398 m_in
.m_lc_pm_rusage
.who
!= RUSAGE_CHILDREN
)
402 * TODO: first relay the call to VFS. As is, VFS does not have any
403 * fields it can fill with meaningful values, but this may change in
404 * the future. In that case, PM would first have to use the tell_vfs()
405 * system to get those values from VFS, and do the rest here upon
406 * getting the response.
409 memset(&r_usage
, 0, sizeof(r_usage
));
411 children
= (m_in
.m_lc_pm_rusage
.who
== RUSAGE_CHILDREN
);
414 * Get system times. For RUSAGE_SELF, get the times for the calling
415 * process from the kernel. For RUSAGE_CHILDREN, we already have the
416 * values we should return right here.
419 if ((r
= sys_times(who_e
, &user_time
, &sys_time
, NULL
,
423 user_time
= mp
->mp_child_utime
;
424 sys_time
= mp
->mp_child_stime
;
427 /* In both cases, convert from clock ticks to microseconds. */
428 set_rusage_times(&r_usage
, user_time
, sys_time
);
430 /* Get additional fields from VM. */
431 if ((r
= vm_getrusage(who_e
, &r_usage
, children
)) != OK
)
434 /* Finally copy the structure to the caller. */
435 return sys_datacopy(SELF
, (vir_bytes
)&r_usage
, who_e
,
436 m_in
.m_lc_pm_rusage
.addr
, (vir_bytes
)sizeof(r_usage
));