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/common/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 /*      $NetBSD: linux_misc.c,v 1.122.2.4 2004/11/12 06:18:59 jmc Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 1995, 1998, 1999 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Frank van der Linden and Eric Haszlakiewicz; by Jason R. Thorpe
    9  * of the Numerical Aerospace Simulation Facility, NASA Ames Research Center.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. All advertising materials mentioning features or use of this software
   20  *    must display the following acknowledgement:
   21  *      This product includes software developed by the NetBSD
   22  *      Foundation, Inc. and its contributors.
   23  * 4. Neither the name of The NetBSD Foundation nor the names of its
   24  *    contributors may be used to endorse or promote products derived
   25  *    from this software without specific prior written permission.
   26  *
   27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   37  * POSSIBILITY OF SUCH DAMAGE.
   38  */
   39 
   40 /*
   41  * Linux compatibility module. Try to deal with various Linux system calls.
   42  */
   43 
   44 /*
   45  * These functions have been moved to multiarch to allow
   46  * selection of which machines include them to be 
   47  * determined by the individual files.linux_<arch> files.
   48  *
   49  * Function in multiarch:
   50  *      linux_sys_break                 : linux_break.c
   51  *      linux_sys_alarm                 : linux_misc_notalpha.c
   52  *      linux_sys_getresgid             : linux_misc_notalpha.c
   53  *      linux_sys_nice                  : linux_misc_notalpha.c
   54  *      linux_sys_readdir               : linux_misc_notalpha.c
   55  *      linux_sys_setresgid             : linux_misc_notalpha.c
   56  *      linux_sys_time                  : linux_misc_notalpha.c
   57  *      linux_sys_utime                 : linux_misc_notalpha.c
   58  *      linux_sys_waitpid               : linux_misc_notalpha.c
   59  *      linux_sys_old_mmap              : linux_oldmmap.c
   60  *      linux_sys_oldolduname           : linux_oldolduname.c
   61  *      linux_sys_oldselect             : linux_oldselect.c
   62  *      linux_sys_olduname              : linux_olduname.c
   63  *      linux_sys_pipe                  : linux_pipe.c
   64  */
   65 
   66 #include <sys/cdefs.h>
   67 __KERNEL_RCSID(0, "$NetBSD: linux_misc.c,v 1.122.2.4 2004/11/12 06:18:59 jmc Exp $");
   68 
   69 #include <sys/param.h>
   70 #include <sys/systm.h>
   71 #include <sys/namei.h>
   72 #include <sys/proc.h>
   73 #include <sys/dirent.h>
   74 #include <sys/file.h>
   75 #include <sys/stat.h>
   76 #include <sys/filedesc.h>
   77 #include <sys/ioctl.h>
   78 #include <sys/kernel.h>
   79 #include <sys/malloc.h>
   80 #include <sys/mbuf.h>
   81 #include <sys/mman.h>
   82 #include <sys/mount.h>
   83 #include <sys/reboot.h>
   84 #include <sys/resource.h>
   85 #include <sys/resourcevar.h>
   86 #include <sys/signal.h>
   87 #include <sys/signalvar.h>
   88 #include <sys/socket.h>
   89 #include <sys/time.h>
   90 #include <sys/times.h>
   91 #include <sys/vnode.h>
   92 #include <sys/uio.h>
   93 #include <sys/wait.h>
   94 #include <sys/utsname.h>
   95 #include <sys/unistd.h>
   96 #include <sys/swap.h>           /* for SWAP_ON */
   97 #include <sys/sysctl.h>         /* for KERN_DOMAINNAME */
   98 
   99 #include <sys/ptrace.h>
  100 #include <machine/ptrace.h>
  101 
  102 #include <sys/sa.h>
  103 #include <sys/syscallargs.h>
  104 
  105 #include <compat/linux/common/linux_types.h>
  106 #include <compat/linux/common/linux_signal.h>
  107 
  108 #include <compat/linux/linux_syscallargs.h>
  109 
  110 #include <compat/linux/common/linux_fcntl.h>
  111 #include <compat/linux/common/linux_mmap.h>
  112 #include <compat/linux/common/linux_dirent.h>
  113 #include <compat/linux/common/linux_util.h>
  114 #include <compat/linux/common/linux_misc.h>
  115 #include <compat/linux/common/linux_ptrace.h>
  116 #include <compat/linux/common/linux_reboot.h>
  117 #include <compat/linux/common/linux_emuldata.h>
  118 
  119 const int linux_ptrace_request_map[] = {
  120         LINUX_PTRACE_TRACEME,   PT_TRACE_ME,
  121         LINUX_PTRACE_PEEKTEXT,  PT_READ_I,
  122         LINUX_PTRACE_PEEKDATA,  PT_READ_D,
  123         LINUX_PTRACE_POKETEXT,  PT_WRITE_I,
  124         LINUX_PTRACE_POKEDATA,  PT_WRITE_D,
  125         LINUX_PTRACE_CONT,      PT_CONTINUE,
  126         LINUX_PTRACE_KILL,      PT_KILL,
  127         LINUX_PTRACE_ATTACH,    PT_ATTACH,
  128         LINUX_PTRACE_DETACH,    PT_DETACH,
  129 #ifdef PT_STEP
  130         LINUX_PTRACE_SINGLESTEP,        PT_STEP,
  131 #endif
  132         -1
  133 };
  134 
  135 static const struct mnttypes {
  136         char *bsd;
  137         int linux;
  138 } fstypes[] = {
  139         { MOUNT_FFS,            LINUX_DEFAULT_SUPER_MAGIC       },
  140         { MOUNT_NFS,            LINUX_NFS_SUPER_MAGIC           },
  141         { MOUNT_MFS,            LINUX_DEFAULT_SUPER_MAGIC       },
  142         { MOUNT_MSDOS,          LINUX_MSDOS_SUPER_MAGIC         },
  143         { MOUNT_LFS,            LINUX_DEFAULT_SUPER_MAGIC       },
  144         { MOUNT_FDESC,          LINUX_DEFAULT_SUPER_MAGIC       },
  145         { MOUNT_PORTAL,         LINUX_DEFAULT_SUPER_MAGIC       },
  146         { MOUNT_NULL,           LINUX_DEFAULT_SUPER_MAGIC       },
  147         { MOUNT_OVERLAY,        LINUX_DEFAULT_SUPER_MAGIC       },      
  148         { MOUNT_UMAP,           LINUX_DEFAULT_SUPER_MAGIC       },
  149         { MOUNT_KERNFS,         LINUX_DEFAULT_SUPER_MAGIC       },
  150         { MOUNT_PROCFS,         LINUX_PROC_SUPER_MAGIC          },
  151         { MOUNT_AFS,            LINUX_DEFAULT_SUPER_MAGIC       },
  152         { MOUNT_CD9660,         LINUX_ISOFS_SUPER_MAGIC         },
  153         { MOUNT_UNION,          LINUX_DEFAULT_SUPER_MAGIC       },
  154         { MOUNT_ADOSFS,         LINUX_ADFS_SUPER_MAGIC          },
  155         { MOUNT_EXT2FS,         LINUX_EXT2_SUPER_MAGIC          },
  156         { MOUNT_CFS,            LINUX_DEFAULT_SUPER_MAGIC       },
  157         { MOUNT_CODA,           LINUX_CODA_SUPER_MAGIC          },
  158         { MOUNT_FILECORE,       LINUX_DEFAULT_SUPER_MAGIC       },
  159         { MOUNT_NTFS,           LINUX_DEFAULT_SUPER_MAGIC       },
  160         { MOUNT_SMBFS,          LINUX_SMB_SUPER_MAGIC           }
  161 };
  162 #define FSTYPESSIZE (sizeof(fstypes) / sizeof(fstypes[0]))
  163 
  164 #ifdef DEBUG_LINUX
  165 #define DPRINTF(a)      uprintf a
  166 #else
  167 #define DPRINTF(a)
  168 #endif
  169 
  170 /* Local linux_misc.c functions: */
  171 static void bsd_to_linux_statfs __P((struct statfs *, struct linux_statfs *));
  172 static int linux_to_bsd_limit __P((int));
  173 static void linux_to_bsd_mmap_args __P((struct sys_mmap_args *,
  174     const struct linux_sys_mmap_args *));
  175 static int linux_mmap __P((struct lwp *, struct linux_sys_mmap_args *,
  176     register_t *, off_t));
  177 
  178 
  179 /*
  180  * The information on a terminated (or stopped) process needs
  181  * to be converted in order for Linux binaries to get a valid signal
  182  * number out of it.
  183  */
  184 void
  185 bsd_to_linux_wstat(st)
  186         int *st;
  187 {
  188 
  189         int sig;
  190 
  191         if (WIFSIGNALED(*st)) {
  192                 sig = WTERMSIG(*st);
  193                 if (sig >= 0 && sig < NSIG)
  194                         *st= (*st& ~0177) | native_to_linux_signo[sig];
  195         } else if (WIFSTOPPED(*st)) {
  196                 sig = WSTOPSIG(*st);
  197                 if (sig >= 0 && sig < NSIG)
  198                         *st = (*st & ~0xff00) |
  199                             (native_to_linux_signo[sig] << 8);
  200         }
  201 }
  202 
  203 /*
  204  * wait4(2).  Passed on to the NetBSD call, surrounded by code to
  205  * reserve some space for a NetBSD-style wait status, and converting
  206  * it to what Linux wants.
  207  */
  208 int
  209 linux_sys_wait4(l, v, retval)
  210         struct lwp *l;
  211         void *v;
  212         register_t *retval;
  213 {
  214         struct linux_sys_wait4_args /* {
  215                 syscallarg(int) pid;
  216                 syscallarg(int *) status;
  217                 syscallarg(int) options;
  218                 syscallarg(struct rusage *) rusage;
  219         } */ *uap = v;
  220         struct proc *p = l->l_proc;
  221         struct sys_wait4_args w4a;
  222         int error, *status, tstat, options, linux_options;
  223         caddr_t sg;
  224 
  225         if (SCARG(uap, status) != NULL) {
  226                 sg = stackgap_init(p, 0);
  227                 status = (int *) stackgap_alloc(p, &sg, sizeof *status);
  228         } else
  229                 status = NULL;
  230 
  231         linux_options = SCARG(uap, options);
  232         options = 0;
  233         if (linux_options & ~(LINUX_WAIT4_KNOWNFLAGS))
  234                 return (EINVAL);
  235 
  236         if (linux_options & LINUX_WAIT4_WNOHANG)
  237                 options |= WNOHANG;
  238         if (linux_options & LINUX_WAIT4_WUNTRACED)
  239                 options |= WUNTRACED;
  240         if (linux_options & LINUX_WAIT4_WALL)
  241                 options |= WALLSIG;
  242         if (linux_options & LINUX_WAIT4_WCLONE)
  243                 options |= WALTSIG;
  244 #ifdef DIAGNOSTIC
  245         if (linux_options & LINUX_WAIT4_WNOTHREAD)
  246                 printf("WARNING: %s: linux process %d.%d called "
  247                        "waitpid with __WNOTHREAD set!",
  248                        __FILE__, p->p_pid, l->l_lid);
  249 
  250 #endif
  251 
  252         SCARG(&w4a, pid) = SCARG(uap, pid);
  253         SCARG(&w4a, status) = status;
  254         SCARG(&w4a, options) = options;
  255         SCARG(&w4a, rusage) = SCARG(uap, rusage);
  256 
  257         if ((error = sys_wait4(l, &w4a, retval)))
  258                 return error;
  259 
  260         sigdelset(&p->p_sigctx.ps_siglist, SIGCHLD);
  261 
  262         if (status != NULL) {
  263                 if ((error = copyin(status, &tstat, sizeof tstat)))
  264                         return error;
  265 
  266                 bsd_to_linux_wstat(&tstat);
  267                 return copyout(&tstat, SCARG(uap, status), sizeof tstat);
  268         }
  269 
  270         return 0;
  271 }
  272 
  273 /*
  274  * Linux brk(2). The check if the new address is >= the old one is
  275  * done in the kernel in Linux. NetBSD does it in the library.
  276  */
  277 int
  278 linux_sys_brk(l, v, retval)
  279         struct lwp *l;
  280         void *v;
  281         register_t *retval;
  282 {
  283         struct linux_sys_brk_args /* {
  284                 syscallarg(char *) nsize;
  285         } */ *uap = v;
  286         struct proc *p = l->l_proc;
  287         char *nbrk = SCARG(uap, nsize);
  288         struct sys_obreak_args oba;
  289         struct vmspace *vm = p->p_vmspace;
  290         struct linux_emuldata *ed = (struct linux_emuldata*)p->p_emuldata;
  291 
  292         SCARG(&oba, nsize) = nbrk;
  293 
  294         if ((caddr_t) nbrk > vm->vm_daddr && sys_obreak(l, &oba, retval) == 0)
  295                 ed->s->p_break = (char*)nbrk;
  296         else 
  297                 nbrk = ed->s->p_break;
  298 
  299         retval[0] = (register_t)nbrk;
  300 
  301         return 0;
  302 }
  303 
  304 /*
  305  * Convert BSD statfs structure to Linux statfs structure.
  306  * The Linux structure has less fields, and it also wants
  307  * the length of a name in a dir entry in a field, which
  308  * we fake (probably the wrong way).
  309  */
  310 static void
  311 bsd_to_linux_statfs(bsp, lsp)
  312         struct statfs *bsp;
  313         struct linux_statfs *lsp;
  314 {
  315         int i;
  316 
  317         for (i = 0; i < FSTYPESSIZE; i++)
  318                 if (strcmp(bsp->f_fstypename, fstypes[i].bsd) == 0)
  319                         break;
  320 
  321         if (i == FSTYPESSIZE) {
  322                 DPRINTF(("unhandled fstype in linux emulation: %s\n",
  323                     bsp->f_fstypename));
  324                 lsp->l_ftype = LINUX_DEFAULT_SUPER_MAGIC;
  325         } else {
  326                 lsp->l_ftype = fstypes[i].linux;
  327         }
  328 
  329         lsp->l_fbsize = bsp->f_bsize;
  330         lsp->l_fblocks = bsp->f_blocks;
  331         lsp->l_fbfree = bsp->f_bfree;
  332         lsp->l_fbavail = bsp->f_bavail;
  333         lsp->l_ffiles = bsp->f_files;
  334         lsp->l_fffree = bsp->f_ffree;
  335         /* Linux sets the fsid to 0..., we don't */
  336         lsp->l_ffsid.val[0] = bsp->f_fsid.val[0];
  337         lsp->l_ffsid.val[1] = bsp->f_fsid.val[1];
  338         lsp->l_fnamelen = MAXNAMLEN;    /* XXX */
  339         (void)memset(lsp->l_fspare, 0, sizeof(lsp->l_fspare));
  340 }
  341 
  342 /*
  343  * Implement the fs stat functions. Straightforward.
  344  */
  345 int
  346 linux_sys_statfs(l, v, retval)
  347         struct lwp *l;
  348         void *v;
  349         register_t *retval;
  350 {
  351         struct linux_sys_statfs_args /* {
  352                 syscallarg(const char *) path;
  353                 syscallarg(struct linux_statfs *) sp;
  354         } */ *uap = v;
  355         struct proc *p = l->l_proc;
  356         struct statfs btmp, *bsp;
  357         struct linux_statfs ltmp;
  358         struct sys_statfs_args bsa;
  359         caddr_t sg;
  360         int error;
  361 
  362         sg = stackgap_init(p, 0);
  363         bsp = (struct statfs *) stackgap_alloc(p, &sg, sizeof (struct statfs));
  364 
  365         CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
  366 
  367         SCARG(&bsa, path) = SCARG(uap, path);
  368         SCARG(&bsa, buf) = bsp;
  369 
  370         if ((error = sys_statfs(l, &bsa, retval)))
  371                 return error;
  372 
  373         if ((error = copyin((caddr_t) bsp, (caddr_t) &btmp, sizeof btmp)))
  374                 return error;
  375 
  376         bsd_to_linux_statfs(&btmp, &ltmp);
  377 
  378         return copyout((caddr_t) &ltmp, (caddr_t) SCARG(uap, sp), sizeof ltmp);
  379 }
  380 
  381 int
  382 linux_sys_fstatfs(l, v, retval)
  383         struct lwp *l;
  384         void *v;
  385         register_t *retval;
  386 {
  387         struct linux_sys_fstatfs_args /* {
  388                 syscallarg(int) fd;
  389                 syscallarg(struct linux_statfs *) sp;
  390         } */ *uap = v;
  391         struct proc *p = l->l_proc;
  392         struct statfs btmp, *bsp;
  393         struct linux_statfs ltmp;
  394         struct sys_fstatfs_args bsa;
  395         caddr_t sg;
  396         int error;
  397 
  398         sg = stackgap_init(p, 0);
  399         bsp = (struct statfs *) stackgap_alloc(p, &sg, sizeof (struct statfs));
  400 
  401         SCARG(&bsa, fd) = SCARG(uap, fd);
  402         SCARG(&bsa, buf) = bsp;
  403 
  404         if ((error = sys_fstatfs(l, &bsa, retval)))
  405                 return error;
  406 
  407         if ((error = copyin((caddr_t) bsp, (caddr_t) &btmp, sizeof btmp)))
  408                 return error;
  409 
  410         bsd_to_linux_statfs(&btmp, &ltmp);
  411 
  412         return copyout((caddr_t) &ltmp, (caddr_t) SCARG(uap, sp), sizeof ltmp);
  413 }
  414 
  415 /*
  416  * uname(). Just copy the info from the various strings stored in the
  417  * kernel, and put it in the Linux utsname structure. That structure
  418  * is almost the same as the NetBSD one, only it has fields 65 characters
  419  * long, and an extra domainname field.
  420  */
  421 int
  422 linux_sys_uname(l, v, retval)
  423         struct lwp *l;
  424         void *v;
  425         register_t *retval;
  426 {
  427         struct linux_sys_uname_args /* {
  428                 syscallarg(struct linux_utsname *) up;
  429         } */ *uap = v;
  430         struct linux_utsname luts;
  431 
  432         strncpy(luts.l_sysname, linux_sysname, sizeof(luts.l_sysname));
  433         strncpy(luts.l_nodename, hostname, sizeof(luts.l_nodename));
  434         strncpy(luts.l_release, linux_release, sizeof(luts.l_release));
  435         strncpy(luts.l_version, linux_version, sizeof(luts.l_version));
  436         strncpy(luts.l_machine, machine, sizeof(luts.l_machine));
  437         strncpy(luts.l_domainname, domainname, sizeof(luts.l_domainname));
  438 
  439         return copyout(&luts, SCARG(uap, up), sizeof(luts));
  440 }
  441 
  442 /* Used directly on: alpha, mips, ppc, sparc, sparc64 */
  443 /* Used indirectly on: arm, i386, m68k */
  444 
  445 /*
  446  * New type Linux mmap call.
  447  * Only called directly on machines with >= 6 free regs.
  448  */
  449 int
  450 linux_sys_mmap(l, v, retval)
  451         struct lwp *l;
  452         void *v;
  453         register_t *retval;
  454 {
  455         struct linux_sys_mmap_args /* {
  456                 syscallarg(unsigned long) addr;
  457                 syscallarg(size_t) len;
  458                 syscallarg(int) prot;
  459                 syscallarg(int) flags;
  460                 syscallarg(int) fd;
  461                 syscallarg(linux_off_t) offset;
  462         } */ *uap = v;
  463 
  464         if (SCARG(uap, offset) & PAGE_MASK)
  465                 return EINVAL;
  466 
  467         return linux_mmap(l, uap, retval, SCARG(uap, offset));
  468 }
  469 
  470 /*
  471  * Guts of most architectures' mmap64() implementations.  This shares
  472  * its list of arguments with linux_sys_mmap().
  473  *
  474  * The difference in linux_sys_mmap2() is that "offset" is actually
  475  * (offset / pagesize), not an absolute byte count.  This translation
  476  * to pagesize offsets is done inside glibc between the mmap64() call
  477  * point, and the actual syscall.
  478  */
  479 int
  480 linux_sys_mmap2(l, v, retval)
  481         struct lwp *l;
  482         void *v;
  483         register_t *retval;
  484 {
  485         struct linux_sys_mmap2_args /* {
  486                 syscallarg(unsigned long) addr;
  487                 syscallarg(size_t) len;
  488                 syscallarg(int) prot;
  489                 syscallarg(int) flags;
  490                 syscallarg(int) fd;
  491                 syscallarg(linux_off_t) offset;
  492         } */ *uap = v;
  493 
  494         return linux_mmap(l, uap, retval,
  495             ((off_t)SCARG(uap, offset)) << PAGE_SHIFT);
  496 }
  497 
  498 /*
  499  * Massage arguments and call system mmap(2).
  500  */
  501 static int
  502 linux_mmap(l, uap, retval, offset)
  503         struct lwp *l;
  504         struct linux_sys_mmap_args *uap;
  505         register_t *retval;
  506         off_t offset;
  507 {
  508         struct sys_mmap_args cma;
  509         int error;
  510         size_t mmoff=0;
  511 
  512         if (SCARG(uap, flags) & LINUX_MAP_GROWSDOWN) {
  513                 /*
  514                  * Request for stack-like memory segment. On linux, this
  515                  * works by mmap()ping (small) segment, which is automatically
  516                  * extended when page fault happens below the currently
  517                  * allocated area. We emulate this by allocating (typically
  518                  * bigger) segment sized at current stack size limit, and
  519                  * offsetting the requested and returned address accordingly.
  520                  * Since physical pages are only allocated on-demand, this
  521                  * is effectively identical.
  522                  */
  523                 rlim_t ssl = l->l_proc->p_rlimit[RLIMIT_STACK].rlim_cur;
  524 
  525                 if (SCARG(uap, len) < ssl) {
  526                         /* Compute the address offset */
  527                         mmoff = round_page(ssl) - SCARG(uap, len);
  528 
  529                         if (SCARG(uap, addr))
  530                                 SCARG(uap, addr) -= mmoff;
  531 
  532                         SCARG(uap, len) = (size_t) ssl;
  533                 }
  534         }
  535 
  536         linux_to_bsd_mmap_args(&cma, uap);
  537         SCARG(&cma, pos) = offset;
  538 
  539         error = sys_mmap(l, &cma, retval);
  540         if (error)
  541                 return (error);
  542 
  543         /* Shift the returned address for stack-like segment if necessary */
  544         if (SCARG(uap, flags) & LINUX_MAP_GROWSDOWN && mmoff)
  545                 retval[0] += mmoff;
  546 
  547         return (0);
  548 }
  549 
  550 static void
  551 linux_to_bsd_mmap_args(cma, uap)
  552         struct sys_mmap_args *cma;
  553         const struct linux_sys_mmap_args *uap;
  554 {
  555         int flags = MAP_TRYFIXED, fl = SCARG(uap, flags);
  556         
  557         flags |= cvtto_bsd_mask(fl, LINUX_MAP_SHARED, MAP_SHARED);
  558         flags |= cvtto_bsd_mask(fl, LINUX_MAP_PRIVATE, MAP_PRIVATE);
  559         flags |= cvtto_bsd_mask(fl, LINUX_MAP_FIXED, MAP_FIXED);
  560         flags |= cvtto_bsd_mask(fl, LINUX_MAP_ANON, MAP_ANON);
  561         /* XXX XAX ERH: Any other flags here?  There are more defined... */
  562 
  563         SCARG(cma, addr) = (void *)SCARG(uap, addr);
  564         SCARG(cma, len) = SCARG(uap, len);
  565         SCARG(cma, prot) = SCARG(uap, prot);
  566         if (SCARG(cma, prot) & VM_PROT_WRITE) /* XXX */
  567                 SCARG(cma, prot) |= VM_PROT_READ;
  568         SCARG(cma, flags) = flags;
  569         SCARG(cma, fd) = flags & MAP_ANON ? -1 : SCARG(uap, fd);
  570         SCARG(cma, pad) = 0;
  571 }
  572 
  573 int
  574 linux_sys_mremap(l, v, retval)
  575         struct lwp *l;
  576         void *v;
  577         register_t *retval;
  578 {
  579         struct linux_sys_mremap_args /* {
  580                 syscallarg(void *) old_address;
  581                 syscallarg(size_t) old_size;
  582                 syscallarg(size_t) new_size;
  583                 syscallarg(u_long) flags;
  584         } */ *uap = v;
  585         struct sys_munmap_args mua;
  586         size_t old_size, new_size;
  587         int error;
  588 
  589         old_size = round_page(SCARG(uap, old_size));
  590         new_size = round_page(SCARG(uap, new_size));
  591 
  592         /*
  593          * Growing mapped region.
  594          */
  595         if (new_size > old_size) {
  596                 /*
  597                  * XXX Implement me.  What we probably want to do is
  598                  * XXX dig out the guts of the old mapping, mmap that
  599                  * XXX object again with the new size, then munmap
  600                  * XXX the old mapping.
  601                  */
  602                 *retval = 0;
  603                 return (ENOMEM);
  604         }
  605 
  606         /*
  607          * Shrinking mapped region.
  608          */
  609         if (new_size < old_size) {
  610                 SCARG(&mua, addr) = (caddr_t)SCARG(uap, old_address) +
  611                     new_size;
  612                 SCARG(&mua, len) = old_size - new_size;
  613                 error = sys_munmap(l, &mua, retval);
  614                 *retval = error ? 0 : (register_t)SCARG(uap, old_address);
  615                 return (error);
  616         }
  617 
  618         /*
  619          * No change.
  620          */
  621         *retval = (register_t)SCARG(uap, old_address);
  622         return (0);
  623 }
  624 
  625 int
  626 linux_sys_msync(l, v, retval)
  627         struct lwp *l;
  628         void *v;
  629         register_t *retval;
  630 {
  631         struct linux_sys_msync_args /* {
  632                 syscallarg(caddr_t) addr;
  633                 syscallarg(int) len;
  634                 syscallarg(int) fl;
  635         } */ *uap = v;
  636 
  637         struct sys___msync13_args bma;
  638 
  639         /* flags are ignored */
  640         SCARG(&bma, addr) = SCARG(uap, addr);
  641         SCARG(&bma, len) = SCARG(uap, len);
  642         SCARG(&bma, flags) = SCARG(uap, fl);
  643 
  644         return sys___msync13(l, &bma, retval);
  645 }
  646 
  647 int
  648 linux_sys_mprotect(l, v, retval)
  649         struct lwp *l;
  650         void *v;
  651         register_t *retval;
  652 {
  653         struct linux_sys_mprotect_args /* {
  654                 syscallarg(const void *) start;
  655                 syscallarg(unsigned long) len;
  656                 syscallarg(int) prot;
  657         } */ *uap = v;
  658         unsigned long end, start = (unsigned long)SCARG(uap, start), len;
  659         int prot = SCARG(uap, prot);
  660         struct vm_map_entry *entry;
  661         struct vm_map *map = &l->l_proc->p_vmspace->vm_map;
  662 
  663         if (start & PAGE_MASK)
  664                 return EINVAL;
  665 
  666         len = round_page(SCARG(uap, len));
  667         end = start + len;
  668 
  669         if (end < start)
  670                 return EINVAL;
  671         else if (end == start)
  672                 return 0;
  673 
  674         if (SCARG(uap, prot) & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
  675                 return EINVAL;
  676 
  677         vm_map_lock(map);
  678 #ifdef notdef
  679         VM_MAP_RANGE_CHECK(map, start, end);
  680 #endif
  681         if (!uvm_map_lookup_entry(map, start, &entry) || entry->start > start) {
  682                 vm_map_unlock(map);
  683                 return ENOMEM;
  684         }
  685         vm_map_unlock(map);
  686         return uvm_map_protect(map, start, end, prot, FALSE);
  687 }
  688 
  689 /*
  690  * This code is partly stolen from src/lib/libc/compat-43/times.c
  691  */
  692 
  693 #define CONVTCK(r)      (r.tv_sec * hz + r.tv_usec / (1000000 / hz))
  694 
  695 int
  696 linux_sys_times(l, v, retval)
  697         struct lwp *l;
  698         void *v;
  699         register_t *retval;
  700 {
  701         struct linux_sys_times_args /* {
  702                 syscallarg(struct times *) tms;
  703         } */ *uap = v;
  704         struct proc *p = l->l_proc;
  705         struct timeval t;
  706         int error, s;
  707 
  708         if (SCARG(uap, tms)) {
  709                 struct linux_tms ltms;
  710                 struct rusage ru;
  711 
  712                 calcru(p, &ru.ru_utime, &ru.ru_stime, NULL);
  713                 ltms.ltms_utime = CONVTCK(ru.ru_utime);
  714                 ltms.ltms_stime = CONVTCK(ru.ru_stime);
  715 
  716                 ltms.ltms_cutime = CONVTCK(p->p_stats->p_cru.ru_utime);
  717                 ltms.ltms_cstime = CONVTCK(p->p_stats->p_cru.ru_stime);
  718 
  719                 if ((error = copyout(&ltms, SCARG(uap, tms), sizeof ltms)))
  720                         return error;
  721         }
  722 
  723         s = splclock();
  724         timersub(&time, &boottime, &t);
  725         splx(s);
  726 
  727         retval[0] = ((linux_clock_t)(CONVTCK(t)));
  728         return 0;
  729 }
  730 
  731 #undef CONVTCK
  732 
  733 /*
  734  * Linux 'readdir' call. This code is mostly taken from the
  735  * SunOS getdents call (see compat/sunos/sunos_misc.c), though
  736  * an attempt has been made to keep it a little cleaner (failing
  737  * miserably, because of the cruft needed if count 1 is passed).
  738  *
  739  * The d_off field should contain the offset of the next valid entry,
  740  * but in Linux it has the offset of the entry itself. We emulate
  741  * that bug here.
  742  *
  743  * Read in BSD-style entries, convert them, and copy them out.
  744  *
  745  * Note that this doesn't handle union-mounted filesystems.
  746  */
  747 int
  748 linux_sys_getdents(l, v, retval)
  749         struct lwp *l;
  750         void *v;
  751         register_t *retval;
  752 {
  753         struct linux_sys_getdents_args /* {
  754                 syscallarg(int) fd;
  755                 syscallarg(struct linux_dirent *) dent;
  756                 syscallarg(unsigned int) count;
  757         } */ *uap = v;
  758         struct proc *p = l->l_proc;
  759         struct dirent *bdp;
  760         struct vnode *vp;
  761         caddr_t inp, buf;               /* BSD-format */
  762         int len, reclen;                /* BSD-format */
  763         caddr_t outp;                   /* Linux-format */
  764         int resid, linux_reclen = 0;    /* Linux-format */
  765         struct file *fp;
  766         struct uio auio;
  767         struct iovec aiov;
  768         struct linux_dirent idb;
  769         off_t off;              /* true file offset */
  770         int buflen, error, eofflag, nbytes, oldcall;
  771         struct vattr va;
  772         off_t *cookiebuf = NULL, *cookie;
  773         int ncookies;
  774 
  775         /* getvnode() will use the descriptor for us */
  776         if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
  777                 return (error);
  778 
  779         if ((fp->f_flag & FREAD) == 0) {
  780                 error = EBADF;
  781                 goto out1;
  782         }
  783 
  784         vp = (struct vnode *)fp->f_data;
  785         if (vp->v_type != VDIR) {
  786                 error = EINVAL;
  787                 goto out1;
  788         }
  789 
  790         if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)))
  791                 goto out1;
  792 
  793         nbytes = SCARG(uap, count);
  794         if (nbytes == 1) {      /* emulating old, broken behaviour */
  795                 nbytes = sizeof (idb);
  796                 buflen = max(va.va_blocksize, nbytes);
  797                 oldcall = 1;
  798         } else {
  799                 buflen = min(MAXBSIZE, nbytes);
  800                 if (buflen < va.va_blocksize)
  801                         buflen = va.va_blocksize;
  802                 oldcall = 0;
  803         }
  804         buf = malloc(buflen, M_TEMP, M_WAITOK);
  805 
  806         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
  807         off = fp->f_offset;
  808 again:
  809         aiov.iov_base = buf;
  810         aiov.iov_len = buflen;
  811         auio.uio_iov = &aiov;
  812         auio.uio_iovcnt = 1;
  813         auio.uio_rw = UIO_READ;
  814         auio.uio_segflg = UIO_SYSSPACE;
  815         auio.uio_procp = p;
  816         auio.uio_resid = buflen;
  817         auio.uio_offset = off;
  818         /*
  819          * First we read into the malloc'ed buffer, then
  820          * we massage it into user space, one record at a time.
  821          */
  822         error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &cookiebuf,
  823             &ncookies);
  824         if (error)
  825                 goto out;
  826 
  827         inp = buf;
  828         outp = (caddr_t)SCARG(uap, dent);
  829         resid = nbytes;
  830         if ((len = buflen - auio.uio_resid) == 0)
  831                 goto eof;
  832 
  833         for (cookie = cookiebuf; len > 0; len -= reclen) {
  834                 bdp = (struct dirent *)inp;
  835                 reclen = bdp->d_reclen;
  836                 if (reclen & 3)
  837                         panic("linux_readdir");
  838                 if (bdp->d_fileno == 0) {
  839                         inp += reclen;  /* it is a hole; squish it out */
  840                         off = *cookie++;
  841                         continue;
  842                 }
  843                 linux_reclen = LINUX_RECLEN(&idb, bdp->d_namlen);
  844                 if (reclen > len || resid < linux_reclen) {
  845                         /* entry too big for buffer, so just stop */
  846                         outp++;
  847                         break;
  848                 }
  849                 /*
  850                  * Massage in place to make a Linux-shaped dirent (otherwise
  851                  * we have to worry about touching user memory outside of
  852                  * the copyout() call).
  853                  */
  854                 idb.d_ino = bdp->d_fileno;
  855                 /*
  856                  * The old readdir() call misuses the offset and reclen fields.
  857                  */
  858                 if (oldcall) {
  859                         idb.d_off = (linux_off_t)linux_reclen;
  860                         idb.d_reclen = (u_short)bdp->d_namlen;
  861                 } else {
  862                         if (sizeof (idb.d_off) <= 4 && (off >> 32) != 0) {
  863                                 compat_offseterr(vp, "linux_getdents");
  864                                 error = EINVAL;
  865                                 goto out;
  866                         }
  867                         idb.d_off = (linux_off_t)off;
  868                         idb.d_reclen = (u_short)linux_reclen;
  869                 }
  870                 strcpy(idb.d_name, bdp->d_name);
  871                 if ((error = copyout((caddr_t)&idb, outp, linux_reclen)))
  872                         goto out;
  873                 /* advance past this real entry */
  874                 inp += reclen;
  875                 off = *cookie++;        /* each entry points to itself */
  876                 /* advance output past Linux-shaped entry */
  877                 outp += linux_reclen;
  878                 resid -= linux_reclen;
  879                 if (oldcall)
  880                         break;
  881         }
  882 
  883         /* if we squished out the whole block, try again */
  884         if (outp == (caddr_t)SCARG(uap, dent))
  885                 goto again;
  886         fp->f_offset = off;     /* update the vnode offset */
  887 
  888         if (oldcall)
  889                 nbytes = resid + linux_reclen;
  890 
  891 eof:
  892         *retval = nbytes - resid;
  893 out:
  894         VOP_UNLOCK(vp, 0);
  895         if (cookiebuf)
  896                 free(cookiebuf, M_TEMP);
  897         free(buf, M_TEMP);
  898 out1:
  899         FILE_UNUSE(fp, p);
  900         return error;
  901 }
  902 
  903 /*
  904  * Even when just using registers to pass arguments to syscalls you can
  905  * have 5 of them on the i386. So this newer version of select() does
  906  * this.
  907  */
  908 int
  909 linux_sys_select(l, v, retval)
  910         struct lwp *l;
  911         void *v;
  912         register_t *retval;
  913 {
  914         struct linux_sys_select_args /* {
  915                 syscallarg(int) nfds;
  916                 syscallarg(fd_set *) readfds;
  917                 syscallarg(fd_set *) writefds;
  918                 syscallarg(fd_set *) exceptfds;
  919                 syscallarg(struct timeval *) timeout;
  920         } */ *uap = v;
  921 
  922         return linux_select1(l, retval, SCARG(uap, nfds), SCARG(uap, readfds),
  923             SCARG(uap, writefds), SCARG(uap, exceptfds), SCARG(uap, timeout));
  924 }
  925 
  926 /*
  927  * Common code for the old and new versions of select(). A couple of
  928  * things are important:
  929  * 1) return the amount of time left in the 'timeout' parameter
  930  * 2) select never returns ERESTART on Linux, always return EINTR
  931  */
  932 int
  933 linux_select1(l, retval, nfds, readfds, writefds, exceptfds, timeout)
  934         struct lwp *l;
  935         register_t *retval;
  936         int nfds;
  937         fd_set *readfds, *writefds, *exceptfds;
  938         struct timeval *timeout;
  939 {
  940         struct sys_select_args bsa;
  941         struct proc *p = l->l_proc;
  942         struct timeval tv0, tv1, utv, *tvp;
  943         caddr_t sg;
  944         int error;
  945 
  946         SCARG(&bsa, nd) = nfds;
  947         SCARG(&bsa, in) = readfds;
  948         SCARG(&bsa, ou) = writefds;
  949         SCARG(&bsa, ex) = exceptfds;
  950         SCARG(&bsa, tv) = timeout;
  951 
  952         /*
  953          * Store current time for computation of the amount of
  954          * time left.
  955          */
  956         if (timeout) {
  957                 if ((error = copyin(timeout, &utv, sizeof(utv))))
  958                         return error;
  959                 if (itimerfix(&utv)) {
  960                         /*
  961                          * The timeval was invalid.  Convert it to something
  962                          * valid that will act as it does under Linux.
  963                          */
  964                         sg = stackgap_init(p, 0);
  965                         tvp = stackgap_alloc(p, &sg, sizeof(utv));
  966                         utv.tv_sec += utv.tv_usec / 1000000;
  967                         utv.tv_usec %= 1000000;
  968                         if (utv.tv_usec < 0) {
  969                                 utv.tv_sec -= 1;
  970                                 utv.tv_usec += 1000000;
  971                         }
  972                         if (utv.tv_sec < 0)
  973                                 timerclear(&utv);
  974                         if ((error = copyout(&utv, tvp, sizeof(utv))))
  975                                 return error;
  976                         SCARG(&bsa, tv) = tvp;
  977                 }
  978                 microtime(&tv0);
  979         }
  980 
  981         error = sys_select(l, &bsa, retval);
  982         if (error) {
  983                 /*
  984                  * See fs/select.c in the Linux kernel.  Without this,
  985                  * Maelstrom doesn't work.
  986                  */
  987                 if (error == ERESTART)
  988                         error = EINTR;
  989                 return error;
  990         }
  991 
  992         if (timeout) {
  993                 if (*retval) {
  994                         /*
  995                          * Compute how much time was left of the timeout,
  996                          * by subtracting the current time and the time
  997                          * before we started the call, and subtracting
  998                          * that result from the user-supplied value.
  999                          */
 1000                         microtime(&tv1);
 1001                         timersub(&tv1, &tv0, &tv1);
 1002                         timersub(&utv, &tv1, &utv);
 1003                         if (utv.tv_sec < 0)
 1004                                 timerclear(&utv);
 1005                 } else
 1006                         timerclear(&utv);
 1007                 if ((error = copyout(&utv, timeout, sizeof(utv))))
 1008                         return error;
 1009         }
 1010 
 1011         return 0;
 1012 }
 1013 
 1014 /*
 1015  * Get the process group of a certain process. Look it up
 1016  * and return the value.
 1017  */
 1018 int
 1019 linux_sys_getpgid(l, v, retval)
 1020         struct lwp *l;
 1021         void *v;
 1022         register_t *retval;
 1023 {
 1024         struct linux_sys_getpgid_args /* {
 1025                 syscallarg(int) pid;
 1026         } */ *uap = v;
 1027         struct proc *p = l->l_proc;
 1028         struct proc *targp;
 1029 
 1030         if (SCARG(uap, pid) != 0 && SCARG(uap, pid) != p->p_pid) {
 1031                 if ((targp = pfind(SCARG(uap, pid))) == 0)
 1032                         return ESRCH;
 1033         }
 1034         else
 1035                 targp = p;
 1036 
 1037         retval[0] = targp->p_pgid;
 1038         return 0;
 1039 }
 1040 
 1041 /*
 1042  * Set the 'personality' (emulation mode) for the current process. Only
 1043  * accept the Linux personality here (0). This call is needed because
 1044  * the Linux ELF crt0 issues it in an ugly kludge to make sure that
 1045  * ELF binaries run in Linux mode, not SVR4 mode.
 1046  */
 1047 int
 1048 linux_sys_personality(l, v, retval)
 1049         struct lwp *l;
 1050         void *v;
 1051         register_t *retval;
 1052 {
 1053         struct linux_sys_personality_args /* {
 1054                 syscallarg(int) per;
 1055         } */ *uap = v;
 1056 
 1057         if (SCARG(uap, per) != 0)
 1058                 return EINVAL;
 1059         retval[0] = 0;
 1060         return 0;
 1061 }
 1062 
 1063 #if defined(__i386__) || defined(__m68k__)
 1064 /*
 1065  * The calls are here because of type conversions.
 1066  */
 1067 int
 1068 linux_sys_setreuid16(l, v, retval)
 1069         struct lwp *l;
 1070         void *v;
 1071         register_t *retval;
 1072 {
 1073         struct linux_sys_setreuid16_args /* {
 1074                 syscallarg(int) ruid;
 1075                 syscallarg(int) euid;
 1076         } */ *uap = v;
 1077         struct sys_setreuid_args bsa;
 1078         
 1079         SCARG(&bsa, ruid) = ((linux_uid_t)SCARG(uap, ruid) == (linux_uid_t)-1) ?
 1080                 (uid_t)-1 : SCARG(uap, ruid);
 1081         SCARG(&bsa, euid) = ((linux_uid_t)SCARG(uap, euid) == (linux_uid_t)-1) ?
 1082                 (uid_t)-1 : SCARG(uap, euid);
 1083 
 1084         return sys_setreuid(l, &bsa, retval);
 1085 }
 1086 
 1087 int
 1088 linux_sys_setregid16(l, v, retval)
 1089         struct lwp *l;
 1090         void *v;
 1091         register_t *retval;
 1092 {
 1093         struct linux_sys_setregid16_args /* {
 1094                 syscallarg(int) rgid;
 1095                 syscallarg(int) egid;
 1096         } */ *uap = v;
 1097         struct sys_setregid_args bsa;
 1098         
 1099         SCARG(&bsa, rgid) = ((linux_gid_t)SCARG(uap, rgid) == (linux_gid_t)-1) ?
 1100                 (uid_t)-1 : SCARG(uap, rgid);
 1101         SCARG(&bsa, egid) = ((linux_gid_t)SCARG(uap, egid) == (linux_gid_t)-1) ?
 1102                 (uid_t)-1 : SCARG(uap, egid);
 1103 
 1104         return sys_setregid(l, &bsa, retval);
 1105 }
 1106 
 1107 int
 1108 linux_sys_setresuid16(l, v, retval)
 1109         struct lwp *l;
 1110         void *v;
 1111         register_t *retval;
 1112 {
 1113         struct linux_sys_setresuid16_args /* {
 1114                 syscallarg(uid_t) ruid;
 1115                 syscallarg(uid_t) euid;
 1116                 syscallarg(uid_t) suid;
 1117         } */ *uap = v;
 1118         struct linux_sys_setresuid16_args lsa;
 1119 
 1120         SCARG(&lsa, ruid) = ((linux_uid_t)SCARG(uap, ruid) == (linux_uid_t)-1) ?
 1121                 (uid_t)-1 : SCARG(uap, ruid);
 1122         SCARG(&lsa, euid) = ((linux_uid_t)SCARG(uap, euid) == (linux_uid_t)-1) ?
 1123                 (uid_t)-1 : SCARG(uap, euid);
 1124         SCARG(&lsa, suid) = ((linux_uid_t)SCARG(uap, suid) == (linux_uid_t)-1) ?
 1125                 (uid_t)-1 : SCARG(uap, suid);
 1126 
 1127         return linux_sys_setresuid(l, &lsa, retval);
 1128 }
 1129 
 1130 int
 1131 linux_sys_setresgid16(l, v, retval)
 1132         struct lwp *l;
 1133         void *v;
 1134         register_t *retval;
 1135 {
 1136         struct linux_sys_setresgid16_args /* {
 1137                 syscallarg(gid_t) rgid;
 1138                 syscallarg(gid_t) egid;
 1139                 syscallarg(gid_t) sgid;
 1140         } */ *uap = v;
 1141         struct linux_sys_setresgid16_args lsa;
 1142 
 1143         SCARG(&lsa, rgid) = ((linux_gid_t)SCARG(uap, rgid) == (linux_gid_t)-1) ?
 1144                 (gid_t)-1 : SCARG(uap, rgid);
 1145         SCARG(&lsa, egid) = ((linux_gid_t)SCARG(uap, egid) == (linux_gid_t)-1) ?
 1146                 (gid_t)-1 : SCARG(uap, egid);
 1147         SCARG(&lsa, sgid) = ((linux_gid_t)SCARG(uap, sgid) == (linux_gid_t)-1) ?
 1148                 (gid_t)-1 : SCARG(uap, sgid);
 1149 
 1150         return linux_sys_setresgid(l, &lsa, retval);
 1151 }
 1152 
 1153 int
 1154 linux_sys_getgroups16(l, v, retval)
 1155         struct lwp *l;
 1156         void *v;
 1157         register_t *retval;
 1158 {
 1159         struct linux_sys_getgroups16_args /* {
 1160                 syscallarg(int) gidsetsize;
 1161                 syscallarg(linux_gid_t *) gidset;
 1162         } */ *uap = v;
 1163         struct proc *p = l->l_proc;
 1164         caddr_t sg; 
 1165         int n, error, i;
 1166         struct sys_getgroups_args bsa;
 1167         gid_t *bset, *kbset;
 1168         linux_gid_t *lset;
 1169         struct pcred *pc = p->p_cred;
 1170 
 1171         n = SCARG(uap, gidsetsize);
 1172         if (n < 0)
 1173                 return EINVAL;
 1174         error = 0;
 1175         bset = kbset = NULL;
 1176         lset = NULL;
 1177         if (n > 0) {
 1178                 n = min(pc->pc_ucred->cr_ngroups, n);
 1179                 sg = stackgap_init(p, 0);
 1180                 bset = stackgap_alloc(p, &sg, n * sizeof (gid_t));
 1181                 kbset = malloc(n * sizeof (gid_t), M_TEMP, M_WAITOK);
 1182                 lset = malloc(n * sizeof (linux_gid_t), M_TEMP, M_WAITOK);
 1183                 if (bset == NULL || kbset == NULL || lset == NULL)
 1184                         return ENOMEM;
 1185                 SCARG(&bsa, gidsetsize) = n;
 1186                 SCARG(&bsa, gidset) = bset;
 1187                 error = sys_getgroups(l, &bsa, retval);
 1188                 if (error != 0)
 1189                         goto out;
 1190                 error = copyin(bset, kbset, n * sizeof (gid_t));
 1191                 if (error != 0)
 1192                         goto out;
 1193                 for (i = 0; i < n; i++)
 1194                         lset[i] = (linux_gid_t)kbset[i];
 1195                 error = copyout(lset, SCARG(uap, gidset),
 1196                     n * sizeof (linux_gid_t));
 1197         } else
 1198                 *retval = pc->pc_ucred->cr_ngroups;
 1199 out:
 1200         if (kbset != NULL)
 1201                 free(kbset, M_TEMP);
 1202         if (lset != NULL)
 1203                 free(lset, M_TEMP);
 1204         return error;
 1205 }
 1206 
 1207 int
 1208 linux_sys_setgroups16(l, v, retval)
 1209         struct lwp *l;
 1210         void *v;
 1211         register_t *retval;
 1212 {
 1213         struct linux_sys_setgroups16_args /* {
 1214                 syscallarg(int) gidsetsize;
 1215                 syscallarg(linux_gid_t *) gidset;
 1216         } */ *uap = v;
 1217         struct proc *p = l->l_proc;
 1218         caddr_t sg;
 1219         int n;
 1220         int error, i;
 1221         struct sys_setgroups_args bsa;
 1222         gid_t *bset, *kbset;
 1223         linux_gid_t *lset;
 1224 
 1225         n = SCARG(uap, gidsetsize);
 1226         if (n < 0 || n > NGROUPS)
 1227                 return EINVAL;
 1228         sg = stackgap_init(p, 0);
 1229         bset = stackgap_alloc(p, &sg, n * sizeof (gid_t));
 1230         lset = malloc(n * sizeof (linux_gid_t), M_TEMP, M_WAITOK);
 1231         kbset = malloc(n * sizeof (gid_t), M_TEMP, M_WAITOK);
 1232         if (lset == NULL || bset == NULL)
 1233                 return ENOMEM;
 1234         error = copyin(SCARG(uap, gidset), lset, n * sizeof (linux_gid_t));
 1235         if (error != 0)
 1236                 goto out;
 1237         for (i = 0; i < n; i++)
 1238                 kbset[i] = (gid_t)lset[i];
 1239         error = copyout(kbset, bset, n * sizeof (gid_t));
 1240         if (error != 0)
 1241                 goto out;
 1242         SCARG(&bsa, gidsetsize) = n;
 1243         SCARG(&bsa, gidset) = bset;
 1244         error = sys_setgroups(l, &bsa, retval);
 1245         
 1246 out:
 1247         if (lset != NULL)
 1248                 free(lset, M_TEMP);
 1249         if (kbset != NULL)
 1250                 free(kbset, M_TEMP);
 1251 
 1252         return error;
 1253 }
 1254 
 1255 #endif /* __i386__ || __m68k__ */
 1256 
 1257 /*
 1258  * We have nonexistent fsuid equal to uid.
 1259  * If modification is requested, refuse.
 1260  */
 1261 int
 1262 linux_sys_setfsuid(l, v, retval)
 1263          struct lwp *l;
 1264          void *v;
 1265          register_t *retval;
 1266 {
 1267          struct linux_sys_setfsuid_args /* {
 1268                  syscallarg(uid_t) uid;
 1269          } */ *uap = v;
 1270          struct proc *p = l->l_proc;
 1271          uid_t uid;
 1272 
 1273          uid = SCARG(uap, uid);
 1274          if (p->p_cred->p_ruid != uid)
 1275                  return sys_nosys(l, v, retval);
 1276          else
 1277                  return (0);
 1278 }
 1279 
 1280 /* XXX XXX XXX */
 1281 #ifndef alpha
 1282 int
 1283 linux_sys_getfsuid(l, v, retval)
 1284         struct lwp *l;
 1285         void *v;
 1286         register_t *retval;
 1287 {
 1288         return sys_getuid(l, v, retval);
 1289 }
 1290 #endif
 1291 
 1292 int
 1293 linux_sys_setresuid(l, v, retval)
 1294         struct lwp *l;
 1295         void *v;
 1296         register_t *retval;
 1297 {
 1298         struct linux_sys_setresuid_args /* {
 1299                 syscallarg(uid_t) ruid;
 1300                 syscallarg(uid_t) euid;
 1301                 syscallarg(uid_t) suid;
 1302         } */ *uap = v;
 1303 
 1304         /*
 1305          * Note: These checks are a little different than the NetBSD
 1306          * setreuid(2) call performs.  This precisely follows the
 1307          * behavior of the Linux kernel.
 1308          */
 1309 
 1310         return do_setresuid(l, SCARG(uap, ruid), SCARG(uap, euid),
 1311                             SCARG(uap, suid),
 1312                             ID_R_EQ_R | ID_R_EQ_E | ID_R_EQ_S |
 1313                             ID_E_EQ_R | ID_E_EQ_E | ID_E_EQ_S |
 1314                             ID_S_EQ_R | ID_S_EQ_E | ID_S_EQ_S );
 1315 }
 1316 
 1317 int
 1318 linux_sys_getresuid(l, v, retval)
 1319         struct lwp *l;
 1320         void *v;
 1321         register_t *retval;
 1322 {
 1323         struct linux_sys_getresuid_args /* {
 1324                 syscallarg(uid_t *) ruid;
 1325                 syscallarg(uid_t *) euid;
 1326                 syscallarg(uid_t *) suid;
 1327         } */ *uap = v;
 1328         struct proc *p = l->l_proc;
 1329         struct pcred *pc = p->p_cred;
 1330         int error;
 1331 
 1332         /*
 1333          * Linux copies these values out to userspace like so:
 1334          *
 1335          *      1. Copy out ruid.
 1336          *      2. If that succeeds, copy out euid.
 1337          *      3. If both of those succeed, copy out suid.
 1338          */
 1339         if ((error = copyout(&pc->p_ruid, SCARG(uap, ruid),
 1340                              sizeof(uid_t))) != 0)
 1341                 return (error);
 1342 
 1343         if ((error = copyout(&pc->pc_ucred->cr_uid, SCARG(uap, euid),
 1344                              sizeof(uid_t))) != 0)
 1345                 return (error);
 1346 
 1347         return (copyout(&pc->p_svuid, SCARG(uap, suid), sizeof(uid_t)));
 1348 }
 1349 
 1350 int
 1351 linux_sys_ptrace(l, v, retval)
 1352         struct lwp *l;
 1353         void *v;
 1354         register_t *retval;
 1355 {
 1356         struct linux_sys_ptrace_args /* {
 1357                 i386, m68k, powerpc: T=int
 1358                 alpha: T=long
 1359                 syscallarg(T) request;
 1360                 syscallarg(T) pid;
 1361                 syscallarg(T) addr;
 1362                 syscallarg(T) data;
 1363         } */ *uap = v;
 1364         const int *ptr;
 1365         int request;
 1366         int error;
 1367 
 1368         ptr = linux_ptrace_request_map;
 1369         request = SCARG(uap, request);
 1370         while (*ptr != -1)
 1371                 if (*ptr++ == request) {
 1372                         struct sys_ptrace_args pta;
 1373 
 1374                         SCARG(&pta, req) = *ptr;
 1375                         SCARG(&pta, pid) = SCARG(uap, pid);
 1376                         SCARG(&pta, addr) = (caddr_t)SCARG(uap, addr);
 1377                         SCARG(&pta, data) = SCARG(uap, data);
 1378 
 1379                         /*
 1380                          * Linux ptrace(PTRACE_CONT, pid, 0, 0) means actually
 1381                          * to continue where the process left off previously.
 1382                          * The same thing is achieved by addr == (caddr_t) 1
 1383                          * on NetBSD, so rewrite 'addr' appropriately.
 1384                          */
 1385                         if (request == LINUX_PTRACE_CONT && SCARG(uap, addr)==0)
 1386                                 SCARG(&pta, addr) = (caddr_t) 1;
 1387                         
 1388                         error = sys_ptrace(l, &pta, retval);
 1389                         if (error) 
 1390                                 return error;
 1391                         switch (request) {
 1392                         case LINUX_PTRACE_PEEKTEXT:
 1393                         case LINUX_PTRACE_PEEKDATA:
 1394                                 error = copyout (retval, 
 1395                                     (caddr_t)SCARG(uap, data), sizeof *retval);
 1396                                 *retval = SCARG(uap, data);
 1397                                 break;
 1398                         default:        
 1399                                 break;
 1400                         }
 1401                         return error;
 1402                 }
 1403                 else
 1404                         ptr++;
 1405 
 1406         return LINUX_SYS_PTRACE_ARCH(l, uap, retval);
 1407 }
 1408 
 1409 int
 1410 linux_sys_reboot(struct lwp *l, void *v, register_t *retval)
 1411 {
 1412         struct linux_sys_reboot_args /* {
 1413                 syscallarg(int) magic1;
 1414                 syscallarg(int) magic2;
 1415                 syscallarg(int) cmd;
 1416                 syscallarg(void *) arg;
 1417         } */ *uap = v;
 1418         struct sys_reboot_args /* {
 1419                 syscallarg(int) opt;
 1420                 syscallarg(char *) bootstr;
 1421         } */ sra;
 1422         struct proc *p = l->l_proc;
 1423         int error;
 1424 
 1425         if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
 1426                 return(error);
 1427 
 1428         if (SCARG(uap, magic1) != LINUX_REBOOT_MAGIC1)
 1429                 return(EINVAL);
 1430         if (SCARG(uap, magic2) != LINUX_REBOOT_MAGIC2 &&
 1431             SCARG(uap, magic2) != LINUX_REBOOT_MAGIC2A &&
 1432             SCARG(uap, magic2) != LINUX_REBOOT_MAGIC2B)
 1433                 return(EINVAL);
 1434 
 1435         switch (SCARG(uap, cmd)) {
 1436         case LINUX_REBOOT_CMD_RESTART:
 1437                 SCARG(&sra, opt) = RB_AUTOBOOT;
 1438                 break;
 1439         case LINUX_REBOOT_CMD_HALT:
 1440                 SCARG(&sra, opt) = RB_HALT;
 1441                 break;
 1442         case LINUX_REBOOT_CMD_POWER_OFF:
 1443                 SCARG(&sra, opt) = RB_HALT|RB_POWERDOWN;
 1444                 break;
 1445         case LINUX_REBOOT_CMD_RESTART2:
 1446                 /* Reboot with an argument. */
 1447                 SCARG(&sra, opt) = RB_AUTOBOOT|RB_STRING;
 1448                 SCARG(&sra, bootstr) = SCARG(uap, arg);
 1449                 break;
 1450         case LINUX_REBOOT_CMD_CAD_ON:
 1451                 return(EINVAL); /* We don't implement ctrl-alt-delete */
 1452         case LINUX_REBOOT_CMD_CAD_OFF:
 1453                 return(0);
 1454         default:
 1455                 return(EINVAL);
 1456         }
 1457 
 1458         return(sys_reboot(l, &sra, retval));
 1459 }
 1460 
 1461 /*
 1462  * Copy of compat_12_sys_swapon().
 1463  */
 1464 int
 1465 linux_sys_swapon(l, v, retval)
 1466         struct lwp *l;
 1467         void *v;
 1468         register_t *retval;
 1469 {
 1470         struct sys_swapctl_args ua;
 1471         struct linux_sys_swapon_args /* {
 1472                 syscallarg(const char *) name;
 1473         } */ *uap = v;
 1474 
 1475         SCARG(&ua, cmd) = SWAP_ON;
 1476         SCARG(&ua, arg) = (void *)SCARG(uap, name);
 1477         SCARG(&ua, misc) = 0;   /* priority */
 1478         return (sys_swapctl(l, &ua, retval));
 1479 }
 1480 
 1481 /*
 1482  * Stop swapping to the file or block device specified by path.
 1483  */
 1484 int
 1485 linux_sys_swapoff(l, v, retval)
 1486         struct lwp *l;
 1487         void *v;
 1488         register_t *retval;
 1489 {
 1490         struct sys_swapctl_args ua;
 1491         struct linux_sys_swapoff_args /* {
 1492                 syscallarg(const char *) path;
 1493         } */ *uap = v;
 1494 
 1495         SCARG(&ua, cmd) = SWAP_OFF;
 1496         SCARG(&ua, arg) = (void *)SCARG(uap, path);
 1497         return (sys_swapctl(l, &ua, retval));
 1498 }
 1499 
 1500 /*
 1501  * Copy of compat_09_sys_setdomainname()
 1502  */
 1503 /* ARGSUSED */
 1504 int
 1505 linux_sys_setdomainname(l, v, retval)
 1506         struct lwp *l;
 1507         void *v;
 1508         register_t *retval;
 1509 {
 1510         struct linux_sys_setdomainname_args /* {
 1511                 syscallarg(char *) domainname;
 1512                 syscallarg(int) len;
 1513         } */ *uap = v;
 1514         int name[2];
 1515 
 1516         name[0] = CTL_KERN;
 1517         name[1] = KERN_DOMAINNAME;
 1518         return (old_sysctl(&name[0], 2, 0, 0, SCARG(uap, domainname),
 1519                             SCARG(uap, len), l));
 1520 }
 1521 
 1522 /*
 1523  * sysinfo()
 1524  */
 1525 /* ARGSUSED */
 1526 int
 1527 linux_sys_sysinfo(l, v, retval)
 1528         struct lwp *l;
 1529         void *v;
 1530         register_t *retval;
 1531 {
 1532         struct linux_sys_sysinfo_args /* {
 1533                 syscallarg(struct linux_sysinfo *) arg;
 1534         } */ *uap = v;
 1535         struct linux_sysinfo si;
 1536         struct loadavg *la;
 1537 
 1538         si.uptime = time.tv_sec - boottime.tv_sec;
 1539         la = &averunnable;
 1540         si.loads[0] = la->ldavg[0] * LINUX_SYSINFO_LOADS_SCALE / la->fscale;
 1541         si.loads[1] = la->ldavg[1] * LINUX_SYSINFO_LOADS_SCALE / la->fscale;
 1542         si.loads[2] = la->ldavg[2] * LINUX_SYSINFO_LOADS_SCALE / la->fscale;
 1543         si.totalram = ctob(physmem);
 1544         si.freeram = uvmexp.free * uvmexp.pagesize;
 1545         si.sharedram = 0;       /* XXX */
 1546         si.bufferram = uvmexp.filepages * uvmexp.pagesize;
 1547         si.totalswap = uvmexp.swpages * uvmexp.pagesize;
 1548         si.freeswap = (uvmexp.swpages - uvmexp.swpginuse) * uvmexp.pagesize;
 1549         si.procs = nprocs;
 1550 
 1551         /* The following are only present in newer Linux kernels. */
 1552         si.totalbig = 0;
 1553         si.freebig = 0;
 1554         si.mem_unit = 1;
 1555 
 1556         return (copyout(&si, SCARG(uap, arg), sizeof si));
 1557 }
 1558 
 1559 #define bsd_to_linux_rlimit1(l, b, f) \
 1560     (l)->f = ((b)->f == RLIM_INFINITY || \
 1561              ((b)->f & 0xffffffff00000000ULL) != 0) ? \
 1562     LINUX_RLIM_INFINITY : (int32_t)(b)->f
 1563 #define bsd_to_linux_rlimit(l, b) \
 1564     bsd_to_linux_rlimit1(l, b, rlim_cur); \
 1565     bsd_to_linux_rlimit1(l, b, rlim_max)
 1566 
 1567 #define linux_to_bsd_rlimit1(b, l, f) \
 1568     (b)->f = (l)->f == LINUX_RLIM_INFINITY ? RLIM_INFINITY : (l)->f
 1569 #define linux_to_bsd_rlimit(b, l) \
 1570     linux_to_bsd_rlimit1(b, l, rlim_cur); \
 1571     linux_to_bsd_rlimit1(b, l, rlim_max)
 1572 
 1573 static int
 1574 linux_to_bsd_limit(lim)
 1575         int lim;
 1576 {
 1577         switch (lim) {
 1578         case LINUX_RLIMIT_CPU:
 1579                 return RLIMIT_CPU;
 1580         case LINUX_RLIMIT_FSIZE:
 1581                 return RLIMIT_FSIZE;
 1582         case LINUX_RLIMIT_DATA:
 1583                 return RLIMIT_DATA;
 1584         case LINUX_RLIMIT_STACK:
 1585                 return RLIMIT_STACK;
 1586         case LINUX_RLIMIT_CORE:
 1587                 return RLIMIT_CORE;
 1588         case LINUX_RLIMIT_RSS:
 1589                 return RLIMIT_RSS;
 1590         case LINUX_RLIMIT_NPROC:
 1591                 return RLIMIT_NPROC;
 1592         case LINUX_RLIMIT_NOFILE:
 1593                 return RLIMIT_NOFILE;
 1594         case LINUX_RLIMIT_MEMLOCK:
 1595                 return RLIMIT_MEMLOCK;
 1596         case LINUX_RLIMIT_AS:
 1597         case LINUX_RLIMIT_LOCKS:
 1598                 return -EOPNOTSUPP;
 1599         default:
 1600                 return -EINVAL;
 1601         }
 1602 }
 1603 
 1604 
 1605 int
 1606 linux_sys_getrlimit(l, v, retval)
 1607         struct lwp *l;
 1608         void *v;
 1609         register_t *retval;
 1610 {
 1611         struct linux_sys_getrlimit_args /* {
 1612                 syscallarg(int) which;
 1613                 syscallarg(struct orlimit *) rlp;
 1614         } */ *uap = v;
 1615         struct proc *p = l->l_proc;
 1616         caddr_t sg = stackgap_init(p, 0);
 1617         struct sys_getrlimit_args ap;
 1618         struct rlimit rl;
 1619         struct orlimit orl;
 1620         int error;
 1621 
 1622         SCARG(&ap, which) = linux_to_bsd_limit(SCARG(uap, which));
 1623         if ((error = SCARG(&ap, which)) < 0)
 1624                 return -error;
 1625         SCARG(&ap, rlp) = stackgap_alloc(p, &sg, sizeof rl);
 1626         if ((error = sys_getrlimit(l, &ap, retval)) != 0)
 1627                 return error;
 1628         if ((error = copyin(SCARG(&ap, rlp), &rl, sizeof(rl))) != 0)
 1629                 return error;
 1630         bsd_to_linux_rlimit(&orl, &rl);
 1631         return copyout(&orl, SCARG(uap, rlp), sizeof(orl));
 1632 }
 1633 
 1634 int
 1635 linux_sys_setrlimit(l, v, retval)
 1636         struct lwp *l;
 1637         void *v;
 1638         register_t *retval;
 1639 {
 1640         struct linux_sys_setrlimit_args /* {
 1641                 syscallarg(int) which;
 1642                 syscallarg(struct orlimit *) rlp;
 1643         } */ *uap = v;
 1644         struct proc *p = l->l_proc;
 1645         caddr_t sg = stackgap_init(p, 0);
 1646         struct sys_setrlimit_args ap;
 1647         struct rlimit rl;
 1648         struct orlimit orl;
 1649         int error;
 1650 
 1651         SCARG(&ap, which) = linux_to_bsd_limit(SCARG(uap, which));
 1652         SCARG(&ap, rlp) = stackgap_alloc(p, &sg, sizeof rl);
 1653         if ((error = SCARG(&ap, which)) < 0)
 1654                 return -error;
 1655         if ((error = copyin(SCARG(uap, rlp), &orl, sizeof(orl))) != 0)
 1656                 return error;
 1657         linux_to_bsd_rlimit(&rl, &orl);
 1658         /* XXX: alpha complains about this */
 1659         if ((error = copyout(&rl, (void *)SCARG(&ap, rlp), sizeof(rl))) != 0)
 1660                 return error;
 1661         return sys_setrlimit(l, &ap, retval);
 1662 }
 1663 
 1664 #ifndef __mips__
 1665 /* XXX: this doesn't look 100% common, at least mips doesn't have it */
 1666 int
 1667 linux_sys_ugetrlimit(l, v, retval)
 1668         struct lwp *l;
 1669         void *v;
 1670         register_t *retval;
 1671 {
 1672         return linux_sys_getrlimit(l, v, retval);
 1673 }
 1674 #endif
 1675 
 1676 /*
 1677  * This gets called for unsupported syscalls. The difference to sys_nosys()
 1678  * is that process does not get SIGSYS, the call just returns with ENOSYS.
 1679  * This is the way Linux does it and glibc depends on this behaviour.
 1680  */
 1681 int
 1682 linux_sys_nosys(l, v, retval)
 1683         struct lwp *l;
 1684         void *v;
 1685         register_t *retval;
 1686 {
 1687         return (ENOSYS);
 1688 }

Cache object: fc16f088879c2f74655d34dd684bb682


[ 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.