@need 3200

@node A Virtual Unix File-System Interface
@chapter A Virtual Unix File-System Interface

VU provides a @geindex virtual file-system interface
@dfn{virtual file-system interface} -- a way for programs
to redefine the meaning of the basic file-system functions for a
particular file descriptor or for a particular part of the
file-system namespace.  When a process defines a virtual
file-system, its definitions apply to that process only.

@menu
* The VU File-System Functions::
* Virtual File-System Functions::
* VU Closures::
* Pseudo-Descriptors::
* Establishing VU Handlers::
* Looking Up VU Handlers::
* Stacking Descriptor Handlers::
* The VU File-system Interface::
@end menu

@need 3200

@node The VU File-System Functions
@section The VU File-System Functions

For the purposes of this section, the unix file system interface is
defined as these functions:

@example
@group
     access chdir chmod chown chroot close closedir fchdir fchmod
     fchown fstat fsync ftruncate link lseek lstat mkdir open
     opendir read readdir readlink rename rmdir stat
     symlink truncate unlink utime write fcntl
     dup dup2
@end group
@group
@end group
@end example

For each of those functions, there is a corresponding @code{vu_} function:

@example
@group
     vu_access vu_chdir vu_chmod ...
@end group
@group
@end group
@end example

The function prototypes of the @code{vu_} functions are slightly
different from the traditional unix functions.  For one thing, all
@code{vu_} functions accept an output paramter, @code{errn}, as the first
argument:

@example
@group
     int vu_open (int * errn, char * path, int flags, int mode)
@end group
@group
@end group
@end example

That parameter takes the place of the global variable @code{errno}.
When an error occurs in a @code{vu_} function, the error number is
returned in @code{*errn}.


The other interface difference is the functions for reading
directories.  The @code{vu_} functions return an integer to indicate
success @code{(0)} or failure @code{(-1)} and return other information through
output parameters:

@example
@group
     int vu_opendir (int * errn, DIR ** retv,  char * path)
     int vu_readdir (int * errn,
                     struct alloc_limits * limits,
                     char ** file_ret,
                     DIR * dir)
@end group
@group
@end group
@end example

Aside from those difference, @code{vu_} functions can be substituted
freely for their unix counterparts.  If no other changes are made,
the modified program will run just the same as the original.


There are two additional @code{vu_} functions:

@example
@group
     vu_read_retry vu_write_retry
@end group
@group
@end group
@end example

@noindent
which are similar to @code{read} and @code{write} but which
automatically restart after a @code{EINTR} or @code{EAGAIN}.




@need 3200

@node Virtual File-System Functions
@section Virtual File-System Functions

Programs can provide their own definitions of the @code{vu_} file-system
functions.  These definitions can be made to apply to specific file
descriptors or to a subset of the names in the file-system
namespace of the process.


To define a set of virtual functions, a program defines functions
having the same return types and almost the same parameters as the
@code{vu_} virtual functions.  The virtual functions take one extra
(final) argument, @code{void * closure}.  For example:

@example
@group
     int my_virtual_open (int * errn, 
                          char * path, 
                          int flags,
                          int mode,
                          void * closure)
@end group
@group
@end group
@end example

All of these functions must be named consistently by adding a
prefix to the root name of the file system functions:

@example
@group
     my_virtual_access my_virtual_chdir my_virtual_chmod ...
@end group
@group
@end group
@end example

Two additional functions must be provided:

@example
@group
     void * my_virtual_make_closure (void * closure)
     void my_virtual_free_closure (void * closure)
@end group
@group
@end group
@end example

These are explained below.


Having defined a set of virtual file system functions, a program
must declare a @geindex vtable
@dfn{vtable} for the functions:

@example
@group
     #include "hackerlab/vu/vu.h"
     ...
@end group
@group
@end group
@end example
@example
@group
     struct vu_fs_discipline my_fs_vtable
      = @{ VU_FS_DISCIPLINE_INITIALIZERS (my_virtual_) @};
@end group
@group
@end group
@end example

Note that the prefix used to name virtual functions is used by
the macro @code{VU_FS_DISCIPLINE_INITIALIZERS} to initialize the vtable.


Finally, the functions may be applied to either a portion of the 
file-system namespace or to a particular descriptor:

@example
@group
     // Applying `my_virtual_' functions to a particular 
     // descriptor:
     //
     vu_set_fd_handler (fd, &my_fs_vtable, closure);
