--- /dev/null
+#ifndef __LICENSE_H
+#define __LICENSE_H
+
+static inline int license_is_gpl_compatible(const char *license)
+{
+ return (strcmp(license, "GPL") == 0
+ || strcmp(license, "GPL v2") == 0
+ || strcmp(license, "GPL and additional rights") == 0
+ || strcmp(license, "Dual BSD/GPL") == 0
+ || strcmp(license, "Dual MIT/GPL") == 0
+ || strcmp(license, "Dual MPL/GPL") == 0);
+}
+
+#endif
#include <asm/uaccess.h>
#include <asm/semaphore.h>
#include <asm/cacheflush.h>
+#include <linux/license.h>
#if 0
#define DEBUGP printk
}
}
-static inline int license_is_gpl_compatible(const char *license)
-{
- return (strcmp(license, "GPL") == 0
- || strcmp(license, "GPL v2") == 0
- || strcmp(license, "GPL and additional rights") == 0
- || strcmp(license, "Dual BSD/GPL") == 0
- || strcmp(license, "Dual MIT/GPL") == 0
- || strcmp(license, "Dual MPL/GPL") == 0);
-}
-
static void set_license(struct module *mod, const char *license)
{
if (!license)
#include <ctype.h>
#include "modpost.h"
+#include "../../include/linux/license.h"
/* Are we using CONFIG_MODVERSIONS? */
int modversions = 0;
/* add to list */
mod->name = p;
+ mod->gpl_compatible = -1;
mod->next = modules;
modules = mod;
return string;
}
-static char *get_modinfo(void *modinfo, unsigned long modinfo_len,
- const char *tag)
+static char *get_next_modinfo(void *modinfo, unsigned long modinfo_len,
+ const char *tag, char *info)
{
char *p;
unsigned int taglen = strlen(tag);
unsigned long size = modinfo_len;
+ if (info) {
+ size -= info - (char *)modinfo;
+ modinfo = next_string(info, &size);
+ }
+
for (p = modinfo; p; p = next_string(p, &size)) {
if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
return p + taglen + 1;
return NULL;
}
+static char *get_modinfo(void *modinfo, unsigned long modinfo_len,
+ const char *tag)
+
+{
+ return get_next_modinfo(modinfo, modinfo_len, tag, NULL);
+}
+
/**
* Test if string s ends in string sub
* return 0 if match
{
const char *symname;
char *version;
+ char *license;
struct module *mod;
struct elf_info info = { };
Elf_Sym *sym;
mod->skip = 1;
}
+ license = get_modinfo(info.modinfo, info.modinfo_len, "license");
+ while (license) {
+ if (license_is_gpl_compatible(license))
+ mod->gpl_compatible = 1;
+ else {
+ mod->gpl_compatible = 0;
+ break;
+ }
+ license = get_next_modinfo(info.modinfo, info.modinfo_len,
+ "license", license);
+ }
+
for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
symname = info.strtab + sym->st_name;
buf->pos += len;
}
+void check_license(struct module *mod)
+{
+ struct symbol *s, *exp;
+
+ for (s = mod->unres; s; s = s->next) {
+ if (mod->gpl_compatible == 1) {
+ /* GPL-compatible modules may use all symbols */
+ continue;
+ }
+ exp = find_symbol(s->name);
+ if (!exp || exp->module == mod)
+ continue;
+ const char *basename = strrchr(mod->name, '/');
+ if (basename)
+ basename++;
+ switch (exp->export) {
+ case export_gpl:
+ fatal("modpost: GPL-incompatible module %s "
+ "uses GPL-only symbol '%s'\n",
+ basename ? basename : mod->name,
+ exp->name);
+ break;
+ case export_gpl_future:
+ warn("modpost: GPL-incompatible module %s "
+ "uses future GPL-only symbol '%s'\n",
+ basename ? basename : mod->name,
+ exp->name);
+ break;
+ case export_plain: /* ignore */ break;
+ case export_unknown: /* ignore */ break;
+ }
+ }
+}
+
/**
* Header for the generated file
**/
read_symbols(argv[optind++]);
}
+ for (mod = modules; mod; mod = mod->next) {
+ if (mod->skip)
+ continue;
+ check_license(mod);
+ }
+
for (mod = modules; mod; mod = mod->next) {
if (mod->skip)
continue;