Add transaction barriers 0.5.3
authorJ. Ali Harlow <ali@juiblex.co.uk>
Thu Feb 09 20:45:27 2012 +0000 (2012-02-09)
changeset 41833b825d3128d
parent 417 c7063ba682e0
child 419 891991677a7f
child 420 a7a1be2fed47
Add transaction barriers
These allow packages to be installed and removed which have scripts
that depend on each other when atomic transactions are involved.
Note that yum supports pre, but not other requires flags. post will
need similar support to the post scripts themselves pulling in the
requires flags from the rpms. Likewise preun and postun will need
similar handling to those scrips since the requires flags will need
to be stored in the razor database.
configure.ac
librazor/razor.c
librazor/razor.h
src/import-yum.c
src/main.c
test/zip.spec
test/zsh.spec
     1.1 --- a/configure.ac	Thu Feb 09 20:43:58 2012 +0000
     1.2 +++ b/configure.ac	Thu Feb 09 20:45:27 2012 +0000
     1.3 @@ -10,9 +10,9 @@
     1.4  #
     1.5  # See http://sources.redhat.com/autobook/autobook/autobook_91.html#SEC91 for details
     1.6  #
     1.7 -LT_CURRENT=2
     1.8 +LT_CURRENT=3
     1.9  LT_REVISION=0
    1.10 -LT_AGE=0
    1.11 +LT_AGE=1
    1.12  AC_SUBST(LT_CURRENT)
    1.13  AC_SUBST(LT_REVISION)
    1.14  AC_SUBST(LT_AGE)
     2.1 --- a/librazor/razor.c	Thu Feb 09 20:43:58 2012 +0000
     2.2 +++ b/librazor/razor.c	Thu Feb 09 20:45:27 2012 +0000
     2.3 @@ -1,7 +1,7 @@
     2.4  /*
     2.5   * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     2.6   * Copyright (C) 2008  Red Hat, Inc
     2.7 - * Copyright (C) 2009-2011  J. Ali Harlow <ali@juiblex.co.uk>
     2.8 + * Copyright (C) 2009-2012  J. Ali Harlow <ali@juiblex.co.uk>
     2.9   *
    2.10   * This program is free software; you can redistribute it and/or modify
    2.11   * it under the terms of the GNU General Public License as published by
    2.12 @@ -992,6 +992,32 @@
    2.13  	}
    2.14  }
    2.15  
    2.16 +/*
    2.17 + * Does <package> have a requirement for <script> which is
    2.18 + * satisfied by <provider> ?
    2.19 + * Note: We already know that <provider> is to be added as part of this install
    2.20 + * so there is no need to check the relation.
    2.21 + */
    2.22 +static int
    2.23 +package_script_requires(struct razor_set *set, struct razor_package *package,
    2.24 +			enum razor_property_flags script,
    2.25 +			struct razor_package *provider)
    2.26 +{
    2.27 +	struct list *link;
    2.28 +	struct razor_property *prop;
    2.29 +
    2.30 +	link = list_first(&package->properties, &set->property_pool);
    2.31 +	for(; link; link = list_next(link)) {
    2.32 +		prop = set->properties.data;
    2.33 +		prop += link->data;
    2.34 +		if ((prop->flags & RAZOR_PROPERTY_SCRIPT_MASK) & script &&
    2.35 +		    (prop->flags & RAZOR_PROPERTY_TYPE_MASK) == RAZOR_PROPERTY_REQUIRES &&
    2.36 +		    provider->name == prop->name)
    2.37 +			return 1;
    2.38 +	}
    2.39 +	return 0;
    2.40 +}
    2.41 +
    2.42  RAZOR_EXPORT struct razor_install_iterator *
    2.43  razor_set_create_install_iterator(struct razor_set *set,
    2.44  				  struct razor_set *next)
    2.45 @@ -1002,10 +1028,12 @@
    2.46  	 * A->B means action A should follow action B.
    2.47  	 */
    2.48  	struct graph follows;
    2.49 -	struct install_action *actions, *ai, *aj;
    2.50 +	struct install_action *actions, *ai, *aj, *an;
    2.51  	int i, j, count, vertex_added;
    2.52  	struct list *link;
    2.53  	struct razor_set *rs;
    2.54 +	struct deque *order;
    2.55 +	int barrier_needed;
    2.56  
    2.57  	assert (set != NULL);
    2.58  	assert (next != NULL);
    2.59 @@ -1066,7 +1094,73 @@
    2.60  			graph_add_edge(&follows, i, i);
    2.61  	}
    2.62  
    2.63 -	ii->order = graph_sort(&follows);
    2.64 +	/*
    2.65 +	 * Because files are installed and removed using razor_atomic,
    2.66 +	 * but scripts are run with no regard for these, we need some
    2.67 +	 * means for synchronisation between the two. We support this
    2.68 +	 * via transaction barriers which are points where
    2.69 +	 * razor_atomic_commit() should be called so that scripts can
    2.70 +	 * rely on the files they need being present.
    2.71 +	 *
    2.72 +	 * Rules:
    2.73 +	 *   1)	Transaction barriers never occur within a dependency
    2.74 +	 *	loop. Since we can't guarantee any ordering of actions
    2.75 +	 *	within such a loop, they make no sense.
    2.76 +	 *   2) Otherwise the following table applies:
    2.77 +	 *	Action I    Action J	Barrier between I and J iff
    2.78 +	 *	ADD P	    ADD Q	%pre(Q) requires P
    2.79 +	 *	ADD P	    REMOVE Q	%preun(Q) requires P
    2.80 +	 *	REMOVE P    ADD Q	never
    2.81 +	 *	REMOVE P    REMOVE Q	%postun(P) requires Q
    2.82 +	 *
    2.83 +	 * FIXME:
    2.84 +	 *	This should take account of conflicts somehow.
    2.85 +	 */
    2.86 +	order = graph_sort(&follows);
    2.87 +	ii->order = deque_new(0);
    2.88 +	if (!deque_empty(order)) {
    2.89 +		j = deque_pop(order);
    2.90 +		deque_unshift(ii->order, j);
    2.91 +	}
    2.92 +	while (!deque_empty(order)) {
    2.93 +		i = j;
    2.94 +		j = deque_pop(order);
    2.95 +		ai = actions + i;
    2.96 +		aj = actions + j;
    2.97 +		if (graph_is_connected(&follows, i, j) &&
    2.98 +		    graph_is_connected(&follows, j, i))
    2.99 +			barrier_needed = 0;
   2.100 +		else if (ai->action == RAZOR_INSTALL_ACTION_ADD &&
   2.101 +			 aj->action == RAZOR_INSTALL_ACTION_ADD &&
   2.102 +			 package_script_requires(next, aj->package,
   2.103 +						 RAZOR_PROPERTY_PRE,
   2.104 +						 ai->package))
   2.105 +			barrier_needed = 1;
   2.106 +		else if (ai->action == RAZOR_INSTALL_ACTION_ADD &&
   2.107 +			 aj->action == RAZOR_INSTALL_ACTION_REMOVE &&
   2.108 +			 package_script_requires(set, aj->package,
   2.109 +						 RAZOR_PROPERTY_PREUN,
   2.110 +						 ai->package))
   2.111 +			barrier_needed = 1;
   2.112 +		else if (ai->action == RAZOR_INSTALL_ACTION_REMOVE &&
   2.113 +			 aj->action == RAZOR_INSTALL_ACTION_REMOVE &&
   2.114 +			 package_script_requires(set, ai->package,
   2.115 +						 RAZOR_PROPERTY_POSTUN,
   2.116 +						 aj->package))
   2.117 +			barrier_needed = 1;
   2.118 +		else
   2.119 +			barrier_needed = 0;
   2.120 +		if (barrier_needed) {
   2.121 +			an = array_add(&ii->actions, sizeof *an);
   2.122 +			actions = ii->actions.data;
   2.123 +			an->package = NULL;
   2.124 +			an->action = RAZOR_INSTALL_ACTION_COMMIT;
   2.125 +			deque_unshift(ii->order, an - actions);
   2.126 +		}
   2.127 +		deque_unshift(ii->order, j);
   2.128 +	}
   2.129 +	deque_free(order);
   2.130 +
   2.131  	ii->left = deque_dup(ii->order);
   2.132  	graph_release(&follows);
   2.133  
   2.134 @@ -1105,12 +1199,99 @@
   2.135  				(*count)++;
   2.136  		}
   2.137  		razor_package_iterator_destroy(pi);
   2.138 -	} else
   2.139 +	} else if (a->action == RAZOR_INSTALL_ACTION_ADD)
   2.140  		*count = 1;
   2.141  
   2.142  	return 1;
   2.143  }
   2.144  
   2.145 +static int
   2.146 +action_is_included(struct razor_install_iterator *ii, struct deque *done,
   2.147 +		   struct razor_package *package,
   2.148 +		   enum razor_install_action action)
   2.149 +{
   2.150 +	struct deque *t;
   2.151 +	struct install_action *a;
   2.152 +	int retval;
   2.153 +
   2.154 +	t = deque_dup(done);
   2.155 +
   2.156 +	while(!deque_empty(t)) {
   2.157 +		a = (struct install_action *)ii->actions.data + deque_pop(t);
   2.158 +		if (a->package == package && a->action == action)
   2.159 +			break;
   2.160 +	}
   2.161 +	retval = !deque_empty(t);
   2.162 +
   2.163 +	deque_free(t);
   2.164 +
   2.165 +	return retval;
   2.166 +}
   2.167 +
   2.168 +RAZOR_EXPORT struct razor_set *
   2.169 +razor_install_iterator_commit_set(struct razor_install_iterator *ii)
   2.170 +{
   2.171 +	struct razor_merger *merger;
   2.172 +	struct razor_set *set;
   2.173 +	struct razor_package *n, *nend, *npkgs, *s, *send, *spkgs;
   2.174 +	struct deque *done;
   2.175 +	size_t pos;
   2.176 +	char *npool, *spool;
   2.177 +	int cmp;
   2.178 +
   2.179 +	done = deque_dup(ii->order);
   2.180 +	pos = razor_install_iterator_tell(ii);
   2.181 +	while(deque_length(done) > pos)
   2.182 +		deque_shift(done);
   2.183 +
   2.184 +	s = ii->set->packages.data;
   2.185 +	spkgs = ii->set->packages.data;
   2.186 +	send = ii->set->packages.data + ii->set->packages.size;
   2.187 +	spool = ii->set->string_pool.data;
   2.188 +
   2.189 +	n = ii->next->packages.data;
   2.190 +	npkgs = ii->next->packages.data;
   2.191 +	nend = ii->next->packages.data + ii->next->packages.size;
   2.192 +	npool = ii->next->string_pool.data;
   2.193 +
   2.194 +	merger = razor_merger_create(ii->set, ii->next);
   2.195 +	while (s < send || n < nend) {
   2.196 +		if (s < send && n < nend)
   2.197 +			cmp = strcmp(&spool[s->name], &npool[n->name]);
   2.198 +		else if (s < send)
   2.199 +			cmp = -1;
   2.200 +		else
   2.201 +			cmp = 1;
   2.202 +
   2.203 +		if (cmp < 0) {
   2.204 +			if (!action_is_included(ii, done, s,
   2.205 +						RAZOR_INSTALL_ACTION_REMOVE))
   2.206 +				razor_merger_add_package(merger, s);
   2.207 +			s++;
   2.208 +		} else if (cmp == 0) {
   2.209 +			if (!action_is_included(ii, done, s,
   2.210 +						RAZOR_INSTALL_ACTION_REMOVE))
   2.211 +				razor_merger_add_package(merger, s);
   2.212 +			if (action_is_included(ii, done, n,
   2.213 +					       RAZOR_INSTALL_ACTION_ADD))
   2.214 +				razor_merger_add_package(merger, n);
   2.215 +
   2.216 +			s++;
   2.217 +			n++;
   2.218 +		} else {
   2.219 +			if (action_is_included(ii, done, n,
   2.220 +					       RAZOR_INSTALL_ACTION_ADD))
   2.221 +				razor_merger_add_package(merger, n);
   2.222 +			n++;
   2.223 +		}
   2.224 +	}
   2.225 +
   2.226 +	set = razor_merger_commit(merger);
   2.227 +	razor_merger_destroy(merger);
   2.228 +
   2.229 +	return set;
   2.230 +}
   2.231 +
   2.232  RAZOR_EXPORT void
   2.233  razor_install_iterator_rewind(struct razor_install_iterator *ii)
   2.234  {
   2.235 @@ -1118,6 +1299,35 @@
   2.236  	ii->left=deque_dup(ii->order);
   2.237  }
   2.238  
   2.239 +RAZOR_EXPORT size_t
   2.240 +razor_install_iterator_tell(struct razor_install_iterator *ii)
   2.241 +{
   2.242 +	return deque_length(ii->order) - deque_length(ii->left);
   2.243 +}
   2.244 +
   2.245 +RAZOR_EXPORT size_t
   2.246 +razor_install_iterator_seek(struct razor_install_iterator *ii, size_t pos)
   2.247 +{
   2.248 +	size_t current_pos;
   2.249 +
   2.250 +	if (pos > deque_length(ii->order))
   2.251 +		pos = deque_length(ii->order);
   2.252 +
   2.253 +	current_pos = razor_install_iterator_tell(ii);
   2.254 +
   2.255 +	if (pos < current_pos) {
   2.256 +		razor_install_iterator_rewind(ii);
   2.257 +		current_pos = 0;
   2.258 +	}
   2.259 +
   2.260 +	while(current_pos < pos) {
   2.261 +		(void) deque_pop(ii->left);
   2.262 +		current_pos++;
   2.263 +	}
   2.264 +
   2.265 +	return current_pos;
   2.266 +}
   2.267 +
   2.268  RAZOR_EXPORT void
   2.269  razor_install_iterator_destroy(struct razor_install_iterator *ii)
   2.270  {
     3.1 --- a/librazor/razor.h	Thu Feb 09 20:43:58 2012 +0000
     3.2 +++ b/librazor/razor.h	Thu Feb 09 20:45:27 2012 +0000
     3.3 @@ -1,7 +1,7 @@
     3.4  /*
     3.5   * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     3.6   * Copyright (C) 2008  Red Hat, Inc
     3.7 - * Copyright (C) 2009, 2011  J. Ali Harlow <ali@juiblex.co.uk>
     3.8 + * Copyright (C) 2009, 2011, 2012  J. Ali Harlow <ali@juiblex.co.uk>
     3.9   *
    3.10   * This program is free software; you can redistribute it and/or modify
    3.11   * it under the terms of the GNU General Public License as published by
    3.12 @@ -349,7 +349,22 @@
    3.13  				enum razor_install_action *action,
    3.14  				int *count);
    3.15  
    3.16 +/**
    3.17 + * razor_install_iterator_commit_set
    3.18 + *
    3.19 + * Immediately after razor_install_iterator_next() returns
    3.20 + * RAZOR_INSTALL_ACTION_COMMIT, this function will return the razor_set
    3.21 + * which should be committed.
    3.22 + *
    3.23 + * Returns: a new #razor_set object.
    3.24 + **/
    3.25 +struct razor_set *
    3.26 +razor_install_iterator_commit_set(struct razor_install_iterator *ii);
    3.27 +
    3.28  void razor_install_iterator_rewind(struct razor_install_iterator *ii);
    3.29 +size_t razor_install_iterator_tell(struct razor_install_iterator *ii);
    3.30 +size_t razor_install_iterator_seek(struct razor_install_iterator *ii,
    3.31 +				   size_t pos);
    3.32  void razor_install_iterator_destroy(struct razor_install_iterator *ii);
    3.33  
    3.34  /**
     4.1 --- a/src/import-yum.c	Thu Feb 09 20:43:58 2012 +0000
     4.2 +++ b/src/import-yum.c	Thu Feb 09 20:45:27 2012 +0000
     4.3 @@ -170,11 +170,7 @@
     4.4  			else if (strcmp(atts[i], "flags") == 0)
     4.5  				relation = yum_to_razor_relation(atts[i + 1]);
     4.6  			else if (strcmp(atts[i], "pre") == 0)
     4.7 -				pre = 
     4.8 -					RAZOR_PROPERTY_PRE |
     4.9 -					RAZOR_PROPERTY_POST |
    4.10 -					RAZOR_PROPERTY_PREUN |
    4.11 -					RAZOR_PROPERTY_POSTUN;
    4.12 +				pre = RAZOR_PROPERTY_PRE;
    4.13  		}
    4.14  
    4.15  		if (n == NULL) {
     5.1 --- a/src/main.c	Thu Feb 09 20:43:58 2012 +0000
     5.2 +++ b/src/main.c	Thu Feb 09 20:45:27 2012 +0000
     5.3 @@ -1,7 +1,7 @@
     5.4  /*
     5.5   * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     5.6   * Copyright (C) 2008  Red Hat, Inc
     5.7 - * Copyright (C) 2009, 2011  J. Ali Harlow <ali@juiblex.co.uk>
     5.8 + * Copyright (C) 2009, 2011-2012  J. Ali Harlow <ali@juiblex.co.uk>
     5.9   *
    5.10   * This program is free software; you can redistribute it and/or modify
    5.11   * it under the terms of the GNU General Public License as published by
    5.12 @@ -48,18 +48,16 @@
    5.13  
    5.14  #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
    5.15  
    5.16 -enum update_pass_type {
    5.17 -    UPDATE_PASS_PRE_REMOVE,
    5.18 -    UPDATE_PASS_MAIN,
    5.19 -    UPDATE_PASS_POST_INSTALL,
    5.20 -};
    5.21 -
    5.22  static int
    5.23  update_packages(struct razor_transaction *trans,
    5.24  		struct razor_install_iterator *ii, struct razor_set *system,
    5.25  		struct razor_set *next, struct razor_atomic *atomic,
    5.26  		struct razor_relocations *relocations,
    5.27 -		enum update_pass_type stage);
    5.28 +		enum razor_stage_type stage);
    5.29 +static int
    5.30 +update_system(const char *install_root, struct razor_relocations *relocations,
    5.31 +	      struct razor_transaction *trans, struct razor_set *system,
    5.32 +	      struct razor_set *next, const char *verb);
    5.33  
    5.34  static struct razor_package_iterator *
    5.35  create_iterator_from_argv(struct razor_set *set, int argc, const char *argv[])
    5.36 @@ -619,24 +617,22 @@
    5.37  static int
    5.38  command_remove(int argc, const char *argv[])
    5.39  {
    5.40 -	struct razor_root *root;
    5.41  	struct razor_set *system, *upstream, *next;
    5.42  	struct razor_transaction *trans;
    5.43  	struct razor_atomic *atomic;
    5.44 -	struct razor_install_iterator *ii;
    5.45  	int i, retval;
    5.46  
    5.47  	atomic = razor_atomic_open("Remove packages");
    5.48  
    5.49 -	root = razor_root_open(install_root, atomic);
    5.50 -	system = razor_set_ref(razor_root_get_system_set(root));
    5.51 +	system = razor_root_open_read_only(install_root, atomic);
    5.52  	if (system == NULL) {
    5.53  		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
    5.54 -		razor_root_close(root);
    5.55  		razor_atomic_destroy(atomic);
    5.56  		return 1;
    5.57  	}
    5.58  
    5.59 +	razor_atomic_destroy(atomic);
    5.60 +
    5.61  	upstream = razor_set_create_without_root();
    5.62  	trans = razor_transaction_create(system, upstream);
    5.63  	razor_set_unref(upstream);
    5.64 @@ -645,8 +641,6 @@
    5.65  			fprintf(stderr, "no match for %s\n", argv[i]);
    5.66  			razor_transaction_destroy(trans);
    5.67  			razor_set_unref(system);
    5.68 -			razor_root_close(root);
    5.69 -			razor_atomic_destroy(atomic);
    5.70  			return 1;
    5.71  		}
    5.72  	}
    5.73 @@ -656,33 +650,15 @@
    5.74  	if (retval) {
    5.75  		razor_transaction_destroy(trans);
    5.76  		razor_set_unref(system);
    5.77 -		razor_root_close(root);
    5.78 -		razor_atomic_destroy(atomic);
    5.79  		return 1;
    5.80  	}
    5.81  
    5.82  	next = razor_transaction_commit(trans);
    5.83 -	ii = razor_set_create_install_iterator(system, next);
    5.84 -	retval = update_packages(trans, ii, system, next, atomic, NULL,
    5.85 -				 UPDATE_PASS_PRE_REMOVE);
    5.86 -	if (retval)
    5.87 -		fprintf(stderr, "Remove aborted\n");
    5.88 -	else {
    5.89 -		update_packages(trans, ii, system, next, atomic, NULL,
    5.90 -				UPDATE_PASS_MAIN);
    5.91  
    5.92 -		razor_root_update(root, next);
    5.93 +	retval = update_system(install_root, NULL, trans, system, next,
    5.94 +			       "Remove");
    5.95  
    5.96 -		(void)razor_root_commit(root);
    5.97 -		retval = razor_atomic_commit(atomic);
    5.98 -		if (retval)
    5.99 -			fprintf(stderr, "%s\n",
   5.100 -				razor_atomic_get_error_msg(atomic));
   5.101 -	}
   5.102 -
   5.103 -	razor_install_iterator_destroy(ii);
   5.104  	razor_transaction_destroy(trans);
   5.105 -	razor_atomic_destroy(atomic);
   5.106  	razor_set_unref(system);
   5.107  	razor_set_unref(next);
   5.108  
   5.109 @@ -826,7 +802,7 @@
   5.110  
   5.111  	ii = razor_set_create_install_iterator(system, next);
   5.112  	while (razor_install_iterator_next(ii, &package, &action, &count)) {
   5.113 -		if (action == RAZOR_INSTALL_ACTION_REMOVE)
   5.114 +		if (action != RAZOR_INSTALL_ACTION_ADD)
   5.115  			continue;
   5.116  
   5.117  		razor_package_get_details(next, package,
   5.118 @@ -989,108 +965,118 @@
   5.119  }
   5.120  
   5.121  /*
   5.122 - * In the most general case, there should be three passes:
   5.123 - *
   5.124 - * 1) For each package to be removed, run %preun
   5.125 - *
   5.126 - * 2) For each package:
   5.127 - *	If the package is to be installed, run %pre
   5.128 - *	Update the files on disk
   5.129 - *	If the package has been removed, run %postun
   5.130 - *
   5.131 - * 3) For each packge installed, run %post
   5.132 - *
   5.133 - * This guarantees that:
   5.134 - *   a)	Save where dependency loops make it impossible, at the time
   5.135 - *	%pre is run, all required packages are installed (although
   5.136 - *	their %post script may not have been run). We should support
   5.137 - *	Requires(%pre) to allow packagers to describe their requirements
   5.138 - *	more accurately and avoid unnecessary dependency loops.
   5.139 - *   b)	At the time %preun is run, all required packages are installed.
   5.140 - *	Supporting Requires(%preun) would make this more complicated
   5.141 - *	since we might have to install a package in order to remove
   5.142 - *	another one. For now, treating Requires(%preun) as Requires
   5.143 - *	seems more sensible.
   5.144 - *   c)	At the time %post is run, all required packages are installed.
   5.145 - *	Supporting Requires(%post) would allow us to remove a package
   5.146 - *	that was only needed to install another, but there seems no
   5.147 - *	obvious advantage.
   5.148 - *   d)	Save where dependency loops make it impossible, at the time
   5.149 - *	%postun is run, all required packages are installed. Again,
   5.150 - *	we should support Requires(%postun) to avoid unnecessary
   5.151 - *	dependency loops.
   5.152 - *
   5.153 - * Notes:
   5.154 - *	rpm treats %pre and %preun script failures as fatal errors
   5.155 - *	and %post and %postun failures as warnings.
   5.156 + * Returns 0 on success, -1 on failure and 1 if a RAZOR_INSTALL_ACTION_COMMIT
   5.157 + * is met (in which case the action is consumed).
   5.158   */
   5.159  static int
   5.160  update_packages(struct razor_transaction *trans,
   5.161  		struct razor_install_iterator *ii, struct razor_set *system,
   5.162  		struct razor_set *next, struct razor_atomic *atomic,
   5.163  		struct razor_relocations *relocations,
   5.164 -		enum update_pass_type pass)
   5.165 +		enum razor_stage_type stage)
   5.166  {
   5.167  	struct razor_package *package;
   5.168  	enum razor_install_action action;
   5.169  	int retval = 0, count;
   5.170 -	enum razor_stage_type remove_stage, add_stage;
   5.171 -
   5.172 -	switch (pass) {
   5.173 -	case UPDATE_PASS_PRE_REMOVE:
   5.174 -		add_stage = 0;
   5.175 -		remove_stage = RAZOR_STAGE_SCRIPTS_PRE;
   5.176 -		break;
   5.177 -	case UPDATE_PASS_MAIN:
   5.178 -		add_stage = RAZOR_STAGE_SCRIPTS_PRE | RAZOR_STAGE_FILES;
   5.179 -		remove_stage = RAZOR_STAGE_FILES | RAZOR_STAGE_SCRIPTS_POST;
   5.180 -		break;
   5.181 -	case UPDATE_PASS_POST_INSTALL:
   5.182 -		add_stage = RAZOR_STAGE_SCRIPTS_POST;
   5.183 -		remove_stage = 0;
   5.184 -		break;
   5.185 -	}
   5.186 -
   5.187 -	razor_install_iterator_rewind(ii);
   5.188  
   5.189  	while (!retval && razor_install_iterator_next(ii, &package, &action,
   5.190  						      &count)) {
   5.191 -		if (action == RAZOR_INSTALL_ACTION_ADD && add_stage)
   5.192 -			retval = install_package(trans, next, atomic, package,
   5.193 -						 relocations, count, add_stage);
   5.194 -		else if (action == RAZOR_INSTALL_ACTION_REMOVE && remove_stage)
   5.195 -			retval = razor_package_remove(system, next, atomic,
   5.196 -						      package, install_root,
   5.197 -						      count, remove_stage);
   5.198 +		if (action == RAZOR_INSTALL_ACTION_ADD) {
   5.199 +			if (install_package(trans, next, atomic, package,
   5.200 +					    relocations, count, stage))
   5.201 +				retval = -1;
   5.202 +		} else if (action == RAZOR_INSTALL_ACTION_REMOVE) {
   5.203 +			if (razor_package_remove(system, next, atomic, package,
   5.204 +						 install_root, count, stage))
   5.205 +				retval = -1;
   5.206 +		} else if (action == RAZOR_INSTALL_ACTION_COMMIT)
   5.207 +				retval = 1;
   5.208  	}
   5.209  
   5.210  	return retval;
   5.211  }
   5.212  
   5.213  static int
   5.214 +update_system(const char *install_root, struct razor_relocations *relocations,
   5.215 +	      struct razor_transaction *trans, struct razor_set *system,
   5.216 +	      struct razor_set *next, const char *verb)
   5.217 +{
   5.218 +	struct razor_root *root;
   5.219 +	struct razor_set *set;
   5.220 +	struct razor_atomic *atomic;
   5.221 +	struct razor_install_iterator *ii;
   5.222 +	int r, retval = 0;
   5.223 +	char *description;
   5.224 +	size_t pos;
   5.225 +
   5.226 +	description = razor_concat(verb, " packages", NULL);
   5.227 +
   5.228 +	ii = razor_set_create_install_iterator(system, next);
   5.229 +
   5.230 +	do {
   5.231 +		pos = razor_install_iterator_tell(ii);
   5.232 +
   5.233 +		atomic = razor_atomic_open(description);
   5.234 +
   5.235 +		root = razor_root_open(install_root, atomic);
   5.236 +		if (root == NULL) {
   5.237 +			fprintf(stderr, "%s\n",
   5.238 +				razor_atomic_get_error_msg(atomic));
   5.239 +			razor_atomic_destroy(atomic);
   5.240 +			retval = 1;
   5.241 +			break;
   5.242 +		}
   5.243 +
   5.244 +		r = update_packages(trans, ii, system, next, atomic,
   5.245 +				    relocations, RAZOR_STAGE_SCRIPTS_PRE);
   5.246 +		if (r < 0) {
   5.247 +			fprintf(stderr, "%s aborted\n", verb);
   5.248 +			razor_atomic_destroy(atomic);
   5.249 +			retval = r;
   5.250 +		} else {
   5.251 +			razor_install_iterator_seek(ii, pos);
   5.252 +			r = update_packages(trans, ii, system, next, atomic,
   5.253 +					    relocations, RAZOR_STAGE_FILES);
   5.254 +
   5.255 +			if (r == 1) {
   5.256 +				set = razor_install_iterator_commit_set(ii);
   5.257 +				razor_root_update(root, set);
   5.258 +				razor_set_unref(set);
   5.259 +			} else if (r == 0)
   5.260 +				razor_root_update(root, next);
   5.261 +
   5.262 +			(void)razor_root_commit(root);
   5.263 +			retval = razor_atomic_commit(atomic);
   5.264 +			if (retval) {
   5.265 +				fprintf(stderr, "%s\n",
   5.266 +					razor_atomic_get_error_msg(atomic));
   5.267 +				razor_atomic_destroy(atomic);
   5.268 +			} else {
   5.269 +				razor_install_iterator_seek(ii, pos);
   5.270 +				update_packages(trans, ii, system, next,
   5.271 +						atomic, relocations,
   5.272 +						RAZOR_STAGE_SCRIPTS_POST);
   5.273 +			}
   5.274 +		}
   5.275 +
   5.276 +		razor_atomic_destroy(atomic);
   5.277 +	} while(!retval && r == 1);
   5.278 +
   5.279 +	free(description);
   5.280 +
   5.281 +	return retval;
   5.282 +}
   5.283 +
   5.284 +static int
   5.285  command_install_or_update(int argc, const char *argv[], int do_update)
   5.286  {
   5.287 -	struct razor_root *root;
   5.288  	struct razor_relocations *relocations=NULL;
   5.289  	struct razor_set *system, *upstream, *next, *set;
   5.290  	struct razor_transaction *trans;
   5.291  	struct razor_atomic *atomic;
   5.292 -	struct razor_install_iterator *ii;
   5.293  	int i, retval, len, dependencies = 1;
   5.294  	char *oldpath;
   5.295  
   5.296 -	if (do_update)
   5.297 -		atomic = razor_atomic_open("Update packages");
   5.298 -	else
   5.299 -		atomic = razor_atomic_open("Install packages");
   5.300 -
   5.301 -	root = razor_root_open(install_root, atomic);
   5.302 -	if (root == NULL) {
   5.303 -		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
   5.304 -		razor_atomic_destroy(atomic);
   5.305 -		return 1;
   5.306 -	}
   5.307 -
   5.308  	for (i = 0; i < argc; i++) {
   5.309  		if (strcmp(argv[i], "--no-dependencies") == 0)
   5.310  			dependencies = 0;
   5.311 @@ -1119,10 +1105,14 @@
   5.312  			break;
   5.313  	}
   5.314  
   5.315 +	if (do_update)
   5.316 +		atomic = razor_atomic_open("Update packages");
   5.317 +	else
   5.318 +		atomic = razor_atomic_open("Install packages");
   5.319 +
   5.320  	upstream = razor_set_open(rawhide_repo_filename, atomic);
   5.321  	if (upstream == NULL) {
   5.322  		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
   5.323 -		razor_root_close(root);
   5.324  		razor_atomic_destroy(atomic);
   5.325  		return 1;
   5.326  	}
   5.327 @@ -1132,7 +1122,6 @@
   5.328  		if (set == NULL) {
   5.329  			fprintf(stderr, "%s\n",
   5.330  				razor_atomic_get_error_msg(atomic));
   5.331 -			razor_root_close(root);
   5.332  			razor_atomic_destroy(atomic);
   5.333  			razor_set_unref(upstream);
   5.334  			return 1;
   5.335 @@ -1141,7 +1130,7 @@
   5.336  		upstream = set;
   5.337  	}
   5.338  
   5.339 -	system = razor_set_ref(razor_root_get_system_set(root));
   5.340 +	system = razor_root_open_read_only(install_root, atomic);
   5.341  
   5.342  	trans = razor_transaction_create(system, upstream);
   5.343  
   5.344 @@ -1156,7 +1145,6 @@
   5.345  			razor_transaction_destroy(trans);
   5.346  			razor_set_unref(upstream);
   5.347  			razor_set_unref(system);
   5.348 -			razor_root_close(root);
   5.349  			razor_atomic_destroy(atomic);
   5.350  			return 1;
   5.351  		}
   5.352 @@ -1168,23 +1156,24 @@
   5.353  			razor_transaction_destroy(trans);
   5.354  			razor_set_unref(upstream);
   5.355  			razor_set_unref(system);
   5.356 -			razor_root_close(root);
   5.357  			razor_atomic_destroy(atomic);
   5.358  			return 1;
   5.359  		}
   5.360  	}
   5.361  
   5.362  	if (razor_atomic_create_dir(atomic, "rpms",
   5.363 -				    S_IRWXU | S_IRWXG | S_IRWXO)) {
   5.364 +				    S_IRWXU | S_IRWXG | S_IRWXO) ||
   5.365 +	    razor_atomic_commit(atomic)) {
   5.366  		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
   5.367  		razor_transaction_destroy(trans);
   5.368  		razor_set_unref(upstream);
   5.369  		razor_set_unref(system);
   5.370 -		razor_root_close(root);
   5.371  		razor_atomic_destroy(atomic);
   5.372  		return 1;
   5.373  	}
   5.374  
   5.375 +	razor_atomic_destroy(atomic);
   5.376 +
   5.377  	next = razor_transaction_commit(trans);
   5.378  
   5.379  	if (download_packages(system, next) < 0) {
   5.380 @@ -1192,43 +1181,18 @@
   5.381  		razor_transaction_destroy(trans);
   5.382  		razor_set_unref(upstream);
   5.383  		razor_set_unref(system);
   5.384 -		razor_root_close(root);
   5.385  		razor_atomic_destroy(atomic);
   5.386                  return 1;
   5.387          }
   5.388  
   5.389 -	ii = razor_set_create_install_iterator(system, next);
   5.390 +	retval = update_system(install_root, relocations, trans, system, next,
   5.391 +			       do_update ? "Update" : "Install");
   5.392  
   5.393 -	retval = update_packages(trans, ii, system, next, atomic, relocations,
   5.394 -				 UPDATE_PASS_PRE_REMOVE);
   5.395 -	if (retval)
   5.396 -		fprintf(stderr, "%s aborted\n",
   5.397 -			do_update ? "Update" : "Install");
   5.398 -	else {
   5.399 -		update_packages(trans, ii, system, next, atomic, relocations,
   5.400 -				UPDATE_PASS_MAIN);
   5.401 -
   5.402 -		razor_root_update(root, next);
   5.403 -
   5.404 -		razor_set_unref(upstream);
   5.405 -
   5.406 -		(void)razor_root_commit(root);
   5.407 -		retval = razor_atomic_commit(atomic);
   5.408 -		if (retval)
   5.409 -			fprintf(stderr, "%s\n",
   5.410 -				razor_atomic_get_error_msg(atomic));
   5.411 -		else
   5.412 -			(void)update_packages(trans, ii, system, next, atomic,
   5.413 -					      relocations,
   5.414 -					      UPDATE_PASS_POST_INSTALL);
   5.415 -	}
   5.416 +	razor_set_unref(upstream);
   5.417  
   5.418  	razor_transaction_destroy(trans);
   5.419  	if (relocations)
   5.420  		razor_relocations_destroy(relocations);
   5.421 -	razor_install_iterator_destroy(ii);
   5.422 -
   5.423 -	razor_atomic_destroy(atomic);
   5.424  
   5.425  	razor_set_unref(next);
   5.426  	razor_set_unref(system);
     6.1 --- a/test/zip.spec	Thu Feb 09 20:43:58 2012 +0000
     6.2 +++ b/test/zip.spec	Thu Feb 09 20:45:27 2012 +0000
     6.3 @@ -12,6 +12,7 @@
     6.4  BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
     6.5  Prefix:    /usr
     6.6  Requires:  zap
     6.7 +Requires(pre,postun):  zap
     6.8  
     6.9  %description
    6.10  Test package
     7.1 --- a/test/zsh.spec	Thu Feb 09 20:43:58 2012 +0000
     7.2 +++ b/test/zsh.spec	Thu Feb 09 20:45:27 2012 +0000
     7.3 @@ -12,6 +12,7 @@
     7.4  BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
     7.5  Prefix:    /usr
     7.6  Requires:  zip
     7.7 +Requires(pre,postun):  zip
     7.8  
     7.9  %description
    7.10  Test package