src/main.c
author J. Ali Harlow <ali@juiblex.co.uk>
Sat Aug 23 16:28:31 2014 +0100 (2014-08-23)
changeset 442 c4bcba8023a9
parent 426 2e896ad9754b
child 445 aada48958b92
permissions -rw-r--r--
Fix compiler warnings
     1 /*
     2  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     3  * Copyright (C) 2008  Red Hat, Inc
     4  * Copyright (C) 2009, 2011-2012  J. Ali Harlow <ali@juiblex.co.uk>
     5  *
     6  * This program is free software; you can redistribute it and/or modify
     7  * it under the terms of the GNU General Public License as published by
     8  * the Free Software Foundation; either version 2 of the License, or
     9  * (at your option) any later version.
    10  *
    11  * This program is distributed in the hope that it will be useful,
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  * GNU General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU General Public License along
    17  * with this program; if not, write to the Free Software Foundation, Inc.,
    18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    19  */
    20 
    21 #define _GNU_SOURCE
    22 
    23 #include "config.h"
    24 
    25 #include <stdlib.h>
    26 #include <stddef.h>
    27 #include <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,
    53 		struct razor_install_iterator *ii, struct razor_set *system,
    54 		struct razor_set *next, struct razor_atomic *atomic,
    55 		struct razor_relocations *relocations,
    56 		enum razor_stage_type stage);
    57 static int
    58 update_system(struct razor_root *root, struct razor_relocations *relocations,
    59 	      struct razor_transaction *trans, struct razor_set *next,
    60 	      const char *verb);
    61 
    62 static struct razor_package_iterator *
    63 create_iterator_from_argv(struct razor_set *set, int argc, const char *argv[])
    64 {
    65 	struct razor_package_query *query;
    66 	struct razor_package_iterator *iter;
    67 	struct razor_package *package;
    68 	const char *name, *pattern;
    69 	int i, count;
    70 
    71 	if (argc == 0)
    72 		return razor_package_iterator_create(set);
    73 
    74 	query = razor_package_query_create(set);
    75 
    76 	for (i = 0; i < argc; i++) {
    77 		iter = razor_package_iterator_create(set);
    78 		pattern = argv[i];
    79 		count = 0;
    80 		while (razor_package_iterator_next(iter, &package,
    81 						   RAZOR_DETAIL_NAME, &name,
    82 						   RAZOR_DETAIL_LAST)) {
    83 			if (fnmatch(pattern, name, 0) != 0)
    84 				continue;
    85 
    86 			razor_package_query_add_package(query, package);
    87 			count++;
    88 		}
    89 		razor_package_iterator_destroy(iter);
    90 
    91 		if (count == 0)
    92 			fprintf(stderr,
    93 				"no package matches \"%s\"\n", pattern);
    94 	}
    95 
    96 	return razor_package_query_finish(query);
    97 }
    98 
    99 #define LIST_PACKAGES_ONLY_NAMES 0x01
   100 
   101 static void
   102 list_packages(struct razor_package_iterator *iter, uint32_t flags)
   103 {
   104 	struct razor_package *package;
   105 	const char *name, *version, *arch;
   106 
   107 	while (razor_package_iterator_next(iter, &package,
   108 					   RAZOR_DETAIL_NAME, &name,
   109 					   RAZOR_DETAIL_VERSION, &version,
   110 					   RAZOR_DETAIL_ARCH, &arch,
   111 					   RAZOR_DETAIL_LAST)) {
   112 		if (flags & LIST_PACKAGES_ONLY_NAMES)
   113 			printf("%s\n", name);
   114 		else
   115 			printf("%s-%s.%s\n", name, version, arch);
   116 	}
   117 }
   118 
   119 static int
   120 command_list(int argc, const char *argv[])
   121 {
   122 	struct razor_package_iterator *pi;
   123 	struct razor_error *error = NULL;
   124 	struct razor_set *set;
   125 	uint32_t flags = 0;
   126 	int i = 0;
   127 
   128 	if (i < argc && strcmp(argv[i], "--only-names") == 0) {
   129 		flags |= LIST_PACKAGES_ONLY_NAMES;
   130 		i++;
   131 	}
   132 
   133 	set = razor_root_open_read_only(install_root, &error);
   134 	if (set == NULL) {
   135 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   136 		razor_error_free(error);
   137 		return 1;
   138 	}
   139 
   140 	pi = create_iterator_from_argv(set, argc - i, argv + i);
   141 	list_packages(pi, flags);
   142 	razor_package_iterator_destroy(pi);
   143 	razor_set_unref(set);
   144 
   145 	return 0;
   146 }
   147 
   148 static void
   149 list_package_properties(struct razor_set *set,
   150 			struct razor_package *package, uint32_t type)
   151 {
   152 	struct razor_property_iterator *pi;
   153 	struct razor_property *property;
   154 	const char *name, *version;
   155 	uint32_t flags;
   156 
   157 	pi = razor_property_iterator_create(set, package);
   158 	while (razor_property_iterator_next(pi, &property,
   159 					    &name, &flags, &version)) {
   160 		if ((flags & RAZOR_PROPERTY_TYPE_MASK) != type)
   161 			continue;
   162 		printf("%s", name);
   163 		if (version[0] != '\0')
   164 			printf(" %s %s",
   165 			       razor_property_relation_to_string(property),
   166 			       version);
   167 
   168 		if (flags & ~(RAZOR_PROPERTY_RELATION_MASK | RAZOR_PROPERTY_TYPE_MASK)) {
   169 			printf(" [");
   170 			if (flags & RAZOR_PROPERTY_PRE)
   171 				printf(" pre");
   172 			if (flags & RAZOR_PROPERTY_POST)
   173 				printf(" post");
   174 			if (flags & RAZOR_PROPERTY_PREUN)
   175 				printf(" preun");
   176 			if (flags & RAZOR_PROPERTY_POSTUN)
   177 				printf(" postun");
   178 			printf(" ]");
   179 		}
   180 		printf("\n");
   181 	}
   182 	razor_property_iterator_destroy(pi);
   183 }
   184 
   185 static int
   186 list_properties(int argc, const char *argv[], uint32_t type)
   187 {
   188 	struct razor_set *set;
   189 	struct razor_error *error = NULL;
   190 	struct razor_package *package;
   191 	struct razor_package_iterator *pi;
   192 	const char *name, *version, *arch;
   193 
   194 	set = razor_root_open_read_only(install_root, &error);
   195 	if (set == NULL) {
   196 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   197 		razor_error_free(error);
   198 		return 1;
   199 	}
   200 
   201 	pi = create_iterator_from_argv(set, argc, argv);
   202 	while (razor_package_iterator_next(pi, &package,
   203 					   RAZOR_DETAIL_NAME, &name,
   204 					   RAZOR_DETAIL_VERSION, &version,
   205 					   RAZOR_DETAIL_ARCH, &arch,
   206 					   RAZOR_DETAIL_LAST))
   207 		list_package_properties(set, package, type);
   208 	razor_package_iterator_destroy(pi);
   209 	razor_set_unref(set);
   210 
   211 	return 0;
   212 }
   213 
   214 static int
   215 command_list_requires(int argc, const char *argv[])
   216 {
   217 	return list_properties(argc, argv, RAZOR_PROPERTY_REQUIRES);
   218 }
   219 
   220 static int
   221 command_list_provides(int argc, const char *argv[])
   222 {
   223 	return list_properties(argc, argv, RAZOR_PROPERTY_PROVIDES);
   224 }
   225 
   226 static int
   227 command_list_obsoletes(int argc, const char *argv[])
   228 {
   229 	return list_properties(argc, argv, RAZOR_PROPERTY_OBSOLETES);
   230 }
   231 
   232 static int
   233 command_list_conflicts(int argc, const char *argv[])
   234 {
   235 	return list_properties(argc, argv, RAZOR_PROPERTY_CONFLICTS);
   236 }
   237 
   238 static int
   239 command_list_scripts(int argc, const char *argv[])
   240 {
   241 	struct razor_set *set;
   242 	struct razor_error *error = NULL;
   243 	struct razor_package *package;
   244 	struct razor_package_iterator *pi;
   245 	const char *preunprog, *preun, *postunprog, *postun;
   246 
   247 	set = razor_root_open_read_only(install_root, &error);
   248 	if (set == NULL) {
   249 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   250 		razor_error_free(error);
   251 		return 1;
   252 	}
   253 
   254 	pi = create_iterator_from_argv(set, argc, argv);
   255 	while (razor_package_iterator_next(pi, &package,
   256 					   RAZOR_DETAIL_PREUNPROG, &preunprog,
   257 					   RAZOR_DETAIL_PREUN, &preun,
   258 					   RAZOR_DETAIL_POSTUNPROG, &postunprog,
   259 					   RAZOR_DETAIL_POSTUN, &postun,
   260 					   RAZOR_DETAIL_LAST)) {
   261 		if (preun && *preun) {
   262 			printf("preuninstall scriptlet");
   263 			if (preunprog && *preunprog)
   264 				printf(" (using %s)",preunprog);
   265 			printf(":\n%s\n",preun);
   266 		}
   267 		if (postun && *postun) {
   268 			printf("postuninstall scriptlet");
   269 			if (postunprog && *postunprog)
   270 				printf(" (using %s)",postunprog);
   271 			printf(":\n%s\n",postun);
   272 		}
   273 	}
   274 	razor_package_iterator_destroy(pi);
   275 	razor_set_unref(set);
   276 
   277 	return 0;
   278 }
   279 
   280 static int
   281 command_list_files(int argc, const char *argv[])
   282 {
   283 	struct razor_error *error = NULL;
   284 	struct razor_set *set;
   285 
   286 	set = razor_root_open_read_only(install_root, &error);
   287 	if (set == NULL) {
   288 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   289 		razor_error_free(error);
   290 		return 1;
   291 	}
   292 
   293 	razor_set_list_files(set, argv[0]);
   294 	razor_set_unref(set);
   295 
   296 	return 0;
   297 }
   298 
   299 static int
   300 command_list_file_packages(int argc, const char *argv[])
   301 {
   302 	struct razor_error *error = NULL;
   303 	struct razor_set *set;
   304 	struct razor_package_iterator *pi;
   305 
   306 	set = razor_root_open_read_only(install_root, &error);
   307 	if (set == NULL) {
   308 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   309 		razor_error_free(error);
   310 		return 1;
   311 	}
   312 
   313 	pi = razor_package_iterator_create_for_file(set, argv[0]);
   314 	list_packages(pi, 0);
   315 	razor_package_iterator_destroy(pi);
   316 
   317 	razor_set_unref(set);
   318 
   319 	return 0;
   320 }
   321 
   322 static int
   323 command_list_package_files(int argc, const char *argv[])
   324 {
   325 	struct razor_error *error = NULL;
   326 	struct razor_set *set;
   327 	struct razor_package_iterator *pi;
   328 	struct razor_package *package;
   329 	const char *name, *version, *arch;
   330 
   331 	set = razor_root_open_read_only(install_root, &error);
   332 	if (set == NULL) {
   333 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   334 		razor_error_free(error);
   335 		return 1;
   336 	}
   337 
   338 	pi = create_iterator_from_argv(set, argc, argv);
   339 	while (razor_package_iterator_next(pi, &package,
   340 					   RAZOR_DETAIL_NAME, &name,
   341 					   RAZOR_DETAIL_VERSION, &version,
   342 					   RAZOR_DETAIL_ARCH, &arch,
   343 					   RAZOR_DETAIL_LAST))
   344 		razor_set_list_package_files(set, package);
   345 	razor_package_iterator_destroy(pi);
   346 
   347 	razor_set_unref(set);
   348 
   349 	return 0;
   350 }
   351 
   352 static int
   353 list_property_packages(const char *ref_name,
   354 		       const char *ref_version,
   355 		       uint32_t type)
   356 {
   357 	struct razor_error *error = NULL;
   358 	struct razor_set *set;
   359 	struct razor_property *property;
   360 	struct razor_property_iterator *prop_iter;
   361 	struct razor_package_iterator *pkg_iter;
   362 	const char *name, *version;
   363 	uint32_t flags;
   364 
   365 	if (ref_name == NULL)
   366 		return 0;
   367 
   368 	set = razor_root_open_read_only(install_root, &error);
   369 	if (set == NULL) {
   370 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   371 		razor_error_free(error);
   372 		return 1;
   373 	}
   374 
   375 	prop_iter = razor_property_iterator_create(set, NULL);
   376 	while (razor_property_iterator_next(prop_iter, &property,
   377 					    &name, &flags, &version)) {
   378 		if (strcmp(ref_name, name) != 0)
   379 			continue;
   380 		if (ref_version &&
   381 		    (flags & RAZOR_PROPERTY_RELATION_MASK) == RAZOR_PROPERTY_EQUAL &&
   382 		    strcmp(ref_version, version) != 0)
   383 			continue;
   384 		if ((flags & RAZOR_PROPERTY_TYPE_MASK) != type)
   385 			continue;
   386 
   387 		pkg_iter =
   388 			razor_package_iterator_create_for_property(set,
   389 								   property);
   390 		list_packages(pkg_iter, 0);
   391 		razor_package_iterator_destroy(pkg_iter);
   392 	}
   393 	razor_property_iterator_destroy(prop_iter);
   394 
   395 	razor_set_unref(set);
   396 
   397 	return 0;
   398 }
   399 
   400 static int
   401 command_what_requires(int argc, const char *argv[])
   402 {
   403 	return list_property_packages(argv[0], argv[1],
   404 				      RAZOR_PROPERTY_REQUIRES);
   405 }
   406 
   407 static int
   408 command_what_provides(int argc, const char *argv[])
   409 {
   410 	return list_property_packages(argv[0], argv[1],
   411 				      RAZOR_PROPERTY_PROVIDES);
   412 }
   413 
   414 #ifdef HAVE_CURL
   415 static int
   416 show_progress(void *clientp,
   417 	      double dltotal, double dlnow, double ultotal, double ulnow)
   418 {
   419 	const char *file = clientp;
   420 
   421 	if (!dlnow < dltotal)
   422 		fprintf(stderr, "\rdownloading %s, %dkB/%dkB",
   423 			file, (int) dlnow / 1024, (int) dltotal / 1024);
   424 
   425 	return 0;
   426 }
   427 #endif	/* HAVE_CURL */
   428 
   429 static int
   430 download_if_missing(const char *url, const char *file)
   431 {
   432 #ifndef HAVE_CURL
   433 	return 1;
   434 #else
   435 	CURL *curl;
   436 	struct stat buf;
   437 	char error[256];
   438 	FILE *fp;
   439 	CURLcode res;
   440 	long response;
   441 
   442 	curl = curl_easy_init();
   443 	if (curl == NULL)
   444 		return 1;
   445 
   446 	curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error);
   447 	curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
   448 	curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, show_progress);
   449 	curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, file);
   450 
   451 	if (stat(file, &buf) < 0) {
   452 		fp = fopen(file, "wb");
   453 		if (fp == NULL) {
   454 			fprintf(stderr,
   455 				"failed to open %s for writing\n", file);
   456 			return -1;
   457 		}
   458 		curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
   459 		curl_easy_setopt(curl, CURLOPT_URL, url);
   460 		res = curl_easy_perform(curl);
   461 		fclose(fp);
   462 		if (res != CURLE_OK) {
   463 			fprintf(stderr, "curl error: %s\n", error);
   464 			unlink(file);
   465 			return -1;
   466 		}
   467 		res = curl_easy_getinfo(curl,
   468 					CURLINFO_RESPONSE_CODE, &response);
   469 		if (res != CURLE_OK) {
   470 			fprintf(stderr, "curl error: %s\n", error);
   471                         unlink(file);
   472                         return -1;
   473 		}
   474 		if (response != 200) {
   475 			fprintf(stderr, " - failed %ld\n", response);
   476                         unlink(file);
   477                         return -1;
   478 		}
   479 		fprintf(stderr, "\n");
   480 	}
   481 
   482 	curl_easy_cleanup(curl);
   483 
   484 	return 0;
   485 #endif	/* HAVE_CURL */
   486 }
   487 
   488 #define YUM_URL "http://download.fedora.redhat.com" \
   489 	"/pub/fedora/linux/development/i386/os"
   490 
   491 static int
   492 command_import_yum(int argc, const char *argv[])
   493 {
   494 	int retval;
   495 	struct razor_set *set;
   496 	struct razor_atomic *atomic;
   497 	char buffer[512];
   498 
   499 	printf("downloading from %s.\n", yum_url);
   500 	snprintf(buffer, sizeof buffer,
   501 		 "%s/repodata/primary.xml.gz", yum_url);
   502 	if (download_if_missing(buffer, "primary.xml.gz") < 0)
   503 		return -1;
   504 	snprintf(buffer, sizeof buffer,
   505 		 "%s/repodata/filelists.xml.gz", yum_url);
   506 	if (download_if_missing(buffer, "filelists.xml.gz") < 0)
   507 		return -1;
   508 
   509 	set = razor_set_create_from_yum();
   510 	if (set == NULL)
   511 		return 1;
   512 	atomic = razor_atomic_open("Yum import repository");
   513 	razor_set_write(set, atomic, rawhide_repo_filename, RAZOR_SECTION_ALL);
   514 	retval = razor_atomic_commit(atomic);
   515 	razor_set_unref(set);
   516 	if (retval)
   517 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
   518 	else
   519 		printf("wrote %s\n", rawhide_repo_filename);
   520 	razor_atomic_destroy(atomic);
   521 
   522 	return retval;
   523 }
   524 
   525 #if HAVE_RPMLIB
   526 static int
   527 command_import_rpmdb(int argc, const char *argv[])
   528 {
   529 	struct razor_set *set;
   530 	struct razor_root *root;
   531 	struct razor_error *error = NULL;
   532 	struct razor_atomic *atomic;
   533 	int retval;
   534 
   535 	root = razor_root_open(install_root, &error);
   536 	if (root == NULL) {
   537 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   538 		razor_error_free(error);
   539 		return 1;
   540 	}
   541 
   542 	set = razor_set_create_from_rpmdb();
   543 	if (set == NULL)
   544 		return 1;
   545 
   546 	atomic = razor_atomic_open("Import RPM database");
   547 
   548 	retval = razor_root_update(root, set, atomic);
   549 
   550 	if (retval)
   551 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
   552 
   553 	razor_atomic_destroy(atomic);
   554 
   555 	razor_root_close(root);
   556 
   557 	return retval;
   558 }
   559 #endif
   560 
   561 static int
   562 mark_packages_for_update(struct razor_transaction *trans,
   563 			 struct razor_set *set, const char *pattern)
   564 {
   565 	struct razor_package_iterator *pi;
   566 	struct razor_package *package;
   567 	const char *name;
   568 	int matches = 0;
   569 
   570 	pi = razor_package_iterator_create(set);
   571 	while (razor_package_iterator_next(pi, &package,
   572 					   RAZOR_DETAIL_NAME, &name,
   573 					   RAZOR_DETAIL_LAST)) {
   574 		if (pattern && fnmatch(pattern, name, 0) == 0) {
   575 			razor_transaction_update_package(trans, package);
   576 			matches++;
   577 		}
   578 	}
   579 	razor_package_iterator_destroy(pi);
   580 
   581 	return matches;
   582 }
   583 
   584 static int
   585 mark_packages_for_removal(struct razor_transaction *trans,
   586 			  struct razor_set *set, const char *pattern)
   587 {
   588 	struct razor_package_iterator *pi;
   589 	struct razor_package *package;
   590 	const char *name;
   591 	int matches = 0;
   592 
   593 	pi = razor_package_iterator_create(set);
   594 	while (razor_package_iterator_next(pi, &package,
   595 					   RAZOR_DETAIL_NAME, &name,
   596 					   RAZOR_DETAIL_LAST)) {
   597 		if (pattern && fnmatch(pattern, name, 0) == 0) {
   598 			razor_transaction_remove_package(trans, package);
   599 			matches++;
   600 		}
   601 	}
   602 	razor_package_iterator_destroy(pi);
   603 
   604 	return matches;
   605 }
   606 
   607 static int
   608 command_remove(int argc, const char *argv[])
   609 {
   610 	struct razor_set *system, *upstream, *next;
   611 	struct razor_transaction *trans;
   612 	struct razor_error *error = NULL;
   613 	struct razor_root *root;
   614 	int i, retval;
   615 
   616 	root = razor_root_open(install_root, &error);
   617 	if (root == NULL) {
   618 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   619 		razor_error_free(error);
   620 		return 1;
   621 	}
   622 
   623 	system = razor_root_get_system_set(root);
   624 	upstream = razor_set_create_without_root();
   625 	trans = razor_transaction_create(system, upstream);
   626 	razor_set_unref(upstream);
   627 	for (i = 0; i < argc; i++) {
   628 		if (mark_packages_for_removal(trans, system, argv[i]) == 0) {
   629 			fprintf(stderr, "no match for %s\n", argv[i]);
   630 			razor_transaction_destroy(trans);
   631 			razor_root_close(root);
   632 			return 1;
   633 		}
   634 	}
   635 
   636 	razor_transaction_resolve(trans);
   637 	retval = razor_transaction_describe(trans);
   638 	if (retval) {
   639 		razor_transaction_destroy(trans);
   640 		razor_root_close(root);
   641 		return 1;
   642 	}
   643 
   644 	next = razor_transaction_commit(trans);
   645 
   646 	retval = update_system(root, NULL, trans, next, "Remove");
   647 
   648 	razor_transaction_destroy(trans);
   649 	razor_root_close(root);
   650 	razor_set_unref(next);
   651 
   652 	return retval;
   653 }
   654 
   655 static void
   656 print_diff(enum razor_diff_action action,
   657 	   struct razor_package *package,
   658 	   const char *name,
   659 	   const char *version,
   660 	   const char *arch,
   661 	   void *data)
   662 {
   663 	if (action == RAZOR_DIFF_ACTION_ADD)
   664 		printf("install %s-%s.%s\n", name, version, arch);
   665 	if (action == RAZOR_DIFF_ACTION_REMOVE)
   666 		printf("remove %s-%s.%s\n", name, version, arch);
   667 }
   668 
   669 static int
   670 command_diff(int argc, const char *argv[])
   671 {
   672 	struct razor_error *error = NULL;
   673 	struct razor_set *set, *updated;
   674 
   675 	set = razor_root_open_read_only(install_root, &error);
   676 	if (set)
   677 		updated = razor_set_open(rawhide_repo_filename, 0, &error);
   678 	else
   679 		updated = NULL;
   680 	if (updated == NULL) {
   681 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   682 		razor_error_free(error);
   683 		if (set)
   684 			razor_set_unref(set);
   685 		return 1;
   686 	}
   687 
   688 	razor_set_diff(set, updated, print_diff, NULL);
   689 
   690 	razor_set_unref(set);
   691 	razor_set_unref(updated);
   692 
   693 	return 0;
   694 }
   695 
   696 static int
   697 command_import_rpms(int argc, const char *argv[])
   698 {
   699 	DIR *dir;
   700 	struct dirent *de;
   701 	struct razor_importer *importer;
   702 	struct razor_set *set;
   703 	struct razor_rpm *rpm;
   704 	struct razor_error *error=NULL;
   705 	struct razor_atomic *atomic;
   706 	int len, imported_count = 0;
   707 	char filename[256];
   708 	const char *dirname = argv[0];
   709 	int retval;
   710 
   711 	if (dirname == NULL) {
   712 		fprintf(stderr, "usage: razor import-rpms DIR\n");
   713 		return -1;
   714 	}
   715 
   716 	dir = opendir(dirname);
   717 	if (dir == NULL) {
   718 		fprintf(stderr, "couldn't read dir %s\n", dirname);
   719 		return -1;
   720 	}
   721 
   722 	importer = razor_importer_create();
   723 
   724 	while (de = readdir(dir), de != NULL) {
   725 		len = strlen(de->d_name);
   726 		if (len < 5 || strcmp(de->d_name + len - 4, ".rpm") != 0)
   727 			continue;
   728 		snprintf(filename, sizeof filename,
   729 			 "%s/%s", dirname, de->d_name);
   730 		rpm = razor_rpm_open(filename, &error);
   731 		if (rpm == NULL) {
   732 			fprintf(stderr, "%s\n", razor_error_get_msg(error));
   733 			razor_error_free(error);
   734 			error=NULL;
   735 			continue;
   736 		}
   737 		if (razor_importer_add_rpm(importer, rpm)) {
   738 			fprintf(stderr, "couldn't import %s\n", filename);
   739 			break;
   740 		}
   741 		razor_rpm_close(rpm);
   742 
   743 		printf("\rimporting %d", ++imported_count);
   744 		fflush(stdout);
   745 	}
   746 
   747 	if (de != NULL) {
   748 		razor_importer_destroy(importer);
   749 		return -1;
   750 	}
   751 
   752 	printf("\nsaving\n");
   753 	set = razor_importer_finish(importer);
   754 
   755 	atomic = razor_atomic_open("Update system database");
   756 	razor_set_write(set, atomic, repo_filename, RAZOR_SECTION_ALL);
   757 	razor_set_unref(set);
   758 	retval = razor_atomic_commit(atomic);
   759 	if (retval)
   760 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
   761 	else
   762 		printf("wrote %s\n", repo_filename);
   763 	razor_atomic_destroy(atomic);
   764 
   765 	return retval;
   766 }
   767 
   768 static char *
   769 rpm_filename(const char *name, const char *version, const char *arch)
   770 {
   771  	const char *v;
   772  
   773  	/* Skip epoch */
   774 	v = strchr(version, ':');
   775  	if (v != NULL)
   776  		v = v + 1;
   777  	else
   778 		v = version;
   779 
   780 	return razor_concat(name, "-", v, ".", arch, ".rpm", NULL);
   781 }
   782 
   783 static int
   784 download_packages(struct razor_set *system, struct razor_set *next)
   785 {
   786 	struct razor_install_iterator *ii;
   787 	struct razor_package *package;
   788 	enum razor_install_action action;
   789 	const char *name, *version, *arch;
   790 	char *file, *url, *s;
   791 	int errors = 0, count;
   792 
   793 	ii = razor_set_create_install_iterator(system, next);
   794 	while (razor_install_iterator_next(ii, &package, &action, &count)) {
   795 		if (action != RAZOR_INSTALL_ACTION_ADD)
   796 			continue;
   797 
   798 		razor_package_get_details(next, package,
   799 					  RAZOR_DETAIL_NAME, &name,
   800 					  RAZOR_DETAIL_VERSION, &version,
   801 					  RAZOR_DETAIL_ARCH, &arch,
   802 					  RAZOR_DETAIL_LAST);
   803 		
   804 		s = rpm_filename(name, version, arch);
   805 		url = razor_concat(yum_url, "/Packages/", s, NULL);
   806 		file = razor_concat("rpms/", s, NULL);
   807 		free(s);
   808 		if (download_if_missing(url, file) < 0)
   809 			errors++;
   810 		free(file);
   811 		free(url);
   812 	}
   813 	razor_install_iterator_destroy(ii);
   814 
   815 	if (errors > 0) {
   816 		fprintf(stderr, "failed to download %d packages\n", errors);
   817                 return -1;
   818         }
   819 
   820 	return 0;
   821 }
   822 
   823 static struct razor_set *
   824 relocate_packages(struct razor_set *set, struct razor_atomic *atomic,
   825 		  struct razor_relocations *relocations)
   826 {
   827 	int i;
   828 	struct razor_importer *importer;
   829 	struct razor_property_iterator *prop_iter;
   830 	struct razor_package_iterator *pkg_iter;
   831  	struct razor_file_iterator *file_iter;
   832  	struct razor_package *package;
   833 	struct razor_property *property;
   834 	struct razor_rpm *rpm;
   835 	struct razor_error *error=NULL;
   836 	const char *name, *version, *arch, *summary, *desc, *url, *license;
   837 	const char *preunprog, *preun, *postunprog, *postun;
   838 	const char *install_prefix;
   839 	const char *const *prefixes;
   840 	char *file, *s;
   841 	uint32_t flags;
   842 
   843 	importer = razor_importer_create();
   844 	pkg_iter = razor_package_iterator_create(set);
   845 
   846 	while (razor_package_iterator_next(pkg_iter, &package,
   847 					   RAZOR_DETAIL_NAME, &name,
   848 					   RAZOR_DETAIL_VERSION, &version,
   849 					   RAZOR_DETAIL_ARCH, &arch,
   850 					   RAZOR_DETAIL_SUMMARY, &summary,
   851 					   RAZOR_DETAIL_DESCRIPTION, &desc,
   852 					   RAZOR_DETAIL_URL, &url,
   853 					   RAZOR_DETAIL_LICENSE, &license,
   854 					   RAZOR_DETAIL_PREUNPROG, &preunprog,
   855 					   RAZOR_DETAIL_PREUN, &preun,
   856 					   RAZOR_DETAIL_POSTUNPROG, &postunprog,
   857 					   RAZOR_DETAIL_POSTUN, &postun,
   858 					   RAZOR_DETAIL_LAST)) {
   859 		s = rpm_filename(name, version, arch);
   860 		file = razor_concat("rpms/", s, NULL);
   861 		free(s);
   862 		rpm = razor_rpm_open(file, &error);
   863 		free(file);
   864 		if (rpm == NULL) {
   865 			razor_atomic_abort(atomic, razor_error_get_msg(error));
   866 			razor_error_free(error);
   867 			razor_package_iterator_destroy(pkg_iter);
   868 			razor_importer_destroy(importer);
   869 			return NULL;
   870 		}
   871 
   872 		razor_relocations_set_rpm(relocations, rpm);
   873 
   874 		razor_importer_begin_package(importer, name, version, arch);
   875 		razor_importer_add_details(importer,
   876 					   summary, desc, url, license);
   877 
   878 		razor_rpm_get_details(rpm, RAZOR_DETAIL_PREFIXES, &prefixes,
   879 				      RAZOR_DETAIL_LAST);
   880 		for (i = 0; prefixes && prefixes[i]; i++) {
   881 			install_prefix = razor_relocations_apply(relocations,
   882 								 prefixes[i]);
   883 			razor_importer_add_install_prefix(importer,
   884 							  install_prefix);
   885 		}
   886 
   887 		razor_rpm_close(rpm);
   888 
   889 		prop_iter = razor_property_iterator_create(set, package);
   890 		while (razor_property_iterator_next(prop_iter, &property,
   891 						    &name, &flags, &version))
   892 			razor_importer_add_property(importer,
   893 						    name, flags, version);
   894 		razor_property_iterator_destroy(prop_iter);
   895 
   896 		file_iter = razor_file_iterator_create(set, package, 0);
   897 		while (razor_file_iterator_next(file_iter, &name)) {
   898 			name = razor_relocations_apply(relocations, name);
   899 			razor_importer_add_file(importer, name);
   900 		}
   901 		razor_file_iterator_destroy(file_iter);
   902 
   903 		razor_importer_add_script(importer, RAZOR_PROPERTY_PREUN,
   904 					  preunprog, preun);
   905 		razor_importer_add_script(importer, RAZOR_PROPERTY_POSTUN,
   906 					  postunprog, postun);
   907 
   908 		razor_importer_finish_package(importer);
   909 	}
   910 
   911 	razor_package_iterator_destroy(pkg_iter);
   912 	return razor_importer_finish(importer);
   913 }
   914 
   915 static int
   916 install_package(struct razor_transaction *trans, struct razor_set *set,
   917 		struct razor_atomic *atomic, struct razor_package *package,
   918 		struct razor_relocations *relocations, int install_count,
   919 		enum razor_stage_type stage)
   920 {
   921 	int retval;
   922 	const char *name, *version, *arch;
   923 	char *file, *s;
   924 	struct razor_rpm *rpm;
   925 	struct razor_error *error=NULL;
   926 
   927 	razor_package_get_details(set, package,
   928 				  RAZOR_DETAIL_NAME, &name,
   929 				  RAZOR_DETAIL_VERSION, &version,
   930 				  RAZOR_DETAIL_ARCH, &arch,
   931 				  RAZOR_DETAIL_LAST);
   932 
   933 	if (stage & RAZOR_STAGE_SCRIPTS_PRE)
   934 		printf("install %s-%s\n", name, version);
   935 
   936 	s = rpm_filename(name, version, arch);
   937 	file = razor_concat("rpms/", s, NULL);
   938 	free(s);
   939 	rpm = razor_rpm_open(file, &error);
   940 	free(file);
   941 	if (rpm == NULL) {
   942 		razor_atomic_abort(atomic, razor_error_get_msg(error));
   943 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   944 		razor_error_free(error);
   945 		return -1;
   946 	}
   947 	if (relocations)
   948 		razor_rpm_set_relocations(rpm, relocations);
   949 	razor_transaction_fixup_package(trans, package, rpm);
   950 	retval = razor_rpm_install(rpm, atomic, install_root, install_count,
   951 				   stage);
   952 	if (retval < 0) {
   953 		s = rpm_filename(name, version, arch);
   954 		fprintf(stderr, "%s: %s\n", s,
   955 			razor_atomic_get_error_msg(atomic));
   956 		free(s);
   957 	}
   958 	razor_rpm_close(rpm);
   959 	return retval;
   960 }
   961 
   962 /*
   963  * Returns 0 on success, -1 on failure and 1 if a RAZOR_INSTALL_ACTION_COMMIT
   964  * is met (in which case the action is consumed).
   965  */
   966 static int
   967 update_packages(struct razor_transaction *trans,
   968 		struct razor_install_iterator *ii, struct razor_set *system,
   969 		struct razor_set *next, struct razor_atomic *atomic,
   970 		struct razor_relocations *relocations,
   971 		enum razor_stage_type stage)
   972 {
   973 	struct razor_package *package;
   974 	enum razor_install_action action;
   975 	int retval = 0, count;
   976 
   977 	while (!retval && razor_install_iterator_next(ii, &package, &action,
   978 						      &count)) {
   979 		if (action == RAZOR_INSTALL_ACTION_ADD) {
   980 			if (install_package(trans, next, atomic, package,
   981 					    relocations, count, stage))
   982 				retval = -1;
   983 		} else if (action == RAZOR_INSTALL_ACTION_REMOVE) {
   984 			if (razor_package_remove(system, next, atomic, package,
   985 						 install_root, count, stage))
   986 				retval = -1;
   987 		} else if (action == RAZOR_INSTALL_ACTION_COMMIT)
   988 				retval = 1;
   989 	}
   990 
   991 	return retval;
   992 }
   993 
   994 static int
   995 update_system(struct razor_root *root, struct razor_relocations *relocations,
   996 	      struct razor_transaction *trans, struct razor_set *next,
   997 	      const char *verb)
   998 {
   999 	struct razor_set *system, *set;
  1000 	struct razor_atomic *atomic;
  1001 	struct razor_install_iterator *ii;
  1002 	int r, retval = 0;
  1003 	char *description;
  1004 	size_t pos;
  1005 
  1006 	description = razor_concat(verb, " packages", NULL);
  1007 
  1008 	system = razor_set_ref(razor_root_get_system_set(root));
  1009 
  1010 	ii = razor_set_create_install_iterator(system, next);
  1011 
  1012 	do {
  1013 		pos = razor_install_iterator_tell(ii);
  1014 
  1015 		atomic = razor_atomic_open(description);
  1016 
  1017 		r = update_packages(trans, ii, system, next, atomic,
  1018 				    relocations, RAZOR_STAGE_SCRIPTS_PRE);
  1019 		if (r < 0) {
  1020 			fprintf(stderr, "%s aborted\n", verb);
  1021 			retval = r;
  1022 		} else {
  1023 			razor_install_iterator_seek(ii, pos);
  1024 			r = update_packages(trans, ii, system, next, atomic,
  1025 					    relocations, RAZOR_STAGE_FILES);
  1026 
  1027 			if (r == 1) {
  1028 				set = razor_install_iterator_commit_set(ii);
  1029 				razor_root_update(root, set, atomic);
  1030 				razor_set_unref(set);
  1031 			} else if (r == 0)
  1032 				razor_root_update(root, next, atomic);
  1033 
  1034 			retval = razor_atomic_commit(atomic);
  1035 			if (retval)
  1036 				fprintf(stderr, "%s\n",
  1037 					razor_atomic_get_error_msg(atomic));
  1038 			else {
  1039 				razor_install_iterator_seek(ii, pos);
  1040 				update_packages(trans, ii, system, next,
  1041 						atomic, relocations,
  1042 						RAZOR_STAGE_SCRIPTS_POST);
  1043 			}
  1044 		}
  1045 
  1046 		razor_atomic_destroy(atomic);
  1047 	} while(!retval && r == 1);
  1048 
  1049 	razor_set_unref(system);
  1050 
  1051 	free(description);
  1052 
  1053 	return retval;
  1054 }
  1055 
  1056 static int
  1057 command_install_or_update(int argc, const char *argv[], int do_update)
  1058 {
  1059 	struct razor_relocations *relocations = NULL;
  1060 	struct razor_set *system, *upstream, *next, *set;
  1061 	struct razor_transaction *trans;
  1062 	struct razor_error *error = NULL;
  1063 	struct razor_atomic *atomic;
  1064 	struct razor_root *root;
  1065 	int i, retval, len, dependencies = 1;
  1066 	char *oldpath;
  1067 
  1068 	for (i = 0; i < argc; i++) {
  1069 		if (strcmp(argv[i], "--no-dependencies") == 0)
  1070 			dependencies = 0;
  1071 		else if (strcmp(argv[i], "--relocate") == 0) {
  1072 			i++;
  1073 			if (i >= argc || strchr(argv[i], '=') == NULL) {
  1074 				fprintf(stderr,
  1075 				    "Usage: razor %s [OPTION...] RPM\n",
  1076 				    do_update ? "update" : "install");
  1077 				fprintf(stderr, "Options:\n");
  1078 				fprintf(stderr, "    [--no-dependencies]\n");
  1079 				fprintf(stderr,
  1080 				    "    [--relocate OLDPATH=NEWPATH] RPM\n");
  1081 				return -1;
  1082 			}
  1083 			len = strchr(argv[i], '=') - argv[i];
  1084 			oldpath = malloc(len + 1);
  1085 			strncpy(oldpath, argv[i], len);
  1086 			oldpath[len] = '\0';
  1087 			if (!relocations)
  1088 			       relocations = razor_relocations_create();
  1089 			razor_relocations_add(relocations, oldpath,
  1090 					      argv[i] + len + 1);
  1091 			free(oldpath);
  1092 		} else
  1093 			break;
  1094 	}
  1095 
  1096 	upstream = razor_set_open(rawhide_repo_filename, 0, &error);
  1097 	if (upstream == NULL) {
  1098 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1099 		razor_error_free(error);
  1100 		return 1;
  1101 	}
  1102 
  1103 	if (do_update)
  1104 		atomic = razor_atomic_open("Update packages");
  1105 	else
  1106 		atomic = razor_atomic_open("Install packages");
  1107 
  1108 	if (relocations) {
  1109 		set = relocate_packages(upstream, atomic, relocations);
  1110 		if (set == NULL) {
  1111 			fprintf(stderr, "%s\n",
  1112 				razor_atomic_get_error_msg(atomic));
  1113 			razor_atomic_destroy(atomic);
  1114 			razor_set_unref(upstream);
  1115 			return 1;
  1116 		}
  1117 		razor_set_unref(upstream);
  1118 		upstream = set;
  1119 	}
  1120 
  1121 	root = razor_root_open(install_root, &error);
  1122 	if (root == NULL) {
  1123 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1124 		razor_error_free(error);
  1125 		razor_atomic_destroy(atomic);
  1126 		razor_set_unref(upstream);
  1127 		if (relocations)
  1128 			razor_relocations_destroy(relocations);
  1129 		return 1;
  1130 	}
  1131 
  1132 	system = razor_root_get_system_set(root);
  1133 	trans = razor_transaction_create(system, upstream);
  1134 
  1135 	if (i == argc && do_update)
  1136 		razor_transaction_update_all(trans);
  1137 	for (; i < argc; i++) {
  1138 		if (do_update &&
  1139 		    mark_packages_for_update(trans, system, argv[i]))
  1140 			continue;
  1141 		if (mark_packages_for_update(trans, upstream, argv[i]) == 0) {
  1142 			fprintf(stderr, "no package matched %s\n", argv[i]);
  1143 			razor_transaction_destroy(trans);
  1144 			razor_root_close(root);
  1145 			razor_set_unref(upstream);
  1146 			razor_atomic_destroy(atomic);
  1147 			if (relocations)
  1148 				razor_relocations_destroy(relocations);
  1149 			return 1;
  1150 		}
  1151 	}
  1152 
  1153 	if (dependencies) {
  1154 		razor_transaction_resolve(trans);
  1155 		if (razor_transaction_describe(trans) > 0) {
  1156 			razor_transaction_destroy(trans);
  1157 			razor_set_unref(upstream);
  1158 			razor_root_close(root);
  1159 			razor_atomic_destroy(atomic);
  1160 			if (relocations)
  1161 				razor_relocations_destroy(relocations);
  1162 			return 1;
  1163 		}
  1164 	}
  1165 
  1166 	if (razor_atomic_create_dir(atomic, "rpms",
  1167 				    S_IRWXU | S_IRWXG | S_IRWXO) ||
  1168 	    razor_atomic_commit(atomic)) {
  1169 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  1170 		razor_transaction_destroy(trans);
  1171 		razor_set_unref(upstream);
  1172 		razor_root_close(root);
  1173 		razor_atomic_destroy(atomic);
  1174 		if (relocations)
  1175 			razor_relocations_destroy(relocations);
  1176 		return 1;
  1177 	}
  1178 
  1179 	razor_atomic_destroy(atomic);
  1180 
  1181 	next = razor_transaction_commit(trans);
  1182 
  1183 	if (download_packages(system, next) < 0) {
  1184 		razor_set_unref(next);
  1185 		razor_transaction_destroy(trans);
  1186 		razor_set_unref(upstream);
  1187 		razor_root_close(root);
  1188 		razor_atomic_destroy(atomic);
  1189 		if (relocations)
  1190 			razor_relocations_destroy(relocations);
  1191                 return 1;
  1192         }
  1193 
  1194 	retval = update_system(root, relocations, trans, next,
  1195 			       do_update ? "Update" : "Install");
  1196 
  1197 	razor_set_unref(upstream);
  1198 	razor_root_close(root);
  1199 
  1200 	razor_transaction_destroy(trans);
  1201 	if (relocations)
  1202 		razor_relocations_destroy(relocations);
  1203 
  1204 	razor_set_unref(next);
  1205 
  1206 	return retval;
  1207 }
  1208 
  1209 static int
  1210 command_update(int argc, const char *argv[])
  1211 {
  1212 	return command_install_or_update(argc, argv, 1);
  1213 }
  1214 
  1215 static int
  1216 command_install(int argc, const char *argv[])
  1217 {
  1218 	return command_install_or_update(argc, argv, 0);
  1219 }
  1220 
  1221 static int
  1222 command_init(int argc, const char *argv[])
  1223 {
  1224 	int retval;
  1225 	struct razor_error *error = NULL;
  1226 
  1227 	retval = razor_root_create(install_root, &error);
  1228 	if (retval) {
  1229 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1230 		razor_error_free(error);
  1231 	} else
  1232 		printf("Created install root\n");
  1233 
  1234 	return retval;
  1235 }
  1236 
  1237 static int
  1238 command_download(int argc, const char *argv[])
  1239 {
  1240 	struct razor_error *error = NULL;
  1241 	struct razor_atomic *atomic;
  1242 	struct razor_set *set;
  1243 	struct razor_package_iterator *pi;
  1244 	struct razor_package *package;
  1245 	const char *pattern = argv[0], *name, *version, *arch;
  1246 	char url[256], file[256];
  1247 	int matches = 0;
  1248 
  1249 	set = razor_set_open(rawhide_repo_filename, 0, &error);
  1250 	if (set == NULL) {
  1251 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1252 		razor_error_free(error);
  1253 		return 1;
  1254 	}
  1255 
  1256 	atomic = razor_atomic_open("Download packages");
  1257 
  1258 	if (razor_atomic_create_dir(atomic, "rpms", 
  1259 				    S_IRWXU | S_IRWXG | S_IRWXO)) {
  1260 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  1261 		razor_atomic_destroy(atomic);
  1262 		return 1;
  1263 	}
  1264 
  1265 	if (razor_atomic_commit(atomic)) {
  1266 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  1267 		razor_atomic_destroy(atomic);
  1268 		return 1;
  1269 	}
  1270 	razor_atomic_destroy(atomic);
  1271 
  1272 	pi = razor_package_iterator_create(set);
  1273 	while (razor_package_iterator_next(pi, &package,
  1274 					   RAZOR_DETAIL_NAME, &name,
  1275 					   RAZOR_DETAIL_VERSION, &version,
  1276 					   RAZOR_DETAIL_ARCH, &arch,
  1277 					   RAZOR_DETAIL_LAST)) {
  1278 		if (pattern && fnmatch(pattern, name, 0) != 0)
  1279 			continue;
  1280 
  1281 		matches++;
  1282 		snprintf(url, sizeof url,
  1283 			 "%s/Packages/%s-%s.%s.rpm",
  1284 			 yum_url, name, version, arch);
  1285 		snprintf(file, sizeof file,
  1286 			 "rpms/%s-%s.%s.rpm", name, version, arch);
  1287 		download_if_missing(url, file);
  1288 	}
  1289 	razor_package_iterator_destroy(pi);
  1290 	razor_set_unref(set);
  1291 
  1292 	if (matches == 0)
  1293 		fprintf(stderr, "no packages matched \"%s\"\n", pattern);
  1294 	else if (matches == 1)
  1295 		fprintf(stderr, "downloaded 1 package\n");
  1296 	else
  1297 		fprintf(stderr, "downloaded %d packages\n", matches);
  1298 
  1299 	return 0;
  1300 }
  1301 
  1302 static int
  1303 command_info(int argc, const char *argv[])
  1304 {
  1305 	struct razor_error *error = NULL;
  1306 	struct razor_set *set;
  1307 	struct razor_package_iterator *pi;
  1308 	struct razor_package *package;
  1309 	const char *pattern = argv[0], *name, *version, *arch;
  1310 	const char *summary, *description, *url, *license;
  1311 
  1312 	set = razor_root_open_read_only(install_root, &error);
  1313 	if (set == NULL) {
  1314 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1315 		razor_error_free(error);
  1316 		return 1;
  1317 	}
  1318 
  1319 	pi = razor_package_iterator_create(set);
  1320 	while (razor_package_iterator_next(pi, &package,
  1321 					   RAZOR_DETAIL_NAME, &name,
  1322 					   RAZOR_DETAIL_VERSION, &version,
  1323 					   RAZOR_DETAIL_ARCH, &arch,
  1324 					   RAZOR_DETAIL_LAST)) {
  1325 		if (pattern && fnmatch(pattern, name, 0) != 0)
  1326 			continue;
  1327 
  1328 		razor_package_get_details (set, package,
  1329 					   RAZOR_DETAIL_SUMMARY, &summary,
  1330 					   RAZOR_DETAIL_DESCRIPTION, &description,
  1331 					   RAZOR_DETAIL_URL, &url,
  1332 					   RAZOR_DETAIL_LICENSE, &license,
  1333 					   RAZOR_DETAIL_LAST);
  1334 
  1335 		printf ("Name:        %s\n", name);
  1336 		printf ("Arch:        %s\n", arch);
  1337 		printf ("Version:     %s\n", version);
  1338 		printf ("URL:         %s\n", url);
  1339 		printf ("License:     %s\n", license);
  1340 		printf ("Summary:     %s\n", summary);
  1341 		printf ("Description:\n");
  1342 		printf ("%s\n", description);
  1343 		printf ("\n");
  1344 	}
  1345 	razor_package_iterator_destroy(pi);
  1346 	razor_set_unref(set);
  1347 
  1348 	return 0;
  1349 }
  1350 
  1351 #define SEARCH_MAX 256
  1352 
  1353 static int
  1354 command_search(int argc, const char *argv[])
  1355 {
  1356 	struct razor_error *error = NULL;
  1357 	struct razor_set *set;
  1358 	struct razor_package_iterator *pi;
  1359 	struct razor_package *package;
  1360 	char pattern[SEARCH_MAX];
  1361 	const char *name, *version, *arch;
  1362 	const char *summary, *description, *url, *license;
  1363 
  1364 	if (!argv[0]) {
  1365 		fprintf(stderr, "must specify a search term\n");
  1366 		return 1;
  1367 	}
  1368 
  1369 	snprintf(pattern, sizeof pattern, "*%s*", argv[0]);
  1370 
  1371 	set = razor_set_open(rawhide_repo_filename, 0, &error);
  1372 	if (set == NULL) {
  1373 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1374 		razor_error_free(error);
  1375 		return 1;
  1376 	}
  1377 
  1378 	pi = razor_package_iterator_create(set);
  1379 	while (razor_package_iterator_next(pi, &package,
  1380 					   RAZOR_DETAIL_NAME, &name,
  1381 					   RAZOR_DETAIL_VERSION, &version,
  1382 					   RAZOR_DETAIL_ARCH, &arch,
  1383 					   RAZOR_DETAIL_SUMMARY, &summary,
  1384 					   RAZOR_DETAIL_DESCRIPTION, &description,
  1385 					   RAZOR_DETAIL_URL, &url,
  1386 					   RAZOR_DETAIL_LICENSE, &license,
  1387 					   RAZOR_DETAIL_LAST)) {
  1388 		if (!fnmatch(pattern, name, FNM_CASEFOLD) ||
  1389 		    !fnmatch(pattern, url, FNM_CASEFOLD) ||
  1390 		    !fnmatch(pattern, summary, FNM_CASEFOLD) ||
  1391 		    !fnmatch(pattern, description, FNM_CASEFOLD))
  1392 			printf("%s-%s.%s: %s\n", name, version, arch, summary);
  1393 	}
  1394 	razor_package_iterator_destroy(pi);
  1395 	razor_set_unref(set);
  1396 
  1397 	return 0;
  1398 }
  1399 
  1400 static struct {
  1401 	const char *name;
  1402 	const char *description;
  1403 	int (*func)(int argc, const char *argv[]);
  1404 } razor_commands[] = {
  1405 	{ "list", "list all packages", command_list },
  1406 	{ "list-requires", "list all requires for the given package", command_list_requires },
  1407 	{ "list-provides", "list all provides for the given package", command_list_provides },
  1408 	{ "list-obsoletes", "list all obsoletes for the given package", command_list_obsoletes },
  1409 	{ "list-conflicts", "list all conflicts for the given package", command_list_conflicts },
  1410 	{ "list-scripts", "list all scripts for the given package", command_list_scripts },
  1411 	{ "list-files", "list files for package set", command_list_files },
  1412 	{ "list-file-packages", "list packages owning file", command_list_file_packages },
  1413 	{ "list-package-files", "list files in package", command_list_package_files },
  1414 	{ "what-requires", "list the packages that have the given requires", command_what_requires },
  1415 	{ "what-provides", "list the packages that have the given provides", command_what_provides },
  1416 	{ "import-yum", "import yum metadata files", command_import_yum },
  1417 #if HAVE_RPMLIB
  1418 	{ "import-rpmdb", "import the system rpm database", command_import_rpmdb },
  1419 #endif
  1420 	{ "import-rpms", "import rpms from the given directory", command_import_rpms },
  1421 	{ "update", "update all or specified packages", command_update },
  1422 	{ "remove", "remove specified packages", command_remove },
  1423 	{ "diff", "show diff between two package sets", command_diff },
  1424 	{ "install", "install rpm", command_install },
  1425 	{ "init", "init razor root", command_init },
  1426 	{ "download", "download packages", command_download },
  1427 	{ "info", "display package details", command_info },
  1428 	{ "search", "search package details", command_search }
  1429 };
  1430 
  1431 static int
  1432 usage(void)
  1433 {
  1434 	int i;
  1435 
  1436 	printf("usage:\n");
  1437 	for (i = 0; i < ARRAY_SIZE(razor_commands); i++)
  1438 		printf("  %-20s%s\n",
  1439 		       razor_commands[i].name, razor_commands[i].description);
  1440 
  1441 	return 1;
  1442 }
  1443 
  1444 int
  1445 main(int argc, const char *argv[])
  1446 {
  1447 	char *repo, *root;
  1448 	int i;
  1449 
  1450 	repo = getenv("RAZOR_REPO");
  1451 	if (repo != NULL)
  1452 		repo_filename = repo;
  1453 
  1454 	root = getenv("RAZOR_ROOT");
  1455 	if (root != NULL)
  1456 		install_root = root;
  1457 
  1458 	yum_url = getenv("YUM_URL");
  1459 	if (yum_url == NULL)
  1460 		yum_url = YUM_URL;
  1461 
  1462 	if (getenv("RAZOR_NO_ROOT_NAME_CHECKS"))
  1463 		razor_disable_root_name_checks(1);
  1464 
  1465 	if (argc < 2)
  1466 		return usage();
  1467 
  1468 	for (i = 0; i < ARRAY_SIZE(razor_commands); i++)
  1469 		if (strcmp(razor_commands[i].name, argv[1]) == 0)
  1470 			return razor_commands[i].func(argc - 2, argv + 2);
  1471 
  1472 	return usage();
  1473 }