@end group
@group
@end group
@end example
@example
@group
     // Applying `my_virtual_' functions to a part
     // of the file-system namespace.  Note that
     // preg is a `regex_t' -- a regular expression
     // compiled by `regcomp'.  `eflags' is like the
     // parameter of the same name to `regexec':
     //
     vu_push_name_handler (name, doc, preg, eflags, 
                           &my_fs_vtable, closure, 0);
@end group
@group
@end group
@end example

After those calls, a call to a @code{vu_} file-system using descriptor
@code{fd} will do its work by calling a @code{my_virtual_} function (e.g.
@code{vu_read} will call @code{my_virtual_read} to read from @code{fd}).


A call to a @code{vu_} function with a path that matches the regexp
@code{preg} will also do its work by calling a @code{my_virtual_} function
(e.g. @code{vu_open} will call @code{my_virtual_open} to open a matching
file-name).  If a new file is successfully opened this way, VU
automatically calls @code{vu_set_fd_handler} to establish the same
vtable as the handler for the new descriptor.


Name-space handlers are kept on a stack and searched from the
top of stack down.  Each handler has a name and an array of
strings which are its documentation.




@need 3200

@node VU Closures
@section VU Closures

When a set of virtual file system functions is installed by
@code{vu_set_fd_handler} or @code{vu_push_name_handler} the caller provides a
closure.  This closure is an opaque value to @code{vu} itself.  A copy
of the closure is passed as the final parameter to the caller's
virtual functions.  For example, to open a file that has matched a
regular expression passed to @code{vu_push_name_handler}, @code{vu_open} uses
the sequence:

@example
@group
    fd = handler->vtable->open (errn, path, flags, mode, 
                                handler->closure);
@end group
@group
@end group
@end example

VU doesn't save a copy of the closure directly.  Instead, it calls
the @code{make_closure} function from the vtable to create the value
to save and the @code{free_closure} function when that copy is being
discarded.  @code{make_closure} is called once when
@code{vu_push_name_handler} is called, and once each time
@code{vu_set_fd_handler} is called.   @code{free_closure} is called each time
@code{vu_close} or @code{vu_closedir} is called.

@sp 1
@need 1750
@noindent
@b{* Type} @code{vu_handler}@tyindex vu_handler
@*
@example
@group
struct vu_handler;
@end group
@group
@end group
@end example

For each VU namespace handler and file-descriptor handler, there
is a @code{struct vu_handler} that indicates the @code{vtable} and @code{closure}
to use for that portion of the file-system.

@example
@group
   struct vu_handler
   @{
     struct vu_fs_discipline * vtable;
     void * closure;
   @};
@end group
@group
@end group
@end example



@need 3200

@node Pseudo-Descriptors
@section Pseudo-Descriptors

The @code{vu_} functions can operate on file descriptors which are
created by the program itself without the knowledge of the
operating system kernel.  The advantage of such descriptors is that
they take up no kernel resources so it is practical to create a
large number of them.


Pseudo-descriptors which are guaranteed to be distinct from all
kernel descriptors can be created using the function
@code{reserv_pseudo} and destroyed using the function @code{unreserv_pseudo}.
For example:

@example
@group
     fd = reserv_pseudo ();
     vu_set_fd_handler (fd, &my_fs_vtable, 0);
@end group
@group
@end group
@end example

@noindent
and:

@example
@group
     int
     my_virtual_close (int * errn, int fd, void * closure)
     @{
       unreserv_pseudo (fd);
       return 0;
     @}
@end group
@group
@end group
@end example

One way to use a pseudo-descriptor is to combine it with
buffered-I/O to create a file that corresponds to a string in the
program's address space.  (See @ref{Buffered File Descriptors}.)




@need 3200

@node Establishing VU Handlers
@section Establishing VU Handlers
@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_push_name_handler}@fuindex vu_push_name_handler
@*
@example
@group
void vu_push_name_handler (t_uchar * name,
                           t_uchar ** doc,
                           regex_t * preg,
                           int eflags,
                           struct vu_fs_discipline * vtable,
                           void * closure,
                           int is_optional);
@end group
@group
@end group
@end example

@code{vu_push_name_handler} establishs a vtable of virtual file system
functions for a portion of the file-system namespace.


@code{name} is the name for the handler recognized by
@code{vu_enable_optional_name_handler}.  Conventionally,
this name may be used as an option argument to the 
command line options @code{-N} or @code{--namespace}.  For optimal 
help message formatting, @code{name} should be no longer than
@code{30} characters.  A pointer to @code{name} is kept by this function.


@code{doc} is a documentation string for the handler, printed in the
outpupt of @code{vu_help_for_optional_handlers}.  For optimal help
message formatting, each line of @code{doc} should be no longer than @code{40}
characters.  The last element of the array @code{doc} must be @code{0}.
A pointer to @code{doc} is kept by this function.


