xref: /freebsd/crypto/openssl/util/mkerr.pl (revision e0c4386e7e71d93b0edc0c8fa156263fc4a8b0b6)
1*e0c4386eSCy Schubert#! /usr/bin/env perl
2*e0c4386eSCy Schubert# Copyright 1999-2021 The OpenSSL Project Authors. All Rights Reserved.
3*e0c4386eSCy Schubert#
4*e0c4386eSCy Schubert# Licensed under the Apache License 2.0 (the "License").  You may not use
5*e0c4386eSCy Schubert# this file except in compliance with the License.  You can obtain a copy
6*e0c4386eSCy Schubert# in the file LICENSE in the source distribution or at
7*e0c4386eSCy Schubert# https://www.openssl.org/source/license.html
8*e0c4386eSCy Schubert
9*e0c4386eSCy Schubertuse strict;
10*e0c4386eSCy Schubertuse warnings;
11*e0c4386eSCy Schubert
12*e0c4386eSCy Schubertuse File::Basename;
13*e0c4386eSCy Schubertuse File::Spec::Functions qw(abs2rel rel2abs);
14*e0c4386eSCy Schubert
15*e0c4386eSCy Schubertuse lib ".";
16*e0c4386eSCy Schubertuse configdata;
17*e0c4386eSCy Schubert
18*e0c4386eSCy Schubertmy $config       = "crypto/err/openssl.ec";
19*e0c4386eSCy Schubertmy $debug        = 0;
20*e0c4386eSCy Schubertmy $internal     = 0;
21*e0c4386eSCy Schubertmy $nowrite      = 0;
22*e0c4386eSCy Schubertmy $rebuild      = 0;
23*e0c4386eSCy Schubertmy $reindex      = 0;
24*e0c4386eSCy Schubertmy $static       = 0;
25*e0c4386eSCy Schubertmy $unref        = 0;
26*e0c4386eSCy Schubertmy %modules         = ();
27*e0c4386eSCy Schubert
28*e0c4386eSCy Schubertmy $errors       = 0;
29*e0c4386eSCy Schubertmy @t            = localtime();
30*e0c4386eSCy Schubertmy $YEAR         = $t[5] + 1900;
31*e0c4386eSCy Schubert
32*e0c4386eSCy Schubertsub phase
33*e0c4386eSCy Schubert{
34*e0c4386eSCy Schubert    my $text = uc(shift);
35*e0c4386eSCy Schubert    print STDERR "\n---\n$text\n" if $debug;
36*e0c4386eSCy Schubert}
37*e0c4386eSCy Schubert
38*e0c4386eSCy Schubertsub help
39*e0c4386eSCy Schubert{
40*e0c4386eSCy Schubert    print STDERR <<"EOF";
41*e0c4386eSCy Schubertmkerr.pl [options] [files...]
42*e0c4386eSCy Schubert
43*e0c4386eSCy SchubertOptions:
44*e0c4386eSCy Schubert
45*e0c4386eSCy Schubert    -conf FILE  Use the named config file FILE instead of the default.
46*e0c4386eSCy Schubert
47*e0c4386eSCy Schubert    -debug      Verbose output debugging on stderr.
48*e0c4386eSCy Schubert
49*e0c4386eSCy Schubert    -internal   Generate code that is to be built as part of OpenSSL itself.
50*e0c4386eSCy Schubert                Also scans internal list of files.
51*e0c4386eSCy Schubert
52*e0c4386eSCy Schubert    -module M   Only useful with -internal!
53*e0c4386eSCy Schubert                Only write files for library module M.  Whether files are
54*e0c4386eSCy Schubert                actually written or not depends on other options, such as
55*e0c4386eSCy Schubert                -rebuild.
56*e0c4386eSCy Schubert                Note: this option is cumulative.  If not given at all, all
57*e0c4386eSCy Schubert                internal modules will be considered.
58*e0c4386eSCy Schubert
59*e0c4386eSCy Schubert    -nowrite    Do not write the header/source files, even if changed.
60*e0c4386eSCy Schubert
61*e0c4386eSCy Schubert    -rebuild    Rebuild all header and C source files, even if there
62*e0c4386eSCy Schubert                were no changes.
63*e0c4386eSCy Schubert
64*e0c4386eSCy Schubert    -reindex    Ignore previously assigned values (except for R records in
65*e0c4386eSCy Schubert                the config file) and renumber everything starting at 100.
66*e0c4386eSCy Schubert
67*e0c4386eSCy Schubert    -static     Make the load/unload functions static.
68*e0c4386eSCy Schubert
69*e0c4386eSCy Schubert    -unref      List all unreferenced function and reason codes on stderr;
70*e0c4386eSCy Schubert                implies -nowrite.
71*e0c4386eSCy Schubert
72*e0c4386eSCy Schubert    -help       Show this help text.
73*e0c4386eSCy Schubert
74*e0c4386eSCy Schubert    ...         Additional arguments are added to the file list to scan,
75*e0c4386eSCy Schubert                if '-internal' was NOT specified on the command line.
76*e0c4386eSCy Schubert
77*e0c4386eSCy SchubertEOF
78*e0c4386eSCy Schubert}
79*e0c4386eSCy Schubert
80*e0c4386eSCy Schubertwhile ( @ARGV ) {
81*e0c4386eSCy Schubert    my $arg = $ARGV[0];
82*e0c4386eSCy Schubert    last unless $arg =~ /-.*/;
83*e0c4386eSCy Schubert    $arg = $1 if $arg =~ /-(-.*)/;
84*e0c4386eSCy Schubert    if ( $arg eq "-conf" ) {
85*e0c4386eSCy Schubert        $config = $ARGV[1];
86*e0c4386eSCy Schubert        shift @ARGV;
87*e0c4386eSCy Schubert    } elsif ( $arg eq "-debug" ) {
88*e0c4386eSCy Schubert        $debug = 1;
89*e0c4386eSCy Schubert        $unref = 1;
90*e0c4386eSCy Schubert    } elsif ( $arg eq "-internal" ) {
91*e0c4386eSCy Schubert        $internal = 1;
92*e0c4386eSCy Schubert    } elsif ( $arg eq "-nowrite" ) {
93*e0c4386eSCy Schubert        $nowrite = 1;
94*e0c4386eSCy Schubert    } elsif ( $arg eq "-rebuild" ) {
95*e0c4386eSCy Schubert        $rebuild = 1;
96*e0c4386eSCy Schubert    } elsif ( $arg eq "-reindex" ) {
97*e0c4386eSCy Schubert        $reindex = 1;
98*e0c4386eSCy Schubert    } elsif ( $arg eq "-static" ) {
99*e0c4386eSCy Schubert        $static = 1;
100*e0c4386eSCy Schubert    } elsif ( $arg eq "-unref" ) {
101*e0c4386eSCy Schubert        $unref = 1;
102*e0c4386eSCy Schubert        $nowrite = 1;
103*e0c4386eSCy Schubert    } elsif ( $arg eq "-module" ) {
104*e0c4386eSCy Schubert        shift @ARGV;
105*e0c4386eSCy Schubert        $modules{uc $ARGV[0]} = 1;
106*e0c4386eSCy Schubert    } elsif ( $arg =~ /-*h(elp)?/ ) {
107*e0c4386eSCy Schubert        &help();
108*e0c4386eSCy Schubert        exit;
109*e0c4386eSCy Schubert    } elsif ( $arg =~ /-.*/ ) {
110*e0c4386eSCy Schubert        die "Unknown option $arg; use -h for help.\n";
111*e0c4386eSCy Schubert    }
112*e0c4386eSCy Schubert    shift @ARGV;
113*e0c4386eSCy Schubert}
114*e0c4386eSCy Schubert
115*e0c4386eSCy Schubertmy @source;
116*e0c4386eSCy Schubertif ( $internal ) {
117*e0c4386eSCy Schubert    die "Cannot mix -internal and -static\n" if $static;
118*e0c4386eSCy Schubert    die "Extra parameters given.\n" if @ARGV;
119*e0c4386eSCy Schubert    @source = ( glob('crypto/*.c'), glob('crypto/*/*.c'),
120*e0c4386eSCy Schubert                glob('ssl/*.c'), glob('ssl/*/*.c'), glob('providers/*.c'),
121*e0c4386eSCy Schubert                glob('providers/*/*.c'), glob('providers/*/*/*.c') );
122*e0c4386eSCy Schubert} else {
123*e0c4386eSCy Schubert    die "-module isn't useful without -internal\n" if scalar keys %modules > 0;
124*e0c4386eSCy Schubert    @source = @ARGV;
125*e0c4386eSCy Schubert}
126*e0c4386eSCy Schubert
127*e0c4386eSCy Schubert# Data parsed out of the config and state files.
128*e0c4386eSCy Schubertmy %hpubinc;    # lib -> public header
129*e0c4386eSCy Schubertmy %libpubinc;  # public header -> lib
130*e0c4386eSCy Schubertmy %hprivinc;   # lib -> private header
131*e0c4386eSCy Schubertmy %libprivinc; # private header -> lib
132*e0c4386eSCy Schubertmy %cskip;      # error_file -> lib
133*e0c4386eSCy Schubertmy %errorfile;  # lib -> error file name
134*e0c4386eSCy Schubertmy %rmax;       # lib -> max assigned reason code
135*e0c4386eSCy Schubertmy %rassigned;  # lib -> colon-separated list of assigned reason codes
136*e0c4386eSCy Schubertmy %rnew;       # lib -> count of new reason codes
137*e0c4386eSCy Schubertmy %rextra;     # "extra" reason code -> lib
138*e0c4386eSCy Schubertmy %rcodes;     # reason-name -> value
139*e0c4386eSCy Schubertmy $statefile;  # state file with assigned reason and function codes
140*e0c4386eSCy Schubertmy %strings;    # define -> text
141*e0c4386eSCy Schubert
142*e0c4386eSCy Schubert# Read and parse the config file
143*e0c4386eSCy Schubertopen(IN, "$config") || die "Can't open config file $config, $!,";
144*e0c4386eSCy Schubertwhile ( <IN> ) {
145*e0c4386eSCy Schubert    next if /^#/ || /^$/;
146*e0c4386eSCy Schubert    if ( /^L\s+(\S+)\s+(\S+)\s+(\S+)(?:\s+(\S+))?\s+$/ ) {
147*e0c4386eSCy Schubert        my $lib = $1;
148*e0c4386eSCy Schubert        my $pubhdr = $2;
149*e0c4386eSCy Schubert        my $err = $3;
150*e0c4386eSCy Schubert        my $privhdr = $4 // 'NONE';
151*e0c4386eSCy Schubert        $hpubinc{$lib}   = $pubhdr;
152*e0c4386eSCy Schubert        $libpubinc{$pubhdr} = $lib;
153*e0c4386eSCy Schubert        $hprivinc{$lib}   = $privhdr;
154*e0c4386eSCy Schubert        $libprivinc{$privhdr} = $lib;
155*e0c4386eSCy Schubert        $cskip{$err}  = $lib;
156*e0c4386eSCy Schubert        $errorfile{$lib} = $err;
157*e0c4386eSCy Schubert        next if $err eq 'NONE';
158*e0c4386eSCy Schubert        $rmax{$lib}      = 100;
159*e0c4386eSCy Schubert        $rassigned{$lib} = ":";
160*e0c4386eSCy Schubert        $rnew{$lib}      = 0;
161*e0c4386eSCy Schubert        die "Public header file must be in include/openssl ($pubhdr is not)\n"
162*e0c4386eSCy Schubert            if ($internal
163*e0c4386eSCy Schubert                && $pubhdr ne 'NONE'
164*e0c4386eSCy Schubert                && $pubhdr !~ m|^include/openssl/|);
165*e0c4386eSCy Schubert        die "Private header file may only be specified with -internal ($privhdr given)\n"
166*e0c4386eSCy Schubert            unless ($privhdr eq 'NONE' || $internal);
167*e0c4386eSCy Schubert    } elsif ( /^R\s+(\S+)\s+(\S+)/ ) {
168*e0c4386eSCy Schubert        $rextra{$1} = $2;
169*e0c4386eSCy Schubert        $rcodes{$1} = $2;
170*e0c4386eSCy Schubert    } elsif ( /^S\s+(\S+)/ ) {
171*e0c4386eSCy Schubert        $statefile = $1;
172*e0c4386eSCy Schubert    } else {
173*e0c4386eSCy Schubert        die "Illegal config line $_\n";
174*e0c4386eSCy Schubert    }
175*e0c4386eSCy Schubert}
176*e0c4386eSCy Schubertclose IN;
177*e0c4386eSCy Schubert
178*e0c4386eSCy Schubertif ( ! $statefile ) {
179*e0c4386eSCy Schubert    $statefile = $config;
180*e0c4386eSCy Schubert    $statefile =~ s/.ec/.txt/;
181*e0c4386eSCy Schubert}
182*e0c4386eSCy Schubert
183*e0c4386eSCy Schubert# The statefile has all the previous assignments.
184*e0c4386eSCy Schubert&phase("Reading state");
185*e0c4386eSCy Schubertmy $skippedstate = 0;
186*e0c4386eSCy Schubertif ( ! $reindex && $statefile ) {
187*e0c4386eSCy Schubert    open(STATE, "<$statefile") || die "Can't open $statefile, $!";
188*e0c4386eSCy Schubert
189*e0c4386eSCy Schubert    # Scan function and reason codes and store them: keep a note of the
190*e0c4386eSCy Schubert    # maximum code used.
191*e0c4386eSCy Schubert    while ( <STATE> ) {
192*e0c4386eSCy Schubert        next if /^#/ || /^$/;
193*e0c4386eSCy Schubert        my $name;
194*e0c4386eSCy Schubert        my $code;
195*e0c4386eSCy Schubert        if ( /^(.+):(\d+):\\$/ ) {
196*e0c4386eSCy Schubert            $name = $1;
197*e0c4386eSCy Schubert            $code = $2;
198*e0c4386eSCy Schubert            my $next = <STATE>;
199*e0c4386eSCy Schubert            $next =~ s/^\s*(.*)\s*$/$1/;
200*e0c4386eSCy Schubert            die "Duplicate define $name" if exists $strings{$name};
201*e0c4386eSCy Schubert            $strings{$name} = $next;
202*e0c4386eSCy Schubert        } elsif ( /^(\S+):(\d+):(.*)$/ ) {
203*e0c4386eSCy Schubert            $name = $1;
204*e0c4386eSCy Schubert            $code = $2;
205*e0c4386eSCy Schubert            die "Duplicate define $name" if exists $strings{$name};
206*e0c4386eSCy Schubert            $strings{$name} = $3;
207*e0c4386eSCy Schubert        } else {
208*e0c4386eSCy Schubert            die "Bad line in $statefile:\n$_\n";
209*e0c4386eSCy Schubert        }
210*e0c4386eSCy Schubert        my $lib = $name;
211*e0c4386eSCy Schubert        $lib =~ s/^((?:OSSL_|OPENSSL_)?[^_]{2,}).*$/$1/;
212*e0c4386eSCy Schubert        $lib = "SSL" if $lib =~ /TLS/;
213*e0c4386eSCy Schubert        if ( !defined $errorfile{$lib} ) {
214*e0c4386eSCy Schubert            print "Skipping $_";
215*e0c4386eSCy Schubert            $skippedstate++;
216*e0c4386eSCy Schubert            next;
217*e0c4386eSCy Schubert        }
218*e0c4386eSCy Schubert        next if $errorfile{$lib} eq 'NONE';
219*e0c4386eSCy Schubert        if ( $name =~ /^(?:OSSL_|OPENSSL_)?[A-Z0-9]{2,}_R_/ ) {
220*e0c4386eSCy Schubert            die "$lib reason code $code collision at $name\n"
221*e0c4386eSCy Schubert                if $rassigned{$lib} =~ /:$code:/;
222*e0c4386eSCy Schubert            $rassigned{$lib} .= "$code:";
223*e0c4386eSCy Schubert            if ( !exists $rextra{$name} ) {
224*e0c4386eSCy Schubert                $rmax{$lib} = $code if $code > $rmax{$lib};
225*e0c4386eSCy Schubert            }
226*e0c4386eSCy Schubert            $rcodes{$name} = $code;
227*e0c4386eSCy Schubert        } elsif ( $name =~ /^(?:OSSL_|OPENSSL_)?[A-Z0-9]{2,}_F_/ ) {
228*e0c4386eSCy Schubert            # We do nothing with the function codes, just let them go away
229*e0c4386eSCy Schubert        } else {
230*e0c4386eSCy Schubert            die "Bad line in $statefile:\n$_\n";
231*e0c4386eSCy Schubert        }
232*e0c4386eSCy Schubert    }
233*e0c4386eSCy Schubert    close(STATE);
234*e0c4386eSCy Schubert
235*e0c4386eSCy Schubert    if ( $debug ) {
236*e0c4386eSCy Schubert        foreach my $lib ( sort keys %rmax ) {
237*e0c4386eSCy Schubert            print STDERR "Reason codes for ${lib}:\n";
238*e0c4386eSCy Schubert            if ( $rassigned{$lib} =~ m/^:(.*):$/ ) {
239*e0c4386eSCy Schubert                my @rassigned = sort { $a <=> $b } split( ":", $1 );
240*e0c4386eSCy Schubert                print STDERR "  ", join(' ', @rassigned), "\n";
241*e0c4386eSCy Schubert            } else {
242*e0c4386eSCy Schubert                print STDERR "  --none--\n";
243*e0c4386eSCy Schubert            }
244*e0c4386eSCy Schubert        }
245*e0c4386eSCy Schubert    }
246*e0c4386eSCy Schubert}
247*e0c4386eSCy Schubert
248*e0c4386eSCy Schubert# Scan each C source file and look for reason codes.  This is done by
249*e0c4386eSCy Schubert# looking for strings that "look like" reason codes: basically anything
250*e0c4386eSCy Schubert# consisting of all upper case and numerics which _R_ in it and which has
251*e0c4386eSCy Schubert# the name of an error library at the start.  Should there be anything else,
252*e0c4386eSCy Schubert# such as a type name, we add exceptions here.
253*e0c4386eSCy Schubert# If a code doesn't exist in list compiled from headers then mark it
254*e0c4386eSCy Schubert# with the value "X" as a place holder to give it a value later.
255*e0c4386eSCy Schubert# Store all reason codes found in and %usedreasons so all those unreferenced
256*e0c4386eSCy Schubert# can be printed out.
257*e0c4386eSCy Schubert&phase("Scanning source");
258*e0c4386eSCy Schubertmy %usedreasons;
259*e0c4386eSCy Schubertforeach my $file ( @source ) {
260*e0c4386eSCy Schubert    # Don't parse the error source file.
261*e0c4386eSCy Schubert    next if exists $cskip{$file};
262*e0c4386eSCy Schubert    open( IN, "<$file" ) || die "Can't open $file, $!,";
263*e0c4386eSCy Schubert    my $func;
264*e0c4386eSCy Schubert    my $linenr = 0;
265*e0c4386eSCy Schubert    print STDERR "$file:\n" if $debug;
266*e0c4386eSCy Schubert    while ( <IN> ) {
267*e0c4386eSCy Schubert
268*e0c4386eSCy Schubert        # skip obsoleted source files entirely!
269*e0c4386eSCy Schubert        last if /^#error\s+obsolete/;
270*e0c4386eSCy Schubert        $linenr++;
271*e0c4386eSCy Schubert
272*e0c4386eSCy Schubert        if ( /(((?:OSSL_|OPENSSL_)?[A-Z0-9]{2,})_R_[A-Z0-9_]+)/ ) {
273*e0c4386eSCy Schubert            next unless exists $errorfile{$2};
274*e0c4386eSCy Schubert            next if $errorfile{$2} eq 'NONE';
275*e0c4386eSCy Schubert            $usedreasons{$1} = 1;
276*e0c4386eSCy Schubert            if ( !exists $rcodes{$1} ) {
277*e0c4386eSCy Schubert                print STDERR "  New reason $1\n" if $debug;
278*e0c4386eSCy Schubert                $rcodes{$1} = "X";
279*e0c4386eSCy Schubert                $rnew{$2}++;
280*e0c4386eSCy Schubert            }
281*e0c4386eSCy Schubert            print STDERR "  Reason $1 = $rcodes{$1}\n" if $debug;
282*e0c4386eSCy Schubert        }
283*e0c4386eSCy Schubert    }
284*e0c4386eSCy Schubert    close IN;
285*e0c4386eSCy Schubert}
286*e0c4386eSCy Schubertprint STDERR "\n" if $debug;
287*e0c4386eSCy Schubert
288*e0c4386eSCy Schubert# Now process each library in turn.
289*e0c4386eSCy Schubert&phase("Writing files");
290*e0c4386eSCy Schubertmy $newstate = 0;
291*e0c4386eSCy Schubertforeach my $lib ( keys %errorfile ) {
292*e0c4386eSCy Schubert    next if ! $rnew{$lib} && ! $rebuild;
293*e0c4386eSCy Schubert    next if scalar keys %modules > 0 && !$modules{$lib};
294*e0c4386eSCy Schubert    next if $nowrite;
295*e0c4386eSCy Schubert    print STDERR "$lib: $rnew{$lib} new reasons\n" if $rnew{$lib};
296*e0c4386eSCy Schubert    $newstate = 1;
297*e0c4386eSCy Schubert
298*e0c4386eSCy Schubert    # If we get here then we have some new error codes so we
299*e0c4386eSCy Schubert    # need to rebuild the header file and C file.
300*e0c4386eSCy Schubert
301*e0c4386eSCy Schubert    # Make a sorted list of error and reason codes for later use.
302*e0c4386eSCy Schubert    my @reasons  = sort grep( /^${lib}_/, keys %rcodes );
303*e0c4386eSCy Schubert
304*e0c4386eSCy Schubert    # indent level for innermost preprocessor lines
305*e0c4386eSCy Schubert    my $indent = " ";
306*e0c4386eSCy Schubert
307*e0c4386eSCy Schubert    # Flag if the sub-library is disablable
308*e0c4386eSCy Schubert    # There are a few exceptions, where disabling the sub-library
309*e0c4386eSCy Schubert    # doesn't actually remove the whole sub-library, but rather implements
310*e0c4386eSCy Schubert    # it with a NULL backend.
311*e0c4386eSCy Schubert    my $disablable =
312*e0c4386eSCy Schubert        ($lib ne "SSL" && $lib ne "ASYNC" && $lib ne "DSO"
313*e0c4386eSCy Schubert         && (grep { $lib eq uc $_ } @disablables, @disablables_int));
314*e0c4386eSCy Schubert
315*e0c4386eSCy Schubert    # Rewrite the internal header file if there is one ($internal only!)
316*e0c4386eSCy Schubert
317*e0c4386eSCy Schubert    if ($hprivinc{$lib} ne 'NONE') {
318*e0c4386eSCy Schubert        my $hfile = $hprivinc{$lib};
319*e0c4386eSCy Schubert        my $guard = $hfile;
320*e0c4386eSCy Schubert
321*e0c4386eSCy Schubert        if ($guard =~ m|^include/|) {
322*e0c4386eSCy Schubert            $guard = $';
323*e0c4386eSCy Schubert        } else {
324*e0c4386eSCy Schubert            $guard = basename($guard);
325*e0c4386eSCy Schubert        }
326*e0c4386eSCy Schubert        $guard = "OSSL_" . join('_', split(m|[./]|, uc $guard));
327*e0c4386eSCy Schubert
328*e0c4386eSCy Schubert        open( OUT, ">$hfile" ) || die "Can't write to $hfile, $!,";
329*e0c4386eSCy Schubert        print OUT <<"EOF";
330*e0c4386eSCy Schubert/*
331*e0c4386eSCy Schubert * Generated by util/mkerr.pl DO NOT EDIT
332*e0c4386eSCy Schubert * Copyright 2020-$YEAR The OpenSSL Project Authors. All Rights Reserved.
333*e0c4386eSCy Schubert *
334*e0c4386eSCy Schubert * Licensed under the Apache License 2.0 (the \"License\").  You may not use
335*e0c4386eSCy Schubert * this file except in compliance with the License.  You can obtain a copy
336*e0c4386eSCy Schubert * in the file LICENSE in the source distribution or at
337*e0c4386eSCy Schubert * https://www.openssl.org/source/license.html
338*e0c4386eSCy Schubert */
339*e0c4386eSCy Schubert
340*e0c4386eSCy Schubert#ifndef $guard
341*e0c4386eSCy Schubert# define $guard
342*e0c4386eSCy Schubert# pragma once
343*e0c4386eSCy Schubert
344*e0c4386eSCy Schubert# include <openssl/opensslconf.h>
345*e0c4386eSCy Schubert# include <openssl/symhacks.h>
346*e0c4386eSCy Schubert
347*e0c4386eSCy Schubert# ifdef  __cplusplus
348*e0c4386eSCy Schubertextern \"C\" {
349*e0c4386eSCy Schubert# endif
350*e0c4386eSCy Schubert
351*e0c4386eSCy SchubertEOF
352*e0c4386eSCy Schubert        $indent = ' ';
353*e0c4386eSCy Schubert        if ($disablable) {
354*e0c4386eSCy Schubert            print OUT <<"EOF";
355*e0c4386eSCy Schubert# ifndef OPENSSL_NO_${lib}
356*e0c4386eSCy Schubert
357*e0c4386eSCy SchubertEOF
358*e0c4386eSCy Schubert            $indent = "  ";
359*e0c4386eSCy Schubert        }
360*e0c4386eSCy Schubert        print OUT <<"EOF";
361*e0c4386eSCy Schubertint ossl_err_load_${lib}_strings(void);
362*e0c4386eSCy SchubertEOF
363*e0c4386eSCy Schubert
364*e0c4386eSCy Schubert        # If this library doesn't have a public header file, we write all
365*e0c4386eSCy Schubert        # definitions that would end up there here instead
366*e0c4386eSCy Schubert        if ($hpubinc{$lib} eq 'NONE') {
367*e0c4386eSCy Schubert            print OUT "\n/*\n * $lib reason codes.\n */\n";
368*e0c4386eSCy Schubert            foreach my $i ( @reasons ) {
369*e0c4386eSCy Schubert                my $z = 48 - length($i);
370*e0c4386eSCy Schubert                $z = 0 if $z < 0;
371*e0c4386eSCy Schubert                if ( $rcodes{$i} eq "X" ) {
372*e0c4386eSCy Schubert                    $rassigned{$lib} =~ m/^:([^:]*):/;
373*e0c4386eSCy Schubert                    my $findcode = $1;
374*e0c4386eSCy Schubert                    $findcode = $rmax{$lib} if !defined $findcode;
375*e0c4386eSCy Schubert                    while ( $rassigned{$lib} =~ m/:$findcode:/ ) {
376*e0c4386eSCy Schubert                        $findcode++;
377*e0c4386eSCy Schubert                    }
378*e0c4386eSCy Schubert                    $rcodes{$i} = $findcode;
379*e0c4386eSCy Schubert                    $rassigned{$lib} .= "$findcode:";
380*e0c4386eSCy Schubert                    print STDERR "New Reason code $i\n" if $debug;
381*e0c4386eSCy Schubert                }
382*e0c4386eSCy Schubert                printf OUT "#${indent}define $i%s $rcodes{$i}\n", " " x $z;
383*e0c4386eSCy Schubert            }
384*e0c4386eSCy Schubert            print OUT "\n";
385*e0c4386eSCy Schubert        }
386*e0c4386eSCy Schubert
387*e0c4386eSCy Schubert        # This doesn't go all the way down to zero, to allow for the ending
388*e0c4386eSCy Schubert        # brace for 'extern "C" {'.
389*e0c4386eSCy Schubert        while (length($indent) > 1) {
390*e0c4386eSCy Schubert            $indent = substr $indent, 0, -1;
391*e0c4386eSCy Schubert            print OUT "#${indent}endif\n";
392*e0c4386eSCy Schubert        }
393*e0c4386eSCy Schubert
394*e0c4386eSCy Schubert        print OUT <<"EOF";
395*e0c4386eSCy Schubert
396*e0c4386eSCy Schubert# ifdef  __cplusplus
397*e0c4386eSCy Schubert}
398*e0c4386eSCy Schubert# endif
399*e0c4386eSCy Schubert#endif
400*e0c4386eSCy SchubertEOF
401*e0c4386eSCy Schubert        close OUT;
402*e0c4386eSCy Schubert    }
403*e0c4386eSCy Schubert
404*e0c4386eSCy Schubert    # Rewrite the public header file
405*e0c4386eSCy Schubert
406*e0c4386eSCy Schubert    if ($hpubinc{$lib} ne 'NONE') {
407*e0c4386eSCy Schubert        my $extra_include =
408*e0c4386eSCy Schubert            $internal
409*e0c4386eSCy Schubert            ? ($lib ne 'SSL'
410*e0c4386eSCy Schubert               ? "# include <openssl/cryptoerr_legacy.h>\n"
411*e0c4386eSCy Schubert               : "# include <openssl/sslerr_legacy.h>\n")
412*e0c4386eSCy Schubert            : '';
413*e0c4386eSCy Schubert        my $hfile = $hpubinc{$lib};
414*e0c4386eSCy Schubert        my $guard = $hfile;
415*e0c4386eSCy Schubert        $guard =~ s|^include/||;
416*e0c4386eSCy Schubert        $guard = join('_', split(m|[./]|, uc $guard));
417*e0c4386eSCy Schubert        $guard = "OSSL_" . $guard unless $internal;
418*e0c4386eSCy Schubert
419*e0c4386eSCy Schubert        open( OUT, ">$hfile" ) || die "Can't write to $hfile, $!,";
420*e0c4386eSCy Schubert        print OUT <<"EOF";
421*e0c4386eSCy Schubert/*
422*e0c4386eSCy Schubert * Generated by util/mkerr.pl DO NOT EDIT
423*e0c4386eSCy Schubert * Copyright 1995-$YEAR The OpenSSL Project Authors. All Rights Reserved.
424*e0c4386eSCy Schubert *
425*e0c4386eSCy Schubert * Licensed under the Apache License 2.0 (the \"License\").  You may not use
426*e0c4386eSCy Schubert * this file except in compliance with the License.  You can obtain a copy
427*e0c4386eSCy Schubert * in the file LICENSE in the source distribution or at
428*e0c4386eSCy Schubert * https://www.openssl.org/source/license.html
429*e0c4386eSCy Schubert */
430*e0c4386eSCy Schubert
431*e0c4386eSCy Schubert#ifndef $guard
432*e0c4386eSCy Schubert# define $guard
433*e0c4386eSCy Schubert# pragma once
434*e0c4386eSCy Schubert
435*e0c4386eSCy Schubert# include <openssl/opensslconf.h>
436*e0c4386eSCy Schubert# include <openssl/symhacks.h>
437*e0c4386eSCy Schubert$extra_include
438*e0c4386eSCy Schubert
439*e0c4386eSCy SchubertEOF
440*e0c4386eSCy Schubert        $indent = ' ';
441*e0c4386eSCy Schubert        if ( $internal ) {
442*e0c4386eSCy Schubert            if ($disablable) {
443*e0c4386eSCy Schubert                print OUT <<"EOF";
444*e0c4386eSCy Schubert# ifndef OPENSSL_NO_${lib}
445*e0c4386eSCy Schubert
446*e0c4386eSCy SchubertEOF
447*e0c4386eSCy Schubert                $indent .= ' ';
448*e0c4386eSCy Schubert            }
449*e0c4386eSCy Schubert        } else {
450*e0c4386eSCy Schubert            print OUT <<"EOF";
451*e0c4386eSCy Schubert# define ${lib}err(f, r) ERR_${lib}_error(0, (r), OPENSSL_FILE, OPENSSL_LINE)
452*e0c4386eSCy Schubert
453*e0c4386eSCy SchubertEOF
454*e0c4386eSCy Schubert            if ( ! $static ) {
455*e0c4386eSCy Schubert                print OUT <<"EOF";
456*e0c4386eSCy Schubert
457*e0c4386eSCy Schubert# ifdef  __cplusplus
458*e0c4386eSCy Schubertextern \"C\" {
459*e0c4386eSCy Schubert# endif
460*e0c4386eSCy Schubertint ERR_load_${lib}_strings(void);
461*e0c4386eSCy Schubertvoid ERR_unload_${lib}_strings(void);
462*e0c4386eSCy Schubertvoid ERR_${lib}_error(int function, int reason, const char *file, int line);
463*e0c4386eSCy Schubert# ifdef  __cplusplus
464*e0c4386eSCy Schubert}
465*e0c4386eSCy Schubert# endif
466*e0c4386eSCy SchubertEOF
467*e0c4386eSCy Schubert            }
468*e0c4386eSCy Schubert        }
469*e0c4386eSCy Schubert
470*e0c4386eSCy Schubert        print OUT "\n/*\n * $lib reason codes.\n */\n";
471*e0c4386eSCy Schubert        foreach my $i ( @reasons ) {
472*e0c4386eSCy Schubert            my $z = 48 - length($i);
473*e0c4386eSCy Schubert            $z = 0 if $z < 0;
474*e0c4386eSCy Schubert            if ( $rcodes{$i} eq "X" ) {
475*e0c4386eSCy Schubert                $rassigned{$lib} =~ m/^:([^:]*):/;
476*e0c4386eSCy Schubert                my $findcode = $1;
477*e0c4386eSCy Schubert                $findcode = $rmax{$lib} if !defined $findcode;
478*e0c4386eSCy Schubert                while ( $rassigned{$lib} =~ m/:$findcode:/ ) {
479*e0c4386eSCy Schubert                    $findcode++;
480*e0c4386eSCy Schubert                }
481*e0c4386eSCy Schubert                $rcodes{$i} = $findcode;
482*e0c4386eSCy Schubert                $rassigned{$lib} .= "$findcode:";
483*e0c4386eSCy Schubert                print STDERR "New Reason code $i\n" if $debug;
484*e0c4386eSCy Schubert            }
485*e0c4386eSCy Schubert            printf OUT "#${indent}define $i%s $rcodes{$i}\n", " " x $z;
486*e0c4386eSCy Schubert        }
487*e0c4386eSCy Schubert        print OUT "\n";
488*e0c4386eSCy Schubert
489*e0c4386eSCy Schubert        while (length($indent) > 0) {
490*e0c4386eSCy Schubert            $indent = substr $indent, 0, -1;
491*e0c4386eSCy Schubert            print OUT "#${indent}endif\n";
492*e0c4386eSCy Schubert        }
493*e0c4386eSCy Schubert        close OUT;
494*e0c4386eSCy Schubert    }
495*e0c4386eSCy Schubert
496*e0c4386eSCy Schubert    # Rewrite the C source file containing the error details.
497*e0c4386eSCy Schubert
498*e0c4386eSCy Schubert    if ($errorfile{$lib} ne 'NONE') {
499*e0c4386eSCy Schubert        # First, read any existing reason string definitions:
500*e0c4386eSCy Schubert        my $cfile = $errorfile{$lib};
501*e0c4386eSCy Schubert        my $pack_lib = $internal ? "ERR_LIB_${lib}" : "0";
502*e0c4386eSCy Schubert        my $hpubincf = $hpubinc{$lib};
503*e0c4386eSCy Schubert        my $hprivincf = $hprivinc{$lib};
504*e0c4386eSCy Schubert        my $includes = '';
505*e0c4386eSCy Schubert        if ($internal) {
506*e0c4386eSCy Schubert            if ($hpubincf ne 'NONE') {
507*e0c4386eSCy Schubert                $hpubincf =~ s|^include/||;
508*e0c4386eSCy Schubert                $includes .= "#include <${hpubincf}>\n";
509*e0c4386eSCy Schubert            }
510*e0c4386eSCy Schubert            if ($hprivincf =~ m|^include/|) {
511*e0c4386eSCy Schubert                $hprivincf = $';
512*e0c4386eSCy Schubert            } else {
513*e0c4386eSCy Schubert                $hprivincf = abs2rel(rel2abs($hprivincf),
514*e0c4386eSCy Schubert                                     rel2abs(dirname($cfile)));
515*e0c4386eSCy Schubert            }
516*e0c4386eSCy Schubert            $includes .= "#include \"${hprivincf}\"\n";
517*e0c4386eSCy Schubert        } else {
518*e0c4386eSCy Schubert            $includes .= "#include \"${hpubincf}\"\n";
519*e0c4386eSCy Schubert        }
520*e0c4386eSCy Schubert
521*e0c4386eSCy Schubert        open( OUT, ">$cfile" )
522*e0c4386eSCy Schubert            || die "Can't open $cfile for writing, $!, stopped";
523*e0c4386eSCy Schubert
524*e0c4386eSCy Schubert        my $const = $internal ? 'const ' : '';
525*e0c4386eSCy Schubert
526*e0c4386eSCy Schubert        print OUT <<"EOF";
527*e0c4386eSCy Schubert/*
528*e0c4386eSCy Schubert * Generated by util/mkerr.pl DO NOT EDIT
529*e0c4386eSCy Schubert * Copyright 1995-$YEAR The OpenSSL Project Authors. All Rights Reserved.
530*e0c4386eSCy Schubert *
531*e0c4386eSCy Schubert * Licensed under the Apache License 2.0 (the "License").  You may not use
532*e0c4386eSCy Schubert * this file except in compliance with the License.  You can obtain a copy
533*e0c4386eSCy Schubert * in the file LICENSE in the source distribution or at
534*e0c4386eSCy Schubert * https://www.openssl.org/source/license.html
535*e0c4386eSCy Schubert */
536*e0c4386eSCy Schubert
537*e0c4386eSCy Schubert#include <openssl/err.h>
538*e0c4386eSCy Schubert$includes
539*e0c4386eSCy SchubertEOF
540*e0c4386eSCy Schubert        $indent = '';
541*e0c4386eSCy Schubert        if ( $internal ) {
542*e0c4386eSCy Schubert            if ($disablable) {
543*e0c4386eSCy Schubert                print OUT <<"EOF";
544*e0c4386eSCy Schubert#ifndef OPENSSL_NO_${lib}
545*e0c4386eSCy Schubert
546*e0c4386eSCy SchubertEOF
547*e0c4386eSCy Schubert                $indent .= ' ';
548*e0c4386eSCy Schubert            }
549*e0c4386eSCy Schubert        }
550*e0c4386eSCy Schubert        print OUT <<"EOF";
551*e0c4386eSCy Schubert#${indent}ifndef OPENSSL_NO_ERR
552*e0c4386eSCy Schubert
553*e0c4386eSCy Schubertstatic ${const}ERR_STRING_DATA ${lib}_str_reasons[] = {
554*e0c4386eSCy SchubertEOF
555*e0c4386eSCy Schubert
556*e0c4386eSCy Schubert        # Add each reason code.
557*e0c4386eSCy Schubert        foreach my $i ( @reasons ) {
558*e0c4386eSCy Schubert            my $rn;
559*e0c4386eSCy Schubert            if ( exists $strings{$i} ) {
560*e0c4386eSCy Schubert                $rn = $strings{$i};
561*e0c4386eSCy Schubert                $rn = "" if $rn eq '*';
562*e0c4386eSCy Schubert            } else {
563*e0c4386eSCy Schubert                $i =~ /^${lib}_R_(\S+)$/;
564*e0c4386eSCy Schubert                $rn = $1;
565*e0c4386eSCy Schubert                $rn =~ tr/_[A-Z]/ [a-z]/;
566*e0c4386eSCy Schubert                $strings{$i} = $rn;
567*e0c4386eSCy Schubert            }
568*e0c4386eSCy Schubert            my $short = "    {ERR_PACK($pack_lib, 0, $i), \"$rn\"},";
569*e0c4386eSCy Schubert            if ( length($short) <= 80 ) {
570*e0c4386eSCy Schubert                print OUT "$short\n";
571*e0c4386eSCy Schubert            } else {
572*e0c4386eSCy Schubert                print OUT "    {ERR_PACK($pack_lib, 0, $i),\n    \"$rn\"},\n";
573*e0c4386eSCy Schubert            }
574*e0c4386eSCy Schubert        }
575*e0c4386eSCy Schubert        print OUT <<"EOF";
576*e0c4386eSCy Schubert    {0, NULL}
577*e0c4386eSCy Schubert};
578*e0c4386eSCy Schubert
579*e0c4386eSCy Schubert#${indent}endif
580*e0c4386eSCy SchubertEOF
581*e0c4386eSCy Schubert        if ( $internal ) {
582*e0c4386eSCy Schubert            print OUT <<"EOF";
583*e0c4386eSCy Schubert
584*e0c4386eSCy Schubertint ossl_err_load_${lib}_strings(void)
585*e0c4386eSCy Schubert{
586*e0c4386eSCy Schubert#${indent}ifndef OPENSSL_NO_ERR
587*e0c4386eSCy Schubert    if (ERR_reason_error_string(${lib}_str_reasons[0].error) == NULL)
588*e0c4386eSCy Schubert        ERR_load_strings_const(${lib}_str_reasons);
589*e0c4386eSCy Schubert#${indent}endif
590*e0c4386eSCy Schubert    return 1;
591*e0c4386eSCy Schubert}
592*e0c4386eSCy SchubertEOF
593*e0c4386eSCy Schubert        } else {
594*e0c4386eSCy Schubert            my $st = $static ? "static " : "";
595*e0c4386eSCy Schubert            print OUT <<"EOF";
596*e0c4386eSCy Schubert
597*e0c4386eSCy Schubertstatic int lib_code = 0;
598*e0c4386eSCy Schubertstatic int error_loaded = 0;
599*e0c4386eSCy Schubert
600*e0c4386eSCy Schubert${st}int ERR_load_${lib}_strings(void)
601*e0c4386eSCy Schubert{
602*e0c4386eSCy Schubert    if (lib_code == 0)
603*e0c4386eSCy Schubert        lib_code = ERR_get_next_error_library();
604*e0c4386eSCy Schubert
605*e0c4386eSCy Schubert    if (!error_loaded) {
606*e0c4386eSCy Schubert#ifndef OPENSSL_NO_ERR
607*e0c4386eSCy Schubert        ERR_load_strings(lib_code, ${lib}_str_reasons);
608*e0c4386eSCy Schubert#endif
609*e0c4386eSCy Schubert        error_loaded = 1;
610*e0c4386eSCy Schubert    }
611*e0c4386eSCy Schubert    return 1;
612*e0c4386eSCy Schubert}
613*e0c4386eSCy Schubert
614*e0c4386eSCy Schubert${st}void ERR_unload_${lib}_strings(void)
615*e0c4386eSCy Schubert{
616*e0c4386eSCy Schubert    if (error_loaded) {
617*e0c4386eSCy Schubert#ifndef OPENSSL_NO_ERR
618*e0c4386eSCy Schubert        ERR_unload_strings(lib_code, ${lib}_str_reasons);
619*e0c4386eSCy Schubert#endif
620*e0c4386eSCy Schubert        error_loaded = 0;
621*e0c4386eSCy Schubert    }
622*e0c4386eSCy Schubert}
623*e0c4386eSCy Schubert
624*e0c4386eSCy Schubert${st}void ERR_${lib}_error(int function, int reason, const char *file, int line)
625*e0c4386eSCy Schubert{
626*e0c4386eSCy Schubert    if (lib_code == 0)
627*e0c4386eSCy Schubert        lib_code = ERR_get_next_error_library();
628*e0c4386eSCy Schubert    ERR_raise(lib_code, reason);
629*e0c4386eSCy Schubert    ERR_set_debug(file, line, NULL);
630*e0c4386eSCy Schubert}
631*e0c4386eSCy SchubertEOF
632*e0c4386eSCy Schubert
633*e0c4386eSCy Schubert        }
634*e0c4386eSCy Schubert
635*e0c4386eSCy Schubert        while (length($indent) > 1) {
636*e0c4386eSCy Schubert            $indent = substr $indent, 0, -1;
637*e0c4386eSCy Schubert            print OUT "#${indent}endif\n";
638*e0c4386eSCy Schubert        }
639*e0c4386eSCy Schubert        if ($internal && $disablable) {
640*e0c4386eSCy Schubert            print OUT <<"EOF";
641*e0c4386eSCy Schubert#else
642*e0c4386eSCy SchubertNON_EMPTY_TRANSLATION_UNIT
643*e0c4386eSCy Schubert#endif
644*e0c4386eSCy SchubertEOF
645*e0c4386eSCy Schubert        }
646*e0c4386eSCy Schubert        close OUT;
647*e0c4386eSCy Schubert    }
648*e0c4386eSCy Schubert}
649*e0c4386eSCy Schubert
650*e0c4386eSCy Schubert&phase("Ending");
651*e0c4386eSCy Schubert# Make a list of unreferenced reason codes
652*e0c4386eSCy Schubertif ( $unref ) {
653*e0c4386eSCy Schubert    my @runref;
654*e0c4386eSCy Schubert    foreach ( keys %rcodes ) {
655*e0c4386eSCy Schubert        push( @runref, $_ ) unless exists $usedreasons{$_};
656*e0c4386eSCy Schubert    }
657*e0c4386eSCy Schubert    if ( @runref ) {
658*e0c4386eSCy Schubert        print STDERR "The following reason codes were not referenced:\n";
659*e0c4386eSCy Schubert        foreach ( sort @runref ) {
660*e0c4386eSCy Schubert            print STDERR "  $_\n";
661*e0c4386eSCy Schubert        }
662*e0c4386eSCy Schubert    }
663*e0c4386eSCy Schubert}
664*e0c4386eSCy Schubert
665*e0c4386eSCy Schubertdie "Found $errors errors, quitting" if $errors;
666*e0c4386eSCy Schubert
667*e0c4386eSCy Schubert# Update the state file
668*e0c4386eSCy Schubertif ( $newstate )  {
669*e0c4386eSCy Schubert    open(OUT, ">$statefile.new")
670*e0c4386eSCy Schubert        || die "Can't write $statefile.new, $!";
671*e0c4386eSCy Schubert    print OUT <<"EOF";
672*e0c4386eSCy Schubert# Copyright 1999-$YEAR The OpenSSL Project Authors. All Rights Reserved.
673*e0c4386eSCy Schubert#
674*e0c4386eSCy Schubert# Licensed under the Apache License 2.0 (the "License").  You may not use
675*e0c4386eSCy Schubert# this file except in compliance with the License.  You can obtain a copy
676*e0c4386eSCy Schubert# in the file LICENSE in the source distribution or at
677*e0c4386eSCy Schubert# https://www.openssl.org/source/license.html
678*e0c4386eSCy SchubertEOF
679*e0c4386eSCy Schubert    print OUT "\n#Reason codes\n";
680*e0c4386eSCy Schubert    foreach my $i ( sort keys %rcodes ) {
681*e0c4386eSCy Schubert        my $short = "$i:$rcodes{$i}:";
682*e0c4386eSCy Schubert        my $t = exists $strings{$i} ? "$strings{$i}" : "";
683*e0c4386eSCy Schubert        $t = "\\\n\t" . $t if length($short) + length($t) > 80;
684*e0c4386eSCy Schubert        print OUT "$short$t\n" if !exists $rextra{$i};
685*e0c4386eSCy Schubert    }
686*e0c4386eSCy Schubert    close(OUT);
687*e0c4386eSCy Schubert    if ( $skippedstate ) {
688*e0c4386eSCy Schubert        print "Skipped state, leaving update in $statefile.new";
689*e0c4386eSCy Schubert    } else {
690*e0c4386eSCy Schubert        rename "$statefile", "$statefile.old"
691*e0c4386eSCy Schubert            || die "Can't backup $statefile to $statefile.old, $!";
692*e0c4386eSCy Schubert        rename "$statefile.new", "$statefile"
693*e0c4386eSCy Schubert            || die "Can't rename $statefile to $statefile.new, $!";
694*e0c4386eSCy Schubert    }
695*e0c4386eSCy Schubert}
696*e0c4386eSCy Schubert
697*e0c4386eSCy Schubertexit;
698