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