Merge tag 'kbuild-v5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild

Pull Kbuild updates from Masahiro Yamada:

 - fix warnings in 'make clean' for ARCH=um, hexagon, h8300, unicore32

 - ensure to rebuild all objects when the compiler is upgraded

 - exclude system headers from dependency tracking and fixdep processing

 - fix potential bit-size mismatch between the kernel and BPF user-mode
   helper

 - add the new syntax 'userprogs' to build user-space programs for the
   target architecture (the same arch as the kernel)

 - compile user-space sample code under samples/ for the target arch
   instead of the host arch

 - make headers_install fail if a CONFIG option is leaked to user-space

 - sanitize the output format of scripts/checkstack.pl

 - handle ARM 'push' instruction in scripts/checkstack.pl

 - error out before modpost if a module name conflict is found

 - error out when multiple directories are passed to M= because this
   feature is broken for a long time

 - add CONFIG_DEBUG_INFO_COMPRESSED to support compressed debug info

 - a lot of cleanups of modpost

 - dump vmlinux symbols out into vmlinux.symvers, and reuse it in the
   second pass of modpost

 - do not run the second pass of modpost if nothing in modules is
   updated

 - install modules.builtin(.modinfo) by 'make install' as well as by
   'make modules_install' because it is useful even when
   CONFIG_MODULES=n

 - add new command line variables, GZIP, BZIP2, LZOP, LZMA, LZ4, and XZ
   to allow users to use alternatives such as pigz, pbzip2, etc.

* tag 'kbuild-v5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild: (96 commits)
  kbuild: add variables for compression tools
  Makefile: install modules.builtin even if CONFIG_MODULES=n
  mksysmap: Fix the mismatch of '.L' symbols in System.map
  kbuild: doc: rename LDFLAGS to KBUILD_LDFLAGS
  modpost: change elf_info->size to size_t
  modpost: remove is_vmlinux() helper
  modpost: strip .o from modname before calling new_module()
  modpost: set have_vmlinux in new_module()
  modpost: remove mod->skip struct member
  modpost: add mod->is_vmlinux struct member
  modpost: remove is_vmlinux() call in check_for_{gpl_usage,unused}()
  modpost: remove mod->is_dot_o struct member
  modpost: move -d option in scripts/Makefile.modpost
  modpost: remove -s option
  modpost: remove get_next_text() and make {grab,release_}file static
  modpost: use read_text_file() and get_line() for reading text files
  modpost: avoid false-positive file open error
  modpost: fix potential mmap'ed file overrun in get_src_version()
  modpost: add read_text_file() and get_line() helpers
  modpost: do not call get_modinfo() for vmlinux(.o)
  ...
