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_getepinfo: get the pid/uid/gid of a process given its endpoint
9 * do_getsetpriority: get/set process priority
10 * do_svrctl: process manager control
16 #include <minix/callnr.h>
18 #include <sys/svrctl.h>
19 #include <sys/resource.h>
20 #include <sys/utsname.h>
21 #include <minix/com.h>
22 #include <minix/config.h>
23 #include <minix/sysinfo.h>
24 #include <minix/type.h>
27 #include <machine/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 FORWARD
_PROTOTYPE( int getpciinfo
, (struct pciinfo
*pciinfo
) );
65 /*===========================================================================*
67 *===========================================================================*/
68 PUBLIC
int do_procstat()
70 /* For the moment, this is only used to return pending signals to
71 * system processes that request the PM for their own status.
73 * Future use might include the FS requesting for process status of
77 /* This call should be removed, or made more general. */
79 if (m_in
.stat_nr
== SELF
) {
80 mp
->mp_reply
.sig_set
= mp
->mp_sigpending
;
81 sigemptyset(&mp
->mp_sigpending
);
89 /*===========================================================================*
91 *===========================================================================*/
92 PUBLIC
int do_sysuname()
94 /* Set or get uname strings. */
99 #if 0 /* for updates */
100 char tmp
[sizeof(uts_val
.nodename
)];
101 static short sizes
[] = {
102 0, /* arch, (0 = read-only) */
105 0, /* sizeof(uts_val.hostname), */
106 sizeof(uts_val
.nodename
),
113 if ((unsigned) m_in
.sysuname_field
>= _UTS_MAX
) return(EINVAL
);
115 string
= uts_tbl
[m_in
.sysuname_field
];
117 return EINVAL
; /* Unsupported field */
119 switch (m_in
.sysuname_req
) {
121 /* Copy an uname string to the user. */
122 n
= strlen(string
) + 1;
123 if (n
> m_in
.sysuname_len
) n
= m_in
.sysuname_len
;
124 r
= sys_vircopy(SELF
, D
, (phys_bytes
) string
,
125 mp
->mp_endpoint
, D
, (phys_bytes
) m_in
.sysuname_value
,
127 if (r
< 0) return(r
);
130 #if 0 /* no updates yet */
132 /* Set an uname string, needs root power. */
133 len
= sizes
[m_in
.sysuname_field
];
134 if (mp
->mp_effuid
!= 0 || len
== 0) return(EPERM
);
135 n
= len
< m_in
.sysuname_len
? len
: m_in
.sysuname_len
;
136 if (n
<= 0) return(EINVAL
);
137 r
= sys_vircopy(mp
->mp_endpoint
, D
, (phys_bytes
) m_in
.sysuname_value
,
138 SELF
, D
, (phys_bytes
) tmp
, (phys_bytes
) n
);
139 if (r
< 0) return(r
);
148 /* Return the number of bytes moved. */
153 /*===========================================================================*
155 *===========================================================================*/
156 PUBLIC
int do_getsysinfo()
158 struct mproc
*proc_addr
;
159 vir_bytes src_addr
, dst_addr
;
161 struct loadinfo loadinfo
;
162 struct pciinfo pciinfo
;
163 static struct proc proctab
[NR_PROCS
+NR_TASKS
];
167 /* This call leaks important information (the contents of registers). */
168 if (mp
->mp_effuid
!= 0)
170 printf("PM: unauthorized call of do_getsysinfo by proc %d '%s'\n",
171 mp
->mp_endpoint
, mp
->mp_name
);
172 sys_sysctl_stacktrace(mp
->mp_endpoint
);
176 switch(m_in
.info_what
) {
177 case SI_KINFO
: /* kernel info is obtained via PM */
178 sys_getkinfo(&kinfo
);
179 src_addr
= (vir_bytes
) &kinfo
;
180 len
= sizeof(struct kinfo
);
182 case SI_PROC_ADDR
: /* get address of PM process table */
183 proc_addr
= &mproc
[0];
184 src_addr
= (vir_bytes
) &proc_addr
;
185 len
= sizeof(struct mproc
*);
187 case SI_PROC_TAB
: /* copy entire process table */
188 src_addr
= (vir_bytes
) mproc
;
189 len
= sizeof(struct mproc
) * NR_PROCS
;
191 case SI_KPROC_TAB
: /* copy entire process table */
192 if((r
=sys_getproctab(proctab
)) != OK
)
194 src_addr
= (vir_bytes
) proctab
;
195 len
= sizeof(proctab
);
197 case SI_LOADINFO
: /* loadinfo is obtained via PM */
198 sys_getloadinfo(&loadinfo
);
199 src_addr
= (vir_bytes
) &loadinfo
;
200 len
= sizeof(struct loadinfo
);
202 case SI_PCI_INFO
: /* PCI info is obtained via PM */
203 if ((r
=getpciinfo(&pciinfo
)) != OK
)
205 src_addr
= (vir_bytes
) &pciinfo
;
206 len
= sizeof(struct pciinfo
);
208 #if ENABLE_SYSCALL_STATS
210 src_addr
= (vir_bytes
) calls_stats
;
211 len
= sizeof(calls_stats
);
218 dst_addr
= (vir_bytes
) m_in
.info_where
;
219 if (OK
!= (s
=sys_datacopy(SELF
, src_addr
, who_e
, dst_addr
, len
)))
224 /*===========================================================================*
226 *===========================================================================*/
227 PUBLIC
int do_getsysinfo_up()
229 vir_bytes src_addr
, dst_addr
;
230 struct loadinfo loadinfo
;
231 size_t len
, real_len
;
235 switch(m_in
.SIU_WHAT
) {
236 case SIU_LOADINFO
: /* loadinfo is obtained via PM */
237 if ((s
= sys_getloadinfo(&loadinfo
)) != OK
)
239 src_addr
= (vir_bytes
) &loadinfo
;
240 real_len
= sizeof(struct loadinfo
);
243 src_addr
= (vir_bytes
) &system_hz
;
244 real_len
= sizeof(system_hz
);
247 if ((s
= sys_getidletsc(&idle_tsc
)) != OK
)
249 src_addr
= (vir_bytes
) &idle_tsc
;
250 real_len
= sizeof(idle_tsc
);
256 /* Let application know what the length was. */
258 if(len
> m_in
.SIU_LEN
)
261 dst_addr
= (vir_bytes
) m_in
.SIU_WHERE
;
262 if (OK
!= (s
=sys_datacopy(SELF
, src_addr
, who_e
, dst_addr
, len
)))
267 /*===========================================================================*
269 *===========================================================================*/
270 PUBLIC
int do_getprocnr()
272 register struct mproc
*rmp
;
273 static char search_key
[PROC_NAME_LEN
+1];
277 /* This call should be moved to DS. */
278 if (mp
->mp_effuid
!= 0)
280 /* For now, allow non-root processes to request their own endpoint. */
281 if (m_in
.pid
< 0 && m_in
.namelen
== 0) {
282 mp
->mp_reply
.PM_ENDPT
= who_e
;
283 mp
->mp_reply
.PM_PENDPT
= NONE
;
287 printf("PM: unauthorized call of do_getprocnr by proc %d\n",
289 sys_sysctl_stacktrace(mp
->mp_endpoint
);
294 printf("PM: do_getprocnr(%d) call from endpoint %d, %s\n",
295 m_in
.pid
, mp
->mp_endpoint
, mp
->mp_name
);
298 if (m_in
.pid
>= 0) { /* lookup process by pid */
299 if ((rmp
= find_proc(m_in
.pid
)) != NIL_MPROC
) {
300 mp
->mp_reply
.PM_ENDPT
= rmp
->mp_endpoint
;
302 printf("PM: pid result: %d\n", rmp
->mp_endpoint
);
307 } else if (m_in
.namelen
> 0) { /* lookup process by name */
308 key_len
= MIN(m_in
.namelen
, PROC_NAME_LEN
);
309 if (OK
!= (s
=sys_datacopy(who_e
, (vir_bytes
) m_in
.PMBRK_ADDR
,
310 SELF
, (vir_bytes
) search_key
, key_len
)))
312 search_key
[key_len
] = '\0'; /* terminate for safety */
313 for (rmp
= &mproc
[0]; rmp
< &mproc
[NR_PROCS
]; rmp
++) {
314 if (((rmp
->mp_flags
& (IN_USE
| EXITING
)) == IN_USE
) &&
315 strncmp(rmp
->mp_name
, search_key
, key_len
)==0) {
316 mp
->mp_reply
.PM_ENDPT
= rmp
->mp_endpoint
;
321 } else { /* return own/parent process number */
323 printf("PM: endpt result: %d\n", mp
->mp_reply
.PM_ENDPT
);
325 mp
->mp_reply
.PM_ENDPT
= who_e
;
326 mp
->mp_reply
.PM_PENDPT
= mproc
[mp
->mp_parent
].mp_endpoint
;
332 /*===========================================================================*
334 *===========================================================================*/
335 PUBLIC
int do_getepinfo()
337 register struct mproc
*rmp
;
340 /* This call should be moved to DS. */
341 if (mp
->mp_effuid
!= 0)
343 printf("PM: unauthorized call of do_getepinfo by proc %d\n",
345 sys_sysctl_stacktrace(mp
->mp_endpoint
);
351 for (rmp
= &mproc
[0]; rmp
< &mproc
[NR_PROCS
]; rmp
++) {
352 if ((rmp
->mp_flags
& IN_USE
) && (rmp
->mp_endpoint
== ep
)) {
353 mp
->mp_reply
.reply_res2
= rmp
->mp_effuid
;
354 mp
->mp_reply
.reply_res3
= rmp
->mp_effgid
;
359 /* Process not found */
363 /*===========================================================================*
365 *===========================================================================*/
366 PUBLIC
int do_reboot()
370 /* Check permission to abort the system. */
371 if (mp
->mp_effuid
!= SUPER_USER
) return(EPERM
);
373 /* See how the system should be aborted. */
374 abort_flag
= (unsigned) m_in
.reboot_flag
;
375 if (abort_flag
>= RBT_INVALID
) return(EINVAL
);
376 if (RBT_MONITOR
== abort_flag
) {
378 if(m_in
.reboot_strlen
>= sizeof(monitor_code
))
380 if((r
= sys_datacopy(who_e
, (vir_bytes
) m_in
.reboot_code
,
381 SELF
, (vir_bytes
) monitor_code
, m_in
.reboot_strlen
)) != OK
)
383 monitor_code
[m_in
.reboot_strlen
] = '\0';
386 monitor_code
[0] = '\0';
388 /* Order matters here. When FS is told to reboot, it exits all its
389 * processes, and then would be confused if they're exited again by
390 * SIGKILL. So first kill, then reboot.
393 check_sig(-1, SIGKILL
, FALSE
/* ksig*/); /* kill all users except init */
394 sys_stop(INIT_PROC_NR
); /* stop init, but keep it around */
396 /* Tell FS to reboot */
397 m
.m_type
= PM_REBOOT
;
399 tell_fs(&mproc
[FS_PROC_NR
], &m
);
401 return(SUSPEND
); /* don't reply to caller */
404 /*===========================================================================*
405 * do_getsetpriority *
406 *===========================================================================*/
407 PUBLIC
int do_getsetpriority()
409 int r
, arg_which
, arg_who
, arg_pri
, new_q
;
412 arg_which
= m_in
.m1_i1
;
413 arg_who
= m_in
.m1_i2
;
414 arg_pri
= m_in
.m1_i3
; /* for SETPRIORITY */
416 /* Code common to GETPRIORITY and SETPRIORITY. */
418 /* Only support PRIO_PROCESS for now. */
419 if (arg_which
!= PRIO_PROCESS
)
425 if ((rmp
= find_proc(arg_who
)) == NIL_MPROC
)
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.
443 * The value passed in is currently between PRIO_MIN and PRIO_MAX.
444 * We have to scale this between MIN_USER_Q and MAX_USER_Q to match
445 * the kernel's scheduling queues.
447 * TODO: This assumes that we are the scheduler, this will be changed
448 * once the scheduler gets factored out of PM to its own server
450 if (arg_pri
< PRIO_MIN
|| arg_pri
> PRIO_MAX
) return(EINVAL
);
452 new_q
= MAX_USER_Q
+ (arg_pri
-PRIO_MIN
) * (MIN_USER_Q
-MAX_USER_Q
+1) /
453 (PRIO_MAX
-PRIO_MIN
+1);
454 if (new_q
< MAX_USER_Q
) new_q
= MAX_USER_Q
; /* shouldn't happen */
455 if (new_q
> MIN_USER_Q
) new_q
= MIN_USER_Q
; /* shouldn't happen */
457 rmp
->mp_max_priority
= rmp
->mp_priority
= new_q
;
458 if ((r
= schedule_process(rmp
)))
461 rmp
->mp_nice
= arg_pri
;
465 /*===========================================================================*
467 *===========================================================================*/
468 PUBLIC
int do_svrctl()
472 #define MAX_LOCAL_PARAMS 2
476 } local_param_overrides
[MAX_LOCAL_PARAMS
];
477 static int local_params
= 0;
479 req
= m_in
.svrctl_req
;
480 ptr
= (vir_bytes
) m_in
.svrctl_argp
;
482 /* Is the request indeed for the MM? */
483 if (((req
>> 8) & 0xFF) != 'M') return(EINVAL
);
485 /* Control operations local to the PM. */
489 struct sysgetenv sysgetenv
;
495 /* Copy sysgetenv structure to PM. */
496 if (sys_datacopy(who_e
, ptr
, SELF
, (vir_bytes
) &sysgetenv
,
497 sizeof(sysgetenv
)) != OK
) return(EFAULT
);
499 /* Set a param override? */
500 if (req
== MMSETPARAM
) {
501 if (local_params
>= MAX_LOCAL_PARAMS
) return ENOSPC
;
502 if (sysgetenv
.keylen
<= 0
503 || sysgetenv
.keylen
>=
504 sizeof(local_param_overrides
[local_params
].name
)
505 || sysgetenv
.vallen
<= 0
506 || sysgetenv
.vallen
>=
507 sizeof(local_param_overrides
[local_params
].value
))
510 if ((s
= sys_datacopy(who_e
, (vir_bytes
) sysgetenv
.key
,
511 SELF
, (vir_bytes
) local_param_overrides
[local_params
].name
,
512 sysgetenv
.keylen
)) != OK
)
514 if ((s
= sys_datacopy(who_e
, (vir_bytes
) sysgetenv
.val
,
515 SELF
, (vir_bytes
) local_param_overrides
[local_params
].value
,
516 sysgetenv
.vallen
)) != OK
)
518 local_param_overrides
[local_params
].name
[sysgetenv
.keylen
] = '\0';
519 local_param_overrides
[local_params
].value
[sysgetenv
.vallen
] = '\0';
526 if (sysgetenv
.keylen
== 0) { /* copy all parameters */
527 val_start
= monitor_params
;
528 val_len
= sizeof(monitor_params
);
530 else { /* lookup value for key */
532 /* Try to get a copy of the requested key. */
533 if (sysgetenv
.keylen
> sizeof(search_key
)) return(EINVAL
);
534 if ((s
= sys_datacopy(who_e
, (vir_bytes
) sysgetenv
.key
,
535 SELF
, (vir_bytes
) search_key
, sysgetenv
.keylen
)) != OK
)
538 /* Make sure key is null-terminated and lookup value.
539 * First check local overrides.
541 search_key
[sysgetenv
.keylen
-1]= '\0';
542 for(p
= 0; p
< local_params
; p
++) {
543 if (!strcmp(search_key
, local_param_overrides
[p
].name
)) {
544 val_start
= local_param_overrides
[p
].value
;
548 if (p
>= local_params
&& (val_start
= find_param(search_key
)) == NULL
)
550 val_len
= strlen(val_start
) + 1;
553 /* See if it fits in the client's buffer. */
554 if (val_len
> sysgetenv
.vallen
)
557 /* Value found, make the actual copy (as far as possible). */
558 copy_len
= MIN(val_len
, sysgetenv
.vallen
);
559 if ((s
=sys_datacopy(SELF
, (vir_bytes
) val_start
,
560 who_e
, (vir_bytes
) sysgetenv
.val
, copy_len
)) != OK
)
571 /*===========================================================================*
573 *===========================================================================*/
575 extern char *_brksize
;
576 PUBLIC
int brk(brk_addr
)
580 /* PM wants to call brk() itself. */
581 if((r
=vm_brk(PM_PROC_NR
, brk_addr
)) != OK
) {
583 printf("PM: own brk(%p) failed: vm_brk() returned %d\n",
592 /*===========================================================================*
594 *===========================================================================*/
596 PRIVATE
int getpciinfo(pciinfo
)
597 struct pciinfo
*pciinfo
;
600 struct pciinfo_entry
*entry
;
604 /* look up PCI process number */
607 /* start enumerating devices */
608 entry
= pciinfo
->pi_entries
;
609 r
= pci_first_dev(&devind
, &vid
, &did
);
612 /* fetch device name */
613 name
= pci_dev_name(vid
, did
);
617 /* store device information in table */
618 assert((char *) entry
< (char *) (pciinfo
+ 1));
619 entry
->pie_vid
= vid
;
620 entry
->pie_did
= did
;
621 strncpy(entry
->pie_name
, name
, sizeof(entry
->pie_name
));
622 entry
->pie_name
[sizeof(entry
->pie_name
) - 1] = 0;
625 /* continue with the next device */
626 r
= pci_next_dev(&devind
, &vid
, &did
);
629 /* store number of entries */
630 pciinfo
->pi_count
= entry
- pciinfo
->pi_entries
;