gbranden pushed a commit to branch master
in repository groff.

commit b62f0605427caa156f23c81280f345496dd8a5cc
Author: G. Branden Robinson <[email protected]>
AuthorDate: Thu Sep 26 17:26:16 2024 -0500

    [pdfmom]: Handle errors and abnormal exits.
    
    * src/devices/gropdf/pdfmom.pl: Handle signaled and error exits from
      groff pipeline.  Improve diagnostics.  Store "basename" of executing
      command into `prog` scalar.  Gather the wait status returned by every
      use of `system()`.
    
      (abort): New subroutine writes a fatal diagnostic message and
      exits with status 1.
    
      (autopsy): New subroutine decodes a POSIX wait status to
      determine the fate of an unlucky process, and returns it as a
      human-readable string scalar.  (The interesting part is cribbed
      from Perl documentation.)
    
    Also discard trailing whitespace from lines.  Also update Vim modeline
    to reflect indentation practice in evidence.
    
    I managed to introduce a SEGV into tbl (that didn't show up with simple
    inputs) in my working copy.  To my dismay, the build just kept right on
    trucking after failing to build "groff-man-pages.pdf", because pdfmom
    ignored the return value of `system()`, concealing errors.  I don't
    think we can accept that; we need to fail fast and fail hard.  If I
    hadn't noticed the piteous "Segmentation fault" error scroll by, I might
    have overlooked my mistake for a long time.
---
 ChangeLog                    | 15 +++++++++++
 src/devices/gropdf/pdfmom.pl | 64 ++++++++++++++++++++++++++++++++++----------
 2 files changed, 65 insertions(+), 14 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index a192af200..b31b3831f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2024-09-26  G. Branden Robinson <[email protected]>
+
+       [pdfmom]: Handle errors and abnormal exits.
+
+       * src/devices/gropdf/pdfmom.pl: Handle signaled and error exits
+       from groff pipeline.  Improve diagnostics.  Store "basename" of
+       executing command into `prog` scalar.  Gather the wait status
+       returned by every use of `system()`.
+       (abort): New subroutine writes a fatal diagnostic message and
+       exits with status 1.
+       (autopsy): New subroutine decodes a POSIX wait status to
+       determine the fate of an unlucky process, and returns it as a
+       human-readable string scalar.  (The interesting part is cribbed
+       from Perl documentation.)
+
 2024-09-26  G. Branden Robinson <[email protected]>
 
        * src/preproc/tbl/table.cpp (table::add_entry): Throw warnings
diff --git a/src/devices/gropdf/pdfmom.pl b/src/devices/gropdf/pdfmom.pl
index a8117a56a..5806fba9b 100644
--- a/src/devices/gropdf/pdfmom.pl
+++ b/src/devices/gropdf/pdfmom.pl
@@ -4,7 +4,7 @@
 #      Deri James      : Friday 16 Mar 2012
 #
 
-# Copyright (C) 2012-2020 Free Software Foundation, Inc.
+# Copyright (C) 2012-2024 Free Software Foundation, Inc.
 #      Written by Deri James <[email protected]>
 #
 # This file is part of groff.
@@ -24,7 +24,9 @@
 
 use strict;
 use warnings;
+use File::Spec qw/splitpath/;
 use File::Temp qw/tempfile/;
+
 my @cmd;
 my $dev='pdf';
 my $preconv='';
@@ -48,10 +50,38 @@ my $RT_SEP='@RT_SEP@';
 $ENV{PATH}=$ENV{GROFF_BIN_PATH}.$RT_SEP.$ENV{PATH} if 
exists($ENV{GROFF_BIN_PATH});
 $ENV{TMPDIR}=$ENV{GROFF_TMPDIR} if exists($ENV{GROFF_TMPDIR});
 
