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