]> git.cameronkatri.com Git - mandoc.git/blobdiff - catman.c
more details about Mac OS X; information from Sevan Janiyan
[mandoc.git] / catman.c
index 4574a6e4a89cb2492ebfd3c0204427ed6444d73b..b1bab0f68c4b90e68f9f58bbf7cff465040217b0 100644 (file)
--- a/catman.c
+++ b/catman.c
@@ -1,4 +1,4 @@
-/*     $Id: catman.c,v 1.13 2017/02/04 12:03:07 schwarze Exp $ */
+/*     $Id: catman.c,v 1.22 2020/06/14 23:40:31 schwarze Exp $ */
 /*
  * Copyright (c) 2017 Michael Stapelberg <stapelberg@debian.org>
  * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
  */
 #include "config.h"
 
+#if NEED_XPG4_2
+#define _XPG4_2
+#endif
+
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
@@ -24,6 +28,7 @@
 #if HAVE_ERR
 #include <err.h>
 #endif
+#include <errno.h>
 #include <fcntl.h>
 #if HAVE_FTS
 #include <fts.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <time.h>
 #include <unistd.h>
 
 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    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 +77,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 +101,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 +170,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 +199,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 +236,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 +254,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);
 }