librazor/razor.c
author J. Ali Harlow <ali@juiblex.co.uk>
Sat Feb 11 23:50:26 2012 +0000 (2012-02-11)
changeset 423 6112bcc5d1cf
parent 418 33b825d3128d
child 424 8cbc438cc298
permissions -rw-r--r--
Add an error object.
This is intended to dis-entangle the two roles that the atomic
object has evolved into so that atomic need only be used where
atomic actions are actually being undertaken.
     1 /*
     2  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     3  * Copyright (C) 2008  Red Hat, Inc
     4  * Copyright (C) 2009-2012  J. Ali Harlow <ali@juiblex.co.uk>
     5  *
     6  * This program is free software; you can redistribute it and/or modify
     7  * it under the terms of the GNU General Public License as published by
     8  * the Free Software Foundation; either version 2 of the License, or
     9  * (at your option) any later version.
    10  *
    11  * This program is distributed in the hope that it will be useful,
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  * GNU General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU General Public License along
    17  * with this program; if not, write to the Free Software Foundation, Inc.,
    18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    19  */
    20 
    21 #define _GNU_SOURCE
    22 
    23 #include "config.h"
    24 
    25 #include <stdlib.h>
    26 #include <stddef.h>
    27 #include <stdint.h>
    28 #include <stdio.h>
    29 #include <stdarg.h>
    30 #include <string.h>
    31 #include <sys/types.h>
    32 #include <sys/stat.h>
    33 #include <unistd.h>
    34 #include <fcntl.h>
    35 #include <errno.h>
    36 #include <ctype.h>
    37 #include <fnmatch.h>
    38 #include <limits.h>
    39 #include <assert.h>
    40 #ifdef MSWIN_API
    41 #include <windows.h>
    42 #endif
    43 
    44 #include "razor-internal.h"
    45 #include "razor.h"
    46 
    47 #ifndef O_BINARY
    48 #define O_BINARY	0
    49 #endif
    50 
    51 void *
    52 zalloc(size_t size)
    53 {
    54 	void *p;
    55 
    56 	p = malloc(size);
    57 	memset(p, 0, size);
    58 
    59 	return p;
    60 }
    61 
    62 struct razor_set_section_index {
    63 	const char *name;
    64 	uint32_t offset;
    65 	uint32_t flags;
    66 };
    67 
    68 #define MAIN(type, field) \
    69 	{ type, offsetof(struct razor_set, field), RAZOR_SECTION_MAIN }
    70 #define FILES(type, field) \
    71 	{ type, offsetof(struct razor_set, field), RAZOR_SECTION_FILES }
    72 #define DETAILS(type, field) \
    73 	{ type, offsetof(struct razor_set, field), RAZOR_SECTION_DETAILS }
    74 
    75 struct razor_set_section_index razor_sections[] = {
    76 	MAIN(RAZOR_STRING_POOL, string_pool),
    77 	MAIN(RAZOR_PACKAGES, packages),
    78 	MAIN(RAZOR_PROPERTIES, properties),
    79 	MAIN(RAZOR_PACKAGE_POOL, package_pool),
    80 	MAIN(RAZOR_PROPERTY_POOL, property_pool),
    81 	MAIN(RAZOR_PREFIX_POOL, prefix_pool),
    82 	FILES(RAZOR_FILES, files),
    83 	FILES(RAZOR_FILE_POOL, file_pool),
    84 	FILES(RAZOR_FILE_STRING_POOL, file_string_pool),
    85 	DETAILS(RAZOR_DETAILS_STRING_POOL, details_string_pool)
    86 };
    87 
    88 RAZOR_EXPORT struct razor_set *
    89 razor_set_create_without_root(void)
    90 {
    91 	struct razor_set *set;
    92 	char *empty;
    93 
    94 	set = zalloc(sizeof *set);
    95 
    96 	if (set) {
    97 		empty = array_add(&set->string_pool, 1);
    98 		*empty = '\0';
    99 
   100 		set->lock_fd = -1;
   101 
   102 		set->ref_count = 1;
   103 
   104 		set->header_version = RAZOR_HEADER_VERSION;
   105 	}
   106 
   107 	return set;
   108 }
   109 
   110 RAZOR_EXPORT struct razor_set *
   111 razor_set_create(void)
   112 {
   113 	struct razor_set *set;
   114 	struct razor_entry *e;
   115 
   116 	set = razor_set_create_without_root();
   117 
   118 	e = array_add(&set->files, sizeof *e);
   119 	e->name = 0;
   120 	e->flags = RAZOR_ENTRY_LAST;
   121 	e->start = 0;
   122 	list_set_empty(&e->packages);
   123 
   124 	return set;
   125 }
   126 
   127 RAZOR_EXPORT uint32_t
   128 razor_set_get_header_version(struct razor_set *set)
   129 {
   130 	return set->header_version;
   131 }
   132 
   133 RAZOR_EXPORT int
   134 razor_set_set_header_version(struct razor_set *set, uint32_t header_version)
   135 {
   136 	if (header_version<RAZOR_HEADER_VERSION_MIN ||
   137 	    header_version>RAZOR_HEADER_VERSION)
   138 		return -1;
   139 	else {
   140 		set->header_version = header_version;
   141 		return 0;
   142 	}
   143 }
   144 
   145 struct razor_mapped_file {
   146 	struct razor_set_header *header;
   147 	size_t size;
   148 	struct razor_mapped_file *next;
   149 };
   150 
   151 RAZOR_EXPORT int
   152 razor_set_bind_sections(struct razor_set *set, struct razor_atomic *atomic,
   153 			const char *filename)
   154 {
   155 	struct razor_set_section *s, *sections;
   156 	struct razor_mapped_file *file;
   157 	const char *pool, *reason;
   158 	char *msg;
   159 	struct array *array;
   160 	int i, j;
   161 
   162 	file = zalloc(sizeof *file);
   163 	if (file == NULL) {
   164 		razor_atomic_abort(atomic, "Not enough memory");
   165 		return -1;
   166 	}
   167 
   168 	file->header = razor_file_get_contents(filename, &file->size);
   169 	if (!file->header) {
   170 		msg = razor_concat(filename, ": ", strerror(errno), NULL);
   171 		razor_atomic_abort(atomic, msg);
   172 		free(msg);
   173 		free(file);
   174 		return -1;
   175 	}
   176 
   177 	if (file->size < sizeof *file->header)
   178 		reason = "Premature EOF";
   179 	else if (file->header->magic != RAZOR_MAGIC)
   180 		reason = "Bad magic number";
   181 	else if (file->header->version < RAZOR_HEADER_VERSION_MIN ||
   182 		 file->header->version > RAZOR_HEADER_VERSION)
   183 		reason = "Incompatible file version";
   184 	else
   185 		reason = NULL;
   186 
   187 	if (reason) {
   188 		msg = razor_concat(filename, ": ", reason, NULL);
   189 		razor_atomic_abort(atomic, msg);
   190 		free(msg);
   191 		razor_file_free_contents(file->header, file->size);
   192 		free(file);
   193 		return -1;
   194 	}
   195 
   196 	set->header_version = file->header->version;
   197 
   198 	if (set->mapped_files == NULL) {
   199 		for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
   200 			array = (void *) set + razor_sections[i].offset;
   201 			array_release(array);
   202 		}
   203 	}
   204 
   205 	file->next = set->mapped_files;
   206 	set->mapped_files = file;
   207 
   208 	sections = (void *) file->header + sizeof *file->header;
   209 	pool = (void *) sections +
   210 		file->header->num_sections * sizeof *sections;
   211 
   212 	for (i = 0; i < file->header->num_sections; i++) {
   213 		s = sections + i;
   214 		for (j = 0; j < ARRAY_SIZE(razor_sections); j++)
   215 			if (!strcmp(razor_sections[j].name, &pool[s->name]))
   216 				break;
   217 		if (j == ARRAY_SIZE(razor_sections))
   218 			continue;
   219 		array = (void *) set + razor_sections[j].offset;
   220 		array->data = (void *) file->header + s->offset;
   221 		array->size = s->size;
   222 		array->alloc = s->size;
   223 	}
   224 
   225 	return 0;
   226 }
   227 
   228 RAZOR_EXPORT struct razor_set *
   229 razor_set_open(const char *filename, struct razor_atomic *atomic)
   230 {
   231 	struct razor_set *set;
   232 
   233 	set = zalloc(sizeof *set);
   234 	if (!set) {
   235 		razor_atomic_abort(atomic, "Not enough memory");
   236 		return NULL;
   237 	}
   238 
   239 	set->lock_fd = -1;
   240 	set->ref_count = 1;
   241 	if (razor_set_bind_sections(set, atomic, filename)) {
   242 		free(set);
   243 		return NULL;
   244 	}
   245 	return set;
   246 }
   247 
   248 int
   249 razor_set_aquire_lock(struct razor_set *set, const char *path, int exclusive)
   250 {
   251 	int fd;
   252 	assert(set != NULL);
   253 
   254 	if (path) {
   255 		fd = open(path, O_CREAT | O_RDWR | O_TRUNC | O_BINARY, 0666);
   256 		if (fd < 0)
   257 			return -1;
   258 	} else {
   259 		fd = -1;
   260 	}
   261 
   262 #ifdef MSWIN_API
   263 	DWORD flags = LOCKFILE_FAIL_IMMEDIATELY;
   264 	OVERLAPPED lock = {0};
   265 
   266 	if (exclusive)
   267 		flags |= LOCKFILE_EXCLUSIVE_LOCK;
   268 	if (fd >= 0 && !LockFileEx((HANDLE)_get_osfhandle(fd), flags, 0, 1, 0,
   269 				   &lock)) {
   270 		close(fd);
   271 		return -1;
   272 	}
   273 	if (set->lock_fd >= 0)
   274 		(void)UnlockFile((HANDLE)_get_osfhandle(set->lock_fd), 0, 0, 1,
   275 				 0);
   276 #else
   277 	struct flock lock = {0};
   278 
   279 	lock.l_type = exclusive ? F_WRLCK : F_RDLCK;
   280 	lock.l_whence = SEEK_SET;
   281 	lock.l_start = 0;
   282 	lock.l_len = 0;
   283 	if (fd >= 0 && fcntl(fd, F_SETLK, &lock) < 0) {
   284 		close(fd);
   285 		return -1;
   286 	}
   287 	if (set->lock_fd >= 0) {
   288 		lock.l_type = F_UNLCK;
   289 		(void)fcntl(set->lock_fd, F_SETLK, &lock);
   290 	}
   291 #endif
   292 
   293 	if (set->lock_fd >= 0)
   294 		close(set->lock_fd);
   295 	set->lock_fd = fd;
   296 
   297 	return 0;
   298 }
   299 
   300 static void
   301 razor_set_destroy(struct razor_set *set)
   302 {
   303 	struct razor_mapped_file *file, *next;
   304 	struct array *array;
   305 	int i;
   306 
   307 	assert (set != NULL);
   308 
   309 	if (set->mapped_files == NULL) {
   310 		for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
   311 			array = (void *) set + razor_sections[i].offset;
   312 			array_release(array);
   313 		}
   314 	} else {
   315 		for (file = set->mapped_files; file != NULL; file = next) {
   316 			next = file->next;
   317 			razor_file_free_contents(file->header, file->size);
   318 			free(file);
   319 		}
   320 	}
   321 
   322 	razor_set_aquire_lock(set, NULL, 0);
   323 	free(set);
   324 }
   325 
   326 RAZOR_EXPORT void
   327 razor_set_unref(struct razor_set *set)
   328 {
   329 	if (set && !--set->ref_count)
   330 		razor_set_destroy(set);
   331 }
   332 
   333 RAZOR_EXPORT struct razor_set *
   334 razor_set_ref(struct razor_set *set)
   335 {
   336 	if (set)
   337 		set->ref_count++;
   338 	return set;
   339 }
   340 
   341 RAZOR_EXPORT void
   342 razor_set_write_to_handle(struct razor_set *set, struct razor_atomic *atomic,
   343 			  int handle, uint32_t section_mask)
   344 {
   345 	struct razor_set_header header;
   346 	struct razor_set_section sections[ARRAY_SIZE(razor_sections)];
   347 	struct hashtable table;
   348 	struct array pool, *arrays[ARRAY_SIZE(razor_sections)];
   349 	uint32_t offset;
   350 	int count, i, j;
   351 	static const char padding[4];
   352 
   353 	array_init(&pool);
   354 	hashtable_init(&table, &pool);
   355 
   356 	j = 0;
   357 	for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
   358 		if ((razor_sections[i].flags & section_mask) == 0)
   359 			continue;
   360 
   361 		arrays[j] = (void *) set + razor_sections[i].offset;
   362 		sections[j].name =
   363 			hashtable_tokenize(&table, razor_sections[i].name);
   364 		j++;
   365 	}
   366 
   367 	count = j;
   368 	header.magic = RAZOR_MAGIC;
   369 	header.version = set->header_version;
   370 	header.num_sections = count;
   371 	offset = sizeof header + count * sizeof *sections + ALIGN(pool.size, 4);
   372 
   373 	for (i = 0; i < count; i++) {
   374 		sections[i].offset = offset;
   375 		sections[i].size = arrays[i]->size;
   376 		offset += ALIGN(arrays[i]->size, 4);
   377 	}
   378 
   379 	razor_atomic_write(atomic, handle, &header, sizeof header);
   380 	razor_atomic_write(atomic, handle, sections, count * sizeof *sections);
   381 	razor_atomic_write(atomic, handle, pool.data, pool.size);
   382 	razor_atomic_write(atomic, handle, padding, PADDING(pool.size, 4));
   383 
   384 	for (i = 0; i < count; i++) {
   385 		razor_atomic_write(atomic, handle, arrays[i]->data,
   386 				   arrays[i]->size);
   387 		razor_atomic_write(atomic, handle, padding,
   388 				   PADDING(arrays[i]->size, 4));
   389 	}
   390 
   391 	array_release(&pool);
   392 	hashtable_release(&table);
   393 }
   394 
   395 RAZOR_EXPORT int
   396 razor_set_write(struct razor_set *set, struct razor_atomic *atomic,
   397 		const char *filename, uint32_t sections)
   398 {
   399 	int h;
   400 
   401 	h = razor_atomic_create_file(atomic, filename,
   402 				     S_IRWXU | S_IRWXG | S_IRWXO);
   403 	if (h < 0)
   404 		return -1;
   405 
   406 	razor_set_write_to_handle(set, atomic, h, sections);
   407 
   408 	return razor_atomic_close(atomic, h);
   409 }
   410 
   411 RAZOR_EXPORT void
   412 razor_build_evr(char *evr_buf, int size, const char *epoch,
   413 		const char *version, const char *release)
   414 {
   415 	int len;
   416 
   417 	if (!version || !*version) {
   418 		*evr_buf = '\0';
   419 		return;
   420 	}
   421 
   422 	if (epoch && *epoch && strcmp(epoch, "0") != 0) {
   423 		len = snprintf(evr_buf, size, "%s:", epoch);
   424 		evr_buf += len;
   425 		size -= len;
   426 	}
   427 	len = snprintf(evr_buf, size, "%s", version);
   428 	evr_buf += len;
   429 	size -= len;
   430 	if (release && *release)
   431 		snprintf(evr_buf, size, "-%s", release);
   432 }
   433 
   434 RAZOR_EXPORT int
   435 razor_versioncmp(const char *s1, const char *s2)
   436 {
   437 	const char *p1, *p2;
   438 	long n1, n2;
   439 	int res;
   440 
   441 	assert (s1 != NULL);
   442 	assert (s2 != NULL);
   443 
   444 	n1 = strtol(s1, (char **) &p1, 10);
   445 	n2 = strtol(s2, (char **) &p2, 10);
   446 
   447 	/* Epoch; if one but not the other has an epoch set, default
   448 	 * the epoch-less version to 0. */
   449 	res = (*p1 == ':') - (*p2 == ':');
   450 	if (res < 0) {
   451 		n1 = 0;
   452 		p1 = s1;
   453 		p2++;
   454 	} else if (res > 0) {
   455 		p1++;
   456 		n2 = 0;
   457 		p2 = s2;
   458 	}
   459 
   460 	if (n1 != n2)
   461 		return n1 - n2;
   462 	while (*p1 && *p2) {
   463 		if (*p1 != *p2)
   464 			return *p1 - *p2;
   465 		p1++;
   466 		p2++;
   467 		if (isdigit(*p1) && isdigit(*p2))
   468 			return razor_versioncmp(p1, p2);
   469 	}
   470 
   471 	return *p1 - *p2;
   472 }
   473 
   474 static const char *
   475 razor_package_get_details_string(struct razor_set *set,
   476 				 struct razor_package *package,
   477 				 enum razor_detail_type type)
   478 {
   479 	const char *pool;
   480 
   481 	switch (type) {
   482 	case RAZOR_DETAIL_NAME:
   483 		pool = set->string_pool.data;
   484 		return &pool[package->name];
   485 
   486 	case RAZOR_DETAIL_VERSION:
   487 		pool = set->string_pool.data;
   488 		return &pool[package->version];
   489 
   490 	case RAZOR_DETAIL_ARCH:
   491 		pool = set->string_pool.data;
   492 		return &pool[package->arch];
   493 
   494 	case RAZOR_DETAIL_SUMMARY:
   495 		if (!set->details_string_pool.size)
   496 			return "";
   497 		pool = set->details_string_pool.data;
   498 		return &pool[package->summary];
   499 
   500 	case RAZOR_DETAIL_DESCRIPTION:
   501 		if (!set->details_string_pool.size)
   502 			return "";
   503 		pool = set->details_string_pool.data;
   504 		return &pool[package->description];
   505 
   506 	case RAZOR_DETAIL_URL:
   507 		if (!set->details_string_pool.size)
   508 			return "";
   509 		pool = set->details_string_pool.data;
   510 		return &pool[package->url];
   511 
   512 	case RAZOR_DETAIL_LICENSE:
   513 		if (!set->details_string_pool.size)
   514 			return "";
   515 		pool = set->details_string_pool.data;
   516 		return &pool[package->license];
   517 
   518 	case RAZOR_DETAIL_PREUNPROG:
   519 		pool = set->string_pool.data;
   520 		return &pool[package->preun.program];
   521 
   522 	case RAZOR_DETAIL_PREUN:
   523 		pool = set->string_pool.data;
   524 		return &pool[package->preun.body];
   525 
   526 	case RAZOR_DETAIL_POSTUNPROG:
   527 		pool = set->string_pool.data;
   528 		return &pool[package->postun.program];
   529 
   530 	case RAZOR_DETAIL_POSTUN:
   531 		pool = set->string_pool.data;
   532 		return &pool[package->postun.body];
   533 
   534 	default:
   535 		fprintf(stderr, "type %u not found\n", type);
   536 		return NULL;
   537 	}
   538 }
   539 
   540 static const char *const *
   541 razor_package_get_details_array(struct razor_set *set,
   542 				struct razor_package *package,
   543 				enum razor_detail_type type)
   544 {
   545 	switch (type) {
   546 	case RAZOR_DETAIL_PREFIXES:
   547 		/* We don't track prefixes in packages. Install prefixes
   548 		 * are tracked, but we don't provide an API to get them.
   549 		 */
   550 		return NULL;
   551 
   552 	default:
   553 		fprintf(stderr, "type %u not found\n", type);
   554 		return NULL;
   555 	}
   556 }
   557 
   558 /**
   559  * razor_package_get_details_varg:
   560  * @set: a %razor_set
   561  * @package: a %razor_package
   562  * @args: a va_list of arguments to set
   563  **/
   564 void
   565 razor_package_get_details_varg(struct razor_set *set,
   566 			       struct razor_package *package,
   567 			       va_list args)
   568 {
   569 	int i;
   570 	enum razor_detail_type type;
   571 	const char **string;
   572 	const char *const **array;
   573 
   574 	for (i = 0;; i += 2) {
   575 		type = va_arg(args, enum razor_detail_type);
   576 		if (type == RAZOR_DETAIL_LAST)
   577 			break;
   578 		if (type == RAZOR_DETAIL_PREFIXES) {
   579 			array = va_arg(args, const char *const **);
   580 			*array = razor_package_get_details_array(set, package,
   581 								 type);
   582 		} else {
   583 			string = va_arg(args, const char **);
   584 			*string = razor_package_get_details_string(set, package,
   585 								   type);
   586 		}
   587 	}
   588 
   589 }
   590 
   591 /**
   592  * razor_package_get_details:
   593  * @set: a %razor_set
   594  * @package: a %razor_package
   595  *
   596  * Gets details about a package using a varg interface
   597  * The vararg must be terminated with %RAZOR_DETAIL_LAST.
   598  *
   599  * Example: razor_package_get_details (set, package,
   600  *				       RAZOR_DETAIL_URL, &url,
   601  *				       RAZOR_DETAIL_LAST);
   602  **/
   603 RAZOR_EXPORT void
   604 razor_package_get_details(struct razor_set *set, struct razor_package *package, ...)
   605 {
   606 	va_list args;
   607 
   608 	assert (set != NULL);
   609 	assert (package != NULL);
   610 
   611 	va_start(args, NULL);
   612 	razor_package_get_details_varg (set, package, args);
   613 	va_end (args);
   614 }
   615 
   616 /**
   617  * razor_package_remove:
   618  * @prev: The %razor_set before the current transaction
   619  * @next: The %razor_set after the current transaction is applied
   620  * @package: a %razor_package
   621  * @root: the root into which the package is currently installed
   622  * @install_count: the value to pass to uninstall scripts
   623  * @stage: Limit the removal to just the scripts or the files
   624  *
   625  * Removes an installed package.
   626  **/
   627 RAZOR_EXPORT int
   628 razor_package_remove(struct razor_set *prev, struct razor_set *next,
   629 		     struct razor_atomic *atomic, struct razor_package *package,
   630 		     const char *root, int install_count,
   631 		     enum razor_stage_type stage)
   632 {
   633 	struct razor_file_iterator *fi;
   634 	struct razor_package_iterator *pi;
   635 	struct razor_package *p;
   636 	char *buffer, buf[32];
   637 	const char *name, *program, *script;
   638 	int i, count, retval = 0;
   639 	struct environment env;
   640 	struct list *link;
   641 	const char *prefix;
   642 
   643 	if (stage & RAZOR_STAGE_SCRIPTS) {
   644 		environment_init(&env);
   645 		link = list_first(&package->install_prefixes,
   646 				  &prev->prefix_pool);
   647 		for (i = 0; link; i++) {
   648 			prefix = (const char *)prev->string_pool.data +
   649 				 link->data;
   650 			sprintf(buf, "RPM_INSTALL_PREFIX%d", i);
   651 			environment_add_variable(&env, buf, prefix);
   652 			link = list_next(link);
   653 		}
   654 		environment_set(&env);
   655 	}
   656 
   657 	if (stage & RAZOR_STAGE_SCRIPTS_PRE) {
   658 		razor_package_get_details(prev, package,
   659 					  RAZOR_DETAIL_PREUNPROG, &program,
   660 					  RAZOR_DETAIL_PREUN, &script,
   661 					  RAZOR_DETAIL_LAST);
   662 
   663 		retval = razor_run_script(root, RAZOR_PROPERTY_PREUN, program,
   664 					  script, install_count);
   665 	}
   666 
   667 	if (!retval && (stage & RAZOR_STAGE_FILES)) {
   668 		fi = razor_file_iterator_create(prev, package, 1);
   669 
   670 		while (razor_file_iterator_next(fi, &name)) {
   671 			pi = razor_package_iterator_create_for_file(next, name);
   672 			count = 0;
   673 			while (razor_package_iterator_next(pi, &p,
   674 							   RAZOR_DETAIL_LAST))
   675 				count++;
   676 			razor_package_iterator_destroy(pi);
   677 			if (count <= 0) {
   678 				buffer = razor_concat(root, name, NULL);
   679 				razor_atomic_remove(atomic, buffer);
   680 				free(buffer);
   681 			}
   682 		}
   683 
   684 		razor_file_iterator_destroy(fi);
   685 
   686 		retval = razor_atomic_in_error_state(atomic);
   687 	}
   688 
   689 	if (!retval && (stage & RAZOR_STAGE_SCRIPTS_POST)) {
   690 		razor_package_get_details(prev, package,
   691 					  RAZOR_DETAIL_POSTUNPROG, &program,
   692 					  RAZOR_DETAIL_POSTUN, &script,
   693 					  RAZOR_DETAIL_LAST);
   694 
   695 		retval |= razor_run_script(root, RAZOR_PROPERTY_POSTUN, program,
   696 					   script, install_count);
   697 	}
   698 
   699 	if (stage & RAZOR_STAGE_SCRIPTS) {
   700 		environment_unset(&env);
   701 		environment_release(&env);
   702 	}
   703 
   704 	return retval;
   705 }
   706 
   707 RAZOR_EXPORT const char *
   708 razor_property_relation_to_string(struct razor_property *p)
   709 {
   710 	assert (p != NULL);
   711 
   712 	switch (p->flags & RAZOR_PROPERTY_RELATION_MASK) {
   713 	case RAZOR_PROPERTY_LESS:
   714 		return "<";
   715 
   716 	case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL:
   717 		return "<=";
   718 
   719 	case RAZOR_PROPERTY_EQUAL:
   720 		return "=";
   721 
   722 	case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL:
   723 		return ">=";
   724 
   725 	case RAZOR_PROPERTY_GREATER:
   726 		return ">";
   727 
   728 	default:
   729 		return "?";
   730 	}
   731 }
   732 
   733 RAZOR_EXPORT const char *
   734 razor_property_type_to_string(struct razor_property *p)
   735 {
   736 	assert (p != NULL);
   737 
   738 	switch (p->flags & RAZOR_PROPERTY_TYPE_MASK) {
   739 	case RAZOR_PROPERTY_REQUIRES:
   740 		return "requires";
   741 	case RAZOR_PROPERTY_PROVIDES:
   742 		return "provides";
   743 	case RAZOR_PROPERTY_CONFLICTS:
   744 		return "conflicts";
   745 	case RAZOR_PROPERTY_OBSOLETES:
   746 		return "obsoletes";
   747 	default:
   748 		return NULL;
   749 	}
   750 }
   751 
   752 RAZOR_EXPORT struct razor_entry *
   753 razor_set_find_entry(struct razor_set *set,
   754 		     struct razor_entry *dir, const char *pattern)
   755 {
   756 	struct razor_entry *e, *subdir;
   757 	const char *n, *pool = set->file_string_pool.data;
   758 	int len;
   759 
   760 	assert (set != NULL);
   761 	assert (pattern != NULL);
   762 
   763 	if (dir == NULL)
   764 		return NULL;
   765 
   766 	e = dir;
   767 	do {
   768 		n = pool + e->name;
   769 		if (strcmp(pattern, n) == 0)
   770 			return e;
   771 		len = strlen(n);
   772 		if (e->start != 0 && strncmp(pattern, n, len) == 0 &&
   773 		    pattern[len] == '/') {
   774 			subdir = (struct razor_entry *) set->files.data +
   775 				 e->start;
   776 			return razor_set_find_entry(set, subdir,
   777 						    pattern + len + 1);
   778 		}
   779 	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
   780 
   781 	return NULL;
   782 }
   783 
   784 static void
   785 list_dir(struct razor_set *set, struct razor_entry *dir,
   786 	 char *prefix, const char *pattern)
   787 {
   788 	struct razor_entry *e, *subdir;
   789 	const char *n, *pool = set->file_string_pool.data;
   790 
   791 	e = dir;
   792 	do {
   793 		n = pool + e->name;
   794 		if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
   795 			continue;
   796 		printf("%s/%s\n", prefix, n);
   797 		if (e->start) {
   798 			char *sub = prefix + strlen (prefix);
   799 			*sub = '/';
   800 			strcpy (sub + 1, n);
   801 			subdir = (struct razor_entry *) set->files.data +
   802 				 e->start;
   803 			list_dir(set, subdir, prefix, pattern);
   804 			*sub = '\0';
   805 		}
   806 	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
   807 }
   808 
   809 RAZOR_EXPORT void
   810 razor_set_list_files(struct razor_set *set, const char *pattern)
   811 {
   812 	struct razor_entry *root, *e;
   813 	char buffer[512], *p, *base;
   814 
   815 	assert (set != NULL);
   816 
   817 	root = (struct razor_entry *) set->files.data;
   818 
   819 	if (pattern == NULL) {
   820 		p = set->file_string_pool.data;
   821 		e = root;
   822 		do {
   823 			if (e->start) {
   824 				strcpy(buffer, p + e->name);
   825 				list_dir(set, root + e->start, buffer, NULL);
   826 			}
   827 		} while (!((e++)->flags & RAZOR_ENTRY_LAST));
   828 		return;
   829 	}
   830 
   831 	strcpy(buffer, pattern);
   832 	e = razor_set_find_entry(set, root, buffer);
   833 	if (e && e->start) {
   834 		base = NULL;
   835 	} else {
   836 		p = strrchr(buffer, '/');
   837 		if (p) {
   838 			*p = '\0';
   839 			base = p + 1;
   840 		} else {
   841 			base = NULL;
   842 		}
   843 	}
   844 	e = razor_set_find_entry(set, root, buffer);
   845 	if (e && e->start)
   846 		list_dir(set, root + e->start, buffer, base);
   847 }
   848 
   849 RAZOR_EXPORT void
   850 razor_set_list_package_files(struct razor_set *set,
   851 			     struct razor_package *package)
   852 {
   853 	struct razor_file_iterator *fi;
   854 	const char *name;
   855 
   856 	assert (set != NULL);
   857 	assert (package != NULL);
   858 
   859 	fi = razor_file_iterator_create(set, package, 0);
   860 
   861 	while (razor_file_iterator_next(fi, &name))
   862 		printf("%s\n", name);
   863 
   864 	razor_file_iterator_destroy(fi);
   865 }
   866 
   867 /*
   868  * Package data can potentially come from two places. The so-called
   869  * metadata (eg., from comps.xml) and from an RPM file. We consider
   870  * a package which has additional data from an RPM file as "fixed".
   871  * If a package needs fixing, then razor_transaction_fixup_package()
   872  * will do so. When considering what packages to add and to remove
   873  * we need to take this into account since we always want to add
   874  * unfixed packages (otherwise we have a potential conflict between
   875  * the existing package data and that present in the RPM).
   876  */
   877 static int
   878 razor_package_is_fixed(struct razor_set *set, struct razor_package *p)
   879 {
   880 	const char *preunprog, *preun, *postunprog, *postun;
   881 
   882 	if (!p)
   883 		return 0;
   884 	razor_package_get_details(set, p,
   885 				  RAZOR_DETAIL_PREUNPROG, &preunprog,
   886 				  RAZOR_DETAIL_PREUN, &preun,
   887 				  RAZOR_DETAIL_POSTUNPROG, &postunprog,
   888 				  RAZOR_DETAIL_POSTUN, &postun,
   889 				  RAZOR_DETAIL_LAST);
   890 	return *preunprog || *preun || *postunprog || *postun;
   891 }
   892 
   893 RAZOR_EXPORT void
   894 razor_set_diff(struct razor_set *set, struct razor_set *upstream,
   895 	       razor_diff_callback_t callback, void *data)
   896 {
   897  	struct razor_package_iterator *pi1, *pi2;
   898  	struct razor_package *p1, *p2;
   899 	const char *name1, *name2, *version1, *version2, *arch1, *arch2;
   900 	int res, is_fixed1, is_fixed2;
   901 
   902 	assert (set != NULL);
   903 	assert (upstream != NULL);
   904 
   905 	pi1 = razor_package_iterator_create(set);
   906 	pi2 = razor_package_iterator_create(upstream);
   907 
   908 	razor_package_iterator_next(pi1, &p1,
   909 				    RAZOR_DETAIL_NAME, &name1,
   910 				    RAZOR_DETAIL_VERSION, &version1,
   911 				    RAZOR_DETAIL_ARCH, &arch1,
   912 				    RAZOR_DETAIL_LAST);
   913 	is_fixed1 = razor_package_is_fixed(set, p1);
   914 	razor_package_iterator_next(pi2, &p2,
   915 				    RAZOR_DETAIL_NAME, &name2,
   916 				    RAZOR_DETAIL_VERSION, &version2,
   917 				    RAZOR_DETAIL_ARCH, &arch2,
   918 				    RAZOR_DETAIL_LAST);
   919 	is_fixed2 = razor_package_is_fixed(upstream, p2);
   920 
   921 	while (p1 || p2) {
   922 		if (p1 && p2) {
   923 			res = strcmp(name1, name2);
   924 			if (res == 0)
   925 				res = razor_versioncmp(version1, version2);
   926 			if (res == 0)
   927 				res = is_fixed1 - is_fixed2;
   928 		} else {
   929 			res = 0;
   930 		}
   931 
   932 		if (p2 == NULL || res < 0)
   933 			callback(RAZOR_DIFF_ACTION_REMOVE,
   934 				 p1, name1, version1, arch1, data);
   935 		else if (p1 == NULL || res > 0)
   936 			callback(RAZOR_DIFF_ACTION_ADD,
   937 				 p2, name2, version2, arch2, data);
   938 
   939 		if (p1 != NULL && res <= 0) {
   940 			razor_package_iterator_next(pi1, &p1,
   941 						    RAZOR_DETAIL_NAME, &name1,
   942 						    RAZOR_DETAIL_VERSION, &version1,
   943 						    RAZOR_DETAIL_ARCH, &arch1,
   944 						    RAZOR_DETAIL_LAST);
   945 			is_fixed1 = razor_package_is_fixed(set, p1);
   946 		}
   947 		if (p2 != NULL && res >= 0) {
   948 			razor_package_iterator_next(pi2, &p2,
   949 						    RAZOR_DETAIL_NAME, &name2,
   950 						    RAZOR_DETAIL_VERSION, &version2,
   951 						    RAZOR_DETAIL_ARCH, &arch2,
   952 						    RAZOR_DETAIL_LAST);
   953 			is_fixed2 = razor_package_is_fixed(upstream, p2);
   954 		}
   955 	}
   956 
   957 	razor_package_iterator_destroy(pi1);
   958 	razor_package_iterator_destroy(pi2);
   959 }
   960 
   961 struct install_action {
   962 	enum razor_install_action action;
   963 	struct razor_package *package;
   964 };
   965 
   966 struct razor_install_iterator {
   967 	struct razor_set *set;
   968 	struct razor_set *next;
   969 	struct array actions;
   970 	struct deque *order, *left;
   971 };
   972 
   973 static void
   974 add_action(enum razor_diff_action action,
   975 	   struct razor_package *package,
   976 	   const char *name,
   977 	   const char *version,
   978 	   const char *arch,
   979 	   void *data)
   980 {
   981 	struct razor_install_iterator *ii = data;
   982 	struct install_action *a;
   983 
   984 	a = array_add(&ii->actions, sizeof *a);
   985 	a->package = package;
   986 
   987 	switch (action) {
   988 	case RAZOR_DIFF_ACTION_ADD:
   989 		a->action = RAZOR_INSTALL_ACTION_ADD;
   990 		break;
   991 	case RAZOR_DIFF_ACTION_REMOVE:
   992 		a->action = RAZOR_INSTALL_ACTION_REMOVE;
   993 		break;
   994 	}
   995 }
   996 
   997 /*
   998  * Does <package> have a requirement for <script> which is
   999  * satisfied by <provider> ?
  1000  * Note: We already know that <provider> is to be added as part of this install
  1001  * so there is no need to check the relation.
  1002  */
  1003 static int
  1004 package_script_requires(struct razor_set *set, struct razor_package *package,
  1005 			enum razor_property_flags script,
  1006 			struct razor_package *provider)
  1007 {
  1008 	struct list *link;
  1009 	struct razor_property *prop;
  1010 
  1011 	link = list_first(&package->properties, &set->property_pool);
  1012 	for(; link; link = list_next(link)) {
  1013 		prop = set->properties.data;
  1014 		prop += link->data;
  1015 		if ((prop->flags & RAZOR_PROPERTY_SCRIPT_MASK) & script &&
  1016 		    (prop->flags & RAZOR_PROPERTY_TYPE_MASK) == RAZOR_PROPERTY_REQUIRES &&
  1017 		    provider->name == prop->name)
  1018 			return 1;
  1019 	}
  1020 	return 0;
  1021 }
  1022 
  1023 RAZOR_EXPORT struct razor_install_iterator *
  1024 razor_set_create_install_iterator(struct razor_set *set,
  1025 				  struct razor_set *next)
  1026 {
  1027 	struct razor_install_iterator *ii;
  1028 	struct razor_property *prop;
  1029 	/* A graph of the actions to be perfomed where
  1030 	 * A->B means action A should follow action B.
  1031 	 */
  1032 	struct graph follows;
  1033 	struct install_action *actions, *ai, *aj, *an;
  1034 	int i, j, count, vertex_added;
  1035 	struct list *link;
  1036 	struct razor_set *rs;
  1037 	struct deque *order;
  1038 	int barrier_needed;
  1039 
  1040 	assert (set != NULL);
  1041 	assert (next != NULL);
  1042 
  1043 	ii = zalloc(sizeof *ii);
  1044 	ii->set = set;
  1045 	ii->next = next;
  1046 	
  1047 	razor_set_diff(set, next, add_action, ii);
  1048 
  1049 	actions = ii->actions.data;
  1050 	count = ii->actions.size / sizeof (struct install_action);
  1051 
  1052 	graph_init(&follows);
  1053 
  1054 	for(i = 0; i < count; i++) {
  1055 		ai = actions + i;
  1056 		rs = ai->action == RAZOR_INSTALL_ACTION_ADD ? next : set;
  1057 		vertex_added = 0;
  1058 		link = list_first(&ai->package->properties, &rs->property_pool);
  1059 		for(; link; link = list_next(link)) {
  1060 			prop = rs->properties.data;
  1061 			prop += link->data;
  1062 			switch(prop->flags & RAZOR_PROPERTY_TYPE_MASK) {
  1063 			case RAZOR_PROPERTY_REQUIRES:
  1064 			case RAZOR_PROPERTY_CONFLICTS:
  1065 				for(j = 0; j < count; j++) {
  1066 					if (j == i)
  1067 						continue;
  1068 					aj = actions + j;
  1069 					if (aj->package->name == prop->name) {
  1070 						if (ai->action ==
  1071 						    RAZOR_INSTALL_ACTION_ADD)
  1072 							graph_add_edge(&follows,
  1073 								       i, j);
  1074 						else
  1075 							graph_add_edge(&follows,
  1076 								       j, i);
  1077 						vertex_added++;
  1078 					}
  1079 				}
  1080 				break;
  1081 			}
  1082 		}
  1083 		if (ai->action == RAZOR_INSTALL_ACTION_ADD) {
  1084 			for(j = 0; j < count; j++) {
  1085 				if (j == i)
  1086 					continue;
  1087 				aj = actions + j;
  1088 				if (aj->package == ai->package &&
  1089 				    aj->action == RAZOR_INSTALL_ACTION_REMOVE) {
  1090 					graph_add_edge(&follows, i, j);
  1091 					vertex_added++;
  1092 				}
  1093 			}
  1094 		}
  1095 		if (!vertex_added)
  1096 			graph_add_edge(&follows, i, i);
  1097 	}
  1098 
  1099 	/*
  1100 	 * Because files are installed and removed using razor_atomic,
  1101 	 * but scripts are run with no regard for these, we need some
  1102 	 * means for synchronisation between the two. We support this
  1103 	 * via transaction barriers which are points where
  1104 	 * razor_atomic_commit() should be called so that scripts can
  1105 	 * rely on the files they need being present.
  1106 	 *
  1107 	 * Rules:
  1108 	 *   1)	Transaction barriers never occur within a dependency
  1109 	 *	loop. Since we can't guarantee any ordering of actions
  1110 	 *	within such a loop, they make no sense.
  1111 	 *   2) Otherwise the following table applies:
  1112 	 *	Action I    Action J	Barrier between I and J iff
  1113 	 *	ADD P	    ADD Q	%pre(Q) requires P
  1114 	 *	ADD P	    REMOVE Q	%preun(Q) requires P
  1115 	 *	REMOVE P    ADD Q	never
  1116 	 *	REMOVE P    REMOVE Q	%postun(P) requires Q
  1117 	 *
  1118 	 * FIXME:
  1119 	 *	This should take account of conflicts somehow.
  1120 	 */
  1121 	order = graph_sort(&follows);
  1122 	ii->order = deque_new(0);
  1123 	if (!deque_empty(order)) {
  1124 		j = deque_pop(order);
  1125 		deque_unshift(ii->order, j);
  1126 	}
  1127 	while (!deque_empty(order)) {
  1128 		i = j;
  1129 		j = deque_pop(order);
  1130 		ai = actions + i;
  1131 		aj = actions + j;
  1132 		if (graph_is_connected(&follows, i, j) &&
  1133 		    graph_is_connected(&follows, j, i))
  1134 			barrier_needed = 0;
  1135 		else if (ai->action == RAZOR_INSTALL_ACTION_ADD &&
  1136 			 aj->action == RAZOR_INSTALL_ACTION_ADD &&
  1137 			 package_script_requires(next, aj->package,
  1138 						 RAZOR_PROPERTY_PRE,
  1139 						 ai->package))
  1140 			barrier_needed = 1;
  1141 		else if (ai->action == RAZOR_INSTALL_ACTION_ADD &&
  1142 			 aj->action == RAZOR_INSTALL_ACTION_REMOVE &&
  1143 			 package_script_requires(set, aj->package,
  1144 						 RAZOR_PROPERTY_PREUN,
  1145 						 ai->package))
  1146 			barrier_needed = 1;
  1147 		else if (ai->action == RAZOR_INSTALL_ACTION_REMOVE &&
  1148 			 aj->action == RAZOR_INSTALL_ACTION_REMOVE &&
  1149 			 package_script_requires(set, ai->package,
  1150 						 RAZOR_PROPERTY_POSTUN,
  1151 						 aj->package))
  1152 			barrier_needed = 1;
  1153 		else
  1154 			barrier_needed = 0;
  1155 		if (barrier_needed) {
  1156 			an = array_add(&ii->actions, sizeof *an);
  1157 			actions = ii->actions.data;
  1158 			an->package = NULL;
  1159 			an->action = RAZOR_INSTALL_ACTION_COMMIT;
  1160 			deque_unshift(ii->order, an - actions);
  1161 		}
  1162 		deque_unshift(ii->order, j);
  1163 	}
  1164 	deque_free(order);
  1165 
  1166 	ii->left = deque_dup(ii->order);
  1167 	graph_release(&follows);
  1168 
  1169 	return ii;
  1170 }
  1171 
  1172 RAZOR_EXPORT int
  1173 razor_install_iterator_next(struct razor_install_iterator *ii,
  1174 			    struct razor_package **package,
  1175 			    enum razor_install_action *action,
  1176 			    int *count)
  1177 {
  1178 	struct install_action *a;
  1179 	struct razor_package_iterator *pi;
  1180 	struct razor_package *pkg;
  1181 	const char *removing, *name;
  1182 
  1183 	if (deque_empty(ii->left))
  1184 		return 0;
  1185 
  1186 	a = (struct install_action *)ii->actions.data + deque_pop(ii->left);
  1187 	*package = a->package;
  1188 	*action = a->action;
  1189 	*count = 0;
  1190 
  1191 	if (a->action == RAZOR_INSTALL_ACTION_REMOVE) {
  1192 		razor_package_get_details(ii->set, a->package,
  1193 					  RAZOR_DETAIL_NAME, &removing,
  1194 					  RAZOR_DETAIL_LAST);
  1195 
  1196 		pi = razor_package_iterator_create(ii->next);
  1197 		while (razor_package_iterator_next(pi, &pkg,
  1198 						   RAZOR_DETAIL_NAME, &name,
  1199 						   RAZOR_DETAIL_LAST)) {
  1200 			if (!strcmp(name, removing))
  1201 				(*count)++;
  1202 		}
  1203 		razor_package_iterator_destroy(pi);
  1204 	} else if (a->action == RAZOR_INSTALL_ACTION_ADD)
  1205 		*count = 1;
  1206 
  1207 	return 1;
  1208 }
  1209 
  1210 static int
  1211 action_is_included(struct razor_install_iterator *ii, struct deque *done,
  1212 		   struct razor_package *package,
  1213 		   enum razor_install_action action)
  1214 {
  1215 	struct deque *t;
  1216 	struct install_action *a;
  1217 	int retval;
  1218 
  1219 	t = deque_dup(done);
  1220 
  1221 	while(!deque_empty(t)) {
  1222 		a = (struct install_action *)ii->actions.data + deque_pop(t);
  1223 		if (a->package == package && a->action == action)
  1224 			break;
  1225 	}
  1226 	retval = !deque_empty(t);
  1227 
  1228 	deque_free(t);
  1229 
  1230 	return retval;
  1231 }
  1232 
  1233 RAZOR_EXPORT struct razor_set *
  1234 razor_install_iterator_commit_set(struct razor_install_iterator *ii)
  1235 {
  1236 	struct razor_merger *merger;
  1237 	struct razor_set *set;
  1238 	struct razor_package *n, *nend, *npkgs, *s, *send, *spkgs;
  1239 	struct deque *done;
  1240 	size_t pos;
  1241 	char *npool, *spool;
  1242 	int cmp;
  1243 
  1244 	done = deque_dup(ii->order);
  1245 	pos = razor_install_iterator_tell(ii);
  1246 	while(deque_length(done) > pos)
  1247 		deque_shift(done);
  1248 
  1249 	s = ii->set->packages.data;
  1250 	spkgs = ii->set->packages.data;
  1251 	send = ii->set->packages.data + ii->set->packages.size;
  1252 	spool = ii->set->string_pool.data;
  1253 
  1254 	n = ii->next->packages.data;
  1255 	npkgs = ii->next->packages.data;
  1256 	nend = ii->next->packages.data + ii->next->packages.size;
  1257 	npool = ii->next->string_pool.data;
  1258 
  1259 	merger = razor_merger_create(ii->set, ii->next);
  1260 	while (s < send || n < nend) {
  1261 		if (s < send && n < nend)
  1262 			cmp = strcmp(&spool[s->name], &npool[n->name]);
  1263 		else if (s < send)
  1264 			cmp = -1;
  1265 		else
  1266 			cmp = 1;
  1267 
  1268 		if (cmp < 0) {
  1269 			if (!action_is_included(ii, done, s,
  1270 						RAZOR_INSTALL_ACTION_REMOVE))
  1271 				razor_merger_add_package(merger, s);
  1272 			s++;
  1273 		} else if (cmp == 0) {
  1274 			if (!action_is_included(ii, done, s,
  1275 						RAZOR_INSTALL_ACTION_REMOVE))
  1276 				razor_merger_add_package(merger, s);
  1277 			if (action_is_included(ii, done, n,
  1278 					       RAZOR_INSTALL_ACTION_ADD))
  1279 				razor_merger_add_package(merger, n);
  1280 
  1281 			s++;
  1282 			n++;
  1283 		} else {
  1284 			if (action_is_included(ii, done, n,
  1285 					       RAZOR_INSTALL_ACTION_ADD))
  1286 				razor_merger_add_package(merger, n);
  1287 			n++;
  1288 		}
  1289 	}
  1290 
  1291 	set = razor_merger_commit(merger);
  1292 	razor_merger_destroy(merger);
  1293 
  1294 	return set;
  1295 }
  1296 
  1297 RAZOR_EXPORT void
  1298 razor_install_iterator_rewind(struct razor_install_iterator *ii)
  1299 {
  1300 	deque_free(ii->left);
  1301 	ii->left=deque_dup(ii->order);
  1302 }
  1303 
  1304 RAZOR_EXPORT size_t
  1305 razor_install_iterator_tell(struct razor_install_iterator *ii)
  1306 {
  1307 	return deque_length(ii->order) - deque_length(ii->left);
  1308 }
  1309 
  1310 RAZOR_EXPORT size_t
  1311 razor_install_iterator_seek(struct razor_install_iterator *ii, size_t pos)
  1312 {
  1313 	size_t current_pos;
  1314 
  1315 	if (pos > deque_length(ii->order))
  1316 		pos = deque_length(ii->order);
  1317 
  1318 	current_pos = razor_install_iterator_tell(ii);
  1319 
  1320 	if (pos < current_pos) {
  1321 		razor_install_iterator_rewind(ii);
  1322 		current_pos = 0;
  1323 	}
  1324 
  1325 	while(current_pos < pos) {
  1326 		(void) deque_pop(ii->left);
  1327 		current_pos++;
  1328 	}
  1329 
  1330 	return current_pos;
  1331 }
  1332 
  1333 RAZOR_EXPORT void
  1334 razor_install_iterator_destroy(struct razor_install_iterator *ii)
  1335 {
  1336 	array_release(&ii->actions);
  1337 	deque_free(ii->order);
  1338 	deque_free(ii->left);
  1339 	free(ii);
  1340 }