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 */ 11 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" 29 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 #if defined(__i386__) 36 "i386", /* machine (cpu) type */ 37 "i386", /* architecture */ 38 #elif defined(__arm__) 39 "arm", /* machine (cpu) type */ 40 "arm", /* architecture */ 41 #else 42 #error /* oops, no 'uname -mk' */ 43 #endif 44 }; 45 46 static char *uts_tbl[] = { 47 uts_val.arch, 48 NULL, /* No kernel architecture */ 49 uts_val.machine, 50 NULL, /* No hostname */ 51 uts_val.nodename, 52 uts_val.release, 53 uts_val.version, 54 uts_val.sysname, 55 NULL, /* No bus */ /* No bus */ 56 }; 57 58 #if ENABLE_SYSCALL_STATS 59 unsigned long calls_stats[NR_PM_CALLS]; 60 #endif 61 62 /*===========================================================================* 63 * do_sysuname * 64 *===========================================================================*/ 65 int do_sysuname() 66 { 67 /* Set or get uname strings. */ 68 int r; 69 size_t n; 70 char *string; 71 #if 0 /* for updates */ 72 char tmp[sizeof(uts_val.nodename)]; 73 static short sizes[] = { 74 0, /* arch, (0 = read-only) */ 75 0, /* kernel */ 76 0, /* machine */ 77 0, /* sizeof(uts_val.hostname), */ 78 sizeof(uts_val.nodename), 79 0, /* release */ 80 0, /* version */ 81 0, /* sysname */ 82 }; 83 #endif 84 85 if (m_in.m_lc_pm_sysuname.field >= _UTS_MAX) return(EINVAL); 86 87 string = uts_tbl[m_in.m_lc_pm_sysuname.field]; 88 if (string == NULL) 89 return EINVAL; /* Unsupported field */ 90 91 switch (m_in.m_lc_pm_sysuname.req) { 92 case _UTS_GET: 93 /* Copy an uname string to the user. */ 94 n = strlen(string) + 1; 95 if (n > m_in.m_lc_pm_sysuname.len) n = m_in.m_lc_pm_sysuname.len; 96 r = sys_datacopy(SELF, (vir_bytes)string, mp->mp_endpoint, 97 m_in.m_lc_pm_sysuname.value, (phys_bytes)n); 98 if (r < 0) return(r); 99 break; 100 101 #if 0 /* no updates yet */ 102 case _UTS_SET: 103 /* Set an uname string, needs root power. */ 104 len = sizes[m_in.m_lc_pm_sysuname.field]; 105 if (mp->mp_effuid != 0 || len == 0) return(EPERM); 106 n = len < m_in.m_lc_pm_sysuname.len ? len : m_in.m_lc_pm_sysuname.len; 107 if (n <= 0) return(EINVAL); 108 r = sys_datacopy(mp->mp_endpoint, m_in.m_lc_pm_sysuname.value, SELF, 109 (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 115 116 default: 117 return(EINVAL); 118 } 119 /* Return the number of bytes moved. */ 120 return(n); 121 } 122 123 124 /*===========================================================================* 125 * do_getsysinfo * 126 *===========================================================================*/ 127 int do_getsysinfo() 128 { 129 vir_bytes src_addr, dst_addr; 130 size_t len; 131 132 /* This call leaks important information. In the future, requests from 133 * non-system processes should be denied. 134 */ 135 if (mp->mp_effuid != 0) 136 { 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; 141 } 142 143 switch(m_in.m_lsys_getsysinfo.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); 156 } 157 158 if (len != m_in.m_lsys_getsysinfo.size) 159 return(EINVAL); 160 161 dst_addr = m_in.m_lsys_getsysinfo.where; 162 return sys_datacopy(SELF, src_addr, who_e, dst_addr, len); 163 } 164 165 /*===========================================================================* 166 * do_getprocnr * 167 *===========================================================================*/ 168 int do_getprocnr(void) 169 { 170 register struct mproc *rmp; 171 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; 176 } 177 178 if ((rmp = find_proc(m_in.m_lsys_pm_getprocnr.pid)) == NULL) 179 return(ESRCH); 180 181 mp->mp_reply.m_pm_lsys_getprocnr.endpt = rmp->mp_endpoint; 182 return(OK); 183 } 184 185 /*===========================================================================* 186 * do_getepinfo * 187 *===========================================================================*/ 188 int do_getepinfo(void) 189 { 190 struct mproc *rmp; 191 endpoint_t ep; 192 int slot; 193 194 ep = m_in.m_lsys_pm_getepinfo.endpt; 195 if (pm_isokendpt(ep, &slot) != OK) 196 return(ESRCH); 197 198 rmp = &mproc[slot]; 199 mp->mp_reply.m_pm_lsys_getepinfo.uid = rmp->mp_effuid; 200 mp->mp_reply.m_pm_lsys_getepinfo.gid = rmp->mp_effgid; 201 return(rmp->mp_pid); 202 } 203 204 /*===========================================================================* 205 * do_reboot * 206 *===========================================================================*/ 207 int do_reboot() 208 { 209 message m; 210 211 /* Check permission to abort the system. */ 212 if (mp->mp_effuid != SUPER_USER) return(EPERM); 213 214 /* See how the system should be aborted. */ 215 abort_flag = m_in.m_lc_pm_reboot.how; 216 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); 223 } 224 } 225 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. 229 */ 230 231 check_sig(-1, SIGKILL, FALSE /* ksig*/); /* kill all users except init */ 232 sys_stop(INIT_PROC_NR); /* stop init, but keep it around */ 233 234 /* Tell VFS to reboot */ 235 memset(&m, 0, sizeof(m)); 236 m.m_type = VFS_PM_REBOOT; 237 238 tell_vfs(&mproc[VFS_PROC_NR], &m); 239 240 return(SUSPEND); /* don't reply to caller */ 241 } 242 243 /*===========================================================================* 244 * do_getsetpriority * 245 *===========================================================================*/ 246 int do_getsetpriority() 247 { 248 int r, arg_which, arg_who, arg_pri; 249 struct mproc *rmp; 250 251 arg_which = m_in.m_lc_pm_priority.which; 252 arg_who = m_in.m_lc_pm_priority.who; 253 arg_pri = m_in.m_lc_pm_priority.prio; /* for SETPRIORITY */ 254 255 /* Code common to GETPRIORITY and SETPRIORITY. */ 256 257 /* Only support PRIO_PROCESS for now. */ 258 if (arg_which != PRIO_PROCESS) 259 return(EINVAL); 260 261 if (arg_who == 0) 262 rmp = mp; 263 else 264 if ((rmp = find_proc(arg_who)) == NULL) 265 return(ESRCH); 266 267 if (mp->mp_effuid != SUPER_USER && 268 mp->mp_effuid != rmp->mp_effuid && mp->mp_effuid != rmp->mp_realuid) 269 return EPERM; 270 271 /* If GET, that's it. */ 272 if (call_nr == PM_GETPRIORITY) { 273 return(rmp->mp_nice - PRIO_MIN); 274 } 275 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); 279 280 /* We're SET, and it's allowed. 281 * 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. 285 */ 286 287 if ((r = sched_nice(rmp, arg_pri)) != OK) { 288 return r; 289 } 290 291 rmp->mp_nice = arg_pri; 292 return(OK); 293 } 294 295 /*===========================================================================* 296 * do_svrctl * 297 *===========================================================================*/ 298 int do_svrctl(void) 299 { 300 unsigned long req; 301 int s; 302 vir_bytes ptr; 303 #define MAX_LOCAL_PARAMS 2 304 static struct { 305 char name[30]; 306 char value[30]; 307 } local_param_overrides[MAX_LOCAL_PARAMS]; 308 static int local_params = 0; 309 310 req = m_in.m_lc_svrctl.request; 311 ptr = m_in.m_lc_svrctl.arg; 312 313 /* Is the request indeed for the PM? ('M' is old and being phased out) */ 314 if (IOCGROUP(req) != 'P' && IOCGROUP(req) != 'M') return(EINVAL); 315 316 /* Control operations local to the PM. */ 317 switch(req) { 318 case OPMSETPARAM: 319 case OPMGETPARAM: 320 case PMSETPARAM: 321 case PMGETPARAM: { 322 struct sysgetenv sysgetenv; 323 char search_key[64]; 324 char *val_start; 325 size_t val_len; 326 size_t copy_len; 327 328 /* Copy sysgetenv structure to PM. */ 329 if (sys_datacopy(who_e, ptr, SELF, (vir_bytes) &sysgetenv, 330 sizeof(sysgetenv)) != OK) return(EFAULT); 331 332 /* Set a param override? */ 333 if (req == PMSETPARAM || req == OPMSETPARAM) { 334 if (local_params >= MAX_LOCAL_PARAMS) return ENOSPC; 335 if (sysgetenv.keylen <= 0 336 || sysgetenv.keylen >= 337 sizeof(local_param_overrides[local_params].name) 338 || sysgetenv.vallen <= 0 339 || sysgetenv.vallen >= 340 sizeof(local_param_overrides[local_params].value)) 341 return EINVAL; 342 343 if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.key, 344 SELF, (vir_bytes) local_param_overrides[local_params].name, 345 sysgetenv.keylen)) != OK) 346 return s; 347 if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.val, 348 SELF, (vir_bytes) local_param_overrides[local_params].value, 349 sysgetenv.vallen)) != OK) 350 return s; 351 local_param_overrides[local_params].name[sysgetenv.keylen] = '\0'; 352 local_param_overrides[local_params].value[sysgetenv.vallen] = '\0'; 353 354 local_params++; 355 356 return OK; 357 } 358 359 if (sysgetenv.keylen == 0) { /* copy all parameters */ 360 val_start = monitor_params; 361 val_len = sizeof(monitor_params); 362 } 363 else { /* lookup value for key */ 364 int p; 365 /* Try to get a copy of the requested key. */ 366 if (sysgetenv.keylen > sizeof(search_key)) return(EINVAL); 367 if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.key, 368 SELF, (vir_bytes) search_key, sysgetenv.keylen)) != OK) 369 return(s); 370 371 /* Make sure key is null-terminated and lookup value. 372 * First check local overrides. 373 */ 374 search_key[sysgetenv.keylen-1]= '\0'; 375 for(p = 0; p < local_params; p++) { 376 if (!strcmp(search_key, local_param_overrides[p].name)) { 377 val_start = local_param_overrides[p].value; 378 break; 379 } 380 } 381 if (p >= local_params && (val_start = find_param(search_key)) == NULL) 382 return(ESRCH); 383 val_len = strlen(val_start) + 1; 384 } 385 386 /* See if it fits in the client's buffer. */ 387 if (val_len > sysgetenv.vallen) 388 return E2BIG; 389 390 /* Value found, make the actual copy (as far as possible). */ 391 copy_len = MIN(val_len, sysgetenv.vallen); 392 if ((s=sys_datacopy(SELF, (vir_bytes) val_start, 393 who_e, (vir_bytes) sysgetenv.val, copy_len)) != OK) 394 return(s); 395 396 return OK; 397 } 398 399 default: 400 return(EINVAL); 401 } 402 } 403 404 /*===========================================================================* 405 * do_getrusage * 406 *===========================================================================*/ 407 int do_getrusage() 408 { 409 int res = 0; 410 clock_t user_time = 0; 411 clock_t sys_time = 0; 412 struct rusage r_usage; 413 u64_t usec; 414 if (m_in.m_lc_pm_rusage.who != RUSAGE_SELF && 415 m_in.m_lc_pm_rusage.who != RUSAGE_CHILDREN) 416 return EINVAL; 417 if ((res = sys_getrusage(&r_usage, who_e)) < 0) 418 return res; 419 420 if (m_in.m_lc_pm_rusage.who == RUSAGE_CHILDREN) { 421 usec = mp->mp_child_utime * 1000000 / sys_hz(); 422 r_usage.ru_utime.tv_sec = usec / 1000000; 423 r_usage.ru_utime.tv_usec = usec % 1000000; 424 usec = mp->mp_child_stime * 1000000 / sys_hz(); 425 r_usage.ru_stime.tv_sec = usec / 1000000; 426 r_usage.ru_stime.tv_usec = usec % 1000000; 427 } 428 429 return sys_datacopy(SELF, (vir_bytes)&r_usage, who_e, 430 m_in.m_lc_pm_rusage.addr, (vir_bytes) sizeof(r_usage)); 431 } 432