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

Annotation of mandoc/mandocd.c, Revision 1.13

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

CVSweb