------------------------------------------------------------------------------
			   API for Hibernate Scriptlets
------------------------------------------------------------------------------

A scriptlet is written in shell code, and is simply sourced into the main
script.  This means it can potentially change a lot about the way suspending
works.  For sanity's sake though, their actions should be restricted to work
through a small set of functions provided by the main hibernate script.  These
are documented below.

A scriptlet can request both extra command-line arguments, or extra
configuration file options. It can execute arbitrary commands during the
suspend and resume process.

NAMING
------
A scriptlet's name (filename) is restricted to alphanumerics and the underscore
(_) character. Otherwise, things will break! It must not conflict with an
existing script (the hibernate script will warn if it does). Function and
variable names within the scriptlet should be sufficiently unique (eg, prefixed
with the name of the scriptlet).

STDOUT/STDERR
-------------

A scriptlet should use vecho rather than echo, and choose a verbosity level
appropriately (see vecho, below). All scriptlet output is automatically sent to
$LOGPIPE

FUNCTIONS
---------

AddSuspendHook NN function_name
  This will add the given function to the chain of functions called at suspend.
  NN must be a number between 00 and 99, inclusive (see ORDERING section
  below).

  A scriptlet should only add a function to the suspend chain until it knows
  that it is going to do work (eg, it parses a config option to do something).

  eg: AddSuspendHook 55 SuspendHair

AddResumeHook NN function_name
  Similar to above. See ORDERING section below.

  eg: AddSuspendHook 55 ResumeHair

AddConfigHandler function_name
  The given function_name will be called when a configuration file line is read
  and hasn't been handled already. The entire line is passed as parameters to
  the function. The function must return 0 if it handled the function, and 1
  otherwise.

  eg: AddConfigHandler HairParseConfig

AddConfigHelp <config option name> <help text>
  Similar to above, but for configuration file options.

  eg: AddConfigHelp "HairTime <boolean>" "Allows some extra time to wash your hair while suspending."


AddOptionHandler function_name
  The given function_name will be called when a command line option is received
  that hasn't been handled already. If the option has no parameter, then the
  function is called with a single paramter, which is the option itself in
  single quotes (eg, '-t' or '--time'). If the option has a parameter linked
  with it, the function is called with two parameters - the first is the
  option, as before and the second is the parameter. The function must return
  0 if it handled the function, and 1 otherwise.

  eg: AddOptionHandler HairParseOptions

AddShortOption <option character>
  Adds a short option to the list of accepted options for the function.

  eg: AddShortOption t

AddLongOption <option name>
  Adds a long option to the list of accepted options for the function.

  eg: AddLongOption time

AddOptionHelp <option name> <help text>
  Adds help text to the help screen. The help text must have each paragraph on
  a single line.

  eg: AddOptionHelp "-t, --time" "Allows some extra time to wash your hair while suspending. If you find you are often out of shampoo, then specifying this twice may give you enough time to duck out to the shops to get some and still wash your hair."

vecho N <echo params>
  N is a verbosity level between 0 and 4 inclusive. If the given verbosity
  level is greater than or equal to N, the text will be written to screen and
  logged to file. Verbosity levels are :
    0: silent except for errors
    1: print functions executed
    2: print functions executed with debugging
    3: print functions executed with lots of debugging
    4: use shell's -x option to print every command executed (very noisy)

HOOK FUNCTIONS
--------------

Hook functions are called at the relevant point in the suspend/resume chain
with no arguments. Suspend hooks can choose from the following return values:
 - 0 if they are successful.
 - 1 if they are unsuccessful but can be overridden with --force.
 - 2 if they are unsuccessful and the suspend *must* be stopped (a message
   is written indicating the suspend was aborted.
 - 3 if the scriptlet requires the suspend script to silently abort *right now*.

ORDERING
--------

Each scriptlet can register functions to be called at some stage in the suspend
process. The stage is identified by a two-digit number, between 01 and 98,
inclusive. 00 and 99 are reserved for use by scriptlets that implement a
suspend method (eg, TuxOnIce) which require absolute certainty that they are
the first and last things executing.

On suspend, the scripts are called in ascending order.
On resume, the scripts are called in descending order.

The following general recommendations apply:

 00 for standalone features instead of suspending (probably useful to return 3)
 10 suspend capability detection
 11 definitely going to suspend by this point
 20 user programs stopped
 30 services started/stopped
 50 filesystems mounted/unmounted
 60 networking start/stopped
 90-91 kernel modules loaded/unloaded
 95-98 all sorts of voodoo to get VT switching happy in all cases
 99 reserved

Running "bash admin/list-hooks.sh scriptlets.d/" will produce a list of all the
hook functions in order of execution if you need to look closely.

POSIX COMPLIANCE
----------------

In order to keep the script running correctly under not only bash, but ash and
zsh, some extra care needs to be taken when writing scriptlets. The common
points to note are:
 - source: Don't use source. use . instead. You also need to specify a path,
   even for files in the current directory (./foo).
 - = not == for string comparisons.

For the script to work under zsh, certain options need to be changed in order
to make zsh act less sensibly (see setopts at the start of hibernate.sh).

WHITESPACE NAZI
---------------

Not wanting to be too pedantic, but for consistency, whitespace should be done
using "tabstop=8, shiftwidth=4, noexpandtab" and softtabs in vimspeak. This
means that it renders well anywhere (tabstops are universally 8 spaces), and
tabbing is consistent. Don't worry too much - I'll generally fix the whitespace
in any code I commit.

SKELETON EXAMPLE
----------------

This needs more work, but gives you the general idea of structure.

--- snip: scriptlets.d/skeleton ---
AddConfigHandler SkeletonOptions

SkeletonSuspend() {
    return 0
}

SkeletonResume() {
    return 0
}

SkeletonOptions() {
    case $1 in
	*)
	    return 1
    esac

    if [ -z "$SKELETON_HOOKED" ] ; then
	AddSuspendHook 20 SkeletonSuspend
	AddResumeHook 20 SkeletonResume
	SKELETON_HOOKED=1
    fi
    return 0
}

$Id$
