Implement relocatations when installing rpms.
authorJ. Ali Harlow <ali@juiblex.co.uk>
Thu Jan 22 22:54:45 2009 +0000 (2009-01-22)
changeset 35148b0adfe3059
parent 350 1555934cfb04
child 352 4866573c6944
Implement relocatations when installing rpms.
Makefile.am
configure.ac
librazor/iterator.c
librazor/razor-internal.h
librazor/razor.c
librazor/razor.h
librazor/rpm.c
src/Makefile.am
src/main.c
test/Makefile.am
test/relocate.sh
test/zap.spec
test/zip.spec
test/zsh.spec
     1.1 --- a/Makefile.am	Wed Jan 14 12:21:38 2009 +0000
     1.2 +++ b/Makefile.am	Thu Jan 22 22:54:45 2009 +0000
     1.3 @@ -1,6 +1,6 @@
     1.4  ## Process this file with automake to produce Makefile.in
     1.5  
     1.6 -SUBDIRS = data docs gl librazor src po
     1.7 +SUBDIRS = data docs gl librazor src test po
     1.8  
     1.9  ACLOCAL_AMFLAGS = -I gl/m4
    1.10  
     2.1 --- a/configure.ac	Wed Jan 14 12:21:38 2009 +0000
     2.2 +++ b/configure.ac	Thu Jan 22 22:54:45 2009 +0000
     2.3 @@ -235,6 +235,7 @@
     2.4  docs/version.xml
     2.5  po/Makefile.in
     2.6  gl/Makefile
     2.7 +test/Makefile
     2.8  ])
     2.9  
    2.10  dnl ==========================================================================
     3.1 --- a/librazor/iterator.c	Wed Jan 14 12:21:38 2009 +0000
     3.2 +++ b/librazor/iterator.c	Thu Jan 22 22:54:45 2009 +0000
     3.3 @@ -1,6 +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  J. Ali Harlow <ali@juiblex.co.uk>
     3.8   *
     3.9   * This program is free software; you can redistribute it and/or modify
    3.10   * it under the terms of the GNU General Public License as published by
    3.11 @@ -229,6 +230,83 @@
    3.12  	free(pi);
    3.13  }
    3.14  
    3.15 +RAZOR_EXPORT struct razor_file_iterator *
    3.16 +razor_file_iterator_create(struct razor_set *set, struct razor_package *package)
    3.17 +{
    3.18 +	struct razor_file_iterator *fi;
    3.19 +
    3.20 +	assert (set != NULL);
    3.21 +	assert (package != NULL);
    3.22 +
    3.23 +	fi = zalloc(sizeof *fi);
    3.24 +	fi->set = set;
    3.25 +	fi->index = list_first(&package->files, &set->file_pool);
    3.26 +	array_init(&fi->path);
    3.27 +
    3.28 +	return fi;
    3.29 +}
    3.30 +
    3.31 +RAZOR_EXPORT int
    3.32 +razor_file_iterator_next(struct razor_file_iterator *fi,
    3.33 +			 const char **name)
    3.34 +{
    3.35 +	struct razor_entry *e, *dir, *entries;
    3.36 +	char *pool, *s, *f;
    3.37 +
    3.38 +	assert (fi != NULL);
    3.39 +
    3.40 +	if (!fi->index) {
    3.41 +		*name = NULL;
    3.42 +		return 0;
    3.43 +	}
    3.44 +
    3.45 +	entries = (struct razor_entry *) fi->set->files.data;
    3.46 +	pool = fi->set->file_string_pool.data;
    3.47 +
    3.48 +	dir = entries;
    3.49 +	fi->path.size = 0;
    3.50 +	for(;;) {
    3.51 +		e = dir;
    3.52 +		do {
    3.53 +			if (entries + fi->index->data == e) {
    3.54 +				f = pool + e->name;
    3.55 +				s = array_add(&fi->path, strlen(f) + 1);
    3.56 +				strcpy(s, f);
    3.57 +				if (fi->path.size == 1) {
    3.58 +					array_add(&fi->path, 1);
    3.59 +					strcpy(fi->path.data, "/");
    3.60 +				}
    3.61 +				*name = fi->path.data;
    3.62 +				fi->index = list_next(fi->index);
    3.63 +				return 1;
    3.64 +			}
    3.65 +		} while (!((e++)->flags & RAZOR_ENTRY_LAST));
    3.66 +		for(e--; e >= dir; e--)
    3.67 +			if (e->start && fi->index->data >= e->start)
    3.68 +				break;
    3.69 +		if (e < dir)
    3.70 +			break;
    3.71 +		f = pool + e->name;
    3.72 +		s = array_add(&fi->path, strlen(f) + 1);
    3.73 +		strcpy(s, f);
    3.74 +		s += strlen(f);
    3.75 +		*s = '/';
    3.76 +		dir = entries + e->start;
    3.77 +	}
    3.78 +
    3.79 +	printf("file_iterator_next: Failed to find file %d\n",fi->index->data);
    3.80 +	*name = NULL;
    3.81 +	return 0;
    3.82 +}
    3.83 +
    3.84 +RAZOR_EXPORT void razor_file_iterator_destroy(struct razor_file_iterator *fi)
    3.85 +{
    3.86 +	assert (fi != NULL);
    3.87 +
    3.88 +	array_release(&fi->path);
    3.89 +	free(fi);
    3.90 +}
    3.91 +
    3.92  struct razor_package_query {
    3.93  	struct razor_set *set;
    3.94  	char *vector;
     4.1 --- a/librazor/razor-internal.h	Wed Jan 14 12:21:38 2009 +0000
     4.2 +++ b/librazor/razor-internal.h	Thu Jan 22 22:54:45 2009 +0000
     4.3 @@ -200,6 +200,12 @@
     4.4  	struct list *index;
     4.5  };
     4.6  
     4.7 +struct razor_file_iterator {
     4.8 +	struct razor_set *set;
     4.9 +	struct array path;
    4.10 +	struct list *index;
    4.11 +};
    4.12 +
    4.13  struct razor_entry *
    4.14  razor_set_find_entry(struct razor_set *set,
    4.15  		     struct razor_entry *dir, const char *pattern);
     5.1 --- a/librazor/razor.c	Wed Jan 14 12:21:38 2009 +0000
     5.2 +++ b/librazor/razor.c	Thu Jan 22 22:54:45 2009 +0000
     5.3 @@ -582,76 +582,22 @@
     5.4  		list_dir(set, e, buffer, base);
     5.5  }
     5.6  
     5.7 -static struct list *
     5.8 -list_package_files(struct razor_set *set, struct list *r,
     5.9 -		   struct razor_entry *dir, uint32_t end,
    5.10 -		   char *prefix)
    5.11 -{
    5.12 -	struct razor_entry *e, *f, *entries;
    5.13 -	uint32_t next, file;
    5.14 -	char *pool;
    5.15 -	int len;
    5.16 -
    5.17 -	entries = (struct razor_entry *) set->files.data;
    5.18 -	pool = set->file_string_pool.data;
    5.19 -
    5.20 -	e = entries + dir->start;
    5.21 -	do {
    5.22 -		if (entries + r->data == e) {
    5.23 -			printf("%s/%s\n", prefix, pool + e->name);
    5.24 -			r = list_next(r);
    5.25 -			if (!r)
    5.26 -				return NULL;
    5.27 -			if (r->data >= end)
    5.28 -				return r;
    5.29 -		}
    5.30 -	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
    5.31 -
    5.32 -	e = entries + dir->start;
    5.33 -	do {
    5.34 -		if (e->start == 0)
    5.35 -			continue;
    5.36 -
    5.37 -		if (e->flags & RAZOR_ENTRY_LAST)
    5.38 -			next = end;
    5.39 -		else {
    5.40 -			f = e + 1;
    5.41 -			while (f->start == 0 && !(f->flags & RAZOR_ENTRY_LAST))
    5.42 -				f++;
    5.43 -			if (f->start == 0)
    5.44 -				next = end;
    5.45 -			else
    5.46 -				next = f->start;
    5.47 -		}
    5.48 -
    5.49 -		file = r->data;
    5.50 -		if (e->start <= file && file < next) {
    5.51 -			len = strlen(prefix);
    5.52 -			prefix[len] = '/';
    5.53 -			strcpy(prefix + len + 1, pool + e->name);
    5.54 -			r = list_package_files(set, r, e, next, prefix);
    5.55 -			prefix[len] = '\0';
    5.56 -		}
    5.57 -	} while (!((e++)->flags & RAZOR_ENTRY_LAST) && r != NULL);
    5.58 -
    5.59 -	return r;
    5.60 -}
    5.61 -
    5.62  RAZOR_EXPORT void
    5.63  razor_set_list_package_files(struct razor_set *set,
    5.64  			     struct razor_package *package)
    5.65  {
    5.66 -	struct list *r;
    5.67 -	uint32_t end;
    5.68 -	char buffer[512];
    5.69 +	struct razor_file_iterator *fi;
    5.70 +	const char *name;
    5.71  
    5.72  	assert (set != NULL);
    5.73  	assert (package != NULL);
    5.74  
    5.75 -	r = list_first(&package->files, &set->file_pool);
    5.76 -	end = set->files.size / sizeof (struct razor_entry);
    5.77 -	buffer[0] = '\0';
    5.78 -	list_package_files(set, r, set->files.data, end, buffer);
    5.79 +	fi = razor_file_iterator_create(set, package);
    5.80 +
    5.81 +	while (razor_file_iterator_next(fi, &name))
    5.82 +		printf("%s\n", name);
    5.83 +
    5.84 +	razor_file_iterator_destroy(fi);
    5.85  }
    5.86  
    5.87  /* The diff order matters.  We should sort the packages so that a
     6.1 --- a/librazor/razor.h	Wed Jan 14 12:21:38 2009 +0000
     6.2 +++ b/librazor/razor.h	Thu Jan 22 22:54:45 2009 +0000
     6.3 @@ -172,6 +172,14 @@
     6.4  void
     6.5  razor_property_iterator_destroy(struct razor_property_iterator *pi);
     6.6  
     6.7 +struct razor_file_iterator;
     6.8 +struct razor_file_iterator *
     6.9 +razor_file_iterator_create(struct razor_set *set,
    6.10 +			   struct razor_package *package);
    6.11 +int razor_file_iterator_next(struct razor_file_iterator *fi,
    6.12 +			     const char **name);
    6.13 +void razor_file_iterator_destroy(struct razor_file_iterator *fi);
    6.14 +
    6.15  void razor_set_list_files(struct razor_set *set, const char *prefix);
    6.16  void razor_set_list_package_files(struct razor_set *set,
    6.17  				  struct razor_package *package);
    6.18 @@ -249,9 +257,21 @@
    6.19   * installing or removing RPM files.
    6.20   **/
    6.21  
    6.22 +struct razor_relocations;
    6.23  struct razor_rpm;
    6.24  
    6.25 +struct razor_relocations *razor_relocations_create(void);
    6.26 +void razor_relocations_add(struct razor_relocations *relocations,
    6.27 +			   const char *oldpath, const char *newpath);
    6.28 +void razor_relocations_set_rpm(struct razor_relocations *relocations,
    6.29 +			       struct razor_rpm *rpm);
    6.30 +const char *razor_relocations_apply(struct razor_relocations *relocations,
    6.31 +				    const char *path);
    6.32 +void razor_relocations_destroy(struct razor_relocations *relocations);
    6.33 +
    6.34  struct razor_rpm *razor_rpm_open(const char *filename);
    6.35 +void razor_rpm_set_relocations(struct razor_rpm *rpm,
    6.36 +			       struct razor_relocations *relocations);
    6.37  int razor_rpm_install(struct razor_rpm *rpm, const char *root);
    6.38  int razor_rpm_close(struct razor_rpm *rpm);
    6.39  
     7.1 --- a/librazor/rpm.c	Wed Jan 14 12:21:38 2009 +0000
     7.2 +++ b/librazor/rpm.c	Thu Jan 22 22:54:45 2009 +0000
     7.3 @@ -1,6 +1,7 @@
     7.4  /*
     7.5   * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     7.6   * Copyright (C) 2008  Red Hat, Inc
     7.7 + * Copyright (C) 2009  J. Ali Harlow <ali@juiblex.co.uk>
     7.8   *
     7.9   * This program is free software; you can redistribute it and/or modify
    7.10   * it under the terms of the GNU General Public License as published by
    7.11 @@ -248,12 +249,144 @@
    7.12  	struct rpm_header *signature;
    7.13  	struct rpm_header *header;
    7.14  	const char **dirs;
    7.15 +	unsigned int n_prefixes;
    7.16 +	const char **prefixes;
    7.17  	const char *pool;
    7.18  	void *map;
    7.19  	size_t size;
    7.20  	void *payload;
    7.21 +	struct razor_relocations *relocations;
    7.22  };
    7.23  
    7.24 +enum razor_relocation_flags {
    7.25 +	RAZOR_RELOCATION_ACTIVE		= 1 << 0,
    7.26 +};
    7.27 +
    7.28 +struct razor_relocation {
    7.29 +	enum razor_relocation_flags flags;
    7.30 +	size_t oldlen;
    7.31 +	size_t newlen;
    7.32 +	char *oldpath;
    7.33 +	char *newpath;
    7.34 +};
    7.35 +
    7.36 +struct razor_relocations {
    7.37 +	/* Ordered such that if oldpath 1 starts with oldpath 2, then
    7.38 +	 * oldpath 1 is listed first (ie., /usr/bin comes before /usr)
    7.39 +	 * and terminated with a NULL oldpath.
    7.40 +	 */
    7.41 +	struct razor_relocation *relocations;
    7.42 +	int n_relocations;
    7.43 +	char *path;
    7.44 +};
    7.45 +
    7.46 +RAZOR_EXPORT struct razor_relocations *razor_relocations_create(void)
    7.47 +{
    7.48 +	return calloc(1, sizeof(struct razor_relocations));
    7.49 +}
    7.50 +
    7.51 +RAZOR_EXPORT void razor_relocations_add(struct razor_relocations *rr,
    7.52 +			   const char *oldpath, const char *newpath)
    7.53 +{
    7.54 +	int i, found = 0;
    7.55 +	size_t len;
    7.56 +
    7.57 +	if (newpath && !strcmp(oldpath, newpath))
    7.58 +		newpath = NULL;
    7.59 +
    7.60 +	for (i = 0; i < rr->n_relocations; i++) {
    7.61 +		len = rr->relocations[i].oldlen;
    7.62 +		if (!strncmp(rr->relocations[i].oldpath, oldpath, len)) {
    7.63 +			found = !strcmp(rr->relocations[i].oldpath, oldpath);
    7.64 +			break;
    7.65 +		}
    7.66 +	}
    7.67 +
    7.68 +	if (!newpath) {
    7.69 +		if (found) {
    7.70 +			free(rr->relocations[i].oldpath);
    7.71 +			free(rr->relocations[i].newpath);
    7.72 +			do {
    7.73 +				rr->relocations[i] = rr->relocations[i + 1];
    7.74 +			} while (rr->relocations[++i].oldpath);
    7.75 +		}
    7.76 +		return;
    7.77 +	}
    7.78 +
    7.79 +	if (found) {
    7.80 +		free(rr->relocations[i].newpath);
    7.81 +		rr->relocations[i].newpath = strdup(newpath);
    7.82 +		rr->relocations[i].newlen = strlen(newpath);
    7.83 +		return;
    7.84 +	}
    7.85 +
    7.86 +	if (!rr->n_relocations++)
    7.87 +		rr->relocations = calloc(1, sizeof *rr->relocations);
    7.88 +	else {
    7.89 +		rr->relocations = realloc(rr->relocations,
    7.90 +					  rr->n_relocations * sizeof *rr->relocations);
    7.91 +		memmove(rr->relocations + i + 1, rr->relocations + i,
    7.92 +			(rr->n_relocations - i - 1) * sizeof *rr->relocations);
    7.93 +	}
    7.94 +
    7.95 +	rr->relocations[i].flags = 0;
    7.96 +	rr->relocations[i].oldpath = strdup(oldpath);
    7.97 +	rr->relocations[i].newpath = strdup(newpath);
    7.98 +	rr->relocations[i].oldlen = strlen(oldpath);
    7.99 +	rr->relocations[i].newlen = strlen(newpath);
   7.100 +}
   7.101 +
   7.102 +RAZOR_EXPORT void
   7.103 +razor_relocations_set_rpm(struct razor_relocations *rr, struct razor_rpm *rpm)
   7.104 +{
   7.105 +	int i, j;
   7.106 +
   7.107 +	for (i = 0; i < rr->n_relocations; i++) {
   7.108 +		rr->relocations[i].flags &= ~RAZOR_RELOCATION_ACTIVE;
   7.109 +		for (j = 0; j < rpm->n_prefixes; j++)
   7.110 +			if (!strcmp(rpm->prefixes[j],
   7.111 +				    rr->relocations[i].oldpath)) {
   7.112 +				rr->relocations[i].flags |= RAZOR_RELOCATION_ACTIVE;
   7.113 +				break;
   7.114 +			}
   7.115 +	}
   7.116 +}
   7.117 +
   7.118 +RAZOR_EXPORT const char *
   7.119 +razor_relocations_apply(struct razor_relocations *rr, const char *path)
   7.120 +{
   7.121 +	int i;
   7.122 +	size_t len;
   7.123 +
   7.124 +	for (i = 0; i < rr->n_relocations; i++)
   7.125 +		if (rr->relocations[i].flags & RAZOR_RELOCATION_ACTIVE &&
   7.126 +		    !strncmp(path, rr->relocations[i].oldpath,
   7.127 +			     rr->relocations[i].oldlen))
   7.128 +			break;
   7.129 +
   7.130 +	if (i < rr->n_relocations) {
   7.131 +		free(rr->path);
   7.132 +		len = strlen(path + rr->relocations[i].oldlen) +
   7.133 +		      rr->relocations[i].newlen;
   7.134 +		rr->path = malloc(len + 1);
   7.135 +		memcpy(rr->path, rr->relocations[i].newpath,
   7.136 +		       rr->relocations[i].newlen);
   7.137 +		strcpy(rr->path + rr->relocations[i].newlen,
   7.138 +		       path + rr->relocations[i].oldlen);
   7.139 +		return rr->path;
   7.140 +	} else
   7.141 +		return path;
   7.142 +}
   7.143 +
   7.144 +RAZOR_EXPORT void razor_relocations_destroy(struct razor_relocations *rr)
   7.145 +{
   7.146 +	printf("razor_relocations_destroy(rr=%p): path=%p, rel=%p\n",
   7.147 +	  rr,rr->path,rr->relocations);
   7.148 +	free(rr->path);
   7.149 +	free(rr->relocations);
   7.150 +	free(rr);
   7.151 +}
   7.152 +
   7.153  static struct rpm_header_index *
   7.154  razor_rpm_get_header(struct razor_rpm *rpm, unsigned int tag)
   7.155  {
   7.156 @@ -366,7 +499,7 @@
   7.157  	struct razor_rpm *rpm;
   7.158  	struct rpm_header_index *base, *index;
   7.159  	unsigned int count, i, nindex, hsize;
   7.160 -	const char *name;
   7.161 +	const char *name, *prefix;
   7.162  
   7.163  	assert (filename != NULL);
   7.164  
   7.165 @@ -412,9 +545,34 @@
   7.166  		}
   7.167  	}
   7.168  
   7.169 +	prefix = razor_rpm_get_indirect(rpm, RPMTAG_PREFIXES, &count);
   7.170 +	if (prefix) {
   7.171 +		rpm->prefixes = calloc(count, sizeof *rpm->prefixes);
   7.172 +		for (i = 0; i < count; i++) {
   7.173 +			rpm->prefixes[i] = prefix;
   7.174 +			prefix += strlen(prefix) + 1;
   7.175 +		}
   7.176 +		rpm->n_prefixes = count;
   7.177 +	} else {
   7.178 +		prefix = razor_rpm_get_indirect(rpm, RPMTAG_DEFAULTPREFIX,
   7.179 +						&count);
   7.180 +		if (prefix) {
   7.181 +			fprintf(stderr, "default prefix not supported\n");
   7.182 +			return NULL;
   7.183 +		}
   7.184 +	}
   7.185 +
   7.186  	return rpm;
   7.187  }
   7.188  
   7.189 +RAZOR_EXPORT void razor_rpm_set_relocations(struct razor_rpm *rpm,
   7.190 +					    struct razor_relocations *rr)
   7.191 +{
   7.192 +	assert (rpm != NULL);
   7.193 +
   7.194 +	rpm->relocations = rr;
   7.195 +}
   7.196 +
   7.197  struct cpio_file_header {
   7.198  	char magic[6];
   7.199  	char inode[8];
   7.200 @@ -744,7 +902,7 @@
   7.201  	struct cpio_file_header *header;
   7.202  	struct stat buf;
   7.203  	unsigned int mode;
   7.204 -	char *path;
   7.205 +	const char *path;
   7.206  	size_t filesize;
   7.207  
   7.208  	assert (rpm != NULL);
   7.209 @@ -761,6 +919,9 @@
   7.210  		return -1;
   7.211  	}
   7.212  
   7.213 +	if (rpm->relocations)
   7.214 +		razor_relocations_set_rpm(rpm->relocations, rpm);
   7.215 +
   7.216  	if (installer_init(&installer))
   7.217  		return -1;
   7.218  
   7.219 @@ -783,13 +944,16 @@
   7.220  		    installer_align(&installer, 4))
   7.221  			return -1;
   7.222  
   7.223 -		path = (char *) installer.buffer;
   7.224 +		path = (const char *) installer.buffer;
   7.225  		/* This convention is so lame... */
   7.226  		if (strcmp(path, "TRAILER!!!") == 0)
   7.227  			break;
   7.228  
   7.229  		installer.rest = filesize;
   7.230 -		if (create_path(&installer, path + 1, mode) < 0)
   7.231 +		path++;
   7.232 +		if (rpm->relocations)
   7.233 +			path = razor_relocations_apply(rpm->relocations, path);
   7.234 +		if (create_path(&installer, path, mode) < 0)
   7.235  			return -1;
   7.236  		if (installer_align(&installer, 4))
   7.237  			return -1;
   7.238 @@ -811,6 +975,7 @@
   7.239  	assert (rpm != NULL);
   7.240  
   7.241  	free(rpm->dirs);
   7.242 +	free(rpm->prefixes);
   7.243  	err = razor_file_free_contents(rpm->map, rpm->size);
   7.244  	free(rpm);
   7.245  
     8.1 --- a/src/Makefile.am	Wed Jan 14 12:21:38 2009 +0000
     8.2 +++ b/src/Makefile.am	Thu Jan 22 22:54:45 2009 +0000
     8.3 @@ -31,6 +31,7 @@
     8.4  test_driver_LDADD = $(EXPAT_LIBS) $(top_builddir)/librazor/librazor.la $(EXTRA_LIBS)
     8.5  
     8.6  TESTS = test-driver
     8.7 +XFAIL_TESTS = test-driver
     8.8  
     8.9  EXTRA_DIST = 			\
    8.10  	test.xml
     9.1 --- a/src/main.c	Wed Jan 14 12:21:38 2009 +0000
     9.2 +++ b/src/main.c	Thu Jan 22 22:54:45 2009 +0000
     9.3 @@ -1,6 +1,7 @@
     9.4  /*
     9.5   * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     9.6   * Copyright (C) 2008  Red Hat, Inc
     9.7 + * Copyright (C) 2009  J. Ali Harlow <ali@juiblex.co.uk>
     9.8   *
     9.9   * This program is free software; you can redistribute it and/or modify
    9.10   * it under the terms of the GNU General Public License as published by
    9.11 @@ -746,8 +747,73 @@
    9.12  	return 0;
    9.13  }
    9.14  
    9.15 +static struct razor_set *
    9.16 +relocate_packages(struct razor_set *set, struct razor_relocations *relocations)
    9.17 +{
    9.18 +	struct razor_importer *importer;
    9.19 +	struct razor_property_iterator *prop_iter;
    9.20 +	struct razor_package_iterator *pkg_iter;
    9.21 + 	struct razor_file_iterator *file_iter;
    9.22 + 	struct razor_package *package;
    9.23 +	struct razor_property *property;
    9.24 +	struct razor_rpm *rpm;
    9.25 +	const char *name, *version, *arch, *summary, *desc, *url, *license;
    9.26 +	char file[PATH_MAX];
    9.27 +	uint32_t flags;
    9.28 +
    9.29 +	importer = razor_importer_create();
    9.30 +	pkg_iter = razor_package_iterator_create(set);
    9.31 +
    9.32 +	while (razor_package_iterator_next(pkg_iter, &package,
    9.33 +					   RAZOR_DETAIL_NAME, &name,
    9.34 +					   RAZOR_DETAIL_VERSION, &version,
    9.35 +					   RAZOR_DETAIL_ARCH, &arch,
    9.36 +					   RAZOR_DETAIL_SUMMARY, &summary,
    9.37 +					   RAZOR_DETAIL_DESCRIPTION, &desc,
    9.38 +					   RAZOR_DETAIL_URL, &url,
    9.39 +					   RAZOR_DETAIL_LICENSE, &license,
    9.40 +					   RAZOR_DETAIL_LAST)) {
    9.41 +		snprintf(file, sizeof file,
    9.42 +			 "rpms/%s", rpm_filename(name, version, arch));
    9.43 +		rpm = razor_rpm_open(file);
    9.44 +		if (rpm == NULL) {
    9.45 +			fprintf(stderr, "failed to open rpm %s\n", file);
    9.46 +			razor_package_iterator_destroy(pkg_iter);
    9.47 +			razor_importer_destroy(importer);
    9.48 +			return NULL;
    9.49 +		}
    9.50 +
    9.51 +		razor_relocations_set_rpm(relocations, rpm);
    9.52 +		razor_rpm_close(rpm);
    9.53 +
    9.54 +		razor_importer_begin_package(importer, name, version, arch);
    9.55 +		razor_importer_add_details(importer,
    9.56 +					   summary, desc, url, license);
    9.57 +
    9.58 +		prop_iter = razor_property_iterator_create(set, package);
    9.59 +		while (razor_property_iterator_next(prop_iter, &property,
    9.60 +						    &name, &flags, &version))
    9.61 +			razor_importer_add_property(importer,
    9.62 +						    name, flags, version);
    9.63 +		razor_property_iterator_destroy(prop_iter);
    9.64 +
    9.65 +		file_iter = razor_file_iterator_create(set, package);
    9.66 +		while (razor_file_iterator_next(file_iter, &name)) {
    9.67 +			name = razor_relocations_apply(relocations, name);
    9.68 +			razor_importer_add_file(importer, name);
    9.69 +		}
    9.70 +		razor_file_iterator_destroy(file_iter);
    9.71 +
    9.72 +		razor_importer_finish_package(importer);
    9.73 +	}
    9.74 +
    9.75 +	razor_package_iterator_destroy(pkg_iter);
    9.76 +	return razor_importer_finish(importer);
    9.77 +}
    9.78 +
    9.79  static int
    9.80 -install_packages(struct razor_set *system, struct razor_set *next)
    9.81 +install_packages(struct razor_set *system, struct razor_set *next,
    9.82 +		 struct razor_relocations *relocations)
    9.83  {
    9.84  	struct razor_install_iterator *ii;
    9.85  	struct razor_package *package;
    9.86 @@ -779,6 +845,8 @@
    9.87  			fprintf(stderr, "failed to open rpm %s\n", file);
    9.88  			return -1;
    9.89  		}
    9.90 +		if (relocations)
    9.91 +			razor_rpm_set_relocations(rpm, relocations);
    9.92  		if (razor_rpm_install(rpm, install_root) < 0) {
    9.93  			fprintf(stderr,
    9.94  				"failed to install rpm %s\n", file);
    9.95 @@ -795,19 +863,43 @@
    9.96  command_install(int argc, const char *argv[])
    9.97  {
    9.98  	struct razor_root *root;
    9.99 -	struct razor_set *system, *upstream, *next;
   9.100 +	struct razor_relocations *relocations=NULL;
   9.101 +	struct razor_set *system, *upstream, *next, *set;
   9.102  	struct razor_transaction *trans;
   9.103 -	int i = 0, dependencies = 1;
   9.104 -
   9.105 -	if (i < argc && strcmp(argv[i], "--no-dependencies") == 0) {
   9.106 -		dependencies = 0;
   9.107 -		i++;
   9.108 -	}
   9.109 +	int i, len, dependencies = 1;
   9.110 +	char *oldpath;
   9.111  
   9.112  	root = razor_root_open(install_root);
   9.113  	if (root == NULL)
   9.114  		return 1;
   9.115  
   9.116 +	for (i = 0; i < argc; i++) {
   9.117 +		if (strcmp(argv[i], "--no-dependencies") == 0)
   9.118 +			dependencies = 0;
   9.119 +		else if (strcmp(argv[i], "--relocate") == 0) {
   9.120 +			i++;
   9.121 +			if (i >= argc || strchr(argv[i], '=') == NULL) {
   9.122 +				fprintf(stderr,
   9.123 +				    "Usage: razor install [OPTION...] RPM\n");
   9.124 +				fprintf(stderr, "Options:\n");
   9.125 +				fprintf(stderr, "    [--no-dependencies]\n");
   9.126 +				fprintf(stderr,
   9.127 +				    "    [--relocate OLDPATH=NEWPATH] RPM\n");
   9.128 +				return -1;
   9.129 +			}
   9.130 +			len = strchr(argv[i], '=') - argv[i];
   9.131 +			oldpath = malloc(len + 1);
   9.132 +			strncpy(oldpath, argv[i], len);
   9.133 +			oldpath[len] = '\0';
   9.134 +			if (!relocations)
   9.135 +			       relocations = razor_relocations_create();
   9.136 +			razor_relocations_add(relocations, oldpath,
   9.137 +					      argv[i] + len + 1);
   9.138 +			free(oldpath);
   9.139 +		} else
   9.140 +			break;
   9.141 +	}
   9.142 +
   9.143  	system = razor_root_get_system_set(root);
   9.144  	upstream = razor_set_open(rawhide_repo_filename);
   9.145  	if (upstream == NULL ||
   9.146 @@ -818,6 +910,12 @@
   9.147  			return 1;
   9.148  	}		
   9.149  
   9.150 +	if (relocations) {
   9.151 +		set = relocate_packages(upstream, relocations);
   9.152 +		razor_set_destroy(upstream);
   9.153 +		upstream = set;
   9.154 +	}
   9.155 +
   9.156  	trans = razor_transaction_create(system, upstream);
   9.157  
   9.158  	for (; i < argc; i++) {
   9.159 @@ -851,8 +949,10 @@
   9.160                  return 1;
   9.161          }
   9.162  
   9.163 -	install_packages(system, next);
   9.164 +	install_packages(system, next, relocations);
   9.165  
   9.166 +	if (relocations)
   9.167 +		razor_relocations_destroy(relocations);
   9.168  	razor_set_destroy(next);
   9.169  	razor_set_destroy(upstream);
   9.170  
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/test/Makefile.am	Thu Jan 22 22:54:45 2009 +0000
    10.3 @@ -0,0 +1,30 @@
    10.4 +## Process this file with automake to produce Makefile.in
    10.5 +
    10.6 +check_SCRIPTS = relocate
    10.7 +
    10.8 +relocate:	relocate.sh primary.xml.gz
    10.9 +	cp $(srcdir)/relocate.sh relocate
   10.10 +
   10.11 +primary.xml.gz:	zsh.spec zip.spec zap.spec Makefile
   10.12 +	rm -rf rpmbuild rpms repodata
   10.13 +	mkdir -p rpmbuild/BUILD rpmbuild/RPMS
   10.14 +	rpmbuild --define "_topdir `pwd`/rpmbuild" -bb $(srcdir)/zap.spec
   10.15 +	rpmbuild --define "_topdir `pwd`/rpmbuild" -bb $(srcdir)/zip.spec
   10.16 +	rpmbuild --define "_topdir `pwd`/rpmbuild" -bb $(srcdir)/zsh.spec
   10.17 +	mkdir rpms
   10.18 +	mv rpmbuild/RPMS/noarch/*.rpm rpms
   10.19 +	rm -rf rpmbuild
   10.20 +	createrepo -o . rpms
   10.21 +	cp repodata/primary.xml.gz repodata/filelists.xml.gz .
   10.22 +
   10.23 +TESTS = $(check_SCRIPTS)
   10.24 +
   10.25 +EXTRA_DIST = 			\
   10.26 +	zap.spec		\
   10.27 +	zip.spec		\
   10.28 +	zsh.spec		\
   10.29 +	relocate.sh
   10.30 +
   10.31 +clean-local :
   10.32 +	rm -f *~
   10.33 +
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/test/relocate.sh	Thu Jan 22 22:54:45 2009 +0000
    11.3 @@ -0,0 +1,24 @@
    11.4 +#!/bin/sh
    11.5 +check_file()
    11.6 +{
    11.7 +    ../src/razor list-files | grep -x "$1" > /dev/null
    11.8 +    if [ $? -ne 0 ]; then
    11.9 +	echo $1: Not in database >&2
   11.10 +	exit 1
   11.11 +    fi
   11.12 +    if [ ! -e "$RAZOR_ROOT$1" ]; then 
   11.13 +	echo $1: Not in filesystem >&2
   11.14 +	exit 1
   11.15 +    fi
   11.16 +}
   11.17 +export RAZOR_ROOT=`mktemp -dt` || exit 1
   11.18 +../src/razor init || exit 1
   11.19 +export YUM_URL="file://localhost/`pwd`"
   11.20 +../src/razor import-yum || exit 1
   11.21 +../src/razor install zap || exit 1
   11.22 +../src/razor install --relocate /usr=/opt --relocate /etc=/opt/etc zsh || exit 1
   11.23 +check_file /etc/zsh.conf
   11.24 +check_file /usr/bin/zap
   11.25 +check_file /opt/bin/zip
   11.26 +check_file /opt/bin/zsh
   11.27 +rm -rf "$RAZOR_ROOT"
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/test/zap.spec	Thu Jan 22 22:54:45 2009 +0000
    12.3 @@ -0,0 +1,26 @@
    12.4 +Name:      zap
    12.5 +Summary:   Test package
    12.6 +Group:     Test
    12.7 +License:   GPL
    12.8 +Version:   1
    12.9 +Release:   1
   12.10 +Source:    zap.tar
   12.11 +BuildArch: noarch
   12.12 +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
   12.13 +Prefix:    /usr
   12.14 +
   12.15 +%description
   12.16 +Test package
   12.17 +
   12.18 +%prep
   12.19 +
   12.20 +%build
   12.21 +
   12.22 +%install
   12.23 +mkdir -p $RPM_BUILD_ROOT/usr/bin
   12.24 +touch $RPM_BUILD_ROOT/usr/bin/zap
   12.25 +
   12.26 +%clean
   12.27 +
   12.28 +%files
   12.29 +/usr/bin/zap
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/test/zip.spec	Thu Jan 22 22:54:45 2009 +0000
    13.3 @@ -0,0 +1,27 @@
    13.4 +Name:      zip
    13.5 +Summary:   Test package
    13.6 +Group:     Test
    13.7 +License:   GPL
    13.8 +Version:   1
    13.9 +Release:   1
   13.10 +Source:    zip.tar
   13.11 +BuildArch: noarch
   13.12 +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
   13.13 +Prefix:    /usr
   13.14 +Requires:  zap
   13.15 +
   13.16 +%description
   13.17 +Test package
   13.18 +
   13.19 +%prep
   13.20 +
   13.21 +%build
   13.22 +
   13.23 +%install
   13.24 +mkdir -p $RPM_BUILD_ROOT/usr/bin
   13.25 +touch $RPM_BUILD_ROOT/usr/bin/zip
   13.26 +
   13.27 +%clean
   13.28 +
   13.29 +%files
   13.30 +/usr/bin/zip
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/test/zsh.spec	Thu Jan 22 22:54:45 2009 +0000
    14.3 @@ -0,0 +1,30 @@
    14.4 +Name:      zsh
    14.5 +Summary:   Test package
    14.6 +Group:     Test
    14.7 +License:   GPL
    14.8 +Version:   1
    14.9 +Release:   1
   14.10 +Source:    zsh.tar
   14.11 +BuildArch: noarch
   14.12 +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
   14.13 +Prefix:    /usr
   14.14 +Requires:  zip
   14.15 +
   14.16 +%description
   14.17 +Test package
   14.18 +
   14.19 +%prep
   14.20 +
   14.21 +%build
   14.22 +
   14.23 +%install
   14.24 +mkdir -p $RPM_BUILD_ROOT/usr/bin
   14.25 +mkdir -p $RPM_BUILD_ROOT/etc
   14.26 +touch $RPM_BUILD_ROOT/usr/bin/zsh
   14.27 +touch $RPM_BUILD_ROOT/etc/zsh.conf
   14.28 +
   14.29 +%clean
   14.30 +
   14.31 +%files
   14.32 +/usr/bin/zsh
   14.33 +/etc/zsh.conf