+(undef,undef,my $prog)=File::Spec->splitpath($0);
+
+sub abort
+{
+    my $message=shift(@_);
+    print STDERR "$prog: fatal error: $message";
+    exit 1;
+}
+
+sub autopsy
+{
+    my $waitstatus=shift(@_);
+    my $finding;
+
+    if ($waitstatus == -1) {
+       $finding = "unable to run groff: $!\n";
+    }
+    elsif ($? & 127) {
+       $finding = sprintf("groff died with signal %d, %s core dump\n",
+           ($? & 127),  ($? & 128) ? 'with' : 'without');
+    }
+    else {
+       $finding = sprintf("groff exited with status %d\n", $? >> 8);
+    }
+
+    return $finding;
+}
+
 while (my $c=shift)
 {
     $c=~s/(?<!\\)"/\\"/g;
-    
+
     if (substr($c,0,2) eq '-T')
     {
        if (length($c) > 2)
@@ -122,7 +152,7 @@ while (my $c=shift)
        else
        {
            # Just a '-'
-           
+
            push(@cmd,$c);
            $readstdin=2;
        }
@@ -130,10 +160,10 @@ while (my $c=shift)
     else
     {
        # Got a filename?
-       
+
        push(@cmd,"\"$c\"");
        $readstdin=0 if $readstdin == 1;
-       
+
     }
 
 }
@@ -148,40 +178,46 @@ if ($readstdin)
     {
        print $fh ($_);
     }
-    
+
     close($fh);
-    
+
     $cmdstring=~s/ - / $tmpfn / if $readstdin == 2;
     $cmdstring.=" $tmpfn " if $readstdin == 1;
 }
 
+my $waitstatus = 0;
+
 if ($dev eq 'pdf')
 {
     if ($mom)
     {
-        system("groff -Tpdf -dLABEL.REFS=1 $mom -z $cmdstring 2>&1 | LC_ALL=C 
grep '^\\. *ds' | groff -Tpdf $preconv -dPDF.EXPORT=1 -dLABEL.REFS=1 $mom -z - 
$cmdstring 2>&1 | LC_ALL=C grep '^\\. *ds' | groff -Tpdf $mom $preconv - 
$cmdstring $zflg");
+       $waitstatus = system("groff -Tpdf -dLABEL.REFS=1 $mom -z $cmdstring 
2>&1 | LC_ALL=C grep '^\\. *ds' | groff -Tpdf $preconv -dPDF.EXPORT=1 
-dLABEL.REFS=1 $mom -z - $cmdstring 2>&1 | LC_ALL=C grep '^\\. *ds' | groff 
-Tpdf $mom $preconv - $cmdstring $zflg");
+       abort(autopsy($?)) unless $waitstatus == 0;
+
     }
     else
     {
-        system("groff -Tpdf $preconv -dPDF.EXPORT=1 -z $cmdstring 2>&1 | 
LC_ALL=C grep '^\\. *ds' | groff -Tpdf $preconv - $cmdstring $zflg");
+       $waitstatus = system("groff -Tpdf $preconv -dPDF.EXPORT=1 -z $cmdstring 
2>&1 | LC_ALL=C grep '^\\. *ds' | groff -Tpdf $preconv - $cmdstring $zflg");
+       abort(autopsy($?)) unless $waitstatus == 0;
     }
 }
 elsif ($dev eq 'ps')
 {
-    system("groff -Tpdf -dLABEL.REFS=1 $mom -z $cmdstring 2>&1 | LC_ALL=C grep 
'^\\. *ds' | pdfroff -mpdfmark $mom --no-toc - $preconv $cmdstring");
+       $waitstatus = system("groff -Tpdf -dLABEL.REFS=1 $mom -z $cmdstring 
2>&1 | LC_ALL=C grep '^\\. *ds' | pdfroff -mpdfmark $mom --no-toc - $preconv 
$cmdstring");
+       abort(autopsy($?)) unless $waitstatus == 0;
 }
 elsif ($dev eq '-z') # pseudo dev - just compile for warnings
 {
-    system("groff -Tpdf $mom -z $cmdstring");
+    $waitstatus = system("groff -Tpdf $mom -z $cmdstring");
+    abort(autopsy($?)) unless $waitstatus == 0;
 }
 else
 {
-    print STDERR "Not compatible with device '-T $dev'\n";
-    exit 1;
+    abort("groff output device '$dev' not supported");
 }
 
 # Local Variables:
 # fill-column: 72
 # mode: CPerl
 # End:
-# vim: set cindent noexpandtab shiftwidth=2 softtabstop=2 textwidth=72:
+# vim: set cindent noexpandtab shiftwidth=4 softtabstop=4 textwidth=72:

_______________________________________________
Groff-commit mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/groff-commit

Reply via email to