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