This commit is contained in:
Linus Torvalds
2020-06-06 12:00:25 -07:00
60 changed files with 883 additions and 757 deletions
+184 -200
View File
@@ -30,8 +30,6 @@ static int have_vmlinux = 0;
static int all_versions = 0;
/* If we are modposting external module set to 1 */
static int external_module = 0;
/* Warn about section mismatch in vmlinux if set to 1 */
static int vmlinux_section_warnings = 1;
/* Only warn about unresolved symbols */
static int warn_unresolved = 0;
/* How a symbol is exported */
@@ -90,20 +88,6 @@ static inline bool strends(const char *str, const char *postfix)
return strcmp(str + strlen(str) - strlen(postfix), postfix) == 0;
}
static int is_vmlinux(const char *modname)
{
const char *myname;
myname = strrchr(modname, '/');
if (myname)
myname++;
else
myname = modname;
return (strcmp(myname, "vmlinux") == 0) ||
(strcmp(myname, "vmlinux.o") == 0);
}
void *do_nofail(void *ptr, const char *expr)
{
if (!ptr)
@@ -112,6 +96,55 @@ void *do_nofail(void *ptr, const char *expr)
return ptr;
}
char *read_text_file(const char *filename)
{
struct stat st;
size_t nbytes;
int fd;
char *buf;
fd = open(filename, O_RDONLY);
if (fd < 0) {
perror(filename);
exit(1);
}
if (fstat(fd, &st) < 0) {
perror(filename);
exit(1);
}
buf = NOFAIL(malloc(st.st_size + 1));
nbytes = st.st_size;
while (nbytes) {
ssize_t bytes_read;
bytes_read = read(fd, buf, nbytes);
if (bytes_read < 0) {
perror(filename);
exit(1);
}
nbytes -= bytes_read;
}
buf[st.st_size] = '\0';
close(fd);
return buf;
}
char *get_line(char **stringp)
{
/* do not return the unwanted extra line at EOF */
if (*stringp && **stringp == '\0')
return NULL;
return strsep(stringp, "\n");
}
/* A list of all modules we processed */
static struct module *modules;
@@ -128,24 +161,20 @@ static struct module *find_module(const char *modname)
static struct module *new_module(const char *modname)
{
struct module *mod;
char *p;
mod = NOFAIL(malloc(sizeof(*mod)));
mod = NOFAIL(malloc(sizeof(*mod) + strlen(modname) + 1));
memset(mod, 0, sizeof(*mod));
p = NOFAIL(strdup(modname));
/* strip trailing .o */
if (strends(p, ".o")) {
p[strlen(p) - 2] = '\0';
mod->is_dot_o = 1;
}
/* add to list */
mod->name = p;
strcpy(mod->name, modname);
mod->is_vmlinux = (strcmp(modname, "vmlinux") == 0);
mod->gpl_compatible = -1;
mod->next = modules;
modules = mod;
if (mod->is_vmlinux)
have_vmlinux = 1;
return mod;
}
@@ -161,12 +190,9 @@ struct symbol {
int crc_valid;
char *namespace;
unsigned int weak:1;
unsigned int vmlinux:1; /* 1 if symbol is defined in vmlinux */
unsigned int kernel:1; /* 1 if symbol is from kernel
* (only for external modules) **/
unsigned int is_static:1; /* 1 if symbol is not global */
enum export export; /* Type of export */
char name[0];
char name[];
};
static struct symbol *symbolhash[SYMBOL_HASH_SIZE];
@@ -288,31 +314,34 @@ static enum export export_no(const char *s)
return export_unknown;
}
static const char *sech_name(struct elf_info *elf, Elf_Shdr *sechdr)
static void *sym_get_data_by_offset(const struct elf_info *info,
unsigned int secindex, unsigned long offset)
{
return (void *)elf->hdr +
elf->sechdrs[elf->secindex_strings].sh_offset +
sechdr->sh_name;
}
static const char *sec_name(struct elf_info *elf, int secindex)
{
return sech_name(elf, &elf->sechdrs[secindex]);
}
static void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym)
{
unsigned int secindex = get_secindex(info, sym);
Elf_Shdr *sechdr = &info->sechdrs[secindex];
unsigned long offset;
offset = sym->st_value;
if (info->hdr->e_type != ET_REL)
offset -= sechdr->sh_addr;
return (void *)info->hdr + sechdr->sh_offset + offset;
}
static void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym)
{
return sym_get_data_by_offset(info, get_secindex(info, sym),
sym->st_value);
}
static const char *sech_name(const struct elf_info *info, Elf_Shdr *sechdr)
{
return sym_get_data_by_offset(info, info->secindex_strings,
sechdr->sh_name);
}
static const char *sec_name(const struct elf_info *info, int secindex)
{
return sech_name(info, &info->sechdrs[secindex]);
}
#define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0)
static enum export export_from_secname(struct elf_info *elf, unsigned int sec)
@@ -386,17 +415,15 @@ static struct symbol *sym_add_exported(const char *name, struct module *mod,
if (!s) {
s = new_symbol(name, mod, export);
} else if (!external_module || is_vmlinux(s->module->name) ||
} else if (!external_module || s->module->is_vmlinux ||
s->module == mod) {
warn("%s: '%s' exported twice. Previous export was in %s%s\n",
mod->name, name, s->module->name,
is_vmlinux(s->module->name) ? "" : ".ko");
s->module->is_vmlinux ? "" : ".ko");
return s;
}
s->module = mod;
s->vmlinux = is_vmlinux(mod->name);
s->kernel = 0;
s->export = export;
return s;
}
@@ -416,7 +443,7 @@ static void sym_set_crc(const char *name, unsigned int crc)
s->crc_valid = 1;
}
void *grab_file(const char *filename, unsigned long *size)
static void *grab_file(const char *filename, size_t *size)
{
struct stat st;
void *map = MAP_FAILED;
@@ -438,41 +465,7 @@ failed:
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;
signed char *p = (signed 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)
static void release_file(void *file, size_t size)
{
munmap(file, size);
}
@@ -528,9 +521,8 @@ static int parse_elf(struct elf_info *info, const char *filename)
/* Check if file offset is correct */
if (hdr->e_shoff > info->size) {
fatal("section header offset=%lu in file '%s' is bigger than "
"filesize=%lu\n", (unsigned long)hdr->e_shoff,
filename, info->size);
fatal("section header offset=%lu in file '%s' is bigger than filesize=%zu\n",
(unsigned long)hdr->e_shoff, filename, info->size);
return 0;
}
@@ -683,7 +675,7 @@ static void handle_modversion(const struct module *mod,
if (sym->st_shndx == SHN_UNDEF) {
warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n",
symname, mod->name, is_vmlinux(mod->name) ? "":".ko");
symname, mod->name, mod->is_vmlinux ? "" : ".ko");
return;
}
@@ -705,8 +697,7 @@ static void handle_symbol(struct module *mod, struct elf_info *info,
enum export export;
const char *name;
if ((!is_vmlinux(mod->name) || mod->is_dot_o) &&
strstarts(symname, "__ksymtab"))
if (strstarts(symname, "__ksymtab"))
export = export_from_secname(info, get_secindex(info, sym));
else
export = export_from_sec(info, get_secindex(info, sym));
@@ -1752,11 +1743,7 @@ static void check_section_mismatch(const char *modname, struct elf_info *elf,
static unsigned int *reloc_location(struct elf_info *elf,
Elf_Shdr *sechdr, Elf_Rela *r)
{
Elf_Shdr *sechdrs = elf->sechdrs;
int section = sechdr->sh_info;
return (void *)elf->hdr + sechdrs[section].sh_offset +
r->r_offset;
return sym_get_data_by_offset(elf, sechdr->sh_info, r->r_offset);
}
static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
@@ -2005,34 +1992,36 @@ static void read_symbols(const char *modname)
if (!parse_elf(&info, modname))
return;
mod = new_module(modname);
{
char *tmp;
/* When there's no vmlinux, don't print warnings about
* unresolved symbols (since there'll be too many ;) */
if (is_vmlinux(modname)) {
have_vmlinux = 1;
mod->skip = 1;
/* strip trailing .o */
tmp = NOFAIL(strdup(modname));
tmp[strlen(tmp) - 2] = '\0';
mod = new_module(tmp);
free(tmp);
}
license = get_modinfo(&info, "license");
if (!license && !is_vmlinux(modname))
warn("missing MODULE_LICENSE() in %s\n"
"see include/linux/module.h for "
"more information\n", modname);
while (license) {
if (license_is_gpl_compatible(license))
mod->gpl_compatible = 1;
else {
mod->gpl_compatible = 0;
break;
if (!mod->is_vmlinux) {
license = get_modinfo(&info, "license");
if (!license)
warn("missing MODULE_LICENSE() in %s\n", modname);
while (license) {
if (license_is_gpl_compatible(license))
mod->gpl_compatible = 1;
else {
mod->gpl_compatible = 0;
break;
}
license = get_next_modinfo(&info, "license", license);
}
license = get_next_modinfo(&info, "license", license);
}
namespace = get_modinfo(&info, "import_ns");
while (namespace) {
add_namespace(&mod->imported_namespaces, namespace);
namespace = get_next_modinfo(&info, "import_ns", namespace);
namespace = get_modinfo(&info, "import_ns");
while (namespace) {
add_namespace(&mod->imported_namespaces, namespace);
namespace = get_next_modinfo(&info, "import_ns",
namespace);
}
}
for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
@@ -2070,16 +2059,14 @@ static void read_symbols(const char *modname)
}
}
if (!is_vmlinux(modname) || vmlinux_section_warnings)
check_sec_ref(mod, modname, &info);
check_sec_ref(mod, modname, &info);
version = get_modinfo(&info, "version");
if (version)
maybe_frob_rcs_version(modname, version, info.modinfo,
version - (char *)info.hdr);
if (version || (all_versions && !is_vmlinux(modname)))
get_src_version(modname, mod->srcversion,
sizeof(mod->srcversion)-1);
if (!mod->is_vmlinux) {
version = get_modinfo(&info, "version");
if (version || all_versions)
get_src_version(modname, mod->srcversion,
sizeof(mod->srcversion) - 1);
}
parse_elf_finish(&info);
@@ -2143,20 +2130,18 @@ void buf_write(struct buffer *buf, const char *s, int len)
static void check_for_gpl_usage(enum export exp, const char *m, const char *s)
{
const char *e = is_vmlinux(m) ?"":".ko";
switch (exp) {
case export_gpl:
fatal("GPL-incompatible module %s%s "
"uses GPL-only symbol '%s'\n", m, e, s);
fatal("GPL-incompatible module %s.ko uses GPL-only symbol '%s'\n",
m, s);
break;
case export_unused_gpl:
fatal("GPL-incompatible module %s%s "
"uses GPL-only symbol marked UNUSED '%s'\n", m, e, s);
fatal("GPL-incompatible module %s.ko uses GPL-only symbol marked UNUSED '%s'\n",
m, s);
break;
case export_gpl_future:
warn("GPL-incompatible module %s%s "
"uses future GPL-only symbol '%s'\n", m, e, s);
warn("GPL-incompatible module %s.ko uses future GPL-only symbol '%s'\n",
m, s);
break;
case export_plain:
case export_unused:
@@ -2168,13 +2153,11 @@ static void check_for_gpl_usage(enum export exp, const char *m, const char *s)
static void check_for_unused(enum export exp, const char *m, const char *s)
{
const char *e = is_vmlinux(m) ?"":".ko";
switch (exp) {
case export_unused:
case export_unused_gpl:
warn("module %s%s "
"uses symbol '%s' marked UNUSED\n", m, e, s);
warn("module %s.ko uses symbol '%s' marked UNUSED\n",
m, s);
break;
default:
/* ignore */
@@ -2349,7 +2332,7 @@ static void add_depends(struct buffer *b, struct module *mod)
/* Clear ->seen flag of modules that own symbols needed by this. */
for (s = mod->unres; s; s = s->next)
if (s->module)
s->module->seen = is_vmlinux(s->module->name);
s->module->seen = s->module->is_vmlinux;
buf_printf(b, "\n");
buf_printf(b, "MODULE_INFO(depends, \"");
@@ -2382,6 +2365,25 @@ static void add_srcversion(struct buffer *b, struct module *mod)
}
}
static void write_buf(struct buffer *b, const char *fname)
{
FILE *file;
file = fopen(fname, "w");
if (!file) {
perror(fname);
exit(1);
}
if (fwrite(b->p, 1, b->pos, file) != b->pos) {
perror(fname);
exit(1);
}
if (fclose(file) != 0) {
perror(fname);
exit(1);
}
}
static void write_if_changed(struct buffer *b, const char *fname)
{
char *tmp;
@@ -2414,32 +2416,24 @@ static void write_if_changed(struct buffer *b, const char *fname)
close_write:
fclose(file);
write:
file = fopen(fname, "w");
if (!file) {
perror(fname);
exit(1);
}
if (fwrite(b->p, 1, b->pos, file) != b->pos) {
perror(fname);
exit(1);
}
fclose(file);
write_buf(b, fname);
}
/* parse Module.symvers file. line format:
* 0x12345678<tab>symbol<tab>module<tab>export<tab>namespace
**/
static void read_dump(const char *fname, unsigned int kernel)
static void read_dump(const char *fname)
{
unsigned long size, pos = 0;
void *file = grab_file(fname, &size);
char *line;
char *buf, *pos, *line;
if (!file)
buf = read_text_file(fname);
if (!buf)
/* No symbol versions, silently ignore */
return;
while ((line = get_next_line(&pos, file, size))) {
pos = buf;
while ((line = get_line(&pos))) {
char *symname, *namespace, *modname, *d, *export;
unsigned int crc;
struct module *mod;
@@ -2463,21 +2457,18 @@ static void read_dump(const char *fname, unsigned int kernel)
goto fail;
mod = find_module(modname);
if (!mod) {
if (is_vmlinux(modname))
have_vmlinux = 1;
mod = new_module(modname);
mod->skip = 1;
mod->from_dump = 1;
}
s = sym_add_exported(symname, mod, export_no(export));
s->kernel = kernel;
s->is_static = 0;
sym_set_crc(symname, crc);
sym_update_namespace(symname, namespace);
}
release_file(file, size);
free(buf);
return;
fail:
release_file(file, size);
free(buf);
fatal("parse error in symbol dump file\n");
}
@@ -2489,7 +2480,7 @@ static int dump_sym(struct symbol *sym)
{
if (!external_module)
return 1;
if (sym->vmlinux || sym->kernel)
if (sym->module->from_dump)
return 0;
return 1;
}
@@ -2515,7 +2506,7 @@ static void write_dump(const char *fname)
symbol = symbol->next;
}
}
write_if_changed(&buf, fname);
write_buf(&buf, fname);
free(buf.p);
}
@@ -2527,7 +2518,7 @@ static void write_namespace_deps_files(const char *fname)
for (mod = modules; mod; mod = mod->next) {
if (mod->skip || !mod->missing_namespaces)
if (mod->from_dump || !mod->missing_namespaces)
continue;
buf_printf(&ns_deps_buf, "%s.ko:", mod->name);
@@ -2542,8 +2533,8 @@ static void write_namespace_deps_files(const char *fname)
free(ns_deps_buf.p);
}
struct ext_sym_list {
struct ext_sym_list *next;
struct dump_list {
struct dump_list *next;
const char *file;
};
@@ -2551,28 +2542,24 @@ int main(int argc, char **argv)
{
struct module *mod;
struct buffer buf = { };
char *kernel_read = NULL;
char *missing_namespace_deps = NULL;
char *dump_write = NULL, *files_source = NULL;
int opt;
int err;
int n;
struct ext_sym_list *extsym_iter;
struct ext_sym_list *extsym_start = NULL;
struct dump_list *dump_read_start = NULL;
struct dump_list **dump_read_iter = &dump_read_start;
while ((opt = getopt(argc, argv, "i:e:mnsT:o:awENd:")) != -1) {
while ((opt = getopt(argc, argv, "ei:mnT:o:awENd:")) != -1) {
switch (opt) {
case 'i':
kernel_read = optarg;
external_module = 1;
break;
case 'e':
external_module = 1;
extsym_iter =
NOFAIL(malloc(sizeof(*extsym_iter)));
extsym_iter->next = extsym_start;
extsym_iter->file = optarg;
extsym_start = extsym_iter;
break;
case 'i':
*dump_read_iter =
NOFAIL(calloc(1, sizeof(**dump_read_iter)));
(*dump_read_iter)->file = optarg;
dump_read_iter = &(*dump_read_iter)->next;
break;
case 'm':
modversions = 1;
@@ -2586,9 +2573,6 @@ int main(int argc, char **argv)
case 'a':
all_versions = 1;
break;
case 's':
vmlinux_section_warnings = 0;
break;
case 'T':
files_source = optarg;
break;
@@ -2609,13 +2593,13 @@ int main(int argc, char **argv)
}
}
if (kernel_read)
read_dump(kernel_read, 1);
while (extsym_start) {
read_dump(extsym_start->file, 0);
extsym_iter = extsym_start->next;
free(extsym_start);
extsym_start = extsym_iter;
while (dump_read_start) {
struct dump_list *tmp;
read_dump(dump_read_start->file);
tmp = dump_read_start->next;
free(dump_read_start);
dump_read_start = tmp;
}
while (optind < argc)
@@ -2624,12 +2608,19 @@ int main(int argc, char **argv)
if (files_source)
read_symbols_from_files(files_source);
/*
* When there's no vmlinux, don't print warnings about
* unresolved symbols (since there'll be too many ;)
*/
if (!have_vmlinux)
warn("Symbol info of vmlinux is missing. Unresolved symbol check will be entirely skipped.\n");
err = 0;
for (mod = modules; mod; mod = mod->next) {
char fname[PATH_MAX];
if (mod->skip)
if (mod->is_vmlinux || mod->from_dump)
continue;
buf.pos = 0;
@@ -2662,13 +2653,6 @@ int main(int argc, char **argv)
struct symbol *s;
for (s = symbolhash[n]; s; s = s->next) {
/*
* Do not check "vmlinux". This avoids the same warnings
* shown twice, and false-positives for ARCH=um.
*/
if (is_vmlinux(s->module->name) && !s->module->is_dot_o)
continue;
if (s->is_static)
warn("\"%s\" [%s] is a static %s\n",
s->name, s->module->name,
+7 -12
View File
@@ -111,29 +111,29 @@ buf_write(struct buffer *buf, const char *s, int len);
struct namespace_list {
struct namespace_list *next;
char namespace[0];
char namespace[];
};
struct module {
struct module *next;
const char *name;
int gpl_compatible;
struct symbol *unres;
int from_dump; /* 1 if module was loaded from *.symvers */
int is_vmlinux;
int seen;
int skip;
int has_init;
int has_cleanup;
struct buffer dev_table_buf;
char srcversion[25];
int is_dot_o;
// Missing namespace dependencies
struct namespace_list *missing_namespaces;
// Actual imported namespaces
struct namespace_list *imported_namespaces;
char name[];
};
struct elf_info {
unsigned long size;
size_t size;
Elf_Ehdr *hdr;
Elf_Shdr *sechdrs;
Elf_Sym *symtab_start;
@@ -187,16 +187,11 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
void add_moddevtable(struct buffer *buf, struct module *mod);
/* sumversion.c */
void maybe_frob_rcs_version(const char *modfilename,
char *version,
void *modinfo,
unsigned long modinfo_offset);
void get_src_version(const char *modname, char sum[], unsigned sumlen);
/* from modpost.c */
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);
char *read_text_file(const char *filename);
char *get_line(char **stringp);
enum loglevel {
LOG_WARN,
+20 -97
View File
@@ -258,9 +258,8 @@ static int parse_file(const char *fname, struct md4_ctx *md)
char *file;
unsigned long i, len;
file = grab_file(fname, &len);
if (!file)
return 0;
file = read_text_file(fname);
len = strlen(file);
for (i = 0; i < len; i++) {
/* Collapse and ignore \ and CR. */
@@ -287,7 +286,7 @@ static int parse_file(const char *fname, struct md4_ctx *md)
add_char(file[i], md);
}
release_file(file, len);
free(file);
return 1;
}
/* Check whether the file is a static library or not */
@@ -304,9 +303,8 @@ static int is_static_library(const char *objfile)
* to figure out source files. */
static int parse_source_files(const char *objfile, struct md4_ctx *md)
{
char *cmd, *file, *line, *dir;
char *cmd, *file, *line, *dir, *pos;
const char *base;
unsigned long flen, pos = 0;
int dirlen, ret = 0, check_files = 0;
cmd = NOFAIL(malloc(strlen(objfile) + sizeof("..cmd")));
@@ -324,14 +322,12 @@ static int parse_source_files(const char *objfile, struct md4_ctx *md)
strncpy(dir, objfile, dirlen);
dir[dirlen] = '\0';
file = grab_file(cmd, &flen);
if (!file) {
warn("could not find %s for %s\n", cmd, objfile);
goto out;
}
file = read_text_file(cmd);
pos = file;
/* Sum all files in the same dir or subdirs. */
while ((line = get_next_line(&pos, file, flen)) != NULL) {
while ((line = get_line(&pos))) {
char* p = line;
if (strncmp(line, "source_", sizeof("source_")-1) == 0) {
@@ -382,8 +378,7 @@ static int parse_source_files(const char *objfile, struct md4_ctx *md)
/* Everyone parsed OK */
ret = 1;
out_file:
release_file(file, flen);
out:
free(file);
free(dir);
free(cmd);
return ret;
@@ -392,106 +387,34 @@ out:
/* Calc and record src checksum. */
void get_src_version(const char *modname, char sum[], unsigned sumlen)
{
void *file;
unsigned long len;
char *buf, *pos, *firstline;
struct md4_ctx md;
char *sources, *end, *fname;
char *fname;
char filelist[PATH_MAX + 1];
/* objects for a module are listed in the first line of *.mod file. */
snprintf(filelist, sizeof(filelist), "%.*smod",
(int)strlen(modname) - 1, modname);
file = grab_file(filelist, &len);
if (!file)
/* not a module or .mod file missing - ignore */
return;
buf = read_text_file(filelist);
sources = file;
end = strchr(sources, '\n');
if (!end) {
pos = buf;
firstline = get_line(&pos);
if (!firstline) {
warn("bad ending versions file for %s\n", modname);
goto release;
goto free;
}
*end = '\0';
md4_init(&md);
while ((fname = strsep(&sources, " ")) != NULL) {
while ((fname = strsep(&firstline, " "))) {
if (!*fname)
continue;
if (!(is_static_library(fname)) &&
!parse_source_files(fname, &md))
goto release;
goto free;
}
md4_final_ascii(&md, sum, sumlen);
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) {
warn("changing sum in %s failed: %s\n",
filename, strerror(errno));
return;
}
if (lseek(fd, offset, SEEK_SET) == (off_t)-1) {
warn("changing sum in %s:%lu failed: %s\n",
filename, offset, strerror(errno));
goto out;
}
if (write(fd, sum, strlen(sum)+1) != strlen(sum)+1) {
warn("writing sum in %s failed: %s\n",
filename, strerror(errno));
goto out;
}
out:
close(fd);
}
static int strip_rcs_crap(char *version)
{
unsigned int len, full_len;
if (strncmp(version, "$Revision", strlen("$Revision")) != 0)
return 0;
/* Space for version string follows. */
full_len = strlen(version) + strlen(version + strlen(version) + 1) + 2;
/* Move string to start with version number: prefix will be
* $Revision$ or $Revision: */
len = strlen("$Revision");
if (version[len] == ':' || version[len] == '$')
len++;
while (isspace(version[len]))
len++;
memmove(version, version+len, full_len-len);
full_len -= len;
/* Preserve up to next whitespace. */
len = 0;
while (version[len] && !isspace(version[len]))
len++;
memmove(version + len, version + strlen(version),
full_len - strlen(version));
return 1;
}
/* Clean up RCS-style version numbers. */
void maybe_frob_rcs_version(const char *modfilename,
char *version,
void *modinfo,
unsigned long version_offset)
{
if (strip_rcs_crap(version))
write_version(modfilename, version, version_offset);
free:
free(buf);
}