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

Cache object: 55b7fad426672182cdef21212a959181


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