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