Annotation of mandoc/catman.c, Revision 1.13
1.13 ! schwarze 1: /* $Id$ */
1.1 kristaps 2: /*
1.13 ! schwarze 3: * Copyright (c) 2017 Michael Stapelberg <stapelberg@debian.org>
! 4: * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
1.1 kristaps 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: *
1.13 ! schwarze 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
1.1 kristaps 11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1.13 ! schwarze 12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
1.1 kristaps 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:
1.13 ! schwarze 20: #include <sys/types.h>
! 21: #include <sys/socket.h>
1.1 kristaps 22: #include <sys/stat.h>
23:
1.13 ! schwarze 24: #if HAVE_ERR
! 25: #include <err.h>
! 26: #endif
1.1 kristaps 27: #include <fcntl.h>
1.13 ! schwarze 28: #if HAVE_FTS
! 29: #include <fts.h>
! 30: #else
! 31: #include "compat_fts.h"
! 32: #endif
1.1 kristaps 33: #include <stdio.h>
34: #include <stdlib.h>
35: #include <string.h>
36: #include <unistd.h>
37:
1.13 ! schwarze 38: int process_manpage(int, int, const char *);
! 39: int process_tree(int, int);
! 40: void run_mandocd(int, const char *) __attribute__((noreturn));
! 41: ssize_t sock_fd_write(int, int, int, int);
! 42: void usage(void) __attribute__((noreturn));
! 43:
! 44:
! 45: void
! 46: run_mandocd(int sockfd, const char *outtype)
! 47: {
! 48: char sockfdstr[10];
! 49:
! 50: if (snprintf(sockfdstr, sizeof(sockfdstr), "%d", sockfd) == -1)
! 51: err(1, "snprintf");
! 52: execlp("mandocd", "mandocd", "-T", outtype, sockfdstr, NULL);
! 53: err(1, "exec");
! 54: }
! 55:
! 56: ssize_t
! 57: sock_fd_write(int fd, int fd0, int fd1, int fd2)
! 58: {
! 59: struct msghdr msg;
! 60: struct iovec iov;
! 61: union {
! 62: struct cmsghdr cmsghdr;
! 63: char control[CMSG_SPACE(3 * sizeof(int))];
! 64: } cmsgu;
! 65: struct cmsghdr *cmsg;
! 66: int *walk;
! 67: unsigned char dummy[1] = {'\0'};
! 68:
! 69: iov.iov_base = dummy;
! 70: iov.iov_len = sizeof(dummy);
! 71:
! 72: msg.msg_name = NULL;
! 73: msg.msg_namelen = 0;
! 74: msg.msg_iov = &iov;
! 75: msg.msg_iovlen = 1;
! 76:
! 77: msg.msg_control = cmsgu.control;
! 78: msg.msg_controllen = sizeof(cmsgu.control);
! 79:
! 80: cmsg = CMSG_FIRSTHDR(&msg);
! 81: cmsg->cmsg_len = CMSG_LEN(3 * sizeof(int));
! 82: cmsg->cmsg_level = SOL_SOCKET;
! 83: cmsg->cmsg_type = SCM_RIGHTS;
! 84:
! 85: walk = (int *)CMSG_DATA(cmsg);
! 86: *(walk++) = fd0;
! 87: *(walk++) = fd1;
! 88: *(walk++) = fd2;
1.1 kristaps 89:
1.13 ! schwarze 90: return sendmsg(fd, &msg, 0);
! 91: }
1.1 kristaps 92:
93: int
1.13 ! schwarze 94: process_manpage(int srv_fd, int dstdir_fd, const char *path)
1.1 kristaps 95: {
1.13 ! schwarze 96: int in_fd, out_fd;
1.1 kristaps 97:
1.13 ! schwarze 98: if ((in_fd = open(path, O_RDONLY)) == -1) {
! 99: warn("open(%s)", path);
! 100: return -1;
! 101: }
1.1 kristaps 102:
1.13 ! schwarze 103: if ((out_fd = openat(dstdir_fd, path,
! 104: O_WRONLY | O_NOFOLLOW | O_CREAT | O_TRUNC,
! 105: S_IRUSR | S_IWUSR | S_IRGRP | S_IRWXO)) == -1) {
! 106: warn("openat(%s)", path);
! 107: close(in_fd);
! 108: return -1;
1.1 kristaps 109: }
110:
1.13 ! schwarze 111: if (sock_fd_write(srv_fd, in_fd, out_fd, STDERR_FILENO) < 0) {
! 112: warn("sendmsg");
! 113: return -1;
! 114: }
1.1 kristaps 115:
1.13 ! schwarze 116: close(in_fd);
! 117: close(out_fd);
! 118: return 0;
1.1 kristaps 119: }
120:
1.13 ! schwarze 121: int
! 122: process_tree(int srv_fd, int dstdir_fd)
1.1 kristaps 123: {
1.13 ! schwarze 124: FTS *ftsp;
! 125: FTSENT *entry;
! 126: const char *argv[2];
! 127: const char *path;
1.1 kristaps 128:
1.13 ! schwarze 129: argv[0] = ".";
! 130: argv[1] = (char *)NULL;
1.1 kristaps 131:
1.13 ! schwarze 132: if ((ftsp = fts_open((char * const *)argv,
! 133: FTS_PHYSICAL | FTS_NOCHDIR, NULL)) == NULL) {
! 134: warn("fts_open");
! 135: return -1;
! 136: }
! 137:
! 138: while ((entry = fts_read(ftsp)) != NULL) {
! 139: path = entry->fts_path + 2;
! 140: switch (entry->fts_info) {
! 141: case FTS_F:
! 142: process_manpage(srv_fd, dstdir_fd, path);
! 143: break;
! 144: case FTS_D:
! 145: case FTS_DP:
! 146: break;
! 147: default:
! 148: warnx("%s: not a regular file", path);
! 149: break;
1.1 kristaps 150: }
1.13 ! schwarze 151: }
1.1 kristaps 152:
1.13 ! schwarze 153: fts_close(ftsp);
! 154: return 0;
1.1 kristaps 155: }
156:
1.13 ! schwarze 157: int
! 158: main(int argc, char **argv)
1.1 kristaps 159: {
1.13 ! schwarze 160: const char *outtype;
! 161: int srv_fds[2];
! 162: int dstdir_fd;
! 163: int opt;
1.1 kristaps 164: pid_t pid;
165:
1.13 ! schwarze 166: outtype = "ascii";
! 167: while ((opt = getopt(argc, argv, "T:")) != -1) {
! 168: switch (opt) {
! 169: case 'T':
! 170: outtype = optarg;
1.1 kristaps 171: break;
1.13 ! schwarze 172: default:
! 173: usage();
1.1 kristaps 174: }
1.13 ! schwarze 175: }
1.1 kristaps 176:
1.13 ! schwarze 177: if (argc > 0) {
! 178: argc -= optind;
! 179: argv += optind;
1.1 kristaps 180: }
1.13 ! schwarze 181: if (argc != 2)
! 182: usage();
1.1 kristaps 183:
1.13 ! schwarze 184: if (socketpair(AF_LOCAL, SOCK_STREAM, AF_UNSPEC, srv_fds) == -1)
! 185: err(1, "socketpair");
1.1 kristaps 186:
1.13 ! schwarze 187: pid = fork();
! 188: switch (pid) {
! 189: case -1:
! 190: err(1, "fork");
! 191: case 0:
! 192: close(srv_fds[0]);
! 193: run_mandocd(srv_fds[1], outtype);
! 194: default:
! 195: break;
1.1 kristaps 196: }
1.13 ! schwarze 197: close(srv_fds[1]);
1.1 kristaps 198:
1.13 ! schwarze 199: if ((dstdir_fd = open(argv[1], O_RDONLY | O_DIRECTORY)) == -1)
! 200: err(1, "open(%s)", argv[1]);
1.1 kristaps 201:
1.13 ! schwarze 202: if (chdir(argv[0]) == -1)
! 203: err(1, "chdir(%s)", argv[0]);
1.1 kristaps 204:
1.13 ! schwarze 205: return process_tree(srv_fds[0], dstdir_fd) == -1 ? 1 : 0;
1.1 kristaps 206: }
207:
1.13 ! schwarze 208: void
! 209: usage(void)
1.1 kristaps 210: {
1.13 ! schwarze 211: fprintf(stderr, "usage: catman [-T output] srcdir dstdir\n");
! 212: exit(1);
1.1 kristaps 213: }
CVSweb