The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/compat/linux/linux_misc.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2002 Doug Rabson
    3  * Copyright (c) 1994-1995 Søren Schmidt
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer
   11  *    in this position and unchanged.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. The name of the author may not be used to endorse or promote products
   16  *    derived from this software without specific prior written permission
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD: releng/5.4/sys/compat/linux/linux_misc.c 144437 2005-03-31 22:17:42Z sobomax $");
   32 
   33 #include "opt_mac.h"
   34 
   35 #include <sys/param.h>
   36 #include <sys/blist.h>
   37 #include <sys/fcntl.h>
   38 #if defined(__i386__) || defined(__alpha__)
   39 #include <sys/imgact_aout.h>
   40 #endif
   41 #include <sys/jail.h>
   42 #include <sys/kernel.h>
   43 #include <sys/limits.h>
   44 #include <sys/lock.h>
   45 #include <sys/mac.h>
   46 #include <sys/malloc.h>
   47 #include <sys/mman.h>
   48 #include <sys/mount.h>
   49 #include <sys/mutex.h>
   50 #include <sys/namei.h>
   51 #include <sys/proc.h>
   52 #include <sys/reboot.h>
   53 #include <sys/resourcevar.h>
   54 #include <sys/signalvar.h>
   55 #include <sys/stat.h>
   56 #include <sys/syscallsubr.h>
   57 #include <sys/sysctl.h>
   58 #include <sys/sysproto.h>
   59 #include <sys/systm.h>
   60 #include <sys/time.h>
   61 #include <sys/vmmeter.h>
   62 #include <sys/vnode.h>
   63 #include <sys/wait.h>
   64 
   65 #include <vm/vm.h>
   66 #include <vm/pmap.h>
   67 #include <vm/vm_kern.h>
   68 #include <vm/vm_map.h>
   69 #include <vm/vm_extern.h>
   70 #include <vm/vm_object.h>
   71 #include <vm/swap_pager.h>
   72 
   73 #include <posix4/sched.h>
   74 
   75 #include "opt_compat.h"
   76 
   77 #include <compat/linux/linux_sysproto.h>
   78 
   79 #ifdef COMPAT_LINUX32
   80 #include <machine/../linux32/linux.h>
   81 #include <machine/../linux32/linux32_proto.h>
   82 #else
   83 #include <machine/../linux/linux.h>
   84 #include <machine/../linux/linux_proto.h>
   85 #endif
   86 
   87 #include <compat/linux/linux_mib.h>
   88 #include <compat/linux/linux_util.h>
   89 
   90 #ifdef __i386__
   91 #include <machine/cputypes.h>
   92 #endif
   93 
   94 #ifdef __alpha__
   95 #define BSD_TO_LINUX_SIGNAL(sig)       (sig)
   96 #else
   97 #define BSD_TO_LINUX_SIGNAL(sig)        \
   98         (((sig) <= LINUX_SIGTBLSZ) ? bsd_to_linux_signal[_SIG_IDX(sig)] : sig)
   99 #endif
  100 
  101 #ifndef __alpha__
  102 static unsigned int linux_to_bsd_resource[LINUX_RLIM_NLIMITS] = {
  103         RLIMIT_CPU, RLIMIT_FSIZE, RLIMIT_DATA, RLIMIT_STACK,
  104         RLIMIT_CORE, RLIMIT_RSS, RLIMIT_NPROC, RLIMIT_NOFILE,
  105         RLIMIT_MEMLOCK, -1
  106 };
  107 #endif /*!__alpha__*/
  108 
  109 struct l_sysinfo {
  110         l_long          uptime;         /* Seconds since boot */
  111         l_ulong         loads[3];       /* 1, 5, and 15 minute load averages */
  112 #define LINUX_SYSINFO_LOADS_SCALE 65536
  113         l_ulong         totalram;       /* Total usable main memory size */
  114         l_ulong         freeram;        /* Available memory size */
  115         l_ulong         sharedram;      /* Amount of shared memory */
  116         l_ulong         bufferram;      /* Memory used by buffers */
  117         l_ulong         totalswap;      /* Total swap space size */
  118         l_ulong         freeswap;       /* swap space still available */
  119         l_ushort        procs;          /* Number of current processes */
  120         l_ulong         totalbig;
  121         l_ulong         freebig;
  122         l_uint          mem_unit;
  123         char            _f[6];          /* Pads structure to 64 bytes */
  124 };
  125 #ifndef __alpha__
  126 int
  127 linux_sysinfo(struct thread *td, struct linux_sysinfo_args *args)
  128 {
  129         struct l_sysinfo sysinfo;
  130         vm_object_t object;
  131         int i, j;
  132         struct timespec ts;
  133 
  134         /* Uptime is copied out of print_uptime() in kern_shutdown.c */
  135         getnanouptime(&ts);
  136         i = 0;
  137         if (ts.tv_sec >= 86400) {
  138                 ts.tv_sec %= 86400;
  139                 i = 1;
  140         }
  141         if (i || ts.tv_sec >= 3600) {
  142                 ts.tv_sec %= 3600;
  143                 i = 1;
  144         }
  145         if (i || ts.tv_sec >= 60) {
  146                 ts.tv_sec %= 60;
  147                 i = 1;
  148         }
  149         sysinfo.uptime=ts.tv_sec;
  150 
  151         /* Use the information from the mib to get our load averages */
  152         for (i = 0; i < 3; i++)
  153                 sysinfo.loads[i] = averunnable.ldavg[i] *
  154                     LINUX_SYSINFO_LOADS_SCALE / averunnable.fscale;
  155 
  156         sysinfo.totalram = physmem * PAGE_SIZE;
  157         sysinfo.freeram = sysinfo.totalram - cnt.v_wire_count * PAGE_SIZE;
  158 
  159         sysinfo.sharedram = 0;
  160         mtx_lock(&vm_object_list_mtx);
  161         TAILQ_FOREACH(object, &vm_object_list, object_list)
  162                 if (object->shadow_count > 1)
  163                         sysinfo.sharedram += object->resident_page_count;
  164         mtx_unlock(&vm_object_list_mtx);
  165 
  166         sysinfo.sharedram *= PAGE_SIZE;
  167         sysinfo.bufferram = 0;
  168 
  169         swap_pager_status(&i, &j);
  170         sysinfo.totalswap= i * PAGE_SIZE;
  171         sysinfo.freeswap = (i - j) * PAGE_SIZE;
  172 
  173         sysinfo.procs = nprocs;
  174 
  175         /* The following are only present in newer Linux kernels. */
  176         sysinfo.totalbig = 0;
  177         sysinfo.freebig = 0;
  178         sysinfo.mem_unit = 1;
  179 
  180         return copyout(&sysinfo, args->info, sizeof(sysinfo));
  181 }
  182 #endif /*!__alpha__*/
  183 
  184 #ifndef __alpha__
  185 int
  186 linux_alarm(struct thread *td, struct linux_alarm_args *args)
  187 {
  188         struct itimerval it, old_it;
  189         struct timeval tv;
  190         struct proc *p;
  191 
  192 #ifdef DEBUG
  193         if (ldebug(alarm))
  194                 printf(ARGS(alarm, "%u"), args->secs);
  195 #endif
  196 
  197         if (args->secs > 100000000)
  198                 return EINVAL;
  199 
  200         it.it_value.tv_sec = (long)args->secs;
  201         it.it_value.tv_usec = 0;
  202         it.it_interval.tv_sec = 0;
  203         it.it_interval.tv_usec = 0;
  204         p = td->td_proc;
  205         PROC_LOCK(p);
  206         old_it = p->p_realtimer;
  207         getmicrouptime(&tv);
  208         if (timevalisset(&old_it.it_value))
  209                 callout_stop(&p->p_itcallout);
  210         if (it.it_value.tv_sec != 0) {
  211                 callout_reset(&p->p_itcallout, tvtohz(&it.it_value),
  212                     realitexpire, p);
  213                 timevaladd(&it.it_value, &tv);
  214         }
  215         p->p_realtimer = it;
  216         PROC_UNLOCK(p);
  217         if (timevalcmp(&old_it.it_value, &tv, >)) {
  218                 timevalsub(&old_it.it_value, &tv);
  219                 if (old_it.it_value.tv_usec != 0)
  220                         old_it.it_value.tv_sec++;
  221                 td->td_retval[0] = old_it.it_value.tv_sec;
  222         }
  223         return 0;
  224 }
  225 #endif /*!__alpha__*/
  226 
  227 int
  228 linux_brk(struct thread *td, struct linux_brk_args *args)
  229 {
  230         struct vmspace *vm = td->td_proc->p_vmspace;
  231         vm_offset_t new, old;
  232         struct obreak_args /* {
  233                 char * nsize;
  234         } */ tmp;
  235 
  236 #ifdef DEBUG
  237         if (ldebug(brk))
  238                 printf(ARGS(brk, "%p"), (void *)(uintptr_t)args->dsend);
  239 #endif
  240         old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize);
  241         new = (vm_offset_t)args->dsend;
  242         tmp.nsize = (char *) new;
  243         if (((caddr_t)new > vm->vm_daddr) && !obreak(td, &tmp))
  244                 td->td_retval[0] = (long)new;
  245         else
  246                 td->td_retval[0] = (long)old;
  247 
  248         return 0;
  249 }
  250 
  251 #if defined(__i386__) || defined(__alpha__)
  252 
  253 int
  254 linux_uselib(struct thread *td, struct linux_uselib_args *args)
  255 {
  256         struct nameidata ni;
  257         struct vnode *vp;
  258         struct exec *a_out;
  259         struct vattr attr;
  260         vm_offset_t vmaddr;
  261         unsigned long file_offset;
  262         vm_offset_t buffer;
  263         unsigned long bss_size;
  264         char *library;
  265         int error;
  266         int locked;
  267 
  268         LCONVPATHEXIST(td, args->library, &library);
  269 
  270 #ifdef DEBUG
  271         if (ldebug(uselib))
  272                 printf(ARGS(uselib, "%s"), library);
  273 #endif
  274 
  275         a_out = NULL;
  276         locked = 0;
  277         vp = NULL;
  278 
  279         /*
  280          * XXX: This code should make use of vn_open(), rather than doing
  281          * all this stuff itself.
  282          */
  283         NDINIT(&ni, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, library, td);
  284         error = namei(&ni);
  285         LFREEPATH(library);
  286         if (error)
  287                 goto cleanup;
  288 
  289         vp = ni.ni_vp;
  290         /*
  291          * XXX - This looks like a bogus check. A LOCKLEAF namei should not
  292          * succeed without returning a vnode.
  293          */
  294         if (vp == NULL) {
  295                 error = ENOEXEC;        /* ?? */
  296                 goto cleanup;
  297         }
  298         NDFREE(&ni, NDF_ONLY_PNBUF);
  299 
  300         /*
  301          * From here on down, we have a locked vnode that must be unlocked.
  302          */
  303         locked++;
  304 
  305         /* Writable? */
  306         if (vp->v_writecount) {
  307                 error = ETXTBSY;
  308                 goto cleanup;
  309         }
  310 
  311         /* Executable? */
  312         error = VOP_GETATTR(vp, &attr, td->td_ucred, td);
  313         if (error)
  314                 goto cleanup;
  315 
  316         if ((vp->v_mount->mnt_flag & MNT_NOEXEC) ||
  317             ((attr.va_mode & 0111) == 0) || (attr.va_type != VREG)) {
  318                 error = ENOEXEC;
  319                 goto cleanup;
  320         }
  321 
  322         /* Sensible size? */
  323         if (attr.va_size == 0) {
  324                 error = ENOEXEC;
  325                 goto cleanup;
  326         }
  327 
  328         /* Can we access it? */
  329         error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td);
  330         if (error)
  331                 goto cleanup;
  332 
  333         /*
  334          * XXX: This should use vn_open() so that it is properly authorized,
  335          * and to reduce code redundancy all over the place here.
  336          */
  337 #ifdef MAC
  338         error = mac_check_vnode_open(td->td_ucred, vp, FREAD);
  339         if (error)
  340                 goto cleanup;
  341 #endif
  342         error = VOP_OPEN(vp, FREAD, td->td_ucred, td, -1);
  343         if (error)
  344                 goto cleanup;
  345 
  346         /* Pull in executable header into kernel_map */
  347         error = vm_mmap(kernel_map, (vm_offset_t *)&a_out, PAGE_SIZE,
  348             VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp, 0);
  349         /*
  350          * Lock no longer needed
  351          */
  352         locked = 0;
  353         VOP_UNLOCK(vp, 0, td);
  354 
  355         if (error)
  356                 goto cleanup;
  357 
  358         /* Is it a Linux binary ? */
  359         if (((a_out->a_magic >> 16) & 0xff) != 0x64) {
  360                 error = ENOEXEC;
  361                 goto cleanup;
  362         }
  363 
  364         /*
  365          * While we are here, we should REALLY do some more checks
  366          */
  367 
  368         /* Set file/virtual offset based on a.out variant. */
  369         switch ((int)(a_out->a_magic & 0xffff)) {
  370         case 0413:      /* ZMAGIC */
  371                 file_offset = 1024;
  372                 break;
  373         case 0314:      /* QMAGIC */
  374                 file_offset = 0;
  375                 break;
  376         default:
  377                 error = ENOEXEC;
  378                 goto cleanup;
  379         }
  380 
  381         bss_size = round_page(a_out->a_bss);
  382 
  383         /* Check various fields in header for validity/bounds. */
  384         if (a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) {
  385                 error = ENOEXEC;
  386                 goto cleanup;
  387         }
  388 
  389         /* text + data can't exceed file size */
  390         if (a_out->a_data + a_out->a_text > attr.va_size) {
  391                 error = EFAULT;
  392                 goto cleanup;
  393         }
  394 
  395         /*
  396          * text/data/bss must not exceed limits
  397          * XXX - this is not complete. it should check current usage PLUS
  398          * the resources needed by this library.
  399          */
  400         PROC_LOCK(td->td_proc);
  401         if (a_out->a_text > maxtsiz ||
  402             a_out->a_data + bss_size > lim_cur(td->td_proc, RLIMIT_DATA)) {
  403                 PROC_UNLOCK(td->td_proc);
  404                 error = ENOMEM;
  405                 goto cleanup;
  406         }
  407         PROC_UNLOCK(td->td_proc);
  408 
  409         mp_fixme("Unlocked vflags access.");
  410         /* prevent more writers */
  411         vp->v_vflag |= VV_TEXT;
  412 
  413         /*
  414          * Check if file_offset page aligned. Currently we cannot handle
  415          * misalinged file offsets, and so we read in the entire image
  416          * (what a waste).
  417          */
  418         if (file_offset & PAGE_MASK) {
  419 #ifdef DEBUG
  420                 printf("uselib: Non page aligned binary %lu\n", file_offset);
  421 #endif
  422                 /* Map text+data read/write/execute */
  423 
  424                 /* a_entry is the load address and is page aligned */
  425                 vmaddr = trunc_page(a_out->a_entry);
  426 
  427                 /* get anon user mapping, read+write+execute */
  428                 error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0,
  429                     &vmaddr, a_out->a_text + a_out->a_data, FALSE, VM_PROT_ALL,
  430                     VM_PROT_ALL, 0);
  431                 if (error)
  432                         goto cleanup;
  433 
  434                 /* map file into kernel_map */
  435                 error = vm_mmap(kernel_map, &buffer,
  436                     round_page(a_out->a_text + a_out->a_data + file_offset),
  437                     VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp,
  438                     trunc_page(file_offset));
  439                 if (error)
  440                         goto cleanup;
  441 
  442                 /* copy from kernel VM space to user space */
  443                 error = copyout(PTRIN(buffer + file_offset),
  444                     (void *)vmaddr, a_out->a_text + a_out->a_data);
  445 
  446                 /* release temporary kernel space */
  447                 vm_map_remove(kernel_map, buffer, buffer +
  448                     round_page(a_out->a_text + a_out->a_data + file_offset));
  449 
  450                 if (error)
  451                         goto cleanup;
  452         } else {
  453 #ifdef DEBUG
  454                 printf("uselib: Page aligned binary %lu\n", file_offset);
  455 #endif
  456                 /*
  457                  * for QMAGIC, a_entry is 20 bytes beyond the load address
  458                  * to skip the executable header
  459                  */
  460                 vmaddr = trunc_page(a_out->a_entry);
  461 
  462                 /*
  463                  * Map it all into the process's space as a single
  464                  * copy-on-write "data" segment.
  465                  */
  466                 error = vm_mmap(&td->td_proc->p_vmspace->vm_map, &vmaddr,
  467                     a_out->a_text + a_out->a_data, VM_PROT_ALL, VM_PROT_ALL,
  468                     MAP_PRIVATE | MAP_FIXED, (caddr_t)vp, file_offset);
  469                 if (error)
  470                         goto cleanup;
  471         }
  472 #ifdef DEBUG
  473         printf("mem=%08lx = %08lx %08lx\n", (long)vmaddr, ((long*)vmaddr)[0],
  474             ((long*)vmaddr)[1]);
  475 #endif
  476         if (bss_size != 0) {
  477                 /* Calculate BSS start address */
  478                 vmaddr = trunc_page(a_out->a_entry) + a_out->a_text +
  479                     a_out->a_data;
  480 
  481                 /* allocate some 'anon' space */
  482                 error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0,
  483                     &vmaddr, bss_size, FALSE, VM_PROT_ALL, VM_PROT_ALL, 0);
  484                 if (error)
  485                         goto cleanup;
  486         }
  487 
  488 cleanup:
  489         /* Unlock vnode if needed */
  490         if (locked)
  491                 VOP_UNLOCK(vp, 0, td);
  492 
  493         /* Release the kernel mapping. */
  494         if (a_out)
  495                 vm_map_remove(kernel_map, (vm_offset_t)a_out,
  496                     (vm_offset_t)a_out + PAGE_SIZE);
  497 
  498         return error;
  499 }
  500 
  501 #endif  /* __i386__ || __alpha__ */
  502 
  503 int
  504 linux_select(struct thread *td, struct linux_select_args *args)
  505 {
  506         l_timeval ltv;
  507         struct timeval tv0, tv1, utv, *tvp;
  508         int error;
  509 
  510 #ifdef DEBUG
  511         if (ldebug(select))
  512                 printf(ARGS(select, "%d, %p, %p, %p, %p"), args->nfds,
  513                     (void *)args->readfds, (void *)args->writefds,
  514                     (void *)args->exceptfds, (void *)args->timeout);
  515 #endif
  516 
  517         /*
  518          * Store current time for computation of the amount of
  519          * time left.
  520          */
  521         if (args->timeout) {
  522                 if ((error = copyin(args->timeout, &ltv, sizeof(ltv))))
  523                         goto select_out;
  524                 utv.tv_sec = ltv.tv_sec;
  525                 utv.tv_usec = ltv.tv_usec;
  526 #ifdef DEBUG
  527                 if (ldebug(select))
  528                         printf(LMSG("incoming timeout (%ld/%ld)"),
  529                             utv.tv_sec, utv.tv_usec);
  530 #endif
  531 
  532                 if (itimerfix(&utv)) {
  533                         /*
  534                          * The timeval was invalid.  Convert it to something
  535                          * valid that will act as it does under Linux.
  536                          */
  537                         utv.tv_sec += utv.tv_usec / 1000000;
  538                         utv.tv_usec %= 1000000;
  539                         if (utv.tv_usec < 0) {
  540                                 utv.tv_sec -= 1;
  541                                 utv.tv_usec += 1000000;
  542                         }
  543                         if (utv.tv_sec < 0)
  544                                 timevalclear(&utv);
  545                 }
  546                 microtime(&tv0);
  547                 tvp = &utv;
  548         } else
  549                 tvp = NULL;
  550 
  551         error = kern_select(td, args->nfds, args->readfds, args->writefds,
  552             args->exceptfds, tvp);
  553 
  554 #ifdef DEBUG
  555         if (ldebug(select))
  556                 printf(LMSG("real select returns %d"), error);
  557 #endif
  558         if (error) {
  559                 /*
  560                  * See fs/select.c in the Linux kernel.  Without this,
  561                  * Maelstrom doesn't work.
  562                  */
  563                 if (error == ERESTART)
  564                         error = EINTR;
  565                 goto select_out;
  566         }
  567 
  568         if (args->timeout) {
  569                 if (td->td_retval[0]) {
  570                         /*
  571                          * Compute how much time was left of the timeout,
  572                          * by subtracting the current time and the time
  573                          * before we started the call, and subtracting
  574                          * that result from the user-supplied value.
  575                          */
  576                         microtime(&tv1);
  577                         timevalsub(&tv1, &tv0);
  578                         timevalsub(&utv, &tv1);
  579                         if (utv.tv_sec < 0)
  580                                 timevalclear(&utv);
  581                 } else
  582                         timevalclear(&utv);
  583 #ifdef DEBUG
  584                 if (ldebug(select))
  585                         printf(LMSG("outgoing timeout (%ld/%ld)"),
  586                             utv.tv_sec, utv.tv_usec);
  587 #endif
  588                 ltv.tv_sec = utv.tv_sec;
  589                 ltv.tv_usec = utv.tv_usec;
  590                 if ((error = copyout(&ltv, args->timeout, sizeof(ltv))))
  591                         goto select_out;
  592         }
  593 
  594 select_out:
  595 #ifdef DEBUG
  596         if (ldebug(select))
  597                 printf(LMSG("select_out -> %d"), error);
  598 #endif
  599         return error;
  600 }
  601 
  602 int
  603 linux_mremap(struct thread *td, struct linux_mremap_args *args)
  604 {
  605         struct munmap_args /* {
  606                 void *addr;
  607                 size_t len;
  608         } */ bsd_args;
  609         int error = 0;
  610 
  611 #ifdef DEBUG
  612         if (ldebug(mremap))
  613                 printf(ARGS(mremap, "%p, %08lx, %08lx, %08lx"),
  614                     (void *)(uintptr_t)args->addr,
  615                     (unsigned long)args->old_len,
  616                     (unsigned long)args->new_len,
  617                     (unsigned long)args->flags);
  618 #endif
  619         args->new_len = round_page(args->new_len);
  620         args->old_len = round_page(args->old_len);
  621 
  622         if (args->new_len > args->old_len) {
  623                 td->td_retval[0] = 0;
  624                 return ENOMEM;
  625         }
  626 
  627         if (args->new_len < args->old_len) {
  628                 bsd_args.addr =
  629                     (caddr_t)((uintptr_t)args->addr + args->new_len);
  630                 bsd_args.len = args->old_len - args->new_len;
  631                 error = munmap(td, &bsd_args);
  632         }
  633 
  634         td->td_retval[0] = error ? 0 : (uintptr_t)args->addr;
  635         return error;
  636 }
  637 
  638 #define LINUX_MS_ASYNC       0x0001
  639 #define LINUX_MS_INVALIDATE  0x0002
  640 #define LINUX_MS_SYNC        0x0004
  641 
  642 int
  643 linux_msync(struct thread *td, struct linux_msync_args *args)
  644 {
  645         struct msync_args bsd_args;
  646 
  647         bsd_args.addr = (caddr_t)(uintptr_t)args->addr;
  648         bsd_args.len = (uintptr_t)args->len;
  649         bsd_args.flags = args->fl & ~LINUX_MS_SYNC;
  650 
  651         return msync(td, &bsd_args);
  652 }
  653 
  654 #ifndef __alpha__
  655 int
  656 linux_time(struct thread *td, struct linux_time_args *args)
  657 {
  658         struct timeval tv;
  659         l_time_t tm;
  660         int error;
  661 
  662 #ifdef DEBUG
  663         if (ldebug(time))
  664                 printf(ARGS(time, "*"));
  665 #endif
  666 
  667         microtime(&tv);
  668         tm = tv.tv_sec;
  669         if (args->tm && (error = copyout(&tm, args->tm, sizeof(tm))))
  670                 return error;
  671         td->td_retval[0] = tm;
  672         return 0;
  673 }
  674 #endif  /*!__alpha__*/
  675 
  676 struct l_times_argv {
  677         l_long          tms_utime;
  678         l_long          tms_stime;
  679         l_long          tms_cutime;
  680         l_long          tms_cstime;
  681 };
  682 
  683 #ifdef __alpha__
  684 #define CLK_TCK 1024    /* Linux uses 1024 on alpha */
  685 #else
  686 #define CLK_TCK 100     /* Linux uses 100 */
  687 #endif
  688 
  689 #define CONVTCK(r)      (r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK))
  690 
  691 int
  692 linux_times(struct thread *td, struct linux_times_args *args)
  693 {
  694         struct timeval tv;
  695         struct l_times_argv tms;
  696         struct rusage ru;
  697         int error;
  698 
  699 #ifdef DEBUG
  700         if (ldebug(times))
  701                 printf(ARGS(times, "*"));
  702 #endif
  703 
  704         mtx_lock_spin(&sched_lock);
  705         calcru(td->td_proc, &ru.ru_utime, &ru.ru_stime, NULL);
  706         mtx_unlock_spin(&sched_lock);
  707 
  708         tms.tms_utime = CONVTCK(ru.ru_utime);
  709         tms.tms_stime = CONVTCK(ru.ru_stime);
  710 
  711         tms.tms_cutime = CONVTCK(td->td_proc->p_stats->p_cru.ru_utime);
  712         tms.tms_cstime = CONVTCK(td->td_proc->p_stats->p_cru.ru_stime);
  713 
  714         if ((error = copyout(&tms, args->buf, sizeof(tms))))
  715                 return error;
  716 
  717         microuptime(&tv);
  718         td->td_retval[0] = (int)CONVTCK(tv);
  719         return 0;
  720 }
  721 
  722 int
  723 linux_newuname(struct thread *td, struct linux_newuname_args *args)
  724 {
  725         struct l_new_utsname utsname;
  726         char osname[LINUX_MAX_UTSNAME];
  727         char osrelease[LINUX_MAX_UTSNAME];
  728         char *p;
  729 
  730 #ifdef DEBUG
  731         if (ldebug(newuname))
  732                 printf(ARGS(newuname, "*"));
  733 #endif
  734 
  735         linux_get_osname(td, osname);
  736         linux_get_osrelease(td, osrelease);
  737 
  738         bzero(&utsname, sizeof(utsname));
  739         strlcpy(utsname.sysname, osname, LINUX_MAX_UTSNAME);
  740         getcredhostname(td->td_ucred, utsname.nodename, LINUX_MAX_UTSNAME);
  741         strlcpy(utsname.release, osrelease, LINUX_MAX_UTSNAME);
  742         strlcpy(utsname.version, version, LINUX_MAX_UTSNAME);
  743         for (p = utsname.version; *p != '\0'; ++p)
  744                 if (*p == '\n') {
  745                         *p = '\0';
  746                         break;
  747                 }
  748 #ifdef __i386__
  749         {
  750                 const char *class;
  751                 switch (cpu_class) {
  752                 case CPUCLASS_686:
  753                         class = "i686";
  754                         break;
  755                 case CPUCLASS_586:
  756                         class = "i586";
  757                         break;
  758                 case CPUCLASS_486:
  759                         class = "i486";
  760                         break;
  761                 default:
  762                         class = "i386";
  763                 }
  764                 strlcpy(utsname.machine, class, LINUX_MAX_UTSNAME);
  765         }
  766 #elif defined(__amd64__)        /* XXX: Linux can change 'personality'. */
  767 #ifdef COMPAT_LINUX32
  768         strlcpy(utsname.machine, "i686", LINUX_MAX_UTSNAME);
  769 #else
  770         strlcpy(utsname.machine, "x86_64", LINUX_MAX_UTSNAME);
  771 #endif /* COMPAT_LINUX32 */
  772 #else /* something other than i386 or amd64 - assume we and Linux agree */
  773         strlcpy(utsname.machine, machine, LINUX_MAX_UTSNAME);
  774 #endif /* __i386__ */
  775         strlcpy(utsname.domainname, domainname, LINUX_MAX_UTSNAME);
  776 
  777         return (copyout(&utsname, args->buf, sizeof(utsname)));
  778 }
  779 
  780 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
  781 struct l_utimbuf {
  782         l_time_t l_actime;
  783         l_time_t l_modtime;
  784 };
  785 
  786 int
  787 linux_utime(struct thread *td, struct linux_utime_args *args)
  788 {
  789         struct timeval tv[2], *tvp;
  790         struct l_utimbuf lut;
  791         char *fname;
  792         int error;
  793 
  794         LCONVPATHEXIST(td, args->fname, &fname);
  795 
  796 #ifdef DEBUG
  797         if (ldebug(utime))
  798                 printf(ARGS(utime, "%s, *"), fname);
  799 #endif
  800 
  801         if (args->times) {
  802                 if ((error = copyin(args->times, &lut, sizeof lut))) {
  803                         LFREEPATH(fname);
  804                         return error;
  805                 }
  806                 tv[0].tv_sec = lut.l_actime;
  807                 tv[0].tv_usec = 0;
  808                 tv[1].tv_sec = lut.l_modtime;
  809                 tv[1].tv_usec = 0;
  810                 tvp = tv;
  811         } else
  812                 tvp = NULL;
  813 
  814         error = kern_utimes(td, fname, UIO_SYSSPACE, tvp, UIO_SYSSPACE);
  815         LFREEPATH(fname);
  816         return (error);
  817 }
  818 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
  819 
  820 #define __WCLONE 0x80000000
  821 
  822 #ifndef __alpha__
  823 int
  824 linux_waitpid(struct thread *td, struct linux_waitpid_args *args)
  825 {
  826         int error, options, tmpstat;
  827 
  828 #ifdef DEBUG
  829         if (ldebug(waitpid))
  830                 printf(ARGS(waitpid, "%d, %p, %d"),
  831                     args->pid, (void *)args->status, args->options);
  832 #endif
  833 
  834         options = (args->options & (WNOHANG | WUNTRACED));
  835         /* WLINUXCLONE should be equal to __WCLONE, but we make sure */
  836         if (args->options & __WCLONE)
  837                 options |= WLINUXCLONE;
  838 
  839         error = kern_wait(td, args->pid, &tmpstat, options, NULL);
  840         if (error)
  841                 return error;
  842 
  843         if (args->status) {
  844                 tmpstat &= 0xffff;
  845                 if (WIFSIGNALED(tmpstat))
  846                         tmpstat = (tmpstat & 0xffffff80) |
  847                             BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat));
  848                 else if (WIFSTOPPED(tmpstat))
  849                         tmpstat = (tmpstat & 0xffff00ff) |
  850                             (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8);
  851                 return copyout(&tmpstat, args->status, sizeof(int));
  852         }
  853 
  854         return 0;
  855 }
  856 #endif  /*!__alpha__*/
  857 
  858 int
  859 linux_wait4(struct thread *td, struct linux_wait4_args *args)
  860 {
  861         int error, options, tmpstat;
  862         struct rusage ru;
  863         struct proc *p;
  864 
  865 #ifdef DEBUG
  866         if (ldebug(wait4))
  867                 printf(ARGS(wait4, "%d, %p, %d, %p"),
  868                     args->pid, (void *)args->status, args->options,
  869                     (void *)args->rusage);
  870 #endif
  871 
  872         options = (args->options & (WNOHANG | WUNTRACED));
  873         /* WLINUXCLONE should be equal to __WCLONE, but we make sure */
  874         if (args->options & __WCLONE)
  875                 options |= WLINUXCLONE;
  876 
  877         error = kern_wait(td, args->pid, &tmpstat, options, &ru);
  878         if (error)
  879                 return error;
  880 
  881         p = td->td_proc;
  882         PROC_LOCK(p);
  883         SIGDELSET(p->p_siglist, SIGCHLD);
  884         PROC_UNLOCK(p);
  885 
  886         if (args->status) {
  887                 tmpstat &= 0xffff;
  888                 if (WIFSIGNALED(tmpstat))
  889                         tmpstat = (tmpstat & 0xffffff80) |
  890                             BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat));
  891                 else if (WIFSTOPPED(tmpstat))
  892                         tmpstat = (tmpstat & 0xffff00ff) |
  893                             (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8);
  894                 error = copyout(&tmpstat, args->status, sizeof(int));
  895         }
  896         if (args->rusage != NULL && error == 0)
  897                 error = copyout(&ru, args->rusage, sizeof(ru));
  898 
  899         return (error);
  900 }
  901 
  902 int
  903 linux_mknod(struct thread *td, struct linux_mknod_args *args)
  904 {
  905         char *path;
  906         int error;
  907 
  908         LCONVPATHCREAT(td, args->path, &path);
  909 
  910 #ifdef DEBUG
  911         if (ldebug(mknod))
  912                 printf(ARGS(mknod, "%s, %d, %d"), path, args->mode, args->dev);
  913 #endif
  914 
  915         if (args->mode & S_IFIFO)
  916                 error = kern_mkfifo(td, path, UIO_SYSSPACE, args->mode);
  917         else
  918                 error = kern_mknod(td, path, UIO_SYSSPACE, args->mode,
  919                     args->dev);
  920         LFREEPATH(path);
  921         return (error);
  922 }
  923 
  924 /*
  925  * UGH! This is just about the dumbest idea I've ever heard!!
  926  */
  927 int
  928 linux_personality(struct thread *td, struct linux_personality_args *args)
  929 {
  930 #ifdef DEBUG
  931         if (ldebug(personality))
  932                 printf(ARGS(personality, "%lu"), (unsigned long)args->per);
  933 #endif
  934 #ifndef __alpha__
  935         if (args->per != 0)
  936                 return EINVAL;
  937 #endif
  938 
  939         /* Yes Jim, it's still a Linux... */
  940         td->td_retval[0] = 0;
  941         return 0;
  942 }
  943 
  944 struct l_itimerval {
  945         l_timeval it_interval;
  946         l_timeval it_value;
  947 };
  948 
  949 int
  950 linux_setitimer(struct thread *td, struct linux_setitimer_args *uap)
  951 {
  952         int error;
  953         caddr_t sg;
  954         struct l_itimerval *lp, *lop, ls;
  955         struct itimerval *p = NULL, *op = NULL, s;
  956 
  957 #ifdef DEBUG
  958         if (ldebug(setitimer))
  959                 printf(ARGS(setitimer, "%p, %p"),
  960                     (void *)uap->itv, (void *)uap->oitv);
  961 #endif
  962         lp = uap->itv;
  963         if (lp != NULL) {
  964                 sg = stackgap_init();
  965                 p = stackgap_alloc(&sg, sizeof(struct itimerval));
  966                 uap->itv = (struct l_itimerval *)p;
  967                 error = copyin(lp, &ls, sizeof(ls));
  968                 if (error != 0)
  969                         return (error);
  970                 s.it_interval.tv_sec = ls.it_interval.tv_sec;
  971                 s.it_interval.tv_usec = ls.it_interval.tv_usec;
  972                 s.it_value.tv_sec = ls.it_value.tv_sec;
  973                 s.it_value.tv_usec = ls.it_value.tv_usec;
  974                 error = copyout(&s, p, sizeof(s));
  975                 if (error != 0)
  976                         return (error);
  977 #ifdef DEBUG
  978                 if (ldebug(setitimer)) {
  979                         printf("setitimer: value: sec: %ld, usec: %ld\n",
  980                             s.it_value.tv_sec, s.it_value.tv_usec);
  981                         printf("setitimer: interval: sec: %ld, usec: %ld\n",
  982                             s.it_interval.tv_sec, s.it_interval.tv_usec);
  983                 }
  984 #endif
  985         }
  986         lop = uap->oitv;
  987         if (lop != NULL) {
  988                 sg = stackgap_init();
  989                 op = stackgap_alloc(&sg, sizeof(struct itimerval));
  990                 uap->oitv = (struct l_itimerval *)op;
  991         }
  992         error = setitimer(td, (struct setitimer_args *) uap);
  993         if (error != 0)
  994                 return (error);
  995         if (lop != NULL) {
  996                 error = copyin(op, &s, sizeof(s));
  997                 if (error != 0)
  998                         return (error);
  999                 ls.it_interval.tv_sec = s.it_interval.tv_sec;
 1000                 ls.it_interval.tv_usec = s.it_interval.tv_usec;
 1001                 ls.it_value.tv_sec = s.it_value.tv_sec;
 1002                 ls.it_value.tv_usec = s.it_value.tv_usec;
 1003                 error = copyout(&ls, lop, sizeof(ls));
 1004         }
 1005         return (error);
 1006 }
 1007 
 1008 int
 1009 linux_getitimer(struct thread *td, struct linux_getitimer_args *uap)
 1010 {
 1011         int error;
 1012         caddr_t sg;
 1013         struct l_itimerval *lp, ls;
 1014         struct itimerval *p = NULL, s;
 1015 
 1016 #ifdef DEBUG
 1017         if (ldebug(getitimer))
 1018                 printf(ARGS(getitimer, "%p"), (void *)uap->itv);
 1019 #endif
 1020         lp = uap->itv;
 1021         if (lp != NULL) {
 1022                 sg = stackgap_init();
 1023                 p = stackgap_alloc(&sg, sizeof(struct itimerval));
 1024                 uap->itv = (struct l_itimerval *)p;
 1025         }
 1026         error = getitimer(td, (struct getitimer_args *) uap);
 1027         if (error != 0)
 1028                 return (error);
 1029         if (lp != NULL) {
 1030                 error = copyin(p, &s, sizeof(s));
 1031                 if (error != 0)
 1032                         return (error);
 1033                 ls.it_interval.tv_sec = s.it_interval.tv_sec;
 1034                 ls.it_interval.tv_usec = s.it_interval.tv_usec;
 1035                 ls.it_value.tv_sec = s.it_value.tv_sec;
 1036                 ls.it_value.tv_usec = s.it_value.tv_usec;
 1037                 error = copyout(&ls, lp, sizeof(ls));
 1038         }
 1039         return (error);
 1040 }
 1041 
 1042 #ifndef __alpha__
 1043 int
 1044 linux_nice(struct thread *td, struct linux_nice_args *args)
 1045 {
 1046         struct setpriority_args bsd_args;
 1047 
 1048         bsd_args.which = PRIO_PROCESS;
 1049         bsd_args.who = 0;       /* current process */
 1050         bsd_args.prio = args->inc;
 1051         return setpriority(td, &bsd_args);
 1052 }
 1053 #endif  /*!__alpha__*/
 1054 
 1055 int
 1056 linux_setgroups(struct thread *td, struct linux_setgroups_args *args)
 1057 {
 1058         struct ucred *newcred, *oldcred;
 1059         l_gid_t linux_gidset[NGROUPS];
 1060         gid_t *bsd_gidset;
 1061         int ngrp, error;
 1062         struct proc *p;
 1063 
 1064         ngrp = args->gidsetsize;
 1065         if (ngrp < 0 || ngrp >= NGROUPS)
 1066                 return (EINVAL);
 1067         error = copyin(args->grouplist, linux_gidset, ngrp * sizeof(l_gid_t));
 1068         if (error)
 1069                 return (error);
 1070         newcred = crget();
 1071         p = td->td_proc;
 1072         PROC_LOCK(p);
 1073         oldcred = p->p_ucred;
 1074 
 1075         /*
 1076          * cr_groups[0] holds egid. Setting the whole set from
 1077          * the supplied set will cause egid to be changed too.
 1078          * Keep cr_groups[0] unchanged to prevent that.
 1079          */
 1080 
 1081         if ((error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0) {
 1082                 PROC_UNLOCK(p);
 1083                 crfree(newcred);
 1084                 return (error);
 1085         }
 1086 
 1087         crcopy(newcred, oldcred);
 1088         if (ngrp > 0) {
 1089                 newcred->cr_ngroups = ngrp + 1;
 1090 
 1091                 bsd_gidset = newcred->cr_groups;
 1092                 ngrp--;
 1093                 while (ngrp >= 0) {
 1094                         bsd_gidset[ngrp + 1] = linux_gidset[ngrp];
 1095                         ngrp--;
 1096                 }
 1097         }
 1098         else
 1099                 newcred->cr_ngroups = 1;
 1100 
 1101         setsugid(p);
 1102         p->p_ucred = newcred;
 1103         PROC_UNLOCK(p);
 1104         crfree(oldcred);
 1105         return (0);
 1106 }
 1107 
 1108 int
 1109 linux_getgroups(struct thread *td, struct linux_getgroups_args *args)
 1110 {
 1111         struct ucred *cred;
 1112         l_gid_t linux_gidset[NGROUPS];
 1113         gid_t *bsd_gidset;
 1114         int bsd_gidsetsz, ngrp, error;
 1115 
 1116         cred = td->td_ucred;
 1117         bsd_gidset = cred->cr_groups;
 1118         bsd_gidsetsz = cred->cr_ngroups - 1;
 1119 
 1120         /*
 1121          * cr_groups[0] holds egid. Returning the whole set
 1122          * here will cause a duplicate. Exclude cr_groups[0]
 1123          * to prevent that.
 1124          */
 1125 
 1126         if ((ngrp = args->gidsetsize) == 0) {
 1127                 td->td_retval[0] = bsd_gidsetsz;
 1128                 return (0);
 1129         }
 1130 
 1131         if (ngrp < bsd_gidsetsz)
 1132                 return (EINVAL);
 1133 
 1134         ngrp = 0;
 1135         while (ngrp < bsd_gidsetsz) {
 1136                 linux_gidset[ngrp] = bsd_gidset[ngrp + 1];
 1137                 ngrp++;
 1138         }
 1139 
 1140         if ((error = copyout(linux_gidset, args->grouplist,
 1141             ngrp * sizeof(l_gid_t))))
 1142                 return (error);
 1143 
 1144         td->td_retval[0] = ngrp;
 1145         return (0);
 1146 }
 1147 
 1148 #ifndef __alpha__
 1149 int
 1150 linux_setrlimit(struct thread *td, struct linux_setrlimit_args *args)
 1151 {
 1152         struct rlimit bsd_rlim;
 1153         struct l_rlimit rlim;
 1154         u_int which;
 1155         int error;
 1156 
 1157 #ifdef DEBUG
 1158         if (ldebug(setrlimit))
 1159                 printf(ARGS(setrlimit, "%d, %p"),
 1160                     args->resource, (void *)args->rlim);
 1161 #endif
 1162 
 1163         if (args->resource >= LINUX_RLIM_NLIMITS)
 1164                 return (EINVAL);
 1165 
 1166         which = linux_to_bsd_resource[args->resource];
 1167         if (which == -1)
 1168                 return (EINVAL);
 1169 
 1170         error = copyin(args->rlim, &rlim, sizeof(rlim));
 1171         if (error)
 1172                 return (error);
 1173 
 1174         bsd_rlim.rlim_cur = (rlim_t)rlim.rlim_cur;
 1175         bsd_rlim.rlim_max = (rlim_t)rlim.rlim_max;
 1176         return (kern_setrlimit(td, which, &bsd_rlim));
 1177 }
 1178 
 1179 int
 1180 linux_old_getrlimit(struct thread *td, struct linux_old_getrlimit_args *args)
 1181 {
 1182         struct l_rlimit rlim;
 1183         struct proc *p = td->td_proc;
 1184         struct rlimit bsd_rlim;
 1185         u_int which;
 1186 
 1187 #ifdef DEBUG
 1188         if (ldebug(old_getrlimit))
 1189                 printf(ARGS(old_getrlimit, "%d, %p"),
 1190                     args->resource, (void *)args->rlim);
 1191 #endif
 1192 
 1193         if (args->resource >= LINUX_RLIM_NLIMITS)
 1194                 return (EINVAL);
 1195 
 1196         which = linux_to_bsd_resource[args->resource];
 1197         if (which == -1)
 1198                 return (EINVAL);
 1199 
 1200         PROC_LOCK(p);
 1201         lim_rlimit(p, which, &bsd_rlim);
 1202         PROC_UNLOCK(p);
 1203 
 1204 #ifdef COMPAT_LINUX32
 1205         rlim.rlim_cur = (unsigned int)bsd_rlim.rlim_cur;
 1206         if (rlim.rlim_cur == UINT_MAX)
 1207                 rlim.rlim_cur = INT_MAX;
 1208         rlim.rlim_max = (unsigned int)bsd_rlim.rlim_max;
 1209         if (rlim.rlim_max == UINT_MAX)
 1210                 rlim.rlim_max = INT_MAX;
 1211 #else
 1212         rlim.rlim_cur = (unsigned long)bsd_rlim.rlim_cur;
 1213         if (rlim.rlim_cur == ULONG_MAX)
 1214                 rlim.rlim_cur = LONG_MAX;
 1215         rlim.rlim_max = (unsigned long)bsd_rlim.rlim_max;
 1216         if (rlim.rlim_max == ULONG_MAX)
 1217                 rlim.rlim_max = LONG_MAX;
 1218 #endif
 1219         return (copyout(&rlim, args->rlim, sizeof(rlim)));
 1220 }
 1221 
 1222 int
 1223 linux_getrlimit(struct thread *td, struct linux_getrlimit_args *args)
 1224 {
 1225         struct l_rlimit rlim;
 1226         struct proc *p = td->td_proc;
 1227         struct rlimit bsd_rlim;
 1228         u_int which;
 1229 
 1230 #ifdef DEBUG
 1231         if (ldebug(getrlimit))
 1232                 printf(ARGS(getrlimit, "%d, %p"),
 1233                     args->resource, (void *)args->rlim);
 1234 #endif
 1235 
 1236         if (args->resource >= LINUX_RLIM_NLIMITS)
 1237                 return (EINVAL);
 1238 
 1239         which = linux_to_bsd_resource[args->resource];
 1240         if (which == -1)
 1241                 return (EINVAL);
 1242 
 1243         PROC_LOCK(p);
 1244         lim_rlimit(p, which, &bsd_rlim);
 1245         PROC_UNLOCK(p);
 1246 
 1247         rlim.rlim_cur = (l_ulong)bsd_rlim.rlim_cur;
 1248         rlim.rlim_max = (l_ulong)bsd_rlim.rlim_max;
 1249         return (copyout(&rlim, args->rlim, sizeof(rlim)));
 1250 }
 1251 #endif /*!__alpha__*/
 1252 
 1253 int
 1254 linux_sched_setscheduler(struct thread *td,
 1255     struct linux_sched_setscheduler_args *args)
 1256 {
 1257         struct sched_setscheduler_args bsd;
 1258 
 1259 #ifdef DEBUG
 1260         if (ldebug(sched_setscheduler))
 1261                 printf(ARGS(sched_setscheduler, "%d, %d, %p"),
 1262                     args->pid, args->policy, (const void *)args->param);
 1263 #endif
 1264 
 1265         switch (args->policy) {
 1266         case LINUX_SCHED_OTHER:
 1267                 bsd.policy = SCHED_OTHER;
 1268                 break;
 1269         case LINUX_SCHED_FIFO:
 1270                 bsd.policy = SCHED_FIFO;
 1271                 break;
 1272         case LINUX_SCHED_RR:
 1273                 bsd.policy = SCHED_RR;
 1274                 break;
 1275         default:
 1276                 return EINVAL;
 1277         }
 1278 
 1279         bsd.pid = args->pid;
 1280         bsd.param = (struct sched_param *)args->param;
 1281         return sched_setscheduler(td, &bsd);
 1282 }
 1283 
 1284 int
 1285 linux_sched_getscheduler(struct thread *td,
 1286     struct linux_sched_getscheduler_args *args)
 1287 {
 1288         struct sched_getscheduler_args bsd;
 1289         int error;
 1290 
 1291 #ifdef DEBUG
 1292         if (ldebug(sched_getscheduler))
 1293                 printf(ARGS(sched_getscheduler, "%d"), args->pid);
 1294 #endif
 1295 
 1296         bsd.pid = args->pid;
 1297         error = sched_getscheduler(td, &bsd);
 1298 
 1299         switch (td->td_retval[0]) {
 1300         case SCHED_OTHER:
 1301                 td->td_retval[0] = LINUX_SCHED_OTHER;
 1302                 break;
 1303         case SCHED_FIFO:
 1304                 td->td_retval[0] = LINUX_SCHED_FIFO;
 1305                 break;
 1306         case SCHED_RR:
 1307                 td->td_retval[0] = LINUX_SCHED_RR;
 1308                 break;
 1309         }
 1310 
 1311         return error;
 1312 }
 1313 
 1314 int
 1315 linux_sched_get_priority_max(struct thread *td,
 1316     struct linux_sched_get_priority_max_args *args)
 1317 {
 1318         struct sched_get_priority_max_args bsd;
 1319 
 1320 #ifdef DEBUG
 1321         if (ldebug(sched_get_priority_max))
 1322                 printf(ARGS(sched_get_priority_max, "%d"), args->policy);
 1323 #endif
 1324 
 1325         switch (args->policy) {
 1326         case LINUX_SCHED_OTHER:
 1327                 bsd.policy = SCHED_OTHER;
 1328                 break;
 1329         case LINUX_SCHED_FIFO:
 1330                 bsd.policy = SCHED_FIFO;
 1331                 break;
 1332         case LINUX_SCHED_RR:
 1333                 bsd.policy = SCHED_RR;
 1334                 break;
 1335         default:
 1336                 return EINVAL;
 1337         }
 1338         return sched_get_priority_max(td, &bsd);
 1339 }
 1340 
 1341 int
 1342 linux_sched_get_priority_min(struct thread *td,
 1343     struct linux_sched_get_priority_min_args *args)
 1344 {
 1345         struct sched_get_priority_min_args bsd;
 1346 
 1347 #ifdef DEBUG
 1348         if (ldebug(sched_get_priority_min))
 1349                 printf(ARGS(sched_get_priority_min, "%d"), args->policy);
 1350 #endif
 1351 
 1352         switch (args->policy) {
 1353         case LINUX_SCHED_OTHER:
 1354                 bsd.policy = SCHED_OTHER;
 1355                 break;
 1356         case LINUX_SCHED_FIFO:
 1357                 bsd.policy = SCHED_FIFO;
 1358                 break;
 1359         case LINUX_SCHED_RR:
 1360                 bsd.policy = SCHED_RR;
 1361                 break;
 1362         default:
 1363                 return EINVAL;
 1364         }
 1365         return sched_get_priority_min(td, &bsd);
 1366 }
 1367 
 1368 #define REBOOT_CAD_ON   0x89abcdef
 1369 #define REBOOT_CAD_OFF  0
 1370 #define REBOOT_HALT     0xcdef0123
 1371 
 1372 int
 1373 linux_reboot(struct thread *td, struct linux_reboot_args *args)
 1374 {
 1375         struct reboot_args bsd_args;
 1376 
 1377 #ifdef DEBUG
 1378         if (ldebug(reboot))
 1379                 printf(ARGS(reboot, "0x%x"), args->cmd);
 1380 #endif
 1381         if (args->cmd == REBOOT_CAD_ON || args->cmd == REBOOT_CAD_OFF)
 1382                 return (0);
 1383         bsd_args.opt = (args->cmd == REBOOT_HALT) ? RB_HALT : 0;
 1384         return (reboot(td, &bsd_args));
 1385 }
 1386 
 1387 #ifndef __alpha__
 1388 
 1389 /*
 1390  * The FreeBSD native getpid(2), getgid(2) and getuid(2) also modify
 1391  * td->td_retval[1] when COMPAT_43 is defined. This
 1392  * globbers registers that are assumed to be preserved. The following
 1393  * lightweight syscalls fixes this. See also linux_getgid16() and
 1394  * linux_getuid16() in linux_uid16.c.
 1395  *
 1396  * linux_getpid() - MP SAFE
 1397  * linux_getgid() - MP SAFE
 1398  * linux_getuid() - MP SAFE
 1399  */
 1400 
 1401 int
 1402 linux_getpid(struct thread *td, struct linux_getpid_args *args)
 1403 {
 1404 
 1405         td->td_retval[0] = td->td_proc->p_pid;
 1406         return (0);
 1407 }
 1408 
 1409 int
 1410 linux_getgid(struct thread *td, struct linux_getgid_args *args)
 1411 {
 1412 
 1413         td->td_retval[0] = td->td_ucred->cr_rgid;
 1414         return (0);
 1415 }
 1416 
 1417 int
 1418 linux_getuid(struct thread *td, struct linux_getuid_args *args)
 1419 {
 1420 
 1421         td->td_retval[0] = td->td_ucred->cr_ruid;
 1422         return (0);
 1423 }
 1424 
 1425 #endif /*!__alpha__*/
 1426 
 1427 int
 1428 linux_getsid(struct thread *td, struct linux_getsid_args *args)
 1429 {
 1430         struct getsid_args bsd;
 1431         bsd.pid = args->pid;
 1432         return getsid(td, &bsd);
 1433 }
 1434 
 1435 int
 1436 linux_nosys(struct thread *td, struct nosys_args *ignore)
 1437 {
 1438 
 1439         return (ENOSYS);
 1440 }

Cache object: e52cd956b229a3b43d3a022ad98069c4


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.