64-bit VFS_LSEEK_OFF
[minix3.git] / servers / pm / misc.c
blob0e409e018fa427547b5889eed7227f75737a2fae
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_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
12 #include "pm.h"
13 #include <minix/callnr.h>
14 #include <signal.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>
23 #include <minix/ds.h>
24 #include <machine/archtypes.h>
25 #include <lib.h>
26 #include <assert.h>
27 #include "mproc.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) */
36 #if defined(__i386__)
37 "i386", /* architecture */
38 #elif defined(__arm__)
39 "arm", /* architecture */
40 #else
41 #error /* oops, no 'uname -mk' */
42 #endif
45 static char *uts_tbl[] = {
46 uts_val.arch,
47 NULL, /* No kernel architecture */
48 uts_val.machine,
49 NULL, /* No hostname */
50 uts_val.nodename,
51 uts_val.release,
52 uts_val.version,
53 uts_val.sysname,
54 NULL, /* No bus */ /* No bus */
57 #if ENABLE_SYSCALL_STATS
58 unsigned long calls_stats[NR_PM_CALLS];
59 #endif
61 /*===========================================================================*
62 * do_sysuname *
63 *===========================================================================*/
64 int do_sysuname()
66 /* Set or get uname strings. */
67 int r;
68 size_t n;
69 char *string;
70 #if 0 /* for updates */
71 char tmp[sizeof(uts_val.nodename)];
72 static short sizes[] = {
73 0, /* arch, (0 = read-only) */
74 0, /* kernel */
75 0, /* machine */
76 0, /* sizeof(uts_val.hostname), */
77 sizeof(uts_val.nodename),
78 0, /* release */
79 0, /* version */
80 0, /* sysname */
82 #endif
84 if ((unsigned) m_in.PM_SYSUNAME_FIELD >= _UTS_MAX) return(EINVAL);
86 string = uts_tbl[m_in.PM_SYSUNAME_FIELD];
87 if (string == NULL)
88 return EINVAL; /* Unsupported field */
90 switch (m_in.PM_SYSUNAME_REQ) {
91 case _UTS_GET:
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,
97 (phys_bytes) n);
98 if (r < 0) return(r);
99 break;
101 #if 0 /* no updates yet */
102 case _UTS_SET:
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);
111 tmp[n-1] = 0;
112 strcpy(string, tmp);
113 break;
114 #endif
116 default:
117 return(EINVAL);
119 /* Return the number of bytes moved. */
120 return(n);
124 /*===========================================================================*
125 * do_getsysinfo *
126 *===========================================================================*/
127 int do_getsysinfo()
129 vir_bytes src_addr, dst_addr;
130 size_t len;
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);
140 return EPERM;
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;
147 break;
148 #if ENABLE_SYSCALL_STATS
149 case SI_CALL_STATS:
150 src_addr = (vir_bytes) calls_stats;
151 len = sizeof(calls_stats);
152 break;
153 #endif
154 default:
155 return(EINVAL);
158 if (len != m_in.SI_SIZE)
159 return(EINVAL);
161 dst_addr = (vir_bytes) m_in.SI_WHERE;
162 return sys_datacopy(SELF, src_addr, who_e, dst_addr, len);
165 /*===========================================================================*
166 * do_getprocnr *
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);
175 return EPERM;
178 if ((rmp = find_proc(m_in.PM_GETPROCNR_PID)) == NULL)
179 return(ESRCH);
181 mp->mp_reply.PM_GETPROCNR_ENDPT = rmp->mp_endpoint;
182 return(OK);
185 /*===========================================================================*
186 * do_getepinfo *
187 *===========================================================================*/
188 int do_getepinfo(void)
190 struct mproc *rmp;
191 endpoint_t ep;
192 int slot;
194 ep = m_in.PM_GETEPINFO_ENDPT;
195 if (pm_isokendpt(ep, &slot) != OK)
196 return(ESRCH);
198 rmp = &mproc[slot];
199 mp->mp_reply.PM_GETEPINFO_UID = rmp->mp_effuid;
200 mp->mp_reply.PM_GETEPINFO_GID = rmp->mp_effgid;
201 return(rmp->mp_pid);
204 /*===========================================================================*
205 * do_reboot *
206 *===========================================================================*/
207 int do_reboot()
209 message m;
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;
249 struct mproc *rmp;
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)
259 return(EINVAL);
261 if (arg_who == 0)
262 rmp = mp;
263 else
264 if ((rmp = find_proc(arg_who)) == NULL)
265 return(ESRCH);
267 if (mp->mp_effuid != SUPER_USER &&
268 mp->mp_effuid != rmp->mp_effuid && mp->mp_effuid != rmp->mp_realuid)
269 return EPERM;
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)
278 return(EACCES);
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) {
288 return r;
291 rmp->mp_nice = arg_pri;
292 return(OK);
295 /*===========================================================================*
296 * do_svrctl *
297 *===========================================================================*/
298 int do_svrctl()
300 int s, req;
301 vir_bytes ptr;
302 #define MAX_LOCAL_PARAMS 2
303 static struct {
304 char name[30];
305 char value[30];
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. */
316 switch(req) {
317 case PMSETPARAM:
318 case PMGETPARAM: {
319 struct sysgetenv sysgetenv;
320 char search_key[64];
321 char *val_start;
322 size_t val_len;
323 size_t copy_len;
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))
338 return EINVAL;
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)
343 return s;
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)
347 return s;
348 local_param_overrides[local_params].name[sysgetenv.keylen] = '\0';
349 local_param_overrides[local_params].value[sysgetenv.vallen] = '\0';
351 local_params++;
353 return OK;
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 */
361 int p;
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)
366 return(s);
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;
375 break;
378 if (p >= local_params && (val_start = find_param(search_key)) == NULL)
379 return(ESRCH);
380 val_len = strlen(val_start) + 1;
383 /* See if it fits in the client's buffer. */
384 if (val_len > sysgetenv.vallen)
385 return E2BIG;
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)
391 return(s);
393 return OK;
396 default:
397 return(EINVAL);
401 /*===========================================================================*
402 * do_getrusage *
403 *===========================================================================*/
404 int do_getrusage()
406 int res = 0;
407 clock_t user_time = 0;
408 clock_t sys_time = 0;
409 struct rusage r_usage;
410 u64_t usec;
411 if (m_in.RU_WHO != RUSAGE_SELF && m_in.RU_WHO != RUSAGE_CHILDREN)
412 return EINVAL;
413 if ((res = sys_getrusage(&r_usage, who_e)) < 0)
414 return res;
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));