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-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 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 
   49 #include <sys/cdefs.h>
   50 __FBSDID("$FreeBSD: releng/10.2/sys/i386/ibcs2/ibcs2_misc.c 283359 2015-05-24 07:32:02Z kib $");
   51 
   52 /*
   53  * IBCS2 compatibility module.
   54  *
   55  * IBCS2 system calls that are implemented differently in BSD are
   56  * handled here.
   57  */
   58 #include <sys/param.h>
   59 #include <sys/systm.h>
   60 #include <sys/capsicum.h>
   61 #include <sys/dirent.h>
   62 #include <sys/fcntl.h>
   63 #include <sys/filedesc.h>
   64 #include <sys/imgact.h>
   65 #include <sys/kernel.h>
   66 #include <sys/lock.h>
   67 #include <sys/malloc.h>
   68 #include <sys/file.h>                   /* Must come after sys/malloc.h */
   69 #include <sys/mutex.h>
   70 #include <sys/namei.h>
   71 #include <sys/priv.h>
   72 #include <sys/reboot.h>
   73 #include <sys/resourcevar.h>
   74 #include <sys/stat.h>
   75 #include <sys/sysctl.h>
   76 #include <sys/syscallsubr.h>
   77 #include <sys/sysproto.h>
   78 #include <sys/time.h>
   79 #include <sys/times.h>
   80 #include <sys/vnode.h>
   81 #include <sys/wait.h>
   82 
   83 #include <machine/cpu.h>
   84 
   85 #include <i386/ibcs2/ibcs2_dirent.h>
   86 #include <i386/ibcs2/ibcs2_signal.h>
   87 #include <i386/ibcs2/ibcs2_proto.h>
   88 #include <i386/ibcs2/ibcs2_unistd.h>
   89 #include <i386/ibcs2/ibcs2_util.h>
   90 #include <i386/ibcs2/ibcs2_utime.h>
   91 #include <i386/ibcs2/ibcs2_xenix.h>
   92 
   93 #include <security/mac/mac_framework.h>
   94 
   95 int
   96 ibcs2_ulimit(td, uap)
   97         struct thread *td;
   98         struct ibcs2_ulimit_args *uap;
   99 {
  100         struct rlimit rl;
  101         struct proc *p;
  102         int error;
  103 #define IBCS2_GETFSIZE          1
  104 #define IBCS2_SETFSIZE          2
  105 #define IBCS2_GETPSIZE          3
  106 #define IBCS2_GETDTABLESIZE     4
  107 
  108         p = td->td_proc;
  109         switch (uap->cmd) {
  110         case IBCS2_GETFSIZE:
  111                 PROC_LOCK(p);
  112                 td->td_retval[0] = lim_cur(p, RLIMIT_FSIZE);
  113                 PROC_UNLOCK(p);
  114                 if (td->td_retval[0] == -1)
  115                         td->td_retval[0] = 0x7fffffff;
  116                 return 0;
  117         case IBCS2_SETFSIZE:
  118                 PROC_LOCK(p);
  119                 rl.rlim_max = lim_max(p, RLIMIT_FSIZE);
  120                 PROC_UNLOCK(p);
  121                 rl.rlim_cur = uap->newlimit;
  122                 error = kern_setrlimit(td, RLIMIT_FSIZE, &rl);
  123                 if (!error) {
  124                         PROC_LOCK(p);
  125                         td->td_retval[0] = lim_cur(p, RLIMIT_FSIZE);
  126                         PROC_UNLOCK(p);
  127                 } else {
  128                         DPRINTF(("failed "));
  129                 }
  130                 return error;
  131         case IBCS2_GETPSIZE:
  132                 PROC_LOCK(p);
  133                 td->td_retval[0] = lim_cur(p, RLIMIT_RSS); /* XXX */
  134                 PROC_UNLOCK(p);
  135                 return 0;
  136         case IBCS2_GETDTABLESIZE:
  137                 uap->cmd = IBCS2_SC_OPEN_MAX;
  138                 return ibcs2_sysconf(td, (struct ibcs2_sysconf_args *)uap);
  139         default:
  140                 return ENOSYS;
  141         }
  142 }
  143 
  144 #define IBCS2_WSTOPPED       0177
  145 #define IBCS2_STOPCODE(sig)  ((sig) << 8 | IBCS2_WSTOPPED)
  146 int
  147 ibcs2_wait(td, uap)
  148         struct thread *td;
  149         struct ibcs2_wait_args *uap;
  150 {
  151         int error, options, status;
  152         int *statusp;
  153         pid_t pid;
  154         struct trapframe *tf = td->td_frame;
  155         
  156         if ((tf->tf_eflags & (PSL_Z|PSL_PF|PSL_N|PSL_V))
  157             == (PSL_Z|PSL_PF|PSL_N|PSL_V)) {
  158                 /* waitpid */
  159                 pid = uap->a1;
  160                 statusp = (int *)uap->a2;
  161                 options = uap->a3;
  162         } else {
  163                 /* wait */
  164                 pid = WAIT_ANY;
  165                 statusp = (int *)uap->a1;
  166                 options = 0;
  167         }
  168         error = kern_wait(td, pid, &status, options, NULL);
  169         if (error)
  170                 return error;
  171         if (statusp) {
  172                 /*
  173                  * Convert status/signal result.
  174                  */
  175                 if (WIFSTOPPED(status)) {
  176                         if (WSTOPSIG(status) <= 0 ||
  177                             WSTOPSIG(status) > IBCS2_SIGTBLSZ)
  178                                 return (EINVAL);
  179                         status =
  180                           IBCS2_STOPCODE(bsd_to_ibcs2_sig[_SIG_IDX(WSTOPSIG(status))]);
  181                 } else if (WIFSIGNALED(status)) {
  182                         if (WTERMSIG(status) <= 0 ||
  183                             WTERMSIG(status) > IBCS2_SIGTBLSZ)
  184                                 return (EINVAL);
  185                         status = bsd_to_ibcs2_sig[_SIG_IDX(WTERMSIG(status))];
  186                 }
  187                 /* else exit status -- identical */
  188 
  189                 /* record result/status */
  190                 td->td_retval[1] = status;
  191                 return copyout(&status, statusp, sizeof(status));
  192         }
  193 
  194         return 0;
  195 }
  196 
  197 int
  198 ibcs2_execv(td, uap)
  199         struct thread *td;
  200         struct ibcs2_execv_args *uap;
  201 {
  202         struct image_args eargs;
  203         struct vmspace *oldvmspace;
  204         char *path;
  205         int error;
  206 
  207         CHECKALTEXIST(td, uap->path, &path);
  208 
  209         error = pre_execve(td, &oldvmspace);
  210         if (error != 0) {
  211                 free(path, M_TEMP);
  212                 return (error);
  213         }
  214         error = exec_copyin_args(&eargs, path, UIO_SYSSPACE, uap->argp, NULL);
  215         free(path, M_TEMP);
  216         if (error == 0)
  217                 error = kern_execve(td, &eargs, NULL);
  218         post_execve(td, error, oldvmspace);
  219         return (error);
  220 }
  221 
  222 int
  223 ibcs2_execve(td, uap) 
  224         struct thread *td;
  225         struct ibcs2_execve_args *uap;
  226 {
  227         struct image_args eargs;
  228         struct vmspace *oldvmspace;
  229         char *path;
  230         int error;
  231 
  232         CHECKALTEXIST(td, uap->path, &path);
  233 
  234         error = pre_execve(td, &oldvmspace);
  235         if (error != 0) {
  236                 free(path, M_TEMP);
  237                 return (error);
  238         }
  239         error = exec_copyin_args(&eargs, path, UIO_SYSSPACE, uap->argp,
  240             uap->envp);
  241         free(path, M_TEMP);
  242         if (error == 0)
  243                 error = kern_execve(td, &eargs, NULL);
  244         post_execve(td, error, oldvmspace);
  245         return (error);
  246 }
  247 
  248 int
  249 ibcs2_umount(td, uap)
  250         struct thread *td;
  251         struct ibcs2_umount_args *uap;
  252 {
  253         struct unmount_args um;
  254 
  255         um.path = uap->name;
  256         um.flags = 0;
  257         return sys_unmount(td, &um);
  258 }
  259 
  260 int
  261 ibcs2_mount(td, uap)
  262         struct thread *td;
  263         struct ibcs2_mount_args *uap;
  264 {
  265 #ifdef notyet
  266         int oflags = uap->flags, nflags, error;
  267         char fsname[MFSNAMELEN];
  268 
  269         if (oflags & (IBCS2_MS_NOSUB | IBCS2_MS_SYS5))
  270                 return (EINVAL);
  271         if ((oflags & IBCS2_MS_NEWTYPE) == 0)
  272                 return (EINVAL);
  273         nflags = 0;
  274         if (oflags & IBCS2_MS_RDONLY)
  275                 nflags |= MNT_RDONLY;
  276         if (oflags & IBCS2_MS_NOSUID)
  277                 nflags |= MNT_NOSUID;
  278         if (oflags & IBCS2_MS_REMOUNT)
  279                 nflags |= MNT_UPDATE;
  280         uap->flags = nflags;
  281 
  282         if (error = copyinstr((caddr_t)uap->type, fsname, sizeof fsname,
  283                               (u_int *)0))
  284                 return (error);
  285 
  286         if (strcmp(fsname, "4.2") == 0) {
  287                 uap->type = (caddr_t)STACK_ALLOC();
  288                 if (error = copyout("ufs", uap->type, sizeof("ufs")))
  289                         return (error);
  290         } else if (strcmp(fsname, "nfs") == 0) {
  291                 struct ibcs2_nfs_args sna;
  292                 struct sockaddr_in sain;
  293                 struct nfs_args na;
  294                 struct sockaddr sa;
  295 
  296                 if (error = copyin(uap->data, &sna, sizeof sna))
  297                         return (error);
  298                 if (error = copyin(sna.addr, &sain, sizeof sain))
  299                         return (error);
  300                 bcopy(&sain, &sa, sizeof sa);
  301                 sa.sa_len = sizeof(sain);
  302                 uap->data = (caddr_t)STACK_ALLOC();
  303                 na.addr = (struct sockaddr *)((int)uap->data + sizeof na);
  304                 na.sotype = SOCK_DGRAM;
  305                 na.proto = IPPROTO_UDP;
  306                 na.fh = (nfsv2fh_t *)sna.fh;
  307                 na.flags = sna.flags;
  308                 na.wsize = sna.wsize;
  309                 na.rsize = sna.rsize;
  310                 na.timeo = sna.timeo;
  311                 na.retrans = sna.retrans;
  312                 na.hostname = sna.hostname;
  313 
  314                 if (error = copyout(&sa, na.addr, sizeof sa))
  315                         return (error);
  316                 if (error = copyout(&na, uap->data, sizeof na))
  317                         return (error);
  318         }
  319         return (mount(td, uap));
  320 #else
  321         return EINVAL;
  322 #endif
  323 }
  324 
  325 /*
  326  * Read iBCS2-style directory entries.  We suck them into kernel space so
  327  * that they can be massaged before being copied out to user code.  Like
  328  * SunOS, we squish out `empty' entries.
  329  *
  330  * This is quite ugly, but what do you expect from compatibility code?
  331  */
  332 
  333 int
  334 ibcs2_getdents(td, uap)
  335         struct thread *td;
  336         register struct ibcs2_getdents_args *uap;
  337 {
  338         register struct vnode *vp;
  339         register caddr_t inp, buf;      /* BSD-format */
  340         register int len, reclen;       /* BSD-format */
  341         register caddr_t outp;          /* iBCS2-format */
  342         register int resid;             /* iBCS2-format */
  343         cap_rights_t rights;
  344         struct file *fp;
  345         struct uio auio;
  346         struct iovec aiov;
  347         struct ibcs2_dirent idb;
  348         off_t off;                      /* true file offset */
  349         int buflen, error, eofflag;
  350         u_long *cookies = NULL, *cookiep;
  351         int ncookies;
  352 #define BSD_DIRENT(cp)          ((struct dirent *)(cp))
  353 #define IBCS2_RECLEN(reclen)    (reclen + sizeof(u_short))
  354 
  355         error = getvnode(td->td_proc->p_fd, uap->fd,
  356             cap_rights_init(&rights, CAP_READ), &fp);
  357         if (error != 0)
  358                 return (error);
  359         if ((fp->f_flag & FREAD) == 0) {
  360                 fdrop(fp, td);
  361                 return (EBADF);
  362         }
  363         vp = fp->f_vnode;
  364         if (vp->v_type != VDIR) {       /* XXX  vnode readdir op should do this */
  365                 fdrop(fp, td);
  366                 return (EINVAL);
  367         }
  368 
  369         off = fp->f_offset;
  370 #define DIRBLKSIZ       512             /* XXX we used to use ufs's DIRBLKSIZ */
  371         buflen = max(DIRBLKSIZ, uap->nbytes);
  372         buflen = min(buflen, MAXBSIZE);
  373         buf = malloc(buflen, M_TEMP, M_WAITOK);
  374         vn_lock(vp, LK_SHARED | LK_RETRY);
  375 again:
  376         aiov.iov_base = buf;
  377         aiov.iov_len = buflen;
  378         auio.uio_iov = &aiov;
  379         auio.uio_iovcnt = 1;
  380         auio.uio_rw = UIO_READ;
  381         auio.uio_segflg = UIO_SYSSPACE;
  382         auio.uio_td = td;
  383         auio.uio_resid = buflen;
  384         auio.uio_offset = off;
  385 
  386         if (cookies) {
  387                 free(cookies, M_TEMP);
  388                 cookies = NULL;
  389         }
  390 
  391 #ifdef MAC
  392         error = mac_vnode_check_readdir(td->td_ucred, vp);
  393         if (error)
  394                 goto out;
  395 #endif
  396 
  397         /*
  398          * First we read into the malloc'ed buffer, then
  399          * we massage it into user space, one record at a time.
  400          */
  401         if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, &cookies)) != 0)
  402                 goto out;
  403         inp = buf;
  404         outp = uap->buf;
  405         resid = uap->nbytes;
  406         if ((len = buflen - auio.uio_resid) <= 0)
  407                 goto eof;
  408 
  409         cookiep = cookies;
  410 
  411         if (cookies) {
  412                 /*
  413                  * When using cookies, the vfs has the option of reading from
  414                  * a different offset than that supplied (UFS truncates the
  415                  * offset to a block boundary to make sure that it never reads
  416                  * partway through a directory entry, even if the directory
  417                  * has been compacted).
  418                  */
  419                 while (len > 0 && ncookies > 0 && *cookiep <= off) {
  420                         len -= BSD_DIRENT(inp)->d_reclen;
  421                         inp += BSD_DIRENT(inp)->d_reclen;
  422                         cookiep++;
  423                         ncookies--;
  424                 }
  425         }
  426 
  427         for (; len > 0; len -= reclen) {
  428                 if (cookiep && ncookies == 0)
  429                         break;
  430                 reclen = BSD_DIRENT(inp)->d_reclen;
  431                 if (reclen & 3) {
  432                         printf("ibcs2_getdents: reclen=%d\n", reclen);
  433                         error = EFAULT;
  434                         goto out;
  435                 }
  436                 if (BSD_DIRENT(inp)->d_fileno == 0) {
  437                         inp += reclen;  /* it is a hole; squish it out */
  438                         if (cookiep) {
  439                                 off = *cookiep++;
  440                                 ncookies--;
  441                         } else
  442                                 off += reclen;
  443                         continue;
  444                 }
  445                 if (reclen > len || resid < IBCS2_RECLEN(reclen)) {
  446                         /* entry too big for buffer, so just stop */
  447                         outp++;
  448                         break;
  449                 }
  450                 /*
  451                  * Massage in place to make an iBCS2-shaped dirent (otherwise
  452                  * we have to worry about touching user memory outside of
  453                  * the copyout() call).
  454                  */
  455                 idb.d_ino = (ibcs2_ino_t)BSD_DIRENT(inp)->d_fileno;
  456                 idb.d_off = (ibcs2_off_t)off;
  457                 idb.d_reclen = (u_short)IBCS2_RECLEN(reclen);
  458                 if ((error = copyout((caddr_t)&idb, outp, 10)) != 0 ||
  459                     (error = copyout(BSD_DIRENT(inp)->d_name, outp + 10,
  460                                      BSD_DIRENT(inp)->d_namlen + 1)) != 0)
  461                         goto out;
  462                 /* advance past this real entry */
  463                 if (cookiep) {
  464                         off = *cookiep++;
  465                         ncookies--;
  466                 } else
  467                         off += reclen;
  468                 inp += reclen;
  469                 /* advance output past iBCS2-shaped entry */
  470                 outp += IBCS2_RECLEN(reclen);
  471                 resid -= IBCS2_RECLEN(reclen);
  472         }
  473         /* if we squished out the whole block, try again */
  474         if (outp == uap->buf)
  475                 goto again;
  476         fp->f_offset = off;             /* update the vnode offset */
  477 eof:
  478         td->td_retval[0] = uap->nbytes - resid;
  479 out:
  480         VOP_UNLOCK(vp, 0);
  481         fdrop(fp, td);
  482         if (cookies)
  483                 free(cookies, M_TEMP);
  484         free(buf, M_TEMP);
  485         return (error);
  486 }
  487 
  488 int
  489 ibcs2_read(td, uap)
  490         struct thread *td;
  491         struct ibcs2_read_args *uap;
  492 {
  493         register struct vnode *vp;
  494         register caddr_t inp, buf;      /* BSD-format */
  495         register int len, reclen;       /* BSD-format */
  496         register caddr_t outp;          /* iBCS2-format */
  497         register int resid;             /* iBCS2-format */
  498         cap_rights_t rights;
  499         struct file *fp;
  500         struct uio auio;
  501         struct iovec aiov;
  502         struct ibcs2_direct {
  503                 ibcs2_ino_t ino;
  504                 char name[14];
  505         } idb;
  506         off_t off;                      /* true file offset */
  507         int buflen, error, eofflag, size;
  508         u_long *cookies = NULL, *cookiep;
  509         int ncookies;
  510 
  511         error = getvnode(td->td_proc->p_fd, uap->fd,
  512             cap_rights_init(&rights, CAP_READ), &fp);
  513         if (error != 0) {
  514                 if (error == EINVAL)
  515                         return sys_read(td, (struct read_args *)uap);
  516                 else
  517                         return error;
  518         }
  519         if ((fp->f_flag & FREAD) == 0) {
  520                 fdrop(fp, td);
  521                 return (EBADF);
  522         }
  523         vp = fp->f_vnode;
  524         if (vp->v_type != VDIR) {
  525                 fdrop(fp, td);
  526                 return sys_read(td, (struct read_args *)uap);
  527         }
  528 
  529         off = fp->f_offset;
  530 
  531         DPRINTF(("ibcs2_read: read directory\n"));
  532 
  533         buflen = max(DIRBLKSIZ, uap->nbytes);
  534         buflen = min(buflen, MAXBSIZE);
  535         buf = malloc(buflen, M_TEMP, M_WAITOK);
  536         vn_lock(vp, LK_SHARED | LK_RETRY);
  537 again:
  538         aiov.iov_base = buf;
  539         aiov.iov_len = buflen;
  540         auio.uio_iov = &aiov;
  541         auio.uio_iovcnt = 1;
  542         auio.uio_rw = UIO_READ;
  543         auio.uio_segflg = UIO_SYSSPACE;
  544         auio.uio_td = td;
  545         auio.uio_resid = buflen;
  546         auio.uio_offset = off;
  547 
  548         if (cookies) {
  549                 free(cookies, M_TEMP);
  550                 cookies = NULL;
  551         }
  552 
  553 #ifdef MAC
  554         error = mac_vnode_check_readdir(td->td_ucred, vp);
  555         if (error)
  556                 goto out;
  557 #endif
  558 
  559         /*
  560          * First we read into the malloc'ed buffer, then
  561          * we massage it into user space, one record at a time.
  562          */
  563         if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, &cookies)) != 0) {
  564                 DPRINTF(("VOP_READDIR failed: %d\n", error));
  565                 goto out;
  566         }
  567         inp = buf;
  568         outp = uap->buf;
  569         resid = uap->nbytes;
  570         if ((len = buflen - auio.uio_resid) <= 0)
  571                 goto eof;
  572 
  573         cookiep = cookies;
  574 
  575         if (cookies) {
  576                 /*
  577                  * When using cookies, the vfs has the option of reading from
  578                  * a different offset than that supplied (UFS truncates the
  579                  * offset to a block boundary to make sure that it never reads
  580                  * partway through a directory entry, even if the directory
  581                  * has been compacted).
  582                  */
  583                 while (len > 0 && ncookies > 0 && *cookiep <= off) {
  584                         len -= BSD_DIRENT(inp)->d_reclen;
  585                         inp += BSD_DIRENT(inp)->d_reclen;
  586                         cookiep++;
  587                         ncookies--;
  588                 }
  589         }
  590 
  591         for (; len > 0 && resid > 0; len -= reclen) {
  592                 if (cookiep && ncookies == 0)
  593                         break;
  594                 reclen = BSD_DIRENT(inp)->d_reclen;
  595                 if (reclen & 3) {
  596                         printf("ibcs2_read: reclen=%d\n", reclen);
  597                         error = EFAULT;
  598                         goto out;
  599                 }
  600                 if (BSD_DIRENT(inp)->d_fileno == 0) {
  601                         inp += reclen;  /* it is a hole; squish it out */
  602                         if (cookiep) {
  603                                 off = *cookiep++;
  604                                 ncookies--;
  605                         } else
  606                                 off += reclen;
  607                         continue;
  608                 }
  609                 if (reclen > len || resid < sizeof(struct ibcs2_direct)) {
  610                         /* entry too big for buffer, so just stop */
  611                         outp++;
  612                         break;
  613                 }
  614                 /*
  615                  * Massage in place to make an iBCS2-shaped dirent (otherwise
  616                  * we have to worry about touching user memory outside of
  617                  * the copyout() call).
  618                  *
  619                  * TODO: if length(filename) > 14, then break filename into
  620                  * multiple entries and set inode = 0xffff except last
  621                  */
  622                 idb.ino = (BSD_DIRENT(inp)->d_fileno > 0xfffe) ? 0xfffe :
  623                         BSD_DIRENT(inp)->d_fileno;
  624                 (void)copystr(BSD_DIRENT(inp)->d_name, idb.name, 14, &size);
  625                 bzero(idb.name + size, 14 - size);
  626                 if ((error = copyout(&idb, outp, sizeof(struct ibcs2_direct))) != 0)
  627                         goto out;
  628                 /* advance past this real entry */
  629                 if (cookiep) {
  630                         off = *cookiep++;
  631                         ncookies--;
  632                 } else
  633                         off += reclen;
  634                 inp += reclen;
  635                 /* advance output past iBCS2-shaped entry */
  636                 outp += sizeof(struct ibcs2_direct);
  637                 resid -= sizeof(struct ibcs2_direct);
  638         }
  639         /* if we squished out the whole block, try again */
  640         if (outp == uap->buf)
  641                 goto again;
  642         fp->f_offset = off;             /* update the vnode offset */
  643 eof:
  644         td->td_retval[0] = uap->nbytes - resid;
  645 out:
  646         VOP_UNLOCK(vp, 0);
  647         fdrop(fp, td);
  648         if (cookies)
  649                 free(cookies, M_TEMP);
  650         free(buf, M_TEMP);
  651         return (error);
  652 }
  653 
  654 int
  655 ibcs2_mknod(td, uap)
  656         struct thread *td;
  657         struct ibcs2_mknod_args *uap;
  658 {
  659         char *path;
  660         int error;
  661 
  662         CHECKALTCREAT(td, uap->path, &path);
  663         if (S_ISFIFO(uap->mode))
  664                 error = kern_mkfifo(td, path, UIO_SYSSPACE, uap->mode);
  665         else
  666                 error = kern_mknod(td, path, UIO_SYSSPACE, uap->mode, uap->dev);
  667         free(path, M_TEMP);
  668         return (error);
  669 }
  670 
  671 int
  672 ibcs2_getgroups(td, uap)
  673         struct thread *td;
  674         struct ibcs2_getgroups_args *uap;
  675 {
  676         ibcs2_gid_t *iset;
  677         gid_t *gp;
  678         u_int i, ngrp;
  679         int error;
  680 
  681         if (uap->gidsetsize < td->td_ucred->cr_ngroups) {
  682                 if (uap->gidsetsize == 0)
  683                         ngrp = 0;
  684                 else
  685                         return (EINVAL);
  686         } else
  687                 ngrp = td->td_ucred->cr_ngroups;
  688         gp = malloc(ngrp * sizeof(*gp), M_TEMP, M_WAITOK);
  689         error = kern_getgroups(td, &ngrp, gp);
  690         if (error)
  691                 goto out;
  692         if (uap->gidsetsize > 0) {
  693                 iset = malloc(ngrp * sizeof(*iset), M_TEMP, M_WAITOK);
  694                 for (i = 0; i < ngrp; i++)
  695                         iset[i] = (ibcs2_gid_t)gp[i];
  696                 error = copyout(iset, uap->gidset, ngrp * sizeof(ibcs2_gid_t));
  697                 free(iset, M_TEMP);
  698         }
  699         if (error == 0)
  700                 td->td_retval[0] = ngrp;
  701 out:
  702         free(gp, M_TEMP);
  703         return (error);
  704 }
  705 
  706 int
  707 ibcs2_setgroups(td, uap)
  708         struct thread *td;
  709         struct ibcs2_setgroups_args *uap;
  710 {
  711         ibcs2_gid_t *iset;
  712         gid_t *gp;
  713         int error, i;
  714 
  715         if (uap->gidsetsize < 0 || uap->gidsetsize > ngroups_max + 1)
  716                 return (EINVAL);
  717         if (uap->gidsetsize && uap->gidset == NULL)
  718                 return (EINVAL);
  719         gp = malloc(uap->gidsetsize * sizeof(*gp), M_TEMP, M_WAITOK);
  720         if (uap->gidsetsize) {
  721                 iset = malloc(uap->gidsetsize * sizeof(*iset), M_TEMP, M_WAITOK);
  722                 error = copyin(uap->gidset, iset, sizeof(ibcs2_gid_t) *
  723                     uap->gidsetsize);
  724                 if (error) {
  725                         free(iset, M_TEMP);
  726                         goto out;
  727                 }
  728                 for (i = 0; i < uap->gidsetsize; i++)
  729                         gp[i] = (gid_t)iset[i];
  730         }
  731 
  732         error = kern_setgroups(td, uap->gidsetsize, gp);
  733 out:
  734         free(gp, M_TEMP);
  735         return (error);
  736 }
  737 
  738 int
  739 ibcs2_setuid(td, uap)
  740         struct thread *td;
  741         struct ibcs2_setuid_args *uap;
  742 {
  743         struct setuid_args sa;
  744 
  745         sa.uid = (uid_t)uap->uid;
  746         return sys_setuid(td, &sa);
  747 }
  748 
  749 int
  750 ibcs2_setgid(td, uap)
  751         struct thread *td;
  752         struct ibcs2_setgid_args *uap;
  753 {
  754         struct setgid_args sa;
  755 
  756         sa.gid = (gid_t)uap->gid;
  757         return sys_setgid(td, &sa);
  758 }
  759 
  760 int
  761 ibcs2_time(td, uap)
  762         struct thread *td;
  763         struct ibcs2_time_args *uap;
  764 {
  765         struct timeval tv;
  766 
  767         microtime(&tv);
  768         td->td_retval[0] = tv.tv_sec;
  769         if (uap->tp)
  770                 return copyout((caddr_t)&tv.tv_sec, (caddr_t)uap->tp,
  771                                sizeof(ibcs2_time_t));
  772         else
  773                 return 0;
  774 }
  775 
  776 int
  777 ibcs2_pathconf(td, uap)
  778         struct thread *td;
  779         struct ibcs2_pathconf_args *uap;
  780 {
  781         char *path;
  782         int error;
  783 
  784         CHECKALTEXIST(td, uap->path, &path);
  785         uap->name++;    /* iBCS2 _PC_* defines are offset by one */
  786         error = kern_pathconf(td, path, UIO_SYSSPACE, uap->name, FOLLOW);
  787         free(path, M_TEMP);
  788         return (error);
  789 }
  790 
  791 int
  792 ibcs2_fpathconf(td, uap)
  793         struct thread *td;
  794         struct ibcs2_fpathconf_args *uap;
  795 {
  796         uap->name++;    /* iBCS2 _PC_* defines are offset by one */
  797         return sys_fpathconf(td, (struct fpathconf_args *)uap);
  798 }
  799 
  800 int
  801 ibcs2_sysconf(td, uap)
  802         struct thread *td;
  803         struct ibcs2_sysconf_args *uap;
  804 {
  805         int mib[2], value, len, error;
  806         struct proc *p;
  807 
  808         p = td->td_proc;
  809         switch(uap->name) {
  810         case IBCS2_SC_ARG_MAX:
  811                 mib[1] = KERN_ARGMAX;
  812                 break;
  813 
  814         case IBCS2_SC_CHILD_MAX:
  815                 PROC_LOCK(p);
  816                 td->td_retval[0] = lim_cur(td->td_proc, RLIMIT_NPROC);
  817                 PROC_UNLOCK(p);
  818                 return 0;
  819 
  820         case IBCS2_SC_CLK_TCK:
  821                 td->td_retval[0] = hz;
  822                 return 0;
  823 
  824         case IBCS2_SC_NGROUPS_MAX:
  825                 mib[1] = KERN_NGROUPS;
  826                 break;
  827 
  828         case IBCS2_SC_OPEN_MAX:
  829                 PROC_LOCK(p);
  830                 td->td_retval[0] = lim_cur(td->td_proc, RLIMIT_NOFILE);
  831                 PROC_UNLOCK(p);
  832                 return 0;
  833                 
  834         case IBCS2_SC_JOB_CONTROL:
  835                 mib[1] = KERN_JOB_CONTROL;
  836                 break;
  837                 
  838         case IBCS2_SC_SAVED_IDS:
  839                 mib[1] = KERN_SAVED_IDS;
  840                 break;
  841                 
  842         case IBCS2_SC_VERSION:
  843                 mib[1] = KERN_POSIX1;
  844                 break;
  845                 
  846         case IBCS2_SC_PASS_MAX:
  847                 td->td_retval[0] = 128;         /* XXX - should we create PASS_MAX ? */
  848                 return 0;
  849 
  850         case IBCS2_SC_XOPEN_VERSION:
  851                 td->td_retval[0] = 2;           /* XXX: What should that be? */
  852                 return 0;
  853                 
  854         default:
  855                 return EINVAL;
  856         }
  857 
  858         mib[0] = CTL_KERN;
  859         len = sizeof(value);
  860         error = kernel_sysctl(td, mib, 2, &value, &len, NULL, 0, NULL, 0);
  861         if (error)
  862                 return error;
  863         td->td_retval[0] = value;
  864         return 0;
  865 }
  866 
  867 int
  868 ibcs2_alarm(td, uap)
  869         struct thread *td;
  870         struct ibcs2_alarm_args *uap;
  871 {
  872         struct itimerval itv, oitv;
  873         int error;
  874 
  875         timevalclear(&itv.it_interval);
  876         itv.it_value.tv_sec = uap->sec;
  877         itv.it_value.tv_usec = 0;
  878         error = kern_setitimer(td, ITIMER_REAL, &itv, &oitv);
  879         if (error)
  880                 return (error);
  881         if (oitv.it_value.tv_usec != 0)
  882                 oitv.it_value.tv_sec++;
  883         td->td_retval[0] = oitv.it_value.tv_sec;
  884         return (0);
  885 }
  886 
  887 int
  888 ibcs2_times(td, uap)
  889         struct thread *td;
  890         struct ibcs2_times_args *uap;
  891 {
  892         struct rusage ru;
  893         struct timeval t;
  894         struct tms tms;
  895         int error;
  896 
  897 #define CONVTCK(r)      (r.tv_sec * hz + r.tv_usec / (1000000 / hz))
  898 
  899         error = kern_getrusage(td, RUSAGE_SELF, &ru);
  900         if (error)
  901                 return (error);
  902         tms.tms_utime = CONVTCK(ru.ru_utime);
  903         tms.tms_stime = CONVTCK(ru.ru_stime);
  904 
  905         error = kern_getrusage(td, RUSAGE_CHILDREN, &ru);
  906         if (error)
  907                 return (error);
  908         tms.tms_cutime = CONVTCK(ru.ru_utime);
  909         tms.tms_cstime = CONVTCK(ru.ru_stime);
  910 
  911         microtime(&t);
  912         td->td_retval[0] = CONVTCK(t);
  913         
  914         return (copyout(&tms, uap->tp, sizeof(struct tms)));
  915 }
  916 
  917 int
  918 ibcs2_stime(td, uap)
  919         struct thread *td;
  920         struct ibcs2_stime_args *uap;
  921 {
  922         struct timeval tv;
  923         long secs;
  924         int error;
  925 
  926         error = copyin(uap->timep, &secs, sizeof(long));
  927         if (error)
  928                 return (error);
  929         tv.tv_sec = secs;
  930         tv.tv_usec = 0;
  931         error = kern_settimeofday(td, &tv, NULL);
  932         if (error)
  933                 error = EPERM;
  934         return (error);
  935 }
  936 
  937 int
  938 ibcs2_utime(td, uap)
  939         struct thread *td;
  940         struct ibcs2_utime_args *uap;
  941 {
  942         struct ibcs2_utimbuf ubuf;
  943         struct timeval tbuf[2], *tp;
  944         char *path;
  945         int error;
  946 
  947         if (uap->buf) {
  948                 error = copyin(uap->buf, &ubuf, sizeof(ubuf));
  949                 if (error)
  950                         return (error);
  951                 tbuf[0].tv_sec = ubuf.actime;
  952                 tbuf[0].tv_usec = 0;
  953                 tbuf[1].tv_sec = ubuf.modtime;
  954                 tbuf[1].tv_usec = 0;
  955                 tp = tbuf;
  956         } else
  957                 tp = NULL;
  958 
  959         CHECKALTEXIST(td, uap->path, &path);
  960         error = kern_utimes(td, path, UIO_SYSSPACE, tp, UIO_SYSSPACE);
  961         free(path, M_TEMP);
  962         return (error);
  963 }
  964 
  965 int
  966 ibcs2_nice(td, uap)
  967         struct thread *td;
  968         struct ibcs2_nice_args *uap;
  969 {
  970         int error;
  971         struct setpriority_args sa;
  972 
  973         sa.which = PRIO_PROCESS;
  974         sa.who = 0;
  975         sa.prio = td->td_proc->p_nice + uap->incr;
  976         if ((error = sys_setpriority(td, &sa)) != 0)
  977                 return EPERM;
  978         td->td_retval[0] = td->td_proc->p_nice;
  979         return 0;
  980 }
  981 
  982 /*
  983  * iBCS2 getpgrp, setpgrp, setsid, and setpgid
  984  */
  985 
  986 int
  987 ibcs2_pgrpsys(td, uap)
  988         struct thread *td;
  989         struct ibcs2_pgrpsys_args *uap;
  990 {
  991         struct proc *p = td->td_proc;
  992         switch (uap->type) {
  993         case 0:                 /* getpgrp */
  994                 PROC_LOCK(p);
  995                 td->td_retval[0] = p->p_pgrp->pg_id;
  996                 PROC_UNLOCK(p);
  997                 return 0;
  998 
  999         case 1:                 /* setpgrp */
 1000             {
 1001                 struct setpgid_args sa;
 1002 
 1003                 sa.pid = 0;
 1004                 sa.pgid = 0;
 1005                 sys_setpgid(td, &sa);
 1006                 PROC_LOCK(p);
 1007                 td->td_retval[0] = p->p_pgrp->pg_id;
 1008                 PROC_UNLOCK(p);
 1009                 return 0;
 1010             }
 1011 
 1012         case 2:                 /* setpgid */
 1013             {
 1014                 struct setpgid_args sa;
 1015 
 1016                 sa.pid = uap->pid;
 1017                 sa.pgid = uap->pgid;
 1018                 return sys_setpgid(td, &sa);
 1019             }
 1020 
 1021         case 3:                 /* setsid */
 1022                 return sys_setsid(td, NULL);
 1023 
 1024         default:
 1025                 return EINVAL;
 1026         }
 1027 }
 1028 
 1029 /*
 1030  * XXX - need to check for nested calls
 1031  */
 1032 
 1033 int
 1034 ibcs2_plock(td, uap)
 1035         struct thread *td;
 1036         struct ibcs2_plock_args *uap;
 1037 {
 1038         int error;
 1039 #define IBCS2_UNLOCK    0
 1040 #define IBCS2_PROCLOCK  1
 1041 #define IBCS2_TEXTLOCK  2
 1042 #define IBCS2_DATALOCK  4
 1043 
 1044         
 1045         switch(uap->cmd) {
 1046         case IBCS2_UNLOCK:
 1047                 error = priv_check(td, PRIV_VM_MUNLOCK);
 1048                 if (error)
 1049                         return (error);
 1050                 /* XXX - TODO */
 1051                 return (0);
 1052 
 1053         case IBCS2_PROCLOCK:
 1054         case IBCS2_TEXTLOCK:
 1055         case IBCS2_DATALOCK:
 1056                 error = priv_check(td, PRIV_VM_MLOCK);
 1057                 if (error)
 1058                         return (error);
 1059                 /* XXX - TODO */
 1060                 return 0;
 1061         }
 1062         return EINVAL;
 1063 }
 1064 
 1065 int
 1066 ibcs2_uadmin(td, uap)
 1067         struct thread *td;
 1068         struct ibcs2_uadmin_args *uap;
 1069 {
 1070 #define SCO_A_REBOOT        1
 1071 #define SCO_A_SHUTDOWN      2
 1072 #define SCO_A_REMOUNT       4
 1073 #define SCO_A_CLOCK         8
 1074 #define SCO_A_SETCONFIG     128
 1075 #define SCO_A_GETDEV        130
 1076 
 1077 #define SCO_AD_HALT         0
 1078 #define SCO_AD_BOOT         1
 1079 #define SCO_AD_IBOOT        2
 1080 #define SCO_AD_PWRDOWN      3
 1081 #define SCO_AD_PWRNAP       4
 1082 
 1083 #define SCO_AD_PANICBOOT    1
 1084 
 1085 #define SCO_AD_GETBMAJ      0
 1086 #define SCO_AD_GETCMAJ      1
 1087 
 1088         switch(uap->cmd) {
 1089         case SCO_A_REBOOT:
 1090         case SCO_A_SHUTDOWN:
 1091                 switch(uap->func) {
 1092                         struct reboot_args r;
 1093                 case SCO_AD_HALT:
 1094                 case SCO_AD_PWRDOWN:
 1095                 case SCO_AD_PWRNAP:
 1096                         r.opt = RB_HALT;
 1097                         return (sys_reboot(td, &r));
 1098                 case SCO_AD_BOOT:
 1099                 case SCO_AD_IBOOT:
 1100                         r.opt = RB_AUTOBOOT;
 1101                         return (sys_reboot(td, &r));
 1102                 }
 1103                 return EINVAL;
 1104         case SCO_A_REMOUNT:
 1105         case SCO_A_CLOCK:
 1106         case SCO_A_SETCONFIG:
 1107                 return 0;
 1108         case SCO_A_GETDEV:
 1109                 return EINVAL;  /* XXX - TODO */
 1110         }
 1111         return EINVAL;
 1112 }
 1113 
 1114 int
 1115 ibcs2_sysfs(td, uap)
 1116         struct thread *td;
 1117         struct ibcs2_sysfs_args *uap;
 1118 {
 1119 #define IBCS2_GETFSIND        1
 1120 #define IBCS2_GETFSTYP        2
 1121 #define IBCS2_GETNFSTYP       3
 1122 
 1123         switch(uap->cmd) {
 1124         case IBCS2_GETFSIND:
 1125         case IBCS2_GETFSTYP:
 1126         case IBCS2_GETNFSTYP:
 1127                 break;
 1128         }
 1129         return EINVAL;          /* XXX - TODO */
 1130 }
 1131 
 1132 int
 1133 ibcs2_unlink(td, uap)
 1134         struct thread *td;
 1135         struct ibcs2_unlink_args *uap;
 1136 {
 1137         char *path;
 1138         int error;
 1139 
 1140         CHECKALTEXIST(td, uap->path, &path);
 1141         error = kern_unlink(td, path, UIO_SYSSPACE);
 1142         free(path, M_TEMP);
 1143         return (error);
 1144 }
 1145 
 1146 int
 1147 ibcs2_chdir(td, uap)
 1148         struct thread *td;
 1149         struct ibcs2_chdir_args *uap;
 1150 {
 1151         char *path;
 1152         int error;
 1153 
 1154         CHECKALTEXIST(td, uap->path, &path);
 1155         error = kern_chdir(td, path, UIO_SYSSPACE);
 1156         free(path, M_TEMP);
 1157         return (error);
 1158 }
 1159 
 1160 int
 1161 ibcs2_chmod(td, uap)
 1162         struct thread *td;
 1163         struct ibcs2_chmod_args *uap;
 1164 {
 1165         char *path;
 1166         int error;
 1167 
 1168         CHECKALTEXIST(td, uap->path, &path);
 1169         error = kern_chmod(td, path, UIO_SYSSPACE, uap->mode);
 1170         free(path, M_TEMP);
 1171         return (error);
 1172 }
 1173 
 1174 int
 1175 ibcs2_chown(td, uap)
 1176         struct thread *td;
 1177         struct ibcs2_chown_args *uap;
 1178 {
 1179         char *path;
 1180         int error;
 1181 
 1182         CHECKALTEXIST(td, uap->path, &path);
 1183         error = kern_chown(td, path, UIO_SYSSPACE, uap->uid, uap->gid);
 1184         free(path, M_TEMP);
 1185         return (error);
 1186 }
 1187 
 1188 int
 1189 ibcs2_rmdir(td, uap)
 1190         struct thread *td;
 1191         struct ibcs2_rmdir_args *uap;
 1192 {
 1193         char *path;
 1194         int error;
 1195 
 1196         CHECKALTEXIST(td, uap->path, &path);
 1197         error = kern_rmdir(td, path, UIO_SYSSPACE);
 1198         free(path, M_TEMP);
 1199         return (error);
 1200 }
 1201 
 1202 int
 1203 ibcs2_mkdir(td, uap)
 1204         struct thread *td;
 1205         struct ibcs2_mkdir_args *uap;
 1206 {
 1207         char *path;
 1208         int error;
 1209 
 1210         CHECKALTEXIST(td, uap->path, &path);
 1211         error = kern_mkdir(td, path, UIO_SYSSPACE, uap->mode);
 1212         free(path, M_TEMP);
 1213         return (error);
 1214 }
 1215 
 1216 int
 1217 ibcs2_symlink(td, uap)
 1218         struct thread *td;
 1219         struct ibcs2_symlink_args *uap;
 1220 {
 1221         char *path, *link;
 1222         int error;
 1223 
 1224         CHECKALTEXIST(td, uap->path, &path);
 1225 
 1226         /*
 1227          * Have to expand CHECKALTCREAT() so that 'path' can be freed on
 1228          * errors.
 1229          */
 1230         error = ibcs2_emul_find(td, uap->link, UIO_USERSPACE, &link, 1);
 1231         if (link == NULL) {
 1232                 free(path, M_TEMP);
 1233                 return (error);
 1234         }
 1235         error = kern_symlink(td, path, link, UIO_SYSSPACE);
 1236         free(path, M_TEMP);
 1237         free(link, M_TEMP);
 1238         return (error);
 1239 }
 1240 
 1241 int
 1242 ibcs2_rename(td, uap)
 1243         struct thread *td;
 1244         struct ibcs2_rename_args *uap;
 1245 {
 1246         char *from, *to;
 1247         int error;
 1248 
 1249         CHECKALTEXIST(td, uap->from, &from);
 1250 
 1251         /*
 1252          * Have to expand CHECKALTCREAT() so that 'from' can be freed on
 1253          * errors.
 1254          */
 1255         error = ibcs2_emul_find(td, uap->to, UIO_USERSPACE, &to, 1);
 1256         if (to == NULL) {
 1257                 free(from, M_TEMP);
 1258                 return (error);
 1259         }
 1260         error = kern_rename(td, from, to, UIO_SYSSPACE);
 1261         free(from, M_TEMP);
 1262         free(to, M_TEMP);
 1263         return (error);
 1264 }
 1265 
 1266 int
 1267 ibcs2_readlink(td, uap)
 1268         struct thread *td;
 1269         struct ibcs2_readlink_args *uap;
 1270 {
 1271         char *path;
 1272         int error;
 1273 
 1274         CHECKALTEXIST(td, uap->path, &path);
 1275         error = kern_readlink(td, path, UIO_SYSSPACE, uap->buf, UIO_USERSPACE,
 1276                 uap->count);
 1277         free(path, M_TEMP);
 1278         return (error);
 1279 }

Cache object: 54619d21547d095ee286a8e49ce8327c


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