File-names matching @code{preg} are handled by the functions in
@code{vtable}.  Matching is performed by @code{regexec}:

@example
@group
     regexec (preg, path, 0, 0, eflags)
@end group
@group
@end group
@end example

If a matching file is successfully opened, @code{vu_open} and
@code{vu_opendir} call:

@example
@group
     vu_set_fd_handler (new_fd, vtable, closure)
@end group
@group
@end group
@end example

If @code{is_optional} is not @code{0}, the file-name handler is recorded
but not enabled.  It can be made active by a call to 
@code{vu_enable_optional_name_handler}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_enable_optional_name_handler}@fuindex vu_enable_optional_name_handler
@*
@example
@group
int vu_enable_optional_name_handler (t_uchar * name);
@end group
@group
@end group
@end example

Push the named namespace handler on the VU namespace stack.


The named handler must have previously been established by a 
call to @code{vu_push_optional_name_handler}.


Return @code{0} on success, @code{-1} if the named handler was not found.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_set_fd_handler}@fuindex vu_set_fd_handler
@*
@example
@group
void vu_set_fd_handler (int fd,
                        struct vu_fs_discipline * vtable,
                        void * closure);
@end group
@group
@end group
@end example

Establish a vtable of virtual file system functions for a
particular descriptor or pseudo-descriptor.


The handler is automatically removed by @code{vu_close}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_move_state}@fuindex vu_move_state
@*
@example
@group
int vu_move_state (int * errn, int fd, int newfd);
@end group
@group
@end group
@end example

Move the VU handler for @code{fd} to @code{newfd}.




@need 3200

@node Looking Up VU Handlers
@section Looking Up VU Handlers
@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_path_dispatch}@fuindex vu_path_dispatch
@*
@example
@group
struct vu_handler * vu_path_dispatch (char * path);
@end group
@group
@end group
@end example

Return the vtable and closure that handle the file-name @code{path}.
(See @strong{vu_handler} in @ref{VU Closures}.)

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_fd_dispatch}@fuindex vu_fd_dispatch
@*
@example
@group
struct vu_handler * vu_fd_dispatch (int fd);
@end group
@group
@end group
@end example

Return the vtable and closure that handle the descriptor @code{fd}.
(See @strong{vu_handler} in @ref{VU Closures}.)

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_dir_dispatch}@fuindex vu_dir_dispatch
@*
@example
@group
struct vu_handler * vu_dir_dispatch (DIR * dir);
@end group
@group
@end group
@end example

Return the vtable and closure that handle the directory @code{dir}.
(See @strong{vu_handler} in @ref{VU Closures}.)




@need 3200

@node Stacking Descriptor Handlers
@section Stacking Descriptor Handlers

The function @code{vu_fd_dispatch} returns a pointer to a @code{struct
vu_handler} which in turn holds a pointer to the vtable and closure
used to handle @code{vu_} functions for a particular descriptor (see
@strong{vu_handler} in @ref{VU Closures}).


Using @code{vu_fd_dispatch}, descriptor handlers can be stacked.  For
example, the buffered-I/O functions (@code{vfdbuf_}) work by imposing a
file-system vtable that maintains a buffer but that performs actual
I/O by calling functions from an underlying vtable.  To establish
the buffering vtable, the function @code{vfdbuf_buffer_fd} uses a
sequence of operations like:

@example
@group
     int
     vfdbuf_buffer_fd (int * errn, int fd,
                       long bufsize, int flags, int zero_buffer)
     @{
       struct vu_handler * sub_handler;
@end group
@group
@end group
@end example
@example
@group
       ...
       sub_handler = vu_fd_dispatch (fd);
@end group
@group
@end group
@end example
@example
@group
       ... remember that sub_handler does I/O for fd:
       bufs[fd].sub_handler = sub_handler;
       ...
@end group
@group
@end group
@end example
@example
@group
       ... Establish the buffering functions as the new vtable for
           `fd'.
@end group
@group
@end group
@end example
@example
@group
       vu_set_fd_handler (fd, &vfdbuf_vtable, 0);
     @}
@end group
@group
@end group
@end example

The @code{vfdbuf_} file-system functions follow this example:

@example
@group
     int
     vfdbuf_fsync (int * errn, int fd, void * closure)
     @{
       ... Empty the buffer.
@end group
@group
@end group
@end example
@example
@group
       if (vfdbuf_flush (errn, fd) < 0)
         return -1;
@end group
@group
@end group
@end example
@example
@group
       ... Perform the actual `fsync' using the vtable set aside
           in vfdbuf_buffer_fd:
@end group
@group
@end group
@end example
@example
@group
       return bufs[fd].sub_handler.vtable->fsync 
                     (errn, fd, bufs[fd].sub_handler.closure);
     @}
