ERR: Modify util/mkerr.pl to produce internal err string loaders
authorRichard Levitte <levitte@openssl.org>
Thu, 12 Nov 2020 08:12:41 +0000 (09:12 +0100)
committerRichard Levitte <levitte@openssl.org>
Tue, 24 Nov 2020 14:18:29 +0000 (15:18 +0100)
This also modifies the .ec L statement to take a third file, which is
the internal header file to declare internal things.  This is only
useful for our internal declarations and will not affect engines.

Fixes #10527

Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/13390)

crypto/err/openssl.ec
util/mkerr.pl

index 589ff1094c05b201e993a6e361ab57d300adf32f..f265ca0f5dd8f67830cbec6c6d0f75d06834d107 100644 (file)
@@ -1,55 +1,49 @@
 # configuration file for util/mkerr.pl
 
 # The INPUT HEADER is scanned for declarations
-# LIBNAME       INPUT HEADER                    ERROR-TABLE FILE
-L ERR           NONE                            NONE
-L FUNC          NONE                            NONE
-L BN            include/openssl/bn.h            crypto/bn/bn_err.c
-L RSA           include/openssl/rsa.h           crypto/rsa/rsa_err.c
-L DH            include/openssl/dh.h            crypto/dh/dh_err.c
-L EVP           include/openssl/evp.h           crypto/evp/evp_err.c
-L BUF           include/openssl/buffer.h        crypto/buffer/buf_err.c
-L OBJ           include/openssl/objects.h       crypto/objects/obj_err.c
-L PEM           include/openssl/pem.h           crypto/pem/pem_err.c
-L DSA           include/openssl/dsa.h           crypto/dsa/dsa_err.c
-L X509          include/openssl/x509.h          crypto/x509/x509_err.c
-L ASN1          include/openssl/asn1.h          crypto/asn1/asn1_err.c
-L CONF          include/openssl/conf.h          crypto/conf/conf_err.c
-L CRYPTO        include/openssl/crypto.h        crypto/cpt_err.c
-L EC            include/openssl/ec.h            crypto/ec/ec_err.c
-L SSL           include/openssl/ssl.h           ssl/ssl_err.c
-L BIO           include/openssl/bio.h           crypto/bio/bio_err.c
-L PKCS7         include/openssl/pkcs7.h         crypto/pkcs7/pkcs7err.c
-L X509V3        include/openssl/x509v3.h        crypto/x509/v3err.c
-L PKCS12        include/openssl/pkcs12.h        crypto/pkcs12/pk12err.c
-L RAND          include/openssl/rand.h          crypto/rand/rand_err.c
-L DSO           include/internal/dso.h          crypto/dso/dso_err.c
-L ENGINE        include/openssl/engine.h        crypto/engine/eng_err.c
-L OCSP          include/openssl/ocsp.h          crypto/ocsp/ocsp_err.c
-L UI            include/openssl/ui.h            crypto/ui/ui_err.c
-L COMP          include/openssl/comp.h          crypto/comp/comp_err.c
-L TS            include/openssl/ts.h            crypto/ts/ts_err.c
-L CMS           include/openssl/cms.h           crypto/cms/cms_err.c
-L CRMF          include/openssl/crmf.h          crypto/crmf/crmf_err.c
-L CMP           include/openssl/cmp.h           crypto/cmp/cmp_err.c
-L CT            include/openssl/ct.h            crypto/ct/ct_err.c
-L ASYNC         include/openssl/async.h         crypto/async/async_err.c
-L KDF           NONE                            crypto/kdf/kdf_err.c
-L SM2           include/crypto/sm2.h            crypto/sm2/sm2_err.c
-L OSSL_STORE    include/openssl/store.h         crypto/store/store_err.c
-L ESS           include/openssl/ess.h           crypto/ess/ess_err.c
-L PROP          include/internal/property.h     crypto/property/property_err.c
-L PROV          providers/common/include/prov/providercommon.h providers/common/provider_err.c
-L OSSL_ENCODER  include/openssl/encoder.h       crypto/encode_decode/encoder_err.c
-L OSSL_DECODER  include/openssl/decoder.h       crypto/encode_decode/decoder_err.c
-L HTTP          include/openssl/http.h          crypto/http/http_err.c
-
-# additional header files to be scanned for function names
-L NONE          include/openssl/x509_vfy.h      NONE
-L NONE          crypto/ec/ec_local.h            NONE
-L NONE          crypto/cms/cms_local.h          NONE
-L NONE          crypto/ct/ct_local.h            NONE
-L NONE          ssl/ssl_local.h                 NONE
+# LIBNAME       PUBLIC HEADER                   ERROR-TABLE FILE                        INTERNAL HEADER (if relevant)
+L ERR           NONE                            NONE                                    
+L FUNC          NONE                            NONE                                    
+L BN            include/openssl/bnerr.h         crypto/bn/bn_err.c                      include/crypto/bnerr.h
+L RSA           include/openssl/rsaerr.h        crypto/rsa/rsa_err.c                    include/crypto/rsaerr.h
+L DH            include/openssl/dherr.h         crypto/dh/dh_err.c                      include/crypto/dherr.h
+L EVP           include/openssl/evperr.h        crypto/evp/evp_err.c                    include/crypto/evperr.h
+L BUF           include/openssl/buffererr.h     crypto/buffer/buf_err.c                 include/crypto/buffererr.h
+L OBJ           include/openssl/objectserr.h    crypto/objects/obj_err.c                include/crypto/objectserr.h
+L PEM           include/openssl/pemerr.h        crypto/pem/pem_err.c                    include/crypto/pemerr.h
+L DSA           include/openssl/dsaerr.h        crypto/dsa/dsa_err.c                    include/crypto/dsaerr.h
+L X509          include/openssl/x509err.h       crypto/x509/x509_err.c                  include/crypto/x509err.h
+L ASN1          include/openssl/asn1err.h       crypto/asn1/asn1_err.c                  include/crypto/asn1err.h
+L CONF          include/openssl/conferr.h       crypto/conf/conf_err.c                  include/crypto/conferr.h
+L CRYPTO        include/openssl/cryptoerr.h     crypto/cpt_err.c                        include/crypto/cryptoerr.h
+L EC            include/openssl/ecerr.h         crypto/ec/ec_err.c                      include/crypto/ecerr.h
+L SSL           include/openssl/sslerr.h        ssl/ssl_err.c                           ssl/sslerr.h
+L BIO           include/openssl/bioerr.h        crypto/bio/bio_err.c                    include/crypto/bioerr.h
+L PKCS7         include/openssl/pkcs7err.h      crypto/pkcs7/pkcs7err.c                 include/crypto/pkcs7err.h
+L X509V3        include/openssl/x509v3err.h     crypto/x509/v3err.c                     include/crypto/x509v3err.h
+L PKCS12        include/openssl/pkcs12err.h     crypto/pkcs12/pk12err.c                 include/crypto/pkcs12err.h
+L RAND          include/openssl/randerr.h       crypto/rand/rand_err.c                  include/crypto/randerr.h
+L DSO           NONE                            crypto/dso/dso_err.c                    include/internal/dsoerr.h
+L ENGINE        include/openssl/engineerr.h     crypto/engine/eng_err.c                 include/crypto/engineerr.h
+L OCSP          include/openssl/ocsperr.h       crypto/ocsp/ocsp_err.c                  include/crypto/ocsperr.h
+L UI            include/openssl/uierr.h         crypto/ui/ui_err.c                      include/crypto/uierr.h
+L COMP          include/openssl/comperr.h       crypto/comp/comp_err.c                  include/crypto/comperr.h
+L TS            include/openssl/tserr.h         crypto/ts/ts_err.c                      include/crypto/tserr.h
+L CMS           include/openssl/cmserr.h        crypto/cms/cms_err.c                    include/crypto/cmserr.h
+L CRMF          include/openssl/crmferr.h       crypto/crmf/crmf_err.c                  include/crypto/crmferr.h
+L CMP           include/openssl/cmperr.h        crypto/cmp/cmp_err.c                    include/crypto/cmperr.h
+L CT            include/openssl/cterr.h         crypto/ct/ct_err.c                      include/crypto/cterr.h
+L ASYNC         include/openssl/asyncerr.h      crypto/async/async_err.c                include/crypto/asyncerr.h
+# KDF is only here for conservation purposes
+L KDF           NONE                            NONE                                    NONE
+L SM2           NONE                            crypto/sm2/sm2_err.c                    include/crypto/sm2err.h
+L OSSL_STORE    include/openssl/storeerr.h      crypto/store/store_err.c                include/crypto/storeerr.h
+L ESS           include/openssl/esserr.h        crypto/ess/ess_err.c                    include/crypto/esserr.h
+L PROP          NONE                            crypto/property/property_err.c          include/internal/propertyerr.h
+L PROV          NONE                            providers/common/provider_err.c         providers/common/include/prov/providercommonerr.h
+L OSSL_ENCODER  include/openssl/encodererr.h    crypto/encode_decode/encoder_err.c      include/crypto/encodererr.h
+L OSSL_DECODER  include/openssl/decodererr.h    crypto/encode_decode/decoder_err.c      include/crypto/decodererr.h
+L HTTP          include/openssl/httperr.h       crypto/http/http_err.c                  include/crypto/httperr.h
 
 # SSL/TLS alerts
 R SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE          1010
