linux_misc.c revision 218030
19313Ssos/*- 2133749Stjr * Copyright (c) 2002 Doug Rabson 39313Ssos * Copyright (c) 1994-1995 S�ren Schmidt 49313Ssos * All rights reserved. 59313Ssos * 69313Ssos * Redistribution and use in source and binary forms, with or without 79313Ssos * modification, are permitted provided that the following conditions 89313Ssos * are met: 99313Ssos * 1. Redistributions of source code must retain the above copyright 1014331Speter * notice, this list of conditions and the following disclaimer 119313Ssos * in this position and unchanged. 129313Ssos * 2. Redistributions in binary form must reproduce the above copyright 139313Ssos * notice, this list of conditions and the following disclaimer in the 149313Ssos * documentation and/or other materials provided with the distribution. 159313Ssos * 3. The name of the author may not be used to endorse or promote products 1697748Sschweikh * derived from this software without specific prior written permission 179313Ssos * 189313Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 199313Ssos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 209313Ssos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 219313Ssos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 229313Ssos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 239313Ssos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 249313Ssos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 259313Ssos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 269313Ssos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 279313Ssos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 289313Ssos */ 299313Ssos 30116173Sobrien#include <sys/cdefs.h> 31116173Sobrien__FBSDID("$FreeBSD: head/sys/compat/linux/linux_misc.c 218030 2011-01-28 18:47:07Z dchagin $"); 32116173Sobrien 33156874Sru#include "opt_compat.h" 3449842Smarcel 359313Ssos#include <sys/param.h> 36102954Sbde#include <sys/blist.h> 3776166Smarkm#include <sys/fcntl.h> 38158415Snetchild#if defined(__i386__) 3976166Smarkm#include <sys/imgact_aout.h> 40133816Stjr#endif 4191385Srobert#include <sys/jail.h> 4212458Sbde#include <sys/kernel.h> 43114216Skan#include <sys/limits.h> 4476166Smarkm#include <sys/lock.h> 45102954Sbde#include <sys/malloc.h> 469313Ssos#include <sys/mman.h> 479313Ssos#include <sys/mount.h> 4876166Smarkm#include <sys/mutex.h> 499313Ssos#include <sys/namei.h> 50164033Srwatson#include <sys/priv.h> 5176166Smarkm#include <sys/proc.h> 5272538Sjlemon#include <sys/reboot.h> 539313Ssos#include <sys/resourcevar.h> 54164184Strhodes#include <sys/sched.h> 5576166Smarkm#include <sys/signalvar.h> 569313Ssos#include <sys/stat.h> 57102814Siedowse#include <sys/syscallsubr.h> 5812458Sbde#include <sys/sysctl.h> 5976166Smarkm#include <sys/sysproto.h> 60102954Sbde#include <sys/systm.h> 6176166Smarkm#include <sys/time.h> 6280180Spirzyk#include <sys/vmmeter.h> 639313Ssos#include <sys/vnode.h> 649313Ssos#include <sys/wait.h> 65177257Srdivacky#include <sys/cpuset.h> 669313Ssos 67163606Srwatson#include <security/mac/mac_framework.h> 68163606Srwatson 6912652Sbde#include <vm/vm.h> 7012689Speter#include <vm/pmap.h> 7112458Sbde#include <vm/vm_kern.h> 7212689Speter#include <vm/vm_map.h> 7312842Sbde#include <vm/vm_extern.h> 7480180Spirzyk#include <vm/vm_object.h> 7580180Spirzyk#include <vm/swap_pager.h> 7612458Sbde 77140214Sobrien#ifdef COMPAT_LINUX32 78140214Sobrien#include <machine/../linux32/linux.h> 79140214Sobrien#include <machine/../linux32/linux32_proto.h> 80140214Sobrien#else 8164909Smarcel#include <machine/../linux/linux.h> 8268583Smarcel#include <machine/../linux/linux_proto.h> 83133816Stjr#endif 84102954Sbde 85177997Skib#include <compat/linux/linux_file.h> 8664909Smarcel#include <compat/linux/linux_mib.h> 87163734Snetchild#include <compat/linux/linux_signal.h> 8864909Smarcel#include <compat/linux/linux_util.h> 89178976Srdivacky#include <compat/linux/linux_sysproto.h> 90178976Srdivacky#include <compat/linux/linux_emul.h> 91178976Srdivacky#include <compat/linux/linux_misc.h> 9264909Smarcel 93191966Sdchaginint stclohz; /* Statistics clock frequency */ 94191966Sdchagin 9551793Smarcel#define BSD_TO_LINUX_SIGNAL(sig) \ 9651793Smarcel (((sig) <= LINUX_SIGTBLSZ) ? bsd_to_linux_signal[_SIG_IDX(sig)] : sig) 9751793Smarcel 9883221Smarcelstatic unsigned int linux_to_bsd_resource[LINUX_RLIM_NLIMITS] = { 9983221Smarcel RLIMIT_CPU, RLIMIT_FSIZE, RLIMIT_DATA, RLIMIT_STACK, 10083221Smarcel RLIMIT_CORE, RLIMIT_RSS, RLIMIT_NPROC, RLIMIT_NOFILE, 101165871Snetchild RLIMIT_MEMLOCK, RLIMIT_AS 10249626Smarcel}; 10349626Smarcel 10483221Smarcelstruct l_sysinfo { 10583221Smarcel l_long uptime; /* Seconds since boot */ 10683221Smarcel l_ulong loads[3]; /* 1, 5, and 15 minute load averages */ 107122802Ssobomax#define LINUX_SYSINFO_LOADS_SCALE 65536 10883221Smarcel l_ulong totalram; /* Total usable main memory size */ 10983221Smarcel l_ulong freeram; /* Available memory size */ 11083221Smarcel l_ulong sharedram; /* Amount of shared memory */ 11183221Smarcel l_ulong bufferram; /* Memory used by buffers */ 11283221Smarcel l_ulong totalswap; /* Total swap space size */ 11383221Smarcel l_ulong freeswap; /* swap space still available */ 11483221Smarcel l_ushort procs; /* Number of current processes */ 115164380Skib l_ushort pads; 116122802Ssobomax l_ulong totalbig; 117122802Ssobomax l_ulong freebig; 118122802Ssobomax l_uint mem_unit; 119164380Skib char _f[20-2*sizeof(l_long)-sizeof(l_int)]; /* padding */ 12080180Spirzyk}; 1219313Ssosint 12283366Sjulianlinux_sysinfo(struct thread *td, struct linux_sysinfo_args *args) 12380180Spirzyk{ 12483221Smarcel struct l_sysinfo sysinfo; 12583221Smarcel vm_object_t object; 126117723Sphk int i, j; 12783221Smarcel struct timespec ts; 12880180Spirzyk 12983221Smarcel getnanouptime(&ts); 130147816Sjhb if (ts.tv_nsec != 0) 131147816Sjhb ts.tv_sec++; 132147816Sjhb sysinfo.uptime = ts.tv_sec; 13380180Spirzyk 13483221Smarcel /* Use the information from the mib to get our load averages */ 13583221Smarcel for (i = 0; i < 3; i++) 136122802Ssobomax sysinfo.loads[i] = averunnable.ldavg[i] * 137122802Ssobomax LINUX_SYSINFO_LOADS_SCALE / averunnable.fscale; 13880180Spirzyk 13983221Smarcel sysinfo.totalram = physmem * PAGE_SIZE; 140170170Sattilio sysinfo.freeram = sysinfo.totalram - cnt.v_wire_count * PAGE_SIZE; 14180180Spirzyk 14283221Smarcel sysinfo.sharedram = 0; 143124082Salc mtx_lock(&vm_object_list_mtx); 144124082Salc TAILQ_FOREACH(object, &vm_object_list, object_list) 14583221Smarcel if (object->shadow_count > 1) 14683221Smarcel sysinfo.sharedram += object->resident_page_count; 147124082Salc mtx_unlock(&vm_object_list_mtx); 14880180Spirzyk 14983221Smarcel sysinfo.sharedram *= PAGE_SIZE; 15083221Smarcel sysinfo.bufferram = 0; 15180180Spirzyk 152117723Sphk swap_pager_status(&i, &j); 153165686Snetchild sysinfo.totalswap = i * PAGE_SIZE; 154117723Sphk sysinfo.freeswap = (i - j) * PAGE_SIZE; 15580180Spirzyk 156122802Ssobomax sysinfo.procs = nprocs; 15780180Spirzyk 158122802Ssobomax /* The following are only present in newer Linux kernels. */ 159122802Ssobomax sysinfo.totalbig = 0; 160122802Ssobomax sysinfo.freebig = 0; 161122802Ssobomax sysinfo.mem_unit = 1; 162122802Ssobomax 163111797Sdes return copyout(&sysinfo, args->info, sizeof(sysinfo)); 16480180Spirzyk} 16580180Spirzyk 16680180Spirzykint 16783366Sjulianlinux_alarm(struct thread *td, struct linux_alarm_args *args) 1689313Ssos{ 16983221Smarcel struct itimerval it, old_it; 170180766Srdivacky u_int secs; 171141467Sjhb int error; 1729313Ssos 1739313Ssos#ifdef DEBUG 17472543Sjlemon if (ldebug(alarm)) 17572543Sjlemon printf(ARGS(alarm, "%u"), args->secs); 1769313Ssos#endif 177180766Srdivacky 178180766Srdivacky secs = args->secs; 17983221Smarcel 180180766Srdivacky if (secs > INT_MAX) 181180766Srdivacky secs = INT_MAX; 18283221Smarcel 183180766Srdivacky it.it_value.tv_sec = (long) secs; 18483221Smarcel it.it_value.tv_usec = 0; 18583221Smarcel it.it_interval.tv_sec = 0; 18683221Smarcel it.it_interval.tv_usec = 0; 187141467Sjhb error = kern_setitimer(td, ITIMER_REAL, &it, &old_it); 188141467Sjhb if (error) 189141467Sjhb return (error); 190165686Snetchild if (timevalisset(&old_it.it_value)) { 19183221Smarcel if (old_it.it_value.tv_usec != 0) 19283221Smarcel old_it.it_value.tv_sec++; 19383366Sjulian td->td_retval[0] = old_it.it_value.tv_sec; 19483221Smarcel } 195141467Sjhb return (0); 1969313Ssos} 1979313Ssos 1989313Ssosint 19983366Sjulianlinux_brk(struct thread *td, struct linux_brk_args *args) 2009313Ssos{ 20183366Sjulian struct vmspace *vm = td->td_proc->p_vmspace; 20283221Smarcel vm_offset_t new, old; 20383221Smarcel struct obreak_args /* { 20483221Smarcel char * nsize; 20583221Smarcel } */ tmp; 2069313Ssos 2079313Ssos#ifdef DEBUG 20872543Sjlemon if (ldebug(brk)) 209133845Sobrien printf(ARGS(brk, "%p"), (void *)(uintptr_t)args->dsend); 2109313Ssos#endif 21183221Smarcel old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize); 21283221Smarcel new = (vm_offset_t)args->dsend; 213165686Snetchild tmp.nsize = (char *)new; 21483366Sjulian if (((caddr_t)new > vm->vm_daddr) && !obreak(td, &tmp)) 21583366Sjulian td->td_retval[0] = (long)new; 21683221Smarcel else 21783366Sjulian td->td_retval[0] = (long)old; 2189313Ssos 21983221Smarcel return 0; 2209313Ssos} 2219313Ssos 222158415Snetchild#if defined(__i386__) 223158415Snetchild/* XXX: what about amd64/linux32? */ 224133816Stjr 2259313Ssosint 22683366Sjulianlinux_uselib(struct thread *td, struct linux_uselib_args *args) 2279313Ssos{ 22883221Smarcel struct nameidata ni; 22983221Smarcel struct vnode *vp; 23083221Smarcel struct exec *a_out; 23183221Smarcel struct vattr attr; 23283221Smarcel vm_offset_t vmaddr; 23383221Smarcel unsigned long file_offset; 23483221Smarcel vm_offset_t buffer; 23583221Smarcel unsigned long bss_size; 236102814Siedowse char *library; 23783221Smarcel int error; 238160555Sjhb int locked, vfslocked; 2399313Ssos 240102814Siedowse LCONVPATHEXIST(td, args->library, &library); 24114331Speter 2429313Ssos#ifdef DEBUG 24372543Sjlemon if (ldebug(uselib)) 244102814Siedowse printf(ARGS(uselib, "%s"), library); 2459313Ssos#endif 2469313Ssos 24783221Smarcel a_out = NULL; 248160555Sjhb vfslocked = 0; 24983221Smarcel locked = 0; 25083221Smarcel vp = NULL; 25114114Speter 252160555Sjhb NDINIT(&ni, LOOKUP, ISOPEN | FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1, 253160555Sjhb UIO_SYSSPACE, library, td); 25483221Smarcel error = namei(&ni); 255102814Siedowse LFREEPATH(library); 25683221Smarcel if (error) 25783221Smarcel goto cleanup; 2589313Ssos 25983221Smarcel vp = ni.ni_vp; 260160555Sjhb vfslocked = NDHASGIANT(&ni); 26183221Smarcel NDFREE(&ni, NDF_ONLY_PNBUF); 2629313Ssos 26383221Smarcel /* 26483221Smarcel * From here on down, we have a locked vnode that must be unlocked. 265160555Sjhb * XXX: The code below largely duplicates exec_check_permissions(). 26683221Smarcel */ 267160555Sjhb locked = 1; 26814114Speter 26983221Smarcel /* Writable? */ 27083221Smarcel if (vp->v_writecount) { 27183221Smarcel error = ETXTBSY; 27283221Smarcel goto cleanup; 27383221Smarcel } 2749313Ssos 27583221Smarcel /* Executable? */ 276182371Sattilio error = VOP_GETATTR(vp, &attr, td->td_ucred); 27783221Smarcel if (error) 27883221Smarcel goto cleanup; 2799313Ssos 28083221Smarcel if ((vp->v_mount->mnt_flag & MNT_NOEXEC) || 28183221Smarcel ((attr.va_mode & 0111) == 0) || (attr.va_type != VREG)) { 282160555Sjhb /* EACCESS is what exec(2) returns. */ 28383221Smarcel error = ENOEXEC; 28483221Smarcel goto cleanup; 28583221Smarcel } 2869313Ssos 28783221Smarcel /* Sensible size? */ 28883221Smarcel if (attr.va_size == 0) { 28983221Smarcel error = ENOEXEC; 29083221Smarcel goto cleanup; 29183221Smarcel } 2929313Ssos 29383221Smarcel /* Can we access it? */ 29491406Sjhb error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td); 29583221Smarcel if (error) 29683221Smarcel goto cleanup; 2979313Ssos 29898209Srwatson /* 29998209Srwatson * XXX: This should use vn_open() so that it is properly authorized, 30098209Srwatson * and to reduce code redundancy all over the place here. 301160555Sjhb * XXX: Not really, it duplicates far more of exec_check_permissions() 302160555Sjhb * than vn_open(). 30398209Srwatson */ 304101189Srwatson#ifdef MAC 305183275Strasz error = mac_vnode_check_open(td->td_ucred, vp, VREAD); 306101189Srwatson if (error) 307101189Srwatson goto cleanup; 308101189Srwatson#endif 309170152Skib error = VOP_OPEN(vp, FREAD, td->td_ucred, td, NULL); 31083221Smarcel if (error) 31183221Smarcel goto cleanup; 3129313Ssos 313103941Sjeff /* Pull in executable header into kernel_map */ 314103941Sjeff error = vm_mmap(kernel_map, (vm_offset_t *)&a_out, PAGE_SIZE, 315144501Sjhb VM_PROT_READ, VM_PROT_READ, 0, OBJT_VNODE, vp, 0); 31683221Smarcel if (error) 31783221Smarcel goto cleanup; 3189313Ssos 31983221Smarcel /* Is it a Linux binary ? */ 32083221Smarcel if (((a_out->a_magic >> 16) & 0xff) != 0x64) { 32183221Smarcel error = ENOEXEC; 32283221Smarcel goto cleanup; 32383221Smarcel } 3249313Ssos 32583221Smarcel /* 32683221Smarcel * While we are here, we should REALLY do some more checks 32783221Smarcel */ 32814114Speter 32983221Smarcel /* Set file/virtual offset based on a.out variant. */ 33083221Smarcel switch ((int)(a_out->a_magic & 0xffff)) { 331165686Snetchild case 0413: /* ZMAGIC */ 33283221Smarcel file_offset = 1024; 33383221Smarcel break; 334165686Snetchild case 0314: /* QMAGIC */ 33583221Smarcel file_offset = 0; 33683221Smarcel break; 33783221Smarcel default: 33883221Smarcel error = ENOEXEC; 33983221Smarcel goto cleanup; 34083221Smarcel } 3419313Ssos 34283221Smarcel bss_size = round_page(a_out->a_bss); 34314114Speter 34483221Smarcel /* Check various fields in header for validity/bounds. */ 34583221Smarcel if (a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) { 34683221Smarcel error = ENOEXEC; 34783221Smarcel goto cleanup; 34883221Smarcel } 34914114Speter 35083221Smarcel /* text + data can't exceed file size */ 35183221Smarcel if (a_out->a_data + a_out->a_text > attr.va_size) { 35283221Smarcel error = EFAULT; 35383221Smarcel goto cleanup; 35483221Smarcel } 35514114Speter 35683221Smarcel /* 35783221Smarcel * text/data/bss must not exceed limits 35883221Smarcel * XXX - this is not complete. it should check current usage PLUS 35983221Smarcel * the resources needed by this library. 36083221Smarcel */ 361125454Sjhb PROC_LOCK(td->td_proc); 36284783Sps if (a_out->a_text > maxtsiz || 363125454Sjhb a_out->a_data + bss_size > lim_cur(td->td_proc, RLIMIT_DATA)) { 364125454Sjhb PROC_UNLOCK(td->td_proc); 36583221Smarcel error = ENOMEM; 36683221Smarcel goto cleanup; 36783221Smarcel } 368125454Sjhb PROC_UNLOCK(td->td_proc); 36914114Speter 370160555Sjhb /* 371160555Sjhb * Prevent more writers. 372160555Sjhb * XXX: Note that if any of the VM operations fail below we don't 373160555Sjhb * clear this flag. 374160555Sjhb */ 375101308Sjeff vp->v_vflag |= VV_TEXT; 37614114Speter 37783221Smarcel /* 378160555Sjhb * Lock no longer needed 379160555Sjhb */ 380160555Sjhb locked = 0; 381175294Sattilio VOP_UNLOCK(vp, 0); 382160555Sjhb VFS_UNLOCK_GIANT(vfslocked); 383160555Sjhb 384160555Sjhb /* 38583221Smarcel * Check if file_offset page aligned. Currently we cannot handle 38683221Smarcel * misalinged file offsets, and so we read in the entire image 38783221Smarcel * (what a waste). 38883221Smarcel */ 38983221Smarcel if (file_offset & PAGE_MASK) { 3909313Ssos#ifdef DEBUG 39183221Smarcel printf("uselib: Non page aligned binary %lu\n", file_offset); 3929313Ssos#endif 39383221Smarcel /* Map text+data read/write/execute */ 39414114Speter 39583221Smarcel /* a_entry is the load address and is page aligned */ 39683221Smarcel vmaddr = trunc_page(a_out->a_entry); 39714114Speter 39883221Smarcel /* get anon user mapping, read+write+execute */ 39983366Sjulian error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0, 40083366Sjulian &vmaddr, a_out->a_text + a_out->a_data, FALSE, VM_PROT_ALL, 40183221Smarcel VM_PROT_ALL, 0); 40283221Smarcel if (error) 40383221Smarcel goto cleanup; 4049313Ssos 40583221Smarcel /* map file into kernel_map */ 40683221Smarcel error = vm_mmap(kernel_map, &buffer, 40783221Smarcel round_page(a_out->a_text + a_out->a_data + file_offset), 408144501Sjhb VM_PROT_READ, VM_PROT_READ, 0, OBJT_VNODE, vp, 40983221Smarcel trunc_page(file_offset)); 41083221Smarcel if (error) 41183221Smarcel goto cleanup; 4129313Ssos 41383221Smarcel /* copy from kernel VM space to user space */ 414133816Stjr error = copyout(PTRIN(buffer + file_offset), 415111797Sdes (void *)vmaddr, a_out->a_text + a_out->a_data); 4169313Ssos 41783221Smarcel /* release temporary kernel space */ 41883221Smarcel vm_map_remove(kernel_map, buffer, buffer + 41983221Smarcel round_page(a_out->a_text + a_out->a_data + file_offset)); 4209313Ssos 42183221Smarcel if (error) 42283221Smarcel goto cleanup; 42383221Smarcel } else { 4249313Ssos#ifdef DEBUG 42583221Smarcel printf("uselib: Page aligned binary %lu\n", file_offset); 4269313Ssos#endif 42783221Smarcel /* 42883221Smarcel * for QMAGIC, a_entry is 20 bytes beyond the load address 42983221Smarcel * to skip the executable header 43083221Smarcel */ 43183221Smarcel vmaddr = trunc_page(a_out->a_entry); 43214114Speter 43383221Smarcel /* 43483221Smarcel * Map it all into the process's space as a single 43583221Smarcel * copy-on-write "data" segment. 43683221Smarcel */ 43783366Sjulian error = vm_mmap(&td->td_proc->p_vmspace->vm_map, &vmaddr, 43883221Smarcel a_out->a_text + a_out->a_data, VM_PROT_ALL, VM_PROT_ALL, 439144501Sjhb MAP_PRIVATE | MAP_FIXED, OBJT_VNODE, vp, file_offset); 44083221Smarcel if (error) 44183221Smarcel goto cleanup; 44283221Smarcel } 4439313Ssos#ifdef DEBUG 444165686Snetchild printf("mem=%08lx = %08lx %08lx\n", (long)vmaddr, ((long *)vmaddr)[0], 445165686Snetchild ((long *)vmaddr)[1]); 4469313Ssos#endif 44783221Smarcel if (bss_size != 0) { 44883221Smarcel /* Calculate BSS start address */ 44983221Smarcel vmaddr = trunc_page(a_out->a_entry) + a_out->a_text + 45083221Smarcel a_out->a_data; 45114114Speter 45283221Smarcel /* allocate some 'anon' space */ 45383366Sjulian error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0, 45483366Sjulian &vmaddr, bss_size, FALSE, VM_PROT_ALL, VM_PROT_ALL, 0); 45583221Smarcel if (error) 45683221Smarcel goto cleanup; 45783221Smarcel } 45814114Speter 45914114Spetercleanup: 46083221Smarcel /* Unlock vnode if needed */ 461160555Sjhb if (locked) { 462175294Sattilio VOP_UNLOCK(vp, 0); 463160555Sjhb VFS_UNLOCK_GIANT(vfslocked); 464160555Sjhb } 46514114Speter 46683221Smarcel /* Release the kernel mapping. */ 46783221Smarcel if (a_out) 46883221Smarcel vm_map_remove(kernel_map, (vm_offset_t)a_out, 46983221Smarcel (vm_offset_t)a_out + PAGE_SIZE); 47014114Speter 47183221Smarcel return error; 4729313Ssos} 4739313Ssos 474158415Snetchild#endif /* __i386__ */ 475133816Stjr 4769313Ssosint 47783366Sjulianlinux_select(struct thread *td, struct linux_select_args *args) 47814331Speter{ 479133747Stjr l_timeval ltv; 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) { 495133747Stjr if ((error = copyin(args->timeout, <v, sizeof(ltv)))) 49683221Smarcel goto select_out; 497133747Stjr utv.tv_sec = ltv.tv_sec; 498133747Stjr utv.tv_usec = ltv.tv_usec; 49914331Speter#ifdef DEBUG 50083221Smarcel if (ldebug(select)) 501153775Strhodes printf(LMSG("incoming timeout (%jd/%ld)"), 502153775Strhodes (intmax_t)utv.tv_sec, utv.tv_usec); 50314331Speter#endif 50483221Smarcel 50583221Smarcel if (itimerfix(&utv)) { 50683221Smarcel /* 50783221Smarcel * The timeval was invalid. Convert it to something 50883221Smarcel * valid that will act as it does under Linux. 50983221Smarcel */ 51083221Smarcel utv.tv_sec += utv.tv_usec / 1000000; 51183221Smarcel utv.tv_usec %= 1000000; 51283221Smarcel if (utv.tv_usec < 0) { 51383221Smarcel utv.tv_sec -= 1; 51483221Smarcel utv.tv_usec += 1000000; 51583221Smarcel } 51683221Smarcel if (utv.tv_sec < 0) 51783221Smarcel timevalclear(&utv); 51883221Smarcel } 51983221Smarcel microtime(&tv0); 520102814Siedowse tvp = &utv; 521102814Siedowse } else 522102814Siedowse tvp = NULL; 52314331Speter 524102814Siedowse error = kern_select(td, args->nfds, args->readfds, args->writefds, 525197049Skib args->exceptfds, tvp, sizeof(l_int) * 8); 526102814Siedowse 52714331Speter#ifdef DEBUG 52883221Smarcel if (ldebug(select)) 52972543Sjlemon printf(LMSG("real select returns %d"), error); 53014331Speter#endif 531182935Srdivacky if (error) 53283221Smarcel goto select_out; 53314331Speter 53483221Smarcel if (args->timeout) { 53583366Sjulian if (td->td_retval[0]) { 53683221Smarcel /* 53783221Smarcel * Compute how much time was left of the timeout, 53883221Smarcel * by subtracting the current time and the time 53983221Smarcel * before we started the call, and subtracting 54083221Smarcel * that result from the user-supplied value. 54183221Smarcel */ 54283221Smarcel microtime(&tv1); 54383221Smarcel timevalsub(&tv1, &tv0); 54483221Smarcel timevalsub(&utv, &tv1); 54583221Smarcel if (utv.tv_sec < 0) 54683221Smarcel timevalclear(&utv); 54783221Smarcel } else 54883221Smarcel timevalclear(&utv); 54914331Speter#ifdef DEBUG 55083221Smarcel if (ldebug(select)) 551153775Strhodes printf(LMSG("outgoing timeout (%jd/%ld)"), 552153775Strhodes (intmax_t)utv.tv_sec, utv.tv_usec); 55314331Speter#endif 554133747Stjr ltv.tv_sec = utv.tv_sec; 555133747Stjr ltv.tv_usec = utv.tv_usec; 556133747Stjr if ((error = copyout(<v, args->timeout, sizeof(ltv)))) 55783221Smarcel goto select_out; 55883221Smarcel } 55914331Speter 56014331Speterselect_out: 56114331Speter#ifdef DEBUG 56283221Smarcel if (ldebug(select)) 56383221Smarcel printf(LMSG("select_out -> %d"), error); 56414331Speter#endif 56583221Smarcel return error; 5669313Ssos} 5679313Ssos 568111798Sdesint 56983366Sjulianlinux_mremap(struct thread *td, struct linux_mremap_args *args) 57037548Sjkh{ 57137548Sjkh struct munmap_args /* { 57237548Sjkh void *addr; 57337548Sjkh size_t len; 574111798Sdes } */ bsd_args; 57537548Sjkh int error = 0; 576111798Sdes 57737548Sjkh#ifdef DEBUG 57872543Sjlemon if (ldebug(mremap)) 57972543Sjlemon printf(ARGS(mremap, "%p, %08lx, %08lx, %08lx"), 580133845Sobrien (void *)(uintptr_t)args->addr, 581111798Sdes (unsigned long)args->old_len, 58272543Sjlemon (unsigned long)args->new_len, 58372543Sjlemon (unsigned long)args->flags); 58437548Sjkh#endif 585176460Skib 586176460Skib if (args->flags & ~(LINUX_MREMAP_FIXED | LINUX_MREMAP_MAYMOVE)) { 587176460Skib td->td_retval[0] = 0; 588176460Skib return (EINVAL); 589176460Skib } 590176460Skib 591176460Skib /* 592176460Skib * Check for the page alignment. 593176460Skib * Linux defines PAGE_MASK to be FreeBSD ~PAGE_MASK. 594176460Skib */ 595176460Skib if (args->addr & PAGE_MASK) { 596176460Skib td->td_retval[0] = 0; 597176460Skib return (EINVAL); 598176460Skib } 599176460Skib 60037548Sjkh args->new_len = round_page(args->new_len); 60137548Sjkh args->old_len = round_page(args->old_len); 60237548Sjkh 60337548Sjkh if (args->new_len > args->old_len) { 60483366Sjulian td->td_retval[0] = 0; 60537548Sjkh return ENOMEM; 60637548Sjkh } 60737548Sjkh 60837548Sjkh if (args->new_len < args->old_len) { 609133816Stjr bsd_args.addr = 610133816Stjr (caddr_t)((uintptr_t)args->addr + args->new_len); 61137548Sjkh bsd_args.len = args->old_len - args->new_len; 61283366Sjulian error = munmap(td, &bsd_args); 61337548Sjkh } 61437548Sjkh 615102963Sbde td->td_retval[0] = error ? 0 : (uintptr_t)args->addr; 61637548Sjkh return error; 61737548Sjkh} 61837548Sjkh 619103652Smdodd#define LINUX_MS_ASYNC 0x0001 620103652Smdodd#define LINUX_MS_INVALIDATE 0x0002 621103652Smdodd#define LINUX_MS_SYNC 0x0004 622103652Smdodd 62314331Speterint 62483366Sjulianlinux_msync(struct thread *td, struct linux_msync_args *args) 62514331Speter{ 62614331Speter struct msync_args bsd_args; 6279313Ssos 628133816Stjr bsd_args.addr = (caddr_t)(uintptr_t)args->addr; 629133816Stjr bsd_args.len = (uintptr_t)args->len; 630103652Smdodd bsd_args.flags = args->fl & ~LINUX_MS_SYNC; 63114331Speter 63283366Sjulian return msync(td, &bsd_args); 63314331Speter} 63414331Speter 6359313Ssosint 63683366Sjulianlinux_time(struct thread *td, struct linux_time_args *args) 6379313Ssos{ 63883221Smarcel struct timeval tv; 63983221Smarcel l_time_t tm; 64083221Smarcel int error; 6419313Ssos 6429313Ssos#ifdef DEBUG 64372543Sjlemon if (ldebug(time)) 64472543Sjlemon printf(ARGS(time, "*")); 6459313Ssos#endif 64683221Smarcel 64783221Smarcel microtime(&tv); 64883221Smarcel tm = tv.tv_sec; 649111797Sdes if (args->tm && (error = copyout(&tm, args->tm, sizeof(tm)))) 65083221Smarcel return error; 65183366Sjulian td->td_retval[0] = tm; 65283221Smarcel return 0; 6539313Ssos} 6549313Ssos 65583221Smarcelstruct l_times_argv { 656191880Sdchagin l_clock_t tms_utime; 657191880Sdchagin l_clock_t tms_stime; 658191880Sdchagin l_clock_t tms_cutime; 659191880Sdchagin l_clock_t tms_cstime; 6609313Ssos}; 6619313Ssos 66274701Sgallatin 663191973Sdchagin/* 664191973Sdchagin * Glibc versions prior to 2.2.1 always use hard-coded CLK_TCK value. 665191973Sdchagin * Since 2.2.1 Glibc uses value exported from kernel via AT_CLKTCK 666191973Sdchagin * auxiliary vector entry. 667191973Sdchagin */ 668191973Sdchagin#define CLK_TCK 100 669191973Sdchagin 670191973Sdchagin#define CONVOTCK(r) (r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK)) 671191973Sdchagin#define CONVNTCK(r) (r.tv_sec * stclohz + r.tv_usec / (1000000 / stclohz)) 672191973Sdchagin 673191973Sdchagin#define CONVTCK(r) (linux_kernver(td) >= LINUX_KERNVER_2004000 ? \ 674191973Sdchagin CONVNTCK(r) : CONVOTCK(r)) 675191973Sdchagin 6769313Ssosint 67783366Sjulianlinux_times(struct thread *td, struct linux_times_args *args) 6789313Ssos{ 679136152Sjhb struct timeval tv, utime, stime, cutime, cstime; 68083221Smarcel struct l_times_argv tms; 681136152Sjhb struct proc *p; 68283221Smarcel int error; 6839313Ssos 6849313Ssos#ifdef DEBUG 68572543Sjlemon if (ldebug(times)) 68672543Sjlemon printf(ARGS(times, "*")); 6879313Ssos#endif 68814381Speter 689159896Snetchild if (args->buf != NULL) { 690159896Snetchild p = td->td_proc; 691159896Snetchild PROC_LOCK(p); 692170472Sattilio PROC_SLOCK(p); 693159896Snetchild calcru(p, &utime, &stime); 694170472Sattilio PROC_SUNLOCK(p); 695159896Snetchild calccru(p, &cutime, &cstime); 696159896Snetchild PROC_UNLOCK(p); 69714381Speter 698159896Snetchild tms.tms_utime = CONVTCK(utime); 699159896Snetchild tms.tms_stime = CONVTCK(stime); 70014381Speter 701159896Snetchild tms.tms_cutime = CONVTCK(cutime); 702159896Snetchild tms.tms_cstime = CONVTCK(cstime); 70314381Speter 704159896Snetchild if ((error = copyout(&tms, args->buf, sizeof(tms)))) 705159896Snetchild return error; 706159896Snetchild } 70783221Smarcel 70883221Smarcel microuptime(&tv); 70983366Sjulian td->td_retval[0] = (int)CONVTCK(tv); 71083221Smarcel return 0; 7119313Ssos} 7129313Ssos 7139313Ssosint 71483366Sjulianlinux_newuname(struct thread *td, struct linux_newuname_args *args) 7159313Ssos{ 71683221Smarcel struct l_new_utsname utsname; 71787275Srwatson char osname[LINUX_MAX_UTSNAME]; 71887275Srwatson char osrelease[LINUX_MAX_UTSNAME]; 719118149Sdes char *p; 7209313Ssos 7219313Ssos#ifdef DEBUG 72272543Sjlemon if (ldebug(newuname)) 72372543Sjlemon printf(ARGS(newuname, "*")); 7249313Ssos#endif 72550345Smarcel 726112206Sjhb linux_get_osname(td, osname); 727112206Sjhb linux_get_osrelease(td, osrelease); 72850465Smarcel 72983221Smarcel bzero(&utsname, sizeof(utsname)); 730105359Srobert strlcpy(utsname.sysname, osname, LINUX_MAX_UTSNAME); 731105359Srobert getcredhostname(td->td_ucred, utsname.nodename, LINUX_MAX_UTSNAME); 732194090Sjamie getcreddomainname(td->td_ucred, utsname.domainname, LINUX_MAX_UTSNAME); 733105359Srobert strlcpy(utsname.release, osrelease, LINUX_MAX_UTSNAME); 734105359Srobert strlcpy(utsname.version, version, LINUX_MAX_UTSNAME); 735118149Sdes for (p = utsname.version; *p != '\0'; ++p) 736118149Sdes if (*p == '\n') { 737118149Sdes *p = '\0'; 738118149Sdes break; 739118149Sdes } 740189362Sdchagin strlcpy(utsname.machine, linux_platform, LINUX_MAX_UTSNAME); 741165686Snetchild 742111797Sdes return (copyout(&utsname, args->buf, sizeof(utsname))); 7439313Ssos} 7449313Ssos 745140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 74683221Smarcelstruct l_utimbuf { 74783221Smarcel l_time_t l_actime; 74883221Smarcel l_time_t l_modtime; 74914381Speter}; 7509313Ssos 7519313Ssosint 75283366Sjulianlinux_utime(struct thread *td, struct linux_utime_args *args) 7539313Ssos{ 75483221Smarcel struct timeval tv[2], *tvp; 75583221Smarcel struct l_utimbuf lut; 756102814Siedowse char *fname; 75783221Smarcel int error; 7589313Ssos 759102814Siedowse LCONVPATHEXIST(td, args->fname, &fname); 76014331Speter 7619313Ssos#ifdef DEBUG 76272543Sjlemon if (ldebug(utime)) 763102814Siedowse printf(ARGS(utime, "%s, *"), fname); 7649313Ssos#endif 76514381Speter 76683221Smarcel if (args->times) { 767111797Sdes if ((error = copyin(args->times, &lut, sizeof lut))) { 768102814Siedowse LFREEPATH(fname); 76983221Smarcel return error; 770102814Siedowse } 77183221Smarcel tv[0].tv_sec = lut.l_actime; 77283221Smarcel tv[0].tv_usec = 0; 77383221Smarcel tv[1].tv_sec = lut.l_modtime; 77483221Smarcel tv[1].tv_usec = 0; 775102814Siedowse tvp = tv; 77683221Smarcel } else 777102814Siedowse tvp = NULL; 77883221Smarcel 779102814Siedowse error = kern_utimes(td, fname, UIO_SYSSPACE, tvp, UIO_SYSSPACE); 780102814Siedowse LFREEPATH(fname); 781102814Siedowse return (error); 7829313Ssos} 783165689Snetchild 784165689Snetchildint 785165689Snetchildlinux_utimes(struct thread *td, struct linux_utimes_args *args) 786165689Snetchild{ 787165689Snetchild l_timeval ltv[2]; 788165689Snetchild struct timeval tv[2], *tvp = NULL; 789165689Snetchild char *fname; 790165689Snetchild int error; 791165689Snetchild 792165689Snetchild LCONVPATHEXIST(td, args->fname, &fname); 793165689Snetchild 794165689Snetchild#ifdef DEBUG 795165689Snetchild if (ldebug(utimes)) 796165689Snetchild printf(ARGS(utimes, "%s, *"), fname); 797165689Snetchild#endif 798165689Snetchild 799165689Snetchild if (args->tptr != NULL) { 800165689Snetchild if ((error = copyin(args->tptr, ltv, sizeof ltv))) { 801165689Snetchild LFREEPATH(fname); 802165689Snetchild return (error); 803165689Snetchild } 804165689Snetchild tv[0].tv_sec = ltv[0].tv_sec; 805165689Snetchild tv[0].tv_usec = ltv[0].tv_usec; 806165689Snetchild tv[1].tv_sec = ltv[1].tv_sec; 807165689Snetchild tv[1].tv_usec = ltv[1].tv_usec; 808165689Snetchild tvp = tv; 809165689Snetchild } 810165689Snetchild 811165689Snetchild error = kern_utimes(td, fname, UIO_SYSSPACE, tvp, UIO_SYSSPACE); 812165689Snetchild LFREEPATH(fname); 813165689Snetchild return (error); 814165689Snetchild} 815177997Skib 816177997Skibint 817177997Skiblinux_futimesat(struct thread *td, struct linux_futimesat_args *args) 818177997Skib{ 819177997Skib l_timeval ltv[2]; 820177997Skib struct timeval tv[2], *tvp = NULL; 821177997Skib char *fname; 822177997Skib int error, dfd; 823177997Skib 824177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 825177997Skib LCONVPATHEXIST_AT(td, args->filename, &fname, dfd); 826177997Skib 827177997Skib#ifdef DEBUG 828177997Skib if (ldebug(futimesat)) 829177997Skib printf(ARGS(futimesat, "%s, *"), fname); 830177997Skib#endif 831177997Skib 832177997Skib if (args->utimes != NULL) { 833177997Skib if ((error = copyin(args->utimes, ltv, sizeof ltv))) { 834177997Skib LFREEPATH(fname); 835177997Skib return (error); 836177997Skib } 837177997Skib tv[0].tv_sec = ltv[0].tv_sec; 838177997Skib tv[0].tv_usec = ltv[0].tv_usec; 839177997Skib tv[1].tv_sec = ltv[1].tv_sec; 840177997Skib tv[1].tv_usec = ltv[1].tv_usec; 841177997Skib tvp = tv; 842177997Skib } 843177997Skib 844177997Skib error = kern_utimesat(td, dfd, fname, UIO_SYSSPACE, tvp, UIO_SYSSPACE); 845177997Skib LFREEPATH(fname); 846177997Skib return (error); 847177997Skib} 848133816Stjr#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 8499313Ssos 8509313Ssosint 851218030Sdchaginlinux_common_wait(struct thread *td, int pid, int *status, 852218030Sdchagin int options, struct rusage *ru) 8539313Ssos{ 854218030Sdchagin int error, tmpstat; 8559313Ssos 856218030Sdchagin error = kern_wait(td, pid, &tmpstat, options, ru); 857127140Sjhb if (error) 858218030Sdchagin return (error); 85983221Smarcel 860218030Sdchagin if (status) { 86183221Smarcel tmpstat &= 0xffff; 86283221Smarcel if (WIFSIGNALED(tmpstat)) 86383221Smarcel tmpstat = (tmpstat & 0xffffff80) | 86483221Smarcel BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat)); 86583221Smarcel else if (WIFSTOPPED(tmpstat)) 86683221Smarcel tmpstat = (tmpstat & 0xffff00ff) | 86783221Smarcel (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8); 868218030Sdchagin error = copyout(&tmpstat, status, sizeof(int)); 86983221Smarcel } 87083221Smarcel 871218030Sdchagin return (error); 8729313Ssos} 8739313Ssos 87414331Speterint 875218030Sdchaginlinux_waitpid(struct thread *td, struct linux_waitpid_args *args) 8769313Ssos{ 877218030Sdchagin int options; 878218030Sdchagin 8799313Ssos#ifdef DEBUG 880218030Sdchagin if (ldebug(waitpid)) 881218030Sdchagin printf(ARGS(waitpid, "%d, %p, %d"), 882218030Sdchagin args->pid, (void *)args->status, args->options); 8839313Ssos#endif 884218030Sdchagin /* 885218030Sdchagin * this is necessary because the test in kern_wait doesn't work 886218030Sdchagin * because we mess with the options here 887218030Sdchagin */ 888218030Sdchagin if (args->options & ~(WUNTRACED | WNOHANG | WCONTINUED | __WCLONE)) 889218030Sdchagin return (EINVAL); 890218030Sdchagin 891127140Sjhb options = (args->options & (WNOHANG | WUNTRACED)); 89283221Smarcel /* WLINUXCLONE should be equal to __WCLONE, but we make sure */ 89383221Smarcel if (args->options & __WCLONE) 894127140Sjhb options |= WLINUXCLONE; 89514331Speter 896218030Sdchagin return (linux_common_wait(td, args->pid, args->status, options, NULL)); 897218030Sdchagin} 89814331Speter 89983221Smarcel 90014331Speterint 90183366Sjulianlinux_mknod(struct thread *td, struct linux_mknod_args *args) 90213420Ssos{ 903102814Siedowse char *path; 904102814Siedowse int error; 90514331Speter 906102814Siedowse LCONVPATHCREAT(td, args->path, &path); 90714331Speter 90814331Speter#ifdef DEBUG 90972543Sjlemon if (ldebug(mknod)) 910102814Siedowse printf(ARGS(mknod, "%s, %d, %d"), path, args->mode, args->dev); 91114331Speter#endif 91214331Speter 913164893Sjkim switch (args->mode & S_IFMT) { 914164893Sjkim case S_IFIFO: 915164893Sjkim case S_IFSOCK: 916102814Siedowse error = kern_mkfifo(td, path, UIO_SYSSPACE, args->mode); 917164893Sjkim break; 918164893Sjkim 919164893Sjkim case S_IFCHR: 920164893Sjkim case S_IFBLK: 921102814Siedowse error = kern_mknod(td, path, UIO_SYSSPACE, args->mode, 922102814Siedowse args->dev); 923164893Sjkim break; 924164893Sjkim 925164893Sjkim case S_IFDIR: 926164893Sjkim error = EPERM; 927164893Sjkim break; 928164893Sjkim 929164893Sjkim case 0: 930164893Sjkim args->mode |= S_IFREG; 931165686Snetchild /* FALLTHROUGH */ 932164893Sjkim case S_IFREG: 933164893Sjkim error = kern_open(td, path, UIO_SYSSPACE, 934164893Sjkim O_WRONLY | O_CREAT | O_TRUNC, args->mode); 935177997Skib if (error == 0) 936177997Skib kern_close(td, td->td_retval[0]); 937164893Sjkim break; 938164893Sjkim 939164893Sjkim default: 940164893Sjkim error = EINVAL; 941164893Sjkim break; 942164893Sjkim } 943102814Siedowse LFREEPATH(path); 944102814Siedowse return (error); 94513420Ssos} 94614331Speter 947177997Skibint 948177997Skiblinux_mknodat(struct thread *td, struct linux_mknodat_args *args) 949177997Skib{ 950177997Skib char *path; 951177997Skib int error, dfd; 952177997Skib 953177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 954177997Skib LCONVPATHCREAT_AT(td, args->filename, &path, dfd); 955177997Skib 956177997Skib#ifdef DEBUG 957177997Skib if (ldebug(mknodat)) 958177997Skib printf(ARGS(mknodat, "%s, %d, %d"), path, args->mode, args->dev); 959177997Skib#endif 960177997Skib 961177997Skib switch (args->mode & S_IFMT) { 962177997Skib case S_IFIFO: 963177997Skib case S_IFSOCK: 964177997Skib error = kern_mkfifoat(td, dfd, path, UIO_SYSSPACE, args->mode); 965177997Skib break; 966177997Skib 967177997Skib case S_IFCHR: 968177997Skib case S_IFBLK: 969177997Skib error = kern_mknodat(td, dfd, path, UIO_SYSSPACE, args->mode, 970177997Skib args->dev); 971177997Skib break; 972177997Skib 973177997Skib case S_IFDIR: 974177997Skib error = EPERM; 975177997Skib break; 976177997Skib 977177997Skib case 0: 978177997Skib args->mode |= S_IFREG; 979177997Skib /* FALLTHROUGH */ 980177997Skib case S_IFREG: 981177997Skib error = kern_openat(td, dfd, path, UIO_SYSSPACE, 982177997Skib O_WRONLY | O_CREAT | O_TRUNC, args->mode); 983177997Skib if (error == 0) 984177997Skib kern_close(td, td->td_retval[0]); 985177997Skib break; 986177997Skib 987177997Skib default: 988177997Skib error = EINVAL; 989177997Skib break; 990177997Skib } 991177997Skib LFREEPATH(path); 992177997Skib return (error); 993177997Skib} 994177997Skib 99514331Speter/* 99614331Speter * UGH! This is just about the dumbest idea I've ever heard!! 99714331Speter */ 99814331Speterint 99983366Sjulianlinux_personality(struct thread *td, struct linux_personality_args *args) 100014331Speter{ 100114331Speter#ifdef DEBUG 100272543Sjlemon if (ldebug(personality)) 1003113579Sjhb printf(ARGS(personality, "%lu"), (unsigned long)args->per); 100414331Speter#endif 100514331Speter if (args->per != 0) 100614331Speter return EINVAL; 100714331Speter 100814331Speter /* Yes Jim, it's still a Linux... */ 100983366Sjulian td->td_retval[0] = 0; 101014331Speter return 0; 101114331Speter} 101214331Speter 1013133749Stjrstruct l_itimerval { 1014133749Stjr l_timeval it_interval; 1015133749Stjr l_timeval it_value; 1016133749Stjr}; 1017133749Stjr 1018140832Ssobomax#define B2L_ITIMERVAL(bip, lip) \ 1019140832Ssobomax (bip)->it_interval.tv_sec = (lip)->it_interval.tv_sec; \ 1020140832Ssobomax (bip)->it_interval.tv_usec = (lip)->it_interval.tv_usec; \ 1021140832Ssobomax (bip)->it_value.tv_sec = (lip)->it_value.tv_sec; \ 1022140832Ssobomax (bip)->it_value.tv_usec = (lip)->it_value.tv_usec; 1023140832Ssobomax 102414331Speterint 1025133749Stjrlinux_setitimer(struct thread *td, struct linux_setitimer_args *uap) 102614331Speter{ 102714331Speter int error; 1028140832Ssobomax struct l_itimerval ls; 1029140832Ssobomax struct itimerval aitv, oitv; 103014331Speter 103114331Speter#ifdef DEBUG 103272543Sjlemon if (ldebug(setitimer)) 103372543Sjlemon printf(ARGS(setitimer, "%p, %p"), 1034133840Sobrien (void *)uap->itv, (void *)uap->oitv); 103514331Speter#endif 1036140832Ssobomax 1037140832Ssobomax if (uap->itv == NULL) { 1038140832Ssobomax uap->itv = uap->oitv; 1039140832Ssobomax return (linux_getitimer(td, (struct linux_getitimer_args *)uap)); 104014331Speter } 1041140832Ssobomax 1042140832Ssobomax error = copyin(uap->itv, &ls, sizeof(ls)); 1043133749Stjr if (error != 0) 1044133749Stjr return (error); 1045140832Ssobomax B2L_ITIMERVAL(&aitv, &ls); 1046140832Ssobomax#ifdef DEBUG 1047140832Ssobomax if (ldebug(setitimer)) { 1048153775Strhodes printf("setitimer: value: sec: %jd, usec: %ld\n", 1049153775Strhodes (intmax_t)aitv.it_value.tv_sec, aitv.it_value.tv_usec); 1050153775Strhodes printf("setitimer: interval: sec: %jd, usec: %ld\n", 1051153775Strhodes (intmax_t)aitv.it_interval.tv_sec, aitv.it_interval.tv_usec); 1052133749Stjr } 1053140832Ssobomax#endif 1054140832Ssobomax error = kern_setitimer(td, uap->which, &aitv, &oitv); 1055140832Ssobomax if (error != 0 || uap->oitv == NULL) 1056140832Ssobomax return (error); 1057140832Ssobomax B2L_ITIMERVAL(&ls, &oitv); 1058140832Ssobomax 1059140832Ssobomax return (copyout(&ls, uap->oitv, sizeof(ls))); 106014331Speter} 106114331Speter 106214331Speterint 1063133749Stjrlinux_getitimer(struct thread *td, struct linux_getitimer_args *uap) 106414331Speter{ 1065133749Stjr int error; 1066140832Ssobomax struct l_itimerval ls; 1067140832Ssobomax struct itimerval aitv; 1068133749Stjr 106914331Speter#ifdef DEBUG 107072543Sjlemon if (ldebug(getitimer)) 1071133840Sobrien printf(ARGS(getitimer, "%p"), (void *)uap->itv); 107214331Speter#endif 1073140832Ssobomax error = kern_getitimer(td, uap->which, &aitv); 1074133749Stjr if (error != 0) 1075133749Stjr return (error); 1076140832Ssobomax B2L_ITIMERVAL(&ls, &aitv); 1077140832Ssobomax return (copyout(&ls, uap->itv, sizeof(ls))); 107814331Speter} 107930837Skato 108030837Skatoint 108183366Sjulianlinux_nice(struct thread *td, struct linux_nice_args *args) 108230837Skato{ 1083165686Snetchild struct setpriority_args bsd_args; 108430837Skato 108530837Skato bsd_args.which = PRIO_PROCESS; 1086165686Snetchild bsd_args.who = 0; /* current process */ 108730837Skato bsd_args.prio = args->inc; 108883366Sjulian return setpriority(td, &bsd_args); 108930837Skato} 109030837Skato 109142185Ssosint 109283366Sjulianlinux_setgroups(struct thread *td, struct linux_setgroups_args *args) 109342185Ssos{ 109477183Srwatson struct ucred *newcred, *oldcred; 1095194498Sbrooks l_gid_t *linux_gidset; 109650350Smarcel gid_t *bsd_gidset; 109750350Smarcel int ngrp, error; 109894621Sjhb struct proc *p; 109942185Ssos 110083221Smarcel ngrp = args->gidsetsize; 1101202341Sbrooks if (ngrp < 0 || ngrp >= ngroups_max + 1) 110294621Sjhb return (EINVAL); 1103194498Sbrooks linux_gidset = malloc(ngrp * sizeof(*linux_gidset), M_TEMP, M_WAITOK); 1104111797Sdes error = copyin(args->grouplist, linux_gidset, ngrp * sizeof(l_gid_t)); 110594621Sjhb if (error) 1106194498Sbrooks goto out; 110794621Sjhb newcred = crget(); 110894621Sjhb p = td->td_proc; 110994621Sjhb PROC_LOCK(p); 1110194498Sbrooks oldcred = crcopysafe(p, newcred); 111142185Ssos 111250350Smarcel /* 111350350Smarcel * cr_groups[0] holds egid. Setting the whole set from 111450350Smarcel * the supplied set will cause egid to be changed too. 111550350Smarcel * Keep cr_groups[0] unchanged to prevent that. 111650350Smarcel */ 111742185Ssos 1118170587Srwatson if ((error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS, 0)) != 0) { 111994621Sjhb PROC_UNLOCK(p); 112094621Sjhb crfree(newcred); 1121194498Sbrooks goto out; 112294621Sjhb } 112342185Ssos 112450350Smarcel if (ngrp > 0) { 112577183Srwatson newcred->cr_ngroups = ngrp + 1; 112650350Smarcel 112777183Srwatson bsd_gidset = newcred->cr_groups; 112850350Smarcel ngrp--; 112950350Smarcel while (ngrp >= 0) { 113050350Smarcel bsd_gidset[ngrp + 1] = linux_gidset[ngrp]; 113150350Smarcel ngrp--; 113250350Smarcel } 1133165686Snetchild } else 113477183Srwatson newcred->cr_ngroups = 1; 113550350Smarcel 113694621Sjhb setsugid(p); 113794621Sjhb p->p_ucred = newcred; 113894621Sjhb PROC_UNLOCK(p); 113977183Srwatson crfree(oldcred); 1140194498Sbrooks error = 0; 1141194498Sbrooksout: 1142194498Sbrooks free(linux_gidset, M_TEMP); 1143194498Sbrooks return (error); 114442185Ssos} 114542185Ssos 114642185Ssosint 114783366Sjulianlinux_getgroups(struct thread *td, struct linux_getgroups_args *args) 114842185Ssos{ 114977183Srwatson struct ucred *cred; 1150194498Sbrooks l_gid_t *linux_gidset; 115150350Smarcel gid_t *bsd_gidset; 115250350Smarcel int bsd_gidsetsz, ngrp, error; 115342185Ssos 115494454Sjhb cred = td->td_ucred; 115577183Srwatson bsd_gidset = cred->cr_groups; 115677183Srwatson bsd_gidsetsz = cred->cr_ngroups - 1; 115742185Ssos 115850350Smarcel /* 115950350Smarcel * cr_groups[0] holds egid. Returning the whole set 116050350Smarcel * here will cause a duplicate. Exclude cr_groups[0] 116150350Smarcel * to prevent that. 116250350Smarcel */ 116342185Ssos 116483221Smarcel if ((ngrp = args->gidsetsize) == 0) { 116583366Sjulian td->td_retval[0] = bsd_gidsetsz; 116650350Smarcel return (0); 116750350Smarcel } 116842185Ssos 116950546Smarcel if (ngrp < bsd_gidsetsz) 117050350Smarcel return (EINVAL); 117142185Ssos 117250546Smarcel ngrp = 0; 1173194498Sbrooks linux_gidset = malloc(bsd_gidsetsz * sizeof(*linux_gidset), 1174194498Sbrooks M_TEMP, M_WAITOK); 117550350Smarcel while (ngrp < bsd_gidsetsz) { 117650546Smarcel linux_gidset[ngrp] = bsd_gidset[ngrp + 1]; 117750350Smarcel ngrp++; 117850350Smarcel } 117950350Smarcel 1180194498Sbrooks error = copyout(linux_gidset, args->grouplist, ngrp * sizeof(l_gid_t)); 1181194498Sbrooks free(linux_gidset, M_TEMP); 1182194498Sbrooks if (error) 118350350Smarcel return (error); 118450350Smarcel 118583366Sjulian td->td_retval[0] = ngrp; 118650350Smarcel return (0); 118742185Ssos} 118849626Smarcel 118949626Smarcelint 119083366Sjulianlinux_setrlimit(struct thread *td, struct linux_setrlimit_args *args) 119149626Smarcel{ 1192102814Siedowse struct rlimit bsd_rlim; 119383221Smarcel struct l_rlimit rlim; 1194102814Siedowse u_int which; 119565099Smarcel int error; 119649842Smarcel 119749626Smarcel#ifdef DEBUG 119872543Sjlemon if (ldebug(setrlimit)) 119972543Sjlemon printf(ARGS(setrlimit, "%d, %p"), 120083221Smarcel args->resource, (void *)args->rlim); 120149626Smarcel#endif 120249626Smarcel 120383221Smarcel if (args->resource >= LINUX_RLIM_NLIMITS) 120465099Smarcel return (EINVAL); 120549626Smarcel 1206102814Siedowse which = linux_to_bsd_resource[args->resource]; 1207102814Siedowse if (which == -1) 120865099Smarcel return (EINVAL); 120949626Smarcel 1210111797Sdes error = copyin(args->rlim, &rlim, sizeof(rlim)); 121165099Smarcel if (error) 121265099Smarcel return (error); 121349626Smarcel 1214102814Siedowse bsd_rlim.rlim_cur = (rlim_t)rlim.rlim_cur; 1215102814Siedowse bsd_rlim.rlim_max = (rlim_t)rlim.rlim_max; 1216125454Sjhb return (kern_setrlimit(td, which, &bsd_rlim)); 121749626Smarcel} 121849626Smarcel 121949626Smarcelint 122083366Sjulianlinux_old_getrlimit(struct thread *td, struct linux_old_getrlimit_args *args) 122149626Smarcel{ 122283221Smarcel struct l_rlimit rlim; 1223102814Siedowse struct proc *p = td->td_proc; 1224125454Sjhb struct rlimit bsd_rlim; 1225102814Siedowse u_int which; 122649842Smarcel 122749626Smarcel#ifdef DEBUG 122883221Smarcel if (ldebug(old_getrlimit)) 122983221Smarcel printf(ARGS(old_getrlimit, "%d, %p"), 123083221Smarcel args->resource, (void *)args->rlim); 123149626Smarcel#endif 123249626Smarcel 123383221Smarcel if (args->resource >= LINUX_RLIM_NLIMITS) 123465099Smarcel return (EINVAL); 123549626Smarcel 1236102814Siedowse which = linux_to_bsd_resource[args->resource]; 1237102814Siedowse if (which == -1) 123865099Smarcel return (EINVAL); 123949626Smarcel 1240125454Sjhb PROC_LOCK(p); 1241125454Sjhb lim_rlimit(p, which, &bsd_rlim); 1242125454Sjhb PROC_UNLOCK(p); 1243125454Sjhb 1244140214Sobrien#ifdef COMPAT_LINUX32 1245140214Sobrien rlim.rlim_cur = (unsigned int)bsd_rlim.rlim_cur; 1246140214Sobrien if (rlim.rlim_cur == UINT_MAX) 1247140214Sobrien rlim.rlim_cur = INT_MAX; 1248140214Sobrien rlim.rlim_max = (unsigned int)bsd_rlim.rlim_max; 1249140214Sobrien if (rlim.rlim_max == UINT_MAX) 1250140214Sobrien rlim.rlim_max = INT_MAX; 1251140214Sobrien#else 1252125454Sjhb rlim.rlim_cur = (unsigned long)bsd_rlim.rlim_cur; 125365106Smarcel if (rlim.rlim_cur == ULONG_MAX) 125465106Smarcel rlim.rlim_cur = LONG_MAX; 1255125454Sjhb rlim.rlim_max = (unsigned long)bsd_rlim.rlim_max; 125665106Smarcel if (rlim.rlim_max == ULONG_MAX) 125765106Smarcel rlim.rlim_max = LONG_MAX; 1258133816Stjr#endif 1259111797Sdes return (copyout(&rlim, args->rlim, sizeof(rlim))); 126049626Smarcel} 126183221Smarcel 126283221Smarcelint 126383366Sjulianlinux_getrlimit(struct thread *td, struct linux_getrlimit_args *args) 126483221Smarcel{ 126583221Smarcel struct l_rlimit rlim; 1266102814Siedowse struct proc *p = td->td_proc; 1267125454Sjhb struct rlimit bsd_rlim; 1268102814Siedowse u_int which; 126983221Smarcel 127083221Smarcel#ifdef DEBUG 127183221Smarcel if (ldebug(getrlimit)) 127283221Smarcel printf(ARGS(getrlimit, "%d, %p"), 127383221Smarcel args->resource, (void *)args->rlim); 127483221Smarcel#endif 127583221Smarcel 127683221Smarcel if (args->resource >= LINUX_RLIM_NLIMITS) 127783221Smarcel return (EINVAL); 127883221Smarcel 1279102814Siedowse which = linux_to_bsd_resource[args->resource]; 1280102814Siedowse if (which == -1) 128183221Smarcel return (EINVAL); 128283221Smarcel 1283125454Sjhb PROC_LOCK(p); 1284125454Sjhb lim_rlimit(p, which, &bsd_rlim); 1285125454Sjhb PROC_UNLOCK(p); 1286125454Sjhb 1287125454Sjhb rlim.rlim_cur = (l_ulong)bsd_rlim.rlim_cur; 1288125454Sjhb rlim.rlim_max = (l_ulong)bsd_rlim.rlim_max; 1289111797Sdes return (copyout(&rlim, args->rlim, sizeof(rlim))); 129083221Smarcel} 129149849Smarcel 129249849Smarcelint 129383366Sjulianlinux_sched_setscheduler(struct thread *td, 129483221Smarcel struct linux_sched_setscheduler_args *args) 129549849Smarcel{ 129649849Smarcel struct sched_setscheduler_args bsd; 129749849Smarcel 129849849Smarcel#ifdef DEBUG 129972543Sjlemon if (ldebug(sched_setscheduler)) 130072543Sjlemon printf(ARGS(sched_setscheduler, "%d, %d, %p"), 130183221Smarcel args->pid, args->policy, (const void *)args->param); 130249849Smarcel#endif 130349849Smarcel 130483221Smarcel switch (args->policy) { 130549849Smarcel case LINUX_SCHED_OTHER: 130649849Smarcel bsd.policy = SCHED_OTHER; 130749849Smarcel break; 130849849Smarcel case LINUX_SCHED_FIFO: 130949849Smarcel bsd.policy = SCHED_FIFO; 131049849Smarcel break; 131149849Smarcel case LINUX_SCHED_RR: 131249849Smarcel bsd.policy = SCHED_RR; 131349849Smarcel break; 131449849Smarcel default: 131549849Smarcel return EINVAL; 131649849Smarcel } 131749849Smarcel 131883221Smarcel bsd.pid = args->pid; 131983221Smarcel bsd.param = (struct sched_param *)args->param; 132083366Sjulian return sched_setscheduler(td, &bsd); 132149849Smarcel} 132249849Smarcel 132349849Smarcelint 132483366Sjulianlinux_sched_getscheduler(struct thread *td, 132583221Smarcel struct linux_sched_getscheduler_args *args) 132649849Smarcel{ 132749849Smarcel struct sched_getscheduler_args bsd; 132849849Smarcel int error; 132949849Smarcel 133049849Smarcel#ifdef DEBUG 133172543Sjlemon if (ldebug(sched_getscheduler)) 133283221Smarcel printf(ARGS(sched_getscheduler, "%d"), args->pid); 133349849Smarcel#endif 133449849Smarcel 133583221Smarcel bsd.pid = args->pid; 133683366Sjulian error = sched_getscheduler(td, &bsd); 133749849Smarcel 133883366Sjulian switch (td->td_retval[0]) { 133949849Smarcel case SCHED_OTHER: 134083366Sjulian td->td_retval[0] = LINUX_SCHED_OTHER; 134149849Smarcel break; 134249849Smarcel case SCHED_FIFO: 134383366Sjulian td->td_retval[0] = LINUX_SCHED_FIFO; 134449849Smarcel break; 134549849Smarcel case SCHED_RR: 134683366Sjulian td->td_retval[0] = LINUX_SCHED_RR; 134749849Smarcel break; 134849849Smarcel } 134949849Smarcel 135049849Smarcel return error; 135149849Smarcel} 135272538Sjlemon 135375053Salcint 135483366Sjulianlinux_sched_get_priority_max(struct thread *td, 135583221Smarcel struct linux_sched_get_priority_max_args *args) 135675053Salc{ 135775053Salc struct sched_get_priority_max_args bsd; 135875053Salc 135975053Salc#ifdef DEBUG 136075053Salc if (ldebug(sched_get_priority_max)) 136183221Smarcel printf(ARGS(sched_get_priority_max, "%d"), args->policy); 136275053Salc#endif 136375053Salc 136483221Smarcel switch (args->policy) { 136575053Salc case LINUX_SCHED_OTHER: 136675053Salc bsd.policy = SCHED_OTHER; 136775053Salc break; 136875053Salc case LINUX_SCHED_FIFO: 136975053Salc bsd.policy = SCHED_FIFO; 137075053Salc break; 137175053Salc case LINUX_SCHED_RR: 137275053Salc bsd.policy = SCHED_RR; 137375053Salc break; 137475053Salc default: 137575053Salc return EINVAL; 137675053Salc } 137783366Sjulian return sched_get_priority_max(td, &bsd); 137875053Salc} 137975053Salc 138075053Salcint 138183366Sjulianlinux_sched_get_priority_min(struct thread *td, 138283221Smarcel struct linux_sched_get_priority_min_args *args) 138375053Salc{ 138475053Salc struct sched_get_priority_min_args bsd; 138575053Salc 138675053Salc#ifdef DEBUG 138775053Salc if (ldebug(sched_get_priority_min)) 138883221Smarcel printf(ARGS(sched_get_priority_min, "%d"), args->policy); 138975053Salc#endif 139075053Salc 139183221Smarcel switch (args->policy) { 139275053Salc case LINUX_SCHED_OTHER: 139375053Salc bsd.policy = SCHED_OTHER; 139475053Salc break; 139575053Salc case LINUX_SCHED_FIFO: 139675053Salc bsd.policy = SCHED_FIFO; 139775053Salc break; 139875053Salc case LINUX_SCHED_RR: 139975053Salc bsd.policy = SCHED_RR; 140075053Salc break; 140175053Salc default: 140275053Salc return EINVAL; 140375053Salc } 140483366Sjulian return sched_get_priority_min(td, &bsd); 140575053Salc} 140675053Salc 140772538Sjlemon#define REBOOT_CAD_ON 0x89abcdef 140872538Sjlemon#define REBOOT_CAD_OFF 0 140972538Sjlemon#define REBOOT_HALT 0xcdef0123 1410162358Snetchild#define REBOOT_RESTART 0x01234567 1411162358Snetchild#define REBOOT_RESTART2 0xA1B2C3D4 1412162358Snetchild#define REBOOT_POWEROFF 0x4321FEDC 1413162358Snetchild#define REBOOT_MAGIC1 0xfee1dead 1414162358Snetchild#define REBOOT_MAGIC2 0x28121969 1415162358Snetchild#define REBOOT_MAGIC2A 0x05121996 1416162358Snetchild#define REBOOT_MAGIC2B 0x16041998 141772538Sjlemon 141872538Sjlemonint 141983366Sjulianlinux_reboot(struct thread *td, struct linux_reboot_args *args) 142072538Sjlemon{ 142172538Sjlemon struct reboot_args bsd_args; 142272538Sjlemon 142372538Sjlemon#ifdef DEBUG 142472538Sjlemon if (ldebug(reboot)) 142583221Smarcel printf(ARGS(reboot, "0x%x"), args->cmd); 142672538Sjlemon#endif 1427162358Snetchild 1428162358Snetchild if (args->magic1 != REBOOT_MAGIC1) 1429162358Snetchild return EINVAL; 1430162358Snetchild 1431162358Snetchild switch (args->magic2) { 1432162358Snetchild case REBOOT_MAGIC2: 1433162358Snetchild case REBOOT_MAGIC2A: 1434162358Snetchild case REBOOT_MAGIC2B: 1435162358Snetchild break; 1436162358Snetchild default: 1437162358Snetchild return EINVAL; 1438162358Snetchild } 1439162358Snetchild 1440162358Snetchild switch (args->cmd) { 1441162358Snetchild case REBOOT_CAD_ON: 1442162358Snetchild case REBOOT_CAD_OFF: 1443164033Srwatson return (priv_check(td, PRIV_REBOOT)); 1444162358Snetchild case REBOOT_HALT: 1445162358Snetchild bsd_args.opt = RB_HALT; 1446162358Snetchild break; 1447162358Snetchild case REBOOT_RESTART: 1448162358Snetchild case REBOOT_RESTART2: 1449162358Snetchild bsd_args.opt = 0; 1450162358Snetchild break; 1451162358Snetchild case REBOOT_POWEROFF: 1452162358Snetchild bsd_args.opt = RB_POWEROFF; 1453162358Snetchild break; 1454162358Snetchild default: 1455162358Snetchild return EINVAL; 1456162358Snetchild } 1457162358Snetchild return reboot(td, &bsd_args); 145872538Sjlemon} 145983221Smarcel 146089717Sgallatin 146183221Smarcel/* 146283221Smarcel * The FreeBSD native getpid(2), getgid(2) and getuid(2) also modify 1463166944Snetchild * td->td_retval[1] when COMPAT_43 is defined. This clobbers registers that 1464166944Snetchild * are assumed to be preserved. The following lightweight syscalls fixes 1465166944Snetchild * this. See also linux_getgid16() and linux_getuid16() in linux_uid16.c 146683221Smarcel * 146783221Smarcel * linux_getpid() - MP SAFE 146883221Smarcel * linux_getgid() - MP SAFE 146983221Smarcel * linux_getuid() - MP SAFE 147083221Smarcel */ 147183221Smarcel 147283221Smarcelint 147383366Sjulianlinux_getpid(struct thread *td, struct linux_getpid_args *args) 147483221Smarcel{ 1475165686Snetchild struct linux_emuldata *em; 147683366Sjulian 1477164378Skib#ifdef DEBUG 1478164378Skib if (ldebug(getpid)) 1479164378Skib printf(ARGS(getpid, "")); 1480164378Skib#endif 1481164378Skib 1482165687Snetchild if (linux_use26(td)) { 1483165869Snetchild em = em_find(td->td_proc, EMUL_DONTLOCK); 1484161420Snetchild KASSERT(em != NULL, ("getpid: emuldata not found.\n")); 1485165686Snetchild td->td_retval[0] = em->shared->group_pid; 1486161420Snetchild } else { 1487165686Snetchild td->td_retval[0] = td->td_proc->p_pid; 1488161420Snetchild } 1489161474Snetchild 1490161310Snetchild return (0); 1491161310Snetchild} 1492161310Snetchild 1493161310Snetchildint 1494161310Snetchildlinux_gettid(struct thread *td, struct linux_gettid_args *args) 1495161310Snetchild{ 1496170152Skib 1497161310Snetchild#ifdef DEBUG 1498161310Snetchild if (ldebug(gettid)) 1499161310Snetchild printf(ARGS(gettid, "")); 1500161310Snetchild#endif 1501161310Snetchild 150283366Sjulian td->td_retval[0] = td->td_proc->p_pid; 150383221Smarcel return (0); 150483221Smarcel} 150583221Smarcel 1506161310Snetchild 150783221Smarcelint 1508161310Snetchildlinux_getppid(struct thread *td, struct linux_getppid_args *args) 1509161310Snetchild{ 1510165686Snetchild struct linux_emuldata *em; 1511161310Snetchild struct proc *p, *pp; 1512161310Snetchild 1513164378Skib#ifdef DEBUG 1514164378Skib if (ldebug(getppid)) 1515164378Skib printf(ARGS(getppid, "")); 1516164378Skib#endif 1517164378Skib 1518165687Snetchild if (!linux_use26(td)) { 1519165686Snetchild PROC_LOCK(td->td_proc); 1520165686Snetchild td->td_retval[0] = td->td_proc->p_pptr->p_pid; 1521165686Snetchild PROC_UNLOCK(td->td_proc); 1522161420Snetchild return (0); 1523161420Snetchild } 1524161420Snetchild 1525165869Snetchild em = em_find(td->td_proc, EMUL_DONTLOCK); 1526161310Snetchild 1527161310Snetchild KASSERT(em != NULL, ("getppid: process emuldata not found.\n")); 1528161310Snetchild 1529161310Snetchild /* find the group leader */ 1530161310Snetchild p = pfind(em->shared->group_pid); 1531161310Snetchild 1532161310Snetchild if (p == NULL) { 1533161310Snetchild#ifdef DEBUG 1534161310Snetchild printf(LMSG("parent process not found.\n")); 1535161310Snetchild#endif 1536161310Snetchild return (0); 1537161310Snetchild } 1538161310Snetchild 1539161310Snetchild pp = p->p_pptr; /* switch to parent */ 1540161310Snetchild PROC_LOCK(pp); 1541161310Snetchild PROC_UNLOCK(p); 1542161310Snetchild 1543161310Snetchild /* if its also linux process */ 1544161310Snetchild if (pp->p_sysent == &elf_linux_sysvec) { 1545165867Snetchild em = em_find(pp, EMUL_DONTLOCK); 1546161310Snetchild KASSERT(em != NULL, ("getppid: parent emuldata not found.\n")); 1547161310Snetchild 1548161420Snetchild td->td_retval[0] = em->shared->group_pid; 1549161310Snetchild } else 1550165686Snetchild td->td_retval[0] = pp->p_pid; 1551161310Snetchild 1552161310Snetchild PROC_UNLOCK(pp); 1553161420Snetchild 1554161310Snetchild return (0); 1555161310Snetchild} 1556161310Snetchild 1557161310Snetchildint 155883366Sjulianlinux_getgid(struct thread *td, struct linux_getgid_args *args) 155983221Smarcel{ 156083366Sjulian 1561164378Skib#ifdef DEBUG 1562164378Skib if (ldebug(getgid)) 1563164378Skib printf(ARGS(getgid, "")); 1564164378Skib#endif 1565164378Skib 156694454Sjhb td->td_retval[0] = td->td_ucred->cr_rgid; 156783221Smarcel return (0); 156883221Smarcel} 156983221Smarcel 157083221Smarcelint 157183366Sjulianlinux_getuid(struct thread *td, struct linux_getuid_args *args) 157283221Smarcel{ 157383366Sjulian 1574164378Skib#ifdef DEBUG 1575164378Skib if (ldebug(getuid)) 1576164378Skib printf(ARGS(getuid, "")); 1577164378Skib#endif 1578164378Skib 157994454Sjhb td->td_retval[0] = td->td_ucred->cr_ruid; 158083221Smarcel return (0); 158183221Smarcel} 158283503Smr 158389717Sgallatin 158483503Smrint 158583503Smrlinux_getsid(struct thread *td, struct linux_getsid_args *args) 158683503Smr{ 158783503Smr struct getsid_args bsd; 1588164378Skib 1589164378Skib#ifdef DEBUG 1590164378Skib if (ldebug(getsid)) 1591164378Skib printf(ARGS(getsid, "%i"), args->pid); 1592164378Skib#endif 1593164378Skib 159483503Smr bsd.pid = args->pid; 159583503Smr return getsid(td, &bsd); 159683503Smr} 1597143197Ssobomax 1598143197Ssobomaxint 1599143197Ssobomaxlinux_nosys(struct thread *td, struct nosys_args *ignore) 1600143197Ssobomax{ 1601143197Ssobomax 1602143197Ssobomax return (ENOSYS); 1603143197Ssobomax} 1604147141Ssobomax 1605147141Ssobomaxint 1606147141Ssobomaxlinux_getpriority(struct thread *td, struct linux_getpriority_args *args) 1607147141Ssobomax{ 1608165686Snetchild struct getpriority_args bsd_args; 1609147141Ssobomax int error; 1610147141Ssobomax 1611164378Skib#ifdef DEBUG 1612164378Skib if (ldebug(getpriority)) 1613164378Skib printf(ARGS(getpriority, "%i, %i"), args->which, args->who); 1614164378Skib#endif 1615164378Skib 1616147141Ssobomax bsd_args.which = args->which; 1617147141Ssobomax bsd_args.who = args->who; 1618147141Ssobomax error = getpriority(td, &bsd_args); 1619147141Ssobomax td->td_retval[0] = 20 - td->td_retval[0]; 1620147141Ssobomax return error; 1621147141Ssobomax} 1622156842Snetchild 1623156842Snetchildint 1624156842Snetchildlinux_sethostname(struct thread *td, struct linux_sethostname_args *args) 1625156842Snetchild{ 1626156842Snetchild int name[2]; 1627156842Snetchild 1628164378Skib#ifdef DEBUG 1629164378Skib if (ldebug(sethostname)) 1630164378Skib printf(ARGS(sethostname, "*, %i"), args->len); 1631164378Skib#endif 1632164378Skib 1633156842Snetchild name[0] = CTL_KERN; 1634156842Snetchild name[1] = KERN_HOSTNAME; 1635186564Sed return (userland_sysctl(td, name, 2, 0, 0, 0, args->hostname, 1636186564Sed args->len, 0, 0)); 1637156842Snetchild} 1638156842Snetchild 1639161310Snetchildint 1640184789Sedlinux_setdomainname(struct thread *td, struct linux_setdomainname_args *args) 1641184789Sed{ 1642184789Sed int name[2]; 1643184789Sed 1644184789Sed#ifdef DEBUG 1645184789Sed if (ldebug(setdomainname)) 1646184789Sed printf(ARGS(setdomainname, "*, %i"), args->len); 1647184789Sed#endif 1648184789Sed 1649184789Sed name[0] = CTL_KERN; 1650184789Sed name[1] = KERN_NISDOMAINNAME; 1651186564Sed return (userland_sysctl(td, name, 2, 0, 0, 0, args->name, 1652186564Sed args->len, 0, 0)); 1653184789Sed} 1654184789Sed 1655184789Sedint 1656161310Snetchildlinux_exit_group(struct thread *td, struct linux_exit_group_args *args) 1657161310Snetchild{ 1658215664Snetchild struct linux_emuldata *em; 1659161310Snetchild 1660161310Snetchild#ifdef DEBUG 1661161310Snetchild if (ldebug(exit_group)) 1662161310Snetchild printf(ARGS(exit_group, "%i"), args->error_code); 1663161310Snetchild#endif 1664161310Snetchild 1665215664Snetchild em = em_find(td->td_proc, EMUL_DONTLOCK); 1666215664Snetchild if (em->shared->refs > 1) { 1667215664Snetchild EMUL_SHARED_WLOCK(&emul_shared_lock); 1668215664Snetchild em->shared->flags |= EMUL_SHARED_HASXSTAT; 1669215664Snetchild em->shared->xstat = W_EXITCODE(args->error_code, 0); 1670215664Snetchild EMUL_SHARED_WUNLOCK(&emul_shared_lock); 1671215664Snetchild if (linux_use26(td)) 1672215664Snetchild linux_kill_threads(td, SIGKILL); 1673215664Snetchild } 1674161310Snetchild 1675165686Snetchild /* 1676165686Snetchild * XXX: we should send a signal to the parent if 1677166397Skib * SIGNAL_EXIT_GROUP is set. We ignore that (temporarily?) 1678165686Snetchild * as it doesnt occur often. 1679165686Snetchild */ 1680165686Snetchild exit1(td, W_EXITCODE(args->error_code, 0)); 1681161310Snetchild 1682165686Snetchild return (0); 1683161310Snetchild} 1684163734Snetchild 1685163734Snetchildint 1686163734Snetchildlinux_prctl(struct thread *td, struct linux_prctl_args *args) 1687163734Snetchild{ 1688165686Snetchild int error = 0, max_size; 1689163734Snetchild struct proc *p = td->td_proc; 1690163734Snetchild char comm[LINUX_MAX_COMM_LEN]; 1691163734Snetchild struct linux_emuldata *em; 1692166931Snetchild int pdeath_signal; 1693163734Snetchild 1694163734Snetchild#ifdef DEBUG 1695163734Snetchild if (ldebug(prctl)) 1696165686Snetchild printf(ARGS(prctl, "%d, %d, %d, %d, %d"), args->option, 1697165686Snetchild args->arg2, args->arg3, args->arg4, args->arg5); 1698163734Snetchild#endif 1699165686Snetchild 1700165686Snetchild switch (args->option) { 1701165686Snetchild case LINUX_PR_SET_PDEATHSIG: 1702165686Snetchild if (!LINUX_SIG_VALID(args->arg2)) 1703165686Snetchild return (EINVAL); 1704165867Snetchild em = em_find(p, EMUL_DOLOCK); 1705163740Snetchild KASSERT(em != NULL, ("prctl: emuldata not found.\n")); 1706163740Snetchild em->pdeath_signal = args->arg2; 1707163740Snetchild EMUL_UNLOCK(&emul_lock); 1708165686Snetchild break; 1709163740Snetchild case LINUX_PR_GET_PDEATHSIG: 1710165867Snetchild em = em_find(p, EMUL_DOLOCK); 1711163740Snetchild KASSERT(em != NULL, ("prctl: emuldata not found.\n")); 1712166931Snetchild pdeath_signal = em->pdeath_signal; 1713166931Snetchild EMUL_UNLOCK(&emul_lock); 1714166931Snetchild error = copyout(&pdeath_signal, 1715165686Snetchild (void *)(register_t)args->arg2, 1716166931Snetchild sizeof(pdeath_signal)); 1717163740Snetchild break; 1718163740Snetchild case LINUX_PR_SET_NAME: 1719164826Snetchild /* 1720164826Snetchild * To be on the safe side we need to make sure to not 1721164826Snetchild * overflow the size a linux program expects. We already 1722164826Snetchild * do this here in the copyin, so that we don't need to 1723164826Snetchild * check on copyout. 1724164826Snetchild */ 1725164826Snetchild max_size = MIN(sizeof(comm), sizeof(p->p_comm)); 1726165686Snetchild error = copyinstr((void *)(register_t)args->arg2, comm, 1727164826Snetchild max_size, NULL); 1728164826Snetchild 1729164826Snetchild /* Linux silently truncates the name if it is too long. */ 1730164826Snetchild if (error == ENAMETOOLONG) { 1731164826Snetchild /* 1732164826Snetchild * XXX: copyinstr() isn't documented to populate the 1733164826Snetchild * array completely, so do a copyin() to be on the 1734164826Snetchild * safe side. This should be changed in case 1735164826Snetchild * copyinstr() is changed to guarantee this. 1736164826Snetchild */ 1737164826Snetchild error = copyin((void *)(register_t)args->arg2, comm, 1738164826Snetchild max_size - 1); 1739164826Snetchild comm[max_size - 1] = '\0'; 1740164826Snetchild } 1741163740Snetchild if (error) 1742165686Snetchild return (error); 1743164826Snetchild 1744163740Snetchild PROC_LOCK(p); 1745164826Snetchild strlcpy(p->p_comm, comm, sizeof(p->p_comm)); 1746163740Snetchild PROC_UNLOCK(p); 1747163740Snetchild break; 1748163740Snetchild case LINUX_PR_GET_NAME: 1749164826Snetchild PROC_LOCK(p); 1750164826Snetchild strlcpy(comm, p->p_comm, sizeof(comm)); 1751164826Snetchild PROC_UNLOCK(p); 1752165686Snetchild error = copyout(comm, (void *)(register_t)args->arg2, 1753165686Snetchild strlen(comm) + 1); 1754163740Snetchild break; 1755163740Snetchild default: 1756163740Snetchild error = EINVAL; 1757163740Snetchild break; 1758163734Snetchild } 1759163734Snetchild 1760163734Snetchild return (error); 1761163734Snetchild} 1762171998Skib 1763171998Skib/* 1764177257Srdivacky * Get affinity of a process. 1765171998Skib */ 1766171998Skibint 1767171998Skiblinux_sched_getaffinity(struct thread *td, 1768171998Skib struct linux_sched_getaffinity_args *args) 1769171998Skib{ 1770171998Skib int error; 1771177257Srdivacky struct cpuset_getaffinity_args cga; 1772171998Skib 1773177257Srdivacky#ifdef DEBUG 1774177257Srdivacky if (ldebug(sched_getaffinity)) 1775177257Srdivacky printf(ARGS(sched_getaffinity, "%d, %d, *"), args->pid, 1776177257Srdivacky args->len); 1777177257Srdivacky#endif 1778183612Skib if (args->len < sizeof(cpuset_t)) 1779183612Skib return (EINVAL); 1780171998Skib 1781177257Srdivacky cga.level = CPU_LEVEL_WHICH; 1782177257Srdivacky cga.which = CPU_WHICH_PID; 1783177257Srdivacky cga.id = args->pid; 1784183612Skib cga.cpusetsize = sizeof(cpuset_t); 1785177604Sru cga.mask = (cpuset_t *) args->user_mask_ptr; 1786183612Skib 1787177257Srdivacky if ((error = cpuset_getaffinity(td, &cga)) == 0) 1788183612Skib td->td_retval[0] = sizeof(cpuset_t); 1789171998Skib 1790177257Srdivacky return (error); 1791171998Skib} 1792177257Srdivacky 1793177257Srdivacky/* 1794177257Srdivacky * Set affinity of a process. 1795177257Srdivacky */ 1796177257Srdivackyint 1797177257Srdivackylinux_sched_setaffinity(struct thread *td, 1798177257Srdivacky struct linux_sched_setaffinity_args *args) 1799177257Srdivacky{ 1800177257Srdivacky struct cpuset_setaffinity_args csa; 1801177257Srdivacky 1802177257Srdivacky#ifdef DEBUG 1803177257Srdivacky if (ldebug(sched_setaffinity)) 1804177257Srdivacky printf(ARGS(sched_setaffinity, "%d, %d, *"), args->pid, 1805177257Srdivacky args->len); 1806177257Srdivacky#endif 1807183612Skib if (args->len < sizeof(cpuset_t)) 1808183612Skib return (EINVAL); 1809183612Skib 1810177257Srdivacky csa.level = CPU_LEVEL_WHICH; 1811177257Srdivacky csa.which = CPU_WHICH_PID; 1812177257Srdivacky csa.id = args->pid; 1813183612Skib csa.cpusetsize = sizeof(cpuset_t); 1814177604Sru csa.mask = (cpuset_t *) args->user_mask_ptr; 1815177257Srdivacky 1816177257Srdivacky return (cpuset_setaffinity(td, &csa)); 1817177257Srdivacky} 1818