@end group
@group
@end group
@end example

Note that when closing a file, it is the responsibility of the
@code{vfdbuf_} functions to free the closure for the underlying vtable:

@example
@group
     int
     vfdbuf_close (int * errn, int fd, void * closure)
     @{
       int errn
       int got;
       int ign;
@end group
@group
@end group
@end example
@example
@group
       ...
       got = bufs[fd].sub_handler.vtable->close 
                     (errn, fd, bufs[fd].sub_handler.closure);
@end group
@group
@end group
@end example
@example
@group
       bufs[fd].sub_handler.vtable->free_closure
             (bufs[fd].sub_handler.closure);
       ...
     @}
@end group
@group
@end group
@end example



@need 3200

@node The VU File-system Interface
@section The VU File-system Interface

These functions approximately mirror the traditional unix system call
interface, but have these improvments:

@example
@group
     1. Error numbers are not stored in a global, but
        in a return value.
@end group
@group
@end group
@end example
@example
@group
     2. Functions dispatch on file names and descriptors,
        permitting these functions to work on objects other than
        ordinary files and sockets and to work on ordinary files
        and sockets in unusual ways.
@end group
@group
@end group
@end example
@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_access}@fuindex vu_access
@*
@example
@group
int vu_access (int * errn, char * path, int mode);
@end group
@group
@end group
@end example

See the manual page for @code{access}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_chdir}@fuindex vu_chdir
@*
@example
@group
int vu_chdir (int * errn, char * path);
@end group
@group
@end group
@end example

See the manual page for @code{chdir}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_chmod}@fuindex vu_chmod
@*
@example
@group
int vu_chmod (int * errn, char * path, int mode);
@end group
@group
@end group
@end example

See the manual page for @code{chmod}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_chown}@fuindex vu_chown
@*
@example
@group
int vu_chown (int * errn, char * path, int owner, int group);
@end group
@group
@end group
@end example

See the manual page for @code{chown}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_chroot}@fuindex vu_chroot
@*
@example
@group
int vu_chroot (int * errn, char * path);
@end group
@group
@end group
@end example

See the manual page for @code{chroot}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_close}@fuindex vu_close
@*
@example
@group
int vu_close (int * errn, int fd);
@end group
@group
@end group
@end example

See the manual page for @code{close}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_closedir}@fuindex vu_closedir
@*
@example
@group
int vu_closedir (int * errn, DIR * dir);
@end group
@group
@end group
@end example

See the manual page for @code{closedir}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_fchdir}@fuindex vu_fchdir
@*
@example
@group
int vu_fchdir (int * errn, int fd);
@end group
@group
@end group
@end example

See the manual page for @code{fchdir}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_fchmod}@fuindex vu_fchmod
@*
@example
@group
int vu_fchmod (int * errn, int fd, int mode);
@end group
@group
@end group
@end example

See the manual page for @code{fchmod}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_fchown}@fuindex vu_fchown
@*
@example
@group
int vu_fchown (int * errn, int fd, int owner, int group);
@end group
@group
@end group
@end example

See the manual page for @code{fchown}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_fstat}@fuindex vu_fstat
@*
@example
@group
int vu_fstat (int * errn, int fd, struct stat * buf);
@end group
@group
@end group
@end example

See the manual page for @code{fstat}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_fsync}@fuindex vu_fsync
@*
@example
@group
int vu_fsync (int * errn, int fd);
@end group
@group
@end group
@end example

See the manual page for @code{fsync}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_ftruncate}@fuindex vu_ftruncate
@*
@example
@group
int vu_ftruncate (int * errn, int fd, off_t where);
@end group
@group
@end group
@end example

See the manual page for @code{ftruncate}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_link}@fuindex vu_link
@*
@example
@group
int vu_link (int * errn, char * from, char * to);
@end group
@group
@end group
@end example

See the manual page for @code{link}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_lseek}@fuindex vu_lseek
@*
@example
@group
off_t vu_lseek (int * errn, int fd, off_t offset, int whence);
@end group
@group
@end group
@end example

See the manual page for @code{lseek}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_lstat}@fuindex vu_lstat
@*
@example
@group
int vu_lstat (int * errn, char * path, struct stat * buf);
@end group
@group
@end group
@end example

