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 r, slot, ngroups; 174 175 ep = m_in.m_lsys_pm_getepinfo.endpt; 176 if (pm_isokendpt(ep, &slot) != OK) 177 return(ESRCH); 178 rmp = &mproc[slot]; 179 180 mp->mp_reply.m_pm_lsys_getepinfo.uid = rmp->mp_realuid; 181 mp->mp_reply.m_pm_lsys_getepinfo.euid = rmp->mp_effuid; 182 mp->mp_reply.m_pm_lsys_getepinfo.gid = rmp->mp_realgid; 183 mp->mp_reply.m_pm_lsys_getepinfo.egid = rmp->mp_effgid; 184 mp->mp_reply.m_pm_lsys_getepinfo.ngroups = ngroups = rmp->mp_ngroups; 185 if (ngroups > m_in.m_lsys_pm_getepinfo.ngroups) 186 ngroups = m_in.m_lsys_pm_getepinfo.ngroups; 187 if (ngroups > 0) { 188 if ((r = sys_datacopy(SELF, (vir_bytes)rmp->mp_sgroups, who_e, 189 m_in.m_lsys_pm_getepinfo.groups, ngroups * sizeof(gid_t))) != OK) 190 return(r); 191 } 192 return(rmp->mp_pid); 193 } 194 195 /*===========================================================================* 196 * do_reboot * 197 *===========================================================================*/ 198 int 199 do_reboot(void) 200 { 201 message m; 202 203 /* Check permission to abort the system. */ 204 if (mp->mp_effuid != SUPER_USER) return(EPERM); 205 206 /* See how the system should be aborted. */ 207 abort_flag = m_in.m_lc_pm_reboot.how; 208 209 /* notify readclock (some arm systems power off via RTC alarms) */ 210 if (abort_flag & RB_POWERDOWN) { 211 endpoint_t readclock_ep; 212 if (ds_retrieve_label_endpt("readclock.drv", &readclock_ep) == OK) { 213 message m; /* no params to set, nothing we can do if it fails */ 214 _taskcall(readclock_ep, RTCDEV_PWR_OFF, &m); 215 } 216 } 217 218 /* Order matters here. When VFS is told to reboot, it exits all its 219 * processes, and then would be confused if they're exited again by 220 * SIGKILL. So first kill, then reboot. 221 */ 222 223 check_sig(-1, SIGKILL, FALSE /* ksig*/); /* kill all users except init */ 224 sys_stop(INIT_PROC_NR); /* stop init, but keep it around */ 225 226 /* Tell VFS to reboot */ 227 memset(&m, 0, sizeof(m)); 228 m.m_type = VFS_PM_REBOOT; 229 230 tell_vfs(&mproc[VFS_PROC_NR], &m); 231 232 return(SUSPEND); /* don't reply to caller */ 233 } 234 235 /*===========================================================================* 236 * do_getsetpriority * 237 *===========================================================================*/ 238 int 239 do_getsetpriority(void) 240 { 241 int r, arg_which, arg_who, arg_pri; 242 struct mproc *rmp; 243 244 arg_which = m_in.m_lc_pm_priority.which; 245 arg_who = m_in.m_lc_pm_priority.who; 246 arg_pri = m_in.m_lc_pm_priority.prio; /* for SETPRIORITY */ 247 248 /* Code common to GETPRIORITY and SETPRIORITY. */ 249 250 /* Only support PRIO_PROCESS for now. */ 251 if (arg_which != PRIO_PROCESS) 252 return(EINVAL); 253 254 if (arg_who == 0) 255 rmp = mp; 256 else 257 if ((rmp = find_proc(arg_who)) == NULL) 258 return(ESRCH); 259 260 if (mp->mp_effuid != SUPER_USER && 261 mp->mp_effuid != rmp->mp_effuid && mp->mp_effuid != rmp->mp_realuid) 262 return EPERM; 263 264 /* If GET, that's it. */ 265 if (call_nr == PM_GETPRIORITY) { 266 return(rmp->mp_nice - PRIO_MIN); 267 } 268 269 /* Only root is allowed to reduce the nice level. */ 270 if (rmp->mp_nice > arg_pri && mp->mp_effuid != SUPER_USER) 271 return(EACCES); 272 273 /* We're SET, and it's allowed. 274 * 275 * The value passed in is currently between PRIO_MIN and PRIO_MAX. 276 * We have to scale this between MIN_USER_Q and MAX_USER_Q to match 277 * the kernel's scheduling queues. 278 */ 279 280 if ((r = sched_nice(rmp, arg_pri)) != OK) { 281 return r; 282 } 283 284 rmp->mp_nice = arg_pri; 285 return(OK); 286 } 287 288 /*===========================================================================* 289 * do_svrctl * 290 *===========================================================================*/ 291 int do_svrctl(void) 292 { 293 unsigned long req; 294 int s; 295 vir_bytes ptr; 296 #define MAX_LOCAL_PARAMS 2 297 static struct { 298 char name[30]; 299 char value[30]; 300 } local_param_overrides[MAX_LOCAL_PARAMS]; 301 static int local_params = 0; 302 303 req = m_in.m_lc_svrctl.request; 304 ptr = m_in.m_lc_svrctl.arg; 305 306 /* Is the request indeed for the PM? ('M' is old and being phased out) */ 307 if (IOCGROUP(req) != 'P' && IOCGROUP(req) != 'M') return(EINVAL); 308 309 /* Control operations local to the PM. */ 310 switch(req) { 311 case OPMSETPARAM: 312 case OPMGETPARAM: 313 case PMSETPARAM: 314 case PMGETPARAM: { 315 struct sysgetenv sysgetenv; 316 char search_key[64]; 317 char *val_start; 318 size_t val_len; 319 size_t copy_len; 320 321 /* Copy sysgetenv structure to PM. */ 322 if (sys_datacopy(who_e, ptr, SELF, (vir_bytes) &sysgetenv, 323 sizeof(sysgetenv)) != OK) return(EFAULT); 324 325 /* Set a param override? */ 326 if (req == PMSETPARAM || req == OPMSETPARAM) { 327 if (local_params >= MAX_LOCAL_PARAMS) return ENOSPC; 328 if (sysgetenv.keylen <= 0 329 || sysgetenv.keylen >= 330 sizeof(local_param_overrides[local_params].name) 331 || sysgetenv.vallen <= 0 332 || sysgetenv.vallen >= 333 sizeof(local_param_overrides[local_params].value)) 334 return EINVAL; 335 336 if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.key, 337 SELF, (vir_bytes) local_param_overrides[local_params].name, 338 sysgetenv.keylen)) != OK) 339 return s; 340 if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.val, 341 SELF, (vir_bytes) local_param_overrides[local_params].value, 342 sysgetenv.vallen)) != OK) 343 return s; 344 local_param_overrides[local_params].name[sysgetenv.keylen] = '\0'; 345 local_param_overrides[local_params].value[sysgetenv.vallen] = '\0'; 346 347 local_params++; 348 349 return OK; 350 } 351 352 if (sysgetenv.keylen == 0) { /* copy all parameters */ 353 val_start = monitor_params; 354 val_len = sizeof(monitor_params); 355 } 356 else { /* lookup value for key */ 357 int p; 358 /* Try to get a copy of the requested key. */ 359 if (sysgetenv.keylen > sizeof(search_key)) return(EINVAL); 360 if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.key, 361 SELF, (vir_bytes) search_key, sysgetenv.keylen)) != OK) 362 return(s); 363 364 /* Make sure key is null-terminated and lookup value. 365 * First check local overrides. 366 */ 367 search_key[sysgetenv.keylen-1]= '\0'; 368 for(p = 0; p < local_params; p++) { 369 if (!strcmp(search_key, local_param_overrides[p].name)) { 370 val_start = local_param_overrides[p].value; 371 break; 372 } 373 } 374 if (p >= local_params && (val_start = find_param(search_key)) == NULL) 375 return(ESRCH); 376 val_len = strlen(val_start) + 1; 377 } 378 379 /* See if it fits in the client's buffer. */ 380 if (val_len > sysgetenv.vallen) 381 return E2BIG; 382 383 /* Value found, make the actual copy (as far as possible). */ 384 copy_len = MIN(val_len, sysgetenv.vallen); 385 if ((s=sys_datacopy(SELF, (vir_bytes) val_start, 386 who_e, (vir_bytes) sysgetenv.val, copy_len)) != OK) 387 return(s); 388 389 return OK; 390 } 391 392 default: 393 return(EINVAL); 394 } 395 } 396 397 /*===========================================================================* 398 * do_getrusage * 399 *===========================================================================*/ 400 int 401 do_getrusage(void) 402 { 403 clock_t user_time, sys_time; 404 struct rusage r_usage; 405 int r, children; 406 407 if (m_in.m_lc_pm_rusage.who != RUSAGE_SELF && 408 m_in.m_lc_pm_rusage.who != RUSAGE_CHILDREN) 409 return EINVAL; 410 411 /* 412 * TODO: first relay the call to VFS. As is, VFS does not have any 413 * fields it can fill with meaningful values, but this may change in 414 * the future. In that case, PM would first have to use the tell_vfs() 415 * system to get those values from VFS, and do the rest here upon 416 * getting the response. 417 */ 418 419 memset(&r_usage, 0, sizeof(r_usage)); 420 421 children = (m_in.m_lc_pm_rusage.who == RUSAGE_CHILDREN); 422 423 /* 424 * Get system times. For RUSAGE_SELF, get the times for the calling 425 * process from the kernel. For RUSAGE_CHILDREN, we already have the 426 * values we should return right here. 427 */ 428 if (!children) { 429 if ((r = sys_times(who_e, &user_time, &sys_time, NULL, 430 NULL)) != OK) 431 return r; 432 } else { 433 user_time = mp->mp_child_utime; 434 sys_time = mp->mp_child_stime; 435 } 436 437 /* In both cases, convert from clock ticks to microseconds. */ 438 set_rusage_times(&r_usage, user_time, sys_time); 439 440 /* Get additional fields from VM. */ 441 if ((r = vm_getrusage(who_e, &r_usage, children)) != OK) 442 return r; 443 444 /* Finally copy the structure to the caller. */ 445 return sys_datacopy(SELF, (vir_bytes)&r_usage, who_e, 446 m_in.m_lc_pm_rusage.addr, (vir_bytes)sizeof(r_usage)); 447 } 448