src/main.c
author J. Ali Harlow <ali@juiblex.co.uk>
Mon Sep 08 10:26:39 2014 +0100 (2014-09-08)
changeset 445 aada48958b92
parent 442 c4bcba8023a9
child 447 0a5e583393e1
permissions -rw-r--r--
Add control over database location
     1 /*
     2  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     3  * Copyright (C) 2008  Red Hat, Inc
     4  * Copyright (C) 2009, 2011-2012, 2014  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 <getopt.h>
    41 #include "razor.h"
    42 
    43 static const char system_repo_filename[] = "system.rzdb";
    44 static const char next_repo_filename[] = "system-next.rzdb";
    45 static const char rawhide_repo_filename[] = "rawhide.rzdb";
    46 static const char *install_root = "";
    47 static const char *repo_filename = system_repo_filename;
    48 static const char *yum_url;
    49 
    50 #ifndef FALSE
    51 #define FALSE 0
    52 #endif
    53 
    54 #ifndef TRUE
    55 #define TRUE (!FALSE)
    56 #endif
    57 
    58 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
    59 
    60 static int
    61 update_packages(struct razor_transaction *trans,
    62 		struct razor_install_iterator *ii, struct razor_set *system,
    63 		struct razor_set *next, struct razor_atomic *atomic,
    64 		struct razor_relocations *relocations,
    65 		enum razor_stage_type stage);
    66 static int
    67 update_system(struct razor_root *root, struct razor_relocations *relocations,
    68 	      struct razor_transaction *trans, struct razor_set *next,
    69 	      const char *verb);
    70 
    71 static int command_help(int argc, char * const argv[]);
    72 
    73 struct razor_option {
    74 	char *name;
    75 	int has_arg;
    76 	int val;
    77 	char *description;
    78 	char *arg_description;
    79 };
    80 
    81 static void
    82 razor_usage(const char *command, int n_options, struct razor_option *options,
    83 	    const char *parameter_string)
    84 {
    85 	int i, help_printed = FALSE;
    86 	char buf[19];
    87 
    88 	printf("Usage: razor %s [options] %s\n", command, parameter_string);
    89 	printf("(Specify the --help global option for a list of other "
    90 	       "help options)\n");
    91 	printf("\nOptions:\n");
    92 
    93 	for(i = 0; i < n_options; i++) {
    94 		if (!help_printed && strcmp(options[i].name, "help") > 0) {
    95 			printf("  --help              "
    96 			       "Show this help message and exit\n");
    97 			help_printed = TRUE;
    98 		}
    99 
   100 		if (options[i].has_arg != no_argument)
   101 			snprintf(buf, sizeof(buf), "%s=%s", options[i].name,
   102 				 options[i].arg_description);
   103 		else
   104 			strncpy(buf, options[i].name, sizeof(buf));
   105 		buf[18] = '\0';
   106 
   107 		printf("  --%-18s%s\n", buf, options[i].description);
   108 	}
   109 
   110 	if (!help_printed)
   111 		printf("  --help              "
   112 		       "Show this help message and exit\n");
   113 }
   114 
   115 /**
   116  * razor_getopt:
   117  *
   118  *
   119  * Returns: The next option found or -2 on handled or -1 on error
   120  *          or 0 on end of option list.
   121  **/
   122 static int
   123 razor_getopt(int argc, char * const argv[], int n_options,
   124 	     struct razor_option *options, const char *parameter_string,
   125 	     const char **arg)
   126 {
   127 	int i, opt, do_help = 0, retval;
   128 	struct option *longopts;
   129 
   130 	longopts = calloc((n_options + 2), sizeof(*longopts));
   131 
   132 	for(i = 0; i < n_options; i++) {
   133 		longopts[i].name = options[i].name;
   134 		longopts[i].has_arg = options[i].has_arg;
   135 		longopts[i].flag = &retval;
   136 		longopts[i].val = options[i].val;
   137 	}
   138 
   139 	longopts[i].name = "help";
   140 	longopts[i].has_arg = no_argument;
   141 	longopts[i].flag = &do_help;
   142 	longopts[i].val = TRUE;
   143 
   144 	opterr = 0;
   145 
   146 	opt = getopt_long(argc, argv, "+", longopts, NULL);
   147 
   148 	switch (opt)
   149 	{
   150 		case 0:
   151 			if (do_help) {
   152 				razor_usage(argv[0], n_options, options,
   153 					    parameter_string);
   154 				retval = -2;
   155 			} else if (arg)
   156 				*arg = optarg;
   157 			break;
   158 
   159 		case -1:
   160 			retval = 0;
   161 			break;
   162 
   163 		default:
   164 			razor_usage(argv[0], n_options, options,
   165 				    parameter_string);
   166 			retval = -1;
   167 	}
   168 
   169 	free(longopts);
   170 	return retval;
   171 }
   172 
   173 static struct razor_package_iterator *
   174 create_iterator_from_argv(struct razor_set *set, int argc, char * const argv[])
   175 {
   176 	struct razor_package_query *query;
   177 	struct razor_package_iterator *iter;
   178 	struct razor_package *package;
   179 	const char *name, *pattern;
   180 	int i, count;
   181 
   182 	if (argc == 0)
   183 		return razor_package_iterator_create(set);
   184 
   185 	query = razor_package_query_create(set);
   186 
   187 	for (i = 0; i < argc; i++) {
   188 		iter = razor_package_iterator_create(set);
   189 		pattern = argv[i];
   190 		count = 0;
   191 		while (razor_package_iterator_next(iter, &package,
   192 						   RAZOR_DETAIL_NAME, &name,
   193 						   RAZOR_DETAIL_LAST)) {
   194 			if (fnmatch(pattern, name, 0) != 0)
   195 				continue;
   196 
   197 			razor_package_query_add_package(query, package);
   198 			count++;
   199 		}
   200 		razor_package_iterator_destroy(iter);
   201 
   202 		if (count == 0)
   203 			fprintf(stderr,
   204 				"no package matches \"%s\"\n", pattern);
   205 	}
   206 
   207 	return razor_package_query_finish(query);
   208 }
   209 
   210 #define LIST_PACKAGES_ONLY_NAMES 0x01
   211 
   212 static void
   213 list_packages(struct razor_package_iterator *iter, uint32_t flags)
   214 {
   215 	struct razor_package *package;
   216 	const char *name, *version, *arch;
   217 
   218 	while (razor_package_iterator_next(iter, &package,
   219 					   RAZOR_DETAIL_NAME, &name,
   220 					   RAZOR_DETAIL_VERSION, &version,
   221 					   RAZOR_DETAIL_ARCH, &arch,
   222 					   RAZOR_DETAIL_LAST)) {
   223 		if (flags & LIST_PACKAGES_ONLY_NAMES)
   224 			printf("%s\n", name);
   225 		else
   226 			printf("%s-%s.%s\n", name, version, arch);
   227 	}
   228 }
   229 
   230 static int
   231 command_list(int argc, char * const argv[])
   232 {
   233 	int opt;
   234 	struct razor_package_iterator *pi;
   235 	struct razor_error *error = NULL;
   236 	struct razor_set *set;
   237 	uint32_t flags = 0;
   238 	enum {
   239 		opt_only_names = 1,
   240 	};
   241 	static struct razor_option options[] = {
   242 		{ .name = "only-names", .has_arg = no_argument,
   243 		  .val = opt_only_names,
   244 		  .description = "Only list package names" },
   245 	};
   246 
   247 	do {
   248 		opt = razor_getopt(argc, argv, ARRAY_SIZE(options), options,
   249 				   "pattern ...", NULL);
   250 		switch (opt) {
   251 			case -2:
   252 				return 0;
   253 			case -1:
   254 				return 1;
   255 			case opt_only_names:
   256 				flags |= LIST_PACKAGES_ONLY_NAMES;
   257 				break;
   258 		}
   259 	} while (opt);
   260 
   261 	set = razor_root_open_read_only(install_root, &error);
   262 	if (set == NULL) {
   263 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   264 		razor_error_free(error);
   265 		return 1;
   266 	}
   267 
   268 	pi = create_iterator_from_argv(set, argc - optind, argv + optind);
   269 	list_packages(pi, flags);
   270 	razor_package_iterator_destroy(pi);
   271 	razor_set_unref(set);
   272 
   273 	return 0;
   274 }
   275 
   276 static void
   277 list_package_properties(struct razor_set *set,
   278 			struct razor_package *package, uint32_t type)
   279 {
   280 	struct razor_property_iterator *pi;
   281 	struct razor_property *property;
   282 	const char *name, *version;
   283 	uint32_t flags;
   284 
   285 	pi = razor_property_iterator_create(set, package);
   286 	while (razor_property_iterator_next(pi, &property,
   287 					    &name, &flags, &version)) {
   288 		if ((flags & RAZOR_PROPERTY_TYPE_MASK) != type)
   289 			continue;
   290 		printf("%s", name);
   291 		if (version[0] != '\0')
   292 			printf(" %s %s",
   293 			       razor_property_relation_to_string(property),
   294 			       version);
   295 
   296 		if (flags & ~(RAZOR_PROPERTY_RELATION_MASK | RAZOR_PROPERTY_TYPE_MASK)) {
   297 			printf(" [");
   298 			if (flags & RAZOR_PROPERTY_PRE)
   299 				printf(" pre");
   300 			if (flags & RAZOR_PROPERTY_POST)
   301 				printf(" post");
   302 			if (flags & RAZOR_PROPERTY_PREUN)
   303 				printf(" preun");
   304 			if (flags & RAZOR_PROPERTY_POSTUN)
   305 				printf(" postun");
   306 			printf(" ]");
   307 		}
   308 		printf("\n");
   309 	}
   310 	razor_property_iterator_destroy(pi);
   311 }
   312 
   313 static int
   314 list_properties(int argc, char * const argv[], uint32_t type)
   315 {
   316 	struct razor_set *set;
   317 	struct razor_error *error = NULL;
   318 	struct razor_package *package;
   319 	struct razor_package_iterator *pi;
   320 	const char *name, *version, *arch;
   321 
   322 	switch (razor_getopt(argc, argv, 0, NULL, "pattern ...", NULL)) {
   323 		case -2:
   324 			return 0;
   325 		case -1:
   326 			return 1;
   327 	}
   328 
   329 	set = razor_root_open_read_only(install_root, &error);
   330 	if (set == NULL) {
   331 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   332 		razor_error_free(error);
   333 		return 1;
   334 	}
   335 
   336 	pi = create_iterator_from_argv(set, argc - optind, argv + optind);
   337 	while (razor_package_iterator_next(pi, &package,
   338 					   RAZOR_DETAIL_NAME, &name,
   339 					   RAZOR_DETAIL_VERSION, &version,
   340 					   RAZOR_DETAIL_ARCH, &arch,
   341 					   RAZOR_DETAIL_LAST))
   342 		list_package_properties(set, package, type);
   343 	razor_package_iterator_destroy(pi);
   344 	razor_set_unref(set);
   345 
   346 	return 0;
   347 }
   348 
   349 static int
   350 command_list_requires(int argc, char * const argv[])
   351 {
   352 	return list_properties(argc, argv, RAZOR_PROPERTY_REQUIRES);
   353 }
   354 
   355 static int
   356 command_list_provides(int argc, char * const argv[])
   357 {
   358 	return list_properties(argc, argv, RAZOR_PROPERTY_PROVIDES);
   359 }
   360 
   361 static int
   362 command_list_obsoletes(int argc, char * const argv[])
   363 {
   364 	return list_properties(argc, argv, RAZOR_PROPERTY_OBSOLETES);
   365 }
   366 
   367 static int
   368 command_list_conflicts(int argc, char * const argv[])
   369 {
   370 	return list_properties(argc, argv, RAZOR_PROPERTY_CONFLICTS);
   371 }
   372 
   373 static int
   374 command_list_scripts(int argc, char * const argv[])
   375 {
   376 	struct razor_set *set;
   377 	struct razor_error *error = NULL;
   378 	struct razor_package *package;
   379 	struct razor_package_iterator *pi;
   380 	const char *preunprog, *preun, *postunprog, *postun;
   381 
   382 	switch (razor_getopt(argc, argv, 0, NULL, "pattern ...", NULL)) {
   383 		case -2:
   384 			return 0;
   385 		case -1:
   386 			return 1;
   387 	}
   388 
   389 	set = razor_root_open_read_only(install_root, &error);
   390 	if (set == NULL) {
   391 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   392 		razor_error_free(error);
   393 		return 1;
   394 	}
   395 
   396 	pi = create_iterator_from_argv(set, argc - optind, argv + optind);
   397 	while (razor_package_iterator_next(pi, &package,
   398 					   RAZOR_DETAIL_PREUNPROG, &preunprog,
   399 					   RAZOR_DETAIL_PREUN, &preun,
   400 					   RAZOR_DETAIL_POSTUNPROG, &postunprog,
   401 					   RAZOR_DETAIL_POSTUN, &postun,
   402 					   RAZOR_DETAIL_LAST)) {
   403 		if (preun && *preun) {
   404 			printf("preuninstall scriptlet");
   405 			if (preunprog && *preunprog)
   406 				printf(" (using %s)",preunprog);
   407 			printf(":\n%s\n",preun);
   408 		}
   409 		if (postun && *postun) {
   410 			printf("postuninstall scriptlet");
   411 			if (postunprog && *postunprog)
   412 				printf(" (using %s)",postunprog);
   413 			printf(":\n%s\n",postun);
   414 		}
   415 	}
   416 	razor_package_iterator_destroy(pi);
   417 	razor_set_unref(set);
   418 
   419 	return 0;
   420 }
   421 
   422 static int
   423 command_list_files(int argc, char * const argv[])
   424 {
   425 	struct razor_error *error = NULL;
   426 	struct razor_set *set;
   427 
   428 	switch (razor_getopt(argc, argv, 0, NULL, "[pattern]", NULL)) {
   429 		case -2:
   430 			return 0;
   431 		case -1:
   432 			return 1;
   433 	}
   434 
   435 	if (argc - optind > 1) {
   436 		razor_usage(argv[0], 0, NULL, "[pattern]");
   437 		return 1;
   438 	}
   439 
   440 	set = razor_root_open_read_only(install_root, &error);
   441 	if (set == NULL) {
   442 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   443 		razor_error_free(error);
   444 		return 1;
   445 	}
   446 
   447 	razor_set_list_files(set, argv[optind]);
   448 	razor_set_unref(set);
   449 
   450 	return 0;
   451 }
   452 
   453 static int
   454 command_list_file_packages(int argc, char * const argv[])
   455 {
   456 	struct razor_error *error = NULL;
   457 	struct razor_set *set;
   458 	struct razor_package_iterator *pi;
   459 
   460 	switch (razor_getopt(argc, argv, 0, NULL, "pattern", NULL)) {
   461 		case -2:
   462 			return 0;
   463 		case -1:
   464 			return 1;
   465 	}
   466 
   467 	if (argc - optind != 1) {
   468 		razor_usage(argv[0], 0, NULL, "pattern");
   469 		return 1;
   470 	}
   471 
   472 	set = razor_root_open_read_only(install_root, &error);
   473 	if (set == NULL) {
   474 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   475 		razor_error_free(error);
   476 		return 1;
   477 	}
   478 
   479 	pi = razor_package_iterator_create_for_file(set, argv[optind]);
   480 	list_packages(pi, 0);
   481 	razor_package_iterator_destroy(pi);
   482 
   483 	razor_set_unref(set);
   484 
   485 	return 0;
   486 }
   487 
   488 static int
   489 command_list_package_files(int argc, char * const argv[])
   490 {
   491 	struct razor_error *error = NULL;
   492 	struct razor_set *set;
   493 	struct razor_package_iterator *pi;
   494 	struct razor_package *package;
   495 	const char *name, *version, *arch;
   496 
   497 	switch (razor_getopt(argc, argv, 0, NULL, "pattern ...", NULL)) {
   498 		case -2:
   499 			return 0;
   500 		case -1:
   501 			return 1;
   502 	}
   503 
   504 	set = razor_root_open_read_only(install_root, &error);
   505 	if (set == NULL) {
   506 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   507 		razor_error_free(error);
   508 		return 1;
   509 	}
   510 
   511 	pi = create_iterator_from_argv(set, argc - optind, argv + optind);
   512 	while (razor_package_iterator_next(pi, &package,
   513 					   RAZOR_DETAIL_NAME, &name,
   514 					   RAZOR_DETAIL_VERSION, &version,
   515 					   RAZOR_DETAIL_ARCH, &arch,
   516 					   RAZOR_DETAIL_LAST))
   517 		razor_set_list_package_files(set, package);
   518 	razor_package_iterator_destroy(pi);
   519 
   520 	razor_set_unref(set);
   521 
   522 	return 0;
   523 }
   524 
   525 static int
   526 list_property_packages(const char *ref_name,
   527 		       const char *ref_version,
   528 		       uint32_t type)
   529 {
   530 	struct razor_error *error = NULL;
   531 	struct razor_set *set;
   532 	struct razor_property *property;
   533 	struct razor_property_iterator *prop_iter;
   534 	struct razor_package_iterator *pkg_iter;
   535 	const char *name, *version;
   536 	uint32_t flags;
   537 
   538 	set = razor_root_open_read_only(install_root, &error);
   539 	if (set == NULL) {
   540 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   541 		razor_error_free(error);
   542 		return 1;
   543 	}
   544 
   545 	prop_iter = razor_property_iterator_create(set, NULL);
   546 	while (razor_property_iterator_next(prop_iter, &property,
   547 					    &name, &flags, &version)) {
   548 		if (strcmp(ref_name, name) != 0)
   549 			continue;
   550 		if (ref_version &&
   551 		    (flags & RAZOR_PROPERTY_RELATION_MASK) == RAZOR_PROPERTY_EQUAL &&
   552 		    strcmp(ref_version, version) != 0)
   553 			continue;
   554 		if ((flags & RAZOR_PROPERTY_TYPE_MASK) != type)
   555 			continue;
   556 
   557 		pkg_iter =
   558 			razor_package_iterator_create_for_property(set,
   559 								   property);
   560 		list_packages(pkg_iter, 0);
   561 		razor_package_iterator_destroy(pkg_iter);
   562 	}
   563 	razor_property_iterator_destroy(prop_iter);
   564 
   565 	razor_set_unref(set);
   566 
   567 	return 0;
   568 }
   569 
   570 static int
   571 command_what_requires(int argc, char * const argv[])
   572 {
   573 	switch (razor_getopt(argc, argv, 0, NULL, "name [version-release]",
   574 			     NULL)) {
   575 		case -2:
   576 			return 0;
   577 		case -1:
   578 			return 1;
   579 	}
   580 
   581 	if (argc - optind < 1 || argc - optind > 2) {
   582 		razor_usage(argv[0], 0, NULL, "name [version-release]");
   583 		return 1;
   584 	}
   585 
   586 	return list_property_packages(argv[optind], argv[optind + 1],
   587 				      RAZOR_PROPERTY_REQUIRES);
   588 }
   589 
   590 static int
   591 command_what_provides(int argc, char * const argv[])
   592 {
   593 	switch (razor_getopt(argc, argv, 0, NULL, "name [version-release]",
   594 			     NULL)) {
   595 		case -2:
   596 			return 0;
   597 		case -1:
   598 			return 1;
   599 	}
   600 
   601 	if (argc - optind < 1 || argc - optind > 2) {
   602 		razor_usage(argv[0], 0, NULL, "name [version-release]");
   603 		return 1;
   604 	}
   605 
   606 	return list_property_packages(argv[optind], argv[optind + 1],
   607 				      RAZOR_PROPERTY_PROVIDES);
   608 }
   609 
   610 #ifdef HAVE_CURL
   611 static int
   612 show_progress(void *clientp,
   613 	      double dltotal, double dlnow, double ultotal, double ulnow)
   614 {
   615 	const char *file = clientp;
   616 
   617 	if (!dlnow < dltotal)
   618 		fprintf(stderr, "\rdownloading %s, %dkB/%dkB",
   619 			file, (int) dlnow / 1024, (int) dltotal / 1024);
   620 
   621 	return 0;
   622 }
   623 #endif	/* HAVE_CURL */
   624 
   625 static int
   626 download_if_missing(const char *url, const char *file)
   627 {
   628 #ifndef HAVE_CURL
   629 	return 1;
   630 #else
   631 	CURL *curl;
   632 	struct stat buf;
   633 	char error[256];
   634 	FILE *fp;
   635 	CURLcode res;
   636 	long response;
   637 
   638 	curl = curl_easy_init();
   639 	if (curl == NULL)
   640 		return 1;
   641 
   642 	curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error);
   643 	curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
   644 	curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, show_progress);
   645 	curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, file);
   646 
   647 	if (stat(file, &buf) < 0) {
   648 		fp = fopen(file, "wb");
   649 		if (fp == NULL) {
   650 			fprintf(stderr,
   651 				"failed to open %s for writing\n", file);
   652 			return -1;
   653 		}
   654 		curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
   655 		curl_easy_setopt(curl, CURLOPT_URL, url);
   656 		res = curl_easy_perform(curl);
   657 		fclose(fp);
   658 		if (res != CURLE_OK) {
   659 			fprintf(stderr, "curl error: %s\n", error);
   660 			unlink(file);
   661 			return -1;
   662 		}
   663 		res = curl_easy_getinfo(curl,
   664 					CURLINFO_RESPONSE_CODE, &response);
   665 		if (res != CURLE_OK) {
   666 			fprintf(stderr, "curl error: %s\n", error);
   667                         unlink(file);
   668                         return -1;
   669 		}
   670 		if (response != 200) {
   671 			fprintf(stderr, " - failed %ld\n", response);
   672                         unlink(file);
   673                         return -1;
   674 		}
   675 		fprintf(stderr, "\n");
   676 	}
   677 
   678 	curl_easy_cleanup(curl);
   679 
   680 	return 0;
   681 #endif	/* HAVE_CURL */
   682 }
   683 
   684 #define YUM_URL "http://download.fedora.redhat.com" \
   685 	"/pub/fedora/linux/development/i386/os"
   686 
   687 static int
   688 command_import_yum(int argc, char * const argv[])
   689 {
   690 	int retval;
   691 	struct razor_set *set;
   692 	struct razor_atomic *atomic;
   693 	char buffer[512];
   694 
   695 	switch (razor_getopt(argc, argv, 0, NULL, "", NULL)) {
   696 		case -2:
   697 			return 0;
   698 		case -1:
   699 			return 1;
   700 	}
   701 
   702 	if (argc - optind > 0) {
   703 		razor_usage(argv[0], 0, NULL, "");
   704 		return 1;
   705 	}
   706 
   707 	printf("downloading from %s.\n", yum_url);
   708 	snprintf(buffer, sizeof buffer,
   709 		 "%s/repodata/primary.xml.gz", yum_url);
   710 	if (download_if_missing(buffer, "primary.xml.gz") < 0)
   711 		return -1;
   712 	snprintf(buffer, sizeof buffer,
   713 		 "%s/repodata/filelists.xml.gz", yum_url);
   714 	if (download_if_missing(buffer, "filelists.xml.gz") < 0)
   715 		return -1;
   716 
   717 	set = razor_set_create_from_yum();
   718 	if (set == NULL)
   719 		return 1;
   720 	atomic = razor_atomic_open("Yum import repository");
   721 	razor_set_write(set, atomic, rawhide_repo_filename, RAZOR_SECTION_ALL);
   722 	retval = razor_atomic_commit(atomic);
   723 	razor_set_unref(set);
   724 	if (retval)
   725 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
   726 	else
   727 		printf("wrote %s\n", rawhide_repo_filename);
   728 	razor_atomic_destroy(atomic);
   729 
   730 	return retval;
   731 }
   732 
   733 #if HAVE_RPMLIB
   734 static int
   735 command_import_rpmdb(int argc, char * const argv[])
   736 {
   737 	struct razor_set *set;
   738 	struct razor_root *root;
   739 	struct razor_error *error = NULL;
   740 	struct razor_atomic *atomic;
   741 	int retval;
   742 
   743 	switch (razor_getopt(argc, argv, 0, NULL, "", NULL)) {
   744 		case -2:
   745 			return 0;
   746 		case -1:
   747 			return 1;
   748 	}
   749 
   750 	if (argc - optind > 0) {
   751 		razor_usage(argv[0], 0, NULL, "");
   752 		return 1;
   753 	}
   754 
   755 	root = razor_root_open(install_root, &error);
   756 	if (root == NULL) {
   757 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   758 		razor_error_free(error);
   759 		return 1;
   760 	}
   761 
   762 	set = razor_set_create_from_rpmdb();
   763 	if (set == NULL)
   764 		return 1;
   765 
   766 	atomic = razor_atomic_open("Import RPM database");
   767 
   768 	retval = razor_root_update(root, set, atomic);
   769 
   770 	if (retval)
   771 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
   772 
   773 	razor_atomic_destroy(atomic);
   774 
   775 	razor_root_close(root);
   776 
   777 	return retval;
   778 }
   779 #endif
   780 
   781 static int
   782 mark_packages_for_update(struct razor_transaction *trans,
   783 			 struct razor_set *set, const char *pattern)
   784 {
   785 	struct razor_package_iterator *pi;
   786 	struct razor_package *package;
   787 	const char *name;
   788 	int matches = 0;
   789 
   790 	pi = razor_package_iterator_create(set);
   791 	while (razor_package_iterator_next(pi, &package,
   792 					   RAZOR_DETAIL_NAME, &name,
   793 					   RAZOR_DETAIL_LAST)) {
   794 		if (pattern && fnmatch(pattern, name, 0) == 0) {
   795 			razor_transaction_update_package(trans, package);
   796 			matches++;
   797 		}
   798 	}
   799 	razor_package_iterator_destroy(pi);
   800 
   801 	return matches;
   802 }
   803 
   804 static int
   805 mark_packages_for_removal(struct razor_transaction *trans,
   806 			  struct razor_set *set, const char *pattern)
   807 {
   808 	struct razor_package_iterator *pi;
   809 	struct razor_package *package;
   810 	const char *name;
   811 	int matches = 0;
   812 
   813 	pi = razor_package_iterator_create(set);
   814 	while (razor_package_iterator_next(pi, &package,
   815 					   RAZOR_DETAIL_NAME, &name,
   816 					   RAZOR_DETAIL_LAST)) {
   817 		if (pattern && fnmatch(pattern, name, 0) == 0) {
   818 			razor_transaction_remove_package(trans, package);
   819 			matches++;
   820 		}
   821 	}
   822 	razor_package_iterator_destroy(pi);
   823 
   824 	return matches;
   825 }
   826 
   827 static int
   828 command_remove(int argc, char * const argv[])
   829 {
   830 	struct razor_set *system, *upstream, *next;
   831 	struct razor_transaction *trans;
   832 	struct razor_error *error = NULL;
   833 	struct razor_root *root;
   834 	int i, retval;
   835 
   836 	switch (razor_getopt(argc, argv, 0, NULL, "pattern ...", NULL)) {
   837 		case -2:
   838 			return 0;
   839 		case -1:
   840 			return 1;
   841 	}
   842 
   843 	root = razor_root_open(install_root, &error);
   844 	if (root == NULL) {
   845 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   846 		razor_error_free(error);
   847 		return 1;
   848 	}
   849 
   850 	system = razor_root_get_system_set(root);
   851 	upstream = razor_set_create_without_root();
   852 	trans = razor_transaction_create(system, upstream);
   853 	razor_set_unref(upstream);
   854 	for (i = optind; i < argc; i++) {
   855 		if (mark_packages_for_removal(trans, system, argv[i]) == 0) {
   856 			fprintf(stderr, "no match for %s\n", argv[i]);
   857 			razor_transaction_destroy(trans);
   858 			razor_root_close(root);
   859 			return 1;
   860 		}
   861 	}
   862 
   863 	razor_transaction_resolve(trans);
   864 	retval = razor_transaction_describe(trans);
   865 	if (retval) {
   866 		razor_transaction_destroy(trans);
   867 		razor_root_close(root);
   868 		return 1;
   869 	}
   870 
   871 	next = razor_transaction_commit(trans);
   872 
   873 	retval = update_system(root, NULL, trans, next, "Remove");
   874 
   875 	razor_transaction_destroy(trans);
   876 	razor_root_close(root);
   877 	razor_set_unref(next);
   878 
   879 	return retval;
   880 }
   881 
   882 static void
   883 print_diff(enum razor_diff_action action,
   884 	   struct razor_package *package,
   885 	   const char *name,
   886 	   const char *version,
   887 	   const char *arch,
   888 	   void *data)
   889 {
   890 	if (action == RAZOR_DIFF_ACTION_ADD)
   891 		printf("install %s-%s.%s\n", name, version, arch);
   892 	if (action == RAZOR_DIFF_ACTION_REMOVE)
   893 		printf("remove %s-%s.%s\n", name, version, arch);
   894 }
   895 
   896 static int
   897 command_diff(int argc, char * const argv[])
   898 {
   899 	struct razor_error *error = NULL;
   900 	struct razor_set *set, *updated;
   901 
   902 	switch (razor_getopt(argc, argv, 0, NULL, "", NULL)) {
   903 		case -2:
   904 			return 0;
   905 		case -1:
   906 			return 1;
   907 	}
   908 
   909 	if (argc - optind > 0) {
   910 		razor_usage(argv[0], 0, NULL, "");
   911 		return 1;
   912 	}
   913 
   914 	set = razor_root_open_read_only(install_root, &error);
   915 	if (set)
   916 		updated = razor_set_open(rawhide_repo_filename, 0, &error);
   917 	else
   918 		updated = NULL;
   919 	if (updated == NULL) {
   920 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   921 		razor_error_free(error);
   922 		if (set)
   923 			razor_set_unref(set);
   924 		return 1;
   925 	}
   926 
   927 	razor_set_diff(set, updated, print_diff, NULL);
   928 
   929 	razor_set_unref(set);
   930 	razor_set_unref(updated);
   931 
   932 	return 0;
   933 }
   934 
   935 static int
   936 command_import_rpms(int argc, char * const argv[])
   937 {
   938 	DIR *dir;
   939 	struct dirent *de;
   940 	struct razor_importer *importer;
   941 	struct razor_set *set;
   942 	struct razor_rpm *rpm;
   943 	struct razor_error *error=NULL;
   944 	struct razor_atomic *atomic;
   945 	int len, imported_count = 0;
   946 	char filename[256];
   947 	const char *dirname;
   948 	int retval;
   949 
   950 	switch (razor_getopt(argc, argv, 0, NULL, "dir", NULL)) {
   951 		case -2:
   952 			return 0;
   953 		case -1:
   954 			return 1;
   955 	}
   956 
   957 	if (argc - optind != 1) {
   958 		razor_usage(argv[0], 0, NULL, "dir");
   959 		return 1;
   960 	}
   961 
   962 	dirname = argv[optind];
   963 
   964 	dir = opendir(dirname);
   965 	if (dir == NULL) {
   966 		fprintf(stderr, "couldn't read dir %s\n", dirname);
   967 		return -1;
   968 	}
   969 
   970 	importer = razor_importer_create();
   971 
   972 	while (de = readdir(dir), de != NULL) {
   973 		len = strlen(de->d_name);
   974 		if (len < 5 || strcmp(de->d_name + len - 4, ".rpm") != 0)
   975 			continue;
   976 		snprintf(filename, sizeof filename,
   977 			 "%s/%s", dirname, de->d_name);
   978 		rpm = razor_rpm_open(filename, &error);
   979 		if (rpm == NULL) {
   980 			fprintf(stderr, "%s\n", razor_error_get_msg(error));
   981 			razor_error_free(error);
   982 			error=NULL;
   983 			continue;
   984 		}
   985 		if (razor_importer_add_rpm(importer, rpm)) {
   986 			fprintf(stderr, "couldn't import %s\n", filename);
   987 			break;
   988 		}
   989 		razor_rpm_close(rpm);
   990 
   991 		printf("\rimporting %d", ++imported_count);
   992 		fflush(stdout);
   993 	}
   994 
   995 	if (de != NULL) {
   996 		razor_importer_destroy(importer);
   997 		return -1;
   998 	}
   999 
  1000 	printf("\nsaving\n");
  1001 	set = razor_importer_finish(importer);
  1002 
  1003 	atomic = razor_atomic_open("Update system database");
  1004 	razor_set_write(set, atomic, repo_filename, RAZOR_SECTION_ALL);
  1005 	razor_set_unref(set);
  1006 	retval = razor_atomic_commit(atomic);
  1007 	if (retval)
  1008 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  1009 	else
  1010 		printf("wrote %s\n", repo_filename);
  1011 	razor_atomic_destroy(atomic);
  1012 
  1013 	return retval;
  1014 }
  1015 
  1016 static char *
  1017 rpm_filename(const char *name, const char *version, const char *arch)
  1018 {
  1019  	const char *v;
  1020  
  1021  	/* Skip epoch */
  1022 	v = strchr(version, ':');
  1023  	if (v != NULL)
  1024  		v = v + 1;
  1025  	else
  1026 		v = version;
  1027 
  1028 	return razor_concat(name, "-", v, ".", arch, ".rpm", NULL);
  1029 }
  1030 
  1031 static int
  1032 download_packages(struct razor_set *system, struct razor_set *next)
  1033 {
  1034 	struct razor_install_iterator *ii;
  1035 	struct razor_package *package;
  1036 	enum razor_install_action action;
  1037 	const char *name, *version, *arch;
  1038 	char *file, *url, *s;
  1039 	int errors = 0, count;
  1040 
  1041 	ii = razor_set_create_install_iterator(system, next);
  1042 	while (razor_install_iterator_next(ii, &package, &action, &count)) {
  1043 		if (action != RAZOR_INSTALL_ACTION_ADD)
  1044 			continue;
  1045 
  1046 		razor_package_get_details(next, package,
  1047 					  RAZOR_DETAIL_NAME, &name,
  1048 					  RAZOR_DETAIL_VERSION, &version,
  1049 					  RAZOR_DETAIL_ARCH, &arch,
  1050 					  RAZOR_DETAIL_LAST);
  1051 		
  1052 		s = rpm_filename(name, version, arch);
  1053 		url = razor_concat(yum_url, "/Packages/", s, NULL);
  1054 		file = razor_concat("rpms/", s, NULL);
  1055 		free(s);
  1056 		if (download_if_missing(url, file) < 0)
  1057 			errors++;
  1058 		free(file);
  1059 		free(url);
  1060 	}
  1061 	razor_install_iterator_destroy(ii);
  1062 
  1063 	if (errors > 0) {
  1064 		fprintf(stderr, "failed to download %d packages\n", errors);
  1065                 return -1;
  1066         }
  1067 
  1068 	return 0;
  1069 }
  1070 
  1071 static struct razor_set *
  1072 relocate_packages(struct razor_set *set, struct razor_atomic *atomic,
  1073 		  struct razor_relocations *relocations)
  1074 {
  1075 	int i;
  1076 	struct razor_importer *importer;
  1077 	struct razor_property_iterator *prop_iter;
  1078 	struct razor_package_iterator *pkg_iter;
  1079  	struct razor_file_iterator *file_iter;
  1080  	struct razor_package *package;
  1081 	struct razor_property *property;
  1082 	struct razor_rpm *rpm;
  1083 	struct razor_error *error=NULL;
  1084 	const char *name, *version, *arch, *summary, *desc, *url, *license;
  1085 	const char *preunprog, *preun, *postunprog, *postun;
  1086 	const char *install_prefix;
  1087 	const char *const *prefixes;
  1088 	char *file, *s;
  1089 	uint32_t flags;
  1090 
  1091 	importer = razor_importer_create();
  1092 	pkg_iter = razor_package_iterator_create(set);
  1093 
  1094 	while (razor_package_iterator_next(pkg_iter, &package,
  1095 					   RAZOR_DETAIL_NAME, &name,
  1096 					   RAZOR_DETAIL_VERSION, &version,
  1097 					   RAZOR_DETAIL_ARCH, &arch,
  1098 					   RAZOR_DETAIL_SUMMARY, &summary,
  1099 					   RAZOR_DETAIL_DESCRIPTION, &desc,
  1100 					   RAZOR_DETAIL_URL, &url,
  1101 					   RAZOR_DETAIL_LICENSE, &license,
  1102 					   RAZOR_DETAIL_PREUNPROG, &preunprog,
  1103 					   RAZOR_DETAIL_PREUN, &preun,
  1104 					   RAZOR_DETAIL_POSTUNPROG, &postunprog,
  1105 					   RAZOR_DETAIL_POSTUN, &postun,
  1106 					   RAZOR_DETAIL_LAST)) {
  1107 		s = rpm_filename(name, version, arch);
  1108 		file = razor_concat("rpms/", s, NULL);
  1109 		free(s);
  1110 		rpm = razor_rpm_open(file, &error);
  1111 		free(file);
  1112 		if (rpm == NULL) {
  1113 			razor_atomic_abort(atomic, razor_error_get_msg(error));
  1114 			razor_error_free(error);
  1115 			razor_package_iterator_destroy(pkg_iter);
  1116 			razor_importer_destroy(importer);
  1117 			return NULL;
  1118 		}
  1119 
  1120 		razor_relocations_set_rpm(relocations, rpm);
  1121 
  1122 		razor_importer_begin_package(importer, name, version, arch);
  1123 		razor_importer_add_details(importer,
  1124 					   summary, desc, url, license);
  1125 
  1126 		razor_rpm_get_details(rpm, RAZOR_DETAIL_PREFIXES, &prefixes,
  1127 				      RAZOR_DETAIL_LAST);
  1128 		for (i = 0; prefixes && prefixes[i]; i++) {
  1129 			install_prefix = razor_relocations_apply(relocations,
  1130 								 prefixes[i]);
  1131 			razor_importer_add_install_prefix(importer,
  1132 							  install_prefix);
  1133 		}
  1134 
  1135 		razor_rpm_close(rpm);
  1136 
  1137 		prop_iter = razor_property_iterator_create(set, package);
  1138 		while (razor_property_iterator_next(prop_iter, &property,
  1139 						    &name, &flags, &version))
  1140 			razor_importer_add_property(importer,
  1141 						    name, flags, version);
  1142 		razor_property_iterator_destroy(prop_iter);
  1143 
  1144 		file_iter = razor_file_iterator_create(set, package, 0);
  1145 		while (razor_file_iterator_next(file_iter, &name)) {
  1146 			name = razor_relocations_apply(relocations, name);
  1147 			razor_importer_add_file(importer, name);
  1148 		}
  1149 		razor_file_iterator_destroy(file_iter);
  1150 
  1151 		razor_importer_add_script(importer, RAZOR_PROPERTY_PREUN,
  1152 					  preunprog, preun);
  1153 		razor_importer_add_script(importer, RAZOR_PROPERTY_POSTUN,
  1154 					  postunprog, postun);
  1155 
  1156 		razor_importer_finish_package(importer);
  1157 	}
  1158 
  1159 	razor_package_iterator_destroy(pkg_iter);
  1160 	return razor_importer_finish(importer);
  1161 }
  1162 
  1163 static int
  1164 install_package(struct razor_transaction *trans, struct razor_set *set,
  1165 		struct razor_atomic *atomic, struct razor_package *package,
  1166 		struct razor_relocations *relocations, int install_count,
  1167 		enum razor_stage_type stage)
  1168 {
  1169 	int retval;
  1170 	const char *name, *version, *arch;
  1171 	char *file, *s;
  1172 	struct razor_rpm *rpm;
  1173 	struct razor_error *error=NULL;
  1174 
  1175 	razor_package_get_details(set, package,
  1176 				  RAZOR_DETAIL_NAME, &name,
  1177 				  RAZOR_DETAIL_VERSION, &version,
  1178 				  RAZOR_DETAIL_ARCH, &arch,
  1179 				  RAZOR_DETAIL_LAST);
  1180 
  1181 	if (stage & RAZOR_STAGE_SCRIPTS_PRE)
  1182 		printf("install %s-%s\n", name, version);
  1183 
  1184 	s = rpm_filename(name, version, arch);
  1185 	file = razor_concat("rpms/", s, NULL);
  1186 	free(s);
  1187 	rpm = razor_rpm_open(file, &error);
  1188 	free(file);
  1189 	if (rpm == NULL) {
  1190 		razor_atomic_abort(atomic, razor_error_get_msg(error));
  1191 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1192 		razor_error_free(error);
  1193 		return -1;
  1194 	}
  1195 	if (relocations)
  1196 		razor_rpm_set_relocations(rpm, relocations);
  1197 	razor_transaction_fixup_package(trans, package, rpm);
  1198 	retval = razor_rpm_install(rpm, atomic, install_root, install_count,
  1199 				   stage);
  1200 	if (retval < 0) {
  1201 		s = rpm_filename(name, version, arch);
  1202 		fprintf(stderr, "%s: %s\n", s,
  1203 			razor_atomic_get_error_msg(atomic));
  1204 		free(s);
  1205 	}
  1206 	razor_rpm_close(rpm);
  1207 	return retval;
  1208 }
  1209 
  1210 /*
  1211  * Returns 0 on success, -1 on failure and 1 if a RAZOR_INSTALL_ACTION_COMMIT
  1212  * is met (in which case the action is consumed).
  1213  */
  1214 static int
  1215 update_packages(struct razor_transaction *trans,
  1216 		struct razor_install_iterator *ii, struct razor_set *system,
  1217 		struct razor_set *next, struct razor_atomic *atomic,
  1218 		struct razor_relocations *relocations,
  1219 		enum razor_stage_type stage)
  1220 {
  1221 	struct razor_package *package;
  1222 	enum razor_install_action action;
  1223 	int retval = 0, count;
  1224 
  1225 	while (!retval && razor_install_iterator_next(ii, &package, &action,
  1226 						      &count)) {
  1227 		if (action == RAZOR_INSTALL_ACTION_ADD) {
  1228 			if (install_package(trans, next, atomic, package,
  1229 					    relocations, count, stage))
  1230 				retval = -1;
  1231 		} else if (action == RAZOR_INSTALL_ACTION_REMOVE) {
  1232 			if (razor_package_remove(system, next, atomic, package,
  1233 						 install_root, count, stage))
  1234 				retval = -1;
  1235 		} else if (action == RAZOR_INSTALL_ACTION_COMMIT)
  1236 				retval = 1;
  1237 	}
  1238 
  1239 	return retval;
  1240 }
  1241 
  1242 static int
  1243 update_system(struct razor_root *root, struct razor_relocations *relocations,
  1244 	      struct razor_transaction *trans, struct razor_set *next,
  1245 	      const char *verb)
  1246 {
  1247 	struct razor_set *system, *set;
  1248 	struct razor_atomic *atomic;
  1249 	struct razor_install_iterator *ii;
  1250 	int r, retval = 0;
  1251 	char *description;
  1252 	size_t pos;
  1253 
  1254 	description = razor_concat(verb, " packages", NULL);
  1255 
  1256 	system = razor_set_ref(razor_root_get_system_set(root));
  1257 
  1258 	ii = razor_set_create_install_iterator(system, next);
  1259 
  1260 	do {
  1261 		pos = razor_install_iterator_tell(ii);
  1262 
  1263 		atomic = razor_atomic_open(description);
  1264 
  1265 		r = update_packages(trans, ii, system, next, atomic,
  1266 				    relocations, RAZOR_STAGE_SCRIPTS_PRE);
  1267 		if (r < 0) {
  1268 			fprintf(stderr, "%s aborted\n", verb);
  1269 			retval = r;
  1270 		} else {
  1271 			razor_install_iterator_seek(ii, pos);
  1272 			r = update_packages(trans, ii, system, next, atomic,
  1273 					    relocations, RAZOR_STAGE_FILES);
  1274 
  1275 			if (r == 1) {
  1276 				set = razor_install_iterator_commit_set(ii);
  1277 				razor_root_update(root, set, atomic);
  1278 				razor_set_unref(set);
  1279 			} else if (r == 0)
  1280 				razor_root_update(root, next, atomic);
  1281 
  1282 			retval = razor_atomic_commit(atomic);
  1283 			if (retval)
  1284 				fprintf(stderr, "%s\n",
  1285 					razor_atomic_get_error_msg(atomic));
  1286 			else {
  1287 				razor_install_iterator_seek(ii, pos);
  1288 				update_packages(trans, ii, system, next,
  1289 						atomic, relocations,
  1290 						RAZOR_STAGE_SCRIPTS_POST);
  1291 			}
  1292 		}
  1293 
  1294 		razor_atomic_destroy(atomic);
  1295 	} while(!retval && r == 1);
  1296 
  1297 	razor_set_unref(system);
  1298 
  1299 	free(description);
  1300 
  1301 	return retval;
  1302 }
  1303 
  1304 static int
  1305 command_install_or_update(int argc, char * const argv[], int do_update)
  1306 {
  1307 	struct razor_relocations *relocations = NULL;
  1308 	struct razor_set *system, *upstream, *next, *set;
  1309 	struct razor_transaction *trans;
  1310 	struct razor_error *error = NULL;
  1311 	struct razor_atomic *atomic;
  1312 	struct razor_root *root;
  1313 	int opt, i, retval = 0, len, dependencies = 1;
  1314 	char *oldpath;
  1315 	const char *arg;
  1316 	enum {
  1317 		opt_no_dependencies = 1,
  1318 		opt_relocate = 2,
  1319 	};
  1320 	static struct razor_option options[] = {
  1321 		{ .name = "no-dependencies", .has_arg = no_argument,
  1322 		  .val = opt_no_dependencies,
  1323 		  .description = "Do not verify package dependencies" },
  1324 		{ .name = "relocate", .has_arg = required_argument,
  1325 		  .val = opt_relocate,
  1326 		  .description = "Relocate files from path OLD to NEW",
  1327 		  .arg_description = "OLD=NEW" },
  1328 	};
  1329 
  1330 	do {
  1331 		opt = razor_getopt(argc, argv, ARRAY_SIZE(options), options,
  1332 				   "rpm ...", &arg);
  1333 		switch (opt) {
  1334 			case -2:
  1335 				return 0;
  1336 			case -1:
  1337 				return 1;
  1338 			case opt_no_dependencies:
  1339 				dependencies = 0;
  1340 				break;
  1341 			case opt_relocate:
  1342 				if (strchr(arg, '=') == NULL) {
  1343 					razor_usage(argv[0],
  1344 						    ARRAY_SIZE(options),
  1345 						    options, "rpm ...");
  1346 					return 1;
  1347 				}
  1348 				len = strchr(arg, '=') - arg;
  1349 				oldpath = malloc(len + 1);
  1350 				strncpy(oldpath, arg, len);
  1351 				oldpath[len] = '\0';
  1352 				if (!relocations)
  1353 				       relocations = razor_relocations_create();
  1354 				razor_relocations_add(relocations, oldpath,
  1355 						      arg + len + 1);
  1356 				free(oldpath);
  1357 				break;
  1358 		}
  1359 	} while (opt);
  1360 
  1361 	upstream = razor_set_open(rawhide_repo_filename, 0, &error);
  1362 	if (upstream == NULL) {
  1363 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1364 		razor_error_free(error);
  1365 		return 1;
  1366 	}
  1367 
  1368 	if (do_update)
  1369 		atomic = razor_atomic_open("Update packages");
  1370 	else
  1371 		atomic = razor_atomic_open("Install packages");
  1372 
  1373 	if (relocations) {
  1374 		set = relocate_packages(upstream, atomic, relocations);
  1375 		if (set == NULL) {
  1376 			fprintf(stderr, "%s\n",
  1377 				razor_atomic_get_error_msg(atomic));
  1378 			razor_atomic_destroy(atomic);
  1379 			razor_set_unref(upstream);
  1380 			return 1;
  1381 		}
  1382 		razor_set_unref(upstream);
  1383 		upstream = set;
  1384 	}
  1385 
  1386 	root = razor_root_open(install_root, &error);
  1387 	if (root == NULL) {
  1388 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1389 		razor_error_free(error);
  1390 		razor_atomic_destroy(atomic);
  1391 		razor_set_unref(upstream);
  1392 		if (relocations)
  1393 			razor_relocations_destroy(relocations);
  1394 		return 1;
  1395 	}
  1396 
  1397 	system = razor_root_get_system_set(root);
  1398 	trans = razor_transaction_create(system, upstream);
  1399 
  1400 	if (optind == argc && do_update)
  1401 		razor_transaction_update_all(trans);
  1402 	for (i = optind; i < argc; i++) {
  1403 		if (do_update &&
  1404 		    mark_packages_for_update(trans, system, argv[i]))
  1405 			continue;
  1406 		if (mark_packages_for_update(trans, upstream, argv[i]) == 0) {
  1407 			fprintf(stderr, "no package matched %s\n", argv[i]);
  1408 			razor_transaction_destroy(trans);
  1409 			razor_root_close(root);
  1410 			razor_set_unref(upstream);
  1411 			razor_atomic_destroy(atomic);
  1412 			if (relocations)
  1413 				razor_relocations_destroy(relocations);
  1414 			return 1;
  1415 		}
  1416 	}
  1417 
  1418 	if (dependencies) {
  1419 		razor_transaction_resolve(trans);
  1420 		if (razor_transaction_describe(trans) > 0) {
  1421 			razor_transaction_destroy(trans);
  1422 			razor_set_unref(upstream);
  1423 			razor_root_close(root);
  1424 			razor_atomic_destroy(atomic);
  1425 			if (relocations)
  1426 				razor_relocations_destroy(relocations);
  1427 			return 1;
  1428 		}
  1429 	}
  1430 
  1431 	if (razor_atomic_create_dir(atomic, "rpms",
  1432 				    S_IRWXU | S_IRWXG | S_IRWXO) ||
  1433 	    razor_atomic_commit(atomic)) {
  1434 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  1435 		razor_transaction_destroy(trans);
  1436 		razor_set_unref(upstream);
  1437 		razor_root_close(root);
  1438 		razor_atomic_destroy(atomic);
  1439 		if (relocations)
  1440 			razor_relocations_destroy(relocations);
  1441 		return 1;
  1442 	}
  1443 
  1444 	razor_atomic_destroy(atomic);
  1445 
  1446 	next = razor_transaction_commit(trans);
  1447 
  1448 	if (download_packages(system, next) < 0) {
  1449 		razor_set_unref(next);
  1450 		razor_transaction_destroy(trans);
  1451 		razor_set_unref(upstream);
  1452 		razor_root_close(root);
  1453 		razor_atomic_destroy(atomic);
  1454 		if (relocations)
  1455 			razor_relocations_destroy(relocations);
  1456                 return 1;
  1457         }
  1458 
  1459 	retval = update_system(root, relocations, trans, next,
  1460 			       do_update ? "Update" : "Install");
  1461 
  1462 	razor_set_unref(upstream);
  1463 	razor_root_close(root);
  1464 
  1465 	razor_transaction_destroy(trans);
  1466 	if (relocations)
  1467 		razor_relocations_destroy(relocations);
  1468 
  1469 	razor_set_unref(next);
  1470 
  1471 	return retval;
  1472 }
  1473 
  1474 static int
  1475 command_update(int argc, char * const argv[])
  1476 {
  1477 	return command_install_or_update(argc, argv, 1);
  1478 }
  1479 
  1480 static int
  1481 command_install(int argc, char * const argv[])
  1482 {
  1483 	return command_install_or_update(argc, argv, 0);
  1484 }
  1485 
  1486 static int
  1487 command_init(int argc, char * const argv[])
  1488 {
  1489 	int retval;
  1490 	struct razor_error *error = NULL;
  1491 
  1492 	switch (razor_getopt(argc, argv, 0, NULL, "", NULL)) {
  1493 		case -2:
  1494 			return 0;
  1495 		case -1:
  1496 			return 1;
  1497 	}
  1498 
  1499 	if (argc - optind > 0) {
  1500 		razor_usage(argv[0], 0, NULL, "");
  1501 		return 1;
  1502 	}
  1503 
  1504 	retval = razor_root_create(install_root, &error);
  1505 	if (retval) {
  1506 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1507 		razor_error_free(error);
  1508 	} else
  1509 		printf("Created install root\n");
  1510 
  1511 	return retval;
  1512 }
  1513 
  1514 static int
  1515 command_download(int argc, char * const argv[])
  1516 {
  1517 	struct razor_error *error = NULL;
  1518 	struct razor_atomic *atomic;
  1519 	struct razor_set *set;
  1520 	struct razor_package_iterator *pi;
  1521 	struct razor_package *package;
  1522 	const char *pattern, *name, *version, *arch;
  1523 	char url[256], file[256];
  1524 	int matches = 0;
  1525 
  1526 	switch (razor_getopt(argc, argv, 0, NULL, "[pattern]", NULL)) {
  1527 		case -2:
  1528 			return 0;
  1529 		case -1:
  1530 			return 1;
  1531 	}
  1532 
  1533 	if (argc - optind > 1) {
  1534 		razor_usage(argv[0], 0, NULL, "[pattern]");
  1535 		return 1;
  1536 	}
  1537 
  1538 	pattern = argv[optind];
  1539 
  1540 	set = razor_set_open(rawhide_repo_filename, 0, &error);
  1541 	if (set == NULL) {
  1542 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1543 		razor_error_free(error);
  1544 		return 1;
  1545 	}
  1546 
  1547 	atomic = razor_atomic_open("Download packages");
  1548 
  1549 	if (razor_atomic_create_dir(atomic, "rpms", 
  1550 				    S_IRWXU | S_IRWXG | S_IRWXO)) {
  1551 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  1552 		razor_atomic_destroy(atomic);
  1553 		return 1;
  1554 	}
  1555 
  1556 	if (razor_atomic_commit(atomic)) {
  1557 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  1558 		razor_atomic_destroy(atomic);
  1559 		return 1;
  1560 	}
  1561 	razor_atomic_destroy(atomic);
  1562 
  1563 	pi = razor_package_iterator_create(set);
  1564 	while (razor_package_iterator_next(pi, &package,
  1565 					   RAZOR_DETAIL_NAME, &name,
  1566 					   RAZOR_DETAIL_VERSION, &version,
  1567 					   RAZOR_DETAIL_ARCH, &arch,
  1568 					   RAZOR_DETAIL_LAST)) {
  1569 		if (pattern && fnmatch(pattern, name, 0) != 0)
  1570 			continue;
  1571 
  1572 		matches++;
  1573 		snprintf(url, sizeof url,
  1574 			 "%s/Packages/%s-%s.%s.rpm",
  1575 			 yum_url, name, version, arch);
  1576 		snprintf(file, sizeof file,
  1577 			 "rpms/%s-%s.%s.rpm", name, version, arch);
  1578 		download_if_missing(url, file);
  1579 	}
  1580 	razor_package_iterator_destroy(pi);
  1581 	razor_set_unref(set);
  1582 
  1583 	if (matches == 0)
  1584 		fprintf(stderr, "no packages matched \"%s\"\n", pattern);
  1585 	else if (matches == 1)
  1586 		fprintf(stderr, "downloaded 1 package\n");
  1587 	else
  1588 		fprintf(stderr, "downloaded %d packages\n", matches);
  1589 
  1590 	return 0;
  1591 }
  1592 
  1593 static int
  1594 command_info(int argc, char * const argv[])
  1595 {
  1596 	struct razor_error *error = NULL;
  1597 	struct razor_set *set;
  1598 	struct razor_package_iterator *pi;
  1599 	struct razor_package *package;
  1600 	const char *pattern, *name, *version, *arch;
  1601 	const char *summary, *description, *url, *license;
  1602 
  1603 	switch (razor_getopt(argc, argv, 0, NULL, "[pattern]", NULL)) {
  1604 		case -2:
  1605 			return 0;
  1606 		case -1:
  1607 			return 1;
  1608 	}
  1609 
  1610 	if (argc - optind > 1) {
  1611 		razor_usage(argv[0], 0, NULL, "[pattern]");
  1612 		return 1;
  1613 	}
  1614 
  1615 	pattern = argv[optind];
  1616 
  1617 	set = razor_root_open_read_only(install_root, &error);
  1618 	if (set == NULL) {
  1619 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1620 		razor_error_free(error);
  1621 		return 1;
  1622 	}
  1623 
  1624 	pi = razor_package_iterator_create(set);
  1625 	while (razor_package_iterator_next(pi, &package,
  1626 					   RAZOR_DETAIL_NAME, &name,
  1627 					   RAZOR_DETAIL_VERSION, &version,
  1628 					   RAZOR_DETAIL_ARCH, &arch,
  1629 					   RAZOR_DETAIL_LAST)) {
  1630 		if (pattern && fnmatch(pattern, name, 0) != 0)
  1631 			continue;
  1632 
  1633 		razor_package_get_details (set, package,
  1634 					   RAZOR_DETAIL_SUMMARY, &summary,
  1635 					   RAZOR_DETAIL_DESCRIPTION, &description,
  1636 					   RAZOR_DETAIL_URL, &url,
  1637 					   RAZOR_DETAIL_LICENSE, &license,
  1638 					   RAZOR_DETAIL_LAST);
  1639 
  1640 		printf ("Name:        %s\n", name);
  1641 		printf ("Arch:        %s\n", arch);
  1642 		printf ("Version:     %s\n", version);
  1643 		printf ("URL:         %s\n", url);
  1644 		printf ("License:     %s\n", license);
  1645 		printf ("Summary:     %s\n", summary);
  1646 		printf ("Description:\n");
  1647 		printf ("%s\n", description);
  1648 		printf ("\n");
  1649 	}
  1650 	razor_package_iterator_destroy(pi);
  1651 	razor_set_unref(set);
  1652 
  1653 	return 0;
  1654 }
  1655 
  1656 #define SEARCH_MAX 256
  1657 
  1658 static int
  1659 command_search(int argc, char * const argv[])
  1660 {
  1661 	struct razor_error *error = NULL;
  1662 	struct razor_set *set;
  1663 	struct razor_package_iterator *pi;
  1664 	struct razor_package *package;
  1665 	char pattern[SEARCH_MAX];
  1666 	const char *name, *version, *arch;
  1667 	const char *summary, *description, *url, *license;
  1668 
  1669 	switch (razor_getopt(argc, argv, 0, NULL, "pattern", NULL)) {
  1670 		case -2:
  1671 			return 0;
  1672 		case -1:
  1673 			return 1;
  1674 	}
  1675 
  1676 	if (argc != 2) {
  1677 		razor_usage(argv[0], 0, NULL, "pattern");
  1678 		return 1;
  1679 	}
  1680 
  1681 	snprintf(pattern, sizeof pattern, "*%s*", argv[1]);
  1682 
  1683 	set = razor_set_open(rawhide_repo_filename, 0, &error);
  1684 	if (set == NULL) {
  1685 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1686 		razor_error_free(error);
  1687 		return 1;
  1688 	}
  1689 
  1690 	pi = razor_package_iterator_create(set);
  1691 	while (razor_package_iterator_next(pi, &package,
  1692 					   RAZOR_DETAIL_NAME, &name,
  1693 					   RAZOR_DETAIL_VERSION, &version,
  1694 					   RAZOR_DETAIL_ARCH, &arch,
  1695 					   RAZOR_DETAIL_SUMMARY, &summary,
  1696 					   RAZOR_DETAIL_DESCRIPTION, &description,
  1697 					   RAZOR_DETAIL_URL, &url,
  1698 					   RAZOR_DETAIL_LICENSE, &license,
  1699 					   RAZOR_DETAIL_LAST)) {
  1700 		if (!fnmatch(pattern, name, FNM_CASEFOLD) ||
  1701 		    !fnmatch(pattern, url, FNM_CASEFOLD) ||
  1702 		    !fnmatch(pattern, summary, FNM_CASEFOLD) ||
  1703 		    !fnmatch(pattern, description, FNM_CASEFOLD))
  1704 			printf("%s-%s.%s: %s\n", name, version, arch, summary);
  1705 	}
  1706 	razor_package_iterator_destroy(pi);
  1707 	razor_set_unref(set);
  1708 
  1709 	return 0;
  1710 }
  1711 
  1712 static struct {
  1713 	const char *name;
  1714 	const char *description;
  1715 	int (*func)(int argc, char * const argv[]);
  1716 } razor_commands[] = {
  1717 	{ "diff", "Show diff between two package sets", command_diff },
  1718 	{ "download", "Download packages", command_download },
  1719 	{ "help", "List available commands", command_help },
  1720 #if HAVE_RPMLIB
  1721 	{ "import-rpmdb", "Import the system rpm database",
  1722 	  command_import_rpmdb },
  1723 #endif
  1724 	{ "import-rpms", "Import rpms from the given directory",
  1725 	  command_import_rpms },
  1726 	{ "import-yum", "Import yum metadata files", command_import_yum },
  1727 	{ "info", "Display package details", command_info },
  1728 	{ "init", "Init razor root", command_init },
  1729 	{ "install", "Install rpm", command_install },
  1730 	{ "list", "List all packages", command_list },
  1731 	{ "list-conflicts", "List all conflicts for the given package",
  1732 	  command_list_conflicts },
  1733 	{ "list-file-packages", "List packages owning file",
  1734 	  command_list_file_packages },
  1735 	{ "list-files", "List files for package set", command_list_files },
  1736 	{ "list-obsoletes", "List all obsoletes for the given package",
  1737 	  command_list_obsoletes },
  1738 	{ "list-package-files", "List files in package",
  1739 	  command_list_package_files },
  1740 	{ "list-provides", "List all provides for the given package",
  1741 	  command_list_provides },
  1742 	{ "list-requires", "List all requires for the given package",
  1743 	  command_list_requires },
  1744 	{ "list-scripts", "List all scripts for the given package",
  1745 	  command_list_scripts },
  1746 	{ "remove", "Remove specified packages", command_remove },
  1747 	{ "search", "Search package details", command_search },
  1748 	{ "update", "Update all or specified packages", command_update },
  1749 	{ "what-provides", "List the packages that have the given provides",
  1750 	  command_what_provides },
  1751 	{ "what-requires", "List the packages that have the given requires",
  1752 	  command_what_requires },
  1753 };
  1754 
  1755 static int
  1756 command_help(int argc, char * const argv[])
  1757 {
  1758 	int i;
  1759 
  1760 	printf("Available commands:\n");
  1761 	for (i = 0; i < ARRAY_SIZE(razor_commands); i++)
  1762 		printf("  %-20s%s\n",
  1763 		       razor_commands[i].name, razor_commands[i].description);
  1764 	printf("\nType \"razor --help\" for help about global options\n"
  1765 	       "or \"razor <command> --help\" for help about a particular "
  1766 	       "command's options.\n");
  1767 
  1768 	return 0;
  1769 }
  1770 
  1771 int
  1772 main(int argc, char *argv[])
  1773 {
  1774 	char *repo, *root;
  1775 	int i, opt, main_optind;
  1776 	int do_help_commands = 0;
  1777 	enum {
  1778 		opt_database = 1,
  1779 		opt_help,
  1780 		opt_help_commands,
  1781 		opt_root,
  1782 		opt_url,
  1783 	};
  1784 	struct option options[] = {
  1785 		{ .name = "database", .has_arg = required_argument,
  1786 		  .val = opt_database },
  1787 		{ .name = "help", .has_arg = no_argument, .val = opt_help },
  1788 		{ .name = "help-commands", .has_arg = no_argument,
  1789 		  .flag = &do_help_commands, .val = TRUE },
  1790 		{ .name = "root", .has_arg = required_argument,
  1791 		  .val = opt_root },
  1792 		{ .name = "url", .has_arg = required_argument, .val = opt_url },
  1793 		{ 0, }
  1794 	};
  1795 
  1796 	repo = getenv("RAZOR_REPO");
  1797 	if (repo != NULL)
  1798 		repo_filename = repo;
  1799 
  1800 	root = getenv("RAZOR_ROOT");
  1801 	if (root != NULL)
  1802 		install_root = root;
  1803 
  1804 	yum_url = getenv("YUM_URL");
  1805 	if (yum_url == NULL)
  1806 		yum_url = YUM_URL;
  1807 
  1808 	if (getenv("RAZOR_NO_ROOT_NAME_CHECKS"))
  1809 		razor_disable_root_name_checks(1);
  1810 
  1811 	optind = 1;
  1812 	opterr = 0;
  1813 
  1814 	while ((opt = getopt_long(argc, argv, "+", options, NULL)) != -1) {
  1815 		switch (opt) {
  1816 			case opt_database:
  1817 				razor_set_database_path(optarg);
  1818 				break;
  1819 			case opt_help:
  1820 			default:
  1821 				printf("Usage: razor [global-options] command "
  1822 				       "[command-options-and-arguments]\n\n");
  1823 				printf("Options:\n");
  1824 				printf("  --help              "
  1825 				       "Show this help message and exit\n");
  1826 				printf("  --help-commands     List commands\n");
  1827 				printf("  --database=PATH     "
  1828 				       "Use alternative database\n");
  1829 				printf("  --root=ROOT         "
  1830 				       "Use ROOT as top level directory\n");
  1831 				printf("  --url=URL           "
  1832 				       "Use URL as upstream repository\n");
  1833 				return opt != opt_help;
  1834 			case opt_root:
  1835 				install_root = optarg;
  1836 				break;
  1837 			case opt_url:
  1838 				yum_url = optarg;
  1839 				break;
  1840 			case 0:
  1841 				break;
  1842 		}
  1843 	}
  1844 
  1845 	main_optind = optind;
  1846 	optind = 1;
  1847 
  1848 	if (do_help_commands || argc - main_optind < 1) {
  1849 		command_help(argc - main_optind, argv + main_optind);
  1850 		return 1;
  1851 	}
  1852 
  1853 	for (i = 0; i < ARRAY_SIZE(razor_commands); i++)
  1854 		if (strcmp(razor_commands[i].name, argv[main_optind]) == 0)
  1855 			return razor_commands[i].func(argc - main_optind,
  1856 						      argv + main_optind);
  1857 
  1858 	command_help(argc - main_optind, argv + main_optind);
  1859 	return 1;
  1860 }