version 1.13, 2017/02/04 12:03:07 |
version 1.23, 2021/10/15 15:04:02 |
|
|
*/ |
*/ |
#include "config.h" |
#include "config.h" |
|
|
|
#if NEED_XPG4_2 |
|
#define _XPG4_2 |
|
#endif |
|
|
#include <sys/types.h> |
#include <sys/types.h> |
#include <sys/socket.h> |
#include <sys/socket.h> |
#include <sys/stat.h> |
#include <sys/stat.h> |
|
|
#if HAVE_ERR |
#if HAVE_ERR |
#include <err.h> |
#include <err.h> |
#endif |
#endif |
|
#include <errno.h> |
#include <fcntl.h> |
#include <fcntl.h> |
#if HAVE_FTS |
#if HAVE_FTS |
#include <fts.h> |
#include <fts.h> |
|
|
#include <stdio.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
|
#include <time.h> |
#include <unistd.h> |
#include <unistd.h> |
|
|
int process_manpage(int, int, const char *); |
int process_manpage(int, int, const char *); |
int process_tree(int, int); |
int process_tree(int, int); |
void run_mandocd(int, const char *) __attribute__((noreturn)); |
void run_mandocd(int, const char *, const char *) |
|
__attribute__((__noreturn__)); |
ssize_t sock_fd_write(int, int, int, int); |
ssize_t sock_fd_write(int, int, int, int); |
void usage(void) __attribute__((noreturn)); |
void usage(void) __attribute__((__noreturn__)); |
|
|
|
|
void |
void |
run_mandocd(int sockfd, const char *outtype) |
run_mandocd(int sockfd, const char *outtype, const char* defos) |
{ |
{ |
char sockfdstr[10]; |
char sockfdstr[10]; |
|
|
if (snprintf(sockfdstr, sizeof(sockfdstr), "%d", sockfd) == -1) |
if (snprintf(sockfdstr, sizeof(sockfdstr), "%d", sockfd) == -1) |
err(1, "snprintf"); |
err(1, "snprintf"); |
execlp("mandocd", "mandocd", "-T", outtype, sockfdstr, NULL); |
if (defos == NULL) |
err(1, "exec"); |
execlp("mandocd", "mandocd", "-T", outtype, |
|
sockfdstr, (char *)NULL); |
|
else |
|
execlp("mandocd", "mandocd", "-T", outtype, |
|
"-I", defos, sockfdstr, (char *)NULL); |
|
err(1, "exec(mandocd)"); |
} |
} |
|
|
ssize_t |
ssize_t |
sock_fd_write(int fd, int fd0, int fd1, int fd2) |
sock_fd_write(int fd, int fd0, int fd1, int fd2) |
{ |
{ |
|
const struct timespec timeout = { 0, 10000000 }; /* 0.01 s */ |
struct msghdr msg; |
struct msghdr msg; |
struct iovec iov; |
struct iovec iov; |
union { |
union { |
Line 64 sock_fd_write(int fd, int fd0, int fd1, int fd2) |
|
Line 77 sock_fd_write(int fd, int fd0, int fd1, int fd2) |
|
} cmsgu; |
} cmsgu; |
struct cmsghdr *cmsg; |
struct cmsghdr *cmsg; |
int *walk; |
int *walk; |
|
ssize_t sz; |
unsigned char dummy[1] = {'\0'}; |
unsigned char dummy[1] = {'\0'}; |
|
|
iov.iov_base = dummy; |
iov.iov_base = dummy; |
Line 87 sock_fd_write(int fd, int fd0, int fd1, int fd2) |
|
Line 101 sock_fd_write(int fd, int fd0, int fd1, int fd2) |
|
*(walk++) = fd1; |
*(walk++) = fd1; |
*(walk++) = fd2; |
*(walk++) = fd2; |
|
|
return sendmsg(fd, &msg, 0); |
/* |
|
* It appears that on some systems, sendmsg(3) |
|
* may return EAGAIN even in blocking mode. |
|
* Seen for example on Oracle Solaris 11.2. |
|
* The sleeping time was chosen by experimentation, |
|
* to neither cause more than a handful of retries |
|
* in normal operation nor unnecessary delays. |
|
*/ |
|
for (;;) { |
|
if ((sz = sendmsg(fd, &msg, 0)) != -1 || |
|
errno != EAGAIN) |
|
break; |
|
nanosleep(&timeout, NULL); |
|
} |
|
return sz; |
} |
} |
|
|
int |
int |
process_manpage(int srv_fd, int dstdir_fd, const char *path) |
process_manpage(int srv_fd, int dstdir_fd, const char *path) |
{ |
{ |
int in_fd, out_fd; |
int in_fd, out_fd; |
|
int irc; |
|
|
if ((in_fd = open(path, O_RDONLY)) == -1) { |
if ((in_fd = open(path, O_RDONLY)) == -1) { |
warn("open(%s)", path); |
warn("open(%s)", path); |
return -1; |
return 0; |
} |
} |
|
|
if ((out_fd = openat(dstdir_fd, path, |
if ((out_fd = openat(dstdir_fd, path, |
O_WRONLY | O_NOFOLLOW | O_CREAT | O_TRUNC, |
O_WRONLY | O_NOFOLLOW | O_CREAT | O_TRUNC, |
S_IRUSR | S_IWUSR | S_IRGRP | S_IRWXO)) == -1) { |
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1) { |
warn("openat(%s)", path); |
warn("openat(%s)", path); |
close(in_fd); |
close(in_fd); |
return -1; |
return 0; |
} |
} |
|
|
if (sock_fd_write(srv_fd, in_fd, out_fd, STDERR_FILENO) < 0) { |
irc = sock_fd_write(srv_fd, in_fd, out_fd, STDERR_FILENO); |
warn("sendmsg"); |
|
return -1; |
|
} |
|
|
|
close(in_fd); |
close(in_fd); |
close(out_fd); |
close(out_fd); |
|
|
|
if (irc < 0) { |
|
warn("sendmsg"); |
|
return -1; |
|
} |
return 0; |
return 0; |
} |
} |
|
|
Line 139 process_tree(int srv_fd, int dstdir_fd) |
|
Line 170 process_tree(int srv_fd, int dstdir_fd) |
|
path = entry->fts_path + 2; |
path = entry->fts_path + 2; |
switch (entry->fts_info) { |
switch (entry->fts_info) { |
case FTS_F: |
case FTS_F: |
process_manpage(srv_fd, dstdir_fd, path); |
if (process_manpage(srv_fd, dstdir_fd, path) == -1) { |
|
fts_close(ftsp); |
|
return -1; |
|
} |
break; |
break; |
case FTS_D: |
case FTS_D: |
|
if (*path != '\0' && |
|
mkdirat(dstdir_fd, path, S_IRWXU | S_IRGRP | |
|
S_IXGRP | S_IROTH | S_IXOTH) == -1 && |
|
errno != EEXIST) { |
|
warn("mkdirat(%s)", path); |
|
(void)fts_set(ftsp, entry, FTS_SKIP); |
|
} |
|
break; |
case FTS_DP: |
case FTS_DP: |
break; |
break; |
default: |
default: |
Line 157 process_tree(int srv_fd, int dstdir_fd) |
|
Line 199 process_tree(int srv_fd, int dstdir_fd) |
|
int |
int |
main(int argc, char **argv) |
main(int argc, char **argv) |
{ |
{ |
const char *outtype; |
const char *defos, *outtype; |
int srv_fds[2]; |
int srv_fds[2]; |
int dstdir_fd; |
int dstdir_fd; |
int opt; |
int opt; |
pid_t pid; |
pid_t pid; |
|
|
|
defos = NULL; |
outtype = "ascii"; |
outtype = "ascii"; |
while ((opt = getopt(argc, argv, "T:")) != -1) { |
while ((opt = getopt(argc, argv, "I:T:")) != -1) { |
switch (opt) { |
switch (opt) { |
|
case 'I': |
|
defos = optarg; |
|
break; |
case 'T': |
case 'T': |
outtype = optarg; |
outtype = optarg; |
break; |
break; |
Line 190 main(int argc, char **argv) |
|
Line 236 main(int argc, char **argv) |
|
err(1, "fork"); |
err(1, "fork"); |
case 0: |
case 0: |
close(srv_fds[0]); |
close(srv_fds[0]); |
run_mandocd(srv_fds[1], outtype); |
run_mandocd(srv_fds[1], outtype, defos); |
default: |
default: |
break; |
break; |
} |
} |
Line 208 main(int argc, char **argv) |
|
Line 254 main(int argc, char **argv) |
|
void |
void |
usage(void) |
usage(void) |
{ |
{ |
fprintf(stderr, "usage: catman [-T output] srcdir dstdir\n"); |
fprintf(stderr, "usage: %s [-I os=name] [-T output] " |
|
"srcdir dstdir\n", BINM_CATMAN); |
exit(1); |
exit(1); |
} |
} |