| lh | 9ed821d | 2023-04-07 01:36:19 -0700 | [diff] [blame] | 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 |  | 
|  | 9 | use strict; | 
|  | 10 | use warnings; | 
|  | 11 |  | 
|  | 12 | use lib "."; | 
|  | 13 | use configdata; | 
|  | 14 |  | 
|  | 15 | my $config       = "crypto/err/openssl.ec"; | 
|  | 16 | my $debug        = 0; | 
|  | 17 | my $internal     = 0; | 
|  | 18 | my $nowrite      = 0; | 
|  | 19 | my $rebuild      = 0; | 
|  | 20 | my $reindex      = 0; | 
|  | 21 | my $static       = 0; | 
|  | 22 | my $unref        = 0; | 
|  | 23 | my %modules         = (); | 
|  | 24 |  | 
|  | 25 | my $errors       = 0; | 
|  | 26 | my @t            = localtime(); | 
|  | 27 | my $YEAR         = $t[5] + 1900; | 
|  | 28 |  | 
|  | 29 | sub phase | 
|  | 30 | { | 
|  | 31 | my $text = uc(shift); | 
|  | 32 | print STDERR "\n---\n$text\n" if $debug; | 
|  | 33 | } | 
|  | 34 |  | 
|  | 35 | sub help | 
|  | 36 | { | 
|  | 37 | print STDERR <<"EOF"; | 
|  | 38 | mkerr.pl [options] [files...] | 
|  | 39 |  | 
|  | 40 | Options: | 
|  | 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 |  | 
|  | 74 | EOF | 
|  | 75 | } | 
|  | 76 |  | 
|  | 77 | while ( @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 |  | 
|  | 112 | my @source; | 
|  | 113 | if ( $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. | 
|  | 124 | my %hinc;       # lib -> header | 
|  | 125 | my %libinc;     # header -> lib | 
|  | 126 | my %cskip;      # error_file -> lib | 
|  | 127 | my %errorfile;  # lib -> error file name | 
|  | 128 | my %fmax;       # lib -> max assigned function code | 
|  | 129 | my %rmax;       # lib -> max assigned reason code | 
|  | 130 | my %fassigned;  # lib -> colon-separated list of assigned function codes | 
|  | 131 | my %rassigned;  # lib -> colon-separated list of assigned reason codes | 
|  | 132 | my %fnew;       # lib -> count of new function codes | 
|  | 133 | my %rnew;       # lib -> count of new reason codes | 
|  | 134 | my %rextra;     # "extra" reason code -> lib | 
|  | 135 | my %rcodes;     # reason-name -> value | 
|  | 136 | my %ftrans;     # old name -> #define-friendly name (all caps) | 
|  | 137 | my %fcodes;     # function-name -> value | 
|  | 138 | my $statefile;  # state file with assigned reason and function codes | 
|  | 139 | my %strings;    # define -> text | 
|  | 140 |  | 
|  | 141 | # Read and parse the config file | 
|  | 142 | open(IN, "$config") || die "Can't open config file $config, $!,"; | 
|  | 143 | while ( <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 | } | 
|  | 169 | close IN; | 
|  | 170 |  | 
|  | 171 | if ( ! $statefile ) { | 
|  | 172 | $statefile = $config; | 
|  | 173 | $statefile =~ s/.ec/.txt/; | 
|  | 174 | } | 
|  | 175 |  | 
|  | 176 | # The statefile has all the previous assignments. | 
|  | 177 | &phase("Reading state"); | 
|  | 178 | my $skippedstate = 0; | 
|  | 179 | if ( ! $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"); | 
|  | 257 | while ( ( 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 | } | 
|  | 351 | print 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"); | 
|  | 364 | my %usedfuncs; | 
|  | 365 | my %usedreasons; | 
|  | 366 | foreach 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 | } | 
|  | 414 | print STDERR "\n" if $debug; | 
|  | 415 |  | 
|  | 416 | # Now process each library in turn. | 
|  | 417 | &phase("Writing files"); | 
|  | 418 | my $newstate = 0; | 
|  | 419 | foreach 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 |  | 
|  | 458 | EOF | 
|  | 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 |  | 
|  | 469 | EOF | 
|  | 470 | $indent = "  "; | 
|  | 471 | } | 
|  | 472 | print OUT <<"EOF"; | 
|  | 473 | #${indent}ifdef  __cplusplus | 
|  | 474 | extern \"C\" | 
|  | 475 | #${indent}endif | 
|  | 476 | int ERR_load_${lib}_strings(void); | 
|  | 477 | EOF | 
|  | 478 | } else { | 
|  | 479 | print OUT <<"EOF"; | 
|  | 480 | # define ${lib}err(f, r) ERR_${lib}_error((f), (r), OPENSSL_FILE, OPENSSL_LINE) | 
|  | 481 |  | 
|  | 482 | EOF | 
|  | 483 | if ( ! $static ) { | 
|  | 484 | print OUT <<"EOF"; | 
|  | 485 |  | 
|  | 486 | # ifdef  __cplusplus | 
|  | 487 | extern \"C\" { | 
|  | 488 | # endif | 
|  | 489 | int ERR_load_${lib}_strings(void); | 
|  | 490 | void ERR_unload_${lib}_strings(void); | 
|  | 491 | void ERR_${lib}_error(int function, int reason, char *file, int line); | 
|  | 492 | # ifdef  __cplusplus | 
|  | 493 | } | 
|  | 494 | # endif | 
|  | 495 | EOF | 
|  | 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 |  | 
|  | 575 | static ${const}ERR_STRING_DATA ${lib}_str_functs[] = { | 
|  | 576 | EOF | 
|  | 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 |  | 
|  | 601 | static ${const}ERR_STRING_DATA ${lib}_str_reasons[] = { | 
|  | 602 | EOF | 
|  | 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 | 
|  | 628 | EOF | 
|  | 629 | if ( $internal ) { | 
|  | 630 | print OUT <<"EOF"; | 
|  | 631 |  | 
|  | 632 | int 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 | } | 
|  | 642 | EOF | 
|  | 643 | } else { | 
|  | 644 | my $st = $static ? "static " : ""; | 
|  | 645 | print OUT <<"EOF"; | 
|  | 646 |  | 
|  | 647 | static int lib_code = 0; | 
|  | 648 | static 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 | } | 
|  | 682 | EOF | 
|  | 683 |  | 
|  | 684 | } | 
|  | 685 |  | 
|  | 686 | close OUT; | 
|  | 687 | } | 
|  | 688 |  | 
|  | 689 | &phase("Ending"); | 
|  | 690 | # Make a list of unreferenced function and reason codes | 
|  | 691 | if ( $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 |  | 
|  | 714 | die "Found $errors errors, quitting" if $errors; | 
|  | 715 |  | 
|  | 716 | # Update the state file | 
|  | 717 | if ( $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 | 
|  | 727 | EOF | 
|  | 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 |  | 
|  | 753 | exit; |