index 0c7ae7b56d46c77aecf89698808a624f7fd8c630..d7c72af14c952224dcafe626dbda98adbe028065 100755 (executable)
@@ -9,6 +9,9 @@
 use strict;
 use warnings;
 
+use File::Basename;
+use File::Spec::Functions qw(abs2rel rel2abs);
+
 use lib ".";
 use configdata;
 
@@ -124,8 +127,10 @@ if ( $internal ) {
 # Data parsed out of the config and state files.
 # We always map function-code values to zero, so items marked below with
 # an asterisk could eventually be removed.  TODO(4.0)
-my %hinc;       # lib -> header
-my %libinc;     # header -> lib
+my %hpubinc;    # lib -> public header
+my %libpubinc;  # public header -> lib
+my %hprivinc;   # lib -> private header
+my %libprivinc; # private header -> lib
 my %cskip;      # error_file -> lib
 my %errorfile;  # lib -> error file name
 my %fmax;       # lib -> max assigned function code*
@@ -145,21 +150,30 @@ my %strings;    # define -> text
 open(IN, "$config") || die "Can't open config file $config, $!,";
 while ( <IN> ) {
     next if /^#/ || /^$/;
-    if ( /^L\s+(\S+)\s+(\S+)\s+(\S+)/ ) {
+    if ( /^L\s+(\S+)\s+(\S+)\s+(\S+)(?:\s+(\S+))?\s+$/ ) {
         my $lib = $1;
-        my $hdr = $2;
+        my $pubhdr = $2;
         my $err = $3;
-        $hinc{$lib}   = $hdr;
-        $libinc{$hdr} = $lib;
+        my $privhdr = $4 // 'NONE';
+        $hpubinc{$lib}   = $pubhdr;
+        $libpubinc{$pubhdr} = $lib;
+        $hprivinc{$lib}   = $privhdr;
+        $libprivinc{$privhdr} = $lib;
         $cskip{$err}  = $lib;
-        next if $err eq 'NONE';
         $errorfile{$lib} = $err;
+        next if $err eq 'NONE';
         $fmax{$lib}      = 100;
         $rmax{$lib}      = 100;
         $fassigned{$lib} = ":";
         $rassigned{$lib} = ":";
         $fnew{$lib}      = 0;
         $rnew{$lib}      = 0;
+        die "Public header file must be in include/openssl ($pubhdr is not)\n"
+            if ($internal
+                && $pubhdr ne 'NONE'
+                && $pubhdr !~ m|^include/openssl/|);
+        die "Private header file may only be specified with -internal ($privhdr given)\n"
+            unless ($privhdr eq 'NONE' || $internal);
     } elsif ( /^R\s+(\S+)\s+(\S+)/ ) {
         $rextra{$1} = $2;
         $rcodes{$1} = $2;
@@ -211,6 +225,7 @@ if ( ! $reindex && $statefile ) {
             $skippedstate++;
             next;
         }
+        next if $errorfile{$lib} eq 'NONE';
         if ( $name =~ /^(?:OSSL_|OPENSSL_)?[A-Z0-9]{2,}_R_/ ) {
             die "$lib reason code $code collision at $name\n"
                 if $rassigned{$lib} =~ /:$code:/;
@@ -252,10 +267,9 @@ if ( ! $reindex && $statefile ) {
     }
 }
 
-# Scan each header file and make a list of error codes
-# and function names
+# Scan each public header file and make a list of function codes and names
 &phase("Scanning headers");
-while ( ( my $hdr, my $lib ) = each %libinc ) {
+while ( ( my $hdr, my $lib ) = each %libpubinc ) {
     next if $hdr eq "NONE";
     print STDERR " ." if $debug;
     my $line = "";
@@ -386,6 +400,7 @@ foreach my $file ( @source ) {
 
         if ( /(((?:OSSL_|OPENSSL_)?[A-Z0-9]{2,})_F_([A-Z0-9_]+))/ ) {
             next unless exists $errorfile{$2};
+            next if $errorfile{$2} eq 'NONE';
             next if $1 eq "BIO_F_BUFFER_CTX";
             $usedfuncs{$1} = 1;
             if ( !exists $fcodes{$1} ) {
@@ -399,6 +414,7 @@ foreach my $file ( @source ) {
         }
         if ( /(((?:OSSL_|OPENSSL_)?[A-Z0-9]{2,})_R_[A-Z0-9_]+)/ ) {
             next unless exists $errorfile{$2};
+            next if $errorfile{$2} eq 'NONE';
             $usedreasons{$1} = 1;
             if ( !exists $rcodes{$1} ) {
                 print STDERR "  New reason $1\n" if $debug;
@@ -419,7 +435,6 @@ foreach my $lib ( keys %errorfile ) {
     next if ! $fnew{$lib} && ! $rnew{$lib} && ! $rebuild;
     next if scalar keys %modules > 0 && !$modules{$lib};
     next if $nowrite;
-    next if $hinc{$lib} eq 'NONE';
     print STDERR "$lib: $fnew{$lib} new functions\n" if $fnew{$lib};
     print STDERR "$lib: $rnew{$lib} new reasons\n" if $rnew{$lib};
     $newstate = 1;
@@ -434,15 +449,32 @@ foreach my $lib ( keys %errorfile ) {
     # indent level for innermost preprocessor lines
     my $indent = " ";
 
-    # Rewrite the header file
+    # Flag if the sub-library is disablable
+    # There are a few exceptions, where disabling the sub-library
+    # doesn't actually remove the whole sub-library, but rather implements
+    # it with a NULL backend.
+    my $disablable =
+        ($lib ne "SSL" && $lib ne "ASYNC" && $lib ne "DSO"
+         && (grep { $lib eq uc $_ } @disablables, @disablables_int));
 
-    my $hfile = $hinc{$lib};
-    $hfile =~ s/.h$/err.h/ if $internal;
-    open( OUT, ">$hfile" ) || die "Can't write to $hfile, $!,";
-    print OUT <<"EOF";
+    # Rewrite the internal header file if there is one ($internal only!)
+
+    if ($hprivinc{$lib} ne 'NONE') {
+        my $hfile = $hprivinc{$lib};
+        my $guard = $hfile;
+
+        if ($guard =~ m|^include/|) {
+            $guard = $';
+        } else {
+            $guard = basename($guard);
+        }
+        $guard = "OSSL_" . join('_', split(m|[./]|, uc $guard));
+
+        open( OUT, ">$hfile" ) || die "Can't write to $hfile, $!,";
+        print OUT <<"EOF";
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-$YEAR The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2020-$YEAR The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the \"License\").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -450,41 +482,142 @@ foreach my $lib ( keys %errorfile ) {
  * https://www.openssl.org/source/license.html
  */
 
-#ifndef OPENSSL_${lib}ERR_H
-# define OPENSSL_${lib}ERR_H
+#ifndef $guard
+# define $guard
 # pragma once
 
 # include <openssl/opensslconf.h>
 # include <openssl/symhacks.h>
 
+# ifdef  __cplusplus
+extern \"C\" {
+# endif
 
 EOF
-    if ( $internal ) {
-        # Declare the load function because the generate C file
-        # includes "fooerr.h" not "foo.h"
-        if ($lib ne "SSL" && $lib ne "ASYNC"
-                && (grep { $lib eq uc $_ } @disablables, @disablables_int)) {
+        $indent = ' ';
+        if ($disablable) {
             print OUT <<"EOF";
-# include <openssl/opensslconf.h>
-
 # ifndef OPENSSL_NO_${lib}
 
 EOF
             $indent = "  ";
         }
         print OUT <<"EOF";
-#${indent}ifdef  __cplusplus
-extern \"C\"
-#${indent}endif
-int ERR_load_${lib}_strings(void);
+int err_load_${lib}_strings_int(void);
 EOF
-    } else {
+
+        # If this library doesn't have a public header file, we write all
+        # definitions that would end up there here instead
+        if ($hpubinc{$lib} eq 'NONE') {
+            print OUT "\n/*\n * $lib function codes.\n */\n";
+            print OUT "#${indent}ifndef OPENSSL_NO_DEPRECATED_3_0\n";
+            foreach my $i ( @function ) {
+                my $z = 48 - length($i);
+                $z = 0 if $z < 0;
+                if ( $fcodes{$i} eq "X" ) {
+                    $fassigned{$lib} =~ m/^:([^:]*):/;
+                    my $findcode = $1;
+                    $findcode = $fmax{$lib} if !defined $findcode;
+                    while ( $fassigned{$lib} =~ m/:$findcode:/ ) {
+                        $findcode++;
+                    }
+                    $fcodes{$i} = $findcode;
+                    $fassigned{$lib} .= "$findcode:";
+                    print STDERR "New Function code $i\n" if $debug;
+                }
+                printf OUT "#${indent} define $i%s 0\n", " " x $z;
+            }
+            print OUT "#${indent}endif\n";
+
+            print OUT "\n/*\n * $lib reason codes.\n */\n";
+            foreach my $i ( @reasons ) {
+                my $z = 48 - length($i);
+                $z = 0 if $z < 0;
+                if ( $rcodes{$i} eq "X" ) {
+                    $rassigned{$lib} =~ m/^:([^:]*):/;
+                    my $findcode = $1;
+                    $findcode = $rmax{$lib} if !defined $findcode;
+                    while ( $rassigned{$lib} =~ m/:$findcode:/ ) {
+                        $findcode++;
+                    }
+                    $rcodes{$i} = $findcode;
+                    $rassigned{$lib} .= "$findcode:";
+                    print STDERR "New Reason code $i\n" if $debug;
+                }
+                printf OUT "#${indent}define $i%s $rcodes{$i}\n", " " x $z;
+            }
+            print OUT "\n";
+        }
+
+        # This doesn't go all the way down to zero, to allow for the ending
+        # brace for 'extern "C" {'.
+        while (length($indent) > 1) {
+            $indent = substr $indent, 0, -1;
+            print OUT "#${indent}endif\n";
+        }
+
         print OUT <<"EOF";
-# define ${lib}err(f, r) ERR_${lib}_error(0, (r), OPENSSL_FILE, OPENSSL_LINE)
 
+# ifdef  __cplusplus
+}
+# endif
+#endif
 EOF
-        if ( ! $static ) {
+        close OUT;
+    }
+
+    # Rewrite the public header file
+
+    if ($hpubinc{$lib} ne 'NONE') {
+        my $extra_include =
+            $internal
+            ? ($lib ne 'SSL'
+               ? "# include <openssl/cryptoerr_legacy.h>\n"
+               : "# include <openssl/sslerr_legacy.h>\n")
+            : '';
+        my $hfile = $hpubinc{$lib};
+        my $guard = $hfile;
+        $guard =~ s|^include/||;
+        $guard = join('_', split(m|[./]|, uc $guard));
+        $guard = "OSSL_" . $guard unless $internal;
+
+        open( OUT, ">$hfile" ) || die "Can't write to $hfile, $!,";
+        print OUT <<"EOF";
+/*
+ * Generated by util/mkerr.pl DO NOT EDIT
+ * Copyright 1995-$YEAR The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the \"License\").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef $guard
+# define $guard
+# pragma once
+
+# include <openssl/opensslconf.h>
+# include <openssl/symhacks.h>
+$extra_include
+
+EOF
+        $indent = ' ';
+        if ( $internal ) {
+            if ($disablable) {
+                print OUT <<"EOF";
+# ifndef OPENSSL_NO_${lib}
+
+EOF
+                $indent .= ' ';
+            }
+        } else {
             print OUT <<"EOF";
+# define ${lib}err(f, r) ERR_${lib}_error(0, (r), OPENSSL_FILE, OPENSSL_LINE)
+
+EOF
+            if ( ! $static ) {
+                print OUT <<"EOF";
 
 # ifdef  __cplusplus
 extern \"C\" {
@@ -496,72 +629,86 @@ void ERR_${lib}_error(int function, int reason, char *file, int line);
 }
 # endif
 EOF
+            }
         }
-    }
 
-    print OUT "\n/*\n * $lib function codes.\n */\n";
-    print OUT "# ifndef OPENSSL_NO_DEPRECATED_3_0\n";
-    foreach my $i ( @function ) {
-        my $z = 48 - length($i);
-        $z = 0 if $z < 0;
-        if ( $fcodes{$i} eq "X" ) {
-            $fassigned{$lib} =~ m/^:([^:]*):/;
-            my $findcode = $1;
-            $findcode = $fmax{$lib} if !defined $findcode;
-            while ( $fassigned{$lib} =~ m/:$findcode:/ ) {
-                $findcode++;
+        print OUT "\n/*\n * $lib function codes.\n */\n";
+        print OUT "#${indent}ifndef OPENSSL_NO_DEPRECATED_3_0\n";
+        foreach my $i ( @function ) {
+            my $z = 48 - length($i);
+            $z = 0 if $z < 0;
+            if ( $fcodes{$i} eq "X" ) {
+                $fassigned{$lib} =~ m/^:([^:]*):/;
+                my $findcode = $1;
+                $findcode = $fmax{$lib} if !defined $findcode;
+                while ( $fassigned{$lib} =~ m/:$findcode:/ ) {
+                    $findcode++;
+                }
+                $fcodes{$i} = $findcode;
+                $fassigned{$lib} .= "$findcode:";
+                print STDERR "New Function code $i\n" if $debug;
             }
-            $fcodes{$i} = $findcode;
-            $fassigned{$lib} .= "$findcode:";
-            print STDERR "New Function code $i\n" if $debug;
+            printf OUT "#${indent} define $i%s 0\n", " " x $z;
         }
-        printf OUT "#${indent} define $i%s 0\n", " " x $z;
-    }
-    print OUT "# endif\n";
-
-    print OUT "\n/*\n * $lib reason codes.\n */\n";
-    foreach my $i ( @reasons ) {
-        my $z = 48 - length($i);
-        $z = 0 if $z < 0;
-        if ( $rcodes{$i} eq "X" ) {
-            $rassigned{$lib} =~ m/^:([^:]*):/;
-            my $findcode = $1;
-            $findcode = $rmax{$lib} if !defined $findcode;
-            while ( $rassigned{$lib} =~ m/:$findcode:/ ) {
-                $findcode++;
+        print OUT "#${indent}endif\n";
+
+        print OUT "\n/*\n * $lib reason codes.\n */\n";
+        foreach my $i ( @reasons ) {
+            my $z = 48 - length($i);
+            $z = 0 if $z < 0;
+            if ( $rcodes{$i} eq "X" ) {
+                $rassigned{$lib} =~ m/^:([^:]*):/;
+                my $findcode = $1;
+                $findcode = $rmax{$lib} if !defined $findcode;
+                while ( $rassigned{$lib} =~ m/:$findcode:/ ) {
+                    $findcode++;
+                }
+                $rcodes{$i} = $findcode;
+                $rassigned{$lib} .= "$findcode:";
+                print STDERR "New Reason code $i\n" if $debug;
             }
-            $rcodes{$i} = $findcode;
-            $rassigned{$lib} .= "$findcode:";
-            print STDERR "New Reason code $i\n" if $debug;
+            printf OUT "#${indent}define $i%s $rcodes{$i}\n", " " x $z;
         }
-        printf OUT "#${indent}define $i%s $rcodes{$i}\n", " " x $z;
-    }
-    print OUT "\n";
+        print OUT "\n";
 
-    while (length($indent) > 0) {
-        $indent = substr $indent, 0, -1;
-        print OUT "#${indent}endif\n";
+        while (length($indent) > 0) {
+            $indent = substr $indent, 0, -1;
+            print OUT "#${indent}endif\n";
+        }
+        close OUT;
     }
 
     # Rewrite the C source file containing the error details.
 
-    # First, read any existing reason string definitions:
-    my $cfile = $errorfile{$lib};
-    my $pack_lib = $internal ? "ERR_LIB_${lib}" : "0";
-    my $hincf = $hfile;
-    $hincf =~ s|.*include/||;
-    if ( $hincf =~ m|^openssl/| ) {
-        $hincf = "<${hincf}>";
-    } else {
-        $hincf = "\"${hincf}\"";
-    }
+    if ($errorfile{$lib} ne 'NONE') {
+        # First, read any existing reason string definitions:
+        my $cfile = $errorfile{$lib};
+        my $pack_lib = $internal ? "ERR_LIB_${lib}" : "0";
+        my $hpubincf = $hpubinc{$lib};
+        my $hprivincf = $hprivinc{$lib};
+        my $includes = '';
+        if ($internal) {
+            if ($hpubincf ne 'NONE') {
+                $hpubincf =~ s|^include/||;
+                $includes .= "#include <${hpubincf}>\n";
+            }
+            if ($hprivincf =~ m|^include/|) {
+                $hprivincf = $';
+            } else {
+                $hprivincf = abs2rel(rel2abs($hprivincf),
+                                     rel2abs(dirname($cfile)));
+            }
+            $includes .= "#include \"${hprivincf}\"\n";
+        } else {
+            $includes .= "#include \"${hpubincf}\"\n";
+        }
 
-    open( OUT, ">$cfile" )
-        || die "Can't open $cfile for writing, $!, stopped";
+        open( OUT, ">$cfile" )
+            || die "Can't open $cfile for writing, $!, stopped";
 
-    my $const = $internal ? 'const ' : '';
+        my $const = $internal ? 'const ' : '';
 
-    print OUT <<"EOF";
+        print OUT <<"EOF";
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
  * Copyright 1995-$YEAR The OpenSSL Project Authors. All Rights Reserved.
@@ -573,53 +720,64 @@ EOF
  */
 
 #include <openssl/err.h>
-#include $hincf
+$includes
+EOF
+        $indent = '';
+        if ( $internal ) {
+            if ($disablable) {
+                print OUT <<"EOF";
+#ifndef OPENSSL_NO_${lib}
 
-#ifndef OPENSSL_NO_ERR
+EOF
+                $indent .= ' ';
+            }
+        }
+        print OUT <<"EOF";
+#${indent}ifndef OPENSSL_NO_ERR
 
 static ${const}ERR_STRING_DATA ${lib}_str_reasons[] = {
 EOF
 
-    # Add each reason code.
-    foreach my $i ( @reasons ) {
-        my $rn;
-        if ( exists $strings{$i} ) {
-            $rn = $strings{$i};
-            $rn = "" if $rn eq '*';
-        } else {
-            $i =~ /^${lib}_R_(\S+)$/;
-            $rn = $1;
-            $rn =~ tr/_[A-Z]/ [a-z]/;
-            $strings{$i} = $rn;
-        }
-        my $short = "    {ERR_PACK($pack_lib, 0, $i), \"$rn\"},";
-        if ( length($short) <= 80 ) {
-            print OUT "$short\n";
-        } else {
-            print OUT "    {ERR_PACK($pack_lib, 0, $i),\n    \"$rn\"},\n";
+        # Add each reason code.
+        foreach my $i ( @reasons ) {
+            my $rn;
+            if ( exists $strings{$i} ) {
+                $rn = $strings{$i};
+                $rn = "" if $rn eq '*';
+            } else {
+                $i =~ /^${lib}_R_(\S+)$/;
+                $rn = $1;
+                $rn =~ tr/_[A-Z]/ [a-z]/;
+                $strings{$i} = $rn;
+            }
+            my $short = "    {ERR_PACK($pack_lib, 0, $i), \"$rn\"},";
+            if ( length($short) <= 80 ) {
+                print OUT "$short\n";
+            } else {
+                print OUT "    {ERR_PACK($pack_lib, 0, $i),\n    \"$rn\"},\n";
+            }
         }
-    }
-    print OUT <<"EOF";
+        print OUT <<"EOF";
     {0, NULL}
 };
 
-#endif
+#${indent}endif
 EOF
-    if ( $internal ) {
-        print OUT <<"EOF";
+        if ( $internal ) {
+            print OUT <<"EOF";
 
-int ERR_load_${lib}_strings(void)
+int err_load_${lib}_strings_int(void)
 {
-#ifndef OPENSSL_NO_ERR
+#${indent}ifndef OPENSSL_NO_ERR
     if (ERR_reason_error_string(${lib}_str_reasons[0].error) == NULL)
         ERR_load_strings_const(${lib}_str_reasons);
-#endif
+#${indent}endif
     return 1;
 }
 EOF
-    } else {
-        my $st = $static ? "static " : "";
-        print OUT <<"EOF";
+        } else {
+            my $st = $static ? "static " : "";
+            print OUT <<"EOF";
 
 static int lib_code = 0;
 static int error_loaded = 0;
@@ -657,9 +815,21 @@ ${st}void ERR_${lib}_error(int function, int reason, char *file, int line)
 }
 EOF
 
-    }
+        }
 
-    close OUT;
+        while (length($indent) > 1) {
+            $indent = substr $indent, 0, -1;
+            print OUT "#${indent}endif\n";
+        }
+        if ($internal && $disablable) {
+            print OUT <<"EOF";
+#else
+NON_EMPTY_TRANSLATION_UNIT
+#endif
+EOF
+        }
+        close OUT;
+    }
 }
 
 &phase("Ending");