1433d6423SLionel Sambuc /* Miscellaneous system calls. Author: Kees J. Bot 2433d6423SLionel Sambuc * 31 Mar 2000 3433d6423SLionel Sambuc * The entry points into this file are: 4433d6423SLionel Sambuc * do_reboot: kill all processes, then reboot system 5433d6423SLionel Sambuc * do_getsysinfo: request copy of PM data structure (Jorrit N. Herder) 6433d6423SLionel Sambuc * do_getprocnr: lookup endpoint by process ID 7433d6423SLionel Sambuc * do_getepinfo: get the pid/uid/gid of a process given its endpoint 8433d6423SLionel Sambuc * do_getsetpriority: get/set process priority 9433d6423SLionel Sambuc * do_svrctl: process manager control 10433d6423SLionel Sambuc */ 11433d6423SLionel Sambuc 12433d6423SLionel Sambuc #include "pm.h" 13433d6423SLionel Sambuc #include <minix/callnr.h> 14433d6423SLionel Sambuc #include <signal.h> 15433d6423SLionel Sambuc #include <sys/svrctl.h> 16433d6423SLionel Sambuc #include <sys/reboot.h> 17433d6423SLionel Sambuc #include <sys/resource.h> 18433d6423SLionel Sambuc #include <sys/utsname.h> 19433d6423SLionel Sambuc #include <minix/com.h> 20433d6423SLionel Sambuc #include <minix/config.h> 21433d6423SLionel Sambuc #include <minix/sysinfo.h> 22433d6423SLionel Sambuc #include <minix/type.h> 23433d6423SLionel Sambuc #include <minix/ds.h> 24433d6423SLionel Sambuc #include <machine/archtypes.h> 25433d6423SLionel Sambuc #include <lib.h> 26433d6423SLionel Sambuc #include <assert.h> 27433d6423SLionel Sambuc #include "mproc.h" 28433d6423SLionel Sambuc #include "kernel/proc.h" 29433d6423SLionel Sambuc 30433d6423SLionel Sambuc struct utsname uts_val = { 31433d6423SLionel Sambuc OS_NAME, /* system name */ 32433d6423SLionel Sambuc "noname", /* node/network name */ 33433d6423SLionel Sambuc OS_RELEASE, /* O.S. release (e.g. 3.3.0) */ 34433d6423SLionel Sambuc OS_VERSION, /* O.S. version (e.g. Minix 3.3.0 (GENERIC)) */ 35433d6423SLionel Sambuc #if defined(__i386__) 36*ea36b58eSLionel Sambuc "i386", /* machine (cpu) type */ 37433d6423SLionel Sambuc "i386", /* architecture */ 38433d6423SLionel Sambuc #elif defined(__arm__) 39*ea36b58eSLionel Sambuc "arm", /* machine (cpu) type */ 40433d6423SLionel Sambuc "arm", /* architecture */ 41433d6423SLionel Sambuc #else 42433d6423SLionel Sambuc #error /* oops, no 'uname -mk' */ 43433d6423SLionel Sambuc #endif 44433d6423SLionel Sambuc }; 45433d6423SLionel Sambuc 46433d6423SLionel Sambuc static char *uts_tbl[] = { 47433d6423SLionel Sambuc uts_val.arch, 48433d6423SLionel Sambuc NULL, /* No kernel architecture */ 49433d6423SLionel Sambuc uts_val.machine, 50433d6423SLionel Sambuc NULL, /* No hostname */ 51433d6423SLionel Sambuc uts_val.nodename, 52433d6423SLionel Sambuc uts_val.release, 53433d6423SLionel Sambuc uts_val.version, 54433d6423SLionel Sambuc uts_val.sysname, 55433d6423SLionel Sambuc NULL, /* No bus */ /* No bus */ 56433d6423SLionel Sambuc }; 57433d6423SLionel Sambuc 58433d6423SLionel Sambuc #if ENABLE_SYSCALL_STATS 59433d6423SLionel Sambuc unsigned long calls_stats[NR_PM_CALLS]; 60433d6423SLionel Sambuc #endif 61433d6423SLionel Sambuc 62433d6423SLionel Sambuc /*===========================================================================* 63433d6423SLionel Sambuc * do_sysuname * 64433d6423SLionel Sambuc *===========================================================================*/ 65433d6423SLionel Sambuc int do_sysuname() 66433d6423SLionel Sambuc { 67433d6423SLionel Sambuc /* Set or get uname strings. */ 68433d6423SLionel Sambuc int r; 69433d6423SLionel Sambuc size_t n; 70433d6423SLionel Sambuc char *string; 71433d6423SLionel Sambuc #if 0 /* for updates */ 72433d6423SLionel Sambuc char tmp[sizeof(uts_val.nodename)]; 73433d6423SLionel Sambuc static short sizes[] = { 74433d6423SLionel Sambuc 0, /* arch, (0 = read-only) */ 75433d6423SLionel Sambuc 0, /* kernel */ 76433d6423SLionel Sambuc 0, /* machine */ 77433d6423SLionel Sambuc 0, /* sizeof(uts_val.hostname), */ 78433d6423SLionel Sambuc sizeof(uts_val.nodename), 79433d6423SLionel Sambuc 0, /* release */ 80433d6423SLionel Sambuc 0, /* version */ 81433d6423SLionel Sambuc 0, /* sysname */ 82433d6423SLionel Sambuc }; 83433d6423SLionel Sambuc #endif 84433d6423SLionel Sambuc 85433d6423SLionel Sambuc if (m_in.m_lc_pm_sysuname.field >= _UTS_MAX) return(EINVAL); 86433d6423SLionel Sambuc 87433d6423SLionel Sambuc string = uts_tbl[m_in.m_lc_pm_sysuname.field]; 88433d6423SLionel Sambuc if (string == NULL) 89433d6423SLionel Sambuc return EINVAL; /* Unsupported field */ 90433d6423SLionel Sambuc 91433d6423SLionel Sambuc switch (m_in.m_lc_pm_sysuname.req) { 92433d6423SLionel Sambuc case _UTS_GET: 93433d6423SLionel Sambuc /* Copy an uname string to the user. */ 94433d6423SLionel Sambuc n = strlen(string) + 1; 95433d6423SLionel Sambuc if (n > m_in.m_lc_pm_sysuname.len) n = m_in.m_lc_pm_sysuname.len; 96433d6423SLionel Sambuc r = sys_datacopy(SELF, (vir_bytes)string, mp->mp_endpoint, 97433d6423SLionel Sambuc m_in.m_lc_pm_sysuname.value, (phys_bytes)n); 98433d6423SLionel Sambuc if (r < 0) return(r); 99433d6423SLionel Sambuc break; 100433d6423SLionel Sambuc 101433d6423SLionel Sambuc #if 0 /* no updates yet */ 102433d6423SLionel Sambuc case _UTS_SET: 103433d6423SLionel Sambuc /* Set an uname string, needs root power. */ 104433d6423SLionel Sambuc len = sizes[m_in.m_lc_pm_sysuname.field]; 105433d6423SLionel Sambuc if (mp->mp_effuid != 0 || len == 0) return(EPERM); 106433d6423SLionel Sambuc n = len < m_in.m_lc_pm_sysuname.len ? len : m_in.m_lc_pm_sysuname.len; 107433d6423SLionel Sambuc if (n <= 0) return(EINVAL); 108433d6423SLionel Sambuc r = sys_datacopy(mp->mp_endpoint, m_in.m_lc_pm_sysuname.value, SELF, 109433d6423SLionel Sambuc (phys_bytes)tmp, (phys_bytes)n); 110433d6423SLionel Sambuc if (r < 0) return(r); 111433d6423SLionel Sambuc tmp[n-1] = 0; 112433d6423SLionel Sambuc strcpy(string, tmp); 113433d6423SLionel Sambuc break; 114433d6423SLionel Sambuc #endif 115433d6423SLionel Sambuc 116433d6423SLionel Sambuc default: 117433d6423SLionel Sambuc return(EINVAL); 118433d6423SLionel Sambuc } 119433d6423SLionel Sambuc /* Return the number of bytes moved. */ 120433d6423SLionel Sambuc return(n); 121433d6423SLionel Sambuc } 122433d6423SLionel Sambuc 123433d6423SLionel Sambuc 124433d6423SLionel Sambuc /*===========================================================================* 125433d6423SLionel Sambuc * do_getsysinfo * 126433d6423SLionel Sambuc *===========================================================================*/ 127433d6423SLionel Sambuc int do_getsysinfo() 128433d6423SLionel Sambuc { 129433d6423SLionel Sambuc vir_bytes src_addr, dst_addr; 130433d6423SLionel Sambuc size_t len; 131433d6423SLionel Sambuc 132433d6423SLionel Sambuc /* This call leaks important information. In the future, requests from 133433d6423SLionel Sambuc * non-system processes should be denied. 134433d6423SLionel Sambuc */ 135433d6423SLionel Sambuc if (mp->mp_effuid != 0) 136433d6423SLionel Sambuc { 137433d6423SLionel Sambuc printf("PM: unauthorized call of do_getsysinfo by proc %d '%s'\n", 138433d6423SLionel Sambuc mp->mp_endpoint, mp->mp_name); 139433d6423SLionel Sambuc sys_diagctl_stacktrace(mp->mp_endpoint); 140433d6423SLionel Sambuc return EPERM; 141433d6423SLionel Sambuc } 142433d6423SLionel Sambuc 143433d6423SLionel Sambuc switch(m_in.m_lsys_getsysinfo.what) { 144433d6423SLionel Sambuc case SI_PROC_TAB: /* copy entire process table */ 145433d6423SLionel Sambuc src_addr = (vir_bytes) mproc; 146433d6423SLionel Sambuc len = sizeof(struct mproc) * NR_PROCS; 147433d6423SLionel Sambuc break; 148433d6423SLionel Sambuc #if ENABLE_SYSCALL_STATS 149433d6423SLionel Sambuc case SI_CALL_STATS: 150433d6423SLionel Sambuc src_addr = (vir_bytes) calls_stats; 151433d6423SLionel Sambuc len = sizeof(calls_stats); 152433d6423SLionel Sambuc break; 153433d6423SLionel Sambuc #endif 154433d6423SLionel Sambuc default: 155433d6423SLionel Sambuc return(EINVAL); 156433d6423SLionel Sambuc } 157433d6423SLionel Sambuc 158433d6423SLionel Sambuc if (len != m_in.m_lsys_getsysinfo.size) 159433d6423SLionel Sambuc return(EINVAL); 160433d6423SLionel Sambuc 161433d6423SLionel Sambuc dst_addr = m_in.m_lsys_getsysinfo.where; 162433d6423SLionel Sambuc return sys_datacopy(SELF, src_addr, who_e, dst_addr, len); 163433d6423SLionel Sambuc } 164433d6423SLionel Sambuc 165433d6423SLionel Sambuc /*===========================================================================* 166433d6423SLionel Sambuc * do_getprocnr * 167433d6423SLionel Sambuc *===========================================================================*/ 168433d6423SLionel Sambuc int do_getprocnr(void) 169433d6423SLionel Sambuc { 170433d6423SLionel Sambuc register struct mproc *rmp; 171433d6423SLionel Sambuc 172433d6423SLionel Sambuc /* This check should be replaced by per-call ACL checks. */ 173433d6423SLionel Sambuc if (who_e != RS_PROC_NR) { 174433d6423SLionel Sambuc printf("PM: unauthorized call of do_getprocnr by %d\n", who_e); 175433d6423SLionel Sambuc return EPERM; 176433d6423SLionel Sambuc } 177433d6423SLionel Sambuc 178433d6423SLionel Sambuc if ((rmp = find_proc(m_in.m_lsys_pm_getprocnr.pid)) == NULL) 179433d6423SLionel Sambuc return(ESRCH); 180433d6423SLionel Sambuc 181433d6423SLionel Sambuc mp->mp_reply.m_pm_lsys_getprocnr.endpt = rmp->mp_endpoint; 182433d6423SLionel Sambuc return(OK); 183433d6423SLionel Sambuc } 184433d6423SLionel Sambuc 185433d6423SLionel Sambuc /*===========================================================================* 186433d6423SLionel Sambuc * do_getepinfo * 187433d6423SLionel Sambuc *===========================================================================*/ 188433d6423SLionel Sambuc int do_getepinfo(void) 189433d6423SLionel Sambuc { 190433d6423SLionel Sambuc struct mproc *rmp; 191433d6423SLionel Sambuc endpoint_t ep; 192433d6423SLionel Sambuc int slot; 193433d6423SLionel Sambuc 194433d6423SLionel Sambuc ep = m_in.m_lsys_pm_getepinfo.endpt; 195433d6423SLionel Sambuc if (pm_isokendpt(ep, &slot) != OK) 196433d6423SLionel Sambuc return(ESRCH); 197433d6423SLionel Sambuc 198433d6423SLionel Sambuc rmp = &mproc[slot]; 199433d6423SLionel Sambuc mp->mp_reply.m_pm_lsys_getepinfo.uid = rmp->mp_effuid; 200433d6423SLionel Sambuc mp->mp_reply.m_pm_lsys_getepinfo.gid = rmp->mp_effgid; 201433d6423SLionel Sambuc return(rmp->mp_pid); 202433d6423SLionel Sambuc } 203433d6423SLionel Sambuc 204433d6423SLionel Sambuc /*===========================================================================* 205433d6423SLionel Sambuc * do_reboot * 206433d6423SLionel Sambuc *===========================================================================*/ 207433d6423SLionel Sambuc int do_reboot() 208433d6423SLionel Sambuc { 209433d6423SLionel Sambuc message m; 210433d6423SLionel Sambuc 211433d6423SLionel Sambuc /* Check permission to abort the system. */ 212433d6423SLionel Sambuc if (mp->mp_effuid != SUPER_USER) return(EPERM); 213433d6423SLionel Sambuc 214433d6423SLionel Sambuc /* See how the system should be aborted. */ 215433d6423SLionel Sambuc abort_flag = m_in.m_lc_pm_reboot.how; 216433d6423SLionel Sambuc 217433d6423SLionel Sambuc /* notify readclock (some arm systems power off via RTC alarms) */ 218433d6423SLionel Sambuc if (abort_flag & RB_POWERDOWN) { 219433d6423SLionel Sambuc endpoint_t readclock_ep; 220433d6423SLionel Sambuc if (ds_retrieve_label_endpt("readclock.drv", &readclock_ep) == OK) { 221433d6423SLionel Sambuc message m; /* no params to set, nothing we can do if it fails */ 222433d6423SLionel Sambuc _taskcall(readclock_ep, RTCDEV_PWR_OFF, &m); 223433d6423SLionel Sambuc } 224433d6423SLionel Sambuc } 225433d6423SLionel Sambuc 226433d6423SLionel Sambuc /* Order matters here. When VFS is told to reboot, it exits all its 227433d6423SLionel Sambuc * processes, and then would be confused if they're exited again by 228433d6423SLionel Sambuc * SIGKILL. So first kill, then reboot. 229433d6423SLionel Sambuc */ 230433d6423SLionel Sambuc 231433d6423SLionel Sambuc check_sig(-1, SIGKILL, FALSE /* ksig*/); /* kill all users except init */ 232433d6423SLionel Sambuc sys_stop(INIT_PROC_NR); /* stop init, but keep it around */ 233433d6423SLionel Sambuc 234433d6423SLionel Sambuc /* Tell VFS to reboot */ 235433d6423SLionel Sambuc memset(&m, 0, sizeof(m)); 236433d6423SLionel Sambuc m.m_type = VFS_PM_REBOOT; 237433d6423SLionel Sambuc 238433d6423SLionel Sambuc tell_vfs(&mproc[VFS_PROC_NR], &m); 239433d6423SLionel Sambuc 240433d6423SLionel Sambuc return(SUSPEND); /* don't reply to caller */ 241433d6423SLionel Sambuc } 242433d6423SLionel Sambuc 243433d6423SLionel Sambuc /*===========================================================================* 244433d6423SLionel Sambuc * do_getsetpriority * 245433d6423SLionel Sambuc *===========================================================================*/ 246433d6423SLionel Sambuc int do_getsetpriority() 247433d6423SLionel Sambuc { 248433d6423SLionel Sambuc int r, arg_which, arg_who, arg_pri; 249433d6423SLionel Sambuc struct mproc *rmp; 250433d6423SLionel Sambuc 251433d6423SLionel Sambuc arg_which = m_in.m_lc_pm_priority.which; 252433d6423SLionel Sambuc arg_who = m_in.m_lc_pm_priority.who; 253433d6423SLionel Sambuc arg_pri = m_in.m_lc_pm_priority.prio; /* for SETPRIORITY */ 254433d6423SLionel Sambuc 255433d6423SLionel Sambuc /* Code common to GETPRIORITY and SETPRIORITY. */ 256433d6423SLionel Sambuc 257433d6423SLionel Sambuc /* Only support PRIO_PROCESS for now. */ 258433d6423SLionel Sambuc if (arg_which != PRIO_PROCESS) 259433d6423SLionel Sambuc return(EINVAL); 260433d6423SLionel Sambuc 261433d6423SLionel Sambuc if (arg_who == 0) 262433d6423SLionel Sambuc rmp = mp; 263433d6423SLionel Sambuc else 264433d6423SLionel Sambuc if ((rmp = find_proc(arg_who)) == NULL) 265433d6423SLionel Sambuc return(ESRCH); 266433d6423SLionel Sambuc 267433d6423SLionel Sambuc if (mp->mp_effuid != SUPER_USER && 268433d6423SLionel Sambuc mp->mp_effuid != rmp->mp_effuid && mp->mp_effuid != rmp->mp_realuid) 269433d6423SLionel Sambuc return EPERM; 270433d6423SLionel Sambuc 271433d6423SLionel Sambuc /* If GET, that's it. */ 272433d6423SLionel Sambuc if (call_nr == PM_GETPRIORITY) { 273433d6423SLionel Sambuc return(rmp->mp_nice - PRIO_MIN); 274433d6423SLionel Sambuc } 275433d6423SLionel Sambuc 276433d6423SLionel Sambuc /* Only root is allowed to reduce the nice level. */ 277433d6423SLionel Sambuc if (rmp->mp_nice > arg_pri && mp->mp_effuid != SUPER_USER) 278433d6423SLionel Sambuc return(EACCES); 279433d6423SLionel Sambuc 280433d6423SLionel Sambuc /* We're SET, and it's allowed. 281433d6423SLionel Sambuc * 282433d6423SLionel Sambuc * The value passed in is currently between PRIO_MIN and PRIO_MAX. 283433d6423SLionel Sambuc * We have to scale this between MIN_USER_Q and MAX_USER_Q to match 284433d6423SLionel Sambuc * the kernel's scheduling queues. 285433d6423SLionel Sambuc */ 286433d6423SLionel Sambuc 287433d6423SLionel Sambuc if ((r = sched_nice(rmp, arg_pri)) != OK) { 288433d6423SLionel Sambuc return r; 289433d6423SLionel Sambuc } 290433d6423SLionel Sambuc 291433d6423SLionel Sambuc rmp->mp_nice = arg_pri; 292433d6423SLionel Sambuc return(OK); 293433d6423SLionel Sambuc } 294433d6423SLionel Sambuc 295433d6423SLionel Sambuc /*===========================================================================* 296433d6423SLionel Sambuc * do_svrctl * 297433d6423SLionel Sambuc *===========================================================================*/ 298433d6423SLionel Sambuc int do_svrctl() 299433d6423SLionel Sambuc { 300433d6423SLionel Sambuc int s, req; 301433d6423SLionel Sambuc vir_bytes ptr; 302433d6423SLionel Sambuc #define MAX_LOCAL_PARAMS 2 303433d6423SLionel Sambuc static struct { 304433d6423SLionel Sambuc char name[30]; 305433d6423SLionel Sambuc char value[30]; 306433d6423SLionel Sambuc } local_param_overrides[MAX_LOCAL_PARAMS]; 307433d6423SLionel Sambuc static int local_params = 0; 308433d6423SLionel Sambuc 309433d6423SLionel Sambuc req = m_in.m_lsys_svrctl.request; 310433d6423SLionel Sambuc ptr = m_in.m_lsys_svrctl.arg; 311433d6423SLionel Sambuc 312433d6423SLionel Sambuc /* Is the request indeed for the PM? */ 313433d6423SLionel Sambuc if (((req >> 8) & 0xFF) != 'M') return(EINVAL); 314433d6423SLionel Sambuc 315433d6423SLionel Sambuc /* Control operations local to the PM. */ 316433d6423SLionel Sambuc switch(req) { 317433d6423SLionel Sambuc case PMSETPARAM: 318433d6423SLionel Sambuc case PMGETPARAM: { 319433d6423SLionel Sambuc struct sysgetenv sysgetenv; 320433d6423SLionel Sambuc char search_key[64]; 321433d6423SLionel Sambuc char *val_start; 322433d6423SLionel Sambuc size_t val_len; 323433d6423SLionel Sambuc size_t copy_len; 324433d6423SLionel Sambuc 325433d6423SLionel Sambuc /* Copy sysgetenv structure to PM. */ 326433d6423SLionel Sambuc if (sys_datacopy(who_e, ptr, SELF, (vir_bytes) &sysgetenv, 327433d6423SLionel Sambuc sizeof(sysgetenv)) != OK) return(EFAULT); 328433d6423SLionel Sambuc 329433d6423SLionel Sambuc /* Set a param override? */ 330433d6423SLionel Sambuc if (req == PMSETPARAM) { 331433d6423SLionel Sambuc if (local_params >= MAX_LOCAL_PARAMS) return ENOSPC; 332433d6423SLionel Sambuc if (sysgetenv.keylen <= 0 333433d6423SLionel Sambuc || sysgetenv.keylen >= 334433d6423SLionel Sambuc sizeof(local_param_overrides[local_params].name) 335433d6423SLionel Sambuc || sysgetenv.vallen <= 0 336433d6423SLionel Sambuc || sysgetenv.vallen >= 337433d6423SLionel Sambuc sizeof(local_param_overrides[local_params].value)) 338433d6423SLionel Sambuc return EINVAL; 339433d6423SLionel Sambuc 340433d6423SLionel Sambuc if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.key, 341433d6423SLionel Sambuc SELF, (vir_bytes) local_param_overrides[local_params].name, 342433d6423SLionel Sambuc sysgetenv.keylen)) != OK) 343433d6423SLionel Sambuc return s; 344433d6423SLionel Sambuc if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.val, 345433d6423SLionel Sambuc SELF, (vir_bytes) local_param_overrides[local_params].value, 346433d6423SLionel Sambuc sysgetenv.vallen)) != OK) 347433d6423SLionel Sambuc return s; 348433d6423SLionel Sambuc local_param_overrides[local_params].name[sysgetenv.keylen] = '\0'; 349433d6423SLionel Sambuc local_param_overrides[local_params].value[sysgetenv.vallen] = '\0'; 350433d6423SLionel Sambuc 351433d6423SLionel Sambuc local_params++; 352433d6423SLionel Sambuc 353433d6423SLionel Sambuc return OK; 354433d6423SLionel Sambuc } 355433d6423SLionel Sambuc 356433d6423SLionel Sambuc if (sysgetenv.keylen == 0) { /* copy all parameters */ 357433d6423SLionel Sambuc val_start = monitor_params; 358433d6423SLionel Sambuc val_len = sizeof(monitor_params); 359433d6423SLionel Sambuc } 360433d6423SLionel Sambuc else { /* lookup value for key */ 361433d6423SLionel Sambuc int p; 362433d6423SLionel Sambuc /* Try to get a copy of the requested key. */ 363433d6423SLionel Sambuc if (sysgetenv.keylen > sizeof(search_key)) return(EINVAL); 364433d6423SLionel Sambuc if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.key, 365433d6423SLionel Sambuc SELF, (vir_bytes) search_key, sysgetenv.keylen)) != OK) 366433d6423SLionel Sambuc return(s); 367433d6423SLionel Sambuc 368433d6423SLionel Sambuc /* Make sure key is null-terminated and lookup value. 369433d6423SLionel Sambuc * First check local overrides. 370433d6423SLionel Sambuc */ 371433d6423SLionel Sambuc search_key[sysgetenv.keylen-1]= '\0'; 372433d6423SLionel Sambuc for(p = 0; p < local_params; p++) { 373433d6423SLionel Sambuc if (!strcmp(search_key, local_param_overrides[p].name)) { 374433d6423SLionel Sambuc val_start = local_param_overrides[p].value; 375433d6423SLionel Sambuc break; 376433d6423SLionel Sambuc } 377433d6423SLionel Sambuc } 378433d6423SLionel Sambuc if (p >= local_params && (val_start = find_param(search_key)) == NULL) 379433d6423SLionel Sambuc return(ESRCH); 380433d6423SLionel Sambuc val_len = strlen(val_start) + 1; 381433d6423SLionel Sambuc } 382433d6423SLionel Sambuc 383433d6423SLionel Sambuc /* See if it fits in the client's buffer. */ 384433d6423SLionel Sambuc if (val_len > sysgetenv.vallen) 385433d6423SLionel Sambuc return E2BIG; 386433d6423SLionel Sambuc 387433d6423SLionel Sambuc /* Value found, make the actual copy (as far as possible). */ 388433d6423SLionel Sambuc copy_len = MIN(val_len, sysgetenv.vallen); 389433d6423SLionel Sambuc if ((s=sys_datacopy(SELF, (vir_bytes) val_start, 390433d6423SLionel Sambuc who_e, (vir_bytes) sysgetenv.val, copy_len)) != OK) 391433d6423SLionel Sambuc return(s); 392433d6423SLionel Sambuc 393433d6423SLionel Sambuc return OK; 394433d6423SLionel Sambuc } 395433d6423SLionel Sambuc 396433d6423SLionel Sambuc default: 397433d6423SLionel Sambuc return(EINVAL); 398433d6423SLionel Sambuc } 399433d6423SLionel Sambuc } 400433d6423SLionel Sambuc 401433d6423SLionel Sambuc /*===========================================================================* 402433d6423SLionel Sambuc * do_getrusage * 403433d6423SLionel Sambuc *===========================================================================*/ 404433d6423SLionel Sambuc int do_getrusage() 405433d6423SLionel Sambuc { 406433d6423SLionel Sambuc int res = 0; 407433d6423SLionel Sambuc clock_t user_time = 0; 408433d6423SLionel Sambuc clock_t sys_time = 0; 409433d6423SLionel Sambuc struct rusage r_usage; 410433d6423SLionel Sambuc u64_t usec; 411433d6423SLionel Sambuc if (m_in.m_lc_pm_rusage.who != RUSAGE_SELF && 412433d6423SLionel Sambuc m_in.m_lc_pm_rusage.who != RUSAGE_CHILDREN) 413433d6423SLionel Sambuc return EINVAL; 414433d6423SLionel Sambuc if ((res = sys_getrusage(&r_usage, who_e)) < 0) 415433d6423SLionel Sambuc return res; 416433d6423SLionel Sambuc 417433d6423SLionel Sambuc if (m_in.m_lc_pm_rusage.who == RUSAGE_CHILDREN) { 418433d6423SLionel Sambuc usec = mp->mp_child_utime * 1000000 / sys_hz(); 419433d6423SLionel Sambuc r_usage.ru_utime.tv_sec = usec / 1000000; 420433d6423SLionel Sambuc r_usage.ru_utime.tv_usec = usec % 1000000; 421433d6423SLionel Sambuc usec = mp->mp_child_stime * 1000000 / sys_hz(); 422433d6423SLionel Sambuc r_usage.ru_stime.tv_sec = usec / 1000000; 423433d6423SLionel Sambuc r_usage.ru_stime.tv_usec = usec % 1000000; 424433d6423SLionel Sambuc } 425433d6423SLionel Sambuc 426433d6423SLionel Sambuc return sys_datacopy(SELF, (vir_bytes)&r_usage, who_e, 427433d6423SLionel Sambuc m_in.m_lc_pm_rusage.addr, (vir_bytes) sizeof(r_usage)); 428433d6423SLionel Sambuc } 429