* NEWS: Mention this.
* zic.c (verror, make_links, main, get_rand_u64)
(random_dirent, open_outfile, dolink, inputline, infile):
Be better about checking for signals, e.g., when the input or
the random number generator is giving is trouble, so that
it’s easier for the user to control-C out.
Although the result is not perfect it should be good
enough for practical use.
---
 NEWS  |  2 ++
 zic.c | 35 ++++++++++++++++++++++-------------
 2 files changed, 24 insertions(+), 13 deletions(-)

diff --git a/NEWS b/NEWS
index d4ba011b..fa791cb9 100644
--- a/NEWS
+++ b/NEWS
@@ -28,6 +28,8 @@ Unreleased, experimental changes
     which can occur with adversarial input.  (Thanks to GitHub
     user rootvector2.)
 
+    zic now checks for signals more often.
+
 
 Release 2026a - 2026-03-01 22:59:49 -0800
 
diff --git a/zic.c b/zic.c
index 77396228..c0891001 100644
--- a/zic.c
+++ b/zic.c
@@ -253,6 +253,7 @@ symlink(char const *target, char const *linkname)
    (errno = ENOTSUP, -1)
 #endif
 
+static void    check_for_signal(void);
 static void    addtt(zic_t starttime, int type);
 static int     addtype(zic_t, char const *, bool, bool, bool);
 static void    leapadd(zic_t, int, int);
@@ -704,6 +705,7 @@ eat(int fnum, lineno num)
 ATTRIBUTE_FORMAT((printf, 1, 0)) static void
 verror(const char *const string, va_list args)
 {
+       check_for_signal();
        /*
        ** Match the format of "cc" to allow sh users to
        **      zic ... 2>&1 | error -t "*" -v
@@ -1074,6 +1076,7 @@ make_links(void)
        warning(_("link %s targeting link %s"),
                links[i].l_linkname, links[i].l_target);
     }
+    check_for_signal();
   }
 }
 
@@ -1391,6 +1394,7 @@ main(int argc, char **argv)
                for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
                        continue;
                outzone(&zones[i], j - i);
+               check_for_signal();
        }
        make_links();
        if (lcltime != NULL) {
@@ -1486,9 +1490,11 @@ get_rand_u64(void)
   static int nwords;
   if (!nwords) {
     ssize_t s;
-    do
+    for (;; check_for_signal()) {
       s = getrandom(entropy_buffer, sizeof entropy_buffer, 0);
-    while (s < 0 && errno == EINTR);
+      if (! (s < 0 && errno == EINTR))
+       break;
+    }
 
     nwords = s < 0 ? -1 : s / sizeof *entropy_buffer;
   }
@@ -1516,7 +1522,7 @@ get_rand_u64(void)
       rmod = INT_MAX < UINT_FAST64_MAX ? 0 : UINT_FAST64_MAX / nrand + 1,
       r = 0, rmax = 0;
 
-    do {
+    for (;; check_for_signal()) {
       uint_fast64_t rmax1 = rmax;
       if (rmod) {
        /* Avoid signed integer overflow on theoretical platforms
@@ -1527,7 +1533,9 @@ get_rand_u64(void)
       rmax1 = nrand * rmax1 + rand_max;
       r = nrand * r + rand();
       rmax = rmax < rmax1 ? rmax1 : UINT_FAST64_MAX;
-    } while (rmax < UINT_FAST64_MAX);
+      if (UINT_FAST64_MAX <= rmax)
+       break;
+    }
 
     return r;
   }
@@ -1574,9 +1582,11 @@ random_dirent(char const **name, char **namealloc)
     *name = *namealloc = dst;
   }
 
-  do
+  for (;; check_for_signal()) {
     r = get_rand_u64();
-  while (unfair_min <= r);
+    if (r < unfair_min)
+      break;
+  }
 
   for (i = 0; i < suffixlen; i++) {
     dst[dirlen + prefixlen + i] = alphabet[r % alphabetlen];
@@ -1611,7 +1621,7 @@ open_outfile(char const **outname, char **tempname)
   if (!*tempname)
     random_dirent(outname, tempname);
 
-  while (true) {
+  for (;; check_for_signal()) {
     int oflags = O_WRONLY | O_BINARY | O_CREAT | O_EXCL;
     int fd = open(*outname, oflags, creat_perms);
     int err;
@@ -1725,8 +1735,6 @@ dolink(char const *target, char const *linkname, bool 
staysymlink)
        char const *outname = linkname;
        int targetissym = -2, linknameissym = -2;
 
-       check_for_signal();
-
        if (strcmp(target, "-") == 0) {
          if (remove(linkname) == 0 || errno == ENOENT || errno == ENOTDIR)
            return;
@@ -1739,7 +1747,7 @@ dolink(char const *target, char const *linkname, bool 
staysymlink)
          }
        }
 
-       while (true) {
+       for (;; check_for_signal()) {
          if (linkat(AT_FDCWD, target, AT_FDCWD, outname, AT_SYMLINK_FOLLOW)
              == 0) {
            link_errno = 0;
@@ -1791,7 +1799,7 @@ dolink(char const *target, char const *linkname, bool 
staysymlink)
          int symlink_errno = -1;
 
          if (contents) {
-           while (true) {
+           for (;; check_for_signal()) {
              if (symlink(contents, outname) == 0) {
                symlink_errno = 0;
                break;
@@ -1822,7 +1830,7 @@ dolink(char const *target, char const *linkname, bool 
staysymlink)
              exit(EXIT_FAILURE);
            }
            tp = open_outfile(&outname, &tempname);
-           while ((c = getc(fp)) != EOF)
+           for (; (c = getc(fp)) != EOF; check_for_signal())
              putc(c, tp);
            close_file(tp, directory, linkname, tempname);
            close_file(fp, directory, target, NULL);
@@ -1946,7 +1954,7 @@ static bool
 inputline(FILE *fp, char *buf, ptrdiff_t bufsize)
 {
   ptrdiff_t linelen = 0, ch;
-  while ((ch = getc(fp)) != '\n') {
+  for (; (ch = getc(fp)) != '\n'; check_for_signal()) {
     if (ch < 0) {
       if (ferror(fp)) {
        error(_("input error"));
@@ -2033,6 +2041,7 @@ infile(int fnum, char const *name)
                                default: unreachable();
                        }
                }
+               check_for_signal();
        }
        close_file(fp, NULL, filename(fnum), NULL);
        if (wantcont)
-- 
2.51.0

Reply via email to