]> granicus.if.org Git - file/commitdiff
From: Denys Vlasenko
authorChristos Zoulas <christos@zoulas.com>
Tue, 7 May 2019 02:20:27 +0000 (02:20 +0000)
committerChristos Zoulas <christos@zoulas.com>
Tue, 7 May 2019 02:20:27 +0000 (02:20 +0000)
Use sigaction(2) to save and restore SIGPIPE instead of signal(3)
because signal(3) does not have reliable semantics with respect to
SA_RESTART across all platforms: The original BSD semantics are to
always set SA_RESTART whereas the "new" BSD semantics were to keep
what siginterrupt(2) did.

And two missed optimizations:
= The saving/restoring of SIGPIPE is done even if file turns out
  to be *not* compressed, and no decompressor is called.
= If old signal was already SIG_IGN, no need to restore it.

This causes, for example, ~160000 unnecessary calls
to rt_sigaction() when rpmbuild generates kernel rpms.

Finally we can't share the old and new sigaction pointer because
of the "restrict" semantics.

src/compress.c

index 1e85ae938fb4fe262a12c3eb54c37a7137d18dae..6ae0c59dae31250ced33097e5db84fb0cbe79804 100644 (file)
@@ -35,7 +35,7 @@
 #include "file.h"
 
 #ifndef lint
-FILE_RCSID("@(#)$File: compress.c,v 1.119 2019/05/05 19:25:23 christos Exp $")
+FILE_RCSID("@(#)$File: compress.c,v 1.120 2019/05/07 02:20:27 christos Exp $")
 #endif
 
 #include "magic.h"
@@ -226,12 +226,12 @@ file_zmagic(struct magic_set *ms, const struct buffer *b, const char *name)
        int fd = b->fd;
        const unsigned char *buf = CAST(const unsigned char *, b->fbuf);
        size_t nbytes = b->flen;
-       sig_t osigpipe;
+       int sa_saved = 0;
+       struct sigaction sig_act;
 
        if ((ms->flags & MAGIC_COMPRESS) == 0)
                return 0;
 
-       osigpipe = signal(SIGPIPE, SIG_IGN);
        for (i = 0; i < ncompr; i++) {
                int zm;
                if (nbytes < compr[i].maglen)
@@ -246,6 +246,16 @@ file_zmagic(struct magic_set *ms, const struct buffer *b, const char *name)
 
                if (!zm)
                        continue;
+
+               /* Prevent SIGPIPE death if child dies unexpectedly */
+               if (!sa_saved) {
+                       //We can use sig_act for both new and old, but
+                       struct sigaction new_act;
+                       memset(&new_act, 0, sizeof(new_act));
+                       new_act.sa_handler = SIG_IGN;
+                       sa_saved = sigaction(SIGPIPE, &new_act, &sig_act) != -1;
+               }
+
                nsz = nbytes;
                urv = uncompressbuf(fd, ms->bytes_max, i, buf, &newbuf, &nsz);
                DPRINTF("uncompressbuf = %d, %s, %" SIZE_T_FORMAT "u\n", urv,
@@ -302,7 +312,9 @@ file_zmagic(struct magic_set *ms, const struct buffer *b, const char *name)
 out:
        DPRINTF("rv = %d\n", rv);
 
-       (void)signal(SIGPIPE, osigpipe);
+       if (sa_saved && sig_act.sa_handler != SIG_IGN)
+               (void)sigaction(SIGPIPE, &sig_act, NULL);
+
        free(newbuf);
        ms->flags |= MAGIC_COMPRESS;
        DPRINTF("Zmagic returns %d\n", rv);