]>
git.cameronkatri.com Git - mandoc.git/blob - catman.c
1 /* $Id: catman.c,v 1.15 2017/02/08 14:50:53 schwarze Exp $ */
3 * Copyright (c) 2017 Michael Stapelberg <stapelberg@debian.org>
4 * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
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.
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.
20 #include <sys/types.h>
21 #include <sys/socket.h>
32 #include "compat_fts.h"
40 int process_manpage(int, int, const char *);
41 int process_tree(int, int);
42 void run_mandocd(int, const char *, const char *)
43 __attribute__((noreturn
));
44 ssize_t
sock_fd_write(int, int, int, int);
45 void usage(void) __attribute__((noreturn
));
49 run_mandocd(int sockfd
, const char *outtype
, const char* defos
)
53 if (snprintf(sockfdstr
, sizeof(sockfdstr
), "%d", sockfd
) == -1)
56 execlp("mandocd", "mandocd", "-T", outtype
, sockfdstr
, NULL
);
58 execlp("mandocd", "mandocd", "-T", outtype
,
59 "-I", defos
, sockfdstr
, NULL
);
64 sock_fd_write(int fd
, int fd0
, int fd1
, int fd2
)
66 const struct timespec timeout
= { 0, 10000000 }; /* 0.01 s */
70 struct cmsghdr cmsghdr
;
71 char control
[CMSG_SPACE(3 * sizeof(int))];
76 unsigned char dummy
[1] = {'\0'};
79 iov
.iov_len
= sizeof(dummy
);
86 msg
.msg_control
= cmsgu
.control
;
87 msg
.msg_controllen
= sizeof(cmsgu
.control
);
89 cmsg
= CMSG_FIRSTHDR(&msg
);
90 cmsg
->cmsg_len
= CMSG_LEN(3 * sizeof(int));
91 cmsg
->cmsg_level
= SOL_SOCKET
;
92 cmsg
->cmsg_type
= SCM_RIGHTS
;
94 walk
= (int *)CMSG_DATA(cmsg
);
100 * It appears that on some systems, sendmsg(3)
101 * may return EAGAIN even in blocking mode.
102 * Seen for example on Oracle Solaris 11.2.
103 * The sleeping time was chosen by experimentation,
104 * to neither cause more than a handful of retries
105 * in normal operation nor unnecessary delays.
108 if ((sz
= sendmsg(fd
, &msg
, 0)) != -1 ||
111 nanosleep(&timeout
, NULL
);
117 process_manpage(int srv_fd
, int dstdir_fd
, const char *path
)
122 if ((in_fd
= open(path
, O_RDONLY
)) == -1) {
123 warn("open(%s)", path
);
127 if ((out_fd
= openat(dstdir_fd
, path
,
128 O_WRONLY
| O_NOFOLLOW
| O_CREAT
| O_TRUNC
,
129 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
)) == -1) {
130 warn("openat(%s)", path
);
135 irc
= sock_fd_write(srv_fd
, in_fd
, out_fd
, STDERR_FILENO
);
148 process_tree(int srv_fd
, int dstdir_fd
)
156 argv
[1] = (char *)NULL
;
158 if ((ftsp
= fts_open((char * const *)argv
,
159 FTS_PHYSICAL
| FTS_NOCHDIR
, NULL
)) == NULL
) {
164 while ((entry
= fts_read(ftsp
)) != NULL
) {
165 path
= entry
->fts_path
+ 2;
166 switch (entry
->fts_info
) {
168 if (process_manpage(srv_fd
, dstdir_fd
, path
) == -1) {
175 mkdirat(dstdir_fd
, path
, S_IRWXU
| S_IRGRP
|
176 S_IXGRP
| S_IROTH
| S_IXOTH
) == -1 &&
178 warn("mkdirat(%s)", path
);
179 (void)fts_set(ftsp
, entry
, FTS_SKIP
);
185 warnx("%s: not a regular file", path
);
195 main(int argc
, char **argv
)
197 const char *defos
, *outtype
;
205 while ((opt
= getopt(argc
, argv
, "I:T:")) != -1) {
225 if (socketpair(AF_LOCAL
, SOCK_STREAM
, AF_UNSPEC
, srv_fds
) == -1)
226 err(1, "socketpair");
234 run_mandocd(srv_fds
[1], outtype
, defos
);
240 if ((dstdir_fd
= open(argv
[1], O_RDONLY
| O_DIRECTORY
)) == -1)
241 err(1, "open(%s)", argv
[1]);
243 if (chdir(argv
[0]) == -1)
244 err(1, "chdir(%s)", argv
[0]);
246 return process_tree(srv_fds
[0], dstdir_fd
) == -1 ? 1 : 0;
252 fprintf(stderr
, "usage: catman [-I os=name] [-T output] "