GUIDE to the SAM Distribution

Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2010, 2011, 2012,
2014, 2015, 2018, 2020, 2021, 2023 Joseph Rosevear



1.  A short table of references in this distribution.

2.  What is this?

3.  Some terminology.

4.  Installing SAM.

5.  Running SAM.

6.  Using SAM.

6.1 SAM command sets.

6.2 The SAM prompt.

7.  About SAM menus.

8.  Special variables.

9.  There is a nuisance you may encounter.

10. SAM's temporary and scratch directories.

11. Shells used.

11.1 Synthetic shells.

11.2 Batch mode.

11.3 Bugs in SAM.

11.4 SAM limits.

12. SAM.tool.

***


0.  Information about SAM that is online.

See the website:

   https://rosevearsoftware.sam/products/sam

1.  Informative files in this distribution.

$sam_root
---------
CONTENTS
COPYING
GUIDE
TIPS

$sam_root is the root of the installation.


2.  What is this?  This is a distribution of SAM.  It was written by me,
Joseph Rosevear.  See file COPYING in this distribution for a statement
of the license agreement.


3.  Some terminology.  I distribute SAM as a tarball.  A "tarball" is a
directory tree compressed into a single file by use of tar.

I have in the past referred to SAM as "SAM Kernel and Application", "An
Application of SAM for GNU/Linux Slackware, or "SAM-GLS".  These are
all the same project, although it has changed over time in content,
structure and function.


4.  Installing SAM.

Please see the information that is available online:

   https://rosevearsoftware.com/products/sam/get


5.  Running SAM.

I have provided instructions for running SAM online at:

   https://rosevearsoftware.com/products/sam/get

These instructions (above) explain how to use begin to run SAM.  Please
refer to these instructions.

The section below gives additional information about the use of begin
and explains also the use of the other executables found in $sam_root.

These executable scripts in $sam_root participate in running SAM.  They
are:

   begin
   bgen
   bits
   bree
   breekit
   buser
   bxadd
   bxauth

You should use the full path when invoking these scripts.  I'm not sure
if this is necessary for all of them, but it is for at least a few, and
this therefore will avoid confusion.  Also, all but bxadd and bxauth
can be run as an ordinary user or as root, although the purpose of bree
and breekit is to become root, so you wouldn't ordinarily run these as
root.  Scripts bxadd and bxauth run xauth which belongs to X.  X
doesn't like root, so don't run them as root.

Here are explanations these scripts:


   begin          Runs SAM for ordinary users and root.  Nested
                  invocations (running SAM from inside SAM) are
                  allowed.  The resulting shell (nested or ordinary
                  invocation) inherits all exported variables plus
                  non-SAM exported functions.

   bgen           You should make symlinks to bgen in /mnt/your_root
                  directory.  Give these symlinks the names of any
                  script in $sam_root that you wish to use in dual
                  mode, but only symlinks "begin", "bree" and "breekit"
                  are necessary.  You can invoke the other scripts
                  directly.

                  Use the resulting symlinks in the same way that you
                  would use the corresponding scripts in $sam_root.

   bits           This script is used internally by SAM.  It enables
                  the managed invocation of three compiled executables
                  which SAM uses.  In particular it automatically
                  chooses between 32 and 64 bit versions that are
                  included in the SAM tarball.

   bree           Runs SAM again from an environment in which it is
                  already running.  The new instance becomes root and
                  inherits all exported variables plus functions that
                  were defined by SAM.  If there are any non-SAM
                  exported functions, these will be inherited also.

   breekit        Uses begin to run SAM, and then bree to run SAM
                  again, recursively, as root.  It inherits variables
                  and functions in the same way as begin.

                  Like begin, this script allows nested invocations,
                  however I can think of no reason you would want to do
                  this.

   buser          This script is for use in X on ZombieSlack
                  systems.  It enables the shell to use special
                  ZombieSlack functionality.  Doing so, it opens a
                  shell as another user.

                  ZombieSlack is another project of mine.  A
                  ZombieSlack system runs a specially tailored version
                  of Slackware.

                  This b-file is an alternative to begin.  Use it from
                  inside an xterm.  Supply a username or "root" for $1,
                  then login.  Next, in the xterm that opens, start SAM
                  using "begin" or similar.  This allows you to run SAM
                  as a different user when in X.

                  Note that this is not the same as what you get by
                  using bxauth and bxadd.  buser is faster and can do
                  at least one thing that bxauth and bxadd cannot do. 
                  Namely, it partners with the command "dog" of menu
                  $env_handy to run a web browser in a special way. 
                  Otherwise it is noticeably lacking, as you cannot use
                  it to run X applications.

   bxadd          Run this script from a remote X session after first
                  running bxauth, on a local X session.  It will give
                  you a local xterm which belongs to the remote
                  session.

                  Use $1 to provide the value of DISPLAY, less ":", for
                  the local session.  

   bxauth         See notes for bxadd.


