src/main.c
author J. Ali Harlow <ali@juiblex.co.uk>
Sat Oct 04 18:12:58 2014 +0100 (2014-10-04)
changeset 454 56ff755c268c
parent 445 aada48958b92
child 455 df914f383f5c
permissions -rw-r--r--
Only export symbols starting with razor_ in dynamic library.

Apart from being good practice to avoid clashes with higher-level
libraries and the application, this also fixes an obscure bug: The
gnulib library is used both by librazor (the dynamic library) and
by razor (the executable). In doing so, we want to have two separate
copies of the library despite the code duplication this involves.
Without the explicit limit to export only razor_ symbols, the razor
executable under mingw64 was picking up the getopt_long function
from librazor and the optind variable from libgnu which meant that
it did not see optind changing. Hiding librazor's copy of getopt
causes the linker to find libgnu's copy and everything works.

Note that under mingw librazor-#.dll still contains undocumented
(private) razor_ symbols but these will do no harm as long as nobody
tries to use them.
     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_propagate_error(atomic, error, NULL);
  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_propagate_error(atomic, error, NULL);
  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 }