]> granicus.if.org Git - postgresql/commitdiff
Make an editorial pass over the newly SGML-ified contrib documentation.
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 16 Dec 2007 23:00:42 +0000 (23:00 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 16 Dec 2007 23:00:42 +0000 (23:00 +0000)
Fix lots of bad markup, bad English, bad explanations.

Last ones ... whew.  Man, that was tedious.

doc/src/sgml/pgcrypto.sgml
doc/src/sgml/pgstandby.sgml

index e0e6d0c4210e4521a821e6c836fe9cc02f9986de..f7fe07c525c53bb55896713740031f8b3fbafade 100644 (file)
+<!-- $PostgreSQL: pgsql/doc/src/sgml/pgcrypto.sgml,v 1.3 2007/12/16 23:00:42 tgl Exp $ -->
 
 <sect1 id="pgcrypto">
  <title>pgcrypto</title>
+
  <indexterm zone="pgcrypto">
   <primary>pgcrypto</primary>
  </indexterm>
 
  <para>
-  This module provides cryptographic functions for PostgreSQL.
+  The <filename>pgcrypto</> module provides cryptographic functions for
+  <productname>PostgreSQL</>.
  </para>
 
  <sect2>
-  <title>Notes</title>
-  <sect3>
-   <title>Configuration</title>
-   <para>
-    pgcrypto configures itself according to the findings of main PostgreSQL
-    <literal>configure</literal> script.  The options that affect it are 
-    <literal>--with-zlib</literal> and <literal>--with-openssl</literal>.
-   </para>
-   <para>
-    When compiled with zlib, PGP encryption functions are able to
-    compress data before encrypting.
-   </para>
-   <para>
-    When compiled with OpenSSL there will be more algorithms available.
-    Also public-key encryption functions will be faster as OpenSSL
-    has more optimized BIGNUM functions.
-   </para>
-   <para>
-    Summary of functionality with and without OpenSSL:
-   </para>
-   <table>
-    <title>Summary of functionality with and without OpenSSL</title>
-    <tgroup cols="3">
-     <thead>
-      <row>
-       <entry>Functionality</entry>
-       <entry>built-in</entry>
-       <entry>OpenSSL</entry>
-      </row>
-     </thead>
-     <tbody>
-      <row>
-       <entry>MD5</entry>
-       <entry>yes</entry>
-       <entry>yes</entry>
-      </row>
-      <row>
-       <entry>SHA1</entry>
-       <entry>yes</entry>
-       <entry>yes</entry>
-      </row>
-      <row>
-       <entry>SHA224/256/384/512</entry>
-       <entry>yes</entry>
-       <entry>yes (3)</entry>
-      </row>
-      <row>
-       <entry>Any other digest algo</entry>
-       <entry>no</entry>
-       <entry>yes (1)</entry>
-      </row>
-      <row>
-       <entry>Blowfish</entry>
-       <entry>yes</entry>
-       <entry>yes</entry>
-      </row>
-      <row>
-       <entry>AES</entry>
-       <entry>yes</entry>
-       <entry>yes (2)</entry>
-      </row>
-      <row>
-       <entry>DES/3DES/CAST5</entry>
-       <entry>no</entry>
-       <entry>yes</entry>
-      </row>
-      <row>
-       <entry>Raw encryption</entry>
-       <entry>yes</entry>
-       <entry>yes</entry>
-      </row>
-      <row>
-       <entry>PGP Symetric encryption</entry>
-       <entry>yes</entry>
-       <entry>yes</entry>
-      </row>
-      <row>
-       <entry>PGP Public-Key encryption</entry>
-       <entry>yes</entry>
-       <entry>yes</entry>
-      </row>
-     </tbody>
-    </tgroup>
-   </table>
-
-   <orderedlist>
-    <listitem>
-     <para>
-      Any digest algorithm OpenSSL supports is automatically picked up.
-      This is not possible with ciphers, which need to be supported
-      explicitly.
-     </para>
-    </listitem>
-    <listitem>
-     <para>
-      AES is included in OpenSSL since version 0.9.7.  If pgcrypto is
-      compiled against older version, it will use built-in AES code,
-      so it has AES always available.
-     </para>
-    </listitem>
-    <listitem>
-     <para>
-      SHA2 algorithms were added to OpenSSL in version 0.9.8.  For
-      older versions, pgcrypto will use built-in code.
-     </para>
-    </listitem>
-   </orderedlist>
-  </sect3>
+  <title>General hashing functions</title>
 
   <sect3>
-   <title>NULL handling</title>
-   <para>
-    As standard in SQL, all functions return NULL, if any of the arguments
-    are NULL.  This may create security risks on careless usage.
-   </para>
-  </sect3>
+   <title><function>digest()</function></title>
 
-  <sect3>
-   <title>Security</title>
-   <para>
-    All the functions here run inside database server.  That means that all
-    the data and passwords move between pgcrypto and client application in
-    clear-text.  Thus you must:
-   </para>
+   <synopsis>
+    digest(data text, type text) returns bytea
+    digest(data bytea, type text) returns bytea
+   </synopsis>
 
-   <orderedlist>
-    <listitem>
-     <para>Connect locally or use SSL connections.</para>
-    </listitem>
-    <listitem>
-     <para>Trust both system and database administrator.</para>
-    </listitem>
-   </orderedlist>
    <para>
-    If you cannot, then better do crypto inside client application.
+    Computes a binary hash of the given <parameter>data</>.
+    <parameter>type</> is the algorithm to use.
+    Standard algorithms are <literal>md5</literal> and
+    <literal>sha1</literal>.  If <filename>pgcrypto</> was built with
+    OpenSSL, more algorithms are available, as detailed in
+    <xref linkend="pgcrypto-with-without-openssl">.
    </para>
-  </sect3>
- </sect2>
 
- <sect2>
-  <title>General hashing</title>
-  
-  <sect3>
-   <title><literal>digest(data, type)</literal></title>
-   <programlisting>
-    digest(data text, type text) RETURNS bytea
-    digest(data bytea, type text) RETURNS bytea
-   </programlisting>
-   <para>
-    Type is here the algorithm to use.  Standard algorithms are `md5` and
-    `sha1`, although there may be more supported, depending on build
-    options.
-   </para>
-   <para>
-    Returns binary hash.
-   </para>
    <para>
-    If you want hexadecimal string, use `encode()` on result.  Example:
+    If you want the digest as a hexadecimal string, use
+    <function>encode()</> on the result.  For example:
    </para>
    <programlisting>
-    CREATE OR REPLACE FUNCTION sha1(bytea) RETURNS text AS $$
+    CREATE OR REPLACE FUNCTION sha1(bytea) returns text AS $$
       SELECT encode(digest($1, 'sha1'), 'hex')
     $$ LANGUAGE SQL STRICT IMMUTABLE;
    </programlisting>
   </sect3>
 
   <sect3>
-   <title><literal>hmac(data, key, type)</literal></title>
-   <programlisting>
-    hmac(data text, key text, type text) RETURNS bytea
-    hmac(data bytea, key text, type text) RETURNS bytea
-   </programlisting>
+   <title><function>hmac()</function></title>
+
+   <synopsis>
+    hmac(data text, key text, type text) returns bytea
+    hmac(data bytea, key text, type text) returns bytea
+   </synopsis>
+
    <para>
-    Calculates Hashed MAC over data.  `type` is the same as in `digest()`.
-    If the key is larger than hash block size it will first hashed and the
-    hash will be used as key.
+    Calculates hashed MAC for <parameter>data</> with key <parameter>key</>.
+    <parameter>type</> is the same as in <function>digest()</>.
    </para>
+
    <para>
-    It is similar to digest() but the hash can be recalculated only knowing
-    the key.  This avoids the scenario of someone altering data and also
-    changing the hash.
+    This is similar to <function>digest()</> but the hash can only be
+    recalculated knowing the key.  This prevents the scenario of someone
+    altering data and also changing the hash to match.
    </para>
+
    <para>
-    Returns binary hash.
+    If the key is larger than the hash block size it will first be hashed and
+    the result will be used as key.
    </para>
   </sect3>
  </sect2>
 
  <sect2>
-  <title>Password hashing</title>
+  <title>Password hashing functions</title>
+
   <para>
-   The functions <literal>crypt()</literal> and <literal>gen_salt()</literal> are specifically designed
-   for hashing passwords.  <literal>crypt()</literal> does the hashing and `gen_salt()`
+   The functions <function>crypt()</> and <function>gen_salt()</>
+   are specifically designed for hashing passwords.
+   <function>crypt()</> does the hashing and <function>gen_salt()</>
    prepares algorithm parameters for it.
   </para>
+
   <para>
-   The algorithms in `crypt()` differ from usual hashing algorithms like
-   MD5 or SHA1 in following respects:
+   The algorithms in <function>crypt()</> differ from usual hashing algorithms
+   like MD5 or SHA1 in the following respects:
   </para>
+
   <orderedlist>
    <listitem>
     <para>
-     They are slow.  As the amount of data is so small, this is only
+     They are slow.  As the amount of data is so small, this is the only
      way to make brute-forcing passwords hard.
     </para>
    </listitem>
    <listitem>
     <para>
-     Include random 'salt' with result, so that users having same
-     password would have different crypted passwords.  This is also
-     additional defense against reversing the algorithm.
+     They use a random value, called the <firstterm>salt</>, so that users
+     having the same password will have different encrypted passwords.
+     This is also an additional defense against reversing the algorithm.
     </para>
    </listitem>
    <listitem>
     <para>
-     Include algorithm type in the result, so passwords hashed with
+     They include the algorithm type in the result, so passwords hashed with
      different algorithms can co-exist.
     </para>
    </listitem>
    <listitem>
     <para>
-     Some of them are adaptive - that means after computers get
+     Some of them are adaptive &mdash; that means when computers get
      faster, you can tune the algorithm to be slower, without
      introducing incompatibility with existing passwords.
     </para>
    </listitem>
   </orderedlist>
 
-  <para>
-   Supported algorithms:
-  </para>
-  <programlisting>
-`------`-------------`---------`----------`---------------------------
- Type   Max password  Adaptive  Salt bits  Description
-----------------------------------------------------------------------
-`bf`     72           yes         128      Blowfish-based, variant 2a
-`md5`    unlimited    no           48      md5-based crypt()
-`xdes`   8            yes          24      Extended DES
-`des`    8            no           12      Original UNIX crypt
----------------------------------------------------------------------- 
-  </programlisting>
+  <table>
+   <title>Supported algorithms for <function>crypt()</></title>
+   <tgroup cols="5">
+    <thead>
+     <row>
+      <entry>Algorithm</entry>
+      <entry>Max password length</entry>
+      <entry>Adaptive?</entry>
+      <entry>Salt bits</entry>
+      <entry>Description</entry>
+     </row>
+    </thead>
+    <tbody>
+     <row>
+      <entry><literal>bf</></entry>
+      <entry>72</entry>
+      <entry>yes</entry>
+      <entry>128</entry>
+      <entry>Blowfish-based, variant 2a</entry>
+     </row>
+     <row>
+      <entry><literal>md5</></entry>
+      <entry>unlimited</entry>
+      <entry>no</entry>
+      <entry>48</entry>
+      <entry>MD5-based crypt</entry>
+     </row>
+     <row>
+      <entry><literal>xdes</></entry>
+      <entry>8</entry>
+      <entry>yes</entry>
+      <entry>24</entry>
+      <entry>Extended DES</entry>
+     </row>
+     <row>
+      <entry><literal>des</></entry>
+      <entry>8</entry>
+      <entry>no</entry>
+      <entry>12</entry>
+      <entry>Original UNIX crypt</entry>
+     </row>
+    </tbody>
+   </tgroup>
+  </table>
 
   <sect3>
-   <title>crypt(password, salt)</title>
-   <programlisting>
-    crypt(password text, salt text) RETURNS text
-   </programlisting>
+   <title><function>crypt()</></title>
+
+   <synopsis>
+    crypt(password text, salt text) returns text
+   </synopsis>
+
    <para>
-    Calculates UN*X crypt(3) style hash of password.  When storing new
-    password, you need to use function `gen_salt()` to generate new salt.
-    When checking password you should use existing hash as salt.
+    Calculates a crypt(3)-style hash of <parameter>password</>.
+    When storing a new password, you need to use
+    <function>gen_salt()</> to generate a new <parameter>salt</> value.
+    To check a password, pass the stored hash value as <parameter>salt</>,
+    and test whether the result matches the stored value.
    </para>
    <para>
-    Example - setting new password:
+    Example of setting a new password:
    </para>
    <programlisting>
-    UPDATE .. SET pswhash = crypt('new password', gen_salt('md5'));
+    UPDATE ... SET pswhash = crypt('new password', gen_salt('md5'));
    </programlisting>
    <para>
-    Example - authentication:
+    Example of authentication:
    </para>
    <programlisting>
-    SELECT pswhash = crypt('entered password', pswhash) WHERE .. ;
+    SELECT pswhash = crypt('entered password', pswhash) FROM ... ;
    </programlisting>
    <para>
-    returns true or false whether the entered password is correct.
-    It also can return NULL if `pswhash` field is NULL.
+    This returns <literal>true</> if the entered password is correct.
    </para>
   </sect3>
 
   <sect3>
-   <title>gen_salt(type)</title>
-   <programlisting>
-    gen_salt(type text) RETURNS text
-   </programlisting>
+   <title><function>gen_salt()</></title>
+
+   <synopsis>
+    gen_salt(type text [, iter_count integer ]) returns text
+   </synopsis>
+
    <para>
-    Generates a new random salt for usage in `crypt()`.  For adaptible
-    algorithms, it uses the default iteration count.
+    Generates a new random salt string for use in <function>crypt()</>.
+    The salt string also tells <function>crypt()</> which algorithm to use.
    </para>
+
    <para>
-    Accepted types are: `des`, `xdes`, `md5` and `bf`.
+    The <parameter>type</> parameter specifies the hashing algorithm.
+    The accepted types are: <literal>des</literal>, <literal>xdes</literal>,
+    <literal>md5</literal> and <literal>bf</literal>.
    </para>
-  </sect3>
-  <sect3>
-   <title>gen_salt(type, rounds)</title>
-   <programlisting>
-    gen_salt(type text, rounds integer) RETURNS text
-   </programlisting>
+
    <para>
-    algorithms.  The higher the count, the more time it takes to hash
+    The <parameter>iter_count</> parameter lets the user specify the iteration
+    count, for algorithms that have one.
+    The higher the count, the more time it takes to hash
     the password and therefore the more time to break it.  Although with
-    too high count the time to calculate a hash may be several years
-    - which is somewhat impractical.
+    too high a count the time to calculate a hash may be several years
+    &mdash; which is somewhat impractical.  If the <parameter>iter_count</>
+    parameter is omitted, the default iteration count is used.
+    Allowed values for <parameter>iter_count</> depend on the algorithm:
    </para>
+
+   <table>
+    <title>Iteration counts for <function>crypt()</></title>
+    <tgroup cols="4">
+     <thead>
+      <row>
+       <entry>Algorithm</entry>
+       <entry>Default</entry>
+       <entry>Min</entry>
+       <entry>Max</entry>
+      </row>
+     </thead>
+     <tbody>
+      <row>
+       <entry><literal>xdes</></entry>
+       <entry>725</entry>
+       <entry>1</entry>
+       <entry>16777215</entry>
+      </row>
+      <row>
+       <entry><literal>bf</></entry>
+       <entry>6</entry>
+       <entry>4</entry>
+       <entry>31</entry>
+      </row>
+     </tbody>
+    </tgroup>
+   </table>
+
    <para>
-    Number is algorithm specific:
+    For <literal>xdes</literal> there is an additional limitation that the
+    iteration count must be an odd number.
    </para>
-   <programlisting>
-`-----'---------'-----'----------
- type   default   min   max
----------------------------------
- `xdes`     725     1   16777215
- `bf`         6     4         31
---------------------------------- 
-   </programlisting>
+
    <para>
-    In case of xdes there is a additional limitation that the count must be
-    a odd number.
+    To pick an appropriate iteration count, consider that
+    the original DES crypt was designed to have the speed of 4 hashes per
+    second on the hardware of that time.
+    Slower than 4 hashes per second would probably dampen usability.
+    Faster than 100 hashes per second is probably too fast.
    </para>
+
    <para>
-    Notes:
+    Here is a table that gives an overview of the relative slowness
+    of different hashing algorithms.
+    The table shows how much time it would take to try all
+    combinations of characters in an 8-character password, assuming
+    that the password contains either only lowercase letters, or
+    upper- and lower-case letters and numbers.
+    In the <literal>crypt-bf</literal> entries, the number after a slash is
+    the <parameter>iter_count</parameter> parameter of
+    <function>gen_salt</function>.
    </para>
-   <itemizedlist>
-    <listitem>
-     <para>
-     Original DES crypt was designed to have the speed of 4 hashes per
-     second on the hardware of that time.
-     </para>
-    </listitem>
-    <listitem>
-     <para>
-     Slower than 4 hashes per second would probably dampen usability.
-     </para>
-    </listitem>
-    <listitem>
-     <para>
-     Faster than 100 hashes per second is probably too fast.
-     </para>
-    </listitem>
-    <listitem>
-     <para>
-     See next section about possible values for `crypt-bf`.
-     </para>
-    </listitem>
-   </itemizedlist>
-  </sect3>
 
-  <sect3>
-   <title>Comparison of crypt and regular hashes</title>
+   <table>
+    <title>Hash algorithm speeds</title>
+    <tgroup cols="4">
+     <thead>
+      <row>
+       <entry>Algorithm</entry>
+       <entry>Hashes/sec</entry>
+       <entry>For <literal>[a-z]</></entry>
+       <entry>For <literal>[A-Za-z0-9]</></entry>
+      </row>
+     </thead>
+     <tbody>
+      <row>
+       <entry><literal>crypt-bf/8</></entry>
+       <entry>28</entry>
+       <entry>246 years</entry>
+       <entry>251322 years</entry>
+      </row>
+      <row>
+       <entry><literal>crypt-bf/7</></entry>
+       <entry>57</entry>
+       <entry>121 years</entry>
+       <entry>123457 years</entry>
+      </row>
+      <row>
+       <entry><literal>crypt-bf/6</></entry>
+       <entry>112</entry>
+       <entry>62 years</entry>
+       <entry>62831 years</entry>
+      </row>
+      <row>
+       <entry><literal>crypt-bf/5</></entry>
+       <entry>211</entry>
+       <entry>33 years</entry>
+       <entry>33351 years</entry>
+      </row>
+      <row>
+       <entry><literal>crypt-md5</></entry>
+       <entry>2681</entry>
+       <entry>2.6 years</entry>
+       <entry>2625 years</entry>
+      </row>
+      <row>
+       <entry><literal>crypt-des</></entry>
+       <entry>362837</entry>
+       <entry>7 days</entry>
+       <entry>19 years</entry>
+      </row>
+      <row>
+       <entry><literal>sha1</></entry>
+       <entry>590223</entry>
+       <entry>4 days</entry>
+       <entry>12 years</entry>
+      </row>
+      <row>
+       <entry><literal>md5</></entry>
+       <entry>2345086</entry>
+       <entry>1 day</entry>
+       <entry>3 years</entry>
+      </row>
+     </tbody>
+    </tgroup>
+   </table>
+
    <para>
-    Here is a table that should give overview of relative slowness
-    of different hashing algorithms.
+    Notes:
    </para>
+
    <itemizedlist>
     <listitem>
      <para>
-     The goal is to crack a 8-character password, which consists:
-     </para>
-     <orderedlist>
-      <listitem><para>Only of lowercase letters</para></listitem>
-      <listitem><para>Numbers, lower- and uppercase letters.</para></listitem>
-     </orderedlist>
-    </listitem>
-    <listitem>
-     <para>
-     The table below shows how much time it would take to try all
-     combinations of characters.
-     </para>
-    </listitem>
-    <listitem>
-     <para>
-     The <literal>crypt-bf</literal> is featured in several settings - the number
-     after slash is the <literal>rounds</literal> parameter of 
-     <literal>gen_salt()</literal>.
-     </para>
-    </listitem>
-   </itemizedlist>
-   <programlisting>
-`------------'----------'--------------'--------------------
-Algorithm     Hashes/sec  Chars: [a-z]   Chars: [A-Za-z0-9]
-------------------------------------------------------------
-crypt-bf/8            28     246 years         251322 years
-crypt-bf/7            57     121 years         123457 years
-crypt-bf/6           112      62 years          62831 years
-crypt-bf/5           211      33 years          33351 years
-crypt-md5           2681     2.6 years           2625 years
-crypt-des         362837        7 days             19 years
-sha1              590223        4 days             12 years
-md5              2345086         1 day              3 years
-------------------------------------------------------------
-   </programlisting>
-   <itemizedlist>
-    <listitem>
-     <para>
-     The machine used is 1.5GHz Pentium 4.
+     The machine used is a 1.5GHz Pentium 4.
      </para>
     </listitem>
     <listitem>
      <para>
-     crypt-des and crypt-md5 algorithm numbers are taken from
-     John the Ripper v1.6.38 `-test` output.
+      <literal>crypt-des</> and <literal>crypt-md5</> algorithm numbers are
+      taken from John the Ripper v1.6.38 <literal>-test</> output.
      </para>
     </listitem>
     <listitem>
      <para>
-     MD5 numbers are from mdcrack 1.2.
+      <literal>md5</> numbers are from mdcrack 1.2.
      </para>
     </listitem>
     <listitem>
      <para>
-     SHA1 numbers are from lcrack-20031130-beta.
+      <literal>sha1</> numbers are from lcrack-20031130-beta.
      </para>
     </listitem>
     <listitem>
      <para>
-     <literal>crypt-bf</literal> numbers are taken using simple program that loops
-     over 1000 8-character passwords.  That way I can show the speed with
-     different number of rounds.  For reference: <literal>john -test</literal>
-     shows 213 loops/sec for crypt-bf/5.  (The small difference in results is 
-     in accordance to the fact that the <literal>crypt-bf</literal> implementation in pgcrypto
-     is same one that is used in John the Ripper.)
+      <literal>crypt-bf</literal> numbers are taken using a simple program that
+      loops over 1000 8-character passwords.  That way I can show the speed
+      with different numbers of iterations.  For reference: <literal>john
+      -test</literal> shows 213 loops/sec for <literal>crypt-bf/5</>.
+      (The very small
+      difference in results is in accordance with the fact that the
+      <literal>crypt-bf</literal> implementation in <filename>pgcrypto</>
+      is the same one used in John the Ripper.)
      </para>
     </listitem>
    </itemizedlist>
 
    <para>
-    Note that "try all combinations" is not a realistic exercise.
+    Note that <quote>try all combinations</quote> is not a realistic exercise.
     Usually password cracking is done with the help of dictionaries, which
     contain both regular words and various mutations of them.  So, even
     somewhat word-like passwords could be cracked much faster than the above
-    numbers suggest, and a 6-character non-word like password may escape
+    numbers suggest, while a 6-character non-word-like password may escape
     cracking.  Or not.
    </para>
   </sect3>
  </sect2>
 
-
  <sect2>
-  <title>PGP encryption</title>
+  <title>PGP encryption functions</title>
+
   <para>
-   The functions here implement the encryption part of OpenPGP (RFC2440)
-   standard.   Supported are both symmetric-key and public-key encryption.
+   The functions here implement the encryption part of the OpenPGP (RFC2440)
+   standard.  Supported are both symmetric-key and public-key encryption.
   </para>
 
-  <sect3>
-   <title>Overview</title>
-   <para>
-    Encrypted PGP message consists of 2 packets:
-   </para>
-   <itemizedlist>
-    <listitem><para>Packet for session key - either symmetric- or public-key encrypted.</para></listitem>
-    <listitem><para>Packet for session-key encrypted data.</para></listitem>
-   </itemizedlist>
-   <para>
-    When encrypting with password:
-   </para>
-   <orderedlist>
-    <listitem>
-     <para>
-     Given password is hashed using String2Key (S2K) algorithm.  This
-     is rather similar to `crypt()` algorithm - purposefully slow
-     and with random salt - but it produces a full-length binary key.
-     </para>
-    </listitem>
-    <listitem>
-     <para>
-     If separate session key is requested, new random key will be
-     generated.  Otherwise S2K key will be used directly as session key.
-     </para>
-    </listitem>
-    <listitem>
-     <para>
-     If S2K key is to be used directly, then only S2K settings will be put
-     into session key packet.  Otherwise session key will be encrypted with
-     S2K key and put into session key packet.
-     </para>
-    </listitem>
-   </orderedlist>
-   <para>
-    When encrypting with public key:
-   </para>
-   <orderedlist>
-    <listitem><para>New random session key is generated.</para></listitem>
-    <listitem><para>It is encrypted using public key and put into session key packet.</para></listitem>
-   </orderedlist>
+  <para>
+   An encrypted PGP message consists of 2 parts, or <firstterm>packets</>:
+  </para>
+  <itemizedlist>
+   <listitem>
+    <para>
+     Packet containing a session key &mdash; either symmetric-key or public-key
+     encrypted.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     Packet containing data encrypted with the session key.
+    </para>
+   </listitem>
+  </itemizedlist>
 
-   <para>
-    Now common part, the session-key encrypted data packet:
-   </para>
-   <orderedlist>
-    <listitem> 
-     <para>
-     Optional data-manipulation: compression, conversion to UTF-8,
-     conversion of line-endings.
-     </para>
-    </listitem>
-    <listitem>
-     <para>
-     Data is prefixed with block of random bytes.  This is equal
-     to using random IV.
-     </para>
-    </listitem>
-    <listitem>
-     <para>
-     A SHA1 hash of random prefix and data is appended.
-     </para>
-    </listitem>
-    <listitem>
-     <para>
-     All this is encrypted with session key.
-     </para>
-    </listitem>
-   </orderedlist>
-  </sect3>
+  <para>
+   When encrypting with a symmetric key (i.e., a password):
+  </para>
+  <orderedlist>
+   <listitem>
+    <para>
+     The given password is hashed using a String2Key (S2K) algorithm.  This is
+     rather similar to <function>crypt()</> algorithms &mdash; purposefully
+     slow and with random salt &mdash; but it produces a full-length binary
+     key.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     If a separate session key is requested, a new random key will be
+     generated.  Otherwise the S2K key will be used directly as the session
+     key.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     If the S2K key is to be used directly, then only S2K settings will be put
+     into the session key packet.  Otherwise the session key will be encrypted
+     with the S2K key and put into the session key packet.
+    </para>
+   </listitem>
+  </orderedlist>
+
+  <para>
+   When encrypting with a public key:
+  </para>
+  <orderedlist>
+   <listitem>
+    <para>
+     A new random session key is generated.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     It is encrypted using the public key and put into the session key packet.
+    </para>
+   </listitem>
+  </orderedlist>
+
+  <para>
+   In either case the data to be encrypted is processed as follows:
+  </para>
+  <orderedlist>
+   <listitem>
+    <para>
+     Optional data-manipulation: compression, conversion to UTF-8,
+     and/or conversion of line-endings.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     The data is prefixed with a block of random bytes.  This is equivalent
+     to using a random IV.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     An SHA1 hash of the random prefix and data is appended.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     All this is encrypted with the session key and placed in the data packet.
+    </para>
+   </listitem>
+  </orderedlist>
 
   <sect3>
-   <title><literal>pgp_sym_encrypt(data, psw)</literal></title>
-   <programlisting>
-    pgp_sym_encrypt(data text, psw text [, options text] ) RETURNS bytea
-    pgp_sym_encrypt_bytea(data bytea, psw text [, options text] ) RETURNS bytea
-   </programlisting>
-   <para>
-    Return a symmetric-key encrypted PGP message.
-   </para>
+   <title><function>pgp_sym_encrypt()</function></title>
+
+   <synopsis>
+    pgp_sym_encrypt(data text, psw text [, options text ]) returns bytea
+    pgp_sym_encrypt_bytea(data bytea, psw text [, options text ]) returns bytea
+   </synopsis>
    <para>
-    Options are described in section 5.8.
+    Encrypt <parameter>data</> with a symmetric PGP key <parameter>psw</>.
+    The <parameter>options</> parameter can contain option settings,
+    as described below.
    </para>
   </sect3>
 
   <sect3>
-   <title><literal>pgp_sym_decrypt(msg, psw)</literal></title>
-   <programlisting>
-    pgp_sym_decrypt(msg bytea, psw text [, options text] ) RETURNS text
-    pgp_sym_decrypt_bytea(msg bytea, psw text [, options text] ) RETURNS bytea
-   </programlisting>
+   <title><function>pgp_sym_decrypt()</function></title>
+
+   <synopsis>
+    pgp_sym_decrypt(msg bytea, psw text [, options text ]) returns text
+    pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea
+   </synopsis>
    <para>
-    Decrypt a symmetric-key encrypted PGP message.
+    Decrypt a symmetric-key-encrypted PGP message.
    </para>
    <para>
-    Decrypting bytea data with `pgp_sym_decrypt` is disallowed.
+    Decrypting bytea data with <function>pgp_sym_decrypt</> is disallowed.
     This is to avoid outputting invalid character data.  Decrypting
-    originally textual data with `pgp_sym_decrypt_bytea` is fine.
+    originally textual data with <function>pgp_sym_decrypt_bytea</> is fine.
    </para>
    <para>
-    Options are described in section 5.8.
+    The <parameter>options</> parameter can contain option settings,
+    as described below.
    </para>
   </sect3>
 
   <sect3>
-   <title><literal>pgp_pub_encrypt(data, pub_key)</literal></title>
-   <programlisting>
-    pgp_pub_encrypt(data text, key bytea [, options text] ) RETURNS bytea
-    pgp_pub_encrypt_bytea(data bytea, key bytea [, options text] ) RETURNS bytea
-   </programlisting>
+   <title><function>pgp_pub_encrypt()</function></title>
+
+   <synopsis>
+    pgp_pub_encrypt(data text, key bytea [, options text ]) returns bytea
+    pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea
+   </synopsis>
    <para>
-    Encrypt data with a public key.  Giving this function a secret key will
-    produce a error.
+    Encrypt <parameter>data</> with a public PGP key <parameter>key</>.
+    Giving this function a secret key will produce a error.
    </para>
    <para>
-    Options are described in section 5.8.
+    The <parameter>options</> parameter can contain option settings,
+    as described below.
    </para>
   </sect3>
 
   <sect3>
-   <title><literal>pgp_pub_decrypt(msg, sec_key [, psw])</literal></title>
-   <programlisting>
-    pgp_pub_decrypt(msg bytea, key bytea [, psw text [, options text]] ) RETURNS text
-    pgp_pub_decrypt_bytea(msg bytea, key bytea [,psw text [, options text]] ) RETURNS bytea
-   </programlisting>
+   <title><function>pgp_pub_decrypt()</function></title>
+
+   <synopsis>
+    pgp_pub_decrypt(msg bytea, key bytea [, psw text [, options text ]]) returns text
+    pgp_pub_decrypt_bytea(msg bytea, key bytea [, psw text [, options text ]]) returns bytea
+   </synopsis>
    <para>
-    Decrypt a public-key encrypted message with secret key.  If the secret
-    key is password-protected, you must give the password in `psw`.  If
-    there is no password, but you want to specify option for function, you
-    need to give empty password.
+    Decrypt a public-key-encrypted message.  <parameter>key</> must be the
+    secret key corresponding to the public key that was used to encrypt.
+    If the secret key is password-protected, you must give the password in
+    <parameter>psw</>.  If there is no password, but you want to specify
+    options, you need to give an empty password.
    </para>
    <para>
-    Decrypting bytea data with `pgp_pub_decrypt` is disallowed.
+    Decrypting bytea data with <function>pgp_pub_decrypt</> is disallowed.
     This is to avoid outputting invalid character data.  Decrypting
-    originally textual data with `pgp_pub_decrypt_bytea` is fine.
+    originally textual data with <function>pgp_pub_decrypt_bytea</> is fine.
    </para>
    <para>
-    Options are described in section 5.8.
+    The <parameter>options</> parameter can contain option settings,
+    as described below.
    </para>
   </sect3>
 
   <sect3>
-   <title><literal>pgp_key_id(key / msg)</literal></title>
-   <programlisting>
-    pgp_key_id(key or msg bytea) RETURNS text
-   </programlisting>
+   <title><function>pgp_key_id()</function></title>
+
+   <synopsis>
+    pgp_key_id(bytea) returns text
+   </synopsis>
    <para>
-    It shows you either key ID if given PGP public or secret key.  Or it
-    gives the key ID that was used for encrypting the data, if given
-    encrypted message.
+    <function>pgp_key_id</> extracts the key ID of a PGP public or secret key.
+    Or it gives the key ID that was used for encrypting the data, if given
+    an encrypted message.
    </para>
    <para>
     It can return 2 special key IDs:
@@ -602,151 +577,163 @@ md5              2345086         1 day              3 years
    <itemizedlist>
     <listitem>
      <para>
-      SYMKEY:
+      <literal>SYMKEY</>
      </para>
      <para>
-      The data is encrypted with symmetric key.
+      The message is encrypted with a symmetric key.
      </para>
     </listitem>
     <listitem>
      <para>
-      ANYKEY:
+      <literal>ANYKEY</>
      </para>
      <para>
-      The data is public-key encrypted, but the key ID is cleared.
-      That means you need to try all your secret keys on it to see
-      which one decrypts it.  pgcrypto itself does not produce such
-      messages.
+      The message is public-key encrypted, but the key ID has been removed.
+      That means you will need to try all your secret keys on it to see
+      which one decrypts it.  <filename>pgcrypto</> itself does not produce
+      such messages.
      </para>
     </listitem>
    </itemizedlist>
    <para>
-    Note that different keys may have same ID.   This is rare but normal
-    event.  Client application should then try to decrypt with each one,
-    to see which fits - like handling ANYKEY.
+    Note that different keys may have the same ID.   This is rare but a normal
+    event. The client application should then try to decrypt with each one,
+    to see which fits &mdash; like handling <literal>ANYKEY</>.
    </para>
   </sect3>
 
   <sect3>
-   <title><literal>armor / dearmor</literal></title>
-   <programlisting>
-    armor(data bytea) RETURNS text
-    dearmor(data text) RETURNS bytea
-   </programlisting>
+   <title><function>armor()</function>, <function>dearmor()</function></title>
+
+   <synopsis>
+    armor(data bytea) returns text
+    dearmor(data text) returns bytea
+   </synopsis>
    <para>
-    Those wrap/unwrap data into PGP Ascii Armor which is basically Base64
-    with CRC and additional formatting.
+    These functions wrap/unwrap binary data into PGP Ascii Armor format,
+    which is basically Base64 with CRC and additional formatting.
    </para>
   </sect3>
 
   <sect3>
    <title>Options for PGP functions</title>
+
    <para>
-    Options are named to be similar to GnuPG.  Values should be given after
-    an equal sign; separate options from each other with commas.  Example:
+    Options are named to be similar to GnuPG.  An option's value should be
+    given after an equal sign; separate options from each other with commas.
+    For example:
    </para>
    <programlisting>
     pgp_sym_encrypt(data, psw, 'compress-algo=1, cipher-algo=aes256')
    </programlisting>
+
    <para>
-    All of the options except `convert-crlf` apply only to encrypt
-    functions.  Decrypt functions get the parameters from PGP data.
+    All of the options except <literal>convert-crlf</literal> apply only to
+    encrypt functions.  Decrypt functions get the parameters from the PGP
+    data.
    </para>
+
    <para>
-    Most interesting options are probably `compression-algo` and
-    <literal>unicode-mode</literal>.  The rest should have reasonable defaults.
+    The most interesting options are probably
+    <literal>compress-algo</literal> and <literal>unicode-mode</literal>.
+    The rest should have reasonable defaults.
    </para>
-  </sect3>
 
-  <sect3>
+  <sect4>
    <title>cipher-algo</title>
+
    <para>
-    What cipher algorithm to use.
+    Which cipher algorithm to use.
    </para>
    <programlisting>
-    Values: bf, aes128, aes192, aes256 (OpenSSL-only: `3des`, `cast5`)
+    Values: bf, aes128, aes192, aes256 (OpenSSL-only: <literal>3des</literal>, <literal>cast5</literal>)
     Default: aes128
-    Applies: pgp_sym_encrypt, pgp_pub_encrypt
+    Applies to: pgp_sym_encrypt, pgp_pub_encrypt
    </programlisting>
-  </sect3>
+  </sect4>
 
-  <sect3>
+  <sect4>
    <title>compress-algo</title>
+
    <para>
-    Which compression algorithm to use.  Needs building with zlib.
-   </para>
-   <para>
-    Values:
+    Which compression algorithm to use.  Only available if
+    <filename>pgcrypto</> was built with zlib.
    </para>
    <programlisting>
-    0 - no compression
-    1 - ZIP compression
-    2 - ZLIB compression [=ZIP plus meta-data and block-CRC's]
+    Values:
+      0 - no compression
+      1 - ZIP compression
+      2 - ZLIB compression (= ZIP plus meta-data and block CRCs)
     Default: 0
-    Applies: pgp_sym_encrypt, pgp_pub_encrypt
+    Applies to: pgp_sym_encrypt, pgp_pub_encrypt
    </programlisting>
-  </sect3>
+  </sect4>
 
-  <sect3>
+  <sect4>
    <title>compress-level</title>
+
    <para>
-    How much to compress.  Bigger level compresses smaller but is slower.
+    How much to compress.  Higher levels compress smaller but are slower.
     0 disables compression.
    </para>
    <programlisting>
     Values: 0, 1-9
     Default: 6
-    Applies: pgp_sym_encrypt, pgp_pub_encrypt
+    Applies to: pgp_sym_encrypt, pgp_pub_encrypt
    </programlisting>
-  </sect3>
+  </sect4>
 
-  <sect3>
+  <sect4>
    <title>convert-crlf</title>
+
    <para>
-    Whether to convert `\n` into `\r\n` when encrypting and `\r\n` to `\n`
-    when decrypting.  RFC2440 specifies that text data should be stored
-    using `\r\n` line-feeds.  Use this to get fully RFC-compliant
+    Whether to convert <literal>\n</literal> into <literal>\r\n</literal> when
+    encrypting and <literal>\r\n</literal> to <literal>\n</literal> when
+    decrypting.  RFC2440 specifies that text data should be stored using
+    <literal>\r\n</literal> line-feeds.  Use this to get fully RFC-compliant
     behavior.
    </para>
    <programlisting>
     Values: 0, 1
     Default: 0
-    Applies: pgp_sym_encrypt, pgp_pub_encrypt, pgp_sym_decrypt, pgp_pub_decrypt
+    Applies to: pgp_sym_encrypt, pgp_pub_encrypt, pgp_sym_decrypt, pgp_pub_decrypt
    </programlisting>
-  </sect3>
+  </sect4>
 
-  <sect3>
+  <sect4>
    <title>disable-mdc</title>
+
    <para>
-    Do not protect data with SHA-1.  Only good reason to use this
-    option is to achieve compatibility with ancient PGP products, as the
-    SHA-1 protected packet is from upcoming update to RFC2440.  (Currently
-    at version RFC2440bis-14.) Recent gnupg.org and pgp.com software
-    supports it fine.
+    Do not protect data with SHA-1.  The only good reason to use this
+    option is to achieve compatibility with ancient PGP products, predating
+    the addition of SHA-1 protected packets to RFC2440.
+    Recent gnupg.org and pgp.com software supports it fine.
    </para>
    <programlisting>
     Values: 0, 1
     Default: 0
-    Applies: pgp_sym_encrypt, pgp_pub_encrypt
+    Applies to: pgp_sym_encrypt, pgp_pub_encrypt
    </programlisting>
-  </sect3>
+  </sect4>
 
-  <sect3>
+  <sect4>
    <title>enable-session-key</title>
+
    <para>
-    Use separate session key.  Public-key encryption always uses separate
-    session key, this is for symmetric-key encryption, which by default
-    uses S2K directly.
+    Use separate session key.  Public-key encryption always uses separate
+    session key; this is for symmetric-key encryption, which by default
+    uses the S2K key directly.
    </para>
    <programlisting>
     Values: 0, 1
     Default: 0
-    Applies: pgp_sym_encrypt
+    Applies to: pgp_sym_encrypt
    </programlisting>
-  </sect3>
+  </sect4>
 
-  <sect3>
+  <sect4>
    <title>s2k-mode</title>
+
    <para>
     Which S2K algorithm to use.
    </para>
@@ -756,126 +743,134 @@ md5              2345086         1 day              3 years
       1 - With salt but with fixed iteration count.
       3 - Variable iteration count.
     Default: 3
-    Applies: pgp_sym_encrypt
+    Applies to: pgp_sym_encrypt
    </programlisting>
-  </sect3>
+  </sect4>
 
-  <sect3>
+  <sect4>
    <title>s2k-digest-algo</title>
+
    <para>
     Which digest algorithm to use in S2K calculation.
    </para>
    <programlisting>
     Values: md5, sha1
     Default: sha1
-    Applies: pgp_sym_encrypt
+    Applies to: pgp_sym_encrypt
    </programlisting>
-  </sect3>
+  </sect4>
 
-  <sect3>
+  <sect4>
    <title>s2k-cipher-algo</title>
+
    <para>
     Which cipher to use for encrypting separate session key.
    </para>
    <programlisting>
     Values: bf, aes, aes128, aes192, aes256
-    Default: use cipher-algo.
-    Applies: pgp_sym_encrypt
+    Default: use cipher-algo
+    Applies to: pgp_sym_encrypt
    </programlisting>
-  </sect3>
+  </sect4>
 
-  <sect3>
+  <sect4>
    <title>unicode-mode</title>
+
    <para>
     Whether to convert textual data from database internal encoding to
     UTF-8 and back.  If your database already is UTF-8, no conversion will
-    be done, only the data will be tagged as UTF-8.  Without this option
+    be done, but the message will be tagged as UTF-8.  Without this option
     it will not be.
    </para>
    <programlisting>
     Values: 0, 1
     Default: 0
-    Applies: pgp_sym_encrypt, pgp_pub_encrypt
+    Applies to: pgp_sym_encrypt, pgp_pub_encrypt
    </programlisting>
+  </sect4>
   </sect3>
- </sect2>
 
- <sect2>
-  <title>Generating keys with GnuPG</title>
+ <sect3>
+  <title>Generating PGP keys with GnuPG</title>
+
   <para>
-   Generate a new key:
+   To generate a new key:
   </para>
   <programlisting>
    gpg --gen-key
   </programlisting>
   <para>
-   The preferred key type is "DSA and Elgamal".
+   The preferred key type is <quote>DSA and Elgamal</>.
   </para>
   <para>
    For RSA encryption you must create either DSA or RSA sign-only key
-   as master and then add RSA encryption subkey with `gpg --edit-key`.
+   as master and then add an RSA encryption subkey with
+   <literal>gpg --edit-key</literal>.
   </para>
   <para>
-   List keys:
+   To list keys:
   </para>
   <programlisting>
    gpg --list-secret-keys
   </programlisting>
   <para>
-   Export ascii-armored public key:
+   To export a public key in ascii-armor format:
   </para>
   <programlisting>
    gpg -a --export KEYID > public.key
   </programlisting>
   <para>
-   Export ascii-armored secret key:
+   To export a secret key in ascii-armor format:
   </para>
   <programlisting>
    gpg -a --export-secret-keys KEYID > secret.key
   </programlisting>
-  <para> 
-   You need to use `dearmor()` on them before giving them to
-   pgp_pub_* functions.  Or if you can handle binary data, you can drop
-   "-a" from gpg.
+  <para>
+   You need to use <function>dearmor()</> on these keys before giving them to
+   the PGP functions.  Or if you can handle binary data, you can drop
+   <literal>-a</literal> from the command.
   </para>
   <para>
-   For more details see `man gpg`, 
-   <ulink url="http://www.gnupg.org/gph/en/manual.html"></ulink>[The GNU 
-   Privacy Handbook] and other docs on 
-   <ulink url="http://www.gnupg.org"></ulink> site.
+   For more details see <literal>man gpg</literal>,
+   <ulink url="http://www.gnupg.org/gph/en/manual.html">The GNU
+   Privacy Handbook</ulink> and other documentation on
+   <ulink url="http://www.gnupg.org"></ulink>.
   </para>
- </sect2>
+ </sect3>
 
- <sect2>
+ <sect3>
   <title>Limitations of PGP code</title>
+
   <itemizedlist>
    <listitem>
     <para>
     No support for signing.  That also means that it is not checked
-    whether the encryption subkey belongs to master key.
+    whether the encryption subkey belongs to the master key.
     </para>
    </listitem>
    <listitem>
     <para>
     No support for encryption key as master key.  As such practice
-    is generally discouraged, it should not be a problem.
+    is generally discouraged, this should not be a problem.
     </para>
    </listitem>
    <listitem>
     <para>
     No support for several subkeys.  This may seem like a problem, as this
     is common practice.  On the other hand, you should not use your regular
-    GPG/PGP keys with pgcrypto, but create new ones, as the usage scenario
-    is rather different.
+    GPG/PGP keys with <filename>pgcrypto</>, but create new ones,
+    as the usage scenario is rather different.
     </para>
    </listitem>
   </itemizedlist>
+  </sect3>
  </sect2>
 
  <sect2>
-  <title>Raw encryption</title>
+  <title>Raw encryption functions</title>
+
   <para>
-   Those functions only run a cipher over data, they don't have any advanced
+   These functions only run a cipher over data; they don't have any advanced
    features of PGP encryption.  Therefore they have some major problems:
   </para>
   <orderedlist>
@@ -906,117 +901,266 @@ md5              2345086         1 day              3 years
    So, with the introduction of PGP encryption, usage of raw
    encryption functions is discouraged.
   </para>
-  <programlisting>
-    encrypt(data bytea, key bytea, type text) RETURNS bytea
-    decrypt(data bytea, key bytea, type text) RETURNS bytea
 
-    encrypt_iv(data bytea, key bytea, iv bytea, type text) RETURNS bytea
-    decrypt_iv(data bytea, key bytea, iv bytea, type text) RETURNS bytea
-  </programlisting>
-  <para>
-   Encrypt/decrypt data with cipher, padding data if needed.
-  </para>
+  <synopsis>
+    encrypt(data bytea, key bytea, type text) returns bytea
+    decrypt(data bytea, key bytea, type text) returns bytea
+
+    encrypt_iv(data bytea, key bytea, iv bytea, type text) returns bytea
+    decrypt_iv(data bytea, key bytea, iv bytea, type text) returns bytea
+  </synopsis>
+
   <para>
-   <literal>type</literal> parameter description in pseudo-noteup:
+   Encrypt/decrypt data using the cipher method specified by
+   <parameter>type</parameter>.  The syntax of the
+   <parameter>type</parameter> string is:
   </para>
-  <programlisting>
-    algo ['-' mode] ['/pad:' padding]
-  </programlisting>
+
+  <synopsis>
+   <replaceable>algorithm</> <optional> <literal>-</> <replaceable>mode</> </optional> <optional> <literal>/pad:</> <replaceable>padding</> </optional>
+  </synopsis>
+
   <para>
-   Supported algorithms:
+   where <replaceable>algorithm</> is one of:
   </para>
   <itemizedlist>
-   <listitem><para><literal>bf</literal>- Blowfish</para></listitem>
-   <listitem><para><literal>aes</literal>- AES (Rijndael-128)</para></listitem>
+   <listitem><para><literal>bf</literal> &mdash; Blowfish</para></listitem>
+   <listitem><para><literal>aes</literal> &mdash; AES (Rijndael-128)</para></listitem>
   </itemizedlist>
   <para>
-   Modes:
+   and <replaceable>mode</> is one of:
   </para>
   <itemizedlist>
    <listitem>
     <para>
-    <literal>cbc</literal>- next block depends on previous. (default)
+    <literal>cbc</literal> &mdash; next block depends on previous (default)
     </para>
    </listitem>
    <listitem>
     <para>
-    <literal>ecb</literal>- each block is encrypted separately. (for testing 
-    only)
+    <literal>ecb</literal> &mdash; each block is encrypted separately (for
+    testing only)
     </para>
    </listitem>
   </itemizedlist>
   <para>
-   Padding:
+   and <replaceable>padding</> is one of:
   </para>
   <itemizedlist>
    <listitem>
     <para>
-    <literal>pkcs</literal>-data may be any length (default)
+    <literal>pkcs</literal> &mdash; data may be any length (default)
     </para>
    </listitem>
    <listitem>
     <para>
-    <literal>none</literal>- data must be multiple of cipher block size.
+    <literal>none</literal> &mdash; data must be multiple of cipher block size
     </para>
    </listitem>
   </itemizedlist>
   <para>
-   IV is initial value for mode, defaults to all zeroes.  It is ignored for
-   ECB.  It is clipped or padded with zeroes if not exactly block size.
-  </para>
-  <para>
-   So, example:
+   So, for example, these are equivalent:
   </para>
   <programlisting>
    encrypt(data, 'fooz', 'bf')
+   encrypt(data, 'fooz', 'bf-cbc/pad:pkcs')
   </programlisting>
   <para>
-   is equal to
+   In <function>encrypt_iv</> and <function>decrypt_iv</>, the
+   <parameter>iv</> parameter is the initial value for the CBC mode;
+   it is ignored for ECB.
+   It is clipped or padded with zeroes if not exactly block size.
+   It defaults to all zeroes in the functions without this parameter.
   </para>
-  <programlisting>
-   encrypt(data, 'fooz', 'bf-cbc/pad:pkcs')
-  </programlisting>
  </sect2>
 
  <sect2>
-  <title>Random bytes</title>
-  <programlisting>
-    gen_random_bytes(count integer)
-  </programlisting>
+  <title>Random-data functions</title>
+
+  <synopsis>
+   gen_random_bytes(count integer) returns bytea
+  </synopsis>
   <para>
-   Returns `count` cryptographically strong random bytes as bytea value.
-   There can be maximally 1024 bytes extracted at a time.  This is to avoid
+   Returns <parameter>count</> cryptographically strong random bytes.
+   At most 1024 bytes can be extracted at a time.  This is to avoid
    draining the randomness generator pool.
   </para>
  </sect2>
 
  <sect2>
-  <title>References/Links</title>
-  
+  <title>Notes</title>
+
+  <sect3>
+   <title>Configuration</title>
+
+   <para>
+    <filename>pgcrypto</> configures itself according to the findings of the
+    main PostgreSQL <literal>configure</literal> script.  The options that
+    affect it are <literal>--with-zlib</literal> and
+    <literal>--with-openssl</literal>.
+   </para>
+
+   <para>
+    When compiled with zlib, PGP encryption functions are able to
+    compress data before encrypting.
+   </para>
+
+   <para>
+    When compiled with OpenSSL, there will be more algorithms available.
+    Also public-key encryption functions will be faster as OpenSSL
+    has more optimized BIGNUM functions.
+   </para>
+
+   <table id="pgcrypto-with-without-openssl">
+    <title>Summary of functionality with and without OpenSSL</title>
+    <tgroup cols="3">
+     <thead>
+      <row>
+       <entry>Functionality</entry>
+       <entry>Built-in</entry>
+       <entry>With OpenSSL</entry>
+      </row>
+     </thead>
+     <tbody>
+      <row>
+       <entry>MD5</entry>
+       <entry>yes</entry>
+       <entry>yes</entry>
+      </row>
+      <row>
+       <entry>SHA1</entry>
+       <entry>yes</entry>
+       <entry>yes</entry>
+      </row>
+      <row>
+       <entry>SHA224/256/384/512</entry>
+       <entry>yes</entry>
+       <entry>yes (Note 1)</entry>
+      </row>
+      <row>
+       <entry>Other digest algorithms</entry>
+       <entry>no</entry>
+       <entry>yes (Note 2)</entry>
+      </row>
+      <row>
+       <entry>Blowfish</entry>
+       <entry>yes</entry>
+       <entry>yes</entry>
+      </row>
+      <row>
+       <entry>AES</entry>
+       <entry>yes</entry>
+       <entry>yes (Note 3)</entry>
+      </row>
+      <row>
+       <entry>DES/3DES/CAST5</entry>
+       <entry>no</entry>
+       <entry>yes</entry>
+      </row>
+      <row>
+       <entry>Raw encryption</entry>
+       <entry>yes</entry>
+       <entry>yes</entry>
+      </row>
+      <row>
+       <entry>PGP Symmetric encryption</entry>
+       <entry>yes</entry>
+       <entry>yes</entry>
+      </row>
+      <row>
+       <entry>PGP Public-Key encryption</entry>
+       <entry>yes</entry>
+       <entry>yes</entry>
+      </row>
+     </tbody>
+    </tgroup>
+   </table>
+
+   <para>
+    Notes:
+   </para>
+
+   <orderedlist>
+    <listitem>
+     <para>
+      SHA2 algorithms were added to OpenSSL in version 0.9.8.  For
+      older versions, <filename>pgcrypto</> will use built-in code.
+     </para>
+    </listitem>
+    <listitem>
+     <para>
+      Any digest algorithm OpenSSL supports is automatically picked up.
+      This is not possible with ciphers, which need to be supported
+      explicitly.
+     </para>
+    </listitem>
+    <listitem>
+     <para>
+      AES is included in OpenSSL since version 0.9.7.  For
+      older versions, <filename>pgcrypto</> will use built-in code.
+     </para>
+    </listitem>
+   </orderedlist>
+  </sect3>
+
+  <sect3>
+   <title>NULL handling</title>
+
+   <para>
+    As is standard in SQL, all functions return NULL, if any of the arguments
+    are NULL.  This may create security risks on careless usage.
+   </para>
+  </sect3>
+
+  <sect3>
+   <title>Security limitations</title>
+
+   <para>
+    All <filename>pgcrypto</> functions run inside the database server.
+    That means that all
+    the data and passwords move between <filename>pgcrypto</> and client
+    applications in clear text.  Thus you must:
+   </para>
+
+   <orderedlist>
+    <listitem>
+     <para>Connect locally or use SSL connections.</para>
+    </listitem>
+    <listitem>
+     <para>Trust both system and database administrator.</para>
+    </listitem>
+   </orderedlist>
+
+   <para>
+    If you cannot, then better do crypto inside client application.
+   </para>
+  </sect3>
+
   <sect3>
    <title>Useful reading</title>
+
    <itemizedlist>
     <listitem>
-     <para><ulink url="http://www.gnupg.org/gph/en/manual.html"></ulink>:</para>
-     <para>The GNU Privacy Handbook</para>
+     <para><ulink url="http://www.gnupg.org/gph/en/manual.html"></ulink></para>
+     <para>The GNU Privacy Handbook.</para>
     </listitem>
     <listitem>
-     <para><ulink url="http://www.openwall.com/crypt/"></ulink>:</para>
+     <para><ulink url="http://www.openwall.com/crypt/"></ulink></para>
      <para>Describes the crypt-blowfish algorithm.</para>
     </listitem>
     <listitem>
      <para>
-      <ulink url="http://www.stack.nl/~galactus/remailers/passphrase-faq.html"></ulink>:
+      <ulink url="http://www.stack.nl/~galactus/remailers/passphrase-faq.html"></ulink>
      </para>
-     <para>How to choose good password.</para>
+     <para>How to choose good password.</para>
     </listitem>
     <listitem>
-     <para><ulink url="http://world.std.com/~reinhold/diceware.html"></ulink>:</para>
+     <para><ulink url="http://world.std.com/~reinhold/diceware.html"></ulink></para>
      <para>Interesting idea for picking passwords.</para>
     </listitem>
     <listitem>
      <para>
-      <ulink url="http://www.interhack.net/people/cmcurtin/snake-oil-faq.html"></ulink>:
+      <ulink url="http://www.interhack.net/people/cmcurtin/snake-oil-faq.html"></ulink>
      </para>
      <para>Describes good and bad cryptography.</para>
     </listitem>
@@ -1025,47 +1169,48 @@ md5              2345086         1 day              3 years
 
   <sect3>
    <title>Technical references</title>
+
    <itemizedlist>
     <listitem>
-     <para><ulink url="http://www.ietf.org/rfc/rfc2440.txt"></ulink>:</para>
-     <para>OpenPGP message format</para>
+     <para><ulink url="http://www.ietf.org/rfc/rfc2440.txt"></ulink></para>
+     <para>OpenPGP message format.</para>
     </listitem>
     <listitem>
      <para>
-      <ulink url="http://www.imc.org/draft-ietf-openpgp-rfc2440bis"></ulink>:
+      <ulink url="http://www.imc.org/draft-ietf-openpgp-rfc2440bis"></ulink>
      </para>
      <para>New version of RFC2440.</para>
     </listitem>
     <listitem>
-     <para><ulink url="http://www.ietf.org/rfc/rfc1321.txt"></ulink>:</para>
-     <para>The MD5 Message-Digest Algorithm</para>
+     <para><ulink url="http://www.ietf.org/rfc/rfc1321.txt"></ulink></para>
+     <para>The MD5 Message-Digest Algorithm.</para>
     </listitem>
     <listitem>
-     <para><ulink url="http://www.ietf.org/rfc/rfc2104.txt"></ulink>:</para>
-     <para>HMAC: Keyed-Hashing for Message Authentication</para>
+     <para><ulink url="http://www.ietf.org/rfc/rfc2104.txt"></ulink></para>
+     <para>HMAC: Keyed-Hashing for Message Authentication.</para>
     </listitem>
     <listitem>
      <para>
-      <ulink url="http://www.usenix.org/events/usenix99/provos.html"></ulink>:
+      <ulink url="http://www.usenix.org/events/usenix99/provos.html"></ulink>
      </para>
      <para>Comparison of crypt-des, crypt-md5 and bcrypt algorithms.</para>
     </listitem>
     <listitem>
-     <para><ulink url="http://csrc.nist.gov/cryptval/des.htm"></ulink>:</para>
+     <para><ulink url="http://csrc.nist.gov/cryptval/des.htm"></ulink></para>
      <para>Standards for DES, 3DES and AES.</para>
     </listitem>
     <listitem>
      <para>
-      <ulink url="http://en.wikipedia.org/wiki/Fortuna_(PRNG)"></ulink>:
+      <ulink url="http://en.wikipedia.org/wiki/Fortuna_(PRNG)"></ulink>
      </para>
      <para>Description of Fortuna CSPRNG.</para>
     </listitem>
     <listitem>
-     <para><ulink url="http://jlcooke.ca/random/"></ulink>:</para>
+     <para><ulink url="http://jlcooke.ca/random/"></ulink></para>
      <para>Jean-Luc Cooke Fortuna-based /dev/random driver for Linux.</para>
     </listitem>
     <listitem>
-     <para><ulink url="http://www.cs.ut.ee/~helger/crypto/"></ulink>:</para>
+     <para><ulink url="http://www.cs.ut.ee/~helger/crypto/"></ulink></para>
      <para>Collection of cryptology pointers.</para>
     </listitem>
    </itemizedlist>
@@ -1073,72 +1218,70 @@ md5              2345086         1 day              3 years
  </sect2>
 
  <sect2>
-  <title>Credits</title>
+  <title>Author</title>
+
+  <para>
+   Marko Kreen <email>markokr@gmail.com</email>
+  </para>
+
   <para>
-   <literal>pgcrypto</literal> uses code from the following sources:
+   <filename>pgcrypto</filename> uses code from the following sources:
   </para>
+
   <table>
    <title>Credits</title>
    <tgroup cols="3">
     <thead>
      <row>
-      <entry><para>Algorithm</para></entry>
-      <entry><para>Author</para></entry>
-      <entry><para>Source origin</para></entry>
+      <entry>Algorithm</entry>
+      <entry>Author</entry>
+      <entry>Source origin</entry>
      </row>
     </thead>
     <tbody>
      <row>
-      <entry><para>DES crypt()</para></entry>
-      <entry><para>David Burren and others</para></entry>
-      <entry><para>FreeBSD libcrypt</para></entry>
+      <entry>DES crypt</entry>
+      <entry>David Burren and others</entry>
+      <entry>FreeBSD libcrypt</entry>
      </row>
      <row>
-      <entry><para>MD5 crypt()</para></entry> 
-      <entry><para>Poul-Henning Kamp</para></entry>        
-      <entry><para>FreeBSD libcrypt</para></entry>
+      <entry>MD5 crypt</entry>
+      <entry>Poul-Henning Kamp</entry>
+      <entry>FreeBSD libcrypt</entry>
      </row>
      <row>
-      <entry><para>Blowfish crypt()</para></entry>     
-      <entry><para>Solar Designer</para></entry>            
-      <entry><para>www.openwall.com</para></entry>
+      <entry>Blowfish crypt</entry>
+      <entry>Solar Designer</entry>
+      <entry>www.openwall.com</entry>
      </row>
      <row>
-      <entry><para>Blowfish cipher</para></entry>     
-      <entry><para>Simon Tatham</para></entry>
-      <entry><para>PuTTY</para></entry>
+      <entry>Blowfish cipher</entry>
+      <entry>Simon Tatham</entry>
+      <entry>PuTTY</entry>
      </row>
      <row>
-      <entry><para>Rijndael cipher</para></entry>     
-      <entry><para>Brian Gladman</para></entry>
-      <entry><para>OpenBSD sys/crypto</para></entry>
+      <entry>Rijndael cipher</entry>
+      <entry>Brian Gladman</entry>
+      <entry>OpenBSD sys/crypto</entry>
      </row>
      <row>
-      <entry><para>MD5 and SHA1</para></entry>        
-      <entry><para>WIDE Project</para></entry>
-      <entry><para>KAME kame/sys/crypto</para></entry>
+      <entry>MD5 and SHA1</entry>
+      <entry>WIDE Project</entry>
+      <entry>KAME kame/sys/crypto</entry>
      </row>
      <row>
-      <entry><para>SHA256/384/512 </para></entry>      
-      <entry><para>Aaron D. Gifford</para></entry>
-      <entry><para>OpenBSD sys/crypto</para></entry>
+      <entry>SHA256/384/512 </entry>
+      <entry>Aaron D. Gifford</entry>
+      <entry>OpenBSD sys/crypto</entry>
      </row>
      <row>
-      <entry><para>BIGNUM math</para></entry>          
-      <entry><para>Michael J. Fromberger</para></entry>
-      <entry><para>dartmouth.edu/~sting/sw/imath</para></entry>
+      <entry>BIGNUM math</entry>
+      <entry>Michael J. Fromberger</entry>
+      <entry>dartmouth.edu/~sting/sw/imath</entry>
      </row>
     </tbody>
    </tgroup>
   </table>
  </sect2>
 
- <sect2>
-  <title>Author</title>
-  <para>
-   Marko Kreen <email>markokr@gmail.com</email>
-  </para>
- </sect2>
 </sect1>
-
index ac4bca63ee3d2d4046576632ca24bd4fcd0662fa..935061055f7733242ac8e3f948558a9de64cbe1a 100644 (file)
+<!-- $PostgreSQL: pgsql/doc/src/sgml/pgstandby.sgml,v 2.4 2007/12/16 23:00:42 tgl Exp $ -->
+
 <sect1 id="pgstandby">
  <title>pg_standby</title>
+
  <indexterm zone="pgstandby">
   <primary>pg_standby</primary>
  </indexterm>
 
  <para>
-  <literal>pg_standby</literal> allows the creation of a Warm Standby server. 
-  Other configuration is required as well, all of which is described in the 
-  main server manual.
- </para>
- <para>
-  The program is designed to be a wait-for <literal>restore_command</literal>, 
-  required to turn a normal archive recovery into a Warm Standby. Within the 
-  <literal>restore_command</literal> of the <literal>recovery.conf</literal> 
-  you could configure <literal>pg_standby</literal> in the following way:
+  <application>pg_standby</> supports creation of a <quote>warm standby</>
+  database server.  It is designed to be a production-ready program, as well
+  as a customizable template should you require specific modifications.
  </para>
- <programlisting>
-restore_command = 'pg_standby archiveDir %f %p %r'
- </programlisting>
+
  <para>
-  which would be sufficient to define that files will be restored from 
-  archiveDir. 
+  <application>pg_standby</> is designed to be a waiting
+  <literal>restore_command</literal>, which is needed to turn a standard
+  archive recovery into a warm standby operation.  Other
+  configuration is required as well, all of which is described in the main
+  server manual (see <xref linkend="warm-standby">).
  </para>
 
  <para>
-  <literal>pg_standby</literal> features include:
+  <application>pg_standby</application> features include:
  </para>
  <itemizedlist>
   <listitem>
    <para>
-    It is written in C. So it is very portable
-    and easy to install.
+    Supports copy or link for restoring WAL files
    </para>
   </listitem>
   <listitem>
    <para>
-   Supports copy or link from a directory (only)
+    Written in C, so very portable and easy to install
    </para>
   </listitem>
   <listitem>
    <para>
-    Source easy to modify, with specifically designated
-    sections to modify for your own needs, allowing 
-    interfaces to be written for additional Backup Archive Restore
-    (BAR) systems
+    Easy-to-modify source code, with specifically designated
+    sections to modify for your own needs
    </para>
   </listitem>
   <listitem>
    <para>
-    Already tested on Linux and Windows 
+    Already tested on Linux and Windows
    </para>
   </listitem>
  </itemizedlist>
 
  <sect2>
   <title>Usage</title>
+
   <para>
-   <literal>pg_standby</literal> should be used within the 
-   <literal>restore_command</literal> of the <literal>recovery.conf</literal>
-   file. 
-  </para>
-  <para>
-   The basic usage should be like this:
+   To configure a standby
+   server to use <application>pg_standby</>, put this into its
+   <filename>recovery.conf</filename> configuration file:
   </para>
   <programlisting>
-   restore_command = 'pg_standby archiveDir %f %p'
+restore_command = 'pg_standby <replaceable>archiveDir</> %f %p %r'
   </programlisting>
   <para>
-   with the pg_standby command usage as
+   where <replaceable>archiveDir</> is the directory from which WAL segment
+   files should be restored.
   </para>
-  <programlisting>
-   pg_standby [OPTION]... ARCHIVELOCATION NEXTWALFILE XLOGFILEPATH [RESTARTWALFILE]
-  </programlisting>
   <para>
-   When used within the <literal>restore_command</literal> the %f and %p macros
-   will provide the actual file and path required for the restore/recovery.
+   The full syntax of <application>pg_standby</>'s command line is
+  </para>
+  <synopsis>
+pg_standby <optional> <replaceable>option</> ... </optional> <replaceable>archivelocation</> <replaceable>nextwalfile</> <replaceable>xlogfilepath</> <optional> <replaceable>restartwalfile</> </optional>
+  </synopsis>
+  <para>
+   When used within <literal>restore_command</literal>, the <literal>%f</> and
+   <literal>%p</> macros should be specified for <replaceable>nextwalfile</>
+   and <replaceable>xlogfilepath</> respectively, to provide the actual file
+   and path required for the restore.
   </para>
   <para>
-   <literal>pg_standby</literal> assumes that <literal>ARCHIVELOCATION</literal>
-   is a directory accessible by the server-owning user.
+   If <replaceable>restartwalfile</> is specified, normally by using the
+   <literal>%r</literal> macro, then all WAL files logically preceding this
+   file will be removed from <replaceable>archivelocation</>. This minimizes
+   the number of files that need to be retained, while preserving
+   crash-restart capability.  Use of this parameter is appropriate if the
+   <replaceable>archivelocation</> is a transient staging area for this
+   particular standby server, but <emphasis>not</> when the
+   <replaceable>archivelocation</> is intended as a long-term WAL archive area.
   </para>
   <para>
-   If <literal>RESTARTWALFILE</literal> is specified, typically by using the 
-   <literal>%r</literal> option, then all files prior to this file will be 
-   removed from <literal>ARCHIVELOCATION</literal>. This then minimises the 
-   number of files that need to be held, whilst at the same time maintaining 
-   restart capability. This capability additionally assumes that 
-   <literal>ARCHIVELOCATION</literal> directory is writable.
+   <application>pg_standby</application> assumes that
+   <replaceable>archivelocation</> is a directory readable by the
+   server-owning user.  If <replaceable>restartwalfile</> (or <literal>-k</>)
+   is specified,
+   the <replaceable>archivelocation</> directory must be writable too.
   </para>
 
   <table>
-   <title>Options</title>
-   <tgroup cols="2">
+   <title><application>pg_standby</> options</title>
+   <tgroup cols="3">
+     <thead>
+     <row>
+      <entry>Option</entry>
+      <entry>Default</entry>
+      <entry>Description</entry>
+     </row>
+    </thead>
     <tbody>
      <row>
-      <entry>-c</entry>
-      <entry> use copy/cp command to restore WAL files from archive</entry>
+      <entry><literal>-c</></entry>
+      <entry>yes</entry>
+      <entry>
+       Use <literal>cp</> or <literal>copy</> command to restore WAL files
+       from archive.
+      </entry>
      </row>
      <row>
-      <entry>-d</entry>
-      <entry>debug/logging option.</entry>
+      <entry><literal>-d</></entry>
+      <entry>no</entry>
+      <entry>Print lots of debug logging output on <filename>stderr</>.</entry>
      </row>
      <row>
-      <entry>-k numfiles</entry>
+      <entry><literal>-k</> <replaceable>numfiles</></entry>
+      <entry>0</entry>
       <entry>
-       <para>
-        Cleanup files in the archive so that we maintain no more than this 
-        many files in the archive. This parameter will be silently ignored if
-        <literal>RESTARTWALFILE</literal> is specified, since that
-        specification method is more accurate in determining the correct
-        cut-off point in archive.
-       </para>
-       <para>
-        You should be wary against setting this number too low,
-        since this may mean you cannot restart the standby. This
-        is because the last restartpoint marked in the WAL files
-        may be many files in the past and can vary considerably.
-        This should be set to a value exceeding the number of WAL
-        files that can be recovered in 2*checkpoint_timeout seconds,
-        according to the value in the warm standby postgresql.conf.
-        It is wholly unrelated to the setting of checkpoint_segments
-        on either primary or standby.
-       </para>
-       <para>
-        Setting <literal>numfiles</literal> to be zero will disable deletion
-        of files from <literal>ARCHIVELOCATION</literal>.
-       </para>
-       <para>
-        If in doubt, use a large value or do not set a value at all.
-       </para>
-       <para>
-        If you specify neither <literal>RESTARTWALFILE</> nor <literal>-k</>,
-        then <literal>-k 0</> will be assumed, i.e. keep all files in archive.
-       </para>
+       Remove files from <replaceable>archivelocation</replaceable> so that
+       no more than this many WAL files before the current one are kept in the
+       archive.  Zero (the default) means not to remove any files from
+       <replaceable>archivelocation</replaceable>.
+       This parameter will be silently ignored if
+       <replaceable>restartwalfile</replaceable> is specified, since that
+       specification method is more accurate in determining the correct
+       archive cut-off point.
+       Use of this parameter is <emphasis>deprecated</> as of
+       <productname>PostgreSQL</> 8.3; it is safer and more efficient to
+       specify a <replaceable>restartwalfile</replaceable> parameter.  A too
+       small setting could result in removal of files that are still needed
+       for a restart of the standby server, while a too large setting wastes
+       archive space.
       </entry>
      </row>
      <row>
-      <entry>-l</entry>
+      <entry><literal>-l</></entry>
+      <entry>no</entry>
       <entry>
-       <para>
-        use ln command to restore WAL files from archive
-        WAL files will remain in archive
-       </para>
-       <para>
-        Link is more efficient, but the default is copy to allow you to 
-        maintain the WAL archive for recovery purposes as well as 
-        high-availability. The default setting is not necessarily recommended,
-        consult the main database server manual for discussion.
-       </para>
-       <para>
-        This option uses the Windows Vista command mklink
-        to provide a file-to-file symbolic link. -l will
-        not work on versions of Windows prior to Vista.
-        Use the -c option instead.
-        see <ulink url="http://en.wikipedia.org/wiki/NTFS_symbolic_link"></ulink>
-       </para>
+       Use <literal>ln</> command to restore WAL files from archive.
+       Link is more efficient than copy, but the default is copy since link
+       will not work in all scenarios.
+       On Windows, this option uses the <literal>mklink</> command
+       to provide a file-to-file symbolic link. <literal>-l</> will
+       not work on versions of Windows prior to Vista.
       </entry>
      </row>
      <row>
-      <entry>-r maxretries</entry>
+      <entry><literal>-r</> <replaceable>maxretries</></entry>
+      <entry>3</entry>
       <entry>
-       <para>
-        the maximum number of times to retry the restore command if it
-        fails. After each failure, we wait for sleeptime * num_retries
-        so that the wait time increases progressively, so by default
-        we will wait 5 secs, 10 secs then 15 secs before reporting
-        the failure back to the database server. This will be
-        interpreted as and end of recovery and the Standby will come
-        up fully as a result. <literal>Default=3 Min=0</literal>
-       </para>
+        Set the maximum number of times to retry the copy or link command if it
+        fails. After each failure, we wait for <replaceable>sleeptime</> *
+        <replaceable>num_retries</>
+        so that the wait time increases progressively.  So by default,
+        we will wait 5 secs, 10 secs, then 15 secs before reporting
+        the failure back to the standby server. This will be
+        interpreted as end of recovery and the standby will come
+        up fully as a result.
       </entry>
      </row>
      <row>
-      <entry>-s sleeptime</entry>
+      <entry><literal>-s</> <replaceable>sleeptime</></entry>
+      <entry>5</entry>
       <entry>
-       the number of seconds to sleep between testing to see
-       if the file to be restored is available in the archive yet.
-       The default setting is not necessarily recommended,
-       consult the main database server manual for discussion.
-       <literal>Default=5, Min=1, Max=60</literal>
+       Set the number of seconds (up to 60) to sleep between tests to see
+       if the WAL file to be restored is available in the archive yet.
+       The default setting is not necessarily recommended;
+       consult <xref linkend="warm-standby"> for discussion.
       </entry>
      </row>
      <row>
-      <entry>-t triggerfile</entry>
+      <entry><literal>-t</> <replaceable>triggerfile</></entry>
+      <entry>none</entry>
       <entry>
-       the presence of the triggerfile will cause recovery to end
-       whether or not the next file is available
-       It is recommended that you use a structured filename to 
+       Specify a trigger file whose presence should cause recovery to end
+       whether or not the next WAL file is available.
+       It is recommended that you use a structured filename to
        avoid confusion as to which server is being triggered
-       when multiple servers exist on same system.
-       e.g. /tmp/pgsql.trigger.5432
+       when multiple servers exist on the same system; for example
+       <filename>/tmp/pgsql.trigger.5432</>.
       </entry>
      </row>
      <row>
-      <entry>-w maxwaittime</entry>
+      <entry><literal>-w</> <replaceable>maxwaittime</></entry>
+      <entry>0</entry>
       <entry>
-       the maximum number of seconds to wait for the next file,
-       after which recovery will end and the Standby will come up.
-       The default setting is not necessarily recommended,
-       consult the main database server manual for discussion. A setting of
-       zero means wait forever.
-       <literal>Default=0, Min=0</literal>
+       Set the maximum number of seconds to wait for the next WAL file,
+       after which recovery will end and the standby will come up.
+       A setting of zero (the default) means wait forever.
+       The default setting is not necessarily recommended;
+       consult <xref linkend="warm-standby"> for discussion.
       </entry>
      </row>
     </tbody>
@@ -209,89 +201,129 @@ restore_command = 'pg_standby archiveDir %f %p %r'
   </table>
   <note>
    <para>
-    <literal>--help</literal> is not supported since 
-    <literal>pg_standby</literal> is not intended for interactive use, except 
-    during development and testing.
+    <literal>--help</literal> is not supported since
+    <application>pg_standby</application> is not intended for interactive use,
+    except during development and testing.
    </para>
   </note>
  </sect2>
 
  <sect2>
-  <title>Supported versions</title>
-  <para>
-   <literal>pg_standby</literal> is designed to work with PostgreSQL 8.2 and
-   and later. It is currently compatible across minor changes between the way
-   8.3 and 8.2 operate.
-  </para>
-  <para>
-   PostgreSQL 8.3 provides the <literal>%r</literal> command line substitution,
-   designed to let <literal>pg_standby</literal> know the last file it needs to
-   keep. If the last parameter is omitted, no error is generated, allowing 
-   <literal>pg_standby</literal> to function correctly with PostgreSQL 8.2 
-   also. With PostgreSQL 8.2, the <literal>-k</literal> option must be used if 
-   archive cleanup is required. This option remains available in 8.3.
-  </para>
- </sect2>
+  <title>Examples</title>
 
- <sect2>
-  <title>Additional design notes</title>
+  <para>On Linux or Unix systems, you might use:</para>
+
+  <programlisting>
+archive_command = 'cp %p .../archive/%f'
+
+restore_command = 'pg_standby -l -d -s 2 -t /tmp/pgsql.trigger.5442 .../archive %f %p %r 2>>standby.log'
+  </programlisting>
   <para>
-   The use of a move command seems like it would be a good idea, but this would
-   prevent recovery from being restartable. Also, the last WAL file is always 
-   requested twice from the archive.
+   where the archive directory is physically located on the standby server,
+   so that the <literal>archive_command</> is accessing it across NFS,
+   but the files are local to the standby (enabling use of <literal>ln</>).
+   This will:
   </para>
- </sect2>
+  <itemizedlist>
+   <listitem>
+    <para>
+     use the <literal>ln</> command to restore WAL files from archive
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     produce debugging output in <filename>standby.log</>
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     sleep for 2 seconds between checks for next WAL file availability
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     stop waiting only when a trigger file called
+     <filename>/tmp/pgsql.trigger.5442</> appears
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     remove no-longer-needed files from the archive directory
+    </para>
+   </listitem>
+  </itemizedlist>
 
- <sect2>
-  <title>Examples</title>
+  <para>On Windows, you might use:</para>
+
+  <programlisting>
+archive_command = 'copy %p ...\\archive\\%f'
 
+restore_command = 'pg_standby -d -s 5 -t C:\pgsql.trigger.5442 ...\archive %f %p %r 2>>standby.log'
+  </programlisting>
+  <para>
+   Note that backslashes need to be doubled in the
+   <literal>archive_command</>, but <emphasis>not</emphasis> in the
+   <literal>restore_command</>.  This will:
+  </para>
   <itemizedlist>
    <listitem>
-    <para>Example on Linux</para>
-    <programlisting>
-archive_command = 'cp %p ../archive/%f'
-
-restore_command = 'pg_standby -l -d -k 255 -r 2 -s 2 -w 0 -t /tmp/pgsql.trigger.5442 $PWD/../archive %f %p 2>> standby.log' 
-    </programlisting>
     <para>
-     which will
+     use the <literal>copy</> command to restore WAL files from archive
     </para>
-    <itemizedlist>
-     <listitem><para>use a ln command to restore WAL files from archive</para></listitem>
-     <listitem><para>produce logfile output in standby.log</para></listitem>
-     <listitem><para>keep the last 255 full WAL files, plus the current one</para></listitem>
-     <listitem><para>sleep for 2 seconds between checks for next WAL file is full</para></listitem>
-     <listitem><para>never timeout if file not found</para></listitem>
-     <listitem><para>stop waiting when a trigger file called /tmp/pgsql.trigger.5442 appears</para></listitem>
-    </itemizedlist>
    </listitem>
-
    <listitem>
     <para>
-     Example on Windows
+     produce debugging output in <filename>standby.log</>
     </para>
-    <programlisting>
-archive_command = 'copy %p ..\\archive\\%f'
-    </programlisting>
+   </listitem>
+   <listitem>
     <para>
-     Note that backslashes need to be doubled in the archive_command, but
-     *not* in the restore_command, in 8.2, 8.1, 8.0 on Windows.
+     sleep for 5 seconds between checks for next WAL file availability
     </para>
-    <programlisting>
-restore_command = 'pg_standby -c -d -s 5 -w 0 -t C:\pgsql.trigger.5442 ..\archive %f %p 2>> standby.log'
-    </programlisting>
+   </listitem>
+   <listitem>
     <para>
-     which will
+     stop waiting only when a trigger file called
+     <filename>C:\pgsql.trigger.5442</> appears
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     remove no-longer-needed files from the archive directory
     </para>
-   <itemizedlist>
-     <listitem><para>use a copy command to restore WAL files from archive</para></listitem>
-     <listitem><para>produce logfile output in standby.log</para></listitem>
-     <listitem><para>sleep for 5 seconds between checks for next WAL file is full</para></listitem>
-     <listitem><para>never timeout if file not found</para></listitem>
-     <listitem><para>stop waiting when a trigger file called C:\pgsql.trigger.5442 appears</para></listitem>
-    </itemizedlist>
    </listitem>
   </itemizedlist>
+
+  <para>
+   Since the Windows example uses <literal>copy</> at both ends, either
+   or both servers might be accessing the archive directory across the
+   network.
+  </para>
+
  </sect2>
+
+ <sect2>
+  <title>Supported server versions</title>
+
+  <para>
+   <application>pg_standby</application> is designed to work with
+   <productname>PostgreSQL</> 8.2 and later.
+  </para>
+  <para>
+   <productname>PostgreSQL</> 8.3 provides the <literal>%r</literal> macro,
+   which is designed to let <application>pg_standby</application> know the
+   last file it needs to keep.  With <productname>PostgreSQL</> 8.2, the
+   <literal>-k</literal> option must be used if archive cleanup is
+   required.  This option remains available in 8.3, but its use is deprecated.
+  </para>
+ </sect2>
+
+ <sect2>
+  <title>Author</title>
+
+  <para>
+   Simon Riggs
+  </para>
+ </sect2>
+
 </sect1>