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/i386/ibcs2/ibcs2_misc.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 1995 Steven Wallace
    3  * Copyright (c) 1994, 1995 Scott Bartram
    4  * Copyright (c) 1992, 1993
    5  *      The Regents of the University of California.  All rights reserved.
    6  *
    7  * This software was developed by the Computer Systems Engineering group
    8  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
    9  * contributed to Berkeley.
   10  *
   11  * All advertising materials mentioning features or use of this software
   12  * must display the following acknowledgement:
   13  *      This product includes software developed by the University of
   14  *      California, Lawrence Berkeley Laboratory.
   15  *
   16  * Redistribution and use in source and binary forms, with or without
   17  * modification, are permitted provided that the following conditions
   18  * are met:
   19  * 1. Redistributions of source code must retain the above copyright
   20  *    notice, this list of conditions and the following disclaimer.
   21  * 2. Redistributions in binary form must reproduce the above copyright
   22  *    notice, this list of conditions and the following disclaimer in the
   23  *    documentation and/or other materials provided with the distribution.
   24  * 3. All advertising materials mentioning features or use of this software
   25  *    must display the following acknowledgement:
   26  *      This product includes software developed by the University of
   27  *      California, Berkeley and its contributors.
   28  * 4. Neither the name of the University nor the names of its contributors
   29  *    may be used to endorse or promote products derived from this software
   30  *    without specific prior written permission.
   31  *
   32  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   33  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   34  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   35  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   36  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   40  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   41  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   42  * SUCH DAMAGE.
   43  *
   44  * from: Header: sun_misc.c,v 1.16 93/04/07 02:46:27 torek Exp 
   45  *
   46  *      @(#)sun_misc.c  8.1 (Berkeley) 6/18/93
   47  *
   48  * $FreeBSD: stable/3/sys/i386/ibcs2/ibcs2_misc.c 50582 1999-08-29 16:07:53Z peter $
   49  */
   50 
   51 /*
   52  * IBCS2 compatibility module.
   53  *
   54  * IBCS2 system calls that are implemented differently in BSD are
   55  * handled here.
   56  */
   57 #include <sys/param.h>
   58 #include <sys/dirent.h>
   59 #include <sys/fcntl.h>
   60 #include <sys/file.h>
   61 #include <sys/filedesc.h>
   62 #include <sys/kernel.h>
   63 #include <sys/lock.h>
   64 #include <sys/malloc.h>
   65 #include <sys/reboot.h>
   66 #include <sys/resourcevar.h>
   67 #include <sys/stat.h>
   68 #include <sys/sysctl.h>
   69 #include <sys/sysproto.h>
   70 #include <sys/systm.h>
   71 #include <sys/time.h>
   72 #include <sys/times.h>
   73 #include <sys/vnode.h>
   74 #include <sys/wait.h>
   75 
   76 #include <machine/cpu.h>
   77 
   78 #include <i386/ibcs2/ibcs2_dirent.h>
   79 #include <i386/ibcs2/ibcs2_signal.h>
   80 #include <i386/ibcs2/ibcs2_proto.h>
   81 #include <i386/ibcs2/ibcs2_unistd.h>
   82 #include <i386/ibcs2/ibcs2_util.h>
   83 #include <i386/ibcs2/ibcs2_utime.h>
   84 #include <i386/ibcs2/ibcs2_xenix.h>
   85 
   86 int
   87 ibcs2_ulimit(p, uap)
   88         struct proc *p;
   89         struct ibcs2_ulimit_args *uap;
   90 {
   91 #ifdef notyet
   92         int error;
   93         struct rlimit rl;
   94         struct setrlimit_args {
   95                 int resource;
   96                 struct rlimit *rlp;
   97         } sra;
   98 #endif
   99 #define IBCS2_GETFSIZE          1
  100 #define IBCS2_SETFSIZE          2
  101 #define IBCS2_GETPSIZE          3
  102 #define IBCS2_GETDTABLESIZE     4
  103         
  104         switch (SCARG(uap, cmd)) {
  105         case IBCS2_GETFSIZE:
  106                 p->p_retval[0] = p->p_rlimit[RLIMIT_FSIZE].rlim_cur;
  107                 if (p->p_retval[0] == -1) p->p_retval[0] = 0x7fffffff;
  108                 return 0;
  109         case IBCS2_SETFSIZE:    /* XXX - fix this */
  110 #ifdef notyet
  111                 rl.rlim_cur = SCARG(uap, newlimit);
  112                 sra.resource = RLIMIT_FSIZE;
  113                 sra.rlp = &rl;
  114                 error = setrlimit(p, &sra);
  115                 if (!error)
  116                         p->p_retval[0] = p->p_rlimit[RLIMIT_FSIZE].rlim_cur;
  117                 else
  118                         DPRINTF(("failed "));
  119                 return error;
  120 #else
  121                 p->p_retval[0] = SCARG(uap, newlimit);
  122                 return 0;
  123 #endif
  124         case IBCS2_GETPSIZE:
  125                 p->p_retval[0] = p->p_rlimit[RLIMIT_RSS].rlim_cur; /* XXX */
  126                 return 0;
  127         case IBCS2_GETDTABLESIZE:
  128                 uap->cmd = IBCS2_SC_OPEN_MAX;
  129                 return ibcs2_sysconf(p, (struct ibcs2_sysconf_args *)uap);
  130         default:
  131                 return ENOSYS;
  132         }
  133 }
  134 
  135 #define IBCS2_WSTOPPED       0177
  136 #define IBCS2_STOPCODE(sig)  ((sig) << 8 | IBCS2_WSTOPPED)
  137 int
  138 ibcs2_wait(p, uap)
  139         struct proc *p;
  140         struct ibcs2_wait_args *uap;
  141 {
  142         int error, status;
  143         struct wait_args w4;
  144         struct trapframe *tf = p->p_md.md_regs;
  145         
  146         SCARG(&w4, rusage) = NULL;
  147         if ((tf->tf_eflags & (PSL_Z|PSL_PF|PSL_N|PSL_V))
  148             == (PSL_Z|PSL_PF|PSL_N|PSL_V)) {
  149                 /* waitpid */
  150                 SCARG(&w4, pid) = SCARG(uap, a1);
  151                 SCARG(&w4, status) = (int *)SCARG(uap, a2);
  152                 SCARG(&w4, options) = SCARG(uap, a3);
  153         } else {
  154                 /* wait */
  155                 SCARG(&w4, pid) = WAIT_ANY;
  156                 SCARG(&w4, status) = (int *)SCARG(uap, a1);
  157                 SCARG(&w4, options) = 0;
  158         }
  159         if ((error = wait4(p, &w4)) != 0)
  160                 return error;
  161         if (SCARG(&w4, status)) {       /* this is real iBCS brain-damage */
  162                 error = copyin((caddr_t)SCARG(&w4, status), (caddr_t)&status,
  163                                sizeof(SCARG(&w4, status)));
  164                 if(error)
  165                   return error;
  166 
  167                 /* convert status/signal result */
  168                 if(WIFSTOPPED(status))
  169                         status =
  170                           IBCS2_STOPCODE(bsd_to_ibcs2_sig[WSTOPSIG(status)]);
  171                 else if(WIFSIGNALED(status))
  172                         status = bsd_to_ibcs2_sig[WTERMSIG(status)];
  173                 /* else exit status -- identical */
  174 
  175                 /* record result/status */
  176                 p->p_retval[1] = status;
  177                 return copyout((caddr_t)&status, (caddr_t)SCARG(&w4, status),
  178                                sizeof(SCARG(&w4, status)));
  179         }
  180 
  181         return 0;
  182 }
  183 
  184 int
  185 ibcs2_execv(p, uap)
  186         struct proc *p;
  187         struct ibcs2_execv_args *uap;
  188 {
  189         struct execve_args ea;
  190         caddr_t sg = stackgap_init();
  191 
  192         CHECKALTEXIST(p, &sg, SCARG(uap, path));
  193         SCARG(&ea, fname) = SCARG(uap, path);
  194         SCARG(&ea, argv) = SCARG(uap, argp);
  195         SCARG(&ea, envv) = NULL;
  196         return execve(p, &ea);
  197 }
  198 
  199 int
  200 ibcs2_execve(p, uap) 
  201         struct proc *p;
  202         struct ibcs2_execve_args *uap;
  203 {
  204         caddr_t sg = stackgap_init();
  205         CHECKALTEXIST(p, &sg, SCARG(uap, path));
  206         return execve(p, (struct execve_args *)uap);
  207 }
  208 
  209 int
  210 ibcs2_umount(p, uap)
  211         struct proc *p;
  212         struct ibcs2_umount_args *uap;
  213 {
  214         struct unmount_args um;
  215 
  216         SCARG(&um, path) = SCARG(uap, name);
  217         SCARG(&um, flags) = 0;
  218         return unmount(p, &um);
  219 }
  220 
  221 int
  222 ibcs2_mount(p, uap)
  223         struct proc *p;
  224         struct ibcs2_mount_args *uap;
  225 {
  226 #ifdef notyet
  227         int oflags = SCARG(uap, flags), nflags, error;
  228         char fsname[MFSNAMELEN];
  229 
  230         if (oflags & (IBCS2_MS_NOSUB | IBCS2_MS_SYS5))
  231                 return (EINVAL);
  232         if ((oflags & IBCS2_MS_NEWTYPE) == 0)
  233                 return (EINVAL);
  234         nflags = 0;
  235         if (oflags & IBCS2_MS_RDONLY)
  236                 nflags |= MNT_RDONLY;
  237         if (oflags & IBCS2_MS_NOSUID)
  238                 nflags |= MNT_NOSUID;
  239         if (oflags & IBCS2_MS_REMOUNT)
  240                 nflags |= MNT_UPDATE;
  241         SCARG(uap, flags) = nflags;
  242 
  243         if (error = copyinstr((caddr_t)SCARG(uap, type), fsname, sizeof fsname,
  244                               (u_int *)0))
  245                 return (error);
  246 
  247         if (strcmp(fsname, "4.2") == 0) {
  248                 SCARG(uap, type) = (caddr_t)STACK_ALLOC();
  249                 if (error = copyout("ufs", SCARG(uap, type), sizeof("ufs")))
  250                         return (error);
  251         } else if (strcmp(fsname, "nfs") == 0) {
  252                 struct ibcs2_nfs_args sna;
  253                 struct sockaddr_in sain;
  254                 struct nfs_args na;
  255                 struct sockaddr sa;
  256 
  257                 if (error = copyin(SCARG(uap, data), &sna, sizeof sna))
  258                         return (error);
  259                 if (error = copyin(sna.addr, &sain, sizeof sain))
  260                         return (error);
  261                 bcopy(&sain, &sa, sizeof sa);
  262                 sa.sa_len = sizeof(sain);
  263                 SCARG(uap, data) = (caddr_t)STACK_ALLOC();
  264                 na.addr = (struct sockaddr *)((int)SCARG(uap, data) + sizeof na);
  265                 na.sotype = SOCK_DGRAM;
  266                 na.proto = IPPROTO_UDP;
  267                 na.fh = (nfsv2fh_t *)sna.fh;
  268                 na.flags = sna.flags;
  269                 na.wsize = sna.wsize;
  270                 na.rsize = sna.rsize;
  271                 na.timeo = sna.timeo;
  272                 na.retrans = sna.retrans;
  273                 na.hostname = sna.hostname;
  274 
  275                 if (error = copyout(&sa, na.addr, sizeof sa))
  276                         return (error);
  277                 if (error = copyout(&na, SCARG(uap, data), sizeof na))
  278                         return (error);
  279         }
  280         return (mount(p, uap));
  281 #else
  282         return EINVAL;
  283 #endif
  284 }
  285 
  286 /*
  287  * Read iBCS2-style directory entries.  We suck them into kernel space so
  288  * that they can be massaged before being copied out to user code.  Like
  289  * SunOS, we squish out `empty' entries.
  290  *
  291  * This is quite ugly, but what do you expect from compatibility code?
  292  */
  293 
  294 int
  295 ibcs2_getdents(p, uap)
  296         struct proc *p;
  297         register struct ibcs2_getdents_args *uap;
  298 {
  299         register struct vnode *vp;
  300         register caddr_t inp, buf;      /* BSD-format */
  301         register int len, reclen;       /* BSD-format */
  302         register caddr_t outp;          /* iBCS2-format */
  303         register int resid;             /* iBCS2-format */
  304         struct file *fp;
  305         struct uio auio;
  306         struct iovec aiov;
  307         struct ibcs2_dirent idb;
  308         off_t off;                      /* true file offset */
  309         int buflen, error, eofflag;
  310         u_long *cookies = NULL, *cookiep;
  311         int ncookies;
  312 #define BSD_DIRENT(cp)          ((struct dirent *)(cp))
  313 #define IBCS2_RECLEN(reclen)    (reclen + sizeof(u_short))
  314 
  315         if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
  316                 return (error);
  317         if ((fp->f_flag & FREAD) == 0)
  318                 return (EBADF);
  319         vp = (struct vnode *)fp->f_data;
  320         if (vp->v_type != VDIR) /* XXX  vnode readdir op should do this */
  321                 return (EINVAL);
  322 
  323         off = fp->f_offset;
  324 #define DIRBLKSIZ       512             /* XXX we used to use ufs's DIRBLKSIZ */
  325         buflen = max(DIRBLKSIZ, SCARG(uap, nbytes));
  326         buflen = min(buflen, MAXBSIZE);
  327         buf = malloc(buflen, M_TEMP, M_WAITOK);
  328         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
  329 again:
  330         aiov.iov_base = buf;
  331         aiov.iov_len = buflen;
  332         auio.uio_iov = &aiov;
  333         auio.uio_iovcnt = 1;
  334         auio.uio_rw = UIO_READ;
  335         auio.uio_segflg = UIO_SYSSPACE;
  336         auio.uio_procp = p;
  337         auio.uio_resid = buflen;
  338         auio.uio_offset = off;
  339 
  340         if (cookies) {
  341                 free(cookies, M_TEMP);
  342                 cookies = NULL;
  343         }
  344 
  345         /*
  346          * First we read into the malloc'ed buffer, then
  347          * we massage it into user space, one record at a time.
  348          */
  349         if (error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, &cookies))
  350                 goto out;
  351         inp = buf;
  352         outp = SCARG(uap, buf);
  353         resid = SCARG(uap, nbytes);
  354         if ((len = buflen - auio.uio_resid) <= 0)
  355                 goto eof;
  356 
  357         cookiep = cookies;
  358 
  359         if (cookies) {
  360                 /*
  361                  * When using cookies, the vfs has the option of reading from
  362                  * a different offset than that supplied (UFS truncates the
  363                  * offset to a block boundary to make sure that it never reads
  364                  * partway through a directory entry, even if the directory
  365                  * has been compacted).
  366                  */
  367                 while (len > 0 && ncookies > 0 && *cookiep <= off) {
  368                         len -= BSD_DIRENT(inp)->d_reclen;
  369                         inp += BSD_DIRENT(inp)->d_reclen;
  370                         cookiep++;
  371                         ncookies--;
  372                 }
  373         }
  374 
  375         for (; len > 0; len -= reclen) {
  376                 if (cookiep && ncookies == 0)
  377                         break;
  378                 reclen = BSD_DIRENT(inp)->d_reclen;
  379                 if (reclen & 3) {
  380                         printf("ibcs2_getdents: reclen=%d\n", reclen);
  381                         error = EFAULT;
  382                         goto out;
  383                 }
  384                 if (BSD_DIRENT(inp)->d_fileno == 0) {
  385                         inp += reclen;  /* it is a hole; squish it out */
  386                         if (cookiep) {
  387                                 off = *cookiep++;
  388                                 ncookies--;
  389                         } else
  390                                 off += reclen;
  391                         continue;
  392                 }
  393                 if (reclen > len || resid < IBCS2_RECLEN(reclen)) {
  394                         /* entry too big for buffer, so just stop */
  395                         outp++;
  396                         break;
  397                 }
  398                 /*
  399                  * Massage in place to make a iBCS2-shaped dirent (otherwise
  400                  * we have to worry about touching user memory outside of
  401                  * the copyout() call).
  402                  */
  403                 idb.d_ino = (ibcs2_ino_t)BSD_DIRENT(inp)->d_fileno;
  404                 idb.d_off = (ibcs2_off_t)off;
  405                 idb.d_reclen = (u_short)IBCS2_RECLEN(reclen);
  406                 if ((error = copyout((caddr_t)&idb, outp, 10)) != 0 ||
  407                     (error = copyout(BSD_DIRENT(inp)->d_name, outp + 10,
  408                                      BSD_DIRENT(inp)->d_namlen + 1)) != 0)
  409                         goto out;
  410                 /* advance past this real entry */
  411                 if (cookiep) {
  412                         off = *cookiep++;
  413                         ncookies--;
  414                 } else
  415                         off += reclen;
  416                 inp += reclen;
  417                 /* advance output past iBCS2-shaped entry */
  418                 outp += IBCS2_RECLEN(reclen);
  419                 resid -= IBCS2_RECLEN(reclen);
  420         }
  421         /* if we squished out the whole block, try again */
  422         if (outp == SCARG(uap, buf))
  423                 goto again;
  424         fp->f_offset = off;             /* update the vnode offset */
  425 eof:
  426         p->p_retval[0] = SCARG(uap, nbytes) - resid;
  427 out:
  428         if (cookies)
  429                 free(cookies, M_TEMP);
  430         VOP_UNLOCK(vp, 0, p);
  431         free(buf, M_TEMP);
  432         return (error);
  433 }
  434 
  435 int
  436 ibcs2_read(p, uap)
  437         struct proc *p;
  438         struct ibcs2_read_args *uap;
  439 {
  440         register struct vnode *vp;
  441         register caddr_t inp, buf;      /* BSD-format */
  442         register int len, reclen;       /* BSD-format */
  443         register caddr_t outp;          /* iBCS2-format */
  444         register int resid;             /* iBCS2-format */
  445         struct file *fp;
  446         struct uio auio;
  447         struct iovec aiov;
  448         struct ibcs2_direct {
  449                 ibcs2_ino_t ino;
  450                 char name[14];
  451         } idb;
  452         off_t off;                      /* true file offset */
  453         int buflen, error, eofflag, size;
  454         u_long *cookies = NULL, *cookiep;
  455         int ncookies;
  456 
  457         if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) {
  458                 if (error == EINVAL)
  459                         return read(p, (struct read_args *)uap);
  460                 else
  461                         return error;
  462         }
  463         if ((fp->f_flag & FREAD) == 0)
  464                 return (EBADF);
  465         vp = (struct vnode *)fp->f_data;
  466         if (vp->v_type != VDIR)
  467                 return read(p, (struct read_args *)uap);
  468 
  469         DPRINTF(("ibcs2_read: read directory\n"));
  470 
  471         off = fp->f_offset;
  472         buflen = max(DIRBLKSIZ, SCARG(uap, nbytes));
  473         buflen = min(buflen, MAXBSIZE);
  474         buf = malloc(buflen, M_TEMP, M_WAITOK);
  475         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
  476 again:
  477         aiov.iov_base = buf;
  478         aiov.iov_len = buflen;
  479         auio.uio_iov = &aiov;
  480         auio.uio_iovcnt = 1;
  481         auio.uio_rw = UIO_READ;
  482         auio.uio_segflg = UIO_SYSSPACE;
  483         auio.uio_procp = p;
  484         auio.uio_resid = buflen;
  485         auio.uio_offset = off;
  486 
  487         if (cookies) {
  488                 free(cookies, M_TEMP);
  489                 cookies = NULL;
  490         }
  491 
  492         /*
  493          * First we read into the malloc'ed buffer, then
  494          * we massage it into user space, one record at a time.
  495          */
  496         if (error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, &cookies)) {
  497                 DPRINTF(("VOP_READDIR failed: %d\n", error));
  498                 goto out;
  499         }
  500         inp = buf;
  501         outp = SCARG(uap, buf);
  502         resid = SCARG(uap, nbytes);
  503         if ((len = buflen - auio.uio_resid) <= 0)
  504                 goto eof;
  505 
  506         cookiep = cookies;
  507 
  508         if (cookies) {
  509                 /*
  510                  * When using cookies, the vfs has the option of reading from
  511                  * a different offset than that supplied (UFS truncates the
  512                  * offset to a block boundary to make sure that it never reads
  513                  * partway through a directory entry, even if the directory
  514                  * has been compacted).
  515                  */
  516                 while (len > 0 && ncookies > 0 && *cookiep <= off) {
  517                         len -= BSD_DIRENT(inp)->d_reclen;
  518                         inp += BSD_DIRENT(inp)->d_reclen;
  519                         cookiep++;
  520                         ncookies--;
  521                 }
  522         }
  523 
  524         for (; len > 0 && resid > 0; len -= reclen) {
  525                 if (cookiep && ncookies == 0)
  526                         break;
  527                 reclen = BSD_DIRENT(inp)->d_reclen;
  528                 if (reclen & 3) {
  529                         printf("ibcs2_read: reclen=%d\n", reclen);
  530                         error = EFAULT;
  531                         goto out;
  532                 }
  533                 if (BSD_DIRENT(inp)->d_fileno == 0) {
  534                         inp += reclen;  /* it is a hole; squish it out */
  535                         if (cookiep) {
  536                                 off = *cookiep++;
  537                                 ncookies--;
  538                         } else
  539                                 off += reclen;
  540                         continue;
  541                 }
  542                 if (reclen > len || resid < sizeof(struct ibcs2_direct)) {
  543                         /* entry too big for buffer, so just stop */
  544                         outp++;
  545                         break;
  546                 }
  547                 /*
  548                  * Massage in place to make a iBCS2-shaped dirent (otherwise
  549                  * we have to worry about touching user memory outside of
  550                  * the copyout() call).
  551                  *
  552                  * TODO: if length(filename) > 14, then break filename into
  553                  * multiple entries and set inode = 0xffff except last
  554                  */
  555                 idb.ino = (BSD_DIRENT(inp)->d_fileno > 0xfffe) ? 0xfffe :
  556                         BSD_DIRENT(inp)->d_fileno;
  557                 (void)copystr(BSD_DIRENT(inp)->d_name, idb.name, 14, &size);
  558                 bzero(idb.name + size, 14 - size);
  559                 if (error = copyout(&idb, outp, sizeof(struct ibcs2_direct)))
  560                         goto out;
  561                 /* advance past this real entry */
  562                 if (cookiep) {
  563                         off = *cookiep++;
  564                         ncookies--;
  565                 } else
  566                         off += reclen;
  567                 inp += reclen;
  568                 /* advance output past iBCS2-shaped entry */
  569                 outp += sizeof(struct ibcs2_direct);
  570                 resid -= sizeof(struct ibcs2_direct);
  571         }
  572         /* if we squished out the whole block, try again */
  573         if (outp == SCARG(uap, buf))
  574                 goto again;
  575         fp->f_offset = off;             /* update the vnode offset */
  576 eof:
  577         p->p_retval[0] = SCARG(uap, nbytes) - resid;
  578 out:
  579         if (cookies)
  580                 free(cookies, M_TEMP);
  581         VOP_UNLOCK(vp, 0, p);
  582         free(buf, M_TEMP);
  583         return (error);
  584 }
  585 
  586 int
  587 ibcs2_mknod(p, uap)
  588         struct proc *p;
  589         struct ibcs2_mknod_args *uap;
  590 {
  591         caddr_t sg = stackgap_init();
  592 
  593         CHECKALTCREAT(p, &sg, SCARG(uap, path));
  594         if (S_ISFIFO(SCARG(uap, mode))) {
  595                 struct mkfifo_args ap;
  596                 SCARG(&ap, path) = SCARG(uap, path);
  597                 SCARG(&ap, mode) = SCARG(uap, mode);
  598                 return mkfifo(p, &ap);
  599         } else {
  600                 struct mknod_args ap;
  601                 SCARG(&ap, path) = SCARG(uap, path);
  602                 SCARG(&ap, mode) = SCARG(uap, mode);
  603                 SCARG(&ap, dev) = SCARG(uap, dev);
  604                 return mknod(p, &ap);
  605         }
  606 }
  607 
  608 int
  609 ibcs2_getgroups(p, uap)
  610         struct proc *p;
  611         struct ibcs2_getgroups_args *uap;
  612 {
  613         int error, i;
  614         ibcs2_gid_t *iset = NULL;
  615         struct getgroups_args sa;
  616         gid_t *gp;
  617         caddr_t sg = stackgap_init();
  618 
  619         SCARG(&sa, gidsetsize) = SCARG(uap, gidsetsize);
  620         if (SCARG(uap, gidsetsize)) {
  621                 SCARG(&sa, gidset) = stackgap_alloc(&sg, NGROUPS_MAX *
  622                                                     sizeof(gid_t *));
  623                 iset = stackgap_alloc(&sg, SCARG(uap, gidsetsize) *
  624                                       sizeof(ibcs2_gid_t));
  625         }
  626         if (error = getgroups(p, &sa))
  627                 return error;
  628         if (SCARG(uap, gidsetsize) == 0)
  629                 return 0;
  630 
  631         for (i = 0, gp = SCARG(&sa, gidset); i < p->p_retval[0]; i++)
  632                 iset[i] = (ibcs2_gid_t)*gp++;
  633         if (p->p_retval[0] && (error = copyout((caddr_t)iset,
  634                                           (caddr_t)SCARG(uap, gidset),
  635                                           sizeof(ibcs2_gid_t) * p->p_retval[0])))
  636                 return error;
  637         return 0;
  638 }
  639 
  640 int
  641 ibcs2_setgroups(p, uap)
  642         struct proc *p;
  643         struct ibcs2_setgroups_args *uap;
  644 {
  645         int error, i;
  646         ibcs2_gid_t *iset;
  647         struct setgroups_args sa;
  648         gid_t *gp;
  649         caddr_t sg = stackgap_init();
  650 
  651         SCARG(&sa, gidsetsize) = SCARG(uap, gidsetsize);
  652         SCARG(&sa, gidset) = stackgap_alloc(&sg, SCARG(&sa, gidsetsize) *
  653                                             sizeof(gid_t *));
  654         iset = stackgap_alloc(&sg, SCARG(&sa, gidsetsize) *
  655                               sizeof(ibcs2_gid_t *));
  656         if (SCARG(&sa, gidsetsize)) {
  657                 if (error = copyin((caddr_t)SCARG(uap, gidset), (caddr_t)iset, 
  658                                    sizeof(ibcs2_gid_t *) *
  659                                    SCARG(uap, gidsetsize)))
  660                         return error;
  661         }
  662         for (i = 0, gp = SCARG(&sa, gidset); i < SCARG(&sa, gidsetsize); i++)
  663                 *gp++ = (gid_t)iset[i];
  664         return setgroups(p, &sa);
  665 }
  666 
  667 int
  668 ibcs2_setuid(p, uap)
  669         struct proc *p;
  670         struct ibcs2_setuid_args *uap;
  671 {
  672         struct setuid_args sa;
  673 
  674         SCARG(&sa, uid) = (uid_t)SCARG(uap, uid);
  675         return setuid(p, &sa);
  676 }
  677 
  678 int
  679 ibcs2_setgid(p, uap)
  680         struct proc *p;
  681         struct ibcs2_setgid_args *uap;
  682 {
  683         struct setgid_args sa;
  684 
  685         SCARG(&sa, gid) = (gid_t)SCARG(uap, gid);
  686         return setgid(p, &sa);
  687 }
  688 
  689 int
  690 ibcs2_time(p, uap)
  691         struct proc *p;
  692         struct ibcs2_time_args *uap;
  693 {
  694         struct timeval tv;
  695 
  696         microtime(&tv);
  697         p->p_retval[0] = tv.tv_sec;
  698         if (SCARG(uap, tp))
  699                 return copyout((caddr_t)&tv.tv_sec, (caddr_t)SCARG(uap, tp),
  700                                sizeof(ibcs2_time_t));
  701         else
  702                 return 0;
  703 }
  704 
  705 int
  706 ibcs2_pathconf(p, uap)
  707         struct proc *p;
  708         struct ibcs2_pathconf_args *uap;
  709 {
  710         SCARG(uap, name)++;     /* iBCS2 _PC_* defines are offset by one */
  711         return pathconf(p, (struct pathconf_args *)uap);
  712 }
  713 
  714 int
  715 ibcs2_fpathconf(p, uap)
  716         struct proc *p;
  717         struct ibcs2_fpathconf_args *uap;
  718 {
  719         SCARG(uap, name)++;     /* iBCS2 _PC_* defines are offset by one */
  720         return fpathconf(p, (struct fpathconf_args *)uap);
  721 }
  722 
  723 int
  724 ibcs2_sysconf(p, uap)
  725         struct proc *p;
  726         struct ibcs2_sysconf_args *uap;
  727 {
  728         int mib[2], value, len, error;
  729         struct sysctl_args sa;
  730         struct __getrlimit_args ga;
  731 
  732         switch(SCARG(uap, name)) {
  733         case IBCS2_SC_ARG_MAX:
  734                 mib[1] = KERN_ARGMAX;
  735                 break;
  736 
  737         case IBCS2_SC_CHILD_MAX:
  738             {
  739                 caddr_t sg = stackgap_init();
  740 
  741                 SCARG(&ga, which) = RLIMIT_NPROC;
  742                 SCARG(&ga, rlp) = stackgap_alloc(&sg, sizeof(struct rlimit *));
  743                 if (error = getrlimit(p, &ga))
  744                         return error;
  745                 p->p_retval[0] = SCARG(&ga, rlp)->rlim_cur;
  746                 return 0;
  747             }
  748 
  749         case IBCS2_SC_CLK_TCK:
  750                 p->p_retval[0] = hz;
  751                 return 0;
  752 
  753         case IBCS2_SC_NGROUPS_MAX:
  754                 mib[1] = KERN_NGROUPS;
  755                 break;
  756 
  757         case IBCS2_SC_OPEN_MAX:
  758             {
  759                 caddr_t sg = stackgap_init();
  760 
  761                 SCARG(&ga, which) = RLIMIT_NOFILE;
  762                 SCARG(&ga, rlp) = stackgap_alloc(&sg, sizeof(struct rlimit *));
  763                 if (error = getrlimit(p, &ga))
  764                         return error;
  765                 p->p_retval[0] = SCARG(&ga, rlp)->rlim_cur;
  766                 return 0;
  767             }
  768                 
  769         case IBCS2_SC_JOB_CONTROL:
  770                 mib[1] = KERN_JOB_CONTROL;
  771                 break;
  772                 
  773         case IBCS2_SC_SAVED_IDS:
  774                 mib[1] = KERN_SAVED_IDS;
  775                 break;
  776                 
  777         case IBCS2_SC_VERSION:
  778                 mib[1] = KERN_POSIX1;
  779                 break;
  780                 
  781         case IBCS2_SC_PASS_MAX:
  782                 p->p_retval[0] = 128;           /* XXX - should we create PASS_MAX ? */
  783                 return 0;
  784 
  785         case IBCS2_SC_XOPEN_VERSION:
  786                 p->p_retval[0] = 2;             /* XXX: What should that be? */
  787                 return 0;
  788                 
  789         default:
  790                 return EINVAL;
  791         }
  792 
  793         mib[0] = CTL_KERN;
  794         len = sizeof(value);
  795         SCARG(&sa, name) = mib;
  796         SCARG(&sa, namelen) = 2;
  797         SCARG(&sa, old) = &value;
  798         SCARG(&sa, oldlenp) = &len;
  799         SCARG(&sa, new) = NULL;
  800         SCARG(&sa, newlen) = 0;
  801         if (error = __sysctl(p, &sa))
  802                 return error;
  803         p->p_retval[0] = value;
  804         return 0;
  805 }
  806 
  807 int
  808 ibcs2_alarm(p, uap)
  809         struct proc *p;
  810         struct ibcs2_alarm_args *uap;
  811 {
  812         int error;
  813         struct itimerval *itp, *oitp;
  814         struct setitimer_args sa;
  815         caddr_t sg = stackgap_init();
  816 
  817         itp = stackgap_alloc(&sg, sizeof(*itp));
  818         oitp = stackgap_alloc(&sg, sizeof(*oitp));
  819         timevalclear(&itp->it_interval);
  820         itp->it_value.tv_sec = SCARG(uap, sec);
  821         itp->it_value.tv_usec = 0;
  822 
  823         SCARG(&sa, which) = ITIMER_REAL;
  824         SCARG(&sa, itv) = itp;
  825         SCARG(&sa, oitv) = oitp;
  826         error = setitimer(p, &sa);
  827         if (error)
  828                 return error;
  829         if (oitp->it_value.tv_usec)
  830                 oitp->it_value.tv_sec++;
  831         p->p_retval[0] = oitp->it_value.tv_sec;
  832         return 0;
  833 }
  834 
  835 int
  836 ibcs2_times(p, uap)
  837         struct proc *p;
  838         struct ibcs2_times_args *uap;
  839 {
  840         int error;
  841         struct getrusage_args ga;
  842         struct tms tms;
  843         struct timeval t;
  844         caddr_t sg = stackgap_init();
  845         struct rusage *ru = stackgap_alloc(&sg, sizeof(*ru));
  846 #define CONVTCK(r)      (r.tv_sec * hz + r.tv_usec / (1000000 / hz))
  847 
  848         SCARG(&ga, who) = RUSAGE_SELF;
  849         SCARG(&ga, rusage) = ru;
  850         error = getrusage(p, &ga);
  851         if (error)
  852                 return error;
  853         tms.tms_utime = CONVTCK(ru->ru_utime);
  854         tms.tms_stime = CONVTCK(ru->ru_stime);
  855 
  856         SCARG(&ga, who) = RUSAGE_CHILDREN;
  857         error = getrusage(p, &ga);
  858         if (error)
  859                 return error;
  860         tms.tms_cutime = CONVTCK(ru->ru_utime);
  861         tms.tms_cstime = CONVTCK(ru->ru_stime);
  862 
  863         microtime(&t);
  864         p->p_retval[0] = CONVTCK(t);
  865         
  866         return copyout((caddr_t)&tms, (caddr_t)SCARG(uap, tp),
  867                        sizeof(struct tms));
  868 }
  869 
  870 int
  871 ibcs2_stime(p, uap)
  872         struct proc *p;
  873         struct ibcs2_stime_args *uap;
  874 {
  875         int error;
  876         struct settimeofday_args sa;
  877         caddr_t sg = stackgap_init();
  878 
  879         SCARG(&sa, tv) = stackgap_alloc(&sg, sizeof(*SCARG(&sa, tv)));
  880         SCARG(&sa, tzp) = NULL;
  881         if (error = copyin((caddr_t)SCARG(uap, timep),
  882                            &(SCARG(&sa, tv)->tv_sec), sizeof(long)))
  883                 return error;
  884         SCARG(&sa, tv)->tv_usec = 0;
  885         if (error = settimeofday(p, &sa))
  886                 return EPERM;
  887         return 0;
  888 }
  889 
  890 int
  891 ibcs2_utime(p, uap)
  892         struct proc *p;
  893         struct ibcs2_utime_args *uap;
  894 {
  895         int error;
  896         struct utimes_args sa;
  897         struct timeval *tp;
  898         caddr_t sg = stackgap_init();
  899 
  900         CHECKALTEXIST(p, &sg, SCARG(uap, path));
  901         SCARG(&sa, path) = SCARG(uap, path);
  902         if (SCARG(uap, buf)) {
  903                 struct ibcs2_utimbuf ubuf;
  904 
  905                 if (error = copyin((caddr_t)SCARG(uap, buf), (caddr_t)&ubuf,
  906                                    sizeof(ubuf)))
  907                         return error;
  908                 SCARG(&sa, tptr) = stackgap_alloc(&sg,
  909                                                   2 * sizeof(struct timeval *));
  910                 tp = (struct timeval *)SCARG(&sa, tptr);
  911                 tp->tv_sec = ubuf.actime;
  912                 tp->tv_usec = 0;
  913                 tp++;
  914                 tp->tv_sec = ubuf.modtime;
  915                 tp->tv_usec = 0;
  916         } else
  917                 SCARG(&sa, tptr) = NULL;
  918         return utimes(p, &sa);
  919 }
  920 
  921 int
  922 ibcs2_nice(p, uap)
  923         struct proc *p;
  924         struct ibcs2_nice_args *uap;
  925 {
  926         int error;
  927         struct setpriority_args sa;
  928 
  929         SCARG(&sa, which) = PRIO_PROCESS;
  930         SCARG(&sa, who) = 0;
  931         SCARG(&sa, prio) = p->p_nice + SCARG(uap, incr);
  932         if (error = setpriority(p, &sa))
  933                 return EPERM;
  934         p->p_retval[0] = p->p_nice;
  935         return 0;
  936 }
  937 
  938 /*
  939  * iBCS2 getpgrp, setpgrp, setsid, and setpgid
  940  */
  941 
  942 int
  943 ibcs2_pgrpsys(p, uap)
  944         struct proc *p;
  945         struct ibcs2_pgrpsys_args *uap;
  946 {
  947         switch (SCARG(uap, type)) {
  948         case 0:                 /* getpgrp */
  949                 p->p_retval[0] = p->p_pgrp->pg_id;
  950                 return 0;
  951 
  952         case 1:                 /* setpgrp */
  953             {
  954                 struct setpgid_args sa;
  955 
  956                 SCARG(&sa, pid) = 0;
  957                 SCARG(&sa, pgid) = 0;
  958                 setpgid(p, &sa);
  959                 p->p_retval[0] = p->p_pgrp->pg_id;
  960                 return 0;
  961             }
  962 
  963         case 2:                 /* setpgid */
  964             {
  965                 struct setpgid_args sa;
  966 
  967                 SCARG(&sa, pid) = SCARG(uap, pid);
  968                 SCARG(&sa, pgid) = SCARG(uap, pgid);
  969                 return setpgid(p, &sa);
  970             }
  971 
  972         case 3:                 /* setsid */
  973                 return setsid(p, NULL);
  974 
  975         default:
  976                 return EINVAL;
  977         }
  978 }
  979 
  980 /*
  981  * XXX - need to check for nested calls
  982  */
  983 
  984 int
  985 ibcs2_plock(p, uap)
  986         struct proc *p;
  987         struct ibcs2_plock_args *uap;
  988 {
  989         int error;
  990 #define IBCS2_UNLOCK    0
  991 #define IBCS2_PROCLOCK  1
  992 #define IBCS2_TEXTLOCK  2
  993 #define IBCS2_DATALOCK  4
  994 
  995         
  996         if (error = suser(p->p_ucred, &p->p_acflag))
  997                 return EPERM;
  998         switch(SCARG(uap, cmd)) {
  999         case IBCS2_UNLOCK:
 1000         case IBCS2_PROCLOCK:
 1001         case IBCS2_TEXTLOCK:
 1002         case IBCS2_DATALOCK:
 1003                 return 0;       /* XXX - TODO */
 1004         }
 1005         return EINVAL;
 1006 }
 1007 
 1008 int
 1009 ibcs2_uadmin(p, uap)
 1010         struct proc *p;
 1011         struct ibcs2_uadmin_args *uap;
 1012 {
 1013 #define SCO_A_REBOOT        1
 1014 #define SCO_A_SHUTDOWN      2
 1015 #define SCO_A_REMOUNT       4
 1016 #define SCO_A_CLOCK         8
 1017 #define SCO_A_SETCONFIG     128
 1018 #define SCO_A_GETDEV        130
 1019 
 1020 #define SCO_AD_HALT         0
 1021 #define SCO_AD_BOOT         1
 1022 #define SCO_AD_IBOOT        2
 1023 #define SCO_AD_PWRDOWN      3
 1024 #define SCO_AD_PWRNAP       4
 1025 
 1026 #define SCO_AD_PANICBOOT    1
 1027 
 1028 #define SCO_AD_GETBMAJ      0
 1029 #define SCO_AD_GETCMAJ      1
 1030 
 1031         if (suser(p->p_ucred, &p->p_acflag))
 1032                 return EPERM;
 1033 
 1034         switch(SCARG(uap, cmd)) {
 1035         case SCO_A_REBOOT:
 1036         case SCO_A_SHUTDOWN:
 1037                 switch(SCARG(uap, func)) {
 1038                         struct reboot_args r;
 1039                 case SCO_AD_HALT:
 1040                 case SCO_AD_PWRDOWN:
 1041                 case SCO_AD_PWRNAP:
 1042                         r.opt = RB_HALT;
 1043                         reboot(p, &r);
 1044                 case SCO_AD_BOOT:
 1045                 case SCO_AD_IBOOT:
 1046                         r.opt = RB_AUTOBOOT;
 1047                         reboot(p, &r);
 1048                 }
 1049                 return EINVAL;
 1050         case SCO_A_REMOUNT:
 1051         case SCO_A_CLOCK:
 1052         case SCO_A_SETCONFIG:
 1053                 return 0;
 1054         case SCO_A_GETDEV:
 1055                 return EINVAL;  /* XXX - TODO */
 1056         }
 1057         return EINVAL;
 1058 }
 1059 
 1060 int
 1061 ibcs2_sysfs(p, uap)
 1062         struct proc *p;
 1063         struct ibcs2_sysfs_args *uap;
 1064 {
 1065 #define IBCS2_GETFSIND        1
 1066 #define IBCS2_GETFSTYP        2
 1067 #define IBCS2_GETNFSTYP       3
 1068 
 1069         switch(SCARG(uap, cmd)) {
 1070         case IBCS2_GETFSIND:
 1071         case IBCS2_GETFSTYP:
 1072         case IBCS2_GETNFSTYP:
 1073                 break;
 1074         }
 1075         return EINVAL;          /* XXX - TODO */
 1076 }
 1077 
 1078 int
 1079 ibcs2_unlink(p, uap)
 1080         struct proc *p;
 1081         struct ibcs2_unlink_args *uap;
 1082 {
 1083         caddr_t sg = stackgap_init();
 1084 
 1085         CHECKALTEXIST(p, &sg, SCARG(uap, path));
 1086         return unlink(p, (struct unlink_args *)uap);
 1087 }
 1088 
 1089 int
 1090 ibcs2_chdir(p, uap)
 1091         struct proc *p;
 1092         struct ibcs2_chdir_args *uap;
 1093 {
 1094         caddr_t sg = stackgap_init();
 1095 
 1096         CHECKALTEXIST(p, &sg, SCARG(uap, path));
 1097         return chdir(p, (struct chdir_args *)uap);
 1098 }
 1099 
 1100 int
 1101 ibcs2_chmod(p, uap)
 1102         struct proc *p;
 1103         struct ibcs2_chmod_args *uap;
 1104 {
 1105         caddr_t sg = stackgap_init();
 1106 
 1107         CHECKALTEXIST(p, &sg, SCARG(uap, path));
 1108         return chmod(p, (struct chmod_args *)uap);
 1109 }
 1110 
 1111 int
 1112 ibcs2_chown(p, uap)
 1113         struct proc *p;
 1114         struct ibcs2_chown_args *uap;
 1115 {
 1116         caddr_t sg = stackgap_init();
 1117 
 1118         CHECKALTEXIST(p, &sg, SCARG(uap, path));
 1119         return chown(p, (struct chown_args *)uap);
 1120 }
 1121 
 1122 int
 1123 ibcs2_rmdir(p, uap)
 1124         struct proc *p;
 1125         struct ibcs2_rmdir_args *uap;
 1126 {
 1127         caddr_t sg = stackgap_init();
 1128 
 1129         CHECKALTEXIST(p, &sg, SCARG(uap, path));
 1130         return rmdir(p, (struct rmdir_args *)uap);
 1131 }
 1132 
 1133 int
 1134 ibcs2_mkdir(p, uap)
 1135         struct proc *p;
 1136         struct ibcs2_mkdir_args *uap;
 1137 {
 1138         caddr_t sg = stackgap_init();
 1139 
 1140         CHECKALTCREAT(p, &sg, SCARG(uap, path));
 1141         return mkdir(p, (struct mkdir_args *)uap);
 1142 }
 1143 
 1144 int
 1145 ibcs2_symlink(p, uap)
 1146         struct proc *p;
 1147         struct ibcs2_symlink_args *uap;
 1148 {
 1149         caddr_t sg = stackgap_init();
 1150 
 1151         CHECKALTEXIST(p, &sg, SCARG(uap, path));
 1152         CHECKALTCREAT(p, &sg, SCARG(uap, link));
 1153         return symlink(p, (struct symlink_args *)uap);
 1154 }
 1155 
 1156 int
 1157 ibcs2_rename(p, uap)
 1158         struct proc *p;
 1159         struct ibcs2_rename_args *uap;
 1160 {
 1161         caddr_t sg = stackgap_init();
 1162 
 1163         CHECKALTEXIST(p, &sg, SCARG(uap, from));
 1164         CHECKALTCREAT(p, &sg, SCARG(uap, to));
 1165         return rename(p, (struct rename_args *)uap);
 1166 }
 1167 
 1168 int
 1169 ibcs2_readlink(p, uap)
 1170         struct proc *p;
 1171         struct ibcs2_readlink_args *uap;
 1172 {
 1173         caddr_t sg = stackgap_init();
 1174 
 1175         CHECKALTEXIST(p, &sg, SCARG(uap, path));
 1176         return readlink(p, (struct readlink_args *) uap);
 1177 }

Cache object: 7c48c56621bd224bedfea38cd138da0e


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