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