1 #include <tools/ccanlint/ccanlint.h>
11 #include <ccan/talloc/talloc.h>
12 #include <ccan/str/str.h>
13 #include <ccan/str_talloc/str_talloc.h>
15 static struct doc_section *find_license_tag(const struct manifest *m)
17 struct doc_section *d;
19 list_for_each(m->info_file->doc_sections, d, list) {
20 if (!streq(d->function, m->basename))
22 if (streq(d->type, "license"))
28 /* See GPLv2 and v2 (basically same wording) for interpreting versions:
29 * the "any later version" means the recepient can choose. */
30 static enum license which_license(struct doc_section *d)
32 /* This means "user chooses what version", including GPLv1! */
33 if (streq(d->lines[0], "GPL"))
35 /* This means "v2 only". */
36 if (streq(d->lines[0], "GPLv2"))
38 /* This means "v2 or above" at user's choice. */
39 if (streq(d->lines[0], "GPL (v2 or any later version)"))
40 return LICENSE_GPLv2_PLUS;
41 /* This means "v3 or above" at user's choice. */
42 if (streq(d->lines[0], "GPL (v3 or any later version)"))
45 /* This means "user chooses what version" */
46 if (streq(d->lines[0], "LGPL"))
48 /* This means "v2.1 only". */
49 if (streq(d->lines[0], "LGPLv2.1"))
50 return LICENSE_LGPLv2;
51 /* This means "v2.1 or above" at user's choice. */
52 if (streq(d->lines[0], "LGPL (v2.1 or any later version)"))
53 return LICENSE_LGPLv2_PLUS;
54 /* This means "v3 or above" at user's choice. */
55 if (streq(d->lines[0], "LGPL (v3 or any later version)"))
56 return LICENSE_LGPLv3;
58 if (streq(d->lines[0], "BSD-MIT") || streq(d->lines[0], "MIT"))
60 if (streq(d->lines[0], "BSD (3 clause)"))
62 if (strreg(NULL, d->lines[0], "[Pp]ublic [Dd]omain"))
63 return LICENSE_PUBLIC_DOMAIN;
65 return LICENSE_UNKNOWN;
68 static const char *expected_link(enum license license)
71 case LICENSE_LGPLv2_PLUS:
73 return "../../licenses/LGPL-2.1";
76 return "../../licenses/LGPL-3";
78 case LICENSE_GPLv2_PLUS:
80 return "../../licenses/GPL-2";
84 return "../../licenses/GPL-3";
87 return "../../licenses/BSD-3CLAUSE";
90 return "../../licenses/BSD-MIT";
97 static void handle_license_link(struct manifest *m, struct score *score)
99 struct doc_section *d = find_license_tag(m);
100 const char *link = talloc_asprintf(m, "%s/LICENSE", m->dir);
101 const char *ldest = expected_link(m->license);
105 "Most modules want a copy of their license, so usually we create a\n"
106 "LICENSE symlink into ../../licenses to avoid too many copies.\n");
108 /* FIXME: make ask printf-like */
109 q = talloc_asprintf(m, "Set up link to %s (license is %s)?",
112 if (symlink(ldest, link) != 0)
113 err(1, "Creating symlink %s -> %s", link, ldest);
117 extern struct ccanlint license_exists;
119 static void check_has_license(struct manifest *m,
121 unsigned int *timeleft, struct score *score)
125 char *license = talloc_asprintf(m, "%s/LICENSE", m->dir);
126 const char *expected;
127 struct doc_section *d;
129 d = find_license_tag(m);
131 score->error = talloc_strdup(score, "No License: tag in _info");
135 m->license = which_license(d);
136 if (m->license == LICENSE_UNKNOWN) {
137 score_file_error(score, m->info_file, d->srcline,
138 "WARNING: unknown License: in _info: %s",
140 /* FIXME: For historical reasons, don't fail here. */
145 /* If they have a license tag at all, we pass. */
148 expected = expected_link(m->license);
150 len = readlink(license, buf, sizeof(buf));
152 /* Could be a real file... OK if not a standard license. */
153 if (errno == EINVAL) {
155 score->score = score->total;
159 = talloc_asprintf(score,
160 "License in _info is '%s',"
161 " expect LICENSE symlink '%s'",
162 d->lines[0], expected);
165 if (errno == ENOENT) {
166 /* Public domain doesn't really need a file. */
167 if (m->license == LICENSE_PUBLIC_DOMAIN) {
168 score->score = score->total;
171 score->error = talloc_strdup(score,
172 "LICENSE does not exist");
174 license_exists.handle = handle_license_link;
177 err(1, "readlink on %s", license);
179 if (len >= sizeof(buf))
180 errx(1, "Reading symlink %s gave huge result", license);
184 if (!strstarts(buf, "../../licenses/")) {
185 score->error = talloc_asprintf(score,
186 "Expected symlink to"
187 " ../../licenses/..."
193 score->error = talloc_asprintf(score,
194 "License in _info is unknown '%s',"
195 " but LICENSE symlink is '%s'",
200 if (!streq(buf, expected)) {
201 score->error = talloc_asprintf(score,
202 "Expected symlink to %s not %s",
207 score->score = score->total;
210 struct ccanlint license_exists = {
211 .key = "license_exists",
212 .name = "Module has License: entry in _info, and LICENSE symlink/file",
213 .check = check_has_license,
214 .needs = "info_exists"
216 REGISTER_TEST(license_exists);