]>
git.cameronkatri.com Git - mandoc.git/blob - catman.c
1 /* $Id: catman.c,v 1.18 2017/02/09 20:53:33 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.
24 #include <sys/types.h>
25 #include <sys/socket.h>
36 #include "compat_fts.h"
48 int process_manpage(int, int, const char *);
49 int process_tree(int, int);
50 void run_mandocd(int, const char *, const char *)
51 __attribute__((noreturn
));
52 ssize_t
sock_fd_write(int, int, int, int);
53 void usage(void) __attribute__((noreturn
));
57 run_mandocd(int sockfd
, const char *outtype
, const char* defos
)
61 if (snprintf(sockfdstr
, sizeof(sockfdstr
), "%d", sockfd
) == -1)
64 execlp("mandocd", "mandocd", "-T", outtype
,
65 sockfdstr
, (char *)NULL
);
67 execlp("mandocd", "mandocd", "-T", outtype
,
68 "-I", defos
, sockfdstr
, (char *)NULL
);
73 sock_fd_write(int fd
, int fd0
, int fd1
, int fd2
)
75 const struct timespec timeout
= { 0, 10000000 }; /* 0.01 s */
79 struct cmsghdr cmsghdr
;
80 char control
[CMSG_SPACE(3 * sizeof(int))];
85 unsigned char dummy
[1] = {'\0'};
88 iov
.iov_len
= sizeof(dummy
);
95 msg
.msg_control
= cmsgu
.control
;
96 msg
.msg_controllen
= sizeof(cmsgu
.control
);
98 cmsg
= CMSG_FIRSTHDR(&msg
);
99 cmsg
->cmsg_len
= CMSG_LEN(3 * sizeof(int));
100 cmsg
->cmsg_level
= SOL_SOCKET
;
101 cmsg
->cmsg_type
= SCM_RIGHTS
;
103 walk
= (int *)CMSG_DATA(cmsg
);
109 * It appears that on some systems, sendmsg(3)
110 * may return EAGAIN even in blocking mode.
111 * Seen for example on Oracle Solaris 11.2.
112 * The sleeping time was chosen by experimentation,
113 * to neither cause more than a handful of retries
114 * in normal operation nor unnecessary delays.
117 if ((sz
= sendmsg(fd
, &msg
, 0)) != -1 ||
120 nanosleep(&timeout
, NULL
);
126 process_manpage(int srv_fd
, int dstdir_fd
, const char *path
)
131 if ((in_fd
= open(path
, O_RDONLY
)) == -1) {
132 warn("open(%s)", path
);
136 if ((out_fd
= openat(dstdir_fd
, path
,
137 O_WRONLY
| O_NOFOLLOW
| O_CREAT
| O_TRUNC
,
138 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
)) == -1) {
139 warn("openat(%s)", path
);
144 irc
= sock_fd_write(srv_fd
, in_fd
, out_fd
, STDERR_FILENO
);
157 process_tree(int srv_fd
, int dstdir_fd
)
165 argv
[1] = (char *)NULL
;
167 if ((ftsp
= fts_open((char * const *)argv
,
168 FTS_PHYSICAL
| FTS_NOCHDIR
, NULL
)) == NULL
) {
173 while ((entry
= fts_read(ftsp
)) != NULL
) {
174 path
= entry
->fts_path
+ 2;
175 switch (entry
->fts_info
) {
177 if (process_manpage(srv_fd
, dstdir_fd
, path
) == -1) {
184 mkdirat(dstdir_fd
, path
, S_IRWXU
| S_IRGRP
|
185 S_IXGRP
| S_IROTH
| S_IXOTH
) == -1 &&
187 warn("mkdirat(%s)", path
);
188 (void)fts_set(ftsp
, entry
, FTS_SKIP
);
194 warnx("%s: not a regular file", path
);
204 main(int argc
, char **argv
)
206 const char *defos
, *outtype
;
214 while ((opt
= getopt(argc
, argv
, "I:T:")) != -1) {
234 if (socketpair(AF_LOCAL
, SOCK_STREAM
, AF_UNSPEC
, srv_fds
) == -1)
235 err(1, "socketpair");
243 run_mandocd(srv_fds
[1], outtype
, defos
);
249 if ((dstdir_fd
= open(argv
[1], O_RDONLY
| O_DIRECTORY
)) == -1)
250 err(1, "open(%s)", argv
[1]);
252 if (chdir(argv
[0]) == -1)
253 err(1, "chdir(%s)", argv
[0]);
255 return process_tree(srv_fds
[0], dstdir_fd
) == -1 ? 1 : 0;
261 fprintf(stderr
, "usage: catman [-I os=name] [-T output] "