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 do_sysuname() 72 { 73 /* Set or get uname strings. */ 74 int r; 75 size_t n; 76 char *string; 77 78 if (m_in.m_lc_pm_sysuname.field >= __arraycount(uts_tbl)) return(EINVAL); 79 80 string = uts_tbl[m_in.m_lc_pm_sysuname.field]; 81 if (string == NULL) 82 return EINVAL; /* Unsupported field */ 83 84 switch (m_in.m_lc_pm_sysuname.req) { 85 case 0: 86 /* Copy an uname string to the user. */ 87 n = strlen(string) + 1; 88 if (n > m_in.m_lc_pm_sysuname.len) n = m_in.m_lc_pm_sysuname.len; 89 r = sys_datacopy(SELF, (vir_bytes)string, mp->mp_endpoint, 90 m_in.m_lc_pm_sysuname.value, (phys_bytes)n); 91 if (r < 0) return(r); 92 break; 93 94 default: 95 return(EINVAL); 96 } 97 /* Return the number of bytes moved. */ 98 return(n); 99 } 100 /* END OF COMPATIBILITY BLOCK */ 101 102 103 /*===========================================================================* 104 * do_getsysinfo * 105 *===========================================================================*/ 106 int do_getsysinfo() 107 { 108 vir_bytes src_addr, dst_addr; 109 size_t len; 110 111 /* This call leaks important information. In the future, requests from 112 * non-system processes should be denied. 113 */ 114 if (mp->mp_effuid != 0) 115 { 116 printf("PM: unauthorized call of do_getsysinfo by proc %d '%s'\n", 117 mp->mp_endpoint, mp->mp_name); 118 sys_diagctl_stacktrace(mp->mp_endpoint); 119 return EPERM; 120 } 121 122 switch(m_in.m_lsys_getsysinfo.what) { 123 case SI_PROC_TAB: /* copy entire process table */ 124 src_addr = (vir_bytes) mproc; 125 len = sizeof(struct mproc) * NR_PROCS; 126 break; 127 #if ENABLE_SYSCALL_STATS 128 case SI_CALL_STATS: 129 src_addr = (vir_bytes) calls_stats; 130 len = sizeof(calls_stats); 131 break; 132 #endif 133 default: 134 return(EINVAL); 135 } 136 137 if (len != m_in.m_lsys_getsysinfo.size) 138 return(EINVAL); 139 140 dst_addr = m_in.m_lsys_getsysinfo.where; 141 return sys_datacopy(SELF, src_addr, who_e, dst_addr, len); 142 } 143 144 /*===========================================================================* 145 * do_getprocnr * 146 *===========================================================================*/ 147 int do_getprocnr(void) 148 { 149 register struct mproc *rmp; 150 151 /* This check should be replaced by per-call ACL checks. */ 152 if (who_e != RS_PROC_NR) { 153 printf("PM: unauthorized call of do_getprocnr by %d\n", who_e); 154 return EPERM; 155 } 156 157 if ((rmp = find_proc(m_in.m_lsys_pm_getprocnr.pid)) == NULL) 158 return(ESRCH); 159 160 mp->mp_reply.m_pm_lsys_getprocnr.endpt = rmp->mp_endpoint; 161 return(OK); 162 } 163 164 /*===========================================================================* 165 * do_getepinfo * 166 *===========================================================================*/ 167 int do_getepinfo(void) 168 { 169 struct mproc *rmp; 170 endpoint_t ep; 171 int slot; 172 173 ep = m_in.m_lsys_pm_getepinfo.endpt; 174 if (pm_isokendpt(ep, &slot) != OK) 175 return(ESRCH); 176 177 rmp = &mproc[slot]; 178 mp->mp_reply.m_pm_lsys_getepinfo.uid = rmp->mp_effuid; 179 mp->mp_reply.m_pm_lsys_getepinfo.gid = rmp->mp_effgid; 180 return(rmp->mp_pid); 181 } 182 183 /*===========================================================================* 184 * do_reboot * 185 *===========================================================================*/ 186 int do_reboot() 187 { 188 message m; 189 190 /* Check permission to abort the system. */ 191 if (mp->mp_effuid != SUPER_USER) return(EPERM); 192 193 /* See how the system should be aborted. */ 194 abort_flag = m_in.m_lc_pm_reboot.how; 195 196 /* notify readclock (some arm systems power off via RTC alarms) */ 197 if (abort_flag & RB_POWERDOWN) { 198 endpoint_t readclock_ep; 199 if (ds_retrieve_label_endpt("readclock.drv", &readclock_ep) == OK) { 200 message m; /* no params to set, nothing we can do if it fails */ 201 _taskcall(readclock_ep, RTCDEV_PWR_OFF, &m); 202 } 203 } 204 205 /* Order matters here. When VFS is told to reboot, it exits all its 206 * processes, and then would be confused if they're exited again by 207 * SIGKILL. So first kill, then reboot. 208 */ 209 210 check_sig(-1, SIGKILL, FALSE /* ksig*/); /* kill all users except init */ 211 sys_stop(INIT_PROC_NR); /* stop init, but keep it around */ 212 213 /* Tell VFS to reboot */ 214 memset(&m, 0, sizeof(m)); 215 m.m_type = VFS_PM_REBOOT; 216 217 tell_vfs(&mproc[VFS_PROC_NR], &m); 218 219 return(SUSPEND); /* don't reply to caller */ 220 } 221 222 /*===========================================================================* 223 * do_getsetpriority * 224 *===========================================================================*/ 225 int do_getsetpriority() 226 { 227 int r, arg_which, arg_who, arg_pri; 228 struct mproc *rmp; 229 230 arg_which = m_in.m_lc_pm_priority.which; 231 arg_who = m_in.m_lc_pm_priority.who; 232 arg_pri = m_in.m_lc_pm_priority.prio; /* for SETPRIORITY */ 233 234 /* Code common to GETPRIORITY and SETPRIORITY. */ 235 236 /* Only support PRIO_PROCESS for now. */ 237 if (arg_which != PRIO_PROCESS) 238 return(EINVAL); 239 240 if (arg_who == 0) 241 rmp = mp; 242 else 243 if ((rmp = find_proc(arg_who)) == NULL) 244 return(ESRCH); 245 246 if (mp->mp_effuid != SUPER_USER && 247 mp->mp_effuid != rmp->mp_effuid && mp->mp_effuid != rmp->mp_realuid) 248 return EPERM; 249 250 /* If GET, that's it. */ 251 if (call_nr == PM_GETPRIORITY) { 252 return(rmp->mp_nice - PRIO_MIN); 253 } 254 255 /* Only root is allowed to reduce the nice level. */ 256 if (rmp->mp_nice > arg_pri && mp->mp_effuid != SUPER_USER) 257 return(EACCES); 258 259 /* We're SET, and it's allowed. 260 * 261 * The value passed in is currently between PRIO_MIN and PRIO_MAX. 262 * We have to scale this between MIN_USER_Q and MAX_USER_Q to match 263 * the kernel's scheduling queues. 264 */ 265 266 if ((r = sched_nice(rmp, arg_pri)) != OK) { 267 return r; 268 } 269 270 rmp->mp_nice = arg_pri; 271 return(OK); 272 } 273 274 /*===========================================================================* 275 * do_svrctl * 276 *===========================================================================*/ 277 int do_svrctl(void) 278 { 279 unsigned long req; 280 int s; 281 vir_bytes ptr; 282 #define MAX_LOCAL_PARAMS 2 283 static struct { 284 char name[30]; 285 char value[30]; 286 } local_param_overrides[MAX_LOCAL_PARAMS]; 287 static int local_params = 0; 288 289 req = m_in.m_lc_svrctl.request; 290 ptr = m_in.m_lc_svrctl.arg; 291 292 /* Is the request indeed for the PM? ('M' is old and being phased out) */ 293 if (IOCGROUP(req) != 'P' && IOCGROUP(req) != 'M') return(EINVAL); 294 295 /* Control operations local to the PM. */ 296 switch(req) { 297 case OPMSETPARAM: 298 case OPMGETPARAM: 299 case PMSETPARAM: 300 case PMGETPARAM: { 301 struct sysgetenv sysgetenv; 302 char search_key[64]; 303 char *val_start; 304 size_t val_len; 305 size_t copy_len; 306 307 /* Copy sysgetenv structure to PM. */ 308 if (sys_datacopy(who_e, ptr, SELF, (vir_bytes) &sysgetenv, 309 sizeof(sysgetenv)) != OK) return(EFAULT); 310 311 /* Set a param override? */ 312 if (req == PMSETPARAM || req == OPMSETPARAM) { 313 if (local_params >= MAX_LOCAL_PARAMS) return ENOSPC; 314 if (sysgetenv.keylen <= 0 315 || sysgetenv.keylen >= 316 sizeof(local_param_overrides[local_params].name) 317 || sysgetenv.vallen <= 0 318 || sysgetenv.vallen >= 319 sizeof(local_param_overrides[local_params].value)) 320 return EINVAL; 321 322 if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.key, 323 SELF, (vir_bytes) local_param_overrides[local_params].name, 324 sysgetenv.keylen)) != OK) 325 return s; 326 if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.val, 327 SELF, (vir_bytes) local_param_overrides[local_params].value, 328 sysgetenv.vallen)) != OK) 329 return s; 330 local_param_overrides[local_params].name[sysgetenv.keylen] = '\0'; 331 local_param_overrides[local_params].value[sysgetenv.vallen] = '\0'; 332 333 local_params++; 334 335 return OK; 336 } 337 338 if (sysgetenv.keylen == 0) { /* copy all parameters */ 339 val_start = monitor_params; 340 val_len = sizeof(monitor_params); 341 } 342 else { /* lookup value for key */ 343 int p; 344 /* Try to get a copy of the requested key. */ 345 if (sysgetenv.keylen > sizeof(search_key)) return(EINVAL); 346 if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.key, 347 SELF, (vir_bytes) search_key, sysgetenv.keylen)) != OK) 348 return(s); 349 350 /* Make sure key is null-terminated and lookup value. 351 * First check local overrides. 352 */ 353 search_key[sysgetenv.keylen-1]= '\0'; 354 for(p = 0; p < local_params; p++) { 355 if (!strcmp(search_key, local_param_overrides[p].name)) { 356 val_start = local_param_overrides[p].value; 357 break; 358 } 359 } 360 if (p >= local_params && (val_start = find_param(search_key)) == NULL) 361 return(ESRCH); 362 val_len = strlen(val_start) + 1; 363 } 364 365 /* See if it fits in the client's buffer. */ 366 if (val_len > sysgetenv.vallen) 367 return E2BIG; 368 369 /* Value found, make the actual copy (as far as possible). */ 370 copy_len = MIN(val_len, sysgetenv.vallen); 371 if ((s=sys_datacopy(SELF, (vir_bytes) val_start, 372 who_e, (vir_bytes) sysgetenv.val, copy_len)) != OK) 373 return(s); 374 375 return OK; 376 } 377 378 default: 379 return(EINVAL); 380 } 381 } 382 383 /*===========================================================================* 384 * do_getrusage * 385 *===========================================================================*/ 386 int 387 do_getrusage(void) 388 { 389 clock_t user_time, sys_time; 390 struct rusage r_usage; 391 int r, children; 392 393 if (m_in.m_lc_pm_rusage.who != RUSAGE_SELF && 394 m_in.m_lc_pm_rusage.who != RUSAGE_CHILDREN) 395 return EINVAL; 396 397 /* 398 * TODO: first relay the call to VFS. As is, VFS does not have any 399 * fields it can fill with meaningful values, but this may change in 400 * the future. In that case, PM would first have to use the tell_vfs() 401 * system to get those values from VFS, and do the rest here upon 402 * getting the response. 403 */ 404 405 memset(&r_usage, 0, sizeof(r_usage)); 406 407 children = (m_in.m_lc_pm_rusage.who == RUSAGE_CHILDREN); 408 409 /* 410 * Get system times. For RUSAGE_SELF, get the times for the calling 411 * process from the kernel. For RUSAGE_CHILDREN, we already have the 412 * values we should return right here. 413 */ 414 if (!children) { 415 if ((r = sys_times(who_e, &user_time, &sys_time, NULL, 416 NULL)) != OK) 417 return r; 418 } else { 419 user_time = mp->mp_child_utime; 420 sys_time = mp->mp_child_stime; 421 } 422 423 /* In both cases, convert from clock ticks to microseconds. */ 424 set_rusage_times(&r_usage, user_time, sys_time); 425 426 /* Get additional fields from VM. */ 427 if ((r = vm_getrusage(who_e, &r_usage, children)) != OK) 428 return r; 429 430 /* Finally copy the structure to the caller. */ 431 return sys_datacopy(SELF, (vir_bytes)&r_usage, who_e, 432 m_in.m_lc_pm_rusage.addr, (vir_bytes)sizeof(r_usage)); 433 } 434