librazor/razor.c
author J. Ali Harlow <ali@juiblex.co.uk>
Wed Apr 29 17:00:01 2009 +0100 (2009-04-29)
changeset 361 2523d03a840e
parent 351 48b0adfe3059
child 363 c75a2d5caae9
permissions -rw-r--r--
Add support for preloading lua modules. This is useful both when
providing lua bindings to applications based on librazor and when
producing static binaries using librazor (where otherwise the lua
POSIX library would need to be included as an additional dynamic
object).
     1 /*
     2  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     3  * Copyright (C) 2008  Red Hat, Inc
     4  *
     5  * This program is free software; you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation; either version 2 of the License, or
     8  * (at your option) any later version.
     9  *
    10  * This program is distributed in the hope that it will be useful,
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  * GNU General Public License for more details.
    14  *
    15  * You should have received a copy of the GNU General Public License along
    16  * with this program; if not, write to the Free Software Foundation, Inc.,
    17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    18  */
    19 
    20 #define _GNU_SOURCE
    21 
    22 #include "config.h"
    23 
    24 #include <stdlib.h>
    25 #include <stddef.h>
    26 #include <stdint.h>
    27 #include <stdio.h>
    28 #include <stdarg.h>
    29 #include <string.h>
    30 #include <sys/types.h>
    31 #include <sys/stat.h>
    32 #include <unistd.h>
    33 #include <fcntl.h>
    34 #include <errno.h>
    35 #include <ctype.h>
    36 #include <fnmatch.h>
    37 #include <assert.h>
    38 
    39 #include "razor-internal.h"
    40 #include "razor.h"
    41 
    42 #ifndef O_BINARY
    43 #define O_BINARY	0
    44 #endif
    45 
    46 void *
    47 zalloc(size_t size)
    48 {
    49 	void *p;
    50 
    51 	p = malloc(size);
    52 	memset(p, 0, size);
    53 
    54 	return p;
    55 }
    56 
    57 struct razor_set_section_index {
    58 	const char *name;
    59 	uint32_t offset;
    60 };
    61 
    62 struct razor_set_section_index razor_sections[] = {
    63 	{ RAZOR_STRING_POOL,	offsetof(struct razor_set, string_pool) },
    64 	{ RAZOR_PACKAGES,	offsetof(struct razor_set, packages) },
    65 	{ RAZOR_PROPERTIES,	offsetof(struct razor_set, properties) },
    66 	{ RAZOR_PACKAGE_POOL,	offsetof(struct razor_set, package_pool) },
    67 	{ RAZOR_PROPERTY_POOL,	offsetof(struct razor_set, property_pool) },
    68 };
    69 
    70 struct razor_set_section_index razor_files_sections[] = {
    71 	{ RAZOR_FILES,			offsetof(struct razor_set, files) },
    72 	{ RAZOR_FILE_POOL,		offsetof(struct razor_set, file_pool) },
    73 	{ RAZOR_FILE_STRING_POOL,	offsetof(struct razor_set, file_string_pool) },
    74 };
    75 
    76 struct razor_set_section_index razor_details_sections[] = {
    77 	{ RAZOR_DETAILS_STRING_POOL,	offsetof(struct razor_set, details_string_pool) },
    78 };
    79 
    80 RAZOR_EXPORT struct razor_set *
    81 razor_set_create(void)
    82 {
    83 	struct razor_set *set;
    84 	struct razor_entry *e;
    85 	char *empty;
    86 
    87 	set = zalloc(sizeof *set);
    88 
    89 	e = array_add(&set->files, sizeof *e);
    90 	empty = array_add(&set->string_pool, 1);
    91 	*empty = '\0';
    92 	e->name = 0;
    93 	e->flags = RAZOR_ENTRY_LAST;
    94 	e->start = 0;
    95 	list_set_empty(&e->packages);
    96 
    97 	return set;
    98 }
    99 
   100 static int
   101 razor_set_bind_sections(struct razor_set *set,
   102 			struct razor_set_header **header,
   103 			size_t *header_size,
   104 			struct razor_set_section_index section_index[],
   105 			int section_index_size,
   106 			const char *filename)
   107 {
   108 	struct razor_set_section *s, *sections;
   109 	struct array *array;
   110 	const char *pool;
   111 	int i;
   112 
   113 	*header = razor_file_get_contents(filename, header_size);
   114 	if (!*header)
   115 		return -1;
   116 
   117 	sections = (void *) *header + sizeof **header;
   118 	pool = (void *) sections + (*header)->num_sections * sizeof *sections;
   119 
   120 	for (i = 0; i < (*header)->num_sections; i++) {
   121 		int j;
   122 		s = sections + i;
   123 		for (j = 0; j < section_index_size; j++)
   124 			if (!strcmp(section_index[j].name,
   125 				    &pool[s->name]))
   126 				break;
   127 		if (j == section_index_size)
   128 			continue;
   129 		array = (void *) set + section_index[j].offset;
   130 		array->data = (void *) *header + s->offset;
   131 		array->size = s->size;
   132 		array->alloc = s->size;
   133 	}
   134 
   135 	return 0;
   136 }
   137 
   138 RAZOR_EXPORT struct razor_set *
   139 razor_set_open(const char *filename)
   140 {
   141 	struct razor_set *set;
   142 
   143 	set = zalloc(sizeof *set);
   144 	if (razor_set_bind_sections(set, &set->header, &set->header_size,
   145 				    razor_sections, ARRAY_SIZE(razor_sections),
   146 				    filename)){
   147 		free(set);
   148 		return NULL;
   149 	}
   150 	return set;
   151 }
   152 
   153 RAZOR_EXPORT int
   154 razor_set_open_details(struct razor_set *set, const char *filename)
   155 {
   156 	return razor_set_bind_sections(set, &set->details_header,
   157 				       &set->details_header_size,
   158 				       razor_details_sections,
   159 				       ARRAY_SIZE(razor_details_sections),
   160 				       filename);
   161 }
   162 
   163 RAZOR_EXPORT int
   164 razor_set_open_files(struct razor_set *set, const char *filename)
   165 {
   166 	return razor_set_bind_sections(set, &set->files_header,
   167 				       &set->files_header_size,
   168 				       razor_files_sections,
   169 				       ARRAY_SIZE(razor_files_sections),
   170 				       filename);
   171 }
   172 
   173 RAZOR_EXPORT void
   174 razor_set_destroy(struct razor_set *set)
   175 {
   176 	struct array *a;
   177 	int i;
   178 
   179 	assert (set != NULL);
   180 
   181 	if (set->header) {
   182 		razor_file_free_contents(set->header, set->header_size);
   183 	} else {
   184 		for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
   185 			a = (void *) set + razor_sections[i].offset;
   186 			free(a->data);
   187 		}
   188 	}
   189 
   190 	if (set->details_header) {
   191 		razor_file_free_contents(set->details_header,
   192 			set->details_header_size);
   193 	} else {
   194 		for (i = 0; i < ARRAY_SIZE(razor_details_sections); i++) {
   195 			a = (void *) set + razor_details_sections[i].offset;
   196 			free(a->data);
   197 		}
   198 	}
   199 
   200 	if (set->files_header) {
   201 		razor_file_free_contents(set->files_header,
   202 			set->files_header_size);
   203 	} else {
   204 		for (i = 0; i < ARRAY_SIZE(razor_files_sections); i++) {
   205 			a = (void *) set + razor_files_sections[i].offset;
   206 			free(a->data);
   207 		}
   208 	}
   209 
   210 	free(set);
   211 }
   212 
   213 static int
   214 razor_set_write_sections_to_fd(struct razor_set *set, int fd,
   215 			       struct razor_set_section_index *sections,
   216 			       size_t array_size)
   217 {
   218 	struct razor_set_header header;
   219 	struct razor_set_section *out_sections =
   220 		malloc(array_size * sizeof *out_sections);
   221 	struct hashtable table;
   222 	struct array *a, pool;
   223 	uint32_t offset;
   224 	int i;
   225 
   226 	header.magic = RAZOR_MAGIC;
   227 	header.version = RAZOR_VERSION;
   228 	header.num_sections = array_size;
   229 	offset = sizeof header + array_size * sizeof *out_sections;
   230 
   231 	array_init(&pool);
   232 	hashtable_init(&table, &pool);
   233 
   234 	for (i = 0; i < array_size; i++)
   235 		out_sections[i].name =
   236 			hashtable_tokenize(&table, sections[i].name);
   237 
   238 	offset += pool.size;
   239 
   240 	for (i = 0; i < array_size; i++) {
   241 		a = (void *) set + sections[i].offset;
   242 		out_sections[i].offset = offset;
   243 		out_sections[i].size = a->size;
   244 		offset += a->size;
   245 	}
   246 
   247 	razor_write(fd, &header, sizeof header);
   248 	razor_write(fd, out_sections, array_size * sizeof *out_sections);
   249 	razor_write(fd, pool.data, pool.size);
   250 
   251 	for (i = 0; i < array_size; i++) {
   252 		a = (void *) set + sections[i].offset;
   253 		razor_write(fd, a->data, a->size);
   254 	}
   255 
   256 	free(out_sections);
   257 
   258 	return 0;
   259 }
   260 
   261 RAZOR_EXPORT int
   262 razor_set_write_to_fd(struct razor_set *set, int fd,
   263 		      enum razor_repo_file_type type)
   264 {
   265 	switch (type) {
   266 	case RAZOR_REPO_FILE_MAIN:
   267 		return razor_set_write_sections_to_fd(set, fd,
   268 						      razor_sections,
   269 						      ARRAY_SIZE(razor_sections));
   270 
   271 	case RAZOR_REPO_FILE_DETAILS:
   272 		return razor_set_write_sections_to_fd(set, fd,
   273 						      razor_details_sections,
   274 						      ARRAY_SIZE(razor_details_sections));
   275 	case RAZOR_REPO_FILE_FILES:
   276 		return razor_set_write_sections_to_fd(set, fd,
   277 						      razor_files_sections,
   278 						      ARRAY_SIZE(razor_files_sections));
   279 	default:
   280 		return -1;
   281 	}
   282 }
   283 
   284 RAZOR_EXPORT int
   285 razor_set_write(struct razor_set *set, const char *filename,
   286 		enum razor_repo_file_type type)
   287 {
   288 	int fd, status;
   289 
   290 	fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, 0666);
   291 	if (fd < 0)
   292 		return -1;
   293 
   294 	status = razor_set_write_to_fd(set, fd, type);
   295 	if (status) {
   296 	    close(fd);
   297 	    return status;
   298 	}
   299 
   300 	return close(fd);
   301 }
   302 
   303 RAZOR_EXPORT void
   304 razor_build_evr(char *evr_buf, int size, const char *epoch,
   305 		const char *version, const char *release)
   306 {
   307 	int len;
   308 
   309 	if (!version || !*version) {
   310 		*evr_buf = '\0';
   311 		return;
   312 	}
   313 
   314 	if (epoch && *epoch && strcmp(epoch, "0") != 0) {
   315 		len = snprintf(evr_buf, size, "%s:", epoch);
   316 		evr_buf += len;
   317 		size -= len;
   318 	}
   319 	len = snprintf(evr_buf, size, "%s", version);
   320 	evr_buf += len;
   321 	size -= len;
   322 	if (release && *release)
   323 		snprintf(evr_buf, size, "-%s", release);
   324 }
   325 
   326 RAZOR_EXPORT int
   327 razor_versioncmp(const char *s1, const char *s2)
   328 {
   329 	const char *p1, *p2;
   330 	long n1, n2;
   331 	int res;
   332 
   333 	assert (s1 != NULL);
   334 	assert (s2 != NULL);
   335 
   336 	n1 = strtol(s1, (char **) &p1, 10);
   337 	n2 = strtol(s2, (char **) &p2, 10);
   338 
   339 	/* Epoch; if one but not the other has an epoch set, default
   340 	 * the epoch-less version to 0. */
   341 	res = (*p1 == ':') - (*p2 == ':');
   342 	if (res < 0) {
   343 		n1 = 0;
   344 		p1 = s1;
   345 		p2++;
   346 	} else if (res > 0) {
   347 		p1++;
   348 		n2 = 0;
   349 		p2 = s2;
   350 	}
   351 
   352 	if (n1 != n2)
   353 		return n1 - n2;
   354 	while (*p1 && *p2) {
   355 		if (*p1 != *p2)
   356 			return *p1 - *p2;
   357 		p1++;
   358 		p2++;
   359 		if (isdigit(*p1) && isdigit(*p2))
   360 			return razor_versioncmp(p1, p2);
   361 	}
   362 
   363 	return *p1 - *p2;
   364 }
   365 
   366 static const char *
   367 razor_package_get_details_type(struct razor_set *set,
   368 			       struct razor_package *package,
   369 			       enum razor_detail_type type)
   370 {
   371 	const char *pool;
   372 
   373 	switch (type) {
   374 	case RAZOR_DETAIL_NAME:
   375 		pool = set->string_pool.data;
   376 		return &pool[package->name];
   377 
   378 	case RAZOR_DETAIL_VERSION:
   379 		pool = set->string_pool.data;
   380 		return &pool[package->version];
   381 
   382 	case RAZOR_DETAIL_ARCH:
   383 		pool = set->string_pool.data;
   384 		return &pool[package->arch];
   385 
   386 	case RAZOR_DETAIL_SUMMARY:
   387 		pool = set->details_string_pool.data;
   388 		return &pool[package->summary];
   389 
   390 	case RAZOR_DETAIL_DESCRIPTION:
   391 		pool = set->details_string_pool.data;
   392 		return &pool[package->description];
   393 
   394 	case RAZOR_DETAIL_URL:
   395 		pool = set->details_string_pool.data;
   396 		return &pool[package->url];
   397 
   398 	case RAZOR_DETAIL_LICENSE:
   399 		pool = set->details_string_pool.data;
   400 		return &pool[package->license];
   401 
   402 	default:
   403 		fprintf(stderr, "type %u not found\n", type);
   404 		return NULL;
   405 	}
   406 }
   407 
   408 /**
   409  * razor_package_get_details_varg:
   410  * @set: a %razor_set
   411  * @package: a %razor_package
   412  * @args: a va_list of arguments to set
   413  **/
   414 void
   415 razor_package_get_details_varg(struct razor_set *set,
   416 			       struct razor_package *package,
   417 			       va_list args)
   418 {
   419 	int i;
   420 	enum razor_detail_type type;
   421 	const char **data;
   422 
   423 	for (i = 0;; i += 2) {
   424 		type = va_arg(args, enum razor_detail_type);
   425 		if (type == RAZOR_DETAIL_LAST)
   426 			break;
   427 		data = va_arg(args, const char **);
   428 		*data = razor_package_get_details_type(set, package, type);
   429 	}
   430 
   431 }
   432 
   433 /**
   434  * razor_package_get_details:
   435  * @set: a %razor_set
   436  * @package: a %razor_package
   437  *
   438  * Gets details about a package using a varg interface
   439  * The vararg must be terminated with %RAZOR_DETAIL_LAST.
   440  *
   441  * Example: razor_package_get_details (set, package,
   442  *				       RAZOR_DETAIL_URL, &url,
   443  *				       RAZOR_DETAIL_LAST);
   444  **/
   445 RAZOR_EXPORT void
   446 razor_package_get_details(struct razor_set *set, struct razor_package *package, ...)
   447 {
   448 	va_list args;
   449 
   450 	assert (set != NULL);
   451 	assert (package != NULL);
   452 
   453 	va_start(args, NULL);
   454 	razor_package_get_details_varg (set, package, args);
   455 	va_end (args);
   456 }
   457 
   458 RAZOR_EXPORT const char *
   459 razor_property_relation_to_string(struct razor_property *p)
   460 {
   461 	assert (p != NULL);
   462 
   463 	switch (p->flags & RAZOR_PROPERTY_RELATION_MASK) {
   464 	case RAZOR_PROPERTY_LESS:
   465 		return "<";
   466 
   467 	case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL:
   468 		return "<=";
   469 
   470 	case RAZOR_PROPERTY_EQUAL:
   471 		return "=";
   472 
   473 	case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL:
   474 		return ">=";
   475 
   476 	case RAZOR_PROPERTY_GREATER:
   477 		return ">";
   478 
   479 	default:
   480 		return "?";
   481 	}
   482 }
   483 
   484 RAZOR_EXPORT const char *
   485 razor_property_type_to_string(struct razor_property *p)
   486 {
   487 	assert (p != NULL);
   488 
   489 	switch (p->flags & RAZOR_PROPERTY_TYPE_MASK) {
   490 	case RAZOR_PROPERTY_REQUIRES:
   491 		return "requires";
   492 	case RAZOR_PROPERTY_PROVIDES:
   493 		return "provides";
   494 	case RAZOR_PROPERTY_CONFLICTS:
   495 		return "conflicts";
   496 	case RAZOR_PROPERTY_OBSOLETES:
   497 		return "obsoletes";
   498 	default:
   499 		return NULL;
   500 	}
   501 }
   502 
   503 RAZOR_EXPORT struct razor_entry *
   504 razor_set_find_entry(struct razor_set *set,
   505 		     struct razor_entry *dir, const char *pattern)
   506 {
   507 	struct razor_entry *e, *subdir;
   508 	const char *n, *pool = set->file_string_pool.data;
   509 	int len;
   510 
   511 	assert (set != NULL);
   512 	assert (dir != NULL);
   513 	assert (pattern != NULL);
   514 
   515 	e = dir;
   516 	do {
   517 		n = pool + e->name;
   518 		if (strcmp(pattern, n) == 0)
   519 			return e;
   520 		len = strlen(n);
   521 		if (e->start != 0 && strncmp(pattern, n, len) == 0 &&
   522 		    pattern[len] == '/') {
   523 			subdir = (struct razor_entry *) set->files.data +
   524 				 e->start;
   525 			return razor_set_find_entry(set, subdir,
   526 						    pattern + len + 1);
   527 		}
   528 	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
   529 
   530 	return NULL;
   531 }
   532 
   533 static void
   534 list_dir(struct razor_set *set, struct razor_entry *dir,
   535 	 char *prefix, const char *pattern)
   536 {
   537 	struct razor_entry *e, *subdir;
   538 	const char *n, *pool = set->file_string_pool.data;
   539 
   540 	e = dir;
   541 	do {
   542 		n = pool + e->name;
   543 		if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
   544 			continue;
   545 		printf("%s/%s\n", prefix, n);
   546 		if (e->start) {
   547 			char *sub = prefix + strlen (prefix);
   548 			*sub = '/';
   549 			strcpy (sub + 1, n);
   550 			subdir = (struct razor_entry *) set->files.data +
   551 				 e->start;
   552 			list_dir(set, subdir, prefix, pattern);
   553 			*sub = '\0';
   554 		}
   555 	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
   556 }
   557 
   558 RAZOR_EXPORT void
   559 razor_set_list_files(struct razor_set *set, const char *pattern)
   560 {
   561 	struct razor_entry *root, *e;
   562 	char buffer[512], *p, *base;
   563 
   564 	assert (set != NULL);
   565 
   566 	root = (struct razor_entry *) set->files.data;
   567 
   568 	if (pattern == NULL) {
   569 		p = set->file_string_pool.data;
   570 		e = root;
   571 		do {
   572 			if (e->start) {
   573 				strcpy(buffer, p + e->name);
   574 				list_dir(set, root + e->start, buffer, NULL);
   575 			}
   576 		} while (!((e++)->flags & RAZOR_ENTRY_LAST));
   577 		return;
   578 	}
   579 
   580 	strcpy(buffer, pattern);
   581 	e = razor_set_find_entry(set, root, buffer);
   582 	if (e && e->start) {
   583 		base = NULL;
   584 	} else {
   585 		p = strrchr(buffer, '/');
   586 		if (p) {
   587 			*p = '\0';
   588 			base = p + 1;
   589 		} else {
   590 			base = NULL;
   591 		}
   592 	}
   593 	e = razor_set_find_entry(set, root, buffer);
   594 	if (e && e->start)
   595 		list_dir(set, root + e->start, buffer, base);
   596 }
   597 
   598 RAZOR_EXPORT void
   599 razor_set_list_package_files(struct razor_set *set,
   600 			     struct razor_package *package)
   601 {
   602 	struct razor_file_iterator *fi;
   603 	const char *name;
   604 
   605 	assert (set != NULL);
   606 	assert (package != NULL);
   607 
   608 	fi = razor_file_iterator_create(set, package);
   609 
   610 	while (razor_file_iterator_next(fi, &name))
   611 		printf("%s\n", name);
   612 
   613 	razor_file_iterator_destroy(fi);
   614 }
   615 
   616 /* The diff order matters.  We should sort the packages so that a
   617  * REMOVE of a package comes before the INSTALL, and so that all
   618  * requires for a package have been installed before the package.
   619  **/
   620 
   621 RAZOR_EXPORT void
   622 razor_set_diff(struct razor_set *set, struct razor_set *upstream,
   623 	       razor_diff_callback_t callback, void *data)
   624 {
   625  	struct razor_package_iterator *pi1, *pi2;
   626  	struct razor_package *p1, *p2;
   627 	const char *name1, *name2, *version1, *version2, *arch1, *arch2;
   628 	int res;
   629 
   630 	assert (set != NULL);
   631 	assert (upstream != NULL);
   632 
   633 	pi1 = razor_package_iterator_create(set);
   634 	pi2 = razor_package_iterator_create(upstream);
   635 
   636 	razor_package_iterator_next(pi1, &p1,
   637 				    RAZOR_DETAIL_NAME, &name1,
   638 				    RAZOR_DETAIL_VERSION, &version1,
   639 				    RAZOR_DETAIL_ARCH, &arch1,
   640 				    RAZOR_DETAIL_LAST);
   641 	razor_package_iterator_next(pi2, &p2,
   642 				    RAZOR_DETAIL_NAME, &name2,
   643 				    RAZOR_DETAIL_VERSION, &version2,
   644 				    RAZOR_DETAIL_ARCH, &arch2,
   645 				    RAZOR_DETAIL_LAST);
   646 
   647 	while (p1 || p2) {
   648 		if (p1 && p2) {
   649 			res = strcmp(name1, name2);
   650 			if (res == 0)
   651 				res = razor_versioncmp(version1, version2);
   652 		} else {
   653 			res = 0;
   654 		}
   655 
   656 		if (p2 == NULL || res < 0)
   657 			callback(RAZOR_DIFF_ACTION_REMOVE,
   658 				 p1, name1, version1, arch1, data);
   659 		else if (p1 == NULL || res > 0)
   660 			callback(RAZOR_DIFF_ACTION_ADD,
   661 				 p2, name2, version2, arch2, data);
   662 
   663 		if (p1 != NULL && res <= 0)
   664 			razor_package_iterator_next(pi1, &p1,
   665 						    RAZOR_DETAIL_NAME, &name1,
   666 						    RAZOR_DETAIL_VERSION, &version1,
   667 						    RAZOR_DETAIL_ARCH, &arch1,
   668 						    RAZOR_DETAIL_LAST);
   669 		if (p2 != NULL && res >= 0)
   670 			razor_package_iterator_next(pi2, &p2,
   671 						    RAZOR_DETAIL_NAME, &name2,
   672 						    RAZOR_DETAIL_VERSION, &version2,
   673 						    RAZOR_DETAIL_ARCH, &arch2,
   674 						    RAZOR_DETAIL_LAST);
   675 	}
   676 
   677 	razor_package_iterator_destroy(pi1);
   678 	razor_package_iterator_destroy(pi2);
   679 }
   680 
   681 struct install_action {
   682 	enum razor_install_action action;
   683 	struct razor_package *package;
   684 };
   685 
   686 struct razor_install_iterator {
   687 	struct razor_set *set;
   688 	struct razor_set *next;
   689 	struct array actions;
   690 	struct install_action *a, *end;
   691 };
   692 
   693 static void
   694 add_action(enum razor_diff_action action,
   695 	   struct razor_package *package,
   696 	   const char *name,
   697 	   const char *version,
   698 	   const char *arch,
   699 	   void *data)
   700 {
   701 	struct razor_install_iterator *ii = data;
   702 	struct install_action *a;
   703 
   704 	a = array_add(&ii->actions, sizeof *a);
   705 	a->package = package;
   706 
   707 	switch (action) {
   708 	case RAZOR_DIFF_ACTION_ADD:
   709 		a->action = RAZOR_INSTALL_ACTION_ADD;
   710 		break;
   711 	case RAZOR_DIFF_ACTION_REMOVE:
   712 		a->action = RAZOR_INSTALL_ACTION_REMOVE;
   713 		break;
   714 	}
   715 }
   716 
   717 RAZOR_EXPORT struct razor_install_iterator *
   718 razor_set_create_install_iterator(struct razor_set *set,
   719 				  struct razor_set *next)
   720 {
   721 	struct razor_install_iterator *ii;
   722 
   723 	assert (set != NULL);
   724 	assert (next != NULL);
   725 
   726 	ii = zalloc(sizeof *ii);
   727 	ii->set = set;
   728 	ii->next = next;
   729 	
   730 	razor_set_diff(set, next, add_action, ii);
   731 
   732 	ii->a = ii->actions.data;
   733 	ii->end = ii->actions.data + ii->actions.size;
   734 
   735 	/* FIXME: We need to figure out the right install order here,
   736 	 * so the post and pre scripts can run. */
   737 
   738 	return ii;
   739 }
   740 
   741 RAZOR_EXPORT int
   742 razor_install_iterator_next(struct razor_install_iterator *ii,
   743 			    struct razor_set **set,
   744 			    struct razor_package **package,
   745 			    enum razor_install_action *action,
   746 			    int *count)
   747 {
   748 	if (ii->a == ii->end)
   749 		return 0;
   750 
   751 	switch (ii->a->action) {
   752 	case RAZOR_INSTALL_ACTION_ADD:
   753 		*set = ii->next;
   754 		break;
   755 	case RAZOR_INSTALL_ACTION_REMOVE:
   756 		*set = ii->set;
   757 		break;
   758 	}
   759 
   760 	*package = ii->a->package;
   761 	*action = ii->a->action;
   762 	*count = 0;
   763 	ii->a++;
   764 
   765 	return 1;
   766 }
   767 
   768 RAZOR_EXPORT void
   769 razor_install_iterator_destroy(struct razor_install_iterator *ii)
   770 {
   771 	array_release(&ii->actions);
   772 	free(ii);
   773 }