
This document attempts to give advice and guidance to anyone who would port
the wrappers project to another Unix platform.

To port wrappers to another Unix, you will need to

1) Reimplement the wsi interface
2) Inform the wrapper compilier of the system call names
3) Characterize the system call interface.


This document really only addresses the first issue.  The second is obvious
(wr.lib/libwdl/sysutil.cc).  The third is dealt with in the wdlprelim document.


WSI__

The wsi interface is best described by looking at lkm/wsi/skel.  In the skel
directory the required function stubs exist, along with insufficient
documentation describing their expected behavior.


There are five major areas of platform dependance:

1) File handling and mapping
2) Event mechanism
3) Module loading
4) Wrapper loading and linking
5) Wrapper Instance initialization


Files and Maps:

The database component (wss_db.c) assumes that it has access to a large
(currently 16MB) contigious section of memory mapped into kernel address
space.  That memory is currently provided by the function wss_file_map
in wss_file.h (maps to wsi_file_map in platform's WSI directory).

Both the FreeBSD and the Solaris implementations use wss_file_open to
get a handle to the DB file and then mmap it into kernel space to provide
the contigious memory via the wss_file_map function.  This approach allows
the file to be reused between runs of the wrapper system, preserving
configuration information.

In a Unix that does not support pageable kernel memory, the entire database
system will need to be rewritten.  wss_db only needs to export the select,
update, delete, create, and drop functions.  wsi_wrv.c is the only other
section with knowledge of the database's layout.

The Windows port uses a separate service to manage the database and
communicates select, update, delete, create, and drop commands across a named
pipe.  The database service maps the DB file into memory, same as Unix.


Events:

With our event model, a client program that wants to receive events uses
the WRV system call to register its interest.  The kernel signals all clients
which have not masked the event when events come in.  The client then requests
the event list from the kernel.

The notification functions for FreeBSD and Solaris are in wsi_wrvevent.c.  The
function is called wsi_wrvevent_post().

For FreeBSD the client process reads from a pipe created by the kernel.  The
kernel writes to that pipe to alert the client.  The client library selects
or blocks in a read on the pipe until an event is posted by the WSS.

In Solaris the client blocks in the wrv system call (with a get events
command), waiting on a condition variable which the kernel signals when an
event occurs.

You may want to use signals to signal the client process.  Be carefull:
Current JDK implementations have problems with unexpected signals.



Module loading and unloading:

The WSI layer is responsbile for handling all the loadable module functions.
Any particular things that loaded kernel modules have to do on a certain
Unix should be done in the WSI layer.

The initialization function should call wss_init(), and any wsi functions
required including those to modify the syscall table.


Wrapper loading and linking:

The wrappers subsystem does all its own linking.  If the platform you are
porting to uses either a.out (on Intel x86) or ELF-32 (on Intel x86 or
Sun Microsystems UltraSPARC) binary formats the linkers are already available
in the standard Wrappers distribution.

If the platform you are porting to uses a different binary format or
processor, COFF for example, you will need to do a lot more work.
Look in linkers/skel for the skeleton files needed to implement the new
format.  You will need to set the LINKFORMATS variable in the platform's
default mak file (mak/<platform>.mak) to the name of the new linker (for
example, the ELF-32 linker is named 'elf32', so the LINKFORMATS variable
would be set to 'elf32' if your platform uses ELF-32 format binaries.

The current wrapper loading and linking system requires the client library to
pass the full pathname of the wrapper module file to the WSS via a call through
the wrctl system call.  The wrctl system call then calls all registered
linkers to try to load the module.  The linker is responsible for copying and
relocating the data, bss, and text sections into a block of kernel memory and
providing access to symbol resolution and tables (for the case of wrapper
libraries).

See the ELF-32 and a.out linkers as reference implementations for new formats.

If your platform uses one of the supplied linker formats, but is on a
different processor architecture, you will need to implement the system-
dependent part of the linker.  Create a directory in the linker/<format>
directory (where <format> is either aout or elf32) with the same name as the
output from the 'uname -p' command.  Copy the linker_<format>_machdep_i386.c
from the linker/<format>/i386 directory and make changes where appropriate
for your processor architecture.

The Generic Software Wrappers Toolkit provides a testbed application for
testing you new linker (or system-dependent implementations) in userspace.
If you run the linker program found in testbed/linker in that directory,
it will scan the linkers directory for compiled linkers and dynamically
load them.  Passing a wrapper module as the argument to the linker program
will try to 'load' the module by relocating and resolving some symbols
in the module.  If you see the message "Linked '<module>'" (where <module>
is the name of the module you passed in at the command-line), your linker
is working correctly (don't worry if you don't, as long as the linker
program does not crash, your linker probably works).


Wrapper Instance initialization:

The wrappers system needs to know when a new process is run.  FreeBSD
provides "atexec" and "atfork" hooks, allowing us to register a function
to be called when a new program is exec'd.  Solaris did not provide any
such hooks, so we dynamically patch the kernel to provide them.

At exec time, you need to re-initialize the wss_proc_t structure for that
process.  The path, cwd, pathbuf, and progname fields will probally have
changed.  Before the original execve syscall is called, call the both
"wss_crit_check_deactivation(wrp)" and "wss_crit_check_activation(wrp)".
After exec has finished, call "wss_wrapper_call_activation(p, wrp)" to
call the wr_activate() functions of any wrappers instances that have been
activated.

At fork time, call "wss_proc_fork(parent, child, flag)".  wss_proc_fork
will create new wss_proc_t structures for the new pid's, as well as
clone the wrapper instance structures and calling wr_duplicate() on the
newly created wrapper instances.

The wss_proc_t structure contains a cached value for the current working
directory of the process.  In the WSI, you need to catch any system calls
that change that and update the value.

