[BACK]Return to mandocd.c CVS log [TXT][DIR] Up to [cvsweb.bsd.lv] / mandoc

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