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