=================================================================== RCS file: /cvs/mandoc/catman.c,v retrieving revision 1.23 retrieving revision 1.26 diff -u -p -r1.23 -r1.26 --- mandoc/catman.c 2021/10/15 15:04:02 1.23 +++ mandoc/catman.c 2025/06/29 23:51:40 1.26 @@ -1,7 +1,7 @@ -/* $Id: catman.c,v 1.23 2021/10/15 15:04:02 schwarze Exp $ */ +/* $Id: catman.c,v 1.26 2025/06/29 23:51:40 schwarze Exp $ */ /* + * Copyright (c) 2017, 2025 Ingo Schwarze * Copyright (c) 2017 Michael Stapelberg - * Copyright (c) 2017 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -41,6 +41,8 @@ #include #include +int verbose_flag = 0; + int process_manpage(int, int, const char *); int process_tree(int, int); void run_mandocd(int, const char *, const char *) @@ -53,8 +55,14 @@ void run_mandocd(int sockfd, const char *outtype, const char* defos) { char sockfdstr[10]; + int len; - if (snprintf(sockfdstr, sizeof(sockfdstr), "%d", sockfd) == -1) + len = snprintf(sockfdstr, sizeof(sockfdstr), "%d", sockfd); + if (len >= (int)sizeof(sockfdstr)) { + errno = EOVERFLOW; + len = -1; + } + if (len < 0) err(1, "snprintf"); if (defos == NULL) execlp("mandocd", "mandocd", "-T", outtype, @@ -109,10 +117,11 @@ sock_fd_write(int fd, int fd0, int fd1, int fd2) * 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) + while ((sz = sendmsg(fd, &msg, 0)) == -1) { + if (errno != EAGAIN) { + warn("FATAL: sendmsg"); break; + } nanosleep(&timeout, NULL); } return sz; @@ -125,14 +134,16 @@ process_manpage(int srv_fd, int dstdir_fd, const char int irc; if ((in_fd = open(path, O_RDONLY)) == -1) { - warn("open(%s)", path); + warn("open %s for reading", path); + fflush(stderr); return 0; } if ((out_fd = openat(dstdir_fd, path, O_WRONLY | O_NOFOLLOW | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1) { - warn("openat(%s)", path); + warn("openat %s for writing", path); + fflush(stderr); close(in_fd); return 0; } @@ -142,11 +153,7 @@ process_manpage(int srv_fd, int dstdir_fd, const char close(in_fd); close(out_fd); - if (irc < 0) { - warn("sendmsg"); - return -1; - } - return 0; + return irc; } int @@ -156,6 +163,8 @@ process_tree(int srv_fd, int dstdir_fd) FTSENT *entry; const char *argv[2]; const char *path; + int fatal; + int gooddirs, baddirs, goodfiles, badfiles; argv[0] = "."; argv[1] = (char *)NULL; @@ -166,13 +175,22 @@ process_tree(int srv_fd, int dstdir_fd) return -1; } - while ((entry = fts_read(ftsp)) != NULL) { + fatal = 0; + gooddirs = baddirs = goodfiles = badfiles = 0; + while (fatal == 0 && (entry = fts_read(ftsp)) != NULL) { path = entry->fts_path + 2; switch (entry->fts_info) { case FTS_F: - if (process_manpage(srv_fd, dstdir_fd, path) == -1) { - fts_close(ftsp); - return -1; + switch (process_manpage(srv_fd, dstdir_fd, path)) { + case -1: + fatal = errno; + break; + case 0: + badfiles++; + break; + default: + goodfiles++; + break; } break; case FTS_D: @@ -180,19 +198,57 @@ process_tree(int srv_fd, int dstdir_fd) mkdirat(dstdir_fd, path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1 && errno != EEXIST) { - warn("mkdirat(%s)", path); + warn("mkdirat %s", path); + fflush(stderr); (void)fts_set(ftsp, entry, FTS_SKIP); - } + baddirs++; + } else + gooddirs++; break; case FTS_DP: break; + case FTS_DNR: + warnx("directory %s unreadable: %s", + path, strerror(entry->fts_errno)); + fflush(stderr); + baddirs++; + break; + case FTS_DC: + warnx("directory %s causes cycle", path); + fflush(stderr); + baddirs++; + break; + case FTS_ERR: + case FTS_NS: + warnx("file %s: %s", + path, strerror(entry->fts_errno)); + fflush(stderr); + badfiles++; + break; default: - warnx("%s: not a regular file", path); + warnx("file %s: not a regular file", path); + fflush(stderr); + badfiles++; break; } } + if (fatal == 0 && (fatal = errno) != 0) + warn("FATAL: fts_read"); fts_close(ftsp); + if (verbose_flag) + warnx("processed %d files in %d directories", + goodfiles, gooddirs); + if (baddirs > 0) + warnx("skipped %d %s due to errors", baddirs, + baddirs == 1 ? "directory" : "directories"); + if (badfiles > 0) + warnx("skipped %d %s due to errors", badfiles, + badfiles == 1 ? "file" : "files"); + if (fatal != 0) { + warnx("processing aborted due to fatal error, " + "results are probably incomplete"); + } return 0; } @@ -207,7 +263,7 @@ main(int argc, char **argv) defos = NULL; outtype = "ascii"; - while ((opt = getopt(argc, argv, "I:T:")) != -1) { + while ((opt = getopt(argc, argv, "I:T:v")) != -1) { switch (opt) { case 'I': defos = optarg; @@ -215,6 +271,9 @@ main(int argc, char **argv) case 'T': outtype = optarg; break; + case 'v': + verbose_flag = 1; + break; default: usage(); } @@ -224,8 +283,20 @@ main(int argc, char **argv) argc -= optind; argv += optind; } - if (argc != 2) + if (argc != 2) { + switch (argc) { + case 0: + warnx("missing arguments: srcdir and dstdir"); + break; + case 1: + warnx("missing argument: dstdir"); + break; + default: + warnx("too many arguments: %s", argv[2]); + break; + } usage(); + } if (socketpair(AF_LOCAL, SOCK_STREAM, AF_UNSPEC, srv_fds) == -1) err(1, "socketpair"); @@ -243,10 +314,10 @@ main(int argc, char **argv) close(srv_fds[1]); if ((dstdir_fd = open(argv[1], O_RDONLY | O_DIRECTORY)) == -1) - err(1, "open(%s)", argv[1]); + err(1, "open destination %s", argv[1]); if (chdir(argv[0]) == -1) - err(1, "chdir(%s)", argv[0]); + err(1, "chdir to source %s", argv[0]); return process_tree(srv_fds[0], dstdir_fd) == -1 ? 1 : 0; }