librazor/razor.c
author Kristian H?gsberg <krh@redhat.com>
Sat Jun 28 20:34:29 2008 -0400 (2008-06-28)
changeset 299 d4f7f167b8bb
parent 288 75da311eda45
parent 296 4531b1390261
child 301 4124c37fd953
permissions -rw-r--r--
Remove a couple of done TODO items.
     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 <stdlib.h>
    23 #include <stddef.h>
    24 #include <stdint.h>
    25 #include <stdio.h>
    26 #include <string.h>
    27 #include <sys/types.h>
    28 #include <sys/stat.h>
    29 #include <sys/mman.h>
    30 #include <unistd.h>
    31 #include <fcntl.h>
    32 #include <errno.h>
    33 #include <ctype.h>
    34 #include <fnmatch.h>
    35 
    36 #include "razor-internal.h"
    37 #include "razor.h"
    38 
    39 void *
    40 zalloc(size_t size)
    41 {
    42 	void *p;
    43 
    44 	p = malloc(size);
    45 	memset(p, 0, size);
    46 
    47 	return p;
    48 }
    49 
    50 struct razor_set_section razor_sections[] = {
    51 	{ RAZOR_STRING_POOL,	offsetof(struct razor_set, string_pool) },
    52 	{ RAZOR_PACKAGES,	offsetof(struct razor_set, packages) },
    53 	{ RAZOR_PROPERTIES,	offsetof(struct razor_set, properties) },
    54 	{ RAZOR_PACKAGE_POOL,	offsetof(struct razor_set, package_pool) },
    55 	{ RAZOR_PROPERTY_POOL,	offsetof(struct razor_set, property_pool) },
    56 };
    57 
    58 struct razor_set_section razor_files_sections[] = {
    59 	{ RAZOR_FILES,			offsetof(struct razor_set, files) },
    60 	{ RAZOR_FILE_POOL,		offsetof(struct razor_set, file_pool) },
    61 	{ RAZOR_FILE_STRING_POOL,	offsetof(struct razor_set, file_string_pool) },
    62 };
    63 
    64 struct razor_set_section razor_details_sections[] = {
    65 	{ RAZOR_DETAILS_STRING_POOL,	offsetof(struct razor_set, details_string_pool) },
    66 };
    67 
    68 RAZOR_EXPORT struct razor_set *
    69 razor_set_create(void)
    70 {
    71 	struct razor_set *set;
    72 	struct razor_entry *e;
    73 	char *empty;
    74 
    75 	set = zalloc(sizeof *set);
    76 
    77 	e = array_add(&set->files, sizeof *e);
    78 	empty = array_add(&set->string_pool, 1);
    79 	*empty = '\0';
    80 	e->name = 0;
    81 	e->flags = RAZOR_ENTRY_LAST;
    82 	e->start = 0;
    83 	list_set_empty(&e->packages);
    84 
    85 	return set;
    86 }
    87 
    88 RAZOR_EXPORT struct razor_set *
    89 razor_set_open(const char *filename)
    90 {
    91 	struct razor_set *set;
    92 	struct razor_set_section *s;
    93 	struct stat stat;
    94 	struct array *array;
    95 	int fd;
    96 
    97 	set = zalloc(sizeof *set);
    98 	fd = open(filename, O_RDONLY);
    99 	if (fstat(fd, &stat) < 0)
   100 		return NULL;
   101 	set->header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
   102 	if (set->header == MAP_FAILED) {
   103 		free(set);
   104 		return NULL;
   105 	}
   106 
   107 	for (s = set->header->sections; ~s->type; s++) {
   108 		if (s->type >= ARRAY_SIZE(razor_sections))
   109 			continue;
   110 		if (s->type != razor_sections[s->type].type)
   111 			continue;
   112 		array = (void *) set + razor_sections[s->type].offset;
   113 		array->data = (void *) set->header + s->offset;
   114 		array->size = s->size;
   115 		array->alloc = s->size;
   116 	}
   117 	close(fd);
   118 
   119 	return set;
   120 }
   121 
   122 RAZOR_EXPORT int
   123 razor_set_open_details(struct razor_set *set, const char *filename)
   124 {
   125 	struct razor_set_section *s;
   126 	struct stat stat;
   127 	struct array *array;
   128 	int fd;
   129 
   130 	fd = open(filename, O_RDONLY);
   131 	if (fstat(fd, &stat) < 0)
   132 		return -1;
   133 	set->details_header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
   134 	if (set->details_header == MAP_FAILED)
   135 		return -1;
   136 
   137 	for (s = set->details_header->sections; ~s->type; s++) {
   138 		if (s->type >= ARRAY_SIZE(razor_details_sections))
   139 			continue;
   140 		if (s->type != razor_details_sections[s->type].type)
   141 			continue;
   142 		array = (void *) set + razor_details_sections[s->type].offset;
   143 		array->data = (void *) set->details_header + s->offset;
   144 		array->size = s->size;
   145 		array->alloc = s->size;
   146 	}
   147 	close(fd);
   148 
   149 	return 0;
   150 }
   151 
   152 RAZOR_EXPORT int
   153 razor_set_open_files(struct razor_set *set, const char *filename)
   154 {
   155 	struct razor_set_section *s;
   156 	struct stat stat;
   157 	struct array *array;
   158 	int fd;
   159 
   160 	fd = open(filename, O_RDONLY);
   161 	if (fstat(fd, &stat) < 0)
   162 		return -1;
   163 	set->files_header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
   164 	if (set->files_header == MAP_FAILED)
   165 		return -1;
   166 
   167 	for (s = set->files_header->sections; ~s->type; s++) {
   168 		if (s->type >= ARRAY_SIZE(razor_files_sections))
   169 			continue;
   170 		if (s->type != razor_files_sections[s->type].type)
   171 			continue;
   172 		array = (void *) set + razor_files_sections[s->type].offset;
   173 		array->data = (void *) set->files_header + s->offset;
   174 		array->size = s->size;
   175 		array->alloc = s->size;
   176 	}
   177 	close(fd);
   178 
   179 	return 0;
   180 }
   181 
   182 RAZOR_EXPORT void
   183 razor_set_destroy(struct razor_set *set)
   184 {
   185 	unsigned int size;
   186 	struct array *a;
   187 	int i;
   188 
   189 	if (set->header) {
   190 		for (i = 0; set->header->sections[i].type; i++)
   191 			;
   192 		size = set->header->sections[i].type;
   193 		munmap(set->header, size);
   194 	} else {
   195 		for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
   196 			a = (void *) set + razor_sections[i].offset;
   197 			free(a->data);
   198 		}
   199 	}
   200 
   201 	if (set->details_header) {
   202 		for (i = 0; set->details_header->sections[i].type; i++)
   203 			;
   204 		size = set->details_header->sections[i].type;
   205 		munmap(set->details_header, size);
   206 	} else {
   207 		for (i = 0; i < ARRAY_SIZE(razor_details_sections); i++) {
   208 			a = (void *) set + razor_details_sections[i].offset;
   209 			free(a->data);
   210 		}
   211 	}
   212 
   213 	if (set->files_header) {
   214 		for (i = 0; set->files_header->sections[i].type; i++)
   215 			;
   216 		size = set->files_header->sections[i].type;
   217 		munmap(set->files_header, size);
   218 	} else {
   219 		for (i = 0; i < ARRAY_SIZE(razor_files_sections); i++) {
   220 			a = (void *) set + razor_files_sections[i].offset;
   221 			free(a->data);
   222 		}
   223 	}
   224 
   225 	free(set);
   226 }
   227 
   228 static int
   229 razor_set_write_sections_to_fd(struct razor_set *set, int fd, int magic,
   230 			       struct razor_set_section *sections,
   231 			       size_t array_size)
   232 {
   233 	char data[4096];
   234 	struct razor_set_header *header = (struct razor_set_header *) data;
   235 	struct array *a;
   236 	uint32_t offset;
   237 	int i;
   238 
   239 	memset(data, 0, sizeof data);
   240 	header->magic = magic;
   241 	header->version = RAZOR_VERSION;
   242 	offset = sizeof data;
   243 
   244 	for (i = 0; i < array_size; i++) {
   245 		if (sections[i].type != i)
   246 			continue;
   247 		a = (void *) set + sections[i].offset;
   248 		header->sections[i].type = i;
   249 		header->sections[i].offset = offset;
   250 		header->sections[i].size = a->size;
   251 		offset += ALIGN(a->size, 4096);
   252 	}
   253 
   254 	header->sections[i].type = ~0;
   255 	header->sections[i].offset = 0;
   256 	header->sections[i].size = 0;
   257 
   258 	razor_write(fd, data, sizeof data);
   259 	memset(data, 0, sizeof data);
   260 	for (i = 0; i < array_size; i++) {
   261 		if (sections[i].type != i)
   262 			continue;
   263 		a = (void *) set + sections[i].offset;
   264 		razor_write(fd, a->data, a->size);
   265 		razor_write(fd, data, ALIGN(a->size, 4096) - a->size);
   266 	}
   267 
   268 	return 0;
   269 }
   270 
   271 RAZOR_EXPORT int
   272 razor_set_write_to_fd(struct razor_set *set, int fd,
   273 		      enum razor_repo_file_type type)
   274 {
   275 	switch (type) {
   276 	case RAZOR_REPO_FILE_MAIN:
   277 		return razor_set_write_sections_to_fd(set, fd, RAZOR_MAGIC,
   278 						      razor_sections,
   279 						      ARRAY_SIZE(razor_sections));
   280 
   281 	case RAZOR_REPO_FILE_DETAILS:
   282 		return razor_set_write_sections_to_fd(set, fd, RAZOR_DETAILS_MAGIC,
   283 						      razor_details_sections,
   284 						      ARRAY_SIZE(razor_details_sections));
   285 	case RAZOR_REPO_FILE_FILES:
   286 		return razor_set_write_sections_to_fd(set, fd, RAZOR_FILES_MAGIC,
   287 						      razor_files_sections,
   288 						      ARRAY_SIZE(razor_files_sections));
   289 	default:
   290 		return -1;
   291 	}
   292 }
   293 
   294 RAZOR_EXPORT int
   295 razor_set_write(struct razor_set *set, const char *filename,
   296 		enum razor_repo_file_type type)
   297 {
   298 	int fd, status;
   299 
   300 	fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
   301 	if (fd < 0)
   302 		return -1;
   303 
   304 	status = razor_set_write_to_fd(set, fd, type);
   305 	if (status) {
   306 	    close(fd);
   307 	    return status;
   308 	}
   309 
   310 	return close(fd);
   311 }
   312 
   313 RAZOR_EXPORT void
   314 razor_build_evr(char *evr_buf, int size, const char *epoch,
   315 		const char *version, const char *release)
   316 {
   317 	int len;
   318 
   319 	if (!version || !*version) {
   320 		*evr_buf = '\0';
   321 		return;
   322 	}
   323 
   324 	if (epoch && *epoch && strcmp(epoch, "0") != 0) {
   325 		len = snprintf(evr_buf, size, "%s:", epoch);
   326 		evr_buf += len;
   327 		size -= len;
   328 	}
   329 	len = snprintf(evr_buf, size, "%s", version);
   330 	evr_buf += len;
   331 	size -= len;
   332 	if (release && *release)
   333 		snprintf(evr_buf, size, "-%s", release);
   334 }
   335 
   336 RAZOR_EXPORT int
   337 razor_versioncmp(const char *s1, const char *s2)
   338 {
   339 	const char *p1, *p2;
   340 	long n1, n2;
   341 	int res;
   342 
   343 	n1 = strtol(s1, (char **) &p1, 10);
   344 	n2 = strtol(s2, (char **) &p2, 10);
   345 
   346 	/* Epoch; if one but not the other has an epoch set, default
   347 	 * the epoch-less version to 0. */
   348 	res = (*p1 == ':') - (*p2 == ':');
   349 	if (res < 0) {
   350 		n1 = 0;
   351 		p1 = s1;
   352 		p2++;
   353 	} else if (res > 0) {
   354 		p1++;
   355 		n2 = 0;
   356 		p2 = s2;
   357 	}
   358 
   359 	if (n1 != n2)
   360 		return n1 - n2;
   361 	while (*p1 && *p2) {
   362 		if (*p1 != *p2)
   363 			return *p1 - *p2;
   364 		p1++;
   365 		p2++;
   366 		if (isdigit(*p1) && isdigit(*p2))
   367 			return razor_versioncmp(p1, p2);
   368 	}
   369 
   370 	return *p1 - *p2;
   371 }
   372 
   373 RAZOR_EXPORT struct razor_package *
   374 razor_set_get_package(struct razor_set *set, const char *package)
   375 {
   376 	struct razor_package_iterator *pi;
   377 	struct razor_package *p;
   378 	const char *name, *version, *arch;
   379 
   380 	pi = razor_package_iterator_create(set);
   381 	while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) {
   382 		if (strcmp(package, name) == 0)
   383 			break;
   384 	}
   385 	razor_package_iterator_destroy(pi);
   386 
   387 	return p;
   388 }
   389 
   390 RAZOR_EXPORT void
   391 razor_package_get_details(struct razor_set *set,
   392 			  struct razor_package *package,
   393 			  const char **summary, const char **description,
   394 			  const char **url, const char **license)
   395 {
   396 	const char *pool = set->details_string_pool.data;
   397 
   398 	if (summary != NULL)
   399 		*summary = &pool[package->summary];
   400 	if (description != NULL)
   401 		*description = &pool[package->description];
   402 	if (url != NULL)
   403 		*url = &pool[package->url];
   404 	if (license != NULL)
   405 		*license = &pool[package->license];
   406 }
   407 
   408 RAZOR_EXPORT const char *
   409 razor_property_relation_to_string(struct razor_property *p)
   410 {
   411 	switch (p->flags & RAZOR_PROPERTY_RELATION_MASK) {
   412 	case RAZOR_PROPERTY_LESS:
   413 		return "<";
   414 
   415 	case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL:
   416 		return "<=";
   417 
   418 	case RAZOR_PROPERTY_EQUAL:
   419 		return "=";
   420 
   421 	case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL:
   422 		return ">=";
   423 
   424 	case RAZOR_PROPERTY_GREATER:
   425 		return ">";
   426 
   427 	default:
   428 		return "?";
   429 	}
   430 }
   431 
   432 RAZOR_EXPORT const char *
   433 razor_property_type_to_string(struct razor_property *p)
   434 {
   435 	switch (p->flags & RAZOR_PROPERTY_TYPE_MASK) {
   436 	case RAZOR_PROPERTY_REQUIRES:
   437 		return "requires";
   438 	case RAZOR_PROPERTY_PROVIDES:
   439 		return "provides";
   440 	case RAZOR_PROPERTY_CONFLICTS:
   441 		return "conflicts";
   442 	case RAZOR_PROPERTY_OBSOLETES:
   443 		return "obsoletes";
   444 	default:
   445 		return NULL;
   446 	}
   447 }
   448 
   449 RAZOR_EXPORT struct razor_entry *
   450 razor_set_find_entry(struct razor_set *set,
   451 		     struct razor_entry *dir, const char *pattern)
   452 {
   453 	struct razor_entry *e;
   454 	const char *n, *pool = set->file_string_pool.data;
   455 	int len;
   456 
   457 	e = (struct razor_entry *) set->files.data + dir->start;
   458 	do {
   459 		n = pool + e->name;
   460 		if (strcmp(pattern + 1, n) == 0)
   461 			return e;
   462 		len = strlen(n);
   463 		if (e->start != 0 && strncmp(pattern + 1, n, len) == 0 &&
   464 		    pattern[len + 1] == '/') {
   465 			return razor_set_find_entry(set, e, pattern + len + 1);
   466 		}
   467 	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
   468 
   469 	return NULL;
   470 }
   471 
   472 static void
   473 list_dir(struct razor_set *set, struct razor_entry *dir,
   474 	 char *prefix, const char *pattern)
   475 {
   476 	struct razor_entry *e;
   477 	const char *n, *pool = set->file_string_pool.data;
   478 
   479 	e = (struct razor_entry *) set->files.data + dir->start;
   480 	do {
   481 		n = pool + e->name;
   482 		if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
   483 			continue;
   484 		printf("%s/%s\n", prefix, n);
   485 		if (e->start) {
   486 			char *sub = prefix + strlen (prefix);
   487 			*sub = '/';
   488 			strcpy (sub + 1, n);
   489 			list_dir(set, e, prefix, pattern);
   490 			*sub = '\0';
   491 		}
   492 	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
   493 }
   494 
   495 RAZOR_EXPORT void
   496 razor_set_list_files(struct razor_set *set, const char *pattern)
   497 {
   498 	struct razor_entry *e;
   499 	char buffer[512], *p, *base;
   500 
   501 	if (pattern == NULL || !strcmp (pattern, "/")) {
   502 		buffer[0] = '\0';
   503 		list_dir(set, set->files.data, buffer, NULL);
   504 		return;
   505 	}
   506 
   507 	strcpy(buffer, pattern);
   508 	e = razor_set_find_entry(set, set->files.data, buffer);
   509 	if (e && e->start > 0) {
   510 		base = NULL;
   511 	} else {
   512 		p = strrchr(buffer, '/');
   513 		if (p) {
   514 			*p = '\0';
   515 			base = p + 1;
   516 		} else {
   517 			base = NULL;
   518 		}
   519 	}
   520 	e = razor_set_find_entry(set, set->files.data, buffer);
   521 	if (e && e->start != 0)
   522 		list_dir(set, e, buffer, base);
   523 }
   524 
   525 static struct list *
   526 list_package_files(struct razor_set *set, struct list *r,
   527 		   struct razor_entry *dir, uint32_t end,
   528 		   char *prefix)
   529 {
   530 	struct razor_entry *e, *f, *entries;
   531 	uint32_t next, file;
   532 	char *pool;
   533 	int len;
   534 
   535 	entries = (struct razor_entry *) set->files.data;
   536 	pool = set->file_string_pool.data;
   537 
   538 	e = entries + dir->start;
   539 	do {
   540 		if (entries + r->data == e) {
   541 			printf("%s/%s\n", prefix, pool + e->name);
   542 			r = list_next(r);
   543 			if (!r)
   544 				return NULL;
   545 			if (r->data >= end)
   546 				return r;
   547 		}
   548 	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
   549 
   550 	e = entries + dir->start;
   551 	do {
   552 		if (e->start == 0)
   553 			continue;
   554 
   555 		if (e->flags & RAZOR_ENTRY_LAST)
   556 			next = end;
   557 		else {
   558 			f = e + 1;
   559 			while (f->start == 0 && !(f->flags & RAZOR_ENTRY_LAST))
   560 				f++;
   561 			if (f->start == 0)
   562 				next = end;
   563 			else
   564 				next = f->start;
   565 		}
   566 
   567 		file = r->data;
   568 		if (e->start <= file && file < next) {
   569 			len = strlen(prefix);
   570 			prefix[len] = '/';
   571 			strcpy(prefix + len + 1, pool + e->name);
   572 			r = list_package_files(set, r, e, next, prefix);
   573 			prefix[len] = '\0';
   574 		}
   575 	} while (!((e++)->flags & RAZOR_ENTRY_LAST) && r != NULL);
   576 
   577 	return r;
   578 }
   579 
   580 RAZOR_EXPORT void
   581 razor_set_list_package_files(struct razor_set *set, const char *name)
   582 {
   583 	struct razor_package *package;
   584 	struct list *r;
   585 	uint32_t end;
   586 	char buffer[512];
   587 
   588 	package = razor_set_get_package(set, name);
   589 	/* TODO: we should return the error to the caller */
   590 	if (!package)
   591 		return;
   592 
   593 	r = list_first(&package->files, &set->file_pool);
   594 	end = set->files.size / sizeof (struct razor_entry);
   595 	buffer[0] = '\0';
   596 	list_package_files(set, r, set->files.data, end, buffer);
   597 }
   598 
   599 /* The diff order matters.  We should sort the packages so that a
   600  * REMOVE of a package comes before the INSTALL, and so that all
   601  * requires for a package have been installed before the package.
   602  **/
   603 
   604 RAZOR_EXPORT void
   605 razor_set_diff(struct razor_set *set, struct razor_set *upstream,
   606 	       razor_diff_callback_t callback, void *data)
   607 {
   608  	struct razor_package_iterator *pi1, *pi2;
   609  	struct razor_package *p1, *p2;
   610 	const char *name1, *name2, *version1, *version2, *arch1, *arch2;
   611 	int res;
   612 
   613 	pi1 = razor_package_iterator_create(set);
   614 	pi2 = razor_package_iterator_create(upstream);
   615 
   616 	razor_package_iterator_next(pi1, &p1, &name1, &version1, &arch1);
   617 	razor_package_iterator_next(pi2, &p2, &name2, &version2, &arch2);
   618 
   619 	while (p1 || p2) {
   620 		if (p1 && p2) {
   621 			res = strcmp(name1, name2);
   622 			if (res == 0)
   623 				res = razor_versioncmp(version1, version2);
   624 		} else {
   625 			res = 0;
   626 		}
   627 
   628 		if (p2 == NULL || res < 0)
   629 			callback(RAZOR_DIFF_ACTION_REMOVE,
   630 				 p1, name1, version1, arch1, data);
   631 		else if (p1 == NULL || res > 0)
   632 			callback(RAZOR_DIFF_ACTION_ADD,
   633 				 p2, name2, version2, arch2, data);
   634 
   635 		if (p1 != NULL && res <= 0)
   636 			razor_package_iterator_next(pi1, &p1,
   637 						    &name1, &version1, &arch1);
   638 		if (p2 != NULL && res >= 0)
   639 			razor_package_iterator_next(pi2, &p2,
   640 						    &name2, &version2, &arch2);
   641 	}
   642 
   643 	razor_package_iterator_destroy(pi1);
   644 	razor_package_iterator_destroy(pi2);
   645 }
   646 
   647 static void
   648 add_new_package(enum razor_diff_action action,
   649 		struct razor_package *package,
   650 		const char *name,
   651 		const char *version,
   652 		const char *arch,
   653 		void *data)
   654 {
   655 	if (action == RAZOR_DIFF_ACTION_ADD)
   656 		razor_package_query_add_package(data, package);
   657 }
   658 
   659 RAZOR_EXPORT struct razor_package_iterator *
   660 razor_set_create_remove_iterator(struct razor_set *set,
   661 				 struct razor_set *next)
   662 {
   663 	struct razor_package_query *query;
   664 	struct razor_package_iterator *pi;
   665 
   666 	query = razor_package_query_create(set);
   667 	razor_set_diff(next, set, add_new_package, query);
   668 
   669 	pi = razor_package_query_finish(query);
   670 
   671 	/* FIXME: We need to figure out the right install order here,
   672 	 * so the post and pre scripts can run. */
   673 
   674 	/* sort */
   675 
   676 	return pi;
   677 }
   678 
   679 RAZOR_EXPORT struct razor_package_iterator *
   680 razor_set_create_install_iterator(struct razor_set *set,
   681 				  struct razor_set *next)
   682 {
   683 	struct razor_package_query *query;
   684 	struct razor_package_iterator *pi;
   685 
   686 	query = razor_package_query_create(next);
   687 	razor_set_diff(set, next, add_new_package, query);
   688 
   689 	pi = razor_package_query_finish(query);
   690 
   691 	/* FIXME: We need to figure out the right install order here,
   692 	 * so the post and pre scripts can run. */
   693 
   694 	/* sort */
   695 
   696 	return pi;
   697 }