linux_misc.c revision 113613
19313Ssos/*- 29313Ssos * Copyright (c) 1994-1995 S�ren Schmidt 39313Ssos * All rights reserved. 49313Ssos * 59313Ssos * Redistribution and use in source and binary forms, with or without 69313Ssos * modification, are permitted provided that the following conditions 79313Ssos * are met: 89313Ssos * 1. Redistributions of source code must retain the above copyright 914331Speter * notice, this list of conditions and the following disclaimer 109313Ssos * in this position and unchanged. 119313Ssos * 2. Redistributions in binary form must reproduce the above copyright 129313Ssos * notice, this list of conditions and the following disclaimer in the 139313Ssos * documentation and/or other materials provided with the distribution. 149313Ssos * 3. The name of the author may not be used to endorse or promote products 1597748Sschweikh * derived from this software without specific prior written permission 169313Ssos * 179313Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 189313Ssos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 199313Ssos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 209313Ssos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 219313Ssos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 229313Ssos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 239313Ssos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 249313Ssos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 259313Ssos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 269313Ssos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 279313Ssos * 2850477Speter * $FreeBSD: head/sys/compat/linux/linux_misc.c 113613 2003-04-17 22:02:47Z jhb $ 299313Ssos */ 309313Ssos 31101189Srwatson#include "opt_mac.h" 3249842Smarcel 339313Ssos#include <sys/param.h> 34102954Sbde#include <sys/blist.h> 3576166Smarkm#include <sys/fcntl.h> 3676166Smarkm#include <sys/imgact_aout.h> 3791385Srobert#include <sys/jail.h> 3812458Sbde#include <sys/kernel.h> 3976166Smarkm#include <sys/lock.h> 40101189Srwatson#include <sys/mac.h> 41102954Sbde#include <sys/malloc.h> 429313Ssos#include <sys/mman.h> 439313Ssos#include <sys/mount.h> 4476166Smarkm#include <sys/mutex.h> 459313Ssos#include <sys/namei.h> 4676166Smarkm#include <sys/proc.h> 4772538Sjlemon#include <sys/reboot.h> 489313Ssos#include <sys/resourcevar.h> 4976166Smarkm#include <sys/signalvar.h> 509313Ssos#include <sys/stat.h> 51102814Siedowse#include <sys/syscallsubr.h> 5212458Sbde#include <sys/sysctl.h> 5376166Smarkm#include <sys/sysproto.h> 54102954Sbde#include <sys/systm.h> 5576166Smarkm#include <sys/time.h> 5680180Spirzyk#include <sys/vmmeter.h> 579313Ssos#include <sys/vnode.h> 589313Ssos#include <sys/wait.h> 599313Ssos 6012652Sbde#include <vm/vm.h> 6112689Speter#include <vm/pmap.h> 6212458Sbde#include <vm/vm_kern.h> 6312689Speter#include <vm/vm_map.h> 6412842Sbde#include <vm/vm_extern.h> 6580180Spirzyk#include <vm/vm_object.h> 6680180Spirzyk#include <vm/swap_pager.h> 6712458Sbde 6865106Smarcel#include <machine/limits.h> 6930837Skato 7049849Smarcel#include <posix4/sched.h> 7149849Smarcel 7264909Smarcel#include <machine/../linux/linux.h> 7368583Smarcel#include <machine/../linux/linux_proto.h> 74102954Sbde 7564909Smarcel#include <compat/linux/linux_mib.h> 7664909Smarcel#include <compat/linux/linux_util.h> 7764909Smarcel 7868201Sobrien#ifdef __alpha__ 7968201Sobrien#define BSD_TO_LINUX_SIGNAL(sig) (sig) 8068201Sobrien#else 8151793Smarcel#define BSD_TO_LINUX_SIGNAL(sig) \ 8251793Smarcel (((sig) <= LINUX_SIGTBLSZ) ? bsd_to_linux_signal[_SIG_IDX(sig)] : sig) 8368201Sobrien#endif 8451793Smarcel 8568201Sobrien#ifndef __alpha__ 8683221Smarcelstatic unsigned int linux_to_bsd_resource[LINUX_RLIM_NLIMITS] = { 8783221Smarcel RLIMIT_CPU, RLIMIT_FSIZE, RLIMIT_DATA, RLIMIT_STACK, 8883221Smarcel RLIMIT_CORE, RLIMIT_RSS, RLIMIT_NPROC, RLIMIT_NOFILE, 8983221Smarcel RLIMIT_MEMLOCK, -1 9049626Smarcel}; 9168201Sobrien#endif /*!__alpha__*/ 9249626Smarcel 9383221Smarcelstruct l_sysinfo { 9483221Smarcel l_long uptime; /* Seconds since boot */ 9583221Smarcel l_ulong loads[3]; /* 1, 5, and 15 minute load averages */ 9683221Smarcel l_ulong totalram; /* Total usable main memory size */ 9783221Smarcel l_ulong freeram; /* Available memory size */ 9883221Smarcel l_ulong sharedram; /* Amount of shared memory */ 9983221Smarcel l_ulong bufferram; /* Memory used by buffers */ 10083221Smarcel l_ulong totalswap; /* Total swap space size */ 10183221Smarcel l_ulong freeswap; /* swap space still available */ 10283221Smarcel l_ushort procs; /* Number of current processes */ 10383221Smarcel char _f[22]; /* Pads structure to 64 bytes */ 10480180Spirzyk}; 10568201Sobrien#ifndef __alpha__ 1069313Ssosint 10783366Sjulianlinux_sysinfo(struct thread *td, struct linux_sysinfo_args *args) 10880180Spirzyk{ 10983221Smarcel struct l_sysinfo sysinfo; 11083221Smarcel vm_object_t object; 11183221Smarcel int i; 11283221Smarcel struct timespec ts; 11380180Spirzyk 11483221Smarcel /* Uptime is copied out of print_uptime() in kern_shutdown.c */ 11583221Smarcel getnanouptime(&ts); 11683221Smarcel i = 0; 11783221Smarcel if (ts.tv_sec >= 86400) { 11883221Smarcel ts.tv_sec %= 86400; 11983221Smarcel i = 1; 12083221Smarcel } 12183221Smarcel if (i || ts.tv_sec >= 3600) { 12283221Smarcel ts.tv_sec %= 3600; 12383221Smarcel i = 1; 12483221Smarcel } 12583221Smarcel if (i || ts.tv_sec >= 60) { 12683221Smarcel ts.tv_sec %= 60; 12783221Smarcel i = 1; 12883221Smarcel } 12983221Smarcel sysinfo.uptime=ts.tv_sec; 13080180Spirzyk 13183221Smarcel /* Use the information from the mib to get our load averages */ 13283221Smarcel for (i = 0; i < 3; i++) 13383221Smarcel sysinfo.loads[i] = averunnable.ldavg[i]; 13480180Spirzyk 13583221Smarcel sysinfo.totalram = physmem * PAGE_SIZE; 13683221Smarcel sysinfo.freeram = sysinfo.totalram - cnt.v_wire_count * PAGE_SIZE; 13780180Spirzyk 13883221Smarcel sysinfo.sharedram = 0; 13983221Smarcel for (object = TAILQ_FIRST(&vm_object_list); object != NULL; 14083221Smarcel object = TAILQ_NEXT(object, object_list)) 14183221Smarcel if (object->shadow_count > 1) 14283221Smarcel sysinfo.sharedram += object->resident_page_count; 14380180Spirzyk 14483221Smarcel sysinfo.sharedram *= PAGE_SIZE; 14583221Smarcel sysinfo.bufferram = 0; 14680180Spirzyk 14783221Smarcel if (swapblist == NULL) { 14883221Smarcel sysinfo.totalswap= 0; 14983221Smarcel sysinfo.freeswap = 0; 15083221Smarcel } else { 15183221Smarcel sysinfo.totalswap = swapblist->bl_blocks * 1024; 15283221Smarcel sysinfo.freeswap = swapblist->bl_root->u.bmu_avail * PAGE_SIZE; 15383221Smarcel } 15480180Spirzyk 15583221Smarcel sysinfo.procs = 20; /* Hack */ 15680180Spirzyk 157111797Sdes return copyout(&sysinfo, args->info, sizeof(sysinfo)); 15880180Spirzyk} 15980180Spirzyk#endif /*!__alpha__*/ 16080180Spirzyk 16180180Spirzyk#ifndef __alpha__ 16280180Spirzykint 16383366Sjulianlinux_alarm(struct thread *td, struct linux_alarm_args *args) 1649313Ssos{ 16583221Smarcel struct itimerval it, old_it; 16683221Smarcel struct timeval tv; 167113613Sjhb struct proc *p; 1689313Ssos 1699313Ssos#ifdef DEBUG 17072543Sjlemon if (ldebug(alarm)) 17172543Sjlemon printf(ARGS(alarm, "%u"), args->secs); 1729313Ssos#endif 17383221Smarcel 17483221Smarcel if (args->secs > 100000000) 17583221Smarcel return EINVAL; 17683221Smarcel 17783221Smarcel it.it_value.tv_sec = (long)args->secs; 17883221Smarcel it.it_value.tv_usec = 0; 17983221Smarcel it.it_interval.tv_sec = 0; 18083221Smarcel it.it_interval.tv_usec = 0; 181113613Sjhb p = td->td_proc; 182113613Sjhb PROC_LOCK(p); 183113613Sjhb old_it = p->p_realtimer; 18483221Smarcel getmicrouptime(&tv); 18583221Smarcel if (timevalisset(&old_it.it_value)) 186113613Sjhb callout_stop(&p->p_itcallout); 18783221Smarcel if (it.it_value.tv_sec != 0) { 188113613Sjhb callout_reset(&p->p_itcallout, tvtohz(&it.it_value), 189113613Sjhb realitexpire, p); 19083221Smarcel timevaladd(&it.it_value, &tv); 19183221Smarcel } 192113613Sjhb p->p_realtimer = it; 193113613Sjhb PROC_UNLOCK(p); 19483221Smarcel if (timevalcmp(&old_it.it_value, &tv, >)) { 19583221Smarcel timevalsub(&old_it.it_value, &tv); 19683221Smarcel if (old_it.it_value.tv_usec != 0) 19783221Smarcel old_it.it_value.tv_sec++; 19883366Sjulian td->td_retval[0] = old_it.it_value.tv_sec; 19983221Smarcel } 20083221Smarcel return 0; 2019313Ssos} 20268201Sobrien#endif /*!__alpha__*/ 2039313Ssos 2049313Ssosint 20583366Sjulianlinux_brk(struct thread *td, struct linux_brk_args *args) 2069313Ssos{ 20783366Sjulian struct vmspace *vm = td->td_proc->p_vmspace; 20883221Smarcel vm_offset_t new, old; 20983221Smarcel struct obreak_args /* { 21083221Smarcel char * nsize; 21183221Smarcel } */ tmp; 2129313Ssos 2139313Ssos#ifdef DEBUG 21472543Sjlemon if (ldebug(brk)) 21572543Sjlemon printf(ARGS(brk, "%p"), (void *)args->dsend); 2169313Ssos#endif 21783221Smarcel old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize); 21883221Smarcel new = (vm_offset_t)args->dsend; 21983221Smarcel tmp.nsize = (char *) new; 22083366Sjulian if (((caddr_t)new > vm->vm_daddr) && !obreak(td, &tmp)) 22183366Sjulian td->td_retval[0] = (long)new; 22283221Smarcel else 22383366Sjulian td->td_retval[0] = (long)old; 2249313Ssos 22583221Smarcel return 0; 2269313Ssos} 2279313Ssos 2289313Ssosint 22983366Sjulianlinux_uselib(struct thread *td, struct linux_uselib_args *args) 2309313Ssos{ 23183221Smarcel struct nameidata ni; 23283221Smarcel struct vnode *vp; 23383221Smarcel struct exec *a_out; 23483221Smarcel struct vattr attr; 23583221Smarcel vm_offset_t vmaddr; 23683221Smarcel unsigned long file_offset; 23783221Smarcel vm_offset_t buffer; 23883221Smarcel unsigned long bss_size; 239102814Siedowse char *library; 24083221Smarcel int error; 24183221Smarcel int locked; 2429313Ssos 243102814Siedowse LCONVPATHEXIST(td, args->library, &library); 24414331Speter 2459313Ssos#ifdef DEBUG 24672543Sjlemon if (ldebug(uselib)) 247102814Siedowse printf(ARGS(uselib, "%s"), library); 2489313Ssos#endif 2499313Ssos 25083221Smarcel a_out = NULL; 25183221Smarcel locked = 0; 25283221Smarcel vp = NULL; 25314114Speter 25495130Srwatson /* 255101189Srwatson * XXX: This code should make use of vn_open(), rather than doing 25695130Srwatson * all this stuff itself. 25795130Srwatson */ 258102814Siedowse NDINIT(&ni, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, library, td); 25983221Smarcel error = namei(&ni); 260102814Siedowse LFREEPATH(library); 26183221Smarcel if (error) 26283221Smarcel goto cleanup; 2639313Ssos 26483221Smarcel vp = ni.ni_vp; 26583221Smarcel /* 26683221Smarcel * XXX - This looks like a bogus check. A LOCKLEAF namei should not 26783221Smarcel * succeed without returning a vnode. 26883221Smarcel */ 26983221Smarcel if (vp == NULL) { 27083221Smarcel error = ENOEXEC; /* ?? */ 27183221Smarcel goto cleanup; 27283221Smarcel } 27383221Smarcel NDFREE(&ni, NDF_ONLY_PNBUF); 2749313Ssos 27583221Smarcel /* 27683221Smarcel * From here on down, we have a locked vnode that must be unlocked. 27783221Smarcel */ 27883221Smarcel locked++; 27914114Speter 28083221Smarcel /* Writable? */ 28183221Smarcel if (vp->v_writecount) { 28283221Smarcel error = ETXTBSY; 28383221Smarcel goto cleanup; 28483221Smarcel } 2859313Ssos 28683221Smarcel /* Executable? */ 28791406Sjhb error = VOP_GETATTR(vp, &attr, td->td_ucred, td); 28883221Smarcel if (error) 28983221Smarcel goto cleanup; 2909313Ssos 29183221Smarcel if ((vp->v_mount->mnt_flag & MNT_NOEXEC) || 29283221Smarcel ((attr.va_mode & 0111) == 0) || (attr.va_type != VREG)) { 29383221Smarcel error = ENOEXEC; 29483221Smarcel goto cleanup; 29583221Smarcel } 2969313Ssos 29783221Smarcel /* Sensible size? */ 29883221Smarcel if (attr.va_size == 0) { 29983221Smarcel error = ENOEXEC; 30083221Smarcel goto cleanup; 30183221Smarcel } 3029313Ssos 30383221Smarcel /* Can we access it? */ 30491406Sjhb error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td); 30583221Smarcel if (error) 30683221Smarcel goto cleanup; 3079313Ssos 30898209Srwatson /* 30998209Srwatson * XXX: This should use vn_open() so that it is properly authorized, 31098209Srwatson * and to reduce code redundancy all over the place here. 31198209Srwatson */ 312101189Srwatson#ifdef MAC 313101189Srwatson error = mac_check_vnode_open(td->td_ucred, vp, FREAD); 314101189Srwatson if (error) 315101189Srwatson goto cleanup; 316101189Srwatson#endif 31791406Sjhb error = VOP_OPEN(vp, FREAD, td->td_ucred, td); 31883221Smarcel if (error) 31983221Smarcel goto cleanup; 3209313Ssos 321103941Sjeff /* Pull in executable header into kernel_map */ 322103941Sjeff error = vm_mmap(kernel_map, (vm_offset_t *)&a_out, PAGE_SIZE, 323103941Sjeff VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp, 0); 32483221Smarcel /* 32583221Smarcel * Lock no longer needed 32683221Smarcel */ 327103941Sjeff locked = 0; 32883366Sjulian VOP_UNLOCK(vp, 0, td); 32911163Sjulian 33083221Smarcel if (error) 33183221Smarcel goto cleanup; 3329313Ssos 33383221Smarcel /* Is it a Linux binary ? */ 33483221Smarcel if (((a_out->a_magic >> 16) & 0xff) != 0x64) { 33583221Smarcel error = ENOEXEC; 33683221Smarcel goto cleanup; 33783221Smarcel } 3389313Ssos 33983221Smarcel /* 34083221Smarcel * While we are here, we should REALLY do some more checks 34183221Smarcel */ 34214114Speter 34383221Smarcel /* Set file/virtual offset based on a.out variant. */ 34483221Smarcel switch ((int)(a_out->a_magic & 0xffff)) { 34583221Smarcel case 0413: /* ZMAGIC */ 34683221Smarcel file_offset = 1024; 34783221Smarcel break; 34883221Smarcel case 0314: /* QMAGIC */ 34983221Smarcel file_offset = 0; 35083221Smarcel break; 35183221Smarcel default: 35283221Smarcel error = ENOEXEC; 35383221Smarcel goto cleanup; 35483221Smarcel } 3559313Ssos 35683221Smarcel bss_size = round_page(a_out->a_bss); 35714114Speter 35883221Smarcel /* Check various fields in header for validity/bounds. */ 35983221Smarcel if (a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) { 36083221Smarcel error = ENOEXEC; 36183221Smarcel goto cleanup; 36283221Smarcel } 36314114Speter 36483221Smarcel /* text + data can't exceed file size */ 36583221Smarcel if (a_out->a_data + a_out->a_text > attr.va_size) { 36683221Smarcel error = EFAULT; 36783221Smarcel goto cleanup; 36883221Smarcel } 36914114Speter 37083366Sjulian /* To protect td->td_proc->p_rlimit in the if condition. */ 37183221Smarcel mtx_assert(&Giant, MA_OWNED); 37270061Sjhb 37383221Smarcel /* 37483221Smarcel * text/data/bss must not exceed limits 37583221Smarcel * XXX - this is not complete. it should check current usage PLUS 37683221Smarcel * the resources needed by this library. 37783221Smarcel */ 37884783Sps if (a_out->a_text > maxtsiz || 37983366Sjulian a_out->a_data + bss_size > 38083366Sjulian td->td_proc->p_rlimit[RLIMIT_DATA].rlim_cur) { 38183221Smarcel error = ENOMEM; 38283221Smarcel goto cleanup; 38383221Smarcel } 38414114Speter 385101308Sjeff mp_fixme("Unlocked vflags access."); 38683221Smarcel /* prevent more writers */ 387101308Sjeff vp->v_vflag |= VV_TEXT; 38814114Speter 38983221Smarcel /* 39083221Smarcel * Check if file_offset page aligned. Currently we cannot handle 39183221Smarcel * misalinged file offsets, and so we read in the entire image 39283221Smarcel * (what a waste). 39383221Smarcel */ 39483221Smarcel if (file_offset & PAGE_MASK) { 3959313Ssos#ifdef DEBUG 39683221Smarcel printf("uselib: Non page aligned binary %lu\n", file_offset); 3979313Ssos#endif 39883221Smarcel /* Map text+data read/write/execute */ 39914114Speter 40083221Smarcel /* a_entry is the load address and is page aligned */ 40183221Smarcel vmaddr = trunc_page(a_out->a_entry); 40214114Speter 40383221Smarcel /* get anon user mapping, read+write+execute */ 40483366Sjulian error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0, 40583366Sjulian &vmaddr, a_out->a_text + a_out->a_data, FALSE, VM_PROT_ALL, 40683221Smarcel VM_PROT_ALL, 0); 40783221Smarcel if (error) 40883221Smarcel goto cleanup; 4099313Ssos 41083221Smarcel /* map file into kernel_map */ 41183221Smarcel error = vm_mmap(kernel_map, &buffer, 41283221Smarcel round_page(a_out->a_text + a_out->a_data + file_offset), 41383221Smarcel VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp, 41483221Smarcel trunc_page(file_offset)); 41583221Smarcel if (error) 41683221Smarcel goto cleanup; 4179313Ssos 41883221Smarcel /* copy from kernel VM space to user space */ 419111797Sdes error = copyout((void *)(buffer + file_offset), 420111797Sdes (void *)vmaddr, a_out->a_text + a_out->a_data); 4219313Ssos 42283221Smarcel /* release temporary kernel space */ 42383221Smarcel vm_map_remove(kernel_map, buffer, buffer + 42483221Smarcel round_page(a_out->a_text + a_out->a_data + file_offset)); 4259313Ssos 42683221Smarcel if (error) 42783221Smarcel goto cleanup; 42883221Smarcel } else { 4299313Ssos#ifdef DEBUG 43083221Smarcel printf("uselib: Page aligned binary %lu\n", file_offset); 4319313Ssos#endif 43283221Smarcel /* 43383221Smarcel * for QMAGIC, a_entry is 20 bytes beyond the load address 43483221Smarcel * to skip the executable header 43583221Smarcel */ 43683221Smarcel vmaddr = trunc_page(a_out->a_entry); 43714114Speter 43883221Smarcel /* 43983221Smarcel * Map it all into the process's space as a single 44083221Smarcel * copy-on-write "data" segment. 44183221Smarcel */ 44283366Sjulian error = vm_mmap(&td->td_proc->p_vmspace->vm_map, &vmaddr, 44383221Smarcel a_out->a_text + a_out->a_data, VM_PROT_ALL, VM_PROT_ALL, 44483221Smarcel MAP_PRIVATE | MAP_FIXED, (caddr_t)vp, file_offset); 44583221Smarcel if (error) 44683221Smarcel goto cleanup; 44783221Smarcel } 4489313Ssos#ifdef DEBUG 44983221Smarcel printf("mem=%08lx = %08lx %08lx\n", (long)vmaddr, ((long*)vmaddr)[0], 45083221Smarcel ((long*)vmaddr)[1]); 4519313Ssos#endif 45283221Smarcel if (bss_size != 0) { 45383221Smarcel /* Calculate BSS start address */ 45483221Smarcel vmaddr = trunc_page(a_out->a_entry) + a_out->a_text + 45583221Smarcel a_out->a_data; 45614114Speter 45783221Smarcel /* allocate some 'anon' space */ 45883366Sjulian error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0, 45983366Sjulian &vmaddr, bss_size, FALSE, VM_PROT_ALL, VM_PROT_ALL, 0); 46083221Smarcel if (error) 46183221Smarcel goto cleanup; 46283221Smarcel } 46314114Speter 46414114Spetercleanup: 46583221Smarcel /* Unlock vnode if needed */ 46683221Smarcel if (locked) 46783366Sjulian VOP_UNLOCK(vp, 0, td); 46814114Speter 46983221Smarcel /* Release the kernel mapping. */ 47083221Smarcel if (a_out) 47183221Smarcel vm_map_remove(kernel_map, (vm_offset_t)a_out, 47283221Smarcel (vm_offset_t)a_out + PAGE_SIZE); 47314114Speter 47483221Smarcel return error; 4759313Ssos} 4769313Ssos 4779313Ssosint 47883366Sjulianlinux_select(struct thread *td, struct linux_select_args *args) 47914331Speter{ 48083221Smarcel struct timeval tv0, tv1, utv, *tvp; 48183221Smarcel int error; 48214331Speter 4839313Ssos#ifdef DEBUG 48483221Smarcel if (ldebug(select)) 48583221Smarcel printf(ARGS(select, "%d, %p, %p, %p, %p"), args->nfds, 48683221Smarcel (void *)args->readfds, (void *)args->writefds, 48783221Smarcel (void *)args->exceptfds, (void *)args->timeout); 4889313Ssos#endif 48914331Speter 49083221Smarcel /* 49183221Smarcel * Store current time for computation of the amount of 49283221Smarcel * time left. 49383221Smarcel */ 49483221Smarcel if (args->timeout) { 495111797Sdes if ((error = copyin(args->timeout, &utv, sizeof(utv)))) 49683221Smarcel goto select_out; 49714331Speter#ifdef DEBUG 49883221Smarcel if (ldebug(select)) 49983221Smarcel printf(LMSG("incoming timeout (%ld/%ld)"), 50083221Smarcel utv.tv_sec, utv.tv_usec); 50114331Speter#endif 50283221Smarcel 50383221Smarcel if (itimerfix(&utv)) { 50483221Smarcel /* 50583221Smarcel * The timeval was invalid. Convert it to something 50683221Smarcel * valid that will act as it does under Linux. 50783221Smarcel */ 50883221Smarcel utv.tv_sec += utv.tv_usec / 1000000; 50983221Smarcel utv.tv_usec %= 1000000; 51083221Smarcel if (utv.tv_usec < 0) { 51183221Smarcel utv.tv_sec -= 1; 51283221Smarcel utv.tv_usec += 1000000; 51383221Smarcel } 51483221Smarcel if (utv.tv_sec < 0) 51583221Smarcel timevalclear(&utv); 51683221Smarcel } 51783221Smarcel microtime(&tv0); 518102814Siedowse tvp = &utv; 519102814Siedowse } else 520102814Siedowse tvp = NULL; 52114331Speter 522102814Siedowse error = kern_select(td, args->nfds, args->readfds, args->writefds, 523102814Siedowse args->exceptfds, tvp); 524102814Siedowse 52514331Speter#ifdef DEBUG 52683221Smarcel if (ldebug(select)) 52772543Sjlemon printf(LMSG("real select returns %d"), error); 52814331Speter#endif 52983221Smarcel if (error) { 53083221Smarcel /* 53183221Smarcel * See fs/select.c in the Linux kernel. Without this, 53283221Smarcel * Maelstrom doesn't work. 53383221Smarcel */ 53483221Smarcel if (error == ERESTART) 53583221Smarcel error = EINTR; 53683221Smarcel goto select_out; 53783221Smarcel } 53814331Speter 53983221Smarcel if (args->timeout) { 54083366Sjulian if (td->td_retval[0]) { 54183221Smarcel /* 54283221Smarcel * Compute how much time was left of the timeout, 54383221Smarcel * by subtracting the current time and the time 54483221Smarcel * before we started the call, and subtracting 54583221Smarcel * that result from the user-supplied value. 54683221Smarcel */ 54783221Smarcel microtime(&tv1); 54883221Smarcel timevalsub(&tv1, &tv0); 54983221Smarcel timevalsub(&utv, &tv1); 55083221Smarcel if (utv.tv_sec < 0) 55183221Smarcel timevalclear(&utv); 55283221Smarcel } else 55383221Smarcel timevalclear(&utv); 55414331Speter#ifdef DEBUG 55583221Smarcel if (ldebug(select)) 55683221Smarcel printf(LMSG("outgoing timeout (%ld/%ld)"), 55783221Smarcel utv.tv_sec, utv.tv_usec); 55814331Speter#endif 559111797Sdes if ((error = copyout(&utv, args->timeout, sizeof(utv)))) 56083221Smarcel goto select_out; 56183221Smarcel } 56214331Speter 56314331Speterselect_out: 56414331Speter#ifdef DEBUG 56583221Smarcel if (ldebug(select)) 56683221Smarcel printf(LMSG("select_out -> %d"), error); 56714331Speter#endif 56883221Smarcel return error; 5699313Ssos} 5709313Ssos 571111798Sdesint 57283366Sjulianlinux_mremap(struct thread *td, struct linux_mremap_args *args) 57337548Sjkh{ 57437548Sjkh struct munmap_args /* { 57537548Sjkh void *addr; 57637548Sjkh size_t len; 577111798Sdes } */ bsd_args; 57837548Sjkh int error = 0; 579111798Sdes 58037548Sjkh#ifdef DEBUG 58172543Sjlemon if (ldebug(mremap)) 58272543Sjlemon printf(ARGS(mremap, "%p, %08lx, %08lx, %08lx"), 583111798Sdes (void *)args->addr, 584111798Sdes (unsigned long)args->old_len, 58572543Sjlemon (unsigned long)args->new_len, 58672543Sjlemon (unsigned long)args->flags); 58737548Sjkh#endif 58837548Sjkh args->new_len = round_page(args->new_len); 58937548Sjkh args->old_len = round_page(args->old_len); 59037548Sjkh 59137548Sjkh if (args->new_len > args->old_len) { 59283366Sjulian td->td_retval[0] = 0; 59337548Sjkh return ENOMEM; 59437548Sjkh } 59537548Sjkh 59637548Sjkh if (args->new_len < args->old_len) { 59783221Smarcel bsd_args.addr = (caddr_t)(args->addr + args->new_len); 59837548Sjkh bsd_args.len = args->old_len - args->new_len; 59983366Sjulian error = munmap(td, &bsd_args); 60037548Sjkh } 60137548Sjkh 602102963Sbde td->td_retval[0] = error ? 0 : (uintptr_t)args->addr; 60337548Sjkh return error; 60437548Sjkh} 60537548Sjkh 606103652Smdodd#define LINUX_MS_ASYNC 0x0001 607103652Smdodd#define LINUX_MS_INVALIDATE 0x0002 608103652Smdodd#define LINUX_MS_SYNC 0x0004 609103652Smdodd 61014331Speterint 61183366Sjulianlinux_msync(struct thread *td, struct linux_msync_args *args) 61214331Speter{ 61314331Speter struct msync_args bsd_args; 6149313Ssos 61583221Smarcel bsd_args.addr = (caddr_t)args->addr; 61614331Speter bsd_args.len = args->len; 617103652Smdodd bsd_args.flags = args->fl & ~LINUX_MS_SYNC; 61814331Speter 61983366Sjulian return msync(td, &bsd_args); 62014331Speter} 62114331Speter 62268201Sobrien#ifndef __alpha__ 6239313Ssosint 62483366Sjulianlinux_time(struct thread *td, struct linux_time_args *args) 6259313Ssos{ 62683221Smarcel struct timeval tv; 62783221Smarcel l_time_t tm; 62883221Smarcel int error; 6299313Ssos 6309313Ssos#ifdef DEBUG 63172543Sjlemon if (ldebug(time)) 63272543Sjlemon printf(ARGS(time, "*")); 6339313Ssos#endif 63483221Smarcel 63583221Smarcel microtime(&tv); 63683221Smarcel tm = tv.tv_sec; 637111797Sdes if (args->tm && (error = copyout(&tm, args->tm, sizeof(tm)))) 63883221Smarcel return error; 63983366Sjulian td->td_retval[0] = tm; 64083221Smarcel return 0; 6419313Ssos} 64268201Sobrien#endif /*!__alpha__*/ 6439313Ssos 64483221Smarcelstruct l_times_argv { 64583221Smarcel l_long tms_utime; 64683221Smarcel l_long tms_stime; 64783221Smarcel l_long tms_cutime; 64883221Smarcel l_long tms_cstime; 6499313Ssos}; 6509313Ssos 65174701Sgallatin#ifdef __alpha__ 65274701Sgallatin#define CLK_TCK 1024 /* Linux uses 1024 on alpha */ 65374701Sgallatin#else 65414381Speter#define CLK_TCK 100 /* Linux uses 100 */ 65574701Sgallatin#endif 65674701Sgallatin 65714381Speter#define CONVTCK(r) (r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK)) 65814381Speter 6599313Ssosint 66083366Sjulianlinux_times(struct thread *td, struct linux_times_args *args) 6619313Ssos{ 66283221Smarcel struct timeval tv; 66383221Smarcel struct l_times_argv tms; 66483221Smarcel struct rusage ru; 66583221Smarcel int error; 6669313Ssos 6679313Ssos#ifdef DEBUG 66872543Sjlemon if (ldebug(times)) 66972543Sjlemon printf(ARGS(times, "*")); 6709313Ssos#endif 67114381Speter 67283221Smarcel mtx_lock_spin(&sched_lock); 67383366Sjulian calcru(td->td_proc, &ru.ru_utime, &ru.ru_stime, NULL); 67483221Smarcel mtx_unlock_spin(&sched_lock); 67514381Speter 67683221Smarcel tms.tms_utime = CONVTCK(ru.ru_utime); 67783221Smarcel tms.tms_stime = CONVTCK(ru.ru_stime); 67814381Speter 67983366Sjulian tms.tms_cutime = CONVTCK(td->td_proc->p_stats->p_cru.ru_utime); 68083366Sjulian tms.tms_cstime = CONVTCK(td->td_proc->p_stats->p_cru.ru_stime); 68114381Speter 682111797Sdes if ((error = copyout(&tms, args->buf, sizeof(tms)))) 68383221Smarcel return error; 68483221Smarcel 68583221Smarcel microuptime(&tv); 68683366Sjulian td->td_retval[0] = (int)CONVTCK(tv); 68783221Smarcel return 0; 6889313Ssos} 6899313Ssos 6909313Ssosint 69183366Sjulianlinux_newuname(struct thread *td, struct linux_newuname_args *args) 6929313Ssos{ 69383221Smarcel struct l_new_utsname utsname; 69487275Srwatson char osname[LINUX_MAX_UTSNAME]; 69587275Srwatson char osrelease[LINUX_MAX_UTSNAME]; 6969313Ssos 6979313Ssos#ifdef DEBUG 69872543Sjlemon if (ldebug(newuname)) 69972543Sjlemon printf(ARGS(newuname, "*")); 7009313Ssos#endif 70150345Smarcel 702112206Sjhb linux_get_osname(td, osname); 703112206Sjhb linux_get_osrelease(td, osrelease); 70450465Smarcel 70583221Smarcel bzero(&utsname, sizeof(utsname)); 706105359Srobert strlcpy(utsname.sysname, osname, LINUX_MAX_UTSNAME); 707105359Srobert getcredhostname(td->td_ucred, utsname.nodename, LINUX_MAX_UTSNAME); 708105359Srobert strlcpy(utsname.release, osrelease, LINUX_MAX_UTSNAME); 709105359Srobert strlcpy(utsname.version, version, LINUX_MAX_UTSNAME); 710105359Srobert strlcpy(utsname.machine, machine, LINUX_MAX_UTSNAME); 711105359Srobert strlcpy(utsname.domainname, domainname, LINUX_MAX_UTSNAME); 71250345Smarcel 713111797Sdes return (copyout(&utsname, args->buf, sizeof(utsname))); 7149313Ssos} 7159313Ssos 71683221Smarcel#if defined(__i386__) 71783221Smarcelstruct l_utimbuf { 71883221Smarcel l_time_t l_actime; 71983221Smarcel l_time_t l_modtime; 72014381Speter}; 7219313Ssos 7229313Ssosint 72383366Sjulianlinux_utime(struct thread *td, struct linux_utime_args *args) 7249313Ssos{ 72583221Smarcel struct timeval tv[2], *tvp; 72683221Smarcel struct l_utimbuf lut; 727102814Siedowse char *fname; 72883221Smarcel int error; 7299313Ssos 730102814Siedowse LCONVPATHEXIST(td, args->fname, &fname); 73114331Speter 7329313Ssos#ifdef DEBUG 73372543Sjlemon if (ldebug(utime)) 734102814Siedowse printf(ARGS(utime, "%s, *"), fname); 7359313Ssos#endif 73614381Speter 73783221Smarcel if (args->times) { 738111797Sdes if ((error = copyin(args->times, &lut, sizeof lut))) { 739102814Siedowse LFREEPATH(fname); 74083221Smarcel return error; 741102814Siedowse } 74283221Smarcel tv[0].tv_sec = lut.l_actime; 74383221Smarcel tv[0].tv_usec = 0; 74483221Smarcel tv[1].tv_sec = lut.l_modtime; 74583221Smarcel tv[1].tv_usec = 0; 746102814Siedowse tvp = tv; 74783221Smarcel } else 748102814Siedowse tvp = NULL; 74983221Smarcel 750102814Siedowse error = kern_utimes(td, fname, UIO_SYSSPACE, tvp, UIO_SYSSPACE); 751102814Siedowse LFREEPATH(fname); 752102814Siedowse return (error); 7539313Ssos} 75483221Smarcel#endif /* __i386__ */ 7559313Ssos 75644384Sjulian#define __WCLONE 0x80000000 75744384Sjulian 75868201Sobrien#ifndef __alpha__ 7599313Ssosint 76083366Sjulianlinux_waitpid(struct thread *td, struct linux_waitpid_args *args) 7619313Ssos{ 76283221Smarcel struct wait_args /* { 76383221Smarcel int pid; 76483221Smarcel int *status; 76583221Smarcel int options; 76683221Smarcel struct rusage *rusage; 76783221Smarcel } */ tmp; 76883221Smarcel int error, tmpstat; 7699313Ssos 7709313Ssos#ifdef DEBUG 77172543Sjlemon if (ldebug(waitpid)) 77272543Sjlemon printf(ARGS(waitpid, "%d, %p, %d"), 77372543Sjlemon args->pid, (void *)args->status, args->options); 7749313Ssos#endif 7759313Ssos 77683221Smarcel tmp.pid = args->pid; 77783221Smarcel tmp.status = args->status; 77883221Smarcel tmp.options = (args->options & (WNOHANG | WUNTRACED)); 77983221Smarcel /* WLINUXCLONE should be equal to __WCLONE, but we make sure */ 78083221Smarcel if (args->options & __WCLONE) 78183221Smarcel tmp.options |= WLINUXCLONE; 78283221Smarcel tmp.rusage = NULL; 78343208Sjulian 78483366Sjulian if ((error = wait4(td, &tmp)) != 0) 78583221Smarcel return error; 78683221Smarcel 78783221Smarcel if (args->status) { 788111797Sdes if ((error = copyin(args->status, &tmpstat, sizeof(int))) != 0) 78983221Smarcel return error; 79083221Smarcel tmpstat &= 0xffff; 79183221Smarcel if (WIFSIGNALED(tmpstat)) 79283221Smarcel tmpstat = (tmpstat & 0xffffff80) | 79383221Smarcel BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat)); 79483221Smarcel else if (WIFSTOPPED(tmpstat)) 79583221Smarcel tmpstat = (tmpstat & 0xffff00ff) | 79683221Smarcel (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8); 797111797Sdes return copyout(&tmpstat, args->status, sizeof(int)); 79883221Smarcel } 79983221Smarcel 80014331Speter return 0; 8019313Ssos} 80268201Sobrien#endif /*!__alpha__*/ 8039313Ssos 80414331Speterint 80583366Sjulianlinux_wait4(struct thread *td, struct linux_wait4_args *args) 8069313Ssos{ 80783221Smarcel struct wait_args /* { 80883221Smarcel int pid; 80983221Smarcel int *status; 81083221Smarcel int options; 81183221Smarcel struct rusage *rusage; 81283221Smarcel } */ tmp; 81383221Smarcel int error, tmpstat; 814113613Sjhb struct proc *p; 8159313Ssos 8169313Ssos#ifdef DEBUG 81772543Sjlemon if (ldebug(wait4)) 81872543Sjlemon printf(ARGS(wait4, "%d, %p, %d, %p"), 81972543Sjlemon args->pid, (void *)args->status, args->options, 82072543Sjlemon (void *)args->rusage); 8219313Ssos#endif 8229313Ssos 82383221Smarcel tmp.pid = args->pid; 82483221Smarcel tmp.status = args->status; 82583221Smarcel tmp.options = (args->options & (WNOHANG | WUNTRACED)); 82683221Smarcel /* WLINUXCLONE should be equal to __WCLONE, but we make sure */ 82783221Smarcel if (args->options & __WCLONE) 82883221Smarcel tmp.options |= WLINUXCLONE; 82983221Smarcel tmp.rusage = (struct rusage *)args->rusage; 83014331Speter 83183366Sjulian if ((error = wait4(td, &tmp)) != 0) 83283221Smarcel return error; 83314331Speter 834113613Sjhb p = td->td_proc; 835113613Sjhb PROC_LOCK(p); 836113613Sjhb SIGDELSET(p->p_siglist, SIGCHLD); 837113613Sjhb PROC_UNLOCK(p); 83883221Smarcel 83983221Smarcel if (args->status) { 840111797Sdes if ((error = copyin(args->status, &tmpstat, sizeof(int))) != 0) 84183221Smarcel return error; 84283221Smarcel tmpstat &= 0xffff; 84383221Smarcel if (WIFSIGNALED(tmpstat)) 84483221Smarcel tmpstat = (tmpstat & 0xffffff80) | 84583221Smarcel BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat)); 84683221Smarcel else if (WIFSTOPPED(tmpstat)) 84783221Smarcel tmpstat = (tmpstat & 0xffff00ff) | 84883221Smarcel (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8); 849111797Sdes return copyout(&tmpstat, args->status, sizeof(int)); 85083221Smarcel } 85183221Smarcel 85214331Speter return 0; 8539313Ssos} 85413420Ssos 85514331Speterint 85683366Sjulianlinux_mknod(struct thread *td, struct linux_mknod_args *args) 85713420Ssos{ 858102814Siedowse char *path; 859102814Siedowse int error; 86014331Speter 861102814Siedowse LCONVPATHCREAT(td, args->path, &path); 86214331Speter 86314331Speter#ifdef DEBUG 86472543Sjlemon if (ldebug(mknod)) 865102814Siedowse printf(ARGS(mknod, "%s, %d, %d"), path, args->mode, args->dev); 86614331Speter#endif 86714331Speter 868102814Siedowse if (args->mode & S_IFIFO) 869102814Siedowse error = kern_mkfifo(td, path, UIO_SYSSPACE, args->mode); 870102814Siedowse else 871102814Siedowse error = kern_mknod(td, path, UIO_SYSSPACE, args->mode, 872102814Siedowse args->dev); 873102814Siedowse LFREEPATH(path); 874102814Siedowse return (error); 87513420Ssos} 87614331Speter 87714331Speter/* 87814331Speter * UGH! This is just about the dumbest idea I've ever heard!! 87914331Speter */ 88014331Speterint 88183366Sjulianlinux_personality(struct thread *td, struct linux_personality_args *args) 88214331Speter{ 88314331Speter#ifdef DEBUG 88472543Sjlemon if (ldebug(personality)) 885113579Sjhb printf(ARGS(personality, "%lu"), (unsigned long)args->per); 88614331Speter#endif 88768201Sobrien#ifndef __alpha__ 88814331Speter if (args->per != 0) 88914331Speter return EINVAL; 89068201Sobrien#endif 89114331Speter 89214331Speter /* Yes Jim, it's still a Linux... */ 89383366Sjulian td->td_retval[0] = 0; 89414331Speter return 0; 89514331Speter} 89614331Speter 89714331Speter/* 89814331Speter * Wrappers for get/setitimer for debugging.. 89914331Speter */ 90014331Speterint 90183366Sjulianlinux_setitimer(struct thread *td, struct linux_setitimer_args *args) 90214331Speter{ 90314331Speter struct setitimer_args bsa; 90414331Speter struct itimerval foo; 90514331Speter int error; 90614331Speter 90714331Speter#ifdef DEBUG 90872543Sjlemon if (ldebug(setitimer)) 90972543Sjlemon printf(ARGS(setitimer, "%p, %p"), 91072543Sjlemon (void *)args->itv, (void *)args->oitv); 91114331Speter#endif 91214331Speter bsa.which = args->which; 91383221Smarcel bsa.itv = (struct itimerval *)args->itv; 91483221Smarcel bsa.oitv = (struct itimerval *)args->oitv; 91514331Speter if (args->itv) { 916111797Sdes if ((error = copyin(args->itv, &foo, sizeof(foo)))) 91714331Speter return error; 91814331Speter#ifdef DEBUG 91972543Sjlemon if (ldebug(setitimer)) { 920111798Sdes printf("setitimer: value: sec: %ld, usec: %ld\n", 92172543Sjlemon foo.it_value.tv_sec, foo.it_value.tv_usec); 922111798Sdes printf("setitimer: interval: sec: %ld, usec: %ld\n", 92372543Sjlemon foo.it_interval.tv_sec, foo.it_interval.tv_usec); 92472543Sjlemon } 92514331Speter#endif 92614331Speter } 92783366Sjulian return setitimer(td, &bsa); 92814331Speter} 92914331Speter 93014331Speterint 93183366Sjulianlinux_getitimer(struct thread *td, struct linux_getitimer_args *args) 93214331Speter{ 93314331Speter struct getitimer_args bsa; 93414331Speter#ifdef DEBUG 93572543Sjlemon if (ldebug(getitimer)) 93672543Sjlemon printf(ARGS(getitimer, "%p"), (void *)args->itv); 93714331Speter#endif 93814331Speter bsa.which = args->which; 93983221Smarcel bsa.itv = (struct itimerval *)args->itv; 94083366Sjulian return getitimer(td, &bsa); 94114331Speter} 94230837Skato 94368201Sobrien#ifndef __alpha__ 94430837Skatoint 94583366Sjulianlinux_nice(struct thread *td, struct linux_nice_args *args) 94630837Skato{ 94730837Skato struct setpriority_args bsd_args; 94830837Skato 94930837Skato bsd_args.which = PRIO_PROCESS; 95030837Skato bsd_args.who = 0; /* current process */ 95130837Skato bsd_args.prio = args->inc; 95283366Sjulian return setpriority(td, &bsd_args); 95330837Skato} 95468201Sobrien#endif /*!__alpha__*/ 95530837Skato 95642185Ssosint 95783366Sjulianlinux_setgroups(struct thread *td, struct linux_setgroups_args *args) 95842185Ssos{ 95977183Srwatson struct ucred *newcred, *oldcred; 96083221Smarcel l_gid_t linux_gidset[NGROUPS]; 96150350Smarcel gid_t *bsd_gidset; 96250350Smarcel int ngrp, error; 96394621Sjhb struct proc *p; 96442185Ssos 96583221Smarcel ngrp = args->gidsetsize; 96694621Sjhb if (ngrp >= NGROUPS) 96794621Sjhb return (EINVAL); 968111797Sdes error = copyin(args->grouplist, linux_gidset, ngrp * sizeof(l_gid_t)); 96994621Sjhb if (error) 97094621Sjhb return (error); 97194621Sjhb newcred = crget(); 97294621Sjhb p = td->td_proc; 97394621Sjhb PROC_LOCK(p); 97494621Sjhb oldcred = p->p_ucred; 97542185Ssos 97650350Smarcel /* 97750350Smarcel * cr_groups[0] holds egid. Setting the whole set from 97850350Smarcel * the supplied set will cause egid to be changed too. 97950350Smarcel * Keep cr_groups[0] unchanged to prevent that. 98050350Smarcel */ 98142185Ssos 98294621Sjhb if ((error = suser_cred(oldcred, PRISON_ROOT)) != 0) { 98394621Sjhb PROC_UNLOCK(p); 98494621Sjhb crfree(newcred); 98550350Smarcel return (error); 98694621Sjhb } 98742185Ssos 98894621Sjhb crcopy(newcred, oldcred); 98950350Smarcel if (ngrp > 0) { 99077183Srwatson newcred->cr_ngroups = ngrp + 1; 99150350Smarcel 99277183Srwatson bsd_gidset = newcred->cr_groups; 99350350Smarcel ngrp--; 99450350Smarcel while (ngrp >= 0) { 99550350Smarcel bsd_gidset[ngrp + 1] = linux_gidset[ngrp]; 99650350Smarcel ngrp--; 99750350Smarcel } 99850350Smarcel } 99950350Smarcel else 100077183Srwatson newcred->cr_ngroups = 1; 100150350Smarcel 100294621Sjhb setsugid(p); 100394621Sjhb p->p_ucred = newcred; 100494621Sjhb PROC_UNLOCK(p); 100577183Srwatson crfree(oldcred); 100650350Smarcel return (0); 100742185Ssos} 100842185Ssos 100942185Ssosint 101083366Sjulianlinux_getgroups(struct thread *td, struct linux_getgroups_args *args) 101142185Ssos{ 101277183Srwatson struct ucred *cred; 101383221Smarcel l_gid_t linux_gidset[NGROUPS]; 101450350Smarcel gid_t *bsd_gidset; 101550350Smarcel int bsd_gidsetsz, ngrp, error; 101642185Ssos 101794454Sjhb cred = td->td_ucred; 101877183Srwatson bsd_gidset = cred->cr_groups; 101977183Srwatson bsd_gidsetsz = cred->cr_ngroups - 1; 102042185Ssos 102150350Smarcel /* 102250350Smarcel * cr_groups[0] holds egid. Returning the whole set 102350350Smarcel * here will cause a duplicate. Exclude cr_groups[0] 102450350Smarcel * to prevent that. 102550350Smarcel */ 102642185Ssos 102783221Smarcel if ((ngrp = args->gidsetsize) == 0) { 102883366Sjulian td->td_retval[0] = bsd_gidsetsz; 102950350Smarcel return (0); 103050350Smarcel } 103142185Ssos 103250546Smarcel if (ngrp < bsd_gidsetsz) 103350350Smarcel return (EINVAL); 103442185Ssos 103550546Smarcel ngrp = 0; 103650350Smarcel while (ngrp < bsd_gidsetsz) { 103750546Smarcel linux_gidset[ngrp] = bsd_gidset[ngrp + 1]; 103850350Smarcel ngrp++; 103950350Smarcel } 104050350Smarcel 1041111797Sdes if ((error = copyout(linux_gidset, args->grouplist, 104283221Smarcel ngrp * sizeof(l_gid_t)))) 104350350Smarcel return (error); 104450350Smarcel 104583366Sjulian td->td_retval[0] = ngrp; 104650350Smarcel return (0); 104742185Ssos} 104849626Smarcel 104968201Sobrien#ifndef __alpha__ 105049626Smarcelint 105183366Sjulianlinux_setrlimit(struct thread *td, struct linux_setrlimit_args *args) 105249626Smarcel{ 1053102814Siedowse struct rlimit bsd_rlim; 105483221Smarcel struct l_rlimit rlim; 1055102814Siedowse u_int which; 105665099Smarcel int error; 105749842Smarcel 105849626Smarcel#ifdef DEBUG 105972543Sjlemon if (ldebug(setrlimit)) 106072543Sjlemon printf(ARGS(setrlimit, "%d, %p"), 106183221Smarcel args->resource, (void *)args->rlim); 106249626Smarcel#endif 106349626Smarcel 106483221Smarcel if (args->resource >= LINUX_RLIM_NLIMITS) 106565099Smarcel return (EINVAL); 106649626Smarcel 1067102814Siedowse which = linux_to_bsd_resource[args->resource]; 1068102814Siedowse if (which == -1) 106965099Smarcel return (EINVAL); 107049626Smarcel 1071111797Sdes error = copyin(args->rlim, &rlim, sizeof(rlim)); 107265099Smarcel if (error) 107365099Smarcel return (error); 107449626Smarcel 1075102814Siedowse bsd_rlim.rlim_cur = (rlim_t)rlim.rlim_cur; 1076102814Siedowse bsd_rlim.rlim_max = (rlim_t)rlim.rlim_max; 1077102814Siedowse return (dosetrlimit(td, which, &bsd_rlim)); 107849626Smarcel} 107949626Smarcel 108049626Smarcelint 108183366Sjulianlinux_old_getrlimit(struct thread *td, struct linux_old_getrlimit_args *args) 108249626Smarcel{ 108383221Smarcel struct l_rlimit rlim; 1084102814Siedowse struct proc *p = td->td_proc; 1085102814Siedowse struct rlimit *bsd_rlp; 1086102814Siedowse u_int which; 108749842Smarcel 108849626Smarcel#ifdef DEBUG 108983221Smarcel if (ldebug(old_getrlimit)) 109083221Smarcel printf(ARGS(old_getrlimit, "%d, %p"), 109183221Smarcel args->resource, (void *)args->rlim); 109249626Smarcel#endif 109349626Smarcel 109483221Smarcel if (args->resource >= LINUX_RLIM_NLIMITS) 109565099Smarcel return (EINVAL); 109649626Smarcel 1097102814Siedowse which = linux_to_bsd_resource[args->resource]; 1098102814Siedowse if (which == -1) 109965099Smarcel return (EINVAL); 1100102814Siedowse bsd_rlp = &p->p_rlimit[which]; 110149626Smarcel 1102102814Siedowse rlim.rlim_cur = (unsigned long)bsd_rlp->rlim_cur; 110365106Smarcel if (rlim.rlim_cur == ULONG_MAX) 110465106Smarcel rlim.rlim_cur = LONG_MAX; 1105102814Siedowse rlim.rlim_max = (unsigned long)bsd_rlp->rlim_max; 110665106Smarcel if (rlim.rlim_max == ULONG_MAX) 110765106Smarcel rlim.rlim_max = LONG_MAX; 1108111797Sdes return (copyout(&rlim, args->rlim, sizeof(rlim))); 110949626Smarcel} 111083221Smarcel 111183221Smarcelint 111283366Sjulianlinux_getrlimit(struct thread *td, struct linux_getrlimit_args *args) 111383221Smarcel{ 111483221Smarcel struct l_rlimit rlim; 1115102814Siedowse struct proc *p = td->td_proc; 1116102814Siedowse struct rlimit *bsd_rlp; 1117102814Siedowse u_int which; 111883221Smarcel 111983221Smarcel#ifdef DEBUG 112083221Smarcel if (ldebug(getrlimit)) 112183221Smarcel printf(ARGS(getrlimit, "%d, %p"), 112283221Smarcel args->resource, (void *)args->rlim); 112383221Smarcel#endif 112483221Smarcel 112583221Smarcel if (args->resource >= LINUX_RLIM_NLIMITS) 112683221Smarcel return (EINVAL); 112783221Smarcel 1128102814Siedowse which = linux_to_bsd_resource[args->resource]; 1129102814Siedowse if (which == -1) 113083221Smarcel return (EINVAL); 1131102814Siedowse bsd_rlp = &p->p_rlimit[which]; 113283221Smarcel 1133102814Siedowse rlim.rlim_cur = (l_ulong)bsd_rlp->rlim_cur; 1134102814Siedowse rlim.rlim_max = (l_ulong)bsd_rlp->rlim_max; 1135111797Sdes return (copyout(&rlim, args->rlim, sizeof(rlim))); 113683221Smarcel} 113768201Sobrien#endif /*!__alpha__*/ 113849849Smarcel 113949849Smarcelint 114083366Sjulianlinux_sched_setscheduler(struct thread *td, 114183221Smarcel struct linux_sched_setscheduler_args *args) 114249849Smarcel{ 114349849Smarcel struct sched_setscheduler_args bsd; 114449849Smarcel 114549849Smarcel#ifdef DEBUG 114672543Sjlemon if (ldebug(sched_setscheduler)) 114772543Sjlemon printf(ARGS(sched_setscheduler, "%d, %d, %p"), 114883221Smarcel args->pid, args->policy, (const void *)args->param); 114949849Smarcel#endif 115049849Smarcel 115183221Smarcel switch (args->policy) { 115249849Smarcel case LINUX_SCHED_OTHER: 115349849Smarcel bsd.policy = SCHED_OTHER; 115449849Smarcel break; 115549849Smarcel case LINUX_SCHED_FIFO: 115649849Smarcel bsd.policy = SCHED_FIFO; 115749849Smarcel break; 115849849Smarcel case LINUX_SCHED_RR: 115949849Smarcel bsd.policy = SCHED_RR; 116049849Smarcel break; 116149849Smarcel default: 116249849Smarcel return EINVAL; 116349849Smarcel } 116449849Smarcel 116583221Smarcel bsd.pid = args->pid; 116683221Smarcel bsd.param = (struct sched_param *)args->param; 116783366Sjulian return sched_setscheduler(td, &bsd); 116849849Smarcel} 116949849Smarcel 117049849Smarcelint 117183366Sjulianlinux_sched_getscheduler(struct thread *td, 117283221Smarcel struct linux_sched_getscheduler_args *args) 117349849Smarcel{ 117449849Smarcel struct sched_getscheduler_args bsd; 117549849Smarcel int error; 117649849Smarcel 117749849Smarcel#ifdef DEBUG 117872543Sjlemon if (ldebug(sched_getscheduler)) 117983221Smarcel printf(ARGS(sched_getscheduler, "%d"), args->pid); 118049849Smarcel#endif 118149849Smarcel 118283221Smarcel bsd.pid = args->pid; 118383366Sjulian error = sched_getscheduler(td, &bsd); 118449849Smarcel 118583366Sjulian switch (td->td_retval[0]) { 118649849Smarcel case SCHED_OTHER: 118783366Sjulian td->td_retval[0] = LINUX_SCHED_OTHER; 118849849Smarcel break; 118949849Smarcel case SCHED_FIFO: 119083366Sjulian td->td_retval[0] = LINUX_SCHED_FIFO; 119149849Smarcel break; 119249849Smarcel case SCHED_RR: 119383366Sjulian td->td_retval[0] = LINUX_SCHED_RR; 119449849Smarcel break; 119549849Smarcel } 119649849Smarcel 119749849Smarcel return error; 119849849Smarcel} 119972538Sjlemon 120075053Salcint 120183366Sjulianlinux_sched_get_priority_max(struct thread *td, 120283221Smarcel struct linux_sched_get_priority_max_args *args) 120375053Salc{ 120475053Salc struct sched_get_priority_max_args bsd; 120575053Salc 120675053Salc#ifdef DEBUG 120775053Salc if (ldebug(sched_get_priority_max)) 120883221Smarcel printf(ARGS(sched_get_priority_max, "%d"), args->policy); 120975053Salc#endif 121075053Salc 121183221Smarcel switch (args->policy) { 121275053Salc case LINUX_SCHED_OTHER: 121375053Salc bsd.policy = SCHED_OTHER; 121475053Salc break; 121575053Salc case LINUX_SCHED_FIFO: 121675053Salc bsd.policy = SCHED_FIFO; 121775053Salc break; 121875053Salc case LINUX_SCHED_RR: 121975053Salc bsd.policy = SCHED_RR; 122075053Salc break; 122175053Salc default: 122275053Salc return EINVAL; 122375053Salc } 122483366Sjulian return sched_get_priority_max(td, &bsd); 122575053Salc} 122675053Salc 122775053Salcint 122883366Sjulianlinux_sched_get_priority_min(struct thread *td, 122983221Smarcel struct linux_sched_get_priority_min_args *args) 123075053Salc{ 123175053Salc struct sched_get_priority_min_args bsd; 123275053Salc 123375053Salc#ifdef DEBUG 123475053Salc if (ldebug(sched_get_priority_min)) 123583221Smarcel printf(ARGS(sched_get_priority_min, "%d"), args->policy); 123675053Salc#endif 123775053Salc 123883221Smarcel switch (args->policy) { 123975053Salc case LINUX_SCHED_OTHER: 124075053Salc bsd.policy = SCHED_OTHER; 124175053Salc break; 124275053Salc case LINUX_SCHED_FIFO: 124375053Salc bsd.policy = SCHED_FIFO; 124475053Salc break; 124575053Salc case LINUX_SCHED_RR: 124675053Salc bsd.policy = SCHED_RR; 124775053Salc break; 124875053Salc default: 124975053Salc return EINVAL; 125075053Salc } 125183366Sjulian return sched_get_priority_min(td, &bsd); 125275053Salc} 125375053Salc 125472538Sjlemon#define REBOOT_CAD_ON 0x89abcdef 125572538Sjlemon#define REBOOT_CAD_OFF 0 125672538Sjlemon#define REBOOT_HALT 0xcdef0123 125772538Sjlemon 125872538Sjlemonint 125983366Sjulianlinux_reboot(struct thread *td, struct linux_reboot_args *args) 126072538Sjlemon{ 126172538Sjlemon struct reboot_args bsd_args; 126272538Sjlemon 126372538Sjlemon#ifdef DEBUG 126472538Sjlemon if (ldebug(reboot)) 126583221Smarcel printf(ARGS(reboot, "0x%x"), args->cmd); 126672538Sjlemon#endif 126783221Smarcel if (args->cmd == REBOOT_CAD_ON || args->cmd == REBOOT_CAD_OFF) 126872538Sjlemon return (0); 126983221Smarcel bsd_args.opt = (args->cmd == REBOOT_HALT) ? RB_HALT : 0; 127083366Sjulian return (reboot(td, &bsd_args)); 127172538Sjlemon} 127283221Smarcel 127389717Sgallatin#ifndef __alpha__ 127489717Sgallatin 127583221Smarcel/* 127683221Smarcel * The FreeBSD native getpid(2), getgid(2) and getuid(2) also modify 127783366Sjulian * td->td_retval[1] when COMPAT_43 or COMPAT_SUNOS is defined. This 127883221Smarcel * globbers registers that are assumed to be preserved. The following 127983221Smarcel * lightweight syscalls fixes this. See also linux_getgid16() and 128083221Smarcel * linux_getuid16() in linux_uid16.c. 128183221Smarcel * 128283221Smarcel * linux_getpid() - MP SAFE 128383221Smarcel * linux_getgid() - MP SAFE 128483221Smarcel * linux_getuid() - MP SAFE 128583221Smarcel */ 128683221Smarcel 128783221Smarcelint 128883366Sjulianlinux_getpid(struct thread *td, struct linux_getpid_args *args) 128983221Smarcel{ 129083366Sjulian 129183366Sjulian td->td_retval[0] = td->td_proc->p_pid; 129283221Smarcel return (0); 129383221Smarcel} 129483221Smarcel 129583221Smarcelint 129683366Sjulianlinux_getgid(struct thread *td, struct linux_getgid_args *args) 129783221Smarcel{ 129883366Sjulian 129994454Sjhb td->td_retval[0] = td->td_ucred->cr_rgid; 130083221Smarcel return (0); 130183221Smarcel} 130283221Smarcel 130383221Smarcelint 130483366Sjulianlinux_getuid(struct thread *td, struct linux_getuid_args *args) 130583221Smarcel{ 130683366Sjulian 130794454Sjhb td->td_retval[0] = td->td_ucred->cr_ruid; 130883221Smarcel return (0); 130983221Smarcel} 131083503Smr 131189717Sgallatin#endif /*!__alpha__*/ 131289717Sgallatin 131383503Smrint 131483503Smrlinux_getsid(struct thread *td, struct linux_getsid_args *args) 131583503Smr{ 131683503Smr struct getsid_args bsd; 131783503Smr bsd.pid = args->pid; 131883503Smr return getsid(td, &bsd); 131983503Smr} 1320