razor.c
author Kristian H?gsberg <krh@redhat.com>
Wed Sep 19 14:09:03 2007 -0400 (2007-09-19)
changeset 28 c8958f67afd8
parent 27 5dbd81809d26
child 29 28a13008d80b
permissions -rw-r--r--
Add importer for system rpm database.
     1 #define _GNU_SOURCE
     2 
     3 #include <stdlib.h>
     4 #include <stddef.h>
     5 #include <stdio.h>
     6 #include <string.h>
     7 #include <sys/types.h>
     8 #include <sys/stat.h>
     9 #include <sys/mman.h>
    10 #include <unistd.h>
    11 #include <fcntl.h>
    12 #include <errno.h>
    13 
    14 #include "razor.h"
    15 
    16 static void
    17 array_init(struct array *array)
    18 {
    19 	memset(array, 0, sizeof *array);
    20 }
    21 
    22 static void
    23 array_release(struct array *array)
    24 {
    25 	free(array->data);
    26 }
    27 
    28 static void *
    29 array_add(struct array *array, int size)
    30 {
    31 	int alloc;
    32 	void *data, *p;
    33 
    34 	if (array->alloc > 0)
    35 		alloc = array->alloc;
    36 	else
    37 		alloc = 16;
    38 
    39 	while (alloc < array->size + size)
    40 		alloc *= 2;
    41 
    42 	if (array->alloc < alloc) {
    43 		data = realloc(array->data, alloc);
    44 		if (data == NULL)
    45 			return 0;
    46 		array->data = data;
    47 		array->alloc = alloc;
    48 	}
    49 
    50 	p = array->data + array->size;
    51 	array->size += size;
    52 
    53 	return p;
    54 }
    55 
    56 static int
    57 write_to_fd(int fd, void *p, size_t size)
    58 {
    59 	int rest, len;
    60 
    61 	rest = size;
    62 	while (rest > 0) {
    63 		len = write(fd, p, rest);
    64 		if (len < 0)
    65 			return -1;
    66 		rest -= len;
    67 	}
    68 
    69 	return 0;
    70 }
    71 
    72 static void *
    73 zalloc(size_t size)
    74 {
    75 	void *p;
    76 
    77 	p = malloc(size);
    78 	memset(p, 0, size);
    79 
    80 	return p;
    81 }
    82 
    83 struct razor_set_section razor_sections[] = {
    84 	{ RAZOR_PACKAGES,	offsetof(struct razor_set, packages) },
    85 	{ RAZOR_REQUIRES,	offsetof(struct razor_set, requires) },
    86 	{ RAZOR_PROVIDES,	offsetof(struct razor_set, provides) },
    87 	{ RAZOR_STRING_POOL,	offsetof(struct razor_set, string_pool) },
    88 	{ RAZOR_PROPERTY_POOL,	offsetof(struct razor_set, property_pool) },
    89 };
    90 
    91 struct razor_set *
    92 razor_set_create(void)
    93 {
    94 	return zalloc(sizeof(struct razor_set));
    95 }
    96 
    97 struct razor_set *
    98 razor_set_open(const char *filename)
    99 {
   100 	struct razor_set *set;
   101 	struct razor_set_section *s;
   102 	struct stat stat;
   103 	struct array *array;
   104 	int fd;
   105 
   106 	set = zalloc(sizeof *set);
   107 	fd = open(filename, O_RDONLY);
   108 	if (fstat(fd, &stat) < 0)
   109 		return NULL;
   110 	set->header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
   111 	if (set->header == MAP_FAILED) {
   112 		free(set);
   113 		return NULL;
   114 	}
   115 
   116 	for (s = set->header->sections; ~s->type; s++) {
   117 		if (s->type >= ARRAY_SIZE(razor_sections))
   118 			continue;
   119 		if (s->type != razor_sections[s->type].type)
   120 			continue;
   121 		array = (void *) set + razor_sections[s->type].offset;
   122 		array->data = (void *) set->header + s->offset;
   123 		array->size = s->size;
   124 		array->alloc = s->size;
   125 	}
   126 	close(fd);
   127 
   128 	return set;
   129 }
   130 
   131 void
   132 razor_set_destroy(struct razor_set *set)
   133 {
   134 	unsigned int size;
   135 	struct array *a;
   136 	int i;
   137 
   138 	if (set->header) {
   139 		for (i = 0; set->header->sections[i].type; i++)
   140 			;
   141 		size = set->header->sections[i].type;
   142 		munmap(set->header, size);
   143 		free(set->buckets.data);
   144 	} else {
   145 		for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
   146 			a = (void *) set + razor_sections[i].offset;
   147 			free(a->data);
   148 		}
   149 		free(set->buckets.data);
   150 	}
   151 
   152 	free(set);
   153 }
   154 
   155 static int
   156 razor_set_write(struct razor_set *set, const char *filename)
   157 {
   158 	char data[4096];
   159 	struct razor_set_header *header = (struct razor_set_header *) data;
   160 	struct array *a;
   161 	unsigned long offset;
   162 	int i, fd;
   163 
   164 	memset(data, 0, sizeof data);
   165 	header->magic = RAZOR_MAGIC;
   166 	header->version = RAZOR_VERSION;
   167 	offset = sizeof data;
   168 
   169 	for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
   170 		if (razor_sections[i].type != i)
   171 			continue;
   172 		a = (void *) set + razor_sections[i].offset;
   173 		header->sections[i].type = i;
   174 		header->sections[i].offset = offset;
   175 		header->sections[i].size = a->size;
   176 		offset += (a->size + 4095) & ~4095;
   177 	}
   178 
   179 	header->sections[i].type = ~0;
   180 	header->sections[i].offset = 0;
   181 	header->sections[i].size = 0;
   182 
   183 	fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
   184 	if (fd < 0)
   185 		return -1;
   186 
   187 	write_to_fd(fd, data, sizeof data);
   188 	for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
   189 		if (razor_sections[i].type != i)
   190 			continue;
   191 		a = (void *) set + razor_sections[i].offset;
   192 		write_to_fd(fd, a->data, (a->size + 4095) & ~4095);
   193 	}
   194 
   195 	close(fd);
   196 
   197 	return 0;
   198 }
   199 
   200 static unsigned int
   201 hash_string(const char *key)
   202 {
   203 	const char *p;
   204 	unsigned int hash = 0;
   205 
   206 	for (p = key; *p; p++)
   207 		hash = (hash * 617) ^ *p;
   208 
   209 	return hash;
   210 }
   211 
   212 unsigned long
   213 razor_set_lookup(struct razor_set *set, const char *key)
   214 {
   215 	unsigned int mask, start, i;
   216 	unsigned long *b;
   217 	char *pool;
   218 
   219 	pool = set->string_pool.data;
   220 	mask = set->buckets.alloc - 1;
   221 	start = hash_string(key) * sizeof(unsigned long);
   222 
   223 	for (i = 0; i < set->buckets.alloc; i += sizeof *b) {
   224 		b = set->buckets.data + ((start + i) & mask);
   225 
   226 		if (*b == 0)
   227 			return 0;
   228 
   229 		if (strcmp(key, &pool[*b]) == 0)
   230 			return *b;
   231 	}
   232 
   233 	return 0;
   234 }
   235 
   236 static unsigned long
   237 add_to_string_pool(struct razor_set *set, const char *key)
   238 {
   239 	int len;
   240 	char *p;
   241 
   242 	len = strlen(key) + 1;
   243 	p = array_add(&set->string_pool, len);
   244 	memcpy(p, key, len);
   245 
   246 	return p - (char *) set->string_pool.data;
   247 }
   248 
   249 static unsigned long
   250 add_to_property_pool(struct razor_set *set, struct array *properties)
   251 {
   252 	unsigned long  *p;
   253 
   254 	p = array_add(properties, sizeof *p);
   255 	*p = ~0ul;
   256 	p = array_add(&set->property_pool, properties->size);
   257 	memcpy(p, properties->data, properties->size);
   258 
   259 	return p - (unsigned long *) set->property_pool.data;
   260 }
   261 
   262 static void
   263 do_insert(struct razor_set *set, unsigned long value)
   264 {
   265 	unsigned int mask, start, i;
   266 	unsigned long *b;
   267 	const char *key;
   268 
   269 	key = (char *) set->string_pool.data + value;
   270 	mask = set->buckets.alloc - 1;
   271 	start = hash_string(key) * sizeof(unsigned long);
   272 
   273 	for (i = 0; i < set->buckets.alloc; i += sizeof *b) {
   274 		b = set->buckets.data + ((start + i) & mask);
   275 		if (*b == 0) {
   276 			*b = value;
   277 			break;
   278 		}
   279 	}
   280 }
   281 
   282 unsigned long
   283 razor_set_insert(struct razor_set *set, const char *key)
   284 {
   285 	unsigned long value, *buckets, *b, *end;
   286 	int alloc;
   287 
   288 	alloc = set->buckets.alloc;
   289 	array_add(&set->buckets, 4 * sizeof *buckets);
   290 	if (alloc != set->buckets.alloc) {
   291 		end = set->buckets.data + alloc;
   292 		memset(end, 0, set->buckets.alloc - alloc);
   293 		for (b = set->buckets.data; b < end; b++) {
   294 			value = *b;
   295 			if (value != 0) {
   296 				*b = 0;
   297 				do_insert(set, value);
   298 			}
   299 		}
   300 	}
   301 
   302 	value = add_to_string_pool(set, key);
   303 	do_insert (set, value);
   304 
   305 	return value;
   306 }
   307 
   308 unsigned long
   309 razor_set_tokenize(struct razor_set *set, const char *string)
   310 {
   311 	unsigned long token;
   312 
   313 	if (string == NULL)
   314 		return razor_set_tokenize(set, "");
   315 
   316 	token = razor_set_lookup(set, string);
   317 	if (token != 0)
   318 		return token;
   319 
   320 	return razor_set_insert(set, string);
   321 }
   322 
   323 void
   324 import_context_add_package(struct import_context *ctx,
   325 			   const char *name, const char *version)
   326 {
   327 	struct razor_package *p;
   328 
   329 	p = array_add(&ctx->set->packages, sizeof *p);
   330 	p->name = razor_set_tokenize(ctx->set, name);
   331 	p->version = razor_set_tokenize(ctx->set, version);
   332 
   333 	ctx->package = p;
   334 	array_init(&ctx->requires.package);
   335 	array_init(&ctx->provides.package);
   336 }
   337 
   338 void
   339 import_context_finish_package(struct import_context *ctx)
   340 {
   341 	struct razor_package *p;
   342 
   343 	p = ctx->package;
   344 	p->requires = add_to_property_pool(ctx->set, &ctx->requires.package);
   345 	p->provides = add_to_property_pool(ctx->set, &ctx->provides.package);
   346 
   347 	array_release(&ctx->requires.package);
   348 	array_release(&ctx->provides.package);
   349 }
   350 
   351 void
   352 import_context_add_property(struct import_context *ctx,
   353 			    struct import_property_context *pctx,
   354 			    const char *name, const char *version)
   355 {
   356 	struct razor_property *p;
   357 	unsigned long *r;
   358 
   359 	p = array_add(pctx->all, sizeof *p);
   360 	p->name = razor_set_tokenize(ctx->set, name);
   361 	p->version = razor_set_tokenize(ctx->set, version);
   362 	p->packages = ctx->package -
   363 		(struct razor_package *) ctx->set->packages.data;
   364 
   365 	r = array_add(&pctx->package, sizeof *r);
   366 	*r = p - (struct razor_property *) pctx->all->data;
   367 }
   368 
   369 void
   370 razor_prepare_import(struct import_context *ctx)
   371 {
   372 	memset(ctx, 0, sizeof *ctx);
   373 	ctx->set = razor_set_create();
   374 	ctx->requires.all = &ctx->set->requires;
   375 	ctx->provides.all = &ctx->set->provides;
   376 }
   377 
   378 typedef int (*compare_with_data_func_t)(const void *p1,
   379 					const void *p,
   380 					void *data);
   381 
   382 struct qsort_context {
   383 	size_t size;
   384 	compare_with_data_func_t compare;
   385 	void *data;
   386 };
   387 
   388 static void
   389 qsort_swap(void *p1, void *p2, size_t size)
   390 {
   391 	char buffer[size];
   392 
   393 	memcpy(buffer, p1, size);
   394 	memcpy(p1, p2, size);
   395 	memcpy(p2, buffer, size);
   396 }
   397 
   398 static void
   399 __qsort_with_data(void *base, size_t nelem, unsigned long *map,
   400 		  struct qsort_context *ctx)
   401 {
   402 	void *p, *start, *end, *pivot;
   403 	unsigned long *mp, *mstart, *mend, tmp;
   404 	int left, right, result;
   405 	size_t size = ctx->size;
   406 
   407 	p = base;
   408 	start = base;
   409 	end = base + nelem * size;
   410 	mp = map;
   411 	mstart = map;
   412 	mend = map + nelem;
   413 	pivot = base + (random() % nelem) * size;
   414 
   415 	while (p < end) {
   416 		result = ctx->compare(p, pivot, ctx->data);
   417 		if (result < 0) {
   418 			qsort_swap(p, start, size);
   419 			tmp = *mp;
   420 			*mp = *mstart;
   421 			*mstart = tmp;
   422 			if (start == pivot)
   423 				pivot = p;
   424 			start += size;
   425 			mstart++;
   426 			p += size;
   427 		} else if (result == 0) {
   428 			p += size;
   429 			mp++;
   430 		} else {
   431  			end -= size;
   432 			mend--;
   433 			qsort_swap(p, end, size);
   434 			tmp = *mp;
   435 			*mp = *mstart;
   436 			*mstart = tmp;
   437 			if (end == pivot)
   438 				pivot = p;
   439 		}
   440 	}
   441 
   442 	left = (start - base) / size;
   443 	right = (base + nelem * size - end) / size;
   444 	if (left > 1)
   445 		__qsort_with_data(base, left, map, ctx);
   446 	if (right > 1)
   447 		__qsort_with_data(end, right, mend, ctx);
   448 }
   449 
   450 unsigned long *
   451 qsort_with_data(void *base, size_t nelem, size_t size,
   452 		compare_with_data_func_t compare, void *data)
   453 {
   454 	struct qsort_context ctx;
   455 	unsigned long *map;
   456 	int i;
   457 
   458 	ctx.size = size;
   459 	ctx.compare = compare;
   460 	ctx.data = data;
   461 
   462 	map = malloc(nelem * sizeof (unsigned long));
   463 	for (i = 0; i < nelem; i++)
   464 		map[i] = i;
   465 
   466 	__qsort_with_data(base, nelem, map, &ctx);
   467 
   468 	return map;
   469 }
   470 
   471 static int
   472 compare_packages(const void *p1, const void *p2, void *data)
   473 {
   474 	const struct razor_package *pkg1 = p1, *pkg2 = p2;
   475 	struct razor_set *set = data;
   476 	char *pool = set->string_pool.data;
   477 
   478 	if (pkg1->name == pkg2->name)
   479 		return 0;
   480 	else
   481 		return strcmp(&pool[pkg1->name], &pool[pkg2->name]);
   482 }
   483 
   484 static int
   485 compare_properties(const void *p1, const void *p2, void *data)
   486 {
   487 	const struct razor_property *prop1 = p1, *prop2 = p2;
   488 	struct razor_set *set = data;
   489 	char *pool = set->string_pool.data;
   490 
   491 	if (prop1->name == prop2->name)
   492 		return strcmp(&pool[prop1->version], &pool[prop2->version]);
   493 	else
   494 		return strcmp(&pool[prop1->name], &pool[prop2->name]);
   495 }
   496 
   497 static unsigned long *
   498 uniqueify_properties(struct razor_set *set, struct array *properties)
   499 {
   500 	struct razor_property *rp, *up, *rp_end;
   501 	struct array *pkgs, *p;
   502 	unsigned long *map, *rmap, *r;
   503 	int i, count, unique;
   504 
   505 	count = properties->size / sizeof(struct razor_property);
   506 	map = qsort_with_data(properties->data,
   507 			      count,
   508 			      sizeof(struct razor_property),
   509 			      compare_properties,
   510 			      set);
   511 
   512 	rp_end = properties->data + properties->size;
   513 	rmap = malloc(count * sizeof *map);
   514 	pkgs = zalloc(count * sizeof *pkgs);
   515 	for (rp = properties->data, up = rp, i = 0; rp < rp_end; rp++, i++) {
   516 		if (rp->name != up->name || rp->version != up->version) {
   517 			up++;
   518 			up->name = rp->name;
   519 			up->version = rp->version;
   520 		}
   521 
   522 		unique = up - (struct razor_property *) properties->data;
   523 		rmap[map[i]] = unique;
   524 		r = array_add(&pkgs[unique], sizeof *r);
   525 		*r = rp->packages;
   526 	}
   527 	free(map);
   528 
   529 	up++;
   530 	properties->size = (void *) up - properties->data;
   531 	rp_end = up;
   532 	for (rp = properties->data, p = pkgs; rp < rp_end; rp++, p++) {
   533 		rp->packages = add_to_property_pool(set, p);
   534 		array_release(p);
   535 	}
   536 
   537 	free(pkgs);
   538 
   539 	return rmap;
   540 }
   541 
   542 static void
   543 remap_package_links(struct import_context *ctx)
   544 {
   545 	struct razor_package *p, *end;
   546 	unsigned long *pool, *r;
   547 
   548 	pool = ctx->set->property_pool.data;
   549 	end = ctx->set->packages.data + ctx->set->packages.size;
   550 	for (p = ctx->set->packages.data; p < end; p++) {
   551 		for (r = &pool[p->requires]; ~*r; r++)
   552 			*r = ctx->requires_map[*r];
   553 		for (r = &pool[p->provides]; ~*r; r++)
   554 			*r = ctx->provides_map[*r];
   555 	}
   556 }
   557 
   558 static void
   559 remap_property_links(struct import_context *ctx, unsigned long *map)
   560 {
   561 	struct razor_property *p, *end;
   562 	struct razor_package *rp;
   563 	unsigned long *pool, *r, *rmap;
   564 	int i, count;
   565 
   566 	pool = ctx->set->property_pool.data;
   567 	count = ctx->set->packages.size / sizeof(struct razor_package);
   568 	rmap = malloc(count * sizeof *map);
   569 	rp = ctx->set->packages.data;
   570 	for (i = 0; i < count; i++)
   571 		rmap[map[i]] = i;
   572 
   573 	/* FIXME: This will break if we implement package list sharing
   574 	 * for all properties, since we'll remap those lists more than
   575 	 * once. We should just have a separate pool for property
   576 	 * lists and a separate pool for package lists and remap it as
   577 	 * a flat pool.  Right now, as property lists and package
   578 	 * lists are mixed, we can't do that. */
   579 
   580 	end = ctx->set->requires.data + ctx->set->requires.size;
   581 	for (p = ctx->set->requires.data; p < end; p++)
   582 		for (r = &pool[p->packages]; ~*r; r++)
   583 			*r = rmap[*r];
   584 
   585 	end = ctx->set->provides.data + ctx->set->provides.size;
   586 	for (p = ctx->set->provides.data; p < end; p++)
   587 		for (r = &pool[p->packages]; ~*r; r++)
   588 			*r = rmap[*r];
   589 
   590 	free(rmap);
   591 }
   592 
   593 struct razor_set *
   594 razor_finish_import(struct import_context *ctx)
   595 {
   596 	unsigned long *map;
   597 	int count;
   598 
   599 	ctx->requires_map = uniqueify_properties(ctx->set, ctx->requires.all);
   600 	ctx->provides_map = uniqueify_properties(ctx->set, ctx->provides.all);
   601 	remap_package_links(ctx);
   602 	free(ctx->requires_map);
   603 	free(ctx->provides_map);
   604 
   605 	count = ctx->set->packages.size / sizeof(struct razor_package);
   606 	map = qsort_with_data(ctx->set->packages.data,
   607 			      count,
   608 			      sizeof(struct razor_package),
   609 			      compare_packages,
   610 			      ctx->set);
   611 	remap_property_links(ctx, map);
   612 	free(map);
   613 
   614 	return ctx->set; 
   615 }
   616 
   617 void
   618 razor_set_list(struct razor_set *set)
   619 {
   620 	struct razor_package *p, *end;
   621 	char *pool;
   622 
   623 	pool = set->string_pool.data;
   624 	end = set->packages.data + set->packages.size;
   625 	for (p = set->packages.data; p < end; p++)
   626 		printf("%s %s\n", &pool[p->name], &pool[p->version]);
   627 }
   628 
   629 struct razor_set *bsearch_set;
   630 
   631 static int
   632 compare_package_name(const void *key, const void *data)
   633 {
   634 	const struct razor_package *p = data;
   635 	char *pool;
   636 
   637 	pool = bsearch_set->string_pool.data;
   638 
   639 	return strcmp(key, &pool[p->name]);
   640 }
   641 
   642 struct razor_package *
   643 razor_set_get_package(struct razor_set *set, const char *package)
   644 {
   645 	bsearch_set = set;
   646 	return bsearch(package, set->packages.data,
   647 		       set->packages.size / sizeof(struct razor_package),
   648 		       sizeof(struct razor_package), compare_package_name);
   649 }
   650 
   651 static int
   652 compare_property_name(const void *key, const void *data)
   653 {
   654 	const struct razor_property *p = data;
   655 	char *pool;
   656 
   657 	pool = bsearch_set->string_pool.data;
   658 
   659 	return strcmp(key, &pool[p->name]);
   660 }
   661 
   662 struct razor_property *
   663 razor_set_get_property(struct razor_set *set,
   664 		       struct array *properties,
   665 		       const char *property)
   666 {
   667 	struct razor_property *p, *start;
   668 
   669 	bsearch_set = set;
   670 	p = bsearch(property, properties->data,
   671 		    properties->size / sizeof(struct razor_property),
   672 		    sizeof(struct razor_property), compare_property_name);
   673 
   674 	start = properties->data;
   675 	while (p > start && (p - 1)->name == p->name)
   676 		p--;
   677 
   678 	return p;
   679 }
   680 
   681 static void
   682 razor_set_list_all_properties(struct razor_set *set, struct array *properties)
   683 {
   684 	struct razor_property *p, *end;
   685 	char *pool;
   686 
   687 	pool = set->string_pool.data;
   688 	end = properties->data + properties->size;
   689 	for (p = properties->data; p < end; p++)
   690 		printf("%s %s\n", &pool[p->name], &pool[p->version]);
   691 }
   692 
   693 void
   694 razor_set_list_requires(struct razor_set *set, const char *name)
   695 {
   696 	struct razor_property *p, *requires;
   697 	struct razor_package *package;
   698 	unsigned long *r;
   699 	char *pool;
   700 
   701 	if (name) {
   702 		package = razor_set_get_package(set, name);
   703 		r = (unsigned long *) set->property_pool.data +
   704 			package->requires;
   705 		requires = set->requires.data;
   706 		pool = set->string_pool.data;
   707 		while (~*r) {
   708 			p = &requires[*r++];
   709 			printf("%s %s\n", &pool[p->name], &pool[p->version]);
   710 		}
   711 	} else
   712 		razor_set_list_all_properties(set, &set->requires);
   713 }
   714 
   715 void
   716 razor_set_list_provides(struct razor_set *set, const char *name)
   717 {
   718 	struct razor_property *p, *provides;
   719 	struct razor_package *package;
   720 	unsigned long *r;
   721 	char *pool;
   722 
   723 	if (name) {
   724 		package = razor_set_get_package(set, name);
   725 		r = (unsigned long *) set->property_pool.data +
   726 			package->provides;
   727 		provides = set->provides.data;
   728 		pool = set->string_pool.data;
   729 		while (~*r) {
   730 			p = &provides[*r++];
   731 			printf("%s %s\n", &pool[p->name], &pool[p->version]);
   732 		}
   733 	} else 
   734 		razor_set_list_all_properties(set, &set->provides);
   735 }
   736 
   737 void
   738 razor_set_list_property_packages(struct razor_set *set,
   739 				 struct array *properties,
   740 				 const char *name,
   741 				 const char *version)
   742 {
   743 	struct razor_property *property, *end;
   744 	struct razor_package *p, *packages;
   745 	unsigned long *r;
   746 	char *pool;
   747 
   748 	if (name == NULL)
   749 		return;
   750 
   751 	property = razor_set_get_property(set, properties, name);
   752 	packages = set->packages.data;
   753 	pool = set->string_pool.data;
   754 	end = properties->data + properties->size;
   755 	while (property < end && strcmp(name, &pool[property->name]) == 0) {
   756 		if (version && strcmp(version, &pool[property->version]) != 0)
   757 			goto next;
   758 		r = (unsigned long *)
   759 			set->property_pool.data + property->packages;
   760 		while (~*r) {
   761 			p = &packages[*r++];
   762 			printf("%s %s\n",
   763 			       &pool[p->name], &pool[p->version]);
   764 		}
   765 	next:
   766 		property++;
   767 	}
   768 }
   769 
   770 void
   771 razor_set_validate(struct razor_set *set, struct array *unsatisfied)
   772 {
   773 	struct razor_property *r, *p, *rend, *pend;
   774 	unsigned long *u;
   775 	char *pool;
   776 
   777 	r = set->requires.data;
   778 	p = set->provides.data;
   779 	rend = set->requires.data + set->requires.size;
   780 	pend = set->provides.data + set->provides.size;
   781 	pool = set->string_pool.data;
   782 	
   783 	while (r < rend) {
   784 		while (p < pend && strcmp(&pool[r->name], &pool[p->name]) > 0)
   785 			p++;
   786 		if (p == pend || strcmp(&pool[r->name], &pool[p->name]) != 0) {
   787 			u = array_add(unsatisfied, sizeof *u);
   788 			*u = r - (struct razor_property *) set->requires.data;
   789 		}
   790 		r++;
   791 	}
   792 }
   793 
   794 void
   795 razor_set_list_unsatisfied(struct razor_set *set)
   796 {
   797 	struct array unsatisfied;
   798 	struct razor_property *requires, *r;
   799 	unsigned long *u, *end;
   800 	char *pool;
   801 
   802 	array_init(&unsatisfied);
   803 	razor_set_validate(set, &unsatisfied);
   804 
   805 	end = unsatisfied.data + unsatisfied.size;
   806 	requires = set->requires.data;
   807 	pool = set->string_pool.data;
   808 
   809 	for (u = unsatisfied.data; u < end; u++) {
   810 		r = requires + *u;
   811 		printf("%s %s not satisfied\n",
   812 		       &pool[r->name], &pool[r->version]);
   813 	}
   814 
   815 	array_release(&unsatisfied);
   816 }
   817 
   818 void
   819 razor_set_info(struct razor_set *set)
   820 {
   821 	unsigned int offset, size;
   822 	int i;
   823 
   824 	for (i = 0; i < set->header->sections[i].type; i++) {
   825 		offset = set->header->sections[i].offset;
   826 		size = set->header->sections[i].size;
   827 
   828 		switch (set->header->sections[i].type) {
   829 		case RAZOR_PACKAGES:
   830 			printf("package section:\t%dkb\n", size / 1024);
   831 			break;
   832 		case RAZOR_REQUIRES:
   833 			printf("requires section:\t%dkb\n", size / 1024);
   834 			break;
   835 		case RAZOR_PROVIDES:
   836 			printf("provides section:\t%dkb\n", size / 1024);
   837 			break;
   838 		case RAZOR_STRING_POOL:
   839 			printf("string pool:\t\t%dkb\n", size / 1024);
   840 			break;
   841 		case RAZOR_PROPERTY_POOL:
   842 			printf("properties section:\t%dkb\n", size / 1024);
   843 			break;
   844 		}
   845 	}
   846 }
   847 
   848 static int
   849 usage(void)
   850 {
   851 	printf("usage: razor [ import FILES | lookup <key> | "
   852 	       "list | list-requires | list-provides | eat-yum | info ]\n");
   853 	exit(1);
   854 }
   855 
   856 static const char *repo_filename = "system.repo";
   857 static const char rawhide_repo_filename[] = "rawhide.repo";
   858 
   859 int
   860 main(int argc, const char *argv[])
   861 {
   862 	struct razor_set *set;
   863 	struct stat statbuf;
   864 	char *repo;
   865 
   866 	repo = getenv("RAZOR_REPO");
   867 	if (repo != NULL)
   868 		repo_filename = repo;
   869 
   870 	if (argc < 2) {
   871 		usage();
   872 	} else if (strcmp(argv[1], "import") == 0) {
   873 		if (stat("set", &statbuf) && mkdir("set", 0777)) {
   874 			fprintf(stderr, "could not create directory 'set'\n");
   875 			exit(-1);
   876 		}
   877 			
   878 		set = razor_import_rzr_files(argc - 2, argv + 2);
   879 
   880 		printf("bucket allocation: %d\n", set->buckets.alloc);
   881 		printf("pool size: %d\n", set->string_pool.size);
   882 		printf("pool allocation: %d\n", set->string_pool.alloc);
   883 		printf("packages: %d\n",
   884 		       set->packages.size / sizeof(struct razor_package));
   885 		printf("requires: %d\n",
   886 		       set->requires.size / sizeof(struct razor_property));
   887 		printf("provides: %d\n",
   888 		       set->provides.size / sizeof(struct razor_property));
   889 
   890 		razor_set_write(set, repo_filename);
   891 
   892 		razor_set_destroy(set);
   893 	} else if (strcmp(argv[1], "lookup") == 0) {
   894 		set = razor_set_open(repo_filename);
   895 		printf("%s is %lu\n", argv[2],
   896 		       razor_set_lookup(set, argv[2]));
   897 		razor_set_destroy(set);
   898 	} else if (strcmp(argv[1], "list") == 0) {
   899 		set = razor_set_open(repo_filename);
   900 		razor_set_list(set);
   901 		razor_set_destroy(set);
   902 	} else if (strcmp(argv[1], "list-requires") == 0) {
   903 		set = razor_set_open(repo_filename);
   904 		razor_set_list_requires(set, argv[2]);
   905 		razor_set_destroy(set);
   906 	} else if (strcmp(argv[1], "list-provides") == 0) {
   907 		set = razor_set_open(repo_filename);
   908 		razor_set_list_provides(set, argv[2]);
   909 		razor_set_destroy(set);
   910 	} else if (strcmp(argv[1], "what-requires") == 0) {
   911 		set = razor_set_open(repo_filename);
   912 		razor_set_list_property_packages(set, &set->requires,
   913 						 argv[2], argv[3]);
   914 		razor_set_destroy(set);
   915 	} else if (strcmp(argv[1], "what-provides") == 0) {
   916 		set = razor_set_open(repo_filename);
   917 		razor_set_list_property_packages(set, &set->provides,
   918 						 argv[2], argv[3]);
   919 		razor_set_destroy(set);
   920 	} else if (strcmp(argv[1], "info") == 0) {
   921 		set = razor_set_open(repo_filename);
   922 		razor_set_info(set);
   923 		razor_set_destroy(set);
   924 	} else if (strcmp(argv[1], "eat-yum") == 0) {
   925 		set = razor_set_create_from_yum_filelist(STDIN_FILENO);
   926 		if (set == NULL)
   927 			return 1;
   928 		razor_set_write(set, rawhide_repo_filename);
   929 		razor_set_destroy(set);
   930 		printf("wrote %s\n", rawhide_repo_filename);
   931 	} else if (strcmp(argv[1], "import-rpmdb") == 0) {
   932 		set = razor_set_create_from_rpmdb();
   933 		if (set == NULL)
   934 			return 1;
   935 		razor_set_write(set, repo_filename);
   936 		razor_set_destroy(set);
   937 		printf("wrote %s\n", repo_filename);
   938 	} else if (strcmp(argv[1], "validate") == 0) {
   939 		set = razor_set_open(repo_filename);
   940 		if (set == NULL)
   941 			return 1;
   942 		razor_set_list_unsatisfied(set);
   943 		razor_set_destroy(set);
   944 	} else {
   945 		usage();
   946 	}
   947 
   948 	return 0;
   949 }