From: Sam Ravnborg <sam@ravnborg.org>

modpost or to be more specific sumversion.c was not behaving correct when
used with O= and MODULE_VERSION was used.  Previously it failed to use
local .h when calculation the md-sum in case of a O= build.

The following patch introduces the following:

- A generic get_next_line()

- Check that the topmost part of the directory matches

- Using strrch when checking for file with suffix .o

- Use NOFAIL for allocations in sumversion

- Avoid memory leak in new_module

The generic get_next_line will pay off when Andreas implmentation of
storing symbol addresses in a seperate file is introduced.


---

 25-akpm/scripts/modpost.c    |   51 ++++++++++++++++++++++++-----
 25-akpm/scripts/modpost.h    |    4 ++
 25-akpm/scripts/sumversion.c |   74 +++++++++++++++++++------------------------
 3 files changed, 80 insertions(+), 49 deletions(-)

diff -puN scripts/modpost.c~kbuild-modpost-fix scripts/modpost.c
--- 25/scripts/modpost.c~kbuild-modpost-fix	Fri Mar 12 14:23:29 2004
+++ 25-akpm/scripts/modpost.c	Fri Mar 12 14:23:29 2004
@@ -11,6 +11,7 @@
  * Usage: modpost vmlinux module1.o module2.o ...
  */
 
+#include <ctype.h>
 #include "modpost.h"
 
 /* Are we using CONFIG_MODVERSIONS? */
@@ -44,8 +45,6 @@ warn(const char *fmt, ...)
 	va_end(arglist);
 }
 
