19313Ssos/*- 2133749Stjr * Copyright (c) 2002 Doug Rabson 3230132Suqs * 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: releng/10.2/sys/compat/linux/linux_misc.c 301051 2016-05-31 16:55:45Z glebius $"); 32116173Sobrien 33156874Sru#include "opt_compat.h" 34235063Snetchild#include "opt_kdtrace.h" 3549842Smarcel 369313Ssos#include <sys/param.h> 37102954Sbde#include <sys/blist.h> 3876166Smarkm#include <sys/fcntl.h> 39158415Snetchild#if defined(__i386__) 4076166Smarkm#include <sys/imgact_aout.h> 41133816Stjr#endif 4291385Srobert#include <sys/jail.h> 4312458Sbde#include <sys/kernel.h> 44114216Skan#include <sys/limits.h> 4576166Smarkm#include <sys/lock.h> 46102954Sbde#include <sys/malloc.h> 479313Ssos#include <sys/mman.h> 489313Ssos#include <sys/mount.h> 4976166Smarkm#include <sys/mutex.h> 509313Ssos#include <sys/namei.h> 51164033Srwatson#include <sys/priv.h> 5276166Smarkm#include <sys/proc.h> 5372538Sjlemon#include <sys/reboot.h> 54220373Strasz#include <sys/racct.h> 559313Ssos#include <sys/resourcevar.h> 56164184Strhodes#include <sys/sched.h> 57235063Snetchild#include <sys/sdt.h> 5876166Smarkm#include <sys/signalvar.h> 599313Ssos#include <sys/stat.h> 60102814Siedowse#include <sys/syscallsubr.h> 6112458Sbde#include <sys/sysctl.h> 6276166Smarkm#include <sys/sysproto.h> 63102954Sbde#include <sys/systm.h> 6476166Smarkm#include <sys/time.h> 6580180Spirzyk#include <sys/vmmeter.h> 669313Ssos#include <sys/vnode.h> 679313Ssos#include <sys/wait.h> 68177257Srdivacky#include <sys/cpuset.h> 699313Ssos 70163606Srwatson#include <security/mac/mac_framework.h> 71163606Srwatson 7212652Sbde#include <vm/vm.h> 7312689Speter#include <vm/pmap.h> 7412458Sbde#include <vm/vm_kern.h> 7512689Speter#include <vm/vm_map.h> 7612842Sbde#include <vm/vm_extern.h> 7780180Spirzyk#include <vm/vm_object.h> 7880180Spirzyk#include <vm/swap_pager.h> 7912458Sbde 80140214Sobrien#ifdef COMPAT_LINUX32 81140214Sobrien#include <machine/../linux32/linux.h> 82140214Sobrien#include <machine/../linux32/linux32_proto.h> 83140214Sobrien#else 8464909Smarcel#include <machine/../linux/linux.h> 8568583Smarcel#include <machine/../linux/linux_proto.h> 86133816Stjr#endif 87102954Sbde 88235063Snetchild#include <compat/linux/linux_dtrace.h> 89177997Skib#include <compat/linux/linux_file.h> 9064909Smarcel#include <compat/linux/linux_mib.h> 91163734Snetchild#include <compat/linux/linux_signal.h> 9264909Smarcel#include <compat/linux/linux_util.h> 93178976Srdivacky#include <compat/linux/linux_sysproto.h> 94178976Srdivacky#include <compat/linux/linux_emul.h> 95178976Srdivacky#include <compat/linux/linux_misc.h> 9664909Smarcel 97235063Snetchild/* DTrace init */ 98235063SnetchildLIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); 99235063Snetchild 100235063Snetchild/* Linuxulator-global DTrace probes */ 101235063SnetchildLIN_SDT_PROBE_DECLARE(locks, emul_lock, locked); 102235063SnetchildLIN_SDT_PROBE_DECLARE(locks, emul_lock, unlock); 103235063SnetchildLIN_SDT_PROBE_DECLARE(locks, emul_shared_rlock, locked); 104235063SnetchildLIN_SDT_PROBE_DECLARE(locks, emul_shared_rlock, unlock); 105235063SnetchildLIN_SDT_PROBE_DECLARE(locks, emul_shared_wlock, locked); 106235063SnetchildLIN_SDT_PROBE_DECLARE(locks, emul_shared_wlock, unlock); 107235063Snetchild 108191966Sdchaginint stclohz; /* Statistics clock frequency */ 109191966Sdchagin 11083221Smarcelstatic unsigned int linux_to_bsd_resource[LINUX_RLIM_NLIMITS] = { 11183221Smarcel RLIMIT_CPU, RLIMIT_FSIZE, RLIMIT_DATA, RLIMIT_STACK, 11283221Smarcel RLIMIT_CORE, RLIMIT_RSS, RLIMIT_NPROC, RLIMIT_NOFILE, 113165871Snetchild RLIMIT_MEMLOCK, RLIMIT_AS 11449626Smarcel}; 11549626Smarcel 11683221Smarcelstruct l_sysinfo { 11783221Smarcel l_long uptime; /* Seconds since boot */ 11883221Smarcel l_ulong loads[3]; /* 1, 5, and 15 minute load averages */ 119122802Ssobomax#define LINUX_SYSINFO_LOADS_SCALE 65536 12083221Smarcel l_ulong totalram; /* Total usable main memory size */ 12183221Smarcel l_ulong freeram; /* Available memory size */ 12283221Smarcel l_ulong sharedram; /* Amount of shared memory */ 12383221Smarcel l_ulong bufferram; /* Memory used by buffers */ 12483221Smarcel l_ulong totalswap; /* Total swap space size */ 12583221Smarcel l_ulong freeswap; /* swap space still available */ 12683221Smarcel l_ushort procs; /* Number of current processes */ 127164380Skib l_ushort pads; 128122802Ssobomax l_ulong totalbig; 129122802Ssobomax l_ulong freebig; 130122802Ssobomax l_uint mem_unit; 131164380Skib char _f[20-2*sizeof(l_long)-sizeof(l_int)]; /* padding */ 13280180Spirzyk}; 1339313Ssosint 13483366Sjulianlinux_sysinfo(struct thread *td, struct linux_sysinfo_args *args) 13580180Spirzyk{ 13683221Smarcel struct l_sysinfo sysinfo; 13783221Smarcel vm_object_t object; 138117723Sphk int i, j; 13983221Smarcel struct timespec ts; 14080180Spirzyk 141301051Sglebius bzero(&sysinfo, sizeof(sysinfo)); 14283221Smarcel getnanouptime(&ts); 143147816Sjhb if (ts.tv_nsec != 0) 144147816Sjhb ts.tv_sec++; 145147816Sjhb sysinfo.uptime = ts.tv_sec; 14680180Spirzyk 14783221Smarcel /* Use the information from the mib to get our load averages */ 14883221Smarcel for (i = 0; i < 3; i++) 149122802Ssobomax sysinfo.loads[i] = averunnable.ldavg[i] * 150122802Ssobomax LINUX_SYSINFO_LOADS_SCALE / averunnable.fscale; 15180180Spirzyk 15283221Smarcel sysinfo.totalram = physmem * PAGE_SIZE; 153170170Sattilio sysinfo.freeram = sysinfo.totalram - cnt.v_wire_count * PAGE_SIZE; 15480180Spirzyk 15583221Smarcel sysinfo.sharedram = 0; 156124082Salc mtx_lock(&vm_object_list_mtx); 157124082Salc TAILQ_FOREACH(object, &vm_object_list, object_list) 15883221Smarcel if (object->shadow_count > 1) 15983221Smarcel sysinfo.sharedram += object->resident_page_count; 160124082Salc mtx_unlock(&vm_object_list_mtx); 16180180Spirzyk 16283221Smarcel sysinfo.sharedram *= PAGE_SIZE; 16383221Smarcel sysinfo.bufferram = 0; 16480180Spirzyk 165117723Sphk swap_pager_status(&i, &j); 166165686Snetchild sysinfo.totalswap = i * PAGE_SIZE; 167117723Sphk sysinfo.freeswap = (i - j) * PAGE_SIZE; 16880180Spirzyk 169122802Ssobomax sysinfo.procs = nprocs; 17080180Spirzyk 171122802Ssobomax /* The following are only present in newer Linux kernels. */ 172122802Ssobomax sysinfo.totalbig = 0; 173122802Ssobomax sysinfo.freebig = 0; 174122802Ssobomax sysinfo.mem_unit = 1; 175122802Ssobomax 176218031Sdchagin return (copyout(&sysinfo, args->info, sizeof(sysinfo))); 17780180Spirzyk} 17880180Spirzyk 17980180Spirzykint 18083366Sjulianlinux_alarm(struct thread *td, struct linux_alarm_args *args) 1819313Ssos{ 18283221Smarcel struct itimerval it, old_it; 183180766Srdivacky u_int secs; 184141467Sjhb int error; 1859313Ssos 1869313Ssos#ifdef DEBUG 18772543Sjlemon if (ldebug(alarm)) 18872543Sjlemon printf(ARGS(alarm, "%u"), args->secs); 1899313Ssos#endif 190180766Srdivacky 191180766Srdivacky secs = args->secs; 19283221Smarcel 193180766Srdivacky if (secs > INT_MAX) 194180766Srdivacky secs = INT_MAX; 19583221Smarcel 196180766Srdivacky it.it_value.tv_sec = (long) secs; 19783221Smarcel it.it_value.tv_usec = 0; 19883221Smarcel it.it_interval.tv_sec = 0; 19983221Smarcel it.it_interval.tv_usec = 0; 200141467Sjhb error = kern_setitimer(td, ITIMER_REAL, &it, &old_it); 201141467Sjhb if (error) 202141467Sjhb return (error); 203165686Snetchild if (timevalisset(&old_it.it_value)) { 20483221Smarcel if (old_it.it_value.tv_usec != 0) 20583221Smarcel old_it.it_value.tv_sec++; 20683366Sjulian td->td_retval[0] = old_it.it_value.tv_sec; 20783221Smarcel } 208141467Sjhb return (0); 2099313Ssos} 2109313Ssos 2119313Ssosint 21283366Sjulianlinux_brk(struct thread *td, struct linux_brk_args *args) 2139313Ssos{ 21483366Sjulian struct vmspace *vm = td->td_proc->p_vmspace; 21583221Smarcel vm_offset_t new, old; 21683221Smarcel struct obreak_args /* { 21783221Smarcel char * nsize; 21883221Smarcel } */ tmp; 2199313Ssos 2209313Ssos#ifdef DEBUG 22172543Sjlemon if (ldebug(brk)) 222133845Sobrien printf(ARGS(brk, "%p"), (void *)(uintptr_t)args->dsend); 2239313Ssos#endif 22483221Smarcel old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize); 22583221Smarcel new = (vm_offset_t)args->dsend; 226165686Snetchild tmp.nsize = (char *)new; 227225617Skmacy if (((caddr_t)new > vm->vm_daddr) && !sys_obreak(td, &tmp)) 22883366Sjulian td->td_retval[0] = (long)new; 22983221Smarcel else 23083366Sjulian td->td_retval[0] = (long)old; 2319313Ssos 232218031Sdchagin return (0); 2339313Ssos} 2349313Ssos 235158415Snetchild#if defined(__i386__) 236158415Snetchild/* XXX: what about amd64/linux32? */ 237133816Stjr 2389313Ssosint 23983366Sjulianlinux_uselib(struct thread *td, struct linux_uselib_args *args) 2409313Ssos{ 24183221Smarcel struct nameidata ni; 24283221Smarcel struct vnode *vp; 24383221Smarcel struct exec *a_out; 24483221Smarcel struct vattr attr; 24583221Smarcel vm_offset_t vmaddr; 24683221Smarcel unsigned long file_offset; 24783221Smarcel unsigned long bss_size; 248102814Siedowse char *library; 249231885Skib ssize_t aresid; 250242476Skib int error, locked, writecount; 2519313Ssos 252102814Siedowse LCONVPATHEXIST(td, args->library, &library); 25314331Speter 2549313Ssos#ifdef DEBUG 25572543Sjlemon if (ldebug(uselib)) 256102814Siedowse printf(ARGS(uselib, "%s"), library); 2579313Ssos#endif 2589313Ssos 25983221Smarcel a_out = NULL; 26083221Smarcel locked = 0; 26183221Smarcel vp = NULL; 26214114Speter 263241896Skib NDINIT(&ni, LOOKUP, ISOPEN | FOLLOW | LOCKLEAF | AUDITVNODE1, 264160555Sjhb UIO_SYSSPACE, library, td); 26583221Smarcel error = namei(&ni); 266102814Siedowse LFREEPATH(library); 26783221Smarcel if (error) 26883221Smarcel goto cleanup; 2699313Ssos 27083221Smarcel vp = ni.ni_vp; 27183221Smarcel NDFREE(&ni, NDF_ONLY_PNBUF); 2729313Ssos 27383221Smarcel /* 27483221Smarcel * From here on down, we have a locked vnode that must be unlocked. 275160555Sjhb * XXX: The code below largely duplicates exec_check_permissions(). 27683221Smarcel */ 277160555Sjhb locked = 1; 27814114Speter 27983221Smarcel /* Writable? */ 280242476Skib error = VOP_GET_WRITECOUNT(vp, &writecount); 281242476Skib if (error != 0) 282242476Skib goto cleanup; 283242476Skib if (writecount != 0) { 28483221Smarcel error = ETXTBSY; 28583221Smarcel goto cleanup; 28683221Smarcel } 2879313Ssos 28883221Smarcel /* Executable? */ 289182371Sattilio error = VOP_GETATTR(vp, &attr, td->td_ucred); 29083221Smarcel if (error) 29183221Smarcel goto cleanup; 2929313Ssos 29383221Smarcel if ((vp->v_mount->mnt_flag & MNT_NOEXEC) || 29483221Smarcel ((attr.va_mode & 0111) == 0) || (attr.va_type != VREG)) { 295160555Sjhb /* EACCESS is what exec(2) returns. */ 29683221Smarcel error = ENOEXEC; 29783221Smarcel goto cleanup; 29883221Smarcel } 2999313Ssos 30083221Smarcel /* Sensible size? */ 30183221Smarcel if (attr.va_size == 0) { 30283221Smarcel error = ENOEXEC; 30383221Smarcel goto cleanup; 30483221Smarcel } 3059313Ssos 30683221Smarcel /* Can we access it? */ 30791406Sjhb error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td); 30883221Smarcel if (error) 30983221Smarcel goto cleanup; 3109313Ssos 31198209Srwatson /* 31298209Srwatson * XXX: This should use vn_open() so that it is properly authorized, 31398209Srwatson * and to reduce code redundancy all over the place here. 314160555Sjhb * XXX: Not really, it duplicates far more of exec_check_permissions() 315160555Sjhb * than vn_open(). 31698209Srwatson */ 317101189Srwatson#ifdef MAC 318183275Strasz error = mac_vnode_check_open(td->td_ucred, vp, VREAD); 319101189Srwatson if (error) 320101189Srwatson goto cleanup; 321101189Srwatson#endif 322170152Skib error = VOP_OPEN(vp, FREAD, td->td_ucred, td, NULL); 32383221Smarcel if (error) 32483221Smarcel goto cleanup; 3259313Ssos 326231885Skib /* Pull in executable header into exec_map */ 327231885Skib error = vm_mmap(exec_map, (vm_offset_t *)&a_out, PAGE_SIZE, 328144501Sjhb VM_PROT_READ, VM_PROT_READ, 0, OBJT_VNODE, vp, 0); 32983221Smarcel if (error) 33083221Smarcel goto cleanup; 3319313Ssos 33283221Smarcel /* Is it a Linux binary ? */ 33383221Smarcel if (((a_out->a_magic >> 16) & 0xff) != 0x64) { 33483221Smarcel error = ENOEXEC; 33583221Smarcel goto cleanup; 33683221Smarcel } 3379313Ssos 33883221Smarcel /* 33983221Smarcel * While we are here, we should REALLY do some more checks 34083221Smarcel */ 34114114Speter 34283221Smarcel /* Set file/virtual offset based on a.out variant. */ 34383221Smarcel switch ((int)(a_out->a_magic & 0xffff)) { 344165686Snetchild case 0413: /* ZMAGIC */ 34583221Smarcel file_offset = 1024; 34683221Smarcel break; 347165686Snetchild case 0314: /* QMAGIC */ 34883221Smarcel file_offset = 0; 34983221Smarcel break; 35083221Smarcel default: 35183221Smarcel error = ENOEXEC; 35283221Smarcel goto cleanup; 35383221Smarcel } 3549313Ssos 35583221Smarcel bss_size = round_page(a_out->a_bss); 35614114Speter 35783221Smarcel /* Check various fields in header for validity/bounds. */ 35883221Smarcel if (a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) { 35983221Smarcel error = ENOEXEC; 36083221Smarcel goto cleanup; 36183221Smarcel } 36214114Speter 36383221Smarcel /* text + data can't exceed file size */ 36483221Smarcel if (a_out->a_data + a_out->a_text > attr.va_size) { 36583221Smarcel error = EFAULT; 36683221Smarcel goto cleanup; 36783221Smarcel } 36814114Speter 36983221Smarcel /* 37083221Smarcel * text/data/bss must not exceed limits 37183221Smarcel * XXX - this is not complete. it should check current usage PLUS 37283221Smarcel * the resources needed by this library. 37383221Smarcel */ 374125454Sjhb PROC_LOCK(td->td_proc); 37584783Sps if (a_out->a_text > maxtsiz || 376220373Strasz a_out->a_data + bss_size > lim_cur(td->td_proc, RLIMIT_DATA) || 377220373Strasz racct_set(td->td_proc, RACCT_DATA, a_out->a_data + 378220373Strasz bss_size) != 0) { 379125454Sjhb PROC_UNLOCK(td->td_proc); 38083221Smarcel error = ENOMEM; 38183221Smarcel goto cleanup; 38283221Smarcel } 383125454Sjhb PROC_UNLOCK(td->td_proc); 38414114Speter 385160555Sjhb /* 386160555Sjhb * Prevent more writers. 387160555Sjhb * XXX: Note that if any of the VM operations fail below we don't 388160555Sjhb * clear this flag. 389160555Sjhb */ 390241025Skib VOP_SET_TEXT(vp); 39114114Speter 39283221Smarcel /* 393160555Sjhb * Lock no longer needed 394160555Sjhb */ 395160555Sjhb locked = 0; 396175294Sattilio VOP_UNLOCK(vp, 0); 397160555Sjhb 398160555Sjhb /* 39983221Smarcel * Check if file_offset page aligned. Currently we cannot handle 40083221Smarcel * misalinged file offsets, and so we read in the entire image 40183221Smarcel * (what a waste). 40283221Smarcel */ 40383221Smarcel if (file_offset & PAGE_MASK) { 4049313Ssos#ifdef DEBUG 40583221Smarcel printf("uselib: Non page aligned binary %lu\n", file_offset); 4069313Ssos#endif 40783221Smarcel /* Map text+data read/write/execute */ 40814114Speter 40983221Smarcel /* a_entry is the load address and is page aligned */ 41083221Smarcel vmaddr = trunc_page(a_out->a_entry); 41114114Speter 41283221Smarcel /* get anon user mapping, read+write+execute */ 41383366Sjulian error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0, 414255426Sjhb &vmaddr, a_out->a_text + a_out->a_data, 0, VMFS_NO_SPACE, 415255426Sjhb VM_PROT_ALL, VM_PROT_ALL, 0); 41683221Smarcel if (error) 41783221Smarcel goto cleanup; 4189313Ssos 419231885Skib error = vn_rdwr(UIO_READ, vp, (void *)vmaddr, file_offset, 420231885Skib a_out->a_text + a_out->a_data, UIO_USERSPACE, 0, 421231885Skib td->td_ucred, NOCRED, &aresid, td); 422231885Skib if (error != 0) 42383221Smarcel goto cleanup; 424231885Skib if (aresid != 0) { 425231885Skib error = ENOEXEC; 42683221Smarcel goto cleanup; 427231885Skib } 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, 444144501Sjhb MAP_PRIVATE | MAP_FIXED, OBJT_VNODE, vp, file_offset); 44583221Smarcel if (error) 44683221Smarcel goto cleanup; 44783221Smarcel } 4489313Ssos#ifdef DEBUG 449165686Snetchild printf("mem=%08lx = %08lx %08lx\n", (long)vmaddr, ((long *)vmaddr)[0], 450165686Snetchild ((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, 459255426Sjhb &vmaddr, bss_size, 0, VMFS_NO_SPACE, VM_PROT_ALL, 460255426Sjhb VM_PROT_ALL, 0); 46183221Smarcel if (error) 46283221Smarcel goto cleanup; 46383221Smarcel } 46414114Speter 46514114Spetercleanup: 46683221Smarcel /* Unlock vnode if needed */ 467241896Skib if (locked) 468175294Sattilio VOP_UNLOCK(vp, 0); 46914114Speter 470231885Skib /* Release the temporary mapping. */ 47183221Smarcel if (a_out) 472254025Sjeff kmap_free_wakeup(exec_map, (vm_offset_t)a_out, PAGE_SIZE); 47314114Speter 474218031Sdchagin return (error); 4759313Ssos} 4769313Ssos 477158415Snetchild#endif /* __i386__ */ 478133816Stjr 4799313Ssosint 48083366Sjulianlinux_select(struct thread *td, struct linux_select_args *args) 48114331Speter{ 482133747Stjr l_timeval ltv; 48383221Smarcel struct timeval tv0, tv1, utv, *tvp; 48483221Smarcel int error; 48514331Speter 4869313Ssos#ifdef DEBUG 48783221Smarcel if (ldebug(select)) 48883221Smarcel printf(ARGS(select, "%d, %p, %p, %p, %p"), args->nfds, 48983221Smarcel (void *)args->readfds, (void *)args->writefds, 49083221Smarcel (void *)args->exceptfds, (void *)args->timeout); 4919313Ssos#endif 49214331Speter 49383221Smarcel /* 49483221Smarcel * Store current time for computation of the amount of 49583221Smarcel * time left. 49683221Smarcel */ 49783221Smarcel if (args->timeout) { 498133747Stjr if ((error = copyin(args->timeout, <v, sizeof(ltv)))) 49983221Smarcel goto select_out; 500133747Stjr utv.tv_sec = ltv.tv_sec; 501133747Stjr utv.tv_usec = ltv.tv_usec; 50214331Speter#ifdef DEBUG 50383221Smarcel if (ldebug(select)) 504153775Strhodes printf(LMSG("incoming timeout (%jd/%ld)"), 505153775Strhodes (intmax_t)utv.tv_sec, utv.tv_usec); 50614331Speter#endif 50783221Smarcel 50883221Smarcel if (itimerfix(&utv)) { 50983221Smarcel /* 51083221Smarcel * The timeval was invalid. Convert it to something 51183221Smarcel * valid that will act as it does under Linux. 51283221Smarcel */ 51383221Smarcel utv.tv_sec += utv.tv_usec / 1000000; 51483221Smarcel utv.tv_usec %= 1000000; 51583221Smarcel if (utv.tv_usec < 0) { 51683221Smarcel utv.tv_sec -= 1; 51783221Smarcel utv.tv_usec += 1000000; 51883221Smarcel } 51983221Smarcel if (utv.tv_sec < 0) 52083221Smarcel timevalclear(&utv); 52183221Smarcel } 52283221Smarcel microtime(&tv0); 523102814Siedowse tvp = &utv; 524102814Siedowse } else 525102814Siedowse tvp = NULL; 52614331Speter 527102814Siedowse error = kern_select(td, args->nfds, args->readfds, args->writefds, 528197049Skib args->exceptfds, tvp, sizeof(l_int) * 8); 529102814Siedowse 53014331Speter#ifdef DEBUG 53183221Smarcel if (ldebug(select)) 53272543Sjlemon printf(LMSG("real select returns %d"), error); 53314331Speter#endif 534182935Srdivacky if (error) 53583221Smarcel goto select_out; 53614331Speter 53783221Smarcel if (args->timeout) { 53883366Sjulian if (td->td_retval[0]) { 53983221Smarcel /* 54083221Smarcel * Compute how much time was left of the timeout, 54183221Smarcel * by subtracting the current time and the time 54283221Smarcel * before we started the call, and subtracting 54383221Smarcel * that result from the user-supplied value. 54483221Smarcel */ 54583221Smarcel microtime(&tv1); 54683221Smarcel timevalsub(&tv1, &tv0); 54783221Smarcel timevalsub(&utv, &tv1); 54883221Smarcel if (utv.tv_sec < 0) 54983221Smarcel timevalclear(&utv); 55083221Smarcel } else 55183221Smarcel timevalclear(&utv); 55214331Speter#ifdef DEBUG 55383221Smarcel if (ldebug(select)) 554153775Strhodes printf(LMSG("outgoing timeout (%jd/%ld)"), 555153775Strhodes (intmax_t)utv.tv_sec, utv.tv_usec); 55614331Speter#endif 557133747Stjr ltv.tv_sec = utv.tv_sec; 558133747Stjr ltv.tv_usec = utv.tv_usec; 559133747Stjr if ((error = copyout(<v, args->timeout, sizeof(ltv)))) 56083221Smarcel goto select_out; 56183221Smarcel } 56214331Speter 56314331Speterselect_out: 56414331Speter#ifdef DEBUG 56583221Smarcel if (ldebug(select)) 56683221Smarcel printf(LMSG("select_out -> %d"), error); 56714331Speter#endif 568218031Sdchagin 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"), 583133845Sobrien (void *)(uintptr_t)args->addr, 584111798Sdes (unsigned long)args->old_len, 58572543Sjlemon (unsigned long)args->new_len, 58672543Sjlemon (unsigned long)args->flags); 58737548Sjkh#endif 588176460Skib 589176460Skib if (args->flags & ~(LINUX_MREMAP_FIXED | LINUX_MREMAP_MAYMOVE)) { 590176460Skib td->td_retval[0] = 0; 591176460Skib return (EINVAL); 592176460Skib } 593176460Skib 594176460Skib /* 595176460Skib * Check for the page alignment. 596176460Skib * Linux defines PAGE_MASK to be FreeBSD ~PAGE_MASK. 597176460Skib */ 598176460Skib if (args->addr & PAGE_MASK) { 599176460Skib td->td_retval[0] = 0; 600176460Skib return (EINVAL); 601176460Skib } 602176460Skib 60337548Sjkh args->new_len = round_page(args->new_len); 60437548Sjkh args->old_len = round_page(args->old_len); 60537548Sjkh 60637548Sjkh if (args->new_len > args->old_len) { 60783366Sjulian td->td_retval[0] = 0; 608218031Sdchagin return (ENOMEM); 60937548Sjkh } 61037548Sjkh 61137548Sjkh if (args->new_len < args->old_len) { 612133816Stjr bsd_args.addr = 613133816Stjr (caddr_t)((uintptr_t)args->addr + args->new_len); 61437548Sjkh bsd_args.len = args->old_len - args->new_len; 615225617Skmacy error = sys_munmap(td, &bsd_args); 61637548Sjkh } 61737548Sjkh 618102963Sbde td->td_retval[0] = error ? 0 : (uintptr_t)args->addr; 619218031Sdchagin return (error); 62037548Sjkh} 62137548Sjkh 622103652Smdodd#define LINUX_MS_ASYNC 0x0001 623103652Smdodd#define LINUX_MS_INVALIDATE 0x0002 624103652Smdodd#define LINUX_MS_SYNC 0x0004 625103652Smdodd 62614331Speterint 62783366Sjulianlinux_msync(struct thread *td, struct linux_msync_args *args) 62814331Speter{ 62914331Speter struct msync_args bsd_args; 6309313Ssos 631133816Stjr bsd_args.addr = (caddr_t)(uintptr_t)args->addr; 632133816Stjr bsd_args.len = (uintptr_t)args->len; 633103652Smdodd bsd_args.flags = args->fl & ~LINUX_MS_SYNC; 63414331Speter 635225617Skmacy return (sys_msync(td, &bsd_args)); 63614331Speter} 63714331Speter 6389313Ssosint 63983366Sjulianlinux_time(struct thread *td, struct linux_time_args *args) 6409313Ssos{ 64183221Smarcel struct timeval tv; 64283221Smarcel l_time_t tm; 64383221Smarcel int error; 6449313Ssos 6459313Ssos#ifdef DEBUG 64672543Sjlemon if (ldebug(time)) 64772543Sjlemon printf(ARGS(time, "*")); 6489313Ssos#endif 64983221Smarcel 65083221Smarcel microtime(&tv); 65183221Smarcel tm = tv.tv_sec; 652111797Sdes if (args->tm && (error = copyout(&tm, args->tm, sizeof(tm)))) 653218031Sdchagin return (error); 65483366Sjulian td->td_retval[0] = tm; 655218031Sdchagin return (0); 6569313Ssos} 6579313Ssos 65883221Smarcelstruct l_times_argv { 659191880Sdchagin l_clock_t tms_utime; 660191880Sdchagin l_clock_t tms_stime; 661191880Sdchagin l_clock_t tms_cutime; 662191880Sdchagin l_clock_t tms_cstime; 6639313Ssos}; 6649313Ssos 66574701Sgallatin 666191973Sdchagin/* 667191973Sdchagin * Glibc versions prior to 2.2.1 always use hard-coded CLK_TCK value. 668191973Sdchagin * Since 2.2.1 Glibc uses value exported from kernel via AT_CLKTCK 669191973Sdchagin * auxiliary vector entry. 670191973Sdchagin */ 671191973Sdchagin#define CLK_TCK 100 672191973Sdchagin 673191973Sdchagin#define CONVOTCK(r) (r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK)) 674191973Sdchagin#define CONVNTCK(r) (r.tv_sec * stclohz + r.tv_usec / (1000000 / stclohz)) 675191973Sdchagin 676191973Sdchagin#define CONVTCK(r) (linux_kernver(td) >= LINUX_KERNVER_2004000 ? \ 677191973Sdchagin CONVNTCK(r) : CONVOTCK(r)) 678191973Sdchagin 6799313Ssosint 68083366Sjulianlinux_times(struct thread *td, struct linux_times_args *args) 6819313Ssos{ 682136152Sjhb struct timeval tv, utime, stime, cutime, cstime; 68383221Smarcel struct l_times_argv tms; 684136152Sjhb struct proc *p; 68583221Smarcel int error; 6869313Ssos 6879313Ssos#ifdef DEBUG 68872543Sjlemon if (ldebug(times)) 68972543Sjlemon printf(ARGS(times, "*")); 6909313Ssos#endif 69114381Speter 692159896Snetchild if (args->buf != NULL) { 693159896Snetchild p = td->td_proc; 694159896Snetchild PROC_LOCK(p); 695170472Sattilio PROC_SLOCK(p); 696159896Snetchild calcru(p, &utime, &stime); 697170472Sattilio PROC_SUNLOCK(p); 698159896Snetchild calccru(p, &cutime, &cstime); 699159896Snetchild PROC_UNLOCK(p); 70014381Speter 701159896Snetchild tms.tms_utime = CONVTCK(utime); 702159896Snetchild tms.tms_stime = CONVTCK(stime); 70314381Speter 704159896Snetchild tms.tms_cutime = CONVTCK(cutime); 705159896Snetchild tms.tms_cstime = CONVTCK(cstime); 70614381Speter 707159896Snetchild if ((error = copyout(&tms, args->buf, sizeof(tms)))) 708218031Sdchagin return (error); 709159896Snetchild } 71083221Smarcel 71183221Smarcel microuptime(&tv); 71283366Sjulian td->td_retval[0] = (int)CONVTCK(tv); 713218031Sdchagin return (0); 7149313Ssos} 7159313Ssos 7169313Ssosint 71783366Sjulianlinux_newuname(struct thread *td, struct linux_newuname_args *args) 7189313Ssos{ 71983221Smarcel struct l_new_utsname utsname; 72087275Srwatson char osname[LINUX_MAX_UTSNAME]; 72187275Srwatson char osrelease[LINUX_MAX_UTSNAME]; 722118149Sdes char *p; 7239313Ssos 7249313Ssos#ifdef DEBUG 72572543Sjlemon if (ldebug(newuname)) 72672543Sjlemon printf(ARGS(newuname, "*")); 7279313Ssos#endif 72850345Smarcel 729112206Sjhb linux_get_osname(td, osname); 730112206Sjhb linux_get_osrelease(td, osrelease); 73150465Smarcel 73283221Smarcel bzero(&utsname, sizeof(utsname)); 733105359Srobert strlcpy(utsname.sysname, osname, LINUX_MAX_UTSNAME); 734105359Srobert getcredhostname(td->td_ucred, utsname.nodename, LINUX_MAX_UTSNAME); 735194090Sjamie getcreddomainname(td->td_ucred, utsname.domainname, LINUX_MAX_UTSNAME); 736105359Srobert strlcpy(utsname.release, osrelease, LINUX_MAX_UTSNAME); 737105359Srobert strlcpy(utsname.version, version, LINUX_MAX_UTSNAME); 738118149Sdes for (p = utsname.version; *p != '\0'; ++p) 739118149Sdes if (*p == '\n') { 740118149Sdes *p = '\0'; 741118149Sdes break; 742118149Sdes } 743189362Sdchagin strlcpy(utsname.machine, linux_platform, LINUX_MAX_UTSNAME); 744165686Snetchild 745111797Sdes return (copyout(&utsname, args->buf, sizeof(utsname))); 7469313Ssos} 7479313Ssos 748140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 74983221Smarcelstruct l_utimbuf { 75083221Smarcel l_time_t l_actime; 75183221Smarcel l_time_t l_modtime; 75214381Speter}; 7539313Ssos 7549313Ssosint 75583366Sjulianlinux_utime(struct thread *td, struct linux_utime_args *args) 7569313Ssos{ 75783221Smarcel struct timeval tv[2], *tvp; 75883221Smarcel struct l_utimbuf lut; 759102814Siedowse char *fname; 76083221Smarcel int error; 7619313Ssos 762102814Siedowse LCONVPATHEXIST(td, args->fname, &fname); 76314331Speter 7649313Ssos#ifdef DEBUG 76572543Sjlemon if (ldebug(utime)) 766102814Siedowse printf(ARGS(utime, "%s, *"), fname); 7679313Ssos#endif 76814381Speter 76983221Smarcel if (args->times) { 770111797Sdes if ((error = copyin(args->times, &lut, sizeof lut))) { 771102814Siedowse LFREEPATH(fname); 772218031Sdchagin return (error); 773102814Siedowse } 77483221Smarcel tv[0].tv_sec = lut.l_actime; 77583221Smarcel tv[0].tv_usec = 0; 77683221Smarcel tv[1].tv_sec = lut.l_modtime; 77783221Smarcel tv[1].tv_usec = 0; 778102814Siedowse tvp = tv; 77983221Smarcel } else 780102814Siedowse tvp = NULL; 78183221Smarcel 782102814Siedowse error = kern_utimes(td, fname, UIO_SYSSPACE, tvp, UIO_SYSSPACE); 783102814Siedowse LFREEPATH(fname); 784102814Siedowse return (error); 7859313Ssos} 786165689Snetchild 787165689Snetchildint 788165689Snetchildlinux_utimes(struct thread *td, struct linux_utimes_args *args) 789165689Snetchild{ 790165689Snetchild l_timeval ltv[2]; 791165689Snetchild struct timeval tv[2], *tvp = NULL; 792165689Snetchild char *fname; 793165689Snetchild int error; 794165689Snetchild 795165689Snetchild LCONVPATHEXIST(td, args->fname, &fname); 796165689Snetchild 797165689Snetchild#ifdef DEBUG 798165689Snetchild if (ldebug(utimes)) 799165689Snetchild printf(ARGS(utimes, "%s, *"), fname); 800165689Snetchild#endif 801165689Snetchild 802165689Snetchild if (args->tptr != NULL) { 803165689Snetchild if ((error = copyin(args->tptr, ltv, sizeof ltv))) { 804165689Snetchild LFREEPATH(fname); 805165689Snetchild return (error); 806165689Snetchild } 807165689Snetchild tv[0].tv_sec = ltv[0].tv_sec; 808165689Snetchild tv[0].tv_usec = ltv[0].tv_usec; 809165689Snetchild tv[1].tv_sec = ltv[1].tv_sec; 810165689Snetchild tv[1].tv_usec = ltv[1].tv_usec; 811165689Snetchild tvp = tv; 812165689Snetchild } 813165689Snetchild 814165689Snetchild error = kern_utimes(td, fname, UIO_SYSSPACE, tvp, UIO_SYSSPACE); 815165689Snetchild LFREEPATH(fname); 816165689Snetchild return (error); 817165689Snetchild} 818177997Skib 819177997Skibint 820177997Skiblinux_futimesat(struct thread *td, struct linux_futimesat_args *args) 821177997Skib{ 822177997Skib l_timeval ltv[2]; 823177997Skib struct timeval tv[2], *tvp = NULL; 824177997Skib char *fname; 825177997Skib int error, dfd; 826177997Skib 827177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 828177997Skib LCONVPATHEXIST_AT(td, args->filename, &fname, dfd); 829177997Skib 830177997Skib#ifdef DEBUG 831177997Skib if (ldebug(futimesat)) 832177997Skib printf(ARGS(futimesat, "%s, *"), fname); 833177997Skib#endif 834177997Skib 835177997Skib if (args->utimes != NULL) { 836177997Skib if ((error = copyin(args->utimes, ltv, sizeof ltv))) { 837177997Skib LFREEPATH(fname); 838177997Skib return (error); 839177997Skib } 840177997Skib tv[0].tv_sec = ltv[0].tv_sec; 841177997Skib tv[0].tv_usec = ltv[0].tv_usec; 842177997Skib tv[1].tv_sec = ltv[1].tv_sec; 843177997Skib tv[1].tv_usec = ltv[1].tv_usec; 844177997Skib tvp = tv; 845177997Skib } 846177997Skib 847177997Skib error = kern_utimesat(td, dfd, fname, UIO_SYSSPACE, tvp, UIO_SYSSPACE); 848177997Skib LFREEPATH(fname); 849177997Skib return (error); 850177997Skib} 851133816Stjr#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 8529313Ssos 8539313Ssosint 854218030Sdchaginlinux_common_wait(struct thread *td, int pid, int *status, 855218030Sdchagin int options, struct rusage *ru) 8569313Ssos{ 857218030Sdchagin int error, tmpstat; 8589313Ssos 859218030Sdchagin error = kern_wait(td, pid, &tmpstat, options, ru); 860127140Sjhb if (error) 861218030Sdchagin return (error); 86283221Smarcel 863218030Sdchagin if (status) { 86483221Smarcel tmpstat &= 0xffff; 86583221Smarcel if (WIFSIGNALED(tmpstat)) 86683221Smarcel tmpstat = (tmpstat & 0xffffff80) | 86783221Smarcel BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat)); 86883221Smarcel else if (WIFSTOPPED(tmpstat)) 86983221Smarcel tmpstat = (tmpstat & 0xffff00ff) | 87083221Smarcel (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8); 871218030Sdchagin error = copyout(&tmpstat, status, sizeof(int)); 87283221Smarcel } 87383221Smarcel 874218030Sdchagin return (error); 8759313Ssos} 8769313Ssos 87714331Speterint 878218030Sdchaginlinux_waitpid(struct thread *td, struct linux_waitpid_args *args) 8799313Ssos{ 880218030Sdchagin int options; 881218030Sdchagin 8829313Ssos#ifdef DEBUG 883218030Sdchagin if (ldebug(waitpid)) 884218030Sdchagin printf(ARGS(waitpid, "%d, %p, %d"), 885218030Sdchagin args->pid, (void *)args->status, args->options); 8869313Ssos#endif 887218030Sdchagin /* 888218030Sdchagin * this is necessary because the test in kern_wait doesn't work 889218030Sdchagin * because we mess with the options here 890218030Sdchagin */ 891218030Sdchagin if (args->options & ~(WUNTRACED | WNOHANG | WCONTINUED | __WCLONE)) 892218030Sdchagin return (EINVAL); 893218030Sdchagin 894127140Sjhb options = (args->options & (WNOHANG | WUNTRACED)); 89583221Smarcel /* WLINUXCLONE should be equal to __WCLONE, but we make sure */ 89683221Smarcel if (args->options & __WCLONE) 897127140Sjhb options |= WLINUXCLONE; 89814331Speter 899218030Sdchagin return (linux_common_wait(td, args->pid, args->status, options, NULL)); 900218030Sdchagin} 90114331Speter 90283221Smarcel 90314331Speterint 90483366Sjulianlinux_mknod(struct thread *td, struct linux_mknod_args *args) 90513420Ssos{ 906102814Siedowse char *path; 907102814Siedowse int error; 90814331Speter 909102814Siedowse LCONVPATHCREAT(td, args->path, &path); 91014331Speter 91114331Speter#ifdef DEBUG 91272543Sjlemon if (ldebug(mknod)) 913102814Siedowse printf(ARGS(mknod, "%s, %d, %d"), path, args->mode, args->dev); 91414331Speter#endif 91514331Speter 916164893Sjkim switch (args->mode & S_IFMT) { 917164893Sjkim case S_IFIFO: 918164893Sjkim case S_IFSOCK: 919102814Siedowse error = kern_mkfifo(td, path, UIO_SYSSPACE, args->mode); 920164893Sjkim break; 921164893Sjkim 922164893Sjkim case S_IFCHR: 923164893Sjkim case S_IFBLK: 924102814Siedowse error = kern_mknod(td, path, UIO_SYSSPACE, args->mode, 925102814Siedowse args->dev); 926164893Sjkim break; 927164893Sjkim 928164893Sjkim case S_IFDIR: 929164893Sjkim error = EPERM; 930164893Sjkim break; 931164893Sjkim 932164893Sjkim case 0: 933164893Sjkim args->mode |= S_IFREG; 934165686Snetchild /* FALLTHROUGH */ 935164893Sjkim case S_IFREG: 936164893Sjkim error = kern_open(td, path, UIO_SYSSPACE, 937164893Sjkim O_WRONLY | O_CREAT | O_TRUNC, args->mode); 938177997Skib if (error == 0) 939177997Skib kern_close(td, td->td_retval[0]); 940164893Sjkim break; 941164893Sjkim 942164893Sjkim default: 943164893Sjkim error = EINVAL; 944164893Sjkim break; 945164893Sjkim } 946102814Siedowse LFREEPATH(path); 947102814Siedowse return (error); 94813420Ssos} 94914331Speter 950177997Skibint 951177997Skiblinux_mknodat(struct thread *td, struct linux_mknodat_args *args) 952177997Skib{ 953177997Skib char *path; 954177997Skib int error, dfd; 955177997Skib 956177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 957177997Skib LCONVPATHCREAT_AT(td, args->filename, &path, dfd); 958177997Skib 959177997Skib#ifdef DEBUG 960177997Skib if (ldebug(mknodat)) 961177997Skib printf(ARGS(mknodat, "%s, %d, %d"), path, args->mode, args->dev); 962177997Skib#endif 963177997Skib 964177997Skib switch (args->mode & S_IFMT) { 965177997Skib case S_IFIFO: 966177997Skib case S_IFSOCK: 967177997Skib error = kern_mkfifoat(td, dfd, path, UIO_SYSSPACE, args->mode); 968177997Skib break; 969177997Skib 970177997Skib case S_IFCHR: 971177997Skib case S_IFBLK: 972177997Skib error = kern_mknodat(td, dfd, path, UIO_SYSSPACE, args->mode, 973177997Skib args->dev); 974177997Skib break; 975177997Skib 976177997Skib case S_IFDIR: 977177997Skib error = EPERM; 978177997Skib break; 979177997Skib 980177997Skib case 0: 981177997Skib args->mode |= S_IFREG; 982177997Skib /* FALLTHROUGH */ 983177997Skib case S_IFREG: 984177997Skib error = kern_openat(td, dfd, path, UIO_SYSSPACE, 985177997Skib O_WRONLY | O_CREAT | O_TRUNC, args->mode); 986177997Skib if (error == 0) 987177997Skib kern_close(td, td->td_retval[0]); 988177997Skib break; 989177997Skib 990177997Skib default: 991177997Skib error = EINVAL; 992177997Skib break; 993177997Skib } 994177997Skib LFREEPATH(path); 995177997Skib return (error); 996177997Skib} 997177997Skib 99814331Speter/* 99914331Speter * UGH! This is just about the dumbest idea I've ever heard!! 100014331Speter */ 100114331Speterint 100283366Sjulianlinux_personality(struct thread *td, struct linux_personality_args *args) 100314331Speter{ 100414331Speter#ifdef DEBUG 100572543Sjlemon if (ldebug(personality)) 1006113579Sjhb printf(ARGS(personality, "%lu"), (unsigned long)args->per); 100714331Speter#endif 100814331Speter if (args->per != 0) 1009218031Sdchagin return (EINVAL); 101014331Speter 101114331Speter /* Yes Jim, it's still a Linux... */ 101283366Sjulian td->td_retval[0] = 0; 1013218031Sdchagin return (0); 101414331Speter} 101514331Speter 1016133749Stjrstruct l_itimerval { 1017133749Stjr l_timeval it_interval; 1018133749Stjr l_timeval it_value; 1019133749Stjr}; 1020133749Stjr 1021140832Ssobomax#define B2L_ITIMERVAL(bip, lip) \ 1022140832Ssobomax (bip)->it_interval.tv_sec = (lip)->it_interval.tv_sec; \ 1023140832Ssobomax (bip)->it_interval.tv_usec = (lip)->it_interval.tv_usec; \ 1024140832Ssobomax (bip)->it_value.tv_sec = (lip)->it_value.tv_sec; \ 1025140832Ssobomax (bip)->it_value.tv_usec = (lip)->it_value.tv_usec; 1026140832Ssobomax 102714331Speterint 1028133749Stjrlinux_setitimer(struct thread *td, struct linux_setitimer_args *uap) 102914331Speter{ 103014331Speter int error; 1031140832Ssobomax struct l_itimerval ls; 1032140832Ssobomax struct itimerval aitv, oitv; 103314331Speter 103414331Speter#ifdef DEBUG 103572543Sjlemon if (ldebug(setitimer)) 103672543Sjlemon printf(ARGS(setitimer, "%p, %p"), 1037133840Sobrien (void *)uap->itv, (void *)uap->oitv); 103814331Speter#endif 1039140832Ssobomax 1040140832Ssobomax if (uap->itv == NULL) { 1041140832Ssobomax uap->itv = uap->oitv; 1042140832Ssobomax return (linux_getitimer(td, (struct linux_getitimer_args *)uap)); 104314331Speter } 1044140832Ssobomax 1045140832Ssobomax error = copyin(uap->itv, &ls, sizeof(ls)); 1046133749Stjr if (error != 0) 1047133749Stjr return (error); 1048140832Ssobomax B2L_ITIMERVAL(&aitv, &ls); 1049140832Ssobomax#ifdef DEBUG 1050140832Ssobomax if (ldebug(setitimer)) { 1051153775Strhodes printf("setitimer: value: sec: %jd, usec: %ld\n", 1052153775Strhodes (intmax_t)aitv.it_value.tv_sec, aitv.it_value.tv_usec); 1053153775Strhodes printf("setitimer: interval: sec: %jd, usec: %ld\n", 1054153775Strhodes (intmax_t)aitv.it_interval.tv_sec, aitv.it_interval.tv_usec); 1055133749Stjr } 1056140832Ssobomax#endif 1057140832Ssobomax error = kern_setitimer(td, uap->which, &aitv, &oitv); 1058140832Ssobomax if (error != 0 || uap->oitv == NULL) 1059140832Ssobomax return (error); 1060140832Ssobomax B2L_ITIMERVAL(&ls, &oitv); 1061140832Ssobomax 1062140832Ssobomax return (copyout(&ls, uap->oitv, sizeof(ls))); 106314331Speter} 106414331Speter 106514331Speterint 1066133749Stjrlinux_getitimer(struct thread *td, struct linux_getitimer_args *uap) 106714331Speter{ 1068133749Stjr int error; 1069140832Ssobomax struct l_itimerval ls; 1070140832Ssobomax struct itimerval aitv; 1071133749Stjr 107214331Speter#ifdef DEBUG 107372543Sjlemon if (ldebug(getitimer)) 1074133840Sobrien printf(ARGS(getitimer, "%p"), (void *)uap->itv); 107514331Speter#endif 1076140832Ssobomax error = kern_getitimer(td, uap->which, &aitv); 1077133749Stjr if (error != 0) 1078133749Stjr return (error); 1079140832Ssobomax B2L_ITIMERVAL(&ls, &aitv); 1080140832Ssobomax return (copyout(&ls, uap->itv, sizeof(ls))); 108114331Speter} 108230837Skato 108330837Skatoint 108483366Sjulianlinux_nice(struct thread *td, struct linux_nice_args *args) 108530837Skato{ 1086165686Snetchild struct setpriority_args bsd_args; 108730837Skato 108830837Skato bsd_args.which = PRIO_PROCESS; 1089165686Snetchild bsd_args.who = 0; /* current process */ 109030837Skato bsd_args.prio = args->inc; 1091225617Skmacy return (sys_setpriority(td, &bsd_args)); 109230837Skato} 109330837Skato 109442185Ssosint 109583366Sjulianlinux_setgroups(struct thread *td, struct linux_setgroups_args *args) 109642185Ssos{ 109777183Srwatson struct ucred *newcred, *oldcred; 1098194498Sbrooks l_gid_t *linux_gidset; 109950350Smarcel gid_t *bsd_gidset; 110050350Smarcel int ngrp, error; 110194621Sjhb struct proc *p; 110242185Ssos 110383221Smarcel ngrp = args->gidsetsize; 1104202341Sbrooks if (ngrp < 0 || ngrp >= ngroups_max + 1) 110594621Sjhb return (EINVAL); 1106194498Sbrooks linux_gidset = malloc(ngrp * sizeof(*linux_gidset), M_TEMP, M_WAITOK); 1107111797Sdes error = copyin(args->grouplist, linux_gidset, ngrp * sizeof(l_gid_t)); 110894621Sjhb if (error) 1109194498Sbrooks goto out; 111094621Sjhb newcred = crget(); 1111293893Sglebius crextend(newcred, ngrp + 1); 111294621Sjhb p = td->td_proc; 111394621Sjhb PROC_LOCK(p); 1114293893Sglebius oldcred = p->p_ucred; 1115293893Sglebius crcopy(newcred, oldcred); 111642185Ssos 111750350Smarcel /* 111850350Smarcel * cr_groups[0] holds egid. Setting the whole set from 111950350Smarcel * the supplied set will cause egid to be changed too. 112050350Smarcel * Keep cr_groups[0] unchanged to prevent that. 112150350Smarcel */ 112242185Ssos 1123170587Srwatson if ((error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS, 0)) != 0) { 112494621Sjhb PROC_UNLOCK(p); 112594621Sjhb crfree(newcred); 1126194498Sbrooks goto out; 112794621Sjhb } 112842185Ssos 112950350Smarcel if (ngrp > 0) { 113077183Srwatson newcred->cr_ngroups = ngrp + 1; 113150350Smarcel 113277183Srwatson bsd_gidset = newcred->cr_groups; 113350350Smarcel ngrp--; 113450350Smarcel while (ngrp >= 0) { 113550350Smarcel bsd_gidset[ngrp + 1] = linux_gidset[ngrp]; 113650350Smarcel ngrp--; 113750350Smarcel } 1138165686Snetchild } else 113977183Srwatson newcred->cr_ngroups = 1; 114050350Smarcel 114194621Sjhb setsugid(p); 114294621Sjhb p->p_ucred = newcred; 114394621Sjhb PROC_UNLOCK(p); 114477183Srwatson crfree(oldcred); 1145194498Sbrooks error = 0; 1146194498Sbrooksout: 1147194498Sbrooks free(linux_gidset, M_TEMP); 1148194498Sbrooks return (error); 114942185Ssos} 115042185Ssos 115142185Ssosint 115283366Sjulianlinux_getgroups(struct thread *td, struct linux_getgroups_args *args) 115342185Ssos{ 115477183Srwatson struct ucred *cred; 1155194498Sbrooks l_gid_t *linux_gidset; 115650350Smarcel gid_t *bsd_gidset; 115750350Smarcel int bsd_gidsetsz, ngrp, error; 115842185Ssos 115994454Sjhb cred = td->td_ucred; 116077183Srwatson bsd_gidset = cred->cr_groups; 116177183Srwatson bsd_gidsetsz = cred->cr_ngroups - 1; 116242185Ssos 116350350Smarcel /* 116450350Smarcel * cr_groups[0] holds egid. Returning the whole set 116550350Smarcel * here will cause a duplicate. Exclude cr_groups[0] 116650350Smarcel * to prevent that. 116750350Smarcel */ 116842185Ssos 116983221Smarcel if ((ngrp = args->gidsetsize) == 0) { 117083366Sjulian td->td_retval[0] = bsd_gidsetsz; 117150350Smarcel return (0); 117250350Smarcel } 117342185Ssos 117450546Smarcel if (ngrp < bsd_gidsetsz) 117550350Smarcel return (EINVAL); 117642185Ssos 117750546Smarcel ngrp = 0; 1178194498Sbrooks linux_gidset = malloc(bsd_gidsetsz * sizeof(*linux_gidset), 1179194498Sbrooks M_TEMP, M_WAITOK); 118050350Smarcel while (ngrp < bsd_gidsetsz) { 118150546Smarcel linux_gidset[ngrp] = bsd_gidset[ngrp + 1]; 118250350Smarcel ngrp++; 118350350Smarcel } 118450350Smarcel 1185194498Sbrooks error = copyout(linux_gidset, args->grouplist, ngrp * sizeof(l_gid_t)); 1186194498Sbrooks free(linux_gidset, M_TEMP); 1187194498Sbrooks if (error) 118850350Smarcel return (error); 118950350Smarcel 119083366Sjulian td->td_retval[0] = ngrp; 119150350Smarcel return (0); 119242185Ssos} 119349626Smarcel 119449626Smarcelint 119583366Sjulianlinux_setrlimit(struct thread *td, struct linux_setrlimit_args *args) 119649626Smarcel{ 1197102814Siedowse struct rlimit bsd_rlim; 119883221Smarcel struct l_rlimit rlim; 1199102814Siedowse u_int which; 120065099Smarcel int error; 120149842Smarcel 120249626Smarcel#ifdef DEBUG 120372543Sjlemon if (ldebug(setrlimit)) 120472543Sjlemon printf(ARGS(setrlimit, "%d, %p"), 120583221Smarcel args->resource, (void *)args->rlim); 120649626Smarcel#endif 120749626Smarcel 120883221Smarcel if (args->resource >= LINUX_RLIM_NLIMITS) 120965099Smarcel return (EINVAL); 121049626Smarcel 1211102814Siedowse which = linux_to_bsd_resource[args->resource]; 1212102814Siedowse if (which == -1) 121365099Smarcel return (EINVAL); 121449626Smarcel 1215111797Sdes error = copyin(args->rlim, &rlim, sizeof(rlim)); 121665099Smarcel if (error) 121765099Smarcel return (error); 121849626Smarcel 1219102814Siedowse bsd_rlim.rlim_cur = (rlim_t)rlim.rlim_cur; 1220102814Siedowse bsd_rlim.rlim_max = (rlim_t)rlim.rlim_max; 1221125454Sjhb return (kern_setrlimit(td, which, &bsd_rlim)); 122249626Smarcel} 122349626Smarcel 122449626Smarcelint 122583366Sjulianlinux_old_getrlimit(struct thread *td, struct linux_old_getrlimit_args *args) 122649626Smarcel{ 122783221Smarcel struct l_rlimit rlim; 1228102814Siedowse struct proc *p = td->td_proc; 1229125454Sjhb struct rlimit bsd_rlim; 1230102814Siedowse u_int which; 123149842Smarcel 123249626Smarcel#ifdef DEBUG 123383221Smarcel if (ldebug(old_getrlimit)) 123483221Smarcel printf(ARGS(old_getrlimit, "%d, %p"), 123583221Smarcel args->resource, (void *)args->rlim); 123649626Smarcel#endif 123749626Smarcel 123883221Smarcel if (args->resource >= LINUX_RLIM_NLIMITS) 123965099Smarcel return (EINVAL); 124049626Smarcel 1241102814Siedowse which = linux_to_bsd_resource[args->resource]; 1242102814Siedowse if (which == -1) 124365099Smarcel return (EINVAL); 124449626Smarcel 1245125454Sjhb PROC_LOCK(p); 1246125454Sjhb lim_rlimit(p, which, &bsd_rlim); 1247125454Sjhb PROC_UNLOCK(p); 1248125454Sjhb 1249140214Sobrien#ifdef COMPAT_LINUX32 1250140214Sobrien rlim.rlim_cur = (unsigned int)bsd_rlim.rlim_cur; 1251140214Sobrien if (rlim.rlim_cur == UINT_MAX) 1252140214Sobrien rlim.rlim_cur = INT_MAX; 1253140214Sobrien rlim.rlim_max = (unsigned int)bsd_rlim.rlim_max; 1254140214Sobrien if (rlim.rlim_max == UINT_MAX) 1255140214Sobrien rlim.rlim_max = INT_MAX; 1256140214Sobrien#else 1257125454Sjhb rlim.rlim_cur = (unsigned long)bsd_rlim.rlim_cur; 125865106Smarcel if (rlim.rlim_cur == ULONG_MAX) 125965106Smarcel rlim.rlim_cur = LONG_MAX; 1260125454Sjhb rlim.rlim_max = (unsigned long)bsd_rlim.rlim_max; 126165106Smarcel if (rlim.rlim_max == ULONG_MAX) 126265106Smarcel rlim.rlim_max = LONG_MAX; 1263133816Stjr#endif 1264111797Sdes return (copyout(&rlim, args->rlim, sizeof(rlim))); 126549626Smarcel} 126683221Smarcel 126783221Smarcelint 126883366Sjulianlinux_getrlimit(struct thread *td, struct linux_getrlimit_args *args) 126983221Smarcel{ 127083221Smarcel struct l_rlimit rlim; 1271102814Siedowse struct proc *p = td->td_proc; 1272125454Sjhb struct rlimit bsd_rlim; 1273102814Siedowse u_int which; 127483221Smarcel 127583221Smarcel#ifdef DEBUG 127683221Smarcel if (ldebug(getrlimit)) 127783221Smarcel printf(ARGS(getrlimit, "%d, %p"), 127883221Smarcel args->resource, (void *)args->rlim); 127983221Smarcel#endif 128083221Smarcel 128183221Smarcel if (args->resource >= LINUX_RLIM_NLIMITS) 128283221Smarcel return (EINVAL); 128383221Smarcel 1284102814Siedowse which = linux_to_bsd_resource[args->resource]; 1285102814Siedowse if (which == -1) 128683221Smarcel return (EINVAL); 128783221Smarcel 1288125454Sjhb PROC_LOCK(p); 1289125454Sjhb lim_rlimit(p, which, &bsd_rlim); 1290125454Sjhb PROC_UNLOCK(p); 1291125454Sjhb 1292125454Sjhb rlim.rlim_cur = (l_ulong)bsd_rlim.rlim_cur; 1293125454Sjhb rlim.rlim_max = (l_ulong)bsd_rlim.rlim_max; 1294111797Sdes return (copyout(&rlim, args->rlim, sizeof(rlim))); 129583221Smarcel} 129649849Smarcel 129749849Smarcelint 129883366Sjulianlinux_sched_setscheduler(struct thread *td, 129983221Smarcel struct linux_sched_setscheduler_args *args) 130049849Smarcel{ 130149849Smarcel struct sched_setscheduler_args bsd; 130249849Smarcel 130349849Smarcel#ifdef DEBUG 130472543Sjlemon if (ldebug(sched_setscheduler)) 130572543Sjlemon printf(ARGS(sched_setscheduler, "%d, %d, %p"), 130683221Smarcel args->pid, args->policy, (const void *)args->param); 130749849Smarcel#endif 130849849Smarcel 130983221Smarcel switch (args->policy) { 131049849Smarcel case LINUX_SCHED_OTHER: 131149849Smarcel bsd.policy = SCHED_OTHER; 131249849Smarcel break; 131349849Smarcel case LINUX_SCHED_FIFO: 131449849Smarcel bsd.policy = SCHED_FIFO; 131549849Smarcel break; 131649849Smarcel case LINUX_SCHED_RR: 131749849Smarcel bsd.policy = SCHED_RR; 131849849Smarcel break; 131949849Smarcel default: 1320218031Sdchagin return (EINVAL); 132149849Smarcel } 132249849Smarcel 132383221Smarcel bsd.pid = args->pid; 132483221Smarcel bsd.param = (struct sched_param *)args->param; 1325225617Skmacy return (sys_sched_setscheduler(td, &bsd)); 132649849Smarcel} 132749849Smarcel 132849849Smarcelint 132983366Sjulianlinux_sched_getscheduler(struct thread *td, 133083221Smarcel struct linux_sched_getscheduler_args *args) 133149849Smarcel{ 133249849Smarcel struct sched_getscheduler_args bsd; 133349849Smarcel int error; 133449849Smarcel 133549849Smarcel#ifdef DEBUG 133672543Sjlemon if (ldebug(sched_getscheduler)) 133783221Smarcel printf(ARGS(sched_getscheduler, "%d"), args->pid); 133849849Smarcel#endif 133949849Smarcel 134083221Smarcel bsd.pid = args->pid; 1341225617Skmacy error = sys_sched_getscheduler(td, &bsd); 134249849Smarcel 134383366Sjulian switch (td->td_retval[0]) { 134449849Smarcel case SCHED_OTHER: 134583366Sjulian td->td_retval[0] = LINUX_SCHED_OTHER; 134649849Smarcel break; 134749849Smarcel case SCHED_FIFO: 134883366Sjulian td->td_retval[0] = LINUX_SCHED_FIFO; 134949849Smarcel break; 135049849Smarcel case SCHED_RR: 135183366Sjulian td->td_retval[0] = LINUX_SCHED_RR; 135249849Smarcel break; 135349849Smarcel } 135449849Smarcel 1355218031Sdchagin return (error); 135649849Smarcel} 135772538Sjlemon 135875053Salcint 135983366Sjulianlinux_sched_get_priority_max(struct thread *td, 136083221Smarcel struct linux_sched_get_priority_max_args *args) 136175053Salc{ 136275053Salc struct sched_get_priority_max_args bsd; 136375053Salc 136475053Salc#ifdef DEBUG 136575053Salc if (ldebug(sched_get_priority_max)) 136683221Smarcel printf(ARGS(sched_get_priority_max, "%d"), args->policy); 136775053Salc#endif 136875053Salc 136983221Smarcel switch (args->policy) { 137075053Salc case LINUX_SCHED_OTHER: 137175053Salc bsd.policy = SCHED_OTHER; 137275053Salc break; 137375053Salc case LINUX_SCHED_FIFO: 137475053Salc bsd.policy = SCHED_FIFO; 137575053Salc break; 137675053Salc case LINUX_SCHED_RR: 137775053Salc bsd.policy = SCHED_RR; 137875053Salc break; 137975053Salc default: 1380218031Sdchagin return (EINVAL); 138175053Salc } 1382225617Skmacy return (sys_sched_get_priority_max(td, &bsd)); 138375053Salc} 138475053Salc 138575053Salcint 138683366Sjulianlinux_sched_get_priority_min(struct thread *td, 138783221Smarcel struct linux_sched_get_priority_min_args *args) 138875053Salc{ 138975053Salc struct sched_get_priority_min_args bsd; 139075053Salc 139175053Salc#ifdef DEBUG 139275053Salc if (ldebug(sched_get_priority_min)) 139383221Smarcel printf(ARGS(sched_get_priority_min, "%d"), args->policy); 139475053Salc#endif 139575053Salc 139683221Smarcel switch (args->policy) { 139775053Salc case LINUX_SCHED_OTHER: 139875053Salc bsd.policy = SCHED_OTHER; 139975053Salc break; 140075053Salc case LINUX_SCHED_FIFO: 140175053Salc bsd.policy = SCHED_FIFO; 140275053Salc break; 140375053Salc case LINUX_SCHED_RR: 140475053Salc bsd.policy = SCHED_RR; 140575053Salc break; 140675053Salc default: 1407218031Sdchagin return (EINVAL); 140875053Salc } 1409225617Skmacy return (sys_sched_get_priority_min(td, &bsd)); 141075053Salc} 141175053Salc 141272538Sjlemon#define REBOOT_CAD_ON 0x89abcdef 141372538Sjlemon#define REBOOT_CAD_OFF 0 141472538Sjlemon#define REBOOT_HALT 0xcdef0123 1415162358Snetchild#define REBOOT_RESTART 0x01234567 1416162358Snetchild#define REBOOT_RESTART2 0xA1B2C3D4 1417162358Snetchild#define REBOOT_POWEROFF 0x4321FEDC 1418162358Snetchild#define REBOOT_MAGIC1 0xfee1dead 1419162358Snetchild#define REBOOT_MAGIC2 0x28121969 1420162358Snetchild#define REBOOT_MAGIC2A 0x05121996 1421162358Snetchild#define REBOOT_MAGIC2B 0x16041998 142272538Sjlemon 142372538Sjlemonint 142483366Sjulianlinux_reboot(struct thread *td, struct linux_reboot_args *args) 142572538Sjlemon{ 142672538Sjlemon struct reboot_args bsd_args; 142772538Sjlemon 142872538Sjlemon#ifdef DEBUG 142972538Sjlemon if (ldebug(reboot)) 143083221Smarcel printf(ARGS(reboot, "0x%x"), args->cmd); 143172538Sjlemon#endif 1432162358Snetchild 1433162358Snetchild if (args->magic1 != REBOOT_MAGIC1) 1434218031Sdchagin return (EINVAL); 1435162358Snetchild 1436162358Snetchild switch (args->magic2) { 1437162358Snetchild case REBOOT_MAGIC2: 1438162358Snetchild case REBOOT_MAGIC2A: 1439162358Snetchild case REBOOT_MAGIC2B: 1440162358Snetchild break; 1441162358Snetchild default: 1442218031Sdchagin return (EINVAL); 1443162358Snetchild } 1444162358Snetchild 1445162358Snetchild switch (args->cmd) { 1446162358Snetchild case REBOOT_CAD_ON: 1447162358Snetchild case REBOOT_CAD_OFF: 1448164033Srwatson return (priv_check(td, PRIV_REBOOT)); 1449162358Snetchild case REBOOT_HALT: 1450162358Snetchild bsd_args.opt = RB_HALT; 1451162358Snetchild break; 1452162358Snetchild case REBOOT_RESTART: 1453162358Snetchild case REBOOT_RESTART2: 1454162358Snetchild bsd_args.opt = 0; 1455162358Snetchild break; 1456162358Snetchild case REBOOT_POWEROFF: 1457162358Snetchild bsd_args.opt = RB_POWEROFF; 1458162358Snetchild break; 1459162358Snetchild default: 1460218031Sdchagin return (EINVAL); 1461162358Snetchild } 1462225617Skmacy return (sys_reboot(td, &bsd_args)); 146372538Sjlemon} 146483221Smarcel 146589717Sgallatin 146683221Smarcel/* 146783221Smarcel * The FreeBSD native getpid(2), getgid(2) and getuid(2) also modify 1468166944Snetchild * td->td_retval[1] when COMPAT_43 is defined. This clobbers registers that 1469166944Snetchild * are assumed to be preserved. The following lightweight syscalls fixes 1470166944Snetchild * this. See also linux_getgid16() and linux_getuid16() in linux_uid16.c 147183221Smarcel * 147283221Smarcel * linux_getpid() - MP SAFE 147383221Smarcel * linux_getgid() - MP SAFE 147483221Smarcel * linux_getuid() - MP SAFE 147583221Smarcel */ 147683221Smarcel 147783221Smarcelint 147883366Sjulianlinux_getpid(struct thread *td, struct linux_getpid_args *args) 147983221Smarcel{ 1480165686Snetchild struct linux_emuldata *em; 148183366Sjulian 1482164378Skib#ifdef DEBUG 1483164378Skib if (ldebug(getpid)) 1484164378Skib printf(ARGS(getpid, "")); 1485164378Skib#endif 1486164378Skib 1487165687Snetchild if (linux_use26(td)) { 1488165869Snetchild em = em_find(td->td_proc, EMUL_DONTLOCK); 1489161420Snetchild KASSERT(em != NULL, ("getpid: emuldata not found.\n")); 1490165686Snetchild td->td_retval[0] = em->shared->group_pid; 1491161420Snetchild } else { 1492165686Snetchild td->td_retval[0] = td->td_proc->p_pid; 1493161420Snetchild } 1494161474Snetchild 1495161310Snetchild return (0); 1496161310Snetchild} 1497161310Snetchild 1498161310Snetchildint 1499161310Snetchildlinux_gettid(struct thread *td, struct linux_gettid_args *args) 1500161310Snetchild{ 1501170152Skib 1502161310Snetchild#ifdef DEBUG 1503161310Snetchild if (ldebug(gettid)) 1504161310Snetchild printf(ARGS(gettid, "")); 1505161310Snetchild#endif 1506161310Snetchild 150783366Sjulian td->td_retval[0] = td->td_proc->p_pid; 150883221Smarcel return (0); 150983221Smarcel} 151083221Smarcel 1511161310Snetchild 151283221Smarcelint 1513161310Snetchildlinux_getppid(struct thread *td, struct linux_getppid_args *args) 1514161310Snetchild{ 1515165686Snetchild struct linux_emuldata *em; 1516161310Snetchild struct proc *p, *pp; 1517161310Snetchild 1518164378Skib#ifdef DEBUG 1519164378Skib if (ldebug(getppid)) 1520164378Skib printf(ARGS(getppid, "")); 1521164378Skib#endif 1522164378Skib 1523165687Snetchild if (!linux_use26(td)) { 1524165686Snetchild PROC_LOCK(td->td_proc); 1525165686Snetchild td->td_retval[0] = td->td_proc->p_pptr->p_pid; 1526165686Snetchild PROC_UNLOCK(td->td_proc); 1527161420Snetchild return (0); 1528161420Snetchild } 1529161420Snetchild 1530165869Snetchild em = em_find(td->td_proc, EMUL_DONTLOCK); 1531161310Snetchild 1532161310Snetchild KASSERT(em != NULL, ("getppid: process emuldata not found.\n")); 1533161310Snetchild 1534161310Snetchild /* find the group leader */ 1535161310Snetchild p = pfind(em->shared->group_pid); 1536161310Snetchild 1537161310Snetchild if (p == NULL) { 1538161310Snetchild#ifdef DEBUG 1539161310Snetchild printf(LMSG("parent process not found.\n")); 1540161310Snetchild#endif 1541161310Snetchild return (0); 1542161310Snetchild } 1543161310Snetchild 1544161310Snetchild pp = p->p_pptr; /* switch to parent */ 1545161310Snetchild PROC_LOCK(pp); 1546161310Snetchild PROC_UNLOCK(p); 1547161310Snetchild 1548161310Snetchild /* if its also linux process */ 1549161310Snetchild if (pp->p_sysent == &elf_linux_sysvec) { 1550165867Snetchild em = em_find(pp, EMUL_DONTLOCK); 1551161310Snetchild KASSERT(em != NULL, ("getppid: parent emuldata not found.\n")); 1552161310Snetchild 1553161420Snetchild td->td_retval[0] = em->shared->group_pid; 1554161310Snetchild } else 1555165686Snetchild td->td_retval[0] = pp->p_pid; 1556161310Snetchild 1557161310Snetchild PROC_UNLOCK(pp); 1558161420Snetchild 1559161310Snetchild return (0); 1560161310Snetchild} 1561161310Snetchild 1562161310Snetchildint 156383366Sjulianlinux_getgid(struct thread *td, struct linux_getgid_args *args) 156483221Smarcel{ 156583366Sjulian 1566164378Skib#ifdef DEBUG 1567164378Skib if (ldebug(getgid)) 1568164378Skib printf(ARGS(getgid, "")); 1569164378Skib#endif 1570164378Skib 157194454Sjhb td->td_retval[0] = td->td_ucred->cr_rgid; 157283221Smarcel return (0); 157383221Smarcel} 157483221Smarcel 157583221Smarcelint 157683366Sjulianlinux_getuid(struct thread *td, struct linux_getuid_args *args) 157783221Smarcel{ 157883366Sjulian 1579164378Skib#ifdef DEBUG 1580164378Skib if (ldebug(getuid)) 1581164378Skib printf(ARGS(getuid, "")); 1582164378Skib#endif 1583164378Skib 158494454Sjhb td->td_retval[0] = td->td_ucred->cr_ruid; 158583221Smarcel return (0); 158683221Smarcel} 158783503Smr 158889717Sgallatin 158983503Smrint 159083503Smrlinux_getsid(struct thread *td, struct linux_getsid_args *args) 159183503Smr{ 159283503Smr struct getsid_args bsd; 1593164378Skib 1594164378Skib#ifdef DEBUG 1595164378Skib if (ldebug(getsid)) 1596164378Skib printf(ARGS(getsid, "%i"), args->pid); 1597164378Skib#endif 1598164378Skib 159983503Smr bsd.pid = args->pid; 1600225617Skmacy return (sys_getsid(td, &bsd)); 160183503Smr} 1602143197Ssobomax 1603143197Ssobomaxint 1604143197Ssobomaxlinux_nosys(struct thread *td, struct nosys_args *ignore) 1605143197Ssobomax{ 1606143197Ssobomax 1607143197Ssobomax return (ENOSYS); 1608143197Ssobomax} 1609147141Ssobomax 1610147141Ssobomaxint 1611147141Ssobomaxlinux_getpriority(struct thread *td, struct linux_getpriority_args *args) 1612147141Ssobomax{ 1613165686Snetchild struct getpriority_args bsd_args; 1614147141Ssobomax int error; 1615147141Ssobomax 1616164378Skib#ifdef DEBUG 1617164378Skib if (ldebug(getpriority)) 1618164378Skib printf(ARGS(getpriority, "%i, %i"), args->which, args->who); 1619164378Skib#endif 1620164378Skib 1621147141Ssobomax bsd_args.which = args->which; 1622147141Ssobomax bsd_args.who = args->who; 1623225617Skmacy error = sys_getpriority(td, &bsd_args); 1624147141Ssobomax td->td_retval[0] = 20 - td->td_retval[0]; 1625218031Sdchagin return (error); 1626147141Ssobomax} 1627156842Snetchild 1628156842Snetchildint 1629156842Snetchildlinux_sethostname(struct thread *td, struct linux_sethostname_args *args) 1630156842Snetchild{ 1631156842Snetchild int name[2]; 1632156842Snetchild 1633164378Skib#ifdef DEBUG 1634164378Skib if (ldebug(sethostname)) 1635164378Skib printf(ARGS(sethostname, "*, %i"), args->len); 1636164378Skib#endif 1637164378Skib 1638156842Snetchild name[0] = CTL_KERN; 1639156842Snetchild name[1] = KERN_HOSTNAME; 1640186564Sed return (userland_sysctl(td, name, 2, 0, 0, 0, args->hostname, 1641186564Sed args->len, 0, 0)); 1642156842Snetchild} 1643156842Snetchild 1644161310Snetchildint 1645184789Sedlinux_setdomainname(struct thread *td, struct linux_setdomainname_args *args) 1646184789Sed{ 1647184789Sed int name[2]; 1648184789Sed 1649184789Sed#ifdef DEBUG 1650184789Sed if (ldebug(setdomainname)) 1651184789Sed printf(ARGS(setdomainname, "*, %i"), args->len); 1652184789Sed#endif 1653184789Sed 1654184789Sed name[0] = CTL_KERN; 1655184789Sed name[1] = KERN_NISDOMAINNAME; 1656186564Sed return (userland_sysctl(td, name, 2, 0, 0, 0, args->name, 1657186564Sed args->len, 0, 0)); 1658184789Sed} 1659184789Sed 1660184789Sedint 1661161310Snetchildlinux_exit_group(struct thread *td, struct linux_exit_group_args *args) 1662161310Snetchild{ 1663215664Snetchild struct linux_emuldata *em; 1664161310Snetchild 1665161310Snetchild#ifdef DEBUG 1666161310Snetchild if (ldebug(exit_group)) 1667161310Snetchild printf(ARGS(exit_group, "%i"), args->error_code); 1668161310Snetchild#endif 1669161310Snetchild 1670215664Snetchild em = em_find(td->td_proc, EMUL_DONTLOCK); 1671215664Snetchild if (em->shared->refs > 1) { 1672215664Snetchild EMUL_SHARED_WLOCK(&emul_shared_lock); 1673215664Snetchild em->shared->flags |= EMUL_SHARED_HASXSTAT; 1674215664Snetchild em->shared->xstat = W_EXITCODE(args->error_code, 0); 1675215664Snetchild EMUL_SHARED_WUNLOCK(&emul_shared_lock); 1676215664Snetchild if (linux_use26(td)) 1677215664Snetchild linux_kill_threads(td, SIGKILL); 1678215664Snetchild } 1679161310Snetchild 1680165686Snetchild /* 1681165686Snetchild * XXX: we should send a signal to the parent if 1682166397Skib * SIGNAL_EXIT_GROUP is set. We ignore that (temporarily?) 1683165686Snetchild * as it doesnt occur often. 1684165686Snetchild */ 1685165686Snetchild exit1(td, W_EXITCODE(args->error_code, 0)); 1686161310Snetchild 1687165686Snetchild return (0); 1688161310Snetchild} 1689163734Snetchild 1690220031Savg#define _LINUX_CAPABILITY_VERSION 0x19980330 1691220031Savg 1692220031Savgstruct l_user_cap_header { 1693220031Savg l_int version; 1694220031Savg l_int pid; 1695220031Savg}; 1696220031Savg 1697220031Savgstruct l_user_cap_data { 1698220031Savg l_int effective; 1699220031Savg l_int permitted; 1700220031Savg l_int inheritable; 1701220031Savg}; 1702220031Savg 1703163734Snetchildint 1704220031Savglinux_capget(struct thread *td, struct linux_capget_args *args) 1705220031Savg{ 1706220031Savg struct l_user_cap_header luch; 1707220031Savg struct l_user_cap_data lucd; 1708220031Savg int error; 1709220031Savg 1710220031Savg if (args->hdrp == NULL) 1711220031Savg return (EFAULT); 1712220031Savg 1713220031Savg error = copyin(args->hdrp, &luch, sizeof(luch)); 1714220031Savg if (error != 0) 1715220031Savg return (error); 1716220031Savg 1717220031Savg if (luch.version != _LINUX_CAPABILITY_VERSION) { 1718220031Savg luch.version = _LINUX_CAPABILITY_VERSION; 1719220031Savg error = copyout(&luch, args->hdrp, sizeof(luch)); 1720220031Savg if (error) 1721220031Savg return (error); 1722220031Savg return (EINVAL); 1723220031Savg } 1724220031Savg 1725220031Savg if (luch.pid) 1726220031Savg return (EPERM); 1727220031Savg 1728220031Savg if (args->datap) { 1729220031Savg /* 1730220031Savg * The current implementation doesn't support setting 1731220031Savg * a capability (it's essentially a stub) so indicate 1732220031Savg * that no capabilities are currently set or available 1733220031Savg * to request. 1734220031Savg */ 1735220031Savg bzero (&lucd, sizeof(lucd)); 1736220031Savg error = copyout(&lucd, args->datap, sizeof(lucd)); 1737220031Savg } 1738220031Savg 1739220031Savg return (error); 1740220031Savg} 1741220031Savg 1742220031Savgint 1743220031Savglinux_capset(struct thread *td, struct linux_capset_args *args) 1744220031Savg{ 1745220031Savg struct l_user_cap_header luch; 1746220031Savg struct l_user_cap_data lucd; 1747220031Savg int error; 1748220031Savg 1749220031Savg if (args->hdrp == NULL || args->datap == NULL) 1750220031Savg return (EFAULT); 1751220031Savg 1752220031Savg error = copyin(args->hdrp, &luch, sizeof(luch)); 1753220031Savg if (error != 0) 1754220031Savg return (error); 1755220031Savg 1756220031Savg if (luch.version != _LINUX_CAPABILITY_VERSION) { 1757220031Savg luch.version = _LINUX_CAPABILITY_VERSION; 1758220031Savg error = copyout(&luch, args->hdrp, sizeof(luch)); 1759220031Savg if (error) 1760220031Savg return (error); 1761220031Savg return (EINVAL); 1762220031Savg } 1763220031Savg 1764220031Savg if (luch.pid) 1765220031Savg return (EPERM); 1766220031Savg 1767220031Savg error = copyin(args->datap, &lucd, sizeof(lucd)); 1768220031Savg if (error != 0) 1769220031Savg return (error); 1770220031Savg 1771220031Savg /* We currently don't support setting any capabilities. */ 1772220031Savg if (lucd.effective || lucd.permitted || lucd.inheritable) { 1773220031Savg linux_msg(td, 1774220031Savg "capset effective=0x%x, permitted=0x%x, " 1775220031Savg "inheritable=0x%x is not implemented", 1776220031Savg (int)lucd.effective, (int)lucd.permitted, 1777220031Savg (int)lucd.inheritable); 1778220031Savg return (EPERM); 1779220031Savg } 1780220031Savg 1781220031Savg return (0); 1782220031Savg} 1783220031Savg 1784220031Savgint 1785163734Snetchildlinux_prctl(struct thread *td, struct linux_prctl_args *args) 1786163734Snetchild{ 1787165686Snetchild int error = 0, max_size; 1788163734Snetchild struct proc *p = td->td_proc; 1789163734Snetchild char comm[LINUX_MAX_COMM_LEN]; 1790163734Snetchild struct linux_emuldata *em; 1791166931Snetchild int pdeath_signal; 1792163734Snetchild 1793163734Snetchild#ifdef DEBUG 1794163734Snetchild if (ldebug(prctl)) 1795165686Snetchild printf(ARGS(prctl, "%d, %d, %d, %d, %d"), args->option, 1796165686Snetchild args->arg2, args->arg3, args->arg4, args->arg5); 1797163734Snetchild#endif 1798165686Snetchild 1799165686Snetchild switch (args->option) { 1800165686Snetchild case LINUX_PR_SET_PDEATHSIG: 1801165686Snetchild if (!LINUX_SIG_VALID(args->arg2)) 1802165686Snetchild return (EINVAL); 1803165867Snetchild em = em_find(p, EMUL_DOLOCK); 1804163740Snetchild KASSERT(em != NULL, ("prctl: emuldata not found.\n")); 1805163740Snetchild em->pdeath_signal = args->arg2; 1806163740Snetchild EMUL_UNLOCK(&emul_lock); 1807165686Snetchild break; 1808163740Snetchild case LINUX_PR_GET_PDEATHSIG: 1809165867Snetchild em = em_find(p, EMUL_DOLOCK); 1810163740Snetchild KASSERT(em != NULL, ("prctl: emuldata not found.\n")); 1811166931Snetchild pdeath_signal = em->pdeath_signal; 1812166931Snetchild EMUL_UNLOCK(&emul_lock); 1813166931Snetchild error = copyout(&pdeath_signal, 1814165686Snetchild (void *)(register_t)args->arg2, 1815166931Snetchild sizeof(pdeath_signal)); 1816163740Snetchild break; 1817220031Savg case LINUX_PR_GET_KEEPCAPS: 1818220031Savg /* 1819220031Savg * Indicate that we always clear the effective and 1820220031Savg * permitted capability sets when the user id becomes 1821220031Savg * non-zero (actually the capability sets are simply 1822220031Savg * always zero in the current implementation). 1823220031Savg */ 1824220031Savg td->td_retval[0] = 0; 1825220031Savg break; 1826220031Savg case LINUX_PR_SET_KEEPCAPS: 1827220031Savg /* 1828220031Savg * Ignore requests to keep the effective and permitted 1829220031Savg * capability sets when the user id becomes non-zero. 1830220031Savg */ 1831220031Savg break; 1832163740Snetchild case LINUX_PR_SET_NAME: 1833164826Snetchild /* 1834164826Snetchild * To be on the safe side we need to make sure to not 1835164826Snetchild * overflow the size a linux program expects. We already 1836164826Snetchild * do this here in the copyin, so that we don't need to 1837164826Snetchild * check on copyout. 1838164826Snetchild */ 1839164826Snetchild max_size = MIN(sizeof(comm), sizeof(p->p_comm)); 1840165686Snetchild error = copyinstr((void *)(register_t)args->arg2, comm, 1841164826Snetchild max_size, NULL); 1842164826Snetchild 1843164826Snetchild /* Linux silently truncates the name if it is too long. */ 1844164826Snetchild if (error == ENAMETOOLONG) { 1845164826Snetchild /* 1846164826Snetchild * XXX: copyinstr() isn't documented to populate the 1847164826Snetchild * array completely, so do a copyin() to be on the 1848164826Snetchild * safe side. This should be changed in case 1849164826Snetchild * copyinstr() is changed to guarantee this. 1850164826Snetchild */ 1851164826Snetchild error = copyin((void *)(register_t)args->arg2, comm, 1852164826Snetchild max_size - 1); 1853164826Snetchild comm[max_size - 1] = '\0'; 1854164826Snetchild } 1855163740Snetchild if (error) 1856165686Snetchild return (error); 1857164826Snetchild 1858163740Snetchild PROC_LOCK(p); 1859164826Snetchild strlcpy(p->p_comm, comm, sizeof(p->p_comm)); 1860163740Snetchild PROC_UNLOCK(p); 1861163740Snetchild break; 1862163740Snetchild case LINUX_PR_GET_NAME: 1863164826Snetchild PROC_LOCK(p); 1864164826Snetchild strlcpy(comm, p->p_comm, sizeof(comm)); 1865164826Snetchild PROC_UNLOCK(p); 1866165686Snetchild error = copyout(comm, (void *)(register_t)args->arg2, 1867165686Snetchild strlen(comm) + 1); 1868163740Snetchild break; 1869163740Snetchild default: 1870163740Snetchild error = EINVAL; 1871163740Snetchild break; 1872163734Snetchild } 1873163734Snetchild 1874163734Snetchild return (error); 1875163734Snetchild} 1876171998Skib 1877171998Skib/* 1878177257Srdivacky * Get affinity of a process. 1879171998Skib */ 1880171998Skibint 1881171998Skiblinux_sched_getaffinity(struct thread *td, 1882171998Skib struct linux_sched_getaffinity_args *args) 1883171998Skib{ 1884171998Skib int error; 1885177257Srdivacky struct cpuset_getaffinity_args cga; 1886171998Skib 1887177257Srdivacky#ifdef DEBUG 1888177257Srdivacky if (ldebug(sched_getaffinity)) 1889177257Srdivacky printf(ARGS(sched_getaffinity, "%d, %d, *"), args->pid, 1890177257Srdivacky args->len); 1891177257Srdivacky#endif 1892183612Skib if (args->len < sizeof(cpuset_t)) 1893183612Skib return (EINVAL); 1894171998Skib 1895177257Srdivacky cga.level = CPU_LEVEL_WHICH; 1896177257Srdivacky cga.which = CPU_WHICH_PID; 1897177257Srdivacky cga.id = args->pid; 1898183612Skib cga.cpusetsize = sizeof(cpuset_t); 1899177604Sru cga.mask = (cpuset_t *) args->user_mask_ptr; 1900183612Skib 1901225617Skmacy if ((error = sys_cpuset_getaffinity(td, &cga)) == 0) 1902183612Skib td->td_retval[0] = sizeof(cpuset_t); 1903171998Skib 1904177257Srdivacky return (error); 1905171998Skib} 1906177257Srdivacky 1907177257Srdivacky/* 1908177257Srdivacky * Set affinity of a process. 1909177257Srdivacky */ 1910177257Srdivackyint 1911177257Srdivackylinux_sched_setaffinity(struct thread *td, 1912177257Srdivacky struct linux_sched_setaffinity_args *args) 1913177257Srdivacky{ 1914177257Srdivacky struct cpuset_setaffinity_args csa; 1915177257Srdivacky 1916177257Srdivacky#ifdef DEBUG 1917177257Srdivacky if (ldebug(sched_setaffinity)) 1918177257Srdivacky printf(ARGS(sched_setaffinity, "%d, %d, *"), args->pid, 1919177257Srdivacky args->len); 1920177257Srdivacky#endif 1921183612Skib if (args->len < sizeof(cpuset_t)) 1922183612Skib return (EINVAL); 1923183612Skib 1924177257Srdivacky csa.level = CPU_LEVEL_WHICH; 1925177257Srdivacky csa.which = CPU_WHICH_PID; 1926177257Srdivacky csa.id = args->pid; 1927183612Skib csa.cpusetsize = sizeof(cpuset_t); 1928177604Sru csa.mask = (cpuset_t *) args->user_mask_ptr; 1929177257Srdivacky 1930225617Skmacy return (sys_cpuset_setaffinity(td, &csa)); 1931177257Srdivacky} 1932