src/main.c
author J. Ali Harlow <ali@juiblex.co.uk>
Thu Jan 22 22:54:45 2009 +0000 (2009-01-22)
changeset 351 48b0adfe3059
parent 350 1555934cfb04
child 359 c9c90315ea24
permissions -rw-r--r--
Implement relocatations when installing rpms.
     1 /*
     2  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     3  * Copyright (C) 2008  Red Hat, Inc
     4  * Copyright (C) 2009  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 <stdio.h>
    28 #include <stdint.h>
    29 #include <string.h>
    30 #include <sys/stat.h>
    31 #include <unistd.h>
    32 #include <fcntl.h>
    33 #include <dirent.h>
    34 #include <limits.h>
    35 #ifdef HAVE_CURL
    36 #include <curl/curl.h>
    37 #endif
    38 #include <fnmatch.h>
    39 #include <errno.h>
    40 #include "razor.h"
    41 
    42 static const char system_repo_filename[] = "system.rzdb";
    43 static const char next_repo_filename[] = "system-next.rzdb";
    44 static const char rawhide_repo_filename[] = "rawhide.rzdb";
    45 static const char updated_repo_filename[] = "system-updated.rzdb";
    46 static const char *install_root = "";
    47 static const char *repo_filename = system_repo_filename;
    48 static const char *yum_url;
    49 
    50 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
    51 
    52 static struct razor_package_iterator *
    53 create_iterator_from_argv(struct razor_set *set, int argc, const char *argv[])
    54 {
    55 	struct razor_package_query *query;
    56 	struct razor_package_iterator *iter;
    57 	struct razor_package *package;
    58 	const char *name, *pattern;
    59 	int i, count;
    60 
    61 	if (argc == 0)
    62 		return razor_package_iterator_create(set);
    63 
    64 	query = razor_package_query_create(set);
    65 
    66 	for (i = 0; i < argc; i++) {
    67 		iter = razor_package_iterator_create(set);
    68 		pattern = argv[i];
    69 		count = 0;
    70 		while (razor_package_iterator_next(iter, &package,
    71 						   RAZOR_DETAIL_NAME, &name,
    72 						   RAZOR_DETAIL_LAST)) {
    73 			if (fnmatch(pattern, name, 0) != 0)
    74 				continue;
    75 
    76 			razor_package_query_add_package(query, package);
    77 			count++;
    78 		}
    79 		razor_package_iterator_destroy(iter);
    80 
    81 		if (count == 0)
    82 			fprintf(stderr,
    83 				"no package matches \"%s\"\n", pattern);
    84 	}
    85 
    86 	return razor_package_query_finish(query);
    87 }
    88 
    89 #define LIST_PACKAGES_ONLY_NAMES 0x01
    90 
    91 static void
    92 list_packages(struct razor_package_iterator *iter, uint32_t flags)
    93 {
    94 	struct razor_package *package;
    95 	const char *name, *version, *arch;
    96 
    97 	while (razor_package_iterator_next(iter, &package,
    98 					   RAZOR_DETAIL_NAME, &name,
    99 					   RAZOR_DETAIL_VERSION, &version,
   100 					   RAZOR_DETAIL_ARCH, &arch,
   101 					   RAZOR_DETAIL_LAST)) {
   102 		if (flags & LIST_PACKAGES_ONLY_NAMES)
   103 			printf("%s\n", name);
   104 		else
   105 			printf("%s-%s.%s\n", name, version, arch);
   106 	}
   107 }
   108 
   109 static int
   110 command_list(int argc, const char *argv[])
   111 {
   112 	struct razor_package_iterator *pi;
   113 	struct razor_set *set;
   114 	uint32_t flags = 0;
   115 	int i = 0;
   116 
   117 	if (i < argc && strcmp(argv[i], "--only-names") == 0) {
   118 		flags |= LIST_PACKAGES_ONLY_NAMES;
   119 		i++;
   120 	}
   121 
   122 	set = razor_root_open_read_only(install_root);
   123 	if (set == NULL)
   124 		return 1;
   125 
   126 	pi = create_iterator_from_argv(set, argc - i, argv + i);
   127 	list_packages(pi, flags);
   128 	razor_package_iterator_destroy(pi);
   129 	razor_set_destroy(set);
   130 
   131 	return 0;
   132 }
   133 
   134 static void
   135 list_package_properties(struct razor_set *set,
   136 			struct razor_package *package, uint32_t type)
   137 {
   138 	struct razor_property_iterator *pi;
   139 	struct razor_property *property;
   140 	const char *name, *version;
   141 	uint32_t flags;
   142 
   143 	pi = razor_property_iterator_create(set, package);
   144 	while (razor_property_iterator_next(pi, &property,
   145 					    &name, &flags, &version)) {
   146 		if ((flags & RAZOR_PROPERTY_TYPE_MASK) != type)
   147 			continue;
   148 		printf("%s", name);
   149 		if (version[0] != '\0')
   150 			printf(" %s %s",
   151 			       razor_property_relation_to_string(property),
   152 			       version);
   153 
   154 		if (flags & ~(RAZOR_PROPERTY_RELATION_MASK | RAZOR_PROPERTY_TYPE_MASK)) {
   155 			printf(" [");
   156 			if (flags & RAZOR_PROPERTY_PRE)
   157 				printf(" pre");
   158 			if (flags & RAZOR_PROPERTY_POST)
   159 				printf(" post");
   160 			if (flags & RAZOR_PROPERTY_PREUN)
   161 				printf(" preun");
   162 			if (flags & RAZOR_PROPERTY_POSTUN)
   163 				printf(" postun");
   164 			printf(" ]");
   165 		}
   166 		printf("\n");
   167 	}
   168 	razor_property_iterator_destroy(pi);
   169 }
   170 
   171 static int
   172 list_properties(int argc, const char *argv[], uint32_t type)
   173 {
   174 	struct razor_set *set;
   175 	struct razor_package *package;
   176 	struct razor_package_iterator *pi;
   177 	const char *name, *version, *arch;
   178 
   179 	set = razor_root_open_read_only(install_root);
   180 	if (set == NULL)
   181 		return 1;
   182 
   183 	pi = create_iterator_from_argv(set, argc, argv);
   184 	while (razor_package_iterator_next(pi, &package,
   185 					   RAZOR_DETAIL_NAME, &name,
   186 					   RAZOR_DETAIL_VERSION, &version,
   187 					   RAZOR_DETAIL_ARCH, &arch,
   188 					   RAZOR_DETAIL_LAST))
   189 		list_package_properties(set, package, type);
   190 	razor_package_iterator_destroy(pi);
   191 	razor_set_destroy(set);
   192 
   193 	return 0;
   194 }
   195 
   196 static int
   197 command_list_requires(int argc, const char *argv[])
   198 {
   199 	return list_properties(argc, argv, RAZOR_PROPERTY_REQUIRES);
   200 }
   201 
   202 static int
   203 command_list_provides(int argc, const char *argv[])
   204 {
   205 	return list_properties(argc, argv, RAZOR_PROPERTY_PROVIDES);
   206 }
   207 
   208 static int
   209 command_list_obsoletes(int argc, const char *argv[])
   210 {
   211 	return list_properties(argc, argv, RAZOR_PROPERTY_OBSOLETES);
   212 }
   213 
   214 static int
   215 command_list_conflicts(int argc, const char *argv[])
   216 {
   217 	return list_properties(argc, argv, RAZOR_PROPERTY_CONFLICTS);
   218 }
   219 
   220 static int
   221 command_list_files(int argc, const char *argv[])
   222 {
   223 	struct razor_set *set;
   224 
   225 	set = razor_root_open_read_only(install_root);
   226 	if (set == NULL)
   227 		return 1;
   228 
   229 	razor_set_list_files(set, argv[0]);
   230 	razor_set_destroy(set);
   231 
   232 	return 0;
   233 }
   234 
   235 static int
   236 command_list_file_packages(int argc, const char *argv[])
   237 {
   238 	struct razor_set *set;
   239 	struct razor_package_iterator *pi;
   240 
   241 	set = razor_root_open_read_only(install_root);
   242 	if (set == NULL)
   243 		return 1;
   244 
   245 	pi = razor_package_iterator_create_for_file(set, argv[0]);
   246 	list_packages(pi, 0);
   247 	razor_package_iterator_destroy(pi);
   248 
   249 	razor_set_destroy(set);
   250 
   251 	return 0;
   252 }
   253 
   254 static int
   255 command_list_package_files(int argc, const char *argv[])
   256 {
   257 	struct razor_set *set;
   258 	struct razor_package_iterator *pi;
   259 	struct razor_package *package;
   260 	const char *name, *version, *arch;
   261 
   262 	set = razor_root_open_read_only(install_root);
   263 	if (set == NULL)
   264 		return 1;
   265 
   266 	pi = create_iterator_from_argv(set, argc, argv);
   267 	while (razor_package_iterator_next(pi, &package,
   268 					   RAZOR_DETAIL_NAME, &name,
   269 					   RAZOR_DETAIL_VERSION, &version,
   270 					   RAZOR_DETAIL_ARCH, &arch,
   271 					   RAZOR_DETAIL_LAST))
   272 		razor_set_list_package_files(set, package);
   273 	razor_package_iterator_destroy(pi);
   274 
   275 	razor_set_destroy(set);
   276 
   277 	return 0;
   278 }
   279 
   280 static int
   281 list_property_packages(const char *ref_name,
   282 		       const char *ref_version,
   283 		       uint32_t type)
   284 {
   285 	struct razor_set *set;
   286 	struct razor_property *property;
   287 	struct razor_property_iterator *prop_iter;
   288 	struct razor_package_iterator *pkg_iter;
   289 	const char *name, *version;
   290 	uint32_t flags;
   291 
   292 	if (ref_name == NULL)
   293 		return 0;
   294 
   295 	set = razor_root_open_read_only(install_root);
   296 	if (set == NULL)
   297 		return 1;
   298 
   299 	prop_iter = razor_property_iterator_create(set, NULL);
   300 	while (razor_property_iterator_next(prop_iter, &property,
   301 					    &name, &flags, &version)) {
   302 		if (strcmp(ref_name, name) != 0)
   303 			continue;
   304 		if (ref_version &&
   305 		    (flags & RAZOR_PROPERTY_RELATION_MASK) == RAZOR_PROPERTY_EQUAL &&
   306 		    strcmp(ref_version, version) != 0)
   307 			continue;
   308 		if ((flags & RAZOR_PROPERTY_TYPE_MASK) != type)
   309 			continue;
   310 
   311 		pkg_iter =
   312 			razor_package_iterator_create_for_property(set,
   313 								   property);
   314 		list_packages(pkg_iter, 0);
   315 		razor_package_iterator_destroy(pkg_iter);
   316 	}
   317 	razor_property_iterator_destroy(prop_iter);
   318 
   319 	razor_set_destroy(set);
   320 
   321 	return 0;
   322 }
   323 
   324 static int
   325 command_what_requires(int argc, const char *argv[])
   326 {
   327 	return list_property_packages(argv[0], argv[1],
   328 				      RAZOR_PROPERTY_REQUIRES);
   329 }
   330 
   331 static int
   332 command_what_provides(int argc, const char *argv[])
   333 {
   334 	return list_property_packages(argv[0], argv[1],
   335 				      RAZOR_PROPERTY_PROVIDES);
   336 }
   337 
   338 static int
   339 show_progress(void *clientp,
   340 	      double dltotal, double dlnow, double ultotal, double ulnow)
   341 {
   342 	const char *file = clientp;
   343 
   344 	if (!dlnow < dltotal)
   345 		fprintf(stderr, "\rdownloading %s, %dkB/%dkB",
   346 			file, (int) dlnow / 1024, (int) dltotal / 1024);
   347 
   348 	return 0;
   349 }
   350 
   351 static int
   352 download_if_missing(const char *url, const char *file)
   353 {
   354 #ifndef HAVE_CURL
   355 	return 1;
   356 #else
   357 	CURL *curl;
   358 	struct stat buf;
   359 	char error[256];
   360 	FILE *fp;
   361 	CURLcode res;
   362 	long response;
   363 
   364 	curl = curl_easy_init();
   365 	if (curl == NULL)
   366 		return 1;
   367 
   368 	curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error);
   369 	curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
   370 	curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, show_progress);
   371 	curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, file);
   372 
   373 	if (stat(file, &buf) < 0) {
   374 		fp = fopen(file, "wb");
   375 		if (fp == NULL) {
   376 			fprintf(stderr,
   377 				"failed to open %s for writing\n", file);
   378 			return -1;
   379 		}
   380 		curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
   381 		curl_easy_setopt(curl, CURLOPT_URL, url);
   382 		res = curl_easy_perform(curl);
   383 		fclose(fp);
   384 		if (res != CURLE_OK) {
   385 			fprintf(stderr, "curl error: %s\n", error);
   386 			unlink(file);
   387 			return -1;
   388 		}
   389 		res = curl_easy_getinfo(curl,
   390 					CURLINFO_RESPONSE_CODE, &response);
   391 		if (res != CURLE_OK) {
   392 			fprintf(stderr, "curl error: %s\n", error);
   393                         unlink(file);
   394                         return -1;
   395 		}
   396 		if (response != 200) {
   397 			fprintf(stderr, " - failed %ld\n", response);
   398                         unlink(file);
   399                         return -1;
   400 		}
   401 		fprintf(stderr, "\n");
   402 	}
   403 
   404 	curl_easy_cleanup(curl);
   405 
   406 	return 0;
   407 #endif	/* HAVE_CURL */
   408 }
   409 
   410 #define YUM_URL "http://download.fedora.redhat.com" \
   411 	"/pub/fedora/linux/development/i386/os"
   412 
   413 static int
   414 command_import_yum(int argc, const char *argv[])
   415 {
   416 	struct razor_set *set;
   417 	char buffer[512];
   418 
   419 	printf("downloading from %s.\n", yum_url);
   420 	snprintf(buffer, sizeof buffer,
   421 		 "%s/repodata/primary.xml.gz", yum_url);
   422 	if (download_if_missing(buffer, "primary.xml.gz") < 0)
   423 		return -1;
   424 	snprintf(buffer, sizeof buffer,
   425 		 "%s/repodata/filelists.xml.gz", yum_url);
   426 	if (download_if_missing(buffer, "filelists.xml.gz") < 0)
   427 		return -1;
   428 
   429 	set = razor_set_create_from_yum();
   430 	if (set == NULL)
   431 		return 1;
   432 	if (razor_set_write(set, rawhide_repo_filename, RAZOR_REPO_FILE_MAIN)) {
   433 		perror(rawhide_repo_filename);
   434 		return -1;
   435 	}
   436 	if (razor_set_write(set, "rawhide-details.rzdb",
   437 	    RAZOR_REPO_FILE_DETAILS)) {
   438 		perror("rawhide-details.rzdb");
   439 		return -1;
   440 	}
   441 	if (razor_set_write(set, "rawhide-files.rzdb", RAZOR_REPO_FILE_FILES)) {
   442 		perror("rawhide-files.rzdb");
   443 		return -1;
   444 	}
   445 	razor_set_destroy(set);
   446 	printf("wrote %s\n", rawhide_repo_filename);
   447 
   448 	return 0;
   449 }
   450 
   451 #if HAVE_RPMLIB
   452 static int
   453 command_import_rpmdb(int argc, const char *argv[])
   454 {
   455 	struct razor_set *set;
   456 	struct razor_root *root;
   457 
   458 	root = razor_root_open(install_root);
   459 	if (root == NULL)
   460 		return 1;
   461 
   462 	set = razor_set_create_from_rpmdb();
   463 	if (set == NULL)
   464 		return 1;
   465 
   466 	razor_root_update(root, set);
   467 
   468 	return razor_root_commit(root);
   469 }
   470 #endif
   471 
   472 static int
   473 mark_packages_for_update(struct razor_transaction *trans,
   474 			 struct razor_set *set, const char *pattern)
   475 {
   476 	struct razor_package_iterator *pi;
   477 	struct razor_package *package;
   478 	const char *name;
   479 	int matches = 0;
   480 
   481 	pi = razor_package_iterator_create(set);
   482 	while (razor_package_iterator_next(pi, &package,
   483 					   RAZOR_DETAIL_NAME, &name,
   484 					   RAZOR_DETAIL_LAST)) {
   485 		if (pattern && fnmatch(pattern, name, 0) == 0) {
   486 			razor_transaction_update_package(trans, package);
   487 			matches++;
   488 		}
   489 	}
   490 	razor_package_iterator_destroy(pi);
   491 
   492 	return matches;
   493 }
   494 
   495 static int
   496 mark_packages_for_removal(struct razor_transaction *trans,
   497 			  struct razor_set *set, const char *pattern)
   498 {
   499 	struct razor_package_iterator *pi;
   500 	struct razor_package *package;
   501 	const char *name;
   502 	int matches = 0;
   503 
   504 	pi = razor_package_iterator_create(set);
   505 	while (razor_package_iterator_next(pi, &package,
   506 					   RAZOR_DETAIL_NAME, &name,
   507 					   RAZOR_DETAIL_LAST)) {
   508 		if (pattern && fnmatch(pattern, name, 0) == 0) {
   509 			razor_transaction_remove_package(trans, package);
   510 			matches++;
   511 		}
   512 	}
   513 	razor_package_iterator_destroy(pi);
   514 
   515 	return matches;
   516 }
   517 
   518 static int
   519 command_update(int argc, const char *argv[])
   520 {
   521 	struct razor_set *set, *upstream;
   522 	struct razor_transaction *trans;
   523 	int i, errors;
   524 
   525 	set = razor_root_open_read_only(install_root);
   526 	if (set == NULL)
   527 		return 1;
   528 
   529 	upstream = razor_set_open(rawhide_repo_filename);
   530 	if (upstream == NULL ||
   531 	    razor_set_open_details(upstream, "rawhide-details.rzdb") ||
   532 	    razor_set_open_files(upstream, "rawhide-files.rzdb"))
   533 		return 1;
   534 
   535 	trans = razor_transaction_create(set, upstream);
   536 	if (argc == 0)
   537 		razor_transaction_update_all(trans);
   538 	for (i = 0; i < argc; i++) {
   539 		if (mark_packages_for_update(trans, set, argv[i]) == 0) {
   540 			fprintf(stderr, "no match for %s\n", argv[i]);
   541 			return 1;
   542 		}
   543 	}
   544 
   545 	razor_transaction_resolve(trans);
   546 	errors = razor_transaction_describe(trans);
   547 	if (errors) {
   548 		fprintf(stderr, "unresolved dependencies\n");
   549 		return 1;
   550 	}
   551 
   552 	set = razor_transaction_finish(trans);
   553 	razor_set_write(set, updated_repo_filename, RAZOR_REPO_FILE_MAIN);
   554 	razor_set_destroy(set);
   555 	razor_set_destroy(upstream);
   556 	printf("wrote system-updated.rzdb\n");
   557 
   558 	return 0;
   559 }
   560 
   561 static int
   562 command_remove(int argc, const char *argv[])
   563 {
   564 	struct razor_set *set, *upstream;
   565 	struct razor_transaction *trans;
   566 	int i, errors;
   567 
   568 	set = razor_root_open_read_only(install_root);
   569 	if (set == NULL)
   570 		return 1;
   571 
   572 	upstream = razor_set_create();
   573 	trans = razor_transaction_create(set, upstream);
   574 	for (i = 0; i < argc; i++) {
   575 		if (mark_packages_for_removal(trans, set, argv[i]) == 0) {
   576 			fprintf(stderr, "no match for %s\n", argv[i]);
   577 			return 1;
   578 		}
   579 	}
   580 
   581 	razor_transaction_resolve(trans);
   582 	errors = razor_transaction_describe(trans);
   583 	if (errors)
   584 		return 1;
   585 
   586 	set = razor_transaction_finish(trans);
   587 	razor_set_write(set, updated_repo_filename, RAZOR_REPO_FILE_MAIN);
   588 	razor_set_destroy(set);
   589 	razor_set_destroy(upstream);
   590 	printf("wrote system-updated.rzdb\n");
   591 
   592 	return 0;
   593 }
   594 
   595 static void
   596 print_diff(enum razor_diff_action action,
   597 	   struct razor_package *package,
   598 	   const char *name,
   599 	   const char *version,
   600 	   const char *arch,
   601 	   void *data)
   602 {
   603 	if (action == RAZOR_DIFF_ACTION_ADD)
   604 		printf("install %s-%s.%s\n", name, version, arch);
   605 	if (action == RAZOR_DIFF_ACTION_REMOVE)
   606 		printf("remove %s-%s.%s\n", name, version, arch);
   607 }
   608 
   609 static int
   610 command_diff(int argc, const char *argv[])
   611 {
   612 	struct razor_set *set, *updated;
   613 
   614 	set = razor_root_open_read_only(install_root);
   615 	updated = razor_set_open(updated_repo_filename);
   616 	if (set == NULL || updated == NULL)
   617 		return 1;
   618 
   619 	razor_set_diff(set, updated, print_diff, NULL);
   620 
   621 	razor_set_destroy(set);
   622 	razor_set_destroy(updated);
   623 
   624 	return 0;
   625 }
   626 
   627 static int
   628 command_import_rpms(int argc, const char *argv[])
   629 {
   630 	DIR *dir;
   631 	struct dirent *de;
   632 	struct razor_importer *importer;
   633 	struct razor_set *set;
   634 	struct razor_rpm *rpm;
   635 	int len, imported_count = 0;
   636 	char filename[256];
   637 	const char *dirname = argv[0];
   638 
   639 	if (dirname == NULL) {
   640 		fprintf(stderr, "usage: razor import-rpms DIR\n");
   641 		return -1;
   642 	}
   643 
   644 	dir = opendir(dirname);
   645 	if (dir == NULL) {
   646 		fprintf(stderr, "couldn't read dir %s\n", dirname);
   647 		return -1;
   648 	}
   649 
   650 	importer = razor_importer_create();
   651 
   652 	while (de = readdir(dir), de != NULL) {
   653 		len = strlen(de->d_name);
   654 		if (len < 5 || strcmp(de->d_name + len - 4, ".rpm") != 0)
   655 		    continue;
   656 		snprintf(filename, sizeof filename,
   657 			 "%s/%s", dirname, de->d_name);
   658 		rpm = razor_rpm_open(filename);
   659 		if (rpm == NULL) {
   660 			fprintf(stderr,
   661 				"failed to open rpm \"%s\"\n", filename);
   662 			continue;
   663 		}
   664 		if (razor_importer_add_rpm(importer, rpm)) {
   665 			fprintf(stderr, "couldn't import %s\n", filename);
   666 			break;
   667 		}
   668 		razor_rpm_close(rpm);
   669 
   670 		printf("\rimporting %d", ++imported_count);
   671 		fflush(stdout);
   672 	}
   673 
   674 	if (de != NULL) {
   675 		razor_importer_destroy(importer);
   676 		return -1;
   677 	}
   678 
   679 	printf("\nsaving\n");
   680 	set = razor_importer_finish(importer);
   681 
   682 	razor_set_write(set, repo_filename, RAZOR_REPO_FILE_MAIN);
   683 	razor_set_write(set, "system-details.rzdb", RAZOR_REPO_FILE_DETAILS);
   684 	razor_set_write(set, "system-files.rzdb", RAZOR_REPO_FILE_FILES);
   685 	razor_set_destroy(set);
   686 	printf("wrote %s\n", repo_filename);
   687 
   688 	return 0;
   689 }
   690 
   691 static const char *
   692 rpm_filename(const char *name, const char *version, const char *arch)
   693 {
   694 	static char file[PATH_MAX];
   695  	const char *v;
   696  
   697  	/* Skip epoch */
   698 	v = strchr(version, ':');
   699  	if (v != NULL)
   700  		v = v + 1;
   701  	else
   702 		v = version;
   703 
   704 	snprintf(file, sizeof file, "%s-%s.%s.rpm", name, v, arch);
   705 
   706 	return file;
   707 }
   708 
   709 static int
   710 download_packages(struct razor_set *system, struct razor_set *next)
   711 {
   712 	struct razor_install_iterator *ii;
   713 	struct razor_package *package;
   714 	struct razor_set *set;
   715 	enum razor_install_action action;
   716 	const char *name, *version, *arch;
   717 	char file[PATH_MAX], url[256];
   718 	int errors = 0, count;
   719 
   720 	ii = razor_set_create_install_iterator(system, next);
   721 	while (razor_install_iterator_next(ii, &set, &package,
   722 					   &action, &count)) {
   723 		if (action == RAZOR_INSTALL_ACTION_REMOVE)
   724 			continue;
   725 
   726 		razor_package_get_details(set, package,
   727 					  RAZOR_DETAIL_NAME, &name,
   728 					  RAZOR_DETAIL_VERSION, &version,
   729 					  RAZOR_DETAIL_ARCH, &arch,
   730 					  RAZOR_DETAIL_LAST);
   731 		
   732 		snprintf(url, sizeof url,
   733 			 "%s/Packages/%s",
   734 			 yum_url, rpm_filename(name, version, arch));
   735 		snprintf(file, sizeof file,
   736 			 "rpms/%s", rpm_filename(name, version, arch));
   737 		if (download_if_missing(url, file) < 0)
   738 			errors++;
   739 	}
   740 	razor_install_iterator_destroy(ii);
   741 
   742 	if (errors > 0) {
   743 		fprintf(stderr, "failed to download %d packages\n", errors);
   744                 return -1;
   745         }
   746 
   747 	return 0;
   748 }
   749 
   750 static struct razor_set *
   751 relocate_packages(struct razor_set *set, struct razor_relocations *relocations)
   752 {
   753 	struct razor_importer *importer;
   754 	struct razor_property_iterator *prop_iter;
   755 	struct razor_package_iterator *pkg_iter;
   756  	struct razor_file_iterator *file_iter;
   757  	struct razor_package *package;
   758 	struct razor_property *property;
   759 	struct razor_rpm *rpm;
   760 	const char *name, *version, *arch, *summary, *desc, *url, *license;
   761 	char file[PATH_MAX];
   762 	uint32_t flags;
   763 
   764 	importer = razor_importer_create();
   765 	pkg_iter = razor_package_iterator_create(set);
   766 
   767 	while (razor_package_iterator_next(pkg_iter, &package,
   768 					   RAZOR_DETAIL_NAME, &name,
   769 					   RAZOR_DETAIL_VERSION, &version,
   770 					   RAZOR_DETAIL_ARCH, &arch,
   771 					   RAZOR_DETAIL_SUMMARY, &summary,
   772 					   RAZOR_DETAIL_DESCRIPTION, &desc,
   773 					   RAZOR_DETAIL_URL, &url,
   774 					   RAZOR_DETAIL_LICENSE, &license,
   775 					   RAZOR_DETAIL_LAST)) {
   776 		snprintf(file, sizeof file,
   777 			 "rpms/%s", rpm_filename(name, version, arch));
   778 		rpm = razor_rpm_open(file);
   779 		if (rpm == NULL) {
   780 			fprintf(stderr, "failed to open rpm %s\n", file);
   781 			razor_package_iterator_destroy(pkg_iter);
   782 			razor_importer_destroy(importer);
   783 			return NULL;
   784 		}
   785 
   786 		razor_relocations_set_rpm(relocations, rpm);
   787 		razor_rpm_close(rpm);
   788 
   789 		razor_importer_begin_package(importer, name, version, arch);
   790 		razor_importer_add_details(importer,
   791 					   summary, desc, url, license);
   792 
   793 		prop_iter = razor_property_iterator_create(set, package);
   794 		while (razor_property_iterator_next(prop_iter, &property,
   795 						    &name, &flags, &version))
   796 			razor_importer_add_property(importer,
   797 						    name, flags, version);
   798 		razor_property_iterator_destroy(prop_iter);
   799 
   800 		file_iter = razor_file_iterator_create(set, package);
   801 		while (razor_file_iterator_next(file_iter, &name)) {
   802 			name = razor_relocations_apply(relocations, name);
   803 			razor_importer_add_file(importer, name);
   804 		}
   805 		razor_file_iterator_destroy(file_iter);
   806 
   807 		razor_importer_finish_package(importer);
   808 	}
   809 
   810 	razor_package_iterator_destroy(pkg_iter);
   811 	return razor_importer_finish(importer);
   812 }
   813 
   814 static int
   815 install_packages(struct razor_set *system, struct razor_set *next,
   816 		 struct razor_relocations *relocations)
   817 {
   818 	struct razor_install_iterator *ii;
   819 	struct razor_package *package;
   820 	struct razor_set *set;
   821 	enum razor_install_action action;
   822 	struct razor_rpm *rpm;
   823 	const char *name, *version, *arch;
   824 	char file[PATH_MAX];
   825 	int count;
   826 
   827 	ii = razor_set_create_install_iterator(system, next);
   828 	while (razor_install_iterator_next(ii, &set, &package,
   829 					   &action, &count)) {
   830 		if (action == RAZOR_INSTALL_ACTION_REMOVE)
   831 			continue;
   832 
   833 		razor_package_get_details(set, package,
   834 					  RAZOR_DETAIL_NAME, &name,
   835 					  RAZOR_DETAIL_VERSION, &version,
   836 					  RAZOR_DETAIL_ARCH, &arch,
   837 					  RAZOR_DETAIL_LAST);
   838 
   839 		printf("install %s-%s\n", name, version);
   840 
   841 		snprintf(file, sizeof file,
   842 			 "rpms/%s", rpm_filename(name, version, arch));
   843 		rpm = razor_rpm_open(file);
   844 		if (rpm == NULL) {
   845 			fprintf(stderr, "failed to open rpm %s\n", file);
   846 			return -1;
   847 		}
   848 		if (relocations)
   849 			razor_rpm_set_relocations(rpm, relocations);
   850 		if (razor_rpm_install(rpm, install_root) < 0) {
   851 			fprintf(stderr,
   852 				"failed to install rpm %s\n", file);
   853 			return -1;
   854 		}
   855 		razor_rpm_close(rpm);
   856 	}
   857 	razor_install_iterator_destroy(ii);
   858 
   859 	return 0;
   860 }
   861 
   862 static int
   863 command_install(int argc, const char *argv[])
   864 {
   865 	struct razor_root *root;
   866 	struct razor_relocations *relocations=NULL;
   867 	struct razor_set *system, *upstream, *next, *set;
   868 	struct razor_transaction *trans;
   869 	int i, len, dependencies = 1;
   870 	char *oldpath;
   871 
   872 	root = razor_root_open(install_root);
   873 	if (root == NULL)
   874 		return 1;
   875 
   876 	for (i = 0; i < argc; i++) {
   877 		if (strcmp(argv[i], "--no-dependencies") == 0)
   878 			dependencies = 0;
   879 		else if (strcmp(argv[i], "--relocate") == 0) {
   880 			i++;
   881 			if (i >= argc || strchr(argv[i], '=') == NULL) {
   882 				fprintf(stderr,
   883 				    "Usage: razor install [OPTION...] RPM\n");
   884 				fprintf(stderr, "Options:\n");
   885 				fprintf(stderr, "    [--no-dependencies]\n");
   886 				fprintf(stderr,
   887 				    "    [--relocate OLDPATH=NEWPATH] RPM\n");
   888 				return -1;
   889 			}
   890 			len = strchr(argv[i], '=') - argv[i];
   891 			oldpath = malloc(len + 1);
   892 			strncpy(oldpath, argv[i], len);
   893 			oldpath[len] = '\0';
   894 			if (!relocations)
   895 			       relocations = razor_relocations_create();
   896 			razor_relocations_add(relocations, oldpath,
   897 					      argv[i] + len + 1);
   898 			free(oldpath);
   899 		} else
   900 			break;
   901 	}
   902 
   903 	system = razor_root_get_system_set(root);
   904 	upstream = razor_set_open(rawhide_repo_filename);
   905 	if (upstream == NULL ||
   906 	    razor_set_open_details(upstream, "rawhide-details.rzdb") ||
   907 	    razor_set_open_files(upstream, "rawhide-files.rzdb")) {
   908 			fprintf(stderr, "couldn't open rawhide repo\n");
   909 			razor_root_close(root);
   910 			return 1;
   911 	}		
   912 
   913 	if (relocations) {
   914 		set = relocate_packages(upstream, relocations);
   915 		razor_set_destroy(upstream);
   916 		upstream = set;
   917 	}
   918 
   919 	trans = razor_transaction_create(system, upstream);
   920 
   921 	for (; i < argc; i++) {
   922 		if (mark_packages_for_update(trans, upstream, argv[i]) == 0) {
   923 			fprintf(stderr, "no package matched %s\n", argv[i]);
   924 			razor_root_close(root);
   925 			return 1;
   926 		}
   927 	}
   928 
   929 	if (dependencies) {
   930 		razor_transaction_resolve(trans);
   931 		if (razor_transaction_describe(trans) > 0) {
   932 			razor_root_close(root);
   933 			return 1;
   934 		}
   935 	}
   936 
   937 	next = razor_transaction_finish(trans);
   938 
   939 	razor_root_update(root, next);
   940 
   941 	if (mkdir("rpms", 0777) && errno != EEXIST) {
   942 		fprintf(stderr, "failed to create rpms directory.\n");
   943 		razor_root_close(root);
   944 		return 1;
   945 	}
   946 
   947 	if (download_packages(system, next) < 0) {
   948 		razor_root_close(root);
   949                 return 1;
   950         }
   951 
   952 	install_packages(system, next, relocations);
   953 
   954 	if (relocations)
   955 		razor_relocations_destroy(relocations);
   956 	razor_set_destroy(next);
   957 	razor_set_destroy(upstream);
   958 
   959 	return razor_root_commit(root);
   960 }
   961 
   962 static int
   963 command_init(int argc, const char *argv[])
   964 {
   965 	return razor_root_create(install_root);
   966 }
   967 
   968 static int
   969 command_download(int argc, const char *argv[])
   970 {
   971 	struct razor_set *set;
   972 	struct razor_package_iterator *pi;
   973 	struct razor_package *package;
   974 	const char *pattern = argv[0], *name, *version, *arch;
   975 	char url[256], file[256];
   976 	int matches = 0;
   977 
   978 	if (mkdir("rpms", 0777) && errno != EEXIST) {
   979 		fprintf(stderr, "failed to create rpms directory.\n");
   980 		return 1;
   981 	}
   982 
   983 	set = razor_set_open(rawhide_repo_filename);
   984 	pi = razor_package_iterator_create(set);
   985 	while (razor_package_iterator_next(pi, &package,
   986 					   RAZOR_DETAIL_NAME, &name,
   987 					   RAZOR_DETAIL_VERSION, &version,
   988 					   RAZOR_DETAIL_ARCH, &arch,
   989 					   RAZOR_DETAIL_LAST)) {
   990 		if (pattern && fnmatch(pattern, name, 0) != 0)
   991 			continue;
   992 
   993 		matches++;
   994 		snprintf(url, sizeof url,
   995 			 "%s/Packages/%s-%s.%s.rpm",
   996 			 yum_url, name, version, arch);
   997 		snprintf(file, sizeof file,
   998 			 "rpms/%s-%s.%s.rpm", name, version, arch);
   999 		download_if_missing(url, file);
  1000 	}
  1001 	razor_package_iterator_destroy(pi);
  1002 	razor_set_destroy(set);
  1003 
  1004 	if (matches == 0)
  1005 		fprintf(stderr, "no packages matched \"%s\"\n", pattern);
  1006 	else if (matches == 1)
  1007 		fprintf(stderr, "downloaded 1 package\n");
  1008 	else
  1009 		fprintf(stderr, "downloaded %d packages\n", matches);
  1010 
  1011 	return 0;
  1012 }
  1013 
  1014 static int
  1015 command_info(int argc, const char *argv[])
  1016 {
  1017 	struct razor_set *set;
  1018 	struct razor_package_iterator *pi;
  1019 	struct razor_package *package;
  1020 	const char *pattern = argv[0], *name, *version, *arch;
  1021 	const char *summary, *description, *url, *license;
  1022 
  1023 	set = razor_root_open_read_only(install_root);
  1024 	if (set == NULL)
  1025 		return 1;
  1026 
  1027 	pi = razor_package_iterator_create(set);
  1028 	while (razor_package_iterator_next(pi, &package,
  1029 					   RAZOR_DETAIL_NAME, &name,
  1030 					   RAZOR_DETAIL_VERSION, &version,
  1031 					   RAZOR_DETAIL_ARCH, &arch,
  1032 					   RAZOR_DETAIL_LAST)) {
  1033 		if (pattern && fnmatch(pattern, name, 0) != 0)
  1034 			continue;
  1035 
  1036 		razor_package_get_details (set, package,
  1037 					   RAZOR_DETAIL_SUMMARY, &summary,
  1038 					   RAZOR_DETAIL_DESCRIPTION, &description,
  1039 					   RAZOR_DETAIL_URL, &url,
  1040 					   RAZOR_DETAIL_LICENSE, &license,
  1041 					   RAZOR_DETAIL_LAST);
  1042 
  1043 		printf ("Name:        %s\n", name);
  1044 		printf ("Arch:        %s\n", arch);
  1045 		printf ("Version:     %s\n", version);
  1046 		printf ("URL:         %s\n", url);
  1047 		printf ("License:     %s\n", license);
  1048 		printf ("Summary:     %s\n", summary);
  1049 		printf ("Description:\n");
  1050 		printf ("%s\n", description);
  1051 		printf ("\n");
  1052 	}
  1053 	razor_package_iterator_destroy(pi);
  1054 	razor_set_destroy(set);
  1055 
  1056 	return 0;
  1057 }
  1058 
  1059 #define SEARCH_MAX 256
  1060 
  1061 static int
  1062 command_search(int argc, const char *argv[])
  1063 {
  1064 	struct razor_set *set;
  1065 	struct razor_package_iterator *pi;
  1066 	struct razor_package *package;
  1067 	char pattern[SEARCH_MAX];
  1068 	const char *name, *version, *arch;
  1069 	const char *summary, *description, *url, *license;
  1070 
  1071 	if (!argv[0]) {
  1072 		fprintf(stderr, "must specify a search term\n");
  1073 		return 1;
  1074 	}
  1075 
  1076 	snprintf(pattern, sizeof pattern, "*%s*", argv[0]);
  1077 
  1078 	set = razor_set_open(rawhide_repo_filename);
  1079 	if (set == NULL)
  1080 		return 1;
  1081 
  1082 	if (razor_set_open_details(set, "rawhide-details.rzdb"))
  1083 		return 1;
  1084 
  1085 	pi = razor_package_iterator_create(set);
  1086 	while (razor_package_iterator_next(pi, &package,
  1087 					   RAZOR_DETAIL_NAME, &name,
  1088 					   RAZOR_DETAIL_VERSION, &version,
  1089 					   RAZOR_DETAIL_ARCH, &arch,
  1090 					   RAZOR_DETAIL_SUMMARY, &summary,
  1091 					   RAZOR_DETAIL_DESCRIPTION, &description,
  1092 					   RAZOR_DETAIL_URL, &url,
  1093 					   RAZOR_DETAIL_LICENSE, &license,
  1094 					   RAZOR_DETAIL_LAST)) {
  1095 		if (!fnmatch(pattern, name, FNM_CASEFOLD) ||
  1096 		    !fnmatch(pattern, url, FNM_CASEFOLD) ||
  1097 		    !fnmatch(pattern, summary, FNM_CASEFOLD) ||
  1098 		    !fnmatch(pattern, description, FNM_CASEFOLD))
  1099 			printf("%s-%s.%s: %s\n", name, version, arch, summary);
  1100 	}
  1101 	razor_package_iterator_destroy(pi);
  1102 	razor_set_destroy(set);
  1103 
  1104 	return 0;
  1105 }
  1106 
  1107 static struct {
  1108 	const char *name;
  1109 	const char *description;
  1110 	int (*func)(int argc, const char *argv[]);
  1111 } razor_commands[] = {
  1112 	{ "list", "list all packages", command_list },
  1113 	{ "list-requires", "list all requires for the given package", command_list_requires },
  1114 	{ "list-provides", "list all provides for the given package", command_list_provides },
  1115 	{ "list-obsoletes", "list all obsoletes for the given package", command_list_obsoletes },
  1116 	{ "list-conflicts", "list all conflicts for the given package", command_list_conflicts },
  1117 	{ "list-files", "list files for package set", command_list_files },
  1118 	{ "list-file-packages", "list packages owning file", command_list_file_packages },
  1119 	{ "list-package-files", "list files in package", command_list_package_files },
  1120 	{ "what-requires", "list the packages that have the given requires", command_what_requires },
  1121 	{ "what-provides", "list the packages that have the given provides", command_what_provides },
  1122 	{ "import-yum", "import yum metadata files", command_import_yum },
  1123 #if HAVE_RPMLIB
  1124 	{ "import-rpmdb", "import the system rpm database", command_import_rpmdb },
  1125 #endif
  1126 	{ "import-rpms", "import rpms from the given directory", command_import_rpms },
  1127 	{ "update", "update all or specified packages", command_update },
  1128 	{ "remove", "remove specified packages", command_remove },
  1129 	{ "diff", "show diff between two package sets", command_diff },
  1130 	{ "install", "install rpm", command_install },
  1131 	{ "init", "init razor root", command_init },
  1132 	{ "download", "download packages", command_download },
  1133 	{ "info", "display package details", command_info },
  1134 	{ "search", "search package details", command_search }
  1135 };
  1136 
  1137 static int
  1138 usage(void)
  1139 {
  1140 	int i;
  1141 
  1142 	printf("usage:\n");
  1143 	for (i = 0; i < ARRAY_SIZE(razor_commands); i++)
  1144 		printf("  %-20s%s\n",
  1145 		       razor_commands[i].name, razor_commands[i].description);
  1146 
  1147 	return 1;
  1148 }
  1149 
  1150 int
  1151 main(int argc, const char *argv[])
  1152 {
  1153 	char *repo, *root;
  1154 	int i;
  1155 
  1156 	repo = getenv("RAZOR_REPO");
  1157 	if (repo != NULL)
  1158 		repo_filename = repo;
  1159 
  1160 	root = getenv("RAZOR_ROOT");
  1161 	if (root != NULL)
  1162 		install_root = root;
  1163 
  1164 	yum_url = getenv("YUM_URL");
  1165 	if (yum_url == NULL)
  1166 		yum_url = YUM_URL;
  1167 
  1168 	if (argc < 2)
  1169 		return usage();
  1170 
  1171 	for (i = 0; i < ARRAY_SIZE(razor_commands); i++)
  1172 		if (strcmp(razor_commands[i].name, argv[1]) == 0)
  1173 			return razor_commands[i].func(argc - 2, argv + 2);
  1174 
  1175 	return usage();
  1176 }