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 10 * do_getrusage: obtain process resource usage information 11 */ 12 13 #include "pm.h" 14 #include <minix/callnr.h> 15 #include <signal.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> 24 #include <minix/ds.h> 25 #include <machine/archtypes.h> 26 #include <lib.h> 27 #include <assert.h> 28 #include "mproc.h" 29 #include "kernel/proc.h" 30 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)) */ 37 #if defined(__i386__) 38 "i386", /* machine (cpu) type */ 39 #elif defined(__arm__) 40 "evbarm", /* machine (cpu) type */ 41 #else 42 #error /* oops, no 'uname -mk' */ 43 #endif 44 }; 45 46 static char *uts_tbl[] = { 47 #if defined(__i386__) 48 "i386", /* architecture */ 49 #elif defined(__arm__) 50 "evbarm", /* architecture */ 51 #endif 52 NULL, /* No kernel architecture */ 53 uts_val.machine, 54 NULL, /* No hostname */ 55 uts_val.nodename, 56 uts_val.release, 57 uts_val.version, 58 uts_val.sysname, 59 NULL, /* No bus */ /* No bus */ 60 }; 61 /* END OF COMPATIBILITY BLOCK */ 62 63 #if ENABLE_SYSCALL_STATS 64 unsigned long calls_stats[NR_PM_CALLS]; 65 #endif 66 67 /* START OF COMPATIBILITY BLOCK */ 68 /*===========================================================================* 69 * do_sysuname * 70 *===========================================================================*/ 71 int 72 do_sysuname(void) 73 { 74 /* Set or get uname strings. */ 75 int r; 76 size_t n; 77 char *string; 78 79 if (m_in.m_lc_pm_sysuname.field >= __arraycount(uts_tbl)) return(EINVAL); 80 81 string = uts_tbl[m_in.m_lc_pm_sysuname.field]; 82 if (string == NULL) 83 return EINVAL; /* Unsupported field */ 84 85 switch (m_in.m_lc_pm_sysuname.req) { 86 case 0: 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); 92 if (r < 0) return(r); 93 break; 94 95 default: 96 return(EINVAL); 97 } 98 /* Return the number of bytes moved. */ 99 return(n); 100 } 101 /* END OF COMPATIBILITY BLOCK */ 102 103 104 /*===========================================================================* 105 * do_getsysinfo * 106 *===========================================================================*/ 107 int 108 do_getsysinfo(void) 109 { 110 vir_bytes src_addr, dst_addr; 111 size_t len; 112 113 /* This call leaks important information. In the future, requests from 114 * non-system processes should be denied. 115 */ 116 if (mp->mp_effuid != 0) 117 { 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); 121 return EPERM; 122 } 123 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; 128 break; 129 #if ENABLE_SYSCALL_STATS 130 case SI_CALL_STATS: 131 src_addr = (vir_bytes) calls_stats; 132 len = sizeof(calls_stats); 133 break; 134 #endif 135 default: 136 return(EINVAL); 137 } 138 139 if (len != m_in.m_lsys_getsysinfo.size) 140 return(EINVAL); 141 142 dst_addr = m_in.m_lsys_getsysinfo.where; 143 return sys_datacopy(SELF, src_addr, who_e, dst_addr, len); 144 } 145 146 /*===========================================================================* 147 * do_getprocnr * 148 *===========================================================================*/ 149 int do_getprocnr(void) 150 { 151 register struct mproc *rmp; 152 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); 156 return EPERM; 157 } 158 159 if ((rmp = find_proc(m_in.m_lsys_pm_getprocnr.pid)) == NULL) 160 return(ESRCH); 161 162 mp->mp_reply.m_pm_lsys_getprocnr.endpt = rmp->mp_endpoint; 163 return(OK); 164 } 165 166 /*===========================================================================* 167 * do_getepinfo * 168 *===========================================================================*/ 169 int do_getepinfo(void) 170 { 171 struct mproc *rmp; 172 endpoint_t ep; 173 int slot; 174 175 ep = m_in.m_lsys_pm_getepinfo.endpt; 176 if (pm_isokendpt(ep, &slot) != OK) 177 return(ESRCH); 178 179 rmp = &mproc[slot]; 180 mp->mp_reply.m_pm_lsys_getepinfo.uid = rmp->mp_effuid; 181 mp->mp_reply.m_pm_lsys_getepinfo.gid = rmp->mp_effgid; 182 return(rmp->mp_pid); 183 } 184 185 /*===========================================================================* 186 * do_reboot * 187 *===========================================================================*/ 188 int 189 do_reboot(void) 190 { 191 message m; 192 193 /* Check permission to abort the system. */ 194 if (mp->mp_effuid != SUPER_USER) return(EPERM); 195 196 /* See how the system should be aborted. */ 197 abort_flag = m_in.m_lc_pm_reboot.how; 198 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); 205 } 206 } 207 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. 211 */ 212 213 check_sig(-1, SIGKILL, FALSE /* ksig*/); /* kill all users except init */ 214 sys_stop(INIT_PROC_NR); /* stop init, but keep it around */ 215 216 /* Tell VFS to reboot */ 217 memset(&m, 0, sizeof(m)); 218 m.m_type = VFS_PM_REBOOT; 219 220 tell_vfs(&mproc[VFS_PROC_NR], &m); 221 222 return(SUSPEND); /* don't reply to caller */ 223 } 224 225 /*===========================================================================* 226 * do_getsetpriority * 227 *===========================================================================*/ 228 int 229 do_getsetpriority(void) 230 { 231 int r, arg_which, arg_who, arg_pri; 232 struct mproc *rmp; 233 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 */ 237 238 /* Code common to GETPRIORITY and SETPRIORITY. */ 239 240 /* Only support PRIO_PROCESS for now. */ 241 if (arg_which != PRIO_PROCESS) 242 return(EINVAL); 243 244 if (arg_who == 0) 245 rmp = mp; 246 else 247 if ((rmp = find_proc(arg_who)) == NULL) 248 return(ESRCH); 249 250 if (mp->mp_effuid != SUPER_USER && 251 mp->mp_effuid != rmp->mp_effuid && mp->mp_effuid != rmp->mp_realuid) 252 return EPERM; 253 254 /* If GET, that's it. */ 255 if (call_nr == PM_GETPRIORITY) { 256 return(rmp->mp_nice - PRIO_MIN); 257 } 258 259 /* Only root is allowed to reduce the nice level. */ 260 if (rmp->mp_nice > arg_pri && mp->mp_effuid != SUPER_USER) 261 return(EACCES); 262 263 /* We're SET, and it's allowed. 264 * 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. 268 */ 269 270 if ((r = sched_nice(rmp, arg_pri)) != OK) { 271 return r; 272 } 273 274 rmp->mp_nice = arg_pri; 275 return(OK); 276 } 277 278 /*===========================================================================* 279 * do_svrctl * 280 *===========================================================================*/ 281 int do_svrctl(void) 282 { 283 unsigned long req; 284 int s; 285 vir_bytes ptr; 286 #define MAX_LOCAL_PARAMS 2 287 static struct { 288 char name[30]; 289 char value[30]; 290 } local_param_overrides[MAX_LOCAL_PARAMS]; 291 static int local_params = 0; 292 293 req = m_in.m_lc_svrctl.request; 294 ptr = m_in.m_lc_svrctl.arg; 295 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); 298 299 /* Control operations local to the PM. */ 300 switch(req) { 301 case OPMSETPARAM: 302 case OPMGETPARAM: 303 case PMSETPARAM: 304 case PMGETPARAM: { 305 struct sysgetenv sysgetenv; 306 char search_key[64]; 307 char *val_start; 308 size_t val_len; 309 size_t copy_len; 310 311 /* Copy sysgetenv structure to PM. */ 312 if (sys_datacopy(who_e, ptr, SELF, (vir_bytes) &sysgetenv, 313 sizeof(sysgetenv)) != OK) return(EFAULT); 314 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)) 324 return EINVAL; 325 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) 329 return s; 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) 333 return s; 334 local_param_overrides[local_params].name[sysgetenv.keylen] = '\0'; 335 local_param_overrides[local_params].value[sysgetenv.vallen] = '\0'; 336 337 local_params++; 338 339 return OK; 340 } 341 342 if (sysgetenv.keylen == 0) { /* copy all parameters */ 343 val_start = monitor_params; 344 val_len = sizeof(monitor_params); 345 } 346 else { /* lookup value for key */ 347 int p; 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) 352 return(s); 353 354 /* Make sure key is null-terminated and lookup value. 355 * First check local overrides. 356 */ 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; 361 break; 362 } 363 } 364 if (p >= local_params && (val_start = find_param(search_key)) == NULL) 365 return(ESRCH); 366 val_len = strlen(val_start) + 1; 367 } 368 369 /* See if it fits in the client's buffer. */ 370 if (val_len > sysgetenv.vallen) 371 return E2BIG; 372 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) 377 return(s); 378 379 return OK; 380 } 381 382 default: 383 return(EINVAL); 384 } 385 } 386 387 /*===========================================================================* 388 * do_getrusage * 389 *===========================================================================*/ 390 int 391 do_getrusage(void) 392 { 393 clock_t user_time, sys_time; 394 struct rusage r_usage; 395 int r, children; 396 397 if (m_in.m_lc_pm_rusage.who != RUSAGE_SELF && 398 m_in.m_lc_pm_rusage.who != RUSAGE_CHILDREN) 399 return EINVAL; 400 401 /* 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. 407 */ 408 409 memset(&r_usage, 0, sizeof(r_usage)); 410 411 children = (m_in.m_lc_pm_rusage.who == RUSAGE_CHILDREN); 412 413 /* 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. 417 */ 418 if (!children) { 419 if ((r = sys_times(who_e, &user_time, &sys_time, NULL, 420 NULL)) != OK) 421 return r; 422 } else { 423 user_time = mp->mp_child_utime; 424 sys_time = mp->mp_child_stime; 425 } 426 427 /* In both cases, convert from clock ticks to microseconds. */ 428 set_rusage_times(&r_usage, user_time, sys_time); 429 430 /* Get additional fields from VM. */ 431 if ((r = vm_getrusage(who_e, &r_usage, children)) != OK) 432 return r; 433 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)); 437 } 438