razor.c
author Kristian H?gsberg <krh@redhat.com>
Wed Sep 19 14:34:11 2007 -0400 (2007-09-19)
changeset 29 28a13008d80b
parent 28 c8958f67afd8
child 30 702c01e59497
permissions -rw-r--r--
Fix swapping of map entries in __qsort_with_data.
     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 			mp++;
   428 		} else if (result == 0) {
   429 			p += size;
   430 			mp++;
   431 		} else {
   432  			end -= size;
   433 			mend--;
   434 			qsort_swap(p, end, size);
   435 			tmp = *mp;
   436 			*mp = *mend;
   437 			*mend = tmp;
   438 			if (end == pivot)
   439 				pivot = p;
   440 		}
   441 	}
   442 
   443 	left = (start - base) / size;
   444 	right = (base + nelem * size - end) / size;
   445 	if (left > 1)
   446 		__qsort_with_data(base, left, map, ctx);
   447 	if (right > 1)
   448 		__qsort_with_data(end, right, mend, ctx);
   449 }
   450 
   451 unsigned long *
   452 qsort_with_data(void *base, size_t nelem, size_t size,
   453 		compare_with_data_func_t compare, void *data)
   454 {
   455 	struct qsort_context ctx;
   456 	unsigned long *map;
   457 	int i;
   458 
   459 	ctx.size = size;
   460 	ctx.compare = compare;
   461 	ctx.data = data;
   462 
   463 	map = malloc(nelem * sizeof (unsigned long));
   464 	for (i = 0; i < nelem; i++)
   465 		map[i] = i;
   466 
   467 	__qsort_with_data(base, nelem, map, &ctx);
   468 
   469 	return map;
   470 }
   471 
   472 static int
   473 compare_packages(const void *p1, const void *p2, void *data)
   474 {
   475 	const struct razor_package *pkg1 = p1, *pkg2 = p2;
   476 	struct razor_set *set = data;
   477 	char *pool = set->string_pool.data;
   478 
   479 	if (pkg1->name == pkg2->name)
   480 		return 0;
   481 	else
   482 		return strcmp(&pool[pkg1->name], &pool[pkg2->name]);
   483 }
   484 
   485 static int
   486 compare_properties(const void *p1, const void *p2, void *data)
   487 {
   488 	const struct razor_property *prop1 = p1, *prop2 = p2;
   489 	struct razor_set *set = data;
   490 	char *pool = set->string_pool.data;
   491 
   492 	if (prop1->name == prop2->name)
   493 		return strcmp(&pool[prop1->version], &pool[prop2->version]);
   494 	else
   495 		return strcmp(&pool[prop1->name], &pool[prop2->name]);
   496 }
   497 
   498 static unsigned long *
   499 uniqueify_properties(struct razor_set *set, struct array *properties)
   500 {
   501 	struct razor_property *rp, *up, *rp_end;
   502 	struct array *pkgs, *p;
   503 	unsigned long *map, *rmap, *r;
   504 	int i, count, unique;
   505 
   506 	count = properties->size / sizeof(struct razor_property);
   507 	map = qsort_with_data(properties->data,
   508 			      count,
   509 			      sizeof(struct razor_property),
   510 			      compare_properties,
   511 			      set);
   512 
   513 	rp_end = properties->data + properties->size;
   514 	rmap = malloc(count * sizeof *map);
   515 	pkgs = zalloc(count * sizeof *pkgs);
   516 	for (rp = properties->data, up = rp, i = 0; rp < rp_end; rp++, i++) {
   517 		if (rp->name != up->name || rp->version != up->version) {
   518 			up++;
   519 			up->name = rp->name;
   520 			up->version = rp->version;
   521 		}
   522 
   523 		unique = up - (struct razor_property *) properties->data;
   524 		rmap[map[i]] = unique;
   525 		r = array_add(&pkgs[unique], sizeof *r);
   526 		*r = rp->packages;
   527 	}
   528 	free(map);
   529 
   530 	up++;
   531 	properties->size = (void *) up - properties->data;
   532 	rp_end = up;
   533 	for (rp = properties->data, p = pkgs; rp < rp_end; rp++, p++) {
   534 		rp->packages = add_to_property_pool(set, p);
   535 		array_release(p);
   536 	}
   537 
   538 	free(pkgs);
   539 
   540 	return rmap;
   541 }
   542 
   543 static void
   544 remap_package_links(struct import_context *ctx)
   545 {
   546 	struct razor_package *p, *end;
   547 	unsigned long *pool, *r;
   548 
   549 	pool = ctx->set->property_pool.data;
   550 	end = ctx->set->packages.data + ctx->set->packages.size;
   551 	for (p = ctx->set->packages.data; p < end; p++) {
   552 		for (r = &pool[p->requires]; ~*r; r++)
   553 			*r = ctx->requires_map[*r];
   554 		for (r = &pool[p->provides]; ~*r; r++)
   555 			*r = ctx->provides_map[*r];
   556 	}
   557 }
   558 
   559 static void
   560 remap_property_links(struct import_context *ctx, unsigned long *map)
   561 {
   562 	struct razor_property *p, *end;
   563 	struct razor_package *rp;
   564 	unsigned long *pool, *r, *rmap;
   565 	int i, count;
   566 
   567 	pool = ctx->set->property_pool.data;
   568 	count = ctx->set->packages.size / sizeof(struct razor_package);
   569 	rmap = malloc(count * sizeof *map);
   570 	rp = ctx->set->packages.data;
   571 	for (i = 0; i < count; i++)
   572 		rmap[map[i]] = i;
   573 
   574 	/* FIXME: This will break if we implement package list sharing
   575 	 * for all properties, since we'll remap those lists more than
   576 	 * once. We should just have a separate pool for property
   577 	 * lists and a separate pool for package lists and remap it as
   578 	 * a flat pool.  Right now, as property lists and package
   579 	 * lists are mixed, we can't do that. */
   580 
   581 	end = ctx->set->requires.data + ctx->set->requires.size;
   582 	for (p = ctx->set->requires.data; p < end; p++)
   583 		for (r = &pool[p->packages]; ~*r; r++)
   584 			*r = rmap[*r];
   585 
   586 	end = ctx->set->provides.data + ctx->set->provides.size;
   587 	for (p = ctx->set->provides.data; p < end; p++)
   588 		for (r = &pool[p->packages]; ~*r; r++)
   589 			*r = rmap[*r];
   590 
   591 	free(rmap);
   592 }
   593 
   594 struct razor_set *
   595 razor_finish_import(struct import_context *ctx)
   596 {
   597 	unsigned long *map;
   598 	int count;
   599 
   600 	ctx->requires_map = uniqueify_properties(ctx->set, ctx->requires.all);
   601 	ctx->provides_map = uniqueify_properties(ctx->set, ctx->provides.all);
   602 	remap_package_links(ctx);
   603 	free(ctx->requires_map);
   604 	free(ctx->provides_map);
   605 
   606 	count = ctx->set->packages.size / sizeof(struct razor_package);
   607 	map = qsort_with_data(ctx->set->packages.data,
   608 			      count,
   609 			      sizeof(struct razor_package),
   610 			      compare_packages,
   611 			      ctx->set);
   612 	remap_property_links(ctx, map);
   613 	free(map);
   614 
   615 	return ctx->set; 
   616 }
   617 
   618 void
   619 razor_set_list(struct razor_set *set)
   620 {
   621 	struct razor_package *p, *end;
   622 	char *pool;
   623 
   624 	pool = set->string_pool.data;
   625 	end = set->packages.data + set->packages.size;
   626 	for (p = set->packages.data; p < end; p++)
   627 		printf("%s %s\n", &pool[p->name], &pool[p->version]);
   628 }
   629 
   630 struct razor_set *bsearch_set;
   631 
   632 static int
   633 compare_package_name(const void *key, const void *data)
   634 {
   635 	const struct razor_package *p = data;
   636 	char *pool;
   637 
   638 	pool = bsearch_set->string_pool.data;
   639 
   640 	return strcmp(key, &pool[p->name]);
   641 }
   642 
   643 struct razor_package *
   644 razor_set_get_package(struct razor_set *set, const char *package)
   645 {
   646 	bsearch_set = set;
   647 	return bsearch(package, set->packages.data,
   648 		       set->packages.size / sizeof(struct razor_package),
   649 		       sizeof(struct razor_package), compare_package_name);
   650 }
   651 
   652 static int
   653 compare_property_name(const void *key, const void *data)
   654 {
   655 	const struct razor_property *p = data;
   656 	char *pool;
   657 
   658 	pool = bsearch_set->string_pool.data;
   659 
   660 	return strcmp(key, &pool[p->name]);
   661 }
   662 
   663 struct razor_property *
   664 razor_set_get_property(struct razor_set *set,
   665 		       struct array *properties,
   666 		       const char *property)
   667 {
   668 	struct razor_property *p, *start;
   669 
   670 	bsearch_set = set;
   671 	p = bsearch(property, properties->data,
   672 		    properties->size / sizeof(struct razor_property),
   673 		    sizeof(struct razor_property), compare_property_name);
   674 
   675 	start = properties->data;
   676 	while (p > start && (p - 1)->name == p->name)
   677 		p--;
   678 
   679 	return p;
   680 }
   681 
   682 static void
   683 razor_set_list_all_properties(struct razor_set *set, struct array *properties)
   684 {
   685 	struct razor_property *p, *end;
   686 	char *pool;
   687 
   688 	pool = set->string_pool.data;
   689 	end = properties->data + properties->size;
   690 	for (p = properties->data; p < end; p++)
   691 		printf("%s %s\n", &pool[p->name], &pool[p->version]);
   692 }
   693 
   694 void
   695 razor_set_list_requires(struct razor_set *set, const char *name)
   696 {
   697 	struct razor_property *p, *requires;
   698 	struct razor_package *package;
   699 	unsigned long *r;
   700 	char *pool;
   701 
   702 	if (name) {
   703 		package = razor_set_get_package(set, name);
   704 		r = (unsigned long *) set->property_pool.data +
   705 			package->requires;
   706 		requires = set->requires.data;
   707 		pool = set->string_pool.data;
   708 		while (~*r) {
   709 			p = &requires[*r++];
   710 			printf("%s %s\n", &pool[p->name], &pool[p->version]);
   711 		}
   712 	} else
   713 		razor_set_list_all_properties(set, &set->requires);
   714 }
   715 
   716 void
   717 razor_set_list_provides(struct razor_set *set, const char *name)
   718 {
   719 	struct razor_property *p, *provides;
   720 	struct razor_package *package;
   721 	unsigned long *r;
   722 	char *pool;
   723 
   724 	if (name) {
   725 		package = razor_set_get_package(set, name);
   726 		r = (unsigned long *) set->property_pool.data +
   727 			package->provides;
   728 		provides = set->provides.data;
   729 		pool = set->string_pool.data;
   730 		while (~*r) {
   731 			p = &provides[*r++];
   732 			printf("%s %s\n", &pool[p->name], &pool[p->version]);
   733 		}
   734 	} else 
   735 		razor_set_list_all_properties(set, &set->provides);
   736 }
   737 
   738 void
   739 razor_set_list_property_packages(struct razor_set *set,
   740 				 struct array *properties,
   741 				 const char *name,
   742 				 const char *version)
   743 {
   744 	struct razor_property *property, *end;
   745 	struct razor_package *p, *packages;
   746 	unsigned long *r;
   747 	char *pool;
   748 
   749 	if (name == NULL)
   750 		return;
   751 
   752 	property = razor_set_get_property(set, properties, name);
   753 	packages = set->packages.data;
   754 	pool = set->string_pool.data;
   755 	end = properties->data + properties->size;
   756 	while (property < end && strcmp(name, &pool[property->name]) == 0) {
   757 		if (version && strcmp(version, &pool[property->version]) != 0)
   758 			goto next;
   759 		r = (unsigned long *)
   760 			set->property_pool.data + property->packages;
   761 		while (~*r) {
   762 			p = &packages[*r++];
   763 			printf("%s %s\n",
   764 			       &pool[p->name], &pool[p->version]);
   765 		}
   766 	next:
   767 		property++;
   768 	}
   769 }
   770 
   771 void
   772 razor_set_validate(struct razor_set *set, struct array *unsatisfied)
   773 {
   774 	struct razor_property *r, *p, *rend, *pend;
   775 	unsigned long *u;
   776 	char *pool;
   777 
   778 	r = set->requires.data;
   779 	p = set->provides.data;
   780 	rend = set->requires.data + set->requires.size;
   781 	pend = set->provides.data + set->provides.size;
   782 	pool = set->string_pool.data;
   783 	
   784 	while (r < rend) {
   785 		while (p < pend && strcmp(&pool[r->name], &pool[p->name]) > 0)
   786 			p++;
   787 		if (p == pend || strcmp(&pool[r->name], &pool[p->name]) != 0) {
   788 			u = array_add(unsatisfied, sizeof *u);
   789 			*u = r - (struct razor_property *) set->requires.data;
   790 		}
   791 		r++;
   792 	}
   793 }
   794 
   795 void
   796 razor_set_list_unsatisfied(struct razor_set *set)
   797 {
   798 	struct array unsatisfied;
   799 	struct razor_property *requires, *r;
   800 	unsigned long *u, *end;
   801 	char *pool;
   802 
   803 	array_init(&unsatisfied);
   804 	razor_set_validate(set, &unsatisfied);
   805 
   806 	end = unsatisfied.data + unsatisfied.size;
   807 	requires = set->requires.data;
   808 	pool = set->string_pool.data;
   809 
   810 	for (u = unsatisfied.data; u < end; u++) {
   811 		r = requires + *u;
   812 		printf("%s %s not satisfied\n",
   813 		       &pool[r->name], &pool[r->version]);
   814 	}
   815 
   816 	array_release(&unsatisfied);
   817 }
   818 
   819 void
   820 razor_set_info(struct razor_set *set)
   821 {
   822 	unsigned int offset, size;
   823 	int i;
   824 
   825 	for (i = 0; i < set->header->sections[i].type; i++) {
   826 		offset = set->header->sections[i].offset;
   827 		size = set->header->sections[i].size;
   828 
   829 		switch (set->header->sections[i].type) {
   830 		case RAZOR_PACKAGES:
   831 			printf("package section:\t%dkb\n", size / 1024);
   832 			break;
   833 		case RAZOR_REQUIRES:
   834 			printf("requires section:\t%dkb\n", size / 1024);
   835 			break;
   836 		case RAZOR_PROVIDES:
   837 			printf("provides section:\t%dkb\n", size / 1024);
   838 			break;
   839 		case RAZOR_STRING_POOL:
   840 			printf("string pool:\t\t%dkb\n", size / 1024);
   841 			break;
   842 		case RAZOR_PROPERTY_POOL:
   843 			printf("properties section:\t%dkb\n", size / 1024);
   844 			break;
   845 		}
   846 	}
   847 }
   848 
   849 static int
   850 usage(void)
   851 {
   852 	printf("usage: razor [ import FILES | lookup <key> | "
   853 	       "list | list-requires | list-provides | eat-yum | info ]\n");
   854 	exit(1);
   855 }
   856 
   857 static const char *repo_filename = "system.repo";
   858 static const char rawhide_repo_filename[] = "rawhide.repo";
   859 
   860 int
   861 main(int argc, const char *argv[])
   862 {
   863 	struct razor_set *set;
   864 	struct stat statbuf;
   865 	char *repo;
   866 
   867 	repo = getenv("RAZOR_REPO");
   868 	if (repo != NULL)
   869 		repo_filename = repo;
   870 
   871 	if (argc < 2) {
   872 		usage();
   873 	} else if (strcmp(argv[1], "import") == 0) {
   874 		if (stat("set", &statbuf) && mkdir("set", 0777)) {
   875 			fprintf(stderr, "could not create directory 'set'\n");
   876 			exit(-1);
   877 		}
   878 			
   879 		set = razor_import_rzr_files(argc - 2, argv + 2);
   880 
   881 		printf("bucket allocation: %d\n", set->buckets.alloc);
   882 		printf("pool size: %d\n", set->string_pool.size);
   883 		printf("pool allocation: %d\n", set->string_pool.alloc);
   884 		printf("packages: %d\n",
   885 		       set->packages.size / sizeof(struct razor_package));
   886 		printf("requires: %d\n",
   887 		       set->requires.size / sizeof(struct razor_property));
   888 		printf("provides: %d\n",
   889 		       set->provides.size / sizeof(struct razor_property));
   890 
   891 		razor_set_write(set, repo_filename);
   892 
   893 		razor_set_destroy(set);
   894 	} else if (strcmp(argv[1], "lookup") == 0) {
   895 		set = razor_set_open(repo_filename);
   896 		printf("%s is %lu\n", argv[2],
   897 		       razor_set_lookup(set, argv[2]));
   898 		razor_set_destroy(set);
   899 	} else if (strcmp(argv[1], "list") == 0) {
   900 		set = razor_set_open(repo_filename);
   901 		razor_set_list(set);
   902 		razor_set_destroy(set);
   903 	} else if (strcmp(argv[1], "list-requires") == 0) {
   904 		set = razor_set_open(repo_filename);
   905 		razor_set_list_requires(set, argv[2]);
   906 		razor_set_destroy(set);
   907 	} else if (strcmp(argv[1], "list-provides") == 0) {
   908 		set = razor_set_open(repo_filename);
   909 		razor_set_list_provides(set, argv[2]);
   910 		razor_set_destroy(set);
   911 	} else if (strcmp(argv[1], "what-requires") == 0) {
   912 		set = razor_set_open(repo_filename);
   913 		razor_set_list_property_packages(set, &set->requires,
   914 						 argv[2], argv[3]);
   915 		razor_set_destroy(set);
   916 	} else if (strcmp(argv[1], "what-provides") == 0) {
   917 		set = razor_set_open(repo_filename);
   918 		razor_set_list_property_packages(set, &set->provides,
   919 						 argv[2], argv[3]);
   920 		razor_set_destroy(set);
   921 	} else if (strcmp(argv[1], "info") == 0) {
   922 		set = razor_set_open(repo_filename);
   923 		razor_set_info(set);
   924 		razor_set_destroy(set);
   925 	} else if (strcmp(argv[1], "eat-yum") == 0) {
   926 		set = razor_set_create_from_yum_filelist(STDIN_FILENO);
   927 		if (set == NULL)
   928 			return 1;
   929 		razor_set_write(set, rawhide_repo_filename);
   930 		razor_set_destroy(set);
   931 		printf("wrote %s\n", rawhide_repo_filename);
   932 	} else if (strcmp(argv[1], "import-rpmdb") == 0) {
   933 		set = razor_set_create_from_rpmdb();
   934 		if (set == NULL)
   935 			return 1;
   936 		razor_set_write(set, repo_filename);
   937 		razor_set_destroy(set);
   938 		printf("wrote %s\n", repo_filename);
   939 	} else if (strcmp(argv[1], "validate") == 0) {
   940 		set = razor_set_open(repo_filename);
   941 		if (set == NULL)
   942 			return 1;
   943 		razor_set_list_unsatisfied(set);
   944 		razor_set_destroy(set);
   945 	} else {
   946 		usage();
   947 	}
   948 
   949 	return 0;
   950 }