1.\" $Id: mandocd.8,v 1.5 2025/06/30 15:07:38 schwarze Exp $ 2.\" 3.\" Copyright (c) 2017, 2025 Ingo Schwarze <schwarze@openbsd.org> 4.\" 5.\" Permission to use, copy, modify, and distribute this software for any 6.\" purpose with or without fee is hereby granted, provided that the above 7.\" copyright notice and this permission notice appear in all copies. 8.\" 9.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16.\" 17.Dd $Mdocdate: June 30 2025 $ 18.Dt MANDOCD 8 19.Os 20.Sh NAME 21.Nm mandocd 22.Nd server process to format manual pages in batch mode 23.Sh SYNOPSIS 24.Nm mandocd 25.Op Fl I Cm os Ns = Ns Ar name 26.Op Fl T Ar output 27.Ar socket_fd 28.Sh DESCRIPTION 29The 30.Nm 31utility formats many manual pages without requiring 32.Xr fork 2 33and 34.Xr exec 3 35overhead in between. 36It does not require listing all the manuals to be formatted on the 37command line, and it supports writing each formatted manual to its 38own file descriptor. 39.Pp 40This server requires that a connected UNIX domain 41.Xr socket 2 42is already present at 43.Xr exec 3 44time. 45Consequently, it cannot be started from the 46.Xr sh 1 47command line because the shell cannot supply such a socket. 48Typically, the socket is created by the parent process using 49.Xr socketpair 2 50before calling 51.Xr fork 2 52and 53.Xr exec 3 54on 55.Nm . 56The parent process will pass the file descriptor number as an argument to 57.Xr exec 3 , 58formatted as a decimal ASCII-encoded integer. 59See 60.Xr catman 8 61for a typical implementation of a parent process. 62.Pp 63.Nm 64loops reading one-byte messages with 65.Xr recvmsg 2 66from the file descriptor number 67.Ar socket_fd . 68It ignores the byte read and only uses the out-of-band auxiliary 69.Vt struct cmsghdr 70control data, typically supplied by the calling process using 71.Xr CMSG_FIRSTHDR 3 . 72The parent process is expected to pass three file descriptors 73with each dummy byte. 74The first one is used for 75.Xr mdoc 7 76or 77.Xr man 7 78input, the second one for formatted output, and the third one 79for error output. 80.Pp 81After accepting each message, 82.Nm 83replies with a one-byte message of its own, 84such that the parent process can keep track of how many messages 85.Nm 86has already accepted and how many file descriptors 87consequently are still in flight, such that the parent process 88can limit the number of file descriptors in flight at any given time 89in order to prevent 90.Er EMFILE 91failure of 92.Xr sendmsg 2 . 93.Pp 94The options are as follows: 95.Bl -tag -width Ds 96.It Fl I Cm os Ns = Ns Ar name 97Override the default operating system 98.Ar name 99for the 100.Xr mdoc 7 101.Ic \&Os 102and for the 103.Xr man 7 104.Ic TH 105macro. 106.It Fl T Ar output 107Output format. 108The 109.Ar output 110argument can be 111.Cm ascii , 112.Cm utf8 , 113or 114.Cm html ; 115see 116.Xr mandoc 1 . 117In 118.Cm html 119output mode, the 120.Cm fragment 121output option is implied. 122Other output options are not supported. 123.El 124.Pp 125After exhausting one input file descriptor, all three file descriptors 126are closed before reading the next dummy byte and control message. 127.Pp 128When a zero-byte message or a misformatted message is read, when the 129.Ar socket_fd 130is closed by the parent process, 131or when an error occurs, 132.Nm 133exits. 134.Sh EXIT STATUS 135.Ex -std 136.Pp 137A zero-byte message or a closed 138.Ar socket_fd 139is considered success. 140Possible errors include: 141.Bl -bullet 142.It 143missing, invalid, or excessive 144.Xr exec 3 145arguments 146.It 147communication failure with the parent, for example failure in 148.Xr recvmsg 2 149or 150.Xr send 2 151.It 152missing or unexpected control data, in particular a 153.Fa cmsg_level 154in the 155.Vt struct cmsghdr 156that differs from 157.Dv SOL_SOCKET , 158a 159.Fa cmsg_type 160that differs from 161.Dv SCM_RIGHTS , 162or a 163.Fa cmsg_len 164that is not three times the size of an 165.Vt int 166.It 167invalid file descriptors passed in the 168.Xr CMSG_DATA 3 169.It 170resource exhaustion, in particular 171.Xr dup 2 172or 173.Xr malloc 3 174failure 175.El 176.Pp 177Except for memory exhaustion and similar system-level failures, 178parsing and formatting errors do not cause 179.Nm 180to return an error exit status. 181Even after severe parsing errors, 182.Nm 183will simply accept and process the next input file descriptor. 184.Sh SEE ALSO 185.Xr mandoc 1 , 186.Xr mandoc 3 , 187.Xr catman 8 188.Sh HISTORY 189The 190.Nm 191utility appeared in version 1.14.1 of the 192.Sy mandoc 193toolkit. 194.Sh AUTHORS 195.An -nosplit 196The concept was designed and implemented by 197.An Michael Stapelberg Aq Mt stapelberg@debian.org . 198The 199.Xr mandoc 3 200glue needed to make it a stand-alone process was added by 201.An Ingo Schwarze Aq Mt schwarze@openbsd.org . 202.Sh CAVEATS 203If the parsed manual pages contain 204.Xr roff 7 205.Pf . Ic so 206requests, 207.Nm 208needs to be started with the current working directory set to the 209root of the manual page tree. 210Avoid starting it in directories that contain secret files in any 211subdirectories, in particular if the user starting it has read 212access to these secret files. 213