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