6.  Using SAM.

After invoking SAM you will see that the prompt has been changed.  It
will look something like this:

   sam 1::)1
   student@220506aa1:/mnt/joe_root)

There is a lot of information in the two-line prompt, but I won't
describe it yet.  If you get a prompt that looks something like the
above, then you are in SAM.

The first command to learn is "menu".  Invoke the menu command.  You
should get a screen that begins like this:

   added:
   
   /mnt/SAM_root/lib/tool
   /mnt/SAM_root/main
   /mnt/SAM_root/kernel
   
   ::
   
    COMMAND       DESCRIPTION
   
   SAM is a flexible, text-based menuing system.
 
The menu name is normally displayed after the ":" above, but as there
is no menu currently defined the prompt shows "::".

Even though there is no menu, you can still tryit out.  Scroll up and
down with the up and down arrows.  (You are actually using the "less"
command.) Pressing "q" returns you to the command prompt.  Enter "menu"
to display the menu again.

One way to use SAM is to enter commands from the current menu to do the
things described by the menu.  This works, because the commands of the
current menu are added by SAM to the PATH.

This is the quintessential use of SAM.  The menu shows shows you what
the current commands are.  You may not remember them otherwise.  The
menu also describes how to use the commands.  This allows use of
commands that take multiple arguments: the text of the menu is a handy
reference that defines the use of $1, $2 and so on.  With such a
reference readily available you can write and use code that is more
powerful than what you could manage otherwise.

SAM, however, makes many commands available, not just the commands of
the current menu.  Every use of the menu command, whether there is a
currently defined menu or not, will show a list of added paths.  These
are paths that have been added by SAM to the current command set.  They
are listed below "added:"

You can see above that there are currently three paths added.  The menu
shows their full names, but these names are equally valid:
"$sam_root/lib/tool", "$sam_root/main" and "$sam_root/kernel".  SAM
plays by its own rules.  It couldn't do the things it needed to do
without having the commands of "$sam_root/kernel" available.  Some of
these commands are handy for your own use as well.

There is no magic in the menu command, and very little code.  All it
does is display file $level/menu.dat.  However, that is just what is
needed.  I wrote a menu.dat file for the kernel.  You can see it, or
any menu, even when it is not current by this use of the menu command:

   menu $sam_root/kernel

This, instead of showing the current menu, displays a named menu.  Try
it and you will see that the menu command itself is listed and
described:

       menu       If $1 is "", displays current menu.  Otherwise
                  displays menu for $1.

Other commands of the kernel that you will surely use are "bound",
"bye" and "library".  These you may also find useful: "hello",
"library" and "shoparts".

Remember always to press "q" to leave a menu before entering a command.

Use "exit" to leave SAM.  This is not a SAM command.  It works by
exiting the shell that is keeping SAM open.  It is like pulling the
stopper from the bath tub--the water goes down the drain.

Use "bye" to leave a menu and return to the previous one.  When there is no
previous menu "bye" will take you all the way out of SAM.