-#define NOFAIL(ptr)	do_nofail((ptr), __FILE__, __LINE__, #ptr)
-
 void *do_nofail(void *ptr, const char *file, int line, const char *expr)
 {
 	if (!ptr) {
@@ -63,21 +62,19 @@ struct module *
 new_module(char *modname)
 {
 	struct module *mod;
-	char *p;
-	size_t len;
+	char *p, *s;
 	
 	mod = NOFAIL(malloc(sizeof(*mod)));
 	memset(mod, 0, sizeof(*mod));
 	p = NOFAIL(strdup(modname));
 
-	len = strlen(p);
-
 	/* strip trailing .o */
-	if (len > 2 && p[len-2] == '.' && p[len-1] == 'o')
-		p[len -2] = '\0';
+	if ((s = strrchr(p, '.')) != NULL)
+		if (strcmp(s, ".o") == 0)
+			*s = '\0';
 
 	/* add to list */
-	mod->name = NOFAIL(strdup(p));
+	mod->name = p;
 	mod->next = modules;
 	modules = mod;
 
@@ -209,6 +206,42 @@ grab_file(const char *filename, unsigned
 	return map;
 }
 
+/*
+   Return a copy of the next line in a mmap'ed file.
+   spaces in the beginning of the line is trimmed away.
+   Return a pointer to a static buffer.
+*/
+char*
+get_next_line(unsigned long *pos, void *file, unsigned long size)
+{
+	static char line[4096];
+	int skip = 1;
+	size_t len = 0;
+	char *p = (char *)file + *pos;
+	char *s = line;
+
+	for (; *pos < size ; (*pos)++)
+	{
+		if (skip && isspace(*p)) {
+			p++;
+			continue;
+		}
+		skip = 0;
+		if (*p != '\n' && (*pos < size)) {
+			len++;
+			*s++ = *p++;
+			if (len > 4095)
+				break; /* Too long, stop */
+		} else {
+			/* End of string */
+			*s = '\0';
+			return line;
+		}
+	}
+	/* End of buffer */
+	return NULL;
+}
+
 void
 release_file(void *file, unsigned long size)
 {
diff -puN scripts/modpost.h~kbuild-modpost-fix scripts/modpost.h
--- 25/scripts/modpost.h~kbuild-modpost-fix	Fri Mar 12 14:23:29 2004
+++ 25-akpm/scripts/modpost.h	Fri Mar 12 14:23:29 2004
@@ -53,6 +53,9 @@ static inline void __endian(const void *
 
 #endif
 
+#define NOFAIL(ptr)   do_nofail((ptr), __FILE__, __LINE__, #ptr)
+void *do_nofail(void *ptr, const char *file, int line, const char *expr);
+
 struct buffer {
 	char *p;
 	int pos;
@@ -95,4 +98,5 @@ void maybe_frob_version(const char *modf
 			unsigned long modinfo_offset);
 
 void *grab_file(const char *filename, unsigned long *size);
+char* get_next_line(unsigned long *pos, void *file, unsigned long size);
 void release_file(void *file, unsigned long size);
diff -puN scripts/sumversion.c~kbuild-modpost-fix scripts/sumversion.c
--- 25/scripts/sumversion.c~kbuild-modpost-fix	Fri Mar 12 14:23:29 2004
+++ 25-akpm/scripts/sumversion.c	Fri Mar 12 14:23:29 2004
@@ -323,12 +323,12 @@ static int parse_file(const char *fname,
  * figure out source file. */
 static int parse_source_files(const char *objfile, struct md4_ctx *md)
 {
-	char *cmd, *file, *p, *end;
+	char *cmd, *file, *line, *dir;
 	const char *base;
-	unsigned long flen;
-	int dirlen, ret = 0;
+	unsigned long flen, pos = 0;
+	int dirlen, ret = 0, check_files = 0;
 
-	cmd = malloc(strlen(objfile) + sizeof("..cmd"));
+	cmd = NOFAIL(malloc(strlen(objfile) + sizeof("..cmd")));
 
 	base = strrchr(objfile, '/');
 	if (base) {
@@ -339,6 +339,9 @@ static int parse_source_files(const char
 		dirlen = 0;
 		sprintf(cmd, ".%s.cmd", objfile);
 	}
+	dir = NOFAIL(malloc(dirlen + 1));
+	strncpy(dir, objfile, dirlen);
+	dir[dirlen] = '\0';
 
 	file = grab_file(cmd, &flen);
 	if (!file) {
@@ -357,48 +360,38 @@ static int parse_source_files(const char
 
 	   Sum all files in the same dir or subdirs.
 	*/
-	/* Strictly illegal: file is not nul terminated. */
-	p = strstr(file, "\ndeps_");
-	if (!p) {
-		fprintf(stderr, "Warning: could not find deps_ line in %s\n",
-			cmd);
-		goto out_file;
-	}
-	p = strstr(p, ":=");
-	if (!p) {
-		fprintf(stderr, "Warning: could not find := line in %s\n",
-			cmd);
-		goto out_file;
-	}
-	p += strlen(":=");
-	p += strspn(p, " \\\n");
-
-	end = strstr(p, "\n\n");
-	if (!end) {
-		fprintf(stderr, "Warning: could not find end line in %s\n",
-			cmd);
-		goto out_file;
-	}
-
-	while (p < end) {
-		unsigned int len;
+	while ((line = get_next_line(&pos, file, flen)) != NULL) {
+		char* p = line;
+		if (strncmp(line, "deps_", sizeof("deps_")-1) == 0) {
+			check_files = 1;
+			continue;
+		}
+		if (!check_files)
+			continue;
+
+		/* Continue until line does not end with '\' */
+		if ( *(p + strlen(p)-1) != '\\')
+			break;
+		/* Terminate line at first space, to get rid of final ' \' */
+		while (*p) {
+			if isspace(*p) {
+				*p = '\0';
+				break;
+			}
+			p++;
+		}
 
-		len = strcspn(p, " \\\n");
-		if (memcmp(objfile, p, dirlen) == 0) {
-			char source[len + 1];
-
-			memcpy(source, p, len);
-			source[len] = '\0';
-			printf("parsing %s\n", source);
-			if (!parse_file(source, md)) {
+		/* Check if this file is in same dir as objfile */
+		if ((strstr(line, dir)+strlen(dir)-1) == strrchr(line, '/')) {
+			if (!parse_file(line, md)) {
 				fprintf(stderr,
 					"Warning: could not open %s: %s\n",
-					source, strerror(errno));
+					line, strerror(errno));
 				goto out_file;
 			}
+
 		}
-		p += len;
-		p += strspn(p, " \\\n");
+
 	}
 
 	/* Everyone parsed OK */
@@ -406,6 +399,7 @@ static int parse_source_files(const char
 out_file:
 	release_file(file, flen);
 out:
+	free(dir);
 	free(cmd);
 	return ret;
 }

_