Slink is a utility program that allows the system administrator of a
UNIX system to create and maintain filesystems that are unions of
disjoint package trees of installed software. Each package tree may
be installed and maintained by a separate person. Slink makes it seem
as if all packages are part of one coherent whole, by creating one
image tree that looks as if it contains all the packages intermixed.
Users refer to this image tree rather than to separate package trees,
and thus automatically gain access to new packages as Slink installs
them in the image.
Slink-5.0 is written in perl-5.001m and works on 4.2 BSD, System VR4,
and later UNIX systems supporting the concept of a symbolic link. It
has been tested extensively under perl-5.001m on SunOs(SUN),
Solaris(SUN), IRIX(SGI), Linux(PC),and OSF(dec) UNIXes.
To make optimal use of Slink, one must install software in disjoint
package trees from which Slink constructs a coherent user view. The
efficiency of using Slink depends upon how much discipline is employed
in constructing these packages, though Slink can integrate almost any
package into the image regardless of structure.
The following is a compressed and simplified user guide to Slink's
basic features. Detailed information is provided in later sections of
this document. The intent of this section is to give novice users of
Slink enough information to perform simple tests and to determine
whether Slink is appropriate for their specific uses.
Slink allows the administrator to construct an image tree of software
packages that are actually installed as disjoint subtrees. For
simplicity, Slink considers itself to be providing an image of files,
and fluidly modifies directory structure of the image tree it
constructs in order to make files available through symbolic links.
To utilize Slink one first installs a group of packages in private
subtrees, taking care to separate files that the user needs to see
from files the package uses secretly and files that are not needed
while using the package. Slink's job is to create an `image tree'
that appears to contain all the disjoint packages, but in actuality
consists entirely of symbolic links to those packages.
To construct this image, we construct a `configuration file' slink.conf
that tells Slink what to include in the image.
In this configuration file, a line like
allows Slink to erase and correct symbolic links in the image tree
/local. There are other protection models that allow Slink more or
less freedom depending upon the outcome desired.
To add a package to the image, one includes a configuration line of the form
link /loc/gnu/gcc-2.7.2/bin /local/bin
This command says to include all commands from the Gnu C compiler in
the image directory /local/bin. Note that this command specifies
not one symbolic link, but an assertion that the structure of the
image should contain appropriate links to make all source nodes available
to arbitrary recursive depth. If /loc/gnu/gcc-2.7.2/bin
contains a directory, it and its contents will appear to be contents
of /local/bin as well. This allows one to make complex assertions about
structure in a single command if source and image have parallel structure.
If, for example, in /loc/gnu/gcc-2.7.2 there are only
with parallel structure
to those subdirectories of /local, then the single directive
link /loc/gnu/gcc-2.7.2 /local
duplicates all the structure of /loc/gnu/gcc-2.7.2 in /local.
In other words, the efficiency of specifying structural mappings is
directly proportional to whatever parallelism in structure you
enforce in installing packages.
One great power of Slink is reversibility. If one decides that the
above directive should be undone, all one has to do is change
the above command to
unlink /loc/gnu/gcc-2.7.2 /local
This has the effect of only undoing links from the image
that happen to point to the source. Links with the same name
that do not point to the source will remain untouched.
To change the revision of a package without worry,
simply add the revision changing command before the
link /loc/gnu/gcc-2.7.3 /local
unlink /loc/gnu/gcc-2.7.2 /local
This will have the effect of replacing all links in /local that should
go to gcc-2.7.3 with the appropriate ones, followed by cleaning up
any links from gcc-2.7.2 that are no longer required.
Of course, deleting a package is easy. Just unlink it and delete it.
Slink also provides maintenance commands to clean up after deletions
that occurred without prior unlinking.
These three commands, the protection directive
, form the basis for using
Slink for maintaining complex filesystems. To add something to an
image, one links it, and to remove something one unlinks it. One may
maintain multiple images by linking one package to multiple images, or
leave an installed package invisible until users require it.
are implemented by fluidly
modifying the directory structure of the image tree /local while
embedding symbolic links in that tree that point to full pathnames in
various package trees. The result is that accessing any path in the
image tree actually refers one to a path in a package tree, while a
package program that relatively addresses its own files will always
locate them, regardless of whether the relative link is expanded within
the image or package trees.
However, one must be cautious about utilizing relative addressing
within the image tree between files in distinct packages, because
those relative references may at Slink's discretion actually be
resolved within an individual package tree, making the reference
invalid. Fine points of
are discussed below.
Slink's strategy works equally well when there is one installer and
one machine as when there are one hundred of each. One can learn how
to utilize Slink and its configuration file in less than a day for
almost all applications. This makes Slink suitable for very small
sites as well as very large ones, unlike more powerful `repository
Slink imposes minimal stylistic restrictions upon the packages it
installs. Unlike object-based configuration systems such as Depot,
Slink relies upon the discipline of the administrator to enforce
stylistic consistency; it is simply a powerful tool whose function is
unencumbered by trying to enforce a particular style of use. In
particular, Slink can manage access to any package regardless of
the vendor's lack of compliance with appropriate package conventions,
without requiring modification of the package to suit reasonable
Any number of people can be simultaneously installing software without
danger of conflicting with one another. If they do manage to try to
install the same file in the user's view, Slink will warn them, and,
since no files are overwritten, the problem is easily correctable.
Slink provides an easy and intuitively obvious mechanism for
replicating installed software on multiple machines of the same
architecture, simply by copying package trees and linking
them into local images as appropriate. One can also construct slave
package trees that are a union of local copies of crucial software and
remote copies of packages deemed less crucial. See
Software installers need not have administrative privilege, but can be
regular users with no administrative privileges, members of an
administrative group, or people with root access. This establishes a
promotion and training path for new installers, from unprivileged use,
through apprenticeships, to root access and beyond.
One can add and retract packages in the user's view without corrupting
the user's filesystem with undetectable useless files, and without
modifying each user's environment for each modification. Most
software installations can be safely performed while the affected
systems are running in multiuser mode, with no effect on users.
One can maintain several versions of the user's environment for use
by different kinds of users. One might have novice, expert, and
data-entry user classes, each of which should have access to a
particular set of commands. Slink can maintain several `images'
of the package hierarchy as easily as one.
One can always determine the source of a file in the user's environment
by referring to Slink's configuration file or the path of the file itself
if that path was created using a symbolic link.
Slink's configuration file (default slink.conf). This file consists of
a list of assertions about filesystem structure that Slink implements
when invoked with no arguments. This file is read by Slink but hand-edited.
For format see
Slink's lockfile (default slink.pid). This file contains the
process ID of the current Slink process, if any. It is used to avoid
running multiple copies of Slink. It is both read and written by
Slink's map file (default slink.map). This file keeps a record of
the current state of all filesystems, and what Slink has done on each.
Entries list a file, an operation, and a source, where operations are
. This file is used for consistency checking
after each Slink operation, and for checking filesystems for
corruption not created by Slink. It is both read and written by
Slink's protection model file (default slink.mod). This file
contains human-input directives on the limits of Slink's rights to
modify filesystems. By default Slink has no rights. You must give it
some by editing this file.
Slink's list of new configuration lines (default slink.new). This file is written during
filesystem checking, and contains new configuration lines whose contents
Slink discovered during checking. If these lines are added to the
configuration file, Slink will no longer complain about these links
A reference to an array of pathnames that should not be allowed as
components of a fully expanded pathname. In forming links, Slink
always uses the most efficient form of each link. This entails
expanding the source path it's given so that no components are links.
Unfortunately, older versions of automount(8) require use of
symbolic links, and resolving links into the automounter trees will
render the automounter nonfunctional. To avoid this, we specifically
trap references to the automounter tree and refuse to expand those
links in expanding the source path. If you don't have an automounter,
or have a more recent one that does not utilize symlinks, this line
has no effect. You may leave this option empty to expand all symlinks
A reference to an array of hosts on which Slink can execute. These
hosts should be entered in the same format that appears in the
$HOST environment variable. If this list is empty Slink can
execute on any host. Of course, this option only applies if Slink
is installed in a shared disk partition.
A default umask with which to create files and directories; see
. By default this umask denies write permission to others,
but gives it to both group and user. In normal use, Slink exploits
BSD-like group inheritance (via chmod g+s or whatever
mechanism) to keep contents of each image directory in the same group
as the parent. You can make this mask more severe, but will have to
run Slink as root at all times.
A default mode to give to created image directories. Of course this should
be world-readable. I also make mine group-writable so that others
in my group can also update it. I then ensure that group inheritance is
enabled, and that top-level directories in my image tree have appropriate
groups. This means that people in my group can execute Slink to
update their parts of the image tree without being root.
The next step in installing Slink is to edit control files
slink.mod and slink.conf so it will behave properly. The file
slink.mod contains protection directives that slink will obey even
as root. The file slink.conf contains assertions about filesystem
structure that Slink will try to enforce. When Slink starts executing,
it reads slink.mod first, followed by slink.conf if appropriate.
In both files, comments are distinguished by having a # as the
leftmost non-space character. Non-comment lines are commands, either
protection commands (in either slink.conf or slink.mod) or
assertions about image structure (in slink.conf only).
The first task in configuring Slink is to define which subtrees of
the global filesystem Slink is allowed to modify, and how. Unlike
UNIX, in Slink there are two kinds of protection for filesystem
that Slink provides; each file has a protection state that determines
whether or not any administrator should be able to change that file.
This protection is the same for root as for normal users.
The problem with physical protection is that it is effectively.nonexistent when one is working as root. Slink's protection scheme
was created to allow one to safely use Slink as root with no danger
that it will corrupt filesystems unexpectedly.
For example, with appropriate protections in place, it's safe to use
Slink to merge two copies of /usr. Overlaps are not errors; if a
file already exists, we use it in place of the new source. See
In error messages and verbose logging, Slink distinguishes between the
two kinds of protection and their failure. If physical protection
fails, Slink says it `cannot' do something, whereas if virtual
protection fails, Slink says it `may not' do it. In general, physical
protection failures are errors, while virtual protection failures are
not; Slink simply refuses to write anything where it's not permitted
to do so. To receive a list of virtual protection violations, execute
Slink in verbose mode.
Slink assigns every file and directory in the system a `protection
model' that determines what Slink will do to that file. There are
five protection models in order of increasing permissiveness.
Each protection model is the first word in a configuration command
that can be placed in either slink.conf or slink.mod.
Some protection models are only
meaningful for files; others control actions on directories or links
to files. The protection for a particular file or directory is either
specified explicitly, or is inherited from the most immediate parent
for which a protection is specified. The protection models are:
This table summarizes the protections and their meanings:.
permitted? freeze protect relink redirect replace prune
may add nodes no yes yes yes yes yes
may remove links no no yes yes yes yes
may convert dirs no no no yes yes yes
may remove files no no no no yes yes
may remove dirs no no no no no yes
Protection commands may occur in two places.
in Slink's configuration file (default slink.conf). In this case,
protection commands are executed as the file is scanned, and the
protection in effect for a directive is the sum of all
protection directives encountered so far.
in the special protection model file (default slink.mod). This file is
scanned before the configuration file to determine defaults.
It is also definitive for direct commands executed outside the
auspices of the configuration file.
The formats for these commands are the same in both places: a.directive followed by a list of images to which it applies. In these
images, a `*' matches zero or more characters, a `?' matches
exactly one character. All other shell metacharacters are disabled.
To allow a literal `*' or `?', precede either with a `\'.
If an image is a directory,
then the protection applies to all subdirectories and contents of its whole
subtree, unless specifically overridden by other protection commands
for subtrees, which then apply to everything beneath them.
For example, the protection directives
have the effect of
freezing everything in / and every subtree, except /local.
allowing relinking in all of /local except for the lock directory
not allowing additions to the lock directory /local/emacs/lock.
This scheme is designed to make specifying protections as easy as possible..For our purposes the above lines suffice to
appropriately protect everything from Slink. As another example,
the protection directives
allow Slink to add missing files to /usr but not to destroy any
The default in the absence of any other information is to
everything. You must therefore include at least one directive in
slink.mod in order to be able to execute direct commands, or at
least one directive in slink.conf in order to be able to process
configuration file requests. If conflicting protections are specified for
the same path, the last one encountered is binding.
In the model file, this simply cancels earlier assertions, while
in the configuration file, the protections binding at time of
an assertion are the protections encountered before the assertion.
All symlinks are fully expanded before encoding protections,
except those that expand to paths in @main::opt_dontresolve.
For example, the first example above has the same effect as
Set working directories to prepend to relative paths for both sources
(what gets installed) and images (formed by linking or copying).
Either directory may be relative, in which case the current corresponding
directory is prepended.
Either directory may be a double quote, in which case that working
directory is left unchanged. For example,
cd " /local
leaves the source directory alone and changes
the image directory to /local.
is scanned for commands. If
is relative it is expanded by prepending the current
directory. The directories
directories for source and image while inside the included file,
and are interpreted exactly as in the
Make links from each
descending into subdirectories of
has a link at a higher path level than
its base, brachiate any such links in to directories of
links so that
is link-free except for its basename.
Utilize file copying to construct an image.
, preserving each file's
modification date, access date, as well as
owner, group, and mode (if possible and reasonable).
Each file's owner can be preserved if the current effective user of
Slink is root or the source file's owner. Group can be preserved if
the current effective user is root or that user is a member of the
group of the source file. Mode can be preserved if the mode does not
contain setuid, setgid, or setvtx (the `sticky bit'), or if the
effective user of Slink is root. In the latter case all such modes
Owner, group, and mode are ignored for directories; they are given the
default owner and group, and a mode specified in the configuration
Delete everything in each
a copy of something in
. A thing is `obviously a copy' if
it is a copy under rdist(1) semantics, i.e., both size and
modification time match exactly.
is completely destroyed, if possible within prevailing
A subtle difference exists between directives in slink.mod and.slink.conf. In slink.mod, the
command expects only one
directory, which is interpreted as an
while as stated above, in slink.conf, the
both source and image working directories.
Of course, the success of any directive depends upon the protection
specified for its image. All the above directives will silently
fail if not awarded sufficient rights to modify an image.
stand-alone (or direct) mode, to make a specific slink not in the
In the first case, a configuration file is edited that contains all.the slinks to be made. In our case this file is /loc/slink.conf.
The identity of this file may be changed by editing the source to the
slink command itself. To use the configuration file, type simply
to assure that all slinks in the file are up to date, or
image [source-pattern [slink-pattern]]
to update links that match particular source patterns or image
patterns in the configuration file. At this point the only patterns
supported are literal substring matches. For example, if the
configuration file contains
link /loc/adm/slink-5.0/sbin /local/sbin
link /loc/adm/foo-1.0 /local
then the command
will update the links that assure that
/loc/adm/foo-1.0 <= /local
but ignore the links that assure that
/loc/adm/slink-5.0/sbin <= /local/sbin
If one wishes to bypass the configuration file, the command
slink -link source image [image ...]
echos the function of a symbolic link, except that it is permissible to
specify two directories and the second will thereafter contain the
contents of the first as well as perhaps other nodes.
To undo one of these links, one can write
slink -unlink source image [image ...]
This command will only undo links that look correct, and links
from image to somewhere other than source will be left alone.
To execute Slink, one specifies zero or one actions and zero
or more options. Actions used in normal operation are as follows.
Slink's default action is to update images so they match its
configuration file. Syntax:
slink [-update] [ ]
If no action flag is specified, Slink assumes that it should read its
configuration file and insure that the filesystems are up to date with
respect to the stated configuration. In this case Slink takes two
optional extra arguments, that are interpreted as literal substrings
(with no star convention) to match against source and image fields in the
configuration file, respectively. Only lines that contain those
substrings will be acted upon. If both substring arguments are
absent, Slink acts on every directive in the configuration file.
This action prints a help message and exits. Syntax:
In addition to normal actions, there are several `direct' commands
that allow one to perform actions without editing them into the
Force a link not in the configuration file.
This action instructs Slink to ignore the configuration file and try to
implement a link request from the command line. Using the protections
solely from the protection model file (default name slink.mod) Slink
will attempt to form links from
This has the same effect as if the line
was included in Slink's configuration file (except that protection mode
commands in the configuration file have no effect). Extra arguments
are interpreted as extra image names to link from.
Undo a link request without utilizing the configuration file.
This action is similar to -link except that Slink tries to undo a previously
made link request. This has roughly the same effect as if the line
was included in Slink's configuration file.
Copy a file into images without using the configuration file.
This action is similar to -link except that Slink tries to copy a file instead
of linking it. This has roughly the same effect as if the line
was included in Slink's configuration file.
Undo a copy without using the configuration file.
This action is similar to -link except that Slink tries to undo a previously
made copy request. This has roughly the same effect as if the command
was included in Slink's configuration file.
Destroy nodes without using the configuration file.
slink -destroy [...]
This action is similar to -link except that Slink tries to destroy
a previously created image node. This has roughly the same effect as
if the command
Several special commands recover from administrative errors.
Clean up image trees. Syntax:
slink -clean [...]
This action cleans image trees by removing symlinks to nonexistent
nodes. One should be careful that all source trees are available
(either locally or via some network file system) before executing this
command. One can thus purge a package by deleting it and then running
Slink with this option. This option is not recommended; use `unlink'
to uninstall packages.
Report on possible image tree corruption.
slink -report [...]
This action checks image trees for artifacts not created by Slink.
If you directly modify image trees, this will give you a list of things you did
that Slink couldn't have done. Its output includes a list of configuration
file lines that could be included in order to place these changes under
Slink's control if desired. Of course, Slink can only suggest
new `link' requests as it has no knowledge of where files are copied from.
Condense directory structure by replacing directories with links
where appropriate. Syntax:
slink -condense [ ]
This action instructs Slink to try to simplify its directory structure
by replacing directories with links where appropriate. In normal
operation this will occur when deletion of a link makes brachiation of
a directory into link no longer needed. In condensing structure,
Slink will obey and implement all deletion requests (
) while trying to condense image trees
requests. If source and/or image substrings are
specified, Slink will only act upon configuration lines matching those
Several options control Slink's behavior. While all options are legal
to specify at all times, some may have no effect if the action
specified does not require them. For example, specifying a
configuration file does not affect any direct commands.
Print a debugging trace. While not particularly useful, this option
prints all internal states of Slink as it executes, tracing important
variable values, control flow, etc.
Don't echo errors to the controlling terminal. Normally Slink writes
every error to your terminal as well as to its error file (default
slink.err). This cancels that behavior, but errors are still
available in the error file.
Print a verbose description of actions taken. In particular, inform
the user of protection mode failures that aren't errors. This option
is helpful if you're trying to understand how Slink works or why it
didn't do something you thought it should do.
Don't utilize a lock file to lock out multiple instances of Slink.
Normally, only one instance of Slink can run at a time.
Don't read or write the map file that records Slink's previous actions in
linking and copying. As the map file is utilized in performing the -report
action, things done with -nomap in effect will be treated as foreign to
Slink during reporting.
Don't read the map file initially, but create a new one at the end of
execution. If your map file gets corrupted or overcrowded, the
command slink -remap will recreate a clean copy based solely on the
Several options control the files that Slink reads and writes.
Specify a new directory prefix for Slink's control files, if specified
using relative filenames. This prefix will be prepended to all default
filenames unless you override them with absolute pathnames in the
filename options below.
Specify a new configuration file (default slink.conf).
This file is read by Slink to determine what it should do.
Specify a new error file (default slink.err).
Slink appends error messages to this file.
Specify a new log file (default slink.log).
Slink appends a list of actions taken to this file as it
Specify a new lock file (default slink.pid).
This file is used to keep two instances of Slink from
running at the same time.
Specify a new link map file (default slink.map). This file is read
before and updated after each Slink execution to contain the current
state of image trees according to Slink. It is used during the
-report option and also after each run to insure that there are no
conflicts in Slink's directions.
Specify a new protection model file (default slink.mod).
This file contains
directives that should be in effect
regardless of whether the configuration file is utilized or not.
These protections affect all direct actions such as -link, etc.
The only difference between the format of this file and the format
of the configuration file is that here,
commands only specify
working directory and are local to this file.
Specify a new `new link' file(default slink.new). This file is
created during the -report action and contains a list of directives
that you can add to the configuration file for things not originally
done by Slink. It is limited to
requests for obvious reasons.
In this section we outline the administrative procedures required to
utilize Slink in the simplest possible environment: one UNIX host
managed by a lone system administrator. These techniques apply with
minor modifications to more complex environments.
To use Slink, one must first decide where to locate image and source
trees. For us, images are located in /local (giving us the option
of maintaining also a `normal' /usr/local) and packages are located
in /loc, /loc1, /loc2, and /loc3. There is no limit to
the number of disjoint package trees one can utilize.
The simplest possible scenario is as follows.
All packages are installed in /loc.
Images of packages are maintained in /local.
As few files as possible are placed in /local, but
treated as sacred when placed there (protection model
All Slink directives are `link's.
Slink constructs one image environment for users.
To implement this plan, follow these steps:.
Edit slink.mod to contain the lines
and any other freezes that seem appropriate. In general, any
directory in the image tree what will contain files created by
programs is suitable for freezing.
Install each package in its own private tree with a
commands the user should be able to run, a
the user should be able to link to, and a
pages the user should be able to read.
For each package, type the lines
link package/bin bin
link package/lib lib
link package/man man
into slink.conf. Alternatively, place
in a subdirectory dist and type
link package/dist .
Run Slink by typing simply
to make /local/bin, /local/lib, and /local/man unions of
all the package trees.
Adjust each user's environment by placing
/local/bin into the user's execution path ($PATH or equivalent),
/local/man into the user's manual path ($MANPATH or equivalent), and
/local/lib into the user's library path ($LD_LIBRARY_PATH or equivalent).
Arrange to execute whatis(8), catman(8), or equivalent to
periodically update the whatis(5) database appropriately.
The beauty of this is that once all this is completed, one may install.a package simply by putting it into a tree and editing slink.conf
to change all user environments at once.
This basic model of Slink use can be easily refined to handle more
To support multiple user environments, construct an image for each
using configuration file commands. Even the least sophisticated
site can utilize three environments: one for normal users (/local),
one for old programs some people are still using (/local/old),
and one for new programs as yet untested (/local/new).
To support multiple installers, assign each one a package tree or
particular directories within an existing package structure.
Make each assigned directory owned by its assignee.
To support multiple versions of the same commands, install them in disjoint
trees and utilize Slink directives to rename their commands in the image
To support multiple identical machines, replicate package trees as
desired and distribute the same master Slink configuration file to
each. Slink will ignore nonexistent packages, so the same
configuration file will work for all hosts.
To keep track of multiple
trees with parallel structure,
use Slink to construct a composite package tree containing all the
packages. This composite tree can then be utilized as a link source,
because Slink will resolve the multiple link path back into a
single link for each imaged component. This strategy is particularly
handy for identifying duplicates in multiple package hierarchies
mounted remotely from different machines. Slink will report such
duplicates as multiple sources!
Typically, a package consists of the installed files from a single
tar'd software distribution obtained from anonymous ftp or a vendor,
though interdependencies between related distributions often require
that all the distributions be placed in the same package. For
example, gcc and g++ are essentially the same program with different
arguments, and libg++ is needed for anyone to do anything with g++, so
all three are inseparable and should probably occupy the same package.
As the main purpose of packages is to document relationships between
files, the minimal package consists of two related files, typically a
compiled program and its source code. Stand-alone shell scripts do not
need to have their own packages as they consist of exactly one file,
the script itself, and the consequences of deleting that script are
clear: that one program will not work. This is also true for
software that is distributed as a single binary image, though we
usually do not, as a rule, install free software off the net unless it
is available in source form and compiled by us (binary images can
contain viral infections, no matter how reputable the source). We place
such binary releases in a special package `alone'.
Slink is powerful enough to integrate a package regardless of how you
install it. But careful structuring of packages will make both
configuration file editing and later cleanup easier. The basic rule
is that ease of use is directly proportional to the structure you
utilize in installing packages, and the parallels between that
structure and the structure you want in images.
files the user must access directly. These include programs the user
must execute, including compiled object-code as well as interpreted
scripts; e.g., contents of directories named
also include libraries the user must load to run a a program, either
with ld, with ld.so, libraries for an interpreter such as perl, and
databases that user-written programs must read, such as fonts; e.g.,
contents of directories named
. They also include documentation
the user must be able to read; e.g., contents of directories named
with some suffix.
files that the package must access, but which do not need to be
available to the user. These include private programs and libraries
that only the programs in the package should use, and databases used
only by the programs and/or libraries in the package.
files that document the package but are unneeded by the user or
package components during normal use. These include source code that
is compiled and installed before use, such as C code, or scripts that
require pre-processing to be usable, as well as installation
instructions, READMEs, and administrative documentation.
The three kinds of package files must be treated differently.during installation:
Files the package needs to work (types a and b) are stored in the
package tree, but type b files are invisible to the user, The package
is compiled to refer to the latter by pathnames in the package tree,
rather than by pathnames in any image tree.
Files the package doesn't need to work (type c) can be deleted when
the package is working properly.
The eventual goal is to place references to your installed files into.the tree /local, so that users can get to the files. In /local,
for ease of use, files are organized in subdirectories by type. The
subdirectories have the same names and meanings as subdirectories of
/, /usr (and /usr/local), in normal UNIX systems. It makes
life much easer if each of these is mirrored in the package source
tree with a parallel structure to how it should look in /local.
Here's a list of conventions for naming UNIX directories.
This information is usually contained in the manual for each system,
but I'll reproduce it here for efficiency.
files to be included in source during compilation.
`.h' files for libraries should be put here so that
the types of routines are correctly declared in applications.
These would traditionally be installed in /usr/include or
general manual page subdirectory for user documentation. The
subdirectories of this directory contain files read by the man
command. These subdirectories would normally be found in
/usr/man or /usr/local/man. These are broken down as follows:
If a package refers only to its own files, installation is easy.
Things become a bit more tricky if a package refers to files from
other packages. The principal problem is that it is relatively easy
to delete a package upon which another package depends, or upgrade one
package with the result of breaking another that uses it.
I utilize the following rules for
compiling references to files into packages.
If a package refers to a file from another package, and the
revision of the other package doesn't matter, make the
file public in /local and refer to it by the public pathname.
If a package refers to a file in another package, and the revision of
the other package is crucial (e.g., CVS utilizes RCS utilities), then
the referring package should directly refer to the private contents of
the other package's installation tree. The logic behind this is that
if the utilized package is deleted, the utilizer will be broken, so it
might as well refer directly. This also allows a different version of
the utilized package (e.g. RCS) to be made available to normal users.
If one directory of information needs to be writable to several
packages, (e.g., the emacs `info' tree), and it's not clear which
package it belongs within, put it in a package by itself. This way,
no package that utilizes it will be broken if another is deleted.
Of course, in our experience, the emacs `info' tree is one of the
few things in an average UNIX that requires this special treatment.
And one can simply place it under emacs where it expects to go, with the
one drawback that upgrading emacs means upgrading it.
This is not a perfect solution to the problem, because Slink does.not keep track of inter-package dependencies. In practice, we find it
necessary to be quite careful in deleting packages to avoid problems,
including a process of demotion to `old software' status (and removal
from the user's image) without deletion, followed by package renaming,
a waiting period to uncover potential dependencies, and deletion if no
problems are uncovered in a month or so. This strategy is not perfect
but for us has required a minimum of reinstallations to repair
reference problems, partially because referencing packages get
upgraded at our site as quickly as referenced ones.
In several years of utilizing Slink, the authors' principal problem
has been managing the complex package trees that Slink integrates.
Particularly, it is difficult to avoid unknowingly duplicating
software in complex hierarchies. One simple tip is to organize
the package hierarchies in two levels, the first of which is
categorical and the second of which contains actual package
directories. This allows one to easily check for duplicates,
because presumably two copies of the same package will be installed
in the same place. Our categories, which should not be treated as
definitive, are as follows:
Of course other sites will have differing needs. Our logic was to.define one level of categories that roughly split software into equal
segments, so that search time for a particular package is minimal.
Over the years, we have discovered the hard way that multi-level
filing systems and non-categorical filing waste more time than they
The real power of Slink is that it allows a head administrator to
delegate installation tasks to a wide variety of assistants.
These assistants can differ in abilities and level of trust,
from being trusted only to install something correctly, to being
trusted as root. This institutes implicit training milestones
after which a person advances from one level of competence and trust
to the next, as well as a scalable mentoring scheme that amplifies
the capabilities of high-level administrators with a large number
of trainees capable of performing useful tasks.
For example, within Tufts Computer Science,
we utilize a three-tier training scheme consisting of
who are given the root password and all privileges pertaining thereto,
including unlimited access to Slink.
People are promoted from one grade to the next after they demonstrate.competence and appropriate conformity to administrative policies,
constructing a natural `training loop'.
The key to implementing a successful multi-tier scheme is careful
attention to directory permissions in both the source and image trees.
To construct our three tier mechanism, perform the following steps:
Create a group whose members have the right to execute Slink.
For us that is the staff group, but it could be any group.
Make all of Slink's databases writable to staff. Optionally, for
better results, place configuration files under control of RCS to
eliminate writing conflicts in updating them.
Make all directories in source and image trees writable to staff.
By an appropriate mechanism, enable BSD-like group inheritance for
directory contents in the image tree(s). If this behavior is not the
default for your UNIX, it can usually be accomplished by
chmod g+s dirname
for every dirname in the image tree. This only need be done once
because Slink will propagate the setgid bit in creating new directories.
Once these conditions are in place,.Only root and members of the staff group will be able to
execute Slink, because others will not be able to modify contents
of directories in image trees. With this limit, one can train
people in software installation in a very orderly and scalable way:
One starts interacting with the system as a novice with no
privileges. Each novice is assigned a staff member who checks work
and executes Slink for that person. Thus the novice's installation
work can be reviewed before incorporating that work into the user's
Once competent in that role, the novice is made a member of the
staff group and allowed to run Slink and modify its databases. As
well, the new staff member is assigned another admin with root
privileges who moderates and implements system changes outside of
Slink's image trees (starting daemons, modifying /etc/services, etc.)
Once the staff member understands all ramifications of being root,
that member is given the root password and becomes a mentor to others.
We have utilized this structure in our academic environment for many.years with very few problems. In practice a novice will often need to
directly approach someone with root privileges to get something done,
but this structure minimizes demands on the time of those admins by
interposing an intermediary layer. At times we also blur distinctions
between the three levels, by granting temporary staff or root
privileges pursuant to a particular task. There is also an
administrative level above root access: the ability to enforce
conformity over an entire network. That level requires facility with
the DISTR and rdist(1) tools and will not be discussed here, though
at our site a similar mentoring arrangement exists between root users
and network administrators.
It has been said that security tools are useless without an appropriate
security policy, and that this policy should predate the tools.
The same is true for Slink; effective use requires the institution of
appropriate administrative policy to keep things straight.
Before designing a policy, answer the following questions:
Who is administrating this machine? One person? A large group?
What are the administrative skills of these people? Can they
be trusted to do things right?
What pre-existing infrastructure must be preserved?
How critical is it to preserve system operation during upgrades?
How critical is it to avoid corrupting image trees with files that
cannot be tagged for deletion?
Depending upon the answers to these questions, you may need more or.less administrative structure than described above. If your turnover
for systems is so fast that filesystem corruption is not a problem,
perhaps you do not need Slink at all. In a more extreme case, where
you don't want to trust anyone other than root to modify the user's
environment, you could require each installer to create a personal
configuration file for each package that simply gets included in the
master file when appropriate. If, conversely, everyone working with
Slink is an expert, you might not need to bother with a staff group.
This use of Slink comes from the common situation that
the local disk in a personal workstation is not large enough
to contain a complete UNIX distribution, but that distribution
is available via some network file system abstraction.
It is easy and practical to utilize Slink to build a tiered
filesystem within which files available locally are accessed
locally, while files available only remotely are made available
locally via symbolic links.
For example, suppose we have an incomplete local /usr and
a remotely available complete one, mounted as /lusr.
We instruct Slink to
link /lusr /usr
This has the effect of making links from /usr to everything in
/lusr that isn't in /usr, excepting things in /usr/spool that
are inherently local in character. Thus local system accesses only
incur link and network overhead when the requested file isn't local.
This approach works so well that when building workstations with
limited disk space at our site, it is the rule rather than the
It should be clear by now that the
directives were afterthoughts rather than principal features of Slink.
Slink can do everything required for normal image maintenance without
these abstractions. They were included for two advanced uses:
embedding frequently utilized files in the image tree to reduce
symbolic link traversal overhead associated with normal Slink operation.
replicating certain subtrees of a master server's package hierarchy on
local clients for execution efficiency.
creating modified images of read-only filesystems such as CD-ROM's by
selective overriding of links to them.
In the first instance, we simply wish to avoid traversing a link in the
image tree; for example, at our site we copy perl(1), tcsh(1),
and slink(1) into the image tree to avoid link traversals.
One must remember, however, to instruct applications to refer to
the copies where appropriate, not to master files in the source tree,
or misleading situations can result. In practice, the link overhead
generated by Slink is hardly noticeable and we do not make much use
of this option.
The copy command can also be utilized to modify local files in the
tiered hierarchy described above. A normal cp(1) operation
would attempt to traverse symbolic links and modify the master,
which should not work if that master is correctly mounted read-only.
Due to the network overhead of retrieving files from huge packages
, gcc, etc., it is often desirable to keep copies
of selected packages on clients rather than the master. But since disk
space is usually limited on clients, we prefer to replicate only those
files that improve general system performance. The rest are obtained
via network file service from a master fileserver.
Replication is simple indeed, and the exact opposite of
the procedure for completing a filesystem. First we replicate
the structure of the
package hierarchy itself and copy the files we want to replicate.
Then optionally we arrange for unreplicated subtrees to be automounted when
referenced. Finally, we run Slink on the machine to reconstruct
the image tree pointing to both local and automounted trees.
For example, suppose we have packages
on the master server. We decide to replicate the perl package.
On the slave, we mount /loc from the server as /rem,
so that all packages are available by the wrong names.
We then ask Slink to
copy /rem/perl5.001m /loc/perl5.001m
link /rem /loc
This makes /loc an image of /rem, so that all local references
work just as on the server, but specifically makes a copy of
/loc/perl5.001m that overrides the link (because the protection
for /loc doesn't allow a link to override a file).
Likewise Slink can only create the copy, and overwriting it requires
one to assign rights to do that, to wit:
One has to modify the configuration file after this step back to the
original configuration, or Slink will try to recopy every time it
runs. Of course, this is awkward and points to an inelegance in the
protection scheme. Slink works around this awkwardness by not copying
unless versions differ according to rdist(1) rules.
For a final (and extreme) example, we desire to modify a read-only
system without really copying all of it. For example, let's suppose
we want to run LINUX from its CD-ROM but modify /usr. If we mount
an empty filesystem as /usr and the CD-ROM as /cdrom, and form
link /cdrom /usr
then all references to /usr will work and actually reference /cdrom.
Now let's make a simple change to /usr, e.g., changing the contents
of /usr/lib/X11/Keysym.db. To do this, we
copy /source/Keysym.db /usr/lib/X11/Keysym.db
Slink automatically restructures /usr into directories of links and
embeds the requested file within them. One warning: this is very
advanced use of Slink and requires complete knowledge of how files are
utilized. In particular, relative symlinks in the source tree
/cdrom will still point to files in /cdrom unless they are
specifically overridden by Slink and appear explicitly in the image
tree /usr. Relative addressing of things in /usr by programs is
unpredictable and will need to be addressed on a case by case basis by
incorporating more structure into the ersatz filesystem /usr so
that these references resolve correctly. This last technique is not
for the faint of heart, nor for people with enough space to simply
copy the CDROM and utilize the copy.
While this section need not be understood by everyone, it helps the
advanced user to understand exactly what Slink does. Slink is both
deterministic and completely predictable to the initiated
Slink performs link requests by implementing a generalization of a symbolic
link that we call a slink. Unlike a symbolic link, which asserts
the equivalence of single files, a slink asserts containment
relationships for whole trees of files. We write
B <= A
to mean there's a slink from directory A to directory B, which means
that A contains links into B that make B appear to be a substructure
of A. If also
C <= A
then A embodies the union of the directory hierarchies B and C (but
perhaps more). If A happens to be a regular file, then
B <= A
degenerates into the normal symbolic link
B <- A
Slinks can be used to construct virtual working trees of
installed software from several disparate, private software trees
maintained by several users. If we have trees
then /local becomes a merge of all of the structure of the three disparate
Thus users can refer to the combined tree /local, while installers
continue to work autonomously in their private trees that /local
references. In this way we completely eliminate conflict between
installers, while maintaining the illusion that they work in the same
space. The effect for users is that they keep the same execution
path, manual path, and library path as packages are installed and
(which installs Slink itself on our system) says that by some
mechanism to be determined, the file /loc/adm/slink-5.0/sbin/slink
should be accessible as /local/sbin/slink. The way this is
accomplished is left up to the Slink program itself. For example, it
could form the physical symbolic link
at its own discretion. For now, Slink's only mechanism for creating
slinks is to use normal symbolic links, but one should not think of it
as limited to this mechanism; new prototypes can mix hard and symbolic
links, and Slink eventually might be able to use other mapping
mechanisms, such as filesystem mounts. In this discussion, we will
always write slinks from B to A as
A <= B
in accordance with the syntax of Slink, which will create that slink
if you type the command
slink -link A B
or include the directive
link A B
in Slink's configuration file.
As another example, the slink
/loc/adm/slink-5.0/sbin <= /local/sbin
says that the things in the directory /loc/adm/slink-5.0/sbin (e.g.
the command truename) should be accessible from the directory
This containment relationship holds for each file or directory within
/loc/adm/slink-5.0/bin to arbitrary recursive depth.
In general, a slink at a particular level of the directory hierarchy implies
slinks at all subdirectories, i.e., the slink
source <= image
implies all slinks of the form
source/path <= image/path
for each path existing in
The converse is not true, but if we say
source/path <= image/path
Slink reserves the right to slink
source <= image
at its convenience. In other words, relationships between
subdirectories of `slinked' directories are guaranteed, while
relationships between parents of the same name are possible but not
guaranteed. Higher-level relationships occur if there are no other
conflicting links at upper levels.
Given a Slink directive, Slink chooses the appropriate
method of accomplishing the slink, so that
Access to the source file involves traversing exactly one symbolic
link. Paths involving multiple links are resolved into a single
All slinks to the same image path are merged into a coherent
image tree, barring naming conflicts, so that the image is a
symbolic union of all sources.
A minimum number of links are used to form this union.
Slink uses a `promotion' algorithm to minimize the links it uses while
protecting the system from disruptive changes.
If trying to make a link to an image directory, and no current link
exists, make a single link to the source from the image tree.
If a current link exists, and points to the correct source
directory, leave the link alone.
If a current link exists and points to a different file, then erase
and correct it.
If some component of the image path is a symlink that points
to a different directory, then
remove that link,
replace it with a directory of the same name,
make links in that directory to the members of the original source directory, and
add links in the new source directory to the links to the old source directory.
Obviously there are a lot of nonsensical things that Slink won't do,.including `promoting' a file to be a directory. etc. If you ask it
to do something nonsensical, it will simply refuse to do so and
continue processing without doing so. However, promoting a file to a
directory is legal under protection model `replace'. The file is
simply removed and replaced by a directory. Caution is necessary
whenever files are present in the image tree.
The -condense option instructs Slink to do the opposite of
promotion. This is not done during normal Slink execution due to the
possible disruptive effects to users, who may change current working
directory to one that ceases to exist. The algorithm for condensing
replaces a directory of links with a link exactly when
The replacement will not make new files visible that were not visible before,
nor hide files that are currently visible.
The replacement will not delete links from image nodes mentioned in
slink.conf. I.e., condensing only occurs at the level
of the link or below it, never above it.
The replacement will not entail deleting any files.
The protection mode of any directories to be replaced is at least
The protection mode of any links to be deleted is at least
For example, if we have only the files.
in /loc/adm/slink-5.0/sbin and only the physical symbolic links
in /local/sbin, but the configuration file has only the lines
link /loc/adm/slink-5.0/sbin /local/sbin
and we execute
slink -condense /local
then the two links will be condensed, by removing them, removing the
containing directory, and reforming the single link
/loc/adm/slink-5.0/sbin <- /local/sbin
Since this link embodies the effects of both of the other links, and
the resulting apparent contents of /local/sbin are unchanged by the
transformation, Slink replaces the redundant directory /local/sbin
with a single link.
Slink does not have transaction control. Slink attempts to
implement every change it's told to implement, subject to the simple
rule that it is permitted to do something if ``it can do what it may
do''. This means that no errors are flagged when the protection model
denies something, but that it is an error to fail to have physical
permission to do something that protection models allow.
Ideally, Slink should not allow changes to occur for a single
transaction unless physical protections are correct for all actions
implied by the transaction. It does not do this, which can lead to
half-installed packages if the user does not have sufficient
permissions. The fix for this would be to add a `commitment' phase
before implementation that would check whether all permissions are
correct before doing the transaction. This would in turn make
transactions somewhat atomic.
Slink does not, by default, check the global consistency of
operations in its configuration file. Instead, it does a running
consistency check and informs the user if any source changed
during a run. This means that it's usually necessary to run Slinktwice to figure out whether things are really inconsistent, when