Use ";" to separate commands on one line.  This is a feature of Bash,
not of SAM, but it works well in SAM.


6.1 SAM command sets.

Command sets are introduced in the online documentation at
https://rosevearsoftware.com/products/sam.  Here is some more
information about them:

When SAM adds a path to the current command set it is doing two things. 
The first thing should be familiar to you.  A path added to the current
command set is added to PATH followed by a subsequent use of "hash -r".

The second thing SAM does is perhaps new.  A path added to the current
command set is examined.  Any qualifying function definitions that are
found in the added path are sourced, and the functions thus defined are
exported.

Similarly when a path is removed from the current command set it is
removed from PATH, "hash -r" is run, and the functions which were
defined by qualifying definitions in the removed path are unset.  In
this way the functions of the added path come in and out of scope in
parallel to executables of the added path.  This allows the concept of
a "command set".

For a function definition to qualify for this behavior its name must
end in ".sam" and it must contain "OK SAM" in the first 10 lines of the
function definition.  Each such file may contain multiple function
definitions, but one of them should define a function having the same
name as the file less ".sam".  That function is the only one involved
in this special behavior.

As mentioned above you *can* put multiple function definitions in a
file that has a name ending in ".sam", but you need to be aware that
the additional function definitions will be sourced and exported by
SAM, but will not be managed by SAM in any other way.  They will remain
in scope until you or your code unsets them.  This is OK, but it
complicates the use of SAM and therefore is not recommended.


6.2 The SAM prompt.

Here is a breakdown of the parts of the prompt:

   \n$sam_file:${level}${sam_symbol}${sam_env_num}$sam_env_num
   \n\u@\h:\w${sam_symbol} 

   The first line of the prompt has these parts:

      sam <instance>:${level}${sam_symbol}${sam_env_num}

         <instance>   SAM can be started a number of times by each
         user.  Theses "instances" of SAM are counted, and the current
         value of the count is displayed in the prompt.

         $level        This is the path which the user selected to
                       represent the current menu.

         $sam_symbol   This is defined by script $sam_root/go/sam where
                       it is defined as ")" and exported.

         $sam_env_num  Each instance of SAM uses a stack of
                       environments.  $sam_env_num is the current
                       position in the stack.

      Note: Internally, SAM represents the instance together with the
      name of the file ($sam_root/go/sam) which was used to start SAM. 
      This combination is referenced in SAM as "$sam_file".  Therefore
      $sam_file is

         sam <instance>

   The second line of the prompt is:

      \u@\h:\w${sam_symbol}

         \u            user

         \h            hostname

         \w            working directory

         $sam_symbol   <See above.>

   Except for the use of $sam_symbol at the end, this is probably
   familiar to you.

I apologize if you have grown accustomed to having the final character
be "#" for user root.  I chose not to implement that behavior, because
SAM allows you to become root in a number of different ways which vary
somewhat in their nature.  Note that, in my experience, \u shows the
same value as `whoami`.  Therefore, if you see "root" in the prompt, it
is probably safe to assume that you are root.  That's what I do.  I
have not found this documented anywhere.

Here is a table which summarizes the different ways to become root in
SAM.  See the Key and Note below also:

     `whoami`/$LOGNAME/$USER in console
   ---------------------------------------
   before       after     after
   starting     begin     begin, then bree
   --------     -----     ----------------
   O/O/O        O/O/O     R/O/O
   R/R/R        R/R/R     R/R/R

        `whoami`/$LOGNAME/$USER in X
   ---------------------------------------
   before       after     after
   starting     begin     begin, then bree
   --------     -----     ----------------
   O/O/O        O/O/O     R/R/O
   R/R/R        R/R/R     R/R/R

   Key: O=Ordinary user, R=Root user.

   Note:  Use of breekit gives the same results as "begin, then bree".


7.  About SAM menus.

A menu for sam is a file named "menu.dat".  Make one and put it in a
directory, and it will be displayed by the use of the command

   menu

