linux_misc.c revision 86852
19313Ssos/*- 29313Ssos * Copyright (c) 1994-1995 S�ren Schmidt 39313Ssos * All rights reserved. 49313Ssos * 59313Ssos * Redistribution and use in source and binary forms, with or without 69313Ssos * modification, are permitted provided that the following conditions 79313Ssos * are met: 89313Ssos * 1. Redistributions of source code must retain the above copyright 914331Speter * notice, this list of conditions and the following disclaimer 109313Ssos * in this position and unchanged. 119313Ssos * 2. Redistributions in binary form must reproduce the above copyright 129313Ssos * notice, this list of conditions and the following disclaimer in the 139313Ssos * documentation and/or other materials provided with the distribution. 149313Ssos * 3. The name of the author may not be used to endorse or promote products 159313Ssos * derived from this software withough specific prior written permission 169313Ssos * 179313Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 189313Ssos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 199313Ssos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 209313Ssos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 219313Ssos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 229313Ssos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 239313Ssos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 249313Ssos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 259313Ssos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 269313Ssos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 279313Ssos * 2850477Speter * $FreeBSD: head/sys/compat/linux/linux_misc.c 86852 2001-11-24 14:09:50Z des $ 299313Ssos */ 309313Ssos 3149842Smarcel#include "opt_compat.h" 3249842Smarcel 339313Ssos#include <sys/param.h> 349313Ssos#include <sys/systm.h> 3576166Smarkm#include <sys/fcntl.h> 3676166Smarkm#include <sys/imgact_aout.h> 3712458Sbde#include <sys/kernel.h> 3876166Smarkm#include <sys/lock.h> 399313Ssos#include <sys/mman.h> 409313Ssos#include <sys/mount.h> 4176166Smarkm#include <sys/mutex.h> 429313Ssos#include <sys/namei.h> 4383221Smarcel#include <sys/poll.h> 4476166Smarkm#include <sys/proc.h> 4580180Spirzyk#include <sys/blist.h> 4672538Sjlemon#include <sys/reboot.h> 479313Ssos#include <sys/resourcevar.h> 4876166Smarkm#include <sys/signalvar.h> 499313Ssos#include <sys/stat.h> 5012458Sbde#include <sys/sysctl.h> 5176166Smarkm#include <sys/sysproto.h> 5276166Smarkm#include <sys/time.h> 5341931Sjulian#include <sys/unistd.h> 5480180Spirzyk#include <sys/vmmeter.h> 559313Ssos#include <sys/vnode.h> 569313Ssos#include <sys/wait.h> 579313Ssos 5812652Sbde#include <vm/vm.h> 5912689Speter#include <vm/pmap.h> 6012458Sbde#include <vm/vm_kern.h> 6112689Speter#include <vm/vm_map.h> 6212842Sbde#include <vm/vm_extern.h> 6380180Spirzyk#include <vm/vm_object.h> 6480180Spirzyk#include <vm/vm_zone.h> 6580180Spirzyk#include <vm/swap_pager.h> 6612458Sbde 6730855Skato#include <machine/frame.h> 6865106Smarcel#include <machine/limits.h> 6930837Skato#include <machine/psl.h> 7050818Smarcel#include <machine/sysarch.h> 7168201Sobrien#ifdef __i386__ 7250818Smarcel#include <machine/segments.h> 7368201Sobrien#endif 7430837Skato 7549849Smarcel#include <posix4/sched.h> 7649849Smarcel 7764909Smarcel#include <machine/../linux/linux.h> 7868583Smarcel#include <machine/../linux/linux_proto.h> 7964909Smarcel#include <compat/linux/linux_mib.h> 8064909Smarcel#include <compat/linux/linux_util.h> 8164909Smarcel 8268201Sobrien#ifdef __alpha__ 8368201Sobrien#define BSD_TO_LINUX_SIGNAL(sig) (sig) 8468201Sobrien#else 8551793Smarcel#define BSD_TO_LINUX_SIGNAL(sig) \ 8651793Smarcel (((sig) <= LINUX_SIGTBLSZ) ? bsd_to_linux_signal[_SIG_IDX(sig)] : sig) 8768201Sobrien#endif 8851793Smarcel 8968201Sobrien#ifndef __alpha__ 9083221Smarcelstatic unsigned int linux_to_bsd_resource[LINUX_RLIM_NLIMITS] = { 9183221Smarcel RLIMIT_CPU, RLIMIT_FSIZE, RLIMIT_DATA, RLIMIT_STACK, 9283221Smarcel RLIMIT_CORE, RLIMIT_RSS, RLIMIT_NPROC, RLIMIT_NOFILE, 9383221Smarcel RLIMIT_MEMLOCK, -1 9449626Smarcel}; 9568201Sobrien#endif /*!__alpha__*/ 9649626Smarcel 9783221Smarcelstruct l_sysinfo { 9883221Smarcel l_long uptime; /* Seconds since boot */ 9983221Smarcel l_ulong loads[3]; /* 1, 5, and 15 minute load averages */ 10083221Smarcel l_ulong totalram; /* Total usable main memory size */ 10183221Smarcel l_ulong freeram; /* Available memory size */ 10283221Smarcel l_ulong sharedram; /* Amount of shared memory */ 10383221Smarcel l_ulong bufferram; /* Memory used by buffers */ 10483221Smarcel l_ulong totalswap; /* Total swap space size */ 10583221Smarcel l_ulong freeswap; /* swap space still available */ 10683221Smarcel l_ushort procs; /* Number of current processes */ 10783221Smarcel char _f[22]; /* Pads structure to 64 bytes */ 10880180Spirzyk}; 10968201Sobrien#ifndef __alpha__ 1109313Ssosint 11183366Sjulianlinux_sysinfo(struct thread *td, struct linux_sysinfo_args *args) 11280180Spirzyk{ 11383221Smarcel struct l_sysinfo sysinfo; 11483221Smarcel vm_object_t object; 11583221Smarcel int i; 11683221Smarcel struct timespec ts; 11780180Spirzyk 11883221Smarcel /* Uptime is copied out of print_uptime() in kern_shutdown.c */ 11983221Smarcel getnanouptime(&ts); 12083221Smarcel i = 0; 12183221Smarcel if (ts.tv_sec >= 86400) { 12283221Smarcel ts.tv_sec %= 86400; 12383221Smarcel i = 1; 12483221Smarcel } 12583221Smarcel if (i || ts.tv_sec >= 3600) { 12683221Smarcel ts.tv_sec %= 3600; 12783221Smarcel i = 1; 12883221Smarcel } 12983221Smarcel if (i || ts.tv_sec >= 60) { 13083221Smarcel ts.tv_sec %= 60; 13183221Smarcel i = 1; 13283221Smarcel } 13383221Smarcel sysinfo.uptime=ts.tv_sec; 13480180Spirzyk 13583221Smarcel /* Use the information from the mib to get our load averages */ 13683221Smarcel for (i = 0; i < 3; i++) 13783221Smarcel sysinfo.loads[i] = averunnable.ldavg[i]; 13880180Spirzyk 13983221Smarcel sysinfo.totalram = physmem * PAGE_SIZE; 14083221Smarcel sysinfo.freeram = sysinfo.totalram - cnt.v_wire_count * PAGE_SIZE; 14180180Spirzyk 14283221Smarcel sysinfo.sharedram = 0; 14383221Smarcel for (object = TAILQ_FIRST(&vm_object_list); object != NULL; 14483221Smarcel object = TAILQ_NEXT(object, object_list)) 14583221Smarcel if (object->shadow_count > 1) 14683221Smarcel sysinfo.sharedram += object->resident_page_count; 14780180Spirzyk 14883221Smarcel sysinfo.sharedram *= PAGE_SIZE; 14983221Smarcel sysinfo.bufferram = 0; 15080180Spirzyk 15183221Smarcel if (swapblist == NULL) { 15283221Smarcel sysinfo.totalswap= 0; 15383221Smarcel sysinfo.freeswap = 0; 15483221Smarcel } else { 15583221Smarcel sysinfo.totalswap = swapblist->bl_blocks * 1024; 15683221Smarcel sysinfo.freeswap = swapblist->bl_root->u.bmu_avail * PAGE_SIZE; 15783221Smarcel } 15880180Spirzyk 15983221Smarcel sysinfo.procs = 20; /* Hack */ 16080180Spirzyk 16183221Smarcel return copyout(&sysinfo, (caddr_t)args->info, sizeof(sysinfo)); 16280180Spirzyk} 16380180Spirzyk#endif /*!__alpha__*/ 16480180Spirzyk 16580180Spirzyk#ifndef __alpha__ 16680180Spirzykint 16783366Sjulianlinux_alarm(struct thread *td, struct linux_alarm_args *args) 1689313Ssos{ 16983221Smarcel struct itimerval it, old_it; 17083221Smarcel struct timeval tv; 17183221Smarcel int s; 1729313Ssos 1739313Ssos#ifdef DEBUG 17472543Sjlemon if (ldebug(alarm)) 17572543Sjlemon printf(ARGS(alarm, "%u"), args->secs); 1769313Ssos#endif 17783221Smarcel 17883221Smarcel if (args->secs > 100000000) 17983221Smarcel return EINVAL; 18083221Smarcel 18183221Smarcel it.it_value.tv_sec = (long)args->secs; 18283221Smarcel it.it_value.tv_usec = 0; 18383221Smarcel it.it_interval.tv_sec = 0; 18483221Smarcel it.it_interval.tv_usec = 0; 18583221Smarcel s = splsoftclock(); 18683366Sjulian old_it = td->td_proc->p_realtimer; 18783221Smarcel getmicrouptime(&tv); 18883221Smarcel if (timevalisset(&old_it.it_value)) 18983366Sjulian callout_stop(&td->td_proc->p_itcallout); 19083221Smarcel if (it.it_value.tv_sec != 0) { 19183366Sjulian callout_reset(&td->td_proc->p_itcallout, tvtohz(&it.it_value), 19286852Sdes realitexpire, td->td_proc); 19383221Smarcel timevaladd(&it.it_value, &tv); 19483221Smarcel } 19583366Sjulian td->td_proc->p_realtimer = it; 19683221Smarcel splx(s); 19783221Smarcel if (timevalcmp(&old_it.it_value, &tv, >)) { 19883221Smarcel timevalsub(&old_it.it_value, &tv); 19983221Smarcel if (old_it.it_value.tv_usec != 0) 20083221Smarcel old_it.it_value.tv_sec++; 20183366Sjulian td->td_retval[0] = old_it.it_value.tv_sec; 20283221Smarcel } 20383221Smarcel return 0; 2049313Ssos} 20568201Sobrien#endif /*!__alpha__*/ 2069313Ssos 2079313Ssosint 20883366Sjulianlinux_brk(struct thread *td, struct linux_brk_args *args) 2099313Ssos{ 21083366Sjulian struct vmspace *vm = td->td_proc->p_vmspace; 21183221Smarcel vm_offset_t new, old; 21283221Smarcel struct obreak_args /* { 21383221Smarcel char * nsize; 21483221Smarcel } */ tmp; 2159313Ssos 2169313Ssos#ifdef DEBUG 21772543Sjlemon if (ldebug(brk)) 21872543Sjlemon printf(ARGS(brk, "%p"), (void *)args->dsend); 2199313Ssos#endif 22083221Smarcel old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize); 22183221Smarcel new = (vm_offset_t)args->dsend; 22283221Smarcel tmp.nsize = (char *) new; 22383366Sjulian if (((caddr_t)new > vm->vm_daddr) && !obreak(td, &tmp)) 22483366Sjulian td->td_retval[0] = (long)new; 22583221Smarcel else 22683366Sjulian td->td_retval[0] = (long)old; 2279313Ssos 22883221Smarcel return 0; 2299313Ssos} 2309313Ssos 2319313Ssosint 23283366Sjulianlinux_uselib(struct thread *td, struct linux_uselib_args *args) 2339313Ssos{ 23483221Smarcel struct nameidata ni; 23583221Smarcel struct vnode *vp; 23683221Smarcel struct exec *a_out; 23783221Smarcel struct vattr attr; 23883221Smarcel vm_offset_t vmaddr; 23983221Smarcel unsigned long file_offset; 24083221Smarcel vm_offset_t buffer; 24183221Smarcel unsigned long bss_size; 24283221Smarcel int error; 24383221Smarcel caddr_t sg; 24483221Smarcel int locked; 2459313Ssos 24683221Smarcel sg = stackgap_init(); 24783366Sjulian CHECKALTEXIST(td, &sg, args->library); 24814331Speter 2499313Ssos#ifdef DEBUG 25072543Sjlemon if (ldebug(uselib)) 25172543Sjlemon printf(ARGS(uselib, "%s"), args->library); 2529313Ssos#endif 2539313Ssos 25483221Smarcel a_out = NULL; 25583221Smarcel locked = 0; 25683221Smarcel vp = NULL; 25714114Speter 25883366Sjulian NDINIT(&ni, LOOKUP, FOLLOW|LOCKLEAF, UIO_USERSPACE, args->library, td); 25983221Smarcel error = namei(&ni); 26083221Smarcel if (error) 26183221Smarcel goto cleanup; 2629313Ssos 26383221Smarcel vp = ni.ni_vp; 26483221Smarcel /* 26583221Smarcel * XXX - This looks like a bogus check. A LOCKLEAF namei should not 26683221Smarcel * succeed without returning a vnode. 26783221Smarcel */ 26883221Smarcel if (vp == NULL) { 26983221Smarcel error = ENOEXEC; /* ?? */ 27083221Smarcel goto cleanup; 27183221Smarcel } 27283221Smarcel NDFREE(&ni, NDF_ONLY_PNBUF); 2739313Ssos 27483221Smarcel /* 27583221Smarcel * From here on down, we have a locked vnode that must be unlocked. 27683221Smarcel */ 27783221Smarcel locked++; 27814114Speter 27983221Smarcel /* Writable? */ 28083221Smarcel if (vp->v_writecount) { 28183221Smarcel error = ETXTBSY; 28283221Smarcel goto cleanup; 28383221Smarcel } 2849313Ssos 28583221Smarcel /* Executable? */ 28683366Sjulian error = VOP_GETATTR(vp, &attr, td->td_proc->p_ucred, td); 28783221Smarcel if (error) 28883221Smarcel goto cleanup; 2899313Ssos 29083221Smarcel if ((vp->v_mount->mnt_flag & MNT_NOEXEC) || 29183221Smarcel ((attr.va_mode & 0111) == 0) || (attr.va_type != VREG)) { 29283221Smarcel error = ENOEXEC; 29383221Smarcel goto cleanup; 29483221Smarcel } 2959313Ssos 29683221Smarcel /* Sensible size? */ 29783221Smarcel if (attr.va_size == 0) { 29883221Smarcel error = ENOEXEC; 29983221Smarcel goto cleanup; 30083221Smarcel } 3019313Ssos 30283221Smarcel /* Can we access it? */ 30383366Sjulian error = VOP_ACCESS(vp, VEXEC, td->td_proc->p_ucred, td); 30483221Smarcel if (error) 30583221Smarcel goto cleanup; 3069313Ssos 30783366Sjulian error = VOP_OPEN(vp, FREAD, td->td_proc->p_ucred, td); 30883221Smarcel if (error) 30983221Smarcel goto cleanup; 3109313Ssos 31183221Smarcel /* 31283221Smarcel * Lock no longer needed 31383221Smarcel */ 31483366Sjulian VOP_UNLOCK(vp, 0, td); 31583221Smarcel locked = 0; 31611163Sjulian 31783221Smarcel /* Pull in executable header into kernel_map */ 31883221Smarcel error = vm_mmap(kernel_map, (vm_offset_t *)&a_out, PAGE_SIZE, 31983221Smarcel VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp, 0); 32083221Smarcel if (error) 32183221Smarcel goto cleanup; 3229313Ssos 32383221Smarcel /* Is it a Linux binary ? */ 32483221Smarcel if (((a_out->a_magic >> 16) & 0xff) != 0x64) { 32583221Smarcel error = ENOEXEC; 32683221Smarcel goto cleanup; 32783221Smarcel } 3289313Ssos 32983221Smarcel /* 33083221Smarcel * While we are here, we should REALLY do some more checks 33183221Smarcel */ 33214114Speter 33383221Smarcel /* Set file/virtual offset based on a.out variant. */ 33483221Smarcel switch ((int)(a_out->a_magic & 0xffff)) { 33583221Smarcel case 0413: /* ZMAGIC */ 33683221Smarcel file_offset = 1024; 33783221Smarcel break; 33883221Smarcel case 0314: /* QMAGIC */ 33983221Smarcel file_offset = 0; 34083221Smarcel break; 34183221Smarcel default: 34283221Smarcel error = ENOEXEC; 34383221Smarcel goto cleanup; 34483221Smarcel } 3459313Ssos 34683221Smarcel bss_size = round_page(a_out->a_bss); 34714114Speter 34883221Smarcel /* Check various fields in header for validity/bounds. */ 34983221Smarcel if (a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) { 35083221Smarcel error = ENOEXEC; 35183221Smarcel goto cleanup; 35283221Smarcel } 35314114Speter 35483221Smarcel /* text + data can't exceed file size */ 35583221Smarcel if (a_out->a_data + a_out->a_text > attr.va_size) { 35683221Smarcel error = EFAULT; 35783221Smarcel goto cleanup; 35883221Smarcel } 35914114Speter 36083366Sjulian /* To protect td->td_proc->p_rlimit in the if condition. */ 36183221Smarcel mtx_assert(&Giant, MA_OWNED); 36270061Sjhb 36383221Smarcel /* 36483221Smarcel * text/data/bss must not exceed limits 36583221Smarcel * XXX - this is not complete. it should check current usage PLUS 36683221Smarcel * the resources needed by this library. 36783221Smarcel */ 36884783Sps if (a_out->a_text > maxtsiz || 36983366Sjulian a_out->a_data + bss_size > 37083366Sjulian td->td_proc->p_rlimit[RLIMIT_DATA].rlim_cur) { 37183221Smarcel error = ENOMEM; 37283221Smarcel goto cleanup; 37383221Smarcel } 37414114Speter 37583221Smarcel /* prevent more writers */ 37683221Smarcel vp->v_flag |= VTEXT; 37714114Speter 37883221Smarcel /* 37983221Smarcel * Check if file_offset page aligned. Currently we cannot handle 38083221Smarcel * misalinged file offsets, and so we read in the entire image 38183221Smarcel * (what a waste). 38283221Smarcel */ 38383221Smarcel if (file_offset & PAGE_MASK) { 3849313Ssos#ifdef DEBUG 38583221Smarcel printf("uselib: Non page aligned binary %lu\n", file_offset); 3869313Ssos#endif 38783221Smarcel /* Map text+data read/write/execute */ 38814114Speter 38983221Smarcel /* a_entry is the load address and is page aligned */ 39083221Smarcel vmaddr = trunc_page(a_out->a_entry); 39114114Speter 39283221Smarcel /* get anon user mapping, read+write+execute */ 39383366Sjulian error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0, 39483366Sjulian &vmaddr, a_out->a_text + a_out->a_data, FALSE, VM_PROT_ALL, 39583221Smarcel VM_PROT_ALL, 0); 39683221Smarcel if (error) 39783221Smarcel goto cleanup; 3989313Ssos 39983221Smarcel /* map file into kernel_map */ 40083221Smarcel error = vm_mmap(kernel_map, &buffer, 40183221Smarcel round_page(a_out->a_text + a_out->a_data + file_offset), 40283221Smarcel VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp, 40383221Smarcel trunc_page(file_offset)); 40483221Smarcel if (error) 40583221Smarcel goto cleanup; 4069313Ssos 40783221Smarcel /* copy from kernel VM space to user space */ 40883221Smarcel error = copyout((caddr_t)(uintptr_t)(buffer + file_offset), 40983221Smarcel (caddr_t)vmaddr, a_out->a_text + a_out->a_data); 4109313Ssos 41183221Smarcel /* release temporary kernel space */ 41283221Smarcel vm_map_remove(kernel_map, buffer, buffer + 41383221Smarcel round_page(a_out->a_text + a_out->a_data + file_offset)); 4149313Ssos 41583221Smarcel if (error) 41683221Smarcel goto cleanup; 41783221Smarcel } else { 4189313Ssos#ifdef DEBUG 41983221Smarcel printf("uselib: Page aligned binary %lu\n", file_offset); 4209313Ssos#endif 42183221Smarcel /* 42283221Smarcel * for QMAGIC, a_entry is 20 bytes beyond the load address 42383221Smarcel * to skip the executable header 42483221Smarcel */ 42583221Smarcel vmaddr = trunc_page(a_out->a_entry); 42614114Speter 42783221Smarcel /* 42883221Smarcel * Map it all into the process's space as a single 42983221Smarcel * copy-on-write "data" segment. 43083221Smarcel */ 43183366Sjulian error = vm_mmap(&td->td_proc->p_vmspace->vm_map, &vmaddr, 43283221Smarcel a_out->a_text + a_out->a_data, VM_PROT_ALL, VM_PROT_ALL, 43383221Smarcel MAP_PRIVATE | MAP_FIXED, (caddr_t)vp, file_offset); 43483221Smarcel if (error) 43583221Smarcel goto cleanup; 43683221Smarcel } 4379313Ssos#ifdef DEBUG 43883221Smarcel printf("mem=%08lx = %08lx %08lx\n", (long)vmaddr, ((long*)vmaddr)[0], 43983221Smarcel ((long*)vmaddr)[1]); 4409313Ssos#endif 44183221Smarcel if (bss_size != 0) { 44283221Smarcel /* Calculate BSS start address */ 44383221Smarcel vmaddr = trunc_page(a_out->a_entry) + a_out->a_text + 44483221Smarcel a_out->a_data; 44514114Speter 44683221Smarcel /* allocate some 'anon' space */ 44783366Sjulian error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0, 44883366Sjulian &vmaddr, bss_size, FALSE, VM_PROT_ALL, VM_PROT_ALL, 0); 44983221Smarcel if (error) 45083221Smarcel goto cleanup; 45183221Smarcel } 45214114Speter 45314114Spetercleanup: 45483221Smarcel /* Unlock vnode if needed */ 45583221Smarcel if (locked) 45683366Sjulian VOP_UNLOCK(vp, 0, td); 45714114Speter 45883221Smarcel /* Release the kernel mapping. */ 45983221Smarcel if (a_out) 46083221Smarcel vm_map_remove(kernel_map, (vm_offset_t)a_out, 46183221Smarcel (vm_offset_t)a_out + PAGE_SIZE); 46214114Speter 46383221Smarcel return error; 4649313Ssos} 4659313Ssos 4669313Ssosint 46783366Sjulianlinux_select(struct thread *td, struct linux_select_args *args) 46814331Speter{ 46983221Smarcel struct select_args bsa; 47083221Smarcel struct timeval tv0, tv1, utv, *tvp; 47183221Smarcel caddr_t sg; 47283221Smarcel int error; 47314331Speter 4749313Ssos#ifdef DEBUG 47583221Smarcel if (ldebug(select)) 47683221Smarcel printf(ARGS(select, "%d, %p, %p, %p, %p"), args->nfds, 47783221Smarcel (void *)args->readfds, (void *)args->writefds, 47883221Smarcel (void *)args->exceptfds, (void *)args->timeout); 4799313Ssos#endif 48014331Speter 48183221Smarcel error = 0; 48283221Smarcel bsa.nd = args->nfds; 48383221Smarcel bsa.in = args->readfds; 48483221Smarcel bsa.ou = args->writefds; 48583221Smarcel bsa.ex = args->exceptfds; 48683221Smarcel bsa.tv = (struct timeval *)args->timeout; 48783221Smarcel 48883221Smarcel /* 48983221Smarcel * Store current time for computation of the amount of 49083221Smarcel * time left. 49183221Smarcel */ 49283221Smarcel if (args->timeout) { 49383221Smarcel if ((error = copyin((caddr_t)args->timeout, &utv, 49483221Smarcel sizeof(utv)))) 49583221Smarcel goto select_out; 49614331Speter#ifdef DEBUG 49783221Smarcel if (ldebug(select)) 49883221Smarcel printf(LMSG("incoming timeout (%ld/%ld)"), 49983221Smarcel utv.tv_sec, utv.tv_usec); 50014331Speter#endif 50183221Smarcel 50283221Smarcel if (itimerfix(&utv)) { 50383221Smarcel /* 50483221Smarcel * The timeval was invalid. Convert it to something 50583221Smarcel * valid that will act as it does under Linux. 50683221Smarcel */ 50783221Smarcel sg = stackgap_init(); 50883221Smarcel tvp = stackgap_alloc(&sg, sizeof(utv)); 50983221Smarcel utv.tv_sec += utv.tv_usec / 1000000; 51083221Smarcel utv.tv_usec %= 1000000; 51183221Smarcel if (utv.tv_usec < 0) { 51283221Smarcel utv.tv_sec -= 1; 51383221Smarcel utv.tv_usec += 1000000; 51483221Smarcel } 51583221Smarcel if (utv.tv_sec < 0) 51683221Smarcel timevalclear(&utv); 51783221Smarcel if ((error = copyout(&utv, tvp, sizeof(utv)))) 51883221Smarcel goto select_out; 51983221Smarcel bsa.tv = tvp; 52083221Smarcel } 52183221Smarcel microtime(&tv0); 52214331Speter } 52314331Speter 52483366Sjulian error = select(td, &bsa); 52514331Speter#ifdef DEBUG 52683221Smarcel if (ldebug(select)) 52772543Sjlemon printf(LMSG("real select returns %d"), error); 52814331Speter#endif 52983221Smarcel if (error) { 53083221Smarcel /* 53183221Smarcel * See fs/select.c in the Linux kernel. Without this, 53283221Smarcel * Maelstrom doesn't work. 53383221Smarcel */ 53483221Smarcel if (error == ERESTART) 53583221Smarcel error = EINTR; 53683221Smarcel goto select_out; 53783221Smarcel } 53814331Speter 53983221Smarcel if (args->timeout) { 54083366Sjulian if (td->td_retval[0]) { 54183221Smarcel /* 54283221Smarcel * Compute how much time was left of the timeout, 54383221Smarcel * by subtracting the current time and the time 54483221Smarcel * before we started the call, and subtracting 54583221Smarcel * that result from the user-supplied value. 54683221Smarcel */ 54783221Smarcel microtime(&tv1); 54883221Smarcel timevalsub(&tv1, &tv0); 54983221Smarcel timevalsub(&utv, &tv1); 55083221Smarcel if (utv.tv_sec < 0) 55183221Smarcel timevalclear(&utv); 55283221Smarcel } else 55383221Smarcel timevalclear(&utv); 55414331Speter#ifdef DEBUG 55583221Smarcel if (ldebug(select)) 55683221Smarcel printf(LMSG("outgoing timeout (%ld/%ld)"), 55783221Smarcel utv.tv_sec, utv.tv_usec); 55814331Speter#endif 55983221Smarcel if ((error = copyout(&utv, (caddr_t)args->timeout, 56083221Smarcel sizeof(utv)))) 56183221Smarcel goto select_out; 56283221Smarcel } 56314331Speter 56414331Speterselect_out: 56514331Speter#ifdef DEBUG 56683221Smarcel if (ldebug(select)) 56783221Smarcel printf(LMSG("select_out -> %d"), error); 56814331Speter#endif 56983221Smarcel return error; 5709313Ssos} 5719313Ssos 57237548Sjkhint 57383366Sjulianlinux_mremap(struct thread *td, struct linux_mremap_args *args) 57437548Sjkh{ 57537548Sjkh struct munmap_args /* { 57637548Sjkh void *addr; 57737548Sjkh size_t len; 57837548Sjkh } */ bsd_args; 57937548Sjkh int error = 0; 58037548Sjkh 58137548Sjkh#ifdef DEBUG 58272543Sjlemon if (ldebug(mremap)) 58372543Sjlemon printf(ARGS(mremap, "%p, %08lx, %08lx, %08lx"), 58472543Sjlemon (void *)args->addr, 58572543Sjlemon (unsigned long)args->old_len, 58672543Sjlemon (unsigned long)args->new_len, 58772543Sjlemon (unsigned long)args->flags); 58837548Sjkh#endif 58937548Sjkh args->new_len = round_page(args->new_len); 59037548Sjkh args->old_len = round_page(args->old_len); 59137548Sjkh 59237548Sjkh if (args->new_len > args->old_len) { 59383366Sjulian td->td_retval[0] = 0; 59437548Sjkh return ENOMEM; 59537548Sjkh } 59637548Sjkh 59737548Sjkh if (args->new_len < args->old_len) { 59883221Smarcel bsd_args.addr = (caddr_t)(args->addr + args->new_len); 59937548Sjkh bsd_args.len = args->old_len - args->new_len; 60083366Sjulian error = munmap(td, &bsd_args); 60137548Sjkh } 60237548Sjkh 60383366Sjulian td->td_retval[0] = error ? 0 : (u_long)args->addr; 60437548Sjkh return error; 60537548Sjkh} 60637548Sjkh 60714331Speterint 60883366Sjulianlinux_msync(struct thread *td, struct linux_msync_args *args) 60914331Speter{ 61014331Speter struct msync_args bsd_args; 6119313Ssos 61283221Smarcel bsd_args.addr = (caddr_t)args->addr; 61314331Speter bsd_args.len = args->len; 61414331Speter bsd_args.flags = 0; /* XXX ignore */ 61514331Speter 61683366Sjulian return msync(td, &bsd_args); 61714331Speter} 61814331Speter 61968201Sobrien#ifndef __alpha__ 6209313Ssosint 62183366Sjulianlinux_time(struct thread *td, struct linux_time_args *args) 6229313Ssos{ 62383221Smarcel struct timeval tv; 62483221Smarcel l_time_t tm; 62583221Smarcel int error; 6269313Ssos 6279313Ssos#ifdef DEBUG 62872543Sjlemon if (ldebug(time)) 62972543Sjlemon printf(ARGS(time, "*")); 6309313Ssos#endif 63183221Smarcel 63283221Smarcel microtime(&tv); 63383221Smarcel tm = tv.tv_sec; 63483221Smarcel if (args->tm && (error = copyout(&tm, (caddr_t)args->tm, sizeof(tm)))) 63583221Smarcel return error; 63683366Sjulian td->td_retval[0] = tm; 63783221Smarcel return 0; 6389313Ssos} 63968201Sobrien#endif /*!__alpha__*/ 6409313Ssos 64183221Smarcelstruct l_times_argv { 64283221Smarcel l_long tms_utime; 64383221Smarcel l_long tms_stime; 64483221Smarcel l_long tms_cutime; 64583221Smarcel l_long tms_cstime; 6469313Ssos}; 6479313Ssos 64874701Sgallatin#ifdef __alpha__ 64974701Sgallatin#define CLK_TCK 1024 /* Linux uses 1024 on alpha */ 65074701Sgallatin#else 65114381Speter#define CLK_TCK 100 /* Linux uses 100 */ 65274701Sgallatin#endif 65374701Sgallatin 65414381Speter#define CONVTCK(r) (r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK)) 65514381Speter 6569313Ssosint 65783366Sjulianlinux_times(struct thread *td, struct linux_times_args *args) 6589313Ssos{ 65983221Smarcel struct timeval tv; 66083221Smarcel struct l_times_argv tms; 66183221Smarcel struct rusage ru; 66283221Smarcel int error; 6639313Ssos 6649313Ssos#ifdef DEBUG 66572543Sjlemon if (ldebug(times)) 66672543Sjlemon printf(ARGS(times, "*")); 6679313Ssos#endif 66814381Speter 66983221Smarcel mtx_lock_spin(&sched_lock); 67083366Sjulian calcru(td->td_proc, &ru.ru_utime, &ru.ru_stime, NULL); 67183221Smarcel mtx_unlock_spin(&sched_lock); 67214381Speter 67383221Smarcel tms.tms_utime = CONVTCK(ru.ru_utime); 67483221Smarcel tms.tms_stime = CONVTCK(ru.ru_stime); 67514381Speter 67683366Sjulian tms.tms_cutime = CONVTCK(td->td_proc->p_stats->p_cru.ru_utime); 67783366Sjulian tms.tms_cstime = CONVTCK(td->td_proc->p_stats->p_cru.ru_stime); 67814381Speter 67983221Smarcel if ((error = copyout(&tms, (caddr_t)args->buf, sizeof(tms)))) 68083221Smarcel return error; 68183221Smarcel 68283221Smarcel microuptime(&tv); 68383366Sjulian td->td_retval[0] = (int)CONVTCK(tv); 68483221Smarcel return 0; 6859313Ssos} 6869313Ssos 6879313Ssosint 68883366Sjulianlinux_newuname(struct thread *td, struct linux_newuname_args *args) 6899313Ssos{ 69083221Smarcel struct l_new_utsname utsname; 69150465Smarcel char *osrelease, *osname; 6929313Ssos 6939313Ssos#ifdef DEBUG 69472543Sjlemon if (ldebug(newuname)) 69572543Sjlemon printf(ARGS(newuname, "*")); 6969313Ssos#endif 69750345Smarcel 69883366Sjulian osname = linux_get_osname(td->td_proc); 69983366Sjulian osrelease = linux_get_osrelease(td->td_proc); 70050465Smarcel 70183221Smarcel bzero(&utsname, sizeof(utsname)); 70250465Smarcel strncpy(utsname.sysname, osname, LINUX_MAX_UTSNAME-1); 70350345Smarcel strncpy(utsname.nodename, hostname, LINUX_MAX_UTSNAME-1); 70450465Smarcel strncpy(utsname.release, osrelease, LINUX_MAX_UTSNAME-1); 70550345Smarcel strncpy(utsname.version, version, LINUX_MAX_UTSNAME-1); 70650345Smarcel strncpy(utsname.machine, machine, LINUX_MAX_UTSNAME-1); 70750345Smarcel strncpy(utsname.domainname, domainname, LINUX_MAX_UTSNAME-1); 70850345Smarcel 70983221Smarcel return (copyout(&utsname, (caddr_t)args->buf, sizeof(utsname))); 7109313Ssos} 7119313Ssos 71283221Smarcel#if defined(__i386__) 71383221Smarcelstruct l_utimbuf { 71483221Smarcel l_time_t l_actime; 71583221Smarcel l_time_t l_modtime; 71614381Speter}; 7179313Ssos 7189313Ssosint 71983366Sjulianlinux_utime(struct thread *td, struct linux_utime_args *args) 7209313Ssos{ 72183221Smarcel struct utimes_args /* { 72283221Smarcel char *path; 72383221Smarcel struct timeval *tptr; 72483221Smarcel } */ bsdutimes; 72583221Smarcel struct timeval tv[2], *tvp; 72683221Smarcel struct l_utimbuf lut; 72783221Smarcel int error; 72883221Smarcel caddr_t sg; 7299313Ssos 73083221Smarcel sg = stackgap_init(); 73183366Sjulian CHECKALTEXIST(td, &sg, args->fname); 73214331Speter 7339313Ssos#ifdef DEBUG 73472543Sjlemon if (ldebug(utime)) 73572543Sjlemon printf(ARGS(utime, "%s, *"), args->fname); 7369313Ssos#endif 73714381Speter 73883221Smarcel if (args->times) { 73983221Smarcel if ((error = copyin((caddr_t)args->times, &lut, sizeof lut))) 74083221Smarcel return error; 74183221Smarcel tv[0].tv_sec = lut.l_actime; 74283221Smarcel tv[0].tv_usec = 0; 74383221Smarcel tv[1].tv_sec = lut.l_modtime; 74483221Smarcel tv[1].tv_usec = 0; 74583221Smarcel /* so that utimes can copyin */ 74683221Smarcel tvp = (struct timeval *)stackgap_alloc(&sg, sizeof(tv)); 74783221Smarcel if (tvp == NULL) 74883221Smarcel return (ENAMETOOLONG); 74983221Smarcel if ((error = copyout(tv, tvp, sizeof(tv)))) 75083221Smarcel return error; 75183221Smarcel bsdutimes.tptr = tvp; 75283221Smarcel } else 75383221Smarcel bsdutimes.tptr = NULL; 75483221Smarcel 75583221Smarcel bsdutimes.path = args->fname; 75683366Sjulian return utimes(td, &bsdutimes); 7579313Ssos} 75883221Smarcel#endif /* __i386__ */ 7599313Ssos 76044384Sjulian#define __WCLONE 0x80000000 76144384Sjulian 76268201Sobrien#ifndef __alpha__ 7639313Ssosint 76483366Sjulianlinux_waitpid(struct thread *td, struct linux_waitpid_args *args) 7659313Ssos{ 76683221Smarcel struct wait_args /* { 76783221Smarcel int pid; 76883221Smarcel int *status; 76983221Smarcel int options; 77083221Smarcel struct rusage *rusage; 77183221Smarcel } */ tmp; 77283221Smarcel int error, tmpstat; 7739313Ssos 7749313Ssos#ifdef DEBUG 77572543Sjlemon if (ldebug(waitpid)) 77672543Sjlemon printf(ARGS(waitpid, "%d, %p, %d"), 77772543Sjlemon args->pid, (void *)args->status, args->options); 7789313Ssos#endif 7799313Ssos 78083221Smarcel tmp.pid = args->pid; 78183221Smarcel tmp.status = args->status; 78283221Smarcel tmp.options = (args->options & (WNOHANG | WUNTRACED)); 78383221Smarcel /* WLINUXCLONE should be equal to __WCLONE, but we make sure */ 78483221Smarcel if (args->options & __WCLONE) 78583221Smarcel tmp.options |= WLINUXCLONE; 78683221Smarcel tmp.rusage = NULL; 78743208Sjulian 78883366Sjulian if ((error = wait4(td, &tmp)) != 0) 78983221Smarcel return error; 79083221Smarcel 79183221Smarcel if (args->status) { 79283221Smarcel if ((error = copyin((caddr_t)args->status, &tmpstat, 79383221Smarcel sizeof(int))) != 0) 79483221Smarcel return error; 79583221Smarcel tmpstat &= 0xffff; 79683221Smarcel if (WIFSIGNALED(tmpstat)) 79783221Smarcel tmpstat = (tmpstat & 0xffffff80) | 79883221Smarcel BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat)); 79983221Smarcel else if (WIFSTOPPED(tmpstat)) 80083221Smarcel tmpstat = (tmpstat & 0xffff00ff) | 80183221Smarcel (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8); 80283221Smarcel return copyout(&tmpstat, (caddr_t)args->status, sizeof(int)); 80383221Smarcel } 80483221Smarcel 80514331Speter return 0; 8069313Ssos} 80768201Sobrien#endif /*!__alpha__*/ 8089313Ssos 80914331Speterint 81083366Sjulianlinux_wait4(struct thread *td, struct linux_wait4_args *args) 8119313Ssos{ 81283221Smarcel struct wait_args /* { 81383221Smarcel int pid; 81483221Smarcel int *status; 81583221Smarcel int options; 81683221Smarcel struct rusage *rusage; 81783221Smarcel } */ tmp; 81883221Smarcel int error, tmpstat; 8199313Ssos 8209313Ssos#ifdef DEBUG 82172543Sjlemon if (ldebug(wait4)) 82272543Sjlemon printf(ARGS(wait4, "%d, %p, %d, %p"), 82372543Sjlemon args->pid, (void *)args->status, args->options, 82472543Sjlemon (void *)args->rusage); 8259313Ssos#endif 8269313Ssos 82783221Smarcel tmp.pid = args->pid; 82883221Smarcel tmp.status = args->status; 82983221Smarcel tmp.options = (args->options & (WNOHANG | WUNTRACED)); 83083221Smarcel /* WLINUXCLONE should be equal to __WCLONE, but we make sure */ 83183221Smarcel if (args->options & __WCLONE) 83283221Smarcel tmp.options |= WLINUXCLONE; 83383221Smarcel tmp.rusage = (struct rusage *)args->rusage; 83414331Speter 83583366Sjulian if ((error = wait4(td, &tmp)) != 0) 83683221Smarcel return error; 83714331Speter 83883366Sjulian SIGDELSET(td->td_proc->p_siglist, SIGCHLD); 83983221Smarcel 84083221Smarcel if (args->status) { 84183221Smarcel if ((error = copyin((caddr_t)args->status, &tmpstat, 84283221Smarcel sizeof(int))) != 0) 84383221Smarcel return error; 84483221Smarcel tmpstat &= 0xffff; 84583221Smarcel if (WIFSIGNALED(tmpstat)) 84683221Smarcel tmpstat = (tmpstat & 0xffffff80) | 84783221Smarcel BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat)); 84883221Smarcel else if (WIFSTOPPED(tmpstat)) 84983221Smarcel tmpstat = (tmpstat & 0xffff00ff) | 85083221Smarcel (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8); 85183221Smarcel return copyout(&tmpstat, (caddr_t)args->status, sizeof(int)); 85283221Smarcel } 85383221Smarcel 85414331Speter return 0; 8559313Ssos} 85613420Ssos 85714331Speterint 85883366Sjulianlinux_mknod(struct thread *td, struct linux_mknod_args *args) 85913420Ssos{ 86014331Speter caddr_t sg; 86114331Speter struct mknod_args bsd_mknod; 86214331Speter struct mkfifo_args bsd_mkfifo; 86314331Speter 86414331Speter sg = stackgap_init(); 86514331Speter 86683366Sjulian CHECKALTCREAT(td, &sg, args->path); 86714331Speter 86814331Speter#ifdef DEBUG 86972543Sjlemon if (ldebug(mknod)) 87072543Sjlemon printf(ARGS(mknod, "%s, %d, %d"), 87172543Sjlemon args->path, args->mode, args->dev); 87214331Speter#endif 87314331Speter 87414331Speter if (args->mode & S_IFIFO) { 87514331Speter bsd_mkfifo.path = args->path; 87614331Speter bsd_mkfifo.mode = args->mode; 87783366Sjulian return mkfifo(td, &bsd_mkfifo); 87814331Speter } else { 87914331Speter bsd_mknod.path = args->path; 88014331Speter bsd_mknod.mode = args->mode; 88114331Speter bsd_mknod.dev = args->dev; 88283366Sjulian return mknod(td, &bsd_mknod); 88314331Speter } 88413420Ssos} 88514331Speter 88614331Speter/* 88714331Speter * UGH! This is just about the dumbest idea I've ever heard!! 88814331Speter */ 88914331Speterint 89083366Sjulianlinux_personality(struct thread *td, struct linux_personality_args *args) 89114331Speter{ 89214331Speter#ifdef DEBUG 89372543Sjlemon if (ldebug(personality)) 89472543Sjlemon printf(ARGS(personality, "%d"), args->per); 89514331Speter#endif 89668201Sobrien#ifndef __alpha__ 89714331Speter if (args->per != 0) 89814331Speter return EINVAL; 89968201Sobrien#endif 90014331Speter 90114331Speter /* Yes Jim, it's still a Linux... */ 90283366Sjulian td->td_retval[0] = 0; 90314331Speter return 0; 90414331Speter} 90514331Speter 90614331Speter/* 90714331Speter * Wrappers for get/setitimer for debugging.. 90814331Speter */ 90914331Speterint 91083366Sjulianlinux_setitimer(struct thread *td, struct linux_setitimer_args *args) 91114331Speter{ 91214331Speter struct setitimer_args bsa; 91314331Speter struct itimerval foo; 91414331Speter int error; 91514331Speter 91614331Speter#ifdef DEBUG 91772543Sjlemon if (ldebug(setitimer)) 91872543Sjlemon printf(ARGS(setitimer, "%p, %p"), 91972543Sjlemon (void *)args->itv, (void *)args->oitv); 92014331Speter#endif 92114331Speter bsa.which = args->which; 92283221Smarcel bsa.itv = (struct itimerval *)args->itv; 92383221Smarcel bsa.oitv = (struct itimerval *)args->oitv; 92414331Speter if (args->itv) { 92583221Smarcel if ((error = copyin((caddr_t)args->itv, &foo, sizeof(foo)))) 92614331Speter return error; 92714331Speter#ifdef DEBUG 92872543Sjlemon if (ldebug(setitimer)) { 92972543Sjlemon printf("setitimer: value: sec: %ld, usec: %ld\n", 93072543Sjlemon foo.it_value.tv_sec, foo.it_value.tv_usec); 93172543Sjlemon printf("setitimer: interval: sec: %ld, usec: %ld\n", 93272543Sjlemon foo.it_interval.tv_sec, foo.it_interval.tv_usec); 93372543Sjlemon } 93414331Speter#endif 93514331Speter } 93683366Sjulian return setitimer(td, &bsa); 93714331Speter} 93814331Speter 93914331Speterint 94083366Sjulianlinux_getitimer(struct thread *td, struct linux_getitimer_args *args) 94114331Speter{ 94214331Speter struct getitimer_args bsa; 94314331Speter#ifdef DEBUG 94472543Sjlemon if (ldebug(getitimer)) 94572543Sjlemon printf(ARGS(getitimer, "%p"), (void *)args->itv); 94614331Speter#endif 94714331Speter bsa.which = args->which; 94883221Smarcel bsa.itv = (struct itimerval *)args->itv; 94983366Sjulian return getitimer(td, &bsa); 95014331Speter} 95130837Skato 95268201Sobrien#ifndef __alpha__ 95330837Skatoint 95483366Sjulianlinux_nice(struct thread *td, struct linux_nice_args *args) 95530837Skato{ 95630837Skato struct setpriority_args bsd_args; 95730837Skato 95830837Skato bsd_args.which = PRIO_PROCESS; 95930837Skato bsd_args.who = 0; /* current process */ 96030837Skato bsd_args.prio = args->inc; 96183366Sjulian return setpriority(td, &bsd_args); 96230837Skato} 96368201Sobrien#endif /*!__alpha__*/ 96430837Skato 96542185Ssosint 96683366Sjulianlinux_setgroups(struct thread *td, struct linux_setgroups_args *args) 96742185Ssos{ 96877183Srwatson struct ucred *newcred, *oldcred; 96983221Smarcel l_gid_t linux_gidset[NGROUPS]; 97050350Smarcel gid_t *bsd_gidset; 97150350Smarcel int ngrp, error; 97242185Ssos 97383221Smarcel ngrp = args->gidsetsize; 97483366Sjulian oldcred = td->td_proc->p_ucred; 97542185Ssos 97650350Smarcel /* 97750350Smarcel * cr_groups[0] holds egid. Setting the whole set from 97850350Smarcel * the supplied set will cause egid to be changed too. 97950350Smarcel * Keep cr_groups[0] unchanged to prevent that. 98050350Smarcel */ 98142185Ssos 98277183Srwatson if ((error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 98350350Smarcel return (error); 98442185Ssos 98550350Smarcel if (ngrp >= NGROUPS) 98650350Smarcel return (EINVAL); 98742185Ssos 98877183Srwatson newcred = crdup(oldcred); 98950350Smarcel if (ngrp > 0) { 99083221Smarcel error = copyin((caddr_t)args->grouplist, linux_gidset, 99183221Smarcel ngrp * sizeof(l_gid_t)); 99250350Smarcel if (error) 99350350Smarcel return (error); 99442185Ssos 99577183Srwatson newcred->cr_ngroups = ngrp + 1; 99650350Smarcel 99777183Srwatson bsd_gidset = newcred->cr_groups; 99850350Smarcel ngrp--; 99950350Smarcel while (ngrp >= 0) { 100050350Smarcel bsd_gidset[ngrp + 1] = linux_gidset[ngrp]; 100150350Smarcel ngrp--; 100250350Smarcel } 100350350Smarcel } 100450350Smarcel else 100577183Srwatson newcred->cr_ngroups = 1; 100650350Smarcel 100783366Sjulian setsugid(td->td_proc); 100883366Sjulian td->td_proc->p_ucred = newcred; 100977183Srwatson crfree(oldcred); 101050350Smarcel return (0); 101142185Ssos} 101242185Ssos 101342185Ssosint 101483366Sjulianlinux_getgroups(struct thread *td, struct linux_getgroups_args *args) 101542185Ssos{ 101677183Srwatson struct ucred *cred; 101783221Smarcel l_gid_t linux_gidset[NGROUPS]; 101850350Smarcel gid_t *bsd_gidset; 101950350Smarcel int bsd_gidsetsz, ngrp, error; 102042185Ssos 102183366Sjulian cred = td->td_proc->p_ucred; 102277183Srwatson bsd_gidset = cred->cr_groups; 102377183Srwatson bsd_gidsetsz = cred->cr_ngroups - 1; 102442185Ssos 102550350Smarcel /* 102650350Smarcel * cr_groups[0] holds egid. Returning the whole set 102750350Smarcel * here will cause a duplicate. Exclude cr_groups[0] 102850350Smarcel * to prevent that. 102950350Smarcel */ 103042185Ssos 103183221Smarcel if ((ngrp = args->gidsetsize) == 0) { 103283366Sjulian td->td_retval[0] = bsd_gidsetsz; 103350350Smarcel return (0); 103450350Smarcel } 103542185Ssos 103650546Smarcel if (ngrp < bsd_gidsetsz) 103750350Smarcel return (EINVAL); 103842185Ssos 103950546Smarcel ngrp = 0; 104050350Smarcel while (ngrp < bsd_gidsetsz) { 104150546Smarcel linux_gidset[ngrp] = bsd_gidset[ngrp + 1]; 104250350Smarcel ngrp++; 104350350Smarcel } 104450350Smarcel 104583221Smarcel if ((error = copyout(linux_gidset, (caddr_t)args->grouplist, 104683221Smarcel ngrp * sizeof(l_gid_t)))) 104750350Smarcel return (error); 104850350Smarcel 104983366Sjulian td->td_retval[0] = ngrp; 105050350Smarcel return (0); 105142185Ssos} 105249626Smarcel 105368201Sobrien#ifndef __alpha__ 105449626Smarcelint 105583366Sjulianlinux_setrlimit(struct thread *td, struct linux_setrlimit_args *args) 105649626Smarcel{ 105765099Smarcel struct __setrlimit_args bsd; 105883221Smarcel struct l_rlimit rlim; 105965099Smarcel int error; 106065099Smarcel caddr_t sg = stackgap_init(); 106149842Smarcel 106249626Smarcel#ifdef DEBUG 106372543Sjlemon if (ldebug(setrlimit)) 106472543Sjlemon printf(ARGS(setrlimit, "%d, %p"), 106583221Smarcel args->resource, (void *)args->rlim); 106649626Smarcel#endif 106749626Smarcel 106883221Smarcel if (args->resource >= LINUX_RLIM_NLIMITS) 106965099Smarcel return (EINVAL); 107049626Smarcel 107183221Smarcel bsd.which = linux_to_bsd_resource[args->resource]; 107265099Smarcel if (bsd.which == -1) 107365099Smarcel return (EINVAL); 107449626Smarcel 107583221Smarcel error = copyin((caddr_t)args->rlim, &rlim, sizeof(rlim)); 107665099Smarcel if (error) 107765099Smarcel return (error); 107849626Smarcel 107965099Smarcel bsd.rlp = stackgap_alloc(&sg, sizeof(struct rlimit)); 108065099Smarcel bsd.rlp->rlim_cur = (rlim_t)rlim.rlim_cur; 108165099Smarcel bsd.rlp->rlim_max = (rlim_t)rlim.rlim_max; 108283366Sjulian return (setrlimit(td, &bsd)); 108349626Smarcel} 108449626Smarcel 108549626Smarcelint 108683366Sjulianlinux_old_getrlimit(struct thread *td, struct linux_old_getrlimit_args *args) 108749626Smarcel{ 108865099Smarcel struct __getrlimit_args bsd; 108983221Smarcel struct l_rlimit rlim; 109065099Smarcel int error; 109165099Smarcel caddr_t sg = stackgap_init(); 109249842Smarcel 109349626Smarcel#ifdef DEBUG 109483221Smarcel if (ldebug(old_getrlimit)) 109583221Smarcel printf(ARGS(old_getrlimit, "%d, %p"), 109683221Smarcel args->resource, (void *)args->rlim); 109749626Smarcel#endif 109849626Smarcel 109983221Smarcel if (args->resource >= LINUX_RLIM_NLIMITS) 110065099Smarcel return (EINVAL); 110149626Smarcel 110283221Smarcel bsd.which = linux_to_bsd_resource[args->resource]; 110365099Smarcel if (bsd.which == -1) 110465099Smarcel return (EINVAL); 110549626Smarcel 110665099Smarcel bsd.rlp = stackgap_alloc(&sg, sizeof(struct rlimit)); 110783366Sjulian error = getrlimit(td, &bsd); 110865099Smarcel if (error) 110965099Smarcel return (error); 111049626Smarcel 111165099Smarcel rlim.rlim_cur = (unsigned long)bsd.rlp->rlim_cur; 111265106Smarcel if (rlim.rlim_cur == ULONG_MAX) 111365106Smarcel rlim.rlim_cur = LONG_MAX; 111465099Smarcel rlim.rlim_max = (unsigned long)bsd.rlp->rlim_max; 111565106Smarcel if (rlim.rlim_max == ULONG_MAX) 111665106Smarcel rlim.rlim_max = LONG_MAX; 111783221Smarcel return (copyout(&rlim, (caddr_t)args->rlim, sizeof(rlim))); 111849626Smarcel} 111983221Smarcel 112083221Smarcelint 112183366Sjulianlinux_getrlimit(struct thread *td, struct linux_getrlimit_args *args) 112283221Smarcel{ 112383221Smarcel struct __getrlimit_args bsd; 112483221Smarcel struct l_rlimit rlim; 112583221Smarcel int error; 112683221Smarcel caddr_t sg = stackgap_init(); 112783221Smarcel 112883221Smarcel#ifdef DEBUG 112983221Smarcel if (ldebug(getrlimit)) 113083221Smarcel printf(ARGS(getrlimit, "%d, %p"), 113183221Smarcel args->resource, (void *)args->rlim); 113283221Smarcel#endif 113383221Smarcel 113483221Smarcel if (args->resource >= LINUX_RLIM_NLIMITS) 113583221Smarcel return (EINVAL); 113683221Smarcel 113783221Smarcel bsd.which = linux_to_bsd_resource[args->resource]; 113883221Smarcel if (bsd.which == -1) 113983221Smarcel return (EINVAL); 114083221Smarcel 114183221Smarcel bsd.rlp = stackgap_alloc(&sg, sizeof(struct rlimit)); 114283366Sjulian error = getrlimit(td, &bsd); 114383221Smarcel if (error) 114483221Smarcel return (error); 114583221Smarcel 114683221Smarcel rlim.rlim_cur = (l_ulong)bsd.rlp->rlim_cur; 114783221Smarcel rlim.rlim_max = (l_ulong)bsd.rlp->rlim_max; 114883221Smarcel return (copyout(&rlim, (caddr_t)args->rlim, sizeof(rlim))); 114983221Smarcel} 115068201Sobrien#endif /*!__alpha__*/ 115149849Smarcel 115249849Smarcelint 115383366Sjulianlinux_sched_setscheduler(struct thread *td, 115483221Smarcel struct linux_sched_setscheduler_args *args) 115549849Smarcel{ 115649849Smarcel struct sched_setscheduler_args bsd; 115749849Smarcel 115849849Smarcel#ifdef DEBUG 115972543Sjlemon if (ldebug(sched_setscheduler)) 116072543Sjlemon printf(ARGS(sched_setscheduler, "%d, %d, %p"), 116183221Smarcel args->pid, args->policy, (const void *)args->param); 116249849Smarcel#endif 116349849Smarcel 116483221Smarcel switch (args->policy) { 116549849Smarcel case LINUX_SCHED_OTHER: 116649849Smarcel bsd.policy = SCHED_OTHER; 116749849Smarcel break; 116849849Smarcel case LINUX_SCHED_FIFO: 116949849Smarcel bsd.policy = SCHED_FIFO; 117049849Smarcel break; 117149849Smarcel case LINUX_SCHED_RR: 117249849Smarcel bsd.policy = SCHED_RR; 117349849Smarcel break; 117449849Smarcel default: 117549849Smarcel return EINVAL; 117649849Smarcel } 117749849Smarcel 117883221Smarcel bsd.pid = args->pid; 117983221Smarcel bsd.param = (struct sched_param *)args->param; 118083366Sjulian return sched_setscheduler(td, &bsd); 118149849Smarcel} 118249849Smarcel 118349849Smarcelint 118483366Sjulianlinux_sched_getscheduler(struct thread *td, 118583221Smarcel struct linux_sched_getscheduler_args *args) 118649849Smarcel{ 118749849Smarcel struct sched_getscheduler_args bsd; 118849849Smarcel int error; 118949849Smarcel 119049849Smarcel#ifdef DEBUG 119172543Sjlemon if (ldebug(sched_getscheduler)) 119283221Smarcel printf(ARGS(sched_getscheduler, "%d"), args->pid); 119349849Smarcel#endif 119449849Smarcel 119583221Smarcel bsd.pid = args->pid; 119683366Sjulian error = sched_getscheduler(td, &bsd); 119749849Smarcel 119883366Sjulian switch (td->td_retval[0]) { 119949849Smarcel case SCHED_OTHER: 120083366Sjulian td->td_retval[0] = LINUX_SCHED_OTHER; 120149849Smarcel break; 120249849Smarcel case SCHED_FIFO: 120383366Sjulian td->td_retval[0] = LINUX_SCHED_FIFO; 120449849Smarcel break; 120549849Smarcel case SCHED_RR: 120683366Sjulian td->td_retval[0] = LINUX_SCHED_RR; 120749849Smarcel break; 120849849Smarcel } 120949849Smarcel 121049849Smarcel return error; 121149849Smarcel} 121272538Sjlemon 121375053Salcint 121483366Sjulianlinux_sched_get_priority_max(struct thread *td, 121583221Smarcel struct linux_sched_get_priority_max_args *args) 121675053Salc{ 121775053Salc struct sched_get_priority_max_args bsd; 121875053Salc 121975053Salc#ifdef DEBUG 122075053Salc if (ldebug(sched_get_priority_max)) 122183221Smarcel printf(ARGS(sched_get_priority_max, "%d"), args->policy); 122275053Salc#endif 122375053Salc 122483221Smarcel switch (args->policy) { 122575053Salc case LINUX_SCHED_OTHER: 122675053Salc bsd.policy = SCHED_OTHER; 122775053Salc break; 122875053Salc case LINUX_SCHED_FIFO: 122975053Salc bsd.policy = SCHED_FIFO; 123075053Salc break; 123175053Salc case LINUX_SCHED_RR: 123275053Salc bsd.policy = SCHED_RR; 123375053Salc break; 123475053Salc default: 123575053Salc return EINVAL; 123675053Salc } 123783366Sjulian return sched_get_priority_max(td, &bsd); 123875053Salc} 123975053Salc 124075053Salcint 124183366Sjulianlinux_sched_get_priority_min(struct thread *td, 124283221Smarcel struct linux_sched_get_priority_min_args *args) 124375053Salc{ 124475053Salc struct sched_get_priority_min_args bsd; 124575053Salc 124675053Salc#ifdef DEBUG 124775053Salc if (ldebug(sched_get_priority_min)) 124883221Smarcel printf(ARGS(sched_get_priority_min, "%d"), args->policy); 124975053Salc#endif 125075053Salc 125183221Smarcel switch (args->policy) { 125275053Salc case LINUX_SCHED_OTHER: 125375053Salc bsd.policy = SCHED_OTHER; 125475053Salc break; 125575053Salc case LINUX_SCHED_FIFO: 125675053Salc bsd.policy = SCHED_FIFO; 125775053Salc break; 125875053Salc case LINUX_SCHED_RR: 125975053Salc bsd.policy = SCHED_RR; 126075053Salc break; 126175053Salc default: 126275053Salc return EINVAL; 126375053Salc } 126483366Sjulian return sched_get_priority_min(td, &bsd); 126575053Salc} 126675053Salc 126772538Sjlemon#define REBOOT_CAD_ON 0x89abcdef 126872538Sjlemon#define REBOOT_CAD_OFF 0 126972538Sjlemon#define REBOOT_HALT 0xcdef0123 127072538Sjlemon 127172538Sjlemonint 127283366Sjulianlinux_reboot(struct thread *td, struct linux_reboot_args *args) 127372538Sjlemon{ 127472538Sjlemon struct reboot_args bsd_args; 127572538Sjlemon 127672538Sjlemon#ifdef DEBUG 127772538Sjlemon if (ldebug(reboot)) 127883221Smarcel printf(ARGS(reboot, "0x%x"), args->cmd); 127972538Sjlemon#endif 128083221Smarcel if (args->cmd == REBOOT_CAD_ON || args->cmd == REBOOT_CAD_OFF) 128172538Sjlemon return (0); 128283221Smarcel bsd_args.opt = (args->cmd == REBOOT_HALT) ? RB_HALT : 0; 128383366Sjulian return (reboot(td, &bsd_args)); 128472538Sjlemon} 128583221Smarcel 128683221Smarcel/* 128783221Smarcel * The FreeBSD native getpid(2), getgid(2) and getuid(2) also modify 128883366Sjulian * td->td_retval[1] when COMPAT_43 or COMPAT_SUNOS is defined. This 128983221Smarcel * globbers registers that are assumed to be preserved. The following 129083221Smarcel * lightweight syscalls fixes this. See also linux_getgid16() and 129183221Smarcel * linux_getuid16() in linux_uid16.c. 129283221Smarcel * 129383221Smarcel * linux_getpid() - MP SAFE 129483221Smarcel * linux_getgid() - MP SAFE 129583221Smarcel * linux_getuid() - MP SAFE 129683221Smarcel */ 129783221Smarcel 129883221Smarcelint 129983366Sjulianlinux_getpid(struct thread *td, struct linux_getpid_args *args) 130083221Smarcel{ 130183366Sjulian 130283366Sjulian td->td_retval[0] = td->td_proc->p_pid; 130383221Smarcel return (0); 130483221Smarcel} 130583221Smarcel 130683221Smarcelint 130783366Sjulianlinux_getgid(struct thread *td, struct linux_getgid_args *args) 130883221Smarcel{ 130983366Sjulian 131083366Sjulian td->td_retval[0] = td->td_proc->p_ucred->cr_rgid; 131183221Smarcel return (0); 131283221Smarcel} 131383221Smarcel 131483221Smarcelint 131583366Sjulianlinux_getuid(struct thread *td, struct linux_getuid_args *args) 131683221Smarcel{ 131783366Sjulian 131883366Sjulian td->td_retval[0] = td->td_proc->p_ucred->cr_ruid; 131983221Smarcel return (0); 132083221Smarcel} 132183503Smr 132283503Smrint 132383503Smrlinux_getsid(struct thread *td, struct linux_getsid_args *args) 132483503Smr{ 132583503Smr struct getsid_args bsd; 132683503Smr bsd.pid = args->pid; 132783503Smr return getsid(td, &bsd); 132883503Smr} 1329