[PATCH] MODULE_VERSION() macro

From: Rusty Russell
Date: Mon Sep 08 2003 - 21:34:39 EST


Comments welcome!

Name: Add a MODULE_VERSION macro
Author: Rusty Russell
Depends: Misc/qemu-page-offset.patch.gz
Status: Tested on 2.6.0-test4-bk9

D: At the kernel summit, various people asked for a MODULE_VERSION
D: macro to store module strings (for later access through sysfs).
D: A simple md4 is needed to identify changes in modules which,
D: inevitably, do not update the version. It skips whitespace and
D: comments, and includes #includes in the same dir.
D:
D: The module versions should be set according to this definition,
D: based on the RPM one. Violators will be shot.
D:
D: [<epoch>`:']<version>[`-'<extraversion>]
D: <epoch>: A (small) unsigned integer which allows you to start versions
D: anew. If not mentioned, it's zero. eg. "2:1.0" is after
D: "1:2.0".
D: <version>: The <version> may contain only alphanumerics.
D: <extraversion>: Like <version>, but inserted for local
D: customizations, eg "rh3" or "rusty1".
D:
D: Comparison of two versions (assuming same epoch):
D:
D: Split each into all-digit and all-alphabetical parts. Compare each
D: one one at a time: digit parts numerically, alphabetical in ASCII
D: order.

diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .31153-2.6.0-test4-bk9-module_version.pre/include/linux/module.h .31153-2.6.0-test4-bk9-module_version/include/linux/module.h
--- .31153-2.6.0-test4-bk9-module_version.pre/include/linux/module.h 2003-07-31 01:50:19.000000000 +1000
+++ .31153-2.6.0-test4-bk9-module_version/include/linux/module.h 2003-09-08 21:47:12.000000000 +1000
@@ -123,6 +123,23 @@ extern const struct gtype##_id __mod_##g
#define MODULE_DEVICE_TABLE(type,name) \
MODULE_GENERIC_TABLE(type##_device,name)

+/* Version of form [<epoch>:]<version>[-<extra-version>].
+ <epoch>: A (small) unsigned integer which allows you to start versions
+ anew. If not mentioned, it's zero. eg. "2:1.0" is after
+ "1:2.0".
+ <version>: The <version> may contain only alphanumerics and the
+ character `.'. Ordered by numeric sort for numeric parts,
+ ascii sort for ascii parts (as per RPM or DEB algorithm).
+ <extraversion>: Like <version>, but inserted for local
+ customizations, eg "rh3" or "rusty1".
+
+ Using this automatically adds a checksum of the .c files and the
+ local headers to the end. Use MODULE_VERSION("") if you want just
+ this. Macro includes room for this.
+*/
+#define MODULE_VERSION(_version) \
+ MODULE_INFO(version, _version "\0xxxxxxxxxxxxxxxxxxxxxxxx")
+
/* Given an address, look for it in the exception tables */
const struct exception_table_entry *search_exception_tables(unsigned long add);

diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .31153-2.6.0-test4-bk9-module_version.pre/scripts/Makefile .31153-2.6.0-test4-bk9-module_version/scripts/Makefile
--- .31153-2.6.0-test4-bk9-module_version.pre/scripts/Makefile 2003-03-25 12:17:36.000000000 +1100
+++ .31153-2.6.0-test4-bk9-module_version/scripts/Makefile 2003-09-08 21:47:12.000000000 +1000
@@ -12,7 +12,7 @@ host-progs := fixdep split-include conma
mk_elfconfig pnmtologo
always := $(host-progs) empty.o

-modpost-objs := modpost.o file2alias.o
+modpost-objs := modpost.o file2alias.o sumversion.o

subdir-$(CONFIG_MODVERSIONS) += genksyms

diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .31153-2.6.0-test4-bk9-module_version.pre/scripts/Makefile.build .31153-2.6.0-test4-bk9-module_version/scripts/Makefile.build
--- .31153-2.6.0-test4-bk9-module_version.pre/scripts/Makefile.build 2003-08-25 11:58:37.000000000 +1000
+++ .31153-2.6.0-test4-bk9-module_version/scripts/Makefile.build 2003-09-08 21:47:12.000000000 +1000
@@ -54,8 +54,6 @@ endif

# We keep a list of all modules in $(MODVERDIR)

-touch-module = @echo $(@:.o=.ko) > $(MODVERDIR)/$(@F:.o=.mod)
-
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
$(if $(KBUILD_MODULES),$(obj-m)) \
$(subdir-ym) $(always)
@@ -168,7 +166,7 @@ endef

$(single-used-m): %.o: %.c FORCE
$(call if_changed_rule,cc_o_c)
- $(touch-module)
+ @{ echo $(@:.o=.ko); echo $<; } > $(MODVERDIR)/$(@F:.o=.mod)

quiet_cmd_cc_lst_c = MKLST $@
cmd_cc_lst_c = $(CC) $(c_flags) -g -c -o $*.o $< && \
@@ -263,7 +261,7 @@ $(multi-used-y) : %.o: $(multi-objs-y) F

$(multi-used-m) : %.o: $(multi-objs-m) FORCE
$(call if_changed,link_multi-m)
- $(touch-module)
+ @{ echo $(@:.o=.ko); echo $(link_multi_deps:.o=.c); } > $(MODVERDIR)/$(@F:.o=.mod)

targets += $(multi-used-y) $(multi-used-m)

diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .31153-2.6.0-test4-bk9-module_version.pre/scripts/Makefile.modpost .31153-2.6.0-test4-bk9-module_version/scripts/Makefile.modpost
--- .31153-2.6.0-test4-bk9-module_version.pre/scripts/Makefile.modpost 2003-04-08 11:15:14.000000000 +1000
+++ .31153-2.6.0-test4-bk9-module_version/scripts/Makefile.modpost 2003-09-08 21:47:12.000000000 +1000
@@ -10,10 +10,11 @@ include scripts/Makefile.lib

#

-__modules := $(shell cat /dev/null $(wildcard $(MODVERDIR)/*.mod))
+__modules := $(shell head -q -n1 /dev/null $(wildcard $(MODVERDIR)/*.mod))
modules := $(patsubst %.o,%.ko,$(wildcard $(__modules:.ko=.o)))

ifneq ($(filter-out $(modules),$(__modules)),)
+ $(warning Trouble: $(__modules) )
$(warning *** Uh-oh, you have stale module entries. You messed with SUBDIRS,)
$(warning do not complain if something goes wrong.)
endif
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .31153-2.6.0-test4-bk9-module_version.pre/scripts/modpost.c .31153-2.6.0-test4-bk9-module_version/scripts/modpost.c
--- .31153-2.6.0-test4-bk9-module_version.pre/scripts/modpost.c 2003-08-12 06:58:08.000000000 +1000
+++ .31153-2.6.0-test4-bk9-module_version/scripts/modpost.c 2003-09-08 21:47:12.000000000 +1000
@@ -65,15 +65,15 @@ new_module(char *modname)
struct module *mod;
char *p;

+ mod = NOFAIL(malloc(sizeof(*mod)));
+ memset(mod, 0, sizeof(*mod));
+ mod->name = NOFAIL(strdup(modname));
+
/* strip trailing .o */
- p = strstr(modname, ".o");
+ p = strstr(mod->name, ".o");
if (p)
*p = 0;

- mod = NOFAIL(malloc(sizeof(*mod)));
- memset(mod, 0, sizeof(*mod));
- mod->name = modname;
-
/* add to list */
mod->next = modules;
modules = mod;
@@ -182,26 +182,28 @@ grab_file(const char *filename, unsigned
int fd;

fd = open(filename, O_RDONLY);
- if (fd < 0) {
- perror(filename);
- abort();
- }
- if (fstat(fd, &st) != 0) {
- perror(filename);
- abort();
- }
+ if (fd < 0)
+ return NULL;
+
+ if (fstat(fd, &st) != 0)
+ return NULL;

*size = st.st_size;
map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
- if (mmap == MAP_FAILED) {
- perror(filename);
- abort();
- }
+ if (mmap == MAP_FAILED)
+ return NULL;
+
close(fd);
return map;
}

void
+release_file(void *file, unsigned long size)
+{
+ munmap(file, size);
+}
+
+void
parse_elf(struct elf_info *info, const char *filename)
{
unsigned int i;
@@ -210,6 +212,10 @@ parse_elf(struct elf_info *info, const c
Elf_Sym *sym;

hdr = grab_file(filename, &info->size);
+ if (!hdr) {
+ perror(filename);
+ abort();
+ }
info->hdr = hdr;
if (info->size < sizeof(*hdr))
goto truncated;
@@ -227,11 +233,19 @@ parse_elf(struct elf_info *info, const c
sechdrs[i].sh_offset = TO_NATIVE(sechdrs[i].sh_offset);
sechdrs[i].sh_size = TO_NATIVE(sechdrs[i].sh_size);
sechdrs[i].sh_link = TO_NATIVE(sechdrs[i].sh_link);
+ sechdrs[i].sh_name = TO_NATIVE(sechdrs[i].sh_name);
}
/* Find symbol table. */
for (i = 1; i < hdr->e_shnum; i++) {
+ const char *secstrings
+ = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+
if (sechdrs[i].sh_offset > info->size)
goto truncated;
+ if (strcmp(secstrings+sechdrs[i].sh_name, ".modinfo") == 0) {
+ info->modinfo = (void *)hdr + sechdrs[i].sh_offset;
+ info->modinfo_len = sechdrs[i].sh_size;
+ }
if (sechdrs[i].sh_type != SHT_SYMTAB)
continue;

@@ -262,7 +276,7 @@ parse_elf(struct elf_info *info, const c
void
parse_elf_finish(struct elf_info *info)
{
- munmap(info->hdr, info->size);
+ release_file(info->hdr, info->size);
}

#define CRC_PFX MODULE_SYMBOL_PREFIX "__crc_"
@@ -348,6 +362,8 @@ read_symbols(char *modname)
handle_modversions(mod, &info, sym, symname);
handle_moddevtable(mod, &info, sym, symname);
}
+ maybe_frob_version(modname, info.modinfo, info.modinfo_len,
+ (void *)info.modinfo - (void *)info.hdr);
parse_elf_finish(&info);

/* Our trick to get versioning for struct_module - it's
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .31153-2.6.0-test4-bk9-module_version.pre/scripts/modpost.h .31153-2.6.0-test4-bk9-module_version/scripts/modpost.h
--- .31153-2.6.0-test4-bk9-module_version.pre/scripts/modpost.h 2003-04-08 11:15:14.000000000 +1000
+++ .31153-2.6.0-test4-bk9-module_version/scripts/modpost.h 2003-09-08 21:47:12.000000000 +1000
@@ -80,9 +80,19 @@ struct elf_info {
Elf_Sym *symtab_start;
Elf_Sym *symtab_stop;
const char *strtab;
+ char *modinfo;
+ unsigned int modinfo_len;
};

void handle_moddevtable(struct module *mod, struct elf_info *info,
Elf_Sym *sym, const char *symname);

void add_moddevtable(struct buffer *buf, struct module *mod);
+
+void maybe_frob_version(const char *modfilename,
+ void *modinfo,
+ unsigned long modinfo_len,
+ unsigned long modinfo_offset);
+
+void *grab_file(const char *filename, unsigned long *size);
+void release_file(void *file, unsigned long size);
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .31153-2.6.0-test4-bk9-module_version.pre/scripts/sumversion.c .31153-2.6.0-test4-bk9-module_version/scripts/sumversion.c
--- .31153-2.6.0-test4-bk9-module_version.pre/scripts/sumversion.c 1970-01-01 10:00:00.000000000 +1000
+++ .31153-2.6.0-test4-bk9-module_version/scripts/sumversion.c 2003-09-08 21:47:12.000000000 +1000
@@ -0,0 +1,510 @@
+#include <netinet/in.h>
+#include <stdint.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include "modpost.h"
+
+/* Parse tag=value strings from .modinfo section */
+static char *next_string(char *string, unsigned long *secsize)
+{
+ /* Skip non-zero chars */
+ while (string[0]) {
+ string++;
+ if ((*secsize)-- <= 1)
+ return NULL;
+ }
+
+ /* Skip any zero padding. */
+ while (!string[0]) {
+ string++;
+ if ((*secsize)-- <= 1)
+ return NULL;
+ }
+ return string;
+}
+
+static char *get_modinfo(void *modinfo, unsigned long modinfo_len,
+ const char *tag)
+{
+ char *p;
+ unsigned int taglen = strlen(tag);
+ unsigned long size = modinfo_len;
+
+ for (p = modinfo; p; p = next_string(p, &size)) {
+ if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
+ return p + taglen + 1;
+ }
+ return NULL;
+}
+
+/*
+ * Stolen form Cryptographic API.
+ *
+ * MD4 Message Digest Algorithm (RFC1320).
+ *
+ * Implementation derived from Andrew Tridgell and Steve French's
+ * CIFS MD4 implementation, and the cryptoapi implementation
+ * originally based on the public domain implementation written
+ * by Colin Plumb in 1993.
+ *
+ * Copyright (c) Andrew Tridgell 1997-1998.
+ * Modified by Steve French (sfrench@xxxxxxxxxx) 2002
+ * Copyright (c) Cryptoapi developers.
+ * Copyright (c) 2002 David S. Miller (davem@xxxxxxxxxx)
+ * Copyright (c) 2002 James Morris <jmorris@xxxxxxxxxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+#define MD4_DIGEST_SIZE 16
+#define MD4_HMAC_BLOCK_SIZE 64
+#define MD4_BLOCK_WORDS 16
+#define MD4_HASH_WORDS 4
+
+struct md4_ctx {
+ uint32_t hash[MD4_HASH_WORDS];
+ uint32_t block[MD4_BLOCK_WORDS];
+ uint64_t byte_count;
+};
+
+static inline uint32_t lshift(uint32_t x, unsigned int s)
+{
+ x &= 0xFFFFFFFF;
+ return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s));
+}
+
+static inline uint32_t F(uint32_t x, uint32_t y, uint32_t z)
+{
+ return (x & y) | ((~x) & z);
+}
+
+static inline uint32_t G(uint32_t x, uint32_t y, uint32_t z)
+{
+ return (x & y) | (x & z) | (y & z);
+}
+
+static inline uint32_t H(uint32_t x, uint32_t y, uint32_t z)
+{
+ return x ^ y ^ z;
+}
+
+#define ROUND1(a,b,c,d,k,s) (a = lshift(a + F(b,c,d) + k, s))
+#define ROUND2(a,b,c,d,k,s) (a = lshift(a + G(b,c,d) + k + (uint32_t)0x5A827999,s))
+#define ROUND3(a,b,c,d,k,s) (a = lshift(a + H(b,c,d) + k + (uint32_t)0x6ED9EBA1,s))
+
+/* XXX: this stuff can be optimized */
+static inline void le32_to_cpu_array(uint32_t *buf, unsigned int words)
+{
+ while (words--) {
+ *buf = ntohl(*buf);
+ buf++;
+ }
+}
+
+static inline void cpu_to_le32_array(uint32_t *buf, unsigned int words)
+{
+ while (words--) {
+ *buf = htonl(*buf);
+ buf++;
+ }
+}
+
+static void md4_transform(uint32_t *hash, uint32_t const *in)
+{
+ uint32_t a, b, c, d;
+
+ a = hash[0];
+ b = hash[1];
+ c = hash[2];
+ d = hash[3];
+
+ ROUND1(a, b, c, d, in[0], 3);
+ ROUND1(d, a, b, c, in[1], 7);
+ ROUND1(c, d, a, b, in[2], 11);
+ ROUND1(b, c, d, a, in[3], 19);
+ ROUND1(a, b, c, d, in[4], 3);
+ ROUND1(d, a, b, c, in[5], 7);
+ ROUND1(c, d, a, b, in[6], 11);
+ ROUND1(b, c, d, a, in[7], 19);
+ ROUND1(a, b, c, d, in[8], 3);
+ ROUND1(d, a, b, c, in[9], 7);
+ ROUND1(c, d, a, b, in[10], 11);
+ ROUND1(b, c, d, a, in[11], 19);
+ ROUND1(a, b, c, d, in[12], 3);
+ ROUND1(d, a, b, c, in[13], 7);
+ ROUND1(c, d, a, b, in[14], 11);
+ ROUND1(b, c, d, a, in[15], 19);
+
+ ROUND2(a, b, c, d,in[ 0], 3);
+ ROUND2(d, a, b, c, in[4], 5);
+ ROUND2(c, d, a, b, in[8], 9);
+ ROUND2(b, c, d, a, in[12], 13);
+ ROUND2(a, b, c, d, in[1], 3);
+ ROUND2(d, a, b, c, in[5], 5);
+ ROUND2(c, d, a, b, in[9], 9);
+ ROUND2(b, c, d, a, in[13], 13);
+ ROUND2(a, b, c, d, in[2], 3);
+ ROUND2(d, a, b, c, in[6], 5);
+ ROUND2(c, d, a, b, in[10], 9);
+ ROUND2(b, c, d, a, in[14], 13);
+ ROUND2(a, b, c, d, in[3], 3);
+ ROUND2(d, a, b, c, in[7], 5);
+ ROUND2(c, d, a, b, in[11], 9);
+ ROUND2(b, c, d, a, in[15], 13);
+
+ ROUND3(a, b, c, d,in[ 0], 3);
+ ROUND3(d, a, b, c, in[8], 9);
+ ROUND3(c, d, a, b, in[4], 11);
+ ROUND3(b, c, d, a, in[12], 15);
+ ROUND3(a, b, c, d, in[2], 3);
+ ROUND3(d, a, b, c, in[10], 9);
+ ROUND3(c, d, a, b, in[6], 11);
+ ROUND3(b, c, d, a, in[14], 15);
+ ROUND3(a, b, c, d, in[1], 3);
+ ROUND3(d, a, b, c, in[9], 9);
+ ROUND3(c, d, a, b, in[5], 11);
+ ROUND3(b, c, d, a, in[13], 15);
+ ROUND3(a, b, c, d, in[3], 3);
+ ROUND3(d, a, b, c, in[11], 9);
+ ROUND3(c, d, a, b, in[7], 11);
+ ROUND3(b, c, d, a, in[15], 15);
+
+ hash[0] += a;
+ hash[1] += b;
+ hash[2] += c;
+ hash[3] += d;
+}
+
+static inline void md4_transform_helper(struct md4_ctx *ctx)
+{
+ le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(uint32_t));
+ md4_transform(ctx->hash, ctx->block);
+}
+
+static void md4_init(struct md4_ctx *mctx)
+{
+ mctx->hash[0] = 0x67452301;
+ mctx->hash[1] = 0xefcdab89;
+ mctx->hash[2] = 0x98badcfe;
+ mctx->hash[3] = 0x10325476;
+ mctx->byte_count = 0;
+}
+
+static void md4_update(struct md4_ctx *mctx,
+ const unsigned char *data, unsigned int len)
+{
+ const uint32_t avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
+
+ mctx->byte_count += len;
+
+ if (avail > len) {
+ memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
+ data, len);
+ return;
+ }
+
+ memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
+ data, avail);
+
+ md4_transform_helper(mctx);
+ data += avail;
+ len -= avail;
+
+ while (len >= sizeof(mctx->block)) {
+ memcpy(mctx->block, data, sizeof(mctx->block));
+ md4_transform_helper(mctx);
+ data += sizeof(mctx->block);
+ len -= sizeof(mctx->block);
+ }
+
+ memcpy(mctx->block, data, len);
+}
+
+static void md4_final_ascii(struct md4_ctx *mctx, char *out, unsigned int len)
+{
+ const unsigned int offset = mctx->byte_count & 0x3f;
+ char *p = (char *)mctx->block + offset;
+ int padding = 56 - (offset + 1);
+
+ *p++ = 0x80;
+ if (padding < 0) {
+ memset(p, 0x00, padding + sizeof (uint64_t));
+ md4_transform_helper(mctx);
+ p = (char *)mctx->block;
+ padding = 56;
+ }
+
+ memset(p, 0, padding);
+ mctx->block[14] = mctx->byte_count << 3;
+ mctx->block[15] = mctx->byte_count >> 29;
+ le32_to_cpu_array(mctx->block, (sizeof(mctx->block) -
+ sizeof(uint64_t)) / sizeof(uint32_t));
+ md4_transform(mctx->hash, mctx->block);
+ cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(uint32_t));
+
+ snprintf(out, len, "%08X%08X%08X%08X",
+ mctx->hash[0], mctx->hash[1], mctx->hash[2], mctx->hash[3]);
+}
+
+static int parse_file(const char *fname, struct md4_ctx *md);
+
+/* Local include files, if in current dir. */
+static void include_file(const char *line, int maxlen, const char *base,
+ struct md4_ctx *md)
+{
+ unsigned int i;
+
+ for (i = 0; line[i] != '"'; i++) {
+ if (i == maxlen) {
+ fprintf(stderr,
+ "sumversion: badly formed #include in %s\n",
+ base);
+ return;
+ }
+ }
+
+ {
+ const char *dirend;
+ char fname[i + strlen(base)];
+
+ dirend = strrchr(base, '/');
+ if (!dirend)
+ dirend = base;
+ else
+ dirend++;
+ memcpy(fname, base, dirend - base);
+ memcpy(fname + (dirend - base), line, i);
+ fname[(dirend - base) + i] = '\0';
+
+ parse_file(fname, md);
+ }
+}
+
+static inline void add_char(unsigned char c, struct md4_ctx *md)
+{
+ md4_update(md, &c, 1);
+}
+
+static int parse_string(const char *file, unsigned long len,
+ struct md4_ctx *md)
+{
+ unsigned long i;
+
+ add_char(file[0], md);
+ for (i = 1; i < len; i++) {
+ add_char(file[i], md);
+ if (file[i] == '"' && file[i-1] != '\\')
+ break;
+ }
+ return i;
+}
+
+static int parse_comment(const char *file, unsigned long len)
+{
+ unsigned long i;
+
+ for (i = 2; i < len; i++) {
+ if (file[i-1] == '*' && file[i] == '/')
+ break;
+ }
+ return i;
+}
+
+static int skip_whitespace(const char *file, unsigned long len)
+{
+ unsigned long i;
+
+ for (i = 0; i < len; i++) {
+ if (file[i] != ' ' && file[i] != '\t')
+ break;
+ }
+ return i;
+}
+
+#define strneq(str, literal) (strncmp((str), (literal), strlen(literal)) == 0)
+
+/* Just in case it does a (local) include. */
+static int parse_cpp_line(const char *file, unsigned long len,
+ const char *base, struct md4_ctx *md)
+{
+ unsigned long i = 0;
+
+ add_char(file[i++], md);
+ i += skip_whitespace(file+i, len - i);
+ if (i + strlen("include") >= len)
+ return i;
+ if (!strneq(file + i, "include"))
+ return i;
+ md4_update(md, (unsigned char *)"include", strlen("include"));
+ i += strlen("include");
+ i += skip_whitespace(file+i, len - i);
+ if (i >= len)
+ return i;
+ if (file[i] != '"')
+ return i-1;
+ include_file(file+i+1, len - i - 1, base, md);
+ return i-1;
+}
+
+static int parse_file(const char *fname, struct md4_ctx *md)
+{
+ char *file;
+ unsigned long i, len;
+ int start_of_line = 1;
+
+ file = grab_file(fname, &len);
+ if (!file)
+ return 0;
+
+ for (i = 0; i < len; i++) {
+ /* Collapse and ignore \ and CR. */
+ if (file[i] == '\\' && (i+1 < len) && file[i+1] == '\n') {
+ i += 2;
+ continue;
+ }
+
+ if (file[i] == '\n')
+ start_of_line = 1;
+
+ /* Ignore whitespace */
+ if (isspace(file[i]))
+ continue;
+
+ /* Handle strings as whole units */
+ if (file[i] == '"') {
+ i += parse_string(file+i, len - i, md);
+ start_of_line = 0;
+ continue;
+ }
+
+ /* Comments: ignore */
+ if (file[i] == '/' && file[i+1] == '*') {
+ i += parse_comment(file+i, len - i);
+ start_of_line = 0;
+ continue;
+ }
+
+ /* Potential #include files */
+ if (file[i] == '#' && start_of_line) {
+ i += parse_cpp_line(file+i, len - i, fname, md);
+ start_of_line = 0;
+ continue;
+ }
+
+ start_of_line = 0;
+ add_char(file[i], md);
+ }
+ return 1;
+}
+
+static void get_version(const char *modname, char sum[])
+{
+ void *file;
+ unsigned long len;
+ struct md4_ctx md;
+ char *sources, *end, *fname;
+ const char *basename;
+ char filelist[sizeof(".tmp_versions/%s.mod") + strlen(modname)];
+
+ /* Source files for module are in .tmp_versions/modname.mod,
+ after the first line. */
+ if (strrchr(modname, '/'))
+ basename = strrchr(modname, '/') + 1;
+ else
+ basename = modname;
+ sprintf(filelist, ".tmp_versions/%s", basename);
+ /* Truncate .o, add .mod */
+ strcpy(filelist + strlen(filelist)-2, ".mod");
+
+ file = grab_file(filelist, &len);
+ if (!file) {
+ fprintf(stderr, "Warning: could not find versions for %s\n",
+ filelist);
+ return;
+ }
+
+ sources = strchr(file, '\n');
+ if (!sources) {
+ fprintf(stderr, "Warning: malformed versions file for %s\n",
+ modname);
+ goto release;
+ }
+
+ sources++;
+ end = strchr(sources, '\n');
+ if (!end) {
+ fprintf(stderr, "Warning: bad ending versions file for %s\n",
+ modname);
+ goto release;
+ }
+ *end = '\0';
+
+ md4_init(&md);
+ for (fname = strtok(sources, " "); fname; fname = strtok(NULL, " "))
+ if (!parse_file(fname, &md)) {
+ fprintf(stderr, "Warning: could not open %s: %s\n",
+ fname, strerror(errno));
+ goto release;
+ }
+
+ /* sum is of form \0<padding>. */
+ md4_final_ascii(&md, sum, 1 + strlen(sum+1));
+release:
+ release_file(file, len);
+}
+
+static void write_version(const char *filename, const char *sum,
+ unsigned long offset)
+{
+ int fd;
+
+ fd = open(filename, O_RDWR);
+ if (fd < 0) {
+ fprintf(stderr, "Warning: changing sum in %s failed: %s\n",
+ filename, strerror(errno));
+ return;
+ }
+
+ if (lseek(fd, offset, SEEK_SET) == (off_t)-1) {
+ fprintf(stderr, "Warning: changing sum in %s:%lu failed: %s\n",
+ filename, offset, strerror(errno));
+ goto out;
+ }
+
+ if (write(fd, sum, strlen(sum)) != strlen(sum)) {
+ fprintf(stderr, "Warning: writing sum in %s failed: %s\n",
+ filename, strerror(errno));
+ goto out;
+ }
+out:
+ close(fd);
+}
+
+/* If the modinfo contains a "version" value, then set this. */
+void maybe_frob_version(const char *modfilename,
+ void *modinfo,
+ unsigned long modinfo_len,
+ unsigned long modinfo_offset)
+{
+ char *version;
+
+ version = get_modinfo(modinfo, modinfo_len, "version");
+ if (!version)
+ return;
+
+ /* Check against double sumversion */
+ if (strchr(version, ' '))
+ return;
+
+ fprintf(stderr, "Version for %s: %s\n", modfilename, version);
+ /* Version contains embedded NUL: second half has space for checksum */
+ version += strlen(version);
+ *version = ' ';
+ get_version(modfilename, version+1);
+ write_version(modfilename, version,
+ modinfo_offset + (version - (char *)modinfo));
+}


--
Anyone who quotes me in their sig is an idiot. -- Rusty Russell.
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/