Annotation of mandoc/mandocd.c, Revision 1.11
1.11 ! schwarze 1: /* $Id: mandocd.c,v 1.10 2019/03/03 11:01:15 schwarze Exp $ */
1.1 schwarze 2: /*
3: * Copyright (c) 2017 Michael Stapelberg <stapelberg@debian.org>
1.11 ! schwarze 4: * Copyright (c) 2017, 2019 Ingo Schwarze <schwarze@openbsd.org>
1.1 schwarze 5: *
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.
9: *
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.
17: */
18: #include "config.h"
1.4 schwarze 19:
20: #if HAVE_CMSG_XPG42
21: #define _XPG4_2
22: #endif
1.1 schwarze 23:
24: #include <sys/types.h>
25: #include <sys/socket.h>
26:
27: #if HAVE_ERR
28: #include <err.h>
29: #endif
30: #include <limits.h>
1.2 schwarze 31: #include <stdint.h>
1.1 schwarze 32: #include <stdio.h>
33: #include <stdlib.h>
34: #include <string.h>
35: #include <unistd.h>
36:
37: #include "mandoc.h"
38: #include "roff.h"
39: #include "mdoc.h"
40: #include "man.h"
1.7 schwarze 41: #include "mandoc_parse.h"
1.1 schwarze 42: #include "main.h"
43: #include "manconf.h"
44:
45: enum outt {
46: OUTT_ASCII = 0,
47: OUTT_UTF8,
48: OUTT_HTML
49: };
50:
51: static void process(struct mparse *, enum outt, void *);
52: static int read_fds(int, int *);
1.5 schwarze 53: static void usage(void) __attribute__((__noreturn__));
1.1 schwarze 54:
55:
56: #define NUM_FDS 3
57: static int
58: read_fds(int clientfd, int *fds)
59: {
60: struct msghdr msg;
61: struct iovec iov[1];
62: unsigned char dummy[1];
63: struct cmsghdr *cmsg;
64: int *walk;
65: int cnt;
66:
67: /* Union used for alignment. */
68: union {
69: uint8_t controlbuf[CMSG_SPACE(NUM_FDS * sizeof(int))];
70: struct cmsghdr align;
71: } u;
72:
73: memset(&msg, '\0', sizeof(msg));
74: msg.msg_control = u.controlbuf;
75: msg.msg_controllen = sizeof(u.controlbuf);
76:
77: /*
78: * Read a dummy byte - sendmsg cannot send an empty message,
79: * even if we are only interested in the OOB data.
80: */
81:
82: iov[0].iov_base = dummy;
83: iov[0].iov_len = sizeof(dummy);
84: msg.msg_iov = iov;
85: msg.msg_iovlen = 1;
86:
87: switch (recvmsg(clientfd, &msg, 0)) {
88: case -1:
89: warn("recvmsg");
90: return -1;
91: case 0:
92: return 0;
93: default:
94: break;
95: }
96:
97: if ((cmsg = CMSG_FIRSTHDR(&msg)) == NULL) {
98: warnx("CMSG_FIRSTHDR: missing control message");
99: return -1;
100: }
101:
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");
106: return -1;
107: }
108:
109: walk = (int *)CMSG_DATA(cmsg);
110: for (cnt = 0; cnt < NUM_FDS; cnt++)
111: fds[cnt] = *walk++;
112:
113: return 1;
114: }
115:
116: int
117: main(int argc, char *argv[])
118: {
119: struct manoutput options;
120: struct mparse *parser;
121: void *formatter;
1.3 schwarze 122: const char *defos;
1.1 schwarze 123: const char *errstr;
124: int clientfd;
125: int old_stdin;
126: int old_stdout;
127: int old_stderr;
128: int fds[3];
129: int state, opt;
130: enum outt outtype;
131:
1.3 schwarze 132: defos = NULL;
1.1 schwarze 133: outtype = OUTT_ASCII;
1.3 schwarze 134: while ((opt = getopt(argc, argv, "I:T:")) != -1) {
1.1 schwarze 135: switch (opt) {
1.3 schwarze 136: case 'I':
137: if (strncmp(optarg, "os=", 3) == 0)
138: defos = optarg + 3;
139: else {
140: warnx("-I %s: Bad argument", optarg);
141: usage();
142: }
143: break;
1.1 schwarze 144: case 'T':
145: if (strcmp(optarg, "ascii") == 0)
146: outtype = OUTT_ASCII;
147: else if (strcmp(optarg, "utf8") == 0)
148: outtype = OUTT_UTF8;
149: else if (strcmp(optarg, "html") == 0)
150: outtype = OUTT_HTML;
151: else {
152: warnx("-T %s: Bad argument", optarg);
153: usage();
154: }
155: break;
156: default:
157: usage();
158: }
159: }
160:
161: if (argc > 0) {
162: argc -= optind;
163: argv += optind;
164: }
165: if (argc != 1)
166: usage();
167:
168: errstr = NULL;
169: clientfd = strtonum(argv[0], 3, INT_MAX, &errstr);
170: if (errstr)
171: errx(1, "file descriptor %s %s", argv[1], errstr);
172:
173: mchars_alloc();
1.10 schwarze 174: parser = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1 |
175: MPARSE_VALIDATE, MANDOC_OS_OTHER, defos);
1.1 schwarze 176:
177: memset(&options, 0, sizeof(options));
178: switch (outtype) {
179: case OUTT_ASCII:
180: formatter = ascii_alloc(&options);
181: break;
182: case OUTT_UTF8:
183: formatter = utf8_alloc(&options);
184: break;
185: case OUTT_HTML:
186: options.fragment = 1;
187: formatter = html_alloc(&options);
188: break;
189: }
190:
191: state = 1; /* work to do */
192: fflush(stdout);
193: fflush(stderr);
194: if ((old_stdin = dup(STDIN_FILENO)) == -1 ||
195: (old_stdout = dup(STDOUT_FILENO)) == -1 ||
196: (old_stderr = dup(STDERR_FILENO)) == -1) {
197: warn("dup");
198: state = -1; /* error */
199: }
200:
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) {
205: warn("dup2");
206: state = -1;
207: break;
208: }
209:
210: close(fds[0]);
211: close(fds[1]);
212: close(fds[2]);
213:
214: process(parser, outtype, formatter);
215: mparse_reset(parser);
1.11 ! schwarze 216: if (outtype == OUTT_HTML)
! 217: html_reset(formatter);
1.1 schwarze 218:
219: fflush(stdout);
220: fflush(stderr);
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) {
225: warn("dup2");
226: state = -1;
227: break;
228: }
229: }
230:
231: close(clientfd);
232: switch (outtype) {
233: case OUTT_ASCII:
234: case OUTT_UTF8:
235: ascii_free(formatter);
236: break;
237: case OUTT_HTML:
238: html_free(formatter);
239: break;
240: }
241: mparse_free(parser);
242: mchars_free();
243: return state == -1 ? 1 : 0;
244: }
245:
246: static void
247: process(struct mparse *parser, enum outt outtype, void *formatter)
248: {
1.9 schwarze 249: struct roff_meta *meta;
1.1 schwarze 250:
251: mparse_readfd(parser, STDIN_FILENO, "<unixfd>");
1.9 schwarze 252: meta = mparse_result(parser);
253: if (meta->macroset == MACROSET_MDOC) {
1.1 schwarze 254: switch (outtype) {
255: case OUTT_ASCII:
256: case OUTT_UTF8:
1.9 schwarze 257: terminal_mdoc(formatter, meta);
1.1 schwarze 258: break;
259: case OUTT_HTML:
1.9 schwarze 260: html_mdoc(formatter, meta);
1.1 schwarze 261: break;
262: }
263: }
1.9 schwarze 264: if (meta->macroset == MACROSET_MAN) {
1.1 schwarze 265: switch (outtype) {
266: case OUTT_ASCII:
267: case OUTT_UTF8:
1.9 schwarze 268: terminal_man(formatter, meta);
1.1 schwarze 269: break;
270: case OUTT_HTML:
1.9 schwarze 271: html_man(formatter, meta);
1.1 schwarze 272: break;
273: }
274: }
275: }
276:
277: void
278: usage(void)
279: {
1.3 schwarze 280: fprintf(stderr, "usage: mandocd [-I os=name] [-T output] socket_fd\n");
1.1 schwarze 281: exit(1);
282: }
CVSweb