when it is the current menu.  To make a menu current use the "bound"
command.

I will illustrate with an example, but first I need to mention my use
of the term "current".  Hopefully you are familiar with "current" as it
applies to directories.  I have given the term "current" a new use by
applying it also to menus.  When a menu is "current" that means that
variable level has been given the value of the path to the directory. 
SAM then knows to treat it in a special way.

A directory is current when you are in it.  You go into a directory by
using "cd".  That is nothing new.  A menu is "current" when you "bound"
to the path that defines it.

Here is an example:

   /mnt/SAM_root/begin
   echo test > /tmp/menu.dat
   bound /tmp
   menu
   bye
 
This example makes the menu at /tmp current ("bound /tmp" does this). 
The "menu" command causes the menu to be displayed, and "bye" will exit
SAM.


8.  Special variables.

This variable can be used to control the behavior of SAM.  Set it
anyplace and anytime:

   sam_batch

      Exporting sam_batch with value of batch (or anything) will cause
      SAM to be run in a batch mode.  In this mode it will not give you
      interactive behavior.  Sometimes interrupting a shell script
      results in an interactive shell opening at the point where the
      script stopped.  Often this is not desired.  Use this variable to
      prevent this behavior.

This variable also controls the behavior of SAM:

   export sam_view=<alternate menu viewer>
   
      You would export this to change the viewer which is used by
      $sam_root/kernel/menu to display menus.
   
      The default viewer is "less".  A suggested alternate viewer is
      "cat".
   
There are other variables that are important to SAM but are normally
dealt with by your $sam_root/bprofile.  Read about them in
$sam_root/TIPS.


9.  There is a nuisance that you might encounter.  This nuisance
happens when files in $sam_temp_dir (which points to the current temp
for SAM) gets files in it that cannot be written to.  Say for example
that you have a temp dir at ~/temp1, but you get a file in it that
belongs to root.

When this happens you will need to change to root, go to ~/temp1 (or
temp2, etc) and change the ownership of the files back to the user (not
root). Or you can leave SAM, clean out the $sam_temp_dir's, and try
again.


10.  SAM's temporary and scratch directories.

This tells the scheme for SAM's temporary and scratch directories.


$sam_temp_base    You can set sam_temp_base to anything you want, but
                  $sam_root/bprofile included with this distribution
                  sets it to:

                     /tmp/`whoami`

$sam_temp_dir     You can set sam_temp_dir to anything you want, but
                  $sam_root/go/sam included with this distribution sets
                  and exports it like this:

                     export sam_temp_dir=$sam_temp_base/temp${1}

temp<n>           temp1 - temp<n> are made by this line in
                  $sam/sam_core:

                     mkdir --parents $sam_temp_dir

                  Note that (in this distribution) this will also make
                  $sam_temp_base if it does not already exist.

