I have a very large (gzipped) archive and I've forgotten exactly how the
contents are structured. (is it stuff, tedu/stuff, etc.)

I run tar ztf bananas.tgz | head. This prints out a few lines, and then...
nothing. For a long time. head is long gone, but tar is still chugging away.
Aren't processes supposed to die in this case? Yes, SIGPIPE.

Alas, tar ignores SIGPIPE with the claim that "we deal with broken pipes
via failed writes." This is a lie. Some writes, yes, but not printf when
listing an archive. Those all got the delightful (void) treatment.

Fixing this quickly dives down into a rabbit hole of crazy, because then we
need to kill the gzip so it doesn't complain about broken pipes, etc.

Anyway, this is what I've got. Now when I examine my big archive it prints the
first ten entries and immediately returns to the shell without wasting
electrons.


Index: ar_io.c
===================================================================
RCS file: /cvs/src/bin/pax/ar_io.c,v
retrieving revision 1.62
diff -u -p -r1.62 ar_io.c
--- ar_io.c     11 Mar 2017 12:55:47 -0000      1.62
+++ ar_io.c     31 Jan 2019 03:14:25 -0000
@@ -74,7 +74,7 @@ static int wr_trail = 1;              /* trailer was
 static int can_unlnk = 0;              /* do we unlink null archives?  */
 const char *arcname;                   /* printable name of archive */
 const char *gzip_program;              /* name of gzip program */
-static pid_t zpid = -1;                        /* pid of child process */
+pid_t zpid = -1;                       /* pid of child process */
 int force_one_volume;                  /* 1 if we ignore volume changes */
 
 static int get_phys(void);
Index: extern.h
===================================================================
RCS file: /cvs/src/bin/pax/extern.h,v
retrieving revision 1.59
diff -u -p -r1.59 extern.h
--- extern.h    13 Sep 2018 12:33:43 -0000      1.59
+++ extern.h    31 Jan 2019 03:07:22 -0000
@@ -159,7 +159,7 @@ int next_file(ARCHD *);
  */
 void ls_list(ARCHD *, time_t, FILE *);
 void ls_tty(ARCHD *);
-void safe_print(const char *, FILE *);
+int safe_print(const char *, FILE *);
 u_long asc_ul(char *, int, int);
 int ul_asc(u_long, char *, int, int);
 unsigned long long asc_ull(char *, int, int);
Index: gen_subs.c
===================================================================
RCS file: /cvs/src/bin/pax/gen_subs.c,v
retrieving revision 1.32
diff -u -p -r1.32 gen_subs.c
--- gen_subs.c  26 Aug 2016 05:06:14 -0000      1.32
+++ gen_subs.c  31 Jan 2019 03:14:57 -0000
@@ -38,6 +38,7 @@
 #include <sys/stat.h>
 #include <grp.h>
 #include <pwd.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -53,6 +54,8 @@
  * a collection of general purpose subroutines used by pax
  */
 
+extern pid_t zpid;
+
 /*
  * constants used by ls_list() when printing out archive members
  */
@@ -78,6 +81,7 @@ ls_list(ARCHD *arcn, time_t now, FILE *f
        char f_mode[MODELEN];
        char f_date[DATELEN];
        int term;
+       int rv;
 
        term = zeroflag ? '\0' : '\n';  /* path termination character */
 
@@ -86,11 +90,17 @@ ls_list(ARCHD *arcn, time_t now, FILE *f
         */
        if (!vflag) {
                if (zeroflag)
-                       (void)fputs(arcn->name, fp);
+                       rv = fputs(arcn->name, fp);
                else
-                       safe_print(arcn->name, fp);
-               (void)putc(term, fp);
-               (void)fflush(fp);
+                       rv = safe_print(arcn->name, fp);
+               if (rv < 0)
+                       goto die;
+               rv = putc(term, fp);
+               if (rv == EOF)
+                       goto die;
+               rv = fflush(fp);
+               if (rv < 0)
+                       goto die;
                return;
        }
 
@@ -136,6 +146,13 @@ ls_list(ARCHD *arcn, time_t now, FILE *f
        }
        (void)putc(term, fp);
        (void)fflush(fp);
+       return;
+
+die:
+       if (zpid > 0)
+               kill(zpid, SIGINT);
+       zpid = -1;
+       exit(1);
 }
 
 /*
@@ -160,11 +177,12 @@ ls_tty(ARCHD *arcn)
        tty_prnt("%s%s %s\n", f_mode, f_date, arcn->name);
 }
 
-void
+int
 safe_print(const char *str, FILE *fp)
 {
        char visbuf[5];
        const char *cp;
+       int rv;
 
        /*
         * if printing to a tty, use vis(3) to print special characters.
@@ -172,11 +190,14 @@ safe_print(const char *str, FILE *fp)
        if (isatty(fileno(fp))) {
                for (cp = str; *cp; cp++) {
                        (void)vis(visbuf, cp[0], VIS_CSTYLE, cp[1]);
-                       (void)fputs(visbuf, fp);
+                       rv = fputs(visbuf, fp);
+                       if (rv < 0)
+                               break;
                }
        } else {
-               (void)fputs(str, fp);
+               rv = fputs(str, fp);
        }
+       return rv;
 }
 
 /*

Reply via email to