linux_misc.c revision 95130
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 95130 2002-04-20 14:43:34Z rwatson $ 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> 3791385Srobert#include <sys/jail.h> 3812458Sbde#include <sys/kernel.h> 3976166Smarkm#include <sys/lock.h> 409313Ssos#include <sys/mman.h> 419313Ssos#include <sys/mount.h> 4276166Smarkm#include <sys/mutex.h> 439313Ssos#include <sys/namei.h> 4483221Smarcel#include <sys/poll.h> 4576166Smarkm#include <sys/proc.h> 4680180Spirzyk#include <sys/blist.h> 4772538Sjlemon#include <sys/reboot.h> 489313Ssos#include <sys/resourcevar.h> 4976166Smarkm#include <sys/signalvar.h> 509313Ssos#include <sys/stat.h> 5112458Sbde#include <sys/sysctl.h> 5276166Smarkm#include <sys/sysproto.h> 5376166Smarkm#include <sys/time.h> 5441931Sjulian#include <sys/unistd.h> 5580180Spirzyk#include <sys/vmmeter.h> 569313Ssos#include <sys/vnode.h> 579313Ssos#include <sys/wait.h> 589313Ssos 5912652Sbde#include <vm/vm.h> 6012689Speter#include <vm/pmap.h> 6112458Sbde#include <vm/vm_kern.h> 6212689Speter#include <vm/vm_map.h> 6312842Sbde#include <vm/vm_extern.h> 6480180Spirzyk#include <vm/vm_object.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 25895130Srwatson /* 25995130Srwatson * XXX This code should make use of vn_open(), rather than doing 26095130Srwatson * all this stuff itself. 26195130Srwatson */ 26283366Sjulian NDINIT(&ni, LOOKUP, FOLLOW|LOCKLEAF, UIO_USERSPACE, args->library, td); 26383221Smarcel error = namei(&ni); 26483221Smarcel if (error) 26583221Smarcel goto cleanup; 2669313Ssos 26783221Smarcel vp = ni.ni_vp; 26883221Smarcel /* 26983221Smarcel * XXX - This looks like a bogus check. A LOCKLEAF namei should not 27083221Smarcel * succeed without returning a vnode. 27183221Smarcel */ 27283221Smarcel if (vp == NULL) { 27383221Smarcel error = ENOEXEC; /* ?? */ 27483221Smarcel goto cleanup; 27583221Smarcel } 27683221Smarcel NDFREE(&ni, NDF_ONLY_PNBUF); 2779313Ssos 27883221Smarcel /* 27983221Smarcel * From here on down, we have a locked vnode that must be unlocked. 28083221Smarcel */ 28183221Smarcel locked++; 28214114Speter 28383221Smarcel /* Writable? */ 28483221Smarcel if (vp->v_writecount) { 28583221Smarcel error = ETXTBSY; 28683221Smarcel goto cleanup; 28783221Smarcel } 2889313Ssos 28983221Smarcel /* Executable? */ 29091406Sjhb error = VOP_GETATTR(vp, &attr, td->td_ucred, td); 29183221Smarcel if (error) 29283221Smarcel goto cleanup; 2939313Ssos 29483221Smarcel if ((vp->v_mount->mnt_flag & MNT_NOEXEC) || 29583221Smarcel ((attr.va_mode & 0111) == 0) || (attr.va_type != VREG)) { 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 31191406Sjhb error = VOP_OPEN(vp, FREAD, td->td_ucred, td); 31283221Smarcel if (error) 31383221Smarcel goto cleanup; 3149313Ssos 31583221Smarcel /* 31683221Smarcel * Lock no longer needed 31783221Smarcel */ 31883366Sjulian VOP_UNLOCK(vp, 0, td); 31983221Smarcel locked = 0; 32011163Sjulian 32183221Smarcel /* Pull in executable header into kernel_map */ 32283221Smarcel error = vm_mmap(kernel_map, (vm_offset_t *)&a_out, PAGE_SIZE, 32383221Smarcel VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp, 0); 32483221Smarcel if (error) 32583221Smarcel goto cleanup; 3269313Ssos 32783221Smarcel /* Is it a Linux binary ? */ 32883221Smarcel if (((a_out->a_magic >> 16) & 0xff) != 0x64) { 32983221Smarcel error = ENOEXEC; 33083221Smarcel goto cleanup; 33183221Smarcel } 3329313Ssos 33383221Smarcel /* 33483221Smarcel * While we are here, we should REALLY do some more checks 33583221Smarcel */ 33614114Speter 33783221Smarcel /* Set file/virtual offset based on a.out variant. */ 33883221Smarcel switch ((int)(a_out->a_magic & 0xffff)) { 33983221Smarcel case 0413: /* ZMAGIC */ 34083221Smarcel file_offset = 1024; 34183221Smarcel break; 34283221Smarcel case 0314: /* QMAGIC */ 34383221Smarcel file_offset = 0; 34483221Smarcel break; 34583221Smarcel default: 34683221Smarcel error = ENOEXEC; 34783221Smarcel goto cleanup; 34883221Smarcel } 3499313Ssos 35083221Smarcel bss_size = round_page(a_out->a_bss); 35114114Speter 35283221Smarcel /* Check various fields in header for validity/bounds. */ 35383221Smarcel if (a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) { 35483221Smarcel error = ENOEXEC; 35583221Smarcel goto cleanup; 35683221Smarcel } 35714114Speter 35883221Smarcel /* text + data can't exceed file size */ 35983221Smarcel if (a_out->a_data + a_out->a_text > attr.va_size) { 36083221Smarcel error = EFAULT; 36183221Smarcel goto cleanup; 36283221Smarcel } 36314114Speter 36483366Sjulian /* To protect td->td_proc->p_rlimit in the if condition. */ 36583221Smarcel mtx_assert(&Giant, MA_OWNED); 36670061Sjhb 36783221Smarcel /* 36883221Smarcel * text/data/bss must not exceed limits 36983221Smarcel * XXX - this is not complete. it should check current usage PLUS 37083221Smarcel * the resources needed by this library. 37183221Smarcel */ 37284783Sps if (a_out->a_text > maxtsiz || 37383366Sjulian a_out->a_data + bss_size > 37483366Sjulian td->td_proc->p_rlimit[RLIMIT_DATA].rlim_cur) { 37583221Smarcel error = ENOMEM; 37683221Smarcel goto cleanup; 37783221Smarcel } 37814114Speter 37983221Smarcel /* prevent more writers */ 38083221Smarcel vp->v_flag |= VTEXT; 38114114Speter 38283221Smarcel /* 38383221Smarcel * Check if file_offset page aligned. Currently we cannot handle 38483221Smarcel * misalinged file offsets, and so we read in the entire image 38583221Smarcel * (what a waste). 38683221Smarcel */ 38783221Smarcel if (file_offset & PAGE_MASK) { 3889313Ssos#ifdef DEBUG 38983221Smarcel printf("uselib: Non page aligned binary %lu\n", file_offset); 3909313Ssos#endif 39183221Smarcel /* Map text+data read/write/execute */ 39214114Speter 39383221Smarcel /* a_entry is the load address and is page aligned */ 39483221Smarcel vmaddr = trunc_page(a_out->a_entry); 39514114Speter 39683221Smarcel /* get anon user mapping, read+write+execute */ 39783366Sjulian error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0, 39883366Sjulian &vmaddr, a_out->a_text + a_out->a_data, FALSE, VM_PROT_ALL, 39983221Smarcel VM_PROT_ALL, 0); 40083221Smarcel if (error) 40183221Smarcel goto cleanup; 4029313Ssos 40383221Smarcel /* map file into kernel_map */ 40483221Smarcel error = vm_mmap(kernel_map, &buffer, 40583221Smarcel round_page(a_out->a_text + a_out->a_data + file_offset), 40683221Smarcel VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp, 40783221Smarcel trunc_page(file_offset)); 40883221Smarcel if (error) 40983221Smarcel goto cleanup; 4109313Ssos 41183221Smarcel /* copy from kernel VM space to user space */ 41283221Smarcel error = copyout((caddr_t)(uintptr_t)(buffer + file_offset), 41383221Smarcel (caddr_t)vmaddr, a_out->a_text + a_out->a_data); 4149313Ssos 41583221Smarcel /* release temporary kernel space */ 41683221Smarcel vm_map_remove(kernel_map, buffer, buffer + 41783221Smarcel round_page(a_out->a_text + a_out->a_data + file_offset)); 4189313Ssos 41983221Smarcel if (error) 42083221Smarcel goto cleanup; 42183221Smarcel } else { 4229313Ssos#ifdef DEBUG 42383221Smarcel printf("uselib: Page aligned binary %lu\n", file_offset); 4249313Ssos#endif 42583221Smarcel /* 42683221Smarcel * for QMAGIC, a_entry is 20 bytes beyond the load address 42783221Smarcel * to skip the executable header 42883221Smarcel */ 42983221Smarcel vmaddr = trunc_page(a_out->a_entry); 43014114Speter 43183221Smarcel /* 43283221Smarcel * Map it all into the process's space as a single 43383221Smarcel * copy-on-write "data" segment. 43483221Smarcel */ 43583366Sjulian error = vm_mmap(&td->td_proc->p_vmspace->vm_map, &vmaddr, 43683221Smarcel a_out->a_text + a_out->a_data, VM_PROT_ALL, VM_PROT_ALL, 43783221Smarcel MAP_PRIVATE | MAP_FIXED, (caddr_t)vp, file_offset); 43883221Smarcel if (error) 43983221Smarcel goto cleanup; 44083221Smarcel } 4419313Ssos#ifdef DEBUG 44283221Smarcel printf("mem=%08lx = %08lx %08lx\n", (long)vmaddr, ((long*)vmaddr)[0], 44383221Smarcel ((long*)vmaddr)[1]); 4449313Ssos#endif 44583221Smarcel if (bss_size != 0) { 44683221Smarcel /* Calculate BSS start address */ 44783221Smarcel vmaddr = trunc_page(a_out->a_entry) + a_out->a_text + 44883221Smarcel a_out->a_data; 44914114Speter 45083221Smarcel /* allocate some 'anon' space */ 45183366Sjulian error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0, 45283366Sjulian &vmaddr, bss_size, FALSE, VM_PROT_ALL, VM_PROT_ALL, 0); 45383221Smarcel if (error) 45483221Smarcel goto cleanup; 45583221Smarcel } 45614114Speter 45714114Spetercleanup: 45883221Smarcel /* Unlock vnode if needed */ 45983221Smarcel if (locked) 46083366Sjulian VOP_UNLOCK(vp, 0, td); 46114114Speter 46283221Smarcel /* Release the kernel mapping. */ 46383221Smarcel if (a_out) 46483221Smarcel vm_map_remove(kernel_map, (vm_offset_t)a_out, 46583221Smarcel (vm_offset_t)a_out + PAGE_SIZE); 46614114Speter 46783221Smarcel return error; 4689313Ssos} 4699313Ssos 4709313Ssosint 47183366Sjulianlinux_select(struct thread *td, struct linux_select_args *args) 47214331Speter{ 47383221Smarcel struct select_args bsa; 47483221Smarcel struct timeval tv0, tv1, utv, *tvp; 47583221Smarcel caddr_t sg; 47683221Smarcel int error; 47714331Speter 4789313Ssos#ifdef DEBUG 47983221Smarcel if (ldebug(select)) 48083221Smarcel printf(ARGS(select, "%d, %p, %p, %p, %p"), args->nfds, 48183221Smarcel (void *)args->readfds, (void *)args->writefds, 48283221Smarcel (void *)args->exceptfds, (void *)args->timeout); 4839313Ssos#endif 48414331Speter 48583221Smarcel error = 0; 48683221Smarcel bsa.nd = args->nfds; 48783221Smarcel bsa.in = args->readfds; 48883221Smarcel bsa.ou = args->writefds; 48983221Smarcel bsa.ex = args->exceptfds; 49083221Smarcel bsa.tv = (struct timeval *)args->timeout; 49183221Smarcel 49283221Smarcel /* 49383221Smarcel * Store current time for computation of the amount of 49483221Smarcel * time left. 49583221Smarcel */ 49683221Smarcel if (args->timeout) { 49783221Smarcel if ((error = copyin((caddr_t)args->timeout, &utv, 49883221Smarcel sizeof(utv)))) 49983221Smarcel goto select_out; 50014331Speter#ifdef DEBUG 50183221Smarcel if (ldebug(select)) 50283221Smarcel printf(LMSG("incoming timeout (%ld/%ld)"), 50383221Smarcel utv.tv_sec, utv.tv_usec); 50414331Speter#endif 50583221Smarcel 50683221Smarcel if (itimerfix(&utv)) { 50783221Smarcel /* 50883221Smarcel * The timeval was invalid. Convert it to something 50983221Smarcel * valid that will act as it does under Linux. 51083221Smarcel */ 51183221Smarcel sg = stackgap_init(); 51283221Smarcel tvp = stackgap_alloc(&sg, sizeof(utv)); 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 if ((error = copyout(&utv, tvp, sizeof(utv)))) 52283221Smarcel goto select_out; 52383221Smarcel bsa.tv = tvp; 52483221Smarcel } 52583221Smarcel microtime(&tv0); 52614331Speter } 52714331Speter 52883366Sjulian error = select(td, &bsa); 52914331Speter#ifdef DEBUG 53083221Smarcel if (ldebug(select)) 53172543Sjlemon printf(LMSG("real select returns %d"), error); 53214331Speter#endif 53383221Smarcel if (error) { 53483221Smarcel /* 53583221Smarcel * See fs/select.c in the Linux kernel. Without this, 53683221Smarcel * Maelstrom doesn't work. 53783221Smarcel */ 53883221Smarcel if (error == ERESTART) 53983221Smarcel error = EINTR; 54083221Smarcel goto select_out; 54183221Smarcel } 54214331Speter 54383221Smarcel if (args->timeout) { 54483366Sjulian if (td->td_retval[0]) { 54583221Smarcel /* 54683221Smarcel * Compute how much time was left of the timeout, 54783221Smarcel * by subtracting the current time and the time 54883221Smarcel * before we started the call, and subtracting 54983221Smarcel * that result from the user-supplied value. 55083221Smarcel */ 55183221Smarcel microtime(&tv1); 55283221Smarcel timevalsub(&tv1, &tv0); 55383221Smarcel timevalsub(&utv, &tv1); 55483221Smarcel if (utv.tv_sec < 0) 55583221Smarcel timevalclear(&utv); 55683221Smarcel } else 55783221Smarcel timevalclear(&utv); 55814331Speter#ifdef DEBUG 55983221Smarcel if (ldebug(select)) 56083221Smarcel printf(LMSG("outgoing timeout (%ld/%ld)"), 56183221Smarcel utv.tv_sec, utv.tv_usec); 56214331Speter#endif 56383221Smarcel if ((error = copyout(&utv, (caddr_t)args->timeout, 56483221Smarcel sizeof(utv)))) 56583221Smarcel goto select_out; 56683221Smarcel } 56714331Speter 56814331Speterselect_out: 56914331Speter#ifdef DEBUG 57083221Smarcel if (ldebug(select)) 57183221Smarcel printf(LMSG("select_out -> %d"), error); 57214331Speter#endif 57383221Smarcel return error; 5749313Ssos} 5759313Ssos 57637548Sjkhint 57783366Sjulianlinux_mremap(struct thread *td, struct linux_mremap_args *args) 57837548Sjkh{ 57937548Sjkh struct munmap_args /* { 58037548Sjkh void *addr; 58137548Sjkh size_t len; 58237548Sjkh } */ bsd_args; 58337548Sjkh int error = 0; 58437548Sjkh 58537548Sjkh#ifdef DEBUG 58672543Sjlemon if (ldebug(mremap)) 58772543Sjlemon printf(ARGS(mremap, "%p, %08lx, %08lx, %08lx"), 58872543Sjlemon (void *)args->addr, 58972543Sjlemon (unsigned long)args->old_len, 59072543Sjlemon (unsigned long)args->new_len, 59172543Sjlemon (unsigned long)args->flags); 59237548Sjkh#endif 59337548Sjkh args->new_len = round_page(args->new_len); 59437548Sjkh args->old_len = round_page(args->old_len); 59537548Sjkh 59637548Sjkh if (args->new_len > args->old_len) { 59783366Sjulian td->td_retval[0] = 0; 59837548Sjkh return ENOMEM; 59937548Sjkh } 60037548Sjkh 60137548Sjkh if (args->new_len < args->old_len) { 60283221Smarcel bsd_args.addr = (caddr_t)(args->addr + args->new_len); 60337548Sjkh bsd_args.len = args->old_len - args->new_len; 60483366Sjulian error = munmap(td, &bsd_args); 60537548Sjkh } 60637548Sjkh 60783366Sjulian td->td_retval[0] = error ? 0 : (u_long)args->addr; 60837548Sjkh return error; 60937548Sjkh} 61037548Sjkh 61114331Speterint 61283366Sjulianlinux_msync(struct thread *td, struct linux_msync_args *args) 61314331Speter{ 61414331Speter struct msync_args bsd_args; 6159313Ssos 61683221Smarcel bsd_args.addr = (caddr_t)args->addr; 61714331Speter bsd_args.len = args->len; 61814331Speter bsd_args.flags = 0; /* XXX ignore */ 61914331Speter 62083366Sjulian return msync(td, &bsd_args); 62114331Speter} 62214331Speter 62368201Sobrien#ifndef __alpha__ 6249313Ssosint 62583366Sjulianlinux_time(struct thread *td, struct linux_time_args *args) 6269313Ssos{ 62783221Smarcel struct timeval tv; 62883221Smarcel l_time_t tm; 62983221Smarcel int error; 6309313Ssos 6319313Ssos#ifdef DEBUG 63272543Sjlemon if (ldebug(time)) 63372543Sjlemon printf(ARGS(time, "*")); 6349313Ssos#endif 63583221Smarcel 63683221Smarcel microtime(&tv); 63783221Smarcel tm = tv.tv_sec; 63883221Smarcel if (args->tm && (error = copyout(&tm, (caddr_t)args->tm, sizeof(tm)))) 63983221Smarcel return error; 64083366Sjulian td->td_retval[0] = tm; 64183221Smarcel return 0; 6429313Ssos} 64368201Sobrien#endif /*!__alpha__*/ 6449313Ssos 64583221Smarcelstruct l_times_argv { 64683221Smarcel l_long tms_utime; 64783221Smarcel l_long tms_stime; 64883221Smarcel l_long tms_cutime; 64983221Smarcel l_long tms_cstime; 6509313Ssos}; 6519313Ssos 65274701Sgallatin#ifdef __alpha__ 65374701Sgallatin#define CLK_TCK 1024 /* Linux uses 1024 on alpha */ 65474701Sgallatin#else 65514381Speter#define CLK_TCK 100 /* Linux uses 100 */ 65674701Sgallatin#endif 65774701Sgallatin 65814381Speter#define CONVTCK(r) (r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK)) 65914381Speter 6609313Ssosint 66183366Sjulianlinux_times(struct thread *td, struct linux_times_args *args) 6629313Ssos{ 66383221Smarcel struct timeval tv; 66483221Smarcel struct l_times_argv tms; 66583221Smarcel struct rusage ru; 66683221Smarcel int error; 6679313Ssos 6689313Ssos#ifdef DEBUG 66972543Sjlemon if (ldebug(times)) 67072543Sjlemon printf(ARGS(times, "*")); 6719313Ssos#endif 67214381Speter 67383221Smarcel mtx_lock_spin(&sched_lock); 67483366Sjulian calcru(td->td_proc, &ru.ru_utime, &ru.ru_stime, NULL); 67583221Smarcel mtx_unlock_spin(&sched_lock); 67614381Speter 67783221Smarcel tms.tms_utime = CONVTCK(ru.ru_utime); 67883221Smarcel tms.tms_stime = CONVTCK(ru.ru_stime); 67914381Speter 68083366Sjulian tms.tms_cutime = CONVTCK(td->td_proc->p_stats->p_cru.ru_utime); 68183366Sjulian tms.tms_cstime = CONVTCK(td->td_proc->p_stats->p_cru.ru_stime); 68214381Speter 68383221Smarcel if ((error = copyout(&tms, (caddr_t)args->buf, sizeof(tms)))) 68483221Smarcel return error; 68583221Smarcel 68683221Smarcel microuptime(&tv); 68783366Sjulian td->td_retval[0] = (int)CONVTCK(tv); 68883221Smarcel return 0; 6899313Ssos} 6909313Ssos 6919313Ssosint 69283366Sjulianlinux_newuname(struct thread *td, struct linux_newuname_args *args) 6939313Ssos{ 69483221Smarcel struct l_new_utsname utsname; 69587275Srwatson char osname[LINUX_MAX_UTSNAME]; 69687275Srwatson char osrelease[LINUX_MAX_UTSNAME]; 6979313Ssos 6989313Ssos#ifdef DEBUG 69972543Sjlemon if (ldebug(newuname)) 70072543Sjlemon printf(ARGS(newuname, "*")); 7019313Ssos#endif 70250345Smarcel 70387275Srwatson linux_get_osname(td->td_proc, osname); 70487275Srwatson linux_get_osrelease(td->td_proc, osrelease); 70550465Smarcel 70683221Smarcel bzero(&utsname, sizeof(utsname)); 70750465Smarcel strncpy(utsname.sysname, osname, LINUX_MAX_UTSNAME-1); 70891392Srobert getcredhostname(td->td_ucred, utsname.nodename, LINUX_MAX_UTSNAME-1); 70950465Smarcel strncpy(utsname.release, osrelease, LINUX_MAX_UTSNAME-1); 71050345Smarcel strncpy(utsname.version, version, LINUX_MAX_UTSNAME-1); 71150345Smarcel strncpy(utsname.machine, machine, LINUX_MAX_UTSNAME-1); 71250345Smarcel strncpy(utsname.domainname, domainname, LINUX_MAX_UTSNAME-1); 71350345Smarcel 71483221Smarcel return (copyout(&utsname, (caddr_t)args->buf, sizeof(utsname))); 7159313Ssos} 7169313Ssos 71783221Smarcel#if defined(__i386__) 71883221Smarcelstruct l_utimbuf { 71983221Smarcel l_time_t l_actime; 72083221Smarcel l_time_t l_modtime; 72114381Speter}; 7229313Ssos 7239313Ssosint 72483366Sjulianlinux_utime(struct thread *td, struct linux_utime_args *args) 7259313Ssos{ 72683221Smarcel struct utimes_args /* { 72783221Smarcel char *path; 72883221Smarcel struct timeval *tptr; 72983221Smarcel } */ bsdutimes; 73083221Smarcel struct timeval tv[2], *tvp; 73183221Smarcel struct l_utimbuf lut; 73283221Smarcel int error; 73383221Smarcel caddr_t sg; 7349313Ssos 73583221Smarcel sg = stackgap_init(); 73683366Sjulian CHECKALTEXIST(td, &sg, args->fname); 73714331Speter 7389313Ssos#ifdef DEBUG 73972543Sjlemon if (ldebug(utime)) 74072543Sjlemon printf(ARGS(utime, "%s, *"), args->fname); 7419313Ssos#endif 74214381Speter 74383221Smarcel if (args->times) { 74483221Smarcel if ((error = copyin((caddr_t)args->times, &lut, sizeof lut))) 74583221Smarcel return error; 74683221Smarcel tv[0].tv_sec = lut.l_actime; 74783221Smarcel tv[0].tv_usec = 0; 74883221Smarcel tv[1].tv_sec = lut.l_modtime; 74983221Smarcel tv[1].tv_usec = 0; 75083221Smarcel /* so that utimes can copyin */ 75183221Smarcel tvp = (struct timeval *)stackgap_alloc(&sg, sizeof(tv)); 75283221Smarcel if (tvp == NULL) 75383221Smarcel return (ENAMETOOLONG); 75483221Smarcel if ((error = copyout(tv, tvp, sizeof(tv)))) 75583221Smarcel return error; 75683221Smarcel bsdutimes.tptr = tvp; 75783221Smarcel } else 75883221Smarcel bsdutimes.tptr = NULL; 75983221Smarcel 76083221Smarcel bsdutimes.path = args->fname; 76183366Sjulian return utimes(td, &bsdutimes); 7629313Ssos} 76383221Smarcel#endif /* __i386__ */ 7649313Ssos 76544384Sjulian#define __WCLONE 0x80000000 76644384Sjulian 76768201Sobrien#ifndef __alpha__ 7689313Ssosint 76983366Sjulianlinux_waitpid(struct thread *td, struct linux_waitpid_args *args) 7709313Ssos{ 77183221Smarcel struct wait_args /* { 77283221Smarcel int pid; 77383221Smarcel int *status; 77483221Smarcel int options; 77583221Smarcel struct rusage *rusage; 77683221Smarcel } */ tmp; 77783221Smarcel int error, tmpstat; 7789313Ssos 7799313Ssos#ifdef DEBUG 78072543Sjlemon if (ldebug(waitpid)) 78172543Sjlemon printf(ARGS(waitpid, "%d, %p, %d"), 78272543Sjlemon args->pid, (void *)args->status, args->options); 7839313Ssos#endif 7849313Ssos 78583221Smarcel tmp.pid = args->pid; 78683221Smarcel tmp.status = args->status; 78783221Smarcel tmp.options = (args->options & (WNOHANG | WUNTRACED)); 78883221Smarcel /* WLINUXCLONE should be equal to __WCLONE, but we make sure */ 78983221Smarcel if (args->options & __WCLONE) 79083221Smarcel tmp.options |= WLINUXCLONE; 79183221Smarcel tmp.rusage = NULL; 79243208Sjulian 79383366Sjulian if ((error = wait4(td, &tmp)) != 0) 79483221Smarcel return error; 79583221Smarcel 79683221Smarcel if (args->status) { 79783221Smarcel if ((error = copyin((caddr_t)args->status, &tmpstat, 79883221Smarcel sizeof(int))) != 0) 79983221Smarcel return error; 80083221Smarcel tmpstat &= 0xffff; 80183221Smarcel if (WIFSIGNALED(tmpstat)) 80283221Smarcel tmpstat = (tmpstat & 0xffffff80) | 80383221Smarcel BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat)); 80483221Smarcel else if (WIFSTOPPED(tmpstat)) 80583221Smarcel tmpstat = (tmpstat & 0xffff00ff) | 80683221Smarcel (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8); 80783221Smarcel return copyout(&tmpstat, (caddr_t)args->status, sizeof(int)); 80883221Smarcel } 80983221Smarcel 81014331Speter return 0; 8119313Ssos} 81268201Sobrien#endif /*!__alpha__*/ 8139313Ssos 81414331Speterint 81583366Sjulianlinux_wait4(struct thread *td, struct linux_wait4_args *args) 8169313Ssos{ 81783221Smarcel struct wait_args /* { 81883221Smarcel int pid; 81983221Smarcel int *status; 82083221Smarcel int options; 82183221Smarcel struct rusage *rusage; 82283221Smarcel } */ tmp; 82383221Smarcel int error, tmpstat; 8249313Ssos 8259313Ssos#ifdef DEBUG 82672543Sjlemon if (ldebug(wait4)) 82772543Sjlemon printf(ARGS(wait4, "%d, %p, %d, %p"), 82872543Sjlemon args->pid, (void *)args->status, args->options, 82972543Sjlemon (void *)args->rusage); 8309313Ssos#endif 8319313Ssos 83283221Smarcel tmp.pid = args->pid; 83383221Smarcel tmp.status = args->status; 83483221Smarcel tmp.options = (args->options & (WNOHANG | WUNTRACED)); 83583221Smarcel /* WLINUXCLONE should be equal to __WCLONE, but we make sure */ 83683221Smarcel if (args->options & __WCLONE) 83783221Smarcel tmp.options |= WLINUXCLONE; 83883221Smarcel tmp.rusage = (struct rusage *)args->rusage; 83914331Speter 84083366Sjulian if ((error = wait4(td, &tmp)) != 0) 84183221Smarcel return error; 84214331Speter 84383366Sjulian SIGDELSET(td->td_proc->p_siglist, SIGCHLD); 84483221Smarcel 84583221Smarcel if (args->status) { 84683221Smarcel if ((error = copyin((caddr_t)args->status, &tmpstat, 84783221Smarcel sizeof(int))) != 0) 84883221Smarcel return error; 84983221Smarcel tmpstat &= 0xffff; 85083221Smarcel if (WIFSIGNALED(tmpstat)) 85183221Smarcel tmpstat = (tmpstat & 0xffffff80) | 85283221Smarcel BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat)); 85383221Smarcel else if (WIFSTOPPED(tmpstat)) 85483221Smarcel tmpstat = (tmpstat & 0xffff00ff) | 85583221Smarcel (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8); 85683221Smarcel return copyout(&tmpstat, (caddr_t)args->status, sizeof(int)); 85783221Smarcel } 85883221Smarcel 85914331Speter return 0; 8609313Ssos} 86113420Ssos 86214331Speterint 86383366Sjulianlinux_mknod(struct thread *td, struct linux_mknod_args *args) 86413420Ssos{ 86514331Speter caddr_t sg; 86614331Speter struct mknod_args bsd_mknod; 86714331Speter struct mkfifo_args bsd_mkfifo; 86814331Speter 86914331Speter sg = stackgap_init(); 87014331Speter 87183366Sjulian CHECKALTCREAT(td, &sg, args->path); 87214331Speter 87314331Speter#ifdef DEBUG 87472543Sjlemon if (ldebug(mknod)) 87572543Sjlemon printf(ARGS(mknod, "%s, %d, %d"), 87672543Sjlemon args->path, args->mode, args->dev); 87714331Speter#endif 87814331Speter 87914331Speter if (args->mode & S_IFIFO) { 88014331Speter bsd_mkfifo.path = args->path; 88114331Speter bsd_mkfifo.mode = args->mode; 88283366Sjulian return mkfifo(td, &bsd_mkfifo); 88314331Speter } else { 88414331Speter bsd_mknod.path = args->path; 88514331Speter bsd_mknod.mode = args->mode; 88614331Speter bsd_mknod.dev = args->dev; 88783366Sjulian return mknod(td, &bsd_mknod); 88814331Speter } 88913420Ssos} 89014331Speter 89114331Speter/* 89214331Speter * UGH! This is just about the dumbest idea I've ever heard!! 89314331Speter */ 89414331Speterint 89583366Sjulianlinux_personality(struct thread *td, struct linux_personality_args *args) 89614331Speter{ 89714331Speter#ifdef DEBUG 89872543Sjlemon if (ldebug(personality)) 89972543Sjlemon printf(ARGS(personality, "%d"), args->per); 90014331Speter#endif 90168201Sobrien#ifndef __alpha__ 90214331Speter if (args->per != 0) 90314331Speter return EINVAL; 90468201Sobrien#endif 90514331Speter 90614331Speter /* Yes Jim, it's still a Linux... */ 90783366Sjulian td->td_retval[0] = 0; 90814331Speter return 0; 90914331Speter} 91014331Speter 91114331Speter/* 91214331Speter * Wrappers for get/setitimer for debugging.. 91314331Speter */ 91414331Speterint 91583366Sjulianlinux_setitimer(struct thread *td, struct linux_setitimer_args *args) 91614331Speter{ 91714331Speter struct setitimer_args bsa; 91814331Speter struct itimerval foo; 91914331Speter int error; 92014331Speter 92114331Speter#ifdef DEBUG 92272543Sjlemon if (ldebug(setitimer)) 92372543Sjlemon printf(ARGS(setitimer, "%p, %p"), 92472543Sjlemon (void *)args->itv, (void *)args->oitv); 92514331Speter#endif 92614331Speter bsa.which = args->which; 92783221Smarcel bsa.itv = (struct itimerval *)args->itv; 92883221Smarcel bsa.oitv = (struct itimerval *)args->oitv; 92914331Speter if (args->itv) { 93083221Smarcel if ((error = copyin((caddr_t)args->itv, &foo, sizeof(foo)))) 93114331Speter return error; 93214331Speter#ifdef DEBUG 93372543Sjlemon if (ldebug(setitimer)) { 93472543Sjlemon printf("setitimer: value: sec: %ld, usec: %ld\n", 93572543Sjlemon foo.it_value.tv_sec, foo.it_value.tv_usec); 93672543Sjlemon printf("setitimer: interval: sec: %ld, usec: %ld\n", 93772543Sjlemon foo.it_interval.tv_sec, foo.it_interval.tv_usec); 93872543Sjlemon } 93914331Speter#endif 94014331Speter } 94183366Sjulian return setitimer(td, &bsa); 94214331Speter} 94314331Speter 94414331Speterint 94583366Sjulianlinux_getitimer(struct thread *td, struct linux_getitimer_args *args) 94614331Speter{ 94714331Speter struct getitimer_args bsa; 94814331Speter#ifdef DEBUG 94972543Sjlemon if (ldebug(getitimer)) 95072543Sjlemon printf(ARGS(getitimer, "%p"), (void *)args->itv); 95114331Speter#endif 95214331Speter bsa.which = args->which; 95383221Smarcel bsa.itv = (struct itimerval *)args->itv; 95483366Sjulian return getitimer(td, &bsa); 95514331Speter} 95630837Skato 95768201Sobrien#ifndef __alpha__ 95830837Skatoint 95983366Sjulianlinux_nice(struct thread *td, struct linux_nice_args *args) 96030837Skato{ 96130837Skato struct setpriority_args bsd_args; 96230837Skato 96330837Skato bsd_args.which = PRIO_PROCESS; 96430837Skato bsd_args.who = 0; /* current process */ 96530837Skato bsd_args.prio = args->inc; 96683366Sjulian return setpriority(td, &bsd_args); 96730837Skato} 96868201Sobrien#endif /*!__alpha__*/ 96930837Skato 97042185Ssosint 97183366Sjulianlinux_setgroups(struct thread *td, struct linux_setgroups_args *args) 97242185Ssos{ 97377183Srwatson struct ucred *newcred, *oldcred; 97483221Smarcel l_gid_t linux_gidset[NGROUPS]; 97550350Smarcel gid_t *bsd_gidset; 97650350Smarcel int ngrp, error; 97794621Sjhb struct proc *p; 97842185Ssos 97983221Smarcel ngrp = args->gidsetsize; 98094621Sjhb if (ngrp >= NGROUPS) 98194621Sjhb return (EINVAL); 98294621Sjhb error = copyin((caddr_t)args->grouplist, linux_gidset, 98394621Sjhb ngrp * sizeof(l_gid_t)); 98494621Sjhb if (error) 98594621Sjhb return (error); 98694621Sjhb newcred = crget(); 98794621Sjhb p = td->td_proc; 98894621Sjhb PROC_LOCK(p); 98994621Sjhb oldcred = p->p_ucred; 99042185Ssos 99150350Smarcel /* 99250350Smarcel * cr_groups[0] holds egid. Setting the whole set from 99350350Smarcel * the supplied set will cause egid to be changed too. 99450350Smarcel * Keep cr_groups[0] unchanged to prevent that. 99550350Smarcel */ 99642185Ssos 99794621Sjhb if ((error = suser_cred(oldcred, PRISON_ROOT)) != 0) { 99894621Sjhb PROC_UNLOCK(p); 99994621Sjhb crfree(newcred); 100050350Smarcel return (error); 100194621Sjhb } 100242185Ssos 100394621Sjhb crcopy(newcred, oldcred); 100450350Smarcel if (ngrp > 0) { 100577183Srwatson newcred->cr_ngroups = ngrp + 1; 100650350Smarcel 100777183Srwatson bsd_gidset = newcred->cr_groups; 100850350Smarcel ngrp--; 100950350Smarcel while (ngrp >= 0) { 101050350Smarcel bsd_gidset[ngrp + 1] = linux_gidset[ngrp]; 101150350Smarcel ngrp--; 101250350Smarcel } 101350350Smarcel } 101450350Smarcel else 101577183Srwatson newcred->cr_ngroups = 1; 101650350Smarcel 101794621Sjhb setsugid(p); 101894621Sjhb p->p_ucred = newcred; 101994621Sjhb PROC_UNLOCK(p); 102077183Srwatson crfree(oldcred); 102150350Smarcel return (0); 102242185Ssos} 102342185Ssos 102442185Ssosint 102583366Sjulianlinux_getgroups(struct thread *td, struct linux_getgroups_args *args) 102642185Ssos{ 102777183Srwatson struct ucred *cred; 102883221Smarcel l_gid_t linux_gidset[NGROUPS]; 102950350Smarcel gid_t *bsd_gidset; 103050350Smarcel int bsd_gidsetsz, ngrp, error; 103142185Ssos 103294454Sjhb cred = td->td_ucred; 103377183Srwatson bsd_gidset = cred->cr_groups; 103477183Srwatson bsd_gidsetsz = cred->cr_ngroups - 1; 103542185Ssos 103650350Smarcel /* 103750350Smarcel * cr_groups[0] holds egid. Returning the whole set 103850350Smarcel * here will cause a duplicate. Exclude cr_groups[0] 103950350Smarcel * to prevent that. 104050350Smarcel */ 104142185Ssos 104283221Smarcel if ((ngrp = args->gidsetsize) == 0) { 104383366Sjulian td->td_retval[0] = bsd_gidsetsz; 104450350Smarcel return (0); 104550350Smarcel } 104642185Ssos 104750546Smarcel if (ngrp < bsd_gidsetsz) 104850350Smarcel return (EINVAL); 104942185Ssos 105050546Smarcel ngrp = 0; 105150350Smarcel while (ngrp < bsd_gidsetsz) { 105250546Smarcel linux_gidset[ngrp] = bsd_gidset[ngrp + 1]; 105350350Smarcel ngrp++; 105450350Smarcel } 105550350Smarcel 105683221Smarcel if ((error = copyout(linux_gidset, (caddr_t)args->grouplist, 105783221Smarcel ngrp * sizeof(l_gid_t)))) 105850350Smarcel return (error); 105950350Smarcel 106083366Sjulian td->td_retval[0] = ngrp; 106150350Smarcel return (0); 106242185Ssos} 106349626Smarcel 106468201Sobrien#ifndef __alpha__ 106549626Smarcelint 106683366Sjulianlinux_setrlimit(struct thread *td, struct linux_setrlimit_args *args) 106749626Smarcel{ 106865099Smarcel struct __setrlimit_args bsd; 106983221Smarcel struct l_rlimit rlim; 107065099Smarcel int error; 107165099Smarcel caddr_t sg = stackgap_init(); 107249842Smarcel 107349626Smarcel#ifdef DEBUG 107472543Sjlemon if (ldebug(setrlimit)) 107572543Sjlemon printf(ARGS(setrlimit, "%d, %p"), 107683221Smarcel args->resource, (void *)args->rlim); 107749626Smarcel#endif 107849626Smarcel 107983221Smarcel if (args->resource >= LINUX_RLIM_NLIMITS) 108065099Smarcel return (EINVAL); 108149626Smarcel 108283221Smarcel bsd.which = linux_to_bsd_resource[args->resource]; 108365099Smarcel if (bsd.which == -1) 108465099Smarcel return (EINVAL); 108549626Smarcel 108683221Smarcel error = copyin((caddr_t)args->rlim, &rlim, sizeof(rlim)); 108765099Smarcel if (error) 108865099Smarcel return (error); 108949626Smarcel 109065099Smarcel bsd.rlp = stackgap_alloc(&sg, sizeof(struct rlimit)); 109165099Smarcel bsd.rlp->rlim_cur = (rlim_t)rlim.rlim_cur; 109265099Smarcel bsd.rlp->rlim_max = (rlim_t)rlim.rlim_max; 109383366Sjulian return (setrlimit(td, &bsd)); 109449626Smarcel} 109549626Smarcel 109649626Smarcelint 109783366Sjulianlinux_old_getrlimit(struct thread *td, struct linux_old_getrlimit_args *args) 109849626Smarcel{ 109965099Smarcel struct __getrlimit_args bsd; 110083221Smarcel struct l_rlimit rlim; 110165099Smarcel int error; 110265099Smarcel caddr_t sg = stackgap_init(); 110349842Smarcel 110449626Smarcel#ifdef DEBUG 110583221Smarcel if (ldebug(old_getrlimit)) 110683221Smarcel printf(ARGS(old_getrlimit, "%d, %p"), 110783221Smarcel args->resource, (void *)args->rlim); 110849626Smarcel#endif 110949626Smarcel 111083221Smarcel if (args->resource >= LINUX_RLIM_NLIMITS) 111165099Smarcel return (EINVAL); 111249626Smarcel 111383221Smarcel bsd.which = linux_to_bsd_resource[args->resource]; 111465099Smarcel if (bsd.which == -1) 111565099Smarcel return (EINVAL); 111649626Smarcel 111765099Smarcel bsd.rlp = stackgap_alloc(&sg, sizeof(struct rlimit)); 111883366Sjulian error = getrlimit(td, &bsd); 111965099Smarcel if (error) 112065099Smarcel return (error); 112149626Smarcel 112265099Smarcel rlim.rlim_cur = (unsigned long)bsd.rlp->rlim_cur; 112365106Smarcel if (rlim.rlim_cur == ULONG_MAX) 112465106Smarcel rlim.rlim_cur = LONG_MAX; 112565099Smarcel rlim.rlim_max = (unsigned long)bsd.rlp->rlim_max; 112665106Smarcel if (rlim.rlim_max == ULONG_MAX) 112765106Smarcel rlim.rlim_max = LONG_MAX; 112883221Smarcel return (copyout(&rlim, (caddr_t)args->rlim, sizeof(rlim))); 112949626Smarcel} 113083221Smarcel 113183221Smarcelint 113283366Sjulianlinux_getrlimit(struct thread *td, struct linux_getrlimit_args *args) 113383221Smarcel{ 113483221Smarcel struct __getrlimit_args bsd; 113583221Smarcel struct l_rlimit rlim; 113683221Smarcel int error; 113783221Smarcel caddr_t sg = stackgap_init(); 113883221Smarcel 113983221Smarcel#ifdef DEBUG 114083221Smarcel if (ldebug(getrlimit)) 114183221Smarcel printf(ARGS(getrlimit, "%d, %p"), 114283221Smarcel args->resource, (void *)args->rlim); 114383221Smarcel#endif 114483221Smarcel 114583221Smarcel if (args->resource >= LINUX_RLIM_NLIMITS) 114683221Smarcel return (EINVAL); 114783221Smarcel 114883221Smarcel bsd.which = linux_to_bsd_resource[args->resource]; 114983221Smarcel if (bsd.which == -1) 115083221Smarcel return (EINVAL); 115183221Smarcel 115283221Smarcel bsd.rlp = stackgap_alloc(&sg, sizeof(struct rlimit)); 115383366Sjulian error = getrlimit(td, &bsd); 115483221Smarcel if (error) 115583221Smarcel return (error); 115683221Smarcel 115783221Smarcel rlim.rlim_cur = (l_ulong)bsd.rlp->rlim_cur; 115883221Smarcel rlim.rlim_max = (l_ulong)bsd.rlp->rlim_max; 115983221Smarcel return (copyout(&rlim, (caddr_t)args->rlim, sizeof(rlim))); 116083221Smarcel} 116168201Sobrien#endif /*!__alpha__*/ 116249849Smarcel 116349849Smarcelint 116483366Sjulianlinux_sched_setscheduler(struct thread *td, 116583221Smarcel struct linux_sched_setscheduler_args *args) 116649849Smarcel{ 116749849Smarcel struct sched_setscheduler_args bsd; 116849849Smarcel 116949849Smarcel#ifdef DEBUG 117072543Sjlemon if (ldebug(sched_setscheduler)) 117172543Sjlemon printf(ARGS(sched_setscheduler, "%d, %d, %p"), 117283221Smarcel args->pid, args->policy, (const void *)args->param); 117349849Smarcel#endif 117449849Smarcel 117583221Smarcel switch (args->policy) { 117649849Smarcel case LINUX_SCHED_OTHER: 117749849Smarcel bsd.policy = SCHED_OTHER; 117849849Smarcel break; 117949849Smarcel case LINUX_SCHED_FIFO: 118049849Smarcel bsd.policy = SCHED_FIFO; 118149849Smarcel break; 118249849Smarcel case LINUX_SCHED_RR: 118349849Smarcel bsd.policy = SCHED_RR; 118449849Smarcel break; 118549849Smarcel default: 118649849Smarcel return EINVAL; 118749849Smarcel } 118849849Smarcel 118983221Smarcel bsd.pid = args->pid; 119083221Smarcel bsd.param = (struct sched_param *)args->param; 119183366Sjulian return sched_setscheduler(td, &bsd); 119249849Smarcel} 119349849Smarcel 119449849Smarcelint 119583366Sjulianlinux_sched_getscheduler(struct thread *td, 119683221Smarcel struct linux_sched_getscheduler_args *args) 119749849Smarcel{ 119849849Smarcel struct sched_getscheduler_args bsd; 119949849Smarcel int error; 120049849Smarcel 120149849Smarcel#ifdef DEBUG 120272543Sjlemon if (ldebug(sched_getscheduler)) 120383221Smarcel printf(ARGS(sched_getscheduler, "%d"), args->pid); 120449849Smarcel#endif 120549849Smarcel 120683221Smarcel bsd.pid = args->pid; 120783366Sjulian error = sched_getscheduler(td, &bsd); 120849849Smarcel 120983366Sjulian switch (td->td_retval[0]) { 121049849Smarcel case SCHED_OTHER: 121183366Sjulian td->td_retval[0] = LINUX_SCHED_OTHER; 121249849Smarcel break; 121349849Smarcel case SCHED_FIFO: 121483366Sjulian td->td_retval[0] = LINUX_SCHED_FIFO; 121549849Smarcel break; 121649849Smarcel case SCHED_RR: 121783366Sjulian td->td_retval[0] = LINUX_SCHED_RR; 121849849Smarcel break; 121949849Smarcel } 122049849Smarcel 122149849Smarcel return error; 122249849Smarcel} 122372538Sjlemon 122475053Salcint 122583366Sjulianlinux_sched_get_priority_max(struct thread *td, 122683221Smarcel struct linux_sched_get_priority_max_args *args) 122775053Salc{ 122875053Salc struct sched_get_priority_max_args bsd; 122975053Salc 123075053Salc#ifdef DEBUG 123175053Salc if (ldebug(sched_get_priority_max)) 123283221Smarcel printf(ARGS(sched_get_priority_max, "%d"), args->policy); 123375053Salc#endif 123475053Salc 123583221Smarcel switch (args->policy) { 123675053Salc case LINUX_SCHED_OTHER: 123775053Salc bsd.policy = SCHED_OTHER; 123875053Salc break; 123975053Salc case LINUX_SCHED_FIFO: 124075053Salc bsd.policy = SCHED_FIFO; 124175053Salc break; 124275053Salc case LINUX_SCHED_RR: 124375053Salc bsd.policy = SCHED_RR; 124475053Salc break; 124575053Salc default: 124675053Salc return EINVAL; 124775053Salc } 124883366Sjulian return sched_get_priority_max(td, &bsd); 124975053Salc} 125075053Salc 125175053Salcint 125283366Sjulianlinux_sched_get_priority_min(struct thread *td, 125383221Smarcel struct linux_sched_get_priority_min_args *args) 125475053Salc{ 125575053Salc struct sched_get_priority_min_args bsd; 125675053Salc 125775053Salc#ifdef DEBUG 125875053Salc if (ldebug(sched_get_priority_min)) 125983221Smarcel printf(ARGS(sched_get_priority_min, "%d"), args->policy); 126075053Salc#endif 126175053Salc 126283221Smarcel switch (args->policy) { 126375053Salc case LINUX_SCHED_OTHER: 126475053Salc bsd.policy = SCHED_OTHER; 126575053Salc break; 126675053Salc case LINUX_SCHED_FIFO: 126775053Salc bsd.policy = SCHED_FIFO; 126875053Salc break; 126975053Salc case LINUX_SCHED_RR: 127075053Salc bsd.policy = SCHED_RR; 127175053Salc break; 127275053Salc default: 127375053Salc return EINVAL; 127475053Salc } 127583366Sjulian return sched_get_priority_min(td, &bsd); 127675053Salc} 127775053Salc 127872538Sjlemon#define REBOOT_CAD_ON 0x89abcdef 127972538Sjlemon#define REBOOT_CAD_OFF 0 128072538Sjlemon#define REBOOT_HALT 0xcdef0123 128172538Sjlemon 128272538Sjlemonint 128383366Sjulianlinux_reboot(struct thread *td, struct linux_reboot_args *args) 128472538Sjlemon{ 128572538Sjlemon struct reboot_args bsd_args; 128672538Sjlemon 128772538Sjlemon#ifdef DEBUG 128872538Sjlemon if (ldebug(reboot)) 128983221Smarcel printf(ARGS(reboot, "0x%x"), args->cmd); 129072538Sjlemon#endif 129183221Smarcel if (args->cmd == REBOOT_CAD_ON || args->cmd == REBOOT_CAD_OFF) 129272538Sjlemon return (0); 129383221Smarcel bsd_args.opt = (args->cmd == REBOOT_HALT) ? RB_HALT : 0; 129483366Sjulian return (reboot(td, &bsd_args)); 129572538Sjlemon} 129683221Smarcel 129789717Sgallatin#ifndef __alpha__ 129889717Sgallatin 129983221Smarcel/* 130083221Smarcel * The FreeBSD native getpid(2), getgid(2) and getuid(2) also modify 130183366Sjulian * td->td_retval[1] when COMPAT_43 or COMPAT_SUNOS is defined. This 130283221Smarcel * globbers registers that are assumed to be preserved. The following 130383221Smarcel * lightweight syscalls fixes this. See also linux_getgid16() and 130483221Smarcel * linux_getuid16() in linux_uid16.c. 130583221Smarcel * 130683221Smarcel * linux_getpid() - MP SAFE 130783221Smarcel * linux_getgid() - MP SAFE 130883221Smarcel * linux_getuid() - MP SAFE 130983221Smarcel */ 131083221Smarcel 131183221Smarcelint 131283366Sjulianlinux_getpid(struct thread *td, struct linux_getpid_args *args) 131383221Smarcel{ 131483366Sjulian 131583366Sjulian td->td_retval[0] = td->td_proc->p_pid; 131683221Smarcel return (0); 131783221Smarcel} 131883221Smarcel 131983221Smarcelint 132083366Sjulianlinux_getgid(struct thread *td, struct linux_getgid_args *args) 132183221Smarcel{ 132283366Sjulian 132394454Sjhb td->td_retval[0] = td->td_ucred->cr_rgid; 132483221Smarcel return (0); 132583221Smarcel} 132683221Smarcel 132783221Smarcelint 132883366Sjulianlinux_getuid(struct thread *td, struct linux_getuid_args *args) 132983221Smarcel{ 133083366Sjulian 133194454Sjhb td->td_retval[0] = td->td_ucred->cr_ruid; 133283221Smarcel return (0); 133383221Smarcel} 133483503Smr 133589717Sgallatin#endif /*!__alpha__*/ 133689717Sgallatin 133783503Smrint 133883503Smrlinux_getsid(struct thread *td, struct linux_getsid_args *args) 133983503Smr{ 134083503Smr struct getsid_args bsd; 134183503Smr bsd.pid = args->pid; 134283503Smr return getsid(td, &bsd); 134383503Smr} 1344