Annotation of mandoc/catman.c, Revision 1.14
1.14 ! schwarze 1: /* $Id: catman.c,v 1.13 2017/02/04 12:03:07 schwarze Exp $ */
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.14 ! schwarze 27: #include <errno.h>
1.1 kristaps 28: #include <fcntl.h>
1.13 schwarze 29: #if HAVE_FTS
30: #include <fts.h>
31: #else
32: #include "compat_fts.h"
33: #endif
1.1 kristaps 34: #include <stdio.h>
35: #include <stdlib.h>
36: #include <string.h>
37: #include <unistd.h>
38:
1.13 schwarze 39: int process_manpage(int, int, const char *);
40: int process_tree(int, int);
1.14 ! schwarze 41: void run_mandocd(int, const char *, const char *)
! 42: __attribute__((noreturn));
1.13 schwarze 43: ssize_t sock_fd_write(int, int, int, int);
44: void usage(void) __attribute__((noreturn));
45:
46:
47: void
1.14 ! schwarze 48: run_mandocd(int sockfd, const char *outtype, const char* defos)
1.13 schwarze 49: {
50: char sockfdstr[10];
51:
52: if (snprintf(sockfdstr, sizeof(sockfdstr), "%d", sockfd) == -1)
53: err(1, "snprintf");
1.14 ! schwarze 54: if (defos == NULL)
! 55: execlp("mandocd", "mandocd", "-T", outtype, sockfdstr, NULL);
! 56: else
! 57: execlp("mandocd", "mandocd", "-T", outtype,
! 58: "-I", defos, sockfdstr, NULL);
1.13 schwarze 59: err(1, "exec");
60: }
61:
62: ssize_t
63: sock_fd_write(int fd, int fd0, int fd1, int fd2)
64: {
65: struct msghdr msg;
66: struct iovec iov;
67: union {
68: struct cmsghdr cmsghdr;
69: char control[CMSG_SPACE(3 * sizeof(int))];
70: } cmsgu;
71: struct cmsghdr *cmsg;
72: int *walk;
73: unsigned char dummy[1] = {'\0'};
74:
75: iov.iov_base = dummy;
76: iov.iov_len = sizeof(dummy);
77:
78: msg.msg_name = NULL;
79: msg.msg_namelen = 0;
80: msg.msg_iov = &iov;
81: msg.msg_iovlen = 1;
82:
83: msg.msg_control = cmsgu.control;
84: msg.msg_controllen = sizeof(cmsgu.control);
85:
86: cmsg = CMSG_FIRSTHDR(&msg);
87: cmsg->cmsg_len = CMSG_LEN(3 * sizeof(int));
88: cmsg->cmsg_level = SOL_SOCKET;
89: cmsg->cmsg_type = SCM_RIGHTS;
90:
91: walk = (int *)CMSG_DATA(cmsg);
92: *(walk++) = fd0;
93: *(walk++) = fd1;
94: *(walk++) = fd2;
1.1 kristaps 95:
1.13 schwarze 96: return sendmsg(fd, &msg, 0);
97: }
1.1 kristaps 98:
99: int
1.13 schwarze 100: process_manpage(int srv_fd, int dstdir_fd, const char *path)
1.1 kristaps 101: {
1.13 schwarze 102: int in_fd, out_fd;
1.14 ! schwarze 103: int irc;
1.1 kristaps 104:
1.13 schwarze 105: if ((in_fd = open(path, O_RDONLY)) == -1) {
106: warn("open(%s)", path);
1.14 ! schwarze 107: return 0;
1.13 schwarze 108: }
1.1 kristaps 109:
1.13 schwarze 110: if ((out_fd = openat(dstdir_fd, path,
111: O_WRONLY | O_NOFOLLOW | O_CREAT | O_TRUNC,
1.14 ! schwarze 112: S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1) {
1.13 schwarze 113: warn("openat(%s)", path);
114: close(in_fd);
1.14 ! schwarze 115: return 0;
1.1 kristaps 116: }
117:
1.14 ! schwarze 118: irc = sock_fd_write(srv_fd, in_fd, out_fd, STDERR_FILENO);
! 119:
! 120: close(in_fd);
! 121: close(out_fd);
! 122:
! 123: if (irc < 0) {
1.13 schwarze 124: warn("sendmsg");
125: return -1;
126: }
127: return 0;
1.1 kristaps 128: }
129:
1.13 schwarze 130: int
131: process_tree(int srv_fd, int dstdir_fd)
1.1 kristaps 132: {
1.13 schwarze 133: FTS *ftsp;
134: FTSENT *entry;
135: const char *argv[2];
136: const char *path;
1.1 kristaps 137:
1.13 schwarze 138: argv[0] = ".";
139: argv[1] = (char *)NULL;
1.1 kristaps 140:
1.13 schwarze 141: if ((ftsp = fts_open((char * const *)argv,
142: FTS_PHYSICAL | FTS_NOCHDIR, NULL)) == NULL) {
143: warn("fts_open");
144: return -1;
145: }
146:
147: while ((entry = fts_read(ftsp)) != NULL) {
148: path = entry->fts_path + 2;
149: switch (entry->fts_info) {
150: case FTS_F:
1.14 ! schwarze 151: if (process_manpage(srv_fd, dstdir_fd, path) == -1) {
! 152: fts_close(ftsp);
! 153: return -1;
! 154: }
1.13 schwarze 155: break;
156: case FTS_D:
1.14 ! schwarze 157: if (*path != '\0' &&
! 158: mkdirat(dstdir_fd, path, S_IRWXU | S_IRGRP |
! 159: S_IXGRP | S_IROTH | S_IXOTH) == -1 &&
! 160: errno != EEXIST) {
! 161: warn("mkdirat(%s)", path);
! 162: (void)fts_set(ftsp, entry, FTS_SKIP);
! 163: }
! 164: break;
1.13 schwarze 165: case FTS_DP:
166: break;
167: default:
168: warnx("%s: not a regular file", path);
169: break;
1.1 kristaps 170: }
1.13 schwarze 171: }
1.1 kristaps 172:
1.13 schwarze 173: fts_close(ftsp);
174: return 0;
1.1 kristaps 175: }
176:
1.13 schwarze 177: int
178: main(int argc, char **argv)
1.1 kristaps 179: {
1.14 ! schwarze 180: const char *defos, *outtype;
1.13 schwarze 181: int srv_fds[2];
182: int dstdir_fd;
183: int opt;
1.1 kristaps 184: pid_t pid;
185:
1.14 ! schwarze 186: defos = NULL;
1.13 schwarze 187: outtype = "ascii";
1.14 ! schwarze 188: while ((opt = getopt(argc, argv, "I:T:")) != -1) {
1.13 schwarze 189: switch (opt) {
1.14 ! schwarze 190: case 'I':
! 191: defos = optarg;
! 192: break;
1.13 schwarze 193: case 'T':
194: outtype = optarg;
1.1 kristaps 195: break;
1.13 schwarze 196: default:
197: usage();
1.1 kristaps 198: }
1.13 schwarze 199: }
1.1 kristaps 200:
1.13 schwarze 201: if (argc > 0) {
202: argc -= optind;
203: argv += optind;
1.1 kristaps 204: }
1.13 schwarze 205: if (argc != 2)
206: usage();
1.1 kristaps 207:
1.13 schwarze 208: if (socketpair(AF_LOCAL, SOCK_STREAM, AF_UNSPEC, srv_fds) == -1)
209: err(1, "socketpair");
1.1 kristaps 210:
1.13 schwarze 211: pid = fork();
212: switch (pid) {
213: case -1:
214: err(1, "fork");
215: case 0:
216: close(srv_fds[0]);
1.14 ! schwarze 217: run_mandocd(srv_fds[1], outtype, defos);
1.13 schwarze 218: default:
219: break;
1.1 kristaps 220: }
1.13 schwarze 221: close(srv_fds[1]);
1.1 kristaps 222:
1.13 schwarze 223: if ((dstdir_fd = open(argv[1], O_RDONLY | O_DIRECTORY)) == -1)
224: err(1, "open(%s)", argv[1]);
1.1 kristaps 225:
1.13 schwarze 226: if (chdir(argv[0]) == -1)
227: err(1, "chdir(%s)", argv[0]);
1.1 kristaps 228:
1.13 schwarze 229: return process_tree(srv_fds[0], dstdir_fd) == -1 ? 1 : 0;
1.1 kristaps 230: }
231:
1.13 schwarze 232: void
233: usage(void)
1.1 kristaps 234: {
1.14 ! schwarze 235: fprintf(stderr, "usage: catman [-I os=name] [-T output] "
! 236: "srcdir dstdir\n");
1.13 schwarze 237: exit(1);
1.1 kristaps 238: }
CVSweb