diff options
Diffstat (limited to 'scripts/mod/modpost.c')
-rw-r--r-- | scripts/mod/modpost.c | 71 |
1 files changed, 69 insertions, 2 deletions
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index ba2e4fc2af20..baa4d83d29a8 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c | |||
@@ -13,6 +13,7 @@ | |||
13 | 13 | ||
14 | #include <ctype.h> | 14 | #include <ctype.h> |
15 | #include "modpost.h" | 15 | #include "modpost.h" |
16 | #include "../../include/linux/license.h" | ||
16 | 17 | ||
17 | /* Are we using CONFIG_MODVERSIONS? */ | 18 | /* Are we using CONFIG_MODVERSIONS? */ |
18 | int modversions = 0; | 19 | int modversions = 0; |
@@ -99,6 +100,7 @@ static struct module *new_module(char *modname) | |||
99 | 100 | ||
100 | /* add to list */ | 101 | /* add to list */ |
101 | mod->name = p; | 102 | mod->name = p; |
103 | mod->gpl_compatible = -1; | ||
102 | mod->next = modules; | 104 | mod->next = modules; |
103 | modules = mod; | 105 | modules = mod; |
104 | 106 | ||
@@ -493,13 +495,18 @@ static char *next_string(char *string, unsigned long *secsize) | |||
493 | return string; | 495 | return string; |
494 | } | 496 | } |
495 | 497 | ||
496 | static char *get_modinfo(void *modinfo, unsigned long modinfo_len, | 498 | static char *get_next_modinfo(void *modinfo, unsigned long modinfo_len, |
497 | const char *tag) | 499 | const char *tag, char *info) |
498 | { | 500 | { |
499 | char *p; | 501 | char *p; |
500 | unsigned int taglen = strlen(tag); | 502 | unsigned int taglen = strlen(tag); |
501 | unsigned long size = modinfo_len; | 503 | unsigned long size = modinfo_len; |
502 | 504 | ||
505 | if (info) { | ||
506 | size -= info - (char *)modinfo; | ||
507 | modinfo = next_string(info, &size); | ||
508 | } | ||
509 | |||
503 | for (p = modinfo; p; p = next_string(p, &size)) { | 510 | for (p = modinfo; p; p = next_string(p, &size)) { |
504 | if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=') | 511 | if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=') |
505 | return p + taglen + 1; | 512 | return p + taglen + 1; |
@@ -507,6 +514,13 @@ static char *get_modinfo(void *modinfo, unsigned long modinfo_len, | |||
507 | return NULL; | 514 | return NULL; |
508 | } | 515 | } |
509 | 516 | ||
517 | static char *get_modinfo(void *modinfo, unsigned long modinfo_len, | ||
518 | const char *tag) | ||
519 | |||
520 | { | ||
521 | return get_next_modinfo(modinfo, modinfo_len, tag, NULL); | ||
522 | } | ||
523 | |||
510 | /** | 524 | /** |
511 | * Test if string s ends in string sub | 525 | * Test if string s ends in string sub |
512 | * return 0 if match | 526 | * return 0 if match |
@@ -981,6 +995,7 @@ static void read_symbols(char *modname) | |||
981 | { | 995 | { |
982 | const char *symname; | 996 | const char *symname; |
983 | char *version; | 997 | char *version; |
998 | char *license; | ||
984 | struct module *mod; | 999 | struct module *mod; |
985 | struct elf_info info = { }; | 1000 | struct elf_info info = { }; |
986 | Elf_Sym *sym; | 1001 | Elf_Sym *sym; |
@@ -996,6 +1011,18 @@ static void read_symbols(char *modname) | |||
996 | mod->skip = 1; | 1011 | mod->skip = 1; |
997 | } | 1012 | } |
998 | 1013 | ||
1014 | license = get_modinfo(info.modinfo, info.modinfo_len, "license"); | ||
1015 | while (license) { | ||
1016 | if (license_is_gpl_compatible(license)) | ||
1017 | mod->gpl_compatible = 1; | ||
1018 | else { | ||
1019 | mod->gpl_compatible = 0; | ||
1020 | break; | ||
1021 | } | ||
1022 | license = get_next_modinfo(info.modinfo, info.modinfo_len, | ||
1023 | "license", license); | ||
1024 | } | ||
1025 | |||
999 | for (sym = info.symtab_start; sym < info.symtab_stop; sym++) { | 1026 | for (sym = info.symtab_start; sym < info.symtab_stop; sym++) { |
1000 | symname = info.strtab + sym->st_name; | 1027 | symname = info.strtab + sym->st_name; |
1001 | 1028 | ||
@@ -1052,6 +1079,40 @@ void buf_write(struct buffer *buf, const char *s, int len) | |||
1052 | buf->pos += len; | 1079 | buf->pos += len; |
1053 | } | 1080 | } |
1054 | 1081 | ||
1082 | void check_license(struct module *mod) | ||
1083 | { | ||
1084 | struct symbol *s, *exp; | ||
1085 | |||
1086 | for (s = mod->unres; s; s = s->next) { | ||
1087 | if (mod->gpl_compatible == 1) { | ||
1088 | /* GPL-compatible modules may use all symbols */ | ||
1089 | continue; | ||
1090 | } | ||
1091 | exp = find_symbol(s->name); | ||
1092 | if (!exp || exp->module == mod) | ||
1093 | continue; | ||
1094 | const char *basename = strrchr(mod->name, '/'); | ||
1095 | if (basename) | ||
1096 | basename++; | ||
1097 | switch (exp->export) { | ||
1098 | case export_gpl: | ||
1099 | fatal("modpost: GPL-incompatible module %s " | ||
1100 | "uses GPL-only symbol '%s'\n", | ||
1101 | basename ? basename : mod->name, | ||
1102 | exp->name); | ||
1103 | break; | ||
1104 | case export_gpl_future: | ||
1105 | warn("modpost: GPL-incompatible module %s " | ||
1106 | "uses future GPL-only symbol '%s'\n", | ||
1107 | basename ? basename : mod->name, | ||
1108 | exp->name); | ||
1109 | break; | ||
1110 | case export_plain: /* ignore */ break; | ||
1111 | case export_unknown: /* ignore */ break; | ||
1112 | } | ||
1113 | } | ||
1114 | } | ||
1115 | |||
1055 | /** | 1116 | /** |
1056 | * Header for the generated file | 1117 | * Header for the generated file |
1057 | **/ | 1118 | **/ |
@@ -1328,6 +1389,12 @@ int main(int argc, char **argv) | |||
1328 | for (mod = modules; mod; mod = mod->next) { | 1389 | for (mod = modules; mod; mod = mod->next) { |
1329 | if (mod->skip) | 1390 | if (mod->skip) |
1330 | continue; | 1391 | continue; |
1392 | check_license(mod); | ||
1393 | } | ||
1394 | |||
1395 | for (mod = modules; mod; mod = mod->next) { | ||
1396 | if (mod->skip) | ||
1397 | continue; | ||
1331 | 1398 | ||
1332 | buf.pos = 0; | 1399 | buf.pos = 0; |
1333 | 1400 | ||