1 /* $Id: mandocd.c,v 1.11 2019/03/03 13:02:11 schwarze Exp $ */
3 * Copyright (c) 2017 Michael Stapelberg <stapelberg@debian.org>
4 * Copyright (c) 2017, 2019 Ingo Schwarze <schwarze@openbsd.org>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 #include <sys/types.h>
25 #include <sys/socket.h>
41 #include "mandoc_parse.h"
51 static void process(struct mparse *, enum outt, void *);
52 static int read_fds(int, int *);
53 static void usage(void) __attribute__((__noreturn__));
58 read_fds(int clientfd, int *fds)
62 unsigned char dummy[1];
67 /* Union used for alignment. */
69 uint8_t controlbuf[CMSG_SPACE(NUM_FDS * sizeof(int))];
73 memset(&msg, '\0', sizeof(msg));
74 msg.msg_control = u.controlbuf;
75 msg.msg_controllen = sizeof(u.controlbuf);
78 * Read a dummy byte - sendmsg cannot send an empty message,
79 * even if we are only interested in the OOB data.
82 iov[0].iov_base = dummy;
83 iov[0].iov_len = sizeof(dummy);
87 switch (recvmsg(clientfd, &msg, 0)) {
97 if ((cmsg = CMSG_FIRSTHDR(&msg)) == NULL) {
98 warnx("CMSG_FIRSTHDR: missing control message");
102 if (cmsg->cmsg_level != SOL_SOCKET ||
103 cmsg->cmsg_type != SCM_RIGHTS ||
104 cmsg->cmsg_len != CMSG_LEN(NUM_FDS * sizeof(int))) {
105 warnx("CMSG_FIRSTHDR: invalid control message");
109 walk = (int *)CMSG_DATA(cmsg);
110 for (cnt = 0; cnt < NUM_FDS; cnt++)
117 main(int argc, char *argv[])
119 struct manoutput options;
120 struct mparse *parser;
133 outtype = OUTT_ASCII;
134 while ((opt = getopt(argc, argv, "I:T:")) != -1) {
137 if (strncmp(optarg, "os=", 3) == 0)
140 warnx("-I %s: Bad argument", optarg);
145 if (strcmp(optarg, "ascii") == 0)
146 outtype = OUTT_ASCII;
147 else if (strcmp(optarg, "utf8") == 0)
149 else if (strcmp(optarg, "html") == 0)
152 warnx("-T %s: Bad argument", optarg);
169 clientfd = strtonum(argv[0], 3, INT_MAX, &errstr);
171 errx(1, "file descriptor %s %s", argv[1], errstr);
174 parser = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1 |
175 MPARSE_VALIDATE, MANDOC_OS_OTHER, defos);
177 memset(&options, 0, sizeof(options));
180 formatter = ascii_alloc(&options);
183 formatter = utf8_alloc(&options);
186 options.fragment = 1;
187 formatter = html_alloc(&options);
191 state = 1; /* work to do */
194 if ((old_stdin = dup(STDIN_FILENO)) == -1 ||
195 (old_stdout = dup(STDOUT_FILENO)) == -1 ||
196 (old_stderr = dup(STDERR_FILENO)) == -1) {
198 state = -1; /* error */
201 while (state == 1 && (state = read_fds(clientfd, fds)) == 1) {
202 if (dup2(fds[0], STDIN_FILENO) == -1 ||
203 dup2(fds[1], STDOUT_FILENO) == -1 ||
204 dup2(fds[2], STDERR_FILENO) == -1) {
214 process(parser, outtype, formatter);
215 mparse_reset(parser);
216 if (outtype == OUTT_HTML)
217 html_reset(formatter);
221 /* Close file descriptors by restoring the old ones. */
222 if (dup2(old_stderr, STDERR_FILENO) == -1 ||
223 dup2(old_stdout, STDOUT_FILENO) == -1 ||
224 dup2(old_stdin, STDIN_FILENO) == -1) {
235 ascii_free(formatter);
238 html_free(formatter);
243 return state == -1 ? 1 : 0;
247 process(struct mparse *parser, enum outt outtype, void *formatter)
249 struct roff_meta *meta;
251 mparse_readfd(parser, STDIN_FILENO, "<unixfd>");
252 meta = mparse_result(parser);
253 if (meta->macroset == MACROSET_MDOC) {
257 terminal_mdoc(formatter, meta);
260 html_mdoc(formatter, meta);
264 if (meta->macroset == MACROSET_MAN) {
268 terminal_man(formatter, meta);
271 html_man(formatter, meta);
280 fprintf(stderr, "usage: mandocd [-I os=name] [-T output] socket_fd\n");