See the manual page for @code{lstat}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_mkdir}@fuindex vu_mkdir
@*
@example
@group
int vu_mkdir (int * errn, char * path, int mode);
@end group
@group
@end group
@end example

See the manual page for @code{mkdir}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_open}@fuindex vu_open
@*
@example
@group
int vu_open (int * errn, char * path, int flags, int mode);
@end group
@group
@end group
@end example

See the manual page for @code{open}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_dir_fd}@fuindex vu_dir_fd
@*
@example
@group
int vu_dir_fd (DIR * dir);
@end group
@group
@end group
@end example

Return the pseudo descriptor associated with DIR.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_opendir}@fuindex vu_opendir
@*
@example
@group
int vu_opendir (int * errn, DIR ** retv,  char * path);
@end group
@group
@end group
@end example

See the manual page for @code{opendir}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_read}@fuindex vu_read
@*
@example
@group
ssize_t vu_read (int * errn, int fd, char * buf, size_t count);
@end group
@group
@end group
@end example

See the manual page for @code{read}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_read_retry}@fuindex vu_read_retry
@*
@example
@group
ssize_t vu_read_retry (int * errn, int fd, char * buf, size_t count);
@end group
@group
@end group
@end example

Use @code{vu_read} to read from @code{fd}.  Read repeatedly (even if a read
returns early from EINTR or EAGAIN) until @code{count} characters are
read, or the end-of-file is reached.


Return the number of characters read or @code{-1} on error.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_readdir}@fuindex vu_readdir
@*
@example
@group
int vu_readdir (int * errn,
                struct alloc_limits * limits,
                char ** file_ret,
                DIR * dir);
@end group
@group
@end group
@end example

See the manual page for @code{readdir}.


Note that in @code{vu}, the file name is returned in @code{*file_ret}
and is dynamically allocated using @code{limits}.  It is up to the
caller to free the file name.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_readlink}@fuindex vu_readlink
@*
@example
@group
int vu_readlink (int * errn, char * path, char * buf, int bufsize);
@end group
@group
@end group
@end example

See the manual page for @code{readlink}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_rename}@fuindex vu_rename
@*
@example
@group
int vu_rename (int * errn, char * from, char * to);
@end group
@group
@end group
@end example

See the manual page for @code{rename}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_rmdir}@fuindex vu_rmdir
@*
@example
@group
int vu_rmdir (int * errn, char * path);
@end group
@group
@end group
@end example

See the manual page for @code{rmdir}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_stat}@fuindex vu_stat
@*
@example
@group
int vu_stat (int * errn, char * path, struct stat * buf);
@end group
@group
@end group
@end example

See the manual page for @code{stat}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_symlink}@fuindex vu_symlink
@*
@example
@group
int vu_symlink (int * errn, char * from, char * to);
@end group
@group
@end group
@end example

See the manual page for @code{symlink}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_truncate}@fuindex vu_truncate
@*
@example
@group
int vu_truncate (int * errn, char * path, off_t where);
@end group
@group
@end group
@end example

See the manual page for @code{truncate}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_unlink}@fuindex vu_unlink
@*
@example
@group
int vu_unlink (int * errn, char * path);
@end group
@group
@end group
@end example

See the manual page for @code{unlink}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_utime}@fuindex vu_utime
@*
@example
@group
int vu_utime (int * errn, char * path, struct utimbuf *times);
@end group
@group
@end group
@end example

See the manual page for @code{utime}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_write}@fuindex vu_write
@*
@example
@group
ssize_t vu_write (int * errn, int fd, char * buf, size_t count);
@end group
@group
@end group
@end example

See the manual page for @code{write}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_write_retry}@fuindex vu_write_retry
@*
@example
@group
ssize_t vu_write_retry (int * errn, int fd, char * buf, size_t count);
@end group
@group
@end group
@end example

Use @code{vu_write} to write to @code{fd}.  Write repeatedly (even if a write
returns early from EINTR or EAGAIN) until @code{count} characters are
written.


Return the number of characters written or @code{-1} on error.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_fcntl}@fuindex vu_fcntl
@*
@example
@group
int vu_fcntl (int * errn, int fd, int cmd, long arg);
@end group
@group
@end group
@end example

See the manual page for @code{fcntl}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_dup}@fuindex vu_dup
@*
@example
@group
int vu_dup (int * errn, int fd);
@end group
@group
@end group
@end example

See the manual page for @code{dup}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vu_dup2}@fuindex vu_dup2
@*
@example
@group
int vu_dup2 (int * errn, int fd, int newfd);
@end group
@group
@end group
@end example

See the manual page for @code{dup2}.







