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