=================================================================== RCS file: /cvs/mandoc/catman.c,v retrieving revision 1.13 retrieving revision 1.19 diff -u -p -r1.13 -r1.19 --- mandoc/catman.c 2017/02/04 12:03:07 1.13 +++ mandoc/catman.c 2017/02/16 15:12:32 1.19 @@ -1,4 +1,4 @@ -/* $Id: catman.c,v 1.13 2017/02/04 12:03:07 schwarze Exp $ */ +/* $Id: catman.c,v 1.19 2017/02/16 15:12:32 schwarze Exp $ */ /* * Copyright (c) 2017 Michael Stapelberg * Copyright (c) 2017 Ingo Schwarze @@ -17,6 +17,10 @@ */ #include "config.h" +#if HAVE_CMSG_XPG42 +#define _XPG4_2 +#endif + #include #include #include @@ -24,6 +28,7 @@ #if HAVE_ERR #include #endif +#include #include #if HAVE_FTS #include @@ -33,29 +38,41 @@ #include #include #include +#include #include +#ifndef O_DIRECTORY +#define O_DIRECTORY 0 +#endif + int process_manpage(int, int, const char *); 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); void usage(void) __attribute__((noreturn)); void -run_mandocd(int sockfd, const char *outtype) +run_mandocd(int sockfd, const char *outtype, const char* defos) { char sockfdstr[10]; if (snprintf(sockfdstr, sizeof(sockfdstr), "%d", sockfd) == -1) err(1, "snprintf"); - execlp("mandocd", "mandocd", "-T", outtype, sockfdstr, NULL); + if (defos == NULL) + execlp("mandocd", "mandocd", "-T", outtype, + sockfdstr, (char *)NULL); + else + execlp("mandocd", "mandocd", "-T", outtype, + "-I", defos, sockfdstr, (char *)NULL); err(1, "exec"); } ssize_t sock_fd_write(int fd, int fd0, int fd1, int fd2) { + const struct timespec timeout = { 0, 10000000 }; /* 0.01 s */ struct msghdr msg; struct iovec iov; union { @@ -64,6 +81,7 @@ sock_fd_write(int fd, int fd0, int fd1, int fd2) } cmsgu; struct cmsghdr *cmsg; int *walk; + ssize_t sz; unsigned char dummy[1] = {'\0'}; iov.iov_base = dummy; @@ -87,34 +105,51 @@ sock_fd_write(int fd, int fd0, int fd1, int fd2) *(walk++) = fd1; *(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 process_manpage(int srv_fd, int dstdir_fd, const char *path) { int in_fd, out_fd; + int irc; if ((in_fd = open(path, O_RDONLY)) == -1) { warn("open(%s)", path); - return -1; + return 0; } if ((out_fd = openat(dstdir_fd, path, 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); close(in_fd); - return -1; + return 0; } - if (sock_fd_write(srv_fd, in_fd, out_fd, STDERR_FILENO) < 0) { - warn("sendmsg"); - return -1; - } + irc = sock_fd_write(srv_fd, in_fd, out_fd, STDERR_FILENO); close(in_fd); close(out_fd); + + if (irc < 0) { + warn("sendmsg"); + return -1; + } return 0; } @@ -139,9 +174,20 @@ process_tree(int srv_fd, int dstdir_fd) path = entry->fts_path + 2; switch (entry->fts_info) { 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; 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: break; default: @@ -157,15 +203,19 @@ process_tree(int srv_fd, int dstdir_fd) int main(int argc, char **argv) { - const char *outtype; + const char *defos, *outtype; int srv_fds[2]; int dstdir_fd; int opt; pid_t pid; + defos = NULL; outtype = "ascii"; - while ((opt = getopt(argc, argv, "T:")) != -1) { + while ((opt = getopt(argc, argv, "I:T:")) != -1) { switch (opt) { + case 'I': + defos = optarg; + break; case 'T': outtype = optarg; break; @@ -190,7 +240,7 @@ main(int argc, char **argv) err(1, "fork"); case 0: close(srv_fds[0]); - run_mandocd(srv_fds[1], outtype); + run_mandocd(srv_fds[1], outtype, defos); default: break; } @@ -208,6 +258,7 @@ main(int argc, char **argv) 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); }