1*a824f5a1SJean-Baptiste Boric /* $NetBSD: license.c,v 1.4 2013/04/20 15:29:23 wiz Exp $ */
2*a824f5a1SJean-Baptiste Boric
3*a824f5a1SJean-Baptiste Boric /*-
4*a824f5a1SJean-Baptiste Boric * Copyright (c) 2009 Joerg Sonnenberger <joerg@NetBSD.org>.
5*a824f5a1SJean-Baptiste Boric * All rights reserved.
6*a824f5a1SJean-Baptiste Boric *
7*a824f5a1SJean-Baptiste Boric * Redistribution and use in source and binary forms, with or without
8*a824f5a1SJean-Baptiste Boric * modification, are permitted provided that the following conditions
9*a824f5a1SJean-Baptiste Boric * are met:
10*a824f5a1SJean-Baptiste Boric *
11*a824f5a1SJean-Baptiste Boric * 1. Redistributions of source code must retain the above copyright
12*a824f5a1SJean-Baptiste Boric * notice, this list of conditions and the following disclaimer.
13*a824f5a1SJean-Baptiste Boric * 2. Redistributions in binary form must reproduce the above copyright
14*a824f5a1SJean-Baptiste Boric * notice, this list of conditions and the following disclaimer in
15*a824f5a1SJean-Baptiste Boric * the documentation and/or other materials provided with the
16*a824f5a1SJean-Baptiste Boric * distribution.
17*a824f5a1SJean-Baptiste Boric *
18*a824f5a1SJean-Baptiste Boric * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19*a824f5a1SJean-Baptiste Boric * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20*a824f5a1SJean-Baptiste Boric * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21*a824f5a1SJean-Baptiste Boric * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22*a824f5a1SJean-Baptiste Boric * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23*a824f5a1SJean-Baptiste Boric * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
24*a824f5a1SJean-Baptiste Boric * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25*a824f5a1SJean-Baptiste Boric * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26*a824f5a1SJean-Baptiste Boric * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27*a824f5a1SJean-Baptiste Boric * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
28*a824f5a1SJean-Baptiste Boric * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29*a824f5a1SJean-Baptiste Boric * SUCH DAMAGE.
30*a824f5a1SJean-Baptiste Boric */
31*a824f5a1SJean-Baptiste Boric
32*a824f5a1SJean-Baptiste Boric #if HAVE_CONFIG_H
33*a824f5a1SJean-Baptiste Boric #include "config.h"
34*a824f5a1SJean-Baptiste Boric #endif
35*a824f5a1SJean-Baptiste Boric
36*a824f5a1SJean-Baptiste Boric #include <nbcompat.h>
37*a824f5a1SJean-Baptiste Boric
38*a824f5a1SJean-Baptiste Boric #if HAVE_ERR_H
39*a824f5a1SJean-Baptiste Boric #include <err.h>
40*a824f5a1SJean-Baptiste Boric #endif
41*a824f5a1SJean-Baptiste Boric #include <stdlib.h>
42*a824f5a1SJean-Baptiste Boric #include <string.h>
43*a824f5a1SJean-Baptiste Boric
44*a824f5a1SJean-Baptiste Boric #include "lib.h"
45*a824f5a1SJean-Baptiste Boric
46*a824f5a1SJean-Baptiste Boric #define HASH_SIZE 521
47*a824f5a1SJean-Baptiste Boric
48*a824f5a1SJean-Baptiste Boric const char *default_acceptable_licenses =
49*a824f5a1SJean-Baptiste Boric "apache-1.1 apache-2.0 "
50*a824f5a1SJean-Baptiste Boric "arphic-public "
51*a824f5a1SJean-Baptiste Boric "artistic artistic-2.0 "
52*a824f5a1SJean-Baptiste Boric "boost-license "
53*a824f5a1SJean-Baptiste Boric "cc-by-sa-v3.0 "
54*a824f5a1SJean-Baptiste Boric "cddl-1.0 "
55*a824f5a1SJean-Baptiste Boric "cpl-1.0 "
56*a824f5a1SJean-Baptiste Boric "epl-v1.0 "
57*a824f5a1SJean-Baptiste Boric "gnu-fdl-v1.1 gnu-fdl-v1.2 gnu-fdl-v1.3 "
58*a824f5a1SJean-Baptiste Boric "gnu-gpl-v1 "
59*a824f5a1SJean-Baptiste Boric "gnu-gpl-v2 gnu-lgpl-v2 gnu-lgpl-v2.1 "
60*a824f5a1SJean-Baptiste Boric "gnu-gpl-v3 gnu-lgpl-v3 "
61*a824f5a1SJean-Baptiste Boric "ibm-public-license-1.0 "
62*a824f5a1SJean-Baptiste Boric "ipafont "
63*a824f5a1SJean-Baptiste Boric "isc "
64*a824f5a1SJean-Baptiste Boric "lppl-1.3c "
65*a824f5a1SJean-Baptiste Boric "lucent "
66*a824f5a1SJean-Baptiste Boric "miros "
67*a824f5a1SJean-Baptiste Boric "mit "
68*a824f5a1SJean-Baptiste Boric "mpl-1.0 mpl-1.1 mpl-2.0 "
69*a824f5a1SJean-Baptiste Boric "mplusfont "
70*a824f5a1SJean-Baptiste Boric "ofl-v1.0 ofl-v1.1 "
71*a824f5a1SJean-Baptiste Boric "original-bsd modified-bsd 2-clause-bsd "
72*a824f5a1SJean-Baptiste Boric "php "
73*a824f5a1SJean-Baptiste Boric "png-license "
74*a824f5a1SJean-Baptiste Boric "postgresql-license "
75*a824f5a1SJean-Baptiste Boric "public-domain "
76*a824f5a1SJean-Baptiste Boric "python-software-foundation "
77*a824f5a1SJean-Baptiste Boric "qpl-v1.0 "
78*a824f5a1SJean-Baptiste Boric "sleepycat-public "
79*a824f5a1SJean-Baptiste Boric "unlicense "
80*a824f5a1SJean-Baptiste Boric "x11 "
81*a824f5a1SJean-Baptiste Boric "zlib "
82*a824f5a1SJean-Baptiste Boric "zpl";
83*a824f5a1SJean-Baptiste Boric
84*a824f5a1SJean-Baptiste Boric #ifdef DEBUG
85*a824f5a1SJean-Baptiste Boric static size_t hash_collisions;
86*a824f5a1SJean-Baptiste Boric #endif
87*a824f5a1SJean-Baptiste Boric
88*a824f5a1SJean-Baptiste Boric static char **license_hash[HASH_SIZE];
89*a824f5a1SJean-Baptiste Boric static const char license_spaces[] = " \t\n";
90*a824f5a1SJean-Baptiste Boric static const char license_chars[] =
91*a824f5a1SJean-Baptiste Boric "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-.";
92*a824f5a1SJean-Baptiste Boric
93*a824f5a1SJean-Baptiste Boric static size_t
hash_license(const char * license,size_t len)94*a824f5a1SJean-Baptiste Boric hash_license(const char *license, size_t len)
95*a824f5a1SJean-Baptiste Boric {
96*a824f5a1SJean-Baptiste Boric size_t hash;
97*a824f5a1SJean-Baptiste Boric
98*a824f5a1SJean-Baptiste Boric for (hash = 0; *license && len; ++license, --len)
99*a824f5a1SJean-Baptiste Boric hash = *license + hash * 32;
100*a824f5a1SJean-Baptiste Boric return hash % HASH_SIZE;
101*a824f5a1SJean-Baptiste Boric }
102*a824f5a1SJean-Baptiste Boric
103*a824f5a1SJean-Baptiste Boric static void
add_license_internal(const char * license,size_t len)104*a824f5a1SJean-Baptiste Boric add_license_internal(const char *license, size_t len)
105*a824f5a1SJean-Baptiste Boric {
106*a824f5a1SJean-Baptiste Boric char *new_license;
107*a824f5a1SJean-Baptiste Boric size_t slot, i;
108*a824f5a1SJean-Baptiste Boric
109*a824f5a1SJean-Baptiste Boric slot = hash_license(license, len);
110*a824f5a1SJean-Baptiste Boric
111*a824f5a1SJean-Baptiste Boric new_license = malloc(len + 1);
112*a824f5a1SJean-Baptiste Boric memcpy(new_license, license, len);
113*a824f5a1SJean-Baptiste Boric new_license[len] = '\0';
114*a824f5a1SJean-Baptiste Boric
115*a824f5a1SJean-Baptiste Boric if (license_hash[slot] == NULL) {
116*a824f5a1SJean-Baptiste Boric license_hash[slot] = calloc(sizeof(char *), 2);
117*a824f5a1SJean-Baptiste Boric license_hash[slot][0] = new_license;
118*a824f5a1SJean-Baptiste Boric } else {
119*a824f5a1SJean-Baptiste Boric for (i = 0; license_hash[slot][i]; ++i) {
120*a824f5a1SJean-Baptiste Boric if (!memcmp(license_hash[slot][i], license, len) &&
121*a824f5a1SJean-Baptiste Boric license_hash[slot][i][len] == '\0') {
122*a824f5a1SJean-Baptiste Boric free(new_license);
123*a824f5a1SJean-Baptiste Boric return;
124*a824f5a1SJean-Baptiste Boric }
125*a824f5a1SJean-Baptiste Boric }
126*a824f5a1SJean-Baptiste Boric
127*a824f5a1SJean-Baptiste Boric #ifdef DEBUG
128*a824f5a1SJean-Baptiste Boric ++hash_collisions;
129*a824f5a1SJean-Baptiste Boric #endif
130*a824f5a1SJean-Baptiste Boric
131*a824f5a1SJean-Baptiste Boric license_hash[slot] = realloc(license_hash[slot],
132*a824f5a1SJean-Baptiste Boric sizeof(char *) * (i + 2));
133*a824f5a1SJean-Baptiste Boric license_hash[slot][i] = new_license;
134*a824f5a1SJean-Baptiste Boric license_hash[slot][i + 1] = NULL;
135*a824f5a1SJean-Baptiste Boric }
136*a824f5a1SJean-Baptiste Boric }
137*a824f5a1SJean-Baptiste Boric
138*a824f5a1SJean-Baptiste Boric int
add_licenses(const char * line)139*a824f5a1SJean-Baptiste Boric add_licenses(const char *line)
140*a824f5a1SJean-Baptiste Boric {
141*a824f5a1SJean-Baptiste Boric const char *next;
142*a824f5a1SJean-Baptiste Boric
143*a824f5a1SJean-Baptiste Boric if (line == NULL)
144*a824f5a1SJean-Baptiste Boric return 0;
145*a824f5a1SJean-Baptiste Boric
146*a824f5a1SJean-Baptiste Boric for (line += strspn(line, license_spaces); line; ) {
147*a824f5a1SJean-Baptiste Boric next = line + strspn(line, license_chars);
148*a824f5a1SJean-Baptiste Boric if (next == line)
149*a824f5a1SJean-Baptiste Boric return *line ? -1 : 0;
150*a824f5a1SJean-Baptiste Boric add_license_internal(line, next - line);
151*a824f5a1SJean-Baptiste Boric line = next + strspn(next, license_spaces);
152*a824f5a1SJean-Baptiste Boric if (next == line)
153*a824f5a1SJean-Baptiste Boric return *line ? -1 : 0;
154*a824f5a1SJean-Baptiste Boric }
155*a824f5a1SJean-Baptiste Boric return 0;
156*a824f5a1SJean-Baptiste Boric }
157*a824f5a1SJean-Baptiste Boric
158*a824f5a1SJean-Baptiste Boric static int
acceptable_license_internal(const char * license,size_t len)159*a824f5a1SJean-Baptiste Boric acceptable_license_internal(const char *license, size_t len)
160*a824f5a1SJean-Baptiste Boric {
161*a824f5a1SJean-Baptiste Boric size_t slot, i;
162*a824f5a1SJean-Baptiste Boric
163*a824f5a1SJean-Baptiste Boric slot = hash_license(license, len);
164*a824f5a1SJean-Baptiste Boric
165*a824f5a1SJean-Baptiste Boric if (license_hash[slot] == NULL)
166*a824f5a1SJean-Baptiste Boric return 0;
167*a824f5a1SJean-Baptiste Boric
168*a824f5a1SJean-Baptiste Boric for (i = 0; license_hash[slot][i]; ++i) {
169*a824f5a1SJean-Baptiste Boric if (strncmp(license_hash[slot][i], license, len) == 0 &&
170*a824f5a1SJean-Baptiste Boric license_hash[slot][i][len] == '\0')
171*a824f5a1SJean-Baptiste Boric return 1;
172*a824f5a1SJean-Baptiste Boric }
173*a824f5a1SJean-Baptiste Boric
174*a824f5a1SJean-Baptiste Boric return 0;
175*a824f5a1SJean-Baptiste Boric }
176*a824f5a1SJean-Baptiste Boric
177*a824f5a1SJean-Baptiste Boric int
acceptable_license(const char * license)178*a824f5a1SJean-Baptiste Boric acceptable_license(const char *license)
179*a824f5a1SJean-Baptiste Boric {
180*a824f5a1SJean-Baptiste Boric size_t len;
181*a824f5a1SJean-Baptiste Boric
182*a824f5a1SJean-Baptiste Boric len = strlen(license);
183*a824f5a1SJean-Baptiste Boric if (strspn(license, license_chars) != len) {
184*a824f5a1SJean-Baptiste Boric warnx("Invalid character in license name at position %" PRIzu, len);
185*a824f5a1SJean-Baptiste Boric return -1;
186*a824f5a1SJean-Baptiste Boric }
187*a824f5a1SJean-Baptiste Boric
188*a824f5a1SJean-Baptiste Boric return acceptable_license_internal(license, len);
189*a824f5a1SJean-Baptiste Boric }
190*a824f5a1SJean-Baptiste Boric
191*a824f5a1SJean-Baptiste Boric static int
acceptable_pkg_license_internal(const char ** licensep,int toplevel,const char * start)192*a824f5a1SJean-Baptiste Boric acceptable_pkg_license_internal(const char **licensep, int toplevel, const char *start)
193*a824f5a1SJean-Baptiste Boric {
194*a824f5a1SJean-Baptiste Boric const char *license = *licensep;
195*a824f5a1SJean-Baptiste Boric int need_parenthesis, is_true = 0;
196*a824f5a1SJean-Baptiste Boric int expr_type = 0; /* 0: unset, 1: or, 2: and */
197*a824f5a1SJean-Baptiste Boric size_t len;
198*a824f5a1SJean-Baptiste Boric
199*a824f5a1SJean-Baptiste Boric license += strspn(license, license_spaces);
200*a824f5a1SJean-Baptiste Boric
201*a824f5a1SJean-Baptiste Boric if (*license == '(' && !toplevel) {
202*a824f5a1SJean-Baptiste Boric need_parenthesis = 1;
203*a824f5a1SJean-Baptiste Boric ++license;
204*a824f5a1SJean-Baptiste Boric license += strspn(license, license_spaces);
205*a824f5a1SJean-Baptiste Boric } else {
206*a824f5a1SJean-Baptiste Boric need_parenthesis = 0;
207*a824f5a1SJean-Baptiste Boric }
208*a824f5a1SJean-Baptiste Boric
209*a824f5a1SJean-Baptiste Boric for (;;) {
210*a824f5a1SJean-Baptiste Boric if (*license == '(') {
211*a824f5a1SJean-Baptiste Boric switch (acceptable_pkg_license_internal(&license, 0, start)) {
212*a824f5a1SJean-Baptiste Boric case -1:
213*a824f5a1SJean-Baptiste Boric return -1;
214*a824f5a1SJean-Baptiste Boric case 0:
215*a824f5a1SJean-Baptiste Boric if (expr_type == 2)
216*a824f5a1SJean-Baptiste Boric is_true = 0;
217*a824f5a1SJean-Baptiste Boric break;
218*a824f5a1SJean-Baptiste Boric case 1:
219*a824f5a1SJean-Baptiste Boric is_true = 1;
220*a824f5a1SJean-Baptiste Boric break;
221*a824f5a1SJean-Baptiste Boric }
222*a824f5a1SJean-Baptiste Boric license += strspn(license, license_spaces);
223*a824f5a1SJean-Baptiste Boric } else {
224*a824f5a1SJean-Baptiste Boric len = strspn(license, license_chars);
225*a824f5a1SJean-Baptiste Boric if (len == 0) {
226*a824f5a1SJean-Baptiste Boric warnx("Invalid character in license name at position %" PRIzu, license - start + 1);
227*a824f5a1SJean-Baptiste Boric return -1;
228*a824f5a1SJean-Baptiste Boric }
229*a824f5a1SJean-Baptiste Boric
230*a824f5a1SJean-Baptiste Boric if (acceptable_license_internal(license, len)) {
231*a824f5a1SJean-Baptiste Boric if (expr_type != 2)
232*a824f5a1SJean-Baptiste Boric is_true = 1;
233*a824f5a1SJean-Baptiste Boric } else if (expr_type == 2) {
234*a824f5a1SJean-Baptiste Boric is_true = 0;
235*a824f5a1SJean-Baptiste Boric }
236*a824f5a1SJean-Baptiste Boric
237*a824f5a1SJean-Baptiste Boric license += len;
238*a824f5a1SJean-Baptiste Boric
239*a824f5a1SJean-Baptiste Boric len = strspn(license, license_spaces);
240*a824f5a1SJean-Baptiste Boric if (len == 0 && *license && *license != ')') {
241*a824f5a1SJean-Baptiste Boric warnx("Missing space at position %" PRIzu, license - start + 1);
242*a824f5a1SJean-Baptiste Boric return -1;
243*a824f5a1SJean-Baptiste Boric }
244*a824f5a1SJean-Baptiste Boric license += len;
245*a824f5a1SJean-Baptiste Boric }
246*a824f5a1SJean-Baptiste Boric
247*a824f5a1SJean-Baptiste Boric if (*license == ')') {
248*a824f5a1SJean-Baptiste Boric if (!need_parenthesis) {
249*a824f5a1SJean-Baptiste Boric warnx("Missing open parenthesis at position %" PRIzu, license - start + 1);
250*a824f5a1SJean-Baptiste Boric return -1;
251*a824f5a1SJean-Baptiste Boric }
252*a824f5a1SJean-Baptiste Boric *licensep = license + 1;
253*a824f5a1SJean-Baptiste Boric return is_true;
254*a824f5a1SJean-Baptiste Boric }
255*a824f5a1SJean-Baptiste Boric if (*license == '\0') {
256*a824f5a1SJean-Baptiste Boric if (need_parenthesis) {
257*a824f5a1SJean-Baptiste Boric warnx("Unbalanced parenthesis at position %" PRIzu, license - start + 1);
258*a824f5a1SJean-Baptiste Boric return -1;
259*a824f5a1SJean-Baptiste Boric }
260*a824f5a1SJean-Baptiste Boric *licensep = license;
261*a824f5a1SJean-Baptiste Boric return is_true;
262*a824f5a1SJean-Baptiste Boric }
263*a824f5a1SJean-Baptiste Boric
264*a824f5a1SJean-Baptiste Boric if (strncmp(license, "AND", 3) == 0) {
265*a824f5a1SJean-Baptiste Boric if (expr_type == 1) {
266*a824f5a1SJean-Baptiste Boric warnx("Invalid operator in OR expression at position %" PRIzu, license - start + 1);
267*a824f5a1SJean-Baptiste Boric return -1;
268*a824f5a1SJean-Baptiste Boric }
269*a824f5a1SJean-Baptiste Boric expr_type = 2;
270*a824f5a1SJean-Baptiste Boric license += 3;
271*a824f5a1SJean-Baptiste Boric } else if (strncmp(license, "OR", 2) == 0) {
272*a824f5a1SJean-Baptiste Boric if (expr_type == 2) {
273*a824f5a1SJean-Baptiste Boric warnx("Invalid operator in AND expression at position %" PRIzu, license - start + 1);
274*a824f5a1SJean-Baptiste Boric return -1;
275*a824f5a1SJean-Baptiste Boric }
276*a824f5a1SJean-Baptiste Boric expr_type = 1;
277*a824f5a1SJean-Baptiste Boric license += 2;
278*a824f5a1SJean-Baptiste Boric } else {
279*a824f5a1SJean-Baptiste Boric warnx("Invalid operator at position %" PRIzu, license - start + 1);
280*a824f5a1SJean-Baptiste Boric return -1;
281*a824f5a1SJean-Baptiste Boric }
282*a824f5a1SJean-Baptiste Boric len = strspn(license, license_spaces);
283*a824f5a1SJean-Baptiste Boric if (len == 0 && *license != '(') {
284*a824f5a1SJean-Baptiste Boric warnx("Missing space at position %" PRIzu, license - start + 1);
285*a824f5a1SJean-Baptiste Boric return -1;
286*a824f5a1SJean-Baptiste Boric }
287*a824f5a1SJean-Baptiste Boric license += len;
288*a824f5a1SJean-Baptiste Boric }
289*a824f5a1SJean-Baptiste Boric }
290*a824f5a1SJean-Baptiste Boric
291*a824f5a1SJean-Baptiste Boric int
acceptable_pkg_license(const char * license)292*a824f5a1SJean-Baptiste Boric acceptable_pkg_license(const char *license)
293*a824f5a1SJean-Baptiste Boric {
294*a824f5a1SJean-Baptiste Boric int ret;
295*a824f5a1SJean-Baptiste Boric
296*a824f5a1SJean-Baptiste Boric ret = acceptable_pkg_license_internal(&license, 1, license);
297*a824f5a1SJean-Baptiste Boric if (ret == -1)
298*a824f5a1SJean-Baptiste Boric return -1;
299*a824f5a1SJean-Baptiste Boric license += strspn(license, license_spaces);
300*a824f5a1SJean-Baptiste Boric if (*license) {
301*a824f5a1SJean-Baptiste Boric warnx("Trailing garbage in license specification");
302*a824f5a1SJean-Baptiste Boric return -1;
303*a824f5a1SJean-Baptiste Boric }
304*a824f5a1SJean-Baptiste Boric return ret;
305*a824f5a1SJean-Baptiste Boric }
306*a824f5a1SJean-Baptiste Boric
307*a824f5a1SJean-Baptiste Boric void
load_license_lists(void)308*a824f5a1SJean-Baptiste Boric load_license_lists(void)
309*a824f5a1SJean-Baptiste Boric {
310*a824f5a1SJean-Baptiste Boric if (add_licenses(getenv("PKGSRC_ACCEPTABLE_LICENSES")))
311*a824f5a1SJean-Baptiste Boric errx(EXIT_FAILURE, "syntax error in PKGSRC_ACCEPTABLE_LICENSES");
312*a824f5a1SJean-Baptiste Boric if (add_licenses(acceptable_licenses))
313*a824f5a1SJean-Baptiste Boric errx(EXIT_FAILURE, "syntax error in ACCEPTABLE_LICENSES");
314*a824f5a1SJean-Baptiste Boric if (add_licenses(getenv("PKGSRC_DEFAULT_ACCEPTABLE_LICENSES")))
315*a824f5a1SJean-Baptiste Boric errx(EXIT_FAILURE, "syntax error in PKGSRC_DEFAULT_ACCEPTABLE_LICENSES");
316*a824f5a1SJean-Baptiste Boric if (add_licenses(default_acceptable_licenses))
317*a824f5a1SJean-Baptiste Boric errx(EXIT_FAILURE, "syntax error in DEFAULT_ACCEPTABLE_LICENSES");
318*a824f5a1SJean-Baptiste Boric }
319