Experiment with alternative longdesc format. longdesc
authorRichard W.M. Jones <rjones@redhat.com>
Tue, 2 Jun 2009 22:37:56 +0000 (23:37 +0100)
committerRichard W.M. Jones <rjones@redhat.com>
Wed, 3 Jun 2009 14:49:42 +0000 (15:49 +0100)
fish/fish.c
src/generator.ml

index 96c1a81..488e8aa 100644 (file)
@@ -256,6 +256,7 @@ main (int argc, char *argv[])
   exit (0);
 }
 
+#if 0
 void
 pod2text (const char *heading, const char *str)
 {
@@ -275,6 +276,7 @@ pod2text (const char *heading, const char *str)
   fputs (str, fp);
   pclose (fp);
 }
+#endif
 
 /* List is built in reverse order, so mount them in reverse order. */
 static void
index bb3744e..c7d208f 100755 (executable)
@@ -250,13 +250,34 @@ and test_init =
 and seq = cmd list
 and cmd = string list
 
-(* Note about long descriptions: When referring to another
- * action, use the format C<guestfs_other> (ie. the full name of
- * the C function).  This will be replaced as appropriate in other
- * language bindings.
- *
- * Apart from that, long descriptions are just perldoc paragraphs.
+(* The short description is always a single, short line of plain text.
+ * Long descriptions use this limited "language" which is converted
+ * into the required formats on output (eg. perldoc, javadoc, etc.)
+ * At the top level, long descriptions are a list of paragraphs.
  *)
+type longdesc = para list
+and para =
+  | P of snippet list                  (* full paragraph *)
+  | Q of string                                (* same as P[T str] *)
+  | ItemList of (snippet list * para) list (* list of items *)
+  | BulletList of para list            (* bullet point list *)
+  | Note of snippet list               (* full note paragraph *)
+  | QNote of string                    (* same as Note[T str] *)
+  | Pre of string list                 (* preformatted lines *)
+  | SeeAlso of string list             (* see also other commands *)
+and snippet =
+  | T of string                                (* text *)
+  | C of string                                (* code *)
+  | A of string                                (* named parameter *)
+  | X of string                                (* cross-reference to other command *)
+  | XA of string * snippet list         (* call command with args *)
+  | XU of string                       (* cross-reference to unimplemented *)
+  | XW of string                       (* cross-reference to wildcard *)
+  | Em of string                       (* emphasized text *)
+  | Man of string * int                        (* manpage (name, section) *)
+  | URL of string                      (* URL *)
+  | NULL                               (* "NULL", "undef" etc. *)
+  | NONNULL                            (* "non-NULL", "defined", etc. *)
 
 (* These test functions are used in the language binding tests. *)
 
@@ -291,39 +312,40 @@ let test_functions = [
   ("test0", (RErr, test_all_args), -1, [NotInFish; NotInDocs],
    [],
    "internal test function - do not use",
-   "\
-This is an internal test function which is used to test whether
+   [
+Q"This is an internal test function which is used to test whether
 the automatically generated bindings can handle every possible
-parameter type correctly.
+parameter type correctly.";
 
-It echos the contents of each parameter to stdout.
+Q"It echos the contents of each parameter to stdout.";
 
-You probably don't want to call this function.");
+Q"You probably don't want to call this function."]);
 ] @ List.flatten (
   List.map (
     fun (name, ret) ->
       [(name, (ret, [String "val"]), -1, [NotInFish; NotInDocs],
        [],
        "internal test function - do not use",
-       "\
-This is an internal test function which is used to test whether
+       [
+Q"This is an internal test function which is used to test whether
 the automatically generated bindings can handle every possible
-return type correctly.
+return type correctly.";
+
+P[T"It converts string ";A"val";T" to the return type."];
 
-It converts string C<val> to the return type.
+Q"You probably don't want to call this function."]);
 
-You probably don't want to call this function.");
        (name ^ "err", (ret, []), -1, [NotInFish; NotInDocs],
        [],
        "internal test function - do not use",
-       "\
-This is an internal test function which is used to test whether
+       [
+Q"This is an internal test function which is used to test whether
 the automatically generated bindings can handle every possible
-return type correctly.
+return type correctly.";
 
-This function always returns an error.
+Q"This function always returns an error.";
 
-You probably don't want to call this function.")]
+Q"You probably don't want to call this function."])]
   ) test_all_rets
 )
 
@@ -336,268 +358,273 @@ let non_daemon_functions = test_functions @ [
   ("launch", (RErr, []), -1, [FishAlias "run"; FishAction "launch"],
    [],
    "launch the qemu subprocess",
-   "\
-Internally libguestfs is implemented by running a virtual machine
-using L<qemu(1)>.
+   [
+P[T"Internally libguestfs is implemented by running a virtual machine
+using ";Man("qemu",1);T"."];
 
-You should call this after configuring the handle
-(eg. adding drives) but before performing any actions.");
+Q"You should call this after configuring the handle
+(eg. adding drives) but before performing any actions."]);
 
   ("wait_ready", (RErr, []), -1, [NotInFish],
    [],
    "wait until the qemu subprocess launches",
-   "\
-Internally libguestfs is implemented by running a virtual machine
-using L<qemu(1)>.
+   [
+P[T"Internally libguestfs is implemented by running a virtual machine
+using ";Man("qemu",1);T"."];
 
-You should call this after C<guestfs_launch> to wait for the launch
-to complete.");
+P[T"You should call this after ";X"launch"; T" to wait for the launch
+to complete."]]);
 
   ("kill_subprocess", (RErr, []), -1, [],
    [],
    "kill the qemu subprocess",
-   "\
-This kills the qemu subprocess.  You should never need to call this.");
+   [
+Q"This kills the qemu subprocess.  You should never need to call this."]);
 
   ("add_drive", (RErr, [String "filename"]), -1, [FishAlias "add"],
    [],
    "add an image to examine or modify",
-   "\
-This function adds a virtual machine disk image C<filename> to the
+   [
+P[T"This function adds a virtual machine disk image ";A"filename";T" to the
 guest.  The first time you call this function, the disk appears as IDE
-disk 0 (C</dev/sda>) in the guest, the second time as C</dev/sdb>, and
-so on.
+disk 0 (";C"/dev/sda";T") in the guest, the second time as ";C"/dev/sdb";T", and
+so on."];
 
-You don't necessarily need to be root when using libguestfs.  However
+Q"You don't necessarily need to be root when using libguestfs.  However
 you obviously do need sufficient permissions to access the filename
 for whatever operations you want to perform (ie. read access if you
 just want to read the image or write access if you want to modify the
-image).
+image).";
 
-This is equivalent to the qemu parameter C<-drive file=filename>.
+P[T"This is equivalent to the qemu parameter ";C"-drive file=filename";T"."];
 
-Note that this call checks for the existence of C<filename>.  This
+Note[T"Note that this call checks for the existence of ";A"filename";T".  This
 stops you from specifying other types of drive which are supported
-by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
-the general C<guestfs_config> call instead.");
+by qemu such as ";C"nbd:";T" and ";C"http:";T" URLs.  To specify those, use
+the general ";X"config";T" call instead."]]);
 
   ("add_cdrom", (RErr, [String "filename"]), -1, [FishAlias "cdrom"],
    [],
    "add a CD-ROM disk image to examine",
-   "\
-This function adds a virtual CD-ROM disk image to the guest.
+   [
+Q"This function adds a virtual CD-ROM disk image to the guest.";
 
-This is equivalent to the qemu parameter C<-cdrom filename>.
+P[T"This is equivalent to the qemu parameter ";C"-cdrom filename";T"."];
 
-Note that this call checks for the existence of C<filename>.  This
+Note[T"Note that this call checks for the existence of ";A"filename";T".  This
 stops you from specifying other types of drive which are supported
-by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
-the general C<guestfs_config> call instead.");
+by qemu such as ";C"nbd:";T" and ";C"http:";T" URLs.  To specify those, use
+the general ";X"config";T" call instead."]]);
 
   ("add_drive_ro", (RErr, [String "filename"]), -1, [FishAlias "add-ro"],
    [],
    "add a drive in snapshot mode (read-only)",
-   "\
-This adds a drive in snapshot mode, making it effectively
-read-only.
+   [
+Q"This adds a drive in snapshot mode, making it effectively
+read-only.";
 
-Note that writes to the device are allowed, and will be seen for
+Q"Note that writes to the device are allowed, and will be seen for
 the duration of the guestfs handle, but they are written
 to a temporary file which is discarded as soon as the guestfs
 handle is closed.  We don't currently have any method to enable
-changes to be committed, although qemu can support this.
+changes to be committed, although qemu can support this.";
 
-This is equivalent to the qemu parameter
-C<-drive file=filename,snapshot=on>.
+P[T"This is equivalent to the qemu parameter ";
+C"-drive file=filename,snapshot=on";T"."];
 
-Note that this call checks for the existence of C<filename>.  This
+Note[T"This call checks for the existence of ";A"filename";T".  This
 stops you from specifying other types of drive which are supported
-by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
-the general C<guestfs_config> call instead.");
+by qemu such as ";C"nbd:";T" and ";C"http:";T" URLs.  To specify those, use
+the general ";X"config";T" call instead."]]);
 
   ("config", (RErr, [String "qemuparam"; OptString "qemuvalue"]), -1, [],
    [],
    "add qemu parameters",
-   "\
-This can be used to add arbitrary qemu command line parameters
-of the form C<-param value>.  Actually it's not quite arbitrary - we
+   [
+P[T"This can be used to add arbitrary qemu command line parameters
+of the form ";C"-qemuparam qemuvalue";T".
+Actually it's not quite arbitrary - we
 prevent you from setting some parameters which would interfere with
-parameters that we use.
+parameters that we use."];
 
-The first character of C<param> string must be a C<-> (dash).
+P[T"The first character of ";A"qemuparam";
+T" string must be a ";C"-";T" (dash)."];
 
-C<value> can be NULL.");
+P[A"qemuvalue";T" can be ";NULL;T"."]]);
 
   ("set_qemu", (RErr, [String "qemu"]), -1, [FishAlias "qemu"],
    [],
    "set the qemu binary",
-   "\
-Set the qemu binary that we will use.
+   [
+Q"Set the qemu binary that we will use.";
 
-The default is chosen when the library was compiled by the
-configure script.
+Q"The default is chosen when the library was compiled by the
+configure script.";
 
-You can also override this by setting the C<LIBGUESTFS_QEMU>
-environment variable.
+P[T"You can also override this by setting the ";C"LIBGUESTFS_QEMU";
+T" environment variable."];
 
-Setting C<qemu> to C<NULL> restores the default qemu binary.");
+P[T"Setting ";A"qemu";T" to ";NULL;T" restores the default qemu binary."]]);
 
   ("get_qemu", (RConstString "qemu", []), -1, [],
    [],
    "get the qemu binary",
-   "\
-Return the current qemu binary.
+   [
+Q"Return the current qemu binary.";
 
-This is always non-NULL.  If it wasn't set already, then this will
-return the default qemu binary name.");
+P[T"This is always ";NONNULL;T".  If it wasn't set already, then this will
+return the default qemu binary name."]]);
 
   ("set_path", (RErr, [String "path"]), -1, [FishAlias "path"],
    [],
    "set the search path",
-   "\
-Set the path that libguestfs searches for kernel and initrd.img.
+   [
+Q"Set the path that libguestfs searches for kernel and initrd.img.";
 
-The default is C<$libdir/guestfs> unless overridden by setting
-C<LIBGUESTFS_PATH> environment variable.
+P[T"The default is ";C"$libdir/guestfs";T" unless overridden by setting ";
+C"LIBGUESTFS_PATH";T" environment variable."];
 
-Setting C<path> to C<NULL> restores the default path.");
+P[T"Setting ";A"path";T" to ";NULL;T" restores the default path."]]);
 
   ("get_path", (RConstString "path", []), -1, [],
    [],
    "get the search path",
-   "\
-Return the current search path.
+   [
+Q"Return the current search path.";
 
-This is always non-NULL.  If it wasn't set already, then this will
-return the default path.");
+P[T"This is always ";NONNULL;T".  If it wasn't set already, then this will
+return the default path."]]);
 
   ("set_append", (RErr, [String "append"]), -1, [FishAlias "append"],
    [],
    "add options to kernel command line",
-   "\
-This function is used to add additional options to the
-guest kernel command line.
+   [
+Q"This function is used to add additional options to the
+guest kernel command line.";
 
-The default is C<NULL> unless overridden by setting
-C<LIBGUESTFS_APPEND> environment variable.
+P[T"The default is ";NULL;T" unless overridden by setting ";
+C"LIBGUESTFS_APPEND";T" environment variable."];
 
-Setting C<append> to C<NULL> means I<no> additional options
-are passed (libguestfs always adds a few of its own).");
+P[T"Setting ";A"append";T" to ";NULL;T" means ";Em"no";
+T" additional options are passed
+(libguestfs always adds a few of its own)."]]);
 
   ("get_append", (RConstString "append", []), -1, [],
    [],
    "get the additional kernel options",
-   "\
-Return the additional kernel options which are added to the
-guest kernel command line.
+   [
+Q"Return the additional kernel options which are added to the
+guest kernel command line.";
 
-If C<NULL> then no options are added.");
+P[T"If ";NULL;T" then no options are added."]]);
 
   ("set_autosync", (RErr, [Bool "autosync"]), -1, [FishAlias "autosync"],
    [],
    "set autosync mode",
-   "\
-If C<autosync> is true, this enables autosync.  Libguestfs will make a
-best effort attempt to run C<guestfs_umount_all> followed by
-C<guestfs_sync> when the handle is closed
-(also if the program exits without closing handles).
+   [
+P[T"If ";A"autosync";T" is true, this enables autosync.  Libguestfs will make a
+best effort attempt to run ";X"umount_all";T" followed by ";
+X"sync";T" when the handle is closed
+(also if the program exits without closing handles)."];
 
-This is disabled by default (except in guestfish where it is
-enabled by default).");
+Q"This is disabled by default (except in guestfish where it is
+enabled by default)."]);
 
   ("get_autosync", (RBool "autosync", []), -1, [],
    [],
    "get autosync mode",
-   "\
-Get the autosync flag.");
+   [
+Q"Get the autosync flag."]);
 
   ("set_verbose", (RErr, [Bool "verbose"]), -1, [FishAlias "verbose"],
    [],
    "set verbose mode",
-   "\
-If C<verbose> is true, this turns on verbose messages (to C<stderr>).
+   [
+P[T"If ";A"verbose";T" is true, this turns on verbose messages
+(to ";C"stderr";T")."];
 
-Verbose messages are disabled unless the environment variable
-C<LIBGUESTFS_DEBUG> is defined and set to C<1>.");
+P[T"Verbose messages are disabled unless the environment variable ";
+C"LIBGUESTFS_DEBUG";T" is defined and set to ";C"1";T"."]]);
 
   ("get_verbose", (RBool "verbose", []), -1, [],
    [],
    "get verbose mode",
-   "\
-This returns the verbose messages flag.");
+   [
+Q"This returns the verbose messages flag."]);
 
   ("is_ready", (RBool "ready", []), -1, [],
    [],
    "is ready to accept commands",
-   "\
-This returns true iff this handle is ready to accept commands
-(in the C<READY> state).
+   [
+P[T"This returns true iff this handle is ready to accept commands
+(in the ";C"READY";T" state)."];
 
-For more information on states, see L<guestfs(3)>.");
+P[T"For more information on states, see ";Man("guestfs",3);T"."]]);
 
   ("is_config", (RBool "config", []), -1, [],
    [],
    "is in configuration state",
-   "\
-This returns true iff this handle is being configured
-(in the C<CONFIG> state).
+   [
+P[T"This returns true iff this handle is being configured
+(in the ";C"CONFIG";T" state)."];
 
-For more information on states, see L<guestfs(3)>.");
+P[T"For more information on states, see ";Man("guestfs",3);T"."]]);
 
   ("is_launching", (RBool "launching", []), -1, [],
    [],
    "is launching subprocess",
-   "\
-This returns true iff this handle is launching the subprocess
-(in the C<LAUNCHING> state).
+   [
+P[T"This returns true iff this handle is launching the subprocess
+(in the ";C"LAUNCHING";T" state)."];
 
-For more information on states, see L<guestfs(3)>.");
+P[T"For more information on states, see ";Man("guestfs",3);T"."]]);
 
   ("is_busy", (RBool "busy", []), -1, [],
    [],
    "is busy processing a command",
-   "\
-This returns true iff this handle is busy processing a command
-(in the C<BUSY> state).
+   [
+P[T"This returns true iff this handle is busy processing a command
+(in the ";C"BUSY";T" state)."];
 
-For more information on states, see L<guestfs(3)>.");
+P[T"For more information on states, see ";Man("guestfs",3);T"."]]);
 
   ("get_state", (RInt "state", []), -1, [],
    [],
    "get the current state",
-   "\
-This returns the current state as an opaque integer.  This is
-only useful for printing debug and internal error messages.
+   [
+Q"This returns the current state as an opaque integer.  This is
+only useful for printing debug and internal error messages.";
 
-For more information on states, see L<guestfs(3)>.");
+P[T"For more information on states, see ";Man("guestfs",3);T"."]]);
 
   ("set_busy", (RErr, []), -1, [NotInFish],
    [],
    "set state to busy",
-   "\
-This sets the state to C<BUSY>.  This is only used when implementing
-actions using the low-level API.
+   [
+P[T"This sets the state to ";C"BUSY";T".  This is only used when implementing
+actions using the low-level API."];
 
-For more information on states, see L<guestfs(3)>.");
+P[T"For more information on states, see ";Man("guestfs",3);T"."]]);
 
   ("set_ready", (RErr, []), -1, [NotInFish],
    [],
    "set state to ready",
-   "\
-This sets the state to C<READY>.  This is only used when implementing
-actions using the low-level API.
+   [
+P[T"This sets the state to ";C"READY";T".  This is only used when implementing
+actions using the low-level API."];
 
-For more information on states, see L<guestfs(3)>.");
+P[T"For more information on states, see ";Man("guestfs",3);T"."]]);
 
   ("end_busy", (RErr, []), -1, [NotInFish],
    [],
    "leave the busy state",
-   "\
-This sets the state to C<READY>, or if in C<CONFIG> then it leaves the
+   [
+P[T"This sets the state to ";C"READY";T", or if in ";C"CONFIG";
+T" then it leaves the
 state as is.  This is only used when implementing
-actions using the low-level API.
+actions using the low-level API."];
 
-For more information on states, see L<guestfs(3)>.");
+P[T"For more information on states, see ";Man("guestfs",3);T"."]]);
 
 ]
 
@@ -614,68 +641,68 @@ let daemon_functions = [
        ["write_file"; "/new"; "new file contents"; "0"];
        ["cat"; "/new"]], "new file contents")],
    "mount a guest disk at a position in the filesystem",
-   "\
-Mount a guest disk at a position in the filesystem.  Block devices
-are named C</dev/sda>, C</dev/sdb> and so on, as they were added to
+   [
+P[T"Mount a guest disk at a position in the filesystem.  Block devices
+are named ";C"/dev/sda";T", ";C"/dev/sdb";T" and so on, as they were added to
 the guest.  If those block devices contain partitions, they will have
-the usual names (eg. C</dev/sda1>).  Also LVM C</dev/VG/LV>-style
-names can be used.
+the usual names (eg. ";C"/dev/sda1";T").  Also LVM ";C"/dev/VG/LV";T"-style
+names can be used."];
 
-The rules are the same as for L<mount(2)>:  A filesystem must
-first be mounted on C</> before others can be mounted.  Other
+P[T"The rules are the same as for ";Man("mount",8);T":  A filesystem must
+first be mounted on ";C"/";T" before others can be mounted.  Other
 filesystems can only be mounted on directories which already
-exist.
+exist."];
 
-The mounted filesystem is writable, if we have sufficient permissions
-on the underlying device.
+Q"The mounted filesystem is writable, if we have sufficient permissions
+on the underlying device.";
 
-The filesystem options C<sync> and C<noatime> are set with this
-call, in order to improve reliability.");
+P[T"The filesystem options ";C"sync";T" and ";C"noatime";T" are set with this
+call, in order to improve reliability."]]);
 
   ("sync", (RErr, []), 2, [],
    [ InitEmpty, Always, TestRun [["sync"]]],
    "sync disks, writes are flushed through to the disk image",
-   "\
-This syncs the disk, so that any writes are flushed through to the
-underlying disk image.
+   [
+Q"This syncs the disk, so that any writes are flushed through to the
+underlying disk image.";
 
-You should always call this if you have modified a disk image, before
-closing the handle.");
+Q"You should always call this if you have modified a disk image, before
+closing the handle."]);
 
   ("touch", (RErr, [String "path"]), 3, [],
    [InitBasicFS, Always, TestOutputTrue (
       [["touch"; "/new"];
        ["exists"; "/new"]])],
    "update file timestamps or create a new file",
-   "\
-Touch acts like the L<touch(1)> command.  It can be used to
+   [
+P[T"Touch acts like the ";Man("touch",1);T" command.  It can be used to
 update the timestamps on a file, or, if the file does not exist,
-to create a new zero-length file.");
+to create a new zero-length file."]]);
 
   ("cat", (RString "content", [String "path"]), 4, [ProtocolLimitWarning],
    [InitBasicFS, Always, TestOutput (
       [["write_file"; "/new"; "new file contents"; "0"];
        ["cat"; "/new"]], "new file contents")],
    "list the contents of a file",
-   "\
-Return the contents of the file named C<path>.
+   [
+P[T"Return the contents of the file named ";A"path";T"."];
 
-Note that this function cannot correctly handle binary files
-(specifically, files containing C<\\0> character which is treated
-as end of string).  For those you need to use the C<guestfs_download>
-function which has a more complex interface.");
+P[T"Note that this function cannot correctly handle binary files
+(specifically, files containing ";C"\\0";T" character which is treated
+as end of string).  For those you need to use the ";X"download";
+T" function which has a more complex interface."]]);
 
   ("ll", (RString "listing", [String "directory"]), 5, [],
    [], (* XXX Tricky to test because it depends on the exact format
        * of the 'ls -l' command, which changes between F10 and F11.
        *)
    "list the files in a directory (long format)",
-   "\
-List the files in C<directory> (relative to the root directory,
-there is no cwd) in the format of 'ls -la'.
+   [
+P[T"List the files in ";A"directory";T" (relative to the root directory,
+there is no cwd) in the format of ";C"ls -la";T"."];
 
-This command is mostly useful for interactive sessions.  It
-is I<not> intended that you try to parse the output string.");
+P[T"This command is mostly useful for interactive sessions.  It
+is ";Em"not";T" intended that you try to parse the output string."]]);
 
   ("ls", (RStringList "listing", [String "directory"]), 6, [],
    [InitBasicFS, Always, TestOutputList (
@@ -684,22 +711,19 @@ is I<not> intended that you try to parse the output string.");
        ["touch"; "/newest"];
        ["ls"; "/"]], ["lost+found"; "new"; "newer"; "newest"])],
    "list the files in a directory",
-   "\
-List the files in C<directory> (relative to the root directory,
-there is no cwd).  The '.' and '..' entries are not returned, but
-hidden files are shown.
-
-This command is mostly useful for interactive sessions.  Programs
-should probably use C<guestfs_readdir> instead.");
+   [
+P[T"List the files in ";A"directory";T" (relative to the root directory,
+there is no cwd).  The ";C".";T" and ";C"..";T" entries are not returned, but
+hidden files are shown."]]);
 
   ("list_devices", (RStringList "devices", []), 7, [],
    [InitEmpty, Always, TestOutputList (
       [["list_devices"]], ["/dev/sda"; "/dev/sdb"; "/dev/sdc"; "/dev/sdd"])],
    "list the block devices",
-   "\
-List all the block devices.
+   [
+Q"List all the block devices.";
 
-The full block device names are returned, eg. C</dev/sda>");
+P[T"The full block device names are returned, eg. ";C"/dev/sda";T"."]]);
 
   ("list_partitions", (RStringList "partitions", []), 8, [],
    [InitBasicFS, Always, TestOutputList (
@@ -708,13 +732,13 @@ The full block device names are returned, eg. C</dev/sda>");
       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
        ["list_partitions"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
    "list the partitions",
-   "\
-List all the partitions detected on all block devices.
+   [
+Q"List all the partitions detected on all block devices.";
 
-The full partition device names are returned, eg. C</dev/sda1>
+P[T"The full partition device names are returned, eg. ";C"/dev/sda1"];
 
-This does not return logical volumes.  For that you will need to
-call C<guestfs_lvs>.");
+P[T"This does not return logical volumes.  For that you will need to
+call ";X"lvs";T"."]]);
 
   ("pvs", (RStringList "physvols", []), 9, [],
    [InitBasicFSonLVM, Always, TestOutputList (
@@ -726,14 +750,14 @@ call C<guestfs_lvs>.");
        ["pvcreate"; "/dev/sda3"];
        ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
    "list the LVM physical volumes (PVs)",
-   "\
-List all the physical volumes detected.  This is the equivalent
-of the L<pvs(8)> command.
+   [
+P[T"List all the physical volumes detected.  This is the equivalent
+of the ";Man("pvs",8);T" command."];
 
-This returns a list of just the device names that contain
-PVs (eg. C</dev/sda2>).
+P[T"This returns a list of just the device names that contain
+PVs (eg. ";C"/dev/sda2";T")."];
 
-See also C<guestfs_pvs_full>.");
+SeeAlso["pvs_full"]]);
 
   ("vgs", (RStringList "volgroups", []), 10, [],
    [InitBasicFSonLVM, Always, TestOutputList (
@@ -747,14 +771,14 @@ See also C<guestfs_pvs_full>.");
        ["vgcreate"; "VG2"; "/dev/sda3"];
        ["vgs"]], ["VG1"; "VG2"])],
    "list the LVM volume groups (VGs)",
-   "\
-List all the volumes groups detected.  This is the equivalent
-of the L<vgs(8)> command.
+   [
+P[T"List all the volumes groups detected.  This is the equivalent
+of the ";Man("vgs",8);T" command."];
 
-This returns a list of just the volume group names that were
-detected (eg. C<VolGroup00>).
+P[T"This returns a list of just the volume group names that were
+detected (eg. ";C"VolGroup00";T")."];
 
-See also C<guestfs_vgs_full>.");
+SeeAlso["vgs_full"]]);
 
   ("lvs", (RStringList "logvols", []), 11, [],
    [InitBasicFSonLVM, Always, TestOutputList (
@@ -771,35 +795,38 @@ See also C<guestfs_vgs_full>.");
        ["lvcreate"; "LV3"; "VG2"; "50"];
        ["lvs"]], ["/dev/VG1/LV1"; "/dev/VG1/LV2"; "/dev/VG2/LV3"])],
    "list the LVM logical volumes (LVs)",
-   "\
-List all the logical volumes detected.  This is the equivalent
-of the L<lvs(8)> command.
+   [
+P[T"List all the logical volumes detected.  This is the equivalent
+of the ";Man("lvs",8);T" command."];
 
-This returns a list of the logical volume device names
-(eg. C</dev/VolGroup00/LogVol00>).
+P[T"This returns a list of the logical volume device names
+(eg. ";C"/dev/VolGroup00/LogVol00";T")."];
 
-See also C<guestfs_lvs_full>.");
+SeeAlso["lvs_full"]]);
 
   ("pvs_full", (RPVList "physvols", []), 12, [],
    [], (* XXX how to test? *)
    "list the LVM physical volumes (PVs)",
-   "\
-List all the physical volumes detected.  This is the equivalent
-of the L<pvs(8)> command.  The \"full\" version includes all fields.");
+   [
+P[T"List all the physical volumes detected.  This is the equivalent
+of the ";Man("pvs",8);T" command.
+The \"full\" version includes all fields."]]);
 
   ("vgs_full", (RVGList "volgroups", []), 13, [],
    [], (* XXX how to test? *)
    "list the LVM volume groups (VGs)",
-   "\
-List all the volumes groups detected.  This is the equivalent
-of the L<vgs(8)> command.  The \"full\" version includes all fields.");
+   [
+P[T"List all the volumes groups detected.  This is the equivalent
+of the ";Man("vgs",8);T" command.
+The \"full\" version includes all fields."]]);
 
   ("lvs_full", (RLVList "logvols", []), 14, [],
    [], (* XXX how to test? *)
    "list the LVM logical volumes (LVs)",
-   "\
-List all the logical volumes detected.  This is the equivalent
-of the L<lvs(8)> command.  The \"full\" version includes all fields.");
+   [
+P[T"List all the logical volumes detected.  This is the equivalent
+of the ";Man("lvs",8);T" command.
+The \"full\" version includes all fields."]]);
 
   ("read_lines", (RStringList "lines", [String "path"]), 15, [],
    [InitBasicFS, Always, TestOutputList (
@@ -809,175 +836,175 @@ of the L<lvs(8)> command.  The \"full\" version includes all fields.");
       [["write_file"; "/new"; ""; "0"];
        ["read_lines"; "/new"]], [])],
    "read file as lines",
-   "\
-Return the contents of the file named C<path>.
+   [
+P[T"Return the contents of the file named ";A"path";T"."];
 
-The file contents are returned as a list of lines.  Trailing
-C<LF> and C<CRLF> character sequences are I<not> returned.
+P[T"The file contents are returned as a list of lines.  Trailing ";
+C"LF";T" and ";C"CRLF";T" character sequences are ";Em"not";T" returned."];
 
-Note that this function cannot correctly handle binary files
-(specifically, files containing C<\\0> character which is treated
-as end of line).  For those you need to use the C<guestfs_read_file>
-function which has a more complex interface.");
+P[T"Note that this function cannot correctly handle binary files
+(specifically, files containing ";C"\\0";T" character which is treated
+as end of line).  For those you need to use the ";XU"read_file";
+T" function which has a more complex interface."]]);
 
   ("aug_init", (RErr, [String "root"; Int "flags"]), 16, [],
    [], (* XXX Augeas code needs tests. *)
    "create a new Augeas handle",
-   "\
-Create a new Augeas handle for editing configuration files.
+   [
+Q"Create a new Augeas handle for editing configuration files.
 If there was any previous Augeas handle associated with this
-guestfs session, then it is closed.
+guestfs session, then it is closed.";
 
-You must call this before using any other C<guestfs_aug_*>
-commands.
+P[T"You must call this before using any other ";XW"aug_*";
+T" commands."];
 
-C<root> is the filesystem root.  C<root> must not be NULL,
-use C</> instead.
+P[A"root";T" is the filesystem root.  ";A"root";T" must be ";NONNULL;T",
+use ";C"/";T" instead."];
 
-The flags are the same as the flags defined in
-E<lt>augeas.hE<gt>, the logical I<or> of the following
-integers:
+P[T"The flags are the same as the flags defined in
+<augeas.h>, the logical OR of the following
+integers:"];
 
-=over 4
+ItemList [
 
-=item C<AUG_SAVE_BACKUP> = 1
+[C"AUG_SAVE_BACKUP";T" = 1"],
 
-Keep the original file with a C<.augsave> extension.
+  P[T"Keep the original file with a ";C".augsave";T" extension."];
 
-=item C<AUG_SAVE_NEWFILE> = 2
+[C"AUG_SAVE_NEWFILE";T" = 2"],
 
-Save changes into a file with extension C<.augnew>, and
-do not overwrite original.  Overrides C<AUG_SAVE_BACKUP>.
+  P[T"Save changes into a file with extension ";C".augnew";T", and
+do not overwrite original.  Overrides ";C"AUG_SAVE_BACKUP";T"."];
 
-=item C<AUG_TYPE_CHECK> = 4
+[C"AUG_TYPE_CHECK";T" = 4"],
 
-Typecheck lenses (can be expensive).
+  Q"Typecheck lenses (can be expensive).";
 
-=item C<AUG_NO_STDINC> = 8
+[C"AUG_NO_STDINC";T" = 8"],
 
-Do not use standard load path for modules.
+  Q"Do not use standard load path for modules.";
 
-=item C<AUG_SAVE_NOOP> = 16
+[C"AUG_SAVE_NOOP";T" = 16"],
 
-Make save a no-op, just record what would have been changed.
+  Q"Make save a no-op, just record what would have been changed.";
 
-=item C<AUG_NO_LOAD> = 32
+[C"AUG_NO_LOAD";T" = 32"],
 
-Do not load the tree in C<guestfs_aug_init>.
+  P[T"Do not load the tree in ";X"aug_init";T"."];
 
-=back
+];
 
-To close the handle, you can call C<guestfs_aug_close>.
+P[T"To close the handle, you can call ";X"aug_close";T"."];
 
-To find out more about Augeas, see L<http://augeas.net/>.");
+P[T"To find out more about Augeas, see ";URL"http://augeas.net/";T"."]]);
 
   ("aug_close", (RErr, []), 26, [],
    [], (* XXX Augeas code needs tests. *)
    "close the current Augeas handle",
-   "\
-Close the current Augeas handle and free up any resources
-used by it.  After calling this, you have to call
-C<guestfs_aug_init> again before you can use any other
-Augeas functions.");
+   [
+P[T"Close the current Augeas handle and free up any resources
+used by it.  After calling this, you have to call ";
+X"aug_init";T" again before you can use any other
+Augeas functions."]]);
 
   ("aug_defvar", (RInt "nrnodes", [String "name"; OptString "expr"]), 17, [],
    [], (* XXX Augeas code needs tests. *)
    "define an Augeas variable",
-   "\
-Defines an Augeas variable C<name> whose value is the result
-of evaluating C<expr>.  If C<expr> is NULL, then C<name> is
-undefined.
+   [
+P[T"Defines an Augeas variable ";A"name";T" whose value is the result
+of evaluating ";A"expr";T".  If ";A"expr";T" is ";NULL;T", then ";A"name";T" is
+undefined."];
 
-On success this returns the number of nodes in C<expr>, or
-C<0> if C<expr> evaluates to something which is not a nodeset.");
+P[T"On success this returns the number of nodes in ";A"expr";T", or ";
+C"0";T" if ";A"expr";T" evaluates to something which is not a nodeset."]]);
 
   ("aug_defnode", (RIntBool ("nrnodes", "created"), [String "name"; String "expr"; String "val"]), 18, [],
    [], (* XXX Augeas code needs tests. *)
    "define an Augeas node",
-   "\
-Defines a variable C<name> whose value is the result of
-evaluating C<expr>.
+   [
+P[T"Defines a variable ";A"name";T" whose value is the result of
+evaluating ";A"expr";T"."];
 
-If C<expr> evaluates to an empty nodeset, a node is created,
-equivalent to calling C<guestfs_aug_set> C<expr>, C<value>.
-C<name> will be the nodeset containing that single node.
+P[T"If ";A"expr";T" evaluates to an empty nodeset, a node is created,
+equivalent to calling ";XA("aug_set",[A"expr";A"value"]);T".  ";
+A"name";T" will be the nodeset containing that single node."];
 
-On success this returns a pair containing the
+Q"On success this returns a pair containing the
 number of nodes in the nodeset, and a boolean flag
-if a node was created.");
+if a node was created."]);
 
   ("aug_get", (RString "val", [String "path"]), 19, [],
    [], (* XXX Augeas code needs tests. *)
    "look up the value of an Augeas path",
-   "\
-Look up the value associated with C<path>.  If C<path>
-matches exactly one node, the C<value> is returned.");
+   [
+P[T"Look up the value associated with ";A"path";T".  If ";A"path";
+T" matches exactly one node, the ";C"value";T" is returned."]]);
 
   ("aug_set", (RErr, [String "path"; String "val"]), 20, [],
    [], (* XXX Augeas code needs tests. *)
    "set Augeas path to value",
-   "\
-Set the value associated with C<path> to C<value>.");
+   [
+P[T"Set the value associated with ";A"path";T" to ";A"val";T"."]]);
 
   ("aug_insert", (RErr, [String "path"; String "label"; Bool "before"]), 21, [],
    [], (* XXX Augeas code needs tests. *)
    "insert a sibling Augeas node",
-   "\
-Create a new sibling C<label> for C<path>, inserting it into
-the tree before or after C<path> (depending on the boolean
-flag C<before>).
+   [
+P[T"Create a new sibling ";A"label";T" for ";A"path";T", inserting it into
+the tree before or after ";A"path";T" (depending on the boolean
+flag ";A"before";T")."];
 
-C<path> must match exactly one existing node in the tree, and
-C<label> must be a label, ie. not contain C</>, C<*> or end
-with a bracketed index C<[N]>.");
+P[A"path";T" must match exactly one existing node in the tree, and ";
+A"label";T" must be a label, ie. not contain ";C"/";T", ";C"*";T" or end
+with a bracketed index ";C"[N]";T"."]]);
 
   ("aug_rm", (RInt "nrnodes", [String "path"]), 22, [],
    [], (* XXX Augeas code needs tests. *)
    "remove an Augeas path",
-   "\
-Remove C<path> and all of its children.
+   [
+P[T"Remove ";A"path";T" and all of its children."];
 
-On success this returns the number of entries which were removed.");
+Q"On success this returns the number of entries which were removed."]);
 
   ("aug_mv", (RErr, [String "src"; String "dest"]), 23, [],
    [], (* XXX Augeas code needs tests. *)
    "move Augeas node",
-   "\
-Move the node C<src> to C<dest>.  C<src> must match exactly
-one node.  C<dest> is overwritten if it exists.");
+   [
+P[T"Move the node ";A"src";T" to ";A"dest";T". ";A"src";T" must match exactly
+one node. ";A"dest";T" is overwritten if it exists."]]);
 
   ("aug_match", (RStringList "matches", [String "path"]), 24, [],
    [], (* XXX Augeas code needs tests. *)
    "return Augeas nodes which match path",
-   "\
-Returns a list of paths which match the path expression C<path>.
+   [
+P[T"Returns a list of paths which match the path expression ";A"path";T".
 The returned paths are sufficiently qualified so that they match
-exactly one node in the current tree.");
+exactly one node in the current tree."]]);
 
   ("aug_save", (RErr, []), 25, [],
    [], (* XXX Augeas code needs tests. *)
    "write all pending Augeas changes to disk",
-   "\
-This writes all pending changes to disk.
+   [
+Q"This writes all pending changes to disk.";
 
-The flags which were passed to C<guestfs_aug_init> affect exactly
-how files are saved.");
+P[T"The flags which were passed to ";X"aug_init";T" affect exactly
+how files are saved."]]);
 
   ("aug_load", (RErr, []), 27, [],
    [], (* XXX Augeas code needs tests. *)
    "load files into the tree",
-   "\
-Load files into the tree.
+   [
+Q"Load files into the tree.";
 
-See C<aug_load> in the Augeas documentation for the full gory
-details.");
+P[T"See ";C"aug_load";T" in the Augeas documentation for the full gory
+details."]]);
 
   ("aug_ls", (RStringList "matches", [String "path"]), 28, [],
    [], (* XXX Augeas code needs tests. *)
    "list Augeas nodes under a path",
-   "\
-This is just a shortcut for listing C<guestfs_aug_match>
-C<path/*> and sorting the resulting nodes into alphabetical order.");
+   [
+P[T"This is just a shortcut for listing ";XA("aug_match",[C"path/*"]);
+T" and sorting the resulting nodes into alphabetical order."]]);
 
   ("rm", (RErr, [String "path"]), 29, [],
    [InitBasicFS, Always, TestRun
@@ -989,8 +1016,8 @@ C<path/*> and sorting the resulting nodes into alphabetical order.");
       [["mkdir"; "/new"];
        ["rm"; "/new"]]],
    "remove a file",
-   "\
-Remove the single file C<path>.");
+   [
+P[T"Remove the single file ";A"path";T"."]]);
 
   ("rmdir", (RErr, [String "path"]), 30, [],
    [InitBasicFS, Always, TestRun
@@ -1002,8 +1029,8 @@ Remove the single file C<path>.");
       [["touch"; "/new"];
        ["rmdir"; "/new"]]],
    "remove a directory",
-   "\
-Remove the single directory C<path>.");
+   [
+P[T"Remove the single directory ";A"path";T"."]]);
 
   ("rm_rf", (RErr, [String "path"]), 31, [],
    [InitBasicFS, Always, TestOutputFalse
@@ -1013,10 +1040,10 @@ Remove the single directory C<path>.");
        ["rm_rf"; "/new"];
        ["exists"; "/new"]]],
    "remove a file or directory recursively",
-   "\
-Remove the file or directory C<path>, recursively removing the
-contents if its a directory.  This is like the C<rm -rf> shell
-command.");
+   [
+P[T"Remove the file or directory ";A"path";T", recursively removing the
+contents if its a directory.  This is like the ";C"rm -rf";T" shell
+command."]]);
 
   ("mkdir", (RErr, [String "path"]), 32, [],
    [InitBasicFS, Always, TestOutputTrue
@@ -1025,8 +1052,8 @@ command.");
     InitBasicFS, Always, TestLastFail
       [["mkdir"; "/new/foo/bar"]]],
    "create a directory",
-   "\
-Create a directory named C<path>.");
+   [
+P[T"Create a directory named ";A"path";T"."]]);
 
   ("mkdir_p", (RErr, [String "path"]), 33, [],
    [InitBasicFS, Always, TestOutputTrue
@@ -1046,26 +1073,26 @@ Create a directory named C<path>.");
       [["touch"; "/new"];
        ["mkdir_p"; "/new"]]],
    "create a directory and parents",
-   "\
-Create a directory named C<path>, creating any parent directories
-as necessary.  This is like the C<mkdir -p> shell command.");
+   [
+P[T"Create a directory named ";A"path";T", creating any parent directories
+as necessary.  This is like the ";C"mkdir -p";T" shell command."]]);
 
   ("chmod", (RErr, [Int "mode"; String "path"]), 34, [],
    [], (* XXX Need stat command to test *)
    "change file mode",
-   "\
-Change the mode (permissions) of C<path> to C<mode>.  Only
-numeric modes are supported.");
+   [
+P[T"Change the mode (permissions) of ";A"path";T" to ";A"mode";T".  Only
+numeric modes are supported."]]);
 
   ("chown", (RErr, [Int "owner"; Int "group"; String "path"]), 35, [],
    [], (* XXX Need stat command to test *)
    "change file owner and group",
-   "\
-Change the file owner to C<owner> and group to C<group>.
+   [
+P[T"Change the file owner to ";A"owner";T" and group to ";A"group";T"."];
 
-Only numeric uid and gid are supported.  If you want to use
+QNote"Only numeric uid and gid are supported.  If you want to use
 names, you will need to locate and parse the password file
-yourself (Augeas support makes this relatively easy).");
+yourself (Augeas support makes this relatively easy)."]);
 
   ("exists", (RBool "existsflag", [String "path"]), 36, [],
    [InitBasicFS, Always, TestOutputTrue (
@@ -1075,11 +1102,11 @@ yourself (Augeas support makes this relatively easy).");
       [["mkdir"; "/new"];
        ["exists"; "/new"]])],
    "test if file or directory exists",
-   "\
-This returns C<true> if and only if there is a file, directory
-(or anything) with the given C<path> name.
+   [
+P[T"This returns ";C"true";T" if and only if there is a file, directory
+(or anything) with the given ";A"path";T" name."];
 
-See also C<guestfs_is_file>, C<guestfs_is_dir>, C<guestfs_stat>.");
+SeeAlso["is_file"; "is_dir"; "stat"]]);
 
   ("is_file", (RBool "fileflag", [String "path"]), 37, [],
    [InitBasicFS, Always, TestOutputTrue (
@@ -1089,12 +1116,12 @@ See also C<guestfs_is_file>, C<guestfs_is_dir>, C<guestfs_stat>.");
       [["mkdir"; "/new"];
        ["is_file"; "/new"]])],
    "test if file exists",
-   "\
-This returns C<true> if and only if there is a file
-with the given C<path> name.  Note that it returns false for
-other objects like directories.
+   [
+P[T"This returns ";C"true";T" if and only if there is a file
+with the given ";A"path";T" name.  Note that it returns false for
+other objects like directories."];
 
-See also C<guestfs_stat>.");
+SeeAlso ["stat"]]);
 
   ("is_dir", (RBool "dirflag", [String "path"]), 38, [],
    [InitBasicFS, Always, TestOutputFalse (
@@ -1104,12 +1131,12 @@ See also C<guestfs_stat>.");
       [["mkdir"; "/new"];
        ["is_dir"; "/new"]])],
    "test if file exists",
-   "\
-This returns C<true> if and only if there is a directory
-with the given C<path> name.  Note that it returns false for
-other objects like files.
+   [
+P[T"This returns ";C"true";T" if and only if there is a directory
+with the given ";A"path";T" name.  Note that it returns false for
+other objects like files."];
 
-See also C<guestfs_stat>.");
+SeeAlso ["stat"]]);
 
   ("pvcreate", (RErr, [String "device"]), 39, [],
    [InitEmpty, Always, TestOutputList (
@@ -1119,10 +1146,10 @@ See also C<guestfs_stat>.");
        ["pvcreate"; "/dev/sda3"];
        ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
    "create an LVM physical volume",
-   "\
-This creates an LVM physical volume on the named C<device>,
-where C<device> should usually be a partition name such
-as C</dev/sda1>.");
+   [
+P[T"This creates an LVM physical volume on the named ";A"device";T",
+where ";A"device";T" should usually be a partition name such
+as ";C"/dev/sda1";T"."]]);
 
   ("vgcreate", (RErr, [String "volgroup"; StringList "physvols"]), 40, [],
    [InitEmpty, Always, TestOutputList (
@@ -1134,9 +1161,9 @@ as C</dev/sda1>.");
        ["vgcreate"; "VG2"; "/dev/sda3"];
        ["vgs"]], ["VG1"; "VG2"])],
    "create an LVM volume group",
-   "\
-This creates an LVM volume group called C<volgroup>
-from the non-empty list of physical volumes C<physvols>.");
+   [
+P[T"This creates an LVM volume group called ";A"volgroup";
+T" from the non-empty list of physical volumes ";A"physvols";T"."]]);
 
   ("lvcreate", (RErr, [String "logvol"; String "volgroup"; Int "mbytes"]), 41, [],
    [InitEmpty, Always, TestOutputList (
@@ -1155,9 +1182,10 @@ from the non-empty list of physical volumes C<physvols>.");
       ["/dev/VG1/LV1"; "/dev/VG1/LV2";
        "/dev/VG2/LV3"; "/dev/VG2/LV4"; "/dev/VG2/LV5"])],
    "create an LVM volume group",
-   "\
-This creates an LVM volume group called C<logvol>
-on the volume group C<volgroup>, with C<size> megabytes.");
+   [
+P[T"This creates an LVM volume group called ";A"logvol";
+T" on the volume group ";A"volgroup";T", with ";A"mbytes";
+T" size in megabytes."]]);
 
   ("mkfs", (RErr, [String "fstype"; String "device"]), 42, [],
    [InitEmpty, Always, TestOutput (
@@ -1167,38 +1195,40 @@ on the volume group C<volgroup>, with C<size> megabytes.");
        ["write_file"; "/new"; "new file contents"; "0"];
        ["cat"; "/new"]], "new file contents")],
    "make a filesystem",
-   "\
-This creates a filesystem on C<device> (usually a partition
-or LVM logical volume).  The filesystem type is C<fstype>, for
-example C<ext3>.");
+   [
+P[T"This creates a filesystem on ";A"device";T" (usually a partition
+or LVM logical volume).  The filesystem type is ";A"fstype";T", for
+example ";C"ext3";T"."]]);
 
   ("sfdisk", (RErr, [String "device";
                     Int "cyls"; Int "heads"; Int "sectors";
                     StringList "lines"]), 43, [DangerWillRobinson],
    [],
    "create partitions on a block device",
-   "\
-This is a direct interface to the L<sfdisk(8)> program for creating
-partitions on block devices.
+   [
+P[T"This is a direct interface to the ";Man("sfdisk",8);T" program for creating
+partitions on block devices."];
 
-C<device> should be a block device, for example C</dev/sda>.
+P[A"device";T" should be a block device, for example ";C"/dev/sda";T"."];
 
-C<cyls>, C<heads> and C<sectors> are the number of cylinders, heads
+P[A"cyls";T", ";A"heads";T" and ";A"sectors";
+T" are the number of cylinders, heads
 and sectors on the device, which are passed directly to sfdisk as
-the I<-C>, I<-H> and I<-S> parameters.  If you pass C<0> for any
+the ";C"-C";T", ";C"-H";T" and ";C"-S";T" parameters.
+If you pass ";C"0";T" for any
 of these, then the corresponding parameter is omitted.  Usually for
-'large' disks, you can just pass C<0> for these, but for small
+'large' disks, you can just pass ";C"0";T" for these, but for small
 (floppy-sized) disks, sfdisk (or rather, the kernel) cannot work
-out the right geometry and you will need to tell it.
+out the right geometry and you will need to tell it."];
 
-C<lines> is a list of lines that we feed to C<sfdisk>.  For more
-information refer to the L<sfdisk(8)> manpage.
+P[A"lines";T" is a list of lines that we feed to ";C"sfdisk";T".  For more
+information refer to the ";Man("sfdisk",8);T" manpage."];
 
-To create a single partition occupying the whole disk, you would
-pass C<lines> as a single element list, when the single element being
-the string C<,> (comma).
+P[T"To create a single partition occupying the whole disk, you would
+pass ";A"lines";T" as a single element list, when the single element being
+the string ";C",";T" (comma)."];
 
-See also: C<guestfs_sfdisk_l>, C<guestfs_sfdisk_N>");
+SeeAlso["sfdisk_l"; "sfdisk_N"]]);
 
   ("write_file", (RErr, [String "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning],
    [InitBasicFS, Always, TestOutput (
@@ -1220,19 +1250,19 @@ See also: C<guestfs_sfdisk_l>, C<guestfs_sfdisk_N>");
       [["write_file"; "/new"; "\n"; "0"];
        ["cat"; "/new"]], "\n")],
    "create a file",
-   "\
-This call creates a file called C<path>.  The contents of the
-file is the string C<content> (which can contain any 8 bit data),
-with length C<size>.
+   [
+P[T"This call creates a file called ";A"path";T".  The contents of the
+file is the string ";A"content";T" (which can contain any 8 bit data),
+with length ";A"size";T"."];
 
-As a special case, if C<size> is C<0>
-then the length is calculated using C<strlen> (so in this case
-the content cannot contain embedded ASCII NULs).
+P[T"As a special case, if ";A"size";T" is ";C"0";
+T" then the length is calculated using ";Man("strlen",3);T" (so in this case
+the content cannot contain embedded ASCII NULs)."];
 
-I<NB.> Owing to a bug, writing content containing ASCII NUL
-characters does I<not> work, even if the length is specified.
+Note[T"Owing to a bug, writing content containing ASCII NUL
+characters does ";Em"not";T" work, even if the length is specified.
 We hope to resolve this bug in a future version.  In the meantime
-use C<guestfs_upload>.");
+use ";X"upload";T"."]]);
 
   ("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"],
    [InitEmpty, Always, TestOutputList (
@@ -1247,20 +1277,20 @@ use C<guestfs_upload>.");
        ["umount"; "/"];
        ["mounts"]], [])],
    "unmount a filesystem",
-   "\
-This unmounts the given filesystem.  The filesystem may be
+   [
+Q"This unmounts the given filesystem.  The filesystem may be
 specified either by its mountpoint (path) or the device which
-contains the filesystem.");
+contains the filesystem."]);
 
   ("mounts", (RStringList "devices", []), 46, [],
    [InitBasicFS, Always, TestOutputList (
       [["mounts"]], ["/dev/sda1"])],
    "show mounted filesystems",
-   "\
-This returns the list of currently mounted filesystems.  It returns
-the list of devices (eg. C</dev/sda1>, C</dev/VG/LV>).
+   [
+P[T"This returns the list of currently mounted filesystems.  It returns
+the list of devices (eg. ";C"/dev/sda1";T", ";C"/dev/VG/LV";T")."];
 
-Some internal mounts are not shown.");
+Q"Some internal mounts are not shown."]);
 
   ("umount_all", (RErr, []), 47, [FishAlias "unmount-all"],
    [InitBasicFS, Always, TestOutputList (
@@ -1281,17 +1311,17 @@ Some internal mounts are not shown.");
        ["umount_all"];
        ["mounts"]], [])],
    "unmount all filesystems",
-   "\
-This unmounts all mounted filesystems.
+   [
+Q"This unmounts all mounted filesystems.";
 
-Some internal mounts are not unmounted by this call.");
+Q"Some internal mounts are not unmounted by this call."]);
 
   ("lvm_remove_all", (RErr, []), 48, [DangerWillRobinson],
    [],
    "remove all LVM LVs, VGs and PVs",
-   "\
-This command removes all LVM logical volumes, volume groups
-and physical volumes.");
+   [
+Q"This command removes all LVM logical volumes, volume groups
+and physical volumes."]);
 
   ("file", (RString "description", [String "path"]), 49, [],
    [InitBasicFS, Always, TestOutput (
@@ -1303,14 +1333,14 @@ and physical volumes.");
     InitBasicFS, Always, TestLastFail (
       [["file"; "/nofile"]])],
    "determine file type",
-   "\
-This call uses the standard L<file(1)> command to determine
+   [
+P[T"This call uses the standard ";Man("file",1);T" command to determine
 the type or contents of the file.  This also works on devices,
-for example to find out whether a partition contains a filesystem.
+for example to find out whether a partition contains a filesystem."];
 
-The exact command which runs is C<file -bsL path>.  Note in
+P[T"The exact command which runs is ";C"file -bsL path";T".  Note in
 particular that the filename is not prepended to the output
-(the C<-b> option).");
+(the ";C"-b";T" option)."]]);
 
   ("command", (RString "output", [StringList "arguments"]), 50, [ProtocolLimitWarning],
    [InitBasicFS, Always, TestOutput (
@@ -1362,34 +1392,34 @@ particular that the filename is not prepended to the output
        ["chmod"; "493"; "/test-command"];
        ["command"; "/test-command"]])],
    "run a command from the guest filesystem",
-   "\
-This call runs a command from the guest filesystem.  The
+   [
+Q"This call runs a command from the guest filesystem.  The
 filesystem must be mounted, and must contain a compatible
 operating system (ie. something Linux, with the same
-or compatible processor architecture).
+or compatible processor architecture).";
 
-The single parameter is an argv-style list of arguments.
+Q"The single parameter is an argv-style list of arguments.
 The first element is the name of the program to run.
 Subsequent elements are parameters.  The list must be
-non-empty (ie. must contain a program name).
+non-empty (ie. must contain a program name).";
 
-The return value is anything printed to I<stdout> by
-the command.
+P[T"The return value is anything printed to ";C"stdout";T" by
+the command."];
 
-If the command returns a non-zero exit status, then
+P[T"If the command returns a non-zero exit status, then
 this function returns an error message.  The error message
-string is the content of I<stderr> from the command.
+string is the content of ";C"stderr";T" from the command."];
 
-The C<$PATH> environment variable will contain at least
-C</usr/bin> and C</bin>.  If you require a program from
+P[T"The ";C"PATH";T" environment variable will contain at least ";
+C"/usr/bin";T" and ";C"/bin";T".  If you require a program from
 another location, you should provide the full path in the
-first parameter.
+first parameter."];
 
-Shared libraries and data files required by the program
+Q"Shared libraries and data files required by the program
 must be available on filesystems which are mounted in the
 correct places.  It is the caller's responsibility to ensure
 all filesystems that are needed are mounted at the right
-locations.");
+locations."]);
 
   ("command_lines", (RStringList "lines", [StringList "arguments"]), 51, [ProtocolLimitWarning],
    [InitBasicFS, Always, TestOutputList (
@@ -1437,33 +1467,33 @@ locations.");
        ["chmod"; "493"; "/test-command"];
        ["command_lines"; "/test-command 11"]], ["Result11-1";"Result11-2"])],
    "run a command, returning lines",
-   "\
-This is the same as C<guestfs_command>, but splits the
-result into a list of lines.");
+   [
+P[T"This is the same as ";X"command";T", but splits the
+result into a list of lines."]]);
 
   ("stat", (RStat "statbuf", [String "path"]), 52, [],
    [InitBasicFS, Always, TestOutputStruct (
       [["touch"; "/new"];
        ["stat"; "/new"]], [CompareWithInt ("size", 0)])],
    "get file information",
-   "\
-Returns file information for the given C<path>.
+   [
+P[T"Returns file information for the given ";A"path";T"."];
 
-This is the same as the C<stat(2)> system call.");
+P[T"This is the same as the ";Man("stat",2);T" system call."]]);
 
   ("lstat", (RStat "statbuf", [String "path"]), 53, [],
    [InitBasicFS, Always, TestOutputStruct (
       [["touch"; "/new"];
        ["lstat"; "/new"]], [CompareWithInt ("size", 0)])],
    "get file information for a symbolic link",
-   "\
-Returns file information for the given C<path>.
+   [
+P[T"Returns file information for the given ";A"path";T"."];
 
-This is the same as C<guestfs_stat> except that if C<path>
-is a symbolic link, then the link is stat-ed, not the file it
-refers to.
+P[T"This is the same as ";X"stat";T" except that if ";A"path";
+T" is a symbolic link, then the link is stat-ed, not the file it
+refers to."];
 
-This is the same as the C<lstat(2)> system call.");
+P[T"This is the same as the ";Man("lstat",2);T" system call."]]);
 
   ("statvfs", (RStatVFS "statbuf", [String "path"]), 54, [],
    [InitBasicFS, Always, TestOutputStruct (
@@ -1471,135 +1501,136 @@ This is the same as the C<lstat(2)> system call.");
                           CompareWithInt ("blocks", 490020);
                           CompareWithInt ("bsize", 1024)])],
    "get file system statistics",
-   "\
-Returns file system statistics for any mounted file system.
-C<path> should be a file or directory in the mounted file system
-(typically it is the mount point itself, but it doesn't need to be).
+   [
+P[T"Returns file system statistics for any mounted file system. ";
+A"path";T" should be a file or directory in the mounted file system
+(typically it is the mount point itself, but it doesn't need to be)."];
 
-This is the same as the C<statvfs(2)> system call.");
+P[T"This is the same as the ";Man("statvfs",2);T" system call."]]);
 
   ("tune2fs_l", (RHashtable "superblock", [String "device"]), 55, [],
    [], (* XXX test *)
    "get ext2/ext3/ext4 superblock details",
-   "\
-This returns the contents of the ext2, ext3 or ext4 filesystem
-superblock on C<device>.
+   [
+P[T"This returns the contents of the ext2, ext3 or ext4 filesystem
+superblock on ";A"device";T"."];
 
-It is the same as running C<tune2fs -l device>.  See L<tune2fs(8)>
-manpage for more details.  The list of fields returned isn't
-clearly defined, and depends on both the version of C<tune2fs>
-that libguestfs was built against, and the filesystem itself.");
+P[T"It is the same as running ";C"tune2fs -l device";T". 
+See ";Man("tune2fs",8);
+T" manpage for more details.  The list of fields returned isn't
+clearly defined, and depends on both the version of ";C"tune2fs";
+T" that libguestfs was built against, and the filesystem itself."]]);
 
   ("blockdev_setro", (RErr, [String "device"]), 56, [],
    [InitEmpty, Always, TestOutputTrue (
       [["blockdev_setro"; "/dev/sda"];
        ["blockdev_getro"; "/dev/sda"]])],
    "set block device to read-only",
-   "\
-Sets the block device named C<device> to read-only.
+   [
+P[T"Sets the block device named ";A"device";T" to read-only."];
 
-This uses the L<blockdev(8)> command.");
+P[T"This uses the ";Man("blockdev",8);T" command."]]);
 
   ("blockdev_setrw", (RErr, [String "device"]), 57, [],
    [InitEmpty, Always, TestOutputFalse (
       [["blockdev_setrw"; "/dev/sda"];
        ["blockdev_getro"; "/dev/sda"]])],
    "set block device to read-write",
-   "\
-Sets the block device named C<device> to read-write.
+   [
+P[T"Sets the block device named ";A"device";T" to read-write."];
 
-This uses the L<blockdev(8)> command.");
+P[T"This uses the ";Man("blockdev",8);T" command."]]);
 
   ("blockdev_getro", (RBool "ro", [String "device"]), 58, [],
    [InitEmpty, Always, TestOutputTrue (
       [["blockdev_setro"; "/dev/sda"];
        ["blockdev_getro"; "/dev/sda"]])],
    "is block device set to read-only",
-   "\
-Returns a boolean indicating if the block device is read-only
-(true if read-only, false if not).
+   [
+Q"Returns a boolean indicating if the block device is read-only
+(true if read-only, false if not).";
 
-This uses the L<blockdev(8)> command.");
+P[T"This uses the ";Man("blockdev",8);T" command."]]);
 
   ("blockdev_getss", (RInt "sectorsize", [String "device"]), 59, [],
    [InitEmpty, Always, TestOutputInt (
       [["blockdev_getss"; "/dev/sda"]], 512)],
    "get sectorsize of block device",
-   "\
-This returns the size of sectors on a block device.
-Usually 512, but can be larger for modern devices.
+   [
+Q"This returns the size of sectors on a block device.
+Usually 512, but can be larger for modern devices.";
 
-(Note, this is not the size in sectors, use C<guestfs_blockdev_getsz>
-for that).
+Note[T"This is not the size in sectors, use ";X"blockdev_getsz";
+T" for that)."];
 
-This uses the L<blockdev(8)> command.");
+P[T"This uses the ";Man("blockdev",8);T" command."]]);
 
   ("blockdev_getbsz", (RInt "blocksize", [String "device"]), 60, [],
    [InitEmpty, Always, TestOutputInt (
       [["blockdev_getbsz"; "/dev/sda"]], 4096)],
    "get blocksize of block device",
-   "\
-This returns the block size of a device.
+   [
+Q"This returns the block size of a device.";
 
-(Note this is different from both I<size in blocks> and
-I<filesystem block size>).
+Note[T"This is different from both ";Em"size in blocks";T" and ";
+Em"filesystem block size";T")."];
 
-This uses the L<blockdev(8)> command.");
+P[T"This uses the ";Man("blockdev",8);T" command."]]);
 
   ("blockdev_setbsz", (RErr, [String "device"; Int "blocksize"]), 61, [],
    [], (* XXX test *)
    "set blocksize of block device",
-   "\
-This sets the block size of a device.
+   [
+Q"This sets the block size of a device.";
 
-(Note this is different from both I<size in blocks> and
-I<filesystem block size>).
+Note[T"This is different from both ";Em"size in blocks";T" and ";
+Em"filesystem block size";T")."];
 
-This uses the L<blockdev(8)> command.");
+P[T"This uses the ";Man("blockdev",8);T" command."]]);
 
   ("blockdev_getsz", (RInt64 "sizeinsectors", [String "device"]), 62, [],
    [InitEmpty, Always, TestOutputInt (
       [["blockdev_getsz"; "/dev/sda"]], 1024000)],
    "get total size of device in 512-byte sectors",
-   "\
-This returns the size of the device in units of 512-byte sectors
-(even if the sectorsize isn't 512 bytes ... weird).
+   [
+Q"This returns the size of the device in units of 512-byte sectors
+(even if the sectorsize isn't 512 bytes ... weird).";
 
-See also C<guestfs_blockdev_getss> for the real sector size of
-the device, and C<guestfs_blockdev_getsize64> for the more
-useful I<size in bytes>.
+P[T"See also ";X"blockdev_getss";T" for the real sector size of
+the device, and ";X"blockdev_getsize64";T" for the more
+useful ";Em"size in bytes";T"."];
 
-This uses the L<blockdev(8)> command.");
+P[T"This uses the ";Man("blockdev",8);T" command."]]);
 
   ("blockdev_getsize64", (RInt64 "sizeinbytes", [String "device"]), 63, [],
    [InitEmpty, Always, TestOutputInt (
       [["blockdev_getsize64"; "/dev/sda"]], 524288000)],
    "get total size of device in bytes",
-   "\
-This returns the size of the device in bytes.
+   [
+Q"This returns the size of the device in bytes.";
 
-See also C<guestfs_blockdev_getsz>.
+SeeAlso ["blockdev_getsz"];
 
-This uses the L<blockdev(8)> command.");
+P[T"This uses the ";Man("blockdev",8);T" command."]]);
 
   ("blockdev_flushbufs", (RErr, [String "device"]), 64, [],
    [InitEmpty, Always, TestRun
       [["blockdev_flushbufs"; "/dev/sda"]]],
    "flush device buffers",
-   "\
-This tells the kernel to flush internal buffers associated
-with C<device>.
+   [
+P[T"This tells the kernel to flush internal buffers associated
+with ";A"device";T"."];
 
-This uses the L<blockdev(8)> command.");
+P[T"This uses the ";Man("blockdev",8);T" command."]]);
 
   ("blockdev_rereadpt", (RErr, [String "device"]), 65, [],
    [InitEmpty, Always, TestRun
       [["blockdev_rereadpt"; "/dev/sda"]]],
    "reread partition table",
-   "\
-Reread the partition table on C<device>.
+   [
+P[T"Reread the partition table on ";A"device";T"."];
 
-This uses the L<blockdev(8)> command.");
+P[T"This uses the ";Man("blockdev",8);T" command."]]);
 
   ("upload", (RErr, [FileIn "filename"; String "remotefilename"]), 66, [],
    [InitBasicFS, Always, TestOutput (
@@ -1607,13 +1638,13 @@ This uses the L<blockdev(8)> command.");
     [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
      ["checksum"; "md5"; "/COPYING.LIB"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
    "upload a file from the local machine",
-   "\
-Upload local file C<filename> to C<remotefilename> on the
-filesystem.
+   [
+P[T"Upload local file ";A"filename";T" to ";A"remotefilename";T" on the
+filesystem."];
 
-C<filename> can also be a named pipe.
+P[A"filename";T" can also be a named pipe."];
 
-See also C<guestfs_download>.");
+SeeAlso["download"]]);
 
   ("download", (RErr, [String "remotefilename"; FileOut "filename"]), 67, [],
    [InitBasicFS, Always, TestOutput (
@@ -1623,13 +1654,13 @@ See also C<guestfs_download>.");
      ["upload"; "testdownload.tmp"; "/upload"];
      ["checksum"; "md5"; "/upload"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
    "download a file to the local machine",
-   "\
-Download file C<remotefilename> and save it as C<filename>
-on the local machine.
+   [
+P[T"Download file ";A"remotefilename";T" and save it as ";A"filename";
+T" on the local machine."];
 
-C<filename> can also be a named pipe.
+P[A"filename";T" can also be a named pipe."];
 
-See also C<guestfs_upload>, C<guestfs_cat>.");
+SeeAlso ["upload"; "cat"]]);
 
   ("checksum", (RString "checksum", [String "csumtype"; String "path"]), 68, [],
    [InitBasicFS, Always, TestOutput (
@@ -1659,87 +1690,87 @@ See also C<guestfs_upload>, C<guestfs_cat>.");
       [["mount"; "/dev/sdd"; "/"];
        ["checksum"; "md5"; "/known-3"]], "46d6ca27ee07cdc6fa99c2e138cc522c")],
    "compute MD5, SHAx or CRC checksum of file",
-   "\
-This call computes the MD5, SHAx or CRC checksum of the
-file named C<path>.
+   [
+P[T"This call computes the MD5, SHAx or CRC checksum of the
+file named ";A"path";T"."];
 
-The type of checksum to compute is given by the C<csumtype>
-parameter which must have one of the following values:
+P[T"The type of checksum to compute is given by the ";A"csumtype";
+T" parameter which must have one of the following values:"];
 
-=over 4
+ItemList [
 
-=item C<crc>
+[C"crc"],
 
-Compute the cyclic redundancy check (CRC) specified by POSIX
-for the C<cksum> command.
+  P[T"Compute the cyclic redundancy check (CRC) specified by POSIX
+for the ";Man("cksum",1);T" command."];
 
-=item C<md5>
+[C"md5"],
 
-Compute the MD5 hash (using the C<md5sum> program).
+  P[T"Compute the MD5 hash (using the ";Man("md5sum",1);T" program)."];
 
-=item C<sha1>
+[C"sha1"],
 
-Compute the SHA1 hash (using the C<sha1sum> program).
+  P[T"Compute the SHA1 hash (using the ";Man("sha1sum",1);T" program)."];
 
-=item C<sha224>
+[C"sha224"],
 
-Compute the SHA224 hash (using the C<sha224sum> program).
+  P[T"Compute the SHA224 hash (using the ";Man("sha224sum",1);T" program)."];
 
-=item C<sha256>
+[C"sha256"],
 
-Compute the SHA256 hash (using the C<sha256sum> program).
+  P[T"Compute the SHA256 hash (using the ";Man("sha256sum",1);T" program)."];
 
-=item C<sha384>
+[C"sha384"],
 
-Compute the SHA384 hash (using the C<sha384sum> program).
+  P[T"Compute the SHA384 hash (using the ";Man("sha384sum",1);T" program)."];
 
-=item C<sha512>
+[C"sha512"],
 
-Compute the SHA512 hash (using the C<sha512sum> program).
+  P[T"Compute the SHA512 hash (using the ";Man("sha512sum",1);T" program)."];
 
-=back
+];
 
-The checksum is returned as a printable string.");
+Q"The checksum is returned as a printable string."]);
 
   ("tar_in", (RErr, [FileIn "tarfile"; String "directory"]), 69, [],
    [InitBasicFS, Always, TestOutput (
       [["tar_in"; "../images/helloworld.tar"; "/"];
        ["cat"; "/hello"]], "hello\n")],
    "unpack tarfile to directory",
-   "\
-This command uploads and unpacks local file C<tarfile> (an
-I<uncompressed> tar file) into C<directory>.
+   [
+P[T"This command uploads and unpacks local file ";A"tarfile";T" (an ";
+Em"uncompressed";T" tar file) into ";A"directory";T"."];
 
-To upload a compressed tarball, use C<guestfs_tgz_in>.");
+P[T"To upload a compressed tarball, use ";X"tgz_in";T"."]]);
 
   ("tar_out", (RErr, [String "directory"; FileOut "tarfile"]), 70, [],
    [],
    "pack directory into tarfile",
-   "\
-This command packs the contents of C<directory> and downloads
-it to local file C<tarfile>.
+   [
+P[T"This command packs the contents of ";A"directory";T" and downloads
+it to local file ";A"tarfile";T"."];
 
-To download a compressed tarball, use C<guestfs_tgz_out>.");
+P[T"To download a compressed tarball, use ";X"tgz_out";T"."]]);
 
   ("tgz_in", (RErr, [FileIn "tarball"; String "directory"]), 71, [],
    [InitBasicFS, Always, TestOutput (
       [["tgz_in"; "../images/helloworld.tar.gz"; "/"];
        ["cat"; "/hello"]], "hello\n")],
    "unpack compressed tarball to directory",
-   "\
-This command uploads and unpacks local file C<tarball> (a
-I<gzip compressed> tar file) into C<directory>.
+   [
+P[T"This command uploads and unpacks local file ";A"tarball";T" (a ";
+Em"gzip compressed";T" tar file) into ";A"directory";T"."];
 
-To upload an uncompressed tarball, use C<guestfs_tar_in>.");
+P[T"To upload an uncompressed tarball, use ";X"tar_in";T"."]]);
 
   ("tgz_out", (RErr, [String "directory"; FileOut "tarball"]), 72, [],
    [],
    "pack directory into compressed tarball",
-   "\
-This command packs the contents of C<directory> and downloads
-it to local file C<tarball>.
+   [
+P[T"This command packs the contents of ";A"directory";T" and downloads
+it to local file ";A"tarball";T"."];
 
-To download an uncompressed tarball, use C<guestfs_tar_out>.");
+P[T"To download an uncompressed tarball, use ";X"tar_out";T"."]]);
 
   ("mount_ro", (RErr, [String "device"; String "mountpoint"]), 73, [],
    [InitBasicFS, Always, TestLastFail (
@@ -1752,37 +1783,37 @@ To download an uncompressed tarball, use C<guestfs_tar_out>.");
        ["mount_ro"; "/dev/sda1"; "/"];
        ["cat"; "/new"]], "data")],
    "mount a guest disk, read-only",
-   "\
-This is the same as the C<guestfs_mount> command, but it
-mounts the filesystem with the read-only (I<-o ro>) flag.");
+   [
+P[T"This is the same as the ";X"mount";T" command, but it
+mounts the filesystem with the read-only (";C"-o ro";T") flag."]]);
 
   ("mount_options", (RErr, [String "options"; String "device"; String "mountpoint"]), 74, [],
    [],
    "mount a guest disk with mount options",
-   "\
-This is the same as the C<guestfs_mount> command, but it
-allows you to set the mount options as for the
-L<mount(8)> I<-o> flag.");
+   [
+P[T"This is the same as the ";X"mount";T" command, but it
+allows you to set the mount options as for the ";
+Man("mount",8);T" ";C"-o";T" flag."]]);
 
   ("mount_vfs", (RErr, [String "options"; String "vfstype"; String "device"; String "mountpoint"]), 75, [],
    [],
    "mount a guest disk with mount options and vfstype",
-   "\
-This is the same as the C<guestfs_mount> command, but it
+   [
+P[T"This is the same as the ";X"mount";T" command, but it
 allows you to set both the mount options and the vfstype
-as for the L<mount(8)> I<-o> and I<-t> flags.");
+as for the ";Man("mount",8);T" ";C"-o";T" and ";C"-t";T" flags."]]);
 
   ("debug", (RString "result", [String "subcmd"; StringList "extraargs"]), 76, [],
    [],
    "debugging and internals",
-   "\
-The C<guestfs_debug> command exposes some internals of
-C<guestfsd> (the guestfs daemon) that runs inside the
-qemu subprocess.
+   [
+P[T"This command exposes some internals of ";
+C"guestfsd";T" (the guestfs daemon) that runs inside the
+qemu subprocess."];
 
-There is no comprehensive help for this command.  You have
-to look at the file C<daemon/debug.c> in the libguestfs source
-to find out what you can do.");
+P[T"There is no comprehensive help for this command.  You have
+to look at the file ";C"daemon/debug.c";T" in the libguestfs source
+to find out what you can do."]]);
 
   ("lvremove", (RErr, [String "device"]), 77, [],
    [InitEmpty, Always, TestOutputList (
@@ -1810,12 +1841,12 @@ to find out what you can do.");
        ["lvremove"; "/dev/VG"];
        ["vgs"]], ["VG"])],
    "remove an LVM logical volume",
-   "\
-Remove an LVM logical volume C<device>, where C<device> is
-the path to the LV, such as C</dev/VG/LV>.
+   [
+P[T"Remove an LVM logical volume ";A"device";T", where ";A"device";T" is
+the path to the LV, such as ";C"/dev/VG/LV";T"."];
 
-You can also remove all LVs in a volume group by specifying
-the VG name, C</dev/VG>.");
+P[T"You can also remove all LVs in a volume group by specifying
+the VG name, ";C"/dev/VG";T"."]]);
 
   ("vgremove", (RErr, [String "vgname"]), 78, [],
    [InitEmpty, Always, TestOutputList (
@@ -1835,11 +1866,11 @@ the VG name, C</dev/VG>.");
        ["vgremove"; "VG"];
        ["vgs"]], [])],
    "remove an LVM volume group",
-   "\
-Remove an LVM volume group C<vgname>, (for example C<VG>).
+   [
+P[T"Remove an LVM volume group ";A"vgname";T", (for example ";C"VG";T")."];
 
-This also forcibly removes all logical volumes in the volume
-group (if any).");
+Q"This also forcibly removes all logical volumes in the volume
+group (if any)."]);
 
   ("pvremove", (RErr, [String "device"]), 79, [],
    [InitEmpty, Always, TestOutputList (
@@ -1870,33 +1901,33 @@ group (if any).");
        ["pvremove"; "/dev/sda1"];
        ["pvs"]], [])],
    "remove an LVM physical volume",
-   "\
-This wipes a physical volume C<device> so that LVM will no longer
-recognise it.
+   [
+P[T"This wipes a physical volume ";A"device";T" so that LVM will no longer
+recognise it."];
 
-The implementation uses the C<pvremove> command which refuses to
+P[T"The implementation uses the ";C"pvremove";T" command which refuses to
 wipe physical volumes that contain any volume groups, so you have
-to remove those first.");
+to remove those first."]]);
 
   ("set_e2label", (RErr, [String "device"; String "label"]), 80, [],
    [InitBasicFS, Always, TestOutput (
       [["set_e2label"; "/dev/sda1"; "testlabel"];
        ["get_e2label"; "/dev/sda1"]], "testlabel")],
    "set the ext2/3/4 filesystem label",
-   "\
-This sets the ext2/3/4 filesystem label of the filesystem on
-C<device> to C<label>.  Filesystem labels are limited to
-16 characters.
+   [
+P[T"This sets the ext2/3/4 filesystem label of the filesystem on ";
+A"device";T" to ";A"label";T".  Filesystem labels are limited to
+16 characters."];
 
-You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2label>
-to return the existing label on a filesystem.");
+P[T"You can use either ";X"tune2fs_l";T" or ";X"get_e2label";
+T" to return the existing label on a filesystem."]]);
 
   ("get_e2label", (RString "label", [String "device"]), 81, [],
    [],
    "get the ext2/3/4 filesystem label",
-   "\
-This returns the ext2/3/4 filesystem label of the filesystem on
-C<device>.");
+   [
+P[T"This returns the ext2/3/4 filesystem label of the filesystem on ";
+A"device";T"."]]);
 
   ("set_e2uuid", (RErr, [String "device"; String "uuid"]), 82, [],
    [InitBasicFS, Always, TestOutput (
@@ -1911,21 +1942,21 @@ C<device>.");
     InitBasicFS, Always, TestRun (
       [["set_e2uuid"; "/dev/sda1"; "time"]])],
    "set the ext2/3/4 filesystem UUID",
-   "\
-This sets the ext2/3/4 filesystem UUID of the filesystem on
-C<device> to C<uuid>.  The format of the UUID and alternatives
-such as C<clear>, C<random> and C<time> are described in the
-L<tune2fs(8)> manpage.
+   [
+P[T"This sets the ext2/3/4 filesystem UUID of the filesystem on ";
+A"device";T" to ";A"uuid";T".  The format of the UUID and alternatives
+such as ";C"clear";T", ";C"random";T" and ";C"time";T" are described in the ";
+Man("tune2fs",8);T" manpage."];
 
-You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2uuid>
-to return the existing UUID of a filesystem.");
+P[T"You can use either ";X"tune2fs_l";T" or ";X"get_e2uuid";
+T" to return the existing UUID of a filesystem."]]);
 
   ("get_e2uuid", (RString "uuid", [String "device"]), 83, [],
    [],
    "get the ext2/3/4 filesystem UUID",
-   "\
-This returns the ext2/3/4 filesystem UUID of the filesystem on
-C<device>.");
+   [
+P[T"This returns the ext2/3/4 filesystem UUID of the filesystem on ";
+A"device";T"."]]);
 
   ("fsck", (RInt "status", [String "fstype"; String "device"]), 84, [],
    [InitBasicFS, Always, TestOutputInt (
@@ -1936,34 +1967,28 @@ C<device>.");
        ["zero"; "/dev/sda1"];
        ["fsck"; "ext2"; "/dev/sda1"]], 8)],
    "run the filesystem checker",
-   "\
-This runs the filesystem checker (fsck) on C<device> which
-should have filesystem type C<fstype>.
+   [
+P[T"This runs the filesystem checker (fsck) on ";A"device";T" which
+should have filesystem type ";A"fstype";T"."];
 
-The returned integer is the status.  See L<fsck(8)> for the
-list of status codes from C<fsck>.
+P[T"The returned integer is the status.  See ";Man("fsck",8);T" for the
+list of status codes from ";C"fsck";T"."];
 
-Notes:
+Q"Notes:";
 
-=over 4
-
-=item *
-
-Multiple status codes can be summed together.
+BulletList [
 
-=item *
+  Q"Multiple status codes can be summed together.";
 
-A non-zero return code can mean \"success\", for example if
-errors have been corrected on the filesystem.
+  Q"A non-zero return code can mean \"success\", for example if
+errors have been corrected on the filesystem.";
 
-=item *
+  Q"Checking or repairing NTFS volumes is not supported (by linux-ntfs)."
 
-Checking or repairing NTFS volumes is not supported
-(by linux-ntfs).
+];
 
-=back
-
-This command is entirely equivalent to running C<fsck -a -t fstype device>.");
+P[T"This command is entirely equivalent to running ";
+C"fsck -a -t fstype device";T"."]]);
 
   ("zero", (RErr, [String "device"]), 85, [],
    [InitBasicFS, Always, TestOutput (
@@ -1971,21 +1996,22 @@ This command is entirely equivalent to running C<fsck -a -t fstype device>.");
        ["zero"; "/dev/sda1"];
        ["file"; "/dev/sda1"]], "data")],
    "write zeroes to the device",
-   "\
-This command writes zeroes over the first few blocks of C<device>.
+   [
+P[T"This command writes zeroes over the first few blocks of ";
+A"device";T"."];
 
-How many blocks are zeroed isn't specified (but it's I<not> enough
-to securely wipe the device).  It should be sufficient to remove
-any partition tables, filesystem superblocks and so on.");
+P[T"How many blocks are zeroed isn't specified (but it's ";Em"not";
+T" enough to securely wipe the device).  It should be sufficient to remove
+any partition tables, filesystem superblocks and so on."]]);
 
   ("grub_install", (RErr, [String "root"; String "device"]), 86, [],
    [InitBasicFS, Always, TestOutputTrue (
       [["grub_install"; "/"; "/dev/sda1"];
        ["is_dir"; "/boot"]])],
    "install GRUB",
-   "\
-This command installs GRUB (the Grand Unified Bootloader) on
-C<device>, with the root directory being C<root>.");
+   [
+P[T"This command installs GRUB (the Grand Unified Bootloader) on ";
+A"device";T", with the root directory being ";A"root";T"."]]);
 
   ("cp", (RErr, [String "src"; String "dest"]), 87, [],
    [InitBasicFS, Always, TestOutput (
@@ -2002,9 +2028,9 @@ C<device>, with the root directory being C<root>.");
        ["cp"; "/old"; "/dir/new"];
        ["cat"; "/dir/new"]], "file content")],
    "copy a file",
-   "\
-This copies a file from C<src> to C<dest> where C<dest> is
-either a destination filename or destination directory.");
+   [
+P[T"This copies a file from ";A"src";T" to ";A"dest";T" where ";A"dest";
+T" is either a destination filename or destination directory."]]);
 
   ("cp_a", (RErr, [String "src"; String "dest"]), 88, [],
    [InitBasicFS, Always, TestOutput (
@@ -2014,9 +2040,9 @@ either a destination filename or destination directory.");
        ["cp_a"; "/olddir"; "/newdir"];
        ["cat"; "/newdir/olddir/file"]], "file content")],
    "copy a file or directory recursively",
-   "\
-This copies a file or directory from C<src> to C<dest>
-recursively using the C<cp -a> command.");
+   [
+P[T"This copies a file or directory from ";A"src";T" to ";A"dest";
+T" recursively using the ";C"cp -a";T" command."]]);
 
   ("mv", (RErr, [String "src"; String "dest"]), 89, [],
    [InitBasicFS, Always, TestOutput (
@@ -2028,48 +2054,48 @@ recursively using the C<cp -a> command.");
        ["mv"; "/old"; "/new"];
        ["is_file"; "/old"]])],
    "move a file",
-   "\
-This moves a file from C<src> to C<dest> where C<dest> is
-either a destination filename or destination directory.");
+   [
+P[T"This moves a file from ";A"src";T" to ";A"dest";T" where ";A"dest";
+T" is either a destination filename or destination directory."]]);
 
   ("drop_caches", (RErr, [Int "whattodrop"]), 90, [],
    [InitEmpty, Always, TestRun (
       [["drop_caches"; "3"]])],
    "drop kernel page cache, dentries and inodes",
-   "\
-This instructs the guest kernel to drop its page cache,
-and/or dentries and inode caches.  The parameter C<whattodrop>
-tells the kernel what precisely to drop, see
-L<http://linux-mm.org/Drop_Caches>
+   [
+P[T"This instructs the guest kernel to drop its page cache,
+and/or dentries and inode caches.  The parameter ";A"whattodrop";
+T" tells the kernel what precisely to drop, see ";
+URL"http://linux-mm.org/Drop_Caches"];
 
-Setting C<whattodrop> to 3 should drop everything.
+P[T"Setting ";A"whattodrop";T" to 3 should drop everything."];
 
-This automatically calls L<sync(2)> before the operation,
-so that the maximum guest memory is freed.");
+P[T"This automatically calls ";Man("sync",2);T" before the operation,
+so that the maximum guest memory is freed."]]);
 
   ("dmesg", (RString "kmsgs", []), 91, [],
    [InitEmpty, Always, TestRun (
       [["dmesg"]])],
    "return kernel messages",
-   "\
-This returns the kernel messages (C<dmesg> output) from
+   [
+P[T"This returns the kernel messages (";C"dmesg";T" output) from
 the guest kernel.  This is sometimes useful for extended
-debugging of problems.
+debugging of problems."];
 
-Another way to get the same information is to enable
-verbose messages with C<guestfs_set_verbose> or by setting
-the environment variable C<LIBGUESTFS_DEBUG=1> before
-running the program.");
+P[T"Another way to get the same information is to enable
+verbose messages with ";X"set_verbose";T" or by setting
+the environment variable ";C"LIBGUESTFS_DEBUG=1";T" before
+running the program."]]);
 
   ("ping_daemon", (RErr, []), 92, [],
    [InitEmpty, Always, TestRun (
       [["ping_daemon"]])],
    "ping the guest daemon",
-   "\
-This is a test probe into the guestfs daemon running inside
+   [
+Q"This is a test probe into the guestfs daemon running inside
 the qemu subprocess.  Calling this function checks that the
 daemon responds to the ping message, without affecting the daemon
-or attached block device(s) in any other way.");
+or attached block device(s) in any other way."]);
 
   ("equal", (RBool "equality", [String "file1"; String "file2"]), 93, [],
    [InitBasicFS, Always, TestOutputTrue (
@@ -2083,11 +2109,11 @@ or attached block device(s) in any other way.");
     InitBasicFS, Always, TestLastFail (
       [["equal"; "/file1"; "/file2"]])],
    "test if two files have equal contents",
-   "\
-This compares the two files C<file1> and C<file2> and returns
-true if their content is exactly equal, or false otherwise.
+   [
+P[T"This compares the two files ";A"file1";T" and ";A"file2";T" and returns
+true if their content is exactly equal, or false otherwise."];
 
-The external L<cmp(1)> program is used for the comparison.");
+P[T"The external ";Man("cmp",1);T" program is used for the comparison."]]);
 
   ("strings", (RStringList "stringsout", [String "path"]), 94, [ProtocolLimitWarning],
    [InitBasicFS, Always, TestOutputList (
@@ -2097,9 +2123,9 @@ The external L<cmp(1)> program is used for the comparison.");
       [["touch"; "/new"];
        ["strings"; "/new"]], [])],
    "print the printable strings in a file",
-   "\
-This runs the L<strings(1)> command on a file and returns
-the list of printable strings found.");
+   [
+P[T"This runs the ";Man("strings",1);T" command on a file and returns
+the list of printable strings found."]]);
 
   ("strings_e", (RStringList "stringsout", [String "encoding"; String "path"]), 95, [ProtocolLimitWarning],
    [InitBasicFS, Always, TestOutputList (
@@ -2109,25 +2135,25 @@ the list of printable strings found.");
       [["write_file"; "/new"; "\000h\000e\000l\000l\000o\000\n\000w\000o\000r\000l\000d\000\n"; "24"];
        ["strings_e"; "b"; "/new"]], ["hello"; "world"])],
    "print the printable strings in a file",
-   "\
-This is like the C<guestfs_strings> command, but allows you to
-specify the encoding.
+   [
+P[T"This is like the ";X"strings";T" command, but allows you to
+specify the encoding."];
 
-See the L<strings(1)> manpage for the full list of encodings.
+P[T"See the ";Man("strings",1);T" manpage for the full list of encodings."];
 
-Commonly useful encodings are C<l> (lower case L) which will
-show strings inside Windows/x86 files.
+P[T"Commonly useful encodings are ";C"l";T" (lower case L) which will
+show strings inside Windows/x86 files."];
 
-The returned strings are transcoded to UTF-8.");
+Q"The returned strings are transcoded to UTF-8."]);
 
   ("hexdump", (RString "dump", [String "path"]), 96, [ProtocolLimitWarning],
    [InitBasicFS, Always, TestOutput (
       [["write_file"; "/new"; "hello\nworld\n"; "12"];
        ["hexdump"; "/new"]], "00000000  68 65 6c 6c 6f 0a 77 6f  72 6c 64 0a              |hello.world.|\n0000000c\n")],
    "dump a file in hexadecimal",
-   "\
-This runs C<hexdump -C> on the given C<path>.  The result is
-the human-readable, canonical hex dump of the file.");
+   [
+P[T"This runs ";C"hexdump -C";T" on the given ";A"path";T".  The result is
+the human-readable, canonical hex dump of the file."]]);
 
   ("zerofree", (RErr, [String "device"]), 97, [],
    [InitNone, Always, TestOutput (
@@ -2140,92 +2166,92 @@ the human-readable, canonical hex dump of the file.");
        ["mount"; "/dev/sda1"; "/"];
        ["cat"; "/new"]], "test file")],
    "zero unused inodes and disk blocks on ext2/3 filesystem",
-   "\
-This runs the I<zerofree> program on C<device>.  This program
-claims to zero unused inodes and disk blocks on an ext2/3
+   [
+P[T"This runs the ";Man("zerofree",8);T" program on ";A"device";
+T". This program claims to zero unused inodes and disk blocks on an ext2/3
 filesystem, thus making it possible to compress the filesystem
-more effectively.
+more effectively."];
 
-You should B<not> run this program if the filesystem is
-mounted.
+P[T"You should ";Em"not";T" run this program if the filesystem is
+mounted."];
 
-It is possible that using this program can damage the filesystem
-or data on the filesystem.");
+Q"It is possible that using this program can damage the filesystem
+or data on the filesystem."]);
 
   ("pvresize", (RErr, [String "device"]), 98, [],
    [],
    "resize an LVM physical volume",
-   "\
-This resizes (expands or shrinks) an existing LVM physical
-volume to match the new size of the underlying device.");
+   [
+Q"This resizes (expands or shrinks) an existing LVM physical
+volume to match the new size of the underlying device."]);
 
   ("sfdisk_N", (RErr, [String "device"; Int "n";
                       Int "cyls"; Int "heads"; Int "sectors";
                       String "line"]), 99, [DangerWillRobinson],
    [],
    "modify a single partition on a block device",
-   "\
-This runs L<sfdisk(8)> option to modify just the single
-partition C<n> (note: C<n> counts from 1).
+   [
+P[T"This runs ";Man("sfdisk",8);T" option to modify just the single
+partition ";A"n";T" (note: ";A"n";T" counts from 1)."];
 
-For other parameters, see C<guestfs_sfdisk>.  You should usually
-pass C<0> for the cyls/heads/sectors parameters.");
+P[T"For other parameters, see ";X"sfdisk";T".  You should usually
+pass ";C"0";T" for the cyls/heads/sectors parameters."]]);
 
   ("sfdisk_l", (RString "partitions", [String "device"]), 100, [],
    [],
    "display the partition table",
-   "\
-This displays the partition table on C<device>, in the
-human-readable output of the L<sfdisk(8)> command.  It is
-not intended to be parsed.");
+   [
+P[T"This displays the partition table on ";A"device";T", in the
+human-readable output of the ";Man("sfdisk",8);T" command.  It is
+not intended to be parsed."]]);
 
   ("sfdisk_kernel_geometry", (RString "partitions", [String "device"]), 101, [],
    [],
    "display the kernel geometry",
-   "\
-This displays the kernel's idea of the geometry of C<device>.
+   [
+P[T"This displays the kernel's idea of the geometry of ";A"device";T"."];
 
-The result is in human-readable format, and not designed to
-be parsed.");
+Q"The result is in human-readable format, and not designed to
+be parsed."]);
 
   ("sfdisk_disk_geometry", (RString "partitions", [String "device"]), 102, [],
    [],
    "display the disk geometry from the partition table",
-   "\
-This displays the disk geometry of C<device> read from the
+   [
+P[T"This displays the disk geometry of ";A"device";T" read from the
 partition table.  Especially in the case where the underlying
 block device has been resized, this can be different from the
-kernel's idea of the geometry (see C<guestfs_sfdisk_kernel_geometry>).
+kernel's idea of the geometry (see ";X"sfdisk_kernel_geometry";T")."];
 
-The result is in human-readable format, and not designed to
-be parsed.");
+Q"The result is in human-readable format, and not designed to
+be parsed."]);
 
   ("vg_activate_all", (RErr, [Bool "activate"]), 103, [],
    [],
    "activate or deactivate all volume groups",
-   "\
-This command activates or (if C<activate> is false) deactivates
+   [
+P[T"This command activates or (if ";A"activate";T" is false) deactivates
 all logical volumes in all volume groups.
 If activated, then they are made known to the
-kernel, ie. they appear as C</dev/mapper> devices.  If deactivated,
-then those devices disappear.
+kernel, ie. they appear as ";C"/dev/mapper";T" devices.  If deactivated,
+then those devices disappear."];
 
-This command is the same as running C<vgchange -a y|n>");
+P[T"This command is the same as running ";C"vgchange -a y|n"]]);
 
   ("vg_activate", (RErr, [Bool "activate"; StringList "volgroups"]), 104, [],
    [],
    "activate or deactivate some volume groups",
-   "\
-This command activates or (if C<activate> is false) deactivates
-all logical volumes in the listed volume groups C<volgroups>.
+   [
+P[T"This command activates or (if ";A"activate";T" is false) deactivates
+all logical volumes in the listed volume groups ";A"volgroups";T".
 If activated, then they are made known to the
-kernel, ie. they appear as C</dev/mapper> devices.  If deactivated,
-then those devices disappear.
+kernel, ie. they appear as ";C"/dev/mapper";T" devices.  If deactivated,
+then those devices disappear."];
 
-This command is the same as running C<vgchange -a y|n volgroups...>
+P[T"This command is the same as running ";C"vgchange -a y|n volgroups..."];
 
-Note that if C<volgroups> is an empty list then B<all> volume groups
-are activated or deactivated.");
+Note[T"If ";A"volgroups";T" is an empty list then ";
+Em"all";T" volume groups are activated or deactivated."]]);
 
   ("lvresize", (RErr, [String "device"; Int "mbytes"]), 105, [],
    [InitNone, Always, TestOutput (
@@ -2243,23 +2269,23 @@ are activated or deactivated.");
      ["mount"; "/dev/VG/LV"; "/"];
      ["cat"; "/new"]], "test content")],
    "resize an LVM logical volume",
-   "\
-This resizes (expands or shrinks) an existing LVM logical
-volume to C<mbytes>.  When reducing, data in the reduced part
-is lost.");
+   [
+P[T"This resizes (expands or shrinks) an existing LVM logical
+volume to ";A"mbytes";T".  When reducing, data in the reduced part
+is lost."]]);
 
   ("resize2fs", (RErr, [String "device"]), 106, [],
    [], (* lvresize tests this *)
    "resize an ext2/ext3 filesystem",
-   "\
-This resizes an ext2 or ext3 filesystem to match the size of
-the underlying device.
+   [
+Q"This resizes an ext2 or ext3 filesystem to match the size of
+the underlying device.";
 
-I<Note:> It is sometimes required that you run C<guestfs_e2fsck_f>
-on the C<device> before calling this command.  For unknown reasons
-C<resize2fs> sometimes gives an error about this and sometimes not.
-In any case, it is always safe to call C<guestfs_e2fsck_f> before
-calling this function.");
+Note[T"It is sometimes required that you run ";X"e2fsck_f";
+T" on the ";A"device";T" before calling this command.  For unknown reasons ";
+C"resize2fs";T" sometimes gives an error about this and sometimes not.
+In any case, it is always safe to call ";X"e2fsck_f";T" before
+calling this function."]]);
 
   ("find", (RStringList "names", [String "directory"]), 107, [],
    [InitBasicFS, Always, TestOutputList (
@@ -2274,42 +2300,46 @@ calling this function.");
        ["touch"; "/a/b/c/d"];
        ["find"; "/a/b/"]], ["c"; "c/d"])],
    "find all files and directories",
-   "\
-This command lists out all files and directories, recursively,
-starting at C<directory>.  It is essentially equivalent to
-running the shell command C<find directory -print> but some
-post-processing happens on the output, described below.
+   [
+P[T"This command lists out all files and directories, recursively,
+starting at ";A"directory";T".  It is essentially equivalent to
+running the shell command ";C"find directory -print";T" but some
+post-processing happens on the output, described below."];
 
-This returns a list of strings I<without any prefix>.  Thus
-if the directory structure was:
+P[T"This returns a list of strings ";Em"without any prefix";T". Thus
+if the directory structure was:"];
 
- /tmp/a
- /tmp/b
- /tmp/c/d
+Pre[
+"/tmp/a";
+"/tmp/b";
+"/tmp/c/d"
+];
 
-then the returned list from C<guestfs_find> C</tmp> would be
-4 elements:
+P[T"then the returned list from ";XA("find",[C"/tmp"]);T" would be
+4 elements:"];
 
- a
- b
- c
- c/d
+Pre[
+"a";
+"b";
+"c";
+"c/d"
+];
 
-If C<directory> is not a directory, then this command returns
-an error.
+P[T"If ";A"directory";T" is not a directory, then this command returns
+an error."];
 
-The returned list is sorted.");
+Q"The returned list is sorted."]);
 
   ("e2fsck_f", (RErr, [String "device"]), 108, [],
    [], (* lvresize tests this *)
    "check an ext2/ext3 filesystem",
-   "\
-This runs C<e2fsck -p -f device>, ie. runs the ext2/ext3
-filesystem checker on C<device>, noninteractively (C<-p>),
-even if the filesystem appears to be clean (C<-f>).
+   [
+P[T"This runs ";C"e2fsck -p -f device";T", ie. runs the ext2/ext3
+filesystem checker on ";A"device";T", noninteractively (";C"-p";T"),
+even if the filesystem appears to be clean (";C"-f";T")."];
 
-This command is only needed because of C<guestfs_resize2fs>
-(q.v.).  Normally you should use C<guestfs_fsck>.");
+P[T"This command is only needed because of ";X"resize2fs";
+T" (q.v.).  Normally you should use ";X"fsck";T"."]]);
 
 ]
 
@@ -2509,6 +2539,19 @@ let rec string_split sep str =
     s' :: string_split sep s''
   )
 
+let string_map f str =
+  let strs = ref [] in
+  let n = String.length str in
+  let rec loop i =
+    if i < n then (
+      let s = f str.[i] in
+      strs := s :: !strs;
+      loop (i+1)
+    )
+  in
+  loop 0;
+  String.concat "" (List.rev !strs)
+
 let files_equal n1 n2 =
   let cmd = sprintf "cmp -s %s %s" (Filename.quote n1) (Filename.quote n2) in
   match Sys.command cmd with
@@ -2537,6 +2580,9 @@ let mapi f xs =
   in
   loop 0 xs
 
+let itersep f sep xs =
+  iteri (fun i x -> if i > 0 then sep (); f x) xs
+
 let name_of_argt = function
   | String n | OptString n | StringList n | Bool n | Int n
   | FileIn n | FileOut n -> n
@@ -2620,12 +2666,67 @@ let check_functions () =
        failwithf "short description of %s should not end with . or \\n." name
   ) all_functions;
 
-  (* Check long dscriptions. *)
-  List.iter (
-    fun (name, _, _, _, _, _, longdesc) ->
-      if longdesc.[String.length longdesc-1] = '\n' then
-       failwithf "long description of %s should not end with \\n." name
-  ) all_functions;
+  (* Check long descriptions. *)
+  let () =
+    let cmds = List.map (fun (name, _, _, _, _, _, _) -> name) all_functions in
+
+    List.iter (
+      fun (name, style, _, _, _, _, longdesc) ->
+       let args = List.map name_of_argt (snd style) in
+
+       if longdesc = [] then
+         failwithf "%s has no long description" name;
+
+       let rec check_para = function
+         | Q str -> check_snippet (T str)
+         | P snips -> List.iter check_snippet snips
+         | ItemList xs ->
+             List.iter
+               (fun (snips, para) -> check_para (P snips); check_para para)
+               xs
+         | BulletList ps -> List.iter check_para ps
+         | QNote str -> check_snippet (T str)
+         | Note snips -> List.iter check_snippet snips
+         | Pre xs -> List.iter (fun str -> check_snippet (T str)) xs
+         | SeeAlso xs -> List.iter (fun cmd -> check_snippet (X cmd)) xs
+       and check_snippet = function
+         | T str | Em str ->
+             if str = "" then
+               failwithf "%s has empty string snippet (eg. T\"\")" name;
+             check_no_perldoc str
+         | C code ->
+             if List.mem code args then
+               failwithf "%s has C\"%s\", should be A\"%s\"" name code code;
+             if code = "NULL" || code = "non-NULL" then
+               failwithf "%s C\"%s\" should be NULL|NONNULL" name code;
+         | A arg ->
+             if not (List.mem arg args) then
+               failwithf "%s A\"%s\" refers to non-existent arg" name arg;
+         | X cmd | XA (cmd, _) ->
+             if not (List.mem cmd cmds) then
+               failwithf "%s X\"%s\" refers to non-existent command" name cmd;
+         | XU cmd ->
+             if List.mem cmd cmds then
+               failwithf "%s XU\"%s\" should be X\"%s\"" name cmd cmd;
+         | XW cmd -> ()
+         | Man ("guestfs", 3) -> ()
+         | Man ("guestfish", 1) -> ()
+         | Man (man, sect) ->
+             let prefix = sprintf "/usr/share/man/man%d/%s.%d" sect man sect in
+             if not (Sys.file_exists prefix) &&
+               not (Sys.file_exists (prefix ^ ".gz")) then
+                 eprintf "warning: %s: refers to non-existent manpage %s(%d)\n"
+                   name man sect
+         | URL _
+         | NULL | NONNULL -> ()
+       and check_no_perldoc str =
+         if find str "C<" >= 0 || find str "I<" >= 0
+           || find str "B<" >= 0 || find str "E<" >= 0
+           || find str "\n=" >= 0 then
+             failwithf "%s long description contains perldoc markup" name
+       in
+       List.iter check_para longdesc
+    ) all_functions in
 
   (* Check proc_nrs. *)
   List.iter (
@@ -2751,7 +2852,7 @@ let rec generate_actions_pod () =
        pr " ";
        generate_prototype ~extern:false ~handle:"handle" name style;
        pr "\n\n";
-       pr "%s\n\n" longdesc;
+       generate_pod_of_longdesc ~language:`C longdesc;
        (match fst style with
         | RErr ->
             pr "This function returns 0 on success or -1 on error.\n\n"
@@ -2844,6 +2945,78 @@ and generate_structs_pod () =
       pr "\n"
   ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
 
+(* Generate POD (Perl documentation format, also used for manpages
+ * and C API documentation) from the longdesc structure.
+ *)
+and generate_pod_of_longdesc ~language paras =
+  let rec do_para = function
+    | Q str -> do_para (P [T str])
+    | P snips -> List.iter do_snippet snips
+    | ItemList items ->
+       pr "=over 4\n\n";
+       List.iter
+         (fun (snips, para) ->
+            pr "=item ";
+            List.iter do_snippet snips;
+            pr "\n\n";
+            do_para para;
+            pr "\n\n";
+         ) items;
+       pr "=back\n\n";
+    | BulletList items ->
+       List.iter
+         (fun para ->
+            pr "=item *\n\n";
+            do_para para;
+            pr "\n\n";
+         ) items
+    | QNote str -> do_para (Note [T str])
+    | Note snips ->
+       pr "B<Note:>\n";
+       List.iter do_snippet snips;
+       pr "\n\n";
+    | Pre lines ->
+       List.iter (pr " %s\n") lines;
+       pr "\n";
+    | SeeAlso cmds ->
+       pr "I<See also:>\n";
+       itersep (fun cmd -> do_snippet (X cmd)) (fun () -> pr ", ") cmds;
+       pr "\n\n";
+  and do_snippet = function
+    | T str -> pr "%s" (pod_quote str)
+    | C str
+    | A str -> pr "C<%s>" (pod_quote str)
+    | X cmd ->
+       (match language with
+        | `C -> pr "L<guestfs_%s>" cmd
+        | `Perl -> pr "$h-E<gt>L<%s>" cmd
+       )
+    | XA (cmd, args) ->
+       (match language with
+        | `C ->
+            pr "L<guestfs_%s> (g" cmd;
+            List.iter (fun arg -> pr ", "; do_snippet arg) args;
+            pr ")"
+        | `Perl ->
+            pr "$h->L<%s> (" cmd;
+            itersep (fun arg -> do_snippet arg) (fun () -> pr ", ") args;
+            pr ")")
+    | XU cmd ->        pr "C<%s> I<[unimplemented]>" cmd
+    | XW cmd ->        pr "C<%s>" cmd
+    | Em str ->        pr "I<%s>" (pod_quote str)
+    | Man (man, sect) -> pr "L<%s(%d)>" man sect
+    | URL url -> pr "L<%s>" url
+    | NULL ->
+       (match language with `C -> pr "NULL" | `Perl -> pr "undef")
+    | NONNULL ->
+       (match language with `C -> pr "non-NULL" | `Perl -> pr "defined")
+  and pod_quote str =
+    string_map
+      (function '<' -> "E<lt>" | '>' -> "E<gt>" | c -> String.make 1 c)
+      str
+  in
+  List.iter do_para paras
+
 (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
  * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
  *
@@ -4445,7 +4618,6 @@ and generate_fish_cmds () =
       let alias =
        try find_map (function FishAlias n -> Some n | _ -> None) flags
        with Not_found -> name in
-      let longdesc = replace_str longdesc "C<guestfs_" "C<" in
       let synopsis =
        match snd style with
        | [] -> name2
@@ -4453,6 +4625,20 @@ and generate_fish_cmds () =
            sprintf "%s <%s>"
              name2 (String.concat "> <" (List.map name_of_argt args)) in
 
+      pr "  if (";
+      pr "strcasecmp (cmd, \"%s\") == 0" name;
+      if name <> name2 then
+       pr " || strcasecmp (cmd, \"%s\") == 0" name2;
+      if name <> alias then
+       pr " || strcasecmp (cmd, \"%s\") == 0" alias;
+      pr ") {\n";
+      pr "    printf (\"%s - %s\\n\\n\");\n" name2 shortdesc;
+      let lines = text_of_longdesc ~language:`Fish ~width:60 longdesc in
+      List.iter (
+       fun line ->
+         pr "    printf (\"%s\\n\");\n" (c_quote line)
+      ) lines;
+
       let warnings =
        if List.mem ProtocolLimitWarning flags then
          ("\n\n" ^ protocol_limit_warning)
@@ -4473,17 +4659,8 @@ and generate_fish_cmds () =
          sprintf "\n\nYou can use '%s' as an alias for this command." alias
        else "" in
 
-      pr "  if (";
-      pr "strcasecmp (cmd, \"%s\") == 0" name;
-      if name <> name2 then
-       pr " || strcasecmp (cmd, \"%s\") == 0" name2;
-      if name <> alias then
-       pr " || strcasecmp (cmd, \"%s\") == 0" alias;
-      pr ")\n";
-      pr "    pod2text (\"%s - %s\", %S);\n"
-       name2 shortdesc
-       (" " ^ synopsis ^ "\n\n" ^ longdesc ^ warnings ^ describe_alias);
-      pr "  else\n"
+
+      pr "  } else\n"
   ) all_functions;
   pr "    display_builtin_command (cmd);\n";
   pr "}\n";
@@ -5784,17 +5961,14 @@ and generate_perl_prototype name style =
    | RHashtable n -> pr "%%%s = " n
   );
   pr "$h->%s (" name;
-  let comma = ref false in
-  List.iter (
+  itersep (
     fun arg ->
-      if !comma then pr ", ";
-      comma := true;
       match arg with
       | String n | OptString n | Bool n | Int n | FileIn n | FileOut n ->
          pr "$%s" n
       | StringList n ->
          pr "\\@%s" n
-  ) (snd style);
+  ) (fun () -> pr ", ") (snd style);
   pr ");"
 
 (* Generate Python C module. *)