$env_scratch      I believe (but I'm not sure) that you can set
                  env_scratch to anything you want, but
                  $sam_root/sam_env included with this distribution
                  sets and exports it like this:

                     export env_scratch=$sam_temp_base/scratch

scratch           Make scratch any way you like, but in this
                  distribution scratch is made by this line in
                  $sam_root/brc:

                     mkdir --parents $sam_temp_base/scratch

                  Note that this will also make $sam_temp_base if it
                  does not already exist.

Note that the number of temp<n> directories is limited mainly by the
way in which SAM is configured.  In the current distribution the
maximum number of directories is configured by the way in which
$sam_root/begin invokes $sam_distro/go/sam1.  In particular, the
maximum is $1.

temp<n> are known as $sam_temp_dir.


11.  Shells used.

SAM uses #!/bin/sh in all* scripts but one.  That script
($sam/sam_core) has code that writes code to open additional shells. 
The code it writes uses "/bin/bash".  I chose "/bin/bash" over
"/bin/sh", because I wanted to use the --rcfile option.  Using this
option let me write better code, so I did it.  SAM, with the features I
described above, worked when I tested it in Ubuntu (see below), but
functionality in Ubuntu was not the reason for the design choices.

Note that I spent some time trying out SAM in Ubuntu.  In Ubuntu
/bin/sh is a link to dash.  SAM should work OK in Ubuntu if you first
change that link to point instead to the (traditional) bash.  Also you
may need to have a real root account.  I found that there was a change
you could make in Ubuntu to do this, but that was many years ago.  Here
are my notes, for what they are worth--I don't know if this still
works:

   Do "sudo passwd root" to get a real root.  If you change your mind
   do "sudo passwd -l root" to lock root again.



11.1  SAM's synthetic shell.

Besides the normal Bash shell, SAM uses an oddity that I call a
"synthetic" shell.  The synthetic shell is what allows SAM's command
sets to function.  See also the section above about command sets.

I invented the synthetic shell to give SAM the behavior I desired.  It
is coupled with $sam_env_num in the same way that a normal shell is
coupled with $SHLVL.  To help the user I gave SAM a prompt that
displays $sam_env_num at the end of the first line of SAM's two-line
prompt.  SAM needs the synthetic shell for it's operation, but you may
interact with it as well.  It works by pushing *some* of the current
variables onto a stack--which is actually a set of files in
$sam_temp_dir--and incrementing the variable sam_env_num.  To "pop" it
decrements sam_env_num and unsets, sets, and exports as needed to
restore the previous environment.  It's actually just a bit more
complex than this.  Look at the source code in sam/source to learn
more.  In short, SAM's synthetic shell works by manipulating the
current environment.

Let me explain my use of the word *some* above.  SAM pushes variables
that begin with a lower case letter onto a stack.  And variables that
begin with some other characters too.  The C code that is operating
here (set_filt.exe) selects all variables (for pushing onto the stack)
that begin with a letter with an ACII value greater than 96.  If you
examine an ASCII table you will see that this includes a-z and some
unusual characters, but excludes A-Z.  The intention was to exclude
variables in all caps which are normally environment variables, but you
can see that by my lazy coding I excluded more than just these.


4b.  Batch mode

SAM has a batch mode.  It is selected by exporting thusly:

   export sam_batch=batch

before invoking SAM.  In batch mode a shell will not stay open waiting
for a command line input.  This capability was added to SAM to allow me
to invoke it from crontab files.  It wouldn't work otherwise.

See $sam/sam_core for the details.


5.  Bugs in SAM

recursion:

You can invoke SAM inside of SAM, but there is one peculiarity when
doing so.  The functions that were defined before the nested SAM was
invoked will be inherited by the nested SAM.  That is they will be
unless something is done before SAM is invoked.

This is either a feature of SAM or a bug.  It is something that you
should be aware of.

SAM is written so that you can easily remove the existing function
definitions.  This guide is not about the application of SAM, but you
can be sure that any application of SAM that I write will automatically
remove inherited function definitions.  Still, you should be aware of
this, and be careful.

lockfile and msdos:

SAM uses the lockfile command to augment the protection given by the
use of the "in_use" file.  The in_use file protects against multiple
simultaneous uses of the same $sam_temp_dir, however it fails at this
when the user invokes SAM rapidly in succession.  That's where the
lockfile command comes in.  It almost fixes things.  The problem is
that I haven't been able to get lockfile to put a lock on a file in an
msdos file system.  There is no such trouble with the native Linux ext2
file system, so maybe this is a non-issue.

SAM tries to put the lock file in sam_temp_dir.  So if you are using an
msdos file system for $sam_temp_dir, be aware that there is no
protection against rapid successive invocations of SAM causing multiple
simultaneous use of a $sam_temp_dir.  You will see a warning from
lockfile that it cannot do it's job--something about praying.  If you
avoid rapid successive invocations of SAM when using $sam_temp_dir in
an msdos file system you'll be OK.


6.  SAM limits.

SAM has some limits that might be seen as bugs as follows:

Don't run instructional text files:

Be careful not to run instructional text files (such as this file). 
BAD things could happen.  Ordinarily such files cannot be run, because
they don't have execute permission.  However, if you run SAM from an
msdos file system, then you will not have this protection.  Or this
could also be the case if I (or someone) have given a text file execute
permission by mistake.

Beware commands and variables:

SAM has a few scripts and executables that you may not know about
unless you look.  They are not likely to do any harm, but it would be
smart for you to look and see what they are so you don't use them by
accident.  The documentation does not currently list all the scripts
and executables.

Similarly, SAM adds many variables to the environment.  It does this in
a shell, so you original environment is protected.  However, SAM
depends on these variables to do what it does.  You could have
difficulty if you alter one of them.  The documentation does not
currently list these variables.
  
cd `pwd`:

SAM does this (the above) in sam/pop.sam.  It is an odd thing to have
to do.  It is needed to make the prompt correct in certain situations,
but this isn't fully understood.

Disk space:

You can run out of disk space needed for SAM's $sam_temp_dir.  Although
this isn't likely, SAM does nothing to prevent it.  It would cause SAM
to fail.

Limited buffers:

A buffer in set_filt.c is of limited size and can cause failure.  The
code checks to prevent writing beyond the end of the buffer, but
unfortunately SAM cannot proceed if the buffer isn't big enough.  See
the source code for details, and be aware that this error message

   Buffer size exceeded.

means the buffer size limit has been encountered.  You are free to
change the buffer size and recompile.

Non existent local directories:

SAM doesn't care if you do this:  "bound /hey".  It works whether /hey
exists or not.  This is good, because SAM is a tool.  You may have a
reason to do this even if /hey doesn't exist.  Similarly, you can do
this: "bound hey".  The leading "/" has been removed.  Again you may
have a reason to do this.  In both cases if you aren't aware of what
you are doing, SAM may surprise you.

Mistakes of comprehension:

When writing SAM scripts you are really writing ordinary Bash shell
scripts.  Yet, there are mistakes of comprehension that can be made. 
It is easy to misunderstand what SAM does.  The methods of scripting
shown by the examples (that may have come with your distribution) work
well when each method is understood and followed.  If a method is not
followed, then it may not work correctly.  Similarly, if a method is
not understood, it may seem to not work correctly.  Both situations can
be frustrating, but such are not necessarily errors belonging to SAM.

Limitation in xargs:

SAM puts a lot of stuff in the environment.  In particular, it exports
a lot of variables and functions.  This is why I sometimes got an error
message which said "xargs: environment is too large for exec".  The
solution I found was to change xargs and recompile it, then replace the
original xargs with the corrected one.

Here's the piece of code I changed, before and after:

   Before:

      if (arg_max > 20 * 1024)
        arg_max = 20 * 1024;

   After:

    /* JHR 050813 I commented out and changed the two lines below */
    /*if (arg_max > 20 * 1024)
        arg_max = 20 * 1024; */
      if (arg_max > 40 * 1024)
        arg_max = 40 * 1024;

I learned that this was the needed fix by what I found when searching
in Google Groups "www.groups.google.com" on the quoted error message.

After doubling the limit (from 20K to 40K) I've had no trouble...yet.

Here's an update (today is 4-18-12):  The native xargs seems to work
fine now, so I removed the modifed xargs.  Perhaps the solution came
from a change that I made.  I added a filter called "slice" to the
kernel.  It is used by "push" and treats an odd runaway growth of the
environment (in particular, the variable TERMCAP).  Read the comments
in slice to learn more.


12.  SAM.tool

This distribution is equivalent to SAM.base with SAM.tool installed.

This installation of SAM.tool was done by simply unpacking SAM.tool to
$lib.  This makes and populates directory $lib/tool.

The commands of $lib/tool are documented in its menu.  You can read the
menu with this command:

   menu $lib/tool

And you can change to the menu with this command.

  bound $lib/tool
