razor.c
author Kristian H?gsberg <krh@redhat.com>
Thu Sep 06 17:01:01 2007 -0400 (2007-09-06)
changeset 9 c4338a14dd9f
parent 8 7820b7d94662
child 10 1b8f6a5022f1
permissions -rw-r--r--
Uniqueify requires and provides after import.
     1 #include <stdlib.h>
     2 #include <stdio.h>
     3 #include <string.h>
     4 #include <sys/types.h>
     5 #include <sys/stat.h>
     6 #include <sys/mman.h>
     7 #include <unistd.h>
     8 #include <fcntl.h>
     9 
    10 #include <expat.h>
    11 #include "sha1.h"
    12 
    13 struct array {
    14 	void *data;
    15 	int size, alloc;
    16 };
    17 
    18 static void *
    19 array_add(struct array *array, int size)
    20 {
    21 	int alloc;
    22 	void *data, *p;
    23 
    24 	if (array->alloc > 0)
    25 		alloc = array->alloc;
    26 	else
    27 		alloc = 1024;
    28 
    29 	while (alloc < array->size + size)
    30 		alloc *= 2;
    31 
    32 	if (array->alloc < alloc) {
    33 		data = realloc(array->data, alloc);
    34 		if (data == NULL)
    35 			return 0;
    36 		array->data = data;
    37 		array->alloc = alloc;
    38 	}
    39 
    40 	p = array->data + array->size;
    41 	array->size += size;
    42 
    43 	return p;
    44 }
    45 
    46 static int
    47 write_to_fd(int fd, void *p, size_t size)
    48 {
    49 	int rest, len;
    50 
    51 	rest = size;
    52 	while (rest > 0) {
    53 		len = write(fd, p, rest);
    54 		if (len < 0)
    55 			return -1;
    56 		rest -= len;
    57 	}
    58 
    59 	return 0;
    60 }
    61 
    62 static int
    63 write_to_file(const char *filename, void *p, size_t size)
    64 {
    65 	int fd, err;
    66 
    67 	fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
    68 	if (fd < 0)
    69 		return -1;
    70 	err = write_to_fd(fd, p, size);
    71 	close(fd);
    72 
    73 	return err;
    74 }
    75 
    76 static void *
    77 zalloc(size_t size)
    78 {
    79 	void *p;
    80 
    81 	p = malloc(size);
    82 	memset(p, 0, size);
    83 
    84 	return p;
    85 }
    86 
    87 struct razor_set_header {
    88 	unsigned int magic;
    89 	unsigned int version;
    90 	struct { unsigned int type, offset; } sections[0];
    91 };
    92 
    93 #define RAZOR_MAGIC 0x7a7a7a7a
    94 #define RAZOR_VERSION 1
    95 
    96 #define RAZOR_BUCKETS 1
    97 #define RAZOR_STRINGS 2
    98 #define RAZOR_PACKAGES 3
    99 #define RAZOR_REQUIRES 4
   100 #define RAZOR_PROVIDES 5
   101 
   102 struct razor_package {
   103 	unsigned long name;
   104 	unsigned long version;
   105 };
   106 
   107 struct razor_property {
   108 	unsigned long name;
   109 	unsigned long version;
   110 	unsigned long packages;
   111 };
   112 
   113 struct razor_set {
   114 	struct array buckets;
   115 	struct array string_pool;
   116  	struct array packages;
   117  	struct array requires;
   118  	struct array provides;
   119 	struct razor_set_header *header;
   120 };
   121 
   122 struct razor_set *
   123 razor_set_create(void)
   124 {
   125 	struct razor_set *set;
   126 	char *p;
   127 
   128 	set = zalloc(sizeof(struct razor_set));
   129 	p = array_add(&set->string_pool, 1);
   130 	*p = '\0';
   131 
   132 	return set;
   133 }
   134 
   135 struct razor_set *
   136 razor_set_open(const char *filename)
   137 {
   138 	struct razor_set *set;
   139 	struct stat stat;
   140 	unsigned int size, offset;
   141 	int fd, i;
   142 
   143 	set = zalloc(sizeof *set);
   144 	fd = open(filename, O_RDONLY);
   145 	if (fstat(fd, &stat) < 0)
   146 		return NULL;
   147 	set->header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
   148 	if (set->header == MAP_FAILED) {
   149 		free(set);
   150 		return NULL;
   151 	}
   152 
   153 	for (i = 0; i < set->header->sections[i].type; i++) {
   154 		offset = set->header->sections[i].offset;
   155 		size = set->header->sections[i + 1].offset - offset;
   156 
   157 		switch (set->header->sections[i].type) {
   158 		case RAZOR_BUCKETS:
   159 			set->buckets.data = (void *) set->header + offset;
   160 			set->buckets.size = size;
   161 			set->buckets.alloc = size;
   162 			break;
   163 		case RAZOR_STRINGS:
   164 			set->string_pool.data = (void *) set->header + offset;
   165 			set->string_pool.size = size;
   166 			set->string_pool.alloc = size;
   167 			break;
   168 		case RAZOR_PACKAGES:
   169 			set->packages.data = (void *) set->header + offset;
   170 			set->packages.size = size;
   171 			set->packages.size = size;
   172 			break;
   173 		case RAZOR_REQUIRES:
   174 			set->requires.data = (void *) set->header + offset;
   175 			set->requires.size = size;
   176 			set->requires.size = size;
   177 			break;
   178 		case RAZOR_PROVIDES:
   179 			set->provides.data = (void *) set->header + offset;
   180 			set->provides.size = size;
   181 			set->provides.size = size;
   182 			break;
   183 		}
   184 	}
   185 	close(fd);
   186 
   187 	return set;
   188 }
   189 
   190 void
   191 razor_set_destroy(struct razor_set *set)
   192 {
   193 	unsigned int size;
   194 	int i;
   195 
   196 	if (set->header) {
   197 		for (i = 0; set->header->sections[i].type; i++)
   198 			;
   199 		size = set->header->sections[i].type;
   200 		munmap(set->header, size);
   201 	} else {
   202 		free(set->buckets.data);
   203 		free(set->string_pool.data);
   204 		free(set->packages.data);
   205 		free(set->requires.data);
   206 		free(set->provides.data);
   207 	}
   208 
   209 	free(set);
   210 }
   211 
   212 static int
   213 razor_set_write(struct razor_set *set, const char *filename)
   214 {
   215 	char data[4096];
   216 	struct razor_set_header *header = (struct razor_set_header *) data;
   217 	int fd, pool_size, packages_size, requires_size, provides_size;
   218 
   219 	/* Align these to pages sizes */
   220 	pool_size = (set->string_pool.size + 4095) & ~4095;
   221 	packages_size = (set->packages.size + 4095) & ~4095;
   222 	requires_size = (set->requires.size + 4095) & ~4095;
   223 	provides_size = (set->provides.size + 4095) & ~4095;
   224 
   225 	memset(data, 0, sizeof data);
   226 	header->magic = RAZOR_MAGIC;
   227 	header->version = RAZOR_VERSION;
   228 
   229 	header->sections[0].type = RAZOR_BUCKETS;
   230 	header->sections[0].offset = sizeof data;
   231 
   232 	header->sections[1].type = RAZOR_STRINGS;
   233 	header->sections[1].offset =
   234 		header->sections[0].offset + set->buckets.alloc;
   235 
   236 	header->sections[2].type = RAZOR_PACKAGES;
   237 	header->sections[2].offset =
   238 		header->sections[1].offset + pool_size;
   239 
   240 	header->sections[3].type = RAZOR_REQUIRES;
   241 	header->sections[3].offset =
   242 		header->sections[2].offset + packages_size;
   243 
   244 	header->sections[4].type = RAZOR_PROVIDES;
   245 	header->sections[4].offset =
   246 		header->sections[3].offset + requires_size;
   247 
   248 	header->sections[5].type = 0;
   249 	header->sections[5].offset =
   250 		header->sections[4].offset + provides_size;
   251 
   252 	fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
   253 	if (fd < 0)
   254 		return -1;
   255 
   256 	write_to_fd(fd, data, sizeof data);
   257 	write_to_fd(fd, set->buckets.data, set->buckets.alloc);
   258 	write_to_fd(fd, set->string_pool.data, pool_size);
   259 	write_to_fd(fd, set->packages.data, packages_size);
   260 	write_to_fd(fd, set->requires.data, requires_size);
   261 	write_to_fd(fd, set->provides.data, provides_size);
   262 
   263 	return 0;
   264 }
   265 
   266 static unsigned int
   267 hash_string(const char *key)
   268 {
   269 	const char *p;
   270 	unsigned int hash = 0;
   271 
   272 	for (p = key; *p; p++)
   273 		hash = (hash * 617) ^ *p;
   274 
   275 	return hash;
   276 }
   277 
   278 unsigned long
   279 razor_set_lookup(struct razor_set *set, const char *key)
   280 {
   281 	unsigned int mask, start, i;
   282 	unsigned long *b;
   283 	char *pool;
   284 
   285 	pool = set->string_pool.data;
   286 	mask = set->buckets.alloc - 1;
   287 	start = hash_string(key) * sizeof(unsigned long);
   288 
   289 	for (i = 0; i < set->buckets.alloc; i += sizeof *b) {
   290 		b = set->buckets.data + ((start + i) & mask);
   291 
   292 		if (*b == 0)
   293 			return 0;
   294 
   295 		if (strcmp(key, &pool[*b]) == 0)
   296 			return *b;
   297 	}
   298 
   299 	return 0;
   300 }
   301 
   302 static unsigned long
   303 add_to_string_pool(struct razor_set *set, const char *key)
   304 {
   305 	int len;
   306 	char *p;
   307 
   308 	len = strlen(key) + 1;
   309 	p = array_add(&set->string_pool, len);
   310 	memcpy(p, key, len);
   311 
   312 	return p - (char *) set->string_pool.data;
   313 }
   314 
   315 static void
   316 do_insert(struct razor_set *set, unsigned long value)
   317 {
   318 	unsigned int mask, start, i;
   319 	unsigned long *b;
   320 	const char *key;
   321 
   322 	key = (char *) set->string_pool.data + value;
   323 	mask = set->buckets.alloc - 1;
   324 	start = hash_string(key) * sizeof(unsigned long);
   325 
   326 	for (i = 0; i < set->buckets.alloc; i += sizeof *b) {
   327 		b = set->buckets.data + ((start + i) & mask);
   328 		if (*b == 0) {
   329 			*b = value;
   330 			break;
   331 		}
   332 	}
   333 }
   334 
   335 unsigned long
   336 razor_set_insert(struct razor_set *set, const char *key)
   337 {
   338 	unsigned long value, *buckets, *b, *end;
   339 	int alloc;
   340 
   341 	alloc = set->buckets.alloc;
   342 	array_add(&set->buckets, 4 * sizeof *buckets);
   343 	if (alloc != set->buckets.alloc) {
   344 		end = set->buckets.data + alloc;
   345 		memset(end, 0, set->buckets.alloc - alloc);
   346 		for (b = set->buckets.data; b < end; b++) {
   347 			value = *b;
   348 			if (value != 0) {
   349 				*b = 0;
   350 				do_insert(set, value);
   351 			}
   352 		}
   353 	}
   354 
   355 	value = add_to_string_pool(set, key);
   356 	do_insert (set, value);
   357 
   358 	return value;
   359 }
   360 
   361 static unsigned long
   362 razor_set_add_package(struct razor_set *set,
   363 		      unsigned long name, unsigned long version)
   364 {
   365 	struct razor_package *p;
   366 
   367 	p = array_add(&set->packages, sizeof *p);
   368 
   369 	p->name = name;
   370 	p->version = version;
   371 
   372 	return p - (struct razor_package *) set->packages.data;
   373 }
   374 
   375 static unsigned long
   376 razor_set_add_requires(struct razor_set *set,
   377 		       unsigned long name, unsigned long version)
   378 {
   379 	struct razor_property *p;
   380 
   381 	p = array_add(&set->requires, sizeof *p);
   382 
   383 	p->name = name;
   384 	p->version = version;
   385 
   386 	return p - (struct razor_property *) set->requires.data;
   387 }
   388 
   389 static unsigned long
   390 razor_set_add_provides(struct razor_set *set,
   391 		       unsigned long name, unsigned long version)
   392 {
   393 	struct razor_property *p;
   394 
   395 	p = array_add(&set->provides, sizeof *p);
   396 
   397 	p->name = name;
   398 	p->version = version;
   399 
   400 	return p - (struct razor_property *) set->provides.data;
   401 }
   402 
   403 unsigned long
   404 razor_set_tokenize(struct razor_set *set, const char *string)
   405 {
   406 	unsigned long token;
   407 
   408 	token = razor_set_lookup(set, string);
   409 	if (token != 0)
   410 		return token;
   411 
   412 	return razor_set_insert(set, string);
   413 }
   414 
   415 struct import_context {
   416 	struct razor_set *set;
   417 	struct array requires;
   418 	struct array provides;
   419 	unsigned long package;
   420 };
   421 
   422 static void
   423 parse_package(struct import_context *ctx, const char **atts, void *data)
   424 {
   425 	unsigned long name = 0, version = 0;
   426 	int i;
   427 
   428 	for (i = 0; atts[i]; i += 2) {
   429 		if (strcmp(atts[i], "name") == 0)
   430 			name = razor_set_tokenize(ctx->set, atts[i + 1]);
   431 		else if (strcmp(atts[i], "version") == 0)
   432 			version = razor_set_tokenize(ctx->set, atts[i + 1]);
   433 	}
   434 
   435 	if (name == 0 || version == 0) {
   436 		fprintf(stderr, "invalid package tag, "
   437 			"missing name or version attributes\n");
   438 		return;
   439 	}
   440 
   441 	ctx->package = razor_set_add_package(ctx->set, name, version);
   442 
   443 	return;
   444 }
   445 
   446 static void
   447 parse_property(struct import_context *ctx, const char **atts, void *data)
   448 {
   449 	unsigned long name = 0, version = 0;
   450 	struct razor_property *p;
   451 	struct array *array = data;
   452 	int i;
   453 
   454 	for (i = 0; atts[i]; i += 2) {
   455 		if (strcmp(atts[i], "name") == 0)
   456 			name = razor_set_tokenize(ctx->set, atts[i + 1]);
   457 		if (strcmp(atts[i], "version") == 0)
   458 			version = razor_set_tokenize(ctx->set, atts[i + 1]);
   459 	}
   460 	
   461 	if (name == 0) {
   462 		fprintf(stderr, "invalid tag, missing name attribute\n");
   463 		return;
   464 	}
   465 
   466 	p = array_add(array, sizeof *p);
   467 	p->name = name;
   468 	p->version = version;
   469 	p->packages = ctx->package;
   470 }
   471 
   472 static void
   473 start_element(void *data, const char *name, const char **atts)
   474 {
   475 	struct import_context *ctx = data;
   476 
   477 	if (strcmp(name, "package") == 0)
   478 		parse_package(ctx, atts, NULL);
   479 	else if (strcmp(name, "requires") == 0)
   480 		parse_property(ctx, atts, &ctx->requires);
   481 	else if (strcmp(name, "provides") == 0)
   482 		parse_property(ctx, atts, &ctx->provides);
   483 }
   484 
   485 static void
   486 end_element (void *data, const char *name)
   487 {
   488 	struct import_context *ctx = data;
   489 
   490 	if (strcmp(name, "package") == 0)
   491 		ctx->package = 0;
   492 }
   493 
   494 static char *
   495 sha1_to_hex(const unsigned char *sha1)
   496 {
   497 	static int bufno;
   498 	static char hexbuffer[4][50];
   499 	static const char hex[] = "0123456789abcdef";
   500 	char *buffer = hexbuffer[3 & ++bufno], *buf = buffer;
   501 	int i;
   502 
   503 	for (i = 0; i < 20; i++) {
   504 		unsigned int val = *sha1++;
   505 		*buf++ = hex[val >> 4];
   506 		*buf++ = hex[val & 0xf];
   507 	}
   508 	*buf = '\0';
   509 
   510 	return buffer;
   511 }
   512 
   513 static void
   514 razor_set_prepare_import(struct razor_set *set, struct import_context *ctx)
   515 {
   516 	memset(ctx, 0, sizeof *ctx);
   517 	ctx->set = set;
   518 }
   519 
   520 static int
   521 razor_set_import(struct import_context *ctx, const char *filename)
   522 {
   523 	SHA_CTX sha1;
   524 	XML_Parser parser;
   525 	int fd;
   526 	void *p;
   527 	struct stat stat;
   528 	char buf[128];
   529 	unsigned char hash[20];
   530 
   531 	fd = open(filename, O_RDONLY);
   532 	if (fstat(fd, &stat) < 0)
   533 		return -1;
   534 	p = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
   535 	if (p == MAP_FAILED)
   536 		return -1;
   537 
   538 	parser = XML_ParserCreate(NULL);
   539 	XML_SetUserData(parser, ctx);
   540 	XML_SetElementHandler(parser, start_element, end_element);
   541 	if (XML_Parse(parser, p, stat.st_size, 1) == XML_STATUS_ERROR) {
   542 		fprintf(stderr,
   543 			"%s at line %d, %s\n",
   544 			XML_ErrorString(XML_GetErrorCode(parser)),
   545 			XML_GetCurrentLineNumber(parser),
   546 			filename);
   547 		return 1;
   548 	}
   549 
   550 	XML_ParserFree(parser);
   551 
   552 	SHA1_Init(&sha1);
   553 	SHA1_Update(&sha1, p, stat.st_size);
   554 	SHA1_Final(hash, &sha1);
   555 
   556 	close(fd);
   557 
   558 	snprintf(buf, sizeof buf, "set/%s", sha1_to_hex(hash));
   559 	if (write_to_file(buf, p, stat.st_size) < 0)
   560 		return -1;
   561 	munmap(p, stat.st_size);
   562 
   563 	return 0;
   564 }
   565 
   566 static struct razor_set *qsort_set;
   567 
   568 static int
   569 compare_packages(const void *p1, const void *p2)
   570 {
   571 	const struct razor_package *pkg1 = p1, *pkg2 = p2;
   572 	char *pool = qsort_set->string_pool.data;
   573 
   574 	return strcmp(&pool[pkg1->name], &pool[pkg2->name]);
   575 }
   576 
   577 static int
   578 compare_properties(const void *p1, const void *p2)
   579 {
   580 	const struct razor_property *prop1 = p1, *prop2 = p2;
   581 	char *pool = qsort_set->string_pool.data;
   582 
   583 	return strcmp(&pool[prop1->name], &pool[prop2->name]);
   584 }
   585 
   586 static void
   587 uniqueify_properties(struct array *in, struct array *out)
   588 {
   589 	struct razor_property *p, *q, *end;
   590 
   591 	qsort(in->data, in->size / sizeof(struct razor_property),
   592 	      sizeof(struct razor_property), compare_properties);
   593 
   594 	q = NULL;
   595 	end = in->data + in->size;
   596 	for (p = in->data; p < end && p->name; p++) {
   597 		if (q == NULL ||
   598 		    p->name != q->name || p->version != q->version) {
   599 			q = array_add(out, sizeof *q);
   600 			q->name = p->name;
   601 			q->version = p->version;
   602 
   603 		}
   604 	}
   605 }
   606 
   607 static void
   608 razor_set_finish_import(struct import_context *ctx)
   609 {
   610 	qsort_set = ctx->set;
   611 	qsort(ctx->set->packages.data,
   612 	      ctx->set->packages.size / sizeof(struct razor_package),
   613 	      sizeof(struct razor_package), compare_packages);
   614 
   615 	uniqueify_properties(&ctx->requires, &ctx->set->requires);
   616 	uniqueify_properties(&ctx->provides, &ctx->set->provides);
   617 
   618 	free(ctx->requires.data);
   619 	free(ctx->provides.data);
   620 
   621 	fprintf(stderr, "parsed %d requires, %d unique\n",
   622 		ctx->requires.size / sizeof(struct razor_property),
   623 		ctx->set->requires.size / sizeof(struct razor_property));
   624 	fprintf(stderr, "parsed %d provides, %d unique\n",
   625 		ctx->provides.size / sizeof(struct razor_property),
   626 		ctx->set->provides.size / sizeof(struct razor_property));
   627 }
   628 
   629 
   630 void
   631 razor_set_list(struct razor_set *set)
   632 {
   633 	struct razor_package *p, *end;
   634 	char *pool;
   635 
   636 	pool = set->string_pool.data;
   637 	end = set->packages.data + set->packages.size;
   638 	for (p = set->packages.data; p < end && p->name; p++)
   639 		printf("%s %s\n", &pool[p->name], &pool[p->version]);
   640 }
   641 
   642 void
   643 razor_set_list_requires(struct razor_set *set)
   644 {
   645 	struct razor_property *p, *end;
   646 	char *pool;
   647 
   648 	pool = set->string_pool.data;
   649 	end = set->requires.data + set->requires.size;
   650 	for (p = set->requires.data; p < end && p->name; p++)
   651 		printf("%s %s\n", &pool[p->name], &pool[p->version]);
   652 }
   653 
   654 void
   655 razor_set_list_provides(struct razor_set *set)
   656 {
   657 	struct razor_property *p, *end;
   658 	char *pool;
   659 
   660 	pool = set->string_pool.data;
   661 	end = set->provides.data + set->provides.size;
   662 	for (p = set->provides.data; p < end && p->name; p++)
   663 		printf("%s %s\n", &pool[p->name], &pool[p->version]);
   664 }
   665 
   666 void
   667 razor_set_info(struct razor_set *set)
   668 {
   669 	unsigned int offset, size;
   670 	int i;
   671 
   672 	for (i = 0; i < set->header->sections[i].type; i++) {
   673 		offset = set->header->sections[i].offset;
   674 		size = set->header->sections[i + 1].offset - offset;
   675 
   676 		switch (set->header->sections[i].type) {
   677 		case RAZOR_BUCKETS:
   678 			printf("bucket section:\t\t%dkb\n", size / 1024);
   679 			break;
   680 		case RAZOR_STRINGS:
   681 			printf("string pool:\t\t%dkb\n", size / 1024);
   682 			break;
   683 		case RAZOR_PACKAGES:
   684 			printf("package section:\t%dkb\n", size / 1024);
   685 			break;
   686 		case RAZOR_REQUIRES:
   687 			printf("requires section:\t%dkb\n", size / 1024);
   688 			break;
   689 		case RAZOR_PROVIDES:
   690 			printf("provides section:\t%dkb\n", size / 1024);
   691 			break;
   692 		}
   693 	}
   694 }
   695 
   696 static int
   697 usage(void)
   698 {
   699 	printf("usage: razor [ import FILES | lookup <key> | "
   700 	       "list | list-requires | list-provides | info ]\n");
   701 	exit(1);
   702 }
   703 
   704 static const char repo_filename[] = "system.repo";
   705 
   706 int
   707 main(int argc, char *argv[])
   708 {
   709 	int i;
   710 	struct razor_set *set;
   711 	struct stat statbuf;
   712 	struct import_context ctx;
   713 
   714 	if (argc < 2) {
   715 		usage();
   716 	} else if (strcmp(argv[1], "import") == 0) {
   717 		if (stat("set", &statbuf) && mkdir("set", 0777)) {
   718 			fprintf(stderr, "could not create directory 'set'\n");
   719 			exit(-1);
   720 		}
   721 			
   722 		set = razor_set_create();
   723 
   724 		razor_set_prepare_import(set, &ctx);
   725 
   726 		for (i = 2; i < argc; i++) {
   727 			if (razor_set_import(&ctx, argv[i]) < 0) {
   728 				fprintf(stderr, "failed to import %s\n",
   729 					argv[i]);
   730 				exit(-1);
   731 			}
   732 		}
   733 
   734 		razor_set_finish_import(&ctx);
   735 
   736 		/* FIXME: We add a sentinel package here, but we
   737 		 * should probably just have a size field in the
   738 		 * header section. */
   739 		razor_set_add_package(set, 0, 0);
   740 		razor_set_add_requires(set, 0, 0);
   741 		razor_set_add_provides(set, 0, 0);
   742 
   743 		printf("bucket allocation: %d\n", set->buckets.alloc);
   744 		printf("pool size: %d\n", set->string_pool.size);
   745 		printf("pool allocation: %d\n", set->string_pool.alloc);
   746 		printf("packages: %d\n",
   747 		       set->packages.size / sizeof(struct razor_package));
   748 		printf("requires: %d\n",
   749 		       set->requires.size / sizeof(struct razor_property));
   750 		printf("provides: %d\n",
   751 		       set->provides.size / sizeof(struct razor_property));
   752 
   753 		razor_set_write(set, repo_filename);
   754 
   755 		razor_set_destroy(set);
   756 	} else if (strcmp(argv[1], "lookup") == 0) {
   757 		set = razor_set_open(repo_filename);
   758 		printf("%s is %lu\n", argv[2],
   759 		       razor_set_lookup(set, argv[2]));
   760 		razor_set_destroy(set);
   761 	} else if (strcmp(argv[1], "list") == 0) {
   762 		set = razor_set_open(repo_filename);
   763 		razor_set_list(set);
   764 		razor_set_destroy(set);
   765 	} else if (strcmp(argv[1], "list-requires") == 0) {
   766 		set = razor_set_open(repo_filename);
   767 		razor_set_list_requires(set);
   768 		razor_set_destroy(set);
   769 	} else if (strcmp(argv[1], "list-provides") == 0) {
   770 		set = razor_set_open(repo_filename);
   771 		razor_set_list_provides(set);
   772 		razor_set_destroy(set);
   773 	} else if (strcmp(argv[1], "info") == 0) {
   774 		set = razor_set_open(repo_filename);
   775 		razor_set_info(set);
   776 		razor_set_destroy(set);
   777 	} else {
   778 		usage();
   779 	}
   780 
   781 	return 0;
   782 }