minix/commands/pkg_install/lib/license.c

303 lines
7.4 KiB
C

/* $NetBSD: license.c,v 1.14 2010/05/06 13:16:59 obache Exp $ */
/*-
* Copyright (c) 2009 Joerg Sonnenberger <joerg@NetBSD.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#ifndef __minix
#include <nbcompat.h>
#endif
#if HAVE_ERR_H
#include <err.h>
#endif
#include <stdlib.h>
#include <string.h>
#include "lib.h"
#define HASH_SIZE 521
const char *default_acceptable_licenses =
"public-domain "
"gnu-fdl-v1.1 gnu-fdl-v1.2 gnu-fdl-v1.3 "
"gnu-gpl-v2 gnu-lgpl-v2 gnu-lgpl-v2.1 "
"gnu-gpl-v3 gnu-lgpl-v3 "
"original-bsd modified-bsd 2-clause-bsd "
"x11 mit miros "
"apache-1.1 apache-2.0 "
"artistic artistic-2.0 "
"cddl-1.0 "
"cpl-1.0 "
"open-font-license "
"mpl-1.0 mpl-1.1 "
"zpl "
"python-software-foundation "
"ipafont "
"isc "
"info-zip";
#ifdef DEBUG
static size_t hash_collisions;
#endif
static char **license_hash[HASH_SIZE];
static const char license_spaces[] = " \t\n";
static const char license_chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-.";
static size_t
hash_license(const char *license, size_t len)
{
size_t hash;
for (hash = 0; *license && len; ++license, --len)
hash = *license + hash * 32;
return hash % HASH_SIZE;
}
static void
add_license_internal(const char *license, size_t len)
{
char *new_license;
size_t slot, i;
slot = hash_license(license, len);
new_license = malloc(len + 1);
memcpy(new_license, license, len);
new_license[len] = '\0';
if (license_hash[slot] == NULL) {
license_hash[slot] = calloc(sizeof(char *), 2);
license_hash[slot][0] = new_license;
} else {
for (i = 0; license_hash[slot][i]; ++i) {
if (!memcmp(license_hash[slot][i], license, len) &&
license_hash[slot][i][len] == '\0') {
free(new_license);
return;
}
}
#ifdef DEBUG
++hash_collisions;
#endif
license_hash[slot] = realloc(license_hash[slot],
sizeof(char *) * (i + 2));
license_hash[slot][i] = new_license;
license_hash[slot][i + 1] = NULL;
}
}
int
add_licenses(const char *line)
{
const char *next;
if (line == NULL)
return 0;
for (line += strspn(line, license_spaces); line; ) {
next = line + strspn(line, license_chars);
if (next == line)
return *line ? -1 : 0;
add_license_internal(line, next - line);
line = next + strspn(next, license_spaces);
if (next == line)
return *line ? -1 : 0;
}
return 0;
}
static int
acceptable_license_internal(const char *license, size_t len)
{
size_t slot, i;
slot = hash_license(license, len);
if (license_hash[slot] == NULL)
return 0;
for (i = 0; license_hash[slot][i]; ++i) {
if (strncmp(license_hash[slot][i], license, len) == 0 &&
license_hash[slot][i][len] == '\0')
return 1;
}
return 0;
}
int
acceptable_license(const char *license)
{
size_t len;
len = strlen(license);
if (strspn(license, license_chars) != len) {
warnx("Invalid character in license name at position %" PRIzu, len);
return -1;
}
return acceptable_license_internal(license, len);
}
static int
acceptable_pkg_license_internal(const char **licensep, int toplevel, const char *start)
{
const char *license = *licensep;
int need_parenthesis, is_true = 0;
int expr_type = 0; /* 0: unset, 1: or, 2: and */
size_t len;
license += strspn(license, license_spaces);
if (*license == '(' && !toplevel) {
need_parenthesis = 1;
++license;
license += strspn(license, license_spaces);
} else {
need_parenthesis = 0;
}
for (;;) {
if (*license == '(') {
switch (acceptable_pkg_license_internal(&license, 0, start)) {
case -1:
return -1;
case 0:
if (expr_type == 2)
is_true = 0;
break;
case 1:
is_true = 1;
break;
}
license += strspn(license, license_spaces);
} else {
len = strspn(license, license_chars);
if (len == 0) {
warnx("Invalid character in license name at position %" PRIzu, license - start + 1);
return -1;
}
if (acceptable_license_internal(license, len)) {
if (expr_type != 2)
is_true = 1;
} else if (expr_type == 2) {
is_true = 0;
}
license += len;
len = strspn(license, license_spaces);
if (len == 0 && *license && *license != ')') {
warnx("Missing space at position %" PRIzu, license - start + 1);
return -1;
}
license += len;
}
if (*license == ')') {
if (!need_parenthesis) {
warnx("Missing open parenthesis at position %" PRIzu, license - start + 1);
return -1;
}
*licensep = license + 1;
return is_true;
}
if (*license == '\0') {
if (need_parenthesis) {
warnx("Unbalanced parenthesis at position %" PRIzu, license - start + 1);
return -1;
}
*licensep = license;
return is_true;
}
if (strncmp(license, "AND", 3) == 0) {
if (expr_type == 1) {
warnx("Invalid operator in OR expression at position %" PRIzu, license - start + 1);
return -1;
}
expr_type = 2;
license += 3;
} else if (strncmp(license, "OR", 2) == 0) {
if (expr_type == 2) {
warnx("Invalid operator in AND expression at position %" PRIzu, license - start + 1);
return -1;
}
expr_type = 1;
license += 2;
} else {
warnx("Invalid operator at position %" PRIzu, license - start + 1);
return -1;
}
len = strspn(license, license_spaces);
if (len == 0 && *license != '(') {
warnx("Missing space at position %" PRIzu, license - start + 1);
return -1;
}
license += len;
}
}
int
acceptable_pkg_license(const char *license)
{
int ret;
ret = acceptable_pkg_license_internal(&license, 1, license);
if (ret == -1)
return -1;
license += strspn(license, license_spaces);
if (*license) {
warnx("Trailing garbage in license specification");
return -1;
}
return ret;
}
void
load_license_lists(void)
{
if (add_licenses(getenv("PKGSRC_ACCEPTABLE_LICENSES")))
errx(EXIT_FAILURE, "syntax error in PKGSRC_ACCEPTABLE_LICENSES");
if (add_licenses(acceptable_licenses))
errx(EXIT_FAILURE, "syntax error in ACCEPTABLE_LICENSES");
if (add_licenses(getenv("PKGSRC_DEFAULT_ACCEPTABLE_LICENSES")))
errx(EXIT_FAILURE, "syntax error in PKGSRC_DEFAULT_ACCEPTABLE_LICENSES");
if (add_licenses(default_acceptable_licenses))
errx(EXIT_FAILURE, "syntax error in DEFAULT_ACCEPTABLE_LICENSES");
}