Annotation of mandoc/mandocd.c, Revision 1.3
1.3 ! schwarze 1: /* $Id: mandocd.c,v 1.2 2017/02/05 22:51:11 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;
1.3 ! schwarze 117: const char *defos;
1.1 schwarze 118: const char *errstr;
119: int clientfd;
120: int old_stdin;
121: int old_stdout;
122: int old_stderr;
123: int fds[3];
124: int state, opt;
125: enum outt outtype;
126:
1.3 ! schwarze 127: defos = NULL;
1.1 schwarze 128: outtype = OUTT_ASCII;
1.3 ! schwarze 129: while ((opt = getopt(argc, argv, "I:T:")) != -1) {
1.1 schwarze 130: switch (opt) {
1.3 ! schwarze 131: case 'I':
! 132: if (strncmp(optarg, "os=", 3) == 0)
! 133: defos = optarg + 3;
! 134: else {
! 135: warnx("-I %s: Bad argument", optarg);
! 136: usage();
! 137: }
! 138: break;
1.1 schwarze 139: case 'T':
140: if (strcmp(optarg, "ascii") == 0)
141: outtype = OUTT_ASCII;
142: else if (strcmp(optarg, "utf8") == 0)
143: outtype = OUTT_UTF8;
144: else if (strcmp(optarg, "html") == 0)
145: outtype = OUTT_HTML;
146: else {
147: warnx("-T %s: Bad argument", optarg);
148: usage();
149: }
150: break;
151: default:
152: usage();
153: }
154: }
155:
156: if (argc > 0) {
157: argc -= optind;
158: argv += optind;
159: }
160: if (argc != 1)
161: usage();
162:
163: errstr = NULL;
164: clientfd = strtonum(argv[0], 3, INT_MAX, &errstr);
165: if (errstr)
166: errx(1, "file descriptor %s %s", argv[1], errstr);
167:
168: mchars_alloc();
169: parser = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1,
1.3 ! schwarze 170: MANDOCLEVEL_BADARG, NULL, defos);
1.1 schwarze 171:
172: memset(&options, 0, sizeof(options));
173: switch (outtype) {
174: case OUTT_ASCII:
175: formatter = ascii_alloc(&options);
176: break;
177: case OUTT_UTF8:
178: formatter = utf8_alloc(&options);
179: break;
180: case OUTT_HTML:
181: options.fragment = 1;
182: formatter = html_alloc(&options);
183: break;
184: }
185:
186: state = 1; /* work to do */
187: fflush(stdout);
188: fflush(stderr);
189: if ((old_stdin = dup(STDIN_FILENO)) == -1 ||
190: (old_stdout = dup(STDOUT_FILENO)) == -1 ||
191: (old_stderr = dup(STDERR_FILENO)) == -1) {
192: warn("dup");
193: state = -1; /* error */
194: }
195:
196: while (state == 1 && (state = read_fds(clientfd, fds)) == 1) {
197: if (dup2(fds[0], STDIN_FILENO) == -1 ||
198: dup2(fds[1], STDOUT_FILENO) == -1 ||
199: dup2(fds[2], STDERR_FILENO) == -1) {
200: warn("dup2");
201: state = -1;
202: break;
203: }
204:
205: close(fds[0]);
206: close(fds[1]);
207: close(fds[2]);
208:
209: process(parser, outtype, formatter);
210: mparse_reset(parser);
211:
212: fflush(stdout);
213: fflush(stderr);
214: /* Close file descriptors by restoring the old ones. */
215: if (dup2(old_stderr, STDERR_FILENO) == -1 ||
216: dup2(old_stdout, STDOUT_FILENO) == -1 ||
217: dup2(old_stdin, STDIN_FILENO) == -1) {
218: warn("dup2");
219: state = -1;
220: break;
221: }
222: }
223:
224: close(clientfd);
225: switch (outtype) {
226: case OUTT_ASCII:
227: case OUTT_UTF8:
228: ascii_free(formatter);
229: break;
230: case OUTT_HTML:
231: html_free(formatter);
232: break;
233: }
234: mparse_free(parser);
235: mchars_free();
236: return state == -1 ? 1 : 0;
237: }
238:
239: static void
240: process(struct mparse *parser, enum outt outtype, void *formatter)
241: {
242: struct roff_man *man;
243:
244: mparse_readfd(parser, STDIN_FILENO, "<unixfd>");
245: mparse_result(parser, &man, NULL);
246:
247: if (man == NULL)
248: return;
249:
250: if (man->macroset == MACROSET_MDOC) {
251: mdoc_validate(man);
252: switch (outtype) {
253: case OUTT_ASCII:
254: case OUTT_UTF8:
255: terminal_mdoc(formatter, man);
256: break;
257: case OUTT_HTML:
258: html_mdoc(formatter, man);
259: break;
260: }
261: }
262: if (man->macroset == MACROSET_MAN) {
263: man_validate(man);
264: switch (outtype) {
265: case OUTT_ASCII:
266: case OUTT_UTF8:
267: terminal_man(formatter, man);
268: break;
269: case OUTT_HTML:
270: html_man(formatter, man);
271: break;
272: }
273: }
274: }
275:
276: void
277: usage(void)
278: {
1.3 ! schwarze 279: fprintf(stderr, "usage: mandocd [-I os=name] [-T output] socket_fd\n");
1.1 schwarze 280: exit(1);
281: }
CVSweb