CATMAN(8)

NAME
catman - format all manual pages below a directory

SYNOPSIS
catman [-I os=name] [-T output] srcdir dstdir

DESCRIPTION
The catman utility assumes that all files below srcdir are manual pages in mdoc(7) and man(7) format and formats all of them, storing the formatted versions in the same relative paths below dstdir. Unless they already exist, dstdir itself and any required subdirectories are created. Existing files are not explicitly deleted, but possibly overwritten.

The options are as follows:

-I os=name
    Override the default operating system name for the mdoc(7) Os and for the man(7) TH macro.

-T output
    Output format. The output argument can be ascii, utf8, or html; see mandoc(1). In html output mode, the fragment output option is implied. Other output options are not supported.

-v  Verbose mode, printing additional information to standard error output. Specifying this once prints a summary about the number of files and directories processed at the end of the iteration. Specifying it twice additionally prints debugging information about the backchannel from mandocd(8) to catman that is used to limit the number of files in flight at any given time. For details, see DIAGNOSTICS.

IMPLEMENTATION NOTES
Since this version avoids fork(2) and exec(3) overhead and uses the much faster mandoc parsers and formatters rather than groff, it may be about one order of magnitude faster than other catman implementations.

EXIT STATUS

Failures while trying to open individual manual pages for reading, to save individual formatted files to the file system, or even to read or create subdirectories do not cause catman to return an error exit status. In such cases, catman simply continues with the next file or subdirectory.

DIAGNOSTICS
Some fatal errors cause catman to exit before the iteration over input files is even started:

unknown option -- option
    An invalid option was passed on the command line.

missing arguments: srcdir and dstdir
    No argument was provided. Both srcdir and dstdir are mandatory.

missing argument: dstdir
    Only one argument was provided. The second argument, dstdir, is mandatory, too.

too many arguments: third argument
    Three or more arguments were provided, but only two are supported.

socketpair: reason
    The sockets needed for communication with mandocd(8) could not be created, for example due to file descriptor or memory exhaustion.

fork: reason
    The new process needed to run mandocd(8) could not be created, for example due to process table exhaustion or system resource limits.

exec(mandocd): reason
    The mandocd(8) child program could not be started, for example because it is not in the PATH or has no execute permission.

mkdir destination dstdir: reason
    The dstdir does not exist and could not be created, for example because the parent directory does not exist or permission is denied.

open destination dstdir: reason
    The dstdir could not be opened for reading, for example because it is not a directory or permission is denied.

chdir to source srcdir: reason
    The current working directory could not be changed to srcdir, for example because it does not exist, it is not a directory, or permission is denied.

fts_open: reason
    Starting the iteration was attempted but failed, for example due to memory exhaustion.

Some fatal errors cause the iteration over input files to be aborted prematurely:

FATAL: fts_read: reason
    A call to fts_read(3) returned NULL, meaning that the iteration failed before being complete.

FATAL: mandocd child died: got SIGNAME
    This message appears if catman gets the SIGCHLD or SIGPIPE signal, most likely due to a fatal bug in mandocd(8).

FATAL: sendmsg: reason
    The file descriptors needed to process one of the manual pages could not be sent to mandocd(8), for example because mandocd(8) could not be started or died unexpectedly.

FATAL: recv: reason
    Trying to read a reply message from mandocd(8) failed, most likely because mandocd(8) unexpectedly died or closed the socket.

FATAL: signal SIGNAME
    This message appears if catman gets a SIGHUP, SIGINT, or SIGTERM signal, for example because the user deliberately killed it.

Some non-fatal errors cause a single subdirectory to be skipped. The iteration is not aborted but continues with the next subdirectory, and the exit status is unaffected:

directory subdirectory unreadable: reason
    A directory below srcdir could not be read and is skipped.

directory subdirectory causes cycle
    A directory below srcdir is skipped because it would cause cyclic processing.

mkdirat subdirectory: reason
    A required directory below dstdir does not exist and could not be created. The corresponding subdirectory below srcdir is skipped.

Some non-fatal errors cause a single source file to be skipped. The iteration is not aborted but continues with the next file, and the exit status is unaffected:

file filename: reason
    The function fts_read(3) reported a non-fatal error with respect to filename.

file filename: not a regular file
    For example, it might be a symbolic link or a device file.

open filename for reading: reason
    A file below srcdir could not be read, for example due to permission problems.

openat filename for writing: reason
    A file below dstdir could not be created or truncated, for example due to permission problems.

If errors occur, the applicable summary messages appear after the end of the iteration:

skipped number directories due to errors
skipped number files due to errors
processing aborted due to fatal error

If the -v flag is specified, the following summary message also appears:

processed nfiles files in ndirs directories
    A file is counted if it could be opened for reading and the corresponding output file could be opened for writing; this does not necessarily mean that it is a useful manual page. A directory is counted if it could be opened for reading and the corresponding output directory existed or could be created; this does not necessarily mean that any files could be processed inside.

If the -v flag is specified twice, the following messages also appear:

allowing up to number files in flight
    This is printed at the beginning of the iteration, showing the maximum number of files that catman allows to be in flight at any given time.

files in flight: old - decrement = new
    This message is printed when catman learns about mandocd(8) accepting more than one file at the same time. The three numbers printed are the old number of files in flight, the amount this number is being reduced, and the resulting new number of files in flight.

waiting for number files in flight
    This message is printed at the end of the iteration, after catman has submitted all files to mandocd(8) that it intends to. THe message informs about the number of files still in flight at this point. The catman program then waits until mandocd(8) has accepted them all or until an error occurs.

SEE ALSO
mandoc(1), mandocd(8)

HISTORY
A catman utility first appeared in FreeBSD 1.0. Other, incompatible implementations appeared in NetBSD 1.0 and in man-db 2.2.

This version appeared in version 1.14.1 of the mandoc toolkit.

AUTHORS
-nosplit The first catman implementation was a short shell script by Christoph Robitschko in July 1993.

The NetBSD implementations were written by J. T. Conklin <jtc@netbsd.org> in 1993, Christian E. Hopps <chopps@netbsd.org> in 1994, and Dante Profeta <dante@netbsd.org> in 1999; the man-db implementation by Graeme W. Wilford in 1994; and the FreeBSD implementations by Wolfram Schneider <wosch@freebsd.org> in 1995 and John Rochester <john@jrochester.org> in 2002.

The concept of the present version was designed and implemented by Michael Stapelberg <stapelberg@debian.org> in 2017. Option and argument handling and directory iteration was added by Ingo Schwarze <schwarze@openbsd.org>.

CAVEATS
All versions of catman are incompatible with each other because each caters to the needs of a specific operating system, for example regarding directory structures and file naming conventions.

This version is more flexible than the others in so far as it does not assume any particular directory structure or naming convention. That flexibility comes at the price of not being able to change the names and relative paths of the source files when reusing them to store the formatted files, of not supporting any configuration file formats or environment variables, and of being unable to scan for and remove junk files in dstdir.

Currently, catman always reformats each page, even if the formatted version is newer than the source version.