diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-10-14 22:41:27 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-10-14 22:41:27 -0700 |
commit | c362495586e8a3a6487a318fcd82eaf15ffe2142 (patch) | |
tree | 86f7b195d36ba198f24f86be327f21a8d24ec248 /scripts | |
parent | b70936d9ffbf0f45f4fa13a03122f015f13ecdb0 (diff) | |
parent | ddffeb8c4d0331609ef2581d84de4d763607bd37 (diff) |
Merge 3.7-rc1 into tty-linus
This syncs up the tty-linus branch to the latest in Linus's tree to get all of
the UAPI stuff needed for the next set of patches to merge.
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'scripts')
33 files changed, 2749 insertions, 171 deletions
diff --git a/scripts/.gitignore b/scripts/.gitignore index 65f362d931b..fb070fa1038 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore @@ -10,3 +10,4 @@ ihex2fw recordmcount docproc sortextable +asn1_compiler diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index 6a3ee981931..978416dd31c 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -98,24 +98,24 @@ try-run = $(shell set -e; \ # Usage: cflags-y += $(call as-option,-Wa$(comma)-isa=foo,) as-option = $(call try-run,\ - $(CC) $(KBUILD_CFLAGS) $(1) -c -xassembler /dev/null -o "$$TMP",$(1),$(2)) + $(CC) $(KBUILD_CFLAGS) $(1) -c -x assembler /dev/null -o "$$TMP",$(1),$(2)) # as-instr # Usage: cflags-y += $(call as-instr,instr,option1,option2) as-instr = $(call try-run,\ - printf "%b\n" "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -xassembler -o "$$TMP" -,$(2),$(3)) + printf "%b\n" "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -x assembler -o "$$TMP" -,$(2),$(3)) # cc-option # Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586) cc-option = $(call try-run,\ - $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",$(1),$(2)) + $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",$(1),$(2)) # cc-option-yn # Usage: flag := $(call cc-option-yn,-march=winchip-c6) cc-option-yn = $(call try-run,\ - $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",y,n) + $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",y,n) # cc-option-align # Prefix align with either -falign or -malign @@ -125,7 +125,7 @@ cc-option-align = $(subst -functions=0,,\ # cc-disable-warning # Usage: cflags-y += $(call cc-disable-warning,unused-but-set-variable) cc-disable-warning = $(call try-run,\ - $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -W$(strip $(1)) -c -xc /dev/null -o "$$TMP",-Wno-$(strip $(1))) + $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -W$(strip $(1)) -c -x c /dev/null -o "$$TMP",-Wno-$(strip $(1))) # cc-version # Usage gcc-ver := $(call cc-version) @@ -143,7 +143,7 @@ cc-ifversion = $(shell [ $(call cc-version, $(CC)) $(1) $(2) ] && echo $(3)) # cc-ldoption # Usage: ldflags += $(call cc-ldoption, -Wl$(comma)--hash-style=both) cc-ldoption = $(call try-run,\ - $(CC) $(1) -nostdlib -xc /dev/null -o "$$TMP",$(1),$(2)) + $(CC) $(1) -nostdlib -x c /dev/null -o "$$TMP",$(1),$(2)) # ld-option # Usage: LDFLAGS += $(call ld-option, -X) @@ -209,7 +209,7 @@ endif # >$< substitution to preserve $ when reloading .cmd file # note: when using inline perl scripts [perl -e '...$$t=1;...'] # in $(cmd_xxx) double $$ your perl vars -make-cmd = $(subst \#,\\\#,$(subst $$,$$$$,$(call escsq,$(cmd_$(1))))) +make-cmd = $(subst \\,\\\\,$(subst \#,\\\#,$(subst $$,$$$$,$(call escsq,$(cmd_$(1)))))) # Find any prerequisites that is newer than target or that does not exist. # PHONY targets skipped in both cases. diff --git a/scripts/Makefile b/scripts/Makefile index a55b0067758..01e7adb838d 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -16,8 +16,10 @@ hostprogs-$(CONFIG_VT) += conmakehash hostprogs-$(CONFIG_IKCONFIG) += bin2c hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable +hostprogs-$(CONFIG_ASN1) += asn1_compiler HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include +HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include always := $(hostprogs-y) $(hostprogs-m) diff --git a/scripts/Makefile.build b/scripts/Makefile.build index ff1720d28d0..0e801c3cdaf 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -354,6 +354,17 @@ quiet_cmd_cpp_lds_S = LDS $@ $(obj)/%.lds: $(src)/%.lds.S FORCE $(call if_changed_dep,cpp_lds_S) +# ASN.1 grammar +# --------------------------------------------------------------------------- +quiet_cmd_asn1_compiler = ASN.1 $@ + cmd_asn1_compiler = $(objtree)/scripts/asn1_compiler $< \ + $(subst .h,.c,$@) $(subst .c,.h,$@) + +.PRECIOUS: $(objtree)/$(obj)/%-asn1.c $(objtree)/$(obj)/%-asn1.h + +$(obj)/%-asn1.c $(obj)/%-asn1.h: $(src)/%.asn1 $(objtree)/scripts/asn1_compiler + $(call cmd,asn1_compiler) + # Build the compiled-in targets # --------------------------------------------------------------------------- diff --git a/scripts/Makefile.fwinst b/scripts/Makefile.fwinst index 4d908d16c03..c3f69ae275d 100644 --- a/scripts/Makefile.fwinst +++ b/scripts/Makefile.fwinst @@ -27,7 +27,7 @@ endif installed-mod-fw := $(addprefix $(INSTALL_FW_PATH)/,$(mod-fw)) installed-fw := $(addprefix $(INSTALL_FW_PATH)/,$(fw-shipped-all)) -installed-fw-dirs := $(sort $(dir $(installed-fw))) $(INSTALL_FW_PATH)/./ +installed-fw-dirs := $(sort $(dir $(installed-fw))) $(INSTALL_FW_PATH)/. # Workaround for make < 3.81, where .SECONDEXPANSION doesn't work. PHONY += $(INSTALL_FW_PATH)/$$(%) install-all-dirs @@ -42,7 +42,7 @@ quiet_cmd_install = INSTALL $(subst $(srctree)/,,$@) $(installed-fw-dirs): $(call cmd,mkdir) -$(installed-fw): $(INSTALL_FW_PATH)/%: $(obj)/% | $(INSTALL_FW_PATH)/$$(dir %) +$(installed-fw): $(INSTALL_FW_PATH)/%: $(obj)/% | $$(dir $(INSTALL_FW_PATH)/%) $(call cmd,install) PHONY += __fw_install __fw_modinst FORCE diff --git a/scripts/Makefile.modinst b/scripts/Makefile.modinst index efa5d940e63..3d13d3a3edf 100644 --- a/scripts/Makefile.modinst +++ b/scripts/Makefile.modinst @@ -9,7 +9,7 @@ include scripts/Kbuild.include # -__modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod))) +__modules := $(sort $(shell grep -h '\.ko$$' /dev/null $(wildcard $(MODVERDIR)/*.mod))) modules := $(patsubst %.o,%.ko,$(wildcard $(__modules:.ko=.o))) PHONY += $(modules) diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index 08dce14f2dc..002089141df 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -14,7 +14,8 @@ # 3) create one <module>.mod.c file pr. module # 4) create one Module.symvers file with CRC for all exported symbols # 5) compile all <module>.mod.c files -# 6) final link of the module to a <module.ko> file +# 6) final link of the module to a <module.ko> (or <module.unsigned>) file +# 7) signs the modules to a <module.ko> file # Step 3 is used to place certain information in the module's ELF # section, including information such as: @@ -32,6 +33,8 @@ # Step 4 is solely used to allow module versioning in external modules, # where the CRC of each module is retrieved from the Module.symvers file. +# Step 7 is dependent on CONFIG_MODULE_SIG being enabled. + # KBUILD_MODPOST_WARN can be set to avoid error out in case of undefined # symbols in the final module linking stage # KBUILD_MODPOST_NOFINAL can be set to skip the final link of modules. @@ -60,7 +63,7 @@ kernelsymfile := $(objtree)/Module.symvers modulesymfile := $(firstword $(KBUILD_EXTMOD))/Module.symvers # Step 1), find all modules listed in $(MODVERDIR)/ -__modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod))) +__modules := $(sort $(shell grep -h '\.ko$$' /dev/null $(wildcard $(MODVERDIR)/*.mod))) modules := $(patsubst %.o,%.ko, $(wildcard $(__modules:.ko=.o))) # Stop after building .o files if NOFINAL is set. Makes compile tests quicker @@ -116,6 +119,7 @@ $(modules:.ko=.mod.o): %.mod.o: %.mod.c FORCE targets += $(modules:.ko=.mod.o) # Step 6), final link of the modules +ifneq ($(CONFIG_MODULE_SIG),y) quiet_cmd_ld_ko_o = LD [M] $@ cmd_ld_ko_o = $(LD) -r $(LDFLAGS) \ $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ @@ -125,7 +129,78 @@ $(modules): %.ko :%.o %.mod.o FORCE $(call if_changed,ld_ko_o) targets += $(modules) +else +quiet_cmd_ld_ko_unsigned_o = LD [M] $@ + cmd_ld_ko_unsigned_o = \ + $(LD) -r $(LDFLAGS) \ + $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ + -o $@ $(filter-out FORCE,$^) \ + $(if $(AFTER_LINK),; $(AFTER_LINK)) + +$(modules:.ko=.ko.unsigned): %.ko.unsigned :%.o %.mod.o FORCE + $(call if_changed,ld_ko_unsigned_o) + +targets += $(modules:.ko=.ko.unsigned) + +# Step 7), sign the modules +MODSECKEY = ./signing_key.priv +MODPUBKEY = ./signing_key.x509 + +ifeq ($(wildcard $(MODSECKEY))+$(wildcard $(MODPUBKEY)),$(MODSECKEY)+$(MODPUBKEY)) +ifeq ($(KBUILD_SRC),) + # no O= is being used + SCRIPTS_DIR := scripts +else + SCRIPTS_DIR := $(KBUILD_SRC)/scripts +endif +SIGN_MODULES := 1 +else +SIGN_MODULES := 0 +endif + +# only sign if it's an in-tree module +ifneq ($(KBUILD_EXTMOD),) +SIGN_MODULES := 0 +endif +# We strip the module as best we can - note that using both strip and eu-strip +# results in a smaller module than using either alone. +EU_STRIP = $(shell which eu-strip || echo true) + +quiet_cmd_sign_ko_stripped_ko_unsigned = STRIP [M] $@ + cmd_sign_ko_stripped_ko_unsigned = \ + cp $< $@ && \ + strip -x -g $@ && \ + $(EU_STRIP) $@ + +ifeq ($(SIGN_MODULES),1) + +quiet_cmd_genkeyid = GENKEYID $@ + cmd_genkeyid = \ + perl $(SCRIPTS_DIR)/x509keyid $< $<.signer $<.keyid + +%.signer %.keyid: % + $(call if_changed,genkeyid) + +KEYRING_DEP := $(MODSECKEY) $(MODPUBKEY) $(MODPUBKEY).signer $(MODPUBKEY).keyid +quiet_cmd_sign_ko_ko_stripped = SIGN [M] $@ + cmd_sign_ko_ko_stripped = \ + sh $(SCRIPTS_DIR)/sign-file $(MODSECKEY) $(MODPUBKEY) $< $@ +else +KEYRING_DEP := +quiet_cmd_sign_ko_ko_unsigned = NO SIGN [M] $@ + cmd_sign_ko_ko_unsigned = \ + cp $< $@ +endif + +$(modules): %.ko :%.ko.stripped $(KEYRING_DEP) FORCE + $(call if_changed,sign_ko_ko_stripped) + +$(patsubst %.ko,%.ko.stripped,$(modules)): %.ko.stripped :%.ko.unsigned FORCE + $(call if_changed,sign_ko_stripped_ko_unsigned) + +targets += $(modules) +endif # Add FORCE to the prequisites of a target to force it to be always rebuilt. # --------------------------------------------------------------------------- diff --git a/scripts/asn1_compiler.c b/scripts/asn1_compiler.c new file mode 100644 index 00000000000..db0e5cd34c7 --- /dev/null +++ b/scripts/asn1_compiler.c @@ -0,0 +1,1545 @@ +/* Simplified ASN.1 notation parser + * + * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <ctype.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <linux/asn1_ber_bytecode.h> + +enum token_type { + DIRECTIVE_ABSENT, + DIRECTIVE_ALL, + DIRECTIVE_ANY, + DIRECTIVE_APPLICATION, + DIRECTIVE_AUTOMATIC, + DIRECTIVE_BEGIN, + DIRECTIVE_BIT, + DIRECTIVE_BMPString, + DIRECTIVE_BOOLEAN, + DIRECTIVE_BY, + DIRECTIVE_CHARACTER, + DIRECTIVE_CHOICE, + DIRECTIVE_CLASS, + DIRECTIVE_COMPONENT, + DIRECTIVE_COMPONENTS, + DIRECTIVE_CONSTRAINED, + DIRECTIVE_CONTAINING, + DIRECTIVE_DEFAULT, + DIRECTIVE_DEFINED, + DIRECTIVE_DEFINITIONS, + DIRECTIVE_EMBEDDED, + DIRECTIVE_ENCODED, + DIRECTIVE_ENCODING_CONTROL, + DIRECTIVE_END, + DIRECTIVE_ENUMERATED, + DIRECTIVE_EXCEPT, + DIRECTIVE_EXPLICIT, + DIRECTIVE_EXPORTS, + DIRECTIVE_EXTENSIBILITY, + DIRECTIVE_EXTERNAL, + DIRECTIVE_FALSE, + DIRECTIVE_FROM, + DIRECTIVE_GeneralString, + DIRECTIVE_GeneralizedTime, + DIRECTIVE_GraphicString, + DIRECTIVE_IA5String, + DIRECTIVE_IDENTIFIER, + DIRECTIVE_IMPLICIT, + DIRECTIVE_IMPLIED, + DIRECTIVE_IMPORTS, + DIRECTIVE_INCLUDES, + DIRECTIVE_INSTANCE, + DIRECTIVE_INSTRUCTIONS, + DIRECTIVE_INTEGER, + DIRECTIVE_INTERSECTION, + DIRECTIVE_ISO646String, + DIRECTIVE_MAX, + DIRECTIVE_MIN, + DIRECTIVE_MINUS_INFINITY, + DIRECTIVE_NULL, + DIRECTIVE_NumericString, + DIRECTIVE_OBJECT, + DIRECTIVE_OCTET, + DIRECTIVE_OF, + DIRECTIVE_OPTIONAL, + DIRECTIVE_ObjectDescriptor, + DIRECTIVE_PATTERN, + DIRECTIVE_PDV, + DIRECTIVE_PLUS_INFINITY, + DIRECTIVE_PRESENT, + DIRECTIVE_PRIVATE, + DIRECTIVE_PrintableString, + DIRECTIVE_REAL, + DIRECTIVE_RELATIVE_OID, + DIRECTIVE_SEQUENCE, + DIRECTIVE_SET, + DIRECTIVE_SIZE, + DIRECTIVE_STRING, + DIRECTIVE_SYNTAX, + DIRECTIVE_T61String, + DIRECTIVE_TAGS, + DIRECTIVE_TRUE, + DIRECTIVE_TeletexString, + DIRECTIVE_UNION, + DIRECTIVE_UNIQUE, + DIRECTIVE_UNIVERSAL, + DIRECTIVE_UTCTime, + DIRECTIVE_UTF8String, + DIRECTIVE_UniversalString, + DIRECTIVE_VideotexString, + DIRECTIVE_VisibleString, + DIRECTIVE_WITH, + NR__DIRECTIVES, + TOKEN_ASSIGNMENT = NR__DIRECTIVES, + TOKEN_OPEN_CURLY, + TOKEN_CLOSE_CURLY, + TOKEN_OPEN_SQUARE, + TOKEN_CLOSE_SQUARE, + TOKEN_OPEN_ACTION, + TOKEN_CLOSE_ACTION, + TOKEN_COMMA, + TOKEN_NUMBER, + TOKEN_TYPE_NAME, + TOKEN_ELEMENT_NAME, + NR__TOKENS +}; + +static const unsigned char token_to_tag[NR__TOKENS] = { + /* EOC goes first */ + [DIRECTIVE_BOOLEAN] = ASN1_BOOL, + [DIRECTIVE_INTEGER] = ASN1_INT, + [DIRECTIVE_BIT] = ASN1_BTS, + [DIRECTIVE_OCTET] = ASN1_OTS, + [DIRECTIVE_NULL] = ASN1_NULL, + [DIRECTIVE_OBJECT] = ASN1_OID, + [DIRECTIVE_ObjectDescriptor] = ASN1_ODE, + [DIRECTIVE_EXTERNAL] = ASN1_EXT, + [DIRECTIVE_REAL] = ASN1_REAL, + [DIRECTIVE_ENUMERATED] = ASN1_ENUM, + [DIRECTIVE_EMBEDDED] = 0, + [DIRECTIVE_UTF8String] = ASN1_UTF8STR, + [DIRECTIVE_RELATIVE_OID] = ASN1_RELOID, + /* 14 */ + /* 15 */ + [DIRECTIVE_SEQUENCE] = ASN1_SEQ, + [DIRECTIVE_SET] = ASN1_SET, + [DIRECTIVE_NumericString] = ASN1_NUMSTR, + [DIRECTIVE_PrintableString] = ASN1_PRNSTR, + [DIRECTIVE_T61String] = ASN1_TEXSTR, + [DIRECTIVE_TeletexString] = ASN1_TEXSTR, + [DIRECTIVE_VideotexString] = ASN1_VIDSTR, + [DIRECTIVE_IA5String] = ASN1_IA5STR, + [DIRECTIVE_UTCTime] = ASN1_UNITIM, + [DIRECTIVE_GeneralizedTime] = ASN1_GENTIM, + [DIRECTIVE_GraphicString] = ASN1_GRASTR, + [DIRECTIVE_VisibleString] = ASN1_VISSTR, + [DIRECTIVE_GeneralString] = ASN1_GENSTR, + [DIRECTIVE_UniversalString] = ASN1_UNITIM, + [DIRECTIVE_CHARACTER] = ASN1_CHRSTR, + [DIRECTIVE_BMPString] = ASN1_BMPSTR, +}; + +static const char asn1_classes[4][5] = { + [ASN1_UNIV] = "UNIV", + [ASN1_APPL] = "APPL", + [ASN1_CONT] = "CONT", + [ASN1_PRIV] = "PRIV" +}; + +static const char asn1_methods[2][5] = { + [ASN1_UNIV] = "PRIM", + [ASN1_APPL] = "CONS" +}; + +static const char *const asn1_universal_tags[32] = { + "EOC", + "BOOL", + "INT", + "BTS", + "OTS", + "NULL", + "OID", + "ODE", + "EXT", + "REAL", + "ENUM", + "EPDV", + "UTF8STR", + "RELOID", + NULL, /* 14 */ + NULL, /* 15 */ + "SEQ", + "SET", + "NUMSTR", + "PRNSTR", + "TEXSTR", + "VIDSTR", + "IA5STR", + "UNITIM", + "GENTIM", + "GRASTR", + "VISSTR", + "GENSTR", + "UNISTR", + "CHRSTR", + "BMPSTR", + NULL /* 31 */ +}; + +static const char *filename; +static const char *grammar_name; +static const char *outputname; +static const char *headername; + +static const char *const directives[NR__DIRECTIVES] = { +#define _(X) [DIRECTIVE_##X] = #X + _(ABSENT), + _(ALL), + _(ANY), + _(APPLICATION), + _(AUTOMATIC), + _(BEGIN), + _(BIT), + _(BMPString), + _(BOOLEAN), + _(BY), + _(CHARACTER), + _(CHOICE), + _(CLASS), + _(COMPONENT), + _(COMPONENTS), + _(CONSTRAINED), + _(CONTAINING), + _(DEFAULT), + _(DEFINED), + _(DEFINITIONS), + _(EMBEDDED), + _(ENCODED), + [DIRECTIVE_ENCODING_CONTROL] = "ENCODING-CONTROL", + _(END), + _(ENUMERATED), + _(EXCEPT), + _(EXPLICIT), + _(EXPORTS), + _(EXTENSIBILITY), + _(EXTERNAL), + _(FALSE), + _(FROM), + _(GeneralString), + _(GeneralizedTime), + _(GraphicString), + _(IA5String), + _(IDENTIFIER), + _(IMPLICIT), + _(IMPLIED), + _(IMPORTS), + _(INCLUDES), + _(INSTANCE), + _(INSTRUCTIONS), + _(INTEGER), + _(INTERSECTION), + _(ISO646String), + _(MAX), + _(MIN), + [DIRECTIVE_MINUS_INFINITY] = "MINUS-INFINITY", + [DIRECTIVE_NULL] = "NULL", + _(NumericString), + _(OBJECT), + _(OCTET), + _(OF), + _(OPTIONAL), + _(ObjectDescriptor), + _(PATTERN), + _(PDV), + [DIRECTIVE_PLUS_INFINITY] = "PLUS-INFINITY", + _(PRESENT), + _(PRIVATE), + _(PrintableString), + _(REAL), + [DIRECTIVE_RELATIVE_OID] = "RELATIVE-OID", + _(SEQUENCE), + _(SET), + _(SIZE), + _(STRING), + _(SYNTAX), + _(T61String), + _(TAGS), + _(TRUE), + _(TeletexString), + _(UNION), + _(UNIQUE), + _(UNIVERSAL), + _(UTCTime), + _(UTF8String), + _(UniversalString), + _(VideotexString), + _(VisibleString), + _(WITH) +}; + +struct action { + struct action *next; + unsigned char index; + char name[]; +}; + +static struct action *action_list; +static unsigned nr_actions; + +struct token { + unsigned short line; + enum token_type token_type : 8; + unsigned char size; + struct action *action; + const char *value; + struct type *type; +}; + +static struct token *token_list; +static unsigned nr_tokens; + +static int directive_compare(const void *_key, const void *_pdir) +{ + const struct token *token = _key; + const char *const *pdir = _pdir, *dir = *pdir; + size_t dlen, clen; + int val; + + dlen = strlen(dir); + clen = (dlen < token->size) ? dlen : token->size; + + //printf("cmp(%*.*s,%s) = ", + // (int)token->size, (int)token->size, token->value, + // dir); + + val = memcmp(token->value, dir, clen); + if (val != 0) { + //printf("%d [cmp]\n", val); + return val; + } + + if (dlen == token->size) { + //printf("0\n"); + return 0; + } + //printf("%d\n", (int)dlen - (int)token->size); + return dlen - token->size; /* shorter -> negative */ +} + +/* + * Tokenise an ASN.1 grammar + */ +static void tokenise(char *buffer, char *end) +{ + struct token *tokens; + char *line, *nl, *p, *q; + unsigned tix, lineno; + + /* Assume we're going to have half as many tokens as we have + * characters + */ + token_list = tokens = calloc((end - buffer) / 2, sizeof(struct token)); + if (!tokens) { + perror(NULL); + exit(1); + } + tix = 0; + + lineno = 0; + while (buffer < end) { + /* First of all, break out a line */ + lineno++; + line = buffer; + nl = memchr(line, '\n', end - buffer); + if (!nl) { + buffer = nl = end; + } else { + buffer = nl + 1; + *nl = '\0'; + } + + /* Remove "--" comments */ + p = line; + next_comment: + while ((p = memchr(p, '-', nl - p))) { + if (p[1] == '-') { + /* Found a comment; see if there's a terminator */ + q = p + 2; + while ((q = memchr(q, '-', nl - q))) { + if (q[1] == '-') { + /* There is - excise the comment */ + q += 2; + memmove(p, q, nl - q); + goto next_comment; + } + q++; + } + *p = '\0'; + nl = p; + break; + } else { + p++; + } + } + + p = line; + while (p < nl) { + /* Skip white space */ + while (p < nl && isspace(*p)) + *(p++) = 0; + if (p >= nl) + break; + + tokens[tix].line = lineno; + tokens[tix].value = p; + + /* Handle string tokens */ + if (isalpha(*p)) { + const char **dir; + + /* Can be a directive, type name or element + * name. Find the end of the name. + */ + q = p + 1; + while (q < nl && (isalnum(*q) || *q == '-' || *q == '_')) + q++; + tokens[tix].size = q - p; + p = q; + + /* If it begins with a lowercase letter then + * it's an element name + */ + if (islower(tokens[tix].value[0])) { + tokens[tix++].token_type = TOKEN_ELEMENT_NAME; + continue; + } + + /* Otherwise we need to search the directive + * table + */ + dir = bsearch(&tokens[tix], directives, + sizeof(directives) / sizeof(directives[1]), + sizeof(directives[1]), + directive_compare); + if (dir) { + tokens[tix++].token_type = dir - directives; + continue; + } + + tokens[tix++].token_type = TOKEN_TYPE_NAME; + continue; + } + + /* Handle numbers */ + if (isdigit(*p)) { + /* Find the end of the number */ + q = p + 1; + while (q < nl && (isdigit(*q))) + q++; + tokens[tix].size = q - p; + p = q; + tokens[tix++].token_type = TOKEN_NUMBER; + continue; + } + + if (nl - p >= 3) { + if (memcmp(p, "::=", 3) == 0) { + p += 3; + tokens[tix].size = 3; + tokens[tix++].token_type = TOKEN_ASSIGNMENT; + continue; + } + } + + if (nl - p >= 2) { + if (memcmp(p, "({", 2) == 0) { + p += 2; + tokens[tix].size = 2; + tokens[tix++].token_type = TOKEN_OPEN_ACTION; + continue; + } + if (memcmp(p, "})", 2) == 0) { + p += 2; + tokens[tix].size = 2; + tokens[tix++].token_type = TOKEN_CLOSE_ACTION; + continue; + } + } + + if (nl - p >= 1) { + tokens[tix].size = 1; + switch (*p) { + case '{': + p += 1; + tokens[tix++].token_type = TOKEN_OPEN_CURLY; + continue; + case '}': + p += 1; + tokens[tix++].token_type = TOKEN_CLOSE_CURLY; + continue; + case '[': + p += 1; + tokens[tix++].token_type = TOKEN_OPEN_SQUARE; + continue; + case ']': + p += 1; + tokens[tix++].token_type = TOKEN_CLOSE_SQUARE; + continue; + case ',': + p += 1; + tokens[tix++].token_type = TOKEN_COMMA; + continue; + default: + break; + } + } + + fprintf(stderr, "%s:%u: Unknown character in grammar: '%c'\n", + filename, lineno, *p); + exit(1); + } + } + + nr_tokens = tix; + printf("Extracted %u tokens\n", nr_tokens); + +#if 0 + { + int n; + for (n = 0; n < nr_tokens; n++) + printf("Token %3u: '%*.*s'\n", + n, + (int)token_list[n].size, (int)token_list[n].size, + token_list[n].value); + } +#endif +} + +static void build_type_list(void); +static void parse(void); +static void render(FILE *out, FILE *hdr); + +/* + * + */ +int main(int argc, char **argv) +{ + struct stat st; + ssize_t readlen; + FILE *out, *hdr; + char *buffer, *p; + int fd; + + if (argc != 4) { + fprintf(stderr, "Format: %s <grammar-file> <c-file> <hdr-file>\n", + argv[0]); + exit(2); + } + + filename = argv[1]; + outputname = argv[2]; + headername = argv[3]; + + fd = open(filename, O_RDONLY); + if (fd < 0) { + perror(filename); + exit(1); + } + + if (fstat(fd, &st) < 0) { + perror(filename); + exit(1); + } + + if (!(buffer = malloc(st.st_size + 1))) { + perror(NULL); + exit(1); + } + + if ((readlen = read(fd, buffer, st.st_size)) < 0) { + perror(filename); + exit(1); + } + + if (close(fd) < 0) { + perror(filename); + exit(1); + } + + if (readlen != st.st_size) { + fprintf(stderr, "%s: Short read\n", filename); + exit(1); + } + + p = strrchr(argv[1], '/'); + p = p ? p + 1 : argv[1]; + grammar_name = strdup(p); + if (!p) { + perror(NULL); + exit(1); + } + p = strchr(grammar_name, '.'); + if (p) + *p = '\0'; + + buffer[readlen] = 0; + tokenise(buffer, buffer + readlen); + build_type_list(); + parse(); + + out = fopen(outputname, "w"); + if (!out) { + perror(outputname); + exit(1); + } + + hdr = fopen(headername, "w"); + if (!out) { + perror(headername); + exit(1); + } + + render(out, hdr); + + if (fclose(out) < 0) { + perror(outputname); + exit(1); + } + + if (fclose(hdr) < 0) { + perror(headername); + exit(1); + } + + return 0; +} + +enum compound { + NOT_COMPOUND, + SET, + SET_OF, + SEQUENCE, + SEQUENCE_OF, + CHOICE, + ANY, + TYPE_REF, + TAG_OVERRIDE +}; + +struct element { + struct type *type_def; + struct token *name; + struct token *type; + struct action *action; + struct element *children; + struct element *next; + struct element *render_next; + struct element *list_next; + uint8_t n_elements; + enum compound compound : 8; + enum asn1_class class : 8; + enum asn1_method method : 8; + uint8_t tag; + unsigned entry_index; + unsigned flags; +#define ELEMENT_IMPLICIT 0x0001 +#define ELEMENT_EXPLICIT 0x0002 +#define ELEMENT_MARKED 0x0004 +#define ELEMENT_RENDERED 0x0008 +#define ELEMENT_SKIPPABLE 0x0010 +#define ELEMENT_CONDITIONAL 0x0020 +}; + +struct type { + struct token *name; + struct token *def; + struct element *element; + unsigned ref_count; + unsigned flags; +#define TYPE_STOP_MARKER 0x0001 +#define TYPE_BEGIN 0x0002 +}; + +static struct type *type_list; +static struct type **type_index; +static unsigned nr_types; + +static int type_index_compare(const void *_a, const void *_b) +{ + const struct type *const *a = _a, *const *b = _b; + + if ((*a)->name->size != (*b)->name->size) + return (*a)->name->size - (*b)->name->size; + else + return memcmp((*a)->name->value, (*b)->name->value, + (*a)->name->size); +} + +static int type_finder(const void *_key, const void *_ti) +{ + const struct token *token = _key; + const struct type *const *ti = _ti; + const struct type *type = *ti; + + if (token->size != type->name->size) + return token->size - type->name->size; + else + return memcmp(token->value, type->name->value, + token->size); +} + +/* + * Build up a list of types and a sorted index to that list. + */ +static void build_type_list(void) +{ + struct type *types; + unsigned nr, t, n; + + nr = 0; + for (n = 0; n < nr_tokens - 1; n++) + if (token_list[n + 0].token_type == TOKEN_TYPE_NAME && + token_list[n + 1].token_type == TOKEN_ASSIGNMENT) + nr++; + + if (nr == 0) { + fprintf(stderr, "%s: No defined types\n", filename); + exit(1); + } + + nr_types = nr; + types = type_list = calloc(nr + 1, sizeof(type_list[0])); + if (!type_list) { + perror(NULL); + exit(1); + } + type_index = calloc(nr, sizeof(type_index[0])); + if (!type_index) { + perror(NULL); + exit(1); + } + + t = 0; + types[t].flags |= TYPE_BEGIN; + for (n = 0; n < nr_tokens - 1; n++) { + if (token_list[n + 0].token_type == TOKEN_TYPE_NAME && + token_list[n + 1].token_type == TOKEN_ASSIGNMENT) { + types[t].name = &token_list[n]; + type_index[t] = &types[t]; + t++; + } + } + types[t].name = &token_list[n + 1]; + types[t].flags |= TYPE_STOP_MARKER; + + qsort(type_index, nr, sizeof(type_index[0]), type_index_compare); + + printf("Extracted %u types\n", nr_types); +#if 0 + for (n = 0; n < nr_types; n++) { + struct type *type = type_index[n]; + printf("- %*.*s\n", + (int)type->name->size, + (int)type->name->size, + type->name->value); + } +#endif +} + +static struct element *parse_type(struct token **_cursor, struct token *stop, + struct token *name); + +/* + * Parse the token stream + */ +static void parse(void) +{ + struct token *cursor; + struct type *type; + + /* Parse one type definition statement at a time */ + type = type_list; + do { + cursor = type->name; + + if (cursor[0].token_type != TOKEN_TYPE_NAME || + cursor[1].token_type != TOKEN_ASSIGNMENT) + abort(); + cursor += 2; + + type->element = parse_type(&cursor, type[1].name, NULL); + type->element->type_def = type; + + if (cursor != type[1].name) { + fprintf(stderr, "%s:%d: Parse error at token '%*.*s'\n", + filename, cursor->line, + (int)cursor->size, (int)cursor->size, cursor->value); + exit(1); + } + + } while (type++, !(type->flags & TYPE_STOP_MARKER)); + + printf("Extracted %u actions\n", nr_actions); +} + +static struct element *element_list; + +static struct element *alloc_elem(struct token *type) +{ + struct element *e = calloc(1, sizeof(*e)); + if (!e) { + perror(NULL); + exit(1); + } + e->list_next = element_list; + element_list = e; + return e; +} + +static struct element *parse_compound(struct token **_cursor, struct token *end, + int alternates); + +/* + * Parse one type definition statement + */ +static struct element *parse_type(struct token **_cursor, struct token *end, + struct token *name) +{ + struct element *top, *element; + struct action *action, **ppaction; + struct token *cursor = *_cursor; + struct type **ref; + char *p; + int labelled = 0, implicit = 0; + + top = element = alloc_elem(cursor); + element->class = ASN1_UNIV; + element->method = ASN1_PRIM; + element->tag = token_to_tag[cursor->token_type]; + element->name = name; + + /* Extract the tag value if one given */ + if (cursor->token_type == TOKEN_OPEN_SQUARE) { + cursor++; + if (cursor >= end) + goto overrun_error; + switch (cursor->token_type) { + case DIRECTIVE_UNIVERSAL: + element->class = ASN1_UNIV; + cursor++; + break; + case DIRECTIVE_APPLICATION: + element->class = ASN1_APPL; + cursor++; + break; + case TOKEN_NUMBER: + element->class = ASN1_CONT; + break; + case DIRECTIVE_PRIVATE: + element->class = ASN1_PRIV; + cursor++; + break; + default: + fprintf(stderr, "%s:%d: Unrecognised tag class token '%*.*s'\n", + filename, cursor->line, + (int)cursor->size, (int)cursor->size, cursor->value); + exit(1); + } + + if (cursor >= end) + goto overrun_error; + if (cursor->token_type != TOKEN_NUMBER) { + fprintf(stderr, "%s:%d: Missing tag number '%*.*s'\n", + filename, cursor->line, + (int)cursor->size, (int)cursor->size, cursor->value); + exit(1); + } + + element->tag &= ~0x1f; + element->tag |= strtoul(cursor->value, &p, 10); + if (p - cursor->value != cursor->size) + abort(); + cursor++; + + if (cursor >= end) + goto overrun_error; + if (cursor->token_type != TOKEN_CLOSE_SQUARE) { + fprintf(stderr, "%s:%d: Missing closing square bracket '%*.*s'\n", + filename, cursor->line, + (int)cursor->size, (int)cursor->size, cursor->value); + exit(1); + } + cursor++; + if (cursor >= end) + goto overrun_error; + labelled = 1; + } + + /* Handle implicit and explicit markers */ + if (cursor->token_type == DIRECTIVE_IMPLICIT) { + element->flags |= ELEMENT_IMPLICIT; + implicit = 1; + cursor++; + if (cursor >= end) + goto overrun_error; + } else if (cursor->token_type == DIRECTIVE_EXPLICIT) { + element->flags |= ELEMENT_EXPLICIT; + cursor++; + if (cursor >= end) + goto overrun_error; + } + + if (labelled) { + if (!implicit) + element->method |= ASN1_CONS; + element->compound = implicit ? TAG_OVERRIDE : SEQUENCE; + element->children = alloc_elem(cursor); + element = element->children; + element->class = ASN1_UNIV; + element->method = ASN1_PRIM; + element->tag = token_to_tag[cursor->token_type]; + element->name = name; + } + + /* Extract the type we're expecting here */ + element->type = cursor; + switch (cursor->token_type) { + case DIRECTIVE_ANY: + element->compound = ANY; + cursor++; + break; + + case DIRECTIVE_NULL: + case DIRECTIVE_BOOLEAN: + case DIRECTIVE_ENUMERATED: + case DIRECTIVE_INTEGER: + element->compound = NOT_COMPOUND; + cursor++; + break; + + case DIRECTIVE_EXTERNAL: + element->method = ASN1_CONS; + + case DIRECTIVE_BMPString: + case DIRECTIVE_GeneralString: + case DIRECTIVE_GraphicString: + case DIRECTIVE_IA5String: + case DIRECTIVE_ISO646String: + case DIRECTIVE_NumericString: + case DIRECTIVE_PrintableString: + case DIRECTIVE_T61String: + case DIRECTIVE_TeletexString: + case DIRECTIVE_UniversalString: + case DIRECTIVE_UTF8String: + case DIRECTIVE_VideotexString: + case DIRECTIVE_VisibleString: + case DIRECTIVE_ObjectDescriptor: + case DIRECTIVE_GeneralizedTime: + case DIRECTIVE_UTCTime: + element->compound = NOT_COMPOUND; + cursor++; + break; + + case DIRECTIVE_BIT: + case DIRECTIVE_OCTET: + element->compound = NOT_COMPOUND; + cursor++; + if (cursor >= end) + goto overrun_error; + if (cursor->token_type != DIRECTIVE_STRING) + goto parse_error; + cursor++; + break; + + case DIRECTIVE_OBJECT: + element->compound = NOT_COMPOUND; + cursor++; + if (cursor >= end) + goto overrun_error; + if (cursor->token_type != DIRECTIVE_IDENTIFIER) + goto parse_error; + cursor++; + break; + + case TOKEN_TYPE_NAME: + element->compound = TYPE_REF; + ref = bsearch(cursor, type_index, nr_types, sizeof(type_index[0]), + type_finder); + if (!ref) { + fprintf(stderr, "%s:%d: Type '%*.*s' undefined\n", + filename, cursor->line, + (int)cursor->size, (int)cursor->size, cursor->value); + exit(1); + } + cursor->type = *ref; + (*ref)->ref_count++; + cursor++; + break; + + case DIRECTIVE_CHOICE: + element->compound = CHOICE; + cursor++; + element->children = parse_compound(&cursor, end, 1); + break; + + case DIRECTIVE_SEQUENCE: + element->compound = SEQUENCE; + element->method = ASN1_CONS; + cursor++; + if (cursor >= end) + goto overrun_error; + if (cursor->token_type == DIRECTIVE_OF) { + element->compound = SEQUENCE_OF; + cursor++; + if (cursor >= end) + goto overrun_error; + element->children = parse_type(&cursor, end, NULL); + } else { + element->children = parse_compound(&cursor, end, 0); + } + break; + + case DIRECTIVE_SET: + element->compound = SET; + element->method = ASN1_CONS; + cursor++; + if (cursor >= end) + goto overrun_error; + if (cursor->token_type == DIRECTIVE_OF) { + element->compound = SET_OF; + cursor++; + if (cursor >= end) + goto parse_error; + element->children = parse_type(&cursor, end, NULL); + } else { + element->children = parse_compound(&cursor, end, 1); + } + break; + + default: + fprintf(stderr, "%s:%d: Token '%*.*s' does not introduce a type\n", + filename, cursor->line, + (int)cursor->size, (int)cursor->size, cursor->value); + exit(1); + } + + /* Handle elements that are optional */ + if (cursor < end && (cursor->token_type == DIRECTIVE_OPTIONAL || + cursor->token_type == DIRECTIVE_DEFAULT) + ) { + cursor++; + top->flags |= ELEMENT_SKIPPABLE; + } + + if (cursor < end && cursor->token_type == TOKEN_OPEN_ACTION) { + cursor++; + if (cursor >= end) + goto overrun_error; + if (cursor->token_type != TOKEN_ELEMENT_NAME) { + fprintf(stderr, "%s:%d: Token '%*.*s' is not an action function name\n", + filename, cursor->line, + (int)cursor->size, (int)cursor->size, cursor->value); + exit(1); + } + + action = malloc(sizeof(struct action) + cursor->size + 1); + if (!action) { + perror(NULL); + exit(1); + } + action->index = 0; + memcpy(action->name, cursor->value, cursor->size); + action->name[cursor->size] = 0; + + for (ppaction = &action_list; + *ppaction; + ppaction = &(*ppaction)->next + ) { + int cmp = strcmp(action->name, (*ppaction)->name); + if (cmp == 0) { + free(action); + action = *ppaction; + goto found; + } + if (cmp < 0) { + action->next = *ppaction; + *ppaction = action; + nr_actions++; + goto found; + } + } + action->next = NULL; + *ppaction = action; + nr_actions++; + found: + + element->action = action; + cursor->action = action; + cursor++; + if (cursor >= end) + goto overrun_error; + if (cursor->token_type != TOKEN_CLOSE_ACTION) { + fprintf(stderr, "%s:%d: Missing close action, got '%*.*s'\n", + filename, cursor->line, + (int)cursor->size, (int)cursor->size, cursor->value); + exit(1); + } + cursor++; + } + + *_cursor = cursor; + return top; + +parse_error: + fprintf(stderr, "%s:%d: Unexpected token '%*.*s'\n", + filename, cursor->line, + (int)cursor->size, (int)cursor->size, cursor->value); + exit(1); + +overrun_error: + fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename); + exit(1); +} + +/* + * Parse a compound type list + */ +static struct element *parse_compound(struct token **_cursor, struct token *end, + int alternates) +{ + struct element *children, **child_p = &children, *element; + struct token *cursor = *_cursor, *name; + + if (cursor->token_type != TOKEN_OPEN_CURLY) { + fprintf(stderr, "%s:%d: Expected compound to start with brace not '%*.*s'\n", + filename, cursor->line, + (int)cursor->size, (int)cursor->size, cursor->value); + exit(1); + } + cursor++; + if (cursor >= end) + goto overrun_error; + + if (cursor->token_type == TOKEN_OPEN_CURLY) { + fprintf(stderr, "%s:%d: Empty compound\n", + filename, cursor->line); + exit(1); + } + + for (;;) { + name = NULL; + if (cursor->token_type == TOKEN_ELEMENT_NAME) { + name = cursor; + cursor++; + if (cursor >= end) + goto overrun_error; + } + + element = parse_type(&cursor, end, name); + if (alternates) + element->flags |= ELEMENT_SKIPPABLE | ELEMENT_CONDITIONAL; + + *child_p = element; + child_p = &element->next; + + if (cursor >= end) + goto overrun_error; + if (cursor->token_type != TOKEN_COMMA) + break; + cursor++; + if (cursor >= end) + goto overrun_error; + } + + children->flags &= ~ELEMENT_CONDITIONAL; + + if (cursor->token_type != TOKEN_CLOSE_CURLY) { + fprintf(stderr, "%s:%d: Expected compound closure, got '%*.*s'\n", + filename, cursor->line, + (int)cursor->size, (int)cursor->size, cursor->value); + exit(1); + } + cursor++; + + *_cursor = cursor; + return children; + +overrun_error: + fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename); + exit(1); +} + +static void render_element(FILE *out, struct element *e, struct element *tag); +static void render_out_of_line_list(FILE *out); + +static int nr_entries; +static int render_depth = 1; +static struct element *render_list, **render_list_p = &render_list; + +__attribute__((format(printf, 2, 3))) +static void render_opcode(FILE *out, const char *fmt, ...) +{ + va_list va; + + if (out) { + fprintf(out, "\t[%4d] =%*s", nr_entries, render_depth, ""); + va_start(va, fmt); + vfprintf(out, fmt, va); + va_end(va); + } + nr_entries++; +} + +__attribute__((format(printf, 2, 3))) +static void render_more(FILE *out, const char *fmt, ...) +{ + va_list va; + + if (out) { + va_start(va, fmt); + vfprintf(out, fmt, va); + va_end(va); + } +} + +/* + * Render the grammar into a state machine definition. + */ +static void render(FILE *out, FILE *hdr) +{ + struct element *e; + struct action *action; + struct type *root; + int index; + + fprintf(hdr, "/*\n"); + fprintf(hdr, " * Automatically generated by asn1_compiler. Do not edit\n"); + fprintf(hdr, " *\n"); + fprintf(hdr, " * ASN.1 parser for %s\n", grammar_name); + fprintf(hdr, " */\n"); + fprintf(hdr, "#include <linux/asn1_decoder.h>\n"); + fprintf(hdr, "\n"); + fprintf(hdr, "extern const struct asn1_decoder %s_decoder;\n", grammar_name); + if (ferror(hdr)) { + perror(headername); + exit(1); + } + + fprintf(out, "/*\n"); + fprintf(out, " * Automatically generated by asn1_compiler. Do not edit\n"); + fprintf(out, " *\n"); + fprintf(out, " * ASN.1 parser for %s\n", grammar_name); + fprintf(out, " */\n"); + fprintf(out, "#include <linux/asn1_ber_bytecode.h>\n"); + fprintf(out, "#include \"%s-asn1.h\"\n", grammar_name); + fprintf(out, "\n"); + if (ferror(out)) { + perror(outputname); + exit(1); + } + + /* Tabulate the action functions we might have to call */ + fprintf(hdr, "\n"); + index = 0; + for (action = action_list; action; action = action->next) { + action->index = index++; + fprintf(hdr, + "extern int %s(void *, size_t, unsigned char," + " const void *, size_t);\n", + action->name); + } + fprintf(hdr, "\n"); + + fprintf(out, "enum %s_actions {\n", grammar_name); + for (action = action_list; action; action = action->next) + fprintf(out, "\tACT_%s = %u,\n", + action->name, action->index); + fprintf(out, "\tNR__%s_actions = %u\n", grammar_name, nr_actions); + fprintf(out, "};\n"); + + fprintf(out, "\n"); + fprintf(out, "static const asn1_action_t %s_action_table[NR__%s_actions] = {\n", + grammar_name, grammar_name); + for (action = action_list; action; action = action->next) + fprintf(out, "\t[%4u] = %s,\n", action->index, action->name); + fprintf(out, "};\n"); + + if (ferror(out)) { + perror(outputname); + exit(1); + } + + /* We do two passes - the first one calculates all the offsets */ + printf("Pass 1\n"); + nr_entries = 0; + root = &type_list[0]; + render_element(NULL, root->element, NULL); + render_opcode(NULL, "ASN1_OP_COMPLETE,\n"); + render_out_of_line_list(NULL); + + for (e = element_list; e; e = e->list_next) + e->flags &= ~ELEMENT_RENDERED; + + /* And then we actually render */ + printf("Pass 2\n"); + fprintf(out, "\n"); + fprintf(out, "static const unsigned char %s_machine[] = {\n", + grammar_name); + + nr_entries = 0; + root = &type_list[0]; + render_element(out, root->element, NULL); + render_opcode(out, "ASN1_OP_COMPLETE,\n"); + render_out_of_line_list(out); + + fprintf(out, "};\n"); + + fprintf(out, "\n"); + fprintf(out, "const struct asn1_decoder %s_decoder = {\n", grammar_name); + fprintf(out, "\t.machine = %s_machine,\n", grammar_name); + fprintf(out, "\t.machlen = sizeof(%s_machine),\n", grammar_name); + fprintf(out, "\t.actions = %s_action_table,\n", grammar_name); + fprintf(out, "};\n"); +} + +/* + * Render the out-of-line elements + */ +static void render_out_of_line_list(FILE *out) +{ + struct element *e, *ce; + const char *act; + int entry; + + while ((e = render_list)) { + render_list = e->render_next; + if (!render_list) + render_list_p = &render_list; + + render_more(out, "\n"); + e->entry_index = entry = nr_entries; + render_depth++; + for (ce = e->children; ce; ce = ce->next) + render_element(out, ce, NULL); + render_depth--; + + act = e->action ? "_ACT" : ""; + switch (e->compound) { + case SEQUENCE: + render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act); + break; + case SEQUENCE_OF: + render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act); + render_opcode(out, "_jump_target(%u),\n", entry); + break; + case SET: + render_opcode(out, "ASN1_OP_END_SET%s,\n", act); + break; + case SET_OF: + render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act); + render_opcode(out, "_jump_target(%u),\n", entry); + break; + } + if (e->action) + render_opcode(out, "_action(ACT_%s),\n", + e->action->name); + render_opcode(out, "ASN1_OP_RETURN,\n"); + } +} + +/* + * Render an element. + */ +static void render_element(FILE *out, struct element *e, struct element *tag) +{ + struct element *ec; + const char *cond, *act; + int entry, skippable = 0, outofline = 0; + + if (e->flags & ELEMENT_SKIPPABLE || + (tag && tag->flags & ELEMENT_SKIPPABLE)) + skippable = 1; + + if ((e->type_def && e->type_def->ref_count > 1) || + skippable) + outofline = 1; + + if (e->type_def && out) { + render_more(out, "\t// %*.*s\n", + (int)e->type_def->name->size, (int)e->type_def->name->size, + e->type_def->name->value); + } + + /* Render the operation */ + cond = (e->flags & ELEMENT_CONDITIONAL || + (tag && tag->flags & ELEMENT_CONDITIONAL)) ? "COND_" : ""; + act = e->action ? "_ACT" : ""; + switch (e->compound) { + case ANY: + render_opcode(out, "ASN1_OP_%sMATCH_ANY%s,", cond, act); + if (e->name) + render_more(out, "\t\t// %*.*s", + (int)e->name->size, (int)e->name->size, + e->name->value); + render_more(out, "\n"); + goto dont_render_tag; + + case TAG_OVERRIDE: + render_element(out, e->children, e); + return; + + case SEQUENCE: + case SEQUENCE_OF: + case SET: + case SET_OF: + render_opcode(out, "ASN1_OP_%sMATCH%s%s,", + cond, + outofline ? "_JUMP" : "", + skippable ? "_OR_SKIP" : ""); + break; + + case CHOICE: + goto dont_render_tag; + + case TYPE_REF: + if (e->class == ASN1_UNIV && e->method == ASN1_PRIM && e->tag == 0) + goto dont_render_tag; + default: + render_opcode(out, "ASN1_OP_%sMATCH%s%s,", + cond, act, + skippable ? "_OR_SKIP" : ""); + break; + } + + if (e->name) + render_more(out, "\t\t// %*.*s", + (int)e->name->size, (int)e->name->size, + e->name->value); + render_more(out, "\n"); + + /* Render the tag */ + if (!tag) + tag = e; + if (tag->class == ASN1_UNIV && + tag->tag != 14 && + tag->tag != 15 && + tag->tag != 31) + render_opcode(out, "_tag(%s, %s, %s),\n", + asn1_classes[tag->class], + asn1_methods[tag->method | e->method], + asn1_universal_tags[tag->tag]); + else + render_opcode(out, "_tagn(%s, %s, %2u),\n", + asn1_classes[tag->class], + asn1_methods[tag->method | e->method], + tag->tag); + tag = NULL; +dont_render_tag: + + /* Deal with compound types */ + switch (e->compound) { + case TYPE_REF: + render_element(out, e->type->type->element, tag); + if (e->action) + render_opcode(out, "ASN1_OP_ACT,\n"); + break; + + case SEQUENCE: + if (outofline) { + /* Render out-of-line for multiple use or + * skipability */ + render_opcode(out, "_jump_target(%u),", e->entry_index); + if (e->type_def && e->type_def->name) + render_more(out, "\t\t// --> %*.*s", + (int)e->type_def->name->size, + (int)e->type_def->name->size, + e->type_def->name->value); + render_more(out, "\n"); + if (!(e->flags & ELEMENT_RENDERED)) { + e->flags |= ELEMENT_RENDERED; + *render_list_p = e; + render_list_p = &e->render_next; + } + return; + } else { + /* Render inline for single use */ + render_depth++; + for (ec = e->children; ec; ec = ec->next) + render_element(out, ec, NULL); + render_depth--; + render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act); + } + break; + + case SEQUENCE_OF: + case SET_OF: + if (outofline) { + /* Render out-of-line for multiple use or + * skipability */ + render_opcode(out, "_jump_target(%u),", e->entry_index); + if (e->type_def && e->type_def->name) + render_more(out, "\t\t// --> %*.*s", + (int)e->type_def->name->size, + (int)e->type_def->name->size, + e->type_def->name->value); + render_more(out, "\n"); + if (!(e->flags & ELEMENT_RENDERED)) { + e->flags |= ELEMENT_RENDERED; + *render_list_p = e; + render_list_p = &e->render_next; + } + return; + } else { + /* Render inline for single use */ + entry = nr_entries; + render_depth++; + render_element(out, e->children, NULL); + render_depth--; + if (e->compound == SEQUENCE_OF) + render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act); + else + render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act); + render_opcode(out, "_jump_target(%u),\n", entry); + } + break; + + case SET: + /* I can't think of a nice way to do SET support without having + * a stack of bitmasks to make sure no element is repeated. + * The bitmask has also to be checked that no non-optional + * elements are left out whilst not preventing optional + * elements from being left out. + */ + fprintf(stderr, "The ASN.1 SET type is not currently supported.\n"); + exit(1); + + case CHOICE: + for (ec = e->children; ec; ec = ec->next) + render_element(out, ec, NULL); + if (!skippable) + render_opcode(out, "ASN1_OP_COND_FAIL,\n"); + if (e->action) + render_opcode(out, "ASN1_OP_ACT,\n"); + break; + + default: + break; + } + + if (e->action) + render_opcode(out, "_action(ACT_%s),\n", e->action->name); +} diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index ca05ba217f5..21a9f5de0a2 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -421,7 +421,7 @@ sub top_of_kernel_tree { } } return 1; - } +} sub parse_email { my ($formatted_email) = @_; @@ -1386,6 +1386,8 @@ sub process { my $in_header_lines = 1; my $in_commit_log = 0; #Scanning lines before patch + my $non_utf8_charset = 0; + our @report = (); our $cnt_lines = 0; our $cnt_error = 0; @@ -1686,10 +1688,17 @@ sub process { $in_commit_log = 1; } -# Still not yet in a patch, check for any UTF-8 - if ($in_commit_log && $realfile =~ /^$/ && +# Check if there is UTF-8 in a commit log when a mail header has explicitly +# declined it, i.e defined some charset where it is missing. + if ($in_header_lines && + $rawline =~ /^Content-Type:.+charset="(.+)".*$/ && + $1 !~ /utf-8/i) { + $non_utf8_charset = 1; + } + + if ($in_commit_log && $non_utf8_charset && $realfile =~ /^$/ && $rawline =~ /$NON_ASCII_UTF8/) { - CHK("UTF8_BEFORE_PATCH", + WARN("UTF8_BEFORE_PATCH", "8-bit UTF-8 used in possible commit log\n" . $herecurr); } @@ -1873,6 +1882,20 @@ sub process { "No space is necessary after a cast\n" . $hereprev); } + if ($realfile =~ m@^(drivers/net/|net/)@ && + $rawline =~ /^\+[ \t]*\/\*[ \t]*$/ && + $prevrawline =~ /^\+[ \t]*$/) { + WARN("NETWORKING_BLOCK_COMMENT_STYLE", + "networking block comments don't use an empty /* line, use /* Comment...\n" . $hereprev); + } + + if ($realfile =~ m@^(drivers/net/|net/)@ && + $rawline !~ m@^\+[ \t]*(\/\*|\*\/)@ && + $rawline =~ m@^\+[ \t]*.+\*\/[ \t]*$@) { + WARN("NETWORKING_BLOCK_COMMENT_STYLE", + "networking block comments put the trailing */ on a separate line\n" . $herecurr); + } + # check for spaces at the beginning of a line. # Exceptions: # 1) within comments @@ -2390,8 +2413,10 @@ sub process { my $orig = $1; my $level = lc($orig); $level = "warn" if ($level eq "warning"); + my $level2 = $level; + $level2 = "dbg" if ($level eq "debug"); WARN("PREFER_PR_LEVEL", - "Prefer pr_$level(... to printk(KERN_$1, ...\n" . $herecurr); + "Prefer netdev_$level2(netdev, ... then dev_$level2(dev, ... then pr_$level(... to printk(KERN_$orig ...\n" . $herecurr); } if ($line =~ /\bpr_warning\s*\(/) { @@ -2947,7 +2972,7 @@ sub process { my $exceptions = qr{ $Declare| module_param_named| - MODULE_PARAM_DESC| + MODULE_PARM_DESC| DECLARE_PER_CPU| DEFINE_PER_CPU| __typeof__\(| diff --git a/scripts/coccicheck b/scripts/coccicheck index 823e972149e..1a49d1c7ecf 100755 --- a/scripts/coccicheck +++ b/scripts/coccicheck @@ -95,6 +95,9 @@ coccinelle () { $SPATCH -D report $FLAGS -sp_file $COCCI $OPT $OPTIONS -no_show_diff || \ $SPATCH -D context $FLAGS -sp_file $COCCI $OPT $OPTIONS || \ $SPATCH -D org $FLAGS -sp_file $COCCI $OPT $OPTIONS -no_show_diff || exit 1 + elif [ "$MODE" = "rep+ctxt" ] ; then + $SPATCH -D report $FLAGS -sp_file $COCCI $OPT $OPTIONS -no_show_diff && \ + $SPATCH -D context $FLAGS -sp_file $COCCI $OPT $OPTIONS || exit 1 else $SPATCH -D $MODE $FLAGS -sp_file $COCCI $OPT $OPTIONS || exit 1 fi diff --git a/scripts/coccinelle/api/ptr_ret.cocci b/scripts/coccinelle/api/ptr_ret.cocci index cbfd08c7d8c..15f076fdecb 100644 --- a/scripts/coccinelle/api/ptr_ret.cocci +++ b/scripts/coccinelle/api/ptr_ret.cocci @@ -30,6 +30,13 @@ expression ptr; - if (IS_ERR(ptr)) return PTR_ERR(ptr); return 0; + return PTR_RET(ptr); +@depends on patch@ +expression ptr; +@@ + +- (IS_ERR(ptr) ? PTR_ERR(ptr) : 0) ++ PTR_RET(ptr) + @r1 depends on !patch@ expression ptr; position p1; @@ -44,6 +51,13 @@ position p2; * if@p2 (IS_ERR(ptr)) return PTR_ERR(ptr); return 0; +@r3 depends on !patch@ +expression ptr; +position p3; +@@ + +* IS_ERR@p3(ptr) ? PTR_ERR(ptr) : 0 + @script:python depends on org@ p << r1.p1; @@ @@ -57,6 +71,12 @@ p << r2.p2; coccilib.org.print_todo(p[0], "WARNING: PTR_RET can be used") +@script:python depends on org@ +p << r3.p3; +@@ + +coccilib.org.print_todo(p[0], "WARNING: PTR_RET can be used") + @script:python depends on report@ p << r1.p1; @@ @@ -68,3 +88,9 @@ p << r2.p2; @@ coccilib.report.print_report(p[0], "WARNING: PTR_RET can be used") + +@script:python depends on report@ +p << r3.p3; +@@ + +coccilib.report.print_report(p[0], "WARNING: PTR_RET can be used") diff --git a/scripts/coccinelle/tests/odd_ptr_err.cocci b/scripts/coccinelle/tests/odd_ptr_err.cocci new file mode 100644 index 00000000000..e8dd8a6b28a --- /dev/null +++ b/scripts/coccinelle/tests/odd_ptr_err.cocci @@ -0,0 +1,65 @@ +/// PTR_ERR should access the value just tested by IS_ERR +//# There can be false positives in the patch case, where it is the call +//# IS_ERR that is wrong. +/// +// Confidence: High +// Copyright: (C) 2012 Julia Lawall, INRIA. GPLv2. +// Copyright: (C) 2012 Gilles Muller, INRIA. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: -no_includes -include_headers + +virtual patch +virtual context +virtual org +virtual report + +@depends on patch@ +expression e,e1; +@@ + +( +if (IS_ERR(e)) { ... PTR_ERR(e) ... } +| +if (IS_ERR(e=e1)) { ... PTR_ERR(e) ... } +| +if (IS_ERR(e)) + { ... + PTR_ERR( +- e1 ++ e + ) + ... } +) + +@r depends on !patch@ +expression e,e1; +position p1,p2; +@@ + +( +if (IS_ERR(e)) { ... PTR_ERR(e) ... } +| +if (IS_ERR(e=e1)) { ... PTR_ERR(e) ... } +| +*if (IS_ERR@p1(e)) + { ... +* PTR_ERR@p2(e1) + ... } +) + +@script:python depends on org@ +p1 << r.p1; +p2 << r.p2; +@@ + +cocci.print_main("inconsistent IS_ERR and PTR_ERR",p1) +cocci.print_secs("PTR_ERR",p2) + +@script:python depends on report@ +p1 << r.p1; +p2 << r.p2; +@@ + +msg = "inconsistent IS_ERR and PTR_ERR, PTR_ERR on line %s" % (p2[0].line) +coccilib.report.print_report(p1[0],msg) diff --git a/scripts/gcc-version.sh b/scripts/gcc-version.sh index debecb5561c..7f2126df91f 100644 --- a/scripts/gcc-version.sh +++ b/scripts/gcc-version.sh @@ -22,10 +22,10 @@ if [ ${#compiler} -eq 0 ]; then exit 1 fi -MAJOR=$(echo __GNUC__ | $compiler -E -xc - | tail -n 1) -MINOR=$(echo __GNUC_MINOR__ | $compiler -E -xc - | tail -n 1) +MAJOR=$(echo __GNUC__ | $compiler -E -x c - | tail -n 1) +MINOR=$(echo __GNUC_MINOR__ | $compiler -E -x c - | tail -n 1) if [ "x$with_patchlevel" != "x" ] ; then - PATCHLEVEL=$(echo __GNUC_PATCHLEVEL__ | $compiler -E -xc - | tail -n 1) + PATCHLEVEL=$(echo __GNUC_PATCHLEVEL__ | $compiler -E -x c - | tail -n 1) printf "%02d%02d%02d\\n" $MAJOR $MINOR $PATCHLEVEL else printf "%02d%02d\\n" $MAJOR $MINOR diff --git a/scripts/gcc-x86_32-has-stack-protector.sh b/scripts/gcc-x86_32-has-stack-protector.sh index 29493dc4528..12dbd0b11ea 100644 --- a/scripts/gcc-x86_32-has-stack-protector.sh +++ b/scripts/gcc-x86_32-has-stack-protector.sh @@ -1,6 +1,6 @@ #!/bin/sh -echo "int foo(void) { char X[200]; return 3; }" | $* -S -xc -c -O0 -fstack-protector - -o - 2> /dev/null | grep -q "%gs" +echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -O0 -fstack-protector - -o - 2> /dev/null | grep -q "%gs" if [ "$?" -eq "0" ] ; then echo y else diff --git a/scripts/gcc-x86_64-has-stack-protector.sh b/scripts/gcc-x86_64-has-stack-protector.sh index afaec618b39..973e8c14156 100644 --- a/scripts/gcc-x86_64-has-stack-protector.sh +++ b/scripts/gcc-x86_64-has-stack-protector.sh @@ -1,6 +1,6 @@ #!/bin/sh -echo "int foo(void) { char X[200]; return 3; }" | $* -S -xc -c -O0 -mcmodel=kernel -fstack-protector - -o - 2> /dev/null | grep -q "%gs" +echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -O0 -mcmodel=kernel -fstack-protector - -o - 2> /dev/null | grep -q "%gs" if [ "$?" -eq "0" ] ; then echo y else diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index 77d53999ffb..3091794e935 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -76,11 +76,17 @@ PHONY += allnoconfig allyesconfig allmodconfig alldefconfig randconfig allnoconfig allyesconfig allmodconfig alldefconfig randconfig: $(obj)/conf $< --$@ $(Kconfig) -PHONY += listnewconfig oldnoconfig savedefconfig defconfig +PHONY += listnewconfig olddefconfig oldnoconfig savedefconfig defconfig -listnewconfig oldnoconfig: $(obj)/conf +listnewconfig olddefconfig: $(obj)/conf $< --$@ $(Kconfig) +# oldnoconfig is an alias of olddefconfig, because people already are dependent +# on its behavior(sets new symbols to their default value but not 'n') with the +# counter-intuitive name. +oldnoconfig: $(obj)/conf + $< --olddefconfig $(Kconfig) + savedefconfig: $(obj)/conf $< --$@=defconfig $(Kconfig) @@ -114,7 +120,7 @@ help: @echo ' alldefconfig - New config with all symbols set to default' @echo ' randconfig - New config with random answer to all options' @echo ' listnewconfig - List new options' - @echo ' oldnoconfig - Same as silentoldconfig but sets new symbols to their default value' + @echo ' olddefconfig - Same as silentoldconfig but sets new symbols to their default value' # lxdialog stuff check-lxdialog := $(srctree)/$(src)/lxdialog/check-lxdialog.sh diff --git a/scripts/kconfig/check.sh b/scripts/kconfig/check.sh index fa59cbf9d62..854d9c7c675 100755 --- a/scripts/kconfig/check.sh +++ b/scripts/kconfig/check.sh @@ -1,6 +1,6 @@ #!/bin/sh # Needed for systems without gettext -$* -xc -o /dev/null - > /dev/null 2>&1 << EOF +$* -x c -o /dev/null - > /dev/null 2>&1 << EOF #include <libintl.h> int main() { diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c index 0dc4a2c779b..4da3b4adfad 100644 --- a/scripts/kconfig/conf.c +++ b/scripts/kconfig/conf.c @@ -32,7 +32,7 @@ enum input_mode { defconfig, savedefconfig, listnewconfig, - oldnoconfig, + olddefconfig, } input_mode = oldaskconfig; static int indent = 1; @@ -365,7 +365,7 @@ static void conf(struct menu *menu) case P_MENU: if ((input_mode == silentoldconfig || input_mode == listnewconfig || - input_mode == oldnoconfig) && + input_mode == olddefconfig) && rootEntry != menu) { check_conf(menu); return; @@ -429,7 +429,7 @@ static void check_conf(struct menu *menu) if (sym->name && !sym_is_choice_value(sym)) { printf("%s%s\n", CONFIG_, sym->name); } - } else if (input_mode != oldnoconfig) { + } else if (input_mode != olddefconfig) { if (!conf_cnt++) printf(_("*\n* Restart config...\n*\n")); rootEntry = menu_get_parent_menu(menu); @@ -454,7 +454,13 @@ static struct option long_opts[] = { {"alldefconfig", no_argument, NULL, alldefconfig}, {"randconfig", no_argument, NULL, randconfig}, {"listnewconfig", no_argument, NULL, listnewconfig}, - {"oldnoconfig", no_argument, NULL, oldnoconfig}, + {"olddefconfig", no_argument, NULL, olddefconfig}, + /* + * oldnoconfig is an alias of olddefconfig, because people already + * are dependent on its behavior(sets new symbols to their default + * value but not 'n') with the counter-intuitive name. + */ + {"oldnoconfig", no_argument, NULL, olddefconfig}, {NULL, 0, NULL, 0} }; @@ -467,7 +473,8 @@ static void conf_usage(const char *progname) printf(" --oldaskconfig Start a new configuration using a line-oriented program\n"); printf(" --oldconfig Update a configuration using a provided .config as base\n"); printf(" --silentoldconfig Same as oldconfig, but quietly, additionally update deps\n"); - printf(" --oldnoconfig Same as silentoldconfig but set new symbols to no\n"); + printf(" --olddefconfig Same as silentoldconfig but sets new symbols to their default value\n"); + printf(" --oldnoconfig An alias of olddefconfig\n"); printf(" --defconfig <file> New config with default defined in <file>\n"); printf(" --savedefconfig <file> Save the minimal current configuration to <file>\n"); printf(" --allnoconfig New config where all options are answered with no\n"); @@ -520,7 +527,7 @@ int main(int ac, char **av) case allmodconfig: case alldefconfig: case listnewconfig: - case oldnoconfig: + case olddefconfig: break; case '?': conf_usage(progname); @@ -565,7 +572,7 @@ int main(int ac, char **av) case oldaskconfig: case oldconfig: case listnewconfig: - case oldnoconfig: + case olddefconfig: conf_read(NULL); break; case allnoconfig: @@ -645,7 +652,7 @@ int main(int ac, char **av) /* fall through */ case oldconfig: case listnewconfig: - case oldnoconfig: + case olddefconfig: case silentoldconfig: /* Update until a loop caused no more changes */ do { @@ -653,7 +660,7 @@ int main(int ac, char **av) check_conf(&rootmenu); } while (conf_cnt && (input_mode != listnewconfig && - input_mode != oldnoconfig)); + input_mode != olddefconfig)); break; } diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h index d4ecce8bc3a..bd2e0989555 100644 --- a/scripts/kconfig/expr.h +++ b/scripts/kconfig/expr.h @@ -12,6 +12,7 @@ extern "C" { #include <assert.h> #include <stdio.h> +#include <sys/queue.h> #ifndef __cplusplus #include <stdbool.h> #endif @@ -173,6 +174,16 @@ struct menu { #define MENU_CHANGED 0x0001 #define MENU_ROOT 0x0002 +struct jump_key { + CIRCLEQ_ENTRY(jump_key) entries; + size_t offset; + struct menu *target; + int index; +}; +CIRCLEQ_HEAD(jk_head, jump_key); + +#define JUMP_NB 9 + extern struct file *file_list; extern struct file *current_file; struct file *lookup_file(const char *name); diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h index 47fe9c340f9..1d1c08537f1 100644 --- a/scripts/kconfig/lkc_proto.h +++ b/scripts/kconfig/lkc_proto.h @@ -21,8 +21,10 @@ P(menu_get_root_menu,struct menu *,(struct menu *menu)); P(menu_get_parent_menu,struct menu *,(struct menu *menu)); P(menu_has_help,bool,(struct menu *menu)); P(menu_get_help,const char *,(struct menu *menu)); -P(get_symbol_str, void, (struct gstr *r, struct symbol *sym)); -P(get_relations_str, struct gstr, (struct symbol **sym_arr)); +P(get_symbol_str, void, (struct gstr *r, struct symbol *sym, struct jk_head + *head)); +P(get_relations_str, struct gstr, (struct symbol **sym_arr, struct jk_head + *head)); P(menu_get_ext_help,void,(struct menu *menu, struct gstr *help)); /* symbol.c */ diff --git a/scripts/kconfig/lxdialog/check-lxdialog.sh b/scripts/kconfig/lxdialog/check-lxdialog.sh index e3b12c01041..c8e8a715475 100644 --- a/scripts/kconfig/lxdialog/check-lxdialog.sh +++ b/scripts/kconfig/lxdialog/check-lxdialog.sh @@ -38,7 +38,7 @@ trap "rm -f $tmp" 0 1 2 3 15 # Check if we can link to ncurses check() { - $cc -xc - -o $tmp 2>/dev/null <<'EOF' + $cc -x c - -o $tmp 2>/dev/null <<'EOF' #include CURSES_LOC main() {} EOF diff --git a/scripts/kconfig/lxdialog/dialog.h b/scripts/kconfig/lxdialog/dialog.h index b5211fce0d9..ee17a5264d5 100644 --- a/scripts/kconfig/lxdialog/dialog.h +++ b/scripts/kconfig/lxdialog/dialog.h @@ -144,6 +144,7 @@ struct dialog_info { */ extern struct dialog_info dlg; extern char dialog_input_result[]; +extern int saved_x, saved_y; /* Needed in signal handler in mconf.c */ /* * Function prototypes @@ -209,7 +210,13 @@ int first_alpha(const char *string, const char *exempt); int dialog_yesno(const char *title, const char *prompt, int height, int width); int dialog_msgbox(const char *title, const char *prompt, int height, int width, int pause); -int dialog_textbox(const char *title, const char *file, int height, int width); + + +typedef void (*update_text_fn)(char *buf, size_t start, size_t end, void + *_data); +int dialog_textbox(const char *title, char *tbuf, int initial_height, + int initial_width, int *keys, int *_vscroll, int *_hscroll, + update_text_fn update_text, void *data); int dialog_menu(const char *title, const char *prompt, const void *selected, int *s_scroll); int dialog_checklist(const char *title, const char *prompt, int height, diff --git a/scripts/kconfig/lxdialog/textbox.c b/scripts/kconfig/lxdialog/textbox.c index 4e5de60a0c0..a48bb93e090 100644 --- a/scripts/kconfig/lxdialog/textbox.c +++ b/scripts/kconfig/lxdialog/textbox.c @@ -22,23 +22,25 @@ #include "dialog.h" static void back_lines(int n); -static void print_page(WINDOW * win, int height, int width); -static void print_line(WINDOW * win, int row, int width); +static void print_page(WINDOW *win, int height, int width, update_text_fn + update_text, void *data); +static void print_line(WINDOW *win, int row, int width); static char *get_line(void); static void print_position(WINDOW * win); static int hscroll; static int begin_reached, end_reached, page_length; -static const char *buf; -static const char *page; +static char *buf; +static char *page; /* * refresh window content */ static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw, - int cur_y, int cur_x) + int cur_y, int cur_x, update_text_fn update_text, + void *data) { - print_page(box, boxh, boxw); + print_page(box, boxh, boxw, update_text, data); print_position(dialog); wmove(dialog, cur_y, cur_x); /* Restore cursor position */ wrefresh(dialog); @@ -47,14 +49,18 @@ static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw, /* * Display text from a file in a dialog box. + * + * keys is a null-terminated array + * update_text() may not add or remove any '\n' or '\0' in tbuf */ -int dialog_textbox(const char *title, const char *tbuf, - int initial_height, int initial_width) +int dialog_textbox(const char *title, char *tbuf, int initial_height, + int initial_width, int *keys, int *_vscroll, int *_hscroll, + update_text_fn update_text, void *data) { int i, x, y, cur_x, cur_y, key = 0; int height, width, boxh, boxw; - int passed_end; WINDOW *dialog, *box; + bool done = false; begin_reached = 1; end_reached = 0; @@ -63,6 +69,15 @@ int dialog_textbox(const char *title, const char *tbuf, buf = tbuf; page = buf; /* page is pointer to start of page to be displayed */ + if (_vscroll && *_vscroll) { + begin_reached = 0; + + for (i = 0; i < *_vscroll; i++) + get_line(); + } + if (_hscroll) + hscroll = *_hscroll; + do_resize: getmaxyx(stdscr, height, width); if (height < 8 || width < 8) @@ -120,9 +135,10 @@ do_resize: /* Print first page of text */ attr_clear(box, boxh, boxw, dlg.dialog.atr); - refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); + refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x, update_text, + data); - while ((key != KEY_ESC) && (key != '\n')) { + while (!done) { key = wgetch(dialog); switch (key) { case 'E': /* Exit */ @@ -130,16 +146,17 @@ do_resize: case 'X': case 'x': case 'q': - delwin(box); - delwin(dialog); - return 0; + case '\n': + done = true; + break; case 'g': /* First page */ case KEY_HOME: if (!begin_reached) { begin_reached = 1; page = buf; refresh_text_box(dialog, box, boxh, boxw, - cur_y, cur_x); + cur_y, cur_x, update_text, + data); } break; case 'G': /* Last page */ @@ -149,45 +166,18 @@ do_resize: /* point to last char in buf */ page = buf + strlen(buf); back_lines(boxh); - refresh_text_box(dialog, box, boxh, boxw, - cur_y, cur_x); + refresh_text_box(dialog, box, boxh, boxw, cur_y, + cur_x, update_text, data); break; case 'K': /* Previous line */ case 'k': case KEY_UP: - if (!begin_reached) { - back_lines(page_length + 1); - - /* We don't call print_page() here but use - * scrolling to ensure faster screen update. - * However, 'end_reached' and 'page_length' - * should still be updated, and 'page' should - * point to start of next page. This is done - * by calling get_line() in the following - * 'for' loop. */ - scrollok(box, TRUE); - wscrl(box, -1); /* Scroll box region down one line */ - scrollok(box, FALSE); - page_length = 0; - passed_end = 0; - for (i = 0; i < boxh; i++) { - if (!i) { - /* print first line of page */ - print_line(box, 0, boxw); - wnoutrefresh(box); - } else - /* Called to update 'end_reached' and 'page' */ - get_line(); - if (!passed_end) - page_length++; - if (end_reached && !passed_end) - passed_end = 1; - } + if (begin_reached) + break; - print_position(dialog); - wmove(dialog, cur_y, cur_x); /* Restore cursor position */ - wrefresh(dialog); - } + back_lines(page_length + 1); + refresh_text_box(dialog, box, boxh, boxw, cur_y, + cur_x, update_text, data); break; case 'B': /* Previous page */ case 'b': @@ -196,23 +186,18 @@ do_resize: if (begin_reached) break; back_lines(page_length + boxh); - refresh_text_box(dialog, box, boxh, boxw, - cur_y, cur_x); + refresh_text_box(dialog, box, boxh, boxw, cur_y, + cur_x, update_text, data); break; case 'J': /* Next line */ case 'j': case KEY_DOWN: - if (!end_reached) { - begin_reached = 0; - scrollok(box, TRUE); - scroll(box); /* Scroll box region up one line */ - scrollok(box, FALSE); - print_line(box, boxh - 1, boxw); - wnoutrefresh(box); - print_position(dialog); - wmove(dialog, cur_y, cur_x); /* Restore cursor position */ - wrefresh(dialog); - } + if (end_reached) + break; + + back_lines(page_length - 1); + refresh_text_box(dialog, box, boxh, boxw, cur_y, + cur_x, update_text, data); break; case KEY_NPAGE: /* Next page */ case ' ': @@ -221,8 +206,8 @@ do_resize: break; begin_reached = 0; - refresh_text_box(dialog, box, boxh, boxw, - cur_y, cur_x); + refresh_text_box(dialog, box, boxh, boxw, cur_y, + cur_x, update_text, data); break; case '0': /* Beginning of line */ case 'H': /* Scroll left */ @@ -237,8 +222,8 @@ do_resize: hscroll--; /* Reprint current page to scroll horizontally */ back_lines(page_length); - refresh_text_box(dialog, box, boxh, boxw, - cur_y, cur_x); + refresh_text_box(dialog, box, boxh, boxw, cur_y, + cur_x, update_text, data); break; case 'L': /* Scroll right */ case 'l': @@ -248,11 +233,12 @@ do_resize: hscroll++; /* Reprint current page to scroll horizontally */ back_lines(page_length); - refresh_text_box(dialog, box, boxh, boxw, - cur_y, cur_x); + refresh_text_box(dialog, box, boxh, boxw, cur_y, + cur_x, update_text, data); break; case KEY_ESC: - key = on_key_esc(dialog); + if (on_key_esc(dialog) == KEY_ESC) + done = true; break; case KEY_RESIZE: back_lines(height); @@ -260,11 +246,31 @@ do_resize: delwin(dialog); on_key_resize(); goto do_resize; + default: + for (i = 0; keys[i]; i++) { + if (key == keys[i]) { + done = true; + break; + } + } } } delwin(box); delwin(dialog); - return key; /* ESC pressed */ + if (_vscroll) { + const char *s; + + s = buf; + *_vscroll = 0; + back_lines(page_length); + while (s < page && (s = strchr(s, '\n'))) { + (*_vscroll)++; + s++; + } + } + if (_hscroll) + *_hscroll = hscroll; + return key; } /* @@ -301,12 +307,23 @@ static void back_lines(int n) } /* - * Print a new page of text. Called by dialog_textbox(). + * Print a new page of text. */ -static void print_page(WINDOW * win, int height, int width) +static void print_page(WINDOW *win, int height, int width, update_text_fn + update_text, void *data) { int i, passed_end = 0; + if (update_text) { + char *end; + + for (i = 0; i < height; i++) + get_line(); + end = page; + back_lines(height); + update_text(buf, page - buf, end - buf, data); + } + page_length = 0; for (i = 0; i < height; i++) { print_line(win, i, width); @@ -319,7 +336,7 @@ static void print_page(WINDOW * win, int height, int width) } /* - * Print a new line of text. Called by dialog_textbox() and print_page(). + * Print a new line of text. */ static void print_line(WINDOW * win, int row, int width) { @@ -357,10 +374,8 @@ static char *get_line(void) end_reached = 0; while (*page != '\n') { if (*page == '\0') { - if (!end_reached) { - end_reached = 1; - break; - } + end_reached = 1; + break; } else if (i < MAX_LEN) line[i++] = *(page++); else { @@ -373,7 +388,7 @@ static char *get_line(void) if (i <= MAX_LEN) line[i] = '\0'; if (!end_reached) - page++; /* move pass '\n' */ + page++; /* move past '\n' */ return line; } diff --git a/scripts/kconfig/lxdialog/util.c b/scripts/kconfig/lxdialog/util.c index f2375ad7ebc..109d53117d2 100644 --- a/scripts/kconfig/lxdialog/util.c +++ b/scripts/kconfig/lxdialog/util.c @@ -23,6 +23,9 @@ #include "dialog.h" +/* Needed in signal handler in mconf.c */ +int saved_x, saved_y; + struct dialog_info dlg; static void set_mono_theme(void) @@ -273,6 +276,10 @@ int init_dialog(const char *backtitle) int height, width; initscr(); /* Init curses */ + + /* Get current cursor position for signal handler in mconf.c */ + getyx(stdscr, saved_y, saved_x); + getmaxyx(stdscr, height, width); if (height < 19 || width < 80) { endwin(); diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c index f584a281bb4..48f67448af7 100644 --- a/scripts/kconfig/mconf.c +++ b/scripts/kconfig/mconf.c @@ -236,16 +236,19 @@ search_help[] = N_( "Result:\n" "-----------------------------------------------------------------\n" "Symbol: FOO [=m]\n" + "Type : tristate\n" "Prompt: Foo bus is used to drive the bar HW\n" - "Defined at drivers/pci/Kconfig:47\n" - "Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n" - "Location:\n" - " -> Bus options (PCI, PCMCIA, EISA, ISA)\n" - " -> PCI support (PCI [=y])\n" - " -> PCI access mode (<choice> [=y])\n" - "Selects: LIBCRC32\n" - "Selected by: BAR\n" + " Defined at drivers/pci/Kconfig:47\n" + " Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n" + " Location:\n" + " -> Bus options (PCI, PCMCIA, EISA, ISA)\n" + " -> PCI support (PCI [=y])\n" + "(1) -> PCI access mode (<choice> [=y])\n" + " Selects: LIBCRC32\n" + " Selected by: BAR\n" "-----------------------------------------------------------------\n" + "o The line 'Type:' shows the type of the configuration option for\n" + " this symbol (boolean, tristate, string, ...)\n" "o The line 'Prompt:' shows the text used in the menu structure for\n" " this symbol\n" "o The 'Defined at' line tell at what file / line number the symbol\n" @@ -254,8 +257,12 @@ search_help[] = N_( " this symbol to be visible in the menu (selectable)\n" "o The 'Location:' lines tell where in the menu structure this symbol\n" " is located\n" - " A location followed by a [=y] indicate that this is a selectable\n" - " menu item - and current value is displayed inside brackets.\n" + " A location followed by a [=y] indicates that this is a\n" + " selectable menu item - and the current value is displayed inside\n" + " brackets.\n" + " Press the key in the (#) prefix to jump directly to that\n" + " location. You will be returned to the current search results\n" + " after exiting this new menu.\n" "o The 'Selects:' line tell what symbol will be automatically\n" " selected if this symbol is selected (y or m)\n" "o The 'Selected by' line tell what symbol has selected this symbol\n" @@ -273,13 +280,15 @@ static struct menu *current_menu; static int child_count; static int single_menu_mode; static int show_all_options; -static int saved_x, saved_y; -static void conf(struct menu *menu); +static void conf(struct menu *menu, struct menu *active_menu); static void conf_choice(struct menu *menu); static void conf_string(struct menu *menu); static void conf_load(void); static void conf_save(void); +static int show_textbox_ext(const char *title, char *text, int r, int c, + int *keys, int *vscroll, int *hscroll, + update_text_fn update_text, void *data); static void show_textbox(const char *title, const char *text, int r, int c); static void show_helptext(const char *title, const char *text); static void show_help(struct menu *menu); @@ -302,12 +311,47 @@ static void set_config_filename(const char *config_filename) } +struct search_data { + struct jk_head *head; + struct menu **targets; + int *keys; +}; + +static void update_text(char *buf, size_t start, size_t end, void *_data) +{ + struct search_data *data = _data; + struct jump_key *pos; + int k = 0; + + CIRCLEQ_FOREACH(pos, data->head, entries) { + if (pos->offset >= start && pos->offset < end) { + char header[4]; + + if (k < JUMP_NB) { + int key = '0' + (pos->index % JUMP_NB) + 1; + + sprintf(header, "(%c)", key); + data->keys[k] = key; + data->targets[k] = pos->target; + k++; + } else { + sprintf(header, " "); + } + + memcpy(buf + pos->offset, header, sizeof(header) - 1); + } + } + data->keys[k] = 0; +} + static void search_conf(void) { struct symbol **sym_arr; struct gstr res; char *dialog_input; - int dres; + int dres, vscroll = 0, hscroll = 0; + bool again; + again: dialog_clear(); dres = dialog_inputbox(_("Search Configuration Parameter"), @@ -330,10 +374,30 @@ again: dialog_input += strlen(CONFIG_); sym_arr = sym_re_search(dialog_input); - res = get_relations_str(sym_arr); + do { + struct jk_head head = CIRCLEQ_HEAD_INITIALIZER(head); + struct menu *targets[JUMP_NB]; + int keys[JUMP_NB + 1], i; + struct search_data data = { + .head = &head, + .targets = targets, + .keys = keys, + }; + + res = get_relations_str(sym_arr, &head); + dres = show_textbox_ext(_("Search Results"), (char *) + str_get(&res), 0, 0, keys, &vscroll, + &hscroll, &update_text, (void *) + &data); + again = false; + for (i = 0; i < JUMP_NB && keys[i]; i++) + if (dres == keys[i]) { + conf(targets[i]->parent, targets[i]); + again = true; + } + str_free(&res); + } while (again); free(sym_arr); - show_textbox(_("Search Results"), str_get(&res), 0, 0); - str_free(&res); } static void build_conf(struct menu *menu) @@ -514,12 +578,11 @@ conf_childs: indent -= doint; } -static void conf(struct menu *menu) +static void conf(struct menu *menu, struct menu *active_menu) { struct menu *submenu; const char *prompt = menu_get_prompt(menu); struct symbol *sym; - struct menu *active_menu = NULL; int res; int s_scroll = 0; @@ -562,13 +625,13 @@ static void conf(struct menu *menu) if (single_menu_mode) submenu->data = (void *) (long) !submenu->data; else - conf(submenu); + conf(submenu, NULL); break; case 't': if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes) conf_choice(submenu); else if (submenu->prompt->type == P_MENU) - conf(submenu); + conf(submenu, NULL); break; case 's': conf_string(submenu); @@ -607,7 +670,7 @@ static void conf(struct menu *menu) if (item_is_tag('t')) sym_toggle_tristate_value(sym); else if (item_is_tag('m')) - conf(submenu); + conf(submenu, NULL); break; case 7: search_conf(); @@ -619,10 +682,19 @@ static void conf(struct menu *menu) } } -static void show_textbox(const char *title, const char *text, int r, int c) +static int show_textbox_ext(const char *title, char *text, int r, int c, int + *keys, int *vscroll, int *hscroll, update_text_fn + update_text, void *data) { dialog_clear(); - dialog_textbox(title, text, r, c); + return dialog_textbox(title, text, r, c, keys, vscroll, hscroll, + update_text, data); +} + +static void show_textbox(const char *title, const char *text, int r, int c) +{ + show_textbox_ext(title, (char *) text, r, c, (int []) {0}, NULL, NULL, + NULL, NULL); } static void show_helptext(const char *title, const char *text) @@ -862,9 +934,6 @@ int main(int ac, char **av) single_menu_mode = 1; } - initscr(); - - getyx(stdscr, saved_y, saved_x); if (init_dialog(NULL)) { fprintf(stderr, N_("Your display is too small to run Menuconfig!\n")); fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n")); @@ -873,7 +942,7 @@ int main(int ac, char **av) set_config_filename(conf_get_configname()); do { - conf(&rootmenu); + conf(&rootmenu, NULL); res = handle_exit(); } while (res == KEY_ESC); diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index 8c2a97e60fa..a3cade659f8 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -507,10 +507,12 @@ const char *menu_get_help(struct menu *menu) return ""; } -static void get_prompt_str(struct gstr *r, struct property *prop) +static void get_prompt_str(struct gstr *r, struct property *prop, + struct jk_head *head) { int i, j; - struct menu *submenu[8], *menu; + struct menu *submenu[8], *menu, *location = NULL; + struct jump_key *jump; str_printf(r, _("Prompt: %s\n"), _(prop->text)); str_printf(r, _(" Defined at %s:%d\n"), prop->menu->file->name, @@ -521,13 +523,43 @@ static void get_prompt_str(struct gstr *r, struct property *prop) str_append(r, "\n"); } menu = prop->menu->parent; - for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) + for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) { + bool accessible = menu_is_visible(menu); + submenu[i++] = menu; + if (location == NULL && accessible) + location = menu; + } + if (head && location) { + jump = malloc(sizeof(struct jump_key)); + + if (menu_is_visible(prop->menu)) { + /* + * There is not enough room to put the hint at the + * beginning of the "Prompt" line. Put the hint on the + * last "Location" line even when it would belong on + * the former. + */ + jump->target = prop->menu; + } else + jump->target = location; + + if (CIRCLEQ_EMPTY(head)) + jump->index = 0; + else + jump->index = CIRCLEQ_LAST(head)->index + 1; + + CIRCLEQ_INSERT_TAIL(head, jump, entries); + } + if (i > 0) { str_printf(r, _(" Location:\n")); for (j = 4; --i >= 0; j += 2) { menu = submenu[i]; - str_printf(r, "%*c-> %s", j, ' ', _(menu_get_prompt(menu))); + if (head && location && menu == location) + jump->offset = r->len - 1; + str_printf(r, "%*c-> %s", j, ' ', + _(menu_get_prompt(menu))); if (menu->sym) { str_printf(r, " (%s [=%s])", menu->sym->name ? menu->sym->name : _("<choice>"), @@ -538,7 +570,10 @@ static void get_prompt_str(struct gstr *r, struct property *prop) } } -void get_symbol_str(struct gstr *r, struct symbol *sym) +/* + * head is optional and may be NULL + */ +void get_symbol_str(struct gstr *r, struct symbol *sym, struct jk_head *head) { bool hit; struct property *prop; @@ -557,7 +592,7 @@ void get_symbol_str(struct gstr *r, struct symbol *sym) } } for_all_prompts(sym, prop) - get_prompt_str(r, prop); + get_prompt_str(r, prop, head); hit = false; for_all_properties(sym, prop, P_SELECT) { if (!hit) { @@ -577,14 +612,14 @@ void get_symbol_str(struct gstr *r, struct symbol *sym) str_append(r, "\n\n"); } -struct gstr get_relations_str(struct symbol **sym_arr) +struct gstr get_relations_str(struct symbol **sym_arr, struct jk_head *head) { struct symbol *sym; struct gstr res = str_new(); int i; for (i = 0; sym_arr && (sym = sym_arr[i]); i++) - get_symbol_str(&res, sym); + get_symbol_str(&res, sym, head); if (!i) str_append(&res, _("No matches found.\n")); return res; @@ -603,5 +638,5 @@ void menu_get_ext_help(struct menu *menu, struct gstr *help) } str_printf(help, "%s\n", _(help_text)); if (sym) - get_symbol_str(help, sym); + get_symbol_str(help, sym, NULL); } diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c index 1704a8562a5..87d4b15da95 100644 --- a/scripts/kconfig/nconf.c +++ b/scripts/kconfig/nconf.c @@ -721,7 +721,7 @@ again: dialog_input += strlen(CONFIG_); sym_arr = sym_re_search(dialog_input); - res = get_relations_str(sym_arr); + res = get_relations_str(sym_arr, NULL); free(sym_arr); show_scroll_win(main_window, _("Search Results"), str_get(&res)); diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 8fd107a3fac..46e7aff80d1 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -6,6 +6,7 @@ use strict; ## Copyright (C) 2000, 1 Tim Waugh <twaugh@redhat.com> ## ## Copyright (C) 2001 Simon Huggins ## ## Copyright (C) 2005-2012 Randy Dunlap ## +## Copyright (C) 2012 Dan Luedtke ## ## ## ## #define enhancements by Armin Kuster <akuster@mvista.com> ## ## Copyright (c) 2000 MontaVista Software, Inc. ## @@ -35,6 +36,8 @@ use strict; # Small fixes (like spaces vs. \s in regex) # -- Tim Jansen <tim@tjansen.de> +# 25/07/2012 - Added support for HTML5 +# -- Dan Luedtke <mail@danrl.de> # # This will read a 'c' file and scan for embedded comments in the @@ -44,12 +47,16 @@ use strict; # Note: This only supports 'c'. # usage: -# kernel-doc [ -docbook | -html | -text | -man | -list ] [ -no-doc-sections ] -# [ -function funcname [ -function funcname ...] ] c file(s)s > outputfile +# kernel-doc [ -docbook | -html | -html5 | -text | -man | -list ] +# [ -no-doc-sections ] +# [ -function funcname [ -function funcname ...] ] +# c file(s)s > outputfile # or -# [ -nofunction funcname [ -function funcname ...] ] c file(s)s > outputfile +# [ -nofunction funcname [ -function funcname ...] ] +# c file(s)s > outputfile # -# Set output format using one of -docbook -html -text or -man. Default is man. +# Set output format using one of -docbook -html -html5 -text or -man. +# Default is man. # The -list format is for internal use by docproc. # # -no-doc-sections @@ -182,6 +189,14 @@ my $local_lt = "\\\\\\\\lt:"; my $local_gt = "\\\\\\\\gt:"; my $blankline_html = $local_lt . "p" . $local_gt; # was "<p>" +# html version 5 +my %highlights_html5 = ( $type_constant, "<span class=\"const\">\$1</span>", + $type_func, "<span class=\"func\">\$1</span>", + $type_struct_xml, "<span class=\"struct\">\$1</span>", + $type_env, "<span class=\"env\">\$1</span>", + $type_param, "<span class=\"param\">\$1</span>" ); +my $blankline_html5 = $local_lt . "br /" . $local_gt; + # XML, docbook format my %highlights_xml = ( "([^=])\\\"([^\\\"<]+)\\\"", "\$1<quote>\$2</quote>", $type_constant, "<constant>\$1</constant>", @@ -230,6 +245,7 @@ my $dohighlight = ""; my $verbose = 0; my $output_mode = "man"; +my $output_preformatted = 0; my $no_doc_sections = 0; my %highlights = %highlights_man; my $blankline = $blankline_man; @@ -280,9 +296,10 @@ my $doc_special = "\@\%\$\&"; my $doc_start = '^/\*\*\s*$'; # Allow whitespace at end of comment start. my $doc_end = '\*/'; my $doc_com = '\s*\*\s*'; +my $doc_com_body = '\s*\* ?'; my $doc_decl = $doc_com . '(\w+)'; my $doc_sect = $doc_com . '([' . $doc_special . ']?[\w\s]+):(.*)'; -my $doc_content = $doc_com . '(.*)'; +my $doc_content = $doc_com_body . '(.*)'; my $doc_block = $doc_com . 'DOC:\s*(.*)?'; my %constants; @@ -309,6 +326,10 @@ while ($ARGV[0] =~ m/^-(.*)/) { $output_mode = "html"; %highlights = %highlights_html; $blankline = $blankline_html; + } elsif ($cmd eq "-html5") { + $output_mode = "html5"; + %highlights = %highlights_html5; + $blankline = $blankline_html5; } elsif ($cmd eq "-man") { $output_mode = "man"; %highlights = %highlights_man; @@ -351,10 +372,11 @@ while ($ARGV[0] =~ m/^-(.*)/) { # continue execution near EOF; sub usage { - print "Usage: $0 [ -v ] [ -docbook | -html | -text | -man | -list ]\n"; + print "Usage: $0 [ -docbook | -html | -html5 | -text | -man | -list ]\n"; print " [ -no-doc-sections ]\n"; print " [ -function funcname [ -function funcname ...] ]\n"; print " [ -nofunction funcname [ -nofunction funcname ...] ]\n"; + print " [ -v ]\n"; print " c source file(s) > outputfile\n"; print " -v : verbose output, more warnings & other info listed\n"; exit 1; @@ -448,7 +470,8 @@ sub output_highlight { # confess "output_highlight got called with no args?\n"; # } - if ($output_mode eq "html" || $output_mode eq "xml") { + if ($output_mode eq "html" || $output_mode eq "html5" || + $output_mode eq "xml") { $contents = local_unescape($contents); # convert data read & converted thru xml_escape() into &xyz; format: $contents =~ s/\\\\\\/\&/g; @@ -458,9 +481,19 @@ sub output_highlight { die $@ if $@; # print STDERR "contents af:$contents\n"; +# strip whitespaces when generating html5 + if ($output_mode eq "html5") { + $contents =~ s/^\s+//; + $contents =~ s/\s+$//; + } foreach $line (split "\n", $contents) { + if (! $output_preformatted) { + $line =~ s/^\s*//; + } if ($line eq ""){ - print $lineprefix, local_unescape($blankline); + if (! $output_preformatted) { + print $lineprefix, local_unescape($blankline); + } } else { $line =~ s/\\\\\\/\&/g; if ($output_mode eq "man" && substr($line, 0, 1) eq ".") { @@ -473,7 +506,7 @@ sub output_highlight { } } -#output sections in html +# output sections in html sub output_section_html(%) { my %args = %{$_[0]}; my $section; @@ -633,6 +666,239 @@ sub output_blockhead_html(%) { print "<hr>\n"; } +# output sections in html5 +sub output_section_html5(%) { + my %args = %{$_[0]}; + my $section; + + foreach $section (@{$args{'sectionlist'}}) { + print "<section>\n"; + print "<h1>$section</h1>\n"; + print "<p>\n"; + output_highlight($args{'sections'}{$section}); + print "</p>\n"; + print "</section>\n"; + } +} + +# output enum in html5 +sub output_enum_html5(%) { + my %args = %{$_[0]}; + my ($parameter); + my $count; + my $html5id; + + $html5id = $args{'enum'}; + $html5id =~ s/[^a-zA-Z0-9\-]+/_/g; + print "<article class=\"enum\" id=\"enum:". $html5id . "\">"; + print "<h1>enum " . $args{'enum'} . "</h1>\n"; + print "<ol class=\"code\">\n"; + print "<li>"; + print "<span class=\"keyword\">enum</span> "; + print "<span class=\"identifier\">" . $args{'enum'} . "</span> {"; + print "</li>\n"; + $count = 0; + foreach $parameter (@{$args{'parameterlist'}}) { + print "<li class=\"indent\">"; + print "<span class=\"param\">" . $parameter . "</span>"; + if ($count != $#{$args{'parameterlist'}}) { + $count++; + print ","; + } + print "</li>\n"; + } + print "<li>};</li>\n"; + print "</ol>\n"; + + print "<section>\n"; + print "<h1>Constants</h1>\n"; + print "<dl>\n"; + foreach $parameter (@{$args{'parameterlist'}}) { + print "<dt>" . $parameter . "</dt>\n"; + print "<dd>"; + output_highlight($args{'parameterdescs'}{$parameter}); + print "</dd>\n"; + } + print "</dl>\n"; + print "</section>\n"; + output_section_html5(@_); + print "</article>\n"; +} + +# output typedef in html5 +sub output_typedef_html5(%) { + my %args = %{$_[0]}; + my ($parameter); + my $count; + my $html5id; + + $html5id = $args{'typedef'}; + $html5id =~ s/[^a-zA-Z0-9\-]+/_/g; + print "<article class=\"typedef\" id=\"typedef:" . $html5id . "\">\n"; + print "<h1>typedef " . $args{'typedef'} . "</h1>\n"; + + print "<ol class=\"code\">\n"; + print "<li>"; + print "<span class=\"keyword\">typedef</span> "; + print "<span class=\"identifier\">" . $args{'typedef'} . "</span>"; + print "</li>\n"; + print "</ol>\n"; + output_section_html5(@_); + print "</article>\n"; +} + +# output struct in html5 +sub output_struct_html5(%) { + my %args = %{$_[0]}; + my ($parameter); + my $html5id; + + $html5id = $args{'struct'}; + $html5id =~ s/[^a-zA-Z0-9\-]+/_/g; + print "<article class=\"struct\" id=\"struct:" . $html5id . "\">\n"; + print "<hgroup>\n"; + print "<h1>" . $args{'type'} . " " . $args{'struct'} . "</h1>"; + print "<h2>". $args{'purpose'} . "</h2>\n"; + print "</hgroup>\n"; + print "<ol class=\"code\">\n"; + print "<li>"; + print "<span class=\"type\">" . $args{'type'} . "</span> "; + print "<span class=\"identifier\">" . $args{'struct'} . "</span> {"; + print "</li>\n"; + foreach $parameter (@{$args{'parameterlist'}}) { + print "<li class=\"indent\">"; + if ($parameter =~ /^#/) { + print "<span class=\"param\">" . $parameter ."</span>\n"; + print "</li>\n"; + next; + } + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; + + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + $type = $args{'parametertypes'}{$parameter}; + if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { + # pointer-to-function + print "<span class=\"type\">$1</span> "; + print "<span class=\"param\">$parameter</span>"; + print "<span class=\"type\">)</span> "; + print "(<span class=\"args\">$2</span>);"; + } elsif ($type =~ m/^(.*?)\s*(:.*)/) { + # bitfield + print "<span class=\"type\">$1</span> "; + print "<span class=\"param\">$parameter</span>"; + print "<span class=\"bits\">$2</span>;"; + } else { + print "<span class=\"type\">$type</span> "; + print "<span class=\"param\">$parameter</span>;"; + } + print "</li>\n"; + } + print "<li>};</li>\n"; + print "</ol>\n"; + + print "<section>\n"; + print "<h1>Members</h1>\n"; + print "<dl>\n"; + foreach $parameter (@{$args{'parameterlist'}}) { + ($parameter =~ /^#/) && next; + + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; + + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + print "<dt>" . $parameter . "</dt>\n"; + print "<dd>"; + output_highlight($args{'parameterdescs'}{$parameter_name}); + print "</dd>\n"; + } + print "</dl>\n"; + print "</section>\n"; + output_section_html5(@_); + print "</article>\n"; +} + +# output function in html5 +sub output_function_html5(%) { + my %args = %{$_[0]}; + my ($parameter, $section); + my $count; + my $html5id; + + $html5id = $args{'function'}; + $html5id =~ s/[^a-zA-Z0-9\-]+/_/g; + print "<article class=\"function\" id=\"func:". $html5id . "\">\n"; + print "<hgroup>\n"; + print "<h1>" . $args{'function'} . "</h1>"; + print "<h2>" . $args{'purpose'} . "</h2>\n"; + print "</hgroup>\n"; + print "<ol class=\"code\">\n"; + print "<li>"; + print "<span class=\"type\">" . $args{'functiontype'} . "</span> "; + print "<span class=\"identifier\">" . $args{'function'} . "</span> ("; + print "</li>"; + $count = 0; + foreach $parameter (@{$args{'parameterlist'}}) { + print "<li class=\"indent\">"; + $type = $args{'parametertypes'}{$parameter}; + if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { + # pointer-to-function + print "<span class=\"type\">$1</span> "; + print "<span class=\"param\">$parameter</span>"; + print "<span class=\"type\">)</span> "; + print "(<span class=\"args\">$2</span>)"; + } else { + print "<span class=\"type\">$type</span> "; + print "<span class=\"param\">$parameter</span>"; + } + if ($count != $#{$args{'parameterlist'}}) { + $count++; + print ","; + } + print "</li>\n"; + } + print "<li>)</li>\n"; + print "</ol>\n"; + + print "<section>\n"; + print "<h1>Arguments</h1>\n"; + print "<p>\n"; + print "<dl>\n"; + foreach $parameter (@{$args{'parameterlist'}}) { + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; + + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + print "<dt>" . $parameter . "</dt>\n"; + print "<dd>"; + output_highlight($args{'parameterdescs'}{$parameter_name}); + print "</dd>\n"; + } + print "</dl>\n"; + print "</section>\n"; + output_section_html5(@_); + print "</article>\n"; +} + +# output DOC: block header in html5 +sub output_blockhead_html5(%) { + my %args = %{$_[0]}; + my ($parameter, $section); + my $count; + my $html5id; + + foreach $section (@{$args{'sectionlist'}}) { + $html5id = $section; + $html5id =~ s/[^a-zA-Z0-9\-]+/_/g; + print "<article class=\"doc\" id=\"doc:". $html5id . "\">\n"; + print "<h1>$section</h1>\n"; + print "<p>\n"; + output_highlight($args{'sections'}{$section}); + print "</p>\n"; + } + print "</article>\n"; +} + sub output_section_xml(%) { my %args = %{$_[0]}; my $section; @@ -643,10 +909,12 @@ sub output_section_xml(%) { print "<title>$section</title>\n"; if ($section =~ m/EXAMPLE/i) { print "<informalexample><programlisting>\n"; + $output_preformatted = 1; } else { print "<para>\n"; } output_highlight($args{'sections'}{$section}); + $output_preformatted = 0; if ($section =~ m/EXAMPLE/i) { print "</programlisting></informalexample>\n"; } else { @@ -949,10 +1217,12 @@ sub output_blockhead_xml(%) { } if ($section =~ m/EXAMPLE/i) { print "<example><para>\n"; + $output_preformatted = 1; } else { print "<para>\n"; } output_highlight($args{'sections'}{$section}); + $output_preformatted = 0; if ($section =~ m/EXAMPLE/i) { print "</para></example>\n"; } else { @@ -1028,10 +1298,12 @@ sub output_function_gnome { print "<simplesect>\n <title>$section</title>\n"; if ($section =~ m/EXAMPLE/i) { print "<example><programlisting>\n"; + $output_preformatted = 1; } else { } print "<para>\n"; output_highlight($args{'sections'}{$section}); + $output_preformatted = 0; print "</para>\n"; if ($section =~ m/EXAMPLE/i) { print "</programlisting></example>\n"; @@ -2046,6 +2318,9 @@ sub process_file($) { $section_counter = 0; while (<IN>) { + while (s/\\\s*$//) { + $_ .= <IN>; + } if ($state == 0) { if (/$doc_start/o) { $state = 1; # next line is always the function name @@ -2073,7 +2348,7 @@ sub process_file($) { $descr= $1; $descr =~ s/^\s*//; $descr =~ s/\s*$//; - $descr =~ s/\s+/ /; + $descr =~ s/\s+/ /g; $declaration_purpose = xml_escape($descr); $in_purpose = 1; } else { @@ -2165,6 +2440,7 @@ sub process_file($) { # Continued declaration purpose chomp($declaration_purpose); $declaration_purpose .= " " . xml_escape($1); + $declaration_purpose =~ s/\s+/ /g; } else { $contents .= $1 . "\n"; } diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 68e9f5ed0a6..0d93856a03f 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -821,12 +821,15 @@ static const char *section_white_list[] = ".debug*", ".zdebug*", /* Compressed debug sections. */ ".GCC-command-line", /* mn10300 */ + ".GCC.command.line", /* record-gcc-switches, non mn10300 */ ".mdebug*", /* alpha, score, mips etc. */ ".pdr", /* alpha, score, mips etc. */ ".stab*", ".note*", ".got*", ".toc*", + ".xt.prop", /* xtensa */ + ".xt.lit", /* xtensa */ NULL }; diff --git a/scripts/package/buildtar b/scripts/package/buildtar index 8a7b15598ea..62d8234f878 100644 --- a/scripts/package/buildtar +++ b/scripts/package/buildtar @@ -28,15 +28,15 @@ case "${1}" in file_ext="" ;; targz-pkg) - compress="gzip -c9" + compress="gzip" file_ext=".gz" ;; tarbz2-pkg) - compress="bzip2 -c9" + compress="bzip2" file_ext=".bz2" ;; tarxz-pkg) - compress="xz -c9" + compress="xz" file_ext=".xz" ;; *) @@ -109,7 +109,7 @@ esac if tar --owner=root --group=root --help >/dev/null 2>&1; then opts="--owner=root --group=root" fi - tar cf - . $opts | ${compress} > "${tarball}${file_ext}" + tar cf - boot/* lib/* $opts | ${compress} > "${tarball}${file_ext}" ) echo "Tarball successfully created in ${tarball}${file_ext}" diff --git a/scripts/sign-file b/scripts/sign-file new file mode 100644 index 00000000000..e58e34e50ac --- /dev/null +++ b/scripts/sign-file @@ -0,0 +1,115 @@ +#!/bin/sh +# +# Sign a module file using the given key. +# +# Format: sign-file <key> <x509> <src-file> <dst-file> +# + +scripts=`dirname $0` + +CONFIG_MODULE_SIG_SHA512=y +if [ -r .config ] +then + . ./.config +fi + +key="$1" +x509="$2" +src="$3" +dst="$4" + +if [ ! -r "$key" ] +then + echo "Can't read private key" >&2 + exit 2 +fi + +if [ ! -r "$x509" ] +then + echo "Can't read X.509 certificate" >&2 + exit 2 +fi +if [ ! -r "$x509.signer" ] +then + echo "Can't read Signer name" >&2 + exit 2; +fi +if [ ! -r "$x509.keyid" ] +then + echo "Can't read Key identifier" >&2 + exit 2; +fi + +# +# Signature parameters +# +algo=1 # Public-key crypto algorithm: RSA +hash= # Digest algorithm +id_type=1 # Identifier type: X.509 + +# +# Digest the data +# +dgst= +if [ "$CONFIG_MODULE_SIG_SHA1" = "y" ] +then + prologue="0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14" + dgst=-sha1 + hash=2 +elif [ "$CONFIG_MODULE_SIG_SHA224" = "y" ] +then + prologue="0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1C" + dgst=-sha224 + hash=7 +elif [ "$CONFIG_MODULE_SIG_SHA256" = "y" ] +then + prologue="0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20" + dgst=-sha256 + hash=4 +elif [ "$CONFIG_MODULE_SIG_SHA384" = "y" ] +then + prologue="0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30" + dgst=-sha384 + hash=5 +elif [ "$CONFIG_MODULE_SIG_SHA512" = "y" ] +then + prologue="0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40" + dgst=-sha512 + hash=6 +else + echo "$0: Can't determine hash algorithm" >&2 + exit 2 +fi + +( +perl -e "binmode STDOUT; print pack(\"C*\", $prologue)" || exit $? +openssl dgst $dgst -binary $src || exit $? +) >$src.dig || exit $? + +# +# Generate the binary signature, which will be just the integer that comprises +# the signature with no metadata attached. +# +openssl rsautl -sign -inkey $key -keyform PEM -in $src.dig -out $src.sig || exit $? +signerlen=`stat -c %s $x509.signer` +keyidlen=`stat -c %s $x509.keyid` +siglen=`stat -c %s $src.sig` + +# +# Build the signed binary +# +( + cat $src || exit $? + echo '~Module signature appended~' || exit $? + cat $x509.signer $x509.keyid || exit $? + + # Preface each signature integer with a 2-byte BE length + perl -e "binmode STDOUT; print pack(\"n\", $siglen)" || exit $? + cat $src.sig || exit $? + + # Generate the information block + perl -e "binmode STDOUT; print pack(\"CCCCCxxxN\", $algo, $hash, $id_type, $signerlen, $keyidlen, $siglen + 2)" || exit $? +) >$dst~ || exit $? + +# Permit in-place signing +mv $dst~ $dst || exit $? diff --git a/scripts/tags.sh b/scripts/tags.sh index cff8faad73d..79fdafb0d26 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -154,7 +154,9 @@ exuberant() --regex-c++='/__CLEARPAGEFLAG_NOOP\(([^,)]*).*/__ClearPage\1/' \ --regex-c++='/TESTCLEARFLAG_FALSE\(([^,)]*).*/TestClearPage\1/' \ --regex-c++='/__TESTCLEARFLAG_FALSE\(([^,)]*).*/__TestClearPage\1/' \ - --regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/' + --regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/' \ + --regex-c='/PCI_OP_READ\(([a-z]*[a-z]).*[1-4]\)/pci_bus_read_config_\1/' \ + --regex-c='/PCI_OP_WRITE\(([a-z]*[a-z]).*[1-4]\)/pci_bus_write_config_\1/' all_kconfigs | xargs $1 -a \ --langdef=kconfig --language-force=kconfig \ @@ -197,7 +199,9 @@ emacs() --regex='/__CLEARPAGEFLAG_NOOP\(([^,)]*).*/__ClearPage\1/' \ --regex='/TESTCLEARFLAG_FALSE\(([^,)]*).*/TestClearPage\1/' \ --regex='/__TESTCLEARFLAG_FALSE\(([^,)]*).*/__TestClearPage\1/' \ - --regex='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/' + --regex='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/' \ + --regex='/PCI_OP_READ\(([a-z]*[a-z]).*[1-4]\)/pci_bus_read_config_\1/' \ + --regex='/PCI_OP_WRITE\(([a-z]*[a-z]).*[1-4]\)/pci_bus_write_config_\1/' all_kconfigs | xargs $1 -a \ --regex='/^[ \t]*\(\(menu\)*config\)[ \t]+\([a-zA-Z0-9_]+\)/\3/' diff --git a/scripts/x509keyid b/scripts/x509keyid new file mode 100755 index 00000000000..c8e91a4af38 --- /dev/null +++ b/scripts/x509keyid @@ -0,0 +1,268 @@ +#!/usr/bin/perl -w +# +# Generate an identifier from an X.509 certificate that can be placed in a +# module signature to indentify the key to use. +# +# Format: +# +# ./scripts/x509keyid <x509-cert> <signer's-name> <key-id> +# +# We read the DER-encoded X509 certificate and parse it to extract the Subject +# name and Subject Key Identifier. The provide the data we need to build the +# certificate identifier. +# +# The signer's name part of the identifier is fabricated from the commonName, +# the organizationName or the emailAddress components of the X.509 subject +# name and written to the second named file. +# +# The subject key ID to select which of that signer's certificates we're +# intending to use to sign the module is written to the third named file. +# +use strict; + +my $raw_data; + +die "Need three filenames\n" if ($#ARGV != 2); + +my $src = $ARGV[0]; + +open(FD, "<$src") || die $src; +binmode FD; +my @st = stat(FD); +die $src if (!@st); +read(FD, $raw_data, $st[7]) || die $src; +close(FD); + +my $UNIV = 0 << 6; +my $APPL = 1 << 6; +my $CONT = 2 << 6; +my $PRIV = 3 << 6; + +my $CONS = 0x20; + +my $BOOLEAN = 0x01; +my $INTEGER = 0x02; +my $BIT_STRING = 0x03; +my $OCTET_STRING = 0x04; +my $NULL = 0x05; +my $OBJ_ID = 0x06; +my $UTF8String = 0x0c; +my $SEQUENCE = 0x10; +my $SET = 0x11; +my $UTCTime = 0x17; +my $GeneralizedTime = 0x18; + +my %OIDs = ( + pack("CCC", 85, 4, 3) => "commonName", + pack("CCC", 85, 4, 6) => "countryName", + pack("CCC", 85, 4, 10) => "organizationName", + pack("CCC", 85, 4, 11) => "organizationUnitName", + pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 1) => "rsaEncryption", + pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 5) => "sha1WithRSAEncryption", + pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 9, 1) => "emailAddress", + pack("CCC", 85, 29, 35) => "authorityKeyIdentifier", + pack("CCC", 85, 29, 14) => "subjectKeyIdentifier", + pack("CCC", 85, 29, 19) => "basicConstraints" +); + +############################################################################### +# +# Extract an ASN.1 element from a string and return information about it. +# +############################################################################### +sub asn1_extract($$@) +{ + my ($cursor, $expected_tag, $optional) = @_; + + return [ -1 ] + if ($cursor->[1] == 0 && $optional); + + die $src, ": ", $cursor->[0], ": ASN.1 data underrun (elem ", $cursor->[1], ")\n" + if ($cursor->[1] < 2); + + my ($tag, $len) = unpack("CC", substr(${$cursor->[2]}, $cursor->[0], 2)); + + if ($expected_tag != -1 && $tag != $expected_tag) { + return [ -1 ] + if ($optional); + die $src, ": ", $cursor->[0], ": ASN.1 unexpected tag (", $tag, + " not ", $expected_tag, ")\n"; + } + + $cursor->[0] += 2; + $cursor->[1] -= 2; + + die $src, ": ", $cursor->[0], ": ASN.1 long tag\n" + if (($tag & 0x1f) == 0x1f); + die $src, ": ", $cursor->[0], ": ASN.1 indefinite length\n" + if ($len == 0x80); + + if ($len > 0x80) { + my $l = $len - 0x80; + die $src, ": ", $cursor->[0], ": ASN.1 data underrun (len len $l)\n" + if ($cursor->[1] < $l); + + if ($l == 0x1) { + $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1)); + } elsif ($l = 0x2) { + $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0], 2)); + } elsif ($l = 0x3) { + $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1)) << 16; + $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0] + 1, 2)); + } elsif ($l = 0x4) { + $len = unpack("N", substr(${$cursor->[2]}, $cursor->[0], 4)); + } else { + die $src, ": ", $cursor->[0], ": ASN.1 element too long (", $l, ")\n"; + } + + $cursor->[0] += $l; + $cursor->[1] -= $l; + } + + die $src, ": ", $cursor->[0], ": ASN.1 data underrun (", $len, ")\n" + if ($cursor->[1] < $len); + + my $ret = [ $tag, [ $cursor->[0], $len, $cursor->[2] ] ]; + $cursor->[0] += $len; + $cursor->[1] -= $len; + + return $ret; +} + +############################################################################### +# +# Retrieve the data referred to by a cursor +# +############################################################################### +sub asn1_retrieve($) +{ + my ($cursor) = @_; + my ($offset, $len, $data) = @$cursor; + return substr($$data, $offset, $len); +} + +############################################################################### +# +# Roughly parse the X.509 certificate +# +############################################################################### +my $cursor = [ 0, length($raw_data), \$raw_data ]; + +my $cert = asn1_extract($cursor, $UNIV | $CONS | $SEQUENCE); +my $tbs = asn1_extract($cert->[1], $UNIV | $CONS | $SEQUENCE); +my $version = asn1_extract($tbs->[1], $CONT | $CONS | 0, 1); +my $serial_number = asn1_extract($tbs->[1], $UNIV | $INTEGER); +my $sig_type = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); +my $issuer = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); +my $validity = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); +my $subject = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); +my $key = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); +my $issuer_uid = asn1_extract($tbs->[1], $CONT | $CONS | 1, 1); +my $subject_uid = asn1_extract($tbs->[1], $CONT | $CONS | 2, 1); +my $extension_list = asn1_extract($tbs->[1], $CONT | $CONS | 3, 1); + +my $subject_key_id = (); +my $authority_key_id = (); + +# +# Parse the extension list +# +if ($extension_list->[0] != -1) { + my $extensions = asn1_extract($extension_list->[1], $UNIV | $CONS | $SEQUENCE); + + while ($extensions->[1]->[1] > 0) { + my $ext = asn1_extract($extensions->[1], $UNIV | $CONS | $SEQUENCE); + my $x_oid = asn1_extract($ext->[1], $UNIV | $OBJ_ID); + my $x_crit = asn1_extract($ext->[1], $UNIV | $BOOLEAN, 1); + my $x_val = asn1_extract($ext->[1], $UNIV | $OCTET_STRING); + + my $raw_oid = asn1_retrieve($x_oid->[1]); + next if (!exists($OIDs{$raw_oid})); + my $x_type = $OIDs{$raw_oid}; + + my $raw_value = asn1_retrieve($x_val->[1]); + + if ($x_type eq "subjectKeyIdentifier") { + my $vcursor = [ 0, length($raw_value), \$raw_value ]; + + $subject_key_id = asn1_extract($vcursor, $UNIV | $OCTET_STRING); + } + } +} + +############################################################################### +# +# Determine what we're going to use as the signer's name. In order of +# preference, take one of: commonName, organizationName or emailAddress. +# +############################################################################### +my $org = ""; +my $cn = ""; +my $email = ""; + +while ($subject->[1]->[1] > 0) { + my $rdn = asn1_extract($subject->[1], $UNIV | $CONS | $SET); + my $attr = asn1_extract($rdn->[1], $UNIV | $CONS | $SEQUENCE); + my $n_oid = asn1_extract($attr->[1], $UNIV | $OBJ_ID); + my $n_val = asn1_extract($attr->[1], -1); + + my $raw_oid = asn1_retrieve($n_oid->[1]); + next if (!exists($OIDs{$raw_oid})); + my $n_type = $OIDs{$raw_oid}; + + my $raw_value = asn1_retrieve($n_val->[1]); + + if ($n_type eq "organizationName") { + $org = $raw_value; + } elsif ($n_type eq "commonName") { + $cn = $raw_value; + } elsif ($n_type eq "emailAddress") { + $email = $raw_value; + } +} + +my $id_name = $email; + +if ($org && $cn) { + # Don't use the organizationName if the commonName repeats it + if (length($org) <= length($cn) && + substr($cn, 0, length($org)) eq $org) { + $id_name = $cn; + goto got_id_name; + } + + # Or a signifcant chunk of it + if (length($org) >= 7 && + length($cn) >= 7 && + substr($cn, 0, 7) eq substr($org, 0, 7)) { + $id_name = $cn; + goto got_id_name; + } + + $id_name = $org . ": " . $cn; +} elsif ($org) { + $id_name = $org; +} elsif ($cn) { + $id_name = $cn; +} + +got_id_name: + +############################################################################### +# +# Output the signer's name and the key identifier that we're going to include +# in module signatures. +# +############################################################################### +die $src, ": ", "X.509: Couldn't find the Subject Key Identifier extension\n" + if (!$subject_key_id); + +my $id_key_id = asn1_retrieve($subject_key_id->[1]); + +open(OUTFD, ">$ARGV[1]") || die $ARGV[1]; +print OUTFD $id_name; +close OUTFD || die $ARGV[1]; + +open(OUTFD, ">$ARGV[2]") || die $ARGV[2]; +print OUTFD $id_key_id; +close OUTFD || die $ARGV[2]; |