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

Cache object: 0c747ae6173b73ac670f9b2c31d76373


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