--- a/lib/Makefile +++ b/lib/Makefile @@ -271,7 +271,7 @@ $(call cmd,build_OID_registry) quiet_cmd_build_OID_registry = GEN $@ - cmd_build_OID_registry = perl $(srctree)/$(src)/build_OID_registry $< $@ + cmd_build_OID_registry = $(CONFIG_SHELL) $(srctree)/$(src)/build_OID_registry <$< >$@ clean-files += oid_registry_data.c --- a/lib/build_OID_registry +++ b/lib/build_OID_registry @@ -1,4 +1,4 @@ -#!/usr/bin/perl -w +#!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later # # Build a static ASN.1 Object Identified (OID) registry @@ -7,197 +7,93 @@ # Written by David Howells (dhowells@redhat.com) # -use strict; - -my @names = (); -my @oids = (); - -if ($#ARGV != 1) { - print STDERR "Format: ", $0, " \n"; - exit(2); -} - # -# Open the file to read from +# Read OID lines and determine the lengths of the encoded data arrays. # -open IN_FILE, "<$ARGV[0]" || die; -while () { - chomp; - if (m!\s+OID_([a-zA-z][a-zA-Z0-9_]+),\s+/[*]\s+([012][.0-9]*)\s+[*]/!) { - push @names, $1; - push @oids, $2; - } -} -close IN_FILE || die; +set -f -- # use "$@" array for data +total_length=0 IFS='.' +while IFS=' ' read -r line; do + if [ "${line#OID_[a-z]}" != "$line" ]; then + name="${line#*_}" name="${name%,*}" oid="${line#*/* }" oid="${oid% */}" + # shellcheck disable=SC2086 + size="$(set -- $oid; printf '%u' "$(($# - 1))")" + for c in $oid; do + # We will base128 encode the number + : "$((size += c ? $(awk "BEGIN{print int(log($c)/log(2)/7)}") : 0))" + done + set -- "$@" "$name:$oid:$total_length" + : "$((total_length += size))" + fi +done # -# Open the files to write into -# -open C_FILE, ">$ARGV[1]" or die; -print C_FILE "/*\n"; -print C_FILE " * Automatically generated by ", $0, ". Do not edit\n"; -print C_FILE " */\n"; - -# -# Split the data up into separate lists and also determine the lengths of the -# encoded data arrays. -# -my @indices = (); -my @lengths = (); -my $total_length = 0; - -for (my $i = 0; $i <= $#names; $i++) { - my $name = $names[$i]; - my $oid = $oids[$i]; - - my @components = split(/[.]/, $oid); - - # Determine the encoded length of this OID - my $size = $#components; - for (my $loop = 2; $loop <= $#components; $loop++) { - my $c = $components[$loop]; - - # We will base128 encode the number - my $tmp = ($c == 0) ? 0 : int(log($c)/log(2)); - $tmp = int($tmp / 7); - $size += $tmp; - } - push @lengths, $size; - push @indices, $total_length; - $total_length += $size; -} - -# # Emit the look-up-by-OID index table # -print C_FILE "\n"; -if ($total_length <= 255) { - print C_FILE "static const unsigned char oid_index[OID__NR + 1] = {\n"; -} else { - print C_FILE "static const unsigned short oid_index[OID__NR + 1] = {\n"; -} -for (my $i = 0; $i <= $#names; $i++) { - print C_FILE "\t[OID_", $names[$i], "] = ", $indices[$i], ",\n" -} -print C_FILE "\t[OID__NR] = ", $total_length, "\n"; -print C_FILE "};\n"; +printf '/*\n * Automatically generated by %s. Do not edit\n */\n\n' "$0" +if [ "$total_length" -le 255 ]; then + printf 'static const unsigned char oid_index[OID__NR + 1] = {\n' +else + printf 'static const unsigned short oid_index[OID__NR + 1] = {\n' +fi +for i do + printf '\t[OID_%s] = %u,\n' "${i%%:*}" "${i##*:}" +done +printf '\t[OID__NR] = %u\n};\n\n' "$total_length" # -# Encode the OIDs +# Encode the OIDs and emit the OID data # -my @encoded_oids = (); +printf 'static const unsigned char oid_data[%u] = {\n' "$total_length" +for i do + IFS='.' j=0 i="${i%:*}" + for c in ${i##*:}; do + case "$((j += 1))" in + 1) o="$((c * 40))";; + 2) : "$((o += c))";; + *) + # Base128 encode the number + tmp="$((c ? $(awk "BEGIN{print int(log($c)/log(2)/7)+1}") : 1))" + while [ "$((tmp -= 1))" -gt 0 ]; do + o="$o.$((c >> tmp * 7 & 127 | 128))" + done + o="$o.$((c & 127))" + esac + done -for (my $i = 0; $i <= $#names; $i++) { - my @octets = (); + set -- "$@" "${i%:*}:$o" + shift - my @components = split(/[.]/, $oids[$i]); + printf '\t' + printf '%s, ' $o + printf '\t// %s\n' "${i%:*}" +done +printf '};\n\n' - push @octets, $components[0] * 40 + $components[1]; +printf 'static const struct {\n\tunsigned char hash;\n' +printf '\tenum OID oid : %u;\n} oid_search_table[OID__NR] = {' \ + "$(($# <= 255 ? 8 : 16))" - for (my $loop = 2; $loop <= $#components; $loop++) { - my $c = $components[$loop]; - - # Base128 encode the number - my $tmp = ($c == 0) ? 0 : int(log($c)/log(2)); - $tmp = int($tmp / 7); - - for (; $tmp > 0; $tmp--) { - push @octets, (($c >> $tmp * 7) & 0x7f) | 0x80; - } - push @octets, $c & 0x7f; - } - - push @encoded_oids, \@octets; -} - # -# Create a hash value for each OID +# Create a hash value for each OID and build and emit the search index and hash +# value table (ordered by length then hash then content) # -my @hash_values = (); -for (my $i = 0; $i <= $#names; $i++) { - my @octets = @{$encoded_oids[$i]}; - - my $hash = $#octets; - foreach (@octets) { - $hash += $_ * 33; - } - - $hash = ($hash >> 24) ^ ($hash >> 16) ^ ($hash >> 8) ^ ($hash); - - push @hash_values, $hash & 0xff; -} - -# -# Emit the OID data -# -print C_FILE "\n"; -print C_FILE "static const unsigned char oid_data[", $total_length, "] = {\n"; -for (my $i = 0; $i <= $#names; $i++) { - my @octets = @{$encoded_oids[$i]}; - print C_FILE "\t"; - print C_FILE $_, ", " foreach (@octets); - print C_FILE "\t// ", $names[$i]; - print C_FILE "\n"; -} -print C_FILE "};\n"; - -# -# Build the search index table (ordered by length then hash then content) -# -my @index_table = ( 0 .. $#names ); - -@index_table = sort { - my @octets_a = @{$encoded_oids[$a]}; - my @octets_b = @{$encoded_oids[$b]}; - - return $hash_values[$a] <=> $hash_values[$b] - if ($hash_values[$a] != $hash_values[$b]); - return $#octets_a <=> $#octets_b - if ($#octets_a != $#octets_b); - for (my $i = $#octets_a; $i >= 0; $i--) { - return $octets_a[$i] <=> $octets_b[$i] - if ($octets_a[$i] != $octets_b[$i]); - } - return 0; - -} @index_table; - -# -# Emit the search index and hash value table -# -print C_FILE "\n"; -print C_FILE "static const struct {\n"; -print C_FILE "\tunsigned char hash;\n"; -if ($#names <= 255) { - print C_FILE "\tenum OID oid : 8;\n"; -} else { - print C_FILE "\tenum OID oid : 16;\n"; -} -print C_FILE "} oid_search_table[OID__NR] = {\n"; -for (my $i = 0; $i <= $#names; $i++) { - my @octets = @{$encoded_oids[$index_table[$i]]}; - printf(C_FILE "\t[%3u] = { %3u, OID_%-35s }, // ", - $i, - $hash_values[$index_table[$i]], - $names[$index_table[$i]]); - printf C_FILE "%02x", $_ foreach (@octets); - print C_FILE "\n"; -} -print C_FILE "};\n"; - -# -# Emit the OID debugging name table -# -#print C_FILE "\n"; -#print C_FILE "const char *const oid_name_table[OID__NR + 1] = {\n"; -# -#for (my $i = 0; $i <= $#names; $i++) { -# print C_FILE "\t\"", $names[$i], "\",\n" -#} -#print C_FILE "\t\"Unknown-OID\"\n"; -#print C_FILE "};\n"; - -# -# Polish off -# -close C_FILE or die; +i=-1 +for j do + IFS='.' + # shellcheck disable=SC2086 + count="$(set -- ${j##*:}; printf '%u' "$(($# - 1))")" + hash="$count" + set -- # use as array for reversing octet set + for k in ${j##*:}; do + : "$((hash += k * 33))" + set -- "$k" "$@" + done + hash="$((hash >> 24 ^ hash >> 16 ^ hash >> 8 ^ hash & 255))" + IFS=':' + printf '%u:%s:%s:%u:%s\n' "$hash" "${j##*:}" "${j%%:*}" "$count" "$*" +done | sort -nt: -k1,1 -k4,4 -k5 | while IFS=':' read -r num octets name _; do + printf '\n\t[%3u] = { %3u, OID_%-35s }, // ' "$((i += 1))" "$num" "$name" + # shellcheck disable=SC2086 + printf '%02x' $octets +done +printf '\n};\n'